ref: 02add69d54728af139a3ade19052993443aee6ea
author: Snesrev <[email protected]>
date: Wed Aug 10 22:35:48 EDT 2022
Initial version Force pushed to reorder all functions Lots of names taken from spannerism's diassembly
--- /dev/null
+++ b/.gitignore
@@ -1,0 +1,12 @@
+/.vs/
+.DS_Store
+*.dSYM
+/Debug
+/Release
+/x64
+/tables/overworld/*.yaml
+/tables/dungeon/*.yaml
+/tables/img/
+/tables/old/
+/saves/*.sav
+__pycache__
--- /dev/null
+++ b/LICENSE.txt
@@ -1,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 elzo_d
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
--- /dev/null
+++ b/README.md
@@ -1,0 +1,79 @@
+# Zelda3
+A reimplementation of Zelda 3.
+
+## About
+
+This is a reverse engineered clone of Zelda 3 - A Link to the Past.
+
+It's around 70-80kLOC of C/C++ code, and reimplements all parts of the original game. The game is playable from start to end.
+
+You need a copy of the ROM to extract game resources (levels, images). Then once that's done, the ROM is no longer needed.
+
+It uses the PPU and DSP implementation from LakeSnes. Additionally, it can be configured to also run the original machine code side by side. Then the RAM state is compared after each frame, to verify that the C++ implementation is correct.
+
+I got much assistance from spannierism's Zelda 3 JP disassembly and the other ones that documented loads of function names and variables.
+
+## Compiling
+
+Put the ROM in tables/zelda3.sfc
+
+`cd tables`
+
+Install python dependencies: `pip install pillow` and `pip install pyyaml`
+
+Run `python extract_resources.py` to extract resources from the ROM into a more human readable format.
+
+Run `python compile_resources.py` to produce .h files that gets included by the C++ code.
+
+### Windows
+Build the .sln file with Visual Studio
+
+### Linux
+`apt install libsdl2-dev`
+
+Make sure you are in the root directory.
+
+`clang++ -I/usr/include/SDL2 -lSDL2 -O2 -ozelda3 *.cpp snes/*.cpp`
+
+
+## Usage and controls
+
+The game supports snapshots. The joypad input history is also saved in the snapshot. It's thus possible to replay a playthrough in turbo mode to verify that the game behaves correctly.
+
+The game is run with `./zelda3` and takes an optional path to the ROM-file, which will verify for each frame that the C++ code matches the original behavior.
+
+| Button | Key |
+| ------ | ----------- |
+| Up | Up arrow |
+| Down | Down arrow |
+| Left | Left arrow |
+| Right | Right arrow |
+| Start | Enter |
+| Select | Right shift |
+| A | X |
+| B | Z |
+| X | S |
+| Y | A |
+| L | D |
+| R | C |
+
+
+Additionally, the following commands are available:
+
+| Key | Action |
+| --- | --------------------- |
+| W | Fill health/magic |
+| E | Hard reset |
+| P | Pause |
+| T | Toggle replay turbo |
+| K | Clear all input history from current snapshot |
+| F1-F10 | Load snapshot |
+| Shift+F1-F10 | Save snapshot |
+| Ctrl+F1-F10 | Replay the snapshot |
+
+Additionally, there are a bunch of included playthrough snapshots that play all dungeons of the game. You access them with the digit keys. If you want to replay the stage in turbo mode, press Ctrl+Digit (eg Ctrl-5).
+
+
+## License
+
+This project is licensed under the MIT license. See 'LICENSE.txt' for details.
--- /dev/null
+++ b/Zelda3.sln
@@ -1,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30717.126
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zelda3", "zelda3.vcxproj", "{CB07E01D-A194-481A-BEA1-DC13756AD150}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CB07E01D-A194-481A-BEA1-DC13756AD150}.Debug|x64.ActiveCfg = Debug|x64
+ {CB07E01D-A194-481A-BEA1-DC13756AD150}.Debug|x64.Build.0 = Debug|x64
+ {CB07E01D-A194-481A-BEA1-DC13756AD150}.Debug|x86.ActiveCfg = Debug|Win32
+ {CB07E01D-A194-481A-BEA1-DC13756AD150}.Debug|x86.Build.0 = Debug|Win32
+ {CB07E01D-A194-481A-BEA1-DC13756AD150}.Release|x64.ActiveCfg = Release|x64
+ {CB07E01D-A194-481A-BEA1-DC13756AD150}.Release|x64.Build.0 = Release|x64
+ {CB07E01D-A194-481A-BEA1-DC13756AD150}.Release|x86.ActiveCfg = Release|Win32
+ {CB07E01D-A194-481A-BEA1-DC13756AD150}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {E47623E3-1B23-4ED7-8FC1-3E1F0AD82DD0}
+ EndGlobalSection
+EndGlobal
--- /dev/null
+++ b/ancilla.cpp
@@ -1,0 +1,7358 @@
+#include "ancilla.h"
+#include "variables.h"
+#include "variables_weathervane.h"
+#include "variables_happiness_pond.h"
+#include "variables_blastwall.h"
+#include "variables_skullwoodsfire.h"
+#include "variables_breaktowerseal.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 "tables/generated_ancilla.h"
+#include "sprite_main.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 };
+struct QuakeItem {
+ int8 x, y;
+ uint8 f;
+};
+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;
+}
+
+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_XY(oam,
+ info.x + kInitialSpinSpark_X[t], info.y + kInitialSpinSpark_Y[t]);
+ oam->charnum = kInitialSpinSpark_Char[t];
+ oam->flags = kInitialSpinSpark_Flags[t] & ~0x30 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ Ancilla_SetXY(k, BG2HOFS_copy2 - 16, 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++) {
+ oam->x = info.x + kIceShotSparkle_X[i + j];
+ oam->y = info.y + kIceShotSparkle_Y[i + j];
+ oam->charnum = kIceShotSparkle_Char[i + j];
+ oam->flags = info.flags | 4;
+ bytewise_extended_oam[oam - oam_buf] = 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];
+
+ oam[0].x = info.x + kSomarianBlast_Draw_X0[j];
+ oam[1].x = info.x + kSomarianBlast_Draw_X1[j];
+ if (!sign8(kSomarianBlast_Draw_Y0[j]))
+ oam[0].y = info.y + kSomarianBlast_Draw_Y0[j];
+ if (!sign8(kSomarianBlast_Draw_Y1[j]))
+ oam[1].y = info.y + kSomarianBlast_Draw_Y1[j];
+ oam[0].charnum = 0x82 + kSomarianBlast_Draw_Char0[j];
+ oam[1].charnum = 0x82 + kSomarianBlast_Draw_Char1[j];
+ oam[0].flags = info.flags | kSomarianBlast_Draw_Flags0[j];
+ oam[1].flags = info.flags | kSomarianBlast_Draw_Flags1[j];
+ bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf + 1] = 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};
+ oam->x = info.x;
+ oam->y = info.y;
+ oam->charnum = kFireShot_Draw_Char[j - 1];
+ oam->flags = info.flags | 2;
+ bytewise_extended_oam[oam - oam_buf] = 2;
+ } else {
+ bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf + 1] = 0;
+ oam[0].x = info.x;
+ oam[1].x = info.x + 8;
+ oam[0].y = info.y - 3;
+ oam[1].y = info.y - 3;
+ oam[0].charnum = 0xa4;
+ oam[1].charnum = 0xa5;
+ oam[0].flags = info.flags | 2;
+ oam[1].flags = info.flags | 2;
+ }
+ }
+}
+
+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->x = info.x + kFireShot_Draw_X2[j + i];
+ oam->y = info.y + kFireShot_Draw_Y2[j + i];
+ oam->charnum = kFireShot_Draw_Char2[i];
+ oam->flags = info.flags | 2;
+ bytewise_extended_oam[oam - oam_buf] = 0;
+ oam++;
+ }
+}
+
+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;
+ oam->x = info.x + kBeamHit_X[m];
+ oam->y = info.y + kBeamHit_Y[m];
+ oam->charnum = kBeamHit_Char[m] + 0x82;
+ oam->flags = kBeamHit_Flags[m] | 2 | info.flags;
+ uint16 x_adj = (uint16)(ancilla_x + (int8)(oam->x - r7) - BG2HOFS_copy2);
+ bytewise_extended_oam[oam - oam_buf] = (x_adj >= 0x100) ? 1 : 0;
+ uint16 y_adj = (uint16)(ancilla_y + (int8)(oam->y - r6) - BG2VOFS_copy2 + 0x10);
+ if (y_adj >= 0x100)
+ oam->y = 0xf0;
+ }
+}
+
+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) {
+ oam->x = x;
+ oam->y = y;
+ oam->charnum = (repulsespark_timer < 9) ? 0x92 : 0x80;
+ oam->flags = flags;
+ bytewise_extended_oam[oam - oam_buf] = 0;
+ return;
+ }
+
+ oam[0].x = x - 4;
+ oam[2].x = x - 4;
+ oam[1].x = x + 4;
+ oam[3].x = x + 4;
+
+ oam[0].y = y - 4;
+ oam[1].y = y - 4;
+ oam[2].y = y + 4;
+ oam[3].y = y + 4;
+
+ oam[0].flags = flags;
+ oam[1].flags = flags | 0x40;
+ oam[2].flags = flags | 0x80;
+ oam[3].flags = flags | 0xc0;
+
+ static const uint8 kRepulseSpark_Char[3] = {0x93, 0x82, 0x81};
+ uint8 c = kRepulseSpark_Char[repulsespark_timer];
+ oam[0].charnum = c;
+ oam[1].charnum = c;
+ oam[2].charnum = c;
+ oam[3].charnum = c;
+
+ uint8 *ext = &bytewise_extended_oam[oam - oam_buf];
+ ext[0] = ext[1] = ext[2] = ext[3] = 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) {
+ if (!link_is_bunny_mirror && !link_auxiliary_state)
+ goto exit_and_draw;
+ Boomerang_Terminate(k);
+ return;
+ }
+ int j = boomerang_arr1[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;
+ }
+ OamEnt *oam = GetOamCurPtr();
+ uint8 ext = Ancilla_SetOam_XY_safe(oam, x, y);
+ oam->charnum = 0x26;
+ oam->flags = kBoomerang_Flags[ancilla_G[k] * 4 + j] & ~0x30 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 2 | ext;
+
+}
+
+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_XY(oam, info.x + kWallHit_X[t], info.y + kWallHit_Y[t]);
+ oam->charnum = kWallHit_Char[t];
+ oam->flags = kWallHit_Flags[t] & ~0x30 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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) {
+ 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) {
+ uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
+ door_debris_x[k] = 0;
+ Bomb_CheckForDestructibles(x, y, 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
+ Ancilla_SetOam_XY(oam, x + kDoorDebris_XY[t * 2 + 1], y + kDoorDebris_XY[t * 2 + 0]);
+
+ uint16 d = kDoorDebris_CharFlags[t];
+ oam->charnum = d;
+ oam->flags = (d >> 8) & 0xc0 | HIBYTE(oam_priority_value);
+
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, x + kArrow_Draw_X[j], y + kArrow_Draw_Y[j]);
+ oam->charnum = kArrow_Draw_Char[j];
+ oam->flags = kArrow_Draw_Flags[j] & ~0x3E | flags | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ uint16 xt = x + kBomb_DrawExplosion_XY[i * 2 + 1];
+ uint8 ext = Ancilla_SetOam_XY_safe(oam, xt, y + kBomb_DrawExplosion_XY[i * 2 + 0]);
+ oam->charnum = kBomb_DrawExplosion_CharFlags[frame * 2];
+ oam->flags = kBomb_DrawExplosion_CharFlags[frame * 2 + 1] & ~0x3E | HIBYTE(oam_priority_value) | r11;
+ bytewise_extended_oam[oam - oam_buf] = ext | 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_XY(oam, pt.x, pt.y);
+ oam->charnum = kAncilla_JumpSplash_Char[j];
+ oam->flags = 0x24 | flags;
+ bytewise_extended_oam[oam - oam_buf] = 2;
+ oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
+ pt.x = x8;
+ flags = 0x40;
+ }
+ Ancilla_SetOam_XY(oam, x6, pt.y);
+ oam->charnum = 0xc0;
+ oam->flags = 0x24;
+ bytewise_extended_oam[oam - oam_buf] = (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_XY(oam, x, y);
+ oam->charnum = kAncilla_HitStars_Char[ancilla_item_to_link[k]];
+ oam->flags = HIBYTE(oam_priority_value) | 4 | flags;
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, pt.x + i * 8, pt.y);
+ oam->charnum = kShovelDirt_Char[b] + i;
+ oam->flags = 4 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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);
+ OamEnt *oam = GetOamCurPtr();
+ Ancilla_SetOam_XY(oam, pt.x, pt.y);
+ oam->charnum = kBlastWallFireball_Char[blastwall_var12[k] & 8 ? 0 : blastwall_var12[k] & 4 ? 1 : 2];
+ oam->flags = 0x22;
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, x, y);
+ oam->charnum = kEther_BlitzBall_Char[s];
+ oam->flags = 0x3c;
+ bytewise_extended_oam[oam - oam_buf] = 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);
+ Ancilla_SetOam_XY(oam, x + ether_x2 - 8 - BG2HOFS_copy2, y + ether_y3 - 8 - BG2VOFS_copy2);
+ int t = s * 8 + k;
+ oam->charnum = kEther_SpllittingBlitzSegment_Char[t * 2];
+ oam->flags = kEther_SpllittingBlitzSegment_Flags[t * 2];
+ bytewise_extended_oam[oam - oam_buf] = 2;
+ oam++;
+ Ancilla_SetOam_XY(oam,
+ x + ether_x2 + kEther_SpllittingBlitzSegment_X[t] - BG2HOFS_copy2,
+ y + ether_y3 + kEther_SpllittingBlitzSegment_Y[t] - BG2VOFS_copy2);
+ oam->charnum = kEther_SpllittingBlitzSegment_Char[t * 2 + 1];
+ oam->flags = kEther_SpllittingBlitzSegment_Flags[t * 2 + 1];
+ bytewise_extended_oam[oam - oam_buf] = 2;
+ return Ancilla_AllocateOamFromCustomRegion(oam + 1);
+}
+
+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_XY(oam, info.x, info.y);
+ oam->charnum = kEther_BlitzSegment_Char[t * 2 + m];
+ oam->flags = kEther_BlitzOrb_Flags[0] | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, x, y);
+ oam->charnum = kEther_BlitzOrb_Char[t + i];
+ oam->flags = kEther_BlitzOrb_Flags[t + i];
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, x, y);
+ oam->charnum = kBombosSpell_FireColumn_Char[k];
+ oam->flags = kBombosSpell_FireColumn_Flags[k];
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam,
+ x + kBombosSpell_DrawBlast_X[t] - BG2HOFS_copy2,
+ y + kBombosSpell_DrawBlast_Y[t] - BG2VOFS_copy2);
+ oam->charnum = kBombosSpell_DrawBlast_Char[t];
+ oam->flags = kBombosSpell_DrawBlast_Flags[t];
+ bytewise_extended_oam[oam - oam_buf] = 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 yval = 0xf0;
+ if (x < 256 && y < 256) {
+ oam->x = x;
+ if (y < 0xf0)
+ yval = y;
+ }
+ oam->y = yval;
+ oam->charnum = kQuakeDrawGroundBolts_Char[p->f & 0x0f];
+ oam->flags = p->f & 0xc0 | 0x3c;
+ bytewise_extended_oam[oam - oam_buf] = 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 {
+ oam->x = p->x;
+ oam->y = p->y;
+ oam->charnum = kQuakeDrawGroundBolts_Char[p->f & 0x0f];
+ oam->flags = p->f & 0xc0 | 0x3c;
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, info.x + kMagicPowder_DrawX[b * 4 + i], info.y + kMagicPowder_DrawY[b * 4 + i]);
+ oam->charnum = kMagicPowder_Draw_Char[b];
+ oam->flags = kMagicPowder_Draw_Flags[b * 4 + i] & ~0x30 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, info.x + r12 + kDashDust_Draw_X[t], info.y + kDashDust_Draw_Y[t]);
+ oam->charnum = kDashDust_Draw_Char[t];
+ oam->flags = 4 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ }
+
+do_draw:
+ 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;
+ 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_XY(oam, x, y);
+ oam->charnum = kHookShot_Draw_Char[j];
+ oam->flags = kHookShot_Draw_Flags[j] | 2 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, x, y);
+ oam->charnum = 0x19;
+ oam->flags = (frame_counter & 2) << 6 | 2 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, x, y);
+ oam->charnum = kBedSpread_Char[j];
+ oam->flags = kBedSpread_Flags[j] | 0xd | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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);
+ OamEnt *oam = GetOamCurPtr();
+ Ancilla_SetOam_XY(oam, pt.x, pt.y);
+ oam->charnum = 9;
+ oam->flags = 0x24;
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam,
+ link_x_coord + kAncilla_VictorySparkle_X[j] - BG2HOFS_copy2,
+ link_y_coord + kAncilla_VictorySparkle_Y[j] - BG2VOFS_copy2);
+ oam->charnum = kAncilla_VictorySparkle_Char[j];
+ oam->flags = kAncilla_VictorySparkle_Flags[j] | 4 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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);
+ OamEnt *oam = GetOamCurPtr();
+ Ancilla_SetOam_XY(oam, info.x, info.y);
+ int j = ancilla_item_to_link[k];
+ oam->charnum = kSwordChargeSpark_Char[j];
+ oam->flags = kSwordChargeSpark_Flags[j] | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, pt.x + kSwordCeremony_X[j], pt.y + kSwordCeremony_Y[j]);
+ oam->charnum = kSwordCeremony_Char[j];
+ oam->flags = kSwordCeremony_Flags[j] & ~0x30 | 4 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ savegame_tagalong = 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]);
+ }
+endif_12:
+ 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];
+ Ancilla_SetOam_XY(oam, x, y);
+ oam->charnum = 0x24;
+ uint8 a = kWishPond2_OamFlags[j];
+ if (sign8(a))
+ a = ancilla_arr4[k];
+ oam->flags = a * 2 | 0x30;
+ uint8 ext = kReceiveItem_Tab1[j];
+ bytewise_extended_oam[oam - oam_buf] = ext;
+ oam++;
+ if (ext == 0) {
+ Ancilla_SetOam_XY(oam, x, y + 8);
+ oam->charnum = 0x34;
+ oam->flags = a * 2 | 0x30;
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, pt.x + kObjectSplash_Draw_X[j], pt.y + kObjectSplash_Draw_Y[j]);
+ oam->charnum = kObjectSplash_Draw_Char[j];
+ oam->flags = kObjectSplash_Draw_Flags[j] | 0x24;
+ bytewise_extended_oam[oam - oam_buf] = 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_sp6 = 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_sp6 = 0;
+ overworld_palette_aux_or_main = 0x200;
+ Palette_Load_SpriteEnvironment_Dungeon();
+ flag_update_cgram_in_nmi++;
+ ancilla_type[k] = 0;
+ return;
+ }
+ }
+label_b:
+
+ uint8 astep;
+
+ 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++;
+ }
+label_a:
+ Point16U info;
+ 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
+ uint8 ext = Ancilla_SetOam_XY_safe(oam, x, y);
+ oam->charnum = 0x24;
+ oam->flags = 0x3c;
+ int j = oam - oam_buf;
+ bytewise_extended_oam[oam - oam_buf] = ext | 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];
+ Ancilla_SetOam_XY(oam, x, y);
+ int j = breaktowerseal_sparkle_var1[k];
+ oam->charnum = kSwordChargeSpark_Char[j];
+ oam->flags = kSwordChargeSpark_Flags[j] | 0x30;
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, pt.x, pt.y - (int8)ancilla_z[k]);
+ oam->charnum = 0x24;
+ oam->flags = HIBYTE(oam_priority_value) | 4;
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ OamEnt *oam = GetOamCurPtr() + (weathervane_var14 >> 2);
+ Ancilla_SetOam_XY(oam, pt.x, pt.y);
+ oam->charnum = kWeathervane_Explode_Char[i];
+ oam->flags = 0x3c;
+ weathervane_var14 += 4;
+ bytewise_extended_oam[oam - oam_buf] = 0;
+}
+
+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_XY(oam, info.x + kTravelBird_Draw_X[0], info.y + (int8)ancilla_z[k] + kTravelBird_Draw_Y[0]);
+ oam->charnum = kTravelBird_Draw_Char[0];
+ oam->flags = kTravelBird_Draw_Flags[0] | 0x30 | kTravelBirdIntro_Tab0[ancilla_dir[k] & 1];
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, info.x + kMorphPoof_X[j * 4 + i], info.y + kMorphPoof_Y[j * 4 + i]);
+ oam->charnum = chr;
+ oam->flags = kMorphPoof_Flags[j * 4 + i] | 4 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, pt.x + kBushPoof_Draw_X[j], pt.y + kBushPoof_Draw_Y[j]);
+ oam->charnum = kBushPoof_Draw_Char[j];
+ oam->flags = kBushPoof_Draw_Flags[j] | 4 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ oam->charnum = chr;
+ oam->flags = kSwordSwingSparkle_Flags[k] | 0x4 | (oam_priority_value >> 8);
+ Ancilla_SetOam_XY(oam, info.x + kSwordSwingSparkle_X[k], info.y + kSwordSwingSparkle_Y[k]);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, pt.x, pt.y);
+ oam->charnum = kSpinSpark_Char[i];
+ oam->flags = flags | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, pt.x, pt.y);
+ oam->charnum = kSpinSpark_Char2[t];
+ oam->flags = 4 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, pt.x + kInitialCaneSpark_Draw_X[j], pt.y + kInitialCaneSpark_Draw_Y[j]);
+ oam->charnum = kInitialCaneSpark_Draw_Char[j];
+ oam->flags = kInitialCaneSpark_Draw_Flags[j] & ~0x30 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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 (eq_selected_y_item != 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_XY(oam, pt.x, pt.y);
+ oam->charnum = kCaneSpark_Char[i];
+ oam->flags = flags | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, pt.x, pt.y);
+ oam->charnum = kSwordBeam_Char[i];
+ oam->flags = flags | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, pt.x, pt.y);
+ oam->charnum = kSwordBeam_Char2[t];
+ oam->flags = 4 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, x, y);
+ oam->charnum = 0xd7;
+ oam->flags = HIBYTE(oam_priority_value) | 2;
+ bytewise_extended_oam[oam - oam_buf] = 0;
+}
+
+void Ancilla27_Duck(int k) { // 88dde8
+ CheckPlayerCollOut coll;
+ int j;
+
+ if (submodule_index)
+ goto endif_1;
+
+ if (ancilla_timer[k]) {
+ Ancilla_SetXY(k, BG2HOFS_copy2 - 16, 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 (!((savegame_tagalong == 12 || savegame_tagalong == 13) && super_bomb_going_off)) {
+ 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 (savegame_tagalong == 9) {
+ savegame_tagalong = 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_XY(oam, info.x + (int8)kTravelBird_Draw_X[i], info.y + z + (int8)kTravelBird_Draw_Y[i]);
+ oam->charnum = kTravelBird_Draw_Char[i];
+ oam->flags = kTravelBird_Draw_Flags[i] | 0x30;
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ }
+ }
+}
+
+void AncillaAdd_SomariaBlock(uint8 type, uint8 y) { // 88e078
+ int k = AncillaAdd_AddAncilla_Bank08(type, y);
+ if (k < 0) {
+ Refund_Magic(4);
+ return;
+ }
+ 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;
+ }
+
+ 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);
+ }
+}
+
+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 {
+ uint8 t = Ancilla_SetOam_XY_safe(oam, pt.x + kSomarianBlock_Draw_X[j], pt.y + kSomarianBlock_Draw_Y[j]);
+ oam->charnum = 0xe9;
+ oam->flags = kSomarianBlock_Draw_Flags[j] & ~0x30 | 2 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = t;
+ 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_XY(oam, x + kSomariaBlockFizzle_X[j], y + kSomariaBlockFizzle_Y[j]);
+ oam->charnum = kSomariaBlockFizzle_Char[j];
+ oam->flags = kSomariaBlockFizzle_Flags[j] & ~0x30 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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(), *oam_org = oam;
+
+ 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_XY(oam, pt.x + kSomarianBlockDivide_X[j], pt.y + kSomarianBlockDivide_Y[j] - z);
+ oam->charnum = kSomarianBlockDivide_Char[j];
+ oam->flags = kSomarianBlockDivide_Flags[j] & ~0x30 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, pt.x + kLampFlame_Draw_X[j], pt.y + kLampFlame_Draw_Y[j]);
+ oam->charnum = kLampFlame_Draw_Char[j];
+ oam->flags = HIBYTE(oam_priority_value) | 2;
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, pt.x + kWaterfallSplash_X[j], pt.y + kWaterfallSplash_Y[j]);
+ oam->charnum = kWaterfallSplash_Char[j];
+ oam->flags = kWaterfallSplash_Flags[j] | 0x30;
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, x, y);
+ oam->charnum = kAncilla_Gravestone_Char[i];
+ oam->flags = kAncilla_Gravestone_Flags[i] | 0x3d;
+ bytewise_extended_oam[oam - oam_buf] = 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_XY(oam, x, y);
+ oam->charnum = kSkullWoodsFire_Draw_Char[j];
+ oam->flags = 0x32;
+ uint8 ext = kSkullWoodsFire_Draw_Ext[j];
+ bytewise_extended_oam[oam - oam_buf] = ext;
+ oam++;
+ if (kSkullWoodsFire_Draw_Ext[j] != 2) {
+ Ancilla_SetOam_XY(oam, x + 8, y);
+ oam->charnum = kSkullWoodsFire_Draw_Char[j] + 1;
+ oam->flags = 0x32;
+ bytewise_extended_oam[oam - oam_buf] = ext;
+ 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_XY(oam,
+ 168 - BG2HOFS_copy2 + kSkullWoodsFire_Draw2_X[j],
+ 200 - BG2VOFS_copy2 + kSkullWoodsFire_Draw2_Y[j]);
+ oam->charnum = kSkullWoodsFire_Draw2_Char[j];
+ oam->flags = kSkullWoodsFire_Draw2_Flags[j] | 0x32;
+ bytewise_extended_oam[oam - oam_buf] = 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) {
+ Bomb_CheckForDestructibles(Ancilla_GetX(k), Ancilla_GetY(k), 0); // r14?
+ savegame_tagalong = 0;
+ }
+}
+
+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;
+ Ancilla_SetOam_XY(oam, pt.x, pt.y - (int8)ancilla_z[k]);
+ if (t != 0)
+ t += 1;
+ else
+ t = (frame_counter >> 2) & 1;
+ oam->charnum = kAncilla_RevivalFaerie_Tab1[t];
+ oam->flags = 0x74;
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ } 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_XY(oam, Ancilla_GetX(k), 0x57);
+ oam->charnum = kGameOverText_Chars[k * 2 + 0];
+ oam->flags = 0x3c;
+ bytewise_extended_oam[oam - oam_buf] = 0;
+ oam++;
+ Ancilla_SetOam_XY(oam, Ancilla_GetX(k), 0x5f);
+ oam->charnum = kGameOverText_Chars[k * 2 + 1];
+ oam->flags = 0x3c;
+ bytewise_extended_oam[oam - oam_buf] = 0;
+ oam++;
+ } while (--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;
+}
+
+void Ancilla_SetOam_XY(OamEnt *oam, uint16 x, uint16 y) { // 88f6e1
+ uint8 yval = 0xf0;
+ if (x < 256 && y < 256) {
+ oam->x = x;
+ if (y < 0xf0)
+ yval = y;
+ }
+ oam->y = yval;
+}
+
+uint8 Ancilla_SetOam_XY_safe(OamEnt *oam, uint16 x, uint16 y) { // 88f702
+ uint8 rv = 0;
+ oam->x = x;
+ if ((uint16)(x + 0x80) < 0x180) {
+ rv = (x >> 8) & 1;
+ oam->y = y;
+ if ((uint16)(y + 0x10) < 0x100)
+ return rv;
+ }
+ oam->y = 0xf0;
+ return rv;
+}
+
+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;
+ uint8 ext = Ancilla_SetOam_XY_safe(oam, x, y);
+ oam->charnum = kAncilla_DrawShadow_Char[k * 2];
+ oam->flags = kAncilla_DrawShadow_Flags[k * 2] & ~0x30 | pal;
+ bytewise_extended_oam[oam - oam_buf] = ext;
+ oam++;
+
+ uint8 ch = kAncilla_DrawShadow_Char[k * 2 + 1];
+ if (ch != 0xff) {
+ x += 8;
+ ext = Ancilla_SetOam_XY_safe(oam, x, y);
+ oam->charnum = ch;
+ oam->flags = kAncilla_DrawShadow_Flags[k * 2 + 1] & ~0x30 | pal;
+ bytewise_extended_oam[oam - oam_buf] = ext;
+ }
+}
+
+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_arr25[k] = 0;
+ ancilla_L[k] = 0;
+ ancilla_arr3[k] = kBomb_Tab0[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];
+ boomerang_arr1[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;
+ int j = 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);
+}
+
+void 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;
+ 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);
+}
+
+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();
+}
+
+void 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);
+ }
+}
+
+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 (savegame_tagalong == 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 (eq_selected_y_item_copy == 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 kAddDashingDust_X[4] = {4, 4, 6, 0};
+ static const uint8 kAddDashingDust_Y[4] = {20, 4, 16, 16};
+ 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;
+ 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_sp6 = 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;
+ byte_7E03FC = 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);
+ OamEnt *oam = GetOamCurPtr();
+ Ancilla_SetOam_XY(oam, info.x, info.y);
+ oam->charnum = kMotiveDashDust_Draw_Char[ancilla_item_to_link[k]];
+ oam->flags = 4 | HIBYTE(oam_priority_value);
+ bytewise_extended_oam[oam - oam_buf] = 0;
+}
+
+uint8 Ancilla_CalculateSfxPan(int k) { // 8dbb5e
+ return CalculateSfxPan(Ancilla_GetX(k));
+}
+
+int Ancilla_AllocInit(uint8 type, uint8 y) { // 8ff577
+ int n = 0;
+ for (int k = 0; k < 5; k++) {
+ if (ancilla_type[k] == type)
+ n++;
+ }
+ if (y + 1 == n)
+ return -1;
+ int k = (type == 7 || type == 8) ? 1 : 4;
+ for (; k >= 0; k--) {
+ if (ancilla_type[k] == 0)
+ return k;
+ }
+ do {
+ if (sign8(--ancilla_alloc_rotate))
+ ancilla_alloc_rotate = y;
+ uint8 type = ancilla_type[ancilla_alloc_rotate];
+ if (type == 0x3c || type == 0x13 || type == 0xa)
+ return ancilla_alloc_rotate;
+ } while (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
+ uint16 x = Ancilla_GetX(j) - BG2HOFS_copy2;
+ uint16 y = Ancilla_GetY(j) - BG2VOFS_copy2;
+ if (x >= 244 || 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/ancilla.h
@@ -1,0 +1,274 @@
+#pragma once
+#include "zelda_rtl.h"
+#include "sprite.h"
+
+struct CheckPlayerCollOut {
+ uint16 r4, r6;
+ uint16 r8, r10;
+};
+
+struct AncillaOamInfo {
+ uint8 x;
+ uint8 y;
+ uint8 flags;
+};
+
+struct AncillaRadialProjection {
+ uint8 r0, r2, r4, r6;
+};
+
+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);
+void 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);
+void Ancilla_SetOam_XY(OamEnt *oam, uint16 x, uint16 y);
+uint8 Ancilla_SetOam_XY_safe(OamEnt *oam, uint16 x, uint16 y);
+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);
+void 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);
+void 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/attract.cpp
@@ -1,0 +1,1092 @@
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "variables_attract.h"
+#include "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[224] = {
+ 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,
+};
+const uint16 kMapMode_Zooms2[224] = {
+ 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,
+};
+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++) {
+ oam->x = attract_x_base + p[n].x;
+ oam->y = attract_y_base + p[n].y;
+ oam->charnum = p[n].c;
+ oam->flags = p[n].f;
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ bytewise_extended_oam[oam - oam_buf] = ext;
+ bytewise_extended_oam[oam - oam_buf + 1] = ext;
+
+ oam[0].x = oam[1].x = attract_x_base;
+ int j = (attract_var1 >> 3) & 1;
+ oam[0].y = attract_y_base + j;
+ oam[1].y = attract_y_base + 10;
+ oam[0].charnum = 6;
+ oam[1].charnum = j ? 10 : 8;
+ oam[0].flags = oam[1].flags = 0x3d;
+
+ 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_SpritePal0Left();
+ Palette_Load_SpriteMain();
+ Palette_Load_SpriteAux1();
+ Palette_Load_SpriteAux2();
+ 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;
+ zelda_ppu_write(WBGLOG, 0);
+ zelda_ppu_write(WOBJLOG, 0);
+
+ 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;
+ zelda_ppu_write(BGMODE, 7);
+ BGMODE_copy = 7;
+ zelda_ppu_write(M7SEL, 0x80);
+ 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
+ zelda_snes_dummy_write(HDMAEN, 0);
+ HDMAEN_copy = 0;
+ CGWSEL_copy = 2;
+ CGADSUB_copy = 0x20;
+ misc_sprites_graphics_index = 10;
+ LoadCommonSprites_2();
+ uint16 bak0 = attract_var12;
+ uint16 bak1 = WORD(attract_state);
+ Dungeon_LoadAndDrawEntranceRoom(0x74);
+ WORD(attract_state) = bak1;
+ attract_var12 = bak0;
+ dung_hdr_palette_1 = 0;
+ overworld_palette_sp0 = 0;
+ sprite_aux1_palette = 14;
+ sprite_aux2_palette = 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;
+
+ dung_hdr_palette_1 = 2;
+ overworld_palette_sp0 = 0;
+ sprite_aux1_palette = 14;
+ sprite_aux2_palette = 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;
+
+ dung_hdr_palette_1 = 0;
+ overworld_palette_sp0 = 0;
+ sprite_aux1_palette = 14;
+ sprite_aux2_palette = 3;
+
+ overworld_palette_aux_or_main = 0;
+ Palette_Load_SpritePal0Left();
+ Palette_Load_SpriteMain();
+ Palette_Load_SpriteAux1();
+ Palette_Load_SpriteAux2();
+ 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();
+ zelda_ppu_write(BGMODE, 9);
+ 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 = 223; i >= 0; i--)
+ mode7_hdma_table[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 {
+ oam->x = attract_x_base + xp[n];
+ oam->y = attract_y_base + yp[n];
+ oam->charnum = cp[n];
+ oam->flags = fp[n];
+ bytewise_extended_oam[oam - oam_buf] = ep[n];
+ } while (oam++, --n >= 0);
+}
+
+void Attract_DrawZelda() { // 8cf9e8
+ OamEnt *oam = &oam_buf[64 + attract_oam_idx];
+ bytewise_extended_oam[oam - oam_buf] = 2;
+ oam[0].x = oam[1].x = 0x60;
+ oam[0].y = attract_x_base;
+ oam[1].y = attract_x_base + 10;
+ oam[0].charnum = 0x28;
+ oam[1].charnum = 0x2a;
+ oam[0].flags = 0x29;
+ oam[1].flags = 0x29;
+ 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/attract.h
@@ -1,0 +1,50 @@
+#pragma once
+struct AttractOamInfo {
+ int8 x, y;
+ uint8 c, f, e;
+};
+
+
+extern const uint16 kMapMode_Zooms1[224];
+extern const uint16 kMapMode_Zooms2[224];
+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/dsp_regs.h
@@ -1,0 +1,108 @@
+#pragma once
+
+enum DspReg {
+ V0VOLL = 0,
+ V0VOLR = 1,
+ V0PITCHL = 2,
+ V0PITCHH = 3,
+ V0SRCN = 4,
+ V0ADSR1 = 5,
+ V0ADSR2 = 6,
+ V0GAIN = 7,
+ V0ENVX = 8,
+ V0OUTX = 9,
+ MVOLL = 0xC,
+ EFB = 0xD,
+ FIR0 = 0xF,
+ V1VOLL = 0x10,
+ V1VOLR = 0x11,
+ V1PL = 0x12,
+ V1PH = 0x13,
+ V1SRCN = 0x14,
+ V1ADSR1 = 0x15,
+ V1ADSR2 = 0x16,
+ V1GAIN = 0x17,
+ V1ENVX = 0x18,
+ V1OUTX = 0x19,
+ MVOLR = 0x1C,
+ FIR1 = 0x1F,
+ V2VOLL = 0x20,
+ V2VOLR = 0x21,
+ V2PL = 0x22,
+ V2PH = 0x23,
+ V2SRCN = 0x24,
+ V2ADSR1 = 0x25,
+ V2ADSR2 = 0x26,
+ V2GAIN = 0x27,
+ V2ENVX = 0x28,
+ V2OUTX = 0x29,
+ EVOLL = 0x2C,
+ PMON = 0x2D,
+ FIR2 = 0x2F,
+ V3VOLL = 0x30,
+ V3VOLR = 0x31,
+ V3PL = 0x32,
+ V3PH = 0x33,
+ V3SRCN = 0x34,
+ V3ADSR1 = 0x35,
+ V3ADSR2 = 0x36,
+ V3GAIN = 0x37,
+ V3ENVX = 0x38,
+ V3OUTX = 0x39,
+ EVOLR = 0x3C,
+ NON = 0x3D,
+ FIR3 = 0x3F,
+ V4VOLL = 0x40,
+ V4VOLR = 0x41,
+ V4PL = 0x42,
+ V4PH = 0x43,
+ V4SRCN = 0x44,
+ V4ADSR1 = 0x45,
+ V4ADSR2 = 0x46,
+ V4GAIN = 0x47,
+ V4ENVX = 0x48,
+ V4OUTX = 0x49,
+ KON = 0x4C,
+ EON = 0x4D,
+ FIR4 = 0x4F,
+ V5VOLL = 0x50,
+ V5VOLR = 0x51,
+ V5PL = 0x52,
+ V5PH = 0x53,
+ V5SRCN = 0x54,
+ V5ADSR1 = 0x55,
+ V5ADSR2 = 0x56,
+ V5GAIN = 0x57,
+ V5ENVX = 0x58,
+ V5OUTX = 0x59,
+ KOF = 0x5C,
+
+ DIR = 0x5D,
+ FIR5 = 0x5F,
+ V6VOLL = 0x60,
+ V6VOLR = 0x61,
+ V6PL = 0x62,
+ V6PH = 0x63,
+ V6SRCN = 0x64,
+ V6ADSR1 = 0x65,
+ V6ADSR2 = 0x66,
+ V6GAIN = 0x67,
+ V6ENVX = 0x68,
+ V6OUTX = 0x69,
+ FLG = 0x6C,
+ ESA = 0x6D,
+ FIR6 = 0x6F,
+ V7VOLL = 0x70,
+ V7VOLR = 0x71,
+ V7PL = 0x72,
+ V7PH = 0x73,
+ V7SRCN = 0x74,
+ V7ADSR1 = 0x75,
+ V7ADSR2 = 0x76,
+ V7GAIN = 0x77,
+ V7ENVX = 0x78,
+ V7OUTX = 0x79,
+ ENDX = 0x7C,
+ EDL = 0x7D,
+ FIR7 = 0x7F,
+};
\ No newline at end of file
--- /dev/null
+++ b/dungeon.cpp
@@ -1,0 +1,8786 @@
+#include "zelda_rtl.h"
+
+#include "variables.h"
+#include "dungeon.h"
+#include "snes_regs.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 "tables/generated_dungeon_rooms.h"
+#include "tagalong.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;
+ }
+ WORD(CGWSEL_copy) = 0x6202;
+ }
+ 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() {
+ 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++;
+ 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 += 1;
+ 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() {
+ 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++;
+ 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 += 1;
+ 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() {
+ link_quadrant_y ^= 2;
+ Dungeon_AdjustQuadrant();
+ RoomBounds_AddA(&room_bounds_y);
+ Dung_SaveDataForCurrentRoom();
+ DungeonTransition_AdjustCamera_Y(link_quadrant_y);
+ HandleEdgeTransition_AdjustCameraBoundaries(0);
+ submodule_index++;
+ 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 += 1;
+ 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 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:
+ int 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];
+}
+
+uint8 GetEntranceMusicTrack(int entrance) {
+ return kEntranceData_musicTrack[entrance];
+}
+
+bool Dungeon_IsPitThatHurtsPlayer() {
+ for (int i = countof(kDungeonPitsHurtPlayer) - 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]];
+ dung_hdr_palette_1 = dpi->pal0;
+ overworld_palette_sp0 = dpi->pal1;
+ sprite_aux1_palette = dpi->pal2;
+ sprite_aux2_palette = 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();
+ 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;
+ Ancilla_SpawnFallingPrize(kBossFinishedFallingItem[BYTE(cur_palace_index_x2) >> 1]);
+ }
+ 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;
+ // 81:D01F
+ assert(0);
+ }
+ }
+
+ 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) {
+handle_f0:
+ int 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))
+ 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) {
+ dung_misc_objs_index = (tile & 0xf) * 2;
+ RoomDraw_16x16Single(dung_misc_objs_index);
+ sound_effect_1 = 0x11;
+ } else if ((tile2 & 0xf0f0) == 0x1010) {
+ 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 < countof(kDungeonRoomChests); 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];
+
+afterStoreCrap:
+ uint8 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]) = 0x202;
+ WORD(dung_bg2_attr_table[pos + 64]) = 0x202;
+
+ pos += XY(0, 2);
+
+ const uint16 *src = SrcPtr(0x14A4);
+ 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 = 0x14A4; // wtf
+
+ uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
+ dst[0] = RoomTag_BuildChestStripes((pos + 0) * 2, yy);
+ dst[3] = RoomTag_BuildChestStripes((pos + 64) * 2, yy);
+ dst[6] = RoomTag_BuildChestStripes((pos + 1) * 2, yy);
+ dst[9] = RoomTag_BuildChestStripes((pos + 65) * 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;
+
+ uint8 rv;
+
+ uint16 r16 = g_ram[0xc8];
+
+ 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];
+ }
+ g_ram[0xc8] = 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;
+ zelda_ppu_write(TS, 0);
+ 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.t3.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_sp6 = 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 (savegame_tagalong == 13) {
+ savegame_tagalong = 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;
+ zelda_snes_dummy_write(NMITIMEN, 0);
+ zelda_snes_dummy_write(HDMAEN, 0);
+ flag_which_music_type = 0;
+ LoadOverworldSongs();
+ zelda_snes_dummy_write(NMITIMEN, 0x81);
+}
+
+void Module07_Dungeon() { // 8287a2
+ Dungeon_HandleLayerEffect();
+ kDungeonSubmodules[submodule_index]();
+ 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) {
+ overworld_map_state = 0;
+ submodule_index = 1;
+ saved_module_for_menu = main_module_index;
+ main_module_index = 14;
+ return;
+ }
+ if (filtered_joypad_L & 0x40 && (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;
+ }
+ if (joypad1H_last & 0x20 && sram_progress_indicator) {
+ 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;
+ overworld_map_state = 0;
+ submodule_index = 11;
+ saved_module_for_menu = main_module_index;
+ main_module_index = 14;
+ return;
+ }
+ }
+ 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) {
+ 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
+ int j;
+
+ 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 && music_unk1 != 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 (savegame_tagalong == 6 && BYTE(dungeon_room_index) == 100)
+ savegame_tagalong = 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 || music_unk1 == 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 (buffer_for_playing_songs != 0xff)
+ music_control = buffer_for_playing_songs;
+ }
+}
+
+// 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 (overworld_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 = buffer_for_playing_songs;
+ 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;
+ zelda_ppu_write(OBSEL, 2);
+ InitializeTilesets();
+ palette_sp6 = 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 (buffer_for_playing_songs == 0xff || buffer_for_playing_songs == 0xf2)
+ return;
+
+ if (buffer_for_playing_songs == 3 || buffer_for_playing_songs == 7 || buffer_for_playing_songs == 14) {
+ LoadOWMusicIfNeeded();
+ } else {
+ if (flag_which_music_type)
+ return;
+ zelda_snes_dummy_write(NMITIMEN, 0);
+ zelda_snes_dummy_write(HDMAEN, 0);
+ flag_which_music_type = 1;
+ LoadDungeonSongs();
+ zelda_snes_dummy_write(NMITIMEN, 0x81);
+ }
+}
+
+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
+ link_quadrant_x ^= 1;
+ Dungeon_AdjustQuadrant();
+ RoomBounds_AddA(&room_bounds_x);
+ Dung_SaveDataForCurrentRoom();
+ DungeonTransition_AdjustCamera_X(link_quadrant_x);
+ HandleEdgeTransition_AdjustCameraBoundaries(2);
+ submodule_index++;
+ 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 += 1;
+ 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;
+ zelda_snes_dummy_write(HDMAEN, 0);
+ 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(savegame_tagalong) == 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;
+
+ buffer_for_playing_songs = kStartingPoint_musicTrack[i];
+ if (i == 0 && sram_progress_indicator == 0)
+ buffer_for_playing_songs = 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];
+ buffer_for_playing_songs = kEntranceData_musicTrack[i];
+ if (buffer_for_playing_songs == 3 && sram_progress_indicator >= 2)
+ buffer_for_playing_songs = 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, sizeof(kMovableBlockDataInit));
+ memcpy(&movable_block_datas[99], kTorchDataInit, 116); // junk
+ memcpy(dung_torch_data, kTorchDataInit, sizeof(kTorchDataInit));
+ memcpy(&dung_torch_data[144], kTorchDataJunk, sizeof(kTorchDataJunk));
+
+ 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;
+ }
+ }
+ LinkHop_FindArbitraryLandingSpot();
+ 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 (savegame_tagalong)
+ 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;
+ LinkHop_FindArbitraryLandingSpot();
+ 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;
+ savegame_tagalong = 1;
+ } else {
+ savegame_tagalong = 6;
+ }
+ LoadFollowerGraphics();
+ savegame_tagalong = 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/dungeon.h
@@ -1,0 +1,459 @@
+#pragma once
+
+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,
+};
+
+struct DungPalInfo {
+ uint8 pal0;
+ uint8 pal1;
+ uint8 pal2;
+ uint8 pal3;
+};
+
+struct RoomBounds {
+ union {
+ struct {
+ uint16 a0, b0, a1, b1;
+ };
+ uint16 v[4];
+ };
+};
+
+#define room_bounds_y (*(RoomBounds*)(g_ram+0x600))
+#define room_bounds_x (*(RoomBounds*)(g_ram+0x608))
+
+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);
+uint8 GetEntranceMusicTrack(int entrance);
+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/ending.cpp
@@ -1,0 +1,2608 @@
+#include "zelda_rtl.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 "tables/generated_ending.h"
+#include "sprite_main.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 = 32;
+ zelda_ppu_write(OBSEL, 2);
+ load_chr_halfslot_even_odd = 20;
+ Graphics_LoadChrHalfSlot();
+ load_chr_halfslot_even_odd = 0;
+ LoadOWMusicIfNeeded();
+
+ zelda_ppu_write(VMAIN, 0x80);
+ zelda_ppu_write_word(VMADDL, 0x27f0);
+ int i = 16;
+ do {
+ zelda_ppu_write_word(VMDATAL, 0);
+ main_palette_buffer[144 + i] = 0x7fff;
+ } while (--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);
+ sprite_aux1_palette = dpi->pal2;
+ sprite_aux2_palette = dpi->pal3;
+ misc_sprites_graphics_index = 10;
+ InitializeTilesets();
+ palette_sp6 = 10;
+ Dungeon_LoadPalettes();
+ BGMODE_copy = 9;
+ R16 = 0;
+ INIDISP_copy = 0;
+ submodule_index++;
+ Credits_PrepAndLoadSprites();
+}
+
+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();
+ zelda_snes_dummy_write(NMITIMEN, 0);
+ LoadCreditsSongs();
+ zelda_snes_dummy_write(NMITIMEN, 0x81);
+ 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
+ zelda_ppu_write(SETINI, 0);
+ BGMODE_copy = 9;
+ MOSAIC_copy = 0;
+ zelda_ppu_write(BG1SC, 0x13);
+ zelda_ppu_write(BG2SC, 3);
+ zelda_ppu_write(BG3SC, 0x63);
+ zelda_ppu_write(BG12NBA, 0x22);
+ zelda_ppu_write(BG34NBA, 7);
+ 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
+ if (submodule_index >= 8 && ((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();
+ zelda_ppu_write(OBSEL, 2);
+ 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;
+ dung_hdr_palette_1 = 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_2();
+ 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 {
+ uint16 xcur = x + src->x;
+ uint16 ycur = y + src->y;
+ oam->x = xcur;
+ oam->y = ClampYForOam(ycur);
+ oam->charnum = src->charnum;
+ oam->flags = src->flags;
+ bytewise_extended_oam[oam - oam_buf] = src->ext | (xcur >> 8 & 1);
+ } 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_2();
+ 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_2();
+ 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 };
+ OamEnt *oam = oam_buf;
+ for (int i = 0; i < 4; i++) {
+ oam[i].x = kIntroLogo_X[i];
+ oam[i].y = 0x68;
+ oam[i].charnum = kIntroLogo_Tile[i];
+ oam[i].flags = 0x32;
+ bytewise_extended_oam[i] = 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] |= 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 };
+ bytewise_extended_oam[0x52 + j] = 2;
+ oam[j].charnum = kIntroSword_Char[j];
+ oam[j].flags = 0x21;
+ oam[j].x = kIntroSword_X[j];
+ uint16 y = intro_sword_ypos + kIntroSword_Y[j];
+ oam[j].y = ((y & 0xff00) ? 0xf8 : y) - 8;
+ }
+
+ 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 };
+ bytewise_extended_oam[0x50] = 0;
+ oam_buf[0x50].x = 0x44;
+ oam_buf[0x50].y = 0x43;
+ oam_buf[0x50].flags = 0x25;
+ oam_buf[0x50].charnum = kSwordSparkle_Char[intro_sword_19];
+ 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;
+ bytewise_extended_oam[0x50] = 0;
+ bytewise_extended_oam[0x51] = 0;
+ oam_buf[0x51].x = oam_buf[0x50].x = 0x42;
+
+ uint8 y = (intro_sword_21 < 0x50 ? intro_sword_21 : 0x4f) + intro_sword_ypos + 0x31;
+ oam_buf[0x50].y = y;
+ oam_buf[0x51].y = y + 8;
+ oam_buf[0x50].charnum = kIntroSwordSparkle_Char[k];
+ oam_buf[0x51].charnum = kIntroSwordSparkle_Char[k + 1];
+ oam_buf[0x51].flags = oam_buf[0x50].flags = 0x23;
+ 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, k;
+
+ 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;
+ zelda_ppu_write(BG2SC, 0x12);
+ 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)
+ zelda_ppu_write_word(BG1SC, 0x1300);
+ 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++;
+ }
+ }
+
+done:
+ 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
+ static const OamEntSigned kEndSequence37_Oams[4] = {
+ {-96, -72, 0x00, 0x3b},
+ {-80, -72, 0x02, 0x3b},
+ {-64, -72, 0x04, 0x3b},
+ {-48, -72, 0x06, 0x3b},
+ };
+ memcpy(oam_buf, kEndSequence37_Oams, 4 * 4);
+ bytewise_extended_oam[0] = bytewise_extended_oam[1] = bytewise_extended_oam[2] = bytewise_extended_oam[3] = 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/ending.h
@@ -1,0 +1,91 @@
+#pragma once
+
+struct IntroSpriteEnt {
+ int8 x, y;
+ uint8 charnum, flags;
+ uint8 ext;
+};
+
+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 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/hud.cpp
@@ -1,0 +1,1486 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include "zelda_rtl.h"
+
+#include "variables.h"
+#include "hud.h"
+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 };
+static const uint16 kHudItemInVramPtr[20] = {
+ 0x11c8, 0x11ce, 0x11d4, 0x11da,
+ 0x11e0, 0x1288, 0x128e, 0x1294,
+ 0x129a, 0x12a0, 0x1348, 0x134e,
+ 0x1354, 0x135a, 0x1360, 0x1408,
+ 0x140e, 0x1414, 0x141a, 0x1420,
+};
+static const uint16 kHudBottlesGfx[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 kHudItemBottles[9][4] = {
+ {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 uint16 kHudItemBow[5][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x28ba, 0x28e9, 0x28e8, 0x28cb},
+ {0x28ba, 0x284a, 0x2849, 0x28cb},
+ {0x28ba, 0x28e9, 0x28e8, 0x28cb},
+ {0x28ba, 0x28bb, 0x24ca, 0x28cb},
+};
+static const uint16 kHudItemBoomerang[3][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2cb8, 0x2cb9, 0x2cf5, 0x2cc9},
+ {0x24b8, 0x24b9, 0x24f5, 0x24c9},
+};
+static const uint16 kHudItemHookshot[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x24f5, 0x24f6, 0x24c0, 0x24f5},
+};
+static const uint16 kHudItemBombs[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2cb2, 0x2cb3, 0x2cc2, 0x6cc2},
+};
+static const uint16 kHudItemMushroom[3][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2444, 0x2445, 0x2446, 0x2447},
+ {0x203b, 0x203c, 0x203d, 0x203e},
+};
+static const uint16 kHudItemFireRod[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x24b0, 0x24b1, 0x24c0, 0x24c1},
+};
+static const uint16 kHudItemIceRod[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2cb0, 0x2cbe, 0x2cc0, 0x2cc1},
+};
+static const uint16 kHudItemBombos[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x287d, 0x287e, 0xe87e, 0xe87d},
+};
+static const uint16 kHudItemEther[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2876, 0x2877, 0xE877, 0xE876},
+};
+static const uint16 kHudItemQuake[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2866, 0x2867, 0xE867, 0xE866},
+};
+static const uint16 kHudItemTorch[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x24bc, 0x24bd, 0x24cc, 0x24cd},
+};
+static const uint16 kHudItemHammer[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x20b6, 0x20b7, 0x20c6, 0x20c7},
+};
+static const uint16 kHudItemFlute[4][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x20d0, 0x20d1, 0x20e0, 0x20e1},
+ {0x2cd4, 0x2cd5, 0x2ce4, 0x2ce5},
+ {0x2cd4, 0x2cd5, 0x2ce4, 0x2ce5},
+};
+static const uint16 kHudItemBugNet[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x3c40, 0x3c41, 0x2842, 0x3c43},
+};
+static const uint16 kHudItemBookMudora[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x3ca5, 0x3ca6, 0x3cd8, 0x3cd9},
+};
+static const uint16 kHudItemCaneSomaria[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x24dc, 0x24dd, 0x24ec, 0x24ed},
+};
+static const uint16 kHudItemCaneByrna[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2cdc, 0x2cdd, 0x2cec, 0x2ced},
+};
+static const uint16 kHudItemCape[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x24b4, 0x24b5, 0x24c4, 0x24c5},
+};
+static const uint16 kHudItemMirror[4][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x28de, 0x28df, 0x28ee, 0x28ef},
+ {0x2c62, 0x2c63, 0x2c72, 0x2c73},
+ {0x2886, 0x2887, 0x2888, 0x2889},
+};
+static const uint16 kHudItemGloves[3][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2130, 0x2131, 0x2140, 0x2141},
+ {0x28da, 0x28db, 0x28ea, 0x28eb},
+};
+static const uint16 kHudItemBoots[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x3429, 0x342a, 0x342b, 0x342c},
+};
+static const uint16 kHudItemFlippers[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2c9a, 0x2c9b, 0x2c9d, 0x2c9e},
+};
+static const uint16 kHudItemMoonPearl[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2433, 0x2434, 0x2435, 0x2436},
+};
+static const uint16 kHudItemEmpty[1][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+};
+static const uint16 kHudItemSword[5][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2c64, 0x2cce, 0x2c75, 0x3d25},
+ {0x2c8a, 0x2c65, 0x2474, 0x3d26},
+ {0x248a, 0x2465, 0x3c74, 0x2d48},
+ {0x288a, 0x2865, 0x2c74, 0x2d39},
+};
+static const uint16 kHudItemShield[4][4] = {
+ {0x24f5, 0x24f5, 0x24f5, 0x24f5},
+ {0x2cfd, 0x6cfd, 0x2cfe, 0x6cfe},
+ {0x34ff, 0x74ff, 0x349f, 0x749f},
+ {0x2880, 0x2881, 0x288d, 0x288e},
+};
+static const uint16 kHudItemArmor[5][4] = {
+ {0x3c68, 0x7c68, 0x3c78, 0x7c78},
+ {0x2c68, 0x6c68, 0x2c78, 0x6c78},
+ {0x2468, 0x6468, 0x2478, 0x6478},
+};
+static const uint16 kHudItemDungeonCompass[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x24bf, 0x64bf, 0x2ccf, 0x6ccf},
+};
+static const uint16 kHudItemPalaceItem[3][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x28d6, 0x68d6, 0x28e6, 0x28e7},
+ {0x354b, 0x354c, 0x354d, 0x354e},
+};
+static const uint16 kHudItemDungeonMap[2][4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x28de, 0x28df, 0x28ee, 0x28ef},
+};
+static const uint16 kHudPendants0[2][4] = {
+ {0x313b, 0x313c, 0x313d, 0x313e},
+ {0x252b, 0x252c, 0x252d, 0x252e}
+};
+static const uint16 kHudPendants1[2][4] = {
+ {0x313b, 0x313c, 0x313d, 0x313e},
+ {0x2d2b, 0x2d2c, 0x2d2d, 0x2d2e}
+};
+static const uint16 kHudPendants2[2][4] = {
+ {0x313b, 0x313c, 0x313d, 0x313e},
+ {0x3d2b, 0x3d2c, 0x3d2d, 0x3d2e}
+};
+static const uint16 kHudItemHeartPieces[4][4] = {
+ {0x2484, 0x6484, 0x2485, 0x6485},
+ {0x24ad, 0x6484, 0x2485, 0x6485},
+ {0x24ad, 0x6484, 0x24ae, 0x6485},
+ {0x24ad, 0x64ad, 0x24ae, 0x6485},
+};
+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,
+};
+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 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,
+};
+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,
+};
+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 kHudTilemap[165] = {
+ 0x207f, 0x207f, 0x2850, 0xa856, 0x2852, 0x285b, 0x285b, 0x285c, 0x207f, 0x3ca8, 0x207f, 0x207f, 0x2c88, 0x2c89, 0x207f, 0x20a7, 0x20a9, 0x207f, 0x2871, 0x207f, 0x207f, 0x207f, 0x288b, 0x288f, 0x24ab, 0x24ac, 0x688f, 0x688b, 0x207f, 0x207f, 0x207f, 0x207f,
+ 0x207f, 0x207f, 0x2854, 0x2871, 0x2858, 0x207f, 0x207f, 0x285d, 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, 0x2854, 0x304e, 0x2858, 0x207f, 0x207f, 0x285d, 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, 0x2854, 0x305e, 0x2859, 0xa85b, 0xa85b, 0xa85c, 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, 0x2854, 0x305e, 0x6854, 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, 0xa850, 0x2856, 0xe850,
+};
+const uint16 *const kHudItemBoxGfxPtrs[] = {
+ kHudItemBow[0],
+ kHudItemBoomerang[0],
+ kHudItemHookshot[0],
+ kHudItemBombs[0],
+ kHudItemMushroom[0],
+ kHudItemFireRod[0],
+ kHudItemIceRod[0],
+ kHudItemBombos[0],
+ kHudItemEther[0],
+ kHudItemQuake[0],
+ kHudItemTorch[0],
+ kHudItemHammer[0],
+ kHudItemFlute[0],
+ kHudItemBugNet[0],
+ kHudItemBookMudora[0],
+ kHudItemBottles[0],
+ kHudItemCaneSomaria[0],
+ kHudItemCaneByrna[0],
+ kHudItemCape[0],
+ kHudItemMirror[0],
+ kHudItemGloves[0],
+ kHudItemBoots[0],
+ kHudItemFlippers[0],
+ kHudItemMoonPearl[0],
+ kHudItemEmpty[0],
+ kHudItemSword[0],
+ kHudItemShield[0],
+ kHudItemArmor[0],
+ kHudItemBottles[0],
+ kHudItemBottles[0],
+ kHudItemBottles[0],
+ kHudItemBottles[0],
+};
+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;
+ }
+}
+
+void Hud_GotoPrevItem() {
+ if (--hud_cur_item < 1)
+ hud_cur_item = 20;
+}
+
+void Hud_GotoNextItem() {
+ if (++hud_cur_item >= 21)
+ hud_cur_item = 1;
+}
+
+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];
+
+}
+
+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 {
+ if (++a >= 1000)
+ link_rupees_goal = a = 999;
+ }
+ 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) {
+ 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_IgnoreHealth();
+ Hud_AnimateHeartRefill();
+ flag_update_hud_in_nmi++;
+ return;
+ }
+ link_health_current = link_health_capacity;
+ link_hearts_filler = 0;
+ }
+ Hud_Update_IgnoreItemBox();
+ 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++;
+}
+
+void Hud_Init() { // 8dddab
+ Hud_SearchForEquippedItem();
+
+ Hud_DrawYButtonItems(Hud_GetPaletteMask(1));
+ Hud_DrawUnknownBox(Hud_GetPaletteMask(1));
+
+ Hud_DrawAbilityText(Hud_GetPaletteMask(1));
+ Hud_DrawAbilityIcons();
+ Hud_DrawProgressIcons();
+ Hud_DrawMoonPearl();
+
+ Hud_DrawEquipment(Hud_GetPaletteMask(1));
+ Hud_DrawShield();
+ Hud_DrawArmor();
+ Hud_DrawMapAndBigKey();
+ Hud_DrawCompass();
+
+ uint8 or_all = 0;
+ for (int i = 0; i < 20; i++)
+ or_all |= (&link_item_bow)[i];
+
+ if (or_all) {
+ uint8 or_bottle = link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3];
+ if (or_bottle == 0) {
+ link_item_bottles = 0;
+ } else if (!link_item_bottles) {
+ uint8 bottle_pos = 1;
+ if (!link_bottle_info[0]) {
+ bottle_pos++;
+ if (!link_bottle_info[1]) {
+ bottle_pos++;
+ if (!link_bottle_info[2])
+ bottle_pos++;
+ }
+ }
+ link_item_bottles = bottle_pos;
+ }
+
+ if (!Hud_DoWeHaveThisItem())
+ Hud_EquipNextItem();
+
+ Hud_DrawSelectedYButtonItem();
+ if (hud_cur_item == 16) {
+ Hud_DrawBottleMenu(Hud_GetPaletteMask(1));
+ }
+ }
+
+ 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
+ uint8 or_all = 0;
+ for (int i = 0; i < 20; i++)
+ or_all |= (&link_item_bow)[i];
+
+ if (or_all != 0) {
+ nmi_subroutine_index = 1;
+ BYTE(nmi_load_target_addr) = 0x22;
+ if (!Hud_DoWeHaveThisItem())
+ Hud_EquipNextItem();
+
+ Hud_DrawSelectedYButtonItem();
+ overworld_map_state = 4;
+ if (hud_cur_item == 16)
+ overworld_map_state = 10;
+ } else {
+ if (filtered_joypad_H)
+ overworld_map_state = 5;
+ }
+}
+
+bool Hud_DoWeHaveThisItem() { // 8ddeb0
+ return (&link_item_bow)[hud_cur_item - 1] != 0;
+}
+
+void Hud_EquipPrevItem() { // 8dded9
+ do {
+ Hud_GotoPrevItem();
+ } while (!Hud_DoWeHaveThisItem());
+}
+
+void Hud_EquipNextItem() { // 8ddee2
+ do {
+ Hud_GotoNextItem();
+ } while (!Hud_DoWeHaveThisItem());
+}
+
+void Hud_EquipItemAbove() { // 8ddeeb
+ do {
+ Hud_GotoPrevItem();
+ Hud_GotoPrevItem();
+ Hud_GotoPrevItem();
+ Hud_GotoPrevItem();
+ Hud_GotoPrevItem();
+ } while (!Hud_DoWeHaveThisItem());
+}
+
+void Hud_EquipItemBelow() { // 8ddf00
+ do {
+ Hud_GotoNextItem();
+ Hud_GotoNextItem();
+ Hud_GotoNextItem();
+ Hud_GotoNextItem();
+ Hud_GotoNextItem();
+ } while (!Hud_DoWeHaveThisItem());
+}
+
+void Hud_NormalMenu() { // 8ddf15
+ timer_for_flashing_circle++;
+ if (!BYTE(joypad1H_last))
+ BYTE(tmp1) = 0;
+
+ if (filtered_joypad_H & 0x10) {
+ overworld_map_state = 5;
+ sound_effect_2 = 18;
+ return;
+ }
+
+ if (!BYTE(tmp1)) {
+ uint16 old_item = hud_cur_item;
+ if (filtered_joypad_H & 8) {
+ Hud_EquipItemAbove();
+ } else if (filtered_joypad_H & 4) {
+ Hud_EquipItemBelow();
+ } else if (filtered_joypad_H & 2) {
+ Hud_EquipPrevItem();
+ } else if (filtered_joypad_H & 1) {
+ Hud_EquipNextItem();
+ }
+ BYTE(tmp1) = filtered_joypad_H;
+ if (hud_cur_item != old_item) {
+ timer_for_flashing_circle = 16;
+ sound_effect_2 = 32;
+ }
+ }
+ Hud_DrawYButtonItems(Hud_GetPaletteMask(1));
+ Hud_DrawSelectedYButtonItem();
+ if (hud_cur_item == 16)
+ 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_UpdateOnly();
+ Hud_UpdateEquippedItem();
+}
+
+void Hud_UpdateEquippedItem() { // 8ddfaf
+ static const uint8 kHudItemToItem[21] = { 0, 3, 2, 14, 1, 10, 5, 6, 15, 16, 17, 9, 4, 8, 7, 12, 11, 18, 13, 19, 20 };
+ assert(hud_cur_item < 21);
+ eq_selected_y_item = kHudItemToItem[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 (eq_selected_y_item != 5 && eq_selected_y_item != 6) {
+ eq_debug_variable = 2;
+ link_debug_value_1 = 0;
+ } else {
+ assert(!link_debug_value_1);
+ eq_debug_variable = 0;
+ }
+}
+
+void Hud_GotoBottleMenu() { // 8ddffb
+ byte_7E0205 = 0;
+ overworld_map_state++;
+}
+
+void Hud_InitBottleMenu() { // 8de002
+ int r = byte_7E0205;
+ for (int i = 21; i <= 30; i++)
+ uvram_screen.row[11 + r].col[i] = 0x207f;
+
+ if (++byte_7E0205 == 19) {
+ overworld_map_state++;
+ byte_7E0205 = 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 = byte_7E0205;
+ for (int i = 0; i < 10; i++)
+ uvram_screen.row[11 + r].col[21 + i] = kBottleMenuTop[i];
+
+ for (int i = 0; i < 10; i++)
+ uvram_screen.row[12 + r].col[21 + i] = kBottleMenuTop2[i];
+
+ for (int i = 0; i < 10; i++)
+ uvram_screen.row[29].col[21 + i] = kBottleMenuBottom[i];
+
+ if (sign8(--byte_7E0205))
+ 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 & 0x10) {
+ sound_effect_2 = 18;
+ overworld_map_state = 5;
+ } else if (filtered_joypad_H & 3) {
+ if (filtered_joypad_H & 2) {
+ Hud_EquipPrevItem();
+ } else {
+ Hud_EquipNextItem();
+ }
+ timer_for_flashing_circle = 16;
+ sound_effect_2 = 32;
+ Hud_DrawYButtonItems(Hud_GetPaletteMask(1));
+ Hud_DrawSelectedYButtonItem();
+ overworld_map_state++;
+ byte_7E0205 = 0;
+ return;
+ }
+ Hud_UpdateBottleMenu();
+ if (filtered_joypad_H & 12) {
+ uint8 old_val = link_item_bottles - 1, val = old_val;
+
+ if (filtered_joypad_H & 8) {
+ 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_bottles = val + 1;
+ timer_for_flashing_circle = 16;
+ sound_effect_2 = 32;
+ }
+ }
+}
+
+void Hud_UpdateBottleMenu() { // 8de17f
+
+ for (int y = 12; y <= 28; y++)
+ for (int x = 0; x < 8; x++)
+ uvram_screen.row[y].col[22 + x] = 0x24f5;
+
+ Hud_DrawItem(0x1372, kHudItemBottles[link_bottle_info[0]]);
+ Hud_DrawItem(0x1472, kHudItemBottles[link_bottle_info[1]]);
+ Hud_DrawItem(0x1572, kHudItemBottles[link_bottle_info[2]]);
+ Hud_DrawItem(0x1672, kHudItemBottles[link_bottle_info[3]]);
+ Hud_DrawItem(0x1408, kHudItemBottles[link_item_bottles ? link_bottle_info[link_item_bottles - 1] : 0]);
+
+ uint16 *p = (uint16 *)&g_ram[kHudItemInVramPtr[hud_cur_item - 1]];
+ uvram_screen.row[6].col[25] = p[0];
+ uvram_screen.row[6].col[26] = p[1];
+ uvram_screen.row[7].col[25] = p[32];
+ uvram_screen.row[7].col[26] = p[33];
+
+ if (timer_for_flashing_circle & 0x10) {
+ int o = ((link_item_bottles - 1) * 0x100 + 0x88) / 2;
+
+ uvram_screen.row[10].col[21 + o] = 0x3C61;
+ uvram_screen.row[10].col[22 + o] = 0x3C61 | 0x4000;
+
+ uvram_screen.row[11].col[20 + o] = 0x3C70;
+ uvram_screen.row[11].col[23 + o] = 0x3C70 | 0x4000;
+
+ uvram_screen.row[12].col[20 + o] = 0xBC70;
+ uvram_screen.row[12].col[23 + o] = 0xBC70 | 0x4000;
+
+ uvram_screen.row[13].col[21 + o] = 0xBC61;
+ uvram_screen.row[13].col[22 + o] = 0xBC61 | 0x4000;
+
+ uvram_screen.row[10].col[20 + o] = 0x3C60;
+ uvram_screen.row[10].col[23 + o] = 0x3C60 | 0x4000;
+
+ uvram_screen.row[13].col[23 + o] = 0x3C60 | 0xC000;
+ uvram_screen.row[13].col[20 + o] = 0x3C60 | 0x8000;
+ }
+
+ if (link_item_bottles) {
+ const uint16 *src = kHudBottlesGfx + (link_bottle_info[link_item_bottles - 1] - 1) * 16;
+ for (int i = 0; i < 8; i++) {
+ uvram_screen.row[8].col[22 + i] = src[i];
+ uvram_screen.row[9].col[22 + i] = src[i + 8];
+ }
+ }
+
+ nmi_subroutine_index = 1;
+ BYTE(nmi_load_target_addr) = 0x22;
+}
+
+void Hud_EraseBottleMenu() { // 8de2fd
+ int r = byte_7E0205;
+ for (int i = 0; i < 10; i++)
+ uvram_screen.row[11 + r].col[21 + i] = 0x207f;
+ if (++byte_7E0205 == 19)
+ overworld_map_state++;
+ nmi_subroutine_index = 1;
+ BYTE(nmi_load_target_addr) = 0x22;
+}
+
+void Hud_RestoreNormalMenu() { // 8de346
+ Hud_DrawProgressIcons();
+ Hud_DrawMoonPearl();
+ Hud_DrawEquipment(Hud_GetPaletteMask(1));
+ Hud_DrawShield();
+ Hud_DrawArmor();
+ Hud_DrawMapAndBigKey();
+ Hud_DrawCompass();
+
+ overworld_map_state = 4;
+ nmi_subroutine_index = 1;
+ BYTE(nmi_load_target_addr) = 0x22;
+}
+
+void Hud_DrawItem(uint16 a, const uint16 *src) { // 8de372
+ uint16 *dst = (uint16 *)&g_ram[a];
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[32] = src[2];
+ dst[33] = src[3];
+}
+
+void Hud_SearchForEquippedItem() { // 8de399
+ uint8 or_all = 0;
+ for (int i = 0; i < 20; i++)
+ or_all |= (&link_item_bow)[i];
+
+ if (or_all == 0) {
+ hud_cur_item = 0;
+ hud_cur_item_hi = 0;
+ hud_var1 = 0;
+ } else {
+ if (!hud_cur_item)
+ hud_cur_item = 1;
+ if (!Hud_DoWeHaveThisItem())
+ Hud_EquipNextItem();
+ }
+}
+
+uint16 Hud_GetPaletteMask(uint8 what) { // 8de3c8
+ return what == 0 ? 0xe3ff : 0xffff;
+}
+
+void Hud_DrawYButtonItems(uint16 mask) { // 8de3d9
+ uint16 t;
+
+ t = 0x3CFB & mask;
+ uvram_screen.row[5].col[1] = t;
+ uvram_screen.row[19].col[1] = (t |= 0x8000);
+ uvram_screen.row[19].col[19] = (t |= 0x4000);
+ uvram_screen.row[5].col[19] = (t ^= 0x8000);
+
+ for (int i = 6; i < 19; i++) {
+ uvram_screen.row[i].col[1] = (t = 0x3cfc & mask);
+ uvram_screen.row[i].col[19] = (t |= 0x4000);
+ }
+
+ for (int i = 2; i < 19; i++) {
+ uvram_screen.row[5].col[i] = (t = 0x3CF9 & mask);
+ uvram_screen.row[19].col[i] = (t |= 0x8000);
+ }
+
+ for (int y = 6; y < 19; y++) {
+ for (int x = 2; x < 19; x++)
+ uvram_screen.row[y].col[x] = 0x24F5;
+ }
+ uvram_screen.row[6].col[2] = 0x3CF0;
+ uvram_screen.row[7].col[2] = 0x3CF1;
+ uvram_screen.row[5].col[3] = 0x246E;
+ uvram_screen.row[5].col[4] = 0x246F;
+
+ Hud_DrawItem(0x11c8, kHudItemBow[link_item_bow]);
+ Hud_DrawItem(0x11ce, kHudItemBoomerang[link_item_boomerang]);
+ Hud_DrawItem(0x11d4, kHudItemHookshot[link_item_hookshot]);
+ Hud_DrawItem(0x11da, kHudItemBombs[link_item_bombs ? 1 : 0]);
+ Hud_DrawItem(0x11e0, kHudItemMushroom[link_item_mushroom]);
+ Hud_DrawItem(0x1288, kHudItemFireRod[link_item_fire_rod]);
+ Hud_DrawItem(0x128e, kHudItemIceRod[link_item_ice_rod]);
+ Hud_DrawItem(0x1294, kHudItemBombos[link_item_bombos_medallion]);
+ Hud_DrawItem(0x129a, kHudItemEther[link_item_ether_medallion]);
+ Hud_DrawItem(0x12a0, kHudItemQuake[link_item_quake_medallion]);
+ Hud_DrawItem(0x1348, kHudItemTorch[link_item_torch]);
+ Hud_DrawItem(0x134e, kHudItemHammer[link_item_hammer]);
+ Hud_DrawItem(0x1354, kHudItemFlute[link_item_flute]);
+ Hud_DrawItem(0x135a, kHudItemBugNet[link_item_bug_net]);
+ Hud_DrawItem(0x1360, kHudItemBookMudora[link_item_book_of_mudora]);
+ Hud_DrawItem(0x1408, kHudItemBottles[link_item_bottles ? link_bottle_info[link_item_bottles - 1] : 0]);
+ Hud_DrawItem(0x140e, kHudItemCaneSomaria[link_item_cane_somaria]);
+ Hud_DrawItem(0x1414, kHudItemCaneByrna[link_item_cane_byrna]);
+ Hud_DrawItem(0x141a, kHudItemCape[link_item_cape]);
+ Hud_DrawItem(0x1420, kHudItemMirror[link_item_mirror]);
+}
+
+void Hud_DrawUnknownBox(uint16 palmask) { // 8de647
+ uint16 t;
+
+ t = 0x3CFB & palmask;
+ uvram_screen.row[5].col[21] = t;
+ uvram_screen.row[10].col[21] = (t |= 0x8000);
+ uvram_screen.row[10].col[30] = (t |= 0x4000);
+ uvram_screen.row[5].col[30] = (t ^= 0x8000);
+
+ t = 0x3CFC & palmask;
+ for (int i = 0; i < 4; i++) {
+ uvram_screen.row[6 + i].col[21] = t;
+ uvram_screen.row[6 + i].col[30] = t | 0x4000;
+ }
+
+ t = 0x3CF9 & palmask;
+ for (int i = 0; i < 8; i++) {
+ uvram_screen.row[5].col[22 + i] = t;
+ uvram_screen.row[10].col[22 + i] = t | 0x8000;
+ }
+
+ for (int i = 0; i < 8; i++) {
+ uvram_screen.row[6].col[22 + i] = 0x24F5;
+ uvram_screen.row[7].col[22 + i] = 0x24F5;
+ uvram_screen.row[8].col[22 + i] = 0x24F5;
+ uvram_screen.row[9].col[22 + i] = 0x24F5;
+ }
+}
+
+void Hud_DrawAbilityText(uint16 palmask) { // 8de6b6
+ for (int i = 0; i < 17; i++) {
+ uvram_screen.row[22].col[2 + i] = 0x24F5;
+ uvram_screen.row[23].col[2 + i] = 0x24F5;
+ uvram_screen.row[24].col[2 + i] = 0x24F5;
+ uvram_screen.row[25].col[2 + i] = 0x24F5;
+ uvram_screen.row[26].col[2 + i] = 0x24F5;
+ uvram_screen.row[27].col[2 + i] = 0x24F5;
+ uvram_screen.row[28].col[2 + i] = 0x24F5;
+ }
+
+ uint8 flags = link_ability_flags;
+ const uint16 *src = kHudAbilityText;
+ uint16 *dst = &uvram_screen.row[22].col[4];
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 4; j++) {
+ if (flags & 0x80) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[32 + 0] = src[5];
+ dst[32 + 1] = src[6];
+ dst[32 + 2] = src[7];
+ dst[32 + 3] = src[8];
+ dst[32 + 4] = src[9];
+ }
+ src += 10;
+ dst += 5;
+ flags <<= 1;
+ }
+ dst += 2 * 32 - 5 * 4;
+ }
+
+ uint16 t;
+
+ t = 0x24FB & palmask;
+ uvram_screen.row[21].col[1] = t;
+ uvram_screen.row[29].col[1] = (t |= 0x8000);
+ uvram_screen.row[29].col[19] = (t |= 0x4000);
+ uvram_screen.row[21].col[19] = (t ^= 0x8000);
+
+ t = 0x24FC & palmask;
+ for (int i = 0; i < 7; i++) {
+ uvram_screen.row[22 + i].col[1] = t;
+ uvram_screen.row[22 + i].col[19] = t | 0x4000;
+ }
+
+ t = 0x24F9 & palmask;
+ for (int i = 0; i < 17; i++) {
+ uvram_screen.row[21].col[2 + i] = t;
+ uvram_screen.row[29].col[2 + i] = t | 0x8000;
+ }
+
+ uvram_screen.row[22].col[2] = 0xA4F0;
+ uvram_screen.row[23].col[2] = 0x24F2;
+ uvram_screen.row[21].col[3] = 0x2482;
+ uvram_screen.row[21].col[4] = 0x2483;
+}
+
+void Hud_DrawAbilityIcons() { // 8de7b7
+ Hud_DrawItem(0x16D0, kHudItemGloves[link_item_gloves]);
+ Hud_DrawItem(0x16C8, kHudItemBoots[link_item_boots]);
+ Hud_DrawItem(0x16D8, kHudItemFlippers[link_item_flippers]);
+ if (link_item_gloves)
+ Hud_DrawGlovesText(link_item_gloves != 1);
+}
+
+void Hud_DrawGlovesText(uint8 idx) { // 8de81a
+ const uint16 *src = kHudGlovesText + idx * 10;
+ uint16 *dst = &uvram_screen.row[22].col[4];
+ memcpy(dst, src, sizeof(uint16) * 5);
+ memcpy(dst + 32, src + 5, sizeof(uint16) * 5);
+}
+
+void Hud_DrawProgressIcons() { // 8de9c8
+ if (sram_progress_indicator < 3)
+ Hud_DrawProgressIcons_Pendants();
+ else
+ Hud_DrawProgressIcons_Crystals();
+}
+
+void Hud_DrawProgressIcons_Pendants() { // 8de9d3
+ const uint16 *src = kProgressIconPendantsBg;
+ for (int y = 0; y < 9; y++) {
+ memcpy(&uvram_screen.row[11 + y].col[21], src, sizeof(uint16) * 10);
+ src += 10;
+ }
+
+ Hud_DrawItem(0x13B2, kHudPendants0[(link_which_pendants >> 0) & 1]);
+ Hud_DrawItem(0x146E, kHudPendants1[(link_which_pendants >> 1) & 1]);
+ Hud_DrawItem(0x1476, kHudPendants2[(link_which_pendants >> 2) & 1]);
+}
+
+void Hud_DrawProgressIcons_Crystals() { // 8dea62
+ const uint16 *src = kProgressIconCrystalsBg;
+ for (int y = 0; y < 9; y++, src += 10)
+ memcpy(&uvram_screen.row[11 + y].col[21], src, sizeof(uint16) * 10);
+
+ uint8 f = link_has_crystals;
+ if (f & 1) {
+ uvram_screen.row[14].col[24] = 0x2D44;
+ uvram_screen.row[14].col[25] = 0x2D45;
+ }
+ if (f & 2) {
+ uvram_screen.row[14].col[26] = 0x2D44;
+ uvram_screen.row[14].col[27] = 0x2D45;
+ }
+ if (f & 4) {
+ uvram_screen.row[16].col[23] = 0x2D44;
+ uvram_screen.row[16].col[24] = 0x2D45;
+ }
+ if (f & 8) {
+ uvram_screen.row[16].col[25] = 0x2D44;
+ uvram_screen.row[16].col[26] = 0x2D45;
+ }
+ if (f & 16) {
+ uvram_screen.row[16].col[27] = 0x2D44;
+ uvram_screen.row[16].col[28] = 0x2D45;
+ }
+ if (f & 32) {
+ uvram_screen.row[18].col[24] = 0x2D44;
+ uvram_screen.row[18].col[25] = 0x2D45;
+ }
+ if (f & 64) {
+ uvram_screen.row[18].col[26] = 0x2D44;
+ uvram_screen.row[18].col[27] = 0x2D45;
+ }
+}
+
+void Hud_DrawSelectedYButtonItem() { // 8deb3a
+ uint16 *p = (uint16 *)&g_ram[kHudItemInVramPtr[hud_cur_item - 1]];
+ uvram_screen.row[6].col[25] = p[0];
+ uvram_screen.row[6].col[26] = p[1];
+ uvram_screen.row[7].col[25] = p[32];
+ uvram_screen.row[7].col[26] = p[33];
+
+ if (timer_for_flashing_circle & 0x10) {
+ p[-32] = 0x3C61;
+ p[-31] = 0x3C61 | 0x4000;
+
+ p[-1] = 0x3C70;
+ p[2] = 0x3C70 | 0x4000;
+
+ p[31] = 0xBC70;
+ p[34] = 0xBC70 | 0x4000;
+
+ p[64] = 0xBC61;
+ p[65] = 0xBC61 | 0x4000;
+
+ p[-33] = 0x3C60;
+ p[-30] = 0x3C60 | 0x4000;
+
+ p[66] = 0x3C60 | 0xC000;
+ p[63] = 0x3C60 | 0x8000;
+ }
+
+ const uint16 *src_p;
+
+ if (hud_cur_item == 16 && link_item_bottles) {
+ src_p = &kHudBottlesItemText[(link_bottle_info[link_item_bottles - 1] - 1) * 16];
+ } else if (hud_cur_item == 5 && link_item_mushroom != 1) {
+ src_p = &kHudMushroomItemText[(link_item_mushroom - 2) * 16];
+ } else if (hud_cur_item == 20 && link_item_mirror != 1) {
+ src_p = &kHudMirrorItemText[(link_item_mirror - 2) * 16];
+ } else if (hud_cur_item == 13 && link_item_flute != 1) {
+ src_p = &kHudFluteItemText[(link_item_flute - 2) * 16];
+ } else if (hud_cur_item == 1 && link_item_bow != 1) {
+ src_p = &kHudBowItemText[(link_item_bow - 2) * 16];
+ } else {
+ src_p = &kHudItemText[(hud_cur_item - 1) * 16];
+ }
+ memcpy(&uvram_screen.row[8].col[22], src_p + 0, sizeof(uint16) * 8);
+ memcpy(&uvram_screen.row[9].col[22], src_p + 8, sizeof(uint16) * 8);
+}
+
+void Hud_DrawMoonPearl() { // 8dece9
+ Hud_DrawItem(0x16e0, kHudItemMoonPearl[link_item_moon_pearl]);
+}
+
+void Hud_DrawEquipment(uint16 palmask) { // 8ded29
+ uint16 t = palmask & 0x28FB;
+ uvram_screen.row[21].col[21] = t | 0x0000;
+ uvram_screen.row[29].col[21] = t | 0x8000;
+ uvram_screen.row[29].col[30] = t | 0xC000;
+ uvram_screen.row[21].col[30] = t | 0x4000;
+
+ t = 0x28FC & palmask;
+ for (int i = 0; i < 7; i++) {
+ uvram_screen.row[22 + i].col[21] = t;
+ uvram_screen.row[22 + i].col[30] = t | 0x4000;
+ }
+
+ t = 0x28F9 & palmask;
+ for (int i = 0; i < 8; i++) {
+ uvram_screen.row[21].col[22 + i] = t;
+ uvram_screen.row[29].col[22 + i] = t | 0x8000;
+ }
+
+ for (int i = 0; i < 7; i++) {
+ for (int j = 0; j < 8; j++)
+ uvram_screen.row[22 + i].col[22 + j] = 0x24F5;
+ }
+
+ // Draw dotted lines
+ t = 0x28D7 & palmask;
+ for (int i = 0; i < 8; i++)
+ uvram_screen.row[25].col[22 + i] = t;
+
+ static const uint16 kHudEquipmentDungeonItemText[16] = {
+ 0x2479, 0x247a, 0x247b, 0x247c, 0x248c, 0x24f5, 0x24f5, 0x24f5,
+ 0x2469, 0x246a, 0x246b, 0x246c, 0x246d, 0x246e, 0x246f, 0x24f5,
+ };
+
+ for (int i = 0; i < 8; i++) {
+ uvram_screen.row[22].col[22 + i] = kHudEquipmentDungeonItemText[i + 0] & palmask;
+ uvram_screen.row[26].col[22 + i] = kHudEquipmentDungeonItemText[i + 8] & palmask;
+ }
+ if (cur_palace_index_x2 == 0xff) {
+ for (int i = 0; i < 8; i++)
+ uvram_screen.row[26].col[22 + i] = 0x24F5;
+ Hud_DrawItem(0x16f2, kHudItemHeartPieces[link_heart_pieces]);
+ }
+ Hud_DrawItem(0x15ec, kHudItemSword[link_sword_type == 0xff ? 0 : link_sword_type]);
+}
+
+void Hud_DrawShield() { // 8dee21
+ Hud_DrawItem(0x15f2, kHudItemShield[link_shield_type]);
+}
+
+void Hud_DrawArmor() { // 8dee3c
+ Hud_DrawItem(0x15f8, kHudItemArmor[link_armor]);
+}
+
+void Hud_DrawMapAndBigKey() { // 8dee57
+ if (cur_palace_index_x2 != 0xff &&
+ (link_bigkey << (cur_palace_index_x2 >> 1)) & 0x8000) {
+ Hud_DrawItem(0x16F8, kHudItemPalaceItem[CheckPalaceItemPosession() + 1]);
+ }
+ if (cur_palace_index_x2 != 0xff &&
+ (link_dungeon_map << (cur_palace_index_x2 >> 1)) & 0x8000) {
+ Hud_DrawItem(0x16EC, kHudItemDungeonMap[1]);
+ }
+}
+
+void Hud_DrawCompass() { // 8def39
+ if (cur_palace_index_x2 != 0xff &&
+ (link_compass << (cur_palace_index_x2 >> 1)) & 0x8000) {
+ Hud_DrawItem(0x16F2, kHudItemDungeonCompass[1]);
+ }
+}
+
+void Hud_DrawBottleMenu(uint16 palmask) { // 8def67
+ uint16 t = 0x28FB & palmask;
+ uvram_screen.row[11].col[21] = t;
+ uvram_screen.row[29].col[21] = t | 0x8000;
+ uvram_screen.row[29].col[30] = t | 0xC000;
+ uvram_screen.row[11].col[30] = t | 0x4000;
+
+ t = 0x28FC & palmask;
+ for (int i = 0; i < 17; i++) {
+ uvram_screen.row[12 + i].col[21] = t;
+ uvram_screen.row[12 + i].col[30] = t | 0x4000;
+ }
+ t = 0x28F9 & palmask;
+ for (int i = 0; i < 8; i++) {
+ uvram_screen.row[11].col[22 + i] = t;
+ uvram_screen.row[29].col[22 + i] = t | 0x8000;
+ }
+ for (int y = 12; y <= 28; y++)
+ for (int x = 0; x < 8; x++)
+ uvram_screen.row[y].col[22 + x] = 0x24f5;
+
+ Hud_DrawItem(0x1372, kHudItemBottles[link_bottle_info[0]]);
+ Hud_DrawItem(0x1472, kHudItemBottles[link_bottle_info[1]]);
+ Hud_DrawItem(0x1572, kHudItemBottles[link_bottle_info[2]]);
+ Hud_DrawItem(0x1672, kHudItemBottles[link_bottle_info[3]]);
+ Hud_DrawItem(0x1408, kHudItemBottles[link_bottle_info[link_item_bottles - 1]]);
+
+ uint16 *p = (uint16 *)&g_ram[kHudItemInVramPtr[hud_cur_item - 1]];
+
+ uvram_screen.row[6].col[25] = p[0];
+ uvram_screen.row[6].col[26] = p[1];
+ uvram_screen.row[7].col[25] = p[32];
+ uvram_screen.row[7].col[26] = p[33];
+
+ int o = ((link_item_bottles - 1) * 0x100 + 0x88) / 2;
+
+ uvram_screen.row[10].col[21 + o] = 0x3C61;
+ uvram_screen.row[10].col[22 + o] = 0x3C61 | 0x4000;
+
+ uvram_screen.row[11].col[20 + o] = 0x3C70;
+ uvram_screen.row[11].col[23 + o] = 0x3C70 | 0x4000;
+
+ uvram_screen.row[12].col[20 + o] = 0xBC70;
+ uvram_screen.row[12].col[23 + o] = 0xBC70 | 0x4000;
+
+ uvram_screen.row[13].col[21 + o] = 0xBC61;
+ uvram_screen.row[13].col[22 + o] = 0xBC61 | 0x4000;
+
+ uvram_screen.row[10].col[20 + o] = 0x3C60;
+ uvram_screen.row[10].col[23 + o] = 0x3C60 | 0x4000;
+
+ uvram_screen.row[13].col[23 + o] = 0x3C60 | 0xC000;
+ uvram_screen.row[13].col[20 + o] = 0x3C60 | 0x8000;
+
+ timer_for_flashing_circle = 16;
+}
+
+void Hud_IntToDecimal(unsigned int number, uint8 *out) { // 8df0f7
+ out[0] = number / 100 + 0x90;
+ out[1] = (number %= 100) / 10 + 0x90;
+ out[2] = (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 + 0x34;
+ 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();
+}
+
+void Hud_Rebuild() { // 8dfa70
+ memcpy(hud_tile_indices_buffer, kHudTilemap, 165 * sizeof(uint16));
+ Hud_UpdateInternal();
+ flag_update_hud_in_nmi++;
+}
+
+void Hud_UpdateOnly() { // 8dfa85
+ Hud_UpdateInternal();
+ flag_update_hud_in_nmi++;
+}
+
+void Hud_UpdateItemBox() { // 8dfafd
+ if (link_item_bow) {
+ if (link_item_bow >= 3) {
+ hud_tile_indices_buffer[15] = 0x2486;
+ hud_tile_indices_buffer[16] = 0x2487;
+ link_item_bow = link_num_arrows ? 4 : 3;
+ } else {
+ link_item_bow = link_num_arrows ? 2 : 1;
+ }
+ }
+
+ if (!hud_cur_item)
+ return;
+
+ uint8 item_val = (&link_item_bow)[hud_cur_item - 1];
+ if (hud_cur_item == 4)
+ item_val = 1;
+ else if (hud_cur_item == 16)
+ item_val = link_bottle_info[item_val - 1];
+
+ const uint16 *p = kHudItemBoxGfxPtrs[hud_cur_item - 1] + item_val * 4;
+
+ hud_tile_indices_buffer[37] = p[0];
+ hud_tile_indices_buffer[38] = p[1];
+ hud_tile_indices_buffer[37 + 32] = p[2];
+ hud_tile_indices_buffer[38 + 32] = p[3];
+}
+
+void Hud_UpdateInternal() { // 8dfb91
+ Hud_UpdateItemBox();
+ Hud_Update_IgnoreItemBox();
+}
+
+void Hud_Update_IgnoreItemBox() { // 8dfb94
+ static const uint16 kHudItemBoxTab1[] = { 0x24A2, 0x24A2, 0x24A2 };
+ static const uint16 kHudItemBoxTab2[] = { 0x24A2, 0x24A1, 0x24A0 };
+
+ Hud_UpdateHearts(&hud_tile_indices_buffer[0x34], kHudItemBoxTab1, link_health_capacity);
+ Hud_UpdateHearts(&hud_tile_indices_buffer[0x34], kHudItemBoxTab2, (link_health_current + 3) & ~3);
+
+ Hud_Update_IgnoreHealth();
+}
+
+void Hud_Update_IgnoreHealth() { // 8dfc09
+ if (link_magic_consumption >= 1) {
+ hud_tile_indices_buffer[2] = 0x28F7;
+ hud_tile_indices_buffer[3] = 0x2851;
+ hud_tile_indices_buffer[4] = 0x28FA;
+ }
+
+ const uint16 *src = kUpdateMagicPowerTilemap[(link_magic_power + 7) >> 3];
+ hud_tile_indices_buffer[0x23] = src[0];
+ hud_tile_indices_buffer[0x43] = src[1];
+ hud_tile_indices_buffer[0x63] = src[2];
+ hud_tile_indices_buffer[0x83] = src[3];
+
+ uint8 d[3];
+
+ Hud_IntToDecimal(link_rupees_actual, d);
+ hud_tile_indices_buffer[0x28] = 0x2400 | d[0];
+ hud_tile_indices_buffer[0x29] = 0x2400 | d[1];
+ hud_tile_indices_buffer[0x2A] = 0x2400 | d[2];
+
+ Hud_IntToDecimal(link_item_bombs, d);
+ hud_tile_indices_buffer[0x2C] = 0x2400 | d[1];
+ hud_tile_indices_buffer[0x2D] = 0x2400 | d[2];
+
+ Hud_IntToDecimal(link_num_arrows, d);
+ hud_tile_indices_buffer[0x2F] = 0x2400 | d[1];
+ hud_tile_indices_buffer[0x30] = 0x2400 | d[2];
+
+ d[2] = 0x7f;
+ if (link_num_keys != 0xff)
+ Hud_IntToDecimal(link_num_keys, d);
+ hud_tile_indices_buffer[0x32] = 0x2400 | d[2];
+ if (hud_tile_indices_buffer[0x32] == 0x247f)
+ hud_tile_indices_buffer[0x12] = hud_tile_indices_buffer[0x32];
+}
+
+void Hud_UpdateHearts(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;
+ }
+}
+
--- /dev/null
+++ b/hud.h
@@ -1,0 +1,72 @@
+#pragma once
+#include "types.h"
+
+
+
+
+
+
+
+
+extern const uint16 *const kHudItemBoxGfxPtrs[];
+void Hud_RefreshIcon();
+uint8 CheckPalaceItemPosession();
+void Hud_GotoPrevItem();
+void Hud_GotoNextItem();
+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();
+bool Hud_DoWeHaveThisItem();
+void Hud_EquipPrevItem();
+void Hud_EquipNextItem();
+void Hud_EquipItemAbove();
+void Hud_EquipItemBelow();
+void Hud_NormalMenu();
+void Hud_UpdateHud();
+void Hud_UpdateEquippedItem();
+void Hud_CloseMenu();
+void Hud_GotoBottleMenu();
+void Hud_InitBottleMenu();
+void Hud_ExpandBottleMenu();
+void Hud_BottleMenu();
+void Hud_UpdateBottleMenu();
+void Hud_EraseBottleMenu();
+void Hud_RestoreNormalMenu();
+void Hud_DrawItem(uint16 a, const uint16 *src);
+void Hud_SearchForEquippedItem();
+uint16 Hud_GetPaletteMask(uint8 what);
+void Hud_DrawYButtonItems(uint16 mask);
+void Hud_DrawUnknownBox(uint16 palmask);
+void Hud_DrawAbilityText(uint16 palmask);
+void Hud_DrawAbilityIcons();
+void Hud_DrawGlovesText(uint8 idx);
+void Hud_DrawProgressIcons();
+void Hud_DrawProgressIcons_Pendants();
+void Hud_DrawProgressIcons_Crystals();
+void Hud_DrawSelectedYButtonItem();
+void Hud_DrawMoonPearl();
+void Hud_DrawEquipment(uint16 palmask);
+void Hud_DrawShield();
+void Hud_DrawArmor();
+void Hud_DrawMapAndBigKey();
+void Hud_DrawCompass();
+void Hud_DrawBottleMenu(uint16 palmask);
+void Hud_IntToDecimal(unsigned int number, uint8 *out);
+bool Hud_RefillHealth();
+void Hud_AnimateHeartRefill();
+bool Hud_RefillMagicPower();
+void Hud_RestoreTorchBackground();
+void Hud_RebuildIndoor();
+void Hud_Rebuild();
+void Hud_UpdateOnly();
+void Hud_UpdateItemBox();
+void Hud_UpdateInternal();
+void Hud_Update_IgnoreItemBox();
+void Hud_Update_IgnoreHealth();
+void Hud_UpdateHearts(uint16 *dst, const uint16 *src, int n);
--- /dev/null
+++ b/load_gfx.cpp
@@ -1,0 +1,2163 @@
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "snes_regs.h"
+#include "overworld.h"
+#include "load_gfx.h"
+#include "player.h"
+#include "tables/generated_images.h"
+#include "tables/generated_font.h"
+#include "tables/generated_palettes.h"
+#include "sprite.h"
+
+static const uint16 kGlovesColor[2] = {0x52f6, 0x376};
+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};
+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};
+const uint16 *GetFontPtr() {
+ return kFontData;
+}
+static const uint8 *GetCompSpritePtr(int i) {
+ return kSprGfx[i];
+}
+
+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);
+}
+
+void DecompAndUpload2bpp(uint8 pack) {
+ Decomp_spr(&g_ram[0x14000], pack);
+ const uint8 *src = &g_ram[0x14000];
+ for (int i = 0; i < 1024; i++, src += 2)
+ zelda_ppu_write_word(VMDATAL, WORD(src[0]));
+}
+
+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
+ zelda_ppu_write(INIDISP, 0x80);
+ INIDISP_copy = 0x80;
+ zelda_snes_dummy_write(HDMAEN, 0);
+ 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 (savegame_tagalong != 1) {
+ yv = 0x66;
+ if (savegame_tagalong >= 9) {
+ yv = 0x59;
+ if (savegame_tagalong >= 12)
+ yv = 0x58;
+ }
+ }
+ Decomp_spr(&g_ram[0x14600], yv);
+ Decomp_spr(&g_ram[0x14000], 0x65);
+ Do3To4Low16Bit(&g_ram[0x9000] + 0x2940, &g_ram[0x14000 + kTagalongWhich[savegame_tagalong]], 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;
+
+ 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
+ zelda_ppu_write(VMAIN, 0x80);
+ zelda_ppu_write_word(VMADDL, 0x4400);
+ 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(sprite_gfx_subset_0, &g_ram[0x7800]);
+ LoadSpriteGraphics(sprite_gfx_subset_1, &g_ram[0x7e00]);
+ LoadSpriteGraphics(sprite_gfx_subset_2, &g_ram[0x8400]);
+ LoadSpriteGraphics(sprite_gfx_subset_3, &g_ram[0x8a00]);
+
+ zelda_ppu_write_word(VMADDL, 0x2000);
+
+ 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(mt[0], 7, &g_ram[0x14000]);
+ LoadBackgroundGraphics(mt[1], 6, &g_ram[0x14000]);
+ LoadBackgroundGraphics(mt[2], 5, &g_ram[0x14000]);
+ LoadBackgroundGraphics(aux_bg_subset_0, 4, &g_ram[0x6000]);
+ LoadBackgroundGraphics(aux_bg_subset_1, 3, &g_ram[0x6600]);
+ LoadBackgroundGraphics(aux_bg_subset_2, 2, &g_ram[0x6c00]);
+ LoadBackgroundGraphics(aux_bg_subset_3, 1, &g_ram[0x7200]);
+ LoadBackgroundGraphics(mt[7], 0, &g_ram[0x14000]);
+}
+
+void LoadDefaultGraphics() { // 80e2d0
+ zelda_ppu_write(VMAIN, 0x80);
+ zelda_ppu_write_word(VMADDL, 0x4000);
+ const uint8 *src = GetCompSpritePtr(0);
+
+ uint16 *tmp = (uint16 *)&g_ram[0xbf];
+ int num = 64;
+ do {
+ for (int i = 7; i >= 0; i--, src += 2) {
+ zelda_ppu_write_word(VMDATAL, WORD(src[0]));
+ tmp[i] = src[0] | src[1];
+ }
+ for (int i = 7; i >= 0; i--, src++) {
+ zelda_ppu_write_word(VMDATAL, src[0] | (src[0] | tmp[i]) << 8);
+ }
+ } while (--num);
+
+ // Load 2bpp graphics used for hud
+ zelda_ppu_write_word(VMADDL, 0x7000);
+ DecompAndUpload2bpp(0x6a);
+ DecompAndUpload2bpp(0x6b);
+ DecompAndUpload2bpp(0x69);
+}
+
+void Attract_LoadBG3GFX() { // 80e36d
+ // load 2bpp gfx for attract images
+ zelda_ppu_write(VMAIN, 0x80);
+ zelda_ppu_write(VMADDL, 0);
+ zelda_ppu_write(VMADDH, 0x78);
+ DecompAndUpload2bpp(0x67);
+}
+
+void LoadCommonSprites_2() { // 80e384
+ zelda_ppu_write(VMAIN, 0x80);
+ zelda_ppu_write(VMADDL, 0);
+ zelda_ppu_write(VMADDH, 0x44);
+ LoadCommonSprites();
+}
+
+void Graphics_LoadChrHalfSlot() { // 80e3fa
+ int k = load_chr_halfslot_even_odd;
+ if (k == 0)
+ return;
+
+ int8 sp6 = kGraphicsLoadSp6[k - 1];
+ if (sp6 >= 0) {
+ palette_sp6 = sp6;
+ if (k == 1) {
+ palette_sp6 = 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
+ zelda_ppu_write(OBSEL, 2);
+ zelda_ppu_write(VMAIN, 0x80);
+ zelda_ppu_write_word(VMADDL, 0x7000);
+ const uint16 *src = GetFontPtr();
+ for (int i = 0; i != 0x800; i++, src++)
+ zelda_ppu_write_word(VMDATAL, *src);
+}
+
+void LoadSpriteGraphics(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(decomp_addr);
+ else
+ Do3To4Low(decomp_addr);
+}
+
+void Do3To4High(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;
+ zelda_ppu_write_word(VMDATAL, d);
+ }
+ for (int i = 7; i >= 0; i--, decomp_addr += 1) {
+ uint8 d = *decomp_addr;
+ zelda_ppu_write_word(VMDATAL, d | (t[i] | d) << 8);
+ }
+ }
+}
+
+void LoadBackgroundGraphics(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(decomp_addr);
+ else
+ Do3To4Low(decomp_addr);
+}
+
+void Do3To4Low(const uint8 *decomp_addr) { // 80e63c
+ for (int j = 0; j < 64; j++) {
+ for (int i = 0; i < 8; i++, decomp_addr += 2)
+ zelda_ppu_write_word(VMDATAL, *(uint16 *)decomp_addr);
+ for (int i = 0; i < 8; i++, decomp_addr += 1)
+ zelda_ppu_write_word(VMDATAL, *decomp_addr);
+ }
+}
+
+void LoadCommonSprites() { // 80e6b7
+ Do3To4High(GetCompSpritePtr(misc_sprites_graphics_index));
+ if (main_module_index != 1) {
+ Do3To4Low(GetCompSpritePtr(6));
+ Do3To4Low(GetCompSpritePtr(7));
+ } else {
+ // select file
+ LoadSpriteGraphics(94, &g_ram[0x14000]);
+ LoadSpriteGraphics(95, &g_ram[0x14000]);
+ }
+}
+
+int Decomp_spr(uint8 *dst, int gfx) { // 80e772
+ return Decompress(dst, kSprGfx[gfx]);
+}
+
+int Decomp_bg(uint8 *dst, int gfx) { // 80e78f
+ return Decompress(dst, kBgGfx[gfx]);
+}
+
+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
+ if (subsubmodule_index == 0) {
+ memcpy(main_palette_buffer + 0x40, aux_palette_buffer + 0x40, 16);
+ 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(0x40, 0x48);
+ 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 < 32 * 7; i++)
+ mode7_hdma_table[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 r10 = r6 - r14;
+ uint16 r4 = r14 - r10;
+ for(;;) {
+ uint16 r8 = 0xff;
+ if (r6 < spotlight_y_upper) {
+ uint8 t = spotlight_var4;
+ if (spotlight_var4)
+ spotlight_var4--;
+ r8 = IrisSpotlight_CalculateCircleValue(t);
+ }
+ if (r4 < 0xe0)
+ hdma_table[r4] = r8;
+ if (r6 < 0xe0)
+ hdma_table[r6] = r8;
+ if (r4 == r14)
+ break;
+ r4++, r6--;
+ }
+
+ memcpy(mode7_hdma_table, hdma_table, 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;
+ zelda_ppu_write(INIDISP, 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 (buffer_for_playing_songs != 0xff)
+ music_control = buffer_for_playing_songs;
+ }
+ main_module_index = saved_module_for_menu;
+ if (main_module_index == 6)
+ Sprite_ResetAll();
+}
+
+void IrisSpotlight_ResetTable() { // 80f427
+ for (int i = 0; i < 224; i++)
+ mode7_hdma_table[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 < 224)
+ mode7_hdma_table[r4] = (a != 0xffff) ? a : 0xff;
+ }
+ if (r6 >= spotlight_y_upper) {
+ a = 0xff;
+ } else {
+ if (r6 >= 225 && word_7E0678)
+ word_7E0678--;
+ a = r12;
+ }
+ if (r6 < 224)
+ mode7_hdma_table[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 {
+ mode7_hdma_table[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) {
+ mode7_hdma_table[r4] = 0xff;
+ } else {
+ uint16 a = r4;
+ do {
+ a *= 2;
+ } while (a >= 448);
+ mode7_hdma_table[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 (overworld_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_SpritePal0Left();
+ Palette_Load_SpriteAux1();
+ Palette_Load_SpriteAux2();
+ 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_sp6 = 5;
+ overworld_palette_sp0 = 11;
+ overworld_palette_swap_flag = 0;
+ overworld_palette_aux_or_main = 0;
+ Palette_BgAndFixedColor_Black();
+ Palette_Load_SpritePal0Left();
+ 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_SpritePal0Left();
+ Palette_Load_SpriteMain();
+ Palette_Load_SpriteAux1();
+ Palette_Load_SpriteAux2();
+ 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 = dung_hdr_palette_1;
+ 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_SpriteAux1();
+ Palette_Load_SpriteAux2();
+ Palette_Load_Sword();
+ Palette_Load_Shield();
+ Palette_Load_LinkArmorAndGloves();
+ overworld_palette_sp0 = (savegame_is_darkworld & 0x40) ? 3 : 1;
+ Palette_Load_SpritePal0Left();
+ 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)
+ sprite_aux1_palette = d[0];
+ if (d[1] >= 0)
+ sprite_aux2_palette = d[1];
+ Palette_Load_OWBG1();
+ Palette_Load_OWBG2();
+ Palette_Load_OWBG3();
+ Palette_Load_SpriteAux1();
+ Palette_Load_SpriteAux2();
+}
+
+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
+ overworld_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);
+}
+
+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 r = (c & 0x1f) + 14;
+ if (r > 0x1f) r = 0x1f;
+ int g = (c & 0x3e0) + 0x1c0;
+ if (g > 0x3e0) g = 0x3e0;
+ int b = (c & 0x7c00) + 0x3800;
+ 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();
+}
+
+void Palette_Load_SpritePal0Left() { // 9bec77
+ const uint16 *src = kPalette_SpriteAux3 + overworld_palette_sp0 * 7;
+ Palette_LoadSingle(src, overworld_palette_swap_flag ? 0x1e2 : 0x102, 6);
+}
+
+void Palette_Load_SpriteMain() { // 9bec9e
+ const uint16 *src = kPalette_MainSpr + (overworld_screen_index & 0x40 ? 60 : 0);
+ Palette_LoadMultiple(src, 0x122, 14, 3);
+}
+
+void Palette_Load_SpriteAux1() { // 9becc5
+ const uint16 *src = kPalette_SpriteAux1 + (sprite_aux1_palette) * 7;
+ Palette_LoadSingle(src, 0x1A2, 6);
+}
+
+void Palette_Load_SpriteAux2() { // 9bece4
+ const uint16 *src = kPalette_SpriteAux1 + (sprite_aux2_palette) * 7;
+ Palette_LoadSingle(src, 0x1C2, 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, 0x1b2, 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, 0x1b8, 3);
+ flag_update_cgram_in_nmi += 1;
+}
+
+void Palette_Load_SpriteEnvironment() { // 9bed6e
+ if (player_is_indoors)
+ Palette_Load_SpriteEnvironment_Dungeon();
+ else
+ Palette_MiscSprite_Outdoors();
+}
+
+void Palette_Load_SpriteEnvironment_Dungeon() { // 9bed72
+ const uint16 *src = kPalette_MiscSprite_Indoors + palette_sp6 * 7;
+ Palette_LoadSingle(src, 0x1d2, 6);
+}
+
+void Palette_MiscSprite_Outdoors() { // 9bed91
+ int t = (overworld_screen_index & 0x40) ? 9 : 7;
+ const uint16 *src = kPalette_MiscSprite_Indoors + t * 7;
+ Palette_LoadSingle(src, overworld_palette_swap_flag ? 0x1f2 : 0x112, 6);
+ src = kPalette_MiscSprite_Indoors + (t - 1) * 7;
+ Palette_LoadSingle(src, 0x1d2, 6);
+}
+
+void Palette_Load_DungeonMapSprite() { // 9beddd
+ Palette_LoadMultiple(kPalette_PalaceMapSpr, 0x182, 6, 2);
+}
+
+void Palette_Load_LinkArmorAndGloves() { // 9bedf9
+ const uint16 *src = kPalette_ArmorAndGloves + link_armor * 15;
+ Palette_LoadMultiple_Arbitrary(src, 0x1e2, 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 + (dung_hdr_palette_1 >> 1) * 90;
+ Palette_LoadMultiple(src, 0x42, 14, 5);
+ Palette_LoadSingle(src, overworld_palette_swap_flag ? 0x1f2 : 0x112, 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/load_gfx.h
@@ -1,0 +1,162 @@
+#pragma once
+
+enum {
+ kSrmOffs_Gloves = 0x354,
+ kSrmOffs_Sword = 0x359,
+ kSrmOffs_Shield = 0x35a,
+ kSrmOffs_Armor = 0x35b,
+ kSrmOffs_DiedCounter = 0x405,
+ kSrmOffs_Name = 0x3d9,
+ kSrmOffs_Health = 0x36c,
+};
+
+const uint16 *GetFontPtr();
+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 DecompAndUpload2bpp(uint8 pack);
+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 LoadCommonSprites_2();
+void Graphics_LoadChrHalfSlot();
+void TransferFontToVRAM();
+void LoadSpriteGraphics(int gfx_pack, uint8 *decomp_addr);
+void Do3To4High(const uint8 *decomp_addr);
+void LoadBackgroundGraphics(int gfx_pack, int slot, uint8 *decomp_addr);
+void Do3To4Low(const 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_SpritePal0Left();
+void Palette_Load_SpriteMain();
+void Palette_Load_SpriteAux1();
+void Palette_Load_SpriteAux2();
+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();
--- /dev/null
+++ b/main.cpp
@@ -1,0 +1,342 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <SDL.h>
+
+#include "snes/snes.h"
+#include "tracing.h"
+
+#include "types.h"
+#include "variables.h"
+
+#include "zelda_rtl.h"
+
+extern uint8 g_emulated_ram[0x20000];
+bool g_run_without_emu = false;
+
+void PatchRom(uint8_t *rom);
+void SetSnes(Snes *snes);
+void RunAudioPlayer();
+void CopyStateAfterSnapshotRestore(bool is_reset);
+void SaveLoadSlot(int cmd, int which);
+void PatchCommand(char cmd);
+bool RunOneFrame(Snes *snes, int input_state, bool turbo);
+
+static uint8_t* readFile(char* name, size_t* length);
+static bool loadRom(char* name, Snes* snes);
+static bool checkExtention(const char* name, bool forZip);
+static void playAudio(Snes *snes, SDL_AudioDeviceID device, int16_t* audioBuffer);
+static void renderScreen(SDL_Renderer* renderer, SDL_Texture* texture);
+static void handleInput(int keyCode, int modCode, bool pressed);
+
+int input1_current_state;
+
+void setButtonState(int button, bool pressed) {
+ // set key in constroller
+ if (pressed) {
+ input1_current_state |= 1 << button;
+ } else {
+ input1_current_state &= ~(1 << button);
+ }
+}
+
+
+#undef main
+int main(int argc, char** argv) {
+ // set up SDL
+ if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
+ printf("Failed to init SDL: %s\n", SDL_GetError());
+ return 1;
+ }
+ SDL_Window* window = SDL_CreateWindow("Zelda3", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 512, 480, 0);
+ if(window == NULL) {
+ printf("Failed to create window: %s\n", SDL_GetError());
+ return 1;
+ }
+ SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
+ if(renderer == NULL) {
+ printf("Failed to create renderer: %s\n", SDL_GetError());
+ return 1;
+ }
+ SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBX8888, SDL_TEXTUREACCESS_STREAMING, 512, 480);
+ if(texture == NULL) {
+ printf("Failed to create texture: %s\n", SDL_GetError());
+ return 1;
+ }
+ 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 1;
+ }
+ int16_t* audioBuffer = (int16_t * )malloc(735 * 4); // *2 for stereo, *2 for sizeof(int16)
+ SDL_PauseAudioDevice(device, 0);
+
+ Snes *snes = snes_init(g_emulated_ram), *snes_run = NULL;
+ if (argc >= 2 && !g_run_without_emu) {
+ // init snes, load rom
+ bool loaded = loadRom(argv[1], snes);
+ if (!loaded) {
+ puts("No rom loaded");
+ return 1;
+ }
+ snes_run = snes;
+ } else {
+ snes_reset(snes, true);
+ }
+ SetSnes(snes);
+ ZeldaInitialize();
+ bool hooks = true;
+ // sdl loop
+ bool running = true;
+ SDL_Event event;
+ uint32_t lastTick = SDL_GetTicks();
+ uint32_t curTick = 0;
+ uint32_t delta = 0;
+ int numFrames = 0;
+ bool cpuNext = false;
+ bool spcNext = false;
+ int counter = 0;
+ bool paused = false;
+ bool turbo = true;
+ uint32_t frameCtr = 0;
+
+ printf("%d\n", *(int *)snes->cart->ram);
+
+ while(running) {
+ while(SDL_PollEvent(&event)) {
+ switch(event.type) {
+ case SDL_KEYDOWN: {
+ switch(event.key.keysym.sym) {
+ case SDLK_e:
+ if (snes) {
+ snes_reset(snes, event.key.keysym.sym == SDLK_e);
+ CopyStateAfterSnapshotRestore(true);
+ }
+ break;
+ case SDLK_p: paused ^= true; break;
+ case SDLK_w:
+ PatchCommand('w');
+ break;
+ case SDLK_o:
+ PatchCommand('o');
+ break;
+ case SDLK_k:
+ PatchCommand('k');
+ break;
+ case SDLK_t:
+ turbo = !turbo;
+ break;
+ }
+ 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 (paused) {
+ SDL_Delay(16);
+ continue;
+ }
+
+ bool is_turbo = RunOneFrame(snes_run, input1_current_state, (counter++ & 0x7f) != 0 && turbo);
+
+ if (is_turbo)
+ continue;
+
+ ZeldaDrawPpuFrame();
+
+ playAudio(snes_run, device, audioBuffer);
+ renderScreen(renderer, texture);
+
+ SDL_RenderPresent(renderer); // vsyncs to 60 FPS
+ // if vsync isn't working, delay manually
+ curTick = SDL_GetTicks();
+
+ static const uint8 delays[3] = { 17, 17, 16 }; // 60 fps
+#if 1
+ lastTick += delays[frameCtr++ % 3];
+
+ if (lastTick > curTick) {
+ delta = lastTick - curTick;
+ if (delta > 500) {
+ lastTick = curTick - 500;
+ delta = 500;
+ }
+ SDL_Delay(delta);
+ } else if (curTick - lastTick > 500) {
+ lastTick = curTick;
+ }
+#endif
+ }
+ // clean snes
+ snes_free(snes);
+ // clean sdl
+ SDL_PauseAudioDevice(device, 1);
+ SDL_CloseAudioDevice(device);
+ free(audioBuffer);
+ SDL_DestroyTexture(texture);
+ SDL_DestroyRenderer(renderer);
+ SDL_DestroyWindow(window);
+ SDL_Quit();
+ return 0;
+}
+
+extern struct Ppu *GetPpuForRendering();
+extern struct Dsp *GetDspForRendering();
+
+static void playAudio(Snes *snes, SDL_AudioDeviceID device, int16_t* audioBuffer) {
+ // generate enough samples
+ if (!kIsOrigEmu && snes) {
+ while (snes->apu->dsp->sampleOffset < 534)
+ apu_cycle(snes->apu);
+ snes->apu->dsp->sampleOffset = 0;
+ }
+
+ dsp_getSamples(GetDspForRendering(), audioBuffer, 735);
+ if(SDL_GetQueuedAudioSize(device) <= 735 * 4 * 6) {
+ // don't queue audio if buffer is still filled
+ SDL_QueueAudio(device, audioBuffer, 735 * 4);
+ } else {
+ printf("Skipping audio!\n");
+ }
+}
+
+static void renderScreen(SDL_Renderer* renderer, SDL_Texture* texture) {
+ void* pixels = NULL;
+ int pitch = 0;
+ if(SDL_LockTexture(texture, NULL, &pixels, &pitch) != 0) {
+ printf("Failed to lock texture: %s\n", SDL_GetError());
+ return;
+ }
+
+ ppu_putPixels(GetPpuForRendering(), (uint8_t*) pixels);
+ SDL_UnlockTexture(texture);
+ SDL_RenderCopy(renderer, texture, NULL, NULL);
+}
+
+
+static void handleInput(int keyCode, int keyMod, bool pressed) {
+ switch(keyCode) {
+ case SDLK_z: setButtonState(0, pressed); break;
+ case SDLK_a: setButtonState(1, pressed); break;
+ case SDLK_RSHIFT: setButtonState(2, pressed); break;
+ case SDLK_RETURN: setButtonState(3, pressed); break;
+ case SDLK_UP: setButtonState(4, pressed); break;
+ case SDLK_DOWN: setButtonState(5, pressed); break;
+ case SDLK_LEFT: setButtonState(6, pressed); break;
+ case SDLK_RIGHT: setButtonState(7, pressed); break;
+ case SDLK_x: setButtonState(8, pressed); break;
+ case SDLK_s: setButtonState(9, pressed); break;
+ case SDLK_d: setButtonState(10, pressed); break;
+ case SDLK_c: setButtonState(11, pressed); break;
+ case SDLK_BACKSPACE:
+ case SDLK_1:
+ case SDLK_2:
+ case SDLK_3:
+ case SDLK_4:
+ case SDLK_5:
+ case SDLK_6:
+ case SDLK_7:
+ case SDLK_8:
+ case SDLK_9:
+ case SDLK_0:
+ case SDLK_MINUS:
+ case SDLK_EQUALS:
+ if (pressed) {
+ SaveLoadSlot(
+ (keyMod & KMOD_CTRL) != 0 ? kSaveLoad_Replay : kSaveLoad_Load,
+ 256 + (keyCode == SDLK_0 ? 9 :
+ keyCode == SDLK_MINUS ? 10 :
+ keyCode == SDLK_EQUALS ? 11 :
+ keyCode == SDLK_BACKSPACE ? 12 :
+ keyCode - SDLK_1));
+ }
+ break;
+
+ case SDLK_F1:
+ case SDLK_F2:
+ case SDLK_F3:
+ case SDLK_F4:
+ case SDLK_F5:
+ case SDLK_F6:
+ case SDLK_F7:
+ case SDLK_F8:
+ case SDLK_F9:
+ case SDLK_F10:
+ if (pressed) {
+ SaveLoadSlot(
+ (keyMod & KMOD_CTRL) != 0 ? kSaveLoad_Replay :
+ (keyMod & KMOD_SHIFT) != 0 ? kSaveLoad_Save : kSaveLoad_Load,
+ keyCode - SDLK_F1);
+ }
+ break;
+ }
+}
+
+static bool checkExtention(const char* name, bool forZip) {
+ if(name == NULL) return false;
+ int length = strlen(name);
+ if(length < 4) return false;
+ if(forZip) {
+ if(strcmp(name + length - 4, ".zip") == 0) return true;
+ if(strcmp(name + length - 4, ".ZIP") == 0) return true;
+ } else {
+ if(strcmp(name + length - 4, ".smc") == 0) return true;
+ if(strcmp(name + length - 4, ".SMC") == 0) return true;
+ if(strcmp(name + length - 4, ".sfc") == 0) return true;
+ if(strcmp(name + length - 4, ".SFC") == 0) return true;
+ }
+ return false;
+}
+
+static bool loadRom(char* name, Snes* snes) {
+ // zip library from https://github.com/kuba--/zip
+ size_t length = 0;
+ uint8_t* file = NULL;
+ file = readFile(name, &length);
+ if(file == NULL) {
+ puts("Failed to read file");
+ return false;
+ }
+
+ PatchRom(file);
+
+ bool result = snes_loadRom(snes, file, length);
+ free(file);
+ return result;
+}
+
+static uint8_t* readFile(char* name, size_t* length) {
+ FILE* f = fopen(name, "rb");
+ if(f == NULL) {
+ return NULL;
+ }
+ fseek(f, 0, SEEK_END);
+ int size = ftell(f);
+ rewind(f);
+ uint8_t* buffer = (uint8_t *)malloc(size);
+ fread(buffer, size, 1, f);
+ fclose(f);
+ *length = size;
+ return buffer;
+}
--- /dev/null
+++ b/messaging.cpp
@@ -1,0 +1,3071 @@
+#include "messaging.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "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 "tables/generated_dialogue.h"
+#include "tables/generated_overworld_map.h"
+#include "tables/generated_dungeon_map.h"
+
+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_Ptrs27[14] = {0xfc00, 0xfc08, 0xfc15, 0xfc21, 0xfc2b, 0xfc32, 0xfc3f, 0xfc4d, 0xfc5f, 0xfc68, 0xfc7d, 0xfc83, 0xfc8f, 0xfca0};
+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 uint8 kTextDictionary[] = {
+ 0x59, 0x59, 0x59, 0x59,
+ 0x59, 0x59, 0x59,
+ 0x59, 0x59,
+ 0x51, 0x2c, 0x59,
+ 0x1a, 0x27, 0x1d, 0x59,
+ 0x1a, 0x2b, 0x1e, 0x59,
+ 0x1a, 0x25, 0x25, 0x59,
+ 0x1a, 0x22, 0x27,
+ 0x1a, 0x27, 0x1d,
+ 0x1a, 0x2d, 0x59,
+ 0x1a, 0x2c, 0x2d,
+ 0x1a, 0x27,
+ 0x1a, 0x2d,
+ 0x1b, 0x25, 0x1e,
+ 0x1b, 0x1a,
+ 0x1b, 0x1e,
+ 0x1b, 0x28,
+ 0x1c, 0x1a, 0x27, 0x59,
+ 0x1c, 0x21, 0x1e,
+ 0x1c, 0x28, 0x26,
+ 0x1c, 0x24,
+ 0x1d, 0x1e, 0x2c,
+ 0x1d, 0x22,
+ 0x1d, 0x28,
+ 0x1e, 0x27, 0x59,
+ 0x1e, 0x2b, 0x59,
+ 0x1e, 0x1a, 0x2b,
+ 0x1e, 0x27, 0x2d,
+ 0x1e, 0x1d, 0x59,
+ 0x1e, 0x27,
+ 0x1e, 0x2b,
+ 0x1e, 0x2f,
+ 0x1f, 0x28, 0x2b,
+ 0x1f, 0x2b, 0x28,
+ 0x20, 0x22, 0x2f, 0x1e, 0x59,
+ 0x20, 0x1e, 0x2d,
+ 0x20, 0x28,
+ 0x21, 0x1a, 0x2f, 0x1e,
+ 0x21, 0x1a, 0x2c,
+ 0x21, 0x1e, 0x2b,
+ 0x21, 0x22,
+ 0x21, 0x1a,
+ 0x22, 0x20, 0x21, 0x2d, 0x59,
+ 0x22, 0x27, 0x20, 0x59,
+ 0x22, 0x27,
+ 0x22, 0x2c,
+ 0x22, 0x2d,
+ 0x23, 0x2e, 0x2c, 0x2d,
+ 0x24, 0x27, 0x28, 0x30,
+ 0x25, 0x32, 0x59,
+ 0x25, 0x1a,
+ 0x25, 0x28,
+ 0x26, 0x1a, 0x27,
+ 0x26, 0x1a,
+ 0x26, 0x1e,
+ 0x26, 0x2e,
+ 0x27, 0x51, 0x2d, 0x59,
+ 0x27, 0x28, 0x27,
+ 0x27, 0x28, 0x2d,
+ 0x28, 0x29, 0x1e, 0x27,
+ 0x28, 0x2e, 0x27, 0x1d,
+ 0x28, 0x2e, 0x2d, 0x59,
+ 0x28, 0x1f,
+ 0x28, 0x27,
+ 0x28, 0x2b,
+ 0x29, 0x1e, 0x2b,
+ 0x29, 0x25, 0x1e,
+ 0x29, 0x28, 0x30,
+ 0x29, 0x2b, 0x28,
+ 0x2b, 0x1e, 0x59,
+ 0x2b, 0x1e,
+ 0x2c, 0x28, 0x26, 0x1e,
+ 0x2c, 0x1e,
+ 0x2c, 0x21,
+ 0x2c, 0x28,
+ 0x2c, 0x2d,
+ 0x2d, 0x1e, 0x2b, 0x59,
+ 0x2d, 0x21, 0x22, 0x27,
+ 0x2d, 0x1e, 0x2b,
+ 0x2d, 0x21, 0x1a,
+ 0x2d, 0x21, 0x1e,
+ 0x2d, 0x21, 0x22,
+ 0x2d, 0x28,
+ 0x2d, 0x2b,
+ 0x2e, 0x29,
+ 0x2f, 0x1e, 0x2b,
+ 0x30, 0x22, 0x2d, 0x21,
+ 0x30, 0x1a,
+ 0x30, 0x1e,
+ 0x30, 0x21,
+ 0x30, 0x22,
+ 0x32, 0x28, 0x2e,
+ 0x7, 0x1e, 0x2b,
+ 0x13, 0x21, 0x1a,
+ 0x13, 0x21, 0x1e,
+ 0x13, 0x21, 0x22,
+ 0x18, 0x28, 0x2e,
+};
+static const uint16 kTextDictionary_Idx[] = {
+ 0, 4, 7, 9, 12, 16, 20, 24, 27, 30, 33, 36, 38, 40, 43, 45, 47, 49, 53, 56, 59, 61, 64, 66, 68, 71, 74, 77, 80, 83, 85, 87, 89, 92, 95, 100, 103, 105, 109, 112, 115, 117, 119, 124, 128, 130, 132, 134, 138, 142, 145, 147, 149, 152, 154, 156, 158, 162, 165, 168, 172, 176, 180, 182, 184, 186, 189, 192, 195, 198, 201, 203, 207, 209, 211, 213, 215, 219, 223, 226, 229, 232, 235, 237, 239, 241, 244, 248, 250, 252, 254, 256, 259, 262, 265, 268, 271, 274
+};
+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 uint8 kVWF_RenderCharacter_widths[99] = {
+ 6, 6, 6, 6, 6, 6, 6, 6, 3, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 7, 6, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 3, 5, 6, 3, 7, 6, 6, 6, 6, 5, 6, 6, 6, 7, 7, 7, 7, 6, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 3, 7,
+ 6, 4, 4, 6, 8, 6, 6, 6, 6, 6, 8, 8, 8, 7, 7, 7, 7, 4, 8, 8, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 8, 8,
+ 8, 8, 4,
+};
+static const uint16 kVWF_RowPositions[3] = {0, 2, 4};
+static const uint16 kVWF_LinePositions[3] = {0, 40, 80};
+static const uint16 kVWF_Command7B[4] = {0x24b8, 0x24ba, 0x24bc, 0x24be};
+static const uint16 kVWF_Command7C[8] = {0x24b8, 0x24ba, 0x24bc, 0x24be, 0x24b8, 0x24ba, 0x24bc, 0x24be};
+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 uint16 kOverworldMapPaletteData[256] = {
+ 0, 0x94b, 0x1563, 0x1203, 0x2995, 0x5bdf, 0x2191, 0x2e37, 0x7c1f, 0x6f37, 0x7359, 0x777a, 0x7b9b, 0x7fbd, 0, 0,
+ 0, 0x100, 0, 0, 0x7b9b, 0x11b6, 0x1a9b, 0x5fff, 0x2995, 0x6e94, 0x76d6, 0x7f39, 0x7f7b, 0x7fbd, 0, 0,
+ 0, 0x100, 0x1d74, 0x67f9, 0x1ee9, 0x338e, 0x6144, 0x7e6a, 0xa44, 0x7c1f, 0x6144, 0x22eb, 0x3dca, 0x5ed2, 0x7fda, 0x316a,
+ 0, 0x100, 0x14cc, 0x1910, 0x2995, 0x3e3a, 0x1963, 0x15e3, 0x25f5, 0x2e37, 0x15e3, 0x22eb, 0x6144, 0x7e33, 0x5d99, 0x771d,
+ 0, 0xcec, 0x22eb, 0x2fb1, 0x1d70, 0x2e37, 0x25f5, 0x3e77, 0x473a, 0x6144, 0x7e6a, 0x15e3, 0x2e0b, 0x5354, 0x7fff, 0x16a6,
+ 0, 0x100, 0x15c5, 0x16a6, 0x1ee9, 0x2f4d, 0x25f5, 0x3e77, 0x473a, 0x5354, 0x15e3, 0x22eb, 0x2918, 0x4a1f, 0x3f7f, 0x7c1f,
+ 0, 0x100, 0x1563, 0x1203, 0x1ee9, 0x2fb0, 0x1d70, 0x2e37, 0x473a, 0x6144, 0x15e3, 0x22eb, 0x1d70, 0x2e37, 0x4f3f, 0x7fbd,
+ 0, 0, 0, 0, 0, 0, 0, 0x25f5, 0x316a, 0x5ed2, 0x7fff, 0x15e3, 0x473a, 0x2918, 0x771d, 0,
+ 0, 0x18c6, 0x948, 0x118a, 0x25cf, 0x57bf, 0x1971, 0x2a18, 0x7c1f, 0x52d8, 0x5af9, 0x5f1a, 0x633b, 0x6b5c, 0, 0,
+ 0, 0x18c6, 5, 0x45fc, 0x633b, 0x1dce, 0x3694, 0x4718, 0x25cf, 0x1d40, 0x34ea, 0x616f, 0x771b, 0x26d6, 0x2b18, 0x2f5a,
+ 0, 0x18c6, 0x2571, 0x63da, 0x2a32, 0x3a94, 0x1d40, 0x2580, 0x7c1f, 0x7c1f, 0xcc0, 0x1ecc, 0x3135, 0x1dce, 0x4718, 0x3694,
+ 0, 0x18c6, 0x14e7, 0x216c, 0x25d0, 0x3a75, 0x2169, 0x2e0e, 0x21d6, 0x2a18, 0x1971, 0x2a32, 0x1d40, 0x2580, 0x597a, 0x72fe,
+ 0, 0x18c6, 0x2a32, 0x3a94, 0x2171, 0x3238, 0x29f6, 0x4278, 0x4edb, 0x1d40, 0x35cd, 0x15ab, 0x198e, 0x3254, 0x731f, 0x1ed4,
+ 0, 0x18c6, 0x16a, 0x21ce, 0x2a32, 0x3a94, 0x29f6, 0x4278, 0x4edb, 0x1d40, 0x1971, 0x2a32, 0x496c, 0x5a10, 0x3b5f, 0x7c1f,
+ 0, 0x18c6, 0x948, 0x118a, 0x222e, 0x32f2, 0x1951, 0x2a18, 0x431b, 0x1d40, 0x1971, 0x2a32, 0x21d4, 0x2a18, 0x4b1f, 0x7b9d,
+ 0, 0x7c1f, 0x7c1f, 0x7c1f, 0x7c1f, 0x2e31, 0xe4, 0x2169, 0x2e0e, 0x42f1, 0x7c1f, 0x7c1f, 0x7c1f, 0x4a1d, 0x4e3f, 0x5a5f,
+};
+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[6] = {0, 0, 224, 480, -72, -224};
+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];
+}
+
+uint8 GetOtherDungmapInfo(int count) {
+ return kDungMap_Tiles[cur_palace_index_x2 >> 1][count];
+}
+
+void DungMap_4() {
+ BG2VOFS_copy2 += dungmap_var4;
+ dungmap_var5 -= dungmap_var4;
+ if (!--byte_7E0205)
+ overworld_map_state--;
+}
+
+const uint8 *GetCurrentTextPtr() {
+ return kDialogueText + kDialogueOffs[dialogue_message_index];
+}
+
+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;
+}
+
+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(mode7_hdma_table, 0, 0x1e0);
+}
+
+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 < 224)
+ mode7_hdma_table[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 < 224)
+ mode7_hdma_table[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;
+ byte_7E03F3 = 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);
+ g_ram[0xc8] = 32;
+ hud_floor_changed_timer = 0;
+ Hud_FloorIndicator();
+ flag_update_hud_in_nmi++;
+ sound_effect_ambient = 5;
+ submodule_index++;
+}
+
+void GameOver_DelayBeforeIris() { // 89f33b
+ if (--g_ram[0xc8])
+ return;
+ Death_InitializeGameOverLetters();
+ IrisSpotlight_close();
+ WOBJSEL_copy = 48;
+ 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;
+ g_ram[0xc8] = 64;
+ BYTE(palette_filter_countdown) = 0;
+ BYTE(darkening_or_lightening_screen) = 0;
+ Death_PrepFaint();
+}
+
+void GameOver_SplatAndFade() { // 89f3de
+ if (g_ram[0xc8]) {
+ g_ram[0xc8]--;
+ 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;
+ g_ram[0xc8] = 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
+ g_ram[0xc8] = 12;
+ load_chr_halfslot_even_odd = 15;
+ Graphics_LoadChrHalfSlot();
+ load_chr_halfslot_even_odd = 0;
+ palette_sp6 = 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;
+ g_ram[0xc8] = 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 (!--g_ram[0xc8]) {
+ g_ram[0xc8] = 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;
+ }
+ g_ram[0xc8] = 12;
+ sound_effect_2 = 32;
+ }
+ }
+ if (!((filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0))
+ return;
+ sound_effect_1 = 44;
+ Death_Func15();
+}
+
+void Death_Func15() { // 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 (savegame_tagalong == 6 || savegame_tagalong == 9 || savegame_tagalong == 10 || savegame_tagalong == 13)
+ savegame_tagalong = 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)
+ death_save_counter++;
+ death_var5++;
+ if (subsubmodule_index != 1) {
+ if (!player_is_indoors)
+ goto outdoors;
+
+ if (savegame_tagalong != 1 && BYTE(cur_palace_index_x2) != 255) {
+ death_var4 = 0;
+ } else {
+ buffer_for_playing_songs = 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;
+ buffer_for_playing_songs = 0;
+ zelda_snes_dummy_write(NMITIMEN, 0);
+ zelda_snes_dummy_write(HDMAEN, 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();
+ zelda_snes_dummy_write(NMITIMEN, 0x81);
+ }
+}
+
+void GameOver_AnimateChoiceFairy() { // 89f67a
+ int spr = 0x14;
+ bytewise_extended_oam[spr] = 2;
+ oam_buf[spr].x = 0x34;
+ oam_buf[spr].y = kDeath_SprY0[subsubmodule_index];
+ oam_buf[spr].charnum = kDeath_SprChar0[frame_counter >> 3 & 1];
+ oam_buf[spr].flags = 0x78;
+}
+
+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:
+ g_ram[0xc8] = 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
+ PointU8 pt;
+
+ if (g_ram[0xc8] == 0) {
+ if ((joypad1L_last | joypad1H_last) & 0xc0) {
+ overworld_map_state++;
+ return;
+ }
+ } else {
+ g_ram[0xc8]--;
+ }
+ 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_HandleSpriteBlink(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_HandleSpriteBlink(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;
+ 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 = (m & 0xf) != music_unk1 ? (m & 0xf) : 0xf3;
+}
+
+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;
+ zelda_ppu_write(BGMODE, 7);
+ BGMODE_copy = 7;
+ zelda_ppu_write(M7SEL, 0x80);
+}
+
+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++;
+}
+
+void WorldMap_PlayerControl() { // 8abae6
+ if (overworld_map_flags & 0x80) {
+ overworld_map_flags &= ~0x80;
+ OverworldMap_SetupHdma();
+ }
+
+ if (!overworld_map_flags && filtered_joypad_L & 0x40) { // X
+ overworld_map_state++;
+ return;
+ }
+ if (BYTE(dung_draw_width_indicator)) {
+ BYTE(dung_draw_width_indicator)--;
+ } else if (filtered_joypad_L & 0x70) {
+ 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 != kOverworldMap_Table2[k]) {
+ BG1VOFS_copy2 += kOverworldMap_Table3[k];
+ M7Y_copy = BG1VOFS_copy2 + 0x100;
+ }
+ k = (joypad1H_last & 3) * 2 + 1;
+ if (BG1HOFS_copy2 != 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;
+ zelda_ppu_write(BGMODE, 9);
+ 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;
+ zelda_ppu_write(M7B, 0);
+ zelda_ppu_write(M7B, 0);
+ zelda_ppu_write(M7C, 0);
+ zelda_ppu_write(M7C, 0);
+ zelda_ppu_write(M7X, 0);
+ zelda_ppu_write(M7X, 1);
+ zelda_ppu_write(M7Y, 0);
+ zelda_ppu_write(M7Y, 1);
+
+ 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
+ PointU8 pt;
+
+ if (frame_counter & 0x10 && WorldMap_CalculateOamCoordinates(&pt))
+ WorldMap_HandleSpriteBlink(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_HandleSpriteBlink(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;
+ uint16 x;
+
+ 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_HandleSpriteBlink(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_HandleSpriteBlink(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_HandleSpriteBlink(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_HandleSpriteBlink(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_HandleSpriteBlink(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_HandleSpriteBlink(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_HandleSpriteBlink(8, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
+ }
+ endif_crystal6:;
+ }
+
+out:
+ link_x_coord_spexit = xbak;
+ link_y_coord_spexit = ybak;
+}
+
+bool WorldMap_CalculateOamCoordinates(PointU8 *pt) { // 8ac39f
+ uint8 r14, r15;
+
+ 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];
+ r15 = 13 * t0 >> 4;
+
+ uint8 at = link_x_coord_spexit >> 4;
+ bool below = at < 0x80;
+ at -= 0x80;
+ if (sign8(at)) at = ~at;
+
+ uint8 t1 = ((r15 < 224 ? r15 : 0) * 0x54 >> 8) + 0xb2;
+ uint8 t2 = at * t1 >> 8;
+ uint8 t3 = (below) ? 0x80 - t2 : t2 + 0x80;
+
+ pt->x = t3 - BG1HOFS_copy2 + 0x80;
+ pt->y = r15 + 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;
+ r15 = kOverworldMap_tab1[t1];
+ uint16 t2 = link_x_coord_spexit;
+ bool below = t2 < 0x7F8;
+ t2 -= 0x7f8;
+ if (sign16(t2))
+ t2 = -t2;
+ uint8 t3 = r15 < 226 ? r15 : 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;
+ r14 = t11 - BG1HOFS_copy2;
+ uint16 t12 = t11 - 0xFF80 - BG1HOFS_copy2;
+ if (t12 >= 0x100)
+ return false;
+ pt->x = r14 + 0x81;
+ pt->y = r15 + 16;
+ return true;
+ }
+}
+
+void WorldMap_HandleSpriteBlink(int spr, uint8 r11_ext, uint8 r12_flags, uint8 r13_char, uint8 r14_x, uint8 r15_y) { // 8ac51c
+ if (!(frame_counter & 0x10) && r13_char == 100) {
+ assert(spr >= 8);
+ r13_char = kOverworldMapData[spr - 8];
+ r12_flags = 0x32;
+ r11_ext = 0;
+ } else {
+ r14_x -= 4;
+ r15_y -= 4;
+ }
+ bytewise_extended_oam[spr] = r11_ext;
+ oam_buf[spr].x = r14_x;
+ oam_buf[spr].y = r15_y;
+ oam_buf[spr].charnum = r13_char;
+ oam_buf[spr].flags = r12_flags;
+}
+
+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;
+ zelda_snes_dummy_write(HDMAEN, 0);
+ 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);
+ uint8 r12 = dung_cur_floor + (t5 & 0xf);
+ 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();
+}
+
+void DungeonMap_HandleInput() { // 8ae95b
+ if (filtered_joypad_L & 0x40) {
+ 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);
+ uint8 yv = 7;
+ 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;
+ }
+ bytewise_extended_oam[spr_pos] = 2;
+ oam_buf[spr_pos].x = 0x19;
+ oam_buf[spr_pos].y = kDungMap_Tab33[r3] - 4;
+ oam_buf[spr_pos].charnum = 0;
+ oam_buf[spr_pos].flags = overworld_palette_swap_flag ? 0x30 : 0x3e;
+}
+
+int DungeonMap_DrawBlinkingIndicator(int spr_pos) { // 8aeb50
+ bytewise_extended_oam[spr_pos] = 0;
+ oam_buf[spr_pos].x = dungmap_var3 - 3;
+ oam_buf[spr_pos].y = ((dungmap_var5 < 256) ? dungmap_var5 : 0xf0) - 3;
+ oam_buf[spr_pos].charnum = 0x34;
+ oam_buf[spr_pos].flags = kDungMap_Tab38[frame_counter >> 2 & 3];
+ return spr_pos + 1;
+}
+
+int DungeonMap_DrawLocationMarker(int spr_pos, uint16 r14) { // 8aeba8
+ for (int i = 3; i >= 0; i--, spr_pos++) {
+ bytewise_extended_oam[spr_pos] = 2;
+ oam_buf[spr_pos].x = kDungMap_Tab29[i] + (dungmap_var3 & 0xf0);
+ uint8 r15 = dungmap_var6 + kDungMap_Tab24[r14];
+ oam_buf[spr_pos].y = r15 + kDungMap_Tab30[i];
+ oam_buf[spr_pos].charnum = 0;
+ int fr = (frame_counter >> 2) & 1;
+ if ((dungmap_var5 + 1 & 0xf0) == ++r15 && dungmap_var5 < 256)
+ fr += 2;
+ oam_buf[spr_pos].flags = kDungMap_Tab32[fr] | kDungMap_Tab31[i];
+ }
+ 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 {
+ bytewise_extended_oam[spr_pos+0] = 0;
+ bytewise_extended_oam[spr_pos+1] = 0;
+ oam_buf[spr_pos + 0].x = 0x30;
+ oam_buf[spr_pos + 1].x = 0x38;
+ oam_buf[spr_pos + 0].y = r4;
+ oam_buf[spr_pos + 1].y = r4;
+ r4 += 16;
+ oam_buf[spr_pos + 0].flags = 0x3d;
+ oam_buf[spr_pos + 1].flags = 0x3d;
+ oam_buf[spr_pos + 0].charnum = sign8(r2) ? 0x1c : kDungMap_Tab34[r2];
+ oam_buf[spr_pos + 1].charnum = sign8(r2) ? kDungMap_Tab34[r2 ^ 0xff] : 0x1d;
+ } 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++) {
+ bytewise_extended_oam[spr_pos+0] = 0;
+ bytewise_extended_oam[spr_pos+4] = 0;
+ oam_buf[spr_pos + 0].x = x;
+ oam_buf[spr_pos + 4].x = x;
+ oam_buf[spr_pos + 0].y = y + flag * 16;
+ oam_buf[spr_pos + 4].y = y + flag * 16 + 8;
+ oam_buf[spr_pos + 0].charnum = kDungMap_Tab36[i];
+ oam_buf[spr_pos + 4].charnum = kDungMap_Tab36[i];
+ uint8 t = 0x3d | (i ? 0 : 0x40);
+ oam_buf[spr_pos + 0].flags = t;
+ oam_buf[spr_pos + 4].flags = t | 0x80;
+ 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;
+ bytewise_extended_oam[spr_pos] = 0;
+ uint16 xy = kDungMap_Tab37[dung];
+ oam_buf[spr_pos].x = (xy >> 8) + dungmap_var7 + 0x90;
+ oam_buf[spr_pos].y = (dungmap_var8 < 256) ? xy + dungmap_var8 : 0xf0;
+ oam_buf[spr_pos].charnum = 0x31;
+ oam_buf[spr_pos].flags = 0x33;
+ 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;
+ bytewise_extended_oam[spr_pos] = 0;
+ uint16 xy = kDungMap_Tab37[dung];
+ oam_buf[spr_pos].x = 0x4C;
+ oam_buf[spr_pos].y = kDungMap_Tab33[r3];
+ oam_buf[spr_pos].charnum = 0x31;
+ oam_buf[spr_pos].flags = 0x33;
+ return spr_pos + 1;
+}
+
+void DungeonMap_RecoverGFX() { // 8aef19
+ uint8 hdmaen_bak = HDMAEN_copy;
+ zelda_snes_dummy_write(HDMAEN, 0);
+ 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;
+
+ 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();
+ RenderText_Draw_EmptyBuffer();
+ dialogue_msg_dst_offs = 0;
+ 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;
+}
+
+void Text_LoadCharacterBuffer() { // 8ec4e2
+ const uint8 *src = GetCurrentTextPtr(), *src_org = src;
+ uint8 *dst = messaging_text_buffer;
+ dst[0] = dst[1] = 0x7f;
+ dialogue_msg_dst_offs = 0;
+ dialogue_msg_src_offs = 0;
+ for (;;) {
+ uint8 c = *src++;
+ if (!(c & 0x80)) {
+ switch (c) {
+ case 0x67 + 3: dst = Text_WritePlayerName(dst); break;
+ case 0x67 + 4: // RenderText_ExtendedCommand_SetWindowType
+ text_render_state = *src++;
+ break;
+ case 0x67 + 5: { // Text_WritePreloadedNumber
+ uint8 t = *src++;
+ uint8 v = byte_7E1CF2[t >> 1];
+ *dst++ = 0x34 + ((t & 1) ? v >> 4 : v & 0xf);
+ break;
+ }
+ case 0x67 + 6:
+ text_msgbox_topleft = kText_Positions[*src++];
+ break;
+ case 0x67 + 16:
+ text_tilemap_cur = ((0x387F & 0xe300) | 0x180) | (*src++ << 10) & 0x3c00;
+ break;
+ case 0x67 + 7:
+ case 0x67 + 17:
+ case 0x67 + 18:
+ case 0x67 + 19:
+ *dst++ = c;
+ *dst++ = *src++;
+ break;
+ case 0x7f:
+ dialogue_msg_dst_offs = dst - messaging_text_buffer;
+ dialogue_msg_src_offs = src - src_org - 1;
+ *dst = 0x7f;
+ return; // done
+ default:
+ *dst++ = c;
+ break;
+ }
+ } else {
+ // dictionary
+ c -= 0x88;
+ int idx = kTextDictionary_Idx[c], num = kTextDictionary_Idx[c + 1] - idx;
+ memcpy(dst, &kTextDictionary[idx], num);
+ dst += num;
+ }
+ }
+}
+
+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:
+ if (dialogue_msg_src_offs >= 99) {
+ dialogue_msg_src_offs = 0;
+ text_next_position = 0;
+ } else if (dialogue_msg_src_offs >= 59 && dialogue_msg_src_offs < 80) {
+ dialogue_msg_src_offs = 0x50;
+ text_next_position = 0;
+ } else if (dialogue_msg_src_offs >= 19 && dialogue_msg_src_offs < 40) {
+ dialogue_msg_src_offs = 0x28;
+ text_next_position = 0;
+ }
+ if ((dialogue_msg_src_offs == 18 || dialogue_msg_src_offs == 58 || dialogue_msg_src_offs == 98) && (text_next_position & 7) >= 6) {
+ dialogue_msg_src_offs++;
+ goto restart;
+ }
+ int t = (messaging_text_buffer[dialogue_msg_dst_offs] & 0x7f) - 0x66;
+ if (t < 0)
+ t = 0;
+ switch (t) {
+ case 0: // RenderText_Draw_RenderCharacter
+ switch (vwf_line_mode < 2 ? vwf_line_mode : 2) {
+ case 0: // RenderText_Draw_RenderCharacter_All
+ RenderText_Draw_RenderCharacter_All();
+ break;
+ case 1: // VWF_RenderSingle
+ VWF_RenderSingle();
+ break;
+ default:
+ vwf_line_mode--;
+ break;
+ }
+ break;
+ case 1: // RenderText_Draw_NextImage
+ if (main_module_index == 20) {
+ PaletteFilterHistory();
+ if (!BYTE(palette_filter_countdown))
+ dialogue_msg_dst_offs++;
+ } else {
+ dialogue_msg_dst_offs++;
+ }
+ break;
+ case 2: // RenderText_Draw_Choose2LowOr3
+ RenderText_Draw_Choose2LowOr3();
+ break;
+ case 3: // RenderText_Draw_ChooseItem
+ RenderText_Draw_ChooseItem();
+ break;
+ case 4: //
+ case 5: //
+ case 6: //
+ case 7: //
+ case 8: // RenderText_Draw_Ignore
+ byte_7E1CEA = messaging_text_buffer[dialogue_msg_dst_offs + 1];
+ dialogue_msg_dst_offs += 2;
+ break;
+ case 9: // RenderText_Draw_Choose2HiOr3
+ RenderText_Draw_Choose2HiOr3();
+ break;
+ case 10: //
+ assert(0);
+ break;
+ case 11: // RenderText_Draw_Choose3
+ RenderText_Draw_Choose3();
+ break;
+ case 12: // RenderText_Draw_Choose1Or2
+ RenderText_Draw_Choose1Or2();
+ break;
+ case 13: // RenderText_Draw_Scroll
+ RenderText_Draw_Scroll();
+ break;
+ case 14: //
+ case 15: //
+ case 16: // VWF_SetLine
+ dialogue_msg_src_offs = kVWF_LinePositions[(t + 2) & 3];
+ vwf_curline = kVWF_RowPositions[(t + 2) & 3];
+ vwf_flag_next_line = 1;
+ dialogue_msg_dst_offs++;
+ text_next_position = 0;
+ break;
+ case 17: // RenderText_Draw_SetColor
+ byte_7E1CDC &= ~0x1c;
+ byte_7E1CDC |= (messaging_text_buffer[dialogue_msg_dst_offs + 1] & 7) << 2;
+ dialogue_msg_dst_offs += 2;
+ break;
+ case 18: // RenderText_Draw_Wait
+ switch (joypad1L_last & 0x80 ? 1 : text_wait_countdown >= 2 ? 2 : text_wait_countdown) {
+ case 0:
+ text_wait_countdown = kText_WaitDurations[messaging_text_buffer[dialogue_msg_dst_offs + 1] & 0xf] - 1;
+ break;
+ case 1:
+ dialogue_msg_dst_offs += 2;
+ BYTE(text_wait_countdown) = 0;
+ break;
+ case 2:
+ text_wait_countdown--;
+ break;
+ }
+ break;
+ case 19: // RenderText_Draw_PlaySfx
+ sound_effect_2 = messaging_text_buffer[dialogue_msg_dst_offs + 1];
+ dialogue_msg_dst_offs += 2;
+ break;
+ case 20: // RenderText_Draw_SetSpeed
+ vwf_line_speed = vwf_line_mode = messaging_text_buffer[dialogue_msg_dst_offs + 1];
+ dialogue_msg_dst_offs += 2;
+ break;
+ case 21: // RenderText_Draw_Command7B
+ RenderText_Draw_Command7B();
+ break;
+ case 22: // RenderText_Draw_ABunchOfSpaces
+ RenderText_Draw_ABunchOfSpaces();
+ break;
+ case 23: // RenderText_Draw_EmptyBuffer
+ RenderText_Draw_EmptyBuffer();
+ break;
+ case 24: // 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) {
+ dialogue_msg_dst_offs++;
+ text_wait_countdown2 = 28;
+ }
+ }
+ break;
+ case 25: // 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;
+ }
+ 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 RenderText_Draw_RenderCharacter_All() { // 8eca99
+ VWF_RenderSingle();
+ if (dialogue_msg_src_offs != 19 && dialogue_msg_src_offs != 59 && dialogue_msg_src_offs != 99)
+ RenderText_Draw_MessageCharacters();
+}
+
+void VWF_RenderSingle() { // 8ecab8
+ uint8 t = messaging_text_buffer[dialogue_msg_dst_offs];
+ if (t != 0x59)
+ sound_effect_2 = 12;
+ VWF_RenderCharacter();
+ vwf_line_mode = vwf_line_speed;
+}
+
+void VWF_RenderCharacter() { // 8ecb5e
+ 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;
+ }
+ uint8 c = messaging_text_buffer[dialogue_msg_dst_offs];
+ uint8 width = kVWF_RenderCharacter_widths[c];
+ 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 *const kTextBits = GetFontPtr();
+ const uint16 *src2 = kTextBits + r10 * 8;
+ 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 = kTextBits + (r10 + 16) * 8;
+ 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;
+ }
+ dialogue_msg_dst_offs++;
+}
+
+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_next_position = 0;
+ dialogue_msg_dst_offs = 0;
+ 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 = kHudItemBoxGfxPtrs[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_next_position = 0;
+ dialogue_msg_dst_offs = 0;
+ 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_next_position = 0;
+ dialogue_msg_dst_offs = 0;
+ 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_next_position = 0;
+ dialogue_msg_dst_offs = 0;
+ Text_InitVwfState();
+ }
+}
+
+void RenderText_Draw_Scroll() { // 8ecfe2
+ uint8 r2 = byte_7E1CEA;
+ 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) {
+ dialogue_msg_dst_offs++;
+ dialogue_msg_src_offs = 80;
+ vwf_curline = 4;
+ vwf_flag_next_line = 1;
+ text_next_position = 0;
+ break;
+ }
+ } while (r2--);
+}
+
+void RenderText_Draw_Command7B() { // 8ed18d
+ int i = (messaging_text_buffer[dialogue_msg_dst_offs + 1] & 0x7f);
+ int j = dialogue_msg_src_offs;
+ WORD(g_ram[0x2D8 + j]) = kVWF_Command7B[i * 2 + 0];
+ WORD(g_ram[0x300 + j]) = kVWF_Command7B[i * 2 + 1];
+ dialogue_msg_src_offs = j + 2;
+ dialogue_msg_dst_offs += 2;
+ RenderText_Draw_MessageCharacters();
+}
+
+void RenderText_Draw_ABunchOfSpaces() { // 8ed1bd
+ int i = (messaging_text_buffer[dialogue_msg_dst_offs + 1] & 0x7f);
+ int j = dialogue_msg_src_offs;
+ WORD(g_ram[0x2D8 + j]) = kVWF_Command7C[i * 4 + 0];
+ WORD(g_ram[0x300 + j]) = kVWF_Command7C[i * 4 + 1];
+ WORD(g_ram[0x2DA + j]) = kVWF_Command7C[i * 4 + 2];
+ WORD(g_ram[0x302 + j]) = kVWF_Command7C[i * 4 + 3];
+ dialogue_msg_src_offs = j + 4;
+ dialogue_msg_dst_offs += 2;
+ RenderText_Draw_MessageCharacters();
+}
+
+void RenderText_Draw_EmptyBuffer() { // 8ed1f9
+ memset(messaging_buf, 0, 0x7e0);
+ dialogue_msg_src_offs = 0;
+ dialogue_msg_dst_offs++;
+ text_next_position = 0;
+}
+
+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
+ const uint8 *src = kDialogueText;
+ uint32 p = 0x1c8000;
+ uint8 *dst = kTextDialoguePointers;
+ for (int i = 0;; i++) {
+ if (i == 359)
+ p = 0xedf40;
+ WORD(dst[0]) = p;
+ dst[2] = p >> 16;
+ dst += 3;
+
+ if (i == 397)
+ break;
+
+ for (;;) {
+ int j = *src;
+ int len = (j >= 0x67 && j < 0x80) ? kText_CommandLengths[j - 0x67] : 1;
+ src += len;
+ p += len;
+ if (j == 0x7f)
+ break;
+ }
+ }
+}
+
+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);
+ WORD(CGWSEL_copy) = 0x2002;
+ 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;
+
+ int spr = 0x74;
+ bytewise_extended_oam[spr] = 2;
+ oam_buf[spr].x = x;
+ oam_buf[spr].y = y;
+ oam_buf[spr].charnum = 0xaa;
+ oam_buf[spr].flags = kDeath_SprFlags[link_is_on_lower_level] | 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;
+ 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;
+}
+
--- /dev/null
+++ b/messaging.h
@@ -1,0 +1,139 @@
+#pragma once
+#include "types.h"
+
+const uint8 *GetDungmapFloorLayout();
+uint8 GetOtherDungmapInfo(int count);
+void DungMap_4();
+const uint8 *GetCurrentTextPtr();
+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();
+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 WorldMap_CalculateOamCoordinates(PointU8 *pt);
+void WorldMap_HandleSpriteBlink(int spr, uint8 r11_ext, uint8 r12_flags, uint8 r13_char, uint8 r14_x, uint8 r15_y);
+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 RenderText_Draw_RenderCharacter_All();
+void VWF_RenderSingle();
+void VWF_RenderCharacter();
+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();
+void RenderText_Draw_Scroll();
+void RenderText_Draw_Command7B();
+void RenderText_Draw_ABunchOfSpaces();
+void RenderText_Draw_EmptyBuffer();
+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();
--- /dev/null
+++ b/misc.cpp
@@ -1,0 +1,962 @@
+#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 "other_modules.h"
+#include "player_oam.h"
+#include "messaging.h"
+#include "ending.h"
+#include "attract.h"
+#include "tables/generated_predefined_tiles.h"
+#include "tables/generated_sound_banks.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 < 224; i++)
+ mode7_hdma_table[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();
+ zelda_ppu_write(OBSEL, 2);
+ 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();
+ }
+ 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/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/nmi.cpp
@@ -1,0 +1,498 @@
+#include "nmi.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "snes_regs.h"
+#include "tables/generated_bg_tilemaps.h"
+#include "tables/generated_link_graphics.h"
+#include "messaging.h"
+#include "snes/ppu.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);
+}
+
+void CopyToVram(uint32 dstv, const uint8 *src, int len) {
+ memcpy(&g_zenv.vram[dstv], src, len);
+}
+
+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);
+}
+
+void CopyToVramLow(const uint8 *src, uint32 addr, int num) {
+ zelda_ppu_write(VMAIN, 0);
+ zelda_ppu_write_word(VMADDL, addr);
+ for (int i = 0; i < num; i++) {
+ zelda_ppu_write(VMDATAL, *src++);
+ }
+}
+
+void Interrupt_NMI(uint16 joypad_input) { // 8080c9
+ if (music_control == 0) {
+ if (zelda_apu_read(APUI00) == last_music_control)
+ zelda_apu_write(APUI00, 0);
+ } else if (music_control != last_music_control) {
+ last_music_control = music_control;
+ zelda_apu_write(APUI00, 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)
+ 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;
+
+ zelda_ppu_write(INIDISP, 0x80);
+ zelda_snes_dummy_write(HDMAEN, 0);
+ if (!nmi_boolean) {
+ nmi_boolean = true;
+ NMI_DoUpdates();
+ NMI_ReadJoypads(joypad_input);
+ }
+
+ if (is_nmi_thread_active) {
+ NMI_SwitchThread();
+ if (thread_other_stack != 0x1f31)
+ thread_other_stack = 0x1f31;
+ else
+ thread_other_stack = 0x1f2;
+ } else {
+ 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(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);
+ }
+ //if (irq_flag) {
+ // snes_dummy_read(g_snes, TIMEUP);
+ // snes_dummy_write(g_snes, VTIMEL, 0x80);
+ // snes_dummy_write(g_snes, VTIMEH, 0);
+ // snes_dummy_write(g_snes, HTIMEL, 0);
+ // snes_dummy_write(g_snes, HTIMEH, 0);
+ // snes_dummy_write(g_snes, NMITIMEN, 0xa1);
+ //}
+ zelda_ppu_write(INIDISP, INIDISP_copy);
+ zelda_snes_dummy_write(HDMAEN, HDMAEN_copy);
+ }
+}
+
+void NMI_SwitchThread() { // 80822d
+ NMI_UpdateIRQGFX();
+ //zelda_snes_dummy_write(VTIMEL, virq_trigger);
+ //zelda_snes_dummy_write(VTIMEH, 0);
+ //zelda_snes_dummy_write(NMITIMEN, 0xa1);
+ 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_snes_dummy_write(HDMAEN, HDMAEN_copy);
+}
+
+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, 0x14a);
+ }
+
+ 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], 0x200);
+ memcpy(g_zenv.ppu->highOam, &g_ram[0xa00], 0x20);
+
+ 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.t3.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.t3.data, *src_org = src;
+ 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
+ static const uint16 kLightWorldTileMapSrcs[4] = { 0, 0x20, 0x1000, 0x1020 };
+ 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/nmi.h
@@ -1,0 +1,39 @@
+#pragma once
+#include "types.h"
+
+void NMI_UploadSubscreenOverlayFormer();
+void NMI_UploadSubscreenOverlayLatter();
+void CopyToVram(uint32 dstv, const uint8 *src, int len);
+void CopyToVramVertical(uint32 dstv, const uint8 *src, int len);
+void CopyToVramLow(const uint8 *src, uint32 addr, int num);
+void Interrupt_NMI(uint16 joypad_input);
+void NMI_SwitchThread();
+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/other/name_remap.txt
@@ -1,0 +1,3157 @@
+Vector_RESET Interrupt_Reset
+Vector_NMI Interrupt_NMI
+Native_mode_IRQ Interrupt_IRQ
+Vram_EraseTilemaps_Triforce EraseTileMaps_triforce
+Vram_EraseTilemaps_PalaceMap EraseTileMaps_dungeonmap
+Vram_EraseTilemaps_normal EraseTileMaps_normal
+Vram_EraseTilemaps EraseTileMaps
+Main_PrepSpritesForNmi NMI_PrepareSprites
+UseImplicitRegIndexedLocalJumpTable JumpTableLocal
+UseImplicitRegIndexedLongJumpTable JumpTableLong
+Overworld_GetTileAttrAtLocation Overworld_GetTileAttributeAtLocation
+Sound_LoadSongBank LoadSongBank
+Sound_LoadLightWorldSongBank LoadOverworldSongs
+Sound_LoadIndoorSongBank LoadDungeonSongs
+Sound_LoadEndingSongBank LoadCreditsSongs
+Main_SaveGameFile SaveGameFile
+NMI_UploadBg3Text NMI_UploadBG3Text
+NMI_UpdateScrollingOwMap NMI_UpdateOWScroll
+NMI_UploadSubscreenOverlay NMI_UpdateSubscreenOverlay
+NMI_UploadSubscreenOverlay_firstHalf NMI_UploadSubscreenOverlayFormer
+NMI_UploadSubscreenOverlay_secondHalf NMI_UploadSubscreenOverlayLatter
+NMI_UploadSubscreenOverlay_StartTransfers NMI_HandleArbitraryTileMap
+NMI_UploadBg3Unknown NMI_UpdateBG1Wall
+NMI_UploadBg3Unknown_doNothing NMI_TileMapNothing
+NMI_LightWorldMode7Tilemap NMI_UpdateLoadLightWorldMap
+NMI_UpdateLeftBg2Tilemaps NMI_UpdateBG2Left
+NMI_UpdateBgChrSlots_3_to_4 NMI_UpdateBGChar3and4
+NMI_UpdateBgChrSlots_5_to_6 NMI_UpdateBGChar5and6
+NMI_UpdateChrHalfSlot NMI_UpdateBGCharHalf
+NMI_UpdateChr_Bg0 NMI_UpdateBGChar0
+NMI_UpdateChr_Bg1 NMI_UpdateBGChar1
+NMI_UpdateChr_Bg2 NMI_UpdateBGChar2
+NMI_UpdateChr_Bg3 NMI_UpdateBGChar3
+NMI_UpdateChr_Spr0 NMI_UpdateObjChar0
+NMI_UpdateChr_Spr2 NMI_UpdateObjChar2
+NMI_UpdateChr_Spr3 NMI_UpdateObjChar3
+NMI_UpdateAny NMI_RunTileMapUpdateDMA
+NMI_DarkWorldMode7Tilemap NMI_UploadDarkWorldMap
+NMI_UpdateBg3ChrForDeathMode NMI_UploadGameOverText
+NMI_UpdateBarrierTileChr NMI_UpdatePegTiles
+UNUSED_sub_8090EB UNREACHABLE_0090EB
+Dungeon_Upload_BG2 Dungeon_PrepareNextRoomQuadrantUpload
+Dungeon_Upload_BG1_Outer WaterFlood_BuildOneQuadrantForVRAM
+Dungeon_Upload_BG1 TileMapPrep_NotWaterOnTag
+Dungeon_Upload_BG1_Water WaterFlood_BuildOneQuadrantForVRAM_not_triggered
+NMI_LoadTilemapToVram HandleStripes14
+UpdatePolyhedralDma NMI_UpdateIRQGFX
+LoadItemAnimationGfx LoadItemGFXIntoWRAM4BPPBuffer
+DecompSwordGfx DecompressSwordGraphics
+DecompShieldGfx DecompressShieldGraphics
+DecompDungAnimatedTiles DecompressAnimatedDungeonTiles
+DecompOwAnimatedTiles DecompressAnimatedOverworldTiles
+IntroLoadGfx4 LoadItemGFX_Auxiliary
+Tagalong_LoadGfx LoadFollowerGraphics
+DecodeAnimatedSpriteTile WriteTo4BPPBuffer_at_7F4000
+Intro_LoadGfx_expand3To4bpp LoadItemGFX_sheet0
+SomeUnpackAnimatedTiles UNREACHABLE_00D5C5
+Do3To4Low_8Tiles Do3bppToWRAM4bpp_LeftPal
+Expand3To4High_6 Do3bppToWRAM4bpp_RightPal
+LoadTransAuxGfx LoadTransAuxGFX
+Dungeon_LoadSpriteSets LoadTransAuxGFX_sprite
+DecompAuxAndSprites ReloadPreviouslyLoadedSheets
+Text_DecompressStoryGfx Attract_DecompressStoryGFX
+MirrorWarp_LoadNext AnimateMirrorWarp
+MirrorWarp_LoadNext_0 AnimateMirrorWarp_LoadPyramidIfAga
+MirrorWarp_LoadNext_5 AnimateMirrorWarp_TriggerOverlayA_2
+MirrorWarp_LoadNext_7x AnimateMirrorWarp_DrawDestinationScreen
+MirrorWarp_LoadNext_8x AnimateMirrorWarp_DoSpritesPalettes
+MirrorWarp_LoadNext_6 AnimateMirrorWarp_TriggerOverlayB
+MirrorWarp_LoadNext_14 AnimateMirrorWarp_TriggerBGChar0
+MirrorWarp_LoadNext_10 AnimateMirrorWarp_DecompressAnimatedTiles
+LoadMainAuxTiles AnimateMirrorWarp_DecompressNewTileSets
+MirrorWarp_LoadNext_2 AnimateMirrorWarp_DecompressBackgroundsA
+MirrorWarp_LoadNext_3 AnimateMirrorWarp_DecompressBackgroundsB
+MirrorWarp_LoadNext_4 AnimateMirrorWarp_DecompressBackgroundsC
+MirrorWarp_LoadNext_11 AnimateMirrorWarp_LoadSubscreen
+MirrorWarp_LoadNext_12 AnimateMirrorWarp_DecompressSpritesA
+MirrorWarp_LoadNext_13 AnimateMirrorWarp_DecompressSpritesB
+Graphics_IncrementalVramUpload Graphics_IncrementalVRAMUpload
+LoadGfxFunc1 LoadNewSpriteGFXSet
+InitTilesets InitializeTilesets
+LoadDefaultGfx LoadDefaultGraphics
+DecompAndDirectCopy DecompressAndCopyManually
+Attract_InitGraphics_Helper1 Attract_LoadBG3GFX
+Graphics_LoadCommonSpr LoadCommonSprites_2
+WriteMode7GraphicsData TransferMode7Characters
+Graphics_MaybeLoadChrHalfSlot Graphics_LoadChrHalfSlot
+LoadSelectScreenGfx LoadFileSelectGraphics
+CopyFontToVram TransferFontToVRAM
+LoadSpriteGfx LoadSpriteGraphics
+Upload3To4High Do3To4High
+LoadBgGfx LoadBackgroundGraphics
+Upload3To4Low Do3To4Low
+LoadCommonSprGfxToVram LoadCommonSprites
+Decomp_spr_to_0x7f4600 Decompress_sprite_high
+DecompSprOrBg Decompress
+Decomp_get_next_byte Decompression_GetNextByte
+PaletteFilter_doFiltering ApplyPaletteFilter
+PaletteFilterUnused UNREACHABLE_00EA79
+Palette_ResetHud45ForText ResetHUDPalettes4and5
+Palette_Restore_SP5F PaletteFilter_RestoreSP5F
+Palette_Filter_SP5F PaletteFilter_SP5F
+KholdstareShell_PaletteFiltering_Code PaletteFilter_KholdstareShell_init
+PaletteFilter_Agahnim AgahnimWarpShadowFilter
+sub_80ED19 AgahnimWarpShadowFilter_filter_one
+sub_80EDB1 PaletteFilter_Restore
+RestorePaletteAdditive_FadeIn PaletteFilter_RestoreAdditive
+RestorePaletteSubtractive PaletteFilter_RestoreSubtractive
+Palette_InitWhiteFilter PaletteFilter_InitializeWhiteFilter
+sub_80EEE0 MirrorWarp_GoToSubmodules
+Palette_MirrorWarp_Step MirrorWarp_RunAnimationSubmodules
+Palette_DarkenOrLighten_Step PaletteFilter_BlindingWhite
+Palette_AnimCommon PaletteFilter_StartBlindingWhite
+TriforceRoom_AnimPalette PaletteFilter_BlindingWhiteTriforce
+WhirlpoolSaturateBlue PaletteFilter_WhirlpoolBlue
+WhirlpoolIsolateBlue PaletteFilter_IsolateWhirlpoolBlue
+WhirlpoolRestoreBlue PaletteFilter_WhirlpoolRestoreBlue
+WhirlpoolRestoreRedGreen PaletteFilter_WhirlpoolRestoreRedGreen
+sub_80F132 EXIT_00F12D
+PaletteFilter_Restore_Strictly_Bg_Subtractive PaletteFilter_RestoreBGSubstractiveStrict
+PaletteFilter_Restore_Strictly_Bg_Additive PaletteFilter_RestoreBGAdditiveStrict
+PaletteFilter_IncreaseTrinexxRed Trinexx_FlashShellPalette_Red
+PaletteFilter_RestoreTrinexxRed Trinexx_UnflashShellPalette_Red
+PaletteFilter_IncreaseTrinexxBlue Trinexx_FlashShellPalette_Blue
+PaletteFilter_RestoreTrinexxBlue Trinexx_UnflashShellPalette_Blue
+Spotlight_close IrisSpotlight_close
+ConfigureSpotlightTable IrisSpotlight_ConfigureTable
+ResetSpotlightTable IrisSpotlight_ResetTable
+ConfigureSpotlightTable_Helper IrisSpotlight_CalculateCircleValue
+OrientLampBg OrientLampLightCone
+Hdma_ConfigureWaterTable AdjustWaterHDMAWindow
+Hdma_ConfigureWaterTable_Inner AdjustWaterHDMAWindow_X
+Watergate_Helper FloodDam_PrepFloodHDMA
+Module_Messaging Module0E_Interface
+Messaging_Main RunInterface
+Messaging_PrayingPlayer Module0E_05_DesertPrayer
+PrayingPlayer_InitScene DesertPrayer_InitializeCutscene
+PrayingPlayer_FadeInScene DesertPrayer_FadeScene
+UNUSED_Module_Messaging_6 Module0E_06_Unused
+Module_Messaging_4 Module0E_04_RedPotion
+Module_Messaging_8 Module0E_08_GreenPotion
+Module_Messaging_9 Module0E_09_BluePotion
+PrepDungeonBossExit PrepareDungeonExitFromBossFight
+Module_Messaging_11 Module0E_0B_SaveMenu
+Overworld_LoadGfxProperties Sprite_LoadGraphicsProperties
+Overworld_LoadGfxProperties_justLightWorld Sprite_LoadGraphicsProperties_light_world_only
+Dungeon_InitStarTileChr ResetStarTileGraphics
+Mirror_InitHdmaSettings InitializeMirrorHDMA
+Overworld_InitMirrorWarp_HDMA MirrorWarp_BuildAndEnableHDMATable
+Overworld_MirrorWarp_State3 MirrorWarp_BuildWavingHDMATable
+Overworld_MirrorWarp_State4 MirrorWarp_BuildDewavingHDMATable
+Dungeon_DrawObjects RoomDraw_DrawAllObjects
+Dungeon_LoadDoor RoomData_DrawObject_Door
+Dungeon_LoadType1Object RoomData_DrawObject
+Dungeon_DrawFloors RoomDraw_DrawFloors
+Dung_FillFloor RoomDraw_FloorChunks
+Object_Draw_N_4x4 RoomDraw_A_Many32x32Blocks
+Object_Draw_WallVert RoomDraw_Downwards4x2_1to15or26
+Object_Draw_WallHorz_LR RoomDraw_Rightwards2x4_1to15or26
+Object_Draw_WallVert_BothBg RoomDraw_Downwards4x2_1to16_BothBG
+Object_Draw_WallHorz_LR_BothBgs RoomDraw_Rightwards2x4spaced4_1to16
+Object_Draw_67 RoomDraw_Downwards2x2_1to16
+Object_Draw_07 RoomDraw_Rightwards2x2_1to16
+Object_Draw_60 RoomDraw_Downwards2x2_1to15or32
+Object_Draw2x2s_AdvanceRight RoomDraw_Rightwards2x2_1to15or32
+Object_Draw_C0 RoomDraw_4x4BlocksIn4x4SuperSquare
+Object_CeilingNW RoomDraw_DiagonalCeilingTopLeftA
+Object_CeilingSW RoomDraw_DiagonalCeilingBottomLeftA
+Object_CeilingNE RoomDraw_DiagonalCeilingTopRightA
+Object_CeilingSE RoomDraw_DiagonalCeilingBottomRightA
+Object_Draw_05 RoomDraw_Rightwards2x4spaced4_1to16_BothBG
+Object_Draw_65 RoomDraw_DownwardsDecor4x2spaced4_1to16
+Object_Draw_09 RoomDraw_DiagonalAcute_1to16
+Object_Draw_0A RoomDraw_DiagonalGrave_1to16
+Object_Draw_15 RoomDraw_DiagonalAcute_1to16_BothBG
+Object_Draw_16 RoomDraw_DiagonalGrave_1to16_BothBG
+Object_Draw_C1 RoomDraw_ClosedChestPlatform
+sub_818D47 RoomDraw_ChestPlatformHorizontalWallWithCorners
+Object_Draw_21 RoomDraw_Rightwards1x2_1to16_plus2
+Object_Draw_Nx3 RoomDraw_1x3_rightwards
+Object_Draw_C3 RoomDraw_3x3FloorIn4x4SuperSquare
+Object_Draw_A4_Hole RoomDraw_BigHole4x4_1to16
+Object_Draw_A5 RoomDraw_DiagonalCeilingTopLeftB
+Object_Draw_A6 RoomDraw_DiagonalCeilingBottomLeftB
+Object_Draw_A7 RoomDraw_DiagonalCeilingTopRightB
+Object_Draw_A8 RoomDraw_DiagonalCeilingBottomRightB
+Object_DrawLongVertRail RoomDraw_DownwardsHasEdge1x1_1to16_plus23
+Object_DrawVertRail RoomDraw_DownwardsHasEdge1x1_1to16_plus3
+Object_Draw_5F RoomDraw_RightwardsHasEdge1x1_1to16_plus23
+Object_DrawHorzRailThin RoomDraw_RightwardsHasEdge1x1_1to16_plus3
+Object_Draw_88 RoomDraw_DownwardsBigRail3x1_1to16plus5
+Object_Draw_5D RoomDraw_RightwardsBigRail1x3_1to16plus5
+Object_DrawEdge_LR RoomDraw_RightwardsHasEdge1x1_1to16_plus2
+Object_DrawEdge_UD RoomDraw_DownwardsEdge1x1_1to16
+Object_Draw_DB RoomDraw_4x4FloorTwoIn4x4SuperSquare
+Object_Draw_C4 RoomDraw_4x4FloorOneIn4x4SuperSquare
+nullsub_5 RoomDraw_Nothing_D
+Object_Draw_2F RoomDraw_RightwardsTopCorners1x2_1to16_plus13
+Object_Draw_30 RoomDraw_RightwardsBottomCorners1x2_1to16_plus13
+Object_Draw_6C RoomDraw_DownwardsLeftCorners2x1_1to16_plus12
+Object_Draw_6D RoomDraw_DownwardsRightCorners2x1_1to16_plus12
+Object_Draw_B0 RoomDraw_RightwardsEdge1x1_1to16plus7
+Object_Draw_8B RoomDraw_DownwardsEdge1x1_1to16plus7
+nullsub_2 RoomDraw_Nothing_A
+Object_Draw_70 RoomDraw_DownwardsFloor4x4_1to16
+Object_RedCarpetFloor RoomDraw_Rightwards4x4_1to16
+Object_Draw_71 RoomDraw_Downwards1x1Solid_1to16_plus3
+Object_RedCarpetFloorTrim RoomDraw_Rightwards1x1Solid_1to16_plus3
+sub_81913F RoomDraw_DoorSwitcherer
+nullsub_4 RoomDraw_Nothing_E
+Object_MovingWallRight RoomDraw_MovingWallWest
+Object_Draw_3x3 RoomDraw_ChestPlatformCorner
+Object_MovingWallLeft RoomDraw_MovingWallEast
+Object_MovingWall_IsEnabled RoomDraw_CheckIfWallIsMoved
+Object_MovingWall_Func1 MovingWall_FillReplacementBuffer
+Object_Draw_36 RoomDraw_RightwardsDecor4x4spaced2_1to16
+Object_Draw_73 RoomDraw_DownwardsDecor4x4spaced2_1to16
+Object_Draw_38 RoomDraw_RightwardsStatue2x3spaced2_1to16
+Object_Draw_5E RoomDraw_RightwardsBlock2x2spaced2_1to16
+Object_Draw_89 RoomDraw_DownwardsBlock2x2spaced2_1to16
+Object_Draw_75 RoomDraw_DownwardsPillar2x4spaced2_1to16
+Object_Draw_39 RoomDraw_RightwardsPillar2x4spaced4_1to16
+Object_DrawWallDecor RoomDraw_RightwardsDecor4x3spaced4_1to16
+Object_Draw_76 RoomDraw_DownwardsDecor3x4spaced4_1to16
+Object_Draw_3C RoomDraw_RightwardsDoubled2x2spaced2_1to16
+Object_Draw_DD RoomDraw_TableRock4x4_1to16
+Object_Draw_DE RoomDraw_Spike2x2In4x4SuperSquare
+Object_Draw_78 RoomDraw_DownwardsDecor2x2spaced12_1to16
+Object_WallColumn RoomDraw_RightwardsDecor2x2spaced12_1to16
+Object_Draw_47 RoomDraw_Waterfall47
+Object_Draw_48 RoomDraw_Waterfall48
+Object_Draw_49 RoomDraw_RightwardsFloorTile4x2_1to16
+Object_Draw_4C RoomDraw_RightwardsBar4x3_1to16
+Object_Draw_4D RoomDraw_RightwardsShelf4x4_1to16
+Object_Draw_D8 RoomDraw_WaterOverlayA8x8_1to16
+Object_Draw_DA RoomDraw_WaterOverlayB8x8_1to16
+Object_Draw_50 RoomDraw_RightwardsLine1x1_1to16plus1
+Object_Draw_7C RoomDraw_DownwardsLine1x1_1to16plus1
+Object_Draw_WallTorches RoomDraw_RightwardsDecor4x2spaced8_1to16
+Object_Draw_7F RoomDraw_DownwardsDecor2x4spaced8_1to16
+nullsub_3 RoomDraw_Nothing_C
+Object_Draw_81 RoomDraw_DownwardsDecor3x4spaced2_1to16
+Object_Draw_ChestPlatform RoomDraw_OpenChestPlatform
+Object_Draw_8F RoomDraw_DownwardsBar2x5_1to16
+Object_Draw_B5 RoomDraw_Weird2x4_1_to_16
+Object_Draw4x4 RoomDraw_4x4
+Object_Draw_Nx4 RoomDraw_Object_Nx4
+Object_Draw4x4_BothBgs RoomDraw_4x4Corner_BothBG
+Object_Draw3x4_BothBgs RoomDraw_WeirdCornerBottom_BothBG
+Object_Draw4x3_BothBgs RoomDraw_WeirdCornerTop_BothBG
+Object_LitTorch RoomDraw_LitTorch
+Object_Draw_2x2 RoomDraw_Rightwards2x2
+Object_BigKeyLock RoomDraw_BigKeyLock
+Object_Chest RoomDraw_Chest
+Object_BigChest RoomDraw_BigChest
+Object_Draw4x3_0 RoomDraw_TableRock4x3
+Object_Draw3x4 RoomDraw_SolidWallDecor3x4
+Object_OpenedBigChest RoomDraw_BigChest_opened
+Object_OpenedBigChest_fake RoomDraw_OpenBigChest
+Object_Draw3x8 RoomDraw_BigWallDecor
+Object_Draw3x6 RoomDraw_Utility6x3
+Object_Draw7x8 RoomDraw_MagicBatAltar
+Object_Draw8x6 RoomDraw_SmithyFurnace
+Object_StarTile_on RoomDraw_EnabledStarSwitch
+Object_Draw6x4 RoomDraw_VerticalTurtleRockPipe
+Object_Draw4x6 RoomDraw_HorizontalTurtleRockPipe
+Object_Rupees RoomDraw_RupeeFloor
+Object_Draw5x4 RoomDraw_Bed4x5
+sub_819B18 UNREACHABLE_019B18
+Object_WaterLadder RoomDraw_WaterHopStairs_A
+Object_DrawWallPaint RoomDraw_PortraitOfMario
+Object_Draw6x3 RoomDraw_DrawRightwards3x6
+Object_SanctuaryMantle RoomDraw_SanctuaryWall
+Object_Draw_3x2_0 RoomDraw_ChestPlatformVerticalWall
+Object_Watergate RoomDraw_DamFloodGate
+sub_819C3B RoomDraw_SomariaLine_increment_count
+Object_PrisonBars RoomDraw_PrisonCell
+Object_Draw_51 RoomDraw_RightwardsCannonHole4x3_1to16
+Object_Draw_85 RoomDraw_DownwardsCannonHole3x4_1to16
+Object_00_DrawWaterFace RoomDraw_EmptyWaterFace
+Object_Draw_4x2 RoomDraw_TableBowl
+Object_Draw_4xN RoomDraw_WaterHoldingObject
+Object_KholdstareShell RoomDraw_KholdstareShell
+Object_Draw8xN_BG2 RoomDraw_SomeBigDecors
+Object_TrinexxShell RoomDraw_TrinexxShell
+Object_LanternLayer RoomDraw_LampCones
+Object_LanternLayer_Helper RoomDraw_SingleLampCone
+Object_AgahnimAltar RoomDraw_AgahnimsAltar
+Object_AgahnimRoomFrame RoomDraw_AgahnimsWindows
+Object_FortuneTellerTemplate RoomDraw_FortuneTellerRoom
+Object_55_WaterTroof RoomDraw_Utility3x5
+Object_Draw62 RoomDraw_VitreousGooGraphics
+Object_EntireFloorIsPit RoomDraw_BG2MaskFull
+Object_InterStaircase1 RoomDraw_AutoStairs_North_MultiLayer_A
+sub_81A2C1 AutoStairsNorthMergedStart
+Object_InterStaircase3 RoomDraw_AutoStairs_North_MergedLayer_A
+Object_InterStaircase4 RoomDraw_AutoStairs_North_MergedLayer_B
+Object_Stair RoomDraw_AutoStairs_South_MultiLayer_A
+sub_81A36A South_MergedStairs_BecomeMultiC
+Object_StairWetS RoomDraw_AutoStairs_South_MultiLayer_C
+Object_33_StairsSubmerged RoomDraw_AutoStairs_South_MergedLayer
+Object_InactiveWaterLadder RoomDraw_WaterHopStairs_B
+Object_InterStaircase5 RoomDraw_InterRoomFatStairsUp
+Object_InterStaircase6 RoomDraw_InterRoomFatStairsDown_A
+Object_InterStaircase7 RoomDraw_InterRoomFatStairsDown_B
+Object_WallUpNorthSpiralStaircase RoomDraw_SpiralStairsGoingUpUpper
+Object_WallUpNorthSpiralStaircase2 RoomDraw_SpiralStairsGoingUpLower
+Object_WallDownNorthSpiralStaircase RoomDraw_SpiralStairsGoingDownUpper
+Object_WallDownNorthSpiralStaircase2 RoomDraw_SpiralStairsGoingDownLower
+Object_1E_Staircase RoomDraw_StraightInterroomStairsGoingUpNorthUpper
+Object_26_Staircase RoomDraw_StraightInterroomStairsGoingUpNorthLower
+Object_27_Staircase RoomDraw_StraightInterroomStairsGoingDownNorthLower
+sub_81A6B5 StraightInterroomStairsLowerMain
+Object_28_Staircase RoomDraw_StraightInterroomStairsGoingUpSouthLower
+Object_29_Staircase RoomDraw_StraightInterroomStairsGoingDownSouthLower
+sub_81A767 StraightInterroomStairsLower_continue
+Object_Draw6x3_Stuff RoomDraw_ArcheryGameTargetDoor
+Object_Stacked4x4s RoomDraw_LightBeamOnFloor
+Object_BlindLight RoomDraw_BigLightBeamOnFloor
+Object_Triforce RoomDraw_GanonTriforceFloorDecor
+Object_Draw10x20_With4x4 RoomDraw_VitreousGooDamage
+Door_Up RoomDraw_Door_North
+Door_Up_Draw_Types_Below_0x40 RoomDraw_NormalRangedDoors_North
+Door_Up_PositionLessThan6 RoomDraw_OneSidedShutters_North
+Door_Down RoomDraw_Door_South
+Door_Down_Draw_Helper_2 RoomDraw_CheckIfLowerLayerDoors_Y
+Door_Draw_Helper_4 RoomDraw_OneSidedShutters_South
+Door_Left RoomDraw_Door_West
+Door_Left_AddNormalDoor RoomDraw_NormalRangedDoors_West
+Dung_PlotDoor_Nx4 RoomDraw_DrawUnreachableDoorSwitcher
+Door_Right RoomDraw_Door_East
+Door_Right_AddNormalDoor RoomDraw_NormalRangedDoors_East
+Door_Right_Helper1 RoomDraw_OneSidedShutters_East
+Draw_Tiles_R14x4 DrawUnusedDoorSwitchObject
+Door_Up_SwordActivated RoomDraw_NorthCurtainDoor
+Door_BlastWallUp_Helper3 ExplodingWallNotOpen
+Door_BlastWallUp RoomDraw_Door_ExplodingWall
+Door_BlastWallUp_Helper RoomDraw_ExplodingWallSegment
+Door_BlastWallUp_Helper2 RoomDraw_ExplodingWallColumn
+Door_Up_Draw_Types_Above_0x40 RoomDraw_HighRangeDoor_North
+Door_Down_Draw_Types_Above_0x40 RoomDraw_OneSidedLowerShutters_South
+Door_Left_AddDoorAbove0x40 RoomDraw_HighRangeDoor_West
+Door_Right_AddDoorAbove0x40 RoomDraw_OneSidedLowerShutters_East
+Door_Up_EntranceDoor_UNUSED RoomDraw_MakeDoorHighPriorityLowerLayer_North
+Door_Helper_SetPriority RoomDraw_MakeDoorHighPriority_North
+Door_Down_EntranceDoor_UNUSED RoomDraw_MakeDoorHighPriorityLowerLayer_South
+Door_Helper_SetPriority2 RoomDraw_MakeDoorHighPriority_South
+Door_Left_EntranceDoor_UNUSED RoomDraw_MakeDoorHighPriorityLowerLayer_West
+Door_Helper_SetPriority3 RoomDraw_MakeDoorHighPriority_West
+Door_Right_EntranceDoor_UNUSED RoomDraw_MakeDoorHighPriorityLowerLayer_East
+Door_PrioritizeAligned RoomDraw_MakeDoorHighPriority_East
+Door_AddPalaceToggleProperty RoomDraw_MarkDungeonToggleDoor
+Door_AddFloorToggleProperty RoomDraw_MarkLayerToggleDoor
+Object_Size_1_to_16 RoomDraw_GetObjectSize_1to16
+Object_Size_1_to_15_or_26 RoomDraw_GetObjectSize_1to15or26
+Object_Size_1_to_15_or_32 RoomDraw_GetObjectSize_1to15or32
+Door_Register RoomDraw_FlagDoorsAndGetFinalType
+Object_CheckTileNotEqualTo RoomDraw_SmallRailCorner
+Door_Prioritize7x4_Unreferenced UNREACHABLE_01B19E
+Door_Prioritize4x7 RoomDraw_MakeDoorPartsHighPriority_Y
+Door_Prioritize7x4 UNREACHABLE_01B1E1
+Door_Prioritize5x4 RoomDraw_MakeDoorPartsHighPriority_X
+Object_Draw_4x2_N RoomDraw_Downwards4x2VariableSpacing
+UNUSED_sub_81B254 UNREACHABLE_01B254
+UNUSED_sub_81B264 UNREACHABLE_01B264
+Object_Draw1x5 RoomDraw_DrawObject2x2and1
+sub_81B293 RoomDraw_DrawDiagonalGrave
+sub_81B2A1 RoomDraw_DrawDiagonalAcute
+Object_Draw_2x2_AdvanceDown RoomDraw_Object_2x2_downwards
+Object_DrawInteriorEdge RoomDraw_LineOf8x8_advance_and_use_B2_for_count
+Object_Draw1x4 RoomDraw_RightwardShelfEnd
+Object_Draw1x3 RoomDraw_RightwardBarSegment
+Object_2B_Staircase RoomDraw_WeirdGloveRequiredPot
+sub_81B30B RoomDraw_WeirdUglyPot
+Object_LargeLiftableBlock RoomDraw_BigGrayRock
+Object_ReplacementTileHelper DrawBigGraySegment
+Object_Draw_BC RoomDraw_RightwardsFakePots2x2_1to16
+Object_Draw_95 RoomDraw_DownwardsFakePots2x2_1to16
+Object_Pot RoomDraw_SinglePot
+Object_BombableFloor RoomDraw_BombableFloor
+Object_Draw_BD RoomDraw_RightwardsHammerPegs2x2_1to16
+Object_Draw_96 RoomDraw_DownwardsHammerPegs2x2_1to16
+Object_PegBlock RoomDraw_HammerPegSingle
+Dungeon_LoadBlock DrawObjects_PushableBlock
+Dungeon_LoadTorch DrawObjects_LightableTorch
+Dungeon_CheckAdjacentRoomOpenedDoors Dungeon_CheckAdjacentRoomsForOpenDoors
+Dungeon_ApplyOverlay_Far Dungeon_ApplyRoomOverlay
+Dungeon_LoadAttrIncremental Dungeon_LoadAttribute_Selectable
+Dungeon_LoadAttrTable Dungeon_LoadAttributeTable
+Dungeon_LoadBasicAttr Dungeon_LoadBasicAttribute
+Dungeon_LoadBasicAttr_full Dungeon_LoadBasicAttribute_full
+Dungeon_LoadObjAttr Dungeon_LoadObjectAttribute
+Dungeon_SetChestAttr Dungeon_SetChestAttributes
+Dungeon_LoadDoorAttr Dungeon_LoadDoorAttribute
+Dungeon_LoadSingleDoorAttr Dungeon_LoadSingleDoorAttribute
+someExperimentalCrap ChangeDoorToSwitch
+Dungeon_InitBarrierAttr Dungeon_InitializePegAttribute
+Dungeon_ToggleBarrierAttr Dungeon_FlipCrystalPegAttribute
+Dungeon_CheckStairsAndRunScripts Dungeon_HandleRoomTags
+Dungeon_DetectStaircaseEasyOut RoomTag_DirtyExit
+Dung_TagRoutine_0x29 RoomTag_NorthWestTrigger
+Dung_TagRoutine_0x31 RoomTag_QuadrantTrigger
+Dung_TagRoutine_0x32 RoomTag_RoomTrigger
+Dung_TagRoutine_0x3F RoomTag_RekillableBoss
+Dung_TagRoutine_0x14 RoomTag_RoomTrigger_BlockDoor
+Dung_TagRoutine_0x15 RoomTag_PrizeTriggerDoorDoor
+Dung_TagRoutine_0x16 RoomTag_SwitchTrigger_HoldDoor
+Dung_TagRoutine_0x17 RoomTag_SwitchTrigger_ToggleDoor
+Dung_DoorSwitch_Func2 PushPressurePlate
+Dung_TagRoutine_0x33 RoomTag_TorchPuzzleDoor
+Dung_TagRoutine_0x20 RoomTag_Switch_ExplodingWall
+Dung_TagRoutine_0x28 RoomTag_PullSwitchExplodingWall
+Dung_TagRoutine_0x25 RoomTag_GetHeartForPrize
+Dung_TagRoutine_0x38 RoomTag_Agahnim
+Dung_TagRoutine_0x3D RoomTag_GanonDoor
+Dung_TagRoutine_0x26 RoomTag_KillRoomBlock
+Dung_TagRoutine_0x3C RoomTag_PushBlockForChest
+Dung_TagRoutine_0x27 RoomTag_TriggerChest
+Dung_TagRoutine_Helper RoomTag_OperateChestReveal
+Dung_TagRoutine_0x3E RoomTag_TorchPuzzleChest
+Dung_TagRoutine_0x1C RoomTag_MovingWall_East
+MovingWall_Func1 RoomTag_MovingWallShakeItUp
+Dung_TagRoutine_0x1D RoomTag_MovingWall_West
+Dung_TagRoutine_0x1F RoomTag_MovingWallTorchesCheck
+MovingWall_Func2 MovingWall_MoveALittle
+MovingWall_Func3 RoomTag_AdvanceGiganticWall
+Dung_TagRoutine_0x18 RoomTag_WaterOff
+Dung_TagRoutine_0x19 RoomTag_WaterOn
+Dung_TagRoutine_0x1A_Watergate RoomTag_WaterGate
+Dung_TagRoutine_0x21 RoomTag_Holes0
+Dung_TagRoutine_0x22 RoomTag_ChestHoles0
+Dung_TagRoutine_0x24 RoomTag_Holes2
+Object_WatergateChannelWater RoomTag_OperateWaterFlooring
+Dung_DoorSwitch_Func1 RoomTag_MaybeCheckShutters
+Dung_DoorSwitch_GetPos RoomTag_GetTilemapCoords
+Dung_CheckStarTileSwitch RoomTag_CheckForPressedSwitch
+Dungeon_ProcessTorchAndDoorInteractives Dungeon_ProcessTorchesAndDoors
+Bomb_CheckForVulnerableTileObjects Bomb_CheckForDestructibles
+Dung_AnimDoor DrawDoorOpening_Step1
+Dung_AnimTrapDoor DrawShutterDoorSteps
+Dung_AnimDoorB DrawEyeWatchDoor
+sub_81D365 IndexAndClearCurtainDoor
+Dungeon_AnimateTrapDoors OperateShutterDoors
+Dungeon_AnimateDestroyingWeakDoor OpenCrackedDoor
+Dungeon_OpeningLockedDoor_Far UnlockKeyDoor_Main
+Dungeon_LoadToggleDoorAttr Dungeon_LoadSingleDoorTileAttribute_from_wram_index
+Dungeon_LoadDoorAttrInner Dungeon_LoadSingleDoorTileAttribute
+Dungeon_OpeningLockedDoor_StairMaskLocked DrawCompletelyOpenDoor
+Door_BlastWallExploding Dungeon_ClearAwayExplodingWall
+Dungeon_QueryIfTileLiftable Dungeon_CheckForAndIDLiftableTile
+PushBlock_Handler_Inner PushBlock_Main
+Dungeon_EraseInteractive2x2 RoomDraw_16x16Single
+PushBlock_StoppedMoving PushBlock_CheckForPit
+Dungeon_GetInteractiveVramAddr RoomDraw_16x16SingleSingleTileStripe
+Dungeon_RevealCoveredTiles Dungeon_LiftAndReplaceLiftable
+Dungeon_CustomIndexedRevealCoveredTiles ThievesAttic_DrawLightenedHole
+return0_loc_81DAB6 FAIL_01DAB4
+Dungeon_ToolAndTileInteraction HandleItemTileAction_Dungeon
+Dungeon_GetUprootedTerrainSpawnCoords ManipBlock_Something
+Dungeon_LoadSecret RevealPotItem
+Dungeon_SpriteInducedTilemapUpdate Dungeon_UpdateTileMapWithCommonTile
+Dungeon_ClearRupeeTile Dungeon_DeleteRupeeTile
+Dungeon_OpenKeyedObject OpenChestForItem
+Dungeon_OpenBigChest OpenBigChest
+Dungeon_ShowMinigameChestMessage OpenMiniGameChestFail
+Dungeon_OpenMiniGameChest OpenMiniGameChest
+Dungeon_GetRupeeChestMinigamePrize_highStakes OpenMiniGameChest_HighStake
+Dungeon_GetKeyedObjectRelativeVramAddr RoomTag_BuildChestStripes
+Dungeon_TurnOffWater_Case0 IncrementallyDrainSwampPool
+Dungeon_TurnOffWater_Case1 DeleteSwampPoolWaterOverlay
+Dungeon_TurnOnOffWater_Func0 Dungeon_FloodSwampWater_PrepTileMap
+Dungeon_TurnOnWaterLong Dungeon_FloodSwampWater
+Dungeon_TurnOnWaterLong_Func4 Dungeon_FloodSwampWater_VomitWater
+Dungeon_OnOffWater_Helper Dungeon_AdjustWaterVomit
+Dungeon_TurnOnWaterLong_Func9 Dungeon_FloodSwampWater_SpillToFloor
+Dungeon_TurnOnWater_Func11 Dungeon_FloodSwampWater_RiseInLevel
+Watergate_Main Dungeon_FloodDam
+sub_81F309 EXIT_01F307
+Watergate_Main_State4 FloodDam_Expand
+Watergate_Main_State0 FloodDam_PrepTiles_init
+Watergate_Main_State5 FloodDam_Fill
+Dungeon_ExtinguishFirstTorch Ganon_ExtinguishTorch_adjust_translucency
+Dungeon_ExtinguishSecondTorch Ganon_ExtinguishTorch
+Dungeon_ElevateStaircasePriority SpiralStairs_MakeNearbyWallsHighPriority_Entering
+Dungeon_DecreaseStaircasePriority SpiralStairs_MakeNearbyWallsLowPriority
+Dungeon_OpenGanonDoor_Far RoomDraw_OpenTriforceDoor
+UNUSED_sub_81F6B4 UNREACHABLE_01F6B2
+Dungeon_PrepOverlayDma RoomDraw_AdjustTorchLightingChange
+Door_BlastWallExploding_CopyToVram ClearAndStripeExplodingWall
+sub_81F908 UNREACHABLE_01F906
+Dungeon_DrawOverlay Dungeon_DrawRoomOverlay
+Dung_AnimTrapDoor_Up GetDoorDrawDataIndex_North_clean_door_index
+Dung_AnimDoor_Up DoorDoorStep1_North
+Dung_AnimDoor_Up_Inner GetDoorDrawDataIndex_North
+Dung_AnimDoorB_Up DrawDoorToTileMap_North
+Dung_AnimTrapDoor_Down GetDoorDrawDataIndex_South_clean_door_index
+Dung_AnimDoor_Down DoorDoorStep1_South
+Dung_AnimDoor_Down_Inner GetDoorDrawDataIndex_South
+Dung_AnimDoorB_Down DrawDoorToTileMap_South
+Dung_AnimTrapDoor_Left GetDoorDrawDataIndex_West_clean_door_index
+Dung_AnimDoor_Left DoorDoorStep1_West
+Dung_AnimDoor_Left_Inner GetDoorDrawDataIndex_West
+Dung_AnimDoorB_Left DrawDoorToTileMap_West
+Dung_AnimTrapDoor_Right GetDoorDrawDataIndex_East_clean_door_index
+Dung_AnimDoor_Right DoorDoorStep1_East
+Dung_AnimDoor_Right_Inner GetDoorDrawDataIndex_East
+Dung_AnimDoorB_Right DrawDoorToTileMap_East
+sub_81FD3E ClearDoorCurtainsFromTileMap
+Dung_AnimDoorB_Remap GetDoorGraphicsIndex
+Door_BlastWallExploding_Helper3 ClearExplodingWallFromTileMap
+Door_BlastWallExploding_Helper4 ClearExplodingWallFromTileMap_ClearOnePair
+Dungeon_ApplyOverlayAttr Dungeon_DrawRoomOverlay_Apply
+Dungeon_ApproachFixedColor ApplyGrayscaleFixed_Incremental
+Player_SetElectrocutionMosaicLevel LinkZap_HandleMosaic
+Player_LedgeJumpInducedLayerChange Dungeon_HandleLayerChange
+Player_CacheStatePriorToHandler CacheCameraProperties
+Link_CheckSwimCapability CheckAbilityToSwim
+Overworld_PitDamage TakeDamageFromPit
+Module_LoadFile Module05_LoadFile
+Module_LoadGame_indoors LoadDungeonRoomRebuildHUD
+Dungeon_InitAndCacheVars2 CacheRoomEntryProperties
+Module_PreOverworld Module08_OverworldLoad
+Overworld_LoadMusicIfNeeded LoadOWMusicIfNeeded
+PreOverworld_LoadBunnyStuff AdjustLinkBunnyStatus
+Player_RemoveBunny ForceNonbunnyStatus
+Module_LocationMenu Module1B_SpawnSelect
+EndingSequenceCode Credits_LoadScene_Overworld
+EndingSequenceCode_0 Credits_LoadScene_Overworld_PrepGFX
+EndingSequenceCode_1 Credits_LoadScene_Overworld_Overlay
+EndingSequenceCode_2 Credits_LoadScene_Overworld_LoadMap
+EndSequence1_Func1 Credits_OperateScrollingAndTileMap
+Ending_Func7 Credits_LoadCoolBackground
+Ending_CinemaSequencesIndoorsInit Credits_LoadScene_Dungeon
+Module_Dungeon Module07_Dungeon
+Dung_CheckTriggerInterRoomTrans Dungeon_TryScreenEdgeTransition
+Dungeon_StartInterRoomTrans Dungeon_HandleEdgeTransitionMovement
+Dungeon_Normal Module07_00_PlayerControl
+Dungeon_IntraRoomTrans Module07_01_SubtileTransition
+Dungeon_IntraRoomTransShutDoors DungeonTransition_Subtile_ResetShutters
+Dungeon_IntraRoomTransInit DungeonTransition_Subtile_PrepTransition
+Dungeon_IntraRoomTransFilter DungeonTransition_Subtile_ApplyFilter
+Dungeon_IntraRoomTransOpenDoors DungeonTransition_Subtile_TriggerShutters
+Dungeon_InterRoomTrans Module07_02_SupertileTransition
+Dungeon_InterRoomTrans_State0 Module07_02_00_InitializeTransition
+Dungeon_InterRoomTrans_State1 Module07_02_01_LoadNextRoom
+Dung_UpdateLightsOutColor DungeonTransition_RunFiltering
+Dungeon_InterRoomTrans_State2 Module07_02_FadedFilter
+Dungeon_ApplyOverlay Module07_03_OverlayChange
+Dungeon_OpeningLockedDoor Module07_04_UnlockDoor
+Dungeon_Submodule_5_TriggerAnim Module07_05_ControlShutters
+Dungeon_Submodule_6_UpFloorTrans Module07_06_FatInterRoomStairs
+Dungeon_SpiralStaircase1 Module07_0E_01_HandleMusicAndResetProps
+Dungeon_Teleport0 ResetTransitionPropsAndAdvance_ResetInterface
+Dungeon_Staircase_Func1 ResetTransitionPropsAndAdvanceSubmodule
+Dungeon_Staircase3 Dungeon_InitializeRoomFromSpecial
+sub_828D01 DungeonTransition_FatStairs_RunFade
+Dungeon_Staircase6 DungeonTransition_LoadSpriteGFX
+Dungeon_HoleStaircase DungeonTransition_AdjustForFatStairScroll
+sub_828D5F DungeonTransition_FatStairsEntryCache
+Dungeon_InitAndCacheVars ResetThenCacheRoomEntryProperties
+Dungeon_Staircase4 DungeonTransition_TriggerBGC34UpdateAndAdvance
+Dungeon_Staircase5 DungeonTransition_TriggerBGC56UpdateAndAdvance
+Dungeon_Submodule_7_DownFloorTrans Module07_07_FallingTransition
+Dungeon_StraightStaircase0 Module07_07_00_HandleMusicAndResetRoom
+Dungeon_StraightStaircase6 Module07_07_06_SyncBG1and2
+Dungeon_StraightStaircase15 Module07_07_0F_FallingFadeIn
+Dungeon_SpiralStaircase7_Inner4 Dungeon_PlayBlipAndCacheQuadrantVisits
+Dungeon_StraightStaircase16 Module07_07_10_LandLinkFromFalling
+Dungeon_StraightStaircase17 Module07_07_11_CacheRoomAndSetMusic
+Dungeon_Straight_StaircaseDown Module07_08_NorthIntraRoomStairs
+Dungeon_Straight_StaircaseDown_State0 Module07_08_00_InitStairs
+Dungeon_Straight_StaircaseDown_State1 Module07_08_01_ClimbStairs
+Dungeon_Straight_Staircase Module07_10_SouthIntraRoomStairs
+Dungeon_Straight_StaircaseUp_State0 Module07_10_00_InitStairs
+Dungeon_Straight_StaircaseUp_State1 Module07_10_01_ClimbStairs
+Dungeon_DestroyingWeakDoor Module07_09_OpenCrackedDoor
+Dungeon_Submodule_A Module07_0A_ChangeBrightness
+Dungeon_TurnOffWater Module07_0B_DrainSwampPool
+Dungeon_TurnOnWater Module07_0C_FloodSwampWater
+Dungeon_Watergate Module07_0D_FloodDam
+Dungeon_SpiralStaircase Module07_0E_SpiralStairs
+Dungeon_SpiralStaircase15 Dungeon_DoubleApplyAndIncrementGrayscale
+Dungeon_SpiralStaircase2 Module07_0E_02_ApplyFilterIf
+Dungeon_SpiralStaircase7 Dungeon_SyncBackgroundsFromSpiralStairs
+Dungeon_SpiralStaircase16 Dungeon_AdvanceThenSetBossMusicUnorthodox
+Dungeon_Staircase_MusicFunc1 Dungeon_SetBossMusicUnorthodox
+Dungeon_SpiralStaircase0 Module07_0E_00_InitPriorityAndScreens
+Dungeon_SpiralStaircase19 Module07_0E_13_SetRoomAndLayerAndCache
+UsedForSpiralStaircase_Helper3 RepositionLinkAfterSpiralStairs
+Dungeon_SpiralStaircase7_Inner SpiralStairs_MakeNearbyWallsHighPriority_Exiting
+Dungeon_Submodule_F Module07_0F_LandingWipe
+Dungeon_Submodule_F_State0 Module07_0F_00_InitSpotlight
+Dungeon_Submodule_F_State1 Module07_0F_01_OperateSpotlight
+Dungeon_StraightStairs Module07_11_StraightInterroomStairs
+StraightStairs_0 Module07_11_00_PrepAndReset
+StraightStairs_1 Module07_11_01_FadeOut
+StraightStairs_2 Module07_11_02_LoadAndPrepRoom
+StraightStairs_3 Module07_11_03_FilterAndLoadBGChars
+StraightStairs_4 Module07_11_04_FilterDoBGAndResetSprites
+StraightStairs_11 Module07_11_0B_PrepDestination
+StraightStairs_9 Module07_11_09_LoadSpriteGraphics
+StraightStairs_16 Module07_11_19_SetSongAndFilter
+StraightStairs_17 Module07_11_11_KeepSliding
+Dungeon_Submodule_14_FallGap Module07_14_RecoverFromFall
+Dungeon_Submodule_14_FallGap_0 Module07_14_00_ScrollCamera
+Overworld_Func2A_State1 RecoverPositionAfterDrowning
+Dungeon_Teleport Module07_15_WarpPad
+Dungeon_Teleport1 Module07_15_01_ApplyMosaicAndFilter
+Dungeon_Teleport4 Module07_15_04_SyncRoomPropsAndBuildOverlay
+Dungeon_Teleport13 Module07_15_0E_FadeInFromWarp
+Dungeon_Teleport14 Module07_15_0F_FinalizeAndCacheEntry
+Dungeon_Submodule_16 Module07_16_UpdatePegs
+Dungeon_OrangeBlueBarrierUpload_A Module07_16_UpdatePegs_Step1
+Dungeon_OrangeBlueBarrierUpload_B Module07_16_UpdatePegs_Step2
+Dungeon_OrangeBlueBarrierUpload_C Module07_16_UpdatePegs_Step3
+Dungeon_OrangeBlueBarrierUpload Dungeon_UpdatePegGFXBuffer
+sub_8297A9 Module07_16_UpdatePegs_FinishUp
+Dungeon_OrangeBlueBarrierUpload_C RecoverPegGFXFromMapping
+Dungeon_Submodule_17 Module07_17_PressurePlate
+Dungeon_Crystal Module07_18_RescuedMaiden
+Dungeon_Crystal0 PrepareForCrystalCutscene
+Dungeon_Crystal1 BuildCrystalCutsceneTilemap
+Dungeon_Crystal10 StartCrystalCutscene
+Dungeon_Submodule_19 Module07_19_MirrorFade
+Dungeon_OpenGanonDoor Module07_1A_RoomDraw_OpenTriforceDoor_bounce
+UNUSED_Module_Unknown0 Module0C_Unused
+UNUSED_sub_829922 Module0C_RunSubmodule
+UNUSED_sub_82992E Module0C_RestoreModule
+UNUSED_Module_Unknown1 Module0D_Unused
+UNUSED_sub_829951 Module0D_RunSubmodule
+UNUSED_sub_82995B Module0D_RestoreModule
+Module_CloseSpotlight Module0F_SpotlightClose
+CloseSpotlight_Init Dungeon_PrepExitWithSpotlight
+OpenSpotlight_Next Spotlight_ConfigureTableAndControl
+Module_OpenSpotlight Module10_SpotlightOpen
+OpenSpotlight_Init Module10_00_OpenIris
+Module_HoleToDungeon Module11_DungeonFallingEntrance
+HoleToDungeon_FadeMusic Module_11_00_SetSongAndInit
+HoleToDungeon_LoadDungeon Module11_02_LoadEntrance
+HoleToDungeon_4 Module11_04_FadeAndLoadQuadrants
+Module_BossVictory Module13_BossVictory_Pendant
+Module_Victory_0 BossVictory_Heal
+Module_Victory_1 Dungeon_StartVictorySpin
+Module_Victory_2 Dungeon_RunVictorySpin
+Module_Victory_3 Dungeon_CloseVictorySpin
+Module_KillAgahnim Module15_MirrorWarpFromAga
+Mirror_LoadMusic Module15_00_Initialize
+Mirror_Init Module15_01_SetTheScene
+Mirror_Func2 Module15_02_RunMirrorWarp_Part1
+Mirror_Func3 Module15_03_RunMirrorWarp_Part2
+MirrorWarp_LoadNext_0_Helper SetTargetOverworldWarpToPyramid
+Mirror_Func30 ResetAncillaAndCutscene
+Module_Victory Module16_BossVictory_Crystal
+nullsub_16 EXIT_029D90
+Module_Victory_4 Module16_04_FadeAndEnd
+Module_GanonEmerges Module18_GanonEmerges
+Module_TriforceRoom Module19_TriforceRoom
+TriforceRoom_Step0 Module19_00_ResetAndInit
+TriforceRoom_Step1 Module19_01_MosaicAndPalette
+TriforceRoom_Step2 Module19_02_LoadMusicAndScreen
+TriforceRoom_Step3 Module19_03_PrepTileSetsPalette
+TriforceRoom_Step4 Module19_04_LoadAndSongAndAdvance
+TriforceRoom_Step5 Module19_05_WalkLinkIn
+TriforceRoom_Step6 Module19_06_MosaicFadeIn
+TriforceRoom_Step7 Module19_07_PrepMessage
+TriforceRoom_Step9 Module19_09_TriforceSpeak
+TriforceRoom_Step8_10 Module19_TriforceExpansionControl
+TriforceRoom_Step11 Module19_0B_ApproachTriforce
+TriforceRoom_Step12 Module19_0C_HoldTriforce
+TriforceRoom_Step13 Module19_0D_FadeToWhite
+TriforceRoom_Step14 Module19_0E_AdvanceToCredits
+Dungeon_SaveRoomData Mirror_SaveRoomData
+Dungeon_SaveRoomData_justKeys SaveDungeonKeys
+Palette_Func1 Dungeon_HandleTranslucencyAndPalettes
+UNUSED_sub_82A281 UnusedInterfacePaletteRecovery
+HoleToDungeon_PaletteFilter PaletteFilter_bounce
+PaletteFilter_doFiltering ApplyPaletteFilter_bounce
+Palette_Func1 Dungeon_HandleTranslucencyAndPalette
+sub_82A2B1 UNREACHABLE_02A1A8
+Dung_AdjustCoordsForNewRoom Dungeon_AdjustAfterSpiralStairs
+Dungeon_AdjustCoordsForLinkedRoom Dungeon_AdjustForTeleportDoors
+Module_Overworld Module09_Overworld
+Overworld_DrawBadWeather OverworldOverlay_HandleRain
+Overworld_Func0_Main Module09_00_PlayerControl
+Overworld_CheckSwitchArea OverworldHandleTransitions
+Overworld_LoadMapProperties Overworld_LoadGFXAndScreenSize
+Overworld_Func0_Main_SpecialOverworld ScrollAndCheckForSOWExit
+Overworld_LoadTransGfx Module09_LoadAuxGFX
+Overworld_TransMapData Module09_LoadNewMapAndGFX
+Overworld_Func6 Overworld_RunScrollTransition
+Overworld_TransMapData2 Module09_LoadNewSprites
+Overworld_TransMapData2_justScroll Overworld_StartScrollTransition
+Overworld_Func7 Overworld_EaseOffScrollTransition
+Overworld_FuncA_StepOutOfDoor Module09_0A_WalkFromExiting_FacingDown
+Overworld_FuncB Module09_0B_WalkFromExiting_FacingUp
+Overworld_Func9_DoorStuff Module09_09_OpenBigDoorFromExiting
+DoorAnim_DoWork2 Overworld_DoMapUpdate32x32_B
+sub_82AD63 UNREACHABLE_02AC62
+Overworld_FuncC Module09_0C_OpenBigDoor
+DoorAnim_Func1 Overworld_DoMapUpdate32x32_conditional
+DoorAnim_DoWork Overworld_DoMapUpdate32x32
+Overworld_FuncD Overworld_StartMosaicTransition
+Overworld_FuncD_State2 OverworldMosaicTransition_HandleScreensAndLoadShroom
+UNUSED_sub_82AEDD Module09_1D_02_FBlankAndEnterModule0A
+UNUSED_sub_82AEF9 Module09_1E_02_FBlankAndLoadSPOW
+Overworld_Func16 Module09_FadeBackInFromMosaic
+Overworld_Func16_State0 OverworldMosaicTransition_RecoverDestinationPalettes
+Overworld_State0_Helper OverworldMosaicTransition_LoadSpriteGraphicsAndSetMosaic
+Overworld_Func16_State1 OverworldMosaicTransition_FilterAndLoadGraphics
+Overworld_Func1C_State2 Module09_1C_02_HandleMusic
+Overworld_LoadAmbientOverlayAndMapData Overworld_LoadAndBuildScreen
+sub_82B1F4 Overworld_ReloadSubscreenOverlayAndAdvance
+Overworld_MirrorWarp Module09_MirrorWarp
+Overworld_MirrorWarp MirrorWarp_Main
+Overworld_InitMirrorWarp MirrorWarp_Initialize
+Overworld_FinishMirrorWarp MirrorWarp_FinalizeAndLoadDestination
+MirrorWarp_LoadNext_5_Inner MirrorWarp_HandleCastlePyramidSubscreen
+MirrorWarp_LoadNext_7 Overworld_DrawScreenAtCurrentMirrorPosition
+MirrorWarp_LoadNext_8 MirrorWarp_LoadSpritesAndColors
+Overworld_Func2E_Whirlpool Module09_2E_Whirlpool
+Overworld_Whirlpool_Case1 Module09_2E_01_MoreBlue
+Overworld_Whirlpool_Case3 Module09_2E_03_FindDestination
+Overworld_Whirlpool_Case5 Module09_2E_05_LoadDestinationMap
+Overworld_Whirlpool_Case7 Module09_2E_07_LoadAuxGraphics
+Overworld_Whirlpool_Case8 Module09_2E_08_TriggerTilemapUpdate
+Overworld_Whirlpool_Case9 Module09_2E_09_LoadPalettes
+Overworld_Func2A Module09_2A_RecoverFromDrowning
+Overworld_Func2A_State0 Module09_2A_00_ScrollToLand
+Dungeon_SpiralStaircase7_Inner3 Dungeon_AdjustForRoomLayout
+Dung_StartInterRoomTrans_RightPlus HandleEdgeTransitionMovementEast_RightBy8
+Dung_StartInterRoomTrans_LeftPlus HandleEdgeTransitionMovementWest_LeftBy8
+Dung_StartInterRoomTrans_DownPlus HandleEdgeTransitionMovementSouth_DownBy16
+Dung_StartInterRoomTrans_Down HandleEdgeTransitionMovementSouth
+Dung_StartInterRoomTrans_Up HandleEdgeTransitionMovementNorth
+Player_CrossQuadrantBoundary_Right AdjustQuadrantAndCamera_right
+Player_UpdateQuadrantsVisited SetAndSaveVisitedQuadrantFlags
+Player_CrossQuadrantBoundary_Left AdjustQuadrantAndCamera_left
+Player_CrossQuadrantBoundary_Down AdjustQuadrantAndCamera_down
+Player_CrossQuadrantBoundary_Up AdjustQuadrantAndCamera_up
+Dungeon_SaveRoomQuadrantData Dungeon_FlagRoomData_Quadrants
+RoomScrollVars_Add0x100 AdjustCameraBoundaries_DownOrRight1Quadrant
+RoomScrollVars_Add0x200 AdjustCameraBoundaries_DownOrRight1Supertile
+RoomScrollVars_Sub0x100 AdjustCameraBoundaries_UpOrLeft1Quadrant
+RoomScrollVars_Sub0x200 AdjustCameraBoundaries_UpOrLeft1Supertile
+Dung_UpdateCameraScrollBounds HandleEdgeTransition_AdjustCameraBoundaries
+UpdateCompositeOfLayoutAndQuadrant Dungeon_AdjustQuadrant
+Dungeon_HandleScreenScrolling Dungeon_HandleCamera
+Overworld_Func1 Overworld_OperateCameraScroll
+Overworld_Func2 OverworldCameraBoundaryCheck
+Dung_CopyInLeftRightScrollTarget DungeonTransition_AdjustCamera_X
+Dung_CopyInUpDownScrollTarget DungeonTransition_AdjustCamera_Y
+Dungeon_InterRoomTrans_State8 DungeonTransition_ScrollRoom
+StraightStairs_10 Module07_11_0A_ScrollCamera
+return_loc_82BFFA OverworldScrollTransition_dirty_exit
+Overworld_Func6B OverworldScrollTransition
+Overworld_SetupSomeBounds Overworld_SetCameraBoundaries
+Dungeon_IntraRoomTrans_State4 DungeonTransition_FindSubtileLanding
+Dungeon_Staircase_Func2 SubtileTransitionCalculateLanding
+Dungeon_Staircase_Func5 DungeonTransition_MoveLinkOutDoor
+Dungeon_Staircase_Func3 CalculateTransitionLanding
+Overworld_Func8 Overworld_FinalizeEntryOntoScreen
+Overworld_ResetMosaic ConditionalMosaicControl
+Intro_InitBgSettings Intro_InitializeBackgroundSettings
+Attract_LoadDungeonRoom Dungeon_LoadAndDrawEntranceRoom
+Attract_LoadDungeonGfxAndTiles Dungeon_SaveAndLoadLoadAllPalettes
+Dungeon_LoadAndUploadRoom Dungeon_LoadAndDrawRoom
+Intro_LoadPalettes Overworld_LoadAllPalettes
+Overworld_LoadAreaPalettes OverworldLoadScreensPaletteSet
+Palette_ZeroPalettesAndCopyFirst SpecialOverworld_CopyPalettesToCache
+Overworld_CgramAuxToMain Overworld_CopyPalettesToCache
+PrayingScene_ResetHDMA CleanUpAndPrepDesertPrayerHDMA
+Dungeon_LoadStartingPoint Dungeon_LoadSpawnEntrance
+Overworld_LoadExitData LoadOverworldFromDungeon
+Overworld_LoadExitData_alternate Overworld_LoadNewScreenProperties
+Overworld_SimpleExit LoadCachedEntranceProperties
+Overworld_SaveSpecialAreaExitData LoadSpecialOverworld
+Overworld_LoadSpecialAreaExitData LoadOverworldFromSpecialOverworld
+BirdTravel_LoadTargetAreaData FluteMenu_LoadTransport
+BirdTravel_LoadTargetAreaPalettes FluteMenu_LoadSelectedScreenPalettes
+Whirlpool_LookUpAndLoadTargetArea FindPartnerWhirlpoolExit
+PreOverworld_LoadLevelData Module08_02_LoadAndAdvance
+Overworld_LoadMapData Overworld_DrawQuadrantsAndOverlays
+Overworld_LoadMapData_justOverlays Overworld_HandleOverlaysAndBombDoors
+Overworld_TransVertical TriggerAndFinishMapLoadStripe_Y
+Overworld_TransHorizontal TriggerAndFinishMapLoadStripe_X
+Overworld_LoadTransMapData SomeTileMapChange
+Overworld_StartTransMapUpdate CreateInitialNewScreenMapToScroll
+UNUSED_sub_82F04B UNREACHABLE_02EDAF
+Overworld_LargeTransUp CreateInitialOWScreenView_Big_North
+Overworld_LargeTransDown CreateInitialOWScreenView_Big_South
+Overworld_LargeTransLeft CreateInitialOWScreenView_Big_West
+Overworld_LargeTransRight CreateInitialOWScreenView_Big_East
+Overworld_SmallTransUp CreateInitialOWScreenView_Small_North
+Overworld_SmallTransDown CreateInitialOWScreenView_Small_South
+Overworld_SmallTransLeft CreateInitialOWScreenView_Small_West
+Overworld_SmallTransRight CreateInitialOWScreenView_Small_East
+ScrollType2 OverworldTransitionScrollAndLoadMap
+ScrollType2_Down BuildFullStripeDuringTransition_North
+ScrollType2_Up BuildFullStripeDuringTransition_South
+ScrollType2_Left BuildFullStripeDuringTransition_West
+ScrollType2_Right BuildFullStripeDuringTransition_East
+Overworld_ScrollMap OverworldHandleMapScroll
+Overworld_TransError Overworld_ResetSubmodule
+Overworld_ScrollRight MapScroll_East
+Overworld_ScrollLeft MapScroll_West
+Overworld_ScrollUp MapScroll_South
+Overworld_ScrollUpAndSide MapScroll_SouthAndClear
+Overworld_ScrollDown MapScroll_North
+Overworld_ScrollDownAndSide MapScroll_NorthAndClear
+Overworld_DoScrollDown CheckForNewlyLoadedMapAreas_North
+Overworld_DoScrollUp CheckForNewlyLoadedMapAreas_South
+Overworld_DoScrollLeft CheckForNewlyLoadedMapAreas_West
+Overworld_DoScrollRight CheckForNewlyLoadedMapAreas_East
+Overworld_DrawHorizontalStrip BufferAndBuildMap16Stripes_X
+Overworld_DrawVerticalStrip BufferAndBuildMap16Stripes_Y
+Overworld_LoadMap32 Overworld_DecompressAndDrawAllQuadrants
+Overworld_LoadQuadrant16x16 Overworld_DecompressAndDrawOneQuadrant
+InterlaceMap32_highBytes BlockMoveMap32Chunks_High
+InterlaceMap32_lowBytes BlockMoveMap32Chunks_Low
+Map32ToMap16 Overworld_ParseMap32Definition
+LoadSubOverlayMap32 OverworldLoad_LoadSubOverlayMap32
+LoadSubscreenOverlay LoadOverworldOverlay
+Map16ToMap8_subscreenOverlay BuildBGOverlayFromMap16
+Map16ToMap8_normalArea BuildOverworldMapFromMap16
+Map16ChunkToMap8 OverworldCopyMap16ToBuffer
+Overworld_RestoreFailedWarpMap16 MirrorBonk_RecoverChangedTiles
+LoadEnemyDamageData DecompressEnemyDamageSubclasses
+Overworld_Decomp Decompress_bank02
+Sprite_HelmasaurFireballTrampoline Sprite_70_KingHelmasaurFireball_bounce
+Sprite_WallCannon Sprite_66_WallCannonVerticalLeft
+SpritePrep_ArcheryGameGuy SpritePrep_ArrowGame
+Sprite_ArcheryGameGuy Sprite_65_ArcheryGame
+ArcheryGameGuy_Main ArcheryGame_Host
+ArcheryGameGuy_RunGame ArcheryGame_Host_ProctorGame
+Sprite_GoodArcheryTarget Sprite_ArcheryGame_Octo
+GoodArcheryTarget_DrawPrize ArcheryGame_DrawPrize
+Sprite_DebirandoPit Sprite_63_DebirandoPit
+Sprite_Debirando Sprite_64_Debirando
+Debirando_UnderSand Debirando_Underground
+Debirando_ShootFireball Debirando_Shoot
+Sprite_MasterSword Sprite_62_MasterSword
+Sprite_MasterLightFountain Sprite_MasterSword_LightFountain
+Sprite_MasterLightWell Sprite_MasterSword_LightWell
+MasterSword_DrawLightBall SpriteDraw_LightFountain
+Sprite_MasterLightBeam Sprite_MasterSword_LightBeam
+MasterLightBeam_SpawnAnotherBeam MasterSword_SpawnReplacementLightBeam
+MasterSword_SpawnLightBeams MasterSword_SpawnLightBeam
+MasterSword_SpawnPendant MasterSword_SpawnPendantProp
+Sprite_MasterSwordPendant Sprite_MasterSword_Prop
+MasterSwordPendant_DriftingAway MasterSword_Prop_Floating
+MasterSwordPendant_Flashing MasterSword_Prop_Flashing
+MasterSwordPendant_FlyAway MasterSword_Prop_FlyAwayNow
+Sprite_SpikeRoller Sprite_5D_Roller_VerticalDownFirst
+Sprite_Beamos Sprite_61_Beamos
+Beamos_FireBeam Beamos_FireLaser
+Beamos_DrawEyeball SpriteDraw_Beamos_Eyeball
+Sprite_BeamosLaser Sprite_Beamos_Laser
+BeamosLaser_PrepOamCoord Sprite_PrepOamCoord_wrapper
+Sprite_BeamosLaserHit Sprite_Beamos_LaserHit
+Sprite_Spark Sprite_5B_Spark_Clockwise
+Sprite_LostWoodsBird Sprite_59_LostWoodsBird
+sub_85944C LostWoodsBird_Ascend
+Sprite_LostWoodsSquirrel Sprite_5A_LostWoodsSquirrel
+Sprite_Crab Sprite_58_Crab
+Sprite_DesertBarrier Sprite_57_DesertStatue
+Sprite_ZoraAndFireball Sprite_55_Zora
+Sprite_ZoraFireball Sprite_Fireball
+Sprite_Zora Sprite_Zora_Main
+Zora_ChooseSurfacingLocation Zora_Submerged
+Zora_Surfacing Zora_Surface
+Zora_Submerging Zora_Submerge
+Sprite_ZoraKing Sprite_52_KingZora
+ZoraKing_WaitingForPlayer KingZora_Idle
+ZoraKing_RumblingGround KingZora_TheRumbling
+ZoraKing_Surfacing KingZora_Surface
+ZoraKing_Dialogue KingZora_Talking
+ZoraKing_Submerge KingZora_Submerge
+Sprite_SpawnSplashRingLong Sprite_Arrghus_SpawnSplash
+Sprite_SpawnSplashRing Sprite_SpawnBigSplash
+Sprite_WalkingZora Sprite_56_WalkingZora
+WalkingZora_Waiting WalkingZora_Wait
+WalkingZora_Surfacing WalkingZora_Surface
+WalkingZora_Ambulating WalkingZora_Walking
+WalkingZora_Depressed WalkingZora_Stunned
+WalkingZora_DetermineShadowStatus WalkingZora_AdjustShadow
+WalkingZora_DrawWaterRipple WalkingZora_DrawWaterRipples
+Sprite_AutoIncDrawWaterRipple SpriteDraw_WaterRipple_WithOamAdjust
+Sprite_DrawWaterRipple SpriteDraw_WaterRipple
+Sprite_ArmosKnight Sprite_53_ArmosKnight
+Lanmola_FinishInitialization SpritePrep_Lanmolas
+Sprite_Lanmola Sprite_54_Lanmolas
+Sprite_Lanmola_00 Sprite_Lanmolas_Hiding
+Sprite_Lanmola_01 Sprite_Lanmolas_BurrowingUp
+Sprite_Lanmola_02 Sprite_Lanmolas_LeapFromSand
+Sprite_Lanmola_03 Sprite_Lanmolas_WiggleInAir
+Sprite_Lanmola_04 Sprite_Lanmolas_BurrowDown
+Sprite_SpawnFallingItem Ancilla_SpawnFallingPrize
+Sprite_Lanmola_05 Sprite_Lanmolas_Exploding
+Sprite_Rat Sprite_6D_Rat
+Sprite_Rope Sprite_6E_Rope
+Sprite_Keese Sprite_6F_Keese
+Sprite_CannonBall Sprite_Cannonball
+Sprite_CheckDamageBoth Sprite_CheckDamageToAndFromLink
+Sprite_CannonTrooper_UNUSED Sprite_6B_Cannonball
+sub_85AC34 CannonGuard_FaceLink
+sub_85AC52 CannonGuard_Charge
+sub_85ACF2 CannonGuard_Fire
+sub_85AD12 CannonGuard_Recoil
+sub_85AD28 CannonGuard_Recover
+CannonTrooper_Draw_UNUSED SpriteDraw_CannonGuard
+Sprite_WarpVortex Sprite_6C_MirrorPortal
+Sprite_ChainBallTrooper Sprite_6A_BallNChain
+FlailTrooper_ApproachPlayer BallNChain_Approach
+FlailTrooper_UpdateGfx BallNChain_Animate
+FlailTrooper_ShortHalting BallNChain_Steady
+FlailTrooper_Attack BallNChain_SpinFlail
+FlailTrooper_WindingDown BallNChain_SlowFlail
+ChainBallTrooper_DrawHead SpriteDraw_BNCHead
+ChainBallTrooper_DrawHeadEx SpriteDraw_GuardHead
+FlailTrooper_DrawBody SpriteDraw_BNCBody
+FlailTrooper_DrawBodyEx SpriteDraw_GuardBody
+ChainBallTrooper_DrawWeapon SpriteDraw_BNCFlail
+ChainBallTrooper_Nop NOP4
+SpriteActive2_MainLong SpriteModule_Active
+Sprite_MetalBall Sprite_50_Cannonball
+MetalBall_DrawLargerVariety SpriteDraw_BigCannonball
+Sprite_Armos Sprite_51_ArmosStatue
+Sprite_Bot Sprite_4E_Popo
+Sprite_GerudoMan Sprite_4C_Geldman
+GerudoMan_ReturnToOrigin Geldman_Hiding
+GerudoMan_AwaitPlayer Geldman_WaitForLink
+GerudoMan_Emerge Geldman_Ambush
+GerudoMan_PursuePlayer Geldman_Chase
+GerudoMan_Submerge Geldman_Retreat
+Sprite_Toppo Sprite_4D_Toppo
+Toppo_PickNextGrassPlot Toppo_Hiding
+Toppo_ChillBeforeJump Toppo_RustleGrass
+Toppo_WaitThenJump Toppo_PokingOut
+Toppo_RiseAndFall Toppo_Leaping
+Toppo_ChillAfterJump Toppo_Retreat
+Toppo_FlusteredTrampoline Toppo_Flustered_bounce
+Toppo_CheckLandingSiteForGrass Toppo_VerifyTile
+Sprite_Recruit Sprite_4B_GreenKnifeGuard
+Recruit_Moving GreenKnifeGuard_Moving
+sub_85BD52 ZoraAndGuardAdvanceAnimation
+Sprite_BombTrooper Sprite_4A_BombGuard
+EnemyBomb_CheckDamageToSprite SpriteBomb_CheckDamageToSprite
+EnemyBomb_ExplosionImminent SpriteBomb_ExplosionIncoming
+BombTrooper_Main BombGuard
+BombTrooper_SpawnAndThrowBomb BombGuard_CreateBomb
+BombTrooper_DrawArm SpriteDraw_BombGuard_Arm
+EnemyBomb_DrawExplosion SpriteDraw_SpriteBombExplosion
+Sprite_Soldier Sprite_41_BlueGuard
+Soldier_Probe Probe
+Soldier_Main Guard_Main
+Soldier_State0 Guard_Idle
+Soldier_Func13 Guard_SetGlanceTo12
+Soldier_Func10 Guard_ShootProbeAndStuff
+Soldier_State1 Guard_OnPatrol
+Soldier_Func7 Guard_TickAndUpdateBody
+Soldier_State2 Guard_Surveying
+Soldier_State3 Guard_InPursuit
+Soldier_Func11 Guard_SetTimerAndAssertTileHitBox
+Soldier_State4 Guard_FallingToDeath
+Sprite_ZeroVelocity Sprite_ZeroVelocity_XY
+Soldier_Func6 Guard_TickTwiceAndUpdateBody
+Probe_SetDirectionTowardsPlayer Guard_ApplySpeedInDirection
+Sprite_SpawnProbeStaggered Sprite_Guard_SendOutProbe
+Soldier_Draw Guard_HandleAllAnimation
+Soldier_Draw1 Guard_AnimateHead
+Soldier_Draw2 Guard_AnimateBody
+Soldier_Draw3 Guard_AnimateWeapon
+Sprite_PsychoSpearSoldier Sprite_45_UsainBolt
+PsychoSpearSoldier_PlayChaseMusic BoltGuard_TriggerChaseTheme
+Sprite_PsychoTrooper Sprite_44_BluesainBolt
+SoldierThrowing_DrawWeapon_1 SpriteDraw_GuardSpear_Fresh
+SoldierThrowing_DrawWeaponEx SpriteDraw_GuardSpear_PreserveOamOffset
+SoldierThrowing_DrawWeapon_3 SpriteDraw_GuardSpear_Bolt
+SoldierThrowing_DrawWeapon SpriteDraw_GuardSpear
+Sprite_MoveIfNotTouchingWall Sprite_Guard_MoveIfNoTileCollision
+Sprite_JavelinTrooper Sprite_48_RedJavelinGuard
+Sprite_ArcherSoldier Sprite_46_BlueArcher
+JavelinTrooper_Resting Archer_Hiding
+JavelinTrooper_WalkingAround Archer_Walking
+JavelinTrooper_LookingAround Archer_Scanning
+JavelinTrooper_NoticedPlayer Archer_NoticeSenpai
+JavelinTrooper_Agitated Archer_Agitated
+JavelinTrooper_Attack Archer_Attack
+JavelinTrooper_SpawnProjectile Guard_LaunchProjectile
+Sprite_BushJavelinSoldier Sprite_49_RedBushGuard
+Sprite_BushArcherSoldier Sprite_47_GreenBushGuard
+Sprite_BushSoldierCommon Sprite_BushGuard_Main
+Sprite_BushSoldierCommon_00 Sprite_BushGuard_Hiding
+Sprite_BushSoldierCommon_01 Sprite_BushGuard_Emerging
+BushSoldier_SpawnWeapon BushGuard_SpawnFoliage
+Sprite_BushSoldierCommon_02 Sprite_BushGuard_Shoot
+Sprite_BushSoldierCommon_03 Sprite_BushGuard_Retreating
+ArcherSoldier_DrawWeapon SpriteDraw_Archer_Weapon
+Sprite_TutorialEntitiesLong Sprite_TutorialGuardOrBarrier
+Sprite_EvilBarrierTrampoline Sprite_BarrierBounce
+Sprite_TutorialEntities Sprite_GuardOrBarrierTest
+Sprite_PullSwitch Sprite_04_PullSwitch
+BadPullSwitch_Main PullSwitch_FacingUp
+BadPullSwitch_Inner PullSwitch_HandleUpPulling
+GoodPullSwitch_Main PullSwitch_FacingDown
+GoodPullSwitch_Inner PullSwitch_HandleDownPulling
+SpritePrep_UncleAndSageLong SpritePrep_UncleAndPriest
+SpritePrep_UncleAndSage UncleOrPriestPrepCheck
+Sage_SpawnMantle Priest_SpawnMantle
+Sprite_UncleAndSageLong Sprite_73_UncleAndPriest
+Sprite_SageMantle Sprite_SanctuaryMantle
+Sprite_SageMantle_Case0 Sprite_SanctuaryMantle_AttemptCutscene
+Sprite_SageMantle_Case1 Sprite_SanctuaryMantle_InitializeSlide
+Sprite_SageMantle_Case2 Sprite_SanctuaryMantle_SlideToTheRight
+Sprite_MakeBodyTrackHeadDirection Sprite_TrackBodyToHead
+Sprite_Sage Sprite_Priest
+Sage_MortallyWounded Priest_Dying
+Sage_DyingWords Priest_LyingOnGround
+Sage_DeathFlash Priest_FinalWords
+Sage_Terminate Priest_Die
+Sage_State1 Priest_RunRescueCutscene
+Sage_AtSanctuary Priest_Chillin
+Uncle_AtHome Uncle_AtHouse
+Uncle_TelepathicZeldaPlea Uncle_TriggerTelepathy
+Uncle_WakeUpPlayer Uncle_AwakenLink
+Uncle_TellPlayerToStay Uncle_DeclareCurfew
+Uncle_LeavingHouse Uncle_Embark
+Uncle_AttachZeldaTelepathTagalong Uncle_ApplyTelepathyFollower
+Uncle_InSecretPassage Uncle_InPassage
+Uncle_RemoveZeldaTelepathTagalong Uncle_LyingInDefeat
+Uncle_GiveSwordAndShield Uncle_GrantEquipment
+Sprite_DrawMultiple_Inner2 Sprite_DrawMultiple_prep_oam_deferred
+Sprite_DrawMultiple_Inner1 Sprite_DrawMultiple_prep_oam
+Sprite_QuarrelBrosLong Sprite_32_ArguingBros
+Sprite_Oprhan1 Sprite_UNREACHABLE_05E052
+Orphan1_State1 UNREACHABLE_05E06B
+Orphan1_State2 UNREACHABLE_05E0B6
+Sprite_ShowSolicitedMessageIfPlayerFacing Sprite_ShowSolicitedMessage
+Sprite_ShowMessageFromPlayerContact Sprite_ShowMessageOnContact
+Sprite_PullForRupeesLong Sprite_33_RupeePull
+Sprite_GargoyleGrateLong Sprite_14_ThievesTownGrate
+Sprite_YoungSnitchLadyLong Sprite_34_YoungSnitch
+Sprite_InnKeeperLong Sprite_35_Innkeeper
+Sprite_WitchLong Sprite_36_Witch
+Witch_GrantCaneOfByrna Witch_GrantByrna
+Witch_Main Witch_DiscussThings
+Witch_PlayerHasNotMushroom Witch_DiscussMushroom
+Witch_PlayerHasMushroom Witch_YouHaveShroom
+Witch_PlayerHandsMushroomOver Witch_AcceptShroom
+Sprite_ArrowTriggerLong Sprite_38_EyeStatue
+ArrowTrigger_Unused UNREACHABLE_05E656
+Sprite2_TrendHorizSpeedToZero Sprite_Decelerate_X
+Sprite2_TrendVertSpeedToZero Sprite_Decelerate_Y
+SpritePrep_SnitchesLong SpritePrep_Snitch
+Sprite_OldSnitchLadyLong Sprite_3D_OldSnitch
+OldSnitchLady_Case0 Snitch_Meander
+OldSnitchLady_Case1 Snitch_FreakOut
+OldSnitchLady_Case2 Snitch_OpenDoor
+OldSnitchLady_Case3 Snitch_SlamDoor
+SpritePrep_RunningManLong SpritePrep_RunningBoy
+Sprite_RunningManLong Sprite_74_RunningBoy
+RunningMan_Chillin RunningBoy_Idle
+RunningMan_AnimateAndRun RunningMan_Running
+RunningMan_RunLeft RunningBoy_RunLeft
+RunningMan_ResumeChillin RunningMan_Relax
+RunningMan_WindingRunRight RunningBoy_RunRight
+RunningMan_GotCaught RunningBoy_Caught
+RunningMan_AnimateAndMakeDust RunningMan_AnimateAndDust
+RunningMan_RunFullSpeed RunningMan_RunAway
+Sprite_BottleVendorLong Sprite_75_BottleMerchant
+BottleVendor_Base BottleVendor_Idle
+BottleVendor_SellingBottle BottleVendor_OfferSale
+BottleVendor_GiveBottle BottleVendor_GrantBottle
+BottleVendor_BuyingFromPlayer BottleVendor_BuyingItem
+BottleVendor_DispenseRewardToPlayer BottleVendor_PayOut
+Zelda_TransitionFromTagalong Priest_SpawnRescuedPrincess
+Sprite_Zelda Sprite_76_Zelda
+Zelda_InPrison Zelda_InCell
+Zelda_AwaitingRescue Zelda_WaitingInCell
+Zelda_ApproachingPlayer Zelda_ApproachHero
+Zelda_TheWizardIsBadMkay Zelda_DebaseAgahnim
+Zelda_WaitUntilPlayerPaysAttention Zelda_VerifyAttentionSpan
+Zelda_TransitionToTagalong Zelda_BecomeFollower
+Zelda_WalkTowardsPriest Zelda_EnterSanctuary
+Zelda_RespondToPriest Zelda_TalkHeadOff
+Zelda_BeCarefulOutThere Zelda_WellWishes
+Sprite_MushroomLong Sprite_E7_Mushroom
+nullsub_10 SpritePrep_FakeMasterSword
+Sprite_FakeSwordLong Sprite_E8_FakeMasterSword
+SpritePrep_HeartContainerLong SpritePrep_HeartContainer
+Sprite_HeartContainerLong Sprite_EA_HeartContainer
+Sprite_HeartPieceLong Sprite_EB_HeartPiece
+Sprite_ElderLong Sprite_16_Elder
+Sahasrahla_Dialogue Sasha_Idle
+Sahasrahla_MarkMap Sasha_GiveQuest
+Sahasrahla_GrantBoots Sasha_GiveBoots
+Sahasrahla_ShamelesslyPromoteIceRod Sasha_PromoteIceRod
+Sprite_MedallionTabletLong Sprite_F2_MedallionTablet
+MedallionTablet_SpawnDustCloud Sprite_SpawnDustCloud
+MedallionTablet_WaitForMudoraReader MedallionTablet_WaitingToBeRead
+MedallionTablet_Wait BombosTablet
+MedallionTablet_WaitForEther EtherTablet
+MedallionTablet_ExtendedDelay MedallionTablet_WasteTime
+MedallionTablet_Crumbling MedallionTablet_Crumble
+MedallionTablet_FinalAnimationState MedallionTablet_AmCrumbled
+Sprite_ElderWifeLong Sprite_78_MrsSahasrahla
+ElderWife_Initial MrsSahasrahla_Idle
+ElderWife_TellLegend MrsSahasrahla_BabbleOn
+ElderWife_LoopUntilPlayerNotDumb MrsSahasrahla_QuestionSanity
+ElderWife_GoAwayFindTheOldMan MrsSahasrahla_FindMyHubby
+SpritePrep_PotionShopLong SpritePrep_MagicShopAssistant
+PotionShop_SpawnMagicPowder MagicShopAssistant_SpawnPowder
+PotionShop_SpawnGreenPotion MagicShopAssistant_SpawnGreenCauldron
+PotionShop_SpawnBluePotion MagicShopAssistant_SpawnBlueCauldron
+PotionShop_SpawnRedPotion MagicShopAssistant_SpawnRedCauldron
+Sprite_PotionShopLong Sprite_E9_MagicShopAssistant
+Sprite_MagicPowderItem Sprite_BagOfPowder
+Sprite_GreenPotionItem Sprite_GreenCauldron
+Sprite_BluePotionItem Sprite_BlueCauldron
+Sprite_RedPotionItem Sprite_RedCauldron
+PotionItem_PlaySound PotionCauldron_GoBeep
+WitchAssistant_CheckIfHaveAnyBottles PotionCauldron_CheckBottles
+Sprite_WitchAssistant Sprite_MagicShopAssistant_Main
+Sprite_DirectionToFacePlayer Sprite_DirectionToFaceLink
+Sprite_IsToRightOfPlayer Sprite_IsRightOfLink
+Sprite_IsBelowPlayer Sprite_IsBelowLink
+Sprite_Move Sprite_MoveXY
+Sprite_ShowMessageIfPlayerTouching Sprite_TutorialGuard_ShowMessageOnContact
+Overworld_ReadSomeTileAttr Overworld_ReadTileAttribute
+Sprite_MadBatterLong Sprite_3A_MagicBat
+MadBatter_WaitForSummoning MagicBat_Dormant
+MadBatter_RisingUp MagicBat_Ascend
+MadBatter_PseudoAttackPlayer MagicBat_Attack
+MadBatter_DoublePlayerMagicPower MagicBat_EnhanceMagic
+MadBatter_LaterBitches MagicBat_Retreat
+Sprite_DashItemLong Sprite_3B_BonkItem
+Sprite_DashKey Sprite_BonkKey
+DashKey_WaitForDashAttack BonkKey_Undisturbed
+DashKey_GiveToPlayer BonkKey_GrantKey
+Sprite_DashBookOfMudora Sprite_BookOfMudora
+DashBookOfMudora_WaitForDashAttack BookOfMudora_WaitForBonk
+DashItem_BeginFalling BonkItem_KnockedDown
+DashItem_WaitTillTouchingGround BonkItem_Land
+DashBookOfMudora_GiveToPlayer BookOfMudora_GrantLiterature
+Sprite_DashTreetop Sprite_LumberjackTree
+DashTreeTop_WaitForDashAttack LumberjackTree_WaitForBonk
+DashTreeTop_SpawnLeaves LumberjackTree_ExplodeViolently
+DashTreeTop_DancingLeaves LumberjackTree_DispersionOfLeaves
+DashTreeTop_SpawnLeafCluster LumberjackTree_SpawnLeaves
+Sprite_TroughBoyLong Sprite_3C_KidInKak
+BottleVendor_DetectFish BottleMerchant_DetectFish
+BottleVendor_SpawnFishRewards BottleMerchant_BuyFish
+ApplyRumbleToSprites Prepare_ApplyRumbleToSprites
+Sprite_SpawnThrowableTerrain_Internal Sprite_SpawnThrowableTerrain_silently
+Utility_CheckIfHitBoxesOverlap CheckIfHitBoxesOverlap
+Sprite_ExecuteSingle2 Sprite_TimersAndOam
+Sprite_Get_16_bit_Coords Sprite_Get16BitCoords
+SpriteFall_Main SpriteModule_Fall1
+SpriteBurn_Main SpriteModule_Burn_bounce
+SpriteExplode_Main SpriteModule_Explode_bounce
+SpriteDrown_Main SpriteModule_Drown
+SpritePrep_Main SpriteModule_Initialize
+SpritePrep_MovableMantle SpritePrep_Mantle
+sub_86884A SpritePrep_MoveRight_8px
+SpritePrep_MedallionTableTrampoline SpritePrep_MedallionTablet_bounce
+SpritePrep_GoodSwitch SpritePrep_Switch
+SpritePrep_OldSnitchLady SpritePrep_Snitch_bounce_1
+SpritePrep_DoNothing SpritePrep_DoNothingA
+SpritePrep_Hokbok SpritePrep_Pokey
+SpritePrep_Vitreolus SpritePrep_MiniVitreous
+SpritePrep_EvilBarrier SpritePrep_AgahnimsBarrier
+SpritePrep_GreatCatfish SpritePrep_Catfish
+SpritePrep_ChattyAgahnim SpritePrep_CutsceneAgahnim
+SpritePrep_Pikit SpritePrep_DoNothingC
+SpritePrep_Moldorm SpritePrep_MiniMoldorm_bounce
+SpritePrep_BombShopEntity SpritePrep_BombShoppe
+SpritePrep_BullyAndBallGuy SpritePrep_BullyAndVictim
+SpritePrep_ThiefChest SpritePrep_PurpleChest
+SpritePrep_Dwarf SpritePrep_Smithy
+SpritePrep_Babusu SpritePrep_Babasu
+SpritePrep_LaserEyeTrampoline SpritePrep_LaserEye_bounce
+SpritePrep_Bot SpritePrep_Popo2
+SpritePrep_MovableStatue SpritePrep_Statue
+SpritePrep_PushSwitch SpritePrep_WaterLever
+SpritePrep_Debirando SpritePrep_DebirandoPit
+SpritePrep_Recruit SpritePrep_WeakGuard
+SpritePrep_ArcheryGameGuyTrampoline SpritePrep_ArrowGame_bounce
+SpritePrep_IgnoresProjectiles SpritePrep_IgnoreProjectiles
+SpritePrep_FluteBoyAnimals SpritePrep_HauntedGroveAnimal
+SpritePrep_FluteBoyOstrich SpritePrep_HauntedGroveOstritch
+SpritePrep_DiggingGameGuyTrampoline SpritePrep_DiggingGameGuy_bounce
+SpritePrep_GargoyleGrate SpritePrep_ThievesTownGrate
+SpritePrep_PullForRupees SpritePrep_RupeePull
+SpritePrep_ShopKeeper SpritePrep_Shopkeeper
+SpritePrep_ShopKeeper_6_9_12 SpritePrep_NiceThief_WithGift
+SpritePrep_ShopKeeper_10 SpritePrep_NiceThief_Desert
+SpritePrep_ShopKeeper_11 SpritePrep_NiceThief_Ice
+SpritePrep_StoryTeller_1 SpritePrep_Storyteller
+SpritePrep_HumanMulti_1 SpritePrep_Adults
+SpritePrep_Elder SpritePrep_Sage
+SpritePrep_DashItem SpritePrep_BonkItem
+SrpritePrep_Kiki SpritePrep_Kiki
+SpritePrep_MiddleAgedMan SpritePrep_Locksmith
+SpritePrep_BugNetKid SpritePrep_SickKid
+SpritePrep_GanonHelpers SpritePrep_Tektite
+SpritePrep_ChainChompTrampoline SpritePrep_Chainchomp_bounce
+SpritePrep_BigFaerie SpritePrep_BigFairy
+SpritePrep_ElderWife SpritePrep_MrsSahasrahla
+SpritePrep_MadBatter SpritePrep_MagicBat
+SpritePrep_Leever SpritePrep_FairyPond
+SpritePrep_HoboEntities SpritePrep_Hobo
+SpritePrep_RollerRightLeft SpritePrep_Roller_HorizontalRightFirst
+SpritePrep_RollerDownUp SpritePrep_Roller_VerticalDownFirst
+SpritePrep_Kodondo SpritePrep_Kodongo
+SpritePrep_Bubble SpritePrep_Antifairy
+SpritePrep_IceBallGenerator SpritePrep_FallingIce
+SpritePrep_ZoraKing SpritePrep_KingZora
+SpritePrep_DesertBarrier SpritePrep_DesertStatue
+SpritePrep_Armos SpritePrep_DoNothingD
+SpritePrep_Octorock SpritePrep_Octorok
+SpritePrep_GiantMoldorm SpritePrep_Moldorm_bounce
+SpritePrep_Lanmola SpritePrep_Lanmolas_bounce
+SpritePrep_SpikeTrap SpritePrep_BigSpike
+SpritePrep_ZoraAndFireball SpritePrep_SwimmingZora
+SpritePrep_GerudoMan SpritePrep_Geldman
+sub_868FCF SpritePrep_StandardGuard_indoors
+SpritePrep_Soldier SpritePrep_StandardGuard
+SpritePrep_FluteBoy SpritePrep_FluteKid
+SpritePrep_MoveDownOneTile SpritePrep_MoveDown_8px
+SpritePrep_HylianPlaque SpritePrep_PedestalPlaque
+Sprite_IncrXYLow8 SpritePrep_MoveDown_8px_Right8px
+SpritePrep_HardHatBeetle SpritePrep_HardhatBeetle
+SpritePrep_Helmasaur SpritePrep_MiniHelmasaur
+SpritePrep_Faerie SpritePrep_Fairy
+SpritePrep_TenArrowRefill SpritePrep_Absorbable
+SpritePrep_DashTriggeredSprite SpritePrep_OverworldBonkItem
+SpritePrep_GoodBee SpritePrep_NiceBee
+SpritePrep_DoNothing_2 SpritePrep_DoNothingG
+SpritePrep_EyegoreTrampoline SpritePrep_Eyegore_bounce
+SpritePrep_GuruguruBar SpritePrep_FireBar
+SpritePrep_TrinexxComponents SpritePrep_Trinexx
+sub_8691CC SpritePrep_FreeUpBossSegmentSlots
+SpritePrep_SpikeBlock SpritePrep_Spike
+SpritePrep_Stal SpritePrep_RockStal
+SpritePrep_Terrorpin SpritePrep_Blob
+SpritePrep_Arghus SpritePrep_Arrghus
+SpritePrep_Arrgi SpritePrep_Arrghi
+SpritePrep_BubbleGroupTrampoline SpritePrep_AntifairyCircle_bounce
+SpritePrep_CrystalMaiden SpritePrep_DoNothingH
+SpritePrep_LoadBigKeyGfx SpritePrep_BigKey_load_graphics
+SpritePrep_Key SpritePrep_SmallKey
+Sprite_GiantMoldormTrampoline Sprite_09_Moldorm_bounce
+Sprite_RavenTrampoline Sprite_00_Raven_bounce
+Sprite_VultureTrampoline Sprite_01_Vulture_bounce
+Sprite_DeadRock Sprite_27_Deadrock
+DeadRock_PickDirection Deadrock_Halted
+DeadRock_Walk Deadrock_Walk
+DeadRock_Petrified Deadrock_Stunned
+Sprite_Sluggula Sprite_20_Sluggula
+Sluggula_LayBomb Sluggula_DropBomb
+Sprite_Poe Sprite_19_Poe
+Poe_SelectVerticalDirection Poe_Halted
+Poe_Roaming Poe_SpookAround
+Sprite_Moldorm Sprite_18_MiniMoldorm
+Moldorm_ConfigureNextState MiniMoldorm_Readjust
+Moldorm_Meander MiniMoldorm_Meander
+Moldorm_SeekPlayer MiniMoldorm_TargetLink
+Sprite_Moblin Sprite_12_Moblin
+Moblin_SelectDirection Moblin_Halted
+Moblin_SpawnThrownSpear Moblin_MaterializeSpear
+Sprite_SnapDragon Sprite_0E_Snapdragon
+SnapDragon_Resting Snapdragon_Halted
+SnapDragon_Attack Snapdragon_MoveAround
+Sprite_Ropa Sprite_22_Ropa
+Ropa_Stationary Ropa_Halted
+Sprite_Hinox Sprite_11_Hinox
+Hinox_SelectNextDirection Hinox_Halted
+Hinox_FacePlayer Hinox_FaceLink
+Hinox_SetRandomDirection Hinox_PickRandomDirection
+Hinox_SetExplicitDirection Hinox_SetDirection
+Sprite_BlueBari Sprite_23_RedBari
+Sprite_Helmasaur Sprite_13_MiniHelmasaur
+Sprite_HardHatBeetle Sprite_26_HardhatBeetle
+Sprite_Bubble Sprite_15_Antifairy
+Sprite_Chicken Sprite_0B_Cucco
+Chicken_Calm Cucco_Calm
+Chicken_IncrSubtype2_4 Cucco_AnimateFast
+Chicken_FleeingPlayer Cucco_Flee
+Chicken_DistressMarker Cucco_DrawPANIC
+Sprite_DrawDistressMarker Sprite_DrawDistressSweat
+Sprite_CustomTimedDrawDistressMarker Sprite_DrawDistress_custom
+Chicken_Aloft Cucco_Carried
+Chicken_Move_XYZ_AndCheckTileCollision Cucco_DoMovement_XYZ
+Chicken_MoveCheckColl Cucco_DoMovement_XY
+Chicken_SpawnAvengerChicken Cucco_SummonAvenger
+Chicken_Sound BawkBawk
+Sprite_MovableMantle Sprite_EE_CastleMantle_bounce
+Sprite_CoveredRupeeCrab Sprite_17_Hoarder
+Sprite_CoveredRupeeCrab_0 Sprite_Hoarder_Covered
+Sprite_RupeeCrab Sprite_Hoarder_Frantic
+Sprite_CheckIfLiftedPermissive Sprite_CheckIfLifted_permissive
+Sprite_ThrowableScenery Sprite_EC_ThrownItem
+ThrowableScenery_DrawLarge SpriteDraw_ThrownItem_Gigantic
+Sprite_TransmuteToEnemyBomb Sprite_TransmuteToBomb
+Sprite_StoryTeller_1 Sprite_28_DarkWorldHintNPC
+Sprite_StoryTeller_1_Case0 Sprite_DarkWorldHintNPC_Bird
+StoryTeller_Before DarkWorldHintNPC_Idle
+StoryTeller_After DarkWorldHintNPC_RestoreHealth
+StoryTeller_Case0_Inner HintBird_TellStory
+Sprite_StoryTeller_1_Case1 Sprite_HamburgerHelper
+Sprite_StoryTeller_1_Case2 Sprite_DarkWorldHintNPC_Octopus
+Sprite_StoryTeller_Case2_Inner Sprite_HintOctopus_TellStory
+Sprite_StoryTeller_1_Case3 Sprite_Broccoli
+Sprite_StoryTeller_1_Case4 Sprite_Watto
+Sprite_StoryTeller_Case4_Inner Sprite_Watto_TellStory
+StoryTeller_CheckPay DarkWorldHintNPC_HandlePayment
+Sprite_FluteBoy Sprite_2E_FluteKid
+FluteBoy_Humanoid FluteKid_TheKid
+FluteBoy_HumanForm FluteKid_Human
+FluteBoy_Chillin FluteKid_Chillin
+FltueBoy_PrepPhaseOut FluteKid_AboutToDisappear
+FluteBoy_PhaseOut FluteKid_PhaseOut
+FluteBoy_FullyPhasedOut FluteKid_HeDisappeared
+Sprite_FluteAardvark Sprite_FluteKid_Stumpy
+FluteAardvark_InitialStateFromFluteState Stumpy_Initialize
+FluteAardvark_Supplicate Stumpy_Supplicate
+FluteAardvark_ThanksButYouKeepIt Stumpy_ThanksButYouKeepIt
+FluteAardvark_AlreadyArborated Stumpy_SorryButAmTree
+FluteAardvark_ReactToSupplicationResponse Stumpy_WaitForConvo
+FluteAardvark_GrantShovel Stumpy_GiveShovel
+FluteAardvark_WaitForPlayerMusic Stumpy_WaitForMusic
+FluteAardvark_Arborating Stumpy_BecomeTree
+FluteAardvark_FullyArborated Stumpy_AmTree
+FluteBoy_CheckIfPlayerTooClose FluteKid_CheckIfInRange
+Sprite_FluteNote Sprite_FluteKid_Quaver
+FluteBoy_SpawnFluteNote FluteKid_SpawnQuaver
+Sprite_SmithyBros Sprite_1A_Smithy
+ReturningSmithy_Main Smithy_Homecoming
+ReturningSmithy_ApproachTheBench Smithy_Homecoming_Walk
+ReturningSmithy_CopiouslyThankful Smithy_Homecoming_TYVM
+SmithyFrog_Main Smithy_Frog
+Smithy_ConversationStart Smithy_Smithing
+Smithy_NearbyHammerUseListener Smithy_ListenForHammer
+Smithy_ProvideTemperingChoice Smithy_WannaTemper
+Smithy_HandleTemperingChoice Smithy_ForRealsies
+Smithy_HandleTemperingCost Smithy_ItAintFreeKid
+Smithy_TemperingSword Smithy_TemperInProgress
+Smithy_GrantTemperedSword Smithy_GiveTemperedSword
+Smithy_SpawnReturningSmithy Smithy_SpawnFriend
+Smithy_SpawnOtherSmithy Smithy_SpawnDwarfPal
+SmithySpark_Main Smithy_Spark
+SmithyBros_SpawnSmithySpark Smithy_SpawnSpark
+Sprite_EnemyArrow Sprite_1B_Arrow
+Sprite_CrystalSwitch Sprite_1E_CrystalSwitch
+Sprite_BugNetKid Sprite_1F_SickKid
+BugNetKid_Resting SickKid_ISleep
+BugNetKid_PerkUp SickKid_RealShit
+BugNetKid_GrantBugNet SickKid_NothingButNet
+BugNetKid_BackToResting SickKid_OutOfShaqMemes
+Sprite_PushSwitch Sprite_21_WaterSwitch
+PushSwitch_Case0 WaterSwitch_Untoggled
+PushSwitch_Case1 WaterSwitch_ReleaseGate
+Sprite_MiddleAgedMan Sprite_39_Locksmith
+MiddleAgedMan_Chillin LockSmith_Chillin
+MiddleAgedMan_TransitionToTagalong LockSmith_FollowLink
+MiddleAgedMan_OfferChestOpening LockSmith_OfferService
+MiddleAgedMan_ReactToSecretKeepingResponse LockSmith_RespondToAnswer
+Sprite_HoboEntities Sprite_2B_Hobo
+Sprite_Hobo Sprite_Hobo_Bum
+Hobo_Sleeping Hobo_Sleep
+Hobo_WakeUp Hobo_Awoken
+Hobo_GrantBottle Hobo_GiveBottle
+Hobo_SpawnHobo SpritePrep_Hobo_SpawnSmoke
+Sprite_HoboBubble Sprite_Hobo_Bubble
+Sprite_HoboFire Sprite_Hobo_Fire
+Hobo_SpawnCampfire SpritePrep_Hobo_SpawnFire
+Sprite_HoboSmoke Sprite_Hobo_Smoke
+HoboFire_SpawnSmoke Hobo_SpawnSmoke
+Sprite_UncleAndSageTrampoline Sprite_73_UncleAndPriest_bounce
+SpritePrep_UncleAndSageTrampoline SpritePrep_UncleAndPriest_bounce
+SpriteActive2_Trampoline SpriteModule_Active_bounce
+SpritePrep_OldMountainManTrampoline SpritePrep_OldMan_bounce
+Sprite_TutorialEntitiesTrampoline Sprite_TutorialGuardOrBarrier_bounce
+Sprite_PullSwitch Sprite_PullSwitch_bounce
+Sprite_SomariaPlatformTrampoline Sprite_SomariaPlatformAndPipe_bounce
+Sprite_MedallionTabletTrampoline Sprite_F2_MedallionTablet_bounce
+Sprite_QuarrelBrosTrampoline Sprite_32_ArguingBros_bounce
+Sprite_PullForRupeesTrampoline Sprite_33_RupeePull_bounce
+Sprite_GargoyleGrateTrampoline Sprite_14_ThievesTownGrate_bounce
+Sprite_YoungSnitchLadyTrampoline Sprite_34_YoungSnitch_bounce
+SpritePrep_YoungSnitchGirl SpritePrep_Snitch_bounce_2
+Sprite_InnKeeperTrampoline Sprite_35_Innkeeper_bounce
+SpritePrep_InnKeeper SpritePrep_Snitch_bounce_3
+Sprite_WitchTrampoline Sprite_36_Witch_bounce
+Sprite_WaterfallTrampoline Sprite_37_Waterfall_bounce
+Sprite_ArrowTriggerTrampoline Sprite_38_EyeStatue_bounce
+Sprite_MadBatterTrampoline Sprite_3A_MagicBat_bounce
+Sprite_DashItemTrampoline Sprite_3B_BonkItem_bounce
+Sprite_TroughBoyTrempoline Sprite_3C_KidInKak_bounce
+Sprite_OldSnitchLadyTrampoline Sprite_3D_OldSnitch_bounce
+Sprite_RunningManTrampoline Sprite_74_RunningBoy_bounce
+SpritePrep_RunningManTrampoline SpritePrep_RunningBoy_bounce
+Sprite_BottleVendorTrampoline Sprite_75_BottleMerchant_bounce
+Sprite_ZeldaTrampoline Sprite_76_Zelda_bounce
+SpritePrep_ZeldaTrampoline SpritePrep_Zelda_bounce
+Sprite_ElderWifeTrampoline Sprite_78_MrsSahasrahla_bounce
+Sprite_MushroomTrampoline Sprite_E7_Mushroom_bounce
+SpritePrep_MushroomTrampoline SpritePrep_Mushroom_bounce
+Sprite_FakeSwordTrampoline Sprite_E8_FakeMasterSword_bounce
+SpritePrep_FakeSwordTrampolnie SpritePrep_FakeMasterSword_bounce
+Sprite_ElderTrampoline Sprite_16_Elder_bounce
+Sprite_PotionShopTrampoline Sprite_E9_MagicShopAssistant_bounce
+SpritePrep_PotionShopTrampoline SpritePrep_MagicShopAssistant_bounce
+Sprite_HeartContainerTrampoline Sprite_EA_HeartContainer_bounce
+SpritePrep_HeartContainerTrampoline SpritePrep_HeartContainer_bounce
+Sprite_HeartPieceTrampoline Sprite_EB_HeartPiece_bounce
+SpritePrep_HeartPieceTrampoline SpritePrep_HeartPiece
+FluteBoy_UnusedInvocation Sprite_2E_FluteKid_bounce
+Sprite_UnusedTelepathTrampoline Sprite_2D_TelepathicTile_bounce
+Sprite_HumanMulti_1_Trampoline Sprite_29_Adult_bounce
+Sprite_SweepingLadyTrampoline Sprite_2A_SweepingLady_bounce
+Sprite_LumberjacksTrampoline Sprite_2C_Lumberjacks_bounce
+Sprite_FortuneTellerTrampoline Sprite_31_FortuneTeller_bounce
+Sprite_MazeGameLadyTrampoline Sprite_2F_RaceGameLady_bounce
+Sprite_MazeGameGuyTrampoline Sprite_30_RaceGameGuy_bounce
+Sprite_TalkingTreeTrampoline Sprite_25_TalkingTree_bounce
+Sprite_MovableStatue Sprite_1C_Statue
+MovableStatue_CheckFullSwitchCovering Statue_CheckForSwitch
+MovableStatue_MoveTouchingSprites Statue_BlockSprites
+Sprite_WeathervaneTrigger Sprite_1D_FluteQuest
+Sprite_WishPond Sprite_72_FairyPond
+Sprite_HappinessPond_0 Sprite_FairyPond_WaitForLink
+Sprite_HappinessPond_1 Sprite_LakeHyliaFairy_WaitForLink
+Sprite_HappinessPond_2 Sprite_LakeHyliaFairy_BegForDonation
+Sprite_HappinessPond_3 Sprite_LakeHyliaFairy_AcceptDonation
+Sprite_HappinessPond_4 Sprite_LakeHyliaFairy_WaitForDonation
+Sprite_HappinessPond_5 Sprite_LakeHyliaFairy_SpawnFairy
+Sprite_HappinessPond_6 Sprite_LakeHyliaFairy_Greetings
+Sprite_HappinessPond_7 Sprite_LakeHyliaFairy_OfferUpgrade
+Sprite_HappinessPond_8 Sprite_LakeHyliaFairy_UpgradeBombs
+Sprite_HappinessPond_9 Sprite_LakeHyliaFairy_RevertTranslucency
+Sprite_HappinessPond_10 Sprite_LakeHyliaFairy_DeleteFairy
+Sprite_HappinessPond_11 Sprite_LakeHyliaFairy_RestoreAndReset
+Sprite_HappinessPond_12 Sprite_LakeHyliaFairy_UpgradeArrows
+Sprite_HappinessPond_13 Sprite_LakeHyliaFairy_GiveDonationStatus
+HappinessPond_GrantLuckStatus LakeHyliaFairy_GrantLuck
+Sprite_WishPond2_0 Sprite_UpgradeFairy_WaitForLink
+Sprite_WishPond2_1 Sprite_UpgradeFairy_OfferItemToss
+Sprite_WishPond2_2 Sprite_UpgradeFairy_HandleItemToss
+Sprite_WishPond2_3 Sprite_UpgradeFairy_SpawnFairy
+Sprite_WishPond2_4 Sprite_UpgradeFairy_AskWhoDidThis
+Sprite_WishPond2_5 Sprite_UpgradeFairy_HandleAnswer
+Sprite_WishPond2_6 Sprite_UpgradeFairy_HandleUpgrade
+Sprite_WishPond2_7 Sprite_UpgradeFairy_Retreat
+Sprite_WishPond2_8 Sprite_UpgradeFairy_FixPalettes
+Sprite_WishPond2_9 Sprite_UpgradeFairy_HandleItemReceipt
+Sprite_WishPond2_10 Sprite_UpgradeFairy_FinalGoodBye
+Sprite_WishPond2_11 Sprite_UpgradeFairy_YouLiar
+Sprite_WishPond2_12 Sprite_UpgradeFairy_SecondChance
+Sprite_WishPond2_13 Sprite_UpgradeFairy_DebaseLink
+Sprite_Leever Sprite_71_Leever
+Leever_UnderSand Leever_Underground
+sub_86CBF5 UNREACHABLE_06CBFD
+Leever_AttackPlayer Leever_Attack
+Leever_Submerge Leever_Dig
+Sprite_HeartRefill Sprite_D8_Heart
+Sprite_ResetVelXYZ Sprite_ZeroVelocity_XYZ
+Sprite_ReturnHandleDraggingByAncilla Sprite_HandleDraggingByAncilla
+Sprite_Faerie Sprite_E3_Fairy
+Faerie_Normal Fairy_Prancing
+Faerie_HandleCapture Fairy_HandleCapture
+Faerie_CheckForTemporaryUntouchability Fairy_CheckIfTouchable
+Sprite_Key Sprite_E4_SmallKey
+Sprite_ItemPickup Sprite_D9_GreenRupee
+Sprite_CommonItemPickup Sprite_Absorbable_Main
+ShieldPickup_AbsorptionByPlayer Absorb_Shield
+BigKey_AbsorptionByPlayer Absorb_BigKey
+Faerie_AbsorptionByPlayer Absorb_Fairy
+sub_86D1AF Absorb_Heart
+GreenRupee_AbsorptionByPlayer Absorb_Rupee
+OneBombRefill_AbsorptionByPlayer Absorb_Bomb
+SmallMagicRefill_AbsorptionByPlayer Absorb_SmallMagic
+FiveArrowRefill_AbsorptionByPlayer Absorb_Arrows_5
+Sprite_DrawAbsorbableOrReturn SpriteDraw_AbsorbableTransient
+Sprite_Octorock Sprite_08_Octorok
+Octorock_Normal Octorok_ShootSingle
+Octorock_FourShooter Octorok_Shoot4Ways
+Octorock_SpitOutRock Octorok_FireLoogie
+Sprite_Octostone Sprite_0C_OctorokStone
+Octostone_DrawCrumbling SpriteDraw_OctorokStoneCrumbling
+Sprite_Octoballoon Sprite_0F_Octoballoon
+Octoballoon_ApplyRecoilToPlayer Octoballoon_RecoilLink
+Octoballoon_SpawnTheSpawn Octoballoon_FormBabby
+Sprite_Octospawn Sprite_10_OctoballoonBaby
+Sprite_Buzzblob Sprite_0D_Buzzblob
+Sprite_WallInducedSpeedInversion Sprite_BounceOffWall
+Sprite_NegateVel Sprite_InvertSpeed_XY
+Sprite_InvertVertSpeed Sprite_InvertSpeed_Y
+Sprite_PrepAndDrawSingleLarge SpriteDraw_SingleLarge
+Sprite_PrepAndDrawSingleSmall SpriteDraw_SingleSmall
+Sprite_DrawShadow SpriteDraw_Shadow
+Sprite_DrawShadowEx SpriteDraw_Shadow_custom
+Sprite_DrawKey Sprite_DrawThinAndTall
+Sprite_StalfosHead Sprite_02_StalfosHead
+SpriteHeld_Main SpriteModule_Carried
+SpriteHeld_ThrowQuery CarriedSprite_CheckForThrow
+ThrownSprite_TileAndPeerInteraction ThrownSprite_TileAndSpriteInteraction
+SpriteStunned_Main SpriteModule_Stunned
+ThrownSprite_CheckDamageToPeers ThrownSprite_CheckDamageToSprites
+ThrownSprite_CheckDamageToSinglePeer ThrownSprite_CheckDamageToSingleSprite
+Sprite_NegateHalveSpeedEtc Sprite_ApplyRicochet
+Sprite_Func20 ThrowableScenery_TransmuteIfValid
+Sprite_Func21 ThrowableScenery_TransmuteToDebris
+Sprite_Func2 Sprite_ScheduleForBreakage
+Sprite_HalveVelocity Sprite_HalveSpeed_XY
+Fish_SpawnLeapingFish Sprite_SpawnLeapingFish
+SpriteStunned_Main_Func1_withRipple HandleFreezeAndStunTimer
+SpritePoof_Main SpriteModule_Poof
+Sprite_PrepOamCoordSafe Sprite_PrepOamCoord
+sub_86E4A1 Sprite_CheckTileCollision_set_layer
+j_Sprite_CheckTileCollisionSingleLayer Sprite_CheckTileCollision_check_just_one
+Sprite_Func7 Sprite_CheckForTileInDirection_horizontal
+Sprite_Func6 Sprite_CheckForTileInDirection_vertical
+Sprite_Func9 SpriteFall_AdjustPosition
+Sprite_Func10 Sprite_CheckTileInDirection
+Sprite_Func5 Sprite_CheckTileProperty
+Entity_GetTileAttr GetTileAttribute
+Sprite_GetTileAttrLocal Sprite_GetTileAttribute
+Entity_CheckSlopedTileCollisionLong Sprite_CheckSlopedTileCollision
+Sprite_ProjectSpeedTowardsPlayer_return Sprite_ProjectSpeedTowardsLink_instantexit
+Sprite_ProjectSpeedTowardsPlayer Sprite_ProjectSpeedTowardsLink
+Sprite_ApplySpeedTowardsPlayer Sprite_ApplySpeedTowardsLink
+Sprite_ProjectSpeedTowardsEntity Sprite_ProjectSpeedTowardsLocation
+sub_86EA2A Sprite_ProjectSpeedTowardsLocation_fastexit
+Sprite_IsToRightOfEntity Sprite_IsRightOfLocation
+Sprite_IsBelowEntity Sprite_IsBelowLocation
+Sprite_DirectionToFaceEntity Sprite_DirectionToFaceLocation
+Sprite_Func1 Guard_ParrySwordAttacks
+Sprite_Func13 Sprite_AttemptZapDamage
+Sprite_CheckAncillaDamage Ancilla_CheckDamageToSprite
+Sprite_CheckAncillaDamage2 Ancilla_CheckDamageToSprite_aggressive
+Sprite_Func11 Ancilla_CheckDamageToSprite_preset
+Sprite_Func14 Sprite_CalculateSwordDamage
+Sprite_Func16 Sprite_ApplyCalculatedDamage
+Sprite_Func17 AgahnimBalls_DamageAgahnim
+Sprite_HitTimer24 Sprite_MiniMoldorm_Recoil
+Sprite_CheckDamageToPlayer Sprite_CheckDamageToLink
+Sprite_CheckDamageToPlayerSameLayer Sprite_CheckDamageToLink_same_layer
+Sprite_CheckDamageToPlayerIgnoreLayer Sprite_CheckDamageToLink_ignore_layer
+Sprite_CheckDamageToPlayer_CheckCoord Sprite_SetupHitBox00
+Sprite_CheckDamageFromPlayer Sprite_CheckDamageFromLink
+Sprite_StaggeredCheckDamageToPlayerPlusRecoil Sprite_AttemptDamageToLinkWithCollisionCheck
+Sprite_AttemptDamageToPlayerPlusRecoil Sprite_AttemptDamageToLinkPlusRecoil
+sub_86F445 Sprite_RecoilLinkAndTHUMP
+Player_SetupActionHitBoxLong SetupActionHitBox
+Player_SetupActionHitBoxInner2 SetupActionHitBox_spinning
+Player_SetupActionHitBoxInner SetupActionHitBox_dashing
+Sprite_Func12 Sprite_DoHitBoxesFast
+Sprite_ApplyRecoilToPlayer Sprite_ApplyRecoilToLink
+Player_PlaceRepulseSpark Link_PlaceWeaponTink
+Sprite_PlaceRupulseSpark Sprite_PlaceWeaponTink
+GetPlayerHitBoxUnlessDisabled Link_SetupHitBox_conditional
+GetPlayerHitBox Link_SetupHitBox
+OAM_AllocateDeferToPlayer Oam_AllocateDeferToPlayer
+SpriteDeath_Main SpriteModule_Die
+SpriteDeath_Func1 Sprite_DoTheDeath
+SpriteDeath_Func2 ForcePrizeDrop
+SpriteDeath_Func3 PrepareEnemyDrop
+SpriteDeath_DrawPerishingOverlay SpriteDeath_DrawPoof
+SpriteCustomFall_Main SpriteModule_Fall2
+Sprite_DrawFall_Type0 SpriteDraw_FallingHelmaBeetle
+Sprite_DrawFall_Type1 SpriteDraw_FallingHumanoid
+sub_86FF6D UNREACHABLE_06FF73
+Player_Main Link_Main
+Player_DoSfx1 PlaySfx_Set1
+Player_DoSfx2 PlaySfx_Set2
+Player_DoSfx3 PlaySfx_Set3
+GetPlayerRelativePan PlaySfx_SetPan
+Player_Main_UnlessFrozen Link_ControlHandler
+PlayerHandler_00_Ground LinkState_Default
+PlayerHandler_00_Ground_2 HandleLink_From1D
+Link_CheckRemoveTempbunny Link_HandleBunnyTransformation
+PlayerHandler_1C_TempBunny LinkState_TemporaryBunny
+Link_TempBunny_Func1 LinkState_Bunny_recache
+PlayerHandler_18_StuckUnderRock LinkState_HoldingBigRock
+Player_InitiateFirstEtherSpell EtherTablet_StartCutscene
+PlayerHandler_19_ReceiveEther LinkState_ReceivingEther
+Player_InitiateFirstBombosSpell BombosTablet_StartCutscene
+PlayerHandler_1A_ReceiveBombos LinkState_ReceivingBombos
+sub_87866D InitiateDesertCutscene
+PlayerHandler_1B_OpenDesertPalace LinkState_ReadingDesertTablet
+Player_CheckGravestoneOrSomariaBlock HandleSomariaAndGraves
+PlayerHandler_02_RecoilMode LinkState_Recoil
+Player_HandleIncapacitated Link_HandleRecoilAndTimer
+PlayerHandler_05_TurtleRockPlatform_UNUSED LinkState_OnIce
+Player_RecoilMode_Helper1 Link_HandleChangeInZVelocity
+PlayerHandler_0B_FallingLedgeDown LinkHop_HoppingSouthOW
+Player_Ledge_Handler1 LinkState_HandlingJump
+Link_DoMoveXCoord_Outdoors_Helper3 LinkHop_FindTileToLandOnSouth
+PlayerHandler_0C_FallingLedge LinkState_HoppingHorizontallyOW
+Link_DoMoveXCoord_Outdoors_Helper2 Link_HoppingHorizontally_FindTile_Y
+Player_RecoilMode_Helper2 Link_SetToDeepWater
+PlayerHandler_0F_JumpLedgeMore_UNUSED LinkState_0F
+Link_DoMoveXCoord_Outdoors_Helper1 Link_HoppingHorizontally_FindTile_X
+PlayerHandler_0D_JumpDiagLedgeUp LinkState_HoppingDiagonallyUpOW
+PlayerHandler_0E_JumpLedgeDown LinkState_HoppingDiagonallyDownOW
+Link_Ledge_Func1 LinkHop_FindLandingSpotDiagonallyDown
+Player_HandleIncapacitated_Helper1 Link_SplashUponLanding
+PlayerHandler_11_StartDash LinkState_Dashing
+PlayerHandler_12_OutOfDash LinkState_ExitingDash
+Player_HaltDashAttack Link_CancelDash
+Link_Move_Helper5 RepelDash
+Link_MoveXY_Helper LinkApplyTileRebound
+Player_RepelDashAttack Sprite_RepelDash
+SetDirectionFromRecoil Flag67WithDirections
+PlayerHandler_01_FallHole LinkState_Pits
+DoSwordInteractionWithTiles_Helper2 HandleLayerOfDestination
+Player_DecreaseHealthWithHole DungeonPitDoDamage
+HoleToDungeon_Helper1 HandleDungeonLandingFromPit
+PlayerHandler_04_Swimming_Inner Link_HandleSwimMovements
+Link_Swim_Helper2 Link_FlagMaxAccels
+Link_Swim_Helper3 Link_SetIceMaxAccel
+Link_Swim_Helper4 Link_SetMomentum
+Player_ResetSwimState Link_ResetSwimmingState
+Link_ResetSomething1 Link_ResetStateAfterDamagingPit
+Player_ResetSwimCollision ResetAllAcceleration
+Link_Swim_Helper1 Link_HandleSwimAccels
+Link_Swim_Helper5 Link_SetTheMaxAccel
+PlayerHandler_07_Electrocution LinkState_Zapped
+Link_SetInBed Link_TuckIntoBed
+PlayerHandler_16_SleepInBed LinkState_Sleeping
+PlayerHandler_16_SleepInBed_00 Link_SnoringInBed
+PlayerHandler_16_SleepInBed_01 Link_SittingUpInBed
+PlayerHandler_16_SleepInBed_02 Link_JumpingOutOfBed
+Player_Sword Link_HandleSwordCooldown
+Link_HandleYButtonItems Link_HandleYItem
+Player_HandleActions Link_HandleAPress
+Player_DoAction Link_APress_PerformBasic
+Link_CheckFireBeam HandleSwordSfxAndBeam
+Player_Sword_Inner Link_CheckForSwordSwing
+Player_Sword_SpinAttackJerks HandleSwordControls
+Player_SetAllowDirChangeEtc Link_ResetSwordAndItemUsage
+Player_CalcSwordOamOffs CalculateSwordHitBox
+Item_Rod_Shoot RodItem_CreateShot
+Item_Rod_Shoot_2 RodItem_CreateIceShot
+Item_Rod_Shoot_1_Outer RodItem_CreateFireShot
+LinkItem_RemoveFromHand Link_ResetBoomerangYStuff
+LinkItem_MagicPowder LinkItem_Powder
+GanonEmerges_SpawnTravelBird CallForDuckIndoors
+LinkItem_BookOfMudora LinkItem_Book
+LinkItem_EtherMedallion LinkItem_Ether
+PlayerHandler_08_Ether LinkState_UsingEther
+PlayerHandler_09_Bombos LinkState_UsingBombos
+PlayerHandler_0A_QuakeMedallion LinkState_UsingQuake
+Link_SomethingThenSetSpinAttacking Link_ActivateSpinAttack
+Link_SetSpinAttacking Link_AnimateVictorySpin
+PlayerHandler_03_SpinAttack LinkState_SpinAttack
+sub_87A8EC UNREACHABLE_07A8DC
+PlayerHandler_14_MagicMirror LinkState_CrossingWorlds
+Link_ActionBookMudora Link_PerformDesertPrayer
+Player_AfterMirrorWarp HandleFollowersAfterMirroring
+PlayerHandler_13_Hookshot LinkState_Hookshotting
+Item_Cape_StopWithAnim Link_ForceUnequipCape
+Player_TurnOffCapeMode Link_ForceUnequipCape_quietly
+Link_SomethingCollideWithFloor HaltLinkWhenUsingItems
+Player_CheckHandleCapeStuff_IfCarry Link_HandleCape_passive_LiftCheck
+DoSwordInteractionWithTiles_Byrna SearchForByrnaSpark
+LinkItem_BugCatchingNet LinkItem_Net
+Link_CheckNewY_ButtonPress CheckYButtonPress
+LinkItem_EvaluateMagicCost LinkCheckMagicCost
+LinkItem_ReturnUnusedMagic Refund_Magic
+Player_ResetSomeCrap Link_ItemReset_FromOverworldThings
+Link_Lift Link_PerformThrow
+Link_AfterAction1_Pickup Link_APress_LiftCarryThrow
+Link_StartDash Link_PerformDash
+nullsub_6 Link_APress_NothingB
+Link_GrabWall Link_PerformGrab
+Link_AfterAction3_GrabWall Link_APress_PullObject
+Link_MovableStatue Link_PerformStatueDrag
+Link_AfterAction6_MovableStatue Link_APress_StatueDrag
+Link_PullForRupees Link_PerformRupeePull
+PlayerHandler_1D_PullRupees LinkState_TreePull
+Link_ReadSign Link_PerformRead
+Link_Chest Link_PerformOpenChest
+CheckAButtonPressedNow Link_CheckNewAPress
+PlayerHandler_00_RelatedToABtn Link_HandleToss
+sub_87B609 UNREACHABLE_07B5F2
+Player_LimitDirections Link_HandleDiagonalCollision
+Player_DoTileInteractions Link_HandleCardinalCollision
+Link_MoveCoord_YX RunSlopeCollisionChecks_VerticalFirst
+Link_MoveCoord_XY RunSlopeCollisionChecks_HorizontalFirst
+Player_CheckSetLowerLevelMoving CheckIfRoomNeedsDoubleLayerCheck
+Player_SetUpperLevelCheckMoving CreateVelocityFromMovingBackground
+Link_DoMoveYCoord StartMovementCollisionChecks_Y
+Link_DoMoveYCoord_Indoors StartMovementCollisionChecks_Y_HandleIndoors
+Player_DoMoveY_Entry2 HandlePushingBonkingSnaps_Y
+Link_DoMoveYCoord_Outdoors StartMovementCollisionChecks_Y_HandleOutdoors
+Link_CheckTriggerJumpLedge1 RunLedgeHopTimer
+Link_Move_Helper4_CheckSmash Link_BonkAndSmash
+AlignYCoordToTile Link_AddInVelocityYFalling
+Link_MoveY_AdjustXForDoor CalculateSnapScratch_Y
+Add_R0_To_X AddAbsoluteScratchToXCoord
+Link_MoveY_Doorway_Helper3 ChangeAxisOfPerpendicularDoorMovement_Y
+Link_SubtractVelFromY Link_AddInVelocityY
+Link_SomeKindOfRecoil_Y Link_HopInOrOutOfWater_Y
+Link_MoveY_RecoilOther Link_FindValidLandingTile_North
+Link_JumpOffLedgeUpDown Link_FindValidLandingTile_DiagonalNorth
+Link_DoMoveXCoord StartMovementCollisionChecks_X
+Link_DoMoveXCoord_Indoors StartMovementCollisionChecks_X_HandleIndoors
+Player_DoMoveX_Entry2 HandlePushingBonkingSnaps_X
+Link_DoMoveXCoord_Outdoors StartMovementCollisionChecks_X_HandleOutdoors
+AlignXCoordToTile SnapOnX
+Link_DoMoveXCoord_Indoors_0 CalculateSnapScratch_X
+Add_R0_to_Y AddAbsoluteScratchToYCoord
+Link_DoMoveXCoord_Indoors_DoorWay ChangeAxisOfPerpendicularDoorMovement_X
+Link_SomeKindOfRecoil_X Link_HopInOrOutOfWater_X
+Link_AvoidJudderAgainstDiagWall Link_HandleDiagonalKickback
+DetectTiles_MoveY TileDetect_Movement_Y
+DetectTiles_MoveX TileDetect_Movement_X
+DetectTiles_3_UpDown TileDetect_Movement_VerticalSlopes
+DetectTiles_4_LeftRight TileDetect_Movement_HorizontalSlopes
+Player_TileDetectNearby_Far TileDetect_BigArea
+DetectTiles_5_UNUSED TileDetect_UnusedIce
+DoSwordInteractionWithTiles TileDetect_MainHandler
+DoSwordInteractionWithTiles_Helper4 Link_PermissionForSloshSounds
+ChangableDungeonObj_Func1B PushBlock_AttemptToPushTheBlock
+GetBestActionToPerformOnTile Link_HandleLiftables
+Link_Move_Helper6 HandleNudging
+Hookshot_CheckTileCollison Hookshot_CheckTileCollision
+DetectTiles_7 HandleNudgingInADoor
+DetectTiles_8 TileCheckForMirrorBonk
+DetectTiles_9 TileDetect_SwordSwingDeepInDoor
+TileDetect_Execute TileDetection_Execute
+DoSwordInteractionWithTiles_Helper TileBehavior_HandleItemAndExecute
+TileHandlerIndoor_01 TileBehavior_StandardCollision
+TileHandlerIndoor_18 TileBehavior_SlopeOuter
+TileHandlerIndoor_10 TileBehavior_Slope
+TileHandlerIndoor_1D TileBehavior_NorthSingleLayerStairs
+TileHandlerIndoor_1E TileBehavior_NorthSwapLayerStairs
+TileHandlerIndoor_20 TileBehavior_Pit
+TileHandlerIndoor_0C TileBehavior_OverlayMask_0C
+TileHandlerIndoor_0E TileBehavior_GanonIce
+TileHandlerIndoor_0F TileBehavior_PalaceIce
+TileHandlerIndoor_C0 TileBehavior_LightableTorch
+TileHandlerIndoor_08 TileBehavior_DeepWater
+TileHandlerIndoor_0A TileBehavior_ShortWaterLadder
+TileHandlerIndoor_1C TileBehavior_OverlayMask_1C
+TileHandlerIndoor_90 TileBehavior_LayerToggleShutterDoor
+TileHandlerIndoor_98 TileBehavior_LayerAndDungeonToggleShutterDoor
+TileHandlerIndoor_A2 TileBehavior_DungeonToggleShutterDoor
+TileHandlerIndoor_A0 TileBehavior_DungeonToggleManualDoor
+TileHandlerIndoor_09 TileBehavior_ShallowWater
+TileHandlerIndoor_70 TileBehavior_ManipulablyReplaced
+TileHandlerOutdoors_0B TileBehavior_UnusedDeepWater
+TileHandlerIndoor_58 TileBehavior_Chest
+TileHandlerIndoor_3D TileBehavior_SouthSingleLayerStairs
+TileHandlerIndoor_44 TileBehavior_Spike
+TileHandlerIndoor_0D TileBehavior_SpikeFloor
+TileHandlerIndoor_27 TileBehavior_Hookshottables
+IsHookshotTile TileBehavior_FlagManipulable
+TileHandlerIndoor_F0 TileBehavior_FlaggableDoor
+TileHandlerIndoor_60 TileBehavior_RupeeTile
+TileHandlerIndoor_67 TileBehavior_CrystalPeg_Up
+TileHandlerIndoor_68 TileBehavior_Conveyor_Upwards
+TileHandlerIndoor_69 TileBehavior_Conveyor_Downwards
+TileHandlerIndoor_6A TileBehavior_Conveyor_Leftwards
+TileHandlerIndoor_6B TileBehavior_Conveyor_Rightwards
+TileHandlerIndoor_63 TileBehavior_MinigameChest
+TileHandlerIndoor_8E TileBehavior_Entrance
+TileHandlerOutdoors_00 TileBehavior_NothingOW
+TileHandlerIndoor_40 TileBehavior_ThickGrass
+TileHandlerIndoor_48 TileBehavior_DiggableGround
+TileHandlerIndoor_50 TileBehavior_Liftable
+TileHandlerIndoor_29 TileBehavior_Ledge_South
+TileHandlerIndoor_28 TileBehavior_Ledge_North
+TileHandlerIndoor_2A TileBehavior_Ledge_EastWest
+TileHandlerIndoor_2C TileBehavior_Ledge_NorthDiagonal
+TileHandlerIndoor_2D TileBehavior_Ledge_SouthDiagonal
+TileHandlerOutdoors_4C TileBehavior_UnusedCornerType
+TileHandlerOutdoors_4E TileBehavior_EasternRuinsCorner
+TileHandlerIndoor_4B TileBehavior_Warp
+TileHandlerOutdoors_42 TileBehavior_GraveStone
+TileHandlerIndoor_46 TileBehavior_HylianPlaque
+TileHandlerIndoor_57 TileBehavior_BonkRocks
+ChangableDungeonObj_Func1C PushBlock_GetTargetTileFlag
+Link_AvoidJudderAgainstDiagWall_Y FlagMovingIntoSlopes_Y
+Link_AvoidJudderAgainstDiagWall_X FlagMovingIntoSlopes_X
+Player_HandleIncapacitated_Inner Link_HandleRecoiling
+Player_SomethingWithVelocity Link_HandleVelocity
+Player_MovePosition1 LinkHop_FindArbitraryLandingSpot
+Player_ApplyDragAndComputeVel Link_HandleVelocityAndSandDrag
+Player_SomethingWithVelocity_IsSwimming HandleSwimStrokeAndSubpixels
+Player_SomethingWithVelocity_IsTired Link_DashInPlace
+Player_CheckApplyFloorVel Link_HandleMovingFloor
+Player_ApplyFloorVel Link_ApplyMovingFloorVelocity
+Player_MovingBelt Link_ApplyConveyor
+Player_UpdateDirection_PushingBits4 Link_HandleMovingAnimation_SetFacingDown
+Player_UpdateDirection Link_HandleMovingAnimation_FullLongEntry
+Player_UpdateDirection_Part2 Link_HandleMovingAnimation_StartWithDash
+Player_UpdateDirection_Swimming Link_HandleMovingAnimationSwimming
+Player_UpdateDirection_Running Link_HandleMovingAnimation_Dash
+Player_CheckDoorwayQuadrantMovement HandleIndoorCameraAndDoors
+Player_CheckDoorwayMovement HandleDoorTransitions
+Player_CheckCrossQuadrantBoundary ApplyLinksMovementToCamera
+PrayingScene_InitHDMA DesertPrayer_InitializeIrisHDMA
+PrayingScene_HDMAStuff DesertPrayer_BuildIrisHDMATable
+PrayingScene_Func1 DesertHDMA_CalculateIrisShapeLine
+InsertIntoChangableDungeonObj FindFreeMovingBlockSlot
+ChangableDungeonObj_Func1 InitializePushBlock
+ChangableDungeonObj_Func2 PushBlock_Slide
+PushBlock_Handler_Step4 PushBlock_HandleFalling
+ChangableDungeonObj_Func2C PushBlock_ApplyVelocity
+ChangableDungeonObj_Func2B PushBlock_HandleCollision
+Sprite_HandlePushedBlocks Sprite_Dungeon_DrawAllPushBlocks
+Sprite_DrawOnePushedBlock Sprite_Dungeon_DrawSinglePushBlock
+Init_Player Link_Initialize
+Player_ResetState Link_ResetProperties_A
+Player_ResetState2 Link_ResetProperties_B
+Player_ResetState3 Link_ResetProperties_C
+Player_UsedForSpiralStaircase HandleLinkOnSpiralStairs
+UsedForSpiralStaircase2 SpiralStairs_FindLandingSpot
+Link_ResetTimerForPushGetTired LinkResetPushTimer
+sub_87F3FD UNREACHABLE_07F3D7
+Player_IsScreenTransitionBlocked Link_CheckForEdgeScreenTransition
+Tagalong_CanWeDisplayMessage Follower_ValidateMessageFreedom
+Player_ApproachTriforce TriforceRoom_LinkApproachTriforce
+Sprite_CheckIfPlayerPreoccupied Sprite_CheckIfLinkIsBusy
+Player_IsPipeEnterable Pipe_ValidateEntry
+Player_OutdoorCacheStatePriorToHandler CacheCameraPropertiesIfOutdoors
+Ancilla_DoSfx1_NearPlayer Ancilla_Sfx1_Near
+Player_DoSfx2 Ancilla_Sfx2_Near
+Player_DoSfx3 Ancilla_Sfx3_Near
+Player_SetSfxPan Ancilla_Sfx_Near
+Ancilla_DoSfx1 Ancilla_Sfx1_Pan
+Ancilla_DoSfx2 Ancilla_Sfx2_Pan
+Ancilla_DoSfx3 Ancilla_Sfx3_Pan
+Ancilla_GetSfxPan Ancilla_Sfx_SetPan
+Item_Rod_Shoot_1 AncillaAdd_FireRodShot
+SomarianBlast_SpawnCentrifugalQuad SomariaBlock_SpawnBullets
+Bomb_ProjectReflexiveSpeedOntoSprite Ancilla_ProjectReflexiveSpeedOntoSprite
+Ancilla_ExecuteObjects Ancilla_ExecuteAll
+Ancilla_ExecuteObject Ancilla_ExecuteOne
+Ancilla_IceShotSparkle Ancilla13_IceRodSparkle
+IceShotSparkle_Spawn AncillaAdd_IceRodSparkle
+Ancilla_SomarianBlast Ancilla01_SomariaBullet
+Ancilla_FireShot Ancilla02_FireRodShot
+Ancilla_CheckTileCollisionStaggered Ancilla_CheckTileCollision_staggered
+Ancilla_CheckTileCollisionOneFloorEx Ancilla_CheckTileCollision_targeted
+Ancilla_BeamHit Ancilla04_BeamHit
+Ancilla_CheckOneSpriteCollision Ancilla_CheckSpriteCollision_Single
+Ancilla_IsToRightOfPlayer Ancilla_IsRightOfLink
+Ancilla_IsBelowPlayer Ancilla_IsBelowLink
+Ancilla_RepulseSpark Ancilla_WeaponTink
+Ancilla_Boomerang Ancilla05_Boomerang
+Boomerang_CheckForScreenEdgeReversal Boomerang_ScreenEdge
+Boomerang_SelfTerminateIfOffscreen Boomerang_StopOffScreen
+Ancilla_WallHit Ancilla06_WallHit
+Ancilla_Bomb Ancilla07_Bomb
+Ancilla_ConveyorBeltVelocityOverride Ancilla_ApplyConveyor
+Ancilla_LiftableObjectLogic Ancilla_HandleLiftLogic
+Ancilla_Liftable_Func4 Ancilla_LatchAltitudeAboveLink
+Ancilla_Liftable_Func3 Ancilla_LatchLinkCoordinates
+Ancilla_Liftable_Func2 Ancilla_LatchCarriedPosition
+Ancilla_Adjust_Y_CoordByAltitude Ancilla_LatchYCoordToZ
+Ancilla_RestoreY Ancilla_SetYFrom_DP72
+Bomb_GetSomeDistance Bomb_GetDisplacementFromLink
+Ancilla_DoorDebris Ancilla08_DoorDebris
+Ancilla_Arrow Ancilla09_Arrow
+Ancilla_HaltedArrow Ancilla0A_ArrowInTheWall
+Ancilla_IceShot Ancilla0B_IceRodShot
+Ancilla_IceShotSpread Ancilla11_IceRodWallHit
+Ancilla_BlastWallStuff Ancilla33_BlastWallExplosion
+BlastWall_DrawExplosion AncillaDraw_BlastWallBlast
+Bomb_DrawExplosion AncillaDraw_Explosion
+Ancilla_JumpSplash Ancilla15_JumpSplash
+Ancilla_HitStars Ancilla16_HitStars
+Ancilla_ShovelDirt Ancilla17_ShovelDirt
+Ancilla_BlastWallFireball Ancilla32_BlastWallFireball
+Ancilla_EtherSpell Ancilla18_EtherSpell
+EtherSpell_LightningDescends EtherSpell_HandleLightningStroke
+EtherSpell_PulsingBlitzOrb EtherSpell_HandleOrbPulse
+EtherSpell_RadialStates EtherSpell_HandleRadialSpin
+EtherSpell_DrawBlitzBall AncillaDraw_EtherBlitzBall
+EtherSpell_DrawSplittingBlitzSegment AncillaDraw_EtherBlitzSegment
+EtherSpell_DrawBlitzSegments AncillaDraw_EtherBlitz
+EtherSpell_DrawBlitzOrb AncillaDraw_EtherOrb
+Bombos_StartAnim AncillaAdd_BombosSpell
+Ancilla_BombosSpell Ancilla19_BombosSpell
+Bombos_ExecuteFlameColumns BombosSpell_ControlFireColumns
+BombosSpell_WrapUpFlameColumns BombosSpell_FinishFireColumns
+BombosSpell_DrawFireColumn AncillaDraw_BombosFireColumn
+BombosSpell_ExecuteBlasts BombosSpell_ControlBlasting
+BombosSpell_DrawBlast AncillaDraw_BombosBlast
+Ancilla_QuakeSpell Ancilla1C_QuakeSpell
+QuakeSpell_ExecuteBolts QuakeSpell_ControlBolts
+QuakeSpell_DrawFirstGroundBolts AncillaDraw_QuakeInitialBolts
+QuakeSpell_SpreadGroundBolts QuakeSpell_SpreadBolts
+Ancilla_MagicPowder Ancilla1A_PowderDust
+MagicPowder_ApplySpriteDamage Powder_ApplyDamageToSprites
+Ancilla_DashTremor Ancilla1D_ScreenShake
+Ancilla_DashDust Ancilla1E_DashDust
+Ancilla_Hookshot Ancilla1F_Hookshot
+Ancilla_BedSpread Ancilla20_Blanket
+Ancilla_SleepIcon Ancilla21_Snore
+Ancilla_VictorySparkle Ancilla3B_SwordUpSparkle
+Ancilla_SwordChargeSpark Ancilla3C_SpinAttackChargeSparkle
+Ancilla_SwordCeremony Ancilla35_MasterSwordReceipt
+Ancilla_ReceiveItem Ancilla22_ItemReceipt
+Ancilla_WishPondItem Ancilla28_WishPondItem
+Ancilla_HappinessPondRupees Ancilla42_HappinessPondRupees
+HappinessPondRupees_ExecuteRupee HapinessPondRupees_ExecuteRupee
+HappinessPondRupees_LoadRupeeeState HapinessPondRupees_GetState
+HappinessPondRupees_StoreRupeeState HapinessPondRupees_SaveState
+Ancilla_TransmuteToObjectSplash Ancilla_TransmuteToSplash
+Ancilla_ObjectSplash Ancilla3D_ItemSplash
+Ancilla_MilestoneItem Ancilla29_MilestoneItemReceipt
+Ancilla_TransmuteToRisingCrystal ItemReceipt_TransmuteToRisingCrystal
+Ancilla_AddSwordChargeSpark AncillaAdd_OccasionalSparkle
+Ancilla_BreakTowerSeal Ancilla43_GanonsTowerCutscene
+BreakTowerSeal_DrawCrystal AncillaDraw_GTCutsceneCrystal
+BreakTowerSeal_ActivateSingleSparkle GTCutscene_ActivateSparkle
+BreakTowerSeal_ExecuteSparkles GTCutscene_SparkleALot
+Ancilla_Flute Ancilla36_Flute
+Ancilla_WeathervaneExplosion Ancilla37_WeathervaneExplosion
+WeathervaneExplosion_DrawWoodChunk AncillaDraw_WeathervaneExplosionWoodDebris
+Ancilla_TravelBirdIntro Ancilla38_CutsceneDuck
+Ancilla_MorphPoof Ancilla23_LinkPoof
+Ancilla_DwarfPoof Ancilla40_DwarfPoof
+Ancilla_BushPoof Ancilla3F_BushPoof
+Ancilla_SwordSwingSparkle Ancilla26_SwordSwingSparkle
+Ancilla_InitialSpinSpark Ancilla2A_SpinAttackSparkleA
+InitialSpinSpark_TransmuteToNormalSpinSpark SpinAttackSparkleA_TransmuteToNextSpark
+Ancilla_SpinSpark Ancilla2B_SpinAttackSparkleB
+Sparkle_GetRadialProjectionCoords Sparkle_PrepOamFromRadial
+SpinSpark_ExecuteClosingSpark SpinAttackSparkleB_Closer
+Ancilla_InitialCaneSpark Ancilla30_ByrnaWindupSpark
+CaneSpark_TransmuteInitialToNormal ByrnaWindupSpark_TransmuteToNormal
+Ancilla_CaneSpark Ancilla31_ByrnaSpark
+Ancilla_SwordFullChargeSpark Ancilla0D_SpinAttackFullChargeSpark
+Ancilla_TravelBird Ancilla27_Duck
+Item_CaneOfSomaria_Shoot AncillaAdd_SomariaBlock
+SomarianBlock_CheckForTransitLine SomariaBlock_CheckForTransitTile
+Ancilla_CheckSingleBasicSpriteCollision Ancilla_CheckBasicSpriteCollision_Single
+Ancilla_SomarianBlock Ancilla2C_SomariaBlock
+SomarianBlock_Func1 AncillaDraw_SomariaBlock
+SomarianBlock_CheckCoveredTileTrigger SomariaBlock_CheckForSwitch
+SomarianBlock_PlayerInteraction SomariaBlock_HandlePlayerInteraction
+Ancilla_TransmuteToSomarianBlockFizzle SomariaBlock_FizzleAway
+Ancilla_SomarianBlockFizzle Ancilla2D_SomariaBlockFizz
+Ancilla_SomarianPlatformPoof Ancilla39_SomariaPlatformPoof
+Ancilla_SomarianBlockDivide Ancilla2E_SomariaBlockFission
+Ancilla_LampFlame Ancilla2F_LampFlame
+Ancilla_WaterfallSplash Ancilla41_WaterfallSplash
+Ancilla_Gravestone Ancilla24_Gravestone
+Gravestone_RepelPlayerAdvance Gravestone_ActAsBarrier
+Ancilla_SkullWoodsFire Ancilla34_SkullWoodsFire
+Ancilla_SuperBombExplosion Ancilla3A_BigBombExplosion
+Ancilla_RevivalFaerie RevivalFairy_Main
+RevivalFaerie_Dust RevivalFairy_Dust
+RevivalFaerie_MonitorPlayerRecovery RevivalFairy_MonitorHP
+Ancilla_GameOverTextLong Animate_GAMEOVER_Letters
+Ancilla_SetSfxPan_NearEntity Ancilla_SetPanRelativeCoordinates
+Ancilla_Func1 AncillaAdd_AddAncilla_Bank08
+Ancilla_FindMatch UNREACHABLE_08F671
+Ancilla_SetSafeOam_XY Ancilla_SetOam_XY_safe
+Ancilla_CheckPlayerCollision Ancilla_CheckLinkCollision
+Hookshot_CheckChainLinkProximityToPlayer Hookshot_CheckProximityToLink
+Ancilla_CheckIfEntranceTriggered Ancilla_CheckForEntranceTrigger
+Ancilla_DrawShadow AncillaDraw_Shadow
+Ancilla_AllocateOam_B_or_E Ancilla_AllocateOamFromRegion_B_or_E
+Tagalong_GetCloseToPlayer Follower_MoveTowardsLink
+Ancilla_CustomAllocateOam Ancilla_AllocateOamFromCustomRegion
+Hookshot_IsCollisionCheckFutile Hookshot_ShouldIEvenBotherWithTiles
+Ancilla_AllocateOam Ancilla_AllocateOamFromRegion_A_or_D_or_F
+BeamHit_Get_Top_X_Bit BeamHit_GetTopXBit
+AddShovelHitStars Ancilla_AddHitStars
+AddLinksBedSpread AncillaAdd_Blanket
+AddSleepInBedAncilla AncillaAdd_Snoring
+Item_Bomb_Place AncillaAdd_Bomb
+Item_Boomerang_Shoot AncillaAdd_Boomerang
+AddReceivedItem AncillaAdd_ItemReceipt
+GiveBottledItem ItemReceipt_GiveBottledItem
+AddWishPondItem AncillaAdd_TossedPondItem
+AddPendantOrCrystal AncillaAdd_FallingPrize
+Item_Shovel_FoundFlute AncillaAdd_DugUpFlute
+AddChargedSpinAttackSparkle AncillaAdd_ChargedSpinAttackSparkle
+Item_Flute_DoAnim1 AncillaAdd_ExplodingWeatherVane
+AddTravelBirdIntro AncillaAdd_CutsceneDuck
+AddSomarianPlatformPoof AncillaAdd_SomariaPlatformPoof
+AddSuperBombExplosion AncillaAdd_SuperBombExplosion
+Ancilla_ConfigureRevivalObjects ConfigureRevivalAncillae
+Item_CaneOfByrna_DoAnim AncillaAdd_CaneOfByrnaInitSpark
+AddLampFlame AncillaAdd_LampFlame
+AddShovelDirt AncillaAdd_ShovelDirt
+AddSwordCeremony AncillaAdd_MSCutscene
+AddDashingDust AncillaAdd_DashDust
+AddDashingDust_notYetMoving AncillaAdd_DashDust_charging
+AddBlastWallFireball AncillaAdd_BlastWallFireball
+Item_Bow_Shoot AncillaAdd_Arrow
+AddWarpTransformationCloud AncillaAdd_BunnyPoof
+Cape_DoAnim AncillaAdd_CapePoof
+AddDwarfTransformationCloud AncillaAdd_DwarfPoof
+AddDisintegratingBushPoof AncillaAdd_BushPoof
+Ether_StartAnim AncillaAdd_EtherSpell
+AddVictorySpinEffect AncillaAdd_VictorySpin
+AddMagicPowder AncillaAdd_MagicPowder
+AddWallTapSpark AncillaAdd_WallTapSpark
+AddLinksSleepZs AncillaAdd_SwordSwingSparkle
+AddDashTremor AncillaAdd_DashTremor
+AddBoomerangWallHit AncillaAdd_BoomerangWallClink
+AddHookshotWallHit AncillaAdd_HookshotWallClink
+Item_Flute_DoAnim2 AncillaAdd_Duck_take_off
+Quake_StartAnim AncillaAdd_QuakeSpell
+AddSpinAttackStartSparkle AncillaAdd_SpinAttackInitSpark
+AddBlastWall AncillaAdd_BlastWall
+AddSwordChargeSpark AncillaAdd_SwordChargeSparkle
+AddSilverArrowSparkle AncillaAdd_SilverArrowSparkle
+Item_Rod_Shoot_2 AncillaAdd_IceRodShot
+AddTransitionSplash AncillaAdd_Splash
+Link_MoveGravestone AncillaAdd_GraveStone
+Item_Hookshot_Shoot AncillaAdd_Hookshot
+AddWaterfallSplash AncillaAdd_WaterfallSplash
+AddBreakTowerSeal AncillaAdd_GTCutscene
+AddDoorDebris AncillaAdd_DoorDebris
+ConsumingFire_TransmuteToSkullWoodsFire FireRodShot_BecomeSkullWoodsFire
+AddAncilla Ancilla_AddAncilla
+AddAncilla AncillaAdd_AddAncilla_Bank09
+Ancilla_HasAncillaOfType AncillaAdd_CheckForPresence
+Ancilla_Arrow_Allocate AncillaAdd_ArrowFindSlot
+Ancilla_CheckCollide_A Ancilla_CheckInitialTile_A
+Tagalong_CheckBlindTriggerRegion Follower_CheckBlindTrigger
+Tagalong_Init Follower_Initialize
+Tagalong_SpawnFromSprite Sprite_BecomeFollower
+Tagalong_Main Follower_Main
+Tagalong_MainB Follower_NoTimedMessage
+Tagalong_Func1 Follower_CheckGameMode
+Tagalong_Type_Other Follower_BasicMover
+Tagalong_Func2 Follower_NotFollowing
+Tagalong_Type_2_4 Follower_OldMan
+Tagalong_Type_3_11 Follower_OldManUnused
+Tagalong_Draw3 Follower_DoLayers
+Tagalong_CheckPlayerProximity Follower_CheckProximityToLink
+Tagalong_HandleMessages Follower_HandleTrigger
+Tagalong_DrawInner Follower_AnimateMovement_preserved
+Tagalong_SetOam_XY FollowerDraw_CalculateOamCoords
+Tagalong_CheckTextTriggerProximity Follower_CheckForTrigger
+Tagalong_Disable Follower_Disable
+Ancilla_GetCoords Ancilla_GetCoordinates
+AddSomarianBlockDivide AncillaAdd_ExplodingSomariaBlock
+GiveRupeeGift Ancilla_AddRupees
+Ancilla_MotiveDashDust DashDust_Motive
+Sprite_InitFromInfo Sprite_SetSpawnedCoordinates
+Sprite_SpawnMadBatterBolts Sprite_MagicBat_SpawnLightning
+Sprite_VerifyAllOnScreenDefeated Sprite_CheckIfScreenIsClear
+Sprite_VerifyAllOnScreenDefeatedB Sprite_CheckIfRoomIsClear
+Sprite_VerifyOverlordDefeated Sprite_CheckIfOverlordsClear
+Sprite_ReinitWarpVortex Sprite_InitializeMirrorPortal
+InitSpriteSlots Sprite_InitializeSlots
+ZoraFireball_SpawnTailGarnish Fireball_SpawnTrailGarnish
+Garnish_ArrghusSplash Garnish15_ArrghusSplash
+Garnish_SpawnPyramidDebris GarnishSpawn_PyramidDebris
+Garnish_PyramidDebris Garnish13_PyramidDebris
+Garnish_Move_XY Garnish_MoveXY
+Garnish_GanonBatFlameout Garnish11_WitheringGanonBatFlame
+Garnish_GanonBatFlame Garnish10_GanonBatFlame
+Garnish_TrinexxIce Garnish0C_TrinexxIceBreath
+Garnish_RunningManDashDust Garnish14_KakKidDashDust
+Garnish_CannonPoof Garnish0A_CannonSmoke
+Garnish_LightningTrail Garnish09_LightningTrail
+Garnish_BabusuFlash Garnish07_BabasuFlash
+Garnish_Nebule Garnish08_KholdstareTrail
+Garnish_ZoroDander Garnish06_ZoroTrail
+Garnish_Sparkle Garnish12_Sparkle
+Garnish_TrinexxLavaBubble Garnish0E_TrinexxFireBreath
+Garnish_BlindLaserTrail Garnish0F_BlindLaserTrail
+Garnish_LaserBeamTrail Garnish04_LaserTrail
+Garnish_CrumbleTile Garnish03_FallingTile
+Garnish_WinderTrail Garnish01_FireSnakeTail
+Garnish_MothulaBeamTrail Garnish02_MothulaBeamTrail
+Garnish_SetOamPropsAndLargeSize Garnish_FinalizeBigOamObject
+Overlord_ArmosCoordinator Overlord19_ArmosCoordinator_bounce
+Overlord_RedStalfosTrap Overlord18_InvisibleStalfos
+Overlord_StalfosTrapTriggerWindow Overlord17_PotTrap
+Overlord_ZoroFactory Overlord16_ZoroSpawner
+Overlord_WizzrobeFactory Overlord15_WizzrobeSpawner
+Overlord_FlyingTileFactory Overlord14_TileRoom
+Overlord_SpawnFlyingTile TileRoom_SpawnTile
+Overlord_PirogusuFactory Overlord10_PirogusuSpawner_left
+Overlord_CrumbleTilePath Overlord0A_FallingSquare
+CrumbleTilePath_SpawnCrumbleTileGarnish SpawnFallingTile
+Overlord_WallMasterFactory Overlord09_WallmasterSpawner
+Overlord_ZolFactory Overlord08_BlobSpawner
+Overlord_MovingFloor Overlord07_MovingFloor
+Overlord_StalfosFactory_Unused Overlord04_Unused
+Sprite_PlayDropSfx Sprite_Overlord_PlayFallingSfx
+Overlord_StalfosTrap Overlord05_FallingStalfos
+Overlord_SnakeTrap Overlord06_BadSwitchSnake
+Overlord_AllDirectionMetalBallFactory Overlord02_FullRoomCannons
+Overlord_CascadeMetalBallFactory Overlord03_VerticalCannon
+Overlord_SpawnMetalBall Overlord_SpawnCannonBall
+Overlord_SpritePositionTarget Overlord01_PositionTarget
+SpawnCrazyVillageSoldier Snitch_SpawnGuard
+Overlord_CheckInRangeStatus Overlord_CheckIfActive
+Sprite_SetDungeonSpriteDeathFlag Sprite_ManuallySetDeathFlagUW
+Dungeon_LoadSprite Dungeon_LoadSingleSprite
+Dungeon_LoadOverlord Dungeon_LoadSingleOverlord
+Sprite_OverworldReloadAll Sprite_ReloadAll_Overworld
+LoadOverworldSprites_A Overworld_LoadSprites
+LoadOverworldSprites_B Sprite_ActivateAllProxima
+Sprite_RangeBasedActivation Sprite_ProximityActivation
+Sprite_RangeBasedActivation_Func1 Sprite_ActivateWhenProximal
+Sprite_RangeBasedActivation_Func2 Sprite_ActivateWhenProximalBig
+Sprite_RangeBasedActivation_Func3 Sprite_Overworld_ProximityMotivatedLoad
+Overworld_LoadSpritesInBlk Overworld_LoadProximaSpriteIfAlive
+Overworld_LoadSpriteOrOverlord Overworld_LoadSingleSprite
+Overworld_LoadOverlord Overworld_LoadSingleOverlord
+SpriteExplode_Main SpriteModule_Explode
+Sprite_SchedulePeersForDeath Sprite_KillFriends
+Garnish_ScatterDebris Garnish16_ThrownItemDebris
+Sprite_SelfTerminate Sprite_KillSelf
+Module_Death Module12_GameOver
+Death_Func0 GameOver_AdvanceImmediately
+Death_Func2 GameOver_DelayBeforeIris
+Death_Func3 GameOver_IrisWipe
+Death_Func5 GameOver_SplatAndFade
+Death_Func7 Animate_GAMEOVER_Letters_bounce
+Death_ShowSaveOptionsMenu GameOver_Finalize_GAMEOVR
+Death_Func9 GameOver_SaveAndOrContinue
+Death_AddSomeSprite GameOver_AnimateChoiceFairy
+Death_Func10 GameOver_InitializeRevivalFairy
+Death_Func11 RevivalFairy_Main_bounce
+Death_Func12 GameOver_RiseALittle
+Death_Func13 GameOver_Restore0D
+Death_Func14 GameOver_Restore0E
+Death_RestoreScreenPostRevival GameOver_ResituateLink
+Module_Quit Module17_SaveAndQuit
+Polyhedral_InitThread Polyhedral_InitializeThread
+Polyhedral_Thread_Main Polyhedral_RunThread
+Poly_LoadFromLut Polyhedral_SetShapePointer
+Poly_GetSinCos Polyhedral_SetRotationMatrix
+Poly_ComputeXY Polyhedral_OperateRotation
+Poly_ComputeF Polyhedral_RotatePoint
+Poly_DivideF2 Polyhedral_ProjectPoint
+Poly_DrawAll Polyhedral_DrawPolyhedron
+Poly_SetColor_Front Polyhedral_SetForegroundColor
+Poly_Check_Ordering Polyhedral_CalculateCrossProduct
+Poly_SetRasterColor Polyhedral_SetColorMask
+Poly_ClearBuf Polyhedral_EmptyBitMapBuffer
+Poly_Rasterize_Polygon Polyhedral_DrawFace
+Poly_Rasterize_Line Polyhedral_FillLine
+Poly_Raster_NextX0 Polyhedral_SetLeft
+Poly_Raster_NextX1 Polyhedral_SetRight
+Messaging_BirdTravel Module0E_0A_FluteMenu
+BirdTravel_InitGfx FluteMenu_LoadMap
+BirdTravel_InitCounter FluteMenu_AdvanceMode
+BirdTravel_Main FluteMenu_HandleSelection
+BirdTravel_LoadTargetArea FluteMenu_LoadSelectedScreen
+BirdTravel_LoadAmbientOverlay Overworld_LoadOverlayAndMap
+BirdTravel_Finish FluteMenu_FadeInAndQuack
+OverworldMap_Backup WorldMap_FadeOut
+OverworldMap_InitGfx WorldMap_LoadLightWorldMap
+OverworldMap_DarkWorldTilemap WorldMap_LoadDarkWorldMap
+OverworldMap_LoadSprGfx WorldMap_LoadSpriteGFX
+OverworldMap_BrightenScreen WorldMap_Brighten
+OverworldMap_Main WorldMap_PlayerControl
+OverworldMap_PrepExit WorldMap_RestoreGraphics
+OverworldMap_SetRegsForExit Attract_SetUpConclusionHDMA
+OverworldMap_RestoreGfx WorldMap_ExitMap
+ConfigureHdmaForMapMode WorldMap_SetUpHDMA
+ClearMode7Tilemap WorldMap_FillTilemapWithEF
+OverworldMap_AddSprites WorldMap_HandleSprites
+OverworldMap_GetCoords WorldMap_CalculateOamCoordinates
+OverworldMap_AddObj WorldMap_HandleSpriteBlink
+Multiply_8bit WorldMap_MultiplyAxB
+Shift_4_times WorldMap_ShiftNibblesRight
+OverworldMap_SubtractXY4 WorldMapIcon_AdjustCoordinate
+OverworldMap_CheckPendant OverworldMap_CheckForPendant
+OverworldMap_CheckCrystal OverworldMap_CheckForCrystal
+Messaging_DungMap Module0E_03_DungeonMap
+DungMap_Init Module0E_03_01_DrawMap
+DungMap_Init0_SetupGraphics Module0E_03_01_00_PrepMapGraphics
+DungMap_Init1_OptionalGraphic Module0E_03_01_01_DrawLEVEL
+DungMap_Init2 Module0E_03_01_02_DrawFloorsBackdrop
+DungMap_Init2_Helper DungeonMap_BuildFloorListBoxes
+DungMap_Init3 Module0E_03_01_03_DrawRooms
+DungMap_Init3A DungeonMap_DrawBorderForRooms
+DungMap_Init3B DungeonMap_DrawFloorNumbersByRoom
+DungMap_Init3C DungeonMap_DrawDungeonLayout
+DungMap_Init3D DungeonMap_DrawSingleRowOfRooms
+DungMap_Init4 DungeonMap_DrawRoomMarkers
+DungMap_State3 DungeonMap_HandleInputAndSprites
+DungMap_Func1 DungeonMap_HandleInput
+DungMap_Func3 DungeonMap_HandleMovementInput
+DungMap_Func4 DungeonMap_HandleFloorSelect
+DungMap_Func5 DungeonMap_ScrollFloors
+DungMap_Func2 DungeonMap_DrawSprites
+DungMap_DrawPlayerFloorIndicator DungeonMap_DrawLinkPointing
+DungMap_Func6 DungeonMap_DrawBlinkingIndicator
+DungMap_Func7 DungeonMap_DrawLocationMarker
+DungMap_Func8 DungeonMap_DrawFloorNumberObjects
+DungMap_Func9 DungeonMap_DrawFloorBlinker
+DungMap_Func10 DungeonMap_DrawBossIcon
+DungMap_DrawBossFloorIndicator DungeonMap_DrawBossIconByFloor
+DungMap_State4 Module0E_03_04_UnusedCrazyScroll
+DungMap_RestoreGraphics DungeonMap_RecoverGFX
+DungMap_RestoreStarTileState ToggleStarTilesAndAdvance
+Dungeon_Effect_Handler Dungeon_HandleLayerEffect
+Effect_DoNothing LayerEffect_Nothing
+Effect_MovingFloor LayerEffect_Scroll
+Effect_MovingFloor2 LayerEffect_Trinexx
+Effect_RedFlashes LayerEffect_Agahnim2
+Effect_TorchHiddenTiles LayerEffect_InvisibleFloor
+Effect_TorchGanonRoom LayerEffect_Ganon
+Effect_MovingWater LayerEffect_WaterRapids
+Overworld_SetFixedColorsAndScroll Overworld_SetFixedColAndScroll
+Player_ResetSomeStuff2 ResetSomeThingsAfterDeath
+sub_8BFFEE ResetAncillaAndLink
+Module_Intro Module00_Intro
+Intro_InitWram Intro_Clear1kbBlocksOfWRAM
+Intro_LoadTitleGraphics Intro_InitializeMemory_darken
+Intro_ShowPlayerSelect FadeMusicAndResetSRAMMirror
+Intro_InitGfxAndSprites Intro_InitializeTriforcePolyThread
+Polyhedral_SetPalette LoadTriforceSpritePalette
+Intro_TopAnimateObjs Intro_HandleAllTriforceAnimations
+Intro_AnimObjs Scene_AnimateEverySprite
+Intro_CheckRunStep Intro_AnimateTriforce
+CopyIntroSprite0ToOam AnimateSceneSprite_DrawTriangle
+Intro_SpriteType_A_1 EXIT_0CCA90
+Intro_SpriteType_A_2 InitializeSceneSprite_Copyright
+Intro_SpriteType_B_2_NintendoCopy AnimateSceneSprite_Copyright
+Intro_SpriteType_A_3 InitializeSceneSprite_Sparkle
+Intro_SpriteType_B_3 AnimateSceneSprite_Sparkle
+IntroSprite3_Periodic AnimateSceneSprite_DrawSparkle
+CopyIntroSpritesToOam AnimateSceneSprite_AddObjectsToOamBuffer
+Intro_MoveObjectWithVel AnimateSceneSprite_MoveTriangle
+TriforceRoom_LoadSprites TriforceRoom_PrepGFXSlotForPoly
+Ending_Func8 Credits_InitializePolyhedral
+TriforceRoom_AnimObjs AdvancePolyhedral
+TriforceRoom_HandlePoly_Case0 IntroPolyhedral_StartUp
+TriforceRoom_HandlePoly_Case2 IntroPolyhedral_MoveRotate
+TriforceRoom_HandlePoly_Case3 IntroPolyhedral_LockIntoPlace
+Ending_Func10 Credits_AnimateTheTriangles
+Ending_Func10_Inner CreditsTriangle_HandleRotation
+Ending_Func10_Inner2 CreditsTriangle_ApplyRotation
+Intro_SpriteType_A_456 InitializeSceneSprite_TriforceRoomTriangle
+IntroSpriteTypeB_456_Helper AnimateTriforceRoomTriangle_HandleContracting
+Intro_SpriteType_A_7 InitializeSceneSprite_CreditsTriangle
+Intro_SpriteType_B_7 AnimateSceneSprite_CreditsTriangle
+Module_SelectFile Module01_FileSelect
+Module_SelectFile_1 FileSelect_ReInitSaveFlagsAndEraseTriforce
+Module_EraseFile_0 FileSelect_EraseTriforce
+Module_SelectFile_3 FileSelect_TriggerStripesAndAdvance
+Module_SelectFile_4 FileSelect_TriggerNameStripesAndAdvance
+Module_SelectFile_5 FileSelect_Main
+sub_8CCEC7 FileSelect_SetUpNamesStripes
+Death_RestoreFromSrm CopySaveToWRAM
+Module_CopyFile Module02_CopyFile
+Module_CopyFile_3 CopyFile_ChooseSelection
+Module_CopyFile_4 CopyFile_ChooseTarget
+Module_CopyFile_5 CopyFile_ConfirmSelection
+sub_8CD0C6 FilePicker_DeleteHeaderStripe
+sub_8CD13F CopyFile_SelectionAndBlinker
+sub_8CD22D ReturnToFileSelect
+sub_8CD27B CopyFile_TargetSelectionAndBlink
+sub_8CD371 CopyFile_HandleConfirmation
+sub_8CD3DC CopyFile_CopyData
+Module_EraseFile Module03_KILLFile
+Module_EraseFile_2 KILLFile_SetUp
+Module_EraseFile_3 KILLFile_HandleSelection
+Module_EraseFile_4 KILLFile_HandleConfirmation
+sub_8CD4BA KILLFile_ChooseTarget
+SelectFile_DrawFaerie FileSelect_DrawFairy
+Module_NamePlayer Module04_NameFile
+sub_8CD89C NameFile_EraseSave
+sub_8CDA4D NameFile_DoTheNaming
+sub_8CDC8C NameFile_CheckForScrollInputX
+sub_8CDCBF NameFile_CheckForScrollInputY
+sub_8CDD30 NameFile_DrawSelectedCharacter
+Module_Attract Module14_Attract
+Attract_SlowBrigthenSetFlag Attract_FadeInStep
+Attract_SlowBrighten Attract_FadeInSequence
+Attract_SlowFadeToBlank Attract_FadeOutSequence
+Attract_PrepNextSequence Attract_LoadNewScene
+Attract_PrepLegend AttractScene_PolkaDots
+Attract_PrepMapZoom AttractScene_WorldMap
+Attract_PrepThroneRoom AttractScene_ThroneRoom
+Attract_PrepLast AttractScene_EndOfStory
+Attract_RunSequence Attract_EnactStory
+Attract_Legend AttractDramatize_PolkaDots
+Attract_MapZoom AttractDramatize_WorldMap
+Attract_ZeldaPrison AttractDramatize_Prison
+Attract_AdvanceToNextSequence Dramaghanim_AdvanceStory
+Attract_MaidenWarp AttractDramatize_AgahnimAltar
+Attract_Exit Attract_SkipToFileSelect
+Attract_LoadNextLegendGraphic Attract_BuildNextImageTileMap
+Attract_AdjustMapZoom Attract_ControlMapZoom
+Attract_InitGraphics_Helper3 Attract_BuildBackgrounds
+sub_8CF879 Attract_TriggerBGDMA
+Attract_DrawSpriteSet Attract_DrawPreloadedSprite
+Atract_DrawZelda Attract_DrawZelda
+sub_8CFA30 Attract_DrawKidnappedMaiden
+Attract_SetupHdma Attract_SetUpWindowingHDMA
+PlayerOam_Main LinkOam_Main
+PlayerOam_GetHighestSetBit FindMostSignificantBit
+PlayerOam_Main_SwordStuff_DoDma LinkOam_SetWeaponVRAMOffsets
+PlayerOam_ShieldStuff LinkOam_SetEquipmentVRAMOffsets
+PlayerOam_DrawTipOfBetterSword LinkOam_CalculateSwordSparklePosition
+PlayerOam_DrawOam_Throwing LinkOam_UnusedWeaponSettings
+PlayerOam_DrawOam_2 LinkOam_DrawDungeonFallShadow
+PlayerOam_DrawGrassOrWater LinkOam_DrawFootObject
+PlayerOam_Unused_0 UNREACHABLE_0DAFA6
+PlayerOam_GetRelativeHighBit LinkOam_CalculateXOffsetRelativeLink
+Sprite_LoadProperties SpritePrep_LoadProperties
+Sprite_LoadPalette SpritePrep_LoadPalette
+Sprite_ResetProperties SpritePrep_ResetProperties
+GetRandomInt GetRandomNumber
+OAM_AllocateFromRegionA Oam_AllocateFromRegionA
+OAM_AllocateFromRegionB Oam_AllocateFromRegionB
+OAM_AllocateFromRegionC Oam_AllocateFromRegionC
+OAM_AllocateFromRegionD Oam_AllocateFromRegionD
+OAM_AllocateFromRegionE Oam_AllocateFromRegionE
+OAM_AllocateFromRegionF Oam_AllocateFromRegionF
+OAM_GetBufferPosition Oam_GetBufferPosition
+Ancilla_GetPanFlag Ancilla_CalculateSfxPan
+Sound_GetPanForPlayer Link_CalculateSfxPan
+Sound_SetSfx1Pan SpriteSfx_QueueSfx1WithPan
+Sound_SetSfx2Pan SpriteSfx_QueueSfx2WithPan
+Sound_SetSfx3Pan SpriteSfx_QueueSfx3WithPan
+Sound_AddSfxPan SpriteSfx_ApplyPanning
+Sprite_GetSfxPan Sprite_CalculateSfxPan
+Sound_GetPanForX CalculateSfxPan
+LightTorch_GetSfxPan CalculateSfxPan_Arbitrary
+sub_8DC217 SpriteDontDraw_Stalfos
+Soldier_CheckTileSolidity Probe_CheckTileSolidity
+Sprite_HumanMulti_1_Long Sprite_29_Adult
+Sprite_BlindHideoutGuy Sprite_BlindsHutGuy
+Sprite_FluteBoyFather Sprite_FluteDad
+Sprite_SweepingLadyLong Sprite_2A_SweepingLady
+Sprite_LumberjacksLong Sprite_2C_Lumberjacks
+Lumberjacks_CheckProximity Lumberjack_CheckProximity
+Sprite_UnusedTelepathLong Sprite_2D_TelepathicTile
+Sprite_FortuneTellerLong Sprite_31_FortuneTeller
+Sprite_DwarfSolidity Sprite_SmithyBlockade
+FortuneTeller_Main FortuneTeller
+LW_FortuneTeller_WaitForInquiry FortuneTeller_LightWorld_PrecognizantResponse
+LW_FortuneTeller_AskIfPlayerWantsReading FortuneTeller_LightWorld_OfferReading
+FortuneTeller_GiveReading FortuneTeller_PerformPseudoScience
+FortuneTeller_PopulateNextMessageSlot FortuneTeller_PrepareNextMessage
+LW_FortuneTeller_ShowCostMessage FortuneTeller_LightWorld_DemandPayment
+LW_FortuneTeller_DeductPayment FortuneTeller_LightWorld_TakeMoney
+DW_FortuneTeller_WaitForInquiry FortuneTeller_DarkWorld_PrecognizantResponse
+DW_FortuneTeller_AskIfPlayerWantsReading FortuneTeller_DarkWorld_OfferReading
+DW_FortuneTeller_ShowCostMessage FortuneTeller_DarkWorld_DemandPayment
+sub_8DCA2D FortuneTeller_DemandPayment
+DW_FortuneTeller_DeductPayment FortuneTeller_DarkWorld_TakeMoney
+Dwarf_SpawnDwarfSolidity Smithy_SpawnDumbBarrierSprite
+Sprite_MazeGameLadyLong Sprite_2F_RaceGameLady
+MazeGameLady_Startup RaceGameLady_Idle
+MazeGameLady_AccumulateTime RaceGameLady_TimeRun
+MazeGameLady_PlayStartingNoise RaceGameLady_FireStarterPistol
+Sprite_MazeGameGuyLong Sprite_30_RaceGameGuy
+MazeGameGuy_ParseElapsedTime RaceGameGuy_VerifyRun
+MazeGameGuy_CheckPlayerQualification RaceGameGuy_MakeModDecision
+MazeGameGuy_SorryCantHaveIt RaceGameGuy_RejectRun
+MazeGameGuy_YouCanHaveIt RaceGameGuy_IdleInDiscord
+BomberPellet_DrawExplosion SpriteDraw_ZirroBomb
+GoodBee_AttackOtherSprite PlayerBee_HoneInOnTarget
+Pikit_DrawTongue SpriteDraw_Pikit_Tongue
+Pikit_MultiplicationDelay Three_NOP
+Pikit_DrawGrabbedItem SpriteDraw_Pikit_Loot
+CheckPalaceItemPossession ItemMenu_CheckForDungeonPrize
+Module_EndSequence Module1A_Credits
+EndSequence_0 Credits_LoadNextScene_Overworld
+EndSequence_2 Credits_LoadNextScene_Dungeon
+EndSequence_ResetSprites Credits_PrepAndLoadSprites
+EndSequence_1 Credits_ScrollScene_Overworld
+EndSequence_3 Credits_ScrollScene_Dungeon
+EndSequence_1_3_Common Credits_HandleSceneFade
+Ending_InitSprites_6 Credits_LoadSprites_Zora
+Ending_InitSprites_10 Credits_LoadSprites_Venus
+EndSequence1_Case0 Credits_SpriteDraw_Castle
+EndSequence1_Case4 Credits_SpriteDraw_Hera
+EndSequence1_Case2 Credits_SpriteDraw_Kakariko1
+EndSequence1_Case5 Credits_SpriteDraw_House
+EndSequence1_Case13 Credits_SpriteDraw_DeathMountain
+EndSequence1_Case8 Credits_SpriteDraw_Lumberjacks
+EndSequence1_Case10 Credits_SpriteDraw_Venus
+EndSequence1_Case12 Credits_SpriteDraw_Kakariko2
+EndSequence_DrawShadow Credits_SpriteDraw_DrawShadow
+Ending_Func2_0x30 Credits_SpriteDraw_AnimateRunningKidAndLocksmith
+Ending_Func4_8 Credits_SpriteDraw_ActivateAndRunSprite_allocate8
+Ending_Func4 Credits_SpriteDraw_ActivateAndRunSprite
+EndSequence_CallMainFunc_8 Credits_SpriteDraw_PreexistingSpriteDraw_eight
+EndSequence_CallMainFunc Credits_SpriteDraw_PreexistingSpriteDraw
+EndSequence_DrawStuff Credits_SpriteDraw_Single
+EndSequence1_Case6 Credits_SpriteDraw_Zora
+EndSequence1_Case11 Credits_SpriteDraw_Smithy
+sub_8EA8C8 Credits_SpriteDraw_DrawSmithSpark
+EndSequence1_Case3 Credits_SpriteDraw_Desert
+EndSequence1_Case1 Credits_SpriteDraw_Sanctuary
+EndSequence1_Case7 Credits_SpriteDraw_Witch
+EndSequence1_Case9 Credits_SpriteDraw_Grove
+EndSequence1_Case14 Credits_SpriteDraw_LostWoods
+EndSequence_SetFlags2 Credits_SpriteDraw_SetShadowProp
+Ending_Func3 Credits_SpriteDraw_AddSparkle
+EndSequence1_Case15 Credits_SpriteDraw_Pedestal
+Ending_Func6 Credits_SpriteDraw_WalkLinkAwayFromPedestal
+Ending_Func5 Credits_SpriteDraw_MoveSquirrel
+Ending_MoveSprite_Func1 Credits_SpriteDraw_CirclingBirds
+EndSequence1_ScrollMap Credits_HandleCameraScrollControl
+EndSequence1_ScrollMap_Inner Credits_SingleCameraScrollControl
+Ending_Func11 Credits_FadeOutFixedCol
+EndSequence_34 Credits_FadeColorAndBeginAnimating
+Ending_DrawCredits Credits_AddNextAttribution
+EndSequence0and2_CopyToVram Credits_AddEndingSequenceText
+EndSequence_33 Credits_BrightenTriangles
+EndSequence_35 Credits_StopCreditsScroll
+EndSequence_36 Credits_FadeAndDisperseTriangles
+EndSequence_37 Credits_FadeInTheEnd
+EndSequence_38 Credits_HangForever
+Messaging_Text RenderText
+Text_PostDeathSaveOptions RenderText_PostDeathSaveOptions
+Text_Command RenderText_ExtendedCommand
+Text_IgnoreCommand RenderText_ExtendedCommand_IgnoreCommand
+Text_IgnoreParamCommand RenderText_ExtendedCommand_IgnoreParameter
+Text_SetWindowType RenderText_ExtendedCommand_SetWindowType
+Text_SetWindowPos RenderText_ExtendedCommand_SetWindowPosition
+Text_DrawBorder RenderText_Draw_Border
+Text_DrawBorderIncremenal RenderText_Draw_BorderIncremental
+Text_DrawFirstBorderRow RenderText_Draw_BorderIncremental_Top
+Text_DrawMiddleBorderRow RenderText_Draw_BorderIncremental_Middle
+Text_DrawBottomBorderRow RenderText_Draw_BorderIncremental_Bottom
+Text_CharacterTilemap RenderText_Draw_CharacterTilemap
+Text_MessageHandler RenderText_Draw_MessageCharacters
+VWF_CharacterOrCommand RenderText_Draw_HandleNext
+Text_Close RenderText_Draw_Finish
+VWF_Render RenderText_Draw_RenderCharacter
+VWF_RenderRecursive RenderText_Draw_RenderCharacter_All
+sub_8ECCF9 RenderText_Draw_RenderCharacter_ReduceSpeed
+VWF_NextPicture RenderText_Draw_NextImage
+VWF_Select2Or3_Indented RenderText_Draw_Choose2LowOr3
+VWF_SelectItem RenderText_Draw_ChooseItem
+VWF_SelectPrevItem RenderText_FindYItem_Previous
+VWF_SelectNextItem RenderText_FindYItem_Next
+VWF_ChangeItemTiles RenderText_DrawSelectedYItem
+VWF_IgnoreCommand RenderText_Draw_Ignore
+VWF_Choose3 RenderText_Draw_Choose3
+VWF_Choose1Or2 RenderText_Draw_Choose1Or2
+VWF_Scroll RenderText_Draw_Scroll
+VWF_SetPalette RenderText_Draw_SetColor
+VWF_Wait RenderText_Draw_Wait
+VWF_WaitLoop_initCounter RenderText_Draw_Wait_Init
+VWF_EndWait RenderText_Draw_Wait_End
+VWF_PlaySound RenderText_Draw_PlaySfx
+VWF_SetSpeed RenderText_Draw_SetSpeed
+VWF_Command7B RenderText_Draw_Command7B
+VWF_Command7C RenderText_Draw_ABunchOfSpaces
+VWF_ClearBuffer RenderText_Draw_EmptyBuffer
+VWF_WaitKey RenderText_Draw_PauseForInput
+VWF_EndMessage RenderText_Draw_Terminate
+Text_SetDefaultWindowPos RenderText_SetDefaultWindowPosition
+Text_InitBorderOffsets RenderText_DrawBorderInitialize
+Text_DrawBorderRow RenderText_DrawBorderRow
+Text_DrawCharacterTilemap RenderText_Refresh
+Sprite_WaterfallLong Sprite_37_Waterfall
+Waterfall_Main Waterfall
+Sprite_RetreatBat Sprite_BatCrash
+RetreatBat_State0 BatCrash_Approach
+RetreatBat_State1 BatCrash_Ascend
+RetreatBat_State2 BatCrash_DiveBomb
+RetreatBat_FinishUp BatCrash_StallTheInevitable
+GanonEmerges_SpawnRetreatBat Sprite_SpawnBatCrashCutscene
+RetreatBat_DrawSomethingElse BatCrash_DrawHardcodedGarbage
+RetreatBat_SpawnPyramidDebris BatCrash_SpawnDebris
+Cukeman_Unused UNREACHABLE_1AF9E6
+RunningMan_SpawnDashDustGarnish RunningBoy_SpawnDustGarnish
+Sprite_MovableMantle Sprite_EE_CastleMantle
+Mothula_Draw_0 SpriteDraw_Mothula
+BottleVendor_PayForGoodBee BottleMerchant_BuyBee
+Item_Hammer_SpawnWater SpawnHammerWaterSplash
+Overworld_Hole Overworld_GetPitDestination
+Overworld_Entrance Overworld_UseEntrance
+ToolAndTileInteraction HandleItemTileAction_Overworld
+Overworld_HammerSfx Overworld_PickHammerSfx
+Overworld_LiftableTiles Overworld_HandleLiftableTiles
+Overworld_HandleBigRock SmashRockPile_fromLift
+Overworld_ApplyBombToTiles Overworld_BombTiles32x32
+Overworld_ApplyBombToTile Overworld_BombTile
+Overworld_AlterGargoyleEntrance OpenGargoylesDomain
+Overworld_CreatePyramidHole CreatePyramidHole
+Overworld_RevealSecret_CheckPowder AdjustSecretForPowder
+Overworld_DrawPersistentMap16 Overworld_DrawMap16_Persist
+Overworld_DrawMap16_Alt Overworld_AlterTileHardcore
+RemapTileAddrToVram Overworld_FindMap16VRAMAddress
+Overworld_DrawWarpTile Overworld_CreateTRPortal
+Overworld_PlayEntranceSequence Overworld_AnimateEntrance
+DarkPalaceEntrance_Main Overworld_AnimateEntrance_PoD
+Overworld_EntranceSequence_Func0_0 AnimateEntrance_PoD_step1
+Overworld_EntranceSequence_Func0_1 AnimateEntrance_PoD_step2
+Overworld_EntranceSequence_Func0_2 AnimateEntrance_PoD_step3
+Overworld_EntranceSequence_Func0_3 AnimateEntrance_PoD_step4
+Overworld_EntranceSequence_Func0_4 AnimateEntrance_PoD_step5
+Overworld_EntranceSequence_Func1 Overworld_AnimateEntrance_Skull
+Overworld_EntranceSequence_Func1_0 AnimateEntrance_Skull_step1
+Overworld_EntranceSequence_Func1_1 AnimateEntrance_Skull_step2
+Overworld_EntranceSequence_Func1_2 AnimateEntrance_Skull_step3
+Overworld_EntranceSequence_Func1_3 AnimateEntrance_Skull_step4
+Overworld_EntranceSequence_Func1_4 AnimateEntrance_Skull_step5
+MiseryMireEntrance_Main Overworld_AnimateEntrance_Mire
+MiseryMireEntrance_Main_Case0 AnimateEntrance_Mire_step1
+MiseryMireEntrance_Main_Case12 AnimateEntrance_Mire_step2
+MiseryMireEntrance_Main_Case3 AnimateEntrance_Mire_step3
+MiseryMireEntrance_Main_Case4 AnimateEntrance_Mire_step4
+MiseryMireEntrance_Main_Case5 AnimateEntrance_Mire_step5
+TurtleRockEntrance_Main Overworld_AnimateEntrance_TurtleRock
+Overworld_EntranceSequence_Func3_0 AnimateEntrance_TurtleRock_step1
+Overworld_EntranceSequence_Func3_4 AnimateEntrance_TurtleRock_step5
+Overworld_EntranceSequence_Func3_5 AnimateEntrance_TurtleRock_step6
+Overworld_EntranceSequence_Func3_6 AnimateEntrance_TurtleRock_step7
+Overworld_EntranceSequence_Func3_7 AnimateEntrance_TurtleRock_step8
+EntranceSequence_Finish OverworldEntrance_PlayJingle
+TurtleRockEntrance_Draw1 OverworldEntrance_DrawManyTR
+GanonTowerEntrance_Main Overworld_AnimateEntrance_GanonsTower
+Overworld_EntranceSequence_Func4_0 AnimateEntrance_GanonsTower_step01
+Overworld_EntranceSequence_Func4_2 AnimateEntrance_GanonsTower_step02
+EntranceSequence_Reset OverworldEntrance_AdvanceAndBoom
+Overworld_EntranceSequence_Func4_3 AnimateEntrance_GanonsTower_step03
+Overworld_EntranceSequence_Func4_4 AnimateEntrance_GanonsTower_step04
+Overworld_EntranceSequence_Func4_5 AnimateEntrance_GanonsTower_step05
+Overworld_EntranceSequence_Func4_6 AnimateEntrance_GanonsTower_step06
+Overworld_EntranceSequence_Func4_7 AnimateEntrance_GanonsTower_step07
+Overworld_EntranceSequence_Func4_8 AnimateEntrance_GanonsTower_step08
+Overworld_EntranceSequence_Func4_9 AnimateEntrance_GanonsTower_step09
+Overworld_EntranceSequence_Func4_10 AnimateEntrance_GanonsTower_step10
+Overworld_EntranceSequence_Func4_11 AnimateEntrance_GanonsTower_step11
+Overworld_EntranceSequence_Func4_12 AnimateEntrance_GanonsTower_step12
+Palette_SpriteAux3 Palette_Load_SpritePal0Left
+Palette_MainSpr Palette_Load_SpriteMain
+Palette_SpriteAux1 Palette_Load_SpriteAux1
+Palette_SpriteAux2 Palette_Load_SpriteAux2
+Palette_Sword Palette_Load_Sword
+Palette_Shield Palette_Load_Shield
+Palette_Unused UNREACHABLE_1BED4F
+Palette_MiscSprite Palette_Load_SpriteEnvironment
+Palette_MiscSprite_Indoors Palette_Load_SpriteEnvironment_Dungeon
+Palette_PalaceMapSpr Palette_Load_DungeonMapSprite
+Palette_ArmorAndGloves Palette_Load_LinkArmorAndGloves
+Palette_PalaceMapBg Palette_Load_DungeonMapBG
+Palette_Hud Palette_Load_HUD
+Palette_DungBgMain Palette_Load_DungeonSet
+Palette_OverworldBgAux3 Palette_Load_OWBG3
+Palette_OverworldBgMain Palette_Load_OWBGMain
+Palette_OverworldBgAux1 Palette_Load_OWBG1
+Palette_OverworldBgAux2 Palette_Load_OWBG2
+Palette_SingleLoad Palette_LoadSingle
+Palette_MultiLoad Palette_LoadMultiple
+Palette_ArbitraryLoad Palette_LoadMultiple_Arbitrary
+Palette_SelectScreen Palette_LoadForFileSelect
+Palette_SelectScreenArmor Palette_LoadForFileSelect_Armor
+Palette_SelectScreenSword Palette_LoadForFileSelect_Sword
+Palette_SelectScreenShield Palette_LoadForFileSelect_Shield
+Palette_AgahnimClones Palette_LoadAgahnim
+Sprite_ApplyConveyorAdjustment Sprite_ApplyConveyor
+Ancilla_CreateDeflectedArrow Sprite_CreateDeflectedArrow
+Sprite_Landmine Sprite_D4_Landmine
+Sprite_Stal Sprite_D3_Stal
+Sprite_Fish Sprite_D2_FloppingFish
+Fish_Wriggle FloppingFish_WriggleInHands
+Fish_PauseBeforeLeap FloppingFish_PrepareLeap
+Sprite_SpawnSmallWaterSplash Sprite_FloppingFish_SpawnSplash
+Fish_Leaping FloppingFish_Leap
+Fish_PreliminaryDeepWaterCheck FloppingFish_CheckForWaterInit
+Fish_FlopAround FloppingFish_Flop
+sub_9D847E DontDrawFloppingFish
+Sprite_ChimneyAndRabbitBeam Sprite_D1_BunnyBeam
+Sprite_RabbitBeam Sprite_BunnyBeam
+Sprite_Lynel Sprite_D0_Lynel
+Lynel_TargetPlayer Lynel_TargetLink
+Lynel_Attack Lynel_Fire
+Trident_PlaySfx SwishEvery16Frames
+Sprite_Trident Sprite_GanonTrident
+Sprite_FlameTrailBat Sprite_FireBat_Trailer
+FireBat_Common FireBat_Move
+Sprite4_Load_16bit_AuxCoord Sprite_AdjustAuxCoords_bank1D
+Sprite_FireBat Sprite_FireBat_Launched
+FireBat_Func1 GetPositionRelativeToTheGreatOverlordGanon
+FireBat_Case0 FireBat_PositionSelfAndAnimateAndPrepareForLaunch
+FireBat_Case1 FireBat_PositionSelfAndAnimate
+FireBat_Func2 FireBat_Animate
+FireBat_Case2 FireBat_LaunchedFlying
+Ganon_CheckEntityProximity Ganon_AttemptTridentCatch
+Ganon_Initialize SpritePrep_Ganon_PrepareBattle
+Ganon_Func5_Math Ganon_HandleFireBatCircle
+MathDelay Six_NOP
+Ganon_SpawnSomething Ganon_SpawnSpiralBat
+Sprite_Ganon Sprite_D6_Ganon
+Ganon_State19 Ganon_Phase4_Stunned
+Ganon_State17 Ganon_Phase4_Attack
+Ganon_ResetSomething Ganon_EnableInvincibility
+Ganon_State15 Ganon_Phase3_SmashFloor
+Ganon_State16 Ganon_Phase3_DropTiles
+Ganon_SpawnOverlord Ganon_SpawnFallingTilesOverlord
+Ganon_State12 Ganon_Phase3_FireBats
+Ganon_Func1_5 Ganon_SpawnFireBat_trailing
+Ganon_State14 Ganon_Phase3_SabotagePB
+Ganon_State07 Ganon_Phase2_CircleOfBats
+Ganon_State08 Ganon_Phase2_LaunchSpiralBats
+Ganon_State09 Ganon_Phase2_Warp
+Ganon_State11 Ganon_Phase2_MakePhaseDecision
+Ganon_State00 Ganon_Phase1_IntroduceSelf
+Ganon_State01 Ganon_Phase1_ThrowTrident
+Ganon_Func2 Ganon_Phase1_AnimateTridentSpin
+Ganon_State02 Ganon_Phase1_WaitForTrident
+Ganon_State03 Ganon_Phase1_MakePhaseDecision
+Ganon_SetGfx Ganon_HandleAnimation_Idle
+Ganon_State04 Ganon_Phase1_Warp
+Ganon_Func3 Ganon_SelectWarpLocation
+Ganon_Func4 Ganon_ShakeHead
+Ganon_State13 Ganon_Phase3_Warp
+Ganon_State05_10_18 Ganon_LookAround
+Ganon_State06 Ganon_Phase2_HoldTrident
+Swamola_InitSegments SpritePrep_Swamola_InitializeSegments
+Sprite_Swamola Sprite_CF_Swamola
+Swamola_Ascending Swamola_Ascend
+Sprite_AdjustVelTowards Sprite_Swamola_ApproachTargetVelocity
+Swamola_WiggleTowardsTarget Swamola_Wiggle
+Swamola_PursueTargetCoord Swamola_ProjectVelocityTowardsTarget
+Swamola_Descending Swamola_Descend
+Sprite_SwamolaRipples Sprite_Swamola_Ripples
+Blind_SpawnFromMaidenTagalong Blind_SpawnFromMaiden
+Blind_Initialize SpritePrep_Blind_PrepareBattle
+Sprite_BlindHead Sprite_Blind_Head
+Blind_SpawnExtraHead Blind_SpawnHead
+Sprite_BlindEntities Sprite_CE_Blind
+Sprite_Blind Sprite_Blind_Blind_Blind
+Blind_BehindTheCurtain Blind_Undress
+Blind_FireballReprisal Blind_FireballFlurry
+BlindHead_SpawnFireball Blind_SpitFireball
+Blind_BlindedByTheLight Blind_THELIGHT
+Blind_SpawnPoof SpawnBossPoof
+Blind_RetreatToBackWall Blind_EscapeLight
+Blind_OscillateAlongWall Blind_Shimmy
+Blind_SwitchWalls Blind_SwapSides
+Blind_WhirlAround Blind_Spin
+Blind_AnimateSetGfx Blind_AnimateRobes
+TrinexxComponents_InitializeLong Trinexx_Initialize
+TrinexxHead_Initialize Trinexx_Initialize_Rock
+TrinexxPartA_Initialize Trinexx_Initialize_Fire
+Trinexx_StoreCoords Trinexx_CachePosition
+Sprite_TrinexxD Sprite_Trinexx_FinalPhase
+Sprite_TrinexxD_Case0 Sprite_Trinexx_Phase2_SnekAlongWall
+Trinexx_Unused Trinexx_CircleLink
+Sprite_TrinexxD_Case1 Sprite_Trinexx_Phase2_SnekAfterLink
+Sprite_TrinexxD_CheckDmg Sprite_Trinexx_CheckDamageToFlashingSegment
+Sprite_Trinexx Sprite_CB_TrinexxRockHead
+Sprite_Trinexx_State0 Trinexx_ChooseNextAction
+Sprite_Trinexx_State1 Trinexx_MoveBody
+Sprite_Trinexx_State2 Trinexx_PrepareLunge
+Sprite_Trinexx_State3 Trinexx_LungeHead
+Trinexx_Func3 Trinexx_WagTail
+Trinexx_Func2 Trinexx_HandleShellCollision
+Trinexx_Draw1 SpriteDraw_TrinexxRockHead
+Trinexx_Draw2 SpriteDraw_TrinexxRockHeadAndBody
+Sprite_Trinexx_CC Sprite_CC_TrinexxBreath_FireHead
+Sprite_Trinexx_CD Sprite_CD_TrinexxBreath_IceHead
+Sprite_TrinexxHead Sprite_Sidenexx
+Sprite_CC_State4 Sidenexx_Stunned
+Sprite_CC_State0 Sidenexx_Dormant
+Sprite_CC_State1 Sidenexx_Think
+Sprite_CC_State2 Sidenexx_Move
+Sprite_CC_State3 Sidenexx_Breathe
+Trinexx_Func5 Sidenexx_ExhaleDanger
+Trinexx_Func4 Sidenexx_Explode
+Sprite_CD_Alt Sprite_TrinexxBreath_ice
+Sprite_CC_Alt Sprite_TrinexxBreath_fire
+Sprite_CC_SpawnGarnish Sprite_TrinexxFire_AddFireGarnish
+SpritePrep_ChainChomp SpritePrep_Chainchomp
+Sprite_ChainChomp Sprite_CA_ChainChomp
+ChainChomp_State0 ChainChomp_Idle
+ChainChomp_State1 ChainChomp_Meander
+ChainChomp_State2 ChainChomp_InvertLunge
+ChainChomp_MulStuff ChainChomp_MoveChain
+ChainChomp_CopyToHist ChainChomp_HandleLeash
+Sprite_GanonHelpers Sprite_C9_Tektite
+Tektite_Stationary Tektite_Idle
+Tektite_Aloft Tektite_Midjump
+Tektite_RepeatingHop Tektite_Bouncy
+Sprite_BigFaerieOrCloud Sprite_C8_BigFairy
+Sprite_FaerieCloud Sprite_FairyCloud
+FaerieCloud_SeekPlayer FairyCloud_ApproachLink
+FaerieCloud_AwaitFullPlayerHealth FairyCloud_WaitForHeal
+FaerieCloud_FadeOut FairyCloud_Dissipate
+Sprite_BigFaerie Sprite_BigFairy
+BigFaerie_AwaitClosePlayer BigFairy_WaitForLink
+BigFaerie_Dormant BigFairy_DoAbsolutelyNothing
+Sprite_Hokbok Sprite_C7_Pokey
+Hokbok_ResetBounceVelocity Pokey_ResetBounce
+Hokbok_Moving Pokey_MoveFaster
+Sprite_Medusa Sprite_C5_Medusa
+sub_9DC845 Fireball_Configure
+Sprite_FireballJunction Sprite_C6_4WayShooter
+Sprite_Thief Sprite_C4_Thief
+Thief_WatchPlayer Thief_Watching
+Thief_ChasePlayer Thief_Chasing
+Thief_StealShit Thief_Stealing
+Thief_TrackDownBooty Thief_TargetBooty
+Thief_AttemptBootyGrab Thief_GrabBooty
+Thief_CheckPlayerCollision Thief_CheckCollisionWithLink
+Thief_DislodgePlayerItems Thief_SpillItems
+Sprite_Gibo Sprite_C3_Gibo
+Gibo_ExpelNucleus Gibo_Mitosis
+Gibo_DelayPursuit Gibo_Osmosis
+Gibo_PursueNucleus Gibo_ConsumeDaughter
+Sprite_Boulder Sprite_C2_Boulder
+Sprite_DrawLargeShadow SpriteDraw_BigShadow
+ChattyAgahnim_SpawnZeldaOnAltar CutsceneAgahnim_SpawnZeldaOnAltar
+Sprite_ChattyAgahnim Sprite_C1_CutsceneAgahnim
+ChattyAgahnim_Main CutsceneAgahnim_Agahnim
+ChattyAgahnim_Problab CutsceneAgahnim_HelloMyNameIs
+ChattyAgahnim_LevitateZelda CutsceneAgahnim_LightAsAFeatherStiffAsABoard
+ChattyAgahnim_DoTelewarpSpell CutsceneAgahnim_BanishZelda
+ChattyAgahnim_CompleteTelewarpSpell CutsceneAgahnim_MadeHerGoPoof
+ChattyAgahnim_Epiblab CutsceneAgahnim_Brag
+ChattyAgahnim_TeleportTowardCurtains CutsceneAgahnim_HideBehindCurtain
+Sprite_SpawnAgahnimAfterImage Sprite_Agahnim_ApplyMotionBlur
+ChattyAgahnim_LingerThenTerminate CutsceneAgahnim_ExistNoMore
+ChattyAgahnim_DrawTelewarpSpell SpriteDraw_CutsceneAgahnimSpell
+Sprite_AltarZelda Sprite_CutsceneAgahnim_Zelda
+AltarZelda_DrawWarpEffect SpriteDraw_AltarZeldaWarp
+Sprite_GiantMoldormLong Sprite_09_Moldorm
+GiantMoldorm_StraightPath Moldorm_Move
+GiantMoldorm_SpinningMeander Moldorm_Turn
+GiantMoldorm_LungeAtPlayer Moldorm_Charge
+GiantMoldorm_DrawHead SpriteDraw_Moldorm_Head
+GiantMoldorm_DrawSegment_A SpriteDraw_Moldorm_SegmentA
+GiantMoldorm_DrawSegment_B SpriteDraw_Moldorm_SegmentB
+GiantMoldorm_DrawSegment_C SpriteDraw_Moldorm_SegmentC
+GiantMoldorm_HandleTail Moldorm_HandleTail
+GiantMoldorm_DrawTail SpriteDraw_Moldorm_Tail
+GiantMoldorm_DrawEyeballs SpriteDraw_Moldorm_Eyeballs
+GiantMoldorm_AwaitDeath Moldorm_Explode
+Sprite_MakeBossDeathExplosion Sprite_MakeBossExplosion
+Sprite_VultureLong Sprite_01_Vulture
+Vulture_Dormant Vulture_Perched
+Sprite_RavenLong Sprite_00_Raven
+Raven_InWait Raven_Perched
+Raven_Ascend Raven_Rise
+Raven_SetSpriteDir Raven_SetFlip
+Raven_FleePlayer Raven_Flee
+Vitreous_SpawnSmallerEyesLong Vitreous_SpawnMinions
+Sprite_GreatCatfish Sprite_C0_Catfish
+Sprite_StandaloneItem Sprite_Catfish_QuakeMedallion
+GreatCatfish_Main Catfish_BigFish
+GreatCatfish_AwaitSpriteThrownInCircle Catfish_Sleep
+GreatCatfish_RumbleBeforeEmergence Catfish_TheRumbling
+GreatCatfish_Emerge Catfish_Surface
+GreatCatfish_ConversateThenSubmerge Catfish_LeaveMeAlone
+GreatCatfish_SpawnSurfacingSplash I_said_no_plop
+GreatCatfish_SpawnQuakeMedallion Catfish_RegurgitateMedallion
+Sprite_SpawnFlippersItem Sprite_Zora_RegurgitateFlippers
+GreatCatfish_SpawnImmediatelyDrownedSprite Catfish_SpawnPlop
+Sprite_WaterSplash Sprite_Catfish_SplashOfWater
+Sprite_Lightning Sprite_BF_Lightning
+Lightning_SpawnFulgurGarnish Lightning_SpawnGarnish
+Sprite_Vitreous Sprite_BD_Vitreous
+Vitreous_Dormant Vitreous_DunkedInGoo
+Vitreous_SpewLightning Vitreous_Lightningening
+Vitreous_PursuePlayer Vitreous_Bouncing
+Vitreous_SelectVitreolusToActivate Vitreous_SetMinionsForth
+Sprite_Vitreolus Sprite_BE_VitreousEye
+Sprite_MoveXyz Sprite_MoveXYZ
+Filter_MajorWhitenMain HandleScreenFlash
+CacheSprite_ExecuteAll ExecuteCachedSprites
+CacheSprite_ExecuteSingle UncacheAndExecuteSprite
+ArmosCoordinatorLong Overlord19_ArmosCoordinator
+ArmosCoordinator_AwaitKnightActivation ArmosCoordinator_WaitForWakeUp
+ArmosCoordinator_AwaitKnightsUnderCoercion ArmosCoordinator_CirclePosition
+ArmosCoordinator_OrderKnightsToBackWall ArmosCoordinator_LineUp
+ArmosCoordinator_CascadeKnightsToFrontWall ArmosCoordinator_ForwardMarch
+ArmosCoordinator_RadialContraction ArmosCoordinator_Pinch
+ArmosCoordinator_RadialDilation ArmosCoordinator_Spread
+ArmosCoordinator_TimedRotateThenTransition ArmosCoordinator_RotateKnights
+ArmosCoordinator_AreAllActiveKnightsSubmissive ArmosCoordinator_CheckKnights
+ArmosCoordinator_DisableKnights_XY_Coercion ArmosCoordinator_DisableCoercion
+Sprite_HelmasaurFireballLong Sprite_70_KingHelmasaurFireball
+Sprite_ArmosCrusherLong Sprite_RedArmosCrusher
+ArmosCrusher_RetargetPlayer RedArmosCrusher_TargetLink
+ArmosCrusher_ApproachTargetCoords RedArmosCrusher_Jump
+ArmosCrusher_Hover RedArmosCrusher_Hover
+ArmosCrusher_Crush RedArmosCrusher_Slam
+Sprite_EvilBarrierLong Sprite_40_LightningGate
+Moldorm_Initialize SpritePrep_MiniMoldorm
+Sprite_DrawFourAroundOne SpriteDraw_Antfairy
+ConvertVelocityToAngle Sprite_ConvertVelocityToAngle
+Sprite_TalkingTreeLong Sprite_25_TalkingTree
+TalkingTree_Type0 TalkingTree_Mouth
+TalkingTree_Type0_State0 TalkingTree_IdleWithBomb
+TalkingTree_Type0_State1 TalkingTree_DelayBomb
+TalkingTree_Type0_State2 TalkingTree_SpitBomb
+TalkingTree_Type0_State3 TalkingTree_IdleWithoutBomb
+TalkingTree_Type1 TalkingTree_Eye
+TalkingTree_SpawnEyes SpritePrep_TalkingTree_SpawnEyeball
+PullForRupees_SpawnRupees RupeePull_SpawnPrize
+Sprite_DiggingGameGuy Sprite_D5_DigGameGuy
+DiggingGameGuy_Introduction DigGameGuy_Idle
+DiggingGameGuy_DoYouWantToPlay DigGameGuy_OfferGame
+DiggingGameGuy_MoveOuttaTheWay DigGameGuy_UnblockEntrance
+DiggingGameGuy_StartMinigameTimer DigGameGuy_SetTimer
+DiggingGameGuy_TerminateMinigame DigGameGuy_Proctor
+Shovel_Helper DigGame_SpawnPrize
+SpriteBurn_Main SpriteModule_Burn
+Sprite_HelmasaurKing Sprite_92_HelmasaurKing
+Sprite_HelmasaurKing_Case0 Sprite_HelmasaurKing_DecisionHome
+Sprite_HelmasaurKing_Case1 Sprite_HelmasaurKing_WalkToLocation
+HelmasaurKing_Func7 HelmasaurKing_HandleMovement
+Sprite_HelmasaurKing_Case2 Sprite_HelmasaurKing_DecisionAway
+Sprite_HelmasaurKing_Case3 Sprite_HelmasaurKing_WalkBackHome
+HelmasaurKing_ReturnFunc6 HelmasaurKing_MaybeFireball
+HelmasaurKing_Func3 HelmasaurKing_SwingTail
+HelmasaurKing_Func5 HelmasaurKing_CheckMaskDamageFromHammer
+HelmasaurKing_Func4 HelmasaurKing_AttemptDamage
+HelmasaurKing_Func2 HelmasaurKing_ChipAwayAtMask
+HelmasaurKing_Func1 HelmasaurKing_ExplodeMask
+HelmasaurKing_SpawnMaskPart HelmasaurKing_SpawnMaskDebris
+HelmasaurKing_SpawnFireball HelmasaurKing_SpitFireball
+HelmasaurKing_DrawB SpriteDraw_KingHelmasaur_Eyes
+HelmasaurKing_DrawC KingHelmasaurMask
+HelmasaurKing_RepulseSpark KingHelmasaur_CheckBombDamage
+HelmasaurKing_DrawD SpriteDraw_KingHelmasaur_Body
+HelmasaurKing_DrawE SpriteDraw_KingHelmasaur_Legs
+HelmasaurKing_DrawF SpriteDraw_KingHelmasaur_Mouth
+HelmasaurKing_DrawA KingHelmasaur_OperateTail
+Sprite3_DivisionDelay NOP8
+Sprite_MadBatterBoltLong Sprite3A_MagicBatLightning
+Sprite_Pikit Sprite_AA_Pikit
+Pikit_SetNextVelocity Pikit_PikNextMovement
+Pikit_FinishJumpThenAttack Pikit_LandAndAttack
+Pikit_AttemptItemGrab Pikit_Steal
+Pikit_PrepThenDraw Pikit_PrepDraw
+Sprite_Bomber Sprite_A8_GreenZirro
+Bomber_Dodge Zirro_Dodge
+Bomber_Hovering Zirro_Idle
+Bomber_Moving Zirro_Move
+Bomber_SpawnPellet Zirro_DropBomb
+Sprite_Stalfos Sprite_A7_Stalfos
+Stalfos_Visible Stalfos_Skellington
+Sprite_Zazak Sprite_Zazak_Main
+Zazak_WalkThenTrackHead StalfosZazak_Walk
+Zazak_HaltAndPickNextDirection StalfosZazak_Wait
+Zazak_ShootFirePhlegm StalfosZazak_Shoot
+Stalfos_ThrowBoneAtPlayer Stalfos_ThrowBone
+Sprite_KholdstareShell Sprite_A3_KholdstareShell
+IceBallGenerator_SpawnSomething GenerateIceball
+Sprite_Kholdstare Sprite_A2_Kholdstare
+Kholdstare_Triplicate Kholdstare_Split
+nullsub_14 Kholdstare_DoAbsolutelyNothing
+Kholdstare_SpawnNebuleGarnish Kholdstare_SpawnPuffCloudGarnish
+Sprite_IceBallGenerator Sprite_A4_FallingIce
+IceBall_Quadruplicate IceBall_Split
+Sprite_Freezor Sprite_A1_Freezor
+Freezor_Stasis Freezor_Dormant
+Freezor_Awakening Freezor_Waking
+Freezor_Moving Freezor_Flailing
+Freezor_Melting Freezor_ImMelllltiiiinnnnggggg
+Sprite_FluteBoyOstrich Sprite_9E_HauntedGroveOstritch
+FluteBoyOstrich_Chillin HauntedGroveOstritch_Idle
+FluteBoyOstrich_RunAway HauntedGroveOstritch_Flee
+Sprite_FluteBoyRabbit Sprite_9F_HauntedGroveRabbit
+FluteBoyRabbit_Chillin HauntedGroveRabbit_Idle
+FluteBoyRabbit_RunAway HauntedGroveRabbit_Flee
+Sprite_FluteBoyBird Sprite_A0_HauntedGroveBird
+FluteBoyBird_Chillin HauntedGroveBird_Idle
+FluteBoyBird_Rising HauntedGroveBird_Ascending
+FluteBoyBird_Falling HauntedGroveBird_Descending
+FluteBoyBird_DrawBlink HauntedGroveBird_Blink
+Sprite_Zoro Sprite_9C_Zoro
+Zoro_Main Zoro
+Babusu_Main Babasu
+Babusu_Reset Babasu_Reset
+Babusu_Hiding Babasu_Hidden
+Babusu_TerrorSprinkles Babasu_Telegraph
+Babusu_ScurryAcross Babasu_Dart
+Sprite_WizzrobeAndBeam Sprite_9B_Wizzrobe
+Wizzrobe_Cloaked Wizzrobe_Invisible
+Wizzrobe_PhasingIn Wizzrobe_Appear
+Wizzrobe_PhasingOut Wizzrobe_Disappear
+Wizzrobe_SpawnBeam Wizzrobe_FireBeam
+Sprite_Kyameron Sprite_9A_Kyameron
+Kyameron_PuddleUp Kyameron_Puddle
+Kyameron_Coagulate Kyameron_BuildUp
+Kyameron_Disperse Kyameron_Dissipate
+Sprite_SpawnSimpleSparkleGarnish_SlotRestricted Sprite_GarnishSpawn_Sparkle_limited
+Sprite_SpawnSimpleSparkleGarnish Sprite_GarnishSpawn_Sparkle
+Sprite_Pengator Sprite_99_Pengator
+Pengator_FacePlayer Pengator_FaceLink
+Pengator_SpeedUp Pengator_Accelerate
+Pengator_Jump Pengator_Hop
+Pengator_SlideAndSparkle Pengator_Slide
+LaserBeam_SpawnGarnish LaserBeam_BuildUpGarnish
+Sprite_LaserEye Sprite_95_LaserEyeLeft
+LaserEye_MonitorFiringZone LaserEye_Reconnaissance
+LaserEye_FiringBeam LaserEye_TangoLocked
+LaserEye_SpawnBeam LaserEye_FireBeam
+j_Sprite_FlyingTile Sprite_94_Tile_bounce
+Sprite_Pirogusu Sprite_94_Pirogusu
+Pirogusu_WriggleInHole Pirogusu_InHole
+Pirogusu_Emerge Pirogusu_Crowning
+Pirogusu_SplashIntoPlay Pirogusu_Plop
+Sprite_SpawnSmallWaterSplash Sprite_SpawnSmallSplash
+Pirogusu_Swim Pirogusu_Active
+Pirogusu_SpawnSplashGarnish Pirogusu_SpawnSplash
+Sprite_Bumper Sprite_93_Bumper
+Sprite_StalfosKnight Sprite_91_StalfosKnight
+StalfosKnight_WaitingForPlayer StalfosKnight_Hidden
+StalfosKnight_Falling StalfosKnight_EnterBattle
+StalfosKnight_Case2 StalfosKnight_Idle
+StalfosKnight_Case3 StalfosKnight_ScanForOpponents
+StalfosKnight_Case4 StalfosKnight_Squat
+StalfosKnight_Case5 StalfosKnight_HopAround
+StalfosKnight_Case6 StalfosKnight_Crumble
+StalfosKnight_Case7 StalfosKnight_CelebrateStandingUp
+StalfosKnight_DrawHead SpriteDraw_StalfosKnight_Head
+Sprite_WallMaster Sprite_90_Wallmaster
+WallMaster_Descend Wallmaster_Descend
+sub_9EAF82 Wallmaster_Ascend
+Sprite_Zol Sprite_8F_Blob
+Zol_HidingUnseen Blob_Hidden
+Zol_PoppingOut Blob_Peeking
+Zol_Falling Blob_Falling
+Zol_Active Blob_Active
+Sprite_Terrorpin Sprite_8E_Terrorpin
+Terrorpin_Upright Terrorpin_RightsideUp
+Terrorpin_Overturned Terrorpin_UpsideDown
+Terrorpin_CheckHammerHitNearby Terrorpin_CheckForHammer
+Terrorpin_FormHammerHitBox Terrorpin_SetUpHammerHitBox
+Sprite_Arrghus Sprite_8C_Arrghus
+Arrghus_JumpWayUp Arrghus_JumpUp
+Arrghus_SmooshFromAbove Arrghus_SmashDown
+Arrghus_SwimFrantically Arrghus_PingPong
+Arrghus_ApproachTargetSpeed Arrghus_Move
+Arrghus_Decelerate Arrghus_MakeDecision
+Arrghus_Case2 Arrghus_PuffAttack
+Arrgi_Initialize Arrghus_HandlePuffs
+Sprite_Arrgi Sprite_8D_Arrghi
+Sprite_Gibdo Sprite_8B_Gibdo
+Gibdo_ApproachTargetDirection Gibdo_Turn
+Gibdo_CanMove Gibdo_Walk
+Sprite_MothulaBeam Sprite_89_MothulaBeam
+Sprite_FlyingTile Sprite_94_Tile
+Sprite_SpikeBlock Sprite_8A_SpikeBlock
+SpikeBlock_InduceTilemapUpdate SpikeBlock_UpdateTilemap
+SpikeBlock_CheckStatueSpriteCollision SpikeBlock_CheckStatueCollision
+Sprite_Mothula Sprite_88_Mothula
+Mothula_Delay Modula_Dormant
+Mothula_Ascend Modula_WakeUp
+Mothula_FlyAbout Modula_ActLikeAMoth
+Mothula_FireBeams Modula_FireBeams
+Mothula_ActivateMovingSpikeBlock Mothula_HandleSpikes
+Sprite_Kodondo Sprite_86_Kodongo
+Kodondo_ChooseDirection Kodongo_MakeDecision
+Kodondo_SetVel Kodongo_SetDirection
+Kodondo_Move Kodongo_Move
+Kodondo_BreatheFlame Kodongo_ShootFire
+Kodondo_SpawnFlames Kodongo_SpawnFire
+Sprite_Flame Sprite_87_KodongoFire
+Sprite_YellowStalfos Sprite_85_YellowStalfos
+YellowStalfos_FacePlayer YellowStalfos_TrackLink
+YellowStalfos_PauseThenDetachHead YellowStalfos_DecapitateSelf
+YellowStalfos_DelayBeforeAscending YellowStalfos_RegretDecapitatingSelf
+YellowStalfos_Neutralized YellowStalfos_Collapsed
+YellowStalfos_DetachHead YellowStalfos_EmancipateHead
+Goriya_StayStill Mimic_Stationary
+Sprite_Eyegore Sprite_83_GreenEyegore
+Eyegore_WaitUntilPlayerNearby Eyegore_Dormant
+Eyegore_OpeningEye Eyegore_WakingUp
+Eyegore_ChasePlayer Eyegore_Chase
+Eyegore_ClosingEye Eyegore_GoToSleep
+SpritePrep_BubbleGroup SpritePrep_AntifairyCircle
+Sprite_BubbleGroup Sprite_82_AntifairyCircle
+Sprite_Hover Sprite_81_Hover
+Hover_Stopped Hover_Idle
+Hover_Moving Hover_Move
+CrystalMaiden_Configure CrystalCutscene_Initialize
+CrystalMaiden_SpawnAndConfigMaiden CrystalCutscene_SpawnMaiden
+CrystalMaiden_InitPolyhedral CrystalCutscene_InitializePolyhedral
+Sprite_CrystalMaiden Sprite_AB_CrystalMaiden
+CrystalMaiden_Main CrystalMaiden_RunCutscene
+CrystalMaiden_GenerateSparkles CrystalMaiden_WaitForCrystalGrowth
+CrystalMaiden_FilterPalette CrystalMaiden_Emerge
+CrystalMaiden_ShowMessage CrystalMaiden_GiveSpeech
+CrystalMaiden_ReadingComprehensionExam CrystalMaiden_DoYouUnderstand
+CrystalMaiden_MayTheWayOfTheHero CrystalMaiden_GoodLuckKid
+CrystalMaiden_InitiateDungeonExit CrystalMaiden_KickOutOfDungeon
+Sprite_SpikeTrap Sprite_7D_BigSpike
+Sprite_GuruguruBar Sprite_7E_Firebar_Clockwise
+GuruguruBar_Main Firebar_Main
+Sprite_Winder Sprite_80_Firesnake
+Winder_SpawnFireballGarnish Firesnake_SpawnFireball
+Sprite_GreenStalfos Sprite_7C_GreenStalfos
+Sprite_Agahnim Sprite_7A_Agahnim
+Agahnim_State_0A Agahnim_SpinToPyramid
+Agahnim_State_08 Agahnim_ExorciseGanon
+Agahnim_State_09 Agahnim_UncloneSelf
+Agahnim_State_06 Agahnim_HelloDarkWorld
+Agahnim_State_07 Agahnim_CreateClones
+Agahnim_State_00 Agahnim_ChooseFirstMove
+Agahnim_State_01 Agahnim_HelloLightWorld
+sub_9ED514 Agahnim_PrepareToEmerge
+Agahnim_State_02 Agahnim_EmergeFromShadow
+Agahnim_State_03 Agahnim_Attack
+Agahnim_State_04 Agahnim_ChooseWarpSpot
+Agahnim_Func1 Agahnim_PerformAttack
+Agahnim_State_05 Agahnim_MoveTowardsWarp
+nullsub_15 UNREACHABLE_1ED971
+Sprite_EnergyBall Sprite_7B_AgahnimBalls
+SeekerEnergyBall_SplitIntoSixSmaller CreateSixBlueBalls
+Sprite_DashBeeHive Sprite_79_Bee
+DashBeeHive_WaitForDash Bee_DormantHive
+DashBeeHive_SpawnBee SpawnBeeFromHive
+SpawnBee_Init InitializeSpawnedBee
+SpawnBee ReleaseBeeFromBottle
+Bee_Normal Bee_Main
+Bee_PutInbottle Bee_Captured
+Sprite_GetEmptyBottleIndex Sprite_Find_EmptyBottle
+Bee_DetermineInteractionStatus Bee_HandleInteractions
+Sprite_GoodBee Sprite_B2_PlayerBee
+GoodBee_WaitingForDash GoldBee_Dormant
+GoodBee_SpawnTangibleVersion GoldBee_SpawnSelf
+GoodBee_Activated PlayerBee_Main
+Bee_SetAltitude Bee_HandleZ
+GoodBee_ScanForTargetableSprites PlayerBee_FindTarget
+Bee_Buzz Bee_Bzzt
+Sprite_HylianPlaque Sprite_B3_PedestalPlaque
+Sprite_ThiefChest Sprite_B4_PurpleChest
+Sprite_BombShopEntity Sprite_B5_BombShop
+Sprite_BombShopGuy Sprite_BombShop_Clerk
+Sprite_BombShopBomb Sprite_BombShop_Bomb
+Sprite_BombShopSuperBomb Sprite_BombShop_SuperBomb
+Sprite_BombShopSnoutPuff Sprite_BombShop_Huff
+BombShopGuy_SpawnSnoutPuff BombShop_ClerkExhalation
+Sprite_Kiki Sprite_B6_Kiki
+Kiki_Fleeing Kiki_Flee
+Kiki_Type2 Kiki_OfferInitialService
+Kiki_Type2_Case0 Kiki_OfferToFollow
+Kiki_Type2_Case1 Kiki_OfferToFollowTransaction
+Kiki_Type2_Case2 Kiki_MoveTowardsLink
+Kiki_Type2_Case3 Kiki_WaitABit
+Kiki_Type2_Case4 Kiki_EndIntroductionCutscene
+Kiki_LyingInWait Kiki_Dormant
+Kiki_Type1 Kiki_OfferEntranceService
+Kiki_Type1_Case0 Kiki_OfferToOpenPOD
+Kiki_Type1_Case1 Kiki_VerifyPurchase
+Kiki_Type1_Case35 Kiki_DartHead
+Kiki_Type1_Case246 Kiki_HopToSpot
+Kiki_Type1_Case7 Kiki_WalkOnRoof
+Kiki_Type1_Case8 Kiki_ReadyButtonPress
+Kiki_Type1_Case9 Kiki_SlamButton
+Kiki_InitiatePalaceOpeningProposal Kiki_RevertToSprite
+Kiki_TransitionFromTagalong Kiki_SpawnHandlerMonke
+Kiki_InitiateFirstBeggingSequence Kiki_SpawnHandler_A
+Kiki_AbandonDamagedPlayer Kiki_SpawnHandler_B
+Sprite_BlindMaiden Sprite_B7_BlindMaiden
+SpritePrep_OldMountainManLong SpritePrep_OldMan
+OldMountainMan_TransitionFromTagalong OldMan_RevertToSprite
+OldMountainMan_FreezePlayer OldMan_EnableCutscene
+Sprite_OldMountainMan Sprite_AD_OldMan
+OldMountainMan_Lost OldMan_Lost
+OldMountainMan_Supplicate OldMan_Lost_Wait
+OldMountainMan_SwitchToTagalong OldMan_Lost_BecomeFollower
+OldMountainMan_EnteringDomicile OldMan_Returning
+OldMountainMan_GrantMagicMirror OldMan_Returning_GiveMirror
+OldMountainMan_ShuffleAway OldMan_Returning_Move
+OldMountainMan_ApproachDoor OldMan_Returning_EnterDoor
+OldMountainMan_MadeItInside OldMan_Returning_FinishUp
+OldMountainMan_SittingAtHome OldMan_Home
+Sprite_DialogueTester Sprite_B8_DialogueTester
+DialogueTester_IncrementMessageIndex DialogueTester_NextMessage
+Sprite_BullyAndBallGuy Sprite_B9_BullyAndPinkBall
+Sprite_BallGuy Sprite_PinkBall
+BallGuy_Friction PinkBall_HandleDeceleration
+BallGuy_DrawDistressMarker PinkBall_Distress
+Bully_ChaseBallGuy Bully_ChaseVictim
+Bully_KickBallGuy Bully_PuntVictim
+Bully_Waiting Bully_Idle
+BullyAndBallGuy_SpawnBully SpawnBully
+BallGuy_Dialogue PinkBall_HandleMessage
+Bully_Dialogue Bully_HandleMessage
+Sprite_Whirlpool Sprite_BA_Whirlpool
+Sprite_ShopKeeper Sprite_BB_Shopkeeper
+ShopKeeper_Type0 Shopkeeper_StandardClerk
+ShopKeeper_Type1 ChestGameGuy
+ShopKeeper_Type1_Case0 ChestGameGuy_OfferGame
+ShopKeeper_Type1_Case1 ChestGameGuy_HandlePayment
+ShopKeeper_Type1_Case2 ChestGameGuy_ProctorGame
+ShopKeeper_HandleThief NiceThief_Animate
+ShopKeeper_Type2 NiceThiefWithGift
+ShopKeeper_Type2_Case0 NiceThiefWithGift_WaitForInteraction
+ShopKeeper_Type2_Case1 NiceThiefWithGift_GiveRupees
+ShopKeeper_Type3 MiniChestGameGuy
+ShopKeeper_Type3_Case0 MiniChestGameGuy_OfferGame
+ShopKeeper_Type3_Case1 MiniChestGameGuy_VerifyPurchase
+ShopKeeper_Type3_Case2 LesserChestGameGuy_AfterGameStart
+ShopKeeper_Type4 LostWoodsChestGameGuy
+ShopKeeper_Type4_Case0 LostWoodsChestGameGuy_OfferGame
+ShopKeeper_Type4_Case1 LostWoodsChestGameGuy_VerifyPurchase
+ShopKeeper_Type5_6 NiceThiefUnderRock
+ShopKeeper_Type7 ShopItem_RedPotion150
+ShopKeeper_SpawnInventoryItem ShopKeeper_SpawnShopItem
+ShopKeeper_Type8 ShopItem_FighterShield
+ShopKeeper_Type9 ShopItem_FireShield
+ShopKeeper_Func1 ShopItem_MakeShieldsDeflect
+ShopKeeper_Type10 ShopItem_Heart
+ShopKeeper_Type11 ShopItem_Arrows
+ShopKeeper_Type12 ShopItem_Bombs
+ShopKeeper_Type13 ShopItem_Bee
+ShopKeeper_GiveItem ShopItem_HandleReceipt
+ShopKeeper_PlaySound ShopItem_PlayBeep
+ShopKeeper_CheckPlayerSolicitedDamage ShopItem_CheckForAPress
+ShopKeeper_TryToGetPaid ShopItem_HandleCost
+ShopKeeper_DrawItemWithPrice SpriteDraw_ShopItem
+Sprite_PlayerCantPassThrough Sprite_BehaveAsBarrier
+Player_HaltSpecialPlayerMovement Sprite_HaltAllMovement
+Sprite_DashApple Sprite_AC_Apple
+Apple_SpawnTangibleApple SpawnApple
+Sprite_DrinkingGuy Sprite_BC_Drunkard
+Pipe_LocateTransitTile Pipe_LocatePath
+SomariaPlatform_LocateTransitTile SomariaPlatform_LocatePath
+Sprite_SomariaPlatformLong Sprite_SomariaPlatformAndPipe
+Sprite_SomariaPlatform_Case0 Sprite_SomariaPlatform_Spawn
+Sprite_SomariaPlatform_Case1 Sprite_SomariaPlatformAndPipe_Main
+SomariaPlatform_UpdateVel SomariaPlatformAndPipe_HandleMovement
+SomariaPlatform_GetTileBelow SomariaPlatformAndPipe_CheckTile
+SomariaPlatform_MoveX SomariaPlatform_HandleDragX
+SomariaPlatform_MoveY SomariaPlatform_HandleDragY
+SomariaPlatform_MoveXY SomariaPlatform_HandleDrag
+nullsub_13 SomariaPlatform_HandleTile_DoNothing
+SomariaPlatform_ZigZagRisingSlope SomariaPlatform_HandleTile_RisingSlope
+SomariaPlatform_ZigZagFallingSlope SomariaPlatform_HandleTile_FallingSlope
+SomariaPlatform_TransitTile SomariaPlatform_HandleTile_TJunctionDLR
+SomariaPlatform_Tjunc_NoUp SomariaPlatform_HandleTile_TJunctionULR
+SomariaPlatform_Tjunc_NoDown SomariaPlatform_HandleTile_TJunctionUDR
+SomariaPlatform_Tjunc_NoLeft SomariaPlatform_HandleTile_TJunctionUDL
+SomariaPlatform_Tjunc_NoRight SomariaPlatform_HandleTile_4WayJunction
+SomariaPlatform_TransitTileNoBack SomariaPlatform_HandleTile_CrossOver
+SomariaPlatform_TransitTileQuestion SomariaPlatform_HandleTile_Unknown
+SomariaPlatform_Endpoint SomariaPlatform_HandleTile_Station
+SomariaPlatform_UpdatePlayerDrag SomariaPlatform_DragLink
+Sprite_Pipe Sprite_AE_Pipe_Down
+Pipe_LocateTransitEndpoint Pipe_FindEndPoint
+Pipe_WaitForPlayer Pipe_Idle
+Pipe_DrawPlayerInward Pipe_DragLink
+Pipe_DragPlayerAlong Pipe_MoveLink
+Pipe_State5 Pipe_Reset
+Pipe_SetPlayerDir Pipe_HandlePlayerMovement
+Faerie_HandleMovementLong Fairy_HandleMovement
+SpawnFairy ReleaseFairy
+VWF_Select2Or3 RenderText_Draw_Choose2HiOr3
--- /dev/null
+++ b/other/names.txt
@@ -1,0 +1,8492 @@
+0x2100: INIDISP
+0x2101: OBSEL
+0x2102: OAMADDL
+0x2103: OAMADDH
+0x2104: OAMDATA
+0x2105: BGMODE
+0x2106: MOSAIC
+0x2107: BG1SC
+0x2108: BG2SC
+0x2109: BG3SC
+0x210a: BG4SC
+0x210b: BG12NBA
+0x210c: BG34NBA
+0x210d: BG1HOFS
+0x210e: BG1VOFS
+0x210f: BG2HOFS
+0x2110: BG2VOFS
+0x2111: BG3HOFS
+0x2112: BG3VOFS
+0x2113: BG4HOFS
+0x2114: BG4VOFS
+0x2115: VMAIN
+0x2116: VMADDL
+0x2117: VMADDH
+0x2118: VMDATAL
+0x2119: VMDATAH
+0x211a: M7SEL
+0x211b: M7A
+0x211c: M7B
+0x211d: M7C
+0x211e: M7D
+0x211f: M7X
+0x2120: M7Y
+0x2121: CGADD
+0x2122: CGDATA
+0x2123: W12SEL
+0x2124: W34SEL
+0x2125: WOBJSEL
+0x2126: WH0
+0x2127: WH1
+0x2128: WH2
+0x2129: WH3
+0x212a: WBGLOG
+0x212b: WOBJLOG
+0x212c: TM
+0x212d: TS
+0x212e: TMW
+0x212f: TSW
+0x2130: CGWSEL
+0x2131: CGADSUB
+0x2132: COLDATA
+0x2133: SETINI
+0x2134: MPYL
+0x2135: MPYM
+0x2136: MPYH
+0x2137: SLHV
+0x2138: RDOAM
+0x2139: RDVRAML
+0x213a: RDVRAMH
+0x213b: RDCGRAM
+0x213c: OPHCT
+0x213d: OPVCT
+0x213e: STAT77
+0x213f: STAT78
+0x2140: APUI00
+0x2141: APUI01
+0x2142: APUI02
+0x2143: APUI03
+0x2180: WMDATA
+0x2181: WMADDL
+0x2182: WMADDM
+0x2183: WMADDH
+0x4016: JOYA
+0x4017: JOYB
+0x4200: NMITIMEN
+0x4201: WRIO
+0x4202: WRMPYA
+0x4203: WRMPYB
+0x4204: WRDIVL
+0x4205: WRDIVH
+0x4206: WRDIVB
+0x4207: HTIMEL
+0x4208: HTIMEH
+0x4209: VTIMEL
+0x420a: VTIMEH
+0x420b: MDMAEN
+0x420c: HDMAEN
+0x420d: MEMSEL
+0x4210: RDNMI
+0x4211: TIMEUP
+0x4212: HVBJOY
+0x4213: RDIO
+0x4214: RDDIVL
+0x4215: RDDIVH
+0x4216: RDMPYL
+0x4217: RDMPYH
+0x4218: JOY1L
+0x4219: JOY1H
+0x421a: JOY2L
+0x421b: JOY2H
+0x421c: JOY3L
+0x421d: JOY3H
+0x421e: JOY4L
+0x421f: JOY4H
+0x4300: DMAP0
+0x4301: BBAD0
+0x4302: A1T0L
+0x4303: A1T0H
+0x4304: A1B0
+0x4305: DAS0L
+0x4306: DAS0H
+0x4307: DAS00
+0x4308: A2A0L
+0x4309: A2A0H
+0x430a: NTRL0
+0x430b: UNUSED0
+0x430f: MIRR0
+0x4310: DMAP1
+0x4311: BBAD1
+0x4312: A1T1L
+0x4313: A1T1H
+0x4314: A1B1
+0x4315: DAS1L
+0x4316: DAS1H
+0x4317: DAS10
+0x4318: A2A1L
+0x4319: A2A1H
+0x431a: NTRL1
+0x431b: UNUSED1
+0x431f: MIRR1
+0x4320: DMAP2
+0x4321: BBAD2
+0x4322: A1T2L
+0x4323: A1T2H
+0x4324: A1B2
+0x4325: DAS2L
+0x4326: DAS2H
+0x4327: DAS20
+0x4328: A2A2L
+0x4329: A2A2H
+0x432a: NTRL2
+0x432b: UNUSED2
+0x432f: MIRR2
+0x4330: DMAP3
+0x4331: BBAD3
+0x4332: A1T3L
+0x4333: A1T3H
+0x4334: A1B3
+0x4335: DAS3L
+0x4336: DAS3H
+0x4337: DAS30
+0x4338: A2A3L
+0x4339: A2A3H
+0x433a: NTRL3
+0x433b: UNUSED3
+0x433f: MIRR3
+0x4340: DMAP4
+0x4341: BBAD4
+0x4342: A1T4L
+0x4343: A1T4H
+0x4344: A1B4
+0x4345: DAS4L
+0x4346: DAS4H
+0x4347: DAS40
+0x4348: A2A4L
+0x4349: A2A4H
+0x434a: NTRL4
+0x434b: UNUSED4
+0x434f: MIRR4
+0x4350: DMAP5
+0x4351: BBAD5
+0x4352: A1T5L
+0x4353: A1T5H
+0x4354: A1B5
+0x4355: DAS5L
+0x4356: DAS5H
+0x4357: DAS50
+0x4358: A2A5L
+0x4359: A2A5H
+0x435a: NTRL5
+0x435b: UNUSED5
+0x435f: MIRR5
+0x4360: DMAP6
+0x4361: BBAD6
+0x4362: A1T6L
+0x4363: A1T6H
+0x4364: A1B6
+0x4365: DAS6L
+0x4366: DAS6H
+0x4367: DAS60
+0x4368: A2A6L
+0x4369: A2A6H
+0x436a: NTRL6
+0x436b: UNUSED6
+0x436f: MIRR6
+0x4370: DMAP7
+0x4371: BBAD7
+0x4372: A1T7L
+0x4373: A1T7H
+0x4374: A1B7
+0x4375: DAS7L
+0x4376: DAS7H
+0x4377: DAS70
+0x4378: A2A7L
+0x4379: A2A7H
+0x437a: NTRL7
+0x437b: UNUSED7
+0x437f: MIRR7
+0x7003e5: sram_slot1_tag
+0x7008e5: sram_slot2_tag
+0x700de5: sram_slot3_tag
+0x7e0000: A0
+0x7e0001: A1
+0x7e0002: A2
+0x7e0003: A3
+0x7e0004: A4
+0x7e0005: A5
+0x7e0006: A6
+0x7e0007: A7
+0x7e0008: A8
+0x7e0009: A9
+0x7e000a: A10
+0x7e000b: A11
+0x7e000c: A12
+0x7e000d: A13
+0x7e000e: A14
+0x7e000f: A15
+0x7e0010: main_module_index
+0x7e0011: submodule_index
+0x7e0012: nmi_boolean
+0x7e0013: INIDISP_copy
+0x7e0014: nmi_load_bg_from_vram
+0x7e0015: flag_update_cgram_in_nmi
+0x7e0016: flag_update_hud_in_nmi
+0x7e0017: nmi_subroutine_index
+0x7e0018: nmi_copy_packets_flag
+0x7e0019: nmi_update_tilemap_dst
+0x7e001a: frame_counter
+0x7e001b: player_is_indoors
+0x7e001c: TM_copy
+0x7e001d: TS_copy
+0x7e001e: TMW_copy
+0x7e001f: TSW_copy
+0x7e0020: link_y_coord
+0x7e0022: link_x_coord
+0x7e0024: link_z_coord
+0x7e0026: link_direction_last
+0x7e0027: link_actual_vel_y
+0x7e0028: link_actual_vel_x
+0x7e0029: link_actual_vel_z
+0x7e002a: link_subpixel_y
+0x7e002b: link_subpixel_x
+0x7e002c: link_subpixel_z
+0x7e002d: link_counter_var1
+0x7e002e: link_animation_steps
+0x7e002f: link_direction_facing
+0x7e0030: link_y_vel
+0x7e0031: link_x_vel
+0x7e0032: link_y_coord_original
+0x7e0038: tiledetect_diagonal_tile
+0x7e003a: button_mask_b_y
+0x7e003b: bitfield_for_a_button
+0x7e003c: button_b_frames
+0x7e003d: link_delay_timer_spin_attack
+0x7e003e: link_y_coord_safe_return_lo
+0x7e003f: link_x_coord_safe_return_lo
+0x7e0040: link_y_coord_safe_return_hi
+0x7e0041: link_x_coord_safe_return_hi
+0x7e0042: link_direction_mask_a
+0x7e0043: link_direction_mask_b
+0x7e0044: player_oam_y_offset
+0x7e0045: player_oam_x_offset
+0x7e0046: link_incapacitated_timer
+0x7e0047: set_when_damaging_enemies
+0x7e0048: bitmask_of_dragstate
+0x7e0049: force_move_any_direction
+0x7e004b: link_visibility_status
+0x7e004c: cape_decrement_counter
+0x7e004d: link_auxiliary_state
+0x7e004f: index_of_dashing_sfx
+0x7e0050: link_cant_change_direction
+0x7e0051: tiledetect_which_y_pos
+0x7e0055: link_cape_mode
+0x7e0056: link_is_bunny
+0x7e0057: link_speed_modifier
+0x7e0058: tiledetect_stair_tile
+0x7e0059: tiledetect_pit_tile
+0x7e005a: link_this_controls_sprite_oam
+0x7e005b: player_near_pit_state
+0x7e005d: link_player_handler_state
+0x7e005e: link_speed_setting
+0x7e005f: tiledetect_var2
+0x7e0061: gravestone_push_timeout
+0x7e0062: tiledetect_var1
+0x7e0064: oam_priority_value
+0x7e0066: link_last_direction_moved_towards
+0x7e0067: link_direction
+0x7e0068: link_y_page_movement_delta
+0x7e0069: link_x_page_movement_delta
+0x7e006a: link_num_orthogonal_directions
+0x7e006b: link_moving_against_diag_tile
+0x7e006c: is_standing_in_doorway
+0x7e006d: moving_against_diag_deadlocked
+0x7e006e: tiledetect_diag_state
+0x7e0072: scratch_b
+0x7e0073: scratch_a
+0x7e0074: scratch_c
+0x7e0075: scratch_d
+0x7e0076: index_of_interacting_tile
+0x7e0078: allow_scroll_z
+0x7e0079: link_spin_attack_step_counter
+0x7e007b: last_light_vs_dark_world
+0x7e0084: map16_load_src_off
+0x7e0086: map16_load_dst_off
+0x7e0088: map16_load_var2
+0x7e008a: overworld_screen_index
+0x7e008c: overlay_index
+0x7e0090: oam_cur_ptr
+0x7e0092: oam_ext_cur_ptr
+0x7e0094: BGMODE_copy
+0x7e0095: MOSAIC_copy
+0x7e0096: W12SEL_copy
+0x7e0097: W34SEL_copy
+0x7e0098: WOBJSEL_copy
+0x7e0099: CGWSEL_copy
+0x7e009a: CGADSUB_copy
+0x7e009b: HDMAEN_copy
+0x7e009c: COLDATA_copy0
+0x7e009d: COLDATA_copy1
+0x7e009e: COLDATA_copy2
+0x7e00a0: dungeon_room_index
+0x7e00a2: dungeon_room_index_prev
+0x7e00a4: dung_cur_floor
+0x7e00a6: quadrant_fullsize_x
+0x7e00a7: quadrant_fullsize_y
+0x7e00a8: composite_of_layout_and_quadrant
+0x7e00a9: link_quadrant_x
+0x7e00aa: link_quadrant_y
+0x7e00ad: dung_hdr_collision_2
+0x7e00ae: dung_hdr_tag
+0x7e00b0: subsubmodule_index
+0x7e00b1: subsubmodule_index_PADDING
+0x7e00b2: dung_draw_width_indicator
+0x7e00b4: dung_draw_height_indicator
+0x7e00b7: dung_load_ptr
+0x7e00b9: dung_load_ptr_bank
+0x7e00ba: dung_load_ptr_offs
+0x7e00bd: tmp1
+0x7e00bf: dung_line_ptrs_row0
+0x7e00cb: dung_line_ptrs_row1
+0x7e00d7: dung_line_ptrs_row2
+0x7e00da: dung_line_ptrs_row3
+0x7e00dd: dung_line_ptrs_row4
+0x7e00e0: BG1HOFS_copy2
+0x7e00e2: BG2HOFS_copy2
+0x7e00e4: BG3HOFS_copy2
+0x7e00e6: BG1VOFS_copy2
+0x7e00e8: BG2VOFS_copy2
+0x7e00ea: BG3VOFS_copy2
+0x7e00ec: tilemap_location_calc_mask
+0x7e00ee: link_is_on_lower_level
+0x7e00ef: room_transitioning_flags
+0x7e00f0: joypad1H_last
+0x7e00f2: joypad1L_last
+0x7e00f4: filtered_joypad_H
+0x7e00f6: filtered_joypad_L
+0x7e00f8: joypad1H_last2
+0x7e00fa: joypad1L_last2
+0x7e00fc: dung_unk2
+0x7e00ff: virq_trigger
+0x7e0100: link_dma_graphics_index
+0x7e0102: link_dma_var1
+0x7e0104: link_dma_var2
+0x7e0107: link_dma_var3
+0x7e0108: link_dma_var4
+0x7e0109: link_dma_var5
+0x7e010a: death_var5
+0x7e010c: saved_module_for_menu
+0x7e010e: which_entrance
+0x7e0110: dung_index_x3
+0x7e0112: flag_custom_spell_anim_active
+0x7e0114: link_tile_below
+0x7e0115: link_tile_below_PADDING
+0x7e0116: nmi_load_target_addr
+0x7e0118: nmi_update_tilemap_src
+0x7e011a: bg1_x_offset
+0x7e011c: bg1_y_offset
+0x7e011e: BG2HOFS_copy
+0x7e0120: BG1HOFS_copy
+0x7e0122: BG2VOFS_copy
+0x7e0124: BG1VOFS_copy
+0x7e0126: transition_counter
+0x7e0128: irq_flag
+0x7e012a: is_nmi_thread_active
+0x7e012c: music_control
+0x7e012d: sound_effect_ambient
+0x7e012e: sound_effect_1
+0x7e012f: sound_effect_2
+0x7e0130: music_unk1
+0x7e0131: sound_effect_ambient_last
+0x7e0132: buffer_for_playing_songs
+0x7e0133: last_music_control
+0x7e0134: animated_tile_vram_addr
+0x7e0136: flag_which_music_type
+0x7e01fe: stk_return_addr
+0x7e0200: overworld_map_state
+0x7e0201: overworld_map_state_UNUSED
+0x7e0202: hud_cur_item
+0x7e0203: hud_cur_item_hi
+0x7e0204: hud_var1
+0x7e0207: timer_for_flashing_circle
+0x7e0208: animate_heart_refill_countdown
+0x7e0209: animate_heart_refill_countdown_subpos
+0x7e020a: is_doing_heart_animation
+0x7e020b: link_debug_value_1
+0x7e020d: dungmap_init_state
+0x7e020e: dungmap_cur_floor
+0x7e0210: dungmap_var2
+0x7e0211: dungmap_idx
+0x7e0213: dungmap_var4
+0x7e0215: dungmap_var3
+0x7e0217: dungmap_var5
+0x7e0280: ancilla_objprio
+0x7e028a: ancilla_U
+0x7e0294: ancilla_z_vel
+0x7e029e: ancilla_z
+0x7e02a8: ancilla_z_subpixel
+0x7e02c0: tiledetect_inroom_staircase
+0x7e02c3: pushedblocks_some_index
+0x7e02c4: pushedblocks_maybe_timeout
+0x7e02c6: link_recoilmode_timer
+0x7e02c7: link_actual_vel_z_copy
+0x7e02ca: fallhole_var2
+0x7e02cb: swimming_countdown
+0x7e02cf: tagalong_var2
+0x7e02d0: tagalong_var3
+0x7e02d1: tagalong_var7
+0x7e02d2: timer_tagalong_reacquire
+0x7e02d3: tagalong_var1
+0x7e02d6: tagalong_var4
+0x7e02d8: link_receiveitem_index
+0x7e02d9: link_receiveitem_var1
+0x7e02da: link_pose_for_item
+0x7e02db: link_triggered_by_whirlpool_sprite
+0x7e02dc: link_x_coord_copy
+0x7e02de: link_y_coord_copy
+0x7e02e0: link_is_bunny_mirror
+0x7e02e1: link_is_transforming
+0x7e02e2: link_bunny_transform_timer
+0x7e02e3: link_sword_delay_timer
+0x7e02e4: flag_is_link_immobilized
+0x7e02e5: tiledetect_chest
+0x7e02e7: tiledetect_key_lock_gravestones
+0x7e02e8: bitfield_spike_cactus_tiles
+0x7e02e9: item_receipt_method
+0x7e02ea: tiledetect_tile_type
+0x7e02ec: flag_is_ancilla_to_pick_up
+0x7e02ee: tiledetect_spike_floor_and_tile_triggers
+0x7e02ef: bitmask_for_dashable_tiles
+0x7e02f1: link_dash_ctr
+0x7e02f2: tagalong_event_flags
+0x7e02f4: flag_is_sprite_to_pick_up_cached
+0x7e02f5: player_on_somaria_platform
+0x7e02f6: tiledetect_misc_tiles
+0x7e02f8: link_want_make_noise_when_dashed
+0x7e02f9: tagalong_var5
+0x7e02fa: link_is_near_moveable_statue
+0x7e0300: player_handler_timer
+0x7e0301: link_item_in_hand
+0x7e0302: fallhole_var1
+0x7e0303: eq_selected_y_item
+0x7e0304: eq_selected_y_item_copy
+0x7e0305: debug_var2
+0x7e0306: unused_2
+0x7e0307: eq_selected_rod
+0x7e0308: link_state_bits
+0x7e0309: link_picking_throw_state
+0x7e030a: some_animation_timer_steps
+0x7e030b: some_animation_timer
+0x7e030d: link_var30d
+0x7e030e: link_var30e
+0x7e0310: dung_floor_y_vel
+0x7e0312: dung_floor_x_vel
+0x7e0314: flag_is_sprite_to_pick_up
+0x7e0315: tile_coll_flag
+0x7e0318: related_to_moving_floor_y
+0x7e031a: related_to_moving_floor_x
+0x7e031c: state_for_spin_attack
+0x7e031d: step_counter_for_spin_attack
+0x7e031e: link_spin_offsets
+0x7e031f: countdown_for_blink
+0x7e0320: tiledetect_moving_floor_tiles
+0x7e0323: link_direction_facing_mirror
+0x7e0326: swimcoll_var3
+0x7e032a: link_maybe_swim_faster
+0x7e032b: swimcoll_var5
+0x7e032f: swimcoll_var1
+0x7e0334: swimcoll_var9
+0x7e0338: swimcoll_var11
+0x7e033c: swimcoll_var7
+0x7e0340: link_some_direction_bits
+0x7e0341: tiledetect_deepwater
+0x7e0343: tiledetect_normal_tiles
+0x7e0345: link_is_in_deep_water
+0x7e0346: link_palette_bits_of_oam
+0x7e0348: tiledetect_icy_floor
+0x7e034a: link_flag_moving
+0x7e034b: eq_debug_variable
+0x7e034c: tiledetect_water_staircase
+0x7e034f: link_swim_hard_stroke
+0x7e0350: link_debug_value_2
+0x7e0351: draw_water_ripples_or_grass
+0x7e0352: sort_sprites_offset_into_oam_buffer
+0x7e0354: value_computed_for_player_oam
+0x7e0355: secondary_water_grass_timer
+0x7e0356: primary_water_grass_timer
+0x7e0357: tiledetect_thick_grass
+0x7e0359: tiledetect_shallow_water
+0x7e035b: tiledetect_destruction_aftermath
+0x7e035d: oam_priority_value_2
+0x7e035f: flag_for_boomerang_in_place
+0x7e0360: link_electrocute_on_touch
+0x7e0362: link_actual_vel_z_mirror
+0x7e0363: link_actual_vel_z_copy_mirror
+0x7e0364: link_z_coord_mirror
+0x7e0366: tiledetect_read_something
+0x7e0368: interacting_with_liftable_tile_x1
+0x7e0369: interacting_with_liftable_tile_x1b
+0x7e036a: interacting_with_liftable_tile_x2
+0x7e036b: player_unk1
+0x7e036c: tile_action_index
+0x7e036d: tiledetect_vertical_ledge
+0x7e036e: detection_of_ledge_tiles_horiz_uphoriz
+0x7e036f: tiledetect_ledges_down_leftright
+0x7e0370: detection_of_unknown_tile_types
+0x7e0371: link_timer_push_get_tired
+0x7e0372: link_is_running
+0x7e0373: link_give_damage
+0x7e0374: link_countdown_for_dash
+0x7e0375: link_timer_jump_ledge
+0x7e0376: link_grabbing_wall
+0x7e0377: link_unk_master_sword
+0x7e0378: countdown_timer_for_staircases
+0x7e037a: link_position_mode
+0x7e037b: link_disable_sprite_damage
+0x7e037c: player_sleep_in_bed_state
+0x7e037d: link_pose_during_opening
+0x7e037e: related_to_hookshot
+0x7e037f: cheatWalkThroughWalls
+0x7e0380: ancilla_K
+0x7e0385: ancilla_L
+0x7e038a: ancilla_A
+0x7e038f: ancilla_B
+0x7e0394: ancilla_G
+0x7e0399: boomerang_temp_y
+0x7e039b: boomerang_temp_x
+0x7e039d: hookshot_effect_index
+0x7e039f: ancilla_arr3
+0x7e03a4: ancilla_arr1
+0x7e03a9: ancilla_S
+0x7e03b1: ancilla_aux_timer
+0x7e03b6: door_debris_x
+0x7e03ba: door_debris_y
+0x7e03be: door_debris_direction
+0x7e03c0: ancilla_arr26
+0x7e03c2: ancilla_arr25
+0x7e03c4: ancilla_alloc_rotate
+0x7e03c5: ancilla_H
+0x7e03ca: ancilla_floor2
+0x7e03cf: boomerang_arr1
+0x7e03d2: ancilla_arr23
+0x7e03d5: ancilla_T
+0x7e03db: ancilla_arr24
+0x7e03e1: ancilla_arr22
+0x7e03e4: ancilla_tile_attr
+0x7e03e9: link_something_with_hookshot
+0x7e03ea: ancilla_R
+0x7e03ef: link_force_hold_sword_up
+0x7e03f0: flute_countdown
+0x7e03f1: tiledetect_var4
+0x7e03f4: dung_unk6
+0x7e03f5: link_timer_tempbunny
+0x7e03f7: link_need_for_poof_for_transform
+0x7e03f8: link_need_for_pullforrupees_sprite
+0x7e03f9: hookshot_var1
+0x7e03fa: bit9_of_xcoord
+0x7e0400: dung_door_opened
+0x7e0402: dung_savegame_state_bits
+0x7e0408: dung_quadrants_visited
+0x7e040a: overworld_area_index
+0x7e040c: cur_palace_index_x2
+0x7e040e: dung_layout_and_starting_quadrant
+0x7e0410: overworld_screen_trans_dir_bits
+0x7e0412: incremental_counter_for_vram
+0x7e0414: dung_hdr_bg2_properties
+0x7e0415: dung_hdr_bg2_properties_PADDING
+0x7e0416: overworld_screen_trans_dir_bits2
+0x7e0418: overworld_screen_transition
+0x7e0419: overworld_screen_transition_ALWAYSZERO
+0x7e041a: dung_floor_move_flags
+0x7e041c: dung_some_subpixel
+0x7e041e: moving_wall_var2
+0x7e041f: moving_wall_var2_PADDING
+0x7e0422: dung_floor_x_offs
+0x7e0424: dung_floor_y_offs
+0x7e0428: dung_hdr_collision_2_mirror
+0x7e0429: dung_hdr_collision_2_mirror_PADDING
+0x7e042a: moving_wall_var1
+0x7e042c: dung_misc_objs_index
+0x7e042e: dung_index_of_torches
+0x7e0430: dung_door_switch_triggered
+0x7e0432: dung_num_star_shaped_switches
+0x7e0436: invisible_door_dir_and_index_x2
+0x7e0438: dung_num_inter_room_upnorth_stairs
+0x7e043a: dung_num_inter_room_southdown_stairs
+0x7e043c: dung_num_inroom_upnorth_stairs
+0x7e043e: dung_num_inroom_southdown_stairs
+0x7e0440: dung_num_interpseudo_upnorth_stairs
+0x7e0442: dung_num_inroom_upnorth_stairs_water
+0x7e0444: dung_num_activated_water_ladders
+0x7e0446: dung_num_water_ladders
+0x7e0448: dung_some_stairs_unk4
+0x7e044a: kind_of_in_room_staircase
+0x7e044e: dung_num_toggle_floor
+0x7e0450: dung_num_toggle_palace
+0x7e0452: dung_blastwall_flag_x
+0x7e0453: dung_blastwall_flag_y
+0x7e0454: dung_unk_blast_walls_2
+0x7e0456: dung_unk_blast_walls_3
+0x7e0458: hdr_dungeon_dark_with_lantern
+0x7e0459: hdr_dungeon_dark_with_lantern_PADDING
+0x7e045a: dung_num_lit_torches
+0x7e045b: dung_num_lit_torches_PADDING
+0x7e045c: dung_cur_quadrant_upload
+0x7e045d: dung_cur_quadrant_upload_PADDING
+0x7e0460: dung_cur_door_idx
+0x7e0462: which_staircase_index
+0x7e0463: which_staircase_index_PADDING
+0x7e0464: staircase_var1
+0x7e0466: related_to_trapdoors_somehow
+0x7e0468: dung_flag_trapdoors_down
+0x7e046a: dung_floor_2_filler_tiles
+0x7e046c: dung_hdr_collision
+0x7e0470: watergate_var1
+0x7e0471: watergate_var1_PADDING
+0x7e0472: watergate_pos
+0x7e0474: push_block_direction
+0x7e0476: link_is_on_lower_level_mirror
+0x7e0478: dung_index_of_torches_start
+0x7e047a: about_to_jump_off_ledge
+0x7e047e: dung_num_wall_upnorth_spiral_stairs
+0x7e0480: dung_num_wall_downnorth_spiral_stairs
+0x7e0482: dung_num_wall_upnorth_spiral_stairs_2
+0x7e0484: dung_num_wall_downnorth_spiral_stairs_2
+0x7e048a: cur_staircase_plane
+0x7e048e: dungeon_room_index2
+0x7e0490: dung_floor_1_filler_tiles
+0x7e0494: move_overlay_ctr
+0x7e0496: dung_num_chests_x2
+0x7e0498: dung_num_bigkey_locks_x2
+0x7e049a: dung_num_stairs_1
+0x7e049c: dung_num_stairs_2
+0x7e049e: dung_num_stairs_wet
+0x7e04a0: hud_floor_changed_timer
+0x7e04a2: dung_num_inter_room_upnorth_straight_stairs
+0x7e04a4: dung_num_inter_room_upsouth_straight_stairs
+0x7e04a6: dung_num_inter_room_downnorth_straight_stairs
+0x7e04a8: dung_num_inter_room_downsouth_straight_stairs
+0x7e04aa: death_var4
+0x7e04ac: num_memorized_tiles
+0x7e04ae: dung_num_inroom_upsouth_stairs_water
+0x7e04b0: dung_unk5
+0x7e04b4: super_bomb_indicator_unk2
+0x7e04b5: super_bomb_indicator_unk1
+0x7e04b8: big_key_door_message_triggered
+0x7e04ba: dung_overlay_to_load
+0x7e04c4: minigame_credits
+0x7e04c6: trigger_special_entrance
+0x7e04c7: flag_skip_call_tag_routines
+0x7e04ca: link_lowlife_countdown_timer_beep
+0x7e04f0: dung_torch_timers
+0x7e0500: dung_replacement_tile_state
+0x7e0520: dung_object_pos_in_objdata
+0x7e0540: dung_object_tilemap_pos
+0x7e0560: replacement_tilemap_UL
+0x7e0580: replacement_tilemap_LL
+0x7e05a0: replacement_tilemap_UR
+0x7e05c0: replacement_tilemap_LR
+0x7e05e0: pushedblocks_x_hi
+0x7e05e4: pushedblocks_x_lo
+0x7e05e8: pushedblocks_target
+0x7e05ec: pushedblocks_y_hi
+0x7e05f0: pushedblocks_y_lo
+0x7e05f4: pushedblocks_subpixel
+0x7e05f8: pushedblock_facing
+0x7e05fc: index_of_changable_dungeon_objs
+0x7e0600: room_scroll_vars0
+0x7e0608: room_scroll_vars1
+0x7e0610: up_down_scroll_target
+0x7e0612: up_down_scroll_target_end
+0x7e0614: left_right_scroll_target
+0x7e0616: left_right_scroll_target_end
+0x7e0618: camera_y_coord_scroll_low
+0x7e061a: camera_y_coord_scroll_hi
+0x7e061c: camera_x_coord_scroll_low
+0x7e061e: camera_x_coord_scroll_hi
+0x7e0620: BG1HOFS_subpixel
+0x7e0622: BG1VOFS_subpixel
+0x7e0624: overworld_unk1
+0x7e0626: overworld_unk1_neg
+0x7e0628: overworld_unk3
+0x7e062a: overworld_unk3_neg
+0x7e062c: dung_loade_bgoffs_h_copy
+0x7e062e: dung_loade_bgoffs_v_copy
+0x7e0630: selectfile_var8
+0x7e0636: overworld_map_flags
+0x7e0637: timer_for_mode7_zoom
+0x7e0638: M7X_copy
+0x7e063a: M7Y_copy
+0x7e063c: dung_hdr_hole_teleporter_plane
+0x7e063d: dung_hdr_staircase_plane
+0x7e0641: dung_flag_movable_block_was_pushed
+0x7e0642: dung_flag_statechange_waterpuzzle
+0x7e0646: dung_flag_somaria_block_switch
+0x7e0647: mosaic_inc_or_dec
+0x7e0670: spotlight_var3
+0x7e0674: spotlight_y_lower
+0x7e0676: spotlight_y_upper
+0x7e067a: spotlight_var4
+0x7e067c: spotlight_var1
+0x7e067e: spotlight_var2
+0x7e0680: water_hdma_var0
+0x7e0682: water_hdma_var1
+0x7e0684: water_hdma_var2
+0x7e0686: water_hdma_var3
+0x7e0688: water_hdma_var4
+0x7e068a: water_hdma_var5
+0x7e068c: dung_door_opened_incl_adjacent
+0x7e068e: dung_cur_door_pos
+0x7e0690: door_animation_step_indicator
+0x7e0692: door_open_closed_counter
+0x7e0694: dung_which_key_x2
+0x7e0696: ow_entrance_value
+0x7e0698: big_rock_starting_address
+0x7e069a: ow_countdown_transition
+0x7e06a0: mirror_vars
+0x7e06c0: dung_toggle_floor_pos
+0x7e06d0: dung_toggle_palace_pos
+0x7e06e0: dung_chest_locations
+0x7e06ec: dung_stairs_table_2
+0x7e0700: current_area_of_player
+0x7e0708: overworld_offset_base_y
+0x7e070a: overworld_offset_mask_y
+0x7e070c: overworld_offset_base_x
+0x7e070e: overworld_offset_mask_x
+0x7e0710: nmi_disable_core_updates
+0x7e0711: nmi_disable_core_updates_UNUSED
+0x7e0712: overworld_area_is_big
+0x7e0714: overworld_area_is_big_backup
+0x7e0716: overworld_right_bottom_bound_for_scroll
+0x7e0720: vwf_flag_next_line
+0x7e0722: vwf_curline
+0x7e0724: vwf_var1
+0x7e0726: vwf_line_ptr
+0x7e0800: oam_buf
+0x7e0a00: extended_oam
+0x7e0a20: bytewise_extended_oam
+0x7e0aa1: main_tile_theme_index
+0x7e0aa2: aux_tile_theme_index
+0x7e0aa3: sprite_graphics_index
+0x7e0aa4: misc_sprites_graphics_index
+0x7e0aa6: unused_config_gfx
+0x7e0aa8: overworld_palette_aux_or_main
+0x7e0aaa: load_chr_halfslot_even_odd
+0x7e0aac: overworld_palette_sp0
+0x7e0aad: sprite_aux1_palette
+0x7e0aae: sprite_aux2_palette
+0x7e0ab1: palette_sp6
+0x7e0ab2: hud_palette
+0x7e0ab3: overworld_palette_mode
+0x7e0ab4: overworld_palette_aux1_bp2to4_hi
+0x7e0ab5: overworld_palette_aux2_bp5to7_hi
+0x7e0ab6: dung_hdr_palette_1
+0x7e0ab8: overworld_palette_aux3_bp7_lo
+0x7e0abd: overworld_palette_swap_flag
+0x7e0abf: flag_overworld_area_did_change
+0x7e0ac0: dma_source_addr_6
+0x7e0ac2: dma_source_addr_11
+0x7e0ac4: dma_source_addr_7
+0x7e0ac6: dma_source_addr_12
+0x7e0ac8: dma_source_addr_8
+0x7e0aca: dma_source_addr_13
+0x7e0acc: dma_source_addr_3
+0x7e0ace: dma_source_addr_0
+0x7e0ad0: dma_source_addr_4
+0x7e0ad2: dma_source_addr_1
+0x7e0ad4: dma_source_addr_5
+0x7e0ad6: dma_source_addr_2
+0x7e0ad8: dma_source_addr_10
+0x7e0ada: dma_source_addr_15
+0x7e0adc: animated_tile_data_src
+0x7e0ae0: dma_source_addr_9
+0x7e0ae2: dma_source_addr_14
+0x7e0ae8: dma_var6
+0x7e0aea: dma_var7
+0x7e0aec: dma_source_addr_16
+0x7e0aee: dma_source_addr_18
+0x7e0af0: dma_source_addr_17
+0x7e0af2: dma_source_addr_19
+0x7e0af4: flag_travel_bird
+0x7e0af6: dma_source_addr_20
+0x7e0af8: dma_source_addr_21
+0x7e0b00: overlord_type
+0x7e0b08: overlord_x_lo
+0x7e0b10: overlord_x_hi
+0x7e0b18: overlord_y_lo
+0x7e0b20: overlord_y_hi
+0x7e0b28: overlord_gen1
+0x7e0b30: overlord_gen2
+0x7e0b38: overlord_gen3
+0x7e0b40: overlord_floor
+0x7e0b48: overlord_offset_sprite_pos
+0x7e0b58: sprite_stunned
+0x7e0b68: repulsespark_floor_status
+0x7e0b6a: sprite_limit_instance
+0x7e0b6b: sprite_flags
+0x7e0b7b: link_prevent_from_moving
+0x7e0b7c: drag_player_x
+0x7e0b7e: drag_player_y
+0x7e0b80: dungeon_room_history
+0x7e0b89: sprite_obj_prio
+0x7e0b99: archery_game_arrows_left
+0x7e0b9a: archery_game_out_of_arrows
+0x7e0b9c: dung_secrets_unk1
+0x7e0ba0: sprite_ignore_projectile
+0x7e0bb0: sprite_unk2
+0x7e0bc0: sprite_N
+0x7e0be0: sprite_flags5
+0x7e0bf0: ancilla_arr4
+0x7e0bfa: ancilla_y_lo
+0x7e0c04: ancilla_x_lo
+0x7e0c0e: ancilla_y_hi
+0x7e0c18: ancilla_x_hi
+0x7e0c22: ancilla_y_vel
+0x7e0c2c: ancilla_x_vel
+0x7e0c36: ancilla_y_subpixel
+0x7e0c40: ancilla_x_subpixel
+0x7e0c4a: ancilla_type
+0x7e0c54: ancilla_step
+0x7e0c5e: ancilla_item_to_link
+0x7e0c68: ancilla_timer
+0x7e0c72: ancilla_dir
+0x7e0c7c: ancilla_floor
+0x7e0c86: ancilla_oam_idx
+0x7e0c90: ancilla_numspr
+0x7e0c9a: sprite_room
+0x7e0caa: sprite_defl_bits
+0x7e0cba: sprite_die_action
+0x7e0cca: overlord_spawned_in_area
+0x7e0cd2: sprite_bump_damage
+0x7e0ce2: sprite_give_damage
+0x7e0cf2: damage_type_determiner
+0x7e0cf3: damage_type_determiner_PADDING
+0x7e0cf4: activate_bomb_trap_overlord
+0x7e0cf5: dungmap_var6
+0x7e0cf7: overworld_secret_subst_ctr
+0x7e0cf9: item_drop_luck
+0x7e0cfa: luck_kill_counter
+0x7e0cfb: num_sprites_killed
+0x7e0cfc: number_of_times_hurt_by_sprites
+0x7e0cfd: rupee_sfx_sound_delay
+0x7e0d00: sprite_y_lo
+0x7e0d10: sprite_x_lo
+0x7e0d20: sprite_y_hi
+0x7e0d30: sprite_x_hi
+0x7e0d40: sprite_y_vel
+0x7e0d50: sprite_x_vel
+0x7e0d60: sprite_y_subpixel
+0x7e0d70: sprite_x_subpixel
+0x7e0d80: sprite_spawned_flag
+0x7e0d90: sprite_A
+0x7e0da0: sprite_B
+0x7e0db0: sprite_C
+0x7e0dc0: sprite_graphics
+0x7e0dd0: sprite_state
+0x7e0de0: sprite_D
+0x7e0df0: sprite_delay_main
+0x7e0e00: sprite_delay_aux1
+0x7e0e10: sprite_delay_aux2
+0x7e0e20: sprite_type
+0x7e0e30: sprite_subtype
+0x7e0e40: sprite_flags2
+0x7e0e50: sprite_health
+0x7e0e60: sprite_flags3
+0x7e0e70: sprite_wallcoll
+0x7e0e80: sprite_subtype2
+0x7e0e90: sprite_E
+0x7e0ea0: sprite_F
+0x7e0eb0: sprite_head_dir
+0x7e0ec0: sprite_anim_clock
+0x7e0ed0: sprite_G
+0x7e0ee0: sprite_delay_aux3
+0x7e0ef0: sprite_hit_timer
+0x7e0f00: sprite_pause
+0x7e0f10: sprite_delay_aux4
+0x7e0f20: sprite_floor
+0x7e0f30: sprite_y_recoil
+0x7e0f40: sprite_x_recoil
+0x7e0f50: sprite_oam_flags
+0x7e0f60: sprite_flags4
+0x7e0f70: sprite_z
+0x7e0f80: sprite_z_vel
+0x7e0f90: sprite_z_subpos
+0x7e0fa0: cur_object_index
+0x7e0fa5: sprite_tiletype
+0x7e0fa8: dungmap_var7
+0x7e0faa: dungmap_var8
+0x7e0fac: repulsespark_timer
+0x7e0fad: repulsespark_x_lo
+0x7e0fae: repulsespark_y_lo
+0x7e0faf: repulsespark_anim_delay
+0x7e0fb3: sort_sprites_setting
+0x7e0fb4: garnish_active
+0x7e0fb7: spr_ranged_based_toggler
+0x7e0fb8: sprcoll_x_size
+0x7e0fba: sprcoll_y_size
+0x7e0fbc: sprcoll_x_base
+0x7e0fbe: sprcoll_y_base
+0x7e0fc1: flag_unk1
+0x7e0fc2: link_x_coord_prev
+0x7e0fc4: link_y_coord_prev
+0x7e0fc7: prizes_arr1
+0x7e0fd7: debug_game_frozen
+0x7e0fd8: cur_sprite_x
+0x7e0fda: cur_sprite_y
+0x7e0fdc: sprite_alert_flag
+0x7e0fe0: oam_region_base
+0x7e0fec: oam_alloc_arr1
+0x7e0ff9: intro_times_pal_flash
+0x7e0ffa: alt_sprites_flag
+0x7e0ffc: flag_block_link_menu
+0x7e0fff: is_in_dark_world
+0x7e1000: uvram
+0x7e1980: door_type_and_slot
+0x7e19a0: dung_door_tilemap_address
+0x7e19c0: dung_door_direction
+0x7e19e0: dung_exit_door_count
+0x7e19e2: dung_exit_door_addresses
+0x7e1a00: tagalong_y_lo
+0x7e1a14: tagalong_y_hi
+0x7e1a28: tagalong_x_lo
+0x7e1a3c: tagalong_x_hi
+0x7e1a50: tagalong_z
+0x7e1a64: tagalong_layerbits
+0x7e1ab0: bird_travel_x_lo
+0x7e1ac0: bird_travel_x_hi
+0x7e1ad0: bird_travel_y_lo
+0x7e1ae0: bird_travel_y_hi
+0x7e1af0: birdtravel_var1
+0x7e1b00: mode7_hdma_table
+0x7e1cd0: text_msgbox_topleft_copy
+0x7e1cd2: text_msgbox_topleft
+0x7e1cd4: text_render_state
+0x7e1cd5: vwf_line_mode
+0x7e1cd6: vwf_line_speed
+0x7e1cd7: text_incremental_state
+0x7e1cd8: messaging_module
+0x7e1cd9: dialogue_msg_dst_offs
+0x7e1cdd: dialogue_msg_src_offs
+0x7e1ce0: text_wait_countdown
+0x7e1ce2: text_tilemap_cur
+0x7e1ce6: text_next_position
+0x7e1ce8: choice_in_multiselect_box
+0x7e1ce9: text_wait_countdown2
+0x7e1cf0: dialogue_message_index
+0x7e1cf4: choice_in_multiselect_box_bak
+0x7e1d00: alt_sprite_state
+0x7e1d10: alt_sprite_type
+0x7e1d20: alt_sprite_x_lo
+0x7e1d30: alt_sprite_x_hi
+0x7e1d40: alt_sprite_y_lo
+0x7e1d50: alt_sprite_y_hi
+0x7e1d60: alt_sprite_graphics
+0x7e1d70: alt_sprite_A
+0x7e1d80: alt_sprite_head_dir
+0x7e1d90: alt_sprite_oam_flags
+0x7e1da0: alt_sprite_obj_prio
+0x7e1db0: alt_sprite_D
+0x7e1dc0: alt_sprite_flags2
+0x7e1dd0: alt_sprite_floor
+0x7e1de0: alt_sprite_spawned_flag
+0x7e1df0: alt_sprite_flags3
+0x7e1e00: intro_step_index
+0x7e1e01: intro_step_timer
+0x7e1e02: intro_want_double_ret
+0x7e1e08: intro_sprite_alloc
+0x7e1e0a: intro_frame_ctr
+0x7e1e0c: triforce_ctr
+0x7e1e10: intro_sprite_isinited
+0x7e1e18: intro_sprite_subtype
+0x7e1e20: intro_sprite_state
+0x7e1e28: intro_x_subpixel
+0x7e1e30: intro_x_lo
+0x7e1e38: intro_x_hi
+0x7e1e40: intro_y_subpixel
+0x7e1e48: intro_y_lo
+0x7e1e50: intro_y_hi
+0x7e1e58: intro_x_vel
+0x7e1e60: intro_y_vel
+0x7e1f00: intro_did_run_step
+0x7e1f01: poly_config_color_mode
+0x7e1f02: poly_config1
+0x7e1f03: poly_which_model
+0x7e1f04: poly_a
+0x7e1f05: poly_b
+0x7e1f06: poly_base_x
+0x7e1f07: poly_base_y
+0x7e1f08: poly_var1
+0x7e1f0a: thread_other_stack
+0x7e1f0c: nmi_flag_update_polyhedral
+0x7e1f3f: poly_config_num_vertex
+0x7e1f40: poly_config_num_polys
+0x7e1f41: poly_fromlut_ptr2
+0x7e1f43: poly_fromlut_ptr4
+0x7e1f45: poly_fromlut_z
+0x7e1f46: poly_fromlut_y
+0x7e1f47: poly_fromlut_x
+0x7e1f48: poly_f0
+0x7e1f4a: poly_f1
+0x7e1f4c: poly_f2
+0x7e1f4e: poly_num_vertex_in_poly
+0x7e1f4f: poly_raster_color_config
+0x7e1f50: poly_sin_a
+0x7e1f52: poly_cos_a
+0x7e1f54: poly_sin_b
+0x7e1f56: poly_cos_b
+0x7e1f58: poly_e0
+0x7e1f5a: poly_e2
+0x7e1f5c: poly_e3
+0x7e1f5e: poly_e1
+0x7e1f60: poly_arr_x
+0x7e1f88: poly_arr_y
+0x7e1fb0: poly_tmp0
+0x7e1fb2: poly_tmp1
+0x7e1fb5: poly_raster_color0
+0x7e1fb7: poly_raster_color1
+0x7e1fb9: poly_raster_dst_ptr
+0x7e1fbc: poly_tmp2
+0x7e1fbf: poly_arr_xy_coords_minus1
+0x7e1fc0: poly_xy_coords
+0x7e1fe0: poly_total_num_steps
+0x7e1fe1: poly_x0_cur
+0x7e1fe2: poly_y0_cur
+0x7e1fe3: poly_x0_target
+0x7e1fe4: poly_y0_trig
+0x7e1fe5: poly_x0_frac
+0x7e1fe7: poly_x0_step
+0x7e1fe9: poly_cur_vertex_idx0
+0x7e1fea: poly_x1_cur
+0x7e1feb: poly_y1_cur
+0x7e1fec: poly_x1_target
+0x7e1fed: poly_y1_trig
+0x7e1fee: poly_x1_frac
+0x7e1ff0: poly_x1_step
+0x7e1ff2: poly_cur_vertex_idx1
+0x7e1ffa: poly_raster_numfull
+0x7e2000: dung_bg2
+0x7e4000: dung_bg1
+0x7e9000: animated_tiles
+0x7ec000: dung_hdr_travel_destinations
+0x7ec005: dung_want_lights_out
+0x7ec006: dung_want_lights_out_copy
+0x7ec007: palette_filter_countdown
+0x7ec009: darkening_or_lightening_screen
+0x7ec00b: mosaic_target_level
+0x7ec00c: mosaic_target_level_PADDING
+0x7ec00d: bg_tile_animation_countdown
+0x7ec011: mosaic_level
+0x7ec017: overworld_fixed_color_plusminus
+0x7ec019: agahnim_pal_setting
+0x7ec100: overworld_area_index_spexit
+0x7ec102: TM_copy_spexit
+0x7ec104: BG2VOFS_copy2_spexit
+0x7ec106: BG2HOFS_copy2_spexit
+0x7ec108: link_y_coord_spexit
+0x7ec10a: link_x_coord_spexit
+0x7ec10c: overworld_screen_index_spexit
+0x7ec10e: map16_load_src_off_spexit
+0x7ec110: camera_y_coord_scroll_low_spexit
+0x7ec112: camera_x_coord_scroll_low_spexit
+0x7ec114: room_scroll_vars_y_vofs1_spexit
+0x7ec116: room_scroll_vars_y_hofs1_spexit
+0x7ec118: room_scroll_vars_y_vofs2_spexit
+0x7ec11a: room_scroll_vars_y_hofs2_spexit
+0x7ec11c: up_down_scroll_target_spexit
+0x7ec11e: up_down_scroll_target_end_spexit
+0x7ec120: left_right_scroll_target_spexit
+0x7ec122: left_right_scroll_target_end_spexit
+0x7ec125: main_tile_theme_index_spexit
+0x7ec126: aux_tile_theme_index_spexit
+0x7ec127: sprite_graphics_index_spexit
+0x7ec12a: overworld_unk1_spexit
+0x7ec12c: overworld_unk1_neg_spexit
+0x7ec12e: overworld_unk3_spexit
+0x7ec130: overworld_unk3_neg_spexit
+0x7ec140: overworld_area_index_exit
+0x7ec142: TM_copy_exit
+0x7ec144: BG2VOFS_copy2_exit
+0x7ec146: BG2HOFS_copy2_exit
+0x7ec148: link_y_coord_exit
+0x7ec14a: link_x_coord_exit
+0x7ec14c: overworld_screen_index_exit
+0x7ec14e: map16_load_src_off_exit
+0x7ec150: camera_y_coord_scroll_low_exit
+0x7ec152: camera_x_coord_scroll_low_exit
+0x7ec154: room_scroll_vars_y_vofs1_exit
+0x7ec156: room_scroll_vars_y_hofs1_exit
+0x7ec158: room_scroll_vars_y_vofs2_exit
+0x7ec15a: room_scroll_vars_y_hofs2_exit
+0x7ec15c: up_down_scroll_target_exit
+0x7ec15e: up_down_scroll_target_end_exit
+0x7ec160: left_right_scroll_target_exit
+0x7ec162: left_right_scroll_target_end_exit
+0x7ec165: main_tile_theme_index_exit
+0x7ec166: aux_tile_theme_index_exit
+0x7ec167: sprite_graphics_index_exit
+0x7ec16a: overworld_unk1_exit
+0x7ec16c: overworld_unk1_neg_exit
+0x7ec16e: overworld_unk3_exit
+0x7ec170: overworld_unk3_neg_exit
+0x7ec172: orange_blue_barrier_state
+0x7ec180: BG2HOFS_copy2_cached
+0x7ec182: BG2VOFS_copy2_cached
+0x7ec184: link_y_coord_cached
+0x7ec186: link_x_coord_cached
+0x7ec188: room_scroll_vars_y_vofs1_cached
+0x7ec18a: room_scroll_vars_y_vofs2_cached
+0x7ec18c: room_scroll_vars_x_vofs1_cached
+0x7ec18e: room_scroll_vars_x_vofs2_cached
+0x7ec190: up_down_scroll_target_cached
+0x7ec192: up_down_scroll_target_end_cached
+0x7ec194: left_right_scroll_target_cached
+0x7ec196: left_right_scroll_target_end_cached
+0x7ec198: camera_y_coord_scroll_low_cached
+0x7ec19a: camera_x_coord_scroll_low_cached
+0x7ec19c: quadrant_fullsize_x_cached
+0x7ec19d: quadrant_fullsize_y_cached
+0x7ec19e: link_quadrant_x_cached
+0x7ec19f: link_quadrant_y_cached
+0x7ec1a6: link_direction_facing_cached
+0x7ec1a7: link_is_on_lower_level_cached
+0x7ec1a8: link_is_on_lower_level_mirror_cached
+0x7ec1a9: is_standing_in_doorway_cahed
+0x7ec1aa: dung_cur_floor_cached
+0x7ec200: mapbak_BG1HOFS_copy2
+0x7ec202: mapbak_BG2HOFS_copy2
+0x7ec204: mapbak_BG1VOFS_copy2
+0x7ec206: mapbak_BG2VOFS_copy2
+0x7ec208: dung_bg2_properties_backup
+0x7ec20a: overworld_pal_unk1
+0x7ec20b: overworld_pal_unk2
+0x7ec20c: overworld_pal_unk3
+0x7ec20e: mapbak_main_tile_theme_index
+0x7ec20f: mapbak_sprite_graphics_index
+0x7ec210: mapbak_aux_tile_theme_index
+0x7ec211: mapbak_TM
+0x7ec212: mapbak_TS
+0x7ec213: overworld_screen_index_prev
+0x7ec215: map16_load_src_off_prev
+0x7ec217: map16_load_var2_prev
+0x7ec219: map16_load_dst_off_prev
+0x7ec21b: overworld_screen_transition_prev
+0x7ec21d: overworld_screen_trans_dir_bits_prev
+0x7ec21f: overworld_screen_trans_dir_bits2_prev
+0x7ec221: mapbak_bg1_x_offset
+0x7ec223: mapbak_bg1_y_offset
+0x7ec225: mapbak_CGWSEL
+0x7ec227: music_unk1_death
+0x7ec228: sound_effect_ambient_last_death
+0x7ec229: mapbak_HDMAEN
+0x7ec230: vwf_arr
+0x7ec2f8: aux_bg_subset_0
+0x7ec2f9: aux_bg_subset_1
+0x7ec2fa: aux_bg_subset_2
+0x7ec2fb: aux_bg_subset_3
+0x7ec2fc: sprite_gfx_subset_0
+0x7ec2fd: sprite_gfx_subset_1
+0x7ec2fe: sprite_gfx_subset_2
+0x7ec2ff: sprite_gfx_subset_3
+0x7ec300: aux_palette_buffer
+0x7ec500: main_palette_buffer
+0x7ec700: hud_tile_indices_buffer
+0x7ec880: moving_wall_arr1
+0x7ee800: polyhedral_buffer
+0x7ef000: save_dung_info
+0x7ef280: save_ow_event_info
+0x7ef300: savegame_has_master_sword_flags
+0x7ef340: link_item_bow
+0x7ef341: link_item_boomerang
+0x7ef342: link_item_hookshot
+0x7ef343: link_item_bombs
+0x7ef344: link_item_mushroom
+0x7ef345: link_item_fire_rod
+0x7ef346: link_item_ice_rod
+0x7ef347: link_item_bombos_medallion
+0x7ef348: link_item_ether_medallion
+0x7ef349: link_item_quake_medallion
+0x7ef34a: link_item_torch
+0x7ef34b: link_item_hammer
+0x7ef34c: link_item_flute
+0x7ef34d: link_item_bug_net
+0x7ef34e: link_item_book_of_mudora
+0x7ef34f: link_item_bottles
+0x7ef350: link_item_cane_somaria
+0x7ef351: link_item_cane_byrna
+0x7ef352: link_item_cape
+0x7ef353: link_item_mirror
+0x7ef354: link_item_gloves
+0x7ef355: link_item_boots
+0x7ef356: link_item_flippers
+0x7ef357: link_item_moon_pearl
+0x7ef359: link_sword_type
+0x7ef35a: link_shield_type
+0x7ef35b: link_armor
+0x7ef35c: link_bottle_info
+0x7ef360: link_rupees_goal
+0x7ef362: link_rupees_actual
+0x7ef364: link_compass
+0x7ef366: link_bigkey
+0x7ef368: link_dungeon_map
+0x7ef36a: link_rupees_in_pond
+0x7ef36b: link_heart_pieces
+0x7ef36c: link_health_capacity
+0x7ef36d: link_health_current
+0x7ef36e: link_magic_power
+0x7ef36f: link_num_keys
+0x7ef370: link_bomb_upgrades
+0x7ef371: link_arrow_upgrades
+0x7ef372: link_hearts_filler
+0x7ef373: link_magic_filler
+0x7ef374: link_which_pendants
+0x7ef375: link_bomb_filler
+0x7ef376: link_arrow_filler
+0x7ef377: link_num_arrows
+0x7ef379: link_ability_flags
+0x7ef37a: link_has_crystals
+0x7ef37b: link_magic_consumption
+0x7ef37c: link_keys_earned_per_dungeon
+0x7ef3c5: sram_progress_indicator
+0x7ef3c6: sram_progress_flags
+0x7ef3c7: savegame_map_icons_indicator
+0x7ef3c8: which_starting_point
+0x7ef3c9: sram_progress_indicator_3
+0x7ef3ca: savegame_is_darkworld
+0x7ef3cc: savegame_tagalong
+0x7ef3cd: saved_tagalong_y
+0x7ef3cf: saved_tagalong_x
+0x7ef3d1: saved_tagalong_indoors
+0x7ef3d2: saved_tagalong_floor
+0x7ef3d3: super_bomb_going_off
+0x7ef3e7: deaths_per_palace
+0x7ef403: death_save_counter
+0x7ef405: death_var2
+0x7ef580: pots_revealed_in_room
+0x7ef800: memorized_tile_addr
+0x7ef940: movable_block_datas
+0x7efa00: memorized_tile_value
+0x7efb40: dung_torch_data
+0x7efcc0: overworld_sprite_gfx
+0x7efd40: overworld_sprite_palettes
+0x7efe00: attributes_for_tile
+0x7f0000: skullwoodsfire_var0
+0x7f0008: skullwoodsfire_var5
+0x7f0010: skullwoodsfire_var4
+0x7f0011: blastwall_var4
+0x7f0018: skullwoodsfire_var9
+0x7f001a: skullwoodsfire_var11
+0x7f001c: blastwall_var7
+0x7f0020: skullwoodsfire_y_arr
+0x7f0026: skullwoodsfire_var10
+0x7f0030: skullwoodsfire_x_arr
+0x7f0036: skullwoodsfire_var12
+0x7f0040: blastwall_var12
+0x7f1200: messaging_text_buffer
+0x7f2000: dung_bg2_attr_table
+0x7f3000: dung_bg1_attr_table
+0x7f4400: map16_decode_0
+0x7f4410: map16_decode_1
+0x7f4420: map16_decode_2
+0x7f4430: map16_decode_3
+0x7f4440: map16_decode_last
+0x7f4442: map16_decode_tmp
+0x7f5800: breaktowerseal_var3
+0x7f5808: breaktowerseal_var4
+0x7f580a: quake_var5
+0x7f580b: quake_var1
+0x7f580e: breaktowerseal_x
+0x7f5810: breaktowerseal_y
+0x7f5812: breaktowerseal_var5
+0x7f5817: breaktowerseal_base_sparkle_y_lo
+0x7f581f: breaktowerseal_base_sparkle_y_hi
+0x7f5827: breaktowerseal_base_sparkle_x_lo
+0x7f582f: breaktowerseal_base_sparkle_x_hi
+0x7f5837: breaktowerseal_sparkle_var1
+0x7f584f: breaktowerseal_sparkle_y_lo
+0x7f5867: breaktowerseal_sparkle_y_hi
+0x7f587f: breaktowerseal_sparkle_x_lo
+0x7f5897: breaktowerseal_sparkle_x_hi
+0x7f58af: breaktowerseal_sparkle_var2
+0x7f58e4: bombos_x_hi
+0x7f5924: bombos_y_coord2
+0x7f592c: bombos_x_coord2
+0x7f5934: bombos_var4
+0x7f5935: bombos_arr3
+0x7f5945: bombos_arr4
+0x7f5955: bombos_y_coord
+0x7f59d5: bombos_x_coord
+0x7f5a55: bombos_var3
+0x7f5a56: bombos_var2
+0x7f5a57: bombos_var1
+0x7f5b00: overworld_music
+0x7f5ba0: freeRam
+0x7f6000: enemy_damage_data
+0x7f7000: hdma_table
+0x7f71c0: kTextDialoguePointers
+0x7fdd80: mapbak_palette
+0x7fdf80: sprite_where_in_room
+0x7fef80: overworld_sprite_was_loaded
+0x7ff800: garnish_type
+0x7ff81e: garnish_y_lo
+0x7ff83c: garnish_x_lo
+0x7ff85a: garnish_y_hi
+0x7ff878: garnish_x_hi
+0x7ff896: garnish_y_vel
+0x7ff8b4: garnish_x_vel
+0x7ff8d2: garnish_y_subpixel
+0x7ff8f0: garnish_x_subpixel
+0x7ff90e: garnish_countdown
+0x7ff92c: garnish_sprite
+0x7ff94a: garnish_anim_5
+0x7ff968: garnish_floor
+0x7ff9c2: sprite_I
+0x7ff9fe: garnish_oam_flags
+0x7ffa1c: sprite_unk3
+0x7ffa2c: sprite_unk4
+0x7ffa3c: sprite_unk5
+0x7ffa4c: sprite_unk1
+0x7ffa5c: swamola_x_lo
+0x7ffa6c: alt_sprite_C
+0x7ffa7c: alt_sprite_E
+0x7ffa8c: alt_sprite_subtype2
+0x7ffa9c: alt_sprite_height_above_shadow
+0x7ffaac: alt_sprite_delay_main
+0x7ffacc: alt_sprite_I
+0x7ffadc: alt_sprite_maybe_ignore_projectile
+0x7ffb1c: swamola_x_hi
+0x7ffbdc: swamola_y_lo
+0x7ffc00: moldorm_x_lo
+0x7ffc80: moldorm_x_hi_
+0x7ffc9c: swamola_y_hi
+0x7ffd00: moldorm_y_lo
+0x7ffd5c: swamola_target_x_lo
+0x7ffd62: swamola_target_x_hi
+0x7ffd68: swamola_target_y_lo
+0x7ffd6e: swamola_target_y_hi
+0x7ffd80: beamos_x_lo
+0x7ffe00: beamos_x_hi
+0x7ffe80: beamos_y_lo
+0x7fff00: beamos_y_hi
+0x808000: Interrupt_Reset
+0x808061: mainrouting_low
+0x80807d: mainrouting_high
+0x808099: mainrouting_bank
+0x8080b5: Module_MainRouting
+0x8080c9: Interrupt_NMI
+0x808100: volume_or_transfer_command
+0x80822c: Native_mode_COP
+0x80822d: NMI_SwitchThread
+0x8082d8: Interrupt_IRQ
+0x808333: EraseTileMaps_triforce
+0x80833f: EraseTileMaps_dungeonmap
+0x80834b: Vram_EraseTilemaps_normal
+0x808355: EraseTileMaps
+0x8083d1: NMI_ReadJoypads
+0x8083f9: NMI_ReadJoypads_Joypad2
+0x80841e: ClearOamBuffer
+0x80848c: kSrmOffsets
+0x808494: kLinkDmaSources8
+0x80849c: kLinkDmaSources4
+0x8084ac: kLinkDmaSources5
+0x8084b2: kLinkDmaSources6
+0x8085b2: kLinkDmaSources7
+0x8085d2: kLinkDmaCtrs0
+0x8085de: kLinkDmaSources9
+0x8085fc: NMI_PrepareSprites
+0x808781: JumpTableLocal
+0x80879c: JumpTableLong
+0x8087c0: Startup_InitializeMemory
+0x80882e: Overworld_GetTileAttributeAtLocation
+0x808888: LoadSongBank
+0x808901: Sound_LoadIntroSongBank
+0x808913: LoadOverworldSongs
+0x808925: LoadDungeonSongs
+0x808931: LoadCreditsSongs
+0x80893d: EnableForceBlank
+0x80894a: SaveGameFile
+0x8089e0: NMI_DoUpdates
+0x808c7e: kNmiSubroutines
+0x808cb0: NMI_UploadTilemap
+0x808ce3: NMI_UploadTilemap_doNothing
+0x808ce4: NMI_UploadBG3Text
+0x808d13: NMI_UpdateOWScroll
+0x808d62: NMI_UpdateSubscreenOverlay
+0x808d7c: NMI_UploadSubscreenOverlay_firstHalf
+0x808d96: NMI_UploadSubscreenOverlay_secondHalf
+0x808dae: NMI_HandleArbitraryTileMap
+0x808e09: NMI_UpdateBG1Wall
+0x808e4b: NMI_TileMapNothing
+0x808e4c: kLightWorldTileMapSrcs
+0x808e54: NMI_UpdateLoadLightWorldMap
+0x808ea9: NMI_UpdateBG2Left
+0x808ee7: NMI_UpdateBGChar3and4
+0x808f16: NMI_UpdateBGChar5and6
+0x808f45: NMI_UpdateBGCharHalf
+0x808f72: NMI_UpdateBGChar0
+0x808f79: NMI_UpdateBGChar1
+0x808f80: NMI_UpdateBGChar2
+0x808f87: NMI_UpdateBGChar3
+0x808f8e: NMI_UpdateObjChar0
+0x808fbd: NMI_UpdateObjChar2
+0x808fc4: NMI_UpdateObjChar3
+0x808fc9: NMI_RunTileMapUpdateDMA
+0x808ff3: NMI_UploadDarkWorldMap
+0x809038: NMI_UploadGameOverText
+0x80908b: NMI_UpdatePegTiles
+0x8090b7: NMI_UpdateStarTiles
+0x8090e3: NMI_UploadTilemap_Far
+0x8090eb: UNREACHABLE_0090EB
+0x80910f: kUploadBgSrcs
+0x80912f: kUploadBgDsts
+0x80913f: Dungeon_PrepareNextRoomQuadrantUpload
+0x8091c4: WaterFlood_BuildOneQuadrantForVRAM
+0x8091d3: TileMapPrep_NotWaterOnTag
+0x809252: WaterFlood_BuildOneQuadrantForVRAM_not_triggered
+0x8092a1: HandleStripes14
+0x809347: NMI_UpdateIRQGFX
+0x80937a: nmi_load_vram_lo
+0x80937b: kNmiLoadVramLo
+0x809384: kNmiLoadVramHi
+0x80938d: kNmiLoadVramBank
+0x809396: kLinkDmaSources1
+0x8095f4: kLinkDmaSources2
+0x809852: kLinkDmaSources3
+0x809888: kNmiVramAddrs
+0x8098c0: kUpperBitmasks
+0x8098e0: kUpperBitmasksNOT
+0x809900: kChestOpenMasks
+0x80990c: kHolesDecreaseHealth
+0x80997e: kDoorPositionToTilemapOffs_Up
+0x809996: kDoorPositionToTilemapOffs_Down
+0x8099ae: kDoorPositionToTilemapOffs_Left
+0x8099c6: kDoorPositionToTilemapOffs_Right
+0x8099de: kDoor_BlastWallUp_Dsts
+0x8099ea: kDungLinkOffs1Y
+0x8099f2: kDungLinkOffs1X
+0x8099fa: kDungLinkOffs1Pos
+0x809a02: kDoorTypeRemap
+0x809a52: kTileAttrsByDoor
+0x809aa2: kDungCheckDoorsLookup
+0x809ad2: kDungCheckDoorsLookupOpposite
+0x809b02: Dungeon_QuadrantOffsets
+0x809b0a: kMovingWall_Sizes0
+0x809b12: kMovingWall_Sizes1
+0x809b1a: kMovingWall_Tab1
+0x809b2a: kMovingWall_Tab0
+0x809b3a: kTab_Plus2
+0x809b52: kPredefinedTileData
+0x80cd9e: kDoorTypeSrcData
+0x80ce06: kDoorTypeSrcData2
+0x80ce66: kDoorTypeSrcData3
+0x80cec6: kDoorTypeSrcData4
+0x80cf24: kDoorAnimUpSrc
+0x80cf2c: kDoorAnimDownSrc
+0x80cf34: kDoorAnimLeftSrc
+0x80cf3c: kDoorAnimRightSrc
+0x80cf80: graphics_data_bank
+0x80cff3: graphics_sprite_bank
+0x80d05f: graphics_data_hi
+0x80d0d2: graphics_sprite_hi
+0x80d13e: graphics_data_lo
+0x80d1b1: graphics_sprite_lo
+0x80d21d: kIntro_LoadGfx_Tab
+0x80d231: LoadItemGFXIntoWRAM4BPPBuffer
+0x80d2be: kSwordTypeToOffs
+0x80d2c8: DecompressSwordGraphics
+0x80d300: kShieldTypeToGfxOffs
+0x80d308: DecompressShieldGraphics
+0x80d337: DecompressAnimatedDungeonTiles
+0x80d394: DecompressAnimatedOverworldTiles
+0x80d3c6: LoadItemGFX_Auxiliary
+0x80d407: kTagalongWhich
+0x80d423: LoadFollowerGraphics
+0x80d469: kDecodeAnimatedSpriteTile_Tab
+0x80d4db: WriteTo4BPPBuffer_at_7F4000
+0x80d4ed: DecodeAnimatedSpriteTile_variable
+0x80d537: LoadItemGFX_sheet0
+0x80d54e: LoadGfx_unpack_expandTo4bpp_from_0x7f4000
+0x80d553: LoadGfx_expandTo4bpp_from_0x7f4000
+0x80d561: LoadGfx_expandTo4bpp_inner
+0x80d585: UNREACHABLE_00D5C5
+0x80d5cb: Do3bppToWRAM4bpp_LeftPal
+0x80d5ce: Do3To4LowAnimated
+0x80d619: Do3bppToWRAM4bpp_RightPal
+0x80d61c: Expand3To4High
+0x80d66e: LoadTransAuxGFX
+0x80d6f9: LoadTransAuxGFX_sprite
+0x80d706: Gfx_LoadSpritesInner
+0x80d788: ReloadPreviouslyLoadedSheets
+0x80d80e: Attract_DecompressStoryGFX
+0x80d855: kMirrorWarp_LoadNext_NmiLoad
+0x80d864: AnimateMirrorWarp
+0x80d892: AnimateMirrorWarp_LoadPyramidIfAga
+0x80d8a5: AnimateMirrorWarp_TriggerOverlayA_2
+0x80d8b3: AnimateMirrorWarp_DrawDestinationScreen
+0x80d8bb: AnimateMirrorWarp_DoSpritesPalettes
+0x80d8c7: AnimateMirrorWarp_TriggerOverlayB
+0x80d8cf: AnimateMirrorWarp_TriggerBGChar0
+0x80d8d5: AnimateMirrorWarp_DecompressAnimatedTiles
+0x80d8ee: kVariousPacks
+0x80d8fe: AnimateMirrorWarp_DecompressNewTileSets
+0x80d9b9: AnimateMirrorWarp_DecompressBackgroundsA
+0x80d9f8: AnimateMirrorWarp_DecompressBackgroundsB
+0x80da2c: AnimateMirrorWarp_DecompressBackgroundsC
+0x80da63: AnimateMirrorWarp_LoadSubscreen
+0x80dabb: AnimateMirrorWarp_DecompressSpritesA
+0x80db1b: AnimateMirrorWarp_DecompressSpritesB
+0x80db57: kSpriteTilesets
+0x80dd97: kAuxTilesets
+0x80dedf: kGraphics_IncrementalVramUpload_Dst
+0x80deef: kGraphics_IncrementalVramUpload_Src
+0x80deff: Graphics_IncrementalVRAMUpload
+0x80df1a: PrepTransAuxGfx
+0x80df4f: Do3To4High16Bit
+0x80dfb8: Do3To4Low16Bit
+0x80e031: LoadNewSpriteGFXSet
+0x80e073: kMainTilesets
+0x80e19b: InitializeTilesets
+0x80e2d0: LoadDefaultGraphics
+0x80e33b: DecompressAndCopyManually
+0x80e36d: Attract_LoadBG3GFX
+0x80e384: LoadCommonSprites_2
+0x80e399: TransferMode7Characters
+0x80e3d2: kGraphicsHalfSlotPacks
+0x80e3e5: kGraphicsLoadSp6
+0x80e3fa: Graphics_LoadChrHalfSlot
+0x80e4e9: LoadFileSelectGraphics
+0x80e556: TransferFontToVRAM
+0x80e583: LoadSpriteGraphics
+0x80e5af: Do3To4High
+0x80e609: LoadBackgroundGraphics
+0x80e60d: LoadBgGfx_toaddr
+0x80e63c: Do3To4Low
+0x80e6b7: LoadCommonSprites
+0x80e75c: Decompress_sprite_high
+0x80e766: Decomp_spr_to_0x7f4000
+0x80e772: Decomp_spr
+0x80e783: Decomp_bg_to_7f4000
+0x80e78b: Decomp_bg_bank
+0x80e78f: Decomp_bg
+0x80e79e: Decompress
+0x80e843: Decompression_GetNextByte
+0x80e880: kPalIncr_R
+0x80e884: kPalIncr_G
+0x80e888: kPalIncr_B
+0x80e88c: kPaletteFilteringBits
+0x80e90c: PaletteFilter
+0x80e914: ApplyPaletteFilter
+0x80e9e4: FilterColors
+0x80ea49: UNREACHABLE_00EA79
+0x80eace: FilterColorsEndpoint
+0x80eb29: ResetHUDPalettes4and5
+0x80eb5e: PaletteFilterHistory
+0x80ebc5: PaletteFilter_WishPonds
+0x80ebcf: PaletteFilter_Crystal
+0x80ebd3: PaletteFilter_WishPonds_Inner
+0x80ebf2: PaletteFilter_RestoreSP5F
+0x80ec0d: PaletteFilter_SP5F
+0x80ec54: PaletteFilter_KholdstareShell_init
+0x80ec79: KholdstareShell_PaletteFiltering
+0x80ecc4: kPaletteFilter_Agahnim_Tab
+0x80ecca: AgahnimWarpShadowFilter
+0x80ed19: AgahnimWarpShadowFilter_filter_one
+0x80ed7c: Palette_FadeIntroOneStep
+0x80ed8f: Palette_FadeIntro2
+0x80edb1: PaletteFilter_Restore
+0x80edca: PaletteFilter_RestoreAdditive
+0x80ee21: PaletteFilter_RestoreSubtractive
+0x80ee78: PaletteFilter_InitializeWhiteFilter
+0x80eee0: MirrorWarp_GoToSubmodules
+0x80eee7: MirrorWarp_RunAnimationSubmodules
+0x80eef1: PaletteFilter_BlindingWhite
+0x80ef27: PaletteFilter_StartBlindingWhite
+0x80ef8a: PaletteFilter_BlindingWhiteTriforce
+0x80ef97: PaletteFilter_WhirlpoolBlue
+0x80f00c: PaletteFilter_IsolateWhirlpoolBlue
+0x80f04a: PaletteFilter_WhirlpoolRestoreBlue
+0x80f0c7: PaletteFilter_WhirlpoolRestoreRedGreen
+0x80f132: EXIT_00F12D
+0x80f135: PaletteFilter_RestoreBGSubstractiveStrict
+0x80f169: PaletteFilter_RestoreBGAdditiveStrict
+0x80f183: Trinexx_FlashShellPalette_Red
+0x80f1cf: Trinexx_UnflashShellPalette_Red
+0x80f207: Trinexx_FlashShellPalette_Blue
+0x80f253: Trinexx_UnflashShellPalette_Blue
+0x80f28b: IrisSpotlight_close
+0x80f295: Spotlight_open
+0x80f29d: SpotlightInternal
+0x80f2fb: kSpotlightIndirectHdma
+0x80f302: kSpotlight_delta_size
+0x80f30a: kSpotlight_goal
+0x80f312: IrisSpotlight_ConfigureTable
+0x80f427: IrisSpotlight_ResetTable
+0x80f44b: kConfigureSpotlightTable_Helper_Tab
+0x80f4cc: IrisSpotlight_CalculateCircleValue
+0x80f53e: kOrientLampBgTab0
+0x80f546: kOrientLampBgTab1
+0x80f54e: kOrientLampBgTab2
+0x80f556: kOrientLampBgTab3
+0x80f55e: kOrientLampBgTab4
+0x80f567: OrientLampLightCone
+0x80f649: AdjustWaterHDMAWindow
+0x80f660: AdjustWaterHDMAWindow_X
+0x80f734: FloodDam_PrepFloodHDMA
+0x80f800: Module0E_Interface
+0x80f875: Module_Messaging_0
+0x80f876: Messaging_MainJumpTable_lo
+0x80f882: Messaging_MainJumpTable_hi
+0x80f88e: Messaging_MainJumpTable_bank
+0x80f89a: RunInterface
+0x80f8b1: Module0E_05_DesertPrayer
+0x80f8c6: DesertPrayer_InitializeCutscene
+0x80f8e0: DesertPrayer_FadeScene
+0x80f8e9: Module0E_06_Unused
+0x80f8fb: Module0E_04_RedPotion
+0x80f911: Module0E_08_GreenPotion
+0x80f918: Module0E_09_BluePotion
+0x80f92d: kDungeonExit_From
+0x80f939: kDungeonExit_To
+0x80f945: PrepareDungeonExitFromBossFight
+0x80f9dd: SavePalaceDeaths
+0x80f9fa: Module0E_0B_SaveMenu
+0x80fa41: kOverworldSpriteGfx
+0x80fb41: kOverworldSpritePalettes
+0x80fc41: Sprite_LoadGraphicsProperties
+0x80fc62: Sprite_LoadGraphicsProperties_light_world_only
+0x80fc9c: kOverworldAuxTileThemeIndexes
+0x80fd1c: kOverworldBgPalettes
+0x80fda4: ResetStarTileGraphics
+0x80fda7: Dungeon_RestoreStarTileChr
+0x80fdee: InitializeMirrorHDMA
+0x80fe5e: MirrorWarp_BuildAndEnableHDMATable
+0x80fe64: MirrorWarp_BuildWavingHDMATable
+0x80ff2f: MirrorWarp_BuildDewavingHDMATable
+0x80ffc0: snes_header
+0x818000: kObjectSubtype1Params
+0x818200: kObjectSubtype1Routines
+0x8183f0: kObjectSubtype2Params
+0x818470: kObjectSubtype2Routines
+0x8184f0: kObjectSubtype3Params
+0x8185f0: kObjectSubtype3Routines
+0x8186f0: kDoorCallb
+0x8186f8: kDungeon_DrawObjectOffsets_BG1
+0x818719: kDungeon_DrawObjectOffsets_BG2
+0x81873a: Dungeon_LoadRoom
+0x8188e4: RoomDraw_DrawAllObjects
+0x818916: RoomData_DrawObject_Door
+0x81893c: RoomData_DrawObject
+0x8189dc: RoomDraw_DrawFloors
+0x818a1f: RoomDraw_FloorChunks
+0x818a44: RoomDraw_A_Many32x32Blocks
+0x818a89: RoomDraw_Downwards4x2_1to15or26
+0x818a92: RoomDraw_Rightwards2x4_1to15or26
+0x818aa4: RoomDraw_Downwards4x2_1to16_BothBG
+0x818b0d: RoomDraw_Rightwards2x4spaced4_1to16
+0x818b74: RoomDraw_Downwards2x2_1to16
+0x818b79: RoomDraw_Rightwards2x2_1to16
+0x818b7e: RoomDraw_Downwards2x2_1to15or32
+0x818b89: RoomDraw_Rightwards2x2_1to15or32
+0x818b94: RoomDraw_4x4BlocksIn4x4SuperSquare
+0x818be0: RoomDraw_DiagonalCeilingTopLeftA
+0x818bf4: RoomDraw_DiagonalCeilingBottomLeftA
+0x818c0e: RoomDraw_DiagonalCeilingTopRightA
+0x818c22: RoomDraw_DiagonalCeilingBottomRightA
+0x818c37: RoomDraw_Rightwards2x4spaced4_1to16_BothBG
+0x818c4f: RoomDraw_DownwardsDecor4x2spaced4_1to16
+0x818c58: RoomDraw_DiagonalAcute_1to16
+0x818c61: RoomDraw_DiagonalGrave_1to16
+0x818c6a: RoomDraw_DiagonalAcute_1to16_BothBG
+0x818cb9: RoomDraw_DiagonalGrave_1to16_BothBG
+0x818cc7: RoomDraw_ClosedChestPlatform
+0x818d47: RoomDraw_ChestPlatformHorizontalWallWithCorners
+0x818d5d: RoomDraw_Rightwards1x2_1to16_plus2
+0x818d80: RoomDraw_1x3_rightwards
+0x818d9e: RoomDraw_3x3FloorIn4x4SuperSquare
+0x818ddc: RoomDraw_BigHole4x4_1to16
+0x818e67: RoomDraw_DiagonalCeilingTopLeftB
+0x818e7b: RoomDraw_DiagonalCeilingBottomLeftB
+0x818e95: RoomDraw_DiagonalCeilingTopRightB
+0x818ea9: RoomDraw_DiagonalCeilingBottomRightB
+0x818ebe: RoomDraw_DownwardsHasEdge1x1_1to16_plus23
+0x818ec3: RoomDraw_DownwardsHasEdge1x1_1to16_plus3
+0x818eeb: RoomDraw_RightwardsHasEdge1x1_1to16_plus23
+0x818ef0: RoomDraw_RightwardsHasEdge1x1_1to16_plus3
+0x818f0c: RoomDraw_DownwardsBigRail3x1_1to16plus5
+0x818f30: Object_Draw_2x3
+0x818f36: RoomDraw_RightwardsBigRail1x3_1to16plus5
+0x818f62: RoomDraw_RightwardsHasEdge1x1_1to16_plus2
+0x818f8a: RoomDraw_DownwardsEdge1x1_1to16
+0x818f9d: RoomDraw_4x4FloorTwoIn4x4SuperSquare
+0x818fa2: RoomDraw_4x4FloorOneIn4x4SuperSquare
+0x818fa5: Object_Draw4x4_Size1to4
+0x818fbc: RoomDraw_Nothing_D
+0x818fbd: RoomDraw_RightwardsTopCorners1x2_1to16_plus13
+0x819001: RoomDraw_RightwardsBottomCorners1x2_1to16_plus13
+0x819045: RoomDraw_DownwardsLeftCorners2x1_1to16_plus12
+0x81908f: RoomDraw_DownwardsRightCorners2x1_1to16_plus12
+0x8190d9: RoomDraw_RightwardsEdge1x1_1to16plus7
+0x8190e2: RoomDraw_DownwardsEdge1x1_1to16plus7
+0x8190f8: RoomDraw_Nothing_A
+0x8190f9: RoomDraw_DownwardsFloor4x4_1to16
+0x819111: RoomDraw_Rightwards4x4_1to16
+0x819120: RoomDraw_Downwards1x1Solid_1to16_plus3
+0x819136: RoomDraw_Rightwards1x1Solid_1to16_plus3
+0x81913f: RoomDraw_DoorSwitcherer
+0x81918f: RoomDraw_Nothing_E
+0x819190: RoomDraw_MovingWallWest
+0x819216: RoomDraw_ChestPlatformCorner
+0x81921c: RoomDraw_MovingWallEast
+0x819298: RoomDraw_CheckIfWallIsMoved
+0x8192d1: MovingWall_FillReplacementBuffer
+0x8192fb: RoomDraw_RightwardsDecor4x4spaced2_1to16
+0x81930e: RoomDraw_DownwardsDecor4x4spaced2_1to16
+0x819323: RoomDraw_RightwardsStatue2x3spaced2_1to16
+0x819338: RoomDraw_RightwardsBlock2x2spaced2_1to16
+0x819347: RoomDraw_DownwardsBlock2x2spaced2_1to16
+0x819357: RoomDraw_DownwardsPillar2x4spaced2_1to16
+0x81936f: RoomDraw_RightwardsPillar2x4spaced4_1to16
+0x819387: RoomDraw_RightwardsDecor4x3spaced4_1to16
+0x81939f: RoomDraw_DownwardsDecor3x4spaced4_1to16
+0x8193b7: RoomDraw_RightwardsDoubled2x2spaced2_1to16
+0x8193dc: RoomDraw_TableRock4x4_1to16
+0x8193f7: Object_Table_Helper
+0x8193ff: Object_Table_Helper_
+0x819429: RoomDraw_Spike2x2In4x4SuperSquare
+0x819446: RoomDraw_DownwardsDecor2x2spaced12_1to16
+0x819456: RoomDraw_RightwardsDecor2x2spaced12_1to16
+0x819466: RoomDraw_Waterfall47
+0x819488: RoomDraw_Waterfall48
+0x8194b4: RoomDraw_RightwardsFloorTile4x2_1to16
+0x8194bd: RoomDraw_RightwardsBar4x3_1to16
+0x8194df: RoomDraw_RightwardsShelf4x4_1to16
+0x819501: RoomDraw_WaterOverlayA8x8_1to16
+0x8195a0: DrawWaterThing
+0x8195ef: RoomDraw_WaterOverlayB8x8_1to16
+0x8196dc: RoomDraw_RightwardsLine1x1_1to16plus1
+0x8196e4: RoomDraw_DownwardsLine1x1_1to16plus1
+0x8196f9: RoomDraw_RightwardsDecor4x2spaced8_1to16
+0x819702: RoomDraw_DownwardsDecor2x4spaced8_1to16
+0x81971a: RoomDraw_Nothing_C
+0x81971b: RoomDraw_DownwardsDecor3x4spaced2_1to16
+0x819733: RoomDraw_OpenChestPlatform
+0x81975c: Object_Draw_ChestPlatform_Helper
+0x8197b5: RoomDraw_DownwardsBar2x5_1to16
+0x8197dc: RoomDraw_Weird2x4_1_to_16
+0x8197ed: RoomDraw_4x4
+0x8197f0: RoomDraw_Object_Nx4
+0x819813: RoomDraw_4x4Corner_BothBG
+0x819819: Object_DrawNx4_BothBgs
+0x819854: RoomDraw_WeirdCornerBottom_BothBG
+0x81985c: RoomDraw_WeirdCornerTop_BothBG
+0x819892: RoomDraw_LitTorch
+0x819895: RoomDraw_Rightwards2x2
+0x8198ae: RoomDraw_BigKeyLock
+0x8198d0: RoomDraw_Chest
+0x8199b8: Object_Chest_startsOpen
+0x8199bb: RoomDraw_BigChest
+0x8199e6: RoomDraw_TableRock4x3
+0x8199ec: RoomDraw_SolidWallDecor3x4
+0x8199f2: RoomDraw_BigChest_opened
+0x819a00: RoomDraw_OpenBigChest
+0x819a06: RoomDraw_BigWallDecor
+0x819a0c: RoomDraw_Utility6x3
+0x819a12: RoomDraw_MagicBatAltar
+0x819a66: RoomDraw_SmithyFurnace
+0x819a6f: RoomDraw_EnabledStarSwitch
+0x819a8d: Object_StarTile_off
+0x819a90: RoomDraw_VerticalTurtleRockPipe
+0x819aa3: RoomDraw_HorizontalTurtleRockPipe
+0x819aa9: RoomDraw_RupeeFloor
+0x819aee: RoomDraw_Bed4x5
+0x819b18: UNREACHABLE_019B18
+0x819b1e: RoomDraw_WaterHopStairs_A
+0x819b48: RoomDraw_PortraitOfMario
+0x819b50: RoomDraw_DrawRightwards3x6
+0x819b56: RoomDraw_SanctuaryWall
+0x819bd9: RoomDraw_ChestPlatformVerticalWall
+0x819bf8: RoomDraw_DamFloodGate
+0x819c3b: RoomDraw_SomariaLine_increment_count
+0x819c3e: Object_Draw1x1
+0x819c44: RoomDraw_PrisonCell
+0x819cc6: RoomDraw_RightwardsCannonHole4x3_1to16
+0x819ceb: RoomDraw_DownwardsCannonHole3x4_1to16
+0x819d04: Object_Draw_3x2
+0x819d29: RoomDraw_EmptyWaterFace
+0x819d5d: Object_01_DrawWaterFace
+0x819d67: Object_Draw_4x7
+0x819d6c: RoomDraw_TableBowl
+0x819d6f: RoomDraw_WaterHoldingObject
+0x819d96: RoomDraw_KholdstareShell
+0x819da2: RoomDraw_SomeBigDecors
+0x819dd9: RoomDraw_TrinexxShell
+0x819de5: RoomDraw_LampCones
+0x819e06: RoomDraw_SingleLampCone
+0x819e30: RoomDraw_AgahnimsAltar
+0x819ea3: RoomDraw_AgahnimsWindows
+0x81a095: RoomDraw_FortuneTellerRoom
+0x81a194: RoomDraw_Utility3x5
+0x81a1d1: RoomDraw_VitreousGooGraphics
+0x81a255: RoomDraw_BG2MaskFull
+0x81a25d: RoomDraw_AutoStairs_North_MultiLayer_A
+0x81a26d: Object_InterStaircase2
+0x81a2c1: AutoStairsNorthMergedStart
+0x81a2c7: RoomDraw_AutoStairs_North_MergedLayer_A
+0x81a2df: RoomDraw_AutoStairs_North_MergedLayer_B
+0x81a30c: RoomDraw_AutoStairs_South_MultiLayer_A
+0x81a31c: Object_Stair_Type2
+0x81a36a: South_MergedStairs_BecomeMultiC
+0x81a36e: RoomDraw_AutoStairs_South_MultiLayer_C
+0x81a380: RoomDraw_AutoStairs_South_MergedLayer
+0x81a3ae: RoomDraw_WaterHopStairs_B
+0x81a41b: RoomDraw_InterRoomFatStairsUp
+0x81a458: RoomDraw_InterRoomFatStairsDown_A
+0x81a486: RoomDraw_InterRoomFatStairsDown_B
+0x81a4b4: RoomDraw_SpiralStairsGoingUpUpper
+0x81a4f5: RoomDraw_SpiralStairsGoingUpLower
+0x81a533: RoomDraw_SpiralStairsGoingDownUpper
+0x81a563: Object_SpiralStaircase1
+0x81a584: RoomDraw_SpiralStairsGoingDownLower
+0x81a5d2: RoomDraw_StraightInterroomStairsGoingUpNorthUpper
+0x81a5f4: Object_1F_Staircase
+0x81a607: Object_20_Staircase
+0x81a626: Object_Staircase_Down_Down
+0x81a664: RoomDraw_StraightInterroomStairsGoingUpNorthLower
+0x81a695: RoomDraw_StraightInterroomStairsGoingDownNorthLower
+0x81a6b5: StraightInterroomStairsLowerMain
+0x81a71c: RoomDraw_StraightInterroomStairsGoingUpSouthLower
+0x81a74a: RoomDraw_StraightInterroomStairsGoingDownSouthLower
+0x81a767: StraightInterroomStairsLower_continue
+0x81a7a3: RoomDraw_ArcheryGameTargetDoor
+0x81a7b6: RoomDraw_LightBeamOnFloor
+0x81a7d3: RoomDraw_BigLightBeamOnFloor
+0x81a7dc: Object_Draw8x8
+0x81a7f0: RoomDraw_GanonTriforceFloorDecor
+0x81a809: RoomDraw_VitreousGooDamage
+0x81a81c: RoomDraw_Door_North
+0x81a892: Door_Up_StairMaskLocked
+0x81a8fa: Door_PrioritizeCurDoor
+0x81a90f: RoomDraw_NormalRangedDoors_North
+0x81a932: RoomDraw_OneSidedShutters_North
+0x81a984: RoomDraw_Door_South
+0x81aa66: RoomDraw_CheckIfLowerLayerDoors_Y
+0x81aa80: RoomDraw_OneSidedShutters_South
+0x81aad7: RoomDraw_Door_West
+0x81ab1f: RoomDraw_NormalRangedDoors_West
+0x81ab78: RoomDraw_DrawUnreachableDoorSwitcher
+0x81ab99: RoomDraw_Door_East
+0x81abc8: RoomDraw_NormalRangedDoors_East
+0x81abe2: RoomDraw_OneSidedShutters_East
+0x81ac1a: DrawUnusedDoorSwitchObject
+0x81ac3b: RoomDraw_NorthCurtainDoor
+0x81ac5b: ExplodingWallNotOpen
+0x81ac70: RoomDraw_Door_ExplodingWall
+0x81ace4: RoomDraw_ExplodingWallSegment
+0x81ad25: RoomDraw_ExplodingWallColumn
+0x81ad41: RoomDraw_HighRangeDoor_North
+0x81add4: RoomDraw_OneSidedLowerShutters_South
+0x81ae40: RoomDraw_HighRangeDoor_West
+0x81aef0: RoomDraw_OneSidedLowerShutters_East
+0x81af7f: RoomDraw_MakeDoorHighPriorityLowerLayer_North
+0x81af8b: RoomDraw_MakeDoorHighPriority_North
+0x81afc8: RoomDraw_MakeDoorHighPriorityLowerLayer_South
+0x81afd4: RoomDraw_MakeDoorHighPriority_South
+0x81b00d: RoomDraw_MakeDoorHighPriorityLowerLayer_West
+0x81b017: RoomDraw_MakeDoorHighPriority_West
+0x81b050: RoomDraw_MakeDoorHighPriorityLowerLayer_East
+0x81b05c: RoomDraw_MakeDoorHighPriority_East
+0x81b092: RoomDraw_MarkDungeonToggleDoor
+0x81b09f: RoomDraw_MarkLayerToggleDoor
+0x81b0ac: RoomDraw_GetObjectSize_1to16
+0x81b0af: Object_SizeAtoAplus15
+0x81b0be: RoomDraw_GetObjectSize_1to15or26
+0x81b0cc: RoomDraw_GetObjectSize_1to15or32
+0x81b0da: RoomDraw_FlagDoorsAndGetFinalType
+0x81b18f: return_0
+0x81b191: RoomDraw_SmallRailCorner
+0x81b19e: UNREACHABLE_01B19E
+0x81b1a4: RoomDraw_MakeDoorPartsHighPriority_Y
+0x81b1e1: UNREACHABLE_01B1E1
+0x81b1e7: RoomDraw_MakeDoorPartsHighPriority_X
+0x81b220: RoomDraw_Downwards4x2VariableSpacing
+0x81b254: UNREACHABLE_01B254
+0x81b264: UNREACHABLE_01B264
+0x81b279: RoomDraw_DrawObject2x2and1
+0x81b293: RoomDraw_DrawDiagonalGrave
+0x81b2a1: RoomDraw_DrawDiagonalAcute
+0x81b2af: RoomDraw_Object_2x2_downwards
+0x81b2ca: RoomDraw_LineOf8x8_advance_and_use_B2_for_count
+0x81b2ce: Object_FillOneRowOfWidth
+0x81b2d0: Object_FillOneRowOfA
+0x81b2e1: RoomDraw_RightwardShelfEnd
+0x81b2f6: RoomDraw_RightwardBarSegment
+0x81b306: RoomDraw_WeirdGloveRequiredPot
+0x81b30b: RoomDraw_WeirdUglyPot
+0x81b310: RoomDraw_BigGrayRock
+0x81b33a: DrawBigGraySegment
+0x81b376: RoomDraw_RightwardsFakePots2x2_1to16
+0x81b381: RoomDraw_DownwardsFakePots2x2_1to16
+0x81b395: RoomDraw_SinglePot
+0x81b3e1: RoomDraw_BombableFloor
+0x81b429: Object_BombableFloor_Helper
+0x81b474: RoomDraw_RightwardsHammerPegs2x2_1to16
+0x81b47f: RoomDraw_DownwardsHammerPegs2x2_1to16
+0x81b493: RoomDraw_HammerPegSingle
+0x81b4d6: DrawObjects_PushableBlock
+0x81b509: DrawObjects_LightableTorch
+0x81b560: kDungeonHeader_SpecialAdjustment
+0x81b564: Dungeon_LoadHeader
+0x81b759: Dungeon_CheckAdjacentRoomsForOpenDoors
+0x81b7ef: Dungeon_LoadAdjacentRoomDoors
+0x81b83e: Dungeon_ApplyRoomOverlay
+0x81b8b4: Dungeon_LoadAttribute_Selectable
+0x81b8bf: Dungeon_LoadAttributeTable
+0x81b8e3: Dungeon_LoadBasicAttribute
+0x81b8ec: Dungeon_LoadBasicAttr_partial
+0x81b8f3: Dungeon_LoadBasicAttribute_full
+0x81b967: Dungeon_LoadObjectAttribute
+0x81bddb: Dungeon_SetChestAttributes
+0x81be17: Dungeon_LoadDoorAttribute
+0x81be35: Dungeon_LoadSingleDoorAttribute
+0x81bfc1: Door_LoadBlastWallAttr
+0x81c1ba: ChangeDoorToSwitch
+0x81c21c: Dungeon_InitializePegAttribute
+0x81c22a: Dungeon_FlipCrystalPegAttribute
+0x81c27d: kDungeon_TagRoutines
+0x81c2fd: Dungeon_HandleRoomTags
+0x81c31f: kTeleportPitLevel1
+0x81c322: kTeleportPitLevel2
+0x81c325: RoomTag_DirtyExit
+0x81c326: return_loc_81C326
+0x81c328: Dung_TagRoutine_0x00
+0x81c329: Dungeon_DetectStaircase
+0x81c432: RoomTag_NorthWestTrigger
+0x81c438: Dung_TagRoutine_0x2A
+0x81c43e: Dung_TagRoutine_0x2B
+0x81c444: Dung_TagRoutine_0x2C
+0x81c44a: Dung_TagRoutine_0x2D
+0x81c450: Dung_TagRoutine_0x2E
+0x81c456: Dung_TagRoutine_0x2F
+0x81c45c: Dung_TagRoutine_0x30
+0x81c461: RoomTag_QuadrantTrigger
+0x81c49e: Dung_TagRoutine_TrapdoorsUp
+0x81c4bf: RoomTag_RoomTrigger
+0x81c4db: RoomTag_RekillableBoss
+0x81c4e7: RoomTag_RoomTrigger_BlockDoor
+0x81c508: RoomTag_PrizeTriggerDoorDoor
+0x81c541: RoomTag_SwitchTrigger_HoldDoor
+0x81c599: RoomTag_SwitchTrigger_ToggleDoor
+0x81c5cf: PushPressurePlate
+0x81c629: RoomTag_TorchPuzzleDoor
+0x81c666: kBlastWall_Tab0
+0x81c670: kBlastWall_Tab1
+0x81c67a: RoomTag_Switch_ExplodingWall
+0x81c685: RoomTag_PullSwitchExplodingWall
+0x81c68c: Dung_TagRoutine_BlastWallStuff
+0x81c6fc: kBossFinishedFallingItem
+0x81c709: RoomTag_GetHeartForPrize
+0x81c74e: RoomTag_Agahnim
+0x81c767: RoomTag_GanonDoor
+0x81c7a2: RoomTag_KillRoomBlock
+0x81c7c2: RoomTag_PushBlockForChest
+0x81c7cc: RoomTag_TriggerChest
+0x81c7d8: RoomTag_OperateChestReveal
+0x81c8ae: RoomTag_TorchPuzzleChest
+0x81c8d4: RoomTag_MovingWall_East
+0x81c961: kMovingWall_Xoff
+0x81c965: kMovingWall_Yoff
+0x81c969: RoomTag_MovingWallShakeItUp
+0x81c98b: RoomTag_MovingWall_West
+0x81ca17: RoomTag_MovingWallTorchesCheck
+0x81ca66: MovingWall_MoveALittle
+0x81ca75: RoomTag_AdvanceGiganticWall
+0x81ca94: RoomTag_WaterOff
+0x81cb1a: RoomTag_WaterOn
+0x81cb49: RoomTag_WaterGate
+0x81cbff: Dung_TagRoutine_0x1B
+0x81cc00: RoomTag_Holes0
+0x81cc04: Dung_TagRoutine_0x23
+0x81cc08: Dung_TagRoutine_0x34
+0x81cc0c: Dung_TagRoutine_0x35
+0x81cc10: Dung_TagRoutine_0x36
+0x81cc14: Dung_TagRoutine_0x37
+0x81cc18: Dung_TagRoutine_0x39
+0x81cc1c: Dung_TagRoutine_0x3A
+0x81cc1e: Dung_TagRoutine_Func2
+0x81cc5b: RoomTag_ChestHoles0
+0x81cc62: Dung_TagRoutine_0x3B
+0x81cc89: RoomTag_Holes2
+0x81cc95: RoomTag_OperateWaterFlooring
+0x81cd39: RoomTag_MaybeCheckShutters
+0x81cda0: return_false_loc_81CDA0
+0x81cda5: RoomTag_GetTilemapCoords
+0x81cdcc: RoomTag_CheckForPressedSwitch
+0x81ce64: kSrcTiles1
+0x81ce6c: kOpenDoorPanning
+0x81ce70: Dungeon_ProcessTorchesAndDoors
+0x81d1f4: Bomb_CheckForDestructibles
+0x81d2e8: DrawDoorOpening_Step1
+0x81d311: DrawShutterDoorSteps
+0x81d33a: DrawEyeWatchDoor
+0x81d365: IndexAndClearCurtainDoor
+0x81d373: Door_BlastWallExploding_Draw
+0x81d38f: OperateShutterDoors
+0x81d469: OpenCrackedDoor
+0x81d476: UnlockKeyDoor_Main
+0x81d48d: step12
+0x81d510: Dungeon_LoadSingleDoorTileAttribute_from_wram_index
+0x81d51c: Dungeon_LoadToggleDoorAttr_OtherEntry
+0x81d51f: Dungeon_LoadSingleDoorTileAttribute
+0x81d5aa: DrawCompletelyOpenDoor
+0x81d6c1: Dungeon_ClearAwayExplodingWall
+0x81d748: Dungeon_CheckForAndIDLiftableTile
+0x81d7c0: kPushBlockMoveDistances
+0x81d7c8: PushBlock_Main
+0x81d81b: Dungeon_PushBlock_Handler
+0x81d828: RoomDraw_16x16Single
+0x81d87f: Dungeon_Store2x2Attr
+0x81d8d4: PushBlock_CheckForPit
+0x81d98e: RoomDraw_16x16SingleSingleTileStripe
+0x81d9ba: kDungeon_QueryIfTileLiftable_y
+0x81d9c2: kDungeon_QueryIfTileLiftable_x
+0x81d9e2: kDungeon_QueryIfTileLiftable_rv
+0x81d9ec: Dungeon_LiftAndReplaceLiftable
+0x81da71: ThievesAttic_DrawLightenedHole
+0x81dab6: FAIL_01DAB4
+0x81dabb: HandleItemTileAction_Dungeon
+0x81db41: ManipBlock_Something
+0x81db69: kDungeonSecretsPtrArray
+0x81e6b2: RevealPotItem
+0x81e795: kPrepSpriteInducedDma_Srcs
+0x81e7a9: Dungeon_UpdateTileMapWithCommonTile
+0x81e7df: Dungeon_PrepSpriteInducedDma
+0x81e899: Dungeon_GetRelativeVramAddr_2
+0x81e8bd: Dungeon_DeleteRupeeTile
+0x81e94a: Dungeon_GetRelativeVramAddr
+0x81e96e: chestinfo
+0x81eb66: OpenChestForItem
+0x81ed05: OpenBigChest
+0x81ed89: OpenMiniGameChestFail
+0x81eda3: kDungeon_MinigameChestPrizes1
+0x81edab: OpenMiniGameChest
+0x81eec5: Dungeon_OpenMiniGameChest_prizeExternallyDetermined
+0x81eed7: kDungeon_RupeeChestMinigamePrizes
+0x81eef7: OpenMiniGameChest_HighStake
+0x81eeff: Dungeon_GetRupeeChestMinigamePrize_lowStakes
+0x81ef0f: RoomTag_BuildChestStripes
+0x81ef34: kTurnOffWater_Tab0
+0x81ef54: IncrementallyDrainSwampPool
+0x81ef93: Dungeon_SetAttrForActivatedWaterOff
+0x81efec: DeleteSwampPoolWaterOverlay
+0x81f046: Dungeon_FloodSwampWater_PrepTileMap
+0x81f063: kTurnOnWater_Tab2
+0x81f06b: kTurnOnWater_Tab1
+0x81f073: kTurnOnWater_Tab0
+0x81f093: Dungeon_FloodSwampWater
+0x81f09b: Dungeon_FloodSwampWater_VomitWater
+0x81f0c9: Dungeon_AdjustWaterVomit
+0x81f16d: Dungeon_FloodSwampWater_SpillToFloor
+0x81f18c: Dungeon_TurnOnWaterLong_Func10
+0x81f1e1: Dungeon_FloodSwampWater_RiseInLevel
+0x81f237: Dungeon_SetAttrForActivatedWater
+0x81f2e8: kWatergateSrcs1
+0x81f2f2: kWatergateFuncs
+0x81f2fe: Dungeon_FloodDam
+0x81f309: EXIT_01F307
+0x81f30c: FloodDam_Expand
+0x81f3a7: FloodDam_PrepTiles_init
+0x81f3aa: Watergate_Main_State1
+0x81f3bd: FloodDam_Fill
+0x81f3db: Dungeon_LightTorchFail
+0x81f3ec: Dungeon_LightTorch
+0x81f3fd: Dungeon_LightTorch_notGanonRoom
+0x81f496: Ganon_ExtinguishTorch_adjust_translucency
+0x81f4a1: Ganon_ExtinguishTorch
+0x81f4a6: Dungeon_ExtinguishTorch
+0x81f528: SpiralStairs_MakeNearbyWallsHighPriority_Entering
+0x81f585: SpiralStairs_MakeNearbyWallsLowPriority
+0x81f5d1: kOpenGanonDoor_Tab
+0x81f5da: RoomDraw_OpenTriforceDoor
+0x81f6b4: UNREACHABLE_01F6B2
+0x81f746: RoomDraw_AdjustTorchLightingChange
+0x81f762: Dungeon_PrepOverlayDma_nextPrep_Start
+0x81f764: Dungeon_PrepOverlayDma_nextPrep
+0x81f77c: Dungeon_PrepOverlayDma_watergate
+0x81f7f1: kBlastWall_Tab2
+0x81f811: ClearAndStripeExplodingWall
+0x81f908: UNREACHABLE_01F906
+0x81f967: Dungeon_DrawRoomOverlay
+0x81f980: Dungeon_DrawOverlayOne
+0x81fa4a: GetDoorDrawDataIndex_North_clean_door_index
+0x81fa54: DoorDoorStep1_North
+0x81faa0: GetDoorDrawDataIndex_North
+0x81fad7: DrawDoorToTileMap_North
+0x81fae3: Object_Draw_DoorUp_4x3
+0x81fb0b: GetDoorDrawDataIndex_South_clean_door_index
+0x81fb15: DoorDoorStep1_South
+0x81fb61: GetDoorDrawDataIndex_South
+0x81fb8e: DrawDoorToTileMap_South
+0x81fb9b: Object_Draw_DoorDown_4x3
+0x81fbc2: GetDoorDrawDataIndex_West_clean_door_index
+0x81fbcc: DoorDoorStep1_West
+0x81fc18: GetDoorDrawDataIndex_West
+0x81fc45: DrawDoorToTileMap_West
+0x81fc80: GetDoorDrawDataIndex_East_clean_door_index
+0x81fc8a: DoorDoorStep1_East
+0x81fcd6: GetDoorDrawDataIndex_East
+0x81fd03: DrawDoorToTileMap_East
+0x81fd3e: ClearDoorCurtainsFromTileMap
+0x81fd79: GetDoorGraphicsIndex
+0x81fd92: ClearExplodingWallFromTileMap
+0x81fddb: ClearExplodingWallFromTileMap_ClearOnePair
+0x81fe41: Dungeon_DrawRoomOverlay_Apply
+0x81feb0: ApplyGrayscaleFixed_Incremental
+0x81fec1: Dungeon_ApproachFixedColor_variable
+0x81fed2: LinkZap_HandleMosaic
+0x81fef0: Player_SetCustomMosaicLevel
+0x81ff05: Dungeon_HandleLayerChange
+0x81ff28: CacheCameraProperties
+0x81ffb6: CheckAbilityToSwim
+0x81ffd9: TakeDamageFromPit
+0x828000: Intro_SetupScreen
+0x828054: Intro_ValidateSram
+0x828116: Intro_LoadTextPointersAndPalettes
+0x82811e: kDungAnimatedTiles
+0x828136: Module05_LoadFile
+0x828208: Module_LoadGame_indoors
+0x82821e: Module_PreDungeon
+0x82838c: Module_PreDungeon_setAmbientSfx
+0x8283b5: Dungeon_InitAndCacheVars2_
+0x8283b9: kModule_PreOverworld_Callb
+0x8283bf: Module08_OverworldLoad
+0x8283c7: PreOverworld_LoadProperties
+0x82854c: LoadOWMusicIfNeeded
+0x82856a: AdjustLinkBunnyStatus
+0x828570: ForceNonbunnyStatus
+0x828583: kLocationMenuStartPos
+0x828586: Module1B_SpawnSelect
+0x8285ba: Credits_LoadScene_Overworld
+0x8285c2: kEnding_Tab1
+0x8285e2: kEnding_SpritePack
+0x8285f3: kEnding_SpritePal
+0x828604: Credits_LoadScene_Overworld_PrepGFX
+0x828697: Credits_LoadScene_Overworld_Overlay
+0x8286a5: Credits_LoadScene_Overworld_LoadMap
+0x8286b3: Credits_OperateScrollingAndTileMap
+0x8286c0: Credits_LoadCoolBackground
+0x8286fd: Credits_LoadScene_Dungeon
+0x82876c: kDungeonSubmodules
+0x8287a2: Module07_Dungeon
+0x82885e: Dungeon_TryScreenEdgeTransition
+0x8288c1: kLimitDirectionOnOneAxis
+0x8288c5: Dungeon_HandleEdgeTransitionMovement
+0x8288de: Module07_00_PlayerControl
+0x82894c: kSpiralTab1
+0x828954: kBossRooms
+0x82896c: kDungeon_IntraRoomTransTable
+0x82897c: Module07_01_SubtileTransition
+0x828995: DungeonTransition_Subtile_ResetShutters
+0x8289b6: DungeonTransition_Subtile_PrepTransition
+0x8289d8: DungeonTransition_Subtile_ApplyFilter
+0x8289f0: DungeonTransition_Subtile_TriggerShutters
+0x828a26: Module07_02_SupertileTransition
+0x828a4f: Module07_02_00_InitializeTransition
+0x828a5b: Module07_02_01_LoadNextRoom
+0x828a87: Dungeon_InterRoomTrans_State3
+0x828aa5: Dungeon_InterRoomTrans_State10
+0x828aaf: Dungeon_SpiralStaircase11
+0x828ab3: Dungeon_InterRoomTrans_notDarkRoom
+0x828aba: Dungeon_InterRoomTrans_State9
+0x828ac4: Dungeon_SpiralStaircase12
+0x828ac8: Dungeon_InterRoomTrans_State4
+0x828acf: Dungeon_InterRoomTrans_State12
+0x828aed: Dungeon_Staircase14
+0x828aef: Dungeon_ResetTorchBackgroundAndPlayer
+0x828b0c: Dungeon_ResetTorchBackgroundAndPlayerInner
+0x828b2e: Dungeon_InterRoomTrans_State7
+0x828b67: DungeonTransition_RunFiltering
+0x828b92: Module07_02_FadedFilter
+0x828bae: Dungeon_InterRoomTrans_State15
+0x828bd7: Dungeon_PlayMusicIfDefeated
+0x828c05: Module07_03_OverlayChange
+0x828c0a: Module07_04_UnlockDoor
+0x828c0f: Module07_05_ControlShutters
+0x828c14: Module07_06_FatInterRoomStairs
+0x828c78: Module07_0E_01_HandleMusicAndResetProps
+0x828ca9: ResetTransitionPropsAndAdvance_ResetInterface
+0x828cac: ResetTransitionPropsAndAdvanceSubmodule
+0x828ce2: Dungeon_InitializeRoomFromSpecial
+0x828d01: DungeonTransition_FatStairs_RunFade
+0x828d10: DungeonTransition_LoadSpriteGFX
+0x828d1b: DungeonTransition_AdjustForFatStairScroll
+0x828d5f: DungeonTransition_FatStairsEntryCache
+0x828d71: ResetThenCacheRoomEntryProperties
+0x828d81: CacheRoomEntryProperties
+0x828e0f: DungeonTransition_TriggerBGC34UpdateAndAdvance
+0x828e1d: DungeonTransition_TriggerBGC56UpdateAndAdvance
+0x828e27: Module07_07_FallingTransition
+0x828e63: Module07_07_00_HandleMusicAndResetRoom
+0x828e80: Module07_07_06_SyncBG1and2
+0x828ea1: Module07_07_0F_FallingFadeIn
+0x828ec9: Dungeon_PlayBlipAndCacheQuadrantVisits
+0x828ee0: Module07_07_10_LandLinkFromFalling
+0x828efa: Module07_07_11_CacheRoomAndSetMusic
+0x828f0c: Module07_08_NorthIntraRoomStairs
+0x828f35: Module07_08_00_InitStairs
+0x828f5f: Module07_08_01_ClimbStairs
+0x828f88: Module07_10_SouthIntraRoomStairs
+0x828fb1: Module07_10_00_InitStairs
+0x828fe1: Module07_10_01_ClimbStairs
+0x82900f: Module07_09_OpenCrackedDoor
+0x829014: Module07_0A_ChangeBrightness
+0x82902d: Module07_0B_DrainSwampPool
+0x829032: Dungeon_TurnOffWater_
+0x82904a: Module07_0C_FloodSwampWater
+0x82904f: Module07_0D_FloodDam
+0x829054: Module07_0E_SpiralStairs
+0x829094: Dungeon_DoubleApplyAndIncrementGrayscale
+0x8290a1: Module07_0E_02_ApplyFilterIf
+0x8290c7: Dungeon_SyncBackgroundsFromSpiralStairs
+0x82915b: Dungeon_AdvanceThenSetBossMusicUnorthodox
+0x829165: Dungeon_SetBossMusicUnorthodox
+0x82919b: Dungeon_SpiralStaircase17
+0x8291b5: Dungeon_SpiralStaircase18
+0x8291c4: Module07_0E_00_InitPriorityAndScreens
+0x8291dd: Module07_0E_13_SetRoomAndLayerAndCache
+0x82920a: kSpiralStaircaseX
+0x829212: kSpiralStaircaseY
+0x82921a: RepositionLinkAfterSpiralStairs
+0x8292b1: SpiralStairs_MakeNearbyWallsHighPriority_Exiting
+0x82931d: Module07_0F_LandingWipe
+0x82932d: Module07_0F_00_InitSpotlight
+0x829334: Module07_0F_01_OperateSpotlight
+0x829357: Module07_11_StraightInterroomStairs
+0x8293bb: Module07_11_00_PrepAndReset
+0x8293ed: Module07_11_01_FadeOut
+0x829403: Module07_11_02_LoadAndPrepRoom
+0x829422: Module07_11_03_FilterAndLoadBGChars
+0x82942a: Module07_11_04_FilterDoBGAndResetSprites
+0x82943b: Module07_11_0B_PrepDestination
+0x8294e0: Module07_11_09_LoadSpriteGraphics
+0x8294ed: Module07_11_19_SetSongAndFilter
+0x829513: endif_1
+0x829518: Module07_11_11_KeepSliding
+0x829520: Module07_14_RecoverFromFall
+0x82952a: Module07_14_00_ScrollCamera
+0x829583: RecoverPositionAfterDrowning
+0x82967a: Module07_15_WarpPad
+0x8296ac: Module07_15_01_ApplyMosaicAndFilter
+0x8296ba: Module07_15_04_SyncRoomPropsAndBuildOverlay
+0x8296ec: Module07_15_0E_FadeInFromWarp
+0x82970f: Module07_15_0F_FinalizeAndCacheEntry
+0x82972a: Module07_16_UpdatePegs
+0x829739: Module07_16_UpdatePegs_Step1
+0x82974d: Module07_16_UpdatePegs_Step2
+0x829761: Module07_16_UpdatePegs_Step3
+0x829773: Dungeon_UpdatePegGFXBuffer
+0x8297a9: Module07_16_UpdatePegs_FinishUp
+0x8297b2: Dungeon_OrangeBlueBarrierUpload_C_
+0x8297c8: Module07_17_PressurePlate
+0x8297fa: kCrystal_Tab0
+0x82980a: Module07_18_RescuedMaiden
+0x829826: PrepareForCrystalCutscene
+0x829888: BuildCrystalCutsceneTilemap
+0x8298e7: StartCrystalCutscene
+0x8298f7: Module07_19_MirrorFade
+0x829916: Module07_1A_RoomDraw_OpenTriforceDoor_bounce
+0x82991b: Module0C_Unused
+0x829922: Module0C_RunSubmodule
+0x82992e: Module0C_RestoreModule
+0x829938: Module0D_Unused
+0x829951: Module0D_RunSubmodule
+0x82995b: Module0D_RestoreModule
+0x82997e: kModule_CloseSpotlight_Funcs
+0x829982: Module0F_SpotlightClose
+0x8299ca: Dungeon_PrepExitWithSpotlight
+0x829a19: Spotlight_ConfigureTableAndControl
+0x829a37: OpenSpotlight_Next2
+0x829ad3: kModule_OpenSpotlight_Funcs
+0x829ad7: Module10_SpotlightOpen
+0x829ae6: Module10_00_OpenIris
+0x829af9: Module11_DungeonFallingEntrance
+0x829b01: Module_11_00_SetSongAndInit
+0x829b1c: Module11_02_LoadEntrance
+0x829bd7: Dungeon_LoadSongBankIfNeeded
+0x829c0f: Module11_04_FadeAndLoadQuadrants
+0x829c1c: HoleToDungeon_5
+0x829c3e: kModule_BossVictory
+0x829c4a: Module13_BossVictory_Pendant
+0x829c59: BossVictory_Heal
+0x829c93: Dungeon_StartVictorySpin
+0x829cad: Dungeon_RunVictorySpin
+0x829cd1: Dungeon_CloseVictorySpin
+0x829cfc: Module15_MirrorWarpFromAga
+0x829d16: Module15_00_Initialize
+0x829d22: Module15_01_SetTheScene
+0x829d5d: Mirror_Func5
+0x829db6: Mirror_Func6
+0x829dc2: Mirror_Func7
+0x829df5: Mirror_Func8
+0x829e06: Module15_02_RunMirrorWarp_Part1
+0x829e0f: Module15_03_RunMirrorWarp_Part2
+0x829e15: Mirror_Func4
+0x829e22: Mirror_Func12
+0x829e5f: SetTargetOverworldWarpToPyramid
+0x829e6e: ResetAncillaAndCutscene
+0x829e8a: Module16_BossVictory_Crystal
+0x829e99: EXIT_029D90
+0x829e9a: Module16_04_FadeAndEnd
+0x829edc: Module18_GanonEmerges
+0x829f2f: GanonEmerges_GetBirdForPursuit
+0x829f42: GanonEmerges_PrepForPyramidLocation
+0x829f5e: GanonEmerges_FadeOutDungeonScreen
+0x829f76: GanonEmerges_LOadPyramidArea
+0x829f8b: GanonEmerges_LoadAmbientOverlay
+0x829f94: GanonEmerges_BrightenScreenThenSpawnBat
+0x829fc0: GanonEmerges_DelayForBatSmashIntoPyramid
+0x829fc1: GanonEmerges_DelayPlayerDropOff
+0x829fc9: GanonEmerges_DropOffPlayerAtPyramid
+0x829fce: kModule_TriforceRoom
+0x829fec: Module19_TriforceRoom
+0x82a021: Module19_00_ResetAndInit
+0x82a02f: Module19_01_MosaicAndPalette
+0x82a035: Module19_02_LoadMusicAndScreen
+0x82a065: Module19_03_PrepTileSetsPalette
+0x82a089: Module19_04_LoadAndSongAndAdvance
+0x82a0cd: Module19_05_WalkLinkIn
+0x82a0e4: Module19_06_MosaicFadeIn
+0x82a100: Module19_07_PrepMessage
+0x82a121: Module19_09_TriforceSpeak
+0x82a137: Module19_TriforceExpansionControl
+0x82a151: Module19_0B_ApproachTriforce
+0x82a164: Module19_0C_HoldTriforce
+0x82a173: Module19_0D_FadeToWhite
+0x82a186: Module19_0E_AdvanceToCredits
+0x82a1a4: kDungeonCrystalPendantBit
+0x82a1b1: Mirror_SaveRoomData
+0x82a1c7: SaveDungeonKeys
+0x82a1e5: kLitTorchesColorPlus
+0x82a1e9: Dungeon_HandleTranslucencyAndPalette
+0x82a281: UnusedInterfacePaletteRecovery
+0x82a29b: PaletteFilter_bounce
+0x82a2a0: PaletteFilter_doFiltering_
+0x82a2a5: Dungeon_Teleport0_
+0x82a2a9: Palette_Func1_
+0x82a2ad: UNUSED_sub_82A2AD
+0x82a2b1: UNREACHABLE_02A1A8
+0x82a2f0: Dungeon_AdjustAfterSpiralStairs
+0x82a37c: Dungeon_AdjustForTeleportDoors
+0x82a40d: kModule_Overworld_Submodules
+0x82a46d: kOverworld_DrawBadWeather_X
+0x82a471: kOverworld_DrawBadWeather_Y
+0x82a475: Module09_Overworld
+0x82a4cd: OverworldOverlay_HandleRain
+0x82a53c: Module09_00_PlayerControl
+0x82a5ec: kOverworldAreaHeads
+0x82a62c: kSwitchAreaTab0
+0x82a634: kSwitchAreaTab1
+0x82a834: kSwitchAreaTab3
+0x82a83c: kOverworld_Func6B_Tab4
+0x82a844: kOverworld_IsSmaller
+0x82a884: kOverworld_CoordMask
+0x82a8c4: kOverworld_OffsetBaseY
+0x82a944: kOverworld_OffsetBaseX
+0x82a9c4: OverworldHandleTransitions
+0x82ab08: Overworld_LoadGFXAndScreenSize
+0x82ab7b: ScrollAndCheckForSOWExit
+0x82ab88: Module09_LoadAuxGFX
+0x82abbc: Overworld_FinishTransGfx
+0x82abc6: Module09_LoadNewMapAndGFX
+0x82abda: Overworld_RunScrollTransition
+0x82abed: Module09_LoadNewSprites
+0x82ac27: Overworld_StartScrollTransition
+0x82ac3a: Overworld_EaseOffScrollTransition
+0x82ac8f: Module09_0A_WalkFromExiting_FacingDown
+0x82acc2: Module09_0B_WalkFromExiting_FacingUp
+0x82acda: kDoorAnimTiles
+0x82ad4a: Module09_09_OpenBigDoorFromExiting
+0x82ad5c: Overworld_DoMapUpdate32x32_B
+0x82ad63: UNREACHABLE_02AC62
+0x82ad6c: Module09_0C_OpenBigDoor
+0x82ad7b: Overworld_DoMapUpdate32x32_conditional
+0x82ad85: Overworld_DoMapUpdate32x32
+0x82ad87: DoorAnim_DoWork_
+0x82ae5a: DoorAnim_OnlyIncrement
+0x82ae5e: Overworld_StartMosaicTransition
+0x82ae6d: Overworld_FuncD_State0
+0x82ae86: OverworldMosaicTransition_HandleScreensAndLoadShroom
+0x82aece: UNUSED_Overworld_Func1D
+0x82aedd: Module09_1D_02_FBlankAndEnterModule0A
+0x82aeea: UNUSED_Overworld_Func1E
+0x82aef9: Module09_1E_02_FBlankAndLoadSPOW
+0x82af0b: Overworld_LoadOverlays
+0x82af19: PreOverworld_LoadOverlays
+0x82af1e: Overworld_LoadOverlays2
+0x82b0d2: Module09_FadeBackInFromMosaic
+0x82b0f3: OverworldMosaicTransition_RecoverDestinationPalettes
+0x82b105: Overworld_Func16_State2
+0x82b150: Overworld_Func1C
+0x82b171: OverworldMosaicTransition_LoadSpriteGraphicsAndSetMosaic
+0x82b195: OverworldMosaicTransition_FilterAndLoadGraphics
+0x82b19e: Module09_1C_02_HandleMusic
+0x82b1bb: Overworld_Func22
+0x82b1c8: Overworld_Func18
+0x82b1df: Overworld_Func19
+0x82b1f0: Overworld_LoadAmbientOverlayAndMapData_
+0x82b1f4: Overworld_ReloadSubscreenOverlayAndAdvance
+0x82b1fa: Module09_MirrorWarp
+0x82b1ff: Overworld_MirrorWarp_
+0x82b217: MirrorWarp_Initialize
+0x82b260: MirrorWarp_FinalizeAndLoadDestination
+0x82b2d4: MirrorWarp_HandleCastlePyramidSubscreen
+0x82b2e6: Overworld_DrawScreenAtCurrentMirrorPosition
+0x82b334: MirrorWarp_LoadSpritesAndColors
+0x82b40a: Overworld_Func2B
+0x82b40e: Overworld_WeathervaneExplosion
+0x82b40f: Module09_2E_Whirlpool
+0x82b432: Overworld_Whirlpool_Case0
+0x82b44c: Module09_2E_01_MoreBlue
+0x82b451: Overworld_Whirlpool_Case2
+0x82b456: Overworld_Whirlpool_Case11
+0x82b45f: Overworld_Whirlpool_Case10
+0x82b46e: Module09_2E_03_FindDestination
+0x82b48a: Overworld_Whirlpool_Case4_6
+0x82b490: Module09_2E_05_LoadDestinationMap
+0x82b49a: Module09_2E_07_LoadAuxGraphics
+0x82b49f: Module09_2E_08_TriggerTilemapUpdate
+0x82b4ae: Module09_2E_09_LoadPalettes
+0x82b4ef: Overworld_Whirlpool_Case12
+0x82b521: Overworld_Func2F
+0x82b528: Module09_2A_RecoverFromDrowning
+0x82b532: Module09_2A_00_ScrollToLand
+0x82b5ac: kLayoutQuadrantFlags
+0x82b5cc: kQuadrantVisitingFlags
+0x82b5dc: Dungeon_AdjustForRoomLayout
+0x82b62e: HandleEdgeTransitionMovementEast_RightBy8
+0x82b63a: Dungeon_StartInterRoomTrans_Right
+0x82b6cd: HandleEdgeTransitionMovementWest_LeftBy8
+0x82b6d9: HandleEdgeTransitionMovementWest_Left
+0x82b76e: HandleEdgeTransitionMovementSouth_DownBy16
+0x82b77a: HandleEdgeTransitionMovementSouth
+0x82b7ae: Dung_HandleExitToOverworld
+0x82b81c: HandleEdgeTransitionMovementNorth
+0x82b8bd: AdjustQuadrantAndCamera_right
+0x82b8cb: SetAndSaveVisitedQuadrantFlags
+0x82b8e5: SaveQuadrantsToSram
+0x82b8f9: AdjustQuadrantAndCamera_left
+0x82b909: AdjustQuadrantAndCamera_down
+0x82b919: AdjustQuadrantAndCamera_up
+0x82b929: Dungeon_FlagRoomData_Quadrants
+0x82b947: Dung_SaveDataForCurrentRoom
+0x82b968: AdjustCameraBoundaries_DownOrRight1Quadrant
+0x82b981: AdjustCameraBoundaries_DownOrRight1Supertile
+0x82b99a: AdjustCameraBoundaries_UpOrLeft1Quadrant
+0x82b9b3: AdjustCameraBoundaries_UpOrLeft1Supertile
+0x82b9cc: kCameraBoundsY
+0x82b9d4: kCameraBoundsX
+0x82b9dc: HandleEdgeTransition_AdjustCameraBoundaries
+0x82ba27: Dungeon_AdjustQuadrant
+0x82ba31: Dungeon_HandleCamera
+0x82bb7b: MirrorBg1Bg2Offs
+0x82bb88: kOverworld_Func2_Tab
+0x82bb90: Overworld_OperateCameraScroll
+0x82bd62: OverworldCameraBoundaryCheck
+0x82bdc8: DungeonTransition_AdjustCamera_X
+0x82bde2: DungeonTransition_AdjustCamera_Y
+0x82bdf3: kStaircaseTab3
+0x82bdfb: kStaircaseTab4
+0x82be03: DungeonTransition_ScrollRoom
+0x82be6d: kStaircaseTab5
+0x82be75: Module07_11_0A_ScrollCamera
+0x82beba: kOverworld_Func6B_Tab1
+0x82beca: kOverworld_Func6B_Tab3
+0x82bee2: kOverworld_UpDownScrollTarget
+0x82bf62: kOverworld_LeftRightScrollTarget
+0x82bfe2: kOverworld_Size1
+0x82bfe6: kOverworld_Size2
+0x82bfea: kOverworld_UpDownScrollSize
+0x82bfee: kOverworld_LeftRightScrollSize
+0x82bff2: kOverworld_Func6B_Tab2
+0x82bffa: OverworldScrollTransition_dirty_exit
+0x82c001: OverworldScrollTransition
+0x82c0c3: Overworld_SetCameraBoundaries
+0x82c0f8: kMult5tab
+0x82c0fc: kStaircaseTab2
+0x82c110: DungeonTransition_FindSubtileLanding
+0x82c12c: SubtileTransitionCalculateLanding
+0x82c162: Dungeon_InterRoomTrans_State13
+0x82c170: Dungeon_IntraRoomTrans_State5
+0x82c191: DungeonTransition_MoveLinkOutDoor
+0x82c1e5: CalculateTransitionLanding
+0x82c23e: kOverworld_Func8_tab
+0x82c242: Overworld_FinalizeEntryOntoScreen
+0x82c2a4: Overworld_Func1F
+0x82c2e4: ConditionalMosaicControl
+0x82c2eb: Overworld_ResetMosaic_alwaysIncrease
+0x82c303: kOwMusicSets
+0x82c403: kOwMusicSets2
+0x82c463: Overworld_SetSongList
+0x82c500: Intro_InitializeBackgroundSettings
+0x82c533: Dungeon_LoadAndDrawEntranceRoom
+0x82c546: Dungeon_SaveAndLoadLoadAllPalettes
+0x82c57b: Dungeon_LoadAndDrawRoom
+0x82c5b2: Overworld_LoadAllPalettes
+0x82c630: Dungeon_LoadPalettes
+0x82c65f: Overworld_LoadPalettesInner
+0x82c68e: Overworld_LoadAreaPalettes_
+0x82c692: OverworldLoadScreensPaletteSet
+0x82c6ad: Overworld_LoadAreaPalettesEx
+0x82c6eb: SpecialOverworld_CopyPalettesToCache
+0x82c769: Overworld_CopyPalettesToCache
+0x82c7b8: CleanUpAndPrepDesertPrayerHDMA
+0x82c80c: kHdmaTableForPrayingScene
+0x82c813: kEntranceData_rooms
+0x82c91d: kEntranceData_relativeCoords
+0x82cd45: kEntranceData_scrollX
+0x82ce4f: kEntranceData_scrollY
+0x82cf59: kEntranceData_playerY
+0x82d063: kEntranceData_playerX
+0x82d16d: kEntranceData_cameraY
+0x82d277: kEntranceData_cameraX
+0x82d381: kEntranceData_blockset
+0x82d406: kEntranceData_floor
+0x82d48b: kEntranceData_palace
+0x82d510: kEntranceData_doorwayOrientation
+0x82d595: kEntranceData_startingBg
+0x82d61a: kEntranceData_quadrant1
+0x82d69f: kEntranceData_quadrant2
+0x82d724: kEntranceData_doorSettings
+0x82d82e: kEntranceData_musicTrack
+0x82d8b3: Dungeon_LoadEntrance
+0x82dadb: Dungeon_LoadEntrance_notExtendedRoom
+0x82db6e: kStartingPoint_rooms
+0x82db7c: kStartingPoint_relativeCoords
+0x82dbb4: kStartingPoint_scrollX
+0x82dbc2: kStartingPoint_scrollY
+0x82dbd0: kStartingPoint_playerY
+0x82dbde: kStartingPoint_playerX
+0x82dbec: kStartingPoint_cameraY
+0x82dbfa: kStartingPoint_cameraX
+0x82dc08: kStartingPoint_blockset
+0x82dc0f: kStartingPoint_floor
+0x82dc16: kStartingPoint_palace
+0x82dc1d: kStartingPoint_startingBg
+0x82dc24: kStartingPoint_quadrant1
+0x82dc2b: kStartingPoint_quadrant2
+0x82dc32: kStartingPoint_doorSettings
+0x82dc40: kStartingPoint_entrance
+0x82dc4e: kStartingPoint_musicTrack
+0x82dc55: Dungeon_LoadSpawnEntrance
+0x82dd8a: kExitDataRooms
+0x82de28: kExitData_ScreenIndex
+0x82de77: kExitData_Map16LoadSrcOff
+0x82df15: kExitData_ScrollY
+0x82dfb3: kExitData_ScrollX
+0x82e051: kExitData_YCoord
+0x82e0ef: kExitData_XCoord
+0x82e18d: kExitData_CameraY
+0x82e22b: kExitData_CameraX
+0x82e2c9: kExitData_Unk1
+0x82e318: kExitData_Unk3
+0x82e367: kExitData_NormalDoor
+0x82e405: kExitData_FancyDoor
+0x82e4a3: LoadOverworldFromDungeon
+0x82e58b: Overworld_LoadNewScreenProperties
+0x82e5d4: LoadCachedEntranceProperties
+0x82e6e1: kSpExit_SizeY
+0x82e701: kSpExit_Tab1
+0x82e721: kSpExit_Tab2
+0x82e741: kSpExit_Tab3
+0x82e761: kSpExit_Tab4
+0x82e781: kSpExit_Tab6
+0x82e7a1: kSpExit_Tab5
+0x82e7c1: kSpExit_Tab7
+0x82e7e1: kSpExit_SizeX
+0x82e801: kSpExit_Dir
+0x82e811: kSpExit_SprGfx
+0x82e821: kSpExit_AuxGfx
+0x82e831: kSpExit_PalBg
+0x82e841: kSpExit_PalSpr
+0x82e851: Overworld_EnterSpecialArea
+0x82e9bc: LoadOverworldFromSpecialOverworld
+0x82eae5: kBirdTravel_ScreenIndex
+0x82eb07: kBirdTravel_Map16LoadSrcOff
+0x82eb29: kBirdTravel_ScrollY
+0x82eb4b: kBirdTravel_ScrollX
+0x82eb6d: kBirdTravel_LinkYCoord
+0x82eb8f: kBirdTravel_LinkXCoord
+0x82ebb1: kBirdTravel_CameraYScroll
+0x82ebd3: kBirdTravel_CameraXScroll
+0x82ebf5: kBirdTravel_Unk1
+0x82ec17: kBirdTravel_Unk3
+0x82ec39: FluteMenu_LoadTransport
+0x82ec47: Overworld_LoadBirdTravelPos
+0x82ecdd: FluteMenu_LoadSelectedScreenPalettes
+0x82ecf8: kWhirlpoolAreas
+0x82ed08: FindPartnerWhirlpoolExit
+0x82ed25: Overworld_LoadAmbientOverlay
+0x82ed59: Overworld_LoadAndBuildScreen
+0x82edb9: Module08_02_LoadAndAdvance
+0x82edc5: kSecondaryOverlayPerOw
+0x82eec5: Overworld_DrawQuadrantsAndOverlays
+0x82ef29: Overworld_HandleOverlaysAndBombDoors
+0x82ef7a: TriggerAndFinishMapLoadStripe_Y
+0x82efb3: TriggerAndFinishMapLoadStripe_X
+0x82efe8: SomeTileMapChange
+0x82f00d: Overworld_LargeTransTable
+0x82f01f: Overworld_SmallTransTable
+0x82f031: CreateInitialNewScreenMapToScroll
+0x82f04b: UNREACHABLE_02EDAF
+0x82f06b: CreateInitialOWScreenView_Big_North
+0x82f087: CreateInitialOWScreenView_Big_South
+0x82f0c0: CreateInitialOWScreenView_Big_West
+0x82f0dc: CreateInitialOWScreenView_Big_East
+0x82f10f: CreateInitialOWScreenView_Small_North
+0x82f141: CreateInitialOWScreenView_Small_South
+0x82f185: CreateInitialOWScreenView_Small_West
+0x82f1b7: CreateInitialOWScreenView_Small_East
+0x82f20e: OverworldTransitionScrollAndLoadMap
+0x82f218: BuildFullStripeDuringTransition_North
+0x82f238: BuildFullStripeDuringTransition_South
+0x82f241: BuildFullStripeDuringTransition_West
+0x82f24a: BuildFullStripeDuringTransition_East
+0x82f273: OverworldHandleMapScroll
+0x82f2a2: Overworld_ResetSubmodule
+0x82f2a5: MapScroll_East
+0x82f2ac: MapScroll_West
+0x82f2b3: MapScroll_South
+0x82f2ba: MapScroll_SouthAndClear
+0x82f2c8: MapScroll_North
+0x82f2cf: MapScroll_NorthAndClear
+0x82f2dd: CheckForNewlyLoadedMapAreas_North
+0x82f311: CheckForNewlyLoadedMapAreas_South
+0x82f345: CheckForNewlyLoadedMapAreas_West
+0x82f37f: CheckForNewlyLoadedMapAreas_East
+0x82f3b9: BufferAndBuildMap16Stripes_X
+0x82f482: BufferAndBuildMap16Stripes_Y
+0x82f54a: Overworld_DecompressAndDrawAllQuadrants
+0x82f595: Overworld_DecompressAndDrawOneQuadrant
+0x82f638: InterlaceMap32_highBytes
+0x82f650: next
+0x82f679: InterlaceMap32_lowBytes
+0x82f691: Overworld_ParseMap32Definition
+0x82f7cb: OverworldLoad_LoadSubOverlayMap32
+0x82f883: kOverworld_DrawStrip_Tab
+0x82f889: kConstant0
+0x82f88b: kConstant32
+0x82f88d: kOverworldMapIsSmall
+0x82f94d: kOverworld_Hibytes_Comp
+0x82fb2d: kOverworld_Lobytes_Comp
+0x82fd0d: LoadOverworldOverlay
+0x82fd26: Map16ToMap8_subscreenOverlay
+0x82fd37: BuildOverworldMapFromMap16
+0x82fd46: Map16ToMap8
+0x82fd87: OverworldCopyMap16ToBuffer
+0x82fdf7: Map16ChunkToMap8_prepForUpload
+0x82fe47: MirrorBonk_RecoverChangedTiles
+0x82fe71: DecompressEnemyDamageSubclasses
+0x82febb: Decompress_bank02
+0x82ff5f: OverworldDecomp_GetNextSourceOctet
+0x838000: ov_tiledata_0
+0x83b400: ov_tiledata_1
+0x848000: ov_tiledata_2
+0x84b400: ov_tiledata_3
+0x84e800: kSinusLookupTable
+0x84ea00: kHobo_Dmd
+0x84ea60: Hobo_Draw
+0x84ea81: Landmine_CheckDetonationFromHammer
+0x84ea9d: EasterEgg_BageCode
+0x84eb63: Bomb_ProjectSpeedTowardsPlayer
+0x84ebaa: Bomb_ProjectReflexiveSpeedOntoSpriteLong
+0x84ebb3: kWaterTurbulence_Dmd
+0x84ebe5: Sprite_DrawLargeWaterTurbulence
+0x84ef2f: kDungeonLayoutPtrs
+0x84ef47: kDungeonLayoutPtrs_00
+0x84efaf: kDungeonLayoutPtrs_01
+0x84eff0: kDungeonLayoutPtrs_02
+0x84f04c: kDungeonLayoutPtrs_03
+0x84f0a8: kDungeonLayoutPtrs_04
+0x84f0ec: kDungeonLayoutPtrs_05
+0x84f148: kDungeonLayoutPtrs_06
+0x84f1a4: kDungeonLayoutPtrs_07
+0x84f1cd: kWatergateLayout
+0x84f1de: kMovableBlockDataInit
+0x84f36a: kTorchDataInit
+0x84f48a: kTorchDataJunk
+0x84f502: kDungeonHeaderPtrs
+0x84f80a: baba_nk_84F80A
+0x858000: kSparkleGarnish_Coord
+0x858008: Sprite_SpawnSparkleGarnish
+0x85807f: Sprite_70_KingHelmasaurFireball_bounce
+0x858084: kWallCannon_Xvel
+0x858086: kWallCannon_Yvel
+0x858088: kWallCannon_Gfx
+0x85808c: kWallCannon_OamFlags
+0x858090: Sprite_66_WallCannonVerticalLeft
+0x85815e: kWallCannon_Spawn_X
+0x858162: kWallCannon_Spawn_XHi
+0x858166: kWallCannon_Spawn_Y
+0x85816a: kWallCannon_Spawn_YHi
+0x85816e: kWallCannon_Spawn_Xvel
+0x858172: kWallCannon_Spawn_Yvel
+0x858176: kArcheryGameGuy_X
+0x85817e: kArcheryGameGuy_Y
+0x858186: kArcheryGameGuy_A
+0x85818e: kArcheryGameGuy_Xvel
+0x858190: kArcheryGameGuy_Flags4
+0x858192: SpritePrep_ArrowGame
+0x8581ff: Sprite_65_ArcheryGame
+0x858213: kArcheryGameGuy_Gfx
+0x858217: ArcheryGame_Host
+0x8582bf: ArcheryGameGuy_ShowMsg
+0x8582d4: ArcheryGame_Host_ProctorGame
+0x858381: kArcheryGame_NumSpr
+0x858387: kArcheryGame_X
+0x858399: kArcheryGame_Y
+0x8583ab: kArcheryGame_Char
+0x8583bd: kArcheryGame_Flags
+0x8583ce: kArcheryGame_CashPrize
+0x8583d9: Sprite_ArcheryGame_Octo
+0x85844e: Sprite_BadArcheryTarget
+0x858492: kArcheryTarget_X
+0x8584af: kGoodArcheryTarget_X
+0x8584b4: kGoodArcheryTarget_Y
+0x8584b9: kGoodArcheryTarget_Draw_Char
+0x8584be: kGoodArcheryTarget_Draw_Flags
+0x8584c2: kGoodArcheryTarget_Draw_Char3
+0x8584c8: kGoodArcheryTarget_Draw_Char4
+0x8584cf: ArcheryGame_DrawPrize
+0x858531: Sprite_63_DebirandoPit
+0x8585de: DebirandoPit_Closed
+0x8585f1: kDebirandoPit_OpeningGfx
+0x8585f5: DebirandoPit_Opening
+0x85860f: DebirandoPit_Open
+0x858630: kDebirandoPit_ClosingGfx
+0x858634: DebirandoPit_Closing
+0x85864e: kDebirandoPit_Draw_X
+0x85867e: kDebirandoPit_Draw_Y
+0x8586ae: kDebirandoPit_Draw_Char
+0x8586c6: kDebirandoPit_Draw_Flags
+0x8586de: kDebirandoPit_Draw_Ext
+0x8586e4: DebirandoPit_Draw
+0x85874d: Sprite_64_Debirando
+0x858762: Debirando_Underground
+0x858773: kDebirando_Emerge_Gfx
+0x858775: Debirando_Emerge
+0x858792: Debirando_Shoot
+0x8587c8: kDebirando_Submerge_Gfx
+0x8587ca: Debirando_Submerge
+0x8587e7: kDebirando_Draw_X
+0x858807: kDebirando_Draw_Y
+0x858827: kDebirando_Draw_Char
+0x858837: kDebirando_Draw_Flags
+0x858847: kDebirando_Draw_Ext
+0x858857: Debirando_Draw
+0x8588c5: Sprite_62_MasterSword
+0x8588d6: MasterSword_Main
+0x858908: MasterSword_ReadyAndWaiting
+0x85894d: MasterSword_PendantsInTransit
+0x858968: MasterSword_CrankUpLightShow
+0x85899d: MasterSword_GrantToPlayer
+0x8589c6: MasterSword_Terminate
+0x8589ca: kMasterSword_Gfx1
+0x8589d3: kMasterSword_NumLightBeams
+0x8589dc: Sprite_MasterSword_LightFountain
+0x858a16: Sprite_MasterSword_LightWell
+0x858a34: kMasterSword_LightBall_Dmd
+0x858a94: SpriteDraw_LightFountain
+0x858ab1: Sprite_DrawMultiple_
+0x858ab6: MasterSword_SpawnLightWell
+0x858ad0: MasterSword_SpawnLightFountain
+0x858aea: Sprite_MasterSword_LightBeam
+0x858b08: kMasterSword_LightBeam_Xv0
+0x858b0a: kMasterSword_LightBeam_Xv1
+0x858b0c: kMasterSword_LightBeam_Xv2
+0x858b0e: kMasterSword_LightBeam_Xv3
+0x858b10: kMasterSword_LightBeam_Yv0
+0x858b12: kMasterSword_LightBeam_Yv1
+0x858b14: kMasterSword_LightBeam_Yv2
+0x858b16: kMasterSword_LightBeam_Yv3
+0x858b18: kMasterSword_LightBeam_Gfx0
+0x858b1a: kMasterSword_LightBeam_Gfx2
+0x858b1c: kMasterSword_LightBeam_Flags0
+0x858b1e: kMasterSword_LightBeam_Flags2
+0x858b20: MasterSword_SpawnReplacementLightBeam
+0x858b62: MasterSword_SpawnLightBeam
+0x858cd3: MasterSword_SpawnPendantProp
+0x858d21: kMasterSword_Pendant_Xv
+0x858d25: kMasterSword_Pendant_Yv
+0x858d29: Sprite_MasterSword_Prop
+0x858d40: MasterSword_Prop_Floating
+0x858d57: MasterSword_Prop_Flashing
+0x858d7a: MasterSword_Prop_FlyAwayNow
+0x858d96: kMasterSword_Draw_X
+0x858d9c: kMasterSword_Draw_Y
+0x858da2: kMasterSword_Draw_Char
+0x858da8: MasterSword_Draw
+0x858dd8: kSpikeRoller_XYvel
+0x858dde: Sprite_5D_Roller_VerticalDownFirst
+0x858e21: kSpikeRoller_Draw_X
+0x858e61: kSpikeRoller_Draw_Y
+0x858ea1: kSpikeRoller_Draw_Char
+0x858ec1: kSpikeRoller_Draw_Flags
+0x858ee1: kSpikeRoller_Draw_Num
+0x858ee3: SpikeRoller_Draw
+0x858f54: Sprite_61_Beamos
+0x858fc2: Beamos_FireLaser
+0x859062: kBeamos_Draw_Y
+0x859066: kBeamos_Draw_Char
+0x859068: Beamos_Draw
+0x8590d1: kBeamosEyeball_Draw_X
+0x8590f1: kBeamosEyeball_Draw_Y
+0x859111: kBeamosEyeball_Draw_Char
+0x859131: kBeamosEyeball_Draw_Flags
+0x859151: SpriteDraw_Beamos_Eyeball
+0x8591b5: Sprite_Beamos_Laser
+0x859257: Sprite_PrepOamCoord_wrapper
+0x85925b: BeamosLaser_Draw
+0x8592c6: kBeamosLaserHit_Draw_X
+0x8592ce: kBeamosLaserHit_Draw_Y
+0x8592d6: kBeamosLaserHit_Draw_Flags
+0x8592da: Sprite_Beamos_LaserHit
+0x859333: kSpark_OamFlags
+0x859337: kSpark_directions
+0x85933f: Sprite_5B_Spark_Clockwise
+0x85940e: Sprite_59_LostWoodsBird
+0x85944c: LostWoodsBird_Ascend
+0x859468: Sprite_5A_LostWoodsSquirrel
+0x8594af: kCrab_Xvel
+0x8594b1: kCrab_Yvel
+0x8594b5: Sprite_58_Crab
+0x859500: kCrab_Draw_X
+0x859508: kCrab_Draw_Char
+0x85950c: kCrab_Draw_Flags
+0x859510: Crab_Draw
+0x85956d: Sprite_57_DesertStatue
+0x8595fc: kDesertBarrier_Xv
+0x8595fe: kDesertBarrier_Yv
+0x859602: kDesertBarrier_NextD
+0x859606: kDesertBarrier_Dmd
+0x859626: DesertBarrier_Draw
+0x85966a: kSprite_ZoraFireball_X
+0x85966e: kSprite_ZoraFireball_Offs
+0x859670: kSprite_ZoraFireball_XHi
+0x859673: kSprite_ZoraFireball_Y
+0x859675: kSprite_ZoraFireball_W
+0x859677: kSprite_ZoraFireball_H
+0x85967b: Sprite_55_Zora
+0x859683: Sprite_Fireball
+0x859725: Sprite_Zora_Main
+0x85974a: kSprite_Zora_Surface_XY
+0x85975a: Zora_Submerged
+0x8597b5: kSprite_Zora_SurfacingGfx
+0x8597c5: Zora_Surface
+0x8597e9: kSprite_Zora_AttackGfx
+0x8597f1: Zora_Attack
+0x859818: kSprite_Zora_SubmergeGfx
+0x859824: Zora_Submerge
+0x85983f: kZora_Draw_X
+0x859873: kZora_Draw_Y
+0x8598a7: kZora_Draw_Char
+0x8598c1: kZora_Draw_Flags
+0x8598db: kZora_Draw_Ext
+0x8598f5: Zora_Draw
+0x85995b: Sprite_52_KingZora
+0x85997a: KingZora_Idle
+0x8599d5: kWalkingZora_Xdelta
+0x8599d9: KingZora_TheRumbling
+0x859a07: kZoraKing_Surfacing_Gfx
+0x859a17: KingZora_Surface
+0x859a3e: kZoraKing_Dialogue_Gfx
+0x859a46: KingZora_Talking
+0x859acf: kZoraKing_Submerge_Gfx
+0x859ae4: KingZora_Submerge
+0x859b08: kSpawnSplashRing_X
+0x859b18: kSpawnSplashRing_Y
+0x859b28: kSpawnSplashRing_Xvel
+0x859b30: kSpawnSplashRing_Yvel
+0x859b38: Sprite_Arrghus_SpawnSplash
+0x859b40: Sprite_SpawnBigSplash
+0x859bbb: kZoraKing_Draw_X0
+0x859bef: kZoraKing_Draw_Y0
+0x859c23: kZoraKing_Draw_Char0
+0x859c57: kZoraKing_Draw_Flags0
+0x859c8b: kZoraKing_Draw_X1
+0x859c93: kZoraKing_Draw_Y1
+0x859c9b: kZoraKing_Draw_Char1
+0x859ca3: kZoraKing_Draw_Flags1
+0x859cab: ZoraKing_Draw
+0x859d4a: Sprite_56_WalkingZora
+0x859d7f: WalkingZora_Wait
+0x859d9c: WalkingZora_Surface
+0x859dd6: WalkingZora_Walking
+0x859e66: WalkingZora_Stunned
+0x859edb: WalkingZora_AdjustShadow
+0x859ef0: kWalkingZora_Draw_Char
+0x859ef4: kWalkingZora_Draw_Flags
+0x859ef8: kWalkingZora_Draw_Char2
+0x859f00: kWalkingZora_Draw_Flags2
+0x859f08: WalkingZora_Draw
+0x859fac: kWaterRipple_Dmd
+0x859fdc: kWaterRipple_Idx
+0x859fe0: WalkingZora_DrawWaterRipples
+0x859fe5: SpriteDraw_WaterRipple_WithOamAdjust
+0x859ffa: SpriteDraw_WaterRipple
+0x85a029: Sprite_AutoIncDrawWaterRipple_
+0x85a031: kArmosKnight_Gfx1
+0x85a036: Sprite_53_ArmosKnight
+0x85a18f: ArmosKnight_ProjectSpeedTowardsTarget
+0x85a1b4: kArmosKnight_Draw_X
+0x85a1e4: kArmosKnight_Draw_Y
+0x85a214: kArmosKnight_Draw_Char
+0x85a22c: kArmosKnight_Draw_Flags
+0x85a244: kArmosKnight_Draw_Ext
+0x85a25c: kArmosKnight_SprOffs
+0x85a274: ArmosKnight_Draw
+0x85a377: kLanmola_InitDelay
+0x85a37a: SpritePrep_Lanmolas
+0x85a3a2: Sprite_54_Lanmolas
+0x85a3bf: Sprite_Lanmolas_Hiding
+0x85a3d6: kLanmola_RandB
+0x85a3de: kLanmola_RandC
+0x85a3e6: Sprite_Lanmolas_BurrowingUp
+0x85a42f: kLanmola_ZVel
+0x85a431: Sprite_Lanmolas_LeapFromSand
+0x85a4cb: Sprite_Lanmolas_WiggleInAir
+0x85a4f2: Sprite_Lanmolas_BurrowDown
+0x85a515: kMult8
+0x85a51d: Ancilla_SpawnFallingPrize
+0x85a529: Sprite_Lanmolas_Exploding
+0x85a5da: kLanmola_Mult64
+0x85a5de: kLanmola_ObjOffs
+0x85a5e0: kLanmola_ObjStep
+0x85a5e2: kLanmola_Draw_Char1
+0x85a5f2: kLanmola_Draw_Char0
+0x85a602: kLanmola_Draw_Flags
+0x85a612: kLanmola_Draw_X4
+0x85a61a: kLanmola_Draw_Y4
+0x85a622: kLanmola_Draw_Char4
+0x85a62a: kLanmola_Draw_Flags4
+0x85a632: kLanmola_Draw_Ext4
+0x85a63a: kLanmola_SprOffs
+0x85a642: kLanmola_ExtSprOffs
+0x85a64a: Lanmola_Draw
+0x85a864: kLanmola_Draw_Char2
+0x85a86a: kLanmola_Draw_Flags2
+0x85a870: kLanmola_Draw_Idx2
+0x85a880: kSpriteRat_Tab0
+0x85a890: kSpriteRat_Tab1
+0x85a8a0: kSpriteRat_Tab2
+0x85a8a8: kSpriteRat_Tab4
+0x85a8b0: Sprite_6D_Rat
+0x85a90b: kSpriteRat_Xvel
+0x85a90f: kSpriteRat_Yvel
+0x85a913: kSpriteRat_Tab3
+0x85a917: Rat_Moving
+0x85a95b: kSpriteRope_Gfx
+0x85a963: kSpriteRope_Flags
+0x85a96b: kSpriteRope_Tab1
+0x85a973: Sprite_6E_Rope
+0x85aa30: kSpriteRope_Xvel
+0x85aa38: kSpriteRope_Yvel
+0x85aa40: kSpriteRope_Tab0
+0x85aa44: Rope_Moving
+0x85aa87: kSpriteKeese_Tab0
+0x85aa8b: Sprite_6F_Keese
+0x85aae2: kSpriteKeese_Tab1
+0x85aae4: kSpriteKeese_Tab2
+0x85aaf4: kSpriteKeese_Tab3
+0x85ab04: Keese_Agitated
+0x85ab54: Sprite_Cannonball
+0x85ab93: Sprite_CheckDamageToAndFromLink
+0x85ab9c: Sprite_SpawnPoofGarnish
+0x85abe4: Sprite_6B_Cannonball
+0x85ac34: CannonGuard_FaceLink
+0x85ac52: CannonGuard_Charge
+0x85ac7b: CannonTrooper_SpawnCannonBall_UNUSED
+0x85acf2: CannonGuard_Fire
+0x85ad12: CannonGuard_Recoil
+0x85ad28: CannonGuard_Recover
+0x85aef9: SpriteDraw_CannonGuard
+0x85af71: kSprite_WarpVortex_Flags
+0x85af75: Sprite_6C_MirrorPortal
+0x85b019: kChainBallTrooper_Tab1
+0x85b01b: Sprite_6A_BallNChain
+0x85b07d: BallNChain_Approach
+0x85b0ab: BallNChain_Animate
+0x85b0c7: kFlailTrooperGfx
+0x85b0e7: BallNChain_Steady
+0x85b0f8: kFlailTrooperAttackDir
+0x85b0fc: BallNChain_SpinFlail
+0x85b12e: BallNChain_SlowFlail
+0x85b144: Sprite_ChainBallTrooper_Draw
+0x85b156: kChainBallTrooperHead_Char
+0x85b15a: kChainBallTrooperHead_Flags
+0x85b15e: SpriteDraw_BNCHead
+0x85b160: SpriteDraw_GuardHead
+0x85b1a3: kFlailTrooperBody_X
+0x85b233: kFlailTrooperBody_Y
+0x85b2c3: kFlailTrooperBody_Char
+0x85b30b: kFlailTrooperBody_Flags
+0x85b353: kFlailTrooperBody_Ext
+0x85b39b: kFlailTrooperBody_Num
+0x85b3b3: kFlailTrooperBody_SprOffs
+0x85b3cb: SpriteDraw_BNCBody
+0x85b3cd: SpriteDraw_GuardBody
+0x85b440: kFlailTrooperWeapon_Tab0
+0x85b460: kFlailTrooperWeapon_Tab1
+0x85b464: kFlailTrooperWeapon_Tab2
+0x85b468: SpriteDraw_BNCFlail
+0x85b5ba: kFlailTrooperWeapon_Tab4
+0x85b5be: NOP4
+0x85b5c3: SpriteModule_Active
+0x85b5cb: kSoldier_DirectionLockSettings
+0x85b5cf: kSoldier_Gfx
+0x85b5d3: SpriteActive2_Main
+0x85b5e8: kSpriteActive2Trampoline
+0x85b648: Sprite_50_Cannonball
+0x85b688: kMetalBallLarge_X
+0x85b690: kMetalBallLarge_Y
+0x85b698: kMetalBallLarge_Char
+0x85b6a0: kMetalBallLarge_Flags
+0x85b6a4: SpriteDraw_BigCannonball
+0x85b703: Sprite_51_ArmosStatue
+0x85b7df: kArmos_Dmd
+0x85b7ef: Armos_Draw
+0x85b80a: Sprite_4E_Popo
+0x85b88d: Sprite_CheckTileCollision
+0x85b892: kBot_Gfx
+0x85b896: kBot_OamFlags
+0x85b89a: Bot_Draw
+0x85b8b3: Sprite_4C_Geldman
+0x85b8ea: Geldman_Hiding
+0x85b90b: Geldman_WaitForLink
+0x85b93f: Geldman_Ambush
+0x85b95d: kGerudoMan_EmergeGfx
+0x85b965: kGerudoMan_PursueGfx
+0x85b967: kGerudoMan_SubmergeGfx
+0x85b96c: Geldman_Chase
+0x85b98f: Geldman_Retreat
+0x85b9a6: kGerudoMan_Draw_X
+0x85b9ca: kGerudoMan_Draw_Y
+0x85b9ee: kGerudoMan_Draw_Char
+0x85ba00: kGerudoMan_Draw_Flags
+0x85ba12: kGerudoMan_Draw_Ext
+0x85ba24: GerudoMan_Draw
+0x85ba85: Sprite_4D_Toppo
+0x85bab6: kToppo_XOffs
+0x85babe: kToppo_YOffs
+0x85bac6: Toppo_Hiding
+0x85bb01: Toppo_RustleGrass
+0x85bb1a: Toppo_PokingOut
+0x85bb30: Toppo_Leaping
+0x85bb53: Toppo_Retreat
+0x85bb6d: Toppo_Flustered_bounce
+0x85bb72: Toppo_VerifyTile
+0x85bb96: kToppo_Draw_X
+0x85bbb4: kToppo_Draw_Y
+0x85bbd2: kToppo_Draw_Char
+0x85bbe1: kToppo_Draw_Flags
+0x85bbf0: kToppo_Draw_Ext
+0x85bbff: Toppo_Draw
+0x85bc8a: kSprite_Recruit_Xvel
+0x85bc92: kSprite_Recruit_Yvel
+0x85bc9a: kSprite_Recruit_Gfx
+0x85bca2: Sprite_4B_GreenKnifeGuard
+0x85bd16: kRecruit_Moving_HeadDir
+0x85bd1e: GreenKnifeGuard_Moving
+0x85bd52: ZoraAndGuardAdvanceAnimation
+0x85bd5e: kRecruit_Draw_X
+0x85bd6e: kRecruit_Draw_Char
+0x85bd76: kRecruit_Draw_Flags
+0x85bd7e: Recruit_Draw
+0x85be0a: Sprite_4A_BombGuard
+0x85be49: SpriteBomb_CheckDamageToSprite
+0x85bed3: SpriteBomb_ExplosionIncoming
+0x85bf51: BombGuard
+0x85bfb1: kBombTrooperBomb_X
+0x85bfb9: kBombTrooperBomb_Y
+0x85bfc1: BombGuard_CreateBomb
+0x85c03b: kBombTrooperBomb_Zvel
+0x85c04b: BombTrooper_Draw
+0x85c069: kBombTrooper_DrawArm_X
+0x85c079: kBombTrooper_DrawArm_Y
+0x85c089: SpriteDraw_BombGuard_Arm
+0x85c0d3: kEnemyBombExplosion_X
+0x85c0e3: kEnemyBombExplosion_Y
+0x85c0f3: kEnemyBombExplosion_Char
+0x85c103: kEnemyBombExplosion_Flags
+0x85c113: SpriteDraw_SpriteBombExplosion
+0x85c155: Sprite_41_BlueGuard
+0x85c15d: Probe
+0x85c227: Guard_Main
+0x85c2d0: kSoldier_Delay
+0x85c2d4: Guard_Idle
+0x85c32b: Guard_SetGlanceTo12
+0x85c331: kSoldier_Xvel
+0x85c335: kSoldier_Yvel
+0x85c339: kSoldier_Gfx2
+0x85c359: kSoldierB_Xvel
+0x85c361: kSoldierB_Yvel
+0x85c369: kSoldierB_Xvel2
+0x85c371: kSoldierB_Yvel2
+0x85c379: kSoldierB_Dir
+0x85c381: kSoldierB_Mask2
+0x85c389: kSoldierB_Mask
+0x85c391: kSoldierB_NextB2
+0x85c399: kSoldierB_NextB
+0x85c3a1: Guard_ShootProbeAndStuff
+0x85c403: Guard_OnPatrol
+0x85c454: Guard_TickAndUpdateBody
+0x85c470: kSoldier_HeadDirs
+0x85c490: Guard_Surveying
+0x85c4c1: Guard_InPursuit
+0x85c4d7: Guard_SetTimerAndAssertTileHitBox
+0x85c4e8: Guard_FallingToDeath
+0x85c4f9: Sprite_ZeroVelocity_
+0x85c500: Soldier_Func12
+0x85c535: Guard_TickTwiceAndUpdateBody
+0x85c53c: kSoldier_SetTowardsVel
+0x85c542: Guard_ApplySpeedInDirection
+0x85c566: kAlways16
+0x85c56a: kAlways18
+0x85c56e: kSpawnProbe_Xvel
+0x85c5ae: kSpawnProbe_Yvel
+0x85c5ee: kSprite_SpawnProbeStaggered_Tab
+0x85c5f2: Sprite_Guard_SendOutProbe
+0x85c612: Sprite_SpawnProbeAlways
+0x85c66e: Sprite_SpawnProbeAlways_
+0x85c676: Soldier_Draw_
+0x85c680: Guard_HandleAllAnimation
+0x85c68c: Soldier_DrawShadow
+0x85c69e: kSoldier_DrawShadow
+0x85c6a2: kSoldier_Draw1_Char
+0x85c6a6: kSoldier_Draw1_Flags
+0x85c6aa: kSoldier_Draw1_Yd
+0x85c6de: Guard_AnimateHead
+0x85c6e0: Soldier_Draw1Ex
+0x85c72d: kSoldier_Draw2_Xd
+0x85c7fd: kSoldier_Draw2_Yd
+0x85c8cd: kSoldier_Draw2_Char
+0x85c935: kSoldier_Draw2_Flags
+0x85c99d: kSoldier_Draw2_Ext
+0x85ca05: kSoldier_Draw2_OamIdx
+0x85ca09: Guard_AnimateBody
+0x85ca10: Soldier_Draw2Ex
+0x85cab8: kSoldier_Draw3_Xd
+0x85caf0: kSoldier_Draw3_Yd
+0x85cb28: kSoldier_Draw3_Char
+0x85cb44: kSoldier_Draw3_Flags
+0x85cb60: kSoldier_Draw3_OamIdx
+0x85cb64: Guard_AnimateWeapon
+0x85cbe0: Sprite_45_UsainBolt
+0x85cc3c: BoltGuard_TriggerChaseTheme
+0x85cc65: Sprite_44_BluesainBolt
+0x85ccd5: PsychoTrooper_Draw
+0x85cce8: kSolderThrowing_Draw_X
+0x85cd08: kSolderThrowing_Draw_Y
+0x85cd28: kSolderThrowing_Draw_Char
+0x85cd38: kSolderThrowing_Draw_Flags
+0x85cd48: SpriteDraw_GuardSpear_Fresh
+0x85cd4a: SpriteDraw_GuardSpear_PreserveOamOffset
+0x85cd4f: SpriteDraw_GuardSpear_Bolt
+0x85cd54: SpriteDraw_GuardSpear
+0x85cdd4: Sprite_Guard_MoveIfNoTileCollision
+0x85cddd: kJavelinTrooper_Gfx
+0x85cde1: Sprite_48_RedJavelinGuard
+0x85cdff: Sprite_46_BlueArcher
+0x85ce23: SoldierThrowing_Common
+0x85ce74: Archer_Hiding
+0x85ceaa: Archer_Walking
+0x85cee2: agitated_jump_to
+0x85cf13: Archer_Scanning
+0x85cf44: Archer_NoticeSenpai
+0x85cf61: kSolderThrowing_Xd
+0x85cf71: kSolderThrowing_Yd
+0x85cf81: kSolderThrowing_DirFlags
+0x85cf85: Archer_Agitated
+0x85d001: kJavelinTrooper_Tab2
+0x85d041: kSoldier_Tab1
+0x85d045: Archer_Attack
+0x85d08b: kJavelinProjectile_X
+0x85d09b: kJavelinProjectile_Y
+0x85d0ab: kJavelinProjectile_Xvel
+0x85d0b1: kJavelinProjectile_Yvel
+0x85d0c1: kJavelinProjectile_Flags4
+0x85d0c5: Guard_LaunchProjectile
+0x85d141: BushJavelinSoldier_Draw
+0x85d192: JavelinTrooper_Draw
+0x85d1ac: Sprite_49_RedBushGuard
+0x85d1bf: Sprite_47_GreenBushGuard
+0x85d1d3: Sprite_BushGuard_Main
+0x85d1f5: Sprite_BushGuard_Hiding
+0x85d203: kBushSoldier_Gfx
+0x85d223: Sprite_BushGuard_Emerging
+0x85d252: BushGuard_SpawnFoliage
+0x85d277: Sprite_BushGuard_Shoot
+0x85d2be: kBushSoldier_Gfx2
+0x85d2ce: Sprite_BushGuard_Retreating
+0x85d2e9: kBushSoldierCommon_Y
+0x85d305: kBushSoldierCommon_Char
+0x85d313: kBushSoldierCommon_Flags
+0x85d321: BushSoldierCommon_Draw
+0x85d381: kArcherSoldier_WeaponOamOffs
+0x85d384: kArcherSoldier_HeadOamOffs
+0x85d388: kArcherSoldier_BodyOamOffs
+0x85d38c: ArcherSoldier_Draw
+0x85d3b0: kArcherSoldier_Draw_X
+0x85d410: kArcherSoldier_Draw_Y
+0x85d470: kArcherSoldier_Draw_Char
+0x85d4a0: kArcherSoldier_Draw_Flags
+0x85d4d0: kArcherSoldier_Tab1
+0x85d4d4: SpriteDraw_Archer_Weapon
+0x85d53b: Sprite_TutorialGuardOrBarrier
+0x85d543: Sprite_BarrierBounce
+0x85d548: kSprite_TutorialEntities_Tab
+0x85d54c: Sprite_GuardOrBarrierTest
+0x85d5bf: kTutorialSoldier_X
+0x85d5e7: kTutorialSoldier_Y
+0x85d60f: kTutorialSoldier_Char
+0x85d623: kTutorialSoldier_Flags
+0x85d637: kTutorialSoldier_Ext
+0x85d64b: TutorialSoldier_Draw
+0x85d6bc: Sprite_04_PullSwitch
+0x85d6d4: PullSwitch_FacingUp
+0x85d72f: kBadPullSwitch_Tab1
+0x85d738: kBadPullSwitch_Tab0
+0x85d743: PullSwitch_HandleUpPulling
+0x85d7ca: kBadPullDownSwitch_X
+0x85d7d0: kBadPullDownSwitch_Y
+0x85d7d6: kBadPullDownSwitch_Char
+0x85d7dc: kBadPullDownSwitch_Flags
+0x85d7e0: kBadPullDownSwitch_Ext
+0x85d7e6: kBadPullSwitch_Tab5
+0x85d7ed: kBadPullSwitch_Tab4
+0x85d7f9: BadPullDownSwitch_Draw
+0x85d856: kBadPullUpSwitch_Tab2
+0x85d858: BadPullUpSwitch_Draw
+0x85d8b5: PullSwitch_FacingDown
+0x85d921: kGoodPullSwitch_Tab1
+0x85d92c: kGoodPullSwitch_Tab0
+0x85d938: kGoodPullSwitch_YOffs
+0x85d945: kGoodPullSwitch_Tab2
+0x85d953: GoodPullSwitch_Draw
+0x85d999: PullSwitch_HandleDownPulling
+0x85da29: SpritePrep_UncleAndPriest
+0x85da31: kUncleAndSage_X
+0x85da37: kUncleAndSage_Y
+0x85da3d: UncleOrPriestPrepCheck
+0x85db27: Priest_SpawnMantle
+0x85db86: Sprite_73_UncleAndPriest
+0x85db8e: Sprite_UncleAndSage
+0x85db9b: Sprite_SanctuaryMantle
+0x85dbd3: SageMantle_NoPlayerCollision
+0x85dbe3: SageMantle_SlidingRight
+0x85dc00: Sprite_SanctuaryMantle_AttemptCutscene
+0x85dc39: Sprite_SanctuaryMantle_InitializeSlide
+0x85dc52: Sprite_SanctuaryMantle_SlideToTheRight
+0x85dc6a: kSageMantle_Dmd
+0x85dc8a: SageMantle_Draw
+0x85dca2: Sprite_TrackBodyToHead
+0x85dce6: Sprite_Priest
+0x85dd0a: Priest_Dying
+0x85dd1f: Priest_LyingOnGround
+0x85dd3f: Priest_FinalWords
+0x85dd5f: Priest_Die
+0x85dd63: Priest_RunRescueCutscene
+0x85dde5: Priest_Chillin
+0x85de24: kUncle_LeaveHouse_Xvel
+0x85de28: kUncle_LeaveHouse_Yvel
+0x85de2c: Sprite_Uncle
+0x85de3e: Uncle_AtHouse
+0x85de52: Uncle_TriggerTelepathy
+0x85de72: Uncle_AwakenLink
+0x85de9a: Uncle_DeclareCurfew
+0x85deb0: kUncle_LeaveHouse_Delay
+0x85deb2: kUncle_LeaveHouse_Dir
+0x85deb4: Uncle_Embark
+0x85def8: Uncle_ApplyTelepathyFollower
+0x85df19: Uncle_InPassage
+0x85df26: Uncle_LyingInDefeat
+0x85df44: Uncle_GrantEquipment
+0x85df6c: Sprite_DrawMultiple
+0x85df70: Sprite_DrawMultiple_R6
+0x85df75: Sprite_DrawMultiplePlayerDeferred
+0x85dfe5: Sprite_DrawMultiple_prep_oam_deferred
+0x85dfe9: Sprite_DrawMultiple_prep_oam
+0x85e00b: Sprite_32_ArguingBros
+0x85e013: Sprite_QuarrelBros
+0x85e052: Sprite_UNREACHABLE_05E052
+0x85e06b: UNREACHABLE_05E06B
+0x85e0b6: UNREACHABLE_05E0B6
+0x85e0ff: kQuarrelBros_Dmd
+0x85e17f: QuarrelBros_Draw
+0x85e1a3: kShowMessageFacing_Tab0
+0x85e1a7: Sprite_ShowSolicitedMessage
+0x85e1f0: Sprite_ShowMessageOnContact
+0x85e219: Sprite_ShowMessageUnconditional
+0x85e24d: Sprite_33_RupeePull
+0x85e255: Sprite_PullForRupees
+0x85e28c: Sprite_14_ThievesTownGrate
+0x85e294: Sprite_GargoyleGrate
+0x85e2ea: Sprite_34_YoungSnitch
+0x85e2f2: Sprite_YoungSnitchLady
+0x85e2ff: kYoungSnitchLady_Dmd
+0x85e37f: YoungSnitchLady_Draw
+0x85e3a7: Sprite_35_Innkeeper
+0x85e3af: Sprite_InnKeeper
+0x85e3cc: kInnKeeper_Dmd
+0x85e3dc: InnKeeper_Draw
+0x85e3f3: Sprite_36_Witch
+0x85e3fb: Sprite_Witch
+0x85e453: Witch_GrantByrna
+0x85e460: Witch_DiscussThings
+0x85e47c: Witch_DiscussMushroom
+0x85e4a7: Witch_YouHaveShroom
+0x85e4cf: Witch_AcceptShroom
+0x85e509: kWitch_DrawDataA
+0x85e549: kWitch_DrawDataB
+0x85e555: kWitch_DrawDataC
+0x85e55d: Witch_Draw
+0x85e62b: Sprite_38_EyeStatue
+0x85e633: Sprite_ArrowTrigger
+0x85e656: UNREACHABLE_05E656
+0x85e657: Sprite_Decelerate_X
+0x85e666: Sprite_Decelerate_Y
+0x85e675: SpritePrep_Snitch
+0x85e67d: SpritePrep_Snitches
+0x85e69a: Sprite_3D_OldSnitch
+0x85e6a2: kOldSnitchLady_Xvel
+0x85e6a6: kOldSnitchLady_Yvel
+0x85e6aa: Sprite_OldSnitchLady
+0x85e706: Snitch_FacePlayer
+0x85e716: kOldSnitchLady_Xd
+0x85e71a: Snitch_Meander
+0x85e78d: Snitch_FreakOut
+0x85e831: Snitch_OpenDoor
+0x85e887: Snitch_SlamDoor
+0x85e88e: SpritePrep_RunningBoy
+0x85e896: SpritePrep_RunningMan
+0x85e8a2: Sprite_74_RunningBoy
+0x85e8aa: kRunningMan_Xvel
+0x85e8ae: kRunningMan_Yvel
+0x85e8b2: Sprite_RunningMan
+0x85e8f5: kRunningMan_Xvel2
+0x85e8f7: RunningBoy_Idle
+0x85e938: RunningMan_Running
+0x85e946: RunningBoy_RunLeft
+0x85e965: RunningMan_Relax
+0x85e96c: kRunningMan_A
+0x85e96f: kRunningMan_Dir
+0x85e973: RunningBoy_RunRight
+0x85e998: RunningBoy_Caught
+0x85e9ac: RunningMan_AnimateAndDust
+0x85e9ba: RunningMan_RunAway
+0x85e9cd: kRunningMan_Dmd
+0x85ea4d: RunningMan_Draw
+0x85ea71: Sprite_75_BottleMerchant
+0x85ea79: Sprite_BottleVendor
+0x85eabe: BottleVendor_SoldOut
+0x85eac7: BottleVendor_Idle
+0x85eaed: BottleVendor_OfferSale
+0x85eb17: BottleVendor_GrantBottle
+0x85eb40: BottleVendor_BuyingItem
+0x85eb5d: BottleVendor_PayOut
+0x85eb87: kBottleVendor_Dmd
+0x85eba7: BottleVendor_Draw
+0x85ebc7: SpritePrep_ZeldaLong
+0x85ebcf: SpritePrep_Zelda
+0x85ec4c: Priest_SpawnRescuedPrincess
+0x85ec8e: kZelda_Xvel
+0x85ec92: kZelda_Yvel
+0x85ec96: Sprite_Zelda_
+0x85ec9e: Sprite_76_Zelda
+0x85ecbf: Zelda_InCell
+0x85ecd9: Zelda_WaitingInCell
+0x85ecfa: Zelda_ApproachHero
+0x85ed20: Zelda_DebaseAgahnim
+0x85ed2c: Zelda_VerifyAttentionSpan
+0x85ed43: Zelda_BecomeFollower
+0x85ed69: Zelda_EnteringSanctuary
+0x85ed76: kZelda_Delay0
+0x85ed7a: kZelda_Dir0
+0x85ed7e: Zelda_EnterSanctuary
+0x85edc4: Zelda_TalkHeadOff
+0x85edec: Zelda_WellWishes
+0x85ee06: kZeldaMsgs
+0x85ee0c: Zelda_AtSanctuary
+0x85ee4b: SpritePrep_MushroomLong
+0x85ee53: SpritePrep_Mushroom
+0x85ee70: Sprite_E7_Mushroom
+0x85ee78: Sprite_Mushroom
+0x85eea6: SpritePrep_FakeMasterSword
+0x85eea7: Sprite_E8_FakeMasterSword
+0x85eeaf: Sprite_FakeSword
+0x85eed6: kFakeSword_Dmd
+0x85eee6: FakeSword_Draw
+0x85eef9: kHeartPieceMsg
+0x85ef01: SpritePrep_HeartContainer
+0x85ef09: HeartUpdgrade_CheckIfAlreadyObtained
+0x85ef3f: Sprite_EA_HeartContainer
+0x85ef47: Sprite_HeartContainer
+0x85efc6: HeartContainer_GrantFromSprite
+0x85efdc: HeartContainer_Grant
+0x85eff7: HeartUpgrade_SetOutdoorAcquiredFlag
+0x85f006: kHeartUpgrade_IndoorAcquiredMasks
+0x85f008: HeartUpgrade_SetIndoorAcquiredFlag
+0x85f018: Sprite_EB_HeartPiece
+0x85f020: Sprite_HeartPiece
+0x85f0c3: HeartUpgrade_SetObtainedFlag
+0x85f0cd: Sprite_16_Elder
+0x85f0d5: Sprite_Elder
+0x85f0ea: Sprite_Aginah
+0x85f14d: Sprite_Sahasrahla
+0x85f160: Sasha_Idle
+0x85f1dc: out
+0x85f1e9: Sasha_GiveQuest
+0x85f1fb: Sasha_GiveBoots
+0x85f20e: Sasha_PromoteIceRod
+0x85f21a: kElder_Dmd
+0x85f23a: Elder_Draw
+0x85f25a: SpritePrep_MedallionTabletLong
+0x85f262: SpritePrep_MedallionTablet
+0x85f296: Sprite_F2_MedallionTablet
+0x85f29e: Sprite_MedallionTablet
+0x85f2a9: kDustCloud_Gfx
+0x85f2b2: Sprite_DustCloud
+0x85f2d6: Sprite_SpawnDustCloud
+0x85f30c: MedallionTablet_Main
+0x85f347: kMedallionTabletEtherMsg
+0x85f34b: kMedallionTabletMsg
+0x85f34f: MedallionTablet_WaitingToBeRead
+0x85f355: BombosTablet
+0x85f3c4: EtherTablet
+0x85f42e: MedallionTablet_WasteTime
+0x85f43c: MedallionTablet_Crumble
+0x85f463: MedallionTablet_AmCrumbled
+0x85f469: Sprite_78_MrsSahasrahla
+0x85f471: Sprite_ElderWife
+0x85f48a: MrsSahasrahla_Idle
+0x85f4b5: MrsSahasrahla_BabbleOn
+0x85f4c1: MrsSahasrahla_QuestionSanity
+0x85f4db: MrsSahasrahla_FindMyHubby
+0x85f4e5: kElderWife_Dmd
+0x85f505: ElderWife_Draw
+0x85f521: SpritePrep_MagicShopAssistant
+0x85f529: SpritePrep_PotionShop
+0x85f539: MagicShopAssistant_SpawnPowder
+0x85f58e: MagicShopAssistant_SpawnGreenCauldron
+0x85f5bf: MagicShopAssistant_SpawnBlueCauldron
+0x85f5f0: MagicShopAssistant_SpawnRedCauldron
+0x85f62b: Sprite_E9_MagicShopAssistant
+0x85f633: Sprite_PotionShop
+0x85f644: Sprite_BagOfPowder
+0x85f66b: kMagicPowder_Dmd
+0x85f67b: MagicPowderItem_Draw
+0x85f68e: Sprite_GreenCauldron
+0x85f700: kGreenPotionItem_Dmd
+0x85f718: GreenPotionItem_Draw
+0x85f72b: Sprite_BlueCauldron
+0x85f79d: kBluePotionItem_Dmd
+0x85f7bd: BluePotionItem_Draw
+0x85f7d0: Sprite_RedCauldron
+0x85f846: PotionCauldron_GoBeep
+0x85f84d: kRedPotionItem_Dmd
+0x85f86d: RedPotionItem_Draw
+0x85f880: PotionCauldron_CheckBottles
+0x85f893: Sprite_MagicShopAssistant_Main
+0x85f8fb: kShopkeeper_Dmd
+0x85f91b: Shopkeeper_Draw
+0x85f93f: Sprite_DirectionToFacePlayer__
+0x85f944: Sprite_IsToRightOfPlayer_
+0x85f949: Sprite_IsBelowPlayer___
+0x85f94e: Sprite_ReturnIfInactive_
+0x85f955: Sprite_ReturnIfPaused_
+0x85f96b: kSprite2_ReturnIfRecoiling_Masks
+0x85f971: Sprite_ReturnIfRecoiling_
+0x85f9ed: Sprite_Move_
+0x85f9f4: Sprite_MoveX__
+0x85fa00: Sprite2_MoveY
+0x85fa2e: Sprite_MoveZ_
+0x85fa50: Sprite_PrepOamCoordOrDoubleRet__
+0x85fa59: Sprite_TutorialGuard_ShowMessageOnContact
+0x85fa8e: Sprite_ShowMessageMinimal
+0x85faa2: Overworld_ReadTileAttribute
+0x85faca: Sprite_3A_MagicBat
+0x85fad2: Sprite_MadBatter
+0x85faff: MagicBat_Dormant
+0x85fb3a: kMadBatter_RisingUp_XAccel
+0x85fb3c: MagicBat_Ascend
+0x85fb86: kMadBatter_PseudoAttack_OamFlags
+0x85fb8e: MagicBat_Attack
+0x85fbb9: MagicBat_EnhanceMagic
+0x85fbe4: MagicBat_Retreat
+0x85fbef: Sprite_3B_BonkItem
+0x85fbf7: Sprite_DashItem
+0x85fc04: Sprite_BonkKey
+0x85fc4e: BonkKey_Undisturbed
+0x85fc7e: BonkKey_GrantKey
+0x85fc9e: Sprite_BookOfMudora
+0x85fce8: BookOfMudora_WaitForBonk
+0x85fd1b: BonkItem_KnockedDown
+0x85fd2e: BonkItem_Land
+0x85fd3a: BookOfMudora_GrantLiterature
+0x85fd4d: Sprite_LumberjackTree
+0x85fd98: LumberjackTree_WaitForBonk
+0x85fdd0: LumberjackTree_ExplodeViolently
+0x85fe0b: LumberjackTree_DispersionOfLeaves
+0x85fe23: kDashTreeTop_CharFlags
+0x85fe43: kDashTreeTop_X
+0x85fe53: kDashTreeTop_Y
+0x85fe63: kDashTreeTop_Char
+0x85fe69: kDashTreeTop_Flags
+0x85fe6f: DashTreeTop_Draw
+0x85ff39: LumberjackTree_SpawnLeaves
+0x85ff5e: Sprite_3C_KidInKak
+0x85ff66: Sprite_TroughBoy
+0x85ff9f: kTroughBoy_Dmd
+0x85ffdf: TroughBoy_Draw
+0x868000: BottleMerchant_DetectFish
+0x868045: kBottleVendor_FishRewardXv
+0x86804a: kBottleVendor_FishRewardYv
+0x86804f: kBottleVendor_FishRewardType
+0x868054: BottleMerchant_BuyFish
+0x86809f: Boomerang_CheatWhenNoOnesLooking
+0x8680e6: kApplyRumble_X
+0x8680ea: kApplyRumble_Y
+0x8680ee: kApplyRumble_Yhi
+0x8680f0: kApplyRumble_Xhi
+0x8680f4: kApplyRumble_WH
+0x8680fa: Prepare_ApplyRumbleToSprites
+0x86812d: Sprite_SpawnImmediatelySmashedTerrain
+0x86814b: Sprite_SpawnThrowableTerrain
+0x868156: Sprite_SpawnThrowableTerrain_silently
+0x8681f4: kSpawnSecretItems
+0x86820a: kSpawnSecretItem_SpawnFlag
+0x868220: kSpawnSecretItem_XLo
+0x868236: kSpawnSecretItem_IgnoreProj
+0x86824c: kSpawnSecretItem_ZVel
+0x868264: Sprite_SpawnSecret
+0x868328: Sprite_Main
+0x8683c2: EasterEgg_BageCodeTrampoline
+0x8683c7: kOam_ResetRegionBases
+0x8683d3: Oam_ResetRegionBases
+0x8683e6: Utility_CheckIfHitBoxesOverlap_
+0x8683ea: Sprite_SetupHitBox_
+0x8683f2: Sprite_TimersAndOam
+0x8684b9: kSpritePrios
+0x8684bd: Sprite_Get_16_bit_Coords_
+0x8684c1: Sprite_Get16BitCoords
+0x8684da: Sprite_ExecuteSingle_
+0x8684e2: Sprite_ExecuteSingle
+0x86850f: SpritePrep_ThrowableScenery
+0x868510: Sprite_inactiveSprite
+0x868526: SpriteActive_Main_
+0x86852e: SpriteModule_Fall1
+0x868543: SpriteBurn_Main_
+0x868548: SpriteExplode_Main_
+0x86854d: kSpriteDrown_Dmd
+0x86858d: kSpriteDrown_Oam_Flags
+0x868591: kSpriteDrown_Oam_Char
+0x86859c: SpriteModule_Drown
+0x86864d: SpriteModule_Initialize
+0x868841: SpritePrep_Mantle
+0x86884a: SpritePrep_MoveRight_8px
+0x868854: SpritePrep_MedallionTablet_bounce
+0x868859: SpritePrep_Switch
+0x86886d: SpritePrep_SwitchFacingUp
+0x86886e: SpritePrep_Snitch_bounce_1
+0x868873: SpritePrep_DoNothingA
+0x868874: kSpriteRat_BumpDamage
+0x868876: kSpriteRat_Health
+0x868878: SpritePrep_Rat
+0x868888: kSpriteKeese_BumpDamage
+0x86888a: kSpriteKeese_Health
+0x86888c: kSpriteKeese_Flags5
+0x86888e: SpritePrep_Keese
+0x8688a4: kSpriteRope_BumpDamage
+0x8688a6: kSpriteRope_Health
+0x8688a8: kSpriteRope_Flags5
+0x8688aa: SpritePrep_Rope
+0x8688c0: SpritePrep_Swamola
+0x8688c7: SpritePrep_Blind
+0x8688cf: SpritePrep_Ganon
+0x8688d7: kHokbok_InitXvel
+0x8688db: kHokbok_InitYvel
+0x8688df: SpritePrep_Pokey
+0x8688fd: SpritePrep_MiniVitreous
+0x868901: SpritePrep_Gibo
+0x86890c: kSprite_Octoballoon_Delay
+0x868910: SpritePrep_Octoballoon
+0x86891b: SpritePrep_AgahnimsBarrier
+0x86892c: SpritePrep_Catfish
+0x86893b: SpritePrep_CutsceneAgahnim
+0x86894d: SpritePrep_Vitreous
+0x868963: kSpriteRaven_BumpDamage
+0x868965: kSpriteRaven_Health
+0x868967: kSpriteRaven_Flags5
+0x868969: SpritePrep_Raven
+0x86897e: SpritePrep_Vulture
+0x868991: SpritePrep_Poe
+0x86899b: SpritePrep_DoNothingC
+0x86899c: SpritePrep_BlindMaiden
+0x8689d3: SpritePrep_MiniMoldorm_bounce
+0x8689d8: SpritePrep_Bomber
+0x8689df: SpritePrep_BombShoppe
+0x868a51: SpritePrep_BullyAndVictim
+0x868a59: SpritePrep_PurpleChest
+0x868a79: SpritePrep_Smithy
+0x868af0: SpritePrep_Babasu
+0x868af3: SpritePrep_Zoro
+0x868b03: SpritePrep_LaserEye_bounce
+0x868b08: SpritePrep_Popo
+0x868b0c: SpritePrep_Popo2
+0x868b12: SpritePrep_Statue
+0x868b1c: SpritePrep_Bari
+0x868b2e: SpritePrep_GreenStalfos
+0x868b34: SpritePrep_WaterLever
+0x868b3e: SpritePrep_FireDebirando
+0x868b4a: SpritePrep_DebirandoPit
+0x868b7f: kDebirando_OamFlags
+0x868b81: SpritePrep_WeakGuard
+0x868b93: SpritePrep_WallCannon
+0x868ba2: SpritePrep_ArrowGame_bounce
+0x868ba7: SpritePrep_IgnoreProjectiles
+0x868bab: SpritePrep_HauntedGroveAnimal
+0x868bb2: SpritePrep_HauntedGroveOstritch
+0x868bbf: SpritePrep_DiggingGameGuy_bounce
+0x868bc4: SpritePrep_ThievesTownGrate
+0x868bcf: SpritePrep_RupeePull
+0x868be4: kShopKeeperWhere
+0x868bf1: SpritePrep_Shopkeeper
+0x868c37: SpritePrep_ShopKeeper_0
+0x868c43: SpritePrep_ShopKeeper_1
+0x868c5c: SpritePrep_ShopKeeper_2
+0x868c60: SpritePrep_ShopKeeper_3
+0x868c67: SpritePrep_ShopKeeper_4
+0x868c72: SpritePrep_ShopKeeper_5_7_8
+0x868c8b: SpritePrep_NiceThief_WithGift
+0x868c91: SpritePrep_NiceThief_Desert
+0x868c95: SpritePrep_NiceThief_Ice
+0x868c99: kStoryTellerRooms
+0x868c9e: SpritePrep_Storyteller
+0x868cbe: kHumanMultiTypes
+0x868cc1: SpritePrep_Adults
+0x868cd5: SpritePrep_Whirlpool
+0x868cde: SpritePrep_Sage
+0x868cf0: kDashItemMask
+0x868cf2: SpritePrep_BonkItem
+0x868d46: SpritePrep_Kiki
+0x868d59: SpritePrep_Locksmith
+0x868d7f: SpritePrep_SickKid
+0x868d8e: kGanonHelpers_OamFlags
+0x868d90: kGanonHelpers_Health
+0x868d92: kGanonHelpers_BumpDamage
+0x868d94: SpritePrep_Tektite
+0x868dc1: SpritePrep_Chainchomp_bounce
+0x868dc6: SpritePrep_BigFairy
+0x868dd1: SpritePrep_MrsSahasrahla
+0x868dda: SpritePrep_MagicBat
+0x868de0: SpritePrep_FortuneTeller
+0x868de7: kLeever_OamFlags
+0x868de9: SpritePrep_FairyPond
+0x868dfd: SpritePrep_Hobo
+0x868e30: SpritePrep_MasterSword
+0x868e42: SpritePrep_Roller_HorizontalRightFirst
+0x868e46: SpritePrep_RollerLeftRight
+0x868e4f: SpritePrep_Roller_VerticalDownFirst
+0x868e53: SpritePrep_RollerUpDown
+0x868e6b: SpritePrep_Kodongo
+0x868e85: SpritePrep_Spark
+0x868ec1: SpritePrep_LostWoodsBird
+0x868ed2: SpritePrep_LostWoodsSquirrel
+0x868ef0: kBubble_Xvel
+0x868ef2: SpritePrep_Antifairy
+0x868f08: SpritePrep_FallingIce
+0x868f0f: SpritePrep_KingZora
+0x868f1c: Sprite_ReturnIfBossFinished
+0x868f3f: SpritePrep_ArmosKnight
+0x868f4d: SpritePrep_DesertStatue
+0x868f6c: SpritePrep_DoNothingD
+0x868f6d: kOctorock_BumpDamage
+0x868f6f: kOctorock_Health
+0x868f71: SpritePrep_Octorok
+0x868f8a: SpritePrep_Moldorm_bounce
+0x868f95: SpritePrep_Lanmolas_bounce
+0x868f9d: SpritePrep_BigSpike
+0x868fa2: SpritePrep_SwimmingZora
+0x868fa7: SpritePrep_Geldman
+0x868fb0: SpritePrep_Kyameron
+0x868fc9: SpritePrep_WalkingZora
+0x868fcf: SpritePrep_StandardGuard_indoors
+0x868fd6: SpritePrep_StandardGuard
+0x869001: SpritePrep_TrooperAndArcherSoldier
+0x86903b: kSpriteSoldier_Tab0
+0x869043: SpritePrep_TalkingTree
+0x869064: SpritePrep_CrystalSwitch
+0x869075: SpritePrep_FluteKid
+0x8690cc: SpritePrep_MoveDown_8px
+0x8690d5: SpritePrep_Zazakku
+0x8690d6: SpritePrep_PedestalPlaque
+0x8690e0: SpritePrep_Stalfos
+0x8690f0: SpritePrep_KholdstareShell
+0x8690fa: SpritePrep_Kholdstare
+0x869107: SpritePrep_Bumper
+0x86910a: SpritePrep_MoveDown_8px_Right8px
+0x869116: kHardHatBeetle_OamFlags
+0x869118: kHardHatBeetle_Health
+0x86911a: kHardHatBeetle_A
+0x86911c: kHardHatBeetle_State
+0x86911e: kHardHatBeetle_Flags5
+0x869120: kHardHatBeetle_BumpDamage
+0x869122: SpritePrep_HardhatBeetle
+0x869151: SpritePrep_MiniHelmasaur
+0x86915c: SpritePrep_Fairy
+0x86916a: SpritePrep_Absorbable
+0x86916e: SpritePrep_OverworldBonkItem
+0x869174: SpritePrep_ShieldPickup
+0x869175: SpritePrep_NiceBee
+0x869193: kAgahnim_OamFlags
+0x869195: SpritePrep_Agahnim
+0x8691ae: SpritePrep_DoNothingG
+0x8691af: SpritePrep_Eyegore_bounce
+0x8691b4: SpritePrep_FireBar
+0x8691ba: SpritePrep_Trinexx
+0x8691c5: SpritePrep_HelmasaurKing
+0x8691cc: SpritePrep_FreeUpBossSegmentSlots
+0x8691d7: SpritePrep_Spike
+0x8691dc: SpritePrep_RockStal
+0x8691e8: SpritePrep_Blob
+0x8691f1: SpritePrep_Arrghus
+0x8691fa: SpritePrep_Arrghi
+0x86922f: SpritePrep_Mothula
+0x869248: SpritePrep_AntifairyCircle_bounce
+0x86924d: SpritePrep_DoNothingH
+0x86924e: SpritePrep_BigKey
+0x869256: SpritePrep_BigKey_load_graphics
+0x869262: SpritePrep_SmallKey
+0x869267: SpritePrep_KeySetItemDrop
+0x869271: SpriteActive_Main
+0x869283: kSpriteActiveRoutines
+0x869469: Sprite_09_Moldorm_bounce
+0x86946e: Sprite_00_Raven_bounce
+0x869473: Sprite_01_Vulture_bounce
+0x869478: kDeadRock_Gfx
+0x869481: kDeadRock_OamFlags
+0x86948a: Sprite_27_Deadrock
+0x869500: kDeadRock_Xvel
+0x869502: kDeadRock_Yvel
+0x869506: Deadrock_Halted
+0x869559: Deadrock_Walk
+0x86958f: Deadrock_Stunned
+0x8695c9: kSluggula_Gfx
+0x8695d1: kSluggula_OamFlags
+0x8695d9: Sprite_20_Sluggula
+0x869615: kMoblin_Xvel
+0x86961b: Sluggula_Normal
+0x86964f: Sluggula_BreakFromBombing
+0x869673: Sluggula_DropBomb
+0x869686: kPoe_OamFlags
+0x869688: Sprite_19_Poe
+0x869715: kPoe_Accel
+0x869719: kPoe_XvelTarget
+0x86971d: kPoe_ZvelTarget
+0x86971f: Poe_Halted
+0x86973f: kPoe_Yvel
+0x869741: Poe_SpookAround
+0x86977e: kPoe_Draw_X
+0x869782: kPoe_Draw_Char
+0x869786: Poe_Draw
+0x8697d8: kMoldorm_Xvel
+0x8697e8: kMoldorm_Yvel
+0x8697f8: kMoldorm_NextDir
+0x869808: Sprite_18_MiniMoldorm
+0x869860: MiniMoldorm_Readjust
+0x86988d: MiniMoldorm_Meander
+0x8698b2: MiniMoldorm_TargetLink
+0x8698e0: kMoblin_Gfx
+0x8698e4: Sprite_12_Moblin
+0x869903: kMoblin_Delay
+0x869907: Moblin_Halted
+0x869930: kMoblin_Dirs
+0x869938: Moblin_Walk
+0x8699a9: kMoblin_Gfx2
+0x8699b1: Moblin_ThrowSpear
+0x8699d9: kMoblinSpear_X
+0x8699dd: kMoblinSpear_Y
+0x8699e5: kMoblinSpear_Xvel
+0x8699e7: kMoblinSpear_Yvel
+0x8699eb: Moblin_MaterializeSpear
+0x869a30: kMoblin_Dmd
+0x869bb0: kMoblin_ObjOffs
+0x869bbc: kMoblin_HeadChar
+0x869bc0: kMoblin_HeadFlags
+0x869bc4: Moblin_Draw
+0x869c20: kSnapDragon_Gfx
+0x869c24: Sprite_0E_Snapdragon
+0x869c4b: kSnapDragon_Xvel
+0x869c53: kSnapDragon_Yvel
+0x869c5b: kSnapDragon_Delay
+0x869c5f: Snapdragon_Halted
+0x869ca9: Snapdragon_MoveAround
+0x869d02: kSnapDragon_Dmd
+0x869e02: SnapDragon_Draw
+0x869e1f: Sprite_22_Ropa
+0x869e44: Ropa_Halted
+0x869e5d: Ropa_Pounce
+0x869e85: kRopa_Dmd
+0x869ee5: Ropa_Draw
+0x869f05: Sprite_11_Hinox
+0x869f30: kHinox_Gfx
+0x869f38: kHinox_BombX
+0x869f3c: kChicken_Avenger
+0x869f40: kHinox_BombY
+0x869f44: kHinox_BombXvel
+0x869f46: kHinox_BombYvel
+0x869f4a: Hinox_ThrowBomb
+0x869fb6: kHinox_Xvel
+0x869fb8: kHinox_Yvel
+0x869fbc: Hinox_Halted
+0x869fe1: Hinox_FaceLink
+0x869fef: kHinox_RandomDirs
+0x869ff7: Hinox_PickRandomDirection
+0x86a004: Hinox_SetDirection
+0x86a025: kHinox_WalkGfx
+0x86a029: Hinox_Walk
+0x86a1ed: kHinoxNum
+0x86a1f9: Hinox_Draw
+0x86a213: kHeartRefill_AccelX
+0x86a215: kBari_Xvel2
+0x86a225: kBari_Yvel2
+0x86a235: kRedBari_SplitX
+0x86a237: kRedBari_SplitXvel
+0x86a239: kBari_Xvel
+0x86a23b: kBari_Gfx
+0x86a23d: Sprite_23_RedBari
+0x86a26f: Sprite_Biri
+0x86a342: set_electrocute_delay
+0x86a34e: RedBari_Split
+0x86a39c: kRedBari_Dmd
+0x86a3dc: RedBari_Draw
+0x86a3f9: kHelmasaur_Gfx
+0x86a401: kHelmasaur_OamFlags
+0x86a409: Sprite_13_MiniHelmasaur
+0x86a460: Sprite_26_HardhatBeetle
+0x86a46d: HelmasaurHardHatBeetleCommon
+0x86a4d2: kHardHatBeetle_Dmd
+0x86a4f2: HardHatBeetle_Draw
+0x86a50c: Sprite_15_Antifairy
+0x86a5c0: kChicken_OamFlags
+0x86a5c2: Sprite_0B_Cucco
+0x86a67f: Cucco_Calm
+0x86a6b1: Chicken_Hopping
+0x86a6e2: Cucco_AnimateFast
+0x86a6e5: Chicken_IncrSubtype2_3
+0x86a6fc: Cucco_Flee
+0x86a727: Cucco_DrawPANIC
+0x86a72f: Sprite_DrawDistressSweat
+0x86a733: Sprite_DrawDistress_custom
+0x86a78e: Cucco_Carried
+0x86a7b8: Cucco_DoMovement_XYZ
+0x86a7bb: Cucco_DoMovement_XY
+0x86a7c3: kSpriteDistress_X
+0x86a7cb: kSpriteDistress_Y
+0x86a7d3: Cucco_SummonAvenger
+0x86a84c: BawkBawk
+0x86a853: Sprite_MovableMantle__
+0x86a858: kRupeeCoveredGrab_Gfx
+0x86a85c: kRupeeCoveredGrab_Xvel
+0x86a860: kRupeeCoveredGrab_Yvel
+0x86a864: kRupeeCrab_Xvel
+0x86a868: kRupeeCrab_Yvel
+0x86a86c: Sprite_17_Hoarder
+0x86a874: Sprite_Hoarder_Covered
+0x86a91d: Sprite_Hoarder_Frantic
+0x86aa04: kRupeeCrab_Gfx
+0x86aa08: kRupeeCrab_OamFlags
+0x86aa0c: Sprite_CheckIfLifted_permissive
+0x86aa14: Sprite_CheckIfLiftedPermissiveWrapper
+0x86aa18: kCoveredRupeeCrab_DrawY
+0x86aa30: kCoveredRupeeCrab_DrawChar
+0x86aa3c: kCoveredRupeeCrab_DrawFlags
+0x86aa48: CoveredRupeeCrab_Draw
+0x86aabe: kThrowableScenery_Char
+0x86aaca: kThrowableScenery_Flags
+0x86aae0: Sprite_EC_ThrownItem
+0x86ab5a: kThrowableScenery_DrawLarge_X
+0x86ab62: kThrowableScenery_DrawLarge_Y
+0x86ab6a: kThrowableScenery_DrawLarge_Flags
+0x86ab6e: kThrowableScenery_DrawLarge_X2
+0x86ab74: kThrowableScenery_DrawLarge_OamFlags
+0x86ab76: SpriteDraw_ThrownItem_Gigantic
+0x86ac31: kScatterDebris_X
+0x86ac35: kScatterDebris_XHi
+0x86ac39: kScatterDebris_Y
+0x86ac3d: kScatterDebris_YHi
+0x86ac41: ThrowableScenery_ScatterIntoDebris
+0x86ad03: Entity_ApplyRumbleToSprites
+0x86ad50: Sprite_TransmuteToBomb
+0x86ad6f: Sprite_28_DarkWorldHintNPC
+0x86ad9a: Sprite_DarkWorldHintNPC_Bird
+0x86ada7: DarkWorldHintNPC_Idle
+0x86adb5: DarkWorldHintNPC_RestoreHealth
+0x86adbf: HintBird_TellStory
+0x86ade1: Sprite_HamburgerHelper
+0x86adee: Sprite_StoryTeller_Case1_Inner
+0x86ae0a: Sprite_DarkWorldHintNPC_Octopus
+0x86ae17: Sprite_HintOctopus_TellStory
+0x86ae34: Sprite_Broccoli
+0x86ae5b: Sprite_Watto
+0x86ae8e: Sprite_Watto_TellStory
+0x86aeab: DarkWorldHintNPC_HandlePayment
+0x86aeca: kStoryTeller_Dmd
+0x86af1a: StoryTeller_1_Draw
+0x86af3b: Sprite_2E_FluteKid
+0x86af46: FluteKid_TheKid
+0x86af51: FluteKid_Human
+0x86af93: FluteKid_Chillin
+0x86afc1: FluteKid_AboutToDisappear
+0x86aff2: FluteKid_PhaseOut
+0x86b008: FluteKid_HeDisappeared
+0x86b019: kFluteAardvark_Gfx
+0x86b02d: kFluteAardvark_Delay
+0x86b040: Sprite_FluteKid_Stumpy
+0x86b05a: Stumpy_Initialize
+0x86b06c: Stumpy_Supplicate
+0x86b07a: FluteAardvark_GetMeMyDamnFlute
+0x86b083: Stumpy_ThanksButYouKeepIt
+0x86b098: Stumpy_SorryButAmTree
+0x86b09e: Stumpy_WaitForConvo
+0x86b0bb: Stumpy_GiveShovel
+0x86b0ca: Stumpy_WaitForMusic
+0x86b0e9: Stumpy_BecomeTree
+0x86b11e: Stumpy_AmTree
+0x86b12e: FluteKid_CheckIfInRange
+0x86b171: kFluteNote_Xv
+0x86b173: Sprite_FluteKid_Quaver
+0x86b1a5: FluteKid_SpawnQuaver
+0x86b1de: kSmithy_Gfx
+0x86b1e6: kSmithy_B
+0x86b1ee: Sprite_1A_Smithy
+0x86b1fd: Smithy_Homecoming
+0x86b20e: kReturningSmithy_Delay
+0x86b210: kReturningSmithy_Dir
+0x86b213: kReturningSmithy_Xvel
+0x86b217: kReturningSmithy_Yvel
+0x86b21b: Smithy_Homecoming_Walk
+0x86b255: Smithy_Homecoming_TYVM
+0x86b274: Smithy_Frog
+0x86b2c0: kReturningSmithy_Dmd
+0x86b300: kReturningSmithy_Dma
+0x86b308: ReturningSmithy_Draw
+0x86b331: kSmithyFrog_Dmd
+0x86b339: SmithyFrog_Draw
+0x86b34e: Smithy_Main
+0x86b3e3: Smithy_Smithing
+0x86b43d: Smithy_ListenForHammer
+0x86b45f: Smithy_WannaTemper
+0x86b47c: Smithy_ForRealsies
+0x86b4ad: Smithy_ItAintFreeKid
+0x86b50e: Smithy_TemperInProgress
+0x86b548: Smithy_GiveTemperedSword
+0x86b56a: Smithy_SpawnFriend
+0x86b59d: Smithy_CopiouslyThankful
+0x86b5a6: Smithy_SpawnDwarfPal
+0x86b5d3: kSmithy_Draw
+0x86b673: Smithy_Draw
+0x86b696: kSmithySpark_Gfx
+0x86b69d: kSmithySpark_Delay
+0x86b6a3: Smithy_Spark
+0x86b6cd: Smithy_SpawnSpark
+0x86b6fc: kSmithySpark_Dmd
+0x86b72c: SmithySpark_Draw
+0x86b74a: kEnemyArrow_Xvel
+0x86b74c: kEnemyArrow_Yvel
+0x86b754: Sprite_1B_Arrow
+0x86b7c3: kEnemyArrow_Dirs
+0x86b807: kEnemyArrow_Draw_X
+0x86b817: kEnemyArrow_Draw_Y
+0x86b827: kEnemyArrow_Draw_Char
+0x86b847: kEnemyArrow_Draw_Flags
+0x86b867: EnemyArrow_Draw
+0x86b8ce: kCrystalSwitchPal
+0x86b8d0: Sprite_1E_CrystalSwitch
+0x86b94c: Sprite_1F_SickKid
+0x86b962: SickKid_ISleep
+0x86b991: kBugNetKid_Gfx
+0x86b999: kBugNetKid_Delay
+0x86b9a0: SickKid_RealShit
+0x86b9c6: SickKid_NothingButNet
+0x86b9d8: SickKid_OutOfShaqMemes
+0x86b9e6: kPushSwitch_Delay
+0x86b9f0: kPushSwitch_Dir
+0x86b9fa: Sprite_21_WaterSwitch
+0x86ba10: WaterSwitch_Untoggled
+0x86ba33: WaterSwitch_ReleaseGate
+0x86ba62: kPushSwitch_Oam
+0x86bb02: kPushSwitch_WH
+0x86bb22: PushSwitch_Draw
+0x86bcac: Sprite_39_Locksmith
+0x86bcc9: LockSmith_Chillin
+0x86bd01: LockSmith_FollowLink
+0x86bd20: LockSmith_OfferService
+0x86bd46: LockSmith_RespondToAnswer
+0x86bd8a: MiddleAgedMan_PromiseReminder
+0x86bd93: MiddleAgedMan_SilenceDueToOtherTagalong
+0x86bd9c: kMiddleAgedMan_Dmd
+0x86bdac: MiddleAgedMan_Draw
+0x86bdc1: Sprite_2B_Hobo
+0x86bdd0: Sprite_Hobo_Bum
+0x86bdfa: Hobo_Sleep
+0x86be2a: kHobo_Gfx
+0x86be32: kHobo_Delay
+0x86be39: Hobo_Awoken
+0x86be5f: Hobo_GiveBottle
+0x86be89: Hobo_BackToSleep
+0x86be9d: SpritePrep_Hobo_SpawnSmoke
+0x86beb4: Sprite_Hobo_Bubble
+0x86beed: Hobo_SpawnBubble
+0x86bf15: Sprite_Hobo_Fire
+0x86bf4b: SpritePrep_Hobo_SpawnFire
+0x86bf7d: kHoboSmoke_OamFlags
+0x86bf81: Sprite_Hobo_Smoke
+0x86bfaf: Hobo_SpawnSmoke
+0x86bfe0: Sprite_73_UncleAndPriest_bounce
+0x86bfe5: SpritePrep_UncleAndPriest_bounce
+0x86bfea: SpriteModule_Active_bounce
+0x86bfef: SpriteActive3_Trampoline
+0x86bff4: SpriteActive4_Trampoline
+0x86bff9: SpritePrep_OldMan_bounce
+0x86bffe: Sprite_TutorialGuardOrBarrier_bounce
+0x86c003: Sprite_PullSwitch_
+0x86c008: Sprite_SomariaPlatformAndPipe_bounce
+0x86c00d: Sprite_F2_MedallionTablet_bounce
+0x86c012: Sprite_32_ArguingBros_bounce
+0x86c017: Sprite_33_RupeePull_bounce
+0x86c01c: Sprite_14_ThievesTownGrate_bounce
+0x86c021: Sprite_34_YoungSnitch_bounce
+0x86c026: SpritePrep_Snitch_bounce_2
+0x86c02b: Sprite_35_Innkeeper_bounce
+0x86c030: SpritePrep_Snitch_bounce_3
+0x86c035: Sprite_36_Witch_bounce
+0x86c03a: Sprite_37_Waterfall_bounce
+0x86c03f: Sprite_38_EyeStatue_bounce
+0x86c044: Sprite_3A_MagicBat_bounce
+0x86c049: Sprite_3B_BonkItem_bounce
+0x86c04e: Sprite_3C_KidInKak_bounce
+0x86c053: Sprite_3D_OldSnitch_bounce
+0x86c058: Sprite_74_RunningBoy_bounce
+0x86c05d: SpritePrep_RunningBoy_bounce
+0x86c062: Sprite_75_BottleMerchant_bounce
+0x86c067: Sprite_76_Zelda_bounce
+0x86c06c: SpritePrep_Zelda_bounce
+0x86c071: Sprite_78_MrsSahasrahla_bounce
+0x86c076: Sprite_E7_Mushroom_bounce
+0x86c07b: SpritePrep_Mushroom_bounce
+0x86c080: Sprite_E8_FakeMasterSword_bounce
+0x86c085: SpritePrep_FakeMasterSword_bounce
+0x86c08a: Sprite_16_Elder_bounce
+0x86c08f: Sprite_E9_MagicShopAssistant_bounce
+0x86c094: SpritePrep_MagicShopAssistant_bounce
+0x86c099: Sprite_EA_HeartContainer_bounce
+0x86c09e: SpritePrep_HeartContainer_bounce
+0x86c0a3: Sprite_EB_HeartPiece_bounce
+0x86c0a8: SpritePrep_HeartPiece
+0x86c0ad: Sprite_2E_FluteKid_bounce
+0x86c0b2: Sprite_2D_TelepathicTile_bounce
+0x86c0b7: Sprite_29_Adult_bounce
+0x86c0bc: Sprite_2A_SweepingLady_bounce
+0x86c0c1: Sprite_2C_Lumberjacks_bounce
+0x86c0c6: Sprite_31_FortuneTeller_bounce
+0x86c0cb: Sprite_2F_RaceGameLady_bounce
+0x86c0d0: Sprite_30_RaceGameGuy_bounce
+0x86c0d5: Sprite_25_TalkingTree_bounce
+0x86c0da: kMovableStatue_Dir
+0x86c0de: kMovableStatue_Joypad
+0x86c0e2: kMovableStatue_Xvel
+0x86c0e4: kMovableStatue_Yvel
+0x86c0e8: Sprite_1C_Statue
+0x86c172: else_1
+0x86c1f7: kMovableStatue_SwitchX
+0x86c1fb: kMovableStatue_SwitchY
+0x86c203: Statue_CheckForSwitch
+0x86c24c: kMovableStatue_Dmd
+0x86c264: MovableStatue_Draw
+0x86c277: Statue_BlockSprites
+0x86c2e5: Sprite_1D_FluteQuest
+0x86c309: kWishPond_X
+0x86c311: kWishPond_Y
+0x86c319: Sprite_72_FairyPond
+0x86c41d: Sprite_WishPond2
+0x86c44c: Sprite_HappinessPond
+0x86c471: kWishPond2_Dmd
+0x86c4b5: WishPond2_Draw
+0x86c4fd: Sprite_FairyPond_WaitForLink
+0x86c523: kHapinessPondCost
+0x86c527: kHapinessPondCostHex
+0x86c52b: Sprite_LakeHyliaFairy_WaitForLink
+0x86c570: Sprite_LakeHyliaFairy_BegForDonation
+0x86c59f: Sprite_LakeHyliaFairy_AcceptDonation
+0x86c603: Sprite_LakeHyliaFairy_WaitForDonation
+0x86c616: Sprite_LakeHyliaFairy_SpawnFairy
+0x86c665: Sprite_LakeHyliaFairy_Greetings
+0x86c691: Sprite_LakeHyliaFairy_OfferUpgrade
+0x86c6a0: Sprite_LakeHyliaFairy_UpgradeBombs
+0x86c6d2: Sprite_LakeHyliaFairy_RevertTranslucency
+0x86c6e7: Sprite_LakeHyliaFairy_DeleteFairy
+0x86c70e: Sprite_LakeHyliaFairy_RestoreAndReset
+0x86c721: Sprite_LakeHyliaFairy_UpgradeArrows
+0x86c763: Sprite_LakeHyliaFairy_GiveDonationStatus
+0x86c76f: kHappinessPondLuckMsg
+0x86c777: kHappinessPondLuck
+0x86c77b: LakeHyliaFairy_GrantLuck
+0x86c7a1: Sprite_UpgradeFairy_WaitForLink
+0x86c7c6: Sprite_UpgradeFairy_OfferItemToss
+0x86c7ed: Sprite_UpgradeFairy_HandleItemToss
+0x86c83c: Sprite_UpgradeFairy_SpawnFairy
+0x86c88b: Sprite_UpgradeFairy_AskWhoDidThis
+0x86c8b7: Sprite_UpgradeFairy_HandleAnswer
+0x86c8c6: Sprite_UpgradeFairy_HandleUpgrade
+0x86c952: Sprite_UpgradeFairy_Retreat
+0x86c97a: Sprite_UpgradeFairy_FixPalettes
+0x86c9a1: Sprite_UpgradeFairy_HandleItemReceipt
+0x86c9be: kWishPondMsgs
+0x86c9c8: Sprite_UpgradeFairy_FinalGoodBye
+0x86c9e5: Sprite_UpgradeFairy_YouLiar
+0x86c9f1: Sprite_UpgradeFairy_SecondChance
+0x86ca00: Sprite_UpgradeFairy_DebaseLink
+0x86ca0e: kFaerieQueen_Draw_X
+0x86ca26: kFaerieQueen_Draw_Y
+0x86ca3e: kFaerieQueen_Draw_Char
+0x86ca56: kFaerieQueen_Draw_Flags
+0x86ca6e: kFaerieQueen_Draw_Ext
+0x86ca86: kFaerieQueen_Dmd
+0x86cb26: FaerieQueen_Draw
+0x86cba2: Sprite_71_Leever
+0x86cbd8: Leever_Underground
+0x86cbf5: UNREACHABLE_06CBFD
+0x86cc03: kLeever_EmergeGfx
+0x86cc13: Leever_Emerge
+0x86cc37: kLeever_AttackGfx
+0x86cc3a: kLeever_AttackSpd
+0x86cc3c: Leever_Attack
+0x86cc7a: kLeever_SubmergeGfx
+0x86cc8a: Leever_Dig
+0x86ccaf: kLeever_Draw_X
+0x86cd1f: kLeever_Draw_Y
+0x86cd8f: kLeever_Draw_Char
+0x86cdc7: kLeever_Draw_Flags
+0x86cdff: kLeever_Draw_Ext
+0x86ce37: kLeever_Draw_Num
+0x86ce45: Leever_Draw
+0x86cec0: Sprite_D8_Heart
+0x86cf0a: HeartRefill_InitializeAscent
+0x86cf20: HeartRefill_BeginDescending
+0x86cf35: kHeartRefill_VelTarget
+0x86cf37: HeartRefill_GlideGroundward
+0x86cf5a: Sprite_ZeroVelocity_XYZ
+0x86cf5d: Sprite_ZeroVelocity_XY
+0x86cf64: Sprite_HandleDraggingByAncilla
+0x86cf94: Sprite_E3_Fairy
+0x86cfbb: Fairy_Prancing
+0x86cfe4: Fairy_HandleCapture
+0x86d011: Fairy_CheckIfTouchable
+0x86d030: kAbsorbBigKey
+0x86d032: Sprite_E4_SmallKey
+0x86d04a: Sprite_D9_GreenRupee
+0x86d051: Sprite_Absorbable_Main
+0x86d0ed: Sprite_ReturnIfPhasingOut
+0x86d116: Sprite_CheckAbsorptionByPlayer
+0x86d125: Sprite_HandleAbsorptionByPlayer_
+0x86d12d: kAbsorptionSfx
+0x86d13c: Sprite_HandleAbsorptionByPlayer
+0x86d170: Absorb_Shield
+0x86d178: Absorb_BigKey
+0x86d1a5: Absorb_Fairy
+0x86d1af: Absorb_Heart
+0x86d1bb: kRupeesAbsorption
+0x86d1be: Absorb_Rupee
+0x86d1d5: kBombsAbsorption
+0x86d1d8: Absorb_Bomb
+0x86d1e8: Absorb_SmallMagic
+0x86d1f8: Absorb_Arrows_5
+0x86d20d: kAbsorbable_Tab1
+0x86d21c: kAbsorbable_Tab2
+0x86d22f: SpriteDraw_AbsorbableTransient
+0x86d232: Sprite_DrawAbsorbable_nontransient
+0x86d28a: kNumberedAbsorbable_X
+0x86d2ae: kOctorock_OamFlags
+0x86d2b2: kNumberedAbsorbable_Y
+0x86d2d6: kNumberedAbsorbable_Char
+0x86d2e8: kNumberedAbsorbable_Ext
+0x86d2fa: Sprite_DrawNumberedAbsorbable
+0x86d363: kOctorock_Dir
+0x86d367: kOctorock_Xvel
+0x86d36b: kOctorock_Yvel
+0x86d36f: kOctorock_Delays
+0x86d377: Sprite_08_Octorok
+0x86d451: kOctorock_Tab0
+0x86d465: kOctorock_Tab1
+0x86d46f: Octorok_ShootSingle
+0x86d486: kOctorock_NextDir
+0x86d48a: Octorok_Shoot4Ways
+0x86d4b5: kOctorock_Spit_X
+0x86d4bd: kOctorock_Spit_Y
+0x86d4c5: kOctorock_Spit_Xvel
+0x86d4c9: kOctorock_Spit_Yvel
+0x86d4cd: Octorok_FireLoogie
+0x86d514: kOctorock_Draw_X
+0x86d526: kOctorock_Draw_Y
+0x86d538: kOctorock_Draw_Char
+0x86d541: kOctorock_Draw_Flags
+0x86d54a: Octorock_Draw
+0x86d5b9: Sprite_0C_OctorokStone
+0x86d5f3: kOctostone_Draw_X
+0x86d613: kOctostone_Draw_Y
+0x86d633: kOctostone_Draw_Flags
+0x86d643: SpriteDraw_OctorokStoneCrumbling
+0x86d6a2: kSprite_Octoballoon_Z
+0x86d6aa: Sprite_0F_Octoballoon
+0x86d72b: Octoballoon_RecoilLink
+0x86d73c: kOctoballoon_Draw_X
+0x86d754: kOctoballoon_Draw_Y
+0x86d76c: kOctoballoon_Draw_Char
+0x86d778: kOctoballoon_Draw_Flags
+0x86d784: Octoballoon_Draw
+0x86d802: kOctoballoon_Spawn_Xv
+0x86d808: kOctoballoon_Spawn_Yv
+0x86d80e: Octoballoon_FormBabby
+0x86d853: Sprite_10_OctoballoonBaby
+0x86d88b: Sprite_CheckDamageBoth___
+0x86d892: kBuzzBlob_Gfx
+0x86d896: kBuzzBlob_ObjPrio
+0x86d89a: Sprite_0D_Buzzblob
+0x86d8ee: kBuzzBlob_Xvel
+0x86d8f6: kBuzzBlob_Yvel
+0x86d8fe: kBuzzBlob_Delay
+0x86d906: Buzzblob_SelectNewDirection
+0x86d920: kBuzzBlob_DrawX
+0x86d926: kBuzzBlob_DrawY
+0x86d92c: kBuzzBlob_DrawChar
+0x86d93e: kBuzzBlob_DrawFlags
+0x86d950: kBuzzBlob_DrawExt
+0x86d953: BuzzBlob_Draw
+0x86d9c0: Sprite_BounceOffWall
+0x86d9d5: Sprite_InvertSpeed_XY
+0x86d9e2: Sprite_InvertSpeed_Y
+0x86d9ec: Sprite_ReturnIfInactive
+0x86d9f3: Sprite_ReturnIfPaused
+0x86da09: kSprite_PrepAndDrawSingleLarge_Tab2
+0x86db04: kSprite_PrepAndDrawSingleLarge_Tab1
+0x86dbf0: Sprite_PrepAndDrawSingleLarge_
+0x86dbf8: Sprite_PrepAndDrawSingleSmall_
+0x86dc10: SpriteDraw_SingleLarge
+0x86dc13: Sprite_PrepAndDrawSingleLargeNoPrep
+0x86dc54: Sprite_DrawShadow_
+0x86dc5c: SpriteDraw_Shadow_custom
+0x86dc64: SpriteDraw_Shadow
+0x86dc66: Sprite_DrawShadowEx_
+0x86dcef: SpriteDraw_SingleSmall
+0x86dd38: Sprite_DrawKey_
+0x86dd40: Sprite_DrawThinAndTall
+0x86ddaf: kStalfosHead_OamFlags
+0x86ddb3: kStalfosHead_Gfx
+0x86ddb7: Sprite_02_StalfosHead
+0x86de4d: kSpriteHeld_X
+0x86de6d: kSpriteHeld_Z
+0x86de7d: kSpriteHeld_ZForFrame
+0x86de83: SpriteModule_Carried
+0x86df61: kSpriteHeld_Throw_Xvel
+0x86df65: kSpriteHeld_Throw_Yvel
+0x86df69: kSpriteHeld_Throw_Zvel
+0x86df6d: CarriedSprite_CheckForThrow
+0x86dff2: ThrownSprite_TileAndPeerInteraction_
+0x86dffa: SpriteModule_Stunned
+0x86e02a: ThrownSprite_TileAndSpriteInteraction
+0x86e0ab: Sprite_Func8
+0x86e0f6: Sprite_Func22
+0x86e164: ThrowableScenery_InteractWithSpritesAndTiles
+0x86e172: ThrownSprite_CheckDamageToSprites
+0x86e1b2: ThrownSprite_CheckDamageToSingleSprite
+0x86e229: Sprite_ApplyRicochet
+0x86e22f: ThrowableScenery_TransmuteIfValid
+0x86e239: ThrowableScenery_TransmuteToDebris
+0x86e25a: Sprite_ScheduleForBreakage
+0x86e26e: Sprite_HalveSpeed_XY
+0x86e27d: kSprite_Func21_Sfx
+0x86e286: Sprite_SpawnLeapingFish
+0x86e2a7: kSparkleGarnish_XY
+0x86e2ab: kSparkleGarnish_HighXY
+0x86e2af: kSpriteStunned_Main_Func1_Masks
+0x86e2b6: HandleFreezeAndStunTimer
+0x86e2ba: SpriteStunned_Main_Func1
+0x86e343: kSpritePoof_X
+0x86e353: kSpritePoof_Y
+0x86e363: kSpritePoof_Char
+0x86e373: kSpritePoof_Flags
+0x86e383: kSpritePoof_Ext
+0x86e393: SpriteModule_Poof
+0x86e416: Sprite_PrepOamCoord
+0x86e41a: Sprite_PrepOamCoordSafeWrapper
+0x86e41e: Sprite_PrepOamCoordOrDoubleRet
+0x86e496: Sprite_CheckTileCollision_
+0x86e4a1: Sprite_CheckTileCollision_set_layer
+0x86e4a8: Sprite_CheckTileCollision_check_just_one
+0x86e4ab: Sprite_CheckTileCollision2
+0x86e4db: Sprite_CheckTileCollisionSingleLayer
+0x86e5b8: Sprite_CheckForTileInDirection_horizontal
+0x86e5ee: Sprite_CheckForTileInDirection_vertical
+0x86e624: SpriteFall_AdjustPosition
+0x86e64b: kSprite_Func5_X
+0x86e6b7: kSprite_Func5_Y
+0x86e723: kSprite_Func7_Tab
+0x86e72f: Sprite_CheckTileInDirection
+0x86e73c: Sprite_CheckTileProperty
+0x86e87b: GetTileAttribute
+0x86e883: Sprite_GetTileAttribute
+0x86e886: Entity_GetTileAttr_
+0x86e8d6: kSlopedTile
+0x86e8f6: Sprite_CheckSlopedTileCollision
+0x86e8fe: Entity_CheckSlopedTileCollision
+0x86e92c: Sprite_MoveXY
+0x86e932: Sprite_MoveX
+0x86e93e: Sprite_MoveY
+0x86e96c: Sprite_MoveZ
+0x86e98e: Sprite_ProjectSpeedTowardsLink_instantexit
+0x86e991: Sprite_ProjectSpeedTowardsLink
+0x86ea04: Sprite_ApplySpeedTowardsLink
+0x86ea12: Sprite_ApplySpeedTowardsPlayer_
+0x86ea1a: Sprite_ProjectSpeedTowardsPlayer_
+0x86ea22: Sprite_ProjectSpeedTowardsEntity_
+0x86ea2a: Sprite_ProjectSpeedTowardsLocation_fastexit
+0x86ea2d: Sprite_ProjectSpeedTowardsLocation
+0x86eaa0: Sprite_DirectionToFacePlayer_
+0x86eaa4: Sprite_DirectionToFaceLink
+0x86eacd: Sprite_IsToRightOfPlayer__
+0x86ead1: Sprite_IsRightOfLink
+0x86eae4: Sprite_IsBelowPlayer_
+0x86eae8: Sprite_IsBelowLink
+0x86eb0a: Sprite_IsRightOfLocation
+0x86eb1d: Sprite_IsBelowLocation
+0x86eb30: Sprite_DirectionToFaceLocation
+0x86eb5e: Guard_ParrySwordAttacks
+0x86eb66: kSprite_Func1_Tab
+0x86eb6e: kSprite_Func1_Tab2
+0x86eb76: Sprite_Func1_
+0x86ec02: Sprite_AttemptZapDamage
+0x86ec5c: Medallion_CheckSpriteDamage
+0x86ec7e: kAncilla_Damage
+0x86ecb7: Ancilla_CheckDamageToSprite
+0x86ecbd: Ancilla_CheckDamageToSprite_aggressive
+0x86ece0: Ancilla_CheckDamageToSprite_preset
+0x86ed25: Sprite_Func15
+0x86ed33: kSprite_Func14_Damage
+0x86ed3f: Sprite_CalculateSwordDamage
+0x86ed89: Sprite_ApplyCalculatedDamage
+0x86edc5: AgahnimBalls_DamageAgahnim
+0x86edcb: Sprite_Func18
+0x86eec8: Sprite_MiniMoldorm_Recoil
+0x86ef5c: kHitTimer24StunValues
+0x86efda: Sprite_Func3
+0x86f025: is_0f
+0x86f0ac: Trinexx_ScheduleSideHeadForDeath
+0x86f121: Sprite_CheckDamageToPlayer_
+0x86f129: Sprite_CheckDamageToPlayerSameLayer_
+0x86f131: Sprite_CheckDamageToPlayerIgnoreLayer_
+0x86f139: kSprite_ReturnIfLifted_Dirs
+0x86f13d: kSpriteDamage_Tab2
+0x86f141: kSpriteDamage_Tab3
+0x86f145: Sprite_CheckDamageToLink
+0x86f14a: Sprite_CheckDamageToPlayer_1
+0x86f154: Sprite_CheckDamageToLink_same_layer
+0x86f15c: Sprite_CheckDamageToLink_ignore_layer
+0x86f1f6: Sprite_SetupHitBox00
+0x86f228: Sprite_ReturnIfLifted
+0x86f257: Sprite_ReturnIfLiftedPermissive
+0x86f2aa: Sprite_CheckDamageFromPlayer_
+0x86f2b4: Sprite_CheckDamageFromLink
+0x86f3ca: Sprite_AttemptDamageToLinkWithCollisionCheck
+0x86f3db: Sprite_AttemptDamageToLinkPlusRecoil
+0x86f41f: Sprite_AttemptDamageToPlayerPlusRecoil_
+0x86f427: kPlayerDamages
+0x86f445: Sprite_RecoilLinkAndTHUMP
+0x86f46d: kPlayer_SetupActionHitBox_Tab0
+0x86f4ae: kPlayer_SetupActionHitBox_Tab1
+0x86f4ef: kPlayer_SetupActionHitBox_Tab2
+0x86f530: kPlayer_SetupActionHitBox_Tab3
+0x86f571: kPlayer_SetupActionHitBox_Tab4
+0x86f57e: SetupActionHitBox
+0x86f586: kPlayerActionBoxRun_YHi
+0x86f588: kPlayerActionBoxRun_XLo
+0x86f58c: kPlayerActionBoxRun_XHi
+0x86f590: kPlayerActionBoxRun_YLo
+0x86f594: SetupActionHitBox_spinning
+0x86f5b7: SetupActionHitBox_dashing
+0x86f5e0: Player_SetupActionHitBox
+0x86f645: Sprite_DoHitBoxesFast
+0x86f688: Sprite_ApplyRecoilToLink
+0x86f69f: Link_PlaceWeaponTink
+0x86f6ca: Sprite_PlaceWeaponTink
+0x86f6d5: Sprite_PlaceRupulseSpark_2
+0x86f705: Link_SetupHitBox_conditional
+0x86f70a: Link_SetupHitBox
+0x86f72f: kSpriteHitbox_XLo
+0x86f74f: kSpriteHitbox_XHi
+0x86f76f: kSpriteHitbox_XSize
+0x86f78f: kSpriteHitbox_YLo
+0x86f7af: kSpriteHitbox_YHi
+0x86f7cf: kSpriteHitbox_YSize
+0x86f7ef: Sprite_SetupHitBox
+0x86f836: CheckIfHitBoxesOverlap
+0x86f864: OAM_AllocateDeferToPlayer_
+0x86f86c: Oam_AllocateDeferToPlayer
+0x86f8a2: SpriteModule_Die
+0x86f8c9: SpriteDeath_MainEx_true
+0x86f917: SpriteDeath_Func1_
+0x86f91f: kPikitDropItems
+0x86f923: Sprite_DoTheDeath
+0x86f9bc: ForcePrizeDrop
+0x86f9bd: SpriteDeath_Func2_argInA
+0x86f9d1: PrepareEnemyDrop
+0x86fa22: SpriteDeath_Func4_Tmp
+0x86fa25: SpriteDeath_Func4
+0x86fa54: SpriteDeath_Func2_
+0x86fa5c: kPrizeMasks
+0x86fa63: kPrizeZ
+0x86fa72: kPrizeItems
+0x86faaa: kPerishOverlay_X
+0x86faca: kPerishOverlay_Y
+0x86faea: kPerishOverlay_Char
+0x86fb0a: kPerishOverlay_Flags
+0x86fb2a: SpriteDeath_DrawPoof
+0x86fb96: kSpriteFall_Tab1
+0x86fbb6: kSpriteFall_Tab2
+0x86fbd6: kSpriteFall_Tab3
+0x86fbe6: kSpriteFall_Tab4
+0x86fbea: SpriteModule_Fall2
+0x86fcb7: kSpriteDrawFall0Data
+0x86fd17: SpriteDraw_FallingHelmaBeetle
+0x86fd43: kSpriteDrawFall1_X
+0x86fd7b: kSpriteDrawFall1_Y
+0x86fdb3: kSpriteDrawFall1_Char
+0x86fdeb: kSpriteDrawFall1_Flags
+0x86fe23: kSpriteDrawFall1_Ext
+0x86fe5b: SpriteDraw_FallingHumanoid
+0x86feb4: Sprite_CorrectOamEntries_
+0x86febc: Sprite_CorrectOamEntries
+0x86ff26: Sprite_GetScreenRelativeCoords
+0x86ff49: Sprite_CheckIfOnScreenX
+0x86ff56: Sprite_CheckIfOnScreenY
+0x86ff6d: UNREACHABLE_06FF73
+0x86ff72: kSprite_ReturnIfRecoiling_Masks
+0x86ff78: Sprite_ReturnIfRecoiling
+0x878000: Link_Main
+0x878021: PlaySfx_Set1
+0x878028: PlaySfx_Set2
+0x87802f: PlaySfx_Set3
+0x878036: PlaySfx_SetPan
+0x878041: kPlayerHandlers
+0x87807f: Link_ControlHandler
+0x878109: LinkState_Default
+0x878130: HandleLink_From1D
+0x8781a0: PlayerHandler_00_Ground_3
+0x8782d8: return_false_loc_8782D8
+0x8782da: Link_HandleBunnyTransformation
+0x878365: LinkState_TemporaryBunny
+0x8783a1: PlayerHandler_17_Bunny
+0x8783c7: LinkState_Bunny_recache
+0x8783fa: Link_TempBunny_Func2
+0x878481: LinkState_HoldingBigRock
+0x87855a: EtherTablet_StartCutscene
+0x878570: LinkState_ReceivingEther
+0x8785e5: BombosTablet_StartCutscene
+0x8785fb: LinkState_ReceivingBombos
+0x87866d: InitiateDesertCutscene
+0x87867b: LinkState_ReadingDesertTablet
+0x878689: HandleSomariaAndGraves
+0x8786b5: LinkState_Recoil
+0x878711: Link_HandleRecoilAndTimer
+0x8787db: Player_HandleIncapacitated_MiddleEntry
+0x878872: LinkState_OnIce
+0x878926: Link_HandleChangeInZVelocity
+0x878932: Player_ChangeZ
+0x87894e: LinkHop_HoppingSouthOW
+0x878a05: LinkState_HandlingJump
+0x878ac9: kLink_DoMoveXCoord_Outdoors_Helper2_y
+0x878acd: kLink_DoMoveXCoord_Outdoors_Helper2_y2
+0x878ad1: LinkHop_FindTileToLandOnSouth
+0x878b74: LinkState_HoppingHorizontallyOW
+0x878b8b: kLink_DoMoveXCoord_Outdoors_Helper2_z
+0x878b93: kLink_DoMoveXCoord_Outdoors_Helper2_velx
+0x878b9b: Link_HoppingHorizontally_FindTile_Y
+0x878c44: Link_SetToDeepWater
+0x878c69: LinkState_0F
+0x878cef: kLink_DoMoveXCoord_Outdoors_Helper1_tab1
+0x878cf3: kLink_DoMoveXCoord_Outdoors_Helper1_tab2
+0x878cf7: kLink_DoMoveXCoord_Outdoors_Helper1_tab3
+0x878cfb: kLink_DoMoveXCoord_Outdoors_Helper1_velx
+0x878d13: kLink_DoMoveXCoord_Outdoors_Helper1_velz
+0x878d2b: Link_HoppingHorizontally_FindTile_X
+0x878dc6: LinkState_HoppingDiagonallyUpOW
+0x878dfd: kLedgeVelX
+0x878e15: LinkState_HoppingDiagonallyDownOW
+0x878e6d: kLink_Ledge_Func1_dx
+0x878e71: kLink_Ledge_Func1_dy
+0x878e75: kLink_Ledge_Func1_dy2
+0x878e79: kLink_Ledge_Func1_bits
+0x878e7b: LinkHop_FindLandingSpotDiagonallyDown
+0x878f1d: Link_SplashUponLanding
+0x878f61: kDashTab2
+0x878f65: kDashTab1
+0x878f68: kTagalongArr1
+0x878f77: kTagalongArr2
+0x878f86: LinkState_Dashing
+0x87915e: LinkState_ExitingDash
+0x879195: Link_CancelDash
+0x8791b9: Player_HaltDashAttack_
+0x8791bd: kDashTab6Y
+0x8791c1: kDashTab6X
+0x8791c5: kDashTabSw11Y
+0x8791c9: kDashTabSw11X
+0x8791cd: kDashTabSw7Y
+0x8791dd: kDashTabSw7X
+0x8791ed: kDashTabDir
+0x8791f1: RepelDash
+0x879222: LinkApplyTileRebound
+0x879291: Sprite_RepelDash
+0x8792a0: Flag67WithDirections
+0x8792bf: kFallHoleDirs2
+0x8792c7: kFallHoleDirs
+0x8792cf: kFallHolePitDirs
+0x8792d3: LinkState_Pits
+0x8794f1: HandleLayerOfDestination
+0x879502: DungeonPitDoDamage
+0x879520: HandleDungeonLandingFromPit
+0x879635: kSwimmingTab1
+0x879639: swim_240
+0x87963b: PlayerHandler_04_Swimming
+0x879715: Link_HandleSwimMovements
+0x879785: Link_FlagMaxAccels
+0x8797a6: Link_SetIceMaxAccel
+0x8797c3: kSwimmingTab2
+0x8797c7: Link_SetMomentum
+0x87983a: Link_ResetSwimmingState
+0x87984b: Link_ResetStateAfterDamagingPit
+0x879873: ResetAllAcceleration
+0x879896: kSwimmingTab3
+0x8798a8: Link_HandleSwimAccels
+0x879903: Link_SetTheMaxAccel
+0x87996c: LinkState_Zapped
+0x8799ac: PlayerHandler_15_HoldItem
+0x8799ad: Link_ReceiveItem
+0x879a2c: Link_TuckIntoBed
+0x879a5a: LinkState_Sleeping
+0x879a62: Link_SnoringInBed
+0x879a71: Link_SittingUpInBed
+0x879aa1: Link_JumpingOutOfBed
+0x879ac2: Link_HandleSwordCooldown
+0x879ae5: return_locret_879AE5
+0x879ae6: kLinkItemHandlers
+0x879b0e: Link_HandleYItem
+0x879ba2: kAbilityBitmasks
+0x879baa: Link_HandleAPress
+0x879c5f: Link_APress_PerformBasic
+0x879c66: HandleSwordSfxAndBeam
+0x879cbf: kSpinAttackDelays
+0x879cd1: kFireBeamSounds
+0x879cd9: Link_CheckForSwordSwing
+0x879d72: HandleSwordControls
+0x879d84: Link_ResetSwordAndItemUsage
+0x879d9f: Player_Sword_SpinAttackJerks_HoldDown
+0x879e63: CalculateSwordHitBox
+0x879eec: kRodAnimDelays
+0x879eef: LinkItem_Rod
+0x879f5d: RodItem_CreateShot
+0x879f66: RodItem_CreateIceShot
+0x879f6f: RodItem_CreateFireShot
+0x879f78: kHammerAnimDelays
+0x879f7b: LinkItem_Hammer
+0x87a003: kBowDelays
+0x87a006: LinkItem_Bow
+0x87a0bb: LinkItem_Boomerang
+0x87a11f: Link_ResetBoomerangYStuff
+0x87a138: LinkItem_Bombs
+0x87a15b: LinkItem_Bottle
+0x87a24d: LinkItem_Lamp
+0x87a289: kMushroomTimer
+0x87a293: LinkItem_Powder
+0x87a313: LinkItem_ShovelAndFlute
+0x87a320: kShovelAnimDelay
+0x87a326: kShovelAnimDelay2
+0x87a32c: LinkItem_Shovel
+0x87a3db: LinkItem_Flute
+0x87a45f: CallForDuckIndoors
+0x87a471: LinkItem_Book
+0x87a494: LinkItem_Ether
+0x87a4f7: kEtherAnimStates
+0x87a503: kEtherAnimDelays
+0x87a50f: LinkState_UsingEther
+0x87a569: LinkItem_Bombos
+0x87a5cf: kBombosAnimStates
+0x87a5e3: kBombosAnimDelays
+0x87a5f7: LinkState_UsingBombos
+0x87a64b: LinkItem_Quake
+0x87a6be: kQuakeAnimStates
+0x87a6ca: kQuakeAnimDelays
+0x87a6d6: LinkState_UsingQuake
+0x87a77a: Link_ActivateSpinAttack
+0x87a783: Link_AnimateVictorySpin
+0x87a7b0: Link_SetSpinAttacking_
+0x87a7b8: kLinkSpinGraphiccsByDir
+0x87a7f4: kLinkSpinDelays
+0x87a800: kLinkSpinOffsetsByDir
+0x87a804: LinkState_SpinAttack
+0x87a8ec: UNREACHABLE_07A8DC
+0x87a91a: LinkItem_Mirror
+0x87a955: PlaySfx60
+0x87a95c: DoSwordInteractionWithTiles_Mirror
+0x87a9b1: LinkState_CrossingWorlds
+0x87aa6c: Link_PerformDesertPrayer
+0x87aaa2: HandleFollowersAfterMirroring
+0x87ab25: LinkItem_Hookshot
+0x87ab6c: kHookshotArrA
+0x87ab70: kHookshotArrB
+0x87ab74: kHookshotArrC
+0x87ab78: kHookshotArrD
+0x87ab7c: LinkState_Hookshotting
+0x87adbe: kCapeDepletionTimers
+0x87adc1: LinkItem_Cape
+0x87ae47: Link_ForceUnequipCape
+0x87ae54: Link_ForceUnequipCape_quietly
+0x87ae65: HaltLinkWhenUsingItems
+0x87ae88: Link_HandleCape_passive_LiftCheck
+0x87ae8f: Player_CheckHandleCapeStuff
+0x87aec0: LinkItem_CaneOfSomaria
+0x87af3b: kByrnaDelays
+0x87af3e: LinkItem_CaneOfByrna
+0x87afb5: SearchForByrnaSpark
+0x87afcc: kBugNetTimers
+0x87aff4: kMult10
+0x87aff8: LinkItem_Net
+0x87b073: CheckYButtonPress
+0x87b087: kLinkItem_MagicCosts
+0x87b0a2: kLinkItem_MagicCostBaseIndices
+0x87b0ab: LinkCheckMagicCost
+0x87b0e9: Refund_Magic
+0x87b107: Link_ItemReset_FromOverworldThings
+0x87b11c: Link_PerformThrow
+0x87b199: kLiftTab2
+0x87b1ad: kLink_Lift_tab
+0x87b1b6: kLiftTab0
+0x87b1c0: kLiftTab1
+0x87b1ca: Link_APress_LiftCarryThrow
+0x87b281: Link_PerformDash
+0x87b2ed: Link_APress_NothingB
+0x87b2ee: Link_PerformGrab
+0x87b310: kGrabWallDirs
+0x87b314: kGrabWall_AnimTimer
+0x87b31b: kGrabWall_AnimSteps
+0x87b322: Link_APress_PullObject
+0x87b371: Link_PerformStatueDrag
+0x87b389: Link_APress_StatueDrag
+0x87b3e5: Link_PerformRupeePull
+0x87b40c: nullsub_9
+0x87b40d: kGrabWall_AnimSteps2
+0x87b416: LinkState_TreePull
+0x87b4f2: Link_PerformRead
+0x87b527: nullsub_7
+0x87b528: kLink_ReceiveItemAlternates
+0x87b574: Link_PerformOpenChest
+0x87b5c0: Link_CheckNewAPress
+0x87b5d6: Link_HandleToss
+0x87b609: UNREACHABLE_07B5F2
+0x87b64b: kPlayer_LimitDirectionMask
+0x87b64f: Link_HandleDiagonalCollision
+0x87b660: Player_LimitDirections_Inner
+0x87b7c7: Link_HandleCardinalCollision
+0x87b956: RunSlopeCollisionChecks_VerticalFirst
+0x87b969: RunSlopeCollisionChecks_HorizontalFirst
+0x87b97c: CheckIfRoomNeedsDoubleLayerCheck
+0x87b9b3: CreateVelocityFromMovingBackground
+0x87b9f7: kLink_DoMoveXCoord_Indoors_dy
+0x87b9ff: kLink_DoMoveXCoord_Indoors_dx
+0x87ba0a: StartMovementCollisionChecks_Y
+0x87ba35: StartMovementCollisionChecks_Y_HandleIndoors
+0x87bd49: endif_24
+0x87bdb1: HandlePushingBonkingSnaps_Y
+0x87bdc8: endif_3
+0x87beaf: StartMovementCollisionChecks_Y_HandleOutdoors
+0x87c16d: RunLedgeHopTimer
+0x87c189: Link_RestorePreviousCoords
+0x87c1a1: Link_BonkAndSmash
+0x87c1c3: Link_Move_Helper4_CheckSmash_Inner
+0x87c1e4: Link_AddInVelocityYFalling
+0x87c1ff: CalculateSnapScratch_Y
+0x87c229: AddAbsoluteScratchToXCoord
+0x87c23d: ChangeAxisOfPerpendicularDoorMovement_Y
+0x87c29f: Link_AddInVelocityY
+0x87c2ba: kRecoilVelY_Ydir
+0x87c2bd: kRecoilVelZ_Ydir
+0x87c2c3: Link_HopInOrOutOfWater_Y
+0x87c30c: kLink_MoveY_RecoilOther_dy
+0x87c32c: kLink_MoveY_RecoilOther_dz
+0x87c34c: kLink_MoveY_RecoilOther_timer
+0x87c36c: Link_FindValidLandingTile_North
+0x87c409: kLink_JumpOffLedgeUpDown_dy
+0x87c429: kLink_JumpOffLedgeUpDown_dx
+0x87c449: kLink_JumpOffLedgeUpDown_dz
+0x87c46d: Link_FindValidLandingTile_DiagonalNorth
+0x87c4d4: StartMovementCollisionChecks_X
+0x87c4ff: StartMovementCollisionChecks_X_HandleIndoors
+0x87c7fc: HandlePushingBonkingSnaps_X
+0x87c8e9: StartMovementCollisionChecks_X_HandleOutdoors
+0x87cb84: SnapOnX
+0x87cb9f: CalculateSnapScratch_X
+0x87cbc9: AddAbsoluteScratchToYCoord
+0x87cbdd: ChangeAxisOfPerpendicularDoorMovement_X
+0x87cc33: kRecoilVelX
+0x87cc36: kRecoilVelZ
+0x87cc39: kRecoilIncapacitated
+0x87cc3c: Link_HopInOrOutOfWater_X
+0x87cc83: Link_AvoidJudderAgainstDiagWall_x0
+0x87cc8d: Link_AvoidJudderAgainstDiagWall_x1
+0x87cc97: Link_AvoidJudderAgainstDiagWall_y0
+0x87cca1: Link_AvoidJudderAgainstDiagWall_y1
+0x87ccab: Link_HandleDiagonalKickback
+0x87cd7b: kDetectTiles_tab0
+0x87cd83: kDetectTiles_tab1
+0x87cd8b: kDetectTiles_tab2
+0x87cd93: kDetectTiles_tab3
+0x87cda3: kDetectTiles_tab4
+0x87cdab: kDetectTiles_tab5
+0x87cdb3: kDetectTiles_tab6
+0x87cdcb: TileDetect_Movement_Y
+0x87ce2a: TileDetect_Movement_X
+0x87ce85: TileDetect_Movement_VerticalSlopes
+0x87cec9: TileDetect_Movement_HorizontalSlopes
+0x87cf0a: TileDetect_BigArea
+0x87cf12: Player_TileDetectNearby
+0x87cf7e: TileDetect_UnusedIce
+0x87cfcc: kDoSwordInteractionWithTiles_y
+0x87d01c: kDoSwordInteractionWithTiles_x
+0x87d06f: kDoSwordInteractionWithTiles_o
+0x87d077: TileDetect_MainHandler
+0x87d2c6: Link_PermissionForSloshSounds
+0x87d2e4: kChangableDungeonObj_Func1B_y0
+0x87d2ec: kChangableDungeonObj_Func1B_y1
+0x87d2f4: kChangableDungeonObj_Func1B_x0
+0x87d2fc: kChangableDungeonObj_Func1B_x1
+0x87d304: PushBlock_AttemptToPushTheBlock
+0x87d365: kGetBestActionToPerformOnTile_y
+0x87d36d: kGetBestActionToPerformOnTile_x
+0x87d375: kGetBestActionToPerformOnTile_a
+0x87d37c: kGetBestActionToPerformOnTile_b
+0x87d383: Link_HandleLiftables
+0x87d445: kLink_Move_Helper6_tab0
+0x87d455: kLink_Move_Helper6_tab1
+0x87d465: kLink_Move_Helper6_tab2
+0x87d475: kLink_Move_Helper6_tab3
+0x87d485: HandleNudging
+0x87d556: kHookShot_CheckColl_Y
+0x87d566: kHookShot_CheckColl_X
+0x87d576: Hookshot_CheckTileCollision
+0x87d607: Hookshot_CheckSingleLayerTileCollision
+0x87d657: kDetectTiles_7_Y
+0x87d65f: kDetectTiles_7_X
+0x87d667: HandleNudgingInADoor
+0x87d6f4: TileCheckForMirrorBonk
+0x87d72e: kDoorwayDetectY
+0x87d736: kDoorwayDetectX
+0x87d73e: TileDetect_SwordSwingDeepInDoor
+0x87d798: TileDetect_ResetState
+0x87d7d8: kTileHandlers_Indoors
+0x87d9d8: TileDetection_Execute
+0x87dc2e: TileDetect_ExecuteInner
+0x87dc4a: TileBehavior_HandleItemAndExecute
+0x87dc50: TileBehavior_StandardCollision
+0x87dc5d: TileBehavior_SlopeOuter
+0x87dc61: TileBehavior_Slope
+0x87dc72: TileBehavior_NorthSingleLayerStairs
+0x87dc7d: TileBehavior_NorthSwapLayerStairs
+0x87dc86: TileHandlerIndoor_22
+0x87dc8b: TileBehavior_Pit
+0x87dc98: TileBehavior_OverlayMask_0C
+0x87dc9e: TileBehavior_GanonIce
+0x87dca4: TileBehavior_PalaceIce
+0x87dcae: TileBehavior_LightableTorch
+0x87dcb6: TileBehavior_DeepWater
+0x87dcbc: TileBehavior_ShortWaterLadder
+0x87dcc2: TileBehavior_OverlayMask_1C
+0x87dcc8: TileBehavior_LayerToggleShutterDoor
+0x87dcd4: TileBehavior_LayerAndDungeonToggleShutterDoor
+0x87dce0: TileBehavior_DungeonToggleShutterDoor
+0x87dcea: TileHandlerIndoor_82
+0x87dd00: TileBehavior_DungeonToggleManualDoor
+0x87dd0a: TileHandlerIndoor_80
+0x87dd1b: TileBehavior_ShallowWater
+0x87dd41: TileBehavior_ManipulablyReplaced
+0x87dd5c: TileBehavior_UnusedDeepWater
+0x87dd6a: TileBehavior_Chest
+0x87dd95: notBigKeyLock
+0x87dd9d: TileBehavior_SouthSingleLayerStairs
+0x87dda1: TileHandlerIndoor_3E
+0x87ddb1: TileBehavior_Spike
+0x87ddca: TileBehavior_SpikeFloor
+0x87dde1: TileBehavior_Hookshottables
+0x87dde5: TileBehavior_FlagManipulable
+0x87ddeb: TileBehavior_FlaggableDoor
+0x87ddf7: TileBehavior_RupeeTile
+0x87de17: TileBehavior_CrystalPeg_Up
+0x87de29: TileBehavior_Conveyor_Upwards
+0x87de2d: TileBehavior_Conveyor_Downwards
+0x87de35: TileBehavior_Conveyor_Leftwards
+0x87de3a: TileBehavior_Conveyor_Rightwards
+0x87de45: TileBehavior_MinigameChest
+0x87de4f: TileBehavior_Entrance
+0x87de5b: TileBehavior_NothingOW
+0x87de61: TileBehavior_ThickGrass
+0x87de67: TileBehavior_DiggableGround
+0x87de7e: TileBehavior_Liftable
+0x87dead: TileBehavior_Ledge_South
+0x87debb: TileBehavior_Ledge_North
+0x87dec5: TileBehavior_Ledge_EastWest
+0x87decf: TileBehavior_Ledge_NorthDiagonal
+0x87dedd: TileBehavior_Ledge_SouthDiagonal
+0x87dee7: TileBehavior_UnusedCornerType
+0x87def1: TileBehavior_EasternRuinsCorner
+0x87deff: TileBehavior_Warp
+0x87df09: TileBehavior_GraveStone
+0x87df11: TileBehavior_HylianPlaque
+0x87df19: TileBehavior_BonkRocks
+0x87e026: PushBlock_GetTargetTileFlag
+0x87e052: kAvoidJudder1
+0x87e072: kAvoidJudder2
+0x87e076: FlagMovingIntoSlopes_Y
+0x87e112: FlagMovingIntoSlopes_X
+0x87e1be: Link_HandleRecoiling
+0x87e1d7: Player_HandleIncapacitated_Inner2
+0x87e227: kPlayer_SomethingWithVelocity_vel
+0x87e245: Link_HandleVelocity
+0x87e370: LinkHop_FindArbitraryLandingSpot
+0x87e373: Player_MovePosition1_
+0x87e3dd: Player_ApplyDragAndComputeVel_
+0x87e3e0: Link_HandleVelocityAndSandDrag
+0x87e402: return_loc_87E402
+0x87e406: kSwimmingTab4
+0x87e41e: kSwimmingTab5
+0x87e422: kSwimmingTab6
+0x87e42a: HandleSwimStrokeAndSubpixels
+0x87e4d3: Player_SomethingWithVelocity_TiredOrSwim
+0x87e545: Link_DashInPlace
+0x87e595: Link_HandleMovingFloor
+0x87e5cd: Link_ApplyMovingFloorVelocity
+0x87e5e4: kMovePosDirFlag
+0x87e5e8: kMovingBeltY
+0x87e5ec: kMovingBeltX
+0x87e5f0: Link_ApplyConveyor
+0x87e671: kPlayer_UpdateDirection_tab
+0x87e675: kPlayer_UpdateDirection_tab2
+0x87e685: kPlayer_UpdateDirection_tab3
+0x87e69d: Link_HandleMovingAnimation_SetFacingDown
+0x87e6a6: Link_HandleMovingAnimation_FullLongEntry
+0x87e6a9: Player_UpdateDirection_
+0x87e704: Link_HandleMovingAnimation_StartWithDash
+0x87e707: Player_UpdateDirection_Part2_
+0x87e7fa: Link_HandleMovingAnimationSwimming
+0x87e842: kDashTab4
+0x87e87a: kDashTab5
+0x87e881: kDashTab3
+0x87e88f: Link_HandleMovingAnimation_Dash
+0x87e8f0: HandleIndoorCameraAndDoors
+0x87e901: HandleDoorTransitions
+0x87e9d3: ApplyLinksMovementToCamera
+0x87ea06: DesertPrayer_InitializeIrisHDMA
+0x87ea22: kPrayingScene_Delays
+0x87ea27: DesertPrayer_BuildIrisHDMATable
+0x87ebda: kPrayingScene_Tab1
+0x87ec5b: kPrayingScene_Tab0
+0x87ecdc: DesertHDMA_CalculateIrisShapeLine
+0x87ed2c: FindFreeMovingBlockSlot
+0x87ed3f: InitializePushBlock
+0x87edb5: PushBlock_Slide
+0x87edf9: PushBlock_HandleFalling
+0x87ee31: kPushedBlockDirMask
+0x87ee35: PushBlock_ApplyVelocity
+0x87ef61: kPushBlockTab1
+0x87ef65: kPushBlockTab2
+0x87ef69: kPushBlock_E
+0x87ef71: kPushBlock_A
+0x87ef79: kPushBlock_B
+0x87ef81: kPushBlock_F
+0x87ef89: kPushBlock_C
+0x87ef91: kPushBlock_D
+0x87ef99: kLinkOtherPosPtrs
+0x87efa1: kLinkOnePosPtrs
+0x87efa9: kPushedBlockOtherPosPtrs
+0x87efb1: kPushedBlockOnePosPtrs
+0x87efb9: PushBlock_HandleCollision
+0x87f0ac: Sprite_Dungeon_DrawAllPushBlocks
+0x87f0cc: kPushedblock_Char
+0x87f0d0: kPushedBlock_Tab1
+0x87f0d9: Sprite_Dungeon_DrawSinglePushBlock
+0x87f13c: Link_Initialize
+0x87f1a3: Link_ResetProperties_A
+0x87f1e6: Link_ResetProperties_B
+0x87f1fa: Link_ResetProperties_C
+0x87f25a: UsedForStraightInterRoomStaircase
+0x87f2c1: HandleLinkOnSpiralStairs
+0x87f391: SpiralStairs_FindLandingSpot
+0x87f3f3: LinkResetPushTimer
+0x87f3fd: UNREACHABLE_07F3D7
+0x87f42f: Player_CheckDoorwayQuadrantMovement_Far
+0x87f439: Link_CheckForEdgeScreenTransition
+0x87f46f: Follower_ValidateMessageFreedom
+0x87f49c: TriforceRoom_LinkApproachTriforce
+0x87f4d0: Sprite_CheckIfLinkIsBusy
+0x87f4f1: Pipe_ValidateEntry
+0x87f514: CacheCameraPropertiesIfOutdoors
+0x87f51d: kOverworld_SignText
+0x87f61d: kDungeon_SignText
+0x888000: Ancilla_Sfx1_Near
+0x888007: Player_DoSfx2_
+0x88800e: Player_DoSfx3_
+0x888015: Player_SetSfxPan_
+0x888020: Ancilla_Sfx1_Pan
+0x888027: Ancilla_Sfx2_Pan
+0x88802e: Ancilla_Sfx3_Pan
+0x888035: Ancilla_Sfx_SetPan
+0x888040: kFireRod_X
+0x888044: kFireRod_XHi
+0x888048: kFireRod_Y
+0x88804c: kFireRod_YHi
+0x888050: kFireRod_Xvel2
+0x88805c: kFireRod_Yvel2
+0x888068: kFireRod_Xvel
+0x88806c: kFireRod_Yvel
+0x88806f: kAncilla_Pflags
+0x8880b3: AncillaAdd_FireRodShot
+0x88819f: kSpawnCentrifugalQuad_X
+0x8881a3: kSpawnCentrifugalQuad_Y
+0x8881a7: SomariaBlock_SpawnBullets
+0x888242: Ancilla_Main
+0x88824d: Ancilla_ProjectReflexiveSpeedOntoSprite
+0x888287: Bomb_CheckSpriteDamage
+0x88832b: Ancilla_ExecuteAll
+0x88833c: Ancilla_ExecuteOne
+0x888405: kIceShotSparkle_X
+0x888415: kIceShotSparkle_Y
+0x888425: kIceShotSparkle_Char
+0x888435: Ancilla13_IceRodSparkle
+0x8884c0: kIceShotSparkle_Yvel
+0x8884c4: kIceShotSparkle_Xvel
+0x8884c8: AncillaAdd_IceRodSparkle
+0x888515: kSomarianBlast_Mask
+0x88851b: Ancilla01_SomariaBullet
+0x888562: kSomarianBlast_Draw_Char0
+0x88857a: kSomarianBlast_Draw_Char1
+0x888592: kSomarianBlast_Draw_Flags0
+0x8885aa: kSomarianBlast_Draw_Flags1
+0x8885c2: kSomarianBlast_Draw_X0
+0x8885da: kSomarianBlast_Draw_X1
+0x8885f2: kSomarianBlast_Draw_Y0
+0x88860a: kSomarianBlast_Draw_Y1
+0x888628: kAncilla_FloorFlags
+0x88862a: Ancilla_ReturnIfOutsideBounds
+0x88864e: kSomarianBlast_Flags
+0x888650: SomarianBlast_Draw
+0x8886d2: Ancilla02_FireRodShot
+0x888759: kFireShot_Draw_X2
+0x888769: kFireShot_Draw_Y2
+0x888779: kFireShot_Draw_Char2
+0x88877c: FireShot_Draw
+0x8887e9: kFireShot_Draw_Char
+0x888853: kAncilla_TileColl0_Attrs
+0x888953: kAncilla_CheckTileColl0_Y
+0x888967: kAncilla_CheckTileColl0_X
+0x88897b: Ancilla_CheckTileCollision_staggered
+0x888981: Ancilla_CheckTileCollision
+0x888a03: Ancilla_CheckTileCollisionOneFloor
+0x888a26: Ancilla_CheckTileCollision_targeted
+0x888ab9: Ancilla_SetSpriteAlert
+0x888abf: kAncilla_TileColl_Attrs
+0x888bbf: kAncilla_CheckTileColl_Y
+0x888bc7: kAncilla_CheckTileColl_X
+0x888bcf: Ancilla_CheckTileCollision_Class2
+0x888c43: Ancilla_CheckTileCollision_Class2_Inner
+0x888cd9: kBeamHit_X
+0x888ce9: kBeamHit_Y
+0x888cf9: kBeamHit_Char
+0x888d09: kBeamHit_Flags
+0x888d19: Ancilla04_BeamHit
+0x888d68: Ancilla_CheckSpriteCollision
+0x888da2: Ancilla_CheckSpriteCollision_
+0x888daa: kAncilla_CheckSpriteColl_Dir
+0x888dae: Ancilla_CheckSpriteCollision_Single
+0x888e75: kAncilla_CheckSpriteColl_RecoilX
+0x888e79: kAncilla_CheckSpriteColl_RecoilY
+0x888e7d: kAncilla_HitBox_X
+0x888e89: kAncilla_HitBox_W
+0x888e95: kAncilla_HitBox_Y
+0x888ea1: kAncilla_HitBox_H
+0x888ead: Ancilla_SetupHitBox
+0x888eed: Ancilla_ProjectSpeedTowardsPlayer
+0x888f5c: Ancilla_IsRightOfLink
+0x888f6f: Ancilla_IsBelowLink
+0x888f82: kRepulseSpark_Char
+0x888f85: kRepulseSpark_Flags
+0x888f89: Ancilla_WeaponTink
+0x889080: Ancilla_MoveX
+0x88908b: Ancilla_MoveY
+0x8890b7: Ancilla_MoveZ
+0x8890dc: kBoomerang_Y0
+0x8890ec: kBoomerang_X0
+0x8890fc: Ancilla05_Boomerang
+0x88923b: Ancilla_CheckTileCollision_
+0x889243: Ancilla_CheckTileCollision_Class2__
+0x88924b: Boomerang_ScreenEdge
+0x8892ab: Boomerang_StopOffScreen
+0x8892f5: Boomerang_Terminate
+0x88931a: kBoomerang_Flags
+0x889322: kBoomerang_Draw_XY
+0x889332: kBoomerang_Draw_OamIdx
+0x889336: kBoomerang_Draw_Tab0
+0x889338: Boomerang_Draw
+0x8893e8: Ancilla06_WallHit
+0x8893ff: Ancilla_SwordWallHit
+0x88941f: kWallHit_Char
+0x88943f: kWallHit_Flags
+0x88945f: kWallHit_Y
+0x88949f: kWallHit_X
+0x8894df: WallHit_Draw
+0x889543: kBomb_Tab0
+0x88954e: kBomb_Draw_Tab0
+0x88955a: Ancilla07_Bomb
+0x8897b6: kAncilla_Belt_Yvel
+0x8897ba: kAncilla_Belt_Xvel
+0x8897be: Ancilla_ApplyConveyor
+0x8897e2: kBomb_Dmg_Speed
+0x8897f2: kBomb_Dmg_Zvel
+0x889802: kBomb_Dmg_Delay
+0x889812: kBomb_Dmg_ToLink
+0x889815: Bomb_CheckSpriteAndPlayerDamage
+0x889913: kAncilla_Func3_Y
+0x88992b: kAncilla_Func3_X
+0x889943: kAncilla_Liftable_Delay
+0x889946: kAncilla_Func2_Y
+0x889952: kAncilla_Liftable_Yvel
+0x889956: kAncilla_Liftable_Xvel
+0x889976: Ancilla_HandleLiftLogic
+0x889a4f: Ancilla_LatchAltitudeAboveLink
+0x889a6a: Ancilla_LatchLinkCoordinates
+0x889a95: Ancilla_Liftable_Func5
+0x889bef: Ancilla_LatchCarriedPosition
+0x889c3e: Ancilla_Liftable_Func6
+0x889c7f: Ancilla_LatchYCoordToZ
+0x889cc3: Ancilla_SetYFrom_DP72
+0x889cce: Bomb_GetDisplacementFromLink
+0x889d10: kBomb_DrawExplosion_CharFlags
+0x889d7c: kBomb_DrawExplosion_XY
+0x889e54: kBomb_DrawExplosion_Ext
+0x889e8a: kBomb_Draw_Mult6
+0x889e93: kBomb_Draw_Tab2
+0x889e9e: Bomb_Draw
+0x889fb6: Ancilla08_DoorDebris
+0x889fd1: kDoorDebris_XY
+0x88a051: kDoorDebris_CharFlags
+0x88a091: DoorDebris_Draw
+0x88a121: kArrow_Y
+0x88a129: kArrow_X
+0x88a131: Ancilla09_Arrow
+0x88a24e: kArrow_Draw_CharFlags
+0x88a2ae: kArrow_Draw_XY
+0x88a36e: Arrow_Draw
+0x88a45b: Ancilla0A_ArrowInTheWall
+0x88a4da: Ancilla_ClearTypeField_
+0x88a4dd: Ancilla0B_IceRodShot
+0x88a536: Ancilla11_IceRodWallHit
+0x88a551: kIceShotSpread_CharFlags
+0x88a561: kIceShotSpread_XY
+0x88a571: IceShotSpread_Draw
+0x88a60e: Ancilla33_BlastWallExplosion
+0x88a752: glb_88A752
+0x88a756: AncillaDraw_BlastWallBlast
+0x88a7ab: AncillaDraw_Explosion
+0x88a80d: kAncilla_JumpSplash_Char
+0x88a80f: Ancilla15_JumpSplash
+0x88a8e3: kAncilla_HitStars_Char
+0x88a8e5: Ancilla16_HitStars
+0x88a997: kShovelDirt_XY
+0x88a9a7: kShovelDirt_Char
+0x88a9a9: Ancilla17_ShovelDirt
+0x88aa32: kBlastWallFireball_Char
+0x88aa35: Ancilla32_BlastWallFireball
+0x88aaa0: Ancilla18_EtherSpell
+0x88ab63: EtherSpell_HandleLightningStroke
+0x88aba7: EtherSpell_HandleOrbPulse
+0x88abef: EtherSpell_HandleRadialSpin
+0x88aceb: kEther_BlitzBall_Char
+0x88aced: AncillaDraw_EtherBlitzBall
+0x88ad49: kEther_SpllittingBlitzSegment_Char
+0x88ad69: kEther_SpllittingBlitzSegment_Flags
+0x88ad89: kEther_SpllittingBlitzSegment_Y
+0x88ada9: kEther_SpllittingBlitzSegment_X
+0x88adc9: AncillaDraw_EtherBlitzSegment
+0x88ae73: kEther_BlitzSegment_Char
+0x88ae77: kEther_BlitzOrb_Char
+0x88ae7f: kEther_BlitzOrb_Flags
+0x88ae87: AncillaDraw_EtherBlitz
+0x88aedd: AncillaDraw_EtherOrb
+0x88af56: kBombos_YDelta
+0x88af5e: kBombos_XDelta
+0x88af66: AncillaAdd_BombosSpell
+0x88b0ce: Ancilla19_BombosSpell
+0x88b10a: BombosSpell_ControlFireColumns
+0x88b236: BombosSpell_FinishFireColumns
+0x88b289: kBombosSpell_FireColumn_Char
+0x88b2b0: kBombosSpell_FireColumn_Flags
+0x88b2d7: kBombosSpell_FireColumn_Y
+0x88b325: kBombosSpell_FireColumn_X
+0x88b373: AncillaDraw_BombosFireColumn
+0x88b40d: BombosSpell_ControlBlasting
+0x88b521: kBombosSpell_DrawBlast_Char
+0x88b541: kBombosSpell_DrawBlast_Flags
+0x88b561: kBombosSpell_DrawBlast_Y
+0x88b5a1: kBombosSpell_DrawBlast_X
+0x88b5e1: AncillaDraw_BombosBlast
+0x88b66a: Ancilla1C_QuakeSpell
+0x88b6f7: QuakeSpell_ShakeScreen
+0x88b713: kQuake_Tab1
+0x88b718: QuakeSpell_ControlBolts
+0x88b78e: kQuakeDrawGroundBolts_Tab
+0x88b793: AncillaDraw_QuakeInitialBolts
+0x88b84f: QuakeSpell_SpreadBolts
+0x88b873: kQuakeDrawGroundBolts_Char
+0x88b8f4: kMagicPowder_Tab0
+0x88b91c: kMagicPower_Mult10
+0x88b920: kMagicPowder_DrawY
+0x88b9b8: kMagicPowder_DrawX
+0x88ba50: kMagicPowder_Draw_Char
+0x88ba64: kMagicPowder_Draw_Flags
+0x88bab0: Ancilla1A_PowderDust
+0x88baeb: Ancilla_MagicPowder_Draw
+0x88bb58: Powder_ApplyDamageToSprites
+0x88bbbc: Ancilla1D_ScreenShake
+0x88bbf4: kDashDust_Draw_Y
+0x88bc30: kDashDust_Draw_X
+0x88bc6c: kDashDust_Draw_Char
+0x88bc8a: kDashDust_Draw_X1
+0x88bc92: Ancilla1E_DashDust
+0x88bd4c: kHookShot_Draw_Char
+0x88bd58: kHookShot_Draw_Flags
+0x88bd64: kHookShot_Move_Y
+0x88bd6c: kHookShot_Move_X
+0x88bd74: Ancilla1F_Hookshot
+0x88c003: kBedSpread_Char
+0x88c00b: kBedSpread_Flags
+0x88c013: Ancilla20_Blanket
+0x88c091: kBedSpread_Dma
+0x88c094: Ancilla21_Snore
+0x88c107: kAncilla_VictorySparkle_Y
+0x88c127: kAncilla_VictorySparkle_X
+0x88c147: kAncilla_VictorySparkle_Char
+0x88c157: kAncilla_VictorySparkle_Flags
+0x88c167: Ancilla3B_SwordUpSparkle
+0x88c1e4: kSwordChargeSpark_Char
+0x88c1e7: kSwordChargeSpark_Flags
+0x88c1ea: Ancilla3C_SpinAttackChargeSparkle
+0x88c22f: kSwordCeremony_Y
+0x88c23f: kSwordCeremony_X
+0x88c24f: kSwordCeremony_Char
+0x88c257: kSwordCeremony_Flags
+0x88c25f: Ancilla35_MasterSwordReceipt
+0x88c38a: Ancilla22_ItemReceipt
+0x88c690: Ancilla_ReceiveItem_Draw
+0x88c6f2: Ancilla28_WishPondItem
+0x88c760: WishPondItem_Draw
+0x88c7de: Ancilla42_HappinessPondRupees
+0x88c819: HapinessPondRupees_ExecuteRupee
+0x88c8be: HapinessPondRupees_GetState
+0x88c924: HapinessPondRupees_SaveState
+0x88c987: kObjectSplash_Draw_Char
+0x88c991: kObjectSplash_Draw_Flags
+0x88c99b: kObjectSplash_Draw_Y
+0x88c9af: kObjectSplash_Draw_X
+0x88c9c3: kObjectSplash_Draw_Ext
+0x88c9cd: Ancilla_TransmuteToSplash
+0x88ca01: Ancilla3D_ItemSplash
+0x88ca22: ObjectSplash_Draw
+0x88ca8c: Ancilla29_MilestoneItemReceipt
+0x88cbe4: ItemReceipt_TransmuteToRisingCrystal
+0x88cbf2: Ancilla_RisingCrystal
+0x88cc93: AncillaAdd_OccasionalSparkle
+0x88cca0: Ancilla43_GanonsTowerCutscene
+0x88ceaa: AncillaDraw_GTCutsceneCrystal
+0x88cec7: GTCutscene_ActivateSparkle
+0x88cf35: GTCutscene_SparkleALot
+0x88cfa6: kFlute_Vels
+0x88cfaa: Ancilla36_Flute
+0x88d03d: Ancilla37_WeathervaneExplosion
+0x88d186: kWeathervane_Explode_Char
+0x88d188: AncillaDraw_WeathervaneExplosionWoodDebris
+0x88d1d4: kTravelBirdIntro_Tab0
+0x88d1d6: kTravelBirdIntro_Tab1
+0x88d1d8: Ancilla38_CutsceneDuck
+0x88d37a: kMorphPoof_Char
+0x88d37d: kMorphPoof_Ext
+0x88d380: kMorphPoof_Flags
+0x88d38c: kMorphPoof_Y
+0x88d3a4: kMorphPoof_X
+0x88d3bc: Ancilla23_LinkPoof
+0x88d3fd: MorphPoof_Draw
+0x88d49a: Ancilla40_DwarfPoof
+0x88d4b9: kBushPoof_Draw_Char
+0x88d4c9: kBushPoof_Draw_Flags
+0x88d4d9: kBushPoof_Draw_Y
+0x88d4f9: kBushPoof_Draw_X
+0x88d519: Ancilla3F_BushPoof
+0x88d596: kSwordSwingSparkle_Char
+0x88d5c6: kSwordSwingSparkle_Flags
+0x88d5f6: kSwordSwingSparkle_Y
+0x88d626: kSwordSwingSparkle_X
+0x88d656: kSwordSwingSparkle_Mult12
+0x88d65a: Ancilla26_SwordSwingSparkle
+0x88d704: kInitialSpinSpark_Timer
+0x88d70a: kInitialSpinSpark_Char
+0x88d726: kInitialSpinSpark_Flags
+0x88d742: kInitialSpinSpark_Y
+0x88d77a: kInitialSpinSpark_X
+0x88d7b2: Ancilla2A_SpinAttackSparkleA
+0x88d84d: kTransmuteSpinSpark_Arr
+0x88d85d: kTransmuteSpinSpark_Y
+0x88d865: kTransmuteSpinSpark_X
+0x88d86d: SpinAttackSparkleA_TransmuteToNextSpark
+0x88d8f6: kSpinSpark_Char
+0x88d8fa: kSpinSpark_Char2
+0x88d8fd: Ancilla2B_SpinAttackSparkleB
+0x88da17: Sparkle_PrepOamFromRadial
+0x88da4c: SpinAttackSparkleB_Closer
+0x88da84: kInitialCaneSpark_Draw_Char
+0x88da94: kInitialCaneSpark_Draw_Flags
+0x88daa4: kInitialCaneSpark_Draw_Y
+0x88dac4: kInitialCaneSpark_Draw_X
+0x88dae4: kInitialCaneSpark_Y
+0x88db04: kInitialCaneSpark_X
+0x88db24: Ancilla30_ByrnaWindupSpark
+0x88dc0e: kCaneSpark_Transmute_Tab
+0x88dc1e: kCaneSpark_Magic
+0x88dc21: ByrnaWindupSpark_TransmuteToNormal
+0x88dc70: Ancilla31_ByrnaSpark
+0x88ddc5: Ancilla_SwordBeam
+0x88ddca: Ancilla0D_SpinAttackFullChargeSpark
+0x88ddd8: kTravelBird_Draw_Char
+0x88dddb: kTravelBird_Draw_Flags
+0x88ddde: kTravelBird_Draw_Y
+0x88dde1: kTravelBird_Draw_X
+0x88dde4: kTravelBird_DmaStuffs
+0x88dde8: Ancilla27_Duck
+0x88e068: kCaneOfSomaria_Y
+0x88e070: kCaneOfSomaria_X
+0x88e078: AncillaAdd_SomariaBlock
+0x88e161: kSomariaTransitLine_Y
+0x88e179: kSomariaTransitLine_X
+0x88e191: SomariaBlock_CheckForTransitTile
+0x88e1f9: Ancilla_CheckBasicSpriteCollision
+0x88e23d: Ancilla_CheckBasicSpriteCollision_Single
+0x88e2ca: Ancilla_SetupBasicHitBox
+0x88e2f9: kSomarianBlock_Draw_Flags
+0x88e305: kSomarianBlock_Draw_Y
+0x88e31d: kSomarianBlock_Draw_X
+0x88e335: kSomarianBlock_Coll_Y
+0x88e34d: kSomarianBlock_Coll_X
+0x88e365: Ancilla2C_SomariaBlock
+0x88e5d8: Ancilla_ClearTypeField
+0x88e61b: AncillaDraw_SomariaBlock
+0x88e74c: kSomarianBlock_CheckCover_Y
+0x88e754: kSomarianBlock_CheckCover_X
+0x88e75c: SomariaBlock_CheckForSwitch
+0x88e7c2: kSomarianBlock_Yvel
+0x88e7d2: kSomarianBlock_Xvel
+0x88e7e2: kSomarianBlock_Zvel
+0x88e7e6: SomariaBlock_HandlePlayerInteraction
+0x88e98e: kSomariaBlockFizzle_Y
+0x88e99a: kSomariaBlockFizzle_X
+0x88e9a6: kSomariaBlockFizzle_Char
+0x88e9ac: kSomariaBlockFizzle_Flags
+0x88e9b2: SomariaBlock_FizzleAway
+0x88e9e8: Ancilla2D_SomariaBlockFizz
+0x88ea7f: kSomarianPlatformPoof_Tab0
+0x88ea83: Ancilla39_SomariaPlatformPoof
+0x88eb3e: Ancilla2E_SomariaBlockFission
+0x88ebe3: kLampFlame_Draw_Char
+0x88ebef: kLampFlame_Draw_Y
+0x88ebfb: kLampFlame_Draw_Xhi
+0x88ec07: kLampFlame_Draw_X
+0x88ec13: Ancilla2F_LampFlame
+0x88ec77: kWaterfallSplash_Char
+0x88ec7f: kWaterfallSplash_Flags
+0x88ec87: kWaterfallSplash_Ext
+0x88ec8f: kWaterfallSplash_Y
+0x88ec97: kWaterfallSplash_Yhi
+0x88ec9f: kWaterfallSplash_X
+0x88eca7: kWaterfallSplash_Xhi
+0x88ecaf: Ancilla41_WaterfallSplash
+0x88ed89: Gravestone_Move
+0x88edf9: kAncilla_Gravestone_Char
+0x88edfd: kAncilla_Gravestone_Flags
+0x88ee01: Ancilla24_Gravestone
+0x88ee57: Gravestone_ActAsBarrier
+0x88eede: kSkullWoodsFire_Draw_Y
+0x88eee2: kSkullWoodsFire_Draw_Yhi
+0x88eee6: kSkullWoodsFire_Draw_Char
+0x88eeea: kSkullWoodsFire_Draw_Ext
+0x88eeee: kSkullWoodsFire_Draw2_Char
+0x88ef06: kSkullWoodsFire_Draw2_Flags
+0x88ef1e: kSkullWoodsFire_Draw2_Ext
+0x88ef36: kSkullWoodsFire_Draw2_Y
+0x88ef66: kSkullWoodsFire_Draw2_X
+0x88ef9a: Ancilla34_SkullWoodsFire
+0x88f169: kSuperBombExplode_Y
+0x88f17b: kSuperBombExplode_X
+0x88f18d: Ancilla3A_BigBombExplosion
+0x88f27c: kAncilla_RevivalFaerie_Tab0
+0x88f27e: kAncilla_RevivalFaerie_Tab1
+0x88f283: RevivalFairy_Main
+0x88f3cf: RevivalFairy_Dust
+0x88f430: RevivalFairy_MonitorHP
+0x88f4ca: Animate_GAMEOVER_Letters
+0x88f4d8: Ancilla_GameOverText
+0x88f4ee: kGameOverText_Tab1
+0x88f4f6: GameOverText_SweepLeft
+0x88f565: kGameOverText_Tab2
+0x88f56d: GameOverText_UnfurlRight
+0x88f5b4: kGameOverText_Chars
+0x88f5c4: GameOverText_Draw
+0x88f624: Ancilla_SetPanRelativeCoordinates
+0x88f631: AncillaAdd_AddAncilla_Bank08
+0x88f65f: UNREACHABLE_08F671
+0x88f66d: kTagalongLayerBits
+0x88f671: Ancilla_PrepOamCoord
+0x88f6a4: Ancilla_PrepAdjustedOamCoord
+0x88f6d9: Ancilla_PrepOamCoord_
+0x88f6e1: Ancilla_SetOam_XY
+0x88f6fe: Ancilla_SetOam_XY_
+0x88f702: Ancilla_SetOam_XY_safe
+0x88f72f: kAncilla_Coll_Yoffs
+0x88f739: kAncilla_Coll_Xoffs
+0x88f743: kAncilla_Coll_H
+0x88f74d: kAncilla_Coll_W
+0x88f757: kAncilla_Coll_LinkYoffs
+0x88f761: kAncilla_Coll_LinkXoffs
+0x88f76b: Ancilla_CheckLinkCollision
+0x88f7dc: Hookshot_CheckProximityToLink
+0x88f824: kEntranceTrigger_BaseY
+0x88f82c: kEntranceTrigger_BaseX
+0x88f834: kEntranceTrigger_SizeY
+0x88f83c: kEntranceTrigger_SizeX
+0x88f844: Ancilla_CheckForEntranceTrigger
+0x88f87b: kAncilla_DrawShadow_Char
+0x88f889: kAncilla_DrawShadow_Flags
+0x88f897: AncillaDraw_Shadow
+0x88f90a: Ancilla_AllocateOamFromRegion_B_or_E
+0x88f91a: Follower_MoveTowardsLink
+0x88f9ba: Ancilla_AllocateOamFromCustomRegion
+0x88fa00: HitStars_UpdateOamBufferPosition
+0x88fa2d: Hookshot_ShouldIEvenBotherWithTiles
+0x88fadd: Ancilla_GetRadialProjection
+0x88fb23: Ancilla_GetRadialProjection_
+0x88fb2b: Ancilla_AllocateOamFromRegion_A_or_D_or_F
+0x88fb44: BeamHit_Unknown
+0x88fba6: BeamHit_GetCoords
+0x88fbc9: BeamHit_GetTopXBit
+0x88fbd6: BeamHit_CheckOffscreen_Y
+0x88feea: kQuake_GroundBoltsPtrs
+0x88ff6a: kQuake_GroundBolts2Ptrs
+0x898000: kShovelHitStars_XY
+0x898018: kShovelHitStars_X2
+0x898024: Ancilla_AddHitStars
+0x898091: AncillaAdd_Blanket
+0x8980c3: Ancilla_SetXY_
+0x8980c8: AncillaAdd_Snoring
+0x8980fd: return
+0x8980ff: kBomb_Place_Y1
+0x898107: kBomb_Place_X1
+0x89810f: kBomb_Place_Y0
+0x898117: kBomb_Place_X0
+0x89811f: AncillaAdd_Bomb
+0x8981b3: kBoomerang_Tab0
+0x8981b7: kBoomerang_Tab1
+0x8981b9: kBoomerang_Tab2
+0x8981bb: kBoomerang_Tab3
+0x8981bf: kBoomerang_Tab4
+0x8981c7: kBoomerang_Tab5
+0x8981cf: kBoomerang_Tab6
+0x8981df: kBoomerang_Tab7
+0x8981ef: kBoomerang_Tab8
+0x8981ff: kBoomerang_Tab9
+0x89820f: AncillaAdd_Boomerang
+0x89836c: kReceiveItem_Tab2
+0x8983b8: kReceiveItem_Tab3
+0x898404: kReceiveItemGfx
+0x898450: kReceiveItem_Tab1
+0x89849c: kWishPond2_OamFlags
+0x8984e8: kMemoryLocationToGiveItemTo
+0x898580: kValueToGiveItemTo
+0x8985e8: AncillaAdd_ItemReceipt
+0x898932: kBottleList
+0x898939: kPotionList
+0x89893e: ItemReceipt_GiveBottledItem
+0x89899a: kWishPondItem_Y
+0x8989e6: kWishPondItem_X
+0x898a32: AncillaAdd_TossedPondItem
+0x898aba: kHappinessPond_Zvel
+0x898ac4: kHappinessPond_Yvel
+0x898ace: kHappinessPond_Xvel
+0x898ad8: kHappinessPond_Start
+0x898adc: kHappinessPond_End
+0x898ae0: AddHappinessPondRupees
+0x898b90: kFallingItem_Type
+0x898b97: kFallingItem_Z
+0x898b9e: kFallingItem_Y
+0x898bac: kFallingItem_X
+0x898bba: kFallingItem_G
+0x898bc1: AncillaAdd_FallingPrize
+0x898c73: AncillaAdd_DugUpFlute
+0x898cb1: AncillaAdd_ChargedSpinAttackSparkle
+0x898cd5: kWeathervane_Tab4
+0x898ce1: kWeathervane_Tab5
+0x898ced: kWeathervane_Tab6
+0x898cf9: kWeathervane_Tab8
+0x898d05: kWeathervane_Tab10
+0x898d11: AncillaAdd_ExplodingWeatherVane
+0x898d90: AncillaAdd_CutsceneDuck
+0x898dd2: AncillaAdd_SomariaPlatformPoof
+0x898df9: AncillaAdd_SuperBombExplosion
+0x898e4e: ConfigureRevivalAncillae
+0x898ee0: AncillaAdd_CaneOfByrnaInitSpark
+0x898f0c: kLampFlame_Y
+0x898f14: kLampFlame_X
+0x898f1c: AncillaAdd_LampFlame
+0x898f5b: AncillaAdd_ShovelDirt
+0x898f7c: AncillaAdd_MSCutscene
+0x898faa: kAddDashingDust_Y
+0x898fb2: kAddDashingDust_X
+0x898fba: AncillaAdd_DashDust
+0x898fc1: AncillaAdd_DashDust_charging
+0x899011: kBlastWall_XY
+0x899031: AncillaAdd_BlastWallFireball
+0x899088: kShootBow_Yvel
+0x89908c: kShootBow_Xvel
+0x899094: kShootBow_Y
+0x89909c: kShootBow_X
+0x8990a4: AncillaAdd_Arrow
+0x899102: AncillaAdd_BunnyPoof
+0x89912c: AncillaAdd_CapePoof
+0x89915f: AncillaAdd_DwarfPoof
+0x8991c3: AncillaAdd_BushPoof
+0x8991fc: AncillaAdd_EtherSpell
+0x8992ac: AncillaAdd_VictorySpin
+0x8992d0: kMagicPower_Y1
+0x8992d8: kMagicPower_X1
+0x8992e0: kMagicPower_Y
+0x8992e8: kMagicPower_X
+0x8992f0: AncillaAdd_MagicPowder
+0x899383: glb_899383
+0x899385: kWallTapSpark_Y
+0x89938d: kWallTapSpark_X
+0x899395: AncillaAdd_WallTapSpark
+0x8993c2: AncillaAdd_SwordSwingSparkle
+0x8993e9: kAddDashTremor_Dir
+0x8993ed: kAddDashTremor_Y
+0x8993f1: kAddDashTremor_Tab
+0x8993f3: AncillaAdd_DashTremor
+0x899448: kBoomerangWallHit_Y
+0x899458: kBoomerangWallHit_X
+0x899468: kBoomerangWallHit_Tab0
+0x899478: AncillaAdd_BoomerangWallClink
+0x8994c6: AncillaAdd_HookshotWallClink
+0x8994fe: AncillaAdd_Duck_take_off
+0x89951d: AddBirdTravelSomething
+0x899589: AncillaAdd_QuakeSpell
+0x8995fb: kSpinAttackStartSparkle_Y
+0x899603: kSpinAttackStartSparkle_X
+0x89960b: AncillaAdd_SpinAttackInitSpark
+0x89965a: kBlastWall_Tab5
+0x89967a: kBlastWall_Tab3
+0x899682: kBlastWall_Tab4
+0x89968a: kBombos_Sfx
+0x899692: AncillaAdd_BlastWall
+0x899757: AncillaAdd_SwordChargeSparkle
+0x8997ce: kSilverArrowSparkle_Y
+0x8997d6: kSilverArrowSparkle_X
+0x8997de: AncillaAdd_SilverArrowSparkle
+0x89984b: kIceRod_Y
+0x899853: kIceRod_X
+0x89985b: kIceRod_Yvel
+0x89985f: kIceRod_Xvel
+0x899863: AncillaAdd_IceRodShot
+0x8998fc: AncillaAdd_Splash
+0x89993a: kMoveGravestone_Y
+0x89994a: kMoveGravestone_X
+0x899968: kMoveGravestone_Y1
+0x899986: kMoveGravestone_X1
+0x8999a4: kMoveGravestone_Pos
+0x8999c2: kMoveGravestone_Ctr
+0x8999e0: kMoveGravestone_Idx
+0x8999e9: AncillaAdd_GraveStone
+0x899af8: kHookshot_Yvel
+0x899afc: kHookshot_Xvel
+0x899b00: kHookshot_Yd
+0x899b08: kHookshot_Xd
+0x899b10: AncillaAdd_Hookshot
+0x899b68: AncillaAdd_WaterfallSplash
+0x899b81: return_loc_899B81
+0x899b83: AncillaAdd_GTCutscene
+0x899c38: AncillaAdd_DoorDebris
+0x899c4f: FireRodShot_BecomeSkullWoodsFire
+0x899ce2: Ancilla_AddAncilla
+0x899d18: AddAncilla_
+0x899d20: AncillaAdd_CheckForPresence
+0x899d2e: Ancilla_CheckIfAlreadyExistsLong
+0x899d36: AncillaAdd_ArrowFindSlot
+0x899da3: kAncilla_Yoffs_Hb
+0x899dbb: kAncilla_Xoffs_Hb
+0x899dd3: Ancilla_CheckInitialTile_A
+0x899e24: kAncilla_InitialTileColl_Y
+0x899e34: kAncilla_InitialTileColl_X
+0x899e44: Ancilla_CheckInitialTileCollision_Class2
+0x899e90: Follower_CheckBlindTrigger
+0x899ef8: kTagalongFlags
+0x899efc: Follower_Initialize
+0x899f39: Sprite_BecomeFollower
+0x899f91: Tagalong_Main_
+0x899f99: kTagalongRoutines
+0x899fb5: kTagalong_Tab0
+0x899fb8: kTagalong_Tab1
+0x899fbe: kTagalong_Msg
+0x899fc4: Follower_Main
+0x89a024: Tagalong_5_14
+0x89a02b: Follower_NoTimedMessage
+0x89a0e1: Follower_CheckGameMode
+0x89a197: Follower_BasicMover
+0x89a2b2: Follower_NotFollowing
+0x89a309: kTagalong_Tab4
+0x89a318: Follower_OldMan
+0x89a410: kTagalong_Tab5
+0x89a41f: Follower_OldManUnused
+0x89a450: Follower_DoLayers
+0x89a48e: Follower_CheckProximityToLink
+0x89a4c8: kTagalong_IndoorRooms
+0x89a4d6: kTagalong_IndoorInfos
+0x89a54e: kTagalong_OutdoorRooms
+0x89a554: kTagalong_OutdoorInfos
+0x89a586: kTagalong_IndoorOffsets
+0x89a596: kTagalong_OutdoorOffsets
+0x89a59e: Follower_HandleTrigger
+0x89a6cd: kTagalongDmaAndFlags
+0x89a6fd: kTagalongDraw_SprXY
+0x89a8bd: kTagalongDraw_Offs
+0x89a8d9: kTagalongDraw_SprInfo0
+0x89a8f1: kTagalongDraw_SprOffs0
+0x89a8f5: kTagalongDraw_SprOffs1
+0x89a8f9: kTagalongDraw_Pals
+0x89a907: Tagalong_Draw
+0x89a957: Tagalong_DrawInner_
+0x89a959: Follower_AnimateMovement_preserved
+0x89abf9: FollowerDraw_CalculateOamCoords
+0x89ac26: Follower_CheckForTrigger
+0x89ac6b: Ancilla_TerminateSelectInteractives
+0x89acf3: Follower_Disable
+0x89ad06: Ancilla_SetXY
+0x89ad1b: Ancilla_GetCoordinates
+0x89ad30: AncillaAdd_ExplodingSomariaBlock
+0x89ad6c: Ancilla_AddRupees
+0x89adc7: Ancilla_TerminateSparkleObjects
+0x89adf1: kMotiveDashDust_Draw_Char
+0x89adf4: DashDust_Motive
+0x89ae40: Sprite_SpawnSuperficialBombBlast
+0x89ae64: Sprite_SetSpawnedCoordinates
+0x89ae7e: Sprite_SpawnDummyDeathAnimation
+0x89aea0: kSpawnMadderBolts_Xvel
+0x89aea4: kSpawnMadderBolts_St2
+0x89aea8: Sprite_MagicBat_SpawnLightning
+0x89af32: Sprite_CheckIfScreenIsClear
+0x89af61: Sprite_CheckIfRoomIsClear
+0x89af76: Sprite_CheckIfOverlordsClear
+0x89af89: Sprite_InitializeMirrorPortal
+0x89afd6: Sprite_InitializeSlots
+0x89b020: Fireball_SpawnTrailGarnish
+0x89b06e: Garnish_ExecuteUpperSlots_
+0x89b07f: Garnish_ExecuteLowerSlots_
+0x89b08c: Garnish_ExecuteUpperSlots
+0x89b097: Garnish_ExecuteLowerSlots
+0x89b0a0: kGarnish_OamMemSize
+0x89b0b6: Garnish_ExecuteSingle
+0x89b150: kArrghusSplash_X
+0x89b158: kArrghusSplash_Y
+0x89b160: kArrghusSplash_Char
+0x89b168: kArrghusSplash_Flags
+0x89b170: kArrghusSplash_Ext
+0x89b178: Garnish15_ArrghusSplash
+0x89b1bd: GarnishSpawn_PyramidDebris
+0x89b216: Garnish13_PyramidDebris
+0x89b252: Garnish_MoveXY
+0x89b284: kGanonBatFlame_Char
+0x89b28b: kGanonBatFlame_Flags
+0x89b292: kGanonBatFlame_Idx
+0x89b2b2: Garnish11_WitheringGanonBatFlame
+0x89b306: Garnish10_GanonBatFlame
+0x89b33f: kTrinexxIce_Char
+0x89b34b: kTrinexxIce_Flags
+0x89b34f: Garnish0C_TrinexxIceBreath
+0x89b3b9: kRunningManDust_Char
+0x89b3bc: Garnish14_KakKidDashDust
+0x89b3c2: Garnish_WaterTrail
+0x89b3e8: kGarnish_CannonPoof_Char
+0x89b3ea: kGarnish_CannonPoof_Flags
+0x89b3ee: Garnish0A_CannonSmoke
+0x89b419: kLightningTrail_Char
+0x89b421: kLightningTrail_Flags
+0x89b429: Garnish09_LightningTrail
+0x89b459: Garnish_CheckPlayerCollision
+0x89b496: kBabusuFlash_Char
+0x89b49a: kBabusuFlash_Flags
+0x89b49e: Garnish07_BabasuFlash
+0x89b4c0: kGarnish_Nebule_XY
+0x89b4c3: kGarnish_Nebule_Char
+0x89b4c6: Garnish08_KholdstareTrail
+0x89b4fb: Garnish06_ZoroTrail
+0x89b51c: kGarnishSparkle_Char
+0x89b520: Garnish12_Sparkle
+0x89b526: Garnish_SimpleSparkle
+0x89b559: kTrinexxLavaBubble_Char
+0x89b55d: Garnish0E_TrinexxFireBreath
+0x89b58d: kBlindLaserTrail_Char
+0x89b591: Garnish0F_BlindLaserTrail
+0x89b5b9: kLaserBeamTrail_Char
+0x89b5bb: Garnish04_LaserTrail
+0x89b5de: Garnish_ReturnIfPrepFails
+0x89b613: kCrumbleTile_Char
+0x89b618: kCrumbleTile_Flags
+0x89b61d: kCrumbleTile_Ext
+0x89b622: kCrumbleTile_XY
+0x89b627: Garnish03_FallingTile
+0x89b6c0: Garnish01_FireSnakeTail
+0x89b6e1: Garnish02_MothulaBeamTrail
+0x89b70c: Garnish_FinalizeBigOamObject
+0x89b714: Overlord_SpawnBoulder
+0x89b773: Overlord_Main
+0x89b77e: Overlord_ExecuteAll
+0x89b793: Overlord_ExecuteSingle
+0x89b7dc: Overlord19_ArmosCoordinator_bounce
+0x89b7e1: kRedStalfosTrap_X
+0x89b7e9: kRedStalfosTrap_Y
+0x89b7f1: kRedStalfosTrap_Delay
+0x89b7f5: Overlord18_InvisibleStalfos
+0x89b884: Overlord17_PotTrap
+0x89b8c1: kOverlordZoroFactory_X
+0x89b8d1: Overlord16_ZoroSpawner
+0x89b972: kOverlordWizzrobe_X
+0x89b97a: kOverlordWizzrobe_Y
+0x89b982: kOverlordWizzrobe_Delay
+0x89b986: Overlord15_WizzrobeSpawner
+0x89b9e8: Overlord14_TileRoom
+0x89ba2a: kSpawnFlyingTile_X
+0x89ba40: kSpawnFlyingTile_Y
+0x89ba56: TileRoom_SpawnTile
+0x89baac: Overlord10_PirogusuSpawner_left
+0x89bac0: kOverlordPirogusu_A
+0x89bac4: PirogusuFactory_Main
+0x89bb24: kCrumbleTilePathData
+0x89bb90: kCrumbleTilePath_X
+0x89bb98: kCrumbleTilePath_Y
+0x89bbb2: Overlord0A_FallingSquare
+0x89bc31: SpawnFallingTile
+0x89bc7b: Overlord09_WallmasterSpawner
+0x89bcc3: Overlord08_BlobSpawner
+0x89bd3f: Overlord07_MovingFloor
+0x89bd8d: kOverlordZol_X
+0x89bd91: kOverlordZol_U
+0x89bd9d: Overlord04_Unused
+0x89bdfd: Sprite_Overlord_PlayFallingSfx
+0x89be07: kStalfosTrap_Trigger
+0x89be0f: Overlord05_FallingStalfos
+0x89be6d: kSnakeTrapOverlord_Tab1
+0x89be75: Overlord06_BadSwitchSnake
+0x89bed9: kAllDirectionMetalBallFactory_Idx
+0x89bee9: kAllDirectionMetalBallFactory_X
+0x89bef9: kAllDirectionMetalBallFactory_Y
+0x89bf09: Overlord02_FullRoomCannons
+0x89bf5b: Overlord03_VerticalCannon
+0x89bfaf: Overlord_SpawnCannonBall
+0x89c016: kOverlordSpawnBall_Xvel
+0x89c01a: kOverlordSpawnBall_Yvel
+0x89c01e: Overlord01_PositionTarget
+0x89c023: kCrazyVillageSoldier_X
+0x89c029: kCrazyVillageSoldier_Y
+0x89c02f: Snitch_SpawnGuard
+0x89c088: kOverlordInRangeOffs
+0x89c08d: Overlord_CheckIfActive
+0x89c114: Dungeon_ResetSprites
+0x89c176: Dungeon_CacheTransSprites
+0x89c22f: Sprite_DisableAll
+0x89c290: Dungeon_LoadSprites
+0x89c2f5: Sprite_ManuallySetDeathFlagUW
+0x89c327: Dungeon_LoadSingleSprite
+0x89c3e8: Dungeon_LoadSingleOverlord
+0x89c44e: Sprite_ResetAll
+0x89c452: Sprite_ResetAll_noDisable
+0x89c499: Sprite_ReloadAll_Overworld
+0x89c49d: Sprite_OverworldReloadAll_justLoad
+0x89c4ac: Overworld_LoadSprites
+0x89c55e: Sprite_ActivateAllProxima
+0x89c58f: Sprite_ProximityActivation
+0x89c5bb: Sprite_ActivateWhenProximal
+0x89c5fa: Sprite_ActivateWhenProximalBig
+0x89c635: kOverworldAreaSprcollSizes
+0x89c6f5: Sprite_Overworld_ProximityMotivatedLoad
+0x89c739: Overworld_LoadProximaSpriteIfAlive
+0x89c770: Overworld_LoadSingleSprite
+0x89c80b: Overworld_LoadSingleOverlord
+0x89c881: kOverworldSprites0
+0x89c901: kOverworldSprites2
+0x89ca21: kOverworldSprites3
+0x89cb41: kNoSprite
+0x89ec9f: kSpriteExplode_Dmd
+0x89ed9f: SpriteModule_Explode_bounce
+0x89eda7: SpriteExplode_Execute
+0x89ee4c: SpriteExplode_SpawnEA
+0x89ef56: Sprite_KillFriends
+0x89ef8b: kScatterDebris_Draw_X
+0x89f00b: kScatterDebris_Draw_Y
+0x89f04b: kScatterDebris_Draw_Char
+0x89f08b: kScatterDebris_Draw_Flags
+0x89f0cb: Garnish16_ThrownItemDebris
+0x89f15c: kScatterDebris_Draw_X2
+0x89f174: kScatterDebris_Draw_Y2
+0x89f180: kScatterDebris_Draw_Char2
+0x89f18c: kScatterDebris_Draw_Flags2
+0x89f198: ScatterDebris_Draw
+0x89f1f8: Sprite_KillSelf
+0x89f270: kModule_Death
+0x89f290: Module12_GameOver
+0x89f2a2: GameOver_AdvanceImmediately
+0x89f2a4: Death_Func1
+0x89f33b: GameOver_DelayBeforeIris
+0x89f350: GameOver_IrisWipe
+0x89f3de: GameOver_SplatAndFade
+0x89f458: Death_Func6
+0x89f47e: Death_Func4
+0x89f483: Animate_GAMEOVER_Letters_bounce
+0x89f488: GameOver_Finalize_GAMEOVR
+0x89f4ac: kHealthAfterDeath
+0x89f4c1: GameOver_SaveAndOrContinue
+0x89f50f: Death_Func15
+0x89f675: kDeath_SprChar0
+0x89f677: kDeath_SprY0
+0x89f67a: GameOver_AnimateChoiceFairy
+0x89f6a4: GameOver_InitializeRevivalFairy
+0x89f6b4: RevivalFairy_Main_bounce
+0x89f6b9: GameOver_RiseALittle
+0x89f71d: GameOver_Restore0D
+0x89f735: GameOver_Restore0E
+0x89f742: GameOver_ResituateLink
+0x89f79f: Module17_SaveAndQuit
+0x89f7af: Quit_IndicateHaltedState
+0x89f7de: Polyhedral_InitializeThread
+0x89f810: kPolyThreadInit
+0x89f81d: Polyhedral_RunThread
+0x89f83d: Polyhedral_SetShapePointer
+0x89f864: Polyhedral_SetRotationMatrix
+0x89f8fb: Polyhedral_OperateRotation
+0x89f931: Polyhedral_RotatePoint
+0x89f9d6: Polyhedral_ProjectPoint
+0x89fa4f: Polyhedral_DrawPolyhedron
+0x89faca: Polyhedral_SetForegroundColor
+0x89fad7: Poly_SetColor_ModeB
+0x89fb24: Polyhedral_CalculateCrossProduct
+0x89fb6d: kPolySinCos
+0x89fcae: Polyhedral_SetColorMask
+0x89fcc4: kPoly_RasterColors
+0x89fd04: Polyhedral_EmptyBitMapBuffer
+0x89fd1e: Polyhedral_DrawFace
+0x89fdcf: Polyhedral_FillLine
+0x89fe94: kPoly_LeftSideMask
+0x89fea4: kPoly_RightSideMask
+0x89feb4: Polyhedral_SetLeft
+0x89ff1e: Polyhedral_SetRight
+0x89ff8c: kPolyTable
+0x89ff98: kPoly0_Vtx
+0x89ffaa: kPoly0_Polys
+0x89ffd2: kPoly1_Vtx
+0x89ffe4: kPoly1_Polys
+0x8a8047: room_85_objects
+0x8ab730: Module0E_0A_FluteMenu
+0x8ab74b: FluteMenu_LoadMap
+0x8ab753: FluteMenu_AdvanceMode
+0x8ab75b: kBirdTravel_tab1
+0x8ab763: kBirdTravel_x_lo
+0x8ab76b: kBirdTravel_x_hi
+0x8ab773: kBirdTravel_y_lo
+0x8ab77b: kBirdTravel_y_hi
+0x8ab78b: FluteMenu_HandleSelection
+0x8ab8c5: FluteMenu_LoadSelectedScreen
+0x8ab948: Overworld_LoadOverlayAndMap
+0x8ab964: FluteMenu_FadeInAndQuack
+0x8ab96c: BirdTravel_Finish_Doit
+0x8ab98b: Messaging_OverworldMap
+0x8ab9a3: WorldMap_FadeOut
+0x8aba30: WorldMap_LoadLightWorldMap
+0x8aba7a: WorldMap_LoadDarkWorldMap
+0x8aba9a: WorldMap_LoadSpriteGFX
+0x8abaaa: WorldMap_Brighten
+0x8abac4: kOverworldMap_Timer
+0x8abac6: kOverworldMap_Table3
+0x8abad6: kOverworldMap_Table2
+0x8abae2: kOverworldMap_TableLow
+0x8abae6: WorldMap_PlayerControl
+0x8abbd6: WorldMap_RestoreGraphics
+0x8abc33: Attract_SetUpConclusionHDMA
+0x8abc54: WorldMap_ExitMap
+0x8abc96: WorldMap_SetUpHDMA
+0x8abda5: WorldMap_FillTilemapWithEF
+0x8abdcf: kMapModeHdma0
+0x8abdd6: kMapModeHdma1
+0x8abddd: kAttractIndirectHdmaTab
+0x8abde4: kOwMapCrystal0_x
+0x8abdf6: kOwMapCrystal0_y
+0x8abe08: kOwMapCrystal1_x
+0x8abe1a: kOwMapCrystal1_y
+0x8abe2c: kOwMapCrystal2_x
+0x8abe3e: kOwMapCrystal2_y
+0x8abe50: kOwMapCrystal3_x
+0x8abe62: kOwMapCrystal3_y
+0x8abe74: kOwMapCrystal4_x
+0x8abe86: kOwMapCrystal4_y
+0x8abe98: kOwMapCrystal5_x
+0x8abeaa: kOwMapCrystal5_y
+0x8abebc: kOwMapCrystal6_x
+0x8abece: kOwMapCrystal6_y
+0x8abee0: kOwMapCrystal0_tab
+0x8abef2: kOwMapCrystal1_tab
+0x8abf04: kOwMapCrystal2_tab
+0x8abf16: kOwMapCrystal3_tab
+0x8abf28: kOwMapCrystal4_tab
+0x8abf3a: kOwMapCrystal5_tab
+0x8abf4c: kOwMapCrystal6_tab
+0x8abf5e: kOwMap_tab2
+0x8abf62: kOverworldMap_Table4
+0x8abf66: WorldMap_HandleSprites
+0x8ac39f: WorldMap_CalculateOamCoordinates
+0x8ac50d: return_true_loc_8AC50D
+0x8ac515: kOverworldMapData
+0x8ac51c: WorldMap_HandleSpriteBlink
+0x8ac56d: WorldMap_MultiplyAxB
+0x8ac580: WorldMap_ShiftNibblesRight
+0x8ac589: WorldMapIcon_AdjustCoordinate
+0x8ac5a6: kPendantBitMask
+0x8ac5a9: OverworldMap_CheckForPendant
+0x8ac5bf: kCrystalBitMask
+0x8ac5c6: OverworldMap_CheckForCrystal
+0x8ac5da: kOverworldMap_tab1
+0x8ac727: kLightOverworldTilemap
+0x8ad727: kDarkOverworldTilemap
+0x8adb27: kOverworldMapPaletteData
+0x8add27: kMapMode_Zooms1
+0x8adee7: kMapMode_Zooms2
+0x8ae0b0: Module0E_03_DungeonMap
+0x8ae0d2: PalaceMap_InitJumpTable
+0x8ae0dc: Module0E_03_01_DrawMap
+0x8ae0e4: Module0E_03_01_00_PrepMapGraphics
+0x8ae15a: kDungMap_Tab3
+0x8ae168: kDungMap_Tab4
+0x8ae176: kDungMap_Tab1
+0x8ae186: kDungMap_Tab2
+0x8ae196: kDungMap_Tab0
+0x8ae1a4: Module0E_03_01_01_DrawLEVEL
+0x8ae1e1: kDungMap_Tab7
+0x8ae1f3: Module0E_03_01_02_DrawFloorsBackdrop
+0x8ae2e5: kDungMap_Tab9
+0x8ae2f5: DungeonMap_BuildFloorListBoxes
+0x8ae384: Module0E_03_01_03_DrawRooms
+0x8ae429: kDungMap_Tab11
+0x8ae431: kDungMap_Tab10
+0x8ae439: kDungMap_Tab13
+0x8ae43d: kDungMap_Tab12
+0x8ae441: kDungMap_Tab15
+0x8ae445: kDungMap_Tab14
+0x8ae449: DungeonMap_DrawBorderForRooms
+0x8ae4e9: kDungMap_Tab16
+0x8ae4f9: DungeonMap_DrawFloorNumbersByRoom
+0x8ae56f: kDungMap_Tab17
+0x8ae579: DungeonMap_DrawDungeonLayout
+0x8ae59a: kMult_5
+0x8ae5bc: DungeonMap_DrawSingleRowOfRooms
+0x8ae7f3: kDungMap_Tab24
+0x8ae7f9: kDungMap_Tab21
+0x8ae7ff: kDungMap_Tab22
+0x8ae807: kDungMap_Tab25
+0x8ae823: DungeonMap_DrawRoomMarkers
+0x8ae954: DungeonMap_HandleInputAndSprites
+0x8ae95b: DungeonMap_HandleInput
+0x8ae975: kDungMap_Tab26
+0x8ae979: DungeonMap_HandleMovementInput
+0x8ae986: DungeonMap_HandleFloorSelect
+0x8aea77: kDungMap_Tab40
+0x8aea7b: kDungMap_Tab39
+0x8aea7f: DungeonMap_ScrollFloors
+0x8aeaaf: ret
+0x8aeab2: DungeonMap_DrawSprites
+0x8aeaf0: DungeonMap_DrawLinkPointing
+0x8aeb48: kDungMap_Tab38
+0x8aeb50: DungeonMap_DrawBlinkingIndicator
+0x8aeb8a: kDungMap_Tab29
+0x8aeb8e: kDungMap_Tab30
+0x8aeb92: kDungMap_Tab31
+0x8aeb96: kDungMap_Tab32
+0x8aeba8: DungeonMap_DrawLocationMarker
+0x8aec0a: DungeonMap_DrawFloorNumberObjects
+0x8aecbe: kDungMap_Tab33
+0x8aecc6: kDungMap_Tab34
+0x8aeccf: DungeonMap_DrawFloorBlinker
+0x8aed4e: kDungMap_Tab35
+0x8aed50: kDungMap_Tab36
+0x8aede4: DungeonMap_DrawBossIcon
+0x8aee5d: kDungMap_Tab37
+0x8aee79: kDungMap_Tab28
+0x8aee95: DungeonMap_DrawBossIconByFloor
+0x8aeef6: Module0E_03_04_UnusedCrazyScroll
+0x8aef19: DungeonMap_RecoverGFX
+0x8aefc9: ToggleStarTilesAndAdvance
+0x8aefd1: kDungMap_Tab8
+0x8aefdf: kDungMap_Tab6
+0x8af009: kDungMap_Tab23
+0x8af5d9: kDungMap_Tab5
+0x8af5f5: kDungMap_Mult25
+0x8af605: kDungMap_Ptrs19
+0x8af621: kDungMap_Size75
+0x8af66c: kDungMap_Size125
+0x8af6e9: kDungMap_Size50
+0x8af71b: kDungMap_Size75_0
+0x8af766: kDungMap_Size175
+0x8af815: kDungMap_Size75_1
+0x8af860: kDungMap_Size50_0
+0x8af892: kDungMap_Size75_2
+0x8af8dd: kDungMap_Size50_1
+0x8af90f: kDungMap_Size200
+0x8af9d7: kDungMap_Size150
+0x8afa6d: kDungMap_Size75_3
+0x8afab8: kDungMap_Size100
+0x8afb1c: kDungMap_Size200_0
+0x8afbe4: kDungMap_Ptrs27
+0x8afce0: kDungFloorIndicator_Gfx0
+0x8afcf6: kDungFloorIndicator_Gfx1
+0x8afd0c: Hud_FloorIndicator
+0x8afd90: Hud_RemoveSuperBombIndicator
+0x8afda8: Hud_SuperBombIndicator
+0x8afe20: Death_InitializeGameOverLetters
+0x8afe80: Dungeon_HandleLayerEffect
+0x8afe87: LayerEffect_Nothing
+0x8afe88: LayerEffect_Scroll
+0x8afeee: LayerEffect_Trinexx
+0x8aff0d: LayerEffect_Agahnim2
+0x8aff5d: LayerEffect_InvisibleFloor
+0x8affa4: LayerEffect_Ganon
+0x8affde: LayerEffect_WaterRapids
+0x8bfe70: Overworld_SetFixedColAndScroll
+0x8bffa8: WallMaster_SendPlayerToLastEntrance
+0x8bffbf: ResetSomeThingsAfterDeath
+0x8bffee: ResetAncillaAndLink
+0x8cc120: Module00_Intro
+0x8cc15d: Intro_Init
+0x8cc170: Intro_Init_Continue
+0x8cc1a0: Intro_Clear1kbBlocksOfWRAM
+0x8cc1f5: Intro_InitializeMemory_darken
+0x8cc25c: IntroZeldaFadein
+0x8cc284: Intro_FadeInBg
+0x8cc2ae: Intro_SwordComingDown
+0x8cc2d4: Intro_WaitPlayer
+0x8cc2f0: FadeMusicAndResetSRAMMirror
+0x8cc33c: Intro_InitializeTriforcePolyThread
+0x8cc36f: Intro_InitGfx_Helper
+0x8cc3bd: LoadTriforceSpritePalette
+0x8cc404: Intro_HandleAllTriforceAnimations
+0x8cc412: Scene_AnimateEverySprite
+0x8cc425: kPolyhedralPalette
+0x8cc435: Intro_AnimateTriforce
+0x8cc448: Intro_RunStep
+0x8cc534: Intro_AnimOneObj
+0x8cc572: kIntroSprite0_X
+0x8cc578: kIntroSprite0_Y
+0x8cc57e: Intro_SpriteType_A_0
+0x8cc5b1: Intro_SpriteType_B_0
+0x8cc5ca: kIntroSprite0_Xvel
+0x8cc5cd: kIntroSprite0_Yvel
+0x8cc5d0: kIntroSprite0_XLimit
+0x8cc5d3: kIntroSprite0_YLimit
+0x8cc60f: kIntroSprite0_Left_Ents
+0x8cc68f: kIntroSprite0_Right_Ents
+0x8cc70f: AnimateSceneSprite_DrawTriangle
+0x8cc72f: kIntroTriforceOam_Left
+0x8cc7af: kIntroTriforceOam_Right
+0x8cc82f: Intro_CopySpriteType4ToOam
+0x8cc84f: EXIT_0CCA90
+0x8cc850: InitializeSceneSprite_Copyright
+0x8cc864: AnimateSceneSprite_Copyright
+0x8cc868: kIntroSprite2_Ents
+0x8cc8d0: CopyIntroSpritesToOam_Sprite2_NintendoCopy
+0x8cc8e2: InitializeSceneSprite_Sparkle
+0x8cc8fd: kIntroSprite3_X
+0x8cc901: kIntroSprite3_Y
+0x8cc905: kIntroSprite3_State
+0x8cc90d: AnimateSceneSprite_Sparkle
+0x8cc936: kIntroSprite3_Ents
+0x8cc956: AnimateSceneSprite_DrawSparkle
+0x8cc972: AnimateSceneSprite_AddObjectsToOamBuffer
+0x8cc9f1: AnimateSceneSprite_MoveTriangle
+0x8cca4c: Intro_MaybeDoubleRet
+0x8cca54: TriforceRoom_PrepGFXSlotForPoly
+0x8cca81: Credits_InitializePolyhedral
+0x8ccab1: AdvancePolyhedral
+0x8ccabc: TriforceRoom_HandlePoly
+0x8ccad8: TriforceRoom_HandlePoly_Switch
+0x8ccae9: IntroPolyhedral_StartUp
+0x8ccafe: TriforceRoom_HandlePoly_Case1
+0x8ccb1f: IntroPolyhedral_MoveRotate
+0x8ccb84: IntroPolyhedral_LockIntoPlace
+0x8ccba1: TriforceRoom_HandlePoly_Case4
+0x8ccba2: Credits_AnimateTheTriangles
+0x8ccbb0: CreditsTriangle_HandleRotation
+0x8ccbc3: CreditsTriangle_ApplyRotation
+0x8ccbd6: kIntroTriforce_X
+0x8ccbdc: kIntroTriforce_Y
+0x8ccbe2: kIntroTriforce_Xvel
+0x8ccbe5: kIntroTriforce_Yvel
+0x8ccbe8: InitializeSceneSprite_TriforceRoomTriangle
+0x8ccc13: Intro_SpriteType_B_456
+0x8ccc2d: kTriforce_Xacc
+0x8ccc30: kTriforce_Yacc
+0x8ccc5d: kTriforce_MinusOnes
+0x8ccc60: kTriforce_Ones
+0x8ccc65: kTriforce_Xfinal
+0x8ccc68: kTriforce_Yfinal
+0x8ccc8c: kTriforce_Yfinal2
+0x8cccb0: AnimateTriforceRoomTriangle_HandleContracting
+0x8ccd0d: kIntroSprite7_X
+0x8ccd13: kIntroSprite7_Y
+0x8ccd19: InitializeSceneSprite_CreditsTriangle
+0x8ccd38: kIntroSprite7_XAcc
+0x8ccd3b: kIntroSprite7_YAcc
+0x8ccd3e: AnimateSceneSprite_CreditsTriangle
+0x8ccd7d: Module01_FileSelect
+0x8ccd9d: Module_SelectFile_0
+0x8ccdf2: FileSelect_ReInitSaveFlagsAndEraseTriforce
+0x8ccdf9: FileSelect_EraseTriforce
+0x8cce53: Module_EraseFile_1
+0x8ccea5: FileSelect_TriggerStripesAndAdvance
+0x8cceb1: FileSelect_TriggerNameStripesAndAdvance
+0x8ccebd: FileSelect_Main
+0x8ccec7: FileSelect_SetUpNamesStripes
+0x8ccfbb: CopySaveToWRAM
+0x8cd053: Module02_CopyFile
+0x8cd06e: Module_CopyFile_2
+0x8cd087: CopyFile_ChooseSelection
+0x8cd0a2: CopyFile_ChooseTarget
+0x8cd0b9: CopyFile_ConfirmSelection
+0x8cd0c6: FilePicker_DeleteHeaderStripe
+0x8cd13f: CopyFile_SelectionAndBlinker
+0x8cd22d: ReturnToFileSelect
+0x8cd27b: CopyFile_TargetSelectionAndBlink
+0x8cd371: CopyFile_HandleConfirmation
+0x8cd3dc: CopyFile_CopyData
+0x8cd485: Module03_KILLFile
+0x8cd49a: KILLFile_SetUp
+0x8cd49f: KILLFile_HandleSelection
+0x8cd4b1: KILLFile_HandleConfirmation
+0x8cd4ba: KILLFile_ChooseTarget
+0x8cd7a5: FileSelect_DrawFairy
+0x8cd88a: Module04_NameFile
+0x8cd89c: NameFile_EraseSave
+0x8cda4d: NameFile_DoTheNaming
+0x8cdc8c: NameFile_CheckForScrollInputX
+0x8cdcbf: NameFile_CheckForScrollInputY
+0x8cdd30: NameFile_DrawSelectedCharacter
+0x8cdd6d: intro_zelda_bg_etc
+0x8ced7a: kIntroLogo_X
+0x8ced7e: kIntroLogo_Tile
+0x8ced82: Intro_DisplayLogo
+0x8cedad: Module14_Attract
+0x8cede6: Attract_Fade
+0x8cee0c: Attract_InitGraphics
+0x8ceea6: Attract_FadeInStep
+0x8ceeba: Attract_FadeInSequence
+0x8ceecb: Attract_FadeOutSequence
+0x8ceee2: IncrementAttractModeIndex
+0x8ceee5: Attract_LoadNewScene
+0x8ceef8: AttractScene_PolkaDots
+0x8ceeff: AttractScene_WorldMap
+0x8cef4e: AttractScene_ThroneRoom
+0x8cefc0: Attract_PrepFinish
+0x8cefe3: Attract_PrepZeldaPrison
+0x8cf058: Attract_PrepMaidenWarp
+0x8cf0dc: AttractScene_EndOfStory
+0x8cf0e2: Death_Func31
+0x8cf115: Attract_EnactStory
+0x8cf126: AttractDramatize_PolkaDots
+0x8cf176: AttractDramatize_WorldMap
+0x8cf1c8: Attract_ThroneRoom
+0x8cf27a: AttractDramatize_Prison
+0x8cf324: Dramaghanim_AdvanceStory
+0x8cf423: AttractDramatize_AgahnimAltar
+0x8cf700: Attract_SkipToFileSelect
+0x8cf72e: Attract_LegendGraphics_pointers
+0x8cf736: Attract_LegendGraphics_sizes
+0x8cf73e: Attract_BuildNextImageTileMap
+0x8cf766: Attract_ShowTimedTextMessage
+0x8cf783: Attract_ControlMapZoom
+0x8cf7e6: Attract_BuildBackgrounds
+0x8cf879: Attract_TriggerBGDMA
+0x8cf9b5: Attract_DrawPreloadedSprite
+0x8cf9e8: Attract_DrawZelda
+0x8cfa30: Attract_DrawKidnappedMaiden
+0x8cfa87: kAttractDmaTable0
+0x8cfa94: kAttractDmaTable1
+0x8cfaa3: Attract_SetUpWindowingHDMA
+0x8cfac2: kAttract_Legendgraphics_0
+0x8cfb5f: kAttract_Legendgraphics_1
+0x8cfc4c: kAttract_Legendgraphics_2
+0x8cfd13: kAttract_Legendgraphics_3
+0x8cfe1c: kIntroSword_Char
+0x8cfe26: kIntroSword_X
+0x8cfe30: kIntroSword_Y
+0x8cfe45: Intro_SetupSwordAndIntroFlash
+0x8cfe56: Intro_PeriodicSwordAndIntroFlash
+0x8cff05: kSwordSparkle_Tab
+0x8cff0c: kSwordSparkle_Char
+0x8cff49: kIntroSwordSparkle_Char
+0x8d8000: link_sprite_bodys
+0x8d838c: kPlayerOam_Prio
+0x8d839b: kSwordTiledata
+0x8d8563: kShieldStuff_OamData
+0x8d85cf: kLinkShadows_Chardata
+0x8d85fb: kLinkDmaGraphicsIndices
+0x8d89f9: kPlayerOam_Spr1Bank
+0x8d8a75: kPlayerOam_Spr2Bank
+0x8d8af1: kPlayerOam_Main_SwordStuff_array1
+0x8d8cf0: kPlayerOam_ShieldStuff_array1
+0x8d8eef: kDrawSword_y
+0x8d90ee: kDrawSword_x
+0x8d92ed: kPlayerOam_Spr1Y
+0x8d9369: kPlayerOam_Spr1X
+0x8d93e5: kPlayerOam_Spr2Y
+0x8d9461: kPlayerOam_Spr2X
+0x8d94dd: kShieldStuff_y
+0x8d96dc: kShieldStuff_x
+0x8d98db: kOffsToShadowGivenDir_Y
+0x8d98e7: kOffsToShadowGivenDir_X
+0x8d98f3: kSwordOamYOffs
+0x8d9af2: kSwordOamXOffs
+0x8d9cf1: kPlayerOamSpriteLocs
+0x8d9ef0: kPlayerOamOtherOffs
+0x8da030: kMultBy80
+0x8da038: kPlayerOam_Tab6
+0x8da070: kMultBy14
+0x8da078: kPlayerOam_Tab19A
+0x8da084: kPlayerOam_Tab20A
+0x8da090: kSwordStuff_oam_index_ptrs_0
+0x8da09c: kLinkBody_oam_index_0
+0x8da0a8: kShieldStuff_oam_index_ptrs_0
+0x8da0b4: kShadow_oam_indexes_0
+0x8da0c0: kPlayerOam_Tab19B
+0x8da0cc: kPlayerOam_Tab20B
+0x8da0d8: kSwordStuff_oam_index_ptrs_1
+0x8da0e4: kLinkBody_oam_index_1
+0x8da0f0: kShieldStuff_oam_index_ptrs_1
+0x8da0fc: kShadow_oam_indexes_1
+0x8da108: kPlayerOam_Ptr19
+0x8da10c: kPlayerOam_Ptr20
+0x8da110: kSwordStuff_oam_index_ptrs
+0x8da114: kPlayerOam_Ptrs15
+0x8da118: kShieldStuff_oam_index_ptrs
+0x8da11c: kPlayerOam_Ptrs16
+0x8da120: kPlayerOam_SortSpritesOffs
+0x8da126: kPlayerOam_FloorOamPrio
+0x8da12e: kPlayerOam_Rod
+0x8da131: kPlayerOam_Tab1
+0x8da13a: kPlayerOam_Tab2
+0x8da142: kPlayerOam_Tab3
+0x8da148: kPlayerOam_Tab4
+0x8da150: kPlayerOam_Tab5
+0x8da15e: kPlayerOam_StairsOffsY
+0x8da18e: LinkOam_Main
+0x8daac3: FindMostSignificantBit
+0x8daacc: kPlayerOam_Main_SwordStuff_array3
+0x8dab18: kPlayerOam_Main_SwordStuff_array4
+0x8dab22: kPlayerOam_Main_SwordStuff_array2
+0x8dab6e: LinkOam_SetWeaponVRAMOffsets
+0x8dabca: kPlayerOam_ShieldStuff_array2
+0x8dabdc: kPlayerOam_ShieldStuff_array3
+0x8dabe6: LinkOam_SetEquipmentVRAMOffsets
+0x8dac45: kSwordTipSomething
+0x8dac8d: kSwordOamYOffs_Good
+0x8dacb1: kSwordOamXOffs_Good
+0x8dacd5: LinkOam_CalculateSwordSparklePosition
+0x8dad82: kPlayerOam_DrawOam_Throwing_Tiles
+0x8dad84: kPlayerOam_DrawOam_Throwing_State
+0x8dad94: kPlayerOam_DrawOam_Throwing_X
+0x8dada4: kPlayerOam_DrawOam_Throwing_Y
+0x8dadb6: LinkOam_UnusedWeaponSettings
+0x8dae38: kPlayerOam_DrawOam_2X
+0x8dae3b: LinkOam_DrawDungeonFallShadow
+0x8daeca: kNoGrassAnimArr
+0x8daecd: kShieldTypeToOffs
+0x8daed1: LinkOam_DrawFootObject
+0x8dafa6: UNREACHABLE_0DAFA6
+0x8dafc0: LinkOam_CalculateXOffsetRelativeLink
+0x8db080: kSpriteInit_Flags2
+0x8db173: kSpriteInit_Health
+0x8db266: kSpriteInit_BumpDamage
+0x8db359: kSpriteInit_Flags3
+0x8db44c: kSpriteInit_Flags4
+0x8db53f: kSpriteInit_Flags
+0x8db632: kSpriteInit_Flags5
+0x8db725: kSpriteInit_DeflBits
+0x8db818: SpritePrep_LoadProperties
+0x8db85c: SpritePrep_LoadPalette
+0x8db871: SpritePrep_ResetProperties
+0x8db8f1: kEnemyDamages
+0x8db971: kSprite_SimplifiedTileAttr
+0x8dba71: GetRandomNumber
+0x8dba80: Oam_AllocateFromRegionA
+0x8dba84: Oam_AllocateFromRegionB
+0x8dba88: Oam_AllocateFromRegionC
+0x8dba8c: Oam_AllocateFromRegionD
+0x8dba90: Oam_AllocateFromRegionE
+0x8dba94: Oam_AllocateFromRegionF
+0x8dba9e: kOamGetBufferPos_Tab0
+0x8dbaaa: kOamGetBufferPos_Tab1
+0x8dbb0a: Oam_GetBufferPosition
+0x8dbb5b: kPanTable
+0x8dbb5e: Ancilla_CalculateSfxPan
+0x8dbb67: Link_CalculateSfxPan
+0x8dbb6e: SpriteSfx_QueueSfx1WithPan
+0x8dbb7c: SpriteSfx_QueueSfx2WithPan
+0x8dbb8a: SpriteSfx_QueueSfx3WithPan
+0x8dbb98: SpriteSfx_ApplyPanning
+0x8dbba1: Sprite_CalculateSfxPan
+0x8dbba8: CalculateSfxPan
+0x8dbbd0: CalculateSfxPan_Arbitrary
+0x8dbbe0: kBabusu_Dmd
+0x8dbd20: Babusu_Draw
+0x8dbd46: kWizzrobe_Dmd
+0x8dbe06: Wizzrobe_Draw
+0x8dbe28: kWizzbeam_Dmd
+0x8dbe68: Wizzbeam_Draw
+0x8dbe86: kFreezor_Dmd0
+0x8dbf66: kFreezor_Dmd1
+0x8dbfa6: Freezor_Draw
+0x8dbfd6: kZazak_Dmd
+0x8dc096: kZazak_Char
+0x8dc09e: kZazak_Flags
+0x8dc0a6: Zazak_Draw
+0x8dc0f3: kStalfos_Dmd
+0x8dc213: kStalfos_Char
+0x8dc217: SpriteDontDraw_Stalfos
+0x8dc21c: Stalfos_Draw
+0x8dc26a: kStalfos_Flags
+0x8dc26e: Probe_CheckTileSolidity
+0x8dc2d1: Sprite_29_Adult
+0x8dc2d9: Sprite_HumanMulti_1
+0x8dc2e6: Sprite_BlindsHutGuy
+0x8dc308: Sprite_ThiefHideoutGuy
+0x8dc343: Sprite_FluteDad
+0x8dc3b1: kFluteBoyFather_Dmd
+0x8dc3e1: FluteBoyFather_Draw
+0x8dc401: kBlindHideoutGuy_Dmd
+0x8dc481: BlindHideoutGuy_Draw
+0x8dc4a5: Sprite_2A_SweepingLady
+0x8dc4ad: Sprite_SweepingLady
+0x8dc4cb: kSweepingLadyDmd
+0x8dc4eb: SweepingLady_Draw
+0x8dc50b: Sprite_2C_Lumberjacks
+0x8dc513: kLumberJackMsg
+0x8dc51b: Sprite_Lumberjacks
+0x8dc57f: kLumberJacks_X
+0x8dc583: kLumberJacks_Y
+0x8dc587: kLumberJacks_W
+0x8dc58b: kLumberJacks_H
+0x8dc58f: Lumberjack_CheckProximity
+0x8dc5b2: kLumberJacks_Dmd
+0x8dc6ba: Lumberjacks_Draw
+0x8dc6de: Sprite_2D_TelepathicTile
+0x8dc6e6: Sprite_UnusedTelepath
+0x8dc737: UnusedTelepath_Draw
+0x8dc75a: Sprite_31_FortuneTeller
+0x8dc762: Sprite_FortuneTeller
+0x8dc76d: Sprite_SmithyBlockade
+0x8dc783: FortuneTeller
+0x8dc79a: FortuneTeller_LightWorld
+0x8dc7b1: kFortuneTeller_Prices
+0x8dc7b9: FortuneTeller_LightWorld_PrecognizantResponse
+0x8dc7de: LW_FortuneTeller_NotEnoughRupees
+0x8dc7e7: FortuneTeller_LightWorld_OfferReading
+0x8dc7ff: LW_FortuneTeller_ReactToPlayerResponse
+0x8dc829: kFortuneTeller_Readings
+0x8dc849: FortuneTeller_PerformPseudoScience
+0x8dc953: FortuneTeller_PrepareNextMessage
+0x8dc960: FortuneTeller_LightWorld_DemandPayment
+0x8dc976: FortuneTeller_LightWorld_TakeMoney
+0x8dc996: FortuneTeller_DarkWorld
+0x8dc9ad: FortuneTeller_DarkWorld_PrecognizantResponse
+0x8dc9d2: DW_FortuneTeller_NotEnoughRupees
+0x8dc9db: FortuneTeller_DarkWorld_OfferReading
+0x8dc9f3: DW_FortuneTeller_ReactToPlayerResponse
+0x8dca1d: FortuneTeller_DarkWorld_DemandPayment
+0x8dca2d: FortuneTeller_DemandPayment
+0x8dca81: FortuneTeller_DarkWorld_TakeMoney
+0x8dcaa1: kFortuneTeller_Dmd
+0x8dcb01: FortuneTeller_Draw
+0x8dcb2a: Smithy_SpawnDumbBarrierSprite
+0x8dcb54: Sprite_2F_RaceGameLady
+0x8dcb5c: Sprite_MazeGameLady
+0x8dcb7e: RaceGameLady_Idle
+0x8dcbba: RaceGameLady_TimeRun
+0x8dcbe0: RaceGameLady_FireStarterPistol
+0x8dcbea: Sprite_30_RaceGameGuy
+0x8dcbf2: Sprite_MazeGameGuy
+0x8dcc2d: RaceGameGuy_VerifyRun
+0x8dcca7: RaceGameGuy_MakeModDecision
+0x8dccf4: RaceGameGuy_RejectRun
+0x8dcd05: RaceGameGuy_IdleInDiscord
+0x8dcd16: MazeGameGuy_NothingMoreToGive
+0x8dcd27: kMazeGameGuy_Dmd
+0x8dcda7: MazeGameGuy_Draw
+0x8dcdcf: kCrystalMaiden_SpriteData
+0x8dce4f: kCrystalMaiden_Dma
+0x8dce5f: CrystalMaiden_Draw
+0x8dce91: kPriest_Dmd
+0x8dcf31: Priest_Draw
+0x8dcf59: kFluteBoy_Dmd
+0x8dcfd9: FluteBoy_Draw
+0x8dd000: kFluteAardvark_Dmd
+0x8dd040: FluteAardvark_Draw
+0x8dd060: kDustCloud_Dmd
+0x8dd120: DustCloud_Draw
+0x8dd142: kMedallionTablet_Dmd
+0x8dd1e2: MedallionTablet_Draw
+0x8dd203: kUncleDraw_Table
+0x8dd383: kUncleDraw_Dma3
+0x8dd38a: kUncleDraw_Dma4
+0x8dd391: Uncle_Draw
+0x8dd3eb: kBugNetKid_Dmd
+0x8dd47b: BugNetKid_Draw
+0x8dd49f: Sprite_ReturnIfInactive_8D
+0x8dd4bc: kBomber_Dmd
+0x8dd56c: Bomber_Draw
+0x8dd58e: kBomberPellet_Dmd
+0x8dd606: SpriteDraw_ZirroBomb
+0x8dd631: PlayerBee_HoneInOnTarget
+0x8dd6a6: kPikit_Dmd
+0x8dd6e6: Pikit_Draw
+0x8dd73a: kPikit_Draw_Char
+0x8dd742: kPikit_Draw_Flags
+0x8dd74a: SpriteDraw_Pikit_Tongue
+0x8dd80f: kPikit_TongueMult
+0x8dd813: Three_NOP
+0x8dd817: kPikit_DrawGrabbedItem_X
+0x8dd82b: kPikit_DrawGrabbedItem_Y
+0x8dd83f: kPikit_DrawGrabbedItem_Char
+0x8dd853: kPikit_DrawGrabbedItem_Flags
+0x8dd858: SpriteDraw_Pikit_Loot
+0x8dd8af: kKholdstare_Dmd
+0x8dd92f: kKholdstare_Draw_X
+0x8dd94f: kKholdstare_Draw_Y
+0x8dd96f: kKholdstare_Draw_Char
+0x8dd97f: kKholdstare_Draw_Flags
+0x8dd98f: Kholdstare_Draw
+0x8dda06: Sprite_SpawnFireball
+0x8dda79: kArcheryGameGuy_Draw_X
+0x8dda88: kArcheryGameGuy_Draw_Y
+0x8dda97: kArcheryGameGuy_Draw_Char
+0x8ddaa6: kArcheryGameGuy_Draw_Flags
+0x8ddab5: kArcheryGameGuy_Draw_Ext
+0x8ddac4: ArcheryGameGuy_Draw
+0x8ddb40: kMaxBombsForLevelHex
+0x8ddb48: kMaxBombsForLevel
+0x8ddb50: kMaxArrowsForLevelHex
+0x8ddb58: kMaxArrowsForLevel
+0x8ddb60: kMaxHealthForLevel
+0x8ddb75: Hud_RefillLogic_Far
+0x8ddb7f: Hud_RefreshIcon__
+0x8ddb92: Hud_RefillLogic
+0x8ddd2a: Hud_Module_Run_Far
+0x8ddd32: Hud_UpdateEquippedItemFar
+0x8ddd36: Hud_Module_Run
+0x8ddd5a: Hud_ClearTileMap
+0x8dddab: Hud_Init
+0x8dde59: Hud_BringMenuDown
+0x8dde6e: Hud_ChooseNextMode
+0x8ddeb0: Hud_DoWeHaveThisItem
+0x8ddebd: Hud_GoToPrevItem
+0x8ddecb: Hud_GoToNextItem
+0x8dded9: Hud_EquipPrevItem
+0x8ddee2: Hud_EquipNextItem
+0x8ddeeb: Hud_EquipItemAbove
+0x8ddf00: Hud_EquipItemBelow
+0x8ddf15: Hud_NormalMenu
+0x8ddfa9: Hud_UpdateHud
+0x8ddfaf: Hud_UpdateEquippedItem
+0x8ddfba: Hud_CloseMenu
+0x8ddffb: Hud_GotoBottleMenu
+0x8de002: Hud_InitBottleMenu
+0x8de050: kBottleMenuTop
+0x8de064: kBottleMenuTop2
+0x8de078: kBottleMenuBottom
+0x8de08c: Hud_ExpandBottleMenu
+0x8de0df: Hud_BottleMenu
+0x8de17f: Hud_UpdateBottleMenu
+0x8de2fd: Hud_EraseBottleMenu
+0x8de346: Hud_RestoreNormalMenu
+0x8de372: Hud_DrawItem
+0x8de395: Hud_SearchForEquippedItem_Far
+0x8de399: Hud_SearchForEquippedItem
+0x8de3c8: Hud_GetPaletteMask
+0x8de3d9: Hud_DrawYButtonItems
+0x8de647: Hud_DrawUnknownBox
+0x8de6b6: Hud_DrawAbilityText
+0x8de7b7: Hud_DrawAbilityIcons
+0x8de81a: Hud_DrawGlovesText
+0x8de860: kProgressIconPendants
+0x8de914: kProgressIconCrystals
+0x8de9c8: Hud_DrawProgressIcons
+0x8de9d3: Hud_DrawProgressIcons_Pendants
+0x8dea62: Hud_DrawProgressIcons_Crystals
+0x8deb3a: Hud_DrawSelectedYButtonItem
+0x8dece9: Hud_DrawMoonPearl
+0x8ded04: Hud_Nop
+0x8ded09: kHudEquipmentDungeonItemText
+0x8ded29: Hud_DrawEquipment
+0x8dee21: Hud_DrawShield
+0x8dee3c: Hud_DrawArmor
+0x8dee57: Hud_DrawMapAndBigKey
+0x8deeb6: ItemMenu_CheckForDungeonPrize
+0x8deedc: CheckPalaceItemPossession_00
+0x8deee1: CheckPalaceItemPossession_02
+0x8deeee: CheckPalaceItemPossession_03
+0x8deef4: CheckPalaceItemPossession_05
+0x8deefa: CheckPalaceItemPossession_06
+0x8def00: CheckPalaceItemPossession_07
+0x8def06: CheckPalaceItemPossession_08
+0x8def0c: CheckPalaceItemPossession_09
+0x8def12: CheckPalaceItemPossession_10
+0x8def18: CheckPalaceItemPossession_11
+0x8def1f: CheckPalaceItemPossession_12
+0x8def2c: CheckPalaceItemPossession_13
+0x8def39: Hud_DrawCompass
+0x8def67: Hud_DrawBottleMenu
+0x8df0f7: Hud_IntToDecimal
+0x8df128: Hud_RefillHealth
+0x8df14f: Hud_AnimateHeartRefill
+0x8df1b3: Hud_RefillMagicPower
+0x8df1c9: kHudItemText
+0x8df449: kHudBottlesItemText
+0x8df549: kHudMushroomItemText
+0x8df569: kHudFluteItemText
+0x8df5a9: kHudMirrorItemText
+0x8df5c9: kHudBowItemText
+0x8df629: kHudItemBow
+0x8df651: kHudItemBoomerang
+0x8df669: kHudItemHookshot
+0x8df679: kHudItemBombs
+0x8df689: kHudItemMushroom
+0x8df6a1: kHudItemFireRod
+0x8df6b1: kHudItemIceRod
+0x8df6c1: kHudItemBombos
+0x8df6d1: kHudItemEther
+0x8df6e1: kHudItemQuake
+0x8df6f1: kHudItemTorch
+0x8df701: kHudItemHammer
+0x8df711: kHudItemFlute
+0x8df731: kHudItemBugNet
+0x8df741: kHudItemBookMudora
+0x8df751: kHudItemBottles
+0x8df799: kHudItemCaneSomaria
+0x8df7a9: kHudItemCaneByrna
+0x8df7b9: kHudItemCape
+0x8df7c9: kHudItemMirror
+0x8df7e9: kHudItemGloves
+0x8df801: kHudItemBoots
+0x8df811: kHudItemFlippers
+0x8df821: kHudItemMoonPearl
+0x8df839: kHudItemSword
+0x8df861: kHudItemShield
+0x8df881: kHudItemArmor
+0x8df899: kHudItemDungeonCompass
+0x8df8a9: kHudItemPalaceItem
+0x8df8c1: kHudItemDungeonMap
+0x8df8d1: kHudPendants0
+0x8df8e1: kHudPendants1
+0x8df8f1: kHudPendants2
+0x8df911: kHudItemHeartPieces
+0x8df931: kHudGlovesText
+0x8df959: kHudAbilityText
+0x8df9fd: kHudItemBoxTab1
+0x8dfa03: kHudItemBoxTab2
+0x8dfa09: kAnimHeartPartial
+0x8dfa15: kItemToHudItem
+0x8dfa33: Hud_RestoreTorchBackground
+0x8dfa58: Hud_RebuildFar
+0x8dfa60: Hud_RebuildIndoor
+0x8dfa68: HUD_RebuildIndoor_palace
+0x8dfa6c: Hud_Rebuild_
+0x8dfa70: Hud_Rebuild
+0x8dfa85: Hud_UpdateOnly
+0x8dfa93: kHudItemBoxGfxPtrs
+0x8dfad5: kHudItemInVramPtr
+0x8dfafd: Hud_UpdateItemBox
+0x8dfb91: Hud_UpdateInternal
+0x8dfb94: Hud_Update_IgnoreItemBox
+0x8dfc09: Hud_Update_IgnoreHealth
+0x8dfcfa: Hud_SeemsUnused
+0x8dfdab: Hud_UpdateHearts
+0x8dfdd9: Hud_UpdateHearts_DrawHeart
+0x8dfdef: kUpdateMagicPowerTilemap
+0x8dfe77: kHudTilemap
+0x8dffc1: new_random_gen
+0x8dffd8: DoorAnim_DoWork2_Preserving
+0x8e8000: kTextBits
+0x8e9000: kDungAttrsForTile_Offs
+0x8e902a: kDungAttrsForTile
+0x8e942a: Dungeon_LoadCustomTileAttr
+0x8e9459: kMap8DataToTileAttr
+0x8e9659: kDungeon_DefaultAttr
+0x8e97d9: Init_LoadDefaultTileAttr
+0x8e986e: Module1A_Credits
+0x8e9889: Credits_LoadNextScene_Overworld
+0x8e9891: Credits_LoadNextScene_Dungeon
+0x8e98b9: Credits_PrepAndLoadSprites
+0x8e98d8: kEnding1_TargetScrollY
+0x8e98f8: kEnding1_TargetScrollX
+0x8e9918: kEnding1_Yvel
+0x8e9938: kEnding1_Xvel
+0x8e9958: Credits_ScrollScene_Overworld
+0x8e99c5: Credits_ScrollScene_Dungeon
+0x8e9a0a: kEnding1_3_Tab0
+0x8e9a2a: Credits_HandleSceneFade
+0x8e9bca: kEndingSprites_Ptrs0
+0x8e9bea: kEndingSprites_Ptrs1
+0x8e9c0a: kEndingSprites_Num
+0x8e9c1a: Credits_LoadSprites_Zora
+0x8e9c27: Ending_InitSprites_2
+0x8e9c2f: Ending_InitSprites_3
+0x8e9c56: kInitSprite9_Delay
+0x8e9c5b: Ending_InitSprites_9
+0x8e9c92: Ending_InitSprites_14
+0x8e9cb4: Ending_InitSprites_15
+0x8e9cca: Ending_InitSprites_7
+0x8e9cd1: Ending_InitSprites_12
+0x8e9cfe: Ending_InitSprites_0
+0x8e9d5c: Credits_LoadSprites_Venus
+0x8e9d70: Ending_InitSprites_11
+0x8e9d84: Ending_InitSprites_1
+0x8e9df0: kEndSequence_Dmd15
+0x8e9e20: kEndSequence_Dmd16
+0x8e9e38: kEndSequence_Dmd17
+0x8e9e48: kEndSequence_Dmd11
+0x8e9e78: kEndSequence_Case0_Tab1
+0x8e9e84: kEndSequence_Case0_Tab0
+0x8e9e90: kEndSequence_Case0_OamFlags
+0x8e9e9c: Credits_SpriteDraw_Castle
+0x8e9ee1: kEndSequence_Dmd24
+0x8e9f01: kEndSequence_Dmd25
+0x8e9f21: kEndSequence_Dmd30
+0x8e9f29: kEnding_Case4_Tab1
+0x8e9f2b: kEnding_Case4_Tab0
+0x8e9f2d: kEnding_Case4_Ctr
+0x8e9f31: kEnding_Case4_XYvel
+0x8e9f3b: kEnding_Case4_DelayVel
+0x8e9f53: Credits_SpriteDraw_Hera
+0x8e9fc0: kEndSequence_Dmd20
+0x8e9ff0: kEndSequence_Dmd21
+0x8ea020: kEndSequence_Dmd19
+0x8ea060: kEndSequence_Dmd22
+0x8ea090: kEndSequence_Dmd23
+0x8ea0c0: kEndSequence_Dmd18
+0x8ea0d0: kEnding_Case2_Delay
+0x8ea0d2: kEnding_Case2_Tab2
+0x8ea0d7: kEnding_Case2_Tab3
+0x8ea0de: kEnding_Case2_Tab0
+0x8ea0e0: kEnding_Case2_Tab1
+0x8ea0e2: Credits_SpriteDraw_Kakariko1
+0x8ea164: kEndSequence_Dmd4
+0x8ea194: kEndSequence_Dmd7
+0x8ea1a4: kEndSequence_Dmd5
+0x8ea1f4: kEndSequence_Dmd13
+0x8ea274: kEnding_Case5_Tab0
+0x8ea276: kEnding_Case5_Tab1
+0x8ea27a: kEnding_Case5_Tab2
+0x8ea27c: Credits_SpriteDraw_House
+0x8ea2f8: kEndSequence_Dmd26
+0x8ea358: Credits_SpriteDraw_DeathMountain
+0x8ea393: Credits_SpriteDraw_Lumberjacks
+0x8ea3c7: Credits_SpriteDraw_Venus
+0x8ea42d: kEndSequence_Dmd0
+0x8ea48d: kEndSequence_Dmd1
+0x8ea4bd: kEndSequence_Dmd2
+0x8ea53d: kEnding_Case12_Tab
+0x8ea540: kEnding_Case12_Z
+0x8ea54f: Credits_SpriteDraw_Kakariko2
+0x8ea5f8: Credits_SpriteDraw_DrawShadow
+0x8ea5fd: EndSequence_DrawShadow2
+0x8ea60d: kEnding_Func2_Delay
+0x8ea627: kEnding_Func2_Tab0
+0x8ea643: Credits_SpriteDraw_AnimateRunningKidAndLocksmith
+0x8ea645: Ending_Func2
+0x8ea692: Credits_SpriteDraw_ActivateAndRunSprite_allocate8
+0x8ea694: Credits_SpriteDraw_ActivateAndRunSprite
+0x8ea6b1: Credits_SpriteDraw_PreexistingSpriteDraw_eight
+0x8ea6b3: Credits_SpriteDraw_PreexistingSpriteDraw
+0x8ea703: Credits_SpriteDraw_Single
+0x8ea73d: kEnding_Case6_SprType
+0x8ea740: kEnding_Case6_OamSize
+0x8ea743: kEnding_Case6_State
+0x8ea746: kEnding_Case6_Gfx
+0x8ea74c: Credits_SpriteDraw_Zora
+0x8ea79a: kEndSequence_Dmd3
+0x8ea7fa: kEndSequence_Dmd31
+0x8ea802: Credits_SpriteDraw_Smithy
+0x8ea888: kEndSequence_Dmd27
+0x8ea8b8: kEnding_Case11_Gfx
+0x8ea8c8: Credits_SpriteDraw_DrawSmithSpark
+0x8ea8e5: kEndSequence_Dmd28
+0x8ea925: kEndSequence_Dmd29
+0x8ea93d: kEnding_Case3_Gfx
+0x8ea941: Credits_SpriteDraw_Desert
+0x8ea995: kEndSequence_Dmd6
+0x8ea9ad: Credits_SpriteDraw_Sanctuary
+0x8ea9d1: kEnding_Case7_Gfx
+0x8ea9d3: Credits_SpriteDraw_Witch
+0x8eaa53: kEndSequence_Dmd9
+0x8eaa73: kEndSequence_Dmd8
+0x8eaa7b: kEnding_Case8_Xvel
+0x8eaa7d: kEnding_Case8_Delay1
+0x8eaa81: kEnding_Case8_Delay2
+0x8eaa86: kEnding_Case8_D
+0x8eaa91: Credits_SpriteDraw_Grove
+0x8eab45: kEndSequence_Dmd12
+0x8eabed: kEnding_Case14_Tab1
+0x8eabf0: kEnding_Case14_Tab0
+0x8eabf5: Credits_SpriteDraw_LostWoods
+0x8eaca2: Credits_SpriteDraw_SetShadowProp
+0x8eacab: kEndSequence_Dmd10
+0x8eaccb: kEnding_Case15_OamFlags
+0x8eaccf: kEnding_Case15_Delay
+0x8eacd7: kEnding_Func3_Delay
+0x8eacdd: kEnding_Case15_X
+0x8eace1: kEnding_Case15_Y
+0x8eace5: Credits_SpriteDraw_AddSparkle
+0x8ead22: Credits_SpriteDraw_Pedestal
+0x8eadb7: kEndSequence_Dmd14_xx
+0x8eadbf: kEndSequence_Dmd14
+0x8eade7: kEnding_Func6_Dma
+0x8eadf7: Credits_SpriteDraw_WalkLinkAwayFromPedestal
+0x8eae2d: kEnding_Func5_Xvel
+0x8eae31: kEnding_Func5_Yvel
+0x8eae35: Credits_SpriteDraw_MoveSquirrel
+0x8eae5f: kEnding_MoveSprite_Func1_TargetX
+0x8eae61: kEnding_MoveSprite_Func1_TargetY
+0x8eae63: Credits_SpriteDraw_CirclingBirds
+0x8eaea6: Credits_HandleCameraScrollControl
+0x8eaff2: Credits_SingleCameraScrollControl
+0x8eb038: kEnding_MapData
+0x8eb178: kEnding_Credits_Text
+0x8eb93d: kEnding_Credits_Offs
+0x8ebc51: kEnding_Digits_ScrollY
+0x8ebc6d: EndSequence_32
+0x8ebd53: kHdmaTableForEnding
+0x8ebd66: Credits_FadeOutFixedCol
+0x8ebd8b: Credits_FadeColorAndBeginAnimating
+0x8ebe04: kEnding_Credits_DigitChar
+0x8ebe08: kEnding_Func9_Tab2
+0x8ebe24: Credits_AddNextAttribution
+0x8ebf4c: kEnding0_Data
+0x8ec2e1: kEnding0_Offs
+0x8ec303: Credits_AddEndingSequenceText
+0x8ec37c: Credits_BrightenTriangles
+0x8ec391: Credits_StopCreditsScroll
+0x8ec3b8: Credits_FadeAndDisperseTriangles
+0x8ec3d5: Credits_FadeInTheEnd
+0x8ec3ea: kEndSequence37_Oams
+0x8ec3fa: EndSequence_38_0
+0x8ec41a: Credits_HangForever
+0x8ec440: RenderText
+0x8ec448: Messaging_Text_Near
+0x8ec455: RenderText_PostDeathSaveOptions
+0x8ec483: Text_Initialize
+0x8ec493: Text_Initialize_initModuleStateLoop
+0x8ec4c9: Text_InitVwfState
+0x8ec4e2: Text_LoadCharacterBuffer
+0x8ec547: RenderText_ExtendedCommand
+0x8ec581: RenderText_ExtendedCommand_IgnoreCommand
+0x8ec598: RenderText_ExtendedCommand_IgnoreParameter
+0x8ec5b3: Text_WritePlayerName
+0x8ec639: Text_FilterPlayerNameCharacters
+0x8ec657: RenderText_ExtendedCommand_SetWindowType
+0x8ec667: Text_WritePreloadedNumber
+0x8ec69c: RenderText_ExtendedCommand_SetWindowPosition
+0x8ec6b6: Text_SetColor
+0x8ec6da: Text_DictionarySequence
+0x8ec703: Text_DictionaryPointers
+0x8ec8d9: Text_Render
+0x8ec8ea: RenderText_Draw_Border
+0x8ec919: RenderText_Draw_BorderIncremental
+0x8ec936: RenderText_Draw_BorderIncremental_Top
+0x8ec94a: RenderText_Draw_BorderIncremental_Middle
+0x8ec961: RenderText_Draw_BorderIncremental_Bottom
+0x8ec97d: RenderText_Draw_CharacterTilemap
+0x8ec984: RenderText_Draw_MessageCharacters
+0x8ec9fd: RenderText_Draw_HandleNext
+0x8eca35: RenderText_Draw_Finish
+0x8eca6c: RenderText_Draw_RenderCharacter
+0x8eca99: RenderText_Draw_RenderCharacter_All
+0x8ecab8: VWF_RenderSingle
+0x8ecadf: kVWF_RenderCharacter_widths
+0x8ecb42: kVWF_RenderCharacter_setMasks
+0x8ecb4a: kVWF_RenderCharacter_renderPos
+0x8ecb50: kVWF_RenderCharacter_linePositions
+0x8ecb56: kVWF_RenderCharacter_unsetMasks
+0x8ecb5e: VWF_RenderCharacter
+0x8eccf9: RenderText_Draw_RenderCharacter_ReduceSpeed
+0x8eccfe: RenderText_Draw_NextImage
+0x8ecd16: VWF_Select2Or3_Indented_messages
+0x8ecd1a: RenderText_Draw_Choose2LowOr3
+0x8ecd88: RenderText_Draw_ChooseItem
+0x8ecdc8: RenderText_FindYItem_Previous
+0x8ecded: RenderText_FindYItem_Next
+0x8ece14: RenderText_DrawSelectedYItem
+0x8ece6b: RenderText_Draw_Ignore
+0x8ece7f: VWF_Select2Or3_messages
+0x8ece83: RenderText_Draw_Choose2HiOr3
+0x8ecef1: VWF_Crash
+0x8ecef7: RenderText_Draw_Choose3
+0x8ecf6e: VWF_Choose1Or2_messages
+0x8ecf72: RenderText_Draw_Choose1Or2
+0x8ecfe2: RenderText_Draw_Scroll
+0x8ed0c3: kVWF_RowPositions
+0x8ed0c9: VWF_SetLine
+0x8ed0f2: RenderText_Draw_SetColor
+0x8ed115: RenderText_Draw_Wait
+0x8ed138: RenderText_Draw_Wait_Init
+0x8ed14c: VWF_WaitLoop_decCounter
+0x8ed154: RenderText_Draw_Wait_End
+0x8ed162: RenderText_Draw_PlaySfx
+0x8ed176: RenderText_Draw_SetSpeed
+0x8ed18d: RenderText_Draw_Command7B
+0x8ed1bd: RenderText_Draw_ABunchOfSpaces
+0x8ed1f9: RenderText_Draw_EmptyBuffer
+0x8ed230: RenderText_Draw_PauseForInput
+0x8ed25b: RenderText_Draw_Terminate
+0x8ed280: RenderText_SetDefaultWindowPosition
+0x8ed29c: RenderText_DrawBorderInitialize
+0x8ed2ab: RenderText_DrawBorderRow
+0x8ed2ec: Text_BuildCharacterTilemap
+0x8ed307: RenderText_Refresh
+0x8ed35a: kText_InitializationData
+0x8ed37f: kText_BorderTiles
+0x8ed391: kText_Positions
+0x8ed399: kVWF_LinePositions
+0x8ed39f: kVWF_Command7C
+0x8ed3a7: kVWF_Command7B
+0x8ed3af: kText_WaitDurations
+0x8ed3cf: Text_UnusedData
+0x8ed3d2: kText_CommandLengths
+0x8ed3eb: Text_GenerateMessagePointers
+0x8ed460: kDungPalinfos
+0x8ed504: kOwBgPalInfo
+0x8ed580: kOwSprPalInfo
+0x8ed5a8: Overworld_LoadPalettes
+0x8ed5f4: Palette_BgAndFixedColor_Black
+0x8ed5f9: Palette_SetBgAndFixedColor
+0x8ed60b: SetBackdropcolorBlack
+0x8ed618: Palette_SetOwBgColor
+0x8ed61d: Palette_SpecialOw
+0x8ed622: Palette_GetOwBgColor
+0x8ed653: Palette_AssertTranslucencySwap_ForcePlayerToBg1
+0x8ed657: Palette_AssertTranslucencySwap
+0x8ed65c: Palette_SetTranslucencySwap
+0x8ed6b9: Palette_RevertTranslucencySwap_ForcePlayerBg2
+0x8ed6bb: Palette_RevertTranslucencySwap
+0x8ed6c0: LoadActualGearPalettes
+0x8ed6d1: Palette_ElectroThemedGear
+0x8ed6dd: LoadGearPalettes_bunny
+0x8ed6e8: LoadGearPalettes
+0x8ed741: LoadGearPalette
+0x8ed757: Filter_Majorly_Whiten_Bg
+0x8ed7fe: Filter_Majorly_Whiten_Color
+0x8ed83a: Palette_Restore_BG_From_Flash
+0x8ed8ae: Palette_Restore_Coldata
+0x8ed8fb: Palette_Restore_BG_And_HUD
+0x8ed940: DungMap_LightenUpMap
+0x8ed94c: DungMap_Backup
+0x8eda37: DungMap_FadeMapToBlack
+0x8eda79: DungMap_RestoreOld
+0x8edd40: Overworld_Memorize_Map16_Change
+0x8edd61: kLwTurtleRockPegPositions
+0x8edd67: HandlePegPuzzles
+0x8eddfc: GanonTowerEntrance_Func1
+0x8ede29: kSpecialSwitchArea_Map8
+0x8ede31: kSpecialSwitchArea_Screen
+0x8ede39: kSpecialSwitchArea_Direction
+0x8ede41: kSpecialSwitchArea_Exit
+0x8ede49: Overworld_CheckSpecialSwitchArea
+0x8ede9a: Overworld_GetMap16OfLink_Mult8
+0x8edece: kSpecialSwitchAreaB_Map8
+0x8eded4: kSpecialSwitchAreaB_Screen
+0x8ededa: kSpecialSwitchAreaB_Direction
+0x8edee0: WeirdAssPlaceForAnExit
+0x8edee3: Overworld_Func0_Main_SpecialOverworldInner
+0x8ef400: Palette_AnimGetMasterSword
+0x8ef404: Palette_AnimGetMasterSword2
+0x8ef48c: Palette_AnimGetMasterSword3
+0x8ef4eb: kDwPaletteAnim
+0x8ef531: kDwPaletteAnim2
+0x8ef582: Overworld_DwDeathMountainPaletteAnimation
+0x8ef652: Overworld_LoadEventOverlay
+0x8ef664: Overworld_EventOverlayFuncs
+0x8f8000: map8_data
+0x8ff540: Sprite_NullifyHookshotDrag
+0x8ff577: Ancilla_AllocInit
+0x8ff5c3: kDeath_AnimCtr0
+0x8ff5d2: kDeath_AnimCtr1
+0x8ff5e1: kDeath_SprFlags
+0x8ff5e3: Death_PlayerSwoon
+0x8ff64d: return_loc_8FF64D
+0x8ff64f: kSwordBeam_Tab
+0x8ff65f: kSwordBeam_Yvel
+0x8ff663: kSwordBeam_Xvel
+0x8ff667: kSwordBeam_S
+0x8ff66b: kSwordBeam_Y
+0x8ff66f: kSwordBeam_YHi
+0x8ff673: kSwordBeam_X
+0x8ff677: kSwordBeam_Xhi
+0x8ff67b: AddSwordBeam
+0x8ff74d: kSwordBeam_Char
+0x8ff751: kSwordBeam_Char2
+0x8ff754: kSwordBeam_Yvel2
+0x8ff758: kSwordBeam_Yvel2Hi
+0x8ff75c: kSwordBeam_Xvel2
+0x8ff760: kSwordBeam_Xvel2Hi
+0x8ff764: Ancilla_SwordBeam_
+0x8ff8eb: kSwordFullChargeSpark_Y
+0x8ff8f3: kSwordFullChargeSpark_X
+0x8ff8fb: kSwordFullChargeSpark_Flags
+0x8ff8ff: Ancilla_SwordFullChargeSpark_
+0x8ff961: kSwordChargeSparkle_Y
+0x8ff969: kSwordChargeSparkle_X
+0x8ff971: kSwordChargeSparkle_A
+0x8ff975: kSwordChargeSparkle_B
+0x8ff979: AncillaSpawn_SwordChargeSparkle
+0x8ffa37: Ancilla_MoveX_
+0x8ffa43: Ancilla_MoveY_
+0x8ffa6f: Death_PrepFaint
+0x8ffaea: ShopKeeper_RapidTerminateReceiveItem
+0x8ffafe: DashTremor_TwiddleOffset
+0x8ffb7a: kBombosBlasts_Tab
+0x8ffbc2: kRadialProjection_Tab2
+0x8ffc02: kRadialProjection_Tab0
+0x8ffc42: kRadialProjection_Tab1
+0x8ffc82: kRadialProjection_Tab3
+0x8ffcc2: kSomarianBlockDivide_Y
+0x8ffce2: kSomarianBlockDivide_X
+0x8ffd02: kSomarianBlockDivide_Char
+0x8ffd12: kSomarianBlockDivide_Flags
+0x8ffd22: Link_CheckBunnyStatus
+0x8ffd3c: Ancilla_TerminateWaterfallSplashes
+0x8ffd52: Ancilla_TerminateIfOffscreen
+0x8ffd86: Sprite_InitializeSecondaryItemMinigame
+0x8ffdaa: Main_ShowTextMessage
+0x8ffdc4: Sprite_SpawnSparkleAncilla
+0x8ffdcf: Bomb_CheckUndersideSpriteStatus
+0x9af500: kRetreatBat_Dmds
+0x9af590: kRetreatBat_Xpos
+0x9af598: kRetreatBat_Ypos
+0x9af5a0: kRetreatBat_Delay
+0x9af5a5: Sprite_37_Waterfall
+0x9af5ad: Sprite_Waterfall
+0x9af5b8: Waterfall
+0x9af5d5: kRetreatBat_Bg1Y
+0x9af5d9: Sprite_BatCrash
+0x9af63d: BatCrash_Approach
+0x9af684: BatCrash_Ascend
+0x9af6c8: BatCrash_DiveBomb
+0x9af6e9: BatCrash_StallTheInevitable
+0x9af6f5: Sprite_SpawnBatCrashCutscene
+0x9af730: kRetreatBat_Oams
+0x9af750: BatCrash_DrawHardcodedGarbage
+0x9af76d: kPyramidDebris_X
+0x9af78b: kPyramidDebris_Y
+0x9af7a9: kPyramidDebris_Xvel
+0x9af7c7: kPyramidDebris_Yvel
+0x9af7e5: BatCrash_SpawnDebris
+0x9af81f: kRetreatBat_count
+0x9af833: RetreatBat_Draw
+0x9af85c: kDrinkingGuy_Dmd
+0x9af88c: DrinkingGuy_Draw
+0x9af8ac: kLadyDmd
+0x9af92c: Lady_Draw
+0x9af954: Sprite_ReturnIfInactive___
+0x9af971: kLanmolaShrapnel_Yvel
+0x9af979: kLanmolaShrapnel_Xvel
+0x9af981: Lanmola_SpawnShrapnel
+0x9af9e6: UNREACHABLE_1AF9E6
+0x9afa0c: Sprite_Cukeman
+0x9afa7e: kCukeman_Dmd
+0x9afb0e: Cukeman_Draw
+0x9afb2c: RunningBoy_SpawnDustGarnish
+0x9afb7b: kSecretSubst_Tab0
+0x9afbbb: kSecretSubst_Tab2
+0x9afbcb: kSecretSubst_Tab1
+0x9afbdb: Overworld_SubstituteAlternateSecret
+0x9afc31: Sprite_MovableMantle_
+0x9afc39: Sprite_EE_CastleMantle_bounce
+0x9afc9b: kMovableMantle_X
+0x9afca1: kMovableMantle_Y
+0x9afca7: kMovableMantle_Char
+0x9afcad: kMovableMantle_Flags
+0x9afcb3: MovableMantle_Draw
+0x9afced: kMothula_Dmd
+0x9afdad: SpriteDraw_Mothula
+0x9afdb5: Mothula_Draw
+0x9afe48: kMothula_Draw_X
+0x9afe7e: kBottleVendor_GoodBeeX
+0x9afe83: kBottleVendor_GoodBeeY
+0x9afe88: BottleMerchant_BuyBee
+0x9afecf: Sprite_ChickenLady_
+0x9afed3: Sprite_ChickenLady
+0x9aff00: SpritePrep_DiggingGameGuy
+0x9aff2b: kItem_Hammer_SpawnWater_X
+0x9aff33: kItem_Hammer_SpawnWater_Y
+0x9aff3c: SpawnHammerWaterSplash
+0x9bb800: kFallHole_Pos
+0x9bb826: kFallHole_Area
+0x9bb84c: kFallHole_Entrances
+0x9bb860: Overworld_GetPitDestination
+0x9bb8bf: kOverworld_Entrance_Tab0
+0x9bb917: kOverworld_Entrance_Tab1
+0x9bb96f: kOverworld_Entrance_Area
+0x9bba71: kOverworld_Entrance_Pos
+0x9bbb73: kOverworld_Entrance_Id
+0x9bbbf4: Overworld_UseEntrance
+0x9bbd7a: HandleItemTileAction_Overworld
+0x9bbd82: Overworld_ToolAndTileInteraction
+0x9bbf1e: Overworld_PickHammerSfx
+0x9bbf4c: kBigRockTab1
+0x9bbf54: kBigRockTabY
+0x9bbf5c: kBigRockTabX
+0x9bbf64: Overworld_GetLinkMap16Coords
+0x9bbf9d: Overworld_HandleLiftableTiles
+0x9bc008: Overworld_LiftingSmallObj
+0x9bc055: Overworld_SmashRockPile
+0x9bc063: Overworld_SmashRockPile_downOneTile
+0x9bc076: Overworld_SmashRockPile_normalCoords
+0x9bc09f: SmashRockPile_fromLift
+0x9bc0f8: Overworld_BombTiles32x32
+0x9bc155: Overworld_BombTile
+0x9bc21d: Overworld_AlterWeathervane
+0x9bc264: OpenGargoylesDomain
+0x9bc2a7: CreatePyramidHole
+0x9bc2f9: kSecretsForScreen
+0x9bc8a4: Overworld_RevealSecret
+0x9bc943: AdjustSecretForPowder
+0x9bc952: Overworld_DrawWoodenDoor
+0x9bc97c: Overworld_DrawMap16_Persist
+0x9bc980: Overworld_DrawMap16
+0x9bc983: Overworld_DrawMap16_Anywhere
+0x9bc9de: Overworld_AlterTileHardcore
+0x9bca69: Overworld_FindMap16VRAMAddress
+0x9bca9f: Overworld_CreateTRPortal
+0x9bcaba: kOverworld_EntranceSequence
+0x9bcac4: Overworld_AnimateEntrance
+0x9bcade: Overworld_AnimateEntrance_PoD
+0x9bcae5: AnimateEntrance_PoD_step1
+0x9bcb2b: AnimateEntrance_PoD_step2
+0x9bcb47: AnimateEntrance_PoD_step3
+0x9bcb6c: AnimateEntrance_PoD_step4
+0x9bcb91: AnimateEntrance_PoD_step5
+0x9bcba6: Overworld_AnimateEntrance_Skull
+0x9bcbad: AnimateEntrance_Skull_step1
+0x9bcbee: AnimateEntrance_Skull_step2
+0x9bcc27: AnimateEntrance_Skull_step3
+0x9bcc4d: AnimateEntrance_Skull_step4
+0x9bcc8c: AnimateEntrance_Skull_step5
+0x9bccd4: Overworld_AnimateEntrance_Mire
+0x9bccfa: kMiseryMireEntranceBits
+0x9bcd14: AnimateEntrance_Mire_step1
+0x9bcd41: AnimateEntrance_Mire_step2
+0x9bcda9: AnimateEntrance_Mire_step3
+0x9bcdd7: AnimateEntrance_Mire_step4
+0x9bce05: AnimateEntrance_Mire_step5
+0x9bce28: Overworld_AnimateEntrance_TurtleRock
+0x9bce48: AnimateEntrance_TurtleRock_step1
+0x9bce5e: Overworld_EntranceSequence_Func3_1
+0x9bce62: Overworld_EntranceSequence_Func3_2
+0x9bce66: Overworld_EntranceSequence_Func3_3
+0x9bce8a: AnimateEntrance_TurtleRock_step5
+0x9bceac: AnimateEntrance_TurtleRock_step6
+0x9bcef8: AnimateEntrance_TurtleRock_step7
+0x9bcf17: AnimateEntrance_TurtleRock_step8
+0x9bcf40: OverworldEntrance_PlayJingle
+0x9bcf60: OverworldEntrance_DrawManyTR
+0x9bcfd9: Overworld_AnimateEntrance_GanonsTower
+0x9bcfe0: AnimateEntrance_GanonsTower_step01
+0x9bcff1: AnimateEntrance_GanonsTower_step02
+0x9bd00e: OverworldEntrance_AdvanceAndBoom
+0x9bd01d: AnimateEntrance_GanonsTower_step03
+0x9bd062: AnimateEntrance_GanonsTower_step04
+0x9bd093: AnimateEntrance_GanonsTower_step05
+0x9bd0de: AnimateEntrance_GanonsTower_step06
+0x9bd107: AnimateEntrance_GanonsTower_step07
+0x9bd127: AnimateEntrance_GanonsTower_step08
+0x9bd14d: AnimateEntrance_GanonsTower_step09
+0x9bd16d: AnimateEntrance_GanonsTower_step10
+0x9bd19f: AnimateEntrance_GanonsTower_step11
+0x9bd1c0: AnimateEntrance_GanonsTower_step12
+0x9bd218: kPalette_MainSpr
+0x9bd308: kPalette_ArmorAndGloves
+0x9bd39e: kPalette_SpriteAux3
+0x9bd446: kPalette_MiscSprite_Indoors
+0x9bd4e0: kPalette_SpriteAux1
+0x9bd630: kPalette_Sword
+0x9bd648: kPalette_Shield
+0x9bd660: kHudPalData
+0x9bd70a: kPalette_PalaceMapSpr
+0x9bd734: kPalette_DungBgMain
+0x9be544: kPalette_PalaceMapBg
+0x9be604: kPalette_OverworldBgAux3
+0x9be6c8: kPalette_OverworldBgMain
+0x9be86c: kPalette_OverworldBgAux12
+0x9bebc6: kMult_14
+0x9bebd6: kMult_14b
+0x9bec13: kMult_42
+0x9bec3b: kMult_70
+0x9bec47: kHudPaletteOffs
+0x9bec4b: kMult_180
+0x9bec77: Palette_Load_SpritePal0Left
+0x9bec9e: Palette_Load_SpriteMain
+0x9becc5: Palette_Load_SpriteAux1
+0x9bece4: Palette_Load_SpriteAux2
+0x9bed03: Palette_Load_Sword
+0x9bed29: Palette_Load_Shield
+0x9bed4f: UNREACHABLE_1BED4F
+0x9bed6e: Palette_Load_SpriteEnvironment
+0x9bed72: Palette_Load_SpriteEnvironment_Dungeon
+0x9bed91: Palette_MiscSprite_Outdoors
+0x9beddd: Palette_Load_DungeonMapSprite
+0x9bedf5: kGlovesColor
+0x9bedf9: Palette_Load_LinkArmorAndGloves
+0x9bee1b: Palette_UpdateGlovesColor
+0x9bee3a: Palette_Load_DungeonMapBG
+0x9bee52: Palette_Load_HUD
+0x9bee74: Palette_Load_DungeonSet
+0x9beea8: Palette_Load_OWBG3
+0x9beec7: Palette_Load_OWBGMain
+0x9beee8: Palette_Load_OWBG1
+0x9bef0c: Palette_Load_OWBG2
+0x9bef30: Palette_LoadSingle
+0x9bef4b: Palette_LoadMultiple
+0x9bef7b: Palette_LoadMultiple_Arbitrary
+0x9bef96: Palette_LoadForFileSelect
+0x9bf032: Palette_LoadForFileSelect_Armor
+0x9bf072: Palette_LoadForFileSelect_Sword
+0x9bf09a: Palette_LoadForFileSelect_Shield
+0x9bf0c2: Palette_LoadAgahnim
+0x9bf110: kSomeTileAttr
+0x9d8000: kFish_Tab2
+0x9d8010: Sprite_ApplyConveyor
+0x9d8040: Sprite_CreateDeflectedArrow
+0x9d808c: Sprite_Move_0x9d
+0x9d8094: Sprite_CheckTileCollision____
+0x9d8099: Sprite_D4_Landmine
+0x9d80bb: kLandMine_OamFlags
+0x9d80bf: Landmine_Detonating
+0x9d80fc: kLandmine_Dmd
+0x9d810c: Landmine_Draw
+0x9d8129: Sprite_D3_Stal
+0x9d814f: Stal_Dormant
+0x9d8198: kStal_Gfx
+0x9d819d: Stal_Active
+0x9d81dc: kStal_Dmd
+0x9d820c: Stal_Draw
+0x9d8235: Sprite_D2_FloppingFish
+0x9d826c: FloppingFish_WriggleInHands
+0x9d827e: FloppingFish_PrepareLeap
+0x9d828b: Sprite_SpawnSmallWaterSplash_
+0x9d8290: kFish_Gfx2
+0x9d82a1: FloppingFish_Leap
+0x9d830f: FloppingFish_CheckForWaterInit
+0x9d8321: kFish_Xvel
+0x9d8329: kFish_Yvel
+0x9d8331: kFish_Tab1
+0x9d8333: kFish_Gfx
+0x9d8336: FloppingFish_Flop
+0x9d83b6: kFish_Dmd
+0x9d8436: kFish_Dmd2
+0x9d847e: DontDrawFloppingFish
+0x9d8483: Fish_Draw
+0x9d84f1: kChimneySmoke_Dmd
+0x9d8531: ChimneySmoke_Draw
+0x9d8549: Sprite_DrawMultiple__
+0x9d8550: Sprite_ChimneySmoke
+0x9d858b: Sprite_D1_BunnyBeam
+0x9d858f: Sprite_Chimney
+0x9d85e0: Sprite_BunnyBeam
+0x9d85fa: kRabbitBeam_Gfx
+0x9d8600: RabbitBeam_Active
+0x9d866a: Sprite_D0_Lynel
+0x9d868a: kLynel_Xtarget
+0x9d8694: kLynel_Ytarget
+0x9d8698: Lynel_TargetLink
+0x9d86cd: kLynel_Gfx
+0x9d86d5: Lynel_ApproachPlayer
+0x9d873c: kLynel_AttackGfx
+0x9d8740: Lynel_Fire
+0x9d8778: kLynel_Dmd
+0x9d8880: Lynel_Draw
+0x9d88a1: Sprite_SpawnPhantomGanon
+0x9d88bc: Sprite_PhantomGanon
+0x9d8906: kGanonBat_Gfx
+0x9d890a: kGanonBat_TargetXvel
+0x9d890c: kGanonBat_TargetYvel
+0x9d890e: Sprite_GanonBat
+0x9d89bb: kGanonBat_Dmd
+0x9d89eb: GanonBat_Draw
+0x9d8a04: kPhantomGanon_Dmd
+0x9d8a84: PhantomGanon_Draw
+0x9d8aa9: SwishEvery16Frames
+0x9d8ab6: Sprite_GanonTrident
+0x9d8ae4: Sprite_ApproachTargetSpeed_
+0x9d8b07: kTrident_Xoffs
+0x9d8b0b: Trident_AimForParentPosition
+0x9d8b49: Sprite_FireBat_Trailer
+0x9d8b52: Sprite_SpiralFireBat
+0x9d8b90: FireBat_Move
+0x9d8bbc: Sprite_AdjustAuxCoords_bank1D
+0x9d8bd1: kFirebat_X
+0x9d8bd3: kFirebat_Xhi
+0x9d8bd5: kFirebat_Y
+0x9d8bd7: Sprite_FireBat_Launched
+0x9d8bee: GetPositionRelativeToTheGreatOverlordGanon
+0x9d8c17: FireBat_PositionSelfAndAnimateAndPrepareForLaunch
+0x9d8c2b: kFirebat_Gfx2
+0x9d8c34: kFirebat_Gfx
+0x9d8c38: FireBat_PositionSelfAndAnimate
+0x9d8c43: FireBat_Animate
+0x9d8c55: FireBat_LaunchedFlying
+0x9d8c90: kFirebat_Draw_X
+0x9d8c94: kFirebat_Draw_Char
+0x9d8c9b: kFirebat_Draw_Flags
+0x9d8ca9: FireBat_Draw
+0x9d8d06: Ganon_AttemptTridentCatch
+0x9d8d29: SpritePrep_Ganon_PrepareBattle
+0x9d8d50: kGanonMath_X
+0x9d8d60: kGanonMath_Y
+0x9d8d70: Ganon_HandleFireBatCircle
+0x9d8e75: Six_NOP
+0x9d8e7c: Ganon_SpawnSpiralBat
+0x9d8eb4: Sprite_D6_Ganon
+0x9d8ecb: kGanon_HeadDir0
+0x9d8ecd: kGanon_GfxB
+0x9d8f8a: kGanon_Gfx19
+0x9d8f8c: Ganon_Phase4_Stunned
+0x9d8fb8: kGanon_Gfx17b
+0x9d8fba: kGanon_Gfx17
+0x9d8fbc: Ganon_Phase4_Attack
+0x9d8ffa: Ganon_EnableInvincibility
+0x9d9016: kGanon_Gfx15
+0x9d9018: Ganon_Phase3_SmashFloor
+0x9d9042: kGanon_Gfx16
+0x9d9044: Ganon_Phase3_DropTiles
+0x9d907f: Sprite_ShowMessageMinimal_
+0x9d90c4: kGanon_Ov_Type
+0x9d90c8: kGanon_Ov_X
+0x9d90cc: kGanon_Ov_Y
+0x9d90d0: Ganon_SpawnFallingTilesOverlord
+0x9d910d: kGanon_Gfx12
+0x9d9113: Ganon_Phase3_FireBats
+0x9d9158: kGanon_Gfx16_Y
+0x9d915c: Ganon_SpawnFireBat_trailing
+0x9d9160: Ganon_Func1_3
+0x9d9162: Ganon_Func1
+0x9d91d5: Ganon_Phase3_SabotagePB
+0x9d9203: Ganon_Phase2_CircleOfBats
+0x9d9231: kGanon_Tab2
+0x9d9240: kGanon_Delay8
+0x9d9248: Ganon_Phase2_LaunchSpiralBats
+0x9d928f: Ganon_Phase2_Warp
+0x9d92aa: Ganon_Phase2_MakePhaseDecision
+0x9d92ca: Ganon_Phase1_IntroduceSelf
+0x9d92f7: kGanon_G_Func2
+0x9d9307: kGanon_GfxFunc2
+0x9d9317: kGanon_X1
+0x9d9319: kGanon_XHi1
+0x9d931b: kGanon_Y1
+0x9d931d: kGanon_YHi1
+0x9d931f: kGanon_Xvel1
+0x9d932f: kGanon_Yvel1
+0x9d933f: kGanon_Gfx1
+0x9d9354: Ganon_Phase1_ThrowTrident
+0x9d93db: Ganon_Phase1_AnimateTridentSpin
+0x9d93fb: kGanon_Gfx2_0
+0x9d93fd: Ganon_Phase1_WaitForTrident
+0x9d9424: kGanon_G
+0x9d9426: kGanon_Gfx
+0x9d9428: Ganon_Phase1_MakePhaseDecision
+0x9d9443: Ganon_HandleAnimation_Idle
+0x9d9456: Ganon_Func2_
+0x9d945a: kGanon_HeadDir
+0x9d946c: Ganon_Phase1_Warp
+0x9d947f: Ganon_SelectWarpLocation
+0x9d94ba: Ganon_ShakeHead
+0x9d94c5: kGanon_NextX
+0x9d94cd: kGanon_NextY
+0x9d94d5: kGanon_NextSubtype
+0x9d94f5: Ganon_Phase3_Warp
+0x9d94fa: Ganon_LookAround
+0x9d95ad: Ganon_Phase2_HoldTrident
+0x9d95ce: kGanon_Draw_X
+0x9d969a: kGanon_Draw_Y
+0x9d9766: kGanon_Draw_Char
+0x9d9832: kGanon_SprOffs
+0x9d9843: kGanon_Draw_Flags
+0x9d990f: kTrident_Dmd
+0x9d9a9f: kTrident_Draw_X
+0x9d9aa9: kTrident_Draw_Y
+0x9d9ab3: kGanon_Draw_Char2
+0x9d9abf: kGanon_Draw_Flags2
+0x9d9acb: kGanon_Dmd
+0x9d9adf: Ganon_Draw
+0x9d9c1c: Trident_Draw
+0x9d9c7a: kSwamola_Mult32
+0x9d9c80: SpritePrep_Swamola_InitializeSegments
+0x9d9cb0: Sprite_CF_Swamola
+0x9d9ced: kSwamola_Target_X
+0x9d9cff: kSwamola_Target_Y
+0x9d9d11: kSwamola_Target_Dir
+0x9d9d19: Swamola_Emerge
+0x9d9d67: Swamola_Ascend
+0x9d9d80: Sprite_Swamola_ApproachTargetVelocity
+0x9d9da3: kSwamola_Z_Accel
+0x9d9da5: kSwamola_Z_Vel_Target
+0x9d9da7: Swamola_Wiggle
+0x9d9e13: Swamola_ProjectVelocityTowardsTarget
+0x9d9e32: Swamola_Descend
+0x9d9e62: Swamola_Submerge
+0x9d9eaa: Swamola_SpawnRipples
+0x9d9ece: Sprite_Swamola_Ripples
+0x9d9edd: kSwamolaRipples_Dmd
+0x9d9f1d: SwamolaRipples_Draw
+0x9d9f3c: kSwamola_HistOffs
+0x9d9f40: kSwamola_Gfx
+0x9d9f50: kSwamola_Draw_OamFlags
+0x9d9f60: kSwamola_Gfx2
+0x9d9f64: Swamola_Draw
+0x9da03c: Blind_SpawnFromMaiden
+0x9da081: SpritePrep_Blind_PrepareBattle
+0x9da0b1: BlindLaser_SpawnTrailGarnish
+0x9da110: kBlindHead_XvelLimit
+0x9da112: kBlindHead_XposLimit
+0x9da114: kBlindHead_YvelLimit
+0x9da116: kBlindHead_YposLimit
+0x9da118: Sprite_Blind_Head
+0x9da1ed: Blind_SpawnHead
+0x9da23c: kBlindLaser_Gfx
+0x9da24c: kBlindLaser_OamFlags
+0x9da25c: kBlind_Gfx0
+0x9da263: Sprite_CE_Blind
+0x9da268: Sprite_BlindLaser
+0x9da2d2: Sprite_Blind_Blind_Blind
+0x9da3d4: kBlind_Gfx_BehindCurtain
+0x9da3d8: Blind_Undress
+0x9da40b: kBlind_Gfx_Rerobe
+0x9da410: Blind_Rerobe
+0x9da445: kBlindHead_SpawnFireball_Xvel
+0x9da455: kBlindHead_SpawnFireball_Yvel
+0x9da465: Blind_FireballFlurry
+0x9da49d: Blind_SpitFireball
+0x9da4c6: Blind_THELIGHT
+0x9da4f9: SpawnBossPoof
+0x9da53a: Blind_EscapeLight
+0x9da567: kBlind_Oscillate_YVelTarget
+0x9da569: kBlind_Oscillate_XVelTarget
+0x9da56b: kBlind_Oscillate_XPosTarget
+0x9da56d: Blind_Shimmy
+0x9da604: kBlind_SwitchWall_YVelTarget
+0x9da606: kBlind_SwitchWall_YPosTarget
+0x9da608: Blind_SwapSides
+0x9da647: Blind_Decelerate_X
+0x9da665: kBlind_WhirlAround_Gfx
+0x9da667: Blind_Spin
+0x9da6a4: Blind_Decelerate_Y
+0x9da6c0: Blind_CheckBumpDamage
+0x9da6cf: kBlind_Gfx_Animate
+0x9da6d7: kBlind_HeadDir
+0x9da6e7: kBlind_Animate_Tab
+0x9da6ef: Blind_Animate
+0x9da729: Blind_AnimateRobes
+0x9da745: kBlind_Laser_Xvel
+0x9da755: kBlind_Laser_Yvel
+0x9da765: Blind_SpawnLaser
+0x9da7aa: kBlind_Dmd
+0x9daaf2: kBlindPoof_Dmd
+0x9dac2f: BlindPoof_Draw
+0x9dac42: kBlind_OamIdx
+0x9dac4c: kBlindHead_Draw_Char
+0x9dac5c: kBlindHead_Draw_Flags
+0x9dac6c: Blind_Draw
+0x9dacc8: Blind_BumpDamageFromBody
+0x9dad0e: Trinexx_Initialize
+0x9dad16: TrinexxComponents_Initialize
+0x9dad26: Trinexx_Initialize_Rock
+0x9dad4f: Trinexx_RestoreXY
+0x9dad67: Trinexx_Initialize_Fire
+0x9dad70: TrinexxPartB_Initialize
+0x9dad8c: Trinexx_CachePosition
+0x9dada5: kSprite_TrinexxD_Gfx3
+0x9dadad: kSprite_TrinexxD_Gfx
+0x9dadb5: Sprite_Trinexx_FinalPhase
+0x9dae65: kSprite_TrinexxD_Xvel
+0x9dae69: kSprite_TrinexxD_Yvel
+0x9dae6d: Sprite_Trinexx_Phase2_SnekAlongWall
+0x9daea8: Trinexx_CircleLink
+0x9daef5: Sprite_Trinexx_Phase2_SnekAfterLink
+0x9daf24: kTrinexxD_HistPos
+0x9daf3c: kSprite_TrinexxD_Gfx2
+0x9daf54: kTrinexxD_OamOffs
+0x9daf84: Sprite_TrinexxD_Draw
+0x9db079: Sprite_Trinexx_CheckDamageToFlashingSegment
+0x9db0ca: Sprite_CB_TrinexxRockHead
+0x9db1b1: kTrinexx_X0
+0x9db1b9: kTrinexx_X0Hi
+0x9db1c1: kTrinexx_Y0
+0x9db1c9: kTrinexx_Y0Hi
+0x9db24a: kTrinexx_Tab0
+0x9db24e: kTrinexx_Tab1
+0x9db252: Trinexx_ChooseNextAction
+0x9db2a1: Trinexx_MoveBody
+0x9db34d: Sprite_Trinexx_State1_Inner
+0x9db369: Trinexx_PrepareLunge
+0x9db388: Trinexx_LungeHead
+0x9db3b5: Trinexx_WagTail
+0x9db3e6: Trinexx_HandleShellCollision
+0x9db440: kTrinexx_Draw1_Dmd
+0x9db560: SpriteDraw_TrinexxRockHead
+0x9db587: SpriteDraw_TrinexxRockHeadAndBody
+0x9db773: kTrinexx_Draw_X
+0x9db7b9: kTrinexx_Draw_Y
+0x9db7ff: kTrinexx_Draw_Char
+0x9db804: kTrinexx_Mults
+0x9db810: kTrinexx_Draw_Xoffs
+0x9db820: kTrinexx_Draw_Yoffs
+0x9db830: kTrinexxHead_Target0
+0x9db85d: kTrinexxHead_Target1
+0x9db88a: kTrinexxHead_Xoffs
+0x9db88c: kTrinexxHead_B
+0x9db897: Sprite_CC_TrinexxBreath_FireHead
+0x9db89f: Sprite_CD_TrinexxBreath_IceHead
+0x9db8a7: Sprite_Sidenexx
+0x9db92b: Sidenexx_Stunned
+0x9db986: Sidenexx_Dormant
+0x9db9a6: Sidenexx_Think
+0x9db9f2: Sidenexx_Move
+0x9dba68: kTrinexxHead_FrameMask
+0x9dba70: Sidenexx_Breathe
+0x9dbae8: Sidenexx_ExhaleDanger
+0x9dbafa: Trinexx_Func5_Inner
+0x9dbb3f: Sidenexx_Explode
+0x9dbb6d: kMult_9
+0x9dbb70: TrinexxHead_Draw
+0x9dbc8c: TrinexxHead_FirstPart_X
+0x9dbc91: TrinexxHead_FirstPart_Y
+0x9dbc96: TrinexxHead_FirstPart_Char
+0x9dbc9b: TrinexxHead_FirstPart_Flags
+0x9dbca0: TrinexxHead_FirstPart_Draw
+0x9dbd28: Sprite_TrinexxBreath_ice
+0x9dbd44: Sprite_CC_CD_Common
+0x9dbd65: Sprite_CD_SpawnGarnish
+0x9dbdc6: Sprite_TrinexxBreath_fire
+0x9dbdd6: Sprite_TrinexxFire_AddFireGarnish
+0x9dbde8: Garnish_FlameTrail
+0x9dbe3c: kChainChomp_Mult16
+0x9dbe44: SpritePrep_Chainchomp
+0x9dbe7d: Sprite_CA_ChainChomp
+0x9dbf0c: kChainChomp_Xvel
+0x9dbf1c: kChainChomp_Yvel
+0x9dbf2c: ChainChomp_Idle
+0x9dbf95: ChainChomp_Meander
+0x9dbfe5: ChainChomp_InvertLunge
+0x9dc00c: ChainChomp_State3
+0x9dc020: kChainChomp_Muls
+0x9dc02a: ChainChomp_MoveChain
+0x9dc0f2: ChainChomp_HandleLeash
+0x9dc172: kChainChomp_Gfx
+0x9dc182: kChainChomp_OamFlags
+0x9dc192: ChainChomp_Draw
+0x9dc211: Sprite_CheckDamageBoth__
+0x9dc21a: SpriteActive4_MainLong
+0x9dc222: SpriteActive4_Main
+0x9dc26d: kTektite_Xvel
+0x9dc271: kTektite_Yvel
+0x9dc275: Sprite_C9_Tektite
+0x9dc293: Sprite_Tektite
+0x9dc2ce: kTektite_Dir
+0x9dc2d2: Tektite_Idle
+0x9dc388: Tektite_Midjump
+0x9dc3a8: Tektite_Bouncy
+0x9dc3c5: kTektite_Dmd
+0x9dc3f5: Tektite_Draw
+0x9dc414: Sprite_C8_BigFairy
+0x9dc41c: Sprite_FairyCloud
+0x9dc443: FairyCloud_ApproachLink
+0x9dc489: FairyCloud_WaitForHeal
+0x9dc49c: FairyCloud_Dissipate
+0x9dc4bf: Sprite_BigFairy
+0x9dc4f9: BigFairy_WaitForLink
+0x9dc54f: BigFairy_DoAbsolutelyNothing
+0x9dc550: kBigFaerie_Dmd
+0x9dc5d0: BigFaerie_Draw
+0x9dc5ee: kFaerieCloud_Draw_XY
+0x9dc5fa: kFaerieCloud_Draw_XY_Hi
+0x9dc606: kFaerieCloud_Draw_Idx
+0x9dc616: FaerieCloud_Draw
+0x9dc64f: Sprite_C7_Pokey
+0x9dc69a: Hokbok_Main
+0x9dc719: kHokbok_B
+0x9dc721: Pokey_ResetBounce
+0x9dc738: Pokey_MoveFaster
+0x9dc751: Sprite_BounceFromTileCollision
+0x9dc778: Sprite_BounceFromTileCollisionLong
+0x9dc77d: Hokbok_Draw
+0x9dc7eb: Sprite_C5_Medusa
+0x9dc845: Fireball_Configure
+0x9dc853: kFireballJunction_X
+0x9dc85b: kFireballJunction_Y
+0x9dc863: kFireballJunction_XYvel
+0x9dc869: Sprite_C6_4WayShooter
+0x9dc8cc: kThief_Gfx
+0x9dc8d8: Sprite_C4_Thief
+0x9dc90e: Thief_Loitering
+0x9dc94c: Thief_Watching
+0x9dc985: Thief_Chasing
+0x9dc9df: Thief_Stealing
+0x9dca24: Thief_ScanForBooty
+0x9dca4c: Thief_TargetBooty
+0x9dca9e: Thief_GrabBooty
+0x9dcaf2: Thief_CheckCollisionWithLink
+0x9dcb20: kThiefSpawn_Xvel
+0x9dcb26: kThiefSpawn_Yvel
+0x9dcb2c: kThiefSpawn_Items
+0x9dcb30: Thief_SpillItems
+0x9dcbd6: kThief_Dmd
+0x9dcc96: kThief_DrawChar
+0x9dcc9a: kThief_DrawFlags
+0x9dcc9e: Thief_Draw
+0x9dccdb: kGibo_OamFlags
+0x9dccdf: kGibo_OamFlags2
+0x9dcce1: Sprite_C3_Gibo
+0x9dcd12: Gibo_Main
+0x9dcd62: kGibo_Xvel
+0x9dcd6a: kGibo_Yvel
+0x9dcd72: Gibo_Mitosis
+0x9dcde2: Gibo_Osmosis
+0x9dcdeb: Gibo_ConsumeDaughter
+0x9dce5e: kGibo_Dmd
+0x9dcf5e: Gibo_Draw
+0x9dcfc3: kBoulder_Zvel
+0x9dcfc5: kBoulder_Yvel
+0x9dcfc7: kBoulder_Xvel
+0x9dcfcb: Sprite_C2_Boulder
+0x9dd02a: Boulder_OutdoorsMain
+0x9dd088: kBoulder_Dmd
+0x9dd108: kLargeShadow_Dmd
+0x9dd180: kGanon_Mult24
+0x9dd185: Boulder_Draw
+0x9dd1a8: SpriteDraw_BigShadow
+0x9dd1af: Sprite_DrawLargeShadow2
+0x9dd1fd: CutsceneAgahnim_SpawnZeldaOnAltar
+0x9dd234: Sprite_C1_CutsceneAgahnim
+0x9dd23f: CutsceneAgahnim_Agahnim
+0x9dd285: CutsceneAgahnim_HelloMyNameIs
+0x9dd2a1: kChattyAgahnim_LevitateGfx
+0x9dd2a5: CutsceneAgahnim_LightAsAFeatherStiffAsABoard
+0x9dd2ef: CutsceneAgahnim_BanishZelda
+0x9dd322: CutsceneAgahnim_MadeHerGoPoof
+0x9dd34f: CutsceneAgahnim_Brag
+0x9dd36b: CutsceneAgahnim_HideBehindCurtain
+0x9dd392: Sprite_Agahnim_ApplyMotionBlur
+0x9dd3b9: CutsceneAgahnim_ExistNoMore
+0x9dd3d1: kChattyAgahnim_Dmd
+0x9dd451: ChattyAgahnim_Draw
+0x9dd48d: kChattyAgahnim_Telewarp_Data
+0x9dd4fd: kChattyAgahnim_Telewarp_Data_Ext
+0x9dd50b: kMult_4
+0x9dd516: SpriteDraw_CutsceneAgahnimSpell
+0x9dd57d: Sprite_CutsceneAgahnim_Zelda
+0x9dd581: kAltarZelda_Dmd
+0x9dd5a1: AltarZelda_Main
+0x9dd5d9: kAltarZelda_XOffs
+0x9dd5e9: AltarZelda_DrawBody
+0x9dd661: kAltarZelda_Warp_Dmd
+0x9dd6b1: SpriteDraw_AltarZeldaWarp
+0x9dd6d1: Sprite_InitializedSegmented
+0x9dd6f6: Sprite_09_Moldorm
+0x9dd6fe: kGiantMoldorm_Xvel
+0x9dd71e: kGiantMoldorm_Yvel
+0x9dd73e: kGiantMoldorm_NextDir
+0x9dd74e: Sprite_GiantMoldorm
+0x9dd7fe: Moldorm_Move
+0x9dd82d: Moldorm_Turn
+0x9dd852: Moldorm_Charge
+0x9dd881: GiantMoldorm_Draw
+0x9dd8f2: GiantMoldorm_IncrementalSegmentExplosion
+0x9dd913: kGiantMoldorm_Head_Dmd
+0x9dd993: SpriteDraw_Moldorm_Head
+0x9dd9b8: kGiantMoldorm_SegA_Dmd
+0x9dd9f8: SpriteDraw_Moldorm_SegmentA
+0x9dda50: SpriteDraw_Moldorm_SegmentB
+0x9dda5b: kGiantMoldorm_OamFlags
+0x9dda5f: SpriteDraw_Moldorm_SegmentC
+0x9ddaba: Moldorm_HandleTail
+0x9ddb17: SpriteDraw_Moldorm_Tail
+0x9ddb3e: kGiantMoldorm_Eye_X
+0x9ddb5e: kGiantMoldorm_Eye_Y
+0x9ddb7e: kGiantMoldorm_Eye_Char
+0x9ddb8e: kGiantMoldorm_Eye_Flags
+0x9ddb9e: SpriteDraw_Moldorm_Eyeballs
+0x9ddc11: Moldorm_Explode
+0x9ddc16: Sprite_ScheduleBossForDeath
+0x9ddc23: nullsub_12
+0x9ddc2a: Sprite_MakeBossExplosion
+0x9ddc30: Sprite_MakeBossDeathExplosion_NoSound
+0x9ddc72: Sprite_01_Vulture
+0x9ddc7a: Sprite_Vulture
+0x9ddc9c: Vulture_Perched
+0x9ddcb5: kVulture_Gfx
+0x9ddcb9: Vulture_Circling
+0x9ddd1e: kVulture_Dmd
+0x9ddd5e: Vulture_Draw
+0x9ddd7b: Sprite_00_Raven
+0x9ddd85: Sprite_Raven
+0x9dddac: kRaven_AscendTime
+0x9dddae: Raven_Perched
+0x9ddde5: Raven_Rise
+0x9dde09: Raven_Attack
+0x9dde5a: Raven_SetFlip
+0x9dde66: Raven_Flee
+0x9dde82: Vitreous_SpawnMinions
+0x9dde8a: kVitreous_SpawnSmallerEyes_X
+0x9ddea4: kVitreous_SpawnSmallerEyes_Y
+0x9ddebe: kVitreous_SpawnSmallerEyes_Gfx
+0x9ddecb: Vitreous_SpawnSmallerEyes
+0x9ddf45: kStandaloneItem_Zvel
+0x9ddf49: Sprite_C0_Catfish
+0x9ddf54: Sprite_Catfish_QuakeMedallion
+0x9ddfd1: Catfish_BigFish
+0x9ddfe6: Catfish_Sleep
+0x9de039: Catfish_TheRumbling
+0x9de07c: kGreatCatfish_Emerge_Gfx
+0x9de08c: Catfish_Surface
+0x9de0bf: kGreatCatfish_Conversate_Gfx
+0x9de0d3: Catfish_LeaveMeAlone
+0x9de144: Sprite_SpawnBomb
+0x9de164: I_said_no_plop
+0x9de16c: Catfish_RegurgitateMedallion
+0x9de1aa: Sprite_Zora_RegurgitateFlippers
+0x9de1ed: Catfish_SpawnPlop
+0x9de214: Sprite_SpawnWaterSplash_
+0x9de21c: Sprite_SpawnWaterSplash
+0x9de240: kGreatCatfish_Dmd
+0x9de320: GreatCatfish_Draw
+0x9de33d: kWaterSplash_Dmd
+0x9de37d: Sprite_Catfish_SplashOfWater
+0x9de39d: kSpriteLightning_Gfx
+0x9de3a5: kSpriteLightning_OamFlags
+0x9de3ad: kSpriteLightning_Xoff
+0x9de3ed: Sprite_BF_Lightning
+0x9de475: Lightning_SpawnGarnish
+0x9de4c8: Sprite_BD_Vitreous
+0x9de4eb: Vitreous_DunkedInGoo
+0x9de53d: kVitreous_Animate_Gfx
+0x9de53f: kVitreous_AfromG
+0x9de549: Vitreous_Lightningening
+0x9de563: Vitreous_Animate
+0x9de589: kVitreous_Xvel
+0x9de58b: Vitreous_Bouncing
+0x9de5ca: kVitreous_WhichToActivate
+0x9de5da: Vitreous_SetMinionsForth
+0x9de602: kAgahnim_Lighting_X
+0x9de612: Sprite_SpawnLightning
+0x9de656: kVitreous_Dmd
+0x9de716: Vitreous_Draw
+0x9de763: kSprite_Vitreolus_Dx
+0x9de76b: kSprite_Vitreolus_Dy
+0x9de773: Sprite_BE_VitreousEye
+0x9de7c4: Vitreolus_TargetPlayerPosition
+0x9de7d9: Vitreolus_PursueTargetPosition
+0x9de82a: Vitreolus_ReturnToOrigin
+0x9de893: Sprite_DirectionToFacePlayer___
+0x9de898: Sprite_IsToRightOfPlayer___
+0x9de89d: Sprite4_IsBelowPlayer
+0x9de8a2: Sprite_ReturnIfInactive____
+0x9de8c5: Sprite_ReturnIfRecoiling__
+0x9de948: Sprite_MoveXyz___
+0x9de94b: Sprite_Move___
+0x9de952: Sprite4_MoveX
+0x9de95d: Sprite_MoveY_
+0x9de98b: Sprite_MoveZ__
+0x9de9ad: Sprite_PrepOamCoordOrDoubleRet___
+0x9de9b6: HandleScreenFlash
+0x9de9da: ExecuteCachedSprites
+0x9dea00: UncacheAndExecuteSprite
+0x9deb84: Sprite_SimulateSoldier
+0x9debeb: Overlord19_ArmosCoordinator
+0x9debf3: ArmosCoordinator_Main
+0x9dec12: ArmosCoordinator_WaitForWakeUp
+0x9dec34: ArmosCoordinator_CirclePosition
+0x9dec42: kArmosCoordinator_BackWallX
+0x9dec48: ArmosCoordinator_LineUp
+0x9dec69: ArmosCoordinator_ForwardMarch
+0x9dec96: ArmosCoordinator_Pinch
+0x9decab: ArmosCoordinator_Spread
+0x9decc0: kArmosCoordinator_Tab0
+0x9deccc: ArmosCoordinator_RotateKnights
+0x9decd4: ArmosCoordinator_Rotate
+0x9dedb8: ArmosCoordinator_CheckKnights
+0x9dedcb: ArmosCoordinator_DisableCoercion
+0x9dedd6: Sprite_70_KingHelmasaurFireball
+0x9dedde: kHelmasaurFireball_Char
+0x9dede1: kHelmasaurFireball_Flags
+0x9dede3: Sprite_HelmasaurFireball
+0x9dee72: HelmasaurFireball_PreMigrateDown
+0x9dee85: HelmasaurFireball_MigrateDown
+0x9dee9c: kHelmasaurFireball_Gfx
+0x9deea0: HelmasaurFireball_DelayThenTriSplit
+0x9deeb3: HelmasaurFireball_DelayThenQuadSplit
+0x9deec9: HelamsaurFireball_Move
+0x9deecd: kHelmasaurFireball_TriSplit_Xvel
+0x9deed0: kHelmasaurFireball_TriSplit_Yvel
+0x9deed3: HelmasaurFireball_TriSplit
+0x9def2d: kHelmasaurFireball_TriSplit_Delay
+0x9def35: kHelmasaurFireball_QuadSplit_Xvel
+0x9def39: kHelmasaurFireball_QuadSplit_Yvel
+0x9def3d: HelmasaurFireball_QuadSplit
+0x9def76: Sprite_RedArmosCrusher
+0x9def7e: Sprite_ArmosCrusher
+0x9defac: RedArmosCrusher_TargetLink
+0x9defe0: RedArmosCrusher_Jump
+0x9df039: RedArmosCrusher_Hover
+0x9df045: RedArmosCrusher_Slam
+0x9df063: Sprite_40_LightningGate
+0x9df06b: Sprite_EvilBarrier
+0x9df0e1: kEvilBarrier_Dmd
+0x9df249: EvilBarrier_Draw
+0x9df277: SpritePrep_MiniMoldorm
+0x9df2a5: kDrawFourAroundOne_Dmd
+0x9df395: SpriteDraw_Antfairy
+0x9df3d4: Toppo_Flustered
+0x9df44d: kGoriya_Dmd
+0x9df54d: kGoriya_Dmd2
+0x9df589: Goriya_Draw
+0x9df5d4: kConvertVelocityToAngle_Tab0
+0x9df5f4: kConvertVelocityToAngle_Tab1
+0x9df614: Sprite_ConvertVelocityToAngle
+0x9df65d: Sprite_SpawnDynamically
+0x9df65f: Sprite_SpawnDynamicallyEx
+0x9df6cf: kSprite_Func5_Tab3
+0x9df7cf: kMult_32
+0x9df7d3: kMoldorm_Draw_Char
+0x9df7d6: kMoldorm_Draw_XY
+0x9df7dc: kMoldorm_Draw_Ext
+0x9df7df: kMoldorm_Draw_GetOffs
+0x9df7e2: kMoldorm_Draw_X
+0x9df802: kMoldorm_Draw_Y
+0x9df822: Moldorm_Draw
+0x9df943: Sprite_25_TalkingTree
+0x9df94b: Sprite_TalkingTree
+0x9df956: TalkingTree_Mouth
+0x9df96e: TalkingTree_IdleWithBomb
+0x9df99c: TalkingTree_DelayBomb
+0x9df9b0: kTalkingTree_Gfx2
+0x9df9b4: TalkingTree_SpitBomb
+0x9df9d2: kTalkingTree_Gfx
+0x9df9da: kTalkingTree_Delay
+0x9df9e2: TalkingTree_IdleWithoutBomb
+0x9dfa01: kTalkingTree_Msgs2
+0x9dfa2b: kTalkingTree_Msgs
+0x9dfa2f: kTalkingTree_Screens
+0x9dfa4e: TalkingTree_SpawnBomb
+0x9dfa7b: kTalkingTree_Dmd
+0x9dfadb: TalkingTree_Draw
+0x9dfafb: kTalkingTree_Type1_X
+0x9dfafd: kTalkingTree_Type1_Xhi
+0x9dfaff: kTalkingTree_Type1_X1
+0x9dfb0a: TalkingTree_Eye
+0x9dfb86: kTalkingTree_SpawnX
+0x9dfb8a: SpritePrep_TalkingTree_SpawnEyeball
+0x9dfbcc: kSpawnRupees_Xvel
+0x9dfbd0: kSpawnRupees_Yvel
+0x9dfbd4: kSpawnRupees_Type
+0x9dfbd7: RupeePull_SpawnPrize
+0x9dfc38: Sprite_D5_DigGameGuy
+0x9dfc5b: DigGameGuy_Idle
+0x9dfc89: DigGameGuy_OfferGame
+0x9dfce0: DigGameGuy_UnblockEntrance
+0x9dfd0a: DigGameGuy_SetTimer
+0x9dfd18: DigGameGuy_Proctor
+0x9dfd42: DiggingGameGuy_ComeBackLater
+0x9dfd4b: DigGame_SpawnPrize
+0x9dfd5c: DiggingGameGuy_AttemptPrizeSpawn
+0x9dfd82: kDiggingGameGuy_Xvel
+0x9dfd84: kDiggingGameGuy_X
+0x9dfd86: kDiggingGameGuy_Items
+0x9dfd8a: DiggingGameGuy_GiveItem
+0x9dfe03: kDiggingGameGuy_Dmd
+0x9dfe4b: DiggingGameGuy_Draw
+0x9dfe6e: kOldMountainMan_Dmd0
+0x9dfe7e: kOldMountainMan_Dmd1
+0x9dfefe: kOldMountainMan_Dma
+0x9dff0e: OldMountainMan_Draw
+0x9dff5b: SpriteModule_Burn_bounce
+0x9dffbd: kSpriteFall_Char
+0x9dffc5: SpriteFall_Draw
+0x9e8000: HelmasaurKing_Initialize
+0x9e8019: HelmasaurKing_Reinitialize
+0x9e8039: Sprite_92_HelmasaurKing
+0x9e810a: kHelmasaurKing_Tab1
+0x9e818c: kHelmasaurKing_Xvel0
+0x9e8194: kHelmasaurKing_Yvel0
+0x9e819c: Sprite_HelmasaurKing_DecisionHome
+0x9e81d5: Sprite_HelmasaurKing_WalkToLocation
+0x9e81e6: HelmasaurKing_HandleMovement
+0x9e8200: HelmasaurKing_Func8
+0x9e8210: Sprite_HelmasaurKing_DecisionAway
+0x9e8242: Sprite_HelmasaurKing_WalkBackHome
+0x9e8253: HelmasaurKing_MaybeFireball
+0x9e827c: kHelmasaur_Tab0
+0x9e829c: kMult_8
+0x9e82a0: HelmasaurKing_SwingTail
+0x9e832b: kHelmasaurKing_Tab2
+0x9e8383: kPlus1Minus1
+0x9e8385: HelmasaurKing_CheckMaskDamageFromHammer
+0x9e83eb: HelmasaurKing_AttemptDamage
+0x9e841a: kHelmasaurKing_Mask_Y
+0x9e842e: kHelmasaurKing_Mask_X
+0x9e8442: kHelmasaurKing_Mask_Z
+0x9e844c: kHelmasaurKing_Mask_Xvel
+0x9e8456: kHelmasaurKing_Mask_Yvel
+0x9e8460: kHelmasaurKing_Mask_Zvel
+0x9e846a: kHelmasaurKing_Mask_OamFlags
+0x9e8474: kHelmasaurKing_Mask_Gfx
+0x9e847e: HelmasaurKing_ChipAwayAtMask
+0x9e848c: HelmasaurKing_ExplodeMask
+0x9e84aa: HelmasaurKing_SpawnMaskDebris
+0x9e8517: HelmasaurKing_SpitFireball
+0x9e853b: HelmasaurKing_Draw
+0x9e855f: kHelmasaurKing_DrawB_X
+0x9e8561: kHelmasaurKing_DrawB_Char
+0x9e8569: kHelmasaurKing_DrawB_Flags
+0x9e856b: SpriteDraw_KingHelmasaur_Eyes
+0x9e85c6: kHelmasaurKing_DrawC_Dmd
+0x9e8686: KingHelmasaurMask
+0x9e86e5: KingHelmasaur_CheckBombDamage
+0x9e874d: kHelmasaurKing_DrawD_Dmd
+0x9e87e5: SpriteDraw_KingHelmasaur_Body
+0x9e87f0: Sprite_DrawMultiple___
+0x9e87f5: kHelmasaurKing_DrawE_X
+0x9e87f9: kHelmasaurKing_DrawE_Y
+0x9e87fd: kHelmasaurKing_DrawE_Char
+0x9e8801: kHelmasaurKing_DrawE_Flags
+0x9e8805: SpriteDraw_KingHelmasaur_Legs
+0x9e889c: kHelmasaurKing_DrawF_Y
+0x9e88bc: SpriteDraw_KingHelmasaur_Mouth
+0x9e88f0: kHelmasaurKing_DrawA_Mult
+0x9e8910: kHelmasaurKing_DrawA_MultB
+0x9e8920: KingHelmasaur_OperateTail
+0x9e8a85: NOP8
+0x9e8a8e: Sprite3A_MagicBatLightning
+0x9e8a96: Sprite_MadBatterBolt
+0x9e8abb: kMadderBolt_X
+0x9e8ac3: kMadderBolt_Y
+0x9e8acb: MadBatterBolt_Active
+0x9e8b11: SpriteActive3_MainLong
+0x9e8b19: SpriteActive3_Main
+0x9e8b2e: Sprite_CheckTileCollision__
+0x9e8bbf: Sprite_AA_Pikit
+0x9e8bd8: kFluteBoyAnimal_Xvel
+0x9e8bda: kZazak_Yvel
+0x9e8bde: Pikit_PikNextMovement
+0x9e8c25: Pikit_LandAndAttack
+0x9e8c72: kPikit_Gfx
+0x9e8c8a: kPikit_XyOffs
+0x9e8cd2: kPikit_Tab0
+0x9e8cda: kPikit_Tab1
+0x9e8ce2: Pikit_Steal
+0x9e8dca: Pikit_PrepDraw
+0x9e8dd2: Sprite_A8_GreenZirro
+0x9e8de7: BomberPellet_Falling
+0x9e8e14: BomberPellet_Exploding
+0x9e8e2d: kBomber_Gfx
+0x9e8e31: Bomber_Main
+0x9e8ed2: Zirro_Dodge
+0x9e8ee4: kBomber_Xvel
+0x9e8eec: kBomber_Yvel
+0x9e8ef4: kBomber_Tab0
+0x9e8ef8: Zirro_Idle
+0x9e8f36: Zirro_Move
+0x9e8f71: kBomber_SpawnPellet_X
+0x9e8f79: kBomber_SpawnPellet_Y
+0x9e8f81: Zirro_DropBomb
+0x9e8fdf: Sprite_StalfosBone
+0x9e9000: kStalfosBone_Dmd
+0x9e9040: StalfosBone_Draw
+0x9e905c: kStalfos_Delay
+0x9e9060: kStalfos_AnimState1
+0x9e9068: kStalfos_AnimState2
+0x9e906c: Sprite_A7_Stalfos
+0x9e90b1: kStalfos_CheckDir
+0x9e90b5: Stalfos_Skellington
+0x9e919f: Sprite_Zazak_Main
+0x9e922b: StalfosZazak_Walk
+0x9e9254: kZazak_Dir2
+0x9e925c: StalfosZazak_Wait
+0x9e92bd: Sprite_ZeroVelocity__
+0x9e92d2: StalfosZazak_Shoot
+0x9e92e4: Sprite_SpawnFirePhlegm
+0x9e9363: kSpawnFirePhlegm_Xvel
+0x9e9365: kSpawnFirePhlegm_Yvel
+0x9e9369: kSpawnFirePhlegm_X
+0x9e9371: kSpawnFirePhlegm_Y
+0x9e9379: Stalfos_ThrowBone
+0x9e93c3: kFirePhlegm_Dmd
+0x9e9443: FirePhlegm_Draw
+0x9e9460: Sprite_A3_KholdstareShell
+0x9e94a2: KholdstareShell_ShakeFromDamage
+0x9e94c1: KholdstareShell_PhaseOut
+0x9e94dd: GenerateIceball
+0x9e9518: Sprite_A2_Kholdstare
+0x9e956f: Kholdstare_Accelerate
+0x9e95aa: Kholdstare_check_coll
+0x9e95dd: kKholdstare_Target_Xvel
+0x9e95e1: kKholdstare_Target_Yvel
+0x9e95e5: Kholdstare_Decelerate
+0x9e9646: kKholdstare_Triplicate_Tab0
+0x9e9649: kKholdstare_Triplicate_Tab1
+0x9e964c: Kholdstare_Split
+0x9e9694: Kholdstare_DoAbsolutelyNothing
+0x9e9695: kNebuleGarnish_XY
+0x9e96a5: Kholdstare_SpawnPuffCloudGarnish
+0x9e9710: Sprite_A4_FallingIce
+0x9e9733: Sprite_IceBall
+0x9e97bf: kIceBall_Quadruplicate_Xvel
+0x9e97c7: kIceBall_Quadruplicate_Yvel
+0x9e97cf: IceBall_Split
+0x9e981d: Sprite_A1_Freezor
+0x9e9859: Freezor_Dormant
+0x9e9871: Freezor_Waking
+0x9e98b8: kFreezor_Xvel
+0x9e98ba: kFreezor_Yvel
+0x9e98be: kFreezor_Moving_Gfx
+0x9e98c2: kFreezor_Sparkle_X
+0x9e98ca: kFreezor_Sparkle_Xhi
+0x9e98d2: Freezor_Flailing
+0x9e993e: kFreezor_Melting_Gfx
+0x9e9942: Freezor_ImMelllltiiiinnnnggggg
+0x9e995b: Sprite_9E_HauntedGroveOstritch
+0x9e996c: HauntedGroveOstritch_Idle
+0x9e998d: kFluteBoyOstrich_Gfx
+0x9e9991: HauntedGroveOstritch_Flee
+0x9e99cb: kFluteBoyOstrich_Dmd
+0x9e9a4b: FluteBoyOstrich_Draw
+0x9e9a6b: kFluteBoyAnimal_OamFlags
+0x9e9a6d: Sprite_9F_HauntedGroveRabbit
+0x9e9a8a: HauntedGroveRabbit_Idle
+0x9e9aac: kFluteBoyAnimal_Gfx
+0x9e9aaf: HauntedGroveRabbit_Flee
+0x9e9aec: Sprite_A0_HauntedGroveBird
+0x9e9b2c: HauntedGroveBird_Idle
+0x9e9b61: HauntedGroveBird_Ascending
+0x9e9b84: HauntedGroveBird_Descending
+0x9e9b9a: kFluteBoyBird_X
+0x9e9b9c: HauntedGroveBird_Blink
+0x9e9bc8: Sprite_9C_Zoro
+0x9e9bd0: Zoro
+0x9e9c6b: Babasu
+0x9e9c81: Babasu_Reset
+0x9e9c8f: Babasu_Hidden
+0x9e9c9d: kBabusu_Gfx
+0x9e9ca3: kBabusu_DirGfx
+0x9e9ca7: kBabusu_XyVel
+0x9e9cad: Babasu_Telegraph
+0x9e9ce8: kBabusu_Scurry_Gfx
+0x9e9cec: Babasu_Dart
+0x9e9d1b: Sprite_9B_Wizzrobe
+0x9e9d46: Sprize_Wizzrobe
+0x9e9d7a: kWizzrobe_Cloak_Gfx
+0x9e9d7e: Wizzrobe_Invisible
+0x9e9daa: Wizzrobe_Appear
+0x9e9db8: kWizzrobe_Attack_Gfx
+0x9e9dc0: kWizzrobe_Attack_DirGfx
+0x9e9dc4: Wizzrobe_Attack
+0x9e9df3: Wizzrobe_Disappear
+0x9e9e0f: kWizzrobe_Beam_XYvel
+0x9e9e15: Wizzrobe_FireBeam
+0x9e9e7b: Sprite_9A_Kyameron
+0x9e9ea5: Kyameron_Reset
+0x9e9edb: Kyameron_Puddle
+0x9e9f01: kKyameron_Coagulate_Gfx
+0x9e9f09: kKyameron_Xvel
+0x9e9f0d: kKyameron_Yvel
+0x9e9f11: Kyameron_BuildUp
+0x9e9f55: kKyameron_Moving_Gfx
+0x9e9f59: Kyameron_Moving
+0x9e9fe3: Kyameron_Dissipate
+0x9ea001: Sprite_GarnishSpawn_Sparkle_limited
+0x9ea007: Sprite_GarnishSpawn_Sparkle
+0x9ea06c: kKyameron_Dmd
+0x9ea14c: kKyameron_OamFlags
+0x9ea158: Kyameron_Draw
+0x9ea192: kPengator_Gfx
+0x9ea196: Sprite_99_Pengator
+0x9ea1ea: Pengator_FaceLink
+0x9ea1f5: kPengator_XYVel
+0x9ea1fb: Pengator_Accelerate
+0x9ea240: kPengator_Jump
+0x9ea244: Pengator_Hop
+0x9ea261: kPengator_Garnish_Y
+0x9ea269: kPengator_Garnish_X
+0x9ea271: Pengator_Slide
+0x9ea2b5: kPengator_Dmd0
+0x9ea3f5: kPengator_Dmd1
+0x9ea415: Pengator_Draw
+0x9ea462: Sprite_LaserBeam
+0x9ea488: LaserBeam_BuildUpGarnish
+0x9ea4e7: SpritePrep_LaserEyeLong
+0x9ea4f1: SpritePrep_LaserEye
+0x9ea541: Sprite_95_LaserEyeLeft
+0x9ea55a: kLaserEye_Dirs
+0x9ea55e: LaserEye_Reconnaissance
+0x9ea5b0: kLaserEye_SpawnXY
+0x9ea5bc: kLaserEye_SpawnXYVel
+0x9ea5c2: LaserEye_TangoLocked
+0x9ea5d8: LaserEye_FireBeam
+0x9ea648: kLaserEye_Dmd
+0x9ea708: LaserEye_Draw
+0x9ea73f: Sprite_94_Tile_bounce
+0x9ea742: Sprite_94_Pirogusu
+0x9ea764: kPirogusu_A0
+0x9ea768: Pirogusu_InHole
+0x9ea782: kPirogusu_A1
+0x9ea78a: kPirogusu_XYvel
+0x9ea790: Pirogusu_Crowning
+0x9ea7ce: kPirogusu_A2
+0x9ea7d6: kPirogusu_XYvel2
+0x9ea7dc: Pirogusu_Plop
+0x9ea820: Sprite_FloppingFish_SpawnSplash
+0x9ea84c: kPirogusu_XYvel3
+0x9ea852: Pirogusu_Active
+0x9ea893: kPirogusu_Tab0
+0x9ea897: Pirogusu_SpawnSplash
+0x9ea903: kPirogusu_OamFlags
+0x9ea91f: kPirogusu_Gfx
+0x9ea93b: Pirogusu_Draw
+0x9ea97f: kBumper_Vels
+0x9ea982: Sprite_93_Bumper
+0x9eaa4b: kBumper_Dmd
+0x9eaa8b: Bumper_Draw
+0x9eaaa7: Sprite_91_StalfosKnight
+0x9eaaf4: StalfosKnight_Hidden
+0x9eab27: StalfosKnight_EnterBattle
+0x9eab46: StalfosKnight_SetToGround
+0x9eab5a: kStalfosKnight_Case2_Gfx
+0x9eab5c: StalfosKnight_Idle
+0x9eab96: kStalfosKnight_Case2_Dir
+0x9eaba6: StalfosKnight_ScanForOpponents
+0x9eabd6: StalfosKnight_Squat
+0x9eabf6: StalfosKnight_HopAround
+0x9eac57: kStalfosKnight_Case6_C
+0x9eac77: StalfosKnight_Crumble
+0x9eacd6: kStalfosKnight_Case7_Gfx
+0x9eacd8: StalfosKnight_CelebrateStandingUp
+0x9eacec: kStalfosKnight_Dmd
+0x9eae04: StalfosKnight_Draw
+0x9eae46: kStalfosKnight_DrawHead_Char
+0x9eae4a: kStalfosKnight_DrawHead_Flags
+0x9eae4e: SpriteDraw_StalfosKnight_Head
+0x9eaea4: Sprite_90_Wallmaster
+0x9eaf2b: Wallmaster_Descend
+0x9eaf59: WallMaster_GrabAttempt
+0x9eaf82: Wallmaster_Ascend
+0x9eafa4: kWallMaster_Dmd
+0x9eafe4: WallMaster_Draw
+0x9eb002: Sprite_8F_Blob
+0x9eb055: Blob_Hidden
+0x9eb09f: kZol_PoppingOutGfx
+0x9eb0af: Blob_Peeking
+0x9eb0d4: kZol_FallingGfx
+0x9eb0d6: Blob_Falling
+0x9eb142: kZol_FallingXvel
+0x9eb144: Blob_Active
+0x9eb1c1: kZol_OamFlags
+0x9eb1c5: Zol_Draw
+0x9eb214: kZol_Dmd
+0x9eb254: Zol_DrawMultiple
+0x9eb26f: Sprite_8E_Terrorpin
+0x9eb297: kTerrorpin_Xvel
+0x9eb29f: kTerrorpin_Yvel
+0x9eb2a7: Terrorpin_RightsideUp
+0x9eb30e: Terrorpin_UpsideDown
+0x9eb39f: kTerrorpin_Oamflags
+0x9eb3a1: kTerrorpin_Overturned_Xvel
+0x9eb3a3: Terrorpin_CheckForHammer
+0x9eb405: Terrorpin_SetUpHammerHitBox
+0x9eb42a: kArrghus_Gfx
+0x9eb433: Sprite_8C_Arrghus
+0x9eb4ca: Arrghus_JumpUp
+0x9eb4ef: Arrghus_SmashDown
+0x9eb532: Arrghus_PingPong
+0x9eb593: Arrghus_Move
+0x9eb5c8: Arrghus_MakeDecision
+0x9eb5ee: Arrghus_SetState3
+0x9eb61b: Sprite_ApproachTargetSpeed_0
+0x9eb63d: Arrghus_PuffAttack
+0x9eb674: kArrgi_Tab0
+0x9eb68e: kArrgi_Tab1
+0x9eb6a8: kArrgi_Tab2
+0x9eb6b5: kArrgi_Tab3
+0x9eb6e9: Arrgi_Initialize_
+0x9eb818: kArrghus_Dmd
+0x9eb840: Arrghus_Draw
+0x9eb8b4: Arrghus_HandlePuffs
+0x9eb8bc: kArrgi_Gfx
+0x9eb8c4: Sprite_8D_Arrghi
+0x9eb9a9: Sprite_8B_Gibdo
+0x9eb9c0: kGibdo_DirTarget
+0x9eb9c4: kGibdo_Gfx
+0x9eb9cc: Gibdo_Turn
+0x9eba00: kGibdo_XyVel
+0x9eba0a: kGibdo_Gfx2
+0x9eba12: Gibdo_Walk
+0x9eba60: kGibdo_Dmd
+0x9ebb20: Gibdo_Draw
+0x9ebb42: Sprite_89_MothulaBeam
+0x9ebbb9: Sprite_94_Tile
+0x9ebbdb: FlyingTile_EraseTilemapEntries
+0x9ebc01: FlyingTile_CareenTowardsPlayer
+0x9ebc4f: FlyingTile_RiseUp
+0x9ebc8a: kFlyingTile_Dmd
+0x9ebcca: FlyingTile_Draw
+0x9ebce8: Sprite_8A_SpikeBlock
+0x9ebd23: Sprite_TransientSpikeBlock
+0x9ebd4d: TransientSpikeBlock_Activated
+0x9ebd74: kSpikeBlock_XVelTarget
+0x9ebd76: kSpikeBlock_YVelTarget
+0x9ebd7a: kSpikeBlock_XVelDelta
+0x9ebd7c: kSpikeBlock_YVelDelta
+0x9ebd80: TransientSpikeBlock_InMotion
+0x9ebdc8: kSpikeBlock_XVel
+0x9ebdcc: kSpikeBlock_YVel
+0x9ebdd0: TransientSpikeBlock_Retract
+0x9ebe00: SpikeBlock_UpdateTilemap
+0x9ebe19: SpikeBlock_CheckStatueCollision
+0x9ebe7e: Sprite_88_Mothula
+0x9ebe88: Mothula_Main
+0x9ebed8: Modula_Dormant
+0x9ebee1: Modula_WakeUp
+0x9ebf09: kMothula_XYvel
+0x9ebf13: Modula_ActLikeAMoth
+0x9ebf9b: kMothula_FlapWingsGfx
+0x9ebf9f: Mothula_FlapWings
+0x9ebfb9: Modula_FireBeams
+0x9ebfd9: kMothula_Beam_Xvel
+0x9ebfdc: kMothula_Beam_Yvel
+0x9ebfdf: Mothula_SpawnBeams
+0x9ec02e: kMothula_Spike_XLo
+0x9ec04c: kMothula_Spike_YLo
+0x9ec06a: kMothula_Spike_Dir
+0x9ec088: Mothula_HandleSpikes
+0x9ec103: Sprite_86_Kodongo
+0x9ec120: kKodondo_Xvel
+0x9ec124: kKodondo_Yvel
+0x9ec128: Kodongo_MakeDecision
+0x9ec158: Kodongo_SetDirection
+0x9ec168: kKodondo_Gfx
+0x9ec170: kKodondo_OamFlags
+0x9ec178: Kodongo_Move
+0x9ec1ce: kKodondo_FlameGfx
+0x9ec1d6: Kodongo_ShootFire
+0x9ec205: kKodondo_Flame_X
+0x9ec20d: kKodondo_Flame_Y
+0x9ec215: kKodondo_Flame_Xvel
+0x9ec219: kKodondo_Flame_Yvel
+0x9ec223: Kodongo_SpawnFire
+0x9ec267: Sprite_CheckDamageBoth____
+0x9ec26b: Sprite_CheckDamageToPlayer__
+0x9ec270: kFlame_OamFlags
+0x9ec274: Sprite_87_KodongoFire
+0x9ec2b4: kFlame_Gfx
+0x9ec2d4: Flame_Halted
+0x9ec2fc: kFlame_Dmd
+0x9ec35c: Flame_Draw
+0x9ec379: kYellowStalfos_ObjPrio
+0x9ec37f: Sprite_85_YellowStalfos
+0x9ec3fb: YellowStalfos_Descend
+0x9ec431: YellowStalfos_TrackLink
+0x9ec457: kYellowStalfos_Gfx
+0x9ec477: kYellowStalfos_HeadX
+0x9ec497: kYellowStalfos_HeadY
+0x9ec4b7: YellowStalfos_DecapitateSelf
+0x9ec4f7: kYellowStalfos_Gfx2
+0x9ec4fb: YellowStalfos_RegretDecapitatingSelf
+0x9ec509: YellowStalfos_Animate
+0x9ec515: YellowStalfos_Ascend
+0x9ec53f: kYellowStalfos_NeutralizedGfx
+0x9ec54f: kYellowStalfos_NeutralizedHeadY
+0x9ec55f: YellowStalfos_Collapsed
+0x9ec580: YellowStalfos_EmancipateHead
+0x9ec5a5: kYellowStalfos_Dmd
+0x9ec655: YellowStalfos_Draw
+0x9ec692: kYellowStalfos_Head_Char
+0x9ec696: kYellowStalfos_Head_Flags
+0x9ec69a: YellowStalfos_DrawHead
+0x9ec700: SpritePrep_Eyegore
+0x9ec721: kGoriya_Xvel
+0x9ec741: kGoriya_Yvel
+0x9ec761: kGoriya_Dir
+0x9ec781: kGoriya_Gfx
+0x9ec791: Mimic_Stationary
+0x9ec79b: Sprite_83_GreenEyegore
+0x9ec839: Eyegore_Main
+0x9ec864: kEyeGore_Opening_Delay
+0x9ec868: Eyegore_Dormant
+0x9ec88b: kEyeGore_Opening_Gfx
+0x9ec893: Eyegore_WakingUp
+0x9ec8bb: kEyeGore_Chasing_Gfx
+0x9ec8cb: Eyegore_Chase
+0x9ec92e: kEyeGore_Closing_Gfx
+0x9ec936: Eyegore_GoToSleep
+0x9ec94f: kEyeGore_Dmd
+0x9ecacf: Eyegore_Draw
+0x9ecaf4: kBubbleGroup_X
+0x9ecafa: kBubbleGroup_Y
+0x9ecb00: kBubbleGroup_Xvel
+0x9ecb03: kBubbleGroup_A
+0x9ecb06: kBubbleGroup_Yvel
+0x9ecb09: kBubbleGroup_B
+0x9ecb0c: SpritePrep_AntifairyCircle
+0x9ecb93: kBubbleGroup_Vel
+0x9ecb95: kBubbleGroup_VelTarget
+0x9ecb97: Sprite_82_AntifairyCircle
+0x9ecc02: Sprite_81_Hover
+0x9ecc43: kHover_OamFlags
+0x9ecc47: Hover_Idle
+0x9ecc79: kHover_AccelX0
+0x9ecc7d: kHover_AccelY0
+0x9ecc81: kHover_AccelX1
+0x9ecc85: kHover_AccelY1
+0x9ecc89: Hover_Move
+0x9eccd3: kCrystalMaiden_Pal
+0x9ecce3: CrystalCutscene_Initialize
+0x9ecd48: CrystalCutscene_SpawnMaiden
+0x9ecdd9: CrystalCutscene_InitializePolyhedral
+0x9ece03: Sprite_AB_CrystalMaiden
+0x9ece39: CrystalMaiden_RunCutscene
+0x9ece63: CrystalMaiden_DisableSubscreen
+0x9ece69: CrystalMaiden_EnableSubscreen
+0x9ece71: CrystalMaiden_WaitForCrystalGrowth
+0x9ece93: CrystalMaiden_Emerge
+0x9ecebc: kCrystalMaiden_Msgs
+0x9ecece: CrystalMaiden_GiveSpeech
+0x9ecf18: CrystalMaiden_DoYouUnderstand
+0x9ecf24: CrystalMaiden_GoodLuckKid
+0x9ecf3b: CrystalMaiden_KickOutOfDungeon
+0x9ecf47: Sprite_7D_BigSpike
+0x9ecf86: kSpikeTrap_Xvel
+0x9ecf8a: kSpikeTrap_Xvel2
+0x9ecf8e: kSpikeTrap_Yvel
+0x9ecf92: kSpikeTrap_Yvel2
+0x9ecf96: kSpikeTrap_Delay
+0x9ecf9a: SpikeTrap_InMotion
+0x9ecfdf: kSpikeTrap_Dmd
+0x9ecfff: SpikeTrap_Draw
+0x9ed012: kGuruguruBar_A
+0x9ed016: kGuruguruBar_B
+0x9ed01a: Sprite_7E_Firebar_Clockwise
+0x9ed049: Firebar_Main
+0x9ed1ca: kGuruguruBar_mults
+0x9ed1cd: kWinder_OamFlags
+0x9ed1d1: Sprite_80_Firesnake
+0x9ed1fe: kWinder_Xvel
+0x9ed202: kWinder_Yvel
+0x9ed206: Winder_DefaultState
+0x9ed239: Firesnake_SpawnFireball
+0x9ed28d: kGreenStalfos_Dir
+0x9ed291: kGreenStalfos_OamFlags
+0x9ed295: kGreenStalfos_Gfx
+0x9ed299: Sprite_7C_GreenStalfos
+0x9ed310: kAgahnim_Dir
+0x9ed329: kAgahnim_Gfx1
+0x9ed330: Sprite_7A_Agahnim
+0x9ed36f: kAgahnim_Gfx3
+0x9ed376: Agahnim_SpinToPyramid
+0x9ed3da: Agahnim_ExorciseGanon
+0x9ed408: Agahnim_UncloneSelf
+0x9ed45e: Agahnim_HelloDarkWorld
+0x9ed47a: kAgahnim_Tab5
+0x9ed47c: Agahnim_CreateClones
+0x9ed4a7: kAgahnim_Tab6
+0x9ed4ea: kAgahnim_StartState
+0x9ed4ec: Agahnim_ChooseFirstMove
+0x9ed4f6: Agahnim_HelloLightWorld
+0x9ed514: Agahnim_PrepareToEmerge
+0x9ed51f: kAgahnim_Gfx0
+0x9ed524: Agahnim_EmergeFromShadow
+0x9ed540: kAgahnim_Tab0
+0x9ed550: kAgahnim_Tab1
+0x9ed560: kAgahnim_Tab2
+0x9ed566: Agahnim_Attack
+0x9ed60b: kAgahnim_Gfx2
+0x9ed610: kAgahnim_Tab3
+0x9ed620: kAgahnim_Tab4
+0x9ed630: Agahnim_ChooseWarpSpot
+0x9ed668: kAgahnim_X0
+0x9ed674: kAgahnim_Y0
+0x9ed67a: Agahnim_PerformAttack
+0x9ed708: Agahnim_MoveTowardsWarp
+0x9ed77f: kAgahnim_Draw_X0
+0x9ed7c7: kAgahnim_Draw_Y0
+0x9ed80f: kAgahnim_Draw_Char0
+0x9ed857: kAgahnim_Draw_Flags0
+0x9ed89f: kAgahnim_Draw_X1
+0x9ed8e7: kAgahnim_Draw_Y1
+0x9ed92f: kAgahnim_Draw_Char1
+0x9ed953: kAgahnim_Draw_Ext1
+0x9ed977: UNREACHABLE_1ED971
+0x9ed978: Agahnim_Draw
+0x9eda42: Sprite_7B_AgahnimBalls
+0x9edb44: kEnergyBall_Gfx
+0x9edb54: EnergyBall_DrawTrail
+0x9edb8a: kEnergyBall_SplitXVel
+0x9edb90: kEnergyBall_SplitYVel
+0x9edb96: CreateSixBlueBalls
+0x9edbfe: kEnergyBall_Dmd
+0x9edc3e: SeekerEnergyBall_Draw
+0x9edc5b: Sprite_79_Bee
+0x9edc68: Bee_DormantHive
+0x9edc7b: kSpawnBee_InitVel
+0x9edc83: kSpawnBee_XY
+0x9edc8b: kSpawnBee_InitDelay
+0x9edc8f: SpawnBeeFromHive
+0x9edc9b: InitializeSpawnedBee
+0x9edccf: ReleaseBeeFromBottle
+0x9edd41: kBee_RandomMove
+0x9edd45: Bee_Main
+0x9eddf1: Bee_Captured
+0x9ede2e: Sprite_Find_EmptyBottle
+0x9ede44: Bee_HandleInteractions
+0x9ede63: Sprite_B2_PlayerBee
+0x9ede70: GoldBee_Dormant
+0x9ede90: GoldBee_SpawnSelf
+0x9eded0: kGoodBee_Tab0
+0x9eded2: PlayerBee_Main
+0x9edf8a: Bee_HandleZ
+0x9edfab: PlayerBee_FindTarget
+0x9ee02e: Bee_Bzzt
+0x9ee044: Sprite_B3_PedestalPlaque
+0x9ee09f: HylianPlaque_Desert
+0x9ee0dd: Sprite_B4_PurpleChest
+0x9ee111: Sprite_B5_BombShop
+0x9ee120: kBombShopGuy_Msg
+0x9ee124: kBombShopGuy_Gfx
+0x9ee12c: kBombShopGuy_Delay
+0x9ee134: Sprite_BombShop_Clerk
+0x9ee190: Sprite_BombShop_Bomb
+0x9ee1df: Sprite_BombShop_SuperBomb
+0x9ee216: kSnoutPutt_Dmd
+0x9ee21a: Sprite_BombShop_Huff
+0x9ee256: BombShop_ClerkExhalation
+0x9ee296: kBombShopEntity_Dmd
+0x9ee2c6: BombShopEntity_Draw
+0x9ee2e9: kKiki_Xvel7
+0x9ee2eb: kKiki_Yvel7
+0x9ee2ef: Sprite_B6_Kiki
+0x9ee2fe: Kiki_Flee
+0x9ee3af: Kiki_OfferInitialService
+0x9ee3e8: Kiki_OfferToFollow
+0x9ee3f4: Kiki_OfferToFollowTransaction
+0x9ee433: Kiki_MoveTowardsLink
+0x9ee465: Kiki_WaitABit
+0x9ee476: Kiki_EndIntroductionCutscene
+0x9ee487: Kiki_Dormant
+0x9ee4c9: Kiki_OfferEntranceService
+0x9ee4fd: Kiki_OfferToOpenPOD
+0x9ee509: Kiki_VerifyPurchase
+0x9ee537: kKiki_Zvel
+0x9ee539: Kiki_DartHead
+0x9ee576: kKiki_Leave_Y
+0x9ee57c: kKiki_Leave_X
+0x9ee582: Kiki_HopToSpot
+0x9ee5e9: kKiki_Tab7
+0x9ee5ec: kKiki_Delay7
+0x9ee5ee: Kiki_WalkOnRoof
+0x9ee640: Kiki_ReadyButtonPress
+0x9ee657: Kiki_SlamButton
+0x9ee66b: Kiki_RevertToSprite
+0x9ee67a: Kiki_SpawnHandlerMonke
+0x9ee6c7: Kiki_SpawnHandler_A
+0x9ee6d0: Kiki_SpawnHandler_B
+0x9ee6e9: kKikiDma
+0x9ee6f9: kKiki_Dmd1
+0x9ee7f9: kKiki_Dmd2
+0x9ee859: Kiki_Draw
+0x9ee8b6: Sprite_B7_BlindMaiden
+0x9ee8f1: SpritePrep_OldMan
+0x9ee8f9: SpritePrep_OldMountainMan
+0x9ee938: OldMan_RevertToSprite
+0x9ee989: OldMan_EnableCutscene
+0x9ee992: Sprite_AD_OldMan
+0x9ee9a6: OldMan_Lost
+0x9ee9b1: OldMan_Lost_Wait
+0x9ee9d2: OldMan_Lost_BecomeFollower
+0x9ee9ea: OldMan_Returning
+0x9ee9fc: OldMan_Returning_GiveMirror
+0x9eea28: OldMan_Returning_Move
+0x9eea3f: OldMan_Returning_EnterDoor
+0x9eeaa3: OldMan_Returning_FinishUp
+0x9eeaad: kOldMountainManMsgs
+0x9eeab3: OldMan_Home
+0x9eeae7: Sprite_B8_DialogueTester
+0x9eeb03: DialogueTester_Initialize
+0x9eeb1c: DialogueTester_NextMessage
+0x9eeb33: Sprite_B9_BullyAndPinkBall
+0x9eeb40: Sprite_PinkBall
+0x9eec31: BallGuy_UpsideDown
+0x9eec4d: PinkBall_HandleDeceleration
+0x9eec74: PinkBall_Distress
+0x9eec7c: Sprite_Bully
+0x9eecb2: Bully_ChaseVictim
+0x9eed23: Bully_PuntVictim
+0x9eed55: Bully_Idle
+0x9eed5e: kBully_Dmd
+0x9eed9e: Bully_Draw
+0x9eedc2: BallGuy_PlayBounceNoise
+0x9eedc9: SpawnBully
+0x9eede8: PinkBall_HandleMessage
+0x9eee25: Bully_HandleMessage
+0x9eee56: kWhirlpool_OamFlags
+0x9eee5a: Sprite_BA_Whirlpool
+0x9eeeef: Sprite_BB_Shopkeeper
+0x9eef12: Shopkeeper_StandardClerk
+0x9eef90: ChestGameGuy
+0x9eefbf: ChestGameGuy_OfferGame
+0x9eefd5: ChestGameGuy_HandlePayment
+0x9ef000: ChestGameGuy_ProctorGame
+0x9ef017: NiceThief_Animate
+0x9ef038: NiceThiefWithGift
+0x9ef04f: NiceThiefWithGift_WaitForInteraction
+0x9ef05d: NiceThiefWithGift_GiveRupees
+0x9ef074: ShopKeeper_Type2_Case2
+0x9ef078: MiniChestGameGuy
+0x9ef09c: MiniChestGameGuy_OfferGame
+0x9ef0b2: MiniChestGameGuy_VerifyPurchase
+0x9ef0e1: LesserChestGameGuy_AfterGameStart
+0x9ef0f3: LostWoodsChestGameGuy
+0x9ef10a: LostWoodsChestGameGuy_OfferGame
+0x9ef120: LostWoodsChestGameGuy_VerifyPurchase
+0x9ef14f: NiceThiefUnderRock
+0x9ef16e: ShopItem_RedPotion150
+0x9ef1ad: kShopKeeper_ItemX
+0x9ef1b3: ShopKeeper_SpawnShopItem
+0x9ef1f2: ShopItem_FighterShield
+0x9ef230: ShopItem_FireShield
+0x9ef261: ShopItem_MakeShieldsDeflect
+0x9ef27d: ShopItem_Heart
+0x9ef2af: ShopItem_Arrows
+0x9ef2f0: ShopItem_Bombs
+0x9ef322: ShopItem_Bee
+0x9ef358: kShopKeeper_GiveItemMsgs
+0x9ef366: ShopItem_HandleReceipt
+0x9ef38a: ShopItem_PlayBeep
+0x9ef391: ShopItem_CheckForAPress
+0x9ef39e: ShopItem_HandleCost
+0x9ef3b6: kShopKeeper_ItemWithPrice_Dmd
+0x9ef4ce: SpriteDraw_ShopItem
+0x9ef4f3: Sprite_BehaveAsBarrier
+0x9ef508: Sprite_HaltAllMovement
+0x9ef515: Sprite_AC_Apple
+0x9ef535: SpawnApple
+0x9ef57c: Sprite_Apple
+0x9ef603: Sprite_BC_Drunkard
+0x9ef632: Pipe_LocatePath
+0x9ef640: SomariaPlatform_LocatePath
+0x9ef6a1: Sprite_SomariaPlatformAndPipe
+0x9ef6a9: kSomariaPlatform_Xvel
+0x9ef6b0: kSomariaPlatform_Yvel
+0x9ef6b8: kSomariaPlatform_DragXhi
+0x9ef6bd: kSomariaPlatform_DragX
+0x9ef6c4: kSomariaPlatform_DragY
+0x9ef6cc: kSomariaPlatform_DragYhi
+0x9ef6d4: Sprite_SomariaPlatform
+0x9ef6df: Sprite_SomariaPlatform_Spawn
+0x9ef709: Sprite_SomariaPlatformAndPipe_Main
+0x9ef7af: SomariaPlatformAndPipe_HandleMovement
+0x9ef7c2: SomariaPlatformAndPipe_CheckTile
+0x9ef7e0: kSomariaPlatform_Dmd
+0x9ef860: SomariaPlatform_Draw
+0x9ef87d: SomariaPlatform_HandleJunctions
+0x9ef8ad: SomariaPlatform_HandleDragX
+0x9ef8d7: SomariaPlatform_HandleDragY
+0x9ef901: SomariaPlatform_HandleDrag
+0x9ef908: SomariaPlatform_HandleTile_DoNothing
+0x9ef909: SomariaPlatform_HandleTile_RisingSlope
+0x9ef912: SomariaPlatform_HandleTile_FallingSlope
+0x9ef91b: kSomariaPlatform_TransitDir
+0x9ef91f: SomariaPlatform_HandleTile_TJunctionDLR
+0x9ef942: kSomariaPlatform_Keys1
+0x9ef946: SomariaPlatform_HandleTile_TJunctionULR
+0x9ef99f: kSomariaPlatform_Keys2
+0x9ef9a3: SomariaPlatform_HandleTile_TJunctionUDR
+0x9ef9fe: kSomariaPlatform_Keys3
+0x9efa02: SomariaPlatform_HandleTile_TJunctionUDL
+0x9efa5d: kSomariaPlatform_Keys4
+0x9efa61: SomariaPlatform_HandleTile_4WayJunction
+0x9efabc: kSomariaPlatform_Keys5
+0x9efac0: SomariaPlatform_HandleTile_CrossOver
+0x9efafb: kSomariaPlatform_Keys6
+0x9efaff: SomariaPlatform_HandleTile_Unknown
+0x9efb34: SomariaPlatform_SetOnFlag
+0x9efb3a: SomariaPlatform_HandleTile_Station
+0x9efb49: SomariaPlatform_DragLink
+0x9efb7e: Sprite_AE_Pipe_Down
+0x9efb94: Pipe_FindEndPoint
+0x9efbbe: Pipe_Idle
+0x9efbf0: kPipe_Dirs
+0x9efbf4: Pipe_DragLink
+0x9efc13: Pipe_MoveLink
+0x9efcd3: Pipe_Reset
+0x9efcff: Pipe_HandlePlayerMovement
+0x9efd14: Fairy_HandleMovement
+0x9efd1c: Faerie_HandleMovement
+0x9efe33: ReleaseFairy
+0x9efe69: Sprite_DirectionToFacePlayer____
+0x9efe6e: Sprite_IsToRightOfPlayer____
+0x9efe73: Sprite_IsBelowPlayer_____
+0x9efe78: Sprite_ReturnIfInactive__
+0x9efe7f: Sprite_ReturnIfPaused__
+0x9efe9b: Sprite_ReturnIfRecoiling____
+0x9eff1e: Sprite_MoveXyz__
+0x9eff21: Sprite_Move__
+0x9eff28: Sprite_MoveX___
+0x9eff34: Sprite_MoveY_9E
+0x9eff62: Sprite_MoveZ___
+0x9eff84: Sprite_PrepOamCoordOrDoubleRet____
+0x9eff8d: Sprite_DrawRippleIfInWater
+0x9f8000: kDungObjectDataForRoom
+0x9f83c0: kDungDoorPtrs
+0x9fb97b: aB
--- /dev/null
+++ b/other/replace_in_files.py
@@ -1,0 +1,28 @@
+import os, re, sys, glob
+
+repl = open(sys.argv[1],'r').read().splitlines()
+repl = [a.split(' ') for a in repl]
+repl_dict = dict(repl)
+
+c = re.compile('\\b(' + "|".join(a[0] for a in repl) + ')\\b')
+
+def replacer(m):
+ return repl_dict[m.group(0)]
+
+def replace_in_file(fname):
+ s = open(fname, 'r').read()
+ s_org = s
+
+ s, num = c.subn(replacer, s)
+ print(num)
+ if num:
+ assert s != s_org
+ open(fname, 'w').write(s)
+
+
+
+for filename in glob.glob('*.cpp') + glob.glob('*.h'):
+ replace_in_file(filename)
+
+
+
--- /dev/null
+++ b/other_modules.cpp
@@ -1,0 +1,92 @@
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "dungeon.h"
+#include "ancilla.h"
+#include "load_gfx.h"
+#include "hud.h"
+#include "sprite.h"
+#include "messaging.h"
+#include "player_oam.h"
+#include "sprite_main.h"
+
+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();
+}
+
--- /dev/null
+++ b/other_modules.h
@@ -1,0 +1,4 @@
+#pragma once
+#include "types.h"
+
+void Module18_GanonEmerges();
--- /dev/null
+++ b/overlord.cpp
@@ -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/overlord.h
@@ -1,0 +1,37 @@
+#pragma once
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "snes_regs.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/overworld.cpp
@@ -1,0 +1,4082 @@
+#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 "tables/generated_map32_to_map16.h"
+#include "tables/generated_map16_to_map8.h"
+#include "tables/generated_overworld_tables.h"
+#include "tables/generated_overworld.h"
+#include "tables/generated_enemy_damage_data.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 (g_ram[0xc8])
+#define ganonentrance_ctr (g_ram[0xc8])
+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_LoadAmbientOverlay,
+ &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 = savegame_tagalong;
+ 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 < 32 * 7; i++)
+ mode7_hdma_table[i] = v;
+ HDMAEN_copy = 0xc0;
+}
+
+void MirrorWarp_BuildWavingHDMATable() { // 80fe64
+ MirrorWarp_RunAnimationSubmodules();
+ if (frame_counter & 1)
+ return;
+
+ int x = 0x1a0 / 2, y = 0x1b0 / 2;
+ do {
+ mode7_hdma_table[y] = mode7_hdma_table[y + 2] = mode7_hdma_table[y + 4] = mode7_hdma_table[y + 6] = mode7_hdma_table[x];
+ x -= 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;
+ }
+ mode7_hdma_table[0] = mode7_hdma_table[2] = mode7_hdma_table[4] = mode7_hdma_table[6] = t + BG2HOFS_copy2;
+}
+
+void MirrorWarp_BuildDewavingHDMATable() { // 80ff2f
+ MirrorWarp_RunAnimationSubmodules();
+ if (frame_counter & 1)
+ return;
+ int x = 0x1a0 / 2, y = 0x1b0 / 2;
+ do {
+ mode7_hdma_table[y] = mode7_hdma_table[y + 2] = mode7_hdma_table[y + 4] = mode7_hdma_table[y + 6] = mode7_hdma_table[x];
+ x -= 8, y -= 8;
+ } while (y != 0);
+
+ uint16 t = mode7_hdma_table[0xc0] | mode7_hdma_table[0xc8] | mode7_hdma_table[0xd0] | mode7_hdma_table[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 (buffer_for_playing_songs == 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:
+ buffer_for_playing_songs = 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 (savegame_tagalong == 6)
+ savegame_tagalong = 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;
+}
+
+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 = GetEntranceMusicTrack(which_entrance);
+ if (m != 3 || (m = sram_progress_indicator) >= 2) {
+ if (m != 0xf2)
+ m = 0xf1;
+ else if (music_unk1 == 0xc)
+ 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 (filtered_joypad_L & 0x40) {
+ overworld_map_state = 0;
+ submodule_index = 7;
+ saved_module_for_menu = main_module_index;
+ main_module_index = 14;
+ return;
+ }
+ if (joypad1H_last & 0x20) {
+ choice_in_multiselect_box_bak = choice_in_multiselect_box;
+ dialogue_message_index = 0x186;
+ int 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;
+ return;
+ }
+ }
+ 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];
+ uint16 pushed = current_area_of_player + kSwitchAreaTab3[y];
+ map16_load_src_off += kSwitchAreaTab1[(y * 128 | pushed) >> 1];
+
+ uint8 old_screen = overworld_screen_index;
+ if (old_screen == 0x2a)
+ sound_effect_ambient = 0x80;
+
+ uint8 new_area = kOverworldAreaHeads[pushed >> 1] | 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 ((music & 0xf) != music_unk1)
+ 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 ((overworld_music[BYTE(overworld_screen_index)] & 0xf) != music_unk1)
+ 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 ((m & 0xf) != music_unk1)
+ 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_SpritePal0Left();
+ 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;
+ ((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;
+ ((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, countof(kWhirlpoolAreas));
+ 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_LoadAmbientOverlay() { // 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.t3.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.t3.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.t3.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.t3.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.t3.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.t3.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);
+}
+
+void Overworld_DecompressAndDrawOneQuadrant(uint16 *dst, int screen) { // 82f595
+ int rv;
+ rv = Decompress_bank02(&g_ram[0x14400], kOverworld_Hibytes_Comp[screen]);
+ for (int i = 0; i < 256; i++)
+ g_ram[0x14001 + i * 2] = g_ram[0x14400 + i];
+
+ rv = Decompress_bank02(&g_ram[0x14400], kOverworld_Lobytes_Comp[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, sizeof(kEnemyDamageData));
+ 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;
+ i = 38 / 2;
+ break;
+ }
+ }
+ 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 (!super_bomb_going_off && (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;
+check_secret:
+ uint32 result;
+ 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 (savegame_tagalong == 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 && savegame_tagalong != 13)
+ goto fail;
+ 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/overworld.h
@@ -1,0 +1,179 @@
+#pragma once
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "snes_regs.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_LoadAmbientOverlay();
+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/player.cpp
@@ -1,0 +1,6489 @@
+#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 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 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
+ 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 != 17) {
+ Link_HandleYItem();
+ if (sram_progress_indicator != 0) {
+ Link_HandleSwordCooldown();
+ if (link_player_handler_state == 3) {
+ link_x_vel = link_y_vel = 0;
+ goto getout_dostuff;
+ }
+ }
+ }
+ }
+
+ 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 & 0xf)) == 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)
+ link_y_vel = link_x_vel = 0;
+
+getout_dostuff:
+ fallhole_var1 = 0;
+ 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 & 0xf)) {
+ 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 & 0xf)) {
+ 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 & 0xf;
+ 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;
+ if (t == 0)
+ link_recoilmode_timer = 3;
+ } 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;
+ }
+ LinkHop_FindArbitraryLandingSpot(); // 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 = 1;
+ 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;
+ LinkHop_FindArbitraryLandingSpot();
+ 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();
+ 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;
+ LinkHop_FindArbitraryLandingSpot();
+ 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);
+ LinkHop_FindArbitraryLandingSpot();
+ 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 };
+
+ int8 velx = kLedgeVelX[(uint16)(link_y_coord - link_y_coord_original) >> 3];
+ 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 (savegame_tagalong == kTagalongArr1[savegame_tagalong])
+ savegame_tagalong = kTagalongArr2[savegame_tagalong];
+ } else {
+ index_of_dashing_sfx = 0;
+ if (!(joypad1L_last & 0x80)) {
+ 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 & 0xf) == 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;
+ if ((joypad1H_last & 0xf) && (joypad1H_last & 0xf) != kDashTab2[link_direction_facing >> 1]) {
+ link_player_handler_state = kPlayerState_StopDash;
+ button_mask_b_y &= ~0x80;
+ button_b_frames = 0;
+ link_delay_timer_spin_attack = 0;
+ LinkState_ExitingDash();
+ return;
+ }
+ 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 & 0xf || 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 (link_countdown_for_dash) {
+ LinkState_Dashing();
+ return;
+ }
+ if (joypad1H_last & 0xf && !(joypad1H_last & 0xf & link_direction)) {
+ Link_CancelDash();
+aux_state:
+ if (link_auxiliary_state != 1)
+ link_direction = joypad1H_last & 0xF;
+ }
+ }
+ TileDetect_MainHandler(4);
+ if (!(tiledetect_pit_tile & 1)) {
+ 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;
+ }
+ 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 (savegame_tagalong != 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;
+ }
+ 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 (savegame_tagalong != 0 && savegame_tagalong != 3) {
+ tagalong_var5 = 0;
+ if (savegame_tagalong == 13) {
+ savegame_tagalong = 0;
+ super_bomb_indicator_unk2 = 0;
+ super_bomb_indicator_unk1 = 0;
+ super_bomb_going_off = 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 & 0x80) | 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 & 0xf)) {
+ 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 & 0xf;
+ 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;
+
+ if (link_is_bunny_mirror && (eq_selected_y_item != 11 && eq_selected_y_item != 20))
+ return;
+
+ if (byte_7E03FC && !link_is_bunny_mirror) {
+ if (byte_7E03FC == 2)
+ LinkItem_Bow();
+ else
+ LinkItem_Shovel();
+ return;
+ }
+
+ if (eq_selected_y_item != eq_selected_y_item_copy) {
+ if (eq_selected_y_item_copy == 8 && (link_item_flute & 2))
+ button_mask_b_y &= ~0x40;
+ if (eq_selected_y_item_copy == 19 && link_cape_mode)
+ Link_ForceUnequipCape();
+ }
+
+ if ((link_item_in_hand | link_position_mode) == 0)
+ eq_selected_y_item_copy = eq_selected_y_item;
+
+ if (eq_selected_y_item_copy == 5 || eq_selected_y_item_copy == 6)
+ eq_selected_rod = eq_selected_y_item_copy - 5 + 1;
+
+ switch (eq_selected_y_item_copy) {
+ 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;
+ default:
+ assert(0);
+ }
+}
+
+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;
+ }
+attempt_action:
+ static const uint8 kAbilityBitmasks[] = { 0xE0, 0x40, 4, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0 };
+ 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(); return;
+ case 1: Link_PerformThrow(); return;
+ case 2: Link_PerformDash(); return;
+ case 3: Link_PerformGrab(); return;
+ case 4: Link_PerformRead(); return;
+ case 5: Link_PerformOpenChest(); return;
+ case 6: Link_PerformStatueDrag(); return;
+ case 7: Link_PerformRupeePull(); return;
+ 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 & 0x80))
+ 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 & 0x80)) {
+ button_mask_b_y &= ~1;
+ HandleSwordSfxAndBeam();
+ return;
+ }
+ }
+ CalculateSwordHitBox();
+}
+
+void HandleSwordControls() { // 879d72
+ if (joypad1H_last & 0x80) {
+ 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 & 0x40))
+ 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 & 0xf;
+ } 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 || savegame_tagalong == 13 || !CheckYButtonPress())
+ return;
+ button_mask_b_y &= ~0x40;
+ AncillaAdd_Bomb(7, 1);
+ link_item_in_hand = 0;
+}
+
+void LinkItem_Bottle() { // 87a15b
+ if (!CheckYButtonPress())
+ return;
+ button_mask_b_y &= ~0x40;
+ int btidx = link_item_bottles - 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) { // bee
+ if (!ReleaseBeeFromBottle())
+ 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 (byte_7E03FC)
+ 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) ||
+ super_bomb_going_off && savegame_tagalong == 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;
+ }
+ link_delay_timer_spin_attack = kEtherAnimDelays[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) ||
+ super_bomb_going_off && savegame_tagalong == 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) ||
+ super_bomb_going_off && savegame_tagalong == 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);
+ LinkHop_FindArbitraryLandingSpot();
+ 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_x_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 & 0x80) : 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 (savegame_tagalong == 10) {
+ dialogue_message_index = 289;
+ Main_ShowTextMessage();
+ return;
+ }
+ }
+ button_mask_b_y &= ~0x40;
+
+ if (is_standing_in_doorway || !cheatWalkThroughWalls && !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 (savegame_tagalong == 12 || savegame_tagalong == 13) {
+ if (savegame_tagalong == 13) {
+ super_bomb_indicator_unk2 = 0xfe;
+ super_bomb_indicator_unk1 = 0;
+ }
+ if (super_bomb_going_off) {
+ super_bomb_going_off = 0;
+ savegame_tagalong = 0;
+ }
+ } else if (savegame_tagalong == 9 || savegame_tagalong == 10) {
+ savegame_tagalong = 0;
+ } else if (savegame_tagalong == 7 || savegame_tagalong == 8) {
+ savegame_tagalong ^= (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:
+ LinkHop_FindArbitraryLandingSpot();
+ 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];
+ if (!--link_magic_power) {
+ Link_ForceUnequipCape();
+ return;
+ }
+ }
+ if (sign8(--link_bunny_transform_timer)) {
+ link_bunny_transform_timer = 0;
+ if (filtered_joypad_H & 0x40)
+ 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
+ if (link_state_bits & 0x80)
+ Player_CheckHandleCapeStuff();
+}
+
+void Player_CheckHandleCapeStuff() { // 87ae8f
+ if (link_cape_mode && eq_selected_y_item_copy == 19) {
+ if (eq_selected_y_item_copy == eq_selected_y_item) {
+ 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;
+ while (ancilla_type[i] != 0x2c) {
+ if (--i < 0) {
+ if (!LinkCheckMagicCost(4))
+ return;
+ break;
+ }
+ }
+ link_debug_value_2 = 1;
+ AncillaAdd_SomariaBlock(44, 1);
+ 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;
+ button_mask_b_y &= ~0x40;
+ link_position_mode &= ~8;
+}
+
+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 & 0x40))
+ 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];
+ link_magic_power += cost;
+}
+
+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 &= ~0x80;
+ 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[] = { 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 &= ~0x80;
+ }
+ return;
+ }
+ } else {
+
+ // todo: This is an OOB read triggered when lifting for too long
+ 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 (savegame_tagalong == kTagalongArr1[savegame_tagalong]) {
+ 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;
+
+ uint8 x;
+
+ 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 & 0x80)) {
+ 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 & 0x80)) {
+ 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 & 0x80)) {
+ 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 & 4))
+ 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 & 0xf))
+ 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:
+ LinkHop_FindArbitraryLandingSpot();
+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 & 0x80))
+ return false;
+ bitfield_for_a_button |= 0x80;
+ return true;
+}
+
+bool Link_HandleToss() { // 87b5d6
+ if (!(bitfield_for_a_button & 0x80) || !(filtered_joypad_L & 0x80) || (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 = 1;
+ 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;
+ byte_7E03F3 = 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) {
+ byte_7E03F3 = 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) {
+ byte_7E03F3 = tiledetect_var4 & 0x20 ? 2 : 1;
+ } else if (tiledetect_var4 & 0x2200) {
+ byte_7E03F3 = tiledetect_var4 & 0x2000 ? 4 : 3;
+ } else {
+ if (!(bitfield_spike_cactus_tiles & 7) && !(R14 & 2))
+ byte_7E03F3 = 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();
+ }
+ 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 = 1;
+ 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 = 1;
+ }
+ 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;
+ byte_7E03F3 = 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) {
+ byte_7E03F3 = 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) {
+ byte_7E03F3 = tiledetect_var4 & 0x20 ? 2 : 1;
+ } else if (tiledetect_var4 & 0x2200) {
+ byte_7E03F3 = tiledetect_var4 & 0x2000 ? 4 : 3;
+ } else {
+ if (!(bitfield_spike_cactus_tiles & 7) && !(R14 & 2))
+ byte_7E03F3 = 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 = 1;
+ 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 = 1;
+ }
+ 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 ((R14 & 2) == 0 && (R12 & 5) != 0 && (!link_is_running || (link_direction_facing & 4))) {
+ 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[] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3 };
+ static const int8 y1[] = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 3 };
+ 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 (!(tiledetect_diag_state & 2)) {
+ ym = 8 - ym;
+ } else {
+ ym += 8;
+ }
+ 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) {
+ o ^= 7;
+ xm = -xm;
+ } else {
+ xm -= 8;
+ xm = -xm;
+ xm = kAvoidJudder1[o] - 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;
+ LinkHop_FindArbitraryLandingSpot();
+}
+
+void LinkHop_FindArbitraryLandingSpot() { // 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 (!byte_7E03F3)
+ 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 = byte_7E03F3 - 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 & 0xf)) {
+ 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 };
+
+ if (link_player_handler_state == 23) { // kPlayerState_PermaBunny
+ 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;
+
+ 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
+ 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) {
+ oam->x = x;
+ oam->y = y;
+ oam->charnum = ch;
+ oam->flags = 0x20;
+ bytewise_extended_oam[oam - oam_buf] = 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;
+}
+
+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;
+ byte_7E03FC = 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
+ 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 & 0xf)) {
+ 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 & 0xf) == ancilla_arr3[k]) {
+ if (link_speed_setting == 18)
+ bitmask_of_dragstate |= 0x81;
+ } else {
+ ancilla_arr3[k] = (joypad1H_last & 0xf);
+ 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 & 15;
+ 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;
+ byte_7E03F3 = 0;
+ byte_7E0322 = 0;
+ flag_is_link_immobilized = 0;
+ overworld_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/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 LinkHop_FindArbitraryLandingSpot();
+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/player_oam.cpp
@@ -1,0 +1,1278 @@
+#include "player_oam.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "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,
+};
+struct LinkSpriteBody {
+ int8 y, x;
+ uint8 tile;
+};
+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 scratch_1_var = dir * 14;
+
+ int r2 = kPlayerOamOtherOffs[dir * 40 + yt] + rt;
+ int r4loc = kPlayerOamSpriteLocs[r2];
+
+ link_palette_bits_of_oam = overworld_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) && eq_selected_y_item == 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 skip_erase = true;
+ if (is_standing_in_doorway && ((t = link_x_coord - BG2HOFS_copy2) < 4 || t >= 252 || (t = link_y_coord - BG2VOFS_copy2) < 4 || t >= 224) ||
+ (skip_erase = false,
+ submodule_index == 0 && countdown_for_blink && --countdown_for_blink >= 4 && (countdown_for_blink & 1) == 0 ||
+ link_visibility_status == 12 ||
+ link_cape_mode != 0)) {
+ 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;
+ if (link_visibility_status != 12 && !skip_erase) {
+ int oam_pos = ((scratch_0_var ? kShadow_oam_indexes_1 : kShadow_oam_indexes_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
+ WORD(bytewise_extended_oam[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 animst = secondary_water_grass_timer;
+
+ 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/player_oam.h
@@ -1,0 +1,19 @@
+#pragma once
+#include "types.h"
+
+struct SwordResult {
+ uint8 r6;
+ uint8 r12;
+};
+
+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/poly.cpp
@@ -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,
+};
+struct Vertex3 {
+ int8 x, y, z;
+};
+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,
+};
+struct PolyConfig {
+ uint8 num_vtx, num_poly;
+ uint16 vtx_val, polys_val;
+ const Vertex3 *vertex;
+ const uint8 *poly;
+};
+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/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();
binary files /dev/null b/saves/ref/Chapter 1 - Zelda's Rescue.sav differ
binary files /dev/null b/saves/ref/Chapter 10 - After Ice Palace.sav differ
binary files /dev/null b/saves/ref/Chapter 11 - After Misery Mire.sav differ
binary files /dev/null b/saves/ref/Chapter 12 - After Turtle Rock.sav differ
binary files /dev/null b/saves/ref/Chapter 13 - After Ganon's Tower.sav differ
binary files /dev/null b/saves/ref/Chapter 2 - After Eastern Palace.sav differ
binary files /dev/null b/saves/ref/Chapter 3 - After Desert Palace.sav differ
binary files /dev/null b/saves/ref/Chapter 4 - After Tower of Hera.sav differ
binary files /dev/null b/saves/ref/Chapter 5 - After Hyrule Castle Tower.sav differ
binary files /dev/null b/saves/ref/Chapter 6 - After Dark Palace.sav differ
binary files /dev/null b/saves/ref/Chapter 7 - After Swamp Palace.sav differ
binary files /dev/null b/saves/ref/Chapter 8 - After Skull Woods.sav differ
binary files /dev/null b/saves/ref/Chapter 9 - After Gargoyle's Domain.sav differ
--- /dev/null
+++ b/select_file.cpp
@@ -1,0 +1,970 @@
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "load_gfx.h"
+#include "select_file.h"
+#include "snes_regs.h"
+#include "variables_attract.h"
+#include "overworld.h"
+#include "messaging.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];
+
+ oam[0].x = oam[1].x = x + 0xc;
+ oam[0].y = y - 5;
+ oam[1].y = y + 3;
+ oam[0].flags = oam[1].flags = kSelectFile_Draw_Flags[k];
+ uint8 sword = sram[kSrmOffs_Sword] - 1;
+ if (sign8(sword))
+ oam[1].y = oam[0].y = 0xf0, sword = 0;
+ oam[0].charnum = kSelectFile_Draw_SwordChar[sword];
+ oam[1].charnum = oam[0].charnum + 16;
+ bytewise_extended_oam[oam - oam_buf] = bytewise_extended_oam[oam - oam_buf + 1] = 0;
+
+ oam += 2;
+ oam[0].x = x - 5;
+ oam[0].y = y + 10;
+ uint8 shield = sram[kSrmOffs_Shield] - 1;
+ if (sign8(shield))
+ oam[0].y = 0xf0, shield = 0;
+ oam[0].charnum = kSelectFile_Draw_ShieldChar[shield];
+ oam[0].flags = kSelectFile_Draw_Flags2[k];
+ bytewise_extended_oam[oam - oam_buf] = 2;
+ oam++;
+
+ oam[0].x = oam[1].x = x;
+ oam[0].y = y;
+ oam[1].y = y + 8;
+ oam[0].charnum = 0;
+ oam[1].charnum = 2;
+ oam[0].flags = kSelectFile_Draw_Flags3[k];
+ oam[1].flags = oam[0].flags | 0x40;
+ bytewise_extended_oam[oam - oam_buf] = bytewise_extended_oam[oam - oam_buf + 1] = 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 {
+ oam->charnum = kSelectFile_DrawDigit_Char[digits[i]];
+ oam->x = x + kSelectFile_DrawDigit_X[i];
+ oam->y = y + 0x10;
+ oam->flags = 0x3c;
+ bytewise_extended_oam[oam - oam_buf] = 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);
+ }
+ 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
+ zelda_ppu_write(OBSEL, 2);
+ zelda_ppu_write(VMAIN, 0x80);
+ zelda_ppu_write_word(VMADDL, 0x5000);
+
+ Decomp_spr(&g_ram[0x14000], 0x5e);
+ Do3To4High(&g_ram[0x14000]);
+
+ Decomp_spr(&g_ram[0x14000], 0x5f);
+ Do3To4High(&g_ram[0x14000]);
+
+ zelda_ppu_write_word(VMADDL, 0x7000);
+
+ const uint16 *src = GetFontPtr();
+ for (int i = 0; i < 0x800; i++)
+ zelda_ppu_write_word(VMDATAL, *src++);
+
+ Decomp_spr(&g_ram[0x14000], 0x6b);
+ src = (const uint16 *)&g_ram[0x14000];
+ for (int i = 0; i < 0x300; i++)
+ zelda_ppu_write_word(VMDATAL, *src++);
+}
+
+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;
+ dung_hdr_palette_1 = 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};
+
+ 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) {
+ 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]) {
+ 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;
+ }
+ 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
+ oam_buf[0].x = x;
+ oam_buf[0].y = y;
+ oam_buf[0].charnum = frame_counter & 8 ? 0xaa : 0xa8;
+ oam_buf[0].flags = 0x7e;
+ bytewise_extended_oam[0] = 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;
+ attract_legend_ctr = selectfile_R16 * 0x500;
+ memset(g_zenv.sram + attract_legend_ctr, 0, 0x500);
+ uint16 *name = (uint16 *)(g_zenv.sram + attract_legend_ctr + 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++) {
+ oam->x = 0x18 + i * 8;
+ oam->y = selectfile_var7;
+ oam->charnum = 0x2e;
+ oam->flags = 0x3c;
+ bytewise_extended_oam[oam - oam_buf] = 0;
+ oam++;
+ }
+
+ oam->x = kNamePlayer_X[selectfile_var4];
+ oam->y = 0x58;
+ oam->charnum = 0x29;
+ oam->flags = 0xc;
+ bytewise_extended_oam[oam - oam_buf] = 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);
+ 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/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/snes/apu.cpp
@@ -1,0 +1,186 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include "apu.h"
+#include "snes.h"
+#include "spc.h"
+#include "dsp.h"
+
+static const uint8_t bootRom[0x40] = {
+ 0xcd, 0xef, 0xbd, 0xe8, 0x00, 0xc6, 0x1d, 0xd0, 0xfc, 0x8f, 0xaa, 0xf4, 0x8f, 0xbb, 0xf5, 0x78,
+ 0xcc, 0xf4, 0xd0, 0xfb, 0x2f, 0x19, 0xeb, 0xf4, 0xd0, 0xfc, 0x7e, 0xf4, 0xd0, 0x0b, 0xe4, 0xf5,
+ 0xcb, 0xf4, 0xd7, 0x00, 0xfc, 0xd0, 0xf3, 0xab, 0x01, 0x10, 0xef, 0x7e, 0xf4, 0x10, 0xeb, 0xba,
+ 0xf6, 0xda, 0x00, 0xba, 0xf4, 0xc4, 0xf4, 0xdd, 0x5d, 0xd0, 0xdb, 0x1f, 0x00, 0x00, 0xc0, 0xff
+};
+
+Apu* apu_init() {
+ Apu* apu = (Apu * )malloc(sizeof(Apu));
+ apu->spc = spc_init(apu);
+ apu->dsp = dsp_init(apu->ram);
+ return apu;
+}
+
+void apu_free(Apu* apu) {
+ spc_free(apu->spc);
+ dsp_free(apu->dsp);
+ free(apu);
+}
+
+void apu_saveload(Apu *apu, SaveLoadFunc *func, void *ctx) {
+ size_t size = sizeof(struct Apu2);
+ size_t size2 = offsetof(Apu, hist);
+ func(ctx, apu->ram, offsetof(Apu, hist) - offsetof(Apu, ram));
+ dsp_saveload(apu->dsp, func, ctx);
+ spc_saveload(apu->spc, func, ctx);
+}
+
+void apu_reset(Apu* apu) {
+ apu->romReadable = true; // before resetting spc, because it reads reset vector from it
+ spc_reset(apu->spc);
+ dsp_reset(apu->dsp);
+ memset(apu->ram, 0, sizeof(apu->ram));
+ apu->dspAdr = 0;
+ apu->cycles = 0;
+ memset(apu->inPorts, 0, sizeof(apu->inPorts));
+ memset(apu->outPorts, 0, sizeof(apu->outPorts));
+ for(int i = 0; i < 3; i++) {
+ apu->timer[i].cycles = 0;
+ apu->timer[i].divider = 0;
+ apu->timer[i].target = 0;
+ apu->timer[i].counter = 0;
+ apu->timer[i].enabled = false;
+ }
+ apu->cpuCyclesLeft = 7;
+ apu->hist.count = 0;
+}
+
+void apu_cycle(Apu* apu) {
+ if(apu->cpuCyclesLeft == 0) {
+ apu->cpuCyclesLeft = spc_runOpcode(apu->spc);
+ }
+ apu->cpuCyclesLeft--;
+
+ if((apu->cycles & 0x1f) == 0) {
+ // every 32 cycles
+ dsp_cycle(apu->dsp);
+ }
+
+ // handle timers
+ for(int i = 0; i < 3; i++) {
+ if(apu->timer[i].cycles == 0) {
+ apu->timer[i].cycles = i == 2 ? 16 : 128;
+ if(apu->timer[i].enabled) {
+ apu->timer[i].divider++;
+ if(apu->timer[i].divider == apu->timer[i].target) {
+ apu->timer[i].divider = 0;
+ apu->timer[i].counter++;
+ apu->timer[i].counter &= 0xf;
+ }
+ }
+ }
+ apu->timer[i].cycles--;
+ }
+
+ apu->cycles++;
+}
+
+uint8_t apu_cpuRead(Apu* apu, uint16_t adr) {
+ switch(adr) {
+ case 0xf0:
+ case 0xf1:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc: {
+ return 0;
+ }
+ case 0xf2: {
+ return apu->dspAdr;
+ }
+ case 0xf3: {
+ return dsp_read(apu->dsp, apu->dspAdr & 0x7f);
+ }
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7:
+ case 0xf8:
+ case 0xf9: {
+ return apu->inPorts[adr - 0xf4];
+ }
+ case 0xfd:
+ case 0xfe:
+ case 0xff: {
+ uint8_t ret = apu->timer[adr - 0xfd].counter;
+ apu->timer[adr - 0xfd].counter = 0;
+ return ret;
+ }
+ }
+ if(apu->romReadable && adr >= 0xffc0) {
+ return bootRom[adr - 0xffc0];
+ }
+ return apu->ram[adr];
+}
+
+void apu_cpuWrite(Apu* apu, uint16_t adr, uint8_t val) {
+ switch(adr) {
+ case 0xf0: {
+ break; // test register
+ }
+ case 0xf1: {
+ for(int i = 0; i < 3; i++) {
+ if(!apu->timer[i].enabled && (val & (1 << i))) {
+ apu->timer[i].divider = 0;
+ apu->timer[i].counter = 0;
+ }
+ apu->timer[i].enabled = val & (1 << i);
+ }
+ if(val & 0x10) {
+ apu->inPorts[0] = 0;
+ apu->inPorts[1] = 0;
+ }
+ if(val & 0x20) {
+ apu->inPorts[2] = 0;
+ apu->inPorts[3] = 0;
+ }
+ apu->romReadable = val & 0x80;
+ break;
+ }
+ case 0xf2: {
+ apu->dspAdr = val;
+ break;
+ }
+ case 0xf3: {
+ int i = apu->hist.count;
+ if (i != 256) {
+ apu->hist.count = i + 1;
+ apu->hist.addr[i] = (DspReg)apu->dspAdr;
+ apu->hist.val[i] = val;
+ }
+ if(apu->dspAdr < 0x80) dsp_write(apu->dsp, apu->dspAdr, val);
+ break;
+ }
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7: {
+ apu->outPorts[adr - 0xf4] = val;
+ break;
+ }
+ case 0xf8:
+ case 0xf9: {
+ apu->inPorts[adr - 0xf4] = val;
+ break;
+ }
+ case 0xfa:
+ case 0xfb:
+ case 0xfc: {
+ apu->timer[adr - 0xfa].target = val;
+ break;
+ }
+ }
+ apu->ram[adr] = val;
+}
--- /dev/null
+++ b/snes/apu.h
@@ -1,0 +1,64 @@
+
+#ifndef APU_H
+#define APU_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct Apu Apu;
+
+#include "spc.h"
+#include "dsp.h"
+
+typedef struct Timer {
+ uint8_t cycles;
+ uint8_t divider;
+ uint8_t target;
+ uint8_t counter;
+ bool enabled;
+} Timer;
+
+
+struct Apu {
+ Spc* spc;
+ Dsp* dsp;
+ uint8_t ram[0x10000];
+ bool romReadable;
+ uint8_t dspAdr;
+ uint32_t cycles;
+ uint8_t inPorts[6]; // includes 2 bytes of ram
+ uint8_t outPorts[4];
+ Timer timer[3];
+ uint8_t cpuCyclesLeft;
+ union {
+ DspRegWriteHistory hist;
+ void *padpad;
+ };
+};
+
+struct Apu2 {
+ // Snes* snes;
+ Spc* spc;
+ Dsp* dsp;
+ uint8_t ram[0x10000];
+ bool romReadable;
+ uint8_t dspAdr;
+ uint32_t cycles;
+ uint8_t inPorts[6]; // includes 2 bytes of ram
+ uint8_t outPorts[4];
+ Timer timer[3];
+ uint8_t cpuCyclesLeft;
+};
+
+Apu* apu_init();
+void apu_free(Apu* apu);
+void apu_reset(Apu* apu);
+void apu_cycle(Apu* apu);
+uint8_t apu_cpuRead(Apu* apu, uint16_t adr);
+void apu_cpuWrite(Apu* apu, uint16_t adr, uint8_t val);
+void apu_saveload(Apu *apu, SaveLoadFunc *func, void *ctx);
+
+#endif
--- /dev/null
+++ b/snes/cart.cpp
@@ -1,0 +1,112 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include "cart.h"
+#include "snes.h"
+
+static uint8_t cart_readLorom(Cart* cart, uint8_t bank, uint16_t adr);
+static void cart_writeLorom(Cart* cart, uint8_t bank, uint16_t adr, uint8_t val);
+static uint8_t cart_readHirom(Cart* cart, uint8_t bank, uint16_t adr);
+static void cart_writeHirom(Cart* cart, uint8_t bank, uint16_t adr, uint8_t val);
+
+Cart* cart_init(Snes* snes) {
+ Cart* cart = (Cart *)malloc(sizeof(Cart));
+ cart->snes = snes;
+ cart->type = 0;
+ cart->rom = NULL;
+ cart->romSize = 0;
+ cart->ramSize = 0x2000;
+ cart->ram = (uint8_t *)malloc(cart->ramSize);
+ return cart;
+}
+
+void cart_free(Cart* cart) {
+ free(cart);
+}
+
+void cart_reset(Cart* cart) {
+ if(cart->ramSize > 0 && cart->ram != NULL) memset(cart->ram, 0, cart->ramSize); // for now
+}
+
+void cart_saveload(Cart *cart, SaveLoadFunc *func, void *ctx) {
+ func(ctx, cart->ram, cart->ramSize);
+}
+
+void cart_load(Cart* cart, int type, uint8_t* rom, int romSize, int ramSize) {
+ cart->type = type;
+ if(cart->rom != NULL) free(cart->rom);
+ cart->rom = (uint8_t*)malloc(romSize);
+ cart->romSize = romSize;
+ assert(ramSize == cart->ramSize);
+ memset(cart->ram, 0, ramSize);
+ cart->ramSize = ramSize;
+ memcpy(cart->rom, rom, romSize);
+}
+
+uint8_t cart_read(Cart* cart, uint8_t bank, uint16_t adr) {
+ if (cart->type == 1)
+ return cart_readLorom(cart, bank, adr);
+
+ switch(cart->type) {
+ case 0: return cart->snes->openBus;
+ case 1:
+ case 2: return cart_readHirom(cart, bank, adr);
+ }
+ return cart->snes->openBus;
+}
+
+void cart_write(Cart* cart, uint8_t bank, uint16_t adr, uint8_t val) {
+ switch(cart->type) {
+ case 0: break;
+ case 1: cart_writeLorom(cart, bank, adr, val); break;
+ case 2: cart_writeHirom(cart, bank, adr, val); break;
+ }
+}
+
+static uint8_t cart_readLorom(Cart* cart, uint8_t bank, uint16_t adr) {
+ if(adr >= 0x8000) {
+ // adr 8000-ffff in all banks or all addresses in banks 40-7f and c0-ff
+ return cart->rom[((bank << 15) | (adr & 0x7fff)) & (cart->romSize - 1)];
+ }
+ if(((bank >= 0x70 && bank < 0x7e) || bank >= 0xf0) && adr < 0x8000 && cart->ramSize > 0) {
+ // banks 70-7e and f0-ff, adr 0000-7fff
+ return cart->ram[(((bank & 0xf) << 15) | adr) & (cart->ramSize - 1)];
+ }
+ if(bank & 0x40) {
+ // adr 8000-ffff in all banks or all addresses in banks 40-7f and c0-ff
+ return cart->rom[((bank << 15) | (adr & 0x7fff)) & (cart->romSize - 1)];
+ }
+ return cart->snes->openBus;
+}
+
+static void cart_writeLorom(Cart* cart, uint8_t bank, uint16_t adr, uint8_t val) {
+ if(((bank >= 0x70 && bank < 0x7e) || bank > 0xf0) && adr < 0x8000 && cart->ramSize > 0) {
+ // banks 70-7e and f0-ff, adr 0000-7fff
+ cart->ram[(((bank & 0xf) << 15) | adr) & (cart->ramSize - 1)] = val;
+ }
+}
+
+static uint8_t cart_readHirom(Cart* cart, uint8_t bank, uint16_t adr) {
+ bank &= 0x7f;
+ if(bank < 0x40 && adr >= 0x6000 && adr < 0x8000 && cart->ramSize > 0) {
+ // banks 00-3f and 80-bf, adr 6000-7fff
+ return cart->ram[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (cart->ramSize - 1)];
+ }
+ if(adr >= 0x8000 || bank >= 0x40) {
+ // adr 8000-ffff in all banks or all addresses in banks 40-7f and c0-ff
+ return cart->rom[(((bank & 0x3f) << 16) | adr) & (cart->romSize - 1)];
+ }
+ return cart->snes->openBus;
+}
+
+static void cart_writeHirom(Cart* cart, uint8_t bank, uint16_t adr, uint8_t val) {
+ bank &= 0x7f;
+ if(bank < 0x40 && adr >= 0x6000 && adr < 0x8000 && cart->ramSize > 0) {
+ // banks 00-3f and 80-bf, adr 6000-7fff
+ cart->ram[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (cart->ramSize - 1)] = val;
+ }
+}
--- /dev/null
+++ b/snes/cart.h
@@ -1,0 +1,35 @@
+
+#ifndef CART_H
+#define CART_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct Cart Cart;
+
+#include "snes.h"
+
+struct Cart {
+ Snes* snes;
+ uint8_t type;
+
+ uint8_t* rom;
+ uint32_t romSize;
+ uint8_t* ram;
+ uint32_t ramSize;
+};
+
+// TODO: how to handle reset & load? (especially where to init ram)
+
+Cart* cart_init(Snes* snes);
+void cart_free(Cart* cart);
+void cart_reset(Cart* cart); // will reset special chips etc, general reading is set up in load
+void cart_load(Cart* cart, int type, uint8_t* rom, int romSize, int ramSize); // TODO: figure out how to handle (battery, cart-chips etc)
+uint8_t cart_read(Cart* cart, uint8_t bank, uint16_t adr);
+void cart_write(Cart* cart, uint8_t bank, uint16_t adr, uint8_t val);
+void cart_saveload(Cart *cart, SaveLoadFunc *func, void *ctx);
+
+#endif
--- /dev/null
+++ b/snes/cpu.cpp
@@ -1,0 +1,2443 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <stddef.h>
+#include "cpu.h"
+#include "snes.h"
+
+static const int cyclesPerOpcode[256] = {
+ 7, 6, 7, 4, 5, 3, 5, 6, 3, 2, 2, 4, 6, 4, 6, 5,
+ 2, 5, 5, 7, 5, 4, 6, 6, 2, 4, 2, 2, 6, 4, 7, 5,
+ 6, 6, 8, 4, 3, 3, 5, 6, 4, 2, 2, 5, 4, 4, 6, 5,
+ 2, 5, 5, 7, 4, 4, 6, 6, 2, 4, 2, 2, 4, 4, 7, 5,
+ 6, 6, 2, 4, 7, 3, 5, 6, 3, 2, 2, 3, 3, 4, 6, 5,
+ 2, 5, 5, 7, 7, 4, 6, 6, 2, 4, 3, 2, 4, 4, 7, 5,
+ 6, 6, 6, 4, 3, 3, 5, 6, 4, 2, 2, 6, 5, 4, 6, 5,
+ 2, 5, 5, 7, 4, 4, 6, 6, 2, 4, 4, 2, 6, 4, 7, 5,
+ 3, 6, 4, 4, 3, 3, 3, 6, 2, 2, 2, 3, 4, 4, 4, 5,
+ 2, 6, 5, 7, 4, 4, 4, 6, 2, 5, 2, 2, 4, 5, 5, 5,
+ 2, 6, 2, 4, 3, 3, 3, 6, 2, 2, 2, 4, 4, 4, 4, 5,
+ 2, 5, 5, 7, 4, 4, 4, 6, 2, 4, 2, 2, 4, 4, 4, 5,
+ 2, 6, 3, 4, 3, 3, 5, 6, 2, 2, 2, 3, 4, 4, 6, 5,
+ 2, 5, 5, 7, 6, 4, 6, 6, 2, 4, 3, 3, 6, 4, 7, 5,
+ 2, 6, 3, 4, 3, 3, 5, 6, 2, 2, 2, 3, 4, 4, 6, 5,
+ 2, 5, 5, 7, 5, 4, 6, 6, 2, 4, 4, 2, 8, 4, 7, 5
+};
+
+static uint8_t cpu_read(Cpu* cpu, uint32_t adr);
+static void cpu_write(Cpu* cpu, uint32_t adr, uint8_t val);
+static uint8_t cpu_readOpcode(Cpu* cpu);
+static uint16_t cpu_readOpcodeWord(Cpu* cpu);
+void cpu_setFlags(Cpu* cpu, uint8_t value);
+static void cpu_setZN(Cpu* cpu, uint16_t value, bool byte);
+static void cpu_doBranch(Cpu* cpu, uint8_t value, bool check);
+static uint8_t cpu_pullByte(Cpu* cpu);
+static void cpu_pushByte(Cpu* cpu, uint8_t value);
+static uint16_t cpu_pullWord(Cpu* cpu);
+static void cpu_pushWord(Cpu* cpu, uint16_t value);
+static uint16_t cpu_readWord(Cpu* cpu, uint32_t adrl, uint32_t adrh);
+static void cpu_writeWord(Cpu* cpu, uint32_t adrl, uint32_t adrh, uint16_t value, bool reversed);
+static void cpu_doInterrupt(Cpu* cpu, bool irq);
+static void cpu_doOpcode(Cpu* cpu, uint8_t opcode);
+
+// addressing modes and opcode functions not declared, only used after defintions
+
+static uint8_t cpu_read(Cpu* cpu, uint32_t adr) {
+ // assume mem is a pointer to a Snes
+ return snes_cpuRead((Snes*) cpu->mem, adr);
+}
+
+static void cpu_write(Cpu* cpu, uint32_t adr, uint8_t val) {
+ // assume mem is a pointer to a Snes
+ snes_cpuWrite((Snes*) cpu->mem, adr, val);
+}
+
+Cpu* cpu_init(void* mem, int memType) {
+ Cpu* cpu = (Cpu * )malloc(sizeof(Cpu));
+ cpu->mem = mem;
+ cpu->memType = memType;
+ return cpu;
+}
+
+void cpu_free(Cpu* cpu) {
+ free(cpu);
+}
+
+void cpu_reset(Cpu* cpu) {
+ cpu->a = 0;
+ cpu->x = 0;
+ cpu->y = 0;
+ cpu->sp = 0x100;
+ cpu->pc = cpu_read(cpu, 0xfffc) | (cpu_read(cpu, 0xfffd) << 8);
+ cpu->dp = 0;
+ cpu->k = 0;
+ cpu->db = 0;
+ cpu->c = false;
+ cpu->z = false;
+ cpu->v = false;
+ cpu->n = false;
+ cpu->i = true;
+ cpu->d = false;
+ cpu->xf = true;
+ cpu->mf = true;
+ cpu->e = true;
+ cpu->irqWanted = false;
+ cpu->nmiWanted = false;
+ cpu->waiting = false;
+ cpu->stopped = false;
+ cpu->cyclesUsed = 0;
+ cpu->spBreakpoint = 0x0;
+ cpu->in_emu = 0;
+}
+
+void cpu_saveload(Cpu *cpu, SaveLoadFunc *func, void *ctx) {
+ func(ctx, &cpu->a, offsetof(Cpu, cyclesUsed) - offsetof(Cpu, a));
+ cpu->spBreakpoint = 0x0;
+}
+
+int cpu_runOpcode(Cpu* cpu) {
+ cpu->cyclesUsed = 0;
+ if(cpu->stopped) return 1;
+ if(cpu->waiting) {
+ if(cpu->irqWanted || cpu->nmiWanted) {
+ cpu->waiting = false;
+ }
+ return 1;
+ }
+ // not stopped or waiting, execute a opcode or go to interrupt
+ if((!cpu->i && cpu->irqWanted) || cpu->nmiWanted) {
+ if (cpu->in_emu) {
+ printf("nmi while in emu!\n");
+ }
+
+ cpu->cyclesUsed = 7; // interrupt: at least 7 cycles
+ if(cpu->nmiWanted) {
+ cpu->nmiWanted = false;
+ cpu_doInterrupt(cpu, false);
+ } else {
+ // must be irq
+ cpu_doInterrupt(cpu, true);
+ }
+ } else {
+ uint8_t opcode = cpu_readOpcode(cpu);
+ cpu->cyclesUsed = cyclesPerOpcode[opcode];
+ cpu_doOpcode(cpu, opcode);
+ }
+ return cpu->cyclesUsed;
+}
+
+static uint8_t cpu_readOpcode(Cpu* cpu) {
+ return cpu_read(cpu, (cpu->k << 16) | cpu->pc++);
+}
+
+static uint16_t cpu_readOpcodeWord(Cpu* cpu) {
+ uint8_t low = cpu_readOpcode(cpu);
+ return low | (cpu_readOpcode(cpu) << 8);
+}
+
+uint8_t cpu_getFlags(Cpu* cpu) {
+ uint8_t val = cpu->n << 7;
+ val |= cpu->v << 6;
+ val |= cpu->mf << 5;
+ val |= cpu->xf << 4;
+ val |= cpu->d << 3;
+ val |= cpu->i << 2;
+ val |= cpu->z << 1;
+ val |= (uint8_t)cpu->c;
+ return val;
+}
+
+void cpu_setFlags(Cpu* cpu, uint8_t val) {
+ cpu->n = val & 0x80;
+ cpu->v = val & 0x40;
+ cpu->mf = val & 0x20;
+ cpu->xf = val & 0x10;
+ cpu->d = val & 8;
+ cpu->i = val & 4;
+ cpu->z = val & 2;
+ cpu->c = val & 1;
+ if(cpu->e) {
+ cpu->mf = true;
+ cpu->xf = true;
+ cpu->sp = (cpu->sp & 0xff) | 0x100;
+ }
+ if(cpu->xf) {
+ cpu->x &= 0xff;
+ cpu->y &= 0xff;
+ }
+}
+
+static void cpu_setZN(Cpu* cpu, uint16_t value, bool byte) {
+ if(byte) {
+ cpu->z = (value & 0xff) == 0;
+ cpu->n = value & 0x80;
+ } else {
+ cpu->z = value == 0;
+ cpu->n = value & 0x8000;
+ }
+}
+
+static void cpu_doBranch(Cpu* cpu, uint8_t value, bool check) {
+ if(check) {
+ cpu->cyclesUsed++; // taken branch: 1 extra cycle
+ cpu->pc += (int8_t) value;
+ }
+}
+
+static uint8_t cpu_pullByte(Cpu* cpu) {
+ cpu->sp++;
+ if(cpu->e) cpu->sp = (cpu->sp & 0xff) | 0x100;
+ return cpu_read(cpu, cpu->sp);
+}
+
+static void cpu_pushByte(Cpu* cpu, uint8_t value) {
+ cpu_write(cpu, cpu->sp, value);
+ cpu->sp--;
+ if(cpu->e) cpu->sp = (cpu->sp & 0xff) | 0x100;
+}
+
+static uint16_t cpu_pullWord(Cpu* cpu) {
+ uint8_t value = cpu_pullByte(cpu);
+ return value | (cpu_pullByte(cpu) << 8);
+}
+
+static void cpu_pushWord(Cpu* cpu, uint16_t value) {
+ cpu_pushByte(cpu, value >> 8);
+ cpu_pushByte(cpu, value & 0xff);
+}
+
+static uint16_t cpu_readWord(Cpu* cpu, uint32_t adrl, uint32_t adrh) {
+ uint8_t value = cpu_read(cpu, adrl);
+ return value | (cpu_read(cpu, adrh) << 8);
+}
+
+static void cpu_writeWord(Cpu* cpu, uint32_t adrl, uint32_t adrh, uint16_t value, bool reversed) {
+ if(reversed) {
+ cpu_write(cpu, adrh, value >> 8);
+ cpu_write(cpu, adrl, value & 0xff);
+ } else {
+ cpu_write(cpu, adrl, value & 0xff);
+ cpu_write(cpu, adrh, value >> 8);
+ }
+}
+
+static void cpu_doInterrupt(Cpu* cpu, bool irq) {
+ cpu_pushByte(cpu, cpu->k);
+ cpu_pushWord(cpu, cpu->pc);
+ cpu_pushByte(cpu, cpu_getFlags(cpu));
+ cpu->cyclesUsed++; // native mode: 1 extra cycle
+ cpu->i = true;
+ cpu->d = false;
+ cpu->k = 0;
+ if(irq) {
+ cpu->pc = cpu_readWord(cpu, 0xffee, 0xffef);
+ } else {
+ // nmi
+ cpu->pc = cpu_readWord(cpu, 0xffea, 0xffeb);
+ }
+}
+
+// addressing modes
+
+static uint32_t cpu_adrImm(Cpu* cpu, uint32_t* low, bool xFlag) {
+ if((xFlag && cpu->xf) || (!xFlag && cpu->mf)) {
+ *low = (cpu->k << 16) | cpu->pc++;
+ return 0;
+ } else {
+ *low = (cpu->k << 16) | cpu->pc++;
+ return (cpu->k << 16) | cpu->pc++;
+ }
+}
+
+static uint32_t cpu_adrDp(Cpu* cpu, uint32_t* low) {
+ uint8_t adr = cpu_readOpcode(cpu);
+ if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle
+ *low = (cpu->dp + adr) & 0xffff;
+ return (cpu->dp + adr + 1) & 0xffff;
+}
+
+static uint32_t cpu_adrDpx(Cpu* cpu, uint32_t* low) {
+ uint8_t adr = cpu_readOpcode(cpu);
+ if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle
+ *low = (cpu->dp + adr + cpu->x) & 0xffff;
+ return (cpu->dp + adr + cpu->x + 1) & 0xffff;
+}
+
+static uint32_t cpu_adrDpy(Cpu* cpu, uint32_t* low) {
+ uint8_t adr = cpu_readOpcode(cpu);
+ if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle
+ *low = (cpu->dp + adr + cpu->y) & 0xffff;
+ return (cpu->dp + adr + cpu->y + 1) & 0xffff;
+}
+
+static uint32_t cpu_adrIdp(Cpu* cpu, uint32_t* low) {
+ uint8_t adr = cpu_readOpcode(cpu);
+ if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle
+ uint16_t pointer = cpu_readWord(cpu, (cpu->dp + adr) & 0xffff, (cpu->dp + adr + 1) & 0xffff);
+ *low = (cpu->db << 16) + pointer;
+ return ((cpu->db << 16) + pointer + 1) & 0xffffff;
+}
+
+static uint32_t cpu_adrIdx(Cpu* cpu, uint32_t* low) {
+ uint8_t adr = cpu_readOpcode(cpu);
+ if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle
+ uint16_t pointer = cpu_readWord(cpu, (cpu->dp + adr + cpu->x) & 0xffff, (cpu->dp + adr + cpu->x + 1) & 0xffff);
+ *low = (cpu->db << 16) + pointer;
+ return ((cpu->db << 16) + pointer + 1) & 0xffffff;
+}
+
+static uint32_t cpu_adrIdy(Cpu* cpu, uint32_t* low, bool write) {
+ uint8_t adr = cpu_readOpcode(cpu);
+ if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle
+ uint16_t pointer = cpu_readWord(cpu, (cpu->dp + adr) & 0xffff, (cpu->dp + adr + 1) & 0xffff);
+ if(write && (!cpu->xf || ((pointer >> 8) != ((pointer + cpu->y) >> 8)))) cpu->cyclesUsed++;
+ // x = 0 or page crossed, with writing opcode: 1 extra cycle
+ *low = ((cpu->db << 16) + pointer + cpu->y) & 0xffffff;
+ return ((cpu->db << 16) + pointer + cpu->y + 1) & 0xffffff;
+}
+
+static uint32_t cpu_adrIdl(Cpu* cpu, uint32_t* low) {
+ uint8_t adr = cpu_readOpcode(cpu);
+ if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle
+ uint32_t pointer = cpu_readWord(cpu, (cpu->dp + adr) & 0xffff, (cpu->dp + adr + 1) & 0xffff);
+ pointer |= cpu_read(cpu, (cpu->dp + adr + 2) & 0xffff) << 16;
+ *low = pointer;
+ return (pointer + 1) & 0xffffff;
+}
+
+static uint32_t cpu_adrIly(Cpu* cpu, uint32_t* low) {
+ uint8_t adr = cpu_readOpcode(cpu);
+ if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle
+ uint32_t pointer = cpu_readWord(cpu, (cpu->dp + adr) & 0xffff, (cpu->dp + adr + 1) & 0xffff);
+ pointer |= cpu_read(cpu, (cpu->dp + adr + 2) & 0xffff) << 16;
+ *low = (pointer + cpu->y) & 0xffffff;
+ return (pointer + cpu->y + 1) & 0xffffff;
+}
+
+static uint32_t cpu_adrSr(Cpu* cpu, uint32_t* low) {
+ uint8_t adr = cpu_readOpcode(cpu);
+ *low = (cpu->sp + adr) & 0xffff;
+ return (cpu->sp + adr + 1) & 0xffff;
+}
+
+static uint32_t cpu_adrIsy(Cpu* cpu, uint32_t* low) {
+ uint8_t adr = cpu_readOpcode(cpu);
+ uint16_t pointer = cpu_readWord(cpu, (cpu->sp + adr) & 0xffff, (cpu->sp + adr + 1) & 0xffff);
+ *low = ((cpu->db << 16) + pointer + cpu->y) & 0xffffff;
+ return ((cpu->db << 16) + pointer + cpu->y + 1) & 0xffffff;
+}
+
+static uint32_t cpu_adrAbs(Cpu* cpu, uint32_t* low) {
+ uint16_t adr = cpu_readOpcodeWord(cpu);
+ *low = (cpu->db << 16) + adr;
+ return ((cpu->db << 16) + adr + 1) & 0xffffff;
+}
+
+static uint32_t cpu_adrAbx(Cpu* cpu, uint32_t* low, bool write) {
+ uint16_t adr = cpu_readOpcodeWord(cpu);
+ if(write && (!cpu->xf || ((adr >> 8) != ((adr + cpu->x) >> 8)))) cpu->cyclesUsed++;
+ // x = 0 or page crossed, with writing opcode: 1 extra cycle
+ *low = ((cpu->db << 16) + adr + cpu->x) & 0xffffff;
+ return ((cpu->db << 16) + adr + cpu->x + 1) & 0xffffff;
+}
+
+static uint32_t cpu_adrAby(Cpu* cpu, uint32_t* low, bool write) {
+ uint16_t adr = cpu_readOpcodeWord(cpu);
+ if(write && (!cpu->xf || ((adr >> 8) != ((adr + cpu->y) >> 8)))) cpu->cyclesUsed++;
+ // x = 0 or page crossed, with writing opcode: 1 extra cycle
+ *low = ((cpu->db << 16) + adr + cpu->y) & 0xffffff;
+ return ((cpu->db << 16) + adr + cpu->y + 1) & 0xffffff;
+}
+
+static uint32_t cpu_adrAbl(Cpu* cpu, uint32_t* low) {
+ uint32_t adr = cpu_readOpcodeWord(cpu);
+ adr |= cpu_readOpcode(cpu) << 16;
+ *low = adr;
+ return (adr + 1) & 0xffffff;
+}
+
+static uint32_t cpu_adrAlx(Cpu* cpu, uint32_t* low) {
+ uint32_t adr = cpu_readOpcodeWord(cpu);
+ adr |= cpu_readOpcode(cpu) << 16;
+ *low = (adr + cpu->x) & 0xffffff;
+ return (adr + cpu->x + 1) & 0xffffff;
+}
+
+static uint16_t cpu_adrIax(Cpu* cpu) {
+ uint16_t adr = cpu_readOpcodeWord(cpu);
+ return cpu_readWord(cpu, (cpu->k << 16) | ((adr + cpu->x) & 0xffff), (cpu->k << 16) | ((adr + cpu->x + 1) & 0xffff));
+}
+
+// opcode functions
+
+static void cpu_and(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->mf) {
+ uint8_t value = cpu_read(cpu, low);
+ cpu->a = (cpu->a & 0xff00) | ((cpu->a & value) & 0xff);
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ uint16_t value = cpu_readWord(cpu, low, high);
+ cpu->a &= value;
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+}
+
+static void cpu_ora(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->mf) {
+ uint8_t value = cpu_read(cpu, low);
+ cpu->a = (cpu->a & 0xff00) | ((cpu->a | value) & 0xff);
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ uint16_t value = cpu_readWord(cpu, low, high);
+ cpu->a |= value;
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+}
+
+static void cpu_eor(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->mf) {
+ uint8_t value = cpu_read(cpu, low);
+ cpu->a = (cpu->a & 0xff00) | ((cpu->a ^ value) & 0xff);
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ uint16_t value = cpu_readWord(cpu, low, high);
+ cpu->a ^= value;
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+}
+
+static void cpu_adc(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->mf) {
+ uint8_t value = cpu_read(cpu, low);
+ int result = 0;
+ if(cpu->d) {
+ result = (cpu->a & 0xf) + (value & 0xf) + cpu->c;
+ if(result > 0x9) result = ((result + 0x6) & 0xf) + 0x10;
+ result = (cpu->a & 0xf0) + (value & 0xf0) + result;
+ } else {
+ result = (cpu->a & 0xff) + value + cpu->c;
+ }
+ cpu->v = (cpu->a & 0x80) == (value & 0x80) && (value & 0x80) != (result & 0x80);
+ if(cpu->d && result > 0x9f) result += 0x60;
+ cpu->c = result > 0xff;
+ cpu->a = (cpu->a & 0xff00) | (result & 0xff);
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ uint16_t value = cpu_readWord(cpu, low, high);
+ int result = 0;
+ if(cpu->d) {
+ result = (cpu->a & 0xf) + (value & 0xf) + cpu->c;
+ if(result > 0x9) result = ((result + 0x6) & 0xf) + 0x10;
+ result = (cpu->a & 0xf0) + (value & 0xf0) + result;
+ if(result > 0x9f) result = ((result + 0x60) & 0xff) + 0x100;
+ result = (cpu->a & 0xf00) + (value & 0xf00) + result;
+ if(result > 0x9ff) result = ((result + 0x600) & 0xfff) + 0x1000;
+ result = (cpu->a & 0xf000) + (value & 0xf000) + result;
+ } else {
+ result = cpu->a + value + cpu->c;
+ }
+ cpu->v = (cpu->a & 0x8000) == (value & 0x8000) && (value & 0x8000) != (result & 0x8000);
+ if(cpu->d && result > 0x9fff) result += 0x6000;
+ cpu->c = result > 0xffff;
+ cpu->a = result;
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+}
+
+static void cpu_sbc(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->mf) {
+ uint8_t value = cpu_read(cpu, low) ^ 0xff;
+ int result = 0;
+ if(cpu->d) {
+ result = (cpu->a & 0xf) + (value & 0xf) + cpu->c;
+ if(result < 0x10) result = (result - 0x6) & ((result - 0x6 < 0) ? 0xf : 0x1f);
+ result = (cpu->a & 0xf0) + (value & 0xf0) + result;
+ } else {
+ result = (cpu->a & 0xff) + value + cpu->c;
+ }
+ cpu->v = (cpu->a & 0x80) == (value & 0x80) && (value & 0x80) != (result & 0x80);
+ if(cpu->d && result < 0x100) result -= 0x60;
+ cpu->c = result > 0xff;
+ cpu->a = (cpu->a & 0xff00) | (result & 0xff);
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ uint16_t value = cpu_readWord(cpu, low, high) ^ 0xffff;
+ int result = 0;
+ if(cpu->d) {
+ result = (cpu->a & 0xf) + (value & 0xf) + cpu->c;
+ if(result < 0x10) result = (result - 0x6) & ((result - 0x6 < 0) ? 0xf : 0x1f);
+ result = (cpu->a & 0xf0) + (value & 0xf0) + result;
+ if(result < 0x100) result = (result - 0x60) & ((result - 0x60 < 0) ? 0xff : 0x1ff);
+ result = (cpu->a & 0xf00) + (value & 0xf00) + result;
+ if(result < 0x1000) result = (result - 0x600) & ((result - 0x600 < 0) ? 0xfff : 0x1fff);
+ result = (cpu->a & 0xf000) + (value & 0xf000) + result;
+ } else {
+ result = cpu->a + value + cpu->c;
+ }
+ cpu->v = (cpu->a & 0x8000) == (value & 0x8000) && (value & 0x8000) != (result & 0x8000);
+ if(cpu->d && result < 0x10000) result -= 0x6000;
+ cpu->c = result > 0xffff;
+ cpu->a = result;
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+}
+
+static void cpu_cmp(Cpu* cpu, uint32_t low, uint32_t high) {
+ int result = 0;
+ if(cpu->mf) {
+ uint8_t value = cpu_read(cpu, low) ^ 0xff;
+ result = (cpu->a & 0xff) + value + 1;
+ cpu->c = result > 0xff;
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ uint16_t value = cpu_readWord(cpu, low, high) ^ 0xffff;
+ result = cpu->a + value + 1;
+ cpu->c = result > 0xffff;
+ }
+ cpu_setZN(cpu, result, cpu->mf);
+}
+
+static void cpu_cpx(Cpu* cpu, uint32_t low, uint32_t high) {
+ int result = 0;
+ if(cpu->xf) {
+ uint8_t value = cpu_read(cpu, low) ^ 0xff;
+ result = (cpu->x & 0xff) + value + 1;
+ cpu->c = result > 0xff;
+ } else {
+ cpu->cyclesUsed++; // x = 0: 1 extra cycle
+ uint16_t value = cpu_readWord(cpu, low, high) ^ 0xffff;
+ result = cpu->x + value + 1;
+ cpu->c = result > 0xffff;
+ }
+ cpu_setZN(cpu, result, cpu->xf);
+}
+
+static void cpu_cpy(Cpu* cpu, uint32_t low, uint32_t high) {
+ int result = 0;
+ if(cpu->xf) {
+ uint8_t value = cpu_read(cpu, low) ^ 0xff;
+ result = (cpu->y & 0xff) + value + 1;
+ cpu->c = result > 0xff;
+ } else {
+ cpu->cyclesUsed++; // x = 0: 1 extra cycle
+ uint16_t value = cpu_readWord(cpu, low, high) ^ 0xffff;
+ result = cpu->y + value + 1;
+ cpu->c = result > 0xffff;
+ }
+ cpu_setZN(cpu, result, cpu->xf);
+}
+
+static void cpu_bit(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->mf) {
+ uint8_t value = cpu_read(cpu, low);
+ uint8_t result = (cpu->a & 0xff) & value;
+ cpu->z = result == 0;
+ cpu->n = value & 0x80;
+ cpu->v = value & 0x40;
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ uint16_t value = cpu_readWord(cpu, low, high);
+ uint16_t result = cpu->a & value;
+ cpu->z = result == 0;
+ cpu->n = value & 0x8000;
+ cpu->v = value & 0x4000;
+ }
+}
+
+static void cpu_lda(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->mf) {
+ cpu->a = (cpu->a & 0xff00) | cpu_read(cpu, low);
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ cpu->a = cpu_readWord(cpu, low, high);
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+}
+
+static void cpu_ldx(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->xf) {
+ cpu->x = cpu_read(cpu, low);
+ } else {
+ cpu->cyclesUsed++; // x = 0: 1 extra cycle
+ cpu->x = cpu_readWord(cpu, low, high);
+ }
+ cpu_setZN(cpu, cpu->x, cpu->xf);
+}
+
+static void cpu_ldy(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->xf) {
+ cpu->y = cpu_read(cpu, low);
+ } else {
+ cpu->cyclesUsed++; // x = 0: 1 extra cycle
+ cpu->y = cpu_readWord(cpu, low, high);
+ }
+ cpu_setZN(cpu, cpu->y, cpu->xf);
+}
+
+static void cpu_sta(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->mf) {
+ cpu_write(cpu, low, cpu->a);
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ cpu_writeWord(cpu, low, high, cpu->a, false);
+ }
+}
+
+static void cpu_stx(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->xf) {
+ cpu_write(cpu, low, cpu->x);
+ } else {
+ cpu->cyclesUsed++; // x = 0: 1 extra cycle
+ cpu_writeWord(cpu, low, high, cpu->x, false);
+ }
+}
+
+static void cpu_sty(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->xf) {
+ cpu_write(cpu, low, cpu->y);
+ } else {
+ cpu->cyclesUsed++; // x = 0: 1 extra cycle
+ cpu_writeWord(cpu, low, high, cpu->y, false);
+ }
+}
+
+static void cpu_stz(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->mf) {
+ cpu_write(cpu, low, 0);
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ cpu_writeWord(cpu, low, high, 0, false);
+ }
+}
+
+static void cpu_ror(Cpu* cpu, uint32_t low, uint32_t high) {
+ bool carry = false;
+ int result = 0;
+ if(cpu->mf) {
+ uint8_t value = cpu_read(cpu, low);
+ carry = value & 1;
+ result = (value >> 1) | (cpu->c << 7);
+ cpu_write(cpu, low, result);
+ } else {
+ cpu->cyclesUsed += 2; // m = 0: 2 extra cycles
+ uint16_t value = cpu_readWord(cpu, low, high);
+ carry = value & 1;
+ result = (value >> 1) | (cpu->c << 15);
+ cpu_writeWord(cpu, low, high, result, true);
+ }
+ cpu_setZN(cpu, result, cpu->mf);
+ cpu->c = carry;
+}
+
+static void cpu_rol(Cpu* cpu, uint32_t low, uint32_t high) {
+ int result = 0;
+ if(cpu->mf) {
+ result = (cpu_read(cpu, low) << 1) | (uint8_t)cpu->c;
+ cpu->c = result & 0x100;
+ cpu_write(cpu, low, result);
+ } else {
+ cpu->cyclesUsed += 2; // m = 0: 2 extra cycles
+ result = (cpu_readWord(cpu, low, high) << 1) | (uint8_t)cpu->c;
+ cpu->c = result & 0x10000;
+ cpu_writeWord(cpu, low, high, result, true);
+ }
+ cpu_setZN(cpu, result, cpu->mf);
+}
+
+static void cpu_lsr(Cpu* cpu, uint32_t low, uint32_t high) {
+ int result = 0;
+ if(cpu->mf) {
+ uint8_t value = cpu_read(cpu, low);
+ cpu->c = value & 1;
+ result = value >> 1;
+ cpu_write(cpu, low, result);
+ } else {
+ cpu->cyclesUsed += 2; // m = 0: 2 extra cycles
+ uint16_t value = cpu_readWord(cpu, low, high);
+ cpu->c = value & 1;
+ result = value >> 1;
+ cpu_writeWord(cpu, low, high, result, true);
+ }
+ cpu_setZN(cpu, result, cpu->mf);
+}
+
+static void cpu_asl(Cpu* cpu, uint32_t low, uint32_t high) {
+ int result = 0;
+ if(cpu->mf) {
+ result = cpu_read(cpu, low) << 1;
+ cpu->c = result & 0x100;
+ cpu_write(cpu, low, result);
+ } else {
+ cpu->cyclesUsed += 2; // m = 0: 2 extra cycles
+ result = cpu_readWord(cpu, low, high) << 1;
+ cpu->c = result & 0x10000;
+ cpu_writeWord(cpu, low, high, result, true);
+ }
+ cpu_setZN(cpu, result, cpu->mf);
+}
+
+static void cpu_inc(Cpu* cpu, uint32_t low, uint32_t high) {
+ int result = 0;
+ if(cpu->mf) {
+ result = cpu_read(cpu, low) + 1;
+ cpu_write(cpu, low, result);
+ } else {
+ cpu->cyclesUsed += 2; // m = 0: 2 extra cycles
+ result = cpu_readWord(cpu, low, high) + 1;
+ cpu_writeWord(cpu, low, high, result, true);
+ }
+ cpu_setZN(cpu, result, cpu->mf);
+}
+
+static void cpu_dec(Cpu* cpu, uint32_t low, uint32_t high) {
+ int result = 0;
+ if(cpu->mf) {
+ result = cpu_read(cpu, low) - 1;
+ cpu_write(cpu, low, result);
+ } else {
+ cpu->cyclesUsed += 2; // m = 0: 2 extra cycles
+ result = cpu_readWord(cpu, low, high) - 1;
+ cpu_writeWord(cpu, low, high, result, true);
+ }
+ cpu_setZN(cpu, result, cpu->mf);
+}
+
+static void cpu_tsb(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->mf) {
+ uint8_t value = cpu_read(cpu, low);
+ cpu->z = ((cpu->a & 0xff) & value) == 0;
+ cpu_write(cpu, low, value | (cpu->a & 0xff));
+ } else {
+ cpu->cyclesUsed += 2; // m = 0: 2 extra cycles
+ uint16_t value = cpu_readWord(cpu, low, high);
+ cpu->z = (cpu->a & value) == 0;
+ cpu_writeWord(cpu, low, high, value | cpu->a, true);
+ }
+}
+
+static void cpu_trb(Cpu* cpu, uint32_t low, uint32_t high) {
+ if(cpu->mf) {
+ uint8_t value = cpu_read(cpu, low);
+ cpu->z = ((cpu->a & 0xff) & value) == 0;
+ cpu_write(cpu, low, value & ~(cpu->a & 0xff));
+ } else {
+ cpu->cyclesUsed += 2; // m = 0: 2 extra cycles
+ uint16_t value = cpu_readWord(cpu, low, high);
+ cpu->z = (cpu->a & value) == 0;
+ cpu_writeWord(cpu, low, high, value & ~cpu->a, true);
+ }
+}
+
+void HookedFunctionRts(int is_long);
+
+static void cpu_doOpcode(Cpu* cpu, uint8_t opcode) {
+ switch(opcode) {
+ case 0x00: { // brk imp
+ uint32_t addr = (cpu->k << 16) | cpu->pc;
+ switch (addr - 1) {
+
+ // Uncle_AtHome case 3 will read random memory.
+ case 0x5DEC7:
+ *(uint8_t *)&cpu->a = cpu_read(cpu, 0x5DEB0 + (cpu->y & 0xff));
+
+ if (cpu_read(cpu, 0xD90 + (cpu->x & 0xff)) == 2) {
+ cpu->pc = 0xdeea;
+ return;
+ }
+ cpu->pc += 2;
+ return;
+
+ // Overlord_StalfosTrap doesn't initialize the sprite_D memory location
+ case 0x9be5e:
+ *(uint8_t *)&cpu->a = 224;
+ cpu_write(cpu, 0xDE0 + (uint8_t)cpu->y, 0);
+ cpu->pc++;
+ return;
+
+ case 0x1AF9A4: // Lanmola_SpawnShrapnel uses undefined carry value
+ *(uint8_t *)&cpu->a += 4;
+ cpu->c = 0;
+ cpu->pc++;
+ return;
+
+ /*
+.9E:8A46 E5 E2 sbc.b A, BYTE BG2HOFS_copy2
+.9E:8A48 E5 08 sbc.b A, R8
+.9E:8A4A 69 0C adc.b A, #0xC
+. */
+ case 0x1E8A46: // carry junk
+ cpu->a = cpu->a - cpu_read(cpu, 0xe2) - cpu_read(cpu, 8) + 12;
+ cpu->pc += 5;
+ return;
+/*
+.9E:8A52 E5 E8 sbc.b A, BYTE BG2VOFS_copy2
+.9E:8A54 69 08 adc.b A, #8
+.9E:8A56 E5 09 sbc.b A, R9
+.9E:8A58 69 08 adc.b A, #8
+*/
+ case 0x1E8A52: // carry junk
+ cpu->a = cpu->a - cpu_read(cpu, 0xe8) + 8 - cpu_read(cpu, 9) + 8;
+ cpu->pc += 7;
+ return;
+
+ case 0x9a966: // TAgalong_DrawInner doesn't init scratch_0 / scratch_1
+ for(int i = 0; i < 4; i++) cpu_write(cpu, 0x72 + i, 0);
+ cpu->pc += 1;
+ return;
+
+ case 0x8f708:
+ cpu->pc += 0;
+ cpu_write(cpu, 0x75, 0);
+ goto case_iny_c8;
+
+ case 0x1de0e5: // GreatCatfish_ConversateThenSubmerge - not carry preserving
+ if ((uint8_t)cpu->a >= 160)
+ cpu->pc = 0xe164;
+ else
+ cpu->pc += 1;
+ return;
+
+ case 0x6d0b6:
+ case 0x6d0c6: { // Sprite_CommonItemPickup - wrong carry chain
+ cpu->c = ((uint8_t)cpu->a >= 4);
+ cpu->a = cpu->a - 4;
+ cpu->pc += 1;
+ return;
+ }
+
+ case 0x1d8f29:
+ case 0x1dc812:
+ case 0x6ED0B:
+ case 0x9b478:
+ case 0x9b46c:
+ cpu->c = 0;
+ goto adc_69;
+
+ case 0x9B468:
+ case 0x9B46A:
+ case 0x9B474:
+ case 0x9B476:
+ cpu->c = 1;
+ goto sbc_e5;
+
+ case 0x9B60C:
+ cpu->c = 1;
+ goto sbc_e9;
+
+ case 0x1DCDEB:
+ cpu->y = cpu_read(cpu, 0x0eb0 + (cpu->x & 0xff)); // BC B0 0E mov.b Y, sprite_head_dir[X]
+ cpu->a = cpu->x;
+ return;
+ }
+
+ assert(0);
+#if 0
+ cpu_pushByte(cpu, cpu->k);
+ cpu_pushWord(cpu, cpu->pc + 1);
+ cpu_pushByte(cpu, cpu_getFlags(cpu));
+ cpu->cyclesUsed++; // native mode: 1 extra cycle
+ cpu->i = true;
+ cpu->d = false;
+ cpu->k = 0;
+ cpu->pc = cpu_readWord(cpu, 0xffe6, 0xffe7);
+#endif
+ break;
+ }
+ case 0x01: { // ora idx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdx(cpu, &low);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x02: { // cop imm(s)
+ cpu_readOpcode(cpu);
+ cpu_pushByte(cpu, cpu->k);
+ cpu_pushWord(cpu, cpu->pc);
+ cpu_pushByte(cpu, cpu_getFlags(cpu));
+ cpu->cyclesUsed++; // native mode: 1 extra cycle
+ cpu->i = true;
+ cpu->d = false;
+ cpu->k = 0;
+ cpu->pc = cpu_readWord(cpu, 0xffe4, 0xffe5);
+ break;
+ }
+ case 0x03: { // ora sr
+ uint32_t low = 0;
+ uint32_t high = cpu_adrSr(cpu, &low);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x04: { // tsb dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_tsb(cpu, low, high);
+ break;
+ }
+ case 0x05: { // ora dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x06: { // asl dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_asl(cpu, low, high);
+ break;
+ }
+ case 0x07: { // ora idl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdl(cpu, &low);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x08: { // php imp
+ cpu_pushByte(cpu, cpu_getFlags(cpu));
+ break;
+ }
+ case 0x09: { // ora imm(m)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrImm(cpu, &low, false);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x0a: { // asla imp
+ if(cpu->mf) {
+ cpu->c = cpu->a & 0x80;
+ cpu->a = (cpu->a & 0xff00) | ((cpu->a << 1) & 0xff);
+ } else {
+ cpu->c = cpu->a & 0x8000;
+ cpu->a <<= 1;
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+ break;
+ }
+ case 0x0b: { // phd imp
+ cpu_pushWord(cpu, cpu->dp);
+ break;
+ }
+ case 0x0c: { // tsb abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_tsb(cpu, low, high);
+ break;
+ }
+ case 0x0d: { // ora abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x0e: { // asl abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_asl(cpu, low, high);
+ break;
+ }
+ case 0x0f: { // ora abl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbl(cpu, &low);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x10: { // bpl rel
+ cpu_doBranch(cpu, cpu_readOpcode(cpu), !cpu->n);
+ break;
+ }
+ case 0x11: { // ora idy(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdy(cpu, &low, false);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x12: { // ora idp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdp(cpu, &low);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x13: { // ora isy
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIsy(cpu, &low);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x14: { // trb dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_trb(cpu, low, high);
+ break;
+ }
+ case 0x15: { // ora dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x16: { // asl dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_asl(cpu, low, high);
+ break;
+ }
+ case 0x17: { // ora ily
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIly(cpu, &low);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x18: { // clc imp
+ cpu->c = false;
+ break;
+ }
+ case 0x19: { // ora aby(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAby(cpu, &low, false);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x1a: { // inca imp
+ if(cpu->mf) {
+ cpu->a = (cpu->a & 0xff00) | ((cpu->a + 1) & 0xff);
+ } else {
+ cpu->a++;
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+ break;
+ }
+ case 0x1b: { // tcs imp
+ cpu->sp = cpu->a;
+ break;
+ }
+ case 0x1c: { // trb abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_trb(cpu, low, high);
+ break;
+ }
+ case 0x1d: { // ora abx(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, false);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x1e: { // asl abx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, true);
+ cpu_asl(cpu, low, high);
+ break;
+ }
+ case 0x1f: { // ora alx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAlx(cpu, &low);
+ cpu_ora(cpu, low, high);
+ break;
+ }
+ case 0x20: { // jsr abs
+ uint16_t value = cpu_readOpcodeWord(cpu);
+ cpu_pushWord(cpu, cpu->pc - 1);
+ cpu->pc = value;
+ break;
+ }
+ case 0x21: { // and idx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdx(cpu, &low);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x22: { // jsl abl
+ uint16_t value = cpu_readOpcodeWord(cpu);
+ uint8_t newK = cpu_readOpcode(cpu);
+ cpu_pushByte(cpu, cpu->k);
+ cpu_pushWord(cpu, cpu->pc - 1);
+ cpu->pc = value;
+ cpu->k = newK;
+ break;
+ }
+ case 0x23: { // and sr
+ uint32_t low = 0;
+ uint32_t high = cpu_adrSr(cpu, &low);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x24: { // bit dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_bit(cpu, low, high);
+ break;
+ }
+ case 0x25: { // and dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x26: { // rol dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_rol(cpu, low, high);
+ break;
+ }
+ case 0x27: { // and idl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdl(cpu, &low);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x28: { // plp imp
+ cpu_setFlags(cpu, cpu_pullByte(cpu));
+ break;
+ }
+ case 0x29: { // and imm(m)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrImm(cpu, &low, false);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x2a: { // rola imp
+ int result = (cpu->a << 1) | (uint8_t)cpu->c;
+ if(cpu->mf) {
+ cpu->c = result & 0x100;
+ cpu->a = (cpu->a & 0xff00) | (result & 0xff);
+ } else {
+ cpu->c = result & 0x10000;
+ cpu->a = result;
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+ break;
+ }
+ case 0x2b: { // pld imp
+ cpu->dp = cpu_pullWord(cpu);
+ cpu_setZN(cpu, cpu->dp, false);
+ break;
+ }
+ case 0x2c: { // bit abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_bit(cpu, low, high);
+ break;
+ }
+ case 0x2d: { // and abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x2e: { // rol abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_rol(cpu, low, high);
+ break;
+ }
+ case 0x2f: { // and abl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbl(cpu, &low);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x30: { // bmi rel
+ cpu_doBranch(cpu, cpu_readOpcode(cpu), cpu->n);
+ break;
+ }
+ case 0x31: { // and idy(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdy(cpu, &low, false);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x32: { // and idp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdp(cpu, &low);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x33: { // and isy
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIsy(cpu, &low);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x34: { // bit dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_bit(cpu, low, high);
+ break;
+ }
+ case 0x35: { // and dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x36: { // rol dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_rol(cpu, low, high);
+ break;
+ }
+ case 0x37: { // and ily
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIly(cpu, &low);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x38: { // sec imp
+ cpu->c = true;
+ break;
+ }
+ case 0x39: { // and aby(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAby(cpu, &low, false);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x3a: { // deca imp
+ if(cpu->mf) {
+ cpu->a = (cpu->a & 0xff00) | ((cpu->a - 1) & 0xff);
+ } else {
+ cpu->a--;
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+ break;
+ }
+ case 0x3b: { // tsc imp
+ cpu->a = cpu->sp;
+ cpu_setZN(cpu, cpu->a, false);
+ break;
+ }
+ case 0x3c: { // bit abx(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, false);
+ cpu_bit(cpu, low, high);
+ break;
+ }
+ case 0x3d: { // and abx(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, false);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x3e: { // rol abx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, true);
+ cpu_rol(cpu, low, high);
+ break;
+ }
+ case 0x3f: { // and alx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAlx(cpu, &low);
+ cpu_and(cpu, low, high);
+ break;
+ }
+ case 0x40: { // rti imp
+ cpu_setFlags(cpu, cpu_pullByte(cpu));
+ cpu->cyclesUsed++; // native mode: 1 extra cycle
+ cpu->pc = cpu_pullWord(cpu);
+ cpu->k = cpu_pullByte(cpu);
+ break;
+ }
+ case 0x41: { // eor idx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdx(cpu, &low);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x42: { // wdm imm(s)
+ cpu_readOpcode(cpu);
+ break;
+ }
+ case 0x43: { // eor sr
+ uint32_t low = 0;
+ uint32_t high = cpu_adrSr(cpu, &low);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x44: { // mvp bm
+ uint8_t dest = cpu_readOpcode(cpu);
+ uint8_t src = cpu_readOpcode(cpu);
+ cpu->db = dest;
+ cpu_write(cpu, (dest << 16) | cpu->y, cpu_read(cpu, (src << 16) | cpu->x));
+ cpu->a--;
+ cpu->x--;
+ cpu->y--;
+ if(cpu->a != 0xffff) {
+ cpu->pc -= 3;
+ }
+ if(cpu->xf) {
+ cpu->x &= 0xff;
+ cpu->y &= 0xff;
+ }
+ break;
+ }
+ case 0x45: { // eor dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x46: { // lsr dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_lsr(cpu, low, high);
+ break;
+ }
+ case 0x47: { // eor idl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdl(cpu, &low);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x48: { // pha imp
+ if(cpu->mf) {
+ cpu_pushByte(cpu, cpu->a);
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ cpu_pushWord(cpu, cpu->a);
+ }
+ break;
+ }
+ case 0x49: { // eor imm(m)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrImm(cpu, &low, false);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x4a: { // lsra imp
+ cpu->c = cpu->a & 1;
+ if(cpu->mf) {
+ cpu->a = (cpu->a & 0xff00) | ((cpu->a >> 1) & 0x7f);
+ } else {
+ cpu->a >>= 1;
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+ break;
+ }
+ case 0x4b: { // phk imp
+ cpu_pushByte(cpu, cpu->k);
+ break;
+ }
+ case 0x4c: { // jmp abs
+ cpu->pc = cpu_readOpcodeWord(cpu);
+ break;
+ }
+ case 0x4d: { // eor abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x4e: { // lsr abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_lsr(cpu, low, high);
+ break;
+ }
+ case 0x4f: { // eor abl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbl(cpu, &low);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x50: { // bvc rel
+ cpu_doBranch(cpu, cpu_readOpcode(cpu), !cpu->v);
+ break;
+ }
+ case 0x51: { // eor idy(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdy(cpu, &low, false);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x52: { // eor idp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdp(cpu, &low);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x53: { // eor isy
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIsy(cpu, &low);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x54: { // mvn bm
+ uint8_t dest = cpu_readOpcode(cpu);
+ uint8_t src = cpu_readOpcode(cpu);
+ cpu->db = dest;
+ cpu_write(cpu, (dest << 16) | cpu->y, cpu_read(cpu, (src << 16) | cpu->x));
+ cpu->a--;
+ cpu->x++;
+ cpu->y++;
+ if(cpu->a != 0xffff) {
+ cpu->pc -= 3;
+ }
+ if(cpu->xf) {
+ cpu->x &= 0xff;
+ cpu->y &= 0xff;
+ }
+ break;
+ }
+ case 0x55: { // eor dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x56: { // lsr dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_lsr(cpu, low, high);
+ break;
+ }
+ case 0x57: { // eor ily
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIly(cpu, &low);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x58: { // cli imp
+ cpu->i = false;
+ break;
+ }
+ case 0x59: { // eor aby(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAby(cpu, &low, false);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x5a: { // phy imp
+ if(cpu->xf) {
+ cpu_pushByte(cpu, cpu->y);
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ cpu_pushWord(cpu, cpu->y);
+ }
+ break;
+ }
+ case 0x5b: { // tcd imp
+ cpu->dp = cpu->a;
+ cpu_setZN(cpu, cpu->dp, false);
+ break;
+ }
+ case 0x5c: { // jml abl
+ uint16_t value = cpu_readOpcodeWord(cpu);
+ cpu->k = cpu_readOpcode(cpu);
+ cpu->pc = value;
+ break;
+ }
+ case 0x5d: { // eor abx(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, false);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x5e: { // lsr abx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, true);
+ cpu_lsr(cpu, low, high);
+ break;
+ }
+ case 0x5f: { // eor alx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAlx(cpu, &low);
+ cpu_eor(cpu, low, high);
+ break;
+ }
+ case 0x60: { // rts imp
+ //if (cpu->spBreakpoint)
+ // fprintf(stderr, "0x%x: rts 0x%x 0x%x\n", cpu->k<<16 | cpu->pc, cpu->spBreakpoint, cpu->sp);
+ if (cpu->sp >= cpu->spBreakpoint && cpu->spBreakpoint) {
+ assert(cpu->sp == cpu->spBreakpoint);
+ cpu->spBreakpoint = 0;
+ HookedFunctionRts(0);
+ }
+ cpu->pc = cpu_pullWord(cpu) + 1;
+ break;
+ }
+ case 0x61: { // adc idx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdx(cpu, &low);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x62: { // per rll
+ uint16_t value = cpu_readOpcodeWord(cpu);
+ cpu_pushWord(cpu, cpu->pc + (int16_t) value);
+ break;
+ }
+ case 0x63: { // adc sr
+ uint32_t low = 0;
+ uint32_t high = cpu_adrSr(cpu, &low);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x64: { // stz dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_stz(cpu, low, high);
+ break;
+ }
+ case 0x65: { // adc dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x66: { // ror dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_ror(cpu, low, high);
+ break;
+ }
+ case 0x67: { // adc idl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdl(cpu, &low);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x68: { // pla imp
+ if(cpu->mf) {
+ cpu->a = (cpu->a & 0xff00) | cpu_pullByte(cpu);
+ } else {
+ cpu->cyclesUsed++; // 16-bit m: 1 extra cycle
+ cpu->a = cpu_pullWord(cpu);
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+ break;
+ }
+ adc_69:
+ case 0x69: { // adc imm(m)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrImm(cpu, &low, false);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x6a: { // rora imp
+ bool carry = cpu->a & 1;
+ if(cpu->mf) {
+ cpu->a = (cpu->a & 0xff00) | ((cpu->a >> 1) & 0x7f) | (cpu->c << 7);
+ } else {
+ cpu->a = (cpu->a >> 1) | (cpu->c << 15);
+ }
+ cpu->c = carry;
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+ break;
+ }
+ case 0x6b: { // rtl imp
+ //if (cpu->spBreakpoint)
+ // fprintf(stderr, "0x%x: rtl 0x%x 0x%x\n", cpu->k<<16 | cpu->pc, cpu->spBreakpoint, cpu->sp);
+
+ if (cpu->sp >= cpu->spBreakpoint && cpu->spBreakpoint) {
+ assert(cpu->sp == cpu->spBreakpoint);
+ cpu->spBreakpoint = 0;
+ HookedFunctionRts(1);
+ }
+ cpu->pc = cpu_pullWord(cpu) + 1;
+ cpu->k = cpu_pullByte(cpu);
+ break;
+ }
+ case 0x6c: { // jmp ind
+ uint16_t adr = cpu_readOpcodeWord(cpu);
+ cpu->pc = cpu_readWord(cpu, adr, (adr + 1) & 0xffff);
+ break;
+ }
+ case 0x6d: { // adc abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x6e: { // ror abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_ror(cpu, low, high);
+ break;
+ }
+ case 0x6f: { // adc abl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbl(cpu, &low);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x70: { // bvs rel
+ cpu_doBranch(cpu, cpu_readOpcode(cpu), cpu->v);
+ break;
+ }
+ case 0x71: { // adc idy(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdy(cpu, &low, false);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x72: { // adc idp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdp(cpu, &low);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x73: { // adc isy
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIsy(cpu, &low);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x74: { // stz dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_stz(cpu, low, high);
+ break;
+ }
+ case 0x75: { // adc dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x76: { // ror dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_ror(cpu, low, high);
+ break;
+ }
+ case 0x77: { // adc ily
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIly(cpu, &low);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x78: { // sei imp
+ cpu->i = true;
+ break;
+ }
+ case 0x79: { // adc aby(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAby(cpu, &low, false);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x7a: { // ply imp
+ if(cpu->xf) {
+ cpu->y = cpu_pullByte(cpu);
+ } else {
+ cpu->cyclesUsed++; // 16-bit x: 1 extra cycle
+ cpu->y = cpu_pullWord(cpu);
+ }
+ cpu_setZN(cpu, cpu->y, cpu->xf);
+ break;
+ }
+ case 0x7b: { // tdc imp
+ cpu->a = cpu->dp;
+ cpu_setZN(cpu, cpu->a, false);
+ break;
+ }
+ case 0x7c: { // jmp iax
+ cpu->pc = cpu_adrIax(cpu);
+ break;
+ }
+ case 0x7d: { // adc abx(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, false);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x7e: { // ror abx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, true);
+ cpu_ror(cpu, low, high);
+ break;
+ }
+ case 0x7f: { // adc alx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAlx(cpu, &low);
+ cpu_adc(cpu, low, high);
+ break;
+ }
+ case 0x80: { // bra rel
+ cpu->pc += (int8_t) cpu_readOpcode(cpu);
+ break;
+ }
+ case 0x81: { // sta idx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdx(cpu, &low);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x82: { // brl rll
+ cpu->pc += (int16_t) cpu_readOpcodeWord(cpu);
+ break;
+ }
+ case 0x83: { // sta sr
+ uint32_t low = 0;
+ uint32_t high = cpu_adrSr(cpu, &low);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x84: { // sty dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_sty(cpu, low, high);
+ break;
+ }
+ case 0x85: { // sta dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x86: { // stx dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_stx(cpu, low, high);
+ break;
+ }
+ case 0x87: { // sta idl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdl(cpu, &low);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x88: { // dey imp
+ if(cpu->xf) {
+ cpu->y = (cpu->y - 1) & 0xff;
+ } else {
+ cpu->y--;
+ }
+ cpu_setZN(cpu, cpu->y, cpu->xf);
+ break;
+ }
+ case 0x89: { // biti imm(m)
+ if(cpu->mf) {
+ uint8_t result = (cpu->a & 0xff) & cpu_readOpcode(cpu);
+ cpu->z = result == 0;
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ uint16_t result = cpu->a & cpu_readOpcodeWord(cpu);
+ cpu->z = result == 0;
+ }
+ break;
+ }
+ case 0x8a: { // txa imp
+ if(cpu->mf) {
+ cpu->a = (cpu->a & 0xff00) | (cpu->x & 0xff);
+ } else {
+ cpu->a = cpu->x;
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+ break;
+ }
+ case 0x8b: { // phb imp
+ cpu_pushByte(cpu, cpu->db);
+ break;
+ }
+ case 0x8c: { // sty abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_sty(cpu, low, high);
+ break;
+ }
+ case 0x8d: { // sta abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x8e: { // stx abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_stx(cpu, low, high);
+ break;
+ }
+ case 0x8f: { // sta abl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbl(cpu, &low);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x90: { // bcc rel
+ cpu_doBranch(cpu, cpu_readOpcode(cpu), !cpu->c);
+ break;
+ }
+ case 0x91: { // sta idy
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdy(cpu, &low, true);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x92: { // sta idp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdp(cpu, &low);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x93: { // sta isy
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIsy(cpu, &low);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x94: { // sty dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_sty(cpu, low, high);
+ break;
+ }
+ case 0x95: { // sta dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x96: { // stx dpy
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpy(cpu, &low);
+ cpu_stx(cpu, low, high);
+ break;
+ }
+ case 0x97: { // sta ily
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIly(cpu, &low);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x98: { // tya imp
+ if(cpu->mf) {
+ cpu->a = (cpu->a & 0xff00) | (cpu->y & 0xff);
+ } else {
+ cpu->a = cpu->y;
+ }
+ cpu_setZN(cpu, cpu->a, cpu->mf);
+ break;
+ }
+ case 0x99: { // sta aby
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAby(cpu, &low, true);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x9a: { // txs imp
+ cpu->sp = cpu->x;
+ break;
+ }
+ case 0x9b: { // txy imp
+ if(cpu->xf) {
+ cpu->y = cpu->x & 0xff;
+ } else {
+ cpu->y = cpu->x;
+ }
+ cpu_setZN(cpu, cpu->y, cpu->xf);
+ break;
+ }
+ case 0x9c: { // stz abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_stz(cpu, low, high);
+ break;
+ }
+ case 0x9d: { // sta abx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, true);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0x9e: { // stz abx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, true);
+ cpu_stz(cpu, low, high);
+ break;
+ }
+ case 0x9f: { // sta alx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAlx(cpu, &low);
+ cpu_sta(cpu, low, high);
+ break;
+ }
+ case 0xa0: { // ldy imm(x)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrImm(cpu, &low, true);
+ cpu_ldy(cpu, low, high);
+ break;
+ }
+ case 0xa1: { // lda idx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdx(cpu, &low);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xa2: { // ldx imm(x)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrImm(cpu, &low, true);
+ cpu_ldx(cpu, low, high);
+ break;
+ }
+ case 0xa3: { // lda sr
+ uint32_t low = 0;
+ uint32_t high = cpu_adrSr(cpu, &low);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xa4: { // ldy dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_ldy(cpu, low, high);
+ break;
+ }
+ case 0xa5: { // lda dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xa6: { // ldx dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_ldx(cpu, low, high);
+ break;
+ }
+ case 0xa7: { // lda idl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdl(cpu, &low);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xa8: { // tay imp
+ if(cpu->xf) {
+ cpu->y = cpu->a & 0xff;
+ } else {
+ cpu->y = cpu->a;
+ }
+ cpu_setZN(cpu, cpu->y, cpu->xf);
+ break;
+ }
+ case 0xa9: { // lda imm(m)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrImm(cpu, &low, false);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xaa: { // tax imp
+ if(cpu->xf) {
+ cpu->x = cpu->a & 0xff;
+ } else {
+ cpu->x = cpu->a;
+ }
+ cpu_setZN(cpu, cpu->x, cpu->xf);
+ break;
+ }
+ case 0xab: { // plb imp
+ cpu->db = cpu_pullByte(cpu);
+ cpu_setZN(cpu, cpu->db, true);
+ break;
+ }
+ case 0xac: { // ldy abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_ldy(cpu, low, high);
+ break;
+ }
+ case 0xad: { // lda abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xae: { // ldx abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_ldx(cpu, low, high);
+ break;
+ }
+ case 0xaf: { // lda abl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbl(cpu, &low);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xb0: { // bcs rel
+ cpu_doBranch(cpu, cpu_readOpcode(cpu), cpu->c);
+ break;
+ }
+ case 0xb1: { // lda idy(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdy(cpu, &low, false);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xb2: { // lda idp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdp(cpu, &low);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xb3: { // lda isy
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIsy(cpu, &low);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xb4: { // ldy dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_ldy(cpu, low, high);
+ break;
+ }
+ case 0xb5: { // lda dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xb6: { // ldx dpy
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpy(cpu, &low);
+ cpu_ldx(cpu, low, high);
+ break;
+ }
+ case 0xb7: { // lda ily
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIly(cpu, &low);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xb8: { // clv imp
+ cpu->v = false;
+ break;
+ }
+ case 0xb9: { // lda aby(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAby(cpu, &low, false);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xba: { // tsx imp
+ if(cpu->xf) {
+ cpu->x = cpu->sp & 0xff;
+ } else {
+ cpu->x = cpu->sp;
+ }
+ cpu_setZN(cpu, cpu->x, cpu->xf);
+ break;
+ }
+ case 0xbb: { // tyx imp
+ if(cpu->xf) {
+ cpu->x = cpu->y & 0xff;
+ } else {
+ cpu->x = cpu->y;
+ }
+ cpu_setZN(cpu, cpu->x, cpu->xf);
+ break;
+ }
+ case 0xbc: { // ldy abx(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, false);
+ cpu_ldy(cpu, low, high);
+ break;
+ }
+ case 0xbd: { // lda abx(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, false);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xbe: { // ldx aby(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAby(cpu, &low, false);
+ cpu_ldx(cpu, low, high);
+ break;
+ }
+ case 0xbf: { // lda alx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAlx(cpu, &low);
+ cpu_lda(cpu, low, high);
+ break;
+ }
+ case 0xc0: { // cpy imm(x)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrImm(cpu, &low, true);
+ cpu_cpy(cpu, low, high);
+ break;
+ }
+ case 0xc1: { // cmp idx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdx(cpu, &low);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xc2: { // rep imm(s)
+ cpu_setFlags(cpu, cpu_getFlags(cpu) & ~cpu_readOpcode(cpu));
+ break;
+ }
+ case 0xc3: { // cmp sr
+ uint32_t low = 0;
+ uint32_t high = cpu_adrSr(cpu, &low);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xc4: { // cpy dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_cpy(cpu, low, high);
+ break;
+ }
+ case 0xc5: { // cmp dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xc6: { // dec dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_dec(cpu, low, high);
+ break;
+ }
+ case 0xc7: { // cmp idl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdl(cpu, &low);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case_iny_c8:
+ case 0xc8: { // iny imp
+ if(cpu->xf) {
+ cpu->y = (cpu->y + 1) & 0xff;
+ } else {
+ cpu->y++;
+ }
+ cpu_setZN(cpu, cpu->y, cpu->xf);
+ break;
+ }
+ case 0xc9: { // cmp imm(m)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrImm(cpu, &low, false);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xca: { // dex imp
+ if(cpu->xf) {
+ cpu->x = (cpu->x - 1) & 0xff;
+ } else {
+ cpu->x--;
+ }
+ cpu_setZN(cpu, cpu->x, cpu->xf);
+ break;
+ }
+ case 0xcb: { // wai imp
+ cpu->waiting = true;
+ break;
+ }
+ case 0xcc: { // cpy abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_cpy(cpu, low, high);
+ break;
+ }
+ case 0xcd: { // cmp abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xce: { // dec abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_dec(cpu, low, high);
+ break;
+ }
+ case 0xcf: { // cmp abl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbl(cpu, &low);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xd0: { // bne rel
+ cpu_doBranch(cpu, cpu_readOpcode(cpu), !cpu->z);
+ break;
+ }
+ case 0xd1: { // cmp idy(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdy(cpu, &low, false);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xd2: { // cmp idp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdp(cpu, &low);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xd3: { // cmp isy
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIsy(cpu, &low);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xd4: { // pei dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_pushWord(cpu, cpu_readWord(cpu, low, high));
+ break;
+ }
+ case 0xd5: { // cmp dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xd6: { // dec dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_dec(cpu, low, high);
+ break;
+ }
+ case 0xd7: { // cmp ily
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIly(cpu, &low);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xd8: { // cld imp
+ cpu->d = false;
+ break;
+ }
+ case 0xd9: { // cmp aby(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAby(cpu, &low, false);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xda: { // phx imp
+ if(cpu->xf) {
+ cpu_pushByte(cpu, cpu->x);
+ } else {
+ cpu->cyclesUsed++; // m = 0: 1 extra cycle
+ cpu_pushWord(cpu, cpu->x);
+ }
+ break;
+ }
+ case 0xdb: { // stp imp
+ cpu->stopped = true;
+ break;
+ }
+ case 0xdc: { // jml ial
+ uint16_t adr = cpu_readOpcodeWord(cpu);
+ cpu->pc = cpu_readWord(cpu, adr, (adr + 1) & 0xffff);
+ cpu->k = cpu_read(cpu, (adr + 2) & 0xffff);
+ break;
+ }
+ case 0xdd: { // cmp abx(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, false);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xde: { // dec abx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, true);
+ cpu_dec(cpu, low, high);
+ break;
+ }
+ case 0xdf: { // cmp alx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAlx(cpu, &low);
+ cpu_cmp(cpu, low, high);
+ break;
+ }
+ case 0xe0: { // cpx imm(x)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrImm(cpu, &low, true);
+ cpu_cpx(cpu, low, high);
+ break;
+ }
+ case 0xe1: { // sbc idx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdx(cpu, &low);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xe2: { // sep imm(s)
+ cpu_setFlags(cpu, cpu_getFlags(cpu) | cpu_readOpcode(cpu));
+ break;
+ }
+ case 0xe3: { // sbc sr
+ uint32_t low = 0;
+ uint32_t high = cpu_adrSr(cpu, &low);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xe4: { // cpx dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_cpx(cpu, low, high);
+ break;
+ }
+ sbc_e5:
+ case 0xe5: { // sbc dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xe6: { // inc dp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDp(cpu, &low);
+ cpu_inc(cpu, low, high);
+ break;
+ }
+ case 0xe7: { // sbc idl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdl(cpu, &low);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xe8: { // inx imp
+ if(cpu->xf) {
+ cpu->x = (cpu->x + 1) & 0xff;
+ } else {
+ cpu->x++;
+ }
+ cpu_setZN(cpu, cpu->x, cpu->xf);
+ break;
+ }
+ sbc_e9:
+ case 0xe9: { // sbc imm(m)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrImm(cpu, &low, false);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xea: { // nop imp
+ // no operation
+ break;
+ }
+ case 0xeb: { // xba imp
+ uint8_t low = cpu->a & 0xff;
+ uint8_t high = cpu->a >> 8;
+ cpu->a = (low << 8) | high;
+ cpu_setZN(cpu, high, true);
+ break;
+ }
+ case 0xec: { // cpx abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_cpx(cpu, low, high);
+ break;
+ }
+ case 0xed: { // sbc abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xee: { // inc abs
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbs(cpu, &low);
+ cpu_inc(cpu, low, high);
+ break;
+ }
+ case 0xef: { // sbc abl
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbl(cpu, &low);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xf0: { // beq rel
+ cpu_doBranch(cpu, cpu_readOpcode(cpu), cpu->z);
+ break;
+ }
+ case 0xf1: { // sbc idy(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdy(cpu, &low, false);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xf2: { // sbc idp
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIdp(cpu, &low);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xf3: { // sbc isy
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIsy(cpu, &low);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xf4: { // pea imm(l)
+ cpu_pushWord(cpu, cpu_readOpcodeWord(cpu));
+ break;
+ }
+ case 0xf5: { // sbc dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xf6: { // inc dpx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrDpx(cpu, &low);
+ cpu_inc(cpu, low, high);
+ break;
+ }
+ case 0xf7: { // sbc ily
+ uint32_t low = 0;
+ uint32_t high = cpu_adrIly(cpu, &low);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xf8: { // sed imp
+ cpu->d = true;
+ break;
+ }
+ case 0xf9: { // sbc aby(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAby(cpu, &low, false);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xfa: { // plx imp
+ if(cpu->xf) {
+ cpu->x = cpu_pullByte(cpu);
+ } else {
+ cpu->cyclesUsed++; // 16-bit x: 1 extra cycle
+ cpu->x = cpu_pullWord(cpu);
+ }
+ cpu_setZN(cpu, cpu->x, cpu->xf);
+ break;
+ }
+ case 0xfb: { // xce imp
+ bool temp = cpu->c;
+ cpu->c = cpu->e;
+ cpu->e = temp;
+ cpu_setFlags(cpu, cpu_getFlags(cpu)); // updates x and m flags, clears upper half of x and y if needed
+ break;
+ }
+ case 0xfc: { // jsr iax
+ uint16_t value = cpu_adrIax(cpu);
+ cpu_pushWord(cpu, cpu->pc - 1);
+ cpu->pc = value;
+ break;
+ }
+ case 0xfd: { // sbc abx(r)
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, false);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ case 0xfe: { // inc abx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAbx(cpu, &low, true);
+ cpu_inc(cpu, low, high);
+ break;
+ }
+ case 0xff: { // sbc alx
+ uint32_t low = 0;
+ uint32_t high = cpu_adrAlx(cpu, &low);
+ cpu_sbc(cpu, low, high);
+ break;
+ }
+ }
+}
--- /dev/null
+++ b/snes/cpu.h
@@ -1,0 +1,58 @@
+
+#ifndef CPU_H
+#define CPU_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "saveload.h"
+
+typedef struct Cpu Cpu;
+
+struct Cpu {
+ // reference to memory handler, for reading//writing
+ void* mem;
+ uint8_t memType; // used to define which type mem is
+ // registers
+ uint16_t a;
+ uint16_t x;
+ uint16_t y;
+ uint16_t sp;
+ uint16_t pc;
+ uint16_t dp; // direct page (D)
+ uint8_t k; // program bank (PB)
+ uint8_t db; // data bank (B)
+ // flags
+ bool c;
+ bool z;
+ bool v;
+ bool n;
+ bool i;
+ bool d;
+ bool xf;
+ bool mf;
+ bool e;
+ // interrupts
+ bool irqWanted;
+ bool nmiWanted;
+ // power state (WAI/STP)
+ bool waiting;
+ bool stopped;
+ // internal use
+ uint8_t cyclesUsed; // indicates how many cycles an opcode used
+ uint16_t spBreakpoint;
+ bool in_emu;
+};
+
+Cpu* cpu_init(void* mem, int memType);
+void cpu_free(Cpu* cpu);
+void cpu_reset(Cpu* cpu);
+int cpu_runOpcode(Cpu* cpu);
+void cpu_saveload(Cpu *cpu, SaveLoadFunc *func, void *ctx);
+uint8_t cpu_getFlags(Cpu *cpu);
+void cpu_setFlags(Cpu *cpu, uint8_t val);
+
+#endif
--- /dev/null
+++ b/snes/dma.cpp
@@ -1,0 +1,328 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include "dma.h"
+#include "snes.h"
+#include "../snes_regs.h"
+static const int 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 int transferLength[8] = {
+ 1, 2, 2, 4, 4, 4, 2, 4
+};
+
+static void dma_transferByte(Dma* dma, uint16_t aAdr, uint8_t aBank, uint8_t bAdr, bool fromB);
+
+Dma* dma_init(Snes* snes) {
+ Dma* dma = (Dma*)malloc(sizeof(Dma));
+ dma->snes = snes;
+ return dma;
+}
+
+void dma_free(Dma* dma) {
+ free(dma);
+}
+
+void dma_reset(Dma* dma) {
+ for(int i = 0; i < 8; i++) {
+ dma->channel[i].bAdr = 0xff;
+ dma->channel[i].aAdr = 0xffff;
+ dma->channel[i].aBank = 0xff;
+ dma->channel[i].size = 0xffff;
+ dma->channel[i].indBank = 0xff;
+ dma->channel[i].tableAdr = 0xffff;
+ dma->channel[i].repCount = 0xff;
+ dma->channel[i].unusedByte = 0xff;
+ dma->channel[i].dmaActive = false;
+ dma->channel[i].hdmaActive = false;
+ dma->channel[i].mode = 7;
+ dma->channel[i].fixed = true;
+ dma->channel[i].decrement = true;
+ dma->channel[i].indirect = true;
+ dma->channel[i].fromB = true;
+ dma->channel[i].unusedBit = true;
+ dma->channel[i].doTransfer = false;
+ dma->channel[i].terminated = false;
+ dma->channel[i].offIndex = 0;
+ }
+ dma->hdmaTimer = 0;
+ dma->dmaTimer = 0;
+ dma->dmaBusy = false;
+}
+
+void dma_saveload(Dma *dma, SaveLoadFunc *func, void *ctx) {
+ func(ctx, &dma->channel, sizeof(Dma) - offsetof(Dma, channel));
+}
+
+uint8_t dma_read(Dma* dma, uint16_t adr) {
+ uint8_t c = (adr & 0x70) >> 4;
+ switch(adr & 0xf) {
+ case 0x0: {
+ uint8_t val = dma->channel[c].mode;
+ val |= dma->channel[c].fixed << 3;
+ val |= dma->channel[c].decrement << 4;
+ val |= dma->channel[c].unusedBit << 5;
+ val |= dma->channel[c].indirect << 6;
+ val |= dma->channel[c].fromB << 7;
+ return val;
+ }
+ case 0x1: {
+ return dma->channel[c].bAdr;
+ }
+ case 0x2: {
+ return dma->channel[c].aAdr & 0xff;
+ }
+ case 0x3: {
+ return dma->channel[c].aAdr >> 8;
+ }
+ case 0x4: {
+ return dma->channel[c].aBank;
+ }
+ case 0x5: {
+ return dma->channel[c].size & 0xff;
+ }
+ case 0x6: {
+ return dma->channel[c].size >> 8;
+ }
+ case 0x7: {
+ return dma->channel[c].indBank;
+ }
+ case 0x8: {
+ return dma->channel[c].tableAdr & 0xff;
+ }
+ case 0x9: {
+ return dma->channel[c].tableAdr >> 8;
+ }
+ case 0xa: {
+ return dma->channel[c].repCount;
+ }
+ case 0xb:
+ case 0xf: {
+ return dma->channel[c].unusedByte;
+ }
+ default: {
+ return dma->snes->openBus;
+ }
+ }
+}
+
+void dma_write(Dma* dma, uint16_t adr, uint8_t val) {
+ uint8_t c = (adr & 0x70) >> 4;
+ switch(adr & 0xf) {
+ case 0x0: {
+
+ dma->channel[c].mode = val & 0x7;
+ dma->channel[c].fixed = val & 0x8;
+ dma->channel[c].decrement = val & 0x10;
+ dma->channel[c].unusedBit = val & 0x20;
+ dma->channel[c].indirect = val & 0x40;
+ dma->channel[c].fromB = val & 0x80;
+ break;
+ }
+ case 0x1: {
+ dma->channel[c].bAdr = val;
+ break;
+ }
+ case 0x2: {
+ dma->channel[c].aAdr = (dma->channel[c].aAdr & 0xff00) | val;
+ break;
+ }
+ case 0x3: {
+ dma->channel[c].aAdr = (dma->channel[c].aAdr & 0xff) | (val << 8);
+ break;
+ }
+ case 0x4: {
+ dma->channel[c].aBank = val;
+ break;
+ }
+ case 0x5: {
+ dma->channel[c].size = (dma->channel[c].size & 0xff00) | val;
+ break;
+ }
+ case 0x6: {
+ dma->channel[c].size = (dma->channel[c].size & 0xff) | (val << 8);
+ break;
+ }
+ case 0x7: {
+ dma->channel[c].indBank = val;
+ break;
+ }
+ case 0x8: {
+ dma->channel[c].tableAdr = (dma->channel[c].tableAdr & 0xff00) | val;
+ break;
+ }
+ case 0x9: {
+ dma->channel[c].tableAdr = (dma->channel[c].tableAdr & 0xff) | (val << 8);
+ break;
+ }
+ case 0xa: {
+ dma->channel[c].repCount = val;
+ break;
+ }
+ case 0xb:
+ case 0xf: {
+ dma->channel[c].unusedByte = val;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+void dma_doDma(Dma* dma) {
+ /*if(dma->dmaTimer > 0) {
+ dma->dmaTimer -= 2;
+ return;
+ }*/
+ // figure out first channel that is active
+ int i = 0;
+ for(i = 0; i < 8; i++) {
+ if(dma->channel[i].dmaActive) {
+ break;
+ }
+ }
+ if(i == 8) {
+ // no active channels
+ dma->dmaBusy = false;
+ return;
+ }
+ // do channel i
+ dma_transferByte(
+ dma, dma->channel[i].aAdr, dma->channel[i].aBank,
+ dma->channel[i].bAdr + bAdrOffsets[dma->channel[i].mode][dma->channel[i].offIndex++], dma->channel[i].fromB
+ );
+ dma->channel[i].offIndex &= 3;
+ dma->dmaTimer += 6; // 8 cycles for each byte taken, -2 for this cycle
+ if(!dma->channel[i].fixed) {
+ dma->channel[i].aAdr += dma->channel[i].decrement ? -1 : 1;
+ }
+ dma->channel[i].size--;
+ if(dma->channel[i].size == 0) {
+ dma->channel[i].offIndex = 0; // reset offset index
+ dma->channel[i].dmaActive = false;
+ dma->dmaTimer += 8; // 8 cycle overhead per channel
+ }
+}
+
+void dma_initHdma(Dma* dma) {
+ dma->hdmaTimer = 0;
+ bool hdmaHappened = false;
+ for(int i = 0; i < 8; i++) {
+ if(dma->channel[i].hdmaActive) {
+ hdmaHappened = true;
+ // terminate any dma
+ dma->channel[i].dmaActive = false;
+ dma->channel[i].offIndex = 0;
+ // load address, repCount, and indirect address if needed
+ dma->channel[i].tableAdr = dma->channel[i].aAdr;
+ dma->channel[i].repCount = snes_read(dma->snes, (dma->channel[i].aBank << 16) | dma->channel[i].tableAdr++);
+ dma->hdmaTimer += 8; // 8 cycle overhead for each active channel
+ if(dma->channel[i].indirect) {
+ dma->channel[i].size = snes_read(dma->snes, (dma->channel[i].aBank << 16) | dma->channel[i].tableAdr++);
+ dma->channel[i].size |= snes_read(dma->snes, (dma->channel[i].aBank << 16) | dma->channel[i].tableAdr++) << 8;
+ dma->hdmaTimer += 16; // another 16 cycles for indirect (total 24)
+ }
+ dma->channel[i].doTransfer = true;
+ } else {
+ dma->channel[i].doTransfer = false;
+ }
+ dma->channel[i].terminated = false;
+ }
+ if(hdmaHappened) dma->hdmaTimer += 16; // 18 cycles overhead, -2 for this cycle
+}
+
+void dma_doHdma(Dma* dma) {
+ dma->hdmaTimer = 0;
+ bool hdmaHappened = false;
+ for(int i = 0; i < 8; i++) {
+ if(dma->channel[i].hdmaActive && !dma->channel[i].terminated) {
+ hdmaHappened = true;
+ // terminate any dma
+ dma->channel[i].dmaActive = false;
+ dma->channel[i].offIndex = 0;
+ // do the hdma
+ dma->hdmaTimer += 8; // 8 cycles overhead for each active channel
+ if(dma->channel[i].doTransfer) {
+ for(int j = 0; j < transferLength[dma->channel[i].mode]; j++) {
+ dma->hdmaTimer += 8; // 8 cycles for each byte transferred
+ if(dma->channel[i].indirect) {
+ dma_transferByte(
+ dma, dma->channel[i].size++, dma->channel[i].indBank,
+ dma->channel[i].bAdr + bAdrOffsets[dma->channel[i].mode][j], dma->channel[i].fromB
+ );
+ } else {
+ dma_transferByte(
+ dma, dma->channel[i].tableAdr++, dma->channel[i].aBank,
+ dma->channel[i].bAdr + bAdrOffsets[dma->channel[i].mode][j], dma->channel[i].fromB
+ );
+ }
+ }
+ }
+ dma->channel[i].repCount--;
+ dma->channel[i].doTransfer = dma->channel[i].repCount & 0x80;
+ if((dma->channel[i].repCount & 0x7f) == 0) {
+ dma->channel[i].repCount = snes_read(dma->snes, (dma->channel[i].aBank << 16) | dma->channel[i].tableAdr++);
+ if(dma->channel[i].indirect) {
+ // TODO: oddness with not fetching high byte if last active channel and reCount is 0
+ dma->channel[i].size = snes_read(dma->snes, (dma->channel[i].aBank << 16) | dma->channel[i].tableAdr++);
+ dma->channel[i].size |= snes_read(dma->snes, (dma->channel[i].aBank << 16) | dma->channel[i].tableAdr++) << 8;
+ dma->hdmaTimer += 16; // 16 cycles for new indirect address
+ }
+ if(dma->channel[i].repCount == 0) dma->channel[i].terminated = true;
+ dma->channel[i].doTransfer = true;
+ }
+ }
+ }
+ if(hdmaHappened) dma->hdmaTimer += 16; // 18 cycles overhead, -2 for this cycle
+}
+
+static void dma_transferByte(Dma* dma, uint16_t aAdr, uint8_t aBank, uint8_t bAdr, bool fromB) {
+ // TODO: invalid writes:
+ // accesing b-bus via a-bus gives open bus,
+ // $2180-$2183 while accessing ram via a-bus open busses $2180-$2183
+ // cannot access $4300-$437f (dma regs), or $420b / $420c
+ if(fromB) {
+ snes_write(dma->snes, (aBank << 16) | aAdr, snes_readBBus(dma->snes, bAdr));
+ } else {
+ uint8_t data = snes_read(dma->snes, (aBank << 16) | aAdr);
+ snes_writeBBus(dma->snes, bAdr, data);
+ }
+}
+
+bool dma_cycle(Dma* dma) {
+ if(dma->hdmaTimer > 0) {
+ dma->hdmaTimer -= 2;
+ return true;
+ } else if(dma->dmaBusy) {
+ dma_doDma(dma);
+ return true;
+ }
+ return false;
+}
+
+void dma_startDma(Dma* dma, uint8_t val, bool hdma) {
+ for(int i = 0; i < 8; i++) {
+ if(hdma) {
+ dma->channel[i].hdmaActive = val & (1 << i);
+ } else {
+ dma->channel[i].dmaActive = val & (1 << i);
+ }
+ }
+ if(!hdma) {
+ dma->dmaBusy = val;
+ dma->dmaTimer += dma->dmaBusy ? 16 : 0; // 12-24 cycle overhead for entire dma transfer
+ }
+}
--- /dev/null
+++ b/snes/dma.h
@@ -1,0 +1,57 @@
+
+#ifndef DMA_H
+#define DMA_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct Dma Dma;
+
+#include "snes.h"
+
+typedef struct DmaChannel {
+ uint8_t bAdr;
+ uint8_t aBank;
+ uint8_t indBank; // hdma
+ uint8_t repCount; // hdma
+ uint16_t aAdr;
+ uint16_t size; // also indirect hdma adr
+ uint16_t tableAdr; // hdma
+ uint8_t unusedByte;
+ bool dmaActive;
+ bool hdmaActive;
+ uint8_t mode;
+ bool fixed;
+ bool decrement;
+ bool indirect; // hdma
+ bool fromB;
+ bool unusedBit;
+ bool doTransfer; // hdma
+ bool terminated; // hdma
+ uint8_t offIndex;
+} DmaChannel;
+
+struct Dma {
+ Snes* snes;
+ DmaChannel channel[8];
+ uint16_t hdmaTimer;
+ uint32_t dmaTimer;
+ bool dmaBusy;
+};
+
+Dma* dma_init(Snes* snes);
+void dma_free(Dma* dma);
+void dma_reset(Dma* dma);
+uint8_t dma_read(Dma* dma, uint16_t adr); // 43x0-43xf
+void dma_write(Dma* dma, uint16_t adr, uint8_t val); // 43x0-43xf
+void dma_doDma(Dma* dma);
+void dma_initHdma(Dma* dma);
+void dma_doHdma(Dma* dma);
+bool dma_cycle(Dma* dma);
+void dma_startDma(Dma* dma, uint8_t val, bool hdma);
+void dma_saveload(Dma *dma, SaveLoadFunc *func, void *ctx);
+
+#endif
--- /dev/null
+++ b/snes/dsp.cpp
@@ -1,0 +1,578 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include "dsp.h"
+
+#define MY_CHANGES 1
+
+static const int rateValues[32] = {
+ 0, 2048, 1536, 1280, 1024, 768, 640, 512,
+ 384, 320, 256, 192, 160, 128, 96, 80,
+ 64, 48, 40, 32, 24, 20, 16, 12,
+ 10, 8, 6, 5, 4, 3, 2, 1
+};
+
+static const int gaussValues[512] = {
+ 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
+ 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002,
+ 0x002, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, 0x004, 0x004, 0x004, 0x004, 0x005, 0x005, 0x005, 0x005,
+ 0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007, 0x008, 0x008, 0x008, 0x009, 0x009, 0x009, 0x00A, 0x00A, 0x00A,
+ 0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00D, 0x00D, 0x00E, 0x00E, 0x00F, 0x00F, 0x00F, 0x010, 0x010, 0x011, 0x011,
+ 0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016, 0x017, 0x017, 0x018, 0x018, 0x019, 0x01A, 0x01B, 0x01B,
+ 0x01C, 0x01D, 0x01D, 0x01E, 0x01F, 0x020, 0x020, 0x021, 0x022, 0x023, 0x024, 0x024, 0x025, 0x026, 0x027, 0x028,
+ 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038,
+ 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x040, 0x041, 0x042, 0x043, 0x045, 0x046, 0x047, 0x049, 0x04A, 0x04C, 0x04D,
+ 0x04E, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059, 0x05A, 0x05C, 0x05E, 0x05F, 0x061, 0x063, 0x064, 0x066,
+ 0x068, 0x06A, 0x06B, 0x06D, 0x06F, 0x071, 0x073, 0x075, 0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x080, 0x082, 0x084,
+ 0x086, 0x089, 0x08B, 0x08D, 0x08F, 0x091, 0x093, 0x096, 0x098, 0x09A, 0x09C, 0x09F, 0x0A1, 0x0A3, 0x0A6, 0x0A8,
+ 0x0AB, 0x0AD, 0x0AF, 0x0B2, 0x0B4, 0x0B7, 0x0BA, 0x0BC, 0x0BF, 0x0C1, 0x0C4, 0x0C7, 0x0C9, 0x0CC, 0x0CF, 0x0D2,
+ 0x0D4, 0x0D7, 0x0DA, 0x0DD, 0x0E0, 0x0E3, 0x0E6, 0x0E9, 0x0EC, 0x0EF, 0x0F2, 0x0F5, 0x0F8, 0x0FB, 0x0FE, 0x101,
+ 0x104, 0x107, 0x10B, 0x10E, 0x111, 0x114, 0x118, 0x11B, 0x11E, 0x122, 0x125, 0x129, 0x12C, 0x130, 0x133, 0x137,
+ 0x13A, 0x13E, 0x141, 0x145, 0x148, 0x14C, 0x150, 0x153, 0x157, 0x15B, 0x15F, 0x162, 0x166, 0x16A, 0x16E, 0x172,
+ 0x176, 0x17A, 0x17D, 0x181, 0x185, 0x189, 0x18D, 0x191, 0x195, 0x19A, 0x19E, 0x1A2, 0x1A6, 0x1AA, 0x1AE, 0x1B2,
+ 0x1B7, 0x1BB, 0x1BF, 0x1C3, 0x1C8, 0x1CC, 0x1D0, 0x1D5, 0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1EB, 0x1EF, 0x1F3, 0x1F8,
+ 0x1FC, 0x201, 0x205, 0x20A, 0x20F, 0x213, 0x218, 0x21C, 0x221, 0x226, 0x22A, 0x22F, 0x233, 0x238, 0x23D, 0x241,
+ 0x246, 0x24B, 0x250, 0x254, 0x259, 0x25E, 0x263, 0x267, 0x26C, 0x271, 0x276, 0x27B, 0x280, 0x284, 0x289, 0x28E,
+ 0x293, 0x298, 0x29D, 0x2A2, 0x2A6, 0x2AB, 0x2B0, 0x2B5, 0x2BA, 0x2BF, 0x2C4, 0x2C9, 0x2CE, 0x2D3, 0x2D8, 0x2DC,
+ 0x2E1, 0x2E6, 0x2EB, 0x2F0, 0x2F5, 0x2FA, 0x2FF, 0x304, 0x309, 0x30E, 0x313, 0x318, 0x31D, 0x322, 0x326, 0x32B,
+ 0x330, 0x335, 0x33A, 0x33F, 0x344, 0x349, 0x34E, 0x353, 0x357, 0x35C, 0x361, 0x366, 0x36B, 0x370, 0x374, 0x379,
+ 0x37E, 0x383, 0x388, 0x38C, 0x391, 0x396, 0x39B, 0x39F, 0x3A4, 0x3A9, 0x3AD, 0x3B2, 0x3B7, 0x3BB, 0x3C0, 0x3C5,
+ 0x3C9, 0x3CE, 0x3D2, 0x3D7, 0x3DC, 0x3E0, 0x3E5, 0x3E9, 0x3ED, 0x3F2, 0x3F6, 0x3FB, 0x3FF, 0x403, 0x408, 0x40C,
+ 0x410, 0x415, 0x419, 0x41D, 0x421, 0x425, 0x42A, 0x42E, 0x432, 0x436, 0x43A, 0x43E, 0x442, 0x446, 0x44A, 0x44E,
+ 0x452, 0x455, 0x459, 0x45D, 0x461, 0x465, 0x468, 0x46C, 0x470, 0x473, 0x477, 0x47A, 0x47E, 0x481, 0x485, 0x488,
+ 0x48C, 0x48F, 0x492, 0x496, 0x499, 0x49C, 0x49F, 0x4A2, 0x4A6, 0x4A9, 0x4AC, 0x4AF, 0x4B2, 0x4B5, 0x4B7, 0x4BA,
+ 0x4BD, 0x4C0, 0x4C3, 0x4C5, 0x4C8, 0x4CB, 0x4CD, 0x4D0, 0x4D2, 0x4D5, 0x4D7, 0x4D9, 0x4DC, 0x4DE, 0x4E0, 0x4E3,
+ 0x4E5, 0x4E7, 0x4E9, 0x4EB, 0x4ED, 0x4EF, 0x4F1, 0x4F3, 0x4F5, 0x4F6, 0x4F8, 0x4FA, 0x4FB, 0x4FD, 0x4FF, 0x500,
+ 0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50A, 0x50B, 0x50C, 0x50D, 0x50E, 0x50F, 0x510, 0x511, 0x511, 0x512,
+ 0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517, 0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519
+};
+
+static void dsp_cycleChannel(Dsp* dsp, int ch);
+static void dsp_handleEcho(Dsp* dsp, int* outputL, int* outputR);
+static void dsp_handleGain(Dsp* dsp, int ch);
+static void dsp_decodeBrr(Dsp* dsp, int ch);
+static int16_t dsp_getSample(Dsp* dsp, int ch, int sampleNum, int offset);
+static void dsp_handleNoise(Dsp* dsp);
+
+Dsp* dsp_init(uint8_t *apu_ram) {
+ Dsp* dsp = (Dsp*)malloc(sizeof(Dsp));
+ dsp->apu_ram = apu_ram;
+ return dsp;
+}
+
+void dsp_free(Dsp* dsp) {
+ free(dsp);
+}
+
+void dsp_reset(Dsp* dsp) {
+ memset(dsp->ram, 0, sizeof(dsp->ram));
+ dsp->ram[0x7c] = 0xff; // set ENDx
+ for(int i = 0; i < 8; i++) {
+ dsp->channel[i].pitch = 0;
+ dsp->channel[i].pitchCounter = 0;
+ dsp->channel[i].pitchModulation = false;
+ memset(dsp->channel[i].decodeBuffer, 0, sizeof(dsp->channel[i].decodeBuffer));
+ dsp->channel[i].srcn = 0;
+ dsp->channel[i].decodeOffset = 0;
+ dsp->channel[i].previousFlags = 0;
+ dsp->channel[i].old = 0;
+ dsp->channel[i].older = 0;
+ dsp->channel[i].useNoise = false;
+ memset(dsp->channel[i].adsrRates, 0, sizeof(dsp->channel[i].adsrRates));
+ dsp->channel[i].rateCounter = 0;
+ dsp->channel[i].adsrState = 0;
+ dsp->channel[i].sustainLevel = 0;
+ dsp->channel[i].useGain = false;
+ dsp->channel[i].gainMode = 0;
+ dsp->channel[i].directGain = false;
+ dsp->channel[i].gainValue = 0;
+ dsp->channel[i].gain = 0;
+ dsp->channel[i].keyOn = false;
+ dsp->channel[i].keyOff = false;
+ dsp->channel[i].sampleOut = 0;
+ dsp->channel[i].volumeL = 0;
+ dsp->channel[i].volumeR = 0;
+ dsp->channel[i].echoEnable = false;
+ }
+ dsp->dirPage = 0;
+ dsp->evenCycle = false;
+ dsp->mute = true;
+ dsp->reset = true;
+ dsp->masterVolumeL = 0;
+ dsp->masterVolumeR = 0;
+ dsp->noiseSample = -0x4000;
+ dsp->noiseRate = 0;
+ dsp->noiseCounter = 0;
+ dsp->echoWrites = false;
+ dsp->echoVolumeL = 0;
+ dsp->echoVolumeR = 0;
+ dsp->feedbackVolume = 0;
+ dsp->echoBufferAdr = 0;
+ dsp->echoDelay = 1;
+ dsp->echoRemain = 1;
+ dsp->echoBufferIndex = 0;
+ dsp->firBufferIndex = 0;
+ memset(dsp->firValues, 0, sizeof(dsp->firValues));
+ memset(dsp->firBufferL, 0, sizeof(dsp->firBufferL));
+ memset(dsp->firBufferR, 0, sizeof(dsp->firBufferR));
+ memset(dsp->sampleBuffer, 0, sizeof(dsp->sampleBuffer));
+ dsp->sampleOffset = 0;
+}
+
+void dsp_saveload(Dsp *dsp, SaveLoadFunc *func, void *ctx) {
+ func(ctx, &dsp->ram, sizeof(Dsp) - offsetof(Dsp, ram));
+}
+
+void dsp_cycle(Dsp* dsp) {
+ int totalL = 0;
+ int totalR = 0;
+ for(int i = 0; i < 8; i++) {
+ dsp_cycleChannel(dsp, i);
+ totalL += (dsp->channel[i].sampleOut * dsp->channel[i].volumeL) >> 6;
+ totalR += (dsp->channel[i].sampleOut * dsp->channel[i].volumeR) >> 6;
+ totalL = totalL < -0x8000 ? -0x8000 : (totalL > 0x7fff ? 0x7fff : totalL); // clamp 16-bit
+ totalR = totalR < -0x8000 ? -0x8000 : (totalR > 0x7fff ? 0x7fff : totalR); // clamp 16-bit
+ }
+ totalL = (totalL * dsp->masterVolumeL) >> 7;
+ totalR = (totalR * dsp->masterVolumeR) >> 7;
+ totalL = totalL < -0x8000 ? -0x8000 : (totalL > 0x7fff ? 0x7fff : totalL); // clamp 16-bit
+ totalR = totalR < -0x8000 ? -0x8000 : (totalR > 0x7fff ? 0x7fff : totalR); // clamp 16-bit
+ dsp_handleEcho(dsp, &totalL, &totalR);
+ if(dsp->mute) {
+ totalL = 0;
+ totalR = 0;
+ }
+ dsp_handleNoise(dsp);
+ // put it in the samplebuffer, if space
+ if (dsp->sampleOffset < 534) {
+ dsp->sampleBuffer[dsp->sampleOffset * 2] = totalL;
+ dsp->sampleBuffer[dsp->sampleOffset * 2 + 1] = totalR;
+ dsp->sampleOffset++;
+ }
+ dsp->evenCycle = !dsp->evenCycle;
+}
+
+static void dsp_handleEcho(Dsp* dsp, int* outputL, int* outputR) {
+ // get value out of ram
+ uint16_t adr = dsp->echoBufferAdr + dsp->echoBufferIndex * 4;
+ dsp->firBufferL[dsp->firBufferIndex] = (
+ dsp->apu_ram[adr] + (dsp->apu_ram[(adr + 1) & 0xffff] << 8)
+ );
+ dsp->firBufferL[dsp->firBufferIndex] >>= 1;
+ dsp->firBufferR[dsp->firBufferIndex] = (
+ dsp->apu_ram[(adr + 2) & 0xffff] + (dsp->apu_ram[(adr + 3) & 0xffff] << 8)
+ );
+ dsp->firBufferR[dsp->firBufferIndex] >>= 1;
+ // calculate FIR-sum
+ int sumL = 0, sumR = 0;
+ for(int i = 0; i < 8; i++) {
+ sumL += (dsp->firBufferL[(dsp->firBufferIndex + i + 1) & 0x7] * dsp->firValues[i]) >> 6;
+ sumR += (dsp->firBufferR[(dsp->firBufferIndex + i + 1) & 0x7] * dsp->firValues[i]) >> 6;
+ if(i == 6) {
+ // clip to 16-bit before last addition
+ sumL = ((int16_t) (sumL & 0xffff)); // clip 16-bit
+ sumR = ((int16_t) (sumR & 0xffff)); // clip 16-bit
+ }
+ }
+ sumL = sumL < -0x8000 ? -0x8000 : (sumL > 0x7fff ? 0x7fff : sumL); // clamp 16-bit
+ sumR = sumR < -0x8000 ? -0x8000 : (sumR > 0x7fff ? 0x7fff : sumR); // clamp 16-bit
+ // modify output with sum
+ int outL = *outputL + ((sumL * dsp->echoVolumeL) >> 7);
+ int outR = *outputR + ((sumR * dsp->echoVolumeR) >> 7);
+ *outputL = outL < -0x8000 ? -0x8000 : (outL > 0x7fff ? 0x7fff : outL); // clamp 16-bit
+ *outputR = outR < -0x8000 ? -0x8000 : (outR > 0x7fff ? 0x7fff : outR); // clamp 16-bit
+ // get echo input
+ int inL = 0, inR = 0;
+ for(int i = 0; i < 8; i++) {
+ if(dsp->channel[i].echoEnable) {
+ inL += (dsp->channel[i].sampleOut * dsp->channel[i].volumeL) >> 6;
+ inR += (dsp->channel[i].sampleOut * dsp->channel[i].volumeR) >> 6;
+ inL = inL < -0x8000 ? -0x8000 : (inL > 0x7fff ? 0x7fff : inL); // clamp 16-bit
+ inR = inR < -0x8000 ? -0x8000 : (inR > 0x7fff ? 0x7fff : inR); // clamp 16-bit
+ }
+ }
+ // write this to ram
+ inL += (sumL * dsp->feedbackVolume) >> 7;
+ inR += (sumR * dsp->feedbackVolume) >> 7;
+ inL = inL < -0x8000 ? -0x8000 : (inL > 0x7fff ? 0x7fff : inL); // clamp 16-bit
+ inR = inR < -0x8000 ? -0x8000 : (inR > 0x7fff ? 0x7fff : inR); // clamp 16-bit
+ inL &= 0xfffe;
+ inR &= 0xfffe;
+ if(dsp->echoWrites) {
+ dsp->apu_ram[adr] = inL & 0xff;
+ dsp->apu_ram[(adr + 1) & 0xffff] = inL >> 8;
+ dsp->apu_ram[(adr + 2) & 0xffff] = inR & 0xff;
+ dsp->apu_ram[(adr + 3) & 0xffff] = inR >> 8;
+ }
+ // handle indexes
+ dsp->firBufferIndex++;
+ dsp->firBufferIndex &= 7;
+ dsp->echoBufferIndex++;
+ dsp->echoRemain--;
+ if(dsp->echoRemain == 0) {
+ dsp->echoRemain = dsp->echoDelay;
+ dsp->echoBufferIndex = 0;
+ }
+}
+
+static void dsp_cycleChannel(Dsp* dsp, int ch) {
+ // handle pitch counter
+ uint16_t pitch = dsp->channel[ch].pitch;
+ if(ch > 0 && dsp->channel[ch].pitchModulation) {
+ int factor = (dsp->channel[ch - 1].sampleOut >> 4) + 0x400;
+ pitch = (pitch * factor) >> 10;
+ if(pitch > 0x3fff) pitch = 0x3fff;
+ }
+ int newCounter = dsp->channel[ch].pitchCounter + pitch;
+ if(newCounter > 0xffff) {
+ // next sample
+ dsp_decodeBrr(dsp, ch);
+ }
+ dsp->channel[ch].pitchCounter = newCounter;
+ int16_t sample = 0;
+ if(dsp->channel[ch].useNoise) {
+ sample = dsp->noiseSample;
+ } else {
+ sample = dsp_getSample(dsp, ch, dsp->channel[ch].pitchCounter >> 12, (dsp->channel[ch].pitchCounter >> 4) & 0xff);
+ }
+#if !MY_CHANGES
+ if(dsp->evenCycle) {
+ // handle keyon/off (every other cycle)
+ if(dsp->channel[ch].keyOff) {
+ // go to release
+ dsp->channel[ch].adsrState = 4;
+ } else if(dsp->channel[ch].keyOn) {
+ dsp->channel[ch].keyOn = false;
+ // restart current sample
+ dsp->channel[ch].previousFlags = 0;
+ uint16_t samplePointer = dsp->dirPage + 4 * dsp->channel[ch].srcn;
+ dsp->channel[ch].decodeOffset = dsp->apu_ram[samplePointer];
+ dsp->channel[ch].decodeOffset |= dsp->apu_ram[(samplePointer + 1) & 0xffff] << 8;
+ memset(dsp->channel[ch].decodeBuffer, 0, sizeof(dsp->channel[ch].decodeBuffer));
+ dsp->channel[ch].gain = 0;
+ dsp->channel[ch].adsrState = dsp->channel[ch].useGain ? 3 : 0;
+ }
+ }
+#endif
+ // handle reset
+ if(dsp->reset) {
+ dsp->channel[ch].adsrState = 4;
+ dsp->channel[ch].gain = 0;
+ }
+ // handle envelope/adsr
+ bool doingDirectGain = dsp->channel[ch].adsrState != 4 && dsp->channel[ch].useGain && dsp->channel[ch].directGain;
+ uint16_t rate = dsp->channel[ch].adsrState == 4 ? 0 : dsp->channel[ch].adsrRates[dsp->channel[ch].adsrState];
+ if(dsp->channel[ch].adsrState != 4 && !doingDirectGain && rate != 0) {
+ dsp->channel[ch].rateCounter++;
+ }
+ if(dsp->channel[ch].adsrState == 4 || (!doingDirectGain && dsp->channel[ch].rateCounter >= rate && rate != 0)) {
+ if(dsp->channel[ch].adsrState != 4) dsp->channel[ch].rateCounter = 0;
+ dsp_handleGain(dsp, ch);
+ }
+ if(doingDirectGain) dsp->channel[ch].gain = dsp->channel[ch].gainValue;
+ // set outputs
+ dsp->ram[(ch << 4) | 8] = dsp->channel[ch].gain >> 4;
+ sample = (sample * dsp->channel[ch].gain) >> 11;
+ dsp->ram[(ch << 4) | 9] = sample >> 7;
+ dsp->channel[ch].sampleOut = sample;
+}
+
+static void dsp_handleGain(Dsp* dsp, int ch) {
+ switch(dsp->channel[ch].adsrState) {
+ case 0: { // attack
+ uint16_t rate = dsp->channel[ch].adsrRates[dsp->channel[ch].adsrState];
+ dsp->channel[ch].gain += rate == 1 ? 1024 : 32;
+ if(dsp->channel[ch].gain >= 0x7e0) dsp->channel[ch].adsrState = 1;
+ if(dsp->channel[ch].gain > 0x7ff) dsp->channel[ch].gain = 0x7ff;
+ break;
+ }
+ case 1: { // decay
+ dsp->channel[ch].gain -= ((dsp->channel[ch].gain - 1) >> 8) + 1;
+ if(dsp->channel[ch].gain < dsp->channel[ch].sustainLevel) dsp->channel[ch].adsrState = 2;
+ break;
+ }
+ case 2: { // sustain
+ dsp->channel[ch].gain -= ((dsp->channel[ch].gain - 1) >> 8) + 1;
+ break;
+ }
+ case 3: { // gain
+ switch(dsp->channel[ch].gainMode) {
+ case 0: { // linear decrease
+ dsp->channel[ch].gain -= 32;
+ // decreasing below 0 will underflow to above 0x7ff
+ if(dsp->channel[ch].gain > 0x7ff) dsp->channel[ch].gain = 0;
+ break;
+ }
+ case 1: { // exponential decrease
+ dsp->channel[ch].gain -= ((dsp->channel[ch].gain - 1) >> 8) + 1;
+ break;
+ }
+ case 2: { // linear increase
+ dsp->channel[ch].gain += 32;
+ if(dsp->channel[ch].gain > 0x7ff) dsp->channel[ch].gain = 0;
+ break;
+ }
+ case 3: { // bent increase
+ dsp->channel[ch].gain += dsp->channel[ch].gain < 0x600 ? 32 : 8;
+ if(dsp->channel[ch].gain > 0x7ff) dsp->channel[ch].gain = 0;
+ break;
+ }
+ }
+ break;
+ }
+ case 4: { // release
+ dsp->channel[ch].gain -= 8;
+ // decreasing below 0 will underflow to above 0x7ff
+ if(dsp->channel[ch].gain > 0x7ff) dsp->channel[ch].gain = 0;
+ break;
+ }
+ }
+}
+
+static int16_t dsp_getSample(Dsp* dsp, int ch, int sampleNum, int offset) {
+ int16_t news = dsp->channel[ch].decodeBuffer[sampleNum + 3];
+ int16_t olds = dsp->channel[ch].decodeBuffer[sampleNum + 2];
+ int16_t olders = dsp->channel[ch].decodeBuffer[sampleNum + 1];
+ int16_t oldests = dsp->channel[ch].decodeBuffer[sampleNum];
+ int out = (gaussValues[0xff - offset] * oldests) >> 10;
+ out += (gaussValues[0x1ff - offset] * olders) >> 10;
+ out += (gaussValues[0x100 + offset] * olds) >> 10;
+ out = ((int16_t) (out & 0xffff)); // clip 16-bit
+ out += (gaussValues[offset] * news) >> 10;
+ out = out < -0x8000 ? -0x8000 : (out > 0x7fff ? 0x7fff : out); // clamp 16-bit
+ return out >> 1;
+}
+
+static void dsp_decodeBrr(Dsp* dsp, int ch) {
+ // copy last 3 samples (16-18) to first 3 for interpolation
+ dsp->channel[ch].decodeBuffer[0] = dsp->channel[ch].decodeBuffer[16];
+ dsp->channel[ch].decodeBuffer[1] = dsp->channel[ch].decodeBuffer[17];
+ dsp->channel[ch].decodeBuffer[2] = dsp->channel[ch].decodeBuffer[18];
+ // handle flags from previous block
+ if(dsp->channel[ch].previousFlags == 1 || dsp->channel[ch].previousFlags == 3) {
+ // loop sample
+ uint16_t samplePointer = dsp->dirPage + 4 * dsp->channel[ch].srcn;
+ dsp->channel[ch].decodeOffset = dsp->apu_ram[(samplePointer + 2) & 0xffff];
+ dsp->channel[ch].decodeOffset |= (dsp->apu_ram[(samplePointer + 3) & 0xffff]) << 8;
+ if(dsp->channel[ch].previousFlags == 1) {
+ // also release and clear gain
+ dsp->channel[ch].adsrState = 4;
+ dsp->channel[ch].gain = 0;
+ }
+ dsp->ram[0x7c] |= 1 << ch; // set ENDx
+ }
+ uint8_t header = dsp->apu_ram[dsp->channel[ch].decodeOffset++];
+ int shift = header >> 4;
+ int filter = (header & 0xc) >> 2;
+ dsp->channel[ch].previousFlags = header & 0x3;
+ uint8_t curByte = 0;
+ int old = dsp->channel[ch].old;
+ int older = dsp->channel[ch].older;
+ for(int i = 0; i < 16; i++) {
+ int s = 0;
+ if(i & 1) {
+ s = curByte & 0xf;
+ } else {
+ curByte = dsp->apu_ram[dsp->channel[ch].decodeOffset++];
+ s = curByte >> 4;
+ }
+ if(s > 7) s -= 16;
+ if(shift <= 0xc) {
+ s = (s << shift) >> 1;
+ } else {
+ s = (s >> 3) << 12;
+ }
+ switch(filter) {
+ case 1: s += old + (-old >> 4); break;
+ case 2: s += 2 * old + ((3 * -old) >> 5) - older + (older >> 4); break;
+ case 3: s += 2 * old + ((13 * -old) >> 6) - older + ((3 * older) >> 4); break;
+ }
+ s = s < -0x8000 ? -0x8000 : (s > 0x7fff ? 0x7fff : s); // clamp 16-bit
+ s = ((int16_t) ((s & 0x7fff) << 1)) >> 1; // clip 15-bit
+ older = old;
+ old = s;
+ dsp->channel[ch].decodeBuffer[i + 3] = s;
+ }
+ dsp->channel[ch].older = older;
+ dsp->channel[ch].old = old;
+}
+
+static void dsp_handleNoise(Dsp* dsp) {
+ if(dsp->noiseRate != 0) {
+ dsp->noiseCounter++;
+ }
+ if(dsp->noiseCounter >= dsp->noiseRate && dsp->noiseRate != 0) {
+ int bit = (dsp->noiseSample & 1) ^ ((dsp->noiseSample >> 1) & 1);
+ dsp->noiseSample = ((dsp->noiseSample >> 1) & 0x3fff) | (bit << 14);
+ dsp->noiseSample = ((int16_t) ((dsp->noiseSample & 0x7fff) << 1)) >> 1;
+ dsp->noiseCounter = 0;
+ }
+}
+
+uint8_t dsp_read(Dsp* dsp, uint8_t adr) {
+ return dsp->ram[adr];
+}
+
+void dsp_write(Dsp* dsp, uint8_t adr, uint8_t val) {
+ int ch = adr >> 4;
+ switch(adr) {
+ case 0x00: case 0x10: case 0x20: case 0x30: case 0x40: case 0x50: case 0x60: case 0x70: {
+ dsp->channel[ch].volumeL = val;
+ break;
+ }
+ case 0x01: case 0x11: case 0x21: case 0x31: case 0x41: case 0x51: case 0x61: case 0x71: {
+ dsp->channel[ch].volumeR = val;
+ break;
+ }
+ case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: case 0x62: case 0x72: {
+ dsp->channel[ch].pitch = (dsp->channel[ch].pitch & 0x3f00) | val;
+ break;
+ }
+ case 0x03: case 0x13: case 0x23: case 0x33: case 0x43: case 0x53: case 0x63: case 0x73: {
+ dsp->channel[ch].pitch = ((dsp->channel[ch].pitch & 0x00ff) | (val << 8)) & 0x3fff;
+ break;
+ }
+ case 0x04: case 0x14: case 0x24: case 0x34: case 0x44: case 0x54: case 0x64: case 0x74: {
+ dsp->channel[ch].srcn = val;
+ break;
+ }
+ case 0x05: case 0x15: case 0x25: case 0x35: case 0x45: case 0x55: case 0x65: case 0x75: {
+ dsp->channel[ch].adsrRates[0] = rateValues[(val & 0xf) * 2 + 1];
+ dsp->channel[ch].adsrRates[1] = rateValues[((val & 0x70) >> 4) * 2 + 16];
+ dsp->channel[ch].useGain = (val & 0x80) == 0;
+ break;
+ }
+ case 0x06: case 0x16: case 0x26: case 0x36: case 0x46: case 0x56: case 0x66: case 0x76: {
+ dsp->channel[ch].adsrRates[2] = rateValues[val & 0x1f];
+ dsp->channel[ch].sustainLevel = (((val & 0xe0) >> 5) + 1) * 0x100;
+ break;
+ }
+ case 0x07: case 0x17: case 0x27: case 0x37: case 0x47: case 0x57: case 0x67: case 0x77: {
+ dsp->channel[ch].directGain = (val & 0x80) == 0;
+ if(val & 0x80) {
+ dsp->channel[ch].gainMode = (val & 0x60) >> 5;
+ dsp->channel[ch].adsrRates[3] = rateValues[val & 0x1f];
+ } else {
+ dsp->channel[ch].gainValue = (val & 0x7f) * 16;
+ }
+ break;
+ }
+ case 0x0c: {
+ dsp->masterVolumeL = val;
+ break;
+ }
+ case 0x1c: {
+ dsp->masterVolumeR = val;
+ break;
+ }
+ case 0x2c: {
+ dsp->echoVolumeL = val;
+ break;
+ }
+ case 0x3c: {
+ dsp->echoVolumeR = val;
+ break;
+ }
+ case 0x4c: {
+ for(int ch = 0; ch < 8; ch++) {
+ dsp->channel[ch].keyOn = val & (1 << ch);
+#if MY_CHANGES
+
+ if (dsp->channel[ch].keyOn) {
+ dsp->channel[ch].keyOn = false;
+ // restart current sample
+ dsp->channel[ch].previousFlags = 0;
+ uint16_t samplePointer = dsp->dirPage + 4 * dsp->channel[ch].srcn;
+ dsp->channel[ch].decodeOffset = dsp->apu_ram[samplePointer];
+ dsp->channel[ch].decodeOffset |= dsp->apu_ram[(samplePointer + 1) & 0xffff] << 8;
+ memset(dsp->channel[ch].decodeBuffer, 0, sizeof(dsp->channel[ch].decodeBuffer));
+ dsp->channel[ch].gain = 0;
+ dsp->channel[ch].adsrState = dsp->channel[ch].useGain ? 3 : 0;
+ }
+#endif
+ }
+ break;
+ }
+ case 0x5c: {
+ for(int ch = 0; ch < 8; ch++) {
+ dsp->channel[ch].keyOff = val & (1 << ch);
+#if MY_CHANGES
+ if (dsp->channel[ch].keyOff) {
+ // go to release
+ dsp->channel[ch].adsrState = 4;
+ }
+#endif
+ }
+
+
+ break;
+ }
+ case 0x6c: {
+ dsp->reset = val & 0x80;
+ dsp->mute = val & 0x40;
+ dsp->echoWrites = (val & 0x20) == 0;
+ dsp->noiseRate = rateValues[val & 0x1f];
+ break;
+ }
+ case 0x7c: {
+ val = 0; // any write clears ENDx
+ break;
+ }
+ case 0x0d: {
+ dsp->feedbackVolume = val;
+ break;
+ }
+ case 0x2d: {
+ for(int i = 0; i < 8; i++) {
+ dsp->channel[i].pitchModulation = val & (1 << i);
+ }
+ break;
+ }
+ case 0x3d: {
+ for(int i = 0; i < 8; i++) {
+ dsp->channel[i].useNoise = val & (1 << i);
+ }
+ break;
+ }
+ case 0x4d: {
+ for(int i = 0; i < 8; i++) {
+ dsp->channel[i].echoEnable = val & (1 << i);
+ }
+ break;
+ }
+ case 0x5d: {
+ dsp->dirPage = val << 8;
+ break;
+ }
+ case 0x6d: {
+ dsp->echoBufferAdr = val << 8;
+ break;
+ }
+ case 0x7d: {
+ dsp->echoDelay = (val & 0xf) * 512; // 2048-byte steps, stereo sample is 4 bytes
+ if(dsp->echoDelay == 0) dsp->echoDelay = 1;
+ break;
+ }
+ case 0x0f: case 0x1f: case 0x2f: case 0x3f: case 0x4f: case 0x5f: case 0x6f: case 0x7f: {
+ dsp->firValues[ch] = val;
+ break;
+ }
+ }
+ dsp->ram[adr] = val;
+}
+
+void dsp_getSamples(Dsp* dsp, int16_t* sampleData, int samplesPerFrame) {
+ // resample from 534 samples per frame to wanted value
+ double adder = 534.0 / samplesPerFrame;
+ double location = 0.0;
+ for(int i = 0; i < samplesPerFrame; i++) {
+ sampleData[i * 2] = dsp->sampleBuffer[((int) location) * 2];
+ sampleData[i * 2 + 1] = dsp->sampleBuffer[((int) location) * 2 + 1];
+ location += adder;
+ }
+ dsp->sampleOffset = 0;
+}
--- /dev/null
+++ b/snes/dsp.h
@@ -1,0 +1,101 @@
+
+#ifndef DSP_H
+#define DSP_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct Dsp Dsp;
+
+#include "saveload.h"
+
+typedef struct DspChannel {
+ // pitch
+ uint16_t pitch;
+ uint16_t pitchCounter;
+ bool pitchModulation;
+ // brr decoding
+ int16_t decodeBuffer[19]; // 16 samples per brr-block, +3 for interpolation
+ uint8_t srcn;
+ uint16_t decodeOffset;
+ uint8_t previousFlags; // from last sample
+ int16_t old;
+ int16_t older;
+ bool useNoise;
+ // adsr, envelope, gain
+ uint16_t adsrRates[4]; // attack, decay, sustain, gain
+ uint16_t rateCounter;
+ uint8_t adsrState; // 0: attack, 1: decay, 2: sustain, 3: gain, 4: release
+ uint16_t sustainLevel;
+ bool useGain;
+ uint8_t gainMode;
+ bool directGain;
+ uint16_t gainValue; // for direct gain
+ uint16_t gain;
+ // keyon/off
+ bool keyOn;
+ bool keyOff;
+ // output
+ int16_t sampleOut; // final sample, to be multiplied by channel volume
+ int8_t volumeL;
+ int8_t volumeR;
+ bool echoEnable;
+} DspChannel;
+
+struct Dsp {
+ uint8_t *apu_ram;
+ // mirror ram
+ uint8_t ram[0x80];
+ // 8 channels
+ DspChannel channel[8];
+ // overarching
+ uint16_t dirPage;
+ bool evenCycle;
+ bool mute;
+ bool reset;
+ int8_t masterVolumeL;
+ int8_t masterVolumeR;
+ // noise
+ int16_t noiseSample;
+ uint16_t noiseRate;
+ uint16_t noiseCounter;
+ // echo
+ bool echoWrites;
+ int8_t echoVolumeL;
+ int8_t echoVolumeR;
+ int8_t feedbackVolume;
+ uint16_t echoBufferAdr;
+ uint16_t echoDelay;
+ uint16_t echoRemain;
+ uint16_t echoBufferIndex;
+ uint8_t firBufferIndex;
+ int8_t firValues[8];
+ int16_t firBufferL[8];
+ int16_t firBufferR[8];
+ // sample buffer (1 frame at 32040 Hz: 534 samples, *2 for stereo)
+ int16_t sampleBuffer[534 * 2];
+ uint16_t sampleOffset; // current offset in samplebuffer
+};
+
+
+#include "../dsp_regs.h"
+
+typedef struct DspRegWriteHistory {
+ uint32_t count;
+ enum DspReg addr[256];
+ uint8_t val[256];
+} DspRegWriteHistory;
+
+Dsp* dsp_init(uint8_t *apu_ram);
+void dsp_free(Dsp* dsp);
+void dsp_reset(Dsp* dsp);
+void dsp_cycle(Dsp* dsp);
+uint8_t dsp_read(Dsp* dsp, uint8_t adr);
+void dsp_write(Dsp* dsp, uint8_t adr, uint8_t val);
+void dsp_getSamples(Dsp* dsp, int16_t* sampleData, int samplesPerFrame);
+void dsp_saveload(Dsp *dsp, SaveLoadFunc *func, void *ctx);
+
+#endif
--- /dev/null
+++ b/snes/input.cpp
@@ -1,0 +1,40 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "input.h"
+#include "snes.h"
+
+Input* input_init(Snes* snes) {
+ Input* input = (Input * )malloc(sizeof(Input));
+ input->snes = snes;
+ // TODO: handle (where?)
+ input->type = 1;
+ input->currentState = 0;
+ return input;
+}
+
+void input_free(Input* input) {
+ free(input);
+}
+
+void input_reset(Input* input) {
+ input->latchLine = false;
+ input->latchedState = 0;
+}
+
+void input_cycle(Input* input) {
+ if(input->latchLine) {
+ input->latchedState = input->currentState;
+ }
+}
+
+uint8_t input_read(Input* input) {
+ uint8_t ret = input->latchedState & 1;
+ input->latchedState >>= 1;
+ input->latchedState |= 0x8000;
+ return ret;
+}
--- /dev/null
+++ b/snes/input.h
@@ -1,0 +1,31 @@
+
+#ifndef INPUT_H
+#define INPUT_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct Input Input;
+
+#include "snes.h"
+
+struct Input {
+ Snes* snes;
+ uint8_t type;
+ // latchline
+ bool latchLine;
+ // for controller
+ uint16_t currentState; // actual state
+ uint16_t latchedState;
+};
+
+Input* input_init(Snes* snes);
+void input_free(Input* input);
+void input_reset(Input* input);
+void input_cycle(Input* input);
+uint8_t input_read(Input* input);
+
+#endif
--- /dev/null
+++ b/snes/ppu.cpp
@@ -1,0 +1,1047 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include "ppu.h"
+#include "snes.h"
+
+// array for layer definitions per mode:
+// 0-7: mode 0-7; 8: mode 1 + l3prio; 9: mode 7 + extbg
+
+// 0-3; layers 1-4; 4: sprites; 5: nonexistent
+static const int layersPerMode[10][12] = {
+ {4, 0, 1, 4, 0, 1, 4, 2, 3, 4, 2, 3},
+ {4, 0, 1, 4, 0, 1, 4, 2, 4, 2, 5, 5},
+ {4, 0, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5},
+ {4, 0, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5},
+ {4, 0, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5},
+ {4, 0, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5},
+ {4, 0, 4, 4, 0, 4, 5, 5, 5, 5, 5, 5},
+ {4, 4, 4, 0, 4, 5, 5, 5, 5, 5, 5, 5},
+ {2, 4, 0, 1, 4, 0, 1, 4, 4, 2, 5, 5},
+ {4, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5, 5}
+};
+
+static const int prioritysPerMode[10][12] = {
+ {3, 1, 1, 2, 0, 0, 1, 1, 1, 0, 0, 0},
+ {3, 1, 1, 2, 0, 0, 1, 1, 0, 0, 5, 5},
+ {3, 1, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5},
+ {3, 1, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5},
+ {3, 1, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5},
+ {3, 1, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5},
+ {3, 1, 2, 1, 0, 0, 5, 5, 5, 5, 5, 5},
+ {3, 2, 1, 0, 0, 5, 5, 5, 5, 5, 5, 5},
+ {1, 3, 1, 1, 2, 0, 0, 1, 0, 0, 5, 5},
+ {3, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5, 5}
+};
+
+static const int layerCountPerMode[10] = {
+ 12, 10, 8, 8, 8, 8, 6, 5, 10, 7
+};
+
+static const int bitDepthsPerMode[10][4] = {
+ {2, 2, 2, 2},
+ {4, 4, 2, 5},
+ {4, 4, 5, 5},
+ {8, 4, 5, 5},
+ {8, 2, 5, 5},
+ {4, 2, 5, 5},
+ {4, 5, 5, 5},
+ {8, 5, 5, 5},
+ {4, 4, 2, 5},
+ {8, 7, 5, 5}
+};
+
+static const int spriteSizes[8][2] = {
+ {8, 16}, {8, 32}, {8, 64}, {16, 32},
+ {16, 64}, {32, 64}, {16, 32}, {16, 32}
+};
+
+static void ppu_handlePixel(Ppu* ppu, int x, int y);
+static int ppu_getPixel(Ppu* ppu, int x, int y, bool sub, int* r, int* g, int* b);
+static uint16_t ppu_getOffsetValue(Ppu* ppu, int col, int row);
+static int ppu_getPixelForBgLayer(Ppu* ppu, int x, int y, int layer, bool priority);
+static void ppu_handleOPT(Ppu* ppu, int layer, int* lx, int* ly);
+static void ppu_calculateMode7Starts(Ppu* ppu, int y);
+static int ppu_getPixelForMode7(Ppu* ppu, int x, int layer, bool priority);
+static bool ppu_getWindowState(Ppu* ppu, int layer, int x);
+static void ppu_evaluateSprites(Ppu* ppu, int line);
+static uint16_t ppu_getVramRemap(Ppu* ppu);
+
+Ppu* ppu_init(Snes* snes) {
+ Ppu* ppu = (Ppu * )malloc(sizeof(Ppu));
+ ppu->snes = snes;
+ return ppu;
+}
+
+void ppu_free(Ppu* ppu) {
+ free(ppu);
+}
+
+void ppu_reset(Ppu* ppu) {
+ memset(ppu->vram, 0, sizeof(ppu->vram));
+ ppu->vramPointer = 0;
+ ppu->vramIncrementOnHigh = false;
+ ppu->vramIncrement = 1;
+ ppu->vramRemapMode = 0;
+ ppu->vramReadBuffer = 0;
+ memset(ppu->cgram, 0, sizeof(ppu->cgram));
+ ppu->cgramPointer = 0;
+ ppu->cgramSecondWrite = false;
+ ppu->cgramBuffer = 0;
+ memset(ppu->oam, 0, sizeof(ppu->oam));
+ memset(ppu->highOam, 0, sizeof(ppu->highOam));
+ ppu->oamAdr = 0;
+ ppu->oamAdrWritten = 0;
+ ppu->oamInHigh = false;
+ ppu->oamInHighWritten = false;
+ ppu->oamSecondWrite = false;
+ ppu->oamBuffer = 0;
+ ppu->objPriority = false;
+ ppu->objTileAdr1 = 0;
+ ppu->objTileAdr2 = 0;
+ ppu->objSize = 0;
+ memset(ppu->objPixelBuffer, 0, sizeof(ppu->objPixelBuffer));
+ memset(ppu->objPriorityBuffer, 0, sizeof(ppu->objPriorityBuffer));
+ ppu->timeOver = false;
+ ppu->rangeOver = false;
+ ppu->objInterlace = false;
+ for(int i = 0; i < 4; i++) {
+ ppu->bgLayer[i].hScroll = 0;
+ ppu->bgLayer[i].vScroll = 0;
+ ppu->bgLayer[i].tilemapWider = false;
+ ppu->bgLayer[i].tilemapHigher = false;
+ ppu->bgLayer[i].tilemapAdr = 0;
+ ppu->bgLayer[i].tileAdr = 0;
+ ppu->bgLayer[i].bigTiles = false;
+ ppu->bgLayer[i].mosaicEnabled = false;
+ }
+ ppu->scrollPrev = 0;
+ ppu->scrollPrev2 = 0;
+ ppu->mosaicSize = 1;
+ ppu->mosaicStartLine = 1;
+ for(int i = 0; i < 5; i++) {
+ ppu->layer[i].mainScreenEnabled = false;
+ ppu->layer[i].subScreenEnabled = false;
+ ppu->layer[i].mainScreenWindowed = false;
+ ppu->layer[i].subScreenWindowed = false;
+ }
+ memset(ppu->m7matrix, 0, sizeof(ppu->m7matrix));
+ ppu->m7prev = 0;
+ ppu->m7largeField = false;
+ ppu->m7charFill = false;
+ ppu->m7xFlip = false;
+ ppu->m7yFlip = false;
+ ppu->m7extBg = false;
+ ppu->m7startX = 0;
+ ppu->m7startY = 0;
+ for(int i = 0; i < 6; i++) {
+ ppu->windowLayer[i].window1enabled = false;
+ ppu->windowLayer[i].window2enabled = false;
+ ppu->windowLayer[i].window1inversed = false;
+ ppu->windowLayer[i].window2inversed = false;
+ ppu->windowLayer[i].maskLogic = 0;
+ }
+ ppu->window1left = 0;
+ ppu->window1right = 0;
+ ppu->window2left = 0;
+ ppu->window2right = 0;
+ ppu->clipMode = 0;
+ ppu->preventMathMode = 0;
+ ppu->addSubscreen = false;
+ ppu->subtractColor = false;
+ ppu->halfColor = false;
+ memset(ppu->mathEnabled, 0, sizeof(ppu->mathEnabled));
+ ppu->fixedColorR = 0;
+ ppu->fixedColorG = 0;
+ ppu->fixedColorB = 0;
+ ppu->forcedBlank = true;
+ ppu->brightness = 0;
+ ppu->mode = 0;
+ ppu->bg3priority = false;
+ ppu->evenFrame = false;
+ ppu->pseudoHires = false;
+ ppu->overscan = false;
+ ppu->frameOverscan = false;
+ ppu->interlace = false;
+ ppu->frameInterlace = false;
+ ppu->directColor = false;
+ ppu->hCount = 0;
+ ppu->vCount = 0;
+ ppu->hCountSecond = false;
+ ppu->vCountSecond = false;
+ ppu->countersLatched = false;
+ ppu->ppu1openBus = 0;
+ ppu->ppu2openBus = 0;
+ memset(ppu->pixelBuffer, 0, sizeof(ppu->pixelBuffer));
+}
+
+void ppu_saveload(Ppu *ppu, SaveLoadFunc *func, void *ctx) {
+ func(ctx, &ppu->vram, offsetof(Ppu, pixelBuffer) - offsetof(Ppu, vram));
+}
+
+bool ppu_checkOverscan(Ppu* ppu) {
+ // called at (0,225)
+ ppu->frameOverscan = ppu->overscan; // set if we have a overscan-frame
+ return ppu->frameOverscan;
+}
+
+void ppu_handleVblank(Ppu* ppu) {
+ // called either right after ppu_checkOverscan at (0,225), or at (0,240)
+ if(!ppu->forcedBlank) {
+ ppu->oamAdr = ppu->oamAdrWritten;
+ ppu->oamInHigh = ppu->oamInHighWritten;
+ ppu->oamSecondWrite = false;
+ }
+ ppu->frameInterlace = ppu->interlace; // set if we have a interlaced frame
+}
+
+void ppu_runLine(Ppu* ppu, int line) {
+ if(line == 0) {
+ // pre-render line
+ // TODO: this now happens halfway into the first line
+ ppu->mosaicStartLine = 1;
+ ppu->rangeOver = false;
+ ppu->timeOver = false;
+ ppu->evenFrame = !ppu->evenFrame;
+ } else {
+ // evaluate sprites
+ memset(ppu->objPixelBuffer, 0, sizeof(ppu->objPixelBuffer));
+ if(!ppu->forcedBlank) ppu_evaluateSprites(ppu, line - 1);
+ // actual line
+ if(ppu->mode == 7) ppu_calculateMode7Starts(ppu, line);
+ for(int x = 0; x < 256; x++) {
+ ppu_handlePixel(ppu, x, line);
+ }
+ }
+}
+
+static void ppu_handlePixel(Ppu* ppu, int x, int y) {
+ int r = 0, r2 = 0;
+ int g = 0, g2 = 0;
+ int b = 0, b2 = 0;
+ if(!ppu->forcedBlank) {
+ int mainLayer = ppu_getPixel(ppu, x, y, false, &r, &g, &b);
+
+ bool colorWindowState = ppu_getWindowState(ppu, 5, x);
+ if(
+ ppu->clipMode == 3 ||
+ (ppu->clipMode == 2 && colorWindowState) ||
+ (ppu->clipMode == 1 && !colorWindowState)
+ ) {
+ r = g = b = 0;
+ }
+ int secondLayer = 5; // backdrop
+ bool mathEnabled = mainLayer < 6 && ppu->mathEnabled[mainLayer] && !(
+ ppu->preventMathMode == 3 ||
+ (ppu->preventMathMode == 2 && colorWindowState) ||
+ (ppu->preventMathMode == 1 && !colorWindowState)
+ );
+ if((mathEnabled && ppu->addSubscreen) || ppu->pseudoHires || ppu->mode == 5 || ppu->mode == 6) {
+ secondLayer = ppu_getPixel(ppu, x, y, true, &r2, &g2, &b2);
+ }
+ // TODO: subscreen pixels can be clipped to black as well
+ // TODO: math for subscreen pixels (add/sub sub to main)
+ if(mathEnabled) {
+ if(ppu->subtractColor) {
+ r -= (ppu->addSubscreen && secondLayer != 5) ? r2 : ppu->fixedColorR;
+ g -= (ppu->addSubscreen && secondLayer != 5) ? g2 : ppu->fixedColorG;
+ b -= (ppu->addSubscreen && secondLayer != 5) ? b2 : ppu->fixedColorB;
+ } else {
+ r += (ppu->addSubscreen && secondLayer != 5) ? r2 : ppu->fixedColorR;
+ g += (ppu->addSubscreen && secondLayer != 5) ? g2 : ppu->fixedColorG;
+ b += (ppu->addSubscreen && secondLayer != 5) ? b2 : ppu->fixedColorB;
+ }
+ if(ppu->halfColor && (secondLayer != 5 || !ppu->addSubscreen)) {
+ r >>= 1;
+ g >>= 1;
+ b >>= 1;
+ }
+ if(r > 31) r = 31;
+ if(g > 31) g = 31;
+ if(b > 31) b = 31;
+ if(r < 0) r = 0;
+ if(g < 0) g = 0;
+ if(b < 0) b = 0;
+ }
+ if(!(ppu->pseudoHires || ppu->mode == 5 || ppu->mode == 6)) {
+ r2 = r; g2 = g; b2 = b;
+ }
+ }
+ int row = (y - 1) + (ppu->evenFrame ? 0 : 239);
+ ppu->pixelBuffer[row * 2048 + x * 8 + 1] = ((b2 << 3) | (b2 >> 2)) * ppu->brightness / 15;
+ ppu->pixelBuffer[row * 2048 + x * 8 + 2] = ((g2 << 3) | (g2 >> 2)) * ppu->brightness / 15;
+ ppu->pixelBuffer[row * 2048 + x * 8 + 3] = ((r2 << 3) | (r2 >> 2)) * ppu->brightness / 15;
+ ppu->pixelBuffer[row * 2048 + x * 8 + 5] = ((b << 3) | (b >> 2)) * ppu->brightness / 15;
+ ppu->pixelBuffer[row * 2048 + x * 8 + 6] = ((g << 3) | (g >> 2)) * ppu->brightness / 15;
+ ppu->pixelBuffer[row * 2048 + x * 8 + 7] = ((r << 3) | (r >> 2)) * ppu->brightness / 15;
+}
+
+static int ppu_getPixel(Ppu* ppu, int x, int y, bool sub, int* r, int* g, int* b) {
+ // figure out which color is on this location on main- or subscreen, sets it in r, g, b
+ // returns which layer it is: 0-3 for bg layer, 4 or 6 for sprites (depending on palette), 5 for backdrop
+ int actMode = ppu->mode == 1 && ppu->bg3priority ? 8 : ppu->mode;
+ actMode = ppu->mode == 7 && ppu->m7extBg ? 9 : actMode;
+ int layer = 5;
+ int pixel = 0;
+ for(int i = 0; i < layerCountPerMode[actMode]; i++) {
+ int curLayer = layersPerMode[actMode][i];
+ int curPriority = prioritysPerMode[actMode][i];
+ bool layerActive = false;
+ if(!sub) {
+ layerActive = ppu->layer[curLayer].mainScreenEnabled && (
+ !ppu->layer[curLayer].mainScreenWindowed || !ppu_getWindowState(ppu, curLayer, x)
+ );
+ } else {
+ layerActive = ppu->layer[curLayer].subScreenEnabled && (
+ !ppu->layer[curLayer].subScreenWindowed || !ppu_getWindowState(ppu, curLayer, x)
+ );
+ }
+ if(layerActive) {
+ if(curLayer < 4) {
+ // bg layer
+ int lx = x;
+ int ly = y;
+ if(ppu->bgLayer[curLayer].mosaicEnabled && ppu->mosaicSize > 1) {
+ lx -= lx % ppu->mosaicSize;
+ ly -= (ly - ppu->mosaicStartLine) % ppu->mosaicSize;
+ }
+ if(ppu->mode == 7) {
+ pixel = ppu_getPixelForMode7(ppu, lx, curLayer, curPriority);
+ } else {
+ lx += ppu->bgLayer[curLayer].hScroll;
+ if(ppu->mode == 5 || ppu->mode == 6) {
+ lx *= 2;
+ lx += (sub || ppu->bgLayer[curLayer].mosaicEnabled) ? 0 : 1;
+ if(ppu->interlace) {
+ ly *= 2;
+ ly += (ppu->evenFrame || ppu->bgLayer[curLayer].mosaicEnabled) ? 0 : 1;
+ }
+ }
+ ly += ppu->bgLayer[curLayer].vScroll;
+ if(ppu->mode == 2 || ppu->mode == 4 || ppu->mode == 6) {
+ ppu_handleOPT(ppu, curLayer, &lx, &ly);
+ }
+ pixel = ppu_getPixelForBgLayer(
+ ppu, lx & 0x3ff, ly & 0x3ff,
+ curLayer, curPriority
+ );
+ }
+ } else {
+ // get a pixel from the sprite buffer
+ pixel = 0;
+ if(ppu->objPriorityBuffer[x] == curPriority) pixel = ppu->objPixelBuffer[x];
+ }
+ }
+ if(pixel > 0) {
+ layer = curLayer;
+ break;
+ }
+ }
+ if(ppu->directColor && layer < 4 && bitDepthsPerMode[actMode][layer] == 8) {
+ *r = ((pixel & 0x7) << 2) | ((pixel & 0x100) >> 7);
+ *g = ((pixel & 0x38) >> 1) | ((pixel & 0x200) >> 8);
+ *b = ((pixel & 0xc0) >> 3) | ((pixel & 0x400) >> 8);
+ } else {
+ uint16_t color = ppu->cgram[pixel & 0xff];
+ *r = color & 0x1f;
+ *g = (color >> 5) & 0x1f;
+ *b = (color >> 10) & 0x1f;
+ }
+ if(layer == 4 && pixel < 0xc0) layer = 6; // sprites with palette color < 0xc0
+ return layer;
+}
+
+static void ppu_handleOPT(Ppu* ppu, int layer, int* lx, int* ly) {
+ int x = *lx;
+ int y = *ly;
+ int column = 0;
+ if(ppu->mode == 6) {
+ column = ((x - (x & 0xf)) - ((ppu->bgLayer[layer].hScroll * 2) & 0xfff0)) >> 4;
+ } else {
+ column = ((x - (x & 0x7)) - (ppu->bgLayer[layer].hScroll & 0xfff8)) >> 3;
+ }
+ if(column > 0) {
+ // fetch offset values from layer 3 tilemap
+ int valid = layer == 0 ? 0x2000 : 0x4000;
+ uint16_t hOffset = ppu_getOffsetValue(ppu, column - 1, 0);
+ uint16_t vOffset = 0;
+ if(ppu->mode == 4) {
+ if(hOffset & 0x8000) {
+ vOffset = hOffset;
+ hOffset = 0;
+ }
+ } else {
+ vOffset = ppu_getOffsetValue(ppu, column - 1, 1);
+ }
+ if(ppu->mode == 6) {
+ // TODO: not sure if correct
+ if(hOffset & valid) *lx = (((hOffset & 0x3f8) + (column * 8)) * 2) | (x & 0xf);
+ } else {
+ if(hOffset & valid) *lx = ((hOffset & 0x3f8) + (column * 8)) | (x & 0x7);
+ }
+ // TODO: not sure if correct for interlace
+ if(vOffset & valid) *ly = (vOffset & 0x3ff) + (y - ppu->bgLayer[layer].vScroll);
+ }
+}
+
+static uint16_t ppu_getOffsetValue(Ppu* ppu, int col, int row) {
+ int x = col * 8 + ppu->bgLayer[2].hScroll;
+ int y = row * 8 + ppu->bgLayer[2].vScroll;
+ int tileBits = ppu->bgLayer[2].bigTiles ? 4 : 3;
+ int tileHighBit = ppu->bgLayer[2].bigTiles ? 0x200 : 0x100;
+ uint16_t tilemapAdr = ppu->bgLayer[2].tilemapAdr + (((y >> tileBits) & 0x1f) << 5 | ((x >> tileBits) & 0x1f));
+ if((x & tileHighBit) && ppu->bgLayer[2].tilemapWider) tilemapAdr += 0x400;
+ if((y & tileHighBit) && ppu->bgLayer[2].tilemapHigher) tilemapAdr += ppu->bgLayer[2].tilemapWider ? 0x800 : 0x400;
+ return ppu->vram[tilemapAdr & 0x7fff];
+}
+
+static int ppu_getPixelForBgLayer(Ppu* ppu, int x, int y, int layer, bool priority) {
+ BgLayer *layerp = &ppu->bgLayer[layer];
+ // figure out address of tilemap word and read it
+ bool wideTiles = layerp->bigTiles || ppu->mode == 5 || ppu->mode == 6;
+ int tileBitsX = wideTiles ? 4 : 3;
+ int tileHighBitX = wideTiles ? 0x200 : 0x100;
+ int tileBitsY = layerp->bigTiles ? 4 : 3;
+ int tileHighBitY = layerp->bigTiles ? 0x200 : 0x100;
+ uint16_t tilemapAdr = layerp->tilemapAdr + (((y >> tileBitsY) & 0x1f) << 5 | ((x >> tileBitsX) & 0x1f));
+ if((x & tileHighBitX) && layerp->tilemapWider) tilemapAdr += 0x400;
+ if((y & tileHighBitY) && layerp->tilemapHigher) tilemapAdr += layerp->tilemapWider ? 0x800 : 0x400;
+ uint16_t tile = ppu->vram[tilemapAdr & 0x7fff];
+ // check priority, get palette
+ if(((bool) (tile & 0x2000)) != priority) return 0; // wrong priority
+ int paletteNum = (tile & 0x1c00) >> 10;
+ // figure out position within tile
+ int row = (tile & 0x8000) ? 7 - (y & 0x7) : (y & 0x7);
+ int col = (tile & 0x4000) ? (x & 0x7) : 7 - (x & 0x7);
+ int tileNum = tile & 0x3ff;
+ if(wideTiles) {
+ // if unflipped right half of tile, or flipped left half of tile
+ if(((bool) (x & 8)) ^ ((bool) (tile & 0x4000))) tileNum += 1;
+ }
+ if(layerp->bigTiles) {
+ // if unflipped bottom half of tile, or flipped upper half of tile
+ if(((bool) (y & 8)) ^ ((bool) (tile & 0x8000))) tileNum += 0x10;
+ }
+ // read tiledata, ajust palette for mode 0
+ int bitDepth = bitDepthsPerMode[ppu->mode][layer];
+ if(ppu->mode == 0) paletteNum += 8 * layer;
+ // plane 1 (always)
+ int paletteSize = 4;
+ uint16_t plane1 = ppu->vram[(layerp->tileAdr + ((tileNum & 0x3ff) * 4 * bitDepth) + row) & 0x7fff];
+ int pixel = (plane1 >> col) & 1;
+ pixel |= ((plane1 >> (8 + col)) & 1) << 1;
+ // plane 2 (for 4bpp, 8bpp)
+ if(bitDepth > 2) {
+ paletteSize = 16;
+ uint16_t plane2 = ppu->vram[(layerp->tileAdr + ((tileNum & 0x3ff) * 4 * bitDepth) + 8 + row) & 0x7fff];
+ pixel |= ((plane2 >> col) & 1) << 2;
+ pixel |= ((plane2 >> (8 + col)) & 1) << 3;
+ }
+ // plane 3 & 4 (for 8bpp)
+ if(bitDepth > 4) {
+ paletteSize = 256;
+ uint16_t plane3 = ppu->vram[(layerp->tileAdr + ((tileNum & 0x3ff) * 4 * bitDepth) + 16 + row) & 0x7fff];
+ pixel |= ((plane3 >> col) & 1) << 4;
+ pixel |= ((plane3 >> (8 + col)) & 1) << 5;
+ uint16_t plane4 = ppu->vram[(layerp->tileAdr + ((tileNum & 0x3ff) * 4 * bitDepth) + 24 + row) & 0x7fff];
+ pixel |= ((plane4 >> col) & 1) << 6;
+ pixel |= ((plane4 >> (8 + col)) & 1) << 7;
+ }
+ // return cgram index, or 0 if transparent, palette number in bits 10-8 for 8-color layers
+ return pixel == 0 ? 0 : paletteSize * paletteNum + pixel;
+}
+
+static void ppu_calculateMode7Starts(Ppu* ppu, int y) {
+ // expand 13-bit values to signed values
+ int hScroll = ((int16_t) (ppu->m7matrix[6] << 3)) >> 3;
+ int vScroll = ((int16_t) (ppu->m7matrix[7] << 3)) >> 3;
+ int xCenter = ((int16_t) (ppu->m7matrix[4] << 3)) >> 3;
+ int yCenter = ((int16_t) (ppu->m7matrix[5] << 3)) >> 3;
+ // do calculation
+ int clippedH = hScroll - xCenter;
+ int clippedV = vScroll - yCenter;
+ clippedH = (clippedH & 0x2000) ? (clippedH | ~1023) : (clippedH & 1023);
+ clippedV = (clippedV & 0x2000) ? (clippedV | ~1023) : (clippedV & 1023);
+ if(ppu->bgLayer[0].mosaicEnabled && ppu->mosaicSize > 1) {
+ y -= (y - ppu->mosaicStartLine) % ppu->mosaicSize;
+ }
+ uint8_t ry = ppu->m7yFlip ? 255 - y : y;
+ ppu->m7startX = (
+ ((ppu->m7matrix[0] * clippedH) & ~63) +
+ ((ppu->m7matrix[1] * ry) & ~63) +
+ ((ppu->m7matrix[1] * clippedV) & ~63) +
+ (xCenter << 8)
+ );
+ ppu->m7startY = (
+ ((ppu->m7matrix[2] * clippedH) & ~63) +
+ ((ppu->m7matrix[3] * ry) & ~63) +
+ ((ppu->m7matrix[3] * clippedV) & ~63) +
+ (yCenter << 8)
+ );
+}
+
+static int ppu_getPixelForMode7(Ppu* ppu, int x, int layer, bool priority) {
+ uint8_t rx = ppu->m7xFlip ? 255 - x : x;
+ int xPos = (ppu->m7startX + ppu->m7matrix[0] * rx) >> 8;
+ int yPos = (ppu->m7startY + ppu->m7matrix[2] * rx) >> 8;
+ bool outsideMap = xPos < 0 || xPos >= 1024 || yPos < 0 || yPos >= 1024;
+ xPos &= 0x3ff;
+ yPos &= 0x3ff;
+ if(!ppu->m7largeField) outsideMap = false;
+ uint8_t tile = outsideMap ? 0 : ppu->vram[(yPos >> 3) * 128 + (xPos >> 3)] & 0xff;
+ uint8_t pixel = outsideMap && !ppu->m7charFill ? 0 : ppu->vram[tile * 64 + (yPos & 7) * 8 + (xPos & 7)] >> 8;
+ if(layer == 1) {
+ if(((bool) (pixel & 0x80)) != priority) return 0;
+ return pixel & 0x7f;
+ }
+ return pixel;
+}
+
+static bool ppu_getWindowState(Ppu* ppu, int layer, int x) {
+ if(!ppu->windowLayer[layer].window1enabled && !ppu->windowLayer[layer].window2enabled) {
+ return false;
+ }
+ if(ppu->windowLayer[layer].window1enabled && !ppu->windowLayer[layer].window2enabled) {
+ bool test = x >= ppu->window1left && x <= ppu->window1right;
+ return ppu->windowLayer[layer].window1inversed ? !test : test;
+ }
+ if(!ppu->windowLayer[layer].window1enabled && ppu->windowLayer[layer].window2enabled) {
+ bool test = x >= ppu->window2left && x <= ppu->window2right;
+ return ppu->windowLayer[layer].window2inversed ? !test : test;
+ }
+ bool test1 = x >= ppu->window1left && x <= ppu->window1right;
+ bool test2 = x >= ppu->window2left && x <= ppu->window2right;
+ if(ppu->windowLayer[layer].window1inversed) test1 = !test1;
+ if(ppu->windowLayer[layer].window2inversed) test2 = !test2;
+ switch(ppu->windowLayer[layer].maskLogic) {
+ case 0: return test1 || test2;
+ case 1: return test1 && test2;
+ case 2: return test1 != test2;
+ case 3: return test1 == test2;
+ }
+ return false;
+}
+
+static void ppu_evaluateSprites(Ppu* ppu, int line) {
+ // TODO: iterate over oam normally to determine in-range sprites,
+ // then iterate those in-range sprites in reverse for tile-fetching
+ // TODO: rectangular sprites, wierdness with sprites at -256
+ uint8_t index = ppu->objPriority ? (ppu->oamAdr & 0xfe) : 0;
+ int spritesFound = 0;
+ int tilesFound = 0;
+ for(int i = 0; i < 128; i++) {
+ uint8_t y = ppu->oam[index] >> 8;
+ // check if the sprite is on this line and get the sprite size
+ uint8_t row = line - y;
+ int spriteSize = spriteSizes[ppu->objSize][(ppu->highOam[index >> 3] >> ((index & 7) + 1)) & 1];
+ int spriteHeight = ppu->objInterlace ? spriteSize / 2 : spriteSize;
+ if(row < spriteHeight) {
+ // in y-range, get the x location, using the high bit as well
+ int x = ppu->oam[index] & 0xff;
+ x |= ((ppu->highOam[index >> 3] >> (index & 7)) & 1) << 8;
+ if(x > 255) x -= 512;
+ // if in x-range
+ if(x > -spriteSize) {
+ // break if we found 32 sprites already
+ spritesFound++;
+ if(spritesFound > 32) {
+ ppu->rangeOver = true;
+ break;
+ }
+ // update row according to obj-interlace
+ if(ppu->objInterlace) row = row * 2 + (ppu->evenFrame ? 0 : 1);
+ // get some data for the sprite and y-flip row if needed
+ int tile = ppu->oam[index + 1] & 0xff;
+ int palette = (ppu->oam[index + 1] & 0xe00) >> 9;
+ bool hFlipped = ppu->oam[index + 1] & 0x4000;
+ if(ppu->oam[index + 1] & 0x8000) row = spriteSize - 1 - row;
+ // fetch all tiles in x-range
+ for(int col = 0; col < spriteSize; col += 8) {
+ if(col + x > -8 && col + x < 256) {
+ // break if we found 34 8*1 slivers already
+ tilesFound++;
+ if(tilesFound > 34) {
+ ppu->timeOver = true;
+ break;
+ }
+ // figure out which tile this uses, looping within 16x16 pages, and get it's data
+ int usedCol = hFlipped ? spriteSize - 1 - col : col;
+ uint8_t usedTile = (((tile >> 4) + (row / 8)) << 4) | (((tile & 0xf) + (usedCol / 8)) & 0xf);
+ uint16_t objAdr = (ppu->oam[index + 1] & 0x100) ? ppu->objTileAdr2 : ppu->objTileAdr1;
+ uint16_t plane1 = ppu->vram[(objAdr + usedTile * 16 + (row & 0x7)) & 0x7fff];
+ uint16_t plane2 = ppu->vram[(objAdr + usedTile * 16 + 8 + (row & 0x7)) & 0x7fff];
+ // go over each pixel
+ for(int px = 0; px < 8; px++) {
+ int shift = hFlipped ? px : 7 - px;
+ int pixel = (plane1 >> shift) & 1;
+ pixel |= ((plane1 >> (8 + shift)) & 1) << 1;
+ pixel |= ((plane2 >> shift) & 1) << 2;
+ pixel |= ((plane2 >> (8 + shift)) & 1) << 3;
+ // draw it in the buffer if there is a pixel here, and the buffer there is still empty
+ int screenCol = col + x + px;
+ if(pixel > 0 && screenCol >= 0 && screenCol < 256 && ppu->objPixelBuffer[screenCol] == 0) {
+ ppu->objPixelBuffer[screenCol] = 0x80 + 16 * palette + pixel;
+ ppu->objPriorityBuffer[screenCol] = (ppu->oam[index + 1] & 0x3000) >> 12;
+ }
+ }
+ }
+ }
+ if(tilesFound > 34) break; // break out of sprite-loop if max tiles found
+ }
+ }
+ index += 2;
+ }
+}
+
+static uint16_t ppu_getVramRemap(Ppu* ppu) {
+ uint16_t adr = ppu->vramPointer;
+ switch(ppu->vramRemapMode) {
+ case 0: return adr;
+ case 1: return (adr & 0xff00) | ((adr & 0xe0) >> 5) | ((adr & 0x1f) << 3);
+ case 2: return (adr & 0xfe00) | ((adr & 0x1c0) >> 6) | ((adr & 0x3f) << 3);
+ case 3: return (adr & 0xfc00) | ((adr & 0x380) >> 7) | ((adr & 0x7f) << 3);
+ }
+ return adr;
+}
+
+uint8_t ppu_read(Ppu* ppu, uint8_t adr) {
+ switch(adr) {
+ case 0x04: case 0x14: case 0x24:
+ case 0x05: case 0x15: case 0x25:
+ case 0x06: case 0x16: case 0x26:
+ case 0x08: case 0x18: case 0x28:
+ case 0x09: case 0x19: case 0x29:
+ case 0x0a: case 0x1a: case 0x2a: {
+ return ppu->ppu1openBus;
+ }
+ case 0x34:
+ case 0x35:
+ case 0x36: {
+ int result = ppu->m7matrix[0] * (ppu->m7matrix[1] >> 8);
+ ppu->ppu1openBus = (result >> (8 * (adr - 0x34))) & 0xff;
+ return ppu->ppu1openBus;
+ }
+ case 0x37: {
+ // TODO: only when ppulatch is set
+ ppu->hCount = ppu->snes->hPos / 4;
+ ppu->vCount = ppu->snes->vPos;
+ ppu->countersLatched = true;
+ if (ppu->snes->disableHpos)
+ ppu->vCount = 192;
+
+ return ppu->snes->openBus;
+ }
+ case 0x38: {
+ uint8_t ret = 0;
+ if(ppu->oamInHigh) {
+ ret = ppu->highOam[((ppu->oamAdr & 0xf) << 1) | (uint8_t)ppu->oamSecondWrite];
+ if(ppu->oamSecondWrite) {
+ ppu->oamAdr++;
+ if(ppu->oamAdr == 0) ppu->oamInHigh = false;
+ }
+ } else {
+ if(!ppu->oamSecondWrite) {
+ ret = ppu->oam[ppu->oamAdr] & 0xff;
+ } else {
+ ret = ppu->oam[ppu->oamAdr++] >> 8;
+ if(ppu->oamAdr == 0) ppu->oamInHigh = true;
+ }
+ }
+ ppu->oamSecondWrite = !ppu->oamSecondWrite;
+ ppu->ppu1openBus = ret;
+ return ret;
+ }
+ case 0x39: {
+ uint16_t val = ppu->vramReadBuffer;
+ if(!ppu->vramIncrementOnHigh) {
+ ppu->vramReadBuffer = ppu->vram[ppu_getVramRemap(ppu) & 0x7fff];
+ ppu->vramPointer += ppu->vramIncrement;
+ }
+ ppu->ppu1openBus = val & 0xff;
+ return val & 0xff;
+ }
+ case 0x3a: {
+ uint16_t val = ppu->vramReadBuffer;
+ if(ppu->vramIncrementOnHigh) {
+ ppu->vramReadBuffer = ppu->vram[ppu_getVramRemap(ppu) & 0x7fff];
+ ppu->vramPointer += ppu->vramIncrement;
+ }
+ ppu->ppu1openBus = val >> 8;
+ return val >> 8;
+ }
+ case 0x3b: {
+ uint8_t ret = 0;
+ if(!ppu->cgramSecondWrite) {
+ ret = ppu->cgram[ppu->cgramPointer] & 0xff;
+ } else {
+ ret = ((ppu->cgram[ppu->cgramPointer++] >> 8) & 0x7f) | (ppu->ppu2openBus & 0x80);
+ }
+ ppu->cgramSecondWrite = !ppu->cgramSecondWrite;
+ ppu->ppu2openBus = ret;
+ return ret;
+ }
+ case 0x3c: {
+#if 0
+ uint8_t val = 0;
+ if(ppu->hCountSecond) {
+ val = ((ppu->hCount >> 8) & 1) | (ppu->ppu2openBus & 0xfe);
+ } else {
+ val = ppu->hCount & 0xff;
+ }
+#else
+ uint8_t val = 0x17;// (ppu->ppu2openBus + ppu->cgramPointer * 7) * 0x31337 >> 8;
+#endif
+ ppu->hCountSecond = !ppu->hCountSecond;
+ ppu->ppu2openBus = val;
+ return val;
+ }
+ case 0x3d: {
+ uint8_t val = 0;
+ uint16_t vCount = 192;// ppu->vCount
+ if(ppu->vCountSecond) {
+ val = ((vCount >> 8) & 1) | (ppu->ppu2openBus & 0xfe);
+ } else {
+ val = vCount & 0xff;
+ }
+ ppu->vCountSecond = !ppu->vCountSecond;
+ ppu->ppu2openBus = val;
+ return val;
+ }
+ case 0x3e: {
+ uint8_t val = 0x1; // ppu1 version (4 bit)
+ val |= ppu->ppu1openBus & 0x10;
+ val |= ppu->rangeOver << 6;
+ val |= ppu->timeOver << 7;
+ ppu->ppu1openBus = val;
+ return val;
+ }
+ case 0x3f: {
+ uint8_t val = 0x3; // ppu2 version (4 bit), bit 4: ntsc/pal
+ val |= ppu->ppu2openBus & 0x20;
+ val |= ppu->countersLatched << 6;
+ val |= ppu->evenFrame << 7;
+ ppu->countersLatched = false; // TODO: only when ppulatch is set
+ ppu->hCountSecond = false;
+ ppu->vCountSecond = false;
+ ppu->ppu2openBus = val;
+ return val;
+ }
+ default: {
+ return ppu->snes->openBus;
+ }
+ }
+}
+
+void ppu_write(Ppu* ppu, uint8_t adr, uint8_t val) {
+ switch(adr) {
+ case 0x00: {
+ // TODO: oam address reset when written on first line of vblank, (and when forced blank is disabled?)
+ ppu->brightness = val & 0xf;
+ ppu->forcedBlank = val & 0x80;
+ break;
+ }
+ case 0x01: {
+ ppu->objSize = val >> 5;
+ ppu->objTileAdr1 = (val & 7) << 13;
+ ppu->objTileAdr2 = ppu->objTileAdr1 + (((val & 0x18) + 8) << 9);
+ break;
+ }
+ case 0x02: {
+ ppu->oamAdr = val;
+ ppu->oamAdrWritten = ppu->oamAdr;
+ ppu->oamInHigh = ppu->oamInHighWritten;
+ ppu->oamSecondWrite = false;
+ break;
+ }
+ case 0x03: {
+ ppu->objPriority = val & 0x80;
+ ppu->oamInHigh = val & 1;
+ ppu->oamInHighWritten = ppu->oamInHigh;
+ ppu->oamAdr = ppu->oamAdrWritten;
+ ppu->oamSecondWrite = false;
+ break;
+ }
+ case 0x04: {
+ if(ppu->oamInHigh) {
+ ppu->highOam[((ppu->oamAdr & 0xf) << 1) | (uint8_t)ppu->oamSecondWrite] = val;
+ if(ppu->oamSecondWrite) {
+ ppu->oamAdr++;
+ if(ppu->oamAdr == 0) ppu->oamInHigh = false;
+ }
+ } else {
+ if(!ppu->oamSecondWrite) {
+ ppu->oamBuffer = val;
+ } else {
+ ppu->oam[ppu->oamAdr++] = (val << 8) | ppu->oamBuffer;
+ if(ppu->oamAdr == 0) ppu->oamInHigh = true;
+ }
+ }
+ ppu->oamSecondWrite = !ppu->oamSecondWrite;
+ break;
+ }
+ case 0x05: {
+ ppu->mode = val & 0x7;
+ ppu->bg3priority = val & 0x8;
+ ppu->bgLayer[0].bigTiles = val & 0x10;
+ ppu->bgLayer[1].bigTiles = val & 0x20;
+ ppu->bgLayer[2].bigTiles = val & 0x40;
+ ppu->bgLayer[3].bigTiles = val & 0x80;
+ break;
+ }
+ case 0x06: {
+ // TODO: mosaic line reset specifics
+ ppu->bgLayer[0].mosaicEnabled = val & 0x1;
+ ppu->bgLayer[1].mosaicEnabled = val & 0x2;
+ ppu->bgLayer[2].mosaicEnabled = val & 0x4;
+ ppu->bgLayer[3].mosaicEnabled = val & 0x8;
+ ppu->mosaicSize = (val >> 4) + 1;
+ ppu->mosaicStartLine = 0;// ppu->snes->vPos;
+ break;
+ }
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a: {
+ ppu->bgLayer[adr - 7].tilemapWider = val & 0x1;
+ ppu->bgLayer[adr - 7].tilemapHigher = val & 0x2;
+ ppu->bgLayer[adr - 7].tilemapAdr = (val & 0xfc) << 8;
+ break;
+ }
+ case 0x0b: {
+ ppu->bgLayer[0].tileAdr = (val & 0xf) << 12;
+ ppu->bgLayer[1].tileAdr = (val & 0xf0) << 8;
+ break;
+ }
+ case 0x0c: {
+ ppu->bgLayer[2].tileAdr = (val & 0xf) << 12;
+ ppu->bgLayer[3].tileAdr = (val & 0xf0) << 8;
+ break;
+ }
+ case 0x0d: {
+ ppu->m7matrix[6] = ((val << 8) | ppu->m7prev) & 0x1fff;
+ ppu->m7prev = val;
+ // fallthrough to normal layer BG-HOFS
+ }
+ case 0x0f:
+ case 0x11:
+ case 0x13: {
+ ppu->bgLayer[(adr - 0xd) / 2].hScroll = ((val << 8) | (ppu->scrollPrev & 0xf8) | (ppu->scrollPrev2 & 0x7)) & 0x3ff;
+ ppu->scrollPrev = val;
+ ppu->scrollPrev2 = val;
+ break;
+ }
+ case 0x0e: {
+ ppu->m7matrix[7] = ((val << 8) | ppu->m7prev) & 0x1fff;
+ ppu->m7prev = val;
+ // fallthrough to normal layer BG-VOFS
+ }
+ case 0x10:
+ case 0x12:
+ case 0x14: {
+ ppu->bgLayer[(adr - 0xe) / 2].vScroll = ((val << 8) | ppu->scrollPrev) & 0x3ff;
+ ppu->scrollPrev = val;
+ break;
+ }
+ case 0x15: {
+ if((val & 3) == 0) {
+ ppu->vramIncrement = 1;
+ } else if((val & 3) == 1) {
+ ppu->vramIncrement = 32;
+ } else {
+ ppu->vramIncrement = 128;
+ }
+ ppu->vramRemapMode = (val & 0xc) >> 2;
+ ppu->vramIncrementOnHigh = val & 0x80;
+ break;
+ }
+ case 0x16: {
+ ppu->vramPointer = (ppu->vramPointer & 0xff00) | val;
+ ppu->vramReadBuffer = ppu->vram[ppu_getVramRemap(ppu) & 0x7fff];
+ break;
+ }
+ case 0x17: {
+ ppu->vramPointer = (ppu->vramPointer & 0x00ff) | (val << 8);
+ ppu->vramReadBuffer = ppu->vram[ppu_getVramRemap(ppu) & 0x7fff];
+ break;
+ }
+ case 0x18: {
+ // TODO: vram access during rendering (also cgram and oam)
+ uint16_t vramAdr = ppu_getVramRemap(ppu);
+ if (val != 0xef) {
+ val += 0;
+ }
+ ppu->vram[vramAdr & 0x7fff] = (ppu->vram[vramAdr & 0x7fff] & 0xff00) | val;
+ if(!ppu->vramIncrementOnHigh) ppu->vramPointer += ppu->vramIncrement;
+ break;
+ }
+ case 0x19: {
+ uint16_t vramAdr = ppu_getVramRemap(ppu);
+ ppu->vram[vramAdr & 0x7fff] = (ppu->vram[vramAdr & 0x7fff] & 0x00ff) | (val << 8);
+ if(ppu->vramIncrementOnHigh) ppu->vramPointer += ppu->vramIncrement;
+ break;
+ }
+ case 0x1a: {
+ ppu->m7largeField = val & 0x80;
+ ppu->m7charFill = val & 0x40;
+ ppu->m7yFlip = val & 0x2;
+ ppu->m7xFlip = val & 0x1;
+ break;
+ }
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e: {
+ ppu->m7matrix[adr - 0x1b] = (val << 8) | ppu->m7prev;
+ ppu->m7prev = val;
+ break;
+ }
+ case 0x1f:
+ case 0x20: {
+ ppu->m7matrix[adr - 0x1b] = ((val << 8) | ppu->m7prev) & 0x1fff;
+ ppu->m7prev = val;
+ break;
+ }
+ case 0x21: {
+ ppu->cgramPointer = val;
+ ppu->cgramSecondWrite = false;
+ break;
+ }
+ case 0x22: {
+ if(!ppu->cgramSecondWrite) {
+ ppu->cgramBuffer = val;
+ } else {
+ ppu->cgram[ppu->cgramPointer++] = (val << 8) | ppu->cgramBuffer;
+ }
+ ppu->cgramSecondWrite = !ppu->cgramSecondWrite;
+ break;
+ }
+ case 0x23:
+ case 0x24:
+ case 0x25: {
+ ppu->windowLayer[(adr - 0x23) * 2].window1inversed = val & 0x1;
+ ppu->windowLayer[(adr - 0x23) * 2].window1enabled = val & 0x2;
+ ppu->windowLayer[(adr - 0x23) * 2].window2inversed = val & 0x4;
+ ppu->windowLayer[(adr - 0x23) * 2].window2enabled = val & 0x8;
+ ppu->windowLayer[(adr - 0x23) * 2 + 1].window1inversed = val & 0x10;
+ ppu->windowLayer[(adr - 0x23) * 2 + 1].window1enabled = val & 0x20;
+ ppu->windowLayer[(adr - 0x23) * 2 + 1].window2inversed = val & 0x40;
+ ppu->windowLayer[(adr - 0x23) * 2 + 1].window2enabled = val & 0x80;
+ break;
+ }
+ case 0x26: {
+ ppu->window1left = val;
+ break;
+ }
+ case 0x27: {
+ ppu->window1right = val;
+ break;
+ }
+ case 0x28: {
+ ppu->window2left = val;
+ break;
+ }
+ case 0x29: {
+ ppu->window2right = val;
+ break;
+ }
+ case 0x2a: {
+ ppu->windowLayer[0].maskLogic = val & 0x3;
+ ppu->windowLayer[1].maskLogic = (val >> 2) & 0x3;
+ ppu->windowLayer[2].maskLogic = (val >> 4) & 0x3;
+ ppu->windowLayer[3].maskLogic = (val >> 6) & 0x3;
+ break;
+ }
+ case 0x2b: {
+ ppu->windowLayer[4].maskLogic = val & 0x3;
+ ppu->windowLayer[5].maskLogic = (val >> 2) & 0x3;
+ break;
+ }
+ case 0x2c: {
+ ppu->layer[0].mainScreenEnabled = val & 0x1;
+ ppu->layer[1].mainScreenEnabled = val & 0x2;
+ ppu->layer[2].mainScreenEnabled = val & 0x4;
+ ppu->layer[3].mainScreenEnabled = val & 0x8;
+ ppu->layer[4].mainScreenEnabled = val & 0x10;
+ break;
+ }
+ case 0x2d: {
+ ppu->layer[0].subScreenEnabled = val & 0x1;
+ ppu->layer[1].subScreenEnabled = val & 0x2;
+ ppu->layer[2].subScreenEnabled = val & 0x4;
+ ppu->layer[3].subScreenEnabled = val & 0x8;
+ ppu->layer[4].subScreenEnabled = val & 0x10;
+ break;
+ }
+ case 0x2e: {
+ ppu->layer[0].mainScreenWindowed = val & 0x1;
+ ppu->layer[1].mainScreenWindowed = val & 0x2;
+ ppu->layer[2].mainScreenWindowed = val & 0x4;
+ ppu->layer[3].mainScreenWindowed = val & 0x8;
+ ppu->layer[4].mainScreenWindowed = val & 0x10;
+ break;
+ }
+ case 0x2f: {
+ ppu->layer[0].subScreenWindowed = val & 0x1;
+ ppu->layer[1].subScreenWindowed = val & 0x2;
+ ppu->layer[2].subScreenWindowed = val & 0x4;
+ ppu->layer[3].subScreenWindowed = val & 0x8;
+ ppu->layer[4].subScreenWindowed = val & 0x10;
+ break;
+ }
+ case 0x30: {
+ ppu->directColor = val & 0x1;
+ ppu->addSubscreen = val & 0x2;
+ ppu->preventMathMode = (val & 0x30) >> 4;
+ ppu->clipMode = (val & 0xc0) >> 6;
+ break;
+ }
+ case 0x31: {
+ ppu->subtractColor = val & 0x80;
+ ppu->halfColor = val & 0x40;
+ for(int i = 0; i < 6; i++) {
+ ppu->mathEnabled[i] = val & (1 << i);
+ }
+ break;
+ }
+ case 0x32: {
+ if(val & 0x80) ppu->fixedColorB = val & 0x1f;
+ if(val & 0x40) ppu->fixedColorG = val & 0x1f;
+ if(val & 0x20) ppu->fixedColorR = val & 0x1f;
+ break;
+ }
+ case 0x33: {
+ ppu->interlace = val & 0x1;
+ ppu->objInterlace = val & 0x2;
+ ppu->overscan = val & 0x4;
+ ppu->pseudoHires = val & 0x8;
+ ppu->m7extBg = val & 0x40;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+void ppu_putPixels(Ppu* ppu, uint8_t* pixels) {
+ for(int y = 0; y < (ppu->frameOverscan ? 239 : 224); y++) {
+ int dest = y * 2 + (ppu->frameOverscan ? 2 : 16);
+ int y1 = y, y2 = y + 239;
+ if(!ppu->frameInterlace) {
+ y1 = y + (ppu->evenFrame ? 0 : 239);
+ y2 = y1;
+ }
+ memcpy(pixels + (dest * 2048), &ppu->pixelBuffer[y1 * 2048], 2048);
+ memcpy(pixels + ((dest + 1) * 2048), &ppu->pixelBuffer[y2 * 2048], 2048);
+ }
+ // clear top 2 lines, and following 14 and last 16 lines if not overscanning
+ memset(pixels, 0, 2048 * 2);
+ if(!ppu->frameOverscan) {
+ memset(pixels + (2 * 2048), 0, 2048 * 14);
+ memset(pixels + (464 * 2048), 0, 2048 * 16);
+ }
+}
--- /dev/null
+++ b/snes/ppu.h
@@ -1,0 +1,145 @@
+
+#ifndef PPU_H
+#define PPU_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct Ppu Ppu;
+
+#include "snes.h"
+
+typedef struct BgLayer {
+ uint16_t hScroll;
+ uint16_t vScroll;
+ bool tilemapWider;
+ bool tilemapHigher;
+ uint16_t tilemapAdr;
+ uint16_t tileAdr;
+ bool bigTiles;
+ bool mosaicEnabled;
+} BgLayer;
+
+typedef struct Layer {
+ bool mainScreenEnabled;
+ bool subScreenEnabled;
+ bool mainScreenWindowed;
+ bool subScreenWindowed;
+} Layer;
+
+typedef struct WindowLayer {
+ bool window1enabled;
+ bool window2enabled;
+ bool window1inversed;
+ bool window2inversed;
+ uint8_t maskLogic;
+} WindowLayer;
+
+struct Ppu {
+ Snes* snes;
+ // vram access
+ uint16_t vram[0x8000];
+ uint16_t vramPointer;
+ bool vramIncrementOnHigh;
+ uint16_t vramIncrement;
+ uint8_t vramRemapMode;
+ uint16_t vramReadBuffer;
+ // cgram access
+ uint16_t cgram[0x100];
+ uint8_t cgramPointer;
+ bool cgramSecondWrite;
+ uint8_t cgramBuffer;
+ // oam access
+ uint16_t oam[0x100];
+ uint8_t highOam[0x20];
+ uint8_t oamAdr;
+ uint8_t oamAdrWritten;
+ bool oamInHigh;
+ bool oamInHighWritten;
+ bool oamSecondWrite;
+ uint8_t oamBuffer;
+ // object/sprites
+ bool objPriority;
+ uint16_t objTileAdr1;
+ uint16_t objTileAdr2;
+ uint8_t objSize;
+ uint8_t objPixelBuffer[256]; // line buffers
+ uint8_t objPriorityBuffer[256];
+ bool timeOver;
+ bool rangeOver;
+ bool objInterlace;
+ // background layers
+ BgLayer bgLayer[4];
+ uint8_t scrollPrev;
+ uint8_t scrollPrev2;
+ uint8_t mosaicSize;
+ uint8_t mosaicStartLine;
+ // layers
+ Layer layer[5];
+ // mode 7
+ int16_t m7matrix[8]; // a, b, c, d, x, y, h, v
+ uint8_t m7prev;
+ bool m7largeField;
+ bool m7charFill;
+ bool m7xFlip;
+ bool m7yFlip;
+ bool m7extBg;
+ // mode 7 internal
+ int32_t m7startX;
+ int32_t m7startY;
+ // windows
+ WindowLayer windowLayer[6];
+ uint8_t window1left;
+ uint8_t window1right;
+ uint8_t window2left;
+ uint8_t window2right;
+ // color math
+ uint8_t clipMode;
+ uint8_t preventMathMode;
+ bool addSubscreen;
+ bool subtractColor;
+ bool halfColor;
+ bool mathEnabled[6];
+ uint8_t fixedColorR;
+ uint8_t fixedColorG;
+ uint8_t fixedColorB;
+ // settings
+ bool forcedBlank;
+ uint8_t brightness;
+ uint8_t mode;
+ bool bg3priority;
+ bool evenFrame;
+ bool pseudoHires;
+ bool overscan;
+ bool frameOverscan; // if we are overscanning this frame (determined at 0,225)
+ bool interlace;
+ bool frameInterlace; // if we are interlacing this frame (determined at start vblank)
+ bool directColor;
+ // latching
+ uint16_t hCount;
+ uint16_t vCount;
+ bool hCountSecond;
+ bool vCountSecond;
+ bool countersLatched;
+ uint8_t ppu1openBus;
+ uint8_t ppu2openBus;
+ // pixel buffer (xbgr)
+ // times 2 for even and odd frame
+ uint8_t pixelBuffer[512 * 4 * 239 * 2];
+};
+
+Ppu* ppu_init(Snes* snes);
+void ppu_free(Ppu* ppu);
+void ppu_reset(Ppu* ppu);
+bool ppu_checkOverscan(Ppu* ppu);
+void ppu_handleVblank(Ppu* ppu);
+void ppu_runLine(Ppu* ppu, int line);
+uint8_t ppu_read(Ppu* ppu, uint8_t adr);
+void ppu_write(Ppu* ppu, uint8_t adr, uint8_t val);
+void ppu_putPixels(Ppu* ppu, uint8_t* pixels);
+void ppu_saveload(Ppu *ppu, SaveLoadFunc *func, void *ctx);
+
+#endif
--- /dev/null
+++ b/snes/saveload.h
@@ -1,0 +1,5 @@
+#pragma once
+
+typedef void SaveLoadFunc(void *ctx, void *data, size_t data_size);
+
+#define SL(x) func(ctx, &x, sizeof(x))
\ No newline at end of file
--- /dev/null
+++ b/snes/snes.cpp
@@ -1,0 +1,586 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <stddef.h>
+
+#include "saveload.h"
+#include "snes.h"
+#include "cpu.h"
+#include "apu.h"
+#include "dma.h"
+#include "ppu.h"
+#include "cart.h"
+#include "input.h"
+#include "../tracing.h"
+#include "../snes_regs.h"
+
+static const double apuCyclesPerMaster = (32040 * 32) / (1364 * 262 * 60.0);
+
+static void snes_runCycle(Snes* snes);
+static void snes_runCpu(Snes* snes);
+static void snes_catchupApu(Snes* snes);
+static uint8_t snes_readReg(Snes* snes, uint16_t adr);
+static void snes_writeReg(Snes* snes, uint16_t adr, uint8_t val);
+static uint8_t snes_rread(Snes* snes, uint32_t adr); // wrapped by read, to set open bus
+static int snes_getAccessTime(Snes* snes, uint32_t adr);
+void zelda_apu_runcycles();
+
+Snes* snes_init(uint8_t *ram) {
+ Snes* snes = (Snes * )malloc(sizeof(Snes));
+ snes->ram = ram;
+ snes->cpu = cpu_init(snes, 0);
+ snes->apu = apu_init();
+ snes->dma = dma_init(snes);
+ snes->ppu = ppu_init(snes);
+ snes->cart = cart_init(snes);
+ snes->input1 = input_init(snes);
+ snes->input2 = input_init(snes);
+ snes->debug_cycles = false;
+ snes->disableHpos = false;
+ return snes;
+}
+
+void snes_free(Snes* snes) {
+ cpu_free(snes->cpu);
+ apu_free(snes->apu);
+ dma_free(snes->dma);
+ ppu_free(snes->ppu);
+ cart_free(snes->cart);
+ input_free(snes->input1);
+ input_free(snes->input2);
+ free(snes);
+}
+
+void snes_saveload(Snes *snes, SaveLoadFunc *func, void *ctx) {
+ cpu_saveload(snes->cpu, func, ctx);
+ apu_saveload(snes->apu, func, ctx);
+ dma_saveload(snes->dma, func, ctx);
+ ppu_saveload(snes->ppu, func, ctx);
+ cart_saveload(snes->cart, func, ctx);
+
+ func(ctx, &snes->hPos, offsetof(Snes, openBus) + 1 - offsetof(Snes, hPos));
+ func(ctx, snes->ram, 0x20000);
+ func(ctx, &snes->ramAdr, 4);
+
+
+ snes->disableHpos = false;
+}
+
+void snes_reset(Snes* snes, bool hard) {
+ cart_reset(snes->cart); // reset cart first, because resetting cpu will read from it (reset vector)
+ cpu_reset(snes->cpu);
+ apu_reset(snes->apu);
+ dma_reset(snes->dma);
+ ppu_reset(snes->ppu);
+ input_reset(snes->input1);
+ input_reset(snes->input2);
+ if (hard) memset(snes->ram, 0, 0x20000);
+ snes->ramAdr = 0;
+ snes->hPos = 0;
+ snes->vPos = 0;
+ snes->frames = 0;
+ snes->cpuCyclesLeft = 52; // 5 reads (8) + 2 IntOp (6)
+ snes->cpuMemOps = 0;
+ snes->apuCatchupCycles = 0.0;
+ snes->hIrqEnabled = false;
+ snes->vIrqEnabled = false;
+ snes->nmiEnabled = false;
+ snes->hTimer = 0x1ff;
+ snes->vTimer = 0x1ff;
+ snes->inNmi = false;
+ snes->inIrq = false;
+ snes->inVblank = false;
+ memset(snes->portAutoRead, 0, sizeof(snes->portAutoRead));
+ snes->autoJoyRead = false;
+ snes->autoJoyTimer = 0;
+ snes->ppuLatch = false;
+ snes->multiplyA = 0xff;
+ snes->multiplyResult = 0xfe01;
+ snes->divideA = 0xffff;
+ snes->divideResult = 0x101;
+ snes->fastMem = false;
+ snes->openBus = 0;
+}
+
+static uint8_t g_last_module;
+bool didit;
+
+void snes_runFrame(Snes* snes) {
+ // runs a signle frame (run cycles until v/h pos is at 0,0)
+ do {
+ snes_runCycle(snes);
+ } while(!(snes->hPos == 0 && snes->vPos == 0));
+}
+
+
+void snes_printCpuLine(Snes *snes) {
+ if (snes->debug_cycles) {
+ static FILE *fout;
+
+ if (!fout)
+ fout = stdout;
+ char line[80];
+ getProcessorStateCpu(snes, line);
+ fputs(line, fout);
+ fprintf(fout, " 0x%x", snes->ppu->vram[0]);
+ fputs("\n", fout);
+ fflush(fout);
+ }
+}
+
+void snes_runGfxCycles(Snes *snes) {
+ // check for h/v timer irq's
+ if(snes->vIrqEnabled && snes->hIrqEnabled) {
+ if(snes->vPos == snes->vTimer && snes->hPos == (4 * snes->hTimer)) {
+ snes->inIrq = true;
+ snes->cpu->irqWanted = true; // request IRQ on CPU
+ }
+ } else if(snes->vIrqEnabled && !snes->hIrqEnabled) {
+ if(snes->vPos == snes->vTimer && snes->hPos == 0) {
+ snes->inIrq = true;
+ snes->cpu->irqWanted = true; // request IRQ on CPU
+ }
+ } else if(!snes->vIrqEnabled && snes->hIrqEnabled) {
+ if(snes->hPos == (4 * snes->hTimer)) {
+ snes->inIrq = true;
+ snes->cpu->irqWanted = true; // request IRQ on CPU
+ }
+ }
+ // handle positional stuff
+ // TODO: better timing? (especially Hpos)
+ if(snes->hPos == 0) {
+ // end of hblank, do most vPos-tests
+ bool startingVblank = false;
+ if(snes->vPos == 0) {
+ // end of vblank
+ snes->inVblank = false;
+ snes->inNmi = false;
+ dma_initHdma(snes->dma);
+ } else if(snes->vPos == 225) {
+ // ask the ppu if we start vblank now or at vPos 240 (overscan)
+ startingVblank = !ppu_checkOverscan(snes->ppu);
+ } else if(snes->vPos == 240){
+ // if we are not yet in vblank, we had an overscan frame, set startingVblank
+ if(!snes->inVblank) startingVblank = true;
+ }
+ if(startingVblank) {
+ // if we are starting vblank
+ ppu_handleVblank(snes->ppu);
+ snes->inVblank = true;
+ snes->inNmi = true;
+ if(snes->autoJoyRead) {
+ // TODO: this starts a little after start of vblank
+ snes->autoJoyTimer = 4224;
+ snes_doAutoJoypad(snes);
+ }
+ if(snes->nmiEnabled) {
+ snes->cpu->nmiWanted = true; // request NMI on CPU
+ }
+ }
+ } else if(snes->hPos == 512) {
+ // render the line halfway of the screen for better compatibility
+ if(!snes->inVblank) ppu_runLine(snes->ppu, snes->vPos);
+ } else if(snes->hPos == 1024) {
+ // start of hblank
+ if(!snes->inVblank) dma_doHdma(snes->dma);
+ }
+ // handle autoJoyRead-timer
+ if(snes->autoJoyTimer > 0) snes->autoJoyTimer -= 2;
+ // increment position
+ // TODO: exact frame timing (line 240 on odd frame is 4 cycles shorter,
+ // even frames in interlace is 1 extra line)
+ if (!snes->disableHpos || !(snes->hPos < 536 || snes->hPos >= 576) || snes->hPos == 0 || snes->vPos == 0)
+ snes->hPos += 2;
+ if(snes->hPos == 1364) {
+ snes->hPos = 0;
+ snes->vPos++;
+ if(snes->vPos == 262) {
+ snes->vPos = 0;
+ snes->frames++;
+ snes_catchupApu(snes); // catch up the apu at the end of the frame
+ }
+ }
+}
+
+static void snes_runCycle(Snes* snes) {
+ snes->apuCatchupCycles += apuCyclesPerMaster * 2.0;
+ input_cycle(snes->input1);
+ input_cycle(snes->input2);
+ // if not in dram refresh, if we are busy with hdma/dma, do that, else do cpu cycle
+ if(snes->hPos < 536 || snes->hPos >= 576) {
+ if(!dma_cycle(snes->dma)) {
+ snes_runCpu(snes);
+ }
+ }
+ snes_runGfxCycles(snes);
+}
+
+static void snes_runCpu(Snes* snes) {
+ if(snes->cpuCyclesLeft == 0) {
+ snes->cpuMemOps = 0;
+ uint32_t pc = snes->cpu->pc | snes->cpu->k << 16;
+ if (snes->debug_cycles) {
+ char line[80];
+ getProcessorStateCpu(snes, line);
+ puts(line);
+ }
+ int cycles = cpu_runOpcode(snes->cpu);
+ snes->cpuCyclesLeft += (cycles - snes->cpuMemOps) * 6;
+ }
+ snes->cpuCyclesLeft -= 2;
+}
+
+static void snes_catchupApu(Snes* snes) {
+ int catchupCycles = (int) snes->apuCatchupCycles;
+ for(int i = 0; i < catchupCycles; i++) {
+ apu_cycle(snes->apu);
+ zelda_apu_runcycles();
+ }
+ snes->apuCatchupCycles -= (double) catchupCycles;
+}
+
+void snes_doAutoJoypad(Snes* snes) {
+ // TODO: improve? (now calls input_cycle)
+ memset(snes->portAutoRead, 0, sizeof(snes->portAutoRead));
+ snes->input1->latchLine = true;
+ snes->input2->latchLine = true;
+ input_cycle(snes->input1); // latches the controllers
+ input_cycle(snes->input2);
+ snes->input1->latchLine = false;
+ snes->input2->latchLine = false;
+ for(int i = 0; i < 16; i++) {
+ uint8_t val = input_read(snes->input1);
+ snes->portAutoRead[0] |= ((val & 1) << (15 - i));
+ snes->portAutoRead[2] |= (((val >> 1) & 1) << (15 - i));
+ val = input_read(snes->input2);
+ snes->portAutoRead[1] |= ((val & 1) << (15 - i));
+ snes->portAutoRead[3] |= (((val >> 1) & 1) << (15 - i));
+ }
+}
+
+uint8_t snes_readBBus(Snes* snes, uint8_t adr) {
+ if(adr < 0x40) {
+ return ppu_read(snes->ppu, adr);
+ }
+ if(adr < 0x80) {
+ if (kIsOrigEmu)
+ snes_catchupApu(snes); // catch up the apu before reading
+ else
+ apu_cycle(snes->apu);//spc_runOpcode(snes->apu->spc);
+ return snes->apu->outPorts[adr & 0x3];
+ }
+ if(adr == 0x80) {
+ uint8_t ret = snes->ram[snes->ramAdr++];
+ snes->ramAdr &= 0x1ffff;
+ return ret;
+ }
+ return snes->openBus;
+}
+
+void snes_writeBBus(Snes* snes, uint8_t adr, uint8_t val) {
+ if(adr < 0x40) {
+ ppu_write(snes->ppu, adr, val);
+ return;
+ }
+ if(adr < 0x80) {
+ snes_catchupApu(snes); // catch up the apu before writing
+ snes->apu->inPorts[adr & 0x3] = val;
+ return;
+ }
+ switch(adr) {
+ case 0x80: {
+ snes->ram[snes->ramAdr++] = val;
+ snes->ramAdr &= 0x1ffff;
+ break;
+ }
+ case 0x81: {
+ snes->ramAdr = (snes->ramAdr & 0x1ff00) | val;
+ break;
+ }
+ case 0x82: {
+ snes->ramAdr = (snes->ramAdr & 0x100ff) | (val << 8);
+ break;
+ }
+ case 0x83: {
+ snes->ramAdr = (snes->ramAdr & 0x0ffff) | ((val & 1) << 16);
+ break;
+ }
+ }
+}
+
+static uint8_t snes_readReg(Snes* snes, uint16_t adr) {
+ switch(adr) {
+ case 0x4210: {
+ uint8_t val = 0x2; // CPU version (4 bit)
+ val |= snes->inNmi << 7;
+ snes->inNmi = false;
+ return val | (snes->openBus & 0x70);
+ }
+ case 0x4211: {
+ uint8_t val = snes->inIrq << 7;
+ snes->inIrq = false;
+ snes->cpu->irqWanted = false;
+ return val | (snes->openBus & 0x7f);
+ }
+ case 0x4212: {
+ uint8_t val = (snes->autoJoyTimer > 0);
+ val |= (snes->hPos >= 1024) << 6;
+ val |= snes->inVblank << 7;
+ return val | (snes->openBus & 0x3e);
+ }
+ case 0x4213: {
+ return snes->ppuLatch << 7; // IO-port
+ }
+ case 0x4214: {
+ return snes->divideResult & 0xff;
+ }
+ case 0x4215: {
+ return snes->divideResult >> 8;
+ }
+ case 0x4216: {
+ return snes->multiplyResult & 0xff;
+ }
+ case 0x4217: {
+ return snes->multiplyResult >> 8;
+ }
+ case 0x4218:
+ case 0x421a:
+ case 0x421c:
+ case 0x421e: {
+ return snes->portAutoRead[(adr - 0x4218) / 2] & 0xff;
+ }
+ case 0x4219:
+ case 0x421b:
+ case 0x421d:
+ case 0x421f: {
+ return snes->portAutoRead[(adr - 0x4219) / 2] >> 8;
+ }
+ default: {
+ return snes->openBus;
+ }
+ }
+}
+
+static void snes_writeReg(Snes* snes, uint16_t adr, uint8_t val) {
+ switch(adr) {
+ case 0x4200: {
+ snes->autoJoyRead = val & 0x1;
+ if(!snes->autoJoyRead) snes->autoJoyTimer = 0;
+ snes->hIrqEnabled = val & 0x10;
+ snes->vIrqEnabled = val & 0x20;
+ snes->nmiEnabled = val & 0x80;
+ if(!snes->hIrqEnabled && !snes->vIrqEnabled) {
+ snes->inIrq = false;
+ snes->cpu->irqWanted = false;
+ }
+ // TODO: enabling nmi during vblank with inNmi still set generates nmi
+ // enabling virq (and not h) on the vPos that vTimer is at generates irq (?)
+ break;
+ }
+ case 0x4201: {
+ if(!(val & 0x80) && snes->ppuLatch) {
+ // latch the ppu
+ ppu_read(snes->ppu, 0x37);
+ }
+ snes->ppuLatch = val & 0x80;
+ break;
+ }
+ case 0x4202: {
+ snes->multiplyA = val;
+ break;
+ }
+ case 0x4203: {
+ snes->multiplyResult = snes->multiplyA * val;
+ break;
+ }
+ case 0x4204: {
+ snes->divideA = (snes->divideA & 0xff00) | val;
+ break;
+ }
+ case 0x4205: {
+ snes->divideA = (snes->divideA & 0x00ff) | (val << 8);
+ break;
+ }
+ case 0x4206: {
+ if(val == 0) {
+ snes->divideResult = 0xffff;
+ snes->multiplyResult = snes->divideA;
+ } else {
+ snes->divideResult = snes->divideA / val;
+ snes->multiplyResult = snes->divideA % val;
+ }
+ break;
+ }
+ case 0x4207: {
+ snes->hTimer = (snes->hTimer & 0x100) | val;
+ break;
+ }
+ case 0x4208: {
+ snes->hTimer = (snes->hTimer & 0x0ff) | ((val & 1) << 8);
+ break;
+ }
+ case 0x4209: {
+ snes->vTimer = (snes->vTimer & 0x100) | val;
+ break;
+ }
+ case 0x420a: {
+ snes->vTimer = (snes->vTimer & 0x0ff) | ((val & 1) << 8);
+ break;
+ }
+ case 0x420b: {
+ dma_startDma(snes->dma, val, false);
+ break;
+ }
+ case 0x420c: {
+ dma_startDma(snes->dma, val, true);
+ break;
+ }
+ case 0x420d: {
+ snes->fastMem = val & 0x1;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+static uint8_t snes_rread(Snes* snes, uint32_t adr) {
+ uint8_t bank = adr >> 16;
+ adr &= 0xffff;
+ if((bank & 0x7f) < 0x40 && adr < 0x4380) {
+ if(adr < 0x2000) {
+ return snes->ram[adr]; // ram mirror
+ }
+ if(adr >= 0x2100 && adr < 0x2200) {
+ return snes_readBBus(snes, adr & 0xff); // B-bus
+ }
+ if(adr == 0x4016) {
+ return input_read(snes->input1) | (snes->openBus & 0xfc);
+ }
+ if(adr == 0x4017) {
+ return input_read(snes->input2) | (snes->openBus & 0xe0) | 0x1c;
+ }
+ if(adr >= 0x4200 && adr < 0x4220) {
+ return snes_readReg(snes, adr); // internal registers
+ }
+ if(adr >= 0x4300 && adr < 0x4380) {
+ return dma_read(snes->dma, adr); // dma registers
+ }
+ } else if ((bank & ~1) == 0x7e) {
+ return snes->ram[((bank & 1) << 16) | adr]; // ram
+ }
+
+ // read from cart
+ return cart_read(snes->cart, bank, adr);
+}
+
+int g_bp_addr = 0;
+
+void PrintState();
+void snes_write(Snes* snes, uint32_t adr, uint8_t val) {
+ snes->openBus = val;
+ uint8_t bank = adr >> 16;
+ adr &= 0xffff;
+ if(bank == 0x7e || bank == 0x7f) {
+ if ((adr & 0xffff) == g_bp_addr && g_bp_addr) {
+ printf("@0x%x: Writing1 0x%X to 0x%x (frame %d) %.2x %.2x %.2x\n", snes->cpu->k * 65536 + snes->cpu->pc, val, adr & 0xffff, snes->ram[0x1a],
+ snes->ram[snes->cpu->sp+1], snes->ram[snes->cpu->sp+2], snes->ram[snes->cpu->sp+3]);
+ }
+
+ snes->ram[((bank & 1) << 16) | adr] = val; // ram
+ } else if(bank < 0x40 || (bank >= 0x80 && bank < 0xc0)) {
+ if (adr < 0x2000) {
+ if ((adr & 0xffff) == g_bp_addr && g_bp_addr) {
+ printf("@0x%x: Writing2 0x%X to 0x%x (frame %d) %.2x %.2x %.2x\n", snes->cpu->k * 65536 + snes->cpu->pc, val, adr & 0xffff, snes->ram[0x1a],
+ snes->ram[snes->cpu->sp+1], snes->ram[snes->cpu->sp+2], snes->ram[snes->cpu->sp+3]);
+ }
+
+ snes->ram[adr] = val; // ram mirror
+ } else if(adr >= 0x2100 && adr < 0x2200) {
+ snes_writeBBus(snes, adr & 0xff, val); // B-bus
+ } else if(adr == 0x4016) {
+ snes->input1->latchLine = val & 1;
+ snes->input2->latchLine = val & 1;
+ } else if(adr >= 0x4200 && adr < 0x4220) {
+ snes_writeReg(snes, adr, val); // internal registers
+ } else if(adr >= 0x4300 && adr < 0x4380) {
+ dma_write(snes->dma, adr, val); // dma registers
+ }
+ }
+ cart_write(snes->cart, bank, adr, val);
+ // write to cart
+}
+
+static int snes_getAccessTime(Snes* snes, uint32_t adr) {
+ // optimization
+ return 6;
+
+ uint8_t bank = adr >> 16;
+ adr &= 0xffff;
+ if(bank >= 0x40 && bank < 0x80) {
+ return 8; // slow
+ }
+ if(bank >= 0xc0) {
+ return snes->fastMem ? 6 : 8; // depends on setting
+ }
+ // banks 0x00-0x3f and 0x80-0xcf
+ if(adr < 0x2000) {
+ return 8; // slow
+ }
+ if(adr < 0x4000) {
+ return 6; // fast
+ }
+ if(adr < 0x4200) {
+ return 12; // extra slow
+ }
+ if(adr < 0x6000) {
+ return 6; // fast
+ }
+ if(adr < 0x8000) {
+ return 8; // slow
+ }
+ // 0x8000-0xffff
+ return (snes->fastMem && bank >= 0x80) ? 6 : 8; // depends on setting in banks 80+
+}
+
+uint8_t snes_read(Snes* snes, uint32_t adr) {
+ uint8_t val = snes_rread(snes, adr);
+ snes->openBus = val;
+ return val;
+}
+
+uint8_t snes_cpuRead(Snes* snes, uint32_t adr) {
+ snes->cpuMemOps++;
+ snes->cpuCyclesLeft += snes_getAccessTime(snes, adr);
+ return snes_read(snes, adr);
+}
+
+void snes_cpuWrite(Snes* snes, uint32_t adr, uint8_t val) {
+ snes->cpuMemOps++;
+ snes->cpuCyclesLeft += snes_getAccessTime(snes, adr);
+ snes_write(snes, adr, val);
+}
+
+// debugging
+
+void snes_debugCycle(Snes* snes, bool* cpuNext, bool* spcNext) {
+ // runs a normal cycle, catches up the apu, then looks if the next cycle will execute a CPU and/or a SPC opcode
+ snes_runCycle(snes);
+ snes_catchupApu(snes);
+ if(snes->dma->hdmaTimer > 0 || snes->dma->dmaBusy || (snes->hPos >= 536 && snes->hPos < 576)) {
+ *cpuNext = false;
+ } else {
+ *cpuNext = snes->cpuCyclesLeft == 0;
+ }
+ if(snes->apuCatchupCycles + (apuCyclesPerMaster * 2.0) >= 1.0) {
+ // we will run a apu cycle next call, see if it also starts a opcode
+ *spcNext = snes->apu->cpuCyclesLeft == 0;
+ } else {
+ *spcNext = false;
+ }
+}
--- /dev/null
+++ b/snes/snes.h
@@ -1,0 +1,106 @@
+
+#ifndef SNES_H
+#define SNES_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct Snes Snes;
+
+#include "cpu.h"
+#include "apu.h"
+#include "dma.h"
+#include "ppu.h"
+#include "cart.h"
+#include "input.h"
+
+enum {
+ kIsOrigEmu = 0
+};
+
+
+struct Snes {
+ Cpu* cpu;
+ Apu* apu;
+ Ppu* ppu;
+ Dma* dma;
+ Cart* cart;
+ // input
+ bool debug_cycles;
+ bool disableHpos;
+ Input* input1;
+ Input* input2;
+
+
+ // frame timing
+
+
+ uint16_t hPos;
+ uint16_t vPos;
+ uint32_t frames;
+ // cpu handling
+ uint8_t cpuCyclesLeft;
+ uint8_t cpuMemOps;
+ double apuCatchupCycles;
+ // nmi / irq
+ bool hIrqEnabled;
+ bool vIrqEnabled;
+ bool nmiEnabled;
+ uint16_t hTimer;
+ uint16_t vTimer;
+ bool inNmi;
+ bool inIrq;
+ bool inVblank;
+ // joypad handling
+ uint16_t portAutoRead[4]; // as read by auto-joypad read
+ bool autoJoyRead;
+ uint16_t autoJoyTimer; // times how long until reading is done
+ bool ppuLatch;
+ // multiplication/division
+ uint8_t multiplyA;
+ uint16_t multiplyResult;
+ uint16_t divideA;
+ uint16_t divideResult;
+ // misc
+ bool fastMem;
+ uint8_t openBus;
+ // ram
+ uint8_t *ram;
+ uint32_t ramAdr;
+};
+
+Snes* snes_init(uint8_t *ram);
+void snes_free(Snes* snes);
+void snes_reset(Snes* snes, bool hard);
+void snes_runFrame(Snes* snes);
+// used by dma, cpu
+uint8_t snes_readBBus(Snes* snes, uint8_t adr);
+void snes_writeBBus(Snes* snes, uint8_t adr, uint8_t val);
+uint8_t snes_read(Snes* snes, uint32_t adr);
+void snes_write(Snes* snes, uint32_t adr, uint8_t val);
+uint8_t snes_cpuRead(Snes* snes, uint32_t adr);
+void snes_cpuWrite(Snes* snes, uint32_t adr, uint8_t val);
+// debugging
+void snes_debugCycle(Snes* snes, bool* cpuNext, bool* spcNext);
+void snes_printCpuLine(Snes *snes);
+void snes_doAutoJoypad(Snes *snes);
+// snes_other.c functions:
+
+bool snes_loadRom(Snes* snes, uint8_t* data, int length);
+void snes_setButtonState(Snes* snes, int player, int button, bool pressed);
+void snes_setPixels(Snes* snes, uint8_t* pixelData);
+void snes_setSamples(Snes* snes, int16_t* sampleData, int samplesPerFrame);
+void snes_saveload(Snes *snes, SaveLoadFunc *func, void *ctx);
+
+enum {
+ kSaveLoad_Save = 0,
+ kSaveLoad_Load = 1,
+ kSaveLoad_Replay = 2,
+};
+
+
+#endif
+
--- /dev/null
+++ b/snes/snes_other.cpp
@@ -1,0 +1,220 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "snes.h"
+#include "cart.h"
+#include "ppu.h"
+#include "dsp.h"
+
+typedef struct CartHeader {
+ // normal header
+ uint8_t headerVersion; // 1, 2, 3
+ char name[22]; // $ffc0-$ffd4 (max 21 bytes + \0), $ffd4=$00: header V2
+ uint8_t speed; // $ffd5.7-4 (always 2 or 3)
+ uint8_t type; // $ffd5.3-0
+ uint8_t coprocessor; // $ffd6.7-4
+ uint8_t chips; // $ffd6.3-0
+ uint32_t romSize; // $ffd7 (0x400 << x)
+ uint32_t ramSize; // $ffd8 (0x400 << x)
+ uint8_t region; // $ffd9 (also NTSC/PAL)
+ uint8_t maker; // $ffda ($33: header V3)
+ uint8_t version; // $ffdb
+ uint16_t checksumComplement; // $ffdc,$ffdd
+ uint16_t checksum; // $ffde,$ffdf
+ // v2/v3 (v2 only exCoprocessor)
+ char makerCode[3]; // $ffb0,$ffb1: (2 chars + \0)
+ char gameCode[5]; // $ffb2-$ffb5: (4 chars + \0)
+ uint32_t flashSize; // $ffbc (0x400 << x)
+ uint32_t exRamSize; // $ffbd (0x400 << x) (used for GSU?)
+ uint8_t specialVersion; // $ffbe
+ uint8_t exCoprocessor; // $ffbf (if coprocessor = $f)
+ // calculated stuff
+ int16_t score; // score for header, to see which mapping is most likely
+ bool pal; // if this is a rom for PAL regions instead of NTSC
+ uint8_t cartType; // calculated type
+} CartHeader;
+
+static void readHeader(uint8_t* data, int location, CartHeader* header);
+
+bool snes_loadRom(Snes* snes, uint8_t* data, int length) {
+ // if smaller than smallest possible, don't load
+ if(length < 0x8000) {
+ printf("Failed to load rom: rom to small (%d bytes)\n", length);
+ return false;
+ }
+ // check headers
+ CartHeader headers[4];
+ memset(headers, 0, sizeof(headers));
+ for(int i = 0; i < 4; i++) {
+ headers[i].score = -50;
+ }
+ if(length >= 0x8000) readHeader(data, 0x7fc0, &headers[0]);
+ if(length >= 0x8200) readHeader(data, 0x81c0, &headers[1]);
+ if(length >= 0x10000) readHeader(data, 0xffc0, &headers[2]);
+ if(length >= 0x10200) readHeader(data, 0x101c0, &headers[3]);
+ // see which it is
+ int max = 0;
+ int used = 0;
+ for(int i = 0; i < 4; i++) {
+ if(headers[i].score > max) {
+ max = headers[i].score;
+ used = i;
+ }
+ }
+ if(used & 1) {
+ // odd-numbered ones are for headered roms
+ data += 0x200; // move pointer past header
+ length -= 0x200; // and subtract from size
+ }
+ // check if we can load it
+ if(headers[used].cartType > 2) {
+ printf("Failed to load rom: unsupported type (%d)\n", headers[used].cartType);
+ return false;
+ }
+ // expand to a power of 2
+ int newLength = 0x8000;
+ while(true) {
+ if(length <= newLength) {
+ break;
+ }
+ newLength *= 2;
+ }
+ uint8_t* newData = (uint8_t * )malloc(newLength);
+ memcpy(newData, data, length);
+ int test = 1;
+ while(length != newLength) {
+ if(length & test) {
+ memcpy(newData + length, newData + length - test, test);
+ length += test;
+ }
+ test *= 2;
+ }
+ // load it
+ printf("Loaded %s rom\n\"%s\"\n", headers[used].cartType == 2 ? "HiROM" : "LoROM", headers[used].name);
+ cart_load(
+ snes->cart, headers[used].cartType,
+ newData, newLength, headers[used].chips > 0 ? headers[used].ramSize : 0
+ );
+ snes_reset(snes, true); // reset after loading
+ free(newData);
+ return true;
+}
+
+void snes_setButtonState(Snes* snes, int player, int button, bool pressed) {
+ // set key in constroller
+ if(player == 1) {
+ if(pressed) {
+ snes->input1->currentState |= 1 << button;
+ } else {
+ snes->input1->currentState &= ~(1 << button);
+ }
+ } else {
+ if(pressed) {
+ snes->input2->currentState |= 1 << button;
+ } else {
+ snes->input2->currentState &= ~(1 << button);
+ }
+ }
+}
+
+void snes_setPixels(Snes* snes, uint8_t* pixelData) {
+ // size is 4 (rgba) * 512 (w) * 480 (h)
+ ppu_putPixels(snes->ppu, pixelData);
+}
+
+void snes_setSamples(Snes* snes, int16_t* sampleData, int samplesPerFrame) {
+ // size is 2 (int16) * 2 (stereo) * samplesPerFrame
+ // sets samples in the sampleData
+ dsp_getSamples(snes->apu->dsp, sampleData, samplesPerFrame);
+}
+
+static void readHeader(uint8_t* data, int location, CartHeader* header) {
+ // read name, TODO: non-ASCII names?
+ for(int i = 0; i < 21; i++) {
+ uint8_t ch = data[location + i];
+ if(ch >= 0x20 && ch < 0x7f) {
+ header->name[i] = ch;
+ } else {
+ header->name[i] = '.';
+ }
+ }
+ header->name[21] = 0;
+ // read rest
+ header->speed = data[location + 0x15] >> 4;
+ header->type = data[location + 0x15] & 0xf;
+ header->coprocessor = data[location + 0x16] >> 4;
+ header->chips = data[location + 0x16] & 0xf;
+ header->romSize = 0x400 << data[location + 0x17];
+ header->ramSize = 0x400 << data[location + 0x18];
+ header->region = data[location + 0x19];
+ header->maker = data[location + 0x1a];
+ header->version = data[location + 0x1b];
+ header->checksumComplement = (data[location + 0x1d] << 8) + data[location + 0x1c];
+ header->checksum = (data[location + 0x1f] << 8) + data[location + 0x1e];
+ // read v3 and/or v2
+ header->headerVersion = 1;
+ if(header->maker == 0x33) {
+ header->headerVersion = 3;
+ // maker code
+ for(int i = 0; i < 2; i++) {
+ uint8_t ch = data[location - 0x10 + i];
+ if(ch >= 0x20 && ch < 0x7f) {
+ header->makerCode[i] = ch;
+ } else {
+ header->makerCode[i] = '.';
+ }
+ }
+ header->makerCode[2] = 0;
+ // game code
+ for(int i = 0; i < 4; i++) {
+ uint8_t ch = data[location - 0xe + i];
+ if(ch >= 0x20 && ch < 0x7f) {
+ header->gameCode[i] = ch;
+ } else {
+ header->gameCode[i] = '.';
+ }
+ }
+ header->gameCode[4] = 0;
+ header->flashSize = 0x400 << data[location - 4];
+ header->exRamSize = 0x400 << data[location - 3];
+ header->specialVersion = data[location - 2];
+ header->exCoprocessor = data[location - 1];
+ } else if(data[location + 0x14] == 0) {
+ header->headerVersion = 2;
+ header->exCoprocessor = data[location - 1];
+ }
+ // get region
+ header->pal = (header->region >= 0x2 && header->region <= 0xc) || header->region == 0x11;
+ header->cartType = location < 0x9000 ? 1 : 2;
+ // get score
+ // TODO: check name, maker/game-codes (if V3) for ASCII, more vectors,
+ // more first opcode, rom-sizes (matches?), type (matches header location?)
+ int score = 0;
+ score += (header->speed == 2 || header->speed == 3) ? 5 : -4;
+ score += (header->type <= 3 || header->type == 5) ? 5 : -2;
+ score += (header->coprocessor <= 5 || header->coprocessor >= 0xe) ? 5 : -2;
+ score += (header->chips <= 6 || header->chips == 9 || header->chips == 0xa) ? 5 : -2;
+ score += (header->region <= 0x14) ? 5 : -2;
+ score += (header->checksum + header->checksumComplement == 0xffff) ? 8 : -6;
+ uint16_t resetVector = data[location + 0x3c] | (data[location + 0x3d] << 8);
+ score += (resetVector >= 0x8000) ? 8 : -20;
+ // check first opcode after reset
+ uint8_t opcode = data[location + 0x40 - 0x8000 + (resetVector & 0x7fff)];
+ if(opcode == 0x78 || opcode == 0x18) {
+ // sei, clc (for clc:xce)
+ score += 6;
+ }
+ if(opcode == 0x4c || opcode == 0x5c || opcode == 0x9c) {
+ // jmp abs, jml abl, stz abs
+ score += 3;
+ }
+ if(opcode == 0x00 || opcode == 0xff || opcode == 0xdb) {
+ // brk, sbc alx, stp
+ score -= 6;
+ }
+ header->score = score;
+}
--- /dev/null
+++ b/snes/spc.cpp
@@ -1,0 +1,1528 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include "spc.h"
+#include "apu.h"
+
+static const int cyclesPerOpcode[256] = {
+ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 5, 4, 5, 4, 6, 8,
+ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 6, 5, 2, 2, 4, 6,
+ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 5, 4, 5, 4, 5, 4,
+ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 6, 5, 2, 2, 3, 8,
+ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 4, 4, 5, 4, 6, 6,
+ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 4, 5, 2, 2, 4, 3,
+ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 4, 4, 5, 4, 5, 5,
+ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 5, 5, 2, 2, 3, 6,
+ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 5, 4, 5, 2, 4, 5,
+ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 5, 5, 2, 2, 12,5,
+ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 4, 4, 5, 2, 4, 4,
+ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 5, 5, 2, 2, 3, 4,
+ 2, 8, 4, 5, 4, 5, 4, 7, 2, 5, 6, 4, 5, 2, 4, 9,
+ 2, 8, 4, 5, 5, 6, 6, 7, 4, 5, 5, 5, 2, 2, 6, 3,
+ 2, 8, 4, 5, 3, 4, 3, 6, 2, 4, 5, 3, 4, 3, 4, 3,
+ 2, 8, 4, 5, 4, 5, 5, 6, 3, 4, 5, 4, 2, 2, 4, 3
+};
+
+static uint8_t spc_read(Spc* spc, uint16_t adr);
+static void spc_write(Spc* spc, uint16_t adr, uint8_t val);
+static uint8_t spc_readOpcode(Spc* spc);
+static uint16_t spc_readOpcodeWord(Spc* spc);
+static uint8_t spc_getFlags(Spc* spc);
+static void spc_setFlags(Spc* spc, uint8_t value);
+static void spc_setZN(Spc* spc, uint8_t value);
+static void spc_doBranch(Spc* spc, uint8_t value, bool check);
+static uint8_t spc_pullByte(Spc* spc);
+static void spc_pushByte(Spc* spc, uint8_t value);
+static uint16_t spc_pullWord(Spc* spc);
+static void spc_pushWord(Spc* spc, uint16_t value);
+static uint16_t spc_readWord(Spc* spc, uint16_t adrl, uint16_t adrh);
+static void spc_writeWord(Spc* spc, uint16_t adrl, uint16_t adrh, uint16_t value);
+static void spc_doOpcode(Spc* spc, uint8_t opcode);
+
+// addressing modes and opcode functions not declared, only used after defintions
+
+static uint8_t spc_read(Spc* spc, uint16_t adr) {
+ return apu_cpuRead(spc->apu, adr);
+}
+
+static void spc_write(Spc* spc, uint16_t adr, uint8_t val) {
+ if (0 && adr == 0x5e)
+ printf("writing to vol_dirty %d\n", val);
+ apu_cpuWrite(spc->apu, adr, val);
+}
+
+Spc* spc_init(Apu* apu) {
+ Spc* spc = (Spc * )malloc(sizeof(Spc));
+ spc->apu = apu;
+ return spc;
+}
+
+void spc_free(Spc* spc) {
+ free(spc);
+}
+
+void spc_reset(Spc* spc) {
+ spc->a = 0;
+ spc->x = 0;
+ spc->y = 0;
+ spc->sp = 0;
+ spc->pc = spc_read(spc, 0xfffe) | (spc_read(spc, 0xffff) << 8);
+ spc->c = false;
+ spc->z = false;
+ spc->v = false;
+ spc->n = false;
+ spc->i = false;
+ spc->h = false;
+ spc->p = false;
+ spc->b = false;
+ spc->stopped = false;
+ spc->cyclesUsed = 0;
+}
+
+void spc_saveload(Spc *spc, SaveLoadFunc *func, void *ctx) {
+ func(ctx, &spc->a, offsetof(Spc, cyclesUsed) - offsetof(Spc, a));
+}
+
+int spc_runOpcode(Spc* spc) {
+ spc->cyclesUsed = 0;
+ if(spc->stopped) return 1;
+ uint8_t opcode = spc_readOpcode(spc);
+ spc->cyclesUsed = cyclesPerOpcode[opcode];
+ spc_doOpcode(spc, opcode);
+ return spc->cyclesUsed;
+}
+
+static uint8_t spc_readOpcode(Spc* spc) {
+ return spc_read(spc, spc->pc++);
+}
+
+static uint16_t spc_readOpcodeWord(Spc* spc) {
+ uint8_t low = spc_readOpcode(spc);
+ return low | (spc_readOpcode(spc) << 8);
+}
+
+static uint8_t spc_getFlags(Spc* spc) {
+ uint8_t val = spc->n << 7;
+ val |= spc->v << 6;
+ val |= spc->p << 5;
+ val |= spc->b << 4;
+ val |= spc->h << 3;
+ val |= spc->i << 2;
+ val |= spc->z << 1;
+ val |= (uint8_t)spc->c;
+ return val;
+}
+
+static void spc_setFlags(Spc* spc, uint8_t val) {
+ spc->n = val & 0x80;
+ spc->v = val & 0x40;
+ spc->p = val & 0x20;
+ spc->b = val & 0x10;
+ spc->h = val & 8;
+ spc->i = val & 4;
+ spc->z = val & 2;
+ spc->c = val & 1;
+}
+
+static void spc_setZN(Spc* spc, uint8_t value) {
+ spc->z = value == 0;
+ spc->n = value & 0x80;
+}
+
+static void spc_doBranch(Spc* spc, uint8_t value, bool check) {
+ if(check) {
+ spc->cyclesUsed += 2; // taken branch: 2 extra cycles
+ spc->pc += (int8_t) value;
+ }
+}
+
+static uint8_t spc_pullByte(Spc* spc) {
+ spc->sp++;
+ return spc_read(spc, 0x100 | spc->sp);
+}
+
+static void spc_pushByte(Spc* spc, uint8_t value) {
+ spc_write(spc, 0x100 | spc->sp, value);
+ spc->sp--;
+}
+
+static uint16_t spc_pullWord(Spc* spc) {
+ uint8_t value = spc_pullByte(spc);
+ return value | (spc_pullByte(spc) << 8);
+}
+
+static void spc_pushWord(Spc* spc, uint16_t value) {
+ spc_pushByte(spc, value >> 8);
+ spc_pushByte(spc, value & 0xff);
+}
+
+static uint16_t spc_readWord(Spc* spc, uint16_t adrl, uint16_t adrh) {
+ uint8_t value = spc_read(spc, adrl);
+ return value | (spc_read(spc, adrh) << 8);
+}
+
+static void spc_writeWord(Spc* spc, uint16_t adrl, uint16_t adrh, uint16_t value) {
+ spc_write(spc, adrl, value & 0xff);
+ spc_write(spc, adrh, value >> 8);
+}
+
+// adressing modes
+
+static uint16_t spc_adrDp(Spc* spc) {
+ return spc_readOpcode(spc) | (spc->p << 8);
+}
+
+static uint16_t spc_adrAbs(Spc* spc) {
+ return spc_readOpcodeWord(spc);
+}
+
+static uint16_t spc_adrInd(Spc* spc) {
+ return spc->x | (spc->p << 8);
+}
+
+static uint16_t spc_adrIdx(Spc* spc) {
+ uint8_t pointer = spc_readOpcode(spc);
+ return spc_readWord(spc, ((pointer + spc->x) & 0xff) | (spc->p << 8), ((pointer + spc->x + 1) & 0xff) | (spc->p << 8));
+}
+
+static uint16_t spc_adrImm(Spc* spc) {
+ return spc->pc++;
+}
+
+static uint16_t spc_adrDpx(Spc* spc) {
+ return ((spc_readOpcode(spc) + spc->x) & 0xff) | (spc->p << 8);
+}
+
+static uint16_t spc_adrDpy(Spc* spc) {
+ return ((spc_readOpcode(spc) + spc->y) & 0xff) | (spc->p << 8);
+}
+
+static uint16_t spc_adrAbx(Spc* spc) {
+ return (spc_readOpcodeWord(spc) + spc->x) & 0xffff;
+}
+
+static uint16_t spc_adrAby(Spc* spc) {
+ return (spc_readOpcodeWord(spc) + spc->y) & 0xffff;
+}
+
+static uint16_t spc_adrIdy(Spc* spc) {
+ uint8_t pointer = spc_readOpcode(spc);
+ uint16_t adr = spc_readWord(spc, pointer | (spc->p << 8), ((pointer + 1) & 0xff) | (spc->p << 8));
+ return (adr + spc->y) & 0xffff;
+}
+
+static uint16_t spc_adrDpDp(Spc* spc, uint16_t* src) {
+ *src = spc_readOpcode(spc) | (spc->p << 8);
+ return spc_readOpcode(spc) | (spc->p << 8);
+}
+
+static uint16_t spc_adrDpImm(Spc* spc, uint16_t* src) {
+ *src = spc->pc++;
+ return spc_readOpcode(spc) | (spc->p << 8);
+}
+
+static uint16_t spc_adrIndInd(Spc* spc, uint16_t* src) {
+ *src = spc->y | (spc->p << 8);
+ return spc->x | (spc->p << 8);
+}
+
+static uint8_t spc_adrAbsBit(Spc* spc, uint16_t* adr) {
+ uint16_t adrBit = spc_readOpcodeWord(spc);
+ *adr = adrBit & 0x1fff;
+ return adrBit >> 13;
+}
+
+static uint16_t spc_adrDpWord(Spc* spc, uint16_t* low) {
+ uint8_t adr = spc_readOpcode(spc);
+ *low = adr | (spc->p << 8);
+ return ((adr + 1) & 0xff) | (spc->p << 8);
+}
+
+static uint16_t spc_adrIndP(Spc* spc) {
+ return spc->x++ | (spc->p << 8);
+}
+
+// opcode functions
+
+static void spc_and(Spc* spc, uint16_t adr) {
+ spc->a &= spc_read(spc, adr);
+ spc_setZN(spc, spc->a);
+}
+
+static void spc_andm(Spc* spc, uint16_t dst, uint16_t src) {
+ uint8_t value = spc_read(spc, src);
+ uint8_t result = spc_read(spc, dst) & value;
+ spc_write(spc, dst, result);
+ spc_setZN(spc, result);
+}
+
+static void spc_or(Spc* spc, uint16_t adr) {
+ spc->a |= spc_read(spc, adr);
+ spc_setZN(spc, spc->a);
+}
+
+static void spc_orm(Spc* spc, uint16_t dst, uint16_t src) {
+ uint8_t value = spc_read(spc, src);
+ uint8_t result = spc_read(spc, dst) | value;
+ spc_write(spc, dst, result);
+ spc_setZN(spc, result);
+}
+
+static void spc_eor(Spc* spc, uint16_t adr) {
+ spc->a ^= spc_read(spc, adr);
+ spc_setZN(spc, spc->a);
+}
+
+static void spc_eorm(Spc* spc, uint16_t dst, uint16_t src) {
+ uint8_t value = spc_read(spc, src);
+ uint8_t result = spc_read(spc, dst) ^ value;
+ spc_write(spc, dst, result);
+ spc_setZN(spc, result);
+}
+
+static void spc_adc(Spc* spc, uint16_t adr) {
+ uint8_t value = spc_read(spc, adr);
+ int result = spc->a + value + spc->c;
+ spc->v = (spc->a & 0x80) == (value & 0x80) && (value & 0x80) != (result & 0x80);
+ spc->h = ((spc->a & 0xf) + (value & 0xf) + spc->c) > 0xf;
+ spc->c = result > 0xff;
+ spc->a = result;
+ spc_setZN(spc, spc->a);
+}
+
+static void spc_adcm(Spc* spc, uint16_t dst, uint16_t src) {
+ uint8_t value = spc_read(spc, src);
+ uint8_t applyOn = spc_read(spc, dst);
+ int result = applyOn + value + spc->c;
+ spc->v = (applyOn & 0x80) == (value & 0x80) && (value & 0x80) != (result & 0x80);
+ spc->h = ((applyOn & 0xf) + (value & 0xf) + spc->c) > 0xf;
+ spc->c = result > 0xff;
+ spc_write(spc, dst, result);
+ spc_setZN(spc, result);
+}
+
+static void spc_sbc(Spc* spc, uint16_t adr) {
+ uint8_t value = spc_read(spc, adr) ^ 0xff;
+ int result = spc->a + value + spc->c;
+ spc->v = (spc->a & 0x80) == (value & 0x80) && (value & 0x80) != (result & 0x80);
+ spc->h = ((spc->a & 0xf) + (value & 0xf) + spc->c) > 0xf;
+ spc->c = result > 0xff;
+ spc->a = result;
+ spc_setZN(spc, spc->a);
+}
+
+static void spc_sbcm(Spc* spc, uint16_t dst, uint16_t src) {
+ uint8_t value = spc_read(spc, src) ^ 0xff;
+ uint8_t applyOn = spc_read(spc, dst);
+ int result = applyOn + value + spc->c;
+ spc->v = (applyOn & 0x80) == (value & 0x80) && (value & 0x80) != (result & 0x80);
+ spc->h = ((applyOn & 0xf) + (value & 0xf) + spc->c) > 0xf;
+ spc->c = result > 0xff;
+ spc_write(spc, dst, result);
+ spc_setZN(spc, result);
+}
+
+static void spc_cmp(Spc* spc, uint16_t adr) {
+ uint8_t value = spc_read(spc, adr) ^ 0xff;
+ int result = spc->a + value + 1;
+ spc->c = result > 0xff;
+ spc_setZN(spc, result);
+}
+
+static void spc_cmpx(Spc* spc, uint16_t adr) {
+ uint8_t value = spc_read(spc, adr) ^ 0xff;
+ int result = spc->x + value + 1;
+ spc->c = result > 0xff;
+ spc_setZN(spc, result);
+}
+
+static void spc_cmpy(Spc* spc, uint16_t adr) {
+ uint8_t value = spc_read(spc, adr) ^ 0xff;
+ int result = spc->y + value + 1;
+ spc->c = result > 0xff;
+ spc_setZN(spc, result);
+}
+
+static void spc_cmpm(Spc* spc, uint16_t dst, uint16_t src) {
+ uint8_t value = spc_read(spc, src) ^ 0xff;
+ int result = spc_read(spc, dst) + value + 1;
+ spc->c = result > 0xff;
+ spc_setZN(spc, result);
+}
+
+static void spc_mov(Spc* spc, uint16_t adr) {
+ spc->a = spc_read(spc, adr);
+ spc_setZN(spc, spc->a);
+}
+
+static void spc_movx(Spc* spc, uint16_t adr) {
+ spc->x = spc_read(spc, adr);
+ spc_setZN(spc, spc->x);
+}
+
+static void spc_movy(Spc* spc, uint16_t adr) {
+ spc->y = spc_read(spc, adr);
+ spc_setZN(spc, spc->y);
+}
+
+static void spc_movs(Spc* spc, uint16_t adr) {
+ spc_read(spc, adr);
+ spc_write(spc, adr, spc->a);
+}
+
+static void spc_movsx(Spc* spc, uint16_t adr) {
+ spc_read(spc, adr);
+ spc_write(spc, adr, spc->x);
+}
+
+static void spc_movsy(Spc* spc, uint16_t adr) {
+ spc_read(spc, adr);
+ spc_write(spc, adr, spc->y);
+}
+
+static void spc_asl(Spc* spc, uint16_t adr) {
+ uint8_t val = spc_read(spc, adr);
+ spc->c = val & 0x80;
+ val <<= 1;
+ spc_write(spc, adr, val);
+ spc_setZN(spc, val);
+}
+
+static void spc_lsr(Spc* spc, uint16_t adr) {
+ uint8_t val = spc_read(spc, adr);
+ spc->c = val & 1;
+ val >>= 1;
+ spc_write(spc, adr, val);
+ spc_setZN(spc, val);
+}
+
+static void spc_rol(Spc* spc, uint16_t adr) {
+ uint8_t val = spc_read(spc, adr);
+ bool newC = val & 0x80;
+ val = (val << 1) | (uint8_t)spc->c;
+ spc->c = newC;
+ spc_write(spc, adr, val);
+ spc_setZN(spc, val);
+}
+
+static void spc_ror(Spc* spc, uint16_t adr) {
+ uint8_t val = spc_read(spc, adr);
+ bool newC = val & 1;
+ val = (val >> 1) | (spc->c << 7);
+ spc->c = newC;
+ spc_write(spc, adr, val);
+ spc_setZN(spc, val);
+}
+
+static void spc_inc(Spc* spc, uint16_t adr) {
+ uint8_t val = spc_read(spc, adr) + 1;
+ spc_write(spc, adr, val);
+ spc_setZN(spc, val);
+}
+
+static void spc_dec(Spc* spc, uint16_t adr) {
+ uint8_t val = spc_read(spc, adr) - 1;
+ spc_write(spc, adr, val);
+ spc_setZN(spc, val);
+}
+
+static void spc_doOpcode(Spc* spc, uint8_t opcode) {
+ switch(opcode) {
+ case 0x00: { // nop imp
+ // no operation
+ break;
+ }
+ case 0x01:
+ case 0x11:
+ case 0x21:
+ case 0x31:
+ case 0x41:
+ case 0x51:
+ case 0x61:
+ case 0x71:
+ case 0x81:
+ case 0x91:
+ case 0xa1:
+ case 0xb1:
+ case 0xc1:
+ case 0xd1:
+ case 0xe1:
+ case 0xf1: { // tcall imp
+ spc_pushWord(spc, spc->pc);
+ uint16_t adr = 0xffde - (2 * (opcode >> 4));
+ spc->pc = spc_readWord(spc, adr, adr + 1);
+ break;
+ }
+ case 0x02:
+ case 0x22:
+ case 0x42:
+ case 0x62:
+ case 0x82:
+ case 0xa2:
+ case 0xc2:
+ case 0xe2: { // set1 dp
+ uint16_t adr = spc_adrDp(spc);
+ spc_write(spc, adr, spc_read(spc, adr) | (1 << (opcode >> 5)));
+ break;
+ }
+ case 0x12:
+ case 0x32:
+ case 0x52:
+ case 0x72:
+ case 0x92:
+ case 0xb2:
+ case 0xd2:
+ case 0xf2: { // clr1 dp
+ uint16_t adr = spc_adrDp(spc);
+ spc_write(spc, adr, spc_read(spc, adr) & ~(1 << (opcode >> 5)));
+ break;
+ }
+ case 0x03:
+ case 0x23:
+ case 0x43:
+ case 0x63:
+ case 0x83:
+ case 0xa3:
+ case 0xc3:
+ case 0xe3: { // bbs dp, rel
+ uint8_t val = spc_read(spc, spc_adrDp(spc));
+ spc_doBranch(spc, spc_readOpcode(spc), val & (1 << (opcode >> 5)));
+ break;
+ }
+ case 0x13:
+ case 0x33:
+ case 0x53:
+ case 0x73:
+ case 0x93:
+ case 0xb3:
+ case 0xd3:
+ case 0xf3: { // bbc dp, rel
+ uint8_t val = spc_read(spc, spc_adrDp(spc));
+ spc_doBranch(spc, spc_readOpcode(spc), (val & (1 << (opcode >> 5))) == 0);
+ break;
+ }
+ case 0x04: { // or dp
+ spc_or(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0x05: { // or abs
+ spc_or(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0x06: { // or ind
+ spc_or(spc, spc_adrInd(spc));
+ break;
+ }
+ case 0x07: { // or idx
+ spc_or(spc, spc_adrIdx(spc));
+ break;
+ }
+ case 0x08: { // or imm
+ spc_or(spc, spc_adrImm(spc));
+ break;
+ }
+ case 0x09: { // orm dp, dp
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpDp(spc, &src);
+ spc_orm(spc, dst, src);
+ break;
+ }
+ case 0x0a: { // or1 abs.bit
+ uint16_t adr = 0;
+ uint8_t bit = spc_adrAbsBit(spc, &adr);
+ spc->c = spc->c | ((spc_read(spc, adr) >> bit) & 1);
+ break;
+ }
+ case 0x0b: { // asl dp
+ spc_asl(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0x0c: { // asl abs
+ spc_asl(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0x0d: { // pushp imp
+ spc_pushByte(spc, spc_getFlags(spc));
+ break;
+ }
+ case 0x0e: { // tset1 abs
+ uint16_t adr = spc_adrAbs(spc);
+ uint8_t val = spc_read(spc, adr);
+ uint8_t result = spc->a + (val ^ 0xff) + 1;
+ spc_setZN(spc, result);
+ spc_write(spc, adr, val | spc->a);
+ break;
+ }
+ case 0x0f: { // brk imp
+ spc_pushWord(spc, spc->pc);
+ spc_pushByte(spc, spc_getFlags(spc));
+ spc->i = false;
+ spc->b = true;
+ spc->pc = spc_readWord(spc, 0xffde, 0xffdf);
+ break;
+ }
+ case 0x10: { // bpl rel
+ spc_doBranch(spc, spc_readOpcode(spc), !spc->n);
+ break;
+ }
+ case 0x14: { // or dpx
+ spc_or(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0x15: { // or abx
+ spc_or(spc, spc_adrAbx(spc));
+ break;
+ }
+ case 0x16: { // or aby
+ spc_or(spc, spc_adrAby(spc));
+ break;
+ }
+ case 0x17: { // or idy
+ spc_or(spc, spc_adrIdy(spc));
+ break;
+ }
+ case 0x18: { // orm dp, imm
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpImm(spc, &src);
+ spc_orm(spc, dst, src);
+ break;
+ }
+ case 0x19: { // orm ind, ind
+ uint16_t src = 0;
+ uint16_t dst = spc_adrIndInd(spc, &src);
+ spc_orm(spc, dst, src);
+ break;
+ }
+ case 0x1a: { // decw dp
+ uint16_t low = 0;
+ uint16_t high = spc_adrDpWord(spc, &low);
+ uint16_t value = spc_readWord(spc, low, high) - 1;
+ spc->z = value == 0;
+ spc->n = value & 0x8000;
+ spc_writeWord(spc, low, high, value);
+ break;
+ }
+ case 0x1b: { // asl dpx
+ spc_asl(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0x1c: { // asla imp
+ spc->c = spc->a & 0x80;
+ spc->a <<= 1;
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0x1d: { // decx imp
+ spc->x--;
+ spc_setZN(spc, spc->x);
+ break;
+ }
+ case 0x1e: { // cmpx abs
+ spc_cmpx(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0x1f: { // jmp iax
+ uint16_t pointer = spc_readOpcodeWord(spc);
+ spc->pc = spc_readWord(spc, (pointer + spc->x) & 0xffff, (pointer + spc->x + 1) & 0xffff);
+ break;
+ }
+ case 0x20: { // clrp imp
+ spc->p = false;
+ break;
+ }
+ case 0x24: { // and dp
+ spc_and(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0x25: { // and abs
+ spc_and(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0x26: { // and ind
+ spc_and(spc, spc_adrInd(spc));
+ break;
+ }
+ case 0x27: { // and idx
+ spc_and(spc, spc_adrIdx(spc));
+ break;
+ }
+ case 0x28: { // and imm
+ spc_and(spc, spc_adrImm(spc));
+ break;
+ }
+ case 0x29: { // andm dp, dp
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpDp(spc, &src);
+ spc_andm(spc, dst, src);
+ break;
+ }
+ case 0x2a: { // or1n abs.bit
+ uint16_t adr = 0;
+ uint8_t bit = spc_adrAbsBit(spc, &adr);
+ spc->c = spc->c | (~(spc_read(spc, adr) >> bit) & 1);
+ break;
+ }
+ case 0x2b: { // rol dp
+ spc_rol(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0x2c: { // rol abs
+ spc_rol(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0x2d: { // pusha imp
+ spc_pushByte(spc, spc->a);
+ break;
+ }
+ case 0x2e: { // cbne dp, rel
+ uint8_t val = spc_read(spc, spc_adrDp(spc)) ^ 0xff;
+ uint8_t result = spc->a + val + 1;
+ spc_doBranch(spc, spc_readOpcode(spc), result != 0);
+ break;
+ }
+ case 0x2f: { // bra rel
+ spc->pc += (int8_t) spc_readOpcode(spc);
+ break;
+ }
+ case 0x30: { // bmi rel
+ spc_doBranch(spc, spc_readOpcode(spc), spc->n);
+ break;
+ }
+ case 0x34: { // and dpx
+ spc_and(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0x35: { // and abx
+ spc_and(spc, spc_adrAbx(spc));
+ break;
+ }
+ case 0x36: { // and aby
+ spc_and(spc, spc_adrAby(spc));
+ break;
+ }
+ case 0x37: { // and idy
+ spc_and(spc, spc_adrIdy(spc));
+ break;
+ }
+ case 0x38: { // andm dp, imm
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpImm(spc, &src);
+ spc_andm(spc, dst, src);
+ break;
+ }
+ case 0x39: { // andm ind, ind
+ uint16_t src = 0;
+ uint16_t dst = spc_adrIndInd(spc, &src);
+ spc_andm(spc, dst, src);
+ break;
+ }
+ case 0x3a: { // incw dp
+ uint16_t low = 0;
+ uint16_t high = spc_adrDpWord(spc, &low);
+ uint16_t value = spc_readWord(spc, low, high) + 1;
+ spc->z = value == 0;
+ spc->n = value & 0x8000;
+ spc_writeWord(spc, low, high, value);
+ break;
+ }
+ case 0x3b: { // rol dpx
+ spc_rol(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0x3c: { // rola imp
+ bool newC = spc->a & 0x80;
+ spc->a = (spc->a << 1) | (uint8_t)spc->c;
+ spc->c = newC;
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0x3d: { // incx imp
+ spc->x++;
+ spc_setZN(spc, spc->x);
+ break;
+ }
+ case 0x3e: { // cmpx dp
+ spc_cmpx(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0x3f: { // call abs
+ uint16_t dst = spc_readOpcodeWord(spc);
+ spc_pushWord(spc, spc->pc);
+ spc->pc = dst;
+ break;
+ }
+ case 0x40: { // setp imp
+ spc->p = true;
+ break;
+ }
+ case 0x44: { // eor dp
+ spc_eor(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0x45: { // eor abs
+ spc_eor(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0x46: { // eor ind
+ spc_eor(spc, spc_adrInd(spc));
+ break;
+ }
+ case 0x47: { // eor idx
+ spc_eor(spc, spc_adrIdx(spc));
+ break;
+ }
+ case 0x48: { // eor imm
+ spc_eor(spc, spc_adrImm(spc));
+ break;
+ }
+ case 0x49: { // eorm dp, dp
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpDp(spc, &src);
+ spc_eorm(spc, dst, src);
+ break;
+ }
+ case 0x4a: { // and1 abs.bit
+ uint16_t adr = 0;
+ uint8_t bit = spc_adrAbsBit(spc, &adr);
+ spc->c = spc->c & ((spc_read(spc, adr) >> bit) & 1);
+ break;
+ }
+ case 0x4b: { // lsr dp
+ spc_lsr(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0x4c: { // lsr abs
+ spc_lsr(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0x4d: { // pushx imp
+ spc_pushByte(spc, spc->x);
+ break;
+ }
+ case 0x4e: { // tclr1 abs
+ uint16_t adr = spc_adrAbs(spc);
+ uint8_t val = spc_read(spc, adr);
+ uint8_t result = spc->a + (val ^ 0xff) + 1;
+ spc_setZN(spc, result);
+ spc_write(spc, adr, val & ~spc->a);
+ break;
+ }
+ case 0x4f: { // pcall dp
+ uint8_t dst = spc_readOpcode(spc);
+ spc_pushWord(spc, spc->pc);
+ spc->pc = 0xff00 | dst;
+ break;
+ }
+ case 0x50: { // bvc rel
+ spc_doBranch(spc, spc_readOpcode(spc), !spc->v);
+ break;
+ }
+ case 0x54: { // eor dpx
+ spc_eor(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0x55: { // eor abx
+ spc_eor(spc, spc_adrAbx(spc));
+ break;
+ }
+ case 0x56: { // eor aby
+ spc_eor(spc, spc_adrAby(spc));
+ break;
+ }
+ case 0x57: { // eor idy
+ spc_eor(spc, spc_adrIdy(spc));
+ break;
+ }
+ case 0x58: { // eorm dp, imm
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpImm(spc, &src);
+ spc_eorm(spc, dst, src);
+ break;
+ }
+ case 0x59: { // eorm ind, ind
+ uint16_t src = 0;
+ uint16_t dst = spc_adrIndInd(spc, &src);
+ spc_eorm(spc, dst, src);
+ break;
+ }
+ case 0x5a: { // cmpw dp
+ uint16_t low = 0;
+ uint16_t high = spc_adrDpWord(spc, &low);
+ uint16_t value = spc_readWord(spc, low, high) ^ 0xffff;
+ uint16_t ya = spc->a | (spc->y << 8);
+ int result = ya + value + 1;
+ spc->c = result > 0xffff;
+ spc->z = (result & 0xffff) == 0;
+ spc->n = result & 0x8000;
+ break;
+ }
+ case 0x5b: { // lsr dpx
+ spc_lsr(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0x5c: { // lsra imp
+ spc->c = spc->a & 1;
+ spc->a >>= 1;
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0x5d: { // movxa imp
+ spc->x = spc->a;
+ spc_setZN(spc, spc->x);
+ break;
+ }
+ case 0x5e: { // cmpy abs
+ spc_cmpy(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0x5f: { // jmp abs
+ spc->pc = spc_readOpcodeWord(spc);
+ break;
+ }
+ case 0x60: { // clrc imp
+ spc->c = false;
+ break;
+ }
+ case 0x64: { // cmp dp
+ spc_cmp(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0x65: { // cmp abs
+ spc_cmp(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0x66: { // cmp ind
+ spc_cmp(spc, spc_adrInd(spc));
+ break;
+ }
+ case 0x67: { // cmp idx
+ spc_cmp(spc, spc_adrIdx(spc));
+ break;
+ }
+ case 0x68: { // cmp imm
+ spc_cmp(spc, spc_adrImm(spc));
+ break;
+ }
+ case 0x69: { // cmpm dp, dp
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpDp(spc, &src);
+ spc_cmpm(spc, dst, src);
+ break;
+ }
+ case 0x6a: { // and1n abs.bit
+ uint16_t adr = 0;
+ uint8_t bit = spc_adrAbsBit(spc, &adr);
+ spc->c = spc->c & (~(spc_read(spc, adr) >> bit) & 1);
+ break;
+ }
+ case 0x6b: { // ror dp
+ spc_ror(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0x6c: { // ror abs
+ spc_ror(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0x6d: { // pushy imp
+ spc_pushByte(spc, spc->y);
+ break;
+ }
+ case 0x6e: { // dbnz dp, rel
+ uint16_t adr = spc_adrDp(spc);
+ uint8_t result = spc_read(spc, adr) - 1;
+ spc_write(spc, adr, result);
+ spc_doBranch(spc, spc_readOpcode(spc), result != 0);
+ break;
+ }
+ case 0x6f: { // ret imp
+ spc->pc = spc_pullWord(spc);
+ break;
+ }
+ case 0x70: { // bvs rel
+ spc_doBranch(spc, spc_readOpcode(spc), spc->v);
+ break;
+ }
+ case 0x74: { // cmp dpx
+ spc_cmp(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0x75: { // cmp abx
+ spc_cmp(spc, spc_adrAbx(spc));
+ break;
+ }
+ case 0x76: { // cmp aby
+ spc_cmp(spc, spc_adrAby(spc));
+ break;
+ }
+ case 0x77: { // cmp idy
+ spc_cmp(spc, spc_adrIdy(spc));
+ break;
+ }
+ case 0x78: { // cmpm dp, imm
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpImm(spc, &src);
+ spc_cmpm(spc, dst, src);
+ break;
+ }
+ case 0x79: { // cmpm ind, ind
+ uint16_t src = 0;
+ uint16_t dst = spc_adrIndInd(spc, &src);
+ spc_cmpm(spc, dst, src);
+ break;
+ }
+ case 0x7a: { // addw dp
+ uint16_t low = 0;
+ uint16_t high = spc_adrDpWord(spc, &low);
+ uint16_t value = spc_readWord(spc, low, high);
+ uint16_t ya = spc->a | (spc->y << 8);
+ int result = ya + value;
+ spc->v = (ya & 0x8000) == (value & 0x8000) && (value & 0x8000) != (result & 0x8000);
+ spc->h = ((ya & 0xfff) + (value & 0xfff) + 1) > 0xfff;
+ spc->c = result > 0xffff;
+ spc->z = (result & 0xffff) == 0;
+ spc->n = result & 0x8000;
+ spc->a = result & 0xff;
+ spc->y = result >> 8;
+ break;
+ }
+ case 0x7b: { // ror dpx
+ spc_ror(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0x7c: { // rora imp
+ bool newC = spc->a & 1;
+ spc->a = (spc->a >> 1) | (spc->c << 7);
+ spc->c = newC;
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0x7d: { // movax imp
+ spc->a = spc->x;
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0x7e: { // cmpy dp
+ spc_cmpy(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0x7f: { // reti imp
+ spc_setFlags(spc, spc_pullByte(spc));
+ spc->pc = spc_pullWord(spc);
+ break;
+ }
+ case 0x80: { // setc imp
+ spc->c = true;
+ break;
+ }
+ case 0x84: { // adc dp
+ spc_adc(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0x85: { // adc abs
+ spc_adc(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0x86: { // adc ind
+ spc_adc(spc, spc_adrInd(spc));
+ break;
+ }
+ case 0x87: { // adc idx
+ spc_adc(spc, spc_adrIdx(spc));
+ break;
+ }
+ case 0x88: { // adc imm
+ spc_adc(spc, spc_adrImm(spc));
+ break;
+ }
+ case 0x89: { // adcm dp, dp
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpDp(spc, &src);
+ spc_adcm(spc, dst, src);
+ break;
+ }
+ case 0x8a: { // eor1 abs.bit
+ uint16_t adr = 0;
+ uint8_t bit = spc_adrAbsBit(spc, &adr);
+ spc->c = spc->c ^ ((spc_read(spc, adr) >> bit) & 1);
+ break;
+ }
+ case 0x8b: { // dec dp
+ spc_dec(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0x8c: { // dec abs
+ spc_dec(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0x8d: { // movy imm
+ spc_movy(spc, spc_adrImm(spc));
+ break;
+ }
+ case 0x8e: { // popp imp
+ spc_setFlags(spc, spc_pullByte(spc));
+ break;
+ }
+ case 0x8f: { // movm dp, imm
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpImm(spc, &src);
+ uint8_t val = spc_read(spc, src);
+ spc_read(spc, dst);
+ spc_write(spc, dst, val);
+ break;
+ }
+ case 0x90: { // bcc rel
+ spc_doBranch(spc, spc_readOpcode(spc), !spc->c);
+ break;
+ }
+ case 0x94: { // adc dpx
+ spc_adc(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0x95: { // adc abx
+ spc_adc(spc, spc_adrAbx(spc));
+ break;
+ }
+ case 0x96: { // adc aby
+ spc_adc(spc, spc_adrAby(spc));
+ break;
+ }
+ case 0x97: { // adc idy
+ spc_adc(spc, spc_adrIdy(spc));
+ break;
+ }
+ case 0x98: { // adcm dp, imm
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpImm(spc, &src);
+ spc_adcm(spc, dst, src);
+ break;
+ }
+ case 0x99: { // adcm ind, ind
+ uint16_t src = 0;
+ uint16_t dst = spc_adrIndInd(spc, &src);
+ spc_adcm(spc, dst, src);
+ break;
+ }
+ case 0x9a: { // subw dp
+ uint16_t low = 0;
+ uint16_t high = spc_adrDpWord(spc, &low);
+ uint16_t value = spc_readWord(spc, low, high) ^ 0xffff;
+ uint16_t ya = spc->a | (spc->y << 8);
+ int result = ya + value + 1;
+ spc->v = (ya & 0x8000) == (value & 0x8000) && (value & 0x8000) != (result & 0x8000);
+ spc->h = ((ya & 0xfff) + (value & 0xfff) + 1) > 0xfff;
+ spc->c = result > 0xffff;
+ spc->z = (result & 0xffff) == 0;
+ spc->n = result & 0x8000;
+ spc->a = result & 0xff;
+ spc->y = result >> 8;
+ break;
+ }
+ case 0x9b: { // dec dpx
+ spc_dec(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0x9c: { // deca imp
+ spc->a--;
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0x9d: { // movxp imp
+ spc->x = spc->sp;
+ spc_setZN(spc, spc->x);
+ break;
+ }
+ case 0x9e: { // div imp
+ // TODO: proper division algorithm
+ uint16_t value = spc->a | (spc->y << 8);
+ int result = 0xffff;
+ int mod = spc->a;
+ if(spc->x != 0) {
+ result = value / spc->x;
+ mod = value % spc->x;
+ }
+ spc->v = result > 0xff;
+ spc->h = (spc->x & 0xf) <= (spc->y & 0xf);
+ spc->a = result;
+ spc->y = mod;
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0x9f: { // xcn imp
+ spc->a = (spc->a >> 4) | (spc->a << 4);
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0xa0: { // ei imp
+ spc->i = true;
+ break;
+ }
+ case 0xa4: { // sbc dp
+ spc_sbc(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0xa5: { // sbc abs
+ spc_sbc(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0xa6: { // sbc ind
+ spc_sbc(spc, spc_adrInd(spc));
+ break;
+ }
+ case 0xa7: { // sbc idx
+ spc_sbc(spc, spc_adrIdx(spc));
+ break;
+ }
+ case 0xa8: { // sbc imm
+ spc_sbc(spc, spc_adrImm(spc));
+ break;
+ }
+ case 0xa9: { // sbcm dp, dp
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpDp(spc, &src);
+ spc_sbcm(spc, dst, src);
+ break;
+ }
+ case 0xaa: { // mov1 abs.bit
+ uint16_t adr = 0;
+ uint8_t bit = spc_adrAbsBit(spc, &adr);
+ spc->c = (spc_read(spc, adr) >> bit) & 1;
+ break;
+ }
+ case 0xab: { // inc dp
+ spc_inc(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0xac: { // inc abs
+ spc_inc(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0xad: { // cmpy imm
+ spc_cmpy(spc, spc_adrImm(spc));
+ break;
+ }
+ case 0xae: { // popa imp
+ spc->a = spc_pullByte(spc);
+ break;
+ }
+ case 0xaf: { // movs ind+
+ uint16_t adr = spc_adrIndP(spc);
+ spc_write(spc, adr, spc->a);
+ break;
+ }
+ case 0xb0: { // bcs rel
+ spc_doBranch(spc, spc_readOpcode(spc), spc->c);
+ break;
+ }
+ case 0xb4: { // sbc dpx
+ spc_sbc(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0xb5: { // sbc abx
+ spc_sbc(spc, spc_adrAbx(spc));
+ break;
+ }
+ case 0xb6: { // sbc aby
+ spc_sbc(spc, spc_adrAby(spc));
+ break;
+ }
+ case 0xb7: { // sbc idy
+ spc_sbc(spc, spc_adrIdy(spc));
+ break;
+ }
+ case 0xb8: { // sbcm dp, imm
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpImm(spc, &src);
+ spc_sbcm(spc, dst, src);
+ break;
+ }
+ case 0xb9: { // sbcm ind, ind
+ uint16_t src = 0;
+ uint16_t dst = spc_adrIndInd(spc, &src);
+ spc_sbcm(spc, dst, src);
+ break;
+ }
+ case 0xba: { // movw dp
+ uint16_t low = 0;
+ uint16_t high = spc_adrDpWord(spc, &low);
+ uint16_t val = spc_readWord(spc, low, high);
+ spc->a = val & 0xff;
+ spc->y = val >> 8;
+ spc->z = val == 0;
+ spc->n = val & 0x8000;
+ break;
+ }
+ case 0xbb: { // inc dpx
+ spc_inc(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0xbc: { // inca imp
+ spc->a++;
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0xbd: { // movpx imp
+ spc->sp = spc->x;
+ break;
+ }
+ case 0xbe: { // das imp
+ if(spc->a > 0x99 || !spc->c) {
+ spc->a -= 0x60;
+ spc->c = false;
+ }
+ if((spc->a & 0xf) > 9 || !spc->h) {
+ spc->a -= 6;
+ }
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0xbf: { // mov ind+
+ uint16_t adr = spc_adrIndP(spc);
+ spc->a = spc_read(spc, adr);
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0xc0: { // di imp
+ spc->i = false;
+ break;
+ }
+ case 0xc4: { // movs dp
+ spc_movs(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0xc5: { // movs abs
+ spc_movs(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0xc6: { // movs ind
+ spc_movs(spc, spc_adrInd(spc));
+ break;
+ }
+ case 0xc7: { // movs idx
+ spc_movs(spc, spc_adrIdx(spc));
+ break;
+ }
+ case 0xc8: { // cmpx imm
+ spc_cmpx(spc, spc_adrImm(spc));
+ break;
+ }
+ case 0xc9: { // movsx abs
+ spc_movsx(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0xca: { // mov1s abs.bit
+ uint16_t adr = 0;
+ uint8_t bit = spc_adrAbsBit(spc, &adr);
+ uint8_t result = (spc_read(spc, adr) & (~(1 << bit))) | (spc->c << bit);
+ spc_write(spc, adr, result);
+ break;
+ }
+ case 0xcb: { // movsy dp
+ spc_movsy(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0xcc: { // movsy abs
+ spc_movsy(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0xcd: { // movx imm
+ spc_movx(spc, spc_adrImm(spc));
+ break;
+ }
+ case 0xce: { // popx imp
+ spc->x = spc_pullByte(spc);
+ break;
+ }
+ case 0xcf: { // mul imp
+ uint16_t result = spc->a * spc->y;
+ spc->a = result & 0xff;
+ spc->y = result >> 8;
+ spc_setZN(spc, spc->y);
+ break;
+ }
+ case 0xd0: { // bne rel
+ spc_doBranch(spc, spc_readOpcode(spc), !spc->z);
+ break;
+ }
+ case 0xd4: { // movs dpx
+ spc_movs(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0xd5: { // movs abx
+ spc_movs(spc, spc_adrAbx(spc));
+ break;
+ }
+ case 0xd6: { // movs aby
+ spc_movs(spc, spc_adrAby(spc));
+ break;
+ }
+ case 0xd7: { // movs idy
+ spc_movs(spc, spc_adrIdy(spc));
+ break;
+ }
+ case 0xd8: { // movsx dp
+ spc_movsx(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0xd9: { // movsx dpy
+ spc_movsx(spc, spc_adrDpy(spc));
+ break;
+ }
+ case 0xda: { // movws dp
+ uint16_t low = 0;
+ uint16_t high = spc_adrDpWord(spc, &low);
+ spc_read(spc, low);
+ spc_write(spc, low, spc->a);
+ spc_write(spc, high, spc->y);
+ break;
+ }
+ case 0xdb: { // movsy dpx
+ spc_movsy(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0xdc: { // decy imp
+ spc->y--;
+ spc_setZN(spc, spc->y);
+ break;
+ }
+ case 0xdd: { // movay imp
+ spc->a = spc->y;
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0xde: { // cbne dpx, rel
+ uint8_t val = spc_read(spc, spc_adrDpx(spc)) ^ 0xff;
+ uint8_t result = spc->a + val + 1;
+ spc_doBranch(spc, spc_readOpcode(spc), result != 0);
+ break;
+ }
+ case 0xdf: { // daa imp
+ if(spc->a > 0x99 || spc->c) {
+ spc->a += 0x60;
+ spc->c = true;
+ }
+ if((spc->a & 0xf) > 9 || spc->h) {
+ spc->a += 6;
+ }
+ spc_setZN(spc, spc->a);
+ break;
+ }
+ case 0xe0: { // clrv imp
+ spc->v = false;
+ spc->h = false;
+ break;
+ }
+ case 0xe4: { // mov dp
+ spc_mov(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0xe5: { // mov abs
+ spc_mov(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0xe6: { // mov ind
+ spc_mov(spc, spc_adrInd(spc));
+ break;
+ }
+ case 0xe7: { // mov idx
+ spc_mov(spc, spc_adrIdx(spc));
+ break;
+ }
+ case 0xe8: { // mov imm
+ spc_mov(spc, spc_adrImm(spc));
+ break;
+ }
+ case 0xe9: { // movx abs
+ spc_movx(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0xea: { // not1 abs.bit
+ uint16_t adr = 0;
+ uint8_t bit = spc_adrAbsBit(spc, &adr);
+ uint8_t result = spc_read(spc, adr) ^ (1 << bit);
+ spc_write(spc, adr, result);
+ break;
+ }
+ case 0xeb: { // movy dp
+ spc_movy(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0xec: { // movy abs
+ spc_movy(spc, spc_adrAbs(spc));
+ break;
+ }
+ case 0xed: { // notc imp
+ spc->c = !spc->c;
+ break;
+ }
+ case 0xee: { // popy imp
+ spc->y = spc_pullByte(spc);
+ break;
+ }
+ case 0xef: { // sleep imp
+ spc->stopped = true; // no interrupts, so sleeping stops as well
+ break;
+ }
+ case 0xf0: { // beq rel
+ spc_doBranch(spc, spc_readOpcode(spc), spc->z);
+ break;
+ }
+ case 0xf4: { // mov dpx
+ spc_mov(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0xf5: { // mov abx
+ spc_mov(spc, spc_adrAbx(spc));
+ break;
+ }
+ case 0xf6: { // mov aby
+ spc_mov(spc, spc_adrAby(spc));
+ break;
+ }
+ case 0xf7: { // mov idy
+ spc_mov(spc, spc_adrIdy(spc));
+ break;
+ }
+ case 0xf8: { // movx dp
+ spc_movx(spc, spc_adrDp(spc));
+ break;
+ }
+ case 0xf9: { // movx dpy
+ spc_movx(spc, spc_adrDpy(spc));
+ break;
+ }
+ case 0xfa: { // movm dp, dp
+ uint16_t src = 0;
+ uint16_t dst = spc_adrDpDp(spc, &src);
+ uint8_t val = spc_read(spc, src);
+ spc_write(spc, dst, val);
+ break;
+ }
+ case 0xfb: { // movy dpx
+ spc_movy(spc, spc_adrDpx(spc));
+ break;
+ }
+ case 0xfc: { // incy imp
+ spc->y++;
+ spc_setZN(spc, spc->y);
+ break;
+ }
+ case 0xfd: { // movya imp
+ spc->y = spc->a;
+ spc_setZN(spc, spc->y);
+ break;
+ }
+ case 0xfe: { // dbnzy rel
+ spc->y--;
+ spc_doBranch(spc, spc_readOpcode(spc), spc->y != 0);
+ break;
+ }
+ case 0xff: { // stop imp
+ spc->stopped = true;
+ break;
+ }
+ }
+}
--- /dev/null
+++ b/snes/spc.h
@@ -1,0 +1,45 @@
+
+#ifndef SPC_H
+#define SPC_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct Spc Spc;
+
+#include "apu.h"
+#include "saveload.h"
+
+struct Spc {
+ Apu* apu;
+ // registers
+ uint8_t a;
+ uint8_t x;
+ uint8_t y;
+ uint8_t sp;
+ uint16_t pc;
+ // flags
+ bool c;
+ bool z;
+ bool v;
+ bool n;
+ bool i;
+ bool h;
+ bool p;
+ bool b;
+ // stopping
+ bool stopped;
+ // internal use
+ uint8_t cyclesUsed; // indicates how many cycles an opcode used
+};
+
+Spc* spc_init(Apu* apu);
+void spc_free(Spc* spc);
+void spc_reset(Spc* spc);
+int spc_runOpcode(Spc* spc);
+void spc_saveload(Spc *spc, SaveLoadFunc *func, void *ctx);
+
+#endif
--- /dev/null
+++ b/snes_regs.h
@@ -1,0 +1,211 @@
+#pragma once
+
+#define INIDISP 0x2100
+#define OBSEL 0x2101
+#define OAMADDL 0x2102
+#define OAMADDH 0x2103
+#define OAMDATA 0x2104
+#define BGMODE 0x2105
+#define MOSAIC 0x2106
+#define BG1SC 0x2107
+#define BG2SC 0x2108
+#define BG3SC 0x2109
+#define BG4SC 0x210a
+#define BG12NBA 0x210b
+#define BG34NBA 0x210c
+#define BG1HOFS 0x210d
+#define BG1VOFS 0x210e
+#define BG2HOFS 0x210f
+#define BG2VOFS 0x2110
+#define BG3HOFS 0x2111
+#define BG3VOFS 0x2112
+#define BG4HOFS 0x2113
+#define BG4VOFS 0x2114
+#define VMAIN 0x2115
+#define VMADDL 0x2116
+#define VMADDH 0x2117
+#define VMDATAL 0x2118
+#define VMDATAH 0x2119
+#define M7SEL 0x211a
+#define M7A 0x211b
+#define M7B 0x211c
+#define M7C 0x211d
+#define M7D 0x211e
+#define M7X 0x211f
+#define M7Y 0x2120
+#define CGADD 0x2121
+#define CGDATA 0x2122
+#define W12SEL 0x2123
+#define W34SEL 0x2124
+#define WOBJSEL 0x2125
+#define WH0 0x2126
+#define WH1 0x2127
+#define WH2 0x2128
+#define WH3 0x2129
+#define WBGLOG 0x212a
+#define WOBJLOG 0x212b
+#define TM 0x212c
+#define TS 0x212d
+#define TMW 0x212e
+#define TSW 0x212f
+#define CGWSEL 0x2130
+#define CGADSUB 0x2131
+#define COLDATA 0x2132
+#define SETINI 0x2133
+#define MPYL 0x2134
+#define MPYM 0x2135
+#define MPYH 0x2136
+#define SLHV 0x2137
+#define RDOAM 0x2138
+#define RDVRAML 0x2139
+#define RDVRAMH 0x213a
+#define RDCGRAM 0x213b
+#define OPHCT 0x213c
+#define OPVCT 0x213d
+#define STAT77 0x213e
+#define STAT78 0x213f
+#define APUI00 0x2140
+#define APUI01 0x2141
+#define APUI02 0x2142
+#define APUI03 0x2143
+#define WMDATA 0x2180
+#define WMADDL 0x2181
+#define WMADDM 0x2182
+#define WMADDH 0x2183
+#define JOYA 0x4016
+#define JOYB 0x4017
+#define NMITIMEN 0x4200
+#define WRIO 0x4201
+#define WRMPYA 0x4202
+#define WRMPYB 0x4203
+#define WRDIVL 0x4204
+#define WRDIVH 0x4205
+#define WRDIVB 0x4206
+#define HTIMEL 0x4207
+#define HTIMEH 0x4208
+#define VTIMEL 0x4209
+#define VTIMEH 0x420a
+#define MDMAEN 0x420b
+#define HDMAEN 0x420c
+#define MEMSEL 0x420d
+#define RDNMI 0x4210
+#define TIMEUP 0x4211
+#define HVBJOY 0x4212
+#define RDIO 0x4213
+#define RDDIVL 0x4214
+#define RDDIVH 0x4215
+#define RDMPYL 0x4216
+#define RDMPYH 0x4217
+#define JOY1L 0x4218
+#define JOY1H 0x4219
+#define JOY2L 0x421a
+#define JOY2H 0x421b
+#define JOY3L 0x421c
+#define JOY3H 0x421d
+#define JOY4L 0x421e
+#define JOY4H 0x421f
+
+#define DMAP0 0x4300
+#define BBAD0 0x4301
+#define A1T0L 0x4302
+#define A1T0H 0x4303
+#define A1B0 0x4304
+#define DAS0L 0x4305
+#define DAS0H 0x4306
+#define DAS00 0x4307
+#define A2A0L 0x4308
+#define A2A0H 0x4309
+#define NTRL0 0x430a
+#define UNUSED0 0x430b
+#define MIRR0 0x430f
+#define DMAP1 0x4310
+#define BBAD1 0x4311
+#define A1T1L 0x4312
+#define A1T1H 0x4313
+#define A1B1 0x4314
+#define DAS1L 0x4315
+#define DAS1H 0x4316
+#define DAS10 0x4317
+#define A2A1L 0x4318
+#define A2A1H 0x4319
+#define NTRL1 0x431a
+#define UNUSED1 0x431b
+#define MIRR1 0x431f
+#define DMAP2 0x4320
+#define BBAD2 0x4321
+#define A1T2L 0x4322
+#define A1T2H 0x4323
+#define A1B2 0x4324
+#define DAS2L 0x4325
+#define DAS2H 0x4326
+#define DAS20 0x4327
+#define A2A2L 0x4328
+#define A2A2H 0x4329
+#define NTRL2 0x432a
+#define UNUSED2 0x432b
+#define MIRR2 0x432f
+#define DMAP3 0x4330
+#define BBAD3 0x4331
+#define A1T3L 0x4332
+#define A1T3H 0x4333
+#define A1B3 0x4334
+#define DAS3L 0x4335
+#define DAS3H 0x4336
+#define DAS30 0x4337
+#define A2A3L 0x4338
+#define A2A3H 0x4339
+#define NTRL3 0x433a
+#define UNUSED3 0x433b
+#define MIRR3 0x433f
+#define DMAP4 0x4340
+#define BBAD4 0x4341
+#define A1T4L 0x4342
+#define A1T4H 0x4343
+#define A1B4 0x4344
+#define DAS4L 0x4345
+#define DAS4H 0x4346
+#define DAS40 0x4347
+#define A2A4L 0x4348
+#define A2A4H 0x4349
+#define NTRL4 0x434a
+#define UNUSED4 0x434b
+#define MIRR4 0x434f
+#define DMAP5 0x4350
+#define BBAD5 0x4351
+#define A1T5L 0x4352
+#define A1T5H 0x4353
+#define A1B5 0x4354
+#define DAS5L 0x4355
+#define DAS5H 0x4356
+#define DAS50 0x4357
+#define A2A5L 0x4358
+#define A2A5H 0x4359
+#define NTRL5 0x435a
+#define UNUSED5 0x435b
+#define MIRR5 0x435f
+#define DMAP6 0x4360
+#define BBAD6 0x4361
+#define A1T6L 0x4362
+#define A1T6H 0x4363
+#define A1B6 0x4364
+#define DAS6L 0x4365
+#define DAS6H 0x4366
+#define DAS60 0x4367
+#define A2A6L 0x4368
+#define A2A6H 0x4369
+#define NTRL6 0x436a
+#define UNUSED6 0x436b
+#define MIRR6 0x436f
+#define DMAP7 0x4370
+#define BBAD7 0x4371
+#define A1T7L 0x4372
+#define A1T7H 0x4373
+#define A1B7 0x4374
+#define DAS7L 0x4375
+#define DAS7H 0x4376
+#define DAS70 0x4377
+#define A2A7L 0x4378
+#define A2A7H 0x4379
+#define NTRL7 0x437a
+#define UNUSED7 0x437b
+#define MIRR7 0x437f
--- /dev/null
+++ b/spc_player.cpp
@@ -1,0 +1,1310 @@
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <SDL.h>
+#include <assert.h>
+#include <algorithm>
+#include "types.h"
+
+#include "snes/spc.h"
+#include "tracing.h"
+
+#include "spc_player.h"
+#include "dsp_regs.h"
+
+static void PlayNote(SpcPlayer *p, Channel *c, uint8 note);
+
+static void Dsp_Write(SpcPlayer *p, uint8_t reg, uint8 value) {
+ if (DspRegWriteHistory *hist = p->reg_write_history) {
+ if (hist->count < 256) {
+ hist->addr[hist->count] = (DspReg)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, (DspReg)(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, (DspReg)(reg + V0PITCHL), t & 0xff);
+ Dsp_Write(p, (DspReg)(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, (DspReg)(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) {
+ static const uint8 kRegAddrs0[10] = {EVOLL, EVOLR, EFB, EON, FLG, KON, KOF, NON, PMON, KOF};
+
+ 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 MemMap2 *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 MemMap2 *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;
+}
+
+// =======================================
+
+DspRegWriteHistory my_write_hist;
+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);
+ SDL_QueueAudio(device, audioBuffer, 736 * 4);
+ 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);
+ SDL_QueueAudio(device, audioBuffer, 736 * 4);
+ while (SDL_GetQueuedAudioSize(device) >= 736 * 4 * 3/* 44100 * 4 * 300*/) {
+ SDL_Delay(1);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+++ b/spc_player.h
@@ -1,0 +1,277 @@
+#include <stddef.h>
+struct DspRegWriteHistory;
+struct Dsp;
+
+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;
+};
+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
+};
+struct MemMap {
+uint16 off, org_off;
+};
+struct MemMap2 {
+uint16 off, org_off, size;
+};
+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},
+};
+const MemMap2 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},
+};
+
+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/sprite.cpp
@@ -1,0 +1,4403 @@
+#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 "tables/generated_dungeon_sprites.h"
+#include "sprite_main.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_Tab0[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_Tab1[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_Tab2[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_Tab3[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();
+ oam->x = pt.x;
+ oam->y = pt.y;
+ oam->charnum = kGarnishSparkle_Char[t];
+ int j = garnish_sprite[k];
+ oam->flags = (sprite_oam_flags[j] | sprite_obj_prio[j]) & 0xf0 | 4;
+ bytewise_extended_oam[oam - oam_buf] = 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();
+ oam->x = pt.x;
+ oam->y = pt.y;
+ oam->charnum = kRunningManDust_Char[tmp_counter];
+ oam->flags = 0x24;
+ bytewise_extended_oam[oam - oam_buf] = 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);
+ }
+}
+
+void Ancilla_SpawnFallingPrize(uint8 item) { // 85a51d
+ 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 x = src->x + info->x;
+ uint16 y = src->y + info->y;
+ oam->x = x;
+ oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0;
+ uint16 d = src->char_flags ^ WORD(info->r4);
+ if (word_7E0CFE >= 1)
+ d = d & ~0xE00 | 0x400;
+ WORD(oam->charnum) = d;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1) | 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 {
+ uint16 x = xin + kSpriteDistress_X[i];
+ uint16 y = yin + kSpriteDistress_Y[i];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = 0x83;
+ oam->flags = 0x22;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1);
+ } 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];
+ 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)
+ 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;
+ uint16 x = info.x + kNumberedAbsorbable_X[j];
+ uint16 y = info.y + kNumberedAbsorbable_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kNumberedAbsorbable_Char[j];
+ oam->flags = info.flags;
+ bytewise_extended_oam[oam - oam_buf] = kNumberedAbsorbable_Ext[j] | (x >> 8 & 1);
+ } 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);
+ oam->x = info->x;
+ if (sprite_flags3[k] & 0x20) {
+ oam->y = y + 1;
+ oam->charnum = 0x38;
+ oam->flags = (info->flags & 0x30) | 8;
+ bytewise_extended_oam[oam - oam_buf] = (info->x >> 8 & 1);
+ } else {
+ oam->y = y;
+ oam->charnum = 0x6c;
+ oam->flags = (info->flags & 0x30) | 8;
+ bytewise_extended_oam[oam - oam_buf] = (info->x >> 8 & 1) | 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();
+ oam[1].x = oam[0].x = info.x;
+ bytewise_extended_oam[oam - oam_buf + 1] = bytewise_extended_oam[oam - oam_buf] = (info.x >= 256);
+ oam[0].y = ClampYForOam(info.y);
+ oam[1].y = ClampYForOam(info.y + 8);
+ uint8 a = kSprite_PrepAndDrawSingleLarge_Tab2[kSprite_PrepAndDrawSingleLarge_Tab1[sprite_type[k]] + sprite_graphics[k]];
+ oam[0].charnum = a;
+ oam[1].charnum = a + 0x10;
+ oam[0].flags = oam[1].flags = info.flags;
+ 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++) {
+ oam->x = kSpritePoof_X[j] + BYTE(dungmap_var7);
+ oam->y = kSpritePoof_Y[j] + HIBYTE(dungmap_var7);
+ oam->charnum = kSpritePoof_Char[j];
+ oam->flags = kSpritePoof_Flags[j];
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ if ((uint16)(x + 0x40) >= 0x170 || (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])) {
+ 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]];
+ AgahnimBalls_DamageAgahnim(k, dmg, a);
+}
+
+void AgahnimBalls_DamageAgahnim(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);
+ }
+flag4:
+ uint8 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);
+ 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);
+ 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_Tab0[t] + player_oam_x_offset);
+ int y = link_y_coord + (int8)(kPlayer_SetupActionHitBox_Tab2[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_Tab1[t];
+ hb->r3 = kPlayer_SetupActionHitBox_Tab3[t];
+ }
+}
+
+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, u;
+ 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;
+ oam->x = info.x + kSpriteDrawFall1_X[i];
+ oam->y = info.y + kSpriteDrawFall1_Y[i];
+ oam->charnum = kSpriteDrawFall1_Char[i];
+ oam->flags = info.flags ^ kSpriteDrawFall1_Flags[i];
+ bytewise_extended_oam[oam - oam_buf] = 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--) {
+ int j = i + g;
+ oam->x = pt.x + kArrghusSplash_X[j];
+ oam->y = pt.y + kArrghusSplash_Y[j];
+ oam->charnum = kArrghusSplash_Char[j];
+ oam->flags = kArrghusSplash_Flags[j];
+ bytewise_extended_oam[oam - oam_buf] = kArrghusSplash_Ext[j];
+ oam++;
+ }
+}
+
+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();
+ oam[0].x = pt.x;
+ oam[0].y = pt.y;
+ oam[1].x = pt.x + 8;
+ oam[1].y = pt.y;
+ oam[0].charnum = 0xa4;
+ oam[1].charnum = 0xa5;
+ oam[0].flags = 0x22;
+ oam[1].flags = 0x22;
+ bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf + 1] = 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;
+ OamEnt *oam = GetOamCurPtr();
+ oam->x = pt.x;
+ oam->y = pt.y;
+ int j = kGanonBatFlame_Idx[garnish_countdown[k] >> 3];
+ oam->charnum = kGanonBatFlame_Char[j];
+ oam->flags = kGanonBatFlame_Flags[j] | 0x22;
+ bytewise_extended_oam[oam - oam_buf] = 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;
+
+ OamEnt *oam = GetOamCurPtr();
+ oam->x = pt.x;
+ oam->y = pt.y;
+ oam->charnum = kTrinexxIce_Char[garnish_countdown[k] >> 4];
+ oam->flags = kTrinexxIce_Flags[(garnish_countdown[k] >> 2) & 3] | 0x35;
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ OamEnt *oam = GetOamCurPtr();
+ oam->x = pt.x;
+ oam->y = pt.y;
+ oam->charnum = kGarnish_CannonPoof_Char[garnish_countdown[k] >> 3];
+ int j = garnish_sprite[k];
+ oam->flags = kGarnish_CannonPoof_Flags[j] | 4;
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ OamEnt *oam = GetOamCurPtr();
+ oam->x = pt.x;
+ oam->y = pt.y;
+ int j = garnish_sprite[k];
+ oam->charnum = kLightningTrail_Char[j] - (BYTE(dungeon_room_index2) == 0x20 ? 0x80 : 0);
+ oam->flags = (frame_counter << 1) & 0xe | kLightningTrail_Flags[j];
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ OamEnt *oam = GetOamCurPtr();
+ oam->x = pt.x;
+ oam->y = pt.y;
+ int j = garnish_countdown[k] >> 3;
+ oam->charnum = kBabusuFlash_Char[j];
+ oam->flags = kBabusuFlash_Flags[j];
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ OamEnt *oam = GetOamCurPtr();
+ int i = garnish_countdown[k] >> 2;
+ oam->x = pt.x + kGarnish_Nebule_XY[i];
+ oam->y = pt.y + kGarnish_Nebule_XY[i];
+ oam->charnum = kGarnish_Nebule_Char[i];
+ int j = garnish_sprite[k];
+ oam->flags = (sprite_oam_flags[j] | sprite_obj_prio[j]) & ~1;
+ bytewise_extended_oam[oam - oam_buf] = 0;
+}
+
+void Garnish06_ZoroTrail(int k) { // 89b4fb
+ Point16U pt;
+ if (Garnish_ReturnIfPrepFails(k, &pt))
+ return;
+ OamEnt *oam = GetOamCurPtr();
+ oam->x = pt.x;
+ oam->y = pt.y;
+ oam->charnum = 0x75;
+ int j = garnish_sprite[k];
+ oam->flags = sprite_oam_flags[j] | sprite_obj_prio[j];
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ OamEnt *oam = GetOamCurPtr();
+ oam->x = pt.x;
+ oam->y = pt.y;
+ oam->charnum = kTrinexxLavaBubble_Char[garnish_countdown[k] >> 3];
+ int j = garnish_sprite[k];
+ oam->flags = (sprite_oam_flags[j] | sprite_obj_prio[j]) & 0xf0 | 0xe;
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ OamEnt *oam = GetOamCurPtr();
+ oam->x = pt.x;
+ oam->y = pt.y;
+ oam->charnum = kBlindLaserTrail_Char[garnish_oam_flags[k] - 7];
+ int j = garnish_sprite[k];
+ oam->flags = sprite_oam_flags[j] | sprite_obj_prio[j];
+ bytewise_extended_oam[oam - oam_buf] = 0;
+}
+
+void Garnish04_LaserTrail(int k) { // 89b5bb
+ static const uint8 kLaserBeamTrail_Char[2] = {0xd2, 0xf3};
+ Point16U pt;
+ if (Garnish_ReturnIfPrepFails(k, &pt))
+ return;
+ OamEnt *oam = GetOamCurPtr();
+ oam->x = pt.x;
+ oam->y = pt.y;
+ oam->charnum = kLaserBeamTrail_Char[garnish_oam_flags[k]];
+ oam->flags = 0x25;
+ bytewise_extended_oam[oam - oam_buf] = 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) {
+ OamEnt *oam = GetOamCurPtr();
+ oam->x = x;
+ oam->y = y - 16;
+ oam->charnum = kCrumbleTile_Char[j];
+ oam->flags = kCrumbleTile_Flags[j];
+ bytewise_extended_oam[oam - oam_buf] = kCrumbleTile_Ext[j];
+ }
+}
+
+void Garnish01_FireSnakeTail(int k) { // 89b6c0
+ Point16U pt;
+ if (Garnish_ReturnIfPrepFails(k, &pt))
+ return;
+ OamEnt *oam = GetOamCurPtr();
+ oam->x = pt.x;
+ oam->y = pt.y;
+ oam->charnum = 0x28;
+ int j = garnish_sprite[k];
+ oam->flags = sprite_oam_flags[j] | sprite_obj_prio[j];
+ bytewise_extended_oam[oam - oam_buf] = 2;
+}
+
+void Garnish02_MothulaBeamTrail(int k) { // 89b6e1
+ OamEnt *oam = GetOamCurPtr();
+ oam->x = garnish_x_lo[k] - BG2HOFS_copy2;
+ oam->y = garnish_y_lo[k] - BG2VOFS_copy2;
+ oam->charnum = 0xaa;
+ int j = garnish_sprite[k];
+ oam->flags = sprite_oam_flags[j] | sprite_obj_prio[j];
+ bytewise_extended_oam[oam - oam_buf] = 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;
+ byte_7E03FC = 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 (savegame_tagalong != 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;
+ for (int i = 21; 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]) {
+ uint16 x = BG2HOFS_copy2 + (sign8(byte_7E069E[1]) ? -0x10 : 0x110);
+ uint16 y = BG2VOFS_copy2 - 48;
+ for (int i = 21; i >= 0; i--, y += 16)
+ Sprite_Overworld_ProximityMotivatedLoad(x, y);
+ }
+}
+
+void Sprite_ActivateWhenProximalBig() { // 89c5fa
+ if (byte_7E069E[0]) {
+ uint16 x = BG2HOFS_copy2 - 48;
+ uint16 y = BG2VOFS_copy2 + (sign8(byte_7E069E[0]) ? -0x10 : 0x110);
+ for (int i = 21; 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--) {
+ int j = i + base;
+ uint16 x = pt.x + kScatterDebris_Draw_X[j];
+ oam->x = x;
+ oam->y = pt.y + kScatterDebris_Draw_Y[j];
+ oam->charnum = (tmp_counter == 0) ? 0x4E : (tmp_counter >= 0x80) ? 0xF2 : kScatterDebris_Draw_Char[j];
+ oam->flags = kScatterDebris_Draw_Flags[j] | r5;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8) & 1;
+ oam++;
+ }
+}
+
+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--) {
+ int j = i + base;
+ uint16 x = pt.x + kScatterDebris_Draw_X2[j];
+ oam->x = x;
+ oam->y = pt.y + kScatterDebris_Draw_Y2[j];
+ oam->charnum = kScatterDebris_Draw_Char2[j];
+ oam->flags = kScatterDebris_Draw_Flags2[j] | 0x22;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8) & 1;
+ oam++;
+ }
+}
+
+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), i;
+ 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/sprite.h
@@ -1,0 +1,325 @@
+#pragma once
+#include "types.h"
+#include "variables.h"
+
+
+struct PrepOamCoordsRet {
+ uint16 x, y;
+ uint8 r4;
+ uint8 flags;
+};
+
+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;
+};
+
+struct SpriteSpawnInfo {
+ uint16 r0_x;
+ uint16 r2_y;
+ uint8 r4_z;
+ uint16 r5_overlord_x;
+ uint16 r7_overlord_y;
+};
+
+extern const uint8 kAbsorbBigKey[2];
+
+
+
+struct DrawMultipleData {
+ int8 x, y;
+ uint16 char_flags;
+ uint8 ext;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+enum {
+ kCheckDamageFromPlayer_Carry = 1,
+ kCheckDamageFromPlayer_Ne = 2,
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+static inline uint8 ClampYForOam(uint16 y) {
+ return (uint16)(y + 0x10) < 0x100 ? y : 0xf0;
+}
+
+
+
+
+
+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);
+void 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 AgahnimBalls_DamageAgahnim(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 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/sprite_main.cpp
@@ -1,0 +1,26166 @@
+#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_Ext[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_Ext[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 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
+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_Ext[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_Ext[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_Moldorm_bounce,
+ &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_bounce,
+ &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_bounce,
+ &Sprite_26_HardhatBeetle,
+ &Sprite_27_Deadrock,
+ &Sprite_28_DarkWorldHintNPC,
+ &Sprite_HumanMulti_1,
+ &Sprite_SweepingLady,
+ &Sprite_2B_Hobo,
+ &Sprite_Lumberjacks,
+ &Sprite_2D_TelepathicTile_bounce,
+ &Sprite_2E_FluteKid,
+ &Sprite_MazeGameLady,
+ &Sprite_MazeGameGuy,
+ &Sprite_FortuneTeller,
+ &Sprite_QuarrelBros,
+ &Sprite_33_RupeePull_bounce,
+ &Sprite_YoungSnitchLady,
+ &Sprite_InnKeeper,
+ &Sprite_Witch,
+ &Sprite_37_Waterfall_bounce,
+ &Sprite_38_EyeStatue_bounce,
+ &Sprite_39_Locksmith,
+ &Sprite_3A_MagicBat_bounce,
+ &Sprite_DashItem,
+ &Sprite_TroughBoy,
+ &Sprite_OldSnitchLady,
+ &Sprite_17_Hoarder,
+ &Sprite_TutorialGuardOrBarrier_bounce,
+ &Sprite_TutorialGuardOrBarrier_bounce,
+ // Trampoline 48 entries
+ &Sprite_41_BlueGuard,
+ &Sprite_41_BlueGuard,
+ &Sprite_41_BlueGuard,
+ &Sprite_44_BluesainBolt,
+ &Sprite_45_UsainBolt,
+ &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_CannonTrooper,
+ &Sprite_6C_MirrorPortal,
+ &Sprite_6D_Rat,
+ &Sprite_6E_Rope,
+ &Sprite_6F_Keese,
+ &Sprite_70_KingHelmasaurFireball_bounce,
+ &Sprite_71_Leever,
+ &Sprite_72_FairyPond,
+ &Sprite_73_UncleAndPriest_bounce,
+ &Sprite_RunningMan,
+ &Sprite_BottleVendor,
+ &Sprite_76_Zelda,
+ &Sprite_15_Antifairy,
+ &Sprite_78_MrsSahasrahla_bounce,
+ // 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_Mushroom,
+ &Sprite_FakeSword,
+ &Sprite_PotionShop,
+ &Sprite_HeartContainer,
+ &Sprite_HeartPiece,
+ &Sprite_EC_ThrownItem,
+ &Sprite_SomariaPlatform,
+ &Sprite_MovableMantleTrampoline,
+ &Sprite_SomariaPlatform,
+ &Sprite_SomariaPlatform,
+ &Sprite_SomariaPlatform,
+ &Sprite_F2_MedallionTablet_bounce,
+};
+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_bounce,
+ &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_bounce,
+ &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,
+};
+static inline uint8 ChainBallMult(uint16 a, uint8 b);
+static inline uint8 GuruguruBarMult(uint16 a, uint8 b);
+static inline int8 GuruguruBarSin(uint16 a, uint8 b);
+static inline uint8 ArrgiMult(uint16 a, uint8 b);
+static inline int8 ArrgiSin(uint16 a, uint8 b);
+static inline uint8 HelmasaurMult(uint16 a, uint8 b);
+static inline int8 HelmasaurSin(uint16 a, uint8 b);
+static inline uint8 TrinexxMult(uint8 a, uint8 b);
+static inline uint8 TrinexxHeadMult(uint16 a, uint8 b);
+static inline int8 TrinexxHeadSin(uint16 a, uint8 b);
+static inline uint8 GanonMult(uint16 a, uint8 b);
+static inline int8 GanonSin(uint16 a, uint8 b);
+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];
+ byte_7E1CF2[0] = (j / 10) | (j % 10)<< 4 ;
+ byte_7E1CF2[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_MovableMantleTrampoline(int k) {
+ MovableMantle_Draw(k);
+ if (Sprite_ReturnIfInactive(k))
+ return;
+ if (!Sprite_CheckDamageToLink_same_layer(k))
+ return;
+ Sprite_NullifyHookshotDrag();
+ Sprite_RepelDash();
+
+ if (savegame_tagalong != 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_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 || savegame_tagalong == 10)
+ return;
+ if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x20)
+ return;
+ if (Sprite_CheckDamageToLink_same_layer(k)) {
+ savegame_tagalong = 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_bounce(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 {
+ oam->x = info.x - 20 + kArcheryGame_X[i] + 1;
+ oam->y = info.y - 48 + kArcheryGame_Y[i] + 1;
+ oam->charnum = kArcheryGame_Char[i];
+ oam->flags = kArcheryGame_Flags[i];
+ bytewise_extended_oam[oam - oam_buf] = 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++) {
+ oam->x = info.x + kGoodArcheryTarget_X[i];
+ oam->y = info.y + kGoodArcheryTarget_Y[i];
+ oam->charnum = (i == 4) ? kGoodArcheryTarget_Draw_Char4[b - 1] :
+ (i == 3) ? kGoodArcheryTarget_Draw_Char3[b - 1] : kGoodArcheryTarget_Draw_Char[i];
+ oam->flags = kGoodArcheryTarget_Draw_Flags[i] & (oam->charnum < 0x7c ? 0xff : 0xfe);
+ bytewise_extended_oam[oam - oam_buf] = 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_Ext[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 ext = kDebirandoPit_Draw_Ext[g];
+ for (int i = 3; i >= 0; i--, oam++) {
+ int j = g * 4 + i;
+ uint16 x = info.x + kDebirandoPit_Draw_X[j];
+ uint16 y = info.y + kDebirandoPit_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kDebirandoPit_Draw_Char[j];
+ oam->flags = kDebirandoPit_Draw_Flags[j] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = ext | (x >> 8 & 1);
+ }
+}
+
+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_Ext[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;
+ uint16 x = info.x + kDebirando_Draw_X[j];
+ uint16 y = info.y + kDebirando_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kDebirando_Draw_Char[j];
+ uint8 f = kDebirando_Draw_Flags[j];
+ oam->flags = (f ^ info.flags) & ((f & 0xf) == 0 ? 0xf0 : 0xff);
+ bytewise_extended_oam[oam - oam_buf] = kDebirando_Draw_Ext[j] | (x >> 8 & 1);
+ }
+}
+
+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;
+ uint16 x = info.x + kSpikeRoller_Draw_X[j];
+ uint16 y = info.y + kSpikeRoller_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = chr ? chr : kSpikeRoller_Draw_Char[j];
+ chr = 0;
+ oam->flags = kSpikeRoller_Draw_Flags[j] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+}
+
+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++) {
+ uint16 x = info.x;
+ uint16 y = info.y + kBeamos_Draw_Y[i];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kBeamos_Draw_Char[i];
+ oam->flags = info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+ 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;
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = 0x5c;
+ oam->flags = info.flags;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1);
+ }
+}
+
+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++) {
+ uint16 x = info.x + kBeamosLaserHit_Draw_X[i];
+ uint16 y = info.y + kBeamosLaserHit_Draw_Y[i];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = 0xd6;
+ oam->flags = kBeamosLaserHit_Draw_Flags[i] | info.flags & 0x30;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1);
+ }
+}
+
+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;
+ uint16 x = info.x + kCrab_Draw_X[j];
+ uint16 y = info.y;
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kCrab_Draw_Char[j];
+ oam->flags = kCrab_Draw_Flags[j] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+ 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]) {
+ Sprite_SetX(k, (sprite_A[k] | sprite_B[k] << 8) + kSprite_Zora_Surface_XY[GetRandomNumber() & 7]);
+ Sprite_SetY(k, (sprite_C[k] | sprite_head_dir[k] << 8) + kSprite_Zora_Surface_XY[GetRandomNumber() & 7]);
+ Sprite_Get16BitCoords(k);
+ Sprite_CheckTileCollision(k);
+ if (sprite_tiletype == 8) {
+ sprite_delay_main[k] = 127;
+ sprite_ai_state[k]++;
+ sprite_flags3[k] |= 0x40;
+ }
+ }
+ 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_Ext[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;
+ uint16 x = info.x + kZora_Draw_X[j];
+ uint16 y = info.y + kZora_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kZora_Draw_Char[j];
+ uint8 f = kZora_Draw_Flags[j];
+ oam->flags = f | (f & 0xf ? 0 : info.flags);
+ bytewise_extended_oam[oam - oam_buf] = kZora_Draw_Ext[j] | (x >> 8 & 1);
+ }
+}
+
+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;
+ oam->x = kZoraKing_Draw_X1[j] + info.x;
+ oam->y = kZoraKing_Draw_Y1[j] + info.y;
+ oam->charnum = kZoraKing_Draw_Char1[j];
+ oam->flags = kZoraKing_Draw_Flags1[j] | 0x24;
+ bytewise_extended_oam[oam - oam_buf] = 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];
+ oam->x = info.x;
+ oam->y = ClampYForOam(info.y - 6);
+ oam->charnum = kWalkingZora_Draw_Char[i];
+ oam->flags = info.flags | kWalkingZora_Draw_Flags[i];
+ bytewise_extended_oam[oam - oam_buf] = 2 | (info.x >> 8 & 1);
+ oam++;
+
+ oam->x = info.x;
+ oam->y = ClampYForOam(info.y + 2);
+ oam->charnum = kWalkingZora_Draw_Char2[g];
+ oam->flags = info.flags | kWalkingZora_Draw_Flags2[g];
+ bytewise_extended_oam[oam - oam_buf] = 2 | (info.x >> 8 & 1);
+
+ 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_Ext[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;
+ uint16 x = info.x + kArmosKnight_Draw_X[j];
+ uint16 y = info.y + kArmosKnight_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kArmosKnight_Draw_Char[j];
+ oam->flags = kArmosKnight_Draw_Flags[j] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = kArmosKnight_Draw_Ext[j] | (x >> 8 & 1);
+ }
+ 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;
+ oam[4].x = info.x - 8 + z;
+ oam[5].x = info.x + 8 - z;
+ if ((uint16)(y + 12 + 16) < 0x100) {
+ oam[5].y = oam[4].y = y + 12;
+ } else {
+ oam[5].y = oam[4].y = 0xf0;
+ }
+ oam[5].charnum = oam[4].charnum = 0xe4;
+ oam[4].flags = 0x25;
+ oam[5].flags = 0x25 | 0x40;
+ bytewise_extended_oam[oam + 4 - oam_buf] = 2;
+ bytewise_extended_oam[oam + 5 - oam_buf] = 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();
+ oam->x = sprite_x_lo[k] - BG2HOFS_copy2;
+ oam->y = sprite_y_lo[k] - BG2VOFS_copy2;
+ j = kLanmola_Draw_Idx2[sprite_delay_main[k] >> 3];
+ oam->charnum = kLanmola_Draw_Char2[j];
+ oam->flags = kLanmola_Draw_Flags2[j] | 0x31;
+ bytewise_extended_oam[oam - oam_buf] = 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_Ext4[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;
+ oam->x = x + kLanmola_Draw_X4[j];
+ oam->y = y + kLanmola_Draw_Y4[j];
+ oam->charnum = kLanmola_Draw_Char4[j];
+ oam->flags = kLanmola_Draw_Flags4[j] | 0x31;
+ bytewise_extended_oam[oam - oam_buf] = kLanmola_Draw_Ext4[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;
+ uint16 x = info->x, y = info->y - 9;
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kChainBallTrooperHead_Char[j];
+ oam->flags = info->flags | kChainBallTrooperHead_Flags[j];
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+}
+
+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;
+ uint16 x = info->x + kFlailTrooperBody_X[j];
+ uint16 y = info->y + kFlailTrooperBody_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kFlailTrooperBody_Char[j];
+ oam->flags = info->flags | kFlailTrooperBody_Flags[j];
+ bytewise_extended_oam[oam - oam_buf] = kFlailTrooperBody_Ext[j] | (x >> 8 & 1);
+ 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 r10 = (r0 & 0x1ff) >> 6;
+ 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;
+
+ oam[0].x = HIBYTE(dungmap_var8) + BYTE(dungmap_var7);
+ oam[0].y = BYTE(dungmap_var8) + HIBYTE(dungmap_var7);
+
+ oam[0].charnum = 0x2a;
+ oam[0].flags = 0x2d;
+ bytewise_extended_oam[oam - oam_buf] = 2;
+ oam++;
+
+ for (int i = 3; i >= 0; i--, oam++) {
+ t = (kFlailTrooperWeapon_Tab4[i] * r14) >> 8;
+ t = sign8(r4) ? -t : t;
+ oam->x = t + BYTE(dungmap_var7) + r12;
+ t = (kFlailTrooperWeapon_Tab4[i] * r15) >> 8;
+ t = sign8(r6) ? -t : t;
+ oam->y = t + HIBYTE(dungmap_var7) + r13;
+ oam->charnum = 0x3f;
+ oam->flags = 0x2d;
+ bytewise_extended_oam[oam - oam_buf] = 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++) {
+ uint16 x = info.x + kMetalBallLarge_X[i];
+ uint16 y = info.y + kMetalBallLarge_Y[i];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kMetalBallLarge_Char[g * 4 + i];
+ oam->flags = kMetalBallLarge_Flags[i] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+
+}
+
+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_Ext[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;
+ uint16 x = info.x + kGerudoMan_Draw_X[j];
+ uint16 y = info.y + kGerudoMan_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kGerudoMan_Draw_Char[j];
+ oam->flags = kGerudoMan_Draw_Flags[j] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = kGerudoMan_Draw_Ext[j] | (x >> 8 & 1);
+ }
+}
+
+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_Ext[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 ext = kToppo_Draw_Ext[j];
+ uint16 x = info.x + kToppo_Draw_X[j];
+ uint16 y = (ext ? info.y : ybase) + kToppo_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kToppo_Draw_Char[j];
+ uint8 flags = kToppo_Draw_Flags[j] | info.flags;
+ if (ext == 0)
+ flags = flags & ~0xf | 2;
+ oam->flags = flags;
+ bytewise_extended_oam[oam - oam_buf] = ext | (x >> 8 & 1);
+ }
+}
+
+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 r6 = sprite_graphics[k];
+ int hd = sprite_head_dir[k];
+ uint16 x = info.x;
+ uint16 y = info.y - 11;
+ oam->x = x;
+ oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0;
+ oam->charnum = kSoldier_Draw1_Char[hd];
+ oam->flags = kSoldier_Draw1_Flags[hd] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+
+ oam++;
+
+ x = info.x + kRecruit_Draw_X[r6];
+ y = info.y;
+ oam->x = x;
+ oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0;
+ oam->charnum = kRecruit_Draw_Char[r6];
+ oam->flags = kRecruit_Draw_Flags[r6] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ 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];
+ uint16 x = info->x + kBombTrooper_DrawArm_X[j];
+ uint16 y = info->y + kBombTrooper_DrawArm_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = 0x6e;
+ oam->flags = info->flags & 0x30 | 0x8;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+}
+
+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;
+ oam->x = poc->x;
+ int dir = sprite_head_dir[k];
+ uint16 y = poc->y - kSoldier_Draw1_Yd[sprite_graphics[k]];
+ oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0;
+ oam->charnum = kSoldier_Draw1_Char[dir];
+ oam->flags = kSoldier_Draw1_Flags[dir] | poc->flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (poc->x & 0x100) >> 8;
+}
+
+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_Ext[j] || i == 3 && kSoldier_Draw2_Char[j] == 0x20))
+ continue;
+ uint16 x = poc->x + kSoldier_Draw2_Xd[j];
+ uint16 y = poc->y + kSoldier_Draw2_Yd[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kSoldier_Draw2_Char[j];
+ bool flag = true;
+ uint8 p = 8;
+ if (oam->charnum == 0x20) {
+ p = 2;
+ if (type == 0x46)
+ oam->y = 0xf0;
+ } else {
+ flag = kSoldier_Draw2_Ext[j] == 0;
+ }
+ uint8 flags = kSoldier_Draw2_Flags[j] | poc->flags;
+ oam->flags = flag ? (flags & 0xf1 | p) : flags;
+ bytewise_extended_oam[oam - oam_buf] = kSoldier_Draw2_Ext[j] | (x & 0x100) >> 8;
+ 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;
+ uint16 x = poc->x + kSoldier_Draw3_Xd[j];
+ uint16 y = poc->y + kSoldier_Draw3_Yd[j];
+ oam->x = x;
+ oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0;
+ dungmap_var8 = kSoldier_Draw3_Xd[j] << 8 | (uint8)kSoldier_Draw3_Yd[j];
+ oam->charnum = kSoldier_Draw3_Char[j] + (type < 0x43 ? 3 : 0);
+ oam->flags = kSoldier_Draw3_Flags[j] | poc->flags;
+ bytewise_extended_oam[oam - oam_buf] = (x & 0x100) >> 8;
+ }
+}
+
+void Sprite_45_UsainBolt(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];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kSolderThrowing_Draw_Char[j] - (sprite_type[k] >= 0x48 ? 3 : 0);
+ oam->flags = (kSolderThrowing_Draw_Flags[j] | info->flags) & 0xf1 | 8;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1);
+ }
+}
+
+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;
+ uint16 x = info.x;
+ uint16 y = info.y + kBushSoldierCommon_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kBushSoldierCommon_Char[j];
+ uint8 flags = kBushSoldierCommon_Flags[j] | 0x20;
+ if (i == 0)
+ flags = flags & ~0xe | info.flags;
+ oam->flags = flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+}
+
+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;
+ uint16 x = info->x + kArcherSoldier_Draw_X[j];
+ uint16 y = info->y + kArcherSoldier_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kArcherSoldier_Draw_Char[j];
+ oam->flags = kArcherSoldier_Draw_Flags[j] | 0x20;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1);
+ }
+}
+
+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;
+ uint16 x = info.x + kTutorialSoldier_X[j];
+ uint16 y = info.y + kTutorialSoldier_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kTutorialSoldier_Char[j];
+ uint8 flags = kTutorialSoldier_Flags[j] | info.flags;
+ if (oam->charnum < 0x40)
+ flags = (flags & 0xf1) | 8;
+ oam->flags = flags;
+ bytewise_extended_oam[oam - oam_buf] = kTutorialSoldier_Ext[j] | (x >> 8 & 1);
+ }
+ 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++) {
+ oam->x = info.x + kBadPullDownSwitch_X[i];
+ oam->y = info.y + kBadPullDownSwitch_Y[i] - (i == 2 ? yoff : 0);
+ oam->charnum = kBadPullDownSwitch_Char[i];
+ oam->flags = kBadPullDownSwitch_Flags[i] | 0x21;
+ bytewise_extended_oam[oam - oam_buf] = kBadPullDownSwitch_Ext[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++) {
+ uint16 x = info.x;
+ uint16 y = info.y - ((i == 0) ? yoff : 0);
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kBadPullUpSwitch_Tab2[i];
+ oam->flags = info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+}
+
+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
+ savegame_tagalong = 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) {
+ savegame_tagalong = 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 == 5) {
+ 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];
+
+ oam[0].x = BYTE(dungmap_var7) + kWitch_DrawDataA[g * 2].x;
+ oam[0].y = HIBYTE(dungmap_var7) + kWitch_DrawDataA[g * 2].y;
+ WORD(oam[0].charnum) = WORD(info.r4) | WORD(kWitch_DrawDataA[g * 2].charnum);
+
+ oam[1].x = BYTE(dungmap_var7) + kWitch_DrawDataA[g * 2 + 1].x;
+ oam[1].y = HIBYTE(dungmap_var7) + kWitch_DrawDataA[g * 2 + 1].y;
+ WORD(oam[1].charnum) = WORD(info.r4) | WORD(kWitch_DrawDataA[g * 2+1].charnum);
+ for (int i = 0; i < 3; i++) {
+ oam[i+2].x = BYTE(dungmap_var7) + kWitch_DrawDataB[i].x;
+ oam[i+2].y = HIBYTE(dungmap_var7) + kWitch_DrawDataB[i].y;
+ WORD(oam[i+2].charnum) = WORD(info.r4) ^ WORD(kWitch_DrawDataB[i].charnum);
+ }
+ int i = (uint16)(g - 3) < 3;
+ oam[5].x = BYTE(dungmap_var7) + kWitch_DrawDataC[i].x;
+ oam[5].y = HIBYTE(dungmap_var7) + kWitch_DrawDataC[i].y;
+ WORD(oam[5].charnum) = WORD(info.r4) | WORD(kWitch_DrawDataC[i].charnum);
+
+ int e = oam - oam_buf;
+ WORD(bytewise_extended_oam[e]) = 0;
+ WORD(bytewise_extended_oam[e+2]) = 0x202;
+ WORD(bytewise_extended_oam[e+4]) = 0x202;
+ 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;
+ savegame_tagalong = 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();
+ savegame_tagalong = 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_Mushroom(int k) { // 85ee78
+ SpriteDraw_SingleLarge(k);
+ if (Sprite_CheckIfLinkIsBusy())
+ 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_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 == 15 && (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 == 15 && (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_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 (savegame_tagalong != 6) {
+ savegame_tagalong = 6;
+ super_bomb_going_off = 0;
+ tagalong_var5 = 0;
+ LoadFollowerGraphics();
+ Follower_Initialize();
+ savegame_tagalong = 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 (savegame_tagalong != 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 || savegame_tagalong != 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 (savegame_tagalong == 9) {
+ sprite_state[k] = 0;
+ return;
+ }
+ if (savegame_tagalong == 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_bounce(int k) { // 868f8a
+ if (Sprite_ReturnIfBossFinished(k))
+ return;
+ sprite_ignore_projectile[k]++;
+ Sprite_InitializedSegmented(k);
+}
+
+void SpritePrep_Lanmolas_bounce(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_Moldorm_bounce(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;
+ sound_effect_2 = Sprite_CalculateSfxPan(k);
+ }
+
+ 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};
+ int j;
+ 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();
+ uint16 x = info.x + kPoe_Draw_X[sprite_D[k]];
+ uint16 y = info.y + 9;
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kPoe_Draw_Char[sprite_subtype2[k] >> 3 & 3];
+ oam->flags = info.flags & 0xf0 | 2;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1);
+}
+
+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;
+ uint16 x = info.x;
+ uint16 y = info.y + kCoveredRupeeCrab_DrawY[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ uint8 ch = kCoveredRupeeCrab_DrawChar[j];
+ oam->charnum = ch + (ch == 0x44 ? r7 : 0);
+ oam->flags = (info.flags & ~1) | kCoveredRupeeCrab_DrawFlags[j];
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+}
+
+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++) {
+ uint16 x = info.x + kThrowableScenery_DrawLarge_X[i];
+ uint16 y = info.y + kThrowableScenery_DrawLarge_Y[i];
+ oam->x = x;
+ oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0;
+ oam->charnum = 0x4a;
+ oam->flags = kThrowableScenery_DrawLarge_Flags[i] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+ Oam_AllocateFromRegionB(12);
+ oam = GetOamCurPtr();
+ info.y = Sprite_GetY(k) - BG2VOFS_copy2;
+ for (int i = 2; i >= 0; i--, oam++) {
+ uint16 x = info.x + kThrowableScenery_DrawLarge_X2[i];
+ uint16 y = info.y + 12;
+ oam->x = x;
+ oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0;
+ oam->charnum = 0x6c;
+ oam->flags = 0x24;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+}
+
+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;
+
+ int type = sprite_subtype2[k];
+
+ 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 == 13 && 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 {
+ savegame_tagalong = 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 (savegame_tagalong != 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;
+ savegame_tagalong = 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 == 12 && (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;
+ uint16 x = info.x + kEnemyArrow_Draw_X[j];
+ uint16 y = info.y + kEnemyArrow_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kEnemyArrow_Draw_Char[j + r7];
+ oam->flags = kEnemyArrow_Draw_Flags[j + r7] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1);
+ }
+}
+
+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 = overworld_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 *ext = &g_ram[oam_ext_cur_ptr];
+ ext[0] = ext[1] = ext[2] = ext[3] = 0;
+ ext[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 (savegame_tagalong != 0)
+ sprite_ai_state[k] = 5;
+ }
+ sprite_x_lo[k] = bak;
+ break;
+ case 1: // transition to tagalong
+ savegame_tagalong = 9;
+ tagalong_var5 = 0;
+ LoadFollowerGraphics();
+ Follower_Initialize();
+ word_7E02CD = 0x40;
+ sprite_state[k] = 0;
+ break;
+ case 2: // offer chest
+ if (Sprite_CheckIfLinkIsBusy())
+ return;
+ if (super_bomb_going_off) {
+ 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 (super_bomb_going_off) {
+ 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;
+ savegame_tagalong = 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_bounce(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 (savegame_tagalong == 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 (savegame_tagalong == 0) {
+ if (link_item_mirror == 2)
+ sprite_state[k] = 0;
+ savegame_tagalong = 4;
+ LoadFollowerGraphics();
+ savegame_tagalong = 0;
+ } else {
+ sprite_state[k] = 0;
+ LoadFollowerGraphics();
+ }
+}
+
+void Sprite_TutorialGuardOrBarrier_bounce(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_bounce(int k) { // 86c00d
+ switch (sprite_subtype2[k]) {
+ case 0:
+ MedallionTablet_Main(k);
+ break;
+ case 1:
+ Sprite_DustCloud(k);
+ break;
+ }
+}
+
+void Sprite_33_RupeePull_bounce(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_bounce(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_bounce(int k) { // 86c03a
+ switch (sprite_subtype2[k]) {
+ case 0: Waterfall(k); break;
+ case 1: Sprite_BatCrash(k); break;
+ }
+}
+
+void Sprite_38_EyeStatue_bounce(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_bounce(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 = savegame_tagalong;
+ savegame_tagalong = 1;
+ LoadFollowerGraphics();
+ savegame_tagalong = 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 (savegame_tagalong != 1 && (sram_progress_flags & 4))
+ sprite_state[k] = 0;
+ }
+}
+
+void Sprite_78_MrsSahasrahla_bounce(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_bounce(int k) { // 86c0b2
+ assert(0);
+}
+
+void Sprite_25_TalkingTree_bounce(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(byte_7E1CF2[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;
+ byte_7E1CF2[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;
+ }
+ byte_7E1CF2[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;
+ byte_7E1CF2[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;
+ byte_7E1CF2[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_Ext[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;
+ oam->x = kFaerieQueen_Draw_X[j] + info.x;
+ oam->y = kFaerieQueen_Draw_Y[j] + info.y;
+ oam->charnum = kFaerieQueen_Draw_Char[j];
+ oam->flags = info.flags | kFaerieQueen_Draw_Flags[j];
+ bytewise_extended_oam[oam - oam_buf] = kFaerieQueen_Draw_Ext[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_Ext[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;
+ uint16 x = info.x + kLeever_Draw_X[j];
+ uint16 y = info.y + kLeever_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kLeever_Draw_Char[j];
+ uint8 f = info.flags;
+ if (oam->charnum >= 0x60 || oam->charnum == 0x28 || oam->charnum == 0x38)
+ f &= 0xf0;
+ oam->flags = kLeever_Draw_Flags[j] | f;
+ bytewise_extended_oam[oam - oam_buf] = kLeever_Draw_Ext[j] | (x >> 8 & 1);
+ }
+}
+
+void Sprite_D8_Heart(int k) { // 86cec0
+ if (SpriteDraw_AbsorbableTransient(k, true))
+ return;
+ if (Sprite_ReturnIfInactive(k))
+ return;
+ Sprite_CheckAbsorptionByPlayer(k);
+ 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;
+ }
+ }
+ 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];
+ uint16 x = info.x + kOctorock_Draw_X[j];
+ uint16 y = info.y + kOctorock_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kOctorock_Draw_Char[j];
+ oam->flags = kOctorock_Draw_Flags[j] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1);
+ }
+ 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;
+ uint16 x = info.x + kOctostone_Draw_X[j];
+ uint16 y = info.y + kOctostone_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = 0xbc;
+ oam->flags = kOctostone_Draw_Flags[j] | 0x2d;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1);
+ }
+
+}
+
+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;
+ uint16 x = info.x + kOctoballoon_Draw_X[j];
+ uint16 y = info.y + kOctoballoon_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kOctoballoon_Draw_Char[j];
+ oam->flags = kOctoballoon_Draw_Flags[j] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+ 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++) {
+ uint16 x = info.x + kBuzzBlob_DrawX[i];
+ uint16 y = info.y + kBuzzBlob_DrawY[i];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kBuzzBlob_DrawChar[g * 3 + i];
+ if (oam->charnum == 0)
+ oam->y = 240;
+ oam->flags = kBuzzBlob_DrawFlags[g * 3 + i] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = kBuzzBlob_DrawExt[i] | (x >> 8 & 1);
+ }
+ 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 == 13 && (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);
+done:
+
+ int 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;
+ byte_7E1CF2[0] = t | c << 4;
+ byte_7E1CF2[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
+ 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];
+ uint16 x = info.x + kKholdstare_Draw_X[j];
+ uint16 y = info.y + kKholdstare_Draw_Y[j];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kKholdstare_Draw_Char[j];
+ oam->flags = kKholdstare_Draw_Flags[j] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ 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_Ext[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;
+ oam->x = info.x + kArcheryGameGuy_Draw_X[j];
+ oam->y = info.y + kArcheryGameGuy_Draw_Y[j];
+ oam->charnum = kArcheryGameGuy_Draw_Char[j];
+ oam->flags = kArcheryGameGuy_Draw_Flags[j] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = kArcheryGameGuy_Draw_Ext[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
+ byte_7E03FC = 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++) {
+ uint16 x = info.x + kMothula_Draw_X[g * 9 + i];
+ uint16 y = info.y + 16;
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = 0x6c;
+ oam->flags = 0x24;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+}
+
+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, 0xd8, &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++) {
+ uint16 x = info.x + kFirebat_Draw_X[i];
+ uint16 y = info.y;
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kFirebat_Draw_Char[g];
+ oam->flags = kFirebat_Draw_Flags[g * 2 + i] | info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+}
+
+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;
+ oam->x = info.x + kGanon_Draw_X[j];
+ oam->y = info.y + kGanon_Draw_Y[j];
+ oam->charnum = kGanon_Draw_Char[j];
+ oam->flags = info.flags | (kGanon_Draw_Flags[j] & ((info.flags & 0xf) >= 5 ? 0xf0 : 0xff));
+ bytewise_extended_oam[oam - oam_buf] = 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
+ static const uint8 kBuggySwamolaLookup[6] = { 0x1c, 0xa9, 0x03, 0x9d, 0x90, 0x0d }; // wrong bank
+ //int j = k * 32;
+ int 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 (savegame_tagalong != 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++) {
+ oam->x = info.x + TrinexxMult(xb, kTrinexx_Mults[i]);
+ oam->y = info.y + TrinexxMult(yb, kTrinexx_Mults[i]);
+ oam->charnum = 0x28;
+ oam->flags = info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 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) {
+ oam[0].x = oam[1].x = xb + (i ? -28 : 28) + kTrinexx_Draw_Xoffs[xidx + (1-i) * 8 & 0xf];
+ oam[0].y = yb - 8 + kTrinexx_Draw_Yoffs[yidx + i * 8 & 0xf];
+ oam[1].y = oam[0].y + 16;
+ oam[0].charnum = 0xc;
+ oam[1].charnum = 0x2a;
+ oam[0].flags = oam[1].flags = info.flags | (i ? 0 : 0x40);
+ WORD(bytewise_extended_oam[oam - oam_buf]) = 0x202;
+ }
+
+ 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;
+ oam->x = xb + kTrinexx_Draw_X[j];
+ uint16 y = yb - kTrinexx_Draw_Y[j] - 0x20 + WORD(overlord_x_lo[7]);
+ oam->y = ClampYForOam(y);
+ oam->charnum = kTrinexx_Draw_Char[i];
+ oam->flags = info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 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);
+ oam->x = BYTE(cur_sprite_x) + kTrinexxHead_FirstPart_X[m];
+
+ BYTE(cur_sprite_y) = info.y + HIBYTE(dungmap_var7);
+ oam->y = BYTE(cur_sprite_y) + kTrinexxHead_FirstPart_Y[m] + (m == 4 ? sprite_subtype[k] : 0);
+
+ oam->charnum = kTrinexxHead_FirstPart_Char[m];
+ oam->flags = info.flags | kTrinexxHead_FirstPart_Flags[m];
+ bytewise_extended_oam[oam - oam_buf] = 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 {
+ BYTE(cur_sprite_x) = oam->x = info.x + BYTE(dungmap_var7);
+ BYTE(cur_sprite_y) = oam->y = info.y + HIBYTE(dungmap_var7);
+ oam->charnum = 8;
+ oam->flags = info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 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++) {
+ uint16 x = chainchomp_x_hist[pos] + r8 - BG2HOFS_copy2;
+ uint16 y = chainchomp_y_hist[pos] + r8 - BG2VOFS_copy2;
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = 0x8b;
+ oam->flags = flags & 0xf0 | 0xd;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1);
+ }
+}
+
+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 x = info.x, y = info.y;
+ for (int i = sprite_A[k]; i >= 0; i--, oam--) {
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = ((i == 0) ? 0xa2 : 0xa0) - ((d < 7) ? 0x20 : 0);
+ oam->flags = info.flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ 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_Ext[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 *ext_data = kChattyAgahnim_Telewarp_Data_Ext;
+ 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;
+ ext_data += t;
+ data += t;
+ do {
+ oam->x = info->x + data->x;
+ oam->y = info->y + data->y - 8;
+ oam->charnum = data->charnum;
+ oam->flags = data->flags | 0x31;
+ bytewise_extended_oam[oam - oam_buf] = *ext_data;
+ } while (data++, ext_data++, 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();
+
+ oam[0].x = info->x + xoffs;
+ oam[1].x = info->x - xoffs;
+ oam[0].y = oam[1].y = ClampYForOam(y + 7);
+ oam[0].charnum = oam[1].charnum = 0x6c;
+ oam[0].flags = oam[1].flags = 0x24;
+ bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf + 1] = 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();
+ uint8 yoff = kBadPullSwitch_Tab5[kBadPullSwitch_Tab4[sprite_graphics[k]]];
+ 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];
+ int y = info->y + (uint16)kGiantMoldorm_Eye_Y[r6 & 0xf];
+ oam->x = x;
+ oam->y = (uint16)(y + 0x10 + ((y >> 16) & 1)) < 0x100 ? y : 0xf0;
+ oam->charnum = kGiantMoldorm_Eye_Char[(r6 + r7) & 0xf];
+ oam->flags = info->flags | kGiantMoldorm_Eye_Flags[(r6 + r7) & 0xf];
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+ }
+}
+
+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_subtype2[k] = 1;
+ }
+ } else if (sprite_subtype[k] < 10) {
+ sprite_subtype[k]++;
+ } else if (sprite_subtype[k] == 10) {
+ 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_Ext[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) {
+ uint16 x = info.x + kMoldorm_Draw_X[base & 0xf];
+ int y = info.y + (uint16)kMoldorm_Draw_Y[base & 0xf];
+ oam->x = x;
+ oam->y = (uint16)(y + 0x10 + ((y >> 16) & 1)) < 0x100 ? y : 0xf0;
+ oam->charnum = 0x4D;
+ oam->flags = info.flags;
+ bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1);
+ }
+ 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];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kMoldorm_Draw_Char[i];
+ oam->flags = info.flags;
+ bytewise_extended_oam[oam - oam_buf] = kMoldorm_Draw_Ext[i] | (x >> 8 & 1);
+ }
+}
+
+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 (savegame_tagalong == 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]++;
+ byte_7E03FC = 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++) {
+ oam->x = info->x + kHelmasaurKing_DrawB_X[i];
+ oam->y = info->y + 0x14;
+ int j = overlord_x_lo[4] >> 2 & 7;
+ oam->charnum = kHelmasaurKing_DrawB_Char[j];
+ oam->flags = kHelmasaurKing_DrawB_Flags[i];
+ bytewise_extended_oam[oam - oam_buf] = 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) {
+ oam[1].x = oam[0].x = info->x + kHelmasaurKing_DrawE_X[i];
+ oam[0].y = info->y + kHelmasaurKing_DrawE_Y[i] + overlord_x_lo[i];
+ oam[1].y = oam[0].y + 0x10;
+ oam[0].charnum = kHelmasaurKing_DrawE_Char[i];
+ oam[1].charnum = oam[0].charnum + 2;
+ oam[1].flags = oam[0].flags = kHelmasaurKing_DrawE_Flags[i] ^ info->flags;
+ bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf + 1] = 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();
+ oam->x = info->x;
+ int t = (uint8)info->y + 0x13;
+ oam->y = t + (t >> 8) + yd;
+ oam->charnum = 0xaa;
+ oam->flags = info->flags ^ 0xb;
+ bytewise_extended_oam[oam - oam_buf] = 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] = -pt.x;
+ sprite_y_vel[k] = -pt.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[2] = {8, -8};
+ 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] & 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);
+skip_sound:
+ static const uint8 kKyameron_Moving_Gfx[4] = {3, 2, 1, 0};
+ 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();
+ oam->x = info->x;
+ oam->y = ClampYForOam(info->y + sprite_C[k] - 12);
+ oam->charnum = kStalfosKnight_DrawHead_Char[i];
+ oam->flags = info->flags | kStalfosKnight_DrawHead_Flags[i];
+ bytewise_extended_oam[oam - oam_buf] = 2 | (info->x >> 8 & 1);
+}
+
+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
+ int j;
+ 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
+ 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;
+ uint16 x = info->x + (int8)sprite_B[k];
+ uint16 y = info->y - sprite_C[k];
+ int j = sprite_head_dir[k];
+ oam->x = x;
+ oam->y = ClampYForOam(y);
+ oam->charnum = kYellowStalfos_Head_Char[j];
+ oam->flags = kYellowStalfos_Head_Flags[j] | info->flags;
+ bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1);
+}
+
+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++) {
+ oam->x = info.x + sinval * (i + 1) / 4;
+ oam->y = info.y + cosval * (i + 1) / 4;
+ oam->charnum = 0x28;
+ oam->flags = flags;
+ bytewise_extended_oam[oam - oam_buf] = 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_Ext1[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;
+ oam->x = info.x + kAgahnim_Draw_X0[j];
+ oam->y = info.y + kAgahnim_Draw_Y0[j];
+ oam->charnum = kAgahnim_Draw_Char0[j];
+ oam->flags = info.flags | kAgahnim_Draw_Flags0[j];
+ bytewise_extended_oam[oam - oam_buf] = (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++) {
+ oam->x = info.x + kAgahnim_Draw_X1[g * 2 + i];
+ oam->y = info.y + kAgahnim_Draw_Y1[g * 2 + i];
+ oam->charnum = kAgahnim_Draw_Char1[g];
+ oam->flags = flags;
+ bytewise_extended_oam[oam - oam_buf] = kAgahnim_Draw_Ext1[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)) {
+ AgahnimBalls_DamageAgahnim(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() { // 9edccf
+ static const int8 kSpawnBee_XY[8] = {8, 2, -2, -8, 10, 5, -5, -10};
+
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamically(0, 0xb2, &info), i;
+ 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);
+
+ uint8 t = (&link_item_bow)[hud_cur_item - 1];
+ if (link_bottle_info[t - 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.x = link_y_coord + (GetRandomNumber() & 3) * 5;
+ }
+ if ((k ^ frame_counter) & 7)
+ return;
+ ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, pt2.x, pt2.y, 32);
+ 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);
+ 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[k] & 0x80)) {
+ if (sprite_floor[k] != sprite_floor[j] || sprite_flags4[j] & 0x40 || sprite_ignore_projectile[j])
+ continue;
+ } else {
+ if (!sprite_head_dir[j] || !(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 != 15 || !(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 != 15 || !(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 && savegame_tagalong == 0)
+ sprite_ai_state[k] = 1;
+ } else {
+ sprite_state[k] = 0;
+ savegame_tagalong = 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 {
+ savegame_tagalong = 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;
+ savegame_tagalong = 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;
+ savegame_tagalong = 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();
+ savegame_tagalong = 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
+ 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
+ savegame_tagalong = 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
+ static const uint16 kOldMountainManMsgs[3] = {0x9e, 0x9f, 0xa0};
+ 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), j;
+ 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_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/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_MovableMantleTrampoline(int k);
+void Sprite_GoodOrBadArcheryTarget(int k);
+void ChainBallTrooper_Draw(int k);
+void Sprite_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_bounce(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_UsainBolt(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_Mushroom(int k);
+void Sprite_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_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_bounce(int k);
+void SpritePrep_Lanmolas_bounce(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_Moldorm_bounce(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_bounce(int k);
+void SpritePrep_UncleAndPriest_bounce(int k);
+void SpritePrep_OldMan_bounce(int k);
+void Sprite_TutorialGuardOrBarrier_bounce(int k);
+void Sprite_F2_MedallionTablet_bounce(int k);
+void Sprite_33_RupeePull_bounce(int k);
+void Sprite_14_ThievesTownGrate_bounce(int k);
+void SpritePrep_Snitch_bounce_2(int k);
+void SpritePrep_Snitch_bounce_3(int k);
+void Sprite_37_Waterfall_bounce(int k);
+void Sprite_38_EyeStatue_bounce(int k);
+void Sprite_3A_MagicBat_bounce(int k);
+void SpritePrep_Zelda_bounce(int k);
+void Sprite_78_MrsSahasrahla_bounce(int k);
+void Sprite_16_Elder_bounce(int k);
+void SpritePrep_HeartPiece(int k);
+void Sprite_2D_TelepathicTile_bounce(int k);
+void Sprite_25_TalkingTree_bounce(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();
+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_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/tables/.gitignore
@@ -1,0 +1,10 @@
+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
\ No newline at end of file
--- /dev/null
+++ b/tables/compile_music.py
@@ -1,0 +1,451 @@
+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, f):
+ 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)
+
+ util.print_int_array('kSoundBank_%s' % song, r, 'uint8', False, 32, file = f)
+
+ if not compare_with_orig(serializer, song):
+ raise Exception('compare failed')
+
+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/tables/compile_resources.py
@@ -1,0 +1,816 @@
+import sys
+import text_compression
+import util
+from PIL import Image
+import yaml
+import tables
+import compile_music
+
+print_int_array = util.print_int_array
+
+PATH = ''
+
+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()}
+
+def print_map32_to_map16():
+ f = open(PATH+'generated_map32_to_map16.h', 'w')
+ tab = {}
+ for line in open(PATH + '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]))
+
+ print_int_array('kMap32ToMap16_0', res[0], 'uint8', True, 16, file = f)
+ print_int_array('kMap32ToMap16_1', res[1], 'uint8', True, 16, file = f)
+ print_int_array('kMap32ToMap16_2', res[2], 'uint8', True, 16, file = f)
+ print_int_array('kMap32ToMap16_3', res[3], 'uint8', True, 16, file = f)
+ f.close()
+
+def print_dialogue():
+ f = open(PATH+'generated_dialogue.h', 'w')
+ new_r = []
+ offs = []
+ for line in open(PATH + 'dialogue.txt'):
+ line = line.strip('\n')
+ a, b = line.split(': ', 1)
+ index = int(a)
+ offs.append(len(new_r))
+ r = text_compression.compress_string(b)
+ new_r.extend(r)
+
+ print_int_array('kDialogueOffs', offs, 'uint16', True, 16, file = f)
+ print_int_array('kDialogueText', new_r, 'uint8', True, 16, file = f)
+ f.close()
+
+ROM = util.LoadedRom()
+
+
+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,
+]
+
+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
+
+def print_images():
+ rall = []
+ f = open(PATH+'generated_images.h', 'w')
+ for i in range(12):
+ r = ROM.get_bytes(kCompSpritePtrs[i], 0x600)
+ rall.append('kSprGfx_%d' % i)
+ print_int_array('kSprGfx_%d' % i, r, 'uint8', True, 64, file = f)
+
+ for i in range(12, 108):
+ decomp, comp_len = util.decomp(kCompSpritePtrs[i], ROM.get_byte, False, True)
+ r = ROM.get_bytes(kCompSpritePtrs[i], comp_len)
+
+ #print('%d: %d -> %d' % (i, len(compress_store(decomp)), comp_len))
+ rall.append('kSprGfx_%d' % i)
+ print_int_array('kSprGfx_%d' % i, r, 'uint8', True, 64, file = f)
+
+ print_int_array('kSprGfx', rall, 'uint8 *const', None, 8, file = f)
+
+ rall = []
+ for i in range(len(kCompBgPtrs)):
+ decomp, comp_len = util.decomp(kCompBgPtrs[i], ROM.get_byte, False, True)
+ r = ROM.get_bytes(kCompBgPtrs[i], comp_len)
+
+ #print('%d: %d -> %d' % (i, len(compress_store(decomp)), comp_len))
+ rall.append('kBgGfx_%d' % i)
+ print_int_array('kBgGfx_%d' % i, r, 'uint8', True, 64, file = f)
+
+ print_int_array('kBgGfx', rall, 'uint8 *const', None, 8, file = f)
+
+ f.close()
+
+
+def print_misc():
+ f = open(PATH+'generated_overworld_map.h', 'w')
+ print_int_array('kOverworldMapGfx', ROM.get_bytes(0x18c000, 0x4000), 'uint8', True, 64, file = f)
+ print_int_array('kLightOverworldTilemap', ROM.get_bytes(0xac727, 4096), 'uint8', True, 64, file = f)
+ print_int_array('kDarkOverworldTilemap', ROM.get_bytes(0xaD727, 1024), 'uint8', True, 64, file = f)
+ f.close()
+
+ f = open(PATH+'generated_predefined_tiles.h', 'w')
+ print_int_array('kPredefinedTileData', ROM.get_words(0x9B52, 6438), 'uint16', False, 16, file = f)
+ f.close()
+
+ f = open(PATH+'generated_font.h', 'w')
+ print_int_array('kFontData', ROM.get_words(0xe8000, 2048), 'uint16', False, 16, file = f)
+ f.close()
+
+ f = open(PATH+'generated_map16_to_map8.h', 'w')
+ print_int_array('kMap16ToMap8', ROM.get_words(0x8f8000, 3752 * 4), 'uint16', False, 16, file = f)
+ f.close()
+
+ f = open(PATH+'generated_ancilla.h', 'w')
+ print_int_array('kGeneratedWishPondItem', ROM.get_bytes(0x888450, 256), 'uint8', False, 16, file = f)
+ print_int_array('kGeneratedBombosArr', ROM.get_bytes(0x8890FC, 256), 'uint8', False, 16, file = f)
+ f.close()
+
+ f = open(PATH+'generated_ending.h', 'w')
+ print_int_array('kGeneratedEndSequence15', ROM.get_bytes(0x8ead25, 256), 'uint8', False, 16, file = f)
+ print_int_array('kEnding_Credits_Text', ROM.get_bytes(0x8EB178, 1989), 'uint8', False, 16, file = f)
+ print_int_array('kEnding_Credits_Offs', ROM.get_words(0x8EB93d, 394), 'uint16', False, 16, file = f)
+ print_int_array('kEnding_MapData', ROM.get_words(0x8EB038, 160), 'uint16', False, 16, file = f)
+ print_int_array('kEnding0_Offs', ROM.get_words(0x8EC2E1, 17), 'uint16', False, 16, file = f)
+ print_int_array('kEnding0_Data', ROM.get_bytes(0x8EBF4C, 917), 'uint8', False, 16, file = f)
+ f.close()
+
+ f = open(PATH+'generated_palettes.h', 'w')
+ print_int_array('kPalette_DungBgMain', ROM.get_words(0x9BD734, 1800), 'uint16', False, 15, file = f)
+ print_int_array('kPalette_MainSpr', ROM.get_words(0x9BD218, 120), 'uint16', False, 15, file = f)
+
+ print_int_array('kPalette_ArmorAndGloves', ROM.get_words(0x9BD308, 75), 'uint16', False, 15, file = f)
+ print_int_array('kPalette_Sword', ROM.get_words(0x9BD630, 12), 'uint16', False, 3, file = f)
+ print_int_array('kPalette_Shield', ROM.get_words(0x9BD648, 12), 'uint16', False, 4, file = f)
+
+ print_int_array('kPalette_SpriteAux3', ROM.get_words(0x9BD39E, 84), 'uint16', False, 7, file = f)
+ print_int_array('kPalette_MiscSprite_Indoors', ROM.get_words(0x9BD446, 77), 'uint16', False, 7, file = f)
+ print_int_array('kPalette_SpriteAux1', ROM.get_words(0x9BD4E0, 168), 'uint16', False, 7, file = f)
+
+ print_int_array('kPalette_OverworldBgMain', ROM.get_words(0x9BE6C8, 210), 'uint16', False, 7, file = f)
+ print_int_array('kPalette_OverworldBgAux12', ROM.get_words(0x9BE86C, 420), 'uint16', False, 21, file = f)
+ print_int_array('kPalette_OverworldBgAux3', ROM.get_words(0x9BE604, 98), 'uint16', False, 7, file = f)
+ print_int_array('kPalette_PalaceMapBg', ROM.get_words(0x9BE544, 96), 'uint16', False,16, file = f)
+ print_int_array('kPalette_PalaceMapSpr', ROM.get_words(0x9BD70A, 21), 'uint16', False,7, file = f)
+ print_int_array('kHudPalData', ROM.get_words(0x9BD660, 64), 'uint16', False, 16, file = f)
+
+ print_int_array('kOverworldMapPaletteData', ROM.get_words(0x8ADB27, 256), 'uint16', False, 16, file = f)
+
+ f.close()
+
+g_overworld_yaml_cache = {}
+def load_overworld_yaml(room):
+ if room not in g_overworld_yaml_cache:
+ g_overworld_yaml_cache[room] = yaml.safe_load(open(PATH+'overworld/overworld-%d.yaml' % room, 'r'))
+ return g_overworld_yaml_cache[room]
+
+
+def print_overworld():
+ f = open(PATH+'generated_overworld.h', 'w')
+
+ 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('kOverworld_Hibytes_Comp_%d' % i)
+ print_int_array('kOverworld_Hibytes_Comp_%d' % i, ROM.get_bytes(addr, comp_len), 'uint8', True, 64, file = f)
+ print_int_array('kOverworld_Hibytes_Comp', r, 'uint8 *const', None, 8, file = f)
+
+ 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('kOverworld_Lobytes_Comp_%d' % i)
+ print_int_array('kOverworld_Lobytes_Comp_%d' % i, ROM.get_bytes(addr, comp_len), 'uint8', True, 64, file = f)
+ print_int_array('kOverworld_Lobytes_Comp', r, 'uint8 *const', None, 8, file = f)
+
+ f.close()
+
+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, f):
+ for type, name, arr, items_per_line in self.arrs:
+ for i, j in enumerate(arr):
+ assert isinstance(j, int), (name, i, j, arr)
+ print_int_array(name, arr, type, True, items_per_line, file = f)
+
+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)
+
+ f = open(PATH+'generated_overworld_tables.h', 'w')
+ A.write(f)
+ print_int_array('kMap8DataToTileAttr', ROM.get_bytes(0x8E9459, 512), 'uint8', False, 16, file = f)
+ print_int_array('kSomeTileAttr', ROM.get_bytes(0x9bf110, 3824), 'uint8', False, 16, file = f)
+ f.close()
+
+
+def print_dungeon_map():
+ f = open(PATH+'generated_dungeon_map.h', 'w')
+
+ r, r2 = [], []
+ name = 'kDungMap_FloorLayout'
+ name2 = 'kDungMap_Tiles'
+ 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)
+ r.append('%s_%d' % (name, i))
+ bytes = ROM.get_bytes(addr, kSizes[i])
+ nonzero_bytes = len(bytes) - bytes.count(0xf)
+ print_int_array(r[-1], bytes, 'uint8', False, 25, file = f)
+ addr = 0xa0000 + ROM.get_word(0x8AFBE4 + i * 2)
+ r2.append('%s_%d' % (name2, i))
+ bytes = ROM.get_bytes(addr, nonzero_bytes)
+ print_int_array(r2[-1], bytes, 'uint8', False, 25, file = f)
+
+ print_int_array(name, r, 'uint8 *const', None, 4, file = f)
+ print_int_array(name2, r2, 'uint8 *const', None, 4, file = f)
+ f.close()
+
+
+
+g_dungeon_yaml_cache = {}
+def load_dungeon_yaml(room):
+ if room not in g_dungeon_yaml_cache:
+ g_dungeon_yaml_cache[room] = yaml.safe_load(open(PATH+'dungeon/dungeon-%d.yaml' % room, 'r'))
+ return g_dungeon_yaml_cache[room]
+
+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)
+ f = open(PATH+'generated_dungeon_sprites.h', 'w')
+ print_int_array('kDungeonSprites', data, 'uint8', True, 16, file = f)
+ print_int_array('kDungeonSpriteOffs', offsets, 'uint16', True, 16, file=f)
+ f.close()
+
+def print_dungeon_secrets_to_file(f):
+ 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
+ print_int_array('kDungeonSecrets', result, 'uint8', True, 16, file = f)
+
+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(f, 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
+
+ print_int_array(prefix+'rooms', [a['room'] for a in entrances], 'uint16', True, 16, file = f)
+ print_int_array(prefix+'relativeCoords', flatten([get_rc(a) for a in entrances]), 'uint8', True, 16, file = f)
+ def get_base_x(a): return ((a['room'] & 0x00f) << 9)
+ def get_base_y(a): return ((a['room'] & 0x1f0) << 5)
+ print_int_array(prefix+'scrollX', [a['scroll_xy'][0] + get_base_x(a) for a in entrances], 'uint16', True, 16, file = f)
+ print_int_array(prefix+'scrollY', [a['scroll_xy'][1] + get_base_y(a) for a in entrances], 'uint16', True, 16, file = f)
+ print_int_array(prefix+'playerX', [a['player_xy'][0] + get_base_x(a) for a in entrances], 'uint16', True, 16, file = f)
+ print_int_array(prefix+'playerY', [a['player_xy'][1] + get_base_y(a) for a in entrances], 'uint16', True, 16, file = f)
+ print_int_array(prefix+'cameraX', [a['camera_xy'][0] for a in entrances], 'uint16', True, 16, file = f)
+ print_int_array(prefix+'cameraY', [a['camera_xy'][1] for a in entrances], 'uint16', True, 16, file = f)
+ print_int_array(prefix+'blockset', [a['blockset'] for a in entrances], 'uint8', True, 16, file = f)
+ print_int_array(prefix+'floor', [a['floor'] for a in entrances], 'int8', True, 16, file = f)
+ print_int_array(prefix+'palace', [get_palace(a['palace']) for a in entrances], 'int8', True, 16, file = f)
+ print_int_array(prefix+'doorwayOrientation', [a['doorway_orientation'] for a in entrances], 'uint8', True, 16, file = f)
+ print_int_array(prefix+'startingBg', [a['plane'] + a['ladder_level'] * 16 for a in entrances], 'uint8', True, 16, file = f)
+ print_int_array(prefix+'quadrant1', [get_quadrant1(a['quadrants']) for a in entrances], 'uint8', True, 16, file = f)
+ print_int_array(prefix+'quadrant2', [get_quadrant2(a['quadrants']) for a in entrances], 'uint8', True, 16, file = f)
+ print_int_array(prefix+'doorSettings', [get_exit_door(a['house_exit_door']) for a in entrances], 'uint16', True, 16, file = f)
+ if prefix == 'kStartingPoint_':
+ print_int_array(prefix+'entrance', [a['associated_entrance_index'] for a in entrances], 'uint8', True, 16, file = f)
+ m = invert_dict(tables.kMusicNames)
+ print_int_array(prefix+'musicTrack', [m[a['music']] for a in entrances], 'uint8', True, 16, file = f)
+
+
+ f = open(PATH+'generated_dungeon_rooms.h', 'w')
+ print_int_array('kDungeonRoom', data, 'uint8', True, 16, file = f)
+ print_int_array('kDungeonRoomOffs', offsets, 'uint16', True, 16, file = f)
+ print_int_array('kDungeonRoomDoorOffs', door_offsets, 'uint16', True, 16, file = f)
+ print_int_array('kDungeonRoomHeaders', room_headers, 'uint8', True, 16, file = f)
+ print_int_array('kDungeonRoomHeadersOffs', header_offsets, 'uint16', True, 16, file = f)
+ print_int_array('kDungeonRoomChests', chests, 'uint8', True, 16, file = f)
+ print_int_array('kDungeonRoomTeleMsg', sign_texts, 'uint16', True, 16, file = f)
+ print_int_array('kDungeonPitsHurtPlayer', pits_hurt_player, 'uint16', True, 16, file = f)
+
+ print_entrance_info(f, entrances, 'kEntranceData_')
+ print_entrance_info(f, starting_points, 'kStartingPoint_')
+
+ data = []
+ offsets = [0] * 8
+ default_yaml = yaml.safe_load(open(PATH+'dungeon/default_rooms.yaml', 'r'))
+ for i in range(len(offsets)):
+ offsets[i] = len(data)
+ print_layer(default_yaml['Default%d' % i], None)
+ print_int_array('kDungeonRoomDefault', data, 'uint8', True, 16, file = f)
+ print_int_array('kDungeonRoomDefaultOffs', offsets, 'uint16', True, 16, file = f)
+
+ data = []
+ offsets = [0] * 19
+ overlay_yaml = yaml.safe_load(open(PATH+'dungeon/overlay_rooms.yaml', 'r'))
+ for i in range(len(offsets)):
+ offsets[i] = len(data)
+ print_layer(overlay_yaml['Overlay%d' % i], None)
+ print_int_array('kDungeonRoomOverlay', data, 'uint8', True, 16, file = f)
+ print_int_array('kDungeonRoomOverlayOffs', offsets, 'uint16', True, 16, file = f)
+
+ print_dungeon_secrets_to_file(f)
+
+ print_int_array('kDungAttrsForTile_Offs', ROM.get_words(0x8e9000, 21), 'uint16', False, 16, file = f)
+ print_int_array('kDungAttrsForTile', ROM.get_bytes(0x8e902a, 1024), 'uint8', False, 16, file = f)
+
+ print_int_array('kMovableBlockDataInit', ROM.get_words(0x84f1de, 198), 'uint16', False, 16, file = f)
+ print_int_array('kTorchDataInit', ROM.get_words(0x84F36A, 144), 'uint16', False, 16, file = f)
+ print_int_array('kTorchDataJunk', ROM.get_words(0x84F48a, 48), 'uint16', False, 16, file = f)
+
+ f.close()
+
+
+
+def print_enemy_damage_data():
+ f = open(PATH+'generated_enemy_damage_data.h', 'w')
+ decomp, comp_len = util.decomp(0x83e800, ROM.get_byte, True, True)
+ print_int_array('kEnemyDamageData', decomp, 'uint8', False, 32, file = f)
+ f.close()
+
+def print_tilemaps():
+ f = open(PATH+'generated_bg_tilemaps.h', 'w')
+ 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)
+ print_int_array('kBgTilemap_%d' % i, ROM.get_bytes(s, l), 'uint8', False, 32, file = f)
+ f.close()
+
+def print_link_graphics():
+ f = open(PATH+'generated_link_graphics.h', 'w')
+ image = Image.open(PATH+'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)
+ print_int_array('kLinkGraphics', b, 'uint8', False, 32, file = f)
+ #print(list(encode_4bit_sprite(data, 0, 128)))
+ f.close()
+
+def print_sound_banks():
+ f = open(PATH+'generated_sound_banks.h', 'w')
+ for song in ['intro', 'indoor', 'ending']:
+ compile_music.print_song(song, f)
+ f.close()
+
+
+
+def print_all():
+ print_sound_banks()
+ print_dungeon_rooms()
+ print_enemy_damage_data()
+ print_link_graphics()
+ print_dungeon_sprites()
+ print_map32_to_map16()
+ print_dialogue()
+ print_images()
+ print_misc()
+ print_dungeon_map()
+ print_tilemaps()
+ print_overworld()
+ print_overworld_tables()
+
+print_all()
+
--- /dev/null
+++ b/tables/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()
+ song = sys.argv[1]
+
+ load_song(ROM, song)
+ print_song(song, sys.stdout)
+
--- /dev/null
+++ b/tables/extract_music.py
@@ -1,0 +1,467 @@
+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__":
+ ROM = util.LoadedRom()
+ song = sys.argv[1]
+
+ load_song(ROM, song)
+ print_song(song, sys.stdout)
+
--- /dev/null
+++ b/tables/extract_resources.py
@@ -1,0 +1,667 @@
+from ast import literal_eval as make_tuple
+import sys
+import text_compression
+import util
+from PIL import Image
+import tables
+import yaml
+import extract_music
+import os
+
+PATH=''
+
+ROM = util.LoadedRom()
+
+get_byte = ROM.get_byte
+get_word = ROM.get_word
+get_bytes = ROM.get_bytes
+
+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 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)
+
+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
+EXIT_DATAS = get_exit_datas()
+
+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 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
+OW_TRAVEL_INFOS = get_ow_travel_infos()
+
+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
+OW_ENTRANCE_INFO = get_ow_entrance_info()
+
+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
+HOLE_INFO = get_hole_infos()
+
+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'] = OW_TRAVEL_INFOS.get(overworld_area, [])
+ y['Entrances'] = OW_ENTRANCE_INFO.get(overworld_area, [])
+ if overworld_area in HOLE_INFO:
+ y['Holes'] = HOLE_INFO[overworld_area]
+ y['Exits'] = 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(PATH+'overworld/overworld-%d.yaml' % overworld_area, 'w').write(s)
+
+def print_all_overworld_areas():
+ area_heads = ROM.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(open('dialogue.txt', 'w'), get_byte)
+
+def decomp_one_spr_2bit(data, offs, target, toffs, pitch):
+ 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 * 255 // 3
+
+def decomp_one_spr_3bit(data, offs, target, toffs, pitch):
+ 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
+ target[toffs + y * pitch + (7 - x)] = t * 255 // 7
+
+def decomp_one_spr_4bit(data, offs, target, toffs, pitch):
+ 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
+ target[toffs + y * pitch + (7 - x)] = t
+
+def save_array_as_image(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 decomp_save(data, fname, func, step, height=32, palette=None):
+ dst=[0]*128*height
+ for i in range(16*height//8):
+ x = i % 16
+ y = i // 16
+ func(data, i * step, dst, x * 8 + y * 8 * 128, 128)
+ save_array_as_image((128, height), dst, fname, palette)
+
+def convert_snes_palette(v):
+ r=[]
+ for x in v:
+ r.extend(((x & 0x1f) << 3, (x >> 5 & 0x1f) << 3, (x >> 10 & 0x1f) << 3))
+ return r
+
+
+def decode_link_sprites():
+ kLinkPalette = [0, 0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5, 0x1ff, 0x1078, 0x599d, 0x3647, 0x3b68, 0xa4a, 0x12ef, 0x2a5c, 0x1571, 0x7a18]
+ decomp_save(get_bytes(0x108000, 32768), PATH+'linksprite.png',
+ decomp_one_spr_4bit, 32, 448, convert_snes_palette(kLinkPalette))
+
+def decomp_save_2bit(data, fname):
+ dst=[0]*128*64
+ for i in range(128):
+ x = i % 16
+ y = i // 16
+ decomp_one_spr_2bit(data, i * 16, dst, x * 8 + y * 8 * 128, 128)
+ img = Image.new("L", (128, 64))
+ img.putdata(dst)
+ img.save(fname)
+
+
+gfx_desc = {
+ 0x00 : ('3bpp_np', 'Half slot images'),
+
+ 0x01 : ('3bpp_np', 'Half slot images'),
+ 0x02 : ('3bpp_np', 'Half slot images'),
+ 0x03 : ('3bpp_np', 'Half slot images'),
+ 0x04 : ('3bpp_np', 'Half slot images'),
+ 0x05 : ('3bpp_np', 'Half slot images'),
+
+ 0x06 : ('3bpp_np', 'common spr gfx'),
+ 0x07 : ('3bpp_np', 'common spr gfx'),
+
+ 0x08 : ('3bpp_np', 'Half slot images'),
+ 0x09 : ('3bpp_np', 'Half slot images'),
+ 0x0a : ('3bpp_np', 'Half slot images'),
+ 0x0b : ('3bpp_np', 'Half slot images'),
+
+ 88 : ('3bpp', 'Tagalong gfx'),
+ 89 : ('3bpp', 'Tagalong gfx'),
+
+ 90 : ('3bpp', 'animated sprites'),
+ 91 : ('3bpp', 'animated sprites'),
+ 92 : ('3bpp', 'animated sprites'),
+ 93 : ('3bpp', 'animated sprites'),
+ 94 : ('3bpp', 'sword/shield gfx'),
+ 95 : ('3bpp', 'sword/shield gfx'),
+
+
+ 100 : ('3bpp', 'Tagalong gfx'),
+ 101 : ('3bpp', 'Tagalong gfx'),
+ 102 : ('3bpp', 'Tagalong gfx'),
+
+ 103 : ('2bpp', 'Attract images loaded to 7800'),
+ 104 : ('2bpp', 'empty'),
+ 105 : ('2bpp', 'hud icons loaded to 7xxx'),
+ 106 : ('2bpp', 'hud icons loaded to 7xxx'),
+ 107 : ('2bpp', 'hud icons loaded to 7xxx'),
+}
+
+def decomp_generic(k, mode, fname_add = "misc"):
+ fname = 'img/%.3d - %s.png' % (k, fname_add)
+ if mode == '2bpp':
+ r = util.decomp(kCompSpritePtrs[k], get_byte, False)
+ decomp_save_2bit(r, fname)
+ elif mode == '3bpp_np':
+ print(k)
+ r = get_bytes(kCompSpritePtrs[k], 0x600)
+ decomp_save(r, fname, decomp_one_spr_3bit, 24)
+ elif mode== '3bpp':
+ r = util.decomp(kCompSpritePtrs[k], get_byte, False)
+ decomp_save(r, fname, decomp_one_spr_3bit, 24)
+ else:
+ assert 0
+
+if 0:
+ for k, v in gfx_desc.items():
+ decomp_generic(k, v[0])
+
+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
+
+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
+
+CHEST_INFO = get_chest_info()
+
+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
+
+
+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
+
+ENTRANCE_INFO = get_entrance_info(0)
+STARTING_POINT_INFO = get_entrance_info(1)
+PITS_HURT_PLAYER = 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 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'] = ENTRANCE_INFO.get(room_index, [])
+ if room_index in STARTING_POINT_INFO:
+ data['StartingPoints'] = STARTING_POINT_INFO[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(PATH + '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(PATH + '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(PATH + 'dungeon/overlay_rooms.yaml', 'w').write(s)
+
+def print_all():
+ os.makedirs('img', exist_ok=True)
+ os.makedirs('overworld', exist_ok=True)
+ os.makedirs('dungeon', exist_ok=True)
+ os.makedirs('sound', exist_ok=True)
+ print_all_overworld_areas()
+ decode_link_sprites()
+ print_all_dungeon_rooms()
+ print_overlay_rooms()
+ print_default_rooms()
+ print_dialogue()
+ print_map32_to_map16(open(PATH+'map32_to_map16.txt', 'w'))
+ extract_music.extract_sound_data(ROM)
+
+
+print_all()
--- /dev/null
+++ b/tables/tables.py
@@ -1,0 +1,882 @@
+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)
--- /dev/null
+++ b/tables/text_compression.py
@@ -1,0 +1,255 @@
+
+kTextAlphabet = [
+ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
+ "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
+
+ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
+ "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
+
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+
+ # codes 0x3E and up
+ "!", "?", "-", ".", ",",
+
+ # codes 0x43 and up
+ "[...]", ">", "(", ")",
+
+ # codes 0x47 and up
+ "[Ankh]", "[Waves]", "[Snake]", "[LinkL]", "[LinkR]",
+ "\"", "[Up]", "[Down]", "[Left]", "[Right]", "'",
+
+ # codes 0x52 and up
+ "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]",
+ "[3HeartR]", "[4HeartL]", "[4HeartR]",
+
+ " ", "<", "[A]", "[B]", "[X]", "[Y]",
+]
+
+kText_CommandLengths = [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 = [
+ "NextPic",
+ "Choose",
+ "Item",
+ "Name",
+ "Window",
+ "Number",
+ "Position",
+ "ScrollSpd",
+ "Selchg",
+ "Crash",
+ "Choose3",
+ "Choose2",
+ "Scroll",
+ "1",
+ "2",
+ "3",
+ "Color",
+ "Wait",
+ "Sound",
+ "Speed",
+ "Mark",
+ "Mark2",
+ "Clear",
+ "Waitkey",
+ "EndMessage"
+]
+
+kTextDictionary = [ 0x59, 0x59, 0x59, 0x59,
+ 0x59, 0x59, 0x59,
+ 0x59, 0x59,
+ 0x51, 0x2c, 0x59,
+ 0x1a, 0x27, 0x1d, 0x59,
+ 0x1a, 0x2b, 0x1e, 0x59,
+ 0x1a, 0x25, 0x25, 0x59,
+ 0x1a, 0x22, 0x27,
+ 0x1a, 0x27, 0x1d,
+ 0x1a, 0x2d, 0x59,
+ 0x1a, 0x2c, 0x2d,
+ 0x1a, 0x27,
+ 0x1a, 0x2d,
+ 0x1b, 0x25, 0x1e,
+ 0x1b, 0x1a,
+ 0x1b, 0x1e,
+ 0x1b, 0x28,
+ 0x1c, 0x1a, 0x27, 0x59,
+ 0x1c, 0x21, 0x1e,
+ 0x1c, 0x28, 0x26,
+ 0x1c, 0x24,
+ 0x1d, 0x1e, 0x2c,
+ 0x1d, 0x22,
+ 0x1d, 0x28,
+ 0x1e, 0x27, 0x59,
+ 0x1e, 0x2b, 0x59,
+ 0x1e, 0x1a, 0x2b,
+ 0x1e, 0x27, 0x2d,
+ 0x1e, 0x1d, 0x59,
+ 0x1e, 0x27,
+ 0x1e, 0x2b,
+ 0x1e, 0x2f,
+ 0x1f, 0x28, 0x2b,
+ 0x1f, 0x2b, 0x28,
+ 0x20, 0x22, 0x2f, 0x1e, 0x59,
+ 0x20, 0x1e, 0x2d,
+ 0x20, 0x28,
+ 0x21, 0x1a, 0x2f, 0x1e,
+ 0x21, 0x1a, 0x2c,
+ 0x21, 0x1e, 0x2b,
+ 0x21, 0x22,
+ 0x21, 0x1a,
+ 0x22, 0x20, 0x21, 0x2d, 0x59,
+ 0x22, 0x27, 0x20, 0x59,
+ 0x22, 0x27,
+ 0x22, 0x2c,
+ 0x22, 0x2d,
+ 0x23, 0x2e, 0x2c, 0x2d,
+ 0x24, 0x27, 0x28, 0x30,
+ 0x25, 0x32, 0x59,
+ 0x25, 0x1a,
+ 0x25, 0x28,
+ 0x26, 0x1a, 0x27,
+ 0x26, 0x1a,
+ 0x26, 0x1e,
+ 0x26, 0x2e,
+ 0x27, 0x51, 0x2d, 0x59,
+ 0x27, 0x28, 0x27,
+ 0x27, 0x28, 0x2d,
+ 0x28, 0x29, 0x1e, 0x27,
+ 0x28, 0x2e, 0x27, 0x1d,
+ 0x28, 0x2e, 0x2d, 0x59,
+ 0x28, 0x1f,
+ 0x28, 0x27,
+ 0x28, 0x2b,
+ 0x29, 0x1e, 0x2b,
+ 0x29, 0x25, 0x1e,
+ 0x29, 0x28, 0x30,
+ 0x29, 0x2b, 0x28,
+ 0x2b, 0x1e, 0x59,
+ 0x2b, 0x1e,
+ 0x2c, 0x28, 0x26, 0x1e,
+ 0x2c, 0x1e,
+ 0x2c, 0x21,
+ 0x2c, 0x28,
+ 0x2c, 0x2d,
+ 0x2d, 0x1e, 0x2b, 0x59,
+ 0x2d, 0x21, 0x22, 0x27,
+ 0x2d, 0x1e, 0x2b,
+ 0x2d, 0x21, 0x1a,
+ 0x2d, 0x21, 0x1e,
+ 0x2d, 0x21, 0x22,
+ 0x2d, 0x28,
+ 0x2d, 0x2b,
+ 0x2e, 0x29,
+ 0x2f, 0x1e, 0x2b,
+ 0x30, 0x22, 0x2d, 0x21,
+ 0x30, 0x1a,
+ 0x30, 0x1e,
+ 0x30, 0x21,
+ 0x30, 0x22,
+ 0x32, 0x28, 0x2e,
+ 0x7, 0x1e, 0x2b,
+ 0x13, 0x21, 0x1a,
+ 0x13, 0x21, 0x1e,
+ 0x13, 0x21, 0x22,
+ 0x18, 0x28, 0x2e,
+]
+
+kTextDictionary_Idx = [
+ 0, 4, 7, 9, 12, 16, 20, 24, 27, 30, 33, 36, 38, 40, 43, 45, 47, 49, 53, 56, 59, 61, 64, 66, 68, 71, 74, 77, 80, 83, 85, 87, 89, 92, 95, 100, 103, 105, 109, 112, 115, 117, 119, 124, 128, 130, 132, 134, 138, 142, 145, 147, 149, 152, 154, 156, 158, 162, 165, 168, 172, 176, 180, 182, 184, 186, 189, 192, 195, 198, 201, 203, 207, 209, 211, 213, 215, 219, 223, 226, 229, 232, 235, 237, 239, 241, 244, 248, 250, 252, 254, 256, 259, 262, 265, 268, 271, 274
+]
+
+def make_dict():
+ r, rinv = {}, {}
+ for i in range(len(kTextDictionary_Idx) - 1):
+ ln = kTextDictionary_Idx[i + 1] - kTextDictionary_Idx[i]
+ idx = kTextDictionary_Idx[i]
+ s = "".join(kTextAlphabet[kTextDictionary[idx+i]] for i in range(ln))
+ r[i] = s
+ rinv[s] = i
+ return r, rinv
+
+kTextDictionary_Ascii, kTextDictionary_AsciiBack = make_dict()
+
+def decode_strings(get_byte):
+ p = 0x9c8000
+ result = []
+ while True:
+ org_p = p
+ #print('0x%x' % p)
+ s = ''
+ srcdata = []
+ while True:
+ c = get_byte(p)
+ srcdata.append(c)
+ l = kText_CommandLengths[c - 0x67] if c >= 0x67 and c < 0x80 else 1
+ p += l
+ if c == 0x7f:
+ break
+ if c < 0x67:
+ s += kTextAlphabet[c]
+ elif c < 0x80:
+ if l == 2:
+ srcdata.append(get_byte(p-1))
+ s += '[%s %.2d]' % (kText_CommandNames[c - 0x67], get_byte(p-1))
+ else:
+ s += '[%s]' % kText_CommandNames[c - 0x67]
+ elif c == 0x80:
+ p = 0x8edf40
+ s = None
+ break
+ elif c > 0x80 and c < 0x88:
+ assert 0
+ elif c == 0xff:
+ return result
+ else:
+ s += kTextDictionary_Ascii[c - 0x88]
+ if s != None:
+ result.append((s, srcdata))
+
+def print_strings(f, get_byte):
+ for i, s in enumerate(decode_strings(get_byte)):
+ print('%s: %s' % (i + 1, s[0]), file = f)
+
+def find_string_char_at(s, i):
+ a = s[i:]
+
+ for k, v in kTextDictionary_AsciiBack.items():
+ if a.startswith(k):
+ return [v + 0x88], len(k)
+
+ for i, s in enumerate(kTextAlphabet):
+ if a.startswith(s):
+ return [i], len(s)
+
+ if a.startswith('['):
+ cmd = a[1:a.index(']')]
+ if cmd in kText_CommandNames:
+ i = kText_CommandNames.index(cmd)
+ return [i + 0x67], len(cmd) + 2
+
+ for i, s in enumerate(kText_CommandNames):
+ if kText_CommandLengths[i] == 2 and cmd.startswith(s):
+ e = cmd[len(s):].strip()
+ return [i + 0x67, int(e)], len(cmd) + 2
+
+ print('substr %s not found' % a)
+ assert 0
+
+def compress_string(s):
+ # find the greedy best match
+ i = 0
+ r = []
+ while i < len(s):
+ what, num = find_string_char_at(s, i)
+ r.extend(what)
+ i += num
+ r.append(0x7f)
+ return r
+
+def verify(get_byte):
+ for i, (decoded, original) in enumerate(decode_strings(get_byte)):
+ c = compress_string(decoded)
+ if c != original:
+ print('String %s not match: %s, %s' % (decoded, c, original))
+ break
+ else:
+ pass
--- /dev/null
+++ b/tables/util.py
@@ -1,0 +1,240 @@
+import array
+import sys
+import hashlib
+
+class LoadedRom:
+ def __init__(self, name = 'zelda3.sfc'):
+ self.ROM = open(name, 'rb').read()
+ hash = hashlib.sha256(self.ROM).hexdigest()
+ if hash != '66871d66be19ad2c34c927d6b14cd8eb6fc3181965b6e517cb361f7316009cfb':
+ raise Exception('Wrong ROM version. Expecting Legend of Zelda - A Link to the Past, The (NA) (1.0).sfc')
+
+ 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 = []
+ 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 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
+
--- /dev/null
+++ b/tagalong.cpp
@@ -1,0 +1,745 @@
+#include "tagalong.h"
+#include "sprite_main.h"
+#include "sprite.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "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};
+struct TagalongSprXY {
+ int8 y1, x1, y2, x2;
+};
+struct TagalongDmaFlags {
+ uint8 dma6, dma7;
+ uint8 flags;
+};
+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;
+}
+
+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;
+ super_bomb_going_off = 0;
+ Follower_MoveTowardsLink();
+}
+
+void Follower_Main() { // 899fc4
+ if (!savegame_tagalong)
+ return;
+ if (savegame_tagalong == 0xe) {
+ Follower_HandleTrigger();
+ return;
+ }
+ int j = FindInByteArray(kTagalong_Tab0, savegame_tagalong, 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 (super_bomb_going_off) {
+ Follower_NotFollowing();
+ return;
+ }
+
+ if (savegame_tagalong == 12) {
+ if (link_auxiliary_state != 0)
+ goto label_a;
+
+ } else if (savegame_tagalong == 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 (savegame_tagalong == 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;
+ }
+
+ super_bomb_going_off = 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 (savegame_tagalong) {
+ 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 (savegame_tagalong == 10 && link_auxiliary_state && countdown_for_blink) {
+ int k = tagalong_var2 + 1 == 20 ? 0 : tagalong_var2 + 1;
+ Kiki_SpawnHandler_B(k);
+ savegame_tagalong = 0;
+ return;
+ }
+
+ if (savegame_tagalong == 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;
+ savegame_tagalong = 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) {
+label_e:
+ uint8 t;
+ 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 (savegame_tagalong == 13) {
+ super_bomb_indicator_unk2 = 254;
+ super_bomb_indicator_unk1 = 0;
+ }
+ super_bomb_going_off = 0;
+ Tagalong_Draw();
+ } else {
+ if (savegame_tagalong == 13 && !player_is_indoors && !super_bomb_indicator_unk2) {
+ AncillaAdd_SuperBombExplosion(0x3a, 0);
+ super_bomb_going_off = 0;
+ }
+ 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 (savegame_tagalong == 0) {
+ return;
+ } else if (savegame_tagalong == 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:
+ savegame_tagalong = kTagalong_Tab4[savegame_tagalong];
+ 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();
+ savegame_tagalong = kTagalong_Tab5[savegame_tagalong];
+ return;
+ }
+ }
+ Follower_DoLayers();
+}
+
+void Follower_DoLayers() { // 89a450
+ oam_priority_value = kTagalongFlags[saved_tagalong_floor] << 8;
+ uint8 a = (savegame_tagalong == 12 || savegame_tagalong == 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 == savegame_tagalong && 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) {
+ savegame_tagalong = 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);
+}
+
+void Follower_AnimateMovement_preserved(uint8 ain, uint16 xin, uint16 yin) { // 89a959
+
+ uint8 yt = 0, av = 0;
+ uint8 sc = 0;
+
+ if ((ain >> 2 & 8) && (savegame_tagalong == 6 || savegame_tagalong == 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 (savegame_tagalong == 11) {
+ av = (frame_counter >> 1) & 4;
+ } else if ((savegame_tagalong == 12 || savegame_tagalong == 13) && super_bomb_going_off || 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 (savegame_tagalong == 1 || savegame_tagalong == 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;
+ {
+ uint16 y = scrolly + 16, x = scrollx, ext = 0;
+ oam->x = x;
+ oam->y = (uint16)(x + 0x80) < 0x180 && (ext = x >> 8 & 1, (uint16)(y + 0x10) < 0x100) ? y : 0xf0;
+ oam->charnum = sk[0];
+ oam->flags = sk[1];
+ bytewise_extended_oam[oam - oam_buf] = ext;
+ oam++;
+
+ ext = 0, x += 8;
+ oam->x = x;
+ oam->y = (uint16)(x + 0x80) < 0x180 && (ext = x >> 8 & 1, (uint16)(y + 0x10) < 0x100) ? y : 0xf0;
+ oam->charnum = sk[2];
+ oam->flags = sk[3];
+ bytewise_extended_oam[oam - oam_buf] = ext;
+ oam++;
+ }
+skip_first_sprites:
+
+ uint8 pal = kTagalongDraw_Pals[savegame_tagalong];
+ if (pal == 7 && overworld_palette_swap_flag)
+ pal = 0;
+
+ if (savegame_tagalong == 13 && super_bomb_indicator_unk2 == 1)
+ pal = (frame_counter & 7);
+
+ const TagalongSprXY *sprd = kTagalongDraw_SprXY + frame + (kTagalongDraw_Offs[savegame_tagalong] >> 3);
+ const TagalongDmaFlags *sprf = kTagalongDmaAndFlags + frame;
+
+ if (savegame_tagalong != 12 && savegame_tagalong != 13) {
+ uint16 y = scrolly + sprd->y1, x = scrollx + sprd->x1, ext = 0;
+ oam->x = x;
+ oam->y = (uint16)(x + 0x80) < 0x180 && (ext = x >> 8 & 1, (uint16)(y + 0x10) < 0x100) ? y : 0xf0;
+ oam->charnum = 0x20;
+ oam->flags = (sprf->flags & 0xf0) | pal << 1 | (oam_priority_value >> 8);
+ bytewise_extended_oam[oam - oam_buf] = 2 | ext;
+ oam++;
+ BYTE(dma_var6) = sprf->dma6;
+ }
+ {
+ uint16 y = scrolly + sprd->y2 + 8, x = scrollx + sprd->x2, ext = 0;
+ oam->x = x;
+ oam->y = (uint16)(x + 0x80) < 0x180 && (ext = x >> 8 & 1, (uint16)(y + 0x10) < 0x100) ? y : 0xf0;
+ oam->charnum = 0x22;
+ oam->flags = ((sprf->flags & 0xf) << 4) | pal << 1 | (oam_priority_value >> 8);
+ bytewise_extended_oam[oam - oam_buf] = 2 | ext;
+ 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 (savegame_tagalong == 9 || savegame_tagalong == 10)
+ savegame_tagalong = 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;
+ savegame_tagalong = 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;
+ savegame_tagalong = 0;
+}
+
--- /dev/null
+++ b/tagalong.h
@@ -1,0 +1,32 @@
+#pragma once
+#include "types.h"
+
+struct TagalongMessageInfo {
+ uint16 y, x, bit, msg, tagalong;
+};
+
+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/tile_detect.cpp
@@ -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/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/tracing.cpp
@@ -1,0 +1,208 @@
+
+#define _CRT_SECURE_NO_WARNINGS 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "tracing.h"
+#include "snes/snes.h"
+#include "snes/apu.h"
+
+// name for each opcode, to be filled in with sprintf (length = 14 (13+\0))
+static const char* opcodeNames[256] = {
+ "brk ", "ora ($%02x,x) ", "cop #$%02x ", "ora $%02x,s ", "tsb $%02x ", "ora $%02x ", "asl $%02x ", "ora [$%02x] ", "php ", "ora #$%04x ", "asl ", "phd ", "tsb $%04x ", "ora $%04x ", "asl $%04x ", "ora $%06x ",
+ "bpl $%04x ", "ora ($%02x),y ", "ora ($%02x) ", "ora ($%02x,s),y", "trb $%02x ", "ora $%02x,x ", "asl $%02x,x ", "ora [$%02x],y ", "clc ", "ora $%04x,y ", "inc ", "tcs ", "trb $%04x ", "ora $%04x,x ", "asl $%04x,x ", "ora $%06x,x",
+ "jsr $%04x ", "and ($%02x,x) ", "jsl $%06x ", "and $%02x,s ", "bit $%02x ", "and $%02x ", "rol $%02x ", "and [$%02x] ", "plp ", "and #$%04x ", "rol ", "pld ", "bit $%04x ", "and $%04x ", "rol $%04x ", "and $%06x ",
+ "bmi $%04x ", "and ($%02x),y ", "and ($%02x) ", "and ($%02x,s),y", "bit $%02x,x ", "and $%02x,x ", "rol $%02x,x ", "and [$%02x],y ", "sec ", "and $%04x,y ", "dec ", "tsc ", "bit $%04x,x ", "and $%04x,x ", "rol $%04x,x ", "and $%06x,x",
+ "rti ", "eor ($%02x,x) ", "wdm #$%02x ", "eor $%02x,s ", "mvp $%02x, $%02x ", "eor $%02x ", "lsr $%02x ", "eor [$%02x] ", "pha ", "eor #$%04x ", "lsr ", "phk ", "jmp $%04x ", "eor $%04x ", "lsr $%04x ", "eor $%06x ",
+ "bvc $%04x ", "eor ($%02x),y ", "eor ($%02x) ", "eor ($%02x,s),y", "mvn $%02x, $%02x ", "eor $%02x,x ", "lsr $%02x,x ", "eor [$%02x],y ", "cli ", "eor $%04x,y ", "phy ", "tcd ", "jml $%06x ", "eor $%04x,x ", "lsr $%04x,x ", "eor $%06x,x",
+ "rts ", "adc ($%02x,x) ", "per $%04x ", "adc $%02x,s ", "stz $%02x ", "adc $%02x ", "ror $%02x ", "adc [$%02x] ", "pla ", "adc #$%04x ", "ror ", "rtl ", "jmp ($%04x) ", "adc $%04x ", "ror $%04x ", "adc $%06x ",
+ "bvs $%04x ", "adc ($%02x),y ", "adc ($%02x) ", "adc ($%02x,s),y", "stz $%02x,x ", "adc $%02x,x ", "ror $%02x,x ", "adc [$%02x],y ", "sei ", "adc $%04x,y ", "ply ", "tdc ", "jmp ($%04x,x)", "adc $%04x,x ", "ror $%04x,x ", "adc $%06x,x",
+ "bra $%04x ", "sta ($%02x,x) ", "brl $%04x ", "sta $%02x,s ", "sty $%02x ", "sta $%02x ", "stx $%02x ", "sta [$%02x] ", "dey ", "bit #$%04x ", "txa ", "phb ", "sty $%04x ", "sta $%04x ", "stx $%04x ", "sta $%06x ",
+ "bcc $%04x ", "sta ($%02x),y ", "sta ($%02x) ", "sta ($%02x,s),y", "sty $%02x,x ", "sta $%02x,x ", "stx $%02x,y ", "sta [$%02x],y ", "tya ", "sta $%04x,y ", "txs ", "txy ", "stz $%04x ", "sta $%04x,x ", "stz $%04x,x ", "sta $%06x,x",
+ "ldy #$%04x ", "lda ($%02x,x) ", "ldx #$%04x ", "lda $%02x,s ", "ldy $%02x ", "lda $%02x ", "ldx $%02x ", "lda [$%02x] ", "tay ", "lda #$%04x ", "tax ", "plb ", "ldy $%04x ", "lda $%04x ", "ldx $%04x ", "lda $%06x ",
+ "bcs $%04x ", "lda ($%02x),y ", "lda ($%02x) ", "lda ($%02x,s),y", "ldy $%02x,x ", "lda $%02x,x ", "ldx $%02x,y ", "lda [$%02x],y ", "clv ", "lda $%04x,y ", "tsx ", "tyx ", "ldy $%04x,x ", "lda $%04x,x ", "ldx $%04x,y ", "lda $%06x,x",
+ "cpy #$%04x ", "cmp ($%02x,x) ", "rep #$%02x ", "cmp $%02x,s ", "cpy $%02x ", "cmp $%02x ", "dec $%02x ", "cmp [$%02x] ", "iny ", "cmp #$%04x ", "dex ", "wai ", "cpy $%04x ", "cmp $%04x ", "dec $%04x ", "cmp $%06x ",
+ "bne $%04x ", "cmp ($%02x),y ", "cmp ($%02x) ", "cmp ($%02x,s),y", "pei $%02x ", "cmp $%02x,x ", "dec $%02x,x ", "cmp [$%02x],y ", "cld ", "cmp $%04x,y ", "phx ", "stp ", "jml [$%04x] ", "cmp $%04x,x ", "dec $%04x,x ", "cmp $%06x,x",
+ "cpx #$%04x ", "sbc ($%02x,x) ", "sep #$%02x ", "sbc $%02x,s ", "cpx $%02x ", "sbc $%02x ", "inc $%02x ", "sbc [$%02x] ", "inx ", "sbc #$%04x ", "nop ", "xba ", "cpx $%04x ", "sbc $%04x ", "inc $%04x ", "sbc $%06x ",
+ "beq $%04x ", "sbc ($%02x),y ", "sbc ($%02x) ", "sbc ($%02x,s),y", "pea #$%04x ", "sbc $%02x,x ", "inc $%02x,x ", "sbc [$%02x],y ", "sed ", "sbc $%04x,y ", "plx ", "xce ", "jsr ($%04x,x)", "sbc $%04x,x ", "inc $%04x,x ", "sbc $%06x,x"
+};
+
+// for 8/16 bit immediates
+// TODO: probably a better way to do this...
+static const char* opcodeNamesSp[256] = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "ora #$%02x ", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "and #$%02x ", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "eor #$%02x ", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "adc #$%02x ", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "bit #$%02x ", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "ldy #$%02x ", NULL, "ldx #$%02x ", NULL, NULL, NULL, NULL, NULL, NULL, "lda #$%02x ", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "cpy #$%02x ", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "cmp #$%02x ", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "cpx #$%02x ", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "sbc #$%02x ", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+// address types for each opcode
+static const int opcodeType[256] = {
+ 0, 1, 1, 1, 1, 1, 1, 1, 0, 4, 0, 0, 2, 2, 2, 3,
+ 6, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 0, 2, 2, 2, 3,
+ 2, 1, 3, 1, 1, 1, 1, 1, 0, 4, 0, 0, 2, 2, 2, 3,
+ 6, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 0, 2, 2, 2, 3,
+ 0, 1, 1, 1, 8, 1, 1, 1, 0, 4, 0, 0, 2, 2, 2, 3,
+ 6, 1, 1, 1, 8, 1, 1, 1, 0, 2, 0, 0, 3, 2, 2, 3,
+ 0, 1, 7, 1, 1, 1, 1, 1, 0, 4, 0, 0, 2, 2, 2, 3,
+ 6, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 0, 2, 2, 2, 3,
+ 6, 1, 7, 1, 1, 1, 1, 1, 0, 4, 0, 0, 2, 2, 2, 3,
+ 6, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 0, 2, 2, 2, 3,
+ 5, 1, 5, 1, 1, 1, 1, 1, 0, 4, 0, 0, 2, 2, 2, 3,
+ 6, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 0, 2, 2, 2, 3,
+ 5, 1, 1, 1, 1, 1, 1, 1, 0, 4, 0, 0, 2, 2, 2, 3,
+ 6, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 0, 2, 2, 2, 3,
+ 5, 1, 1, 1, 1, 1, 1, 1, 0, 4, 0, 0, 2, 2, 2, 3,
+ 6, 1, 1, 1, 2, 1, 1, 1, 0, 2, 0, 0, 2, 2, 2, 3
+};
+
+// name for each opcode, for spc
+static const char* opcodeNamesSpc[256] = {
+ "nop ", "tcall 0 ", "set1 $%02x.0 ", "bbs $%02x.0, $%04x ", "or a, $%02x ", "or a, $%04x ", "or a, [X] ", "or a, [$%02x+x] ", "or a, #$%02x ", "or $%02x, $%02x ", "or1 c, $%04x.%01x ", "asl $%02x ", "asl $%04x ", "push p ", "tset $%04x ", "brk ",
+ "bpl $%04x ", "tcall 1 ", "clr1 $%02x.0 ", "bbc $%02x.0, $%04x ", "or a, $%02x+x ", "or a, $%04x+x ", "or a, $%04x+y ", "or a, [$%02x]+y ", "or $%02x, #$%02x ", "or [X], [Y] ", "decw $%02x ", "asl $%02x+x ", "asl a ", "dec x ", "cmp x, $%04x ", "jmp [$%04x+x] ",
+ "clrp ", "tcall 2 ", "set1 $%02x.1 ", "bbs $%02x.1, $%04x ", "and a, $%02x ", "and a, $%04x ", "and a, [X] ", "and a, [$%02x+x] ", "and a, #$%02x ", "and $%02x, $%02x ", "or1 c, /$%04x.%01x ", "rol $%02x ", "rol $%04x ", "push a ", "cbne $%02x, $%04x ", "bra $%04x ",
+ "bmi $%04x ", "tcall 3 ", "clr1 $%02x.1 ", "bbc $%02x.1, $%04x ", "and a, $%02x+x ", "and a, $%04x+x ", "and a, $%04x+y ", "and a, [$%02x]+y ", "and $%02x, #$%02x ", "and [X], [Y] ", "incw $%02x ", "rol $%02x+x ", "rol a ", "inc x ", "cmp x, $%02x ", "call $%04x ",
+ "setp ", "tcall 4 ", "set1 $%02x.2 ", "bbs $%02x.2, $%04x ", "eor a, $%02x ", "eor a, $%04x ", "eor a, [X] ", "eor a, [$%02x+x] ", "eor a, #$%02x ", "eor $%02x, $%02x ", "and1 c, $%04x.%01x ", "lsr $%02x ", "lsr $%04x ", "push x ", "tclr $%04x ", "pcall $%02x ",
+ "bvc $%04x ", "tcall 5 ", "clr1 $%02x.2 ", "bbc $%02x.2, $%04x ", "eor a, $%02x+x ", "eor a, $%04x+x ", "eor a, $%04x+y ", "eor a, [$%02x]+y ", "eor $%02x, #$%02x ", "eor [X], [Y] ", "cmpw ya, $%02x ", "lsr $%02x+x ", "lsr a ", "mov x, a ", "cmp y, $%04x ", "jmp $%04x ",
+ "clrc ", "tcall 6 ", "set1 $%02x.3 ", "bbs $%02x.3, $%04x ", "cmp a, $%02x ", "cmp a, $%04x ", "cmp a, [X] ", "cmp a, [$%02x+x] ", "cmp a, #$%02x ", "cmp $%02x, $%02x ", "and1 c, /$%04x.%01x ", "ror $%02x ", "ror $%04x ", "push y ", "dbnz $%02x, $%04x ", "ret ",
+ "bvs $%04x ", "tcall 7 ", "clr1 $%02x.3 ", "bbc $%02x.3, $%04x ", "cmp a, $%02x+x ", "cmp a, $%04x+x ", "cmp a, $%04x+y ", "cmp a, [$%02x]+y ", "cmp $%02x, #$%02x ", "cmp [X], [Y] ", "addw ya, $%02x ", "ror $%02x+x ", "ror a ", "mov a, x ", "cmp y, $%02x ", "reti ",
+ "setc ", "tcall 8 ", "set1 $%02x.4 ", "bbs $%02x.4, $%04x ", "adc a, $%02x ", "adc a, $%04x ", "adc a, [X] ", "adc a, [$%02x+x] ", "adc a, #$%02x ", "adc $%02x, $%02x ", "eor1 c, $%04x.%01x ", "dec $%02x ", "dec $%04x ", "mov y, #$%02x ", "pop p ", "mov $%02x, #$%02x ",
+ "bcc $%04x ", "tcall 9 ", "clr1 $%02x.4 ", "bbc $%02x.4, $%04x ", "adc a, $%02x+x ", "adc a, $%04x+x ", "adc a, $%04x+y ", "adc a, [$%02x]+y ", "adc $%02x, #$%02x ", "adc [X], [Y] ", "subw ya, $%02x ", "dec $%02x+x ", "dec a ", "mov x, sp ", "div ya, x ", "xcn a ",
+ "ei ", "tcall 10 ", "set1 $%02x.5 ", "bbs $%02x.5, $%04x ", "sbc a, $%02x ", "sbc a, $%04x ", "sbc a, [X] ", "sbc a, [$%02x+x] ", "sbc a, #$%02x ", "sbc $%02x, $%02x ", "mov1 c, $%04x.%01x ", "inc $%02x ", "inc $%04x ", "cmp y, #$%02x ", "pop a ", "mov [x+], a ",
+ "bcs $%04x ", "tcall 11 ", "clr1 $%02x.5 ", "bbc $%02x.5, $%04x ", "sbc a, $%02x+x ", "sbc a, $%04x+x ", "sbc a, $%04x+y ", "sbc a, [$%02x]+y ", "sbc $%02x, #$%02x ", "sbc [X], [Y] ", "movw ya, $%02x ", "inc $%02x+x ", "inc a ", "mov sp, x ", "das a ", "mov a, [x+] ",
+ "di ", "tcall 12 ", "set1 $%02x.6 ", "bbs $%02x.6, $%04x ", "mov $%02x, a ", "mov $%04x, a ", "mov [X], a ", "mov [$%02x+x], a ", "cmp x, #$%02x ", "mov $%04x, x ", "mov1 $%04x.%01x, c ", "mov $%02x, y ", "mov $%04x, y ", "mov x, #$%02x ", "pop x ", "mul ya ",
+ "bne $%04x ", "tcall 13 ", "clr1 $%02x.6 ", "bbc $%02x.6, $%04x ", "mov $%02x+x, a ", "mov $%04x+x, a ", "mov $%04x+y, a ", "mov [$%02x]+y, a ", "mov $%02x, x ", "mov $%02x+y, x ", "movw $%02x, ya ", "mov $%02x+x, y ", "dec y ", "mov a, y ", "cbne $%02x+x, $%04x", "daa a ",
+ "clrv ", "tcall 14 ", "set1 $%02x.7 ", "bbs $%02x.7, $%04x ", "mov a, $%02x ", "mov a, $%04x ", "mov a, [X] ", "mov a, [$%02x+x] ", "mov a, #$%02x ", "mov x, $%04x ", "not1 $%04x.%01x ", "mov y, $%02x ", "mov y, $%04x ", "notc ", "pop y ", "sleep ",
+ "beq $%04x ", "tcall 15 ", "clr1 $%02x.7 ", "bbc $%02x.7, $%04x ", "mov a, $%02x+x ", "mov a, $%04x+x ", "mov a, $%04x+y ", "mov a, [$%02x]+y ", "mov x, $%02x ", "mov x, $%02x+y ", "mov $%02x, $%02x ", "mov y, $%02x+x ", "inc y ", "mov y, a ", "dbnz y, $%04x ", "stop "
+};
+
+// address types for each opcode, for spc
+static const int opcodeTypeSpc[256] = {
+ 0, 0, 1, 5, 1, 2, 0, 1, 1, 4, 6, 1, 2, 0, 2, 0,
+ 3, 0, 1, 5, 1, 2, 2, 1, 4, 0, 1, 1, 0, 0, 2, 2,
+ 0, 0, 1, 5, 1, 2, 0, 1, 1, 4, 6, 1, 2, 0, 5, 3,
+ 3, 0, 1, 5, 1, 2, 2, 1, 4, 0, 1, 1, 0, 0, 1, 2,
+ 0, 0, 1, 5, 1, 2, 0, 1, 1, 4, 6, 1, 2, 0, 2, 1,
+ 3, 0, 1, 5, 1, 2, 2, 1, 4, 0, 1, 1, 0, 0, 2, 2,
+ 0, 0, 1, 5, 1, 2, 0, 1, 1, 4, 6, 1, 2, 0, 5, 0,
+ 3, 0, 1, 5, 1, 2, 2, 1, 4, 0, 1, 1, 0, 0, 1, 0,
+ 0, 0, 1, 5, 1, 2, 0, 1, 1, 4, 6, 1, 2, 1, 0, 4,
+ 3, 0, 1, 5, 1, 2, 2, 1, 4, 0, 1, 1, 0, 0, 0, 0,
+ 0, 0, 1, 5, 1, 2, 0, 1, 1, 4, 6, 1, 2, 1, 0, 0,
+ 3, 0, 1, 5, 1, 2, 2, 1, 4, 0, 1, 1, 0, 0, 0, 0,
+ 0, 0, 1, 5, 1, 2, 0, 1, 1, 2, 6, 1, 2, 1, 0, 0,
+ 3, 0, 1, 5, 1, 2, 2, 1, 1, 1, 1, 1, 0, 0, 5, 0,
+ 0, 0, 1, 5, 1, 2, 0, 1, 1, 2, 6, 1, 2, 0, 0, 0,
+ 3, 0, 1, 5, 1, 2, 2, 1, 1, 1, 4, 1, 0, 0, 3, 0
+};
+
+static void getDisassemblyCpu(Snes* snes, char* line);
+static void getDisassemblySpc(Apu *apu, char* line);
+
+void getProcessorStateCpu(Snes* snes, char* line) {
+ // 0 1 2 3 4 5 6 7 8
+ // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
+ // CPU 12:3456 1234567890123 A:1234 X:1234 Y:1234 SP:1234 DP:1234 DP:12 e nvmxdizc
+ char disLine[14] = " ";
+ getDisassemblyCpu(snes, disLine);
+ sprintf(
+ line, "CPU %02x:%04x %s A:%04x X:%04x Y:%04x SP:%04x DP:%04x DB:%02x %c %c%c%c%c%c%c%c%c",
+ snes->cpu->k, snes->cpu->pc, disLine, snes->cpu->a, snes->cpu->x, snes->cpu->y,
+ snes->cpu->sp, snes->cpu->dp, snes->cpu->db, snes->cpu->e ? 'E' : 'e',
+ snes->cpu->n ? 'N' : 'n', snes->cpu->v ? 'V' : 'v', snes->cpu->mf ? 'M' : 'm', snes->cpu->xf ? 'X' : 'x',
+ snes->cpu->d ? 'D' : 'd', snes->cpu->i ? 'I' : 'i', snes->cpu->z ? 'Z' : 'z', snes->cpu->c ? 'C' : 'c'
+ );
+}
+
+void getProcessorStateSpc(Apu *apu, char* line) {
+ // 0 1 2 3 4 5 6 7 8
+ // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
+ // SPC 3456 12345678901234567 A:12 X:12 Y:12 SP:12 nvpbhizc
+ char disLine[18] = " ";
+ getDisassemblySpc(apu, disLine);
+ sprintf(
+ line, "SPC %04x %s A:%02x X:%02x Y:%02x SP:%02x %c%c%c%c%c%c%c%c",
+ apu->spc->pc, disLine, apu->spc->a, apu->spc->x, apu->spc->y, apu->spc->sp,
+ apu->spc->n ? 'N' : 'n', apu->spc->v ? 'V' : 'v', apu->spc->p ? 'P' : 'p', apu->spc->b ? 'B' : 'b',
+ apu->spc->h ? 'H' : 'h', apu->spc->i ? 'I' : 'i', apu->spc->z ? 'Z' : 'z', apu->spc->c ? 'C' : 'c'
+ );
+}
+
+static void getDisassemblyCpu(Snes* snes, char* line) {
+ uint32_t adr = snes->cpu->pc | (snes->cpu->k << 16);
+ // read 4 bytes
+ // TODO: this can have side effects, implement and use peaking
+ uint8_t opcode = snes_read(snes, adr);
+ uint8_t byte = snes_read(snes, (adr + 1) & 0xffffff);
+ uint8_t byte2 = snes_read(snes, (adr + 2) & 0xffffff);
+ uint16_t word = (byte2 << 8) | byte;
+ uint32_t longv = (snes_read(snes, (adr + 3) & 0xffffff) << 16) | word;
+ uint16_t rel = snes->cpu->pc + 2 + (int8_t) byte;
+ uint16_t rell = snes->cpu->pc + 3 + (int16_t) word;
+ // switch on type
+ switch(opcodeType[opcode]) {
+ case 0: sprintf(line, "%s", opcodeNames[opcode]); break;
+ case 1: sprintf(line, opcodeNames[opcode], byte); break;
+ case 2: sprintf(line, opcodeNames[opcode], word); break;
+ case 3: sprintf(line, opcodeNames[opcode], longv); break;
+ case 4: {
+ if(snes->cpu->mf) {
+ sprintf(line, opcodeNamesSp[opcode], byte);
+ } else {
+ sprintf(line, opcodeNames[opcode], word);
+ }
+ break;
+ }
+ case 5: {
+ if(snes->cpu->xf) {
+ sprintf(line, opcodeNamesSp[opcode], byte);
+ } else {
+ sprintf(line, opcodeNames[opcode], word);
+ }
+ break;
+ }
+ case 6: sprintf(line, opcodeNames[opcode], rel); break;
+ case 7: sprintf(line, opcodeNames[opcode], rell); break;
+ case 8: sprintf(line, opcodeNames[opcode], byte2, byte); break;
+ }
+}
+
+void getDisassemblySpc(Apu *apu, char* line) {
+ uint16_t adr = apu->spc->pc;
+ // read 3 bytes
+ // TODO: this can have side effects, implement and use peaking
+ uint8_t opcode = apu_cpuRead(apu, adr);
+ uint8_t byte = apu_cpuRead(apu, (adr + 1) & 0xffff);
+ uint8_t byte2 = apu_cpuRead(apu, (adr + 2) & 0xffff);
+ uint16_t word = (byte2 << 8) | byte;
+ uint16_t rel = apu->spc->pc + 2 + (int8_t) byte;
+ uint16_t rel2 = apu->spc->pc + 2 + (int8_t) byte2;
+ uint16_t wordb = word & 0x1fff;
+ uint8_t bit = word >> 13;
+ // switch on type
+ switch(opcodeTypeSpc[opcode]) {
+ case 0: sprintf(line, "%s", opcodeNamesSpc[opcode]); break;
+ case 1: sprintf(line, opcodeNamesSpc[opcode], byte); break;
+ case 2: sprintf(line, opcodeNamesSpc[opcode], word); break;
+ case 3: sprintf(line, opcodeNamesSpc[opcode], rel); break;
+ case 4: sprintf(line, opcodeNamesSpc[opcode], byte2, byte); break;
+ case 5: sprintf(line, opcodeNamesSpc[opcode], byte, rel2); break;
+ case 6: sprintf(line, opcodeNamesSpc[opcode], wordb, bit); break;
+ }
+}
--- /dev/null
+++ b/tracing.h
@@ -1,0 +1,17 @@
+
+#ifndef TRACING_H
+#define TRACING_H
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "snes/snes.h"
+
+void getProcessorStateCpu(Snes* snes, char* line);
+void getProcessorStateSpc(Apu* apu, char* line);
+
+#endif
--- /dev/null
+++ b/types.h
@@ -1,0 +1,76 @@
+#include <stdint.h>
+#include <stdlib.h>
+#pragma once
+
+typedef uint8_t uint8;
+typedef int8_t int8;
+typedef uint16_t uint16;
+typedef int16_t int16;
+typedef uint32_t uint32;
+typedef int32_t int32;
+
+#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
+#else
+#define countof(a) (sizeof(a)/sizeof(*(a)))
+#endif
+static inline uint16 abs16(uint16 t) { return sign16(t) ? -t : t; }
+static inline uint8 abs8(uint8 t) { return sign8(t) ? -t : t; }
+
+#define BYTE(x) (*(uint8*)&(x))
+#define HIBYTE(x) (((uint8*)&(x))[1])
+#define WORD(x) (*(uint16*)&(x))
+#define XY(x, y) ((y)*64+(x))
+
+static inline uint16 swap16(uint16 v) { return (v << 8) | (v >> 8); }
+
+struct Point16U {
+ uint16 x, y;
+};
+struct PointU8 {
+ uint8 x, y;
+};
+
+struct Pair16U {
+ uint16 a, b;
+};
+
+struct PairU8 {
+ uint8 a, b;
+};
+
+struct ProjectSpeedRet {
+ uint8 x, y;
+ uint8 xdiff, ydiff;
+};
+
+struct OamEnt {
+ uint8 x, y, charnum, flags;
+};
+
+struct UploadVram_Row {
+ uint16 col[32];
+};
+
+struct UploadVram_32x32 {
+ UploadVram_Row row[32];
+};
+
+struct UploadVram_3 {
+ uint8 pad[256];
+ uint16 data[4];
+};
+
+union UploadVram {
+ UploadVram_3 t3;
+};
+
+#define uvram (*(UploadVram*)(&g_ram[0x1000]))
+
+typedef void PlayerHandlerFunc();
+typedef void HandlerFuncK(int k);
\ No newline at end of file
--- /dev/null
+++ b/variables.h
@@ -1,0 +1,1237 @@
+
+#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 tmp1 (*(uint16*)(g_ram+0xBD))
+#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 buffer_for_playing_songs (*(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_cur_item_hi (*(uint8*)(g_ram+0x203))
+#define hud_var1 (*(uint8*)(g_ram+0x204))
+#define byte_7E0205 (*(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 eq_selected_y_item (*(uint8*)(g_ram+0x303))
+#define eq_selected_y_item_copy (*(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))
+#define door_debris_x ((uint16*)(g_ram+0x3B6))
+#define door_debris_y ((uint16*)(g_ram+0x3BA))
+#define door_debris_direction ((uint8*)(g_ram+0x3BE))
+#define ancilla_arr26 ((uint8*)(g_ram+0x3C0))
+#define ancilla_arr25 ((uint8*)(g_ram+0x3C2))
+#define ancilla_alloc_rotate (*(uint8*)(g_ram+0x3C4))
+#define ancilla_H ((uint8*)(g_ram+0x3C5))
+#define ancilla_floor2 ((uint8*)(g_ram+0x3CA))
+#define boomerang_arr1 ((uint8*)(g_ram+0x3CF))
+#define ancilla_arr23 ((uint8*)(g_ram+0x3D2))
+#define ancilla_T ((uint8*)(g_ram+0x3D5))
+#define ancilla_arr24 ((uint8*)(g_ram+0x3DB))
+#define ancilla_arr22 ((uint8*)(g_ram+0x3E1))
+#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 byte_7E03F3 (*(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 byte_7E03FC (*(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 overworld_palette_sp0 (*(uint8*)(g_ram+0xAAC))
+#define sprite_aux1_palette (*(uint8*)(g_ram+0xAAD))
+#define sprite_aux2_palette (*(uint8*)(g_ram+0xAAE))
+#define byte_7E0AB0 (*(uint8*)(g_ram+0xAB0))
+#define palette_sp6 (*(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 dung_hdr_palette_1 (*(uint8*)(g_ram+0xAB6))
+#define byte_7E0AB7 (*(uint8*)(g_ram+0xAB7))
+#define overworld_palette_aux3_bp7_lo (*(uint8*)(g_ram+0xAB8))
+#define overworld_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 mode7_hdma_table ((uint16*)(g_ram+0x1B00))
+#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_mode (*(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_dst_offs (*(uint16*)(g_ram+0x1CD9))
+#define byte_7E1CDC (*(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))
+#define byte_7E1CEA (*(uint8*)(g_ram+0x1CEA))
+#define dialogue_message_index (*(uint16*)(g_ram+0x1CF0))
+#define byte_7E1CF2 ((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_bottles (*(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 savegame_tagalong (*(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 super_bomb_going_off (*(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 ((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))
--- /dev/null
+++ b/variables_attract.h
@@ -1,0 +1,40 @@
+#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))
--- /dev/null
+++ b/variables_blastwall.h
@@ -1,0 +1,10 @@
+#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))
--- /dev/null
+++ b/variables_breaktowerseal.h
@@ -1,0 +1,15 @@
+#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))
--- /dev/null
+++ b/variables_happiness_pond.h
@@ -1,0 +1,15 @@
+#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))
--- /dev/null
+++ b/variables_skullwoodsfire.h
@@ -1,0 +1,9 @@
+#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))
--- /dev/null
+++ b/variables_weathervane.h
@@ -1,0 +1,14 @@
+#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))
--- /dev/null
+++ b/zelda3.vcxproj
@@ -1,0 +1,238 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>16.0</VCProjectVersion>
+ <ProjectGuid>{CB07E01D-A194-481A-BEA1-DC13756AD150}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+ <ProjectName>zelda3</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v142</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v142</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>D:\Lib\SDL2-2.0.20\include</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <TargetMachine>MachineX86</TargetMachine>
+ <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);D:\Lib\SDL2-2.0.20\lib\x86\SDL2.lib;D:\Lib\SDL2-2.0.20\lib\x86\SDL2main.lib;</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <AdditionalIncludeDirectories>D:\Lib\SDL2-2.0.20\include</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <TargetMachine>MachineX86</TargetMachine>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <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);D:\Lib\SDL2-2.0.20\lib\x86\SDL2.lib;D:\Lib\SDL2-2.0.20\lib\x86\SDL2main.lib;</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>D:\Lib\SDL2-2.0.20\include</AdditionalIncludeDirectories>
+ <BasicRuntimeChecks>Default</BasicRuntimeChecks>
+ </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);D:\Lib\SDL2-2.0.20\lib\x64\SDL2.lib;D:\Lib\SDL2-2.0.20\lib\x64\SDL2main.lib;</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>D:\Lib\SDL2-2.0.20\include</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);D:\Lib\SDL2-2.0.20\lib\x64\SDL2.lib;D:\Lib\SDL2-2.0.20\lib\x64\SDL2main.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="ancilla.cpp" />
+ <ClCompile Include="attract.cpp" />
+ <ClCompile Include="dungeon.cpp" />
+ <ClCompile Include="ending.cpp" />
+ <ClCompile Include="hud.cpp" />
+ <ClCompile Include="load_gfx.cpp" />
+ <ClCompile Include="main.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Disabled</Optimization>
+ <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
+ </ClCompile>
+ <ClCompile Include="messaging.cpp" />
+ <ClCompile Include="misc.cpp" />
+ <ClCompile Include="nmi.cpp" />
+ <ClCompile Include="other_modules.cpp" />
+ <ClCompile Include="overlord.cpp" />
+ <ClCompile Include="overworld.cpp" />
+ <ClCompile Include="player.cpp" />
+ <ClCompile Include="player_oam.cpp" />
+ <ClCompile Include="poly.cpp" />
+ <ClCompile Include="select_file.cpp" />
+ <ClCompile Include="snes\apu.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
+ <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
+ </ClCompile>
+ <ClCompile Include="snes\cart.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
+ <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
+ </ClCompile>
+ <ClCompile Include="snes\cpu.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
+ <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
+ </ClCompile>
+ <ClCompile Include="snes\dma.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
+ <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
+ </ClCompile>
+ <ClCompile Include="snes\dsp.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
+ <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
+ </ClCompile>
+ <ClCompile Include="snes\input.cpp">
+ <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
+ </ClCompile>
+ <ClCompile Include="snes\ppu.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
+ <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AnySuitable</InlineFunctionExpansion>
+ </ClCompile>
+ <ClCompile Include="snes\snes.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
+ <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
+ </ClCompile>
+ <ClCompile Include="snes\snes_other.cpp">
+ <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
+ </ClCompile>
+ <ClCompile Include="snes\spc.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
+ <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
+ </ClCompile>
+ <ClCompile Include="spc_player.cpp" />
+ <ClCompile Include="sprite.cpp" />
+ <ClCompile Include="sprite_main.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="tagalong.cpp" />
+ <ClCompile Include="tile_detect.cpp" />
+ <ClCompile Include="tracing.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
+ <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
+ </ClCompile>
+ <ClCompile Include="zelda_cpu_infra.cpp" />
+ <ClCompile Include="zelda_rtl.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="ancilla.h" />
+ <ClInclude Include="attract.h" />
+ <ClInclude Include="dungeon.h" />
+ <ClInclude Include="ending.h" />
+ <ClInclude Include="hud.h" />
+ <ClInclude Include="load_gfx.h" />
+ <ClInclude Include="messaging.h" />
+ <ClInclude Include="misc.h" />
+ <ClInclude Include="nmi.h" />
+ <ClInclude Include="other_modules.h" />
+ <ClInclude Include="overlord.h" />
+ <ClInclude Include="overworld.h" />
+ <ClInclude Include="player.h" />
+ <ClInclude Include="player_oam.h" />
+ <ClInclude Include="poly.h" />
+ <ClInclude Include="select_file.h" />
+ <ClInclude Include="snes\apu.h" />
+ <ClInclude Include="snes\cart.h" />
+ <ClInclude Include="snes\cpu.h" />
+ <ClInclude Include="snes\dma.h" />
+ <ClInclude Include="snes\dsp.h" />
+ <ClInclude Include="snes\input.h" />
+ <ClInclude Include="snes\ppu.h" />
+ <ClInclude Include="snes\saveload.h" />
+ <ClInclude Include="snes\snes.h" />
+ <ClInclude Include="snes\spc.h" />
+ <ClInclude Include="snes_regs.h" />
+ <ClInclude Include="spc_player.h" />
+ <ClInclude Include="sprite.h" />
+ <ClInclude Include="sprite_main.h" />
+ <ClInclude Include="tagalong.h" />
+ <ClInclude Include="tile_detect.h" />
+ <ClInclude Include="tracing.h" />
+ <ClInclude Include="types.h" />
+ <ClInclude Include="variables.h" />
+ <ClInclude Include="zelda_cpu_infra.h" />
+ <ClInclude Include="zelda_rtl.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+++ b/zelda3.vcxproj.filters
@@ -1,0 +1,232 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Zelda">
+ <UniqueIdentifier>{d6299dde-0eca-4199-8851-ead8818843b7}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Snes">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="snes\apu.cpp">
+ <Filter>Snes</Filter>
+ </ClCompile>
+ <ClCompile Include="snes\cart.cpp">
+ <Filter>Snes</Filter>
+ </ClCompile>
+ <ClCompile Include="snes\cpu.cpp">
+ <Filter>Snes</Filter>
+ </ClCompile>
+ <ClCompile Include="snes\dma.cpp">
+ <Filter>Snes</Filter>
+ </ClCompile>
+ <ClCompile Include="snes\dsp.cpp">
+ <Filter>Snes</Filter>
+ </ClCompile>
+ <ClCompile Include="snes\input.cpp">
+ <Filter>Snes</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Snes</Filter>
+ </ClCompile>
+ <ClCompile Include="snes\ppu.cpp">
+ <Filter>Snes</Filter>
+ </ClCompile>
+ <ClCompile Include="snes\snes.cpp">
+ <Filter>Snes</Filter>
+ </ClCompile>
+ <ClCompile Include="snes\snes_other.cpp">
+ <Filter>Snes</Filter>
+ </ClCompile>
+ <ClCompile Include="snes\spc.cpp">
+ <Filter>Snes</Filter>
+ </ClCompile>
+ <ClCompile Include="tracing.cpp">
+ <Filter>Snes</Filter>
+ </ClCompile>
+ <ClCompile Include="zelda_rtl.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="hud.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="dungeon.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="nmi.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="player_oam.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="load_gfx.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="messaging.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="overworld.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="sprite.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="sprite_main.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="tagalong.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="overlord.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="poly.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="ancilla.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="ending.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="attract.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="select_file.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="spc_player.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="player.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="tile_detect.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="other_modules.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="misc.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ <ClCompile Include="zelda_cpu_infra.cpp">
+ <Filter>Zelda</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="snes\apu.h">
+ <Filter>Snes</Filter>
+ </ClInclude>
+ <ClInclude Include="snes\cart.h">
+ <Filter>Snes</Filter>
+ </ClInclude>
+ <ClInclude Include="snes\cpu.h">
+ <Filter>Snes</Filter>
+ </ClInclude>
+ <ClInclude Include="snes\dma.h">
+ <Filter>Snes</Filter>
+ </ClInclude>
+ <ClInclude Include="snes\dsp.h">
+ <Filter>Snes</Filter>
+ </ClInclude>
+ <ClInclude Include="snes\input.h">
+ <Filter>Snes</Filter>
+ </ClInclude>
+ <ClInclude Include="snes\ppu.h">
+ <Filter>Snes</Filter>
+ </ClInclude>
+ <ClInclude Include="snes\saveload.h">
+ <Filter>Snes</Filter>
+ </ClInclude>
+ <ClInclude Include="snes\snes.h">
+ <Filter>Snes</Filter>
+ </ClInclude>
+ <ClInclude Include="snes\spc.h">
+ <Filter>Snes</Filter>
+ </ClInclude>
+ <ClInclude Include="tracing.h">
+ <Filter>Snes</Filter>
+ </ClInclude>
+ <ClInclude Include="zelda_rtl.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="hud.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="dungeon.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="snes_regs.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="nmi.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="load_gfx.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="overworld.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="variables.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="sprite.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="tagalong.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="overlord.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="poly.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="ancilla.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="ending.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="select_file.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="tile_detect.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="types.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="player.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="other_modules.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="misc.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="player_oam.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="messaging.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="attract.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="zelda_cpu_infra.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="spc_player.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="sprite_main.h">
+ <Filter>Zelda</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+++ b/zelda_cpu_infra.cpp
@@ -1,0 +1,891 @@
+// This file handles running zelda through the emulated cpu.
+
+#include "zelda_cpu_infra.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "misc.h"
+#include "nmi.h"
+#include "poly.h"
+#include "attract.h"
+#include "spc_player.h"
+
+#include "snes/snes.h"
+#include "snes/cpu.h"
+#include "snes/cart.h"
+#include "tracing.h"
+
+#include <vector>
+
+Snes *g_snes;
+Cpu *g_cpu;
+uint8 g_emulated_ram[0x20000];
+
+
+void SaveLoadSlot(int cmd, int which);
+
+//uint8 *GetPtr(uint32 addr) {
+// Cart *cart = g_snes->cart;
+// return &cart->rom[(((addr >> 16) << 15) | (addr & 0x7fff)) & (cart->romSize - 1)];
+//}
+
+//extern "C" uint8 *GetCartRamPtr(uint32 addr) {
+// Cart *cart = g_snes->cart;
+// return &cart->ram[addr];
+//}
+
+struct Snapshot {
+ uint16 a, x, y, sp, dp, pc;
+ uint8 k, db, flags;
+ uint8 ram[0x20000];
+ uint16 vram[0x8000];
+ uint16 sram[0x2000];
+};
+
+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);
+}
+
+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);
+}
+
+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;
+
+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
+ memcpy(&b->ram[0x1f0d], &a->ram[0x1f0d], 0x3f - 0xd);
+ memcpy(b->ram + 0x138, a->ram + 0x138, 256 - 0x38); // copy the stack over
+
+ 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;
+ }
+ }
+ }
+}
+
+static uint8_t *RomByte(Cart *cart, uint32_t addr) {
+ return &cart->rom[(((addr >> 16) << 15) | (addr & 0x7fff)) & (cart->romSize - 1)];
+}
+
+void SetSnes(Snes *snes) {
+ g_snes = snes;
+ g_cpu = snes->cpu;
+}
+
+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) {
+ // 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)
+ break;
+ }
+}
+
+void RunEmulatedSnesFrame(Snes *snes) {
+ // 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;
+ }
+ 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);
+ snes->cpu->nmiWanted = true;
+ for (;;) {
+ 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 == 0x8039 || pc == 0x9f81d)
+ break;
+ }
+}
+
+struct Ppu *GetPpuForRendering() {
+ return g_zenv.ppu;
+}
+
+Dsp *GetDspForRendering() {
+ SpcPlayer_GenerateSamples(g_zenv.player);
+ return g_zenv.player->dsp;
+}
+
+
+void saveFunc(void *ctx, void *data, size_t data_size) {
+ std::vector<uint8> *vec = (std::vector<uint8> *)ctx;
+ vec->resize(vec->size() + data_size);
+ memcpy(vec->data() + vec->size() - data_size, data, data_size);
+}
+
+struct LoadFuncState {
+ uint8 *p, *pend;
+};
+
+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;
+}
+
+
+void CopyStateAfterSnapshotRestore(bool is_reset) {
+ memcpy(g_zenv.ram, g_snes->ram, 0x20000);
+ memcpy(g_zenv.sram, g_snes->cart->ram, g_snes->cart->ramSize);
+ memcpy(g_zenv.ppu->vram, &g_snes->ppu->vram, offsetof(Ppu, pixelBuffer) - offsetof(Ppu, vram));
+ memcpy(g_zenv.player->ram, g_snes->apu->ram, sizeof(g_snes->apu->ram));
+
+ if (!is_reset) {
+ memcpy(g_zenv.player->dsp->ram, g_snes->apu->dsp->ram, sizeof(Dsp) - offsetof(Dsp, ram));
+ SpcPlayer_CopyVariablesFromRam(g_zenv.player);
+ }
+
+ memcpy(g_zenv.dma->channel, g_snes->dma->channel, sizeof(Dma) - offsetof(Dma, channel));
+
+ g_zenv.player->timer_cycles = 0;
+
+ if (!is_reset) {
+ // Setup some fake cpu state cause we can't depend on the savegame's
+ Cpu *cpu = g_snes->cpu;
+ cpu->a = cpu->x = cpu->y = 0;
+ cpu->pc = 0x8034;
+ cpu->sp = 0x1ff;
+ cpu->k = cpu->dp = cpu->db = 0;
+ cpu_setFlags(cpu, 0x30);
+ cpu->irqWanted = cpu->nmiWanted = cpu->waiting = cpu->stopped = 0;
+ cpu->e = false;
+
+ if (thread_other_stack == 0x1f2) {
+ cpu->sp = 0x1f3e;
+ cpu->pc = 0xf81d;
+ cpu->db = cpu->k = 9;
+ cpu->dp = 0x1f00;
+ static const uint8 kStackInit[] = { 0x82, 0, 0, 0, 0, 0, 0, 0, 0x40, 0xb7, 0xb0, 0x34, 0x80, 0 };
+ memcpy(g_snes->ram + 0x1f2, kStackInit, sizeof(kStackInit));
+ }
+ }
+}
+
+std::vector<uint8> SaveSnesState() {
+ std::vector<uint8> data;
+
+ MakeSnapshot(&g_snapshot_before);
+
+ // Copy from my state into the emulator
+ memcpy(&g_snes->ppu->vram, g_zenv.ppu->vram, offsetof(Ppu, pixelBuffer) - offsetof(Ppu, vram));
+ memcpy(g_snes->ram, g_zenv.ram, 0x20000);
+ memcpy(g_snes->cart->ram, g_zenv.sram, 0x2000);
+ SpcPlayer_CopyVariablesToRam(g_zenv.player);
+ memcpy(g_snes->apu->ram, g_zenv.player->ram, 0x10000);
+ memcpy(g_snes->apu->dsp->ram, g_zenv.player->dsp->ram, sizeof(Dsp) - offsetof(Dsp, ram));
+ memcpy(g_snes->dma->channel, g_zenv.dma->channel, sizeof(Dma) - offsetof(Dma, channel));
+
+ snes_saveload(g_snes, &saveFunc, &data);
+
+
+ RestoreSnapshot(&g_snapshot_before);
+ return data;
+}
+
+
+class StateRecorder {
+public:
+ StateRecorder() : last_inputs_(0), frames_since_last_(0), total_frames_(0), replay_mode_(false) {}
+ void Record(uint16 inputs);
+ void RecordPatchByte(uint32 addr, const uint8 *value, int num);
+
+ void Load(FILE *f, bool replay_mode);
+ void Save(FILE *f);
+
+ uint16 ReadNextReplayState();
+ bool is_replay_mode() { return replay_mode_; }
+
+ void MigrateToBaseSnapshot();
+private:
+
+ void RecordJoypadBit(int command);
+ void AppendByte(uint8 v);
+ void AppendVl(uint32 v);
+
+ uint16 last_inputs_;
+ uint32 frames_since_last_;
+ uint32 total_frames_;
+
+ // For replay
+ uint32 replay_pos_, replay_frame_counter_, replay_next_cmd_at_;
+ uint8 replay_cmd_;
+ bool replay_mode_;
+
+ std::vector<uint8> log_;
+ std::vector<uint8> base_snapshot_;
+};
+
+uint32 RamChecksum() {
+ uint64_t cksum = 0, cksum2 = 0;
+ for (int i = 0; i < 0x20000; i += 4) {
+ cksum += *(uint32 *)&g_ram[i];
+ cksum2 += cksum;
+ }
+ return cksum ^ (cksum >> 32) ^ cksum2 ^ (cksum2 >> 32);
+}
+
+void StateRecorder::AppendByte(uint8 v) {
+ log_.push_back(v);
+ printf("%.2x ", v);
+}
+
+void StateRecorder::AppendVl(uint32 v) {
+ for (; v >= 255; v -= 255)
+ AppendByte(255);
+ AppendByte(v);
+}
+
+void StateRecorder::RecordJoypadBit(int command) {
+ int frames = frames_since_last_;
+ AppendByte(command << 4 | (frames < 15 ? frames : 15));
+ if (frames >= 15)
+ AppendVl(frames - 15);
+ frames_since_last_ = 0;
+}
+
+void StateRecorder::Record(uint16 inputs) {
+ uint16 diff = inputs ^ last_inputs_;
+ if (diff != 0) {
+ last_inputs_ = inputs;
+ printf("0x%.4x %d: ", diff, frames_since_last_);
+ for (int i = 0; i < 12; i++) {
+ if ((diff >> i) & 1)
+ RecordJoypadBit(i);
+ }
+ printf("\n");
+ }
+ frames_since_last_++;
+ total_frames_++;
+}
+
+void StateRecorder::RecordPatchByte(uint32 addr, const uint8 *value, int num) {
+ assert(addr < 0x20000);
+ printf("%d: PatchByte(0x%x, 0x%x. %d): ", frames_since_last_, addr, *value, num);
+
+ int frames = frames_since_last_;
+
+ int lq = (num - 1) <= 3 ? (num - 1) : 3;
+
+ AppendByte(0xc0 | (frames != 0 ? 1 : 0) | (addr & 0x10000 ? 2 : 0) | lq << 2);
+ if (frames != 0)
+ AppendVl(frames - 1);
+ if (lq == 3)
+ AppendVl(num - 1 - 3);
+
+ frames_since_last_ = 0;
+ AppendByte(addr >> 8);
+ AppendByte(addr);
+ for(int i = 0; i < num; i++)
+ AppendByte(value[i]);
+ printf("\n");
+}
+
+void StateRecorder::Load(FILE *f, bool replay_mode) {
+ uint32 hdr[8] = { 0 };
+ fread(hdr, 8, 4, f);
+
+ assert(hdr[0] == 1);
+
+ total_frames_ = hdr[1];
+ log_.resize(hdr[2]);
+ fread(log_.data(), 1, hdr[2], f);
+ last_inputs_ = hdr[3];
+ frames_since_last_ = hdr[4];
+
+ base_snapshot_.resize((hdr[5] & 1) ? hdr[6] : 0);
+ fread(base_snapshot_.data(), 1, base_snapshot_.size(), f);
+
+ bool is_reset = false;
+ replay_mode_ = replay_mode;
+ if (replay_mode) {
+ replay_next_cmd_at_ = frames_since_last_ = 0;
+ last_inputs_ = 0;
+ replay_pos_ = 0;
+ replay_frame_counter_ = 0;
+ replay_cmd_ = 0xff;
+ // Load snapshot from |base_snapshot_|, or reset if empty.
+
+ if (base_snapshot_.size()) {
+ LoadFuncState state = { base_snapshot_.data(), base_snapshot_.data() + base_snapshot_.size() };
+ snes_saveload(g_snes, &loadFunc, &state);
+ assert(state.p == state.pend);
+ } else {
+ snes_reset(g_snes, true);
+ SpcPlayer_Initialize(g_zenv.player);
+ is_reset = true;
+ }
+ } else {
+ std::vector<uint8> data;
+ data.resize(hdr[6]);
+ fread(data.data(), 1, data.size(), f);
+
+ LoadFuncState state = { data.data(), data.data() + data.size() };
+ snes_saveload(g_snes, &loadFunc, &state);
+ assert(state.p == state.pend);
+ }
+ CopyStateAfterSnapshotRestore(is_reset);
+}
+
+void StateRecorder::Save(FILE *f) {
+ uint32 hdr[8] = { 0 };
+
+ std::vector<uint8> data = SaveSnesState();
+ assert(base_snapshot_.size() == 0 || base_snapshot_.size() == data.size());
+
+ hdr[0] = 1;
+ hdr[1] = total_frames_;
+ hdr[2] = log_.size();
+ hdr[3] = last_inputs_;
+ hdr[4] = frames_since_last_;
+ hdr[5] = (base_snapshot_.size() ? 1 : 0);
+ hdr[6] = data.size();
+
+ fwrite(hdr, 8, 4, f);
+ fwrite(log_.data(), 1, log_.size(), f);
+ fwrite(base_snapshot_.data(), 1, base_snapshot_.size(), f);
+ fwrite(data.data(), 1, data.size(), f);
+}
+
+void StateRecorder::MigrateToBaseSnapshot() {
+ printf("Migrating to base snapshot!\n");
+ std::vector<uint8> data = SaveSnesState();
+ base_snapshot_ = std::move(data);
+
+ replay_mode_ = false;
+ frames_since_last_ = 0;
+ last_inputs_ = 0;
+ total_frames_ = 0;
+ log_.clear();
+}
+
+uint16 StateRecorder::ReadNextReplayState() {
+ assert(replay_mode_);
+ while (frames_since_last_ >= replay_next_cmd_at_) {
+ frames_since_last_ = 0;
+ // Apply next command
+ if (replay_cmd_ != 0xff) {
+ if (replay_cmd_ < 0xc0) {
+ last_inputs_ ^= 1 << (replay_cmd_ >> 4);
+ } else if (replay_cmd_ < 0xd0) {
+ int nb = 1 + ((replay_cmd_ >> 2) & 3);
+ uint8 t;
+ if (nb == 4) do {
+ nb += t = log_[replay_pos_++];
+ } while (t == 255);
+ uint32 addr = ((replay_cmd_ >> 1) & 1) << 16;
+ addr |= log_[replay_pos_++] << 8;
+ addr |= log_[replay_pos_++];
+ do {
+ g_emulated_ram[addr & 0x1ffff] = g_ram[addr & 0x1ffff] = log_[replay_pos_++];
+ } while (addr++, --nb);
+ } else {
+ assert(0);
+ }
+ }
+ if (replay_pos_ >= log_.size()) {
+ replay_cmd_ = 0xff;
+ replay_next_cmd_at_ = 0xffffffff;
+ break;
+ }
+ // Read the next one
+ uint8 cmd = log_[replay_pos_++], t;
+ int mask = (cmd < 0xc0) ? 0xf : 0x1;
+ int frames = cmd & mask;
+ if (frames == mask) do {
+ frames += t = log_[replay_pos_++];
+ } while (t == 255);
+ replay_next_cmd_at_ = frames;
+ replay_cmd_ = cmd;
+ }
+ frames_since_last_++;
+ // Turn off replay mode after we reached the final frame position
+ if (++replay_frame_counter_ >= total_frames_) {
+ replay_mode_ = false;
+ }
+ return last_inputs_;
+}
+
+StateRecorder input_recorder;
+static int frame_ctr;
+
+bool RunOneFrame(Snes *snes, int input_state, bool turbo) {
+ frame_ctr++;
+
+ if (kIsOrigEmu) {
+ snes_runFrame(snes);
+ return false;
+ }
+
+ // Either copy state or apply state
+ if (input_recorder.is_replay_mode()) {
+ input_state = input_recorder.ReadNextReplayState();
+ } else {
+ input_recorder.Record(input_state);
+ turbo = false;
+
+ // This is whether APUI00 is true or false, this is used by the ancilla code.
+ uint8 apui00 = g_zenv.player->port_to_snes[0] != 0;
+ if (apui00 != g_ram[0x648]) {
+ g_emulated_ram[0x648] = g_ram[0x648] = apui00;
+ input_recorder.RecordPatchByte(0x648, &apui00, 1);
+ }
+ }
+
+ if (snes == NULL) {
+ ZeldaRunFrame(input_state);
+ return turbo;
+ }
+
+ MakeSnapshot(&g_snapshot_before);
+ MakeMySnapshot(&g_snapshot_mine);
+ MakeSnapshot(&g_snapshot_theirs);
+
+ // Compare both snapshots
+ VerifySnapshotsEq(&g_snapshot_mine, &g_snapshot_theirs, &g_snapshot_before);
+ if (g_fail) {
+ printf("early fail\n");
+ return turbo;
+ }
+
+again:
+ // Run orig version then snapshot
+ snes->input1->currentState = input_state;
+ RunEmulatedSnesFrame(snes);
+ MakeSnapshot(&g_snapshot_theirs);
+
+ // Run my version and snapshot
+again_mine:
+ ZeldaRunFrame(input_state);
+
+ MakeMySnapshot(&g_snapshot_mine);
+
+ // Compare both snapshots
+ VerifySnapshotsEq(&g_snapshot_mine, &g_snapshot_theirs, &g_snapshot_before);
+
+ if (g_fail) {
+ g_fail = false;
+ RestoreMySnapshot(&g_snapshot_before);
+ // RestoreSnapshot(&g_snapshot_before);
+ //SaveLoadSlot(kSaveLoad_Save, 0);
+ goto again_mine;
+ }
+
+ return turbo;
+}
+
+void PatchRomBP(uint8_t *rom, uint32_t addr) {
+ rom[(addr >> 16) << 15 | (addr & 0x7fff)] = 0;
+}
+
+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, 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..
+
+ // 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;
+
+}
+
+
+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)
+ input_recorder.Load(f, cmd == kSaveLoad_Replay);
+ else
+ input_recorder.Save(f);
+
+ fclose(f);
+ }
+}
+
+class PatchRamByteBatch {
+public:
+ PatchRamByteBatch() : count_(0), addr_(0) {}
+ ~PatchRamByteBatch();
+ void Patch(uint32 addr, uint8 value);
+
+private:
+ uint32 count_, addr_;
+ uint8 vals_[256];
+};
+
+PatchRamByteBatch::~PatchRamByteBatch() {
+ if (count_)
+ input_recorder.RecordPatchByte(addr_, vals_, count_);
+}
+
+void PatchRamByteBatch::Patch(uint32 addr, uint8 value) {
+ if (count_ >= 256 || addr != addr_ + count_) {
+ if (count_)
+ input_recorder.RecordPatchByte(addr_, vals_, count_);
+ addr_ = addr;
+ count_ = 0;
+ }
+ vals_[count_++] = value;
+
+ g_emulated_ram[addr] = g_ram[addr] = value;
+}
+
+void PatchCommand(char c) {
+ PatchRamByteBatch b;
+ if (c == 'w') {
+ b.Patch(0xf372, 80); // health filler
+ b.Patch(0xf373, 80); // magic filler
+// b.Patch(0x1FE01, 25);
+ } else if (c == 'k') {
+ input_recorder.MigrateToBaseSnapshot();
+ } else if (c == 'o') {
+ b.Patch(0xf36f, 1);
+ }
+}
--- /dev/null
+++ b/zelda_cpu_infra.h
@@ -1,0 +1,7 @@
+#pragma once
+#include "types.h"
+
+uint8 *GetPtr(uint32 addr);
+
+void RunEmulatedFuncSilent(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b = -1, int whatflags = 0);
+void RunEmulatedFunc(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b = -1, int whatflags = 0);
--- /dev/null
+++ b/zelda_rtl.cpp
@@ -1,0 +1,282 @@
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "misc.h"
+#include "nmi.h"
+#include "poly.h"
+#include "attract.h"
+#include "spc_player.h"
+#include "snes/ppu.h"
+
+ZeldaEnv g_zenv;
+// These point to the rewritten instance of the emu.
+uint8 g_ram[131072];
+struct SimpleHdma {
+ const uint8 *table;
+ const uint8 *indir_ptr;
+ uint8 rep_count;
+ uint8 mode;
+ uint8 ppu_addr;
+ uint8 indir_bank;
+};
+void SimpleHdma_Init(SimpleHdma *c, DmaChannel *dc);
+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
+};
+#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_apu_write(uint32_t adr, uint8_t val) {
+ assert(adr >= APUI00 && adr <= APUI03);
+ g_zenv.player->input_ports[adr & 0x3] = val;
+}
+
+void zelda_apu_write_word(uint32_t adr, uint16_t val) {
+ zelda_apu_write(adr, val);
+ zelda_apu_write(adr + 1, val >> 8);
+}
+
+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[0x648];
+}
+
+uint8_t zelda_apu_read(uint32_t adr) {
+ return g_zenv.player->port_to_snes[adr & 0x3];
+}
+
+uint16_t zelda_apu_read_word(uint32_t adr) {
+ uint16_t rv = zelda_apu_read(adr);
+ rv |= zelda_apu_read(adr + 1) << 8;
+ return rv;
+}
+
+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);
+}
+
+void zelda_apu_runcycles() {
+// apu_cycle(g_zenv.apu);
+}
+
+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;
+ case 0xabdd6: return kMapModeHdma1;
+ case 0xABDDD: return kAttractIndirectHdmaTab;
+ case 0x2c80c: return kHdmaTableForPrayingScene;
+
+ case 0x1b00: return (uint8 *)mode7_hdma_table;
+ case 0x1be0: return (uint8 *)mode7_hdma_table + 0xe0;
+ case 0x1bf0: return (uint8 *)mode7_hdma_table + 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;
+ }
+}
+
+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;
+}
+
+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--;
+}
+
+void ZeldaDrawPpuFrame() {
+ SimpleHdma hdma_chans[2];
+
+ 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]);
+
+ for (int i = 0; i < 225; 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) {
+ struct 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);
+}
+
+void ZeldaInitializationCode() {
+ zelda_snes_dummy_write(NMITIMEN, 0);
+ zelda_snes_dummy_write(HDMAEN, 0);
+ zelda_snes_dummy_write(MDMAEN, 0);
+ zelda_apu_write(APUI00, 0);
+ zelda_apu_write(APUI01, 0);
+ zelda_apu_write(APUI02, 0);
+ zelda_apu_write(APUI03, 0);
+ zelda_ppu_write(INIDISP, 0x80);
+
+ 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);
+}
+
+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);
+}
+
+void ZeldaRunFrame(uint16 input) {
+ if (animated_tile_data_src == 0)
+ ZeldaInitializationCode();
+
+ // When poly is active, the main game loop is not run. They alternate.
+ if (is_nmi_thread_active && thread_other_stack != 0x1f31) {
+ if (intro_did_run_step && !nmi_flag_update_polyhedral) {
+ Poly_RunFrame();
+ intro_did_run_step = 0;
+ nmi_flag_update_polyhedral = 0xff;
+ }
+ } else {
+ ZeldaRunGameLoop();
+ }
+
+ Interrupt_NMI(input);
+}
+
+void ClearOamBuffer() { // 80841e
+ for (int i = 0; i < 128; i++)
+ oam_buf[i].y = 0xf0;
+}
+
+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;
+ zelda_ppu_write(TMW, 0);
+ INIDISP_copy = 0x80;
+ flag_update_cgram_in_nmi++;
+}
+
+void LoadSongBank(const uint8 *p) { // 808888
+ SpcPlayer_Upload(g_zenv.player, p);
+}
+
--- /dev/null
+++ b/zelda_rtl.h
@@ -1,0 +1,197 @@
+#pragma once
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include "types.h"
+#include "snes_regs.h"
+
+
+struct ZeldaEnv {
+ uint8 *ram;
+ uint8 *sram;
+ uint16 *vram;
+ struct Ppu *ppu;
+ struct SpcPlayer *player;
+ struct Dma *dma;
+};
+extern ZeldaEnv g_zenv;
+// it's here so that the variables.h can access it
+extern uint8 g_ram[131072];
+
+
+
+static inline void zelda_snes_dummy_write(uint32_t adr, uint8_t val) {}
+
+
+
+
+
+
+
+
+
+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 };
+
+struct MovableBlockData {
+ uint16 room;
+ uint16 tilemap;
+};
+
+struct OamEntSigned {
+ int8 x, y;
+ uint8 charnum, flags;
+};
+
+
+
+#define movable_block_datas ((MovableBlockData*)(g_ram+0xf940))
+#define oam_buf ((OamEnt*)(g_ram+0x800))
+
+
+
+
+struct OwScrollVars {
+ uint16 ystart, yend, xstart, xend;
+};
+
+#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
+
+
+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;
+};
+
+
+// Various level tables
+
+
+#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 mirror_vars (*(MirrorHdmaVars*)(g_ram+0x6A0))
+#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))
+
+void zelda_apu_write(uint32_t adr, uint8_t val);
+void zelda_apu_write_word(uint32_t adr, uint16_t val);
+uint8_t zelda_read_apui00();
+uint8_t zelda_apu_read(uint32_t adr);
+uint16_t zelda_apu_read_word(uint32_t adr);
+void zelda_ppu_write(uint32_t adr, uint8_t val);
+void zelda_ppu_write_word(uint32_t adr, uint16_t val);
+void zelda_apu_runcycles();
+const uint8 *SimpleHdma_GetPtr(uint32 p);
+void ZeldaDrawPpuFrame();
+void HdmaSetup(uint32 addr6, uint32 addr7, uint8 transfer_unit, uint8 reg6, uint8 reg7, uint8 indirect_bank);
+void ZeldaInitializationCode();
+void ZeldaRunGameLoop();
+void ZeldaInitialize();
+void ZeldaRunFrame(uint16 input);
+void ClearOamBuffer();
+void Startup_InitializeMemory();
+void LoadSongBank(const uint8 *p);