shithub: zelda3

ref: 71b1c3c020f663a42eadba05437758932cda31cb
dir: /ancilla.c/

View raw version
#include "ancilla.h"
#include "variables.h"
#include "sprite.h"
#include "hud.h"
#include "load_gfx.h"
#include "tagalong.h"
#include "overworld.h"
#include "tile_detect.h"
#include "player.h"
#include "misc.h"
#include "dungeon.h"
#include "sprite_main.h"
#include "assets.h"

static const uint8 kAncilla_Pflags[68] = {
  0,    8,  0xc, 0x10, 0x10,    4, 0x10, 0x18,    8,    8,    8,    0, 0x14, 0, 0x10, 0x28,
  0x18, 0x10, 0x10, 0x10, 0x10,  0xc,    8,    8, 0x50,    0, 0x10,    8, 0x40, 0,  0xc, 0x24,
  0x10,  0xc,    8, 0x10, 0x10,    4,  0xc, 0x1c,    0, 0x10, 0x14, 0x14, 0x10, 8, 0x20, 0x10,
  0x10, 0x10,    4,    0, 0x80, 0x10,    4, 0x30, 0x14, 0x10,    0, 0x10,    0, 0,    8,    0,
  0x10,    8, 0x78, 0x80,
};
static const int8 kFireRod_Xvel2[12] = {0, 0, -40, 40, 0, 0, -48, 48, 0, 0, -64, 64};
static const int8 kFireRod_Yvel2[12] = {-40, 40, 0, 0, -48, 48, 0, 0, -64, 64, 0, 0};
static const uint8 kTagalongLayerBits[4] = {0x20, 0x10, 0x30, 0x20};
static const uint8 kBombos_Sfx[8] = {0x80, 0x80, 0x80, 0, 0, 0x40, 0x40, 0x40};
const uint8 kBomb_Tab0[11] = {0xA0, 6, 4, 4, 4, 4, 4, 6, 6, 6, 6};

#define swordbeam_temp_x (*(uint16*)(g_ram+0x1580E))
#define swordbeam_temp_y (*(uint16*)(g_ram+0x15810))
#define swordbeam_arr ((uint8*)(g_ram+0x15800))
#define swordbeam_var1 (*(uint8*)(g_ram+0x15804))
#define swordbeam_var2 (*(uint8*)(g_ram+0x15808))
static const int8 kAncilla_TileColl_Attrs[256] = {
  0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
  1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 3, 3, 3,
  0, 0, 0, 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4,
  1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 3, 3, 3,
  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
static const uint8 kAncilla_TileColl0_Attrs[256] = {
  0, 1, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
  1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 3, 3, 3,
  0, 0, 0, 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4,
  1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 3, 3, 3,
  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
static const uint8 kBomb_Draw_Tab0[12] = {0, 1, 2, 3, 2, 3, 4, 5, 6, 7, 8, 9};
static const uint8 kBomb_Draw_Tab2[11] = {1, 4, 4, 4, 4, 4, 5, 4, 6, 6, 6};

static const uint8 kMagicPowder_Tab0[40] = {
  13, 14, 15, 0,  1,  2,  3, 4, 5, 6, 10, 11, 12, 0, 1, 2,
  3,  4,  5, 6, 16, 17, 18, 0, 1, 2,  3,  4,  5, 6, 7, 8,
  9,  0,  1, 2,  3,  4,  5, 6,
};
#define ether_arr1 ((uint8*)(g_ram+0x15800))
#define ether_var2 (*(uint8*)(g_ram+0x15808))
#define ether_y2 (*(uint16*)(g_ram+0x1580A))
#define ether_y_adjusted (*(uint16*)(g_ram+0x1580C))
#define ether_x2 (*(uint16*)(g_ram+0x1580E))
#define ether_y3 (*(uint16*)(g_ram+0x15810))
#define ether_var1 (*(uint8*)(g_ram+0x15812))
#define ether_y (*(uint16*)(g_ram+0x15813))
#define ether_x (*(uint16*)(g_ram+0x15815))
static const uint8 kEther_BlitzOrb_Char[8] = {0x48, 0x48, 0x4a, 0x4a, 0x4c, 0x4c, 0x4e, 0x4e};
static const uint8 kEther_BlitzOrb_Flags[8] = {0x3c, 0x7c, 0x3c, 0x7c, 0x3c, 0x7c, 0x3c, 0x7c};
static const uint8 kEther_BlitzSegment_Char[4] = {0x40, 0x42, 0x44, 0x46};
#define bombos_arr1 ((uint8*)(g_ram+0x15800))
#define bombos_arr2 ((uint8*)(g_ram+0x15810))
static const uint8 kBombosBlasts_Tab[72] = {
  0xb6, 0x5d, 0xa1, 0x30, 0x69, 0xb5, 0xa3, 0x24, 0x96, 0xac, 0x73, 0x5f, 0x92, 0x48, 0x52, 0x81,
  0x39, 0x95, 0x7f, 0x20, 0x88, 0x5d, 0x34, 0x98, 0xbc, 0xd2, 0x51, 0x77, 0xa2, 0x47, 0x94, 0xb2,
  0x34, 0xda, 0x30, 0x62, 0x9f, 0x76, 0x51, 0x46, 0x98, 0x5c, 0x9b, 0x61, 0x58, 0x95, 0x4c, 0xba,
  0x7e, 0xcb, 0x12, 0xd0, 0x70, 0xa6, 0x46, 0xbf, 0x40, 0x50, 0x7e, 0x8c, 0x2d, 0x61, 0xac, 0x88,
  0x20, 0x6a, 0x72, 0x5f, 0xd2, 0x28, 0x52, 0x80,
};
static const uint8 kQuake_Tab1[5] = {0x17, 0x16, 0x17, 0x16, 0x10};
static const uint8 kQuakeDrawGroundBolts_Char[15] = { 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x63 };
typedef struct QuakeItem {
  int8 x, y;
  uint8 f;
} QuakeItem;
static const QuakeItem kQuakeItems[] = {
  {0, -16, 0x00},
  {0, -16, 0x01},
  {0, -16, 0x02},
  {0, -16, 0x03},
  {0, -16, 0x43},
  {0, -16, 0x42},
  {0, -16, 0x41},
  {0, -16, 0x40},
  {0, -16, 0x40}, {14, -8, 0x84},
  {29, -8, 0x44}, {13, -7, 0x84},
  {31, -7, 0x44}, {47, -4, 0x84},
  {49, -11, 0x06}, {63, -5, 0x44}, {47, -4, 0x84},
  {36, -17, 0x08}, {49, -11, 0x06}, {63, -5, 0x44}, {78, 4, 0x08},
  {22, -31, 0x08}, {36, -17, 0x08}, {78, 4, 0x08}, {93, 20, 0x08},
  {7, -46, 0x08}, {23, -45, 0x48}, {22, -31, 0x08}, {93, 20, 0x08}, {93, 36, 0x48},
  {-7, -61, 0x08}, {37, -59, 0x48}, {7, -46, 0x08}, {23, -45, 0x48}, {93, 36, 0x48}, {93, 52, 0x08},
  {-22, -75, 0x08}, {47, -74, 0x01}, {-8, -61, 0x08}, {36, -60, 0x48}, {93, 52, 0x08}, {108, 67, 0x08},
  {-37, -90, 0x08}, {-22, -75, 0x08}, {47, -74, 0x01}, {59, -62, 0x81}, {108, 67, 0x08}, {121, 80, 0x08},
  {-44, -104, 0xc9}, {-37, -90, 0x08}, {73, -74, 0x48}, {59, -62, 0x81}, {121, 80, 0x08},
  {-44, -120, 0x09}, {-44, -104, 0xc9}, {87, -89, 0x48}, {73, -74, 0x48},
  {-44, -120, 0x09}, {102, -104, 0x48}, {87, -89, 0x48},
  {102, -104, 0x48}, {87, -89, 0x48},
  {112, -116, 0x48}, {102, -104, 0x48},
  {112, -116, 0x48},
  {-13, -16, 0x00},
  {-13, -16, 0x01},
  {-13, -16, 0x02},
  {-13, -16, 0x03},
  {-11, -16, 0x43},
  {-11, -16, 0x42},
  {-11, -16, 0x41},
  {-11, -16, 0x40}, {-24, -10, 0x04},
  {-38, -18, 0x08}, {-24, -10, 0x04}, {-40, -7, 0xc4},
  {-45, -33, 0xc9}, {-38, -18, 0x08}, {-57, -7, 0x04}, {-40, -7, 0xc4},
  {-48, -45, 0x07}, {-45, -33, 0xc9}, {-57, -7, 0x04}, {-71, 2, 0x48},
  {-48, -45, 0x06}, {-71, 2, 0x48}, {-70, 18, 0x08},
  {-48, -45, 0x05}, {-70, 18, 0x08}, {-56, 33, 0x08},
  {-48, -45, 0x07}, {-54, 34, 0x08}, {-54, 49, 0x88},
  {-48, -45, 0x06}, {-54, 49, 0x88}, {-69, 64, 0x88},
  {-48, -45, 0x07}, {-69, 64, 0x88}, {-85, 73, 0xc4},
  {-48, -45, 0x05}, {-101, 73, 0x04}, {-85, 73, 0xc4},
  {-60, -53, 0x08}, {-48, -45, 0x06}, {-101, 73, 0x04}, {-116, 77, 0xc4},
  {-75, -67, 0x08}, {-60, -53, 0x08}, {-128, 76, 0x04}, {-116, 77, 0xc4},
  {-90, -82, 0x08}, {-75, -67, 0x08}, {-128, 76, 0x04},
  {-105, -97, 0x08}, {-90, -82, 0x08},
  {-120, -111, 0x08}, {-105, -97, 0x08},
  {-120, -111, 0x08},
  {0, -5, 0x0a},
  {0, -5, 0x0b},
  {2, -3, 0x0c},
  {1, -3, 0x0d},
  {0, -3, 0x8d},
  {1, -3, 0x8c},
  {1, -3, 0x8b},
  {1, -3, 0x8a}, {-6, 12, 0x89},
  {-6, 12, 0x89}, {-10, 28, 0xc9},
  {-10, 28, 0x49}, {-8, 44, 0x89},
  {-8, 44, 0x89}, {-10, 56, 0x02},
  {-10, 56, 0x02}, {-23, 70, 0x48}, {5, 70, 0x08},
  {-23, 70, 0x48}, {5, 70, 0x08}, {-38, 85, 0x48}, {19, 85, 0x08},
  {-38, 85, 0x48}, {19, 85, 0x08}, {-52, 99, 0x48}, {33, 101, 0x08},
  {-52, 99, 0x48}, {33, 101, 0x08}, {-66, 113, 0x48}, {47, 115, 0x08},
  {-66, 113, 0x48}, {47, 115, 0x08},
};
static const uint8 kQuakeItemPos[] = {
  0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 17, 21, 25, 30,
  36, 42, 48, 53, 57, 60, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 107, 111, 114, 116, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 130, 132, 134, 137, 141, 145, 149, 151
};
static const QuakeItem kQuakeItems2[] = {
  {-96, 112, 0x20},
  {-96, 112, 0x21},
  {-96, 112, 0x66},
  {-96, 112, 0x22},
  {-96, 112, 0x23},
  {-96, 112, 0x63},
  {-96, 112, 0x62},
  {-96, 112, 0x26},
  {-96, 112, 0x27}, {-86, 124, 0x28},
  {-86, 124, 0x28}, {-72, -117, 0x28},
  {-72, -117, 0x28}, {-59, -102, 0xa1},
  {-59, -102, 0xa1}, {-44, -116, 0x68},
  {-44, -116, 0x68}, {-29, 126, 0x68},
  {-29, 126, 0x68},
  {-19, 125, 0xc5},
  {-112, 96, 0x2a},
  {-112, 96, 0x2b},
  {-112, 96, 0x2c},
  {-112, 96, 0x2d},
  {-119, 82, 0x29}, {-112, 96, 0x2a},
  {-123, 66, 0xe9}, {-119, 82, 0x29},
  {-121, 50, 0x29}, {-123, 66, 0xe9},
  {126, 34, 0x28}, {-115, 34, 0x68}, {-121, 50, 0x29},
  {-106, 18, 0xa9}, {111, 19, 0x28}, {126, 34, 0x28}, {-115, 34, 0x68},
  {-100, 2, 0x68}, {102, 4, 0xe9}, {-106, 18, 0xa9}, {111, 19, 0x28},
  {-91, -14, 0xa9}, {95, -11, 0x28}, {-100, 2, 0x68}, {102, 4, 0xe9},
  {96, 112, 0x60},
  {96, 112, 0x61},
  {96, 112, 0x26},
  {96, 112, 0x62},
  {96, 112, 0x63},
  {96, 112, 0x23},
  {96, 112, 0x22},
  {96, 112, 0x66},
  {85, 111, 0xe8}, {96, 112, 0x67},
  {70, 104, 0x24}, {85, 111, 0xe8},
  {70, 104, 0x24}, {54, 108, 0xe4},
  {40, 100, 0x28}, {38, 107, 0x24}, {54, 108, 0xe4},
  {25, 85, 0x28}, {40, 100, 0x28}, {38, 107, 0x24}, {22, 110, 0xe4},
  {11, 70, 0x28}, {25, 85, 0x28}, {7, 108, 0x24}, {22, 110, 0xe4},
  {11, 70, 0x28}, {7, 108, 0x24},
  {112, 112, 0x2a},
  {112, 112, 0x2b},
  {112, 112, 0x2c},
  {112, 112, 0x2d},
  {112, 112, 0x2a}, {108, 125, 0x29},
  {108, 125, 0x29}, {114, -116, 0x28},
  {114, -116, 0x28}, {124, -100, 0x29},
  {124, -100, 0x29}, {123, -84, 0xe9},
  {123, -84, 0xe9}, {117, -74, 0xe4}, {-124, -69, 0x28},
  {117, -74, 0xe4}, {-124, -69, 0x28}, {103, -67, 0x68}, {-110, -54, 0x28},
  {103, -67, 0x68}, {-110, -54, 0x28}, {95, -52, 0x69}, {-102, -39, 0x29},
  {95, -52, 0x69}, {-102, -39, 0x29}, {96, -36, 0xe9}, {-102, -24, 0xe9},
  {96, -36, 0xe9}, {-102, -24, 0xe9},
  {-123, -14, 0x29}, {-115, -14, 0x2e}, {49, -12, 0x28},
};
static const uint8 kQuakeItemPos2[] = {
  0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 19, 20, 21, 22, 23, 24, 26, 28, 30, 33, 37, 41, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 57, 59, 62, 66, 70, 72, 73, 74, 75, 76, 78, 80, 82, 84, 87, 91, 95, 99, 101, 104
};
static const uint8 kReceiveItem_Tab4[3] = {9, 5, 5};
static const uint8 kReceiveItem_Tab5[3] = {0x24, 0x25, 0x26};
static const uint8 kReceiveItem_Tab0[3] = {5, 1, 4};
static const int16 kReceiveItemMsgs[76] = {
  -1, 0x70, 0x77, 0x52,   -1, 0x78,  0x78, 0x62, 0x61, 0x66, 0x69, 0x53, 0x52, 0x56,   -1,  0x64,
  0x63, 0x65, 0x51, 0x54, 0x67, 0x68,  0x6b, 0x77, 0x79, 0x55, 0x6e, 0x58, 0x6d, 0x5d, 0x57,  0x5e,
  -1, 0x74, 0x75, 0x76,   -1, 0x5f, 0x158,   -1, 0x6a, 0x5c, 0x8f, 0x71, 0x72, 0x73, 0x71,  0x72,
  0x73, 0x6a, 0x6c, 0x60,   -1,   -1,    -1, 0x59, 0x84, 0x5a,   -1,   -1,   -1,   -1,   -1, 0x159,
  -1,   -1,   -1,   -1,   -1,   -1,    -1,   -1,   -1, 0xdb, 0x67, 0x7c,
};
static const int16 kReceiveItemMsgs2[2] = {0x5b, 0x83};
static const int16 kReceiveItemMsgs3[4] = {-1, 0x155, 0x156, 0x157};
static const uint8 kTravelBird_DmaStuffs[4] = {0, 0x20, 0x40, 0xe0};
static const int8 kTravelBird_Draw_X[3] = {0, -9, -9};
static const int8 kTravelBird_Draw_Y[3] = {0, 12, 20};
static const uint8 kTravelBird_Draw_Char[3] = {0xe, 0, 2};
static const uint8 kTravelBird_Draw_Flags[3] = {0x22, 0x2e, 0x2e};
static const int8 kSomarianBlock_Coll_X[12] = {0, 0, -8, 8, 0, 0, 0, 0, 8, -8, -8, 8};
static const int8 kSomarianBlock_Coll_Y[12] = {-8, 8, 0, 0, 0, 0, 0, 0, -8, 8, -8, 8};
static HandlerFuncK *const kAncilla_Funcs[67] = {
  &Ancilla01_SomariaBullet,
  &Ancilla02_FireRodShot,
  &Ancilla_Empty,
  &Ancilla04_BeamHit,
  &Ancilla05_Boomerang,
  &Ancilla06_WallHit,
  &Ancilla07_Bomb,
  &Ancilla08_DoorDebris,
  &Ancilla09_Arrow,
  &Ancilla0A_ArrowInTheWall,
  &Ancilla0B_IceRodShot,
  &Ancilla_SwordBeam,
  &Ancilla0D_SpinAttackFullChargeSpark,
  &Ancilla33_BlastWallExplosion,
  &Ancilla33_BlastWallExplosion,
  &Ancilla33_BlastWallExplosion,
  &Ancilla11_IceRodWallHit,
  &Ancilla33_BlastWallExplosion,
  &Ancilla13_IceRodSparkle,
  &Ancilla_Unused_14,
  &Ancilla15_JumpSplash,
  &Ancilla16_HitStars,
  &Ancilla17_ShovelDirt,
  &Ancilla18_EtherSpell,
  &Ancilla19_BombosSpell,
  &Ancilla1A_PowderDust,
  &Ancilla_SwordWallHit,
  &Ancilla1C_QuakeSpell,
  &Ancilla1D_ScreenShake,
  &Ancilla1E_DashDust,
  &Ancilla1F_Hookshot,
  &Ancilla20_Blanket,
  &Ancilla21_Snore,
  &Ancilla22_ItemReceipt,
  &Ancilla23_LinkPoof,
  &Ancilla24_Gravestone,
  &Ancilla_Unused_25,
  &Ancilla26_SwordSwingSparkle,
  &Ancilla27_Duck,
  &Ancilla28_WishPondItem,
  &Ancilla29_MilestoneItemReceipt,
  &Ancilla2A_SpinAttackSparkleA,
  &Ancilla2B_SpinAttackSparkleB,
  &Ancilla2C_SomariaBlock,
  &Ancilla2D_SomariaBlockFizz,
  &Ancilla2E_SomariaBlockFission,
  &Ancilla2F_LampFlame,
  &Ancilla30_ByrnaWindupSpark,
  &Ancilla31_ByrnaSpark,
  &Ancilla32_BlastWallFireball,
  &Ancilla33_BlastWallExplosion,
  &Ancilla34_SkullWoodsFire,
  &Ancilla35_MasterSwordReceipt,
  &Ancilla36_Flute,
  &Ancilla37_WeathervaneExplosion,
  &Ancilla38_CutsceneDuck,
  &Ancilla39_SomariaPlatformPoof,
  &Ancilla3A_BigBombExplosion,
  &Ancilla3B_SwordUpSparkle,
  &Ancilla3C_SpinAttackChargeSparkle,
  &Ancilla3D_ItemSplash,
  &Ancilla_RisingCrystal,
  &Ancilla3F_BushPoof,
  &Ancilla40_DwarfPoof,
  &Ancilla41_WaterfallSplash,
  &Ancilla42_HappinessPondRupees,
  &Ancilla43_GanonsTowerCutscene,
};
uint16 Ancilla_GetX(int k) {
  return ancilla_x_lo[k] | ancilla_x_hi[k] << 8;
}

uint16 Ancilla_GetY(int k) {
  return ancilla_y_lo[k] | ancilla_y_hi[k] << 8;
}

void Ancilla_SetX(int k, uint16 x) {
  ancilla_x_lo[k] = x;
  ancilla_x_hi[k] = x >> 8;
}

void Ancilla_SetY(int k, uint16 y) {
  ancilla_y_lo[k] = y;
  ancilla_y_hi[k] = y >> 8;
}

int Ancilla_AllocHigh() {
  for (int k = 9; k >= 0; k--) {
    if (ancilla_type[k] == 0)
      return k;
  }
  return -1;
}

static void Ancilla_SetOam(OamEnt *oam, uint16 x, uint16 y, uint8 charnum, uint8 flags, uint8 big) {
  uint8 yval = 0xf0;
  int xt = enhanced_features0 & kFeatures0_ExtendScreen64 ? 0x40 : 0;
  if ((uint16)(x + xt) < 256 + xt * 2 && y < 256) {
    big |= (x >> 8) & 1;
    oam->x = x;
    if (y < 0xf0)
      yval = y;
  }
  oam->y = yval;
  oam->charnum = charnum;
  oam->flags = flags;
  bytewise_extended_oam[oam - oam_buf] = big;
}

static void Ancilla_SetOam_Safe(OamEnt *oam, uint16 x, uint16 y, uint8 charnum, uint8 flags, uint8 big) {
  uint8 yval = 0xf0;
  oam->x = x;
  int xt = enhanced_features0 & kFeatures0_ExtendScreen64 ? 0x48 : 0;
  if ((uint16)(x + 0x80) < (0x180 + xt)) {
    big |= (x >> 8) & 1;
    if ((uint16)(y + 0x10) < 0x100)
      yval = y;
  }
  oam->y = yval;
  oam->charnum = charnum;
  oam->flags = flags;
  bytewise_extended_oam[oam - oam_buf] = big;
}

void Ancilla_Empty(int k) {
}

void Ancilla_Unused_14(int k) {
  assert(0);
}

void Ancilla_Unused_25(int k) {
  assert(0);
}

void SpinSpark_Draw(int k, int offs) {
  static const uint8 kInitialSpinSpark_Char[32] = {
    0x92, 0xff, 0xff, 0xff, 0x8c, 0x8c, 0x8c, 0x8c, 0xd6, 0xd6, 0xd6, 0xd6, 0x93, 0x93, 0x93, 0x93,
    0xd6, 0xd6, 0xd6, 0xd6, 0xd7, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x22, 0xff, 0xff, 0xff,  // wtf oob
  };
  static const uint8 kInitialSpinSpark_Flags[29] = {
    0x22, 0xff, 0xff, 0xff, 0x22, 0x62, 0xa2, 0xe2, 0x24, 0x64, 0xa4, 0xe4, 0x22, 0x62, 0xa2, 0xe2,
    0x22, 0x62, 0xa2, 0xe2, 0x22, 0xff, 0xff, 0xff, 0x22, 0xff, 0xff, 0xff,
    0xfc,
  };
  static const int8 kInitialSpinSpark_Y[29] = {
    -4,  0, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0,
    -8, -8, 0, 0, -4,  0, 0, 0, -4,  0, 0, 0,
    -4,
  };
  static const int16 kInitialSpinSpark_X[29] = {
    -4, 0,  0, 0, -8, 0, -8, 0, -8, 0, -8, 0, -8, 0, -8, 0,
    -8, 0, -8, 0, -4, 0,  0, 0, -4, 0,  0, 0,
    0x11a5
  };
  Point16U info;
  Ancilla_PrepOamCoord(k, &info);
  OamEnt *oam = GetOamCurPtr();
  int t = (ancilla_item_to_link[k] + offs) * 4;
  assert(t < 32);
  for(int i = 0; i < 4; i++, t++) {
    if (kInitialSpinSpark_Char[t] != 0xff) {
      Ancilla_SetOam(oam, info.x + kInitialSpinSpark_X[t], info.y + kInitialSpinSpark_Y[t],
                     kInitialSpinSpark_Char[t], kInitialSpinSpark_Flags[t] & ~0x30 | HIBYTE(oam_priority_value), 0);
      oam++;
    }
  }
}

bool SomarianBlock_CheckEmpty(OamEnt *oam) {
  for (int i = 0; i != 4; i++) {
    if (oam[i].y == 0xf0)
      continue;
    for (i = 0; i < 4; i++)
      if (!(bytewise_extended_oam[oam + i - oam_buf] & 1))
        return false;
    break;
  }
  return true;
}

void AddDashingDustEx(uint8 a, uint8 y, uint8 flag) {
  static const int8 kAddDashingDust_X[4] = {4, 4, 6, 0};
  static const int8 kAddDashingDust_Y[4] = {20, 4, 16, 16};
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_step[k] = flag;
    ancilla_item_to_link[k] = 0;
    ancilla_timer[k] = 3;
    int j = link_direction_facing >> 1;
    ancilla_dir[k] = j;
    if (!flag) {
      Ancilla_SetXY(k, link_x_coord, link_y_coord + 20);
    } else {
      Ancilla_SetXY(k, link_x_coord + kAddDashingDust_X[j], link_y_coord + kAddDashingDust_Y[j]);
    }
  }
}

void AddBirdCommon(int k) {
  ancilla_y_vel[k] = 0;
  ancilla_item_to_link[k] = 0;
  ancilla_aux_timer[k] = 1;
  ancilla_x_vel[k] = 56;
  ancilla_arr3[k] = 3;
  ancilla_K[k] = 0;
  ancilla_G[k] = 0;

  int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
  Ancilla_SetXY(k, BG2HOFS_copy2 - 16 - xt, link_y_coord - 8);
}

ProjectSpeedRet Bomb_ProjectSpeedTowardsPlayer(int k, uint16 x, uint16 y, uint8 vel) {  // 84eb63
  uint16 old_x = Sprite_GetX(0), old_y = Sprite_GetY(0), old_z = sprite_z[0];
  Sprite_SetX(0, x);
  Sprite_SetY(0, y);
  sprite_z[0] = 0;
  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(0, vel);
  sprite_z[0] = old_z;
  Sprite_SetX(0, old_x);
  Sprite_SetY(0, old_y);
  return pt;
}

void Boomerang_CheatWhenNoOnesLooking(int k, ProjectSpeedRet *pt) {  // 86809f
  uint16 x = link_x_coord - Ancilla_GetX(k) + 0xf0;
  uint16 y = link_y_coord - Ancilla_GetY(k) + 0xf0;
  if (x >= 0x1e0) {
    pt->x = sign16(x - 0x1e0) ? 0x90 : 0x70;
  } else if (y >= 0x1e0) {
    pt->y = sign16(y - 0x1e0) ? 0x90 : 0x70;
  }
}

void Medallion_CheckSpriteDamage(int k) {  // 86ec5c
  tmp_counter = ancilla_type[k];
  for (int j = 15; j >= 0; j--) {
    if (sprite_state[j] >= 9 && !(sprite_ignore_projectile[j] | sprite_pause[j])) {
      Ancilla_CheckDamageToSprite_aggressive(j, tmp_counter);
    }
  }
}

void Ancilla_CheckDamageToSprite(int k, uint8 type) {  // 86ecb7
  if (!sign8(sprite_hit_timer[k]))
    Ancilla_CheckDamageToSprite_aggressive(k, type);
}

void Ancilla_CheckDamageToSprite_aggressive(int k, uint8 type) {  // 86ecbd
  static const uint8 kAncilla_Damage[57] = {
    6, 1, 11, 0, 0, 0, 0, 8,  0,  6, 0, 12,  1, 0, 0,  0,
    0, 1,  0, 0, 0, 0, 0, 0, 14, 13, 0,  0, 15, 0, 0,  7,
    1, 1,  1, 1, 1, 1, 1, 1,  1,  1, 1,  1,  1, 1, 1, 11,
    0, 1,  1, 1, 1, 1, 1, 1,  1,
  };
  uint8 dmg = kAncilla_Damage[type];
  if (dmg == 6 && link_item_bow >= 3) {
    if (sprite_type[k] == 0xd7)
      sprite_delay_aux4[k] = 32;
    dmg = 9;
  }
  Ancilla_CheckDamageToSprite_preset(k, dmg);
}

void CallForDuckIndoors() {  // 87a45f
  Ancilla_Sfx2_Near(0x13);
  AncillaAdd_Duck_take_off(0x27, 4);
}

void Ancilla_Sfx1_Pan(int k, uint8 v) {  // 888020
  byte_7E0CF8 = v;
  sound_effect_ambient = v | Ancilla_CalculateSfxPan(k);
}

void Ancilla_Sfx2_Pan(int k, uint8 v) {  // 888027
  byte_7E0CF8 = v;
  sound_effect_1 = v | Ancilla_CalculateSfxPan(k);
}

void Ancilla_Sfx3_Pan(int k, uint8 v) {  // 88802e
  byte_7E0CF8 = v;
  sound_effect_2 = v | Ancilla_CalculateSfxPan(k);
}

void AncillaAdd_FireRodShot(uint8 type, uint8 y) {  // 8880b3
  static const int8 kFireRod_X[4] = {0, 0, -8, 16};
  static const int8 kFireRod_Y[4] = {-8, 16, 3, 3};
  static const int8 kFireRod_Xvel[4] = {0, 0, -64, 64};
  static const int8 kFireRod_Yvel[4] = {-64, 64, 0, 0};

  y = 1;
  int j= Ancilla_AllocInit(type, 1);
  if (j < 0) {
    if (type != 1)
      Refund_Magic(0);
    return;
  }

  if (type != 1)
    Ancilla_Sfx2_Near(0xe);

  ancilla_type[j] = type;
  ancilla_numspr[j] = kAncilla_Pflags[type];
  ancilla_timer[j] = 3;
  ancilla_step[j] = 0;
  ancilla_item_to_link[j] = 0;
  ancilla_objprio[j] = 0;
  ancilla_U[j] = 0;
  int i = link_direction_facing >> 1;
  ancilla_dir[j] = i;

  if (Ancilla_CheckInitialTile_A(j) < 0) {
    Ancilla_SetXY(j, link_x_coord + kFireRod_X[i], link_y_coord + kFireRod_Y[i]);
    if (type != 1) {
      ancilla_x_vel[j] = kFireRod_Xvel[i];
      ancilla_y_vel[j] = kFireRod_Yvel[i];
    } else {
      i += (link_sword_type - 2) * 4;
      ancilla_x_vel[j] = kFireRod_Xvel2[i];
      ancilla_y_vel[j] = kFireRod_Yvel2[i];
    }
    ancilla_floor[j] = link_is_on_lower_level;
    ancilla_floor2[j] = link_is_on_lower_level_mirror;
  } else {
    if (type == 1) {
      ancilla_type[j] = 4;
      ancilla_timer[j] = 7;
      ancilla_numspr[j] = 16;
    } else {
      ancilla_step[j] = 1;
      ancilla_timer[j] = 31;
      ancilla_numspr[j] = 8;
      j = link_direction_facing >> 1; // wtf
      Ancilla_Sfx2_Pan(j, 0x2a);
    }
  }
}

void SomariaBlock_SpawnBullets(int k) {  // 8881a7
  static const int8 kSpawnCentrifugalQuad_X[4] = {-8, -8, -9, -4};
  static const int8 kSpawnCentrifugalQuad_Y[4] = {-15, -4, -8, -8};

  uint8 z = (ancilla_z[k] == 0xff) ? 0 : ancilla_z[k];
  uint16 x = Ancilla_GetX(k);
  uint16 y = Ancilla_GetY(k) - z;

  for (int i = 3; i >= 0; i--) {
    int j = Ancilla_AllocInit(1, 4);
    if (j >= 0) {
      ancilla_type[j] = 0x1;
      ancilla_numspr[j] = kAncilla_Pflags[0x1];
      ancilla_step[j] = 4;
      ancilla_item_to_link[j] = 0;
      ancilla_objprio[j] = 0;
      ancilla_dir[j] = i;
      Ancilla_SetXY(j, x + kSpawnCentrifugalQuad_X[i], y + kSpawnCentrifugalQuad_Y[i]);
      Ancilla_TerminateIfOffscreen(j);
      ancilla_x_vel[j] = kFireRod_Xvel2[i];
      ancilla_y_vel[j] = kFireRod_Yvel2[i];
      ancilla_floor[j] = ancilla_floor[k];
      ancilla_floor2[j] = link_is_on_lower_level_mirror;
    }
  }
  tmp_counter = 0xff;
}

void Ancilla_Main() {  // 888242
  Ancilla_WeaponTink();
  Ancilla_ExecuteAll();
}

ProjectSpeedRet Ancilla_ProjectReflexiveSpeedOntoSprite(int k, uint16 x, uint16 y, uint8 vel) {  // 88824d
  uint16 old_x = link_x_coord, old_y = link_y_coord;
  link_x_coord = x;
  link_y_coord = y;
  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, vel);
  link_x_coord = old_x;
  link_y_coord = old_y;
  return pt;
}

void Bomb_CheckSpriteDamage(int k) {  // 888287
  for (int j = 15; j >= 0; j--) {
    if ((j ^ frame_counter) & 3 | sprite_hit_timer[j] | sprite_ignore_projectile[j])
      continue;
    if (sprite_floor[j] != ancilla_floor[k] || sprite_state[j] < 9)
      continue;
    SpriteHitBox hb;
    int ax = Ancilla_GetX(k) - 24;
    int ay = Ancilla_GetY(k) - 24 - ancilla_z[k];
    hb.r0_xlo = ax;
    hb.r8_xhi = ax >> 8;
    hb.r1_ylo = ay;
    hb.r9_yhi = ay >> 8;
    hb.r2 = 48;
    hb.r3 = 48;
    Sprite_SetupHitBox(j, &hb);
    if (!CheckIfHitBoxesOverlap(&hb))
      continue;
    if (sprite_type[j] == 0x92 && sprite_C[j] >= 3)
      continue;
    Ancilla_CheckDamageToSprite(j, ancilla_type[k]);
    ProjectSpeedRet pt = Ancilla_ProjectReflexiveSpeedOntoSprite(j, Ancilla_GetX(k), Ancilla_GetY(k), 64);
    sprite_x_recoil[j] = -pt.x;
    sprite_y_recoil[j] = -pt.y;
  }
}

void Ancilla_ExecuteAll() {  // 88832b
  for (int i = 9; i >= 0; i--) {
    cur_object_index = i;
    if (ancilla_type[i])
      Ancilla_ExecuteOne(ancilla_type[i], i);
  }
}

void Ancilla_ExecuteOne(uint8 type, int k) {  // 88833c
  if (k < 6) {
    ancilla_oam_idx[k] = Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, ancilla_numspr[k]);
  }

  if (submodule_index == 0 && ancilla_timer[k] != 0)
    ancilla_timer[k]--;

  kAncilla_Funcs[type - 1](k);
}

void Ancilla13_IceRodSparkle(int k) {  // 888435
  static const uint8 kIceShotSparkle_X[16] = {2, 7, 6, 1, 1, 7, 7, 1, 0, 7, 8, 1, 4, 9, 4, 0xff};
  static const uint8 kIceShotSparkle_Y[16] = {2, 3, 8, 7, 1, 1, 7, 7, 1, 0, 7, 8, 0xff, 4, 9, 4};
  static const uint8 kIceShotSparkle_Char[16] = {0x83, 0x83, 0x83, 0x83, 0xb6, 0x80, 0xb6, 0x80, 0xb7, 0xb6, 0xb7, 0xb6, 0xb7, 0xb6, 0xb7, 0xb6};

  if (!ancilla_timer[k])
    ancilla_type[k] = 0;
  if (!submodule_index) {
    Ancilla_MoveX(k);
    Ancilla_MoveY(k);
  }
  AncillaOamInfo info;
  if (Ancilla_ReturnIfOutsideBounds(k, &info))
    return;

  int j;
  for (j = 4; j >= 0 && ancilla_type[j] != 0xb; j--) {}
  if (j >= 0 && ancilla_objprio[j])
    info.flags = 0x30;

  if (sort_sprites_setting) {
    if (ancilla_floor[k])
      Oam_AllocateFromRegionE(0x10);
    else
      Oam_AllocateFromRegionD(0x10);
  } else {
    Oam_AllocateFromRegionA(0x10);
  }

  OamEnt *oam = GetOamCurPtr();
  j = ancilla_timer[k] & 0x1c;
  for (int i = 3; i >= 0; i--, oam++)
    SetOamPlain(oam, info.x + kIceShotSparkle_X[i + j], info.y + kIceShotSparkle_Y[i + j], kIceShotSparkle_Char[i + j], info.flags | 4, 0);
}

void AncillaAdd_IceRodSparkle(int k) {  // 8884c8
  static const int8 kIceShotSparkle_Xvel[4] = {0, 0, -4, 4};
  static const int8 kIceShotSparkle_Yvel[4] = {-4, 4, 0, 0};

  if (submodule_index || !sign8(--ancilla_arr4[k]))
    return;

  ancilla_arr4[k] = 5;
  int j = Ancilla_AllocHigh();
  if (j >= 0) {
    ancilla_type[j] = 0x13;
    ancilla_timer[j] = 15;

    int i = ancilla_dir[k];
    ancilla_x_vel[j] = kIceShotSparkle_Xvel[i];
    ancilla_y_vel[j] = kIceShotSparkle_Yvel[i];

    ancilla_x_lo[j] = ancilla_x_lo[k];
    ancilla_y_lo[j] = ancilla_y_lo[k];
    ancilla_floor[j] = ancilla_floor[k];
    ancilla_numspr[j] = 0;
  }

}

void Ancilla01_SomariaBullet(int k) {  // 88851b
  static const uint8 kSomarianBlast_Mask[6] = {7, 3, 1, 0, 0, 0};

  if (!submodule_index) {
    if (!(frame_counter & kSomarianBlast_Mask[ancilla_step[k]])) {
      Ancilla_MoveX(k);
      Ancilla_MoveY(k);
    }
    if (ancilla_timer[k] == 0) {
      ancilla_timer[k] = 3;
      uint8 a = ancilla_step[k] + 1;
      if (a >= 6)
        a = 4;
      ancilla_step[k] = a;
    }
    if (Ancilla_CheckSpriteCollision(k) >= 0 || Ancilla_CheckTileCollision_staggered(k)) {
      ancilla_type[k] = 4;
      ancilla_timer[k] = 7;
      ancilla_numspr[k] = 16;
    }
  }
  SomarianBlast_Draw(k);
}

bool Ancilla_ReturnIfOutsideBounds(int k, AncillaOamInfo *info) {  // 88862a
  static const uint8 kAncilla_FloorFlags[2] = {0x20, 0x10};
  info->flags = kAncilla_FloorFlags[ancilla_floor[k]];
  if ((info->x = ancilla_x_lo[k] - BG2HOFS_copy2) >= 0xf4 ||
      (info->y = ancilla_y_lo[k] - BG2VOFS_copy2) >= 0xf0) {
    ancilla_type[k] = 0;
    return true;
  }
  return false;
}

void SomarianBlast_Draw(int k) {  // 888650
  static const uint8 kSomarianBlast_Flags[2] = {2, 6};
  AncillaOamInfo info;
  if (Ancilla_ReturnIfOutsideBounds(k, &info))
    return;
  info.flags |= kSomarianBlast_Flags[ancilla_item_to_link[k]];
  if (ancilla_objprio[k])
    info.flags |= 0x30;
  static const int8 kSomarianBlast_Draw_X0[24] = {
    0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
  };
  static const int8 kSomarianBlast_Draw_X1[24] = {
    8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 4, 4, 0, 0, 0, 0,
    8, 8, 0, 0, 0, 0, 8, 8,
  };
  static const uint8 kSomarianBlast_Draw_Y0[24] = {
    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    4, 4, 0, 0, 0, 0, 4, 4,
  };
  static const uint8 kSomarianBlast_Draw_Y1[24] = {
    0, 0,    0, 0, 8, 8, 0x80, 0, 0, 0, 8, 8, 0x80, 8, 8, 8,
    4, 4, 0x80, 8, 8, 8,    4, 4,
  };
  static const uint8 kSomarianBlast_Draw_Flags0[24] = {
    0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0xc0, 0x40, 0x40, 0x40, 0x40, 0, 0x40, 0x40, 0x40, 0x40, 0x40,
    0x40, 0xc0,    0,    0,    0,    0,    0, 0x80,
  };
  static const uint8 kSomarianBlast_Draw_Flags1[24] = {
    0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0,    0, 0, 0, 0, 0x40, 0xc0, 0xc0, 0xc0, 0xc0,
    0x40, 0xc0, 0x80, 0x80, 0x80, 0x80, 0, 0x80,
  };
  static const uint8 kSomarianBlast_Draw_Char0[24] = {
    0x50, 0x50, 0x44, 0x44, 0x52, 0x52, 0x50, 0x50, 0x44, 0x44, 0x51, 0x51, 0x43, 0x43, 0x42, 0x42,
    0x41, 0x41, 0x43, 0x43, 0x42, 0x42, 0x40, 0x40,
  };
  static const uint8 kSomarianBlast_Draw_Char1[24] = {
    0x50, 0x50, 0x44, 0x44, 0x51, 0x51, 0x50, 0x50, 0x44, 0x44, 0x52, 0x52, 0x43, 0x43, 0x42, 0x42,
    0x40, 0x40, 0x43, 0x43, 0x42, 0x42, 0x41, 0x41,
  };
  OamEnt *oam = GetOamCurPtr();
  int j = ancilla_dir[k] * 6 + ancilla_step[k];
  SetOamPlain(oam + 0, info.x + kSomarianBlast_Draw_X0[j], sign8(kSomarianBlast_Draw_Y0[j]) ? 0xf0 : info.y + kSomarianBlast_Draw_Y0[j],
              0x82 + kSomarianBlast_Draw_Char0[j], info.flags | kSomarianBlast_Draw_Flags0[j], 0);
  SetOamPlain(oam + 1, info.x + kSomarianBlast_Draw_X1[j], sign8(kSomarianBlast_Draw_Y1[j]) ? 0xf0 : info.y + kSomarianBlast_Draw_Y1[j],
              0x82 + kSomarianBlast_Draw_Char1[j], info.flags | kSomarianBlast_Draw_Flags1[j], 0);
}

void Ancilla02_FireRodShot(int k) {  // 8886d2
  if (ancilla_step[k] == 0) {
    if (!submodule_index) {
      ancilla_L[k] = 0;
      Ancilla_MoveX(k);
      Ancilla_MoveY(k);
      uint8 coll = Ancilla_CheckSpriteCollision(k) >= 0;
      if (!coll) {
        ancilla_dir[k] |= 8;
        coll = Ancilla_CheckTileCollision(k);
        ancilla_L[k] = ancilla_tile_attr[k];
        if (!coll) {
          ancilla_dir[k] |= 12;
          uint8 bak = ancilla_U[k];
          coll = Ancilla_CheckTileCollision(k);
          ancilla_U[k] = bak;
        }
      }
      if (coll) {
        ancilla_step[k]++;
        ancilla_timer[k] = 31;
        ancilla_numspr[k] = 8;
        Ancilla_Sfx2_Pan(k, 0x2a);
      }
      ancilla_item_to_link[k]++;
      ancilla_dir[k] &= ~0xC;
      if (((byte_7E0333 = ancilla_L[k]) & 0xf0) == 0xc0 || ((byte_7E0333 = ancilla_tile_attr[k]) & 0xf0) == 0xc0)
        Dungeon_LightTorch();
    }
    FireShot_Draw(k);
  } else {
    AncillaOamInfo info;
    Ancilla_CheckBasicSpriteCollision(k);
    if (Ancilla_ReturnIfOutsideBounds(k, &info))
      return;
    OamEnt *oam = GetOamCurPtr();
    if (!ancilla_timer[k]) {
      uint8 old_type = ancilla_type[k];
      ancilla_type[k] = 0;
      if (old_type != 0x2f && BYTE(overworld_screen_index) == 64 && ancilla_tile_attr[k] == 0x43)
        FireRodShot_BecomeSkullWoodsFire(k);
      return;
    }
    int j = ancilla_timer[k] >> 3;
    if (j != 0) {
      static const uint8 kFireShot_Draw_Char[3] = {0xa2, 0xa0, 0x8e};
      SetOamPlain(oam, info.x, info.y, kFireShot_Draw_Char[j - 1], info.flags | 2, 2);
    } else {
      SetOamPlain(oam + 0, info.x + 0, info.y - 3, 0xa4, info.flags | 2, 0);
      SetOamPlain(oam + 1, info.x + 8, info.y - 3, 0xa5, info.flags | 2, 0);
    }
  }
}

void FireShot_Draw(int k) {  // 88877c
  static const uint8 kFireShot_Draw_X2[16] = {7, 0, 8, 0, 8, 4, 0, 0, 2, 8, 0, 0, 1, 4, 9, 0};
  static const uint8 kFireShot_Draw_Y2[16] = {1, 4, 9, 0, 7, 0, 8, 0, 8, 4, 0, 0, 2, 8, 0, 0};
  static const uint8 kFireShot_Draw_Char2[3] = {0x8d, 0x9d, 0x9c};
  AncillaOamInfo info;
  if (Ancilla_ReturnIfOutsideBounds(k, &info))
    return;
  if (ancilla_objprio[k])
    info.flags |= 0x30;

  OamEnt *oam = GetOamCurPtr();
  int j = ancilla_item_to_link[k] & 0xc;
  for (int i = 2; i >= 0; i--, oam++)
    SetOamPlain(oam, info.x + kFireShot_Draw_X2[j + i], info.y + kFireShot_Draw_Y2[j + i], kFireShot_Draw_Char2[i], info.flags | 2, 0);
}

uint8 Ancilla_CheckTileCollision_staggered(int k) {  // 88897b
  if ((frame_counter ^ k) & 1)
    return Ancilla_CheckTileCollision(k);
  return 0;
}

uint8 Ancilla_CheckTileCollision(int k) {  // 888981
  if (!player_is_indoors && ancilla_objprio[k]) {
    ancilla_tile_attr[k] = 0;
    return 0;
  }
  if (!dung_hdr_collision)
    return Ancilla_CheckTileCollisionOneFloor(k);
  uint16 x = 0, y = 0;
  if (dung_hdr_collision < 3) {
    x = BG1HOFS_copy2 - BG2HOFS_copy2;
    y = BG1VOFS_copy2 - BG2VOFS_copy2;
  }
  uint16 oldx = Ancilla_GetX(k), oldy = Ancilla_GetY(k);
  Ancilla_SetX(k, oldx + x);
  Ancilla_SetY(k, oldy + y);
  ancilla_floor[k] = 1;
  uint8 b = Ancilla_CheckTileCollisionOneFloor(k);
  ancilla_floor[k] = 0;
  Ancilla_SetX(k, oldx);
  Ancilla_SetY(k, oldy);
  return (b << 1) | (uint8)Ancilla_CheckTileCollisionOneFloor(k);
}

bool Ancilla_CheckTileCollisionOneFloor(int k) {  // 888a03
  static const int8 kAncilla_CheckTileColl0_X[20] = {
    8, 8, 0, 16, 4, 4, 0, 16, 4, 4, 4, 12, 12, 12, 4, 12, 0, 0, 0, 0,
  };
  static const int8 kAncilla_CheckTileColl0_Y[20] = {
    0, 16, 5, 5, 0, 16, 4, 4, 4, 12, 5, 5, 4, 12, 12, 12, 0, 0, 0, 0,
  };
  uint16 x = Ancilla_GetX(k) + kAncilla_CheckTileColl0_X[ancilla_dir[k]];
  uint16 y = Ancilla_GetY(k) + kAncilla_CheckTileColl0_Y[ancilla_dir[k]];
  return Ancilla_CheckTileCollision_targeted(k, x, y);
}

bool Ancilla_CheckTileCollision_targeted(int k, uint16 x, uint16 y) {  // 888a26
  if ((uint16)(y - BG2VOFS_copy2) >= 224 || (uint16)(x - BG2HOFS_copy2) >= 256)
    return 0;
  uint8 tile_attr;
  if (!player_is_indoors) {
    x >>= 3;
    tile_attr = Overworld_GetTileAttributeAtLocation(x, y);
  } else {
    tile_attr = GetTileAttribute(ancilla_floor[k], &x, y);
  }

  ancilla_tile_attr[k] = tile_attr;
  if (tile_attr == 3 && ancilla_floor2[k])
    return 0;

  uint8 t = kAncilla_TileColl0_Attrs[tile_attr];

  if (ancilla_type[k] == 2 && (tile_attr & 0xf0) == 0xc0)
    t = 0;

  if (!ancilla_objprio[k]) {
    if (t == 0)
      return false;
    if (t == 1)
      goto return_true_set_alert;
    if (t == 2)
      return Entity_CheckSlopedTileCollision(x, y);
    if (t == 3) {
      if (ancilla_floor2[k])
        goto return_true_set_alert;
      return 0;
    }
  }
  if (sign8(--ancilla_U[k])) {
    ancilla_U[k] = 0;
    if (t == 4) {
      ancilla_U[k] = 6;
      ancilla_objprio[k] ^= 1;
    }
  }
  return 0;

return_true_set_alert:
  sprite_alert_flag = 3;
  return 1;
}

bool Ancilla_CheckTileCollision_Class2(int k) {  // 888bcf
  if (!dung_hdr_collision)
    return Ancilla_CheckTileCollision_Class2_Inner(k);
  uint16 x = 0, y = 0;
  if (dung_hdr_collision < 3) {
    x = BG1HOFS_copy2 - BG2HOFS_copy2;
    y = BG1VOFS_copy2 - BG2VOFS_copy2;
  }
  uint16 oldx = Ancilla_GetX(k), oldy = Ancilla_GetY(k);
  Ancilla_SetX(k, oldx + x);
  Ancilla_SetY(k, oldy + y);
  ancilla_floor[k] = 1;
  bool b = Ancilla_CheckTileCollision_Class2_Inner(k);
  ancilla_floor[k] = 0;
  Ancilla_SetX(k, oldx);
  Ancilla_SetY(k, oldy);
  return (b | Ancilla_CheckTileCollision_Class2_Inner(k)) != 0;
}

bool Ancilla_CheckTileCollision_Class2_Inner(int k) {  // 888c43
  static const int8 kAncilla_CheckTileColl_Y[4] = {-8, 8, 0, 0};
  static const int8 kAncilla_CheckTileColl_X[4] = {0, 0, -8, 8};

  uint16 x = Ancilla_GetX(k) + kAncilla_CheckTileColl_X[ancilla_dir[k]];
  uint16 y = Ancilla_GetY(k) + kAncilla_CheckTileColl_Y[ancilla_dir[k]];

  if ((uint16)(y - BG2VOFS_copy2) >= 224 || (uint16)(x - BG2HOFS_copy2) >= 256)
    return false;
  uint8 tile_attr;
  if (!player_is_indoors) {
    x >>= 3;
    tile_attr = Overworld_GetTileAttributeAtLocation(x, y);
  } else {
    tile_attr = GetTileAttribute(ancilla_floor[k], &x, y);
  }

  ancilla_tile_attr[k] = tile_attr;
  if (tile_attr == 3 && ancilla_floor2[k])
    return false;

  uint8 t = kAncilla_TileColl_Attrs[tile_attr];
  if (t == 0)
    return false;
  if (t == 2)
    return Entity_CheckSlopedTileCollision(x, y);
  if (t == 4) {
    if (ancilla_floor2[k])
      return true;
    ancilla_objprio[k] = 1;
    return false;
  }
  if (t == 3)
    return ancilla_floor2[k] != 0;
  return true;
}

void Ancilla04_BeamHit(int k) {  // 888d19
  static const int8 kBeamHit_X[16] = {-12, 20, -12, 20, -8, 16, -8, 16, -4, 12, -4, 12, 0, 8, 0, 8};
  static const int8 kBeamHit_Y[16] = {-12, -12, 20, 20, -8, -8, 16, 16, -4, -4, 12, 12, 0, 0, 8, 8};
  static const uint8 kBeamHit_Char[16] = {0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x54};
  static const uint8 kBeamHit_Flags[16] = {0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80, 0, 0x40, 0x80, 0xc0};
  AncillaOamInfo info;
  if (Ancilla_ReturnIfOutsideBounds(k, &info))
    return;
  if (!ancilla_timer[k]) {
    ancilla_type[k] = 0;
    return;
  }
  OamEnt *oam = GetOamCurPtr();
  int j = ancilla_timer[k] >> 1;
  uint16 ancilla_x = Ancilla_GetX(k);
  uint16 ancilla_y = Ancilla_GetY(k);
  uint8 r7 = ancilla_x - BG2HOFS_copy2;
  uint8 r6 = ancilla_y - BG2VOFS_copy2;
  for (int i = 3; i >= 0; i--, oam++) {
    int m = j * 4 + i;
    uint8 x = info.x + kBeamHit_X[m];
    uint8 y = info.y + kBeamHit_Y[m];
    uint16 x_adj = (uint16)(ancilla_x + (int8)(x - r7) - BG2HOFS_copy2);
    uint16 y_adj = (uint16)(ancilla_y + (int8)(y - r6) - BG2VOFS_copy2 + 0x10);
    SetOamPlain(oam, x, (y_adj >= 0x100) ? 0xf0 : y,
                kBeamHit_Char[m] + 0x82, kBeamHit_Flags[m] | 2 | info.flags, (x_adj >= 0x100) ? 1 : 0);
  }
}

int Ancilla_CheckSpriteCollision(int k) {  // 888d68
  for (int j = 15; j >= 0; j--) {
    if (ancilla_type[k] == 9 || ancilla_type[k] == 0x1f || ((j ^ frame_counter) & 3 | sprite_pause[j]) == 0) {
      if ((sprite_state[j] >= 9 && (sprite_defl_bits[j] & 2 || !ancilla_objprio[k])) && ancilla_floor[k] == sprite_floor[j]) {
        if (Ancilla_CheckSpriteCollision_Single(k, j))
          return j;
      }
    }
  }
  return -1;
}

bool Ancilla_CheckSpriteCollision_Single(int k, int j) {  // 888dae
  int i;
  SpriteHitBox hb;
  Ancilla_SetupHitBox(k, &hb);

  Sprite_SetupHitBox(j, &hb);
  if (!CheckIfHitBoxesOverlap(&hb))
    return false;

  bool return_value = true;
  if (sprite_flags[j] & 8 && ancilla_type[k] == 9) {
    if (sprite_type[j] != 0x1b) {
      Sprite_CreateDeflectedArrow(k);
      return false;
    }
    if (link_item_bow < 3) {
      Sprite_CreateDeflectedArrow(k);
    } else {
      return_value = false;
    }
  }

  if (sprite_defl_bits[j] & 0x10) {
    static const uint8 kAncilla_CheckSpriteColl_Dir[4] = {2, 3, 0, 1};
    ancilla_dir[k] &= 3;
    if (ancilla_dir[k] == kAncilla_CheckSpriteColl_Dir[ancilla_dir[k]])
      goto return_true_set_alert;
  }

  if (ancilla_type[k] == 5 || ancilla_type[k] == 0x1f) {
    if (ancilla_type[k] == 0x1f && sprite_type[j] == 0x8d)
      goto skip;
    if (sprite_hit_timer[j])
      goto return_true_set_alert;
    if (sprite_defl_bits[j] & 2) {
skip:
      sprite_B[j] = k + 1;
      sprite_unk2[j] = ancilla_type[k];
      goto return_true_set_alert;
    }
  }

  if (!sprite_ignore_projectile[j]) {
    static const int8 kAncilla_CheckSpriteColl_RecoilX[4] = {0, 0, -64, 64};
    static const int8 kAncilla_CheckSpriteColl_RecoilY[4] = {-64, 64, 0, 0};
    if (sprite_type[j] == 0x92 && sprite_C[j] < 3)
      goto return_true_set_alert;
    i = ancilla_dir[k] & 3;
    sprite_x_recoil[j] = kAncilla_CheckSpriteColl_RecoilX[i];
    sprite_y_recoil[j] = kAncilla_CheckSpriteColl_RecoilY[i];
    byte_7E0FB6 = k;
    Ancilla_CheckDamageToSprite(j, ancilla_type[k]);
return_true_set_alert:
    sprite_unk2[j] = ancilla_type[k];
    sprite_alert_flag = 3;
    return return_value;
  }
  return false;
}

void Ancilla_SetupHitBox(int k, SpriteHitBox *hb) {  // 888ead
  static const int8 kAncilla_HitBox_X[12] = {4, 4, 4, 4, 3, 3, 2, 11, -16, -16, -1, -8};
  static const int8 kAncilla_HitBox_Y[12] = {4, 4, 4, 4, 2, 11, 3, 3, -1, -8, -16, -16};
  static const uint8 kAncilla_HitBox_W[12] = {8, 8, 8, 8, 1, 1, 1, 1, 32, 32, 8, 8};
  static const uint8 kAncilla_HitBox_H[12] = {8, 8, 8, 8, 1, 1, 1, 1, 8, 8, 32, 32};
  int j = ancilla_dir[k];
  if (ancilla_type[k] == 0xc)
    j |= 8;
  int x = Ancilla_GetX(k) + kAncilla_HitBox_X[j];
  hb->r0_xlo = x;
  hb->r8_xhi = x >> 8;
  int y = Ancilla_GetY(k) + kAncilla_HitBox_Y[j];
  hb->r1_ylo = y;
  hb->r9_yhi = y >> 8;
  hb->r2 = kAncilla_HitBox_W[j];
  hb->r3 = kAncilla_HitBox_H[j];
}

ProjectSpeedRet Ancilla_ProjectSpeedTowardsPlayer(int k, uint8 vel) {  // 888eed
  if (vel == 0) {
    ProjectSpeedRet rv = { 0, 0, 0, 0 };
    return rv;
  }
  PairU8 below = Ancilla_IsBelowLink(k);
  uint8 r12 = sign8(below.b) ? -below.b : below.b;

  PairU8 right = Ancilla_IsRightOfLink(k);
  uint8 r13 = sign8(right.b) ? -right.b : right.b;
  uint8 t;
  bool swapped = false;
  if (r13 < r12) {
    swapped = true;
    t = r12, r12 = r13, r13 = t;
  }
  uint8 xvel = vel, yvel = 0;
  t = 0;
  do {
    t += r12;
    if (t >= r13)
      t -= r13, yvel++;
  } while (--vel);
  if (swapped)
    t = xvel, xvel = yvel, yvel = t;
  ProjectSpeedRet rv = {
    (uint8)(right.a ? -xvel : xvel),
    (uint8)(below.a ? -yvel : yvel),
    right.b,
    below.b
  };
  return rv;
}

PairU8 Ancilla_IsRightOfLink(int k) {  // 888f5c
  uint16 x = link_x_coord - Ancilla_GetX(k);
  PairU8 rv = { (uint8)(sign16(x) ? 1 : 0), (uint8)x };
  return rv;
}

PairU8 Ancilla_IsBelowLink(int k) {  // 888f6f
  int y = link_y_coord - Ancilla_GetY(k);
  PairU8 rv = { (uint8)(sign16(y) ? 1 : 0), (uint8)y };
  return rv;
}

void Ancilla_WeaponTink() {  // 888f89
  if (!repulsespark_timer)
    return;
  sprite_alert_flag = 2;
  if (sign8(--repulsespark_anim_delay)) {
    repulsespark_timer--;
    repulsespark_anim_delay = 1;
  }

  if (sort_sprites_setting) {
    if (repulsespark_floor_status)
      Oam_AllocateFromRegionF(0x10);
    else
      Oam_AllocateFromRegionD(0x10);
  } else {
    Oam_AllocateFromRegionA(0x10);
  }

  uint8 x = repulsespark_x_lo - BG2HOFS_copy2;
  uint8 y = repulsespark_y_lo - BG2VOFS_copy2;

  if (x >= 0xf8 || y >= 0xf0) {
    repulsespark_timer = 0;
    return;
  }

  OamEnt *oam = GetOamCurPtr();
  static const uint8 kRepulseSpark_Flags[4] = {0x22, 0x12, 0x22, 0x22};
  uint8 flags = kRepulseSpark_Flags[repulsespark_floor_status];
  if (repulsespark_timer >= 3) {
    SetOamPlain(oam, x, y, (repulsespark_timer < 9) ? 0x92 : 0x80, flags, 0);
    return;
  }
  static const uint8 kRepulseSpark_Char[3] = { 0x93, 0x82, 0x81 };
  uint8 c = kRepulseSpark_Char[repulsespark_timer];
  SetOamPlain(oam + 0, x - 4, y - 4, c, flags | 0x00, 0);
  SetOamPlain(oam + 1, x + 4, y - 4, c, flags | 0x40, 0);
  SetOamPlain(oam + 2, x - 4, y + 4, c, flags | 0x80, 0);
  SetOamPlain(oam + 3, x + 4, y + 4, c, flags | 0xc0, 0);
}

void Ancilla_MoveX(int k) {  // 889080
  uint32 t = ancilla_x_subpixel[k] + (ancilla_x_lo[k] << 8) + (ancilla_x_hi[k] << 16) + ((int8)ancilla_x_vel[k] << 4);
  ancilla_x_subpixel[k] = t, ancilla_x_lo[k] = t >> 8, ancilla_x_hi[k] = t >> 16;
}

void Ancilla_MoveY(int k) {  // 88908b
  uint32 t = ancilla_y_subpixel[k] + (ancilla_y_lo[k] << 8) + (ancilla_y_hi[k] << 16) + ((int8)ancilla_y_vel[k] << 4);
  ancilla_y_subpixel[k] = t, ancilla_y_lo[k] = t >> 8, ancilla_y_hi[k] = t >> 16;
}

void Ancilla_MoveZ(int k) {  // 8890b7
  uint32 t = ancilla_z_subpixel[k] + (ancilla_z[k] << 8) + ((int8)ancilla_z_vel[k] << 4);
  ancilla_z_subpixel[k] = t, ancilla_z[k] = t >> 8;
}

void Ancilla05_Boomerang(int k) {  // 8890fc
  int hit_spr;
  static const int8 kBoomerang_X0[8] = {0, 0, -8, 8, 8, 8, -8, -8};
  static const int8 kBoomerang_Y0[8] = {-16, 6, 0, 0, -8, 8, -8, 8};

  for (int j = 4; j >= 0; j--) {
    if (ancilla_type[j] == 0x22)
      goto exit_and_draw;
  }
  if (submodule_index)
    goto exit_and_draw;

  if (!(frame_counter & 7))
    Ancilla_Sfx2_Pan(k, 0x9);

  if (!ancilla_aux_timer[k]) {
    if (button_b_frames < 9 && player_handler_timer == 0) {
      if (link_is_bunny_mirror || link_auxiliary_state || link_item_in_hand == 0 && (enhanced_features0 & kFeatures0_MiscBugFixes)) {
        Boomerang_Terminate(k);
        return;
      }
      goto exit_and_draw;
    }
    int j = ancilla_arr23[k] >> 1;
    Ancilla_SetXY(k, link_x_coord + kBoomerang_X0[j], link_y_coord + 8 + kBoomerang_Y0[j]);
    ancilla_aux_timer[k]++;
  }
  // endif_2
  if (ancilla_G[k] && !(frame_counter & 1))
    AncillaAdd_SwordChargeSparkle(k);

  if (ancilla_item_to_link[k]) {
    if (ancilla_K[k])
      ancilla_K[k]++;
    WORD(ancilla_A[k]) = link_y_coord;
    link_y_coord += 8;
    ProjectSpeedRet pt = Ancilla_ProjectSpeedTowardsPlayer(k, ancilla_H[k]);
    Boomerang_CheatWhenNoOnesLooking(k, &pt);
    ancilla_x_vel[k] = pt.x;
    ancilla_y_vel[k] = pt.y;
    link_y_coord = WORD(ancilla_A[k]);
  }

  if (ancilla_y_vel[k])
    ancilla_y_vel[k] += ancilla_K[k];
  Ancilla_MoveY(k);

  if (ancilla_x_vel[k])
    ancilla_x_vel[k] += ancilla_K[k];
  Ancilla_MoveX(k);
  hit_spr = Ancilla_CheckSpriteCollision(k);

  if (!ancilla_item_to_link[k]) {
    if (hit_spr >= 0) {
      ancilla_item_to_link[k] ^= 1;
    } else if (Ancilla_CheckTileCollision(k)) {
      AncillaAdd_BoomerangWallClink(k);
      Ancilla_Sfx2_Pan(k, (ancilla_tile_attr[k] == 0xf0) ? 6 : 5);
      ancilla_item_to_link[k] ^= 1;
    } else if (Boomerang_ScreenEdge(k) || --ancilla_step[k] == 0) {
      ancilla_item_to_link[k] ^= 1;
    } else {
      if (ancilla_step[k] < 5)
        ancilla_K[k]--;
    }
  } else {
    uint8 bak0 = ancilla_objprio[k];
    uint8 bak1 = ancilla_floor[k];
    ancilla_floor[k] = 0;
    Ancilla_CheckTileCollision(k);
    ancilla_floor[k] = bak1;
    ancilla_objprio[k] = bak0;
    Boomerang_StopOffScreen(k);
  }

exit_and_draw:
  Boomerang_Draw(k);
}

bool Boomerang_ScreenEdge(int k) {  // 88924b
  uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
  if (hookshot_effect_index & 3) {
    uint16 t = x + (hookshot_effect_index & 1 ? 16 : 0) - BG2HOFS_copy2;
    if (t >= 0x100)
      return true;
  }
  if (hookshot_effect_index & 12) {
    uint16 t = y + (hookshot_effect_index & 4 ? 16 : 0) - BG2VOFS_copy2;
    if (t >= 0xe2)
      return true;
  }
  return false;
}

void Boomerang_StopOffScreen(int k) {  // 8892ab
  uint16 x = Ancilla_GetX(k) + 8, y = Ancilla_GetY(k) + 8;
  if (x >= link_x_coord && x < (uint16)(link_x_coord + 16) &&
      y >= link_y_coord && y < (uint16)(link_y_coord + 24))
    Boomerang_Terminate(k);
}

void Boomerang_Terminate(int k) {  // 8892f5
  ancilla_type[k] = 0;
  flag_for_boomerang_in_place = 0;
  if (link_item_in_hand & 0x80) {
    link_item_in_hand = 0;
    button_mask_b_y &= ~0x40;
    if (!(button_mask_b_y & 0x80))
      link_cant_change_direction &= ~1;
  }
}

void Boomerang_Draw(int k) {  // 889338
  static const uint8 kBoomerang_Flags[8] = {0xa4, 0xe4, 0x64, 0x24, 0xa2, 0xe2, 0x62, 0x22};
  static const int8 kBoomerang_Draw_XY[8] = {2, -2, 2, 2, -2, 2, -2, -2};
  static const uint16 kBoomerang_Draw_OamIdx[2] = {0x180, 0xd0};
  static const uint8 kBoomerang_Draw_Tab0[2] = {3, 2};
  Point16U info;
  Ancilla_PrepOamCoord(k, &info);

  if (ancilla_item_to_link[k]) {
    ancilla_floor[k] = link_is_on_lower_level;
    oam_priority_value = kTagalongLayerBits[link_is_on_lower_level] << 8;
  }

  if (ancilla_objprio[k])
    oam_priority_value = 0x3000;

  if (!submodule_index && ancilla_aux_timer[k] && sign8(--ancilla_arr3[k])) {
    ancilla_arr3[k] = kBoomerang_Draw_Tab0[ancilla_G[k]];
    ancilla_arr1[k] = (ancilla_arr1[k] + (ancilla_S[k] ? -1 : 1)) & 3;
  }

  int j = ancilla_arr1[k];
  uint16 x = info.x + kBoomerang_Draw_XY[j * 2 + 1];
  uint16 y = info.y + kBoomerang_Draw_XY[j * 2 + 0];
  if (!ancilla_aux_timer[k]) {
    int i = kBoomerang_Draw_OamIdx[sort_sprites_setting];
    oam_ext_cur_ptr = (i >> 2) + 0xa20;
    oam_cur_ptr = i + 0x800;
  }
  Ancilla_SetOam_Safe(GetOamCurPtr(), x, y, 0x26, kBoomerang_Flags[ancilla_G[k] * 4 + j] & ~0x30 | HIBYTE(oam_priority_value), 2);
}

void Ancilla06_WallHit(int k) {  // 8893e8
  if (sign8(--ancilla_arr3[k])) {
    uint8 t = ancilla_item_to_link[k] + 1;
    if (t == 5) {
      ancilla_type[k] = 0;
      return;
    }
    ancilla_item_to_link[k] = t;
    ancilla_arr3[k] = 1;
  }
  WallHit_Draw(k);
}

void Ancilla_SwordWallHit(int k) {  // 8893ff
  sprite_alert_flag = 3;
  if (sign8(--ancilla_aux_timer[k])) {
    uint8 t = ancilla_item_to_link[k] + 1;
    if (t == 8) {
      ancilla_type[k] = 0;
      return;
    }
    ancilla_item_to_link[k] = t;
    ancilla_aux_timer[k] = 1;
  }
  WallHit_Draw(k);
}

void WallHit_Draw(int k) {  // 8894df
  static const int8 kWallHit_X[32] = {
    -4, 0,  0, 0, -4, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, 0,
    -8, 0, -8, 0, -4, 0, 0, 0, -4, 0,  0, 0, -8, 0,  0, 0,
  };
  static const int8 kWallHit_Y[32] = {
    -4,  0, 0, 0, -4, 0, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0,
    -8, -8, 0, 0, -4, 0, 0, 0, -4,  0, 0, 0, -8,  0, 0, 0,
  };
  static const uint8 kWallHit_Char[32] = {
    0x80,    0,    0,    0, 0x92, 0, 0, 0, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82,
    0x93, 0x93, 0x93, 0x93, 0x92, 0, 0, 0, 0xb9,    0,    0,    0, 0x90, 0x90,    0,    0,
  };
  static const uint8 kWallHit_Flags[32] = {
    0x32,    0,    0,    0, 0x32, 0, 0, 0, 0x32, 0x72, 0xb2, 0xf2, 0x32, 0x72, 0xb2, 0xf2,
    0x32, 0x72, 0xb2, 0xf2, 0x32, 0, 0, 0, 0x72,    0,    0,    0, 0x32, 0xf2,    0,    0,
  };
  Point16U info;
  Ancilla_PrepOamCoord(k, &info);

  int t = ancilla_item_to_link[k] * 4;

  OamEnt *oam = GetOamCurPtr();
  for (int n = 3; n >= 0; n--, t++) {
    if (kWallHit_Char[t] != 0) {
      Ancilla_SetOam(oam, info.x + kWallHit_X[t], info.y + kWallHit_Y[t], kWallHit_Char[t],
                     kWallHit_Flags[t] & ~0x30 | HIBYTE(oam_priority_value), 0);
      oam++;
    }
    oam = Ancilla_AllocateOamFromCustomRegion(oam);
  }

}

void Ancilla07_Bomb(int k) {  // 88955a
  if (submodule_index) {
    if (submodule_index == 8 || submodule_index == 16) {
      Ancilla_HandleLiftLogic(k);
    } else if (k + 1 == flag_is_ancilla_to_pick_up && ancilla_K[k] != 0) {
      if (ancilla_K[k] != 3) {
        Ancilla_LatchLinkCoordinates(k, 3);
        Ancilla_LatchAltitudeAboveLink(k);
        ancilla_K[k] = 3;
      }
      Ancilla_LatchCarriedPosition(k);
    }
    Bomb_Draw(k);
    return;
  }
  Ancilla_HandleLiftLogic(k);

  uint16 old_y = Ancilla_LatchYCoordToZ(k);
  uint8 s1a = ancilla_dir[k];
  uint8 s1b = ancilla_objprio[k];
  ancilla_objprio[k] = 0;
  bool flag = Ancilla_CheckTileCollision_Class2(k);

  if (player_is_indoors && ancilla_L[k] && ancilla_tile_attr[k] == 0x1c)
    ancilla_T[k] = 1;

label1:
  if (flag && (!(link_state_bits & 0x80) || link_picking_throw_state)) {
    if (!s1b && !ancilla_arr4[k]) {
      ancilla_arr4[k] = 1;
      int qq = (ancilla_dir[k] == 1) ? 16 : 4;
      if (ancilla_y_vel[k])
        ancilla_y_vel[k] = sign8(ancilla_y_vel[k]) ? qq : -qq;
      if (ancilla_x_vel[k])
        ancilla_x_vel[k] = sign8(ancilla_x_vel[k]) ? 4 : -4;
      if (ancilla_dir[k] == 1 && ancilla_z[k]) {
        ancilla_y_vel[k] = -4;
        ancilla_L[k] = 2;
      }
    }
  } else if (!((k + 1 == flag_is_ancilla_to_pick_up) && (link_state_bits & 0x80)) && (ancilla_z[k] == 0 || ancilla_z[k] == 0xff)) {
    ancilla_dir[k] = 16;
    uint8 bak0 = ancilla_objprio[k];
    Ancilla_CheckTileCollision(k);
    ancilla_objprio[k] = bak0;
    uint8 a = ancilla_tile_attr[k];
    if (a == 0x26) {
      flag = true;
      goto label1;
    } else if (a == 0xc || a == 0x1c) {
      if (dung_hdr_collision != 3) {
        if (ancilla_floor[k] == 0 && ancilla_z[k] != 0 && ancilla_z[k] != 0xff)
          ancilla_floor[k] = 1;
      } else {
        old_y = Ancilla_GetY(k) + dung_floor_y_vel;
        Ancilla_SetX(k, Ancilla_GetX(k) + dung_floor_x_vel);
      }
    } else if (a == 0x20 || (a & 0xf0) == 0xb0 && a != 0xb6 && a != 0xbc) {
      if (!(link_state_bits & 0x80)) {
        if (k + 1 == flag_is_ancilla_to_pick_up)
          flag_is_ancilla_to_pick_up = 0;
        if (!ancilla_timer[k]) {
          ancilla_type[k] = 0;
          return;
        }
      }
    } else if (a == 8) {
      if (k + 1 == flag_is_ancilla_to_pick_up)
        flag_is_ancilla_to_pick_up = 0;
      if (ancilla_timer[k] == 0) {
        Ancilla_SetY(k, Ancilla_GetY(k) - 24);
        Ancilla_TransmuteToSplash(k);
        return;
      }
    } else if (a == 0x68 || a == 0x69 || a == 0x6a || a == 0x6b) {
      Ancilla_ApplyConveyor(k);
      old_y = Ancilla_GetY(k);
    } else {
      ancilla_timer[k] = ancilla_L[k] ? 0 : 2;
    }
  }
  // endif_3

  Ancilla_SetY(k, old_y);
  ancilla_dir[k] = s1a;
  ancilla_objprio[k] |= s1b;
  Bomb_CheckSpriteAndPlayerDamage(k);
  if (!--ancilla_arr3[k]) {
    if (++ancilla_item_to_link[k] == 1) {
      Ancilla_Sfx2_Pan(k, 0xc);
      if (k + 1 == flag_is_ancilla_to_pick_up) {
        flag_is_ancilla_to_pick_up = 0;
        if (link_state_bits & 0x80) {
          link_state_bits = 0;
          link_cant_change_direction = 0;
        }
      }
    }

    if (ancilla_item_to_link[k] == 11) {
      // transmute to door debris?
      ancilla_type[k] = ancilla_step[k] ? 8 : 0;
      return;
    }
    ancilla_arr3[k] = kBomb_Tab0[ancilla_item_to_link[k]];
  }

  if (ancilla_item_to_link[k] == 7 && ancilla_arr3[k] == 2) {
    // check whether the bomb causes any door debris, the bomb
    // will transmute to debris later on.
    door_debris_x[k] = 0;
    Bomb_CheckForDestructibles(Ancilla_GetX(k), Ancilla_GetY(k), k);
    if (door_debris_x[k])
      ancilla_step[k] = 1;
  }
  Bomb_Draw(k);
}

void Ancilla_ApplyConveyor(int k) {  // 8897be
  static const int8 kAncilla_Belt_Xvel[4] = {0, 0, -8, 8};
  static const int8 kAncilla_Belt_Yvel[4] = {-8, 8, 0, 0};
  int j = ancilla_tile_attr[k] - 0x68;
  ancilla_y_vel[k] = kAncilla_Belt_Yvel[j];
  ancilla_x_vel[k] = kAncilla_Belt_Xvel[j];
  Ancilla_MoveY(k);
  Ancilla_MoveX(k);
}

void Bomb_CheckSpriteAndPlayerDamage(int k) {  // 889815
  static const uint8 kBomb_Dmg_Speed[16] = {32, 32, 32, 32, 32, 32, 28, 28, 28, 28, 28, 28, 24, 24, 24, 24};
  static const uint8 kBomb_Dmg_Zvel[16] = {16, 16, 16, 16, 16, 16, 12, 12, 12, 12, 8, 8, 8, 8, 8, 8};
  static const uint8 kBomb_Dmg_Delay[16] = {32, 32, 32, 32, 32, 32, 24, 24, 24, 24, 24, 24, 16, 16, 16, 16};
  static const uint8 kBomb_Dmg_ToLink[3] = {8, 4, 2};

  if (ancilla_item_to_link[k] == 0 || ancilla_item_to_link[k] >= 9)
    return;
  Bomb_CheckSpriteDamage(k);
  if (link_disable_sprite_damage) {
    if (k + 1 == flag_is_ancilla_to_pick_up && link_state_bits & 0x80) {
      link_state_bits &= ~0x80;
      link_cant_change_direction = 0;
    }
    return;
  }

  if (link_auxiliary_state || link_incapacitated_timer || ancilla_floor[k] != link_is_on_lower_level)
    return;

  SpriteHitBox hb;
  hb.r0_xlo = link_x_coord;
  hb.r8_xhi = link_x_coord >> 8;
  hb.r1_ylo = link_y_coord;
  hb.r9_yhi = link_y_coord >> 8;
  hb.r2 = 0x10;
  hb.r3 = 0x18;

  int ax = Ancilla_GetX(k) - 16, ay = Ancilla_GetY(k) - 16;
  hb.r6_spr_xsize = 32;
  hb.r7_spr_ysize = 32;
  hb.r4_spr_xlo = ax;
  hb.r10_spr_xhi = ax >> 8;
  hb.r5_spr_ylo = ay;
  hb.r11_spr_yhi = ay >> 8;

  if (!CheckIfHitBoxesOverlap(&hb))
    return;

  int x = Ancilla_GetX(k) - 8, y = Ancilla_GetY(k) - 12;

  int j = Bomb_GetDisplacementFromLink(k);
  ProjectSpeedRet pt = Bomb_ProjectSpeedTowardsPlayer(k, x, y, kBomb_Dmg_Speed[j]);
  if (countdown_for_blink || flag_block_link_menu == 2)
    return;
  link_actual_vel_x = pt.x;
  link_actual_vel_y = pt.y;

  link_actual_vel_z_copy = link_actual_vel_z = kBomb_Dmg_Zvel[j];
  link_incapacitated_timer = kBomb_Dmg_Delay[j];
  link_auxiliary_state = 1;
  countdown_for_blink = 58;
  if (!(dung_savegame_state_bits & 0x8000))
    link_give_damage = kBomb_Dmg_ToLink[link_armor];

}

void Ancilla_HandleLiftLogic(int k) {  // 889976
  static const uint8 kAncilla_Liftable_Delay[3] = {16, 8, 9};

  if (ancilla_R[k]) {
label_6:
    if (ancilla_item_to_link[k])
      return;
    if (ancilla_K[k] == 3) {
      ancilla_z_vel[k] -= 2;
      Ancilla_MoveZ(k);
      if (ancilla_z[k] && ancilla_z[k] < 252)
        return;
      ancilla_z[k] = 0;
      if (++ancilla_R[k] != 3) {
        ancilla_z_vel[k] = 24;
        return;
      }
      ancilla_K[k] = 0;
    }
    ancilla_R[k] = 0;
    link_speed_setting = 0;
    return;
  }
  if (!ancilla_L[k]) {
    if (!flag_is_ancilla_to_pick_up) {
clear_pickup_item:
      flag_is_ancilla_to_pick_up = 0;
      CheckPlayerCollOut coll;
      if (ancilla_item_to_link[k] || link_state_bits || !Ancilla_CheckLinkCollision(k, 0, &coll) || ancilla_floor[k] != link_is_on_lower_level)
        return;
      if (coll.r8 >= 16 || coll.r10 >= 12) {
        int j = (coll.r8 >= coll.r10) ? (sign8(coll.r4) ? 1 : 0) : (sign8(coll.r6) ? 3 : 2);
        if (j * 2 != link_direction_facing)
          return;
      }
      flag_is_ancilla_to_pick_up = k + 1;
      ancilla_K[k] = 0;
      ancilla_aux_timer[k] = kAncilla_Liftable_Delay[0];
      ancilla_L[k] = 0;
      ancilla_z[k] = 0;
      return;
    }

    if (flag_is_ancilla_to_pick_up != k + 1)
      return;
    if (!link_disable_sprite_damage && link_incapacitated_timer || byte_7E03FD || link_auxiliary_state == 1) {
      ancilla_R[k] = 1;
      ancilla_z_vel[k] = 0;
      flag_is_ancilla_to_pick_up = 0;
      ancilla_arr4[k] = 0;
      goto label_6;
    }
    if (!(link_state_bits & 0x80))
      goto clear_pickup_item;
    int j = ancilla_K[k];
    if (link_picking_throw_state != 2 && flag_is_ancilla_to_pick_up != 0 && j != 3) {
      if (j == 0 && ancilla_aux_timer[k] == 16)
        Ancilla_Sfx2_Pan(k, 0x1d);
      if (sign8(--ancilla_aux_timer[k])) {
        ancilla_K[k] = ++j;
        ancilla_aux_timer[k] = j == 3 ? -2 : kAncilla_Liftable_Delay[j];
        if (j == 3) {
          Ancilla_LatchAltitudeAboveLink(k);
          return;
        }
      }
      Ancilla_LatchLinkCoordinates(k, j);
      return;
    }
    if (j != 3)
      return;

    if (link_picking_throw_state != 2 && (submodule_index != 0 || !((filtered_joypad_L | filtered_joypad_H) & 0x80))) {
      if (ancilla_item_to_link[k])
        return;
      if (player_near_pit_state >= 2) {
        link_speed_setting = 0;
        if (k + 1 == flag_is_ancilla_to_pick_up) {
          flag_is_ancilla_to_pick_up = 0;
          ancilla_type[k] = 0;
        }
        return;
      }
      if (!(link_is_in_deep_water | link_is_bunny_mirror)) {
        Ancilla_LatchCarriedPosition(k);
        return;
      }
      link_state_bits = 0;
    }
    static const int8 kAncilla_Liftable_Yvel[4] = {-32, 32, 0, 0};
    static const int8 kAncilla_Liftable_Xvel[4] = {0, 0, -32, 32};
    j = link_direction_facing >> 1;
    ancilla_dir[k] = j;
    ancilla_z_vel[k] = 24;
    ancilla_y_vel[k] = kAncilla_Liftable_Yvel[j];
    ancilla_x_vel[k] = kAncilla_Liftable_Xvel[j];
    link_picking_throw_state = 2;
    ancilla_L[k] = 1;
    flag_is_ancilla_to_pick_up = 0;
    ancilla_arr4[k] = 0;
    ancilla_K[k] = 0;
    ancilla_objprio[k] = 0;
    Ancilla_Sfx3_Pan(k, 0x13);
  }
  // endif_1
  if (!ancilla_item_to_link[k]) {
    ancilla_z_vel[k] -= 2;
    Ancilla_MoveY(k);
    Ancilla_MoveX(k);
    uint8 old_z = ancilla_z[k];
    Ancilla_MoveZ(k);
    if (ancilla_arr4[k] && ancilla_dir[k] == 1 && !sign8(ancilla_z[k]))
      Ancilla_SetY(k, Ancilla_GetY(k) + (int8)(ancilla_z[k] - old_z));
    if (!sign8(ancilla_z[k]) || ancilla_z[k] == 0xff)
      return;
    ancilla_z[k] = 0;
    Ancilla_Sfx2_Pan(k, 0x21);
    if (++ancilla_L[k] != 3) {
      ancilla_y_vel[k] = (int8)ancilla_y_vel[k] / 2;
      ancilla_x_vel[k] = (int8)ancilla_x_vel[k] / 2;
      ancilla_z_vel[k] = 16;
      ancilla_arr4[k] = 0;
    } else {
      ancilla_z[k] = 0;
      ancilla_L[k] = 0;
      ancilla_arr4[k] = 0;
      link_speed_setting = 0;
      ancilla_y_vel[k] = 0;
      ancilla_x_vel[k] = 0;
      ancilla_z_vel[k] = 0;
      if (ancilla_T[k]) {
        ancilla_floor[k] = ancilla_T[k];
        ancilla_T[k] = 0;
      }
    }
  }
}

void Ancilla_LatchAltitudeAboveLink(int k) {  // 889a4f
  ancilla_z[k] = 17;
  Ancilla_SetY(k, Ancilla_GetY(k) + 17);
  ancilla_objprio[k] = 0;
}

void Ancilla_LatchLinkCoordinates(int k, int j) {  // 889a6a
  static const int8 kAncilla_Func3_X[12] = {8, 8, -4, 20, 8, 8, 8, 8, 8, 8, 8, 8};
  static const int8 kAncilla_Func3_Y[12] = {16, 8, 4, 4, 8, 2, -1, -1, 2, 2, -1, -1};
  j = j * 4 + (link_direction_facing >> 1);
  Ancilla_SetXY(k,
      link_x_coord + kAncilla_Func3_X[j],
      link_y_coord + kAncilla_Func3_Y[j]);
}

void Ancilla_LatchCarriedPosition(int k) {  // 889bef
  static const int8 kAncilla_Func2_Y[6] = {-2, -1, 0, -2, -1, 0};
  link_speed_setting = 12;
  ancilla_floor[k] = link_is_on_lower_level;
  ancilla_floor2[k] = link_is_on_lower_level_mirror;
  uint16 z = link_z_coord;
  if (z == 0xffff)
    z = 0;
  Ancilla_SetXY(k,
    link_x_coord + 8,
    link_y_coord - z + 18 + kAncilla_Func2_Y[link_animation_steps]);
}

uint16 Ancilla_LatchYCoordToZ(int k) {  // 889c7f
  uint16 y = Ancilla_GetY(k);
  int8 z = ancilla_z[k];
  if (ancilla_dir[k] == 1 && z != -1)
    Ancilla_SetY(k, y - z);
  return y;
}

int Bomb_GetDisplacementFromLink(int k) {  // 889cce
  int x = Ancilla_GetX(k), y = Ancilla_GetY(k);
  return ((abs16(link_x_coord + 8 - x) + abs16(link_y_coord + 12 - y)) & 0xfc) >> 2;
}

void Bomb_Draw(int k) {  // 889e9e
  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);

  int z = (int8)ancilla_z[k];
  if (z != 0 && z != -1 && ancilla_K[k] != 3 && ancilla_objprio[k])
    oam_priority_value = 0x3000;
  pt.y -= z;
  int j = kBomb_Draw_Tab0[ancilla_item_to_link[k]] * 6;

  uint8 r11 = 2;
  if (ancilla_item_to_link[k] == 0) {
    r11 = (ancilla_arr3[k] < 0x20) ? ancilla_arr3[k] & 0xe : 4;
  }

  if (ancilla_item_to_link[k] == 0) {
    if (ancilla_L[k] == 0 && (sprite_type[0] == 0x92 || k + 1 == flag_is_ancilla_to_pick_up ) && (!(link_state_bits & 0x80) || ancilla_K[k] != 3 && link_direction_facing == 0)) {
      Ancilla_AllocateOamFromRegion_B_or_E(12);
    } else if (sort_sprites_setting && ancilla_floor[k] && (ancilla_L[k] || k + 1 == flag_is_ancilla_to_pick_up && (link_state_bits & 0x80))) {
      oam_cur_ptr = 0x800 + 0x34 * 4;
      oam_ext_cur_ptr = 0xa20 + 0x34;
    }
  }

  OamEnt *oam = GetOamCurPtr(), *oam_org = oam;
  uint8 numframes = kBomb_Draw_Tab2[ancilla_item_to_link[k]];

  oam += (ancilla_item_to_link[k] == 0 && (ancilla_tile_attr[k] == 9 || ancilla_tile_attr[k] == 0x40)) ? 2 : 0;

  AncillaDraw_Explosion(oam, j, 0, numframes, r11, pt.x, pt.y);
  oam += numframes;

  uint8 r10;
  if (!Bomb_CheckUndersideSpriteStatus(k, &pt, &r10)) {
    if (oam != oam_org + 1)
      oam = oam_org;
    AncillaDraw_Shadow(oam, r10, pt.x, pt.y, HIBYTE(oam_priority_value));
  }
}

void Ancilla08_DoorDebris(int k) {  // 889fb6
  DoorDebris_Draw(k);
  if (sign8(--ancilla_arr26[k])) {
    ancilla_arr26[k] = 7;
    if (++ancilla_arr25[k] == 4)
      ancilla_type[k] = 0;
  }
}

void DoorDebris_Draw(int k) {  // 88a091
  static const uint16 kDoorDebris_XY[64] = {
     4,  7,  3, 17,  8,  8,  7, 17, 11,  7, 10, 16, 16,  7, 17, 17,
    20,  7, 21, 17, 16,  8, 17, 17, 13,  7, 14, 16,  8,  7,  7, 17,
     7,  4, 17,  3,  8,  8, 17,  7,  7, 11, 16, 10,  7, 16, 17, 17,
     7, 20, 17, 21,  8, 16, 17, 17,  7, 13, 16, 14,  7,  8, 17,  7,
  };
  static const uint16 kDoorDebris_CharFlags[32] = {
    0x205e, 0xe05e, 0xa05e, 0x605e, 0x204f, 0x204f, 0x204f, 0x204f, 0x605e, 0x605e, 0x205e, 0xe05e, 0x604f, 0x604f, 0x604f, 0x604f,
    0x205e, 0xe05e, 0xa05e, 0x605e, 0x204f, 0xe04f, 0x204f, 0x204f, 0x605e, 0x605e, 0x205e, 0xe05e, 0x604f, 0x604f, 0x604f, 0x604f,
  };
  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr();
  int y = door_debris_y[k] - BG2VOFS_copy2;
  int x = door_debris_x[k] - BG2HOFS_copy2;
  int j = ancilla_arr25[k] + door_debris_direction[k] * 4;

  for (int i = 0; i != 2; i++) {
    int t = j * 2 + i;
    //kDoorDebris_XY
    uint16 d = kDoorDebris_CharFlags[t];
    Ancilla_SetOam(oam, x + kDoorDebris_XY[t * 2 + 1], y + kDoorDebris_XY[t * 2 + 0],
                   d, (d >> 8) & 0xc0 | HIBYTE(oam_priority_value), 0);
    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
  }
}

void Ancilla09_Arrow(int k) {  // 88a131
  static const int8 kArrow_Y[4] = {-4, 2, 0, 0};
  static const int8 kArrow_X[4] = {0, 0, -4, 4};
  int j;

  if (submodule_index != 0) {
    Arrow_Draw(k);
    return;
  }

  if (!sign8(--ancilla_item_to_link[k])) {
    if (ancilla_item_to_link[k] >= 4)
      return;
  } else {
    ancilla_item_to_link[k] = 0xff;
  }
  Ancilla_MoveY(k);
  Ancilla_MoveX(k);
  if (link_item_bow & 4 && !(frame_counter & 1))
    AncillaAdd_SilverArrowSparkle(k);
  ancilla_S[k] = 255;
  if ((j = Ancilla_CheckSpriteCollision(k)) >= 0) {
    ancilla_x_vel[k] = ancilla_x_lo[k] - sprite_x_lo[j];
    ancilla_y_vel[k] = ancilla_y_lo[k] - sprite_y_lo[j] + sprite_z[j];
    ancilla_S[k] = j;
    if (sprite_type[j] == 0x65) {
      if (sprite_A[j] == 1) {
        sound_effect_2 = 0x2d;
        sprite_delay_aux2[j] = 0x80;
        sprite_delay_aux4[0] = 128;
        if (byte_7E0B88 < 9)
          byte_7E0B88++;
        sprite_B[j] = byte_7E0B88;
        sprite_G[j] += 1;
      } else {
        sprite_delay_aux3[j] = 4;
        byte_7E0B88 = 0;
      }
    } else {
      byte_7E0B88 = 0;
    }
  } else if ((j = Ancilla_CheckTileCollision(k)) != 0) {
    ancilla_H[k] = j >> 1;
    j = ancilla_dir[k] & 3;
    Ancilla_SetX(k, Ancilla_GetX(k) + kArrow_X[j]);
    Ancilla_SetY(k, Ancilla_GetY(k) + kArrow_Y[j]);
    byte_7E0B88 = 0;
  } else {
    Arrow_Draw(k);
    return;
  }
  if (sprite_type[j] != 0x1b)
    Ancilla_Sfx2_Pan(k, 8);
  ancilla_item_to_link[k] = 0;
  ancilla_type[k] = 10;
  ancilla_aux_timer[k] = 1;
  if (ancilla_H[k]) {
    ancilla_x_lo[k] += BG1HOFS_copy2 - BG2HOFS_copy2;
    ancilla_y_lo[k] += BG1VOFS_copy2 - BG2VOFS_copy2;
  }
  Arrow_Draw(k);
}

void Arrow_Draw(int k) {  // 88a36e
  static const uint8 kArrow_Draw_Char[48] = {
    0x2b, 0x2a, 0x2a, 0x2b, 0x3d, 0x3a, 0x3a, 0x3d, 0x2b, 0xff, 0x2b, 0xff, 0x3d, 0xff, 0x3d, 0xff,
    0x3c, 0x2c, 0x3c, 0x2a, 0x3c, 0x2c, 0x3c, 0x2a, 0x2c, 0x3c, 0x2a, 0x3c, 0x2c, 0x3c, 0x2a, 0x3c,
    0x3b, 0x2d, 0x3b, 0x3a, 0x3b, 0x2d, 0x3b, 0x3a, 0x2d, 0x3b, 0x3a, 0x3b, 0x2d, 0x3b, 0x3a, 0x3b,
  };
  static const uint8 kArrow_Draw_Flags[48] = {
    0xa4, 0xa4, 0x24, 0x24, 0x64, 0x64, 0x24, 0x24, 0xa4, 0xff, 0x24, 0xff, 0x64, 0xff, 0x24, 0xff,
    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xe4, 0xa4, 0xa4, 0x24, 0x24, 0x24, 0x24, 0x64, 0x24, 0x24, 0x24,
    0x64, 0x64, 0x64, 0xe4, 0x64, 0xe4, 0x64, 0xe4, 0x24, 0x24, 0x24, 0xa4, 0xa4, 0x24, 0x24, 0xa4,
  };
  static const int8 kArrow_Draw_Y[48] = {
    0,  8, 0, 8, 0, 0, 0, 0,  0,  0, 0, 0, 0, 0, 0, 0,
    0,  8, 0, 8, 0, 8, 0, 8,  0,  8, 0, 8, 0, 8, 0, 8,
    -1, -1, 0, 0, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 0, 0,
  };
  static const int8 kArrow_Draw_X[48] = {
    0, 0, 0, 0,  0,  8, 0, 8, 0, 0, 0, 0,  0,  0, 0, 0,
    1, 1, 0, 0, -1, -2, 0, 0, 1, 1, 0, 0, -2, -1, 0, 0,
    0, 8, 0, 8,  0,  8, 0, 8, 0, 8, 0, 8,  0,  8, 0, 8,
  };
  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);
  if (ancilla_objprio[k])
    HIBYTE(oam_priority_value) = 0x30;
  uint16 x = pt.x, y = pt.y;
  if (ancilla_H[k] != 0) {
    x += BG2VOFS_copy2 - BG1VOFS_copy2;
    y += BG2HOFS_copy2 - BG1HOFS_copy2;
  }
  uint8 r7 = ancilla_item_to_link[k];
  int j = ancilla_dir[k] & ~4;
  if (ancilla_type[k] == 0xa) {
    j = j * 4 + 8 + ((r7 & 8) ? 1 : (r7 & 3));
  } else if (!sign8(r7)) {
    j |= 4;
  }

  j *= 2;

  OamEnt *oam = GetOamCurPtr(), *oam_org = oam;
  uint8 flags = (link_item_bow & 4) ? 2 : 4;
  for (int i = 0; i != 2; i++, j++) {
    if (kArrow_Draw_Char[j] != 0xff) {
      Ancilla_SetOam(oam, x + kArrow_Draw_X[j], y + kArrow_Draw_Y[j],
                     kArrow_Draw_Char[j], kArrow_Draw_Flags[j] & ~0x3E | flags | HIBYTE(oam_priority_value), 0);
      oam++;
    }
  }

  if (oam_org[0].y == 0xf0 && oam_org[1].y == 0xf0)
    ancilla_type[k] = 0;
}

void Ancilla0A_ArrowInTheWall(int k) {  // 88a45b
  int j = ancilla_S[k];
  if (!sign8(j)) {
    if (sprite_state[j] < 9 || sign8(sprite_z[j]) || sprite_ignore_projectile[j] || sprite_defl_bits[j] & 2) {
      ancilla_type[k] = 0;
      return;
    }
    Ancilla_SetX(k, Sprite_GetX(j) + (int8)ancilla_x_vel[k]);
    Ancilla_SetY(k, Sprite_GetY(j) + (int8)ancilla_y_vel[k] - sprite_z[j]);
  }
  if (submodule_index == 0 && --ancilla_aux_timer[k] == 0) {
    ancilla_aux_timer[k] = 2;
    if (++ancilla_item_to_link[k] == 9) {
      ancilla_type[k] = 0;
      return;
    } else if (ancilla_item_to_link[k] & 8) {
      ancilla_aux_timer[k] = 0x80;
    }
  }
  Arrow_Draw(k);
}

void Ancilla0B_IceRodShot(int k) {  // 88a4dd
  if (submodule_index == 0) {
    if (sign8(--ancilla_aux_timer[k])) {
      if (++ancilla_item_to_link[k] & ~1) {
        ancilla_step[k] = 1;
        ancilla_item_to_link[k] = ancilla_item_to_link[k] & 7 | 4;
      }
      ancilla_aux_timer[k] = 3;
    }
    if (ancilla_step[k]) {
      AncillaOamInfo info;
      if (Ancilla_ReturnIfOutsideBounds(k, &info))
        return;
      Ancilla_MoveY(k);
      Ancilla_MoveX(k);
      if (Ancilla_CheckSpriteCollision(k) >= 0 || Ancilla_CheckTileCollision(k)) {
        ancilla_type[k] = 0x11;
        ancilla_numspr[k] = kAncilla_Pflags[0x11];
        ancilla_item_to_link[k] = 0;
        ancilla_aux_timer[k] = 4;
      }
    }
  }
  AncillaAdd_IceRodSparkle(k);
}

void Ancilla11_IceRodWallHit(int k) {  // 88a536
  if (sign8(--ancilla_aux_timer[k])) {
    ancilla_aux_timer[k] = 7;
    if (++ancilla_item_to_link[k] == 2) {
      ancilla_type[k] = 0;
      return;
    }
  }
  IceShotSpread_Draw(k);
}

void IceShotSpread_Draw(int k) {  // 88a571
  static const uint8 kIceShotSpread_CharFlags[16] = {0xcf, 0x24, 0xcf, 0x24, 0xcf, 0x24, 0xcf, 0x24, 0xdf, 0x24, 0xdf, 0x24, 0xdf, 0x24, 0xdf, 0x24};
  static const uint8 kIceShotSpread_XY[16] = {0, 0, 0, 8, 8, 0, 8, 8, 0xf8, 0xf8, 0xf8, 0x10, 0x10, 0xf8, 0x10, 0x10};

  Point16U info;
  Ancilla_PrepOamCoord(k, &info);

  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, ancilla_numspr[k]);
  OamEnt *oam = GetOamCurPtr();
  int j = ancilla_item_to_link[k] * 4;
  for (int i = 0; i != 4; i++, j++) {
    uint16 y = info.y + (int8)kIceShotSpread_XY[j * 2 + 0];
    uint16 x = info.x + (int8)kIceShotSpread_XY[j * 2 + 1];
    uint8 yv = 0xf0;
    if (x < 256 && y < 256) {
      oam->x = x;
      if (y < 224)
        yv = y;
    }
    oam->y = yv;
    oam->charnum = kIceShotSpread_CharFlags[j * 2 + 0];
    oam->flags = kIceShotSpread_CharFlags[j * 2 + 1] & ~0x30 | HIBYTE(oam_priority_value);
    bytewise_extended_oam[oam - oam_buf] = 0;
    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
  }
  oam = GetOamCurPtr();
  if (oam[0].y == 0xf0 && oam[1].y == 0xf0)
    ancilla_type[k] = 0;
}

void Ancilla33_BlastWallExplosion(int k) {  // 88a60e
  if (submodule_index == 0) {
    if (blastwall_var5[k]) {
      if (--blastwall_var6[k] == 0) {
        if (++blastwall_var5[k] != 0 && blastwall_var5[k] < 9) {
          AncillaAdd_BlastWallFireball(0x32, 10, k * 4);
        }
        if (blastwall_var5[k] == 11) {
          blastwall_var5[k] = 0;
          blastwall_var6[k] = 0;
        } else {
          blastwall_var6[k] = 3;
        }
      }
    } else if ((k ^= 1), blastwall_var5[k] == 6 && blastwall_var6[k] == 2 && (uint8)(ancilla_item_to_link[0] + 1) < 7) {
      ancilla_item_to_link[0]++;
      blastwall_var5[k] = 1;
      blastwall_var6[k] = 3;
      for (int i = 3; i >= 0; i--) {
        int8 arr[2] = { 0, 0 };
        int j = blastwall_var7 < 4 ? 1 : 0;
        arr[j] = (i & 2) ? -13 : 13;
        j = k * 4 + i;
        blastwall_var10[j] += arr[0];
        blastwall_var11[j] += arr[1];
        uint16 x = blastwall_var11[j] - BG2HOFS_copy2;
        if (x < 256)
          sound_effect_1 = kBombos_Sfx[x >> 5] | 0xc;
      }
    }
  }

  if (blastwall_var5[ancilla_K[0]]) {
    int i = (ancilla_K[0] == 1) ? 7 : 3;
    do {
      AncillaDraw_BlastWallBlast(ancilla_K[0], blastwall_var11[i], blastwall_var10[i]);
    } while ((--i & 3) != 3);
  }
  if (ancilla_item_to_link[0] == 6) {
    if (blastwall_var5[0] == 0 && blastwall_var5[1] == 0) {
      ancilla_type[0] = 0;
      ancilla_type[1] = 0;
      flag_custom_spell_anim_active = 0;
    }
  }
}

void AncillaDraw_BlastWallBlast(int k, int x, int y) {  // 88a756
  oam_priority_value = 0x3000;
  if (sort_sprites_setting)
    Oam_AllocateFromRegionD(0x18);
  else
    Oam_AllocateFromRegionA(0x18);
  OamEnt *oam = GetOamCurPtr();
  int i = blastwall_var5[k];
  AncillaDraw_Explosion(oam, kBomb_Draw_Tab0[i] * 6, 0, kBomb_Draw_Tab2[i], 0x32,
      x - BG2HOFS_copy2, y - BG2VOFS_copy2);
}

OamEnt *AncillaDraw_Explosion(OamEnt *oam, int frame, int idx, int idx_end, uint8 r11, int x, int y) {  // 88a7ab
  static const int8 kBomb_DrawExplosion_XY[108] = {
     -8,  -8,   0,   0,   0,   0,   0,   0,   0,   0,   0,  0,  -8,  -8,  -8,  0,
      0,  -8,   0,   0,   0,   0,   0,   0, -16, -16, -16,  0,   0, -16,   0,  0,
      0,   0,   0,   0, -16, -16, -16,   0,   0, -16,   0,  0,   0,   0,   0,  0,
     -8,  -8, -21, -22, -21,   8,   9, -22,   9,   8,   0,  0,  -6, -15,   0, -1,
    -16,  -2,  -8,  -7,   0,   0,   0,   0,  -9,  -4, -21, -5, -12, -18, -11,  7,
      0, -15,   4,  -2,  -9,  -4, -22,  -5, -13, -20, -11,  8,   1, -16,   5, -2,
    -20,   4, -12, -19,  -9,  16,  -5,  -2,   2,  -9,  10,  6,
  };
  static const uint8 kBomb_DrawExplosion_CharFlags[108] = {
    0x6e, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8c, 0x22, 0x8c, 0x62,
    0x8c, 0xa2, 0x8c, 0xe2, 0xff, 0xff, 0xff, 0xff, 0x84, 0x22, 0x84, 0x62, 0x84, 0xa2, 0x84, 0xe2,
    0xff, 0xff, 0xff, 0xff, 0x88, 0x22, 0x88, 0x62, 0x88, 0xa2, 0x88, 0xe2, 0xff, 0xff, 0xff, 0xff,
    0x86, 0x22, 0x88, 0x22, 0x88, 0x62, 0x88, 0xa2, 0x88, 0xe2, 0xff, 0xff, 0x86, 0x22, 0x86, 0x62,
    0x86, 0xe2, 0x86, 0xe2, 0xff, 0xff, 0xff, 0xff, 0x86, 0xe2, 0x86, 0x22, 0x86, 0x22, 0x86, 0x62,
    0x86, 0xa2, 0x86, 0xa2, 0x8a, 0xa2, 0x8a, 0x62, 0x8a, 0x22, 0x8a, 0x62, 0x8a, 0x62, 0x8a, 0xe2,
    0x9b, 0x22, 0x9b, 0xa2, 0x9b, 0x62, 0x9b, 0xe2, 0x9b, 0xa2, 0x9b, 0x22,
  };
  static const uint8 kBomb_DrawExplosion_Ext[54] = {
    2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 2, 2, 2, 2,
    1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2,
    2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    0, 0, 0, 0, 0, 0,
  };
  int base_frame = frame;
  do {
    if (kBomb_DrawExplosion_CharFlags[frame * 2] != 0xff) {
      int i = idx + base_frame;
      Ancilla_SetOam_Safe(oam, x + kBomb_DrawExplosion_XY[i * 2 + 1], y + kBomb_DrawExplosion_XY[i * 2 + 0],
                          kBomb_DrawExplosion_CharFlags[frame * 2],
                          kBomb_DrawExplosion_CharFlags[frame * 2 + 1] & ~0x3E | HIBYTE(oam_priority_value) | r11,
                          kBomb_DrawExplosion_Ext[frame]);
      oam++;
    }
  } while (frame++, ++idx != idx_end);
  return oam;
}

void Ancilla15_JumpSplash(int k) {  // 88a80f
  static const uint8 kAncilla_JumpSplash_Char[2] = {0xac, 0xae};

  if (!submodule_index) {
    if (sign8(--ancilla_aux_timer[k])) {
      ancilla_aux_timer[k] = 0;
      ancilla_item_to_link[k] = 1;
    }
    if (ancilla_item_to_link[k]) {
      ancilla_x_vel[k] = ancilla_y_vel[k] = ancilla_y_vel[k] - 4;
      if (ancilla_y_vel[k] < 232) {
        ancilla_type[k] = 0;
        if ((link_is_bunny_mirror || link_player_handler_state == kPlayerState_Swimming) && link_is_in_deep_water)
          CheckAbilityToSwim();
        return;
      }
      Ancilla_MoveX(k);
      Ancilla_MoveY(k);
    }
  }
  Point16U pt;
  Ancilla_PrepOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr();
  int ax = Ancilla_GetX(k);
  int x8 = link_x_coord * 2 - ax - BG2HOFS_copy2;
  int x6 = ax + 12 - BG2HOFS_copy2;
  int j = ancilla_item_to_link[k];
  uint8 flags = 0;
  for (int i = 0; i < 2; i++) {
    Ancilla_SetOam(oam, pt.x, pt.y, kAncilla_JumpSplash_Char[j], 0x24 | flags, 2);
    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
    pt.x = x8;
    flags = 0x40;
  }
  Ancilla_SetOam(oam, x6, pt.y, 0xc0, 0x24, ((j == 1) ? 1 : 2));
}

void Ancilla16_HitStars(int k) {  // 88a8e5
  static const uint8 kAncilla_HitStars_Char[2] = {0x90, 0x91};

  if (!sign8(--ancilla_arr3[k]))
    return;

  ancilla_arr3[k] = 0;
  if (!submodule_index) {
    if (sign8(--ancilla_aux_timer[k])) {
      ancilla_aux_timer[k] = 0;
      ancilla_item_to_link[k] = 1;
    }
    if (ancilla_item_to_link[k]) {
      ancilla_x_vel[k] = (ancilla_y_vel[k] -= 4);
      if (ancilla_y_vel[k] < 232) {
        ancilla_type[k] = 0;
        return;
      }
      Ancilla_MoveY(k);
      Ancilla_MoveX(k);
    }
  }
  Point16U info;
  Ancilla_PrepOamCoord(k, &info);

  uint16 ax = Ancilla_GetX(k);
  uint16 tt = ancilla_B[k] << 8 | ancilla_A[k];

  uint16 r8 = 2 * tt - ax - 8 - BG2HOFS_copy2;

  if (ancilla_step[k] == 2)
    Ancilla_AllocateOamFromRegion_B_or_E(8);

  OamEnt *oam = GetOamCurPtr();
  uint16 x = info.x, y = info.y;
  uint8 flags = 0;
  for (int i = 1; i >= 0; i--) {
    Ancilla_SetOam(oam, x, y,
                   kAncilla_HitStars_Char[ancilla_item_to_link[k]],
                   HIBYTE(oam_priority_value) | 4 | flags, 0);
    flags = 0x40;
    BYTE(x) = r8;
    oam = HitStars_UpdateOamBufferPosition(oam + 1);
  }
}

void Ancilla17_ShovelDirt(int k) {  // 88a9a9
  static const int8 kShovelDirt_XY[8] = {18, -13, -9, 4, 18, 13, -9, -11};
  static const int8 kShovelDirt_Char[2] = {0x40, 0x50};
  Point16U pt;
  Ancilla_PrepOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr();
  if (!ancilla_timer[k]) {
    ancilla_timer[k] = 8;
    if (++ancilla_item_to_link[k] == 2) {
      ancilla_type[k] = 0;
      return;
    }
  }
  int b = ancilla_item_to_link[k];
  int j = b + ((link_direction_facing == 4) ? 0 : 2);
  pt.x += kShovelDirt_XY[j * 2 + 1];
  pt.y += kShovelDirt_XY[j * 2 + 0];
  for (int i = 0; i < 2; i++) {
    Ancilla_SetOam(oam, pt.x + i * 8, pt.y, kShovelDirt_Char[b] + i, 4 | HIBYTE(oam_priority_value), 0);
    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
  }
}

void Ancilla32_BlastWallFireball(int k) {  // 88aa35
  static const uint8 kBlastWallFireball_Char[3] = {0x9d, 0x9c, 0x8d};

  if (!submodule_index) {
    ancilla_item_to_link[k] += 2;
    ancilla_y_vel[k] += ancilla_item_to_link[k];
    Ancilla_MoveY(k);
    Ancilla_MoveX(k);
    if (sign8(--blastwall_var12[k])) {
      ancilla_type[k] = 0;
      return;
    }
  }

  if (sort_sprites_setting)
    Oam_AllocateFromRegionD(4);
  else
    Oam_AllocateFromRegionA(4);

  Point16U pt;
  Ancilla_PrepOamCoord(k, &pt);
  Ancilla_SetOam(GetOamCurPtr(), pt.x, pt.y, kBlastWallFireball_Char[blastwall_var12[k] & 8 ? 0 : blastwall_var12[k] & 4 ? 1 : 2], 0x22, 0);
}

void Ancilla18_EtherSpell(int k) {  // 88aaa0
  if (submodule_index)
    return;

  if (ancilla_step[k] != 0) {
    uint8 flag;

    if (step_counter_for_spin_attack == 0) {
      flag = (++ancilla_arr4[k] & 4) == 0;
    } else {
      flag = step_counter_for_spin_attack == 11;
    }
    if (flag) {
      Palette_ElectroThemedGear();
      Filter_Majorly_Whiten_Bg();
    } else {
      LoadActualGearPalettes();
      Palette_Restore_BG_From_Flash();
    }
  }

  if (ancilla_step[k] == 2) {
    if (sign8(--ancilla_aux_timer[k])) {
      ancilla_aux_timer[k] = 2;
      if (++ancilla_item_to_link[k] == 2) {
        ancilla_item_to_link[k]--;
        ancilla_x_vel[k] = 16;
        ancilla_step[k] = 3;
      }
    }
    ancilla_x_vel[k] += 1;
    EtherSpell_HandleRadialSpin(k);
    return;
  } else {
    if (sign8(--ancilla_aux_timer[k])) {
      ancilla_aux_timer[k] = 2;
      ancilla_item_to_link[k] ^= 1;
    }
    if (ancilla_step[k] == 0) {
      EtherSpell_HandleLightningStroke(k);
    } else if (ancilla_step[k] == 1) {
      EtherSpell_HandleOrbPulse(k);
    } else if (ancilla_step[k] == 3) {
      EtherSpell_HandleRadialSpin(k);
    } else if (ancilla_step[k] == 4) {
      if (!--ether_var1)
        ancilla_step[k] = 5;
      EtherSpell_HandleRadialSpin(k);
    } else {
      uint8 vel = ancilla_x_vel[k] + 0x10;
      if (sign8(vel)) vel = 0x7f;
      ancilla_x_vel[k] = vel;
      EtherSpell_HandleRadialSpin(k);
    }
  }
}

void EtherSpell_HandleLightningStroke(int k) {  // 88ab63
  Ancilla_MoveY(k);
  uint16 y = Ancilla_GetY(k);

  if (BYTE(ether_y_adjusted) != (y & 0xf0)) {
    BYTE(ether_y_adjusted) = y & 0xf0;
    ancilla_arr25[k]++;
  }
  if (y < 0xe000 && ether_y2 < 0xe000 && ether_y2 <= y) {
    ancilla_step[k] = 1;
  }
  AncillaDraw_EtherBlitz(k);
}

void EtherSpell_HandleOrbPulse(int k) {  // 88aba7
  if (!sign8(ancilla_arr25[k])) {
    if (!sign8(--ancilla_arr3[k])) {
      AncillaDraw_EtherBlitz(k);
      return;
    }
    ancilla_arr3[k] = 3;
    if (!sign8(--ancilla_arr25[k])) {
      AncillaDraw_EtherBlitz(k);
      return;
    }
    ancilla_arr3[k] = 9;
  }
  if (sign8(--ancilla_arr3[k])) {
    ancilla_step[k] = 2;
    ancilla_y_vel[k] = 0;
    ancilla_x_vel[k] = 16;
    ancilla_item_to_link[k] = 0;
    ancilla_aux_timer[k] = 2;
    if (step_counter_for_spin_attack)
      Medallion_CheckSpriteDamage(k);
  }
  AncillaDraw_EtherOrb(k, GetOamCurPtr());
}

void EtherSpell_HandleRadialSpin(int k) {  // 88abef
  if (ancilla_step[k] == 4) {
    if ((frame_counter & 7) == 0)
      sound_effect_2 = 0x2a;
    else if ((frame_counter & 7) == 4)
      sound_effect_2 = 0xaa;
    else if ((frame_counter & 7) == 7)
      sound_effect_2 = 0x6a;
  } else {
    ancilla_x_lo[k] = ether_var2;
    ancilla_x_hi[k] = 0;
    Ancilla_MoveX(k);
    ether_var2 = ancilla_x_lo[k];
    if (ether_var2 == 0x40)
      ancilla_step[k] = 4;
  }

  uint8 sb = ancilla_step[k];
  uint8 sa = ancilla_item_to_link[k];
  OamEnt *oam = GetOamCurPtr();
  for (int i = 7; i >= 0; i--) {
    if (sb != 2 && sb != 5) {
      ether_arr1[i] = (ether_arr1[i] + 1) & 0x3f;
    }
    AncillaRadialProjection arp = Ancilla_GetRadialProjection(ether_arr1[i], ether_var2);
    if (sb != 2)
      oam = AncillaDraw_EtherBlitzBall(oam, &arp, sa);
    else
      oam = AncillaDraw_EtherBlitzSegment(oam, &arp, sa, i);
  }
  if (ether_var2 < 0xf0) {
    OamEnt *oam = GetOamCurPtr();
    for (int i = 0; i != 8; i++) {
      if (oam[i].y != 0xf0)
        return;
    }
  }
  ancilla_type[k] = 0;
  load_chr_halfslot_even_odd = 1;
  byte_7E0324 = 0;
  state_for_spin_attack = 0;
  step_counter_for_spin_attack = 0;
  link_cant_change_direction = 0;
  flag_unk1 = 0;

  if (BYTE(overworld_screen_index) == 0x70 && !(save_ow_event_info[0x70] & 0x20) && Ancilla_CheckForEntranceTrigger(2)) {
    trigger_special_entrance = 3;
    subsubmodule_index = 0;
    BYTE(R16) = 0;
  }

  if (link_player_handler_state != kPlayerState_ReceivingEther) {
    link_player_handler_state = kPlayerState_Ground;
    link_delay_timer_spin_attack = 0;
    button_mask_b_y = button_b_frames ? (joypad1H_last & 0x80) : 0;
  }
  link_speed_setting = 0;
  byte_7E0325 = 0;
  LoadActualGearPalettes();
  Palette_Restore_BG_And_HUD();
}

OamEnt *AncillaDraw_EtherBlitzBall(OamEnt *oam, const AncillaRadialProjection *arp, int s) {  // 88aced
  static const uint8 kEther_BlitzBall_Char[2] = {0x68, 0x6a};
  int x = (arp->r6 ? -arp->r4 : arp->r4) + ether_x2 - 8 - BG2HOFS_copy2;
  int y = (arp->r2 ? -arp->r0 : arp->r0) + ether_y3 - 8 - BG2VOFS_copy2;
  Ancilla_SetOam(oam, x, y, kEther_BlitzBall_Char[s], 0x3c, 2);
  return Ancilla_AllocateOamFromCustomRegion(oam + 1);
}

OamEnt *AncillaDraw_EtherBlitzSegment(OamEnt *oam, const AncillaRadialProjection *arp, int s, int k) {  // 88adc9
  static const int8 kEther_SpllittingBlitzSegment_X[16] = {-8, -16, -24, -16, -8, 0, 8, -16, -8, -16, -24, -16, -8, 0, 8, 0};
  static const int8 kEther_SpllittingBlitzSegment_Y[16] = {8, 0, -8, -16, -24, -16, -8, -16, 8, 0, -8, -16, -24, -16, -8, 0};
  static const uint8 kEther_SpllittingBlitzSegment_Char[32] = {
    0x40, 0x42, 0x66, 0x64, 0x62, 0x60, 0x64, 0x66, 0x42, 0x40, 0x66, 0x64, 0x60, 0x62, 0x64, 0x66,
    0x68, 0x42, 0x68, 0x64, 0x68, 0x60, 0x68, 0x64, 0x68, 0x40, 0x68, 0x66, 0x68, 0x62, 0x68, 0x64,
  };
  static const uint8 kEther_SpllittingBlitzSegment_Flags[32] = {
    0x3c, 0x3c, 0xfc, 0xfc, 0x3c, 0x3c, 0xbc, 0xbc, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x7c, 0x7c,
    0x3c, 0x7c, 0x3c, 0x3c, 0x3c, 0xbc, 0x3c, 0x7c, 0x3c, 0x7c, 0x3c, 0xfc, 0x3c, 0xbc, 0x3c, 0xbc,
  };
  int x = (arp->r6 ? -arp->r4 : arp->r4);
  int y = (arp->r2 ? -arp->r0 : arp->r0);
  int t = s * 8 + k;
  Ancilla_SetOam(oam, x + ether_x2 - 8 - BG2HOFS_copy2, y + ether_y3 - 8 - BG2VOFS_copy2,
                 kEther_SpllittingBlitzSegment_Char[t * 2], kEther_SpllittingBlitzSegment_Flags[t * 2], 2);
  Ancilla_SetOam(oam + 1,
      x + ether_x2 + kEther_SpllittingBlitzSegment_X[t] - BG2HOFS_copy2,
      y + ether_y3 + kEther_SpllittingBlitzSegment_Y[t] - BG2VOFS_copy2,
      kEther_SpllittingBlitzSegment_Char[t * 2 + 1],
      kEther_SpllittingBlitzSegment_Flags[t * 2 + 1], 2);
  return Ancilla_AllocateOamFromCustomRegion(oam + 2);
}

void AncillaDraw_EtherBlitz(int k) {  // 88ae87
  Point16U info;
  Ancilla_PrepOamCoord(k, &info);
  OamEnt *oam = GetOamCurPtr();
  int t = ancilla_item_to_link[k];
  int i = ancilla_arr25[k];
  int m = 0;
  do {
    Ancilla_SetOam(oam, info.x, info.y,
                   kEther_BlitzSegment_Char[t * 2 + m],
                   kEther_BlitzOrb_Flags[0] | HIBYTE(oam_priority_value), 2);
    info.y -= 16;
    oam++;
    m ^= 1;
  } while (--i >= 0);
  if (ancilla_step[k] == 1)
    AncillaDraw_EtherOrb(k, oam);
}

void AncillaDraw_EtherOrb(int k, OamEnt *oam) {  // 88aedd
  uint16 y = ether_y - 1 - BG2VOFS_copy2;
  uint16 x = ether_x - 8 - BG2HOFS_copy2;
  int t = ancilla_item_to_link[k] * 4;

  for (int i = 0; i < 4; i++) {
    Ancilla_SetOam(oam, x, y, kEther_BlitzOrb_Char[t + i], kEther_BlitzOrb_Flags[t + i], 2);
    oam++;
    oam = Ancilla_AllocateOamFromCustomRegion(oam);
    x += 16;
    if (i == 1)
      x -= 32, y += 16;
  }
}

void AncillaAdd_BombosSpell(uint8 a, uint8 y) {  // 88af66
  int k = AncillaAdd_AddAncilla_Bank08(a, y);
  if (k < 0)
    return;
  for (int i = 0; i < 10; i++) {
    bombos_arr2[i] = 0;
    bombos_arr1[i] = 3;
  }
  for (int i = 0; i < 8; i++) {
    bombos_arr3[i] = 0;
    bombos_arr4[i] = 3;
  }
  bombos_var4 = 0;
  bombos_var2 = 0;
  bombos_var3 = 0x80;
  bombos_arr7[0] = 0x10;
  load_chr_halfslot_even_odd = 11;
  flag_custom_spell_anim_active = 1;
  ancilla_step[k] = 0;
  ancilla_item_to_link[k] = 0;
  Ancilla_Sfx2_Near(0x2a);

  uint8 t = kGeneratedBombosArr[frame_counter];
  t = (t < 0xe0) ? t : t & 0x7f;
  bombos_x_coord[0] = link_x_coord & ~0xff | t;
  bombos_y_coord[0] = link_y_coord & ~0xff | t;

  static const int16 kBombos_YDelta[4] = {16, 24, -128, -16};
  static const int16 kBombos_XDelta[4] = {-16, -128, 0, 128};

  for (int i = 0; i < 1 ; i++) {
    bombos_x_coord2[i] = link_x_coord + kBombos_XDelta[i];
    bombos_y_coord2[i] = link_y_coord + kBombos_YDelta[i];
    bombos_var1 = 16;
    AncillaRadialProjection arp = Ancilla_GetRadialProjection(bombos_arr7[i], 16);
    int x = (arp.r6 ? -arp.r4 : arp.r4) + bombos_x_coord2[i];
    int y = (arp.r2 ? -arp.r0 : arp.r0) + bombos_y_coord2[i];
    bombos_x_lo[i] = (uint8)x;
    bombos_x_hi[i] = x >> 8;
    bombos_y_lo[i] = (uint8)y;
    bombos_y_hi[i] = y >> 8;
  }
}

void Ancilla19_BombosSpell(int k) {  // 88b0ce
  if (bombos_var4 == 0) {
    if (submodule_index == 0) {
      BombosSpell_ControlFireColumns(k);
      return;
    }
    for (int i = 9; i >= 0; i--)
      AncillaDraw_BombosFireColumn(i);
  } else if (bombos_var4 != 2) {
    if (submodule_index == 0) {
      BombosSpell_FinishFireColumns(k);
      return;
    }
    for (int i = 9; i >= 0; i--)
      AncillaDraw_BombosFireColumn(i);
  } else {
    if (submodule_index == 0) {
      BombosSpell_ControlBlasting(k);
      return;
    }
    int i = ancilla_step[k];
    do {
      AncillaDraw_BombosBlast(i);
    } while (--i >= 0);
  }
}

void BombosSpell_ControlFireColumns(int k) {  // 88b10a
  uint8 sa = ancilla_item_to_link[k];
  uint8 sb = ancilla_step[k];

  int j, i = sb;
  do {
    if (bombos_arr2[i] == 13)
      continue;

    if (sign8(--bombos_arr1[i])) {
      bombos_arr1[i] = 3;
      if (++bombos_arr2[i] == 13)
        continue;

      if (bombos_arr2[i] == 2) {
        if (sa)
          continue;

        // pushed x
        if (sb == 9) {
          for (j = 9; j >= 0; j--) {
            if (bombos_arr2[j] == 13) {
              bombos_arr2[j] = 0;
              goto exit_loop;
            }
          }
        }
        sb = j = (sb + 1) != 10 ? sb + 1 : 9;
exit_loop:
        bombos_var1 = (bombos_var1 + 3 >= 207) ? 207 : bombos_var1 + 3;
        bombos_arr7[0] += 6;
        AncillaRadialProjection arp = Ancilla_GetRadialProjection(bombos_arr7[0] & 0x3f, bombos_var1);
        int x = (arp.r6 ? -arp.r4 : arp.r4) + bombos_x_coord2[0];
        int y = (arp.r2 ? -arp.r0 : arp.r0) + bombos_y_coord2[0];
        bombos_x_lo[j] = (uint8)x;
        bombos_x_hi[j] = x >> 8;
        bombos_y_lo[j] = (uint8)y;
        bombos_y_hi[j] = y >> 8;

        uint16 t = x - BG2HOFS_copy2 + 8;
        if (t < 256)
          sound_effect_1 = kBombos_Sfx[t >> 5] | 0x2a;
      }
    }
    AncillaDraw_BombosFireColumn(i);

  } while (--i >= 0);
  if (bombos_arr7[0] >= 0x80)
    bombos_var4 = 1;
  ancilla_step[k] = sb;
}

void BombosSpell_FinishFireColumns(int kk) {  // 88b236
  int k = ancilla_step[kk];
  do {
    if (sign8(--bombos_arr1[k])) {
      bombos_arr1[k] = 3;
      if (++bombos_arr2[k] >= 13)
        bombos_arr2[k] = 13;
    }
    AncillaDraw_BombosFireColumn(k);
  } while (--k >= 0);
  for (int k = 9; k >= 0; k--) {
    if (bombos_arr2[k] != 13)
      return;
  }
  bombos_var4 = 2;
  Medallion_CheckSpriteDamage(kk);
  ancilla_step[kk] = 0;
}

void AncillaDraw_BombosFireColumn(int kk) {  // 88b373
  static const int8 kBombosSpell_FireColumn_X[39] = {
     0, -1, -1,  0, 0, -1,  0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
     0,  0,  0,  0, 0,  0,  0, 0,  0, 0, 0,  0, 0, 0,  0, 0,
    -1,  1, -1, -1, 2, -1, -1,
  };
  static const int8 kBombosSpell_FireColumn_Y[39] = {
     0,  -1, -1,  0,  -4, -1,   0,  -8, -1,   0, -12, -1,   0, -16,  -1,   0,
    -4, -20,  0, -8, -24,  0, -12, -28,  0, -16, -32,  0, -16, -32, -18, -34,
    -1, -35, -1, -1, -36, -1,  -1,
  };
  static const uint8 kBombosSpell_FireColumn_Flags[39] = {
    0x3c, 0xff, 0xff, 0x3c, 0x3c, 0xff, 0x3c, 0x3c, 0xff, 0x7c, 0x7c, 0xff, 0x3c, 0x7c, 0xff, 0x3c,
    0x3c, 0x3c, 0xbc, 0x3c, 0x3c, 0x7c, 0x3c, 0x3c, 0x3c, 0x3c, 0x7c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
    0xff, 0x3c, 0xff, 0xff, 0x3c, 0xff, 0xff,
  };
  static const uint8 kBombosSpell_FireColumn_Char[39] = {
    0x40, 0xff, 0xff, 0x42, 0x44, 0xff, 0x42, 0x44, 0xff, 0x42, 0x44, 0xff, 0x42, 0x44, 0xff, 0x40,
    0x46, 0x44, 0x4a, 0x4a, 0x48, 0x4c, 0x4c, 0x4a, 0x4e, 0x4c, 0x4a, 0x4e, 0x6a, 0x4c, 0x4e, 0x68,
    0xff, 0x6a, 0xff, 0xff, 0x4e, 0xff, 0xff,
  };
  Ancilla_AllocateOamFromRegion_A_or_D_or_F(kk, 0x10);
  OamEnt *oam = GetOamCurPtr();
  for (int i = 0; i < 1; i++) {
    int k = bombos_arr2[kk];
    if (k == 13)
      continue;
    k = k * 3 + 2;
    for (int j = 0; j < 3; j++, k--) {
      if (kBombosSpell_FireColumn_Char[k] != 0xff) {
        uint16 x = bombos_x_lo[kk] | bombos_x_hi[kk] << 8;
        uint16 y = bombos_y_lo[kk] | bombos_y_hi[kk] << 8;
        y += kBombosSpell_FireColumn_Y[k] - BG2VOFS_copy2;
        x += kBombosSpell_FireColumn_X[k] - BG2HOFS_copy2;
        Ancilla_SetOam(oam, x, y,
                       kBombosSpell_FireColumn_Char[k],
                       kBombosSpell_FireColumn_Flags[k], 2);
        oam++;
      }
      oam = Ancilla_AllocateOamFromCustomRegion(oam);
    }
  }
}

void BombosSpell_ControlBlasting(int kk) {  // 88b40d
  int k = ancilla_step[kk], sb = k;
  for (; k >= 0; k--) {
    if (bombos_arr3[k] != 8 && sign8(--bombos_arr4[k])) {
      bombos_arr4[k] = 3;
      if (++bombos_arr3[k] == 1 && !bombos_var2) {
        int j = sb;
        if (j != 15) {
          j = ++sb;
        } else {
          for (; j >= 0 && bombos_arr3[j] != 8; j--) {}
        }
        bombos_arr3[j] = 0;
        bombos_arr4[j] = 3;

        uint16 y = kBombosBlasts_Tab[frame_counter & 0x3f];
        uint16 x = kBombosBlasts_Tab[(frame_counter & 0x3f) + 3];
        bombos_y_coord[j] = y + BG2VOFS_copy2;
        bombos_x_coord[j] = x + BG2HOFS_copy2;

        sound_effect_1 = 0xc | kBombos_Sfx[bombos_x_coord[j] >> 5 & 7];
      }
    }
    AncillaDraw_BombosBlast(k);
  }

  for (int j = 15; j >= 0; j--) {
    if (bombos_arr3[j] != 8) {
      ancilla_step[kk] = sb;
      goto getout;
    }
  }
  ancilla_type[kk] = 0;
  load_chr_halfslot_even_odd = 1;
  byte_7E0324 = 0;
  state_for_spin_attack = 0;
  step_counter_for_spin_attack = 0;
  link_cant_change_direction = 0;
  flag_unk1 = 0;
  if (link_player_handler_state != kPlayerState_ReceivingBombos) {
    link_player_handler_state = kPlayerState_Ground;
    link_delay_timer_spin_attack = 0;
    button_mask_b_y = button_b_frames ? (joypad1H_last & 0x80) : 0;
  }
  link_speed_setting = 0;
  byte_7E0325 = 0;
getout:
  if (--bombos_var3 == 0)
    bombos_var2 = bombos_var3 = 1;
}

void AncillaDraw_BombosBlast(int k) {  // 88b5e1
  static const int8 kBombosSpell_DrawBlast_X[32] = {
     -8, -1,  -1, -1, -12, -4, -12, -4, -16, 0, -16, 0, -16, 0, -16, 0,
    -17,  1, -17,  1, -19,  3, -19,  3, -19, 3, -19, 3, -19, 3, -19, 3,
  };
  static const int8 kBombosSpell_DrawBlast_Y[32] = {
     -8,  -1, -1, -1, -12, -12, -4, -4, -16, -16, 0, 0, -16, -16, 0, 0,
    -17, -17,  1,  1, -19, -19,  3,  3, -19, -19, 3, 3, -19, -19, 3, 3,
  };
  static const uint8 kBombosSpell_DrawBlast_Flags[32] = {
    0x3c, 0xff, 0xff, 0xff, 0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc,
    0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc,
  };
  static const uint8 kBombosSpell_DrawBlast_Char[32] = {
    0x60, 0xff, 0xff, 0xff, 0x62, 0x62, 0x62, 0x62, 0x64, 0x64, 0x64, 0x64, 0x66, 0x66, 0x66, 0x66,
    0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x6a, 0x6a, 0x6a, 0x6a, 0x4e, 0x4e, 0x4e, 0x4e,
  };
  uint16 x = bombos_x_coord[k];
  uint16 y = bombos_y_coord[k];
  if (bombos_arr3[k] == 8)
    return;

  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 0x10);
  OamEnt *oam = GetOamCurPtr();

  int t = bombos_arr3[k] * 4 + 3;
  for (int j = 0; j < 4; j++, t--) {
    if (kBombosSpell_DrawBlast_Char[t] != 0xff) {
      Ancilla_SetOam(oam,
        x + kBombosSpell_DrawBlast_X[t] - BG2HOFS_copy2,
        y + kBombosSpell_DrawBlast_Y[t] - BG2VOFS_copy2,
        kBombosSpell_DrawBlast_Char[t],
        kBombosSpell_DrawBlast_Flags[t], 2);
      oam++;
    }
    oam = Ancilla_AllocateOamFromCustomRegion(oam);
  }

}

void Ancilla1C_QuakeSpell(int k) {  // 88b66a
  if (submodule_index != 0) {
    if (quake_arr2[4] != kQuake_Tab1[4])
      AncillaDraw_QuakeInitialBolts(k);
    return;
  }
  if (ancilla_step[k] != 2) {
    QuakeSpell_ShakeScreen(k);
    QuakeSpell_ControlBolts(k);
    QuakeSpell_SpreadBolts(k);
    return;
  }
  Medallion_CheckSpriteDamage(k);
  Prepare_ApplyRumbleToSprites();
  ancilla_type[k] = 0;
  link_player_handler_state = 0;
  load_chr_halfslot_even_odd = 1;
  byte_7E0324 = 0;
  state_for_spin_attack = 0;
  step_counter_for_spin_attack = 0;
  link_cant_change_direction = 0;
  link_delay_timer_spin_attack = 0;
  flag_unk1 = 0;
  bg1_x_offset = 0;
  bg1_y_offset = 0;
  if (BYTE(overworld_screen_index) == 0x47 && !(save_ow_event_info[0x47] & 0x20) && Ancilla_CheckForEntranceTrigger(3)) {
    trigger_special_entrance = 4;
    subsubmodule_index = 0;
    BYTE(R16) = 0;
  }
  button_mask_b_y = button_b_frames ? (joypad1H_last & 0x80) : 0;
  link_speed_setting = 0;
  byte_7E0325 = 0;
}

void QuakeSpell_ShakeScreen(int k) {  // 88b6f7
  bg1_y_offset = quake_var3;
  quake_var3 = -quake_var3;
  link_y_vel += bg1_y_offset;
}

void QuakeSpell_ControlBolts(int k) {  // 88b718
  quake_var4 = ancilla_step[k];
  int j = quake_var5;
  do {
    if (quake_arr2[j] == kQuake_Tab1[j])
      continue;

    if (sign8(--quake_arr1[j])) {
      quake_arr1[j] = 1;
      if (++quake_arr2[j] == kQuake_Tab1[j])
        continue;

      if (j == 0 && quake_arr2[j] == 2) {
        Ancilla_Sfx2_Near(0xc);
        quake_var5 = 1;
      } else if (j == 1 && quake_arr2[j] == 2) {
        quake_var5 = 4;
      } else if (j == 4 && quake_arr2[j] == 7) {
        quake_var4 = 1;
      }
    }
    AncillaDraw_QuakeInitialBolts(j);
  } while (--j >= 0);
  ancilla_step[k] = quake_var4;
}

void AncillaDraw_QuakeInitialBolts(int k) {  // 88b793
  static const uint8 kQuakeDrawGroundBolts_Tab[5] = {0, 0x18, 0, 0x18, 0x2f};

  int t = quake_arr2[k] + kQuakeDrawGroundBolts_Tab[k];
  OamEnt *oam = GetOamCurPtr();
  int idx = kQuakeItemPos[t], num = kQuakeItemPos[t + 1] - idx;
  const QuakeItem *p = &kQuakeItems[idx], *pend = p + num;
  do {
    uint16 x = p->x + quake_var2 - BG2HOFS_copy2;
    uint16 y = p->y + quake_var1 - BG2VOFS_copy2;

    uint8 xval = oam->x, yval = 0xf0;
    if (x < 256 && y < 256) {
      xval = x;
      if (y < 0xf0)
        yval = y;
    }
    SetOamPlain(oam, xval, yval, kQuakeDrawGroundBolts_Char[p->f & 0x0f], p->f & 0xc0 | 0x3c, 2);
    oam++, oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
  } while (++p != pend);
}

void QuakeSpell_SpreadBolts(int k) {  // 88b84f
  if (ancilla_step[k] != 1)
    return;
  if (ancilla_timer[k] == 0) {
    ancilla_timer[k] = 2;
    if (++ancilla_item_to_link[k] == 55) {
      ancilla_step[k] = 2;
      return;
    }
  }
  int t = ancilla_item_to_link[k];
  int idx = kQuakeItemPos2[t], num = kQuakeItemPos2[t + 1] - idx;
  const QuakeItem *p = &kQuakeItems2[idx], *pend = p + num;
  OamEnt *oam = GetOamCurPtr();
  do {
    SetOamPlain(oam, p->x, p->y, kQuakeDrawGroundBolts_Char[p->f & 0x0f], p->f & 0xc0 | 0x3c, p->f >> 4 & 3);
    oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
  } while (++p != pend);
}

void Ancilla1A_PowderDust(int k) {  // 88bab0
  if (submodule_index == 0) {
    Powder_ApplyDamageToSprites(k);
    if (sign8(--ancilla_aux_timer[k])) {
      ancilla_aux_timer[k] = 1;
      int j = ancilla_dir[k];
      if (ancilla_item_to_link[k] == 9) {
        ancilla_type[k] = 0;
        byte_7E0333 = 0;
        return;
      }
      ancilla_arr25[k] = kMagicPowder_Tab0[++ancilla_item_to_link[k] + j * 10];
    }
  }
  Ancilla_AllocateOamFromRegion_B_or_E(ancilla_numspr[k]);
  Ancilla_MagicPowder_Draw(k);
}

void Ancilla_MagicPowder_Draw(int k) {  // 88baeb
  static const int8 kMagicPowder_DrawX[76] = {
    -5, -12,  2,  -9, -7, -10, -6, -2, -6, -12,  1, -6,  -6, -12,   1,  -6,
    -6, -12,  1,  -6, -6, -12,  1, -6, -6, -12,  1, -6, -17, -23, -14, -19,
    -11, -18, -9, -13, -4, -13, -1, -8, -3,  -9,  0, -5,  -3, -10,  -1,  -5,
    -4, -13, -1,  -8, -3,  -9,  0, -5, -3, -10, -1, -5,  -3, -13,  -1,  -8,
    9,  15,  6,  11,  3,  10,  1,  5, -4,   5, -7,  0,
  };
  static const int8 kMagicPowder_DrawY[76] = {
    -20, -15, -13,  -7, -18, -13, -13, -13, -20, -13, -13,  -8, -20, -13, -13,  -8,
    -19, -12, -12,  -7, -18, -11, -11,  -6, -17, -10, -10,  -5, -16, -14, -12,  -9,
    -17, -14, -12,  -8, -18, -14, -13,  -6, -33, -31, -29, -26, -28, -25, -23, -19,
    -22, -18, -17, -10,  -2,   0,   2,   5,  -9,  -6,  -4,   0, -16, -12, -11,  -4,
    -16, -14, -12,  -9, -17, -14, -12,  -8, -18, -14, -13,  -6,
  };
  static const uint8 kMagicPowder_Draw_Char[19] = {
    9, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
  };
  static const uint8 kMagicPowder_Draw_Flags[76] = {
    0x68, 0x24, 0xa2, 0x28, 0x68, 0xe2, 0x28, 0xa4, 0x68, 0xe2, 0xa4, 0x28, 0x22, 0xa4, 0xe8, 0x62,
    0x24, 0xa8, 0xe2, 0x64, 0x28, 0xa2, 0xe4, 0x68, 0x22, 0xa4, 0xe8, 0x62, 0xe2, 0xa4, 0xe8, 0x64,
    0xe8, 0xa8, 0xe4, 0x62, 0xe4, 0xa8, 0xe2, 0x68, 0xe2, 0xa4, 0xe8, 0x64, 0xe8, 0xa8, 0xe4, 0x62,
    0xe4, 0xa8, 0xe2, 0x68, 0xe2, 0xa4, 0xe8, 0x64, 0xe8, 0xa8, 0xe4, 0x62, 0xe4, 0xa8, 0xe2, 0x68,
    0xe2, 0xa4, 0xe8, 0x64, 0xe8, 0xa8, 0xe4, 0x62, 0xe4, 0xa8, 0xe2, 0x68,
  };
  Point16U info;
  Ancilla_PrepOamCoord(k, &info);
  OamEnt *oam = GetOamCurPtr();
  int b = ancilla_arr25[k];
  for (int i = 0; i < 4; i++, oam++) {
    Ancilla_SetOam(oam, info.x + kMagicPowder_DrawX[b * 4 + i], info.y + kMagicPowder_DrawY[b * 4 + i],
                   kMagicPowder_Draw_Char[b], kMagicPowder_Draw_Flags[b * 4 + i] & ~0x30 | HIBYTE(oam_priority_value), 0);
  }
}

void Powder_ApplyDamageToSprites(int k) {  // 88bb58
  uint8 a;
  for (int j = 15; j >= 0; j--) {
    if ((frame_counter ^ j) & 3 || sprite_state[j] != 9 || sprite_bump_damage[j] & 0x20)
      continue;
    SpriteHitBox hb;
    Ancilla_SetupBasicHitBox(k, &hb);
    Sprite_SetupHitBox(j, &hb);
    if (!CheckIfHitBoxesOverlap(&hb))
      continue;

    if ((a = sprite_type[j]) != 0xb || (a = player_is_indoors) == 0 || (a = dungeon_room_index2 - 1) != 0) {
      if (a != 0xd) {
        Ancilla_CheckDamageToSprite_preset(j, 10);
        continue;
      }
      if (sprite_head_dir[j] != 0)
        continue;
    }
    sprite_head_dir[j] = 1;
    Sprite_SpawnPoofGarnish(j);
  }
}

void Ancilla1D_ScreenShake(int k) {  // 88bbbc
  if (submodule_index == 0) {
    if (sign8(--ancilla_item_to_link[k])) {
      bg1_x_offset = 0;
      bg1_y_offset = 0;
      ancilla_type[k] = 0;
      return;
    }
    int offs = DashTremor_TwiddleOffset(k);
    int j = ancilla_dir[k];
    if (j == 0) {
      bg1_x_offset = offs;
      link_x_vel += offs;
    } else {
      bg1_y_offset = offs;
      link_y_vel += offs;
    }
  }
  sprite_alert_flag = 3;
}

void Ancilla1E_DashDust(int k) {  // 88bc92
  if (ancilla_step[k]) {
    DashDust_Motive(k);
    return;
  }
  if (!ancilla_timer[k]) {
    ancilla_timer[k] = 3;
    if (++ancilla_item_to_link[k] == 5)
      return;
    if (ancilla_item_to_link[k] == 6) {
      ancilla_type[k] = 0;
      return;
    }
  }
  if (ancilla_item_to_link[k] == 5)
    return;

  Point16U info;
  Ancilla_PrepOamCoord(k, &info);
  OamEnt *oam = GetOamCurPtr();

  static const int8 kDashDust_Draw_X1[4] = {0, 0, 4, -4};
  static const int16 kDashDust_Draw_X[30] = {
    10,  5, -1,  0, 10, 5, 0,  5, -1,  0, -1, -1,  9, -1, -1, 10,
    5, -1,  0, 10,  5, 0, 5, -1,  0, -1, -1,  9, -1, -1,
  };
  static const int16 kDashDust_Draw_Y[30] = {
    -2,  0, -1, -3, -2,  0, -3,  0, -1, -3, -1, -1, -2, -1, -1, -2,
    0, -1, -3, -2,  0, -3,  0, -1, -3, -1, -1, -2, -1, -1,
  };
  static const uint8 kDashDust_Draw_Char[30] = {
    0xcf, 0xa9, 0xff, 0xa9, 0xdf, 0xcf, 0xcf, 0xdf, 0xff, 0xdf, 0xff, 0xff, 0xa9, 0xff, 0xff, 0xcf,
    0xcf, 0xff, 0xcf, 0xdf, 0xcf, 0xcf, 0xdf, 0xff, 0xdf, 0xff, 0xff, 0xcf, 0xff, 0xff,
  };
  int r12 = kDashDust_Draw_X1[link_direction_facing >> 1];
  int t = 3 * (ancilla_item_to_link[k] + (draw_water_ripples_or_grass == 1 ? 5 : 0));

  for (int n = 2; n >= 0; n--, t++) {
    if (kDashDust_Draw_Char[t] != 0xff) {
      Ancilla_SetOam(oam, info.x + r12 + kDashDust_Draw_X[t], info.y + kDashDust_Draw_Y[t], kDashDust_Draw_Char[t], 4 | HIBYTE(oam_priority_value), 0);
      oam++;
    }
  }
}

void Ancilla1F_Hookshot(int k) {  // 88bd74
  if (submodule_index != 0)
    goto do_draw;

  if (!ancilla_timer[k]) {
    ancilla_timer[k] = 7;
    Ancilla_Sfx2_Pan(k, 0xa);
  }

  if (related_to_hookshot)
    goto do_draw;
  Ancilla_MoveY(k);
  Ancilla_MoveX(k);
  if (ancilla_step[k]) {
    if (sign8(--ancilla_item_to_link[k])) {
      ancilla_type[k] = 0;
      return;
    }
    goto do_draw;
  }

  if (++ancilla_item_to_link[k] == 32) {
    ancilla_step[k] = 1;
    ancilla_x_vel[k] = -ancilla_x_vel[k];
    ancilla_y_vel[k] = -ancilla_y_vel[k];
  }

  if (Hookshot_ShouldIEvenBotherWithTiles(k))
    goto do_draw;

  if (!ancilla_L[k] && !ancilla_step[k] && Ancilla_CheckSpriteCollision(k) >= 0 && !ancilla_step[k]) {
    ancilla_step[k] = 1;
    ancilla_y_vel[k] = -ancilla_y_vel[k];
    ancilla_x_vel[k] = -ancilla_x_vel[k];
  }

  Hookshot_CheckTileCollision(k);

  uint8 r0;

  r0 = 0;

  if (player_is_indoors) {
    if (!(ancilla_dir[k] & 2)) {
      r0 = (tiledetect_vertical_ledge | (tiledetect_vertical_ledge >> 4)) & 3;
    } else {
      r0 = detection_of_ledge_tiles_horiz_uphoriz & 3;
    }
    if (r0 == 0)
      goto endif_7;
  } else {
    if (!((detection_of_ledge_tiles_horiz_uphoriz & 3 | tiledetect_vertical_ledge | detection_of_unknown_tile_types) & 0x33))
      goto endif_7;
  }
  if (sign8(--ancilla_G[k])) {
    if (ancilla_K[k] && ((r0 & 3) || ancilla_K[k] != BYTE(index_of_interacting_tile))) {
      ancilla_G[k] = 2;
      if (sign8(--ancilla_L[k]))
        ancilla_L[k] = 0;
    } else {
      ancilla_L[k]++;
      ancilla_K[k] = index_of_interacting_tile;
      ancilla_G[k] = 1;
    }
  }
endif_7:
  if (ancilla_L[k])
    goto do_draw;
  if (!sign8(ancilla_G[k])) {
    ancilla_G[k]--;
    goto do_draw;
  }

  if ((R14 >> 4 | R14 | tiledetect_stair_tile | R12) & 3 && !ancilla_step[k]) {
    ancilla_step[k] = 1;
    ancilla_y_vel[k] = -ancilla_y_vel[k];
    ancilla_x_vel[k] = -ancilla_x_vel[k];
    if (!(tiledetect_misc_tiles & 3)) {
      AncillaAdd_HookshotWallClink(k, 6, 1);
      Ancilla_Sfx2_Pan(k, (tiledetect_misc_tiles & 0x30) ? 6 : 5);
    }
  }

  if (tiledetect_misc_tiles & 3) {
    if (ancilla_item_to_link[k] < 4) {
      ancilla_type[k] = 0;
      return;
    }
    related_to_hookshot = 1;
    hookshot_effect_index = k;
  }

  static const int8 kHookShot_Move_X[4] = {0, 0, 8, -8};
  static const int8 kHookShot_Move_Y[4] = {8, -9, 0, 0};
  static const uint8 kHookShot_Draw_Flags[12] = {0, 0, 0xff, 0x80, 0x80, 0xff, 0x40, 0xff, 0x40, 0, 0xff, 0};
  static const uint8 kHookShot_Draw_Char[12] = {9, 0xa, 0xff, 9, 0xa, 0xff, 9, 0xff, 0xa, 9, 0xff, 0xa};

  Point16U info;
do_draw:
  Ancilla_PrepOamCoord(k, &info);
  if (ancilla_L[k])
    oam_priority_value = 0x3000;
  OamEnt *oam = GetOamCurPtr();

  int j = ancilla_dir[k] * 3;
  int x = info.x, y = info.y;
  for (int i = 2; i >= 0; i--, j++) {
    if (kHookShot_Draw_Char[j] != 0xff) {
      Ancilla_SetOam(oam, x, y, kHookShot_Draw_Char[j], kHookShot_Draw_Flags[j] | 2 | HIBYTE(oam_priority_value), 0);
      oam++;
    }
    if (i == 1)
      x -= 8, y += 8;
    else
      x += 8;
  }

  int r10 = 0;
  int n = ancilla_item_to_link[k] >> 1;
  if (n >= 7) {
    r10 = n - 7;
    n = 6;
  }
  if (n == 0)
    return;
  if (ancilla_dir[k] & 1)
    r10 = -r10;
  x = info.x, y = info.y;
  j = ancilla_dir[k];
  if (kHookShot_Move_Y[j] == 0)
    y += 4;
  if (kHookShot_Move_X[j] == 0)
    x += 4;
  do {
    if (kHookShot_Move_Y[j])
      y += kHookShot_Move_Y[j] + r10;
    if (kHookShot_Move_X[j])
      x += kHookShot_Move_X[j] + r10;
    if (!Hookshot_CheckProximityToLink(x, y)) {
      Ancilla_SetOam(oam, x, y, 0x19, (frame_counter & 2) << 6 | 2 | HIBYTE(oam_priority_value), 0);
      oam++;
    }
  } while (--n >= 0);
}

void Ancilla20_Blanket(int k) {  // 88c013
  static const uint8 kBedSpread_Char[8] = {0xa, 0xa, 0xa, 0xa, 0xc, 0xc, 0xa, 0xa};
  static const uint8 kBedSpread_Flags[8] = {0, 0x60, 0xa0, 0xe0, 0, 0x60, 0xa0, 0xe0};
  Point16U pt;
  Ancilla_PrepOamCoord(k, &pt);

  if (!link_pose_during_opening) {
    Oam_AllocateFromRegionB(0x10);
  } else {
    Oam_AllocateFromRegionA(0x10);
  }

  OamEnt *oam = GetOamCurPtr();
  int j = link_pose_during_opening ? 4 : 0;
  uint16 x = pt.x, y = pt.y;
  for (int i = 3; i >= 0; i--, j++, oam++) {
    Ancilla_SetOam(oam, x, y, kBedSpread_Char[j], kBedSpread_Flags[j] | 0xd | HIBYTE(oam_priority_value), 2);
    x += 16;
    if (i == 2)
      x -= 32, y += 8;
  }
}

void Ancilla21_Snore(int k) {  // 88c094
  static const uint8 kBedSpread_Dma[3] = {0x44, 0x43, 0x42};
  if (sign8(--ancilla_aux_timer[k])) {
    if (ancilla_item_to_link[k] != 2)
      ancilla_item_to_link[k]++;
    ancilla_aux_timer[k] = 7;
  }
  ancilla_x_vel[k] += ancilla_step[k];
  if (abs8(ancilla_x_vel[k]) >= 8)
    ancilla_step[k] = -ancilla_step[k];
  Ancilla_MoveY(k);
  Ancilla_MoveX(k);
  if (Ancilla_GetY(k) <= (uint16)(link_y_coord - 24))
    ancilla_type[k] = 0;
  link_dma_var5 = kBedSpread_Dma[ancilla_item_to_link[k]];
  Point16U pt;
  Ancilla_PrepOamCoord(k, &pt);
  Ancilla_SetOam(GetOamCurPtr(), pt.x, pt.y, 9, 0x24, 0);
}

void Ancilla3B_SwordUpSparkle(int k) {  // 88c167
  static const int8 kAncilla_VictorySparkle_X[16] = {16, 0, 0, 0, 8, 16, 8, 16, 9, 15, 0, 0, 12, 0, 0, 0};
  static const int8 kAncilla_VictorySparkle_Y[16] = {-7, 0, 0, 0, -11, -11, -3, -3, -7, -7, 0, 0, -7, 0, 0, 0};
  static const uint8 kAncilla_VictorySparkle_Char[16] = {0x92, 0xff, 0xff, 0xff, 0x93, 0x93, 0x93, 0x93, 0xf9, 0xf9, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff};
  static const uint8 kAncilla_VictorySparkle_Flags[16] = {0, 0xff, 0xff, 0xff, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0xff, 0xff, 0, 0xff, 0xff, 0xff};

  if (ancilla_aux_timer[k]) {
    ancilla_aux_timer[k]--;
    return;
  }

  if (sign8(--ancilla_arr3[k])) {
    ancilla_arr3[k] = 1;
    if (++ancilla_item_to_link[k] == 4) {
      ancilla_type[k] = 0;
      ancilla_aux_timer[k]--;
      return;
    }
  }
  Point16U pt;
  Ancilla_PrepOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr();
  int j = ancilla_item_to_link[k] * 4;
  for (int i = 0; i < 4; i++, j++) {
    if (kAncilla_VictorySparkle_Char[j] != 0xff) {
      Ancilla_SetOam(oam,
                     link_x_coord + kAncilla_VictorySparkle_X[j] - BG2HOFS_copy2,
                     link_y_coord + kAncilla_VictorySparkle_Y[j] - BG2VOFS_copy2,
                     kAncilla_VictorySparkle_Char[j],
                     kAncilla_VictorySparkle_Flags[j] | 4 | HIBYTE(oam_priority_value), 0);
      oam++;
    }
  }
}

void Ancilla3C_SpinAttackChargeSparkle(int k) {  // 88c1ea
  static const uint8 kSwordChargeSpark_Char[3] = {0xb7, 0x80, 0x83};
  static const uint8 kSwordChargeSpark_Flags[3] = {4, 4, 0x84};

  if (!submodule_index && !ancilla_timer[k]) {
    ancilla_timer[k] = 4;
    if (++ancilla_item_to_link[k] == 3) {
      ancilla_type[k] = 0;
      return;
    }
  }
  ancilla_oam_idx[k] = Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 4);
  Point16U info;
  Ancilla_PrepOamCoord(k, &info);
  int j = ancilla_item_to_link[k];
  Ancilla_SetOam(GetOamCurPtr(), info.x, info.y,
                 kSwordChargeSpark_Char[j], kSwordChargeSpark_Flags[j] | HIBYTE(oam_priority_value), 0);
}

void Ancilla35_MasterSwordReceipt(int k) {  // 88c25f
  static const int8 kSwordCeremony_X[8] = {-1, 8, -1, 8, 0, 7, 0, 7};
  static const int8 kSwordCeremony_Y[8] = {1, 1, 9, 9, 1, 1, 9, 9};
  static const uint8 kSwordCeremony_Char[8] = {0x86, 0x86, 0x96, 0x96, 0x87, 0x87, 0x97, 0x97};
  static const uint8 kSwordCeremony_Flags[8] = {1, 0x41, 1, 0x41, 1, 0x41, 1, 0x41};

  if (!ancilla_timer[k]) {
    ancilla_type[k] = 0;
    return;
  }
  if (sign8(--ancilla_aux_timer[k])) {
    ancilla_item_to_link[k] = (ancilla_item_to_link[k] == 2) ? 0 : ancilla_item_to_link[k] + 1;
  }

  Point16U pt;
  Ancilla_PrepOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr();
  int j = (ancilla_item_to_link[k] - 1) * 4;
  if (j < 0)
    return;

  for (int i = 0; i < 4; i++, j++, oam++) {
    Ancilla_SetOam(oam, pt.x + kSwordCeremony_X[j], pt.y + kSwordCeremony_Y[j],
                   kSwordCeremony_Char[j], kSwordCeremony_Flags[j] & ~0x30 | 4 | HIBYTE(oam_priority_value), 0);
  }
}

void Ancilla22_ItemReceipt(int k) {  // 88c38a
  uint8 a;

  if (flag_is_link_immobilized == 2)
    goto endif_1;
  if (submodule_index != 0 && submodule_index != 43 && submodule_index != 9) {
    if (submodule_index == 2)
      ancilla_timer[k] = 16;
    goto endif_1;
  }
  flag_unk1++;

  if (ancilla_step[k] != 0 && ancilla_step[k] != 3) {
    if (sign8(--ancilla_aux_timer[k]))
      goto endif_11;

    if (ancilla_aux_timer[k] == 0)
      goto endif_6;

    if (ancilla_aux_timer[k] == 40 && ancilla_step[k] != 2) {
      if (Ancilla_AddRupees(k) || ancilla_item_to_link[k] != 0x17)
        Ancilla_Sfx3_Near(0xf);
    }
    goto label_b;
  }

  if (ancilla_item_to_link[k] == 1 && ancilla_step[k] != 2) {
    if (ancilla_timer[k] == 0)
      goto label_a;
    if (ancilla_timer[k] != 17)
      goto endif_1;
    word_7E02CD = 0xDF3;
    follower_indicator = 0xe;
    goto endif_6;
  }

  a = --ancilla_aux_timer[k];
  if (a == 0)
    goto label_a;
  if (a == 1) {
    if (ancilla_item_to_link[k] != 0x37 && ancilla_item_to_link[k] != 0x38 && ancilla_item_to_link[k] != 0x39 || zelda_read_apui00() == 0)
      goto endif_6;
    ancilla_aux_timer[k]++;
  }
  goto endif_1;

label_a:
  if (ancilla_item_to_link[k] == 1 && !ancilla_step[k]) {
    sound_effect_ambient = 5;
    music_control = 2;
  }
  link_player_handler_state = link_is_in_deep_water ? kPlayerState_Swimming : 0;
  link_receiveitem_index = 0;
  link_pose_for_item = 0;
  link_disable_sprite_damage = 0;
  Ancilla_AddRupees(k);
endif_11:
  item_receipt_method = 0;
  a = ancilla_item_to_link[k];
  if (a == 23 && link_heart_pieces == 0) {
    Link_ReceiveItem(0x26, 0);
    ancilla_type[k] = 0;
    flag_unk1 = 0;
    return;
  }

  if (a == 0x26 || a == 0x3f) {
    if (link_health_capacity != 0xa0) {
      link_health_capacity += 8;
      link_hearts_filler += link_health_capacity - link_health_current;
      Ancilla_Sfx3_Near(0xd);
    }
  } else if (a == 0x3e) {
    flag_is_link_immobilized = 0;
    if (link_health_capacity != 0xa0) {
      link_health_capacity += 8;
      link_hearts_filler += 8;
      Ancilla_Sfx3_Near(0xd);
    }
  } else if (a == 0x42) {
    link_hearts_filler += 8;
  } else if (a == 0x45) {
    link_magic_filler += 16;
  } else if (a == 0x22 || a == 0x23) {
    Palette_Load_LinkArmorAndGloves();
  }

  ancilla_type[k] = 0;
  flag_unk1 = 0;
  a = ancilla_item_to_link[k];
  if (ancilla_step[k] == 3 && a != 0x10 && a != 0x26 && a != 0xf && a != 0x20) {
    PrepareDungeonExitFromBossFight();
  }

  if (ancilla_step[k] != 2)
    flag_is_link_immobilized = 0;
  return;

endif_6:
  if (player_is_indoors) {
    int room = dungeon_room_index;
    if (room == 0xff || room == 0x10f || room == 0x110 || room == 0x112 || room == 0x11f)
      goto label_b;
  }
  int msg;
  msg = -1;
  if (ancilla_item_to_link[k] == 0x38 || ancilla_item_to_link[k] == 0x39) {
    if ((link_which_pendants & 7) == 7)
      msg = kReceiveItemMsgs2[ancilla_item_to_link[k] - 0x38];
    else
      msg = kReceiveItemMsgs[ancilla_item_to_link[k]];
  } else if (ancilla_step[k] != 2) {
    if (ancilla_item_to_link[k] == 0x17)
      msg = kReceiveItemMsgs3[link_heart_pieces];
    else
      msg = kReceiveItemMsgs[ancilla_item_to_link[k]];
  }
  if (msg != -1) {
    dialogue_message_index = msg;
    if (msg == 0x70)
      sound_effect_ambient = 9;
    Main_ShowTextMessage();
  }
  goto endif_1;

label_b:
  if (ancilla_aux_timer[k] >= 24) {
    a = ancilla_y_vel[k] - 1;
    if (a >= 248)
      ancilla_y_vel[k] = a;
    Ancilla_MoveY(k);
  }
endif_1:

  if (ancilla_item_to_link[k] == 0x20) {
    ancilla_z[k] = 0;
    AncillaAdd_OccasionalSparkle(k);
    if (zelda_read_apui00() == 0) {
      music_control = 0x1a;
      ItemReceipt_TransmuteToRisingCrystal(k);
      return;
    }
  } else if (ancilla_item_to_link[k] == 0x1) {
    ancilla_arr4[k] = kReceiveItem_Tab0[0];
    if (ancilla_step[k] != 2) {
      if (ancilla_timer[k] < 16) {
        a = 0;
      } else {
        if (!sign8(--ancilla_arr3[k]))
          goto skipit;
        ancilla_arr3[k] = 2;
        a = ancilla_arr1[k] + 1;
        if (a == 3)
          a = 0;
      }
      ancilla_arr1[k] = a;
      ancilla_arr4[k] = kReceiveItem_Tab0[a];
skipit:;
    }
  }

  if ((ancilla_item_to_link[k] == 0x34 || ancilla_item_to_link[k] == 0x35 || ancilla_item_to_link[k] == 0x36) && sign8(--ancilla_arr3[k])) {
    a = ancilla_arr1[k] + 1;
    if (a == 3)
      a = 0;
    ancilla_arr1[k] = a;
    ancilla_arr3[k] = kReceiveItem_Tab4[a];
    WriteTo4BPPBuffer_at_7F4000(kReceiveItem_Tab5[a]);
  }
  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);
  Ancilla_ReceiveItem_Draw(k, pt.x, pt.y);
}

OamEnt *Ancilla_ReceiveItem_Draw(int k, int x, int y) {  // 88c690
  OamEnt *oam = GetOamCurPtr();
  int j = ancilla_item_to_link[k];
  oam->charnum = 0x24;
  uint8 a = kWishPond2_OamFlags[j];
  if (sign8(a))
    a = ancilla_arr4[k];
  Ancilla_SetOam(oam, x, y, 0x24, a * 2 | 0x30, kReceiveItem_Tab1[j]);
  oam++;
  if (kReceiveItem_Tab1[j] == 0) {
    Ancilla_SetOam(oam, x, y + 8, 0x34, a * 2 | 0x30, 0);
    oam++;
  }
  return oam;
}

void Ancilla28_WishPondItem(int k) {  // 88c6f2
  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 0x10);

  if (submodule_index == 0 && ancilla_timer[k] == 0) {
    link_picking_throw_state = 2;
    link_state_bits = 0;
    ancilla_z_vel[k] -= 2;
    Ancilla_MoveZ(k);
    Ancilla_MoveY(k);
    Ancilla_MoveX(k);
    if (sign8(ancilla_z[k]) && ancilla_z[k] < 228) {
      ancilla_z[k] = 228;
      Ancilla_SetXY(k,
          Ancilla_GetX(k) + (kGeneratedWishPondItem[ancilla_item_to_link[k]] ? 8 : 4), // wtf
          Ancilla_GetY(k) + 18);
      Ancilla_TransmuteToSplash(k);
      return;
    }
  }
  WishPondItem_Draw(k);
}

void WishPondItem_Draw(int k) {  // 88c760
  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);

  if (ancilla_item_to_link[k] == 1)
    ancilla_arr4[k] = 5;

  OamEnt *oam = Ancilla_ReceiveItem_Draw(k, pt.x, pt.y - (int8)ancilla_z[k]);

  if (link_picking_throw_state != 2 || !sign8(ancilla_z_vel[k]) && ancilla_z_vel[k] >= 2)
    return;

  uint8 xx = kGeneratedWishPondItem[ancilla_item_to_link[k]];
  AncillaDraw_Shadow(oam,
    (xx == 2) ? 1 : 2,
    pt.x - (xx == 2 ? 0 : 4),
    pt.y + 40, HIBYTE(oam_priority_value));
}

void Ancilla42_HappinessPondRupees(int k) {  // 88c7de
  link_picking_throw_state = 2;
  link_state_bits = 0;
  for (int i = 9; i >= 0; i--) {
    if (happiness_pond_arr1[i]) {
      HapinessPondRupees_ExecuteRupee(k, i);
      if (happiness_pond_step[i] == 2)
        happiness_pond_arr1[i] = 0;
    }
  }
  for (int i = 9; i >= 0; i--) {
    if (happiness_pond_arr1[i])
      return;
  }
  ancilla_type[k] = 0;
}

void HapinessPondRupees_ExecuteRupee(int k, int i) {  // 88c819
  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 0x10);
  HapinessPondRupees_GetState(k, i);

  if (ancilla_step[k]) {
    if (!submodule_index && !ancilla_timer[k]) {
      ancilla_timer[k] = 6;
      if (++ancilla_item_to_link[k] == 5) {
        ancilla_step[k]++;
      } else {
        ObjectSplash_Draw(k);
      }
    } else {
      ObjectSplash_Draw(k);
    }
  } else if (submodule_index == 0 && ancilla_timer[k] == 0) {
    ancilla_z_vel[k] -= 2;
    Ancilla_MoveY(k);
    Ancilla_MoveX(k);
    Ancilla_MoveZ(k);
    if (!sign8(ancilla_z[k]) || ancilla_z[k] >= 0xe4)
      goto else_label;
    ancilla_z[k] = 0xe4;
    Ancilla_SetXY(k, Ancilla_GetX(k) - 4, Ancilla_GetY(k) + 30);
    ancilla_item_to_link[k] = 0;
    ancilla_timer[k] = 6;
    Ancilla_Sfx2_Pan(k, 0x28);
    ancilla_step[k]++;
    ObjectSplash_Draw(k);
  } else {
else_label:
    ancilla_arr4[k] = 2;
    ancilla_floor[k] = 0;
    WishPondItem_Draw(k);
  }
  HapinessPondRupees_SaveState(i, k);
}

void HapinessPondRupees_GetState(int j, int k) {  // 88c8be
  ancilla_y_lo[j] = happiness_pond_y_lo[k];
  ancilla_y_hi[j] = happiness_pond_y_hi[k];
  ancilla_x_lo[j] = happiness_pond_x_lo[k];
  ancilla_x_hi[j] = happiness_pond_x_hi[k];
  ancilla_z[j] = happiness_pond_z[k];
  ancilla_y_vel[j] = happiness_pond_y_vel[k];
  ancilla_x_vel[j] = happiness_pond_x_vel[k];
  ancilla_z_vel[j] = happiness_pond_z_vel[k];
  ancilla_y_subpixel[j] = happiness_pond_y_subpixel[k];
  ancilla_x_subpixel[j] = happiness_pond_x_subpixel[k];
  ancilla_z_subpixel[j] = happiness_pond_z_subpixel[k];
  ancilla_item_to_link[j] = happiness_pond_item_to_link[k];
  ancilla_step[j] = happiness_pond_step[k];
  ancilla_timer[j] = happiness_pond_timer[k] ? happiness_pond_timer[k] - 1 : 0;
}

void HapinessPondRupees_SaveState(int k, int j) {  // 88c924
  happiness_pond_y_lo[k] = ancilla_y_lo[j];
  happiness_pond_y_hi[k] = ancilla_y_hi[j];
  happiness_pond_x_lo[k] = ancilla_x_lo[j];
  happiness_pond_x_hi[k] = ancilla_x_hi[j];
  happiness_pond_z[k] = ancilla_z[j];
  happiness_pond_y_vel[k] = ancilla_y_vel[j];
  happiness_pond_x_vel[k] = ancilla_x_vel[j];
  happiness_pond_z_vel[k] = ancilla_z_vel[j];
  happiness_pond_y_subpixel[k] = ancilla_y_subpixel[j];
  happiness_pond_x_subpixel[k] = ancilla_x_subpixel[j];
  happiness_pond_z_subpixel[k] = ancilla_z_subpixel[j];
  happiness_pond_item_to_link[k] = ancilla_item_to_link[j];
  happiness_pond_timer[k] = ancilla_timer[j];
  happiness_pond_step[k] = ancilla_step[j];
}

void Ancilla_TransmuteToSplash(int k) {  // 88c9cd
  ancilla_type[k] = 0x3d;
  ancilla_item_to_link[k] = 0;
  ancilla_timer[k] = 6;
  Ancilla_SetXY(k, Ancilla_GetX(k) - 8, Ancilla_GetY(k) + 12);
  Ancilla_Sfx2_Pan(k, 0x28);
  Ancilla3D_ItemSplash(k);
}

void Ancilla3D_ItemSplash(int k) {  // 88ca01
  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 8);
  if (!submodule_index && !ancilla_timer[k]) {
    ancilla_timer[k] = 6;
    if (++ancilla_item_to_link[k] == 5) {
      ancilla_type[k] = 0;
      return;
    }
  }
  ObjectSplash_Draw(k);
}

void ObjectSplash_Draw(int k) {  // 88ca22
  static const int8 kObjectSplash_Draw_X[10] = {0, 0, 0, 0, 11, -3, 15, -7, 15, -7};
  static const int8 kObjectSplash_Draw_Y[10] = {0, 0, -6, 0, -13, -8, -17, -4, -17, -4};
  static const uint8 kObjectSplash_Draw_Char[10] = {0xc0, 0xff, 0xe7, 0xff, 0xaf, 0xbf, 0x80, 0x80, 0x83, 0x83};
  static const uint8 kObjectSplash_Draw_Flags[10] = {0, 0xff, 0, 0xff, 0x40, 0, 0x40, 0, 0xc0, 0x80};
  static const uint8 kObjectSplash_Draw_Ext[10] = {2, 0, 2, 0, 0, 0, 0, 0, 0, 0};
  Point16U pt;
  Ancilla_PrepOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr();
  int j = ancilla_item_to_link[k] * 2;
  for (int i = 0; i != 2; i++, j++) {
    if (kObjectSplash_Draw_Char[j] != 0xff) {
      Ancilla_SetOam(oam, pt.x + kObjectSplash_Draw_X[j], pt.y + kObjectSplash_Draw_Y[j],
                     kObjectSplash_Draw_Char[j], kObjectSplash_Draw_Flags[j] | 0x24, 
                     kObjectSplash_Draw_Ext[j]);
      oam++;
    }
  }
}

void Ancilla29_MilestoneItemReceipt(int k) {  // 88ca8c
  if (ancilla_item_to_link[k] != 0x10 && ancilla_item_to_link[k] != 0x0f) {
    if (dung_savegame_state_bits & 0x4000) {
      ancilla_type[k] = 0;
      return;
    }

    if (!(dung_savegame_state_bits & 0x8000))
      return;

    if (byte_7E04C2 != 0) {
      if (byte_7E04C2 == 1) {
        if (ancilla_item_to_link[k] == 0x20) {
          sound_effect_ambient = 0x0f;
          DecodeAnimatedSpriteTile_variable(0x28);
        } else {
          DecodeAnimatedSpriteTile_variable(0x23);
        }
      }
      byte_7E04C2--;
      return;
    }
    if (!ancilla_arr3[k] && ancilla_item_to_link[k] == 0x20) {
      ancilla_arr3[k] = 1;
      palette_sp6r_indoors = 4;
      overworld_palette_aux_or_main = 0x200;
      Palette_Load_SpriteEnvironment_Dungeon();
      flag_update_cgram_in_nmi++;
    }
  } else {
    if (ancilla_G[k]) {
      ancilla_G[k]--;
      return;
    }
  }

  if (ancilla_item_to_link[k] == 0x20)
    AncillaAdd_OccasionalSparkle(k);

  if (submodule_index == 0) {
    CheckPlayerCollOut coll_out;
    if (ancilla_z[k] < 24 && Ancilla_CheckLinkCollision(k, 2, &coll_out) && related_to_hookshot == 0 && link_auxiliary_state == 0) {
      ancilla_type[k] = 0;
      if (link_player_handler_state == kPlayerState_ReceivingEther || link_player_handler_state == kPlayerState_ReceivingBombos) {
        flag_custom_spell_anim_active = 0;
        link_force_hold_sword_up = 0;
        link_player_handler_state = 0;
      }
      item_receipt_method = 3;
      Link_ReceiveItem(ancilla_item_to_link[k], 0);
      return;
    }

    if (ancilla_step[k] != 2) {
      if (ancilla_step[k] != 0) {
        ancilla_z_vel[k]--;
      }
      Ancilla_MoveZ(k);
      if (ancilla_z[k] >= 0xf8) {
        ancilla_step[k]++;
        ancilla_z_vel[k] = 0x18;
        ancilla_z[k] = 0;
      }
    }
  }

  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);
  OamEnt *oam = Ancilla_ReceiveItem_Draw(k, pt.x, pt.y - ancilla_z[k]);

  if (sign8(--ancilla_aux_timer[k])) {
    ancilla_aux_timer[k] = 9;
    if (++ancilla_L[k] == 3)
      ancilla_L[k] = 0;
  }

  int t;
  if (ancilla_z[k] == 0) {
    t = (dungeon_room_index == 6) ? ancilla_L[k] + 4 : 0;
  } else {
    t = ancilla_z[k] < 0x20 ? 1 : 2;
  }
  AncillaDraw_Shadow(oam, t, pt.x, pt.y + 12, 0x20);
}

void ItemReceipt_TransmuteToRisingCrystal(int k) {  // 88cbe4
  ancilla_type[k] = 0x3e;
  ancilla_y_vel[k] = 0;
  ancilla_x_vel[k] = 0;
  ancilla_y_subpixel[k] = 0;
  Ancilla_RisingCrystal(k);
}

void Ancilla_RisingCrystal(int k) {  // 88cbf2
  ancilla_z[k] = 0;
  AncillaAdd_OccasionalSparkle(k);
  uint8 yy = ancilla_y_vel[k] - 1;
  if (yy < 0xf0)
    yy = 0xf0;
  ancilla_y_vel[k] = yy;
  Ancilla_MoveY(k);

  uint16 y = Ancilla_GetY(k) - BG2VOFS_copy;
  if (y < 0x49) {
    Ancilla_SetY(k, 0x49 + BG2VOFS_copy);
    if (!submodule_index) {
      link_has_crystals |= kDungeonCrystalPendantBit[BYTE(cur_palace_index_x2) >> 1];
      submodule_index = 0x18;
      subsubmodule_index = 0;
      memset(aux_palette_buffer + 0x20, 0, sizeof(uint16) * 0x60);
      palette_filter_countdown = 0;
      darkening_or_lightening_screen = 0;
    }
  }

  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);
  Ancilla_ReceiveItem_Draw(k, pt.x, pt.y);
}

void AncillaAdd_OccasionalSparkle(int k) {  // 88cc93
  if (!(frame_counter & 7))
    AncillaAdd_SwordChargeSparkle(k);
}

void Ancilla43_GanonsTowerCutscene(int k) {  // 88cca0
  OamEnt *oam = GetOamCurPtr();
  if (!ancilla_step[k]) {
    uint8 yy = ancilla_y_vel[k] - 1;
    ancilla_y_vel[k] = (yy < 0xf0) ? 0xf0 : yy;
    Ancilla_MoveY(k);
    uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
    if ((uint16)(y - BG2VOFS_copy) >= 0x38)
      goto lbl_else;
    breaktowerseal_y = 0x38 + 8 + BG2VOFS_copy;
    breaktowerseal_x = x + 8;
    Ancilla_SetY(k, 0x38 + BG2VOFS_copy);
    ancilla_step[k]++;
    sound_effect_ambient = 5;
    music_control = 0xf1;
    dialogue_message_index = 0x13b;
    Main_ShowTextMessage();
    goto label_a;
  }
lbl_else:
  if (ancilla_step[k] == 1 && submodule_index == 0) {
    ancilla_x_vel[k] = 16;
    uint8 bak0 = ancilla_x_lo[k];
    uint8 bak1 = ancilla_x_hi[k];
    ancilla_x_lo[k] = breaktowerseal_var4;
    ancilla_x_hi[k] = 0;
    Ancilla_MoveX(k);
    breaktowerseal_var4 = ancilla_x_lo[k];
    ancilla_x_lo[k] = bak0;
    ancilla_x_hi[k] = bak1;
    if (breaktowerseal_var4 >= 48) {
      breaktowerseal_var4 = 48;
      ancilla_step[k]++;
    }
  }
  if (submodule_index)
    goto label_b;
  if (ancilla_step[k] == 0)
    goto label_a;
  if (ancilla_step[k] == 1)
    goto label_b;
  if (ancilla_step[k] == 2) {
    if (--breaktowerseal_var5 == 0) {
      trigger_special_entrance = 5;
      subsubmodule_index = 0;
      BYTE(R16) = 0;
      ancilla_step[k]++;
    }
  } else {
    ancilla_x_vel[k] = 48;
    uint8 bak0 = ancilla_x_lo[k];
    uint8 bak1 = ancilla_x_hi[k];
    ancilla_x_lo[k] = breaktowerseal_var4;
    ancilla_x_hi[k] = 0;
    Ancilla_MoveX(k);
    breaktowerseal_var4 = ancilla_x_lo[k];
    ancilla_x_lo[k] = bak0;
    ancilla_x_hi[k] = bak1;
    if (breaktowerseal_var4 >= 240) {
      palette_sp6r_indoors = 0;
      overworld_palette_aux_or_main = 0x200;
      Palette_Load_SpriteEnvironment_Dungeon();
      flag_update_cgram_in_nmi++;
      ancilla_type[k] = 0;
      return;
    }
  }
  uint8 astep;
label_b:


  astep = ancilla_step[k];
  if (astep != 0)
    oam = GTCutscene_SparkleALot(oam);

  for (int j = 6; j >= 0; j--) {
    if (submodule_index == 0 && astep != 1 && !(frame_counter & 1))
      breaktowerseal_var3[j] = breaktowerseal_var3[j] + 1 & 63;
    AncillaRadialProjection arp = Ancilla_GetRadialProjection(breaktowerseal_var3[j], breaktowerseal_var4);
    int x = (arp.r6 ? -arp.r4 : arp.r4) + breaktowerseal_x - 8 - BG2HOFS_copy;
    int y = (arp.r2 ? -arp.r0 : arp.r0) + breaktowerseal_y - 8 - BG2VOFS_copy;

    breaktowerseal_base_sparkle_x_lo[j] = x;
    breaktowerseal_base_sparkle_x_hi[j] = x >> 8;

    breaktowerseal_base_sparkle_y_lo[j] = y;
    breaktowerseal_base_sparkle_y_hi[j] = y >> 8;

    AncillaDraw_GTCutsceneCrystal(oam, x, y);
    oam++;
  }
  Point16U info;
label_a:
  Ancilla_PrepAdjustedOamCoord(k, &info);

  breaktowerseal_base_sparkle_x_lo[7] = info.x;
  breaktowerseal_base_sparkle_x_hi[7] = info.x >> 8;
  breaktowerseal_base_sparkle_y_lo[7] = info.y;
  breaktowerseal_base_sparkle_y_hi[7] = info.y >> 8;

  AncillaDraw_GTCutsceneCrystal(oam, info.x, info.y);

  if (!ancilla_step[k])
    AncillaAdd_OccasionalSparkle(k);
  else if (!submodule_index)
    GTCutscene_ActivateSparkle();
}

void AncillaDraw_GTCutsceneCrystal(OamEnt *oam, int x, int y) {  // 88ceaa
  Ancilla_SetOam_Safe(oam, x, y, 0x24, 0x3c, 2);
}

void GTCutscene_ActivateSparkle() {  // 88cec7
  for (int k = 0x17; k >= 0; k--) {
    if (breaktowerseal_sparkle_var1[k] == 0xff) {
      breaktowerseal_sparkle_var1[k] = 0;
      breaktowerseal_sparkle_var2[k] = 4;
      int r = GetRandomNumber();
      int x = breaktowerseal_base_sparkle_x_hi[k & 7] << 8 | breaktowerseal_base_sparkle_x_lo[k & 7];
      int y = breaktowerseal_base_sparkle_y_hi[k & 7] << 8 | breaktowerseal_base_sparkle_y_lo[k & 7];
      x += r >> 4;
      y += r & 0xf;
      breaktowerseal_sparkle_x_lo[k] = x;
      breaktowerseal_sparkle_x_hi[k] = x >> 8;
      breaktowerseal_sparkle_y_lo[k] = y;
      breaktowerseal_sparkle_y_hi[k] = y >> 8;
      return;
    }
  }
}

OamEnt *GTCutscene_SparkleALot(OamEnt *oam) {  // 88cf35
  static const uint8 kSwordChargeSpark_Char[3] = {0xb7, 0x80, 0x83};
  static const uint8 kSwordChargeSpark_Flags[3] = {4, 4, 0x84};
  for (int k = 0x17; k >= 0; k--) {
    if (breaktowerseal_sparkle_var1[k] == 0xff)
      continue;

    if (sign8(--breaktowerseal_sparkle_var2[k])) {
      breaktowerseal_sparkle_var2[k] = 4;
      if (++breaktowerseal_sparkle_var1[k] == 3) {
        breaktowerseal_sparkle_var1[k] = 0xff;
        continue;
      }
    }

    int x = breaktowerseal_sparkle_x_hi[k] << 8 | breaktowerseal_sparkle_x_lo[k];
    int y = breaktowerseal_sparkle_y_hi[k] << 8 | breaktowerseal_sparkle_y_lo[k];
    int j = breaktowerseal_sparkle_var1[k];
    Ancilla_SetOam(oam, x, y, kSwordChargeSpark_Char[j], kSwordChargeSpark_Flags[j] | 0x30, 0);
    oam++;
  }
  return oam;
}

void Ancilla36_Flute(int k) {  // 88cfaa
  static const uint8 kFlute_Vels[4] = {0x18, 0x10, 0xa, 0};

  if (!submodule_index) {
    if (ancilla_step[k] != 3) {
      ancilla_z_vel[k] -= 2;
      Ancilla_MoveX(k);
      Ancilla_MoveZ(k);
      if (sign8(ancilla_z[k]) || ancilla_z[k] >= 0xf0) {
        ancilla_z_vel[k] = kFlute_Vels[++ancilla_step[k]];
        ancilla_z[k] = 0;
      }
    } else {
      CheckPlayerCollOut coll_out;
      if (Ancilla_CheckLinkCollision(k, 2, &coll_out) && !related_to_hookshot && link_auxiliary_state == 0) {
        ancilla_type[k] = 0;
        item_receipt_method = 0;
        Link_ReceiveItem(0x14, 0);
        return;
      }
    }
  }

  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr();
  Ancilla_SetOam(oam, pt.x, pt.y - (int8)ancilla_z[k], 0x24, HIBYTE(oam_priority_value) | 4, 2);
  if (oam->y == 0xf0)
    ancilla_type[k] = 0;
}

void Ancilla37_WeathervaneExplosion(int k) {  // 88d03d
  if (--weathervane_var2)
    return;
  weathervane_var2 = 1;
  if (!weathervane_var1) {
    weathervane_var1 = 1;
    music_control = 0xf3;
  }
  if (--ancilla_G[k])
    return;
  ancilla_G[k] = 1;
  if (!ancilla_arr3[k]) {
    ancilla_arr3[k] += 1;
    Ancilla_Sfx2_Near(0xc);
  }
  if (!ancilla_step[k] && sign8(--ancilla_aux_timer[k])) {
    ancilla_step[k] = 1;
    Overworld_AlterWeathervane();
    AncillaAdd_CutsceneDuck(0x38, 0);
  }
  weathervane_var13 = k;
  weathervane_var14 = 0;
  for (int i = 11; i >= 0; i--) {
    if (weathervane_arr12[i] == 0xff)
      continue;
    if (sign8(--weathervane_arr11[i])) {
      weathervane_arr11[i] = 1;
      weathervane_arr12[i] ^= 1;
    }

    ancilla_item_to_link[k] = weathervane_arr12[i];
    ancilla_y_lo[k] = weathervane_arr6[i];
    ancilla_y_hi[k] = weathervane_arr7[i];
    ancilla_x_lo[k] = weathervane_arr8[i];
    ancilla_x_hi[k] = weathervane_arr9[i];
    ancilla_z[k] = weathervane_arr10[i];
    ancilla_y_vel[k] = weathervane_arr3[i];
    ancilla_x_vel[k] = weathervane_arr4[i];
    weathervane_arr5[i] = ancilla_z_vel[k] = weathervane_arr5[i] - 1;

    Ancilla_MoveY(k);
    Ancilla_MoveX(k);
    Ancilla_MoveZ(k);

    uint8 c = (ancilla_z[k] < 0xf0) ? 0 : 0xff;
    AncillaDraw_WeathervaneExplosionWoodDebris(k);
    if (sign8(c))
      weathervane_arr12[i] = c;
    weathervane_arr6[i] = ancilla_y_lo[k];
    weathervane_arr7[i] = ancilla_y_hi[k];
    weathervane_arr8[i] = ancilla_x_lo[k];
    weathervane_arr9[i] = ancilla_x_hi[k];
    weathervane_arr10[i] = ancilla_z[k];
  }
  for (int i = 11; i >= 0; i--) {
    if (weathervane_arr12[i] != 0xff)
      return;
  }
  ancilla_type[k] = 0;
}

void AncillaDraw_WeathervaneExplosionWoodDebris(int k) {  // 88d188
  static const uint8 kWeathervane_Explode_Char[2] = {0x4e, 0x4f};
  Point16U pt;
  Ancilla_PrepOamCoord(k, &pt);
  pt.y -= (int8)ancilla_z[k];
  int i = ancilla_item_to_link[k];
  if (sign8(i))
    return;
  Ancilla_SetOam(GetOamCurPtr() + (weathervane_var14 >> 2), pt.x, pt.y, kWeathervane_Explode_Char[i], 0x3c, 0);
  weathervane_var14 += 4;
}

void Ancilla38_CutsceneDuck(int k) {  // 88d1d8
  static const uint8 kTravelBirdIntro_Tab0[2] = {0x40, 0};
  static const uint8 kTravelBirdIntro_Tab1[2] = {28, 60};

  if (!(frame_counter & 31))
    Ancilla_Sfx3_Pan(k, 0x1e);

  if (sign8(--ancilla_arr3[k])) {
    ancilla_arr3[k] = 3;
    ancilla_K[k] ^= 1;
  }

  if (!--ancilla_aux_timer[k]) {
    ancilla_aux_timer[k] = 1;
    if (!ancilla_L[k]) {
      if (!sign8(--ancilla_item_to_link[k])) {
        ancilla_z_vel[k] += ancilla_step[k] ? 1 : -1;
        if (abs8(ancilla_z_vel[k]) >= 12)
          ancilla_step[k] ^= 1;
        goto after_stuff;
      }
      ancilla_item_to_link[k] = 0;
      ancilla_step[k] = 0;
      ancilla_x_vel[k] = kTravelBirdIntro_Tab1[0];
      ancilla_z_vel[k] = -16;
      ancilla_L[k]++;
      ancilla_step[k] = 3;
    }
    ancilla_x_vel[k] += (ancilla_step[k] & 1) == 0 ? 1 : -1;
    uint8 absx = abs8(ancilla_x_vel[k]);
    if (absx == 0 && ++ancilla_L[k] == 7)
      ancilla_S[k] = 1;
    if (absx >= kTravelBirdIntro_Tab1[ancilla_S[k]]) {
      ancilla_step[k] ^= 3;
    }
    ancilla_dir[k] = sign8(ancilla_x_vel[k]) ? 2 : 3;
    uint8 t = (uint8)(kTravelBirdIntro_Tab1[ancilla_S[k]] - absx) >> 1;
    ancilla_z_vel[k] = (ancilla_step[k] & 2) ? -t : t;
  }
after_stuff:
  Ancilla_MoveX(k);
  Ancilla_MoveZ(k);
  BYTE(flag_travel_bird) = kTravelBird_DmaStuffs[ancilla_K[k] + 1];
  Point16U info;
  Ancilla_PrepOamCoord(k, &info);
  OamEnt *oam = GetOamCurPtr();
  Ancilla_SetOam(oam, info.x + kTravelBird_Draw_X[0], info.y + (int8)ancilla_z[k] + kTravelBird_Draw_Y[0],
                 kTravelBird_Draw_Char[0],
                 kTravelBird_Draw_Flags[0] | 0x30 | kTravelBirdIntro_Tab0[ancilla_dir[k] & 1], 2);
  oam++;
  AncillaDraw_Shadow(oam, 1, info.x, info.y + 48, 0x30);
  if (!sign16(info.x) && info.x >= 248) {
    ancilla_type[k] = 0;
    submodule_index = 0;
    link_item_flute = 3;
  }
}

void Ancilla23_LinkPoof(int k) {  // 88d3bc
  if (sign8(--ancilla_aux_timer[k])) {
    ancilla_aux_timer[k] = 7;
    if (++ancilla_item_to_link[k] == 3) {
      ancilla_type[k] = 0;
      link_is_transforming = 0;
      link_cant_change_direction = 0;
      if (!ancilla_step[k]) {
        link_animation_steps = 0;
        link_visibility_status = 0;
        link_is_bunny = link_is_bunny_mirror = BYTE(overworld_screen_index) & 0x40 ? 1 : 0;
        if (link_is_bunny)
          LoadGearPalettes_bunny();
        else
          LoadActualGearPalettes();
      }
      return;
    }
  }
  MorphPoof_Draw(k);
}

void MorphPoof_Draw(int k) {  // 88d3fd
  static const int8 kMorphPoof_X[12] = {0, 0, 0, 0, 0, 8, 0, 8, -4, 12, -4, 12};
  static const int8 kMorphPoof_Y[12] = {0, 0, 0, 0, 0, 0, 8, 8, -4, -4, 12, 12};
  static const uint8 kMorphPoof_Flags[12] = {0, 0xff, 0xff, 0xff, 0x40, 0, 0xc0, 0x80, 0, 0x40, 0x80, 0xc0};
  static const uint8 kMorphPoof_Char[3] = {0x86, 0xa9, 0x9b};
  static const uint8 kMorphPoof_Ext[3] = {2, 0, 0};
  if (sort_sprites_setting && ancilla_floor[k] && (!flag_for_boomerang_in_place || !(frame_counter & 1))) {
    oam_cur_ptr = 0x8d0;
    oam_ext_cur_ptr = 0xa20 + (0xd0 >> 2);
  }
  Point16U info;
  Ancilla_PrepOamCoord(k, &info);
  OamEnt *oam = GetOamCurPtr();
  int j = ancilla_item_to_link[k];
  uint8 ext = kMorphPoof_Ext[j];
  uint8 chr = kMorphPoof_Char[j];
  for (int i = 0; i < 4; i++, oam++) {
    Ancilla_SetOam(oam, info.x + kMorphPoof_X[j * 4 + i], info.y + kMorphPoof_Y[j * 4 + i], chr,
                   kMorphPoof_Flags[j * 4 + i] | 4 | HIBYTE(oam_priority_value), ext);
    if (ext == 2)
      break;
  }
}

void Ancilla40_DwarfPoof(int k) {  // 88d49a
  if (sign8(--ancilla_aux_timer[k])) {
    ancilla_aux_timer[k] = 7;
    if (++ancilla_item_to_link[k] == 3) {
      ancilla_type[k] = 0;
      tagalong_var5 = 0;
      return;
    }
  }
  MorphPoof_Draw(k);
}

void Ancilla3F_BushPoof(int k) {  // 88d519
  static const int8 kBushPoof_Draw_X[16] = {0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, -2, 10, -2, 10};
  static const int8 kBushPoof_Draw_Y[16] = {0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, -2, -2, 10, 10};
  static const uint8 kBushPoof_Draw_Char[16] = {0x86, 0x87, 0x96, 0x97, 0xa9, 0xa9, 0xa9, 0xa9, 0x8a, 0x8b, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b};
  static const uint8 kBushPoof_Draw_Flags[16] = {0, 0, 0, 0, 0, 0x40, 0x80, 0xc0, 0, 0, 0, 0, 0xc0, 0x80, 0x40, 0};

  if (ancilla_timer[k] == 0) {
    ancilla_timer[k] = 7;
    if (++ancilla_item_to_link[k] == 4) {
      ancilla_type[k] = 0;
      return;
    }
  }
  Oam_AllocateFromRegionC(0x10);
  Point16U pt;
  Ancilla_PrepOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr();

  int j = ancilla_item_to_link[k] * 4;
  for (int i = 0; i < 4; i++, j++, oam++) {
    Ancilla_SetOam(oam, pt.x + kBushPoof_Draw_X[j], pt.y + kBushPoof_Draw_Y[j],
                   kBushPoof_Draw_Char[j], kBushPoof_Draw_Flags[j] | 4 | HIBYTE(oam_priority_value), 0);
  }
}

void Ancilla26_SwordSwingSparkle(int k) {  // 88d65a
  static const int8 kSwordSwingSparkle_X[48] = {
    5,  10, -1,  5, 10, -4,  5, 10,  -4,  -4, -1,  -1,   0,   5,  -1,   0,
    5,  14,  0,  5, 14, 14, -1, -1, -23, -27, -1, -23, -27, -22, -23, -27,
    -22, -22, -1, -1, 32, 35, -1, 32,  35,  30, 32,  35,  30,  30,  -1,  -1,
  };
  static const int8 kSwordSwingSparkle_Y[48] = {
    -22, -18, -1, -22, -18, -17, -22, -18, -17, -17, -1, -1, 35, 40, -1, 35,
    40,  37, 35,  40,  37,  37,  -1,  -1,   2,   7, -1,  2,  7, 19,  2,  7,
    19,  19, -1,  -1,   2,   7,  -1,   2,   7,  19,  2,  7, 19, 19, -1, -1,
  };
  static const uint8 kSwordSwingSparkle_Char[48] = {
    0xb7, 0xb7, 0xff, 0x80, 0x80, 0xb7, 0x83, 0x83, 0x80, 0x83, 0xff, 0xff, 0xb7, 0xb7, 0xff, 0x80,
    0x80, 0xb7, 0x83, 0x83, 0x80, 0x83, 0xff, 0xff, 0xb7, 0xb7, 0xff, 0x80, 0x80, 0xb7, 0x83, 0x83,
    0x80, 0x83, 0xff, 0xff, 0xb7, 0xb7, 0xff, 0x80, 0x80, 0xb7, 0x83, 0x83, 0x80, 0x83, 0xff, 0xff,
  };
  static const uint8 kSwordSwingSparkle_Flags[48] = {
    0,    0, 0xff,    0, 0,    0, 0x80, 0x80, 0, 0x80, 0xff, 0xff, 0,    0, 0xff,    0,
    0,    0, 0x80, 0x80, 0, 0x80, 0xff, 0xff, 0,    0, 0xff,    0, 0,    0, 0x80, 0x80,
    0, 0x80, 0xff, 0xff, 0,    0, 0xff,    0, 0,    0, 0x80, 0x80, 0, 0x80, 0xff, 0xff,
  };
  if (sign8(--ancilla_aux_timer[k])) {
    ancilla_aux_timer[k] = 0;
    if (++ancilla_item_to_link[k] == 4) {
      ancilla_type[k] = 0;
      return;
    }
  }
  Ancilla_SetXY(k, link_x_coord, link_y_coord);

  Point16U info;
  Ancilla_PrepOamCoord(k, &info);

  k = ancilla_item_to_link[k] * 3 + ancilla_dir[k] * 12;

  OamEnt *oam = GetOamCurPtr();
  for (int n = 2; n >= 0; n--, k++, oam++) {
    uint8 chr = kSwordSwingSparkle_Char[k];
    if (chr == 0xff)
      continue;
    Ancilla_SetOam(oam, info.x + kSwordSwingSparkle_X[k], info.y + kSwordSwingSparkle_Y[k],
                   chr, kSwordSwingSparkle_Flags[k] | 0x4 | (oam_priority_value >> 8), 0);
  }
}

void Ancilla2A_SpinAttackSparkleA(int k) {  // 88d7b2
  static const uint8 kInitialSpinSpark_Timer[6] = {4, 2, 3, 3, 2, 1};
  if (!submodule_index && sign8(--ancilla_aux_timer[k])) {
    ancilla_aux_timer[k] = 0;
    if (!ancilla_timer[k]) {
      int j = ++ancilla_item_to_link[k];
      ancilla_timer[k] = kInitialSpinSpark_Timer[j];
      if (j == 5) {
        if (ancilla_step[k])
          AddSwordBeam(j);
        else
          SpinAttackSparkleA_TransmuteToNextSpark(k);
        return;
      }
    }
  }
  if (!ancilla_item_to_link[k])
    return;
  SpinSpark_Draw(k, -1);
}

void SpinAttackSparkleA_TransmuteToNextSpark(int k) {  // 88d86d
  static const uint8 kTransmuteSpinSpark_Arr[16] = {0x21, 0x20, 0x1f, 0x1e, 3, 2, 1, 0, 0x12, 0x11, 0x10, 0xf, 0x31, 0x30, 0x2f, 0x2e};
  static const int8 kTransmuteSpinSpark_X[4] = {-3, 21, 25, -8};
  static const int8 kTransmuteSpinSpark_Y[4] = {28, -2, 24, 6};

  ancilla_type[k] = 0x2b;
  int j = link_direction_facing * 2;
  swordbeam_arr[0] = kTransmuteSpinSpark_Arr[j + 0];
  swordbeam_arr[1] = kTransmuteSpinSpark_Arr[j + 1];
  swordbeam_arr[2] = kTransmuteSpinSpark_Arr[j + 2];
  swordbeam_arr[3] = swordbeam_var1 = kTransmuteSpinSpark_Arr[j + 3];
  ancilla_aux_timer[k] = 2;
  ancilla_item_to_link[k] = 0x4c;
  ancilla_arr3[k] = 8;
  ancilla_step[k] = 0;
  ancilla_L[k] = 0;
  ancilla_arr1[k] = 255;
  swordbeam_var2 = 20;

  swordbeam_temp_x = link_x_coord + 8;
  swordbeam_temp_y = link_y_coord + 12;

  j = link_direction_facing>>1;
  Ancilla_SetXY(k,
      link_x_coord + kTransmuteSpinSpark_X[j],
      link_y_coord + kTransmuteSpinSpark_Y[j]);
  Ancilla2B_SpinAttackSparkleB(k);
}

void Ancilla2B_SpinAttackSparkleB(int k) {  // 88d8fd
  static const uint8 kSpinSpark_Char[4] = {0xd7, 0xb7, 0x80, 0x83};

  if (ancilla_L[k]) {
    SpinAttackSparkleB_Closer(k);
    return;
  }
  uint8 flags = 2;
  if (!submodule_index) {
    uint8 t = (ancilla_item_to_link[k] -= 3);
    if (t < 13) {
      ancilla_aux_timer[k] = 1;
      ancilla_L[k] = 1;
      ancilla_item_to_link[k] = 0;
      SpinAttackSparkleB_Closer(k);
      return;
    }
    ancilla_step[k] = (t < 0x42) ? 3 : (t == 0x46) ? 1 : (t == 0x43) ? 2 : 0;
    if (sign8(--ancilla_aux_timer[k])) {
      flags = 4;
      ancilla_aux_timer[k] = 2;
    }
  }
  OamEnt *oam = GetOamCurPtr(), *oam_org = oam;
  int i = ancilla_step[k];
  do {
    if (submodule_index == 0)
      swordbeam_arr[i] = (swordbeam_arr[i] + 4) & 0x3f;
    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_arr[i], swordbeam_var2));
    Ancilla_SetOam(oam, pt.x, pt.y, kSpinSpark_Char[i], flags | HIBYTE(oam_priority_value), 0);
  } while (oam++, --i >= 0);

  if (submodule_index == 0) {
    if (!sign8(--ancilla_arr3[k]))
      goto endif_2;

    ancilla_arr3[k] = 0;
    ancilla_arr1[k] = (ancilla_arr1[k] + 1) & 3;
    if (ancilla_arr1[k] == 3)
      swordbeam_var1 = (swordbeam_var1 + 9) & 0x3f;
  }

  uint8 t;

  t = ancilla_arr1[k];
  if (t != 3) {
    static const uint8 kSpinSpark_Char2[3] = {0xb7, 0x80, 0x83};
    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_var1, swordbeam_var2));
    Ancilla_SetOam(oam, pt.x, pt.y, kSpinSpark_Char2[t], 4 | HIBYTE(oam_priority_value), 0);
  }
endif_2:
  if (ancilla_item_to_link[k] == 7)
    bytewise_extended_oam[oam_org - oam_buf + 3] = 1;
}

Point16U Sparkle_PrepOamFromRadial(AncillaRadialProjection p) {  // 88da17
  Point16U pt;
  pt.y = (p.r2 ? -p.r0 : p.r0) + swordbeam_temp_y - 4 - BG2VOFS_copy2;
  pt.x = (p.r6 ? -p.r4 : p.r4) + swordbeam_temp_x - 4 - BG2HOFS_copy2;
  return pt;
}

void SpinAttackSparkleB_Closer(int k) {  // 88da4c
  if (sign8(--ancilla_aux_timer[k])) {
    ancilla_aux_timer[k] = 1;
    if (++ancilla_item_to_link[k] == 3)
      ancilla_type[k] = 0;
  }
  SpinSpark_Draw(k, 4);
}

void Ancilla30_ByrnaWindupSpark(int k) {  // 88db24
  static const int8 kInitialCaneSpark_X[16] = {3, 1, 0, 0, 13, 16, 12, 12, 24, 7, -4, -10, -8, 9, 22, 26};
  static const int8 kInitialCaneSpark_Y[16] = {5, 0, -3, -6, -8, -3, 12, 28, 5, 0, 8, 16, 5, 0, 8, 16};
  static const int8 kInitialCaneSpark_Draw_X[16] = {-4, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, 0, -8, 0, -8, 0};
  static const int8 kInitialCaneSpark_Draw_Y[16] = {-4, 0, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0};
  static const uint8 kInitialCaneSpark_Draw_Char[16] = {0x92, 0xff, 0xff, 0xff, 0x8c, 0x8c, 0x8c, 0x8c, 0xd6, 0xd6, 0xd6, 0xd6, 0x93, 0x93, 0x93, 0x93};
  static const uint8 kInitialCaneSpark_Draw_Flags[16] = {0x22, 0xff, 0xff, 0xff, 0x22, 0x62, 0xa2, 0xe2, 0x24, 0x64, 0xa4, 0xe4, 0x22, 0x62, 0xa2, 0xe2};

  if (!submodule_index && sign8(--ancilla_aux_timer[k])) {
    ancilla_aux_timer[k] = 1;
    if (++ancilla_item_to_link[k] == 17) {
      ByrnaWindupSpark_TransmuteToNormal(k);
      return;
    }
  }
  if (!ancilla_item_to_link[k])
    return;

  int j = player_handler_timer;
  if (j == 2) {
    uint8 a = ancilla_arr3[k] - 1;
    if (sign8(a))
      a = 0, j = 3;
    ancilla_arr3[k] = a;
  }
  j += link_direction_facing * 2;
  Ancilla_SetXY(k, link_x_coord + kInitialCaneSpark_X[j], link_y_coord + kInitialCaneSpark_Y[j]);
  Point16U pt;
  Ancilla_PrepOamCoord(k, &pt);

  uint8 a = (ancilla_item_to_link[k] - 1) & 0xf;
  j = 0;
  if (a != 0)
    j = 4 * ((a != 15) ? (a & 1) + 1 : 3);

  OamEnt *oam = GetOamCurPtr();
  for (int i = 0; i < 4; i++, j++) {
    if (kInitialCaneSpark_Draw_Char[j] != 255) {
      Ancilla_SetOam(oam, pt.x + kInitialCaneSpark_Draw_X[j], pt.y + kInitialCaneSpark_Draw_Y[j],
                     kInitialCaneSpark_Draw_Char[j],
                     kInitialCaneSpark_Draw_Flags[j] & ~0x30 | HIBYTE(oam_priority_value), 0);
      oam++;
    }
  }
}

void ByrnaWindupSpark_TransmuteToNormal(int k) {  // 88dc21
  static const uint8 kCaneSpark_Transmute_Tab[16] = {0x34, 0x33, 0x32, 0x31, 0x16, 0x15, 0x14, 0x13, 0x2a, 0x29, 0x28, 0x27, 0x10, 0xf, 0xe, 0xd};

  ancilla_type[k] = 0x31;
  int j = link_direction_facing << 1;
  swordbeam_arr[0] = kCaneSpark_Transmute_Tab[j + 0];
  swordbeam_arr[1] = kCaneSpark_Transmute_Tab[j + 1];
  swordbeam_arr[2] = kCaneSpark_Transmute_Tab[j + 2];
  swordbeam_arr[3] = kCaneSpark_Transmute_Tab[j + 3];
  ancilla_aux_timer[k] = 0x17;
  ancilla_G[k] = 0;
  ancilla_item_to_link[k] = 0;
  ancilla_arr3[k] = 8;
  ancilla_step[k] = 0;
  ancilla_L[k] = 0;
  ancilla_arr1[k] = 2;
  ancilla_timer[k] = 21;
  swordbeam_var2 = 20;
  Ancilla_Sfx3_Near(0x30);
  Ancilla31_ByrnaSpark(k);
}

void Ancilla31_ByrnaSpark(int k) {  // 88dc70
  static const uint8 kCaneSpark_Magic[3] = {4, 2, 1};

  uint8 flags = 2;
  if (submodule_index == 0) {
    if (current_item_y != 13) {
kill_me:
      link_disable_sprite_damage = 0;
      ancilla_type[k] = 0;
      link_give_damage = 0;
      return;
    }
    link_disable_sprite_damage = 1;
    if (!--ancilla_aux_timer[k]) {
      ancilla_aux_timer[k] = 1;
      uint8 r0 = kCaneSpark_Magic[link_magic_consumption];
      if (!link_magic_power || (uint8)(r0 = link_magic_power - r0) >= 0x80)
        goto kill_me;

      if (sign8(--ancilla_G[k])) {
        ancilla_G[k] = 0x17;
        link_magic_power = r0;
      }
      if (filtered_joypad_H & 0x40)
        goto kill_me;
    }
    if (ancilla_step[k] != 3) {
      uint8 a = ++ancilla_item_to_link[k];
      ancilla_step[k] = (a >= 4) ? 3 : (a == 2) ? 1 : (a == 3) ? 2 : 0;
    }
    if (sign8(--ancilla_arr1[k])) {
      ancilla_arr1[k] = 2;
      flags = 4;
    }
  }

  int z = (int8)link_z_coord;
  if (z == -1)
    z = 0;
  swordbeam_temp_y = link_y_coord + 12 - z;
  swordbeam_temp_x = link_x_coord + 8;
  if (!ancilla_timer[k]) {
    ancilla_timer[k] = 21;
    Ancilla_Sfx3_Near(0x30);
  }
  OamEnt *oam = GetOamCurPtr();
  int i = ancilla_step[k];
  do {
    static const uint8 kCaneSpark_Char[4] = {0xd7, 0xb7, 0x80, 0x83};
    if (!submodule_index)
      swordbeam_arr[i] = (swordbeam_arr[i] + 3) & 0x3f;
    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_arr[i], swordbeam_var2));
    Ancilla_SetOam(oam, pt.x, pt.y, kCaneSpark_Char[i], flags | HIBYTE(oam_priority_value), 0);
    Ancilla_SetXY(k, pt.x + BG2HOFS_copy2, pt.y + BG2VOFS_copy2);
    ancilla_dir[k] = 0;
    Ancilla_CheckSpriteCollision(k);
  } while (oam++, --i >= 0);
}

void Ancilla_SwordBeam(int k) {  // 88ddc5
  uint8 flags = 2;

  if (!submodule_index) {
    Ancilla_SetXY(k, swordbeam_temp_x, swordbeam_temp_y);
    Ancilla_MoveX(k);
    Ancilla_MoveY(k);
    swordbeam_temp_x = Ancilla_GetX(k);
    swordbeam_temp_y = Ancilla_GetY(k);

    if ((ancilla_G[k]++ & 0xf) == 0) {
      sound_effect_2 = Ancilla_CalculateSfxPan(k) | 1;
    }

    if (Ancilla_CheckSpriteCollision(k) >= 0 || Ancilla_CheckTileCollision(k)) {
      static const int8 kSwordBeam_Yvel2[4] = {0, 0, -6, -6};
      static const int8 kSwordBeam_Xvel2[4] = {-8, -10, 0, 0};
      int j = ancilla_dir[k];
      Ancilla_SetXY(k,
          Ancilla_GetX(k) + kSwordBeam_Xvel2[j],
          Ancilla_GetY(k) + kSwordBeam_Yvel2[j]);
      ancilla_type[k] = 4;
      ancilla_timer[k] = 7;
      ancilla_numspr[k] = 0x10;
      return;
    }
    if (sign8(--ancilla_aux_timer[k])) {
      flags = 4;
      ancilla_aux_timer[k] = 2;
    }
  }

  OamEnt *oam = GetOamCurPtr();
  uint8 s = ancilla_S[k];
  for (int i = 3; i >= 0; i--, oam++) {
    static const uint8 kSwordBeam_Char[4] = {0xd7, 0xb7, 0x80, 0x83};
    if (submodule_index == 0)
      swordbeam_arr[i] = (swordbeam_arr[i] + s) & 0x3f;
    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_arr[i], swordbeam_var2));
    Ancilla_SetOam(oam, pt.x, pt.y, kSwordBeam_Char[i], flags | HIBYTE(oam_priority_value), 0);
  }

  if (submodule_index == 0) {
    if (!sign8(--ancilla_arr3[k]))
      goto endif_2;

    ancilla_arr3[k] = 0;
    ancilla_arr1[k] = (ancilla_arr1[k] + 1) & 3;
    if (ancilla_arr1[k] == 3)
      swordbeam_var1 = (swordbeam_var1 + s) & 0x3f;
  }

  uint8 t;

  t = ancilla_arr1[k];
  if (t != 3) {
    static const uint8 kSwordBeam_Char2[3] = {0xb7, 0x80, 0x83};
    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_var1, swordbeam_var2));
    Ancilla_SetOam(oam, pt.x, pt.y, kSwordBeam_Char2[t], 4 | HIBYTE(oam_priority_value), 0);
  }
endif_2:
  oam -= 4;
  for (int i = 0; i < 4; i++) {
    if (oam[i].y != 0xf0)
      return;
  }
  ancilla_type[k] = 0;
}

void Ancilla0D_SpinAttackFullChargeSpark(int k) {  // 88ddca
  static const int8 kSwordFullChargeSpark_Y[4] = {-8, 27, 12, 12};
  static const int8 kSwordFullChargeSpark_X[4] = {4, 4, -13, 20};
  static const uint8 kSwordFullChargeSpark_Flags[4] = {0x20, 0x10, 0x30, 0x20};

  ancilla_oam_idx[k] = Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 4);

  if (!ancilla_timer[k]) {
    ancilla_type[k] = 0;
    return;
  }

  int j = link_direction_facing >> 1;

  uint16 x = link_x_coord + kSwordFullChargeSpark_X[j] - BG2HOFS_copy2;
  uint16 y = link_y_coord + kSwordFullChargeSpark_Y[j] - BG2VOFS_copy2;

  oam_priority_value = kSwordFullChargeSpark_Flags[ancilla_floor[k]] << 8;
  OamEnt *oam = GetOamCurPtr();
  Ancilla_SetOam(oam, x, y, 0xd7, HIBYTE(oam_priority_value) | 2, 0);
}

void Ancilla27_Duck(int k) {  // 88dde8
  CheckPlayerCollOut coll;
  int j;

  if (submodule_index)
    goto endif_1;

  if (ancilla_timer[k]) {
    int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
    Ancilla_SetXY(k, BG2HOFS_copy2 - 16 - xt, link_y_coord - 8);
    return;
  }

  if (sign8(--ancilla_G[k])) {
    ancilla_G[k] = 0x28;
    Ancilla_Sfx3_Pan(k, 0x1e);
  }

  if (ancilla_L[k] || ancilla_step[k] && (flag_unk1++, true)) {
    ancilla_z_vel[k]--;
    Ancilla_MoveZ(k);
  }
  Ancilla_MoveX(k);


  if (ancilla_L[k]) {
    uint16 x = Ancilla_GetX(k);
    if (ancilla_step[k])
      flag_unk1++;
    if (!sign16(x) && x >= link_x_coord) {
      if (ancilla_step[k]) {
        ancilla_step[k] = 0;
        link_visibility_status = 0;
        tagalong_var5 = 0;
        link_pose_for_item = 0;
        ancilla_y_vel[k] = 0;
        flag_is_link_immobilized = 0;
        link_disable_sprite_damage = 0;
        byte_7E03FD = 0;
        countdown_for_blink = 144;
        if (!((follower_indicator == 12 || follower_indicator == 13) && follower_dropped)) {
          Follower_Initialize();
        }
      }
    } else if ((uint16)(link_x_coord - x) < 48) {
      j = 3;
      goto endif_5;
    }
    goto endif_1;
  }

  if (!Ancilla_CheckLinkCollision(k, 1, &coll) || main_module_index == 15)
    goto endif_1;

  if (!player_is_indoors) {
    if (link_player_handler_state == 8 || link_player_handler_state == 9 || link_player_handler_state == 10 ||
        player_near_pit_state == 2 ||
        (link_pose_for_item | related_to_hookshot | link_force_hold_sword_up | link_disable_sprite_damage) ||
        (link_state_bits & 0x80))
      goto endif_1;
    for (int i = 4; i >= 0; i--) {
      uint8 a = ancilla_type[i];
      if (a == 0x2a || a == 0x1f || a == 0x30 || a == 0x31 || a == 0x41)
        ancilla_type[i] = 0;
    }
    if (follower_indicator == 9) {
      follower_indicator = 0;
      tagalong_var5 = 0;
    }
  }
  link_state_bits = 0;
  link_picking_throw_state = 0;

  bg1_x_offset = 0;
  bg1_y_offset = 0;
  Link_ResetProperties_A();
  link_is_in_deep_water = 0;
  link_need_for_pullforrupees_sprite = 0;
  link_visibility_status = 12;
  link_player_handler_state = 0;
  link_pose_for_item = 1;
  flag_is_link_immobilized = 1;
  link_disable_sprite_damage = 1;
  tagalong_var5 = 1;
  ancilla_step[k] = 2;
  flag_unk1++;
  link_give_damage = 0;
  if (player_is_indoors)
    byte_7E03FD = player_is_indoors;
endif_1:
  if (sign8(--ancilla_arr3[k])) {
    ancilla_arr3[k] = 3;
    if (++ancilla_K[k] == 3)
      ancilla_K[k] = 0;
  }
  j = ancilla_K[k];
endif_5:
  BYTE(flag_travel_bird) = kTravelBird_DmaStuffs[j];

  Point16U info;
  Ancilla_PrepOamCoord(k, &info);

  OamEnt *oam = GetOamCurPtr();
  int z = ancilla_z[k] ? ancilla_z[k] | ~0xff : 0;
  int i = 0, n = ancilla_step[k] + 1;
  do {
    Ancilla_SetOam(oam, info.x + (int8)kTravelBird_Draw_X[i], info.y + z + (int8)kTravelBird_Draw_Y[i],
                   kTravelBird_Draw_Char[i], kTravelBird_Draw_Flags[i] | 0x30, 2);
    oam++;
  } while (++i != n);

  AncillaDraw_Shadow(oam, 1, info.x, info.y + 28, 0x30);
  oam += 2;
  if (ancilla_step[k])
    AncillaDraw_Shadow(oam, 1, info.x - 7, info.y + 28, 0x30);

  if (!sign16(info.x) && info.x >= 0x130) {
    ancilla_type[k] = 0;
    if (!ancilla_L[k] && ancilla_step[k]) {
      submodule_index = 10;
      saved_module_for_menu = main_module_index;
      main_module_index = 14;
    }
  }
}

int AncillaAdd_SomariaBlock(uint8 type, uint8 y) {  // 88e078
  int k = AncillaAdd_AddAncilla_Bank08(type, y);
  if (k < 0)
    return k;
  for (int j = 4; j >= 0; j--) {
    if (j == k || ancilla_type[j] != 0x2c)
      continue;
    if (j == flag_is_ancilla_to_pick_up - 1)
      flag_is_ancilla_to_pick_up = 0;
    AncillaAdd_ExplodingSomariaBlock(j);
    ancilla_type[k] = 0;
    dung_flag_somaria_block_switch = 0;
    if (link_speed_setting == 0x12) {
      bitmask_of_dragstate = 0;
      link_speed_setting = 0;
    }
    return k;
  }

  Ancilla_Sfx3_Near(0x2a);
  ancilla_step[k] = 0;
  ancilla_y_vel[k] = 0;
  ancilla_x_vel[k] = 0;
  ancilla_item_to_link[k] = 0;
  ancilla_aux_timer[k] = 0;
  ancilla_arr3[k] = 0;
  ancilla_arr1[k] = 0;
  ancilla_H[k] = 0;
  ancilla_G[k] = 12;
  ancilla_timer[k] = 18;
  ancilla_L[k] = 0;
  ancilla_z[k] = 0;
  ancilla_K[k] = 0;
  ancilla_R[k] = 0;
  ancilla_arr4[k] = 0;
  ancilla_S[k] = 9;
  ancilla_T[k] = 0;
  ancilla_dir[k] = link_direction_facing >> 1;
  if (Ancilla_CheckInitialTileCollision_Class2(k)) {
    Ancilla_SetX(k, link_x_coord + 8);
    Ancilla_SetY(k, link_y_coord + 16);
  } else {
    static const int8 kCaneOfSomaria_Y[4] = { -8, 31, 17, 17 };
    static const int8 kCaneOfSomaria_X[4] = { 8, 8, -8, 23 };
    int j = link_direction_facing >> 1;
    Ancilla_SetX(k, link_x_coord + kCaneOfSomaria_X[j]);
    Ancilla_SetY(k, link_y_coord + kCaneOfSomaria_Y[j]);
    SomariaBlock_CheckForTransitTile(k);
  }
  return k;
}

void SomariaBlock_CheckForTransitTile(int k) {  // 88e191
  static const int8 kSomariaTransitLine_X[12] = { -8, 0, 8, -8, 0, 8, -16, -16, -16, 16, 16, 16 };
  static const int8 kSomariaTransitLine_Y[12] = { -16, -16, -16, 16, 16, 16, -8, 0, 8, -8, 0, 8 };
  if (!dung_unk6)
    return;
  for (int j = 11; j >= 0; j--) {
    uint16 x = Ancilla_GetX(k) + kSomariaTransitLine_X[j];
    uint16 y = Ancilla_GetY(k) + kSomariaTransitLine_Y[j];
    uint8 bak = ancilla_objprio[k];
    Ancilla_CheckTileCollision_targeted(k, x, y);
    ancilla_objprio[k] = bak;
    if (ancilla_tile_attr[k] == 0xb6 || ancilla_tile_attr[k] == 0xbc) {
      Ancilla_SetX(k, x);
      Ancilla_SetY(k, y);
      AncillaAdd_SomariaPlatformPoof(k);
      return;
    }
  }
}

int Ancilla_CheckBasicSpriteCollision(int k) {  // 88e1f9
  for (int j = 15; j >= 0; j--) {
    if (((j ^ frame_counter) & 3 | sprite_pause[j] | sprite_hit_timer[j]) != 0)
      continue;
    if (sprite_state[j] < 9 || !(sprite_defl_bits[j] & 2) && ancilla_objprio[k])
      continue;
    if (ancilla_floor[k] != sprite_floor[j])
      continue;
    if (ancilla_type[k] == 0x2c && (sprite_type[j] == 0x1e || sprite_type[j] == 0x90))
      continue;
    if (Ancilla_CheckBasicSpriteCollision_Single(k, j))
      return j;
  }
  return -1;
}

bool Ancilla_CheckBasicSpriteCollision_Single(int k, int j) {  // 88e23d
  SpriteHitBox hb;
  Ancilla_SetupBasicHitBox(k, &hb);
  Sprite_SetupHitBox(j, &hb);
  if (!CheckIfHitBoxesOverlap(&hb))
    return false;
  if (sprite_type[j] == 0x92 && sprite_C[j] < 3)
    return true;
  if (sprite_type[j] == 0x80 && sprite_delay_aux4[j] == 0) {
    sprite_delay_aux4[j] = 24;
    sprite_D[j] ^= 1;
  }
  if (sprite_ignore_projectile[j])
    return false;

  int x = Ancilla_GetX(k) - 8, y = Ancilla_GetY(k) - 8 - ancilla_z[k];
  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(j, x, y, 80);
  sprite_y_recoil[j] = ~pt.y;
  sprite_x_recoil[j] = ~pt.x;
  Ancilla_CheckDamageToSprite(j, ancilla_type[k]);
  return true;
}

void Ancilla_SetupBasicHitBox(int k, SpriteHitBox *hb) {  // 88e2ca
  int x = Ancilla_GetX(k) - 8;
  hb->r0_xlo = x;
  hb->r8_xhi = x >> 8;
  int y = Ancilla_GetY(k) - 8 - ancilla_z[k];
  hb->r1_ylo = y;
  hb->r9_yhi = y >> 8;
  hb->r2 = 15;
  hb->r3 = 15;
}

void Ancilla2C_SomariaBlock(int k) {  // 88e365
  if (!sign8(--ancilla_G[k]))
    return;
  ancilla_G[k] = 0;

  if (ancilla_H[k])
    goto label_1;
  if (submodule_index == 0 || submodule_index == 8 || submodule_index == 16) {
    Ancilla_HandleLiftLogic(k);
  } else if (k + 1 == flag_is_ancilla_to_pick_up && ancilla_K[k] != 0) {
    if (ancilla_K[k] != 3) {
      Ancilla_LatchLinkCoordinates(k, 3);
      Ancilla_LatchAltitudeAboveLink(k);
      ancilla_K[k] = 3;
    }
    Ancilla_LatchCarriedPosition(k);
  }
  if (player_is_indoors) {
    if (!ancilla_K[k] && !(link_state_bits & 0x80) && (ancilla_z[k] == 0 || ancilla_z[k] == 0xff)) {
      if (dung_unk6) {
        int j = frame_counter & 3;
        do {
          uint8 bak = ancilla_objprio[k];
          uint16 x = Ancilla_GetX(k) + kSomarianBlock_Coll_X[j];
          uint16 y = Ancilla_GetY(k) + kSomarianBlock_Coll_Y[j];
          Ancilla_CheckTileCollision_targeted(k, x, y);
          ancilla_objprio[k] = bak;
          if (ancilla_tile_attr[k] == 0xb6 || ancilla_tile_attr[k] == 0xbc) {
            Ancilla_SetXY(k, x, y);
            AncillaAdd_SomariaPlatformPoof(k);
            if (k + 1 == flag_is_ancilla_to_pick_up)
              flag_is_ancilla_to_pick_up = 0;
            return;
          }
        } while ((j += 4) < 12);
      } else {
        if (!SomariaBlock_CheckForSwitch(k) && (ancilla_z[k] == 0 || ancilla_z[k] == 0xff))
          dung_flag_somaria_block_switch++;
      }
    } else {
label_1:
      if (flag_is_ancilla_to_pick_up == k + 1)
        dung_flag_somaria_block_switch = 0;
    }
  }

  uint16 old_y = Ancilla_LatchYCoordToZ(k);
  uint8 s1a = ancilla_dir[k];
  uint8 s1b = ancilla_objprio[k];
  ancilla_objprio[k] = 0;
  bool flag = Ancilla_CheckTileCollision_Class2(k);

  if (player_is_indoors && ancilla_L[k] && ancilla_tile_attr[k] == 0x1c)
    ancilla_T[k] = 1;

label1:
  if (flag && (!(link_state_bits & 0x80) || link_picking_throw_state)) {
    if (!s1b && !ancilla_arr4[k] && ancilla_z[k]) {
      ancilla_arr4[k] = 1;
      int qq = (ancilla_dir[k] == 1) ? 16 : 4;
      if (ancilla_y_vel[k])
        ancilla_y_vel[k] = sign8(ancilla_y_vel[k]) ? qq : -qq;
      if (ancilla_x_vel[k])
        ancilla_x_vel[k] = sign8(ancilla_x_vel[k]) ? 4 : -4;
      if (ancilla_dir[k] == 1 && ancilla_z[k]) {
        ancilla_y_vel[k] = -4;
        ancilla_L[k] = 2;
      }
    }
  } else if (!(link_state_bits & 0x80) && (ancilla_z[k] == 0 || ancilla_z[k] == 0xff)) {
    ancilla_dir[k] = 16;
    uint8 bak0 = ancilla_objprio[k];
    Ancilla_CheckTileCollision(k);
    ancilla_objprio[k] = bak0;
    uint8 a = ancilla_tile_attr[k];
    if (a == 0x26) {
      flag = true;
      goto label1;
    } else if (a == 0xc || a == 0x1c) {
      if (dung_hdr_collision != 3) {
        if (ancilla_floor[k] == 0 && ancilla_z[k] != 0 && ancilla_z[k] != 0xff)
          ancilla_floor[k] = 1;
      } else {
        old_y = Ancilla_GetY(k) + dung_floor_y_vel;
        Ancilla_SetX(k, Ancilla_GetX(k) + dung_floor_x_vel);
      }
    } else if (a == 0x20 || (a & 0xf0) == 0xb0 && a != 0xb6 && a != 0xbc) {
      if (!(link_state_bits & 0x80)) {
        if (k + 1 == flag_is_ancilla_to_pick_up)
          flag_is_ancilla_to_pick_up = 0;
        if (!ancilla_timer[k]) {
          if (link_speed_setting == 18) {
            link_speed_setting = 0;
            bitmask_of_dragstate = 0;
          }
          ancilla_type[k] = 0;
          return;
        }
      }
    } else if (a == 8) {
      if (k + 1 == flag_is_ancilla_to_pick_up)
        flag_is_ancilla_to_pick_up = 0;
      if (ancilla_timer[k] == 0) {
        Ancilla_SetY(k, Ancilla_GetY(k) - 24);
        Ancilla_TransmuteToSplash(k);
        return;
      }
    } else if (a == 0x68 || a == 0x69 || a == 0x6a || a == 0x6b) {
      Ancilla_ApplyConveyor(k);
      old_y = Ancilla_GetY(k);
    } else {
      ancilla_timer[k] = (ancilla_L[k] | ancilla_H[k]) ? 0 : 2;
    }
  }
  // endif_3
  s1b |= ancilla_objprio[k];

  if (!(link_state_bits & 0x80) && !--ancilla_S[k]) {
    ancilla_S[k] = 1;
    ancilla_objprio[k] = 0;
    if (Ancilla_CheckBasicSpriteCollision(k) >= 0) {
      ancilla_S[k] = 7;
      if (++ancilla_step[k] == 5) {
        SomariaBlock_FizzleAway(k);
        return;
      }
    }
  }
  Ancilla_SetY(k, old_y);
  ancilla_dir[k] = s1a;
  ancilla_objprio[k] = s1b;

  AncillaDraw_SomariaBlock(k);
}

void AncillaDraw_SomariaBlock(int k) {  // 88e61b
  static const int8 kSomarianBlock_Draw_X[12] = {-8, 0, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  static const int8 kSomarianBlock_Draw_Y[12] = {-8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  static const uint8 kSomarianBlock_Draw_Flags[12] = {0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0};

  if (k + 1 == flag_is_ancilla_to_pick_up && link_state_bits & 0x80 && ancilla_K[k] != 3 && link_direction_facing == 0) {
    Ancilla_AllocateOamFromRegion_B_or_E(ancilla_numspr[k]);
  } else if (sort_sprites_setting && ancilla_floor[k] && (ancilla_L[k] || k + 1 == flag_is_ancilla_to_pick_up && (link_state_bits & 0x80))) {
    oam_cur_ptr = 0x8d0;
    oam_ext_cur_ptr = 0xa20 + 0x34;
  }

  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr(), *oam_org = oam;
  int z = (int8)ancilla_z[k];
  if (z != 0 && z != -1 && ancilla_K[k] != 3 && ancilla_objprio[k])
    oam_priority_value = 0x3000;
  pt.y -= z;
  int j = ancilla_arr1[k] * 4;
  int r8 = 0;
  do {
    Ancilla_SetOam_Safe(oam, pt.x + kSomarianBlock_Draw_X[j], pt.y + kSomarianBlock_Draw_Y[j], 0xe9,
                        kSomarianBlock_Draw_Flags[j] & ~0x30 | 2 | HIBYTE(oam_priority_value), 0);
    oam++;
  } while (j++, ++r8 & 3);

  if (SomarianBlock_CheckEmpty(oam_org)) {
    dung_flag_somaria_block_switch = 0;
    ancilla_type[k] = 0;
    if (k + 1 == flag_is_ancilla_to_pick_up) {
      flag_is_ancilla_to_pick_up = 0;
      if (link_state_bits & 128)
        link_state_bits = 0;
    }
  }
}

bool SomariaBlock_CheckForSwitch(int k) {  // 88e75c
  static const int8 kSomarianBlock_CheckCover_X[4] = {0, 0, -4, 4};
  static const int8 kSomarianBlock_CheckCover_Y[4] = {-4, 4, 0, 0};
  dung_flag_somaria_block_switch = 0;
  ancilla_arr24[k] = 0;
  for (int j = 3; j >= 0; j--) {
    uint16 y = Ancilla_GetY(k) + kSomarianBlock_CheckCover_Y[j];
    uint16 x = Ancilla_GetX(k) + kSomarianBlock_CheckCover_X[j];
    uint8 bak = ancilla_objprio[k];
    Ancilla_CheckTileCollision_targeted(k, x, y);
    ancilla_objprio[k] = bak;
    uint8 a = ancilla_tile_attr[k];
    if (a == 0x23 || a == 0x24 || a == 0x25 || a == 0x3b)
      ancilla_arr24[k]++;
  }
  return ancilla_arr24[k] != 4;
}

void SomariaBlock_FizzleAway(int k) {  // 88e9b2
  if (link_speed_setting == 18) {
    bitmask_of_dragstate = 0;
    link_speed_setting = 0;
  }
  dung_flag_somaria_block_switch = 0;
  ancilla_type[k] = 0x2d;
  ancilla_aux_timer[k] = 0;
  ancilla_step[k] = 0;
  ancilla_item_to_link[k] = 0;
  ancilla_arr3[k] = 0;
  ancilla_arr1[k] = 0;
  ancilla_R[k] = 0;
  if (k + 1 == flag_is_ancilla_to_pick_up) {
    flag_is_ancilla_to_pick_up = 0;
    link_state_bits &= 0x80;
  }
  Ancilla2D_SomariaBlockFizz(k);
}

void Ancilla2D_SomariaBlockFizz(int k) {  // 88e9e8
  static const int8 kSomariaBlockFizzle_X[6] = {-4, -1, -8, 0, -6, -2};
  static const int8 kSomariaBlockFizzle_Y[6] = {-4, -1, -4, -4, -4, -4};
  static const uint8 kSomariaBlockFizzle_Char[6] = {0x92, 0xff, 0xf9, 0xf9, 0xf9, 0xf9};
  static const uint8 kSomariaBlockFizzle_Flags[6] = {6, 0xff, 0x86, 0xc6, 0x86, 0xc6};
  if (sign8(--ancilla_aux_timer[k])) {
    ancilla_aux_timer[k] = 3;
    if (++ancilla_item_to_link[k] == 3) {
      ancilla_type[k] = 0;
      return;
    }
  }
  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr();
  uint8 z = ancilla_z[k];
  if (z == 0xff)
    z = 0;
  int x = pt.x, y = pt.y - (int8)z;
  int j = ancilla_item_to_link[k] * 2;
  for (int i = 0; i < 2; i++, j++, oam++) {
    if (kSomariaBlockFizzle_Char[j] != 0xff) {
      Ancilla_SetOam(oam, x + kSomariaBlockFizzle_X[j], y + kSomariaBlockFizzle_Y[j],
                     kSomariaBlockFizzle_Char[j],
                     kSomariaBlockFizzle_Flags[j] & ~0x30 | HIBYTE(oam_priority_value), 0);
    }
  }
}

void Ancilla39_SomariaPlatformPoof(int k) {  // 88ea83
  static const uint8 kSomarianPlatformPoof_Tab0[4] = {1, 0, 3, 2};
  if (!sign8(--ancilla_aux_timer[k]))
    return;
  ancilla_type[k] = 0;
  SpriteSpawnInfo info;
  int x = Ancilla_GetX(k) & ~7 | 4, y = Ancilla_GetY(k) & ~7 | 4;
  uint8 floor = ancilla_floor[k];
  int j = Sprite_SpawnDynamically(k, 0xed, &info);  // wtf
  if (j >= 0) {
    player_on_somaria_platform = 0;
    Sprite_SetX(j, x);
    Sprite_SetY(j, y);

    int pos = ((x & 0x1f8) >> 3) + ((y & 0x1f8) << 3) + (floor >= 1 ? 0x1000 : 0);

    int t = 0;
    if ((dung_bg2_attr_table[pos + XY(0, -1)] & 0xf0) != 0xb0) {
      t += 1;
      if ((dung_bg2_attr_table[pos + XY(0, 1)] & 0xf0) != 0xb0) {
        t += 1;
        if ((dung_bg2_attr_table[pos + XY(-1, 0)] & 0xf0) != 0xb0) {
          t += 1;
        }
      }
    }
    sprite_D[j] = kSomarianPlatformPoof_Tab0[t];
    sprite_floor[j] = 0;
  } else {
    AncillaDraw_SomariaBlock(k);
  }
}

void Ancilla2E_SomariaBlockFission(int k) {  // 88eb3e
  static const int8 kSomarianBlockDivide_X[16] = {-8, 0, -8, 0, -10, -10, 2, 2, -8, 0, -8, 0, -12, -12, 4, 4};
  static const int8 kSomarianBlockDivide_Y[16] = {-10, -10, 2, 2, -8, 0, -8, 0, -12, -12, 4, 4, -8, 0, -8, 0};
  static const uint8 kSomarianBlockDivide_Char[16] = {0xc6, 0xc6, 0xc6, 0xc6, 0xc4, 0xc4, 0xc4, 0xc4, 0xd2, 0xd2, 0xd2, 0xd2, 0xc5, 0xc5, 0xc5, 0xc5};
  static const uint8 kSomarianBlockDivide_Flags[16] = {0xc6, 0x86, 0x46, 6, 0x46, 0xc6, 6, 0x86, 0xc6, 0x86, 0x46, 6, 0x46, 0xc6, 6, 0x86};

  if (sign8(--ancilla_aux_timer[k])) {
    ancilla_aux_timer[k] = 3;
    if (++ancilla_item_to_link[k] == 2) {
      ancilla_type[k] = 0;
      SomariaBlock_SpawnBullets(k);
      return;
    }
  }
  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr();

  int8 z = ancilla_z[k] + (ancilla_K[k] == 3 && BYTE(link_z_coord) != 0xff ? BYTE(link_z_coord) : 0);
  int j = ancilla_item_to_link[k] * 8;
  for (int i = 0; i != 8; i++, j++, oam++) {
    Ancilla_SetOam(oam, pt.x + kSomarianBlockDivide_X[j], pt.y + kSomarianBlockDivide_Y[j] - z,
                   kSomarianBlockDivide_Char[j], kSomarianBlockDivide_Flags[j] & ~0x30 | HIBYTE(oam_priority_value), 0);
  }
}

void Ancilla2F_LampFlame(int k) {  // 88ec13
  static const uint8 kLampFlame_Draw_Char[12] = {0x9c, 0x9c, 0xff, 0xff, 0xa4, 0xa5, 0xb2, 0xb3, 0xe3, 0xf3, 0xff, 0xff};
  static const int8 kLampFlame_Draw_Y[12] = {-3, 0, 0, 0, 0, 0, 8, 8, 0, 8, 0, 0};
  static const int8 kLampFlame_Draw_X[12] = {4, 10, 0, 0, 1, 9, 2, 7, 4, 4, 0, 0};

  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr();
  if (!ancilla_timer[k]) {
    ancilla_type[k] = 0;
    return;
  }
  int j = (ancilla_timer[k] & 0xf8) >> 1;
  do {
    if (kLampFlame_Draw_Char[j] != 0xff) {
      Ancilla_SetOam(oam, pt.x + kLampFlame_Draw_X[j], pt.y + kLampFlame_Draw_Y[j], kLampFlame_Draw_Char[j], HIBYTE(oam_priority_value) | 2, 0);
      oam++;
    }
  } while (++j & 3);
}

void Ancilla41_WaterfallSplash(int k) {  // 88ecaf
  if (!Ancilla_CheckForEntranceTrigger(player_is_indoors ? 0 : 1)) {
    ancilla_type[k] = 0;
    return;
  }

  if (!submodule_index && !(frame_counter & 7))
    Ancilla_Sfx2_Near(0x1c);

  draw_water_ripples_or_grass = 1;
  if (!sign8(link_animation_steps - 6))
    link_animation_steps -= 6;

  if (!ancilla_timer[k]) {
    ancilla_timer[k] = 2;
    ancilla_item_to_link[k] = (ancilla_item_to_link[k] + 1) & 3;
  }

  if (player_is_indoors && BYTE(link_y_coord) < 0x38) {
    Ancilla_SetY(k, 0xd38);
  } else {
    Ancilla_SetY(k, link_y_coord);
  }
  Ancilla_SetX(k, link_x_coord);

  static const int8 kWaterfallSplash_X[8] = {0, 0, -4, 4, -7, 7, -9, 17};
  static const int8 kWaterfallSplash_Y[8] = {-4, 0, -5, -5, -3, -3, 12, 12};
  static const uint8 kWaterfallSplash_Char[8] = {0xc0, 0xff, 0xac, 0xac, 0xae, 0xae, 0xbf, 0xbf};
  static const uint8 kWaterfallSplash_Flags[8] = {0x84, 0xff, 0x84, 0xc4, 0x84, 0xc4, 0x84, 0xc4};
  static const uint8 kWaterfallSplash_Ext[8] = {2, 0xff, 2, 2, 2, 2, 0, 0};

  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);
  OamEnt *oam = GetOamCurPtr();

  uint8 z = link_z_coord;
  pt.y -= (sign8(z) ? 0 : z);

  int j = ancilla_item_to_link[k] * 2;
  for (int i = 0; i != 2; i++, j++, oam++) {
    if (kWaterfallSplash_Char[j] != 0xff) {
      Ancilla_SetOam(oam, pt.x + kWaterfallSplash_X[j], pt.y + kWaterfallSplash_Y[j], kWaterfallSplash_Char[j],
                     kWaterfallSplash_Flags[j] | 0x30, kWaterfallSplash_Ext[j]);
    }
  }
}

void Ancilla24_Gravestone(int k) {  // 88ee01
  static const uint8 kAncilla_Gravestone_Char[4] = {0xc8, 0xc8, 0xd8, 0xd8};
  static const uint8 kAncilla_Gravestone_Flags[4] = {0, 0x40, 0, 0x40};
  Point16U pt;
  Ancilla_PrepAdjustedOamCoord(k, &pt);
  Oam_AllocateFromRegionB(16);
  OamEnt *oam = GetOamCurPtr();
  uint16 x = pt.x, y = pt.y;
  for (int i = 0; i < 4; i++, oam++) {
    Ancilla_SetOam(oam, x, y, kAncilla_Gravestone_Char[i], kAncilla_Gravestone_Flags[i] | 0x3d, 2);
    x += 16;
    if (i == 1)
      x -= 32, y += 8;
  }
}

void Ancilla34_SkullWoodsFire(int k) {  // 88ef9a
  static const int8 kSkullWoodsFire_Draw_Y[4] = {0, 0, 0, -3};
  static const uint8 kSkullWoodsFire_Draw_Char[4] = {0x8e, 0xa0, 0xa2, 0xa4};
  static const uint8 kSkullWoodsFire_Draw_Ext[4] = {2, 2, 2, 0};
  static const int8 kSkullWoodsFire_Draw2_X[24] = {
    -13, -21, -10, -1,  -1,  -1, -16, -27, -4, -16, -6, -25, -16, -27, -4, -16,
    -6, -25, -13, -5, -27, -11, -22,  -3,
  };
  static const int8 kSkullWoodsFire_Draw2_Y[24] = {
    -31, -24, -22,  -1,  -1,  -1, -37, -32, -32, -23, -16, -14, -37, -32, -32, -23,
    -16, -14, -35, -29, -28, -20, -13, -11,
  };
  static const uint8 kSkullWoodsFire_Draw2_Char[24] = {
    0x86, 0x86, 0x86, 0xff, 0xff, 0xff, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x8a, 0x8a, 0x8a, 0x8a,
    0x8a, 0x8a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
  };
  static const uint8 kSkullWoodsFire_Draw2_Flags[24] = {
    0, 0,    0,    0,    0,    0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0x80, 0x40, 0x40, 0x80, 0x40, 0,
  };
  static const uint8 kSkullWoodsFire_Draw2_Ext[24] = {
    2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 0, 0, 0, 0, 0, 0,
  };
  if (skullwoodsfire_var4 && ancilla_item_to_link[k] != 4 && sign8(--ancilla_aux_timer[k])) {
    ancilla_aux_timer[k] = 5;
    ancilla_item_to_link[k]++;
  }
  OamEnt *oam = GetOamCurPtr();
  for(int k = 3; k >= 0; k--) {
    if (sign8(--skullwoodsfire_var5[k])) {
      skullwoodsfire_var5[k] = 5;
      if (skullwoodsfire_var0[k] == 128)
        goto endif_2;
      if (++skullwoodsfire_var0[k] != 0) {
        if (skullwoodsfire_var0[k] != 4)
          goto endif_2;
        skullwoodsfire_var0[k] = 0;
      }
      skullwoodsfire_var9 -= 8;
      if (skullwoodsfire_var9 < 200 && skullwoodsfire_var4 != 1) {
        skullwoodsfire_var4 = 1;
        sound_effect_1 = kBombos_Sfx[(uint8)(0x98 - BG2HOFS_copy2) >> 5] | 0xc;
      }
      if (skullwoodsfire_var9 < 168)
        skullwoodsfire_var0[k] = 128;
      skullwoodsfire_x_arr[k] = skullwoodsfire_var11;
      skullwoodsfire_y_arr[k] = skullwoodsfire_var9;
      if (sound_effect_1 == 0)
        sound_effect_1 = kBombos_Sfx[(uint8)(skullwoodsfire_var11 - BG2HOFS_copy2) >> 5] | 0x2a;
    }
endif_2:
    if (!sign8(skullwoodsfire_var0[k])) {
      int j = skullwoodsfire_var0[k];
      uint16 x = skullwoodsfire_x_arr[k] - BG2HOFS_copy2;
      uint16 y = skullwoodsfire_y_arr[k] - BG2VOFS_copy2 + kSkullWoodsFire_Draw_Y[j];
      Ancilla_SetOam(oam, x, y, kSkullWoodsFire_Draw_Char[j], 0x32, kSkullWoodsFire_Draw_Ext[j]);
      oam++;
      if (kSkullWoodsFire_Draw_Ext[j] != 2) {
        Ancilla_SetOam(oam, x + 8, y, kSkullWoodsFire_Draw_Char[j] + 1, 0x32, kSkullWoodsFire_Draw_Ext[j]);
        oam++;
      }
    }
  }

  for (int i = 3; sign8(skullwoodsfire_var0[i]); ) {
    if (--i < 0) {
      ancilla_type[k] = 0;
      return;
    }
  }

  if (skullwoodsfire_var4 == 0 || ancilla_item_to_link[k] == 4)
    return;

  int j = ancilla_item_to_link[k] * 6;
  for (int i = 0; i < 6; i++, j++) {
    if (kSkullWoodsFire_Draw2_Char[j] != 0xff) {
      Ancilla_SetOam(oam,
          168 - BG2HOFS_copy2 + kSkullWoodsFire_Draw2_X[j],
          200 - BG2VOFS_copy2 + kSkullWoodsFire_Draw2_Y[j],
          kSkullWoodsFire_Draw2_Char[j],
          kSkullWoodsFire_Draw2_Flags[j] | 0x32, kSkullWoodsFire_Draw2_Ext[j]);
      oam++;
    }
  }
}

void Ancilla3A_BigBombExplosion(int k) {  // 88f18d
  static const int8 kSuperBombExplode_X[9] = {0, -16, 0, 16, -24, 24, -16, 0, 16};
  static const int8 kSuperBombExplode_Y[9] = {0, -16, -24, -16, 0, 0, 16, 24, 16};

  if (!submodule_index && !--ancilla_arr3[k]) {
    if (++ancilla_item_to_link[k] == 2)
      Ancilla_Sfx2_Pan(k, 0xc);
    if (ancilla_item_to_link[k] == 11) {
      ancilla_type[k] = 0;
      return;
    }
    ancilla_arr3[k] = kBomb_Tab0[ancilla_item_to_link[k]];
  }
  oam_priority_value = 0x3000;
  uint8 numframes = kBomb_Draw_Tab2[ancilla_item_to_link[k]];
  int j = kBomb_Draw_Tab0[ancilla_item_to_link[k]] * 6;
  ancilla_step[k] = j * 2;

  int yy = 0;
  for (int i = 8; i >= 0; i--) {
    uint16 x = Ancilla_GetX(k) + kSuperBombExplode_X[i] - BG2HOFS_copy2;
    uint16 y = Ancilla_GetY(k) + kSuperBombExplode_Y[i] - BG2VOFS_copy2;
    if (x < 256 && y < 256) {
      Ancilla_AllocateOamFromRegion_A_or_D_or_F((uint8)(j * 2), 0x18); // wtf
      OamEnt *oam = GetOamCurPtr() + yy;
      yy += AncillaDraw_Explosion(oam, j, 0, numframes, 0x32, x, y) - oam;

    }
  }
  if (ancilla_item_to_link[k] == 3 && ancilla_arr3[k] == 1) {
    // Changed so this is reset elsewhere. Some code depends on the value 13.
    uint8 old = (enhanced_features0 & kFeatures0_MiscBugFixes) ? follower_indicator : 0;
    follower_indicator = 13;
    Bomb_CheckForDestructibles(Ancilla_GetX(k), Ancilla_GetY(k), 0); // r14?
    follower_indicator = old;
  }
}

void RevivalFairy_Main() {  // 88f283
  static const uint8 kAncilla_RevivalFaerie_Tab0[2] = {0, 0x90};
  static const uint8 kAncilla_RevivalFaerie_Tab1[5] = {0x4b, 0x4d, 0x49, 0x47, 0x49};

  int k = 0;
  switch (ancilla_step[k]) {
  case 0:
    if (!--ancilla_arr3[k]) {
      ancilla_arr3[k] = kAncilla_RevivalFaerie_Tab0[++ancilla_step[k]];
      ancilla_K[k] = 0;
      ancilla_z_vel[k] = 0;
    } else {
      Ancilla_MoveZ(k);
    }
    break;
  case 1:
    if (!--ancilla_arr3[k]) {
      ancilla_step[k]++;
      ancilla_z_vel[k] = 0;
      ancilla_x_vel[k] = 0;
    } else {
      if (ancilla_arr3[k] == 0x4f || ancilla_arr3[k] == 0x8f) {
        ancilla_L[k]++;
        Ancilla_Sfx2_Pan(k, 0x31);
      }
      if (ancilla_L[k] != 0 && sign8(--ancilla_G[k])) {
        ancilla_G[k] = 5;
        if (++ancilla_item_to_link[k] == 3) {
          ancilla_item_to_link[k] = 0;
          ancilla_L[k] = 0;
        }
      }
      ancilla_z_vel[k] += ancilla_K[k] ? 1 : -1;
      if (abs8(ancilla_z_vel[k]) == 8)
        ancilla_K[k] ^= 1;
      Ancilla_MoveZ(k);
    }
    break;
  case 2:
    if (ancilla_z_vel[k] < 24)
      ancilla_z_vel[k] += 1;
    if (ancilla_x_vel[k] < 16)
      ancilla_x_vel[k] += 1;
    Ancilla_MoveX(k);
    Ancilla_MoveZ(k);
    break;
  case 3:
    goto skip_draw;
  }

  {
    Oam_AllocateFromRegionC(12);
    Point16U pt;
    Ancilla_PrepOamCoord(k, &pt);
    OamEnt *oam = GetOamCurPtr();
    int t = (ancilla_step[k] == 1 && ancilla_L[k]) ? ancilla_item_to_link[k] + 1 : 0;
    if (t != 0)
      t += 1;
    else
      t = (frame_counter >> 2) & 1;
    Ancilla_SetOam(oam, pt.x, pt.y - (int8)ancilla_z[k], kAncilla_RevivalFaerie_Tab1[t], 0x74, 2);
    if (oam->y == 0xf0) {
      ancilla_step[k] = 3;
      submodule_index++;
      TM_copy = mapbak_TM;
    }
  }
skip_draw:
  RevivalFairy_Dust();
  RevivalFairy_MonitorHP();
}

void RevivalFairy_Dust() {  // 88f3cf
  int k = 2;
  if (ancilla_step[0] == 0 || ancilla_step[k] == 2 || !sign8(--ancilla_arr3[k]))
    return;
  ancilla_arr3[k] = 0;
  if (!sort_sprites_setting)
    Oam_AllocateFromRegionA(16);
  else
    Oam_AllocateFromRegionD(16);
  if (sign8(--ancilla_aux_timer[k])) {
    ancilla_aux_timer[k] = 3;
    if (ancilla_item_to_link[k] == 9) {
      ancilla_arr3[k] = 32;
      ancilla_step[k]++;
      ancilla_item_to_link[k] = 2;
      return;
    }
    ancilla_arr25[k] = kMagicPowder_Tab0[30 + ++ancilla_item_to_link[k]];
  }
  Ancilla_MagicPowder_Draw(k);
}

void RevivalFairy_MonitorHP() {  // 88f430
  if ((link_health_current == link_health_capacity || link_health_current == 0x38) && !is_doing_heart_animation) {
    if (link_is_in_deep_water) {
      link_some_direction_bits = 4;
      link_player_handler_state = kPlayerState_Swimming;
    } else if (link_is_bunny) {
      link_player_handler_state = kPlayerState_PermaBunny;
      link_is_bunny_mirror = 1;
      //bugfix: dying as permabunny doesn't restore link palette during death animation
      if (enhanced_features0 & kFeatures0_MiscBugFixes)
        LoadGearPalettes_bunny();
    } else {
      link_player_handler_state = kPlayerState_Ground;
    }
    link_auxiliary_state = 0;
    player_unk1 = 0;
    link_var30d = 0;
    some_animation_timer_steps = 0;
    BYTE(link_z_coord) = 0;
    link_incapacitated_timer = 0;
    for(int i = 0; i < 5; i++)
      ancilla_type[i] = 0;
    return;
  }
  int k = 1;
  if (!ancilla_step[k]) {
    if (!--ancilla_arr3[k]) {
      ancilla_arr3[k]++;
      ancilla_z_vel[k] = 4;
      Ancilla_MoveZ(k);
      if (ancilla_z[k] >= 16) {
        ancilla_step[k]++;
        ancilla_z_vel[k] = 2;
      }
    }
  } else {
    if (sign8(--ancilla_K[k])) {
      ancilla_K[k] = 32;
      ancilla_z_vel[k] = -ancilla_z_vel[k];
    }
    Ancilla_MoveZ(k);
  }
  BYTE(link_z_coord) = ancilla_z[k];
}

void GameOverText_Draw() {  // 88f5c4
  static const uint8 kGameOverText_Chars[16] = {0x40, 0x50, 0x41, 0x51, 0x42, 0x52, 0x43, 0x53, 0x44, 0x54, 0x45, 0x55, 0x43, 0x53, 0x46, 0x56};
  oam_cur_ptr = 0x800;
  oam_ext_cur_ptr = 0xa20;
  OamEnt *oam = GetOamCurPtr();
  int k = flag_for_boomerang_in_place;
  do {
    Ancilla_SetOam(oam + 0, Ancilla_GetX(k), 0x57, kGameOverText_Chars[k * 2 + 0], 0x3c, 0);
    Ancilla_SetOam(oam + 1, Ancilla_GetX(k), 0x5f, kGameOverText_Chars[k * 2 + 1], 0x3c, 0);
  } while (oam += 2, --k >= 0);
}

int AncillaAdd_AddAncilla_Bank08(uint8 type, uint8 y) {  // 88f631
  int k = Ancilla_AllocInit(type, y);
  if (k >= 0) {
    ancilla_type[k] = type;
    ancilla_numspr[k] = kAncilla_Pflags[type];
    ancilla_floor[k] = link_is_on_lower_level;
    ancilla_floor2[k] = link_is_on_lower_level_mirror;
    ancilla_y_vel[k] = 0;
    ancilla_x_vel[k] = 0;
    ancilla_objprio[k] = 0;
    ancilla_U[k] = 0;
  }
  return k;
}

void Ancilla_PrepOamCoord(int k, Point16U *info) {  // 88f671
  oam_priority_value = kTagalongLayerBits[ancilla_floor[k]] << 8;
  info->x = Ancilla_GetX(k) - BG2HOFS_copy2;
  info->y = Ancilla_GetY(k) - BG2VOFS_copy2;
}

void Ancilla_PrepAdjustedOamCoord(int k, Point16U *info) {  // 88f6a4
  oam_priority_value = kTagalongLayerBits[ancilla_floor[k]] << 8;
  info->x = Ancilla_GetX(k) - BG2HOFS_copy;
  info->y = Ancilla_GetY(k) - BG2VOFS_copy;
}

bool Ancilla_CheckLinkCollision(int k, int j, CheckPlayerCollOut *out) {  // 88f76b
  static const int16 kAncilla_Coll_Yoffs[5] = {0, 8, 8, 8, 0};
  static const int16 kAncilla_Coll_Xoffs[5] = {0, 8, 8, 8, 0};
  static const int16 kAncilla_Coll_H[5] = {20, 20, 8, 28, 14};
  static const int16 kAncilla_Coll_W[5] = {20, 3, 8, 24, 14};
  static const int16 kAncilla_Coll_LinkYoffs[5] = {12, 12, 12, 12, 12};
  static const int16 kAncilla_Coll_LinkXoffs[5] = {8, 8, 8, 12, 8};
  uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
  y += kAncilla_Coll_Yoffs[j] + (int8)ancilla_z[k];
  x += kAncilla_Coll_Xoffs[j];
  out->r4 = link_y_coord + kAncilla_Coll_LinkYoffs[j] - y;
  out->r8 = abs16(out->r4);
  out->r6 = link_x_coord + kAncilla_Coll_LinkXoffs[j] - x;
  out->r10 = abs16(out->r6);
  return out->r8 < kAncilla_Coll_H[j] && out->r10 < kAncilla_Coll_W[j];
}

bool Hookshot_CheckProximityToLink(int x, int y) {  // 88f7dc
  return abs16(link_y_coord - BG2VOFS_copy2 + 12 - y - 4) < 12 &&
         abs16(link_x_coord - BG2HOFS_copy2 +  8 - x - 4) < 12;
}

bool Ancilla_CheckForEntranceTrigger(int what) {  // 88f844
  static const uint16 kEntranceTrigger_BaseY[4] = {0xd40, 0x210, 0xcfc, 0x100};
  static const uint16 kEntranceTrigger_BaseX[4] = {0xd80, 0xe68, 0x130, 0xf10};
  static const uint8 kEntranceTrigger_SizeY[4] = {11, 32, 16, 12};
  static const uint8 kEntranceTrigger_SizeX[4] = {16, 16, 16, 16};
  return
    abs16(link_y_coord + 12 - kEntranceTrigger_BaseY[what]) < kEntranceTrigger_SizeY[what] &&
    abs16(link_x_coord + 8 - kEntranceTrigger_BaseX[what]) < kEntranceTrigger_SizeX[what];
}

void AncillaDraw_Shadow(OamEnt *oam, int k, int x, int y, uint8 pal) {  // 88f897
  static const uint8 kAncilla_DrawShadow_Char[14] = {0x6c, 0x6c, 0x28, 0x28, 0x38, 0xff, 0xc8, 0xc8, 0xd8, 0xd8, 0xd9, 0xd9, 0xda, 0xda};
  static const uint8 kAncilla_DrawShadow_Flags[14] = {0x28, 0x68, 0x28, 0x68, 0x28, 0xff, 0x22, 0x22, 0x24, 0x64, 0x24, 0x64, 0x24, 0x64};

  if (k == 2)
    x += 4;
  Ancilla_SetOam_Safe(oam, x, y,
                      kAncilla_DrawShadow_Char[k * 2],
                      kAncilla_DrawShadow_Flags[k * 2] & ~0x30 | pal, 0);
  uint8 ch = kAncilla_DrawShadow_Char[k * 2 + 1];
  if (ch != 0xff) {
    x += 8;
    Ancilla_SetOam_Safe(oam + 1, x, y, ch, kAncilla_DrawShadow_Flags[k * 2 + 1] & ~0x30 | pal, 0);
  }
}

void Ancilla_AllocateOamFromRegion_B_or_E(uint8 size) {  // 88f90a
  if (!sort_sprites_setting)
    Oam_AllocateFromRegionB(size);
  else
    Oam_AllocateFromRegionE(size);
}

OamEnt *Ancilla_AllocateOamFromCustomRegion(OamEnt *oam) {  // 88f9ba
  int a = (uint8 *)oam - g_ram;
  if (sort_sprites_setting) {
    if (a < 0x900) {
      if (a < 0x8e0)
        return oam;
      a = 0x820;
    } else {
      if (a < 0x9d0)
        return oam;
      a = 0x940;
    }
  } else {
    if (a < 0x990)
      return oam;
    a = 0x820;
  }
  oam_cur_ptr = a;
  oam_ext_cur_ptr = ((a - 0x800) >> 2) + 0xa20;
  return GetOamCurPtr();
}

OamEnt *HitStars_UpdateOamBufferPosition(OamEnt *oam) {  // 88fa00
  int a = (uint8 *)oam - g_ram;
  if (!sort_sprites_setting && a >= 0x9d0) {
    oam_cur_ptr = 0x820;
    oam_ext_cur_ptr = 0xa20 + (0x20 >> 2);
    oam = GetOamCurPtr();
  }
  return oam;
}

bool Hookshot_ShouldIEvenBotherWithTiles(int k) {  // 88fa2d
  uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
  if (!player_is_indoors) {
    if (!(ancilla_dir[k] & 2)) {
      uint16 t = y - kOverworld_OffsetBaseY[BYTE(current_area_of_player) >> 1];
      return (t < 4) || (t >= overworld_right_bottom_bound_for_scroll);
    } else {
      uint16 t = x - kOverworld_OffsetBaseX[BYTE(current_area_of_player) >> 1];
      return (t < 6) || (t >= overworld_right_bottom_bound_for_scroll);
    }
  }
  if (!(ancilla_dir[k] & 2)) {
    return (y & 0x1ff) < 4 || (y & 0x1ff) >= 0x1e8 || (y & 0x200) != (link_y_coord & 0x200);
  } else {
    return (x & 0x1ff) < 4 || (x & 0x1ff) >= 0x1f0 || (x & 0x200) != (link_x_coord & 0x200);
  }
}

AncillaRadialProjection Ancilla_GetRadialProjection(uint8 a, uint8 r8) {  // 88fadd
  static const uint8 kRadialProjection_Tab0[64] = {
    255, 254, 251, 244, 236, 225, 212, 197, 181, 162, 142, 120,  97,  74,  49,  25,
      0,  25,  49,  74,  97, 120, 142, 162, 181, 197, 212, 225, 236, 244, 251, 254,
    255, 254, 251, 244, 236, 225, 212, 197, 181, 162, 142, 120,  97,  74,  49,  25,
      0,  25,  49,  74,  97, 120, 142, 162, 181, 197, 212, 225, 236, 244, 251, 254,
  };
  static const uint8 kRadialProjection_Tab2[64] = {
      0,  25,  49,  74,  97, 120, 142, 162, 181, 197, 212, 225, 236, 244, 251, 254,
    255, 254, 251, 244, 236, 225, 212, 197, 181, 162, 142, 120,  97,  74,  49,  25,
      0,  25,  49,  74,  97, 120, 142, 162, 181, 197, 212, 225, 236, 244, 251, 254,
    255, 254, 251, 244, 236, 225, 212, 197, 181, 162, 142, 120,  97,  74,  49,  25,
  };
  static const uint8 kRadialProjection_Tab1[64] = {
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  };
  static const uint8 kRadialProjection_Tab3[64] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  };
  AncillaRadialProjection rv;
  int p0 = kRadialProjection_Tab0[a] * r8;
  int p1 = kRadialProjection_Tab2[a] * r8;
  rv.r0 = (p0 >> 8) + (p0 >> 7 & 1);
  rv.r2 = kRadialProjection_Tab1[a];
  rv.r4 = (p1 >> 8) + (p1 >> 7 & 1);
  rv.r6 = kRadialProjection_Tab3[a];
  return rv;
}

int Ancilla_AllocateOamFromRegion_A_or_D_or_F(int k, uint8 size) {  // 88fb2b
  if (sort_sprites_setting) {
    if (ancilla_floor[k])
      return Oam_AllocateFromRegionF(size);
    else
      return Oam_AllocateFromRegionD(size);
  } else {
    return Oam_AllocateFromRegionA(size);
  }
}

void Ancilla_AddHitStars(uint8 a, uint8 y) {  // 898024
  static const int8 kShovelHitStars_XY[12] = {21, -11, 21, 11, 3, -6, 21, 5, 16, -14, 16, 14};
  static const int8 kShovelHitStars_X2[6] = {-3, 19, 2, 13, -6, 22};
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_item_to_link[k] = 0;
    ancilla_aux_timer[k] = 2;
    ancilla_arr3[k] = 1;
    ancilla_y_vel[k] = 0;
    ancilla_x_vel[k] = 0;
    int j = a;
    if (link_item_in_hand) {
      j = (link_direction_facing >> 1) + 2;
    } else if (link_position_mode) {
      j = link_direction_facing != 4 ? 1 : 0;
    }
    ancilla_step[k] = j;
    int t = link_x_coord + kShovelHitStars_X2[j];
    ancilla_A[k] = t;
    ancilla_B[k] = t >> 8;
    Ancilla_SetXY(k, link_x_coord + kShovelHitStars_XY[j * 2 + 1], link_y_coord + kShovelHitStars_XY[j * 2 + 0]);
  }
}

void AncillaAdd_Blanket(uint8 a) {  // 898091
  int k = 0;
  ancilla_type[k] = a;
  ancilla_numspr[k] = kAncilla_Pflags[a];
  ancilla_floor[k] = link_is_on_lower_level;
  ancilla_floor2[k] = link_is_on_lower_level_mirror;
  ancilla_objprio[k] = 0;
  Ancilla_SetXY(k, 0x938, 0x2162);
}

void AncillaAdd_Snoring(uint8 a, uint8 y) {  // 8980c8
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_item_to_link[k] = 0;
    ancilla_y_vel[k] = -8;
    ancilla_aux_timer[k] = 7;
    ancilla_x_vel[k] = 8;
    ancilla_step[k] = 255;
    Ancilla_SetXY(k, link_x_coord + 16, link_y_coord + 4);
  }
}

void AncillaAdd_Bomb(uint8 a, uint8 y) {  // 89811f
  static const int8 kBomb_Place_X0[4] = {8, 8, 0, 16};
  static const int8 kBomb_Place_Y0[4] = {0, 24, 12, 12};
  static const int8 kBomb_Place_X1[4] = {8, 8, -6, 22};
  static const int8 kBomb_Place_Y1[4] = {4, 28, 12, 12};

  int k = Ancilla_AddAncilla(a, y);
  if (k < 0)
    return;
  if (link_item_bombs == 0) {
    ancilla_type[k] = 0;
    return;
  }

  if (--link_item_bombs == 0)
    Hud_RefreshIcon();

  ancilla_R[k] = 0;
  ancilla_step[k] = 0;
  ancilla_item_to_link[k] = 0;
  ancilla_L[k] = 0;
  ancilla_arr3[k] = kBomb_Tab0[0];

  // These are not used directly by bombs, but used by door debris
  ancilla_arr25[k] = 0;
  ancilla_arr26[k] = 7;

  ancilla_z[k] = 0;
  ancilla_timer[k] = 8;
  ancilla_dir[k] = link_direction_facing >> 1;
  ancilla_T[k] = 0;
  ancilla_arr23[k] = 0;
  ancilla_arr22[k] = 0;
  if (Ancilla_CheckInitialTileCollision_Class2(k)) {
    int j = link_direction_facing >> 1;
    Ancilla_SetXY(k, link_x_coord + kBomb_Place_X0[j], link_y_coord + kBomb_Place_Y0[j]);
  } else {
    int j = link_direction_facing >> 1;
    Ancilla_SetXY(k, link_x_coord + kBomb_Place_X1[j], link_y_coord + kBomb_Place_Y1[j]);
  }
  sound_effect_1 = Link_CalculateSfxPan() | 0xb;
}

uint8 AncillaAdd_Boomerang(uint8 a, uint8 y) {  // 89820f
  static const uint8 kBoomerang_Tab0[4] = {0x20, 0x18, 0x30, 0x28};
  static const uint8 kBoomerang_Tab1[2] = {0x20, 0x60};
  static const uint8 kBoomerang_Tab2[2] = {3, 2};
  static const uint8 kBoomerang_Tab3[4] = {8, 4, 2, 1};
  static const uint8 kBoomerang_Tab4[8] = {8, 4, 2, 1, 9, 5, 10, 6};
  static const uint8 kBoomerang_Tab5[8] = {2, 3, 3, 2, 2, 3, 3, 3};
  static const int8 kBoomerang_Tab6[8] = {-10, -8, -9, -9, -10, -8, -9, -9};
  static const int8 kBoomerang_Tab7[8] = {-10, 11, 8, -8, -10, 11, 8, -8};
  static const int8 kBoomerang_Tab8[8] = {-16, 6, 0, 0, -8, 8, -8, 8};
  static const int8 kBoomerang_Tab9[8] = {0, 0, -8, 8, 8, 8, -8, -8};

  int k = Ancilla_AddAncilla(a, y);
  if (k < 0)
    return 0;
  ancilla_aux_timer[k] = 0;
  ancilla_item_to_link[k] = 0;
  ancilla_K[k] = 0;
  ancilla_z[k] = 0;
  ancilla_L[k] = ancilla_numspr[k];
  flag_for_boomerang_in_place = 1;
  int j = link_item_boomerang - 1;
  ancilla_G[k] = j;
  ancilla_step[k] = kBoomerang_Tab1[j];
  ancilla_arr3[k] = kBoomerang_Tab2[j];

  int s = ancilla_G[k] * 2 + ((joypad1H_last & 0xc) && (joypad1H_last & 3) ? 1 : 0);
  uint8 r0 = kBoomerang_Tab0[s];
  ancilla_H[k] = r0;

  uint8 r1 = (joypad1H_last & 0xf) ? (joypad1H_last & 0xf) : kBoomerang_Tab3[link_direction_facing >> 1];
  hookshot_effect_index = 0;

  if (r1 & 0xc) {
    ancilla_y_vel[k] = r1 & 8 ? -r0 : r0;
    int i = sign8(ancilla_y_vel[k]) ? 0 : 1;
    ancilla_dir[k] = i;
    hookshot_effect_index = kBoomerang_Tab3[i];
  }
  ancilla_S[k] = 0;

  if (r1 & 3) {
    if (!(r1 & 2))
      ancilla_S[k] = 1;
    ancilla_x_vel[k] = (r1 & 2) ? -r0 : r0;
    int i = sign8(ancilla_x_vel[k]) ? 2 : 3;
    ancilla_dir[k] = i;
    hookshot_effect_index |= kBoomerang_Tab3[i];
  }

  j = FindInByteArray(kBoomerang_Tab4, r1, 8);
  if (j < 0)
    j = 0;
  ancilla_arr1[k] = kBoomerang_Tab5[j];
  ancilla_arr23[k] = j << 1;
  if (button_b_frames >= 9) {
    ancilla_aux_timer[k]++;
  } else {
    if (s || !(joypad1H_last & 0xf))
      j = link_direction_facing >> 1;
  }
  s = Ancilla_CheckInitialTile_A(k);
  if (s < 0) {
    if (ancilla_aux_timer[k]) {
      Ancilla_SetXY(k, link_x_coord + kBoomerang_Tab9[j], link_y_coord + 8 + kBoomerang_Tab8[j]);
    } else {
      Ancilla_SetXY(k, link_x_coord + kBoomerang_Tab7[j], link_y_coord + 8 + kBoomerang_Tab6[j]);
    }
  } else {
    ancilla_type[k] = 0;
    flag_for_boomerang_in_place = 0;
    if (ancilla_tile_attr[k] != 0xf0) {
      sound_effect_1 = Ancilla_CalculateSfxPan(k) | 5;
    } else {
      sound_effect_1 = Ancilla_CalculateSfxPan(k) | 6;
    }
    AncillaAdd_BoomerangWallClink(k);
  }
  return s;
}

void AncillaAdd_TossedPondItem(uint8 a, uint8 xin, uint8 yin) {  // 898a32
  static const uint8 kWishPondItem_X[76] = {
    4, 4, 4, 4,  4, 0, 0, 4, 4, 4, 4, 4, 5, 0, 0, 0,
    0, 0, 0, 4,  0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 11, 0, 0, 0, 2, 0, 5, 0, 0, 0, 0, 0,
    0, 0, 0, 0,  4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 4, 4,  0, 4, 0, 0, 0, 4, 0, 0,
  };
  static const int8 kWishPondItem_Y[76] = {
    -13, -13, -13, -13, -13, -12, -12, -13, -13, -12, -12, -12, -10, -12, -12, -12,
    -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
    -12, -12, -12, -13, -12, -12, -12, -12, -12, -12, -10, -12, -12, -12, -12, -12,
    -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
    -12, -12, -12, -12, -12, -12, -12, -12, -12, -13, -12, -12,
  };

  link_receiveitem_index = xin;
  int k = Ancilla_AddAncilla(a, yin);
  if (k >= 0) {
    sound_effect_2 = Link_CalculateSfxPan() | 0x13;
    uint8 sb = kReceiveItemGfx[xin];

    if (sb != 0xff) {
      if (sb == 0x20)
        DecompressShieldGraphics();
      DecodeAnimatedSpriteTile_variable(sb);
    } else {
      DecodeAnimatedSpriteTile_variable(0);
    }
    if (sb == 6)
      DecompressSwordGraphics();

    link_state_bits = 0x80;
    link_picking_throw_state = 0;
    link_direction_facing = 0;
    link_animation_steps = 0;
    ancilla_z_vel[k] = 20;
    ancilla_y_vel[k] = -40;
    ancilla_x_vel[k] = 0;
    ancilla_z[k] = 0;
    ancilla_timer[k] = 16;
    ancilla_item_to_link[k] = link_receiveitem_index;
    Ancilla_SetXY(k,
      link_x_coord + kWishPondItem_X[link_receiveitem_index],
      link_y_coord + kWishPondItem_Y[link_receiveitem_index]);
  }
}

void AddHappinessPondRupees(uint8 arg) {  // 898ae0
  int k = Ancilla_AddAncilla(0x42, 9);
  if (k < 0)
    return;
  sound_effect_2 = Link_CalculateSfxPan() | 0x13;
  uint8 sb = kReceiveItemGfx[0x35];
  DecodeAnimatedSpriteTile_variable(sb);
  link_state_bits = 0x80;
  link_picking_throw_state = 0;
  link_direction_facing = 0;
  link_animation_steps = 0;

  memset(happiness_pond_arr1, 0, 10);

  static const int8 kHappinessPond_Start[4] = {0, 4, 4, 9};
  static const int8 kHappinessPond_End[4] = {-1, 0, -1, -1};
  static const int8 kHappinessPond_Xvel[10] = {0, -12, -6, 6, 12, -9, -5, 0, 5, 9};
  static const int8 kHappinessPond_Yvel[10] = {-40, -40, -40, -40, -40, -32, -32, -32, -32, -32};
  static const int8 kHappinessPond_Zvel[10] = {20, 20, 20, 20, 20, 16, 16, 16, 16, 16};

  int j = kHappinessPond_Start[arg], j_end = kHappinessPond_End[arg];
  k = 9;
  do {
    happiness_pond_arr1[k] = 1;
    happiness_pond_z_vel[k] = kHappinessPond_Zvel[j];
    happiness_pond_y_vel[k] = kHappinessPond_Yvel[j];
    happiness_pond_x_vel[k] = kHappinessPond_Xvel[j];
    happiness_pond_z[k] = 0;
    happiness_pond_step[k] = 0;
    happiness_pond_timer[k] = 16;
    happiness_pond_item_to_link[k] = 53;
    int x = link_x_coord + 4;
    int y = link_y_coord - 12;
    happiness_pond_x_lo[k] = x;
    happiness_pond_x_hi[k] = x >> 8;
    happiness_pond_y_lo[k] = y;
    happiness_pond_y_hi[k] = y >> 8;
  } while (--k, --j != j_end);
}

int AncillaAdd_FallingPrize(uint8 a, uint8 item_idx, uint8 yv) {  // 898bc1
  static const int8 kFallingItem_Type[7] = {0x10, 0x37, 0x39, 0x38, 0x26, 0xf, 0x20};
  static const int8 kFallingItem_G[7] = {0x40, 0, 0, 0, 0, -1, 0};
  static const int16 kFallingItem_X[7] = {0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x78};
  static const int16 kFallingItem_Y[7] = {0x48, 0x78, 0x78, 0x78, 0x78, 0x68, 0x78};
  static const uint8 kFallingItem_Z[7] = {0x60, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
  link_receiveitem_index = item_idx;
  int k = Ancilla_AddAncilla(a, yv);
  if (k < 0)
    return k;
  uint8 item_type = kFallingItem_Type[item_idx];
  ancilla_item_to_link[k] = item_type;
  if (item_type == 0x10 || item_type == 0xf)
    DecodeAnimatedSpriteTile_variable(kReceiveItemGfx[item_type]);

  ancilla_z_vel[k] = -48;
  ancilla_y_vel[k] = 0;
  ancilla_x_vel[k] = 0;
  ancilla_step[k] = 0;
  ancilla_z[k] = kFallingItem_Z[item_idx];
  ancilla_aux_timer[k] = 9;
  ancilla_arr3[k] = 0;
  ancilla_L[k] = 0;
  ancilla_G[k] = kFallingItem_G[item_idx];
  link_receiveitem_index = item_type;

  int x, y;
  if (item_idx != 0 && item_idx != 5) {
    if (BYTE(cur_palace_index_x2) == 20) {
      x = (link_x_coord & 0xff00) | 0x100;
      y = (link_y_coord & 0xff00) | 0x100;
    } else {
      x = kFallingItem_X[item_idx] + BG2HOFS_copy2;
      y = kFallingItem_Y[item_idx] + BG2VOFS_copy2;
    }
  } else {
    x = link_x_coord;
    y = kFallingItem_Y[item_idx] + BG2VOFS_copy2;
  }
  Ancilla_SetXY(k, x, y);
  return k;
}

void AncillaAdd_ChargedSpinAttackSparkle() {  // 898cb1
  for (int k = 9; k >= 0; k--) {
    if (ancilla_type[k] == 0 || ancilla_type[k] == 0x3c) {
      ancilla_type[k] = 13;
      ancilla_floor[k] = link_is_on_lower_level;
      ancilla_timer[k] = 6;
      break;
    }
  }
}

void AncillaAdd_ExplodingWeatherVane(uint8 a, uint8 y) {  // 898d11
  static const int8 kWeathervane_Tab4[12] = {8, 10, 9, 4, 11, 12, -10, -8, 4, -6, -10, -4};
  static const int8 kWeathervane_Tab5[12] = {20, 22, 20, 20, 22, 20, 20, 22, 20, 22, 20, 20};
  static const uint8 kWeathervane_Tab6[12] = {0xb0, 0xa3, 0xa0, 0xa2, 0xa0, 0xa8, 0xa0, 0xa0, 0xa8, 0xa1, 0xb0, 0xa0};
  static const uint8 kWeathervane_Tab8[12] = {0, 2, 4, 6, 3, 8, 14, 8, 12, 7, 10, 8};
  static const uint8 kWeathervane_Tab10[12] = {48, 18, 32, 20, 22, 24, 32, 20, 24, 22, 20, 32};

  int k = Ancilla_AddAncilla(a, y);
  if (k < 0)
    return;

  ancilla_aux_timer[k] = 10;
  ancilla_G[k] = 128;
  ancilla_step[k] = 0;
  ancilla_arr3[k] = 0;
  sound_effect_1 = 0;
  music_control = 0xf2;
  sound_effect_ambient = 0x17;

  weathervane_var1 = 0;
  weathervane_var2 = 0x280;

  for (int i = 11; i >= 0; i--) {
    weathervane_arr3[i] = 0;
    weathervane_arr4[i] = kWeathervane_Tab4[i];
    weathervane_arr5[i] = kWeathervane_Tab5[i];
    weathervane_arr6[i] = kWeathervane_Tab6[i];
    weathervane_arr7[i] = 7;
    weathervane_arr8[i] = kWeathervane_Tab8[i];
    weathervane_arr9[i] = 2;
    weathervane_arr10[i] = kWeathervane_Tab10[i];
    weathervane_arr11[i] = 1;
    weathervane_arr12[i] = i & 1;
  }
}

void AncillaAdd_CutsceneDuck(uint8 a, uint8 y) {  // 898d90
  if (AncillaAdd_CheckForPresence(a))
    return;
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_dir[k] = 2;
    ancilla_arr3[k] = 3;
    ancilla_step[k] = 0;
    ancilla_aux_timer[k] = 32;
    ancilla_item_to_link[k] = 116;
    ancilla_z_vel[k] = 0;
    ancilla_L[k] = 0;
    ancilla_z[k] = 0;
    ancilla_S[k] = 0;
    Ancilla_SetXY(k, 0x200, 0x788);
  }
}

void AncillaAdd_SomariaPlatformPoof(int k) {  // 898dd2
  ancilla_type[k] = 0x39;
  ancilla_aux_timer[k] = 7;
  for (int j = 15; j >= 0; j--) {
    if (sprite_type[j] == 0xed) {
      sprite_state[j] = 0;
      player_on_somaria_platform = 0;
    }
  }
  Player_TileDetectNearby();
}

int AncillaAdd_SuperBombExplosion(uint8 a, uint8 y) {  // 898df9
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_R[k] = 0;
    ancilla_step[k] = 0;
    ancilla_arr25[k] = 0;
    ancilla_L[k] = 0;
    ancilla_arr3[k] = kBomb_Tab0[1];
    ancilla_item_to_link[k] = 1;
    int j = WORD(tagalong_var2);
    int y = tagalong_y_lo[j] | tagalong_y_hi[j] << 8;
    int x = tagalong_x_lo[j] | tagalong_x_hi[j] << 8;
    Ancilla_SetXY(k, x + 8, y + 16);
  }
  return k;
}

void ConfigureRevivalAncillae() {  // 898e4e
  link_dma_var5 = 80;
  int k = 0;

  ancilla_arr3[k] = 64;
  ancilla_step[k] = 0;
  ancilla_z_vel[k] = 8;
  ancilla_L[k] = 0;
  ancilla_G[k] = 5;
  ancilla_item_to_link[k] = 0;
  ancilla_K[k] = 0;
  Ancilla_SetXY(k, link_x_coord, link_y_coord);
  ancilla_z[k] = 0;
  k += 1;

  ancilla_z[k] = 0;
  ancilla_arr3[k] = 240;
  ancilla_step[k] = 0;
  ancilla_K[k] = 0;
  k += 1;

  ancilla_item_to_link[k] = 2;
  ancilla_aux_timer[k] = 3;
  ancilla_arr3[k] = 8;
  ancilla_step[k] = 0;
  ancilla_dir[k] = 3;
  ancilla_arr25[k] = kMagicPowder_Tab0[30 + ancilla_item_to_link[k]];

  Ancilla_SetXY(k, link_x_coord + 20, link_y_coord + 2);
}

void AncillaAdd_LampFlame(uint8 a, uint8 y) {  // 898f1c
  static const int8 kLampFlame_X[4] = {0, 0, -20, 18};
  static const int8 kLampFlame_Y[4] = {-16, 24, 4, 4};
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_item_to_link[k] = 0;
    ancilla_aux_timer[k] = 0;
    ancilla_timer[k] = 23;
    int j = link_direction_facing >> 1;
    ancilla_dir[k] = j;
    Ancilla_SetXY(k, link_x_coord + kLampFlame_X[j], link_y_coord + kLampFlame_Y[j]);
    sound_effect_1 = Ancilla_CalculateSfxPan(k) | 42;
  }
}

void AncillaAdd_MSCutscene(uint8 a, uint8 y) {  // 898f7c
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_item_to_link[k] = 0;
    ancilla_aux_timer[k] = 2;
    ancilla_timer[k] = 64;
    Ancilla_SetXY(k, link_x_coord + 8, link_y_coord - 8);
  }
}

void AncillaAdd_DashDust(uint8 a, uint8 y) {  // 898fba
  AddDashingDustEx(a, y, 1);
}

void AncillaAdd_DashDust_charging(uint8 a, uint8 y) {  // 898fc1
  AddDashingDustEx(a, y, 0);
}

void AncillaAdd_BlastWallFireball(uint8 a, uint8 y, int r4) {  // 899031
  static const int8 kBlastWall_XY[32] = {
    -64, 0, -22,  42, -38,  38, -42,  22, 0,  64,  22,  42,  38,  38,  42,  22,
    64, 0,  22, -42,  38, -38,  42, -22, 0, -64, -22, -42, -38, -38, -42, -22,
  };
  for (int k = 10; k != 4; k--) {
    if (ancilla_type[k] == 0) {
      ancilla_type[k] = 0x32;
      ancilla_floor[k] = link_is_on_lower_level;
      blastwall_var12[k] = 16;
      int j = frame_counter & 15;
      ancilla_y_vel[k] = kBlastWall_XY[j * 2 + 0];
      ancilla_x_vel[k] = kBlastWall_XY[j * 2 + 1];
      Ancilla_SetXY(k, blastwall_var11[r4] + 16, blastwall_var10[r4] + 8);
      return;
    }
  }

}

int AncillaAdd_Arrow(uint8 a, uint8 ax, uint8 ay, uint16 xcoord, uint16 ycoord) {  // 8990a4
  static const int8 kShootBow_X[4] = {4, 4, 0, 4};
  static const int8 kShootBow_Y[4] = {-4, 3, 4, 4};
  static const int8 kShootBow_Xvel[4] = {0, 0, -48, 48};
  static const int8 kShootBow_Yvel[4] = {-48, 48, 0, 0};

  scratch_0 = ycoord;
  scratch_1 = xcoord;
  BYTE(index_of_interacting_tile) = ax;

  if (AncillaAdd_CheckForPresence(a))
    return -1;

  int k = AncillaAdd_ArrowFindSlot(a, ay);

  if (k >= 0) {
    sound_effect_1 = Link_CalculateSfxPan() | 7;
    ancilla_H[k] = 0;
    ancilla_item_to_link[k] = 8;
    int j = ax >> 1;
    ancilla_dir[k] = j | 4;
    ancilla_y_vel[k] = kShootBow_Yvel[j];
    ancilla_x_vel[k] = kShootBow_Xvel[j];
    Ancilla_SetXY(k, xcoord + kShootBow_X[j], ycoord + 8 +  kShootBow_Y[j]);
  }
  return k;
}

void AncillaAdd_BunnyPoof(uint8 a, uint8 y) {  // 899102
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    link_visibility_status = 0xc;
    ancilla_step[k] = 0;
    if (!link_is_bunny_mirror)
      sound_effect_1 = Link_CalculateSfxPan() | 0x14;
    else
      sound_effect_1 = Link_CalculateSfxPan() | 0x15;

    ancilla_item_to_link[k] = 0;
    ancilla_aux_timer[k] = 7;
    Ancilla_SetXY(k, link_x_coord, link_y_coord + 4);
  }
}

void AncillaAdd_CapePoof(uint8 a, uint8 y) {  // 89912c
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_step[k] = 1;
    link_is_transforming = 1;
    link_cant_change_direction |= 1;
    link_direction = 0;
    link_direction_last = 0;
    ancilla_item_to_link[k] = 0;
    ancilla_aux_timer[k] = 7;
    Ancilla_SetXY(k, link_x_coord, link_y_coord + 4);
  }
}

void AncillaAdd_DwarfPoof(uint8 ain, uint8 yin) {  // 89915f
  int k = Ancilla_AddAncilla(ain, yin);
  if (k < 0)
    return;
  if (follower_indicator == 8)
    sound_effect_1 = Link_CalculateSfxPan() | 0x14;
  else
    sound_effect_1 = Link_CalculateSfxPan() | 0x15;

  ancilla_item_to_link[k] = 0;
  ancilla_step[k] = 0;
  ancilla_aux_timer[k] = 7;
  tagalong_var5 = 1;
  int j = tagalong_var2;
  int x = tagalong_x_lo[j] | tagalong_x_hi[j] << 8;
  int y = tagalong_y_lo[j] | tagalong_y_hi[j] << 8;
  Ancilla_SetXY(k, x, y + 4);
}

void AncillaAdd_BushPoof(uint16 x, uint16 y) {  // 8991c3
  if (!(link_item_in_hand & 0x40))
    return;
  int k = Ancilla_AddAncilla(0x3f, 4);
  if (k >= 0) {
    ancilla_item_to_link[k] = 0;
    ancilla_timer[k] = 7;
    sound_effect_1 = Link_CalculateSfxPan() | 21;
    Ancilla_SetXY(k, x, y - 2);
  }
}

void AncillaAdd_EtherSpell(uint8 a, uint8 y) {  // 8991fc
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_item_to_link[k] = 0;
    ancilla_arr25[k] = 0;
    ancilla_step[k] = 0;
    flag_custom_spell_anim_active = 1;
    ancilla_aux_timer[k] = 2;
    ancilla_arr3[k] = 3;
    ancilla_y_vel[k] = 127;
    ether_var2 = 40;
    load_chr_halfslot_even_odd = 9;
    ether_var1 = 0x40;
    sound_effect_2 = Link_CalculateSfxPan() | 0x26;
    for(int i = 0; i < 8; i++)
      ether_arr1[i] = i * 8;
    ether_y = link_y_coord;
    uint16 y = BG2VOFS_copy2 - 16;
    ether_y_adjusted = y & 0xf0;
    ether_x = link_x_coord;
    ether_x2 = ether_x + 8;
    ether_y2 = link_y_coord - 16;
    ether_y3 = ether_y2 + 0x24;
    Ancilla_SetXY(k, link_x_coord, y);
  }
}

void AncillaAdd_VictorySpin() {  // 8992ac
  if ((link_sword_type + 1 & 0xfe) != 0) {
    int k = Ancilla_AddAncilla(0x3b, 0);
    if (k >= 0) {
      ancilla_item_to_link[k] = 0;
      ancilla_arr3[k] = 1;
      ancilla_aux_timer[k] = 34;
    }
  }
}

void AncillaAdd_MagicPowder(uint8 a, uint8 y) {  // 8992f0
  static const int8 kMagicPower_X[4] = {-2, -2, -12, 12};
  static const int8 kMagicPower_Y[4] = {0, 20, 16, 16};
  static const int8 kMagicPower_X1[4] = {10, 10, -8, 28};
  static const int8 kMagicPower_Y1[4] = {1, 40, 22, 22};

  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_item_to_link[k] = 0;
    ancilla_z[k] = 0;
    ancilla_aux_timer[k] = 1;
    link_dma_var5 = 80;
    int j = link_direction_facing >> 1;
    ancilla_dir[k] = j;
    ancilla_arr25[k] = kMagicPowder_Tab0[j * 10];
    Ancilla_SetXY(k, link_x_coord + kMagicPower_X[j], link_y_coord + kMagicPower_Y[j]);
    Ancilla_CheckTileCollision(k);
    byte_7E0333 = ancilla_tile_attr[k];
    if (current_item_active == 9) {
      ancilla_type[k] = 0;
      return;
    }
    sound_effect_1 = Link_CalculateSfxPan() | 0xd;
    Ancilla_SetXY(k, link_x_coord + kMagicPower_X1[j], link_y_coord + kMagicPower_Y1[j]);
  }
}

void AncillaAdd_WallTapSpark(uint8 a, uint8 y) {  // 899395
  static const int8 kWallTapSpark_X[4] = {11, 10, -12, 29};
  static const int8 kWallTapSpark_Y[4] = {-4, 32, 17, 17};
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_item_to_link[k] = 5;
    ancilla_aux_timer[k] = 1;
    int i = link_direction_facing >> 1;
    Ancilla_SetXY(k, link_x_coord + kWallTapSpark_X[i], link_y_coord + kWallTapSpark_Y[i]);
  }
}

void AncillaAdd_SwordSwingSparkle(uint8 a, uint8 y) {  // 8993c2
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_item_to_link[k] = 0;
    ancilla_aux_timer[k] = 1;
    ancilla_dir[k] = link_direction_facing >> 1;
    Ancilla_SetXY(k, link_x_coord, link_y_coord);
  }
}

void AncillaAdd_DashTremor(uint8 a, uint8 y) {  // 8993f3
  static const uint8 kAddDashTremor_Dir[4] = {2, 2, 0, 0};
  static const uint8 kAddDashTremor_Tab[2] = {0x80, 0x78};
  if (AncillaAdd_CheckForPresence(a))
    return;
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_item_to_link[k] = 16;
    ancilla_L[k] = 0;
    int j = link_direction_facing >> 1;
    ancilla_dir[k] = j = kAddDashTremor_Dir[j];
    uint8 y = link_y_coord - BG2VOFS_copy2;
    uint8 x = link_x_coord - BG2HOFS_copy2;
    Ancilla_SetY(k, (j ? y : x) < kAddDashTremor_Tab[j >> 1] ? 3 : -3);
  }
}

void AncillaAdd_BoomerangWallClink(int k) {  // 899478
  static const int8 kBoomerangWallHit_X[8] = {8, 8, 0, 10, 12, 8, 4, 0};
  static const int8 kBoomerangWallHit_Y[8] = {0, 8, 8, 8, 4, 8, 12, 8};
  static const uint8 kBoomerangWallHit_Tab0[16] = {0, 6, 4, 0, 2, 10, 12, 0, 0, 8, 14, 0, 0, 0, 0, 0};
  boomerang_temp_x = Ancilla_GetX(k);
  boomerang_temp_y = Ancilla_GetY(k);
  k = Ancilla_AddAncilla(6, 1);
  if (k >= 0) {
    ancilla_item_to_link[k] = 0;
    ancilla_arr3[k] = 1;
    int j = kBoomerangWallHit_Tab0[hookshot_effect_index] >> 1;
    Ancilla_SetXY(k, boomerang_temp_x + kBoomerangWallHit_X[j], boomerang_temp_y + kBoomerangWallHit_Y[j]);
  }
}

void AncillaAdd_HookshotWallClink(int kin, uint8 a, uint8 y) {  // 8994c6
  static const int8 kHookshotWallHit_X[8] = {8, 8, 0, 10, 12, 8, 4, 0};
  static const int8 kHookshotWallHit_Y[8] = {0, 8, 8, 8, 4, 8, 12, 8};
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_item_to_link[k] = 0;
    ancilla_arr3[k] = 1;
    int j = ancilla_dir[kin];
    Ancilla_SetXY(k, Ancilla_GetX(kin) + kHookshotWallHit_X[j], Ancilla_GetY(kin) + kHookshotWallHit_Y[j]);
  }
}

void AncillaAdd_Duck_take_off(uint8 a, uint8 y) {  // 8994fe
  if (AncillaAdd_CheckForPresence(a))
    return;
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_timer[k] = 0x78;
    ancilla_L[k] = 0;
    ancilla_z_vel[k] = 0;
    ancilla_z[k] = 0;
    ancilla_step[k] = 0;
    AddBirdCommon(k);
  }
}

void AddBirdTravelSomething(uint8 a, uint8 y) {  // 89951d
  if (AncillaAdd_CheckForPresence(a))
    return;
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    link_player_handler_state = 0;
    link_speed_setting = 0;
    button_mask_b_y &= ~0x81;
    button_b_frames = 0;
    link_delay_timer_spin_attack = 0;
    link_cant_change_direction &= ~1;
    ancilla_L[k] = 1;

    if (enhanced_features0 & kFeatures0_ExtendScreen64) {
      // todo: tune these better so the angle of attack is better
      ancilla_z_vel[k] = 58;
      ancilla_z[k] = -105;
    } else {
      ancilla_z_vel[k] = 40;
      ancilla_z[k] = -51;
    }
    ancilla_step[k] = 2;
    AddBirdCommon(k);
  }
}

void AncillaAdd_QuakeSpell(uint8 a, uint8 y) {  // 899589
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    ancilla_step[k] = 0;
    ancilla_item_to_link[k] = 0;
    load_chr_halfslot_even_odd = 13;
    sound_effect_1 = 0x35;
    for(int i = 0; i < 5; i++)
      quake_arr2[i] = 0;
    quake_var5 = 0;
    for(int i = 0; i < 5; i++)
      quake_arr1[i] = 1;
    flag_custom_spell_anim_active = 1;
    ancilla_timer[k] = 2;
    quake_var1 = link_y_coord + 26;
    quake_var2 = link_x_coord + 8;
    quake_var3 = 3;
  }
}

void AncillaAdd_SpinAttackInitSpark(uint8 a, uint8 x, uint8 y) {  // 89960b
  static const int8 kSpinAttackStartSparkle_Y[4] = {32, -8, 10, 20};
  static const int8 kSpinAttackStartSparkle_X[4] = {10, 7, 28, -10};

  int k = Ancilla_AddAncilla(a, y);
  for (int i = 4; i >= 0; i--) {
    if (ancilla_type[i] == 0x31)
      ancilla_type[i] = 0;
  }
  ancilla_item_to_link[k] = 0;
  ancilla_step[k] = x;
  ancilla_timer[k] = 4;
  ancilla_aux_timer[k] = 3;
  int j = link_direction_facing >> 1;
  Ancilla_SetXY(k,
      link_x_coord + kSpinAttackStartSparkle_X[j],
      link_y_coord + kSpinAttackStartSparkle_Y[j]);
}

void AncillaAdd_BlastWall() {  // 899692
  static const int8 kBlastWall_Tab3[4] = {-16, 16, 0, 0};
  static const int8 kBlastWall_Tab4[4] = {0, 0, -16, 16};
  static const int8 kBlastWall_Tab5[16] = {-8, 0, -8, 16, 16, 0, 16, 16, 0, -8, 16, -8, 0, 16, 16, 16};

  ancilla_type[0] = 0x33;
  ancilla_type[1] = 0x33;
  ancilla_type[2] = 0;
  ancilla_type[3] = 0;
  ancilla_type[4] = 0;
  ancilla_type[5] = 0;

  ancilla_item_to_link[0] = 0;
  flag_is_ancilla_to_pick_up = 0;
  link_state_bits = 0;
  link_cant_change_direction = 0;
  ancilla_K[0] = 0;
  ancilla_floor[0] = link_is_on_lower_level;
  ancilla_floor[1] = link_is_on_lower_level;
  ancilla_floor2[0] = link_is_on_lower_level_mirror;
  blastwall_var1 = 0;
  blastwall_var6[1] = 0;
  blastwall_var5[1] = 0;
  blastwall_var4 = 0;
  blastwall_var5[0] = 1;
  flag_custom_spell_anim_active = 1;
  blastwall_var6[0] = 3;
  int j = blastwall_var7;
  blastwall_var8 += kBlastWall_Tab3[j];
  blastwall_var9 += kBlastWall_Tab4[j];
  j = (j < 4) ? 4 : 0;
  for (int k = 3; k >= 0; k--, j++) {
    blastwall_var10[k] = blastwall_var8 + kBlastWall_Tab5[j * 2 + 0];
    blastwall_var11[k] = blastwall_var9 + kBlastWall_Tab5[j * 2 + 1];
    uint16 x = blastwall_var11[k] - BG2HOFS_copy2;
    if (x < 256)
      sound_effect_1 = kBombos_Sfx[x >> 5] | 0xc;
  }
  // In dark world forest castle hole outside door

}

void AncillaAdd_SwordChargeSparkle(int k) {  // 899757
  int j;
  for (j = 9; ancilla_type[j] != 0; ) {
    if (--j < 0)
      return;
  }
  ancilla_type[j] = 60;
  ancilla_floor[j] = link_is_on_lower_level;
  ancilla_item_to_link[j] = 0;
  ancilla_timer[j] = 4;

  uint8 rand = GetRandomNumber();

  uint8 z = ancilla_z[k];
  if (z >= 0xF8)
    z = 0;
  Ancilla_SetXY(j, Ancilla_GetX(k) + 2 + (rand >> 5), Ancilla_GetY(k) - 2 - z + (rand & 0xf));
}

void AncillaAdd_SilverArrowSparkle(int kin) {  // 8997de
  static const int8 kSilverArrowSparkle_X[4] = {-4, -4, 0, 2};
  static const int8 kSilverArrowSparkle_Y[4] = {0, 2, -4, -4};
  int k = Ancilla_AllocHigh();
  if (k >= 0) {
    ancilla_type[k] = 0x3c;
    ancilla_item_to_link[k] = 0;
    ancilla_timer[k] = 4;
    ancilla_floor[k] = link_is_on_lower_level;
    int m = GetRandomNumber();
    int j = ancilla_dir[kin] & 3;
    Ancilla_SetXY(k,
      Ancilla_GetX(kin) + kSilverArrowSparkle_X[j] + (m >> 4 & 7),
      Ancilla_GetY(kin) + kSilverArrowSparkle_Y[j] + (m & 7));
  }
}

void AncillaAdd_IceRodShot(uint8 a, uint8 y) {  // 899863
  static const int8 kIceRod_X[4] = {0, 0, -20, 20};
  static const int8 kIceRod_Y[4] = {-16, 24, 8, 8};
  static const int8 kIceRod_Xvel[4] = {0, 0, -48, 48};
  static const int8 kIceRod_Yvel[4] = {-48, 48, 0, 0};

  int k = Ancilla_AddAncilla(a, y);
  if (k < 0) {
    Refund_Magic(0);
    return;
  }
  sound_effect_1 = Link_CalculateSfxPan() | 15;
  ancilla_step[k] = 0;
  ancilla_arr25[k] = 0;
  ancilla_item_to_link[k] = 255;
  ancilla_L[k] = 1;
  ancilla_aux_timer[k] = 3;
  ancilla_arr3[k] = 6;
  int j = link_direction_facing >> 1;
  ancilla_dir[k] = j;
  ancilla_y_vel[k] = kIceRod_Yvel[j];
  ancilla_x_vel[k] = kIceRod_Xvel[j];

  if (Ancilla_CheckInitialTile_A(k) < 0) {
    uint16 x = link_x_coord + kIceRod_X[j];
    uint16 y = link_y_coord + kIceRod_Y[j];

    if (((x - BG2HOFS_copy2) | (y - BG2VOFS_copy2)) & 0xff00) {
      ancilla_type[k] = 0;
      return;
    }
    Ancilla_SetXY(k, x, y);
  } else {
    ancilla_type[k] = 0x11;
    ancilla_numspr[k] = kAncilla_Pflags[0x11];
    ancilla_item_to_link[k] = 0;
    ancilla_aux_timer[k] = 4;
  }
}

bool AncillaAdd_Splash(uint8 a, uint8 y) {  // 8998fc
  int k = Ancilla_AddAncilla(a, y);
  if (k >= 0) {
    sound_effect_1 = Link_CalculateSfxPan() | 0x24;
    ancilla_item_to_link[k] = 0;
    ancilla_aux_timer[k] = 2;
    if (player_is_indoors && !link_is_in_deep_water)
      link_is_on_lower_level = 0;
    Ancilla_SetXY(k, link_x_coord - 11, link_y_coord + 8);
  }
  return k < 0;
}

void AncillaAdd_GraveStone(uint8 ain, uint8 yin) {  // 8999e9
  static const uint16 kMoveGravestone_Y[8] = {0x550, 0x540, 0x530, 0x520, 0x500, 0x4e0, 0x4c0, 0x4b0};
  static const uint16 kMoveGravestone_X[15] = {0x8b0, 0x8f0, 0x910, 0x950, 0x970, 0x9a0, 0x850, 0x870, 0x8b0, 0x8f0, 0x920, 0x950, 0x880, 0x990, 0x840};
  static const uint16 kMoveGravestone_Y1[15] = {0x540, 0x530, 0x530, 0x530, 0x520, 0x520, 0x510, 0x510, 0x4f0, 0x4f0, 0x4f0, 0x4f0, 0x4d0, 0x4b0, 0x4a0};
  static const uint16 kMoveGravestone_X1[15] = {0x8b0, 0x8f0, 0x910, 0x950, 0x970, 0x9a0, 0x850, 0x870, 0x8b0, 0x8f0, 0x920, 0x950, 0x880, 0x990, 0x840};
  static const uint16 kMoveGravestone_Pos[15] = {0xa16, 0x99e, 0x9a2, 0x9aa, 0x92e, 0x934, 0x88a, 0x88e, 0x796, 0x79e, 0x7a4, 0x7aa, 0x690, 0x5b2, 0x508};
  static const uint8 kMoveGravestone_Ctr[15] = {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x58};
  static const uint8 kMoveGravestone_Idx[9] = {0, 1, 4, 6, 8, 12, 13, 14, 15};

  int k = Ancilla_AddAncilla(ain, yin);
  if (k < 0)
    return;
  int t = ((link_y_coord & 0xf) < 7 ? link_y_coord : link_y_coord + 16) & ~0xf;

  int i = 7;
  while (kMoveGravestone_Y[i] != t) {
    if (--i < 0) {
      ancilla_type[k] = 0;
      return;
    }
  }

  int j = kMoveGravestone_Idx[i];
  int end = kMoveGravestone_Idx[i + 1];
  do {
    int x = kMoveGravestone_X[j];
    if (x < link_x_coord && (uint16)(x + 15) >= link_x_coord) {
      if (j == 13 ? !link_is_running : link_is_running)
        break;

      int pos = kMoveGravestone_Pos[j];
      big_rock_starting_address = pos;
      door_open_closed_counter = kMoveGravestone_Ctr[j];
      if (door_open_closed_counter == 0x58) {
        sound_effect_2 = Link_CalculateSfxPan() | 0x1b;
      } else if (door_open_closed_counter == 0x38) {
        save_ow_event_info[BYTE(overworld_screen_index)] |= 0x20;
        sound_effect_2 = Link_CalculateSfxPan() | 0x1b;
      }

      ((uint8 *)door_debris_y)[k] = (pos - 0x80);
      ((uint8 *)door_debris_x)[k] = (pos - 0x80) >> 8;

      Overworld_DoMapUpdate32x32_B();

      if ((sound_effect_2 & 0x3f) != 0x1b)
        sound_effect_1 = Link_CalculateSfxPan() | 0x22;

      int yy = kMoveGravestone_Y1[j];
      int xx = kMoveGravestone_X1[j];
      bitmask_of_dragstate = 4;
      link_something_with_hookshot = 1;
      ancilla_A[k] = (yy - 18);
      ancilla_B[k] = (yy - 18) >> 8;
      Ancilla_SetXY(k, xx, yy - 2);
      return;
    }
  } while (++j != end);
  ancilla_type[k] = 0;
}

void AncillaAdd_WaterfallSplash() {  // 899b68
  if (AncillaAdd_CheckForPresence(0x41))
    return;
  int k = Ancilla_AddAncilla(0x41, 4);
  if (k >= 0) {
    ancilla_timer[k] = 2;
    ancilla_item_to_link[k] = 0;
  }
}

void AncillaAdd_GTCutscene() {  // 899b83
  if (link_state_bits & 0x80 | link_auxiliary_state ||
     (link_has_crystals & 0x7f) != 0x7f ||
      save_ow_event_info[0x43] & 0x20)
    return;

  Ancilla_TerminateSparkleObjects();

  if (AncillaAdd_CheckForPresence(0x43))
    return;

  int k = Ancilla_AddAncilla(0x43, 4);
  if (k < 0)
    return;

  for (int i = 15; i >= 0; i--) {
    if (sprite_type[i] == 0x37)
      sprite_state[i] = 0;
  }

  for (int i = 0x17; i >= 0; i--)
    breaktowerseal_sparkle_var1[i] = 0xff;
  DecodeAnimatedSpriteTile_variable(0x28);
  palette_sp6r_indoors = 4;
  overworld_palette_aux_or_main = 0x200;
  Palette_Load_SpriteEnvironment_Dungeon();
  flag_update_cgram_in_nmi++;
  flag_is_link_immobilized = 1;
  ancilla_y_subpixel[k] = 0;
  ancilla_x_subpixel[k] = 0;
  ancilla_step[k] = 0;
  breaktowerseal_var5 = 240;
  breaktowerseal_var4 = 0;

  breaktowerseal_var3[0] = 0;

  breaktowerseal_var3[1] = 10;
  breaktowerseal_var3[2] = 22;
  breaktowerseal_var3[3] = 32;
  breaktowerseal_var3[4] = 42;
  breaktowerseal_var3[5] = 54;

  Ancilla_SetXY(k, link_x_coord, link_y_coord - 16);
}

int AncillaAdd_DoorDebris() {  // 899c38
  int k = Ancilla_AddAncilla(8, 1);
  if (k >= 0) {
    ancilla_arr25[k] = 0;
    ancilla_arr26[k] = 7;
  }
  return k;
}

void FireRodShot_BecomeSkullWoodsFire(int k) {  // 899c4f
  if (player_is_indoors || !(BYTE(overworld_screen_index) & 0x40))
    return;

  ancilla_type[0] = 0x34;
  ancilla_type[1] = 0;
  ancilla_type[2] = 0;
  ancilla_type[3] = 0;
  ancilla_type[4] = 0;
  ancilla_type[5] = 0;
  flag_for_boomerang_in_place = 0;
  ancilla_numspr[0] = kAncilla_Pflags[0x34];
  skullwoodsfire_var0[0] = 253;
  skullwoodsfire_var0[1] = 254;
  skullwoodsfire_var0[2] = 255;
  skullwoodsfire_var0[3] = 0;
  skullwoodsfire_var4 = 0;
  skullwoodsfire_var5[0] = 5;
  skullwoodsfire_var5[1] = 5;
  skullwoodsfire_var5[2] = 5;
  skullwoodsfire_var5[3] = 5;
  ancilla_aux_timer[0] = 5;
  skullwoodsfire_var9 = 0x100;
  skullwoodsfire_var10 = 0x100;
  skullwoodsfire_var11 = 0x98;
  skullwoodsfire_var12 = 0x98;

  trigger_special_entrance = 2;
  subsubmodule_index = 0;
  BYTE(R16) = 0;
  ancilla_floor[0] = link_is_on_lower_level;
  ancilla_floor2[0] = link_is_on_lower_level_mirror;
  ancilla_item_to_link[0] = 0;
  ancilla_step[0] = 0;

}

int Ancilla_AddAncilla(uint8 a, uint8 y) {  // 899ce2
  int k = Ancilla_AllocInit(a, y);
  if (k >= 0) {
    ancilla_type[k] = a;
    ancilla_floor[k] = link_is_on_lower_level;
    ancilla_floor2[k] = link_is_on_lower_level_mirror;
    ancilla_y_vel[k] = 0;
    ancilla_x_vel[k] = 0;
    ancilla_objprio[k] = 0;
    ancilla_U[k] = 0;
    ancilla_numspr[k] = kAncilla_Pflags[a];
  }
  return k;
}

bool AncillaAdd_CheckForPresence(uint8 a) {  // 899d20
  for (int k = 5; k >= 0; k--) {
    if (ancilla_type[k] == a)
      return true;
  }
  return false;
}

int AncillaAdd_ArrowFindSlot(uint8 type, uint8 ay) {  // 899d36
  int k, n = 0;
  for (k = 4; k >= 0; k--) {
    if (ancilla_type[k] == 10)
      n++;
  }
  if (n != ay + 1) {
    for (k = 4; k >= 0; k--) {
      if (ancilla_type[k] == 0)
        break;
    }
  } else {
    do {
      if (sign8(--ancilla_alloc_rotate))
        ancilla_alloc_rotate = 4;
      k = ancilla_alloc_rotate;
    } while (ancilla_type[k] != 10);
  }
  if (k >= 0) {
    ancilla_type[k] = type;
    ancilla_floor[k] = link_is_on_lower_level;
    ancilla_floor2[k] = link_is_on_lower_level_mirror;
    ancilla_y_vel[k] = 0;
    ancilla_x_vel[k] = 0;
    ancilla_objprio[k] = 0;
    ancilla_U[k] = 0;
    ancilla_numspr[k] = kAncilla_Pflags[type];
  }
  return k;
}

int Ancilla_CheckInitialTile_A(int k) {  // 899dd3
  static const int8 kAncilla_Yoffs_Hb[12] = {8, 0, -8, 8, 16, 24, 8, 8, 8, 8, 8, 8};
  static const int8 kAncilla_Xoffs_Hb[12] = {0, 0, 0, 0, 0, 0, 0, -8, -16, 0, 8, 16};
  int j = ancilla_dir[k] * 3;
  int i;
  for (i = 2; i >= 0; i--, j++) {
    uint16 x = link_x_coord + kAncilla_Xoffs_Hb[j];
    uint16 y = link_y_coord + kAncilla_Yoffs_Hb[j];
    Ancilla_SetXY(k, x, y);
    if (Ancilla_CheckTileCollision(k))
      break;
  }
  return i;
}

bool Ancilla_CheckInitialTileCollision_Class2(int k) {  // 899e44
  static const int16 kAncilla_InitialTileColl_Y[9] = {15, 16, 28, 24, 12, 12, 12, 12, 8};
  static const int16 kAncilla_InitialTileColl_X[9] = {8, 8, 8, 8, -1, 0, 17, 16, 0x4b8b}; // wtf
  int j = ancilla_dir[k] * 2;
  for (int n = 2; n >= 0; n--, j++) {
    Ancilla_SetXY(k, link_x_coord + kAncilla_InitialTileColl_X[j],
                     link_y_coord + kAncilla_InitialTileColl_Y[j]);
    if (Ancilla_CheckTileCollision_Class2(k))
      return true;
  }
  return false;
}

uint8 Ancilla_TerminateSelectInteractives(uint8 y) {  // 89ac6b
  int i = 5;

  do {
    if (ancilla_type[i] == 0x3e) {
      y = i;
    }
    else if (ancilla_type[i] == 0x2c) {
      dung_flag_somaria_block_switch = 0;
      if (bitmask_of_dragstate & 0x80) {
        bitmask_of_dragstate = 0;
        link_speed_setting = 0;
      }
    }

    if (sign8(link_state_bits)) {
      if (i + 1 != flag_is_ancilla_to_pick_up)
        ancilla_type[i] = 0;
    }
    else {
      if (i + 1 == flag_is_ancilla_to_pick_up)
        flag_is_ancilla_to_pick_up = 0;
      ancilla_type[i] = 0;
    }
  } while (--i >= 0);

  if (link_position_mode & 0x10) {
    link_incapacitated_timer = 0;
    link_position_mode = 0;
  }
  flute_countdown = 0;
  tagalong_event_flags = 0;
  byte_7E02F3 = 0;
  flag_for_boomerang_in_place = 0;
  is_archer_or_shovel_game = 0;
  link_disable_sprite_damage = 0;
  byte_7E03FD = 0;
  link_electrocute_on_touch = 0;
  if (link_player_handler_state == 19) {
    link_player_handler_state = 0;
    button_mask_b_y &= ~0x40;
    link_cant_change_direction &= ~1;
    link_position_mode &= ~4;
    related_to_hookshot = 0;
  }
  return y;
}

void Ancilla_SetXY(int k, uint16 x, uint16 y) {  // 89ad06
  Ancilla_SetX(k, x);
  Ancilla_SetY(k, y);
}

void AncillaAdd_ExplodingSomariaBlock(int k) {  // 89ad30
  ancilla_type[k] = 0x2e;
  ancilla_numspr[k] = kAncilla_Pflags[0x2e];
  ancilla_aux_timer[k] = 3;
  ancilla_step[k] = 0;
  ancilla_item_to_link[k] = 0;
  ancilla_arr3[k] = 0;
  ancilla_arr1[k] = 0;
  ancilla_R[k] = 0;
  ancilla_objprio[k] = 0;
  dung_flag_somaria_block_switch = 0;
  sound_effect_2 = Ancilla_CalculateSfxPan(k) | 1;
}

bool Ancilla_AddRupees(int k) {  // 89ad6c
  static const uint8 kGiveRupeeGift_Tab[5] = {1, 5, 20, 100, 50};
  uint8 a = ancilla_item_to_link[k];
  if (a == 0x34 || a == 0x35 || a == 0x36) {
    link_rupees_goal += kGiveRupeeGift_Tab[a - 0x34];
  } else if (a == 0x40 || a == 0x41) {
    link_rupees_goal += kGiveRupeeGift_Tab[a - 0x40 + 3];
  } else if (a == 0x46) {
    link_rupees_goal += 300;
  } else if (a == 0x47) {
    link_rupees_goal += 20;
  } else {
    return false;
  }
  return true;
}

void DashDust_Motive(int k) {  // 89adf4
  static const uint8 kMotiveDashDust_Draw_Char[3] = {0xa9, 0xcf, 0xdf};
  if (!ancilla_timer[k]) {
    ancilla_timer[k] = 3;
    if (++ancilla_item_to_link[k] == 3) {
      ancilla_type[k] = 0;
      return;
    }
  }
  if (link_direction_facing == 2)
    Oam_AllocateFromRegionB(4);
  Point16U info;
  Ancilla_PrepOamCoord(k, &info);
  Ancilla_SetOam(GetOamCurPtr(), info.x, info.y,
                 kMotiveDashDust_Draw_Char[ancilla_item_to_link[k]], 4 | HIBYTE(oam_priority_value), 0);
}

uint8 Ancilla_CalculateSfxPan(int k) {  // 8dbb5e
  return CalculateSfxPan(Ancilla_GetX(k));
}

int Ancilla_AllocInit(uint8 type, uint8 limit) {  // 8ff577
  // snes bug: R14 is used in tile detection already
  // unless this is here it the memcmp will fail when entering/leaving a water through steps quickly
  if (g_ram[kRam_BugsFixed] >= kBugFix_PolyRenderer)
    BYTE(R14) = limit + 1;

  int n = 0;
  for (int i = 0; i < 5; i++) {
    if (ancilla_type[i] == type)
      n++;
  }
  if (limit + 1 == n)
    return -1;

  // Try to reuse an empty ancilla slot
  for (int j = (type == 7 || type == 8) ? limit : 4; j >= 0; j--) {
    if (ancilla_type[j] == 0)
      return j;
  }
  int k = ancilla_alloc_rotate;
  do {
    if (--k < 0)
      k = limit;
    uint8 old_type = ancilla_type[k];
    // reuse slots for sparkles or arrows in wall
    if (old_type == 0x3c || old_type == 0x13 || old_type == 0xa) {
      ancilla_alloc_rotate = k;
      return k;
    }
  } while (k != 0);
  ancilla_alloc_rotate = 0;
  return -1;
}

void AddSwordBeam(uint8 y) {  // 8ff67b
  static const int8 kSwordBeam_X[4] = {-8, -10, -22, 4};
  static const int8 kSwordBeam_Y[4] = {-24, 8, -6, -6};
  static const int8 kSwordBeam_S[4] = {-8, -8, -8, 8};
  static const uint8 kSwordBeam_Tab[16] = {0x21, 0x1d, 0x19, 0x15, 3, 0x3e, 0x3a, 0x36, 0x12, 0xe, 0xa, 6, 0x31, 0x2d, 0x29, 0x25};
  static const int8 kSwordBeam_Yvel[4] = {-64, 64, 0, 0};
  static const int8 kSwordBeam_Xvel[4] = {0, 0, -64, 64};

  int k = Ancilla_AddAncilla(0xc, y);
  if (k < 0)
    return;
  int j = link_direction_facing * 2;
  swordbeam_arr[0] = kSwordBeam_Tab[j + 0];
  swordbeam_arr[1] = kSwordBeam_Tab[j + 1];
  swordbeam_arr[2] = kSwordBeam_Tab[j + 2];
  swordbeam_arr[3] = swordbeam_var1 = kSwordBeam_Tab[j + 3];
  ancilla_aux_timer[k] = 2;
  ancilla_item_to_link[k] = 0x4c;
  ancilla_arr3[k] = 8;
  ancilla_step[k] = 0;
  ancilla_L[k] = 0;
  ancilla_G[k] = 0;
  ancilla_arr1[k] = 0;
  swordbeam_var2 = 14;
  j = link_direction_facing >> 1;
  ancilla_dir[k] = j;
  ancilla_y_vel[k] = kSwordBeam_Yvel[j];
  ancilla_x_vel[k] = kSwordBeam_Xvel[j];
  ancilla_S[k] = kSwordBeam_S[j];

  swordbeam_temp_y = link_y_coord + 12;
  swordbeam_temp_x = link_x_coord + 8;

  if (Ancilla_CheckInitialTile_A(k) >= 0) {
    Ancilla_SetXY(k, swordbeam_temp_x + kSwordBeam_X[j], swordbeam_temp_y + kSwordBeam_Y[j]);
    sound_effect_2 = 1 | Ancilla_CalculateSfxPan(k);
    ancilla_type[k] = 4;
    ancilla_timer[k] = 7;
    ancilla_numspr[k] = 16;
  }
}

void AncillaSpawn_SwordChargeSparkle() {  // 8ff979
  static const uint8 kSwordChargeSparkle_A[4] = {0, 0, 7, 7};
  static const uint8 kSwordChargeSparkle_B[4] = {0x70, 0x70, 0, 0};
  static const uint8 kSwordChargeSparkle_X[4] = {0, 3, 4, 5};
  static const uint8 kSwordChargeSparkle_Y[4] = {5, 12, 8, 8};
  int k = Ancilla_AllocHigh();
  if (k < 0)
    return;
  ancilla_type[k] = 0x3c;
  ancilla_item_to_link[k] = 0;
  ancilla_timer[k] = 4;
  ancilla_floor[k] = link_is_on_lower_level;
  int j = link_direction_facing >> 1;
  int8 x = 0, y = 0;
  uint8 m0 = kSwordChargeSparkle_A[j];
  if (!m0) {
    y = link_spin_attack_step_counter >> 2;
    if (j == 0)
      y = -y;
  }
  uint8 m1 = kSwordChargeSparkle_B[j];
  if (!m1) {
    x = link_spin_attack_step_counter >> 2;
    if (j == 2)
      x = -x;
  }
  uint8 r = GetRandomNumber();
  Ancilla_SetXY(k,
    link_x_coord + x + kSwordChargeSparkle_X[j] + ((r & m1) >> 4),
    link_y_coord + y + kSwordChargeSparkle_Y[j] + (r & m0));
}

int DashTremor_TwiddleOffset(int k) {  // 8ffafe
  int j = ancilla_dir[k];
  uint16 y = -Ancilla_GetY(k);
  Ancilla_SetY(k, y);
  if (player_is_indoors)
    return y;
  if (j == 2) {
    uint16 start = ow_scroll_vars0.ystart + 1;
    uint16 end = ow_scroll_vars0.yend - 1;
    uint16 a = y + BG2VOFS_copy2;
    return (a <= start || a >= end) ? 0 : y;
  } else {
    uint16 start = ow_scroll_vars0.xstart + 1;
    uint16 end = ow_scroll_vars0.xend - 1;
    uint16 a = y + BG2HOFS_copy2;
    return (a <= start || a >= end) ? 0 : y;
  }
}

void Ancilla_TerminateIfOffscreen(int j) {  // 8ffd52
  int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
  uint16 x = Ancilla_GetX(j) - BG2HOFS_copy2 + xt;
  uint16 y = Ancilla_GetY(j) - BG2VOFS_copy2;
  if (x >= 244 + xt * 2 || y >= 240)
    ancilla_type[j] = 0;
}

bool Bomb_CheckUndersideSpriteStatus(int k, Point16U *out_pt, uint8 *out_r10) {  // 8ffdcf
  if (ancilla_item_to_link[k] != 0)
    return true;

  uint8 r10 = 0;
  if (ancilla_tile_attr[k] == 9) {
    if (sign8(--ancilla_arr22[k])) {
      ancilla_arr22[k] = 3;
      if (++ancilla_arr23[k] == 3)
        ancilla_arr23[k] = 0;
    }
    r10 = ancilla_arr23[k] + 4;
    if ((sound_effect_1 & 0x3f) == 0xb || (sound_effect_1 & 0x3f) == 0x21)
      sound_effect_1 = Ancilla_CalculateSfxPan(k) | 0x28;
  } else if (ancilla_tile_attr[k] == 0x40) {
    r10 = 3;
  }

  if (ancilla_z[k] >= 2 && ancilla_z[k] < 252)
    r10 = 2;
  if (k + 1 == flag_is_ancilla_to_pick_up && (link_state_bits & 0x80))
    return true;
  int z = (int8)ancilla_z[k];
  out_pt->y += z + 2;
  out_pt->x += -8;
  *out_r10 = r10;
  return false;
}

void Sprite_CreateDeflectedArrow(int k) {  // 9d8040
  ancilla_type[k] = 0;
  SpriteSpawnInfo info;
  int j = Sprite_SpawnDynamically(k, 0x1b, &info);
  if (j >= 0) {
    sprite_x_lo[j] = ancilla_x_lo[k];
    sprite_x_hi[j] = ancilla_x_hi[k];
    sprite_y_lo[j] = ancilla_y_lo[k];
    sprite_y_hi[j] = ancilla_y_hi[k];
    sprite_state[j] = 6;
    sprite_delay_main[j] = 31;
    sprite_x_vel[j] = ancilla_x_vel[k];
    sprite_y_vel[j] = ancilla_y_vel[k];
    sprite_floor[j] = link_is_on_lower_level;
    Sprite_PlaceWeaponTink(j);
  }
}