ref: b85e91a33657a60d256ab4a2cb30b07bddfe944f
parent: f83f949d200c1cd6c07bd50ce5108f7dea80660c
author: Snesrev <snesrev@protonmail.com>
date: Wed Aug 31 17:03:04 EDT 2022
Migrate to C99 instead of C Co-authored-by: Rémy F <yne@users.noreply.github.com>
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
/.vs/
/packages/
+/.vscode/
.DS_Store
*.dSYM
/Debug
@@ -12,7 +13,11 @@
/tables/zelda3.sfc
/tables/zelda3.smc
/saves/*.sav
+/saves/sram.dat
+/saves/sram.bak
/zelda3
-/.vs/
__pycache__
-*.o
\ No newline at end of file
+/*.o
+/*.exe
+/*.out
+/snes/*.o
--- a/Makefile
+++ b/Makefile
@@ -1,22 +1,22 @@
# adapted from original README.md:
-# `clang++ -I/usr/include/SDL2 -lSDL2 -O2 -ozelda3 *.cpp snes/*.cpp`
+# `clang -I/usr/include/SDL2 -lSDL2 -O2 -ozelda3 *.c snes/*.c`
-ifneq (,$(shell command -v clang++))
- CXX = clang++
-else ifneq (,$(shell command -v g++))
- CXX = g++
+ifneq (,$(shell which clang))
+ CC = clang
+else ifneq (,$(shell which gcc))
+ CC = gcc
endif
-ifneq (,$(findstring clang,$(CXX)))
+ifneq (,$(findstring clang,$(CC)))
LTO = -flto=thin
-else ifneq (,$(findstring g++,$(CXX)))
+else ifneq (,$(findstring gcc,$(CC)))
LTO = -flto=auto
endif
-override CXXFLAGS := -O2 -I/usr/include/SDL2 $(LTO) $(CXXFLAGS)
+override CFLAGS := -O2 -I/usr/include/SDL2 $(LTO) $(CXXFLAGS)
override LDFLAGS := -lSDL2 $(LDFLAGS)
-override OBJS = $(patsubst %.cpp,%.o,$(wildcard *.cpp snes/*.cpp))
+override OBJS = $(patsubst %.c,%.o,$(wildcard *.c snes/*.c))
override BIN = zelda3
.PHONY: all clean
@@ -27,4 +27,4 @@
$(RM) $(BIN) $(OBJS)
$(BIN): $(OBJS)
- $(CXX) $(CXXFLAGS) -o $(BIN) $(OBJS) $(LDFLAGS)
+ $(CC) $(CFLAGS) -o $(BIN) $(OBJS) $(LDFLAGS)
--- a/README.md
+++ b/README.md
@@ -5,28 +5,32 @@
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.
+It's around 70-80kLOC of 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.
+It uses the PPU and DSP implementation from [LakeSnes](https://github.com/elzo-d/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
+## Dependencies
-Put the ROM in tables/zelda3.sfc. The ROM needs to be the US ROM with SHA256 hash `66871d66be19ad2c34c927d6b14cd8eb6fc3181965b6e517cb361f7316009cfb`.
+- the `libsdl2-dev` library (ubuntu: `apt install libsdl2-dev`, macOS: `brew install sdl2`). On Windows, it's installed automatically with NuGet.
+- a `tables/zelda3.sfc` US ROM file (for asset extraction step only) with SHA256 hash `66871d66be19ad2c34c927d6b14cd8eb6fc3181965b6e517cb361f7316009cfb`.
+- The `pillow` and `pyyaml` python dependencies used by the assets extractor. `pip install pillow pyyaml`
+## Compiling
+
`cd tables`
-Install python dependencies: `pip install pillow` and `pip install pyyaml`
+Run `python3 extract_resources.py` to extract resources from the ROM into a more human readable format.
-Run `python extract_resources.py` to extract resources from the ROM into a more human readable format.
+Run `python3 compile_resources.py` to produce .h files that get included by the C code.
-Run `python compile_resources.py` to produce .h files that gets included by the C++ code.
### Windows
-Build the .sln file with Visual Studio
+First extract and compile resources, see above. Then build the .sln file with Visual Studio.
### Linux/macOS
#### Dependencies
@@ -35,20 +39,19 @@
macOS: `brew install sdl2`
#### Building
-Make sure you are in the root directory.
+First extract and compile resources, see above. Then make sure you are in the root directory.
```
-clang++ `sdl2-config --cflags` -O2 -ozelda3 *.cpp snes/*.cpp `sdl2-config --libs`
+clang++ `sdl2-config --cflags` -O2 -ozelda3 *.c snes/*.c `sdl2-config --libs`
```
or
`make -j$(nproc)`
-
## 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.
+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 |
| ------ | ----------- |
--- /dev/null
+++ b/ancilla.c
@@ -1,0 +1,7363 @@
+#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 };
+typedef struct QuakeItem {
+ int8 x, y;
+ uint8 f;
+} QuakeItem;
+static const QuakeItem kQuakeItems[] = {
+ {0, -16, 0x00},
+ {0, -16, 0x01},
+ {0, -16, 0x02},
+ {0, -16, 0x03},
+ {0, -16, 0x43},
+ {0, -16, 0x42},
+ {0, -16, 0x41},
+ {0, -16, 0x40},
+ {0, -16, 0x40}, {14, -8, 0x84},
+ {29, -8, 0x44}, {13, -7, 0x84},
+ {31, -7, 0x44}, {47, -4, 0x84},
+ {49, -11, 0x06}, {63, -5, 0x44}, {47, -4, 0x84},
+ {36, -17, 0x08}, {49, -11, 0x06}, {63, -5, 0x44}, {78, 4, 0x08},
+ {22, -31, 0x08}, {36, -17, 0x08}, {78, 4, 0x08}, {93, 20, 0x08},
+ {7, -46, 0x08}, {23, -45, 0x48}, {22, -31, 0x08}, {93, 20, 0x08}, {93, 36, 0x48},
+ {-7, -61, 0x08}, {37, -59, 0x48}, {7, -46, 0x08}, {23, -45, 0x48}, {93, 36, 0x48}, {93, 52, 0x08},
+ {-22, -75, 0x08}, {47, -74, 0x01}, {-8, -61, 0x08}, {36, -60, 0x48}, {93, 52, 0x08}, {108, 67, 0x08},
+ {-37, -90, 0x08}, {-22, -75, 0x08}, {47, -74, 0x01}, {59, -62, 0x81}, {108, 67, 0x08}, {121, 80, 0x08},
+ {-44, -104, 0xc9}, {-37, -90, 0x08}, {73, -74, 0x48}, {59, -62, 0x81}, {121, 80, 0x08},
+ {-44, -120, 0x09}, {-44, -104, 0xc9}, {87, -89, 0x48}, {73, -74, 0x48},
+ {-44, -120, 0x09}, {102, -104, 0x48}, {87, -89, 0x48},
+ {102, -104, 0x48}, {87, -89, 0x48},
+ {112, -116, 0x48}, {102, -104, 0x48},
+ {112, -116, 0x48},
+ {-13, -16, 0x00},
+ {-13, -16, 0x01},
+ {-13, -16, 0x02},
+ {-13, -16, 0x03},
+ {-11, -16, 0x43},
+ {-11, -16, 0x42},
+ {-11, -16, 0x41},
+ {-11, -16, 0x40}, {-24, -10, 0x04},
+ {-38, -18, 0x08}, {-24, -10, 0x04}, {-40, -7, 0xc4},
+ {-45, -33, 0xc9}, {-38, -18, 0x08}, {-57, -7, 0x04}, {-40, -7, 0xc4},
+ {-48, -45, 0x07}, {-45, -33, 0xc9}, {-57, -7, 0x04}, {-71, 2, 0x48},
+ {-48, -45, 0x06}, {-71, 2, 0x48}, {-70, 18, 0x08},
+ {-48, -45, 0x05}, {-70, 18, 0x08}, {-56, 33, 0x08},
+ {-48, -45, 0x07}, {-54, 34, 0x08}, {-54, 49, 0x88},
+ {-48, -45, 0x06}, {-54, 49, 0x88}, {-69, 64, 0x88},
+ {-48, -45, 0x07}, {-69, 64, 0x88}, {-85, 73, 0xc4},
+ {-48, -45, 0x05}, {-101, 73, 0x04}, {-85, 73, 0xc4},
+ {-60, -53, 0x08}, {-48, -45, 0x06}, {-101, 73, 0x04}, {-116, 77, 0xc4},
+ {-75, -67, 0x08}, {-60, -53, 0x08}, {-128, 76, 0x04}, {-116, 77, 0xc4},
+ {-90, -82, 0x08}, {-75, -67, 0x08}, {-128, 76, 0x04},
+ {-105, -97, 0x08}, {-90, -82, 0x08},
+ {-120, -111, 0x08}, {-105, -97, 0x08},
+ {-120, -111, 0x08},
+ {0, -5, 0x0a},
+ {0, -5, 0x0b},
+ {2, -3, 0x0c},
+ {1, -3, 0x0d},
+ {0, -3, 0x8d},
+ {1, -3, 0x8c},
+ {1, -3, 0x8b},
+ {1, -3, 0x8a}, {-6, 12, 0x89},
+ {-6, 12, 0x89}, {-10, 28, 0xc9},
+ {-10, 28, 0x49}, {-8, 44, 0x89},
+ {-8, 44, 0x89}, {-10, 56, 0x02},
+ {-10, 56, 0x02}, {-23, 70, 0x48}, {5, 70, 0x08},
+ {-23, 70, 0x48}, {5, 70, 0x08}, {-38, 85, 0x48}, {19, 85, 0x08},
+ {-38, 85, 0x48}, {19, 85, 0x08}, {-52, 99, 0x48}, {33, 101, 0x08},
+ {-52, 99, 0x48}, {33, 101, 0x08}, {-66, 113, 0x48}, {47, 115, 0x08},
+ {-66, 113, 0x48}, {47, 115, 0x08},
+};
+static const uint8 kQuakeItemPos[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 17, 21, 25, 30,
+ 36, 42, 48, 53, 57, 60, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 107, 111, 114, 116, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 130, 132, 134, 137, 141, 145, 149, 151
+};
+static const QuakeItem kQuakeItems2[] = {
+ {-96, 112, 0x20},
+ {-96, 112, 0x21},
+ {-96, 112, 0x66},
+ {-96, 112, 0x22},
+ {-96, 112, 0x23},
+ {-96, 112, 0x63},
+ {-96, 112, 0x62},
+ {-96, 112, 0x26},
+ {-96, 112, 0x27}, {-86, 124, 0x28},
+ {-86, 124, 0x28}, {-72, -117, 0x28},
+ {-72, -117, 0x28}, {-59, -102, 0xa1},
+ {-59, -102, 0xa1}, {-44, -116, 0x68},
+ {-44, -116, 0x68}, {-29, 126, 0x68},
+ {-29, 126, 0x68},
+ {-19, 125, 0xc5},
+ {-112, 96, 0x2a},
+ {-112, 96, 0x2b},
+ {-112, 96, 0x2c},
+ {-112, 96, 0x2d},
+ {-119, 82, 0x29}, {-112, 96, 0x2a},
+ {-123, 66, 0xe9}, {-119, 82, 0x29},
+ {-121, 50, 0x29}, {-123, 66, 0xe9},
+ {126, 34, 0x28}, {-115, 34, 0x68}, {-121, 50, 0x29},
+ {-106, 18, 0xa9}, {111, 19, 0x28}, {126, 34, 0x28}, {-115, 34, 0x68},
+ {-100, 2, 0x68}, {102, 4, 0xe9}, {-106, 18, 0xa9}, {111, 19, 0x28},
+ {-91, -14, 0xa9}, {95, -11, 0x28}, {-100, 2, 0x68}, {102, 4, 0xe9},
+ {96, 112, 0x60},
+ {96, 112, 0x61},
+ {96, 112, 0x26},
+ {96, 112, 0x62},
+ {96, 112, 0x63},
+ {96, 112, 0x23},
+ {96, 112, 0x22},
+ {96, 112, 0x66},
+ {85, 111, 0xe8}, {96, 112, 0x67},
+ {70, 104, 0x24}, {85, 111, 0xe8},
+ {70, 104, 0x24}, {54, 108, 0xe4},
+ {40, 100, 0x28}, {38, 107, 0x24}, {54, 108, 0xe4},
+ {25, 85, 0x28}, {40, 100, 0x28}, {38, 107, 0x24}, {22, 110, 0xe4},
+ {11, 70, 0x28}, {25, 85, 0x28}, {7, 108, 0x24}, {22, 110, 0xe4},
+ {11, 70, 0x28}, {7, 108, 0x24},
+ {112, 112, 0x2a},
+ {112, 112, 0x2b},
+ {112, 112, 0x2c},
+ {112, 112, 0x2d},
+ {112, 112, 0x2a}, {108, 125, 0x29},
+ {108, 125, 0x29}, {114, -116, 0x28},
+ {114, -116, 0x28}, {124, -100, 0x29},
+ {124, -100, 0x29}, {123, -84, 0xe9},
+ {123, -84, 0xe9}, {117, -74, 0xe4}, {-124, -69, 0x28},
+ {117, -74, 0xe4}, {-124, -69, 0x28}, {103, -67, 0x68}, {-110, -54, 0x28},
+ {103, -67, 0x68}, {-110, -54, 0x28}, {95, -52, 0x69}, {-102, -39, 0x29},
+ {95, -52, 0x69}, {-102, -39, 0x29}, {96, -36, 0xe9}, {-102, -24, 0xe9},
+ {96, -36, 0xe9}, {-102, -24, 0xe9},
+ {-123, -14, 0x29}, {-115, -14, 0x2e}, {49, -12, 0x28},
+};
+static const uint8 kQuakeItemPos2[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 19, 20, 21, 22, 23, 24, 26, 28, 30, 33, 37, 41, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 57, 59, 62, 66, 70, 72, 73, 74, 75, 76, 78, 80, 82, 84, 87, 91, 95, 99, 101, 104
+};
+static const uint8 kReceiveItem_Tab4[3] = {9, 5, 5};
+static const uint8 kReceiveItem_Tab5[3] = {0x24, 0x25, 0x26};
+static const uint8 kReceiveItem_Tab0[3] = {5, 1, 4};
+static const int16 kReceiveItemMsgs[76] = {
+ -1, 0x70, 0x77, 0x52, -1, 0x78, 0x78, 0x62, 0x61, 0x66, 0x69, 0x53, 0x52, 0x56, -1, 0x64,
+ 0x63, 0x65, 0x51, 0x54, 0x67, 0x68, 0x6b, 0x77, 0x79, 0x55, 0x6e, 0x58, 0x6d, 0x5d, 0x57, 0x5e,
+ -1, 0x74, 0x75, 0x76, -1, 0x5f, 0x158, -1, 0x6a, 0x5c, 0x8f, 0x71, 0x72, 0x73, 0x71, 0x72,
+ 0x73, 0x6a, 0x6c, 0x60, -1, -1, -1, 0x59, 0x84, 0x5a, -1, -1, -1, -1, -1, 0x159,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 0xdb, 0x67, 0x7c,
+};
+static const int16 kReceiveItemMsgs2[2] = {0x5b, 0x83};
+static const int16 kReceiveItemMsgs3[4] = {-1, 0x155, 0x156, 0x157};
+static const uint8 kTravelBird_DmaStuffs[4] = {0, 0x20, 0x40, 0xe0};
+static const int8 kTravelBird_Draw_X[3] = {0, -9, -9};
+static const int8 kTravelBird_Draw_Y[3] = {0, 12, 20};
+static const uint8 kTravelBird_Draw_Char[3] = {0xe, 0, 2};
+static const uint8 kTravelBird_Draw_Flags[3] = {0x22, 0x2e, 0x2e};
+static const int8 kSomarianBlock_Coll_X[12] = {0, 0, -8, 8, 0, 0, 0, 0, 8, -8, -8, 8};
+static const int8 kSomarianBlock_Coll_Y[12] = {-8, 8, 0, 0, 0, 0, 0, 0, -8, 8, -8, 8};
+static HandlerFuncK *const kAncilla_Funcs[67] = {
+ &Ancilla01_SomariaBullet,
+ &Ancilla02_FireRodShot,
+ &Ancilla_Empty,
+ &Ancilla04_BeamHit,
+ &Ancilla05_Boomerang,
+ &Ancilla06_WallHit,
+ &Ancilla07_Bomb,
+ &Ancilla08_DoorDebris,
+ &Ancilla09_Arrow,
+ &Ancilla0A_ArrowInTheWall,
+ &Ancilla0B_IceRodShot,
+ &Ancilla_SwordBeam,
+ &Ancilla0D_SpinAttackFullChargeSpark,
+ &Ancilla33_BlastWallExplosion,
+ &Ancilla33_BlastWallExplosion,
+ &Ancilla33_BlastWallExplosion,
+ &Ancilla11_IceRodWallHit,
+ &Ancilla33_BlastWallExplosion,
+ &Ancilla13_IceRodSparkle,
+ &Ancilla_Unused_14,
+ &Ancilla15_JumpSplash,
+ &Ancilla16_HitStars,
+ &Ancilla17_ShovelDirt,
+ &Ancilla18_EtherSpell,
+ &Ancilla19_BombosSpell,
+ &Ancilla1A_PowderDust,
+ &Ancilla_SwordWallHit,
+ &Ancilla1C_QuakeSpell,
+ &Ancilla1D_ScreenShake,
+ &Ancilla1E_DashDust,
+ &Ancilla1F_Hookshot,
+ &Ancilla20_Blanket,
+ &Ancilla21_Snore,
+ &Ancilla22_ItemReceipt,
+ &Ancilla23_LinkPoof,
+ &Ancilla24_Gravestone,
+ &Ancilla_Unused_25,
+ &Ancilla26_SwordSwingSparkle,
+ &Ancilla27_Duck,
+ &Ancilla28_WishPondItem,
+ &Ancilla29_MilestoneItemReceipt,
+ &Ancilla2A_SpinAttackSparkleA,
+ &Ancilla2B_SpinAttackSparkleB,
+ &Ancilla2C_SomariaBlock,
+ &Ancilla2D_SomariaBlockFizz,
+ &Ancilla2E_SomariaBlockFission,
+ &Ancilla2F_LampFlame,
+ &Ancilla30_ByrnaWindupSpark,
+ &Ancilla31_ByrnaSpark,
+ &Ancilla32_BlastWallFireball,
+ &Ancilla33_BlastWallExplosion,
+ &Ancilla34_SkullWoodsFire,
+ &Ancilla35_MasterSwordReceipt,
+ &Ancilla36_Flute,
+ &Ancilla37_WeathervaneExplosion,
+ &Ancilla38_CutsceneDuck,
+ &Ancilla39_SomariaPlatformPoof,
+ &Ancilla3A_BigBombExplosion,
+ &Ancilla3B_SwordUpSparkle,
+ &Ancilla3C_SpinAttackChargeSparkle,
+ &Ancilla3D_ItemSplash,
+ &Ancilla_RisingCrystal,
+ &Ancilla3F_BushPoof,
+ &Ancilla40_DwarfPoof,
+ &Ancilla41_WaterfallSplash,
+ &Ancilla42_HappinessPondRupees,
+ &Ancilla43_GanonsTowerCutscene,
+};
+uint16 Ancilla_GetX(int k) {
+ return ancilla_x_lo[k] | ancilla_x_hi[k] << 8;
+}
+
+uint16 Ancilla_GetY(int k) {
+ return ancilla_y_lo[k] | ancilla_y_hi[k] << 8;
+}
+
+void Ancilla_SetX(int k, uint16 x) {
+ ancilla_x_lo[k] = x;
+ ancilla_x_hi[k] = x >> 8;
+}
+
+void Ancilla_SetY(int k, uint16 y) {
+ ancilla_y_lo[k] = y;
+ ancilla_y_hi[k] = y >> 8;
+}
+
+int Ancilla_AllocHigh() {
+ for (int k = 9; k >= 0; k--) {
+ if (ancilla_type[k] == 0)
+ return k;
+ }
+ return -1;
+}
+
+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;
+ }
+
+ static const int8 kHookShot_Move_X[4] = {0, 0, 8, -8};
+ static const int8 kHookShot_Move_Y[4] = {8, -9, 0, 0};
+ static const uint8 kHookShot_Draw_Flags[12] = {0, 0, 0xff, 0x80, 0x80, 0xff, 0x40, 0xff, 0x40, 0, 0xff, 0};
+ static const uint8 kHookShot_Draw_Char[12] = {9, 0xa, 0xff, 9, 0xa, 0xff, 9, 0xff, 0xa, 9, 0xff, 0xa};
+
+ Point16U info;
+do_draw:
+ Ancilla_PrepOamCoord(k, &info);
+ if (ancilla_L[k])
+ oam_priority_value = 0x3000;
+ OamEnt *oam = GetOamCurPtr();
+
+ int j = ancilla_dir[k] * 3;
+ int x = info.x, y = info.y;
+ for (int i = 2; i >= 0; i--, j++) {
+ if (kHookShot_Draw_Char[j] != 0xff) {
+ Ancilla_SetOam_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]);
+ }
+ Point16U pt;
+endif_12:
+ 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;
+ }
+ }
+ uint8 astep;
+label_b:
+
+
+ astep = ancilla_step[k];
+ if (astep != 0)
+ oam = GTCutscene_SparkleALot(oam);
+
+ for (int j = 6; j >= 0; j--) {
+ if (submodule_index == 0 && astep != 1 && !(frame_counter & 1))
+ breaktowerseal_var3[j] = breaktowerseal_var3[j] + 1 & 63;
+ AncillaRadialProjection arp = Ancilla_GetRadialProjection(breaktowerseal_var3[j], breaktowerseal_var4);
+ int x = (arp.r6 ? -arp.r4 : arp.r4) + breaktowerseal_x - 8 - BG2HOFS_copy;
+ int y = (arp.r2 ? -arp.r0 : arp.r0) + breaktowerseal_y - 8 - BG2VOFS_copy;
+
+ breaktowerseal_base_sparkle_x_lo[j] = x;
+ breaktowerseal_base_sparkle_x_hi[j] = x >> 8;
+
+ breaktowerseal_base_sparkle_y_lo[j] = y;
+ breaktowerseal_base_sparkle_y_hi[j] = y >> 8;
+
+ AncillaDraw_GTCutsceneCrystal(oam, x, y);
+ oam++;
+ }
+ Point16U info;
+label_a:
+ Ancilla_PrepAdjustedOamCoord(k, &info);
+
+ breaktowerseal_base_sparkle_x_lo[7] = info.x;
+ breaktowerseal_base_sparkle_x_hi[7] = info.x >> 8;
+ breaktowerseal_base_sparkle_y_lo[7] = info.y;
+ breaktowerseal_base_sparkle_y_hi[7] = info.y >> 8;
+
+ AncillaDraw_GTCutsceneCrystal(oam, info.x, info.y);
+
+ if (!ancilla_step[k])
+ AncillaAdd_OccasionalSparkle(k);
+ else if (!submodule_index)
+ GTCutscene_ActivateSparkle();
+}
+
+void AncillaDraw_GTCutsceneCrystal(OamEnt *oam, int x, int y) { // 88ceaa
+ 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
+ // snes bug: R14 is used in tile detection already
+ // unless this is here it the memcmp will fail when entering/leaving a water through steps quickly
+ if (g_ram[kRam_BugsFixed] >= kBugFix_PolyRenderer)
+ BYTE(R14) = y + 1;
+
+ 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);
+ }
+}
+
--- a/ancilla.cpp
+++ /dev/null
@@ -1,7363 +1,0 @@
-#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
- // snes bug: R14 is used in tile detection already
- // unless this is here it the memcmp will fail when entering/leaving a water through steps quickly
- if (g_ram[kRam_BugsFixed] >= kBugFix_PolyRenderer)
- BYTE(R14) = y + 1;
-
- 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);
- }
-}
-
--- a/ancilla.h
+++ b/ancilla.h
@@ -1,21 +1,22 @@
#pragma once
+#include "types.h"
#include "zelda_rtl.h"
#include "sprite.h"
-struct CheckPlayerCollOut {
+typedef struct CheckPlayerCollOut {
uint16 r4, r6;
uint16 r8, r10;
-};
+} CheckPlayerCollOut;
-struct AncillaOamInfo {
+typedef struct AncillaOamInfo {
uint8 x;
uint8 y;
uint8 flags;
-};
+} AncillaOamInfo;
-struct AncillaRadialProjection {
+typedef struct AncillaRadialProjection {
uint8 r0, r2, r4, r6;
-};
+} AncillaRadialProjection;
uint16 Ancilla_GetX(int k);
uint16 Ancilla_GetY(int k);
--- /dev/null
+++ b/attract.c
@@ -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);
+}
+
--- a/attract.cpp
+++ /dev/null
@@ -1,1092 +1,0 @@
-#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);
-}
-
--- a/attract.h
+++ b/attract.h
@@ -1,8 +1,8 @@
#pragma once
-struct AttractOamInfo {
+typedef struct AttractOamInfo {
int8 x, y;
uint8 c, f, e;
-};
+} AttractOamInfo;
extern const uint16 kMapMode_Zooms1[224];
--- a/dsp_regs.h
+++ /dev/null
@@ -1,108 +1,0 @@
-#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.c
@@ -1,0 +1,8788 @@
+#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 m, k, dma_ptr;
+
+ if (skip_anim) {
+ door_animation_step_indicator = 16;
+ goto step12;
+ }
+
+ door_animation_step_indicator++;
+ if (door_animation_step_indicator != 4) {
+ if (door_animation_step_indicator != 12)
+ goto middle;
+step12:
+ m = kUpperBitmasks[dung_bg2_attr_table[dung_cur_door_pos] & 7];
+ dung_door_opened_incl_adjacent |= m;
+ dung_door_opened |= m;
+ ctr = 4;
+ }
+ door_open_closed_counter = ctr;
+
+ k = dung_bg2_attr_table[dung_cur_door_pos] & 0xf;
+ dma_ptr = DrawDoorOpening_Step1(k, 0);
+ Dungeon_PrepOverlayDma_nextPrep(dma_ptr, dung_door_tilemap_address[k]);
+ sound_effect_2 = 21;
+ nmi_copy_packets_flag = 1;
+
+middle:
+ if (door_animation_step_indicator == 16) {
+ Dungeon_LoadToggleDoorAttr_OtherEntry(dung_bg2_attr_table[dung_cur_door_pos] & 0xf);
+ if (dung_bg2_attr_table[dung_cur_door_pos] >= 0xf0) {
+ k = dung_bg2_attr_table[dung_cur_door_pos] & 0xf;
+ uint8 door_type = door_type_and_slot[k];
+ if (door_type >= kDoorType_StairMaskLocked0 && door_type <= kDoorType_StairMaskLocked3)
+ DrawCompletelyOpenDoor();
+ }
+ submodule_index = 0;
+ }
+}
+
+const DungPalInfo *GetDungPalInfo(int idx) {
+ return &kDungPalinfos[idx];
+}
+
+uint16 Dungeon_GetTeleMsg(int room) {
+ return kDungeonRoomTeleMsg[room];
+}
+
+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) {
+ int j;
+handle_f0:
+ j = a & 0xf;
+ a = door_type_and_slot[j] & 0xfe;
+ if (a != kDoorType_BreakableWall && a != 0x2A && a != 0x2E)
+ return;
+ dung_cur_door_pos = k;
+ door_debris_x[r14] = ((dung_door_tilemap_address[j] & 0x7e) << 2) + dung_loade_bgoffs_h_copy;
+ door_debris_y[r14] = ((dung_door_tilemap_address[j] & 0x1f80) >> 4) + dung_loade_bgoffs_v_copy;
+ door_debris_direction[r14] = dung_door_direction[j] & 3;
+ sound_effect_2 = 0x1b;
+ submodule_index = 9;
+ return;
+ }
+
+ a = dung_bg2_attr_table[k += 2];
+ if (a == 0x62) goto handle_62;
+ if ((a & 0xf0) == 0xf0) goto handle_f0;
+
+ a = dung_bg2_attr_table[k += 2];
+ if (a == 0x62) goto handle_62;
+ if ((a & 0xf0) == 0xf0) goto handle_f0;
+
+ k += 0x7c;
+ }
+
+}
+
+int DrawDoorOpening_Step1(int door, int dma_ptr) { // 81d2e8
+ dung_cur_door_idx = door * 2;
+ dung_which_key_x2 = door * 2;
+ switch (dung_door_direction[door] & 3) {
+ case 0: return DoorDoorStep1_North(door, dma_ptr);
+ case 1: return DoorDoorStep1_South(door, dma_ptr);
+ case 2: return DoorDoorStep1_West(door, dma_ptr);
+ case 3: return DoorDoorStep1_East(door, dma_ptr);
+ }
+ return 0;
+}
+
+void DrawShutterDoorSteps(int door) { // 81d311
+ dung_cur_door_idx = door * 2;
+ dung_which_key_x2 = door * 2;
+ switch (dung_door_direction[door] & 3) {
+ case 0: GetDoorDrawDataIndex_North_clean_door_index(door); break;
+ case 1: GetDoorDrawDataIndex_South_clean_door_index(door); break;
+ case 2: GetDoorDrawDataIndex_West_clean_door_index(door); break;
+ case 3: GetDoorDrawDataIndex_East_clean_door_index(door); break;
+ }
+}
+
+void DrawEyeWatchDoor(int door) { // 81d33a
+ dung_cur_door_idx = door * 2;
+ dung_which_key_x2 = door * 2;
+ switch (dung_door_direction[door] & 3) {
+ case 0: DrawDoorToTileMap_North(door, door); break;
+ case 1: DrawDoorToTileMap_South(door, door); break;
+ case 2: DrawDoorToTileMap_West(door, door); break;
+ case 3: DrawDoorToTileMap_East(door, door); break;
+ }
+}
+
+void Door_BlastWallExploding_Draw(int dsto) { // 81d373
+ uint16 *dst = &dung_bg2[dsto];
+ const uint16 *src = SrcPtr(0x31ea);
+ ClearExplodingWallFromTileMap_ClearOnePair(dst, src);
+ dst += 2;
+ uint16 v = src[24];
+ for (int n = dung_unk_blast_walls_2 - 1; n; n--) {
+ for (int j = 0; j < 12; j++)
+ dst[XY(0, j)] = v;
+ dst++;
+ }
+ ClearExplodingWallFromTileMap_ClearOnePair(dst, src + 25);
+}
+
+void OperateShutterDoors() { // 81d38f
+ int anim_dst = 0;
+ uint8 y = 2;
+
+ if (++door_animation_step_indicator != 4) {
+ y = dung_flag_trapdoors_down ? 0 : 4;
+ if (door_animation_step_indicator != 8)
+ goto getout;
+ }
+ door_open_closed_counter = y;
+
+ for (dung_cur_door_pos = 0; dung_cur_door_pos != 0x18; dung_cur_door_pos += 2) {
+ int j = dung_cur_door_pos >> 1;
+ uint8 door_type = door_type_and_slot[j] & 0xfe;
+ if (door_type != kDoorType_Shutter && door_type != kDoorType_ShuttersTwoWay)
+ continue;
+
+ int mask = kUpperBitmasks[j];
+ if (!dung_flag_trapdoors_down) {
+ if (dung_door_opened_incl_adjacent & mask)
+ continue;
+ if (door_animation_step_indicator == 8) {
+ sound_effect_2 = 21;
+ dung_door_opened_incl_adjacent ^= mask;
+ }
+ } else {
+ if (!(dung_door_opened_incl_adjacent & mask))
+ continue;
+ if (door_animation_step_indicator == 8) {
+ sound_effect_2 = 22;
+ dung_door_opened_incl_adjacent ^= mask;
+ }
+ }
+ DrawShutterDoorSteps(j);
+ anim_dst = Dungeon_PrepOverlayDma_nextPrep(anim_dst, dung_door_tilemap_address[j]);
+ if (door_animation_step_indicator == 8)
+ Dungeon_LoadToggleDoorAttr_OtherEntry(j);
+ }
+ dung_cur_door_pos -= 2;
+
+ if (anim_dst != 0) {
+ nmi_disable_core_updates = nmi_copy_packets_flag = 1;
+getout:
+ if (BYTE(door_animation_step_indicator) != 0x10)
+ return;
+ }
+ submodule_index = 0;
+ nmi_copy_packets_flag = 0;
+}
+
+void OpenCrackedDoor() { // 81d469
+ Dungeon_OpeningLockedDoor_Combined(true);
+}
+
+void Dungeon_LoadToggleDoorAttr_OtherEntry(int door) { // 81d51c
+ Dungeon_LoadSingleDoorAttribute(door);
+ Dungeon_LoadSingleDoorTileAttribute();
+}
+
+void Dungeon_LoadSingleDoorTileAttribute() { // 81d51f
+ for (int i = 0; i != dung_num_toggle_floor; i += 2) {
+ int j = dung_toggle_floor_pos[i >> 1];
+ if ((dung_bg2_attr_table[j] & 0xf0) == 0x80) {
+ uint16 attr = *(uint16 *)&dung_bg2_attr_table[j];
+ WriteAttr2(j + XY(0, 0), attr | 0x1010);
+ WriteAttr2(j + XY(0, 1), attr | 0x1010);
+ } else {
+ uint16 attr = *(uint16 *)&dung_bg1_attr_table[j];
+ WriteAttr1(j + XY(0, 0), attr | 0x1010);
+ WriteAttr1(j + XY(0, 1), attr | 0x1010);
+ }
+ }
+ for (int i = 0; i != dung_num_toggle_palace; i += 2) {
+ int j = dung_toggle_palace_pos[i >> 1];
+ if ((dung_bg2_attr_table[j] & 0xf0) == 0x80) {
+ uint16 attr = *(uint16 *)&dung_bg2_attr_table[j];
+ WriteAttr2(j + XY(0, 0), attr | 0x2020);
+ WriteAttr2(j + XY(0, 1), attr | 0x2020);
+ } else {
+ uint16 attr = *(uint16 *)&dung_bg1_attr_table[j];
+ WriteAttr1(j + XY(0, 0), attr | 0x2020);
+ WriteAttr1(j + XY(0, 1), attr | 0x2020);
+ }
+ }
+}
+
+void DrawCompletelyOpenDoor() { // 81d5aa
+ uint16 t;
+ int i;
+
+ for (i = 0, t = 0x3030; i != dung_num_inter_room_upnorth_stairs; i += 2, t += 0x101) {}
+
+ for (; i != dung_num_wall_upnorth_spiral_stairs; i += 2, t += 0x101) {
+ int pos = dung_inter_starcases[i >> 1];
+ WriteAttr2(pos + XY(1, 0), 0x5e5e);
+ WriteAttr2(pos + XY(1, 1), t);
+ WriteAttr2(pos + XY(1, 2), 0);
+ WriteAttr2(pos + XY(1, 3), 0);
+ }
+
+ for (; i != dung_num_wall_upnorth_spiral_stairs_2; i += 2, t += 0x101) {
+ int pos = dung_inter_starcases[i >> 1];
+ WriteAttr2(pos + XY(1, 0), 0x5f5f);
+ WriteAttr2(pos + XY(1, 1), t);
+ WriteAttr2(pos + XY(1, 2), 0);
+ WriteAttr2(pos + XY(1, 3), 0);
+ }
+
+ for (; i != dung_num_inter_room_upnorth_straight_stairs; i += 2, t += 0x101) {}
+ for (; i != dung_num_inter_room_upsouth_straight_stairs; i += 2, t += 0x101) {}
+
+ t = (t & 0x707) | 0x3434;
+
+ for (; i != dung_num_inter_room_southdown_stairs; i += 2, t += 0x101) {}
+
+ for (; i != dung_num_wall_downnorth_spiral_stairs; i += 2, t += 0x101) {
+ int pos = dung_inter_starcases[i >> 1];
+ WriteAttr2(pos + XY(1, 0), 0x5e5e);
+ WriteAttr2(pos + XY(1, 1), t);
+ WriteAttr2(pos + XY(1, 2), 0);
+ WriteAttr2(pos + XY(1, 3), 0);
+ }
+
+ for (; i != dung_num_wall_downnorth_spiral_stairs_2; i += 2, t += 0x101) {
+ int pos = dung_inter_starcases[i >> 1];
+ WriteAttr2(pos + XY(1, 0), 0x5f5f);
+ WriteAttr2(pos + XY(1, 1), t);
+ WriteAttr2(pos + XY(1, 2), 0);
+ WriteAttr2(pos + XY(1, 3), 0);
+ }
+}
+
+void Dungeon_ClearAwayExplodingWall() { // 81d6c1
+ flag_is_link_immobilized = 6;
+ flag_unk1 = 6;
+ if (BYTE(messaging_buf[0]) != 6)
+ return;
+
+ word_7E045E = 0;
+ g_ram[12] = 0;
+ door_animation_step_indicator = 0;
+ dung_cur_door_idx = dung_unk_blast_walls_3;
+ int dsto = (dung_door_tilemap_address[dung_unk_blast_walls_3 >> 1] -= 2) >> 1;
+
+ Door_BlastWallExploding_Draw(dsto);
+ ClearAndStripeExplodingWall(dsto);
+
+ WORD(nmi_disable_core_updates) = 0xffff;
+ dung_unk_blast_walls_2 += 2;
+
+ if (dung_unk_blast_walls_2 == 21) {
+ int m = kUpperBitmasks[dung_unk_blast_walls_3 >> 1];
+ dung_door_opened_incl_adjacent |= m;
+ dung_door_opened |= m;
+
+ if (dung_door_direction[dung_unk_blast_walls_3 >> 1] & 2) {
+ dung_blastwall_flag_x = 1;
+ quadrant_fullsize_x = 2;
+ } else {
+ dung_blastwall_flag_y = 1;
+ quadrant_fullsize_y = 2;
+ }
+ WORD(quadrant_fullsize_x_cached) = WORD(quadrant_fullsize_x);
+ Door_LoadBlastWallAttr(dung_unk_blast_walls_3 >> 1);
+ dung_unk_blast_walls_2 = 0;
+ dung_unk_blast_walls_3 = 0;
+ Dungeon_FlagRoomData_Quadrants();
+ flag_is_link_immobilized = 0;
+ flag_unk1 = 0;
+ }
+ nmi_copy_packets_flag = 3;
+}
+
+uint16 Dungeon_CheckForAndIDLiftableTile() { // 81d748
+ uint16 x = (link_x_coord + kDungeon_QueryIfTileLiftable_x[link_direction_facing >> 1]) & 0x1f8;
+ uint16 y = (link_y_coord + kDungeon_QueryIfTileLiftable_y[link_direction_facing >> 1]) & 0x1f8;
+ uint16 xy = (y << 3) | (x >> 3) | (link_is_on_lower_level ? 0x1000 : 0x0);
+
+ uint8 attr = dung_bg2_attr_table[xy];
+ if ((attr & 0xf0) != 0x70)
+ return 0xffff; // clc
+
+ uint16 rt = dung_replacement_tile_state[attr & 0xf];
+ if (rt == 0)
+ return 0xffff;
+ if ((rt & 0xf0f0) == 0x2020)
+ return 0x55;
+ return kDungeon_QueryIfTileLiftable_rv[rt & 0xf];
+}
+
+void Dungeon_PushBlock_Handler() { // 81d81b
+ while (dung_misc_objs_index != dung_index_of_torches_start) {
+ int k = dung_misc_objs_index >> 1;
+ int st = dung_replacement_tile_state[k];
+ if (st == 1) {
+ RoomDraw_16x16Single(k * 2);
+ dung_object_tilemap_pos[k] += kPushBlockMoveDistances[push_block_direction >> 1];
+ dung_replacement_tile_state[k] = 2;
+ } else if (st == 2) {
+ PushBlock_Slide(k * 2);
+
+ if (dung_replacement_tile_state[dung_misc_objs_index >> 1] == 3) {
+ PushBlock_CheckForPit(dung_misc_objs_index);
+ dung_replacement_tile_state[dung_misc_objs_index >> 1]++;
+ }
+ } else if (st == 4) {
+ PushBlock_HandleFalling(k * 2);
+ }
+
+ dung_misc_objs_index += 2;
+ }
+}
+
+void RoomDraw_16x16Single(uint8 index) { // 81d828
+ index >>= 1;
+ uint16 pos = (dung_object_tilemap_pos[index] & 0x3fff) >> 1;
+ Dungeon_Store2x2(pos,
+ replacement_tilemap_UL[index],
+ replacement_tilemap_LL[index],
+ replacement_tilemap_UR[index],
+ replacement_tilemap_LR[index],
+ attributes_for_tile[replacement_tilemap_LR[index] & 0x3ff]);
+}
+
+void PushBlock_CheckForPit(uint8 y) { // 81d8d4
+ y >>= 1;
+ if (!(dung_object_tilemap_pos[y] & 0x4000))
+ dung_flag_movable_block_was_pushed ^= 1;
+
+ int p = (dung_object_tilemap_pos[y] & 0x3fff) >> 1;
+ uint8 attr = dung_bg2_attr_table[p];
+ if (attr == 0x20) { // fall into pit
+ sound_effect_1 = 0x20;
+ int k = dung_object_pos_in_objdata[y] >> 2;
+ movable_block_datas[k].room = dung_hdr_travel_destinations[0];
+ movable_block_datas[k].tilemap = dung_object_tilemap_pos[y];
+ return;
+ }
+
+ int i = (index_of_changable_dungeon_objs[1] - 1) == y;
+ index_of_changable_dungeon_objs[i] = 0;
+
+ if (attr == 0x23) {
+ related_to_trapdoors_somehow = dung_flag_trapdoors_down ^ 1;
+ dung_replacement_tile_state[y] = 4;
+ } else {
+ dung_replacement_tile_state[y] = 0xffff;
+ }
+ Dungeon_Store2x2(p, 0x922, 0x932, 0x923, 0x933, 0x27);
+}
+
+uint8 Dungeon_LiftAndReplaceLiftable(Point16U *pt) { // 81d9ec
+ uint16 x = link_x_coord + kDungeon_QueryIfTileLiftable_x[link_direction_facing >> 1];
+ uint16 y = link_y_coord + kDungeon_QueryIfTileLiftable_y[link_direction_facing >> 1];
+ pt->x = x;
+ pt->y = y;
+
+ R16 = y;
+ R18 = x;
+
+ x &= 0x1f8;
+ y &= 0x1f8;
+ uint16 xy = (y << 3) | (x >> 3) | (link_is_on_lower_level ? 0x1000 : 0x0);
+
+ uint8 attr = dung_bg2_attr_table[xy];
+
+ assert((attr & 0x70) == 0x70);
+
+ attr &= 0xf;
+ uint16 rt = dung_replacement_tile_state[attr];
+
+ if ((rt & 0xf0f0) == 0x1010) {
+ dung_misc_objs_index = attr * 2;
+ RevealPotItem(xy, dung_object_tilemap_pos[attr]);
+ RoomDraw_16x16Single(dung_misc_objs_index);
+ ManipBlock_Something(pt);
+ return kDungeon_QueryIfTileLiftable_rv[rt & 0xf];
+ } else if ((rt & 0xf0f0) == 0x2020) {
+ return ThievesAttic_DrawLightenedHole(xy, (attr - (rt & 0xf)) * 2, pt);
+ } else {
+ return 0;
+ }
+ return 0;
+}
+
+uint8 ThievesAttic_DrawLightenedHole(uint16 pos6, uint16 a, Point16U *pt) { // 81da71
+ dung_misc_objs_index = a;
+ RevealPotItem(pos6, dung_object_tilemap_pos[a >> 1]);
+ RoomDraw_16x16Single(a);
+ RoomDraw_16x16Single(a + 2);
+ RoomDraw_16x16Single(a + 4);
+ RoomDraw_16x16Single(a + 6);
+ ManipBlock_Something(pt);
+ return 0x55;
+}
+
+uint8 HandleItemTileAction_Dungeon(uint16 x, uint16 y) { // 81dabb
+ if (!(link_item_in_hand & 2))
+ 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];
+
+ uint8 attr;
+afterStoreCrap:
+ attr = (loc < 0x8000) ? 0x27 : 0x00;
+
+ dung_bg2_attr_table[pos + 0] = attr;
+ dung_bg2_attr_table[pos + 64] = attr;
+ dung_bg2_attr_table[pos + 1] = attr;
+ dung_bg2_attr_table[pos + 65] = attr;
+
+ uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
+ dst[0] = Dungeon_MapVramAddr(pos + 0);
+ dst[3] = Dungeon_MapVramAddr(pos + 64);
+ dst[6] = Dungeon_MapVramAddr(pos + 1);
+ dst[9] = Dungeon_MapVramAddr(pos + 65);
+
+ dst[2] = ptr[0];
+ dst[5] = ptr[1];
+ dst[8] = ptr[2];
+ dst[11] = ptr[3];
+
+ dst[1] = 0x100;
+ dst[4] = 0x100;
+ dst[7] = 0x100;
+ dst[10] = 0x100;
+
+ dst[12] = 0xffff;
+
+ vram_upload_offset += 24;
+ nmi_load_bg_from_vram = 1;
+ Dungeon_FlagRoomData_Quadrants();
+ if (sound_effect_2 == 0)
+ sound_effect_2 = 14;
+
+ *chest_position = loc & 0x7fff;
+ return data;
+ }
+ }
+ }
+ return 0xff;
+ }
+}
+
+void OpenBigChest(uint16 loc, int *chest_position) { // 81ed05
+ uint16 pos = loc >> 1;
+ const uint16 *src = SrcPtr(0x14C4);
+
+ for (int i = 0; i < 4; i++) {
+ dung_bg2[pos + XY(i, 0)] = src[0];
+ dung_bg2[pos + XY(i, 1)] = src[1];
+ dung_bg2[pos + XY(i, 2)] = src[2];
+ src += 3;
+ }
+
+ Dungeon_PrepOverlayDma_nextPrep(0, loc);
+ *chest_position = (loc + 2);
+ WORD(dung_bg2_attr_table[pos + XY(0, 0)]) = 0x2727;
+ WORD(dung_bg2_attr_table[pos + XY(2, 0)]) = 0x2727;
+ WORD(dung_bg2_attr_table[pos + XY(0, 1)]) = 0x2727;
+ WORD(dung_bg2_attr_table[pos + XY(2, 1)]) = 0x2727;
+ WORD(dung_bg2_attr_table[pos + XY(0, 2)]) = 0x2727;
+ WORD(dung_bg2_attr_table[pos + XY(2, 2)]) = 0x2727;
+ Dungeon_FlagRoomData_Quadrants();
+ sound_effect_2 = 14;
+ nmi_copy_packets_flag = 1;
+ byte_7E0B9E = 1;
+}
+
+uint8 OpenMiniGameChest(int *chest_position) { // 81edab
+ int t;
+ if (minigame_credits == 0) {
+ dialogue_message_index = 0x163;
+ Main_ShowTextMessage();
+ return 0xff;
+ }
+ if (minigame_credits == 255) {
+ dialogue_message_index = 0x162;
+ Main_ShowTextMessage();
+ return 0xff;
+ }
+ minigame_credits--;
+
+ int pos = ((link_y_coord - 4) & 0x1f8) * 8;
+ pos |= ((link_x_coord + 7) & 0x1f8) >> 3;
+
+ if (WORD(dung_bg2_attr_table[pos]) != 0x6363) {
+ pos--;
+ if (WORD(dung_bg2_attr_table[pos]) != 0x6363)
+ pos -= 2;
+ }
+
+ *chest_position = pos * 2;
+
+ WORD(dung_bg2_attr_table[pos]) = 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.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;
+}
+
--- a/dungeon.cpp
+++ /dev/null
@@ -1,8786 +1,0 @@
-#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;
-}
-
--- a/dungeon.h
+++ b/dungeon.h
@@ -34,14 +34,14 @@
kDoorType_ShutterTrapDL = 74,
};
-struct DungPalInfo {
+typedef struct DungPalInfo {
uint8 pal0;
uint8 pal1;
uint8 pal2;
uint8 pal3;
-};
+} DungPalInfo;
-struct RoomBounds {
+typedef struct RoomBounds {
union {
struct {
uint16 a0, b0, a1, b1;
@@ -48,7 +48,7 @@
};
uint16 v[4];
};
-};
+} RoomBounds;
#define room_bounds_y (*(RoomBounds*)(g_ram+0x600))
#define room_bounds_x (*(RoomBounds*)(g_ram+0x608))
--- /dev/null
+++ b/ending.c
@@ -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;
+}
+
--- a/ending.cpp
+++ /dev/null
@@ -1,2608 +1,0 @@
-#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;
-}
-
--- a/ending.h
+++ b/ending.h
@@ -1,10 +1,10 @@
#pragma once
-struct IntroSpriteEnt {
+typedef struct IntroSpriteEnt {
int8 x, y;
uint8 charnum, flags;
uint8 ext;
-};
+} IntroSpriteEnt;
void Intro_SetupScreen();
void Intro_LoadTextPointersAndPalettes();
--- /dev/null
+++ b/hud.c
@@ -1,0 +1,1498 @@
+#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"
+
+typedef struct ItemBoxGfx {
+ uint16 v[4];
+} ItemBoxGfx;
+
+static void Hud_DrawItem(uint16 a, const ItemBoxGfx *src);
+
+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 ItemBoxGfx kHudItemBottles[9] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2044, 0x2045, 0x2046, 0x2047},
+ {0x2837, 0x2838, 0x2cc3, 0x2cd3},
+ {0x24d2, 0x64d2, 0x24e2, 0x24e3},
+ {0x3cd2, 0x7cd2, 0x3ce2, 0x3ce3},
+ {0x2cd2, 0x6cd2, 0x2ce2, 0x2ce3},
+ {0x2855, 0x6855, 0x2c57, 0x2c5a},
+ {0x2837, 0x2838, 0x2839, 0x283a},
+ {0x2837, 0x2838, 0x2839, 0x283a},
+};
+static const ItemBoxGfx kHudItemBow[5] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x28ba, 0x28e9, 0x28e8, 0x28cb},
+ {0x28ba, 0x284a, 0x2849, 0x28cb},
+ {0x28ba, 0x28e9, 0x28e8, 0x28cb},
+ {0x28ba, 0x28bb, 0x24ca, 0x28cb},
+};
+static const ItemBoxGfx kHudItemBoomerang[3] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2cb8, 0x2cb9, 0x2cf5, 0x2cc9},
+ {0x24b8, 0x24b9, 0x24f5, 0x24c9},
+};
+static const ItemBoxGfx kHudItemHookshot[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x24f5, 0x24f6, 0x24c0, 0x24f5},
+};
+static const ItemBoxGfx kHudItemBombs[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2cb2, 0x2cb3, 0x2cc2, 0x6cc2},
+};
+static const ItemBoxGfx kHudItemMushroom[3] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2444, 0x2445, 0x2446, 0x2447},
+ {0x203b, 0x203c, 0x203d, 0x203e},
+};
+static const ItemBoxGfx kHudItemFireRod[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x24b0, 0x24b1, 0x24c0, 0x24c1},
+};
+static const ItemBoxGfx kHudItemIceRod[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2cb0, 0x2cbe, 0x2cc0, 0x2cc1},
+};
+static const ItemBoxGfx kHudItemBombos[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x287d, 0x287e, 0xe87e, 0xe87d},
+};
+static const ItemBoxGfx kHudItemEther[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2876, 0x2877, 0xE877, 0xE876},
+};
+static const ItemBoxGfx kHudItemQuake[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2866, 0x2867, 0xE867, 0xE866},
+};
+static const ItemBoxGfx kHudItemTorch[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x24bc, 0x24bd, 0x24cc, 0x24cd},
+};
+static const ItemBoxGfx kHudItemHammer[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x20b6, 0x20b7, 0x20c6, 0x20c7},
+};
+static const ItemBoxGfx kHudItemFlute[4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x20d0, 0x20d1, 0x20e0, 0x20e1},
+ {0x2cd4, 0x2cd5, 0x2ce4, 0x2ce5},
+ {0x2cd4, 0x2cd5, 0x2ce4, 0x2ce5},
+};
+static const ItemBoxGfx kHudItemBugNet[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x3c40, 0x3c41, 0x2842, 0x3c43},
+};
+static const ItemBoxGfx kHudItemBookMudora[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x3ca5, 0x3ca6, 0x3cd8, 0x3cd9},
+};
+static const ItemBoxGfx kHudItemCaneSomaria[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x24dc, 0x24dd, 0x24ec, 0x24ed},
+};
+static const ItemBoxGfx kHudItemCaneByrna[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2cdc, 0x2cdd, 0x2cec, 0x2ced},
+};
+static const ItemBoxGfx kHudItemCape[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x24b4, 0x24b5, 0x24c4, 0x24c5},
+};
+static const ItemBoxGfx kHudItemMirror[4] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x28de, 0x28df, 0x28ee, 0x28ef},
+ {0x2c62, 0x2c63, 0x2c72, 0x2c73},
+ {0x2886, 0x2887, 0x2888, 0x2889},
+};
+static const ItemBoxGfx kHudItemGloves[3] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2130, 0x2131, 0x2140, 0x2141},
+ {0x28da, 0x28db, 0x28ea, 0x28eb},
+};
+static const ItemBoxGfx kHudItemBoots[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x3429, 0x342a, 0x342b, 0x342c},
+};
+static const ItemBoxGfx kHudItemFlippers[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2c9a, 0x2c9b, 0x2c9d, 0x2c9e},
+};
+static const ItemBoxGfx kHudItemMoonPearl[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2433, 0x2434, 0x2435, 0x2436},
+};
+static const ItemBoxGfx kHudItemEmpty[1] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+};
+static const ItemBoxGfx kHudItemSword[5] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x2c64, 0x2cce, 0x2c75, 0x3d25},
+ {0x2c8a, 0x2c65, 0x2474, 0x3d26},
+ {0x248a, 0x2465, 0x3c74, 0x2d48},
+ {0x288a, 0x2865, 0x2c74, 0x2d39},
+};
+static const ItemBoxGfx kHudItemShield[4] = {
+ {0x24f5, 0x24f5, 0x24f5, 0x24f5},
+ {0x2cfd, 0x6cfd, 0x2cfe, 0x6cfe},
+ {0x34ff, 0x74ff, 0x349f, 0x749f},
+ {0x2880, 0x2881, 0x288d, 0x288e},
+};
+static const ItemBoxGfx kHudItemArmor[5] = {
+ {0x3c68, 0x7c68, 0x3c78, 0x7c78},
+ {0x2c68, 0x6c68, 0x2c78, 0x6c78},
+ {0x2468, 0x6468, 0x2478, 0x6478},
+};
+static const ItemBoxGfx kHudItemDungeonCompass[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x24bf, 0x64bf, 0x2ccf, 0x6ccf},
+};
+static const ItemBoxGfx kHudItemPalaceItem[3] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x28d6, 0x68d6, 0x28e6, 0x28e7},
+ {0x354b, 0x354c, 0x354d, 0x354e},
+};
+static const ItemBoxGfx kHudItemDungeonMap[2] = {
+ {0x20f5, 0x20f5, 0x20f5, 0x20f5},
+ {0x28de, 0x28df, 0x28ee, 0x28ef},
+};
+static const ItemBoxGfx kHudPendants0[2] = {
+ {0x313b, 0x313c, 0x313d, 0x313e},
+ {0x252b, 0x252c, 0x252d, 0x252e}
+};
+static const ItemBoxGfx kHudPendants1[2] = {
+ {0x313b, 0x313c, 0x313d, 0x313e},
+ {0x2d2b, 0x2d2c, 0x2d2d, 0x2d2e}
+};
+static const ItemBoxGfx kHudPendants2[2] = {
+ {0x313b, 0x313c, 0x313d, 0x313e},
+ {0x3d2b, 0x3d2c, 0x3d2d, 0x3d2e}
+};
+static const ItemBoxGfx kHudItemHeartPieces[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,
+};
+
+static const ItemBoxGfx * const kHudItemBoxGfxPtrs[] = {
+ kHudItemBow,
+ kHudItemBoomerang,
+ kHudItemHookshot,
+ kHudItemBombs,
+ kHudItemMushroom,
+ kHudItemFireRod,
+ kHudItemIceRod,
+ kHudItemBombos,
+ kHudItemEther,
+ kHudItemQuake,
+ kHudItemTorch,
+ kHudItemHammer,
+ kHudItemFlute,
+ kHudItemBugNet,
+ kHudItemBookMudora,
+ kHudItemBottles,
+ kHudItemCaneSomaria,
+ kHudItemCaneByrna,
+ kHudItemCape,
+ kHudItemMirror,
+ kHudItemGloves,
+ kHudItemBoots,
+ kHudItemFlippers,
+ kHudItemMoonPearl,
+ kHudItemEmpty,
+ kHudItemSword,
+ kHudItemShield,
+ kHudItemArmor,
+ kHudItemBottles,
+ kHudItemBottles,
+ kHudItemBottles,
+ kHudItemBottles,
+};
+static const uint16 kUpdateMagicPowerTilemap[17][4] = {
+ {0x3cf5, 0x3cf5, 0x3cf5, 0x3cf5},
+ {0x3cf5, 0x3cf5, 0x3cf5, 0x3c5f},
+ {0x3cf5, 0x3cf5, 0x3cf5, 0x3c4c},
+ {0x3cf5, 0x3cf5, 0x3cf5, 0x3c4d},
+ {0x3cf5, 0x3cf5, 0x3cf5, 0x3c4e},
+ {0x3cf5, 0x3cf5, 0x3c5f, 0x3c5e},
+ {0x3cf5, 0x3cf5, 0x3c4c, 0x3c5e},
+ {0x3cf5, 0x3cf5, 0x3c4d, 0x3c5e},
+ {0x3cf5, 0x3cf5, 0x3c4e, 0x3c5e},
+ {0x3cf5, 0x3c5f, 0x3c5e, 0x3c5e},
+ {0x3cf5, 0x3c4c, 0x3c5e, 0x3c5e},
+ {0x3cf5, 0x3c4d, 0x3c5e, 0x3c5e},
+ {0x3cf5, 0x3c4e, 0x3c5e, 0x3c5e},
+ {0x3c5f, 0x3c5e, 0x3c5e, 0x3c5e},
+ {0x3c4c, 0x3c5e, 0x3c5e, 0x3c5e},
+ {0x3c4d, 0x3c5e, 0x3c5e, 0x3c5e},
+ {0x3c4e, 0x3c5e, 0x3c5e, 0x3c5e},
+};
+static const uint16 kDungFloorIndicator_Gfx0[11] = { 0x2508, 0x2509, 0x2509, 0x250a, 0x250b, 0x250c, 0x250d, 0x251d, 0xe51c, 0x250e, 0x7f };
+static const uint16 kDungFloorIndicator_Gfx1[11] = { 0x2518, 0x2519, 0xa509, 0x251a, 0x251b, 0x251c, 0x2518, 0xa51d, 0xe50c, 0xa50e, 0x7f };
+void Hud_RefreshIcon() {
+ Hud_SearchForEquippedItem();
+ Hud_UpdateHud();
+ Hud_Rebuild();
+ overworld_map_state = 0;
+}
+
+uint8 CheckPalaceItemPosession() {
+ switch (cur_palace_index_x2 >> 1) {
+ case 2: return link_item_bow != 0;
+ case 3: return link_item_gloves != 0;
+ case 5: return link_item_hookshot != 0;
+ case 6: return link_item_hammer != 0;
+ case 7: return link_item_cane_somaria != 0;
+ case 8: return link_item_fire_rod != 0;
+ case 9: return link_armor != 0;
+ case 10: return link_item_moon_pearl != 0;
+ case 11: return link_item_gloves != 1;
+ case 12: return link_shield_type == 3;
+ case 13: return link_armor == 2;
+ default:
+ return 0;
+ }
+}
+
+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;
+}
+
+static void Hud_DrawItem(uint16 a, const ItemBoxGfx *src) { // 8de372
+ uint16 *dst = (uint16 *)&g_ram[a];
+ dst[0] = src->v[0];
+ dst[1] = src->v[1];
+ dst[32] = src->v[2];
+ dst[33] = src->v[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].v;
+
+ 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;
+ }
+}
+
+const uint16 *Hud_GetItemBoxPtr(int item) {
+ return kHudItemBoxGfxPtrs[item]->v;
+}
--- a/hud.cpp
+++ /dev/null
@@ -1,1486 +1,0 @@
-#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;
- }
-}
-
--- a/hud.h
+++ b/hud.h
@@ -1,14 +1,6 @@
#pragma once
#include "types.h"
-
-
-
-
-
-
-
-extern const uint16 *const kHudItemBoxGfxPtrs[];
void Hud_RefreshIcon();
uint8 CheckPalaceItemPosession();
void Hud_GotoPrevItem();
@@ -38,7 +30,6 @@
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);
@@ -70,3 +61,4 @@
void Hud_Update_IgnoreItemBox();
void Hud_Update_IgnoreHealth();
void Hud_UpdateHearts(uint16 *dst, const uint16 *src, int n);
+const uint16 *Hud_GetItemBoxPtr(int item);
\ No newline at end of file
--- /dev/null
+++ b/load_gfx.c
@@ -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++;
+}
+
--- a/load_gfx.cpp
+++ /dev/null
@@ -1,2163 +1,0 @@
-#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/main.c
@@ -1,0 +1,348 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <SDL.h>
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
+
+#include "snes/snes.h"
+#include "tracing.h"
+
+#include "types.h"
+#include "variables.h"
+
+#include "zelda_rtl.h"
+
+extern Ppu *GetPpuForRendering();
+extern Dsp *GetDspForRendering();
+
+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 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 NORETURN Die(const char *error) {
+ fprintf(stderr, "Error: %s\n", error);
+ exit(1);
+}
+
+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;
+ }
+ uint32 win_flags = SDL_WINDOWPOS_UNDEFINED;
+ SDL_Window* window = SDL_CreateWindow("Zelda3", SDL_WINDOWPOS_UNDEFINED, win_flags, 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);
+ }
+
+#if defined(_WIN32)
+ _mkdir("saves");
+#else
+ mkdir("saves", 755);
+#endif
+
+ SetSnes(snes);
+ ZeldaInitialize();
+ ZeldaReadSram(snes);
+
+ bool hooks = true;
+ // sdl loop
+ bool running = true;
+ SDL_Event event;
+ uint32 lastTick = SDL_GetTicks();
+ uint32 curTick = 0;
+ uint32 delta = 0;
+ int numFrames = 0;
+ bool cpuNext = false;
+ bool spcNext = false;
+ int counter = 0;
+ bool paused = false;
+ bool turbo = true;
+ uint32 frameCtr = 0;
+
+ while(running) {
+ while(SDL_PollEvent(&event)) {
+ switch(event.type) {
+ case SDL_KEYDOWN: {
+ bool skip_default = false;
+ 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;
+ case SDLK_RETURN:
+ if (event.key.keysym.mod & KMOD_ALT) {
+ win_flags ^= SDL_WINDOW_FULLSCREEN_DESKTOP;
+ SDL_SetWindowFullscreen(window, win_flags);
+ skip_default = true;
+ }
+ break;
+ }
+ if (!skip_default)
+ 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;
+}
+
+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 loadRom(char* name, Snes* snes) {
+ size_t length = 0;
+ uint8_t* file = NULL;
+ file = readFile(name, &length);
+ if(!file) Die("Failed to read file");
+
+ 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);
+ if (!buffer) Die("malloc failed");
+ fread(buffer, size, 1, f);
+ fclose(f);
+ *length = size;
+ return buffer;
+}
--- a/main.cpp
+++ /dev/null
@@ -1,384 +1,0 @@
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <SDL.h>
-#ifdef _WIN32
-#include <direct.h>
-#else
-#include <sys/stat.h>
-#include <sys/types.h>
-#endif
-
-#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);
- }
-}
-
-
-void ZeldaReadSram(Snes *snes) {
- FILE *f = fopen("saves/sram.dat", "rb");
- if (f) {
- fread(g_zenv.sram, 1, 8192, f);
- memcpy(snes->cart->ram, g_zenv.sram, 8192);
- fclose(f);
- }
-}
-
-void ZeldaWriteSram() {
- rename("saves/sram.dat", "saves/sram.bak");
- FILE *f = fopen("saves/sram.dat", "wb");
- if (f) {
- fwrite(g_zenv.sram, 1, 8192, f);
- fclose(f);
- } else {
- fprintf(stderr, "Unable to write saves/sram.dat\n");
- }
-}
-
-#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;
- }
- uint32 win_flags = SDL_WINDOWPOS_UNDEFINED;
- SDL_Window* window = SDL_CreateWindow("Zelda3", SDL_WINDOWPOS_UNDEFINED, win_flags, 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);
- }
-
-#if defined(_WIN32)
- _mkdir("saves");
-#else
- mkdir("saves", 755);
-#endif
-
- SetSnes(snes);
- ZeldaInitialize();
- ZeldaReadSram(snes);
-
- bool hooks = true;
- // sdl loop
- bool running = true;
- SDL_Event event;
- uint32 lastTick = SDL_GetTicks();
- uint32 curTick = 0;
- uint32 delta = 0;
- int numFrames = 0;
- bool cpuNext = false;
- bool spcNext = false;
- int counter = 0;
- bool paused = false;
- bool turbo = true;
- uint32 frameCtr = 0;
-
- while(running) {
- while(SDL_PollEvent(&event)) {
- switch(event.type) {
- case SDL_KEYDOWN: {
- bool skip_default = false;
- 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;
- case SDLK_RETURN:
- if (event.key.keysym.mod & KMOD_ALT) {
- win_flags ^= SDL_WINDOW_FULLSCREEN_DESKTOP;
- SDL_SetWindowFullscreen(window, win_flags);
- skip_default = true;
- }
- break;
- }
- if (!skip_default)
- 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.c
@@ -1,0 +1,3072 @@
+#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;
+ ZeldaWriteSram();
+}
+
+void TransferMode7Characters() { // 80e399
+ uint16 *dst = g_zenv.vram;
+ const uint8 *src = kOverworldMapGfx;
+ for (int i = 0; i != 0x4000; i++)
+ HIBYTE(dst[i]) = src[i];
+}
+
+void Module0E_Interface() { // 80f800
+ bool skip_run = false;
+ if (player_is_indoors) {
+ if (submodule_index == 3) {
+ skip_run = (overworld_map_state != 0 && overworld_map_state != 7);
+ } else {
+ Dungeon_PushBlock_Handler();
+ }
+ } else {
+ skip_run = ((submodule_index == 7 || submodule_index == 10) && overworld_map_state);
+ }
+ if (!skip_run) {
+ Sprite_Main();
+ LinkOam_Main();
+ if (!player_is_indoors)
+ OverworldOverlay_HandleRain();
+ Hud_RefillLogic();
+ if (submodule_index != 2)
+ OrientLampLightCone();
+ }
+ RunInterface();
+ BG2HOFS_copy = BG2HOFS_copy2 + bg1_x_offset;
+ BG2VOFS_copy = BG2VOFS_copy2 + bg1_y_offset;
+ BG1HOFS_copy = BG1HOFS_copy2 + bg1_x_offset;
+ BG1VOFS_copy = BG1VOFS_copy2 + bg1_y_offset;
+}
+
+void Module_Messaging_0() { // 80f875
+ assert(0);
+}
+
+static void RunInterface() { // 80f89a
+ kMessagingSubmodules[submodule_index]();
+}
+
+void Module0E_05_DesertPrayer() { // 80f8b1
+ switch (subsubmodule_index) {
+ case 0: ResetTransitionPropsAndAdvance_ResetInterface(); break;
+ case 1: ApplyPaletteFilter_bounce(); break;
+ case 2:
+ DesertPrayer_InitializeIrisHDMA();
+ BYTE(palette_filter_countdown) = mosaic_target_level - 1;
+ mosaic_target_level = 0;
+ BYTE(darkening_or_lightening_screen) = 2;
+ break;
+ case 3:
+ ApplyPaletteFilter_bounce();
+ // fall through
+ case 4:
+ DesertPrayer_BuildIrisHDMATable();
+ break;
+ }
+}
+
+void Module0E_04_RedPotion() { // 80f8fb
+ if (Hud_RefillHealth()) {
+ button_mask_b_y &= ~0x40;
+ flag_update_hud_in_nmi++;
+ submodule_index = 0;
+ main_module_index = saved_module_for_menu;
+ }
+}
+
+void Module0E_08_GreenPotion() { // 80f911
+ if (Hud_RefillMagicPower()) {
+ button_mask_b_y &= ~0x40;
+ flag_update_hud_in_nmi++;
+ submodule_index = 0;
+ main_module_index = saved_module_for_menu;
+ }
+}
+
+void Module0E_09_BluePotion() { // 80f918
+ if (Hud_RefillHealth())
+ submodule_index = 8;
+ if (Hud_RefillMagicPower())
+ submodule_index = 4;
+}
+
+void Module0E_0B_SaveMenu() { // 80f9fa
+ // This is the continue / save and quit menu
+ if (!player_is_indoors)
+ Overworld_DwDeathMountainPaletteAnimation();
+ RenderText();
+ flag_update_hud_in_nmi = 0;
+ nmi_disable_core_updates = 0;
+ if (subsubmodule_index < 3)
+ subsubmodule_index++;
+ else
+ nmi_load_bg_from_vram = 0;
+ if (!submodule_index) {
+ subsubmodule_index = 0;
+ nmi_load_bg_from_vram = 1;
+ if (choice_in_multiselect_box) {
+ sound_effect_ambient = 15;
+ main_module_index = 23;
+ submodule_index = 1;
+ index_of_changable_dungeon_objs[0] = 0;
+ index_of_changable_dungeon_objs[1] = 0;
+ } else {
+ choice_in_multiselect_box = choice_in_multiselect_box_bak;
+ }
+ }
+}
+
+void Module1B_SpawnSelect() { // 828586
+ RenderText();
+ if (submodule_index)
+ return;
+ nmi_load_bg_from_vram = 0;
+ EnableForceBlank();
+ EraseTileMaps_normal();
+ uint8 bak = which_starting_point;
+ which_starting_point = kLocationMenuStartPos[choice_in_multiselect_box];
+ subsubmodule_index = 0;
+ LoadDungeonRoomRebuildHUD();
+ which_starting_point = bak;
+}
+
+void CleanUpAndPrepDesertPrayerHDMA() { // 82c7b8
+ HdmaSetup(0, 0x2c80c, 0x41, 0, (uint8)WH0, 0);
+
+ W12SEL_copy = 0x33;
+ W34SEL_copy = 3;
+ WOBJSEL_copy = 0x33;
+ TMW_copy = TM_copy;
+ TSW_copy = TS_copy;
+ HDMAEN_copy = 0x80;
+ memset(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 = Hud_GetItemBoxPtr(item);
+ p += ((item == 3 || item == 32) ? 1 : (&link_item_bow)[item]) * 4;
+ uint8 *vwf300 = &g_ram[0x1300];
+ memcpy(vwf300 + 0xc2, p, 4);
+ memcpy(vwf300 + 0xec, p + 2, 4);
+}
+
+void RenderText_Draw_Choose2HiOr3() { // 8ece83
+ if (text_wait_countdown2 != 0) {
+ if (--text_wait_countdown2 == 1)
+ sound_effect_2 = 36;
+ } else if ((filtered_joypad_H | filtered_joypad_L) & 0xc0) {
+ sound_effect_1 = 43;
+ text_render_state = 4;
+ } else if (filtered_joypad_H & 12) {
+ int t = filtered_joypad_H & 8 ? 0 : 1;
+ if (choice_in_multiselect_box == t)
+ return;
+ choice_in_multiselect_box = t;
+ sound_effect_2 = 32;
+ dialogue_message_index = t + 11;
+ Text_LoadCharacterBuffer();
+ text_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;
+}
+
--- a/messaging.cpp
+++ /dev/null
@@ -1,3072 +1,0 @@
-#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;
- ZeldaWriteSram();
-}
-
-void TransferMode7Characters() { // 80e399
- uint16 *dst = g_zenv.vram;
- const uint8 *src = kOverworldMapGfx;
- for (int i = 0; i != 0x4000; i++)
- HIBYTE(dst[i]) = src[i];
-}
-
-void Module0E_Interface() { // 80f800
- bool skip_run = false;
- if (player_is_indoors) {
- if (submodule_index == 3) {
- skip_run = (overworld_map_state != 0 && overworld_map_state != 7);
- } else {
- Dungeon_PushBlock_Handler();
- }
- } else {
- skip_run = ((submodule_index == 7 || submodule_index == 10) && overworld_map_state);
- }
- if (!skip_run) {
- Sprite_Main();
- LinkOam_Main();
- if (!player_is_indoors)
- OverworldOverlay_HandleRain();
- Hud_RefillLogic();
- if (submodule_index != 2)
- OrientLampLightCone();
- }
- RunInterface();
- BG2HOFS_copy = BG2HOFS_copy2 + bg1_x_offset;
- BG2VOFS_copy = BG2VOFS_copy2 + bg1_y_offset;
- BG1HOFS_copy = BG1HOFS_copy2 + bg1_x_offset;
- BG1VOFS_copy = BG1VOFS_copy2 + bg1_y_offset;
-}
-
-void Module_Messaging_0() { // 80f875
- assert(0);
-}
-
-static void RunInterface() { // 80f89a
- kMessagingSubmodules[submodule_index]();
-}
-
-void Module0E_05_DesertPrayer() { // 80f8b1
- switch (subsubmodule_index) {
- case 0: ResetTransitionPropsAndAdvance_ResetInterface(); break;
- case 1: ApplyPaletteFilter_bounce(); break;
- case 2:
- DesertPrayer_InitializeIrisHDMA();
- BYTE(palette_filter_countdown) = mosaic_target_level - 1;
- mosaic_target_level = 0;
- BYTE(darkening_or_lightening_screen) = 2;
- break;
- case 3:
- ApplyPaletteFilter_bounce();
- // fall through
- case 4:
- DesertPrayer_BuildIrisHDMATable();
- break;
- }
-}
-
-void Module0E_04_RedPotion() { // 80f8fb
- if (Hud_RefillHealth()) {
- button_mask_b_y &= ~0x40;
- flag_update_hud_in_nmi++;
- submodule_index = 0;
- main_module_index = saved_module_for_menu;
- }
-}
-
-void Module0E_08_GreenPotion() { // 80f911
- if (Hud_RefillMagicPower()) {
- button_mask_b_y &= ~0x40;
- flag_update_hud_in_nmi++;
- submodule_index = 0;
- main_module_index = saved_module_for_menu;
- }
-}
-
-void Module0E_09_BluePotion() { // 80f918
- if (Hud_RefillHealth())
- submodule_index = 8;
- if (Hud_RefillMagicPower())
- submodule_index = 4;
-}
-
-void Module0E_0B_SaveMenu() { // 80f9fa
- // This is the continue / save and quit menu
- if (!player_is_indoors)
- Overworld_DwDeathMountainPaletteAnimation();
- RenderText();
- flag_update_hud_in_nmi = 0;
- nmi_disable_core_updates = 0;
- if (subsubmodule_index < 3)
- subsubmodule_index++;
- else
- nmi_load_bg_from_vram = 0;
- if (!submodule_index) {
- subsubmodule_index = 0;
- nmi_load_bg_from_vram = 1;
- if (choice_in_multiselect_box) {
- sound_effect_ambient = 15;
- main_module_index = 23;
- submodule_index = 1;
- index_of_changable_dungeon_objs[0] = 0;
- index_of_changable_dungeon_objs[1] = 0;
- } else {
- choice_in_multiselect_box = choice_in_multiselect_box_bak;
- }
- }
-}
-
-void Module1B_SpawnSelect() { // 828586
- RenderText();
- if (submodule_index)
- return;
- nmi_load_bg_from_vram = 0;
- EnableForceBlank();
- EraseTileMaps_normal();
- uint8 bak = which_starting_point;
- which_starting_point = kLocationMenuStartPos[choice_in_multiselect_box];
- subsubmodule_index = 0;
- LoadDungeonRoomRebuildHUD();
- which_starting_point = bak;
-}
-
-void CleanUpAndPrepDesertPrayerHDMA() { // 82c7b8
- HdmaSetup(0, 0x2c80c, 0x41, 0, (uint8)WH0, 0);
-
- W12SEL_copy = 0x33;
- W34SEL_copy = 3;
- WOBJSEL_copy = 0x33;
- TMW_copy = TM_copy;
- TSW_copy = TS_copy;
- HDMAEN_copy = 0x80;
- memset(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/misc.c
@@ -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);
+}
+
--- a/misc.cpp
+++ /dev/null
@@ -1,962 +1,0 @@
-#include "misc.h"
-#include "variables.h"
-#include "hud.h"
-#include "dungeon.h"
-#include "overworld.h"
-#include "load_gfx.h"
-#include "sprite.h"
-#include "poly.h"
-#include "ancilla.h"
-#include "select_file.h"
-#include "tile_detect.h"
-#include "player.h"
-#include "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/nmi.c
@@ -1,0 +1,495 @@
+#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();
+ } 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);
+ thread_other_stack = (thread_other_stack != 0x1f31) ? 0x1f31 : 0x1f2;
+}
+
+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.data;
+ do {
+ int dst = WORD(p[0]);
+ int vmain = p[2];
+ int len = p[3];
+ p += 4;
+ if (vmain == 0x80) {
+ // plain copy
+ memcpy(&g_zenv.vram[dst], p, len);
+ } else if (vmain == 0x81) {
+ // copy with other increment
+ assert((len & 1) == 0);
+ uint16 *dp = &g_zenv.vram[dst];
+ for (int i = 0; i < len; i += 2, dp += 32)
+ *dp = WORD(p[i]);
+ } else {
+ assert(0);
+ }
+ p += len;
+ } while (WORD(p[0]) != 0xffff);
+ nmi_copy_packets_flag = 0;
+ nmi_disable_core_updates = 0;
+ }
+
+ int idx = nmi_subroutine_index;
+ nmi_subroutine_index = 0;
+ kNmiSubroutines[idx]();
+}
+
+void NMI_UploadTilemap() { // 808cb0
+ memcpy(&g_zenv.vram[kNmiVramAddrs[BYTE(nmi_load_target_addr)] << 8], &g_ram[0x1000], 0x800);
+
+ *(uint16 *)&g_ram[0x1000] = 0;
+ nmi_disable_core_updates = 0;
+}
+
+void NMI_UploadTilemap_doNothing() { // 808ce3
+}
+
+void NMI_UploadBG3Text() { // 808ce4
+ memcpy(&g_zenv.vram[0x7c00], &g_ram[0x10000], 0x7e0);
+ nmi_disable_core_updates = 0;
+}
+
+void NMI_UpdateOWScroll() { // 808d13
+ uint8 *src = (uint8 *)uvram.data, *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;
+ }
+}
+
--- a/nmi.cpp
+++ /dev/null
@@ -1,495 +1,0 @@
-#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();
- } 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);
- thread_other_stack = (thread_other_stack != 0x1f31) ? 0x1f31 : 0x1f2;
-}
-
-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;
- }
-}
-
--- a/other/replace_in_files.py
+++ b/other/replace_in_files.py
@@ -21,7 +21,7 @@
-for filename in glob.glob('*.cpp') + glob.glob('*.h'):
+for filename in glob.glob('*.c') + glob.glob('*.h'):
replace_in_file(filename)
--- /dev/null
+++ b/other_modules.c
@@ -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();
+}
+
--- a/other_modules.cpp
+++ /dev/null
@@ -1,92 +1,0 @@
-#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/overlord.c
@@ -1,0 +1,653 @@
+#include "overlord.h"
+#include "sprite.h"
+#include "misc.h"
+#include "sprite_main.h"
+
+uint16 Overlord_GetX(int k) { return (overlord_x_lo[k] | overlord_x_hi[k] << 8); }
+uint16 Overlord_GetY(int k) { return (overlord_y_lo[k] | overlord_y_hi[k] << 8); }
+static HandlerFuncK *const kOverlordFuncs[26] = {
+ &Overlord01_PositionTarget,
+ &Overlord02_FullRoomCannons,
+ &Overlord03_VerticalCannon,
+ &Overlord_StalfosFactory,
+ &Overlord05_FallingStalfos,
+ &Overlord06_BadSwitchSnake,
+ &Overlord07_MovingFloor,
+ &Overlord08_BlobSpawner,
+ &Overlord09_WallmasterSpawner,
+ &Overlord0A_FallingSquare,
+ &Overlord0A_FallingSquare,
+ &Overlord0A_FallingSquare,
+ &Overlord0A_FallingSquare,
+ &Overlord0A_FallingSquare,
+ &Overlord0A_FallingSquare,
+ &Overlord10_PirogusuSpawner_left,
+ &Overlord10_PirogusuSpawner_left,
+ &Overlord10_PirogusuSpawner_left,
+ &Overlord10_PirogusuSpawner_left,
+ &Overlord14_TileRoom,
+ &Overlord15_WizzrobeSpawner,
+ &Overlord16_ZoroSpawner,
+ &Overlord17_PotTrap,
+ &Overlord18_InvisibleStalfos,
+ &Overlord19_ArmosCoordinator_bounce,
+ &Overlord06_BadSwitchSnake,
+};
+static inline uint8 ArmosMult(uint16 a, uint8 b);
+static inline int8 ArmosSin(uint16 a, uint8 b);
+void Overlord_StalfosFactory(int k) {
+ // unused
+ assert(0);
+}
+
+void Overlord_SetX(int k, uint16 v) {
+ overlord_x_lo[k] = v;
+ overlord_x_hi[k] = v >> 8;
+}
+
+void Overlord_SetY(int k, uint16 v) {
+ overlord_y_lo[k] = v;
+ overlord_y_hi[k] = v >> 8;
+}
+
+static inline uint8 ArmosMult(uint16 a, uint8 b) {
+ if (a >= 256)
+ return b;
+ int p = a * b;
+ return (p >> 8) + (p >> 7 & 1);
+}
+
+static inline int8 ArmosSin(uint16 a, uint8 b) {
+ uint8 t = ArmosMult(kSinusLookupTable[a & 0xff], b);
+ return (a & 0x100) ? -t : t;
+}
+
+void Overlord_SpawnBoulder() { // 89b714
+ if (player_is_indoors || !byte_7E0FFD || (submodule_index | flag_unk1) || ++byte_7E0FFE & 63)
+ return;
+
+ if (sign8((BG2VOFS_copy2 >> 8) - (sprcoll_y_base >> 8) - 2))
+ return;
+
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamically(0, 0xc2, &info);
+ if (j >= 0) {
+ Sprite_SetX(j, BG2HOFS_copy2 + (GetRandomNumber() & 127) + 64);
+ Sprite_SetY(j, BG2VOFS_copy2 - 0x30);
+ sprite_floor[j] = 0;
+ sprite_D[j] = 0;
+ sprite_z[j] = 0;
+ }
+}
+
+void Overlord_Main() { // 89b773
+ Overlord_ExecuteAll();
+ Overlord_SpawnBoulder();
+}
+
+void Overlord_ExecuteAll() { // 89b77e
+ if (submodule_index | flag_unk1)
+ return;
+ for (int i = 7; i >= 0; i--) {
+ if (overlord_type[i])
+ Overlord_ExecuteSingle(i);
+ }
+}
+
+void Overlord_ExecuteSingle(int k) { // 89b793
+ int j = overlord_type[k];
+ Overlord_CheckIfActive(k);
+ kOverlordFuncs[j - 1](k);
+}
+
+void Overlord19_ArmosCoordinator_bounce(int k) { // 89b7dc
+ static const uint8 kArmosCoordinator_BackWallX[6] = { 49, 77, 105, 131, 159, 187 };
+
+ if (overlord_gen2[k])
+ overlord_gen2[k]--;
+ switch (overlord_gen1[k]) {
+ case 0: // wait for knight activation
+ if (sprite_A[0]) {
+ overlord_x_lo[k] = 120;
+ overlord_floor[k] = 255;
+ overlord_x_lo[2] = 64;
+ overlord_x_lo[0] = 192;
+ overlord_x_lo[1] = 1;
+ ArmosCoordinator_RotateKnights(k);
+ }
+ break;
+ case 1: // wait knight under coercion
+ if (ArmosCoordinator_CheckKnights()) {
+ overlord_gen1[k]++;
+ overlord_gen2[k] = 0xff;
+ }
+ break;
+ case 2: // timed rotate then transition
+ case 4:
+ ArmosCoordinator_RotateKnights(k);
+ break;
+ case 3: // radial contraction
+ if (--overlord_x_lo[2] == 32) {
+ overlord_gen1[k]++;
+ overlord_gen2[k] = 64;
+ }
+ ArmosCoordinator_Rotate(k);
+ break;
+ case 5: // radial dilation
+ if (++overlord_x_lo[2] == 64) {
+ overlord_gen1[k]++;
+ overlord_gen2[k] = 64;
+ }
+ ArmosCoordinator_Rotate(k);
+ break;
+ case 6: // order knights to back wall
+ if (overlord_gen2[k])
+ return;
+ ArmosCoordinator_DisableCoercion(k);
+ for (int j = 5; j >= 0; j--) {
+ overlord_x_hi[j] = kArmosCoordinator_BackWallX[j];
+ overlord_gen2[j] = 48;
+ }
+ overlord_gen1[k]++;
+ overlord_gen2[k] = 255;
+ break;
+ case 7: // cascade knights to front wall
+ if (overlord_gen2[k])
+ return;
+ for (int j = 5; j >= 0; j--) {
+ if (++overlord_gen2[j] == 192) {
+ overlord_gen1[k] = 1;
+ overlord_floor[k] = -overlord_floor[k];
+ ArmosCoordinator_DisableCoercion(k);
+ ArmosCoordinator_Rotate(k);
+ return;
+ }
+ }
+ break;
+ }
+}
+
+void Overlord18_InvisibleStalfos(int k) { // 89b7f5
+ static const int8 kRedStalfosTrap_X[4] = { 0, 0, -48, 48 };
+ static const int8 kRedStalfosTrap_Y[4] = { -40, 56, 8, 8 };
+ static const uint8 kRedStalfosTrap_Delay[4] = { 0x30, 0x50, 0x70, 0x90 };
+
+ uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8);
+ uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8);
+ if ((uint16)(x - link_x_coord + 24) >= 48 || (uint16)(y - link_y_coord + 24) >= 48)
+ return;
+ overlord_type[k] = 0;
+ tmp_counter = 3;
+ do {
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamicallyEx(k, 0xa7, &info, 12);
+ if (j < 0)
+ return;
+ Sprite_SetX(j, link_x_coord + kRedStalfosTrap_X[tmp_counter]);
+ Sprite_SetY(j, link_y_coord + kRedStalfosTrap_Y[tmp_counter]);
+ sprite_delay_main[j] = kRedStalfosTrap_Delay[tmp_counter];
+ sprite_floor[j] = overlord_floor[k];
+ sprite_E[j] = 1;
+ sprite_flags2[j] = 3;
+ sprite_D[j] = 2;
+ } while (!sign8(--tmp_counter));
+}
+
+void Overlord17_PotTrap(int k) { // 89b884
+ uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8);
+ uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8);
+ if ((uint16)(x - link_x_coord + 32) < 64 &&
+ (uint16)(y - link_y_coord + 32) < 64) {
+ overlord_type[k] = 0;
+ byte_7E0B9E++;
+ }
+}
+
+void Overlord16_ZoroSpawner(int k) { // 89b8d1
+ static const int8 kOverlordZoroFactory_X[8] = { -4, -2, 0, 2, 4, 6, 8, 12 };
+ overlord_gen2[k]--;
+ uint16 x = Overlord_GetX(k) + 8;
+ uint16 y = Overlord_GetY(k) + 8;
+ if (GetTileAttribute(overlord_floor[k], &x, y) != 0x82)
+ return;
+ if (overlord_gen2[k] >= 0x18 || (overlord_gen2[k] & 3) != 0)
+ return;
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamicallyEx(k, 0x9c, &info, 12);
+ if (j >= 0) {
+ Sprite_SetX(j, info.r5_overlord_x + kOverlordZoroFactory_X[GetRandomNumber() & 7] + 8);
+ sprite_y_lo[j] = info.r7_overlord_y + 8;
+ sprite_y_hi[j] = info.r7_overlord_y >> 8;
+ sprite_floor[j] = overlord_floor[k];
+ sprite_flags4[j] = 1;
+ sprite_E[j] = 1;
+ sprite_ignore_projectile[j] = 1;
+ sprite_y_vel[j] = 16;
+ sprite_flags2[j] = 32;
+ sprite_oam_flags[j] = 13;
+ sprite_subtype2[j] = GetRandomNumber();
+ sprite_delay_main[j] = 48;
+ sprite_bump_damage[j] = 3;
+ }
+}
+
+void Overlord15_WizzrobeSpawner(int k) { // 89b986
+ static const int8 kOverlordWizzrobe_X[4] = { 48, -48, 0, 0 };
+ static const int8 kOverlordWizzrobe_Y[4] = { 16, 16, 64, -32 };
+ static const uint8 kOverlordWizzrobe_Delay[4] = { 0, 16, 32, 48 };
+ if (overlord_gen2[k] != 128) {
+ if (frame_counter & 1)
+ overlord_gen2[k]--;
+ return;
+ }
+ overlord_gen2[k] = 127;
+ for (int i = 3; i >= 0; i--) {
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamicallyEx(k, 0x9b, &info, 12);
+ if (j >= 0) {
+ Sprite_SetX(j, link_x_coord + kOverlordWizzrobe_X[i]);
+ Sprite_SetY(j, link_y_coord + kOverlordWizzrobe_Y[i]);
+ sprite_delay_main[j] = kOverlordWizzrobe_Delay[i];
+ sprite_floor[j] = overlord_floor[k];
+ sprite_B[j] = 1;
+ }
+ }
+ tmp_counter = 0xff;
+}
+
+void Overlord14_TileRoom(int k) { // 89b9e8
+ uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
+ uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8) - BG2VOFS_copy2;
+ if (x & 0xff00 || y & 0xff00)
+ return;
+ if (--overlord_gen2[k] != 0x80)
+ return;
+ int j = TileRoom_SpawnTile(k);
+ if (j < 0) {
+ overlord_gen2[k] = 0x81;
+ return;
+ }
+ if (++overlord_gen1[k] != 22)
+ overlord_gen2[k] = 0xE0;
+ else
+ overlord_type[k] = 0;
+}
+
+int TileRoom_SpawnTile(int k) { // 89ba56
+ static const uint8 kSpawnFlyingTile_X[22] = {
+ 0x70, 0x80, 0x60, 0x90, 0x90, 0x60, 0x70, 0x80, 0x80, 0x70, 0x50, 0xa0, 0xa0, 0x50, 0x50, 0xa0,
+ 0xa0, 0x50, 0x70, 0x80, 0x80, 0x70,
+ };
+ static const uint8 kSpawnFlyingTile_Y[22] = {
+ 0x80, 0x80, 0x70, 0x90, 0x70, 0x90, 0x60, 0xa0, 0x60, 0xa0, 0x60, 0xb0, 0x60, 0xb0, 0x80, 0x90,
+ 0x80, 0x90, 0x70, 0x90, 0x70, 0x90,
+ };
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamically(k, 0x94, &info);
+ if (j < 0)
+ return j;
+ sprite_E[j] = 1;
+ int i = overlord_gen1[k];
+ sprite_x_lo[j] = kSpawnFlyingTile_X[i];
+ sprite_y_lo[j] = kSpawnFlyingTile_Y[i] - 8;
+ sprite_y_hi[j] = overlord_y_hi[k];
+ sprite_x_hi[j] = overlord_x_hi[k];
+ sprite_floor[j] = overlord_floor[k];
+ sprite_health[j] = 4;
+ sprite_flags5[j] = 0;
+ sprite_health[j] = 0;
+ sprite_defl_bits[j] = 8;
+ sprite_flags2[j] = 4;
+ sprite_oam_flags[j] = 1;
+ sprite_bump_damage[j] = 4;
+ return j;
+}
+
+void Overlord10_PirogusuSpawner_left(int k) { // 89baac
+ static const uint8 kOverlordPirogusu_A[4] = { 2, 3, 0, 1 };
+
+ tmp_counter = overlord_type[k] - 16;
+ if (overlord_gen2[k] != 128) {
+ overlord_gen2[k]--;
+ return;
+ }
+ overlord_gen2[k] = (GetRandomNumber() & 31) + 96;
+ int n = 0;
+ for (int i = 0; i != 16; i++) {
+ if (sprite_state[i] != 0 && sprite_type[i] == 0x10)
+ n++;
+ }
+ if (n >= 5)
+ return;
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamicallyEx(k, 0x94, &info, 12);
+ if (j >= 0) {
+ Sprite_SetX(j, info.r5_overlord_x);
+ Sprite_SetY(j, info.r7_overlord_y);
+ sprite_floor[j] = overlord_floor[k];
+ sprite_delay_main[j] = 32;
+ sprite_D[j] = tmp_counter;
+ sprite_A[j] = kOverlordPirogusu_A[tmp_counter];
+ }
+}
+
+void Overlord0A_FallingSquare(int k) { // 89bbb2
+ static const uint8 kCrumbleTilePathData[108 + 1] = {
+ 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
+ 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 1, 3, 0, 3, 1,
+ 3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1,
+ 3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1,
+ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0xff
+ };
+ static const uint8 kCrumbleTilePathOffs[7] = {
+ 0, 25, 66, 77, 87, 98, 108
+ };
+ static const int8 kCrumbleTilePath_X[4] = { 16, -16, 0, 0 };
+ static const int8 kCrumbleTilePath_Y[4] = { 0, 0, 16, -16 };
+ if (overlord_gen2[k]) {
+ if (overlord_gen3[k]) {
+ overlord_gen2[k]--;
+ return;
+ }
+ uint16 x = Overlord_GetX(k) - BG2HOFS_copy2;
+ uint16 y = Overlord_GetY(k) - BG2VOFS_copy2;
+ if (!(x & 0xff00 || y & 0xff00))
+ overlord_gen3[k]++;
+ return;
+ }
+
+ overlord_gen2[k] = 16;
+ SpawnFallingTile(k);
+ int j = overlord_type[k] - 10;
+ int i = overlord_gen1[k]++;
+ if (i == kCrumbleTilePathOffs[j + 1] - kCrumbleTilePathOffs[j]) {
+ overlord_type[k] = 0;
+ }
+ int t = kCrumbleTilePathData[kCrumbleTilePathOffs[j] + i];
+ if (t == 0xff) {
+ Overlord_SetX(k, Overlord_GetX(k) + 0xc1a);
+ Overlord_SetY(k, Overlord_GetY(k) + 0xbb66);
+ } else {
+ Overlord_SetX(k, Overlord_GetX(k) + kCrumbleTilePath_X[t]);
+ Overlord_SetY(k, Overlord_GetY(k) + kCrumbleTilePath_Y[t]);
+ }
+}
+
+void SpawnFallingTile(int k) { // 89bc31
+ int j = GarnishAlloc();
+ if (j >= 0) {
+ garnish_type[j] = 3;
+ garnish_x_hi[j] = overlord_x_hi[k];
+ garnish_x_lo[j] = overlord_x_lo[k];
+ sound_effect_1 = CalculateSfxPan_Arbitrary(garnish_x_lo[j]) | 0x1f;
+ int y = Overlord_GetY(k) + 16;
+ garnish_y_lo[j] = y;
+ garnish_y_hi[j] = y >> 8;
+ garnish_countdown[j] = 31;
+ garnish_active = 31;
+ }
+}
+
+void Overlord09_WallmasterSpawner(int k) { // 89bc7b
+ if (overlord_gen2[k] != 128) {
+ if (!(frame_counter & 1))
+ overlord_gen2[k]--;
+ return;
+ }
+ overlord_gen2[k] = 127;
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamicallyEx(k, 0x90, &info, 12);
+ if (j < 0)
+ return;
+ Sprite_SetX(j, link_x_coord);
+ Sprite_SetY(j, link_y_coord);
+ sprite_z[j] = 208;
+ SpriteSfx_QueueSfx2WithPan(j, 0x20);
+ sprite_floor[j] = link_is_on_lower_level;
+}
+
+void Overlord08_BlobSpawner(int k) { // 89bcc3
+ if (overlord_gen2[k]) {
+ overlord_gen2[k]--;
+ return;
+ }
+ overlord_gen2[k] = 0xa0;
+ int n = 0;
+ for (int i = 0; i != 16; i++) {
+ if (sprite_state[i] != 0 && sprite_type[i] == 0x8f)
+ n++;
+ }
+ if (n >= 5)
+ return;
+
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamicallyEx(k, 0x8f, &info, 12);
+ if (j >= 0) {
+ static const int8 kOverlordZol_X[4] = { 0, 0, -48, 48 };
+ static const int8 kOverlordZol_Y[4] = { -40, 56, 8, 8 };
+ int i = link_direction_facing >> 1;
+ Sprite_SetX(j, link_x_coord + kOverlordZol_X[i]);
+ Sprite_SetY(j, link_y_coord + kOverlordZol_Y[i]);
+ sprite_z[j] = 192;
+ sprite_floor[j] = link_is_on_lower_level;
+ sprite_ai_state[j] = 2;
+ sprite_E[j] = 2;
+ sprite_C[j] = 2;
+ sprite_head_dir[j] = GetRandomNumber() & 31 | 16;
+ }
+}
+
+void Overlord07_MovingFloor(int k) { // 89bd3f
+ if (sprite_state[0] == 4) {
+ overlord_type[k] = 0;
+ BYTE(dung_floor_move_flags) = 1;
+ return;
+ }
+ if (!overlord_gen1[k]) {
+ if (++overlord_gen2[k] == 32) {
+ overlord_gen2[k] = 0;
+ BYTE(dung_floor_move_flags) = (GetRandomNumber() & (overlord_x_lo[k] ? 3 : 1)) * 2;
+ overlord_gen2[k] = (GetRandomNumber() & 127) + 128;
+ overlord_gen1[k]++;
+ } else {
+ BYTE(dung_floor_move_flags) = 1;
+ }
+ } else {
+ if (!--overlord_gen2[k])
+ overlord_gen1[k] = 0;
+ }
+}
+
+void Sprite_Overlord_PlayFallingSfx(int k) { // 89bdfd
+ SpriteSfx_QueueSfx2WithPan(k, 0x20);
+}
+
+void Overlord05_FallingStalfos(int k) { // 89be0f
+ static const uint8 kStalfosTrap_Trigger[8] = { 255, 224, 192, 160, 128, 96, 64, 32 };
+
+ uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
+ uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8) - BG2VOFS_copy2;
+ if (x & 0xff00 || y & 0xff00)
+ return;
+ if (overlord_gen1[k] == 0) {
+ if (byte_7E0B9E)
+ overlord_gen1[k]++;
+ return;
+ }
+ if (overlord_gen1[k]++ == kStalfosTrap_Trigger[k]) {
+ overlord_type[k] = 0;
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamicallyEx(k, 0x85, &info, 12);
+ if (j < 0)
+ return;
+ Sprite_SetX(j, info.r5_overlord_x);
+ Sprite_SetY(j, info.r7_overlord_y);
+ sprite_z[j] = 224;
+ sprite_floor[j] = overlord_floor[k];
+ sprite_D[j] = 0; // zelda bug: unitialized
+ Sprite_Overlord_PlayFallingSfx(j);
+ }
+}
+
+void Overlord06_BadSwitchSnake(int k) { // 89be75
+ static const uint8 kSnakeTrapOverlord_Tab1[8] = { 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90 };
+
+ uint8 a = overlord_gen1[k];
+ if (a == 0) {
+ if (activate_bomb_trap_overlord != 0)
+ overlord_gen1[k] = 1;
+ return;
+ }
+ overlord_gen1[k] = a + 1;
+
+ if (a != kSnakeTrapOverlord_Tab1[k])
+ return;
+
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamically(k, 0x6e, &info);
+ if (j < 0)
+ return;
+ Sprite_SetX(j, info.r5_overlord_x);
+ Sprite_SetY(j, info.r7_overlord_y);
+
+ sprite_z[j] = 192;
+ sprite_E[j] = 192;
+
+ sprite_flags3[j] |= 0x10;
+ sprite_floor[j] = overlord_floor[k];
+ SpriteSfx_QueueSfx2WithPan(j, 0x20);
+ uint8 type = overlord_type[k];
+ overlord_type[k] = 0;
+ if (type == 26) {
+ sprite_type[j] = 74;
+ Sprite_TransmuteToBomb(j);
+ sprite_delay_aux1[j] = 112;
+ }
+}
+
+void Overlord02_FullRoomCannons(int k) { // 89bf09
+ static const uint8 kAllDirectionMetalBallFactory_Idx[16] = { 2, 2, 2, 2, 1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0 };
+ static const uint8 kAllDirectionMetalBallFactory_X[16] = { 64, 96, 144, 176, 240, 240, 240, 240, 176, 144, 96, 64, 0, 0, 0, 0 };
+ static const uint8 kAllDirectionMetalBallFactory_Y[16] = { 16, 16, 16, 16, 64, 96, 160, 192, 240, 240, 240, 240, 192, 160, 96, 64 };
+ uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
+ uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8) - BG2VOFS_copy2;
+ if ((x | y) & 0xff00 || frame_counter & 0xf)
+ return;
+
+ byte_7E0FB6 = 0;
+ int j = GetRandomNumber() & 15;
+ tmp_counter = kAllDirectionMetalBallFactory_Idx[j];
+ overlord_x_lo[k] = kAllDirectionMetalBallFactory_X[j];
+ overlord_x_hi[k] = byte_7E0FB0;
+ overlord_y_lo[k] = kAllDirectionMetalBallFactory_Y[j];
+ overlord_y_hi[k] = byte_7E0FB1 + 1;
+ Overlord_SpawnCannonBall(k, 0);
+}
+
+void Overlord03_VerticalCannon(int k) { // 89bf5b
+ uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
+ if (x & 0xff00) {
+ overlord_gen2[k] = 255;
+ return;
+ }
+ if (!(frame_counter & 1) && overlord_gen2[k])
+ overlord_gen2[k]--;
+ tmp_counter = 2;
+ byte_7E0FB6 = 0;
+ if (!sign8(--overlord_gen1[k]))
+ return;
+ overlord_gen1[k] = 56;
+ int xd;
+ if (!overlord_gen2[k]) {
+ overlord_gen2[k] = 160;
+ byte_7E0FB6 = 160;
+ xd = 8;
+ } else {
+ xd = (GetRandomNumber() & 2) * 8;
+ }
+ Overlord_SpawnCannonBall(k, xd);
+}
+
+void Overlord_SpawnCannonBall(int k, int xd) { // 89bfaf
+ static const int8 kOverlordSpawnBall_Xvel[4] = { 24, -24, 0, 0 };
+ static const int8 kOverlordSpawnBall_Yvel[4] = { 0, 0, 24, -24 };
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamically(k, 0x50, &info);
+ if (j < 0)
+ return;
+
+ Sprite_SetX(j, info.r5_overlord_x + xd);
+ Sprite_SetY(j, info.r7_overlord_y - 1);
+
+ sprite_x_vel[j] = kOverlordSpawnBall_Xvel[tmp_counter];
+ sprite_y_vel[j] = kOverlordSpawnBall_Yvel[tmp_counter];
+ sprite_floor[j] = overlord_floor[k];
+ if (byte_7E0FB6) {
+ sprite_ai_state[j] = byte_7E0FB6;
+ sprite_y_lo[j] = sprite_y_lo[j] + 8;
+ sprite_flags2[j] = 3;
+ sprite_flags4[j] = 9;
+ }
+ sprite_delay_aux2[j] = 64;
+ SpriteSfx_QueueSfx3WithPan(j, 0x7);
+}
+
+void Overlord01_PositionTarget(int k) { // 89c01e
+ byte_7E0FDE = k;
+}
+
+void Overlord_CheckIfActive(int k) { // 89c08d
+ static const int16 kOverlordInRangeOffs[2] = { 0x130, -0x40 };
+ if (player_is_indoors)
+ return;
+ int j = frame_counter & 1;
+ uint16 x = BG2HOFS_copy2 + kOverlordInRangeOffs[j] - (overlord_x_lo[k] | overlord_x_hi[k] << 8);
+ uint16 y = BG2VOFS_copy2 + kOverlordInRangeOffs[j] - (overlord_y_lo[k] | overlord_y_hi[k] << 8);
+ if ((x >> 15) != j || (y >> 15) != j) {
+ overlord_type[k] = 0;
+ uint16 blk = overlord_offset_sprite_pos[k];
+ if (blk != 0xffff) {
+ uint8 loadedmask = (0x80 >> (blk & 7));
+ overworld_sprite_was_loaded[blk >> 3] &= ~loadedmask;
+ }
+ }
+}
+
+void ArmosCoordinator_RotateKnights(int k) { // 9deccc
+ if (!overlord_gen2[k])
+ overlord_gen1[k]++;
+ ArmosCoordinator_Rotate(k);
+}
+
+void ArmosCoordinator_Rotate(int k) { // 9decd4
+ static const uint16 kArmosCoordinator_Tab0[6] = { 0, 425, 340, 255, 170, 85 };
+
+ WORD(overlord_x_lo[0]) += (int8)overlord_floor[k];
+ for (int i = 0; i != 6; i++) {
+ int t0 = WORD(overlord_x_lo[0]) + kArmosCoordinator_Tab0[i];
+ uint8 size = overlord_x_lo[2];
+ int tx = (overlord_x_lo[k] | overlord_x_hi[k] << 8) + ArmosSin(t0, size);
+ overlord_x_hi[i] = tx;
+ overlord_y_hi[i] = tx >> 8;
+ int ty = (overlord_y_lo[k] | overlord_y_hi[k] << 8) + ArmosSin(t0 + 0x80, size);
+ overlord_gen2[i] = ty;
+ overlord_floor[i] = ty >> 8;
+ }
+ tmp_counter = 6;
+}
+
+bool ArmosCoordinator_CheckKnights() { // 9dedb8
+ for (int j = 5; j >= 0; j--) {
+ if (sprite_state[j] && sprite_ai_state[j] == 0)
+ return false;
+ }
+ return true;
+}
+
+void ArmosCoordinator_DisableCoercion(int k) { // 9dedcb
+ for (int j = 5; j >= 0; j--)
+ sprite_ai_state[j] = 0;
+}
+
--- a/overlord.cpp
+++ /dev/null
@@ -1,653 +1,0 @@
-#include "overlord.h"
-#include "sprite.h"
-#include "misc.h"
-#include "sprite_main.h"
-
-uint16 Overlord_GetX(int k) { return (overlord_x_lo[k] | overlord_x_hi[k] << 8); }
-uint16 Overlord_GetY(int k) { return (overlord_y_lo[k] | overlord_y_hi[k] << 8); }
-static HandlerFuncK *const kOverlordFuncs[26] = {
- &Overlord01_PositionTarget,
- &Overlord02_FullRoomCannons,
- &Overlord03_VerticalCannon,
- &Overlord_StalfosFactory,
- &Overlord05_FallingStalfos,
- &Overlord06_BadSwitchSnake,
- &Overlord07_MovingFloor,
- &Overlord08_BlobSpawner,
- &Overlord09_WallmasterSpawner,
- &Overlord0A_FallingSquare,
- &Overlord0A_FallingSquare,
- &Overlord0A_FallingSquare,
- &Overlord0A_FallingSquare,
- &Overlord0A_FallingSquare,
- &Overlord0A_FallingSquare,
- &Overlord10_PirogusuSpawner_left,
- &Overlord10_PirogusuSpawner_left,
- &Overlord10_PirogusuSpawner_left,
- &Overlord10_PirogusuSpawner_left,
- &Overlord14_TileRoom,
- &Overlord15_WizzrobeSpawner,
- &Overlord16_ZoroSpawner,
- &Overlord17_PotTrap,
- &Overlord18_InvisibleStalfos,
- &Overlord19_ArmosCoordinator_bounce,
- &Overlord06_BadSwitchSnake,
-};
-static inline uint8 ArmosMult(uint16 a, uint8 b);
-static inline int8 ArmosSin(uint16 a, uint8 b);
-void Overlord_StalfosFactory(int k) {
- // unused
- assert(0);
-}
-
-void Overlord_SetX(int k, uint16 v) {
- overlord_x_lo[k] = v;
- overlord_x_hi[k] = v >> 8;
-}
-
-void Overlord_SetY(int k, uint16 v) {
- overlord_y_lo[k] = v;
- overlord_y_hi[k] = v >> 8;
-}
-
-static inline uint8 ArmosMult(uint16 a, uint8 b) {
- if (a >= 256)
- return b;
- int p = a * b;
- return (p >> 8) + (p >> 7 & 1);
-}
-
-static inline int8 ArmosSin(uint16 a, uint8 b) {
- uint8 t = ArmosMult(kSinusLookupTable[a & 0xff], b);
- return (a & 0x100) ? -t : t;
-}
-
-void Overlord_SpawnBoulder() { // 89b714
- if (player_is_indoors || !byte_7E0FFD || (submodule_index | flag_unk1) || ++byte_7E0FFE & 63)
- return;
-
- if (sign8((BG2VOFS_copy2 >> 8) - (sprcoll_y_base >> 8) - 2))
- return;
-
- SpriteSpawnInfo info;
- int j = Sprite_SpawnDynamically(0, 0xc2, &info);
- if (j >= 0) {
- Sprite_SetX(j, BG2HOFS_copy2 + (GetRandomNumber() & 127) + 64);
- Sprite_SetY(j, BG2VOFS_copy2 - 0x30);
- sprite_floor[j] = 0;
- sprite_D[j] = 0;
- sprite_z[j] = 0;
- }
-}
-
-void Overlord_Main() { // 89b773
- Overlord_ExecuteAll();
- Overlord_SpawnBoulder();
-}
-
-void Overlord_ExecuteAll() { // 89b77e
- if (submodule_index | flag_unk1)
- return;
- for (int i = 7; i >= 0; i--) {
- if (overlord_type[i])
- Overlord_ExecuteSingle(i);
- }
-}
-
-void Overlord_ExecuteSingle(int k) { // 89b793
- int j = overlord_type[k];
- Overlord_CheckIfActive(k);
- kOverlordFuncs[j - 1](k);
-}
-
-void Overlord19_ArmosCoordinator_bounce(int k) { // 89b7dc
- static const uint8 kArmosCoordinator_BackWallX[6] = { 49, 77, 105, 131, 159, 187 };
-
- if (overlord_gen2[k])
- overlord_gen2[k]--;
- switch (overlord_gen1[k]) {
- case 0: // wait for knight activation
- if (sprite_A[0]) {
- overlord_x_lo[k] = 120;
- overlord_floor[k] = 255;
- overlord_x_lo[2] = 64;
- overlord_x_lo[0] = 192;
- overlord_x_lo[1] = 1;
- ArmosCoordinator_RotateKnights(k);
- }
- break;
- case 1: // wait knight under coercion
- if (ArmosCoordinator_CheckKnights()) {
- overlord_gen1[k]++;
- overlord_gen2[k] = 0xff;
- }
- break;
- case 2: // timed rotate then transition
- case 4:
- ArmosCoordinator_RotateKnights(k);
- break;
- case 3: // radial contraction
- if (--overlord_x_lo[2] == 32) {
- overlord_gen1[k]++;
- overlord_gen2[k] = 64;
- }
- ArmosCoordinator_Rotate(k);
- break;
- case 5: // radial dilation
- if (++overlord_x_lo[2] == 64) {
- overlord_gen1[k]++;
- overlord_gen2[k] = 64;
- }
- ArmosCoordinator_Rotate(k);
- break;
- case 6: // order knights to back wall
- if (overlord_gen2[k])
- return;
- ArmosCoordinator_DisableCoercion(k);
- for (int j = 5; j >= 0; j--) {
- overlord_x_hi[j] = kArmosCoordinator_BackWallX[j];
- overlord_gen2[j] = 48;
- }
- overlord_gen1[k]++;
- overlord_gen2[k] = 255;
- break;
- case 7: // cascade knights to front wall
- if (overlord_gen2[k])
- return;
- for (int j = 5; j >= 0; j--) {
- if (++overlord_gen2[j] == 192) {
- overlord_gen1[k] = 1;
- overlord_floor[k] = -overlord_floor[k];
- ArmosCoordinator_DisableCoercion(k);
- ArmosCoordinator_Rotate(k);
- return;
- }
- }
- break;
- }
-}
-
-void Overlord18_InvisibleStalfos(int k) { // 89b7f5
- static const int8 kRedStalfosTrap_X[4] = { 0, 0, -48, 48 };
- static const int8 kRedStalfosTrap_Y[4] = { -40, 56, 8, 8 };
- static const uint8 kRedStalfosTrap_Delay[4] = { 0x30, 0x50, 0x70, 0x90 };
-
- uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8);
- uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8);
- if ((uint16)(x - link_x_coord + 24) >= 48 || (uint16)(y - link_y_coord + 24) >= 48)
- return;
- overlord_type[k] = 0;
- tmp_counter = 3;
- do {
- SpriteSpawnInfo info;
- int j = Sprite_SpawnDynamicallyEx(k, 0xa7, &info, 12);
- if (j < 0)
- return;
- Sprite_SetX(j, link_x_coord + kRedStalfosTrap_X[tmp_counter]);
- Sprite_SetY(j, link_y_coord + kRedStalfosTrap_Y[tmp_counter]);
- sprite_delay_main[j] = kRedStalfosTrap_Delay[tmp_counter];
- sprite_floor[j] = overlord_floor[k];
- sprite_E[j] = 1;
- sprite_flags2[j] = 3;
- sprite_D[j] = 2;
- } while (!sign8(--tmp_counter));
-}
-
-void Overlord17_PotTrap(int k) { // 89b884
- uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8);
- uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8);
- if ((uint16)(x - link_x_coord + 32) < 64 &&
- (uint16)(y - link_y_coord + 32) < 64) {
- overlord_type[k] = 0;
- byte_7E0B9E++;
- }
-}
-
-void Overlord16_ZoroSpawner(int k) { // 89b8d1
- static const int8 kOverlordZoroFactory_X[8] = { -4, -2, 0, 2, 4, 6, 8, 12 };
- overlord_gen2[k]--;
- uint16 x = Overlord_GetX(k) + 8;
- uint16 y = Overlord_GetY(k) + 8;
- if (GetTileAttribute(overlord_floor[k], &x, y) != 0x82)
- return;
- if (overlord_gen2[k] >= 0x18 || (overlord_gen2[k] & 3) != 0)
- return;
- SpriteSpawnInfo info;
- int j = Sprite_SpawnDynamicallyEx(k, 0x9c, &info, 12);
- if (j >= 0) {
- Sprite_SetX(j, info.r5_overlord_x + kOverlordZoroFactory_X[GetRandomNumber() & 7] + 8);
- sprite_y_lo[j] = info.r7_overlord_y + 8;
- sprite_y_hi[j] = info.r7_overlord_y >> 8;
- sprite_floor[j] = overlord_floor[k];
- sprite_flags4[j] = 1;
- sprite_E[j] = 1;
- sprite_ignore_projectile[j] = 1;
- sprite_y_vel[j] = 16;
- sprite_flags2[j] = 32;
- sprite_oam_flags[j] = 13;
- sprite_subtype2[j] = GetRandomNumber();
- sprite_delay_main[j] = 48;
- sprite_bump_damage[j] = 3;
- }
-}
-
-void Overlord15_WizzrobeSpawner(int k) { // 89b986
- static const int8 kOverlordWizzrobe_X[4] = { 48, -48, 0, 0 };
- static const int8 kOverlordWizzrobe_Y[4] = { 16, 16, 64, -32 };
- static const uint8 kOverlordWizzrobe_Delay[4] = { 0, 16, 32, 48 };
- if (overlord_gen2[k] != 128) {
- if (frame_counter & 1)
- overlord_gen2[k]--;
- return;
- }
- overlord_gen2[k] = 127;
- for (int i = 3; i >= 0; i--) {
- SpriteSpawnInfo info;
- int j = Sprite_SpawnDynamicallyEx(k, 0x9b, &info, 12);
- if (j >= 0) {
- Sprite_SetX(j, link_x_coord + kOverlordWizzrobe_X[i]);
- Sprite_SetY(j, link_y_coord + kOverlordWizzrobe_Y[i]);
- sprite_delay_main[j] = kOverlordWizzrobe_Delay[i];
- sprite_floor[j] = overlord_floor[k];
- sprite_B[j] = 1;
- }
- }
- tmp_counter = 0xff;
-}
-
-void Overlord14_TileRoom(int k) { // 89b9e8
- uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
- uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8) - BG2VOFS_copy2;
- if (x & 0xff00 || y & 0xff00)
- return;
- if (--overlord_gen2[k] != 0x80)
- return;
- int j = TileRoom_SpawnTile(k);
- if (j < 0) {
- overlord_gen2[k] = 0x81;
- return;
- }
- if (++overlord_gen1[k] != 22)
- overlord_gen2[k] = 0xE0;
- else
- overlord_type[k] = 0;
-}
-
-int TileRoom_SpawnTile(int k) { // 89ba56
- static const uint8 kSpawnFlyingTile_X[22] = {
- 0x70, 0x80, 0x60, 0x90, 0x90, 0x60, 0x70, 0x80, 0x80, 0x70, 0x50, 0xa0, 0xa0, 0x50, 0x50, 0xa0,
- 0xa0, 0x50, 0x70, 0x80, 0x80, 0x70,
- };
- static const uint8 kSpawnFlyingTile_Y[22] = {
- 0x80, 0x80, 0x70, 0x90, 0x70, 0x90, 0x60, 0xa0, 0x60, 0xa0, 0x60, 0xb0, 0x60, 0xb0, 0x80, 0x90,
- 0x80, 0x90, 0x70, 0x90, 0x70, 0x90,
- };
- SpriteSpawnInfo info;
- int j = Sprite_SpawnDynamically(k, 0x94, &info);
- if (j < 0)
- return j;
- sprite_E[j] = 1;
- int i = overlord_gen1[k];
- sprite_x_lo[j] = kSpawnFlyingTile_X[i];
- sprite_y_lo[j] = kSpawnFlyingTile_Y[i] - 8;
- sprite_y_hi[j] = overlord_y_hi[k];
- sprite_x_hi[j] = overlord_x_hi[k];
- sprite_floor[j] = overlord_floor[k];
- sprite_health[j] = 4;
- sprite_flags5[j] = 0;
- sprite_health[j] = 0;
- sprite_defl_bits[j] = 8;
- sprite_flags2[j] = 4;
- sprite_oam_flags[j] = 1;
- sprite_bump_damage[j] = 4;
- return j;
-}
-
-void Overlord10_PirogusuSpawner_left(int k) { // 89baac
- static const uint8 kOverlordPirogusu_A[4] = { 2, 3, 0, 1 };
-
- tmp_counter = overlord_type[k] - 16;
- if (overlord_gen2[k] != 128) {
- overlord_gen2[k]--;
- return;
- }
- overlord_gen2[k] = (GetRandomNumber() & 31) + 96;
- int n = 0;
- for (int i = 0; i != 16; i++) {
- if (sprite_state[i] != 0 && sprite_type[i] == 0x10)
- n++;
- }
- if (n >= 5)
- return;
- SpriteSpawnInfo info;
- int j = Sprite_SpawnDynamicallyEx(k, 0x94, &info, 12);
- if (j >= 0) {
- Sprite_SetX(j, info.r5_overlord_x);
- Sprite_SetY(j, info.r7_overlord_y);
- sprite_floor[j] = overlord_floor[k];
- sprite_delay_main[j] = 32;
- sprite_D[j] = tmp_counter;
- sprite_A[j] = kOverlordPirogusu_A[tmp_counter];
- }
-}
-
-void Overlord0A_FallingSquare(int k) { // 89bbb2
- static const uint8 kCrumbleTilePathData[108 + 1] = {
- 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
- 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 1, 3, 0, 3, 1,
- 3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1,
- 3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1,
- 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0xff
- };
- static const uint8 kCrumbleTilePathOffs[7] = {
- 0, 25, 66, 77, 87, 98, 108
- };
- static const int8 kCrumbleTilePath_X[4] = { 16, -16, 0, 0 };
- static const int8 kCrumbleTilePath_Y[4] = { 0, 0, 16, -16 };
- if (overlord_gen2[k]) {
- if (overlord_gen3[k]) {
- overlord_gen2[k]--;
- return;
- }
- uint16 x = Overlord_GetX(k) - BG2HOFS_copy2;
- uint16 y = Overlord_GetY(k) - BG2VOFS_copy2;
- if (!(x & 0xff00 || y & 0xff00))
- overlord_gen3[k]++;
- return;
- }
-
- overlord_gen2[k] = 16;
- SpawnFallingTile(k);
- int j = overlord_type[k] - 10;
- int i = overlord_gen1[k]++;
- if (i == kCrumbleTilePathOffs[j + 1] - kCrumbleTilePathOffs[j]) {
- overlord_type[k] = 0;
- }
- int t = kCrumbleTilePathData[kCrumbleTilePathOffs[j] + i];
- if (t == 0xff) {
- Overlord_SetX(k, Overlord_GetX(k) + 0xc1a);
- Overlord_SetY(k, Overlord_GetY(k) + 0xbb66);
- } else {
- Overlord_SetX(k, Overlord_GetX(k) + kCrumbleTilePath_X[t]);
- Overlord_SetY(k, Overlord_GetY(k) + kCrumbleTilePath_Y[t]);
- }
-}
-
-void SpawnFallingTile(int k) { // 89bc31
- int j = GarnishAlloc();
- if (j >= 0) {
- garnish_type[j] = 3;
- garnish_x_hi[j] = overlord_x_hi[k];
- garnish_x_lo[j] = overlord_x_lo[k];
- sound_effect_1 = CalculateSfxPan_Arbitrary(garnish_x_lo[j]) | 0x1f;
- int y = Overlord_GetY(k) + 16;
- garnish_y_lo[j] = y;
- garnish_y_hi[j] = y >> 8;
- garnish_countdown[j] = 31;
- garnish_active = 31;
- }
-}
-
-void Overlord09_WallmasterSpawner(int k) { // 89bc7b
- if (overlord_gen2[k] != 128) {
- if (!(frame_counter & 1))
- overlord_gen2[k]--;
- return;
- }
- overlord_gen2[k] = 127;
- SpriteSpawnInfo info;
- int j = Sprite_SpawnDynamicallyEx(k, 0x90, &info, 12);
- if (j < 0)
- return;
- Sprite_SetX(j, link_x_coord);
- Sprite_SetY(j, link_y_coord);
- sprite_z[j] = 208;
- SpriteSfx_QueueSfx2WithPan(j, 0x20);
- sprite_floor[j] = link_is_on_lower_level;
-}
-
-void Overlord08_BlobSpawner(int k) { // 89bcc3
- if (overlord_gen2[k]) {
- overlord_gen2[k]--;
- return;
- }
- overlord_gen2[k] = 0xa0;
- int n = 0;
- for (int i = 0; i != 16; i++) {
- if (sprite_state[i] != 0 && sprite_type[i] == 0x8f)
- n++;
- }
- if (n >= 5)
- return;
-
- SpriteSpawnInfo info;
- int j = Sprite_SpawnDynamicallyEx(k, 0x8f, &info, 12);
- if (j >= 0) {
- static const int8 kOverlordZol_X[4] = { 0, 0, -48, 48 };
- static const int8 kOverlordZol_Y[4] = { -40, 56, 8, 8 };
- int i = link_direction_facing >> 1;
- Sprite_SetX(j, link_x_coord + kOverlordZol_X[i]);
- Sprite_SetY(j, link_y_coord + kOverlordZol_Y[i]);
- sprite_z[j] = 192;
- sprite_floor[j] = link_is_on_lower_level;
- sprite_ai_state[j] = 2;
- sprite_E[j] = 2;
- sprite_C[j] = 2;
- sprite_head_dir[j] = GetRandomNumber() & 31 | 16;
- }
-}
-
-void Overlord07_MovingFloor(int k) { // 89bd3f
- if (sprite_state[0] == 4) {
- overlord_type[k] = 0;
- BYTE(dung_floor_move_flags) = 1;
- return;
- }
- if (!overlord_gen1[k]) {
- if (++overlord_gen2[k] == 32) {
- overlord_gen2[k] = 0;
- BYTE(dung_floor_move_flags) = (GetRandomNumber() & (overlord_x_lo[k] ? 3 : 1)) * 2;
- overlord_gen2[k] = (GetRandomNumber() & 127) + 128;
- overlord_gen1[k]++;
- } else {
- BYTE(dung_floor_move_flags) = 1;
- }
- } else {
- if (!--overlord_gen2[k])
- overlord_gen1[k] = 0;
- }
-}
-
-void Sprite_Overlord_PlayFallingSfx(int k) { // 89bdfd
- SpriteSfx_QueueSfx2WithPan(k, 0x20);
-}
-
-void Overlord05_FallingStalfos(int k) { // 89be0f
- static const uint8 kStalfosTrap_Trigger[8] = { 255, 224, 192, 160, 128, 96, 64, 32 };
-
- uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
- uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8) - BG2VOFS_copy2;
- if (x & 0xff00 || y & 0xff00)
- return;
- if (overlord_gen1[k] == 0) {
- if (byte_7E0B9E)
- overlord_gen1[k]++;
- return;
- }
- if (overlord_gen1[k]++ == kStalfosTrap_Trigger[k]) {
- overlord_type[k] = 0;
- SpriteSpawnInfo info;
- int j = Sprite_SpawnDynamicallyEx(k, 0x85, &info, 12);
- if (j < 0)
- return;
- Sprite_SetX(j, info.r5_overlord_x);
- Sprite_SetY(j, info.r7_overlord_y);
- sprite_z[j] = 224;
- sprite_floor[j] = overlord_floor[k];
- sprite_D[j] = 0; // zelda bug: unitialized
- Sprite_Overlord_PlayFallingSfx(j);
- }
-}
-
-void Overlord06_BadSwitchSnake(int k) { // 89be75
- static const uint8 kSnakeTrapOverlord_Tab1[8] = { 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90 };
-
- uint8 a = overlord_gen1[k];
- if (a == 0) {
- if (activate_bomb_trap_overlord != 0)
- overlord_gen1[k] = 1;
- return;
- }
- overlord_gen1[k] = a + 1;
-
- if (a != kSnakeTrapOverlord_Tab1[k])
- return;
-
- SpriteSpawnInfo info;
- int j = Sprite_SpawnDynamically(k, 0x6e, &info);
- if (j < 0)
- return;
- Sprite_SetX(j, info.r5_overlord_x);
- Sprite_SetY(j, info.r7_overlord_y);
-
- sprite_z[j] = 192;
- sprite_E[j] = 192;
-
- sprite_flags3[j] |= 0x10;
- sprite_floor[j] = overlord_floor[k];
- SpriteSfx_QueueSfx2WithPan(j, 0x20);
- uint8 type = overlord_type[k];
- overlord_type[k] = 0;
- if (type == 26) {
- sprite_type[j] = 74;
- Sprite_TransmuteToBomb(j);
- sprite_delay_aux1[j] = 112;
- }
-}
-
-void Overlord02_FullRoomCannons(int k) { // 89bf09
- static const uint8 kAllDirectionMetalBallFactory_Idx[16] = { 2, 2, 2, 2, 1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0 };
- static const uint8 kAllDirectionMetalBallFactory_X[16] = { 64, 96, 144, 176, 240, 240, 240, 240, 176, 144, 96, 64, 0, 0, 0, 0 };
- static const uint8 kAllDirectionMetalBallFactory_Y[16] = { 16, 16, 16, 16, 64, 96, 160, 192, 240, 240, 240, 240, 192, 160, 96, 64 };
- uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
- uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8) - BG2VOFS_copy2;
- if ((x | y) & 0xff00 || frame_counter & 0xf)
- return;
-
- byte_7E0FB6 = 0;
- int j = GetRandomNumber() & 15;
- tmp_counter = kAllDirectionMetalBallFactory_Idx[j];
- overlord_x_lo[k] = kAllDirectionMetalBallFactory_X[j];
- overlord_x_hi[k] = byte_7E0FB0;
- overlord_y_lo[k] = kAllDirectionMetalBallFactory_Y[j];
- overlord_y_hi[k] = byte_7E0FB1 + 1;
- Overlord_SpawnCannonBall(k, 0);
-}
-
-void Overlord03_VerticalCannon(int k) { // 89bf5b
- uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
- if (x & 0xff00) {
- overlord_gen2[k] = 255;
- return;
- }
- if (!(frame_counter & 1) && overlord_gen2[k])
- overlord_gen2[k]--;
- tmp_counter = 2;
- byte_7E0FB6 = 0;
- if (!sign8(--overlord_gen1[k]))
- return;
- overlord_gen1[k] = 56;
- int xd;
- if (!overlord_gen2[k]) {
- overlord_gen2[k] = 160;
- byte_7E0FB6 = 160;
- xd = 8;
- } else {
- xd = (GetRandomNumber() & 2) * 8;
- }
- Overlord_SpawnCannonBall(k, xd);
-}
-
-void Overlord_SpawnCannonBall(int k, int xd) { // 89bfaf
- static const int8 kOverlordSpawnBall_Xvel[4] = { 24, -24, 0, 0 };
- static const int8 kOverlordSpawnBall_Yvel[4] = { 0, 0, 24, -24 };
- SpriteSpawnInfo info;
- int j = Sprite_SpawnDynamically(k, 0x50, &info);
- if (j < 0)
- return;
-
- Sprite_SetX(j, info.r5_overlord_x + xd);
- Sprite_SetY(j, info.r7_overlord_y - 1);
-
- sprite_x_vel[j] = kOverlordSpawnBall_Xvel[tmp_counter];
- sprite_y_vel[j] = kOverlordSpawnBall_Yvel[tmp_counter];
- sprite_floor[j] = overlord_floor[k];
- if (byte_7E0FB6) {
- sprite_ai_state[j] = byte_7E0FB6;
- sprite_y_lo[j] = sprite_y_lo[j] + 8;
- sprite_flags2[j] = 3;
- sprite_flags4[j] = 9;
- }
- sprite_delay_aux2[j] = 64;
- SpriteSfx_QueueSfx3WithPan(j, 0x7);
-}
-
-void Overlord01_PositionTarget(int k) { // 89c01e
- byte_7E0FDE = k;
-}
-
-void Overlord_CheckIfActive(int k) { // 89c08d
- static const int16 kOverlordInRangeOffs[2] = { 0x130, -0x40 };
- if (player_is_indoors)
- return;
- int j = frame_counter & 1;
- uint16 x = BG2HOFS_copy2 + kOverlordInRangeOffs[j] - (overlord_x_lo[k] | overlord_x_hi[k] << 8);
- uint16 y = BG2VOFS_copy2 + kOverlordInRangeOffs[j] - (overlord_y_lo[k] | overlord_y_hi[k] << 8);
- if ((x >> 15) != j || (y >> 15) != j) {
- overlord_type[k] = 0;
- uint16 blk = overlord_offset_sprite_pos[k];
- if (blk != 0xffff) {
- uint8 loadedmask = (0x80 >> (blk & 7));
- overworld_sprite_was_loaded[blk >> 3] &= ~loadedmask;
- }
- }
-}
-
-void ArmosCoordinator_RotateKnights(int k) { // 9deccc
- if (!overlord_gen2[k])
- overlord_gen1[k]++;
- ArmosCoordinator_Rotate(k);
-}
-
-void ArmosCoordinator_Rotate(int k) { // 9decd4
- static const uint16 kArmosCoordinator_Tab0[6] = { 0, 425, 340, 255, 170, 85 };
-
- WORD(overlord_x_lo[0]) += (int8)overlord_floor[k];
- for (int i = 0; i != 6; i++) {
- int t0 = WORD(overlord_x_lo[0]) + kArmosCoordinator_Tab0[i];
- uint8 size = overlord_x_lo[2];
- int tx = (overlord_x_lo[k] | overlord_x_hi[k] << 8) + ArmosSin(t0, size);
- overlord_x_hi[i] = tx;
- overlord_y_hi[i] = tx >> 8;
- int ty = (overlord_y_lo[k] | overlord_y_hi[k] << 8) + ArmosSin(t0 + 0x80, size);
- overlord_gen2[i] = ty;
- overlord_floor[i] = ty >> 8;
- }
- tmp_counter = 6;
-}
-
-bool ArmosCoordinator_CheckKnights() { // 9dedb8
- for (int j = 5; j >= 0; j--) {
- if (sprite_state[j] && sprite_ai_state[j] == 0)
- return false;
- }
- return true;
-}
-
-void ArmosCoordinator_DisableCoercion(int k) { // 9dedcb
- for (int j = 5; j >= 0; j--)
- sprite_ai_state[j] = 0;
-}
-
--- /dev/null
+++ b/overworld.c
@@ -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_LoadAmbientOverlayFalse,
+ &Overworld_Func22,
+ &Module09_MirrorWarp,
+ &Overworld_StartMosaicTransition,
+ &Overworld_LoadOverlays,
+ &Module09_LoadAuxGFX,
+ &Overworld_FinishTransGfx,
+ &Overworld_LoadAndBuildScreen,
+ &Module09_FadeBackInFromMosaic,
+ &Module09_2A_RecoverFromDrowning,
+ &Overworld_Func2B,
+ &Module09_MirrorWarp,
+ &Overworld_WeathervaneExplosion,
+ &Module09_2E_Whirlpool,
+ &Overworld_Func2F,
+};
+static PlayerHandlerFunc *const kModule_PreOverworld[3] = {
+ &PreOverworld_LoadProperties,
+ &PreOverworld_LoadOverlays,
+ &Module08_02_LoadAndAdvance,
+};
+const uint8 *GetMap8toTileAttr() {
+ return kMap8DataToTileAttr;
+}
+
+const uint16 *GetMap16toMap8Table() {
+ return kMap16ToMap8;
+}
+
+bool LookupInOwEntranceTab(uint16 r0, uint16 r2) {
+ for (int i = countof(kOverworld_Entrance_Tab0) - 1; i >= 0; i--) {
+ if (r0 == kOverworld_Entrance_Tab0[i] && r2 == kOverworld_Entrance_Tab1[i])
+ return true;
+ }
+ return false;
+}
+
+int LookupInOwEntranceTab2(uint16 pos) {
+ for (int i = 128; i >= 0; i--) {
+ if (pos == kOverworld_Entrance_Pos[i] && overworld_area_index == kOverworld_Entrance_Area[i])
+ return i;
+ }
+ return -1;
+}
+
+bool CanEnterWithTagalong(int e) {
+ uint8 t = 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_LoadAmbientOverlayFalse() { // 82ed24
+ Overworld_LoadAmbientOverlay(false);
+}
+
+void Overworld_LoadAndBuildScreen() { // 82ed59
+ Overworld_LoadAmbientOverlay(true);
+}
+
+void Module08_02_LoadAndAdvance() { // 82edb9
+ Overworld_LoadAndBuildScreen();
+ main_module_index = 16;
+ submodule_index = 0;
+ subsubmodule_index = 0;
+}
+
+void Overworld_DrawQuadrantsAndOverlays() { // 82eec5
+ Overworld_DecompressAndDrawAllQuadrants();
+ for (int i = 0; i < 16 * 4; i++)
+ dung_bg1[i] = 0xdc4;
+ uint16 pos = ow_entrance_value;
+ if (pos != 0 && pos != 0xffff) {
+ if (pos < 0x8000) {
+ dung_bg2[pos >> 1] = 0xDA4;
+ Overworld_Memorize_Map16_Change(pos, 0xda4);
+ dung_bg2[(pos + 2) >> 1] = 0xda6;
+ Overworld_Memorize_Map16_Change(pos + 2, 0xda6);
+ } else {
+ pos &= 0x1fff;
+ dung_bg2[pos >> 1] = 0xdb4;
+ Overworld_Memorize_Map16_Change(pos, 0xdb4);
+ dung_bg2[(pos + 2) >> 1] = 0xdb5;
+ Overworld_Memorize_Map16_Change(pos + 2, 0xdb5);
+ }
+ ow_entrance_value = 0;
+ }
+ Overworld_HandleOverlaysAndBombDoors();
+}
+
+void Overworld_HandleOverlaysAndBombDoors() { // 82ef29
+ if (overworld_screen_index == 0x33)
+ dung_bg2[340] = 0x20f;
+ else if (overworld_screen_index == 0x2f)
+ dung_bg2[1497] = 0x20f;
+ if (BYTE(overworld_screen_index) < 0x80 && save_ow_event_info[BYTE(overworld_screen_index)] & 0x20)
+ Overworld_LoadEventOverlay();
+ if (save_ow_event_info[BYTE(overworld_screen_index)] & 2) {
+ int pos = kSecondaryOverlayPerOw[overworld_screen_index] >> 1;
+ dung_bg2[pos + 0] = 0xdb4;
+ dung_bg2[pos + 1] = 0xdb5;
+ }
+}
+
+void TriggerAndFinishMapLoadStripe_Y(int n) { // 82ef7a
+ BYTE(overworld_screen_trans_dir_bits2) = 8;
+ nmi_subroutine_index = 3;
+ uint16 *dst = uvram.data;
+ *dst++ = 0x80;
+ do {
+ dst = BufferAndBuildMap16Stripes_Y(dst);
+ map16_load_src_off -= 0x80;
+ map16_load_var2 = (map16_load_var2 - 1) & 0x1f;
+ } while (--n);
+ *dst = 0xffff;
+}
+
+void TriggerAndFinishMapLoadStripe_X(int n) { // 82efb3
+ BYTE(overworld_screen_trans_dir_bits2) = 2;
+ nmi_subroutine_index = 3;
+ uint16 *dst = uvram.data;
+ *dst++ = 0x8040;
+ do {
+ dst = BufferAndBuildMap16Stripes_X(dst);
+ map16_load_src_off -= 2;
+ map16_load_dst_off = (map16_load_dst_off - 1) & 0x1f;
+ } while (--n);
+ *dst = 0xffff;
+}
+
+void SomeTileMapChange() { // 82efe8
+ Overworld_DecompressAndDrawAllQuadrants();
+ for (int i = 0; i < 64; i++)
+ dung_bg1[i] = 0xdc4;
+ Overworld_HandleOverlaysAndBombDoors();
+ submodule_index++;
+}
+
+void CreateInitialNewScreenMapToScroll() { // 82f031
+ if (!kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
+ switch (BYTE(overworld_screen_trans_dir_bits2)) {
+ case 1: CreateInitialOWScreenView_Big_East(); break;
+ case 2: CreateInitialOWScreenView_Big_West(); break;
+ case 4: CreateInitialOWScreenView_Big_South(); break;
+ case 8: CreateInitialOWScreenView_Big_North(); break;
+ default:
+ assert(0);
+ submodule_index = 0;
+ }
+ } else {
+ switch (BYTE(overworld_screen_trans_dir_bits2)) {
+ case 1: CreateInitialOWScreenView_Small_East(); break;
+ case 2: CreateInitialOWScreenView_Small_West(); break;
+ case 4: CreateInitialOWScreenView_Small_South(); break;
+ case 8: CreateInitialOWScreenView_Small_North(); break;
+ default:
+ assert(0);
+ submodule_index = 0;
+ }
+ }
+}
+
+void CreateInitialOWScreenView_Big_North() { // 82f06b
+ map16_load_src_off += 0x380;
+ map16_load_var2 = 31;
+ TriggerAndFinishMapLoadStripe_Y(7);
+}
+
+void CreateInitialOWScreenView_Big_South() { // 82f087
+ uint16 pos = map16_load_src_off;
+ while (pos >= 0x80)
+ pos -= 0x80;
+ map16_load_src_off = pos + 0x780;
+ map16_load_var2 = 7;
+ TriggerAndFinishMapLoadStripe_Y(8);
+ map16_load_var2 = (map16_load_var2 + 9) & 0x1f;
+ map16_load_src_off -= 0xB80;
+}
+
+void CreateInitialOWScreenView_Big_West() { // 82f0c0
+ map16_load_src_off += 14;
+ map16_load_dst_off = 31;
+ TriggerAndFinishMapLoadStripe_X(7);
+}
+
+void CreateInitialOWScreenView_Big_East() { // 82f0dc
+ map16_load_src_off = map16_load_src_off - 0x60 + 0x1e;
+ map16_load_dst_off = 7;
+ TriggerAndFinishMapLoadStripe_X(8);
+ map16_load_dst_off = (map16_load_dst_off + 9) & 0x1f;
+ map16_load_src_off -= 0x2e;
+}
+
+void CreateInitialOWScreenView_Small_North() { // 82f10f
+ orange_blue_barrier_state = map16_load_src_off - 0x700;
+ word_7EC174 = map16_load_dst_off;
+ word_7EC176 = 10;
+ map16_load_src_off = 0x1390;
+ map16_load_dst_off = 0;
+ map16_load_var2 = 31;
+ TriggerAndFinishMapLoadStripe_Y(7);
+}
+
+void CreateInitialOWScreenView_Small_South() { // 82f141
+ orange_blue_barrier_state = BYTE(map16_load_src_off);
+ word_7EC174 = map16_load_dst_off;
+ word_7EC176 = 24;
+ map16_load_src_off = 0x790;
+ map16_load_dst_off = 0;
+ map16_load_var2 = 7;
+ TriggerAndFinishMapLoadStripe_Y(8);
+ map16_load_var2 = (map16_load_var2 + 9) & 0x1f;
+ map16_load_src_off -= 0xB80;
+}
+
+void CreateInitialOWScreenView_Small_West() { // 82f185
+ orange_blue_barrier_state = map16_load_src_off - 0x20;
+ word_7EC174 = 8;
+ word_7EC176 = map16_load_var2;
+ map16_load_src_off = 0x44e;
+ map16_load_var2 = 0;
+ map16_load_dst_off = 31;
+ TriggerAndFinishMapLoadStripe_X(7);
+}
+
+void CreateInitialOWScreenView_Small_East() { // 82f1b7
+ orange_blue_barrier_state = map16_load_src_off - 0x60;
+ word_7EC174 = 0x18;
+ word_7EC176 = map16_load_var2;
+ map16_load_src_off = 0x41e;
+ map16_load_var2 = 0;
+ map16_load_dst_off = 7;
+ TriggerAndFinishMapLoadStripe_X(8);
+ map16_load_dst_off = (map16_load_dst_off + 9) & 0x1f;
+ map16_load_src_off -= 0x2e;
+}
+
+void OverworldTransitionScrollAndLoadMap() { // 82f20e
+ uint16 *dst = uvram.data;
+ switch (BYTE(overworld_screen_trans_dir_bits2)) {
+ case 1: dst = BuildFullStripeDuringTransition_East(dst); break;
+ case 2: dst = BuildFullStripeDuringTransition_West(dst); break;
+ case 4: dst = BuildFullStripeDuringTransition_South(dst); break;
+ case 8: dst = BuildFullStripeDuringTransition_North(dst); break;
+ default:
+ assert(0);
+ submodule_index = 0;
+ }
+ dst[0] = dst[1] = 0xffff;
+ if (dst != uvram.data)
+ nmi_subroutine_index = 3;
+}
+
+uint16 *BuildFullStripeDuringTransition_North(uint16 *dst) { // 82f218
+ *dst++ = 0x80;
+ dst = BufferAndBuildMap16Stripes_Y(dst);
+ map16_load_src_off -= 0x80;
+ map16_load_var2 = (map16_load_var2 - 1) & 0x1f;
+ return dst;
+}
+
+uint16 *BuildFullStripeDuringTransition_South(uint16 *dst) { // 82f238
+ *dst++ = 0x80;
+ dst = BufferAndBuildMap16Stripes_Y(dst);
+ map16_load_src_off += 0x80;
+ map16_load_var2 = (map16_load_var2 + 1) & 0x1f;
+ return dst;
+}
+
+uint16 *BuildFullStripeDuringTransition_West(uint16 *dst) { // 82f241
+ *dst++ = 0x8040;
+ dst = BufferAndBuildMap16Stripes_X(dst);
+ map16_load_src_off -= 2;
+ map16_load_dst_off = (map16_load_dst_off - 1) & 0x1f;
+ return dst;
+}
+
+uint16 *BuildFullStripeDuringTransition_East(uint16 *dst) { // 82f24a
+ *dst++ = 0x8040;
+ dst = BufferAndBuildMap16Stripes_X(dst);
+ map16_load_src_off += 2;
+ map16_load_dst_off = (map16_load_dst_off + 1) & 0x1f;
+ return dst;
+}
+
+void OverworldHandleMapScroll() { // 82f273
+ uint16 *dst = uvram.data;
+ switch (BYTE(overworld_screen_trans_dir_bits2)) {
+ case 1:
+ dst = CheckForNewlyLoadedMapAreas_East(dst);
+ BYTE(overworld_screen_trans_dir_bits2) = 0;
+ break;
+ case 2:
+ dst = CheckForNewlyLoadedMapAreas_West(dst);
+ BYTE(overworld_screen_trans_dir_bits2) = 0;
+ break;
+ case 4:
+ dst = CheckForNewlyLoadedMapAreas_South(dst);
+ BYTE(overworld_screen_trans_dir_bits2) = 0;
+ break;
+ case 5:
+ case 6:
+ dst = CheckForNewlyLoadedMapAreas_South(dst);
+ BYTE(overworld_screen_trans_dir_bits2) &= 3;
+ break;
+ case 8:
+ dst = CheckForNewlyLoadedMapAreas_North(dst);
+ BYTE(overworld_screen_trans_dir_bits2) = 0;
+ break;
+ case 9:
+ case 10:
+ dst = CheckForNewlyLoadedMapAreas_North(dst);
+ BYTE(overworld_screen_trans_dir_bits2) &= 3;
+ break;
+ default:
+ assert(0);
+ submodule_index = 0;
+ }
+ dst[0] = dst[1] = 0xffff;
+ if (dst != uvram.data)
+ nmi_subroutine_index = 3;
+ overworld_screen_transition = overworld_screen_trans_dir_bits2;
+}
+
+uint16 *CheckForNewlyLoadedMapAreas_North(uint16 *dst) { // 82f2dd
+ if (sign16(map16_load_src_off - 0x80))
+ return dst;
+ if (!kOverworldMapIsSmall[overworld_screen_index]) {
+ *dst++ = 0x80;
+ dst = BufferAndBuildMap16Stripes_Y(dst);
+ }
+ map16_load_src_off -= 0x80;
+ map16_load_var2 = (map16_load_var2 - 1) & 0x1f;
+ return dst;
+}
+
+uint16 *CheckForNewlyLoadedMapAreas_South(uint16 *dst) { // 82f311
+ if (map16_load_src_off >= 0x1800)
+ return dst;
+ if (!kOverworldMapIsSmall[overworld_screen_index]) {
+ *dst++ = 0x80;
+ dst = BufferAndBuildMap16Stripes_Y(dst);
+ }
+ map16_load_src_off += 0x80;
+ map16_load_var2 = (map16_load_var2 + 1) & 0x1f;
+ return dst;
+}
+
+uint16 *CheckForNewlyLoadedMapAreas_West(uint16 *dst) { // 82f345
+ uint16 pos = map16_load_src_off;
+ while (pos >= 0x80)
+ pos -= 0x80;
+ if (pos == 0)
+ return dst;
+ if (!kOverworldMapIsSmall[overworld_screen_index]) {
+ *dst++ = 0x8040;
+ dst = BufferAndBuildMap16Stripes_X(dst);
+ }
+ map16_load_src_off -= 2;
+ map16_load_dst_off = (map16_load_dst_off - 1) & 0x1f;
+ return dst;
+}
+
+uint16 *CheckForNewlyLoadedMapAreas_East(uint16 *dst) { // 82f37f
+ uint16 pos = map16_load_src_off;
+ while (pos >= 0x80)
+ pos -= 0x80;
+ if (pos >= 0x60)
+ return dst;
+ if (!kOverworldMapIsSmall[overworld_screen_index]) {
+ *dst++ = 0x8040;
+ dst = BufferAndBuildMap16Stripes_X(dst);
+ }
+ map16_load_src_off += 2;
+ map16_load_dst_off = (map16_load_dst_off + 1) & 0x1f;
+ return dst;
+}
+
+uint16 *BufferAndBuildMap16Stripes_X(uint16 *dst) { // 82f3b9
+ uint16 pos = map16_load_src_off - kOverworld_DrawStrip_Tab[overworld_screen_trans_dir_bits2 >> 1 & 1];
+ int d = map16_load_var2;
+ uint16 *tmp = dung_replacement_tile_state;
+ for (int i = 0; i < 32; i++) {
+ tmp[d] = (pos >= 0x2000) ? 0 : dung_bg2[pos >> 1];
+ d = (d + 1) & 0x1f, pos += 128;
+ }
+ const uint16 *map8 = GetMap16toMap8Table();
+ uint16 r0 = 0, of = map16_load_dst_off;
+ if (of >= 0x10)
+ of &= 0xf, r0 = 0x400;
+ r0 += of * 2;
+ for (int i = 0; i < 2; i++, r0 += 0x800) {
+ dst[0] = r0;
+ dst[33] = r0 + 1;
+ dst++;
+ for (int j = 0; j < 16; j++) {
+ int k = *tmp++;
+ assert(k < 0xea8);
+ const uint16 *s = map8 + k * 4;
+ dst[0] = s[0];
+ dst[33] = s[1];
+ dst[1] = s[2];
+ dst[34] = s[3];
+ dst += 2;
+ }
+ dst += 33;
+ }
+ return dst;
+}
+
+uint16 *BufferAndBuildMap16Stripes_Y(uint16 *dst) { // 82f482
+ uint16 pos = map16_load_src_off - kOverworld_DrawStrip_Tab[1 + (overworld_screen_trans_dir_bits2 >> 2 & 1)];
+ int d = map16_load_dst_off;
+ uint16 *tmp = dung_replacement_tile_state;
+ for (int i = 0; i < 32; i++) {
+ tmp[d] = (pos >= 0x2000) ? 0 : dung_bg2[pos >> 1]; // fixed bug warning. can go negative
+ pos += 2;
+ d = (d + 1) & 0x1f;
+ }
+ const uint16 *map8 = GetMap16toMap8Table();
+ uint16 r0 = 0, of = map16_load_var2;
+ if (of >= 0x10)
+ of &= 0xf, r0 = 0x800;
+ r0 += of * 64;
+ for (int i = 0; i < 2; i++, r0 += 0x400) {
+ *dst++ = r0;
+ for (int j = 0; j < 16; j++) {
+ int k = *tmp++;
+ assert(k < 0xea8);
+ const uint16 *s = map8 + k * 4;
+ dst[0] = s[0];
+ dst[32] = s[2];
+ dst[1] = s[1];
+ dst[33] = s[3];
+ dst += 2;
+ }
+ dst += 32;
+ }
+ return dst;
+}
+
+void Overworld_DecompressAndDrawAllQuadrants() { // 82f54a
+ int si = overworld_screen_index;
+ Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x2000], si + 0);
+ Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x2040], si + 1);
+ Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x3000], si + 8);
+ Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x3040], si + 9);
+}
+
+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;
+ uint32 result;
+check_secret:
+ result = Overworld_RevealSecret(pos);
+ if (result != 0)
+ yv = result;
+memoize_getout:
+ overworld_tileattr[pos >> 1] = yv;
+ Overworld_Memorize_Map16_Change(pos, yv);
+ Overworld_DrawMap16(pos, yv);
+ nmi_load_bg_from_vram = 1;
+ }
+ uint16 t;
+ t = GetMap16toMap8Table()[attr * 4 + ((y & 8) >> 2) + (x & 1)];
+ attr = kMap8DataToTileAttr[t & 0x1ff];
+ if (index_of_interacting_tile) {
+ Sprite_SpawnImmediatelySmashedTerrain(index_of_interacting_tile, scratch_0, scratch_1);
+ AncillaAdd_BushPoof(scratch_0, scratch_1);
+ }
+ return attr;
+ }
+ return attr;
+ } else { // else_1
+ if (attr == 0x21b) {
+ sound_effect_1 = 17;
+ HandlePegPuzzles(pos);
+ yv = 0xdcb;
+ goto memoize_getout;
+ } else { // else_3
+ Overworld_PickHammerSfx(attr);
+ return attr;
+ }
+ }
+
+ return 0;
+}
+
+void Overworld_PickHammerSfx(uint16 a) { // 9bbf1e
+ uint16 attr = kMap8DataToTileAttr[GetMap16toMap8Table()[a * 4] & 0x1ff];
+ uint8 y;
+ if (attr < 0x50) {
+ return;
+ } else if (attr < 0x52) {
+ y = 26;
+ } else if (attr < 0x54) {
+ y = 17;
+ } else if (attr < 0x58) {
+ y = 5;
+ } else {
+ return;
+ }
+ sound_effect_1 = y;
+}
+
+uint16 Overworld_GetLinkMap16Coords(Point16U *xy) { // 9bbf64
+ uint16 x = (link_x_coord + kGetBestActionToPerformOnTile_x[link_direction_facing >> 1]) & ~0xf;
+ uint16 y = (link_y_coord + kGetBestActionToPerformOnTile_y[link_direction_facing >> 1]) & ~0xf;
+ xy->x = x;
+ xy->y = y;
+ uint16 rv = ((y - overworld_offset_base_y) & overworld_offset_mask_y) << 3;
+ return rv + (((x >> 3) - overworld_offset_base_x) & overworld_offset_mask_x);
+}
+
+uint8 Overworld_HandleLiftableTiles(Point16U *pt_arg) { // 9bbf9d
+ uint16 pos = Overworld_GetLinkMap16Coords(pt_arg);
+ Point16U pt = *pt_arg;
+ uint16 a = overworld_tileattr[pos >> 1], y;
+ if ((y = 0, a == 0x36d) || (y = 1, a == 0x36e) || (y = 2, a == 0x374) || (y = 3, a == 0x375) ||
+ (y = 0, a == 0x23b) || (y = 1, a == 0x23c) || (y = 2, a == 0x23d) || (y = 3, a == 0x23e)) {
+ return SmashRockPile_fromLift(a, pos, y, pt);
+ } else if ((y = 0xdc7, a == 0x36) || (y = 0xdc8, a == 0x72a) || (y = 0xdca, a == 0x20f) || (y = 0xdca, a == 0x239) || (y = 0xdc6, a == 0x101)) {
+ return Overworld_LiftingSmallObj(a, pos, y, pt);
+ } else {
+ uint16 t = a * 4 + (pt.x & 8 ? 2 : 0) + (pt.y & 8 ? 1 : 0);
+ return kMap8DataToTileAttr[GetMap16toMap8Table()[t] & 0x1ff];
+ }
+}
+
+uint8 Overworld_LiftingSmallObj(uint16 a, uint16 pos, uint16 y, Point16U pt) { // 9bc008
+ uint16 secret = Overworld_RevealSecret(pos);
+ if (secret != 0)
+ y = secret;
+ overworld_tileattr[pos >> 1] = y;
+ Overworld_Memorize_Map16_Change(pos, y);
+ Overworld_DrawMap16(pos, y);
+ nmi_load_bg_from_vram = 1;
+ uint16 t = a * 4 + (pt.x & 8 ? 2 : 0) + (pt.y & 8 ? 1 : 0);
+ return kMap8DataToTileAttr[GetMap16toMap8Table()[t] & 0x1ff];
+}
+
+int Overworld_SmashRockPile(bool down_one_tile, Point16U *pt) { // 9bc055
+ uint16 bak = link_y_coord;
+ link_y_coord += down_one_tile ? 8 : 0;
+ uint16 pos = Overworld_GetLinkMap16Coords(pt);
+ link_y_coord = bak;
+ uint16 a = dung_bg2[pos >> 1];
+ uint8 y = 0;
+ if ((y = 0, a == 0x226) || (y = 1, a == 0x227) || (y = 2, a == 0x228) || (y = 3, a == 0x229)) {
+ return SmashRockPile_fromLift(a, pos, y, *pt);
+ } else if (a == 0x36) {
+ return Overworld_LiftingSmallObj(a, pos, 0xDC7, *pt);
+ } else {
+ return -1;
+ }
+}
+
+uint8 SmashRockPile_fromLift(uint16 a, uint16 pos, uint16 y, Point16U pt) { // 9bc09f
+ static const int8 kBigRockTab1[] = { 0, -1, -64, -65 };
+ static const int8 kBigRockTabY[] = { 0, 0, -64, -64 };
+ static const int8 kBigRockTabX[] = { 0, -1, 0, -1 };
+ pos = 2 * ((pos >> 1) + kBigRockTab1[y]);
+ big_rock_starting_address = pos;
+ door_open_closed_counter = 40;
+
+ *(uint16 *)&g_ram[0] = pt.y;
+ *(uint16 *)&g_ram[2] = pt.x;
+
+ uint16 secret = Overworld_RevealSecret(pos);
+ pt.y = *(uint16 *)&g_ram[0];
+ pt.x = *(uint16 *)&g_ram[2];
+
+ if (secret == 0xffff) {
+ save_ow_event_info[overworld_screen_index] |= 0x20;
+ sound_effect_2 = 27;
+ door_open_closed_counter = 80;
+ }
+ pt.x += kBigRockTabX[y] * 2;
+ pt.y += kBigRockTabY[y] * 2;
+
+ Overworld_DoMapUpdate32x32_B(); // WARNING: The original destroys ram[0] and ram[2]
+
+ uint16 t = a * 4 + (pt.x & 8 ? 2 : 0) + (pt.y & 8 ? 1 : 0);
+ return kMap8DataToTileAttr[GetMap16toMap8Table()[t] & 0x1ff];
+}
+
+void Overworld_BombTiles32x32(uint16 x, uint16 y) { // 9bc0f8
+ x = (x - 23) & ~7;
+ y = (y - 20) & ~7;
+
+ for (int yy = 3; yy != 0; yy--, y += 16) {
+ for (int xx = 3, xt = x; xx != 0; xx--, xt += 16) {
+ Overworld_BombTile(xt, y);
+ }
+ }
+ word_7E0486 = x, word_7E0488 = y;
+}
+
+void Overworld_BombTile(int x, int y) { // 9bc155
+ int a, j, k;
+
+ int pos = ((y - overworld_offset_base_y & overworld_offset_mask_y) << 3) +
+ ((x >> 3) - overworld_offset_base_x & overworld_offset_mask_x);
+
+ if (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;
+}
+
--- a/overworld.cpp
+++ /dev/null
@@ -1,4082 +1,0 @@
-#include "overworld.h"
-#include "hud.h"
-#include "load_gfx.h"
-#include "dungeon.h"
-#include "tagalong.h"
-#include "sprite.h"
-#include "ancilla.h"
-#include "player.h"
-#include "misc.h"
-#include "messaging.h"
-#include "player_oam.h"
-#include "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;
-}
-
--- a/overworld.h
+++ b/overworld.h
@@ -96,7 +96,7 @@
void FluteMenu_LoadSelectedScreenPalettes();
void FindPartnerWhirlpoolExit();
void Overworld_LoadAmbientOverlay(bool load_map_data);
-void Overworld_LoadAmbientOverlay();
+void Overworld_LoadAmbientOverlayFalse();
void Overworld_LoadAndBuildScreen();
void Module08_02_LoadAndAdvance();
void Overworld_DrawQuadrantsAndOverlays();
--- /dev/null
+++ b/player.c
@@ -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;
+ }
+ static const uint8 kAbilityBitmasks[] = { 0xE0, 0x40, 4, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0 };
+attempt_action:
+ if (!(kAbilityBitmasks[action] & link_ability_flags)) {
+ bitfield_for_a_button = 0;
+ return;
+ }
+
+ tile_action_index = action;
+ Link_APress_PerformBasic(action * 2);
+ }
+
+ // actionInProgress
+ unused_2 = tile_action_index;
+ switch (tile_action_index) {
+ case 1: Link_APress_LiftCarryThrow(); break;
+ case 3: Link_APress_PullObject(); break;
+ case 6: Link_APress_StatueDrag(); break;
+ }
+}
+
+void Link_APress_PerformBasic(uint8 action_x2) { // 879c5f
+ switch (action_x2 >> 1) {
+ case 0: Link_PerformDesertPrayer(); 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);
+ }
+}
+
--- a/player.cpp
+++ /dev/null
@@ -1,6489 +1,0 @@
-#include "player.h"
-#include "zelda_rtl.h"
-#include "variables.h"
-#include "tile_detect.h"
-#include "ancilla.h"
-#include "sprite.h"
-#include "load_gfx.h"
-#include "hud.h"
-#include "overworld.h"
-#include "tagalong.h"
-#include "dungeon.h"
-#include "misc.h"
-#include "player_oam.h"
-#include "sprite_main.h"
-
-static 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_oam.c
@@ -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,
+};
+typedef struct LinkSpriteBody {
+ int8 y, x;
+ uint8 tile;
+} LinkSpriteBody;
+static const LinkSpriteBody kLinkSpriteBodys[303] = {
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 0, 0x04},
+ { 2, 0, 0x04},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 0, 0x04},
+ { 2, 0, 0x04},
+ { 0, 1, 0x44},
+ { 1, 1, 0x44},
+ { 2, 2, 0x44},
+ { 0, -1, 0x00},
+ { 1, -1, 0x00},
+ { 2, -2, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ {-1, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 1, 0, 0x00},
+ { 1, 0, 0x00},
+ { 1, 1, 0x44},
+ { 1, 1, 0x44},
+ { 1, 0, 0x44},
+ { 1, 1, 0x44},
+ { 1, -1, 0x00},
+ { 1, -1, 0x00},
+ { 1, 0, 0x00},
+ { 1, -1, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 0, 0x04},
+ { 2, 0, 0x04},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 0, 1, 0x44},
+ { 1, 1, 0x44},
+ { 2, 1, 0x44},
+ { 0, -1, 0x00},
+ { 1, -1, 0x00},
+ { 2, -1, 0x00},
+ {-1, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, -1, 0x44},
+ { 1, 1, 0x44},
+ { 1, 1, 0x44},
+ { 2, 1, 0x00},
+ { 1, -1, 0x00},
+ { 1, -1, 0x00},
+ { 0, -8, 0x00},
+ { 4, 0, 0x0f},
+ { 4, 0, 0x0f},
+ { 0, 0, 0xff},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x44},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ {-1, 0, 0x00},
+ {-1, 0, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 0, 0, 0x44},
+ { 1, 0, 0x44},
+ { 1, 0, 0x44},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 1, 0, 0x00},
+ {-1, 0, 0x00},
+ {-5, 0, 0x00},
+ { 2, 0, 0x00},
+ { 5, 0, 0x00},
+ {-1, 0, 0x44},
+ { 0, 0, 0x44},
+ { 0, 1, 0x44},
+ {-1, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, -1, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 0, 0x04},
+ { 2, 0, 0x04},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 0, 0x04},
+ { 2, 0, 0x04},
+ { 0, 1, 0x44},
+ { 1, 1, 0x44},
+ { 2, 1, 0x44},
+ { 0, -1, 0x00},
+ { 1, -1, 0x00},
+ { 2, -1, 0x00},
+ { 1, 0, 0x04},
+ { 0, 0, 0x44},
+ { 0, 0, 0x00},
+ { 0, 1, 0x44},
+ { 0, 0, 0x00},
+ { 0, 0, 0x04},
+ { 0, 0, 0x44},
+ { 0, 1, 0x40},
+ { 0, 2, 0x40},
+ { 0, -1, 0x00},
+ { 0, -2, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, 1, 0x44},
+ { 0, -1, 0x00},
+ { 1, 1, 0x00},
+ { 2, 1, 0x00},
+ { 2, 4, 0x00},
+ { 2, 1, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 1, 0, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 1, -1, 0x44},
+ { 2, -1, 0x44},
+ { 2, -4, 0x44},
+ { 2, -1, 0x44},
+ { 1, 0, 0x44},
+ { 0, 0, 0x00},
+ { 0, 0, 0x40},
+ { 0, 0, 0x04},
+ { 0, 0, 0x04},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x04},
+ { 1, 0, 0x00},
+ { 2, 0, 0x04},
+ { 5, 1, 0x40},
+ { 6, 1, 0x44},
+ { 5, -1, 0x04},
+ { 6, -1, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x04},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x44},
+ { 0, 0, 0x00},
+ {13, 3, 0x44},
+ {12, 5, 0x44},
+ {12, 5, 0x44},
+ {13, -3, 0x00},
+ {12, -5, 0x00},
+ {12, -5, 0x00},
+ { 1, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 0, 0, 0x44},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x44},
+ { 0, 0, 0x44},
+ {-1, 0, 0x04},
+ { 0, 0, 0x00},
+ {-1, 0, 0x00},
+ {-2, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ {-1, 0, 0x00},
+ {-2, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x04},
+ {-1, 0, 0x00},
+ {-2, 0, 0x00},
+ { 0, 0, 0x00},
+ {-1, 0, 0x04},
+ {-2, 0, 0x04},
+ { 0, 0, 0x04},
+ {-1, 1, 0x44},
+ {-1, 0, 0x44},
+ { 0, 1, 0x44},
+ { 0, 1, 0x44},
+ {-1, 1, 0x44},
+ {-1, 0, 0x44},
+ { 0, 0, 0x44},
+ {-1, -1, 0x00},
+ {-1, 0, 0x00},
+ { 0, -1, 0x00},
+ { 0, -1, 0x00},
+ {-1, -1, 0x00},
+ {-1, 0, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x04},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 0, 0x04},
+ { 2, 0, 0x04},
+ { 1, 1, 0x44},
+ { 2, 1, 0x44},
+ { 1, -1, 0x00},
+ { 2, -1, 0x00},
+ { 2, 0, 0x00},
+ { 2, 0, 0x00},
+ { 3, 0, 0x00},
+ { 3, 0, 0x00},
+ { 2, -2, 0x44},
+ { 2, 1, 0x44},
+ { 2, 2, 0x00},
+ { 2, -1, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 0, 0x04},
+ { 2, 0, 0x04},
+ { 2, 0, 0x00},
+ { 3, 0, 0x00},
+ { 4, 0, 0x00},
+ { 3, 0, 0x04},
+ { 4, 0, 0x04},
+ { 0, 0, 0x44},
+ { 1, 0, 0x44},
+ { 2, 0, 0x44},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 3, 0, 0x00},
+ { 2, 0, 0x00},
+ {-1, 0, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ {-1, 0, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ {-1, 0, 0x44},
+ { 0, 0, 0x44},
+ { 1, 0, 0x44},
+ {-1, 0, 0x44},
+ { 0, 0, 0x44},
+ { 1, 0, 0x44},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 0, 0x00},
+ { 2, 0, 0x00},
+ { 0, 0, 0x00},
+ { 3, 0, 0x00},
+ { 4, 0, 0x00},
+ { 2, 0, 0x00},
+ { 0, -1, 0x44},
+ { 1, 1, 0x44},
+ { 0, 1, 0x44},
+ { 0, 1, 0x00},
+ { 1, 1, 0x00},
+ { 0, -1, 0x00},
+ { 3, 0, 0x00},
+ { 2, 0, 0x04},
+ { 3, 0, 0x04},
+ { 0, 2, 0x00},
+ { 8, 8, 0x00},
+ { 0, 0, 0x00},
+ { 0, 0, 0x00},
+ {-1, 0, 0x0f},
+ { 1, 0, 0x00},
+ { 0, 0, 0x04},
+ { 0, 0, 0x00},
+ { 2, 0, 0x00},
+ { 1, 4, 0x44},
+ { 1, -4, 0x00},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 1, 0, 0x04},
+ { 0, 0, 0x00},
+ { 1, 0, 0x00},
+ { 1, 0, 0x04},
+ { 0, 1, 0x44},
+ { 1, 1, 0x44},
+ { 0, -1, 0x00},
+ { 1, -1, 0x00},
+ { 0, 0, 0x44},
+ {-2, 0, 0x00},
+ { 0, -2, 0x04},
+ { 0, 0, 0x00},
+ { 0, 1, 0x00},
+ { 0, 0, 0x04},
+ {12, 0, 0x08},
+ {14, 0, 0x80},
+ {12, 0, 0x00},
+ {11, 0, 0x00},
+};
+static const uint8 kSwordStuff_oam_index_ptrs_1[12] = {0, 0, 24, 32, 24, 0, 0, 24, 24, 24, 32, 0};
+static const uint8 kSwordStuff_oam_index_ptrs_0[12] = {8, 16, 16, 24, 16, 0, 0, 16, 24, 16, 24, 16};
+static const int8 kPlayerOam_DrawOam_Throwing_State[16] = {-1, -1, -1, -1, 0, -1, -1, -1, 0, 0, -1, -1, 0, 0, 0, -1};
+static const int8 kPlayerOam_DrawOam_Throwing_X[16] = {-1, -1, -1, -1, 8, -1, -1, -1, 8, 5, -1, -1, 8, 5, 2, -1};
+static const int8 kPlayerOam_DrawOam_Throwing_Y[16] = {-1, -1, -1, -1, 14, -1, -1, -1, 14, 22, -1, -1, 14, 22, 30, -1};
+static const uint8 kShieldTypeToOffs[4] = {4, 4, 8, 8};
+static const int8 kOffsToShadowGivenDir_X[12] = {0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int8 kOffsToShadowGivenDir_Y[12] = {16, 16, 17, 17, 16, 16, 16, 16, 18, 18, 18, 18};
+static const uint8 kShadow_oam_indexes_1[12] = {12, 12, 0, 0, 0, 12, 12, 0, 0, 0, 0, 12};
+static const uint8 kShadow_oam_indexes_0[12] = {40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40};
+static const uint16 kLinkShadows_Chardata[22] = {0x286c, 0x686c, 0x2828, 0x6828, 0x2838, 0xffff, 0x286e, 0x686e, 0x287e, 0x687e, 0x24d8, 0x64d8, 0x24d9, 0x64d9, 0x24da, 0x64da, 0x22c8, 0x62c8, 0x22c9, 0x62c9, 0x22ca, 0x62ca};
+static const uint8 kPlayerOam_DrawOam_2X[3] = {0, 0, 4};
+bool PlayerOam_WantInvokeSword() {
+ if (link_player_handler_state != kPlayerState_Ether &&
+ link_player_handler_state != kPlayerState_Bombos &&
+ link_player_handler_state != kPlayerState_Quake &&
+ link_player_handler_state != kPlayerState_SpinAttacking &&
+ link_player_handler_state != kPlayerState_SpinAttackMotion &&
+ !link_state_bits && !link_force_hold_sword_up && !link_electrocute_on_touch) {
+ if (link_item_in_hand & 0x40)
+ return false;
+ if (link_position_mode & 0x3d || link_item_in_hand & 0x93)
+ return true;
+ if (!(button_mask_b_y & 0x80))
+ return false;
+ }
+ return ((link_sword_type + 1) & 0xfe) != 0;
+}
+
+void CalculateSwordHitBox() { // 879e63
+ if (link_sword_type == 0 || link_sword_type == 0xff)
+ return;
+ if (link_sword_type >= 2 && button_b_frames < 9) {
+ int i = button_b_frames + ((link_direction_facing>>1) * 9);
+ if ((uint8)kSwordTipSomething[i] != 0xff) {
+ player_oam_y_offset = kSwordOamYOffs_Good[i];
+ player_oam_x_offset = kSwordOamXOffs_Good[i];
+ return;
+ }
+ }
+ uint8 offs = button_b_frames;
+ if (offs == 9)
+ return;
+ uint8 y = 39;
+ if (offs >= 10) {
+ offs -= 10;
+ y = 3;
+ }
+ int i = kPlayerOamOtherOffs[(link_direction_facing >> 1) * 40 + y] + offs;
+ player_oam_y_offset = kSwordOamYOffs[i];
+ player_oam_x_offset = kSwordOamXOffs[i];
+}
+
+void LinkOam_Main() { // 8da18e
+ uint16 y_coord_backup = link_y_coord;
+
+ if (submodule_index == 18 || submodule_index == 19) {
+ int t = submodule_index == 18 ? 0 : 12;
+ t += which_staircase_index & 4 ? 6 : 0;
+ t += (link_animation_steps < 6) ? link_animation_steps : 0;
+ link_y_coord += kPlayerOam_StairsOffsY[t];
+ }
+
+ uint8 xcoord = link_x_coord - BG2HOFS_copy2;
+ uint8 ycoord = link_y_coord - BG2VOFS_copy2;
+ player_oam_x_offset = player_oam_y_offset = 0x80;
+ uint8 scratch_0_var = (draw_water_ripples_or_grass != 0);
+ oam_priority_value = kPlayerOam_FloorOamPrio[link_is_on_lower_level];
+ sort_sprites_offset_into_oam_buffer = kPlayerOam_SortSpritesOffs[(uint8)sort_sprites_setting];
+
+ uint8 yt, rt;
+
+ if (link_player_handler_state == kPlayerState_AsleepInBed && link_pose_during_opening != 2) {
+ yt = 0x1f, rt = link_pose_during_opening;
+ goto continue_after_set;
+ }
+ if (link_force_hold_sword_up) {
+ yt = 0x24, rt = 0;
+ link_direction_facing_mirror = link_direction_facing;
+ goto continue_after_set;
+ }
+ if (link_is_bunny_mirror) {
+ yt = 0x21, rt = link_animation_steps & 3;
+ link_direction_facing_mirror = link_direction_facing;
+ goto continue_after_set;
+ }
+ yt = draw_water_ripples_or_grass ? 10 : 0;
+
+ if (submodule_index == 14 && main_module_index != 18 && ((yt = 10), link_actual_vel_x)) {
+ if (link_direction_facing != 4 && link_direction_facing != 6) {
+ rt = kPlayerOam_Tab1[link_animation_steps];
+ yt = which_staircase_index & 4 ? 0x1a : 0x19;
+ } else {
+ rt = link_animation_steps;
+ }
+ } else {
+ if (link_grabbing_wall & 3) {
+ yt = 0x18, rt = some_animation_timer_steps;
+ } else {
+ if (bitmask_of_dragstate & 0xd) {
+ yt = 0x16;
+ if (link_animation_steps >= 5)
+ link_animation_steps = 0;
+ }
+ rt = link_animation_steps;
+ }
+ }
+ link_direction_facing_mirror = link_direction_facing;
+ if (link_is_in_deep_water)
+ oam_priority_value = 0x2000;
+
+ if (link_player_handler_state == kPlayerState_Swimming) {
+ yt = 0x11, rt &= 1;
+ if (submodule_index == 0 && (joypad1H_last & 0xf) != 0 || (swimcoll_var7[0] | swimcoll_var7[1]))
+ yt = 0x13, rt = byte_7E02CC;
+ if (link_maybe_swim_faster)
+ yt = 0x12, rt = link_maybe_swim_faster - 1;
+ goto continue_after_set;
+ }
+ if (link_pose_for_item) {
+ rt = 0, yt = (link_pose_for_item != 2) ? 0x1d : 0x1e;
+ goto continue_after_set;
+ }
+ if (player_unk1 & 1) {
+ yt = 0x1b, rt = some_animation_timer_steps;
+ goto continue_after_set;
+ }
+
+ if (link_auxiliary_state != 0) {
+ if (link_auxiliary_state == 4) {
+ yt = 0x13, rt = kSwimmingTab1[(frame_counter & 0x18) >> 3];
+ goto continue_after_set;
+ } else if (link_auxiliary_state == 1) {
+ if (link_player_handler_state == kPlayerState_TurtleRock) {
+ if (!byte_7E034E)
+ oam_priority_value = 0x3000;
+ goto link_state_is_empty;
+ } else if (link_player_handler_state != kPlayerState_Hookshot && !link_cape_mode) {
+ if (link_electrocute_on_touch)
+ yt = 0x14, rt = player_handler_timer & 3;
+ else
+ yt = 5, rt = 0;
+ goto continue_after_set;
+ }
+ }
+ }
+
+ if (player_near_pit_state != 0 && player_near_pit_state != 1) {
+ if (player_near_pit_state == 3)
+ sort_sprites_offset_into_oam_buffer = 0;
+ yt = 4, rt = link_this_controls_sprite_oam;
+ if (rt >= 6)
+ oam_priority_value |= 0x3000;
+ goto continue_after_set;
+ }
+
+ if (link_state_bits != 0) {
+ uint8 bit = FindMostSignificantBit(link_state_bits);
+ if (bit < 6)
+ link_direction_facing_mirror = 2;
+ yt = kPlayerOam_Tab4[bit];
+ if (yt >= 0xd) {
+ if (link_picking_throw_state & 2)
+ yt += 1;
+
+ if (link_picking_throw_state & 1)
+ yt = 0x10;
+ else if (link_state_bits & 0x80)
+ goto continue_after_set;
+ }
+ rt = some_animation_timer_steps;
+ goto continue_after_set;
+ }
+link_state_is_empty:
+ if (link_unk_master_sword != 0) {
+ yt = 0x17, rt = link_unk_master_sword - 1;
+ goto continue_after_set;
+ }
+
+ if (link_item_in_hand != 0) {
+ yt = kPlayerOam_Tab2[FindMostSignificantBit(link_item_in_hand)];
+ rt = player_handler_timer;
+ goto continue_after_set;
+ } else if (link_position_mode != 0) {
+ yt = kPlayerOam_Tab3[FindMostSignificantBit(link_position_mode)];
+ rt = player_handler_timer;
+ goto continue_after_set;
+ }
+
+ if (link_player_handler_state == kPlayerState_Quake || link_player_handler_state == kPlayerState_Ether || link_player_handler_state == kPlayerState_Bombos) {
+ yt = 0x15, rt = state_for_spin_attack;
+ goto continue_after_set;
+ } else if (link_player_handler_state == kPlayerState_SpinAttackMotion || link_player_handler_state == kPlayerState_SpinAttacking) {
+ yt = 0xf, rt = state_for_spin_attack;
+ goto continue_after_set;
+ }
+
+ if (button_mask_b_y & 0x80) {
+ if (button_b_frames == 9) {
+ yt = 2;
+ } else {
+ yt = 0x27, rt = button_b_frames;
+ if (rt >= 9) {
+ yt = 3;
+ rt -= 10;
+ }
+ }
+ }
+continue_after_set:
+ value_computed_for_player_oam = yt;
+ if (yt != 5)
+ oam_priority_value_2 = oam_priority_value;
+
+ BYTE(index_of_interacting_tile) = rt;
+
+ int dir = link_direction_facing >> 1;
+ int 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;
+}
+
--- a/player_oam.cpp
+++ /dev/null
@@ -1,1278 +1,0 @@
-#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;
-}
-
--- a/player_oam.h
+++ b/player_oam.h
@@ -1,10 +1,10 @@
#pragma once
#include "types.h"
-struct SwordResult {
+typedef struct SwordResult {
uint8 r6;
uint8 r12;
-};
+} SwordResult;
bool PlayerOam_WantInvokeSword();
void CalculateSwordHitBox();
--- /dev/null
+++ b/poly.c
@@ -1,0 +1,323 @@
+#include "poly.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+
+static const int8 kPolySinCos[320] = {
+ 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23,
+ 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
+ 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60,
+ 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46,
+ 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26,
+ 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2,
+ 0, -2, -3, -5, -6, -8, -9, -11, -12, -14, -16, -17, -19, -20, -22, -23,
+ -24, -26, -27, -29, -30, -32, -33, -34, -36, -37, -38, -39, -41, -42, -43, -44,
+ -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -56, -57, -58, -59,
+ -59, -60, -60, -61, -61, -62, -62, -62, -63, -63, -63, -64, -64, -64, -64, -64,
+ -64, -64, -64, -64, -64, -64, -63, -63, -63, -62, -62, -62, -61, -61, -60, -60,
+ -59, -59, -58, -57, -56, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46,
+ -45, -44, -43, -42, -41, -39, -38, -37, -36, -34, -33, -32, -30, -29, -27, -26,
+ -24, -23, -22, -20, -19, -17, -16, -14, -12, -11, -9, -8, -6, -5, -3, -2,
+ 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23,
+ 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
+ 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
+};
+typedef struct Vertex3 {
+ int8 x, y, z;
+} Vertex3;
+static const Vertex3 kPoly0_Vtx[6] = {
+ { 0, 65, 0},
+ { 0, -65, 0},
+ { 0, 0, -40},
+ {-40, 0, 0},
+ { 0, 0, 40},
+ { 40, 0, 0},
+};
+static const uint8 kPoly0_Polys[40] = {
+ 3, 0, 5, 2, 4,
+ 3, 0, 2, 3, 1,
+ 3, 0, 3, 4, 2,
+ 3, 0, 4, 5, 3,
+ 3, 1, 2, 5, 4,
+ 3, 1, 3, 2, 1,
+ 3, 1, 4, 3, 2,
+ 3, 1, 5, 4, 3,
+};
+static const Vertex3 kPoly1_Vtx[6] = {
+ { 0, 40, 10},
+ { 40, -40, 10},
+ {-40, -40, 10},
+ { 0, 40, -10},
+ {-40, -40, -10},
+ { 40, -40, -10},
+};
+static const uint8 kPoly1_Polys[28] = {
+ 3, 0, 1, 2, 7,
+ 3, 3, 4, 5, 6,
+ 4, 0, 3, 5, 1, 5,
+ 4, 1, 5, 4, 2, 4,
+ 4, 3, 0, 2, 4, 3,
+};
+typedef struct PolyConfig {
+ uint8 num_vtx, num_poly;
+ uint16 vtx_val, polys_val;
+ const Vertex3 *vertex;
+ const uint8 *poly;
+} PolyConfig;
+static const PolyConfig kPolyConfigs[2] = {
+ {6, 8, 0xff98, 0xffaa, kPoly0_Vtx, kPoly0_Polys},
+ {6, 5, 0xffd2, 0xffe4, kPoly1_Vtx, kPoly1_Polys},
+};
+static const uint32 kPoly_RasterColors[16] = {
+ 0x00, 0xff, 0xff00, 0xffff,
+ 0xff0000, 0xff00ff, 0xffff00, 0xffffff,
+ 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
+ 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff,
+};
+static const uint16 kPoly_LeftSideMask[8] = {0xffff, 0x7f7f, 0x3f3f, 0x1f1f, 0xf0f, 0x707, 0x303, 0x101};
+static const uint16 kPoly_RightSideMask[8] = {0x8080, 0xc0c0, 0xe0e0, 0xf0f0, 0xf8f8, 0xfcfc, 0xfefe, 0xffff};
+uint16 Poly_Divide(uint16 a, uint16 b) {
+ poly_tmp1 = sign16(a) ? -a : a;
+ poly_tmp0 = b;
+ while (poly_tmp0 >= 256)
+ poly_tmp0 >>= 1, poly_tmp1 >>= 1;
+ int q = poly_tmp1 / poly_tmp0;
+ return sign16(a) ? -q : q;
+}
+
+void Poly_RunFrame() {
+ Polyhedral_EmptyBitMapBuffer();
+ Polyhedral_SetShapePointer();
+ Polyhedral_SetRotationMatrix();
+ Polyhedral_OperateRotation();
+ Polyhedral_DrawPolyhedron();
+}
+
+void Polyhedral_SetShapePointer() { // 89f83d
+ poly_var1 = poly_config1 * 2 + 0x80;
+ poly_tmp0 = poly_which_model * 2;
+
+ const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
+ poly_config_num_vertex = poly_config->num_vtx;
+ poly_config_num_polys = poly_config->num_poly;
+ poly_fromlut_ptr2 = poly_config->vtx_val;
+ poly_fromlut_ptr4 = poly_config->polys_val;
+}
+
+void Polyhedral_SetRotationMatrix() { // 89f864
+ poly_sin_a = kPolySinCos[poly_a];
+ poly_cos_a = kPolySinCos[poly_a + 64];
+ poly_sin_b = kPolySinCos[poly_b];
+ poly_cos_b = kPolySinCos[poly_b + 64];
+ poly_e0 = (int16)poly_sin_b * (int8)poly_sin_a >> 8 << 2;
+ poly_e1 = (int16)poly_cos_b * (int8)poly_cos_a >> 8 << 2;
+ poly_e2 = (int16)poly_cos_b * (int8)poly_sin_a >> 8 << 2;
+ poly_e3 = (int16)poly_sin_b * (int8)poly_cos_a >> 8 << 2;
+}
+
+void Polyhedral_OperateRotation() { // 89f8fb
+ const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
+ const int8 *src = &poly_config->vertex[0].x;
+ int i = poly_config_num_vertex;
+ src += i * 3;
+ do {
+ src -= 3, i -= 1;
+ poly_fromlut_x = src[2];
+ poly_fromlut_y = src[1];
+ poly_fromlut_z = src[0];
+ Polyhedral_RotatePoint();
+ Polyhedral_ProjectPoint();
+ poly_arr_x[i] = poly_base_x + poly_f0;
+ poly_arr_y[i] = poly_base_y - poly_f1;
+ } while (i);
+}
+
+void Polyhedral_RotatePoint() { // 89f931
+ int x = (int8)poly_fromlut_x;
+ int y = (int8)poly_fromlut_y;
+ int z = (int8)poly_fromlut_z;
+
+ poly_f0 = (int16)poly_cos_b * z - (int16)poly_sin_b * x;
+ poly_f1 = (int16)poly_e0 * z + (int16)poly_cos_a * y + (int16)poly_e2 * x;
+ poly_f2 = ((int16)poly_e3 * z >> 8) - ((int16)poly_sin_a * y >> 8) + ((int16)poly_e1 * x >> 8) + poly_var1;
+}
+
+void Polyhedral_ProjectPoint() { // 89f9d6
+ poly_f0 = Poly_Divide(poly_f0, poly_f2);
+ poly_f1 = Poly_Divide(poly_f1, poly_f2);
+}
+
+void Polyhedral_DrawPolyhedron() { // 89fa4f
+ const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
+ const uint8 *src = poly_config->poly;
+ do {
+ poly_num_vertex_in_poly = *src++;
+ BYTE(poly_tmp0) = poly_num_vertex_in_poly;
+ poly_xy_coords[0] = poly_num_vertex_in_poly * 2;
+
+ int i = 1;
+ do {
+ int j = *src++;
+ poly_xy_coords[i + 0] = poly_arr_x[j];
+ poly_xy_coords[i + 1] = poly_arr_y[j];
+ i += 2;
+ } while (--BYTE(poly_tmp0));
+
+ poly_raster_color_config = *src++;
+ int order = Polyhedral_CalculateCrossProduct();
+ if (order > 0) {
+ Polyhedral_SetForegroundColor();
+ Polyhedral_DrawFace();
+ }
+ } while (--poly_config_num_polys);
+}
+
+void Polyhedral_SetForegroundColor() { // 89faca
+ uint8 t = poly_which_model ? (poly_config1 >> 5) : 0;
+ uint8 a = (poly_tmp0 << (t + 1)) >> 8;
+ Polyhedral_SetColorMask(a <= 1 ? 1 : a >= 7 ? 7 : a);
+}
+
+int16 Polyhedral_CalculateCrossProduct() { // 89fb24
+ int16 a = poly_xy_coords[3] - poly_xy_coords[1];
+ poly_tmp0 = a * (int8)(poly_xy_coords[6] - poly_xy_coords[4]);
+ a = poly_xy_coords[5] - poly_xy_coords[3];
+ poly_tmp0 -= a * (int8)(poly_xy_coords[4] - poly_xy_coords[2]);
+ return poly_tmp0;
+}
+
+void Polyhedral_SetColorMask(int c) { // 89fcae
+ uint32 v = kPoly_RasterColors[c];
+ poly_raster_color0 = v;
+ poly_raster_color1 = v >> 16;
+}
+
+void Polyhedral_EmptyBitMapBuffer() { // 89fd04
+ memset(polyhedral_buffer, 0, 0x800);
+}
+
+void Polyhedral_DrawFace() { // 89fd1e
+ int n = poly_xy_coords[0];
+ uint8 min_y = poly_xy_coords[n];
+ int min_idx = n;
+ while (n -= 2) {
+ if (poly_xy_coords[n] < min_y)
+ min_y = poly_xy_coords[n], min_idx = n;
+ }
+ poly_raster_dst_ptr = 0xe800 + (((min_y & 0x38) ^ (min_y & 0x20 ? 0x24 : 0)) << 6) + (min_y & 7) * 2;
+ poly_cur_vertex_idx0 = poly_cur_vertex_idx1 = min_idx;
+ poly_total_num_steps = poly_xy_coords[0] >> 1;
+ poly_y0_cur = poly_y1_cur = poly_xy_coords[min_idx];
+ poly_x0_cur = poly_x1_cur = poly_xy_coords[min_idx - 1];
+ if (Polyhedral_SetLeft() || Polyhedral_SetRight())
+ return;
+ for (;;) {
+ Polyhedral_FillLine();
+ if (BYTE(poly_raster_dst_ptr) != 0xe) {
+ poly_raster_dst_ptr += 2;
+ } else {
+ uint8 a = HIBYTE(poly_raster_dst_ptr) + 2;
+ poly_raster_dst_ptr = (a ^ ((a & 8) ? 0 : 0x19)) << 8;
+ }
+ if (poly_y0_cur == poly_y0_trig) {
+ poly_x0_cur = poly_x0_target;
+ if (Polyhedral_SetLeft())
+ return;
+ }
+ poly_y0_cur++;
+ if (poly_y1_cur == poly_y1_trig) {
+ poly_x1_cur = poly_x1_target;
+ if (Polyhedral_SetRight())
+ return;
+ }
+ poly_y1_cur++;
+ poly_x0_frac += poly_x0_step;
+ poly_x1_frac += poly_x1_step;
+ }
+}
+
+void Polyhedral_FillLine() { // 89fdcf
+ uint16 left = kPoly_LeftSideMask[(poly_x0_frac >> 8) & 7];
+ uint16 right = kPoly_RightSideMask[(poly_x1_frac >> 8) & 7];
+ poly_tmp2 = (poly_x0_frac >> 8) & 0x38;
+ int d0 = ((poly_x1_frac >> 8) & 0x38);
+ uint16 *ptr = (uint16*)&g_ram[poly_raster_dst_ptr + d0 * 4];
+ if ((d0 -= poly_tmp2) == 0) {
+ poly_tmp1 = left & right;
+ ptr[0] ^= (ptr[0] ^ poly_raster_color0) & poly_tmp1;
+ ptr[8] ^= (ptr[8] ^ poly_raster_color1) & poly_tmp1;
+ return;
+ }
+ if (d0 < 0)
+ return;
+ int n = d0 >> 3;
+ ptr[0] ^= (ptr[0] ^ poly_raster_color0) & right;
+ ptr[8] ^= (ptr[8] ^ poly_raster_color1) & right;
+ ptr -= 0x10;
+ while (--n) {
+ ptr[0] = poly_raster_color0;
+ ptr[8] = poly_raster_color1;
+ ptr -= 0x10;
+ }
+ ptr[0] ^= (ptr[0] ^ poly_raster_color0) & left;
+ ptr[8] ^= (ptr[8] ^ poly_raster_color1) & left;
+ poly_tmp1 = left, poly_raster_numfull = 0;
+}
+
+bool Polyhedral_SetLeft() { // 89feb4
+ int i;
+ for (;;) {
+ if (sign8(--poly_total_num_steps))
+ return true;
+ i = poly_cur_vertex_idx0 - 2;
+ if (i == 0)
+ i = poly_xy_coords[0];
+ if (poly_xy_coords[i] < poly_y0_cur)
+ return true;
+ if (poly_xy_coords[i] != poly_y0_cur)
+ break;
+ poly_x0_cur = poly_xy_coords[i - 1];
+ poly_cur_vertex_idx0 = i;
+ }
+ poly_y0_trig = poly_xy_coords[i];
+ poly_x0_target = poly_xy_coords[i - 1];
+ poly_cur_vertex_idx0 = i;
+ int t = poly_x0_target - poly_x0_cur, u = t;
+ if (t < 0)
+ t = -t;
+ t = ((t & 0xff) << 8) / (uint8)(poly_y0_trig - poly_y0_cur);
+ poly_x0_frac = (poly_x0_cur << 8) | 0x80;
+ poly_x0_step = (u < 0) ? -t : t;
+ return false;
+}
+
+bool Polyhedral_SetRight() { // 89ff1e
+ int i;
+ for (;;) {
+ if (sign8(--poly_total_num_steps))
+ return true;
+ i = poly_cur_vertex_idx1;
+ if (i == poly_xy_coords[0])
+ i = 0;
+ i += 2;
+ if (poly_xy_coords[i] < poly_y1_cur)
+ return true;
+ if (poly_xy_coords[i] != poly_y1_cur)
+ break;
+ poly_x1_cur = poly_xy_coords[i - 1];
+ poly_cur_vertex_idx1 = i;
+ }
+ poly_y1_trig = poly_xy_coords[i];
+ poly_x1_target = poly_xy_coords[i - 1];
+ poly_cur_vertex_idx1 = i;
+ int t = poly_x1_target - poly_x1_cur, u = t;
+ if (t < 0)
+ t = -t;
+ t = ((t & 0xff) << 8) / (uint8)(poly_y1_trig - poly_y1_cur);
+ poly_x1_frac = (poly_x1_cur << 8) | 0x80;
+ poly_x1_step = (u < 0) ? -t : t;
+ return false;
+}
+
--- a/poly.cpp
+++ /dev/null
@@ -1,323 +1,0 @@
-#include "poly.h"
-#include "zelda_rtl.h"
-#include "variables.h"
-
-static const int8 kPolySinCos[320] = {
- 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23,
- 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
- 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60,
- 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46,
- 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26,
- 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2,
- 0, -2, -3, -5, -6, -8, -9, -11, -12, -14, -16, -17, -19, -20, -22, -23,
- -24, -26, -27, -29, -30, -32, -33, -34, -36, -37, -38, -39, -41, -42, -43, -44,
- -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -56, -57, -58, -59,
- -59, -60, -60, -61, -61, -62, -62, -62, -63, -63, -63, -64, -64, -64, -64, -64,
- -64, -64, -64, -64, -64, -64, -63, -63, -63, -62, -62, -62, -61, -61, -60, -60,
- -59, -59, -58, -57, -56, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46,
- -45, -44, -43, -42, -41, -39, -38, -37, -36, -34, -33, -32, -30, -29, -27, -26,
- -24, -23, -22, -20, -19, -17, -16, -14, -12, -11, -9, -8, -6, -5, -3, -2,
- 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23,
- 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
- 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
-};
-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/select_file.c
@@ -1,0 +1,974 @@
+#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);
+ ZeldaWriteSram();
+ }
+ ReturnToFileSelect();
+ subsubmodule_index = 0;
+ }
+}
+
+void Module_NamePlayer_1() {
+ uint16 *dst = SelectFile_Func1();
+ dst[0] = 0xffff;
+ nmi_load_bg_from_vram = 1;
+ submodule_index++;
+}
+
+void Module_NamePlayer_2() {
+ nmi_load_bg_from_vram = 5;
+ submodule_index++;
+ INIDISP_copy = 15;
+ nmi_disable_core_updates = 0;
+}
+
+void Intro_FixCksum(uint8 *s) {
+ uint16 *src = (uint16 *)s;
+ uint16 sum = 0;
+ for (int i = 0; i < 0x27f; i++)
+ sum += src[i];
+ src[0x27f] = 0x5a5a - sum;
+}
+
+void LoadFileSelectGraphics() { // 80e4e9
+ 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};
+
+ const uint8 *cart = g_zenv.sram;
+
+ if (selectfile_R16 < 3)
+ selectfile_var2 = selectfile_R16;
+
+ for (int k = 0; k < 3; k++) {
+ if (*(uint16 *)(cart + k * 0x500 + 0x3E5) == 0x55AA) {
+ selectfile_arr1[k] = 1;
+ SelectFile_Func5_DrawOams(k);
+ SelectFile_Func6_DrawOams2(k);
+ SelectFile_Func17(k);
+ }
+ }
+
+ FileSelect_DrawFairy(0x1c, kSelectFile_Faerie_Y[selectfile_R16]);
+ nmi_load_bg_from_vram = 1;
+
+ uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
+ if (a & 0x2c) {
+ if (a & 8) {
+ sound_effect_2 = 0x20;
+ if (sign8(--selectfile_R16))
+ selectfile_R16 = 4;
+ } else {
+ sound_effect_2 = 0x20;
+ if (++selectfile_R16 == 5)
+ selectfile_R16 = 0;
+ }
+ } else if (a != 0) {
+ sound_effect_1 = 0x2c;
+ if (selectfile_R16 < 3) {
+ selectfile_R17 = 0;
+ if (!selectfile_arr1[selectfile_R16]) {
+ main_module_index = 4;
+ submodule_index = 0;
+ subsubmodule_index = 0;
+ } else {
+ music_control = 0xf1;
+ srm_var1 = selectfile_R16 * 2 + 2;
+ WORD(g_ram[0]) = selectfile_R16 * 0x500;
+ CopySaveToWRAM();
+ }
+ } else if (selectfile_arr1[0] | selectfile_arr1[1] | selectfile_arr1[2]) {
+ main_module_index = (selectfile_R16 == 3) ? 2 : 3;
+ selectfile_R16 = 0;
+ submodule_index = 0;
+ subsubmodule_index = 0;
+ } else {
+ sound_effect_1 = 0x3c;
+ }
+ }
+}
+
+void Module02_CopyFile() { // 8cd053
+ selectfile_var2 = 0;
+ switch (submodule_index) {
+ case 0: FileSelect_EraseTriforce(); break;
+ case 1: Module_EraseFile_1(); break;
+ case 2: Module_CopyFile_2(); break;
+ case 3: CopyFile_ChooseSelection(); break;
+ case 4: CopyFile_ChooseTarget(); break;
+ case 5: CopyFile_ConfirmSelection(); break;
+ }
+}
+
+void Module_CopyFile_2() { // 8cd06e
+ nmi_load_bg_from_vram = 7;
+ submodule_index++;
+ INIDISP_copy = 0xf;
+ nmi_disable_core_updates = 0;
+ int i = 0;
+ for (; selectfile_arr1[i] == 0; i++) {}
+ selectfile_R16 = i;
+}
+
+void CopyFile_ChooseSelection() { // 8cd087
+ CopyFile_SelectionAndBlinker();
+ if (submodule_index == 3 && !(frame_counter & 0x30))
+ FilePicker_DeleteHeaderStripe();
+ nmi_load_bg_from_vram = 1;
+}
+
+void CopyFile_ChooseTarget() { // 8cd0a2
+ CopyFile_TargetSelectionAndBlink();
+ if (submodule_index == 4 && !(frame_counter & 0x30))
+ FilePicker_DeleteHeaderStripe();
+ nmi_load_bg_from_vram = 1;
+}
+
+void CopyFile_ConfirmSelection() { // 8cd0b9
+ CopyFile_HandleConfirmation();
+ nmi_load_bg_from_vram = 1;
+}
+
+void FilePicker_DeleteHeaderStripe() { // 8cd0c6
+ static const uint16 kFilePicker_DeleteHeaderStripe_Dst[2] = {4, 0x1e};
+ for (int j = 1; j >= 0; j--) {
+ uint16 *dst = vram_upload_data + kFilePicker_DeleteHeaderStripe_Dst[j] / 2;
+ for (int i = 0; i != 11; i++)
+ dst[i] = 0xa9;
+ }
+}
+
+void CopyFile_SelectionAndBlinker() { // 8cd13f
+ static const uint8 kCopyFile_SelectionAndBlinker_Tab[173] = {
+ 0x61, 4, 0, 0x15, 0x85, 0x18, 0x26, 0x18, 7, 0x18, 0xaf, 0x18, 2, 0x18, 7, 0x18,
+ 0x6f, 0x18, 0x86, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0x24, 0, 0x15, 0x95, 0x18,
+ 0x36, 0x18, 0x17, 0x18, 0xbf, 0x18, 0x12, 0x18, 0x17, 0x18, 0x7f, 0x18, 0x96, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0x61, 0x67, 0, 0xf, 0xe7, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0x87, 0, 0xf, 0xf7, 0x18, 0x91, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xc7, 0, 0xf,
+ 0xe8, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0x61, 0xe7, 0, 0xf, 0xf8, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x27, 0, 0xf, 0xe9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x47, 0, 0xf, 0xf9, 0x18, 0x91, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xff,
+ };
+ static const uint8 kCopyFile_SelectionAndBlinker_Tab1[73] = {
+ 0x61, 0x67, 0x40, 0xe, 0xa9, 0, 0x61, 0x87, 0x40, 0xe, 0xa9, 0, 0x61, 0xc7, 0x40, 0xe,
+ 0xa9, 0, 0x61, 0xe7, 0x40, 0xe, 0xa9, 0, 0x11, 0x30, 0, 1, 0x83, 0x35, 0x11, 0x31,
+ 0x40, 0x14, 0x85, 0x35, 0x11, 0x3c, 0, 1, 0x84, 0x35, 0x11, 0x50, 0xc0, 0xe, 0x86, 0x35,
+ 0x11, 0x5c, 0xc0, 0xe, 0x96, 0x35, 0x12, 0x50, 0, 1, 0x93, 0x35, 0x12, 0x51, 0x40, 0x14,
+ 0x95, 0x35, 0x12, 0x5c, 0, 1, 0x94, 0x35, 0xff,
+ };
+ static const uint16 kCopyFile_SelectionAndBlinker_Dst[3] = {0x3c, 0x64, 0x8c};
+ static const uint8 kCopyFile_SelectionAndBlinker_FaerieX[4] = {36, 36, 36, 28};
+ static const uint8 kCopyFile_SelectionAndBlinker_FaerieY[4] = {87, 111, 135, 191};
+
+ vram_upload_offset = 0xac;
+ memcpy(vram_upload_data, kCopyFile_SelectionAndBlinker_Tab, 173);
+
+ for (int k = 0; k != 3; k++) {
+ if (selectfile_arr1[k] & 1) {
+ const uint16 *name = (uint16 *)(g_zenv.sram + 0x500 * k + kSrmOffs_Name);
+ uint16 *dst = vram_upload_data + kCopyFile_SelectionAndBlinker_Dst[k] / 2;
+ for (int i = 0; i != 6; i++) {
+ uint16 t = *name++ + 0x1800;
+ dst[0] = t;
+ dst[10] = t + 0x10;
+ dst++;
+ }
+ }
+ }
+ FileSelect_DrawFairy(kCopyFile_SelectionAndBlinker_FaerieX[selectfile_R16], kCopyFile_SelectionAndBlinker_FaerieY[selectfile_R16]);
+
+ uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
+ if (a & 0x2c) {
+ uint8 k = selectfile_R16;
+ if (a & 8) {
+ do {
+ if (--k < 0) {
+ k = 3;
+ break;
+ }
+ } while (!selectfile_arr1[k]);
+ } else {
+ do {
+ k++;
+ if (k >= 4)
+ k = 0;
+ } while (k != 3 && !selectfile_arr1[k]);
+ }
+ selectfile_R16 = k;
+ sound_effect_2 = 0x20;
+ } else if (a != 0) {
+ sound_effect_1 = 0x2c;
+ if (selectfile_R16 == 3) {
+ ReturnToFileSelect();
+ return;
+ }
+ selectfile_R20 = selectfile_R16 * 2;
+ memcpy(vram_upload_data + 26, kCopyFile_SelectionAndBlinker_Tab1, 73);
+ if (selectfile_R16 != 2) {
+ uint16 *dst = vram_upload_data + selectfile_R16 * 6;
+ dst[26] = 0x2762;
+ dst[29] = 0x4762;
+ }
+ submodule_index++;
+ selectfile_R16 = 0;
+ }
+}
+
+void ReturnToFileSelect() { // 8cd22d
+ main_module_index = 1;
+ submodule_index = 1;
+ subsubmodule_index = 0;
+ selectfile_R16 = 0;
+}
+
+void CopyFile_TargetSelectionAndBlink() { // 8cd27b
+ {
+ int k = 1, t = 4;
+ do {
+ if (t != selectfile_R20)
+ selectfile_arr2[k--] = t;
+ } while ((t -= 2) >= 0);
+ }
+
+ static const uint8 kCopyFile_TargetSelectionAndBlink_Tab0[133] = {
+ 0x61, 0x51, 0, 0x15, 0x85, 0x18, 0x23, 0x18, 0xe, 0x18, 0xa9, 0x18, 0x26, 0x18, 7, 0x18,
+ 0xaf, 0x18, 2, 0x18, 7, 0x18, 0x6f, 0x18, 0x86, 0x18, 0x61, 0x71, 0, 0x15, 0x95, 0x18,
+ 0x33, 0x18, 0x1e, 0x18, 0xb9, 0x18, 0x36, 0x18, 0x17, 0x18, 0xbf, 0x18, 0x12, 0x18, 0x17, 0x18,
+ 0x7f, 0x18, 0x96, 0x18, 0x61, 0xb4, 0, 0xf, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xd4, 0, 0xf, 0xa9, 0x18, 0x91, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x14, 0, 0xf,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0x62, 0x34, 0, 0xf, 0xa9, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xff,
+ };
+ static const uint8 kCopyFile_TargetSelectionAndBlink_Tab2[49] = {
+ 0x61, 0xb4, 0x40, 0xe, 0xa9, 0, 0x61, 0xd4, 0x40, 0xe, 0xa9, 0, 0x62, 0xc6, 0, 0xd,
+ 2, 0x18, 0xe, 0x18, 0xf, 0x18, 0x28, 0x18, 0xa9, 0x18, 0xe, 0x18, 0xa, 0x18, 0x62, 0xe6,
+ 0, 0xd, 0x12, 0x18, 0x1e, 0x18, 0x1f, 0x18, 0x38, 0x18, 0xa9, 0x18, 0x1e, 0x18, 0x1a, 0x18,
+ 0xff,
+ };
+ static const uint8 kCopyFile_TargetSelectionAndBlink_FaerieX[3] = {0x8c, 0x8c, 0x1c};
+ static const uint8 kCopyFile_TargetSelectionAndBlink_FaerieY[3] = {0x67, 0x7f, 0xbf};
+ static const uint16 kCopyFile_TargetSelectionAndBlink_Dst[2] = {0x38, 0x60};
+ static const uint16 kCopyFile_TargetSelectionAndBlink_Tab1[3] = {0x18e7, 0x18e8, 0x18e9};
+ memcpy(vram_upload_data, kCopyFile_TargetSelectionAndBlink_Tab0, 133);
+
+ for (int k = 0, j = 0; k != 3; k++) {
+ if (k * 2 == selectfile_R20)
+ continue;
+
+ uint16 *dst = vram_upload_data + kCopyFile_TargetSelectionAndBlink_Dst[j++] / 2;
+ uint16 t = kCopyFile_TargetSelectionAndBlink_Tab1[k];
+ dst[0] = t;
+ dst[10] = t + 0x10;
+ dst += 2;
+ if (selectfile_arr1[k]) {
+ const uint16 *name = (uint16 *)(g_zenv.sram + 0x500 * k + kSrmOffs_Name);
+ for (int i = 0; i != 6; i++) {
+ uint16 t = *name++ + 0x1800;
+ dst[0] = t;
+ dst[10] = t + 0x10;
+ dst++;
+ }
+ }
+ }
+
+ vram_upload_offset = 132;
+
+ FileSelect_DrawFairy(kCopyFile_TargetSelectionAndBlink_FaerieX[selectfile_R16], kCopyFile_TargetSelectionAndBlink_FaerieY[selectfile_R16]);
+
+ uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
+ if (a & 0x2c) {
+ uint8 k = selectfile_R16;
+ if (a & 8) {
+ if (sign8(--k))
+ k = 2;
+ } else {
+ if (++k >= 3)
+ k = 0;
+ }
+ selectfile_R16 = k;
+ sound_effect_2 = 0x20;
+ } else if (a) {
+ sound_effect_1 = 0x2c;
+ if (selectfile_R16 == 2) {
+ ReturnToFileSelect();
+ selectfile_R16 = 0;
+ return;
+ }
+ selectfile_R18 = selectfile_arr2[selectfile_R16];
+ memcpy(vram_upload_data + 26, kCopyFile_TargetSelectionAndBlink_Tab2, 49);
+ if (selectfile_R16 == 0) {
+ uint16 *dst = vram_upload_data;
+ dst[26] = 0x1462;
+ dst[29] = 0x3462;
+ }
+ submodule_index++;
+ selectfile_R16 = 0;
+ }
+}
+
+void CopyFile_HandleConfirmation() { // 8cd371
+ static const uint8 kCopyFile_HandleConfirmation_FaerieY[2] = {0xaf, 0xbf};
+ FileSelect_DrawFairy(0x1c, kCopyFile_HandleConfirmation_FaerieY[selectfile_R16]);
+
+ uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
+ if (a & 0x2c) {
+ sound_effect_2 = 0x20;
+ if (a & 0x24) {
+ if (++selectfile_R16 >= 2)
+ selectfile_R16 = 0;
+ } else {
+ if (sign8(--selectfile_R16))
+ selectfile_R16 = 1;
+ }
+ } else if (a != 0) {
+ sound_effect_1 = 0x2c;
+ if (selectfile_R16 == 0) {
+ memcpy(g_zenv.sram + (selectfile_R18 >> 1) * 0x500, g_zenv.sram + (selectfile_R20 >> 1) * 0x500, 0x500);
+ selectfile_arr1[(selectfile_R18 >> 1)] = 1;
+ ZeldaWriteSram();
+ }
+ ReturnToFileSelect();
+ selectfile_R16 = 0;
+ }
+}
+
+void Module03_KILLFile() { // 8cd485
+ switch (submodule_index) {
+ case 0: FileSelect_EraseTriforce(); break;
+ case 1: Module_EraseFile_1(); break;
+ case 2: KILLFile_SetUp(); break;
+ case 3: KILLFile_HandleSelection(); break;
+ case 4: KILLFile_HandleConfirmation(); break;
+ }
+}
+
+void KILLFile_SetUp() { // 8cd49a
+ nmi_load_bg_from_vram = 8;
+ submodule_index++;
+ INIDISP_copy = 0xf;
+ nmi_disable_core_updates = 0;
+ int i = 0;
+ for (; selectfile_arr1[i] == 0; i++) {}
+ selectfile_R16 = i;
+}
+
+void KILLFile_HandleSelection() { // 8cd49f
+ if (selectfile_R16 < 3)
+ selectfile_var2 = selectfile_R16;
+ KILLFile_ChooseTarget();
+ nmi_load_bg_from_vram = 1;
+}
+
+void KILLFile_HandleConfirmation() { // 8cd4b1
+ SelectFile_Func16();
+ nmi_load_bg_from_vram = 1;
+}
+
+void KILLFile_ChooseTarget() { // 8cd4ba
+ static const uint8 kKILLFile_ChooseTarget_Tab[253] = {
+ 0x61, 0xa7, 0, 0x25, 0xe7, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xc7, 0, 0x25, 0xf7, 0x18,
+ 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0x62, 7, 0, 0x25, 0xe8, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x27,
+ 0, 0x25, 0xf8, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x67, 0, 0x25, 0xe9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0x62, 0x87, 0, 0x25, 0xf9, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+ 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xff,
+ };
+ static const uint8 kKILLFile_ChooseTarget_Tab2[101] = {
+ 0x61, 0xa7, 0x40, 0x24, 0xa9, 0, 0x61, 0xc7, 0x40, 0x24, 0xa9, 0, 0x62, 7, 0x40, 0x24,
+ 0xa9, 0, 0x62, 0x27, 0x40, 0x24, 0xa9, 0, 0x62, 0xc6, 0, 0x21, 4, 0x18, 0x21, 0x18,
+ 0, 0x18, 0x22, 0x18, 4, 0x18, 0xa9, 0x18, 0x23, 0x18, 7, 0x18, 0xaf, 0x18, 0x22, 0x18,
+ 0xa9, 0x18, 0xf, 0x18, 0xb, 0x18, 0, 0x18, 0x28, 0x18, 4, 0x18, 0x21, 0x18, 0x62, 0xe6,
+ 0, 0x21, 0x14, 0x18, 0x31, 0x18, 0x10, 0x18, 0x32, 0x18, 0x14, 0x18, 0xa9, 0x18, 0x33, 0x18,
+ 0x17, 0x18, 0xbf, 0x18, 0x32, 0x18, 0xa9, 0x18, 0x1f, 0x18, 0x1b, 0x18, 0x10, 0x18, 0x38, 0x18,
+ 0x14, 0x18, 0x31, 0x18, 0xff,
+ };
+ static const uint8 kKILLFile_ChooseTarget_FaerieX[4] = {36, 36, 36, 28};
+ static const uint8 kKILLFile_ChooseTarget_FaerieY[4] = {103, 127, 151, 191};
+ memcpy(vram_upload_data, kKILLFile_ChooseTarget_Tab, 253);
+ for (int k = 0; k < 3; k++) {
+ if (selectfile_arr1[k])
+ SelectFile_Func17(k);
+ }
+
+ FileSelect_DrawFairy(kKILLFile_ChooseTarget_FaerieX[selectfile_R16], kKILLFile_ChooseTarget_FaerieY[selectfile_R16]);
+
+ int k = selectfile_R16;
+ if (filtered_joypad_H & 0x2c) {
+ if (!(filtered_joypad_H & 0x24)) {
+ do {
+ if (--k < 0) {
+ k = 3;
+ break;
+ }
+ } while (!selectfile_arr1[k]);
+ } else {
+ do {
+ k++;
+ if (k >= 4)
+ k = 0;
+ } while (k != 3 && !selectfile_arr1[k]);
+ }
+ sound_effect_2 = 0x20;
+ }
+ selectfile_R16 = k;
+
+ uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0;
+ if (a) {
+ sound_effect_1 = 0x2c;
+ if (k == 3) {
+ ReturnToFileSelect();
+ return;
+ }
+
+ memcpy(vram_upload_data, kKILLFile_ChooseTarget_Tab2, 101);
+ submodule_index++;
+ if (selectfile_R16 != 2) {
+ uint16 *dst = vram_upload_data + selectfile_R16 * 6;
+ dst[0] = 0x6762;
+ dst[3] = 0x8762;
+ }
+ subsubmodule_index = selectfile_R16;
+ selectfile_R16 = 0;
+ }
+}
+
+void FileSelect_DrawFairy(uint8 x, uint8 y) { // 8cd7a5
+ 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;
+ int offs = selectfile_R16 * 0x500;
+ attract_legend_ctr = offs;
+ memset(g_zenv.sram + offs, 0, 0x500);
+ uint16 *name = (uint16 *)(g_zenv.sram + offs + kSrmOffs_Name);
+ name[0] = name[1] = name[2] = name[3] = name[4] = name[5] = 0xa9;
+}
+
+void NameFile_DoTheNaming() { // 8cda4d
+ static const int16 kNamePlayer_Tab1[26] = {
+ -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
+ -2, 2, -2, 2, -2, 2, -2, 2, -4, 4,
+ };
+ static const uint8 kNamePlayer_Tab2[4] = {131, 147, 163, 179};
+ static const int8 kNamePlayer_X[6] = {31, 47, 63, 79, 95, 111};
+ static const int16 kNamePlayer_Tab0[32] = {
+ 0x1f0, 0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0,
+ 0xf0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1a0, 0x1b0, 0x1c0, 0x1d0, 0x1e0,
+ };
+ static const int8 kNamePlayer_Tab3[128] = {
+ 6, 7, 0x5f, 9, 0x59, 0x59, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x60, 0x23,
+ 0x59, 0x59, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x59, 0x59, 0x59, 0, 1, 2, 3, 4, 5,
+ 0x10, 0x11, 0x12, 0x13, 0x59, 0x59, 0x24, 0x5f, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+ 0x59, 0x59, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x59, 0x59, 0x59, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
+ 0x40, 0x41, 0x42, 0x59, 0x59, 0x59, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x40, 0x41, 0x42, 0x59,
+ 0x59, 0x59, 0x61, 0x3f, 0x45, 0x46, 0x59, 0x59, 0x59, 0x59, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ 0x44, 0x59, 0x6f, 0x6f, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x44, 0x59, 0x6f, 0x6f,
+ 0x59, 0x59, 0x5a, 0x44, 0x59, 0x6f, 0x6f, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a,
+ };
+ for (;;) {
+ int j = selectfile_var9;
+ if (j == 0) {
+ NameFile_CheckForScrollInputX();
+ break;
+ }
+ if (j != 0x31)
+ selectfile_var9 += 4;
+ j--;
+ if (kNamePlayer_Tab0[selectfile_var3] == selectfile_var8) {
+ selectfile_var9 = (joypad1H_last & 3) ? 0x30 : 0;
+ NameFile_CheckForScrollInputX();
+ continue;
+ }
+ if (!selectfile_var10)
+ j += 2;
+ selectfile_var8 = (selectfile_var8 + WORD(((uint8*)&kNamePlayer_Tab1)[j])) & 0x1ff;
+ break;
+ }
+
+ for (;;) {
+ if (selectfile_var11 == 0) {
+ NameFile_CheckForScrollInputY();
+ break;
+ }
+ uint8 diff = selectfile_var7 - kNamePlayer_Tab2[selectfile_var5];
+ if (diff != 0) {
+ selectfile_var7 += sign8(diff) ? 2 : -2;
+ break;
+ }
+ selectfile_var11 = 0;
+ NameFile_CheckForScrollInputY();
+ }
+
+ OamEnt *oam = oam_buf;
+ for (int i = 0; i != 26; i++) {
+ 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);
+ ZeldaWriteSram();
+ ReturnToFileSelect();
+ irq_flag = 0xff;
+ sound_effect_1 = 0x2c;
+}
+
+void NameFile_CheckForScrollInputX() { // 8cdc8c
+ static const uint16 kNameFile_CheckForScrollInputX_Add[2] = {1, 0xff};
+ static const int16 kNameFile_CheckForScrollInputX_Cmp[2] = {0x20, 0xff};
+ static const int16 kNameFile_CheckForScrollInputX_Set[2] = {0, 0x1f};
+ if (joypad1H_last & 3) {
+ int k = (joypad1H_last & 3) - 1;
+ selectfile_var10 = k;
+ selectfile_var9++;
+ uint8 t = selectfile_var3 + kNameFile_CheckForScrollInputX_Add[k];
+ if (t == kNameFile_CheckForScrollInputX_Cmp[k])
+ t = kNameFile_CheckForScrollInputX_Set[k];
+ selectfile_var3 = t;
+ }
+}
+
+void NameFile_CheckForScrollInputY() { // 8cdcbf
+ static const int8 kNameFile_CheckForScrollInputY_Add[2] = {1, -1};
+ static const int8 kNameFile_CheckForScrollInputY_Cmp[2] = {4, -1};
+ static const int8 kNameFile_CheckForScrollInputY_Set[2] = {0, 3};
+
+ uint8 a = joypad1H_last & 0xc;
+ if (a) {
+ if ((a * 2 | selectfile_var5) == 0x10 || (a * 4 | selectfile_var5) == 0x13) {
+ selectfile_arr2[1] = a;
+ return;
+ }
+ a >>= 2;
+ int t = selectfile_var5 + kNameFile_CheckForScrollInputY_Add[a-1];
+ if (t == kNameFile_CheckForScrollInputY_Cmp[a-1])
+ t = kNameFile_CheckForScrollInputY_Set[a-1];
+ selectfile_var5 = t;
+
+ selectfile_var11++;
+ selectfile_arr2[1] = a;
+
+ } else {
+ selectfile_arr2[0] = 0;
+ }
+}
+
+void NameFile_DrawSelectedCharacter(int k, uint16 chr) { // 8cdd30
+ static const uint16 kNameFile_DrawSelectedCharacter_Tab[6] = {0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e};
+ uint16 *dst = vram_upload_data;
+ uint16 a = kNameFile_DrawSelectedCharacter_Tab[k] | 0x6100;
+ dst[0] = swap16(a);
+ dst[1] = 0x100;
+ dst[2] = 0x1800 | chr;
+ dst[3] = swap16(a + 0x20);
+ dst[4] = 0x100;
+ dst[5] = (0x1800 | chr) + 0x10;
+ BYTE(dst[6]) = 0xff;
+ nmi_load_bg_from_vram = 1;
+}
+
--- a/select_file.cpp
+++ /dev/null
@@ -1,974 +1,0 @@
-#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);
- ZeldaWriteSram();
- }
- ReturnToFileSelect();
- subsubmodule_index = 0;
- }
-}
-
-void Module_NamePlayer_1() {
- uint16 *dst = SelectFile_Func1();
- dst[0] = 0xffff;
- nmi_load_bg_from_vram = 1;
- submodule_index++;
-}
-
-void Module_NamePlayer_2() {
- nmi_load_bg_from_vram = 5;
- submodule_index++;
- INIDISP_copy = 15;
- nmi_disable_core_updates = 0;
-}
-
-void Intro_FixCksum(uint8 *s) {
- uint16 *src = (uint16 *)s;
- uint16 sum = 0;
- for (int i = 0; i < 0x27f; i++)
- sum += src[i];
- src[0x27f] = 0x5a5a - sum;
-}
-
-void LoadFileSelectGraphics() { // 80e4e9
- 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};
-
- const uint8 *cart = g_zenv.sram;
-
- if (selectfile_R16 < 3)
- selectfile_var2 = selectfile_R16;
-
- for (int k = 0; k < 3; k++) {
- if (*(uint16 *)(cart + k * 0x500 + 0x3E5) == 0x55AA) {
- selectfile_arr1[k] = 1;
- SelectFile_Func5_DrawOams(k);
- SelectFile_Func6_DrawOams2(k);
- SelectFile_Func17(k);
- }
- }
-
- FileSelect_DrawFairy(0x1c, kSelectFile_Faerie_Y[selectfile_R16]);
- nmi_load_bg_from_vram = 1;
-
- uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
- if (a & 0x2c) {
- if (a & 8) {
- sound_effect_2 = 0x20;
- if (sign8(--selectfile_R16))
- selectfile_R16 = 4;
- } else {
- sound_effect_2 = 0x20;
- if (++selectfile_R16 == 5)
- selectfile_R16 = 0;
- }
- } else if (a != 0) {
- sound_effect_1 = 0x2c;
- if (selectfile_R16 < 3) {
- selectfile_R17 = 0;
- if (!selectfile_arr1[selectfile_R16]) {
- main_module_index = 4;
- submodule_index = 0;
- subsubmodule_index = 0;
- } else {
- music_control = 0xf1;
- srm_var1 = selectfile_R16 * 2 + 2;
- WORD(g_ram[0]) = selectfile_R16 * 0x500;
- CopySaveToWRAM();
- }
- } else if (selectfile_arr1[0] | selectfile_arr1[1] | selectfile_arr1[2]) {
- main_module_index = (selectfile_R16 == 3) ? 2 : 3;
- selectfile_R16 = 0;
- submodule_index = 0;
- subsubmodule_index = 0;
- } else {
- sound_effect_1 = 0x3c;
- }
- }
-}
-
-void Module02_CopyFile() { // 8cd053
- selectfile_var2 = 0;
- switch (submodule_index) {
- case 0: FileSelect_EraseTriforce(); break;
- case 1: Module_EraseFile_1(); break;
- case 2: Module_CopyFile_2(); break;
- case 3: CopyFile_ChooseSelection(); break;
- case 4: CopyFile_ChooseTarget(); break;
- case 5: CopyFile_ConfirmSelection(); break;
- }
-}
-
-void Module_CopyFile_2() { // 8cd06e
- nmi_load_bg_from_vram = 7;
- submodule_index++;
- INIDISP_copy = 0xf;
- nmi_disable_core_updates = 0;
- int i = 0;
- for (; selectfile_arr1[i] == 0; i++) {}
- selectfile_R16 = i;
-}
-
-void CopyFile_ChooseSelection() { // 8cd087
- CopyFile_SelectionAndBlinker();
- if (submodule_index == 3 && !(frame_counter & 0x30))
- FilePicker_DeleteHeaderStripe();
- nmi_load_bg_from_vram = 1;
-}
-
-void CopyFile_ChooseTarget() { // 8cd0a2
- CopyFile_TargetSelectionAndBlink();
- if (submodule_index == 4 && !(frame_counter & 0x30))
- FilePicker_DeleteHeaderStripe();
- nmi_load_bg_from_vram = 1;
-}
-
-void CopyFile_ConfirmSelection() { // 8cd0b9
- CopyFile_HandleConfirmation();
- nmi_load_bg_from_vram = 1;
-}
-
-void FilePicker_DeleteHeaderStripe() { // 8cd0c6
- static const uint16 kFilePicker_DeleteHeaderStripe_Dst[2] = {4, 0x1e};
- for (int j = 1; j >= 0; j--) {
- uint16 *dst = vram_upload_data + kFilePicker_DeleteHeaderStripe_Dst[j] / 2;
- for (int i = 0; i != 11; i++)
- dst[i] = 0xa9;
- }
-}
-
-void CopyFile_SelectionAndBlinker() { // 8cd13f
- static const uint8 kCopyFile_SelectionAndBlinker_Tab[173] = {
- 0x61, 4, 0, 0x15, 0x85, 0x18, 0x26, 0x18, 7, 0x18, 0xaf, 0x18, 2, 0x18, 7, 0x18,
- 0x6f, 0x18, 0x86, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0x24, 0, 0x15, 0x95, 0x18,
- 0x36, 0x18, 0x17, 0x18, 0xbf, 0x18, 0x12, 0x18, 0x17, 0x18, 0x7f, 0x18, 0x96, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0x61, 0x67, 0, 0xf, 0xe7, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0x87, 0, 0xf, 0xf7, 0x18, 0x91, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xc7, 0, 0xf,
- 0xe8, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0x61, 0xe7, 0, 0xf, 0xf8, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x27, 0, 0xf, 0xe9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x47, 0, 0xf, 0xf9, 0x18, 0x91, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xff,
- };
- static const uint8 kCopyFile_SelectionAndBlinker_Tab1[73] = {
- 0x61, 0x67, 0x40, 0xe, 0xa9, 0, 0x61, 0x87, 0x40, 0xe, 0xa9, 0, 0x61, 0xc7, 0x40, 0xe,
- 0xa9, 0, 0x61, 0xe7, 0x40, 0xe, 0xa9, 0, 0x11, 0x30, 0, 1, 0x83, 0x35, 0x11, 0x31,
- 0x40, 0x14, 0x85, 0x35, 0x11, 0x3c, 0, 1, 0x84, 0x35, 0x11, 0x50, 0xc0, 0xe, 0x86, 0x35,
- 0x11, 0x5c, 0xc0, 0xe, 0x96, 0x35, 0x12, 0x50, 0, 1, 0x93, 0x35, 0x12, 0x51, 0x40, 0x14,
- 0x95, 0x35, 0x12, 0x5c, 0, 1, 0x94, 0x35, 0xff,
- };
- static const uint16 kCopyFile_SelectionAndBlinker_Dst[3] = {0x3c, 0x64, 0x8c};
- static const uint8 kCopyFile_SelectionAndBlinker_FaerieX[4] = {36, 36, 36, 28};
- static const uint8 kCopyFile_SelectionAndBlinker_FaerieY[4] = {87, 111, 135, 191};
-
- vram_upload_offset = 0xac;
- memcpy(vram_upload_data, kCopyFile_SelectionAndBlinker_Tab, 173);
-
- for (int k = 0; k != 3; k++) {
- if (selectfile_arr1[k] & 1) {
- const uint16 *name = (uint16 *)(g_zenv.sram + 0x500 * k + kSrmOffs_Name);
- uint16 *dst = vram_upload_data + kCopyFile_SelectionAndBlinker_Dst[k] / 2;
- for (int i = 0; i != 6; i++) {
- uint16 t = *name++ + 0x1800;
- dst[0] = t;
- dst[10] = t + 0x10;
- dst++;
- }
- }
- }
- FileSelect_DrawFairy(kCopyFile_SelectionAndBlinker_FaerieX[selectfile_R16], kCopyFile_SelectionAndBlinker_FaerieY[selectfile_R16]);
-
- uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
- if (a & 0x2c) {
- uint8 k = selectfile_R16;
- if (a & 8) {
- do {
- if (--k < 0) {
- k = 3;
- break;
- }
- } while (!selectfile_arr1[k]);
- } else {
- do {
- k++;
- if (k >= 4)
- k = 0;
- } while (k != 3 && !selectfile_arr1[k]);
- }
- selectfile_R16 = k;
- sound_effect_2 = 0x20;
- } else if (a != 0) {
- sound_effect_1 = 0x2c;
- if (selectfile_R16 == 3) {
- ReturnToFileSelect();
- return;
- }
- selectfile_R20 = selectfile_R16 * 2;
- memcpy(vram_upload_data + 26, kCopyFile_SelectionAndBlinker_Tab1, 73);
- if (selectfile_R16 != 2) {
- uint16 *dst = vram_upload_data + selectfile_R16 * 6;
- dst[26] = 0x2762;
- dst[29] = 0x4762;
- }
- submodule_index++;
- selectfile_R16 = 0;
- }
-}
-
-void ReturnToFileSelect() { // 8cd22d
- main_module_index = 1;
- submodule_index = 1;
- subsubmodule_index = 0;
- selectfile_R16 = 0;
-}
-
-void CopyFile_TargetSelectionAndBlink() { // 8cd27b
- {
- int k = 1, t = 4;
- do {
- if (t != selectfile_R20)
- selectfile_arr2[k--] = t;
- } while ((t -= 2) >= 0);
- }
-
- static const uint8 kCopyFile_TargetSelectionAndBlink_Tab0[133] = {
- 0x61, 0x51, 0, 0x15, 0x85, 0x18, 0x23, 0x18, 0xe, 0x18, 0xa9, 0x18, 0x26, 0x18, 7, 0x18,
- 0xaf, 0x18, 2, 0x18, 7, 0x18, 0x6f, 0x18, 0x86, 0x18, 0x61, 0x71, 0, 0x15, 0x95, 0x18,
- 0x33, 0x18, 0x1e, 0x18, 0xb9, 0x18, 0x36, 0x18, 0x17, 0x18, 0xbf, 0x18, 0x12, 0x18, 0x17, 0x18,
- 0x7f, 0x18, 0x96, 0x18, 0x61, 0xb4, 0, 0xf, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xd4, 0, 0xf, 0xa9, 0x18, 0x91, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x14, 0, 0xf,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0x62, 0x34, 0, 0xf, 0xa9, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xff,
- };
- static const uint8 kCopyFile_TargetSelectionAndBlink_Tab2[49] = {
- 0x61, 0xb4, 0x40, 0xe, 0xa9, 0, 0x61, 0xd4, 0x40, 0xe, 0xa9, 0, 0x62, 0xc6, 0, 0xd,
- 2, 0x18, 0xe, 0x18, 0xf, 0x18, 0x28, 0x18, 0xa9, 0x18, 0xe, 0x18, 0xa, 0x18, 0x62, 0xe6,
- 0, 0xd, 0x12, 0x18, 0x1e, 0x18, 0x1f, 0x18, 0x38, 0x18, 0xa9, 0x18, 0x1e, 0x18, 0x1a, 0x18,
- 0xff,
- };
- static const uint8 kCopyFile_TargetSelectionAndBlink_FaerieX[3] = {0x8c, 0x8c, 0x1c};
- static const uint8 kCopyFile_TargetSelectionAndBlink_FaerieY[3] = {0x67, 0x7f, 0xbf};
- static const uint16 kCopyFile_TargetSelectionAndBlink_Dst[2] = {0x38, 0x60};
- static const uint16 kCopyFile_TargetSelectionAndBlink_Tab1[3] = {0x18e7, 0x18e8, 0x18e9};
- memcpy(vram_upload_data, kCopyFile_TargetSelectionAndBlink_Tab0, 133);
-
- for (int k = 0, j = 0; k != 3; k++) {
- if (k * 2 == selectfile_R20)
- continue;
-
- uint16 *dst = vram_upload_data + kCopyFile_TargetSelectionAndBlink_Dst[j++] / 2;
- uint16 t = kCopyFile_TargetSelectionAndBlink_Tab1[k];
- dst[0] = t;
- dst[10] = t + 0x10;
- dst += 2;
- if (selectfile_arr1[k]) {
- const uint16 *name = (uint16 *)(g_zenv.sram + 0x500 * k + kSrmOffs_Name);
- for (int i = 0; i != 6; i++) {
- uint16 t = *name++ + 0x1800;
- dst[0] = t;
- dst[10] = t + 0x10;
- dst++;
- }
- }
- }
-
- vram_upload_offset = 132;
-
- FileSelect_DrawFairy(kCopyFile_TargetSelectionAndBlink_FaerieX[selectfile_R16], kCopyFile_TargetSelectionAndBlink_FaerieY[selectfile_R16]);
-
- uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
- if (a & 0x2c) {
- uint8 k = selectfile_R16;
- if (a & 8) {
- if (sign8(--k))
- k = 2;
- } else {
- if (++k >= 3)
- k = 0;
- }
- selectfile_R16 = k;
- sound_effect_2 = 0x20;
- } else if (a) {
- sound_effect_1 = 0x2c;
- if (selectfile_R16 == 2) {
- ReturnToFileSelect();
- selectfile_R16 = 0;
- return;
- }
- selectfile_R18 = selectfile_arr2[selectfile_R16];
- memcpy(vram_upload_data + 26, kCopyFile_TargetSelectionAndBlink_Tab2, 49);
- if (selectfile_R16 == 0) {
- uint16 *dst = vram_upload_data;
- dst[26] = 0x1462;
- dst[29] = 0x3462;
- }
- submodule_index++;
- selectfile_R16 = 0;
- }
-}
-
-void CopyFile_HandleConfirmation() { // 8cd371
- static const uint8 kCopyFile_HandleConfirmation_FaerieY[2] = {0xaf, 0xbf};
- FileSelect_DrawFairy(0x1c, kCopyFile_HandleConfirmation_FaerieY[selectfile_R16]);
-
- uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
- if (a & 0x2c) {
- sound_effect_2 = 0x20;
- if (a & 0x24) {
- if (++selectfile_R16 >= 2)
- selectfile_R16 = 0;
- } else {
- if (sign8(--selectfile_R16))
- selectfile_R16 = 1;
- }
- } else if (a != 0) {
- sound_effect_1 = 0x2c;
- if (selectfile_R16 == 0) {
- memcpy(g_zenv.sram + (selectfile_R18 >> 1) * 0x500, g_zenv.sram + (selectfile_R20 >> 1) * 0x500, 0x500);
- selectfile_arr1[(selectfile_R18 >> 1)] = 1;
- ZeldaWriteSram();
- }
- ReturnToFileSelect();
- selectfile_R16 = 0;
- }
-}
-
-void Module03_KILLFile() { // 8cd485
- switch (submodule_index) {
- case 0: FileSelect_EraseTriforce(); break;
- case 1: Module_EraseFile_1(); break;
- case 2: KILLFile_SetUp(); break;
- case 3: KILLFile_HandleSelection(); break;
- case 4: KILLFile_HandleConfirmation(); break;
- }
-}
-
-void KILLFile_SetUp() { // 8cd49a
- nmi_load_bg_from_vram = 8;
- submodule_index++;
- INIDISP_copy = 0xf;
- nmi_disable_core_updates = 0;
- int i = 0;
- for (; selectfile_arr1[i] == 0; i++) {}
- selectfile_R16 = i;
-}
-
-void KILLFile_HandleSelection() { // 8cd49f
- if (selectfile_R16 < 3)
- selectfile_var2 = selectfile_R16;
- KILLFile_ChooseTarget();
- nmi_load_bg_from_vram = 1;
-}
-
-void KILLFile_HandleConfirmation() { // 8cd4b1
- SelectFile_Func16();
- nmi_load_bg_from_vram = 1;
-}
-
-void KILLFile_ChooseTarget() { // 8cd4ba
- static const uint8 kKILLFile_ChooseTarget_Tab[253] = {
- 0x61, 0xa7, 0, 0x25, 0xe7, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xc7, 0, 0x25, 0xf7, 0x18,
- 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0x62, 7, 0, 0x25, 0xe8, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x27,
- 0, 0x25, 0xf8, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x67, 0, 0x25, 0xe9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0x62, 0x87, 0, 0x25, 0xf9, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
- 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xff,
- };
- static const uint8 kKILLFile_ChooseTarget_Tab2[101] = {
- 0x61, 0xa7, 0x40, 0x24, 0xa9, 0, 0x61, 0xc7, 0x40, 0x24, 0xa9, 0, 0x62, 7, 0x40, 0x24,
- 0xa9, 0, 0x62, 0x27, 0x40, 0x24, 0xa9, 0, 0x62, 0xc6, 0, 0x21, 4, 0x18, 0x21, 0x18,
- 0, 0x18, 0x22, 0x18, 4, 0x18, 0xa9, 0x18, 0x23, 0x18, 7, 0x18, 0xaf, 0x18, 0x22, 0x18,
- 0xa9, 0x18, 0xf, 0x18, 0xb, 0x18, 0, 0x18, 0x28, 0x18, 4, 0x18, 0x21, 0x18, 0x62, 0xe6,
- 0, 0x21, 0x14, 0x18, 0x31, 0x18, 0x10, 0x18, 0x32, 0x18, 0x14, 0x18, 0xa9, 0x18, 0x33, 0x18,
- 0x17, 0x18, 0xbf, 0x18, 0x32, 0x18, 0xa9, 0x18, 0x1f, 0x18, 0x1b, 0x18, 0x10, 0x18, 0x38, 0x18,
- 0x14, 0x18, 0x31, 0x18, 0xff,
- };
- static const uint8 kKILLFile_ChooseTarget_FaerieX[4] = {36, 36, 36, 28};
- static const uint8 kKILLFile_ChooseTarget_FaerieY[4] = {103, 127, 151, 191};
- memcpy(vram_upload_data, kKILLFile_ChooseTarget_Tab, 253);
- for (int k = 0; k < 3; k++) {
- if (selectfile_arr1[k])
- SelectFile_Func17(k);
- }
-
- FileSelect_DrawFairy(kKILLFile_ChooseTarget_FaerieX[selectfile_R16], kKILLFile_ChooseTarget_FaerieY[selectfile_R16]);
-
- int k = selectfile_R16;
- if (filtered_joypad_H & 0x2c) {
- if (!(filtered_joypad_H & 0x24)) {
- do {
- if (--k < 0) {
- k = 3;
- break;
- }
- } while (!selectfile_arr1[k]);
- } else {
- do {
- k++;
- if (k >= 4)
- k = 0;
- } while (k != 3 && !selectfile_arr1[k]);
- }
- sound_effect_2 = 0x20;
- }
- selectfile_R16 = k;
-
- uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0;
- if (a) {
- sound_effect_1 = 0x2c;
- if (k == 3) {
- ReturnToFileSelect();
- return;
- }
-
- memcpy(vram_upload_data, kKILLFile_ChooseTarget_Tab2, 101);
- submodule_index++;
- if (selectfile_R16 != 2) {
- uint16 *dst = vram_upload_data + selectfile_R16 * 6;
- dst[0] = 0x6762;
- dst[3] = 0x8762;
- }
- subsubmodule_index = selectfile_R16;
- selectfile_R16 = 0;
- }
-}
-
-void FileSelect_DrawFairy(uint8 x, uint8 y) { // 8cd7a5
- 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;
- int offs = selectfile_R16 * 0x500;
- attract_legend_ctr = offs;
- memset(g_zenv.sram + offs, 0, 0x500);
- uint16 *name = (uint16 *)(g_zenv.sram + offs + kSrmOffs_Name);
- name[0] = name[1] = name[2] = name[3] = name[4] = name[5] = 0xa9;
-}
-
-void NameFile_DoTheNaming() { // 8cda4d
- static const int16 kNamePlayer_Tab1[26] = {
- -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
- -2, 2, -2, 2, -2, 2, -2, 2, -4, 4,
- };
- static const uint8 kNamePlayer_Tab2[4] = {131, 147, 163, 179};
- static const int8 kNamePlayer_X[6] = {31, 47, 63, 79, 95, 111};
- static const int16 kNamePlayer_Tab0[32] = {
- 0x1f0, 0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0,
- 0xf0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1a0, 0x1b0, 0x1c0, 0x1d0, 0x1e0,
- };
- static const int8 kNamePlayer_Tab3[128] = {
- 6, 7, 0x5f, 9, 0x59, 0x59, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x60, 0x23,
- 0x59, 0x59, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x59, 0x59, 0x59, 0, 1, 2, 3, 4, 5,
- 0x10, 0x11, 0x12, 0x13, 0x59, 0x59, 0x24, 0x5f, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
- 0x59, 0x59, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x59, 0x59, 0x59, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
- 0x40, 0x41, 0x42, 0x59, 0x59, 0x59, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x40, 0x41, 0x42, 0x59,
- 0x59, 0x59, 0x61, 0x3f, 0x45, 0x46, 0x59, 0x59, 0x59, 0x59, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
- 0x44, 0x59, 0x6f, 0x6f, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x44, 0x59, 0x6f, 0x6f,
- 0x59, 0x59, 0x5a, 0x44, 0x59, 0x6f, 0x6f, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a,
- };
- for (;;) {
- int j = selectfile_var9;
- if (j == 0) {
- NameFile_CheckForScrollInputX();
- break;
- }
- if (j != 0x31)
- selectfile_var9 += 4;
- j--;
- if (kNamePlayer_Tab0[selectfile_var3] == selectfile_var8) {
- selectfile_var9 = (joypad1H_last & 3) ? 0x30 : 0;
- NameFile_CheckForScrollInputX();
- continue;
- }
- if (!selectfile_var10)
- j += 2;
- selectfile_var8 = (selectfile_var8 + WORD(((uint8*)&kNamePlayer_Tab1)[j])) & 0x1ff;
- break;
- }
-
- for (;;) {
- if (selectfile_var11 == 0) {
- NameFile_CheckForScrollInputY();
- break;
- }
- uint8 diff = selectfile_var7 - kNamePlayer_Tab2[selectfile_var5];
- if (diff != 0) {
- selectfile_var7 += sign8(diff) ? 2 : -2;
- break;
- }
- selectfile_var11 = 0;
- NameFile_CheckForScrollInputY();
- }
-
- OamEnt *oam = oam_buf;
- for (int i = 0; i != 26; i++) {
- 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);
- ZeldaWriteSram();
- ReturnToFileSelect();
- irq_flag = 0xff;
- sound_effect_1 = 0x2c;
-}
-
-void NameFile_CheckForScrollInputX() { // 8cdc8c
- static const uint16 kNameFile_CheckForScrollInputX_Add[2] = {1, 0xff};
- static const int16 kNameFile_CheckForScrollInputX_Cmp[2] = {0x20, 0xff};
- static const int16 kNameFile_CheckForScrollInputX_Set[2] = {0, 0x1f};
- if (joypad1H_last & 3) {
- int k = (joypad1H_last & 3) - 1;
- selectfile_var10 = k;
- selectfile_var9++;
- uint8 t = selectfile_var3 + kNameFile_CheckForScrollInputX_Add[k];
- if (t == kNameFile_CheckForScrollInputX_Cmp[k])
- t = kNameFile_CheckForScrollInputX_Set[k];
- selectfile_var3 = t;
- }
-}
-
-void NameFile_CheckForScrollInputY() { // 8cdcbf
- static const int8 kNameFile_CheckForScrollInputY_Add[2] = {1, -1};
- static const int8 kNameFile_CheckForScrollInputY_Cmp[2] = {4, -1};
- static const int8 kNameFile_CheckForScrollInputY_Set[2] = {0, 3};
-
- uint8 a = joypad1H_last & 0xc;
- if (a) {
- if ((a * 2 | selectfile_var5) == 0x10 || (a * 4 | selectfile_var5) == 0x13) {
- selectfile_arr2[1] = a;
- return;
- }
- a >>= 2;
- int t = selectfile_var5 + kNameFile_CheckForScrollInputY_Add[a-1];
- if (t == kNameFile_CheckForScrollInputY_Cmp[a-1])
- t = kNameFile_CheckForScrollInputY_Set[a-1];
- selectfile_var5 = t;
-
- selectfile_var11++;
- selectfile_arr2[1] = a;
-
- } else {
- selectfile_arr2[0] = 0;
- }
-}
-
-void NameFile_DrawSelectedCharacter(int k, uint16 chr) { // 8cdd30
- static const uint16 kNameFile_DrawSelectedCharacter_Tab[6] = {0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e};
- uint16 *dst = vram_upload_data;
- uint16 a = kNameFile_DrawSelectedCharacter_Tab[k] | 0x6100;
- dst[0] = swap16(a);
- dst[1] = 0x100;
- dst[2] = 0x1800 | chr;
- dst[3] = swap16(a + 0x20);
- dst[4] = 0x100;
- dst[5] = (0x1800 | chr) + 0x10;
- BYTE(dst[6]) = 0xff;
- nmi_load_bg_from_vram = 1;
-}
-
--- /dev/null
+++ b/snes/apu.c
@@ -1,0 +1,184 @@
+
+#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) {
+ 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] = 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;
+}
--- a/snes/apu.cpp
+++ /dev/null
@@ -1,186 +1,0 @@
-
-#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;
-}
--- a/snes/apu.h
+++ b/snes/apu.h
@@ -39,7 +39,7 @@
};
};
-struct Apu2 {
+typedef struct Apu2 {
// Snes* snes;
Spc* spc;
Dsp* dsp;
@@ -51,7 +51,7 @@
uint8_t outPorts[4];
Timer timer[3];
uint8_t cpuCyclesLeft;
-};
+} Apu2;
Apu* apu_init();
void apu_free(Apu* apu);
--- /dev/null
+++ b/snes/cart.c
@@ -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;
+ }
+}
--- a/snes/cart.cpp
+++ /dev/null
@@ -1,112 +1,0 @@
-
-#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/cpu.c
@@ -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;
+ }
+ }
+}
--- a/snes/cpu.cpp
+++ /dev/null
@@ -1,2443 +1,0 @@
-
-#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/dma.c
@@ -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
+ }
+}
--- a/snes/dma.cpp
+++ /dev/null
@@ -1,328 +1,0 @@
-
-#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/dsp.c
@@ -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;
+}
--- a/snes/dsp.cpp
+++ /dev/null
@@ -1,578 +1,0 @@
-
-#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;
-}
--- a/snes/dsp.h
+++ b/snes/dsp.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <stdbool.h>
+#include "dsp_regs.h"
typedef struct Dsp Dsp;
#include "saveload.h"
@@ -81,11 +82,9 @@
};
-#include "../dsp_regs.h"
-
typedef struct DspRegWriteHistory {
uint32_t count;
- enum DspReg addr[256];
+ uint8_t addr[256];
uint8_t val[256];
} DspRegWriteHistory;
--- /dev/null
+++ b/snes/dsp_regs.h
@@ -1,0 +1,110 @@
+#ifndef DSP_REGS_H
+#define DSP_REGS_H
+
+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,
+};
+#endif // DSP_REGS_H
\ No newline at end of file
--- /dev/null
+++ b/snes/input.c
@@ -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;
+}
--- a/snes/input.cpp
+++ /dev/null
@@ -1,40 +1,0 @@
-
-#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/ppu.c
@@ -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);
+ }
+}
--- a/snes/ppu.cpp
+++ /dev/null
@@ -1,1047 +1,0 @@
-
-#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/snes.c
@@ -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;
+ }
+}
--- a/snes/snes.cpp
+++ /dev/null
@@ -1,586 +1,0 @@
-
-#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_other.c
@@ -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;
+}
--- a/snes/snes_other.cpp
+++ /dev/null
@@ -1,220 +1,0 @@
-
-#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.c
@@ -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;
+ }
+ }
+}
--- a/snes/spc.cpp
+++ /dev/null
@@ -1,1528 +1,0 @@
-
-#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/spc_player.c
@@ -1,0 +1,1446 @@
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <SDL.h>
+#include <assert.h>
+#include "types.h"
+
+#include "snes/spc.h"
+#include "snes/dsp_regs.h"
+#include "tracing.h"
+
+#include "spc_player.h"
+
+typedef struct MemMap {
+ uint16 off, org_off;
+} MemMap;
+
+typedef struct MemMapSized {
+ uint16 off, org_off, size;
+} MemMapSized;
+
+static const MemMap kChannel_Maps[] = {
+ {offsetof(Channel, pattern_order_ptr_for_chan), 0x8030},
+ {offsetof(Channel, note_ticks_left), 0x70},
+ {offsetof(Channel, note_keyoff_ticks_left), 0x71},
+ {offsetof(Channel, subroutine_num_loops), 0x80},
+ {offsetof(Channel, volume_fade_ticks), 0x90},
+ {offsetof(Channel, pan_num_ticks), 0x91},
+ {offsetof(Channel, pitch_slide_length), 0xa0},
+ {offsetof(Channel, pitch_slide_delay_left), 0xa1},
+ {offsetof(Channel, vibrato_hold_count), 0xb0},
+ {offsetof(Channel, vib_depth), 0xb1},
+ {offsetof(Channel, tremolo_hold_count), 0xc0},
+ {offsetof(Channel, tremolo_depth), 0xc1},
+ {offsetof(Channel, vibrato_change_count), 0x100},
+ {offsetof(Channel, note_length), 0x200},
+ {offsetof(Channel, note_gate_off_fixedpt), 0x201},
+ {offsetof(Channel, channel_volume_master), 0x210},
+ {offsetof(Channel, instrument_id), 0x211},
+ {offsetof(Channel, instrument_pitch_base), 0x8220},
+ {offsetof(Channel, saved_pattern_ptr), 0x8230},
+ {offsetof(Channel, pattern_start_ptr), 0x8240},
+ {offsetof(Channel, pitch_envelope_num_ticks), 0x280},
+ {offsetof(Channel, pitch_envelope_delay), 0x281},
+ {offsetof(Channel, pitch_envelope_direction), 0x290},
+ {offsetof(Channel, pitch_envelope_slide_value), 0x291},
+ {offsetof(Channel, vibrato_count), 0x2a0},
+ {offsetof(Channel, vibrato_rate), 0x2a1},
+ {offsetof(Channel, vibrato_delay_ticks), 0x2b0},
+ {offsetof(Channel, vibrato_fade_num_ticks), 0x2b1},
+ {offsetof(Channel, vibrato_fade_add_per_tick), 0x2c0},
+ {offsetof(Channel, vibrato_depth_target), 0x2c1},
+ {offsetof(Channel, tremolo_count), 0x2d0},
+ {offsetof(Channel, tremolo_rate), 0x2d1},
+ {offsetof(Channel, tremolo_delay_ticks), 0x2e0},
+ {offsetof(Channel, channel_transposition), 0x2f0},
+ {offsetof(Channel, channel_volume), 0x8300},
+ {offsetof(Channel, volume_fade_addpertick), 0x8310},
+ {offsetof(Channel, volume_fade_target), 0x320},
+ {offsetof(Channel, final_volume), 0x321},
+ {offsetof(Channel, pan_value), 0x8330},
+ {offsetof(Channel, pan_add_per_tick), 0x8340},
+ {offsetof(Channel, pan_target_value), 0x350},
+ {offsetof(Channel, pan_flag_with_phase_invert), 0x351},
+ {offsetof(Channel, pitch), 0x8360},
+ {offsetof(Channel, pitch_add_per_tick), 0x8370},
+ {offsetof(Channel, pitch_target), 0x380},
+ {offsetof(Channel, fine_tune), 0x381},
+ {offsetof(Channel, sfx_sound_ptr), 0x8390},
+ {offsetof(Channel, sfx_which_sound), 0x3a0},
+ {offsetof(Channel, sfx_arr_countdown), 0x3a1},
+ {offsetof(Channel, sfx_note_length_left), 0x3b0},
+ {offsetof(Channel, sfx_note_length), 0x3b1},
+ {offsetof(Channel, sfx_pan), 0x3d0},
+};
+
+static const MemMapSized kSpcPlayer_Maps[] = {
+ {offsetof(SpcPlayer, new_value_from_snes), 0x0, 4},
+ {offsetof(SpcPlayer, port_to_snes), 0x4, 4},
+ {offsetof(SpcPlayer, last_value_from_snes), 0x8, 4},
+ {offsetof(SpcPlayer, counter_sf0c), 0xc, 1},
+ {offsetof(SpcPlayer, _always_zero), 0xe, 2},
+ {offsetof(SpcPlayer, temp_accum), 0x10, 2},
+ {offsetof(SpcPlayer, ttt), 0x12, 1},
+ {offsetof(SpcPlayer, did_affect_volumepitch_flag), 0x13, 1},
+ {offsetof(SpcPlayer, addr0), 0x14, 2},
+ {offsetof(SpcPlayer, addr1), 0x16, 2},
+ {offsetof(SpcPlayer, lfsr_value), 0x18, 2},
+ {offsetof(SpcPlayer, is_chan_on), 0x1a, 1},
+ {offsetof(SpcPlayer, fast_forward), 0x1b, 1},
+ {offsetof(SpcPlayer, sfx_start_arg_pan), 0x20, 1},
+ {offsetof(SpcPlayer, sfx_sound_ptr_cur), 0x2c, 2},
+ {offsetof(SpcPlayer, music_ptr_toplevel), 0x40, 2},
+ {offsetof(SpcPlayer, block_count), 0x42, 1},
+ {offsetof(SpcPlayer, sfx_timer_accum), 0x43, 1},
+ {offsetof(SpcPlayer, chn), 0x44, 1},
+ {offsetof(SpcPlayer, key_ON), 0x45, 1},
+ {offsetof(SpcPlayer, key_OFF), 0x46, 1},
+ {offsetof(SpcPlayer, cur_chan_bit), 0x47, 1},
+ {offsetof(SpcPlayer, reg_FLG), 0x48, 1},
+ {offsetof(SpcPlayer, reg_NON), 0x49, 1},
+ {offsetof(SpcPlayer, reg_EON), 0x4a, 1},
+ {offsetof(SpcPlayer, reg_PMON), 0x4b, 1},
+ {offsetof(SpcPlayer, echo_stored_time), 0x4c, 1},
+ {offsetof(SpcPlayer, echo_parameter_EDL), 0x4d, 1},
+ {offsetof(SpcPlayer, reg_EFB), 0x4e, 1},
+ {offsetof(SpcPlayer, global_transposition), 0x50, 1},
+ {offsetof(SpcPlayer, main_tempo_accum), 0x51, 1},
+ {offsetof(SpcPlayer, tempo), 0x52, 2},
+ {offsetof(SpcPlayer, tempo_fade_num_ticks), 0x54, 1},
+ {offsetof(SpcPlayer, tempo_fade_final), 0x55, 1},
+ {offsetof(SpcPlayer, tempo_fade_add), 0x56, 2},
+ {offsetof(SpcPlayer, master_volume), 0x58, 2},
+ {offsetof(SpcPlayer, master_volume_fade_ticks), 0x5a, 1},
+ {offsetof(SpcPlayer, master_volume_fade_target), 0x5b, 1},
+ {offsetof(SpcPlayer, master_volume_fade_add_per_tick), 0x5c, 2},
+ {offsetof(SpcPlayer, vol_dirty), 0x5e, 1},
+ {offsetof(SpcPlayer, percussion_base_id), 0x5f, 1},
+ {offsetof(SpcPlayer, echo_volume_left), 0x60, 2},
+ {offsetof(SpcPlayer, echo_volume_right), 0x62, 2},
+ {offsetof(SpcPlayer, echo_volume_fade_add_left), 0x64, 2},
+ {offsetof(SpcPlayer, echo_volume_fade_add_right), 0x66, 2},
+ {offsetof(SpcPlayer, echo_volume_fade_ticks), 0x68, 1},
+ {offsetof(SpcPlayer, echo_volume_fade_target_left), 0x69, 1},
+ {offsetof(SpcPlayer, echo_volume_fade_target_right), 0x6a, 1},
+ {offsetof(SpcPlayer, sfx_channel_index), 0x3c0, 1},
+ {offsetof(SpcPlayer, current_bit), 0x3c1, 1},
+ {offsetof(SpcPlayer, dsp_register_index), 0x3c2, 1},
+ {offsetof(SpcPlayer, echo_channels), 0x3c3, 1},
+ {offsetof(SpcPlayer, byte_3C4), 0x3c4, 1},
+ {offsetof(SpcPlayer, byte_3C5), 0x3c5, 1},
+ {offsetof(SpcPlayer, echo_fract_incr), 0x3c7, 1},
+ {offsetof(SpcPlayer, sfx_channel_index2), 0x3c8, 1},
+ {offsetof(SpcPlayer, sfx_channel_bit), 0x3c9, 1},
+ {offsetof(SpcPlayer, pause_music_ctr), 0x3ca, 1},
+ {offsetof(SpcPlayer, port2_active), 0x3cb, 1},
+ {offsetof(SpcPlayer, port2_current_bit), 0x3cc, 1},
+ {offsetof(SpcPlayer, port3_active), 0x3cd, 1},
+ {offsetof(SpcPlayer, port3_current_bit), 0x3ce, 1},
+ {offsetof(SpcPlayer, port1_active), 0x3cf, 1},
+ {offsetof(SpcPlayer, port1_current_bit), 0x3e0, 1},
+ {offsetof(SpcPlayer, byte_3E1), 0x3e1, 1},
+ {offsetof(SpcPlayer, sfx_play_echo_flag), 0x3e2, 1},
+ {offsetof(SpcPlayer, sfx_channels_echo_mask2), 0x3e3, 1},
+ {offsetof(SpcPlayer, port1_counter), 0x3e4, 1},
+ {offsetof(SpcPlayer, channel_67_volume), 0x3e5, 1},
+ {offsetof(SpcPlayer, cutk_always_zero), 0x3ff, 1},
+};
+
+static void PlayNote(SpcPlayer *p, Channel *c, uint8 note);
+
+static void Dsp_Write(SpcPlayer *p, uint8_t reg, uint8 value) {
+ DspRegWriteHistory *hist = p->reg_write_history;
+ if (hist) {
+ if (hist->count < 256) {
+ hist->addr[hist->count] = reg;
+ hist->val[hist->count] = value;
+ hist->count++;
+ }
+ }
+ if (p->dsp)
+ dsp_write(p->dsp, reg, value);
+}
+
+static void Not_Implemented() {
+ assert(0);
+ printf("Not Implemented\n");
+}
+
+static uint16 SpcDivHelper(int a, uint8 b) {
+ int org_a = a;
+ if (a & 0x100)
+ a = -a;
+ int q = b ? (a & 0xff) / b : 0xff;
+ int r = b ? (a & 0xff) % b : (a & 0xff);
+ int t = (q << 8) + (b ? ((r << 8) / b & 0xff) : 0xff);
+ return (org_a & 0x100) ? -t : t;
+}
+
+static inline void Chan_DoAnyFade(uint16 *p, uint16 add, uint8 target, uint8 cont) {
+ if (!cont)
+ *p = target << 8;
+ else
+ *p += add;
+}
+
+static void SetupEchoParameter_EDL(SpcPlayer *p, uint8 a) {
+ p->echo_parameter_EDL = a;
+ if (a != p->last_written_edl) {
+ a = (p->last_written_edl & 0xf) ^ 0xff;
+ if (p->echo_stored_time & 0x80)
+ a += p->echo_stored_time;
+ p->echo_stored_time = a;
+
+ Dsp_Write(p, EON, 0);
+ Dsp_Write(p, EFB, 0);
+ Dsp_Write(p, EVOLR, 0);
+ Dsp_Write(p, EVOLL, 0);
+ Dsp_Write(p, FLG, p->reg_FLG | 0x20);
+
+ p->last_written_edl = p->echo_parameter_EDL;
+ Dsp_Write(p, EDL, p->echo_parameter_EDL);
+ }
+ Dsp_Write(p, ESA, (p->echo_parameter_EDL * 8 ^ 0xff) + 0xd1);
+}
+
+static void WriteVolumeToDsp(SpcPlayer *p, Channel *c, uint16 volume) {
+ static const uint8 kVolumeTable[22] = {0, 1, 3, 7, 13, 21, 30, 41, 52, 66, 81, 94, 103, 110, 115, 119, 122, 124, 125, 126, 127, 127};
+ if (p->is_chan_on & p->cur_chan_bit)
+ return;
+ for (int i = 0; i < 2; i++) {
+ int j = volume >> 8;
+ uint8 t;
+ if (j >= 21) {
+ t = p->ram[j + 0x1178] + ((p->ram[j + 0x1179] - p->ram[j + 0x1178]) * (uint8)volume >> 8);
+ } else {
+ t = kVolumeTable[j] + ((kVolumeTable[j + 1] - kVolumeTable[j]) * (uint8)volume >> 8);
+ }
+
+
+ t = t * c->final_volume >> 8;
+ if ((c->pan_flag_with_phase_invert << i) & 0x80)
+ t = -t;
+ Dsp_Write(p, V0VOLL + i + c->index * 16, t);
+ volume = 0x1400 - volume;
+ }
+}
+
+static void WritePitch(SpcPlayer *p, Channel *c, uint16 pitch) {
+ static const uint16 kBaseNoteFreqs[13] = {2143, 2270, 2405, 2548, 2700, 2860, 3030, 3211, 3402, 3604, 3818, 4045, 4286};
+ if ((pitch >> 8) >= 0x34) {
+ pitch += (pitch >> 8) - 0x34;
+ } else if ((pitch >> 8) < 0x13) {
+ pitch += (uint8)(((pitch >> 8) - 0x13) * 2) - 256;
+ }
+
+ uint8 pp = (pitch >> 8) & 0x7f;
+ uint8 q = pp / 12, r = pp % 12;
+ uint16 t = kBaseNoteFreqs[r] + ((uint8)(kBaseNoteFreqs[r + 1] - kBaseNoteFreqs[r]) * (uint8)pitch >> 8);
+ t *= 2;
+ while (q != 6)
+ t >>= 1, q++;
+
+ t = c->instrument_pitch_base * t >> 8;
+ if (!(p->cur_chan_bit & p->is_chan_on)) {
+ uint8 reg = c->index * 16;
+ Dsp_Write(p, reg + V0PITCHL, t & 0xff);
+ Dsp_Write(p, reg + V0PITCHH, t >> 8);
+ }
+}
+
+static void Music_ResetChan(SpcPlayer *p) {
+ Channel *c = &p->channel[7];
+ p->cur_chan_bit = 0x80;
+ do {
+ HIBYTE(c->channel_volume) = 0xff;
+ c->pan_flag_with_phase_invert = 10;
+ c->pan_value = 10 << 8;
+ c->instrument_id = 0;
+ c->fine_tune = 0;
+ c->channel_transposition = 0;
+ c->pitch_envelope_num_ticks = 0;
+ c->vib_depth = 0;
+ c->tremolo_depth = 0;
+ } while (c--, p->cur_chan_bit >>= 1);
+ p->master_volume_fade_ticks = 0;
+ p->echo_volume_fade_ticks = 0;
+ p->tempo_fade_num_ticks = 0;
+ p->global_transposition = 0;
+ p->block_count = 0;
+ p->percussion_base_id = 0;
+ HIBYTE(p->master_volume) = 0xc0;
+ HIBYTE(p->tempo) = 0x20;
+}
+
+static void Channel_SetInstrument(SpcPlayer *p, Channel *c, uint8 instrument) {
+ c->instrument_id = instrument;
+ if (instrument & 0x80)
+ instrument = instrument + 54 + p->percussion_base_id;
+ const uint8 *ip = p->ram + instrument * 6 + 0x3d00;
+ if (p->is_chan_on & p->cur_chan_bit)
+ return;
+ uint8 reg = c->index * 16;
+ if (ip[0] & 0x80) {
+ // noise
+ p->reg_FLG = (p->reg_FLG & 0x20) | ip[0] & 0x1f;
+ p->reg_NON |= p->cur_chan_bit;
+ Dsp_Write(p, reg + V0SRCN, 0);
+ } else {
+ Dsp_Write(p, reg + V0SRCN, ip[0]);
+ }
+ Dsp_Write(p, reg + V0ADSR1, ip[1]);
+ Dsp_Write(p, reg + V0ADSR2, ip[2]);
+ Dsp_Write(p, reg + V0GAIN, ip[3]);
+ c->instrument_pitch_base = ip[4] << 8 | ip[5];
+}
+
+static void ComputePitchAdd(Channel *c, uint8 pitch) {
+ c->pitch_target = pitch & 0x7f;
+ c->pitch_add_per_tick = SpcDivHelper(c->pitch_target - (c->pitch >> 8), c->pitch_slide_length);
+}
+
+static void PitchSlideToNote_Check(SpcPlayer *p, Channel *c) {
+ if (c->pitch_slide_length || p->ram[c->pattern_order_ptr_for_chan] != 0xf9)
+ return;
+
+ if (p->cur_chan_bit & p->is_chan_on) {
+ c->pattern_order_ptr_for_chan += 4;
+ return;
+ }
+ c->pattern_order_ptr_for_chan++;
+ c->pitch_slide_delay_left = p->ram[c->pattern_order_ptr_for_chan++];
+ c->pitch_slide_length = p->ram[c->pattern_order_ptr_for_chan++];
+ ComputePitchAdd(c, p->ram[c->pattern_order_ptr_for_chan++] + p->global_transposition + c->channel_transposition);
+}
+
+static const uint8 kEffectByteLength[27] = {1, 1, 2, 3, 0, 1, 2, 1, 2, 1, 1, 3, 0, 1, 2, 3, 1, 3, 3, 0, 1, 3, 0, 3, 3, 3, 1};
+
+static void HandleEffect(SpcPlayer *p, Channel *c, uint8 effect) {
+ uint8 arg = kEffectByteLength[effect - 0xe0] ? p->ram[c->pattern_order_ptr_for_chan++] : 0;
+
+ switch (effect) {
+ case 0xe0:
+ Channel_SetInstrument(p, c, arg);
+ break;
+ case 0xe1:
+ c->pan_flag_with_phase_invert = arg;
+ c->pan_value = (arg & 0x1f) << 8;
+ break;
+ case 0xe2:
+ c->pan_num_ticks = arg;
+ c->pan_target_value = p->ram[c->pattern_order_ptr_for_chan++];
+ c->pan_add_per_tick = SpcDivHelper(c->pan_target_value - (c->pan_value >> 8), arg);
+ break;
+ case 0xe3: // vibrato on
+ c->vibrato_delay_ticks = arg;
+ c->vibrato_rate = p->ram[c->pattern_order_ptr_for_chan++];
+ c->vibrato_depth_target = c->vib_depth = p->ram[c->pattern_order_ptr_for_chan++];
+ c->vibrato_fade_num_ticks = 0;
+ break;
+ case 0xe4: // vibrato off
+ c->vibrato_depth_target = c->vib_depth = 0;
+ c->vibrato_fade_num_ticks = 0;
+ break;
+ case 0xe5:
+ if (!p->pause_music_ctr && !p->byte_3E1)
+ p->master_volume = arg << 8;
+ break;
+ case 0xe6:
+ p->master_volume_fade_ticks = arg;
+ p->master_volume_fade_target = p->ram[c->pattern_order_ptr_for_chan++];
+ p->master_volume_fade_add_per_tick = SpcDivHelper(p->master_volume_fade_target - (p->master_volume >> 8), arg);
+ break;
+ case 0xe7:
+ p->tempo = arg << 8;
+ break;
+ case 0xe8:
+ p->tempo_fade_num_ticks = arg;
+ p->tempo_fade_final = p->ram[c->pattern_order_ptr_for_chan++];
+ p->tempo_fade_add = SpcDivHelper(p->tempo_fade_final - (p->tempo >> 8), arg);
+ break;
+ case 0xe9:
+ p->global_transposition = arg;
+ break;
+ case 0xea:
+ c->channel_transposition = arg;
+ break;
+ case 0xeb:
+ c->tremolo_delay_ticks = arg;
+ c->tremolo_rate = p->ram[c->pattern_order_ptr_for_chan++];
+ c->tremolo_depth = p->ram[c->pattern_order_ptr_for_chan++];
+ break;
+ case 0xec:
+ c->tremolo_depth = 0;
+ break;
+ case 0xed:
+ c->channel_volume = arg << 8;
+ break;
+ case 0xee:
+ c->volume_fade_ticks = arg;
+ c->volume_fade_target = p->ram[c->pattern_order_ptr_for_chan++];
+ c->volume_fade_addpertick = SpcDivHelper(c->volume_fade_target - (c->channel_volume >> 8), arg);
+ break;
+ case 0xef:
+ c->pattern_start_ptr = p->ram[c->pattern_order_ptr_for_chan++] << 8 | arg;
+ c->subroutine_num_loops = p->ram[c->pattern_order_ptr_for_chan++];
+ c->saved_pattern_ptr = c->pattern_order_ptr_for_chan;
+ c->pattern_order_ptr_for_chan = c->pattern_start_ptr;
+ break;
+ case 0xf0:
+ c->vibrato_fade_num_ticks = arg;
+ c->vibrato_fade_add_per_tick = arg ? c->vib_depth / arg : 0xff;
+ break;
+ case 0xf4:
+ c->fine_tune = arg;
+ break;
+ case 0xf5:
+ p->reg_EON = p->echo_channels = arg;
+ p->echo_volume_left = p->ram[c->pattern_order_ptr_for_chan++] << 8;
+ p->echo_volume_right = p->ram[c->pattern_order_ptr_for_chan++] << 8;
+ p->reg_FLG &= ~0x20;
+ break;
+ case 0xf6: // echo off
+ p->echo_volume_left = 0;
+ p->echo_volume_right = 0;
+ p->reg_FLG |= 0x20;
+ break;
+ case 0xf7: {
+ static const int8_t kEchoFirParameters[] = {
+ 127, 0, 0, 0, 0, 0, 0, 0,
+ 88, -65, -37, -16, -2, 7, 12, 12,
+ 12, 33, 43, 43, 19, -2, -13, -7,
+ 52, 51, 0, -39, -27, 1, -4, -21,
+ };
+ SetupEchoParameter_EDL(p, arg);
+ p->reg_EFB = p->ram[c->pattern_order_ptr_for_chan++];
+ const int8_t *ep = kEchoFirParameters + p->ram[c->pattern_order_ptr_for_chan++] * 8;
+ for (int i = 0; i < 8; i++)
+ Dsp_Write(p, FIR0 + i * 16, *ep++);
+ break;
+ }
+ case 0xf8:
+ p->echo_volume_fade_ticks = arg;
+ p->echo_volume_fade_target_left = p->ram[c->pattern_order_ptr_for_chan++];
+ p->echo_volume_fade_target_right = p->ram[c->pattern_order_ptr_for_chan++];
+ p->echo_volume_fade_add_left = SpcDivHelper(p->echo_volume_fade_target_left - (p->echo_volume_left >> 8), arg);
+ p->echo_volume_fade_add_right = SpcDivHelper(p->echo_volume_fade_target_right - (p->echo_volume_right >> 8), arg);
+ break;
+ case 0xf9:
+ c->pitch_slide_delay_left = arg;
+ c->pitch_slide_length = p->ram[c->pattern_order_ptr_for_chan++];
+ ComputePitchAdd(c, p->ram[c->pattern_order_ptr_for_chan++] + p->global_transposition + c->channel_transposition);
+ break;
+ case 0xfa:
+ p->percussion_base_id = arg;
+ break;
+ default:
+ Not_Implemented();
+ }
+}
+
+static bool WantWriteKof(SpcPlayer *p, Channel *c) {
+ int loops = c->subroutine_num_loops;
+ int ptr = c->pattern_order_ptr_for_chan;
+
+ for (;;) {
+ uint8 cmd = p->ram[ptr++];
+ if (cmd == 0) {
+ if (loops == 0)
+ return true;
+ ptr = (--loops == 0) ? c->saved_pattern_ptr : c->pattern_start_ptr;
+ } else {
+ while (!(cmd & 0x80))
+ cmd = p->ram[ptr++];
+ if (cmd == 0xc8)
+ return false;
+ if (cmd == 0xef) {
+ ptr = p->ram[ptr + 0] | p->ram[ptr + 1] << 8;
+ } else if (cmd >= 0xe0) {
+ ptr += kEffectByteLength[cmd - 0xe0];
+ } else {
+ return true;
+ }
+ }
+ }
+}
+
+static void HandleTremolo(SpcPlayer *p, Channel *c) {
+ Not_Implemented();
+}
+
+static void CalcVibratoAddPitch(SpcPlayer *p, Channel *c, uint16 pitch, uint8 value) {
+ int t = value << 2;
+ t ^= (t & 0x100) ? 0xff : 0;
+ int r = (c->vib_depth >= 0xf1) ?
+ (uint8)t * (c->vib_depth & 0xf) :
+ (uint8)t * c->vib_depth >> 8;
+ WritePitch(p, c, pitch + (value & 0x80 ? -r : r));
+}
+
+static void HandlePanAndSweep(SpcPlayer *p, Channel *c) {
+ p->did_affect_volumepitch_flag = 0;
+ if (c->tremolo_depth) {
+ c->tremolo_hold_count = c->tremolo_delay_ticks;
+ HandleTremolo(p, c);
+ }
+
+ uint16 volume = c->pan_value;
+
+ if (c->pan_num_ticks) {
+ p->did_affect_volumepitch_flag = 0x80;
+ volume += p->main_tempo_accum * (int16_t)c->pan_add_per_tick / 256;
+ }
+
+ if (p->did_affect_volumepitch_flag)
+ WriteVolumeToDsp(p, c, volume);
+
+ p->did_affect_volumepitch_flag = 0;
+ uint16 pitch = c->pitch;
+ if (c->pitch_slide_length && !c->pitch_slide_delay_left) {
+ p->did_affect_volumepitch_flag |= 0x80;
+ pitch += p->main_tempo_accum * (int16_t)c->pitch_add_per_tick / 256;
+ }
+
+ if (c->vib_depth && c->vibrato_delay_ticks == c->vibrato_hold_count) {
+ CalcVibratoAddPitch(p, c, pitch, (p->main_tempo_accum * c->vibrato_rate >> 8) + c->vibrato_count);
+ return;
+ }
+
+ if (p->did_affect_volumepitch_flag)
+ WritePitch(p, c, pitch);
+}
+
+static void HandleNoteTick(SpcPlayer *p, Channel *c) {
+ if (c->note_keyoff_ticks_left != 0 && (--c->note_keyoff_ticks_left == 0 || c->note_ticks_left == 2)) {
+ if (WantWriteKof(p, c) && !(p->cur_chan_bit & p->is_chan_on))
+ Dsp_Write(p, KOF, p->cur_chan_bit);
+ }
+
+ p->did_affect_volumepitch_flag = 0;
+ if (c->pitch_slide_length) {
+ if (c->pitch_slide_delay_left) {
+ c->pitch_slide_delay_left--;
+ } else if (!(p->is_chan_on & p->cur_chan_bit)) {
+ p->did_affect_volumepitch_flag = 0x80;
+ Chan_DoAnyFade(&c->pitch, c->pitch_add_per_tick, c->pitch_target, --c->pitch_slide_length);
+ }
+ }
+
+ uint16 pitch = c->pitch;
+
+ if (c->vib_depth) {
+ if (c->vibrato_delay_ticks == c->vibrato_hold_count) {
+ if (c->vibrato_change_count == c->vibrato_fade_num_ticks) {
+ c->vib_depth = c->vibrato_depth_target;
+ } else {
+ c->vib_depth = (c->vibrato_change_count++ == 0 ? 0 : c->vib_depth) + c->vibrato_fade_add_per_tick;
+ }
+ c->vibrato_count += c->vibrato_rate;
+ CalcVibratoAddPitch(p, c, pitch, c->vibrato_count);
+ return;
+ }
+ c->vibrato_hold_count++;
+ }
+
+ if (p->did_affect_volumepitch_flag)
+ WritePitch(p, c, pitch);
+}
+
+void CalcFinalVolume(SpcPlayer *p, Channel *c, uint8 vol) {
+ int t = (p->master_volume >> 8) * vol >> 8;
+ t = t * c->channel_volume_master >> 8;
+ t = t * (c->channel_volume >> 8) >> 8;
+ c->final_volume = t * t >> 8;
+}
+
+void CalcTremolo(SpcPlayer *p, Channel *c) {
+ Not_Implemented();
+}
+
+static void Chan_HandleTick(SpcPlayer *p, Channel *c) {
+ if (c->volume_fade_ticks) {
+ c->volume_fade_ticks--;
+ p->vol_dirty |= p->cur_chan_bit;
+ Chan_DoAnyFade(&c->channel_volume, c->volume_fade_addpertick, c->volume_fade_target, true);
+ }
+ if (c->tremolo_depth) {
+ if (c->tremolo_delay_ticks == c->tremolo_hold_count) {
+ p->vol_dirty |= p->cur_chan_bit;
+ if (c->tremolo_count & 0x80 && c->tremolo_depth == 0xff) {
+ c->tremolo_count = 0x80;
+ } else {
+ c->tremolo_count += c->tremolo_rate;
+ }
+ CalcTremolo(p, c);
+ } else {
+ c->tremolo_hold_count++;
+ CalcFinalVolume(p, c, 0xff);
+ }
+ } else {
+ CalcFinalVolume(p, c, 0xff);
+ }
+
+ if (c->pan_num_ticks) {
+ c->pan_num_ticks--;
+ p->vol_dirty |= p->cur_chan_bit;
+ Chan_DoAnyFade(&c->pan_value, c->pan_add_per_tick, c->pan_target_value, true);
+ }
+
+ if (p->vol_dirty & p->cur_chan_bit)
+ WriteVolumeToDsp(p, c, c->pan_value);
+}
+
+static void Port0_HandleMusic(SpcPlayer *p) {
+ Channel *c;
+ uint8 a = p->new_value_from_snes[0];
+ int t;
+
+ if (a == 0) {
+handle_cmd_00:
+ if (p->port_to_snes[0] == 0)
+ return;
+ if (p->pause_music_ctr != 0 && --p->pause_music_ctr == 0)
+ goto HandleCmd_0xf0_PauseMusic;
+ if (p->counter_sf0c == 0)
+ goto label_a;
+ if (--p->counter_sf0c != 0) {
+ Music_ResetChan(p);
+ return;
+ }
+next_phrase:
+ for (;;) {
+ t = WORD(p->ram[p->music_ptr_toplevel]);
+ p->music_ptr_toplevel += 2;
+ if ((t >> 8) != 0)
+ break;
+ if (t == 0)
+ goto HandleCmd_0xf0_PauseMusic;
+ if (t == 0x80) {
+ p->fast_forward = 0x80;
+ } else if (t == 0x81) {
+ p->fast_forward = 0;
+ } else {
+ if (sign8(--p->block_count))
+ p->block_count = t;
+ t = WORD(p->ram[p->music_ptr_toplevel]);
+ p->music_ptr_toplevel += 2;
+ if (p->block_count != 0)
+ p->music_ptr_toplevel = t;
+ }
+ }
+ for (int i = 0; i < 8; i++)
+ p->channel[i].pattern_order_ptr_for_chan = WORD(p->ram[t]), t += 2;
+
+ c = p->channel, p->cur_chan_bit = 1;
+ do {
+ if (HIBYTE(c->pattern_order_ptr_for_chan) && c->instrument_id == 0)
+ Channel_SetInstrument(p, c, 0);
+ c->subroutine_num_loops = 0;
+ c->volume_fade_ticks = 0;
+ c->pan_num_ticks = 0;
+ c->note_ticks_left = 1;
+ } while (c++, p->cur_chan_bit <<= 1);
+label_a:
+ p->vol_dirty = 0;
+ c = p->channel, p->cur_chan_bit = 1;
+ do {
+ if (!HIBYTE(c->pattern_order_ptr_for_chan))
+ continue;
+ if (!--c->note_ticks_left) {
+ for (;;) {
+ uint8 cmd = p->ram[c->pattern_order_ptr_for_chan++];
+ if (cmd == 0) {
+ if (!c->subroutine_num_loops)
+ goto next_phrase;
+ c->pattern_order_ptr_for_chan = (--c->subroutine_num_loops == 0) ? c->saved_pattern_ptr : c->pattern_start_ptr;
+ continue;
+ }
+ if (!(cmd & 0x80)) {
+ static const uint8 kNoteVol[16] = { 25, 50, 76, 101, 114, 127, 140, 152, 165, 178, 191, 203, 216, 229, 242, 252 };
+ static const uint8 kNoteGateOffPct[8] = { 50, 101, 127, 152, 178, 203, 229, 252 };
+ c->note_length = cmd;
+ cmd = p->ram[c->pattern_order_ptr_for_chan++];
+ if (!(cmd & 0x80)) {
+ c->note_gate_off_fixedpt = kNoteGateOffPct[cmd >> 4 & 7];
+ c->channel_volume_master = kNoteVol[cmd & 0xf];
+ cmd = p->ram[c->pattern_order_ptr_for_chan++];
+ }
+ }
+ if (cmd >= 0xe0) {
+ HandleEffect(p, c, cmd);
+ continue;
+ }
+ if (!p->fast_forward && !(p->is_chan_on & p->cur_chan_bit))
+ PlayNote(p, c, cmd);
+ c->note_ticks_left = c->note_length;
+ t = c->note_ticks_left * c->note_gate_off_fixedpt >> 8;
+ c->note_keyoff_ticks_left = (t != 0) ? t : 1;
+ PitchSlideToNote_Check(p, c);
+ break;
+ }
+ } else if (!p->fast_forward) {
+ HandleNoteTick(p, c);
+ PitchSlideToNote_Check(p, c);
+ }
+ } while (c++, p->cur_chan_bit <<= 1);
+ if (p->tempo_fade_num_ticks)
+ p->tempo = (--p->tempo_fade_num_ticks == 0) ? p->tempo_fade_final << 8 : p->tempo + p->tempo_fade_add;
+ if (p->echo_volume_fade_ticks) {
+ p->echo_volume_left += p->echo_volume_fade_add_left;
+ p->echo_volume_right += p->echo_volume_fade_add_right;
+ if (--p->echo_volume_fade_ticks == 0) {
+ p->echo_volume_left = p->echo_volume_fade_target_left << 8;
+ p->echo_volume_right = p->echo_volume_fade_target_right << 8;
+ }
+ }
+ if (p->master_volume_fade_ticks) {
+ p->master_volume = (--p->master_volume_fade_ticks == 0) ? p->master_volume_fade_target << 8 : p->master_volume + p->master_volume_fade_add_per_tick;
+ p->vol_dirty = 0xff;
+ }
+ c = p->channel, p->cur_chan_bit = 1;
+ do {
+ if (HIBYTE(c->pattern_order_ptr_for_chan))
+ Chan_HandleTick(p, c);
+ } while (c++, p->cur_chan_bit <<= 1);
+ } else if (a == 0xff) {
+ // Load new music
+ Not_Implemented();
+ } else if (a == 0xf1) { // continue music
+ p->master_volume_fade_ticks = 0x80;
+ p->pause_music_ctr = 0x80;
+ p->master_volume_fade_target = 0;
+ p->master_volume_fade_add_per_tick = SpcDivHelper(0 - (p->master_volume >> 8), 0x80);
+
+ goto handle_cmd_00;
+ } else if (a == 0xf2) {
+ if (p->byte_3E1 != 0)
+ return;
+ p->byte_3E1 = HIBYTE(p->master_volume);
+ HIBYTE(p->master_volume) = 0x70;
+ goto handle_cmd_00;
+ } else if (a == 0xf3) {
+ if (p->byte_3E1 == 0)
+ return;
+ HIBYTE(p->master_volume) = p->byte_3E1;
+ p->byte_3E1 = 0;
+ goto handle_cmd_00;
+ } else if (a == 0xf0) {
+HandleCmd_0xf0_PauseMusic:
+ p->key_OFF = p->is_chan_on ^ 0xff;
+ p->port_to_snes[0] = 0;
+ p->cur_chan_bit = 0;
+ } else {
+ p->pause_music_ctr = 0;
+ p->byte_3E1 = 0;
+ p->port_to_snes[0] = a;
+ p->music_ptr_toplevel = WORD(p->ram[0xD000 + (a - 1) * 2]);
+ p->counter_sf0c = 2;
+ p->key_OFF |= p->is_chan_on ^ 0xff;
+ }
+
+}
+
+static inline uint8 Asl(uint8 *p) {
+ uint8 old = *p;
+ *p <<= 1;
+ return old >> 7;
+}
+
+static void Sfx_TurnOffChannel(SpcPlayer *p, Channel *c) {
+ c->sfx_which_sound = 0;
+ p->is_chan_on &= ~p->current_bit;
+ p->port1_active &= ~p->current_bit;
+ p->port2_active &= ~p->current_bit;
+ p->port3_active &= ~p->current_bit;
+ Channel_SetInstrument(p, c, c->instrument_id);
+ if (p->echo_channels & p->current_bit && !(p->reg_EON & p->current_bit)) {
+ p->reg_EON |= p->current_bit;
+ Dsp_Write(p, EON, p->reg_EON);
+ p->sfx_channels_echo_mask2 &= ~p->current_bit;
+ }
+}
+
+static void Write_KeyOn(SpcPlayer *p, uint8 bit) {
+ Dsp_Write(p, KOF, 0);
+ Dsp_Write(p, KON, bit);
+}
+
+static void PlayNote(SpcPlayer *p, Channel *c, uint8 note) {
+ if (note >= 0xca) {
+ Channel_SetInstrument(p, c, note);
+ note = 0xa4;
+ }
+
+// if (c->index == 0) {
+// if (note == 0xc8) {
+// printf("-+-\n");
+// } else if (note == 0xc9) {
+// printf("---\n");
+// }
+// }
+
+ if (note >= 0xc8 || p->is_chan_on & p->cur_chan_bit)
+ return;
+
+ static const char *const kNoteNames[] = { "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" };
+ //if (c->index==0)
+ // printf("%s%d\n", kNoteNames[(note & 0x7f) % 12], (note & 0x7f) / 12 + 1);
+
+ c->pitch = ((note & 0x7f) + p->global_transposition + c->channel_transposition) << 8 | c->fine_tune;
+ c->vibrato_count = c->vibrato_fade_num_ticks << 7;
+ c->vibrato_hold_count = 0;
+ c->vibrato_change_count = 0;
+ c->tremolo_count = 0;
+ c->tremolo_hold_count = 0;
+ p->vol_dirty |= p->cur_chan_bit;
+ p->key_ON |= p->cur_chan_bit;
+ c->pitch_slide_length = c->pitch_envelope_num_ticks;
+ if (c->pitch_slide_length) {
+ c->pitch_slide_delay_left = c->pitch_envelope_delay;
+ if (!c->pitch_envelope_direction)
+ c->pitch -= c->pitch_envelope_slide_value << 8;
+ ComputePitchAdd(c, (c->pitch >> 8) + c->pitch_envelope_slide_value);
+ }
+ WritePitch(p, c, c->pitch);
+}
+
+static void Sfx_MaybeDisableEcho(SpcPlayer *p) {
+ if (!(p->port_to_snes[0] & 0x10) || p->current_bit & p->sfx_channels_echo_mask2) {
+ if (p->current_bit & p->reg_EON) {
+ p->reg_EON ^= p->current_bit;
+ Dsp_Write(p, EON, p->reg_EON);
+ }
+ }
+}
+
+static void Sfx_ChannelTick(SpcPlayer *p, Channel *c, bool is_continue) {
+ uint8 cmd;
+
+ if (is_continue) {
+ Sfx_MaybeDisableEcho(p);
+ p->sfx_channel_index = c->index * 2;
+ p->sfx_sound_ptr_cur = c->sfx_sound_ptr;
+ if (--c->sfx_note_length_left)
+ goto note_continue;
+ p->sfx_sound_ptr_cur++;
+ }
+
+ for (;;) {
+ p->dsp_register_index = p->sfx_channel_index * 8;
+
+ cmd = p->ram[p->sfx_sound_ptr_cur];
+ if (cmd == 0) {
+ Sfx_TurnOffChannel(p, c);
+ return;
+ }
+
+ if (!(cmd & 0x80)) {
+ c->sfx_note_length = cmd;
+ cmd = p->ram[++p->sfx_sound_ptr_cur];
+ if (!(cmd & 0x80)) {
+ if (p->port1_active & p->current_bit) {
+ if (cmd == 0 || !p->channel_67_volume) {
+ uint8 volume = cmd;
+ Dsp_Write(p, p->dsp_register_index + V0VOLL, cmd);
+ cmd = p->ram[++p->sfx_sound_ptr_cur];
+ if (cmd & 0x80) {
+ Dsp_Write(p, p->dsp_register_index + V0VOLR, volume);
+ } else {
+ Dsp_Write(p, p->dsp_register_index + V0VOLR, cmd);
+ cmd = p->ram[++p->sfx_sound_ptr_cur];
+ }
+ } else {
+ cmd = p->ram[++p->sfx_sound_ptr_cur];
+ }
+ } else {
+ c->final_volume = cmd * 2;
+ c->pan_flag_with_phase_invert = 10;
+ WriteVolumeToDsp(p, c, (p->sfx_start_arg_pan & 0x80 ? 16 : p->sfx_start_arg_pan & 0x40 ? 4 : 10) << 8);
+ cmd = p->ram[++p->sfx_sound_ptr_cur];
+ }
+ }
+ }
+ // cmd_parsed
+ if (cmd == 0xe0) {
+ const uint8 *ip = p->ram + 0x3E00 + (p->ram[++p->sfx_sound_ptr_cur] * 9);
+ uint8 reg = c->index * 16;
+ Dsp_Write(p, reg + V0VOLL, ip[0]);
+ Dsp_Write(p, reg + V0VOLR, ip[1]);
+ Dsp_Write(p, reg + V0PITCHL, ip[2]);
+ Dsp_Write(p, reg + V0PITCHH, ip[3]);
+ Dsp_Write(p, reg + V0SRCN, ip[4]);
+ Dsp_Write(p, reg + V0ADSR1, ip[5]);
+ Dsp_Write(p, reg + V0ADSR2, ip[6]);
+ Dsp_Write(p, reg + V0GAIN, ip[7]);
+ c->instrument_pitch_base = ip[8] << 8;
+ p->sfx_sound_ptr_cur++;
+ } else if (cmd == 0xf9 || cmd == 0xf1) {
+ if (cmd == 0xf9) {
+ PlayNote(p, c, p->ram[++p->sfx_sound_ptr_cur]);
+ Write_KeyOn(p, p->current_bit);
+ }
+ c->pitch_slide_delay_left = p->ram[++p->sfx_sound_ptr_cur];
+ c->pitch_slide_length = p->ram[++p->sfx_sound_ptr_cur];
+ ComputePitchAdd(c, p->ram[++p->sfx_sound_ptr_cur]);
+ c->sfx_note_length_left = c->sfx_note_length;
+ goto note_continue;
+ } else if (cmd == 0xff) {
+ p->sfx_sound_ptr_cur = c->sfx_sound_ptr = WORD(p->ram[0x17C0 + (c->sfx_which_sound - 1) * 2]);
+ } else {
+ PlayNote(p, c, cmd);
+ Write_KeyOn(p, p->current_bit);
+ c->sfx_note_length_left = c->sfx_note_length;
+note_continue:
+ p->did_affect_volumepitch_flag = 0;
+ if (c->pitch_slide_length) {
+ p->did_affect_volumepitch_flag = 0x80;
+ Chan_DoAnyFade(&c->pitch, c->pitch_add_per_tick, c->pitch_target, --c->pitch_slide_length);
+ p->cur_chan_bit = 0; // force change through
+ WritePitch(p, c, c->pitch);
+ } else if (c->sfx_note_length_left == 2) {
+ Dsp_Write(p, KOF, p->current_bit);
+ }
+ break;
+ }
+ }
+ c->sfx_sound_ptr = p->sfx_sound_ptr_cur;
+}
+
+static void Port1_Play_Inner(SpcPlayer *p) {
+ p->port1_counter = 0;
+ Channel *c = &p->channel[7];
+ c->sfx_which_sound = p->new_value_from_snes[1];
+ c->sfx_arr_countdown = 3;
+ c->pitch_envelope_num_ticks = 0;
+ p->port1_active = 0x80;
+ p->is_chan_on |= 0x80;
+ Dsp_Write(p, KOF, 0x80);
+ p->new_value_from_snes[1] = p->ram[0x1800 + p->new_value_from_snes[1] - 1];
+ if (!p->new_value_from_snes[1])
+ return;
+ c--;
+ c->sfx_which_sound = p->new_value_from_snes[1];
+ c->sfx_arr_countdown = 3;
+ c->pitch_envelope_num_ticks = 0;
+ p->port1_active = 0x40;
+ p->is_chan_on |= 0x40;
+ Dsp_Write(p, KOF, 0x40);
+ p->port1_active = 0xc0;
+ p->sfx_channels_echo_mask2 |= 0xc0;
+ p->port2_active &= 0x3f;
+ p->port3_active &= 0x3f;
+}
+
+static void Port1_StartNewSound(SpcPlayer *p) {
+ if (p->port1_counter != 0) {
+ if (--p->port1_counter == 0) {
+ p->new_value_from_snes[1] = 5;
+ Port1_Play_Inner(p);
+ p->new_value_from_snes[1] = 0;
+ return;
+ }
+ p->channel_67_volume = p->port1_counter >> 1;
+ Dsp_Write(p, V7VOLL, p->channel_67_volume);
+ Dsp_Write(p, V7VOLR, p->channel_67_volume);
+ Dsp_Write(p, V6VOLL, p->channel_67_volume);
+ Dsp_Write(p, V6VOLR, p->channel_67_volume);
+ }
+ p->port1_current_bit = p->port1_active;
+ if (!p->port1_current_bit)
+ return;
+ Channel *c = &p->channel[7];
+ p->current_bit = 0x80;
+ do {
+ if (Asl(&p->port1_current_bit)) {
+ p->sfx_channel_index = c->index * 2;
+ p->dsp_register_index = c->index * 16;
+ p->sfx_start_arg_pan = c->sfx_pan;
+ if (!c->sfx_arr_countdown) {
+ if (c->sfx_which_sound)
+ Sfx_ChannelTick(p, c, true);
+ } else {
+ p->sfx_channel_index = c->index * 2;
+ if (!--c->sfx_arr_countdown) {
+ p->sfx_sound_ptr_cur = c->sfx_sound_ptr = WORD(p->ram[0x17C0 + (c->sfx_which_sound - 1) * 2]);
+ Sfx_ChannelTick(p, c, false);
+ }
+ }
+ }
+ } while (c--, (p->current_bit >>= 1) != 0x10);
+}
+
+static void Port1_HandleCmd(SpcPlayer *p) {
+ uint8 a = p->new_value_from_snes[1];
+ if (!(a & 0x80)) {
+ if (a != 0) {
+ p->port_to_snes[1] = a;
+ if (a != 5 || p->port1_active)
+ Port1_Play_Inner(p);
+ }
+ } else {
+ p->port_to_snes[1] = a;
+ if (p->port1_active)
+ p->port1_counter = 0x78;
+ }
+}
+
+static void Port2_StartNewSound(SpcPlayer *p) {
+ p->port2_current_bit = p->port2_active;
+ if (!p->port2_current_bit)
+ return;
+ Channel *c = &p->channel[7];
+ p->current_bit = 0x80;
+ do {
+ if (Asl(&p->port2_current_bit)) {
+ p->sfx_channel_index = c->index * 2;
+ p->dsp_register_index = c->index * 16;
+ p->sfx_start_arg_pan = c->sfx_pan;
+ if (!c->sfx_arr_countdown) {
+ if (c->sfx_which_sound)
+ Sfx_ChannelTick(p, c, true);
+ } else {
+ p->sfx_channel_index = c->index * 2;
+ if (!--c->sfx_arr_countdown) {
+ p->sfx_sound_ptr_cur = c->sfx_sound_ptr = WORD(p->ram[0x1820 + (c->sfx_which_sound - 1) * 2]);
+ Sfx_ChannelTick(p, c, false);
+ }
+ }
+ }
+ } while (c--, p->current_bit >>= 1);
+}
+
+static Channel *Port2_AllocateChan(SpcPlayer *p) {
+ p->sfx_play_echo_flag = p->ram[0x18dd + (p->new_value_from_snes[2] & 0x3f) - 1];
+ Channel *c = &p->channel[7];
+ p->current_bit = 0x80;
+ do {
+ if (p->port2_active & p->current_bit && c->sfx_which_sound + c->sfx_pan == p->new_value_from_snes[2])
+ goto found_channel;
+ } while (c--, p->current_bit >>= 1);
+ c = &p->channel[7];
+ p->current_bit = 0x80;
+ do {
+ if (!(p->is_chan_on & p->current_bit))
+ goto found_channel;
+ } while (c--, p->current_bit >>= 1);
+ assert(0); // unreachable
+found_channel:
+ p->sfx_channel_index2 = p->sfx_channel_index = c->index * 2;
+ p->sfx_channel_bit = p->current_bit;
+ p->is_chan_on |= p->current_bit;
+ if (p->sfx_play_echo_flag)
+ p->sfx_channels_echo_mask2 |= p->current_bit;
+ Sfx_MaybeDisableEcho(p);
+ return c;
+}
+
+static void Port2_HandleCmd(SpcPlayer *p) {
+ while (p->new_value_from_snes[2] != 0 && p->is_chan_on != 0xff) {
+ Channel *c = Port2_AllocateChan(p);
+ c->sfx_pan = p->new_value_from_snes[2] & 0xc0;
+ c->sfx_which_sound = p->new_value_from_snes[2] & 0x3f;
+ c->sfx_arr_countdown = 3;
+ c->pitch_envelope_num_ticks = 0;
+ p->port2_active |= p->current_bit;
+ Dsp_Write(p, KOF, p->current_bit);
+ p->new_value_from_snes[2] = p->ram[0x189e + c->sfx_which_sound - 1];
+ }
+}
+
+
+static void Port3_StartNewSound(SpcPlayer *p) {
+ p->port3_current_bit = p->port3_active;
+ if (!p->port3_current_bit)
+ return;
+ Channel *c = &p->channel[7];
+ p->current_bit = 0x80;
+ do {
+ if (Asl(&p->port3_current_bit)) {
+ p->sfx_channel_index = c->index * 2;
+ p->dsp_register_index = c->index * 16;
+ p->sfx_start_arg_pan = c->sfx_pan;
+ if (!c->sfx_arr_countdown) {
+ if (c->sfx_which_sound)
+ Sfx_ChannelTick(p, c, true);
+ } else {
+ p->sfx_channel_index = c->index * 2;
+ if (!--c->sfx_arr_countdown) {
+ p->sfx_sound_ptr_cur = c->sfx_sound_ptr = WORD(p->ram[0x191C + (c->sfx_which_sound - 1) * 2]);
+ Sfx_ChannelTick(p, c, false);
+ }
+ }
+ }
+ } while (c--, p->current_bit >>= 1);
+}
+
+static Channel *Port3_AllocateChan(SpcPlayer *p) {
+ p->sfx_play_echo_flag = p->ram[0x19d8 + (p->new_value_from_snes[3] & 0x3f)];
+ Channel *c = &p->channel[7];
+ p->current_bit = 0x80;
+ do {
+ if (p->port3_active & p->current_bit && c->sfx_which_sound + c->sfx_pan == p->new_value_from_snes[3])
+ goto found_channel;
+ } while (c--, p->current_bit >>= 1);
+ c = &p->channel[7];
+ p->current_bit = 0x80;
+ do {
+ if (!(p->is_chan_on & p->current_bit))
+ goto found_channel;
+ } while (c--, p->current_bit >>= 1);
+ assert(0); // unreachable
+found_channel:
+ p->sfx_channel_index2 = p->sfx_channel_index = c->index * 2;
+ p->sfx_channel_bit = p->current_bit;
+ p->is_chan_on |= p->current_bit;
+ if (p->sfx_play_echo_flag)
+ p->sfx_channels_echo_mask2 |= p->current_bit;
+ Sfx_MaybeDisableEcho(p);
+ return c;
+}
+
+static void Port3_HandleCmd(SpcPlayer *p) {
+ while (p->new_value_from_snes[3] != 0 && p->is_chan_on != 0xff) {
+ Channel *c = Port3_AllocateChan(p);
+ c->sfx_pan = p->new_value_from_snes[3] & 0xc0;
+ c->sfx_which_sound = p->new_value_from_snes[3] & 0x3f;
+ c->sfx_arr_countdown = 3;
+ c->pitch_envelope_num_ticks = 0;
+ p->port3_active |= p->current_bit;
+ Dsp_Write(p, KOF, p->current_bit);
+ p->new_value_from_snes[3] = p->ram[0x199a + c->sfx_which_sound - 1];
+ }
+}
+
+static void ReadPortFromSnes(SpcPlayer *p, int port) {
+ uint8 old = p->last_value_from_snes[port];
+ p->last_value_from_snes[port] = p->input_ports[port];
+ if (p->input_ports[port] != old)
+ p->new_value_from_snes[port] = p->input_ports[port];
+ else
+ p->new_value_from_snes[port] = 0;
+}
+
+static void Spc_Loop_Part1(SpcPlayer *p) {
+ 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 MemMapSized *m = &kSpcPlayer_Maps[0]; m != &kSpcPlayer_Maps[countof(kSpcPlayer_Maps)]; m++)
+ memcpy(&p->ram[m->org_off], (uint8 *)p + m->off, m->size);
+}
+
+void SpcPlayer_CopyVariablesFromRam(SpcPlayer *p) {
+ Channel *c = p->channel;
+ for (int i = 0; i < 8; i++, c++) {
+ for (const MemMap *m = &kChannel_Maps[0]; m != &kChannel_Maps[countof(kChannel_Maps)]; m++)
+ memcpy((uint8 *)c + m->off, &p->ram[(m->org_off & 0x7fff) + i * 2], m->org_off & 0x8000 ? 2 : 1);
+ }
+ for (const MemMapSized *m = &kSpcPlayer_Maps[0]; m != &kSpcPlayer_Maps[countof(kSpcPlayer_Maps)]; m++)
+ memcpy((uint8 *)p + m->off, &p->ram[m->org_off], m->size);
+}
+
+
+void SpcPlayer_GenerateSamples(SpcPlayer *p) {
+ assert(p->timer_cycles <= 64);
+
+ assert(p->dsp->sampleOffset <= 534);
+
+ for (;;) {
+ if (p->timer_cycles >= 64) {
+ Spc_Loop_Part2(p, p->timer_cycles >> 6);
+ Spc_Loop_Part1(p);
+ p->timer_cycles &= 63;
+ }
+
+ // sample rate 32000
+ int n = 534 - p->dsp->sampleOffset;
+ if (n > (64 - p->timer_cycles))
+ n = (64 - p->timer_cycles);
+
+ p->timer_cycles += n;
+
+ for (int i = 0; i < n; i++)
+ dsp_cycle(p->dsp);
+
+ if (p->dsp->sampleOffset == 534)
+ break;
+ }
+}
+
+void SpcPlayer_Upload(SpcPlayer *p, const uint8_t *data) {
+ Dsp_Write(p, EVOLL, 0);
+ Dsp_Write(p, EVOLR, 0);
+ Dsp_Write(p, KOF, 0xff);
+
+ for (;;) {
+ int numbytes = *(uint16 *)(data);
+ if (numbytes == 0)
+ break;
+ int target = *(uint16 *)(data + 2);
+ data += 4;
+ do {
+ p->ram[target++ & 0xffff] = *data++;
+ } while (--numbytes);
+ }
+ p->pause_music_ctr = 0;
+ p->port_to_snes[0] = 0;
+ p->port1_active = 0;
+ p->port2_active = 0;
+ p->port3_active = 0;
+ p->is_chan_on = 0;
+ p->input_ports[0] = p->input_ports[1] = p->input_ports[2] = p->input_ports[3] = 0;
+}
+
+// =======================================
+
+static DspRegWriteHistory my_write_hist;
+static SpcPlayer my_spc, my_spc_snapshot;
+static int loop_ctr;
+
+bool CompareSpcImpls(SpcPlayer *p, SpcPlayer *p_org, Apu *apu) {
+ SpcPlayer_CopyVariablesToRam(p);
+ memcpy(p->ram + 0x18, apu->ram + 0x18, 2); //lfsr_value
+ memcpy(p->ram + 0x110, apu->ram + 0x110, 256-16); // stack
+ memcpy(p->ram + 0xf1, apu->ram + 0xf1, 15); // dsp regs
+ memcpy(p->ram + 0x10, apu->ram + 0x10, 8); // temp regs
+ p->ram[0x44] = apu->ram[0x44]; // chn
+ int errs = 0;
+ for (int i = 0; i != 0xc000; i++) { // skip compare echo etc
+ if (p->ram[i] != apu->ram[i]) {
+ if (errs < 16) {
+ if (errs == 0)
+ printf("@%d\n", loop_ctr);
+ printf("%.4X: %.2X != %.2X (mine, theirs) orig %.2X\n", i, p->ram[i], apu->ram[i], p_org->ram[i]);
+ errs++;
+ }
+ }
+ }
+
+ int n = my_write_hist.count < apu->hist.count ? apu->hist.count : my_write_hist.count;
+ for (int i = 0; i != n; i++) {
+ if (i >= my_write_hist.count || i >= apu->hist.count || my_write_hist.addr[i] != apu->hist.addr[i] || my_write_hist.val[i] != apu->hist.val[i]) {
+ if (errs == 0)
+ printf("@%d\n", loop_ctr);
+ printf("%d: ", i);
+ if (i >= my_write_hist.count) printf("[??: ??]"); else printf("[%.2x: %.2x]", my_write_hist.addr[i], my_write_hist.val[i]);
+ printf(" != ");
+ if (i >= apu->hist.count) printf("[??: ??]"); else printf("[%.2x: %.2x]", apu->hist.addr[i], apu->hist.val[i]);
+ printf("\n");
+ errs++;
+ }
+ }
+
+ if (errs) {
+ printf("Total %d errors\n", errs);
+ return false;
+ }
+
+ apu->hist.count = 0;
+ my_write_hist.count = 0;
+ loop_ctr++;
+ return true;
+}
+
+void RunAudioPlayer() {
+ if(SDL_Init(SDL_INIT_AUDIO) != 0) {
+ printf("Failed to init SDL: %s\n", SDL_GetError());
+ return;
+ }
+
+ SDL_AudioSpec want, have;
+ SDL_AudioDeviceID device;
+ SDL_memset(&want, 0, sizeof(want));
+ want.freq = 44100;
+ want.format = AUDIO_S16;
+ want.channels = 2;
+ want.samples = 2048;
+ want.callback = NULL; // use queue
+ device = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
+ if(device == 0) {
+ printf("Failed to open audio device: %s\n", SDL_GetError());
+ return;
+ }
+ int16_t* audioBuffer = (int16_t*)malloc(735 * 4); // *2 for stereo, *2 for sizeof(int16)
+ SDL_PauseAudioDevice(device, 0);
+
+ memset(&my_spc, 0, sizeof(my_spc));
+ FILE *f = fopen("lightworld.spc", "rb");
+ fread(my_spc.ram, 1, 65536, f);
+ fclose(f);
+
+ my_spc.reg_write_history = &my_write_hist;
+
+ bool run_both = 0;// false;// false;
+
+ if (!run_both) {
+ SpcPlayer *p = &my_spc;
+ Dsp *dsp = dsp_init(p->ram);
+ dsp_reset(dsp);
+ p->dsp = dsp;
+ SpcPlayer_Initialize(p);
+
+ p->input_ports[0] = 4;
+
+ for (;;) {
+ SpcPlayer_GenerateSamples(p);
+
+ int16_t audioBuffer[736 * 2];
+ dsp_getSamples(p->dsp, audioBuffer, 736);
+ 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
--- a/spc_player.cpp
+++ /dev/null
@@ -1,1310 +1,0 @@
-#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
--- a/spc_player.h
+++ b/spc_player.h
@@ -1,8 +1,7 @@
#include <stddef.h>
-struct DspRegWriteHistory;
-struct Dsp;
+#include "snes/dsp.h"
-struct Channel {
+typedef struct Channel {
uint16 pattern_order_ptr_for_chan;
uint8 note_ticks_left;
uint8 note_keyoff_ticks_left;
@@ -56,8 +55,9 @@
uint8 sfx_note_length;
uint8 sfx_pan;
uint8 index;
-};
-struct SpcPlayer {
+} Channel;
+
+typedef struct SpcPlayer {
DspRegWriteHistory *reg_write_history;
uint8 timer_cycles;
Dsp *dsp;
@@ -135,139 +135,7 @@
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 *SpcPlayer_Create();
void SpcPlayer_GenerateSamples(SpcPlayer *p);
--- /dev/null
+++ b/sprite.c
@@ -1,0 +1,4404 @@
+#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);
+ }
+ uint8 type;
+flag4:
+ type = sprite_type[k];
+ sprite_F[k] = (damage_type_determiner >= 13) ? 0 :
+ (type == 9) ? 20 :
+ (type == 0x53 || type == 0x18) ? 11 : 15;
+}
+
+void Sprite_Func18(int k, uint8 new_type) { // 86edcb
+ sprite_type[k] = new_type;
+ SpritePrep_LoadProperties(k);
+ Sprite_SpawnPoofGarnish(k);
+ sound_effect_2 = 0;
+ SpriteSfx_QueueSfx3WithPan(k, 0x32);
+ sprite_hit_timer[k] = 0;
+ sprite_give_damage[k] = 0;
+}
+
+void Sprite_MiniMoldorm_Recoil(int k) { // 86eec8
+ if (sprite_state[k] < 9)
+ return;
+ tmp_counter = sprite_state[k];
+
+ uint8 dmg = sprite_give_damage[k];
+ if (dmg == 253) {
+ sprite_give_damage[k] = 0;
+ SpriteSfx_QueueSfx3WithPan(k, 9);
+ sprite_state[k] = 7;
+ sprite_delay_main[k] = 0x70;
+ sprite_flags2[k] += 2;
+ sprite_give_damage[k] = 0;
+ return;
+ }
+
+ if (dmg >= 251) {
+ sprite_give_damage[k] = 0;
+ if (sprite_state[k] == 11)
+ return;
+ sprite_unk5[k] = (dmg == 254);
+ if (sprite_unk5[k]) {
+ sprite_defl_bits[k] |= 8;
+ sprite_flags5[k] &= ~0x80;
+ SpriteSfx_QueueSfx2WithPan(k, 15);
+ sprite_z_vel[k] = 24;
+ sprite_bump_damage[k] &= ~0x80;
+ Sprite_ZeroVelocity_XY(k);
+ }
+ sprite_state[k] = 11;
+ sprite_delay_main[k] = 64;
+ static const uint8 kHitTimer24StunValues[5] = {0x20, 0x80, 0, 0, 0xff};
+ sprite_stunned[k] = kHitTimer24StunValues[(uint8)(dmg + 5)];
+ if (sprite_type[k] == 0x23)
+ sprite_type[k] = 0x24;
+ return;
+ }
+
+ int t = sprite_health[k] - sprite_give_damage[k];
+ sprite_health[k] = t;
+ sprite_give_damage[k] = 0;
+ if (t > 0)
+ return;
+
+ if (sprite_die_action[k] == 0) {
+ if (sprite_state[k] == 11)
+ sprite_die_action[k] = 3;
+ if (sprite_unk1[k] != 0) {
+ sprite_unk1[k] = 0;
+ sprite_flags5[k] = 0;
+ }
+ }
+
+ uint8 type = sprite_type[k];
+ if (type != 0x1b)
+ SpriteSfx_QueueSfx3WithPan(k, 9);
+
+ if (type == 0x40)
+ save_ow_event_info[BYTE(overworld_screen_index)] |= 0x40;
+ else if (type == 0xec) {
+ if (sprite_C[k] == 2)
+ ThrowableScenery_TransmuteToDebris(k);
+ return;
+ }
+
+ if (sprite_state[k] == 10) {
+ link_state_bits = 0;
+ link_picking_throw_state = 0;
+ }
+ sprite_state[k] = 6;
+
+ if (type == 0xc) {
+ Sprite_Func3(k);
+ } else if (type == 0x92) {
+ Sprite_KillFriends();
+ sprite_delay_main[k] = 255;
+ goto out_common;
+ } else if (type == 0xcb) {
+ sprite_ai_state[k] = 128;
+ sprite_delay_main[k] = 128;
+ sprite_state[k] = 9;
+ goto out_common;
+ } else if (type == 0xcc || type == 0xcd) {
+ sprite_ai_state[k] = 128;
+ sprite_delay_main[k] = 96;
+ sprite_state[k] = 9;
+ goto out_common;
+ } else if (type == 0x53) {
+ sprite_delay_main[k] = 35;
+ sprite_hit_timer[k] = 0;
+ goto out_common2;
+ } else if (type == 0x54) {
+ sprite_ai_state[k] = 5;
+ sprite_delay_main[k] = 0xc0;
+ sprite_hit_timer[k] = 0xc0;
+ goto out_common;
+ } else if (type == 0x9) {
+ sprite_ai_state[k] = 3;
+ sprite_delay_aux4[k] = 160;
+ sprite_state[k] = 9;
+ goto out_common;
+ } else if (type == 0x7a) {
+ Sprite_KillFriends();
+ sprite_state[k] = 9;
+ sprite_ignore_projectile[k] = 9;
+ if (is_in_dark_world == 0) {
+ sprite_ai_state[k] = 10;
+ sprite_delay_main[k] = 255;
+ sprite_z_vel[k] = 32;
+ } else {
+ sprite_delay_main[k] = 255;
+ sprite_ai_state[k] = 8;
+ sprite_ai_state[1] = 9;
+ sprite_ai_state[2] = 9;
+ sprite_graphics[1] = 0;
+ sprite_graphics[2] = 0;
+ }
+ goto out_common;
+ } else if (type == 0x23 && sprite_C[k] == 0) {
+ sprite_ai_state[k] = 2;
+ sprite_delay_main[k] = 32;
+ sprite_state[k] = 9;
+ sprite_hit_timer[k] = 0;
+ } else if (type == 0xf) {
+ sprite_hit_timer[k] = 0;
+ sprite_delay_main[k] = 15;
+ } else if (!(sprite_flags[k] & 2)) {
+ sprite_delay_main[k] = sprite_hit_timer[k] & 0x80 ? 31 : 15;
+ sprite_flags2[k] += 4;
+ if (tmp_counter == 11)
+ sprite_flags5[k] = 1;
+ } else {
+ if (type != 0xa2)
+ Sprite_KillFriends();
+ sprite_state[k] = 4;
+ sprite_A[k] = 0;
+ sprite_delay_main[k] = 255;
+ sprite_hit_timer[k] = 255;
+ out_common:
+ flag_block_link_menu++;
+ out_common2:
+ sound_effect_2 = 0;
+ SpriteSfx_QueueSfx3WithPan(k, 0x22);
+ }
+}
+
+void Sprite_Func3(int k) { // 86efda
+ sprite_state[k] = 6;
+ sprite_delay_main[k] = 31;
+ sprite_flags2[k] = 3;
+}
+
+bool Sprite_CheckDamageToLink(int k) { // 86f145
+ if (link_disable_sprite_damage)
+ return false;
+ return Sprite_CheckDamageToPlayer_1(k);
+}
+
+bool Sprite_CheckDamageToPlayer_1(int k) { // 86f14a
+ if ((k ^ frame_counter) & 3 | sprite_hit_timer[k])
+ return false;
+ return Sprite_CheckDamageToLink_same_layer(k);
+}
+
+bool Sprite_CheckDamageToLink_same_layer(int k) { // 86f154
+ if (link_is_on_lower_level != sprite_floor[k])
+ return false;
+ return Sprite_CheckDamageToLink_ignore_layer(k);
+}
+
+bool Sprite_CheckDamageToLink_ignore_layer(int k) { // 86f15c
+ uint8 carry, t;
+ if (sprite_flags4[k]) {
+ SpriteHitBox hitbox;
+ Link_SetupHitBox(&hitbox);
+ 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);
+}
+
--- a/sprite.cpp
+++ /dev/null
@@ -1,4403 +1,0 @@
-#include "sprite.h"
-#include "dungeon.h"
-#include "hud.h"
-#include "load_gfx.h"
-#include "overworld.h"
-#include "variables.h"
-#include "tagalong.h"
-#include "overlord.h"
-#include "ancilla.h"
-#include "player.h"
-#include "misc.h"
-#include "overlord.h"
-#include "tile_detect.h"
-#include "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);
-}
-
--- a/sprite.h
+++ b/sprite.h
@@ -3,13 +3,13 @@
#include "variables.h"
-struct PrepOamCoordsRet {
+typedef struct PrepOamCoordsRet {
uint16 x, y;
uint8 r4;
uint8 flags;
-};
+} PrepOamCoordsRet;
-struct SpriteHitBox {
+typedef struct SpriteHitBox {
uint8 r0_xlo;
uint8 r8_xhi;
uint8 r1_ylo;
@@ -23,25 +23,23 @@
uint8 r11_spr_yhi;
uint8 r6_spr_xsize;
uint8 r7_spr_ysize;
-};
+} SpriteHitBox;
-struct SpriteSpawnInfo {
+typedef struct SpriteSpawnInfo {
uint16 r0_x;
uint16 r2_y;
uint8 r4_z;
uint16 r5_overlord_x;
uint16 r7_overlord_y;
-};
+} SpriteSpawnInfo;
extern const uint8 kAbsorbBigKey[2];
-
-
-struct DrawMultipleData {
+typedef struct DrawMultipleData {
int8 x, y;
uint16 char_flags;
uint8 ext;
-};
+} DrawMultipleData;
--- /dev/null
+++ b/sprite_main.c
@@ -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);
+ int j;
+done:
+ j = ((sram_progress_flags ^= 0x40) & 0x40) != 0;
+ Sprite_ShowMessageUnconditional(kFortuneTeller_Readings[slots[j]]);
+}
+
+void FortuneTeller_Draw(int k) { // 8dcb01
+ static const DrawMultipleData kFortuneTeller_Dmd[12] = {
+ { 0, -48, 0x000c, 2},
+ { 0, -32, 0x002c, 0},
+ { 8, -32, 0x402c, 0},
+ { 0, -48, 0x000a, 2},
+ { 0, -32, 0x002a, 0},
+ { 8, -32, 0x402a, 0},
+ {-4, -40, 0x0066, 2},
+ { 4, -40, 0x4066, 2},
+ {-4, -40, 0x0066, 2},
+ {-4, -40, 0x0068, 2},
+ { 4, -40, 0x4068, 2},
+ {-4, -40, 0x0068, 2},
+ };
+ int j = (savegame_is_darkworld >> 6 & 1) * 2 + sprite_graphics[k];
+ Sprite_DrawMultiple(k, &kFortuneTeller_Dmd[j * 3], 3, NULL);
+}
+
+void Smithy_SpawnDumbBarrierSprite(int k) { // 8dcb2a
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamically(k, 0x31, &info);
+ if (j < 0)
+ return;
+ Sprite_SetX(j, info.r0_x);
+ Sprite_SetY(j, info.r2_y);
+ sprite_subtype2[j] = 1;
+ sprite_flags4[j] = 0;
+ sprite_ignore_projectile[j] = 1;
+}
+
+void Sprite_MazeGameLady(int k) { // 8dcb5c
+ Lady_Draw(k);
+ if (Sprite_ReturnIfInactive(k))
+ return;
+ Sprite_TrackBodyToHead(k);
+ sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+ switch (sprite_ai_state[k]) {
+ case 0: // startup
+ if (sprite_x_lo[k] < BYTE(link_x_coord)) {
+ int j = Sprite_ShowMessageOnContact(k, 0xcc);
+ if (j & 0x100) {
+ sprite_D[k] = sprite_head_dir[k] = (uint8)j;
+ sprite_ai_state[k] = 1;
+ word_7FFE00 = 0;
+ word_7FFE02 = 0;
+ sprite_A[k] = 0;
+ flag_overworld_area_did_change = 0;
+ }
+ } else {
+ Sprite_ShowMessageOnContact(k, 0xd0);
+ }
+ break;
+ case 1: // sound
+ SpriteSfx_QueueSfx3WithPan(k, 0x7);
+ sprite_ai_state[k] = 2;
+ break;
+ case 2: // accumulate time
+ if (++sprite_A[k] == 63) {
+ sprite_A[k] = 0;
+ word_7FFE00 += 1;
+ if (word_7FFE00 == 0)
+ word_7FFE02++;
+ }
+ break;
+ }
+}
+
+void Sprite_MazeGameGuy(int k) { // 8dcbf2
+ int j;
+ MazeGameGuy_Draw(k);
+ if (Sprite_ReturnIfInactive(k))
+ return;
+ Sprite_TrackBodyToHead(k);
+ sprite_head_dir[k] = 0;
+ Sprite_BehaveAsBarrier(k);
+ sprite_graphics[k] = frame_counter >> 3 & 1;
+ if (flag_overworld_area_did_change) {
+ Sprite_ShowMessageOnContact(k, 0xd0);
+ return;
+ }
+ switch (sprite_ai_state[k]) {
+ case 0: { // parse time
+ word_7FFE04 = word_7FFE00;
+ word_7FFE06 = word_7FFE02;
+ int t = word_7FFE04 % 6000;
+ int a = t / 600;
+ t %= 600;
+ int b = t / 60;
+ t %= 60;
+ int c = t / 10;
+ t %= 10;
+ 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);
+ static const uint8 kKyameron_Moving_Gfx[4] = {3, 2, 1, 0};
+skip_sound:
+ sprite_graphics[k] = kKyameron_Moving_Gfx[++sprite_subtype2[k] >> 3 & 3];
+ if (!((k ^ frame_counter) & 7)) {
+ uint16 x = (GetRandomNumber() & 0xf) - 4;
+ uint16 y = (GetRandomNumber() & 0xf) - 4;
+ Sprite_GarnishSpawn_Sparkle(k, x, y);
+ }
+ break;
+ }
+ case 4: // disperse
+ if (!sprite_delay_main[k]) {
+ sprite_anim_clock[k] = 0;
+ sprite_ai_state[k] = 0;
+ sprite_z[k] = 0;
+ sprite_delay_main[k] = 64;
+ } else {
+ sprite_graphics[k] = (sprite_delay_main[k] >> 2) + 15;
+ }
+ break;
+ }
+}
+
+void Kyameron_Draw(int k) { // 9ea158
+ static const uint8 kKyameron_OamFlags[12] = {0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0xc0, 0x80};
+ static const DrawMultipleData kKyameron_Dmd[28] = {
+ { 1, 8, 0x00b4, 0},
+ { 7, 8, 0x00b5, 0},
+ { 4, -3, 0x0086, 0},
+ { 0, -13, 0x80a2, 2},
+ { 2, 8, 0x00b4, 0},
+ { 6, 8, 0x00b5, 0},
+ { 4, -6, 0x0096, 0},
+ { 0, -20, 0x00a2, 2},
+ { 4, -1, 0x0096, 0},
+ { 0, -27, 0x00a2, 2},
+ { 0, -27, 0x00a2, 2},
+ { 0, -27, 0x00a2, 2},
+ {-6, -6, 0x01df, 0},
+ {14, -6, 0x41df, 0},
+ {-6, 14, 0x81df, 0},
+ {14, 14, 0xc1df, 0},
+ {-6, -6, 0x0096, 0},
+ {14, -6, 0x4096, 0},
+ {-6, 14, 0x8096, 0},
+ {14, 14, 0xc096, 0},
+ {-4, -4, 0x018d, 0},
+ {12, -4, 0x418d, 0},
+ {-4, 12, 0x818d, 0},
+ {12, 12, 0xc18d, 0},
+ { 0, 0, 0x018d, 0},
+ { 8, 0, 0x418d, 0},
+ { 0, 8, 0x818d, 0},
+ { 8, 8, 0xc18d, 0},
+ };
+ int j = sprite_graphics[k];
+ if (j < 12) {
+ uint8 bak = sprite_oam_flags[k];
+ sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kKyameron_OamFlags[j];
+ SpriteDraw_SingleLarge(k);
+ sprite_oam_flags[k] = bak;
+ } else {
+ Sprite_DrawMultiple(k, &kKyameron_Dmd[(j - 12) * 4], 4, NULL);
+ }
+}
+
+void Sprite_99_Pengator(int k) { // 9ea196
+ static const uint8 kPengator_Gfx[4] = {5, 0, 10, 15};
+ sprite_graphics[k] = sprite_A[k] + kPengator_Gfx[sprite_D[k]];
+ Pengator_Draw(k);
+ if (sprite_F[k] || sprite_wallcoll[k] & 15) {
+ sprite_ai_state[k] = 0;
+ sprite_x_vel[k] = 0;
+ sprite_y_vel[k] = 0;
+ }
+ if (Sprite_ReturnIfInactive(k))
+ return;
+ if (Sprite_ReturnIfRecoiling(k))
+ return;
+ Sprite_CheckDamageToAndFromLink(k);
+ Sprite_MoveXYZ(k);
+ sprite_z_vel[k] -= 2;
+ if (sign8(sprite_z[k])) {
+ sprite_z_vel[k] = 0;
+ sprite_z[k] = 0;
+ }
+ Sprite_CheckTileCollision(k);
+ switch(sprite_ai_state[k]) {
+ case 0: // face player
+ sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+ sprite_ai_state[k] = 1;
+ break;
+ case 1: // speedup
+ if (!((k ^ frame_counter) & 3)) {
+ static const int8 kPengator_XYVel[6] = { 1, -1, 0, 0, 1, -1 };
+ bool flag = false;
+ int j = sprite_D[k];
+ if (sprite_x_vel[k] != (uint8)kFluteBoyAnimal_Xvel[j])
+ sprite_x_vel[k] += kPengator_XYVel[j], flag = true;
+ if (sprite_y_vel[k] != (uint8)kZazak_Yvel[j])
+ sprite_y_vel[k] += kPengator_XYVel[j + 2], flag = true;
+ if (!flag) {
+ sprite_delay_main[k] = 15;
+ sprite_ai_state[k] = 2;
+ }
+ }
+ sprite_A[k] = (frame_counter & 4) >> 2;
+ break;
+ case 2: { // jump
+ static const uint8 kPengator_Jump[4] = {4, 4, 3, 2};
+ if (!sprite_delay_main[k])
+ sprite_ai_state[k]++;
+ else if (sprite_delay_main[k] == 5)
+ sprite_z_vel[k] = 24;
+ sprite_A[k] = kPengator_Jump[sprite_delay_main[k] >> 2];
+ break;
+ }
+ case 3: // slide and sparkle
+ if (!((k ^ frame_counter) & 7 | sprite_z[k])) {
+ static const int8 kPengator_Garnish_Y[8] = { 8, 10, 12, 14, 12, 12, 12, 12 };
+ static const int8 kPengator_Garnish_X[8] = { 4, 4, 4, 4, 0, 4, 8, 12 };
+ int i = sprite_D[k];
+ int x = kPengator_Garnish_X[(GetRandomNumber() & 3) + (i >= 2) * 4];
+ int y = kPengator_Garnish_Y[(GetRandomNumber() & 3) + (i >= 2) * 4];
+ Sprite_GarnishSpawn_Sparkle_limited(k, x, y);
+ }
+ break;
+ }
+}
+
+void Pengator_Draw(int k) { // 9ea415
+ static const DrawMultipleData kPengator_Dmd0[40] = {
+ {-1, -8, 0x0082, 2},
+ { 0, 0, 0x0088, 2},
+ {-1, -7, 0x0082, 2},
+ { 0, 0, 0x008a, 2},
+ {-3, -6, 0x0082, 2},
+ { 0, 0, 0x0088, 2},
+ {-6, -4, 0x0082, 2},
+ { 0, 0, 0x008a, 2},
+ {-4, 0, 0x00a2, 2},
+ { 4, 0, 0x00a3, 2},
+ { 1, -8, 0x4082, 2},
+ { 0, 0, 0x4088, 2},
+ { 1, -7, 0x4082, 2},
+ { 0, 0, 0x408a, 2},
+ { 3, -6, 0x4082, 2},
+ { 0, 0, 0x4088, 2},
+ { 6, -4, 0x4082, 2},
+ { 0, 0, 0x408a, 2},
+ { 4, 0, 0x40a2, 2},
+ {-4, 0, 0x40a3, 2},
+ { 0, -7, 0x0080, 2},
+ { 0, 0, 0x0086, 2},
+ { 0, -7, 0x4080, 2},
+ { 0, 0, 0x4086, 2},
+ { 0, -4, 0x0080, 2},
+ { 0, 0, 0x0086, 2},
+ { 0, -1, 0x0080, 2},
+ { 0, 0, 0x0086, 2},
+ {-8, 0, 0x008e, 2},
+ { 8, 0, 0x408e, 2},
+ { 0, -8, 0x0084, 2},
+ { 0, 0, 0x008c, 2},
+ { 0, -8, 0x4084, 2},
+ { 0, 0, 0x408c, 2},
+ { 0, -7, 0x0084, 2},
+ { 0, 0, 0x008c, 2},
+ { 0, 0, 0x408c, 2},
+ { 0, -6, 0x4084, 2},
+ {-8, 0, 0x00a0, 2},
+ { 8, 0, 0x40a0, 2},
+ };
+ static const DrawMultipleData kPengator_Dmd1[4] = {
+ {0, 16, 0x00b5, 0},
+ {8, 16, 0x40b5, 0},
+ {0, -8, 0x00a5, 0},
+ {8, -8, 0x40a5, 0},
+ };
+ PrepOamCoordsRet info;
+ Sprite_DrawMultiple(k, &kPengator_Dmd0[sprite_graphics[k] * 2], 2, &info);
+ int i;
+ if ((i = 0, sprite_graphics[k] == 14) || (i = 1, sprite_graphics[k] == 19)) {
+ oam_cur_ptr += 8, oam_ext_cur_ptr += 2;
+ Sprite_DrawMultiple(k, &kPengator_Dmd1[i * 2], 2, &info);
+ }
+ SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_LaserBeam(int k) { // 9ea462
+ SpriteDraw_SingleSmall(k);
+ if (Sprite_ReturnIfInactive(k))
+ return;
+ LaserBeam_BuildUpGarnish(k);
+ Sprite_MoveXY(k);
+ Sprite_CheckDamageToLink_same_layer(k);
+ if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k)) {
+ sprite_state[k] = 0;
+ SpriteSfx_QueueSfx3WithPan(k, 0x26);
+ }
+}
+
+void LaserBeam_BuildUpGarnish(int k) { // 9ea488
+ int j = GarnishAllocOverwriteOld();
+ garnish_type[j] = 4;
+ garnish_active = 4;
+ Garnish_SetX(j, Sprite_GetX(k));
+ Garnish_SetY(j, Sprite_GetY(k) + 16);
+ garnish_countdown[j] = 16;
+ garnish_oam_flags[j] = sprite_graphics[k];
+ garnish_sprite[j] = k;
+ garnish_floor[j] = sprite_floor[k];
+}
+
+void Sprite_95_LaserEyeLeft(int k) { // 9ea541
+ static const uint8 kLaserEye_Dirs[4] = {2, 3, 0, 1};
+ if (sprite_A[k]) {
+ Sprite_LaserBeam(k);
+ return;
+ }
+ LaserEye_Draw(k);
+ if (Sprite_ReturnIfInactive(k))
+ return;
+ switch(sprite_ai_state[k]) {
+ case 0: // monitor firing zone
+ if (sprite_head_dir[k] == 0 && sprite_D[k] != kLaserEye_Dirs[link_direction_facing >> 1]) {
+ sprite_graphics[k] = 0;
+ } else {
+ uint16 j = (sprite_D[k] < 2) ? link_y_coord - cur_sprite_y : link_x_coord - cur_sprite_x;
+ if ((uint16)(j + 16) < 32) {
+ sprite_delay_main[k] = 32;
+ sprite_ai_state[k] = 1;
+ } else {
+ sprite_graphics[k] = 0;
+ }
+ }
+ break;
+ case 1: // firing beam
+ sprite_graphics[k] = 1;
+ if (!sprite_delay_main[k]) {
+ sprite_ai_state[k] = 0;
+ LaserEye_FireBeam(k);
+ sprite_delay_aux4[k] = 12;
+ }
+ break;
+ }
+}
+
+void LaserEye_FireBeam(int k) { // 9ea5d8
+ static const int8 kLaserEye_SpawnXY[6] = {12, -4, 4, 4, 12, -4};
+ static const int8 kLaserEye_SpawnXYVel[6] = {112, -112, 0, 0, 112, -112};
+ SpriteSpawnInfo info;
+ int j = Sprite_SpawnDynamically(k, 0x95, &info);
+ if (j >= 0) {
+ int i = sprite_D[k];
+ sprite_graphics[j] = (i & 2) >> 1;
+ Sprite_SetX(j, info.r0_x + kLaserEye_SpawnXY[i]);
+ Sprite_SetY(j, info.r2_y + kLaserEye_SpawnXY[i + 2]);
+ sprite_x_vel[j] = kLaserEye_SpawnXYVel[i];
+ sprite_y_vel[j] = kLaserEye_SpawnXYVel[i + 2];
+ sprite_flags2[j] = 0x20;
+ sprite_A[j] = 0x20;
+ sprite_oam_flags[j] = 5;
+ sprite_defl_bits[j] = 0x48;
+ sprite_ignore_projectile[j] = 0x48;
+ sprite_delay_main[j] = 5;
+ if (link_shield_type == 3)
+ sprite_flags5[j] = 32;
+ SpriteSfx_QueueSfx3WithPan(k, 0x19);
+ }
+}
+
+void LaserEye_Draw(int k) { // 9ea708
+ static const DrawMultipleData kLaserEye_Dmd[24] = {
+ { 8, -4, 0x40c8, 0},
+ { 8, 4, 0x40d8, 0},
+ { 8, 12, 0xc0c8, 0},
+ { 8, -4, 0x40c9, 0},
+ { 8, 4, 0x40d9, 0},
+ { 8, 12, 0xc0c9, 0},
+ { 0, -4, 0x00c8, 0},
+ { 0, 4, 0x00d8, 0},
+ { 0, 12, 0x80c8, 0},
+ { 0, -4, 0x00c9, 0},
+ { 0, 4, 0x00d9, 0},
+ { 0, 12, 0x80c9, 0},
+ {-4, 8, 0x00d6, 0},
+ { 4, 8, 0x00d7, 0},
+ {12, 8, 0x40d6, 0},
+ {-4, 8, 0x00c6, 0},
+ { 4, 8, 0x00c7, 0},
+ {12, 8, 0x40c6, 0},
+ {-4, 0, 0x80d6, 0},
+ { 4, 0, 0x80d7, 0},
+ {12, 0, 0xc0d6, 0},
+ {-4, 0, 0x80c6, 0},
+ { 4, 0, 0x80c7, 0},
+ {12, 0, 0xc0c6, 0},
+ };
+ if (sprite_head_dir[k])
+ sprite_graphics[k] = (sprite_delay_aux4[k] == 0);
+ sprite_obj_prio[k] = 0x30;
+ Sprite_DrawMultiple(k, &kLaserEye_Dmd[(sprite_graphics[k] + sprite_D[k] * 2) * 3], 3, NULL);
+}
+
+void Sprite_94_Pirogusu(int k) { // 9ea742
+ static const uint8 kPirogusu_A0[4] = {2, 3, 0, 1};
+ static const uint8 kPirogusu_A1[8] = {9, 11, 5, 7, 5, 11, 7, 9};
+ static const uint8 kPirogusu_A2[8] = {16, 17, 18, 19, 12, 13, 14, 15};
+ static const int8 kPirogusu_XYvel[6] = {0, 0, 4, -4, 0, 0};
+ static const int8 kPirogusu_XYvel2[6] = {2, -2, 0, 0, 2, -2};
+ static const int8 kPirogusu_XYvel3[6] = {24, -24, 0, 0, 24, -24};
+
+ if (sprite_E[k]) {
+ Sprite_94_Tile(k);
+ return;
+ }
+ sprite_obj_prio[k] |= 0x30;
+ Pirogusu_Draw(k);
+ if (Sprite_ReturnIfInactive(k))
+ return;
+ switch(sprite_ai_state[k]) {
+ case 0: // wriggle in hole
+ if (!sprite_delay_main[k]) {
+ sprite_ai_state[k] = 1;
+ sprite_delay_main[k] = 31;
+ }
+ sprite_ignore_projectile[k] = sprite_delay_main[k];
+ sprite_A[k] = kPirogusu_A0[sprite_D[k]];
+ break;
+ case 1: { // emerge
+ if (!sprite_delay_main[k]) {
+ sprite_ai_state[k] = 2;
+ sprite_delay_main[k] = 32;
+ sprite_ignore_projectile[k] = 0;
+ Sprite_ZeroVelocity_XY(k);
+ } else {
+ sprite_A[k] = kPirogusu_A1[sprite_delay_main[k] >> 3 & 1 | sprite_D[k] << 1];
+ int j = sprite_D[k];
+ sprite_x_vel[k] = kPirogusu_XYvel[j + 2];
+ sprite_y_vel[k] = kPirogusu_XYvel[j];
+ Sprite_MoveXY(k);
+ }
+ break;
+ }
+ case 2: { // splash into play
+ Sprite_CheckDamageToAndFromLink(k);
+ Sprite_MoveXY(k);
+ int j = sprite_D[k];
+ sprite_x_vel[k] += kPirogusu_XYvel2[j];
+ sprite_y_vel[k] += kPirogusu_XYvel2[j + 2];
+ if (!sprite_delay_main[k]) {
+ Sprite_SpawnSmallSplash(k);
+ sprite_delay_aux1[k] = 16;
+ sprite_ai_state[k] = 3;
+ }
+ sprite_A[k] = kPirogusu_A2[frame_counter >> 2 & 1 | sprite_D[k] << 1];
+ break;
+ }
+ case 3: { // swim
+ if (Sprite_ReturnIfRecoiling(k))
+ return;
+ Sprite_CheckDamageToAndFromLink(k);
+ sprite_A[k] = kPirogusu_A2[frame_counter >> 2 & 1 | sprite_D[k] << 1] + 8;
+ if (!sprite_delay_aux1[k]) {
+ Pirogusu_SpawnSplash(k);
+ Sprite_MoveXY(k);
+ if (Sprite_CheckTileCollision(k) & 15) {
+ static const uint8 kPirogusu_Dir[8] = {2, 3, 2, 3, 0, 1, 0, 1};
+ sprite_D[k] = kPirogusu_Dir[sprite_D[k] << 1 | GetRandomNumber() & 1];
+ }
+ int j = sprite_D[k];
+ sprite_x_vel[k] = kPirogusu_XYvel3[j];
+ sprite_y_vel[k] = kPirogusu_XYvel3[j + 2];
+ }
+ break;
+ }
+ }
+}
+
+void Pirogusu_SpawnSplash(int k) { // 9ea897
+ static const uint8 kPirogusu_Tab0[4] = {3, 4, 5, 4};
+ if ((k ^ frame_counter) & 3)
+ return;
+ int x = kPirogusu_Tab0[GetRandomNumber() & 3];
+ int y = kPirogusu_Tab0[GetRandomNumber() & 3];
+ int j = GarnishAllocLow();
+ if (j >= 0) {
+ garnish_type[j] = 11;
+ garnish_active = 11;
+ Garnish_SetX(j, Sprite_GetX(k) + x);
+ Garnish_SetY(j, Sprite_GetY(k) + y + 16);
+ garnish_countdown[j] = 15;
+ }
+}
+
+void Pirogusu_Draw(int k) { // 9ea93b
+ static const uint8 kPirogusu_OamFlags[28] = {
+ 0, 0x80, 0x40, 0, 0, 0, 0, 0x80, 0x80, 0xc0, 0x40, 0x40, 0, 0x40, 0x80, 0xc0,
+ 0x40, 0xc0, 0, 0x80, 0, 0x40, 0x80, 0xc0, 0x40, 0xc0, 0, 0x80,
+ };
+ static const uint8 kPirogusu_Gfx[28] = {
+ 0, 0, 1, 1, 2, 3, 4, 3, 2, 3, 4, 3, 5, 5, 5, 5,
+ 7, 7, 7, 7, 6, 6, 6, 6, 8, 8, 8, 8,
+ };
+ int j = sprite_A[k];
+ sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kPirogusu_OamFlags[j];
+ sprite_graphics[k] = kPirogusu_Gfx[j];
+ if (j < 4) {
+ cur_sprite_x += 4, cur_sprite_y += 4;
+ SpriteDraw_SingleSmall(k);
+ } else {
+ SpriteDraw_SingleLarge(k);
+ }
+}
+
+void Sprite_93_Bumper(int k) { // 9ea982
+ static const int8 kBumper_Vels[4] = { 0, 2, -2, 0 };
+ Bumper_Draw(k);
+ if (Sprite_ReturnIfInactive(k))
+ return;
+ Sprite_CheckTileCollision(k);
+ if (!link_cape_mode && Sprite_CheckDamageToLink_same_layer(k)) {
+ Link_CancelDash();
+ sprite_delay_main[k] = 32;
+ ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 0x30);
+ link_actual_vel_y = pt.y + kBumper_Vels[joypad1H_last >> 2 & 3];
+ link_actual_vel_x = pt.x + kBumper_Vels[joypad1H_last & 3];
+ link_incapacitated_timer = 20;
+ Link_ResetSwimmingState();
+ SpriteSfx_QueueSfx3WithPan(k, 0x32);
+ }
+ for (int j = 15; j >= 0; j--) {
+ if ((j ^ frame_counter) & 3 | sprite_z[j])
+ continue;
+ if (sprite_state[j] < 9 || (sprite_flags3[j] | sprite_flags4[j]) & 0x40)
+ continue;
+ int x = Sprite_GetX(j), y = Sprite_GetY(j);
+ if ((uint16)(cur_sprite_x - x + 16) < 32 && (uint16)(cur_sprite_y - y + 16) < 32) {
+ sprite_F[j] = 15;
+ ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 0x40);
+ sprite_y_recoil[j] = pt.y;
+ sprite_x_recoil[j] = pt.x;
+ sprite_delay_main[k] = 32;
+ SpriteSfx_QueueSfx3WithPan(k, 0x32);
+ }
+ }
+}
+
+void Bumper_Draw(int k) { // 9eaa8b
+ static const DrawMultipleData kBumper_Dmd[8] = {
+ {-8, -8, 0x00ec, 2},
+ { 8, -8, 0x40ec, 2},
+ {-8, 8, 0x80ec, 2},
+ { 8, 8, 0xc0ec, 2},
+ {-7, -7, 0x00ec, 2},
+ { 7, -7, 0x40ec, 2},
+ {-7, 7, 0x80ec, 2},
+ { 7, 7, 0xc0ec, 2},
+ };
+ Sprite_DrawMultiple(k, &kBumper_Dmd[(sprite_delay_main[k] >> 1 & 1) * 4], 4, NULL);
+}
+
+void Sprite_91_StalfosKnight(int k) { // 9eaaa7
+ int j;
+ if (!sprite_ai_state[k]) {
+ PrepOamCoordsRet info;
+ Sprite_PrepOamCoord(k, &info);
+ } else {
+ StalfosKnight_Draw(k);
+ }
+ if (Sprite_ReturnIfInactive(k))
+ return;
+ if ((sprite_hit_timer[k] & 127) == 1) {
+ sprite_hit_timer[k] = 0;
+ sprite_ai_state[k] = 6;
+ sprite_delay_main[k] = 255;
+ sprite_x_vel[k] = 0;
+ sprite_y_vel[k] = 0;
+ enemy_damage_data[0x918] = 2;
+ }
+ if (Sprite_ReturnIfRecoiling(k))
+ return;
+ switch(sprite_ai_state[k]) {
+ case 0: { // waiting for player
+ sprite_flags4[k] = 9;
+ sprite_ignore_projectile[k] = 9;
+ uint8 bak0 = sprite_flags2[k];
+ sprite_flags2[k] |= 128;
+ bool flag = Sprite_CheckDamageToLink(k);
+ sprite_flags2[k] = bak0;
+ if (flag) {
+ sprite_z[k] = 144;
+ sprite_ai_state[k] = 1;
+ sprite_head_dir[k] = 2;
+ sprite_graphics[k] = 2;
+ SpriteSfx_QueueSfx2WithPan(k, 0x20);
+ }
+ break;
+ }
+ case 1: { // falling
+ uint8 old_z = sprite_z[k];
+ Sprite_MoveZ(k);
+ if (!sign8(sprite_z_vel[k] + 64))
+ sprite_z_vel[k] -= 3;
+ if (sign8(old_z ^ sprite_z[k]) && sign8(sprite_z[k])) {
+ sprite_ai_state[k] = 2;
+ sprite_ignore_projectile[k] = 0;
+ sprite_z[k] = 0;
+ sprite_z_vel[k] = 0;
+ sprite_delay_main[k] = 63;
+ }
+ break;
+ }
+ case 2: { //
+ static const uint8 kStalfosKnight_Case2_Gfx[2] = {0, 1};
+ enemy_damage_data[0x918] = 0;
+ Sprite_CheckDamageToAndFromLink(k);
+ if (!sprite_delay_main[k]) {
+ sprite_ai_state[k] = 3;
+ sprite_B[k] = GetRandomNumber() & 63;
+ sprite_delay_main[k] = 127;
+ } else {
+ sprite_C[k] = sprite_graphics[k] = kStalfosKnight_Case2_Gfx[sprite_delay_main[k] >> 5];
+ sprite_head_dir[k] = 2;
+ }
+ break;
+ }
+ case 3: //
+ Sprite_CheckDamageToAndFromLink(k);
+ if (sprite_delay_main[k] == sprite_B[k]) {
+ sprite_head_dir[k] = Sprite_IsRightOfLink(k).a;
+ sprite_ai_state[k] = 4;
+ sprite_delay_main[k] = 32;
+ } else {
+ static const uint8 kStalfosKnight_Case2_Dir[16] = {0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2};
+ sprite_head_dir[k] = kStalfosKnight_Case2_Dir[sprite_delay_main[k] >> 3];
+ sprite_C[k] = 0;
+ sprite_graphics[k] = 0;
+ }
+ break;
+ case 4: //
+ Sprite_CheckDamageToAndFromLink(k);
+ if (!sprite_delay_main[k]) {
+ sprite_ai_state[k] = 5;
+ sprite_delay_main[k] = 255;
+ sprite_delay_aux1[k] = 32;
+ }
+ sprite_C[k] = 1;
+ sprite_graphics[k] = 1;
+ break;
+ case 5: //
+ Sprite_CheckDamageToAndFromLink(k);
+ if (sprite_delay_aux1[k] == 0) {
+ Sprite_MoveXYZ(k);
+ Sprite_CheckTileCollision(k);
+ if (!sign8(sprite_z_vel[k] + 64))
+ sprite_z_vel[k] -= 2;
+ if (sign8(sprite_z[k] - 1)) {
+ sprite_z[k] = 0;
+ sprite_z_vel[k] = 0;
+ if (!sprite_delay_main[k])
+ goto SetToGround;
+ sprite_delay_aux1[k] = 16;
+ }
+ sprite_graphics[k] = sign8(sprite_z_vel[k] - 24) ? 2 : 0;
+ } else {
+ if (sprite_delay_aux1[k] == 1) {
+ sprite_z_vel[k] = 48;
+ Sprite_ApplySpeedTowardsLink(k, 16);
+ sprite_head_dir[k] = Sprite_IsRightOfLink(k).a;
+ SpriteSfx_QueueSfx3WithPan(k, 0x13);
+ }
+ sprite_C[k] = 1;
+ sprite_graphics[k] = 1;
+ }
+ break;
+ case 6: //
+ Sprite_MoveXYZ(k);
+ Sprite_CheckTileCollision(k);
+ if (!sign8(sprite_z_vel[k] + 64))
+ sprite_z_vel[k] -= 2;
+ if (sign8(sprite_z[k] - 1)) {
+ sprite_z[k] = 0;
+ sprite_z_vel[k] = 0;
+ }
+ j = sprite_delay_main[k];
+ if (!j) {
+ if (GetRandomNumber() & 1)
+ goto SetToGround;
+ sprite_ai_state[k] = 7;
+ sprite_delay_main[k] = 80;
+ } else {
+ if (j >= 224 && (j & 3) == 0)
+ SpriteSfx_QueueSfx3WithPan(k, 0x14);
+ static const uint8 kStalfosKnight_Case6_C[32] = {
+ 0, 4, 8, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 12, 8, 4, 0,
+ };
+ sprite_C[k] = kStalfosKnight_Case6_C[j >> 3];
+ sprite_graphics[k] = 3;
+ sprite_head_dir[k] = 2;
+ }
+ break;
+ case 7: //
+ if (!sprite_delay_main[k]) {
+SetToGround:
+ sprite_ai_state[k] = 2;
+ sprite_ignore_projectile[k] = 0;
+ sprite_z[k] = 0;
+ sprite_z_vel[k] = 0;
+ sprite_delay_main[k] = 63;
+ } else {
+ static const uint8 kStalfosKnight_Case7_Gfx[2] = {1, 4};
+ sprite_graphics[k] = kStalfosKnight_Case7_Gfx[sprite_delay_main[k] >> 2 & 1];
+ }
+ break;
+ }
+}
+
+void StalfosKnight_Draw(int k) { // 9eae04
+ static const DrawMultipleData kStalfosKnight_Dmd[35] = {
+ {-4, -8, 0x0064, 0},
+ {-4, 0, 0x0061, 2},
+ { 4, 0, 0x0062, 2},
+ {-3, 16, 0x0074, 0},
+ {11, 16, 0x4074, 0},
+ {-4, -7, 0x0064, 0},
+ {-4, 1, 0x0061, 2},
+ { 4, 1, 0x0062, 2},
+ {-3, 16, 0x0065, 0},
+ {11, 16, 0x4065, 0},
+ {-4, -8, 0x0048, 2},
+ { 4, -8, 0x0049, 2},
+ {-4, 8, 0x004b, 2},
+ { 4, 8, 0x004c, 2},
+ { 4, 8, 0x004c, 2},
+ {-4, 8, 0x0068, 2},
+ { 4, 8, 0x0069, 2},
+ { 4, 8, 0x0069, 2},
+ { 4, 8, 0x0069, 2},
+ { 4, 8, 0x0069, 2},
+ {12, -7, 0x4064, 0},
+ {-4, 1, 0x4062, 2},
+ { 4, 1, 0x4061, 2},
+ {-3, 16, 0x0065, 0},
+ {11, 16, 0x4065, 0},
+ {12, -8, 0x4064, 0},
+ {-4, 0, 0x4062, 2},
+ { 4, 0, 0x4061, 2},
+ {-3, 16, 0x0074, 0},
+ {11, 16, 0x4074, 0},
+ {-4, -8, 0x4049, 2},
+ { 4, -8, 0x4048, 2},
+ {-4, 8, 0x404c, 2},
+ { 4, 8, 0x404b, 2},
+ { 4, 8, 0x404b, 2},
+ };
+ PrepOamCoordsRet info;
+ if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+ return;
+ SpriteDraw_StalfosKnight_Head(k, &info);
+ oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
+ Sprite_DrawMultiple(k, &kStalfosKnight_Dmd[sprite_graphics[k] * 5], 5, &info);
+ oam_cur_ptr -= 4, oam_ext_cur_ptr -= 1;
+ SpriteDraw_Shadow_custom(k, &info, 18);
+}
+
+void SpriteDraw_StalfosKnight_Head(int k, PrepOamCoordsRet *info) { // 9eae4e
+ static const uint8 kStalfosKnight_DrawHead_Char[4] = {0x66, 0x66, 0x46, 0x46};
+ static const uint8 kStalfosKnight_DrawHead_Flags[4] = {0x40, 0, 0, 0};
+ if (sprite_graphics[k] == 2)
+ return;
+ int i = sprite_head_dir[k];
+ OamEnt *oam = GetOamCurPtr();
+ 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
+ static const uint16 kOldMountainManMsgs[3] = {0x9e, 0x9f, 0xa0};
+ int j;
+ OldMountainMan_Draw(k);
+ if (Sprite_ReturnIfInactive(k))
+ return;
+ switch(sprite_subtype2[k]) {
+ case 0: // lost
+ switch (sprite_ai_state[k]) {
+ case 0: // supplicate
+ Sprite_TrackBodyToHead(k);
+ sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+ j = Sprite_ShowMessageOnContact(k, 0x9c);
+ if (j & 0x100) {
+ sprite_D[k] = sprite_head_dir[k] = j;
+ sprite_ai_state[k] = 1;
+ }
+ break;
+ case 1: // switch to tagalong
+ 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
+ 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;
+ }
+}
+
--- a/sprite_main.cpp
+++ /dev/null
@@ -1,26166 +1,0 @@
-#include "sprite_main.h"
-#include "sprite.h"
-#include "tagalong.h"
-#include "ancilla.h"
-#include "overworld.h"
-#include "load_gfx.h"
-#include "hud.h"
-#include "dungeon.h"
-#include "player.h"
-#include "misc.h"
-
-#define byte_7FFE01 (*(uint8*)(g_ram+0x1FE01))
-static const int8 kSpriteKeese_Tab2[16] = {0, 8, 11, 14, 16, 14, 11, 8, 0, -8, -11, -14, -16, -14, -11, -8};
-static const int8 kSpriteKeese_Tab3[16] = {-16, -14, -11, -8, 0, 8, 11, 14, 16, 14, 11, 8, 0, -9, -11, -14};
-static const int8 kZazak_Yvel[4] = {0, 0, 16, -16};
-static const int8 kFluteBoyAnimal_Xvel[4] = {16, -16, 0, 0};
-static const int8 kDesertBarrier_Xv[4] = {16, -16, 0, 0};
-static const int8 kDesertBarrier_Yv[4] = {0, 0, 16, -16};
-static const uint8 kCrystalSwitchPal[2] = {2, 4};
-static const uint8 kZazak_Dir2[8] = {2, 3, 2, 3, 0, 1, 0, 1};
-#define moldorm_x_lo ((uint8*)(g_ram+0x1FC00))
-#define moldorm_x_hi ((uint8*)(g_ram+0x1FC80))
-#define moldorm_y_lo ((uint8*)(g_ram+0x1FD00))
-#define moldorm_y_hi ((uint8*)(g_ram+0x1FD80))
-static const int8 kBadPullDownSwitch_X[5] = {-4, 12, 0, -4, 4};
-static const int8 kBadPullDownSwitch_Y[5] = {-3, -3, 0, 5, 5};
-static const uint8 kBadPullDownSwitch_Char[5] = {0xd2, 0xd2, 0xc4, 0xe4, 0xe4};
-static const uint8 kBadPullDownSwitch_Flags[5] = {0x40, 0, 0, 0x40, 0};
-static const uint8 kBadPullDownSwitch_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;
- }
-}
-
--- a/tables/compile_resources.py
+++ b/tables/compile_resources.py
@@ -61,7 +61,7 @@
print_int_array('kDialogueText', new_r, 'uint8', True, 16, file = f)
f.close()
-ROM = util.LoadedRom()
+ROM = util.LoadedRom(sys.argv[1])
kCompSpritePtrs = [
--- a/tables/decode_music.py
+++ b/tables/decode_music.py
@@ -463,8 +463,8 @@
print_song('ending', open('sound_ending.txt', 'w'))
if __name__ == "__main__":
- ROM = util.LoadedRom()
- song = sys.argv[1]
+ ROM = util.LoadedRom(sys.argv[1])
+ song = sys.argv[2]
load_song(ROM, song)
print_song(song, sys.stdout)
--- a/tables/extract_music.py
+++ b/tables/extract_music.py
@@ -459,11 +459,11 @@
print_all_sfx(open('sfx.txt', 'w'))
if __name__ == "__main__":
- if len(sys.argv) < 2:
- print('extract_music.py [intro|lightworld|indoor|ending]')
+ if len(sys.argv) < 3:
+ print('extract_music.py [rom-filename] [intro|lightworld|indoor|ending]')
sys.exit(0)
- ROM = util.LoadedRom()
- song = sys.argv[1]
+ ROM = util.LoadedRom(None if sys.argv[1] == '' else sys.argv[1])
+ song = sys.argv[2]
load_song(ROM, song)
print_song(song, sys.stdout)
--- a/tables/extract_resources.py
+++ b/tables/extract_resources.py
@@ -7,22 +7,10 @@
import yaml
import extract_music
import os
-import getopt
PATH=''
-option_list, args = getopt.getopt(sys.argv[1:], 'r:', ['rom_path='])
-rom_path = None
-for opt, arg in option_list:
- if opt in ('-r', '--rom_path'):
- rom_path = arg
-
-try:
- ROM = util.LoadedRom(rom_path)
-except Exception as error:
- print(f"Failed to load ROM data for extraction. Error: {error}")
- sys.exit(1)
-
+ROM = util.LoadedRom(sys.argv[1] if len(sys.argv) >= 2 else None)
get_byte = ROM.get_byte
get_word = ROM.get_word
--- /dev/null
+++ b/tagalong.c
@@ -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};
+typedef struct TagalongSprXY {
+ int8 y1, x1, y2, x2;
+} TagalongSprXY;
+typedef struct TagalongDmaFlags {
+ uint8 dma6, dma7;
+ uint8 flags;
+} TagalongDmaFlags;
+static const TagalongSprXY kTagalongDraw_SprXY[56] = {
+ {-2, 0, 0, 0},
+ {-2, 0, 0, 0},
+ {-2, 0, 0, 0},
+ {-2, 0, 0, 0},
+ {-1, 0, 1, 0},
+ {-1, 0, 1, 0},
+ {-1, 0, 1, 0},
+ {-1, 0, 1, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {1, 0, 0, 0},
+ {1, 0, 0, 0},
+ {1, 0, 0, 0},
+ {1, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, -3, 0, 0},
+ {0, 3, 0, 0},
+ {1, 0, 0, 0},
+ {1, 0, 0, 0},
+ {1, -3, 1, 0},
+ {1, 3, 1, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 1, 0},
+ {0, 0, 1, 0},
+ {0, 0, 1, 0},
+ {0, 0, 1, 0},
+ {-1, 0, 0, 0},
+ {-1, 0, 0, 0},
+ {-1, 0, 0, 0},
+ {-1, 0, 0, 0},
+ {0, 0, 1, 0},
+ {0, 0, 1, 0},
+ {0, 0, 1, 0},
+ {0, 0, 1, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {2, 0, 0, 0},
+ {2, 0, 0, 0},
+ {2, -1, 0, 0},
+ {2, 1, 0, 0},
+ {3, 0, 1, 0},
+ {3, 0, 1, 0},
+ {3, -1, 1, 0},
+ {3, 1, 1, 0},
+};
+static const TagalongDmaFlags kTagalongDmaAndFlags[16] = {
+ {0x20, 0xc0, 0x00},
+ {0x00, 0xa0, 0x00},
+ {0x40, 0x60, 0x00},
+ {0x40, 0x60, 0x44},
+ {0x20, 0xc0, 0x04},
+ {0x00, 0xa0, 0x04},
+ {0x40, 0x80, 0x00},
+ {0x40, 0x80, 0x44},
+ {0x20, 0xe0, 0x00},
+ {0x00, 0xe0, 0x00},
+ {0x40, 0xe0, 0x00},
+ {0x40, 0xe0, 0x44},
+ {0x20, 0xe0, 0x04},
+ {0x00, 0xe0, 0x04},
+ {0x40, 0xe0, 0x04},
+ {0x40, 0xe0, 0x40},
+};
+static const uint8 kTagalongDraw_Pals[14] = {0, 4, 4, 4, 4, 0, 7, 4, 4, 3, 4, 4, 4, 4};
+static const uint16 kTagalongDraw_Offs[14] = {0, 0, 0x80, 0x80, 0x80, 0, 0, 0xc0, 0xc0, 0x100, 0x180, 0x180, 0x140, 0x140};
+static const uint8 kTagalongDraw_SprInfo0[24] = {
+ 0xd8, 0x24, 0xd8, 0x64, 0xd9, 0x24, 0xd9, 0x64, 0xda, 0x24, 0xda, 0x64, 0xc8, 0x22, 0xc8, 0x62,
+ 0xc9, 0x22, 0xc9, 0x62, 0xca, 0x22, 0xca, 0x62,
+};
+static const uint16 kTagalongDraw_SprOffs0[2] = {0x170, 0xc0};
+static const uint16 kTagalongDraw_SprOffs1[2] = {0x1c0, 0x110};
+bool Tagalong_IsFollowing() {
+ uint8 main = main_module_index;
+ uint8 sub = submodule_index;
+ return !flag_is_link_immobilized && sub != 10 && !(main == 9 && sub == 0x23) && !(main == 14 && (sub == 1 || sub == 2));
+}
+
+bool Follower_ValidateMessageFreedom() { // 87f46f
+ uint8 ps = link_player_handler_state;
+ if (ps != kPlayerState_Ground && ps != kPlayerState_Swimming && ps != kPlayerState_StartDash)
+ return false;
+ uint8 t = button_mask_b_y & 0x80 | link_unk_master_sword | link_item_in_hand |
+ link_position_mode | flag_is_ancilla_to_pick_up | flag_is_sprite_to_pick_up |
+ link_state_bits | link_grabbing_wall;
+ return t == 0;
+}
+
+void Follower_MoveTowardsLink() { // 88f91a
+ for(;;) {
+ int k = 9;
+ int j = tagalong_var1;
+ ancilla_y_lo[k] = tagalong_y_lo[j];
+ ancilla_y_hi[k] = tagalong_y_hi[j];
+ ancilla_x_lo[k] = tagalong_x_lo[j];
+ ancilla_x_hi[k] = tagalong_x_hi[j];
+
+ ProjectSpeedRet pt = Ancilla_ProjectSpeedTowardsPlayer(k, 24);
+ ancilla_x_vel[k] = pt.x;
+ ancilla_y_vel[k] = pt.y;
+ Ancilla_MoveY(k);
+ Ancilla_MoveX(k);
+
+ uint16 x = Ancilla_GetX(k);
+ uint16 y = Ancilla_GetY(k);
+ if (abs16(x - link_x_coord) < 2 && abs16(y - link_y_coord) < 2)
+ return;
+ k = ++tagalong_var1;
+ if (k == 18)
+ return;
+ tagalong_y_lo[k] = y;
+ tagalong_y_hi[k] = y >> 8;
+ tagalong_x_lo[k] = x;
+ tagalong_x_hi[k] = x >> 8;
+ static const uint8 kTagalongLayerBits[4] = {0x20, 0x10, 0x30, 0x20};
+ tagalong_layerbits[k] = kTagalongLayerBits[link_is_on_lower_level] >> 2 | 1;
+ }
+}
+
+bool Follower_CheckBlindTrigger() { // 899e90
+ int k = tagalong_var2;
+ uint16 x = tagalong_x_hi[k] << 8 | tagalong_x_lo[k];
+ uint16 y = tagalong_y_hi[k] << 8 | tagalong_y_lo[k];
+ uint16 z = (int8)tagalong_z[k];
+ y += z + 12;
+ x += 8;
+ return abs16(0x1568 - y) < 24 && abs16(0x1980 - x) < 24;
+}
+
+void Follower_Initialize() { // 899efc
+ tagalong_y_lo[0] = link_y_coord;
+ tagalong_y_hi[0] = link_y_coord >> 8;
+
+ tagalong_x_lo[0] = link_x_coord;
+ tagalong_x_hi[0] = link_x_coord >> 8;
+
+ tagalong_layerbits[0] = kTagalongFlags[link_is_on_lower_level] >> 2 | (link_direction_facing >> 1);
+ timer_tagalong_reacquire = 64;
+ tagalong_var2 = 0;
+ tagalong_var1 = 0;
+ tagalong_var3 = 0;
+ tagalong_var4 = 0;
+ link_speed_setting = 0;
+}
+
+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) {
+ uint8 t;
+label_e:
+ t = tagalong_var1 - 15;
+ if (sign8(t))
+ t += 20;
+ if (t == tagalong_var2) {
+label_d:
+ tagalong_var2 = (tagalong_var2 + 1 == 20) ? 0 : tagalong_var2 + 1;
+ }
+ }
+ Tagalong_Draw();
+}
+
+void Follower_NotFollowing() { // 89a2b2
+ if (saved_tagalong_indoors != player_is_indoors)
+ return;
+ if (!link_is_running && !Follower_CheckProximityToLink()) {
+ Follower_Initialize();
+ saved_tagalong_indoors = player_is_indoors;
+ if (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++;
+ }
+ uint8 pal;
+skip_first_sprites:
+ 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;
+}
+
--- a/tagalong.cpp
+++ /dev/null
@@ -1,745 +1,0 @@
-#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;
-}
-
--- a/tagalong.h
+++ b/tagalong.h
@@ -1,9 +1,9 @@
#pragma once
#include "types.h"
-struct TagalongMessageInfo {
+typedef struct TagalongMessageInfo {
uint16 y, x, bit, msg, tagalong;
-};
+} TagalongMessageInfo;
bool Tagalong_IsFollowing();
bool Follower_ValidateMessageFreedom();
--- /dev/null
+++ b/tile_detect.c
@@ -1,0 +1,527 @@
+#include "tile_detect.h"
+#include "zelda_rtl.h"
+#include "ancilla.h"
+#include "variables.h"
+#include "overworld.h"
+
+static const uint8 kDetectTiles_tab0[] = { 8, 24, 0, 15 };
+static const uint8 kDetectTiles_tab1[] = { 0, 0, 8, 8 };
+static const uint8 kDetectTiles_tab2[] = { 8, 8, 16, 16 };
+static const uint8 kDetectTiles_tab3[] = { 15, 15, 23, 23 };
+static const int8 kDetectTiles_tab4[] = { 7, 24, -1, 16 };
+static const uint8 kDetectTiles_tab5[] = { 0, 0, 8, 8 };
+static const uint8 kDetectTiles_tab6[] = { 15, 15, 23, 23 };
+uint8 Overworld_GetTileAttributeAtLocation(uint16 x, uint16 y) { // 80882e
+ uint16 t;
+
+ t = ((y - overworld_offset_base_y) & overworld_offset_mask_y) * 8;
+ t |= ((x - overworld_offset_base_x) & overworld_offset_mask_x);
+ t = overworld_tileattr[t >> 1] * 4;
+ t |= (y & 8) >> 2;
+ t |= (x & 1);
+ t = GetMap16toMap8Table()[t];
+
+ uint8 rv = GetMap8toTileAttr()[t & 0x1ff];
+ if (rv >= 0x10 && rv < 0x1C) {
+ rv |= (t >> 14) & 1;
+ }
+ return rv;
+}
+
+void TileDetect_Movement_Y(uint16 direction) { // 87cdcb
+ assert(direction < 4);
+ TileDetect_ResetState();
+ tiledetect_pit_tile = 0;
+
+ tiledetect_which_y_pos[0] = (link_y_coord + kDetectTiles_tab0[direction]);
+ uint16 y = tiledetect_which_y_pos[0] & tilemap_location_calc_mask;
+ uint16 x0 = ((link_x_coord + kDetectTiles_tab1[direction]) & tilemap_location_calc_mask) >> 3;
+ uint16 x1 = ((link_x_coord + kDetectTiles_tab2[direction]) & tilemap_location_calc_mask) >> 3;
+ uint16 x2 = ((link_x_coord + kDetectTiles_tab3[direction]) & tilemap_location_calc_mask) >> 3;
+ scratch_1 = x2;
+ TileDetection_Execute(x0, y, 1);
+ TileDetection_Execute(x1, y, 2);
+ TileDetection_Execute(x2, y, 4);
+}
+
+void TileDetect_Movement_X(uint16 direction) { // 87ce2a
+ assert(direction < 4);
+ TileDetect_ResetState();
+ tiledetect_pit_tile = 0;
+
+ uint16 x = ((link_x_coord + kDetectTiles_tab0[direction]) & tilemap_location_calc_mask) >> 3;
+ uint16 y0 = ((link_y_coord + kDetectTiles_tab1[direction]) & tilemap_location_calc_mask);
+ tiledetect_which_y_pos[0] = link_y_coord + kDetectTiles_tab2[direction];
+ uint16 y1 = tiledetect_which_y_pos[0] & tilemap_location_calc_mask;
+ tiledetect_which_y_pos[1] = link_y_coord + kDetectTiles_tab3[direction];
+ uint16 y2 = tiledetect_which_y_pos[1] & tilemap_location_calc_mask;
+ TileDetection_Execute(x, y0, 1);
+ TileDetection_Execute(x, y1, 2);
+ TileDetection_Execute(x, y2, 4);
+}
+
+void TileDetect_Movement_VerticalSlopes(uint16_t direction) { // 87ce85
+ assert(direction < 4);
+ TileDetect_ResetState();
+ tiledetect_pit_tile = 0;
+
+ uint16 y = (link_y_coord + kDetectTiles_tab4[direction]) & tilemap_location_calc_mask;
+ uint16 x0 = ((link_x_coord + kDetectTiles_tab5[direction]) & tilemap_location_calc_mask) >> 3;
+ uint16 x1 = ((link_x_coord + kDetectTiles_tab6[direction]) & tilemap_location_calc_mask) >> 3;
+ TileDetection_Execute(x0, y, 1);
+ TileDetection_Execute(x1, y, 2);
+}
+
+void TileDetect_Movement_HorizontalSlopes(uint16_t direction) { // 87cec9
+ assert(direction < 4);
+ TileDetect_ResetState();
+ tiledetect_pit_tile = 0;
+
+ uint16 x = ((link_x_coord + kDetectTiles_tab4[direction]) & tilemap_location_calc_mask) >> 3;
+ uint16 y0 = ((link_y_coord + kDetectTiles_tab5[direction]) & tilemap_location_calc_mask);
+ uint16 y1 = ((link_y_coord + kDetectTiles_tab6[direction]) & tilemap_location_calc_mask);
+ TileDetection_Execute(x, y0, 1);
+ TileDetection_Execute(x, y1, 2);
+}
+
+void Player_TileDetectNearby() { // 87cf12
+ TileDetect_ResetState();
+ tiledetect_pit_tile = 0;
+
+ uint16 x0 = ((link_x_coord + kDetectTiles_tab1[0]) & tilemap_location_calc_mask) >> 3;
+ uint16 x1 = ((link_x_coord + kDetectTiles_tab3[0]) & tilemap_location_calc_mask) >> 3;
+
+ uint16 y0 = ((link_y_coord + kDetectTiles_tab1[2]) & tilemap_location_calc_mask);
+ uint16 y1 = ((link_y_coord + kDetectTiles_tab3[2]) & tilemap_location_calc_mask);
+
+ scratch_1 = y0;
+
+ TileDetection_Execute(x0, y0, 8);
+ TileDetection_Execute(x0, y1, 2);
+ TileDetection_Execute(x1, y0, 4);
+ TileDetection_Execute(x1, y1, 1);
+}
+
+void Hookshot_CheckTileCollision(int k) { // 87d576
+ uint8 bak0 = BYTE(dungeon_room_index);
+ uint8 bak1 = link_is_on_lower_level;
+
+ if (ancilla_arr1[k]) {
+ if (!BYTE(kind_of_in_room_staircase))
+ BYTE(dungeon_room_index) += 0x10;
+ link_is_on_lower_level ^= 1;
+ }
+
+ uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
+ int dir = ancilla_dir[k];
+
+ tiledetect_pit_tile = 0;
+ TileDetect_ResetState();
+ if (dung_hdr_collision == 2) {
+ link_is_on_lower_level = 1;
+ Hookshot_CheckSingleLayerTileCollision(x + BG1HOFS_copy2 - BG2HOFS_copy2, y + BG1VOFS_copy2 - BG2VOFS_copy2, dir);
+ link_is_on_lower_level = 0;
+ }
+ Hookshot_CheckSingleLayerTileCollision(x, y, dir);
+
+ link_is_on_lower_level = bak1;
+ BYTE(dungeon_room_index) = bak0;
+}
+
+void Hookshot_CheckSingleLayerTileCollision(uint16 x, uint16 y, int dir) { // 87d607
+ static const uint8 kHookShot_CheckColl_X[8] = { 0, 15, 0, 15, 0, 0, 8, 8 };
+ static const uint8 kHookShot_CheckColl_Y[8] = { 0, 0, 7, 7, 0, 15, 0, 15 };
+ uint16 y0 = (y + kHookShot_CheckColl_Y[dir * 2 + 0]) & tilemap_location_calc_mask;
+ uint16 y1 = (y + kHookShot_CheckColl_Y[dir * 2 + 1]) & tilemap_location_calc_mask;
+ uint16 x0 = ((x + kHookShot_CheckColl_X[dir * 2 + 0]) & tilemap_location_calc_mask) >> 3;
+ uint16 x1 = ((x + kHookShot_CheckColl_X[dir * 2 + 1]) & tilemap_location_calc_mask) >> 3;
+ TileDetection_Execute(x0, y0, 1);
+ TileDetection_Execute(x1, y1, 2);
+}
+
+void HandleNudgingInADoor(int8 speed) { // 87d667
+ uint8 y;
+
+ if (link_last_direction_moved_towards & 2) {
+ y = (uint8)link_y_coord < 0x80 ? 1 : 0;
+ } else {
+ y = (uint8)link_x_coord < 0x80 ? 3 : 2;
+ }
+ tiledetect_pit_tile = 0;
+ TileDetect_ResetState();
+
+ static const int8 kDetectTiles_7_Y[] = { 8, 23, 16, 16 };
+ static const int8 kDetectTiles_7_X[] = { 8, 8, 0, 15 };
+
+ uint16 x0 = ((link_x_coord + kDetectTiles_7_X[y]) & tilemap_location_calc_mask) >> 3;
+ uint16 y0 = ((link_y_coord + kDetectTiles_7_Y[y]) & tilemap_location_calc_mask);
+
+ TileDetection_Execute(x0, y0, 1);
+
+ if (((R14 | detection_of_ledge_tiles_horiz_uphoriz) & 3) == 0) {
+ if (((tiledetect_vertical_ledge | detection_of_unknown_tile_types) & 0x33) == 0)
+ return;
+ }
+
+ if (link_last_direction_moved_towards & 2)
+ link_y_coord -= speed;
+ else
+ link_x_coord -= speed;
+}
+
+void TileCheckForMirrorBonk() { // 87d6f4
+ tiledetect_pit_tile = 0;
+ TileDetect_ResetState();
+
+ uint16 x0 = ((link_x_coord + 2) & tilemap_location_calc_mask) >> 3;
+ uint16 x1 = ((link_x_coord + 13) & tilemap_location_calc_mask) >> 3;
+
+ uint16 y0 = ((link_y_coord + 10) & tilemap_location_calc_mask);
+ uint16 y1 = ((link_y_coord + 21) & tilemap_location_calc_mask);
+
+ scratch_1 = y0;
+
+ TileDetection_Execute(x0, y0, 8);
+ TileDetection_Execute(x0, y1, 2);
+ TileDetection_Execute(x1, y0, 4);
+ TileDetection_Execute(x1, y1, 1);
+
+}
+
+// Used when holding sword in doorway
+void TileDetect_SwordSwingDeepInDoor(uint8 dw) { // 87d73e
+ tiledetect_pit_tile = 0;
+ TileDetect_ResetState();
+
+ static const int8 kDoorwayDetectX[] = { 8, 8, -1, 16 };
+ static const int8 kDoorwayDetectY[] = { -1, 24, 16, 16 };
+ int o = (dw - 1) * 2;
+ uint16 x0 = ((link_x_coord + kDoorwayDetectX[o + 0]) & tilemap_location_calc_mask) >> 3;
+ uint16 x1 = ((link_x_coord + kDoorwayDetectX[o + 1]) & tilemap_location_calc_mask) >> 3;
+
+ uint16 y0 = ((link_y_coord + kDoorwayDetectY[o + 0]) & tilemap_location_calc_mask);
+ uint16 y1 = ((link_y_coord + kDoorwayDetectY[o + 1]) & tilemap_location_calc_mask);
+
+ TileDetection_Execute(x0, y0, 1);
+ TileDetection_Execute(x1, y1, 2);
+}
+
+void TileDetect_ResetState() { // 87d798
+ R12 = 0;
+ R14 = 0;
+ tiledetect_diagonal_tile = 0;
+ tiledetect_stair_tile = 0;
+ tiledetect_pit_tile = 0;
+ tiledetect_inroom_staircase = 0;
+ tiledetect_var2 = 0;
+ tiledetect_var1 = 0;
+ tiledetect_moving_floor_tiles = 0;
+ tiledetect_deepwater = 0;
+ tiledetect_normal_tiles = 0;
+ tiledetect_icy_floor = 0;
+ tiledetect_water_staircase = 0;
+ tiledetect_thick_grass = 0;
+ tiledetect_shallow_water = 0;
+ tiledetect_destruction_aftermath = 0;
+ tiledetect_read_something = 0;
+ tiledetect_vertical_ledge = 0;
+ detection_of_ledge_tiles_horiz_uphoriz = 0;
+ tiledetect_ledges_down_leftright = 0;
+ detection_of_unknown_tile_types = 0;
+ tiledetect_chest = 0;
+ tiledetect_key_lock_gravestones = 0;
+ bitfield_spike_cactus_tiles = 0;
+ tiledetect_spike_floor_and_tile_triggers = 0;
+ bitmask_for_dashable_tiles = 0;
+ tiledetect_misc_tiles = 0;
+ tiledetect_var4 = 0;
+}
+
+void TileDetection_Execute(uint16 x, uint16 y, uint16 bits) { // 87d9d8
+ uint8 tile;
+ uint16 offs = 0;
+ if (player_is_indoors) {
+ force_move_any_direction = force_move_any_direction & 0xff;
+ offs = (y & ~7) * 8 + (x & 63) + (link_is_on_lower_level ? 0x1000 : 0);
+ tile = dung_bg2_attr_table[offs];
+ if (cheatWalkThroughWalls)
+ tile = 0;
+ link_tile_below = tile;
+ } else {
+ tile = Overworld_GetTileAttributeAtLocation(x, y);
+ }
+ TileDetect_ExecuteInner(tile, offs, bits, player_is_indoors);
+}
+
+void TileDetect_ExecuteInner(uint8 tile, uint16 offs, uint16 bits, bool is_indoors) { // 87dc2e
+ static const uint8 word_87DC55[] = { 4, 0, 6, 2 };
+ if (cheatWalkThroughWalls)
+ tile = 0;
+
+ switch (tile) {
+ case 0x00: case 0x05: case 0x06: case 0x07: case 0x14: case 0x15: case 0x16: case 0x17: case 0x21: case 0x23: case 0x24: case 0x25: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x41: case 0x45: case 0x47: case 0x49: case 0x5e: case 0x5f: case 0x61: case 0x62: case 0x64: case 0x65: case 0x66: case 0xa6: case 0xa7: case 0xbe: case 0xbf: case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: // TileBehavior_NothingOW
+ if (!is_indoors)
+ tiledetect_normal_tiles |= bits;
+ break;
+ case 0x01: case 0x02: case 0x03: // TileBehavior_StandardCollision
+ case 0x26: case 0x43:
+ R14 |= bits;
+ break;
+ case 0x6c: case 0x6d: case 0x6e: case 0x6f:
+ if (is_indoors)
+ R14 |= bits;
+ else
+ tiledetect_normal_tiles |= bits;
+ break;
+ case 0x04:
+ if (is_indoors) {
+ R14 |= bits;
+ } else {
+ tiledetect_thick_grass |= bits;
+ }
+ break;
+ case 0x0b:
+ if (is_indoors) {
+ R14 |= bits;
+ } else {
+ index_of_interacting_tile = tile;
+ tiledetect_deepwater |= bits << 4;
+ }
+ break;
+ case 0x08: // TileBehavior_DeepWater
+ tiledetect_deepwater |= bits;
+ break;
+ case 0x09: // TileBehavior_ShallowWater
+ tiledetect_shallow_water |= bits;
+ break;
+ case 0x0a: // TileBehavior_ShortWaterLadder
+ tiledetect_normal_tiles |= bits;
+ break;
+ case 0x0c: // TileBehavior_OverlayMask_0C
+ tiledetect_moving_floor_tiles |= bits;
+ break;
+ case 0x0d: // TileBehavior_SpikeFloor
+ if (!flag_block_link_menu && !(dung_savegame_state_bits & 0x8000))
+ tiledetect_spike_floor_and_tile_triggers |= bits << 4;
+ break;
+ case 0x0e: // TileBehavior_GanonIce
+ tiledetect_icy_floor |= bits;
+ break;
+ case 0x0f: // TileBehavior_PalaceIce
+ tiledetect_icy_floor |= bits << 4;
+ break;
+ case 0x10: case 0x11: case 0x12: case 0x13: // TileBehavior_Slope
+ R12 |= bits;
+ tiledetect_diag_state = word_87DC55[tile & 3];
+ break;
+ case 0x18: case 0x19: case 0x1a: case 0x1b: // TileBehavior_SlopeOuter
+ tiledetect_diagonal_tile |= bits;
+ R12 |= bits;
+ tiledetect_diag_state = word_87DC55[tile & 3];
+ break;
+ case 0x1c: // TileBehavior_OverlayMask_1C
+ tiledetect_water_staircase |= bits;
+ break;
+ case 0x1d: // TileBehavior_NorthSingleLayerStairs
+ index_of_interacting_tile = tile;
+ tiledetect_inroom_staircase |= bits;
+ tiledetect_stair_tile |= bits;
+ break;
+ case 0x1e: case 0x1f: // TileBehavior_NorthSwapLayerStairs
+ index_of_interacting_tile = tile;
+ tiledetect_inroom_staircase |= bits;
+ tiledetect_stair_tile |= bits;
+ break;
+ case 0x20: case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: // TileBehavior_Pit
+ if (!player_on_somaria_platform)
+ tiledetect_pit_tile |= bits;
+ break;
+ case 0x22: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: // TileHandlerIndoor_22
+ tiledetect_stair_tile |= bits;
+ break;
+ case 0x27: // TileBehavior_Hookshottables
+ R14 |= bits;
+ tiledetect_misc_tiles |= bits;
+ break;
+ case 0x28: // TileBehavior_Ledge_North
+ index_of_interacting_tile = tile;
+ tiledetect_vertical_ledge |= bits;
+ break;
+ case 0x29: // TileBehavior_Ledge_South
+ index_of_interacting_tile = tile;
+ tiledetect_vertical_ledge |= bits << 4;
+ break;
+ case 0x2a: case 0x2b: // TileBehavior_Ledge_EastWest
+ index_of_interacting_tile = tile;
+ detection_of_ledge_tiles_horiz_uphoriz |= bits;
+ break;
+ case 0x2c: case 0x2e: // TileBehavior_Ledge_NorthDiagonal
+ index_of_interacting_tile = tile;
+ detection_of_ledge_tiles_horiz_uphoriz |= bits << 4;
+ break;
+ case 0x2d: case 0x2f: // TileBehavior_Ledge_SouthDiagonal
+ index_of_interacting_tile = tile;
+ tiledetect_ledges_down_leftright |= bits;
+ break;
+ case 0x3d: case 0x3e: case 0x3f: // TileHandlerIndoor_3E
+ index_of_interacting_tile = tile;
+ tiledetect_inroom_staircase |= bits << 4;
+ tiledetect_stair_tile |= bits;
+ break;
+ case 0x40: // TileBehavior_ThickGrass
+ tiledetect_thick_grass |= bits;
+ break;
+ case 0x44: // TileBehavior_Spike
+ if (!flag_block_link_menu && !(dung_savegame_state_bits & 0x8000))
+ bitfield_spike_cactus_tiles |= bits;
+ else
+ R14 |= bits;
+ break;
+ case 0x46: // TileBehavior_HylianPlaque
+ tiledetect_spike_floor_and_tile_triggers |= bits;
+ R14 |= bits;
+ break;
+ case 0x48: case 0x4a: // TileBehavior_DiggableGround
+ tiledetect_destruction_aftermath |= bits;
+ tiledetect_normal_tiles |= bits;
+ break;
+ case 0x4b: // TileBehavior_Warp
+ tiledetect_thick_grass |= bits << 4;
+ break;
+ case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: { // TileBehavior_Liftable
+ static const uint8 kTile50data[] = { 0x54, 0x52, 0x50, 0x51, 0x53, 0x55, 0x56 };
+ for (int i = 6; i >= 0; i--) {
+ if (kTile50data[i] == tile) {
+ if (tile == 0x50 || tile == 0x51)
+ bitmask_for_dashable_tiles |= bits << 4;
+ tiledetect_read_something |= bits;
+ interacting_with_liftable_tile_x2 = i * 2;
+ R14 |= bits;
+ tiledetect_misc_tiles |= bits;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x57: // TileBehavior_BonkRocks
+ R14 |= bits;
+ bitmask_for_dashable_tiles |= bits << 4;
+ break;
+ case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: // TileBehavior_Chest
+ tiledetect_misc_tiles |= bits;
+ index_of_interacting_tile = tile;
+ if (dung_chest_locations[tile - 0x58] >= 0x8000) {
+ R14 |= bits;
+ tiledetect_key_lock_gravestones |= bits << 4;
+ if (bits & 2)
+ tiledetect_tile_type = tile;
+ } else {
+ tiledetect_chest |= bits; // small key lock
+ R14 |= bits;
+ }
+ break;
+ case 0x60: // TileBehavior_RupeeTile
+ if (is_indoors) {
+ if (dung_bg2_attr_table[offs + 64] == 0x60) {
+ tiledetect_misc_tiles |= bits << 8;
+ } else {
+ tiledetect_misc_tiles |= bits << 12;
+ }
+ } else {
+ tiledetect_normal_tiles |= bits;
+ }
+ break;
+ case 0x63: // TileBehavior_MinigameChest
+ tiledetect_misc_tiles |= bits;
+ index_of_interacting_tile = tile;
+ tiledetect_chest |= bits; // small key lock
+ R14 |= bits;
+ break;
+ case 0x67: // TileBehavior_CrystalPeg_Up
+ R14 |= bits;
+ tiledetect_misc_tiles |= bits;
+ bitfield_spike_cactus_tiles |= bits << 4;
+ break;
+ case 0x68: // TileBehavior_Conveyor_Upwards
+ tiledetect_var4 |= bits;
+ break;
+ case 0x69: // TileBehavior_Conveyor_Downwards
+ tiledetect_var4 |= bits << 4;
+ break;
+ case 0x6a: // TileBehavior_Conveyor_Leftwards
+ tiledetect_var4 |= bits << 8;
+ break;
+ case 0x6b: // TileBehavior_Conveyor_Rightwards
+ tiledetect_var4 |= bits << 12;
+ break;
+ case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: // TileBehavior_ManipulablyReplaced
+ if (bits & 2)
+ tiledetect_var2 |= 1 << (tile & 0xf);
+ R14 |= bits;
+ tiledetect_misc_tiles |= bits;
+ break;
+ case 0x80: case 0x81: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: // TileHandlerIndoor_80
+ R14 |= bits << 4;
+ tiledetect_var1 = 2 * (tile & 1);
+ break;
+ case 0x82: case 0x83: // TileHandlerIndoor_82
+ R14 |= (bits << 4) | (bits << 8);
+ tiledetect_var1 = 2 * (tile & 1);
+ break;
+ case 0x8e: case 0x8f: // TileBehavior_Entrance
+ R14 |= bits << 4;
+ bitmask_for_dashable_tiles |= bits;
+ tiledetect_var1 = 0;
+ break;
+ case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: // TileBehavior_LayerToggleShutterDoor
+ room_transitioning_flags = 1;
+ R14 |= (bits << 4) | (bits << 8);
+ tiledetect_var1 = 2 * (tile & 1);
+ break;
+ case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: // TileBehavior_LayerAndDungeonToggleShutterDoor
+ room_transitioning_flags = 3;
+ R14 |= (bits << 4) | (bits << 8);
+ tiledetect_var1 = 2 * (tile & 1);
+ break;
+ case 0xa0: case 0xa1: case 0xa4: case 0xa5: // TileBehavior_DungeonToggleManualDoor
+ room_transitioning_flags = 2;
+ R14 |= bits << 4;
+ tiledetect_var1 = 2 * (tile & 1);
+ break;
+ case 0xa2: case 0xa3: // TileBehavior_DungeonToggleShutterDoor
+ room_transitioning_flags = 2;
+ R14 |= (bits << 4) | (bits << 8);
+ tiledetect_var1 = 2 * (tile & 1);
+ break;
+ case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: // TileBehavior_LightableTorch
+ R14 |= bits;
+ tiledetect_misc_tiles |= bits;
+ break;
+ case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: // TileBehavior_FlaggableDoor
+ R14 |= bits;
+ tiledetect_misc_tiles |= bits << 4;
+ break;
+
+ case 0x42: // TileBehavior_GraveStone
+ if (!is_indoors) {
+ tiledetect_key_lock_gravestones |= bits;
+ R14 |= bits;
+ }
+ break;
+ case 0x4c: case 0x4d: // TileBehavior_UnusedCornerType
+ if (!is_indoors) {
+ index_of_interacting_tile = tile;
+ detection_of_unknown_tile_types |= bits;
+ }
+ break;
+ case 0x4e: case 0x4f: // TileBehavior_EasternRuinsCorner
+ if (!is_indoors) {
+ index_of_interacting_tile = tile;
+ detection_of_unknown_tile_types |= bits << 4;
+ }
+ break;
+ default:
+ assert(0);
+ }
+}
+
--- a/tile_detect.cpp
+++ /dev/null
@@ -1,527 +1,0 @@
-#include "tile_detect.h"
-#include "zelda_rtl.h"
-#include "ancilla.h"
-#include "variables.h"
-#include "overworld.h"
-
-static const uint8 kDetectTiles_tab0[] = { 8, 24, 0, 15 };
-static const uint8 kDetectTiles_tab1[] = { 0, 0, 8, 8 };
-static const uint8 kDetectTiles_tab2[] = { 8, 8, 16, 16 };
-static const uint8 kDetectTiles_tab3[] = { 15, 15, 23, 23 };
-static const int8 kDetectTiles_tab4[] = { 7, 24, -1, 16 };
-static const uint8 kDetectTiles_tab5[] = { 0, 0, 8, 8 };
-static const uint8 kDetectTiles_tab6[] = { 15, 15, 23, 23 };
-uint8 Overworld_GetTileAttributeAtLocation(uint16 x, uint16 y) { // 80882e
- uint16 t;
-
- t = ((y - overworld_offset_base_y) & overworld_offset_mask_y) * 8;
- t |= ((x - overworld_offset_base_x) & overworld_offset_mask_x);
- t = overworld_tileattr[t >> 1] * 4;
- t |= (y & 8) >> 2;
- t |= (x & 1);
- t = GetMap16toMap8Table()[t];
-
- uint8 rv = GetMap8toTileAttr()[t & 0x1ff];
- if (rv >= 0x10 && rv < 0x1C) {
- rv |= (t >> 14) & 1;
- }
- return rv;
-}
-
-void TileDetect_Movement_Y(uint16 direction) { // 87cdcb
- assert(direction < 4);
- TileDetect_ResetState();
- tiledetect_pit_tile = 0;
-
- tiledetect_which_y_pos[0] = (link_y_coord + kDetectTiles_tab0[direction]);
- uint16 y = tiledetect_which_y_pos[0] & tilemap_location_calc_mask;
- uint16 x0 = ((link_x_coord + kDetectTiles_tab1[direction]) & tilemap_location_calc_mask) >> 3;
- uint16 x1 = ((link_x_coord + kDetectTiles_tab2[direction]) & tilemap_location_calc_mask) >> 3;
- uint16 x2 = ((link_x_coord + kDetectTiles_tab3[direction]) & tilemap_location_calc_mask) >> 3;
- scratch_1 = x2;
- TileDetection_Execute(x0, y, 1);
- TileDetection_Execute(x1, y, 2);
- TileDetection_Execute(x2, y, 4);
-}
-
-void TileDetect_Movement_X(uint16 direction) { // 87ce2a
- assert(direction < 4);
- TileDetect_ResetState();
- tiledetect_pit_tile = 0;
-
- uint16 x = ((link_x_coord + kDetectTiles_tab0[direction]) & tilemap_location_calc_mask) >> 3;
- uint16 y0 = ((link_y_coord + kDetectTiles_tab1[direction]) & tilemap_location_calc_mask);
- tiledetect_which_y_pos[0] = link_y_coord + kDetectTiles_tab2[direction];
- uint16 y1 = tiledetect_which_y_pos[0] & tilemap_location_calc_mask;
- tiledetect_which_y_pos[1] = link_y_coord + kDetectTiles_tab3[direction];
- uint16 y2 = tiledetect_which_y_pos[1] & tilemap_location_calc_mask;
- TileDetection_Execute(x, y0, 1);
- TileDetection_Execute(x, y1, 2);
- TileDetection_Execute(x, y2, 4);
-}
-
-void TileDetect_Movement_VerticalSlopes(uint16_t direction) { // 87ce85
- assert(direction < 4);
- TileDetect_ResetState();
- tiledetect_pit_tile = 0;
-
- uint16 y = (link_y_coord + kDetectTiles_tab4[direction]) & tilemap_location_calc_mask;
- uint16 x0 = ((link_x_coord + kDetectTiles_tab5[direction]) & tilemap_location_calc_mask) >> 3;
- uint16 x1 = ((link_x_coord + kDetectTiles_tab6[direction]) & tilemap_location_calc_mask) >> 3;
- TileDetection_Execute(x0, y, 1);
- TileDetection_Execute(x1, y, 2);
-}
-
-void TileDetect_Movement_HorizontalSlopes(uint16_t direction) { // 87cec9
- assert(direction < 4);
- TileDetect_ResetState();
- tiledetect_pit_tile = 0;
-
- uint16 x = ((link_x_coord + kDetectTiles_tab4[direction]) & tilemap_location_calc_mask) >> 3;
- uint16 y0 = ((link_y_coord + kDetectTiles_tab5[direction]) & tilemap_location_calc_mask);
- uint16 y1 = ((link_y_coord + kDetectTiles_tab6[direction]) & tilemap_location_calc_mask);
- TileDetection_Execute(x, y0, 1);
- TileDetection_Execute(x, y1, 2);
-}
-
-void Player_TileDetectNearby() { // 87cf12
- TileDetect_ResetState();
- tiledetect_pit_tile = 0;
-
- uint16 x0 = ((link_x_coord + kDetectTiles_tab1[0]) & tilemap_location_calc_mask) >> 3;
- uint16 x1 = ((link_x_coord + kDetectTiles_tab3[0]) & tilemap_location_calc_mask) >> 3;
-
- uint16 y0 = ((link_y_coord + kDetectTiles_tab1[2]) & tilemap_location_calc_mask);
- uint16 y1 = ((link_y_coord + kDetectTiles_tab3[2]) & tilemap_location_calc_mask);
-
- scratch_1 = y0;
-
- TileDetection_Execute(x0, y0, 8);
- TileDetection_Execute(x0, y1, 2);
- TileDetection_Execute(x1, y0, 4);
- TileDetection_Execute(x1, y1, 1);
-}
-
-void Hookshot_CheckTileCollision(int k) { // 87d576
- uint8 bak0 = BYTE(dungeon_room_index);
- uint8 bak1 = link_is_on_lower_level;
-
- if (ancilla_arr1[k]) {
- if (!BYTE(kind_of_in_room_staircase))
- BYTE(dungeon_room_index) += 0x10;
- link_is_on_lower_level ^= 1;
- }
-
- uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
- int dir = ancilla_dir[k];
-
- tiledetect_pit_tile = 0;
- TileDetect_ResetState();
- if (dung_hdr_collision == 2) {
- link_is_on_lower_level = 1;
- Hookshot_CheckSingleLayerTileCollision(x + BG1HOFS_copy2 - BG2HOFS_copy2, y + BG1VOFS_copy2 - BG2VOFS_copy2, dir);
- link_is_on_lower_level = 0;
- }
- Hookshot_CheckSingleLayerTileCollision(x, y, dir);
-
- link_is_on_lower_level = bak1;
- BYTE(dungeon_room_index) = bak0;
-}
-
-void Hookshot_CheckSingleLayerTileCollision(uint16 x, uint16 y, int dir) { // 87d607
- static const uint8 kHookShot_CheckColl_X[8] = { 0, 15, 0, 15, 0, 0, 8, 8 };
- static const uint8 kHookShot_CheckColl_Y[8] = { 0, 0, 7, 7, 0, 15, 0, 15 };
- uint16 y0 = (y + kHookShot_CheckColl_Y[dir * 2 + 0]) & tilemap_location_calc_mask;
- uint16 y1 = (y + kHookShot_CheckColl_Y[dir * 2 + 1]) & tilemap_location_calc_mask;
- uint16 x0 = ((x + kHookShot_CheckColl_X[dir * 2 + 0]) & tilemap_location_calc_mask) >> 3;
- uint16 x1 = ((x + kHookShot_CheckColl_X[dir * 2 + 1]) & tilemap_location_calc_mask) >> 3;
- TileDetection_Execute(x0, y0, 1);
- TileDetection_Execute(x1, y1, 2);
-}
-
-void HandleNudgingInADoor(int8 speed) { // 87d667
- uint8 y;
-
- if (link_last_direction_moved_towards & 2) {
- y = (uint8)link_y_coord < 0x80 ? 1 : 0;
- } else {
- y = (uint8)link_x_coord < 0x80 ? 3 : 2;
- }
- tiledetect_pit_tile = 0;
- TileDetect_ResetState();
-
- static const int8 kDetectTiles_7_Y[] = { 8, 23, 16, 16 };
- static const int8 kDetectTiles_7_X[] = { 8, 8, 0, 15 };
-
- uint16 x0 = ((link_x_coord + kDetectTiles_7_X[y]) & tilemap_location_calc_mask) >> 3;
- uint16 y0 = ((link_y_coord + kDetectTiles_7_Y[y]) & tilemap_location_calc_mask);
-
- TileDetection_Execute(x0, y0, 1);
-
- if (((R14 | detection_of_ledge_tiles_horiz_uphoriz) & 3) == 0) {
- if (((tiledetect_vertical_ledge | detection_of_unknown_tile_types) & 0x33) == 0)
- return;
- }
-
- if (link_last_direction_moved_towards & 2)
- link_y_coord -= speed;
- else
- link_x_coord -= speed;
-}
-
-void TileCheckForMirrorBonk() { // 87d6f4
- tiledetect_pit_tile = 0;
- TileDetect_ResetState();
-
- uint16 x0 = ((link_x_coord + 2) & tilemap_location_calc_mask) >> 3;
- uint16 x1 = ((link_x_coord + 13) & tilemap_location_calc_mask) >> 3;
-
- uint16 y0 = ((link_y_coord + 10) & tilemap_location_calc_mask);
- uint16 y1 = ((link_y_coord + 21) & tilemap_location_calc_mask);
-
- scratch_1 = y0;
-
- TileDetection_Execute(x0, y0, 8);
- TileDetection_Execute(x0, y1, 2);
- TileDetection_Execute(x1, y0, 4);
- TileDetection_Execute(x1, y1, 1);
-
-}
-
-// Used when holding sword in doorway
-void TileDetect_SwordSwingDeepInDoor(uint8 dw) { // 87d73e
- tiledetect_pit_tile = 0;
- TileDetect_ResetState();
-
- static const int8 kDoorwayDetectX[] = { 8, 8, -1, 16 };
- static const int8 kDoorwayDetectY[] = { -1, 24, 16, 16 };
- int o = (dw - 1) * 2;
- uint16 x0 = ((link_x_coord + kDoorwayDetectX[o + 0]) & tilemap_location_calc_mask) >> 3;
- uint16 x1 = ((link_x_coord + kDoorwayDetectX[o + 1]) & tilemap_location_calc_mask) >> 3;
-
- uint16 y0 = ((link_y_coord + kDoorwayDetectY[o + 0]) & tilemap_location_calc_mask);
- uint16 y1 = ((link_y_coord + kDoorwayDetectY[o + 1]) & tilemap_location_calc_mask);
-
- TileDetection_Execute(x0, y0, 1);
- TileDetection_Execute(x1, y1, 2);
-}
-
-void TileDetect_ResetState() { // 87d798
- R12 = 0;
- R14 = 0;
- tiledetect_diagonal_tile = 0;
- tiledetect_stair_tile = 0;
- tiledetect_pit_tile = 0;
- tiledetect_inroom_staircase = 0;
- tiledetect_var2 = 0;
- tiledetect_var1 = 0;
- tiledetect_moving_floor_tiles = 0;
- tiledetect_deepwater = 0;
- tiledetect_normal_tiles = 0;
- tiledetect_icy_floor = 0;
- tiledetect_water_staircase = 0;
- tiledetect_thick_grass = 0;
- tiledetect_shallow_water = 0;
- tiledetect_destruction_aftermath = 0;
- tiledetect_read_something = 0;
- tiledetect_vertical_ledge = 0;
- detection_of_ledge_tiles_horiz_uphoriz = 0;
- tiledetect_ledges_down_leftright = 0;
- detection_of_unknown_tile_types = 0;
- tiledetect_chest = 0;
- tiledetect_key_lock_gravestones = 0;
- bitfield_spike_cactus_tiles = 0;
- tiledetect_spike_floor_and_tile_triggers = 0;
- bitmask_for_dashable_tiles = 0;
- tiledetect_misc_tiles = 0;
- tiledetect_var4 = 0;
-}
-
-void TileDetection_Execute(uint16 x, uint16 y, uint16 bits) { // 87d9d8
- uint8 tile;
- uint16 offs = 0;
- if (player_is_indoors) {
- force_move_any_direction = force_move_any_direction & 0xff;
- offs = (y & ~7) * 8 + (x & 63) + (link_is_on_lower_level ? 0x1000 : 0);
- tile = dung_bg2_attr_table[offs];
- if (cheatWalkThroughWalls)
- tile = 0;
- link_tile_below = tile;
- } else {
- tile = Overworld_GetTileAttributeAtLocation(x, y);
- }
- TileDetect_ExecuteInner(tile, offs, bits, player_is_indoors);
-}
-
-void TileDetect_ExecuteInner(uint8 tile, uint16 offs, uint16 bits, bool is_indoors) { // 87dc2e
- static const uint8 word_87DC55[] = { 4, 0, 6, 2 };
- if (cheatWalkThroughWalls)
- tile = 0;
-
- switch (tile) {
- case 0x00: case 0x05: case 0x06: case 0x07: case 0x14: case 0x15: case 0x16: case 0x17: case 0x21: case 0x23: case 0x24: case 0x25: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x41: case 0x45: case 0x47: case 0x49: case 0x5e: case 0x5f: case 0x61: case 0x62: case 0x64: case 0x65: case 0x66: case 0xa6: case 0xa7: case 0xbe: case 0xbf: case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: // TileBehavior_NothingOW
- if (!is_indoors)
- tiledetect_normal_tiles |= bits;
- break;
- case 0x01: case 0x02: case 0x03: // TileBehavior_StandardCollision
- case 0x26: case 0x43:
- R14 |= bits;
- break;
- case 0x6c: case 0x6d: case 0x6e: case 0x6f:
- if (is_indoors)
- R14 |= bits;
- else
- tiledetect_normal_tiles |= bits;
- break;
- case 0x04:
- if (is_indoors) {
- R14 |= bits;
- } else {
- tiledetect_thick_grass |= bits;
- }
- break;
- case 0x0b:
- if (is_indoors) {
- R14 |= bits;
- } else {
- index_of_interacting_tile = tile;
- tiledetect_deepwater |= bits << 4;
- }
- break;
- case 0x08: // TileBehavior_DeepWater
- tiledetect_deepwater |= bits;
- break;
- case 0x09: // TileBehavior_ShallowWater
- tiledetect_shallow_water |= bits;
- break;
- case 0x0a: // TileBehavior_ShortWaterLadder
- tiledetect_normal_tiles |= bits;
- break;
- case 0x0c: // TileBehavior_OverlayMask_0C
- tiledetect_moving_floor_tiles |= bits;
- break;
- case 0x0d: // TileBehavior_SpikeFloor
- if (!flag_block_link_menu && !(dung_savegame_state_bits & 0x8000))
- tiledetect_spike_floor_and_tile_triggers |= bits << 4;
- break;
- case 0x0e: // TileBehavior_GanonIce
- tiledetect_icy_floor |= bits;
- break;
- case 0x0f: // TileBehavior_PalaceIce
- tiledetect_icy_floor |= bits << 4;
- break;
- case 0x10: case 0x11: case 0x12: case 0x13: // TileBehavior_Slope
- R12 |= bits;
- tiledetect_diag_state = word_87DC55[tile & 3];
- break;
- case 0x18: case 0x19: case 0x1a: case 0x1b: // TileBehavior_SlopeOuter
- tiledetect_diagonal_tile |= bits;
- R12 |= bits;
- tiledetect_diag_state = word_87DC55[tile & 3];
- break;
- case 0x1c: // TileBehavior_OverlayMask_1C
- tiledetect_water_staircase |= bits;
- break;
- case 0x1d: // TileBehavior_NorthSingleLayerStairs
- index_of_interacting_tile = tile;
- tiledetect_inroom_staircase |= bits;
- tiledetect_stair_tile |= bits;
- break;
- case 0x1e: case 0x1f: // TileBehavior_NorthSwapLayerStairs
- index_of_interacting_tile = tile;
- tiledetect_inroom_staircase |= bits;
- tiledetect_stair_tile |= bits;
- break;
- case 0x20: case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: // TileBehavior_Pit
- if (!player_on_somaria_platform)
- tiledetect_pit_tile |= bits;
- break;
- case 0x22: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: // TileHandlerIndoor_22
- tiledetect_stair_tile |= bits;
- break;
- case 0x27: // TileBehavior_Hookshottables
- R14 |= bits;
- tiledetect_misc_tiles |= bits;
- break;
- case 0x28: // TileBehavior_Ledge_North
- index_of_interacting_tile = tile;
- tiledetect_vertical_ledge |= bits;
- break;
- case 0x29: // TileBehavior_Ledge_South
- index_of_interacting_tile = tile;
- tiledetect_vertical_ledge |= bits << 4;
- break;
- case 0x2a: case 0x2b: // TileBehavior_Ledge_EastWest
- index_of_interacting_tile = tile;
- detection_of_ledge_tiles_horiz_uphoriz |= bits;
- break;
- case 0x2c: case 0x2e: // TileBehavior_Ledge_NorthDiagonal
- index_of_interacting_tile = tile;
- detection_of_ledge_tiles_horiz_uphoriz |= bits << 4;
- break;
- case 0x2d: case 0x2f: // TileBehavior_Ledge_SouthDiagonal
- index_of_interacting_tile = tile;
- tiledetect_ledges_down_leftright |= bits;
- break;
- case 0x3d: case 0x3e: case 0x3f: // TileHandlerIndoor_3E
- index_of_interacting_tile = tile;
- tiledetect_inroom_staircase |= bits << 4;
- tiledetect_stair_tile |= bits;
- break;
- case 0x40: // TileBehavior_ThickGrass
- tiledetect_thick_grass |= bits;
- break;
- case 0x44: // TileBehavior_Spike
- if (!flag_block_link_menu && !(dung_savegame_state_bits & 0x8000))
- bitfield_spike_cactus_tiles |= bits;
- else
- R14 |= bits;
- break;
- case 0x46: // TileBehavior_HylianPlaque
- tiledetect_spike_floor_and_tile_triggers |= bits;
- R14 |= bits;
- break;
- case 0x48: case 0x4a: // TileBehavior_DiggableGround
- tiledetect_destruction_aftermath |= bits;
- tiledetect_normal_tiles |= bits;
- break;
- case 0x4b: // TileBehavior_Warp
- tiledetect_thick_grass |= bits << 4;
- break;
- case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: { // TileBehavior_Liftable
- static const uint8 kTile50data[] = { 0x54, 0x52, 0x50, 0x51, 0x53, 0x55, 0x56 };
- for (int i = 6; i >= 0; i--) {
- if (kTile50data[i] == tile) {
- if (tile == 0x50 || tile == 0x51)
- bitmask_for_dashable_tiles |= bits << 4;
- tiledetect_read_something |= bits;
- interacting_with_liftable_tile_x2 = i * 2;
- R14 |= bits;
- tiledetect_misc_tiles |= bits;
- break;
- }
- }
- break;
- }
- case 0x57: // TileBehavior_BonkRocks
- R14 |= bits;
- bitmask_for_dashable_tiles |= bits << 4;
- break;
- case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: // TileBehavior_Chest
- tiledetect_misc_tiles |= bits;
- index_of_interacting_tile = tile;
- if (dung_chest_locations[tile - 0x58] >= 0x8000) {
- R14 |= bits;
- tiledetect_key_lock_gravestones |= bits << 4;
- if (bits & 2)
- tiledetect_tile_type = tile;
- } else {
- tiledetect_chest |= bits; // small key lock
- R14 |= bits;
- }
- break;
- case 0x60: // TileBehavior_RupeeTile
- if (is_indoors) {
- if (dung_bg2_attr_table[offs + 64] == 0x60) {
- tiledetect_misc_tiles |= bits << 8;
- } else {
- tiledetect_misc_tiles |= bits << 12;
- }
- } else {
- tiledetect_normal_tiles |= bits;
- }
- break;
- case 0x63: // TileBehavior_MinigameChest
- tiledetect_misc_tiles |= bits;
- index_of_interacting_tile = tile;
- tiledetect_chest |= bits; // small key lock
- R14 |= bits;
- break;
- case 0x67: // TileBehavior_CrystalPeg_Up
- R14 |= bits;
- tiledetect_misc_tiles |= bits;
- bitfield_spike_cactus_tiles |= bits << 4;
- break;
- case 0x68: // TileBehavior_Conveyor_Upwards
- tiledetect_var4 |= bits;
- break;
- case 0x69: // TileBehavior_Conveyor_Downwards
- tiledetect_var4 |= bits << 4;
- break;
- case 0x6a: // TileBehavior_Conveyor_Leftwards
- tiledetect_var4 |= bits << 8;
- break;
- case 0x6b: // TileBehavior_Conveyor_Rightwards
- tiledetect_var4 |= bits << 12;
- break;
- case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: // TileBehavior_ManipulablyReplaced
- if (bits & 2)
- tiledetect_var2 |= 1 << (tile & 0xf);
- R14 |= bits;
- tiledetect_misc_tiles |= bits;
- break;
- case 0x80: case 0x81: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: // TileHandlerIndoor_80
- R14 |= bits << 4;
- tiledetect_var1 = 2 * (tile & 1);
- break;
- case 0x82: case 0x83: // TileHandlerIndoor_82
- R14 |= (bits << 4) | (bits << 8);
- tiledetect_var1 = 2 * (tile & 1);
- break;
- case 0x8e: case 0x8f: // TileBehavior_Entrance
- R14 |= bits << 4;
- bitmask_for_dashable_tiles |= bits;
- tiledetect_var1 = 0;
- break;
- case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: // TileBehavior_LayerToggleShutterDoor
- room_transitioning_flags = 1;
- R14 |= (bits << 4) | (bits << 8);
- tiledetect_var1 = 2 * (tile & 1);
- break;
- case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: // TileBehavior_LayerAndDungeonToggleShutterDoor
- room_transitioning_flags = 3;
- R14 |= (bits << 4) | (bits << 8);
- tiledetect_var1 = 2 * (tile & 1);
- break;
- case 0xa0: case 0xa1: case 0xa4: case 0xa5: // TileBehavior_DungeonToggleManualDoor
- room_transitioning_flags = 2;
- R14 |= bits << 4;
- tiledetect_var1 = 2 * (tile & 1);
- break;
- case 0xa2: case 0xa3: // TileBehavior_DungeonToggleShutterDoor
- room_transitioning_flags = 2;
- R14 |= (bits << 4) | (bits << 8);
- tiledetect_var1 = 2 * (tile & 1);
- break;
- case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: // TileBehavior_LightableTorch
- R14 |= bits;
- tiledetect_misc_tiles |= bits;
- break;
- case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: // TileBehavior_FlaggableDoor
- R14 |= bits;
- tiledetect_misc_tiles |= bits << 4;
- break;
-
- case 0x42: // TileBehavior_GraveStone
- if (!is_indoors) {
- tiledetect_key_lock_gravestones |= bits;
- R14 |= bits;
- }
- break;
- case 0x4c: case 0x4d: // TileBehavior_UnusedCornerType
- if (!is_indoors) {
- index_of_interacting_tile = tile;
- detection_of_unknown_tile_types |= bits;
- }
- break;
- case 0x4e: case 0x4f: // TileBehavior_EasternRuinsCorner
- if (!is_indoors) {
- index_of_interacting_tile = tile;
- detection_of_unknown_tile_types |= bits << 4;
- }
- break;
- default:
- assert(0);
- }
-}
-
--- /dev/null
+++ b/tracing.c
@@ -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;
+ }
+}
--- a/tracing.cpp
+++ /dev/null
@@ -1,208 +1,0 @@
-
-#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;
- }
-}
--- a/types.h
+++ b/types.h
@@ -1,5 +1,6 @@
#include <stdint.h>
#include <stdlib.h>
+#include <stdbool.h>
#pragma once
typedef uint8_t uint8;
@@ -16,9 +17,12 @@
#ifdef _MSC_VER
#define countof _countof
+#define NORETURN __declspec(noreturn)
#else
#define countof(a) (sizeof(a)/sizeof(*(a)))
+#define NORETURN
#endif
+
static inline uint16 abs16(uint16 t) { return sign16(t) ? -t : t; }
static inline uint8 abs8(uint8 t) { return sign8(t) ? -t : t; }
@@ -29,48 +33,43 @@
static inline uint16 swap16(uint16 v) { return (v << 8) | (v >> 8); }
-struct Point16U {
+typedef struct Point16U {
uint16 x, y;
-};
-struct PointU8 {
+} Point16U;
+typedef struct PointU8 {
uint8 x, y;
-};
-
-struct Pair16U {
+} PointU8;
+typedef struct Pair16U {
uint16 a, b;
-};
+} Pair16U;
-struct PairU8 {
+typedef struct PairU8 {
uint8 a, b;
-};
+} PairU8;
-struct ProjectSpeedRet {
+typedef struct ProjectSpeedRet {
uint8 x, y;
uint8 xdiff, ydiff;
-};
+} ProjectSpeedRet;
-struct OamEnt {
+typedef struct OamEnt {
uint8 x, y, charnum, flags;
-};
+} OamEnt;
-struct UploadVram_Row {
+typedef struct UploadVram_Row {
uint16 col[32];
-};
+} UploadVram_Row;
-struct UploadVram_32x32 {
+typedef struct UploadVram_32x32 {
UploadVram_Row row[32];
-};
+} UploadVram_32x32;
-struct UploadVram_3 {
+typedef struct UploadVram_3 {
uint8 pad[256];
uint16 data[4];
-};
+} UploadVram_3;
-union UploadVram {
- UploadVram_3 t3;
-};
-
-#define uvram (*(UploadVram*)(&g_ram[0x1000]))
+#define uvram (*(UploadVram_3*)(&g_ram[0x1000]))
typedef void PlayerHandlerFunc();
typedef void HandlerFuncK(int k);
\ No newline at end of file
--- a/zelda3.vcxproj
+++ b/zelda3.vcxproj
@@ -123,77 +123,77 @@
</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">
+ <ClCompile Include="ancilla.c" />
+ <ClCompile Include="attract.c" />
+ <ClCompile Include="dungeon.c" />
+ <ClCompile Include="ending.c" />
+ <ClCompile Include="hud.c" />
+ <ClCompile Include="load_gfx.c" />
+ <ClCompile Include="main.c">
<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">
+ <ClCompile Include="messaging.c" />
+ <ClCompile Include="misc.c" />
+ <ClCompile Include="nmi.c" />
+ <ClCompile Include="other_modules.c" />
+ <ClCompile Include="overlord.c" />
+ <ClCompile Include="overworld.c" />
+ <ClCompile Include="player.c" />
+ <ClCompile Include="player_oam.c" />
+ <ClCompile Include="poly.c" />
+ <ClCompile Include="select_file.c" />
+ <ClCompile Include="snes\apu.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
- <ClCompile Include="snes\cart.cpp">
+ <ClCompile Include="snes\cart.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
- <ClCompile Include="snes\cpu.cpp">
+ <ClCompile Include="snes\cpu.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
- <ClCompile Include="snes\dma.cpp">
+ <ClCompile Include="snes\dma.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
- <ClCompile Include="snes\dsp.cpp">
+ <ClCompile Include="snes\dsp.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
- <ClCompile Include="snes\input.cpp">
+ <ClCompile Include="snes\input.c">
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
- <ClCompile Include="snes\ppu.cpp">
+ <ClCompile Include="snes\ppu.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AnySuitable</InlineFunctionExpansion>
</ClCompile>
- <ClCompile Include="snes\snes.cpp">
+ <ClCompile Include="snes\snes.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
- <ClCompile Include="snes\snes_other.cpp">
+ <ClCompile Include="snes\snes_other.c">
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
- <ClCompile Include="snes\spc.cpp">
+ <ClCompile Include="snes\spc.c">
<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">
+ <ClCompile Include="spc_player.c" />
+ <ClCompile Include="sprite.c" />
+ <ClCompile Include="sprite_main.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
- <ClCompile Include="tagalong.cpp" />
- <ClCompile Include="tile_detect.cpp" />
- <ClCompile Include="tracing.cpp">
+ <ClCompile Include="tagalong.c" />
+ <ClCompile Include="tile_detect.c" />
+ <ClCompile Include="tracing.c">
<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" />
+ <ClCompile Include="zelda_cpu_infra.c" />
+ <ClCompile Include="zelda_rtl.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="ancilla.h" />
@@ -217,6 +217,7 @@
<ClInclude Include="snes\cpu.h" />
<ClInclude Include="snes\dma.h" />
<ClInclude Include="snes\dsp.h" />
+ <ClInclude Include="snes\dsp_regs.h" />
<ClInclude Include="snes\input.h" />
<ClInclude Include="snes\ppu.h" />
<ClInclude Include="snes\saveload.h" />
--- a/zelda3.vcxproj.filters
+++ b/zelda3.vcxproj.filters
@@ -10,109 +10,109 @@
</Filter>
</ItemGroup>
<ItemGroup>
- <ClCompile Include="snes\apu.cpp">
+ <ClCompile Include="snes\apu.c">
<Filter>Snes</Filter>
</ClCompile>
- <ClCompile Include="snes\cart.cpp">
+ <ClCompile Include="snes\cart.c">
<Filter>Snes</Filter>
</ClCompile>
- <ClCompile Include="snes\cpu.cpp">
+ <ClCompile Include="snes\cpu.c">
<Filter>Snes</Filter>
</ClCompile>
- <ClCompile Include="snes\dma.cpp">
+ <ClCompile Include="snes\dma.c">
<Filter>Snes</Filter>
</ClCompile>
- <ClCompile Include="snes\dsp.cpp">
+ <ClCompile Include="snes\dsp.c">
<Filter>Snes</Filter>
</ClCompile>
- <ClCompile Include="snes\input.cpp">
+ <ClCompile Include="snes\input.c">
<Filter>Snes</Filter>
</ClCompile>
- <ClCompile Include="main.cpp">
+ <ClCompile Include="main.c">
<Filter>Snes</Filter>
</ClCompile>
- <ClCompile Include="snes\ppu.cpp">
+ <ClCompile Include="snes\ppu.c">
<Filter>Snes</Filter>
</ClCompile>
- <ClCompile Include="snes\snes.cpp">
+ <ClCompile Include="snes\snes.c">
<Filter>Snes</Filter>
</ClCompile>
- <ClCompile Include="snes\snes_other.cpp">
+ <ClCompile Include="snes\snes_other.c">
<Filter>Snes</Filter>
</ClCompile>
- <ClCompile Include="snes\spc.cpp">
+ <ClCompile Include="snes\spc.c">
<Filter>Snes</Filter>
</ClCompile>
- <ClCompile Include="tracing.cpp">
+ <ClCompile Include="tracing.c">
<Filter>Snes</Filter>
</ClCompile>
- <ClCompile Include="zelda_rtl.cpp">
+ <ClCompile Include="zelda_rtl.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="hud.cpp">
+ <ClCompile Include="hud.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="dungeon.cpp">
+ <ClCompile Include="dungeon.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="nmi.cpp">
+ <ClCompile Include="nmi.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="player_oam.cpp">
+ <ClCompile Include="player_oam.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="load_gfx.cpp">
+ <ClCompile Include="load_gfx.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="messaging.cpp">
+ <ClCompile Include="messaging.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="overworld.cpp">
+ <ClCompile Include="overworld.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="sprite.cpp">
+ <ClCompile Include="sprite.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="sprite_main.cpp">
+ <ClCompile Include="sprite_main.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="tagalong.cpp">
+ <ClCompile Include="tagalong.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="overlord.cpp">
+ <ClCompile Include="overlord.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="poly.cpp">
+ <ClCompile Include="poly.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="ancilla.cpp">
+ <ClCompile Include="ancilla.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="ending.cpp">
+ <ClCompile Include="ending.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="attract.cpp">
+ <ClCompile Include="attract.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="select_file.cpp">
+ <ClCompile Include="select_file.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="spc_player.cpp">
+ <ClCompile Include="spc_player.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="player.cpp">
+ <ClCompile Include="player.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="tile_detect.cpp">
+ <ClCompile Include="tile_detect.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="other_modules.cpp">
+ <ClCompile Include="other_modules.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="misc.cpp">
+ <ClCompile Include="misc.c">
<Filter>Zelda</Filter>
</ClCompile>
- <ClCompile Include="zelda_cpu_infra.cpp">
+ <ClCompile Include="zelda_cpu_infra.c">
<Filter>Zelda</Filter>
</ClCompile>
</ItemGroup>
@@ -227,6 +227,9 @@
</ClInclude>
<ClInclude Include="sprite_main.h">
<Filter>Zelda</Filter>
+ </ClInclude>
+ <ClInclude Include="snes\dsp_regs.h">
+ <Filter>Snes</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
--- /dev/null
+++ b/zelda_cpu_infra.c
@@ -1,0 +1,929 @@
+// 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 "snes/snes.h"
+#include "snes/cpu.h"
+#include "snes/cart.h"
+#include "tracing.h"
+
+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)];
+}
+
+uint8 *GetCartRamPtr(uint32 addr) {
+ Cart *cart = g_snes->cart;
+ return &cart->ram[addr];
+}
+
+typedef struct Snapshot {
+ uint16 a, x, y, sp, dp, pc;
+ uint8 k, db, flags;
+ uint8 ram[0x20000];
+ uint16 vram[0x8000];
+ uint16 sram[0x2000];
+} Snapshot;
+
+static Snapshot g_snapshot_mine, g_snapshot_theirs, g_snapshot_before;
+
+static void MakeSnapshot(Snapshot *s) {
+ Cpu *c = g_cpu;
+ s->a = c->a, s->x = c->x, s->y = c->y;
+ s->sp = c->sp, s->dp = c->dp, s->db = c->db;
+ s->pc = c->pc, s->k = c->k;
+ s->flags = cpu_getFlags(c);
+ memcpy(s->ram, g_snes->ram, 0x20000);
+ memcpy(s->sram, g_snes->cart->ram, g_snes->cart->ramSize);
+ memcpy(s->vram, g_snes->ppu->vram, sizeof(uint16) * 0x8000);
+}
+
+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
+
+ // c code is authoritative
+ WORD(a->ram[0x1f0a]) = WORD(b->ram[0x1f0a]);
+
+ memcpy(&b->ram[0x1f0d], &a->ram[0x1f0d], 0x3f - 0xd);
+ memcpy(b->ram + 0x138, a->ram + 0x138, 256 - 0x38); // copy the stack over
+
+ 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) {
+ Cpu *cpu = snes->cpu;
+ cpu->a = cpu->x = cpu->y = 0;
+ cpu->e = false;
+ cpu->irqWanted = cpu->nmiWanted = cpu->waiting = cpu->stopped = 0;
+ cpu_setFlags(cpu, 0x30);
+
+ // Run until the wait loop in Interrupt_Reset,
+ // Or the polyhedral main function.
+ for(int loops = 0;;loops++) {
+ snes_printCpuLine(snes);
+ cpu_runOpcode(snes->cpu);
+ while (snes->dma->dmaBusy)
+ dma_doDma(snes->dma);
+
+ uint32_t pc = snes->cpu->k << 16 | snes->cpu->pc;
+ if (pc == 0x8034 || pc == 0x9f81d && loops >= 10 || pc == 0x8225 || pc == 0x82D2)
+ break;
+ }
+}
+
+void RunEmulatedSnesFrame(Snes *snes, int run_what) {
+ // First call runs until init
+ if (snes->cpu->pc == 0x8000 && snes->cpu->k == 0) {
+ RunOrigAsmCodeOneLoop(snes);
+ g_emulated_ram[0x12] = 1;
+ // Fixup uninitialized variable
+ *(uint16*)(g_emulated_ram+0xAE0) = 0xb280;
+ *(uint16*)(g_emulated_ram+0xAE2) = 0xb280 + 0x60;
+ }
+
+ // Run poly code
+ if (run_what & 2) {
+ Cpu *cpu = snes->cpu;
+ cpu->sp = 0x1f3e;
+ cpu->pc = 0xf81d;
+ cpu->db = cpu->k = 9;
+ cpu->dp = 0x1f00;
+ RunOrigAsmCodeOneLoop(snes);
+ }
+
+ // Run main code
+ if (run_what & 1) {
+ Cpu *cpu = g_snes->cpu;
+ cpu->sp = 0x1ff;
+ cpu->pc = 0x8034;
+ cpu->k = cpu->dp = cpu->db = 0;
+ RunOrigAsmCodeOneLoop(snes);
+ }
+
+ snes_doAutoJoypad(snes);
+
+ // animated_tile_vram_addr uninited
+ if (snes->ram[0xadd] == 0)
+ *(uint16_t*)&snes->ram[0xadc] = 0xa680;
+
+ // In one code path flag_update_hud_in_nmi uses an undefined value
+ snes_write(snes, DMAP0, 0x01);
+ snes_write(snes, BBAD0, 0x18);
+
+ // Run NMI handler
+ Cpu *cpu = g_snes->cpu;
+ cpu->sp = 0x1ff;
+ cpu->pc = 0x80D9;
+ cpu->k = cpu->dp = cpu->db = 0;
+ RunOrigAsmCodeOneLoop(snes);
+}
+
+struct Ppu *GetPpuForRendering() {
+ return g_zenv.ppu;
+}
+
+Dsp *GetDspForRendering() {
+ SpcPlayer_GenerateSamples(g_zenv.player);
+ return g_zenv.player->dsp;
+}
+
+typedef struct ByteArray {
+ uint8 *data;
+ size_t size, capacity;
+} ByteArray;
+
+void ByteArray_Resize(ByteArray *arr, size_t new_size) {
+ arr->size = new_size;
+ if (new_size > arr->capacity) {
+ size_t minsize = arr->capacity + (arr->capacity >> 1) + 8;
+ arr->capacity = new_size < minsize ? minsize : new_size;
+ void *data = realloc(arr->data, arr->capacity);
+ if (!data) Die("memory allocation failed");
+ arr->data = data;
+ }
+}
+
+void ByteArray_Destroy(ByteArray *arr) {
+ free(arr->data);
+ arr->data = NULL;
+}
+
+void saveFunc(void *ctx_in, void *data, size_t data_size) {
+ ByteArray *arr = (ByteArray *)ctx_in;
+ ByteArray_Resize(arr, arr->size + data_size);
+ memcpy(arr->data + arr->size - data_size, data, data_size);
+}
+
+typedef struct LoadFuncState {
+ uint8 *p, *pend;
+} LoadFuncState;
+
+void loadFunc(void *ctx, void *data, size_t data_size) {
+ LoadFuncState *st = (LoadFuncState *)ctx;
+ assert(st->pend - st->p >= data_size);
+ memcpy(data, st->p, data_size);
+ st->p += data_size;
+}
+
+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;
+}
+
+void SaveSnesState(ByteArray *ctx) {
+ 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, ctx);
+
+ RestoreSnapshot(&g_snapshot_before);
+}
+
+typedef struct StateRecorder {
+ uint16 last_inputs;
+ uint32 frames_since_last;
+ uint32 total_frames;
+
+ // For replay
+ uint32 replay_pos;
+ uint32 replay_frame_counter;
+ uint32 replay_next_cmd_at;
+ uint8 replay_cmd;
+ bool replay_mode;
+
+ ByteArray log;
+ ByteArray base_snapshot;
+} StateRecorder;
+
+static StateRecorder state_recorder;
+
+void StateRecorder_Init(StateRecorder *sr) {
+ memset(sr, 0, sizeof(*sr));
+}
+
+void StateRecorder_AppendByte(StateRecorder *sr, uint8 v) {
+ ByteArray_Resize(&sr->log, sr->log.size + 1);
+ sr->log.data[sr->log.size - 1] = v;
+ printf("%.2x ", v);
+}
+
+void StateRecorder_AppendVl(StateRecorder *sr, uint32 v) {
+ for (; v >= 255; v -= 255)
+ StateRecorder_AppendByte(sr, 255);
+ StateRecorder_AppendByte(sr, v);
+}
+
+void StateRecorder_RecordJoypadBit(StateRecorder *sr, int command) {
+ int frames = sr->frames_since_last;
+ StateRecorder_AppendByte(sr, command << 4 | (frames < 15 ? frames : 15));
+ if (frames >= 15)
+ StateRecorder_AppendVl(sr, frames - 15);
+ sr->frames_since_last = 0;
+}
+
+void StateRecorder_Record(StateRecorder *sr, uint16 inputs) {
+ uint16 diff = inputs ^ sr->last_inputs;
+ if (diff != 0) {
+ sr->last_inputs = inputs;
+ printf("0x%.4x %d: ", diff, sr->frames_since_last);
+ for (int i = 0; i < 12; i++) {
+ if ((diff >> i) & 1)
+ StateRecorder_RecordJoypadBit(sr, i);
+ }
+ printf("\n");
+ }
+ sr->frames_since_last++;
+ sr->total_frames++;
+}
+
+void StateRecorder_RecordPatchByte(StateRecorder *sr, uint32 addr, const uint8 *value, int num) {
+ assert(addr < 0x20000);
+ printf("%d: PatchByte(0x%x, 0x%x. %d): ", sr->frames_since_last, addr, *value, num);
+
+ int frames = sr->frames_since_last;
+ sr->frames_since_last = 0;
+
+ int lq = (num - 1) <= 3 ? (num - 1) : 3;
+ StateRecorder_AppendByte(sr, 0xc0 | (frames != 0 ? 1 : 0) | (addr & 0x10000 ? 2 : 0) | lq << 2);
+ if (frames != 0)
+ StateRecorder_AppendVl(sr, frames - 1);
+ if (lq == 3)
+ StateRecorder_AppendVl(sr, num - 1 - 3);
+ StateRecorder_AppendByte(sr, addr >> 8);
+ StateRecorder_AppendByte(sr, addr);
+ for(int i = 0; i < num; i++)
+ StateRecorder_AppendByte(sr, value[i]);
+ printf("\n");
+}
+
+void StateRecorder_Load(StateRecorder *sr, FILE *f, bool replay_mode) {
+ uint32 hdr[8] = { 0 };
+ fread(hdr, 8, 4, f);
+
+ assert(hdr[0] == 1);
+
+ sr->total_frames = hdr[1];
+ ByteArray_Resize(&sr->log, hdr[2]);
+ fread(sr->log.data, 1, sr->log.size, f);
+ sr->last_inputs = hdr[3];
+ sr->frames_since_last = hdr[4];
+
+ ByteArray_Resize(&sr->base_snapshot, (hdr[5] & 1) ? hdr[6] : 0);
+ fread(sr->base_snapshot.data, 1, sr->base_snapshot.size, f);
+
+ bool is_reset = false;
+ sr->replay_mode = replay_mode;
+ if (replay_mode) {
+ sr->replay_next_cmd_at = sr->frames_since_last = 0;
+ sr->last_inputs = 0;
+ sr->replay_pos = 0;
+ sr->replay_frame_counter = 0;
+ sr->replay_cmd = 0xff;
+ // Load snapshot from |base_snapshot_|, or reset if empty.
+
+ if (sr->base_snapshot.size) {
+ LoadFuncState state = { sr->base_snapshot.data, sr->base_snapshot.data + sr->base_snapshot.size };
+ 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 {
+ ByteArray arr = { 0 };
+ ByteArray_Resize(&arr, hdr[6]);
+ fread(arr.data, 1, arr.size, f);
+ LoadFuncState state = { arr.data, arr.data + arr.size };
+ snes_saveload(g_snes, &loadFunc, &state);
+ ByteArray_Destroy(&arr);
+ assert(state.p == state.pend);
+ }
+ CopyStateAfterSnapshotRestore(is_reset);
+}
+
+void StateRecorder_Save(StateRecorder *sr, FILE *f) {
+ uint32 hdr[8] = { 0 };
+ ByteArray arr = {0};
+ SaveSnesState(&arr);
+ assert(sr->base_snapshot.size == 0 || sr->base_snapshot.size == arr.size);
+
+ hdr[0] = 1;
+ hdr[1] = sr->total_frames;
+ hdr[2] = sr->log.size;
+ hdr[3] = sr->last_inputs;
+ hdr[4] = sr->frames_since_last;
+ hdr[5] = sr->base_snapshot.size ? 1 : 0;
+ hdr[6] = arr.size;
+
+ fwrite(hdr, 8, 4, f);
+ fwrite(sr->log.data, 1, sr->log.size, f);
+ fwrite(sr->base_snapshot.data, 1, sr->base_snapshot.size, f);
+ fwrite(arr.data, 1, arr.size, f);
+
+ ByteArray_Destroy(&arr);
+}
+
+void StateRecorder_MigrateToBaseSnapshot(StateRecorder *sr) {
+ printf("Migrating to base snapshot!\n");
+ sr->base_snapshot.size = 0;
+ SaveSnesState(&sr->base_snapshot);
+ sr->replay_mode = false;
+ sr->frames_since_last = 0;
+ sr->last_inputs = 0;
+ sr->total_frames = 0;
+ sr->log.size = 0;
+}
+
+uint16 StateRecorder_ReadNextReplayState(StateRecorder *sr) {
+ assert(sr->replay_mode);
+ while (sr->frames_since_last >= sr->replay_next_cmd_at) {
+ sr->frames_since_last = 0;
+ // Apply next command
+ if (sr->replay_cmd != 0xff) {
+ if (sr->replay_cmd < 0xc0) {
+ sr->last_inputs ^= 1 << (sr->replay_cmd >> 4);
+ } else if (sr->replay_cmd < 0xd0) {
+ int nb = 1 + ((sr->replay_cmd >> 2) & 3);
+ uint8 t;
+ if (nb == 4) do {
+ nb += t = sr->log.data[sr->replay_pos++];
+ } while (t == 255);
+ uint32 addr = ((sr->replay_cmd >> 1) & 1) << 16;
+ addr |= sr->log.data[sr->replay_pos++] << 8;
+ addr |= sr->log.data[sr->replay_pos++];
+ do {
+ g_emulated_ram[addr & 0x1ffff] = g_ram[addr & 0x1ffff] = sr->log.data[sr->replay_pos++];
+ } while (addr++, --nb);
+ } else {
+ assert(0);
+ }
+ }
+ if (sr->replay_pos >= sr->log.size) {
+ sr->replay_cmd = 0xff;
+ sr->replay_next_cmd_at = 0xffffffff;
+ break;
+ }
+ // Read the next one
+ uint8 cmd = sr->log.data[sr->replay_pos++], t;
+ int mask = (cmd < 0xc0) ? 0xf : 0x1;
+ int frames = cmd & mask;
+ if (frames == mask) do {
+ frames += t = sr->log.data[sr->replay_pos++];
+ } while (t == 255);
+ sr->replay_next_cmd_at = frames;
+ sr->replay_cmd = cmd;
+ }
+ sr->frames_since_last++;
+ // Turn off replay mode after we reached the final frame position
+ if (++sr->replay_frame_counter >= sr->total_frames) {
+ sr->replay_mode = false;
+ }
+ return sr->last_inputs;
+}
+
+static int frame_ctr;
+
+int IncrementCrystalCountdown(uint8 *a, int v) {
+ int t = *a + v;
+ *a = t;
+ return t >> 8;
+}
+
+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 (state_recorder.replay_mode) {
+ input_state = StateRecorder_ReadNextReplayState(&state_recorder);
+ } else {
+ StateRecorder_Record(&state_recorder, 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;
+ StateRecorder_RecordPatchByte(&state_recorder, 0x648, &apui00, 1);
+ }
+
+ // Whenever we're no longer replaying, we'll remember what bugs were fixed,
+ // but only if game is initialized.
+ if (g_ram[kRam_BugsFixed] < kBugFix_Latest && animated_tile_data_src != 0) {
+ g_emulated_ram[kRam_BugsFixed] = g_ram[kRam_BugsFixed] = kBugFix_Latest;
+ StateRecorder_RecordPatchByte(&state_recorder, kRam_BugsFixed, &g_ram[kRam_BugsFixed], 1);
+ }
+ }
+
+ int run_what;
+ if (g_ram[kRam_BugsFixed] < kBugFix_PolyRenderer) {
+ // A previous version of this code alternated the game loop with
+ // the poly renderer.
+ run_what = (is_nmi_thread_active && thread_other_stack != 0x1f31) ? 2 : 1;
+ } else {
+ // The snes seems to let poly rendering run for a little
+ // while each fram until it eventually completes a frame.
+ // Simulate this by rendering the poly every n:th frame.
+ run_what = (is_nmi_thread_active && IncrementCrystalCountdown(&g_ram[kRam_CrystalRotateCounter], virq_trigger)) ? 3 : 1;
+ g_emulated_ram[kRam_CrystalRotateCounter] = g_ram[kRam_CrystalRotateCounter];
+ }
+
+ if (snes == NULL) {
+ ZeldaRunFrame(input_state, run_what);
+ 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, run_what);
+ MakeSnapshot(&g_snapshot_theirs);
+
+ // Run my version and snapshot
+again_mine:
+ ZeldaRunFrame(input_state, run_what);
+
+ MakeMySnapshot(&g_snapshot_mine);
+
+ // Compare both snapshots
+ VerifySnapshotsEq(&g_snapshot_mine, &g_snapshot_theirs, &g_snapshot_before);
+
+ if (g_fail) {
+ g_fail = false;
+ 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)
+ StateRecorder_Load(&state_recorder, f, cmd == kSaveLoad_Replay);
+ else
+ StateRecorder_Save(&state_recorder, f);
+
+ fclose(f);
+ }
+}
+
+void ZeldaReadSram(Snes *snes) {
+ FILE *f = fopen("saves/sram.dat", "rb");
+ if (f) {
+ fread(g_zenv.sram, 1, 8192, f);
+ memcpy(snes->cart->ram, g_zenv.sram, 8192);
+ fclose(f);
+ }
+}
+
+void ZeldaWriteSram() {
+ rename("saves/sram.dat", "saves/sram.bak");
+ FILE *f = fopen("saves/sram.dat", "wb");
+ if (f) {
+ fwrite(g_zenv.sram, 1, 8192, f);
+ fclose(f);
+ } else {
+ fprintf(stderr, "Unable to write saves/sram.dat\n");
+ }
+}
+
+typedef struct StateRecoderMultiPatch {
+ uint32 count;
+ uint32 addr;
+ uint8 vals[256];
+} StateRecoderMultiPatch;
+
+
+void StateRecoderMultiPatch_Init(StateRecoderMultiPatch *mp) {
+ mp->count = mp->addr = 0;
+}
+
+void StateRecoderMultiPatch_Commit(StateRecoderMultiPatch *mp) {
+ if (mp->count)
+ StateRecorder_RecordPatchByte(&state_recorder, mp->addr, mp->vals, mp->count);
+}
+
+void StateRecoderMultiPatch_Patch(StateRecoderMultiPatch *mp, uint32 addr, uint8 value) {
+ if (mp->count >= 256 || addr != mp->addr + mp->count) {
+ StateRecoderMultiPatch_Commit(mp);
+ mp->addr = addr;
+ mp->count = 0;
+ }
+ mp->vals[mp->count++] = value;
+ g_emulated_ram[addr] = g_ram[addr] = value;
+}
+
+void PatchCommand(char c) {
+ StateRecoderMultiPatch mp;
+
+ StateRecoderMultiPatch_Init(&mp);
+ if (c == 'w') {
+ StateRecoderMultiPatch_Patch(&mp, 0xf372, 80); // health filler
+ StateRecoderMultiPatch_Patch(&mp, 0xf373, 80); // magic filler
+ // b.Patch(0x1FE01, 25);
+ } else if (c == 'k') {
+ StateRecorder_MigrateToBaseSnapshot(&state_recorder);
+ } else if (c == 'o') {
+ StateRecoderMultiPatch_Patch(&mp, 0xf36f, 1);
+ }
+ StateRecoderMultiPatch_Commit(&mp);
+}
--- a/zelda_cpu_infra.cpp
+++ /dev/null
@@ -1,919 +1,0 @@
-// 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
-
- // c code is authoritative
- WORD(a->ram[0x1f0a]) = WORD(b->ram[0x1f0a]);
-
- memcpy(&b->ram[0x1f0d], &a->ram[0x1f0d], 0x3f - 0xd);
- memcpy(b->ram + 0x138, a->ram + 0x138, 256 - 0x38); // copy the stack over
-
- 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) {
- Cpu *cpu = snes->cpu;
- cpu->a = cpu->x = cpu->y = 0;
- cpu->e = false;
- cpu->irqWanted = cpu->nmiWanted = cpu->waiting = cpu->stopped = 0;
- cpu_setFlags(cpu, 0x30);
-
- // Run until the wait loop in Interrupt_Reset,
- // Or the polyhedral main function.
- for(int loops = 0;;loops++) {
- snes_printCpuLine(snes);
- cpu_runOpcode(snes->cpu);
- while (snes->dma->dmaBusy)
- dma_doDma(snes->dma);
-
- uint32_t pc = snes->cpu->k << 16 | snes->cpu->pc;
- if (pc == 0x8034 || pc == 0x9f81d && loops >= 10 || pc == 0x8225 || pc == 0x82D2)
- break;
- }
-}
-
-void RunEmulatedSnesFrame(Snes *snes, int run_what) {
- // First call runs until init
- if (snes->cpu->pc == 0x8000 && snes->cpu->k == 0) {
- RunOrigAsmCodeOneLoop(snes);
- g_emulated_ram[0x12] = 1;
- // Fixup uninitialized variable
- *(uint16*)(g_emulated_ram+0xAE0) = 0xb280;
- *(uint16*)(g_emulated_ram+0xAE2) = 0xb280 + 0x60;
- }
-
- // Run poly code
- if (run_what & 2) {
- Cpu *cpu = snes->cpu;
- cpu->sp = 0x1f3e;
- cpu->pc = 0xf81d;
- cpu->db = cpu->k = 9;
- cpu->dp = 0x1f00;
- RunOrigAsmCodeOneLoop(snes);
- }
-
- // Run main code
- if (run_what & 1) {
- Cpu *cpu = g_snes->cpu;
- cpu->sp = 0x1ff;
- cpu->pc = 0x8034;
- cpu->k = cpu->dp = cpu->db = 0;
- RunOrigAsmCodeOneLoop(snes);
- }
-
- snes_doAutoJoypad(snes);
-
- // animated_tile_vram_addr uninited
- if (snes->ram[0xadd] == 0)
- *(uint16_t*)&snes->ram[0xadc] = 0xa680;
-
- // In one code path flag_update_hud_in_nmi uses an undefined value
- snes_write(snes, DMAP0, 0x01);
- snes_write(snes, BBAD0, 0x18);
-
- // Run NMI handler
- Cpu *cpu = g_snes->cpu;
- cpu->sp = 0x1ff;
- cpu->pc = 0x80D9;
- cpu->k = cpu->dp = cpu->db = 0;
- RunOrigAsmCodeOneLoop(snes);
-}
-
-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;
-}
-
-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;
-
-int IncrementCrystalCountdown(uint8 *a, int v) {
- int t = *a + v;
- *a = t;
- return t >> 8;
-}
-
-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[kRam_APUI00]) {
- g_emulated_ram[kRam_APUI00] = g_ram[kRam_APUI00] = apui00;
- input_recorder.RecordPatchByte(kRam_APUI00, &apui00, 1);
- }
-
- // Whenever we're no longer replaying, we'll remember what bugs were fixed,
- // but only if game is initialized.
- if (g_ram[kRam_BugsFixed] < kBugFix_Latest && animated_tile_data_src != 0) {
- g_emulated_ram[kRam_BugsFixed] = g_ram[kRam_BugsFixed] = kBugFix_Latest;
- input_recorder.RecordPatchByte(kRam_BugsFixed, &g_ram[kRam_BugsFixed], 1);
- }
- }
-
- int run_what;
- if (g_ram[kRam_BugsFixed] < kBugFix_PolyRenderer) {
- // A previous version of this code alternated the game loop with
- // the poly renderer.
- run_what = (is_nmi_thread_active && thread_other_stack != 0x1f31) ? 2 : 1;
- } else {
- // The snes seems to let poly rendering run for a little
- // while each fram until it eventually completes a frame.
- // Simulate this by rendering the poly every n:th frame.
- run_what = (is_nmi_thread_active && IncrementCrystalCountdown(&g_ram[kRam_CrystalRotateCounter], virq_trigger)) ? 3 : 1;
- g_emulated_ram[kRam_CrystalRotateCounter] = g_ram[kRam_CrystalRotateCounter];
- }
-
- if (snes == NULL) {
- ZeldaRunFrame(input_state, run_what);
- 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, run_what);
- MakeSnapshot(&g_snapshot_theirs);
-
- // Run my version and snapshot
-again_mine:
- ZeldaRunFrame(input_state, run_what);
-
- MakeMySnapshot(&g_snapshot_mine);
-
- // Compare both snapshots
- VerifySnapshotsEq(&g_snapshot_mine, &g_snapshot_theirs, &g_snapshot_before);
-
- if (g_fail) {
- g_fail = false;
- 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);
- }
-}
--- a/zelda_cpu_infra.h
+++ b/zelda_cpu_infra.h
@@ -3,5 +3,6 @@
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);
+void RunEmulatedFuncSilent(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b, int whatflags);
+void RunEmulatedFunc(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b, int whatflags);
+
--- /dev/null
+++ b/zelda_rtl.c
@@ -1,0 +1,287 @@
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "misc.h"
+#include "nmi.h"
+#include "poly.h"
+#include "attract.h"
+#include "snes/ppu.h"
+
+ZeldaEnv g_zenv;
+// These point to the rewritten instance of the emu.
+uint8 g_ram[131072];
+typedef struct SimpleHdma {
+ const uint8 *table;
+ const uint8 *indir_ptr;
+ uint8 rep_count;
+ uint8 mode;
+ uint8 ppu_addr;
+ uint8 indir_bank;
+} SimpleHdma;
+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
+};
+const uint16 kUpperBitmasks[] = { 0x8000, 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100, 0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1 };
+const uint8 kLitTorchesColorPlus[] = {31, 8, 4, 0};
+const uint8 kDungeonCrystalPendantBit[13] = {0, 0, 4, 2, 0, 16, 2, 1, 64, 4, 1, 32, 8};
+const int8 kGetBestActionToPerformOnTile_x[4] = { 7, 7, -3, 16 };
+const int8 kGetBestActionToPerformOnTile_y[4] = { 6, 24, 12, 12 };
+#define AT_WORD(x) (uint8)(x), (x)>>8
+// direct
+static const uint8 kAttractDmaTable0[13] = {0x20, AT_WORD(0x00ff), 0x50, AT_WORD(0xe018), 0x50, AT_WORD(0xe018), 1, AT_WORD(0x00ff), 0};
+static const uint8 kAttractDmaTable1[10] = {0x48, AT_WORD(0x00ff), 0x30, AT_WORD(0xd830), 1, AT_WORD(0x00ff), 0};
+static const uint8 kHdmaTableForEnding[19] = {
+ 0x52, AT_WORD(0x600), 8, AT_WORD(0xe2), 8, AT_WORD(0x602), 5, AT_WORD(0x604), 0x10, AT_WORD(0x606), 0x81, AT_WORD(0xe2), 0,
+};
+static const uint8 kSpotlightIndirectHdma[7] = {0xf8, AT_WORD(0x1b00), 0xf8, AT_WORD(0x1bf0), 0};
+static const uint8 kMapModeHdma0[7] = {0xf0, AT_WORD(0xdd27), 0xf0, AT_WORD(0xde07), 0};
+static const uint8 kMapModeHdma1[7] = {0xf0, AT_WORD(0xdee7), 0xf0, AT_WORD(0xdfc7), 0};
+static const uint8 kAttractIndirectHdmaTab[7] = {0xf0, AT_WORD(0x1b00), 0xf0, AT_WORD(0x1be0), 0};
+static const uint8 kHdmaTableForPrayingScene[7] = {0xf8, AT_WORD(0x1b00), 0xf8, AT_WORD(0x1bf0), 0};
+void zelda_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[kRam_APUI00];
+}
+
+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) {
+ 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 ZeldaRunPolyLoop() {
+ if (intro_did_run_step && !nmi_flag_update_polyhedral) {
+ Poly_RunFrame();
+ intro_did_run_step = 0;
+ nmi_flag_update_polyhedral = 0xff;
+ }
+}
+
+void ZeldaRunFrame(uint16 input, int run_what) {
+ if (animated_tile_data_src == 0)
+ ZeldaInitializationCode();
+
+ if (run_what & 2)
+ ZeldaRunPolyLoop();
+ if (run_what & 1)
+ ZeldaRunGameLoop();
+ Interrupt_NMI(input);
+}
+
+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);
+}
+
--- a/zelda_rtl.cpp
+++ /dev/null
@@ -1,283 +1,0 @@
-#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[kRam_APUI00];
-}
-
-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 ZeldaRunPolyLoop() {
- if (intro_did_run_step && !nmi_flag_update_polyhedral) {
- Poly_RunFrame();
- intro_did_run_step = 0;
- nmi_flag_update_polyhedral = 0xff;
- }
-}
-
-void ZeldaRunFrame(uint16 input, int run_what) {
- if (animated_tile_data_src == 0)
- ZeldaInitializationCode();
-
- if (run_what & 2)
- ZeldaRunPolyLoop();
- if (run_what & 1)
- ZeldaRunGameLoop();
- Interrupt_NMI(input);
-}
-
-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);
-}
-
--- a/zelda_rtl.h
+++ b/zelda_rtl.h
@@ -1,3 +1,5 @@
+#ifndef ZELDA_RTL_H
+#define ZELDA_RTL_H
#pragma once
#include <stdio.h>
@@ -8,39 +10,39 @@
#include "types.h"
#include "snes_regs.h"
+#include "snes/dma.h"
+#include "snes/ppu.h"
+#include "spc_player.h"
-
-struct ZeldaEnv {
+typedef struct ZeldaEnv {
uint8 *ram;
uint8 *sram;
uint16 *vram;
- struct Ppu *ppu;
- struct SpcPlayer *player;
- struct Dma *dma;
-};
+ Ppu *ppu;
+ SpcPlayer *player;
+ Dma *dma;
+} ZeldaEnv;
extern ZeldaEnv g_zenv;
+
// it's here so that the variables.h can access it
extern uint8 g_ram[131072];
+extern const uint16 kUpperBitmasks[];
+extern const uint8 kLitTorchesColorPlus[];
+extern const uint8 kDungeonCrystalPendantBit[];
+extern const int8 kGetBestActionToPerformOnTile_x[];
+extern const int8 kGetBestActionToPerformOnTile_y[];
+static inline void zelda_snes_dummy_write(uint32 adr, uint8 val) {}
-
-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 {
+typedef struct MovableBlockData {
uint16 room;
uint16 tilemap;
-};
+} MovableBlockData;
-struct OamEntSigned {
+typedef struct OamEntSigned {
int8 x, y;
uint8 charnum, flags;
-};
+} OamEntSigned;
@@ -47,12 +49,9 @@
#define movable_block_datas ((MovableBlockData*)(g_ram+0xf940))
#define oam_buf ((OamEnt*)(g_ram+0x800))
-
-
-
-struct OwScrollVars {
+typedef struct OwScrollVars {
uint16 ystart, yend, xstart, xend;
-};
+} OwScrollVars;
#define ow_scroll_vars0 (*(OwScrollVars*)(g_ram+0x600))
#define ow_scroll_vars1 (*(OwScrollVars*)(g_ram+0x608))
@@ -59,9 +58,6 @@
#define ow_scroll_vars0_exit (*(OwScrollVars*)(g_ram+0xC154))
-
-
-
extern const uint8 kLayoutQuadrantFlags[];
extern const uint8 kVariousPacks[16];
extern const uint8 kMaxBombsForLevel[];
@@ -75,7 +71,7 @@
// forwards
-struct MirrorHdmaVars {
+typedef struct MirrorHdmaVars {
uint16 var0;
uint16 var1[2];
uint16 var3[2];
@@ -88,7 +84,7 @@
uint16 var11;
uint16 pad;
uint8 ctr2, ctr;
-};
+} MirrorHdmaVars;
// Special RAM locations that are unused but I use for compat things.
@@ -199,4 +195,8 @@
void ClearOamBuffer();
void Startup_InitializeMemory();
void LoadSongBank(const uint8 *p);
+void NORETURN Die(const char *error);
void ZeldaWriteSram();
+void ZeldaReadSram(Snes *snes);
+
+#endif // ZELDA_RTL_H