ref: 3870ca7517f18856e5e3eba9d067fb07fd97b7d2
dir: /sprite_main.c/
#include "sprite_main.h" #include "sprite.h" #include "tagalong.h" #include "ancilla.h" #include "overworld.h" #include "load_gfx.h" #include "hud.h" #include "dungeon.h" #include "player.h" #include "misc.h" #define byte_7FFE01 (*(uint8*)(g_ram+0x1FE01)) static const int8 kSpriteKeese_Tab2[16] = {0, 8, 11, 14, 16, 14, 11, 8, 0, -8, -11, -14, -16, -14, -11, -8}; static const int8 kSpriteKeese_Tab3[16] = {-16, -14, -11, -8, 0, 8, 11, 14, 16, 14, 11, 8, 0, -9, -11, -14}; static const int8 kZazak_Yvel[4] = {0, 0, 16, -16}; static const int8 kFluteBoyAnimal_Xvel[4] = {16, -16, 0, 0}; static const int8 kDesertBarrier_Xv[4] = {16, -16, 0, 0}; static const int8 kDesertBarrier_Yv[4] = {0, 0, 16, -16}; static const uint8 kCrystalSwitchPal[2] = {2, 4}; static const uint8 kZazak_Dir2[8] = {2, 3, 2, 3, 0, 1, 0, 1}; #define moldorm_x_lo ((uint8*)(g_ram+0x1FC00)) #define moldorm_x_hi ((uint8*)(g_ram+0x1FC80)) #define moldorm_y_lo ((uint8*)(g_ram+0x1FD00)) #define moldorm_y_hi ((uint8*)(g_ram+0x1FD80)) static const int8 kBadPullDownSwitch_X[5] = {-4, 12, 0, -4, 4}; static const int8 kBadPullDownSwitch_Y[5] = {-3, -3, 0, 5, 5}; static const uint8 kBadPullDownSwitch_Char[5] = {0xd2, 0xd2, 0xc4, 0xe4, 0xe4}; static const uint8 kBadPullDownSwitch_Flags[5] = {0x40, 0, 0, 0x40, 0}; static const uint8 kBadPullDownSwitch_Ext[5] = {0, 0, 2, 2, 2}; static const uint8 kBadPullSwitch_Tab5[6] = {0, 1, 2, 3, 4, 5}; static const uint8 kBadPullSwitch_Tab4[12] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5}; static const uint8 kThief_Gfx[12] = {11, 8, 2, 5, 9, 6, 0, 3, 10, 7, 1, 4}; #define word_7FFE00 (*(uint16*)(g_ram+0x1FE00)) #define word_7FFE02 (*(uint16*)(g_ram+0x1FE02)) #define word_7FFE04 (*(uint16*)(g_ram+0x1FE04)) #define word_7FFE06 (*(uint16*)(g_ram+0x1FE06)) static const int16 kTutorialSoldier_X[20] = { 4, 0, -6, -6, 2, 0, 0, -7, -7, -7, 0, 0, 0xf, 0xf, 0xf, 6, 0xe, -4, 4, 0, }; static const int16 kTutorialSoldier_Y[20] = { 0, -10, -4, 12, 12, 0, -9, -11, -3, 5, 0, -9, -11, -3, 5, -11, 5, 0, 0, -9, }; static const uint8 kTutorialSoldier_Char[20] = { 0x46, 0x40, 0, 0x28, 0x29, 0x4e, 0x42, 0x39, 0x2a, 0x3a, 0x4e, 0x42, 0x39, 0x2a, 0x3a, 0x26, 0x38, 0x64, 0x64, 0x44, }; static const uint8 kTutorialSoldier_Flags[20] = { 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0x40, 0, 0x40, 0, }; static const uint8 kTutorialSoldier_Ext[20] = { 2, 2, 2, 0, 0, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 2, 0, 2, 2, 2, }; static const uint8 kSprite_TutorialEntities_Tab[4] = {2, 1, 0, 3}; static const uint8 kSoldier_DirectionLockSettings[4] = {3, 2, 0, 1}; static const uint8 kWishPond_X[8] = {0, 4, 8, 12, 16, 20, 24, 0}; static const uint8 kWishPond_Y[8] = {0, 8, 16, 24, 32, 40, 4, 36}; const uint8 kWishPond2_OamFlags[76] = { 5, 0xff, 5, 5, 5, 5, 5, 1, 2, 1, 1, 1, 2, 2, 2, 4, 4, 4, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 4, 4, 2, 1, 6, 1, 2, 1, 2, 2, 1, 2, 2, 4, 1, 1, 4, 2, 1, 4, 2, 2, 4, 4, 4, 2, 1, 4, 1, 2, 2, 1, 2, 2, 1, 1, 4, 4, 1, 2, 2, 4, 4, 4, 2, 5, 2, 1, }; static const uint8 kWishPondItemOffs[32] = { 0, 4, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 20, 21, 22, 22, 23, 24, 25, 28, 30, 31, 32, 33, 33, 37, 40, 42, 42, 42, 42 }; static const uint8 kWishPondItemData[50] = { 0x3a, 0x3a, 0x3b, 0x3b, 0x0c, 0x2a, 0x0a, 0x27, 0x29, 0x0d, 0x07, 0x08, 0x0f, 0x10, 0x11, 0x12, 0x09, 0x13, 0x14, 0x4a, 0x21, 0x1d, 0x15, 0x18, 0x19, 0x31, 0x1a, 0x1a, 0x1b, 0x1c, 0x4b, 0x1e, 0x1f, 0x49, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x22, 0x23, 0x29, 0x16, 0x2b, 0x2c, 0x2d, 0x3d, 0x3c, 0x48 }; static const DrawMultipleData kUncleDraw_Table[48] = { { 0, -10, 0x0e00, 2}, { 0, 0, 0x0c06, 2}, { 0, -10, 0x0e00, 2}, { 0, 0, 0x0c06, 2}, { 0, -10, 0x0e00, 2}, { 0, 0, 0x0c06, 2}, { 0, -10, 0x0e02, 2}, { 0, 0, 0x0c06, 2}, { 0, -10, 0x0e02, 2}, { 0, 0, 0x0c06, 2}, { 0, -10, 0x0e02, 2}, { 0, 0, 0x0c06, 2}, { -7, 2, 0x0d07, 2}, { -7, 2, 0x0d07, 2}, { 10, 12, 0x8d05, 0}, { 10, 4, 0x8d15, 0}, { 0, -10, 0x0e00, 2}, { 0, 0, 0x0c04, 2}, { -7, 1, 0x0d07, 2}, { -7, 1, 0x0d07, 2}, { 10, 13, 0x8d05, 0}, { 10, 5, 0x8d15, 0}, { 0, -9, 0x0e00, 2}, { 0, 1, 0x4c04, 2}, { -7, 8, 0x8d05, 0}, { 1, 8, 0x8d06, 0}, { 0, -10, 0x0e02, 2}, { -6, -1, 0x4d07, 2}, { 0, 0, 0x0c23, 2}, { 0, 0, 0x0c23, 2}, { -9, 7, 0x8d05, 0}, { -1, 7, 0x8d06, 0}, { 0, -9, 0x0e02, 2}, { -6, 0, 0x4d07, 2}, { 0, 1, 0x0c25, 2}, { 0, 1, 0x0c25, 2}, {-10, -17, 0x0d07, 2}, { 15, -12, 0x8d15, 0}, { 15, -4, 0x8d05, 0}, { 0, -28, 0x0e08, 2}, { -8, -19, 0x0c20, 2}, { 8, -19, 0x4c20, 2}, { 0, -28, 0x0e08, 2}, { 0, -28, 0x0e08, 2}, { -8, -19, 0x0c20, 2}, { 8, -19, 0x4c20, 2}, { -8, -19, 0x0c20, 2}, { 8, -19, 0x4c20, 2}, }; static const uint8 kUncleDraw_Dma3[8] = {8, 8, 0, 0, 6, 6, 0, 0}; static const uint8 kUncleDraw_Dma4[8] = {0, 0, 0, 0, 4, 4, 0, 0x8b}; // wtf static const uint8 kUncle_LeaveHouse_Delay[2] = {64, 224}; static const uint8 kUncle_LeaveHouse_Dir[2] = {2, 1}; static const int8 kUncle_LeaveHouse_Xvel[4] = {0, 0, -12, 12}; static const int8 kUncle_LeaveHouse_Yvel[4] = {-12, 12, 0, 0}; static const DrawMultipleData kPriest_Dmd[20] = { { 0, -8, 0x0e20, 2}, { 0, 0, 0x0e26, 2}, { 0, -8, 0x0e20, 2}, { 0, 0, 0x4e26, 2}, { 0, -8, 0x0e0e, 2}, { 0, 0, 0x0e24, 2}, { 0, -8, 0x0e0e, 2}, { 0, 0, 0x0e24, 2}, { 0, -8, 0x0e22, 2}, { 0, 0, 0x0e28, 2}, { 0, -8, 0x0e22, 2}, { 0, 0, 0x0e2a, 2}, { 0, -8, 0x4e22, 2}, { 0, 0, 0x4e28, 2}, { 0, -8, 0x4e22, 2}, { 0, 0, 0x4e2a, 2}, {-7, 1, 0x0e0a, 2}, { 3, 3, 0x0e0c, 2}, {-7, 1, 0x0e0a, 2}, { 3, 3, 0x0e0c, 2}, }; static const DrawMultipleData kSageMantle_Dmd[4] = { {0, 0, 0x162c, 2}, {16, 0, 0x562c, 2}, {0, 16, 0x062e, 2}, {16, 16, 0x462e, 2}, }; static const uint8 kCrystalMaiden_Dma[16] = {0x20, 0xc0, 0x20, 0xc0, 0, 0xa0, 0, 0xa0, 0x40, 0x80, 0x40, 0x60, 0x40, 0x80, 0x40, 0x60}; static const DrawMultipleData kCrystalMaiden_SpriteData[16] = { {1, -7, 0x0120, 2}, {1, 3, 0x0122, 2}, {1, -7, 0x0120, 2}, {1, 3, 0x4122, 2}, {1, -7, 0x0120, 2}, {1, 3, 0x0122, 2}, {1, -7, 0x0120, 2}, {1, 3, 0x4122, 2}, {1, -7, 0x0120, 2}, {1, 3, 0x0122, 2}, {1, -7, 0x0120, 2}, {1, 3, 0x0122, 2}, {1, -7, 0x4120, 2}, {1, 3, 0x4122, 2}, {1, -7, 0x4120, 2}, {1, 3, 0x4122, 2}, }; static const int8 kZelda_Xvel[4] = {0, 0, -9, 9}; static const int8 kZelda_Yvel[4] = {-9, 9, 0, 0}; static const int8 kHeartRefill_AccelX[2] = {1, -1}; static const int8 kHeartRefill_VelTarget[2] = {10, -10}; static const DrawMultipleData kFakeSword_Dmd[2] = { {4, 0, 0x00f4, 0}, {4, 8, 0x00f5, 0}, }; static const uint8 kThrowableScenery_Char[12] = {0x42, 0x44, 0x46, 0, 0x46, 0x44, 0x42, 0x44, 0x44, 0, 0x46, 0x44}; const uint8 kThrowableScenery_Flags[9] = { 0xc, 0xc, 0xc, 0, 0, 0, 0xb0, 0x08, 0xb4 }; static const int16 kThrowableScenery_DrawLarge_X[4] = {-8, 8, -8, 8}; static const int16 kThrowableScenery_DrawLarge_Y[4] = {-14, -14, 2, 2}; static const uint8 kThrowableScenery_DrawLarge_Flags[4] = {0, 0x40, 0x80, 0xc0}; static const int16 kThrowableScenery_DrawLarge_X2[3] = {-6, 0, 6}; static const uint8 kThrowableScenery_DrawLarge_OamFlags[2] = {0xc, 0}; static const int8 kScatterDebris_X[4] = {-8, 8, -8, 8}; static const int8 kScatterDebris_Y[4] = {-8, -8, 8, 8}; static const uint8 kMovableMantle_X[6] = {0, 0x10, 0x20, 0, 0x10, 0x20}; static const uint8 kMovableMantle_Y[6] = {0, 0, 0, 0x10, 0x10, 0x10}; static const uint8 kMovableMantle_Char[6] = {0xc, 0xe, 0xc, 0x2c, 0x2e, 0x2c}; static const uint8 kMovableMantle_Flags[6] = {0x31, 0x31, 0x71, 0x31, 0x31, 0x71}; static const uint8 kSprite_SimplifiedTileAttr[256] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; static const uint8 kSoldier_Gfx[4] = {8, 0, 12, 5}; static const uint8 kSoldier_Delay[4] = {0x60, 0xc0, 0xff, 0x40}; static const uint8 kSoldier_Draw1_Char[4] = {0x42, 0x42, 0x40, 0x44}; static const uint8 kSoldier_Draw1_Flags[4] = {0x40, 0, 0, 0}; static const int8 kSoldier_Draw1_Yd[26] = { 7, 8, 7, 8, 8, 7, 8, 7, 8, 7, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, }; static const int8 kSoldier_Draw2_Xd[104] = { -4, 4, 10, 10, -4, 4, 10, 10, -4, 4, 10, 10, -4, 4, 10, 10, -4, -4, 0, 0, -4, -4, 0, 0, -3, -3, 0, 0, -3, -3, -4, 4, -3, -3, -4, 4, -3, -3, -4, 4, -3, -3, -4, 4, 12, 12, 0, 0, 12, 12, 0, 0, 11, 11, 0, 0, -4, 4, 0, 0, -4, 4, 0, 0, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 4, 0, 0, -4, 4, 0, 0, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const int8 kSoldier_Draw2_Yd[104] = { 0, 0, 2, 10, 0, 0, 2, 10, 0, 0, 1, 9, 0, 0, 2, 10, -2, 6, 1, 1, -2, 6, 2, 2, -2, 6, 1, 1, -5, 3, 0, 0, -4, 4, 0, 0, -4, 4, 0, 0, -5, 3, 0, 0, -2, 6, 1, 1, -2, 6, 2, 2, -2, 6, 1, 1, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, }; static const uint8 kSoldier_Draw2_Char[104] = { 0x48, 0x49, 0x6d, 0x7d, 0x49, 0x48, 0x6d, 0x7d, 0x46, 0x46, 0x6d, 0x7d, 0x4b, 0x46, 0x6d, 0x7d, 0x4d, 0x5d, 0x4e, 0x4e, 0x4d, 0x5d, 0x60, 0x60, 0x4d, 0x5d, 0x62, 0x62, 0x6d, 0x7d, 0x64, 0x64, 0x6d, 0x7d, 0x66, 0x67, 0x6d, 0x7d, 0x67, 0x66, 0x6d, 0x7d, 0x64, 0x69, 0x4d, 0x5d, 0x4e, 0x4e, 0x4d, 0x5d, 0x60, 0x60, 0x4d, 0x5d, 0x62, 0x62, 2, 3, 0x20, 0x20, 2, 0xc, 0x20, 0x20, 2, 0xc, 0x20, 0x20, 8, 8, 0x20, 0x20, 0xe, 0xe, 0x20, 0x20, 0xe, 0xe, 0x20, 0x20, 5, 6, 0x20, 0x20, 0x22, 6, 0x20, 0x20, 0x22, 6, 0x20, 0x20, 8, 8, 0x20, 0x20, 0xe, 0xe, 0x20, 0x20, 0xe, 0xe, 0x20, 0x20, }; static const uint8 kSoldier_Draw2_Flags[104] = { 0, 0, 0, 0, 0x40, 0x40, 0, 0, 0, 0x40, 0, 0, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, }; static const uint8 kSoldier_Draw2_Ext[104] = { 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, }; static const uint8 kSoldier_Draw2_OamIdx[4] = {12, 12, 12, 4}; static const int8 kSoldier_Draw3_Xd[28] = { -3, -3, -4, -4, -4, -4, -4, -4, -11, -3, -11, -3, -16, -8, 12, 12, 12, 12, 12, 12, 12, 12, 21, 13, 21, 13, 24, 16, }; static const int8 kSoldier_Draw3_Yd[28] = { 11, 19, 11, 19, 10, 18, 14, 22, 8, 8, 8, 8, 6, 6, -10, -2, -9, -1, -9, -1, -16, -8, 8, 8, 8, 8, 6, 6, }; static const uint8 kSoldier_Draw3_Char[28] = { 0x7b, 0x6b, 0x7b, 0x6b, 0x7b, 0x6b, 0x7b, 0x6b, 0x6c, 0x7c, 0x6c, 0x7c, 0x6c, 0x7c, 0x6b, 0x7b, 0x6b, 0x7b, 0x6b, 0x7b, 0x6b, 0x7b, 0x6c, 0x7c, 0x6c, 0x7c, 0x6c, 0x7c, }; static const uint8 kSoldier_Draw3_Flags[28] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, }; static const uint8 kSoldier_Draw3_OamIdx[4] = {4, 4, 4, 20}; static const int8 kSoldier_Xvel[4] = {8, -8, 0, 0}; static const int8 kSoldier_Yvel[4] = {0, 0, 8, -8}; static const uint8 kSoldier_Gfx2[32] = { 11, 12, 13, 12, 4, 5, 6, 5, 0, 1, 2, 3, 7, 8, 9, 10, 17, 18, 17, 18, 7, 8, 7, 8, 3, 4, 3, 4, 13, 14, 13, 14, }; static const int8 kSoldierB_Xvel[8] = {1, 1, -1, -1, -1, -1, 1, 1}; static const int8 kSoldierB_Yvel[8] = {-1, 1, 1, -1, -1, 1, 1, -1}; static const int8 kSoldierB_Xvel2[8] = {8, 0, -8, 0, -8, 0, 8, 0}; static const int8 kSoldierB_Yvel2[8] = {0, 8, 0, -8, 0, 8, 0, -8}; static const uint8 kSoldierB_Dir[8] = {0, 2, 1, 3, 1, 2, 0, 3}; static const uint8 kSoldierB_Mask2[8] = {1, 4, 2, 8, 2, 4, 1, 8}; static const uint8 kSoldierB_Mask[8] = {8, 1, 4, 2, 8, 2, 4, 1}; static const uint8 kSoldierB_NextB2[8] = {1, 2, 3, 0, 5, 6, 7, 4}; static const uint8 kSoldierB_NextB[8] = {3, 0, 1, 2, 7, 4, 5, 6}; static const uint8 kSoldier_HeadDirs[32] = { 0, 2, 2, 2, 0, 3, 3, 3, 1, 3, 3, 3, 1, 2, 2, 2, 2, 0, 0, 0, 2, 1, 1, 1, 3, 1, 1, 1, 3, 0, 0, 0, }; static const uint8 kSoldier_Tab1[4] = {13, 13, 12, 12}; static const uint8 kSoldier_DrawShadow[4] = {0xc, 0xc, 0xa, 0xa}; static const int8 kSoldier_SetTowardsVel[6] = {14, -14, 0, 0, 14, -14}; static const uint8 kSprite_SpawnProbeStaggered_Tab[4] = {0x10, 0x30, 0, 0x20}; static const int8 kSpawnProbe_Xvel[64] = { -16, -16, -16, -16, -16, -16, -16, -16, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 14, 12, 10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -12, -14, -16, -16, -16, -16, -16, -16, -16, -16, -16, }; static const int8 kSpawnProbe_Yvel[64] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 14, 12, 10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -12, -14, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -14, -12, -10, -8, -6, -4, -2, 0, }; int ctr; bool foo = false; static const uint8 kChainBallTrooper_Tab1[4] = {0x0d, 0x60, 0x22, 0x10}; // wtf static const uint8 kFlailTrooperGfx[32] = { 0x10, 0x11, 0x12, 0x13, 0x10, 0x11, 0x12, 0x13, 6, 7, 8, 9, 6, 7, 8, 9, 0, 1, 2, 3, 0, 1, 4, 5, 0xa, 0xb, 0xc, 0xd, 0xa, 0xb, 0xe, 0xf, }; static const uint8 kJavelinTrooper_Tab2[64] = { 25, 25, 24, 24, 23, 23, 23, 23, 19, 19, 18, 18, 17, 17, 17, 17, 16, 16, 15, 15, 14, 14, 14, 14, 22, 22, 21, 21, 20, 20, 20, 20, 20, 20, 18, 18, 18, 16, 16, 16, 21, 21, 8, 8, 8, 6, 6, 6, 22, 22, 4, 4, 4, 3, 3, 3, 23, 23, 15, 15, 15, 11, 11, 11, }; static const int8 kSprite_Recruit_Xvel[8] = {12, -12, 0, 0, 18, -18, 0, 0}; static const int8 kSprite_Recruit_Yvel[8] = {0, 0, 0xc, -0xc, 0, 0, 0x12, -0x12}; static const int8 kSprite_Recruit_Gfx[8] = {0, 2, 4, 6, 1, 3, 5, 7}; static const uint8 kRecruit_Moving_HeadDir[8] = {2, 3, 2, 3, 0, 1, 0, 1}; static const int16 kRecruit_Draw_X[8] = {2, 2, -2, -2, 0, 0, 0, 0}; static const uint8 kRecruit_Draw_Char[8] = {0x8a, 0x8c, 0x8a, 0x8c, 0x86, 0x88, 0x8e, 0xa0}; static const uint8 kRecruit_Draw_Flags[8] = {0x40, 0x40, 0, 0, 0, 0, 0, 0}; static const uint8 kSprite_Zora_SurfacingGfx[16] = {4, 3, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0}; static const uint8 kChainBallTrooperHead_Char[4] = {2, 2, 0, 4}; static const uint8 kChainBallTrooperHead_Flags[4] = {0x40, 0, 0, 0}; static const int8 kFlailTrooperBody_X[72] = { -4, 4, 12, -4, 4, 13, -4, 4, 13, -4, 4, 13, -4, 4, 13, -4, 4, 13, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 4, -4, 4, -6, -4, 4, -5, -4, 4, -5, -4, 4, -6, -4, 4, -5, -4, 4, -6, 0, 0, 4, 0, 0, 3, 0, 0, 2, 0, 0, 4, 0, 0, 0, 0, 0, 0, -4, 4, 4, -4, 4, 4, }; static const int8 kFlailTrooperBody_Y[72] = { 0, 0, -4, 0, 0, -4, 0, 0, -3, 0, 0, -2, 0, 0, -3, 0, 0, -2, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, 0, 2, 0, 0, -2, 0, 0, -2, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const uint8 kFlailTrooperBody_Char[72] = { 0x46, 6, 0x2f, 0x46, 6, 0x2f, 0x48, 0xd, 0x2f, 0x48, 0xd, 0x2f, 0x49, 0xc, 0x2f, 0x49, 0xc, 0x2f, 8, 8, 0x2f, 8, 8, 0x2f, 0x22, 0x22, 0x2f, 0x22, 0x22, 0x2f, 0xa, 0x64, 0x2f, 0xa, 0x64, 0x2f, 0x2c, 0x67, 0x2f, 0x2c, 0x67, 0x2f, 0x2d, 0x66, 0x2f, 0x2d, 0x66, 0x2f, 8, 8, 0x2f, 8, 8, 0x2f, 0x22, 0x22, 0x2f, 0x22, 0x22, 0x2f, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x46, 0x4b, 0x4b, 0x69, 0x64, 0x64, }; static const uint8 kFlailTrooperBody_Flags[72] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0, 0x40, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0, 0x40, 0x40, 0, 0, 0x40, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0, 0x40, 0x40, 0, 0x40, 0x40, }; static const uint8 kFlailTrooperBody_Ext[72] = { 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, }; static const uint8 kFlailTrooperBody_Num[24] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, }; static const uint8 kFlailTrooperBody_SprOffs[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, }; const uint16 kSinusLookupTable[256] = { 0, 3, 6, 9, 12, 15, 18, 21, 25, 28, 31, 34, 37, 40, 40, 46, 49, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 97, 100, 103, 106, 109, 112, 115, 117, 120, 123, 126, 128, 131, 134, 136, 139, 142, 144, 147, 149, 152, 155, 157, 159, 162, 164, 167, 169, 171, 174, 176, 178, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 212, 214, 216, 217, 219, 221, 222, 224, 225, 227, 228, 230, 231, 232, 234, 235, 236, 237, 238, 239, 241, 242, 243, 244, 244, 245, 246, 247, 248, 249, 249, 250, 251, 251, 252, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 256, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 252, 251, 251, 250, 249, 249, 248, 247, 246, 245, 244, 244, 243, 242, 241, 239, 238, 237, 236, 235, 234, 232, 231, 230, 228, 227, 225, 224, 222, 221, 219, 217, 216, 214, 212, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 191, 189, 187, 185, 183, 181, 178, 176, 174, 171, 169, 167, 164, 162, 159, 157, 155, 152, 149, 147, 144, 142, 139, 136, 134, 131, 128, 126, 123, 120, 117, 115, 112, 109, 106, 103, 100, 97, 95, 92, 89, 86, 83, 80, 77, 74, 71, 68, 65, 62, 59, 56, 53, 49, 46, 43, 40, 37, 34, 31, 28, 25, 21, 18, 15, 12, 9, 6, 3, }; static const uint8 kFlailTrooperWeapon_Tab4[4] = {0x33, 0x66, 0x99, 0xcc}; static const uint8 kFlailTrooperWeapon_Tab0[32] = { 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1e, 0x1c, 0x1a, 0x18, 0x16, 0x14, 0x12, }; static const int8 kFlailTrooperWeapon_Tab1[4] = {4, 4, 12, -5}; static const int8 kFlailTrooperWeapon_Tab2[4] = {-2, -2, -6, -4}; static const uint8 kFlailTrooperAttackDir[4] = {3, 1, 2, 0}; static const uint8 kSprite_WarpVortex_Flags[4] = {0, 0x40, 0xc0, 0x80}; static const int8 kSpriteRope_Gfx[8] = {0, 0, 2, 3, 2, 3, 1, 1}; static const int8 kSpriteRope_Flags[8] = {0, 0x40, 0, 0, 0x40, 0x40, 0, 0x40}; static const int8 kSpriteRope_Tab1[8] = {4, 5, 2, 3, 0, 1, 6, 7}; static const int8 kSpriteRope_Xvel[8] = {8, -8, 0, 0, 16, -16, 0, 0}; static const int8 kSpriteRope_Yvel[8] = {0, 0, 8, -8, 0, 0, 0x10, -0x10}; static const int8 kSpriteRope_Tab0[4] = {2, 3, 1, 0}; static const uint8 kSpawnBee_InitDelay[4] = {64, 64, 255, 255}; static const int8 kSpawnBee_InitVel[8] = {15, 5, -5, -15, 20, 10, -10, -20}; static const DrawMultipleData kLargeShadow_Dmd[15] = { {-6, 19, 0x086c, 2}, { 0, 19, 0x086c, 2}, { 6, 19, 0x086c, 2}, {-5, 19, 0x086c, 2}, { 0, 19, 0x086c, 2}, { 5, 19, 0x086c, 2}, {-4, 19, 0x086c, 2}, { 0, 19, 0x086c, 2}, { 4, 19, 0x086c, 2}, {-3, 19, 0x086c, 2}, { 0, 19, 0x086c, 2}, { 3, 19, 0x086c, 2}, {-2, 19, 0x086c, 2}, { 0, 19, 0x086c, 2}, { 2, 19, 0x086c, 2}, }; static const uint8 kHelmasaur_Tab0[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 5, 4, 3, 2, 1, }; static const uint8 kFluteBoyAnimal_OamFlags[2] = {0x40, 0}; static const uint8 kFluteBoyAnimal_Gfx[3] = {0, 1, 2}; static const uint8 kGibo_OamFlags[4] = {0, 0x40, 0xc0, 0x80}; static const uint8 kGibo_OamFlags2[2] = {11, 7}; #define chainchomp_x_hist ((uint16*)(g_ram+0x1FC00)) #define chainchomp_y_hist ((uint16*)(g_ram+0x1FD00)) static const uint8 kBlindHead_Draw_Char[16] = {0x86, 0x86, 0x84, 0x82, 0x80, 0x82, 0x84, 0x86, 0x86, 0x86, 0x88, 0x8a, 0x8c, 0x8a, 0x88, 0x86}; static const uint8 kBlindHead_Draw_Flags[16] = {0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0}; static const uint8 kGanon_G_Func2[16] = { 8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1 }; static const int8 kGanon_Draw_X[204] = { 18, -8, 8, -8, 8, -18, -18, 18, -8, 8, -8, 8, 18, -8, 8, -8, 8, -18, -18, 18, -8, 8, -8, 8, 16, -8, 8, -8, 8, -18, -18, 16, -8, 8, -11, 11, 16, -8, 8, -8, 8, -18, -18, 16, -8, 8, -11, 11, 16, -8, 8, -8, 8, -18, -18, 16, -8, 8, -11, 11, 18, -8, 8, -8, 8, -18, -18, 18, -8, 8, -8, 8, 18, -8, 8, -8, 8, -18, -18, 18, -8, 8, -8, 8, 18, -8, 8, -8, 8, -18, -18, 18, -8, 8, -11, 11, -8, 8, -8, 8, -8, 8, -8, 8, -18, -18, 18, 18, -8, 8, -8, 8, -8, 8, -8, 8, -18, -18, 18, 18, -8, 8, -8, 8, -8, 8, -10, 10, -18, -18, 18, 18, -8, 8, -8, 8, -8, 8, -10, 10, -18, -18, 18, 18, -8, 8, -8, 8, -8, 8, -10, 10, -18, -18, 18, 18, -8, 8, -8, 8, -8, 8, -8, 8, -18, -18, 18, 18, -8, 8, -8, 8, -8, 8, -8, 8, -18, -18, 18, 18, -7, -8, 8, -8, 8, -9, 8, -14, -14, -8, 8, 8, -8, 8, -8, 8, -18, -18, 18, 18, -8, 8, -11, 11, }; static const int8 kGanon_Draw_Y[204] = { -8, -16, -16, -13, -13, -9, -1, -16, 3, 3, 8, 8, -8, -16, -16, -13, -13, -9, -1, -16, 3, 3, 8, 8, 5, -10, -10, -13, -13, -7, 1, -3, 3, 3, 8, 8, 5, -10, -10, -13, -13, -7, 1, -3, 3, 3, 8, 8, 5, -10, -10, -13, -13, -7, 1, -3, 3, 3, 8, 8, -1, -16, -16, -13, -13, -9, -1, -9, 3, 3, 8, 8, -10, -16, -16, -13, -13, -18, -10, -18, 3, 3, 8, 8, 1, -10, -10, -13, -13, -7, 1, -7, 3, 3, 8, 8, -12, -12, 4, 4, -18, -18, 10, 10, -16, -8, -4, 4, -12, -12, 4, 4, -18, -18, 10, 10, -16, -8, -4, 4, -12, -12, 4, 4, -12, -12, 10, 10, -4, 4, -4, 4, -12, -12, 4, 4, -12, -12, 10, 10, -4, 4, -4, 4, -12, -12, 4, 4, -12, -12, 10, 10, -4, 4, -4, 4, -12, -12, 4, 4, -18, -18, 10, 10, -4, 4, -4, 4, -12, -12, 4, 4, -18, -18, 10, 10, -16, -8, -16, -8, -7, -12, -12, 4, 4, 7, 13, -11, -4, -16, -16, -16, -10, -10, -13, -13, -7, -7, -7, -7, 3, 3, 8, 8, }; static const uint8 kGanon_Draw_Char[204] = { 0x16, 0, 0, 2, 2, 8, 0x18, 6, 0x22, 0x22, 0x20, 0x20, 0x46, 0, 0, 2, 2, 8, 0x18, 0x36, 0x22, 0x22, 0x20, 0x20, 0x1a, 0, 0, 4, 4, 0x38, 0x48, 0xa, 0x24, 0x24, 0x20, 0x20, 0x1a, 0x40, 0x42, 4, 4, 0x38, 0x48, 0xa, 0x24, 0x24, 0x20, 0x20, 0x1a, 0x42, 0x40, 4, 4, 0x38, 0x48, 0xa, 0x24, 0x24, 0x20, 0x20, 0x18, 0, 0, 2, 2, 8, 0x18, 8, 0x22, 0x22, 0x20, 0x20, 0x16, 0x6a, 0x6a, 0xe, 0xe, 6, 0x16, 6, 0x22, 0x22, 0x20, 0x20, 0x48, 0, 0, 4, 4, 0x38, 0x48, 0x38, 0x24, 0x24, 0x20, 0x20, 0x4e, 0x4e, 0x6e, 0x6e, 0x6c, 0x6c, 0xa2, 0xa2, 0xc, 0x1c, 0x3c, 0x4c, 0x4e, 0x4e, 0x6e, 0x6e, 0x6c, 0x6c, 0xa2, 0xa2, 0x3a, 0x4a, 0x3c, 0x4c, 0x84, 0x84, 0xa4, 0xa4, 0xa0, 0xa0, 0xa2, 0xa2, 0x3c, 0x4c, 0x3c, 0x4c, 0x84, 0x84, 0xa4, 0xa4, 0x80, 0x82, 0xa2, 0xa2, 0x3c, 0x4c, 0x3c, 0x4c, 0x84, 0x84, 0xa4, 0xa4, 0x82, 0x80, 0xa2, 0xa2, 0x3c, 0x4c, 0x3c, 0x4c, 0x4e, 0x4e, 0x6e, 0x6e, 0x6c, 0x6c, 0xa2, 0xa2, 0x3c, 0x4c, 0x3c, 0x4c, 0x4e, 0x4e, 0x6e, 0x6e, 0x6c, 0x6c, 0xa2, 0xa2, 0xc, 0x1c, 0xc, 0x1c, 0xe0, 0xc6, 0xc8, 0xe6, 0xe8, 0x20, 0x20, 8, 0x18, 0xc0, 0xc2, 0xc2, 0, 0, 0xce, 0xce, 0xec, 0xec, 0xec, 0xec, 0xee, 0xee, 0xc4, 0xc4, }; static const uint8 kGanon_Draw_Flags[204] = { 0x4c, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0x4c, 0x4c, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0x4c, 0x4c, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0x4c, 0x4c, 0xc, 0xc, 0xa, 0x4a, 0xc, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0x4c, 0x4c, 0x4c, 0x4c, 0xa, 0x4a, 0xc, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0x4c, 0x4c, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0x4c, 0x4c, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0x4c, 0x4c, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0x4c, 0xa, 0x4a, 0xa, 0x4a, 0xc, 0x4c, 0xc, 0x4c, 0xc, 0xc, 0x4c, 0x4c, 0xa, 0x4a, 0xa, 0x4a, 0xc, 0x4c, 0xc, 0x4c, 0xc, 0xc, 0x4c, 0x4c, 0xa, 0x4a, 0xa, 0x4a, 0xc, 0x4c, 0xc, 0x4c, 0xc, 0xc, 0x4c, 0x4c, 0xa, 0x4a, 0xa, 0x4a, 0xc, 0xc, 0xc, 0x4c, 0xc, 0xc, 0x4c, 0x4c, 0xa, 0x4a, 0xa, 0x4a, 0x4c, 0x4c, 0xc, 0x4c, 0xc, 0xc, 0x4c, 0x4c, 0xa, 0x4a, 0xa, 0x4a, 0xc, 0x4c, 0xc, 0x4c, 0xc, 0xc, 0x4c, 0x4c, 0xa, 0x4a, 0xa, 0x4a, 0xc, 0x4c, 0xc, 0x4c, 0xc, 0xc, 0x4c, 0x4c, 0xc, 0xa, 0xa, 0xa, 0xa, 0xc, 0x4c, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0x4c, 0xa, 0x4a, 0xc, 0xc, 0x4c, 0x4c, 0xa, 0x4a, 0xc, 0x4c, }; static const uint8 kGanon_Draw_Char2[12] = { 0x40, 0x42, 0, 0, 0x42, 0x40, 0x82, 0x80, 0xa0, 0xa0, 0x80, 0x82 }; static const uint8 kGanon_Draw_Flags2[12] = { 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0x40, 0, 0 }; static HandlerFuncK *const kSpriteActiveRoutines[243] = { &Sprite_Raven, &Sprite_01_Vulture_bounce, &Sprite_02_StalfosHead, NULL, &Sprite_PullSwitch_bounce, &Sprite_PullSwitch_bounce, &Sprite_PullSwitch_bounce, &Sprite_PullSwitch_bounce, &Sprite_08_Octorok, &Sprite_09_Moldorm_bounce, &Sprite_08_Octorok, &Sprite_0B_Cucco, &Sprite_0C_OctorokStone, &Sprite_0D_Buzzblob, &Sprite_0E_Snapdragon, &Sprite_0F_Octoballoon, &Sprite_10_OctoballoonBaby, &Sprite_11_Hinox, &Sprite_12_Moblin, &Sprite_13_MiniHelmasaur, &Sprite_14_ThievesTownGrate_bounce, &Sprite_15_Antifairy, &Sprite_16_Elder_bounce, &Sprite_17_Hoarder, &Sprite_18_MiniMoldorm, &Sprite_19_Poe, &Sprite_1A_Smithy, &Sprite_1B_Arrow, &Sprite_1C_Statue, &Sprite_1D_FluteQuest, &Sprite_1E_CrystalSwitch, &Sprite_1F_SickKid, &Sprite_20_Sluggula, &Sprite_21_WaterSwitch, &Sprite_22_Ropa, &Sprite_23_RedBari, &Sprite_23_RedBari, &Sprite_25_TalkingTree_bounce, &Sprite_26_HardhatBeetle, &Sprite_27_Deadrock, &Sprite_28_DarkWorldHintNPC, &Sprite_HumanMulti_1, &Sprite_SweepingLady, &Sprite_2B_Hobo, &Sprite_Lumberjacks, &Sprite_2D_TelepathicTile_bounce, &Sprite_2E_FluteKid, &Sprite_MazeGameLady, &Sprite_MazeGameGuy, &Sprite_FortuneTeller, &Sprite_QuarrelBros, &Sprite_33_RupeePull_bounce, &Sprite_YoungSnitchLady, &Sprite_InnKeeper, &Sprite_Witch, &Sprite_37_Waterfall_bounce, &Sprite_38_EyeStatue_bounce, &Sprite_39_Locksmith, &Sprite_3A_MagicBat_bounce, &Sprite_DashItem, &Sprite_TroughBoy, &Sprite_OldSnitchLady, &Sprite_17_Hoarder, &Sprite_TutorialGuardOrBarrier_bounce, &Sprite_TutorialGuardOrBarrier_bounce, // Trampoline 48 entries &Sprite_41_BlueGuard, &Sprite_41_BlueGuard, &Sprite_41_BlueGuard, &Sprite_44_BluesainBolt, &Sprite_45_UsainBolt, &Sprite_46_BlueArcher, &Sprite_47_GreenBushGuard, &Sprite_48_RedJavelinGuard, &Sprite_49_RedBushGuard, &Sprite_4A_BombGuard, &Sprite_4B_GreenKnifeGuard, &Sprite_4C_Geldman, &Sprite_4D_Toppo, &Sprite_4E_Popo, &Sprite_4E_Popo, &Sprite_50_Cannonball, &Sprite_51_ArmosStatue, &Sprite_52_KingZora, &Sprite_53_ArmosKnight, &Sprite_54_Lanmolas, &Sprite_55_Zora, &Sprite_56_WalkingZora, &Sprite_57_DesertStatue, &Sprite_58_Crab, &Sprite_59_LostWoodsBird, &Sprite_5A_LostWoodsSquirrel, &Sprite_5B_Spark_Clockwise, &Sprite_5B_Spark_Clockwise, &Sprite_5D_Roller_VerticalDownFirst, &Sprite_5D_Roller_VerticalDownFirst, &Sprite_5D_Roller_VerticalDownFirst, &Sprite_5D_Roller_VerticalDownFirst, &Sprite_61_Beamos, &Sprite_62_MasterSword, &Sprite_63_DebirandoPit, &Sprite_64_Debirando, &Sprite_65_ArcheryGame, &Sprite_66_WallCannonVerticalLeft, &Sprite_66_WallCannonVerticalLeft, &Sprite_66_WallCannonVerticalLeft, &Sprite_66_WallCannonVerticalLeft, &Sprite_6A_BallNChain, &Sprite_CannonTrooper, &Sprite_6C_MirrorPortal, &Sprite_6D_Rat, &Sprite_6E_Rope, &Sprite_6F_Keese, &Sprite_70_KingHelmasaurFireball_bounce, &Sprite_71_Leever, &Sprite_72_FairyPond, &Sprite_73_UncleAndPriest_bounce, &Sprite_RunningMan, &Sprite_BottleVendor, &Sprite_76_Zelda, &Sprite_15_Antifairy, &Sprite_78_MrsSahasrahla_bounce, // Trampoline 68 entries &Sprite_79_Bee, &Sprite_7A_Agahnim, &Sprite_7B_AgahnimBalls, &Sprite_7C_GreenStalfos, &Sprite_7D_BigSpike, &Sprite_7E_Firebar_Clockwise, &Sprite_7E_Firebar_Clockwise, &Sprite_80_Firesnake, &Sprite_81_Hover, &Sprite_82_AntifairyCircle, &Sprite_83_GreenEyegore, &Sprite_83_GreenEyegore, &Sprite_85_YellowStalfos, &Sprite_86_Kodongo, &Sprite_87_KodongoFire, &Sprite_88_Mothula, &Sprite_89_MothulaBeam, &Sprite_8A_SpikeBlock, &Sprite_8B_Gibdo, &Sprite_8C_Arrghus, &Sprite_8D_Arrghi, &Sprite_8E_Terrorpin, &Sprite_8F_Blob, &Sprite_90_Wallmaster, &Sprite_91_StalfosKnight, &Sprite_92_HelmasaurKing, &Sprite_93_Bumper, &Sprite_94_Pirogusu, &Sprite_95_LaserEyeLeft, &Sprite_95_LaserEyeLeft, &Sprite_95_LaserEyeLeft, &Sprite_95_LaserEyeLeft, &Sprite_99_Pengator, &Sprite_9A_Kyameron, &Sprite_9B_Wizzrobe, &Sprite_9C_Zoro, &Sprite_9C_Zoro, &Sprite_9E_HauntedGroveOstritch, &Sprite_9F_HauntedGroveRabbit, &Sprite_A0_HauntedGroveBird, &Sprite_A1_Freezor, &Sprite_A2_Kholdstare, &Sprite_A3_KholdstareShell, &Sprite_A4_FallingIce, &Sprite_Zazak_Main, &Sprite_Zazak_Main, &Sprite_A7_Stalfos, &Sprite_A8_GreenZirro, &Sprite_A8_GreenZirro, &Sprite_AA_Pikit, &Sprite_AB_CrystalMaiden, &Sprite_AC_Apple, &Sprite_AD_OldMan, &Sprite_AE_Pipe_Down, &Sprite_AE_Pipe_Down, &Sprite_AE_Pipe_Down, &Sprite_AE_Pipe_Down, &Sprite_B2_PlayerBee, &Sprite_B3_PedestalPlaque, &Sprite_B4_PurpleChest, &Sprite_B5_BombShop, &Sprite_B6_Kiki, &Sprite_B7_BlindMaiden, &Sprite_B8_DialogueTester, &Sprite_B9_BullyAndPinkBall, &Sprite_BA_Whirlpool, &Sprite_BB_Shopkeeper, &Sprite_BC_Drunkard, // Trampoline 4, starts at 187, 27 entries &Sprite_BD_Vitreous, &Sprite_BE_VitreousEye, &Sprite_BF_Lightning, &Sprite_C0_Catfish, &Sprite_C1_CutsceneAgahnim, &Sprite_C2_Boulder, &Sprite_C3_Gibo, &Sprite_C4_Thief, &Sprite_C5_Medusa, &Sprite_C6_4WayShooter, &Sprite_C7_Pokey, &Sprite_C8_BigFairy, &Sprite_C9_Tektite, &Sprite_CA_ChainChomp, &Sprite_CB_TrinexxRockHead, &Sprite_CC, &Sprite_CD, &Sprite_CE_Blind, &Sprite_CF_Swamola, &Sprite_D0_Lynel, &Sprite_D1_BunnyBeam, &Sprite_D2_FloppingFish, &Sprite_D3_Stal, &Sprite_D4_Landmine, &Sprite_D5_DigGameGuy, &Sprite_D6_Ganon, &Sprite_D6_Ganon, &Sprite_D8_Heart, &Sprite_D9_GreenRupee, &Sprite_D9_GreenRupee, &Sprite_D9_GreenRupee, &Sprite_D9_GreenRupee, &Sprite_D9_GreenRupee, &Sprite_D9_GreenRupee, &Sprite_D9_GreenRupee, &Sprite_D9_GreenRupee, &Sprite_D9_GreenRupee, &Sprite_D9_GreenRupee, &Sprite_E3_Fairy, &Sprite_E4_SmallKey, &Sprite_E4_SmallKey, &Sprite_D9_GreenRupee, &Sprite_Mushroom, &Sprite_FakeSword, &Sprite_PotionShop, &Sprite_HeartContainer, &Sprite_HeartPiece, &Sprite_EC_ThrownItem, &Sprite_SomariaPlatform, &Sprite_MovableMantleTrampoline, &Sprite_SomariaPlatform, &Sprite_SomariaPlatform, &Sprite_SomariaPlatform, &Sprite_F2_MedallionTablet_bounce, }; static HandlerFuncK *const kSpritePrep_Main[243] = { &SpritePrep_Raven, &SpritePrep_Vulture, &SpritePrep_DoNothingA, NULL, &SpritePrep_Switch, &SpritePrep_DoNothingA, &SpritePrep_Switch, &SpritePrep_SwitchFacingUp, &SpritePrep_Octorok, &SpritePrep_Moldorm_bounce, &SpritePrep_Octorok, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_Octoballoon, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_MiniHelmasaur, &SpritePrep_ThievesTownGrate, &SpritePrep_Antifairy, &SpritePrep_Sage, &SpritePrep_DoNothingA, &SpritePrep_MiniMoldorm_bounce, &SpritePrep_Poe, &SpritePrep_Smithy, &SpritePrep_DoNothingA, &SpritePrep_Statue, &SpritePrep_IgnoreProjectiles, &SpritePrep_CrystalSwitch, &SpritePrep_SickKid, &SpritePrep_DoNothingA, &SpritePrep_WaterLever, &SpritePrep_DoNothingA, &SpritePrep_Bari, &SpritePrep_Bari, &SpritePrep_TalkingTree, &SpritePrep_HardhatBeetle, &SpritePrep_DoNothingA, &SpritePrep_Storyteller, &SpritePrep_Adults, &SpritePrep_IgnoreProjectiles, &SpritePrep_Hobo, &SpritePrep_MagicBat, &SpritePrep_IgnoreProjectiles, &SpritePrep_FluteKid, &SpritePrep_IgnoreProjectiles, &SpritePrep_IgnoreProjectiles, &SpritePrep_FortuneTeller, &SpritePrep_IgnoreProjectiles, &SpritePrep_RupeePull, &SpritePrep_Snitch_bounce_2, &SpritePrep_Snitch_bounce_3, &SpritePrep_IgnoreProjectiles, &SpritePrep_IgnoreProjectiles, &SpritePrep_DoNothingA, &SpritePrep_Locksmith, &SpritePrep_MagicBat, &SpritePrep_BonkItem, &SpritePrep_IgnoreProjectiles, &SpritePrep_Snitch_bounce_1, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_AgahnimsBarrier, &SpritePrep_StandardGuard, &SpritePrep_StandardGuard, &SpritePrep_StandardGuard, &SpritePrep_TrooperAndArcherSoldier, &SpritePrep_TrooperAndArcherSoldier, &SpritePrep_TrooperAndArcherSoldier, &SpritePrep_TrooperAndArcherSoldier, &SpritePrep_TrooperAndArcherSoldier, &SpritePrep_TrooperAndArcherSoldier, &SpritePrep_TrooperAndArcherSoldier, &SpritePrep_WeakGuard, &SpritePrep_Geldman, &SpritePrep_Kyameron, &SpritePrep_Popo, &SpritePrep_Popo2, &SpritePrep_DoNothingA, &SpritePrep_DoNothingD, &SpritePrep_KingZora, &SpritePrep_ArmosKnight, &SpritePrep_Lanmolas_bounce, &SpritePrep_SwimmingZora, &SpritePrep_WalkingZora, &SpritePrep_DesertStatue, &SpritePrep_DoNothingA, &SpritePrep_LostWoodsBird, &SpritePrep_LostWoodsSquirrel, &SpritePrep_Spark, &SpritePrep_Spark, &SpritePrep_Roller_VerticalDownFirst, &SpritePrep_RollerUpDown, &SpritePrep_Roller_HorizontalRightFirst, &SpritePrep_RollerLeftRight, &SpritePrep_DoNothingA, &SpritePrep_MasterSword, &SpritePrep_DebirandoPit, &SpritePrep_FireDebirando, &SpritePrep_ArrowGame_bounce, &SpritePrep_WallCannon, &SpritePrep_WallCannon, &SpritePrep_WallCannon, &SpritePrep_WallCannon, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_Rat, &SpritePrep_Rope, &SpritePrep_Keese, &SpritePrep_DoNothingG, &SpritePrep_FairyPond, &SpritePrep_IgnoreProjectiles, &SpritePrep_UncleAndPriest_bounce, &SpritePrep_RunningMan, &SpritePrep_IgnoreProjectiles, &SpritePrep_Zelda_bounce, &SpritePrep_Antifairy, &SpritePrep_MrsSahasrahla, &SpritePrep_OverworldBonkItem, &SpritePrep_Agahnim, &SpritePrep_DoNothingG, &SpritePrep_GreenStalfos, &SpritePrep_BigSpike, &SpritePrep_FireBar, &SpritePrep_FireBar, &SpritePrep_DoNothingG, &SpritePrep_DoNothingG, &SpritePrep_AntifairyCircle, &SpritePrep_Eyegore, &SpritePrep_Eyegore, &SpritePrep_DoNothingG, &SpritePrep_Kodongo, &SpritePrep_DoNothingG, &SpritePrep_Mothula, &SpritePrep_DoNothingG, &SpritePrep_Spike, &SpritePrep_DoNothingG, &SpritePrep_Arrghus, &SpritePrep_Arrghi, &SpritePrep_DoNothingG, &SpritePrep_Blob, &SpritePrep_DoNothingG, &SpritePrep_DoNothingG, &SpritePrep_HelmasaurKing, &SpritePrep_Bumper, &SpritePrep_DoNothingA, &SpritePrep_LaserEye_bounce, &SpritePrep_LaserEye_bounce, &SpritePrep_LaserEye_bounce, &SpritePrep_LaserEye_bounce, &SpritePrep_DoNothingA, &SpritePrep_Kyameron, &SpritePrep_DoNothingA, &SpritePrep_Zoro, &SpritePrep_Babasu, &SpritePrep_HauntedGroveOstritch, &SpritePrep_HauntedGroveAnimal, &SpritePrep_HauntedGroveAnimal, &SpritePrep_MoveDown_8px, &SpritePrep_Kholdstare, &SpritePrep_KholdstareShell, &SpritePrep_FallingIce, &SpritePrep_Zazakku, &SpritePrep_Zazakku, &SpritePrep_Stalfos, &SpritePrep_Bomber, &SpritePrep_Bomber, &SpritePrep_DoNothingC, &SpritePrep_DoNothingH, &SpritePrep_OverworldBonkItem, &SpritePrep_OldMan_bounce, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_NiceBee, &SpritePrep_PedestalPlaque, &SpritePrep_PurpleChest, &SpritePrep_BombShoppe, &SpritePrep_Kiki, &SpritePrep_BlindMaiden, &SpritePrep_DoNothingA, &SpritePrep_BullyAndVictim, &SpritePrep_Whirlpool, &SpritePrep_Shopkeeper, &SpritePrep_IgnoreProjectiles, &SpritePrep_Vitreous, &SpritePrep_MiniVitreous, &SpritePrep_DoNothingA, &SpritePrep_Catfish, &SpritePrep_CutsceneAgahnim, &SpritePrep_DoNothingA, &SpritePrep_Gibo, &SpritePrep_DoNothingA, &SpritePrep_IgnoreProjectiles, &SpritePrep_IgnoreProjectiles, &SpritePrep_Pokey, &SpritePrep_BigFairy, &SpritePrep_Tektite, &SpritePrep_Chainchomp_bounce, &SpritePrep_Trinexx, &SpritePrep_Trinexx, &SpritePrep_Trinexx, &SpritePrep_Blind, &SpritePrep_Swamola, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_IgnoreProjectiles, &SpritePrep_RockStal, &SpritePrep_IgnoreProjectiles, &SpritePrep_DiggingGameGuy_bounce, &SpritePrep_Ganon, &SpritePrep_Ganon, &SpritePrep_Absorbable, &SpritePrep_Absorbable, &SpritePrep_Absorbable, &SpritePrep_Absorbable, &SpritePrep_Absorbable, &SpritePrep_Absorbable, &SpritePrep_Absorbable, &SpritePrep_Absorbable, &SpritePrep_Absorbable, &SpritePrep_Absorbable, &SpritePrep_Absorbable, &SpritePrep_Fairy, &SpritePrep_SmallKey, &SpritePrep_BigKey, &SpritePrep_ShieldPickup, &SpritePrep_Mushroom, &SpritePrep_FakeSword, &SpritePrep_PotionShop, &SpritePrep_HeartContainer, &SpritePrep_HeartPiece, &SpritePrep_ThrowableScenery, &SpritePrep_DoNothingA, &SpritePrep_Mantle, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_DoNothingA, &SpritePrep_MedallionTable, }; static inline uint8 ChainBallMult(uint16 a, uint8 b); static inline uint8 GuruguruBarMult(uint16 a, uint8 b); static inline int8 GuruguruBarSin(uint16 a, uint8 b); static inline uint8 ArrgiMult(uint16 a, uint8 b); static inline int8 ArrgiSin(uint16 a, uint8 b); static inline uint8 HelmasaurMult(uint16 a, uint8 b); static inline int8 HelmasaurSin(uint16 a, uint8 b); static inline uint8 TrinexxMult(uint8 a, uint8 b); static inline uint8 TrinexxHeadMult(uint16 a, uint8 b); static inline int8 TrinexxHeadSin(uint16 a, uint8 b); static inline uint8 GanonMult(uint16 a, uint8 b); static inline int8 GanonSin(uint16 a, uint8 b); void Sprite_PullSwitch_bounce(int k) { if (sprite_type[k] == 5 || sprite_type[k] == 7) PullSwitch_FacingUp(k); else PullSwitch_FacingDown(k); } void GiantMoldorm_DrawSegment_AB(int k, int lookback) { static const DrawMultipleData kGiantMoldorm_SegA_Dmd[8] = { {-8, -8, 0x0084, 2}, { 8, -8, 0x0086, 2}, {-8, 8, 0x00a4, 2}, { 8, 8, 0x00a6, 2}, {-8, -8, 0x4086, 2}, { 8, -8, 0x4084, 2}, {-8, 8, 0x40a6, 2}, { 8, 8, 0x40a4, 2}, }; int j = sprite_subtype2[k] - lookback & 0x7f; cur_sprite_x = moldorm_x_lo[j] | moldorm_x_hi[j] << 8; cur_sprite_y = moldorm_y_lo[j] | moldorm_y_hi[j] << 8; oam_cur_ptr += 0x10; oam_ext_cur_ptr += 4; Sprite_DrawMultiple(k, &kGiantMoldorm_SegA_Dmd[(sprite_subtype2[k] >> 1 & 1) * 4], 4, NULL); } void GiantMoldorm_DrawSegment_C_OrTail(int k, int lookback) { static const uint8 kGiantMoldorm_OamFlags[4] = {0, 0x40, 0xc0, 0x80}; int j = sprite_subtype2[k] - lookback & 0x7f; cur_sprite_x = moldorm_x_lo[j] | moldorm_x_hi[j] << 8; cur_sprite_y = moldorm_y_lo[j] | moldorm_y_hi[j] << 8; uint8 bak = sprite_oam_flags[k]; sprite_oam_flags[k] = (bak & 0x3f) | kGiantMoldorm_OamFlags[sprite_subtype2[k] >> 1 & 3]; SpriteDraw_SingleLarge(k); sprite_oam_flags[k] = bak; } void Chicken_IncrSubtype2(int k, int j) { sprite_subtype2[k] += j; sprite_graphics[k] = (sprite_subtype2[k] >> 4) & 1; Sprite_ReturnIfLifted(k); } bool Octoballoon_Find() { for (int i = 15; i >= 0; i--) { if (sprite_state[i] && sprite_type[i] == 0x10) return true; } return false; } bool FluteBoy_CheckIfPlayerClose(int k) { int xx = Sprite_GetX(k); int yy = Sprite_GetY(k) - 16; int x = link_x_coord - xx - (yy < 0); // zelda bug: carry int y = link_y_coord - yy - (x < 0); if (sign16(x)) x = ~x; if (sign16(y)) y = ~y; return (uint16)x < 48 && (uint16)y < 48; } void FortuneTeller_LightOrDarkWorld(int k, bool dark_world) { int j; static const uint8 kFortuneTeller_Prices[4] = {10, 15, 20, 30}; switch (sprite_ai_state[k]) { case 0: // WaitForInquiry sprite_graphics[k] = 0; sprite_A[k] = (j = (GetRandomNumber() & 3)) << 1; if (link_rupees_goal < kFortuneTeller_Prices[j]) sprite_ai_state[k] = 1; else sprite_ai_state[k] = 2; break; case 1: // NotEnoughRupees Sprite_ShowSolicitedMessage(k, 0xf2); break; case 2: // AskIfPlayerWantsReading if (Sprite_ShowSolicitedMessage(k, 0xf3) & 0x100) { sprite_delay_main[k] = 255; flag_is_link_immobilized = 1; sprite_ai_state[k]=3; } break; case 3: // ReactToPlayerResponse if (!choice_in_multiselect_box) { if (!sprite_delay_main[k]) sprite_ai_state[k]++; sprite_graphics[k] = frame_counter >> 4 & 1; } else { Sprite_ShowMessageUnconditional(0xf5); sprite_ai_state[k] = 2; flag_is_link_immobilized = 0; } break; case 4: // FortuneTeller_PerformPseudoScience FortuneTeller_PerformPseudoScience(k); break; case 5: // ShowCostMessage if (!dark_world) sprite_graphics[k] = 0; j = kFortuneTeller_Prices[sprite_A[k]>>1]; byte_7E1CF2[0] = (j / 10) | (j % 10)<< 4 ; byte_7E1CF2[1] = 0; Sprite_ShowMessageUnconditional(0xf4); sprite_ai_state[k]++; break; case 6: // DeductPayment link_rupees_goal -= kFortuneTeller_Prices[sprite_A[k]>>1]; sprite_ai_state[k]++; link_hearts_filler = 160; flag_is_link_immobilized = 0; break; case 7: break; } } int GarnishAllocForce() { int k = 29; while (garnish_type[k--] && k >= 0) {} return k + 1; } int GarnishAlloc() { int k = 29; while (garnish_type[k] && k >= 0) k--; return k; } int GarnishAllocLow() { int k = 14; while (garnish_type[k] && k >= 0) k--; return k; } int GarnishAllocLimit(int k) { while (garnish_type[k] && k >= 0) k--; return k; } int GarnishAllocOverwriteOldLow() { int k = 14; while (garnish_type[k] && k >= 0) k--; if (k < 0) { if (sign8(--byte_7E0FF8)) byte_7E0FF8 = 14; k = byte_7E0FF8; } return k; } int GarnishAllocOverwriteOld() { int k = 29; while (garnish_type[k] && k >= 0) k--; if (k < 0) { if (sign8(--byte_7E0FF8)) byte_7E0FF8 = 29; k = byte_7E0FF8; } return k; } void Garnish_SetX(int k, uint16 x) { garnish_x_lo[k] = x; garnish_x_hi[k] = x >> 8; } void Garnish_SetY(int k, uint16 y) { garnish_y_lo[k] = y; garnish_y_hi[k] = y >> 8; } void Sprite_WishPond3(int k) { int j; switch (sprite_ai_state[k]) { case 0: flag_is_link_immobilized = 0; if (sprite_delay_main[k] || Sprite_CheckIfLinkIsBusy()) return; if (Sprite_ShowMessageOnContact(k, 0x14a) & 0x100) { sprite_ai_state[k] = 1; Link_ResetProperties_A(); link_direction_facing = 0; sprite_head_dir[k] = 0; } break; case 1: if (!choice_in_multiselect_box) { Sprite_ShowMessageUnconditional(0x8a); sprite_ai_state[k] = 2; flag_is_link_immobilized = 1; } else { Sprite_ShowMessageUnconditional(0x14b); sprite_ai_state[k] = 0; sprite_delay_main[k] = 255; } break; case 2: { sprite_ai_state[k] = 3; j = choice_in_multiselect_box; sprite_C[k] = j; uint8 item = (&link_item_bow)[j]; (&link_item_bow)[j] = 0; uint8 t = kWishPondItemData[kWishPondItemOffs[j] + ((j == 3 || j == 32) ? 1 : item) - 1]; AncillaAdd_TossedPondItem(0x28, t, 4); Hud_RefreshIcon(); sprite_graphics[k] = t; sprite_D[k] = item; sprite_delay_main[k] = 255; break; } case 3: if (sprite_delay_main[k] == 0) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x72, &info); assert(j >= 0); Sprite_SetX(j, info.r0_x); Sprite_SetY(j, info.r2_y - 80); music_control = 0x1b; last_music_control = 0; sprite_B[j] = 1; Palette_AssertTranslucencySwap(); PaletteFilter_WishPonds(); sprite_E[k] = j; sprite_ai_state[k] = 4; sprite_delay_main[k] = 255; } break; case 4: if (!(frame_counter & 7)) { PaletteFilter_SP5F(); if (!BYTE(palette_filter_countdown)) { Sprite_ShowMessageUnconditional(0x8b); Palette_RevertTranslucencySwap(); TS_copy = 0; CGADSUB_copy = 0x20; flag_update_cgram_in_nmi++; sprite_ai_state[k] = 5; } } break; case 5: if (!choice_in_multiselect_box) { sprite_ai_state[k] = 6; } else { sprite_ai_state[k] = 11; } break; case 6: sprite_ai_state[k] = 7; if (!savegame_is_darkworld) { if (sprite_graphics[k] == 12) { sprite_graphics[k] = 42; sprite_head_dir[k] = 1; } else if (sprite_graphics[k] == 4) { sprite_graphics[k] = 5; sprite_head_dir[k] = 2; } else if (sprite_graphics[k] == 22) { sprite_graphics[k] = 44; sprite_head_dir[k] = 3; } else { Sprite_ShowMessageUnconditional(0x14d); return; } } else { if (sprite_graphics[k] == 58) { sprite_graphics[k] = 59; sprite_head_dir[k] = 4; Sprite_ShowMessageUnconditional(0x14f); return; } else if (sprite_graphics[k] == 2) { sprite_graphics[k] = 3; sprite_head_dir[k] = 5; } else if (sprite_graphics[k] == 22) { sprite_graphics[k] = 44; sprite_head_dir[k] = 3; } else { Sprite_ShowMessageUnconditional(0x14d); return; } } Sprite_ShowMessageUnconditional(0x8c); break; case 7: if (sprite_C[k] == 3) (&link_item_bow)[sprite_C[k]] = sprite_D[k]; Palette_AssertTranslucencySwap(); TS_copy = 2; CGADSUB_copy = 0x30; flag_update_cgram_in_nmi++; sprite_ai_state[k] = 8; break; case 8: if (!(frame_counter & 7)) { PaletteFilter_SP5F(); if (BYTE(palette_filter_countdown) == 30) { sprite_state[sprite_E[k]] = 0; } else if (BYTE(palette_filter_countdown) == 0) { sprite_ai_state[k] = 9; } } break; case 9: PaletteFilter_RestoreSP5F(); Palette_RevertTranslucencySwap(); item_receipt_method = 2; Link_ReceiveItem(sprite_graphics[k], 0); sprite_ai_state[k] = 10; break; case 10: { static const uint8 kWishPondMsgs[5] = { 0x8f, 0x90, 0x92, 0x91, 0x93 }; if (sprite_head_dir[k]) Sprite_ShowMessageUnconditional(kWishPondMsgs[sprite_head_dir[k] - 1]); sprite_ai_state[k] = 0; sprite_delay_main[k] = 255; break; } case 11: Sprite_ShowMessageUnconditional(0x8d); sprite_ai_state[k] = 12; break; case 12: if (!choice_in_multiselect_box) sprite_ai_state[k] = 13; else sprite_ai_state[k] = 6; break; case 13: Sprite_ShowMessageUnconditional(0x8e); sprite_ai_state[k] = 7; break; } } int Sprite_SpawnSmallSplash(int k) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamicallyEx(k, 0xec, &info, 14); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sound_effect_1 = 0; SpriteSfx_QueueSfx2WithPan(k, 0x28); sprite_state[j] = 3; sprite_delay_main[j] = 15; sprite_ai_state[j] = 0; sprite_flags2[j] = 3; } return j; } void HeartUpgrade_CheckIfAlreadyObtained(int k) { if (!player_is_indoors) { if (BYTE(overworld_screen_index) == 0x3b && !(save_ow_event_info[0x3b] & 0x20) || save_ow_event_info[BYTE(overworld_screen_index)] & 0x40) sprite_state[k] = 0; } else { int j = sprite_x_hi[k] & 1; if (dung_savegame_state_bits & (j ? 0x2000 : 0x4000)) sprite_state[k] = 0; } } void Sprite_MovableMantleTrampoline(int k) { MovableMantle_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (!Sprite_CheckDamageToLink_same_layer(k)) return; Sprite_NullifyHookshotDrag(); Sprite_RepelDash(); if (savegame_tagalong != 1 || !link_item_torch || link_is_running || sprite_G[k] == 0x90 || sign8(link_actual_vel_x - 24)) return; which_starting_point = 4; sprite_subtype2[k]++; if (!(sprite_subtype2[k] & 1)) sprite_G[k]++; if (sprite_G[k] < 8) return; if (sound_effect_1 == 0) sound_effect_1 = 34; sprite_x_vel[k] = 2; Sprite_MoveXY(k); } void Sprite_GoodOrBadArcheryTarget(int k) { static const uint8 kArcheryGame_CashPrize[10] = {4, 8, 16, 32, 64, 99, 99, 99, 99, 99}; if (sprite_A[k] == 1) { // good target if (sprite_G[k] >= 5) sprite_B[k] = 6; sprite_flags2[k] &= ~0x1f; int j = sprite_delay_aux2[k] ? sprite_delay_aux2[k] : (sprite_subtype2[k] >> 3); sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (j & 4) << 4; BYTE(cur_sprite_y) -= 3; SpriteDraw_SingleLarge(k); if (sprite_delay_aux2[k]) { if (sprite_delay_aux2[k] == 96 && !submodule_index) { sprite_delay_main[0] = 112; link_rupees_goal += kArcheryGame_CashPrize[sprite_B[k] - 1]; } sprite_flags2[k] |= 5; ArcheryGame_DrawPrize(k); } } else { // bad target sprite_flags2[k] &= ~0x1f; BYTE(cur_sprite_y) += 3; SpriteDraw_SingleLarge(k); } if (Sprite_ReturnIfInactive(k)) return; if (sprite_delay_aux3[k] == 1) sound_effect_1 = 0x3c; sprite_subtype2[k]++; Sprite_MoveX(k); if (!sprite_delay_aux1[k]) { sprite_ignore_projectile[k] = sprite_delay_main[k]; if (sprite_delay_main[k] == 0) { if (Sprite_CheckTileCollision(k)) { sprite_delay_main[k] = 16; sprite_delay_aux2[k] = 0; } } else if (sprite_delay_main[k] == 1) { static const int8 kArcheryTarget_X[2] = {-24, 8}; sprite_x_lo[k] = kArcheryTarget_X[sprite_graphics[k]]; sprite_x_hi[k] = link_x_coord >> 8; sprite_delay_aux1[k] = 32; sprite_G[k] = 0; } } } static inline uint8 ChainBallMult(uint16 a, uint8 b) { if (a >= 256) return b; int p = a * b; return (p >> 8) + (p >> 7 & 1); } void ChainBallTrooper_Draw(int k) { PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; SpriteDraw_GuardHead(k, &info, 0x18 / 4); SpriteDraw_BNCBody(k, &info, 0x14 / 4); SpriteDraw_BNCFlail(k, &info); if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; if (sprite_flags3[k] & 0x10) SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]); } void Sprite_CannonTrooper(int k) { if (sprite_C[k] != 0) { Sprite_Cannonball(k); return; } assert(0); } void Bee_PutInBottle(int k) { Bee_HandleInteractions(k); if (Sprite_ReturnIfInactive(k)) return; if (!choice_in_multiselect_box) { int j = Sprite_Find_EmptyBottle(); if (j >= 0) { link_bottle_info[j] = 7 + sprite_head_dir[k]; Hud_RefreshIcon(); sprite_state[k] = 0; return; } Sprite_ShowMessageUnconditional(0xca); } sprite_delay_aux4[k] = 64; sprite_ai_state[k] = 1; } static inline uint8 GuruguruBarMult(uint16 a, uint8 b) { if (a >= 256) return b; int p = a * b; return (p >> 8) + (p >> 7 & 1); } static inline int8 GuruguruBarSin(uint16 a, uint8 b) { uint8 t = GuruguruBarMult(kSinusLookupTable[a & 0xff], b); return (a & 0x100) ? -t : t; } static inline uint8 ArrgiMult(uint16 a, uint8 b) { if (a >= 256) return b; int p = a * b; return (p >> 8) + (p >> 7 & 1); } static inline int8 ArrgiSin(uint16 a, uint8 b) { uint8 t = ArrgiMult(kSinusLookupTable[a & 0xff], b); return (a & 0x100) ? -t : t; } static inline uint8 HelmasaurMult(uint16 a, uint8 b) { if (a >= 256) return b; int p = a * b; return (p >> 8) + (p >> 7 & 1); } static inline int8 HelmasaurSin(uint16 a, uint8 b) { uint8 t = HelmasaurMult(kSinusLookupTable[a & 0xff], b); return (a & 0x100) ? -t : t; } void Sprite_Wizzbeam(int k) { Wizzbeam_Draw(k); if (Sprite_ReturnIfInactive(k)) return; sprite_oam_flags[k] ^= 6; sprite_subtype2[k]++; if (!sprite_ai_state[k]) Sprite_CheckDamageToLink(k); Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) sprite_state[k] = 0; } void Kiki_LyingInwait(int k) { PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; if (link_is_bunny_mirror | link_disable_sprite_damage | countdown_for_blink || savegame_tagalong == 10) return; if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x20) return; if (Sprite_CheckDamageToLink_same_layer(k)) { savegame_tagalong = 10; tagalong_var5 = 0; LoadFollowerGraphics(); Follower_Initialize(); } } int ChainChomp_OneMult(uint8 a, uint8 b) { uint8 at = sign8(a) ? -a : a; uint8 prod = at * b >> 8; return sign8(a) ? ~prod : prod; } static inline uint8 TrinexxMult(uint8 a, uint8 b) { uint8 at = sign8(a) ? -a : a; int p = at * b; uint8 res = (p >> 8) + (p >> 7 & 1); return sign8(a) ? -res : res; } static inline uint8 TrinexxHeadMult(uint16 a, uint8 b) { if (a >= 256) return b; int p = a * b; return (p >> 8) + (p >> 7 & 1); } static inline int8 TrinexxHeadSin(uint16 a, uint8 b) { uint8 t = TrinexxHeadMult(kSinusLookupTable[a & 0xff], b); return (a & 0x100) ? -t : t; } void Sprite_CC(int k) { if (!sprite_E[k]) { Sprite_Sidenexx(k); return; } PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXY(k); Sprite_TrinexxFire_AddFireGarnish(k); Sprite_CC_CD_Common(k); } void Sprite_CD(int k) { if (!sprite_E[k]) { Sprite_Sidenexx(k); return; } PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; uint8 old_xvel = sprite_x_vel[k]; sprite_x_vel[k] += sprite_C[k]; Sprite_MoveXY(k); sprite_x_vel[k] = old_xvel; Sprite_CD_SpawnGarnish(k); Sprite_CC_CD_Common(k); } static inline uint8 GanonMult(uint16 a, uint8 b) { if (a >= 256) return b; int p = a * b; return (p >> 8) + (p >> 7 & 1); } static inline int8 GanonSin(uint16 a, uint8 b) { uint8 t = GanonMult(kSinusLookupTable[a & 0xff], b); return (a & 0x100) ? -t : t; } void SpritePrep_IncrXYLow8(int k) { sprite_x_lo[k] += 8; sprite_y_lo[k] += 8; } void SpritePrep_FakeSword(int k) { } void SpritePrep_MedallionTable(int k) { sprite_ignore_projectile[k]++; if (BYTE(overworld_screen_index) != 3) { sprite_x_lo[k] += 8; if (link_item_bombos_medallion) { sprite_graphics[k] = 4; sprite_ai_state[k] = 3; } } else { if (link_item_ether_medallion) { sprite_graphics[k] = 4; sprite_ai_state[k] = 3; } } } void Hobo_Draw(int k) { // 84ea60 static const DrawMultipleData kHobo_Dmd[12] = { {-5, 3, 0x00a6, 2}, { 3, 3, 0x00a7, 2}, {-5, 3, 0x00a6, 2}, { 3, 3, 0x00a7, 2}, {-5, 3, 0x00ab, 0}, { 3, 3, 0x00a7, 2}, {-5, 3, 0x00a6, 2}, { 3, 3, 0x00a7, 2}, { 5, -11, 0x008a, 2}, {-5, 3, 0x00ab, 0}, { 3, 3, 0x0088, 2}, {-5, 3, 0x00a6, 2}, }; Sprite_DrawMultiplePlayerDeferred(k, &kHobo_Dmd[sprite_graphics[k] * 4], 4, NULL); } bool Landmine_CheckDetonationFromHammer(int k) { // 84ea81 if (!(link_item_in_hand & 10) || player_oam_y_offset == 0x80) return false; SpriteHitBox hb; Player_SetupActionHitBox(&hb); Sprite_SetupHitBox(k, &hb); return CheckIfHitBoxesOverlap(&hb); } void Sprite_DrawLargeWaterTurbulence(int k) { // 84ebe5 static const DrawMultipleData kWaterTurbulence_Dmd[6] = { {-10, 14, 0x00c0, 2}, { -5, 16, 0x40c0, 2}, { -2, 18, 0x00c0, 2}, { 2, 18, 0x40c0, 2}, { 5, 16, 0x00c0, 2}, { 10, 14, 0x40c0, 2}, }; uint8 bak = sprite_oam_flags[k]; sprite_oam_flags[k] = (sprite_subtype2[k] >> 1 & 1) ? 0x44 : 4; sprite_obj_prio[k] &= ~0xf; Oam_AllocateFromRegionC(sprite_obj_prio[k]); // wtf????? Sprite_DrawMultiple(k, kWaterTurbulence_Dmd, 6, NULL); sprite_oam_flags[k] = bak; } void Sprite_SpawnSparkleGarnish(int k) { // 858008 static const int8 kSparkleGarnish_Coord[4] = {-4, 0, 4, 8}; if (frame_counter & 3) return; int j = GarnishAllocForce(); garnish_type[j] = 0x12; garnish_active = 0x12; int x = Sprite_GetX(k) + kSparkleGarnish_Coord[GetRandomNumber() & 3]; int y = Sprite_GetY(k) + kSparkleGarnish_Coord[GetRandomNumber() & 3]; garnish_x_lo[j] = x; garnish_x_hi[j] = x >> 8; garnish_y_lo[j] = y; garnish_y_hi[j] = y >> 8; garnish_sprite[j] = k; garnish_countdown[j] = 15; } void Sprite_70_KingHelmasaurFireball_bounce(int k) { // 85807f static const uint8 kHelmasaurFireball_Char[3] = {0xcc, 0xcc, 0xca}; static const uint8 kHelmasaurFireball_Flags[2] = {0x33, 0x73}; static const uint8 kHelmasaurFireball_Gfx[4] = {2, 2, 1, 0}; OamEnt *oam = GetOamCurPtr(); uint8 flags = kHelmasaurFireball_Flags[++sprite_subtype2[k] >> 2 & 1]; if ((uint8)((oam->x = sprite_x_lo[k] - BG2HOFS_copy2) + 32) < 64 || (uint8)((oam->y = sprite_y_lo[k] - BG2VOFS_copy2) + 16) < 32) { sprite_state[k] = 0; return; } oam->charnum = kHelmasaurFireball_Char[sprite_graphics[k]]; oam->flags = flags; bytewise_extended_oam[oam - oam_buf] = 2; if (Sprite_ReturnIfInactive(k)) return; if (!((k ^ frame_counter) & 3) && (uint16)(link_x_coord - cur_sprite_x + 8) < 16 && (uint16)(link_y_coord - cur_sprite_y + 16) < 16) { Sprite_AttemptDamageToLinkPlusRecoil(k); } switch (sprite_ai_state[k]) { case 0: // pre migrate down if (!sprite_delay_main[k]) { sprite_delay_main[k] = 18; sprite_ai_state[k] = 1; sprite_y_vel[k] = 36; } break; case 1: // migrate down if (!sprite_delay_main[k]) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 31; } sprite_y_vel[k] -= 2; Sprite_MoveY(k); break; case 2: // delay tri split if (!sprite_delay_main[k]) HelmasaurFireball_TriSplit(k); else sprite_graphics[k] = kHelmasaurFireball_Gfx[sprite_delay_main[k] >> 3]; break; case 3: // delay quad split if (!sprite_delay_main[k]) { HelmasaurFireball_QuadSplit(k); } else if (sprite_head_dir[k] < 20) { sprite_head_dir[k]++; Sprite_MoveXY(k); } break; case 4: // move Sprite_MoveXY(k); break; } } void Sprite_66_WallCannonVerticalLeft(int k) { // 858090 static const int8 kWallCannon_Xvel[4] = {0, 0, -16, 16}; static const int8 kWallCannon_Yvel[4] = {-16, 16, 0, 0}; static const uint8 kWallCannon_Gfx[4] = {0, 0, 2, 2}; static const uint8 kWallCannon_OamFlags[4] = {0x40, 0, 0, 0x80}; static const int8 kWallCannon_Spawn_X[4] = {8, -8, 0, 0}; static const int8 kWallCannon_Spawn_Y[4] = {0, 0, 8, -8}; static const int8 kWallCannon_Spawn_Xvel[4] = {24, -24, 0, 0}; static const int8 kWallCannon_Spawn_Yvel[4] = {0, 0, 24, -24}; int j = sprite_D[k]; sprite_graphics[k] = kWallCannon_Gfx[j] + (sprite_delay_aux2[k] != 0); sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kWallCannon_OamFlags[j]; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (!sprite_delay_main[k]) { sprite_delay_main[k] = 128; sprite_A[k] ^= 1; } j = sprite_A[k]; sprite_x_vel[k] = kWallCannon_Xvel[j]; sprite_y_vel[k] = kWallCannon_Yvel[j]; Sprite_MoveXY(k); if (!((k << 2) + frame_counter & 31)) sprite_delay_aux2[k] = 16; if (sprite_delay_aux2[k] != 1 || sprite_pause[k]) return; SpriteSpawnInfo info; j = Sprite_SpawnDynamicallyEx(k, 0x6B, &info, 13); if (j >= 0) { SpriteSfx_QueueSfx3WithPan(k, 0x7); sprite_C[j] = 1; sprite_graphics[j] = 1; int i = sprite_D[k]; Sprite_SetX(j, info.r0_x + kWallCannon_Spawn_X[i]); Sprite_SetY(j, info.r2_y + kWallCannon_Spawn_Y[i]); sprite_x_vel[j] = kWallCannon_Spawn_Xvel[i]; sprite_y_vel[j] = kWallCannon_Spawn_Yvel[i]; sprite_flags2[j] = sprite_flags2[j] & 0xf0 | 1; sprite_flags3[j] |= 0x47; sprite_defl_bits[j] |= 0x44; sprite_delay_main[j] = 32; } } void Sprite_65_ArcheryGame(int k) { // 8581ff link_num_arrows = sprite_subtype[k]; if (sprite_A[k] == 0) ArcheryGame_Host(k); else Sprite_GoodOrBadArcheryTarget(k); } void ArcheryGame_Host(int k) { // 858217 if (!archery_game_arrows_left) archery_game_out_of_arrows++; ArcheryGameGuy_Draw(k); if (Sprite_ReturnIfInactive(k)) return; sprite_flags4[k] = 0; if (Sprite_CheckDamageToLink_same_layer(k)) { Sprite_NullifyHookshotDrag(); link_speed_setting = 0; Link_CancelDash(); } if (sprite_delay_main[k]) { if (!(sprite_delay_main[k] & 7)) SpriteSfx_QueueSfx2WithPan(k, 0x11); sprite_graphics[k] = (sprite_delay_main[k] & 4) >> 2; } else { static const uint8 kArcheryGameGuy_Gfx[4] = {3, 4, 3, 2}; sprite_graphics[k] = kArcheryGameGuy_Gfx[sprite_ai_state[k] ? (frame_counter >> 5 & 3) : 0]; } switch (sprite_ai_state[k]) { case 0: sprite_flags4[k] = 10; if (Sprite_CheckDamageToLink_same_layer(k) && filtered_joypad_L & 0x80) { sprite_ai_state[k] = 1; ArcheryGameGuy_ShowMsg(k, 0x85); } break; case 1: case 3: if (!choice_in_multiselect_box && link_rupees_goal >= 20) { sprite_head_dir[k] = 0; byte_7E0B88 = 0; sprite_ai_state[k] = 2; ArcheryGameGuy_ShowMsg(k, 0x86); } else { sprite_ai_state[k] = 0; ArcheryGameGuy_ShowMsg(k, 0x87); } break; case 2: ArcheryGame_Host_ProctorGame(k); break; } } void ArcheryGameGuy_ShowMsg(int k, int msg) { // 8582bf dialogue_message_index = msg; Sprite_ShowMessageMinimal(); sprite_delay_main[k] = 0; } void ArcheryGame_Host_ProctorGame(int k) { // 8582d4 static const uint8 kArcheryGame_NumSpr[6] = {5, 4, 3, 2, 1, 0}; static const int8 kArcheryGame_X[18] = { 0, 0, 0, 0, 48, 48, 48, 48, 8, 8, 16, 16, 24, 24, 32, 32, 40, 40, }; static const int8 kArcheryGame_Y[18] = {-8, 0, 8, 16, -8, 0, 8, 16, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8 }; static const uint8 kArcheryGame_Char[18] = { 0x2b, 0x3b, 0x3b, 0x2b, 0x2b, 0x3b, 0x3b, 0x2b, 0x63, 0x73, 0x63, 0x73, 0x63, 0x73, 0x63, 0x73, 0x63, 0x73 }; static const uint8 kArcheryGame_Flags[18] = { 0x33, 0x33, 0xb3, 0xb3, 0x73, 0x73, 0xf3, 0xf3, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 }; if (!sprite_head_dir[k]) { archery_game_arrows_left = 5; Sprite_InitializeSecondaryItemMinigame(2); sprite_delay_aux1[k] = 39; link_rupees_goal -= 20; sprite_head_dir[k]++; } Oam_AllocateFromRegionA(0x34); PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int i = sprite_delay_aux1[k] ? kArcheryGame_NumSpr[sprite_delay_aux1[k] >> 3] : archery_game_arrows_left; i = i * 2 + 7; do { oam->x = info.x - 20 + kArcheryGame_X[i] + 1; oam->y = info.y - 48 + kArcheryGame_Y[i] + 1; oam->charnum = kArcheryGame_Char[i]; oam->flags = kArcheryGame_Flags[i]; bytewise_extended_oam[oam - oam_buf] = 0; } while (oam++, --i >= 0); if (archery_game_arrows_left | sprite_delay_aux4[k] | ancilla_type[0] | ancilla_type[1] | ancilla_type[2] | ancilla_type[3] | ancilla_type[4]) return; sprite_flags4[k] = 0xA; if (Sprite_CheckDamageToLink_same_layer(k) && filtered_joypad_L & 0x80) { ArcheryGameGuy_ShowMsg(k, 0x88); sprite_ai_state[k] = 3; } } void ArcheryGame_DrawPrize(int k) { // 8584cf static const int8 kGoodArcheryTarget_X[5] = {-8, -8, 0, 8, 16}; static const int8 kGoodArcheryTarget_Y[5] = {-24, -16, -20, -20, -20}; static const uint8 kGoodArcheryTarget_Draw_Char[3] = {0xb, 0x1b, 0xb6}; static const int8 kGoodArcheryTarget_Draw_Flags[5] = {0x38, 0x38, 0x34, 0x35, 0x35}; static const uint8 kGoodArcheryTarget_Draw_Char3[6] = {0x12, 0x32, 0x31, 3, 0x22, 0x33}; static const uint8 kGoodArcheryTarget_Draw_Char4[6] = {0x7c, 0x7c, 0x22, 2, 0x12, 0x33}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr() + 1; int b = sprite_B[k]; for (int i = 4; i >= 0; i--, oam++) { oam->x = info.x + kGoodArcheryTarget_X[i]; oam->y = info.y + kGoodArcheryTarget_Y[i]; oam->charnum = (i == 4) ? kGoodArcheryTarget_Draw_Char4[b - 1] : (i == 3) ? kGoodArcheryTarget_Draw_Char3[b - 1] : kGoodArcheryTarget_Draw_Char[i]; oam->flags = kGoodArcheryTarget_Draw_Flags[i] & (oam->charnum < 0x7c ? 0xff : 0xfe); bytewise_extended_oam[oam - oam_buf] = 0; } Sprite_DrawDistress_custom(info.x, info.y, frame_counter); } void Sprite_63_DebirandoPit(int k) { // 858531 static const uint8 kDebirandoPit_OpeningGfx[4] = {5, 4, 3, 3}; static const uint8 kDebirandoPit_ClosingGfx[4] = {3, 3, 4, 5}; PointU8 pt; Sprite_DirectionToFaceLink(k, &pt); if ((uint8)(pt.y + 0x20) < 0x40 && (uint8)(pt.x + 0x20) < 0x40) Oam_AllocateFromRegionB(16); DebirandoPit_Draw(k); if (Sprite_ReturnIfInactive(k)) return; int j = sprite_head_dir[k]; if (sprite_state[j] == 6) { sprite_state[k] = sprite_state[j]; sprite_delay_main[k] = sprite_delay_main[j]; sprite_flags2[k] += 4; return; } if (sprite_graphics[k] < 3 && Sprite_CheckDamageToLink_same_layer(k)) { Link_CancelDash(); if (!(filtered_joypad_L & 16)) link_prevent_from_moving = 1; Sprite_ApplySpeedTowardsLink(k, 16); uint8 v = sprite_y_vel[k]; int t; sprite_A[k] = (t = (sign8(v) ? (uint8)-v : v) + sprite_A[k]); if (t >= 256) drag_player_y = sign8(v) ? 1 : -1; v = sprite_x_vel[k]; sprite_B[k] = (t = (sign8(v) ? (uint8)-v : v) + sprite_B[k]); if (t >= 256) drag_player_x = sign8(v) ? 1 : -1; } switch (sprite_ai_state[k]) { case 0: // closed sprite_graphics[k] = 6; if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 63; } break; case 1: // opening if (!sprite_delay_main[k]) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 255; } else { sprite_graphics[k] = kDebirandoPit_OpeningGfx[sprite_delay_main[k] >> 4]; } break; case 2: // open if (!(frame_counter & 15) && ++sprite_graphics[k] >= 3) sprite_graphics[k] = 0; if (!sprite_delay_main[k]) { sprite_delay_main[k] = 63; sprite_ai_state[k] = 3; } break; case 3: // closing if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 32; } else { sprite_graphics[k] = kDebirandoPit_ClosingGfx[sprite_delay_main[k] >> 4]; } break; } } void DebirandoPit_Draw(int k) { // 8586e4 static const int16 kDebirandoPit_Draw_X[24] = { -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, 0, 8, 0, 8, 0, 8, 0, 8, -8, 8, -8, 8, }; static const int16 kDebirandoPit_Draw_Y[24] = { -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, -8, -8, 8, 8, }; static const uint8 kDebirandoPit_Draw_Char[24] = { 4, 4, 4, 4, 0x22, 0x22, 0x22, 0x22, 2, 2, 2, 2, 0x29, 0x29, 0x29, 0x29, 0x39, 0x39, 0x39, 0x39, 0x2a, 0x2a, 0x2a, 0x2a, }; static const uint8 kDebirandoPit_Draw_Flags[24] = { 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, }; static const uint8 kDebirandoPit_Draw_Ext[6] = {2, 2, 2, 0, 0, 2}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; int g = sprite_graphics[k]; if (g == 6) return; OamEnt *oam = GetOamCurPtr(); uint8 ext = kDebirandoPit_Draw_Ext[g]; for (int i = 3; i >= 0; i--, oam++) { int j = g * 4 + i; uint16 x = info.x + kDebirandoPit_Draw_X[j]; uint16 y = info.y + kDebirandoPit_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kDebirandoPit_Draw_Char[j]; oam->flags = kDebirandoPit_Draw_Flags[j] | info.flags; bytewise_extended_oam[oam - oam_buf] = ext | (x >> 8 & 1); } } void Sprite_64_Debirando(int k) { // 85874d static const uint8 kDebirando_Emerge_Gfx[2] = {1, 0}; static const uint8 kDebirando_Submerge_Gfx[2] = {0, 1}; Debirando_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch (sprite_ai_state[k]) { case 0: // under sand sprite_ignore_projectile[k] = sprite_delay_main[k]; if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 31; } break; case 1: // emerge Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 128; } else { sprite_graphics[k] = kDebirando_Emerge_Gfx[sprite_delay_main[k] >> 4]; } break; case 2: // fireball Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) { sprite_delay_main[k] = 31; sprite_ai_state[k]++; } else { if (!(sprite_delay_main[k] & 31 | sprite_G[k] | submodule_index | sprite_pause[k] | flag_unk1)) Sprite_SpawnFireball(k); sprite_graphics[k] = (++sprite_subtype2[k] >> 3 & 1) + 2; } break; case 3: // submerge Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 223; } else { sprite_graphics[k] = kDebirando_Submerge_Gfx[sprite_delay_main[k] >> 4]; } break; } } void Debirando_Draw(int k) { // 858857 if (!sprite_ai_state[k]) return; static const int8 kDebirando_Draw_X[16] = {0, 8, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0}; static const int8 kDebirando_Draw_Y[16] = {2, 2, 6, 6, -2, -2, 6, 6, -4, -4, -4, -4, -4, -4, -4, -4}; static const uint8 kDebirando_Draw_Char[16] = {0, 0, 0xd8, 0xd8, 0, 0, 0xd9, 0xd9, 0, 0, 0, 0, 0x20, 0x20, 0x20, 0x20}; static const uint8 kDebirando_Draw_Flags[16] = {1, 0x41, 0, 0x40, 1, 1, 0, 0x40, 1, 1, 1, 1, 1, 1, 1, 1}; static const uint8 kDebirando_Draw_Ext[16] = {0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int d = sprite_graphics[k] * 4; for (int i = 3; i >= 0; i--, oam++) { int j = d + i; uint16 x = info.x + kDebirando_Draw_X[j]; uint16 y = info.y + kDebirando_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kDebirando_Draw_Char[j]; uint8 f = kDebirando_Draw_Flags[j]; oam->flags = (f ^ info.flags) & ((f & 0xf) == 0 ? 0xf0 : 0xff); bytewise_extended_oam[oam - oam_buf] = kDebirando_Draw_Ext[j] | (x >> 8 & 1); } } void Sprite_62_MasterSword(int k) { // 8588c5 switch (sprite_subtype2[k]) { case 0: MasterSword_Main(k); break; case 1: Sprite_MasterSword_LightFountain(k); break; case 2: Sprite_MasterSword_LightBeam(k); break; case 3: Sprite_MasterSword_Prop(k); break; case 4: Sprite_MasterSword_LightWell(k); break; } } void MasterSword_Main(int k) { // 8588d6 if (main_module_index != 26 && save_ow_event_info[BYTE(overworld_screen_index)] & 0x40) { sprite_state[k] = 0; return; } if (sprite_ai_state[k] != 5) MasterSword_Draw(k); switch (sprite_ai_state[k]) { case 0: // waiting if (Sprite_CheckIfLinkIsBusy() || !Sprite_CheckDamageToLink_same_layer(k) || link_direction_facing != 2 || !(filtered_joypad_L & 0x80) || (link_which_pendants & 7) != 7) return; music_control = 10; link_disable_sprite_damage = 1; MasterSword_SpawnPendantProp(k, 9); MasterSword_SpawnPendantProp(k, 11); MasterSword_SpawnPendantProp(k, 15); MasterSword_SpawnLightWell(k); sprite_ai_state[k] = 1; sprite_delay_main[k] = 240; break; case 1: // pendants transfer if (!sprite_delay_main[k]) { MasterSword_SpawnLightFountain(k); sprite_ai_state[k] = 2; sprite_delay_main[k] = 192; } link_unk_master_sword = 10; flag_is_link_immobilized = 1; break; case 2: // light show if (!sprite_delay_main[k]) { MasterSword_SpawnLightBeam(k, 0, 0xff); sprite_ai_state[k] = 3; sprite_delay_main[k] = 8; } link_unk_master_sword = 10; flag_is_link_immobilized = 1; break; case 3: // if (!sprite_delay_main[k]) { MasterSword_SpawnLightBeam(k, 1, 0xff); sprite_ai_state[k] = 4; sprite_delay_main[k] = 16; } link_unk_master_sword = 11; flag_is_link_immobilized = 1; break; case 4: // give to player if (!sprite_delay_main[k]) { save_ow_event_info[BYTE(overworld_screen_index)] |= 0x40; item_receipt_method = 0; Link_ReceiveItem(1, 0); savegame_map_icons_indicator = 5; link_unk_master_sword = 0; sprite_ai_state[k] = 5; } break; case 5: // stop sprite_state[k] = 0; break; } } void Sprite_MasterSword_LightFountain(int k) { // 8589dc static const uint8 kMasterSword_Gfx1[9] = {0, 1, 1, 2, 2, 2, 1, 1, 0}; static const uint8 kMasterSword_NumLightBeams[9] = {0, 0, 1, 1, 2, 2, 0, 0, 0}; SpriteDraw_LightFountain(k); sprite_A[k]++; if (!sprite_A[k]) { sprite_C[k]++; sprite_state[k] = 0; } sprite_D[k] = sprite_A[k] >> 2 & 3; int j = sprite_A[k] >> 5 & 7; sprite_graphics[k] = kMasterSword_Gfx1[j]; if (kMasterSword_NumLightBeams[j]) MasterSword_SpawnLightBeam(k, sprite_A[k] >> 2 & 1, kMasterSword_NumLightBeams[j]); } void Sprite_MasterSword_LightWell(int k) { // 858a16 SpriteDraw_LightFountain(k); sprite_A[k]++; if (!sprite_A[k]) { sprite_C[k]++; sprite_state[k] = 0; } sprite_D[k] = sprite_A[k] >> 2 & 3; sprite_graphics[k] = 0; } void SpriteDraw_LightFountain(int k) { // 858a94 static const DrawMultipleData kMasterSword_LightBall_Dmd[12] = { {-6, 4, 0x0082, 2}, {-6, 4, 0x4082, 2}, {-6, 4, 0xc082, 2}, {-6, 4, 0x8082, 2}, {-6, 4, 0x00a0, 2}, {-6, 4, 0x40a0, 2}, {-6, 4, 0xc0a0, 2}, {-6, 4, 0x80a0, 2}, {-6, 4, 0x0080, 2}, {-6, 4, 0x4080, 2}, {-6, 4, 0xc080, 2}, {-6, 4, 0x8080, 2}, }; Oam_AllocateFromRegionC(4); Sprite_DrawMultiple(k, &kMasterSword_LightBall_Dmd[sprite_graphics[k] * 4 + sprite_D[k]], 1, NULL); } void MasterSword_SpawnLightWell(int k) { // 858ab6 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x62, &info); Sprite_SetSpawnedCoordinates(j, &info); sprite_subtype2[j] = 4; sprite_oam_flags[j] = 5; sprite_flags2[j] = 0; } void MasterSword_SpawnLightFountain(int k) { // 858ad0 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x62, &info); Sprite_SetSpawnedCoordinates(j, &info); sprite_subtype2[j] = 1; sprite_oam_flags[j] = 5; sprite_flags2[j] = 0; } void Sprite_MasterSword_LightBeam(int k) { // 858aea SpriteDraw_SingleLarge(k); if (sprite_A[k]) { Sprite_MoveXY(k); if (frame_counter & 3) return; MasterSword_SpawnReplacementLightBeam(k); } if (!--sprite_B[k]) sprite_state[k] = 0; } void MasterSword_SpawnReplacementLightBeam(int k) { // 858b20 SpriteSpawnInfo info; int j; if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0) return; Sprite_SetX(j, info.r0_x); Sprite_SetY(j, info.r2_y); sprite_subtype2[j] = 2; sprite_B[j] = 3; sprite_graphics[j] = sprite_graphics[k]; sprite_oam_flags[j] = sprite_oam_flags[k]; sprite_flags2[j] = 0; } void MasterSword_SpawnLightBeam(int k, uint8 ain, uint8 yin) { // 858b62 static const int8 kMasterSword_LightBeam_Xv0[2] = {0, -48}; static const int8 kMasterSword_LightBeam_Xv1[2] = {0, 48}; static const int8 kMasterSword_LightBeam_Xv2[2] = {-96, -48}; static const int8 kMasterSword_LightBeam_Xv3[2] = {96, 48}; static const int8 kMasterSword_LightBeam_Yv0[2] = {-96, -48}; static const int8 kMasterSword_LightBeam_Yv1[2] = {96, 48}; static const int8 kMasterSword_LightBeam_Yv2[2] = {0, 48}; static const int8 kMasterSword_LightBeam_Yv3[2] = {0, -48}; static const uint8 kMasterSword_LightBeam_Gfx0[2] = {1, 0}; static const uint8 kMasterSword_LightBeam_Gfx2[2] = {3, 2}; static const uint8 kMasterSword_LightBeam_Flags0[2] = {5, 0x45}; static const uint8 kMasterSword_LightBeam_Flags2[2] = {5, 5}; SpriteSpawnInfo info; int j; if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0) return; Sprite_SetX(j, info.r0_x - 4); Sprite_SetY(j, info.r2_y + 4); sprite_subtype2[j] = 2; sprite_A[j] = 2; sprite_flags2[j] = 0; sprite_x_vel[j] = kMasterSword_LightBeam_Xv0[ain]; sprite_y_vel[j] = kMasterSword_LightBeam_Yv0[ain]; sprite_graphics[j] = kMasterSword_LightBeam_Gfx0[ain]; sprite_oam_flags[j] = kMasterSword_LightBeam_Flags0[ain]; sprite_B[j] = yin; if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0) return; Sprite_SetX(j, info.r0_x - 4); Sprite_SetY(j, info.r2_y + 4); sprite_subtype2[j] = 2; sprite_A[j] = 2; sprite_flags2[j] = 0; sprite_x_vel[j] = kMasterSword_LightBeam_Xv1[ain]; sprite_y_vel[j] = kMasterSword_LightBeam_Yv1[ain]; sprite_graphics[j] = kMasterSword_LightBeam_Gfx0[ain]; sprite_oam_flags[j] = kMasterSword_LightBeam_Flags0[ain]; sprite_B[j] = yin; if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0) return; Sprite_SetX(j, info.r0_x - 4); Sprite_SetY(j, info.r2_y + 4); sprite_subtype2[j] = 2; sprite_A[j] = 2; sprite_flags2[j] = 0; sprite_x_vel[j] = kMasterSword_LightBeam_Xv2[ain]; sprite_y_vel[j] = kMasterSword_LightBeam_Yv2[ain]; sprite_graphics[j] = kMasterSword_LightBeam_Gfx2[ain]; sprite_oam_flags[j] = kMasterSword_LightBeam_Flags2[ain]; sprite_B[j] = yin; if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0) return; Sprite_SetX(j, info.r0_x - 4); Sprite_SetY(j, info.r2_y + 4); sprite_subtype2[j] = 2; sprite_A[j] = 2; sprite_flags2[j] = 0; sprite_x_vel[j] = kMasterSword_LightBeam_Xv3[ain]; sprite_y_vel[j] = kMasterSword_LightBeam_Yv3[ain]; sprite_graphics[j] = kMasterSword_LightBeam_Gfx2[ain]; sprite_oam_flags[j] = kMasterSword_LightBeam_Flags2[ain]; sprite_B[j] = yin; } void MasterSword_SpawnPendantProp(int k, uint8 ain) { // 858cd3 static const int8 kMasterSword_Pendant_Xv[4] = {-4, 4, 0, 0}; static const int8 kMasterSword_Pendant_Yv[4] = {-2, -2, -4, -4}; SpriteSpawnInfo info; int j; if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0) return; sprite_oam_flags[j] = ain; Sprite_SetX(j, link_x_coord); Sprite_SetY(j, link_y_coord + 8); sprite_graphics[j] = 4; sprite_subtype2[j] = 3; sprite_flags2[j] = 64; sprite_delay_main[j] = 228; int i = ain >> 1 & 3; sprite_x_vel[j] = kMasterSword_Pendant_Xv[i]; sprite_y_vel[j] = kMasterSword_Pendant_Yv[i]; } void Sprite_MasterSword_Prop(int k) { // 858d29 Oam_AllocateFromRegionB(4); SpriteDraw_SingleLarge(k); switch (sprite_ai_state[k]) { case 0: // drifting away Sprite_MoveXY(k); if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 208; sprite_A[k] = sprite_oam_flags[k]; } break; case 1: // flashing sprite_oam_flags[k] = (sprite_oam_flags[k] & ~0xe) | ((k << 1 ^ frame_counter) & 0xe); if (!sprite_delay_main[k]) { sprite_ai_state[k] = 2; sprite_oam_flags[k] = sprite_A[k]; } break; case 2: // fly Sprite_MoveXY(k); if (!sprite_delay_main[k]) { sprite_x_vel[k] <<= 1; sprite_y_vel[k] <<= 1; sprite_delay_main[k] = 6; } sprite_E[k]++; if (sprite_E[k] == 0) sprite_state[k] = 0; break; } } void MasterSword_Draw(int k) { // 858da8 static const int8 kMasterSword_Draw_X[6] = {-8, 0, -8, 0, -8, 0}; static const int8 kMasterSword_Draw_Y[6] = {-8, -8, 0, 0, 8, 8}; static const uint8 kMasterSword_Draw_Char[6] = {0xc3, 0xc4, 0xd3, 0xd4, 0xe0, 0xf0}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); for (int i = 5; i >= 0; i--, oam++) { oam->x = kMasterSword_Draw_X[i] + info.x; oam->y = kMasterSword_Draw_Y[i] + info.y; oam->charnum = kMasterSword_Draw_Char[i]; oam->flags = info.flags; } Sprite_CorrectOamEntries(k, 5, 0); } void Sprite_5D_Roller_VerticalDownFirst(int k) { // 858dde static const int8 kSpikeRoller_XYvel[6] = {-16, 16, 0, 0, -16, 16}; sprite_graphics[k] = sprite_subtype2[k] >> 1 & 1 | sprite_D[k] & 2; SpikeRoller_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) { sprite_delay_main[k] = 112; sprite_D[k] ^= 1; } int j = sprite_D[k]; sprite_x_vel[k] = kSpikeRoller_XYvel[j]; sprite_y_vel[k] = kSpikeRoller_XYvel[j + 2]; Sprite_MoveXY(k); sprite_subtype2[k]++; } void SpikeRoller_Draw(int k) { // 858ee3 static const uint8 kSpikeRoller_Draw_X[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, }; static const uint8 kSpikeRoller_Draw_Y[32] = { 0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const uint8 kSpikeRoller_Draw_Char[32] = { 0x8e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x8e, 0x8e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x8e, 0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, }; static const uint8 kSpikeRoller_Draw_Flags[32] = { 0, 0, 0, 0x80, 0, 0, 0, 0x80, 0x40, 0x40, 0x40, 0xc0, 0x40, 0x40, 0x40, 0xc0, 0, 0, 0, 0x40, 0, 0, 0, 0x40, 0x80, 0x80, 0x80, 0xc0, 0x80, 0x80, 0x80, 0xc0, }; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; uint8 chr = kSpikeRoller_Draw_Char[g * 8]; for (int i = sprite_ai_state[k] ? 7 : 3; i >= 0; i--, oam++) { int j = g * 8 + i; uint16 x = info.x + kSpikeRoller_Draw_X[j]; uint16 y = info.y + kSpikeRoller_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = chr ? chr : kSpikeRoller_Draw_Char[j]; chr = 0; oam->flags = kSpikeRoller_Draw_Flags[j] | info.flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } } void Sprite_61_Beamos(int k) { // 858f54 if (sprite_C[k] == 1) { Sprite_Beamos_Laser(k); return; } else if (sprite_C[k] != 0) { Sprite_Beamos_LaserHit(k); return; } Beamos_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckTileCollision(k); Sprite_CheckDamageToLink(k); switch (sprite_ai_state[k]) { case 0: if (!((k ^ frame_counter) & 3)) { Sprite_SpawnProbeAlways(k, sprite_D[k]); sprite_D[k]++; } sprite_D[k] &= 63; break; case 3: if (!sprite_delay_main[k]) { sprite_ai_state[k] = 4; sprite_delay_main[k] = 80; SpritePrep_LoadPalette(k); } else { if (sprite_delay_main[k] == 15) Beamos_FireLaser(k); sprite_oam_flags[k] ^= (sprite_delay_main[k] >> 1 & 0xe); } break; default: if (!sprite_delay_main[k]) sprite_ai_state[k] = 0; break; } } void Beamos_FireLaser(int k) { // 858fc2 if (sprite_limit_instance >= 4) return; SpriteSpawnInfo info; int j, t; if ((j = Sprite_SpawnDynamically(k, 0x61, &info)) < 0) return; SpriteSfx_QueueSfx3WithPan(k, 0x19); Sprite_SetX(j, info.r0_x + (int8)BYTE(dungmap_var7)); Sprite_SetY(j, info.r2_y + (int8)HIBYTE(dungmap_var7)); Sprite_ApplySpeedTowardsLink(j, 0x20); sprite_flags2[j] = 0x3f; sprite_flags4[j] = 0x54; sprite_C[j] = 1; sprite_defl_bits[j] = 0x48; sprite_oam_flags[j] = 3; sprite_bump_damage[j] = 4; sprite_delay_aux1[j] = 12; sprite_graphics[j] = t = sprite_limit_instance++; for (int i = 0; i < 32; i++) { beamos_x_lo[t * 32 + i] = sprite_x_lo[j]; beamos_x_hi[t * 32 + i] = sprite_x_hi[j]; beamos_y_lo[t * 32 + i] = sprite_y_lo[j]; beamos_y_hi[t * 32 + i] = sprite_y_hi[j]; } } void Beamos_Draw(int k) { // 859068 static const int8 kBeamos_Draw_Y[2] = {-16, 0}; static const int8 kBeamos_Draw_Char[2] = {0x48, 0x68}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; int spr_offs = 0; if (sprite_D[k] < 0x20) { Oam_AllocateFromRegionB(12); spr_offs = 1; } else { Oam_AllocateFromRegionC(12); } OamEnt *oam = GetOamCurPtr() + spr_offs; for (int i = 1; i >= 0; i--, oam++) { uint16 x = info.x; uint16 y = info.y + kBeamos_Draw_Y[i]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kBeamos_Draw_Char[i]; oam->flags = info.flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } SpriteDraw_Beamos_Eyeball(k, &info); } void SpriteDraw_Beamos_Eyeball(int k, PrepOamCoordsRet *info) { // 859151 static const int8 kBeamosEyeball_Draw_X[32] = { -1, 0, 1, 2, 3, 4, 5, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 15, 14, 13, 12, 11, 10, 8, 7, 5, 4, 3, 2, 1, 0, -2, }; static const int8 kBeamosEyeball_Draw_Y[32] = { 11, 12, 13, 14, 14, 15, 15, 15, 15, 15, 15, 14, 14, 13, 12, 11, 10, 9, 8, 7, 7, 6, 6, 6, 6, 6, 6, 7, 7, 8, 9, 10, }; static const uint8 kBeamosEyeball_Draw_Char[32] = { 0x5b, 0x5b, 0x5a, 0x5a, 0x4b, 0x4b, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x5b, 0x5b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, }; static const uint8 kBeamosEyeball_Draw_Flags[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, }; int n = (sprite_D[k] < 0x20) ? 0 : 2; OamEnt *oam = GetOamCurPtr() + n; int i = sprite_D[k] >> 1; BYTE(dungmap_var7) = kBeamosEyeball_Draw_X[i] - 3; oam->x = BYTE(dungmap_var7) + info->x; HIBYTE(dungmap_var7) = kBeamosEyeball_Draw_Y[i] - 18; oam->y = HIBYTE(dungmap_var7) + info->y; oam->charnum = kBeamosEyeball_Draw_Char[i]; oam->flags = info->flags&0x31|0xA|kBeamosEyeball_Draw_Flags[i]; oam_cur_ptr += n * 4; oam_ext_cur_ptr += n; Sprite_CorrectOamEntries(k, 0, 0); } void Sprite_Beamos_Laser(int k) { // 8591b5 if (sprite_delay_aux1[k]) return; BeamosLaser_Draw(k); if (!sprite_state[k]) { sprite_limit_instance--; return; } if (Sprite_ReturnIfInactive(k)) return; for (int i = 3; i >= 0; i--) { int t = (sprite_subtype2[k]++ & 31) + sprite_graphics[k] * 32; beamos_y_hi[t] = sprite_y_hi[k]; beamos_y_lo[t] = sprite_y_lo[k]; beamos_x_hi[t] = sprite_x_hi[k]; beamos_x_lo[t] = sprite_x_lo[k]; Sprite_MoveXY(k); } if (sprite_delay_main[k]) { if (sprite_delay_main[k] == 1) { sprite_state[k] = 0; sprite_limit_instance--; } return; } if (!Sprite_CheckDamageToLink_same_layer(k) && !Sprite_CheckTileCollision(k)) return; SpriteSfx_QueueSfx3WithPan(k, 0x26); sprite_delay_main[k] = 16; Sprite_ZeroVelocity_XY(k); SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x61, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_delay_main[j] = 16; sprite_flags2[j] = 3; sprite_C[j] = 2; sprite_flags3[j] = 0x40; } sprite_y_hi[k] = 128; } void BeamosLaser_Draw(int k) { // 85925b PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; for (int i = 31; i >= 0; i--, oam++) { int j = g * 32 + i; uint16 x = (beamos_x_lo[j] | beamos_x_hi[j] << 8) - BG2HOFS_copy2; uint16 y = (beamos_y_lo[j] | beamos_y_hi[j] << 8) - BG2VOFS_copy2; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = 0x5c; oam->flags = info.flags; bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1); } } void Sprite_Beamos_LaserHit(int k) { // 8592da static const int8 kBeamosLaserHit_Draw_X[4] = {-4, 4, -4, 4}; static const int8 kBeamosLaserHit_Draw_Y[4] = {-4, -4, 4, 4}; static const uint8 kBeamosLaserHit_Draw_Flags[4] = {6, 0x46, 0x86, 0xc6}; if (!sprite_delay_main[k]) sprite_state[k] = 0; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); for (int i = 3; i >= 0; i--, oam++) { uint16 x = info.x + kBeamosLaserHit_Draw_X[i]; uint16 y = info.y + kBeamosLaserHit_Draw_Y[i]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = 0xd6; oam->flags = kBeamosLaserHit_Draw_Flags[i] | info.flags & 0x30; bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1); } } void Sprite_5B_Spark_Clockwise(int k) { // 85933f static const uint8 kSpark_OamFlags[4] = {0, 0x40, 0x80, 0xc0}; static const uint8 kSpark_directions[8] = {1, 3, 2, 0, 7, 5, 6, 4}; int j; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (!(frame_counter & 1)) sprite_oam_flags[k] ^= 6; if (!sprite_ai_state[k]) { sprite_ai_state[k] = 1; sprite_x_vel[k] = sprite_y_vel[k] = 1; uint8 coll = Sprite_CheckTileCollision(k); sprite_x_vel[k] = sprite_y_vel[k] = -1; coll |= Sprite_CheckTileCollision(k); if (coll < 4) j = (coll & 1) ? 0 : 1; else j = (coll & 4) ? 2 : 3; sprite_D[k] = kSpark_directions[(sprite_type[k] != 0x5c) * 4 + j]; } sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kSpark_OamFlags[frame_counter >> 2 & 3]; Sprite_MoveXY(k); Sprite_CheckDamageToLink(k); j = sprite_D[k]; sprite_x_vel[k] = kSoldierB_Xvel[j]; sprite_y_vel[k] = kSoldierB_Yvel[j]; Sprite_CheckTileCollision(k); j = sprite_D[k]; if (sprite_delay_aux2[k]) { if (sprite_delay_aux2[k] == 6) j = kSoldierB_NextB[j]; } else { if (!(sprite_wallcoll[k] & kSoldierB_Mask[j])) sprite_delay_aux2[k] = 10; } if (sprite_wallcoll[k] & kSoldierB_Mask2[j]) j = kSoldierB_NextB2[j]; sprite_D[k] = j; sprite_x_vel[k] = kSoldierB_Xvel2[j] * 2; sprite_y_vel[k] = kSoldierB_Yvel2[j] * 2; } void Sprite_59_LostWoodsBird(int k) { // 85940e if (sprite_delay_aux1[k]) return; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(sprite_x_vel[k]) ? 0 : 0x40); SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXY(k); Sprite_MoveZ(k); switch (sprite_ai_state[k]) { case 0: sprite_graphics[k] = 0; if (sign8(--sprite_z_vel[k] - 0xf1)) sprite_ai_state[k] = 1; break; case 1: sprite_z_vel[k] += 2; if (!sign8(sprite_z_vel[k] - 0x10)) sprite_ai_state[k] = 0; sprite_graphics[k] = ++sprite_subtype2[k] >> 1 & 1; break; } } void Sprite_5A_LostWoodsSquirrel(int k) { // 859468 if (sprite_delay_aux1[k]) return; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(sprite_x_vel[k]) ? 0 : 0x40); SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXY(k); Sprite_MoveZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = 16; sprite_delay_main[k] = 12; } sprite_graphics[k] = sprite_delay_main[k] ? 1 : 0; } void Sprite_58_Crab(int k) { // 8594b5 static const int8 kCrab_Xvel[4] = {28, -28, 0, 0}; static const int8 kCrab_Yvel[4] = {0, 0, 12, -12}; Crab_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k) || !sprite_delay_main[k]) { sprite_delay_main[k] = (GetRandomNumber() & 63) + 32; sprite_D[k] = sprite_delay_main[k] & 3; } int j = sprite_D[k]; sprite_x_vel[k] = kCrab_Xvel[j & 3]; sprite_y_vel[k] = kCrab_Yvel[j & 3]; sprite_graphics[k] = (++sprite_subtype2[k] >> (j < 2 ? 1 : 3)) & 1; } void Crab_Draw(int k) { // 859510 static const int16 kCrab_Draw_X[4] = {-8, 8, -8, 8}; static const uint8 kCrab_Draw_Char[4] = {0x8e, 0x8e, 0xae, 0xae}; static const int8 kCrab_Draw_Flags[4] = {0, 0x40, 0, 0x40}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int d = sprite_graphics[k] * 2; for (int i = 1; i >= 0; i--, oam++) { int j = d + i; uint16 x = info.x + kCrab_Draw_X[j]; uint16 y = info.y; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kCrab_Draw_Char[j]; oam->flags = kCrab_Draw_Flags[j] | info.flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } SpriteDraw_Shadow(k, &info); } void Sprite_57_DesertStatue(int k) { // 85956d static const uint8 kDesertBarrier_NextD[4] = {3, 2, 0, 1}; DesertBarrier_Draw(k); if (Sprite_ReturnIfInactive(k)) return; bool dmg = Sprite_CheckDamageToLink_same_layer(k); if (dmg) { Sprite_NullifyHookshotDrag(); Sprite_RepelDash(); } if (sprite_delay_main[k] || sign8(sprite_ai_state[k])) return; if (sprite_ai_state[k] == 0) { if (!byte_7E02F0) return; sprite_ai_state[k] = byte_7E02F0; sprite_delay_main[k] = 128; sound_effect_ambient = 7; } if (dmg && !link_incapacitated_timer) { link_incapacitated_timer = 16; Sprite_ApplySpeedTowardsLink(k, 32); } int j = sprite_D[k]; sprite_x_vel[k] = kDesertBarrier_Xv[j]; sprite_y_vel[k] = kDesertBarrier_Yv[j]; Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) sprite_D[k] = kDesertBarrier_NextD[sprite_D[k]]; flag_is_link_immobilized = 1; if (!(++sprite_subtype2[k] & 1)) { if (++sprite_G[k] == 130) { sprite_ai_state[k] = 128; flag_is_link_immobilized = 0; } } } void DesertBarrier_Draw(int k) { // 859626 static const DrawMultipleData kDesertBarrier_Dmd[4] = { {-8, -8, 0x008e, 2}, { 8, -8, 0x408e, 2}, {-8, 8, 0x00ae, 2}, { 8, 8, 0x40ae, 2}, }; if (sprite_delay_main[k] == 1) { sound_effect_2 = 0x1b; sound_effect_ambient = 5; } BYTE(cur_sprite_x) += (sprite_delay_main[k] >> 1) & 1; PointU8 pt; Sprite_DirectionToFaceLink(k, &pt); if ((uint8)(pt.x + 0x20) < 0x40 && (uint8)(pt.y + 0x20) < 0x40) Oam_AllocateFromRegionB(16); Sprite_DrawMultiple(k, kDesertBarrier_Dmd, 4, NULL); } void Sprite_55_Zora(int k) { // 85967b if (sprite_E[k]) Sprite_Fireball(k); else Sprite_Zora_Main(k); } void Sprite_Fireball(int k) { // 859683 static const uint8 kSprite_ZoraFireball_Offs[4] = {3, 2, 0, 0}; static const int8 kSprite_ZoraFireball_X[4] = {4, 4, -4, 16}; static const int8 kSprite_ZoraFireball_Y[4] = {0, 16, 8, 8}; static const uint8 kSprite_ZoraFireball_W[4] = {8, 8, 4, 4}; static const uint8 kSprite_ZoraFireball_H[4] = {4, 4, 8, 8}; sprite_ignore_projectile[k] = sprite_E[k]; if (sprite_delay_main[k]) Oam_AllocateFromRegionC(4); SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; Fireball_SpawnTrailGarnish(k); if (Sprite_CheckDamageToLink(k)) { sprite_state[k] = 0; return; } Sprite_MoveXY(k); if (player_is_indoors && !sprite_delay_aux1[k] && !((k ^ frame_counter) & 3) && Sprite_CheckTileCollision(k)) { sprite_state[k] = 0; return; } if ((link_is_bunny_mirror | link_disable_sprite_damage) || sign8(link_state_bits) || link_shield_type < 2 || link_is_on_lower_level != sprite_floor[k]) return; SpriteHitBox hb; Sprite_SetupHitBox(k, &hb); int j = link_direction_facing >> 1; if (button_b_frames) j = kSprite_ZoraFireball_Offs[j]; int x = link_x_coord + kSprite_ZoraFireball_X[j], y = link_y_coord + kSprite_ZoraFireball_Y[j]; hb.r0_xlo = x; hb.r8_xhi = x >> 8; hb.r2 = kSprite_ZoraFireball_W[j]; hb.r1_ylo = y; hb.r9_yhi = y >> 8; hb.r3 = kSprite_ZoraFireball_H[j]; if (CheckIfHitBoxesOverlap(&hb)) { Sprite_PlaceRupulseSpark_2(k); sprite_state[k] = 0; SpriteSfx_QueueSfx2WithPan(k, 0x6); } } void Sprite_Zora_Main(int k) { // 859725 static const int8 kSprite_Zora_Surface_XY[8] = {-32, -24, -16, -8, 8, 16, 24, 32}; static const uint8 kSprite_Zora_AttackGfx[8] = {5, 5, 6, 10, 6, 5, 5, 5}; static const uint8 kSprite_Zora_SubmergeGfx[12] = {12, 11, 9, 8, 7, 0, 0, 0, 0, 0, 0, 0}; PrepOamCoordsRet info; if (!sprite_ai_state[k]) Sprite_PrepOamCoord(k, &info); else Zora_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch (sprite_ai_state[k]) { case 0: // choose surfacing location sprite_ignore_projectile[k] = sprite_delay_main[k]; if (!sprite_delay_main[k]) { Sprite_SetX(k, (sprite_A[k] | sprite_B[k] << 8) + kSprite_Zora_Surface_XY[GetRandomNumber() & 7]); Sprite_SetY(k, (sprite_C[k] | sprite_head_dir[k] << 8) + kSprite_Zora_Surface_XY[GetRandomNumber() & 7]); Sprite_Get16BitCoords(k); Sprite_CheckTileCollision(k); if (sprite_tiletype == 8) { sprite_delay_main[k] = 127; sprite_ai_state[k]++; sprite_flags3[k] |= 0x40; } } break; case 1: // surfacing sprite_ignore_projectile[k] = sprite_delay_main[k]; if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 127; sprite_flags3[k] &= ~0x40; } else { sprite_graphics[k] = kSprite_Zora_SurfacingGfx[sprite_delay_main[k] >> 3]; } break; case 2: // attack Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 23; } else { if (sprite_delay_main[k] == 48) Sprite_SpawnFireball(k); sprite_graphics[k] = kSprite_Zora_AttackGfx[sprite_delay_main[k] >> 4]; } break; case 3: // submerging if (!sprite_delay_main[k]) { sprite_delay_main[k] = 128; sprite_graphics[k] = 0; sprite_ai_state[k] = 0; } else { sprite_graphics[k] = kSprite_Zora_SubmergeGfx[sprite_delay_main[k] >> 2]; } break; } } void Zora_Draw(int k) { // 8598f5 static const int8 kZora_Draw_X[26] = { 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 11, 0, 4, -8, 18, -8, 18, }; static const int8 kZora_Draw_Y[26] = { 4, 4, 0, 0, 0, 0, 0, -3, 0, -3, -3, -3, -3, -3, -3, -3, -6, -6, -8, -9, -3, 5, -10, -11, -10, -11, }; static const uint8 kZora_Draw_Char[26] = { 0xa8, 0xa8, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa4, 0x88, 0xa4, 0xa4, 0xa4, 0xa6, 0xa6, 0xa4, 0xc0, 0x8a, 0x8a, 0xae, 0xaf, 0xa6, 0x8d, 0xcf, 0xcf, 0xdf, 0xdf, }; static const uint8 kZora_Draw_Flags[26] = { 0x25, 0x25, 0x25, 0x25, 0xe5, 0xe5, 0x25, 0x20, 0xe5, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x25, 0x25, 0x24, 0x64, 0x20, 0x26, 0x24, 0x64, 0x24, 0x64, }; static const uint8 kZora_Draw_Ext[26] = { 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 0, 0, 0, 0, 0, }; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int d = sprite_graphics[k] * 2; for (int i = 1; i >= 0; i--, oam++) { int j = d + i; uint16 x = info.x + kZora_Draw_X[j]; uint16 y = info.y + kZora_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kZora_Draw_Char[j]; uint8 f = kZora_Draw_Flags[j]; oam->flags = f | (f & 0xf ? 0 : info.flags); bytewise_extended_oam[oam - oam_buf] = kZora_Draw_Ext[j] | (x >> 8 & 1); } } void Sprite_52_KingZora(int k) { // 85995b ZoraKing_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch(sprite_ai_state[k]) { case 0: // WaitingForPlayer if ((uint16)(link_x_coord - cur_sprite_x + 16) < 32 && (uint16)(link_y_coord - cur_sprite_y + 48) < 96) { Link_CancelDash(); sprite_delay_main[k] = 127; sound_effect_1 = 0x35; sprite_ai_state[k] = 1; for (int j = 15; j >= 0; j--) { if (j != k && !(sprite_defl_bits[j] & 0x80)) { if (sprite_state[j] == 10) { link_state_bits = 0; link_picking_throw_state = 0; } Sprite_KillSelf(j); } } } break; case 1: // RumblingGround if (!sprite_delay_main[k]) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 127; bg1_x_offset = 0; sprite_graphics[k] = 4; } else { bg1_x_offset = sprite_delay_main[k] & 1 ? -1 : 1; flag_is_link_immobilized = 1; } break; case 2: { // Surfacing static const uint8 kZoraKing_Surfacing_Gfx[16] = {0, 0, 0, 3, 9, 8, 7, 6, 9, 8, 7, 6, 5, 4, 5, 4}; if (!sprite_delay_main[k]) { sprite_ai_state[k] = 3; sprite_delay_main[k] = 127; } else { if (sprite_delay_main[k] == 28) { sprite_delay_aux2[k] = 15; Sprite_SpawnBigSplash(k); } sprite_graphics[k] = kZoraKing_Surfacing_Gfx[sprite_delay_main[k] >> 3]; } break; } case 3: { // Dialogue static const uint8 kZoraKing_Dialogue_Gfx[8] = {0, 0, 1, 2, 1, 2, 0, 0}; int j = sprite_delay_main[k]; if (!j) { sprite_ai_state[k] = 4; sprite_delay_main[k] = 36; return; } sprite_graphics[k] = kZoraKing_Dialogue_Gfx[j >> 4]; if (j == 80) { dialogue_message_index = 0x142; Sprite_ShowMessageMinimal(); } else if (j == 79) { if (choice_in_multiselect_box == 0) { dialogue_message_index = 0x143; Sprite_ShowMessageMinimal(); } else { dialogue_message_index = 0x146; Sprite_ShowMessageMinimal(); sprite_delay_main[k] = 0x30; } } else if (j == 78) { if (choice_in_multiselect_box == 0 && link_rupees_goal >= 500) { link_rupees_goal -= 500; dialogue_message_index = 0x144; Sprite_ShowMessageMinimal(); sprite_E[k] = 1; } else { dialogue_message_index = 0x145; Sprite_ShowMessageMinimal(); sprite_delay_main[k] = 0x30; } } else if (j == 77) { if (sprite_E[k]) Sprite_Zora_RegurgitateFlippers(k); } break; } case 4: { // Submerge static const uint8 kZoraKing_Submerge_Gfx[21] = { 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, }; int j = sprite_delay_main[k]; if (!j) { Sprite_KillSelf(k); flag_is_link_immobilized = 0; } else { if (j == 29) { sprite_delay_aux2[k] = 15; Sprite_SpawnBigSplash(k); } sprite_graphics[k] = kZoraKing_Submerge_Gfx[sprite_delay_main[k] >> 1]; } break; } } } void Sprite_SpawnBigSplash(int k) { // 859b40 static const int8 kSpawnSplashRing_X[8] = {-8, -5, 4, 13, 16, 13, 4, -5}; static const int8 kSpawnSplashRing_Y[8] = {4, -5, -8, -5, 4, 13, 16, 13}; static const int8 kSpawnSplashRing_Xvel[8] = {-8, -6, 0, 6, 8, 6, 0, -6}; static const int8 kSpawnSplashRing_Yvel[8] = {0, -6, -8, -6, 0, 6, 8, 6}; SpriteSfx_QueueSfx2WithPan(k, 0x24); for (int i = 7; i >= 0; i--) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 8, &info); if (j >= 0) { sprite_state[j] = 3; Sprite_SetX(j, info.r0_x + kSpawnSplashRing_X[i] - 4); Sprite_SetY(j, info.r2_y + kSpawnSplashRing_Y[i] - 4); sprite_x_vel[j] = kSpawnSplashRing_Xvel[i]; sprite_y_vel[j] = kSpawnSplashRing_Yvel[i]; sprite_A[j] = i; sprite_z_vel[j] = (GetRandomNumber() & 15) + 24; sprite_ai_state[j] = 1; sprite_z[j] = 0; sprite_flags3[j] |= 0x40; sprite_ignore_projectile[j] = sprite_flags3[j]; } } } void ZoraKing_Draw(int k) { // 859cab PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; if (sprite_ai_state[k] >= 2) { static const int8 kZoraKing_Draw_X0[52] = { -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, 0, 0, 0, 0, 0, 0, 0, 0, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -9, 9, -9, 9, -10, 10, -10, 10, -11, 11, -11, 11, }; static const int8 kZoraKing_Draw_Y0[52] = { -18, -18, -2, -2, -18, -18, -2, -2, -18, -18, -2, -2, -12, -12, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -5, -5, 5, 5, -5, -5, 5, 5, -5, -5, 5, 5, }; static const uint8 kZoraKing_Draw_Char0[52] = { 0xc0, 0xc0, 0xe0, 0xe0, 0xc2, 0xea, 0xe2, 0xe2, 0xea, 0xc2, 0xe2, 0xe2, 0xc0, 0xc0, 0xe4, 0xe6, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc4, 0xc6, 0xe4, 0xe6, 0xc6, 0xc4, 0xe6, 0xe4, 0xe6, 0xe4, 0xc6, 0xc4, 0xe4, 0xe6, 0xc4, 0xc6, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, }; static const uint8 kZoraKing_Draw_Flags0[52] = { 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 5, 5, 5, 5, 5, 5, 0xc5, 0xc5, 0xc5, 0xc5, 5, 5, 5, 5, 0x45, 0x45, 0x45, 0x45, 0xc5, 0xc5, 0xc5, 0xc5, 0x85, 0x85, 0x85, 0x85, 4, 0x44, 0x84, 0xc4, 4, 0x44, 0x84, 0xc4, 4, 0x44, 0x84, 0xc4, }; OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; for (int i = 3; i >= 0; i--, oam++) { int j = g * 4 + i; oam->x = kZoraKing_Draw_X0[j] + info.x; oam->y = kZoraKing_Draw_Y0[j] + info.y; oam->charnum = kZoraKing_Draw_Char0[j]; uint8 f = kZoraKing_Draw_Flags0[j]; oam->flags = (f & 0xf ? f : f | info.flags) | 0x20; } Sprite_CorrectOamEntries(k, 3, 2); if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; } if (!sprite_delay_aux2[k]) return; static const int8 kZoraKing_Draw_X1[8] = {-23, 23, 23, 23, -20, -15, 13, 18}; static const int8 kZoraKing_Draw_Y1[8] = {-8, -8, -8, -8, -7, 0, 0, -7}; static const uint8 kZoraKing_Draw_Char1[8] = {0xae, 0xae, 0xae, 0xae, 0xac, 0xac, 0xac, 0xac}; static const uint8 kZoraKing_Draw_Flags1[8] = {0, 0x40, 0x40, 0x40, 0, 0, 0x40, 0x40}; Oam_AllocateFromRegionC(0x10); OamEnt *oam = GetOamCurPtr(); int g = (sprite_delay_aux2[k] >> 1) & 4; for (int i = 3; i >= 0; i--, oam++) { int j = g + i; oam->x = kZoraKing_Draw_X1[j] + info.x; oam->y = kZoraKing_Draw_Y1[j] + info.y; oam->charnum = kZoraKing_Draw_Char1[j]; oam->flags = kZoraKing_Draw_Flags1[j] | 0x24; bytewise_extended_oam[oam - oam_buf] = 2; } } void Sprite_56_WalkingZora(int k) { // 859d4a if (sprite_F[k]) { sprite_F[k] = 0; sprite_B[k] = 3; sprite_G[k] = 192; sprite_x_vel[k] = (int8)sprite_x_recoil[k] >> 1; sprite_y_vel[k] = (int8)sprite_y_recoil[k] >> 1; } PrepOamCoordsRet info; switch(sprite_B[k]) { case 0: // Waiting Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; if (!sprite_delay_main[k]) { sprite_delay_main[k] = 127; sprite_B[k]++; sprite_flags3[k] |= 64; } break; case 1: // Surfacing Zora_Draw(k); if (Sprite_ReturnIfInactive(k)) return; sprite_ignore_projectile[k] = sprite_delay_main[k]; if (!sprite_delay_main[k]) { sprite_flags3[k] &= ~0x40; SpriteSfx_QueueSfx2WithPan(k, 0x28); sprite_B[k]++; sprite_z_vel[k] = 48; sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL); } else { sprite_graphics[k] = kSprite_Zora_SurfacingGfx[sprite_delay_main[k] >> 3]; } break; case 2: // Ambulating sprite_graphics[k] = kSprite_Recruit_Gfx[(sprite_subtype2[k] >> 1 & 4) + sprite_D[k]]; WalkingZora_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k] - 1)) { if (sign8(sprite_z_vel[k] + 16)) Sprite_ZeroVelocity_XY(k); sprite_z[k] = 0; sprite_z_vel[k] = 0; if (!((k ^ frame_counter) & 15)) { int j = Sprite_DirectionToFaceLink(k, NULL); sprite_head_dir[k] = j; if (!((k ^ frame_counter) & 31)) { sprite_D[k] = j; Sprite_ApplySpeedTowardsLink(k, 8); } } } Sprite_MoveXY(k); Sprite_CheckTileCollision(k); if (sign8(sprite_z[k] - 1)) { WalkingZora_AdjustShadow(k); if (sprite_tiletype == 8) { Sprite_KillSelf(k); SpriteSfx_QueueSfx2WithPan(k, 0x28); sprite_state[k] = 3; sprite_delay_main[k] = 15; sprite_ai_state[k] = 0; sprite_flags2[k] = 3; } } sprite_subtype2[k]++; break; case 3: // Depressed Sprite_CheckDamageFromLink(k); if (!(frame_counter & 3) && !--sprite_G[k]) { sprite_B[k] = 2; if (sprite_state[k] == 10) { link_state_bits = 0; link_picking_throw_state = 0; } sprite_state[k] = 9; } if (sprite_G[k] < 48 && !(frame_counter & 1)) Sprite_SetX(k, Sprite_GetX(k) + (frame_counter & 2 ? -1 : 1)); sprite_graphics[k] = 0; sprite_wallcoll[k] = 0; WalkingZora_DrawWaterRipples(k); sprite_flags2[k] -= 2; SpriteDraw_SingleLarge(k); sprite_flags2[k] += 2; sprite_anim_clock[k] = 0; if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_MoveXY(k); ThrownSprite_TileAndSpriteInteraction(k); WalkingZora_AdjustShadow(k); break; } } void WalkingZora_AdjustShadow(int k) { // 859edb sprite_anim_clock[k] = (sprite_z[k] == 0 && sprite_tiletype == 9); } void WalkingZora_Draw(int k) { // 859f08 static const uint8 kWalkingZora_Draw_Char[4] = {0xce, 0xce, 0xa4, 0xee}; static const uint8 kWalkingZora_Draw_Flags[4] = {0x40, 0, 0, 0}; static const uint8 kWalkingZora_Draw_Char2[8] = {0xcc, 0xec, 0xcc, 0xec, 0xe8, 0xe8, 0xca, 0xca}; static const uint8 kWalkingZora_Draw_Flags2[8] = {0x40, 0x40, 0, 0, 0, 0x40, 0, 0x40}; PrepOamCoordsRet info; WalkingZora_DrawWaterRipples(k); if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; if (g == 0 || g == 2) info.y--; int i = sprite_head_dir[k]; oam->x = info.x; oam->y = ClampYForOam(info.y - 6); oam->charnum = kWalkingZora_Draw_Char[i]; oam->flags = info.flags | kWalkingZora_Draw_Flags[i]; bytewise_extended_oam[oam - oam_buf] = 2 | (info.x >> 8 & 1); oam++; oam->x = info.x; oam->y = ClampYForOam(info.y + 2); oam->charnum = kWalkingZora_Draw_Char2[g]; oam->flags = info.flags | kWalkingZora_Draw_Flags2[g]; bytewise_extended_oam[oam - oam_buf] = 2 | (info.x >> 8 & 1); if (!sprite_anim_clock[k]) SpriteDraw_Shadow(k, &info); } void WalkingZora_DrawWaterRipples(int k) { // 859fe0 if (sprite_anim_clock[k]) SpriteDraw_WaterRipple_WithOamAdjust(k); } void SpriteDraw_WaterRipple_WithOamAdjust(int k) { // 859fe5 SpriteDraw_WaterRipple(k); oam_cur_ptr += 8; oam_ext_cur_ptr += 2; } void SpriteDraw_WaterRipple(int k) { // 859ffa static const DrawMultipleData kWaterRipple_Dmd[6] = { {0, 10, 0x01d8, 0}, {8, 10, 0x41d8, 0}, {0, 10, 0x01d9, 0}, {8, 10, 0x41d9, 0}, {0, 10, 0x01da, 0}, {8, 10, 0x41da, 0}, }; static const uint8 kWaterRipple_Idx[4] = {0, 1, 2, 1}; Sprite_DrawMultiple(k, &kWaterRipple_Dmd[kWaterRipple_Idx[frame_counter >> 2 & 3] * 2], 2, NULL); OamEnt *oam = GetOamCurPtr(); uint8 t = (oam[0].flags & 0x30) | 0x4; oam[0].flags = t; oam[1].flags = t | 0x40; } void Sprite_53_ArmosKnight(int k) { // 85a036 static const uint8 kArmosKnight_Gfx1[5] = {5, 4, 3, 2, 1}; static const int8 kArmosKnight_Xv[2] = {16, -16}; sprite_obj_prio[k] |= 0x30; ArmosKnight_Draw(k); if (Sprite_ReturnIfPaused(k)) return; if (sprite_state[k] != 9) { if (sprite_delay_main[k]) { sprite_graphics[k] = kArmosKnight_Gfx1[sprite_delay_main[k] >> 3]; return; } if (--byte_7E0FF8 == 1) { for (int j = 5; j >= 0; j--) { sprite_health[j] = 48; sprite_x_vel[j] = sprite_y_vel[j] = sprite_z_vel[j] = 0; } } sprite_state[k] = 0; if (Sprite_CheckIfScreenIsClear()) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xea, &info); assert(j >= 0); Sprite_SetSpawnedCoordinates(j, &info); sprite_z_vel[j] = 32; sprite_A[j] = 1; } return; } Sprite_MoveXY(k); Sprite_MoveZ(k); sprite_z_vel[k] -= 4; if (sign8(sprite_z[k])) { sprite_z_vel[k] = 0; sprite_z[k] = 0; if (byte_7E0FF8 != 1 && sprite_A[k]) { sprite_z_vel[k] = 48; SpriteSfx_QueueSfx3WithPan(k, 0x16); } } if (sprite_F[k]) { Sprite_ZeroVelocity_XY(k); sprite_ai_state[k] = 0; sprite_G[k] = 0; } if (Sprite_ReturnIfRecoiling(k)) return; if (!sprite_A[k]) { if (!sprite_delay_main[k]) { sprite_A[k]++; sprite_flags2[k] = (sprite_flags2[k] & 0x7f) - 2; sprite_defl_bits[k] &= ~4; sprite_flags3[k] &= ~0x40; } else { if (sprite_delay_main[k] == 64) { sound_effect_1 = 0x35; } else if (sprite_delay_main[k] < 64) { int j = ((sprite_delay_main[k] >> 1) ^ k) & 1; sprite_x_vel[k] = kArmosKnight_Xv[j]; Sprite_MoveX(k); sprite_x_vel[k] = 0; } Sprite_CheckDamageFromLink(k); if (Sprite_CheckDamageToLink_same_layer(k)) { Sprite_NullifyHookshotDrag(); Sprite_RepelDash(); } } } else if (byte_7E0FF8 == 1) { Sprite_ArmosCrusher(k); } else { Sprite_CheckDamageToAndFromLink(k); if (!sprite_ai_state[k]) { uint16 x = overlord_y_hi[k] << 8 | overlord_x_hi[k]; uint16 y = overlord_floor[k] << 8 | overlord_gen2[k]; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16); sprite_x_vel[k] = pt.x; sprite_y_vel[k] = pt.y; Sprite_Get16BitCoords(k); if ((uint16)(x - cur_sprite_x + 2) < 4 && (uint16)(y - cur_sprite_y + 2) < 4) sprite_ai_state[k] = 1; } else { sprite_x_lo[k] = overlord_x_hi[k]; sprite_x_hi[k] = overlord_y_hi[k]; sprite_y_lo[k] = overlord_gen2[k]; sprite_y_hi[k] = overlord_floor[k]; } } } void ArmosKnight_Draw(int k) { // 85a274 static const int8 kArmosKnight_Draw_X[24] = { -8, 8, -8, 8, -10, 10, -10, 10, -10, 10, -10, 10, -12, 12, -12, 12, -14, 14, -14, 14, -16, 24, -16, 24, }; static const int8 kArmosKnight_Draw_Y[24] = { -8, -8, 8, 8, -10, -10, 10, 10, -10, -10, 10, 10, -12, -12, 12, 12, -14, -14, 14, 14, -16, -16, 24, 24, }; static const uint8 kArmosKnight_Draw_Char[24] = { 0xc0, 0xc2, 0xe0, 0xe2, 0xc0, 0xc2, 0xe0, 0xe2, 0xc4, 0xc4, 0xc4, 0xc4, 0xc6, 0xc6, 0xc6, 0xc6, 0xc8, 0xc8, 0xc8, 0xc8, 0xd8, 0xd8, 0xd8, 0xd8, }; static const uint8 kArmosKnight_Draw_Flags[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80, }; static const uint8 kArmosKnight_Draw_Ext[24] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, }; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; if (!sprite_A[k] && submodule_index != 7) Oam_AllocateDeferToPlayer(k); OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; for (int i = 3; i >= 0; i--, oam++) { int j = g * 4 + i; uint16 x = info.x + kArmosKnight_Draw_X[j]; uint16 y = info.y + kArmosKnight_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kArmosKnight_Draw_Char[j]; oam->flags = kArmosKnight_Draw_Flags[j] | info.flags; bytewise_extended_oam[oam - oam_buf] = kArmosKnight_Draw_Ext[j] | (x >> 8 & 1); } if (g != 0) return; if (sprite_A[k]) { int spr_idx = 76 + k * 2; oam_cur_ptr = 0x800 + spr_idx * 4; oam_ext_cur_ptr = 0xA20 + spr_idx; } oam = GetOamCurPtr(); int z = sprite_z[k]; z = ((z >= 32) ? 32 : z) >> 3; uint16 y = Sprite_GetY(k) - BG2VOFS_copy2; oam[4].x = info.x - 8 + z; oam[5].x = info.x + 8 - z; if ((uint16)(y + 12 + 16) < 0x100) { oam[5].y = oam[4].y = y + 12; } else { oam[5].y = oam[4].y = 0xf0; } oam[5].charnum = oam[4].charnum = 0xe4; oam[4].flags = 0x25; oam[5].flags = 0x25 | 0x40; bytewise_extended_oam[oam + 4 - oam_buf] = 2; bytewise_extended_oam[oam + 5 - oam_buf] = 2; } void Sprite_54_Lanmolas(int k) { // 85a3a2 static const uint8 kLanmola_RandB[8] = {0x58, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0x98}; static const uint8 kLanmola_RandC[8] = {0x68, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xa8, 0x80}; static const int8 kLanmola_ZVel[2] = {2, -2}; PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); Lanmola_Draw(k); if (Sprite_ReturnIfPaused(k)) return; switch(sprite_ai_state[k]) { case 0: if (!(sprite_delay_main[k] | sprite_pause[k])) { sprite_delay_main[k] = 127; sprite_ai_state[k] = 1; SpriteSfx_QueueSfx2WithPan(k, 0x35); } break; case 1: if (!sprite_delay_main[k]) { Lanmola_SpawnShrapnel(k); sound_effect_ambient = 0x13; sprite_B[k] = kLanmola_RandB[GetRandomNumber() & 7]; sprite_C[k] = kLanmola_RandC[GetRandomNumber() & 7]; sprite_ai_state[k] = 2; sprite_z_vel[k] = 24; sprite_anim_clock[k] = 0; sprite_G[k] = 0; lbl_a: sprite_D[k] = sprite_x_lo[k]; sprite_wallcoll[k] = sprite_y_lo[k]; sprite_delay_aux1[k] = 74; } break; case 2: { Sprite_CheckDamageToAndFromLink(k); Sprite_MoveZ(k); if (!sprite_anim_clock[k]) { if (!--sprite_z_vel[k]) sprite_anim_clock[k]++; } else if ((frame_counter & 1) == 0) { int j = sprite_G[k] & 1; if ((sprite_z_vel[k] += kLanmola_ZVel[j]) == (uint8)kDesertBarrier_Xv[j]) sprite_G[k]++; } uint16 x = Sprite_GetX(k), y = Sprite_GetY(k); uint16 x2 = sprite_x_hi[k] << 8 | sprite_B[k]; uint16 y2 = sprite_y_hi[k] << 8 | sprite_C[k]; if ((uint16)(x - x2 + 2) < 4 && (uint16)(y - y2 + 2) < 4) sprite_ai_state[k] = 3; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x2, y2, 10); sprite_y_vel[k] = pt.y; sprite_x_vel[k] = pt.x; Sprite_MoveXY(k); break; } case 3: Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); Sprite_MoveZ(k); if (!sign8(sprite_z_vel[k] + 20)) sprite_z_vel[k] -= 1; if (sign8(sprite_z[k])) { sprite_ai_state[k] = 4; sprite_delay_main[k] = 128; goto lbl_a; } break; case 4: if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_x_lo[k] = kLanmola_RandB[GetRandomNumber() & 7]; sprite_y_lo[k] = kLanmola_RandC[GetRandomNumber() & 7]; } break; case 5: if (!sprite_delay_main[k]) { sprite_state[k] = 0; if (Sprite_CheckIfScreenIsClear()) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xEA, &info); assert(j >= 0); Sprite_SetSpawnedCoordinates(j, &info); sprite_z_vel[j] = 32; sprite_A[j] = 3; } } if (sprite_delay_main[k] >= 32 && sprite_delay_main[k] < 160 && !(sprite_delay_main[k] & 15)) { int i = ((sprite_subtype2[k] - garnish_y_lo[k] * 8) & 0x3f) + k * 0x40; uint8 xlo = moldorm_x_lo[i] - BG2HOFS_copy2; uint8 ylo = moldorm_y_lo[i] - beamos_x_hi[i] - BG2VOFS_copy2; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x00, &info); if (j >= 0) { load_chr_halfslot_even_odd = 11; sprite_state[j] = 4; sprite_delay_main[j] = 31; sprite_A[j] = 31; Sprite_SetX(j, BG2HOFS_copy2 + xlo); Sprite_SetY(j, BG2VOFS_copy2 + ylo); sprite_flags2[j] = 3; sprite_oam_flags[j] = 0xc; SpriteSfx_QueueSfx2WithPan(k, 0xc); if (!sign8(garnish_y_lo[k])) garnish_y_lo[k]--; } } break; } } void Lanmola_Draw(int k) { // 85a64a static const uint8 kLanmola_SprOffs[4] = {76, 60, 44, 28}; static const uint8 kLanmola_Draw_Char1[16] = {0xc4, 0xe2, 0xc2, 0xe0, 0xc0, 0xe0, 0xc2, 0xe2, 0xc4, 0xe2, 0xc2, 0xe0, 0xc0, 0xe0, 0xc2, 0xe2}; static const uint8 kLanmola_Draw_Char0[16] = {0xcc, 0xe4, 0xca, 0xe6, 0xc8, 0xe6, 0xca, 0xe4, 0xcc, 0xe4, 0xca, 0xe6, 0xc8, 0xe6, 0xca, 0xe4}; static const uint8 kLanmola_Draw_Flags[16] = {0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40}; int spr_offs = kLanmola_SprOffs[k]; oam_cur_ptr = 0x800 + spr_offs * 4; oam_ext_cur_ptr = 0xA20 + spr_offs; sprite_graphics[k] = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k] - sprite_z_vel[k]); uint8 r2 = sprite_subtype2[k], r5 = r2; int j = k * 64 + r2; moldorm_x_lo[j] = sprite_x_lo[k]; moldorm_y_lo[j] = sprite_y_lo[k]; beamos_x_hi[j] = sprite_z[k]; beamos_y_hi[j] = sprite_graphics[k]; if (sprite_state[k] == 9 && !(submodule_index | flag_unk1)) sprite_subtype2[k] = sprite_subtype2[k] + 1 & 63; uint8 r3 = sprite_oam_flags[k] | sprite_obj_prio[k]; uint8 n = garnish_y_lo[k]; if (sign8(n)) return; j = sign8(sprite_y_vel[k]) ? 1 : 0; int oam_step = (j ? -1 : 1); OamEnt *oam = GetOamCurPtr() + (j ? 7 : 0); uint8 i = n; do { int j = r2 + k * 64; r2 = r2 - 8 & 63; oam->x = moldorm_x_lo[j] - BG2HOFS_copy2; if (!sign8(beamos_x_hi[j])) oam->y = moldorm_y_lo[j] - beamos_x_hi[j] - BG2VOFS_copy2; j = beamos_y_hi[j]; if (n != 7 || i != 0) { oam->charnum = (n == i) ? kLanmola_Draw_Char1[j] : 0xc6; } else { oam->charnum = kLanmola_Draw_Char0[j]; } oam->flags = kLanmola_Draw_Flags[j] | r3; bytewise_extended_oam[oam - oam_buf] = 2; } while (oam += oam_step, !sign8(--i)); oam = GetOamCurPtr() + 8; i = n; do { int j = r5 + k * 64; r5 = r5 - 8 & 63; oam->x = moldorm_x_lo[j] - BG2HOFS_copy2; if (!sign8(beamos_x_hi[j])) oam->y = moldorm_y_lo[j] + 10 - BG2VOFS_copy2; oam->charnum = 0x6c; oam->flags = 0x34; bytewise_extended_oam[oam - oam_buf] = 2; } while (oam++, !sign8(--i)); if (sprite_ai_state[k] == 1) { static const uint8 kLanmola_Draw_Idx2[16] = {4, 5, 4, 5, 4, 5, 4, 5, 4, 3, 2, 2, 1, 1, 0, 0}; static const uint8 kLanmola_Draw_Char2[6] = {0xee, 0xee, 0xec, 0xec, 0xce, 0xce}; static const uint8 kLanmola_Draw_Flags2[6] = {0, 0x40, 0, 0x40, 0, 0x40}; Oam_AllocateFromRegionB(4); OamEnt *oam = GetOamCurPtr(); oam->x = sprite_x_lo[k] - BG2HOFS_copy2; oam->y = sprite_y_lo[k] - BG2VOFS_copy2; j = kLanmola_Draw_Idx2[sprite_delay_main[k] >> 3]; oam->charnum = kLanmola_Draw_Char2[j]; oam->flags = kLanmola_Draw_Flags2[j] | 0x31; bytewise_extended_oam[oam - oam_buf] = 2; } else if (sprite_ai_state[k] != 5 && sprite_delay_aux1[k] != 0) { static const int8 kLanmola_Draw_X4[8] = {-8, 8, -10, 10, -16, 16, -24, 32}; static const int8 kLanmola_Draw_Y4[8] = {0, 0, -1, -1, -1, -1, 3, 3}; static const uint8 kLanmola_Draw_Char4[8] = {0xe8, 0xe8, 0xe8, 0xe8, 0xea, 0xea, 0xea, 0xea}; static const uint8 kLanmola_Draw_Flags4[8] = {0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40}; static const uint8 kLanmola_Draw_Ext4[8] = {2, 2, 2, 2, 2, 2, 0, 0}; if (((sprite_y_vel[k] >> 6) ^ sprite_ai_state[k]) & 2) Oam_AllocateFromRegionB(8); else Oam_AllocateFromRegionC(8); OamEnt *oam = GetOamCurPtr(); uint8 r6 = (((sprite_delay_aux1[k] >> 2) & 3) ^ 3) * 2; uint8 x = sprite_D[k] - BG2HOFS_copy2; uint8 y = sprite_wallcoll[k] - BG2VOFS_copy2; for (int i = 1; i >= 0; i--, oam++) { int j = i + r6; oam->x = x + kLanmola_Draw_X4[j]; oam->y = y + kLanmola_Draw_Y4[j]; oam->charnum = kLanmola_Draw_Char4[j]; oam->flags = kLanmola_Draw_Flags4[j] | 0x31; bytewise_extended_oam[oam - oam_buf] = kLanmola_Draw_Ext4[j]; } } } void Sprite_6D_Rat(int k) { // 85a8b0 static const uint8 kSpriteRat_Tab0[16] = {0, 0, 3, 3, 1, 2, 4, 5, 1, 2, 4, 5, 0, 0, 3, 3}; static const uint8 kSpriteRat_Tab1[16] = {0, 0x40, 0, 0x40, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x80, 0xc0, 0x80, 0xc0}; static const uint8 kSpriteRat_Tab2[8] = {10, 11, 6, 7, 2, 3, 14, 15}; static const uint8 kSpriteRat_Tab4[8] = {8, 9, 4, 5, 0, 1, 12, 13}; static const int8 kSpriteRat_Xvel[4] = {24, -24, 0, 0}; static const int8 kSpriteRat_Yvel[4] = {0, 0, 24, -24}; static const uint8 kSpriteRat_Tab3[4] = {2, 3, 1, 0}; int j = sprite_A[k]; sprite_graphics[k] = kSpriteRat_Tab0[j]; sprite_oam_flags[k] = (sprite_oam_flags[k] & 0x3f) | kSpriteRat_Tab1[j]; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); Sprite_CheckTileCollision(k); if (sprite_ai_state[k] != 0) { if (sprite_delay_main[k] == 0) { if (is_in_dark_world == 0) SpriteSfx_QueueSfx3WithPan(k, 0x17); sprite_ai_state[k] = 0; sprite_delay_main[k] = 80; } j = sprite_D[k]; if (sprite_wallcoll[k] != 0) sprite_D[k] = j = kSpriteRat_Tab3[j]; sprite_x_vel[k] = kSpriteRat_Xvel[j]; sprite_y_vel[k] = kSpriteRat_Yvel[j]; sprite_A[k] = kSpriteRat_Tab4[sprite_D[k] * 2 + (frame_counter >> 2 & 1)]; } else { Sprite_ZeroVelocity_XY(k); if (sprite_delay_main[k] == 0) { uint8 a = GetRandomNumber(); sprite_D[k] = a & 3; sprite_ai_state[k]++; sprite_delay_main[k] = (a & 0x7f) + 0x40; } sprite_A[k] = kSpriteRat_Tab2[sprite_D[k] * 2 + (frame_counter >> 3 & 1)]; } } void Sprite_6E_Rope(int k) { // 85a973 int j; j = sprite_A[k]; sprite_graphics[k] = kSpriteRope_Gfx[j]; sprite_oam_flags[k] = (sprite_oam_flags[k] & 0x3f) | kSpriteRope_Flags[j]; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_E[k]) { OamEnt *oam = GetOamCurPtr(); oam[0].flags |= 0x30; uint8 old_z = sprite_z[k]; Sprite_MoveZ(k); if (!sign8(sprite_z_vel[k] - 0xc0)) sprite_z_vel[k] -= 2; if (!sign8(old_z ^ sprite_z[k]) || !sign8(sprite_z[k])) return; sprite_z[k] = 0; sprite_z_vel[k] = 0; sprite_E[k] = 0; sprite_flags3[k] &= ~0x10; } else { sprite_flags2[k] = 0; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); Sprite_CheckTileCollision(k); if (sprite_ai_state[k] != 0) { if (sprite_delay_main[k] == 0) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 32; } j = sprite_D[k]; if (sprite_wallcoll[k] != 0) sprite_D[k] = j = kSpriteRope_Tab0[j]; j += sprite_G[k]; sprite_x_vel[k] = kSpriteRope_Xvel[j]; sprite_y_vel[k] = kSpriteRope_Yvel[j]; int i = frame_counter; if (j < 4) i >>= 1; sprite_A[k] = kSpriteRope_Tab1[sprite_D[k] * 2 + (i >> 1 & 1)]; } else { Sprite_ZeroVelocity_XY(k); if (sprite_delay_main[k] == 0) { sprite_G[k] = 0; uint8 a = GetRandomNumber(); sprite_D[k] = a & 3; sprite_ai_state[k]++; sprite_delay_main[k] = (a & 0x7f) + 0x40; PointU8 pt; uint8 dir = Sprite_DirectionToFaceLink(k, &pt); if ((uint8)(pt.y + 0x10) < 0x20 || (uint8)(pt.x + 0x18) < 0x20) { sprite_G[k] = 4; sprite_D[k] = dir; } } sprite_A[k] = kSpriteRope_Tab1[sprite_D[k] * 2 + (frame_counter >> 3 & 1)]; } } } void Sprite_6F_Keese(int k) { // 85aa8b static const int8 kSpriteKeese_Tab1[2] = {1, -1}; static const int8 kSpriteKeese_Tab0[4] = {2, 10, 6, 14}; sprite_obj_prio[k] |= 0x30; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); if (sprite_ai_state[k]) { if (sprite_delay_main[k] == 0) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 64; sprite_graphics[k] = 0; Sprite_ZeroVelocity_XY(k); } else { if ((sprite_delay_main[k] & 7) == 0) { sprite_A[k] += kSpriteKeese_Tab1[sprite_B[k] & 1]; if (!(GetRandomNumber() & 3)) sprite_B[k]++; } int j = sprite_A[k] & 0xf; sprite_x_vel[k] = kSpriteKeese_Tab2[j]; sprite_y_vel[k] = kSpriteKeese_Tab3[j]; sprite_graphics[k] = ((frame_counter >> 2) & 1) + 1; } } else { if ((k ^ frame_counter) & 3 | sprite_delay_main[k]) return; PointU8 pt; uint8 dir = Sprite_DirectionToFaceLink(k, &pt); if ((uint8)(pt.y + 0x28) >= 0x50 || (uint8)(pt.x + 0x28) >= 0x50) return; SpriteSfx_QueueSfx3WithPan(k, 0x1e); sprite_ai_state[k]++; sprite_delay_main[k] = 64; sprite_B[k] = 64; sprite_A[k] = kSpriteKeese_Tab0[dir]; } } void Sprite_Cannonball(int k) { // 85ab54 SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXY(k); if (sprite_delay_main[k] == 30) { Sprite_SpawnPoofGarnish(k); } else if (sprite_delay_main[k] == 0 && Sprite_CheckTileCollision(k)) { sprite_state[k] = 0; sprite_x_lo[k] += 4; sprite_y_lo[k] += 4; Sprite_PlaceRupulseSpark_2(k); SpriteSfx_QueueSfx2WithPan(k, 0x5); } Sprite_CheckDamageToAndFromLink(k); } void Sprite_SpawnPoofGarnish(int j) { // 85ab9c int k = GarnishAllocForce(); garnish_type[k] = 10; garnish_active = 10; garnish_x_lo[k] = sprite_x_lo[j]; garnish_x_hi[k] = sprite_x_hi[j]; int y = Sprite_GetY(j) + 16; garnish_y_lo[k] = y; garnish_y_hi[k] = y >> 8; garnish_sprite[k] = sprite_floor[j]; garnish_countdown[k] = 15; } void Sprite_6C_MirrorPortal(int k) { // 85af75 if (savegame_is_darkworld) { sprite_state[k] = 0; } else { if (BYTE(overworld_screen_index) >= 0x80) return; if (submodule_index != 0x23 && byte_7E0FC6 < 3) SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; int j = frame_counter >> 2 & 3; sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kSprite_WarpVortex_Flags[j]; if (Sprite_CheckIfLinkIsBusy()) return; if (Sprite_CheckDamageToLink_same_layer(k)) { if (sprite_A[k] && (link_disable_sprite_damage | countdown_for_blink) == 0 && !flag_is_link_immobilized) { submodule_index = 0x23; link_triggered_by_whirlpool_sprite = 1; subsubmodule_index = 0; link_actual_vel_y = 0; link_actual_vel_x = 0; link_player_handler_state = kPlayerState_Mirror; last_light_vs_dark_world = overworld_screen_index & 0x40; sprite_state[k] = 0; } } else { sprite_A[k] = 1; } } if (++sprite_B[k] == 0) sprite_A[k] = 1; sprite_x_lo[k] = bird_travel_x_lo[15]; sprite_x_hi[k] = bird_travel_x_hi[15]; int t = (bird_travel_y_lo[15] | (bird_travel_y_hi[15] << 8)) + 8; sprite_y_lo[k] = t; sprite_y_hi[k] = t >> 8; } void Sprite_6A_BallNChain(int k) { // 85b01b ChainBallTrooper_Draw(k); if (sprite_ai_state[k] < 2) HIBYTE(dungmap_var8) = 0x80; if (Sprite_ReturnIfInactive(k)) return; Guard_ParrySwordAttacks(k); int t = sprite_B[k] << 8 | sprite_A[k]; t += kChainBallTrooper_Tab1[sprite_ai_state[k]]; sprite_A[k] = t; sprite_B[k] = t >> 8 & 1; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckTileCollision(k); Sprite_MoveXY(k); Sprite_CheckDamageToLink(k); PointU8 pt = { 0, 0 }; if (((k ^ frame_counter) & 0xf) == 0) sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, &pt); switch (sprite_ai_state[k]) { case 0: if (((k ^ frame_counter) & 0xf) == 0) { sprite_D[k] = sprite_head_dir[k]; if ((uint8)(pt.y + 0x40) < 0x68 && (uint8)(pt.x + 0x30) < 0x60) { sprite_ai_state[k]++; sprite_delay_main[k] = 24; return; } Sprite_ApplySpeedTowardsLink(k, 8); } BallNChain_Animate(k); break; case 1: Sprite_ZeroVelocity_XY(k); if (!sprite_delay_main[k]) { sprite_delay_main[k] = 48; sprite_ai_state[k]++; } break; case 2: if (!sprite_delay_main[k] && sprite_head_dir[k] == kFlailTrooperAttackDir[(sprite_A[k] >> 7 & 1) + sprite_B[k] * 2]) { sprite_ai_state[k]++; sprite_delay_aux2[k] = 31; } attack_common: sprite_subtype2[k]++; BallNChain_Animate(k); if (((k ^ frame_counter) & 0xf) == 0) SpriteSfx_QueueSfx3WithPan(k, 6); break; case 3: Sprite_ZeroVelocity_XY(k); t = sprite_delay_aux2[k]; if (t == 0) sprite_ai_state[k] = 0; else if (t >= 0x10) goto attack_common; sprite_subtype2[k]++; BallNChain_Animate(k); break; } } void BallNChain_Animate(int k) { // 85b0ab sprite_graphics[k] = kFlailTrooperGfx[sprite_D[k] * 8 + (++sprite_subtype2[k] >> 2 & 7)]; } void SpriteDraw_GuardHead(int k, PrepOamCoordsRet *info, int spr_offs) { // 85b160 int j = sprite_head_dir[k]; OamEnt *oam = GetOamCurPtr() + spr_offs; uint16 x = info->x, y = info->y - 9; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kChainBallTrooperHead_Char[j]; oam->flags = info->flags | kChainBallTrooperHead_Flags[j]; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } void SpriteDraw_BNCBody(int k, PrepOamCoordsRet *info, int spr_offs) { // 85b3cb int g = sprite_graphics[k]; spr_offs += kFlailTrooperBody_SprOffs[g] >> 2; OamEnt *oam = GetOamCurPtr() + spr_offs; int n = kFlailTrooperBody_Num[g]; do { int j = g * 3 + n; uint16 x = info->x + kFlailTrooperBody_X[j]; uint16 y = info->y + kFlailTrooperBody_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kFlailTrooperBody_Char[j]; oam->flags = info->flags | kFlailTrooperBody_Flags[j]; bytewise_extended_oam[oam - oam_buf] = kFlailTrooperBody_Ext[j] | (x >> 8 & 1); if (n == 2) oam++; } while (oam++, --n >= 0); } void SpriteDraw_BNCFlail(int k, PrepOamCoordsRet *info) { // 85b468 OamEnt *oam = GetOamCurPtr(); BYTE(dungmap_var7) = info->x; HIBYTE(dungmap_var7) = info->y; uint8 t; uint16 r0 = sprite_A[k] | sprite_B[k] << 8; uint8 qq = sprite_ai_state[k] < 2 ? 0 : kFlailTrooperWeapon_Tab0[sprite_delay_aux2[k]]; uint8 r12 = kFlailTrooperWeapon_Tab1[sprite_D[k]]; uint8 r13 = kFlailTrooperWeapon_Tab2[sprite_D[k]]; uint16 r10 = (r0 & 0x1ff) >> 6; uint16 r2 = (r0 + 0x80) & 0x1ff; uint8 r14 = ChainBallMult(kSinusLookupTable[r0 & 0xff], qq); uint8 r4 = (r0 & 0x100) ? -r14 : r14; uint8 r15 = ChainBallMult(kSinusLookupTable[r2 & 0xff], qq); uint8 r6 = (r2 & 0x100) ? -r15 : r15; HIBYTE(dungmap_var8) = r4 - 4 + r12; BYTE(dungmap_var8) = r6 - 4 + r13; oam[0].x = HIBYTE(dungmap_var8) + BYTE(dungmap_var7); oam[0].y = BYTE(dungmap_var8) + HIBYTE(dungmap_var7); oam[0].charnum = 0x2a; oam[0].flags = 0x2d; bytewise_extended_oam[oam - oam_buf] = 2; oam++; for (int i = 3; i >= 0; i--, oam++) { t = (kFlailTrooperWeapon_Tab4[i] * r14) >> 8; t = sign8(r4) ? -t : t; oam->x = t + BYTE(dungmap_var7) + r12; t = (kFlailTrooperWeapon_Tab4[i] * r15) >> 8; t = sign8(r6) ? -t : t; oam->y = t + HIBYTE(dungmap_var7) + r13; oam->charnum = 0x3f; oam->flags = 0x2d; bytewise_extended_oam[oam - oam_buf] = 0; } Sprite_CorrectOamEntries(k, 4, 0xff); } void Sprite_50_Cannonball(int k) { // 85b648 if (!sprite_ai_state[k]) SpriteDraw_SingleLarge(k); else SpriteDraw_BigCannonball(k); if (Sprite_ReturnIfInactive(k)) return; sprite_graphics[k] = ++sprite_subtype2[k] >> 2 & 1; Sprite_MoveXY(k); if (sprite_delay_main[k]) { if (sprite_delay_main[k] == 1) sprite_state[k] = 0; return; } Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_aux2[k] && Sprite_CheckTileCollision(k)) sprite_delay_main[k] = 16; } void SpriteDraw_BigCannonball(int k) { // 85b6a4 static const int8 kMetalBallLarge_X[4] = {-8, 8, -8, 8}; static const int8 kMetalBallLarge_Y[4] = {-8, -8, 8, 8}; static const uint8 kMetalBallLarge_Char[8] = {0x84, 0x88, 0x88, 0x88, 0x86, 0x88, 0x88, 0x88}; static const uint8 kMetalBallLarge_Flags[4] = {0, 0, 0xc0, 0x80}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; for (int i = 3; i >= 0; i--, oam++) { uint16 x = info.x + kMetalBallLarge_X[i]; uint16 y = info.y + kMetalBallLarge_Y[i]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kMetalBallLarge_Char[g * 4 + i]; oam->flags = kMetalBallLarge_Flags[i] | info.flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } } void Sprite_51_ArmosStatue(int k) { // 85b703 Armos_Draw(k); if (sprite_F[k]) Sprite_ZeroVelocity_XY(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = 0; Sprite_ZeroVelocity_XY(k); } if (!sprite_ai_state[k]) { sprite_flags3[k] |= 0x40; if (sprite_delay_main[k] == 1) { sprite_flags3[k] &= ~0x40; sprite_ai_state[k]++; sprite_flags2[k] &= ~0x80; sprite_flags3[k] &= ~0x40; sprite_oam_flags[k] = 0xb; } else { if (!((k ^ frame_counter) & 3) && (uint16)(link_x_coord - cur_sprite_x + 31) < 62 && (uint16)(link_y_coord + 8 - cur_sprite_y + 48) < 88 && !sprite_delay_main[k]) { sprite_delay_main[k] = 48; SpriteSfx_QueueSfx2WithPan(k, 0x22); } if (Sprite_CheckDamageToLink_same_layer(k)) { Sprite_NullifyHookshotDrag(); Sprite_RepelDash(); } if (sprite_delay_main[k]) sprite_oam_flags[k] ^= (sprite_delay_main[k] >> 1) & 0xe; } } else { Sprite_CheckDamageToAndFromLink(k); if (Sprite_ReturnIfRecoiling(k)) return; Sprite_MoveXY(k); Sprite_CheckTileCollision(k); if ((sprite_delay_main[k] | sprite_z[k]) == 0) { sprite_delay_main[k] = 8; sprite_z_vel[k] = 16; Sprite_ApplySpeedTowardsLink(k, 12); } } } void Armos_Draw(int k) { // 85b7ef static const DrawMultipleData kArmos_Dmd[2] = { {0, -16, 0x00c0, 2}, {0, 0, 0x00e0, 2}, }; PrepOamCoordsRet info; if (!sprite_ai_state[k]) { if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; } Sprite_DrawMultiple(k, &kArmos_Dmd[0], 2, &info); SpriteDraw_Shadow(k, &info); } void Sprite_4E_Popo(int k) { // 85b80a Bot_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; sprite_subtype2[k]++; sprite_A[k] = sprite_subtype2[k] >> 4 & 3; Sprite_CheckDamageToAndFromLink(k); switch (sprite_ai_state[k]) { case 0: if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 105; } break; case 1: sprite_subtype2[k]++; if (!sprite_delay_main[k]) { sprite_delay_main[k] = (GetRandomNumber() & 63) + 128; sprite_ai_state[k]++; int j = GetRandomNumber() & 15; sprite_x_vel[k] = kSpriteKeese_Tab2[j] << 2; sprite_y_vel[k] = kSpriteKeese_Tab3[j] << 2; } break; case 2: sprite_subtype2[k]++; if (sprite_delay_main[k]) { if ((k ^ frame_counter) & sprite_B[k]) { Sprite_CheckTileCollision(k); return; } Sprite_MoveXY(k); if (!sprite_wallcoll[k]) { Sprite_CheckTileCollision(k); return; } } sprite_ai_state[k] = 0; sprite_delay_main[k] = 80; break; } } void Bot_Draw(int k) { // 85b89a static const uint8 kBot_Gfx[4] = {0, 1, 0, 1}; static const uint8 kBot_OamFlags[4] = {0, 0, 0x40, 0x40}; int j = sprite_A[k]; sprite_graphics[k] = kBot_Gfx[j]; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kBot_OamFlags[j]; SpriteDraw_SingleLarge(k); } void Sprite_4C_Geldman(int k) { // 85b8b3 static const uint8 kGerudoMan_EmergeGfx[8] = {3, 2, 0, 0, 0, 0, 0, 0}; static const uint8 kGerudoMan_PursueGfx[2] = {4, 5}; static const uint8 kGerudoMan_SubmergeGfx[5] = {0, 1, 2, 3, 3}; PrepOamCoordsRet info; if (sprite_ai_state[k] < 2) Sprite_PrepOamCoord(k, &info); else GerudoMan_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; sprite_ignore_projectile[k] = 1; switch (sprite_ai_state[k]) { case 0: // return if (!sprite_delay_main[k]) { sprite_x_lo[k] = sprite_A[k]; sprite_x_hi[k] = sprite_B[k]; sprite_y_lo[k] = sprite_C[k]; sprite_y_hi[k] = sprite_head_dir[k]; sprite_ai_state[k] = 1; } break; case 1: // wait if (!((k ^ frame_counter) & 7) && (uint16)(link_x_coord - cur_sprite_x + 0x30) < 0x60 && (uint16)(link_y_coord - cur_sprite_y + 0x30) < 0x60) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 31; } break; case 2: // emerge if (!sprite_delay_main[k]) { sprite_ai_state[k] = 3; sprite_delay_main[k] = 96; Sprite_ApplySpeedTowardsLink(k, 16); } else { sprite_graphics[k] = kGerudoMan_EmergeGfx[sprite_delay_main[k] >> 2]; } break; case 3: // pursue sprite_ignore_projectile[k] = 0; if (!sprite_delay_main[k]) { sprite_ai_state[k] = 4; sprite_delay_main[k] = 8; } else { sprite_graphics[k] = kGerudoMan_PursueGfx[sprite_delay_main[k] >> 2 & 1]; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); } break; case 4: // submerge if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 16; } else { sprite_graphics[k] = kGerudoMan_SubmergeGfx[sprite_delay_main[k] >> 1]; } break; } } void GerudoMan_Draw(int k) { // 85ba24 static const int8 kGerudoMan_Draw_X[18] = { 4, 4, 4, 4, 4, 4, -8, 8, 8, -8, 8, 8, -16, 0, 16, -16, 0, 16 }; static const int8 kGerudoMan_Draw_Y[18] = { 8, 8, 8, 8, 8, 8, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const uint8 kGerudoMan_Draw_Char[18] = { 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa4, 0xa2, 0xa0, 0xa0, 0xa2, 0xa4, }; static const uint8 kGerudoMan_Draw_Flags[18] = { 0, 0, 0, 0x40, 0x40, 0x40, 0, 0x40, 0x40, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0, }; static const uint8 kGerudoMan_Draw_Ext[18] = { 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; for (int i = 2; i >= 0; i--, oam++) { int j = g * 3 + i; uint16 x = info.x + kGerudoMan_Draw_X[j]; uint16 y = info.y + kGerudoMan_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kGerudoMan_Draw_Char[j]; oam->flags = kGerudoMan_Draw_Flags[j] | info.flags; bytewise_extended_oam[oam - oam_buf] = kGerudoMan_Draw_Ext[j] | (x >> 8 & 1); } } void Sprite_4D_Toppo(int k) { // 85ba85 static const int8 kToppo_XOffs[4] = {-32, 32, 0, 0}; static const int8 kToppo_YOffs[4] = {0, 0, -32, 32}; if (sprite_ai_state[k]) { sprite_obj_prio[k] |= 0x30; Toppo_Draw(k); } if (Sprite_ReturnIfInactive(k)) return; switch (sprite_ai_state[k]) { case 0: // Toppo_Hiding if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 8; int j = GetRandomNumber() & 3; uint16 x = sprite_A[k] | sprite_B[k] << 8; uint16 y = sprite_C[k] | sprite_head_dir[k] << 8; Sprite_SetX(k, x + kToppo_XOffs[j]); Sprite_SetY(k, y + kToppo_YOffs[j]); } break; case 1: // Toppo_RustleGrass if (!sprite_delay_main[k]) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 16; } else { sprite_graphics[k] = sprite_delay_main[k] >> 2 & 1; Toppo_VerifyTile(k); } break; case 2: // Toppo_PokingOut if (!sprite_delay_main[k]) { sprite_ai_state[k] = 3; sprite_z_vel[k] = 64; } sprite_graphics[k] = 2; Toppo_VerifyTile(k); break; case 3: // Toppo_Leaping Sprite_CheckDamageToAndFromLink(k); Sprite_MoveZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_ai_state[k] = 4; sprite_delay_main[k] = 16; Toppo_VerifyTile(k); } break; case 4: // Toppo_Retreat if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 32; } else { sprite_graphics[k] = sprite_delay_main[k] >> 2 & 1; } Toppo_VerifyTile(k); break; case 5: // Toppo_Flustered Toppo_Flustered(k); break; } } void Toppo_VerifyTile(int k) { // 85bb72 uint16 x = Sprite_GetX(k); if (GetTileAttribute(0, &x, Sprite_GetY(k)) != 0x40) sprite_ai_state[k] = 5; } void Toppo_Draw(int k) { // 85bbff static const int8 kToppo_Draw_X[15] = {0, 8, 8, 0, 8, 8, 0, 0, 8, 0, 0, 0, 0, 0, 0}; static const int8 kToppo_Draw_Y[15] = {8, 8, 8, 8, 8, 8, 0, 8, 8, 0, 0, 0, 0, 0, 0}; static const uint8 kToppo_Draw_Char[15] = {0xc8, 0xc8, 0xc8, 0xca, 0xca, 0xca, 0xc0, 0xc8, 0xc8, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2}; static const uint8 kToppo_Draw_Flags[15] = {0, 0x40, 0x40, 0, 0x40, 0x40, 0, 0, 0x40, 0, 0, 0, 0x40, 0x40, 0x40}; static const uint8 kToppo_Draw_Ext[15] = {0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2, 2}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; uint16 ybase = Sprite_GetY(k) - BG2VOFS_copy2; for (int i = 2; i >= 0; i--, oam++) { int j = i + g * 3; uint8 ext = kToppo_Draw_Ext[j]; uint16 x = info.x + kToppo_Draw_X[j]; uint16 y = (ext ? info.y : ybase) + kToppo_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kToppo_Draw_Char[j]; uint8 flags = kToppo_Draw_Flags[j] | info.flags; if (ext == 0) flags = flags & ~0xf | 2; oam->flags = flags; bytewise_extended_oam[oam - oam_buf] = ext | (x >> 8 & 1); } } void Sprite_4B_GreenKnifeGuard(int k) { // 85bca2 sprite_graphics[k] = kSprite_Recruit_Gfx[sprite_D[k] + (sprite_subtype2[k] >> 1 & 4) ]; Recruit_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); Sprite_CheckTileCollision(k); if (sprite_ai_state[k] != 0) { GreenKnifeGuard_Moving(k); return; } if (sprite_delay_main[k] != 0) return; sprite_delay_main[k] = (GetRandomNumber() & 0x3f) + 0x30; sprite_ai_state[k]++; sprite_D[k] = sprite_head_dir[k]; PointU8 out; int j = sprite_D[k]; if (j == Sprite_DirectionToFaceLink(k, &out) && (((uint8)(out.x + 0x10) < 0x20) || ((uint8)(out.y + 0x10) < 0x20))) { j += 4; sprite_delay_main[k] = 128; } sprite_x_vel[k] = kSprite_Recruit_Xvel[j]; sprite_y_vel[k] = kSprite_Recruit_Yvel[j]; } void GreenKnifeGuard_Moving(int k) { // 85bd1e uint8 t = 0x10; if (sprite_wallcoll[k] == 0) { if (sprite_delay_main[k] != 0) goto out; t = 0x30; } sprite_delay_main[k] = t; Sprite_ZeroVelocity_XY(k); sprite_head_dir[k] = kRecruit_Moving_HeadDir[sprite_D[k] * 2 | (GetRandomNumber() & 1)]; sprite_ai_state[k] = 0; out: sprite_subtype2[k] += (sprite_delay_aux1[k] != 0) ? 2 : 1; } void Recruit_Draw(int k) { // 85bd7e PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int r6 = sprite_graphics[k]; int hd = sprite_head_dir[k]; uint16 x = info.x; uint16 y = info.y - 11; oam->x = x; oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0; oam->charnum = kSoldier_Draw1_Char[hd]; oam->flags = kSoldier_Draw1_Flags[hd] | info.flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); oam++; x = info.x + kRecruit_Draw_X[r6]; y = info.y; oam->x = x; oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0; oam->charnum = kRecruit_Draw_Char[r6]; oam->flags = kRecruit_Draw_Flags[r6] | info.flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); SpriteDraw_Shadow(k, &info); } void Sprite_4A_BombGuard(int k) { // 85be0a if (sprite_C[k] == 0) { BombGuard(k); return; } if (sprite_C[k] < 2) { SpriteBomb_ExplosionIncoming(k); return; } if (sprite_C[k] == 2) { for (int j = 15; j >= 0; j--) { if (j != cur_object_index && sprite_state[j] >= 9 && !((frame_counter ^ j) & 7 | sprite_hit_timer[j])) SpriteBomb_CheckDamageToSprite(k, j); } Sprite_CheckDamageToLink(k); } SpriteDraw_SpriteBombExplosion(k); if (!sprite_delay_aux1[k]) sprite_state[k] = 0; } void SpriteBomb_CheckDamageToSprite(int k, int j) { // 85be49 int x = Sprite_GetX(k) - 16, y = Sprite_GetY(k) - 16; SpriteHitBox hb; hb.r0_xlo = x; hb.r8_xhi = x >> 8; hb.r3 = hb.r2 = 48; hb.r1_ylo = y; hb.r9_yhi = y >> 8; Sprite_SetupHitBox(j, &hb); if (!CheckIfHitBoxesOverlap(&hb) || sprite_type[j] == 0x11) return; Ancilla_CheckDamageToSprite_preset(j, 8); x = Sprite_GetX(j); y = Sprite_GetY(j) - sprite_z[j]; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 32); sprite_y_recoil[j] = pt.y; sprite_x_recoil[j] = pt.x; } void SpriteBomb_ExplosionIncoming(int k) { // 85bed3 if (sprite_E[k]) sprite_obj_prio[k] |= 48; SpriteDraw_SingleLarge(k); if (sprite_hit_timer[k] || sprite_delay_aux1[k] == 1) { sprite_hit_timer[k] = 0; if (sprite_state[k] == 10) link_state_bits = 0, link_picking_throw_state = 0; SpriteSfx_QueueSfx2WithPan(k, 0xc); sprite_C[k]++; sprite_flags4[k] = 9; sprite_oam_flags[k] = 2; sprite_delay_aux1[k] = 31; sprite_state[k] = 6; sprite_flags2[k] = 3; return; } if (sprite_delay_aux1[k] < 64) sprite_oam_flags[k] = sprite_oam_flags[k] & ~0xe | (sprite_delay_aux1[k] >> 1) & 0xe; if (Sprite_ReturnIfInactive(k)) return; if (!sprite_delay_aux3[k]) Sprite_CheckDamageFromLink(k); Sprite_MoveXY(k); if (player_is_indoors) Sprite_CheckTileCollision(k); ThrownSprite_TileAndSpriteInteraction(k); } void BombGuard(int k) { // 85bf51 BombTrooper_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToAndFromLink(k); sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL); if (sprite_ai_state[k] == 0) { if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 112; } } else { int j = sprite_delay_main[k]; if (!j) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 32; return; } sprite_subtype2[k] = (j >= 80); if (j == 32) BombGuard_CreateBomb(k); sprite_graphics[k] = kJavelinTrooper_Tab2[(sprite_D[k] << 3 | j >> 4) + 32]; } } void BombGuard_CreateBomb(int k) { // 85bfc1 static const int8 kBombTrooperBomb_X[4] = {0, 1, 9, -8}; static const int8 kBombTrooperBomb_Y[4] = {-12, -12, -15, -13}; static const int8 kBombTrooperBomb_Zvel[16] = {32, 40, 48, 56, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x4a, &info); if (j >= 0) { int i = sprite_D[k]; Sprite_SetX(j, info.r0_x + kBombTrooperBomb_X[i]); Sprite_SetY(j, info.r2_y + kBombTrooperBomb_Y[i]); Sprite_ApplySpeedTowardsLink(j, 16); PointU8 pt; sprite_C[j] = 1; Sprite_DirectionToFaceLink(j, &pt); if (sign8(pt.x)) pt.x = -pt.x; if (sign8(pt.y)) pt.y = -pt.y; sprite_z_vel[j] = kBombTrooperBomb_Zvel[(pt.y | pt.x) >> 4]; sprite_flags3[j] = sprite_flags3[k] & 0xee | 0x18; sprite_oam_flags[j] = 8; sprite_delay_aux1[j] = 255; sprite_health[j] = 0; SpriteSfx_QueueSfx3WithPan(j, 0x13); } } void BombTrooper_Draw(int k) { // 85c04b PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; SpriteDraw_GuardHead(k, &info, 2); SpriteDraw_BNCBody(k, &info, 1); if (sprite_graphics[k] < 20) SpriteDraw_BombGuard_Arm(k, &info); SpriteDraw_Shadow_custom(k, &info, 10); } void SpriteDraw_BombGuard_Arm(int k, PrepOamCoordsRet *info) { // 85c089 static const int8 kBombTrooper_DrawArm_X[8] = {-1, 1, 2, 0, 9, 9, -8, -8}; static const int8 kBombTrooper_DrawArm_Y[8] = {-12, -12, -12, -12, -16, -14, -12, -14}; OamEnt *oam = GetOamCurPtr(); int j = sprite_D[k] * 2 | sprite_subtype2[k]; uint16 x = info->x + kBombTrooper_DrawArm_X[j]; uint16 y = info->y + kBombTrooper_DrawArm_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = 0x6e; oam->flags = info->flags & 0x30 | 0x8; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } void SpriteDraw_SpriteBombExplosion(int k) { // 85c113 static const int8 kEnemyBombExplosion_X[16] = {-12, 12, -12, 12, -8, 8, -8, 8, -8, 8, -8, 8, 0, 0, 0, 0}; static const int8 kEnemyBombExplosion_Y[16] = {-12, -12, 12, 12, -8, -8, 8, 8, -8, -8, 8, 8, 0, 0, 0, 0}; static const uint8 kEnemyBombExplosion_Char[16] = {0x88, 0x88, 0x88, 0x88, 0x8a, 0x8a, 0x8a, 0x8a, 0x84, 0x84, 0x84, 0x84, 0x86, 0x86, 0x86, 0x86}; static const uint8 kEnemyBombExplosion_Flags[16] = {0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0, 0, 0}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int base = sprite_delay_aux1[k] >> 1 & 0xc; for (int i = 3; i >= 0; i--, oam++) { int j = base + i; oam->x = kEnemyBombExplosion_X[j] + info.x; oam->y = kEnemyBombExplosion_Y[j] + info.y; oam->charnum = kEnemyBombExplosion_Char[j]; oam->flags = kEnemyBombExplosion_Flags[j] | info.flags; } Sprite_CorrectOamEntries(k, 3, 2); } void Sprite_41_BlueGuard(int k) { // 85c155 if (sprite_C[k]) Probe(k); else Guard_Main(k); } void Probe(int k) { // 85c15d SpriteAddXY(k, (int8)sprite_x_vel[k], (int8)sprite_y_vel[k]); bool is_close; if (sprite_type[sprite_C[k] - 1] == 0xce) { // parent is blind the thief? uint16 x = cur_sprite_x - link_x_coord + 16; uint16 y = link_y_coord - cur_sprite_y + 24; is_close = (x < 32 && y < 32); } else { if (Probe_CheckTileSolidity(k) && sprite_tiletype != 9 || link_cape_mode != 0) { sprite_state[k] = 0; return; } uint16 x = cur_sprite_x - link_x_coord; uint16 y = cur_sprite_y - link_y_coord; is_close = (x < 16 && y < 16 && sprite_floor[k] == link_is_on_lower_level); } if (is_close) { int p = sprite_C[k] - 1; if (sprite_ai_state[p] != 3) { sprite_ai_state[p] = 3; if (sprite_type[p] != 0xce) { sprite_delay_main[p] = 16; sprite_subtype2[p] = 0; } } sprite_state[k] = 0; } else { PrepOamCoordsRet oam; if (Sprite_PrepOamCoordOrDoubleRet(k, &oam)) return; if ((oam.x | oam.y) >= 256) sprite_state[k] = 0; } } void Guard_Main(int k) { // 85c227 uint8 bak1 = sprite_graphics[k]; uint8 bak2 = sprite_D[k]; if (sprite_delay_aux1[k]) { sprite_D[k] = kSoldier_DirectionLockSettings[bak2]; sprite_graphics[k] = kSoldier_Gfx[bak2]; } Guard_HandleAllAnimation(k); sprite_D[k] = bak2; sprite_graphics[k] = bak1; if (sprite_state[k] == 5) { if (submodule_index == 0) { sprite_subtype2[k]++; Guard_TickAndUpdateBody(k); sprite_subtype2[k]++; Guard_TickAndUpdateBody(k); } return; } if (Sprite_ReturnIfInactive(k)) return; Guard_ParrySwordAttacks(k); if ((Sprite_CheckDamageToLink(k) || sprite_alert_flag) && sprite_ai_state[k] < 3) { sprite_ai_state[k] = 3; Guard_SetTimerAndAssertTileHitBox(k, 0x20); } else if (sprite_F[k] != 0 && sprite_F[k] >= 4) { sprite_ai_state[k] = 4; Guard_SetTimerAndAssertTileHitBox(k, 0x80); } if (Sprite_ReturnIfRecoiling(k)) return; if ((sprite_subtype[k] & 7) < 5) { if (!sprite_wallcoll[k]) Sprite_MoveXY(k); Sprite_CheckTileCollision(k); } else { Sprite_MoveXY(k); } if (sprite_ai_state[k] != 4) sprite_G[k] = 0; switch (sprite_ai_state[k]) { case 0: Sprite_ZeroVelocity_XY(k); if (sprite_delay_main[k]) break; sprite_ai_state[k]++; if (sprite_subtype[k] && (sprite_subtype[k] & 7) < 5) { sprite_delay_main[k] = kSoldier_Delay[sprite_subtype[k] >> 3 & 3]; sprite_D[k] ^= 1; sprite_subtype2[k] = 0; } else { sprite_delay_main[k] = (GetRandomNumber() & 0x3f) + 0x28; // note: adc uint8 t = sprite_D[k], u = GetRandomNumber() & 3; sprite_D[k] = u; if (t == u || (t ^ u) & 2) return; } sprite_delay_aux1[k] = 12; break; case 1: { Sprite_Guard_SendOutProbe(k); if ((sprite_subtype[k] & 7) >= 5) { Guard_ShootProbeAndStuff(k); return; } if (!sprite_delay_main[k]) { Sprite_ZeroVelocity_XY(k); sprite_ai_state[k] = 2; sprite_delay_main[k] = 160; return; } if (!(sprite_subtype2[k] & 1)) sprite_delay_main[k]++; if (sprite_wallcoll[k] & 0xf) { sprite_D[k] ^= 1; Guard_SetGlanceTo12(k); } int dir = sprite_D[k]; sprite_x_vel[k] = kSoldier_Xvel[dir]; sprite_y_vel[k] = kSoldier_Yvel[dir]; sprite_head_dir[k] = dir; Guard_TickAndUpdateBody(k); break; } case 2: { Sprite_ZeroVelocity_XY(k); Sprite_Guard_SendOutProbe(k); if (sprite_delay_main[k] == 0) { sprite_delay_main[k] = 0x20; sprite_ai_state[k] = 0; } else if (sprite_delay_main[k] < 0x80) { int t = sprite_D[k] * 8 | (sprite_delay_main[k] >> 3 & 7); sprite_head_dir[k] = kSoldier_HeadDirs[t]; } break; } case 3: Sprite_ZeroVelocity_XY(k); sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL); if (sprite_delay_main[k] == 0) { sprite_ai_state[k] = 4; Guard_SetTimerAndAssertTileHitBox(k, 255); } break; case 4: if (sprite_delay_main[k]) { Soldier_Func12(k); } else { sprite_anim_clock[k] = kSoldier_Tab1[sprite_D[k]]; Sprite_ZeroVelocity_XY(k); sprite_ai_state[k] = 2; sprite_delay_main[k] = 160; } break; } } void Guard_SetGlanceTo12(int k) { // 85c32b sprite_delay_aux1[k] = 12; } void Guard_ShootProbeAndStuff(int k) { // 85c3a1 int i = sprite_B[k]; sprite_x_vel[k] = kSoldierB_Xvel[i]; sprite_y_vel[k] = kSoldierB_Yvel[i]; Sprite_CheckTileCollision(k); if (sprite_delay_aux2[k]) { if (sprite_delay_aux2[k] == 44) sprite_B[k] = i = kSoldierB_NextB[i]; } else if (!(sprite_wallcoll[k] & kSoldierB_Mask[i])) { sprite_delay_aux2[k] = 88; } if (sprite_wallcoll[k] & kSoldierB_Mask2[i]) sprite_B[k] = i = kSoldierB_NextB2[i]; sprite_x_vel[k] = kSoldierB_Xvel2[i]; sprite_y_vel[k] = kSoldierB_Yvel2[i]; sprite_head_dir[k] = sprite_D[k] = kSoldierB_Dir[i]; Guard_TickAndUpdateBody(k); } void Guard_TickAndUpdateBody(int k) { // 85c454 sprite_subtype2[k]++; int t = sprite_D[k] * 4 + (sprite_subtype2[k] >> 3 & 3); sprite_graphics[k] = kSoldier_Gfx2[t]; } void Guard_SetTimerAndAssertTileHitBox(int k, uint8 a) { // 85c4d7 sprite_delay_main[k] = a; sprite_subtype[k] = 0; sprite_flags[k] = sprite_flags[k] & 0xf | 0x60; } void Soldier_Func12(int k) { // 85c500 if (((k ^ frame_counter) & 0x1f) == 0) { if (!sprite_G[k]) { sprite_G[k] = 1; SpriteSfx_QueueSfx3WithPan(k, 4); } Sprite_ApplySpeedTowardsLink(k, 16); sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL); } Guard_ApplySpeedInDirection(k); sprite_subtype2[k]++; Guard_TickAndUpdateBody(k); } void Guard_ApplySpeedInDirection(int k) { // 85c542 if (!sprite_wallcoll[k]) return; int i; if (sprite_wallcoll[k] & 3) { i = 2 + Sprite_IsBelowLink(k).a; } else { i = Sprite_IsRightOfLink(k).a; } sprite_x_vel[k] = kSoldier_SetTowardsVel[i]; sprite_y_vel[k] = kSoldier_SetTowardsVel[i + 2]; } void Sprite_Guard_SendOutProbe(int k) { // 85c5f2 if ((k + frame_counter & 3) | sprite_pause[k]) return; uint8 a = sprite_anim_clock[k]++; uint8 r15 = ((a & 0x1f) + kSprite_SpawnProbeStaggered_Tab[sprite_D[k]]) & 0x3f; Sprite_SpawnProbeAlways(k, r15); } void Sprite_SpawnProbeAlways(int k, uint8 r15) { // 85c612 SpriteSpawnInfo info; int j = Sprite_SpawnDynamicallyEx(k, 0x41, &info, 10); if (j < 0) return; int t = info.r0_x + 8; sprite_x_lo[j] = t; sprite_x_hi[j] = t >> 8; t = info.r2_y + 4; sprite_y_lo[j] = t; sprite_y_hi[j] = t >> 8; sprite_D[j] = r15; sprite_x_vel[j] = kSpawnProbe_Xvel[r15]; sprite_y_vel[j] = kSpawnProbe_Yvel[r15]; sprite_flags2[j] = sprite_flags2[j] & 0xf0 | 0xa0; sprite_C[j] = k + 1; sprite_ignore_projectile[j] = k + 1; sprite_flags4[j] = 0x40; sprite_flags3[j] = 0x40; sprite_defl_bits[j] = 2; } void Guard_HandleAllAnimation(int k) { // 85c680 PrepOamCoordsRet poc; if (Sprite_PrepOamCoordOrDoubleRet(k, &poc)) return; Guard_AnimateHead(k, 0, &poc); Guard_AnimateBody(k, kSoldier_Draw2_OamIdx[sprite_D[k]] >> 2, &poc); Guard_AnimateWeapon(k, &poc); if (sprite_flags3[k] & 0x10) SpriteDraw_Shadow_custom(k, &poc, kSoldier_DrawShadow[sprite_D[k]]); } void Guard_AnimateHead(int k, int oam_offs, const PrepOamCoordsRet *poc) { // 85c6de OamEnt *oam = GetOamCurPtr() + oam_offs; oam->x = poc->x; int dir = sprite_head_dir[k]; uint16 y = poc->y - kSoldier_Draw1_Yd[sprite_graphics[k]]; oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0; oam->charnum = kSoldier_Draw1_Char[dir]; oam->flags = kSoldier_Draw1_Flags[dir] | poc->flags; bytewise_extended_oam[oam - oam_buf] = 2 | (poc->x & 0x100) >> 8; } void Guard_AnimateBody(int k, int oam_idx, const PrepOamCoordsRet *poc) { // 85ca09 int g = sprite_graphics[k] * 4; uint8 type = sprite_type[k]; OamEnt *oam = GetOamCurPtr() + oam_idx; for (int i = 3; i >= 0; i--) { int j = i + g; if (type >= 0x46 && (!kSoldier_Draw2_Ext[j] || i == 3 && kSoldier_Draw2_Char[j] == 0x20)) continue; uint16 x = poc->x + kSoldier_Draw2_Xd[j]; uint16 y = poc->y + kSoldier_Draw2_Yd[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kSoldier_Draw2_Char[j]; bool flag = true; uint8 p = 8; if (oam->charnum == 0x20) { p = 2; if (type == 0x46) oam->y = 0xf0; } else { flag = kSoldier_Draw2_Ext[j] == 0; } uint8 flags = kSoldier_Draw2_Flags[j] | poc->flags; oam->flags = flag ? (flags & 0xf1 | p) : flags; bytewise_extended_oam[oam - oam_buf] = kSoldier_Draw2_Ext[j] | (x & 0x100) >> 8; oam++; } } void Guard_AnimateWeapon(int k, const PrepOamCoordsRet *poc) { // 85cb64 int oam_idx = kSoldier_Draw3_OamIdx[sprite_D[k]] >> 2; int g = sprite_graphics[k] * 2; uint8 type = sprite_type[k]; OamEnt *oam = GetOamCurPtr() + oam_idx; for (int i = 1; i >= 0; i--, oam++) { int j = i + g; uint16 x = poc->x + kSoldier_Draw3_Xd[j]; uint16 y = poc->y + kSoldier_Draw3_Yd[j]; oam->x = x; oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0; dungmap_var8 = kSoldier_Draw3_Xd[j] << 8 | (uint8)kSoldier_Draw3_Yd[j]; oam->charnum = kSoldier_Draw3_Char[j] + (type < 0x43 ? 3 : 0); oam->flags = kSoldier_Draw3_Flags[j] | poc->flags; bytewise_extended_oam[oam - oam_buf] = (x & 0x100) >> 8; } } void Sprite_45_UsainBolt(int k) { // 85cbe0 Guard_HandleAllAnimation(k); if (Sprite_ReturnIfInactive(k)) return; BoltGuard_TriggerChaseTheme(k); Guard_ParrySwordAttacks(k); if (Sprite_ReturnIfRecoiling(k)) return; if (!sprite_wallcoll[k]) Sprite_MoveXY(k); Sprite_CheckTileCollision(k); Sprite_CheckDamageToLink(k); if (!((k ^ frame_counter) & 15)) { sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL); Sprite_ApplySpeedTowardsLink(k, 18); Guard_ApplySpeedInDirection(k); } sprite_subtype2[k]++; Guard_TickAndUpdateBody(k); } void BoltGuard_TriggerChaseTheme(int k) { // 85cc3c if (sprite_G[k] != 16 && sprite_G[k]++ == 15) { SpriteSfx_QueueSfx3WithPan(k, 0x4); if (sram_progress_indicator == 2 && BYTE(overworld_area_index) == 24) music_control = 12; } } void Sprite_44_BluesainBolt(int k) { // 85cc65 PsychoTrooper_Draw(k); if (Sprite_ReturnIfInactive(k)) return; BoltGuard_TriggerChaseTheme(k); Guard_ParrySwordAttacks(k); if (Sprite_ReturnIfRecoiling(k)) return; if (!sprite_wallcoll[k]) Sprite_MoveXY(k); Sprite_CheckTileCollision(k); Sprite_CheckDamageToLink(k); if (!((k ^ frame_counter) & 15)) { sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL); Sprite_ApplySpeedTowardsLink(k, 18); Guard_ApplySpeedInDirection(k); } sprite_graphics[k] = kFlailTrooperGfx[++sprite_subtype2[k] >> 1 & 7 | sprite_D[k] << 3]; } void PsychoTrooper_Draw(int k) { // 85ccd5 PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; SpriteDraw_GuardHead(k, &info, 3); SpriteDraw_BNCBody(k, &info, 2); SpriteDraw_GuardSpear(k, &info, 0); if (sprite_flags3[k] & 0x10) SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]); } void SpriteDraw_GuardSpear(int k, PrepOamCoordsRet *info, int spr_offs) { // 85cd54 static const int8 kSolderThrowing_Draw_X[16] = {15, 7, 17, 9, -8, 0, -10, -2, 13, 13, 13, 13, -4, -4, -4, -4}; static const int8 kSolderThrowing_Draw_Y[16] = {-2, -2, -2, -2, -2, -2, -2, -2, 8, 0, 10, 2, -14, -6, -16, -8}; static const uint8 kSolderThrowing_Draw_Char[16] = {0x6f, 0x7f, 0x6f, 0x7f, 0x6f, 0x7f, 0x6f, 0x7f, 0x6e, 0x7e, 0x6e, 0x7e, 0x6e, 0x7e, 0x6e, 0x7e}; static const uint8 kSolderThrowing_Draw_Flags[16] = {0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0}; OamEnt *oam = GetOamCurPtr() + spr_offs; uint8 r6 = sprite_D[k] * 4 + (((sprite_A[k] ^ 1) << 1) & 2); for (int i = 1; i >= 0; i--, oam++) { int j = r6 + i; uint16 x = info->x + kSolderThrowing_Draw_X[j]; uint16 y = info->y + kSolderThrowing_Draw_Y[j]; HIBYTE(dungmap_var8) = kSolderThrowing_Draw_X[j]; BYTE(dungmap_var8) = kSolderThrowing_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kSolderThrowing_Draw_Char[j] - (sprite_type[k] >= 0x48 ? 3 : 0); oam->flags = (kSolderThrowing_Draw_Flags[j] | info->flags) & 0xf1 | 8; bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1); } } void Sprite_48_RedJavelinGuard(int k) { // 85cde1 static const uint8 kJavelinTrooper_Gfx[4] = {12, 0, 18, 8}; uint8 bak0 = sprite_graphics[k]; int j = sprite_D[k]; if (sprite_delay_aux1[k] != 0) { sprite_D[k] = kSoldier_DirectionLockSettings[j]; sprite_graphics[k] = kJavelinTrooper_Gfx[j]; } JavelinTrooper_Draw(k); sprite_D[k] = j; sprite_graphics[k] = bak0; SoldierThrowing_Common(k); } void Sprite_46_BlueArcher(int k) { // 85cdff uint8 bak0 = sprite_graphics[k]; int j = sprite_D[k]; if (sprite_delay_aux1[k] != 0) { sprite_D[k] = kSoldier_DirectionLockSettings[j]; sprite_graphics[k] = kSoldier_Gfx[j]; } ArcherSoldier_Draw(k); sprite_D[k] = j; sprite_graphics[k] = bak0; SoldierThrowing_Common(k); } void SoldierThrowing_Common(int k) { // 85ce23 int j; static const uint8 kSolderThrowing_DirFlags[4] = {3, 3, 12, 12}; static const int8 kSolderThrowing_Xd[8] = {-80, 80, 0, -8, -80, 80, -8, 8}; static const int8 kSolderThrowing_Yd[8] = {8, 8, -80, 80, 8, 8, -80, 80}; if (Sprite_ReturnIfInactive(k)) return; if ((Sprite_CheckDamageToAndFromLink(k) || sprite_alert_flag) && sprite_ai_state[k] < 3) { sprite_ai_state[k] = 3; sprite_delay_main[k] = 32; } if (sprite_F[k] >= 4) { sprite_ai_state[k] = 4; sprite_delay_main[k] = 60; sprite_subtype2[k] = 0; } if (Sprite_ReturnIfRecoiling(k)) return; if (!sprite_wallcoll[k]) Sprite_MoveXY(k); Sprite_CheckTileCollision(k); switch (sprite_ai_state[k]) { case 0: // resting Sprite_ZeroVelocity_XY(k); if (sprite_delay_main[k] == 0) { sprite_ai_state[k]++; sprite_delay_main[k] = 0x50 + (GetRandomNumber() & 0x7f); uint8 jbak = sprite_D[k]; sprite_D[k] = GetRandomNumber() & 3; if (sprite_D[k] != jbak && !((sprite_D[k] ^ jbak) & 2)) sprite_delay_aux1[k] = 12; } break; case 1: // walking if (sprite_delay_main[k] == 0) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 160; return; } Sprite_Guard_SendOutProbe(k); if (sprite_wallcoll[k] & 0xf) { sprite_D[k] ^= 1; Guard_SetGlanceTo12(k); } j = sprite_D[k]; sprite_x_vel[k] = kSoldier_Xvel[j]; sprite_y_vel[k] = kSoldier_Yvel[j]; sprite_head_dir[k] = j; agitated_jump_to: sprite_subtype2[k]++; if (!(sprite_subtype2[k] & 0xf) && ++sprite_A[k] == 2) sprite_A[k] = 0; sprite_graphics[k] = kSoldier_Gfx2[sprite_D[k] * 4 + sprite_A[k] + (sprite_type[k] == 0x48 ? 16 : 0)]; break; case 2: // looking Sprite_ZeroVelocity_XY(k); Sprite_Guard_SendOutProbe(k); if (sprite_delay_main[k] == 0) { sprite_delay_main[k] = 32; sprite_ai_state[k] = 0; } else if (sprite_delay_main[k] < 0x80) { int t = sprite_D[k] * 8 | (sprite_delay_main[k] >> 3 & 7); sprite_head_dir[k] = kSoldier_HeadDirs[t]; } break; case 3: // noticed player Sprite_ZeroVelocity_XY(k); sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL); if (sprite_delay_main[k] == 0) { sprite_ai_state[k] = 4; sprite_delay_main[k] = 60; sprite_subtype2[k] = 0; } break; case 4: // agitated j = sprite_D[k]; if (sprite_wallcoll[k] & kSolderThrowing_DirFlags[j] || !sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 24; return; } if (!((frame_counter ^ k) & 7)) { sprite_D[k] = sprite_head_dir[k] = j = Sprite_DirectionToFaceLink(k, NULL); if (sprite_type[k] == 0x48) j += 4; uint16 x = link_x_coord + kSolderThrowing_Xd[j]; uint16 y = link_y_coord + kSolderThrowing_Yd[j]; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 24); sprite_x_vel[k] = pt.x; sprite_y_vel[k] = pt.y; if ((uint8)(pt.xdiff + 6) < 12 && (uint8)(pt.ydiff + 6) < 12) { sprite_ai_state[k]++; sprite_delay_main[k] = 24; return; } } sprite_subtype2[k]++; goto agitated_jump_to; case 5: // attack sprite_anim_clock[k] = kSoldier_Tab1[sprite_D[k]]; Sprite_ZeroVelocity_XY(k); if ((j = sprite_delay_main[k]) == 0) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 160; return; } sprite_subtype2[k] = (j >= 40) ? 255 : 0; if (j == 12) Guard_LaunchProjectile(k); sprite_graphics[k] = kJavelinTrooper_Tab2[sprite_D[k] * 8 + (j >> 3) + (sprite_type[k] == 0x48 ? 32 : 0)]; break; } } void Guard_LaunchProjectile(int k) { // 85d0c5 static const int8 kJavelinProjectile_X[8] = {16, -8, 3, 11, 12, -4, 12, -4}; static const int8 kJavelinProjectile_Y[8] = {2, 2, 16, -8, -2, -2, 2, -8}; static const int8 kJavelinProjectile_Xvel[8] = {48, -48, 0, 0, 32, -32, 0, 0}; static const int8 kJavelinProjectile_Yvel[8] = {0, 0, 48, -48, 0, 0, 32, -32}; static const uint8 kJavelinProjectile_Flags4[4] = {5, 5, 6, 6}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x1b, &info); if (j < 0) return; SpriteSfx_QueueSfx3WithPan(k, 0x5); int i = sprite_D[k] + (sprite_type[k] >= 0x48 ? 4 : 0); Sprite_SetX(j, info.r0_x + kJavelinProjectile_X[i]); Sprite_SetY(j, info.r2_y + kJavelinProjectile_Y[i]); sprite_x_vel[j] = kJavelinProjectile_Xvel[i]; sprite_y_vel[j] = kJavelinProjectile_Yvel[i]; i &= 3; sprite_D[j] = i; sprite_flags4[j] = kJavelinProjectile_Flags4[i]; sprite_z[j] = 0; sprite_A[j] = (sprite_type[k] >= 0x48); if (sprite_A[j] && link_shield_type == 0) sprite_flags5[j] &= ~0x20; } void BushJavelinSoldier_Draw(int k) { // 85d141 uint8 bak0 = sprite_graphics[k]; sprite_graphics[k] = 0; uint8 bak1 = sprite_oam_flags[k]; sprite_oam_flags[k] = sprite_oam_flags[k] & 0xf1 | 2; uint16 bak2 = cur_sprite_y; cur_sprite_y += 8; SpriteDraw_SingleLarge(k); cur_sprite_y = bak2; sprite_oam_flags[k] = bak1; sprite_graphics[k] = bak0; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; Guard_AnimateHead(k, 0x10 / 4, &info); SpriteDraw_BNCBody(k, &info, 0xC / 4); if (sprite_graphics[k] < 20) SpriteDraw_GuardSpear(k, &info, 4 / 4); if (sprite_flags3[k] & 0x10) SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]); } void JavelinTrooper_Draw(int k) { // 85d192 PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; SpriteDraw_GuardHead(k, &info, 3); SpriteDraw_BNCBody(k, &info, 2); if (sprite_graphics[k] < 20) SpriteDraw_GuardSpear(k, &info, 0); if (sprite_flags3[k] & 0x10) SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]); } void Sprite_49_RedBushGuard(int k) { // 85d1ac if (sprite_ai_state[k]) { if (sprite_ai_state[k] == 2) BushJavelinSoldier_Draw(k); else BushSoldierCommon_Draw(k); } Sprite_BushGuard_Main(k); } void Sprite_47_GreenBushGuard(int k) { // 85d1bf if (sprite_ai_state[k]) { if (sprite_graphics[k] >= 14) ArcherSoldier_Draw(k); else BushSoldierCommon_Draw(k); } Sprite_BushGuard_Main(k); } void Sprite_BushGuard_Main(int k) { // 85d1d3 int j; static const uint8 kBushSoldier_Gfx[32] = { 4, 4, 4, 4, 4, 4, 4, 4, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, }; static const uint8 kBushSoldier_Gfx2[16] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 3, 4, 4, 4, 4, 4}; if (Sprite_ReturnIfInactive(k)) return; sprite_ignore_projectile[k] = 1; switch (sprite_ai_state[k]) { case 0: if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 64; } break; case 1: Sprite_CheckDamageFromLink(k); if (sprite_delay_main[k] == 0) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 48; sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);; } else { if (sprite_delay_main[k] == 0x20) BushGuard_SpawnFoliage(k); sprite_graphics[k] = kBushSoldier_Gfx[sprite_delay_main[k] >> 2]; } break; case 2: sprite_ignore_projectile[k] = 0; Sprite_CheckDamageToAndFromLink(k); j = sprite_delay_main[k]; if (!j) { sprite_ai_state[k] = 3; sprite_delay_main[k] = 48; goto case_3; } sprite_A[k] = j < 40 ? 0xff : 0x00; if (j == 16) Guard_LaunchProjectile(k); sprite_graphics[k] = kJavelinTrooper_Tab2[sprite_D[k] * 8 + (j >> 3) + (sprite_type[k] == 0x49 ? 32 : 0)]; break; case 3: case_3: Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 64; } else { sprite_graphics[k] = kBushSoldier_Gfx2[sprite_delay_main[k] >> 2]; } break; } } void BushGuard_SpawnFoliage(int k) { // 85d252 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xec, &info); if (j < 0) return; Sprite_SetSpawnedCoordinates(j, &info); sprite_state[j] = 6; sprite_delay_main[j] = 32; sprite_flags2[j] += 3; sprite_C[j] = 2; } void BushSoldierCommon_Draw(int k) { // 85d321 static const int8 kBushSoldierCommon_Y[14] = {8, 8, 8, 8, 2, 8, 0, 8, -3, 8, -3, 8, -3, 8}; static const uint8 kBushSoldierCommon_Char[14] = {0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x42, 0x20, 0x42, 0x20}; static const uint8 kBushSoldierCommon_Flags[14] = {9, 3, 0x49, 0x43, 9, 3, 0x49, 0x43, 9, 3, 0x49, 0x43, 9, 3}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k] * 2; for (int i = 1; i >= 0; i--, oam++) { int j = g + i; uint16 x = info.x; uint16 y = info.y + kBushSoldierCommon_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kBushSoldierCommon_Char[j]; uint8 flags = kBushSoldierCommon_Flags[j] | 0x20; if (i == 0) flags = flags & ~0xe | info.flags; oam->flags = flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } } void ArcherSoldier_Draw(int k) { // 85d38c static const uint8 kArcherSoldier_WeaponOamOffs[4] = {0, 0, 0, 16}; static const uint8 kArcherSoldier_HeadOamOffs[4] = {16, 16, 16, 0}; static const uint8 kArcherSoldier_BodyOamOffs[4] = {20, 20, 20, 4}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; Guard_AnimateHead(k, kArcherSoldier_HeadOamOffs[sprite_D[k]] >> 2, &info); Guard_AnimateBody(k, kArcherSoldier_BodyOamOffs[sprite_D[k]] >> 2, &info); SpriteDraw_Archer_Weapon(k, kArcherSoldier_WeaponOamOffs[sprite_D[k]] >> 2, &info); if (sprite_flags3[k] & 0x10) SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]); } void SpriteDraw_Archer_Weapon(int k, int spr_offs, PrepOamCoordsRet *info) { // 85d4d4 static const uint8 kArcherSoldier_Tab1[4] = {9, 3, 0, 6}; static const int8 kArcherSoldier_Draw_X[48] = { -1, 7, 3, 3, -1, 7, 3, 3, -1, 7, 7, 7, -5, -5, -10, -2, -4, -4, -6, 2, -5, -5, -5, -5, 6, 14, 11, 11, 6, 14, 11, 11, 6, 14, 14, 14, 11, 11, 18, 10, 12, 12, 14, 6, 11, 11, 11, 11, }; static const int8 kArcherSoldier_Draw_Y[48] = { 7, 7, 3, 11, 6, 6, 1, 9, 7, 7, 7, 7, -2, 6, 2, 2, -2, 6, 2, 2, -2, 6, 6, 6, -6, -6, -12, -4, -6, -6, -9, -1, -6, -6, -6, -6, -2, 6, 2, 2, -2, 6, 2, 2, -2, 6, 6, 6, }; static const uint8 kArcherSoldier_Draw_Char[48] = { 0xa, 0xa, 0x2a, 0x2b, 0x1a, 0x1a, 0x2a, 0x2b, 0xa, 0xa, 0xa, 0xa, 0xb, 0xb, 0x3d, 0x3a, 0x1b, 0x1b, 0x3d, 0x3a, 0xb, 0xb, 0xb, 0xb, 0xa, 0xa, 0x2b, 0x2a, 0xa, 0xa, 0x2b, 0x2a, 0xa, 0xa, 0xa, 0xa, 0xb, 0xb, 0x3d, 0x3a, 0x1b, 0x1b, 0x3d, 0x3a, 0xb, 0xb, 0xb, 0xb, }; static const uint8 kArcherSoldier_Draw_Flags[48] = { 0xd, 0x4d, 8, 8, 0xd, 0x4d, 8, 8, 0xd, 0x4d, 0x4d, 0x4d, 0xd, 0x8d, 0x48, 0x48, 0xd, 0x8d, 0x48, 0x48, 0xd, 0x8d, 0x8d, 0x8d, 0x8d, 0xcd, 0x88, 0x88, 0x8d, 0xcd, 0x88, 0x88, 0x8d, 0xcd, 0xcd, 0xcd, 0x4d, 0xcd, 8, 8, 0x4d, 0xcd, 8, 8, 0x4d, 0xcd, 0xcd, 0xcd, }; OamEnt *oam = GetOamCurPtr() + spr_offs; int base = sprite_graphics[k] - 14; if (base < 0) base = kArcherSoldier_Tab1[sprite_D[k]]; for (int i = 3; i >= 0; i--, oam++) { int j = base * 4 + i; uint16 x = info->x + kArcherSoldier_Draw_X[j]; uint16 y = info->y + kArcherSoldier_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kArcherSoldier_Draw_Char[j]; oam->flags = kArcherSoldier_Draw_Flags[j] | 0x20; bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1); } } void TutorialSoldier_Draw(int k) { // 85d64b PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int d = sprite_graphics[k] * 5; for (int i = 4; i >= 0; i--, oam++) { int j = d + i; uint16 x = info.x + kTutorialSoldier_X[j]; uint16 y = info.y + kTutorialSoldier_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kTutorialSoldier_Char[j]; uint8 flags = kTutorialSoldier_Flags[j] | info.flags; if (oam->charnum < 0x40) flags = (flags & 0xf1) | 8; oam->flags = flags; bytewise_extended_oam[oam - oam_buf] = kTutorialSoldier_Ext[j] | (x >> 8 & 1); } SpriteDraw_Shadow_custom(k, &info, 12); } void PullSwitch_FacingUp(int k) { // 85d6d4 static const uint8 kBadPullSwitch_Tab1[10] = {8, 24, 4, 4, 4, 4, 4, 4, 2, 10}; static const uint8 kBadPullSwitch_Tab0[10] = {6, 7, 8, 8, 8, 8, 8, 9, 9, 9}; PullSwitch_HandleUpPulling(k); int j = sprite_graphics[k]; if (j != 0 && j != 11) { link_unk_master_sword = kBadPullSwitch_Tab0[j - 1]; link_y_coord = Sprite_GetY(k) - 19; link_x_coord = Sprite_GetX(k); if (sprite_delay_main[k] == 0) { sprite_graphics[k] = ++j; if (j == 11) { sound_effect_2 = 0x1b; dung_flag_statechange_waterpuzzle = 1; } sprite_delay_main[k] = kBadPullSwitch_Tab1[j - 2]; } } if (sprite_type[k] != 7) BadPullDownSwitch_Draw(k); else BadPullUpSwitch_Draw(k); } void PullSwitch_HandleUpPulling(int k) { // 85d743 if (!Sprite_CheckDamageToLink_same_layer(k)) return; link_actual_vel_y = 0; link_actual_vel_x = 0; Sprite_RepelDash(); bitmask_of_dragstate = 0; uint8 y = link_y_coord - sprite_y_lo[k]; if (!sign8(y - 2)) { link_y_coord = Sprite_GetY(k) + 9; } else if (sign8(y - 244)) { byte_7E0379++; if (joypad1L_last & 0x80 && !(joypad1H_last & 3) && sprite_graphics[k] == 0) { sprite_graphics[k] = 1; sprite_delay_main[k] = 8; SpriteSfx_QueueSfx2WithPan(k, 0x22); } link_y_coord = Sprite_GetY(k) - 21; } else { if (sign8(link_x_coord - sprite_x_lo[k])) link_x_coord = Sprite_GetX(k) - 16; else link_x_coord = Sprite_GetX(k) + 14; } } void BadPullDownSwitch_Draw(int k) { // 85d7f9 PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; Oam_AllocateDeferToPlayer(k); OamEnt *oam = GetOamCurPtr(); uint8 yoff = kBadPullSwitch_Tab5[kBadPullSwitch_Tab4[sprite_graphics[k]]]; for (int i = 4; i >= 0; i--, oam++) { oam->x = info.x + kBadPullDownSwitch_X[i]; oam->y = info.y + kBadPullDownSwitch_Y[i] - (i == 2 ? yoff : 0); oam->charnum = kBadPullDownSwitch_Char[i]; oam->flags = kBadPullDownSwitch_Flags[i] | 0x21; bytewise_extended_oam[oam - oam_buf] = kBadPullDownSwitch_Ext[i]; } Sprite_CorrectOamEntries(k, 4, 0xff); } void BadPullUpSwitch_Draw(int k) { // 85d858 static const uint8 kBadPullUpSwitch_Tab2[2] = {0xa2, 0xa4}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; Oam_AllocateDeferToPlayer(k); OamEnt *oam = GetOamCurPtr(); uint8 yoff = kBadPullSwitch_Tab5[kBadPullSwitch_Tab4[sprite_graphics[k]]]; for (int i = 1; i >= 0; i--, oam++) { uint16 x = info.x; uint16 y = info.y - ((i == 0) ? yoff : 0); oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kBadPullUpSwitch_Tab2[i]; oam->flags = info.flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } } void PullSwitch_FacingDown(int k) { // 85d8b5 static const uint8 kGoodPullSwitch_Tab1[12] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; static const uint8 kGoodPullSwitch_Tab0[12] = {1, 1, 2, 2, 3, 3, 1, 1, 4, 4, 5, 5}; static const uint8 kGoodPullSwitch_YOffs[12] = {9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14}; PullSwitch_HandleDownPulling(k); int j = sprite_graphics[k]; if (j != 0 && j != 13) { link_unk_master_sword = kGoodPullSwitch_Tab0[j - 1]; link_y_coord = Sprite_GetY(k) + kGoodPullSwitch_YOffs[j - 1]; link_x_coord = Sprite_GetX(k); if (sprite_delay_main[k] == 0) { sprite_graphics[k] = ++j; if (j == 13) { if (sprite_type[k] == 6) { activate_bomb_trap_overlord = 1; sound_effect_1 = 0x3c; } else { dung_flag_statechange_waterpuzzle = 1; sound_effect_2 = 0x1b; } } sprite_delay_main[k] = kGoodPullSwitch_Tab1[j - 2]; } } GoodPullSwitch_Draw(k); if (sprite_pause[k]) sprite_graphics[k] = 0; } void GoodPullSwitch_Draw(int k) { // 85d953 static const uint8 kGoodPullSwitch_Tab2[14] = {1, 1, 2, 3, 2, 3, 4, 5, 6, 7, 6, 7, 7, 7}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; Oam_AllocateDeferToPlayer(k); OamEnt *oam = GetOamCurPtr(); uint8 t = kGoodPullSwitch_Tab2[sprite_graphics[k]]; oam[0].x = oam[1].x = info.x; oam[0].y = info.y - 1; oam[1].y = info.y - 1 + t; oam[0].charnum = 0xee; oam[1].charnum = 0xce; oam[0].flags = oam[1].flags = info.flags; Sprite_CorrectOamEntries(k, 1, 2); } void PullSwitch_HandleDownPulling(int k) { // 85d999 if (!Sprite_CheckDamageToLink_same_layer(k)) return; link_actual_vel_y = 0; link_actual_vel_x = 0; Sprite_RepelDash(); bitmask_of_dragstate = 0; uint8 y = link_y_coord - sprite_y_lo[k]; if (!sign8(y - 2)) { byte_7E0379++; if (joypad1L_last & 0x80 && !(joypad1H_last & 3)) { link_unk_master_sword++; if ((joypad1H_last & 4) && sprite_graphics[k] == 0) { sprite_graphics[k] = 1; sprite_delay_main[k] = 12; SpriteSfx_QueueSfx2WithPan(k, 0x22); } } link_y_coord = Sprite_GetY(k) + 9; } else if (sign8(y - 244)) { link_y_coord = Sprite_GetY(k) - 21; } else { if (sign8(link_x_coord - sprite_x_lo[k])) link_x_coord = Sprite_GetX(k) - 16; else link_x_coord = Sprite_GetX(k) + 14; } } void Priest_SpawnMantle(int k) { // 85db27 sprite_state[15]++; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x73, &info); sprite_state[15] = 0; sprite_flags2[j] = sprite_flags2[j] & 0xf0 | 0x3; sprite_x_lo[j] = 0xF0; sprite_x_hi[j] = 4; sprite_y_lo[j] = 0x37; sprite_y_hi[j] = 2; sprite_E[j] = 2; sprite_flags4[j] = 11; sprite_defl_bits[j] |= 0x20; sprite_subtype2[j] = 1; if (link_y_coord < Sprite_GetY(j)) sprite_C[j] = 1; } void Sprite_SanctuaryMantle(int k) { // 85db9b SageMantle_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_C[k]) { sprite_A[k] = 0x40; goto lbl2; } if (Sprite_CheckDamageToLink_same_layer(k)) { Sprite_NullifyHookshotDrag(); link_speed_setting = 0; Sprite_RepelDash(); sprite_delay_aux1[k] = 7; lbl: sprite_subtype2[k] = 0; bitmask_of_dragstate = 0x81; link_speed_setting = 8; lbl2: switch (sprite_ai_state[k]) { case 0: { uint16 x = Sprite_GetX(k); Sprite_SetX(k, x + 19); uint8 dir = Sprite_DirectionToFaceLink(k, NULL); Sprite_SetX(k, x); if (dir == 1 || dir == 3) { sprite_A[k]++; if (sprite_A[k] >= 64) { sprite_ai_state[k]++; flag_is_link_immobilized = 1; } } break; } case 1: SpriteSfx_QueueSfx3WithPan(k, 24); sprite_ai_state[k]++; sprite_delay_main[k] = 168; sprite_x_vel[k] = 3; sprite_delay_aux1[k] = 2; break; case 2: Sprite_MoveXY(k); if (sprite_delay_main[k] == 0) { flag_is_link_immobilized = 0; sprite_x_vel[k] = 0; sprite_C[k] = 0; } else { sprite_delay_aux1[k] = 2; } break; } } else { // no collision if (sprite_delay_aux1[k]) goto lbl; switch (sprite_subtype2[k]) { case 0: sprite_A[k] = 0; bitmask_of_dragstate = 0; link_speed_setting = 0; sprite_subtype2[k]++; break; case 1: break; } } } void SageMantle_Draw(int k) { // 85dc8a if (sprite_C[k] == 0) Oam_AllocateFromRegionB(0x10); Sprite_DrawMultiple(k, kSageMantle_Dmd, 4, NULL); } void Sprite_Priest(int k) { // 85dce6 if (sprite_A[k] == 0) Priest_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (Sprite_TrackBodyToHead(k)) Sprite_MoveXY(k); switch (sprite_subtype2[k]) { case 0: Priest_Dying(k); break; case 1: Priest_RunRescueCutscene(k); break; case 2: Priest_Chillin(k); break; } } void Priest_Dying(int k) { // 85dd0a sprite_head_dir[k] = 4; sprite_D[k] = 4; switch (sprite_ai_state[k]) { case 0: // Priest_LyingOnGround if (Sprite_ShowSolicitedMessage(k, 0x1b) & 0x100) { sprite_ai_state[k]++; sprite_graphics[k]++; sram_progress_flags |= 0x2; sprite_delay_aux2[k] = 128; } break; case 1: // Priest_FinalWords sprite_graphics[k] = 0; if (sprite_delay_aux2[k] == 0) sprite_ai_state[k]++; sprite_A[k] = frame_counter & 2; if (!(sprite_delay_aux2[k] & 7)) SpriteSfx_QueueSfx2WithPan(k, 0x33); break; case 2: // Priest_Die sprite_state[k] = 0; break; } } void Priest_RunRescueCutscene(int k) { // 85dd63 int j; switch (sprite_ai_state[k]) { case 0: sprite_head_dir[k] = 0; sprite_D[k] = 0; if (sprite_delay_main[k] == 0) { Sprite_ShowMessageUnconditional(0x17); sprite_ai_state[k]++; byte_7FFE01 = 1; Priest_SpawnRescuedPrincess(); flag_is_link_immobilized = 1; savegame_map_icons_indicator = 1; } break; case 1: if (byte_7FFE01 == 2) { Sprite_ShowMessageUnconditional(0x18); sprite_ai_state[k]++; } break; case 2: if (choice_in_multiselect_box == 0) { sprite_ai_state[k]++; flag_is_link_immobilized = 0; } else { sprite_ai_state[k] = 1; } break; case 3: sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; j = Sprite_ShowSolicitedMessage(k, 0x16); if (j & 0x100) sprite_D[k] = sprite_head_dir[k] = (uint8)j; break; } } void Priest_Chillin(int k) { // 85dde5 sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; int m = (link_which_pendants & 7) == 7 ? 0x1a : savegame_map_icons_indicator >= 3 ? 0x19 : 0x16; int j = Sprite_ShowSolicitedMessage(k, m); if (j & 0x100) { sprite_D[k] = sprite_head_dir[k] = (uint8)j; link_hearts_filler = 0xa0; } } void Sprite_Uncle(int k) { // 85de2c Uncle_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_subtype2[k] == 0) Uncle_AtHouse(k); else Uncle_InPassage(k); } void Uncle_AtHouse(int k) { // 85de3e Sprite_MoveXY(k); switch (sprite_ai_state[k]) { case 0: // Uncle_TriggerTelepathy link_x_coord_prev = 0x940; link_y_coord_prev = 0x215a; Sprite_ShowMessageUnconditional(0x1f); sprite_ai_state[k]++; break; case 1: // Uncle_AwakenLink if (frame_counter & 3) break; if (COLDATA_copy0 != 32) { COLDATA_copy0--; COLDATA_copy1--; break; } link_pose_during_opening++; player_sleep_in_bed_state++; link_y_coord = 0x2157; flag_is_link_immobilized = 1; sprite_ai_state[k]++; break; case 2: // Uncle_DeclareCurfew Sprite_ShowMessageUnconditional(0x0d); music_control = 3; sprite_graphics[k] = 1; sprite_ai_state[k]++; break; case 3: // Uncle_Embark sprite_graphics[k] = frame_counter >> 3 & 1; if (!sprite_delay_main[k]) { int j = sprite_A[k]; if (j == 2) { sprite_ai_state[k]++; } else { sprite_A[k]++; if (!j) sprite_y_lo[k] -= 2; sprite_delay_main[k] = kUncle_LeaveHouse_Delay[j]; sprite_D[k] = j = kUncle_LeaveHouse_Dir[j]; sprite_x_vel[k] = kUncle_LeaveHouse_Xvel[j]; sprite_y_vel[k] = kUncle_LeaveHouse_Yvel[j]; } } break; case 4: // Uncle_ApplyTelepathyFollower savegame_tagalong = 5; word_7E02CD = 0xdf3; sram_progress_flags |= 0x10; sprite_state[k] = 0; flag_is_link_immobilized = 0; break; } } void Uncle_InPassage(int k) { // 85df19 switch (sprite_ai_state[k]) { case 0: // RemoveZeldaTelepathTagalong if (Sprite_CheckDamageToLink_same_layer(k)) Link_CancelDash(); if (Sprite_ShowMessageOnContact(k, 0xe) & 0x100) { savegame_tagalong = 0; sprite_ai_state[k]++; } break; case 1: // GiveSwordAndShield item_receipt_method = 0; Link_ReceiveItem(0, 0); sprite_ai_state[k]++; sprite_graphics[k] = 1; which_starting_point = 3; sram_progress_flags |= 1; sram_progress_indicator = 1; break; } } void Sprite_QuarrelBros(int k) { // 85e013 QuarrelBros_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_TrackBodyToHead(k); sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; if (!(dungeon_room_index & 1)) { Sprite_ShowSolicitedMessage(k, 0x131); } else if (!(dung_door_opened & 0xff00)) { Sprite_ShowSolicitedMessage(k, 0x12f); } else { Sprite_ShowSolicitedMessage(k, 0x130); } Sprite_BehaveAsBarrier(k); } void QuarrelBros_Draw(int k) { // 85e17f static const DrawMultipleData kQuarrelBros_Dmd[16] = { {0, -12, 0x0004, 2}, {0, 0, 0x000a, 2}, {0, -11, 0x0004, 2}, {0, 1, 0x400a, 2}, {0, -12, 0x0004, 2}, {0, 0, 0x000a, 2}, {0, -11, 0x0004, 2}, {0, 1, 0x400a, 2}, {0, -12, 0x0008, 2}, {0, 0, 0x000a, 2}, {0, -11, 0x0008, 2}, {0, 1, 0x400a, 2}, {0, -12, 0x4008, 2}, {0, 0, 0x000a, 2}, {0, -11, 0x4008, 2}, {0, 1, 0x400a, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kQuarrelBros_Dmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info); SpriteDraw_Shadow(k, &info); } void Sprite_YoungSnitchLady(int k) { // 85e2f2 Sprite_OldSnitchLady(k); } void YoungSnitchLady_Draw(int k) { // 85e37f static const DrawMultipleData kYoungSnitchLady_Dmd[16] = { {0, -8, 0x0026, 2}, {0, 0, 0x00e8, 2}, {0, -7, 0x0026, 2}, {0, 1, 0x40e8, 2}, {0, -8, 0x0024, 2}, {0, 0, 0x00c2, 2}, {0, -7, 0x0024, 2}, {0, 1, 0x40c2, 2}, {0, -8, 0x0028, 2}, {0, 0, 0x00e4, 2}, {0, -7, 0x0028, 2}, {0, 1, 0x00e6, 2}, {0, -8, 0x4028, 2}, {0, 0, 0x40e4, 2}, {0, -7, 0x4028, 2}, {0, 1, 0x40e6, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kYoungSnitchLady_Dmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info); SpriteDraw_Shadow(k, &info); } void Sprite_InnKeeper(int k) { // 85e3af InnKeeper_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); Sprite_ShowSolicitedMessage(k, link_item_flippers ? 0x183 : 0x182); } void InnKeeper_Draw(int k) { // 85e3dc static const DrawMultipleData kInnKeeper_Dmd[2] = { {0, -8, 0x00c4, 2}, {0, 0, 0x00ca, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, kInnKeeper_Dmd, 2, &info); SpriteDraw_Shadow(k, &info); } void Sprite_Witch(int k) { // 85e3fb Witch_Draw(k); if (Sprite_ReturnIfInactive(k)) return; uint8 bak0 = sprite_flags4[k]; sprite_flags4[k] = 2; if (Sprite_CheckDamageToLink_same_layer(k)) { Sprite_NullifyHookshotDrag(); link_speed_setting = 0; Link_CancelDash(); } sprite_flags4[k] = bak0; if (!frame_counter) sprite_A[k] = (GetRandomNumber() & 1) + 2; int shift = sprite_A[k] + 1; sprite_graphics[k] = (frame_counter >> shift) & 7; if (Sprite_CheckIfLinkIsBusy()) return; switch (sprite_ai_state[k]) { case 0: // main if (link_item_mushroom == 0) { if (save_dung_info[0x109] & 0x80) Sprite_ShowSolicitedMessage(k, 0x4b); else Sprite_ShowSolicitedMessage(k, 0x4a); } else if (link_item_mushroom == 1) { if (!(joypad1H_last & 0x40)) { Sprite_ShowSolicitedMessage(k, 0x4c); } else if (Sprite_CheckDamageToLink_same_layer(k) && hud_cur_item == 5) { Witch_AcceptShroom(k); } } else { Sprite_ShowSolicitedMessage(k, 0x4a); } break; case 1: // grant cane of byrna sprite_ai_state[k] = 0; item_receipt_method = 0; Link_ReceiveItem(0x18, 0); break; } } void Witch_AcceptShroom(int k) { // 85e4cf link_item_mushroom = 0; save_dung_info[0x109] |= 0x80; sound_effect_1 = 0; Hud_RefreshIcon(); Sprite_ShowMessageUnconditional(0x4b); SpriteSfx_QueueSfx1WithPan(k, 0xd); flag_overworld_area_did_change = 0; } void Witch_Draw(int k) { // 85e55d static const OamEntSigned kWitch_DrawDataA[16] = { {-3, 8, 0xae, 0x00}, {-3, 16, 0xbe, 0x00}, {-2, 8, 0xae, 0x00}, {-2, 16, 0xbe, 0x00}, {-1, 8, 0xaf, 0x00}, {-1, 16, 0xbf, 0x00}, { 0, 9, 0xaf, 0x00}, { 0, 17, 0xbf, 0x00}, { 1, 10, 0xaf, 0x00}, { 1, 18, 0xbf, 0x00}, { 0, 11, 0xaf, 0x00}, { 0, 18, 0xbf, 0x00}, {-1, 10, 0xae, 0x00}, {-1, 18, 0xbe, 0x00}, {-3, 9, 0xae, 0x00}, {-3, 17, 0xbe, 0x00}, }; static const OamEntSigned kWitch_DrawDataB[3] = { { 0, -4, 0x80, 0x00}, {-11, 15, 0x86, 0x04}, { -3, 15, 0x86, 0x44}, }; static const OamEntSigned kWitch_DrawDataC[2] = { {0, 4, 0x84, 0x00}, {0, 4, 0x82, 0x00}, }; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; Oam_AllocateDeferToPlayer(k); OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; oam[0].x = BYTE(dungmap_var7) + kWitch_DrawDataA[g * 2].x; oam[0].y = HIBYTE(dungmap_var7) + kWitch_DrawDataA[g * 2].y; WORD(oam[0].charnum) = WORD(info.r4) | WORD(kWitch_DrawDataA[g * 2].charnum); oam[1].x = BYTE(dungmap_var7) + kWitch_DrawDataA[g * 2 + 1].x; oam[1].y = HIBYTE(dungmap_var7) + kWitch_DrawDataA[g * 2 + 1].y; WORD(oam[1].charnum) = WORD(info.r4) | WORD(kWitch_DrawDataA[g * 2+1].charnum); for (int i = 0; i < 3; i++) { oam[i+2].x = BYTE(dungmap_var7) + kWitch_DrawDataB[i].x; oam[i+2].y = HIBYTE(dungmap_var7) + kWitch_DrawDataB[i].y; WORD(oam[i+2].charnum) = WORD(info.r4) ^ WORD(kWitch_DrawDataB[i].charnum); } int i = (uint16)(g - 3) < 3; oam[5].x = BYTE(dungmap_var7) + kWitch_DrawDataC[i].x; oam[5].y = HIBYTE(dungmap_var7) + kWitch_DrawDataC[i].y; WORD(oam[5].charnum) = WORD(info.r4) | WORD(kWitch_DrawDataC[i].charnum); int e = oam - oam_buf; WORD(bytewise_extended_oam[e]) = 0; WORD(bytewise_extended_oam[e+2]) = 0x202; WORD(bytewise_extended_oam[e+4]) = 0x202; Sprite_CorrectOamEntries(k, 5, 0xff); } void SpritePrep_Snitches(int k) { // 85e67d sprite_D[k] = 2; sprite_head_dir[k] = 2; sprite_ignore_projectile[k]++; sprite_A[k] = sprite_x_lo[k]; sprite_B[k] = sprite_x_hi[k]; sprite_x_vel[k] = -9; } void Sprite_OldSnitchLady(int k) { // 85e6aa static const int8 kOldSnitchLady_Xd[2] = {-32, 32}; static const int8 kOldSnitchLady_Xvel[4] = {0, 0, -9, 9}; static const int8 kOldSnitchLady_Yvel[4] = {-9, 9, 0, 0}; int j; if (sprite_type[k] == 0x34) { if (sprite_ai_state[k] < 2) YoungSnitchLady_Draw(k); } else { if (sprite_subtype[k]) { Sprite_ChickenLady(k); return; } if (sprite_ai_state[k] < 3) Lady_Draw(k); } if (Sprite_ReturnIfInactive(k)) return; if (sprite_ai_state[k] < 3) { if (player_is_indoors) { Sprite_TrackBodyToHead(k); sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; Sprite_ShowSolicitedMessage(k, 0xad); return; } if (!sprite_ai_state[k] && Sprite_CheckDamageToLink_same_layer(k)) { sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; sprite_delay_main[k] = 1; } else { if (Sprite_TrackBodyToHead(k)) Sprite_MoveXY(k); else sprite_delay_main[k] = 1; } } switch (sprite_ai_state[k]) { case 0: { if (sprite_delay_main[k] == 0) { uint16 t = (sprite_A[k] | sprite_B[k] << 8) + kOldSnitchLady_Xd[sprite_C[k]]; if (t == Sprite_GetX(k)) { sprite_head_dir[k] = (j = sprite_D[k] ^ 1); sprite_x_vel[k] = kOldSnitchLady_Xvel[j]; sprite_y_vel[k] = kOldSnitchLady_Yvel[j]; sprite_C[k] ^= 1; } } sprite_graphics[k] = (k ^ frame_counter) >> 4 & 1; uint8 bak0 = sprite_flags4[k]; sprite_flags4[k] = 3; j = Sprite_ShowMessageOnContact(k, 0x2f); sprite_flags4[k] = bak0; if (j & 0x100) { sprite_D[k] = j; Snitch_SpawnGuard(k); sprite_ai_state[k] = 1; } break; } case 1: { uint16 ovx = overlord_x_lo[byte_7E0FDE] | overlord_x_hi[byte_7E0FDE] << 8; uint16 ovy = overlord_y_lo[byte_7E0FDE] | overlord_y_hi[byte_7E0FDE] << 8; if (ovy >= Sprite_GetY(k)) { sprite_ai_state[k] = 2; sprite_x_vel[k] = 0; sprite_y_vel[k] = 0; sprite_flags4[k] = 2; uint16 pos = ((ovy - overworld_offset_base_y) & overworld_offset_mask_y) * 8; pos += (((ovx >> 3) - overworld_offset_base_x) & overworld_offset_mask_x); Overworld_DrawWoodenDoor(pos, false); sprite_delay_main[k] = 16; } else { flag_is_link_immobilized = 1; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, ovx, ovy, 64); sprite_x_vel[k] = pt.x; sprite_y_vel[k] = pt.y; sprite_D[k] = 0; sprite_head_dir[k] = 0; sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1; } break; } case 2: if (sprite_delay_main[k] == 0) { uint16 ovx = overlord_x_lo[byte_7E0FDE] | overlord_x_hi[byte_7E0FDE] << 8; uint16 ovy = overlord_y_lo[byte_7E0FDE] | overlord_y_hi[byte_7E0FDE] << 8; Sprite_SetX(k, ovx); Sprite_SetY(k, ovy); uint16 pos = ((ovy - overworld_offset_base_y) & overworld_offset_mask_y) * 8; pos += (((ovx >> 3) - overworld_offset_base_x) & overworld_offset_mask_x); Overworld_DrawWoodenDoor(pos, true); sprite_ai_state[k] = 3; } Sprite_MoveXY(k); break; case 3: sprite_state[k] = 0; flag_is_link_immobilized = 0; break; } } void SpritePrep_RunningMan(int k) { // 85e896 sprite_head_dir[k] = 2; sprite_D[k] = 2; sprite_ignore_projectile[k]++; } void Sprite_RunningMan(int k) { // 85e8b2 static const int8 kRunningMan_Xvel2[2] = {-24, 24}; static const int8 kRunningMan_Xvel[4] = {0, 0, -54, 54}; static const int8 kRunningMan_Yvel[4] = {-54, 54, 0, 0}; static const int8 kRunningMan_Dir[4] = {3, 1, 3, -1}; static const uint8 kRunningMan_A[4] = {120, 24, 128, 3}; int j; RunningMan_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_TrackBodyToHead(k); Sprite_BehaveAsBarrier(k); sprite_subtype[k] = 255; Sprite_CheckTileCollision(k); uint8 bak0 = sprite_flags4[k]; sprite_flags4[k] = 7; if (Sprite_CheckDamageToLink_same_layer(k)) { sprite_C[k] = sprite_ai_state[k]; sprite_ai_state[k] = 3; } sprite_flags4[k] = bak0; switch (sprite_ai_state[k]) { case 0: // chill Sprite_TrackBodyToHead(k); j = Sprite_DirectionToFaceLink(k, NULL); sprite_head_dir[k] = j ^ 3; if (Sprite_CheckDamageToLink_same_layer(k)) { Link_CancelDash(); sprite_D[k] = j ^ 3; sprite_head_dir[k] = j | 2; sprite_ai_state[k] = (j & 1) + 1; sprite_x_vel[k] = kRunningMan_Xvel2[j & 1]; sprite_delay_main[k] = 32; } else { sprite_x_vel[k] = 0; sprite_y_vel[k] = 0; } break; case 1: // run left case 2: // run right if (sprite_delay_main[k] != 0) { sprite_graphics[k] = frame_counter >> 3 & 1; Sprite_MoveXY(k); } else { RunningBoy_SpawnDustGarnish(k); sprite_graphics[k] = frame_counter >> 2 & 1; j = sprite_head_dir[k]; sprite_x_vel[k] = kRunningMan_Xvel[j]; sprite_y_vel[k] = kRunningMan_Yvel[j]; Sprite_MoveXY(k); if (sprite_A[k]) { sprite_A[k]--; break; } if (sprite_ai_state[k] == 1) { // left sprite_A[k] = 255; sprite_head_dir[k] = 2; } else { j = sprite_B[k]++; sprite_A[k] = kRunningMan_A[j]; if (kRunningMan_Dir[j] < 0) { sprite_ai_state[k] = 0; sprite_subtype2[k] = 0; } else { sprite_head_dir[k] = kRunningMan_Dir[j]; } } } break; case 3: // caught Sprite_ShowMessageUnconditional(0xa6); if (link_player_handler_state >= kPlayerState_RecoilWall) // wtf sprite_D[k] = link_player_handler_state; sprite_ai_state[k] = sprite_C[k]; break; } } void RunningMan_Draw(int k) { // 85ea4d static const DrawMultipleData kRunningMan_Dmd[16] = { {0, -8, 0x002c, 2}, {0, 0, 0x08ee, 2}, {0, -7, 0x002c, 2}, {0, 1, 0x48ee, 2}, {0, -8, 0x002a, 2}, {0, 0, 0x08ca, 2}, {0, -7, 0x002a, 2}, {0, 1, 0x48ca, 2}, {0, -8, 0x002e, 2}, {0, 0, 0x08cc, 2}, {0, -7, 0x002e, 2}, {0, 1, 0x08ce, 2}, {0, -8, 0x402e, 2}, {0, 0, 0x48cc, 2}, {0, -7, 0x402e, 2}, {0, 1, 0x48ce, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kRunningMan_Dmd[(sprite_D[k] * 4 + sprite_graphics[k] * 2) & 0xf], 2, &info); SpriteDraw_Shadow(k, &info); } void Sprite_BottleVendor(int k) { // 85ea79 int j; sprite_A[k] = BottleVendor_Draw(k); if (Sprite_ReturnIfInactive(k)) return; BottleMerchant_DetectFish(k); Sprite_BehaveAsBarrier(k); if (Sprite_CheckIfLinkIsBusy()) return; if (GetRandomNumber() == 0) { sprite_delay_main[k] = 20; sprite_graphics[k] = 1; } else if (!sprite_delay_main[k]) { sprite_graphics[k] = 0; } switch (sprite_ai_state[k]) { case 0: // base if (!sprite_A[k] && sprite_E[k]) sprite_ai_state[k] = 3; else if (sram_progress_indicator_3 & 2) Sprite_ShowSolicitedMessage(k, 0xd4); else if (Sprite_ShowSolicitedMessage(k, 0xd1) & 0x100) sprite_ai_state[k] = 1; break; case 1: // selling if (choice_in_multiselect_box == 0 && link_rupees_goal >= 100) { Sprite_ShowMessageUnconditional(0xd2); sprite_ai_state[k] = 2; } else { Sprite_ShowMessageUnconditional(0xd3); sprite_ai_state[k] = 0; } break; case 2: // giving item_receipt_method = 0; Link_ReceiveItem(0x16, 0); sram_progress_indicator_3 |= 2; link_rupees_goal -= 100; sprite_ai_state[k] = 0; break; case 3: // buying if (!sign8(sprite_E[k])) Sprite_ShowMessageUnconditional(0xd5); else Sprite_ShowMessageUnconditional(0xd6); sprite_ai_state[k] = 4; break; case 4: // reward j = sprite_E[k]; if (!sign8(j)) { sprite_state[j - 1] = 0; BottleMerchant_BuyBee(k); } else { sprite_state[j & 0xf] = 0; BottleMerchant_BuyFish(k); } sprite_E[k] = 0; sprite_ai_state[k] = 0; break; } } uint8 BottleVendor_Draw(int k) { // 85eba7 PrepOamCoordsRet info; static const DrawMultipleData kBottleVendor_Dmd[4] = { {0, -7, 0x00ac, 2}, {0, 0, 0x0088, 2}, {0, -6, 0x00ac, 2}, {0, 0, 0x00a2, 2}, }; Sprite_DrawMultiplePlayerDeferred(k, &kBottleVendor_Dmd[sprite_graphics[k] * 2], 2, &info); SpriteDraw_Shadow(k, &info); return (info.x | info.y) >> 8; } void Priest_SpawnRescuedPrincess() { // 85ec4c SpriteSpawnInfo info; int k = Sprite_SpawnDynamically(0, 0x76, &info); if (k < 0) return; sprite_D[k] = sprite_head_dir[k] = tagalong_layerbits[tagalong_var2] & 3; Sprite_SetX(k, link_x_coord); Sprite_SetY(k, link_y_coord); sprite_subtype2[k] = 1; savegame_tagalong = 0; sprite_ignore_projectile[k]++; sprite_flags4[k] = 3; } void Sprite_76_Zelda(int k) { // 85ec9e CrystalMaiden_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (Sprite_TrackBodyToHead(k)) Sprite_MoveXY(k); switch (sprite_subtype2[k]) { case 0: Zelda_InCell(k); break; case 1: Zelda_EnteringSanctuary(k); break; case 2: Zelda_AtSanctuary(k); break; } } void Zelda_InCell(int k) { // 85ecbf int j; sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; switch (sprite_ai_state[k]) { case 0: // AwaitingRescue if (!Sprite_CheckDamageToLink_same_layer(k)) return; sprite_ai_state[k]++; flag_is_link_immobilized++; j = sprite_head_dir[k]; sprite_x_vel[k] = kZelda_Xvel[j]; sprite_y_vel[k] = kZelda_Yvel[j]; sprite_delay_main[k] = 16; break; case 1: // ApproachingPlayer if (!sprite_delay_main[k]) { sprite_ai_state[k]++; Sprite_ShowMessageUnconditional(0x1c); sprite_x_vel[k] = 0; sprite_y_vel[k] = 0; music_control = 25; } sprite_graphics[k] = frame_counter >> 3 & 1; break; case 2: // TheWizardIsBadMkay sprite_ai_state[k]++; Sprite_ShowMessageUnconditional(0x25); break; case 3: // WaitUntilPlayerPaysAttention if (choice_in_multiselect_box) { sprite_ai_state[k] = 2; } else { sprite_ai_state[k]++; Sprite_ShowMessageUnconditional(0x24); } break; case 4: // TransitionToTagalong flag_is_link_immobilized = 0; which_starting_point = 2; SavePalaceDeaths(); savegame_tagalong = 1; Dungeon_FlagRoomData_Quadrants(); Sprite_BecomeFollower(k); sprite_state[k] = 0; music_control = 16; break; } } void Zelda_EnteringSanctuary(int k) { // 85ed69 static const uint8 kZelda_Delay0[4] = {38, 26, 44, 1}; static const uint8 kZelda_Dir0[4] = {1, 3, 1, 2}; int j; switch (sprite_ai_state[k]) { case 0: // walk to priest if (sprite_delay_main[k] == 0) { j = sprite_A[k]; if (j >= 4) { sprite_ai_state[k]++; sprite_head_dir[k] = sprite_D[k] = 0; sprite_x_vel[k] = 0; sprite_y_vel[k] = 0; return; } sprite_delay_main[k] = kZelda_Delay0[j]; sprite_D[k] = sprite_head_dir[k] = j = kZelda_Dir0[j]; sprite_A[k]++; sprite_x_vel[k] = kZelda_Xvel[j]; sprite_y_vel[k] = kZelda_Yvel[j]; } sprite_graphics[k] = (frame_counter >> 3) & 1; break; case 1: // respond to priest Sprite_ShowMessageUnconditional(0x1d); sprite_ai_state[k]++; byte_7FFE01 = 2; which_starting_point = 1; SavePalaceDeaths(); sram_progress_indicator = 2; Sprite_LoadGraphicsProperties_light_world_only(); break; case 2: // be careful sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; j = Sprite_ShowSolicitedMessage(k, 0x1e); if (j & 0x100) sprite_D[k] = sprite_head_dir[k] = (uint8)j; break; } } void Zelda_AtSanctuary(int k) { // 85ee0c sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; int m = (link_which_pendants & 7) == 7 ? 0x27 : savegame_map_icons_indicator >= 3 ? 0x26 : 0x1e; int j = Sprite_ShowSolicitedMessage(k, m); if (j & 0x100) { sprite_D[k] = sprite_head_dir[k] = (uint8)j; link_hearts_filler = 0xa0; } } void SpritePrep_Mushroom(int k) { // 85ee53 if (link_item_mushroom >= 2) { sprite_state[k] = 0; } else { sprite_graphics[k] = 0; sprite_oam_flags[k] |= 8; sprite_ignore_projectile[k]++; } } void Sprite_Mushroom(int k) { // 85ee78 SpriteDraw_SingleLarge(k); if (Sprite_CheckIfLinkIsBusy()) return; if (Sprite_CheckDamageToLink_same_layer(k)) { sprite_state[k] = 0; item_receipt_method = 0; Link_ReceiveItem(0x29, 0); } else if ((frame_counter & 0x1f) == 0) { sprite_oam_flags[k] ^= 0x40; } } void Sprite_FakeSword(int k) { // 85eeaf FakeSword_Draw(k); if (Sprite_ReturnIfPaused(k)) return; if (sprite_unk3[k] == 3) { if (!sprite_C[k]) { sprite_C[k] = 1; Sprite_ShowMessageUnconditional(0x6f); } } else { Sprite_MoveXY(k); ThrownSprite_TileAndSpriteInteraction(k); } } void FakeSword_Draw(int k) { // 85eee6 Sprite_DrawMultiplePlayerDeferred(k, kFakeSword_Dmd, 2, NULL); } void SpritePrep_HeartContainer(int k) { // 85ef01 HeartUpgrade_CheckIfAlreadyObtained(k); } void Sprite_HeartContainer(int k) { // 85ef47 if (BYTE(cur_palace_index_x2) == 26) { sprite_state[k] = 0; return; } sprite_ignore_projectile[k] = sprite_G[k]; if (!sprite_G[k]) { DecodeAnimatedSpriteTile_variable(3); Sprite_Get16BitCoords(k); sprite_G[k] = 1; } if (BYTE(dungeon_room_index2) == 6 && !sprite_z[k]) SpriteDraw_WaterRipple_WithOamAdjust(k); SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; sprite_z_vel[k] -= 2; Sprite_MoveZ(k); if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2; if (BYTE(dungeon_room_index2) == 6 && !sprite_subtype[k]) { sprite_flags2[k] += 2; sprite_subtype[k] = 1; Sprite_SpawnWaterSplash(k); } } if (Sprite_CheckIfLinkIsBusy()) return; if (!Sprite_CheckDamageToLink_same_layer(k)) return; sprite_state[k] = 0; if (sprite_A[k]) { item_receipt_method = 2; Link_ReceiveItem(0x3e, 0); dung_savegame_state_bits |= 0x8000; return; } Link_CancelDash(); item_receipt_method = 0; Link_ReceiveItem(0x26, 0); if (!player_is_indoors) save_ow_event_info[BYTE(overworld_screen_index)] |= 0x40; else dung_savegame_state_bits |= (sprite_x_hi[k] & 1) ? 0x2000 : 0x4000; } void Sprite_HeartPiece(int k) { // 85f020 static const uint16 kHeartPieceMsg[4] = {0x158, 0x155, 0x156, 0x157}; if (!sprite_ai_state[k]) { sprite_ai_state[k]++; HeartUpgrade_CheckIfAlreadyObtained(k); if (!sprite_state[k]) return; } SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_CheckIfLinkIsBusy()) return; if (Sprite_CheckTileCollision(k) & 3) sprite_x_vel[k] = -sprite_x_vel[k]; sprite_z_vel[k]--; Sprite_MoveZ(k); Sprite_MoveXY(k); if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = ((sprite_z_vel[k] ^ 255) & 248) >> 1; sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1; } if (sprite_delay_aux4[k] || !Sprite_CheckDamageToLink_same_layer(k)) return; link_heart_pieces = link_heart_pieces + 1 & 3; if (link_heart_pieces == 0) { Link_CancelDash(); item_receipt_method = 0; Link_ReceiveItem(0x26, 0); } else { SpriteSfx_QueueSfx3WithPan(k, 0x2d); Sprite_ShowMessageUnconditional(kHeartPieceMsg[link_heart_pieces]); } sprite_state[k] = 0; HeartUpgrade_SetObtainedFlag(k); } void HeartUpgrade_SetObtainedFlag(int k) { // 85f0c3 if (!player_is_indoors) { save_ow_event_info[BYTE(overworld_screen_index)] |= 0x40; } else { int j = sprite_x_hi[k] & 1; dung_savegame_state_bits |= (j ? 0x2000 : 0x4000); } } void Sprite_Aginah(int k) { // 85f0ea if (!(sram_progress_flags & 0x20)) goto default_msg; if (link_sword_type >= 2) { Sprite_ShowSolicitedMessage(k, 0x128); } else if ((link_which_pendants & 7) == 7) { Sprite_ShowSolicitedMessage(k, 0x126); } else if ((link_which_pendants & 2) != 0) { Sprite_ShowSolicitedMessage(k, 0x129); } else if (link_item_book_of_mudora) { Sprite_ShowSolicitedMessage(k, 0x127); } else { default_msg: sram_progress_flags |= 0x20; Sprite_ShowSolicitedMessage(k, 0x125); } sprite_graphics[k] = frame_counter >> 5 & 1; } void Sprite_Sahasrahla(int k) { // 85f14d switch (sprite_ai_state[k]) { case 0: // dialogue Sasha_Idle(k); break; case 1: // mark map Sprite_ShowMessageUnconditional(0x33); sprite_ai_state[k] = 0; savegame_map_icons_indicator = 3; break; case 2: // grant boots item_receipt_method = 0; Link_ReceiveItem(0x4b, 0); sprite_ai_state[k] = 3; savegame_map_icons_indicator = 3; break; case 3: // shamelessly promote ice rod Sprite_ShowMessageUnconditional(0x37); sprite_ai_state[k] = 0; break; } } void Sasha_Idle(int k) { // 85f160 if (!(link_which_pendants & 4)) { if (Sprite_ShowSolicitedMessage(k, 0x32) & 0x100) sprite_ai_state[k] = 1; } else if (!link_item_boots) { int m = (savegame_map_icons_indicator >= 3) ? 0x38 : 0x39; if (Sprite_ShowSolicitedMessage(k, m) & 0x100) sprite_ai_state[k] = 2; } else if (!link_item_ice_rod) { Sprite_ShowSolicitedMessage(k, 0x37); } else if ((link_which_pendants & 7) != 7) { Sprite_ShowSolicitedMessage(k, 0x34); } else if (link_sword_type < 2) { Sprite_ShowSolicitedMessage(k, 0x30); } else { Sprite_ShowSolicitedMessage(k, 0x31); } sprite_graphics[k] = frame_counter >> 5 & 1; } void Elder_Draw(int k) { // 85f23a static const DrawMultipleData kElder_Dmd[4] = { {0, -9, 0x00a0, 2}, {0, 0, 0x00a2, 2}, {0, -8, 0x00a0, 2}, {0, 0, 0x40a4, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kElder_Dmd[sprite_graphics[k] * 2], 2, &info); SpriteDraw_Shadow(k, &info); } void Sprite_DustCloud(int k) { // 85f2b2 static const uint8 kDustCloud_Gfx[9] = {0, 1, 2, 3, 4, 5, 1, 0, 0xff}; DustCloud_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_delay_main[k]) return; sprite_delay_main[k] = 5; if (!sign8(kDustCloud_Gfx[sprite_A[k]])) { sprite_graphics[k] = kDustCloud_Gfx[sprite_A[k]]; sprite_A[k]++; } else { sprite_state[k] = 0; } } int Sprite_SpawnDustCloud(int k) { // 85f2d6 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xF2, &info); if (j >= 0) { info.r2_y += (GetRandomNumber() & 15); info.r0_x += (GetRandomNumber() & 15) - 8; Sprite_SetSpawnedCoordinates(j, &info); sprite_subtype2[j] = 1; } return j; } void MedallionTablet_Main(int k) { // 85f30c MedallionTablet_Draw(k); if (Sprite_ReturnIfInactive(k)) return; link_position_mode &= ~0x20; sprite_A[k] = 0; if (Sprite_CheckDamageToLink_same_layer(k)) { Sprite_NullifyHookshotDrag(); link_speed_setting = 0; Sprite_RepelDash(); sprite_A[k]++; } if (Sprite_CheckIfLinkIsBusy()) return; switch (sprite_ai_state[k]) { case 0: // wait for mudora if (BYTE(overworld_screen_index) != 3) BombosTablet(k); else EtherTablet(k); break; case 1: // delay if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 128; } break; case 2: // crumbling if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 240; } else { if (sprite_delay_main[k] == 0x20 || sprite_delay_main[k] == 0x40 || sprite_delay_main[k] == 0x60) sprite_graphics[k]++; if (!(frame_counter & 7)) Sprite_SpawnDustCloud(k); } break; case 3: // final animstate sprite_graphics[k] = 4; break; } } void BombosTablet(int k) { // 85f355 static const uint16 kMedallionTabletMsg[2] = {0x10d, 0x10f}; if (link_direction_facing || Sprite_DirectionToFaceLink(k, NULL) != 2) return; if ((uint16)(cur_sprite_y + 16) < link_y_coord) return; if (filtered_joypad_H & 0x80 && link_sword_type == 2) return; int j = 1; if (!(hud_cur_item == 15 && (filtered_joypad_H & 0x40)) && (j = 0, !(filtered_joypad_L & 0x80))) return; if (j) { player_handler_timer = 0; link_position_mode = 32; sound_effect_1 = 0; if (!sign8(link_sword_type) && link_sword_type >= 2) { sprite_ai_state[k]++; BombosTablet_StartCutscene(); sprite_delay_main[k] = 64; } } Sprite_ShowMessageUnconditional(kMedallionTabletMsg[j]); } void EtherTablet(int k) { // 85f3c4 static const uint16 kMedallionTabletEtherMsg[2] = {0x10d, 0x10e}; if (link_direction_facing || Sprite_DirectionToFaceLink(k, NULL) != 2) return; if ((uint8)(sprite_y_lo[k] + 16) < BYTE(link_y_coord)) return; if (filtered_joypad_H & 0x80 && link_sword_type == 2) return; int j = 1; if (!(hud_cur_item == 15 && (filtered_joypad_H & 0x40)) && (j = 0, !(filtered_joypad_L & 0x80))) return; if (j) { player_handler_timer = 0; link_position_mode = 32; sound_effect_1 = 0; if (!sign8(link_sword_type) && link_sword_type >= 2) { sprite_ai_state[k]++; EtherTablet_StartCutscene(); sprite_delay_main[k] = 64; } } Sprite_ShowMessageUnconditional(kMedallionTabletEtherMsg[j]); } void ElderWife_Draw(int k) { // 85f505 static const DrawMultipleData kElderWife_Dmd[4] = { {0, -5, 0x008e, 2}, {0, 5, 0x0028, 2}, {0, -4, 0x008e, 2}, {0, 5, 0x4028, 2}, }; Sprite_DrawMultiplePlayerDeferred(k, &kElderWife_Dmd[sprite_graphics[k] * 2], 2, NULL); } void SpritePrep_PotionShop(int k) { // 85f529 MagicShopAssistant_SpawnPowder(k); MagicShopAssistant_SpawnGreenCauldron(k); MagicShopAssistant_SpawnBlueCauldron(k); MagicShopAssistant_SpawnRedCauldron(k); sprite_ignore_projectile[k]++; } void MagicShopAssistant_SpawnPowder(int k) { // 85f539 if (!flag_overworld_area_did_change || link_item_mushroom == 2) return; if (save_dung_info[0x109] & 0x80) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xe9, &info); sprite_subtype2[j] = 1; Sprite_SetX(j, info.r0_x - 16); Sprite_SetY(j, info.r2_y); sprite_flags4[j] = 3; sprite_defl_bits[j] |= 0x20; } } void MagicShopAssistant_SpawnGreenCauldron(int k) { // 85f58e SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xe9, &info); sprite_subtype2[j] = 2; Sprite_SetX(j, info.r0_x - 40); Sprite_SetY(j, info.r2_y - 72); sprite_flags4[j] = 3; sprite_defl_bits[j] |= 0x20; } void MagicShopAssistant_SpawnBlueCauldron(int k) { // 85f5bf SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xe9, &info); sprite_subtype2[j] = 3; Sprite_SetX(j, info.r0_x + 8); Sprite_SetY(j, info.r2_y - 72); sprite_flags4[j] = 3; sprite_defl_bits[j] |= 0x20; } void MagicShopAssistant_SpawnRedCauldron(int k) { // 85f5f0 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xe9, &info); sprite_subtype2[j] = 4; Sprite_SetX(j, info.r0_x - 88); Sprite_SetY(j, info.r2_y - 72); sprite_flags4[j] = 3; sprite_defl_bits[j] |= 0x20; } void Sprite_PotionShop(int k) { // 85f633 switch(sprite_subtype2[k]) { case 0: Sprite_MagicShopAssistant_Main(k); return; case 1: Sprite_BagOfPowder(k); return; case 2: Sprite_GreenCauldron(k); return; case 3: Sprite_BlueCauldron(k); return; case 4: Sprite_RedCauldron(k); return; } } void Sprite_BagOfPowder(int k) { // 85f644 MagicPowderItem_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (!Sprite_CheckDamageToLink_same_layer(k) || !(filtered_joypad_L & 0x80)) return; Link_CancelDash(); item_receipt_method = 0; Link_ReceiveItem(0xd, 0); sprite_state[k] = 0; } void MagicPowderItem_Draw(int k) { // 85f67b static const DrawMultipleData kMagicPowder_Dmd[2] = { {0, 0, 0x04e6, 2}, {0, 0, 0x04e6, 2}, }; Sprite_DrawMultiplePlayerDeferred(k, kMagicPowder_Dmd, 2, NULL); } void Sprite_GreenCauldron(int k) { // 85f68e GreenPotionItem_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (sprite_delay_main[k]) return; if (!PotionCauldron_CheckBottles()) { if (Sprite_ShowMessageOnContact(k, 0x4f) & 0x100) PotionCauldron_GoBeep(k); return; } if (!Sprite_CheckDamageToLink_same_layer(k) || !(filtered_joypad_L & 0x80)) return; if (link_rupees_goal < 60) { Sprite_ShowMessageUnconditional(0x17c); PotionCauldron_GoBeep(k); return; } if (Sprite_Find_EmptyBottle() < 0) { Sprite_ShowMessageUnconditional(0x50); PotionCauldron_GoBeep(k); return; } SpriteSfx_QueueSfx3WithPan(k, 0x1d); sprite_delay_main[k] = 64; link_rupees_goal -= 60; item_receipt_method = 0; Link_ReceiveItem(0x2f, 0); } void GreenPotionItem_Draw(int k) { // 85f718 static const DrawMultipleData kGreenPotionItem_Dmd[3] = { { 0, 0, 0x08c0, 2}, { 8, 18, 0x0a30, 0}, {-1, 18, 0x0a22, 0}, }; Sprite_DrawMultiplePlayerDeferred(k, kGreenPotionItem_Dmd, 3, NULL); } void Sprite_BlueCauldron(int k) { // 85f72b BluePotionItem_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (sprite_delay_main[k]) return; if (!PotionCauldron_CheckBottles()) { if (Sprite_ShowMessageOnContact(k, 0x4f) & 0x100) PotionCauldron_GoBeep(k); return; } if (!Sprite_CheckDamageToLink_same_layer(k) || !(filtered_joypad_L & 0x80)) return; if (link_rupees_goal < 160) { Sprite_ShowMessageUnconditional(0x17c); PotionCauldron_GoBeep(k); return; } if (Sprite_Find_EmptyBottle() < 0) { Sprite_ShowMessageUnconditional(0x50); PotionCauldron_GoBeep(k); return; } SpriteSfx_QueueSfx3WithPan(k, 0x1d); sprite_delay_main[k] = 64; link_rupees_goal -= 160; item_receipt_method = 0; Link_ReceiveItem(0x30, 0); } void BluePotionItem_Draw(int k) { // 85f7bd static const DrawMultipleData kBluePotionItem_Dmd[4] = { { 0, 0, 0x04c0, 2}, {13, 18, 0x0a30, 0}, { 5, 18, 0x0a22, 0}, {-3, 18, 0x0a31, 0}, }; Sprite_DrawMultiplePlayerDeferred(k, kBluePotionItem_Dmd, 4, NULL); } void Sprite_RedCauldron(int k) { // 85f7d0 RedPotionItem_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (sprite_delay_main[k]) return; if (!PotionCauldron_CheckBottles()) { if (Sprite_ShowMessageOnContact(k, 0x4f) & 0x100) PotionCauldron_GoBeep(k); return; } if (!Sprite_CheckDamageToLink_same_layer(k) || !(filtered_joypad_L & 0x80)) return; if (link_rupees_goal < 120) { Sprite_ShowMessageUnconditional(0x17c); PotionCauldron_GoBeep(k); return; } if (Sprite_Find_EmptyBottle() < 0) { Sprite_ShowMessageUnconditional(0x50); PotionCauldron_GoBeep(k); return; } SpriteSfx_QueueSfx3WithPan(k, 0x1d); sprite_delay_main[k] = 64; link_rupees_goal -= 120; item_receipt_method = 0; Link_ReceiveItem(0x2e, 0); } void PotionCauldron_GoBeep(int k) { // 85f846 SpriteSfx_QueueSfx2WithPan(k, 0x3c); } void RedPotionItem_Draw(int k) { // 85f86d static const DrawMultipleData kRedPotionItem_Dmd[4] = { { 0, 0, 0x02c0, 2}, {13, 18, 0x0a30, 0}, { 5, 18, 0x0a02, 0}, {-3, 18, 0x0a31, 0}, }; Sprite_DrawMultiplePlayerDeferred(k, kRedPotionItem_Dmd, 4, NULL); } bool PotionCauldron_CheckBottles() { // 85f880 return (link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3]) >= 2; } void Sprite_MagicShopAssistant_Main(int k) { // 85f893 Shopkeeper_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (Sprite_CheckIfLinkIsBusy()) return; if (sprite_ai_state[k]) { link_hearts_filler = 160; sprite_ai_state[k] = 0; } sprite_graphics[k] = frame_counter >> 5 & 1; int msg; if (link_bottle_info[0] >= 2 || link_bottle_info[1] >= 2 || link_bottle_info[2] >= 2 || link_bottle_info[3] >= 2 || !flag_overworld_area_did_change) msg = 0x4e; else msg = 0x4d; if (Sprite_ShowSolicitedMessage(k, msg) & 0x100) sprite_ai_state[k] = 1; } void Shopkeeper_Draw(int k) { // 85f91b static const DrawMultipleData kShopkeeper_Dmd[4] = { {0, -8, 0x0c00, 2}, {0, 0, 0x0c10, 2}, {0, -8, 0x0c00, 2}, {0, 0, 0x4c10, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kShopkeeper_Dmd[sprite_graphics[k] * 2], 2, &info); SpriteDraw_Shadow(k, &info); } void Sprite_DashItem(int k) { // 85fbf7 switch (sprite_graphics[k]) { case 0: Sprite_BookOfMudora(k); break; case 1: Sprite_BonkKey(k); break; case 2: Sprite_LumberjackTree(k); break; } } void Sprite_BonkKey(int k) { // 85fc04 Sprite_DrawThinAndTall(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_CheckDamageToLink_same_layer(k)) sprite_ai_state[k] = 3; Sprite_MoveXY(k); sprite_z_vel[k]--; Sprite_MoveZ(k); if (sign8(sprite_z[k])) { sprite_y_vel[k] = 0; sprite_z[k] = 0; sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2; if (sprite_z_vel[k] & 254) SpriteSfx_QueueSfx3WithPan(k, 0x14); } switch (sprite_ai_state[k]) { case 0: // wait for dash if ((uint16)(cur_sprite_x - link_x_coord + 16) < 33 && (uint16)(cur_sprite_y - link_y_coord + 24) < 41 && (bg1_x_offset | bg1_y_offset)) sprite_ai_state[k] = 1; break; case 1: // being falling sprite_z_vel[k] = 32; sprite_y_vel[k] = -5; sound_effect_2 = 27; sprite_ai_state[k] = 2; break; case 2: // falling if (!sprite_z[k]) sprite_floor[k] = link_is_on_lower_level; break; case 3: // give to player link_num_keys++; sprite_state[k] = 0; dung_savegame_state_bits |= (sprite_die_action[k] ? 0x2000 : 0x4000); SpriteSfx_QueueSfx3WithPan(k, 0x2f); break; } } void Sprite_BookOfMudora(int k) { // 85fc9e SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_CheckDamageToLink_same_layer(k)) sprite_ai_state[k] = 3; Sprite_MoveXY(k); sprite_z_vel[k]--; Sprite_MoveZ(k); if (sign8(sprite_z[k])) { sprite_y_vel[k] = 0; sprite_z[k] = 0; sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2; if (sprite_z_vel[k] & 254) SpriteSfx_QueueSfx2WithPan(k, 0x21); } switch (sprite_ai_state[k]) { case 0: // wait for dash if (link_direction_facing == 0 && (uint16)(cur_sprite_x - link_x_coord + 39) < 47 && (uint16)(cur_sprite_y - link_y_coord + 40) < 46 && (bg1_x_offset | bg1_y_offset)) sprite_ai_state[k] = 1; break; case 1: // being falling sprite_z_vel[k] = 32; sprite_y_vel[k] = -5; sound_effect_2 = 27; sprite_ai_state[k] = 2; break; case 2: // falling if (!sprite_z[k]) sprite_floor[k] = link_is_on_lower_level; break; case 3: // give to player Link_CancelDash(); item_receipt_method = 0; Link_ReceiveItem(0x1d, 0); sprite_state[k] = 0; break; } } void Sprite_LumberjackTree(int k) { // 85fd4d sprite_flags2[k] = 0x8f; sprite_flags4[k] = 0x47; DashTreeTop_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_CheckDamageToLink_same_layer(k)) { Sprite_NullifyHookshotDrag(); link_speed_setting = 0; Sprite_RepelDash(); } Sprite_MoveXY(k); sprite_z_vel[k]--; Sprite_MoveZ(k); if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2; } switch (sprite_ai_state[k]) { case 0: // wait for dash sprite_subtype2[k] = 0; if ((uint16)(cur_sprite_x - link_x_coord + 24) < 65 && (uint16)(cur_sprite_y - link_y_coord + 32) < 81 && (bg1_x_offset | bg1_y_offset) & 0xff) { sprite_z_vel[k] = 20; sprite_ai_state[k] = 1; } break; case 1: // spawn leaves if (!sprite_z[k]) { sprite_ai_state[k]++; sound_effect_2 = 0x1b; sprite_x_vel[k] = -4; sprite_y_vel[k] = -4; int j = LumberjackTree_SpawnLeaves(k); sprite_x_vel[j] = 5; sprite_y_vel[j] = 5; j = LumberjackTree_SpawnLeaves(k); sprite_x_vel[j] = 5; sprite_y_vel[j] = -4; j = LumberjackTree_SpawnLeaves(k); sprite_x_vel[j] = -4; sprite_y_vel[j] = 4; } break; case 2: // dancing leaves if (!sprite_delay_main[k]) { sprite_delay_main[k] = 8; if (sprite_subtype2[k] == 6) sprite_state[k] = 0; sprite_subtype2[k]++; } break; } } void DashTreeTop_Draw(int k) { // 85fe6f static const uint16 kDashTreeTop_CharFlags[16] = {0x3100, 0x3102, 0x7102, 0x7100, 0x3120, 0x3122, 0x7122, 0x7120, 0x3104, 0x3106, 0x7106, 0x7104, 0x3124, 0x3126, 0x7126, 0x7124}; static const int8 kDashTreeTop_X[16] = {10, 22, 30, 1, 34, 5, 13, 29, 0, 17, 27, 44, 15, 33, 18, 26}; static const int8 kDashTreeTop_Y[16] = {0, 4, 2, 7, 10, 16, 24, 23, 34, 35, 30, 31, 46, 42, 10, 11}; static const int8 kDashTreeTop_Char[6] = {8, 8, 0x28, 0x28, 0x2a, 0x2a}; static const int8 kDashTreeTop_Flags[6] = {0x31, 0x71, 0x31, 0x71, 0x31, 0x71}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); BYTE(dungmap_var7) -= 0x20; HIBYTE(dungmap_var7) -= 0x20; if (!sprite_subtype2[k]) { uint8 x = BYTE(dungmap_var7); uint8 y = HIBYTE(dungmap_var7); for (int i = 0; i < 16; i++) { oam[i].x = x + (i & 3) * 0x10; oam[i].y = y + (i >> 2) * 0x10; WORD(oam[i].charnum) = kDashTreeTop_CharFlags[i]; } Sprite_CorrectOamEntries(k, 15, 2); } else { int j = sprite_subtype2[k] - 1; for (int i = 15; i >= 0; i--, oam++) { oam->x = BYTE(dungmap_var7) + kDashTreeTop_X[i]; oam->y = HIBYTE(dungmap_var7) + kDashTreeTop_Y[i]; oam->charnum = kDashTreeTop_Char[j]; oam->flags = kDashTreeTop_Flags[j]; } Sprite_CorrectOamEntries(k, 15, 2); } } int LumberjackTree_SpawnLeaves(int k) { // 85ff39 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x3B, &info); assert(j >= 0); sprite_graphics[j] = 2; sprite_z_vel[j] = sprite_z_vel[k]; sprite_subtype2[j] = 1; sprite_ai_state[j] = 2; sprite_delay_main[j] = 8; Sprite_SetSpawnedCoordinates(j, &info); return j; } void Sprite_TroughBoy(int k) { // 85ff66 TroughBoy_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); Sprite_TrackBodyToHead(k); sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; if (savegame_map_icons_indicator < 3) { if (Sprite_ShowSolicitedMessage(k, 0x147) & 0x100) savegame_map_icons_indicator = 2; } else { Sprite_ShowSolicitedMessage(k, 0x148); } } void TroughBoy_Draw(int k) { // 85ffdf static const DrawMultipleData kTroughBoy_Dmd[8] = { {0, -8, 0x0882, 2}, {0, 0, 0x0aaa, 2}, {0, -8, 0x0882, 2}, {0, 0, 0x0aaa, 2}, {0, -8, 0x4880, 2}, {0, 0, 0x0aaa, 2}, {0, -8, 0x0880, 2}, {0, 0, 0x0aaa, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kTroughBoy_Dmd[sprite_D[k] * 2], 2, &info); SpriteDraw_Shadow(k, &info); } void BottleMerchant_DetectFish(int k) { // 868000 for (int i = 15; i >= 0; i--) { if (sprite_state[i] && sprite_type[i] == 0xd2) { SpriteHitBox hb; hb.r0_xlo = sprite_x_lo[k]; hb.r8_xhi = sprite_x_hi[k]; hb.r2 = 16; hb.r1_ylo = sprite_y_lo[k]; hb.r9_yhi = sprite_y_hi[k]; hb.r3 = 16; Sprite_SetupHitBox(i, &hb); if (CheckIfHitBoxesOverlap(&hb)) sprite_E[k] = 0x80 | i; return; } } } void BottleMerchant_BuyFish(int k) { // 868054 static const uint8 kBottleVendor_FishRewardType[5] = {0xdb, 0xe0, 0xde, 0xe2, 0xd9}; static const int8 kBottleVendor_FishRewardXv[5] = {-6, -3, 0, 4, 7}; static const int8 kBottleVendor_FishRewardYv[5] = {11, 14, 16, 14, 11}; SpriteSpawnInfo info; SpriteSfx_QueueSfx3WithPan(k, 0x13); tmp_counter = 4; do { int j = Sprite_SpawnDynamically(k, kBottleVendor_FishRewardType[tmp_counter], &info); if (j < 0) return; Sprite_SetSpawnedCoordinates(j, &info); sprite_x_lo[j] = info.r0_x + 4; sprite_stunned[j] = 0xff; sprite_x_vel[j] = kBottleVendor_FishRewardXv[tmp_counter]; sprite_y_vel[j] = kBottleVendor_FishRewardYv[tmp_counter]; sprite_z_vel[j] = 32; sprite_delay_aux4[j] = 32; } while (!sign8(--tmp_counter)); } void SpritePrep_ThrowableScenery(int k) { // 86850f } void SpriteModule_Initialize(int k) { // 86864d SpritePrep_LoadProperties(k); sprite_state[k]++; kSpritePrep_Main[sprite_type[k]](k); } void SpritePrep_Mantle(int k) { // 868841 sprite_y_lo[k] += 3; sprite_x_lo[k] += 8; } void SpritePrep_Switch(int k) { // 868859 int j = BYTE(dungeon_room_index2); if (j == 0xce || j == 4 || j == 0x3f) sprite_oam_flags[k] = 0xD; } void SpritePrep_SwitchFacingUp(int k) { // 86886d } void SpritePrep_Snitch_bounce_1(int k) { // 86886e SpritePrep_Snitches(k); } void SpritePrep_DoNothingA(int k) { // 868873 } void SpritePrep_Rat(int k) { // 868878 static const uint8 kSpriteRat_BumpDamage[2] = {0, 5}; static const uint8 kSpriteRat_Health[2] = {2, 8}; int j = is_in_dark_world; sprite_bump_damage[k] = kSpriteRat_BumpDamage[j]; sprite_health[k] = kSpriteRat_Health[j]; } void SpritePrep_Keese(int k) { // 86888e static const uint8 kSpriteKeese_BumpDamage[2] = {0x80, 0x85}; static const uint8 kSpriteKeese_Health[2] = {1, 4}; static const uint8 kSpriteKeese_Flags5[2] = {0, 7}; int j = is_in_dark_world; sprite_bump_damage[k] = kSpriteKeese_BumpDamage[j]; sprite_health[k] = kSpriteKeese_Health[j]; sprite_flags5[k] = kSpriteKeese_Flags5[j]; } void SpritePrep_Rope(int k) { // 8688aa static const uint8 kSpriteRope_BumpDamage[2] = {1, 5}; static const uint8 kSpriteRope_Health[2] = {4, 8}; static const uint8 kSpriteRope_Flags5[2] = {1, 7}; int j = is_in_dark_world; sprite_bump_damage[k] = kSpriteRope_BumpDamage[j]; sprite_health[k] = kSpriteRope_Health[j]; sprite_flags5[k] = kSpriteRope_Flags5[j]; } void SpritePrep_Swamola(int k) { // 8688c0 SpritePrep_Swamola_InitializeSegments(k); SpritePrep_Kyameron(k); } void SpritePrep_Blind(int k) { // 8688c7 if (Sprite_ReturnIfBossFinished(k)) return; SpritePrep_Blind_PrepareBattle(k); } void SpritePrep_Ganon(int k) { // 8688cf if (Sprite_ReturnIfBossFinished(k)) return; Ganon_HandleAnimation_Idle(k); sprite_delay_main[k] = 128; sprite_room[k] = 2; music_control = 0x1e; } void SpritePrep_Pokey(int k) { // 8688df static const int8 kHokbok_InitXvel[4] = {16, -16, 16, -16}; static const int8 kHokbok_InitYvel[4] = {16, 16, -16, -16}; sprite_A[k] = 3; sprite_B[k] = 8; int j = GetRandomNumber() & 3; sprite_x_vel[k] = kHokbok_InitXvel[j]; sprite_y_vel[k] = kHokbok_InitYvel[j]; } void SpritePrep_MiniVitreous(int k) { // 8688fd Sprite_ReturnIfBossFinished(k); } void SpritePrep_Gibo(int k) { // 868901 sprite_z[k] = 16; sprite_G[k] = 8; } void SpritePrep_Octoballoon(int k) { // 868910 static const uint8 kSprite_Octoballoon_Delay[4] = {192, 208, 224, 240}; sprite_delay_main[k] = kSprite_Octoballoon_Delay[k & 3]; } void SpritePrep_AgahnimsBarrier(int k) { // 86891b if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x40) sprite_graphics[k] = 4; SpritePrep_MoveDown_8px_Right8px(k); sprite_y_lo[k] -= 12; sprite_ignore_projectile[k]++; } void SpritePrep_Catfish(int k) { // 86892c SpritePrep_MoveDown_8px_Right8px(k); sprite_y_lo[k] -= 12; SpritePrep_IgnoreProjectiles(k); } void SpritePrep_CutsceneAgahnim(int k) { // 86893b if (dung_savegame_state_bits & 0x4000) { sprite_state[k] = 0; } else { CutsceneAgahnim_SpawnZeldaOnAltar(k); sprite_ignore_projectile[k]++; } } void SpritePrep_Vitreous(int k) { // 86894d if (Sprite_ReturnIfBossFinished(k)) return; SpritePrep_MoveDown_8px_Right8px(k); sprite_y_lo[k] -= 16; Vitreous_SpawnSmallerEyes(k); sprite_ignore_projectile[k]++; } void SpritePrep_Raven(int k) { // 868969 static const uint8 kSpriteRaven_BumpDamage[2] = {0x81, 0x88}; static const uint8 kSpriteRaven_Health[2] = {4, 8}; static const uint8 kSpriteRaven_Flags5[2] = {6, 2}; int j = is_in_dark_world; sprite_bump_damage[k] = kSpriteRaven_BumpDamage[j]; sprite_health[k] = kSpriteRaven_Health[j]; sprite_flags5[k] = kSpriteRaven_Flags5[j]; sprite_z[k] = 0; sprite_A[k] = (sprite_x_lo[k] & 16) >> 4; sprite_subtype[k] = 254; } void SpritePrep_Vulture(int k) { // 86897e sprite_z[k] = 0; sprite_A[k] = (sprite_x_lo[k] & 16) >> 4; sprite_subtype[k] = 254; } void SpritePrep_Poe(int k) { // 868991 sprite_z[k] = 12; sprite_subtype[k] = 254; } void SpritePrep_DoNothingC(int k) { // 86899b // empty } void SpritePrep_BlindMaiden(int k) { // 86899c if (!(save_dung_info[0xac] & 0x800)) { sprite_ignore_projectile[k]++; if (savegame_tagalong != 6) { savegame_tagalong = 6; super_bomb_going_off = 0; tagalong_var5 = 0; LoadFollowerGraphics(); Follower_Initialize(); savegame_tagalong = 0; return; } } sprite_state[k] = 0; } void SpritePrep_MiniMoldorm_bounce(int k) { // 8689d3 int j = 32 * k; for (int i = 0; i < 32; i++, j++) { moldorm_x_lo[j] = sprite_x_lo[k]; moldorm_x_hi[j] = sprite_x_hi[k]; moldorm_y_lo[j] = sprite_y_lo[k]; moldorm_y_hi[j] = sprite_y_hi[k]; } } void SpritePrep_Bomber(int k) { // 8689d8 sprite_z[k] = 16; sprite_subtype[k] = 254; } void SpritePrep_BombShoppe(int k) { // 8689df sprite_ignore_projectile[k]++; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xb5, &info); if (j >= 0) { Sprite_SetX(j, info.r0_x - 24); Sprite_SetY(j, info.r2_y - 24); sprite_subtype2[j] = 1; sprite_ignore_projectile[j] = 1; } if ((link_has_crystals & 5) == 5 && sram_progress_indicator_3 & 32) { int j = Sprite_SpawnDynamically(k, 0xb5, &info); if (j >= 0) { Sprite_SetX(j, info.r0_x - 56); Sprite_SetY(j, info.r2_y - 24); sprite_subtype2[j] = 2; sprite_ignore_projectile[j] = 2; } } } void SpritePrep_BullyAndVictim(int k) { // 868a51 SpawnBully(k); sprite_ignore_projectile[k]++; } void SpritePrep_PurpleChest(int k) { // 868a59 if (savegame_tagalong != 12 && !(sram_progress_indicator_3 & 16) && sram_progress_indicator_3 & 32) sprite_ignore_projectile[k]++; else sprite_state[k] = 0; } void SpritePrep_Smithy(int k) { // 868a79 sprite_ignore_projectile[k]++; if (savegame_is_darkworld & 64) { if (sram_progress_indicator_3 & 32 || savegame_tagalong != 0) sprite_state[k] = 0; else sprite_subtype2[k] = 2; return; } Smithy_SpawnDumbBarrierSprite(k); if (!(sram_progress_indicator_3 & 32)) { sprite_x_lo[k] += 2; sprite_y_lo[k] -= 3; return; } sprite_x_lo[k] += 2; sprite_y_lo[k] -= 3; int j = Smithy_SpawnDwarfPal(k); Smithy_SpawnDumbBarrierSprite(j); sprite_E[j] = k; sprite_E[k] = j; if (sram_progress_indicator_3 & 0x80) { sprite_ai_state[k] = 5; sprite_ai_state[j] = 5; } } void SpritePrep_Babasu(int k) { // 868af0 SpritePrep_MoveDown_8px(k); SpritePrep_Zoro(k); } void SpritePrep_Zoro(int k) { // 868af3 sprite_D[k] = (sprite_type[k] - 0x9c) << 1; sprite_graphics[k]--; } void SpritePrep_LaserEye_bounce(int k) { // 868b03 int t = sprite_type[k]; sprite_D[k] = t - 0x95; if (t >= 0x97) { sprite_x_lo[k] += 8; sprite_head_dir[k] = sprite_x_lo[k] & 16 ^ 16; if (!sprite_head_dir[k]) sprite_y_lo[k] += (t & 1) ? -8 : 8; } else { sprite_head_dir[k] = sprite_y_lo[k] & 16; if (!sprite_head_dir[k]) sprite_x_lo[k] += (t & 1) ? -8 : 8; } } void SpritePrep_Popo(int k) { // 868b08 sprite_B[k] = 7; } void SpritePrep_Popo2(int k) { // 868b0c sprite_B[k] = 15; } void SpritePrep_Statue(int k) { // 868b12 sprite_y_lo[k] += 7; } void SpritePrep_Bari(int k) { // 868b1c sprite_z[k] = 6; if (BYTE(dungeon_room_index2) == 206) sprite_C[k]--; sprite_delay_aux1[k] = (GetRandomNumber() & 63) + 128; } void SpritePrep_GreenStalfos(int k) { // 868b2e sprite_z[k] = 9; } void SpritePrep_WaterLever(int k) { // 868b34 sprite_y_lo[k] += 5; } void SpritePrep_FireDebirando(int k) { // 868b3e sprite_type[k] = 0x63; SpritePrep_LoadProperties(k); sprite_G[k]--; SpritePrep_DebirandoPit(k); } void SpritePrep_DebirandoPit(int k) { // 868b4a static const uint8 kDebirando_OamFlags[2] = {6, 8}; sprite_G[k]++; sprite_delay_main[k] = 0; sprite_graphics[k] = 6; SpritePrep_IgnoreProjectiles(k); SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x64, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_delay_main[j] = 96; sprite_head_dir[k] = j; sprite_G[j] = sprite_G[k]; sprite_oam_flags[j] = kDebirando_OamFlags[sprite_G[j]]; } } void SpritePrep_WeakGuard(int k) { // 868b81 sprite_D[k] = sprite_head_dir[k] = GetRandomNumber() & 3; sprite_delay_main[k] = 16; } void SpritePrep_WallCannon(int k) { // 868b93 sprite_D[k] = sprite_type[k] - 0x66; sprite_A[k] = sprite_D[k] & 2; } void SpritePrep_ArrowGame_bounce(int k) { // 868ba2 static const uint8 kArcheryGameGuy_X[8] = {0, 0x40, 0x80, 0xc0, 0x30, 0x60, 0x90, 0xc0}; static const uint8 kArcheryGameGuy_Y[8] = {0, 0x4f, 0x4f, 0x4f, 0x5a, 0x5a, 0x5a, 0x5a}; static const uint8 kArcheryGameGuy_A[8] = {0, 1, 1, 1, 2, 2, 2, 2}; static const int8 kArcheryGameGuy_Xvel[2] = {-8, 12}; static const uint8 kArcheryGameGuy_Flags4[2] = {0x1c, 0x15}; byte_7E0B88 = 0; sprite_y_lo[k] -= 9; for (int i = 7; i != 0; i--) { sprite_type[i] = 0x65; sprite_state[i] = 9; SpritePrep_LoadProperties(i); sprite_x_hi[i] = (link_x_coord >> 8); sprite_x_lo[i] = kArcheryGameGuy_X[i]; sprite_y_hi[i] = (link_y_coord >> 8); sprite_y_lo[i] = kArcheryGameGuy_Y[i]; sprite_A[i] = kArcheryGameGuy_A[i]; int j = kArcheryGameGuy_A[i] - 1; sprite_graphics[i] = j; sprite_x_vel[i] = kArcheryGameGuy_Xvel[j]; sprite_flags4[i] = kArcheryGameGuy_Flags4[j]; sprite_oam_flags[i] = 13; sprite_floor[i] = link_is_on_lower_level; sprite_subtype2[i] = GetRandomNumber(); } sprite_ignore_projectile[k]++; sprite_subtype[k] = link_num_arrows; } void SpritePrep_IgnoreProjectiles(int k) { // 868ba7 sprite_ignore_projectile[k]++; } void SpritePrep_HauntedGroveAnimal(int k) { // 868bab sprite_D[k] = Sprite_IsRightOfLink(k).a; SpritePrep_HauntedGroveOstritch(k); } void SpritePrep_HauntedGroveOstritch(int k) { // 868bb2 if (link_item_flute >= 2) sprite_state[k] = 0; sprite_ignore_projectile[k]++; } void SpritePrep_DiggingGameGuy_bounce(int k) { // 868bbf if (link_y_coord < Sprite_GetY(k)) { sprite_ai_state[k] = 5; sprite_x_lo[k] -= 9; sprite_graphics[k] = 1; } sprite_ignore_projectile[k]++; } void SpritePrep_ThievesTownGrate(int k) { // 868bc4 if (save_ow_event_info[0x58] & 0x20) sprite_state[k] = 0; sprite_ignore_projectile[k]++; Sprite_SetX(k, Sprite_GetX(k) - 8); } void SpritePrep_RupeePull(int k) { // 868bcf sprite_ignore_projectile[k]++; Sprite_SetX(k, Sprite_GetX(k) - 8); } void SpritePrep_Shopkeeper(int k) { // 868bf1 sprite_ignore_projectile[k]++; sprite_flags2[k] |= 2; sprite_oam_flags[k] |= 12; sprite_flags3[k] |= 16; static const uint8 kShopKeeperWhere[13] = {0xf, 0x10, 0, 6, 0x18, 0x12, 0x1e, 0xff, 0x1f, 0x23, 0x24, 0x25, 0x27}; uint8 room = BYTE(dungeon_room_index); int j = FindInByteArray(kShopKeeperWhere, room, 13); switch (j) { case 0: ShopKeeper_SpawnShopItem(k, 0, 7); ShopKeeper_SpawnShopItem(k, 1, 8); ShopKeeper_SpawnShopItem(k, 2, 12); break; case 1: ShopKeeper_SpawnShopItem(k, 0, 9); ShopKeeper_SpawnShopItem(k, 1, 13); ShopKeeper_SpawnShopItem(k, 2, 11); break; case 2: sprite_subtype2[k] = 4; minigame_credits = 0xff; break; case 3: sprite_subtype2[k] = sprite_graphics[k] = 1; minigame_credits = 0xff; break; case 4: sprite_subtype2[k] = 3; minigame_credits = 0xff; break; case 5: case 7: case 8: ShopKeeper_SpawnShopItem(k, 0, 7); ShopKeeper_SpawnShopItem(k, 1, 10); ShopKeeper_SpawnShopItem(k, 2, 12); break; case 6: case 9: case 12: sprite_subtype2[k] = 2; break; case 10: sprite_subtype2[k] = 5; break; case 11: sprite_subtype2[k] = 6; break; default: assert(0); } } void SpritePrep_Storyteller(int k) { // 868c9e static const uint8 kStoryTellerRooms[5] = {0xe, 0xe, 0x12, 0x1a, 0x14}; int r = FindInByteArray(kStoryTellerRooms, BYTE(dungeon_room_index), 5); if (r == 0 && sprite_x_hi[k] & 1) r = 1; sprite_subtype2[k] = r; sprite_ignore_projectile[k]++; } void SpritePrep_Adults(int k) { // 868cc1 static const uint8 kHumanMultiTypes[3] = {3, 0xe1, 0x19}; sprite_ignore_projectile[k]++; sprite_subtype2[k] = FindInByteArray(kHumanMultiTypes, BYTE(dungeon_room_index), 3); } void SpritePrep_Whirlpool(int k) { // 868cd5 sprite_ignore_projectile[k]++; sprite_A[k] = 1; } void SpritePrep_Sage(int k) { // 868cde sprite_ignore_projectile[k]++; if (BYTE(dungeon_room_index) == 10) { sprite_subtype2[k]++; sprite_oam_flags[k] = 11; } } void SpritePrep_BonkItem(int k) { // 868cf2 static const uint16 kDashItemMask[2] = {0x4000, 0x2000}; if (!player_is_indoors) { sprite_graphics[k] = 2; return; } sprite_floor[k] = 2; if (dungeon_room_index == 0x107) { if (link_item_book_of_mudora) sprite_state[k] = 0; else DecodeAnimatedSpriteTile_variable(0xe); } else { int j = byte_7E0B9B++; sprite_die_action[k] = j; if (dung_savegame_state_bits & kDashItemMask[j]) sprite_state[k] = 0; sprite_graphics[k]++; sprite_oam_flags[k] = 8; sprite_flags3[k] |= 0x20; } } void SpritePrep_Kiki(int k) { // 868d46 sprite_ignore_projectile[k]++; if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x20) sprite_state[k] = 0; } void SpritePrep_Locksmith(int k) { // 868d59 sprite_ignore_projectile[k]++; if (savegame_tagalong == 9) { sprite_state[k] = 0; return; } if (savegame_tagalong == 12) { sprite_ai_state[k] = 2; } if (sram_progress_indicator_3 & 0x10) sprite_ai_state[k] = 4; } void SpritePrep_SickKid(int k) { // 868d7f if (link_item_bug_net) sprite_ai_state[k] = 3; sprite_ignore_projectile[k]++; } void SpritePrep_Tektite(int k) { // 868d94 static const uint8 kGanonHelpers_OamFlags[2] = {9, 7}; static const uint8 kGanonHelpers_Health[2] = {8, 12}; static const uint8 kGanonHelpers_BumpDamage[2] = {3, 5}; int j; sprite_A[k] = j = sprite_x_lo[k] >> 4 & 1; sprite_oam_flags[k] = kGanonHelpers_OamFlags[j]; sprite_health[k] = kGanonHelpers_Health[j]; sprite_bump_damage[k] = kGanonHelpers_BumpDamage[j]; Sprite_ApplySpeedTowardsLink(k, 16); sprite_z_vel[k] = 32; sprite_ai_state[k]++; } void SpritePrep_Chainchomp_bounce(int k) { // 868dc1 int i = k * 8; for (int j = 5; j >= 0; j--, i++) { chainchomp_x_hist[i] = cur_sprite_x; chainchomp_y_hist[i] = cur_sprite_y; } sprite_A[k] = sprite_x_lo[k]; sprite_B[k] = sprite_x_hi[k]; sprite_C[k] = sprite_y_lo[k]; sprite_G[k] = sprite_y_hi[k]; } void SpritePrep_BigFairy(int k) { // 868dc6 sprite_z[k] = 24; SpritePrep_MoveDown_8px_Right8px(k); sprite_ignore_projectile[k]++; } void SpritePrep_MrsSahasrahla(int k) { // 868dd1 sprite_y_lo[k] += 8; SpritePrep_MagicBat(k); } void SpritePrep_MagicBat(int k) { // 868dda sprite_x_lo[k] += 8; sprite_ignore_projectile[k]++; } void SpritePrep_FortuneTeller(int k) { // 868de0 SpritePrep_IncrXYLow8(k); sprite_ignore_projectile[k]++; } void SpritePrep_FairyPond(int k) { // 868de9 static const uint8 kLeever_OamFlags[2] = {10, 2}; int j = sprite_x_lo[k] >> 4 & 1; sprite_A[k] = j; sprite_oam_flags[k] = kLeever_OamFlags[j]; } void SpritePrep_Hobo(int k) { // 868dfd for (int i = 15; i; i--) SpritePrep_Hobo_SpawnSmoke(k); for (int i = 15; i; i--) { if (sprite_type[i] == 0x2b) sprite_state[i] = 0; } SpritePrep_Hobo_SpawnFire(k); if (sram_progress_indicator_3 & 1) sprite_ai_state[0] = 3; sprite_ignore_projectile[0] = 1; } void SpritePrep_MasterSword(int k) { // 868e30 sprite_x_lo[k] += 6; sprite_y_lo[k] += 6; } void SpritePrep_Roller_HorizontalRightFirst(int k) { // 868e42 sprite_ai_state[k] = (~sprite_x_lo[k] & 16) >> 4; if (sprite_ai_state[k]) sprite_flags4[k]++; sprite_D[k] = 0; } void SpritePrep_RollerLeftRight(int k) { // 868e46 sprite_ai_state[k] = (~sprite_x_lo[k] & 16) >> 4; if (sprite_ai_state[k]) sprite_flags4[k]++; sprite_D[k] = 1; } void SpritePrep_Roller_VerticalDownFirst(int k) { // 868e4f sprite_ai_state[k] = (sprite_y_lo[k] & 16) >> 4; if (sprite_ai_state[k]) sprite_flags4[k]++; sprite_D[k] = 2; } void SpritePrep_RollerUpDown(int k) { // 868e53 sprite_ai_state[k] = (sprite_y_lo[k] & 16) >> 4; if (sprite_ai_state[k]) sprite_flags4[k]++; sprite_D[k] = 3; } void SpritePrep_Kodongo(int k) { // 868e6b sprite_x_lo[k] += 4; Sprite_SetY(k, Sprite_GetY(k) - 5); sprite_subtype[k]--; } void SpritePrep_Spark(int k) { // 868e85 sprite_subtype[k]--; } void SpritePrep_LostWoodsBird(int k) { // 868ec1 sprite_z_vel[k] = (GetRandomNumber() & 0x1f) - 0x10; sprite_z[k] = 64; SpritePrep_LostWoodsSquirrel(k); } void SpritePrep_LostWoodsSquirrel(int k) { // 868ed2 sprite_x_vel[k] = Sprite_IsRightOfLink(k).a ? -16 : 16; sprite_ignore_projectile[k] = sprite_y_vel[k] = sign8(byte_7E069E[0]) ? 4 : -4; } void SpritePrep_Antifairy(int k) { // 868ef2 static const int8 kBubble_Xvel[2] = {16, -16}; sprite_x_vel[k] = kBubble_Xvel[sprite_x_lo[k] >> 4 & 1]; sprite_y_vel[k] = -16; } void SpritePrep_FallingIce(int k) { // 868f08 if (Sprite_ReturnIfBossFinished(k)) return; sprite_ignore_projectile[k]++; } void SpritePrep_KingZora(int k) { // 868f0f if (link_item_flippers) sprite_state[k] = 0; else sprite_ignore_projectile[k]++; } bool Sprite_ReturnIfBossFinished(int k) { // 868f1c if (dung_savegame_state_bits & 0x8000) { sprite_state[k] = 0; return true; } for (int j = 15; j >= 0; j--) { if (!(kSpriteInit_BumpDamage[sprite_type[j]] & 0x10)) sprite_state[j] = 0; } return false; } void SpritePrep_ArmosKnight(int k) { // 868f3f if (Sprite_ReturnIfBossFinished(k)) return; sprite_delay_main[k] = 255; byte_7E0FF8++; SpritePrep_MoveDown_8px_Right8px(k); } void SpritePrep_DesertStatue(int k) { // 868f4d sprite_A[k] = sprite_limit_instance; sprite_limit_instance++; SpritePrep_MoveDown_8px_Right8px(k); sprite_D[k] = (sprite_x_lo[k] < 0x30) ? 1 : (sprite_x_lo[k] < 0xe0) ? 3 : 2; } void SpritePrep_DoNothingD(int k) { // 868f6c // empty } void SpritePrep_Octorok(int k) { // 868f71 static const uint8 kOctorock_BumpDamage[2] = {3, 5}; static const uint8 kOctorock_Health[2] = {2, 4}; int j = is_in_dark_world; sprite_health[k] = kOctorock_Health[j]; sprite_bump_damage[k] = kOctorock_BumpDamage[j]; sprite_delay_main[k] = GetRandomNumber() & 127; } void SpritePrep_Moldorm_bounce(int k) { // 868f8a if (Sprite_ReturnIfBossFinished(k)) return; sprite_ignore_projectile[k]++; Sprite_InitializedSegmented(k); } void SpritePrep_Lanmolas_bounce(int k) { // 868f95 static const uint8 kLanmola_InitDelay[3] = {128, 192, 255}; if (Sprite_ReturnIfBossFinished(k)) return; sprite_delay_main[k] = kLanmola_InitDelay[k]; sprite_z[k] = -1; for (int i = 0; i < 64; i++) beamos_x_hi[k * 0x40 + i] = 0xff; garnish_y_lo[k] = 7; } void SpritePrep_BigSpike(int k) { // 868f9d SpritePrep_MoveDown_8px_Right8px(k); SpritePrep_Kyameron(k); } void SpritePrep_SwimmingZora(int k) { // 868fa2 sprite_delay_main[k] = 64; SpritePrep_Geldman(k); } void SpritePrep_Geldman(int k) { // 868fa7 sprite_x_lo[k] += 8; SpritePrep_Kyameron(k); } void SpritePrep_Kyameron(int k) { // 868fb0 sprite_A[k] = sprite_x_lo[k]; sprite_B[k] = sprite_x_hi[k]; sprite_C[k] = sprite_y_lo[k]; sprite_head_dir[k] = sprite_y_hi[k]; } void SpritePrep_WalkingZora(int k) { // 868fc9 sprite_delay_main[k] = 96; } void SpritePrep_StandardGuard(int k) { // 868fd6 static const uint8 kSpriteSoldier_Tab0[8] = {0, 2, 1, 3, 6, 4, 5, 7}; uint8 subtype = sprite_subtype[k]; if (subtype != 0) { if ((subtype & 7) >= 5) { int j = ((subtype & 7) != 5) * 4 + (subtype >> 3 & 3); sprite_B[k] = kSpriteSoldier_Tab0[j]; sprite_flags[k] = sprite_flags[k] & 0xf | 0x50; SpritePrep_TrooperAndArcherSoldier(k); return; } sprite_D[k] = ((subtype & 7) - 1) ^ 1; } if (player_is_indoors) { sprite_flags5[k] &= ~0x80; return; } sprite_ai_state[k] = 1; sprite_delay_main[k] = 112; sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL); SpritePrep_TrooperAndArcherSoldier(k); } void SpritePrep_TrooperAndArcherSoldier(int k) { // 869001 uint8 bak0 = submodule_index; submodule_index = 0; sprite_defl_bits[k] = (sprite_defl_bits[k] >> 1) | 0x80; SpriteActive_Main(k); SpriteActive_Main(k); sprite_defl_bits[k] <<= 1; submodule_index = bak0; } void SpritePrep_TalkingTree(int k) { // 869043 sprite_ignore_projectile[k]++; Sprite_SetX(k, Sprite_GetX(k) - 8); SpritePrep_TalkingTree_SpawnEyeball(k, 0); SpritePrep_TalkingTree_SpawnEyeball(k, 1); } void SpritePrep_CrystalSwitch(int k) { // 869064 sprite_oam_flags[k] |= kCrystalSwitchPal[orange_blue_barrier_state & 1]; } void SpritePrep_FluteKid(int k) { // 869075 sprite_ignore_projectile[k]++; sprite_subtype2[k] = savegame_is_darkworld >> 6 & 1; if (sprite_subtype2[k]) { if (sram_progress_indicator_3 & 8 || link_item_flute > 2) { sprite_graphics[k] = 3; sprite_ai_state[k] = 5; } else if (link_item_flute == 2) { sprite_graphics[k] = 1; } sprite_x_lo[k] += 8; sprite_y_lo[k] -= 8; } else { if (link_item_flute >= 2) sprite_state[k] = 0; else sprite_x_lo[k] += 7; } } void SpritePrep_MoveDown_8px(int k) { // 8690cc sprite_y_lo[k] += 8; } void SpritePrep_Zazakku(int k) { // 8690d5 // empty } void SpritePrep_PedestalPlaque(int k) { // 8690d6 sprite_ignore_projectile[k]++; if (BYTE(overworld_screen_index) == 48) sprite_x_lo[k] += 7; } void SpritePrep_Stalfos(int k) { // 8690e0 sprite_subtype[k] = sprite_x_lo[k] & 16; if (sprite_subtype[k]) sprite_oam_flags[k] = 7; } void SpritePrep_KholdstareShell(int k) { // 8690f0 if (Sprite_ReturnIfBossFinished(k)) return; sprite_delay_aux1[k] = 192; SpritePrep_MoveDown_8px_Right8px(k); } void SpritePrep_Kholdstare(int k) { // 8690fa if (Sprite_ReturnIfBossFinished(k)) return; sprite_ai_state[k] = 3; SpritePrep_IgnoreProjectiles(k); SpritePrep_MoveDown_8px_Right8px(k); } void SpritePrep_Bumper(int k) { // 869107 sprite_ignore_projectile[k]++; SpritePrep_MoveDown_8px_Right8px(k); } void SpritePrep_MoveDown_8px_Right8px(int k) { // 86910a sprite_x_lo[k] += 8; sprite_y_lo[k] += 8; } void SpritePrep_HardhatBeetle(int k) { // 869122 static const uint8 kHardHatBeetle_OamFlags[2] = {6, 8}; static const uint8 kHardHatBeetle_Health[2] = {32, 6}; static const uint8 kHardHatBeetle_A[2] = {16, 12}; static const uint8 kHardHatBeetle_State[2] = {1, 3}; static const uint8 kHardHatBeetle_Flags5[2] = {2, 6}; static const uint8 kHardHatBeetle_BumpDamage[2] = {5, 3}; int j = (sprite_x_lo[k] & 0x10) != 0; sprite_oam_flags[k] = kHardHatBeetle_OamFlags[j]; sprite_health[k] = kHardHatBeetle_Health[j]; sprite_A[k] = kHardHatBeetle_A[j]; sprite_ai_state[k] = kHardHatBeetle_State[j]; sprite_flags5[k] = kHardHatBeetle_Flags5[j]; sprite_bump_damage[k] = kHardHatBeetle_BumpDamage[j]; } void SpritePrep_MiniHelmasaur(int k) { // 869151 sprite_A[k] = 16; sprite_ai_state[k] = 1; } void SpritePrep_Fairy(int k) { // 86915c sprite_A[k] = GetRandomNumber() & 1; sprite_D[k] = sprite_A[k] ^ 1; SpritePrep_Absorbable(k); } void SpritePrep_Absorbable(int k) { // 86916a if (!player_is_indoors) { sprite_E[k]++; sprite_ignore_projectile[k]++; } } void SpritePrep_OverworldBonkItem(int k) { // 86916e sprite_E[k]++; sprite_ignore_projectile[k]++; } void SpritePrep_ShieldPickup(int k) { // 869174 } void SpritePrep_NiceBee(int k) { // 869175 uint8 or_bottle = link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3]; if (or_bottle & 8) sprite_state[k] = 0; sprite_E[k]++; sprite_ignore_projectile[k]++; } void SpritePrep_Agahnim(int k) { // 869195 static const uint8 kAgahnim_OamFlags[2] = {11, 7}; if (Sprite_ReturnIfBossFinished(k)) return; sprite_graphics[k] = 0; sprite_D[k] = 3; SpritePrep_MoveDown_8px_Right8px(k); sprite_oam_flags[k] = kAgahnim_OamFlags[is_in_dark_world]; } void SpritePrep_DoNothingG(int k) { // 8691ae // empty } void SpritePrep_FireBar(int k) { // 8691b4 sprite_B[k]++; sprite_ignore_projectile[k]++; } void SpritePrep_Trinexx(int k) { // 8691ba if (Sprite_ReturnIfBossFinished(k)) return; TrinexxComponents_Initialize(k); for (int i = 15; i >= 0; i--) alt_sprite_state[i] = 0; } void SpritePrep_HelmasaurKing(int k) { // 8691c5 if (Sprite_ReturnIfBossFinished(k)) return; HelmasaurKing_Initialize(k); memset(alt_sprite_state, 0, 16); } void SpritePrep_Spike(int k) { // 8691d7 sprite_x_vel[k] = 32; sprite_y_vel[k] = -16; Sprite_MoveY(k); sprite_y_vel[k] = 0; } void SpritePrep_RockStal(int k) { // 8691dc sprite_y_vel[k] = -16; Sprite_MoveY(k); sprite_y_vel[k] = 0; } void SpritePrep_Blob(int k) { // 8691e8 sprite_graphics[k] = 4; SpritePrep_IgnoreProjectiles(k); } void SpritePrep_Arrghus(int k) { // 8691f1 if (Sprite_ReturnIfBossFinished(k)) return; sprite_z[k] = 24; } void SpritePrep_Arrghi(int k) { // 8691fa if (Sprite_ReturnIfBossFinished(k)) return; sprite_subtype2[k] = GetRandomNumber(); if (k == 13) { overlord_x_lo[2] = 0; overlord_x_lo[3] = 0; Arrghus_HandlePuffs(0); } sprite_x_lo[k] = overlord_x_lo[k + 7]; sprite_x_hi[k] = overlord_y_lo[k + 7]; sprite_y_lo[k] = overlord_gen1[k + 7]; sprite_y_hi[k] = overlord_gen3[k + 7]; } void SpritePrep_Mothula(int k) { // 86922f if (Sprite_ReturnIfBossFinished(k)) return; sprite_delay_main[k] = 80; sprite_ignore_projectile[k]++; sprite_graphics[k] = 2; BYTE(dung_floor_move_flags)++; sprite_C[k] = 112; } void SpritePrep_DoNothingH(int k) { // 86924d // empty } void SpritePrep_BigKey(int k) { // 86924e sprite_x_lo[k] += 8; sprite_subtype[k] = 0xff; SpritePrep_BigKey_load_graphics(k); } void SpritePrep_BigKey_load_graphics(int k) { // 869256 DecodeAnimatedSpriteTile_variable(0x22); SpritePrep_KeySetItemDrop(k); } void SpritePrep_SmallKey(int k) { // 869262 sprite_subtype[k] = 255; sprite_die_action[k] = byte_7E0B9B++; } void SpritePrep_KeySetItemDrop(int k) { // 869267 sprite_die_action[k] = byte_7E0B9B; byte_7E0B9B++; } void SpriteActive_Main(int k) { // 869271 uint8 type = sprite_type[k]; kSpriteActiveRoutines[type](k); } void Sprite_09_Moldorm_bounce(int k) { // 869469 static const int8 kGiantMoldorm_Xvel[32] = { 24, 22, 17, 9, 0, -9, -17, -22, -24, -22, -17, -9, 0, 9, 17, 22, 36, 33, 25, 13, 0, -13, -25, -33, -36, -33, -25, -13, 0, 13, 25, 33, }; static const int8 kGiantMoldorm_Yvel[32] = { 0, 9, 17, 22, 24, 22, 17, 9, 0, -9, -17, -22, -24, -22, -17, -9, 0, 13, 25, 33, 36, 33, 25, 13, 0, -13, -25, -33, -36, -33, -25, -13, }; static const uint8 kGiantMoldorm_NextDir[16] = {8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7}; GiantMoldorm_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_ai_state[k] == 3) { // await death if (!sprite_delay_aux4[k]) { sprite_state[k] = 4; sprite_A[k] = 0; sprite_delay_main[k] = 224; } else { sprite_hit_timer[k] = sprite_delay_aux4[k] | 224; } return; } Sprite_CheckDamageFromLink(k); bool low_health = (sprite_health[k] < 3); sprite_subtype2[k] += low_health ? 2 : 1; if (!(frame_counter & (low_health ? 3 : 7))) SpriteSfx_QueueSfx3WithPan(k, 0x31); if (sprite_F[k]) { sprite_delay_aux2[k] = 64; if (!(frame_counter & 3)) sprite_F[k]--; return; } if (!link_incapacitated_timer && Sprite_CheckDamageToLink(k)) { Link_CancelDash(); ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 0x28); link_actual_vel_y = pt.y; link_actual_vel_x = pt.x; link_incapacitated_timer = 24; sprite_delay_aux1[k] = 48; sound_effect_2 = Sprite_CalculateSfxPan(k); } int j = sprite_D[k] + low_health * 16; sprite_x_vel[k] = kGiantMoldorm_Xvel[j]; sprite_y_vel[k] = kGiantMoldorm_Yvel[j]; Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) { sprite_D[k] = kGiantMoldorm_NextDir[sprite_D[k]]; SpriteSfx_QueueSfx2WithPan(k, 0x21); } switch(sprite_ai_state[k]) { case 0: // straight path if (!sprite_delay_main[k]) { j = 1; if (++sprite_G[k] == 3) sprite_G[k] = 0, j = 2; sprite_ai_state[k] = j; sprite_head_dir[k] = (GetRandomNumber() & 2) - 1; sprite_delay_main[k] = (GetRandomNumber() & 31) + 32; } break; case 1: // spinning meander if (!sprite_delay_main[k]) { sprite_delay_main[k] = (GetRandomNumber() & 15) + 8; sprite_ai_state[k] = 0; } else if (!(sprite_delay_main[k] & 3)) { sprite_D[k] = (sprite_D[k] + sprite_head_dir[k]) & 0xf; } break; case 2: // lunge at player if (!((k ^ frame_counter) & 3)) { Sprite_ApplySpeedTowardsLink(k, 0x1f); uint8 dir = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]) - sprite_D[k]; if (dir == 0) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 48; } else { sprite_D[k] += sign8(dir) ? -1 : 1; } } break; } } void Sprite_01_Vulture_bounce(int k) { // 869473 static const uint8 kVulture_Gfx[4] = {1, 2, 3, 2}; sprite_obj_prio[k] |= 0x30; Vulture_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); switch (sprite_ai_state[k]) { case 0: // dormant if (++sprite_subtype2[k] == 160) { sprite_ai_state[k] = 1; SpriteSfx_QueueSfx3WithPan(k, 0x1e); sprite_delay_main[k] = 16; } break; case 1: { // circling sprite_graphics[k] = kVulture_Gfx[frame_counter >> 1 & 3]; if (sprite_delay_main[k]) { sprite_z[k]++; return; } if ((k ^ frame_counter) & 1) return; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, (k & 0xf) + 24); sprite_x_vel[k] = -pt.y; sprite_y_vel[k] = pt.x; if ((uint8)(pt.xdiff + 0x28) < 0x50 && (uint8)(pt.ydiff + 0x28) < 0x50) return; sprite_y_vel[k] += (int8)pt.y >> 2; sprite_x_vel[k] += (int8)pt.x >> 2; break; } } } void Sprite_27_Deadrock(int k) { // 86948a static const uint8 kDeadRock_Gfx[9] = {0, 1, 0, 1, 2, 2, 3, 3, 4}; static const uint8 kDeadRock_OamFlags[9] = {0x40, 0x40, 0, 0, 0, 0x40, 0, 0x40, 0}; static const int8 kDeadRock_Xvel[4] = {32, -32, 0, 0}; static const int8 kDeadRock_Yvel[4] = {0, 0, 32, -32}; int j = (sprite_delay_aux2[k] ? (sprite_delay_aux2[k] & 4) : (sprite_ai_state[k] != 2)) ? sprite_A[k] : 8; sprite_graphics[k] = kDeadRock_Gfx[j]; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kDeadRock_OamFlags[j]; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (!sprite_F[k] && (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Carry) && !sound_effect_1) SpriteSfx_QueueSfx2WithPan(k, 0xb); if (Sprite_CheckDamageToLink_same_layer(k)) { Sprite_NullifyHookshotDrag(); Sprite_RepelDash(); } if (sprite_F[k] == 14) { sprite_ai_state[k] = 2; sprite_delay_aux1[k] = 255; sprite_delay_aux2[k] = 64; } if (Sprite_ReturnIfRecoiling(k)) return; switch(sprite_ai_state[k]) { case 0: // pick dir if (!sprite_delay_main[k]) { sprite_flags2[k] &= ~0x80; sprite_defl_bits[k] &= ~4; sprite_flags3[k] &= ~0x40; sprite_ai_state[k]++; sprite_delay_main[k] = (GetRandomNumber() & 31) + 32; if (++sprite_B[k] == 4) { sprite_B[k] = 0; j = Sprite_DirectionToFaceLink(k, NULL); } else { j = GetRandomNumber() & 3; } set_dir: sprite_D[k] = j; sprite_x_vel[k] = kDeadRock_Xvel[j]; sprite_y_vel[k] = kDeadRock_Yvel[j]; } break; case 1: // walk if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 32; } else { Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) { j = sprite_D[k] ^ 1; goto set_dir; } sprite_A[k] = sprite_D[k] << 1 | ++sprite_subtype2[k] >> 2 & 1; } break; case 2: // petrified sprite_flags2[k] |= 0x80; sprite_defl_bits[k] |= 4; sprite_flags3[k] |= 0x40; if (!(frame_counter & 1)) { if (sprite_delay_aux1[k] == 0) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 16; } else if (sprite_delay_aux1[k] == 0x20) { sprite_delay_aux2[k] = 0x40; } } else { sprite_delay_aux1[k]++; } break; } } void Sprite_20_Sluggula(int k) { // 8695d9 static const uint8 kSluggula_Gfx[8] = {0, 1, 0, 1, 2, 3, 4, 5}; static const uint8 kSluggula_OamFlags[8] = {0x40, 0x40, 0, 0, 0, 0, 0, 0}; static const int8 kSluggula_XYvel[6] = {16, -16, 0, 0, 16, -16}; int j = sprite_D[k] << 1 | (sprite_subtype2[k] & 8) >> 3; sprite_graphics[k] = kSluggula_Gfx[j]; sprite_oam_flags[k] = sprite_oam_flags[k] & 191 | kSluggula_OamFlags[j]; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); sprite_subtype2[k]++; switch(sprite_ai_state[k]) { case 0: // normal if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = (GetRandomNumber() & 31) + 32; sprite_D[k] = j = sprite_delay_main[k] & 3; set_vel: sprite_x_vel[k] = kSluggula_XYvel[j]; sprite_y_vel[k] = kSluggula_XYvel[j + 2]; } else if (sprite_delay_main[k] == 16 && !(GetRandomNumber() & 1)) { Sluggula_DropBomb(k); } break; case 1: // break from bombing if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 32; } Sprite_MoveXY(k); if (!Sprite_CheckTileCollision(k)) return; j = (sprite_D[k] ^= 1); goto set_vel; } } void Sluggula_DropBomb(int k) { // 869673 SpriteSpawnInfo info; int j = Sprite_SpawnDynamicallyEx(k, 0x4a, &info, 11); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); Sprite_TransmuteToBomb(j); } } void Sprite_19_Poe(int k) { // 869688 static const int8 kPoe_Accel[4] = {1, -1, 2, -2}; static const int8 kPoe_ZvelTarget[2] = {8, -8}; static const int8 kPoe_XvelTarget[4] = {16, -16, 28, -28}; static const uint8 kPoe_OamFlags[2] = {0x40, 0}; static const int8 kPoe_Yvel[2] = {8, -8}; int j; sprite_D[k] = j = sprite_x_vel[k] >> 7; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kPoe_OamFlags[j]; if (!sprite_E[k]) sprite_obj_prio[k] |= 0x30; Poe_Draw(k); oam_cur_ptr += 4; oam_ext_cur_ptr++; sprite_flags2[k]--; SpriteDraw_SingleLarge(k); sprite_flags2[k]++; if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; if (sprite_E[k]) { if (++sprite_z[k] == 12) sprite_E[k] = 0; return; } Sprite_CheckDamageToAndFromLink(k); sprite_subtype2[k]++; Sprite_MoveXY(k); if (!(frame_counter & 1)) { j = sprite_G[k] & 1; sprite_z_vel[k] += kPoe_Accel[j]; if (sprite_z_vel[k] == (uint8)kPoe_ZvelTarget[j]) sprite_G[k]++; } Sprite_MoveZ(k); sprite_y_vel[k] = 0; switch(sprite_ai_state[k]) { case 0: // select vertical dir if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; if (!(GetRandomNumber() & 12)) sprite_head_dir[k] = Sprite_IsBelowLink(k).a; else sprite_head_dir[k] = GetRandomNumber() & 1; } break; case 1: // roaming if (!(frame_counter & 1)) { int j = (sprite_anim_clock[k] & 1) + is_in_dark_world * 2; sprite_x_vel[k] += kPoe_Accel[j]; if (sprite_x_vel[k] == (uint8)kPoe_XvelTarget[j]) { sprite_anim_clock[k]++; sprite_ai_state[k] = 0; sprite_delay_main[k] = (GetRandomNumber() & 31) + 16; } } sprite_y_vel[k] = kPoe_Yvel[sprite_head_dir[k]]; break; } } void Poe_Draw(int k) { // 869786 static const int8 kPoe_Draw_X[2] = {9, -1}; static const uint8 kPoe_Draw_Char[4] = {0x7c, 0x80, 0xb7, 0x80}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); uint16 x = info.x + kPoe_Draw_X[sprite_D[k]]; uint16 y = info.y + 9; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kPoe_Draw_Char[sprite_subtype2[k] >> 3 & 3]; oam->flags = info.flags & 0xf0 | 2; bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1); } void Sprite_18_MiniMoldorm(int k) { // 869808 static const int8 kMoldorm_Xvel[16] = {24, 22, 17, 9, 0, -9, -17, -22, -24, -22, -17, -9, 0, 9, 17, 22}; static const int8 kMoldorm_Yvel[16] = {0, 9, 17, 22, 24, 22, 17, 9, 0, -9, -17, -22, -24, -22, -17, -9}; static const uint8 kMoldorm_NextDir[16] = {8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7}; Moldorm_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_F[k]) SpritePrep_MiniMoldorm_bounce(k); if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); sprite_subtype2[k]++; int j = sprite_D[k]; sprite_x_vel[k] = kMoldorm_Xvel[j]; sprite_y_vel[k] = kMoldorm_Yvel[j]; Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) { if (GetRandomNumber() & 1) sprite_head_dir[k] = -sprite_head_dir[k]; sprite_D[k] = kMoldorm_NextDir[sprite_D[k]]; } switch (sprite_ai_state[k]) { case 0: // configure if (!sprite_delay_main[k]) { if (++sprite_G[k] == 6) sprite_G[k] = 0, sprite_ai_state[k] = 2; else sprite_ai_state[k] = 1; sprite_head_dir[k] = (GetRandomNumber() & 2) - 1; sprite_delay_main[k] = (GetRandomNumber() & 0x1f) + 0x20; } break; case 1: // meander if (!sprite_delay_main[k]) { sprite_delay_main[k] = (GetRandomNumber() & 15) + 8; sprite_ai_state[k] = 0; } else if ((sprite_delay_main[k] & 3) == 0) { sprite_D[k] = (sprite_D[k] + sprite_head_dir[k]) & 0xf; } break; case 2: // seek player if (!((k ^ frame_counter) & 3)) { Sprite_ApplySpeedTowardsLink(k, 31); uint8 d = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]) - sprite_D[k]; if (d == 0) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 48; } else { sprite_D[k] = (sprite_D[k] + (sign8(d) ? -1 : 1)) & 0xf; } } break; } } void Sprite_12_Moblin(int k) { // 8698e4 static const int8 kMoblin_Xvel[4] = {16, -16, 0, 0}; static const int8 kMoblin_Yvel[4] = {0, 0, 16, -16}; static const uint8 kMoblin_Delay[4] = {0x10, 0x20, 0x30, 0x40}; static const uint8 kMoblin_Gfx2[8] = {11, 10, 8, 9, 7, 5, 0, 2}; static const uint8 kMoblin_Dirs[8] = {2, 3, 2, 3, 0, 1, 0, 1}; static const uint8 kMoblin_Gfx[4] = {6, 4, 0, 2}; int j; Moblin_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); Sprite_CheckTileCollision2(k); switch(sprite_ai_state[k]) { case 0: // select dir if (!sprite_delay_main[k]) { sprite_delay_main[k] = kMoblin_Delay[GetRandomNumber() & 3]; sprite_ai_state[k]++; sprite_D[k] = sprite_head_dir[k]; j = sprite_head_dir[k]; sprite_x_vel[k] = kMoblin_Xvel[j]; sprite_y_vel[k] = kMoblin_Yvel[j]; } break; case 1: // walk sprite_graphics[k] = (sprite_subtype2[k] & 1) + kMoblin_Gfx[sprite_D[k]]; if (!sprite_wallcoll[k]) { if (sprite_delay_main[k]) { if (sign8(--sprite_E[k])) { sprite_E[k] = 11; sprite_subtype2[k]++; } return; } if (sprite_D[k] == Sprite_DirectionToFaceLink(k, NULL)) { sprite_ai_state[k]++; sprite_delay_main[k] = 32; Sprite_ZeroVelocity_XY(k); sprite_z_vel[k] = 0; return; } sprite_delay_main[k] = 0x10; } else { sprite_delay_main[k] = 0xc; } sprite_head_dir[k] = kMoblin_Dirs[sprite_D[k] << 1 | GetRandomNumber() & 1]; sprite_ai_state[k] = 0; if (++sprite_C[k] == 4) { sprite_C[k] = 0; sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL); } Sprite_ZeroVelocity_XY(k); sprite_z_vel[k] = 0; break; case 2: // throw spear j = sprite_D[k]; if (!sprite_delay_main[k]) sprite_ai_state[k] = 0; if (sprite_delay_main[k] < 16) { if (sprite_delay_main[k] == 15) { Moblin_MaterializeSpear(k); sprite_delay_aux1[k] = 32; } j += 4; } sprite_graphics[k] = kMoblin_Gfx2[j]; break; } } void Moblin_MaterializeSpear(int k) { // 8699eb static const int8 kMoblinSpear_X[4] = {11, -2, -3, 11}; static const int8 kMoblinSpear_Y[4] = {-3, -3, 3, -11}; static const int8 kMoblinSpear_Xvel[4] = {32, -32, 0, 0}; static const int8 kMoblinSpear_Yvel[4] = {0, 0, 32, -32}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x1b, &info), i; if (j >= 0) { sprite_A[j] = 3; sprite_D[j] = i = sprite_D[k]; Sprite_SetX(j, info.r0_x + kMoblinSpear_X[i]); Sprite_SetY(j, info.r2_y + kMoblinSpear_Y[i]); sprite_x_vel[j] = kMoblinSpear_Xvel[i]; sprite_y_vel[j] = kMoblinSpear_Yvel[i]; } } void Moblin_Draw(int k) { // 869bc4 static const DrawMultipleData kMoblin_Dmd[48] = { {-2, 3, 0x8091, 0}, {-2, 11, 0x8090, 0}, { 0, -10, 0x0086, 2}, { 0, 0, 0x008a, 2}, {-2, 7, 0x8091, 0}, {-2, 15, 0x8090, 0}, { 0, -10, 0x0086, 2}, { 0, 0, 0x408a, 2}, { 0, -9, 0x0084, 2}, { 0, 0, 0x00a0, 2}, {11, -5, 0x0090, 0}, {11, 3, 0x0091, 0}, { 0, -9, 0x0084, 2}, { 0, 0, 0x40a0, 2}, {11, -8, 0x0090, 0}, {11, 0, 0x0091, 0}, {-4, 8, 0x0080, 0}, { 4, 8, 0x0081, 0}, { 0, -9, 0x0088, 2}, { 0, 0, 0x00a6, 2}, {-9, 6, 0x0080, 0}, {-1, 6, 0x0081, 0}, { 0, -8, 0x0088, 2}, { 0, 0, 0x00a4, 2}, {12, 8, 0x4080, 0}, { 4, 8, 0x4081, 0}, { 0, -9, 0x4088, 2}, { 0, 0, 0x40a6, 2}, {17, 6, 0x4080, 0}, { 9, 6, 0x4081, 0}, { 0, -8, 0x4088, 2}, { 0, 0, 0x40a4, 2}, {-3, -5, 0x8091, 0}, {-3, 3, 0x8090, 0}, { 0, -10, 0x0086, 2}, { 0, 0, 0x00a8, 2}, {11, -11, 0x0090, 0}, {11, -3, 0x0091, 0}, { 0, -9, 0x0084, 2}, { 0, 0, 0x4082, 2}, {-2, -3, 0x0080, 0}, { 6, -3, 0x0081, 0}, { 0, -9, 0x0088, 2}, { 0, 0, 0x00a2, 2}, {10, -3, 0x4080, 0}, { 2, -3, 0x4081, 0}, { 0, -9, 0x4088, 2}, { 0, 0, 0x40a2, 2}, }; static const uint8 kMoblin_ObjOffs[12] = {2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2}; static const uint8 kMoblin_HeadChar[4] = {0x88, 0x88, 0x86, 0x84}; static const uint8 kMoblin_HeadFlags[4] = {0x40, 0, 0, 0}; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kMoblin_Dmd[sprite_graphics[k] * 4], 4, &info); if (sprite_pause[k]) return; OamEnt *oam = GetOamCurPtr(); if (sprite_delay_aux1[k]) { for (int i = 0; i < 4; i++, oam++) { if (!(bytewise_extended_oam[oam - oam_buf] & 2)) oam->y = 0xf0; } } oam = GetOamCurPtr() + kMoblin_ObjOffs[sprite_graphics[k]]; int j = sprite_head_dir[k]; oam->charnum = kMoblin_HeadChar[j]; oam->flags = oam->flags &~0x40 | kMoblin_HeadFlags[j]; SpriteDraw_Shadow(k, &info); } void Sprite_0E_Snapdragon(int k) { // 869c24 static const uint8 kSnapDragon_Delay[4] = {0x20, 0x30, 0x40, 0x50}; static const uint8 kSnapDragon_Gfx[4] = {4, 0, 6, 2}; static const int8 kSnapDragon_Xvel[8] = {8, -8, 8, -8, 16, -16, 16, -16}; static const int8 kSnapDragon_Yvel[8] = {8, 8, -8, -8, 16, 16, -16, -16}; int j; sprite_graphics[k] = sprite_B[k] + kSnapDragon_Gfx[sprite_D[k]]; SnapDragon_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); sprite_B[k] = 0; switch(sprite_ai_state[k]) { case 0: // resting if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = kSnapDragon_Delay[(GetRandomNumber() & 12) >> 2]; if (sign8(--sprite_A[k])) { sprite_A[k] = 3; sprite_delay_main[k] = 96; sprite_C[k]++; sprite_D[k] = Sprite_IsBelowLink(k).a * 2 + Sprite_IsRightOfLink(k).a; } else { sprite_D[k] = GetRandomNumber() & 3; } } else if (sprite_delay_main[k] & 0x18) { sprite_B[k]++; } break; case 1: // attack sprite_B[k]++; Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) sprite_D[k] ^= 3; j = sprite_D[k] + (sprite_C[k] ? 4 : 0); sprite_x_vel[k] = kSnapDragon_Xvel[j]; sprite_y_vel[k] = kSnapDragon_Yvel[j]; Sprite_MoveZ(k); sprite_z_vel[k] -= 4; if (sign8(sprite_z[k])) { sprite_z[k] = 0; if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_C[k] = 0; sprite_delay_main[k] = 63; } else { sprite_z_vel[k] = 20; } } break; } } void SnapDragon_Draw(int k) { // 869e02 static const DrawMultipleData kSnapDragon_Dmd[32] = { { 4, -8, 0x008f, 0}, {12, -8, 0x009f, 0}, {-4, 0, 0x008c, 2}, { 4, 0, 0x008d, 2}, { 4, -8, 0x002b, 0}, {12, -8, 0x003b, 0}, {-4, 0, 0x0028, 2}, { 4, 0, 0x0029, 2}, {-4, -8, 0x003c, 0}, { 4, -8, 0x003d, 0}, {-4, 0, 0x00aa, 2}, { 4, 0, 0x00ab, 2}, {-4, -8, 0x003e, 0}, { 4, -8, 0x003f, 0}, {-4, 0, 0x00ad, 2}, { 4, 0, 0x00ae, 2}, {-4, -8, 0x409f, 0}, { 4, -8, 0x408f, 0}, {-4, 0, 0x408d, 2}, { 4, 0, 0x408c, 2}, {-4, -8, 0x403b, 0}, { 4, -8, 0x402b, 0}, {-4, 0, 0x4029, 2}, { 4, 0, 0x4028, 2}, { 4, -8, 0x403d, 0}, {12, -8, 0x403c, 0}, {-4, 0, 0x40ab, 2}, { 4, 0, 0x40aa, 2}, { 4, -8, 0x403f, 0}, {12, -8, 0x403e, 0}, {-4, 0, 0x40ae, 2}, { 4, 0, 0x40ad, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kSnapDragon_Dmd[sprite_graphics[k] * 4], 4, &info); SpriteDraw_Shadow(k, &info); } void Sprite_22_Ropa(int k) { // 869e1f Ropa_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); sprite_subtype2[k]++; sprite_graphics[k] = sprite_subtype2[k] >> 3 & 3; switch(sprite_ai_state[k]) { case 0: // stationary if (!sprite_delay_main[k]) { Sprite_ApplySpeedTowardsLink(k, 16); sprite_z_vel[k] = (GetRandomNumber() & 15) + 20; sprite_ai_state[k]++; } break; case 1: // pounce Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) Sprite_ZeroVelocity_XY(k); Sprite_MoveZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_delay_main[k] = 48; sprite_ai_state[k] = 0; } break; } } void Ropa_Draw(int k) { // 869ee5 static const DrawMultipleData kRopa_Dmd[12] = { {0, -8, 0x0026, 0}, {8, -8, 0x0027, 0}, {0, 0, 0x0008, 2}, {0, -8, 0x0036, 0}, {8, -8, 0x0037, 0}, {0, 0, 0x000a, 2}, {0, -8, 0x4027, 0}, {8, -8, 0x4026, 0}, {0, 0, 0x4008, 2}, {0, -8, 0x4037, 0}, {8, -8, 0x4036, 0}, {0, 0, 0x4008, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kRopa_Dmd[sprite_graphics[k] * 3], 3, &info); SpriteDraw_Shadow(k, &info); } void Sprite_11_Hinox(int k) { // 869f05 Hinox_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_F[k]) { Hinox_FaceLink(k); sprite_ai_state[k] = 2; sprite_delay_main[k] = 48; } if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); switch(sprite_ai_state[k]) { case 0: // select dir if (!sprite_delay_main[k]) { if (!(GetRandomNumber() & 3)) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 64; } else { if (++sprite_C[k] == 4) { sprite_C[k] = 0; Hinox_FaceLink(k); } else { static const uint8 kHinox_RandomDirs[8] = {2, 3, 3, 2, 0, 1, 1, 0}; Hinox_SetDirection(k, kHinox_RandomDirs[sprite_D[k] * 2 + (GetRandomNumber() & 1)]); } } } break; case 1: // walk if (sprite_delay_main[k]) { if (sign8(--sprite_A[k])) { sprite_A[k] = 11; sprite_subtype2[k]++; } Sprite_MoveXY(k); if (!Sprite_CheckTileCollision(k)) { static const uint8 kHinox_WalkGfx[4] = {6, 4, 0, 2}; sprite_graphics[k] = kHinox_WalkGfx[sprite_D[k]] + (sprite_subtype2[k] & 1); return; } } sprite_delay_main[k] = 16; sprite_ai_state[k] = 0; break; case 2: // throw bomb if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 2; return; } if (sprite_delay_main[k] == 32) { static const int8 kHinox_BombX[4] = {8, -8, -13, 13}; static const int8 kHinox_BombY[4] = {-11, -11, -16, -16}; static const int8 kHinox_BombXvel[4] = {24, -24, 0, 0}; static const int8 kHinox_BombYvel[4] = {0, 0, 24, -24}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x4a, &info); if (j >= 0) { Sprite_TransmuteToBomb(j); sprite_delay_aux1[j] = 64; int i = sprite_D[k]; Sprite_SetX(j, info.r0_x + kHinox_BombX[i]); Sprite_SetY(j, info.r2_y + kHinox_BombY[i]); sprite_x_vel[j] = kHinox_BombXvel[i]; sprite_y_vel[j] = kHinox_BombYvel[i]; sprite_z_vel[j] = 40; } } else { static const uint8 kHinox_Gfx[8] = {11, 10, 8, 9, 7, 5, 1, 3}; sprite_graphics[k] = kHinox_Gfx[sprite_D[k] + (sprite_delay_main[k] < 32 ? 4 : 0)]; } break; } } void Hinox_ThrowBomb(int k) { // 869f4a } void Hinox_FaceLink(int k) { // 869fe1 Hinox_SetDirection(k, Sprite_DirectionToFaceLink(k, NULL)); sprite_x_vel[k] <<= 1; sprite_y_vel[k] <<= 1; } void Hinox_SetDirection(int k, uint8 dir) { // 86a004 static const int8 kHinox_Xvel[4] = {8, -8, 0, 0}; static const int8 kHinox_Yvel[4] = {0, 0, 8, -8}; sprite_D[k] = dir; sprite_delay_main[k] = (GetRandomNumber() & 63) + 96; sprite_ai_state[k]++; sprite_x_vel[k] = kHinox_Xvel[dir]; sprite_y_vel[k] = kHinox_Yvel[dir]; } void Hinox_Draw(int k) { // 86a1f9 static const DrawMultipleData kHinox_Dmd[46] = { { 0, -13, 0x0600, 2}, { -8, -5, 0x0624, 2}, { 8, -5, 0x4624, 2}, { 0, 1, 0x0606, 2}, { 0, -13, 0x0600, 2}, { -8, -5, 0x0624, 2}, { 8, -5, 0x4624, 2}, { 0, 1, 0x4606, 2}, { -8, -6, 0x0624, 2}, { 8, -6, 0x4624, 2}, { 0, 0, 0x0606, 2}, { 0, -13, 0x0604, 2}, { -8, -6, 0x0624, 2}, { 8, -6, 0x4624, 2}, { 0, 0, 0x4606, 2}, { 0, -13, 0x0604, 2}, { -3, -13, 0x0602, 2}, { 0, -8, 0x060c, 2}, { 0, 0, 0x061c, 2}, { -3, -12, 0x0602, 2}, { 0, -8, 0x060e, 2}, { 0, 0, 0x061e, 2}, { 3, -13, 0x4602, 2}, { 0, -8, 0x460c, 2}, { 0, 0, 0x461c, 2}, { 3, -12, 0x4602, 2}, { 0, -8, 0x460e, 2}, { 0, 0, 0x461e, 2}, {-13, -16, 0x056e, 2}, { 0, -13, 0x0600, 2}, { -8, -5, 0x0620, 2}, { 8, -5, 0x4624, 2}, { 0, 1, 0x0606, 2}, { -8, -5, 0x0624, 2}, { 8, -5, 0x4620, 2}, { 0, 1, 0x0606, 2}, { 0, -13, 0x0604, 2}, { 13, -16, 0x056e, 2}, { -8, -11, 0x056e, 2}, { -3, -13, 0x0602, 2}, { 0, 0, 0x0622, 2}, { 0, -8, 0x060c, 2}, { 8, -11, 0x056e, 2}, { 3, -13, 0x4602, 2}, { 0, 0, 0x4622, 2}, { 0, -8, 0x460c, 2}, }; PrepOamCoordsRet info; static const uint8 kHinoxNum[12] = { 4, 4, 4, 4, 3, 3, 3, 3, 5, 5, 4, 4 }; static const uint8 kHinoxOffs[12] = { 0, 4, 8, 12, 16, 19, 22, 25, 28, 33, 38, 42 }; int j = sprite_graphics[k]; Sprite_DrawMultiple(k, &kHinox_Dmd[kHinoxOffs[j]], kHinoxNum[j], &info); SpriteDraw_Shadow(k, &info); } void Sprite_23_RedBari(int k) { // 86a23d static const int8 kBari_Xvel2[16] = {0, 8, 11, 14, 16, 14, 11, 8, 0, -8, -11, -14, -16, -14, -11, -8}; static const int8 kBari_Yvel2[16] = {-16, -14, -11, -8, 0, 8, 11, 14, 16, 14, 11, 8, 0, -9, -11, -14}; static const uint8 kBari_Gfx[2] = {0, 3}; int j; if (sign8(sprite_C[k])) { if (sprite_head_dir[k] != 16) { sprite_head_dir[k]++; } else { sprite_x_vel[k] = 255; sprite_subtype[k] = 255; Sprite_CheckTileCollision2(k); sprite_subtype[k] = 0; if (!sprite_tiletype) { sprite_C[k] = 0; sprite_ignore_projectile[k] = 0; goto set_electrocute_delay; } sprite_ignore_projectile[k] = sprite_tiletype; } return; } if (sprite_C[k] != 0) { SpriteDraw_SingleSmall(k); } else if (sprite_graphics[k] >= 2) { SpriteDraw_SingleLarge(k); } else { RedBari_Draw(k); } if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; if (sprite_delay_aux2[k]) goto recoil_from_split; if (sprite_ai_state[k] == 2) { static const int8 kBari_Xvel[2] = {8, -8}; sprite_ignore_projectile[k] = sprite_ai_state[k]; sprite_x_vel[k] = kBari_Xvel[frame_counter >> 1 & 1]; Sprite_MoveX(k); if (!sprite_delay_main[k]) { RedBari_Split(k); sprite_state[k] = 0; } return; } Sprite_CheckDamageToAndFromLink(k); if (!((k ^ frame_counter) & 15)) { sprite_A[k] += (sprite_B[k] & 1) ? -1 : 1; if (!(GetRandomNumber() & 3)) sprite_B[k]++; } j = sprite_A[k] & 15; sprite_x_vel[k] = kBari_Xvel2[j]; sprite_y_vel[k] = kBari_Yvel2[j]; if (!((k ^ frame_counter) & 3 | sprite_delay_main[k])) { recoil_from_split: if (!sprite_wallcoll[k]) Sprite_MoveXY(k); Sprite_CheckTileCollision2(k); } j = sprite_C[k]; sprite_graphics[k] = (frame_counter >> 3 & 1) + kBari_Gfx[j]; if (sprite_ai_state[k]) { if (sprite_delay_main[k]) { sprite_graphics[k] = (frame_counter >> 1 & 2) + kBari_Gfx[j]; return; } sprite_ai_state[k] = 0; } else if (sprite_delay_aux1[k]) { return; } else if (!(GetRandomNumber() & 1)) { sprite_delay_main[k] = 128; sprite_ai_state[k]++; return; } set_electrocute_delay: sprite_delay_aux1[k] = (GetRandomNumber() & 63) + 128; } void RedBari_Split(int k) { // 86a34e static const int8 kRedBari_SplitX[2] = {0, 8}; static const int8 kRedBari_SplitXvel[2] = {-32, 32}; tmp_counter = 1; do { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x23, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_flags3[j] = 0x33; sprite_oam_flags[j] = 3; sprite_flags4[j] = 1; sprite_C[j] = 1; Sprite_SetX(j, info.r0_x + kRedBari_SplitX[tmp_counter]); sprite_x_vel[j] = kRedBari_SplitXvel[tmp_counter]; sprite_delay_aux2[j] = 8; sprite_delay_aux1[j] = 64; } } while (!sign8(--tmp_counter)); } void RedBari_Draw(int k) { // 86a3dc static const DrawMultipleData kRedBari_Dmd[8] = { {0, 0, 0x0022, 0}, {8, 0, 0x4022, 0}, {0, 8, 0x0032, 0}, {8, 8, 0x4032, 0}, {0, 0, 0x0023, 0}, {8, 0, 0x4023, 0}, {0, 8, 0x0033, 0}, {8, 8, 0x4033, 0}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kRedBari_Dmd[sprite_graphics[k] * 4], 4, &info); SpriteDraw_Shadow(k, &info); } void Sprite_13_MiniHelmasaur(int k) { // 86a409 static const uint8 kHelmasaur_Gfx[8] = {3, 4, 3, 4, 2, 2, 5, 5}; static const uint8 kHelmasaur_OamFlags[8] = {0x40, 0x40, 0, 0, 0, 0x40, 0x40, 0}; int j = sprite_subtype2[k] >> 2 & 1 | sprite_D[k] << 1; sprite_graphics[k] = kHelmasaur_Gfx[j]; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kHelmasaur_OamFlags[j]; if (!((k ^ frame_counter) & 15)) { uint8 x = sprite_x_vel[k]; if (sign8(x)) x = -x; uint8 y = sprite_y_vel[k]; if (sign8(y)) y = -y; sprite_D[k] = (x >= y) ? (sprite_x_vel[k] >> 7) : (sprite_y_vel[k] >> 7) + 2; } SpriteDraw_SingleLarge(k); HelmasaurHardHatBeetleCommon(k); } void Sprite_26_HardhatBeetle(int k) { // 86a460 sprite_graphics[k] = sprite_subtype2[k] >> 2 & 1; HardHatBeetle_Draw(k); HelmasaurHardHatBeetleCommon(k); } void HelmasaurHardHatBeetleCommon(int k) { // 86a46d if (Sprite_ReturnIfInactive(k)) return; sprite_subtype2[k]++; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); if (sprite_wallcoll[k] & 15) { if (sprite_wallcoll[k] & 3) sprite_x_vel[k] = 0; sprite_y_vel[k] = 0; } else { Sprite_MoveXY(k); } Sprite_CheckTileCollision(k); if (!((k ^ frame_counter) & 31)) { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, sprite_A[k]); sprite_B[k] = pt.y; sprite_C[k] = pt.x; } if ((k ^ frame_counter) & sprite_ai_state[k]) return; sprite_y_vel[k] += sign8(sprite_y_vel[k] - sprite_B[k]) ? 1 : -1; sprite_x_vel[k] += sign8(sprite_x_vel[k] - sprite_C[k]) ? 1 : -1; } void HardHatBeetle_Draw(int k) { // 86a4f2 static const DrawMultipleData kHardHatBeetle_Dmd[4] = { {0, -4, 0x0140, 2}, {0, 2, 0x0142, 2}, {0, -5, 0x0140, 2}, {0, 2, 0x0144, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kHardHatBeetle_Dmd[sprite_graphics[k] * 2], 2, &info); if (sprite_flags3[k] & 0x10) SpriteDraw_Shadow(k, &info); } void Sprite_15_Antifairy(int k) { // 86a50c SpriteDraw_Antfairy(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_CheckDamageToLink(k) && sprite_delay_main[k] == 0) { sprite_delay_main[k] = 16; int t = link_magic_power - 8; if (t < 0) t = 0; else sound_effect_2 = 0x1d; link_magic_power = t; } Sprite_MoveXY(k); Sprite_BounceFromTileCollision(k); } void Sprite_0B_Cucco(int k) { // 86a5c2 if (sprite_x_vel[k] != 0) sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(sprite_x_vel[k]) ? 0 : 0x40); SpriteDraw_SingleLarge(k); if (sprite_head_dir[k] != 0) { sprite_type[k] = 0x3d; SpritePrep_LoadProperties(k); sprite_subtype[k]++; sprite_delay_main[k] = 48; sound_effect_1 = 21; sprite_ignore_projectile[k] = 21; return; } if (sprite_state[k] == 10) { sprite_ai_state[k] = 3; if (submodule_index == 0) { Chicken_IncrSubtype2(k, 3); Cucco_DrawPANIC(k); if (!(frame_counter & 0xf)) BawkBawk(k); } } if (Sprite_ReturnIfInactive(k)) return; if (sprite_C[k] != 0) { sprite_oam_flags[k] |= 0x10; Sprite_MoveXY(k); sprite_z[k] = 12; sprite_ignore_projectile[k] = 12; if (((k ^ frame_counter) & 7) == 0) Sprite_CheckDamageToLink(k); Chicken_IncrSubtype2(k, 4); } else { sprite_health[k] = 255; if (sprite_B[k] >= 35) Cucco_SummonAvenger(k); if (sprite_F[k] != 0) { sprite_F[k] = 0; if (sprite_B[k] < 35) { sprite_B[k]++; BawkBawk(k); } sprite_ai_state[k] = 2; } Sprite_CheckDamageFromLink(k); switch (sprite_ai_state[k]) { case 0: Cucco_Calm(k); break; case 1: Chicken_Hopping(k); break; case 2: Cucco_Flee(k); break; case 3: Cucco_Carried(k); break; } } } void Cucco_Calm(int k) { // 86a67f if (sprite_delay_main[k] == 0) { int j = GetRandomNumber() & 0xf; sprite_x_vel[k] = kSpriteKeese_Tab2[j]; sprite_y_vel[k] = kSpriteKeese_Tab3[j]; sprite_delay_main[k] = (GetRandomNumber() & 0x1f) + 0x10; sprite_ai_state[k]++; } sprite_graphics[k] = 0; Sprite_ReturnIfLifted(k); } void Chicken_Hopping(int k) { // 86a6b1 if ((k ^ frame_counter) & 1 && Cucco_DoMovement_XY(k)) sprite_ai_state[k] = 0; Sprite_MoveZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; if (sprite_delay_main[k] == 0) { sprite_delay_main[k] = 32; sprite_ai_state[k] = 0; } sprite_z_vel[k] = 10; } Chicken_IncrSubtype2(k, 4); } void Cucco_Flee(int k) { // 86a6fc Sprite_ReturnIfLifted(k); Cucco_DoMovement_XY(k); sprite_z[k] = 0; if (!((k ^ frame_counter) & 0x1f)) { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 16); sprite_x_vel[k] = -pt.x; sprite_y_vel[k] = -pt.y; } Chicken_IncrSubtype2(k, 5); Cucco_DrawPANIC(k); } void Cucco_DrawPANIC(int k) { // 86a727 PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; Sprite_DrawDistress_custom(info.x, info.y, frame_counter); } void Cucco_Carried(int k) { // 86a78e Sprite_MoveZ(k); if (Cucco_DoMovement_XY(k)) { sprite_x_vel[k] = -sprite_x_vel[k]; sprite_y_vel[k] = -sprite_y_vel[k]; Sprite_MoveXY(k); Sprite_HalveSpeed_XY(k); Sprite_HalveSpeed_XY(k); BawkBawk(k); } sprite_z_vel[k]--; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_ai_state[k] = 2; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 16); sprite_x_vel[k] = -pt.x; sprite_y_vel[k] = -pt.y; Chicken_IncrSubtype2(k, 5); Cucco_DrawPANIC(k); } else { Chicken_IncrSubtype2(k, 4); } } uint8 Cucco_DoMovement_XY(int k) { // 86a7bb Sprite_MoveXY(k); return Sprite_CheckTileCollision(k); } void Cucco_SummonAvenger(int k) { // 86a7d3 static const uint8 kChicken_Avenger[2] = {0, 0xff}; if ((k ^ frame_counter) & 0xf | player_is_indoors) return; SpriteSpawnInfo info; int j = Sprite_SpawnDynamicallyEx(k, 0xB, &info, 10); if (j < 0) return; SpriteSfx_QueueSfx3WithPan(j, 0x1e); sprite_C[j] = 1; uint8 t = GetRandomNumber(); uint16 x = BG2HOFS_copy2, y = BG2VOFS_copy2; if (t & 2) x += t, y += kChicken_Avenger[t & 1]; else y += t, x += kChicken_Avenger[t & 1]; Sprite_SetX(j, x); Sprite_SetY(j, y); Sprite_ApplySpeedTowardsLink(j, 32); BawkBawk(k); } void BawkBawk(int k) { // 86a84c SpriteSfx_QueueSfx2WithPan(k, 0x30); } void Sprite_17_Hoarder(int k) { // 86a86c if (sprite_ai_state[k]) Sprite_Hoarder_Frantic(k); else Sprite_Hoarder_Covered(k); } void Sprite_Hoarder_Covered(int k) { // 86a874 static const uint8 kRupeeCoveredGrab_Gfx[4] = {3, 4, 5, 4}; static const int8 kRupeeCoveredGrab_Xvel[4] = {-12, 12, 0, 0}; static const int8 kRupeeCoveredGrab_Yvel[4] = {0, 0, -12, 12}; CoveredRupeeCrab_Draw(k); if (Sprite_ReturnIfInactive(k)) return; sprite_graphics[k] = 0; PointU8 pt; uint8 dir = Sprite_DirectionToFaceLink(k, &pt); if (sprite_delay_main[k]) goto lbl; if ((uint8)(pt.y + 0x30) < 0x60 && (uint8)(pt.x + 0x20) < 0x40) { sprite_delay_main[k] = 32; lbl:sprite_x_vel[k] = kRupeeCoveredGrab_Xvel[dir]; sprite_y_vel[k] = kRupeeCoveredGrab_Yvel[dir]; if (!sprite_wallcoll[k]) Sprite_MoveXY(k); Sprite_CheckTileCollision2(k); Sprite_CheckDamageFromLink(k); sprite_graphics[k] = kRupeeCoveredGrab_Gfx[++sprite_subtype2[k] >> 1 & 3]; } if (sprite_type[k] != 0x3e || link_item_gloves >= 1) Sprite_ReturnIfLiftedPermissive(k); // note, dont ret if (sprite_state[k] != 9) { sprite_C[k] = (sprite_type[k] == 0x17) ? 2 : 1; sprite_type[k] = 0xec; sprite_oam_flags[k] &= ~1; sprite_graphics[k] = 0; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x3e, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_flags2[j] &= ~0x80; sprite_delay_aux2[j] = 128; sprite_oam_flags[j] = 9; sprite_ai_state[j] = 9; } } } void Sprite_Hoarder_Frantic(int k) { // 86a91d static const uint8 kRupeeCrab_Gfx[4] = {0, 1, 0, 1}; static const uint8 kRupeeCrab_OamFlags[4] = {0, 0, 0x40, 0}; static const int8 kRupeeCrab_Xvel[4] = {-16, 16, -16, 16}; static const int8 kRupeeCrab_Yvel[4] = {-16, -16, 16, 16}; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageFromLink(k); if (!sprite_delay_aux2[k]) Sprite_CheckDamageToLink(k); int j = ++sprite_subtype2[k] >> 1 & 3; sprite_graphics[k] = kRupeeCrab_Gfx[j]; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kRupeeCrab_OamFlags[j]; if (sprite_wallcoll[k]) { sprite_delay_aux4[k] = 16; j = GetRandomNumber() & 3; sprite_x_vel[k] = kRupeeCrab_Xvel[j]; sprite_y_vel[k] = kRupeeCrab_Yvel[j]; } else { Sprite_MoveXY(k); } Sprite_CheckTileCollision2(k); if (!sprite_delay_aux4[k] && !((k ^ frame_counter) & 31)) { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 16); sprite_y_vel[k] = -pt.y; sprite_x_vel[k] = -pt.x; } if (frame_counter & 1) return; int end; uint8 type; if (++sprite_G[k] == 192) { sprite_delay_main[k] = 15; sprite_state[k] = 6; sprite_flags2[k] += 4; end = 1; type = 0xd9; } else { if (sprite_G[k] & 15) return; end = 0; type = sprite_head_dir[k] == 6 ? 0xdb : 0xd9; } SpriteSpawnInfo info; j = Sprite_SpawnDynamicallyEx(k, type, &info, end); if (j >= 0) { sprite_head_dir[k]++; Sprite_SetSpawnedCoordinates(j, &info); Sprite_SetX(j, info.r0_x + 8); sprite_z_vel[j] = 32; sprite_delay_aux4[j] = 16; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(j, 16); sprite_y_vel[j] = ~pt.y; sprite_x_vel[j] = ~pt.x; SpriteSfx_QueueSfx3WithPan(k, 0x30); } } void CoveredRupeeCrab_Draw(int k) { // 86aa48 static const int8 kCoveredRupeeCrab_DrawY[12] = {0, 0, 0, -3, 0, -5, 0, -6, 0, -6, 0, -6}; static const uint8 kCoveredRupeeCrab_DrawChar[12] = {0x44, 0x44, 0xe8, 0x44, 0xe8, 0x44, 0xe6, 0x44, 0xe8, 0x44, 0xe6, 0x44}; static const uint8 kCoveredRupeeCrab_DrawFlags[12] = {0, 0xc, 3, 0xc, 3, 0xc, 3, 0xc, 3, 0xc, 0x43, 0xc}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; if (byte_7E0FC6 >= 3) return; OamEnt *oam = GetOamCurPtr(); uint8 r7 = (sprite_type[k] == 0x17) ? 2 : 0; uint8 r6 = sprite_graphics[k] * 2; for (int i = 1; i >= 0; i--, oam++) { int j = i + r6; uint16 x = info.x; uint16 y = info.y + kCoveredRupeeCrab_DrawY[j]; oam->x = x; oam->y = ClampYForOam(y); uint8 ch = kCoveredRupeeCrab_DrawChar[j]; oam->charnum = ch + (ch == 0x44 ? r7 : 0); oam->flags = (info.flags & ~1) | kCoveredRupeeCrab_DrawFlags[j]; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } } void Sprite_EC_ThrownItem(int k) { // 86aae0 if (byte_7E0FC6 < 3) { if (sort_sprites_setting && sprite_floor[k]) { int spr_slot = 0x2c + (k & 3); oam_cur_ptr = 0x0800 + spr_slot * 4; oam_ext_cur_ptr = 0x0A20 + spr_slot; } sprite_ignore_projectile[k] = sprite_state[k]; if (sprite_C[k] >= 6) { SpriteDraw_ThrownItem_Gigantic(k); } else { SpriteDraw_SingleLarge(k); OamEnt *oam = GetOamCurPtr(); uint8 t = player_is_indoors + is_in_dark_world; int j = sprite_C[k]; oam->charnum = kThrowableScenery_Char[j + ((t >= 2) ? 6 : 0)]; oam->flags = (oam->flags & 0xf0) | kThrowableScenery_Flags[j]; sprite_oam_flags[k] = (sprite_oam_flags[k] & 0xc0) | (oam->flags & 0xf); } } if (sprite_state[k] == 9) { if (Sprite_ReturnIfInactive(k)) return; ThrowableScenery_InteractWithSpritesAndTiles(k); } } void SpriteDraw_ThrownItem_Gigantic(int k) { // 86ab76 PrepOamCoordsRet info; sprite_oam_flags[k] = kThrowableScenery_DrawLarge_OamFlags[sprite_C[k] - 6]; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); for (int i = 3; i >= 0; i--, oam++) { uint16 x = info.x + kThrowableScenery_DrawLarge_X[i]; uint16 y = info.y + kThrowableScenery_DrawLarge_Y[i]; oam->x = x; oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0; oam->charnum = 0x4a; oam->flags = kThrowableScenery_DrawLarge_Flags[i] | info.flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } Oam_AllocateFromRegionB(12); oam = GetOamCurPtr(); info.y = Sprite_GetY(k) - BG2VOFS_copy2; for (int i = 2; i >= 0; i--, oam++) { uint16 x = info.x + kThrowableScenery_DrawLarge_X2[i]; uint16 y = info.y + 12; oam->x = x; oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0; oam->charnum = 0x6c; oam->flags = 0x24; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } } void ThrowableScenery_ScatterIntoDebris(int k) { // 86ac41 if (!sign8(sprite_C[k]) && sprite_C[k] >= 6) { for (int i = 3; i >= 0; i--) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xec, &info); if (j >= 0) { sprite_z[j] = sprite_z[k]; Sprite_SetX(j, info.r0_x + kScatterDebris_X[i]); Sprite_SetY(j, info.r2_y + kScatterDebris_Y[i]); sprite_C[j] = 1; Sprite_ScheduleForBreakage(j); sprite_oam_flags[j] = (sprite_C[k] < 7) ? 12 : 0; } } sprite_state[k] = 0; } else { sprite_state[k] = 0; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; int j = 29; while (garnish_type[j--] && j >= 0) {} j++; garnish_type[j] = 22; garnish_active = 22; garnish_x_lo[j] = sprite_x_lo[k]; garnish_x_hi[j] = sprite_x_hi[k]; uint16 y = Sprite_GetY(k) - sprite_z[k] + 0x10; garnish_y_lo[j] = (uint8)y; garnish_y_hi[j] = (uint8)(y >> 8); garnish_oam_flags[j] = info.flags; garnish_floor[j] = sprite_floor[k]; garnish_countdown[j] = 31; garnish_sprite[j] = sprite_C[k]; } } void Sprite_TransmuteToBomb(int k) { // 86ad50 sprite_type[k] = 0x4a; sprite_C[k] = 1; sprite_delay_aux1[k] = 255; sprite_flags3[k] = 0x18; sprite_oam_flags[k] = 8; sprite_health[k] = 0; } void Sprite_28_DarkWorldHintNPC(int k) { // 86ad6f StoryTeller_1_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (!sprite_delay_main[k]) sprite_graphics[k] = frame_counter >> 4 & 1; int type = sprite_subtype2[k]; switch(sprite_subtype2[k]) { case 0: switch (sprite_ai_state[k]) { case 0: DarkWorldHintNPC_Idle(k); break; case 1: if (choice_in_multiselect_box == 0 && DarkWorldHintNPC_HandlePayment()) { Sprite_ShowMessageUnconditional(0xff); sprite_ai_state[k] = 2; } else { Sprite_ShowMessageUnconditional(0x100); sprite_ai_state[k] = 0; } break; case 2: DarkWorldHintNPC_RestoreHealth(k); break; } break; case 1: switch (sprite_ai_state[k]) { case 0: DarkWorldHintNPC_Idle(k); break; case 1: if (choice_in_multiselect_box == 0 && DarkWorldHintNPC_HandlePayment()) { Sprite_ShowMessageUnconditional(0x101); sprite_ai_state[k] = 2; } else { Sprite_ShowMessageUnconditional(0x100); sprite_ai_state[k] = 0; } break; case 2: DarkWorldHintNPC_RestoreHealth(k); break; } break; case 2: switch (sprite_ai_state[k]) { case 0: DarkWorldHintNPC_Idle(k); break; case 1: if (choice_in_multiselect_box == 0 && DarkWorldHintNPC_HandlePayment()) { Sprite_ShowMessageUnconditional(0x102); sprite_ai_state[k] = 2; } else { Sprite_ShowMessageUnconditional(0x100); sprite_ai_state[k] = 0; } break; case 2: DarkWorldHintNPC_RestoreHealth(k); break; } break; case 3: if (sprite_delay_main[k] == 0) { if ((frame_counter & 0x3f) == 0) sprite_oam_flags[k] ^= 0x40; if (GetRandomNumber() == 0) sprite_delay_main[k] = 32; } Sprite_ShowSolicitedMessage(k, 0x149); break; case 4: sprite_graphics[k] = frame_counter >> 1 & 1; Sprite_MoveZ(k); if (sign8(sprite_z[k])) sprite_z[k] = 0; sprite_z_vel[k] += (sprite_z[k] >= 4) ? -1 : 1; switch (sprite_ai_state[k]) { case 0: DarkWorldHintNPC_Idle(k); break; case 1: if (choice_in_multiselect_box == 0 && DarkWorldHintNPC_HandlePayment()) { Sprite_ShowMessageUnconditional(0x103); sprite_ai_state[k] = 2; } else { Sprite_ShowMessageUnconditional(0x100); sprite_ai_state[k] = 0; } break; case 2: DarkWorldHintNPC_RestoreHealth(k); break; } break; } } void DarkWorldHintNPC_Idle(int k) { // 86ada7 if (Sprite_ShowSolicitedMessage(k, 0xfe) & 0x100) sprite_ai_state[k] = 1; } void DarkWorldHintNPC_RestoreHealth(int k) { // 86adb5 link_hearts_filler = 0xa0; sprite_ai_state[k] = 0; } bool DarkWorldHintNPC_HandlePayment() { // 86aeab if (link_rupees_goal < 20) return false; link_rupees_goal -= 20; return true; } void StoryTeller_1_Draw(int k) { // 86af1a static const DrawMultipleData kStoryTeller_Dmd[10] = { {0, 0, 0x0a4a, 2}, {0, 0, 0x4a6e, 2}, {0, 0, 0x0a24, 2}, {0, 0, 0x4a24, 2}, {0, 0, 0x0804, 2}, {0, 0, 0x4804, 2}, {0, 0, 0x0a6a, 2}, {0, 0, 0x0a6c, 2}, {0, 0, 0x0a0e, 2}, {0, 0, 0x0a2e, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kStoryTeller_Dmd[sprite_subtype2[k] * 2 + sprite_graphics[k]], 1, &info); SpriteDraw_Shadow(k, &info); } void Sprite_2E_FluteKid(int k) { // 86af3b switch (sprite_head_dir[k]) { case 0: switch (sprite_subtype2[k]) { case 0: FluteKid_Human(k); break; case 1: Sprite_FluteKid_Stumpy(k); break; } break; case 1: Sprite_FluteKid_Quaver(k); break; } } void FluteKid_Human(int k) { // 86af51 if (sprite_ai_state[k] != 3) sprite_C[k] = FluteBoy_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (!sprite_C[k] && !sprite_B[k]) { sound_effect_ambient = 11; sprite_B[k] = 11; } sprite_graphics[k] = frame_counter >> 5 & 1; switch (sprite_ai_state[k]) { case 0: // wait if (link_item_flute >= 2 || FluteBoy_CheckIfPlayerClose(k)) { sprite_ai_state[k] = 1; sprite_D[k]++; byte_7E0FDD++; sprite_delay_main[k] = 176; flag_is_link_immobilized = 1; } if (!sprite_delay_main[k]) { sprite_delay_main[k] = 25; FluteKid_SpawnQuaver(k); } break; case 1: // prep phase out flag_is_link_immobilized = 1; if (!sprite_delay_main[k]) { TS_copy = 2; CGADSUB_copy = 48; BYTE(palette_filter_countdown) = 0; BYTE(darkening_or_lightening_screen) = 0; Palette_AssertTranslucencySwap(); sprite_ai_state[k] = 2; sound_effect_ambient = 128; SpriteSfx_QueueSfx2WithPan(k, 0x33); } break; case 2: // phase out if (!(frame_counter & 15)) { PaletteFilter_SP5F(); if (!BYTE(palette_filter_countdown)) sprite_ai_state[k] = 3; } break; case 3: // phased out PaletteFilter_RestoreSP5F(); Palette_RevertTranslucencySwap(); sprite_state[k] = 0; flag_is_link_immobilized = 0; break; } } void Sprite_FluteKid_Stumpy(int k) { // 86b040 static const int8 kFluteAardvark_Gfx[20] = { 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, -1, }; static const int8 kFluteAardvark_Delay[19] = { -1, -1, -1, 16, 2, 12, 6, 8, 10, 4, 14, 2, 10, 6, 6, 10, 2, 14, 2, }; FluteAardvark_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch (sprite_ai_state[k]) { case 0: // switch (link_item_flute & 3) { case 0: // supplicate if (Sprite_ShowSolicitedMessage(k, 0xe5) & 0x100) sprite_ai_state[k] = 1; break; case 1: // give me flute Sprite_ShowSolicitedMessage(k, 0xe8); break; case 2: // thanks sprite_graphics[k] = 1; if (Sprite_ShowSolicitedMessage(k, 0xe9) & 0x100) sprite_ai_state[k] = 3; break; case 3: // already did sprite_graphics[k] = 3; break; } break; case 1: // if (!choice_in_multiselect_box) { Sprite_ShowMessageUnconditional(0xe6); sprite_ai_state[k] = 2; } else { Sprite_ShowMessageUnconditional(0xe7); sprite_ai_state[k] = 0; } break; case 2: // grant shovel item_receipt_method = 0; Link_ReceiveItem(0x13, 0); sprite_ai_state[k] = 0; break; case 3: // wait for music if (hud_cur_item == 13 && joypad1H_last & 0x40) { sprite_ai_state[k] = 4; music_control = 0xf2; sound_effect_1 = 0; sound_effect_ambient = 23; flag_is_link_immobilized++; } break; case 4: // if (!sprite_delay_main[k]) { if (sprite_A[k] >= 3) SpriteSfx_QueueSfx2WithPan(k, 0x33); int j = sprite_A[k]++; if (kFluteAardvark_Gfx[j] >= 0) { sprite_graphics[k] = kFluteAardvark_Gfx[j]; sprite_delay_main[k] = kFluteAardvark_Delay[j]; } else { music_control = 0xf3; sprite_ai_state[k] = 5; flag_is_link_immobilized = 0; } } break; case 5: // done sprite_graphics[k] = 3; sram_progress_indicator_3 |= 8; break; } } void Sprite_FluteKid_Quaver(int k) { // 86b173 SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXY(k); Sprite_MoveZ(k); if (!sprite_delay_main[k]) sprite_state[k] = 0; if (!(frame_counter & 1)) sprite_x_vel[k] += (frame_counter >> 5 ^ cur_object_index) & 1 ? -1 : 1; } void FluteKid_SpawnQuaver(int k) { // 86b1a5 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x2e, &info); if (j >= 0) { Sprite_SetX(j, info.r0_x + 4); Sprite_SetY(j, info.r2_y - 4); sprite_head_dir[j] = 1; sprite_z_vel[j] = 8; sprite_delay_main[j] = 96; sprite_ignore_projectile[j] = 96; } } void Sprite_1A_Smithy(int k) { // 86b1ee switch (sprite_subtype2[k]) { case 0: Smithy_Main(k); break; case 1: Smithy_Spark(k); break; case 2: Smithy_Frog(k); break; case 3: Smithy_Homecoming(k); break; } } void Smithy_Homecoming(int k) { // 86b1fd ReturningSmithy_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch(sprite_ai_state[k]) { case 0: { // ApproachTheBench static const int8 kReturningSmithy_Delay[3] = {104, 12, 0}; static const int8 kReturningSmithy_Dir[3] = {0, 2, -1}; static const int8 kReturningSmithy_Xvel[4] = {0, 0, -13, 13}; static const int8 kReturningSmithy_Yvel[4] = {-13, 13, 0, 0}; Sprite_MoveXY(k); sprite_graphics[k] = frame_counter >> 3 & 1; if (sprite_delay_main[k]) return; int j = sprite_A[k]++; sprite_delay_main[k] = kReturningSmithy_Delay[j]; if ((j = kReturningSmithy_Dir[j]) >= 0) { sprite_D[k] = j; sprite_x_vel[k] = kReturningSmithy_Xvel[j]; sprite_y_vel[k] = kReturningSmithy_Yvel[j]; } else { sprite_ai_state[k] = 1; } break; } case 1: // Thankful Sprite_BehaveAsBarrier(k); Sprite_ShowSolicitedMessage(k, 0xe3); flag_is_link_immobilized = 0; sprite_D[k] = 1; sram_progress_indicator_3 |= 32; break; } } void Smithy_Frog(int k) { // 86b274 SmithyFrog_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); sprite_z_vel[k] -= 2; Sprite_MoveZ(k); if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = 16; } if (!sprite_ai_state[k]) { sprite_D[k] = 1; if (Sprite_ShowSolicitedMessage(k, 0xe1) & 0x100) sprite_ai_state[k] = 1; } else { savegame_tagalong = 7; LoadFollowerGraphics(); Sprite_BecomeFollower(k); // zelda bug: doesn't save X sprite_state[k] = 0; } } void ReturningSmithy_Draw(int k) { // 86b308 static const DrawMultipleData kReturningSmithy_Dmd[8] = { {0, 0, 0x4122, 2}, {0, 0, 0x0122, 2}, {0, 0, 0x4122, 2}, {0, 0, 0x0122, 2}, {0, 0, 0x0122, 2}, {0, 0, 0x0122, 2}, {0, 0, 0x4122, 2}, {0, 0, 0x4122, 2}, }; static const uint8 kReturningSmithy_Dma[8] = {0xc0, 0xc0, 0xa0, 0xa0, 0x80, 0x60, 0x80, 0x60}; int j = sprite_D[k] * 2 + sprite_graphics[k]; PrepOamCoordsRet info; BYTE(dma_var7) = kReturningSmithy_Dma[j]; Sprite_DrawMultiplePlayerDeferred(k, &kReturningSmithy_Dmd[j], 1, &info); SpriteDraw_Shadow(k, &info); } void SmithyFrog_Draw(int k) { // 86b339 static const DrawMultipleData kSmithyFrog_Dmd[1] = { {0, 0, 0x00c8, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, kSmithyFrog_Dmd, 1, &info); SpriteDraw_Shadow(k, &info); } void Smithy_Main(int k) { // 86b34e Smithy_Draw(k); sprite_z_vel[k] -= 2; Sprite_MoveZ(k); if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = 0; } if (Sprite_ReturnIfInactive(k)) return; int j = sprite_ai_state[sprite_E[k]]; int i = sprite_ai_state[k]; if ((j == 5 || j == 7 || j == 9 || i == 5 || i == 7 || i == 9 || (i | j) == 0) && sprite_B[k]-- == 0) { static const uint8 kSmithy_Gfx[8] = {0, 1, 2, 3, 3, 2, 1, 0}; static const uint8 kSmithy_B[8] = {24, 4, 1, 16, 16, 5, 10, 16}; j = sprite_A[k]; sprite_A[k] = j + 1 & 7; sprite_graphics[k] = kSmithy_Gfx[j]; sprite_B[k] = kSmithy_B[j]; if (j == 1) sprite_z_vel[k] = 16; if (j == 3) { Smithy_SpawnSpark(k); SpriteSfx_QueueSfx2WithPan(k, 0x5); } } switch(sprite_ai_state[k]) { case 0: // ConversationStart sprite_C[k] = 0; if (savegame_tagalong != 8) { if (Smithy_ListenForHammer(k)) { Sprite_ShowMessageUnconditional(0xe4); sprite_delay_aux1[k] = 96; sprite_C[k]++; } else if (sram_progress_indicator_3 & 0x20) { if (Sprite_ShowSolicitedMessage(k, 0xd8) & 0x100) { sprite_ai_state[k]++; sprite_C[k]++; } } else { Sprite_ShowSolicitedMessage(k, 0xdf); } } else { if (BYTE(link_y_coord) < 0xc2) { Sprite_ShowMessageUnconditional(0xe0); sprite_ai_state[k] = 10; flag_is_link_immobilized++; } } break; case 1: // ProvideTemperingChoice if (!choice_in_multiselect_box) { Sprite_ShowMessageUnconditional(0xd9); sprite_ai_state[k] = 2; } else { Sprite_ShowMessageUnconditional(0xdc); sprite_ai_state[k] = 0; } break; case 2: // HandleTemperingChoice if (choice_in_multiselect_box == 0) { if (link_sword_type < 3) { Sprite_ShowMessageUnconditional(0xda); sprite_ai_state[k] = 3; } else { Sprite_ShowMessageUnconditional(0xdb); sprite_ai_state[k] = 0; } } else { Sprite_ShowMessageUnconditional(0xdc); sprite_ai_state[k] = 0; } break; case 3: // HandleTemperingCost if (choice_in_multiselect_box || link_rupees_goal < 10) { Sprite_ShowMessageUnconditional(0xdc); sprite_ai_state[k] = 0; } else { link_rupees_goal -= 10; Sprite_ShowMessageUnconditional(0xdd); sprite_ai_state[sprite_E[k]] = 5; sprite_ai_state[k] = 5; flag_overworld_area_did_change = 0; link_sword_type = 255; sram_progress_indicator_3 |= 128; } break; case 4: // TemperingSword case 5: // sprite_C[k] = 0; if (Smithy_ListenForHammer(k)) { Sprite_ShowMessageUnconditional(0xe4); sprite_delay_aux1[k] = 96; sprite_C[k]++; } else if (flag_overworld_area_did_change) { if (Sprite_ShowSolicitedMessage(k, 0xde) & 0x100) { sprite_ai_state[k]++; sprite_graphics[k] = 4; } } else { Sprite_ShowSolicitedMessage(k, 0xe2); } break; case 6: // Smithy_GiveTemperedSword sprite_ai_state[k] = 0; sprite_ai_state[sprite_E[k]] = 0; item_receipt_method = 0; Link_ReceiveItem(2, 0); sram_progress_indicator_3 &= ~0x80; break; case 7: // case 8: // case 9: // break; case 10: { // Smithy_SpawnFriend SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x1a, &info); if (j >= 0) { Sprite_SetX(j, link_x_coord); Sprite_SetY(j, link_y_coord); sprite_subtype2[j] = 3; sprite_ignore_projectile[j] = 3; } sprite_ai_state[k] = 11; savegame_tagalong = 0; sprite_graphics[k] = 4; break; } case 11: // Smithy_CopiouslyThankful Sprite_ShowSolicitedMessage(k, 0xe3); break; } } bool Smithy_ListenForHammer(int k) { // 86b43d return sprite_delay_aux1[k] == 0 && hud_cur_item == 12 && (link_item_in_hand & 2) && player_handler_timer == 2 && Sprite_CheckDamageToLink_same_layer(k); } int Smithy_SpawnDwarfPal(int k) { // 86b5a6 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x1a, &info); if (j < 0) return j; Sprite_SetX(j, info.r0_x); Sprite_SetY(j, info.r2_y); sprite_x_lo[j] += 0x2C; sprite_D[j] = 1; sprite_A[j] = 4; sprite_ignore_projectile[j] = 4; return j; } void Smithy_Draw(int k) { // 86b673 static const DrawMultipleData kSmithy_Dmd[20] = { { 1, 0, 0x4040, 2}, {-11, -10, 0x4060, 2}, { -1, 0, 0x0040, 2}, { 11, -10, 0x0060, 2}, { 1, 0, 0x4040, 2}, { -3, -14, 0x4044, 2}, { -1, 0, 0x0040, 2}, { 3, -14, 0x0044, 2}, { 1, 0, 0x4042, 2}, { 11, -10, 0x0060, 2}, { -1, 0, 0x0042, 2}, {-11, -10, 0x4060, 2}, { 1, 0, 0x4042, 2}, { 13, 2, 0x4062, 2}, { -1, 0, 0x0042, 2}, {-13, 2, 0x0062, 2}, { 0, 0, 0x4064, 2}, { 0, 0, 0x4062, 2}, { 0, 0, 0x0064, 2}, { 0, 0, 0x0064, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kSmithy_Dmd[sprite_graphics[k] * 4 + sprite_D[k] * 2], 2, &info); SpriteDraw_Shadow(k, &info); } void Smithy_Spark(int k) { // 86b6a3 static const int8 kSmithySpark_Gfx[7] = {0, 1, 2, 1, 2, 1, -1}; static const int8 kSmithySpark_Delay[6] = {4, 1, 3, 2, 1, 1}; SmithySpark_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (!sprite_delay_main[k]) { int j = sprite_A[k]; sprite_A[k] = j + 1 & 7; if (sign8(kSmithySpark_Gfx[j])) { sprite_state[k] = 0; return; } sprite_graphics[k] = kSmithySpark_Gfx[j]; sprite_delay_main[k] = kSmithySpark_Delay[j]; } } void Smithy_SpawnSpark(int k) { // 86b6cd SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x1a, &info); if (j >= 0) { Sprite_SetX(j, info.r0_x); Sprite_SetY(j, info.r2_y); sprite_x_lo[j] += sprite_D[k] ? -15 : 15; sprite_y_lo[j] += 2; sprite_subtype2[j] = 1; } } void SmithySpark_Draw(int k) { // 86b72c Oam_AllocateFromRegionB(8); static const DrawMultipleData kSmithySpark_Dmd[6] = { { 0, 3, 0x41aa, 2}, { 0, -1, 0x41aa, 2}, {-4, 0, 0x0190, 0}, {12, 0, 0x4190, 0}, {-5, -2, 0x0191, 0}, {13, -2, 0x0191, 0}, }; Sprite_DrawMultiple(k, &kSmithySpark_Dmd[sprite_graphics[k] * 2], 2, NULL); } void Sprite_1B_Arrow(int k) { // 86b754 int j; static const int8 kEnemyArrow_Xvel[8] = {0, 0, 16, 16, 0, 0, -16, -16}; static const int8 kEnemyArrow_Yvel[8] = {16, 16, 0, 0, -16, -16, 0, 0}; static const uint8 kEnemyArrow_Dirs[4] = {0, 2, 1, 3}; EnemyArrow_Draw(k); if (Sprite_ReturnIfPaused(k)) return; if (sprite_state[k] == 9) { j = sprite_delay_main[k]; if (j != 0) { if (--j == 0) { sprite_state[k] = 0; } else if (j >= 32 && !(j & 1)) { j = (frame_counter << 1 & 4) | sprite_D[k]; sprite_x_vel[k] = kEnemyArrow_Xvel[j]; sprite_y_vel[k] = kEnemyArrow_Yvel[j]; Sprite_MoveXY(k); } return; } Sprite_CheckDamageToLink_same_layer(k); if (sprite_E[k] == 0 && Sprite_CheckTileCollision(k)) { if (sprite_A[k]) { SpriteSfx_QueueSfx2WithPan(k, 0x5); Sprite_ScheduleForBreakage(k); Sprite_PlaceWeaponTink(k); } else { sprite_delay_main[k] = 48; sprite_A[k] = 2; SpriteSfx_QueueSfx2WithPan(k, 0x8); } } else { Sprite_MoveXY(k); } } else { if (sprite_ai_state[k] == 0) { Sprite_ApplyRicochet(k); sprite_z_vel[k] = 24; sprite_delay_main[k] = 255; sprite_ai_state[k]++; sprite_hit_timer[k] = 0; } sprite_D[k] = kEnemyArrow_Dirs[sprite_delay_main[k] >> 3 & 3]; Sprite_MoveZ(k); Sprite_MoveXY(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) sprite_state[k] = 0; } } void EnemyArrow_Draw(int k) { // 86b867 static const int16 kEnemyArrow_Draw_X[8] = {-8, 0, 0, 8, 0, 0, 0, 0}; static const int16 kEnemyArrow_Draw_Y[8] = {0, 0, 0, 0, -8, 0, 0, 8}; static const uint8 kEnemyArrow_Draw_Char[32] = { 0x3a, 0x3d, 0x3d, 0x3a, 0x2a, 0x2b, 0x2b, 0x2a, 0x7c, 0x6c, 0x6c, 0x7c, 0x7b, 0x6b, 0x6b, 0x7b, 0x3a, 0x3b, 0x3b, 0x3a, 0x2a, 0x3c, 0x3c, 0x2a, 0x81, 0x80, 0x80, 0x81, 0x91, 0x90, 0x90, 0x91, }; static const uint8 kEnemyArrow_Draw_Flags[32] = { 8, 8, 0x48, 0x48, 8, 8, 0x88, 0x88, 9, 0x49, 9, 0x49, 9, 0x89, 9, 0x89, 8, 0x88, 0xc8, 0x48, 8, 8, 0x88, 0x88, 0x49, 0x49, 9, 9, 0x89, 0x89, 9, 9, }; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); uint8 r6 = sprite_D[k] * 2, r7 = sprite_A[k] * 8; for (int i = 1; i >= 0; i--, oam++) { int j = r6 + i; uint16 x = info.x + kEnemyArrow_Draw_X[j]; uint16 y = info.y + kEnemyArrow_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kEnemyArrow_Draw_Char[j + r7]; oam->flags = kEnemyArrow_Draw_Flags[j + r7] | info.flags; bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1); } } void Sprite_1E_CrystalSwitch(int k) { // 86b8d0 sprite_oam_flags[k] = sprite_oam_flags[k] & ~0xe | kCrystalSwitchPal[orange_blue_barrier_state & 1]; Oam_AllocateDeferToPlayer(k); SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_CheckDamageToLink_same_layer(k)) { Sprite_NullifyHookshotDrag(); link_speed_setting = 0; Sprite_RepelDash(); } if (sprite_delay_main[k] == 0) { Sprite_GarnishSpawn_Sparkle(k, frame_counter & 7, GetRandomNumber() & 7); sprite_delay_main[k] = 31; } if (sprite_F[k] == 0) { if (sign8(button_b_frames - 9)) Sprite_CheckDamageFromLink(k); } else if (sprite_F[k]-- == 11) { orange_blue_barrier_state ^= 1; submodule_index = 22; SpriteSfx_QueueSfx3WithPan(k, 0x25); } } void Sprite_1F_SickKid(int k) { // 86b94c static const int8 kBugNetKid_Gfx[8] = {0, 1, 0, 1, 0, 1, 2, -1}; static const uint8 kBugNetKid_Delay[7] = {8, 12, 8, 12, 8, 96, 16}; int j; BugNetKid_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch (sprite_ai_state[k]) { case 0: // resting if (Sprite_CheckIfLinkIsBusy() || !Sprite_CheckDamageToLink_same_layer(k)) return; if ((link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3]) < 2) { Sprite_ShowSolicitedMessage(k, 0x104); } else { flag_is_link_immobilized++; sprite_ai_state[k] = 1; } break; case 1: // perk if (sprite_delay_main[k]) return; j = sprite_A[k]; if (kBugNetKid_Gfx[j] >= 0) { sprite_graphics[k] = kBugNetKid_Gfx[j]; sprite_delay_main[k] = kBugNetKid_Delay[j]; sprite_A[k] = j + 1; } else { Sprite_ShowMessageUnconditional(0x105); sprite_ai_state[k] = 2; } break; case 2: // grant item_receipt_method = 0; Link_ReceiveItem(0x21, 0); flag_is_link_immobilized = 0; sprite_ai_state[k] = 3; break; case 3: // back to rest sprite_graphics[k] = 1; Sprite_ShowSolicitedMessage(k, 0x106); break; } } void Sprite_21_WaterSwitch(int k) { // 86b9fa PushSwitch_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch(sprite_ai_state[k]) { case 0: if (sprite_C[k]) { if (!--sprite_B[k]) sprite_ai_state[k] = 1; if (!(frame_counter & 3)) SpriteSfx_QueueSfx2WithPan(k, 0x22); } else { sprite_B[k] = 48; } break; case 1: if (!sprite_delay_main[k]) { static const uint8 kPushSwitch_Delay[10] = {40, 6, 3, 3, 3, 5, 1, 1, 3, 12}; static const uint8 kPushSwitch_Dir[10] = {0, 1, 2, 3, 4, 5, 5, 6, 7, 6}; int j = ++sprite_A[k]; if (j == 10) { sprite_ai_state[k] = 2; dung_flag_statechange_waterpuzzle++; SpriteSfx_QueueSfx3WithPan(k, 0x25); } else { sprite_delay_main[k] = kPushSwitch_Delay[j]; sprite_D[k] = kPushSwitch_Dir[j]; SpriteSfx_QueueSfx2WithPan(k, 0x22); } } break; case 2: break; } } void PushSwitch_Draw(int k) { // 86bb22 static const OamEntSigned kPushSwitch_Oam[40] = { { 4, 20, 0xdc, 0x20}, { 4, 12, 0xdd, 0x20}, { 4, 12, 0xdd, 0x20}, { 4, 12, 0xdd, 0x20}, { 0, 0, 0xca, 0x20}, { 3, 12, 0xdd, 0x20}, { 3, 20, 0xdc, 0x20}, { 3, 20, 0xdc, 0x20}, { 3, 20, 0xdc, 0x20}, { 0, 0, 0xca, 0x20}, { -8, 8, 0xea, 0x20}, { 0, 8, 0xeb, 0x20}, { -8, 16, 0xfa, 0x20}, { 0, 16, 0xfb, 0x20}, { 0, 0, 0xca, 0x20}, {-12, 4, 0xcc, 0x20}, { -4, 4, 0xcd, 0x20}, { -4, 4, 0xcd, 0x20}, { -4, 4, 0xcd, 0x20}, { 0, 0, 0xca, 0x20}, {-10, 4, 0xcc, 0x20}, { -4, 4, 0xcd, 0x20}, { -4, 4, 0xcd, 0x20}, { -4, 4, 0xcd, 0x20}, { 0, 0, 0xca, 0x20}, { -8, 4, 0xcc, 0x20}, { -4, 4, 0xcd, 0x20}, { -4, 4, 0xcd, 0x20}, { -4, 4, 0xcd, 0x20}, { 0, 0, 0xca, 0x20}, { 4, 3, 0xe2, 0x20}, { -6, 4, 0xcc, 0x20}, { -4, 4, 0xcd, 0x20}, { -4, 4, 0xcd, 0x20}, { 0, 0, 0xca, 0x20}, { 4, 3, 0xf1, 0x20}, { -6, 4, 0xcc, 0x20}, { -4, 4, 0xcd, 0x20}, { -4, 4, 0xcd, 0x20}, { 0, 0, 0xca, 0x20}, }; static const uint8 kPushSwitch_WH[16] = {8, 6, 0x10, 0x10, 0x10, 8, 0x10, 8, 0x10, 8, 0x10, 8, 0x10, 3, 0x10, 8}; Oam_AllocateDeferToPlayer(k); PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; uint8 flags; sprite_oam_flags[k] = flags = overworld_palette_swap_flag ? sprite_oam_flags[k] | 0xe : sprite_oam_flags[k] & ~0xe; uint8 r1 = sprite_B[k] >> 2 & 3; oam_cur_ptr += 4, oam_ext_cur_ptr += 1; OamEnt *oam = GetOamCurPtr(); memcpy(oam, &kPushSwitch_Oam[sprite_D[k] * 5], 20); uint8 xv = -r1 + BYTE(dungmap_var7); uint8 yv = HIBYTE(dungmap_var7) - (r1 >> 1); oam[0].x += xv; oam[1].x += xv; oam[2].x += xv; oam[3].x += xv; oam[4].x += BYTE(dungmap_var7); oam[0].y += yv; oam[1].y += yv; oam[2].y += yv; oam[3].y += yv; oam[4].y += HIBYTE(dungmap_var7); oam[0].flags |= flags; oam[1].flags |= flags; oam[2].flags |= flags; oam[3].flags |= flags; oam[4].flags |= flags; uint8 *ext = &g_ram[oam_ext_cur_ptr]; ext[0] = ext[1] = ext[2] = ext[3] = 0; ext[4] = 2; Sprite_CorrectOamEntries(k, 4, 0xff); if (sprite_floor[k] == link_is_on_lower_level) { sprite_C[k] = 0; int d = sprite_D[k]; int x = Sprite_GetX(k) + (int8)kPushSwitch_Oam[d * 4].x; int y = Sprite_GetY(k) + (int8)kPushSwitch_Oam[d * 4].y; SpriteHitBox hb; hb.r4_spr_xlo = x; hb.r10_spr_xhi = x >> 8; hb.r5_spr_ylo = y; hb.r11_spr_yhi = y >> 8; hb.r6_spr_xsize = kPushSwitch_WH[d * 2 + 0]; hb.r7_spr_ysize = kPushSwitch_WH[d * 2 + 1]; Link_SetupHitBox(&hb); if (CheckIfHitBoxesOverlap(&hb)) { uint16 oldy = Sprite_GetY(k); Sprite_SetY(k, oldy + 19); uint8 new_dir = Sprite_DirectionToFaceLink(k, NULL); Sprite_SetY(k, oldy); if (new_dir == 0 && link_direction_facing == 4) sprite_C[k]++; } else { if (!Sprite_CheckDamageToLink_same_layer(k)) return; } Sprite_NullifyHookshotDrag(); link_speed_setting = 0; Sprite_RepelDash(); } } void Sprite_39_Locksmith(int k) { // 86bcac uint8 bak; int j; MiddleAgedMan_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); switch (sprite_ai_state[k]) { case 0: // chilling Sprite_ShowSolicitedMessage(k, 0x107); bak = sprite_x_lo[k]; sprite_x_lo[k] -= 16; Sprite_Get16BitCoords(k); sprite_x_vel[k] = 1; sprite_y_vel[k] = 1; if (!Sprite_CheckTileCollision(k)) { sprite_ai_state[k]++; if (savegame_tagalong != 0) sprite_ai_state[k] = 5; } sprite_x_lo[k] = bak; break; case 1: // transition to tagalong savegame_tagalong = 9; tagalong_var5 = 0; LoadFollowerGraphics(); Follower_Initialize(); word_7E02CD = 0x40; sprite_state[k] = 0; break; case 2: // offer chest if (Sprite_CheckIfLinkIsBusy()) return; if (super_bomb_going_off) { j = Sprite_ShowSolicitedMessage(k, 0x109); } else { j = Sprite_ShowMessageOnContact(k, 0x109); } if (j & 0x100) sprite_ai_state[k] = 3; break; case 3: // react to secret keeping if (!choice_in_multiselect_box) { if (super_bomb_going_off) { Sprite_ShowMessageUnconditional(0x10c); sprite_ai_state[k] = 2; } else { item_receipt_method = 0; Link_ReceiveItem(0x16, 0); sram_progress_indicator_3 |= 0x10; sprite_ai_state[k] = 4; savegame_tagalong = 0; } } else { Sprite_ShowMessageUnconditional(0x10a); sprite_ai_state[k] = 2; } break; case 4: // promise reminder Sprite_ShowSolicitedMessage(k, 0x10b); break; case 5: // silence other tagalong Sprite_ShowSolicitedMessage(k, 0x107); break; } } void MiddleAgedMan_Draw(int k) { // 86bdac static const DrawMultipleData kMiddleAgedMan_Dmd[2] = { {0, -8, 0x00ea, 2}, {0, 0, 0x00ec, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kMiddleAgedMan_Dmd[0], 2, &info); SpriteDraw_Shadow(k, &info); } void Sprite_2B_Hobo(int k) { // 86bdc1 switch (sprite_subtype2[k]) { case 0: Sprite_Hobo_Bum(k); break; case 1: Sprite_Hobo_Bubble(k); break; case 2: Sprite_Hobo_Fire(k); break; case 3: Sprite_Hobo_Smoke(k); break; } } void Sprite_Hobo_Bum(int k) { // 86bdd0 Hobo_Draw(k); if (Sprite_ReturnIfInactive(k)) return; sprite_flags4[k] = 3; if (Sprite_CheckDamageToLink_same_layer(k)) { Sprite_NullifyHookshotDrag(); link_speed_setting = 0; Link_CancelDash(); } switch(sprite_ai_state[k]) { case 0: // sleeping sprite_flags4[k] = 7; if (Sprite_CheckDamageToLink_same_layer(k) && (filtered_joypad_L & 0x80)) { sprite_ai_state[k] = 1; int j = sprite_E[k]; sprite_delay_main[j] = 4; flag_is_link_immobilized = 1; } if (!sprite_delay_aux2[k]) { sprite_delay_aux2[k] = 160; sprite_E[k] = Hobo_SpawnBubble(k); } break; case 1: // wake up if (!sprite_delay_main[k]) { static const int8 kHobo_Gfx[7] = {0, 1, 0, 1, 0, 1, 2}; static const int8 kHobo_Delay[7] = {6, 2, 6, 6, 2, 100, 30}; int j = sprite_A[k]; if (j != 7) { sprite_graphics[k] = kHobo_Gfx[j]; sprite_delay_main[k] = kHobo_Delay[j]; sprite_A[k]++; } else { Sprite_ShowMessageUnconditional(0xd7); sprite_ai_state[k] = 2; } } break; case 2: // grant bottle sprite_ai_state[k] = 3; sprite_graphics[k] = 1; save_ow_event_info[BYTE(overworld_screen_index)] |= 0x20; item_receipt_method = 0; Link_ReceiveItem(0x16, 0); sram_progress_indicator_3 |= 1; break; case 3: // back to sleep flag_is_link_immobilized = 0; sprite_graphics[k] = 0; if (!sprite_delay_main[k]) { sprite_delay_main[k] = 160; Hobo_SpawnBubble(k); } break; } } void SpritePrep_Hobo_SpawnSmoke(int k) { // 86be9d SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x2b, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_subtype2[j] = 0; sprite_ignore_projectile[j] = 0; } } void Sprite_Hobo_Bubble(int k) { // 86beb4 Oam_AllocateFromRegionC(4); SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; sprite_graphics[k] = (frame_counter >> 4 & 1) + 2; if (!sprite_delay_aux1[k]) { sprite_graphics[k]++; Sprite_MoveZ(k); if (!sprite_delay_main[k]) sprite_state[k] = 0; } if (sprite_delay_main[k] < 4) sprite_graphics[k] = 3; } int Hobo_SpawnBubble(int k) { // 86beed SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x2b, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_subtype2[j] = 1; sprite_z_vel[j] = 2; sprite_delay_main[j] = 96; sprite_delay_aux1[j] = 96 >> 1; sprite_ignore_projectile[j] = 96 >> 1; sprite_flags2[j] = 0; } return j; } void Sprite_Hobo_Fire(int k) { // 86bf15 SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; sprite_graphics[k] = frame_counter >> 3 & 1; sprite_oam_flags[k] &= ~0x40; if (!sprite_delay_main[k]) { Hobo_SpawnSmoke(k); sprite_delay_main[k] = 47; } } void SpritePrep_Hobo_SpawnFire(int k) { // 86bf4b SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x2b, &info); if (j >= 0) { Sprite_SetX(j, 0x194); Sprite_SetY(j, 0x03f); sprite_subtype2[j] = 2; sprite_ignore_projectile[j] = 2; sprite_flags2[j] = 0; sprite_oam_flags[j] = sprite_oam_flags[j] & ~0xE | 2; } } void Sprite_Hobo_Smoke(int k) { // 86bf81 static const uint8 kHoboSmoke_OamFlags[4] = {0, 64, 128, 192}; sprite_graphics[k] = 6; SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXY(k); Sprite_MoveZ(k); sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kHoboSmoke_OamFlags[frame_counter >> 4 & 3]; if (!sprite_delay_main[k]) sprite_state[k] = 0; } void Hobo_SpawnSmoke(int k) { // 86bfaf SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x2b, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); Sprite_SetY(j, info.r2_y - 4); sprite_subtype2[j] = 3; sprite_z_vel[j] = 7; sprite_delay_main[j] = 96; sprite_ignore_projectile[j] = 96; sprite_flags2[j] = 0; } } void Sprite_73_UncleAndPriest_bounce(int k) { // 86bfe0 switch (sprite_E[k]) { case 0: Sprite_Uncle(k); break; case 1: Sprite_Priest(k); break; case 2: Sprite_SanctuaryMantle(k); break; } } void SpritePrep_UncleAndPriest_bounce(int k) { // 86bfe5 if (BYTE(dungeon_room_index) == 18) { Priest_SpawnMantle(k); if (sram_progress_indicator >= 3) sram_progress_flags |= 2; if (sram_progress_flags & 2) { sprite_state[k] = 0; return; } sprite_E[k] = 1; sprite_flags2[k] = sprite_flags2[k] & 0xf0 | 0x2; sprite_flags4[k] = 3; int j; if (link_sword_type >= 2) { sprite_D[k] = 4; sprite_graphics[k] = 0; j = 0; } else { sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; if (savegame_tagalong == 1) { sram_progress_flags |= 0x4; save_ow_event_info[0x1b] |= 0x20; sprite_delay_main[k] = 170; j = 1; } else { j = 2; } } sprite_subtype2[k] = j; static const int16 kUncleAndSage_Y[3] = {0, -9, 0}; Sprite_SetX(k, Sprite_GetX(k) - 6); Sprite_SetY(k, Sprite_GetY(k) + kUncleAndSage_Y[j]); sprite_ignore_projectile[k]++; byte_7FFE01 = 0; } else if (BYTE(dungeon_room_index) == 4) { if (!(sram_progress_flags & 0x10)) sprite_x_lo[k] += 8; else sprite_state[k] = 0; } else { if (!(sram_progress_flags & 1)) { sprite_D[k] = 3; sprite_subtype2[k] = 1; } else { sprite_state[k] = 0; } } } void SpritePrep_OldMan_bounce(int k) { // 86bff9 sprite_ignore_projectile[k]++; if (BYTE(dungeon_room_index) == 0xe4) { sprite_subtype2[k] = 2; return; } if (savegame_tagalong == 0) { if (link_item_mirror == 2) sprite_state[k] = 0; savegame_tagalong = 4; LoadFollowerGraphics(); savegame_tagalong = 0; } else { sprite_state[k] = 0; LoadFollowerGraphics(); } } void Sprite_TutorialGuardOrBarrier_bounce(int k) { // 86bffe if (sprite_type[k] == 0x40) { Sprite_EvilBarrier(k); return; } int jbak = sprite_D[k]; if (sprite_delay_aux1[k]) sprite_D[k] = kSoldier_DirectionLockSettings[jbak]; sprite_graphics[k] = kSprite_TutorialEntities_Tab[sprite_D[k]]; TutorialSoldier_Draw(k); sprite_D[k] = jbak; if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageFromLink(k); if (BYTE(overworld_area_index) == 0x1b && (sprite_y_lo[k] == 0x50 || sprite_y_lo[k] == 0x90)) { Sprite_TutorialGuard_ShowMessageOnContact(k, sprite_y_lo[k] == 0x50 ? 0xB2 : 0xB3); } else { if (Sprite_TutorialGuard_ShowMessageOnContact(k, byte_7E0B69 + 0xf)) { byte_7E0B69 = byte_7E0B69 != 6 ? byte_7E0B69 + 1 : 0; } } Sprite_CheckDamageToAndFromLink(k); if (((k ^ frame_counter) & 0x1f) == 0) { uint8 jbak = sprite_D[k]; sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL); if (sprite_D[k] != jbak && !((sprite_D[k] ^ jbak) & 2)) sprite_delay_aux1[k] = 12; } } void Sprite_F2_MedallionTablet_bounce(int k) { // 86c00d switch (sprite_subtype2[k]) { case 0: MedallionTablet_Main(k); break; case 1: Sprite_DustCloud(k); break; } } void Sprite_33_RupeePull_bounce(int k) { // 86c017 PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_CheckIfLinkIsBusy()) return; if (Sprite_CheckDamageToLink_same_layer(k)) { link_need_for_pullforrupees_sprite = 1; sprite_A[k] = 1; } else { if (sprite_A[k]) { link_need_for_pullforrupees_sprite = 0; if (link_state_bits & 1) { sprite_state[k] = 0; RupeePull_SpawnPrize(k); Sprite_SpawnPoofGarnish(k); } } } } void Sprite_14_ThievesTownGrate_bounce(int k) { // 86c01c PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_CheckIfLinkIsBusy()) return; if (Sprite_CheckDamageToLink_same_layer(k)) { link_need_for_pullforrupees_sprite = 1; sprite_A[k] = 1; } else { if (!sprite_A[k]) return; link_need_for_pullforrupees_sprite = 0; if (!(link_state_bits & 1)) return; SpriteSfx_QueueSfx2WithPan(k, 0x1f); OpenGargoylesDomain(); int j = Sprite_SpawnDustCloud(k); Sprite_SetX(j, Sprite_GetX(k)); Sprite_SetY(j, Sprite_GetY(k)); sprite_state[k] = 0; } } void SpritePrep_Snitch_bounce_2(int k) { // 86c026 SpritePrep_Snitches(k); } void SpritePrep_Snitch_bounce_3(int k) { // 86c030 SpritePrep_Snitches(k); } void Sprite_37_Waterfall_bounce(int k) { // 86c03a switch (sprite_subtype2[k]) { case 0: Waterfall(k); break; case 1: Sprite_BatCrash(k); break; } } void Sprite_38_EyeStatue_bounce(int k) { // 86c03f if (!sprite_B[k]) { PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_DirectionToFaceLink(k, NULL) == 2 && sprite_unk2[k] == 9) { dung_flag_statechange_waterpuzzle++; sprite_B[k] = 1; } } } void Sprite_3A_MagicBat_bounce(int k) { // 86c044 if (sprite_head_dir[k]) { Sprite_MadBatterBolt(k); return; } if (sprite_ai_state[k]) SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXY(k); Sprite_MoveZ(k); switch(sprite_ai_state[k]) { case 0: // wait for summon if (link_magic_consumption >= 2) return; if (!Sprite_CheckDamageToLink_same_layer(k)) return; for (int i = 4; i >= 0; i--) { if (ancilla_type[i] == 0x1a) { Sprite_SpawnSuperficialBombBlast(k); SpriteSfx_QueueSfx1WithPan(k, 0xd); sprite_ai_state[k]++; sprite_A[k] = 20; flag_is_link_immobilized = 1; sprite_oam_flags[k] |= 32; return; } } break; case 1: // RisingUp if (!sprite_delay_main[k]) { sprite_delay_main[k] = --sprite_A[k]; if (sprite_delay_main[k] != 1) { static const int8 kMadBatter_RisingUp_XAccel[2] = {-8, 7}; sprite_z_vel[k] = sprite_delay_main[k] >> 2; sprite_x_vel[k] += kMadBatter_RisingUp_XAccel[sprite_A[k] & 1]; sprite_graphics[k] ^= 1; } else { Sprite_ShowMessageUnconditional(0x110); sprite_ai_state[k]++; sprite_graphics[k] = 0; sprite_z_vel[k] = 0; sprite_x_vel[k] = 0; sprite_delay_main[k] = 255; } } break; case 2: { // PseudoAttackPlayer if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_aux1[k] = 64; } static const int8 kMadBatter_PseudoAttack_OamFlags[8] = {0xa, 4, 2, 4, 2, 0xa, 4, 2}; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0xE | kMadBatter_PseudoAttack_OamFlags[sprite_delay_main[k] >> 1 & 7]; if (sprite_delay_main[k] == 240) Sprite_MagicBat_SpawnLightning(k); break; } case 3: // DoublePlayerMagicPower if (!sprite_delay_aux1[k]) { Sprite_ShowMessageUnconditional(0x111); Palette_Restore_BG_And_HUD(); flag_update_cgram_in_nmi++; sprite_ai_state[k]++; link_magic_consumption = 1; Hud_RefreshIcon(); } else if (sprite_delay_aux1[k] == 0x10) { intro_times_pal_flash = 0x10; } break; case 4: // LaterBitches Sprite_SpawnDummyDeathAnimation(k); sprite_state[k] = 0; flag_is_link_immobilized = 0; break; } } void SpritePrep_Zelda_bounce(int k) { // 86c06c if (link_sword_type >= 2) { sprite_state[k] = 0; return; } sprite_ignore_projectile[k]++; sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; uint8 bak0 = savegame_tagalong; savegame_tagalong = 1; LoadFollowerGraphics(); savegame_tagalong = bak0; if (BYTE(dungeon_room_index) == 0x12) { sprite_subtype2[k] = 2; if (!(sram_progress_flags & 4)) { sprite_state[k] = 0; } else { Sprite_SetX(k, Sprite_GetX(k) + 6); Sprite_SetY(k, Sprite_GetY(k) + 15); sprite_flags4[k] = 3; } } else { sprite_subtype2[k] = 0; if (savegame_tagalong == 1 || (sram_progress_flags & 4)) sprite_state[k] = 0; } } void Sprite_78_MrsSahasrahla_bounce(int k) { // 86c071 ElderWife_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); switch (sprite_ai_state[k]) { case 0: // initial if (link_sword_type < 2) { if (Sprite_ShowSolicitedMessage(k, 0x2b) & 0x100) sprite_ai_state[k] = 1; } else { Sprite_ShowSolicitedMessage(k, 0x2e); } sprite_graphics[k] = frame_counter >> 4 & 1; break; case 1: // tell legend Sprite_ShowMessageUnconditional(0x2c); sprite_ai_state[k] = 2; break; case 2: // loop until player not dumb if (choice_in_multiselect_box == 0) { sprite_ai_state[k] = 3; Sprite_ShowMessageUnconditional(0x2d); } else { Sprite_ShowMessageUnconditional(0x2c); } break; case 3: // go away find old man Sprite_ShowSolicitedMessage(k, 0x2d); sprite_graphics[k] = frame_counter >> 4 & 1; break; } } void Sprite_16_Elder_bounce(int k) { // 86c08a Elder_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); switch (sprite_subtype2[k]) { case 0: Sprite_Sahasrahla(k); break; case 1: Sprite_Aginah(k); break; } } void SpritePrep_HeartPiece(int k) { // 86c0a8 HeartUpgrade_CheckIfAlreadyObtained(k); } void Sprite_2D_TelepathicTile_bounce(int k) { // 86c0b2 assert(0); } void Sprite_25_TalkingTree_bounce(int k) { // 86c0d5 switch (sprite_subtype2[k]) { case 0: TalkingTree_Mouth(k); break; case 1: TalkingTree_Eye(k); break; } } void Sprite_1C_Statue(int k) { // 86c0e8 static const uint8 kMovableStatue_Dir[4] = {4, 6, 0, 2}; static const uint8 kMovableStatue_Joypad[4] = {1, 2, 4, 8}; static const int8 kMovableStatue_Xvel[4] = {-16, 16, 0, 0}; static const int8 kMovableStatue_Yvel[4] = {0, 0, -16, 16}; int j; if (sprite_D[k]) { sprite_D[k] = 0; link_speed_setting = 0; bitmask_of_dragstate = 0; } if (sprite_delay_main[k]) { sprite_D[k] = 1; bitmask_of_dragstate = 129; link_speed_setting = 8; } MovableStatue_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Statue_BlockSprites(k); dung_flag_statechange_waterpuzzle = 0; if (Statue_CheckForSwitch(k)) dung_flag_statechange_waterpuzzle = 1; Sprite_MoveXY(k); Sprite_Get16BitCoords(k); Sprite_CheckTileCollision2(k); Sprite_ZeroVelocity_XY(k); if (Sprite_CheckDamageToLink_same_layer(k)) { sprite_delay_main[k] = 7; Sprite_RepelDash(); if (sprite_delay_aux1[k]) { Sprite_NullifyHookshotDrag(); return; } j = Sprite_DirectionToFaceLink(k, NULL); sprite_x_vel[k] = kMovableStatue_Xvel[j]; sprite_y_vel[k] = kMovableStatue_Yvel[j]; } else { if (!sprite_delay_main[k]) sprite_delay_aux1[k] = 13; if ((uint16)(cur_sprite_x - link_x_coord + 16) < 35 && (uint16)(cur_sprite_y - link_y_coord + 12) < 36 && link_direction_facing == kMovableStatue_Dir[j = Sprite_DirectionToFaceLink(k, NULL)] && !link_is_running) { link_is_near_moveable_statue = 1; sprite_A[k] = 1; if (!(link_grabbing_wall & 2) || !(kMovableStatue_Joypad[j] & joypad1H_last) || (link_x_vel | link_y_vel) == 0) return; j ^= 1; sprite_x_vel[k] = kMovableStatue_Xvel[j]; sprite_y_vel[k] = kMovableStatue_Yvel[j]; } else { if (sprite_A[k]) { sprite_A[k] = 0; link_speed_setting = 0; link_grabbing_wall = 0; link_is_near_moveable_statue = 0; link_cant_change_direction &= ~1; } return; } } if (!(link_grabbing_wall & 2)) Sprite_NullifyHookshotDrag(); if (!(sprite_wallcoll[k] & 15) && !sprite_delay_aux4[k]) { SpriteSfx_QueueSfx2WithPan(k, 0x22); sprite_delay_aux4[k] = 8; } } bool Statue_CheckForSwitch(int k) { // 86c203 static const int8 kMovableStatue_SwitchX[4] = {3, 12, 3, 12}; static const int8 kMovableStatue_SwitchY[4] = {3, 3, 12, 12}; for (int j = 3; j >= 0; j--) { uint16 x = Sprite_GetX(k) + kMovableStatue_SwitchX[j]; uint16 y = Sprite_GetY(k) + kMovableStatue_SwitchY[j]; uint8 t = GetTileAttribute(sprite_floor[k], &x, y); if (t != 0x23 && t != 0x24 && t != 0x25 && t != 0x3b) return false; } return true; } void MovableStatue_Draw(int k) { // 86c264 static const DrawMultipleData kMovableStatue_Dmd[3] = { {0, -8, 0x00c2, 0}, {8, -8, 0x40c2, 0}, {0, 0, 0x00c0, 2}, }; Sprite_DrawMultiplePlayerDeferred(k, &kMovableStatue_Dmd[0], 3, NULL); } void Statue_BlockSprites(int k) { // 86c277 for (int j = 15; j >= 0; j--) { if (sprite_type[j] == 0x1c || j == k || (j ^ frame_counter) & 1 || sprite_state[j] < 9) continue; int x = Sprite_GetX(j), y = Sprite_GetY(j); if ((uint16)(cur_sprite_x - x + 12) < 24 && (uint16)(cur_sprite_y - y + 12) < 36) { sprite_F[j] = 4; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 32); sprite_y_recoil[j] = pt.y; sprite_x_recoil[j] = pt.x; } } } void Sprite_1D_FluteQuest(int k) { // 86c2e5 PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; if (BYTE(overworld_screen_index) == 0x18) { if (link_item_flute == 3) sprite_state[k] = 0; } else { if (link_item_flute & 2) sprite_state[k] = 0; } } void Sprite_72_FairyPond(int k) { // 86c319 if (sprite_A[k]) { if (!--sprite_C[k]) sprite_state[k] = 0; sprite_graphics[k] = sprite_C[k] >> 3; Oam_AllocateFromRegionC(4); SpriteDraw_SingleSmall(k); return; } if (sprite_B[k]) { FaerieQueen_Draw(k); sprite_graphics[k] = frame_counter >> 4 & 1; if (frame_counter & 15) return; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x72, &info); if (j >= 0) { Sprite_SetX(j, info.r0_x + kWishPond_X[GetRandomNumber() & 7]); Sprite_SetY(j, info.r2_y + kWishPond_Y[GetRandomNumber() & 7]); sprite_C[j] = 31; sprite_A[j] = 31; sprite_flags2[j] = 0; sprite_flags3[j] = 0x48; sprite_oam_flags[j] = 0x48 & 0xf; sprite_B[j] = 1; } return; } PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); Sprite_WishPond2(k); } void Sprite_WishPond2(int k) { // 86c41d WishPond2_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (BYTE(dungeon_room_index) != 21) Sprite_WishPond3(k); else Sprite_HappinessPond(k); } void Sprite_HappinessPond(int k) { // 86c44c static const uint8 kHappinessPondCost[4] = {5, 20, 25, 50}; static const uint8 kHappinessPondCostHex[4] = {5, 0x20, 0x25, 0x50}; switch (sprite_ai_state[k]) { case 0: flag_is_link_immobilized = 0; if (sprite_delay_main[k] || Sprite_CheckIfLinkIsBusy()) return; if (Sprite_ShowMessageOnContact(k, 0x89) & 0x100) { sprite_ai_state[k] = 1; Link_ResetProperties_A(); Ancilla_TerminateSparkleObjects(); link_direction_facing = 0; } break; case 1: if (choice_in_multiselect_box == 0) { int i = (link_bomb_upgrades | link_arrow_upgrades) != 0; sprite_graphics[k] = i * 2; WORD(byte_7E1CF2[0]) = WORD(kHappinessPondCostHex[i * 2]); Sprite_ShowMessageUnconditional(0x14e); sprite_ai_state[k] = 2; flag_is_link_immobilized = 1; } else { show_later_msg: Sprite_ShowMessageUnconditional(0x14c); sprite_ai_state[k] = 0; sprite_delay_main[k] = 255; } break; case 2: { int i = sprite_graphics[k] + choice_in_multiselect_box; byte_7E1CF2[1] = kHappinessPondCostHex[i]; if (link_rupees_goal < kHappinessPondCost[i]) { goto show_later_msg; } else { sprite_D[k] = kHappinessPondCost[i]; sprite_head_dir[k] = i; sprite_ai_state[k] = 3; } break; } case 3: { sprite_delay_main[k] = 80; int i = sprite_D[k]; link_rupees_goal -= i; link_rupees_in_pond += i; AddHappinessPondRupees(sprite_head_dir[k]); if (link_rupees_in_pond >= 100) { link_rupees_in_pond -= 100; sprite_ai_state[k] = 5; return; } byte_7E1CF2[0] = (link_rupees_in_pond / 10) * 16 + (link_rupees_in_pond % 10); sprite_ai_state[k] = 4; break; } case 4: if (sprite_delay_main[k] == 0) { Sprite_ShowMessageUnconditional(0x94); sprite_ai_state[k] = 13; } break; case 5: if (sprite_delay_main[k] == 0) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x72, &info); assert(j >= 0); Sprite_SetX(j, info.r0_x); Sprite_SetY(j, info.r2_y - 80); music_control = 0x1b; last_music_control = 0; sprite_B[j] = 1; Palette_AssertTranslucencySwap(); PaletteFilter_WishPonds(); sprite_E[k] = j; sprite_ai_state[k] = 6; sprite_delay_main[k] = 255; } break; case 6: if (!(frame_counter & 7)) { PaletteFilter_SP5F(); if (!BYTE(palette_filter_countdown)) { Sprite_ShowMessageUnconditional(0x95); Palette_RevertTranslucencySwap(); TS_copy = 0; CGADSUB_copy = 0x20; flag_update_cgram_in_nmi++; sprite_ai_state[k] = 7; } } break; case 7: if (!choice_in_multiselect_box) sprite_ai_state[k] = 8; else sprite_ai_state[k] = 12; break; case 8: { static const uint8 kMaxBombsForLevelHex[8] = {0x10, 0x15, 0x20, 0x25, 0x30, 0x35, 0x40, 0x50}; int i = link_bomb_upgrades + 1; if (i != 8) { link_bomb_upgrades = i; byte_7E1CF2[0] = link_bomb_filler = kMaxBombsForLevelHex[i]; Sprite_ShowMessageUnconditional(0x96); } else { link_rupees_goal += 100; Sprite_ShowMessageUnconditional(0x98); } sprite_ai_state[k] = 9; break; } case 9: Palette_AssertTranslucencySwap(); TS_copy = 2; CGADSUB_copy = 0x30; flag_update_cgram_in_nmi++; sprite_ai_state[k] = 10; break; case 10: if (!(frame_counter & 7)) { PaletteFilter_SP5F(); if (BYTE(palette_filter_countdown) == 30) { sprite_state[sprite_E[k]] = 0; } else if (BYTE(palette_filter_countdown) == 0) { sprite_ai_state[k] = 11; } } break; case 11: PaletteFilter_RestoreSP5F(); Palette_RevertTranslucencySwap(); sprite_ai_state[k] = 0; sprite_delay_main[k] = 255; break; case 12: { static const uint8 kMaxArrowsForLevelHex[8] = {0x30, 0x35, 0x40, 0x45, 0x50, 0x55, 0x60, 0x70}; int i = link_arrow_upgrades + 1; if (i != 8) { link_arrow_upgrades = i; byte_7E1CF2[0] = link_arrow_filler = kMaxArrowsForLevelHex[i]; Sprite_ShowMessageUnconditional(0x97); } else { link_rupees_goal += 100; Sprite_ShowMessageUnconditional(0x98); } sprite_ai_state[k] = 9; break; } case 13: Sprite_ShowMessageUnconditional(0x154); sprite_ai_state[k] = 14; break; case 14: { static const uint16 kHappinessPondLuckMsg[4] = {0x150, 0x151, 0x152, 0x153}; static const uint8 kHappinessPondLuck[4] = {1, 0, 0, 2}; int i = GetRandomNumber() & 3; item_drop_luck = kHappinessPondLuck[i]; luck_kill_counter = 0; Sprite_ShowMessageUnconditional(kHappinessPondLuckMsg[i]); sprite_ai_state[k] = 0; sprite_delay_main[k] = 255; break; } } } void WishPond2_Draw(int k) { // 86c4b5 static const DrawMultipleData kWishPond2_Dmd[8] = { {32, -64, 0x0024, 0}, {32, -56, 0x0034, 0}, {32, -64, 0x0024, 0}, {32, -56, 0x0034, 0}, {32, -64, 0x0024, 2}, {32, -64, 0x0024, 2}, {32, -64, 0x0024, 2}, {32, -64, 0x0024, 2}, }; if (BYTE(dungeon_room_index) == 21) return; uint8 t = sprite_ai_state[k]; if (t != 5 && t != 6 && t != 11 && t != 12) return; int g = sprite_graphics[k]; uint8 f = kWishPond2_OamFlags[g]; if (f == 0xff) f = 5; sprite_oam_flags[k] = (f & 7) * 2; Sprite_DrawMultiple(k, &kWishPond2_Dmd[(kReceiveItem_Tab1[g] >> 1) * 4], 4, NULL); } void FaerieQueen_Draw(int k) { // 86cb26 static const uint8 kFaerieQueen_Draw_X[24] = { 0, 16, 0, 8, 16, 24, 0, 8, 16, 24, 0, 16, 0, 16, 0, 8, 16, 24, 0, 8, 16, 24, 0, 16, }; static const uint8 kFaerieQueen_Draw_Y[24] = { 0, 0, 16, 16, 16, 16, 24, 24, 24, 24, 32, 32, 0, 0, 16, 16, 16, 16, 24, 24, 24, 24, 32, 32, }; static const uint8 kFaerieQueen_Draw_Char[24] = { 0xc7, 0xc7, 0xcf, 0xca, 0xca, 0xcf, 0xdf, 0xda, 0xda, 0xdf, 0xcb, 0xcb, 0xcd, 0xcd, 0xc9, 0xca, 0xca, 0xc9, 0xd9, 0xda, 0xda, 0xd9, 0xcb, 0xcb, }; static const uint8 kFaerieQueen_Draw_Flags[24] = { 0, 0x40, 0, 0, 0x40, 0x40, 0, 0, 0x40, 0x40, 0, 0x40, 0, 0x40, 0, 0, 0x40, 0x40, 0, 0, 0x40, 0x40, 0, 0x40, }; static const uint8 kFaerieQueen_Draw_Ext[24] = { 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, }; static const DrawMultipleData kFaerieQueen_Dmd[20] = { { 0, 0, 0x00e9, 2}, {16, 0, 0x40e9, 2}, { 0, 0, 0x00e9, 2}, {16, 0, 0x40e9, 2}, { 0, 0, 0x00e9, 2}, {16, 0, 0x40e9, 2}, { 0, 16, 0x00eb, 2}, {16, 16, 0x40eb, 2}, { 0, 32, 0x00ed, 2}, {16, 32, 0x40ed, 2}, { 0, 0, 0x00ef, 0}, {24, 0, 0x40ef, 0}, { 0, 8, 0x00ff, 0}, {24, 8, 0x40ff, 0}, { 0, 0, 0x00e9, 2}, {16, 0, 0x40e9, 2}, { 0, 16, 0x00eb, 2}, {16, 16, 0x40eb, 2}, { 0, 32, 0x00ed, 2}, {16, 32, 0x40ed, 2}, }; if (!savegame_is_darkworld) { PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; for (int i = 11; i >= 0; i--, oam++) { int j = g * 12 + i; oam->x = kFaerieQueen_Draw_X[j] + info.x; oam->y = kFaerieQueen_Draw_Y[j] + info.y; oam->charnum = kFaerieQueen_Draw_Char[j]; oam->flags = info.flags | kFaerieQueen_Draw_Flags[j]; bytewise_extended_oam[oam - oam_buf] = kFaerieQueen_Draw_Ext[j]; } Sprite_CorrectOamEntries(k, 11, 0xff); } else { Sprite_DrawMultiple(k, &kFaerieQueen_Dmd[sprite_graphics[k] * 10], 10, NULL); } } void Sprite_71_Leever(int k) { // 86cba2 static const uint8 kLeever_EmergeGfx[16] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 1, 2, 1, 0, 0}; static const uint8 kLeever_AttackGfx[4] = {9, 10, 11, 12}; static const uint8 kLeever_AttackSpd[2] = {12, 8}; static const uint8 kLeever_SubmergeGfx[16] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 1, 2, 1, 0, 0}; if (sprite_ai_state[k]) Leever_Draw(k); else { PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); } if (sprite_pause[k]) sprite_state[k] = 8; if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; switch(sprite_ai_state[k]) { case 0: // under sand sprite_ignore_projectile[k] = sprite_delay_main[k]; if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 127; } else { Sprite_ApplySpeedTowardsLink(k, 16); Sprite_MoveXY(k); Sprite_CheckTileCollision2(k); } break; case 1: // emerge sprite_ignore_projectile[k] = sprite_delay_main[k]; if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = (GetRandomNumber() & 63) + 160; Sprite_ZeroVelocity_XY(k); } else { sprite_graphics[k] = kLeever_EmergeGfx[sprite_delay_main[k] >> 3]; } break; case 2: // attack Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) { stop_attack: sprite_ai_state[k]++; sprite_delay_main[k] = 127; } else { if (!(sprite_subtype2[k] & 7)) Sprite_ApplySpeedTowardsLink(k, kLeever_AttackSpd[sprite_A[k]]); Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) goto stop_attack; sprite_graphics[k] = kLeever_AttackGfx[++sprite_subtype2[k] >> 2 & 3]; } break; case 3: // submerge sprite_ignore_projectile[k] = sprite_delay_main[k]; if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = (GetRandomNumber() & 31) + 64; } else { sprite_graphics[k] = kLeever_SubmergeGfx[sprite_delay_main[k] >> 3 ^ 15]; } break; } } void Leever_Draw(int k) { // 86ce45 static const uint8 kLeever_Draw_Num[14] = {1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1}; static const int8 kLeever_Draw_X[56] = { 2, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const int8 kLeever_Draw_Y[56] = { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 5, 5, 8, 8, 5, 5, 8, 8, 2, 2, 8, 8, 1, 1, 8, 8, 0, 0, 8, 8, -1, -1, 8, 8, 8, -2, -2, 0, 8, -2, -2, 0, 8, -2, -2, 0, 8, -2, -2, 0, 8, -2, -2, 0, }; static const uint8 kLeever_Draw_Char[56] = { 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x38, 0x38, 0x38, 0x38, 8, 9, 0x28, 0x28, 8, 9, 0xd9, 0xd9, 8, 8, 0xd8, 0xd8, 8, 8, 0xda, 0xda, 6, 6, 0xd9, 0xd9, 0x26, 0x26, 0xd8, 0xd8, 0x6c, 6, 6, 0, 0x6c, 0x26, 0x26, 0, 0x6c, 6, 6, 0, 0x6c, 0x26, 0x26, 0, 0x6c, 8, 8, 0, }; static const uint8 kLeever_Draw_Flags[56] = { 1, 0x41, 0x41, 0x41, 1, 0x41, 0x41, 0x41, 1, 0x41, 0x41, 0x41, 1, 1, 1, 0x41, 1, 1, 0, 0x40, 1, 1, 0, 0x40, 1, 1, 0, 0x40, 1, 1, 0, 0x40, 0, 1, 0, 0x40, 6, 0x41, 0x41, 0, 6, 0x41, 0x41, 0, 6, 1, 1, 0, 6, 1, 1, 0, 6, 1, 1, 0, }; static const uint8 kLeever_Draw_Ext[56] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, }; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int d = sprite_graphics[k]; for (int i = kLeever_Draw_Num[d]; i >= 0; i--, oam++) { int j = d * 4 + i; uint16 x = info.x + kLeever_Draw_X[j]; uint16 y = info.y + kLeever_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kLeever_Draw_Char[j]; uint8 f = info.flags; if (oam->charnum >= 0x60 || oam->charnum == 0x28 || oam->charnum == 0x38) f &= 0xf0; oam->flags = kLeever_Draw_Flags[j] | f; bytewise_extended_oam[oam - oam_buf] = kLeever_Draw_Ext[j] | (x >> 8 & 1); } } void Sprite_D8_Heart(int k) { // 86cec0 if (SpriteDraw_AbsorbableTransient(k, true)) return; if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckAbsorptionByPlayer(k); if (Sprite_HandleDraggingByAncilla(k)) return; Sprite_MoveXY(k); Sprite_MoveZ(k); if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_ai_state[k]++; sprite_graphics[k] = 0; } sprite_oam_flags[k] &= ~0x40; if (!sign8(sprite_x_vel[k])) sprite_oam_flags[k] |= 0x40; switch (sprite_ai_state[k] >= 3 ? 3 : sprite_ai_state[k]) { case 0: // InitializeAscent sprite_ai_state[k]++; sprite_delay_main[k] = 18; sprite_z_vel[k] = 20; sprite_graphics[k] = 1; sprite_D[k] = 0; break; case 1: // BeginDescending if (sprite_delay_main[k] != 0) { sprite_z_vel[k]--; } else { sprite_ai_state[k]++; sprite_z_vel[k] = 253; sprite_x_vel[k] = 0; } break; case 2: // GlideGroundward if (sprite_delay_main[k] == 0) { int j = sprite_D[k] & 1; sprite_x_vel[k] += kHeartRefill_AccelX[j]; if (sprite_x_vel[k] == (uint8)kHeartRefill_VelTarget[j]) { sprite_D[k]++; sprite_delay_main[k] = 8; } } break; case 3: // Grounded sprite_z_vel[k] = sprite_x_vel[k] = sprite_y_vel[k] = 0; break; } } void Sprite_E3_Fairy(int k) { // 86cf94 sprite_ignore_projectile[k] = 1; if (!sprite_ai_state[k]) { if (!player_is_indoors) sprite_obj_prio[k] = 48; if (SpriteDraw_AbsorbableTransient(k, true)) return; } Fairy_CheckIfTouchable(k); if (Sprite_ReturnIfInactive(k)) return; switch (sprite_ai_state[k]) { case 0: // normal if (!sprite_delay_aux4[k]) { if (Sprite_CheckDamageToLink(k)) { Sprite_HandleAbsorptionByPlayer(k); } else if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Ne) { sprite_ai_state[k]++; Sprite_ShowMessageUnconditional(0xc9); return; } } if (Sprite_HandleDraggingByAncilla(k)) return; Faerie_HandleMovement(k); break; case 1: // capture if (choice_in_multiselect_box == 0) { int j = Sprite_Find_EmptyBottle(); if (j >= 0) { link_bottle_info[j] = 6; Hud_RefreshIcon(); sprite_state[k] = 0; return; } Sprite_ShowMessageUnconditional(0xca); } sprite_delay_aux4[k] = 48; sprite_ai_state[k] = 0; break; } } void Fairy_CheckIfTouchable(int k) { // 86d011 if (submodule_index == 2 && (dialogue_message_index == 0xc9 || dialogue_message_index == 0xca)) sprite_delay_aux4[k] = 40; } void Sprite_E4_SmallKey(int k) { // 86d032 if (dung_savegame_state_bits & (kAbsorbBigKey[sprite_die_action[k]] << 8)) { sprite_state[k] = 0; return; } Sprite_DrawRippleIfInWater(k); if (SpriteDraw_AbsorbableTransient(k, false)) return; Sprite_Absorbable_Main(k); } void Sprite_D9_GreenRupee(int k) { // 86d04a Sprite_DrawRippleIfInWater(k); if (SpriteDraw_AbsorbableTransient(k, true)) return; Sprite_Absorbable_Main(k); } void Sprite_Absorbable_Main(int k) { // 86d051 if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveZ(k); Sprite_MoveXY(k); if (sprite_delay_aux3[k] == 0) { Sprite_CheckTileCollision2(k); Sprite_BounceOffWall(k); } sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1; sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1; uint8 t = -sprite_z_vel[k]; t >>= 1; if (t < 9) { sprite_z_vel[k] = sprite_x_vel[k] = sprite_y_vel[k] = 0; } else { sprite_z_vel[k] = t; if (sprite_I[k] == 8 || sprite_I[k] == 9) { sprite_z_vel[k] = 0; int j = Sprite_SpawnSmallSplash(k); if (j >= 0 && sprite_flags3[k] & 0x20) { // wtf carry propagation Sprite_SetX(j, Sprite_GetX(j) - 4); Sprite_SetY(j, Sprite_GetY(j) - 4); } } else { if (sprite_type[k] >= 0xe4 && player_is_indoors) SpriteSfx_QueueSfx2WithPan(k, 5); } } } if (Sprite_HandleDraggingByAncilla(k)) return; Sprite_CheckAbsorptionByPlayer(k); } void Sprite_08_Octorok(int k) { // 86d377 static const uint8 kOctorock_Tab0[20] = { 0, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 0, }; static const uint8 kOctorock_Tab1[10] = {2, 2, 2, 2, 2, 2, 2, 2, 1, 0}; static const uint8 kOctorock_NextDir[4] = {2, 3, 1, 0}; static const uint8 kOctorock_Dir[4] = {3, 2, 0, 1}; static const int8 kOctorock_Xvel[4] = {24, -24, 0, 0}; static const int8 kOctorock_Yvel[4] = {0, 0, 24, -24}; static const uint8 kOctorock_OamFlags[4] = {0x40, 0, 0, 0}; int j = sprite_D[k]; if (sprite_delay_aux1[k]) sprite_D[k] = kOctorock_Dir[j]; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kOctorock_OamFlags[j] | (sprite_graphics[k] == 7 ? 0x40 : 0); Octorock_Draw(k); sprite_D[k] = j; if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_MoveXY(k); Sprite_CheckDamageToAndFromLink(k); if (!(sprite_ai_state[k] & 1)) { sprite_graphics[k] = ++sprite_subtype2[k] >> 3 & 3 | (sprite_D[k] & 2) << 1; if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = sprite_type[k] == 8 ? 60 : 160; } else { j = sprite_D[k]; sprite_x_vel[k] = kOctorock_Xvel[j]; sprite_y_vel[k] = kOctorock_Yvel[j]; if (Sprite_CheckTileCollision(k)) sprite_D[k] ^= 1; } return; } else { Sprite_ZeroVelocity_XY(k); if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = (GetRandomNumber() & 0x3f) + 48; sprite_D[k] = sprite_delay_main[k] & 3; } else { switch (sprite_type[k]) { case 8: // normal j = sprite_delay_main[k]; if (j == 28) Octorok_FireLoogie(k); sprite_C[k] = kOctorock_Tab0[j >> 3]; break; case 10: // four shooter j = sprite_delay_main[k]; if (j < 128) { if (!(j & 15)) sprite_D[k] = kOctorock_NextDir[sprite_D[k]]; if ((j & 15) == 8) Octorok_FireLoogie(k); } sprite_C[k] = kOctorock_Tab1[j >> 4]; break; } } } } void Octorok_FireLoogie(int k) { // 86d4cd static const int8 kOctorock_Spit_X[4] = {12, -12, 0, 0}; static const int8 kOctorock_Spit_Y[4] = {4, 4, 12, -12}; static const int8 kOctorock_Spit_Xvel[4] = {44, -44, 0, 0}; static const int8 kOctorock_Spit_Yvel[4] = {0, 0, 44, -44}; SpriteSpawnInfo info; SpriteSfx_QueueSfx2WithPan(k, 0x7); int j = Sprite_SpawnDynamically(k, 0xc, &info); if (j >= 0) { int i = sprite_D[k]; Sprite_SetX(j, info.r0_x + kOctorock_Spit_X[i]); Sprite_SetY(j, info.r2_y + kOctorock_Spit_Y[i]); sprite_x_vel[j] = kOctorock_Spit_Xvel[i]; sprite_y_vel[j] = kOctorock_Spit_Yvel[i]; } } void Octorock_Draw(int k) { // 86d54a static const int8 kOctorock_Draw_X[9] = {8, 0, 4, 8, 0, 4, 9, -1, 4}; static const int8 kOctorock_Draw_Y[9] = {6, 6, 9, 6, 6, 9, 6, 6, 9}; static const uint8 kOctorock_Draw_Char[9] = {0xbb, 0xbb, 0xba, 0xab, 0xab, 0xaa, 0xa9, 0xa9, 0xb9}; static const uint8 kOctorock_Draw_Flags[9] = {0x65, 0x25, 0x25, 0x65, 0x25, 0x25, 0x65, 0x25, 0x25}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; if (sprite_D[k] != 3) { OamEnt *oam = GetOamCurPtr(); int j = sprite_C[k] * 3 + sprite_D[k]; uint16 x = info.x + kOctorock_Draw_X[j]; uint16 y = info.y + kOctorock_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kOctorock_Draw_Char[j]; oam->flags = kOctorock_Draw_Flags[j] | info.flags; bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1); } oam_cur_ptr += 4; oam_ext_cur_ptr++; sprite_flags2[k]--; Sprite_PrepAndDrawSingleLargeNoPrep(k, &info); sprite_flags2[k]++; } void Sprite_0C_OctorokStone(int k) { // 86d5b9 if (sprite_state[k] == 6) { SpriteDraw_OctorokStoneCrumbling(k); if (Sprite_ReturnIfPaused(k)) return; if (sprite_delay_main[k] == 30) SpriteSfx_QueueSfx2WithPan(k, 0x1f); } else { SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToLink(k); Sprite_MoveXY(k); if (!((k ^ frame_counter) & 3) && Sprite_CheckTileCollision(k)) Sprite_Func3(k); } } void SpriteDraw_OctorokStoneCrumbling(int k) { // 86d643 static const int8 kOctostone_Draw_X[16] = {0, 8, 0, 8, -8, 16, -8, 16, -12, 20, -12, 20, -14, 22, -14, 22}; static const int8 kOctostone_Draw_Y[16] = {0, 0, 8, 8, -8, -8, 16, 16, -12, -12, 20, 20, -14, -14, 22, 22}; static const uint8 kOctostone_Draw_Flags[16] = {0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int g = ((sprite_delay_main[k] >> 1 & 0xc) ^ 0xc); for (int i = 3; i >= 0; i--, oam++) { int j = g + i; uint16 x = info.x + kOctostone_Draw_X[j]; uint16 y = info.y + kOctostone_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = 0xbc; oam->flags = kOctostone_Draw_Flags[j] | 0x2d; bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1); } } void Sprite_0F_Octoballoon(int k) { // 86d6aa static const uint8 kSprite_Octoballoon_Z[8] = {16, 17, 18, 19, 20, 19, 18, 17}; sprite_z[k] = kSprite_Octoballoon_Z[sprite_subtype2[k] >> 3 & 7]; Octoballoon_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (!sprite_delay_main[k]) { sprite_delay_main[k] = 3; if (!Octoballoon_Find()) { sprite_state[k] = 6; sprite_hit_timer[k] = 0; sprite_delay_main[k] = 15; return; } } if (Sprite_ReturnIfRecoiling(k)) return; sprite_subtype2[k]++; if (!((k ^ frame_counter) & 15)) { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 4); if (sprite_x_vel[k] - pt.x) sprite_x_vel[k] += sign8(sprite_x_vel[k] - pt.x) ? 1 : -1; if (sprite_y_vel[k] - pt.y) sprite_y_vel[k] += sign8(sprite_y_vel[k] - pt.y) ? 1 : -1; } Sprite_MoveXY(k); if (Sprite_CheckDamageToLink(k)) Octoballoon_RecoilLink(k); Sprite_CheckDamageFromLink(k); Sprite_CheckTileCollision2(k); Sprite_BounceOffWall(k); } void Octoballoon_RecoilLink(int k) { // 86d72b if (!link_incapacitated_timer) { link_incapacitated_timer = 4; Sprite_ApplyRecoilToLink(k, 16); Sprite_InvertSpeed_XY(k); } } void Octoballoon_Draw(int k) { // 86d784 static const int8 kOctoballoon_Draw_X[12] = {-4, 4, -4, 4, -8, 8, -8, 8, -4, 4, -4, 4}; static const int8 kOctoballoon_Draw_Y[12] = {-4, -4, 4, 4, -8, -8, 8, 8, -4, -4, 4, 4}; static const uint8 kOctoballoon_Draw_Char[12] = {0x8c, 0x8c, 0x9c, 0x9c, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86}; static const uint8 kOctoballoon_Draw_Flags[12] = {0, 0x40, 0, 0x40, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0}; int d = 0; if (sprite_state[k] == 6) { if (sprite_delay_main[k] == 6 && !submodule_index) Octoballoon_FormBabby(k); d = (sprite_delay_main[k] >> 1 & 4) + 4; } PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); for (int i = 3; i >= 0; i--, oam++) { int j = d + i; uint16 x = info.x + kOctoballoon_Draw_X[j]; uint16 y = info.y + kOctoballoon_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kOctoballoon_Draw_Char[j]; oam->flags = kOctoballoon_Draw_Flags[j] | info.flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } SpriteDraw_Shadow(k, &info); } void Octoballoon_FormBabby(int k) { // 86d80e static const int8 kOctoballoon_Spawn_Xv[6] = {16, 11, -11, -16, -11, 11}; static const int8 kOctoballoon_Spawn_Yv[6] = {0, 11, 11, 0, -11, -11}; SpriteSfx_QueueSfx2WithPan(k, 0xc); for (int i = 5; i >= 0; i--) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x10, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_x_vel[j] = kOctoballoon_Spawn_Xv[i]; sprite_y_vel[j] = kOctoballoon_Spawn_Yv[i]; sprite_z_vel[j] = 48; sprite_subtype2[j] = 255; } } } void Sprite_10_OctoballoonBaby(int k) { // 86d853 if (!sprite_subtype2[k]) sprite_state[k] = 0; if (sprite_subtype2[k] >= 64 || !(sprite_subtype2[k] & 1)) SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; sprite_subtype2[k]--; if (Sprite_ReturnIfRecoiling(k)) return; sprite_z_vel[k]--; Sprite_MoveZ(k); if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = 16; } Sprite_MoveXY(k); Sprite_CheckTileCollision2(k); Sprite_BounceOffWall(k); Sprite_CheckDamageToAndFromLink(k); } void Sprite_0D_Buzzblob(int k) { // 86d89a static const uint8 kBuzzBlob_Gfx[4] = {0, 1, 0, 2}; static const uint8 kBuzzBlob_ObjPrio[4] = {10, 2, 8, 2}; if (sprite_delay_aux1[k]) sprite_obj_prio[k] = sprite_obj_prio[k] & 0xf1 | kBuzzBlob_ObjPrio[sprite_delay_aux1[k] >> 1 & 3]; Sprite_Cukeman(k); BuzzBlob_Draw(k); sprite_graphics[k] = kBuzzBlob_Gfx[sprite_subtype2[k] >> 3 & 3] + (sprite_delay_aux1[k] ? 3 : 0); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; sprite_subtype2[k]++; if (!sprite_delay_main[k]) Buzzblob_SelectNewDirection(k); if (!sprite_delay_aux1[k]) Sprite_MoveXY(k); Sprite_CheckTileCollision2(k); Sprite_BounceOffWall(k); Sprite_CheckDamageToAndFromLink(k); } void Buzzblob_SelectNewDirection(int k) { // 86d906 static const int8 kBuzzBlob_Xvel[8] = {3, 2, -2, -3, -2, 2, 0, 0}; static const int8 kBuzzBlob_Yvel[8] = {0, 2, 2, 0, -2, -2, 0, 0}; static const uint8 kBuzzBlob_Delay[8] = {48, 48, 48, 48, 48, 48, 64, 64}; int j = GetRandomNumber() & 7; sprite_x_vel[k] = kBuzzBlob_Xvel[j]; sprite_y_vel[k] = kBuzzBlob_Yvel[j]; sprite_delay_main[k] = kBuzzBlob_Delay[j]; } void BuzzBlob_Draw(int k) { // 86d953 static const uint16 kBuzzBlob_DrawX[3] = {0, 8, 0}; static const int16 kBuzzBlob_DrawY[3] = {-8, -8, 0}; static const uint8 kBuzzBlob_DrawChar[18] = { 0xf0, 0xf0, 0xe1, 0, 0, 0xce, 0, 0, 0xce, 0xe3, 0xe3, 0xca, 0xe4, 0xe5, 0xcc, 0xe5, 0xe4, 0xcc }; static const uint8 kBuzzBlob_DrawFlags[18] = { 0, 0x40, 0, 0, 0, 0, 0, 0, 0x40, 0, 0x40, 0, 0, 0, 0, 0x40, 0x40, 0x40 }; static const uint8 kBuzzBlob_DrawExt[3] = {0, 0, 2}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; for (int i = 2; i >= 0; i--, oam++) { uint16 x = info.x + kBuzzBlob_DrawX[i]; uint16 y = info.y + kBuzzBlob_DrawY[i]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kBuzzBlob_DrawChar[g * 3 + i]; if (oam->charnum == 0) oam->y = 240; oam->flags = kBuzzBlob_DrawFlags[g * 3 + i] | info.flags; bytewise_extended_oam[oam - oam_buf] = kBuzzBlob_DrawExt[i] | (x >> 8 & 1); } SpriteDraw_Shadow(k, &info); } void Sprite_02_StalfosHead(int k) { // 86ddb7 static const uint8 kStalfosHead_OamFlags[4] = {0, 0, 0, 0x40}; static const uint8 kStalfosHead_Gfx[4] = {0, 1, 2, 1}; sprite_floor[k] = link_is_on_lower_level; if (sprite_delay_aux1[k]) Oam_AllocateFromRegionC(8); int j = sprite_subtype2[k] >> 3 & 3; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kStalfosHead_OamFlags[j]; sprite_graphics[k] = kStalfosHead_Gfx[j]; sprite_obj_prio[k] = 0x30; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); if (sprite_F[k]) Sprite_ZeroVelocity_XY(k); Sprite_MoveXY(k); sprite_subtype2[k]++; ProjectSpeedRet pt; if (sprite_delay_main[k]) { if (sprite_delay_main[k] & 1) return; pt = Sprite_ProjectSpeedTowardsLink(k, 16); } else { if ((k ^ frame_counter) & 3) return; pt = Sprite_ProjectSpeedTowardsLink(k, 16); pt.x = -pt.x; pt.y = -pt.y; } if (sprite_x_vel[k] - pt.x != 0) sprite_x_vel[k] += sign8(sprite_x_vel[k] - pt.x) ? 1 : -1; if (sprite_y_vel[k] - pt.y != 0) sprite_y_vel[k] += sign8(sprite_y_vel[k] - pt.y) ? 1 : -1; } bool Pipe_ValidateEntry() { // 87f4f1 for (int k = 4; k >= 0; k--) { if (ancilla_type[k] == 0x31) { link_position_mode = 0; link_cant_change_direction = 0; ancilla_type[k] = 0; break; } } return ((link_state_bits & 0x80) | link_auxiliary_state) != 0; } void Ancilla_TerminateSparkleObjects() { // 89adc7 for (int i = 4; i >= 0; i--) { uint8 t = ancilla_type[i]; if (t == 0x2a || t == 0x2b || t == 0x30 || t == 0x31 || t == 0x18 || t == 0x19 || t == 0xc) ancilla_type[i] = 0; } } int Sprite_SpawnSuperficialBombBlast(int k) { // 89ae40 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x4a, &info); if (j >= 0) { sprite_state[j] = 6; sprite_delay_aux1[j] = 31; sprite_C[j] = 3; sprite_flags2[j] = 3; sprite_oam_flags[j] = 4; SpriteSfx_QueueSfx2WithPan(k, 0x15); Sprite_SetSpawnedCoordinates(j, &info); } return j; } void Sprite_SpawnDummyDeathAnimation(int k) { // 89ae7e SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xb, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_state[j] = 6; sprite_delay_main[j] = 15; SpriteSfx_QueueSfx2WithPan(k, 0x14); sprite_floor[j] = 2; } } void Sprite_MagicBat_SpawnLightning(int k) { // 89aea8 static const int8 kSpawnMadderBolts_Xvel[4] = {-8, -4, 4, 8}; static const int8 kSpawnMadderBolts_St2[4] = {0, 0x11, 0x22, 0x33}; for (int i = 0; i < 4; i++) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x3a, &info); if (j >= 0) { SpriteSfx_QueueSfx3WithPan(k, 0x1); Sprite_SetSpawnedCoordinates(j, &info); Sprite_SetX(j, info.r0_x + 4); Sprite_SetY(j, info.r2_y + 12 - sprite_z[k]); sprite_z[j] = 0; sprite_y_vel[j] = 24; sprite_head_dir[j] = 24; sprite_ignore_projectile[j] = 24; sprite_flags2[j] = 0x80; sprite_flags3[j] = 3; sprite_oam_flags[j] = 3; sprite_delay_main[j] = 32; sprite_graphics[j] = 2; int i = sprite_G[k]; sprite_x_vel[j] = kSpawnMadderBolts_Xvel[i]; sprite_subtype2[j] = kSpawnMadderBolts_St2[i]; sprite_floor[j] = 2; sprite_G[k]++; } } } void Fireball_SpawnTrailGarnish(int k) { // 89b020 if ((k ^ frame_counter) & 3) return; int j = GarnishAlloc(); garnish_type[j] = 8; garnish_active = 8; garnish_countdown[j] = 11; garnish_x_lo[j] = cur_sprite_x; garnish_x_hi[j] = cur_sprite_x >> 8; garnish_y_lo[j] = cur_sprite_y + 16; garnish_y_hi[j] = (cur_sprite_y + 16) >> 8; garnish_sprite[j] = k; } void GarnishSpawn_PyramidDebris(int8 x, int8 y, int8 xvel, int8 yvel) { // 89b1bd int k = GarnishAllocForce(); sound_effect_2 = 3; sound_effect_1 = 31; sound_effect_ambient = 5; garnish_type[k] = 19; garnish_active = 19; garnish_x_lo[k] = 232 + x; garnish_y_lo[k] = 96 + y; garnish_x_vel[k] = xvel; garnish_y_vel[k] = yvel; garnish_countdown[k] = (GetRandomNumber() & 31) + 48; } void Snitch_SpawnGuard(int k) { // 89c02f static const uint16 kCrazyVillageSoldier_X[3] = {0x120, 0x340, 0x2e0}; static const uint16 kCrazyVillageSoldier_Y[3] = {0x100, 0x3b0, 0x160}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamicallyEx(k, 0x45, &info, 0); if (j < 0) return; int i = sprite_type[k] == 0x3d ? 0 : sprite_type[k] == 0x35 ? 1 : 2; Sprite_SetX(j, kCrazyVillageSoldier_X[i] + (sprcoll_x_base & 0xff00)); Sprite_SetY(j, kCrazyVillageSoldier_Y[i] + (sprcoll_y_base & 0xff00)); sprite_floor[j] = 0; sprite_health[j] = 4; sprite_defl_bits[j] = 0x80; sprite_flags5[j] = 0x90; sprite_oam_flags[j] = 0xb; } void Babusu_Draw(int k) { // 8dbd20 static const DrawMultipleData kBabusu_Dmd[40] = { { 0, 4, 0x4380, 0}, { 0, 4, 0x4380, 0}, { 0, 4, 0x43b6, 0}, { 0, 4, 0x43b6, 0}, { 0, 4, 0x43b7, 0}, { 8, 4, 0x0380, 0}, { 0, 4, 0x4380, 0}, { 8, 4, 0x03b6, 0}, { 8, 4, 0x03b7, 0}, { 8, 4, 0x03b7, 0}, { 8, 4, 0x0380, 0}, { 8, 4, 0x0380, 0}, { 4, 0, 0x8380, 0}, { 4, 0, 0x8380, 0}, { 4, 0, 0x83b6, 0}, { 4, 0, 0x83b6, 0}, { 4, 0, 0x83b7, 0}, { 4, 8, 0x0380, 0}, { 4, 0, 0x8380, 0}, { 4, 8, 0x03b6, 0}, { 4, 8, 0x03b7, 0}, { 4, 8, 0x03b7, 0}, { 4, 8, 0x0380, 0}, { 4, 8, 0x0380, 0}, { 0, -8, 0x0a4e, 2}, { 0, 0, 0x0a5e, 2}, { 0, -8, 0x4a4e, 2}, { 0, 0, 0x4a5e, 2}, { 8, 0, 0x0a6c, 2}, { 0, 0, 0x0a6b, 2}, { 8, 0, 0x8a6c, 2}, { 0, 0, 0x8a6b, 2}, { 0, 8, 0x8a4e, 2}, { 0, 0, 0x8a5e, 2}, { 0, 8, 0xca4e, 2}, { 0, 0, 0xca5e, 2}, {-8, 0, 0x4a6c, 2}, { 0, 0, 0x4a6b, 2}, {-8, 0, 0xca6c, 2}, { 0, 0, 0xca6b, 2}, }; if (sprite_graphics[k] != 0xff) { Sprite_DrawMultiple(k, &kBabusu_Dmd[sprite_graphics[k] * 2], 2, NULL); } else { PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); } } void Wizzrobe_Draw(int k) { // 8dbe06 static const DrawMultipleData kWizzrobe_Dmd[24] = { {0, -8, 0x00b2, 0}, {8, -8, 0x00b3, 0}, {0, 0, 0x0088, 2}, {0, -8, 0x00b2, 0}, {8, -8, 0x00b3, 0}, {0, 0, 0x0086, 2}, {0, -8, 0x00b2, 0}, {8, -8, 0x00b3, 0}, {0, 0, 0x008c, 2}, {0, -8, 0x00b2, 0}, {8, -8, 0x00b3, 0}, {0, 0, 0x008a, 2}, {0, -8, 0x00b2, 0}, {8, -8, 0x00b3, 0}, {0, 0, 0x408c, 2}, {0, -8, 0x00b2, 0}, {8, -8, 0x00b3, 0}, {0, 0, 0x408a, 2}, {0, -8, 0x00b2, 0}, {8, -8, 0x00b3, 0}, {0, 0, 0x00a4, 2}, {0, -8, 0x00b2, 0}, {8, -8, 0x00b3, 0}, {0, 0, 0x008e, 2}, }; Sprite_DrawMultiple(k, &kWizzrobe_Dmd[sprite_graphics[k] * 3], 3, NULL); } void Wizzbeam_Draw(int k) { // 8dbe68 static const DrawMultipleData kWizzbeam_Dmd[8] = { { 0, -4, 0x00c5, 0}, { 0, 4, 0x80c5, 0}, { 0, -4, 0x40c5, 0}, { 0, 4, 0xc0c5, 0}, {-4, 0, 0x40d2, 0}, { 4, 0, 0x00d2, 0}, {-4, 0, 0xc0d2, 0}, { 4, 0, 0x80d2, 0}, }; Sprite_DrawMultiple(k, &kWizzbeam_Dmd[sprite_D[k] * 2], 2, NULL); } void Freezor_Draw(int k) { // 8dbfa6 static const DrawMultipleData kFreezor_Dmd0[28] = { {-8, 0, 0x00a6, 2}, { 8, 0, 0x40a6, 2}, {-8, 0, 0x00a6, 2}, { 8, 0, 0x40a6, 2}, {-8, 0, 0x00a6, 2}, { 8, 0, 0x40a6, 2}, { 0, 11, 0x00ab, 0}, { 8, 11, 0x40ab, 0}, {-8, 0, 0x00ac, 2}, { 8, 0, 0x40a8, 2}, { 0, 11, 0x00ba, 0}, { 8, 11, 0x00bb, 0}, {-8, 0, 0x00a8, 2}, { 8, 0, 0x40ac, 2}, { 0, 11, 0x40bb, 0}, { 8, 11, 0x40ba, 0}, { 0, 2, 0x00ae, 0}, { 8, 2, 0x40ae, 0}, { 0, 10, 0x00be, 0}, { 8, 10, 0x40be, 0}, { 0, 4, 0x00af, 0}, { 8, 4, 0x40af, 0}, { 0, 12, 0x00bf, 0}, { 8, 12, 0x40bf, 0}, { 0, 8, 0x00aa, 0}, { 8, 8, 0x40aa, 0}, { 0, 8, 0x00aa, 0}, { 8, 8, 0x40aa, 0}, }; static const DrawMultipleData kFreezor_Dmd1[8] = { { 0, 0, 0x00ae, 0}, { 8, 0, 0x40ae, 0}, { 0, 8, 0x00be, 0}, { 8, 8, 0x40be, 0}, {-2, 0, 0x00ae, 0}, {10, 0, 0x40ae, 0}, {-2, 8, 0x00be, 0}, {10, 8, 0x40be, 0}, }; if (sprite_graphics[k] != 7) { Sprite_DrawMultiple(k, &kFreezor_Dmd0[sprite_graphics[k] * 4], 4, NULL); } else { Sprite_DrawMultiple(k, kFreezor_Dmd1, 8, NULL); } } void Zazak_Draw(int k) { // 8dc0a6 static const uint8 kZazak_Char[8] = {0x82, 0x82, 0x80, 0x84, 0x88, 0x88, 0x86, 0x84}; static const uint8 kZazak_Flags[8] = {0x40, 0, 0, 0, 0x40, 0, 0, 0}; static const DrawMultipleData kZazak_Dmd[24] = { { 0, -8, 0x0008, 2}, {-4, 0, 0x00a0, 2}, { 4, 0, 0x00a1, 2}, { 0, -7, 0x0008, 2}, {-4, 1, 0x40a1, 2}, { 4, 1, 0x40a0, 2}, { 0, -8, 0x000e, 2}, {-4, 0, 0x00a3, 2}, { 4, 0, 0x00a4, 2}, { 0, -7, 0x000e, 2}, {-4, 1, 0x40a4, 2}, { 4, 1, 0x40a3, 2}, { 0, -9, 0x000c, 2}, { 0, 0, 0x00a6, 2}, { 0, 0, 0x00a6, 2}, { 0, -8, 0x000c, 2}, { 0, 0, 0x00a8, 2}, { 0, 0, 0x00a8, 2}, { 0, -9, 0x400c, 2}, { 0, 0, 0x40a6, 2}, { 0, 0, 0x40a6, 2}, { 0, -8, 0x400c, 2}, { 0, 0, 0x40a8, 2}, { 0, 0, 0x40a8, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kZazak_Dmd[sprite_graphics[k] * 3], 3, &info); if (sprite_pause[k]) return; int i = sprite_head_dir[k] + (sprite_delay_aux1[k] == 0 ? 0 : 4); OamEnt *oam = GetOamCurPtr(); oam->charnum = kZazak_Char[i]; oam->flags = (oam->flags & ~0x40) | kZazak_Flags[i]; SpriteDraw_Shadow(k, &info); } void Stalfos_Draw(int k) { // 8dc21c static const uint8 kStalfos_Char[4] = {2, 2, 0, 4}; static const uint8 kStalfos_Flags[4] = {0x70, 0x30, 0x30, 0x30}; static const DrawMultipleData kStalfos_Dmd[36] = { { 0, -10, 0x0000, 2}, { 0, 0, 0x0006, 2}, { 0, 0, 0x0006, 2}, { 0, -9, 0x0000, 2}, { 0, 1, 0x4006, 2}, { 0, 1, 0x4006, 2}, { 0, -10, 0x0004, 2}, { 0, 0, 0x0006, 2}, { 0, 0, 0x0006, 2}, { 0, -9, 0x0004, 2}, { 0, 1, 0x4006, 2}, { 0, 1, 0x4006, 2}, { 0, -10, 0x0002, 2}, { 5, 5, 0x002e, 0}, { 0, 0, 0x0024, 2}, { 0, -10, 0x0002, 2}, { 0, 0, 0x000e, 2}, { 0, 0, 0x000e, 2}, { 0, -10, 0x4002, 2}, { 3, 5, 0x402e, 0}, { 0, 0, 0x4024, 2}, { 0, -10, 0x4002, 2}, { 0, 0, 0x400e, 2}, { 0, 0, 0x000e, 2}, { 2, -8, 0x4002, 2}, { 0, 0, 0x4008, 2}, { 0, 0, 0x4008, 2}, {-2, -8, 0x0002, 2}, { 0, 0, 0x0008, 2}, { 0, 0, 0x0008, 2}, { 0, -6, 0x0000, 2}, { 0, 0, 0x000a, 2}, { 0, 0, 0x000a, 2}, { 0, 0, 0x000a, 2}, { 0, -6, 0x0004, 2}, { 0, -6, 0x0004, 2}, }; PrepOamCoordsRet info; if (sprite_delay_aux2[k]) { Sprite_PrepOamCoord(k, &info); return; } Sprite_DrawMultiple(k, &kStalfos_Dmd[sprite_graphics[k] * 3], 3, &info); if (sprite_graphics[k] < 8 && !sprite_pause[k]) { OamEnt *oam = GetOamCurPtr(); int i = sprite_head_dir[k]; oam->charnum = kStalfos_Char[i]; oam->flags = (oam->flags & ~0x70) | kStalfos_Flags[i]; } SpriteDraw_Shadow(k, &info); } bool Probe_CheckTileSolidity(int k) { // 8dc26e uint8 tiletype; if (player_is_indoors) { int t = (sprite_floor[k] >= 1) ? 0x1000 : 0; t += (cur_sprite_x & 0x1f8) >> 3; t += (cur_sprite_y & 0x1f8) << 3; tiletype = dung_bg2_attr_table[t]; } else { tiletype = Overworld_ReadTileAttribute(cur_sprite_x >> 3, cur_sprite_y); } sprite_tiletype = tiletype; return kSprite_SimplifiedTileAttr[tiletype] >= 1; } void Sprite_HumanMulti_1(int k) { // 8dc2d9 switch (sprite_subtype2[k]) { case 0: Sprite_FluteDad(k); break; case 1: Sprite_ThiefHideoutGuy(k); break; case 2: Sprite_BlindsHutGuy(k); break; } } void Sprite_BlindsHutGuy(int k) { // 8dc2e6 BlindHideoutGuy_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); Sprite_TrackBodyToHead(k); sprite_head_dir[k] = 0; int j = Sprite_ShowSolicitedMessage(k, 0x172); if (j & 0x100) sprite_D[k] = sprite_head_dir[k] = j; } void Sprite_ThiefHideoutGuy(int k) { // 8dc308 if (!(frame_counter & 3)) { sprite_graphics[k] = 2; uint8 dir = Sprite_DirectionToFaceLink(k, NULL); sprite_head_dir[k] = dir == 3 ? 2 : dir; } sprite_oam_flags[k] = 15; Oam_AllocateDeferToPlayer(k); Thief_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); Sprite_ShowSolicitedMessage(k, 0x171); sprite_graphics[k] = 2; } void Sprite_FluteDad(int k) { // 8dc343 FluteBoyFather_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); sprite_graphics[k] = (frame_counter < 48) ? 2 : (frame_counter >> 7) & 1; if (sprite_ai_state[k]) { Sprite_ShowSolicitedMessage(k, 0xa3); sprite_graphics[k] = 2; } else if (link_item_flute < 2) { Sprite_ShowSolicitedMessage(k, 0xa1); } else if (!(Sprite_ShowSolicitedMessage(k, 0xa4) & 0x100) && hud_cur_item == 13 && (joypad1H_last&0x40) && Sprite_CheckDamageToLink_same_layer(k)) { Sprite_ShowMessageUnconditional(0xa2); sprite_ai_state[k]++; sprite_graphics[k] = 2; } } void FluteBoyFather_Draw(int k) { // 8dc3e1 static const DrawMultipleData kFluteBoyFather_Dmd[6] = { {0, -7, 0x0086, 2}, {0, 0, 0x0088, 2}, {0, -6, 0x0086, 2}, {0, 0, 0x0088, 2}, {0, -8, 0x0084, 2}, {0, 0, 0x0088, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kFluteBoyFather_Dmd[sprite_graphics[k] * 2], 2, &info); SpriteDraw_Shadow(k, &info); } void BlindHideoutGuy_Draw(int k) { // 8dc481 static const DrawMultipleData kBlindHideoutGuy_Dmd[16] = { {0, -8, 0x000c, 2}, {0, 0, 0x00ca, 2}, {0, -8, 0x000c, 2}, {0, 0, 0x40ca, 2}, {0, -8, 0x000c, 2}, {0, 0, 0x00ca, 2}, {0, -8, 0x000c, 2}, {0, 0, 0x40ca, 2}, {0, -8, 0x000e, 2}, {0, 0, 0x00ca, 2}, {0, -8, 0x000e, 2}, {0, 0, 0x40ca, 2}, {0, -8, 0x400e, 2}, {0, 0, 0x00ca, 2}, {0, -8, 0x400e, 2}, {0, 0, 0x40ca, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kBlindHideoutGuy_Dmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info); SpriteDraw_Shadow(k, &info); } void Sprite_SweepingLady(int k) { // 8dc4ad SweepingLady_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_ShowSolicitedMessage(k, 0xa5); Sprite_BehaveAsBarrier(k); sprite_graphics[k] = frame_counter >> 4 & 1; } void SweepingLady_Draw(int k) { // 8dc4eb static const DrawMultipleData kSweepingLadyDmd[4] = { {0, -7, 0x008e, 2}, {0, 5, 0x008a, 2}, {0, -8, 0x008e, 2}, {0, 4, 0x008c, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kSweepingLadyDmd[sprite_graphics[k] * 2], 2, &info); SpriteDraw_Shadow(k, &info); } void Sprite_Lumberjacks(int k) { // 8dc51b static const uint16 kLumberJackMsg[4] = {0x12c, 0x12d, 0x12e, 0x12d}; Lumberjacks_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Lumberjack_CheckProximity(k, 0)) { Sprite_NullifyHookshotDrag(); link_speed_setting = 0; Link_CancelDash(); } if (!Sprite_CheckIfLinkIsBusy() && Lumberjack_CheckProximity(k, 1) && (filtered_joypad_L & 0x80)) { int msg = (BYTE(link_x_coord) >= sprite_x_lo[k]) + (link_sword_type >= 2) * 2; Sprite_ShowMessageUnconditional(kLumberJackMsg[msg]); } sprite_graphics[k] = frame_counter >> 5 & 1; } bool Lumberjack_CheckProximity(int k, int j) { // 8dc58f static const uint8 kLumberJacks_X[2] = {48, 52}; static const uint8 kLumberJacks_Y[2] = {19, 20}; static const uint8 kLumberJacks_W[2] = {98, 106}; static const uint8 kLumberJacks_H[2] = {37, 40}; return (uint16)(cur_sprite_x - link_x_coord + kLumberJacks_X[j]) < kLumberJacks_W[j] && (uint16)(cur_sprite_y - link_y_coord + kLumberJacks_Y[j]) < kLumberJacks_H[j]; } void Lumberjacks_Draw(int k) { // 8dc6ba static const DrawMultipleData kLumberJacks_Dmd[33] = { {-23, 5, 0x02be, 0}, {-15, 5, 0x02bf, 0}, { -7, 5, 0x02bf, 0}, { 1, 5, 0x02bf, 0}, { 9, 5, 0x02bf, 0}, { 17, 5, 0x02bf, 0}, { 25, 5, 0x42be, 0}, {-32, -8, 0x40a8, 2}, {-32, 4, 0x40a6, 2}, { 30, -8, 0x00a8, 2}, { 31, 4, 0x00a4, 2}, {-19, 5, 0x02be, 0}, {-11, 5, 0x02bf, 0}, { -3, 5, 0x02bf, 0}, { 5, 5, 0x02bf, 0}, { 13, 5, 0x02bf, 0}, { 21, 5, 0x02bf, 0}, { 29, 5, 0x42be, 0}, {-31, -8, 0x40a8, 2}, {-32, 4, 0x40a4, 2}, { 31, -8, 0x00a8, 2}, { 31, 4, 0x00a6, 2}, {-19, 5, 0x02be, 0}, {-11, 5, 0x02bf, 0}, { -3, 5, 0x02bf, 0}, { 5, 5, 0x02bf, 0}, { 13, 5, 0x02bf, 0}, { 21, 5, 0x02bf, 0}, { 29, 5, 0x42be, 0}, {-32, -8, 0x400e, 2}, {-32, 4, 0x40a4, 2}, { 32, -8, 0x000e, 2}, { 31, 4, 0x00a6, 2}, }; Sprite_DrawMultiple(k, &kLumberJacks_Dmd[sprite_graphics[k] * 11], 11, NULL); } void Sprite_FortuneTeller(int k) { // 8dc762 switch (sprite_subtype2[k]) { case 0: // fortuneteller main FortuneTeller_Draw(k); if (Sprite_ReturnIfInactive(k)) return; FortuneTeller_LightOrDarkWorld(k, savegame_is_darkworld >> 6 & 1); break; case 1: // dwarf solidity if (Sprite_ReturnIfInactive(k)) return; if (Sprite_CheckDamageToLink_same_layer(k)) { Sprite_NullifyHookshotDrag(); link_speed_setting = 0; Link_CancelDash(); } break; } } void FortuneTeller_PerformPseudoScience(int k) { // 8dc849 sprite_graphics[k] = 0; sprite_ai_state[k]++; static const uint8 kFortuneTeller_Readings[16] = {0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd}; uint8 slots[2] = { 0, 0 }; int n = 0; #define ADD_MSG(q) { slots[n++]=(q); if (n==2) goto done; } if (savegame_map_icons_indicator < 3) goto done; if (!link_item_book_of_mudora) ADD_MSG(2); if (!(link_which_pendants & 2)) ADD_MSG(1); if (link_item_mushroom < 2) ADD_MSG(3); if (!link_item_flippers) ADD_MSG(4); if (!link_item_moon_pearl) ADD_MSG(5); if (sram_progress_indicator < 3) ADD_MSG(6); if (!link_magic_consumption) ADD_MSG(7); if (!link_item_bombos_medallion) ADD_MSG(8); if (!(sram_progress_indicator_3 & 0x10)) ADD_MSG(9); if (!(sram_progress_indicator_3 & 0x20)) ADD_MSG(10); if (!link_item_cape) ADD_MSG(11); if (!(save_ow_event_info[0x5b] & 2)) ADD_MSG(12); if (link_sword_type < 4) ADD_MSG(13); ADD_MSG(14); ADD_MSG(15); int j; done: j = ((sram_progress_flags ^= 0x40) & 0x40) != 0; Sprite_ShowMessageUnconditional(kFortuneTeller_Readings[slots[j]]); } void FortuneTeller_Draw(int k) { // 8dcb01 static const DrawMultipleData kFortuneTeller_Dmd[12] = { { 0, -48, 0x000c, 2}, { 0, -32, 0x002c, 0}, { 8, -32, 0x402c, 0}, { 0, -48, 0x000a, 2}, { 0, -32, 0x002a, 0}, { 8, -32, 0x402a, 0}, {-4, -40, 0x0066, 2}, { 4, -40, 0x4066, 2}, {-4, -40, 0x0066, 2}, {-4, -40, 0x0068, 2}, { 4, -40, 0x4068, 2}, {-4, -40, 0x0068, 2}, }; int j = (savegame_is_darkworld >> 6 & 1) * 2 + sprite_graphics[k]; Sprite_DrawMultiple(k, &kFortuneTeller_Dmd[j * 3], 3, NULL); } void Smithy_SpawnDumbBarrierSprite(int k) { // 8dcb2a SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x31, &info); if (j < 0) return; Sprite_SetX(j, info.r0_x); Sprite_SetY(j, info.r2_y); sprite_subtype2[j] = 1; sprite_flags4[j] = 0; sprite_ignore_projectile[j] = 1; } void Sprite_MazeGameLady(int k) { // 8dcb5c Lady_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_TrackBodyToHead(k); sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; switch (sprite_ai_state[k]) { case 0: // startup if (sprite_x_lo[k] < BYTE(link_x_coord)) { int j = Sprite_ShowMessageOnContact(k, 0xcc); if (j & 0x100) { sprite_D[k] = sprite_head_dir[k] = (uint8)j; sprite_ai_state[k] = 1; word_7FFE00 = 0; word_7FFE02 = 0; sprite_A[k] = 0; flag_overworld_area_did_change = 0; } } else { Sprite_ShowMessageOnContact(k, 0xd0); } break; case 1: // sound SpriteSfx_QueueSfx3WithPan(k, 0x7); sprite_ai_state[k] = 2; break; case 2: // accumulate time if (++sprite_A[k] == 63) { sprite_A[k] = 0; word_7FFE00 += 1; if (word_7FFE00 == 0) word_7FFE02++; } break; } } void Sprite_MazeGameGuy(int k) { // 8dcbf2 int j; MazeGameGuy_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_TrackBodyToHead(k); sprite_head_dir[k] = 0; Sprite_BehaveAsBarrier(k); sprite_graphics[k] = frame_counter >> 3 & 1; if (flag_overworld_area_did_change) { Sprite_ShowMessageOnContact(k, 0xd0); return; } switch (sprite_ai_state[k]) { case 0: { // parse time word_7FFE04 = word_7FFE00; word_7FFE06 = word_7FFE02; int t = word_7FFE04 % 6000; int a = t / 600; t %= 600; int b = t / 60; t %= 60; int c = t / 10; t %= 10; byte_7E1CF2[0] = t | c << 4; byte_7E1CF2[1] = b | a << 4; t = Sprite_ShowMessageOnContact(k, 0xcb); if (t & 0x100) { sprite_D[k] = sprite_head_dir[k] = (uint8)t; sprite_ai_state[k] = 1; } break; } case 1: // check qualify if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x40) { Sprite_ShowMessageUnconditional(0xcf); sprite_ai_state[k] = 4; } else if (word_7FFE04 < 16) { Sprite_ShowMessageUnconditional(0xcd); sprite_D[k] = sprite_head_dir[k] = (uint8)link_player_handler_state; // wtf sprite_ai_state[k] = 3; } else { Sprite_ShowMessageUnconditional(0xce); sprite_D[k] = sprite_head_dir[k] = (uint8)link_player_handler_state; // wtf sprite_ai_state[k] = 2; } break; case 2: // sorry j = Sprite_ShowMessageOnContact(k, 0xce); if (j & 0x100) sprite_D[k] = sprite_head_dir[k] = (uint8)j; break; case 3: // can have it j = Sprite_ShowSolicitedMessage(k, 0xcd); if (j & 0x100) sprite_D[k] = sprite_head_dir[k] = (uint8)j; break; case 4: // nothing more j = Sprite_ShowSolicitedMessage(k, 0xcf); if (j & 0x100) sprite_D[k] = sprite_head_dir[k] = (uint8)j; break; } } void MazeGameGuy_Draw(int k) { // 8dcda7 static const DrawMultipleData kMazeGameGuy_Dmd[16] = { {0, -10, 0x0000, 2}, {0, 0, 0x0020, 2}, {0, -10, 0x0000, 2}, {0, 0, 0x0020, 2}, {0, -10, 0x0000, 2}, {0, 0, 0x0020, 2}, {0, -10, 0x0000, 2}, {0, 0, 0x0020, 2}, {0, -10, 0x4002, 2}, {0, 0, 0x0020, 2}, {0, -10, 0x4002, 2}, {0, 0, 0x0020, 2}, {0, -10, 0x0002, 2}, {0, 0, 0x0020, 2}, {0, -10, 0x0002, 2}, {0, 0, 0x0020, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kMazeGameGuy_Dmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info); SpriteDraw_Shadow(k, &info); } void CrystalMaiden_Draw(int k) { // 8dce5f int j = sprite_D[k] * 2 + sprite_graphics[k]; BYTE(dma_var6) = kCrystalMaiden_Dma[j * 2 + 0]; BYTE(dma_var7) = kCrystalMaiden_Dma[j * 2 + 1]; Sprite_DrawMultiplePlayerDeferred(k, kCrystalMaiden_SpriteData + j * 2, 2, NULL); } void Priest_Draw(int k) { // 8dcf31 int j = sprite_D[k] * 2 + sprite_graphics[k]; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, kPriest_Dmd + j * 2, 2, &info); SpriteDraw_Shadow(k, &info); } uint8 FluteBoy_Draw(int k) { // 8dcfd9 static const DrawMultipleData kFluteBoy_Dmd[16] = { {-1, -1, 0x0abe, 0}, { 0, 0, 0x0aaa, 2}, { 0, -10, 0x0aa8, 2}, { 0, 0, 0x0aaa, 2}, {-1, -1, 0x0abe, 0}, { 0, 8, 0x0abf, 0}, { 0, -10, 0x0aa8, 2}, { 0, 0, 0x0aaa, 2}, {-1, -1, 0x0abe, 0}, { 0, 0, 0x0aaa, 2}, { 0, -10, 0x0aa8, 2}, { 0, 0, 0x0aaa, 2}, {-1, -1, 0x0abe, 0}, { 0, 8, 0x0abf, 0}, { 0, -10, 0x0aa8, 2}, { 0, 0, 0x0aaa, 2}, }; Oam_AllocateFromRegionB(0x10); PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kFluteBoy_Dmd[sprite_D[k] * 8 + sprite_graphics[k] * 4], 4, &info); return (info.x | info.y) >> 8; } void FluteAardvark_Draw(int k) { // 8dd040 static const DrawMultipleData kFluteAardvark_Dmd[8] = { {0, -16, 0x06e6, 2}, {0, -8, 0x06c8, 2}, {0, -16, 0x06e6, 2}, {0, -8, 0x06ca, 2}, {0, -16, 0x06e8, 2}, {0, -8, 0x06ca, 2}, {0, -16, 0x00cc, 2}, {0, -8, 0x00dc, 2}, }; Sprite_DrawMultiplePlayerDeferred(k, &kFluteAardvark_Dmd[sprite_graphics[k] * 2], 2, NULL); } void DustCloud_Draw(int k) { // 8dd120 static const DrawMultipleData kDustCloud_Dmd[24] = { { 0, -3, 0x008b, 0}, { 3, 0, 0x009b, 0}, {-3, 0, 0xc08b, 0}, { 0, 3, 0xc09b, 0}, { 0, -5, 0x008a, 2}, { 5, 0, 0x008a, 2}, {-5, 0, 0x008a, 2}, { 0, 5, 0x008a, 2}, { 0, -7, 0x0086, 2}, { 7, 0, 0x0086, 2}, {-7, 0, 0x0086, 2}, { 0, 7, 0x0086, 2}, { 0, -9, 0x8086, 2}, { 9, 0, 0x8086, 2}, {-9, 0, 0x8086, 2}, { 0, 9, 0x8086, 2}, { 0, -9, 0xc086, 2}, { 9, 0, 0xc086, 2}, {-9, 0, 0xc086, 2}, { 0, 9, 0xc086, 2}, { 0, -7, 0x4086, 2}, { 7, 0, 0x4086, 2}, {-7, 0, 0x4086, 2}, { 0, 7, 0x4086, 2}, }; sprite_oam_flags[k] = 0x14; Sprite_DrawMultiple(k, &kDustCloud_Dmd[sprite_graphics[k] * 4], 4, NULL); } void MedallionTablet_Draw(int k) { // 8dd1e2 static const DrawMultipleData kMedallionTablet_Dmd[20] = { {-8, -16, 0x008c, 2}, { 8, -16, 0x408c, 2}, {-8, 0, 0x00ac, 2}, { 8, 0, 0x40ac, 2}, {-8, -13, 0x008a, 2}, { 8, -13, 0x408a, 2}, {-8, 0, 0x00ac, 2}, { 8, 0, 0x40ac, 2}, {-8, -8, 0x008a, 2}, { 8, -8, 0x408a, 2}, {-8, 0, 0x00ac, 2}, { 8, 0, 0x40ac, 2}, {-8, -4, 0x008a, 2}, { 8, -4, 0x408a, 2}, {-8, 0, 0x00aa, 2}, { 8, 0, 0x40aa, 2}, {-8, 0, 0x00aa, 2}, { 8, 0, 0x40aa, 2}, {-8, 0, 0x00aa, 2}, { 8, 0, 0x40aa, 2}, }; Sprite_DrawMultiplePlayerDeferred(k, &kMedallionTablet_Dmd[sprite_graphics[k] * 4], 4, NULL); } void Uncle_Draw(int k) { // 8dd391 Oam_AllocateFromRegionB(0x18); const DrawMultipleData *src = &kUncleDraw_Table[sprite_D[k] * 12 + sprite_graphics[k] * 6]; int j = sprite_D[k] * 2 + sprite_graphics[k]; link_dma_var3 = kUncleDraw_Dma3[j]; link_dma_var4 = kUncleDraw_Dma4[j]; PrepOamCoordsRet info; Sprite_DrawMultiple(k, src, 6, &info); if (sprite_D[k] != 0 && sprite_D[k] != 3) SpriteDraw_Shadow(k, &info); } void BugNetKid_Draw(int k) { // 8dd47b static const DrawMultipleData kBugNetKid_Dmd[18] = { { 4, 0, 0x0027, 0}, { 0, -5, 0x000e, 2}, {-8, 6, 0x040a, 2}, { 8, 6, 0x440a, 2}, {-8, 14, 0x840a, 2}, { 8, 14, 0xc40a, 2}, { 0, -5, 0x000e, 2}, { 0, -5, 0x000e, 2}, {-8, 6, 0x040a, 2}, { 8, 6, 0x440a, 2}, {-8, 14, 0x840a, 2}, { 8, 14, 0xc40a, 2}, { 0, -5, 0x002e, 2}, { 0, -5, 0x002e, 2}, {-8, 7, 0x040a, 2}, { 8, 7, 0x440a, 2}, {-8, 14, 0x840a, 2}, { 8, 14, 0xc40a, 2}, }; Sprite_DrawMultiplePlayerDeferred(k, &kBugNetKid_Dmd[sprite_graphics[k] * 6], 6, NULL); } void Bomber_Draw(int k) { // 8dd56c static const DrawMultipleData kBomber_Dmd[22] = { { 0, 0, 0x40c6, 2}, { 0, 0, 0x40c6, 2}, { 0, 0, 0x40c4, 2}, { 0, 0, 0x40c4, 2}, { 0, 0, 0x00c6, 2}, { 0, 0, 0x00c6, 2}, { 0, 0, 0x00c4, 2}, { 0, 0, 0x00c4, 2}, {-8, 0, 0x00c0, 2}, { 8, 0, 0x40c0, 2}, {-8, 0, 0x00c2, 2}, { 8, 0, 0x40c2, 2}, {-8, 0, 0x00e0, 2}, { 8, 0, 0x40e0, 2}, {-8, 0, 0x00e2, 2}, { 8, 0, 0x40e2, 2}, {-8, 0, 0x00e4, 2}, { 8, 0, 0x40e4, 2}, { 0, 0, 0x40e6, 2}, { 0, 0, 0x40e6, 2}, { 0, 0, 0x00e6, 2}, { 0, 0, 0x00e6, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kBomber_Dmd[sprite_graphics[k] * 2], 2, &info); SpriteDraw_Shadow(k, &info); } void SpriteDraw_ZirroBomb(int k) { // 8dd606 static const DrawMultipleData kBomberPellet_Dmd[15] = { {-11, 0, 0x019b, 0}, { 0, -8, 0xc19b, 0}, { 6, 6, 0x419b, 0}, {-15, -6, 0x018a, 2}, { -4, -14, 0x018a, 2}, { 2, 0, 0x018a, 2}, {-15, -6, 0x0186, 2}, { -4, -14, 0x0186, 2}, { 2, 0, 0x0186, 2}, { -4, -4, 0x0186, 2}, { -4, -4, 0x0186, 2}, { -4, -4, 0x0186, 2}, { -4, -4, 0x01aa, 2}, { -4, -4, 0x01aa, 2}, { -4, -4, 0x01aa, 2}, }; if (!sprite_delay_main[k]) sprite_state[k] = 0; Sprite_DrawMultiple(k, &kBomberPellet_Dmd[(sprite_delay_main[k] >> 2) * 3], 3, NULL); } void PlayerBee_HoneInOnTarget(int j, int k) { // 8dd631 if (sprite_type[j] != 0x88 && (sprite_flags[j] & 2)) return; uint16 x = Sprite_GetX(j); uint16 y = Sprite_GetY(j); if ((uint16)(cur_sprite_x - x + 16) >= 24 || (uint16)(cur_sprite_y - y - 8) >= 24) return; if (sprite_type[j] == 0x75) { sprite_E[j] = k + 1; return; } Ancilla_CheckDamageToSprite_preset(j, 1); sprite_F[j] = 15; sprite_x_recoil[j] = sprite_x_vel[k] << 1; sprite_y_recoil[j] = sprite_y_vel[k] << 1; sprite_B[k]++; } void Pikit_Draw(int k) { // 8dd6e6 static const DrawMultipleData kPikit_Dmd[8] = { { 0, 0, 0x00c8, 2}, { 0, 0, 0x00c8, 2}, { 0, 0, 0x00ca, 2}, { 0, 0, 0x00ca, 2}, {-8, 0, 0x00cc, 2}, { 8, 0, 0x40cc, 2}, {-8, 0, 0x00ce, 2}, { 8, 0, 0x40ce, 2}, }; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; SpriteDraw_Pikit_Tongue(k, &info); OamEnt *oam = GetOamCurPtr(); tmp_counter = oam->x; byte_7E0FB6 = oam->y; oam_cur_ptr += 24; oam_ext_cur_ptr += 6; Sprite_DrawMultiple(k, &kPikit_Dmd[sprite_graphics[k] * 2], 2, &info); uint8 bak = sprite_flags2[k]; sprite_flags2[k] -= 6; SpriteDraw_Shadow(k, &info); sprite_flags2[k] = bak; SpriteDraw_Pikit_Loot(k, &info); } void SpriteDraw_Pikit_Tongue(int k, PrepOamCoordsRet *info) { // 8dd74a static const uint8 kPikit_TongueMult[4] = {0x33, 0x66, 0x99, 0xcc}; static const uint8 kPikit_Draw_Char[8] = {0xee, 0xfd, 0xed, 0xfd, 0xee, 0xfd, 0xed, 0xfd}; static const uint8 kPikit_Draw_Flags[8] = {0, 0, 0, 0x40, 0x40, 0xc0, 0x80, 0x80}; if (sprite_ai_state[k] != 2 || sprite_pause[k]) return; OamEnt *oam = GetOamCurPtr(); int x = info->x + 4, y = info->y + 3; oam[5].x = x; oam[5].y = y; oam[0].x = x + sprite_A[k]; oam[0].y = y + sprite_B[k]; oam[0].charnum = oam[5].charnum = 0xfe; oam[0].flags = oam[5].flags = info->flags; oam++; int g = sprite_D[k]; for (int i = 3; i >= 0; i--, oam++) { oam->x = x + (int8)sprite_A[k] * kPikit_TongueMult[i] / 256; oam->y = y + (int8)sprite_B[k] * kPikit_TongueMult[i] / 256; oam->charnum = kPikit_Draw_Char[g]; oam->flags = kPikit_Draw_Flags[g] | info->flags; } Sprite_CorrectOamEntries(k, 5, 0); } void SpriteDraw_Pikit_Loot(int k, PrepOamCoordsRet *info) { // 8dd858 static const int8 kPikit_DrawGrabbedItem_X[20] = { -4, 4, -4, 4, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, -4, 4, -4, 4, }; static const int8 kPikit_DrawGrabbedItem_Y[20] = { -4, -4, 4, 4, -4, -4, 4, 4, -4, -4, 4, 4, -4, -4, 4, 4, -4, -4, 4, 4, }; static const uint8 kPikit_DrawGrabbedItem_Char[20] = { 0x6e, 0x6f, 0x7e, 0x7f, 0x63, 0x7c, 0x73, 0x7c, 0xb, 0x7c, 0x1b, 0x7c, 0xec, 0xf9, 0xfc, 0xf9, 0xea, 0xeb, 0xfa, 0xfb, }; static const uint8 kPikit_DrawGrabbedItem_Flags[5] = {0x24, 0x24, 0x28, 0x29, 0x2f}; if (!sprite_G[k]) return; int g = sprite_G[k] - 1; if (g == 3) g = sprite_subtype[k] + 2; Oam_AllocateFromRegionC(0x10); OamEnt *oam = GetOamCurPtr(); for (int i = 3; i >= 0; i--, oam++) { int j = g * 4 + i; oam->x = tmp_counter + kPikit_DrawGrabbedItem_X[j]; oam->y = byte_7E0FB6 + kPikit_DrawGrabbedItem_Y[j]; oam->charnum = kPikit_DrawGrabbedItem_Char[j]; oam->flags = kPikit_DrawGrabbedItem_Flags[g]; } Sprite_CorrectOamEntries(k, 3, 0); } void Kholdstare_Draw(int k) { // 8dd98f static const DrawMultipleData kKholdstare_Dmd[16] = { {-8, -8, 0x0080, 2}, { 8, -8, 0x0082, 2}, {-8, 8, 0x00a0, 2}, { 8, 8, 0x00a2, 2}, {-7, -7, 0x0080, 2}, { 7, -7, 0x0082, 2}, {-7, 7, 0x00a0, 2}, { 7, 7, 0x00a2, 2}, {-7, -7, 0x0084, 2}, { 7, -7, 0x0086, 2}, {-7, 7, 0x00a4, 2}, { 7, 7, 0x00a6, 2}, {-8, -8, 0x0084, 2}, { 8, -8, 0x0086, 2}, {-8, 8, 0x00a4, 2}, { 8, 8, 0x00a6, 2}, }; static const int8 kKholdstare_Draw_X[16] = {8, 7, 4, 2, 0, -2, -4, -7, -8, -7, -4, -2, 0, 2, 4, 7}; static const int8 kKholdstare_Draw_Y[16] = {0, 2, 4, 7, 8, 7, 4, 2, 0, -2, -4, -7, -8, -7, -4, -2}; static const uint8 kKholdstare_Draw_Char[16] = {0xac, 0xac, 0xaa, 0x8c, 0x8c, 0x8c, 0xaa, 0xac, 0xac, 0xaa, 0xaa, 0x8c, 0x8c, 0x8c, 0xaa, 0xac}; static const uint8 kKholdstare_Draw_Flags[16] = {0x40, 0x40, 0x40, 0, 0, 0, 0, 0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int j = sprite_A[k]; uint16 x = info.x + kKholdstare_Draw_X[j]; uint16 y = info.y + kKholdstare_Draw_Y[j]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kKholdstare_Draw_Char[j]; oam->flags = kKholdstare_Draw_Flags[j] | info.flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); oam_cur_ptr += 4, oam_ext_cur_ptr += 1; Sprite_DrawMultiple(k, &kKholdstare_Dmd[sprite_graphics[k] * 4], 4, &info); } int Sprite_SpawnFireball(int k) { // 8dda06 SpriteSpawnInfo info; SpriteSfx_QueueSfx3WithPan(k, 0x19); int j = Sprite_SpawnDynamicallyEx(k, 0x55, &info, 13); if (j < 0) return j; Sprite_SetX(j, info.r0_x + 4); Sprite_SetY(j, info.r2_y + 4 - info.r4_z); sprite_flags3[j] = sprite_flags3[j] & 0xfe | 0x40; sprite_oam_flags[j] = 6; sprite_flags4[j] = 0x54; sprite_E[j] = 0x54; sprite_flags2[j] = 0x20; Sprite_ApplySpeedTowardsLink(j, 0x20); sprite_delay_main[j] = 20; sprite_delay_aux1[j] = 16; sprite_flags5[j] = 0; sprite_defl_bits[j] = 0x48; return j; } void ArcheryGameGuy_Draw(int k) { // 8ddac4 static const int8 kArcheryGameGuy_Draw_X[15] = {0, 0, 0, 0, 0, -5, 0, -1, -1, 0, 0, 0, 0, 1, 1}; static const int8 kArcheryGameGuy_Draw_Y[15] = {0, -10, -10, 0, -10, -3, 0, -10, -10, 0, -10, -10, 0, -10, -10}; static const uint8 kArcheryGameGuy_Draw_Char[15] = {0x26, 6, 6, 8, 6, 0x3a, 0x26, 6, 6, 0x26, 6, 6, 0x26, 6, 6}; static const uint8 kArcheryGameGuy_Draw_Flags[15] = {8, 6, 6, 8, 6, 8, 8, 6, 6, 8, 6, 6, 8, 6, 6}; static const uint8 kArcheryGameGuy_Draw_Ext[15] = {2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2}; Oam_AllocateDeferToPlayer(k); PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; for (int i = 2; i >= 0; i--, oam++) { int j = g * 3 + i; oam->x = info.x + kArcheryGameGuy_Draw_X[j]; oam->y = info.y + kArcheryGameGuy_Draw_Y[j]; oam->charnum = kArcheryGameGuy_Draw_Char[j]; oam->flags = kArcheryGameGuy_Draw_Flags[j] | info.flags; bytewise_extended_oam[oam - oam_buf] = kArcheryGameGuy_Draw_Ext[j]; } SpriteDraw_Shadow(k, &info); } void ShopKeeper_RapidTerminateReceiveItem() { // 8ffaea for (int i = 4; i >= 0; i--) { if (ancilla_type[i] == 0x22) ancilla_aux_timer[i] = 1; } } void Sprite_InitializeSecondaryItemMinigame(int what) { // 8ffd86 byte_7E03FC = what; Link_ResetProperties_C(); for (int k = 4; k >= 0; k--) { if (ancilla_type[k] == 0x30 || ancilla_type[k] == 0x31) { ancilla_type[k] = 0; } else if (ancilla_type[k] == 5) { flag_for_boomerang_in_place = 0; ancilla_type[k] = 0; } } } void Waterfall(int k) { // 9af5b8 if (Sprite_ReturnIfInactive(k)) return; if (Sprite_CheckDamageToLink_same_layer(k)) { if (BYTE(overworld_screen_index) == 0x43) AncillaAdd_GTCutscene(); else AncillaAdd_WaterfallSplash(); } } void Sprite_BatCrash(int k) { // 9af5d9 static const uint16 kRetreatBat_Xpos[4] = {0x7dc, 0x7f0, 0x820, 0x818}; static const uint16 kRetreatBat_Ypos[4] = {0x62e, 0x636, 0x630, 0x5e0}; static const uint8 kRetreatBat_Delay[5] = {4, 3, 4, 6, 0}; int j; RetreatBat_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXY(k); BatCrash_DrawHardcodedGarbage(k); bg1_y_offset = 0; if (sprite_delay_aux3[k]) { if (sprite_delay_aux3[k] == 1) sound_effect_ambient = 5; bg1_y_offset = sprite_delay_aux3[k] & 1 ? 1 : -1; } if (!sprite_delay_main[k]) { sprite_graphics[k] = sprite_graphics[k] + 1 & 3; if (sprite_graphics[k] == 0 && sprite_ai_state[k] < 2) SpriteSfx_QueueSfx2WithPan(k, 0x3); sprite_delay_main[k] = kRetreatBat_Delay[sprite_D[k]]; } switch(sprite_ai_state[k]) { case 0: { j = sprite_A[k]; if (kRetreatBat_Xpos[j] < cur_sprite_x) { if (j >= 2) { sprite_ai_state[k]++; sprite_delay_aux1[k] = 208; } sprite_A[k]++; sprite_D[k]++; } update_pos: if (!(frame_counter & 7)) sprite_y_vel[k] += (kRetreatBat_Ypos[j] >= cur_sprite_y) ? 1 : -1; if (!(frame_counter & 15)) sprite_x_vel[k]++; break; } case 1: if (!sprite_delay_aux1[k]) { sprite_ai_state[k]++; SpriteSfx_QueueSfx3WithPan(k, 0x26); sprite_D[k]++; sprite_x_lo[k] = 232; sprite_x_hi[k] = 7; sprite_y_lo[k] = 224; sprite_y_hi[k] = 5; sprite_x_vel[k] = 0; sprite_y_vel[k] = 64; sprite_delay_aux1[k] = 45; } else { if (!(frame_counter & 3)) sprite_x_vel[k]--; j = sprite_A[k]; goto update_pos; } break; case 2: if (!sprite_delay_aux1[k]) { sprite_y_vel[k] = 0; sprite_delay_aux1[k] = 96; sprite_ai_state[k]++; } if (sprite_delay_aux1[k] == 9) { BatCrash_SpawnDebris(k); CreatePyramidHole(); } break; case 3: // Finishing Up if (!sprite_delay_aux1[k]) { sprite_state[k] = 0; overworld_map_state++; } break; } } void Sprite_SpawnBatCrashCutscene() { // 9af6f5 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(0, 0x37, &info); if (j >= 0) { sprite_y_vel[j] = 0; sprite_B[j] = 0; sprite_D[j] = 0; sprite_floor[j] = 0; sprite_subtype2[j] = 1; sprite_flags2[j] = 1; sprite_flags3[j] = 1; sprite_oam_flags[j] = 1; sprite_x_lo[j] = 204; sprite_x_hi[j] = 7; sprite_y_lo[j] = 50; sprite_y_hi[j] = 6; sprite_defl_bits[j] = 128; } } void BatCrash_DrawHardcodedGarbage(int k) { // 9af750 static const OamEntSigned kRetreatBat_Oams[8] = { { 104, -105, 0x57, 0x01}, { 120, -105, 0x57, 0x01}, {-120, -105, 0x57, 0x01}, { 104, -89, 0x57, 0x01}, { 120, -89, 0x57, 0x01}, {-120, -89, 0x57, 0x01}, { 101, -112, 0x57, 0x01}, {-117, -112, 0x57, 0x01}, }; memcpy(oam_buf + 76, kRetreatBat_Oams, 32); for (int i = 0; i < 9; i++) // wtf 9 bytewise_extended_oam[i + 76] = 2; } void BatCrash_SpawnDebris(int k) { // 9af7e5 static const int8 kPyramidDebris_X[30] = { -8, 0, 8, 16, 24, 32, -8, 0, 8, 16, 24, 32, -8, 0, 8, 16, 24, 32, -8, 0, 8, 16, 24, 32, -8, 0, 8, 16, 24, 32, }; static const int8 kPyramidDebris_Y[30] = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, }; static const int8 kPyramidDebris_Xvel[30] = { -30, -25, -8, 8, 25, 30, -50, -45, -20, 20, 45, 50, -50, -35, -25, 25, 35, 50, -45, -50, -60, 60, 50, 45, -30, -35, -40, 40, 35, 30, }; static const int8 kPyramidDebris_Yvel[30] = { 2, 5, 10, 10, 5, 2, 5, 20, 30, 30, 20, 5, 10, 30, 40, 40, 30, 10, -20, -40, -60, -60, -40, -20, -10, -20, -40, -40, -20, -10, }; for (int j = 29; j >= 0; j--) { GarnishSpawn_PyramidDebris(kPyramidDebris_X[j], kPyramidDebris_Y[j], kPyramidDebris_Xvel[j], kPyramidDebris_Yvel[j]); } sprite_delay_aux3[k] = 32; } void RetreatBat_Draw(int k) { // 9af833 static const DrawMultipleData kRetreatBat_Dmds[18] = { { 0, 0, 0x044b, 0}, { 5, -4, 0x045b, 0}, {-2, -4, 0x0464, 2}, {-2, -4, 0x0449, 2}, {-8, -9, 0x046c, 2}, { 8, -9, 0x446c, 2}, {-8, -7, 0x044c, 2}, { 8, -7, 0x444c, 2}, {-8, -9, 0x0444, 2}, { 8, -9, 0x4444, 2}, {-8, -8, 0x0462, 2}, { 8, -8, 0x4462, 2}, {-8, -7, 0x0460, 2}, { 8, -7, 0x4460, 2}, { 0, 0, 0x044e, 2}, {16, 0, 0x444e, 2}, { 0, 16, 0x046e, 2}, {16, 16, 0x446e, 2}, }; static const uint8 kOffs[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 8, 10, 12, 10, 14, 14, 14, 14}; static const uint8 kCount[20] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, }; oam_cur_ptr = 0x960; oam_ext_cur_ptr = 0xa78; int j = sprite_D[k] * 4 + sprite_graphics[k]; Sprite_DrawMultiple(k, &kRetreatBat_Dmds[kOffs[j]], kCount[j], NULL); } void DrinkingGuy_Draw(int k) { // 9af88c static const DrawMultipleData kDrinkingGuy_Dmd[6] = { {8, 2, 0x00ae, 0}, {0, -9, 0x0822, 2}, {0, 0, 0x0006, 2}, {7, 0, 0x00af, 0}, {0, -9, 0x0822, 2}, {0, 0, 0x0006, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kDrinkingGuy_Dmd[sprite_graphics[k] * 3], 3, &info); SpriteDraw_Shadow(k, &info); } void Lady_Draw(int k) { // 9af92c static const DrawMultipleData kLadyDmd[16] = { {0, -8, 0x00e0, 2}, {0, 0, 0x00e8, 2}, {0, -7, 0x00e0, 2}, {0, 1, 0x40e8, 2}, {0, -8, 0x00c0, 2}, {0, 0, 0x00c2, 2}, {0, -7, 0x00c0, 2}, {0, 1, 0x40c2, 2}, {0, -8, 0x00e2, 2}, {0, 0, 0x00e4, 2}, {0, -7, 0x00e2, 2}, {0, 1, 0x00e6, 2}, {0, -8, 0x40e2, 2}, {0, 0, 0x40e4, 2}, {0, -7, 0x40e2, 2}, {0, 1, 0x40e6, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kLadyDmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info); SpriteDraw_Shadow(k, &info); } void Lanmola_SpawnShrapnel(int k) { // 9af981 static const int8 kLanmolaShrapnel_Yvel[8] = {28, -28, 28, -28, 0, 36, 0, -36}; static const int8 kLanmolaShrapnel_Xvel[8] = {-28, -28, 28, 28, -36, 0, 36, 0}; tmp_counter = (sprite_state[0] + sprite_state[1] + sprite_state[2]) < 10 ? 7 : 3; do { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xC2, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_x_lo[j] = info.r0_x + 4; sprite_y_lo[j] = info.r2_y + 4; sprite_ignore_projectile[j] = 1; sprite_bump_damage[j] = 1; sprite_flags4[j] = 1; sprite_z[j] = 0; sprite_flags2[j] = 0x20; sprite_x_vel[j] = kLanmolaShrapnel_Xvel[tmp_counter]; sprite_y_vel[j] = kLanmolaShrapnel_Yvel[tmp_counter]; sprite_graphics[j] = GetRandomNumber() & 1; } } while (!sign8(--tmp_counter)); } void Sprite_Cukeman(int k) { // 9afa0c if (sprite_head_dir[k] == 0) return; if (sprite_state[k] == 9 && !(submodule_index | flag_unk1) && (uint16)(cur_sprite_x - link_x_coord + 0x18) < 0x30 && (uint16)(link_y_coord - cur_sprite_y + 0x20) < 0x30 && (filtered_joypad_L & 0x80)) { dialogue_message_index = 0x17a + (sprite_subtype[k]++ & 1); Sprite_ShowMessageMinimal(); } uint8 old = sprite_oam_flags[k] & 0xf0; sprite_oam_flags[k] = old | 8; Cukeman_Draw(k); sprite_oam_flags[k] = old | 0xd; Oam_AllocateFromRegionA(0x10); } void Cukeman_Draw(int k) { // 9afb0e static const DrawMultipleData kCukeman_Dmd[18] = { { 0, 0, 0x01f3, 0}, { 7, 0, 0x41f3, 0}, { 4, 7, 0x07e0, 0}, {-1, 2, 0x01f3, 0}, { 6, 1, 0x41f3, 0}, { 4, 8, 0x07e0, 0}, { 1, 1, 0x01f3, 0}, { 8, 2, 0x41f3, 0}, { 4, 8, 0x07e0, 0}, {-2, 0, 0x01f3, 0}, {10, 0, 0x41f3, 0}, { 4, 7, 0x07e0, 0}, { 0, 0, 0x01f3, 0}, { 8, 0, 0x41f3, 0}, { 4, 6, 0x07e0, 0}, {-5, 0, 0x01f3, 0}, {16, 0, 0x41f3, 0}, { 4, 8, 0x07e0, 0}, }; Sprite_DrawMultiple(k, &kCukeman_Dmd[sprite_graphics[k] * 3], 3, NULL); } void RunningBoy_SpawnDustGarnish(int k) { // 9afb2c if (++sprite_die_action[k] & 0xf) return; int j = GarnishAllocForce(); garnish_type[j] = 20; garnish_active = 20; Garnish_SetX(j, Sprite_GetX(k) + 4); Garnish_SetY(j, Sprite_GetY(k) + 28); garnish_countdown[j] = 10; } void MovableMantle_Draw(int k) { // 9afcb3 Oam_AllocateFromRegionB(0x20); PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); for (int i = 5; i >= 0; i--, oam++) { oam->x = kMovableMantle_X[i] + info.x; oam->y = kMovableMantle_Y[i] + info.y; oam->charnum = kMovableMantle_Char[i]; oam->flags = kMovableMantle_Flags[i]; } Sprite_CorrectOamEntries(k, 5, 2); } void Mothula_Draw(int k) { // 9afdb5 static const DrawMultipleData kMothula_Dmd[24] = { {-24, -8, 0x0080, 2}, { -8, -8, 0x0082, 2}, { 8, -8, 0x4082, 2}, { 24, -8, 0x4080, 2}, {-24, 8, 0x00a0, 2}, { -8, 8, 0x00a2, 2}, { 8, 8, 0x40a2, 2}, { 24, 8, 0x40a0, 2}, {-24, -8, 0x0084, 2}, { -8, -8, 0x0086, 2}, { 8, -8, 0x4086, 2}, { 24, -8, 0x4084, 2}, {-24, 8, 0x00a4, 2}, { -8, 8, 0x00a6, 2}, { 8, 8, 0x40a6, 2}, { 24, 8, 0x40a4, 2}, { -8, -8, 0x0088, 2}, { -8, -8, 0x0088, 2}, { 8, -8, 0x4088, 2}, { 8, -8, 0x4088, 2}, { -8, 8, 0x00a8, 2}, { -8, 8, 0x00a8, 2}, { 8, 8, 0x40a8, 2}, { 8, 8, 0x40a8, 2}, }; oam_cur_ptr = 0x920; oam_ext_cur_ptr = 0xa68; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kMothula_Dmd[sprite_graphics[k] * 8], 8, &info); if (sprite_pause[k]) return; info.y += sprite_z[k]; static const int8 kMothula_Draw_X[27] = { 0, 3, 6, 9, 12, -3, -6, -9, -12, 0, 2, 4, 6, 8, -2, -4, -6, -8, 0, 1, 2, 3, 4, -1, -2, -3, -4, }; OamEnt *oam = GetOamCurPtr() + 10; int g = sprite_graphics[k]; for (int i = 8; i >= 0; i--, oam++) { uint16 x = info.x + kMothula_Draw_X[g * 9 + i]; uint16 y = info.y + 16; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = 0x6c; oam->flags = 0x24; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } } void BottleMerchant_BuyBee(int k) { // 9afe88 static const int8 kBottleVendor_GoodBeeX[5] = {-6, -3, 0, 4, 7}; static const int8 kBottleVendor_GoodBeeY[5] = {11, 14, 16, 14, 11}; SpriteSpawnInfo info; SpriteSfx_QueueSfx3WithPan(k, 0x13); tmp_counter = 4; do { int j = Sprite_SpawnDynamically(k, 0xd8, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_x_lo[j] = info.r0_x + 4; sprite_stunned[j] = 0xff; sprite_x_vel[j] = kBottleVendor_GoodBeeX[tmp_counter]; sprite_y_vel[j] = kBottleVendor_GoodBeeY[tmp_counter]; sprite_z_vel[j] = 32; sprite_delay_aux4[j] = 32; } } while (!sign8(--tmp_counter)); } void Sprite_ChickenLady(int k) { // 9afed3 sprite_D[k] = 1; Lady_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_delay_main[k] == 1) { dialogue_message_index = 0x17d; Sprite_ShowMessageMinimal(); } sprite_graphics[k] = frame_counter >> 4 & 1; } void Overworld_DrawWoodenDoor(uint16 pos, bool unlocked) { // 9bc952 Overworld_DrawMap16_Persist(pos, unlocked ? 0xda5 : 0xda4); Overworld_DrawMap16_Persist(pos+2, unlocked ? 0xda7 : 0xda6); nmi_load_bg_from_vram = 1; } void Sprite_D4_Landmine(int k) { // 9d8099 static const uint8 kLandMine_OamFlags[4] = {4, 2, 8, 2}; Landmine_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (!Landmine_CheckDetonationFromHammer(k)) { if (!sprite_delay_main[k]) { sprite_oam_flags[k] = 4; if (Sprite_CheckDamageToLink(k)) sprite_delay_main[k] = 8; return; } if (sprite_delay_main[k] != 1) { sprite_oam_flags[k] = kLandMine_OamFlags[sprite_delay_main[k] >> 1 & 3]; return; } } sprite_state[k] = 0; int j = Sprite_SpawnBomb(k); if (j >= 0) { sprite_state[j] = 6; sprite_C[j] = 2; sprite_oam_flags[j] = 2; sprite_flags4[j] = 9; sprite_delay_aux1[j] = 31; sprite_flags2[j] = 3; sound_effect_1 = Sprite_CalculateSfxPan(k) | 12; } } void Landmine_Draw(int k) { // 9d810c static const DrawMultipleData kLandmine_Dmd[2] = { {0, 4, 0x0070, 0}, {8, 4, 0x4070, 0}, }; Oam_AllocateFromRegionB(8); if (byte_7E0FC6 >= 3) return; Sprite_DrawMultiple(k, kLandmine_Dmd, 2, NULL); } void Sprite_D3_Stal(int k) { // 9d8129 static const uint8 kStal_Gfx[5] = {2, 2, 1, 0, 1}; if (byte_7E0FC6 < 3) { if (!sprite_ai_state[k]) Oam_AllocateFromRegionB(4); Stal_Draw(k); } if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; switch(sprite_ai_state[k]) { case 0: // dormant sprite_ignore_projectile[k] = 1; if (Sprite_CheckDamageToLink_same_layer(k)) { Sprite_NullifyHookshotDrag(); Sprite_RepelDash(); if (!sprite_delay_main[k]) { sprite_delay_main[k] = 64; SpriteSfx_QueueSfx2WithPan(k, 0x22); } } if (sprite_delay_main[k] != 0) { if (sprite_delay_main[k] - 1) { sprite_hit_timer[k] = (sprite_delay_main[k] - 1) | 64; } else { sprite_ignore_projectile[k] = 0; sprite_ai_state[k]++; sprite_hit_timer[k] = 0; sprite_flags3[k] &= ~0x40; sprite_flags2[k] &= ~0x80; } } break; case 1: // active Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXYZ(k); Sprite_CheckTileCollision(k); sprite_z_vel[k]-=2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = 16; Sprite_ApplySpeedTowardsLink(k, 12); } if (!(frame_counter & 3) && ++sprite_subtype2[k] == 5) sprite_subtype2[k] = 0; sprite_graphics[k] = kStal_Gfx[sprite_subtype2[k]]; break; } } void Stal_Draw(int k) { // 9d820c static const DrawMultipleData kStal_Dmd[6] = { {0, 0, 0x0044, 2}, {4, 11, 0x0070, 0}, {0, 0, 0x0044, 2}, {4, 12, 0x0070, 0}, {0, 0, 0x0044, 2}, {4, 13, 0x0070, 0}, }; PrepOamCoordsRet info; int n = sprite_ai_state[k] ? 2 : 1; Sprite_DrawMultiple(k, &kStal_Dmd[sprite_graphics[k] * 2], n, &info); if (sprite_ai_state[k]) SpriteDraw_Shadow(k, &info); } void Sprite_D2_FloppingFish(int k) { // 9d8235 static const int8 kFish_Xvel[8] = {0, 12, 16, 12, 0, -12, -16, -12}; static const int8 kFish_Yvel[8] = {-16, -12, 0, 12, 16, 12, 0, -12}; static const uint8 kFish_Tab1[2] = {2, 0}; static const uint8 kFish_Gfx[3] = {1, 5, 3}; static const uint8 kFish_Gfx2[17] = {5, 5, 6, 6, 5, 5, 4, 4, 3, 7, 7, 8, 8, 7, 7, 8, 8 }; if (byte_7E0FC6 < 3) Fish_Draw(k); if (sprite_state[k] == 10) { sprite_ai_state[k] = 4; sprite_graphics[k] = (frame_counter >> 4 & 1) + 3; } if (Sprite_ReturnIfInactive(k)) return; switch (sprite_ai_state[k]) { case 0: // check deep water Sprite_CheckTileCollision(k); if (sprite_tiletype == 8) sprite_state[k] = 0; else sprite_ai_state[k] = 1; break; case 1: // flop around Sprite_CheckIfLifted_permissive(k); Sprite_BounceFromTileCollision(k); Sprite_MoveXYZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; if (sprite_tiletype == 9) { Sprite_SpawnSmallSplash(k); } else if (sprite_tiletype == 8) { sprite_state[k] = 0; Sprite_SpawnSmallSplash(k); } sprite_z_vel[k] = (GetRandomNumber() & 15) + 16; int j = GetRandomNumber() & 7; sprite_x_vel[k] = kFish_Xvel[j]; sprite_y_vel[k] = kFish_Yvel[j]; sprite_D[k]++; sprite_subtype2[k] = 3; } sprite_subtype2[k]++; if (!(sprite_subtype2[k] & 7)) { int j = sprite_D[k] & 1; if (sprite_A[k] != kFish_Tab1[j]) sprite_A[k] += j ? -1 : 1; } sprite_graphics[k] = kFish_Gfx[sprite_A[k]] + (frame_counter >> 3 & 1); break; case 2: // pause before leap if (!sprite_delay_main[k]) { sprite_ai_state[k] = 3; sprite_z_vel[k] = 48; Sprite_SpawnSmallSplash(k); } break; case 3: // leaping Sprite_MoveZ(k); sprite_z_vel[k] -= 2; if (sprite_z_vel[k] == 0 && sprite_A[k] != 0) { dialogue_message_index = 0x176; Sprite_ShowMessageMinimal(); } if (sign8(sprite_z[k])) { sprite_z[k] = 0; Sprite_SpawnSmallSplash(k); if (sprite_A[k]) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xdb, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); Sprite_SetX(j, info.r0_x + 4); sprite_stunned[j] = 255; sprite_z_vel[j] = 48; sprite_delay_aux3[j] = 48; Sprite_ApplySpeedTowardsLink(j, 16); } } sprite_state[k] = 0; } sprite_graphics[k] = kFish_Gfx2[++sprite_subtype2[k] >> 2]; break; case 4: // wiggle if (!sprite_z[k]) sprite_ai_state[k] = 1; Sprite_MoveXY(k); ThrownSprite_TileAndSpriteInteraction(k); break; } } void Fish_Draw(int k) { // 9d8483 static const DrawMultipleData kFish_Dmd[16] = { {-4, 8, 0x045e, 0}, { 4, 8, 0x045f, 0}, {-4, 8, 0x845e, 0}, { 4, 8, 0x845f, 0}, {-4, 8, 0x445f, 0}, { 4, 8, 0x445e, 0}, {-4, 8, 0xc45f, 0}, { 4, 8, 0xc45e, 0}, { 0, 0, 0x0461, 0}, { 0, 8, 0x0471, 0}, { 0, 0, 0x4461, 0}, { 0, 8, 0x4471, 0}, { 0, 0, 0x8471, 0}, { 0, 8, 0x8461, 0}, { 0, 0, 0xc471, 0}, { 0, 8, 0xc461, 0}, }; static const DrawMultipleData kFish_Dmd2[9] = { {-2, 11, 0x0438, 0}, { 0, 11, 0x0438, 0}, { 2, 11, 0x0438, 0}, {-1, 11, 0x0438, 0}, { 0, 11, 0x0438, 0}, { 1, 11, 0x0438, 0}, { 0, 11, 0x0438, 0}, { 0, 11, 0x0438, 0}, { 0, 11, 0x0438, 0}, }; PrepOamCoordsRet info; if (sprite_graphics[k] == 0) { Sprite_PrepOamCoord(k, &info); return; } cur_sprite_x += 4; Sprite_DrawMultiple(k, &kFish_Dmd[(sprite_graphics[k] - 1) * 2], 2, &info); cur_sprite_y += sprite_z[k]; int j = sprite_z[k] >> 2; oam_cur_ptr += 8, oam_ext_cur_ptr += 2; Sprite_DrawMultiple(k, &kFish_Dmd2[((j >= 2) ? 2 : j) * 3], 3, &info); Sprite_Get16BitCoords(k); } void ChimneySmoke_Draw(int k) { // 9d8531 static const DrawMultipleData kChimneySmoke_Dmd[8] = { {0, 0, 0x0086, 0}, {8, 0, 0x0087, 0}, {0, 8, 0x0096, 0}, {8, 8, 0x0097, 0}, {1, 1, 0x0086, 0}, {7, 1, 0x0087, 0}, {1, 7, 0x0096, 0}, {7, 7, 0x0097, 0}, }; Sprite_DrawMultiple(k, &kChimneySmoke_Dmd[(sprite_graphics[k] & 1) * 4], 4, NULL); } void Sprite_D1_BunnyBeam(int k) { // 9d858b if (player_is_indoors) Sprite_BunnyBeam(k); else Sprite_Chimney(k); } void Sprite_Chimney(int k) { // 9d858f sprite_flags3[k] = 64; sprite_ignore_projectile[k] = 64; if (!sprite_ai_state[k]) { if (Sprite_ReturnIfInactive(k)) return; if (sprite_delay_main[k]) return; sprite_delay_main[k] = 67; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xd1, &info); if (j < 0) return; Sprite_SetSpawnedCoordinates(j, &info); int t = (uint8)info.r0_x + 8; sprite_x_lo[j] = t; sprite_y_lo[j] = info.r2_y + 4 + (t >> 8); sprite_oam_flags[j] = 4; sprite_ai_state[j] = 4; sprite_flags2[j] = 67; sprite_flags3[j] = 67; sprite_x_vel[j] = -4; sprite_y_vel[j] = -6; } else { sprite_obj_prio[k] = 0x30; ChimneySmoke_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXY(k); if (!(++sprite_subtype2[k] & 7)) { int j = sprite_D[k] & 1; sprite_x_vel[k] += j ? -1 : 1; if (sprite_x_vel[k] == (uint8)(j ? -4 : 4)) sprite_D[k]++; } if (!(sprite_subtype2[k] & 31)) sprite_graphics[k]++; } } void Sprite_BunnyBeam(int k) { // 9d85e0 static const uint8 kRabbitBeam_Gfx[6] = {0xd7, 0xd7, 0xd7, 0x91, 0x91, 0x91}; PrepOamCoordsRet info; if (!sprite_ai_state[k]) { Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; if (!Sprite_CheckTileCollision(k)) { sprite_ai_state[k]++; sprite_delay_main[k] = 128; } return; } SpriteDraw_Antfairy(k); if (!sprite_pause[k]) { OamEnt *oam = GetOamCurPtr(); uint8 charnum = kRabbitBeam_Gfx[sprite_graphics[k]]; for (int i = 0; i < 5; i++) { oam[i].charnum = charnum; oam[i].flags = oam[i].flags & 0xf0 | 2; } } if (Sprite_ReturnIfInactive(k)) return; if (!sprite_delay_main[k]) { sprite_bump_damage[k] = 0x30; if (Sprite_CheckDamageToLink(k)) { sprite_state[k] = 0; link_timer_tempbunny = 256; } if (link_is_on_lower_level == sprite_floor[k]) Sprite_ApplySpeedTowardsLink(k, 16); Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) { sprite_state[k] = 0; Sprite_SpawnPoofGarnish(k); SpriteSfx_QueueSfx2WithPan(k, 0x15); } } } void Sprite_D0_Lynel(int k) { // 9d866a static const int8 kLynel_AttackGfx[4] = {5, 2, 8, 10}; static const int8 kLynel_Gfx[8] = {3, 0, 6, 9, 4, 1, 7, 10}; Lynel_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL); Sprite_CheckDamageToAndFromLink(k); switch(sprite_ai_state[k]) { case 0: // target if (!sprite_delay_main[k]) { static const int8 kLynel_Xtarget[4] = {-96, 96, 0, 0}; static const int8 kLynel_Ytarget[4] = {8, 8, -96, 112}; int j = sprite_D[k]; int x = link_x_coord + kLynel_Xtarget[j]; sprite_A[k] = x, sprite_B[k] = x >> 8; int y = link_y_coord + kLynel_Ytarget[j]; sprite_C[k] = y, sprite_E[k] = y >> 8; sprite_ai_state[k]++; sprite_delay_main[k] = 80; } sprite_graphics[k] = kLynel_Gfx[sprite_subtype2[k] & 4 | sprite_D[k]]; break; case 1: // approach if (sprite_delay_main[k]) { if (!((k ^ frame_counter) & 3)) { uint16 x = sprite_A[k] | sprite_B[k] << 8; uint16 y = sprite_C[k] | sprite_E[k] << 8; if ((uint16)(x - cur_sprite_x + 5) < 10 && (uint16)(y - cur_sprite_y + 5) < 10) goto incr_state; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 24); sprite_x_vel[k] = pt.x; sprite_y_vel[k] = pt.y; } Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) goto incr_state; sprite_graphics[k] = kLynel_Gfx[++sprite_subtype2[k] & 4 | sprite_D[k]]; } else { incr_state: sprite_ai_state[k]++; sprite_delay_main[k] = 32; } break; case 2: // attack if (!sprite_delay_main[k]) { sprite_delay_main[k] = (GetRandomNumber() & 15) + 16; sprite_ai_state[k] = 0; return; } if (sprite_delay_main[k] == 16) { int j = Sprite_SpawnFirePhlegm(k); if (j >= 0 && link_shield_type != 3) sprite_flags5[j] = 0; } sprite_graphics[k] = kLynel_AttackGfx[sprite_D[k]]; Sprite_CheckTileCollision(k); break; } } void Lynel_Draw(int k) { // 9d8880 static const DrawMultipleData kLynel_Dmd[33] = { {-5, -11, 0x00cc, 2}, {-4, 0, 0x00e4, 2}, { 4, 0, 0x00e5, 2}, {-5, -10, 0x00cc, 2}, {-4, 0, 0x00e7, 2}, { 4, 0, 0x00e8, 2}, {-5, -11, 0x00c8, 2}, {-4, 0, 0x00e4, 2}, { 4, 0, 0x00e5, 2}, { 5, -11, 0x40cc, 2}, {-4, 0, 0x40e5, 2}, { 4, 0, 0x40e4, 2}, { 5, -10, 0x40cc, 2}, {-4, 0, 0x40e8, 2}, { 4, 0, 0x40e7, 2}, { 5, -11, 0x40c8, 2}, {-4, 0, 0x40e8, 2}, { 4, 0, 0x40e7, 2}, { 0, -9, 0x00ce, 2}, {-4, 0, 0x00ea, 2}, { 4, 0, 0x00eb, 2}, { 0, -9, 0x00ce, 2}, {-4, 0, 0x40eb, 2}, { 4, 0, 0x40ea, 2}, { 0, -9, 0x00ca, 2}, {-4, 0, 0x40eb, 2}, { 4, 0, 0x00eb, 2}, { 0, -14, 0x00c6, 2}, {-4, 0, 0x00ed, 2}, { 4, 0, 0x00ee, 2}, { 0, -14, 0x00c6, 2}, {-4, 0, 0x40ee, 2}, { 4, 0, 0x40ed, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kLynel_Dmd[sprite_graphics[k] * 3], 3, &info); SpriteDraw_Shadow(k, &info); } void Sprite_SpawnPhantomGanon(int k) { // 9d88a1 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xc9, &info); Sprite_SetSpawnedCoordinates(j, &info); sprite_flags2[j] = 2; sprite_ignore_projectile[j] = 2; sprite_anim_clock[j] = 1; sprite_oam_flags[j] = 0; } void Sprite_PhantomGanon(int k) { // 9d88bc static const uint8 kGanonBat_Gfx[4] = {0, 1, 2, 1}; static const int8 kGanonBat_TargetXvel[2] = {32, -32}; static const int8 kGanonBat_TargetYvel[2] = {16, -16}; if (!sprite_ai_state[k]) { PhantomGanon_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveY(k); if (!(++sprite_subtype2[k] & 31)) { if (--sprite_y_vel[k] == 252) { int j = SpawnBossPoof(k); Sprite_SetY(j, Sprite_GetY(j) - 20); } else if (sprite_y_vel[k] == 251) { sprite_ai_state[k]++; sprite_delay_main[k] = 255; sprite_y_vel[k] = -4; } } } else { GanonBat_Draw(k); if (sprite_pause[k]) { sprite_state[k] = 0; dung_savegame_state_bits |= 0x8000; } if (Sprite_ReturnIfInactive(k)) return; sprite_graphics[k] = kGanonBat_Gfx[frame_counter >> 2 & 3]; if (sprite_delay_main[k]) { if (sprite_delay_main[k] < 208) { int j = sprite_head_dir[k] & 1; sprite_y_vel[k] += j ? -1 : 1; if (sprite_y_vel[k] == (uint8)kGanonBat_TargetYvel[j]) sprite_head_dir[k]++; j = sprite_D[k] & 1; sprite_x_vel[k] += j ? -1 : 1; if (sprite_x_vel[k] == (uint8)kGanonBat_TargetXvel[j]) sprite_D[k]++; if (sprite_x_vel[k] == 0) SpriteSfx_QueueSfx3WithPan(k, 0x1e); } ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, link_x_coord & 0xff00 | 0x78, link_y_coord & 0xff00 | 0x50, 5); uint8 xvel = sprite_x_vel[k], yvel = sprite_y_vel[k]; sprite_x_vel[k] = xvel + pt.x, sprite_y_vel[k] = yvel + pt.y; Sprite_MoveXY(k); sprite_x_vel[k] = xvel, sprite_y_vel[k] = yvel; } else { Sprite_MoveXY(k); if (sprite_x_vel[k] != 64) { sprite_x_vel[k]++; sprite_y_vel[k]--; } } } } void GanonBat_Draw(int k) { // 9d89eb static const DrawMultipleData kGanonBat_Dmd[6] = { {-8, 0, 0x0560, 2}, { 8, 0, 0x4560, 2}, {-8, 0, 0x0562, 2}, { 8, 0, 0x4562, 2}, {-8, 0, 0x0544, 2}, { 8, 0, 0x4544, 2}, }; Sprite_DrawMultiple(k, &kGanonBat_Dmd[sprite_graphics[k] * 2], 2, NULL); } void PhantomGanon_Draw(int k) { // 9d8a84 static const DrawMultipleData kPhantomGanon_Dmd[16] = { {-16, -8, 0x0d46, 2}, { -8, -8, 0x0d47, 2}, { 8, -8, 0x4d47, 2}, { 16, -8, 0x4d46, 2}, {-16, 8, 0x0d69, 2}, { -8, 8, 0x0d6a, 2}, { 8, 8, 0x4d6a, 2}, { 16, 8, 0x4d69, 2}, {-16, -8, 0x0d46, 2}, { -8, -8, 0x0d47, 2}, { 8, -8, 0x4d47, 2}, { 16, -8, 0x4d46, 2}, {-16, 8, 0x0d66, 2}, { -8, 8, 0x0d67, 2}, { 8, 8, 0x4d67, 2}, { 16, 8, 0x4d66, 2}, }; oam_cur_ptr = 0x950; oam_ext_cur_ptr = 0xa74; Sprite_DrawMultiple(k, &kPhantomGanon_Dmd[sprite_graphics[k] * 8], 8, NULL); } void SwishEvery16Frames(int k) { // 9d8aa9 if (!(frame_counter & 15)) SpriteSfx_QueueSfx3WithPan(k, 0x6); } void Sprite_GanonTrident(int k) { // 9d8ab6 Trident_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToAndFromLink(k); SwishEvery16Frames(k); Sprite_MoveXY(k); sprite_G[k] = kGanon_G_Func2[--sprite_subtype2[k] >> 2 & 7]; if (sprite_delay_main[k]) { if (sprite_delay_main[k] & 1) return; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32); Sprite_ApproachTargetSpeed(k, pt.x, pt.y); } else { int x = Sprite_GetX(0) + (sprite_D[0] ? -16 : 24); int y = Sprite_GetY(0) - 16; if (Ganon_AttemptTridentCatch(x, y)) { sprite_state[k] = 0; sprite_ai_state[0] = 3; sprite_delay_main[0] = 16; } ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 32); Sprite_ApproachTargetSpeed(k, pt.x, pt.y); } } void Sprite_FireBat_Trailer(int k) { // 9d8b49 FireBat_Draw(k); if (Sprite_ReturnIfInactive(k)) return; FireBat_Move(k); } void Sprite_SpiralFireBat(int k) { // 9d8b52 FireBat_Draw(k); if (Sprite_ReturnIfInactive(k)) return; { uint16 x = sprite_A[k] | sprite_B[k] << 8; uint16 y = sprite_C[k] | sprite_E[k] << 8; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 2); ProjectSpeedRet pt2 = Sprite_ProjectSpeedTowardsLocation(k, x, y, 80); sprite_x_vel[k] = pt2.y - pt.x; sprite_y_vel[k] = -pt2.x - pt.y; } FireBat_Move(k); } void FireBat_Move(int k) { // 9d8b90 FireBat_Animate(k); Sprite_MoveXY(k); if (sprite_subtype2[k] & 7) return; int j = Garnish_FlameTrail(k, true); // garnish_type[j] = 0x10; garnish_countdown[j] = (sprite_anim_clock[k] == 5) ? 0x2f : 0x4f; } void Sprite_FireBat_Launched(int k) { // 9d8bd7 FireBat_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToLink(k); switch (sprite_ai_state[k]) { case 0: GetPositionRelativeToTheGreatOverlordGanon(k); if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; } else { sprite_graphics[k] = sprite_delay_main[k] >> 2 & 1; } break; case 1: GetPositionRelativeToTheGreatOverlordGanon(k); sprite_graphics[k] = ++sprite_subtype2[k] >> 2 & 1; break; case 2: Sprite_MoveXY(k); sprite_defl_bits[k] = 64; if (sprite_delay_aux1[k] == 0) { if (sprite_delay_main[k] == 0) { FireBat_Animate(k); FireBat_Animate(k); } else { uint8 t = sprite_delay_main[k] - 1; if (t == 0) sprite_delay_aux1[k] = t = 35; sprite_graphics[k] = t >> 2 & 1; } } else if (sprite_delay_aux1[k] == 1) { Sprite_ApplySpeedTowardsLink(k, 48); SpriteSfx_QueueSfx3WithPan(k, 0x1e); FireBat_Animate(k); FireBat_Animate(k); } else { static const uint8 kFirebat_Gfx2[9] = { 4, 4, 4, 3, 3, 3, 2, 2, 2 }; sprite_graphics[k] = kFirebat_Gfx2[sprite_delay_aux1[k] >> 2]; } break; } } void GetPositionRelativeToTheGreatOverlordGanon(int k) { // 9d8bee static const int8 kFirebat_X[2] = { 20, -18 }; static const int8 kFirebat_Y[2] = { -20, -20 }; int j = sprite_D[0]; Sprite_SetX(k, (overlord_x_hi[k] | overlord_y_hi[k] << 8) + kFirebat_X[j]); Sprite_SetY(k, (overlord_gen2[k] | overlord_floor[k] << 8) + kFirebat_Y[j]); } void FireBat_Animate(int k) { // 9d8c43 static const uint8 kFirebat_Gfx[4] = { 4, 5, 6, 5 }; sprite_graphics[k] = kFirebat_Gfx[++sprite_subtype2[k] >> 2 & 3]; } void FireBat_Draw(int k) { // 9d8ca9 static const int8 kFirebat_Draw_X[2] = { -8, 8 }; static const uint8 kFirebat_Draw_Char[7] = { 0x88, 0x88, 0x8a, 0x8c, 0x68, 0xaa, 0xa8 }; static const uint8 kFirebat_Draw_Flags[14] = { 0, 0xc0, 0x80, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40 }; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; for (int i = 1; i >= 0; i--, oam++) { uint16 x = info.x + kFirebat_Draw_X[i]; uint16 y = info.y; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kFirebat_Draw_Char[g]; oam->flags = kFirebat_Draw_Flags[g * 2 + i] | info.flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } } bool Ganon_AttemptTridentCatch(uint16 x, uint16 y) { // 9d8d06 return (uint16)(cur_sprite_x - x + 4) < 8 && (uint16)(cur_sprite_y - y + 4) < 8; } void Ganon_HandleFireBatCircle(int k) { // 9d8d70 static const int8 kGanonMath_X[16] = { 0, 16, 24, 28, 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16 }; static const int8 kGanonMath_Y[16] = { 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16, 0, 16, 24, 28 }; WORD(overlord_x_lo[0]) -= 4; for (int i = 0; i != 8; i++) { int t = WORD(overlord_x_lo[0]) + i * 64 & 0x1ff; if (sprite_ai_state[i + 1] != 2) { int j = (t >> 5) - 4 & 0xf; sprite_x_vel[i + 1] = (int8)kGanonMath_X[j] >> 2; sprite_y_vel[i + 1] = (int8)kGanonMath_Y[j] >> 2; } int x = Sprite_GetX(0) + GanonSin(t, overlord_x_lo[2]); overlord_x_hi[i + 1] = x; overlord_y_hi[i + 1] = x >> 8; int y = Sprite_GetY(0) + GanonSin(t + 0x80, overlord_x_lo[2]); overlord_gen2[i + 1] = y; overlord_floor[i + 1] = y >> 8; } tmp_counter = 8; } void Ganon_SpawnSpiralBat(int k) { // 9d8e7c SpriteSpawnInfo info; int j = Sprite_SpawnDynamicallyEx(k, 0xc9, &info, 8); if (j < 0) return; Sprite_SetSpawnedCoordinates(j, &info); sprite_anim_clock[j] = 4; sprite_oam_flags[j] = 3; sprite_flags3[j] = 0x40; sprite_flags2[j] = 1; sprite_defl_bits[j] = 0x80; sprite_y_hi[j] = 128; sprite_delay_main[j] = 48; sprite_bump_damage[j] = 7; sprite_ignore_projectile[j] = 7; } void Sprite_D6_Ganon(int k) { // 9d8eb4 int j; if (sign8(sprite_ai_state[k])) { if (Sprite_ReturnIfInactive(k)) return; if (!sprite_delay_main[k]) sprite_state[k] = 0; if (!(sprite_delay_main[k] & 1)) Ganon_Draw(k); return; } if (sprite_delay_aux4[k]) { static const uint8 kGanon_GfxB[2] = { 16, 10 }; sprite_graphics[k] = kGanon_GfxB[sprite_D[k]]; } if (byte_7E04C5 == 2 && byte_7E04C5 != sprite_room[k]) sprite_delay_aux1[k] = 64; sprite_room[k] = byte_7E04C5; Ganon_Draw(k); if (sprite_delay_aux1[k]) { sprite_graphics[k] = 15; Ganon_EnableInvincibility(k); Sprite_CheckDamageToAndFromLink(k); return; } if (Sprite_ReturnIfInactive(k)) return; if (sprite_delay_aux2[k] == 1) Ganon_ExtinguishTorch(); else if (sprite_delay_aux2[k] == 16) Ganon_ExtinguishTorch_adjust_translucency(); PairU8 pair = Sprite_IsRightOfLink(k); static const uint8 kGanon_HeadDir0[2] = { 2, 0 }; sprite_head_dir[k] = (uint8)(pair.b + 32) < 64 ? 1 : kGanon_HeadDir0[pair.a]; if (sprite_delay_aux4[k]) { sprite_ignore_projectile[k] = sprite_delay_aux4[k]; if (Sprite_ReturnIfRecoiling(k)) return; sprite_delay_main[k] = 0; return; } if (!(sprite_ignore_projectile[k] | flag_is_link_immobilized) && byte_7E04C5 == 2) Sprite_CheckDamageToAndFromLink(k); sprite_ignore_projectile[k] = 0; switch (sprite_ai_state[k]) { case 0: // if (sprite_delay_main[k] == 0) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 128; } else if (sprite_delay_main[k] == 32) { music_control = 0x1f; } else if (sprite_delay_main[k] == 64) { dialogue_message_index = 0x16f; Sprite_ShowMessageMinimal(); } break; case 1: // if (sprite_health[k] < 209) sprite_health[k] = 208; if (sprite_delay_main[k] < 64) { static const uint8 kGanon_Gfx1[2] = { 2, 10 }; if (sprite_delay_main[k] == 0) { Ganon_SelectWarpLocation(k, 5); } else { sprite_graphics[k] = kGanon_Gfx1[sprite_D[k]]; } } else if (sprite_delay_main[k] != 64) { Ganon_Phase1_AnimateTridentSpin(k); } else { static const int8 kGanon_X1[2] = { 24, -16 }; static const int8 kGanon_Y1[2] = { 4, 4 }; static const int8 kGanon_Xvel1[16] = { 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16, 0, 16, 24, 28 }; static const int8 kGanon_Yvel1[16] = { 0, 16, 24, 28, 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16 }; sprite_G[k] = 0; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xc9, &info); int i = sprite_D[k]; Sprite_SetX(j, info.r0_x + kGanon_X1[i]); Sprite_SetY(j, info.r2_y + kGanon_Y1[i]); Sprite_ApplySpeedTowardsLink(k, 31); uint8 angle = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]); sprite_x_vel[j] = kGanon_Xvel1[angle - 2 & 0xf]; sprite_y_vel[j] = kGanon_Yvel1[angle - 2 & 0xf]; sprite_delay_main[j] = 112; sprite_anim_clock[j] = 2; sprite_oam_flags[j] = 1; sprite_flags2[j] = 4; sprite_defl_bits[j] = 0x84; sprite_D[j] = 2; sprite_bump_damage[j] = 7; sprite_ignore_projectile[j] = 7; } break; case 2: { // static const uint8 kGanon_Gfx2_0[2] = { 0, 8 }; if (sprite_health[k] < 209) sprite_health[k] = 208; sprite_graphics[k] = kGanon_Gfx2_0[sprite_D[k]]; if (sprite_delay_main[k]) { sprite_ignore_projectile[k]++; if (sprite_delay_main[k] & 1) sprite_graphics[k] = 255; } break; } case 3: // if (sprite_health[k] < 209) sprite_health[k] = 208; if (sprite_delay_main[k] != 0) { Ganon_Phase1_AnimateTridentSpin(k); } else { sprite_ai_state[k] = 6; sprite_delay_main[k] = 127; Ganon_HandleAnimation_Idle(k); } break; case 4: // if (sprite_health[k] < 209) sprite_health[k] = 208; if (sprite_delay_main[k] != 0) Ganon_ShakeHead(k); else Ganon_SelectWarpLocation(k, 5); break; case 13: // sprite_health[k] = 100; // fall through case 5: // case 10: // case 18: { // sprite_ignore_projectile[k]++; uint16 x = sprite_x_hi[k] << 8 | swamola_target_x_lo[0]; uint16 y = sprite_y_hi[k] << 8 | swamola_target_y_lo[0]; if (Ganon_AttemptTridentCatch(x, y)) { sprite_D[k] = sprite_subtype[k] >> 2; if (sprite_ai_state[k] == 5) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 32; } else if (sprite_health[k] >= 161) { sprite_ai_state[k] = 11; sprite_delay_main[k] = 40; } else if (sprite_health[k] >= 97) { sprite_ai_state[k] = 14; sprite_delay_main[k] = 40; } else { sprite_ai_state[k] = 17; sprite_delay_main[k] = 104; } } else { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 32); Sprite_ApproachTargetSpeed(k, pt.x, pt.y); Sprite_MoveXY(k); if (sprite_delay_main[k] == 0 || frame_counter & 1) { sprite_graphics[k] = 255; return; } static const uint8 kGanon_Gfx5[2] = { 2, 10 }; sprite_graphics[k] = kGanon_Gfx5[sprite_D[k]]; if (!(frame_counter & 7)) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xd6, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_ignore_projectile[j] = 24; sprite_delay_main[j] = 24; sprite_ai_state[j] = 255; sprite_graphics[j] = sprite_graphics[k]; sprite_head_dir[j] = sprite_head_dir[k]; } } } break; } case 6: // if (sprite_health[k] < 209) sprite_health[k] = 208; if (!sprite_delay_main[k]) { if (sprite_health[k] >= 209) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 128; } else { sprite_delay_main[k] = 255; sprite_ai_state[k] = 7; } } else { Ganon_ShakeHead(k); } break; case 7: // if (sprite_health[k] < 161) sprite_health[k] = 160; overlord_x_lo[2] = 40; if (!sprite_delay_main[k]) { sprite_ai_state[k] = 8; sprite_delay_main[k] = 255; } else { if (sprite_delay_main[k] < 0xc0 && (sprite_delay_main[k] & 0xf) == 0) Ganon_SpawnSpiralBat(k); Ganon_Phase1_AnimateTridentSpin(k); Ganon_HandleFireBatCircle(k); } break; case 8: { // static const int8 kGanon_Tab2[16] = { 0, 0, 0, 0, -1, -1, -2, -1, 0, 0, 0, 0, 1, 2, 1, 1 }; static const uint8 kGanon_Delay8[8] = { 0x10, 0x30, 0x50, 0x70, 0x90, 0xb0, 0xd0, 0xbd }; if (sprite_health[k] < 161) sprite_health[k] = 160; if (!sprite_delay_main[k]) { sprite_ai_state[k] = 9; sprite_delay_main[k] = 127; Ganon_HandleAnimation_Idle(k); for (int j = 8; j != 0; j--) { sprite_ai_state[j] = 2; sprite_delay_main[j] = kGanon_Delay8[j - 1]; } } else { overlord_x_lo[2] += kGanon_Tab2[sprite_delay_main[k] >> 4 & 15]; Ganon_Phase1_AnimateTridentSpin(k); Ganon_HandleFireBatCircle(k); } break; } case 9: // if (sprite_health[k] < 161) sprite_health[k] = 160; if (!sprite_delay_main[k]) { Ganon_SelectWarpLocation(k, 10); } else { Ganon_ShakeHead(k); } break; case 11: // sprite_ignore_projectile[k]++; Ganon_HandleAnimation_Idle(k); if (!sprite_delay_main[k]) { sprite_delay_main[k] = 255; sprite_ai_state[k] = 7; } else if (sprite_delay_main[k] & 1) { sprite_graphics[k] = 255; } break; case 12: { // j = sprite_delay_main[k]; if (j == 0) { Ganon_SelectWarpLocation(k, 13); return; } int t = 0; if (j < 96) { t = 1; if (j < 72) { if (j == 66) Ganon_Func1(k, 3); t = 2; } } if (sprite_D[k]) t += 3; static const uint8 kGanon_Gfx12[6] = { 5, 6, 7, 13, 14, 10 }; sprite_graphics[k] = kGanon_Gfx12[t]; if ((sprite_hit_timer[k] & 127) == 1) { sprite_ai_state[k] = 15; sprite_z_vel[k] = 24; sprite_delay_main[k] = 0; } break; } case 14: // sprite_ignore_projectile[k]++; Ganon_HandleAnimation_Idle(k); sprite_G[k] = 0; if (!sprite_delay_main[k]) { if (GetRandomNumber() & 1) { Ganon_SelectWarpLocation(k, 13); } else { sprite_delay_main[k] = 127; sprite_ai_state[k] = 12; } } else if (sprite_delay_main[k] & 1) { sprite_graphics[k] = 255; } break; case 15: { // static const uint8 kGanon_Gfx15[2] = { 6, 14 }; if (sprite_delay_main[k]) { if (sprite_delay_main[k] == 1) { sprite_ai_state[k] = 16; sprite_z_vel[k] = 160; return; } } else { Sprite_MoveZ(k); if (--sprite_z_vel[k] == 0) sprite_delay_main[k] = 32; } sprite_graphics[k] = kGanon_Gfx15[sprite_D[k]]; break; } case 16: { // bg1_y_offset = 0; if (sprite_delay_main[k]) { if (sprite_delay_main[k] == 1) { sound_effect_ambient = 5; Ganon_SelectWarpLocation(k, 13); flag_is_link_immobilized = 0; Ganon_SpawnFallingTilesOverlord(k); if (sprite_anim_clock[k] >= 4) { Ganon_SelectWarpLocation(k, 10); sprite_health[k] = 96; sprite_delay_aux2[k] = 224; dialogue_message_index = 0x170; Sprite_ShowMessageMinimal(); } } else { bg1_y_offset = (sprite_delay_main[k] - 1) & 1 ? -1 : 1; flag_is_link_immobilized = 1; } } else { static const uint8 kGanon_Gfx16[2] = { 2, 10 }; Sprite_MoveZ(k); if (sign8(sprite_z[k])) { sprite_z_vel[k] = 0; sprite_z[k] = 0; sprite_delay_main[k] = 96; sound_effect_ambient = 7; SpriteSfx_QueueSfx2WithPan(k, 0xc); } sprite_graphics[k] = kGanon_Gfx16[sprite_D[k]]; } break; } case 17: { // static const uint8 kGanon_Gfx17b[2] = { 6, 14 }; static const uint8 kGanon_Gfx17[2] = { 7, 10 }; sprite_graphics[k] = kGanon_Gfx17b[sprite_D[k]]; if (!sprite_delay_main[k]) { Ganon_SelectWarpLocation(k, 0x12); return; } else if (sprite_delay_main[k] == 52) { Ganon_Func1(k, 5); } else if (sprite_delay_main[k] < 52) { sprite_graphics[k] = kGanon_Gfx17[sprite_D[k]]; } if (sprite_delay_main[k] >= 72 || sprite_delay_main[k] < 40) { sprite_ignore_projectile[k]++; if (sprite_delay_main[k] & 1) sprite_graphics[k] = 0xff; } Ganon_EnableInvincibility(k); break; } case 19: // sprite_oam_flags[k] = 5; sprite_flags[k] = 2; if (!sprite_delay_main[k]) { sprite_oam_flags[k] = 1; Ganon_SelectWarpLocation(k, 18); sprite_type[k] = 0xd6; sprite_hit_timer[k] = 0; } else { static const uint8 kGanon_Gfx19[2] = { 5, 13 }; sprite_graphics[k] = kGanon_Gfx19[sprite_D[k]]; } break; } } void Ganon_EnableInvincibility(int k) { // 9d8ffa if ((sprite_hit_timer[k] & 127) == 26) { sprite_hit_timer[k] = 0; sprite_ai_state[k] = 19; sprite_delay_main[k] = 127; sprite_type[k] = 215; } } void Ganon_SpawnFallingTilesOverlord(int k) { // 9d90d0 static const uint8 kGanon_Ov_Type[4] = { 12, 13, 14, 15 }; static const uint8 kGanon_Ov_X[4] = { 0x18, 0xd8, 0xd8, 0x18 }; static const uint8 kGanon_Ov_Y[4] = { 0x28, 0x28, 0xd8, 0xd8 }; int j; for (j = 7; j >= 0 && overlord_type[j] != 0; j--); int t = sprite_anim_clock[k]; if (t >= 4) return; sprite_anim_clock[k] = t + 1; overlord_type[j] = kGanon_Ov_Type[t]; overlord_x_lo[j] = kGanon_Ov_X[t]; overlord_x_hi[j] = link_x_coord >> 8; overlord_y_lo[j] = kGanon_Ov_Y[t]; overlord_y_hi[j] = link_y_coord >> 8; overlord_gen1[j] = 0; overlord_gen2[j] = 0; } void Ganon_Func1(int k, int t) { // 9d9162 tmp_counter = t; SpriteSpawnInfo info; int j = Sprite_SpawnDynamicallyEx(k, 0xC9, &info, 8); if (j < 0) return; SpriteSfx_QueueSfx2WithPan(k, 0x2a); Sprite_SetSpawnedCoordinates(j, &info); sprite_ignore_projectile[j] = sprite_anim_clock[j] = t; sprite_oam_flags[j] = 3; sprite_flags3[j] = 0x40; sprite_flags2[j] = 0x21; sprite_defl_bits[j] = 0x40; static const int8 kGanon_Gfx16_Y[2] = { 0, -16 }; Sprite_SetY(j, info.r2_y + kGanon_Gfx16_Y[sprite_D[k]]); Sprite_ApplySpeedTowardsLink(j, 32); sprite_delay_main[j] = 16; sprite_A[j] = sprite_x_lo[0]; sprite_B[j] = sprite_x_hi[0]; sprite_C[j] = sprite_y_lo[0]; sprite_E[j] = sprite_y_hi[0]; sprite_bump_damage[j] = 7; sprite_ignore_projectile[j] = 7; } void Ganon_Phase1_AnimateTridentSpin(int k) { // 9d93db static const uint8 kGanon_GfxFunc2[16] = { 0, 0, 1, 1, 0, 0, 1, 1, 8, 8, 9, 9, 8, 8, 9, 9 }; int j = (sprite_delay_main[k] >> 2 & 7) + (sprite_D[k] ? 8 : 0); sprite_G[k] = kGanon_G_Func2[j]; sprite_graphics[k] = kGanon_GfxFunc2[j]; SwishEvery16Frames(k); } void Ganon_HandleAnimation_Idle(int k) { // 9d9443 static const uint8 kGanon_G[2] = { 9, 10 }; static const uint8 kGanon_Gfx[2] = { 2, 10 }; sprite_G[k] = kGanon_G[sprite_D[k]]; sprite_graphics[k] = kGanon_Gfx[sprite_D[k]]; } void Ganon_SelectWarpLocation(int k, int a) { // 9d947f int j; static const uint8 kGanon_NextSubtype[32] = { 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, }; static const uint8 kGanon_NextY[8] = { 0x40, 0x30, 0x30, 0x40, 0xb0, 0xc0, 0xc0, 0xb0 }; static const uint8 kGanon_NextX[8] = { 0x30, 0x50, 0xa0, 0xc0, 0x40, 0x60, 0x90, 0xb0 }; sprite_subtype[k] = j = kGanon_NextSubtype[GetRandomNumber() & 3 | sprite_subtype[k] << 2]; swamola_target_x_lo[0] = kGanon_NextX[j]; swamola_target_y_lo[0] = kGanon_NextY[j]; sprite_ai_state[k] = a; sprite_x_vel[k] = sprite_y_vel[k] = 0; sprite_delay_main[k] = 48; SpriteSfx_QueueSfx3WithPan(k, 0x28); } void Ganon_ShakeHead(int k) { // 9d94ba static const uint8 kGanon_HeadDir[18] = { 0, 0, 0, 1, 2, 2, 2, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 16, }; sprite_head_dir[k] = kGanon_HeadDir[sprite_delay_main[k] >> 3]; } void Ganon_Draw(int k) { // 9d9adf PrepOamCoordsRet info; if (sign8(sprite_graphics[k]) || sprite_ai_state[k] != 19 && sprite_delay_aux4[k] == 0 && byte_7E04C5 == 0) { Sprite_PrepOamCoordOrDoubleRet(k, &info); return; } Trident_Draw(k); if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr() + 5; int g = sprite_graphics[k]; for (int i = 0; i < 12; i++, oam++) { int j = g * 12 + i; oam->x = info.x + kGanon_Draw_X[j]; oam->y = info.y + kGanon_Draw_Y[j]; oam->charnum = kGanon_Draw_Char[j]; oam->flags = info.flags | (kGanon_Draw_Flags[j] & ((info.flags & 0xf) >= 5 ? 0xf0 : 0xff)); bytewise_extended_oam[oam - oam_buf] = 2; } static const uint8 kGanon_SprOffs[17] = { 1, 1, 1, 1, 1, 1, 15, 1, 4, 4, 4, 4, 4, 4, 4, 15, 15, }; if (kGanon_SprOffs[g] != 15) { oam = oam - 12 + kGanon_SprOffs[g]; int j = sprite_head_dir[k] * 2 + (sprite_D[k] ? 6 : 0); oam[0].charnum = kGanon_Draw_Char2[j]; oam[0].flags = (oam[0].flags & 0x3f) | kGanon_Draw_Flags2[j]; oam[1].charnum = kGanon_Draw_Char2[j + 1]; oam[1].flags = (oam[1].flags & 0x3f) | kGanon_Draw_Flags2[j + 1]; } if (submodule_index) Sprite_CorrectOamEntries(k, 9, 0xff); if (sprite_G[k] == 9) { static const DrawMultipleData kGanon_Dmd[2] = { {16, -3, 0x4c0a, 2}, {16, 5, 0x4c1a, 2}, }; oam_cur_ptr = 0x828, oam_ext_cur_ptr = 0xa2a; Sprite_DrawMultiple(k, kGanon_Dmd, 2, NULL); } uint16 z = sprite_z[k] - 1; int frame = (z >> 11) > 4 ? 4 : (z >> 11); cur_sprite_y += z; oam_cur_ptr = 0x9f4; oam_ext_cur_ptr = 0xa9d; uint8 bak = sprite_oam_flags[k]; sprite_oam_flags[k] = 0; sprite_obj_prio[k] = 48; Sprite_DrawMultiple(k, &kLargeShadow_Dmd[frame * 3], 3, NULL); sprite_oam_flags[k] = bak; Sprite_Get16BitCoords(k); } void Trident_Draw(int k) { // 9d9c1c static const DrawMultipleData kTrident_Dmd[50] = { { 10, -10, 0x0864, 0}, { 5, -15, 0x0864, 0}, { 0, -20, 0x0864, 0}, { -5, -25, 0x0864, 0}, {-18, -38, 0x0844, 2}, { 1, -4, 0x0865, 0}, { 1, -11, 0x0865, 0}, { 1, -18, 0x0865, 0}, { 1, -25, 0x0865, 0}, { -3, -40, 0x0862, 2}, { -8, -9, 0x4864, 0}, { -3, -14, 0x4864, 0}, { 3, -20, 0x4864, 0}, { 9, -26, 0x4864, 0}, { 12, -37, 0x4844, 2}, {-10, -20, 0x4874, 0}, { -3, -20, 0x4874, 0}, { 4, -20, 0x4874, 0}, { 11, -20, 0x4874, 0}, { 18, -23, 0x4860, 2}, {-10, -30, 0xc864, 0}, { -4, -24, 0xc864, 0}, { 2, -18, 0xc864, 0}, { 8, -12, 0xc864, 0}, { 12, -8, 0xc844, 2}, { 1, -32, 0x8865, 0}, { 1, -25, 0x8865, 0}, { 1, -18, 0x8865, 0}, { 1, -11, 0x8865, 0}, { -3, -5, 0x8862, 2}, { 13, -30, 0x8864, 0}, { 8, -25, 0x8864, 0}, { 2, -19, 0x8864, 0}, { -4, -13, 0x8864, 0}, {-16, -9, 0x8844, 2}, { 14, -20, 0x0874, 0}, { 7, -20, 0x0874, 0}, { 0, -20, 0x0874, 0}, { -7, -20, 0x0874, 0}, {-21, -23, 0x0860, 2}, { 13, -30, 0x8864, 0}, { 8, -25, 0x8864, 0}, { 2, -19, 0x8864, 0}, { -4, -13, 0x8864, 0}, {-16, -9, 0x8844, 2}, {-10, -30, 0xc864, 0}, { -4, -24, 0xc864, 0}, { -4, -24, 0xc864, 0}, { -4, -24, 0xc864, 0}, { -4, -24, 0xc864, 0}, }; int g = sprite_G[k]; if (g == 0) return; static const int8 kTrident_Draw_X[5] = { 24, -16, 0, 16, -8 }; static const int8 kTrident_Draw_Y[5] = { 4, 4, 16, 21, 19 }; int j = sprite_G[k] == 9 ? 3 : sprite_G[k] >= 9 ? 4 : sprite_D[k]; cur_sprite_x += kTrident_Draw_X[j]; cur_sprite_y += kTrident_Draw_Y[j]; uint8 bak = sprite_obj_prio[k]; sprite_obj_prio[k] &= ~0xf; Sprite_DrawMultiple(k, &kTrident_Dmd[(g - 1) * 5], 5, NULL); sprite_obj_prio[k] = bak; Sprite_Get16BitCoords(k); } void SpritePrep_Swamola_InitializeSegments(int k) { // 9d9c80 static const uint8 kBuggySwamolaLookup[6] = { 0x1c, 0xa9, 0x03, 0x9d, 0x90, 0x0d }; // wrong bank //int j = k * 32; int j = kBuggySwamolaLookup[k]; for (int i = 0; i < 32; i++, j++) { swamola_x_lo[j] = sprite_x_lo[k]; swamola_x_hi[j] = sprite_x_hi[k]; swamola_y_lo[j] = sprite_y_lo[k]; swamola_y_hi[j] = sprite_y_hi[k]; } } void Sprite_CF_Swamola(int k) { // 9d9cb0 static const uint8 kSwamola_Target_Dir[8] = {1, 2, 3, 4, 5, 6, 7, 8}; static const int8 kSwamola_Target_X[9] = {0, 0, 32, 32, 32, 0, -32, -32, -32}; static const int8 kSwamola_Target_Y[9] = {0, -32, -32, 0, 32, 32, 32, 0, -32}; int j; if (sprite_ai_state[k]) { if (sign8(sprite_ai_state[k])) { Sprite_Swamola_Ripples(k); return; } Swamola_Draw(k); } Sprite_Get16BitCoords(k); if (Sprite_ReturnIfInactive(k)) return; sprite_subtype2[k]++; Sprite_CheckDamageToAndFromLink(k); uint8 old_vel = sprite_y_vel[k]; sprite_y_vel[k] += sprite_z_vel[k]; Sprite_MoveXY(k); sprite_y_vel[k] = old_vel; switch(sprite_ai_state[k]) { case 0: { // emerge if (!sprite_delay_main[k] && (j = kSwamola_Target_Dir[GetRandomNumber() & 7]) != sprite_D[k]) { int t = (sprite_B[k] << 8 | sprite_A[k]) + kSwamola_Target_X[j]; swamola_target_x_lo[k] = t, swamola_target_x_hi[k] = t >> 8; t = (sprite_head_dir[k] << 8 | sprite_C[k]) + kSwamola_Target_Y[j]; swamola_target_y_lo[k] = t, swamola_target_y_hi[k] = t >> 8; sprite_ai_state[k] = 1; sprite_x_vel[k] = sprite_y_vel[k] = 0; sprite_z_vel[k] = -15; Swamola_SpawnRipples(k); } break; } case 1: // ascending if (!(sprite_subtype2[k] & 3)) { if (!++sprite_z_vel[k]) sprite_ai_state[k] = 2; ProjectSpeedRet pt = Swamola_ProjectVelocityTowardsTarget(k); Sprite_ApproachTargetSpeed(k, pt.x, pt.y); } break; case 2: { // wiggle static const int8 kSwamola_Z_Accel[2] = {2, -2}; static const int8 kSwamola_Z_Vel_Target[2] = {12, -12}; int j = sprite_G[k] & 1; sprite_z_vel[k] += kSwamola_Z_Accel[j]; if (sprite_z_vel[k] == (uint8)kSwamola_Z_Vel_Target[j]) sprite_G[k]++; uint16 x = swamola_target_x_hi[k] << 8 | swamola_target_x_lo[k]; uint16 y = swamola_target_y_hi[k] << 8 | swamola_target_y_lo[k]; if ((uint16)(cur_sprite_x - x + 8) < 16 && (uint16)(cur_sprite_y - y + 8) < 16) sprite_ai_state[k] = 3; ProjectSpeedRet pt = Swamola_ProjectVelocityTowardsTarget(k); sprite_x_vel[k] = pt.x; sprite_y_vel[k] = pt.y; break; } case 3: // descending if (!(sprite_subtype2[k] & 3) && ++sprite_z_vel[k] == 16) { sprite_ai_state[k] = 4; Swamola_SpawnRipples(k); sprite_y_hi[k] = 128; sprite_delay_main[k] = 80; } if (!(sprite_subtype2[k] & 3)) Sprite_ApproachTargetSpeed(k, 0, 0); break; case 4: // submerge if (!sprite_delay_main[k]) { sprite_D[k] = j = kSwamola_Target_Dir[GetRandomNumber() & 7]; Sprite_SetX(k, (sprite_B[k] << 8 | sprite_A[k]) + kSwamola_Target_X[j]); Sprite_SetY(k, (sprite_head_dir[k] << 8 | sprite_C[k]) + kSwamola_Target_Y[j]); sprite_ai_state[k] = 0; sprite_delay_main[k] = 48; sprite_x_vel[k] = sprite_y_vel[k] = 0; sprite_z_vel[k] = 0; } break; } } ProjectSpeedRet Swamola_ProjectVelocityTowardsTarget(int k) { // 9d9e13 uint16 x = swamola_target_x_hi[k] << 8 | swamola_target_x_lo[k]; uint16 y = swamola_target_y_hi[k] << 8 | swamola_target_y_lo[k]; return Sprite_ProjectSpeedTowardsLocation(k, x, y, 15); } void Swamola_SpawnRipples(int k) { // 9d9eaa SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xcf, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_ai_state[j] = 128; sprite_delay_main[j] = 32; sprite_oam_flags[j] = 4; sprite_ignore_projectile[j] = 4; sprite_flags2[j] = 0; } } void Sprite_Swamola_Ripples(int k) { // 9d9ece SwamolaRipples_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (!sprite_delay_main[k]) sprite_state[k] = 0; } void SwamolaRipples_Draw(int k) { // 9d9f1d static const DrawMultipleData kSwamolaRipples_Dmd[8] = { {0, 4, 0x00d8, 0}, {8, 4, 0x40d8, 0}, {0, 4, 0x00d9, 0}, {8, 4, 0x40d9, 0}, {0, 4, 0x00da, 0}, {8, 4, 0x40da, 0}, {0, 4, 0x00d9, 0}, {8, 4, 0x40d9, 0}, }; Oam_AllocateFromRegionB(8); Sprite_DrawMultiple(k, &kSwamolaRipples_Dmd[(sprite_delay_main[k] >> 2 & 3) * 2], 2, NULL); } void Swamola_Draw(int k) { // 9d9f64 static const uint8 kSwamola_Gfx[16] = {7, 6, 5, 4, 3, 4, 5, 6, 7, 6, 5, 4, 3, 4, 5, 6}; static const uint8 kSwamola_Gfx2[4] = {0, 0, 1, 2}; static const uint8 kSwamola_Draw_OamFlags[16] = {0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40}; static const uint8 kSwamola_HistOffs[4] = {8, 16, 22, 26}; int j = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k] + sprite_z_vel[k]); sprite_graphics[k] = kSwamola_Gfx[j]; sprite_oam_flags[k] = sprite_oam_flags[k] & 63 | kSwamola_Draw_OamFlags[j]; SpriteDraw_SingleLarge(k); j = (sprite_subtype2[k] & 0x1f) + k * 32; swamola_x_lo[j] = sprite_x_lo[k]; swamola_x_hi[j] = sprite_x_hi[k]; swamola_y_lo[j] = sprite_y_lo[k]; swamola_y_hi[j] = sprite_y_hi[k]; j = sign8(sprite_y_vel[k]) ? 5 : 0; int delta = sign8(sprite_y_vel[k]) ? -1 : 1; oam_cur_ptr += j * 4, oam_ext_cur_ptr += j; for (int i = 0; i < 4; i++) { sprite_graphics[k] = kSwamola_Gfx2[i]; j = (sprite_subtype2[k] - kSwamola_HistOffs[i] & 31) + k * 32; cur_sprite_x = swamola_x_hi[j] << 8 | swamola_x_lo[j]; cur_sprite_y = swamola_y_hi[j] << 8 | swamola_y_lo[j]; oam_cur_ptr += delta * 4, oam_ext_cur_ptr += delta; SpriteDraw_SingleLarge(k); } byte_7E0FB6 = 4; } void SpritePrep_Blind_PrepareBattle(int k) { // 9da081 if (savegame_tagalong != 6 && dung_savegame_state_bits & 0x2000) { sprite_delay_aux2[k] = 96; sprite_C[k] = 1; sprite_D[k] = 2; sprite_head_dir[k] = 4; sprite_graphics[k] = 7; byte_7E0B69 = 0; } else { sprite_state[k] = 0; } } void BlindLaser_SpawnTrailGarnish(int j) { // 9da0b1 int k = GarnishAllocOverwriteOld(); garnish_type[k] = 15; garnish_active = 15; garnish_oam_flags[k] = sprite_graphics[j]; garnish_sprite[k] = j; garnish_x_lo[k] = sprite_x_lo[j]; garnish_x_hi[k] = sprite_x_hi[j]; uint16 y = Sprite_GetY(j) + 16; garnish_y_lo[k] = y; garnish_y_hi[k] = y >> 8; garnish_countdown[k] = 10; } void Sprite_Blind_Head(int k) { // 9da118 static const uint8 kBlindHead_XposLimit[2] = {0x98, 0x58}; static const uint8 kBlindHead_YposLimit[2] = {0xb0, 0x50}; static const int8 kBlindHead_YvelLimit[2] = {24, -24}; static const int8 kBlindHead_XvelLimit[2] = {32, -32}; sprite_obj_prio[k] |= 48; SpriteDraw_SingleLarge(k); OamEnt *oam = GetOamCurPtr(); int j = sprite_head_dir[k]; oam->charnum = kBlindHead_Draw_Char[j]; oam->flags = oam->flags & 0x3f | kBlindHead_Draw_Flags[j]; if (Sprite_ReturnIfInactive(k)) return; if (sprite_F[k] == 14) sprite_F[k] = 8; if (Sprite_ReturnIfRecoiling(k)) return; if (sign8(--sprite_subtype[k])) { sprite_subtype[k] = 2; sprite_head_dir[k] = sprite_head_dir[k] + 1 & 15; } if (sprite_delay_main[k]) return; Sprite_CheckDamageToAndFromLink(k); sprite_subtype2[k]++; j = Blind_SpitFireball(k, 0x1f); if (j >= 0 && sign8(--sprite_z_subpos[k])) { sprite_z_subpos[k] = 4; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32); sprite_x_vel[j] = pt.x; sprite_y_vel[j] = pt.y; } j = sprite_G[k] & 1; if (sprite_x_vel[k] != (uint8)kBlindHead_XvelLimit[j]) sprite_x_vel[k] += j ? -1 : 1; if ((sprite_x_lo[k] & ~1) == kBlindHead_XposLimit[j]) sprite_G[k]++; j = sprite_anim_clock[k] & 1; if (sprite_y_vel[k] != (uint8)kBlindHead_YvelLimit[j]) sprite_y_vel[k] += j ? -1 : 1; if ((sprite_y_lo[k] & ~1) == kBlindHead_YposLimit[j]) sprite_anim_clock[k]++; if (!sprite_F[k]) Sprite_MoveXY(k); } void Blind_SpawnHead(int k) { // 9da1ed SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xce, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_flags3[j] = 0x5b; sprite_oam_flags[j] = 0x5b & 15; sprite_defl_bits[j] = 4; sprite_A[j] = 2; sprite_flags2[j] = 1; sprite_flags4[j] = 0; sprite_flags[j] = 0; sprite_z[j] = 23; sprite_y_lo[j] = 23 + info.r2_y; sprite_G[j] = (info.r0_x >> 7) & 1; sprite_anim_clock[j] = (info.r2_y >> 7) & 1; sprite_delay_main[j] = 48; } } void Sprite_CE_Blind(int k) { // 9da263 if (sign8(sprite_A[k])) Sprite_BlindLaser(k); else if (sprite_A[k] == 2) Sprite_Blind_Head(k); else Sprite_Blind_Blind_Blind(k); } void Sprite_BlindLaser(int k) { // 9da268 static const uint8 kBlindLaser_Gfx[16] = {7, 7, 8, 9, 10, 9, 8, 7, 7, 7, 8, 9, 10, 9, 8, 7}; static const uint8 kBlindLaser_OamFlags[16] = {0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80}; int j = sprite_head_dir[k]; sprite_graphics[k] = kBlindLaser_Gfx[j]; sprite_oam_flags[k] = kBlindLaser_OamFlags[j] | 3; PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; if (sprite_delay_main[k]) { if (sprite_delay_main[k] == 1) sprite_state[k] = 0; return; } Sprite_CheckDamageToLink_same_layer(k); Sprite_SetX(k, Sprite_GetX(k) + (int8)sprite_x_vel[k]); Sprite_SetY(k, Sprite_GetY(k) + (int8)sprite_y_vel[k]); if (Sprite_CheckTileCollision(k)) sprite_delay_main[k] = 12; BlindLaser_SpawnTrailGarnish(k); } void Sprite_Blind_Blind_Blind(int k) { // 9da2d2 int j; sprite_obj_prio[k] |= 0x30; Blind_Draw(k); sprite_oam_flags[k] = 1; if (Sprite_ReturnIfInactive(k)) return; uint8 a = sprite_F[k]; if (a) sprite_F[k]--; if (a == 11) { sprite_hit_timer[k] = 0; sprite_wallcoll[k] = 0; if (!sprite_delay_aux4[k]) { sprite_health[k] = 128; sprite_delay_aux4[k] = 48; sprite_oam_flags[k] &= 1; if (++sprite_z_subpos[k] < 3) { sprite_wallcoll[k] = 96; sprite_subtype[k] = 1; } else { sprite_z_subpos[k] = 0; if (++sprite_limit_instance == 3) { Sprite_KillFriends(); sprite_state[k] = 4; sprite_A[k] = 0; sprite_delay_main[k] = 255; sprite_hit_timer[k] = 255; flag_block_link_menu++; SpriteSfx_QueueSfx3WithPan(k, 0x22); return; } sprite_y_vel[k] = sprite_x_vel[k] = 0; sprite_C[k] = 6; sprite_delay_aux2[k] = 255; sprite_ignore_projectile[k] = 255; Blind_SpawnHead(k); } } } if (sprite_A[k]) { static const uint8 kBlind_Gfx0[7] = {20, 19, 18, 17, 16, 15, 15}; if (!sprite_delay_main[k]) sprite_state[k] = 0; sprite_graphics[k] = kBlind_Gfx0[sprite_delay_main[k] >> 3]; return; } if (!(++sprite_subtype2[k] & 1)) sprite_delay_main[k]++; if (sprite_delay_aux1[k]) { sprite_ai_state[k] = 0; if (sprite_delay_aux1[k] == 8) Blind_SpawnLaser(k); Blind_CheckBumpDamage(k); return; } byte_7E0B69++; if (!sprite_stunned[k]) { if (sprite_ai_state[k]) { sprite_delay_aux1[k] = 16; sprite_stunned[k] = 128; sprite_ai_state[k] = 0; } } else { sprite_stunned[k]--; sprite_ai_state[k] = 0; } sprite_x_hi[k] = HIBYTE(link_x_coord); sprite_y_hi[k] = HIBYTE(link_y_coord); switch(sprite_C[k]) { case 0: // blinded BYTE(dma_var6) = 0; BYTE(dma_var7) = 0xA0; if (sprite_delay_aux2[k] == 0) { sprite_C[k]++; sprite_delay_aux2[k] = 96; } else if (sprite_delay_aux2[k] == 80) { dialogue_message_index = 0x123; Sprite_ShowMessageMinimal(); } else if (sprite_delay_aux2[k] == 24) { SpawnBossPoof(k); } break; case 1: // retreat to back wall Blind_CheckBumpDamage(k); sprite_graphics[k] = 9; if (sprite_delay_aux2[k] == 0) { sprite_C[k]++; sprite_delay_main[k] = 255; sprite_ignore_projectile[k] = 0; } else if (sprite_delay_aux2[k] < 64) { sprite_y_vel[k] = -8; Sprite_MoveY(k); } Blind_Animate(k); sprite_head_dir[k] = 4; break; case 2: { // oscillate static const int8 kBlind_Oscillate_YVelTarget[2] = {18, -18}; static const int8 kBlind_Oscillate_XVelTarget[2] = {24, -24}; static const uint8 kBlind_Oscillate_XPosTarget[2] = {164, 76}; Blind_CheckBumpDamage(k); Blind_Animate(k); if ((!(sprite_subtype2[k] & 127) && Sprite_IsBelowLink(k).a + 2 != sprite_D[k] || sprite_delay_main[k] == 0) && sprite_x_lo[k] < 0x78) { sprite_C[k]++; sprite_y_vel[k] &= ~1; sprite_x_vel[k] &= ~1; sprite_delay_aux2[k] = 0x30; return; } j = sprite_B[k] & 1; sprite_y_vel[k] += j ? -1 : 1; if (sprite_y_vel[k] == (uint8)kBlind_Oscillate_YVelTarget[j]) sprite_B[k]++; j = sprite_G[k] & 1; if (sprite_x_vel[k] != (uint8)kBlind_Oscillate_XVelTarget[j]) sprite_x_vel[k] += j ? -1 : 1; if ((sprite_x_lo[k] & ~1) == kBlind_Oscillate_XPosTarget[j]) sprite_G[k]++; Sprite_MoveXY(k); if (sprite_wallcoll[k]) { Blind_FireballFlurry(k, sprite_wallcoll[k]); } else if (!(sprite_subtype2[k] & 7)) { Sprite_SpawnProbeAlways(k, sprite_head_dir[k] << 2); } break; } case 3: // switch walls Blind_CheckBumpDamage(k); if (sprite_delay_aux2[k]) { Blind_Decelerate_X(k); Sprite_MoveX(k); Blind_Decelerate_Y(k); } else { static const int8 kBlind_SwitchWall_YVelTarget[2] = {64, -64}; static const uint8 kBlind_SwitchWall_YPosTarget[2] = {0x90, 0x50}; j = sprite_D[k] - 2; if (sprite_y_vel[k] != (uint8)kBlind_SwitchWall_YVelTarget[j]) sprite_y_vel[k] += j ? -2 : 2; if ((sprite_y_lo[k] & ~3) == kBlind_SwitchWall_YPosTarget[j]) { sprite_C[k]++; sprite_B[k] = sprite_D[k] - 1; } Sprite_MoveXY(k); Blind_Decelerate_X(k); } break; case 4: { // whirl around Blind_CheckBumpDamage(k); if (!(sprite_subtype2[k] & 7)) { static const uint8 kBlind_WhirlAround_Gfx[2] = {0, 9}; j = sprite_D[k] - 2; if (sprite_graphics[k] == kBlind_WhirlAround_Gfx[j]) { sprite_delay_main[k] = 254; sprite_C[k] = 2; sprite_D[k] ^= 1; sprite_G[k] = sprite_x_lo[k] >> 7; } else { sprite_graphics[k] += j ? 1 : -1; } } Blind_Decelerate_Y(k); break; } case 5: // fireball reprisal Blind_FireballFlurry(k, 0x65); // wtf: argument break; case 6: // behind the curtain sprite_hit_timer[k] = 0; sprite_head_dir[k] = 12; if (sprite_delay_aux2[k] == 0) { sprite_C[k]++; sprite_delay_aux2[k] = 39; SpriteSfx_QueueSfx1WithPan(k, 0x13); } else if (sprite_delay_aux2[k] >= 224) { static const uint8 kBlind_Gfx_BehindCurtain[4] = {14, 13, 12, 10}; sprite_graphics[k] = kBlind_Gfx_BehindCurtain[(sprite_delay_aux2[k] - 224) >> 3]; } else { sprite_graphics[k] = 14; } break; case 7: // rerobe if (sprite_delay_aux2[k] == 0) { sprite_C[k] = 2; sprite_delay_main[k] = 128; sprite_D[k] = (sprite_y_lo[k] >> 7) + 2; sprite_G[k] = (sprite_x_lo[k] << 2) | (sprite_x_lo[k] >> 7); sprite_x_vel[k] = sprite_y_vel[k] = 0; sprite_ignore_projectile[k] = 0; } else { static const uint8 kBlind_Gfx_Rerobe[5] = {10, 11, 12, 13, 14}; sprite_graphics[k] = kBlind_Gfx_Rerobe[sprite_delay_aux2[k] >> 3]; } break; } } void Blind_FireballFlurry(int k, uint8 a) { // 9da465 sprite_wallcoll[k]--; sprite_oam_flags[k] = (a & 7) * 2 + 1; if (sign8(--sprite_E[k])) { sprite_E[k] = sprite_subtype[k]; sprite_head_dir[k] = sprite_head_dir[k] + 1 & 15; } if (!(sprite_subtype2[k] & 31) && sprite_subtype[k] != 5) sprite_subtype[k]++; Blind_AnimateRobes(k); Blind_SpitFireball(k, 0xf); } int Blind_SpitFireball(int k, uint8 a) { // 9da49d static const int8 kBlindHead_SpawnFireball_Xvel[16] = {-32, -28, -24, -16, 0, 16, 24, 28, 32, 28, 24, 16, 0, -16, -24, -28}; static const int8 kBlindHead_SpawnFireball_Yvel[16] = {0, 16, 24, 28, 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16}; if (sprite_subtype2[k] & a) return -1; int j = Sprite_SpawnFireball(k); if (j >= 0) { SpriteSfx_QueueSfx3WithPan(k, 0x19); int i = sprite_head_dir[k]; sprite_x_vel[j] = kBlindHead_SpawnFireball_Xvel[i]; sprite_y_vel[j] = kBlindHead_SpawnFireball_Yvel[i]; sprite_defl_bits[j] |= 8; sprite_bump_damage[j] = 4; } return j; } int SpawnBossPoof(int k) { // 9da4f9 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xce, &info); Sprite_SetX(j, info.r0_x + 16); Sprite_SetY(j, info.r2_y + 40); sprite_graphics[j] = 0xf; sprite_A[j] = 1; sprite_delay_main[j] = 47; sprite_flags2[j] = 9; sprite_ignore_projectile[j] = 9; sound_effect_1 = 12; return j; } void Blind_Decelerate_X(int k) { // 9da647 if (sprite_x_vel[k] != 0) sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? 2 : -2; Blind_AnimateRobes(k); if (sprite_wallcoll[k]) Blind_FireballFlurry(k, sprite_wallcoll[k]); } void Blind_Decelerate_Y(int k) { // 9da6a4 if (sprite_y_vel[k] != 0) sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? 4 : -4; Sprite_MoveY(k); if (sprite_wallcoll[k]) Blind_FireballFlurry(k, sprite_wallcoll[k]); } void Blind_CheckBumpDamage(int k) { // 9da6c0 if (!(sprite_delay_aux4[k] | sprite_F[k])) Sprite_CheckDamageToAndFromLink(k); if ((uint16)(link_x_coord - cur_sprite_x + 14) < 28 && (uint16)(link_y_coord - cur_sprite_y) < 28 && !(countdown_for_blink | link_disable_sprite_damage)) { link_auxiliary_state = 1; link_give_damage = 8; link_incapacitated_timer = 16; link_actual_vel_x ^= 255; link_actual_vel_y ^= 255; } } void Blind_Animate(int k) { // 9da6ef static const uint8 kBlind_HeadDir[17] = {0, 1, 2, 3, 4, 3, 2, 1, 0, 15, 14, 13, 12, 13, 14, 15, 0}; static const uint8 kBlind_Animate_Tab[8] = {0, 1, 1, 2, 2, 3, 3, 4}; if (!sprite_wallcoll[k]) { int t1 = kBlind_Animate_Tab[BYTE(link_x_coord) >> 5]; t1 = (sprite_D[k] == 3) ? -t1 : t1; int t0 = (sprite_D[k] - 2) * 8; int idx = (byte_7E0B69 >> 3 & 7) + (byte_7E0B69 >> 2 & 1) + t0; sprite_head_dir[k] = (kBlind_HeadDir[idx] + t1) & 15; } Blind_AnimateRobes(k); } void Blind_AnimateRobes(int k) { // 9da729 static const uint8 kBlind_Gfx_Animate[8] = {7, 8, 9, 8, 0, 1, 2, 1}; sprite_graphics[k] = kBlind_Gfx_Animate[(sprite_subtype2[k] >> 3 & 3) + ((sprite_D[k] - 2) << 2)]; } void Blind_SpawnLaser(int k) { // 9da765 static const int8 kBlind_Laser_Xvel[16] = {-8, -8, -8, -4, 0, 4, 8, 8, 8, 8, 8, 4, 0, -4, -8, -8}; static const int8 kBlind_Laser_Yvel[16] = {0, 0, 4, 8, 8, 8, 4, 0, 0, 0, -4, -8, -8, -8, -4, 0}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xce, &info), i; if (j >= 0) { sound_effect_2 = Sprite_CalculateSfxPan(k) | 0x26; Sprite_SetSpawnedCoordinates(j, &info); sprite_x_lo[j] = info.r0_x + 4; sprite_head_dir[j] = i = sprite_head_dir[k]; sprite_x_vel[j] = kBlind_Laser_Xvel[i]; sprite_y_vel[j] = kBlind_Laser_Yvel[i]; sprite_A[j] = 128; sprite_ignore_projectile[j] = 128; sprite_flags2[j] = 0x40; sprite_flags4[j] = 0x14; } } void Blind_Draw(int k) { // 9dac6c if (sprite_graphics[k] >= 15) { static const DrawMultipleData kBlindPoof_Dmd[37] = { {-16, -20, 0x0586, 2}, {-11, -28, 0x0586, 2}, {-23, -26, 0x0586, 2}, { -8, -17, 0x0586, 2}, {-20, -13, 0x0586, 2}, {-16, -37, 0x0586, 2}, {-27, -31, 0x0586, 2}, {-10, -28, 0x0586, 2}, { -5, -28, 0x0586, 2}, {-20, -27, 0x0586, 2}, {-27, -17, 0x0586, 2}, { -4, -17, 0x0586, 2}, {-16, -13, 0x0586, 2}, {-18, -37, 0x458a, 2}, { -5, -33, 0x458a, 2}, {-32, -32, 0x058a, 2}, {-23, -31, 0x458a, 2}, {-15, -24, 0x458a, 2}, {-23, -31, 0x458a, 2}, {-15, -24, 0x458a, 2}, {-29, -22, 0x058a, 2}, { -5, -22, 0x058a, 2}, {-16, -14, 0x058a, 2}, {-12, -32, 0x458a, 2}, {-26, -29, 0x458a, 2}, { -6, -22, 0x458a, 2}, {-19, -20, 0x058a, 2}, {-26, -29, 0x458a, 2}, { -6, -22, 0x458a, 2}, {-19, -20, 0x058a, 2}, {-17, -27, 0x059b, 0}, {-10, -26, 0x059b, 0}, { 0, -22, 0x459b, 0}, {-19, -16, 0x459b, 0}, { -6, -12, 0x059b, 0}, { 0, 13, 0x0b20, 2}, { 0, 23, 0x0b22, 2}, }; static const uint8 kOffs[] = { 0, 1, 5, 13, 23, 30, 35, 37 }; int j = sprite_graphics[k] - 15; Sprite_DrawMultiple(k, &kBlindPoof_Dmd[kOffs[j]], kOffs[j + 1] - kOffs[j], NULL); return; } static const DrawMultipleData kBlind_Dmd[105] = { { -8, 7, 0x0c8e, 2}, { 8, 7, 0x4c8e, 2}, { -8, 23, 0x0ca0, 2}, { 8, 23, 0x4ca4, 2}, { 0, 0, 0x0a8c, 2}, {-19, 3, 0x0aa6, 2}, { 19, 3, 0x4aa6, 2}, { -8, 7, 0x0c8e, 2}, { 8, 7, 0x4c8e, 2}, { -8, 23, 0x0ca2, 2}, { 8, 23, 0x4ca0, 2}, { 0, 0, 0x0a8c, 2}, {-19, 3, 0x0aa8, 2}, { 19, 3, 0x4aa8, 2}, { -8, 7, 0x0c8e, 2}, { 8, 7, 0x4c8e, 2}, { -8, 23, 0x0ca4, 2}, { 8, 23, 0x4ca2, 2}, { 0, 0, 0x0a8c, 2}, {-19, 3, 0x0aaa, 2}, { 19, 3, 0x4aaa, 2}, {-15, 5, 0x0aa6, 2}, { -6, 7, 0x0c8e, 2}, { 6, 7, 0x4c8e, 2}, { -6, 23, 0x0ca4, 2}, { 6, 23, 0x4ca0, 2}, { 0, 0, 0x0a8a, 2}, { 16, -1, 0x4aa6, 2}, {-11, 9, 0x0aa6, 2}, { -4, 7, 0x0c8e, 2}, { 5, 7, 0x4c8e, 2}, { -4, 23, 0x0ca4, 2}, { 5, 23, 0x4ca0, 2}, { 0, 0, 0x0a88, 2}, { 10, -2, 0x4aa6, 2}, { 0, 0, 0x0a84, 2}, { 13, 8, 0x4aa6, 2}, {-10, -2, 0x0aa6, 2}, { -5, 7, 0x0c8e, 2}, { 5, 7, 0x4c8e, 2}, { -5, 23, 0x0ca0, 2}, { 5, 23, 0x4ca4, 2}, { 0, 0, 0x0a82, 2}, { 18, 4, 0x4aa6, 2}, {-15, -1, 0x0aa6, 2}, { -6, 7, 0x0c8e, 2}, { 6, 7, 0x4c8e, 2}, { -6, 23, 0x0ca0, 2}, { 6, 23, 0x4ca4, 2}, { 0, 0, 0x0a80, 2}, {-19, 3, 0x0aa6, 2}, { 19, 3, 0x4aa6, 2}, { -8, 7, 0x0c8e, 2}, { 8, 7, 0x4c8e, 2}, { -8, 23, 0x0ca0, 2}, { 8, 23, 0x4ca4, 2}, { 0, 0, 0x0a80, 2}, {-19, 3, 0x0aa8, 2}, { 19, 3, 0x4aa8, 2}, { -8, 7, 0x0c8e, 2}, { 8, 7, 0x4c8e, 2}, { -8, 23, 0x0ca2, 2}, { 8, 23, 0x4ca0, 2}, { 0, 0, 0x0a80, 2}, {-19, 3, 0x0aaa, 2}, { 19, 3, 0x4aaa, 2}, { -8, 7, 0x0c8e, 2}, { 8, 7, 0x4c8e, 2}, { -8, 23, 0x0ca0, 2}, { 8, 23, 0x4ca4, 2}, { -8, 9, 0x0c8e, 2}, { 8, 9, 0x4c8e, 2}, { -8, 23, 0x0cae, 2}, { 8, 23, 0x4cae, 2}, { 8, 23, 0x4cae, 2}, { 8, 23, 0x4cae, 2}, { 0, 2, 0x0a8c, 2}, { -8, 16, 0x0c8e, 2}, { 8, 16, 0x4c8e, 2}, { -8, 23, 0x0cae, 2}, { 8, 23, 0x4cae, 2}, { 8, 23, 0x4cae, 2}, { 8, 23, 0x4cae, 2}, { 0, 9, 0x0a8c, 2}, { -8, 23, 0x0cae, 2}, { 8, 23, 0x4cae, 2}, { 8, 23, 0x4cae, 2}, { 8, 23, 0x4cae, 2}, { 8, 23, 0x4cae, 2}, { 8, 23, 0x4cae, 2}, { 0, 16, 0x0a8c, 2}, { -8, 23, 0x0cac, 2}, { 8, 23, 0x4cac, 2}, { 8, 23, 0x4cac, 2}, { 8, 23, 0x4cac, 2}, { 8, 23, 0x4cac, 2}, { 8, 23, 0x4cac, 2}, { 0, 20, 0x0a8c, 2}, { -8, 23, 0x0cac, 2}, { 8, 23, 0x4cac, 2}, { 8, 23, 0x4cac, 2}, { 8, 23, 0x4cac, 2}, { 8, 23, 0x4cac, 2}, { 8, 23, 0x4cac, 2}, { 0, 23, 0x0a8c, 2}, }; Sprite_DrawMultiple(k, &kBlind_Dmd[sprite_graphics[k] * 7], 7, NULL); OamEnt *oam = GetOamCurPtr(); if (sprite_wallcoll[k] == 0) { if (sprite_C[k] == 6) { oam[6].y = 0xf0; return; } if (sprite_C[k] == 4) return; } if (sprite_graphics[k] >= 10) return; static const uint8 kBlind_OamIdx[10] = {4, 4, 4, 5, 5, 0, 0, 0, 0, 0}; oam += kBlind_OamIdx[sprite_graphics[k]]; int j = sprite_head_dir[k]; oam->charnum = kBlindHead_Draw_Char[j]; oam->flags = oam->flags & 0x3f | kBlindHead_Draw_Flags[j]; } void TrinexxComponents_Initialize(int k) { // 9dad16 switch (sprite_type[k]) { case 0xcb: { sprite_x_lo[k] += 8; sprite_y_lo[k] += 16; Trinexx_CachePosition(k); overlord_x_lo[2] = 0; overlord_x_lo[3] = 0; overlord_x_lo[5] = 0; overlord_x_lo[7] = 0; overlord_x_hi[0] = 0; overlord_x_lo[6] = 255; Trinexx_RestoreXY(k); break; } case 0xcc: sprite_graphics[k] = 3; sprite_delay_main[k] = 128; common: for (int j = 0x1a; j >= 0; j--) { alt_sprite_type[j] = 0x40; alt_sprite_x_hi[j] = 0; alt_sprite_y_hi[j] = 0; } sprite_subtype2[k] = 1; Trinexx_CachePosition(k); break; case 0xcd: sprite_delay_main[k] = 255; goto common; } } void Trinexx_RestoreXY(int k) { // 9dad4f sprite_x_lo[k] = sprite_A[k]; Sprite_SetY(k, (sprite_G[k] << 8) + sprite_C[k] + 12); } void Trinexx_CachePosition(int k) { // 9dad8c sprite_A[k] = sprite_x_lo[k]; sprite_B[k] = sprite_x_hi[k]; sprite_C[k] = sprite_y_lo[k]; sprite_G[k] = sprite_y_hi[k]; } void Sprite_Trinexx_FinalPhase(int k) { // 9dadb5 static const uint8 kSprite_TrinexxD_Gfx3[8] = {6, 7, 0, 1, 2, 3, 4, 5}; static const uint8 kSprite_TrinexxD_Gfx[8] = {7, 7, 1, 1, 3, 3, 5, 5}; static const int8 kSprite_TrinexxD_Xvel[4] = {0, -31, 0, 31}; static const int8 kSprite_TrinexxD_Yvel[4] = {31, 0, -31, 0}; int j = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]) >> 1; uint8 gfx = kSprite_TrinexxD_Gfx3[j]; sprite_graphics[k] = sprite_delay_aux1[k] ? kSprite_TrinexxD_Gfx[gfx] : gfx; Sprite_TrinexxD_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sign8(sprite_ai_state[k])) { uint8 t = sprite_delay_main[k]; sprite_hit_timer[k] = t | 0xe0; if (t == 0) { sprite_delay_main[k] = 12; if (sprite_anim_clock[k] == 0) { sprite_hit_timer[k] = 255; Sprite_ScheduleBossForDeath(k); } else { sprite_anim_clock[k]--; Sprite_MakeBossExplosion(k); } } return; } if (!(frame_counter & 7)) SpriteSfx_QueueSfx3WithPan(k, 0x31); j = ++sprite_subtype2[k] & 0x7f; moldorm_x_lo[j] = sprite_x_lo[k]; moldorm_y_lo[j] = sprite_y_lo[k]; moldorm_x_hi[j] = sprite_x_hi[k]; moldorm_y_hi[j] = sprite_y_hi[k]; if (sprite_F[k] == 14) { sprite_F[k] = 8; if (sprite_ai_state[k] == 0) sprite_ai_state[k] = 2; } Sprite_MoveXY(k); Sprite_CheckDamageToAndFromLink(k); switch(sprite_ai_state[k]) { case 0: if (!--sprite_A[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 192; } Sprite_Get16BitCoords(k); if (Sprite_CheckTileCollision(k)) { sprite_D[k] = sprite_D[k] + 1 & 3; sprite_delay_aux1[k] = 8; } j = sprite_D[k]; sprite_x_vel[k] = kSprite_TrinexxD_Xvel[j]; sprite_y_vel[k] = kSprite_TrinexxD_Yvel[j]; break; case 1: if (!(frame_counter & 1)) { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 31); Sprite_ApproachTargetSpeed(k, pt.x, pt.y); } break; } } void Sprite_TrinexxD_Draw(int k) { // 9daf84 static const int8 kTrinexxD_HistPos[24] = { 8, 0xc, 0x10, 0x18, 0x20, 0x28, 0x30, 0x34, 0x38, 0x3c, 0x40, 0x44, 0x48, 0x4c, 0x50, 0x54, 0x58, 0x5c, 0x60, 0x64, 0x68, 0x6c, 0x70, 0x74, }; static const int8 kSprite_TrinexxD_Gfx2[24] = { 2, 2, 2, 3, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const int16 kTrinexxD_OamOffs[24] = { 0x10, 4, 4, 4, 0x10, 0x10, 0x10, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, }; sprite_obj_prio[k] |= 0x30; PrepOamCoordsRet info; SpriteDraw_TrinexxRockHead(k, &info); for (int i = 0; i != sprite_anim_clock[k]; i++) { int j = sprite_subtype2[k] - kTrinexxD_HistPos[i] & 0x7f; cur_sprite_x = moldorm_x_hi[j] << 8 | moldorm_x_lo[j]; cur_sprite_y = moldorm_y_hi[j] << 8 | moldorm_y_lo[j]; if ((uint16)(link_x_coord - cur_sprite_x + 8) < 16 && (uint16)(link_y_coord - cur_sprite_y + 16) < 16 && !sign8(sprite_ai_state[k]) && !(countdown_for_blink | link_disable_sprite_damage | submodule_index | flag_unk1)) { link_auxiliary_state = 1; link_give_damage = 8; link_incapacitated_timer = 16; link_actual_vel_x ^= 255; link_actual_vel_y ^= 255; } oam_cur_ptr += kTrinexxD_OamOffs[i]; oam_ext_cur_ptr += (kTrinexxD_OamOffs[i] >> 2); sprite_oam_flags[k] = 1; if (i == 4 && sprite_ai_state[k] != 0) { Sprite_Trinexx_CheckDamageToFlashingSegment(k); sprite_oam_flags[k] = (sprite_subtype2[k] & 6) ^ sprite_oam_flags[k]; } sprite_graphics[k] = kSprite_TrinexxD_Gfx2[i]; if (sprite_graphics[k] != 3) { SpriteDraw_SingleLarge(k); } else { sprite_graphics[k] = 8; SpriteDraw_TrinexxRockHead(k, &info); } } byte_7E0FB6 = sprite_anim_clock[k]; } void Sprite_Trinexx_CheckDamageToFlashingSegment(int k) { // 9db079 uint16 old_x = Sprite_GetX(k); uint16 old_y = Sprite_GetY(k); Sprite_SetX(k, cur_sprite_x); Sprite_SetY(k, cur_sprite_y); sprite_defl_bits[k] = 0x80; sprite_flags3[k] = 0; Sprite_CheckDamageFromLink(k); sprite_defl_bits[k] = 0x84; sprite_flags3[k] = 0x40; Sprite_SetX(k, old_x); Sprite_SetY(k, old_y); } void Sprite_CB_TrinexxRockHead(int k) { // 9db0ca if (overlord_x_hi[0]) { Sprite_Trinexx_FinalPhase(k); return; } TM_copy = 0x17; TS_copy = 0; SpriteDraw_TrinexxRockHeadAndBody(k); if (Sprite_ReturnIfInactive(k)) return; if (sign8(sprite_ai_state[k])) { flag_block_link_menu = sprite_ai_state[k]; if (!sprite_delay_main[k]) { overlord_x_hi[0]++; Sprite_InitializedSegmented(k); sprite_subtype2[k] = 0; sprite_head_dir[k] = 0; sprite_flags3[k] &= ~0x40; sprite_defl_bits[k] = 0x80; sprite_ai_state[k] = 0; sprite_D[k] = 0; sprite_A[k] = 0; sprite_anim_clock[k] = 16; sprite_x_vel[k] = sprite_y_vel[k] = 0; sprite_A[k] = 128; HIBYTE(dung_floor_y_vel) = 255; } else if (sprite_delay_main[k] >= 0xff) { } else if (sprite_delay_main[k] >= 0xe0) { if (!(sprite_delay_main[k] & 3)) { dung_floor_y_vel = -1; dung_hdr_collision_2_mirror = 1; } sprite_y_vel[k] = -8; Sprite_MoveY(k); Trinexx_CachePosition(k); sprite_C[k] = sprite_y_lo[k] - 12; overlord_x_lo[7] += 2; } else { if (!(sprite_delay_main[k] & 3)) SpriteSfx_QueueSfx2WithPan(k, 0xc); if (!(sprite_delay_main[k] & 1)) { static const int8 kTrinexx_X0[8] = {0, 8, 16, 24, -24, -16, -8, 0}; static const int8 kTrinexx_Y0[8] = {0, 8, 16, 24, -24, -16, -8, 0}; cur_sprite_x = Sprite_GetX(k) + kTrinexx_X0[GetRandomNumber() & 7]; cur_sprite_y = Sprite_GetY(k) + kTrinexx_Y0[GetRandomNumber() & 7] - 8; Sprite_MakeBossDeathExplosion_NoSound(k); } sprite_head_dir[k] = 255; } return; } if ((sprite_state[1] | sprite_state[2]) == 0 && sprite_ai_state[k] < 2) { sprite_delay_main[k] = 255; sprite_ai_state[k] = 255; sound_effect_2 = 0x22; return; } Trinexx_WagTail(k); Trinexx_HandleShellCollision(k); Sprite_CheckDamageToAndFromLink(k); if (!(frame_counter & 63)) { PairU8 pair = Sprite_IsRightOfLink(k); sprite_graphics[k] = (uint8)(pair.b + 24) < 48 ? 0 : pair.a ? 1 : 7; } if (overlord_x_lo[6]) { if (!(frame_counter & 1)) overlord_x_lo[6]--; return; } if (sprite_state[1] && sprite_ai_state[1] == 3) return; if (sprite_state[2] && sprite_ai_state[2] == 3) return; switch (sprite_ai_state[k]) { case 0: if (!sprite_delay_main[k]) { int j = GetRandomNumber() & 3; if ((sprite_subtype[k] & 0x7f) == j) return; if (++sprite_anim_clock[k] == 2) { sprite_anim_clock[k] = 0; sprite_ai_state[k] = 2; sprite_delay_main[k] = 80; return; } static const uint8 kTrinexx_Tab0[4] = {0x60, 0x78, 0x78, 0x90}; static const uint8 kTrinexx_Tab1[4] = {0x80, 0x70, 0x60, 0x80}; overlord_x_lo[0] = kTrinexx_Tab0[j]; overlord_x_lo[1] = kTrinexx_Tab1[j]; sprite_subtype[k] = j + ((GetRandomNumber() & 3) == 0) * 0x80; sprite_ai_state[k] = 1; } break; case 1: { if (sprite_subtype[k] == 0xff && (sprite_delay_main[k] == 0 || Sprite_IsBelowLink(k).a == 0)) { sprite_subtype[k] = 0; sprite_ai_state[k] = 0; sprite_delay_main[k] = 48; } else { uint16 x = sprite_x_hi[k] << 8 | overlord_x_lo[0]; uint16 y = sprite_y_hi[k] << 8 | overlord_x_lo[1]; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, sign8(sprite_subtype[k]) ? 16 : 8); sprite_x_vel[k] = pt.x; sprite_y_vel[k] = pt.y; uint8 bakx = sprite_x_lo[k]; uint8 baky = sprite_y_lo[k]; Sprite_MoveXY(k); dung_floor_y_vel = (int8)(baky - sprite_y_lo[k]); dung_floor_x_vel = (int8)(bakx - sprite_x_lo[k]); dung_hdr_collision_2_mirror = 1; Trinexx_CachePosition(k); sprite_C[k] = sprite_y_lo[k] - 12; if ((uint8)(overlord_x_lo[0] - sprite_x_lo[k] + 2) < 4 && (uint8)(overlord_x_lo[1] - sprite_y_lo[k] + 2) < 4) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 48; } } int i = sign8(sprite_subtype[k]) ? 2 : 1; do { sprite_subtype2[k] += sign8(sprite_x_vel[k]) ? 1 : -1; if (!(sprite_subtype2[k] & 0xf)) SpriteSfx_QueueSfx2WithPan(k, 0x21); } while (--i); break; } case 2: Trinexx_WagTail(k); Trinexx_WagTail(k); if (!sprite_delay_main[k]) { sprite_ai_state[k] = 3; Sprite_ApplySpeedTowardsLink(k, 48); sprite_delay_main[k] = 64; sound_effect_2 = 0x26; } break; case 3: Sprite_MoveXY(k); if (!sprite_delay_main[k]) { Trinexx_RestoreXY(k); sprite_ai_state[k] = 0; sprite_delay_main[k] = 48; } else if (sprite_delay_main[k] == 0x20) { sprite_x_vel[k] = -sprite_x_vel[k]; sprite_y_vel[k] = -sprite_y_vel[k]; } break; } } void Trinexx_WagTail(int k) { // 9db3b5 if (!overlord_x_lo[5]) { if (!(++overlord_x_lo[4] & 3)) { int j = overlord_x_lo[3] & 1; overlord_x_lo[2] += j ? -1 : 1; if (overlord_x_lo[2] == (j ? 0 : 6)) { overlord_x_lo[3] += 1; overlord_x_lo[5] = 8; } } } else { --overlord_x_lo[5]; } } void Trinexx_HandleShellCollision(int k) { // 9db3e6 uint16 x = sprite_A[k] | sprite_B[k] << 8; uint16 y = sprite_C[k] | sprite_G[k] << 8; if ((uint16)(x - link_x_coord + 40) < 80 && (uint16)(y - link_y_coord + 16) < 64 && !(countdown_for_blink | link_disable_sprite_damage)) { link_auxiliary_state = 1; link_give_damage = 8; link_incapacitated_timer = 16; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32); link_actual_vel_x = pt.x; link_actual_vel_y = pt.y; } } void SpriteDraw_TrinexxRockHead(int k, PrepOamCoordsRet *info) { // 9db560 static const DrawMultipleData kTrinexx_Draw1_Dmd[36] = { {-8, -8, 0x40c0, 2}, { 8, -8, 0x00c0, 2}, {-8, 8, 0x40e0, 2}, { 8, 8, 0x00e0, 2}, {-8, -8, 0x0000, 2}, { 8, -8, 0x0002, 2}, {-8, 8, 0x0020, 2}, { 8, 8, 0x0022, 2}, {-8, -8, 0x00c2, 2}, { 8, -8, 0x00c4, 2}, {-8, 8, 0x80c2, 2}, { 8, 8, 0x80c4, 2}, {-8, -8, 0x8020, 2}, { 8, -8, 0x8022, 2}, {-8, 8, 0x8000, 2}, { 8, 8, 0x8002, 2}, {-8, -8, 0xc0e0, 2}, { 8, -8, 0x80e0, 2}, {-8, 8, 0xc0c0, 2}, { 8, 8, 0x80c0, 2}, {-8, -8, 0xc022, 2}, { 8, -8, 0xc020, 2}, {-8, 8, 0xc002, 2}, { 8, 8, 0xc000, 2}, {-8, -8, 0x40c4, 2}, { 8, -8, 0x40c2, 2}, {-8, 8, 0xc0c4, 2}, { 8, 8, 0xc0c2, 2}, {-8, -8, 0x4002, 2}, { 8, -8, 0x4000, 2}, {-8, 8, 0x4022, 2}, { 8, 8, 0x4020, 2}, {-8, -8, 0x0026, 2}, { 8, -8, 0x4026, 2}, {-8, 8, 0x8026, 2}, { 8, 8, 0xc026, 2}, }; if (!sign8(sprite_ai_state[k])) sprite_obj_prio[k] |= 0x30; Sprite_DrawMultiple(k, &kTrinexx_Draw1_Dmd[sprite_graphics[k] * 4], 4, info); } void SpriteDraw_TrinexxRockHeadAndBody(int k) { // 9db587 static const int8 kTrinexx_Draw_X[35] = { 0, 3, 9, 16, 24, 0, 2, 7, 13, 20, 0, 1, 4, 9, 15, 0, 0, 0, 0, 0, 0, -1, -4, -9, -15, 0, -2, -7, -13, -20, 0, -3, -9, -16, -24, }; static const int8 kTrinexx_Draw_Y[35] = { 0x18, 0x20, 0x25, 0x25, 0x21, 0x18, 0x20, 0x27, 0x2a, 0x2c, 0x18, 0x20, 0x28, 0x2f, 0x34, 0x18, 0x21, 0x2a, 0x34, 0x3d, 0x18, 0x20, 0x28, 0x2f, 0x34, 0x18, 0x20, 0x27, 0x2a, 0x2c, 0x18, 0x20, 0x25, 0x25, 0x21, }; static const uint8 kTrinexx_Draw_Char[5] = {6, 0x28, 0x28, 0x2c, 0x2c}; static const uint8 kTrinexx_Mults[8] = {0xfc, 0xe0, 0xc0, 0xa0, 0x80, 0x60, 0x40, 0x20}; static const int8 kTrinexx_Draw_Xoffs[16] = {0, 2, 3, 4, 4, 4, 3, 2, 0, -2, -3, -4, -4, -4, -3, -2}; static const int8 kTrinexx_Draw_Yoffs[16] = {-4, -4, -3, -2, 0, 2, 3, 4, 4, 4, 3, 2, 0, -2, -3, -4}; if (sign8(sprite_head_dir[k])) return; PrepOamCoordsRet info; SpriteDraw_TrinexxRockHead(k, &info); info.flags &= ~0x10; if (sprite_ai_state[k] == 3) { OamEnt *oam = GetOamCurPtr() + 4; uint8 xb = sprite_A[k] - sprite_x_lo[k]; uint8 yb = sprite_C[k] - sprite_y_lo[k]; for (int i = 7; i >= 0; i--, oam++) { oam->x = info.x + TrinexxMult(xb, kTrinexx_Mults[i]); oam->y = info.y + TrinexxMult(yb, kTrinexx_Mults[i]); oam->charnum = 0x28; oam->flags = info.flags; bytewise_extended_oam[oam - oam_buf] = 2; } byte_7E0FB6 = 0x30; } oam_cur_ptr = 0x9f0; oam_ext_cur_ptr = 0xa9c; OamEnt *oam = GetOamCurPtr(); uint8 xb = sprite_A[k] - BG2HOFS_copy2; uint16 yb = (sprite_C[k] | sprite_y_hi[k] << 8) - BG2VOFS_copy2; uint8 xidx = (uint8)(sprite_x_vel[k] + 3) < 7 ? 0 : (sprite_subtype2[k] >> 2); uint8 yidx = sprite_subtype2[k] >> 2; for (int i = 1; i >= 0; i--, oam += 2) { oam[0].x = oam[1].x = xb + (i ? -28 : 28) + kTrinexx_Draw_Xoffs[xidx + (1-i) * 8 & 0xf]; oam[0].y = yb - 8 + kTrinexx_Draw_Yoffs[yidx + i * 8 & 0xf]; oam[1].y = oam[0].y + 16; oam[0].charnum = 0xc; oam[1].charnum = 0x2a; oam[0].flags = oam[1].flags = info.flags | (i ? 0 : 0x40); WORD(bytewise_extended_oam[oam - oam_buf]) = 0x202; } oam = (OamEnt *)&g_ram[0x800] + 91; int g = overlord_x_lo[2]; for (int i = 0; i < 5; i++, oam++) { int j = g * 5 + i; oam->x = xb + kTrinexx_Draw_X[j]; uint16 y = yb - kTrinexx_Draw_Y[j] - 0x20 + WORD(overlord_x_lo[7]); oam->y = ClampYForOam(y); oam->charnum = kTrinexx_Draw_Char[i]; oam->flags = info.flags; bytewise_extended_oam[oam - oam_buf] = 2; } tmp_counter = 0xff; if (submodule_index) Sprite_CorrectOamEntries(k, 3, 2); } void Sprite_Sidenexx(int k) { // 9db8a7 static const int8 kTrinexxHead_Xoffs[2] = {-14, 13}; int xx = (sprite_B[0] << 8 | sprite_A[0]) + kTrinexxHead_Xoffs[sprite_type[k] - 0xcc]; sprite_A[k] = xx, sprite_B[k] = xx >> 8; int yy = (sprite_G[0] << 8 | sprite_C[0]) - 0x20; sprite_C[k] = yy, sprite_G[k] = yy >> 8; sprite_obj_prio[k] |= 0x30; TrinexxHead_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sign8(sprite_ai_state[k])) { sprite_ignore_projectile[k] = sprite_ai_state[k]; Sidenexx_Explode(k); return; } if (sprite_hit_timer[k] && sprite_ai_state[k] != 4) { sprite_hit_timer[k] = 0; sprite_delay_main[k] = 128; sprite_ai_state[k] = 4; sprite_z_vel[k] = sprite_oam_flags[k]; sprite_oam_flags[k] = 3; } Sprite_CheckDamageToAndFromLink(k); sprite_defl_bits[k] |= 4; switch(sprite_ai_state[k]) { case 0: sprite_flags3[k] |= 0x40; if (!sprite_delay_main[k]) { sprite_ai_state[k] = 2; sprite_subtype2[k] = 9; sprite_flags3[k] &= ~0x40; } break; case 1: if (!sprite_delay_main[k]) { int i = (GetRandomNumber() & 7) + 1; int j = sprite_D[k]; if (i < 5 && sprite_D[k] != i) { sprite_D[k] = i; sprite_ai_state[k] = 2; if (j == 1 && !(GetRandomNumber() & 1) && sprite_ai_state[0] < 2) { sprite_graphics[k] = 0; sprite_ai_state[k] = 3; sprite_delay_main[k] = 127; } } } break; case 2: { static const uint8 kTrinexxHead_Target0[45] = { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x58, 0x64, 0x6a, 0x6f, 0x74, 0x7a, 0x7e, 0x80, 0x80, 0x39, 0x48, 0x52, 0x5c, 0x65, 0x73, 0x77, 0x7a, 0x80, 0x1e, 0x24, 0x29, 0x2e, 0x34, 0x3a, 0x44, 0x4d, 0x80, 0xa, 0x11, 0x17, 0x1c, 0x22, 0x2a, 0x36, 0x3a, 0x80, }; static const uint8 kTrinexxHead_Target1[45] = { 0x30, 0x28, 0x23, 0x1e, 0x19, 0x13, 0xc, 6, 0, 0x2f, 0x26, 0x21, 0x1d, 0x18, 0x12, 0xc, 6, 0, 0x2f, 0x27, 0x22, 0x1d, 0x18, 0x12, 0xc, 6, 0, 0x2f, 0x27, 0x22, 0x1d, 0x18, 0x12, 0xc, 6, 0, 0x48, 0x3a, 0x32, 0x29, 0x22, 0x19, 0x10, 7, 0, }; int j = sprite_D[k] * 9, f = k * 9; int n = 0; for (int i = 8; i >= 0; i--, j++, f++) { if (alt_sprite_type[f] - kTrinexxHead_Target0[j]) { alt_sprite_type[f] += sign8(alt_sprite_type[f] - kTrinexxHead_Target0[j]) ? 1 : -1; n++; } if (alt_sprite_type[f] - kTrinexxHead_Target0[j]) { alt_sprite_type[f] += sign8(alt_sprite_type[f] - kTrinexxHead_Target0[j]) ? 1 : -1; n++; } if (alt_sprite_y_hi[f] - kTrinexxHead_Target1[j]) { alt_sprite_y_hi[f] += sign8(alt_sprite_y_hi[f] - kTrinexxHead_Target1[j]) ? 1 : -1; n++; } } if (n == 0) { sprite_ai_state[k] = 1; sprite_delay_main[k] = GetRandomNumber() & 15; } break; } case 3: { static const uint8 kTrinexxHead_FrameMask[8] = {1, 1, 3, 3, 7, 0xf, 0x1f, 0x1f}; int j = sprite_delay_main[k]; if (!j) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 32; return; } if (j == 64) Sidenexx_ExhaleDanger(k); sprite_subtype[k] = (j < 8) ? j : (j < 121) ? 8 : ~(sprite_delay_main[k] + 0x80); if (j >= 64 && !(frame_counter & kTrinexxHead_FrameMask[(j - 64) >> 3])) { int x = (GetRandomNumber() & 0xf) - 3; int y = (GetRandomNumber() & 0xf) + 12; int j = Sprite_GarnishSpawn_Sparkle(k, x, y); if (sprite_type[k] == 0xcc) garnish_type[j] = 0xe; } break; } case 4: { sprite_defl_bits[k] &= ~4; sprite_subtype[k] = 0; int j = sprite_delay_main[k]; if (!j) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 32; sprite_oam_flags[k] = sprite_z_vel[k]; sprite_hit_timer[k] = 0; } if (j >= 15) { if (j >= 63 && j < 78) { if (sprite_type[k] == 0xcd) Trinexx_FlashShellPalette_Blue(); else Trinexx_FlashShellPalette_Red(); } } else { if (sprite_type[k] == 0xcd) Trinexx_UnflashShellPalette_Blue(); else Trinexx_UnflashShellPalette_Red(); } } } } void Sidenexx_ExhaleDanger(int k) { // 9dbae8 SpriteSpawnInfo info; if (sprite_type[k] == 0xcd) { for (int i = 0; i < 2; i++) { int j = Sprite_SpawnDynamically(k, 0xcd, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_C[j] = i ? 1 : -2; SpriteSfx_QueueSfx3WithPan(k, 0x19); sprite_ignore_projectile[j] = sprite_E[j] = 1; sprite_y_vel[j] = 24; sprite_flags2[j] = 0; sprite_flags3[j] = 0x40; } } byte_7E0FB6 = 1; } else { int j = Sprite_SpawnDynamically(k, sprite_type[k], &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); SpriteSfx_QueueSfx2WithPan(k, 0x2a); sprite_ignore_projectile[j] = sprite_E[j] = 1; sprite_y_vel[j] = 24; sprite_flags2[j] = 0; sprite_flags3[j] = 0x40; } } } void Sidenexx_Explode(int k) { // 9dbb3f if (!sprite_delay_main[k]) { sprite_delay_main[k] = 12; if (sprite_subtype2[k] == 1) sprite_state[k] = 0; sprite_subtype2[k]--; BYTE(cur_sprite_x) += BG2HOFS_copy2; BYTE(cur_sprite_y) += BG2VOFS_copy2; Sprite_MakeBossExplosion(k); } } void TrinexxHead_Draw(int k) { // 9dbb70 sprite_x_lo[k] = sprite_A[k]; sprite_x_hi[k] = sprite_B[k]; sprite_y_lo[k] = sprite_C[k]; sprite_y_hi[k] = sprite_G[k]; Sprite_Get16BitCoords(k); PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int i = 0; do { int j = i + k * 9; uint16 r6 = (k != 2) ? 0x100 + (uint8)(-alt_sprite_type[j]) : alt_sprite_type[j]; uint8 r15 = alt_sprite_y_hi[j]; BYTE(dungmap_var7) = TrinexxHeadSin(r6, r15); HIBYTE(dungmap_var7) = TrinexxHeadSin(r6 + 0x80, r15); if (i == 0) { static const int8 kTrinexxHead_FirstPart_X[5] = {-8, 8, -8, 8, 0}; static const int8 kTrinexxHead_FirstPart_Y[5] = {-8, -8, 8, 8, 2}; static const uint8 kTrinexxHead_FirstPart_Char[5] = {4, 4, 0x24, 0x24, 0xa}; static const uint8 kTrinexxHead_FirstPart_Flags[5] = {0x40, 0, 0x40, 0, 0}; for (int m = 0; m < 5; m++) { BYTE(cur_sprite_x) = info.x + BYTE(dungmap_var7); oam->x = BYTE(cur_sprite_x) + kTrinexxHead_FirstPart_X[m]; BYTE(cur_sprite_y) = info.y + HIBYTE(dungmap_var7); oam->y = BYTE(cur_sprite_y) + kTrinexxHead_FirstPart_Y[m] + (m == 4 ? sprite_subtype[k] : 0); oam->charnum = kTrinexxHead_FirstPart_Char[m]; oam->flags = info.flags | kTrinexxHead_FirstPart_Flags[m]; bytewise_extended_oam[oam - oam_buf] = 2; oam++; } Sprite_SetX(k, (sprite_B[k] << 8 | sprite_A[k]) + (int8)BYTE(dungmap_var7)); Sprite_SetY(k, (sprite_G[k] << 8 | sprite_C[k]) + (int8)HIBYTE(dungmap_var7)); } else { BYTE(cur_sprite_x) = oam->x = info.x + BYTE(dungmap_var7); BYTE(cur_sprite_y) = oam->y = info.y + HIBYTE(dungmap_var7); oam->charnum = 8; oam->flags = info.flags; bytewise_extended_oam[oam - oam_buf] = 2; oam++; } } while (++i != sprite_subtype2[k]); tmp_counter = i; byte_7E0FB6 = i * 4 + 16; if (submodule_index) Sprite_CorrectOamEntries(k, 4, 2); } void Sprite_CC_CD_Common(int k) { // 9dbd44 if (!(frame_counter & 3)) { int m = Sprite_IsRightOfLink(k).a ? -1 : 1; if (sprite_x_vel[k] != (uint8)(m * 16)) sprite_x_vel[k] += m; } if (Sprite_CheckTileCollision(k)) sprite_state[k] = 0; } void Sprite_CD_SpawnGarnish(int k) { // 9dbd65 if (++sprite_subtype2[k] & 7) return; SpriteSfx_QueueSfx3WithPan(k, 0x14); int j = GarnishAllocOverwriteOld(); garnish_active = garnish_type[j] = 0xc; garnish_sprite[j] = k; Garnish_SetX(j, Sprite_GetX(k)); Garnish_SetY(j, Sprite_GetY(k) + 16); garnish_countdown[j] = 127; } void Sprite_TrinexxFire_AddFireGarnish(int k) { // 9dbdd6 if (++sprite_subtype2[k] & 7) return; SpriteSfx_QueueSfx2WithPan(k, 0x2a); Garnish_FlameTrail(k, false); } int Garnish_FlameTrail(int k, bool is_low) { // 9dbde8 int j = is_low ? GarnishAllocOverwriteOldLow() : GarnishAllocOverwriteOld(); garnish_active = garnish_type[j] = 0x10; garnish_sprite[j] = k; Garnish_SetX(j, Sprite_GetX(k)); Garnish_SetY(j, Sprite_GetY(k) + 16); garnish_countdown[j] = 127; return j; } void Sprite_CA_ChainChomp(int k) { // 9dbe7d ChainChomp_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToAndFromLink(k); ChainChomp_HandleLeash(k); if (!((k ^ frame_counter) & 3) && (sprite_x_vel[k] | sprite_y_vel[k])) sprite_D[k] = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]) & 0xf; Sprite_MoveXYZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = 0; } Sprite_Get16BitCoords(k); uint16 x = sprite_A[k] | sprite_B[k] << 8; uint16 y = sprite_C[k] | sprite_G[k] << 8; sprite_anim_clock[k] = (uint16)(cur_sprite_x - x + 48) < 96 && (uint16)(cur_sprite_y - y + 48) < 96; switch(sprite_ai_state[k]) { case 0: // if (!sprite_delay_main[k]) { static const int8 kChainChomp_Xvel[16] = {0, 8, 11, 14, 16, 14, 11, 8, 0, -8, -11, -14, -16, -14, -11, -8}; static const int8 kChainChomp_Yvel[16] = {-16, -14, -11, -8, 0, 8, 11, 14, 16, 14, 11, 8, 0, -9, -11, -14}; if (++sprite_subtype2[k] == 4) { sprite_subtype2[k] = 0; sprite_ai_state[k] = 2; int j = GetRandomNumber() & 15; sprite_x_vel[k] = kChainChomp_Xvel[j] << 2; sprite_y_vel[k] = kChainChomp_Yvel[j] << 2; GetRandomNumber(); Sprite_ApplySpeedTowardsLink(k, 64); SpriteSfx_QueueSfx3WithPan(k, 0x4); } else { sprite_delay_main[k] = (GetRandomNumber() & 31) + 16; int j = GetRandomNumber() & 15; sprite_x_vel[k] = kChainChomp_Xvel[j]; sprite_y_vel[k] = kChainChomp_Yvel[j]; sprite_ai_state[k] = 1; } } else { sprite_x_vel[k] = 0; sprite_y_vel[k] = 0; } break; case 1: // if (!sprite_delay_main[k]) { sprite_delay_main[k] = 32; sprite_ai_state[k] = 0; } if (!(sprite_delay_main[k] & 15)) ChainChomp_MoveChain(k); if (!sprite_z[k]) sprite_z_vel[k] = 16; if (!sprite_anim_clock[k]) { uint16 x = sprite_A[k] | sprite_B[k] << 8; uint16 y = sprite_C[k] | sprite_G[k] << 8; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16); sprite_x_vel[k] = pt.x; sprite_y_vel[k] = pt.y; Sprite_MoveXY(k); sprite_delay_main[k] = 12; } break; case 2: // if (!sprite_anim_clock[k]) { sprite_x_vel[k] = -sprite_x_vel[k]; sprite_y_vel[k] = -sprite_y_vel[k]; Sprite_MoveXY(k); sprite_x_vel[k] = sprite_y_vel[k] = 0; sprite_ai_state[k] = 3; sprite_delay_aux1[k] = 48; } ChainChomp_MoveChain(k); ChainChomp_MoveChain(k); break; case 3: // if (!sprite_delay_aux1[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 48; } ChainChomp_MoveChain(k); ChainChomp_MoveChain(k); break; } } void ChainChomp_MoveChain(int k) { // 9dc02a static const uint8 kChainChomp_Muls[6] = {205, 154, 102, 51, 8, 0xbd}; // wtf uint16 x = sprite_A[k] | sprite_B[k] << 8; uint16 y = sprite_C[k] | sprite_G[k] << 8; int pos = k * 8; uint16 x2 = chainchomp_x_hist[pos] - x; uint16 y2 = chainchomp_y_hist[pos] - y; pos++; for (int i = 5; i >= 0; i--) { uint16 x3 = x + ChainChomp_OneMult(x2, kChainChomp_Muls[(pos & 7) - 1]); uint16 y3 = y + ChainChomp_OneMult(y2, kChainChomp_Muls[(pos & 7) - 1]); if (chainchomp_x_hist[pos] - x3) chainchomp_x_hist[pos] += sign16(chainchomp_x_hist[pos] - x3) ? 1 : -1; if (chainchomp_y_hist[pos] - y3) chainchomp_y_hist[pos] += sign16(chainchomp_y_hist[pos] - y3) ? 1 : -1; pos++; } } void ChainChomp_HandleLeash(int k) { // 9dc0f2 int pos = k * 8; chainchomp_x_hist[pos] = cur_sprite_x; chainchomp_y_hist[pos] = cur_sprite_y; for (int i = 0; i < 6; i++, pos++) { uint16 x = chainchomp_x_hist[pos] - chainchomp_x_hist[pos + 1]; if (!sign16(x - 8)) chainchomp_x_hist[pos + 1] = chainchomp_x_hist[pos] - 8; else if (sign16(x + 8)) chainchomp_x_hist[pos + 1] = chainchomp_x_hist[pos] + 8; uint16 y = chainchomp_y_hist[pos] - chainchomp_y_hist[pos + 1]; if (!sign16(y - 8)) chainchomp_y_hist[pos + 1] = chainchomp_y_hist[pos] - 8; else if (sign16(y + 8)) chainchomp_y_hist[pos + 1] = chainchomp_y_hist[pos] + 8; } } void ChainChomp_Draw(int k) { // 9dc192 static const uint8 kChainChomp_Gfx[16] = {0, 1, 2, 3, 3, 3, 2, 1, 0, 0, 0, 4, 4, 4, 0, 0}; static const uint8 kChainChomp_OamFlags[16] = {0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40}; int j = sprite_D[k]; sprite_graphics[k] = kChainChomp_Gfx[j]; sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kChainChomp_OamFlags[j]; SpriteDraw_SingleLarge(k); OamEnt *oam = GetOamCurPtr() + 1; uint8 flags = sprite_oam_flags[k] ^ sprite_obj_prio[k]; int r8 = (sprite_delay_aux1[k] & 1) + 4; int pos = k * 8; for (int i = 5; i >= 0; i--, pos++, oam++) { uint16 x = chainchomp_x_hist[pos] + r8 - BG2HOFS_copy2; uint16 y = chainchomp_y_hist[pos] + r8 - BG2VOFS_copy2; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = 0x8b; oam->flags = flags & 0xf0 | 0xd; bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1); } } void Sprite_C9_Tektite(int k) { // 9dc275 int j = sprite_anim_clock[k]; if (j) { sprite_ignore_projectile[k] = j; sprite_obj_prio[k] = 0x30; } switch (j) { case 0: Sprite_Tektite(k); break; case 1: Sprite_PhantomGanon(k); break; case 2: Sprite_GanonTrident(k); break; case 3: Sprite_SpiralFireBat(k); break; case 4: Sprite_FireBat_Launched(k); break; case 5: Sprite_FireBat_Trailer(k); break; } } void Sprite_Tektite(int k) { // 9dc293 int j; if (sprite_delay_aux1[k]) sprite_graphics[k] = 0; Tektite_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXYZ(k); Sprite_BounceFromTileCollision(k); sprite_z_vel[k] -= 1; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = 0; } switch(sprite_ai_state[k]) { case 0: { // Stationary static const uint8 kTektite_Dir[4] = {3, 2, 1, 0}; static const int8 kTektite_Xvel[4] = {16, -16, 16, -16}; static const int8 kTektite_Yvel[4] = {16, 16, -16, -16}; PointU8 pt; j = Sprite_DirectionToFaceLink(k, &pt); if ((uint8)(pt.x + 40) < 80 && (uint8)(pt.y + 40) < 80 && player_oam_y_offset != 0x80 && !(sprite_z[k] | sprite_pause[k]) && link_is_on_lower_level == sprite_floor[k] && j != kTektite_Dir[link_direction_facing >> 1]) { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32); sprite_x_vel[k] = -pt.x; sprite_y_vel[k] = -pt.y; sprite_z_vel[k] = 16; sprite_ai_state[k] = 1; return; } if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_B[k]++; if (sprite_B[k] == 4) { sprite_B[k] = 0; sprite_ai_state[k]++; sprite_delay_main[k] = (GetRandomNumber() & 63) + 48; sprite_z_vel[k] = 12; j = Sprite_IsBelowLink(k).a * 2 + Sprite_IsRightOfLink(k).a; } else { sprite_z_vel[k] = (GetRandomNumber() & 7) + 24; j = GetRandomNumber() & 3; } sprite_x_vel[k] = kTektite_Xvel[j]; sprite_y_vel[k] = kTektite_Yvel[j]; } else { sprite_graphics[k] = sprite_delay_main[k] >> 4 & 1; } break; } case 1: // Aloft if (!sprite_z[k]) { reset_state: sprite_ai_state[k] = 0; sprite_delay_main[k] = (GetRandomNumber() & 63) + 72; sprite_y_vel[k] = 0; sprite_x_vel[k] = 0; } else { sprite_graphics[k] = 2; } break; case 2: // RepeatingHop if (!sprite_delay_main[k]) goto reset_state; if (!sprite_z[k]) { sprite_z_vel[k] = 12; sprite_z[k]++; sprite_delay_aux1[k] = 8; } sprite_graphics[k] = 2; break; } } void Tektite_Draw(int k) { // 9dc3f5 static const DrawMultipleData kTektite_Dmd[6] = { {-8, 0, 0x00c8, 2}, { 8, 0, 0x40c8, 2}, {-8, 0, 0x00ca, 2}, { 8, 0, 0x40ca, 2}, {-8, 0, 0x00ea, 2}, { 8, 0, 0x40ea, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kTektite_Dmd[sprite_graphics[k] * 2], 2, &info); SpriteDraw_Shadow(k, &info); } void Sprite_C8_BigFairy(int k) { // 9dc414 if (sprite_head_dir[k]) Sprite_FairyCloud(k); else Sprite_BigFairy(k); } void Sprite_FairyCloud(int k) { // 9dc41c PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; sprite_subtype2[k]++; FaerieCloud_Draw(k); if (!(sprite_subtype2[k] & 31)) SpriteSfx_QueueSfx2WithPan(k, 0x31); switch (sprite_ai_state[k]) { case 0: sprite_A[k] = 0; Sprite_ApplySpeedTowardsLink(k, 8); Sprite_MoveXY(k); Sprite_Get16BitCoords(k); if ((uint16)(link_x_coord - cur_sprite_x + 3) < 6 && (uint16)(link_y_coord - cur_sprite_y + 11) < 6) { WORD(link_hearts_filler) += 0xa0; sprite_ai_state[k] = 1; } break; case 1: if (link_health_current == link_health_capacity) { sprite_ai_state[k]++; sprite_delay_aux2[0] = 112; // zelda bug } break; case 2: if ((sprite_subtype2[k] & 15) || sign8(sprite_A[k])) return; sprite_A[k] = sprite_A[k] * 2 + 1; if (sprite_A[k] >= 0x80) { sprite_A[k] = 255; flag_is_link_immobilized = 0; sprite_state[k] = 0; } break; } } void Sprite_BigFairy(int k) { // 9dc4bf PointU8 pt; int i = sprite_delay_aux2[k]; if (i != 0 && i < 0x40) { if (--i == 0) sprite_state[k] = 0; if (i & 1) return; } BigFaerie_Draw(k); if (sign8(--sprite_G[k])) { sprite_G[k] = 5; sprite_graphics[k] = sprite_graphics[k] + 1 & 3; } if (Sprite_ReturnIfInactive(k)) return; sprite_subtype2[k]++; switch (sprite_ai_state[k]) { case 0: // await close player FaerieCloud_Draw(k); sprite_A[k] = 1; Sprite_DirectionToFaceLink(k, &pt); if ((uint8)(pt.x + 0x30) < 0x60 && (uint8)(pt.y + 0x30) < 0x60) { Link_CancelDash(); sprite_ai_state[k] = 1; dialogue_message_index = 0x15a; Sprite_ShowMessageMinimal(); flag_is_link_immobilized = 1; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xC8, &info); Sprite_SetSpawnedCoordinates(j, &info); sprite_head_dir[j] = 1; sprite_y_lo[j] -= sprite_z[k]; sprite_z[j] = 0; } break; case 1: // dormant break; } } void BigFaerie_Draw(int k) { // 9dc5d0 static const DrawMultipleData kBigFaerie_Dmd[16] = { {-4, -8, 0x008e, 2}, { 4, -8, 0x408e, 2}, {-4, 8, 0x00ae, 2}, { 4, 8, 0x40ae, 2}, {-4, -8, 0x008c, 2}, { 4, -8, 0x408c, 2}, {-4, 8, 0x00ac, 2}, { 4, 8, 0x40ac, 2}, {-4, -8, 0x008a, 2}, { 4, -8, 0x408a, 2}, {-4, 8, 0x00aa, 2}, { 4, 8, 0x40aa, 2}, {-4, -8, 0x008c, 2}, { 4, -8, 0x408c, 2}, {-4, 8, 0x00ac, 2}, { 4, 8, 0x40ac, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kBigFaerie_Dmd[sprite_graphics[k] * 4], 4, &info); SpriteDraw_Shadow(k, &info); } void FaerieCloud_Draw(int k) { // 9dc616 static const int8 kFaerieCloud_Draw_XY[8] = {-12, -6, 0, 6, 12, 18, 0, 6}; if (!sign8(sprite_A[k]) && !(sprite_A[k] & sprite_subtype2[k])) { int x = kFaerieCloud_Draw_XY[GetRandomNumber() & 7]; int y = kFaerieCloud_Draw_XY[GetRandomNumber() & 7]; Sprite_GarnishSpawn_Sparkle(k, x, y); } } void Sprite_C7_Pokey(int k) { // 9dc64f if (sprite_C[k]) { SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXYZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z_vel[k] = 16; sprite_z[k] = 0; } if (Sprite_BounceFromTileCollision(k)) SpriteSfx_QueueSfx2WithPan(k, 0x21); if (sprite_G[k] >= 3) { sprite_state[k] = 6; sprite_delay_main[k] = 10; sprite_flags5[k] = 0; SpriteSfx_QueueSfx2WithPan(k, 0x1e); } return; } Hokbok_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_A[k] && sprite_F[k] == 15) { sprite_F[k] = 6; sprite_z[k] += sprite_B[k]; if (!--sprite_A[k]) sprite_health[k] = 17; sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? -4 : 4; sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? -4 : 4; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xc7, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_C[j] = 1; sprite_health[j] = 1; sprite_x_vel[j] = sprite_x_recoil[k]; sprite_y_vel[j] = sprite_y_recoil[k]; sprite_defl_bits[j] = 64; } } if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); switch(sprite_ai_state[k]) { case 0: if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_z_vel[k] = 16; } else { static const uint8 kHokbok_B[8] = {8, 7, 6, 5, 4, 5, 6, 7}; sprite_B[k] = kHokbok_B[sprite_delay_main[k] >> 1]; } break; case 1: Sprite_MoveXYZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_ai_state[k] = 0; sprite_delay_main[k] = 15; } Sprite_BounceFromTileCollision(k); break; } } void Hokbok_Draw(int k) { // 9dc77d PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr() + 3; int d = sprite_B[k]; uint16 x = info.x, y = info.y; for (int i = sprite_A[k]; i >= 0; i--, oam--) { oam->x = x; oam->y = ClampYForOam(y); oam->charnum = ((i == 0) ? 0xa2 : 0xa0) - ((d < 7) ? 0x20 : 0); oam->flags = info.flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); y -= d; } SpriteDraw_Shadow(k, &info); } void Sprite_C5_Medusa(int k) { // 9dc7eb PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (!player_is_indoors) { sprite_x_vel[k] = 255; sprite_subtype[k] = 255; if (!Sprite_CheckTileCollision(k)) return; if (Sprite_ReturnIfInactive(k)) return; sprite_type[k] = 0x19; SpritePrep_LoadProperties(k); sprite_E[k]++; sprite_x_lo[k] += 8; sprite_y_lo[k] -= 8; SpriteSfx_QueueSfx3WithPan(k, 0x19); sprite_defl_bits[k] = 0x80; } else { if (Sprite_ReturnIfInactive(k)) return; sprite_subtype2[k]++; if (!(sprite_subtype2[k] & 0x7f) && sprite_floor[k] == link_is_on_lower_level) { int j = Sprite_SpawnFireball(k); if (j >= 0) { sprite_defl_bits[j] = sprite_defl_bits[j] | 8; sprite_bump_damage[j] = 4; } } } } void Sprite_C6_4WayShooter(int k) { // 9dc869 static const int8 kFireballJunction_X[4] = {12, -12, 0, 0}; static const int8 kFireballJunction_Y[4] = {0, 0, 12, -12}; static const int8 kFireballJunction_XYvel[6] = {0, 0, 40, -40, 0, 0}; PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; if (sprite_delay_main[k] == 24) { int j = Sprite_SpawnFireball(k); if (j >= 0) { sprite_defl_bits[j] |= 8; sprite_bump_damage[j] = 4; int i = Sprite_DirectionToFaceLink(j, NULL); sprite_x_vel[j] = kFireballJunction_XYvel[i + 2]; sprite_y_vel[j] = kFireballJunction_XYvel[i]; Sprite_SetX(j, Sprite_GetX(j) + kFireballJunction_X[i]); Sprite_SetY(j, Sprite_GetY(j) + kFireballJunction_Y[i]); } } else if (sprite_delay_main[k] == 0) { if (button_b_frames && sprite_floor[k] == link_is_on_lower_level) sprite_delay_main[k] = 32; } } void Sprite_C4_Thief(int k) { // 9dc8d8 int j; Thief_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageFromLink(k); if (sprite_ai_state[k] != 3) { j = Sprite_DirectionToFaceLink(k, NULL); sprite_head_dir[k] = j; if ((j ^ sprite_D[k]) == 1) sprite_D[k] = j; } switch (sprite_ai_state[k]) { case 0: // loitering Thief_CheckCollisionWithLink(k); if (!sprite_delay_main[k]) { if ((uint16)(link_x_coord - cur_sprite_x + 0x50) < 0xa0 && (uint16)(link_y_coord - cur_sprite_y + 0x50) < 0xa0) { sprite_ai_state[k]++; sprite_delay_main[k] = 16; } } sprite_graphics[k] = kThief_Gfx[sprite_D[k]]; break; case 1: // watch player Thief_CheckCollisionWithLink(k); sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL); if (!sprite_delay_main[k]) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 32; } thief_common: if (!(frame_counter & 31)) sprite_D[k] = sprite_head_dir[k]; sprite_graphics[k] = kThief_Gfx[4 + sprite_D[k] + (++sprite_subtype2[k] & 4)]; break; case 2: // chase player Sprite_ApplySpeedTowardsLink(k, 18); if (!sprite_wallcoll[k]) Sprite_MoveXY(k); Sprite_CheckTileCollision(k); if (!sprite_delay_main[k]) { if ((uint16)(link_x_coord - cur_sprite_x + 0x50) >= 0xa0 || (uint16)(link_y_coord - cur_sprite_y + 0x50) >= 0xa0) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 128; } } if (Sprite_CheckDamageToLink(k)) { sprite_ai_state[k]++; sprite_delay_main[k] = 32; Thief_SpillItems(k); SpriteSfx_QueueSfx2WithPan(k, 0xb); } goto thief_common; case 3: // steal Thief_CheckCollisionWithLink(k); j = Thief_ScanForBooty(k); if (!sprite_delay_main[k]) { sprite_graphics[k] = kThief_Gfx[4 + sprite_D[k] + (++sprite_subtype2[k] & 4)]; if (!sprite_wallcoll[k]) Sprite_MoveXY(k); Sprite_CheckTileCollision(k); sprite_D[k] = sprite_head_dir[k]; } if (!((k ^ frame_counter) & 3)) sprite_head_dir[k] = Sprite_DirectionToFaceLocation(k, Sprite_GetX(j), Sprite_GetY(j)); break; } } uint8 Thief_ScanForBooty(int k) { // 9dca24 for (int j = 15; j >= 0; j--) { if (sprite_state[j] && (sprite_type[j] == 0xdc || sprite_type[j] == 0xe1 || sprite_type[j] == 0xd9)) { Thief_TargetBooty(k, j); return j; } } sprite_ai_state[k] = 0; sprite_delay_main[k] = 64; return 0xff; } void Thief_TargetBooty(int k, int j) { // 9dca4c if (!((k ^ frame_counter) & 3)) { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, Sprite_GetX(j), Sprite_GetY(j), 19); sprite_x_vel[k] = pt.x; sprite_y_vel[k] = pt.y; } for (j = 15; j >= 0; j--) { if (!((j ^ frame_counter) & 3 | sprite_delay_aux4[j]) && sprite_state[j] && (sprite_type[j] == 0xdc || sprite_type[j] == 0xe1 || sprite_type[j] == 0xd9)) { Thief_GrabBooty(k, j); } } } void Thief_GrabBooty(int k, int j) { // 9dca9e if ((uint16)(Sprite_GetX(j) - cur_sprite_x + 8) < 16 && (uint16)(Sprite_GetY(j) - cur_sprite_y + 12) < 24) { sprite_state[j] = 0; int t = sprite_type[j] - 0xd8; SpriteSfx_QueueSfx3WithPan(t, kAbsorptionSfx[t]); sprite_delay_main[k] = 14; } } void Thief_CheckCollisionWithLink(int k) { // 9dcaf2 if (Sprite_CheckDamageToLink_same_layer(k)) { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32); link_actual_vel_y = pt.y; sprite_y_recoil[k] = pt.y ^ 0xff; link_actual_vel_x = pt.x; sprite_x_recoil[k] = pt.x ^ 0xff; link_incapacitated_timer = 4; sprite_F[k] = 12; SpriteSfx_QueueSfx2WithPan(k, 0xb); } } void Thief_SpillItems(int k) { // 9dcb30 static const uint8 kThiefSpawn_Items[4] = {0xd9, 0xe1, 0xdc, 0xd9}; static const int8 kThiefSpawn_Xvel[6] = {0, 24, 24, 0, -24, -24}; static const int8 kThiefSpawn_Yvel[6] = {-32, -16, 16, 32, 16, -16}; tmp_counter = 5; do { byte_7E0FB6 = GetRandomNumber() & 3; int j; if (byte_7E0FB6 == 1) { j = link_num_arrows; } else if (byte_7E0FB6 == 2) { j = link_item_bombs; } else { j = link_rupees_goal; } if (!j) return; SpriteSpawnInfo info; j = Sprite_SpawnDynamicallyEx(k, kThiefSpawn_Items[byte_7E0FB6], &info, 7); if (j < 0) return; if (byte_7E0FB6 == 1) link_num_arrows--; else if (byte_7E0FB6 == 2) link_item_bombs--; else link_rupees_goal--; Sprite_SetX(j, link_x_coord); Sprite_SetY(j, link_y_coord); sprite_z_vel[j] = 0x18; sprite_x_vel[j] = kThiefSpawn_Xvel[tmp_counter]; sprite_y_vel[j] = kThiefSpawn_Yvel[tmp_counter]; sprite_delay_aux4[j] = 32; sprite_head_dir[j] = 1; sprite_stunned[j] = 255; } while (!sign8(--tmp_counter)); } void Thief_Draw(int k) { // 9dcc9e static const DrawMultipleData kThief_Dmd[24] = { {0, -6, 0x0000, 2}, {0, 0, 0x0006, 2}, {0, -6, 0x0000, 2}, {0, 0, 0x4006, 2}, {0, -6, 0x0000, 2}, {0, 0, 0x0020, 2}, {0, -7, 0x0004, 2}, {0, 0, 0x0022, 2}, {0, -7, 0x0004, 2}, {0, 0, 0x4022, 2}, {0, -7, 0x0004, 2}, {0, 0, 0x0024, 2}, {0, -8, 0x0002, 2}, {0, 0, 0x000a, 2}, {0, -7, 0x0002, 2}, {0, 0, 0x000e, 2}, {0, -7, 0x0002, 2}, {0, 0, 0x000a, 2}, {0, -8, 0x4002, 2}, {0, 0, 0x400a, 2}, {0, -7, 0x4002, 2}, {0, 0, 0x400e, 2}, {0, -7, 0x4002, 2}, {0, 0, 0x400a, 2}, }; static const uint8 kThief_DrawChar[4] = {2, 2, 0, 4}; static const uint8 kThief_DrawFlags[4] = {0x40, 0, 0, 0}; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kThief_Dmd[sprite_graphics[k] * 2], 2, &info); if (!sprite_pause[k]) { OamEnt *oam = GetOamCurPtr(); int j = sprite_head_dir[k]; oam->charnum = kThief_DrawChar[j]; oam->flags = (oam->flags & ~0x40) | kThief_DrawFlags[j]; SpriteDraw_Shadow(k, &info); } } void Sprite_C3_Gibo(int k) { // 9dcce1 if (sprite_B[k]) { SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToAndFromLink(k); sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kGibo_OamFlags[++sprite_subtype2[k] >> 2 & 3]; if (sprite_delay_main[k]) { Sprite_MoveXY(k); Sprite_BounceFromTileCollision(k); } return; } Gibo_Draw(k); if (Sprite_ReturnIfInactive(k)) return; sprite_anim_clock[k]++; int j = sprite_head_dir[k], i; if (sprite_state[j] == 6) { sprite_state[k] = sprite_state[j]; sprite_delay_main[k] = sprite_delay_main[j]; sprite_flags2[k] += 4; return; } sprite_subtype2[k] = frame_counter >> 3 & 3; if (!(frame_counter & 63)) sprite_D[k] = Sprite_IsRightOfLink(k).a << 2; Sprite_CheckDamageToLink(k); // original destroys y which is a bug switch(sprite_ai_state[k]) { case 0: // expel nucleus if (sprite_delay_main[k] == 0) { sprite_ai_state[k]++; sprite_delay_main[k] = 48; sprite_A[k]++; SpriteSpawnInfo info; j = Sprite_SpawnDynamically(k, 0xc3, &info); if (j >= 0) { static const int8 kGibo_Xvel[8] = {16, 16, 0, -16, -16, -16, 0, 16}; static const int8 kGibo_Yvel[8] = {0, 0, 16, -16, 16, 16, -16, -16}; Sprite_SetSpawnedCoordinates(j, &info); sprite_head_dir[k] = j; sprite_flags2[j] = 1; sprite_B[j] = 1; sprite_flags3[j] = 16; sprite_health[j] = sprite_G[k]; sprite_oam_flags[j] = 7; sprite_delay_main[j] = 48; if (++sprite_C[k] == 3) { sprite_C[k] = 0; i = Sprite_DirectionToFaceLink(k, NULL); } else { i = GetRandomNumber() & 7; } sprite_x_vel[j] = kGibo_Xvel[i]; sprite_y_vel[j] = kGibo_Yvel[i]; } } else if (sprite_delay_main[k] == 32) { sprite_delay_aux1[k] = 32; } break; case 1: // delay pursuit if (!sprite_delay_main[k]) sprite_ai_state[k]++; break; case 2: // pursue nucleus if (!((k ^ frame_counter) & 3)) { uint16 x = Sprite_GetX(j), y = Sprite_GetY(j); if ((uint16)(cur_sprite_x - x + 2) < 4 && (uint16)(cur_sprite_y - y + 2) < 4) { j = sprite_head_dir[k]; sprite_state[j] = 0; sprite_A[k] = 0; sprite_ai_state[k] = 0; sprite_G[k] = sprite_health[j]; sprite_delay_main[k] = (GetRandomNumber() & 31) + 32; return; } ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16); sprite_x_vel[k] = pt.x; sprite_y_vel[k] = pt.y; } Sprite_MoveXY(k); break; } } void Gibo_Draw(int k) { // 9dcf5e static const DrawMultipleData kGibo_Dmd[32] = { { 4, -4, 0x408a, 2}, {-4, -4, 0x408f, 0}, {12, 12, 0x408e, 0}, {-4, 4, 0x408c, 2}, { 4, -4, 0x40aa, 2}, {-4, -4, 0x409f, 0}, {12, 12, 0x409e, 0}, {-4, 4, 0x40ac, 2}, { 3, -3, 0x40aa, 2}, {-3, -3, 0x409f, 0}, {11, 11, 0x409e, 0}, {-3, 3, 0x40ac, 2}, { 3, -3, 0x408a, 2}, {-3, -3, 0x408f, 0}, {11, 11, 0x408e, 0}, {-3, 3, 0x408c, 2}, {-3, -4, 0x008a, 2}, {13, -4, 0x008f, 0}, {-3, 12, 0x008e, 0}, { 5, 4, 0x008c, 2}, {-3, -4, 0x00aa, 2}, {13, -4, 0x009f, 0}, {-3, 12, 0x009e, 0}, { 5, 4, 0x00ac, 2}, {-2, -3, 0x00aa, 2}, {12, -3, 0x009f, 0}, {-2, 11, 0x009e, 0}, { 4, 3, 0x00ac, 2}, {-2, -3, 0x008a, 2}, {12, -3, 0x008f, 0}, {-2, 11, 0x008e, 0}, { 4, 3, 0x008c, 2}, }; if (!sprite_A[k]) { uint8 bak0 = sprite_flags2[k]; sprite_flags2[k] = 1; uint8 bak1 = sprite_oam_flags[k]; sprite_oam_flags[k] = kGibo_OamFlags[sprite_anim_clock[k] >> 2 & 3] | kGibo_OamFlags2[sprite_delay_aux1[k] >> 2 & 1]; SpriteDraw_SingleLarge(k); sprite_oam_flags[k] = bak1; sprite_flags2[k] = bak0; } oam_cur_ptr += 8; oam_ext_cur_ptr += 2; Sprite_DrawMultiple(k, &kGibo_Dmd[(sprite_subtype2[k] + sprite_D[k]) * 4], 4, NULL); } void Sprite_C2_Boulder(int k) { // 9dcfcb if (!player_is_indoors) { Boulder_OutdoorsMain(k); return; } if (byte_7E0FC6 < 3) SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; sprite_oam_flags[k] = frame_counter << 2 & 0xc0; Sprite_MoveXYZ(k); if ((k ^ frame_counter) & 3) return; if ((uint16)(cur_sprite_x - link_x_coord + 4) < 16 && (uint16)(cur_sprite_y - link_y_coord - 4) < 12) Sprite_AttemptDamageToLinkPlusRecoil(k); if (!((k ^ frame_counter) & 3) && Sprite_CheckTileCollision(k)) sprite_state[k] = 0; } void Boulder_OutdoorsMain(int k) { // 9dd02a static const int8 kBoulder_Zvel[2] = {32, 48}; static const int8 kBoulder_Yvel[2] = {8, 32}; static const int8 kBoulder_Xvel[4] = {24, 16, -24, -16}; sprite_obj_prio[k] = 0x30; Boulder_Draw(k); if (Sprite_ReturnIfInactive(k)) return; sprite_subtype2[k] -= sprite_D[k]; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXYZ(k); sprite_z_vel[k]-=2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; int j = Sprite_CheckTileCollision(k) != 0; sprite_z_vel[k] = kBoulder_Zvel[j]; sprite_y_vel[k] = kBoulder_Yvel[j]; j += (GetRandomNumber() & 1) * 2; sprite_x_vel[k] = kBoulder_Xvel[j]; sprite_D[k] = (j & 2) - 1; SpriteSfx_QueueSfx2WithPan(k, 0xb); } } void Boulder_Draw(int k) { // 9dd185 static const DrawMultipleData kBoulder_Dmd[16] = { {-8, -8, 0x01cc, 2}, { 8, -8, 0x01ce, 2}, {-8, 8, 0x01ec, 2}, { 8, 8, 0x01ee, 2}, {-8, -8, 0x41ce, 2}, { 8, -8, 0x41cc, 2}, {-8, 8, 0x41ee, 2}, { 8, 8, 0x41ec, 2}, {-8, -8, 0xc1ee, 2}, { 8, -8, 0xc1ec, 2}, {-8, 8, 0xc1ce, 2}, { 8, 8, 0xc1cc, 2}, {-8, -8, 0x81ec, 2}, { 8, -8, 0x81ee, 2}, {-8, 8, 0x81cc, 2}, { 8, 8, 0x81ce, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kBoulder_Dmd[(sprite_subtype2[k] >> 3 & 3) * 4], 4, &info); Sprite_DrawLargeShadow2(k); } void SpriteDraw_BigShadow(int k, int anim) { // 9dd1a8 cur_sprite_y += sprite_z[k]; oam_cur_ptr += 16; oam_ext_cur_ptr += 4; Sprite_DrawMultiple(k, &kLargeShadow_Dmd[anim * 3], 3, NULL); Sprite_Get16BitCoords(k); } void Sprite_DrawLargeShadow2(int k) { // 9dd1af int z = sprite_z[k] >> 3; SpriteDraw_BigShadow(k, (z > 4) ? 4 : z); } void CutsceneAgahnim_SpawnZeldaOnAltar(int k) { // 9dd1fd sprite_x_lo[k] += 8; sprite_y_lo[k] += 6; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xc1, &info); sprite_A[j] = 1; sprite_ignore_projectile[j] = 1; Sprite_SetSpawnedCoordinates(j, &info); sprite_y_lo[j] = info.r2_y + 40; sprite_flags2[j] = 0; sprite_oam_flags[j] = 12; } void Sprite_C1_CutsceneAgahnim(int k) { // 9dd234 switch (sprite_A[k]) { case 0: CutsceneAgahnim_Agahnim(k); break; case 1: Sprite_CutsceneAgahnim_Zelda(k); break; } } void CutsceneAgahnim_Agahnim(int k) { // 9dd23f static const uint8 kChattyAgahnim_LevitateGfx[4] = {2, 0, 3, 0}; int j; PrepOamCoordsRet info; if (sprite_C[k]) { if (!sprite_delay_main[k]) sprite_state[k] = 0; if (!(sprite_delay_main[k] & 1)) ChattyAgahnim_Draw(k, &info); return; } ChattyAgahnim_Draw(k, &info); SpriteDraw_CutsceneAgahnimSpell(k, &info); if (sprite_pause[k]) { sprite_ai_state[k] = 0; sprite_B[k] = 0; sprite_graphics[k] = 0; sprite_delay_main[k] = 64; } if (Sprite_ReturnIfInactive(k)) return; switch(sprite_ai_state[k]) { case 0: // problab if (!sprite_delay_main[k]) { flag_is_link_immobilized = 1; dialogue_message_index = 0x13d; Sprite_ShowMessageMinimal(); sprite_ai_state[k]++; } break; case 1: // levitate zelda j = ++sprite_B[k]; sprite_graphics[k] = sprite_z[15] < 16 ? kChattyAgahnim_LevitateGfx[j >> 5 & 3] : 1; if ((j & 15) == 0) { sprite_graphics[15] = 1; if (++sprite_z[15] == 22) { sound_effect_2 = 0x27; sprite_ai_state[k]++; sprite_delay_main[k] = 255; sprite_subtype2[k] = 2; sprite_subtype[k] = 255; } } break; case 2: // do telewarp if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 80; } else if (sprite_delay_main[k] == 120) { intro_times_pal_flash = 120; } else if (sprite_delay_main[k] < 128 && (sprite_delay_main[k] & 3) == 0) { sound_effect_2 = 0x2b; if (sprite_subtype2[k] != 14) sprite_subtype2[k] += 4; } break; case 3: // complete telewarp if (sprite_delay_main[k]) { if (!(sprite_delay_main[k] & 3) && sprite_subtype[k] != 9) sprite_subtype[k] += 2; } else { sprite_delay_main[15] = 19; sprite_ai_state[k]++; sprite_delay_main[k] = 80; sprite_subtype2[k] = 0; sound_effect_1 = 0x33; } break; case 4: // epiblab if (!sprite_delay_main[k]) { dialogue_message_index = 0x13e; Sprite_ShowMessageMinimal(); sprite_ai_state[k]++; sprite_delay_main[k] = 2; } break; case 5: // teleport to curtains if (sprite_delay_main[k] == 1) sound_effect_2 = 0x28; sprite_y_vel[k] = -32; Sprite_MoveY(k); if (sprite_y_lo[k] < 48) { sprite_delay_aux4[k] = 66; sprite_ai_state[k]++; } Sprite_Agahnim_ApplyMotionBlur(k); break; case 6: // linger then terminate if (!sprite_delay_aux4[k]) { flag_is_link_immobilized = 0; sprite_state[k] = 0; Sprite_ManuallySetDeathFlagUW(k); dung_savegame_state_bits |= 0x4000; } break; } } int Sprite_Agahnim_ApplyMotionBlur(int k) { // 9dd392 if (frame_counter & 3) return -1; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xc1, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_graphics[j] = sprite_graphics[k]; sprite_delay_main[j] = 32; sprite_ignore_projectile[j] = 32; sprite_C[j] = 32; } return j; } void ChattyAgahnim_Draw(int k, PrepOamCoordsRet *info) { // 9dd451 static const DrawMultipleData kChattyAgahnim_Dmd[16] = { {-8, -8, 0x0b82, 2}, { 8, -8, 0x4b82, 2}, {-8, 8, 0x0ba2, 2}, { 8, 8, 0x4ba2, 2}, {-8, -8, 0x0b80, 2}, { 8, -8, 0x4b80, 2}, {-8, 8, 0x0ba0, 2}, { 8, 8, 0x4ba0, 2}, {-8, -8, 0x0b80, 2}, { 8, -8, 0x4b82, 2}, {-8, 8, 0x0ba0, 2}, { 8, 8, 0x4ba2, 2}, {-8, -8, 0x0b82, 2}, { 8, -8, 0x4b80, 2}, {-8, 8, 0x0ba2, 2}, { 8, 8, 0x4ba0, 2}, }; if (sprite_delay_aux4[k] & 1) return; if (sprite_C[k] == 0) { oam_cur_ptr = 0x900; oam_ext_cur_ptr = 0xa60; } Sprite_DrawMultiple(k, &kChattyAgahnim_Dmd[sprite_graphics[k] * 4], 4, info); SpriteDraw_Shadow_custom(k, info, 18); } void SpriteDraw_CutsceneAgahnimSpell(int k, PrepOamCoordsRet *info) { // 9dd516 static const OamEntSigned kChattyAgahnim_Telewarp_Data[28] = { {-10, -16, 0xce, 0x06}, { 18, -16, 0xce, 0x06}, { 20, -13, 0x26, 0x06}, { 20, -5, 0x36, 0x06}, {-12, -13, 0x26, 0x46}, {-12, -5, 0x36, 0x46}, { 18, 0, 0x26, 0x06}, { 18, 8, 0x36, 0x06}, {-10, 0, 0x26, 0x46}, {-10, 8, 0x36, 0x46}, { -8, 0, 0x22, 0x06}, { 8, 0, 0x22, 0x46}, { -8, 16, 0x22, 0x86}, { 8, 16, 0x22, 0xc6}, {-10, -16, 0xce, 0x04}, { 18, -16, 0xce, 0x04}, { 20, -13, 0x26, 0x44}, { 20, -5, 0x36, 0x44}, {-12, -13, 0x26, 0x04}, {-12, -5, 0x36, 0x04}, { 18, 0, 0x26, 0x44}, { 18, 8, 0x36, 0x44}, {-10, 0, 0x26, 0x04}, {-10, 8, 0x36, 0x04}, { -8, 0, 0x20, 0x04}, { 8, 0, 0x20, 0x44}, { -8, 16, 0x20, 0x84}, { 8, 16, 0x20, 0xc4}, }; static const uint8 kChattyAgahnim_Telewarp_Data_Ext[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2}; Oam_AllocateFromRegionA(0x38); const OamEntSigned *data = kChattyAgahnim_Telewarp_Data; if (!(frame_counter & 2)) data += 14; const uint8 *ext_data = kChattyAgahnim_Telewarp_Data_Ext; if (!sprite_subtype2[k]) return; OamEnt *oam = GetOamCurPtr(); uint8 kn = sprite_subtype2[k] - 1; uint8 end = sprite_subtype[k]; uint8 t = end + 1; oam += t; ext_data += t; data += t; do { oam->x = info->x + data->x; oam->y = info->y + data->y - 8; oam->charnum = data->charnum; oam->flags = data->flags | 0x31; bytewise_extended_oam[oam - oam_buf] = *ext_data; } while (data++, ext_data++, oam++, --kn != end); } void Sprite_CutsceneAgahnim_Zelda(int k) { // 9dd57d static const DrawMultipleData kAltarZelda_Dmd[4] = { {-4, 0, 0x0103, 2}, { 4, 0, 0x0104, 2}, {-4, 0, 0x0100, 2}, { 4, 0, 0x0101, 2}, }; int j = sprite_delay_main[k]; if (j != 0) { SpriteDraw_AltarZeldaWarp(k); if (j == 1) sprite_state[k] = 0; if (j < 12) return; } Oam_AllocateFromRegionA(8); PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kAltarZelda_Dmd[sprite_graphics[k] * 2], 2, &info); AltarZelda_DrawBody(k, &info); } void AltarZelda_DrawBody(int k, PrepOamCoordsRet *info) { // 9dd5e9 static const uint8 kAltarZelda_XOffs[16] = {4, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}; Oam_AllocateFromRegionA(8); int z = sprite_z[k] < 31 ? sprite_z[k] : 31; uint8 xoffs = kAltarZelda_XOffs[z >> 1]; int y = Sprite_GetY(k) - BG2VOFS_copy2; OamEnt *oam = GetOamCurPtr(); oam[0].x = info->x + xoffs; oam[1].x = info->x - xoffs; oam[0].y = oam[1].y = ClampYForOam(y + 7); oam[0].charnum = oam[1].charnum = 0x6c; oam[0].flags = oam[1].flags = 0x24; bytewise_extended_oam[oam - oam_buf] = 2; bytewise_extended_oam[oam - oam_buf + 1] = 2; } void SpriteDraw_AltarZeldaWarp(int k) { // 9dd6b1 static const DrawMultipleData kAltarZelda_Warp_Dmd[10] = { { 4, 4, 0x0480, 0}, { 4, 4, 0x0480, 0}, { 4, 4, 0x04b7, 0}, { 4, 4, 0x04b7, 0}, {-6, 0, 0x0524, 2}, { 6, 0, 0x4524, 2}, {-8, 0, 0x0524, 2}, { 8, 0, 0x4524, 2}, { 0, 0, 0x05c6, 2}, { 0, 0, 0x05c6, 2}, }; Oam_AllocateFromRegionA(8); Sprite_DrawMultiple(k, &kAltarZelda_Warp_Dmd[(sprite_delay_main[k] >> 2) * 2], 2, NULL); } void Sprite_InitializedSegmented(int k) { // 9dd6d1 for (int i = 0; i < 128; i++) { moldorm_x_lo[i] = sprite_x_lo[k]; moldorm_x_hi[i] = sprite_x_hi[k]; moldorm_y_lo[i] = sprite_y_lo[k]; moldorm_y_hi[i] = sprite_y_hi[k]; } } void GiantMoldorm_Draw(int k) { // 9dd881 PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; sprite_oam_flags[k] = 11; SpriteDraw_Moldorm_Eyeballs(k, &info); oam_cur_ptr += 8, oam_ext_cur_ptr += 2; int j = sprite_subtype2[k] & 0x7f; moldorm_x_lo[j] = sprite_x_lo[k]; moldorm_x_hi[j] = sprite_x_hi[k]; moldorm_y_lo[j] = sprite_y_lo[k]; moldorm_y_hi[j] = sprite_y_hi[k]; SpriteDraw_Moldorm_Head(k); if (sprite_B[k] < 4) { GiantMoldorm_DrawSegment_AB(k, 16); if (sprite_B[k] < 3) { GiantMoldorm_DrawSegment_AB(k, 28); if (sprite_B[k] < 2) { SpriteDraw_Moldorm_SegmentC(k); if (sprite_B[k] == 0) Moldorm_HandleTail(k); } } } GiantMoldorm_IncrementalSegmentExplosion(k); Sprite_Get16BitCoords(k); } void GiantMoldorm_IncrementalSegmentExplosion(int k) { // 9dd8f2 if (sprite_state[k] == 9 && sprite_delay_aux4[k] && sprite_delay_aux4[k] < 80 && !(sprite_delay_aux4[k] & 15 | submodule_index | flag_unk1)) { sprite_B[k]++; Sprite_MakeBossExplosion(k); } } void SpriteDraw_Moldorm_Head(int k) { // 9dd993 static const DrawMultipleData kGiantMoldorm_Head_Dmd[16] = { {-8, -8, 0x0080, 2}, { 8, -8, 0x0082, 2}, {-8, 8, 0x00a0, 2}, { 8, 8, 0x00a2, 2}, {-8, -8, 0x4082, 2}, { 8, -8, 0x4080, 2}, {-8, 8, 0x40a2, 2}, { 8, 8, 0x40a0, 2}, {-6, -6, 0x0080, 2}, { 6, -6, 0x0082, 2}, {-6, 6, 0x00a0, 2}, { 6, 6, 0x00a2, 2}, {-6, -6, 0x4082, 2}, { 6, -6, 0x4080, 2}, {-6, 6, 0x40a2, 2}, { 6, 6, 0x40a0, 2}, }; int t = (sprite_subtype2[k] >> 1 & 1) + (sprite_delay_aux1[k] & 2); Sprite_DrawMultiple(k, &kGiantMoldorm_Head_Dmd[t * 4], 4, NULL); } void SpriteDraw_Moldorm_SegmentC(int k) { // 9dda5f sprite_graphics[k] = 0; oam_cur_ptr += 0x10; oam_ext_cur_ptr += 4; GiantMoldorm_DrawSegment_C_OrTail(k, 0x28); } void Moldorm_HandleTail(int k) { // 9ddaba SpriteDraw_Moldorm_Tail(k); if (!sprite_delay_aux2[k]) { sprite_A[k] = 1; sprite_flags4[k] = 0; sprite_defl_bits[k] = 0; uint16 oldx = Sprite_GetX(k); uint16 oldy = Sprite_GetY(k); Sprite_SetX(k, cur_sprite_x); Sprite_SetY(k, cur_sprite_y); Sprite_CheckDamageFromLink(k); sprite_A[k] = 0; sprite_flags4[k] = 9; sprite_defl_bits[k] = 4; Sprite_SetX(k, oldx); Sprite_SetY(k, oldy); } } void SpriteDraw_Moldorm_Tail(int k) { // 9ddb17 oam_cur_ptr += 4; oam_ext_cur_ptr += 1; sprite_graphics[k]++; sprite_oam_flags[k] = 13; GiantMoldorm_DrawSegment_C_OrTail(k, 0x30); } void SpriteDraw_Moldorm_Eyeballs(int k, PrepOamCoordsRet *info) { // 9ddb9e static const int16 kGiantMoldorm_Eye_X[16] = {16, 15, 12, 6, 0, -6, -12, -13, -16, -13, -12, -6, 0, 6, 12, 15}; static const int16 kGiantMoldorm_Eye_Y[16] = {0, 6, 12, 15, 16, 15, 12, 6, 0, -6, -12, -13, -16, -13, -12, -6}; static const uint8 kGiantMoldorm_Eye_Char[16] = {0xaa, 0xaa, 0xa8, 0xa8, 0x8a, 0x8a, 0xa8, 0xa8, 0xaa, 0xaa, 0xa8, 0xa8, 0x8a, 0x8a, 0xa8, 0xa8}; static const uint8 kGiantMoldorm_Eye_Flags[16] = {0, 0, 0, 0, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0xc0, 0xc0, 0, 0, 0x80, 0x80}; OamEnt *oam = GetOamCurPtr(); uint8 yoff = kBadPullSwitch_Tab5[kBadPullSwitch_Tab4[sprite_graphics[k]]]; int r7 = sprite_F[k] ? frame_counter : 0; int r6 = sprite_D[k] - 1; for (int i = 1; i >= 0; i--, oam++, r6 += 2) { uint16 x = info->x + kGiantMoldorm_Eye_X[r6 & 0xf]; int y = info->y + (uint16)kGiantMoldorm_Eye_Y[r6 & 0xf]; oam->x = x; oam->y = (uint16)(y + 0x10 + ((y >> 16) & 1)) < 0x100 ? y : 0xf0; oam->charnum = kGiantMoldorm_Eye_Char[(r6 + r7) & 0xf]; oam->flags = info->flags | kGiantMoldorm_Eye_Flags[(r6 + r7) & 0xf]; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } } void Sprite_ScheduleBossForDeath(int k) { // 9ddc16 sprite_state[k] = 4; sprite_A[k] = 0; sprite_delay_main[k] = 224; } void Sprite_MakeBossExplosion(int k) { // 9ddc2a SpriteSfx_QueueSfx2WithPan(k, 0xc); Sprite_MakeBossDeathExplosion_NoSound(k); } void Sprite_MakeBossDeathExplosion_NoSound(int k) { // 9ddc30 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x00, &info); if (j >= 0) { load_chr_halfslot_even_odd = 11; sprite_state[j] = 4; sprite_flags2[j] = 3; sprite_oam_flags[j] = 12; Sprite_SetX(j, cur_sprite_x); Sprite_SetY(j, cur_sprite_y); sprite_delay_main[j] = 31; sprite_A[j] = 31; sprite_floor[j] = 2; } } void Vulture_Draw(int k) { // 9ddd5e static const DrawMultipleData kVulture_Dmd[8] = { {-8, 0, 0x0086, 2}, { 8, 0, 0x4086, 2}, {-8, 0, 0x0080, 2}, { 8, 0, 0x4080, 2}, {-8, 0, 0x0082, 2}, { 8, 0, 0x4082, 2}, {-8, 0, 0x0084, 2}, { 8, 0, 0x4084, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kVulture_Dmd[sprite_graphics[k] * 2], 2, &info); SpriteDraw_Shadow(k, &info); } void Sprite_Raven(int k) { // 9ddd85 static const uint8 kRaven_AscendTime[2] = {16, 248}; int j; bool fleeing = false; sprite_obj_prio[k] |= 0x30; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); switch (sprite_ai_state[k]) { case 0: { // inwait PairU8 r = Sprite_IsRightOfLink(k); sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | r.a * 0x40; int x = link_x_coord - cur_sprite_x; int y = link_y_coord - cur_sprite_y; if ((uint16)(x + 0x50 + (x >= 0)) < 0xa0 && (uint16)(y + 0x58 + (y >= 0)) < 0xa0) { sprite_ai_state[k]++; sprite_delay_main[k] = 24; SpriteSfx_QueueSfx3WithPan(k, 0x1e); } break; } case 1: // ascend if (!sprite_delay_main[k]) { sprite_ai_state[k]++; int j = sprite_A[k]; sprite_delay_main[k] = kRaven_AscendTime[j]; Sprite_ApplySpeedTowardsLink(k, 32); } sprite_z[k]++; sprite_graphics[k] = (frame_counter >> 1 & 1) + 1; break; case 2: // attack if (!sprite_delay_main[k] && !(is_in_dark_world && sprite_A[k]) ) sprite_ai_state[k]++; fly: if (!((k ^ frame_counter) & 1)) { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, fleeing ? 48 : 32); if (fleeing) pt.x = -pt.x, pt.y = -pt.y; if (sprite_x_vel[k] - pt.x) sprite_x_vel[k] += sign8(sprite_x_vel[k] - pt.x) ? 1 : -1; if (sprite_y_vel[k] - pt.y) sprite_y_vel[k] += sign8(sprite_y_vel[k] - pt.y) ? 1 : -1; } sprite_graphics[k] = (frame_counter >> 1 & 1) + 1; j = (sprite_x_vel[k] >> 7) & 1; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | j * 0x40; break; case 3: // flee fleeing = true; goto fly; } } void Vitreous_SpawnSmallerEyes(int k) { // 9ddecb sprite_G[k] = 9; sprite_graphics[k] = 4; SpriteSpawnInfo info; int j = Sprite_SpawnDynamicallyEx(k, 0x4, &info, 13); static const int8 kVitreous_SpawnSmallerEyes_X[13] = {8, 22, -8, -22, 0, 14, 19, 33, 26, -14, -19, -33, -26}; static const int8 kVitreous_SpawnSmallerEyes_Y[13] = {-8, -12, -8, -12, 0, -20, -1, -12, -24, -20, -1, -12, -24}; static const int8 kVitreous_SpawnSmallerEyes_Gfx[13] = {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; for (j = 13; j != 0; j--) { sprite_state[j] = 9; sprite_type[j] = 0xbe; SpritePrep_LoadProperties(j); sprite_floor[j] = 0; Sprite_SetX(j, info.r0_x + kVitreous_SpawnSmallerEyes_X[j - 1]); Sprite_SetY(j, info.r2_y + kVitreous_SpawnSmallerEyes_Y[j - 1] + 32); sprite_A[j] = sprite_x_lo[j]; sprite_B[j] = sprite_x_hi[j]; sprite_C[j] = sprite_y_lo[j]; sprite_D[j] = sprite_y_hi[j]; sprite_ignore_projectile[j] = sprite_graphics[j] = kVitreous_SpawnSmallerEyes_Gfx[j - 1]; sprite_subtype2[j] = (j - 1) * 8 + GetRandomNumber(); } } void Sprite_C0_Catfish(int k) { // 9ddf49 if (sprite_A[k] & 0x80) Sprite_Catfish_SplashOfWater(k); else if (sprite_A[k] == 0) Catfish_BigFish(k); else Sprite_Catfish_QuakeMedallion(k); } void Sprite_Catfish_QuakeMedallion(int k) { // 9ddf54 if (!sprite_z[k]) { SpriteDraw_WaterRipple_WithOamAdjust(k); if (!submodule_index && Sprite_CheckDamageToLink_same_layer(k)) { sprite_state[k] = 0; item_receipt_method = 0; Link_ReceiveItem(sprite_A[k], 0); } } if (sprite_delay_aux3[k]) Oam_AllocateFromRegionC(8); SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXYZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1; sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1; int j = sprite_ai_state[k]; if (j == 4) { sprite_x_vel[k] = 0; sprite_y_vel[k] = 0; sprite_z_vel[k] = 0; } else { sprite_ai_state[k]++; static const uint8 kStandaloneItem_Zvel[4] = {0x20, 0x10, 8, 0}; sprite_z_vel[k] = kStandaloneItem_Zvel[j]; if (j < 2 && (j = Sprite_SpawnWaterSplash(k)) >= 0) sprite_delay_main[j] = 16; } } } void Catfish_BigFish(int k) { // 9ddfd1 GreatCatfish_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch(sprite_ai_state[k]) { case 0: // AwaitSpriteThrownInCircle for (int j = 15; j >= 0; j--) { if (j == k || sprite_state[j] != 3) continue; if ((uint16)(cur_sprite_x - Sprite_GetX(j) + 32) < 64 && (uint16)(cur_sprite_y - Sprite_GetY(j) + 32) < 64) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 255; return; } } break; case 1: { // RumbleBeforeEmergence int j = sprite_delay_main[k]; if (!sprite_delay_main[k]) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 255; bg1_x_offset = 0; sound_effect_ambient = 5; sprite_z_vel[k] = 48; sprite_x_vel[k] = 0; Catfish_SpawnPlop(k); } else if (sprite_delay_main[k] < 0xc0) { if (sprite_delay_main[k] == 0xbf) sound_effect_ambient = 7; bg1_x_offset = (j & 1) ? -1 : 1; flag_is_link_immobilized = 1; } break; } case 2: { // Emerge static const uint8 kGreatCatfish_Emerge_Gfx[16] = {1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 0, 0, 0, 0}; sprite_subtype2[k]++; Sprite_MoveXYZ(k); sprite_z_vel[k] -= 2; if (sprite_z_vel[k] == (uint8)(-48)) Catfish_SpawnPlop(k); if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_ai_state[k]++; sprite_delay_main[k] = 255; } sprite_graphics[k] = kGreatCatfish_Emerge_Gfx[sprite_subtype2[k] >> 2]; break; } case 3: { // ConversateThenSubmerge int j = sprite_delay_main[k]; static const uint8 kGreatCatfish_Conversate_Gfx[20] = { 0, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6 }; if (j == 0) { sprite_state[k] = 0; } else { if (j == 160 || j == 252 || j == 4) { Sprite_SpawnWaterSplash(k); } else if (j == 10) { Catfish_SpawnPlop(k); } else if (j == 96) { flag_is_link_immobilized = 0; dialogue_message_index = link_item_quake_medallion ? 0x12b : 0x12a; Sprite_ShowMessageMinimal(); return; } else if (j == 80) { if (link_item_quake_medallion) { if (GetRandomNumber() & 1) Sprite_SpawnBomb(k); else Sprite_SpawnFireball(k); } else { Catfish_RegurgitateMedallion(k); } } if (j < 160) sprite_graphics[k] = kGreatCatfish_Conversate_Gfx[j >> 3]; } break; } } } int Sprite_SpawnBomb(int k) { // 9de144 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x4a, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); Sprite_TransmuteToBomb(j); sprite_delay_aux1[j] = 80; sprite_x_vel[j] = 24; sprite_z_vel[j] = 48; } return j; } void Catfish_RegurgitateMedallion(int k) { // 9de16c SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xc0, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_x_vel[j] = 24; sprite_z_vel[j] = 48; sprite_A[j] = 17; SpriteSfx_QueueSfx2WithPan(j, 0x20); sprite_flags2[j] = 0x83; sprite_flags3[j] = 0x58; sprite_oam_flags[j] = 0x58 & 0xf; DecodeAnimatedSpriteTile_variable(0x1c); } } void Sprite_Zora_RegurgitateFlippers(int k) { // 9de1aa SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xc0, &info); if (j < 0) return; Sprite_SetSpawnedCoordinates(j, &info); sprite_z_vel[j] = 32; sprite_y_vel[j] = 16; sprite_A[j] = 30; SpriteSfx_QueueSfx2WithPan(j, 0x20); sprite_flags2[j] = 0x83; sprite_flags3[j] = 0x54; sprite_oam_flags[j] = 0x54 & 15; sprite_delay_aux3[j] = 0x30; DecodeAnimatedSpriteTile_variable(0x11); } void Catfish_SpawnPlop(int k) { // 9de1ed SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xec, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_state[j] = 3; sprite_delay_main[j] = 15; sprite_ai_state[j] = 0; sprite_flags2[j] = 3; SpriteSfx_QueueSfx2WithPan(k, 0x28); } } int Sprite_SpawnWaterSplash(int k) { // 9de21c SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xc0, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_A[j] = 0x80; sprite_flags2[j] = 2; sprite_ignore_projectile[j] = 2; sprite_oam_flags[j] = 4; sprite_delay_main[j] = 31; } return j; } void GreatCatfish_Draw(int k) { // 9de320 static const DrawMultipleData kGreatCatfish_Dmd[28] = { {-4, 4, 0x008c, 2}, { 4, 4, 0x008d, 2}, {-4, 4, 0x008c, 2}, { 4, 4, 0x008d, 2}, {-4, -4, 0x008c, 2}, { 4, -4, 0x008d, 2}, {-4, 4, 0x009c, 2}, { 4, 4, 0x009d, 2}, {-4, -4, 0x408d, 2}, { 4, -4, 0x408c, 2}, {-4, 4, 0x409d, 2}, { 4, 4, 0x409c, 2}, {-4, -4, 0xc09d, 2}, { 4, -4, 0xc09c, 2}, {-4, 4, 0xc08d, 2}, { 4, 4, 0xc08c, 2}, {-4, 4, 0xc09d, 2}, { 4, 4, 0xc09c, 2}, {-4, 4, 0xc09d, 2}, { 4, 4, 0xc09c, 2}, { 0, 8, 0x00bd, 0}, { 8, 8, 0x40bd, 0}, { 8, 8, 0x40bd, 0}, { 8, 8, 0x40bd, 0}, {-8, 0, 0x0086, 2}, { 8, 0, 0x4086, 2}, { 8, 0, 0x4086, 2}, { 8, 0, 0x4086, 2}, }; if (sprite_graphics[k]) Sprite_DrawMultiple(k, &kGreatCatfish_Dmd[(sprite_graphics[k] - 1) * 4], 4, NULL); } void Sprite_Catfish_SplashOfWater(int k) { // 9de37d static const DrawMultipleData kWaterSplash_Dmd[8] = { {-8, -4, 0x0080, 0}, {18, -7, 0x0080, 0}, {-5, -2, 0x00bf, 0}, {15, -4, 0x40af, 0}, { 0, -4, 0x00e7, 2}, { 0, -4, 0x00e7, 2}, { 0, -4, 0x00c0, 2}, { 0, -4, 0x00c0, 2}, }; if (!sprite_delay_main[k]) sprite_state[k] = 0; Sprite_DrawMultiple(k, &kWaterSplash_Dmd[(sprite_delay_main[k] >> 3) * 2], 2, NULL); } void Sprite_BF_Lightning(int k) { // 9de3ed static const uint8 kSpriteLightning_Gfx[8] = {0, 1, 2, 3, 0, 1, 2, 3}; static const uint8 kSpriteLightning_OamFlags[8] = {0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40}; static const int8 kSpriteLightning_Xoff[64] = { -15, 0, 0, -15, 0, -15, -15, 0, -15, 0, 0, -15, 0, -15, -15, 0, 0, 15, 15, 0, 15, 0, 0, 15, 0, 15, 15, 0, 15, 0, 0, 15, 0, 15, 15, 0, 15, 0, 0, 15, 0, 15, 15, 0, 15, 0, 0, 15, -15, 0, 0, -15, 0, -15, -15, 0, -15, 0, 0, -15, 0, -15, -15, 0, }; int j = sprite_A[k]; sprite_oam_flags[k] = sprite_oam_flags[k] & 0xb1 | kSpriteLightning_OamFlags[j] | frame_counter << 1 & 14; sprite_graphics[k] = kSpriteLightning_Gfx[j] + (BYTE(dungeon_room_index2) == 0x20 ? 4 : 0); SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_delay_main[k]) return; Lightning_SpawnGarnish(k); sprite_delay_main[k] = 2; Sprite_SetY(k, Sprite_GetY(k) + 16); if ((uint8)(sprite_y_lo[k] - BG2VOFS_copy2) >= 0xd0) { sprite_state[k] = 0; return; } int rr = GetRandomNumber() & 7; Sprite_SetX(k, Sprite_GetX(k) + kSpriteLightning_Xoff[sprite_A[k] << 3 | rr]); sprite_A[k] = rr; } void Lightning_SpawnGarnish(int k) { // 9de475 int j = GarnishAllocOverwriteOld(); garnish_type[j] = 9; garnish_active = 9; garnish_sprite[j] = sprite_A[k]; garnish_x_lo[j] = sprite_x_lo[k]; garnish_x_hi[j] = sprite_x_hi[k]; int y = Sprite_GetY(k) + 16; garnish_y_lo[j] = y; garnish_y_hi[j] = y >> 8; garnish_countdown[j] = 32; } void Sprite_BD_Vitreous(int k) { // 9de4c8 if (sprite_delay_aux4[k]) sprite_graphics[k] = 3; Vitreous_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Vitreous_SetMinionsForth(k); Sprite_CheckDamageToAndFromLink(k); switch(sprite_ai_state[k]) { case 0: // dormant byte_7E0FF8 = 0; sprite_F[k] = 0; sprite_flags3[k] |= 64; if (!(frame_counter & 1) && !--sprite_A[k]) { sprite_flags3[k] &= ~0x40; sprite_delay_aux4[k] = 16; sprite_ai_state[k] = 1; sprite_delay_main[k] = 128; if (!sprite_G[k]) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 64; sprite_ignore_projectile[k] = 0; sound_effect_1 = 0x35; return; } } sprite_graphics[k] = frame_counter & 0x30 ? 4 : 5; break; case 1: // spew lighting sprite_F[k] = 0; if (!sprite_delay_main[k]) { static const uint8 kVitreous_AfromG[10] = {0x20, 0x20, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0}; sprite_delay_aux4[k] = 16; sprite_ai_state[k] = 0; sprite_A[k] = kVitreous_AfromG[sprite_G[k]]; } else { Vitreous_Animate(k, sprite_delay_main[k]); } break; case 2: // pursue player Vitreous_Animate(k, 0x8B); if (Sprite_ReturnIfRecoiling(k)) return; if (sprite_delay_main[k]) { static const int8 kVitreous_Xvel[2] = {8, -8}; sprite_x_vel[k] = kVitreous_Xvel[(sprite_delay_main[k] & 2) >> 1]; Sprite_MoveX(k); } else { Sprite_MoveXYZ(k); Sprite_CheckTileCollision(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = 32; Sprite_ApplySpeedTowardsLink(k, 16); SpriteSfx_QueueSfx2WithPan(k, 0x21); } } break; } } void Vitreous_Animate(int k, uint8 a) { // 9de563 static const int8 kVitreous_Animate_Gfx[2] = {2, 1}; if (a == 0x40 || a == 0x41 || a == 0x42) Sprite_SpawnLightning(k); sprite_graphics[k] = 0; PairU8 pair = Sprite_IsRightOfLink(k); if ((uint8)(pair.b + 16) >= 32) sprite_graphics[k] = kVitreous_Animate_Gfx[pair.a]; } void Vitreous_SetMinionsForth(int k) { // 9de5da static const uint8 kVitreous_WhichToActivate[16] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 5, 6, 7, 8, 9, 10, 11}; if (!(++sprite_subtype2[k] & 63)) { int j = kVitreous_WhichToActivate[GetRandomNumber() & 15]; if (sprite_ai_state[j] == 0) { sprite_ai_state[j] = 1; sound_effect_1 = 0x15; } else { sprite_subtype2[k]--; } } } void Sprite_SpawnLightning(int k) { // 9de612 static const int8 kAgahnim_Lighting_X[8] = {-8, 8, 8, -8, 8, -8, -8, 8}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xBF, &info), i; if (j >= 0) { sound_effect_2 = 0x26; Sprite_SetSpawnedCoordinates(j, &info); sprite_A[j] = i = GetRandomNumber() & 7; int t = info.r0_x + (uint16)kAgahnim_Lighting_X[i]; Sprite_SetX(j, info.r0_x + kAgahnim_Lighting_X[i]); sprite_y_lo[j] = info.r2_y + 12 + (t >> 16); sprite_delay_main[j] = 2; intro_times_pal_flash = 32; } } void Vitreous_Draw(int k) { // 9de716 static const DrawMultipleData kVitreous_Dmd[24] = { {-8, -8, 0x01c0, 2}, { 8, -8, 0x41c0, 2}, {-8, 8, 0x01e0, 2}, { 8, 8, 0x41e0, 2}, {-8, -8, 0x01c8, 2}, { 8, -8, 0x01ca, 2}, {-8, 8, 0x01e8, 2}, { 8, 8, 0x01ea, 2}, {-8, -8, 0x41ca, 2}, { 8, -8, 0x41c8, 2}, {-8, 8, 0x41ea, 2}, { 8, 8, 0x41e8, 2}, {-8, -8, 0x01c2, 2}, { 8, -8, 0x41c2, 2}, {-8, 8, 0x01e2, 2}, { 8, 8, 0x41e2, 2}, {-8, -8, 0x01c4, 2}, { 8, -8, 0x41c4, 2}, {-8, 8, 0x01e4, 2}, { 8, 8, 0x41e4, 2}, {-7, -7, 0x01c4, 2}, { 7, -7, 0x41c4, 2}, {-7, 7, 0x01e4, 2}, { 7, 7, 0x41e4, 2}, }; if (sprite_ai_state[k] == 2 && sprite_state[k] == 9) oam_cur_ptr = 0x800, oam_ext_cur_ptr = 0xa20; Sprite_DrawMultiple(k, &kVitreous_Dmd[sprite_graphics[k] * 4], 4, NULL); if (sprite_ai_state[k] == 2) { sprite_obj_prio[k] &= ~0xe; Sprite_DrawLargeShadow2(k); } } void Sprite_BE_VitreousEye(int k) { // 9de773 static const int8 kSprite_Vitreolus_Dx[4] = {1, 0, -1, 0}; static const int8 kSprite_Vitreolus_Dy[4] = {0, 1, 0, -1}; int j = sprite_subtype2[k] >> 4 & 3; cur_sprite_x += kSprite_Vitreolus_Dx[j]; cur_sprite_y += kSprite_Vitreolus_Dy[j]; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; sprite_subtype2[k]++; if (sprite_graphics[k]) return; Sprite_CheckDamageFromLink(k); Sprite_CheckDamageToLink(k); if (sprite_F[k] == 14) sprite_F[k] = 5; switch (sprite_ai_state[k]) { case 0: // target player sprite_G[k] = link_x_coord; sprite_head_dir[k] = link_x_coord >> 8; sprite_anim_clock[k] = link_y_coord; sprite_subtype[k] = link_y_coord >> 8; break; case 1: // pursue player if (Sprite_ReturnIfRecoiling(k)) return; if (!((k ^ frame_counter) & 1)) { uint16 x = sprite_head_dir[k] << 8 | sprite_G[k]; uint16 y = sprite_subtype[k] << 8 | sprite_anim_clock[k]; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16); sprite_x_vel[k] = pt.x; sprite_y_vel[k] = pt.y; } Sprite_MoveXY(k); if ((uint8)(sprite_G[k] - sprite_x_lo[k] + 4) < 8 && (uint8)(sprite_anim_clock[k] - sprite_y_lo[k] + 4) < 8) sprite_ai_state[k] = 2; break; case 2: // return if (Sprite_ReturnIfRecoiling(k)) return; if (!((k ^ frame_counter) & 1)) { uint16 x = sprite_A[k] | sprite_B[k] << 8; uint16 y = sprite_C[k] | sprite_D[k] << 8; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16); sprite_x_vel[k] = pt.x; sprite_y_vel[k] = pt.y; } Sprite_MoveXY(k); if ((uint8)(sprite_A[k] - sprite_x_lo[k] + 4) < 8 && (uint8)(sprite_C[k] - sprite_y_lo[k] + 4) < 8) { sprite_x_lo[k] = sprite_A[k]; sprite_x_hi[k] = sprite_B[k]; sprite_y_lo[k] = sprite_C[k]; sprite_y_hi[k] = sprite_D[k]; sprite_ai_state[k] = 0; } break; } } void HelmasaurFireball_TriSplit(int k) { // 9deed3 static const int8 kHelmasaurFireball_TriSplit_Xvel[3] = {0, 28, -28}; static const int8 kHelmasaurFireball_TriSplit_Yvel[3] = {-32, 24, 24}; static const uint8 kHelmasaurFireball_TriSplit_Delay[6] = {32, 80, 128, 32, 80, 128}; SpriteSfx_QueueSfx3WithPan(k, 0x36); sprite_state[k] = 0; byte_7E0FB6 = GetRandomNumber(); for (int i = 2; i >= 0; i--) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x70, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_x_vel[j] = kHelmasaurFireball_TriSplit_Xvel[i]; sprite_y_vel[j] = kHelmasaurFireball_TriSplit_Yvel[i]; sprite_ai_state[j] = 3; sprite_ignore_projectile[j] = 3; sprite_delay_main[j] = kHelmasaurFireball_TriSplit_Delay[(byte_7E0FB6 & 3) + i]; sprite_head_dir[j] = 0; sprite_graphics[j] = 1; } } tmp_counter = -1; } void HelmasaurFireball_QuadSplit(int k) { // 9def3d static const int8 kHelmasaurFireball_QuadSplit_Xvel[4] = {32, 32, -32, -32}; static const int8 kHelmasaurFireball_QuadSplit_Yvel[4] = {-32, 32, -32, 32}; SpriteSfx_QueueSfx3WithPan(k, 0x36); sprite_state[k] = 0; for (int i = 3; i >= 0; i--) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x70, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_x_vel[j] = kHelmasaurFireball_QuadSplit_Xvel[i]; sprite_y_vel[j] = kHelmasaurFireball_QuadSplit_Yvel[i]; sprite_ai_state[j] = 4; sprite_ignore_projectile[j] = 4; } } tmp_counter = -1; } void Sprite_ArmosCrusher(int k) { // 9def7e sprite_oam_flags[k] = 7; bg1_y_offset = sprite_delay_aux4[k] ? (sprite_delay_aux4[k] & 1 ? -1 : 1) : 0; switch (sprite_G[k]) { case 0: // retarget Sprite_CheckDamageToAndFromLink(k); if (!(sprite_delay_main[k] | sprite_z[k])) { Sprite_ApplySpeedTowardsLink(k, 32); sprite_z_vel[k] = 32; sprite_G[k]++; sprite_B[k] = link_x_coord; sprite_C[k] = link_x_coord >> 8; sprite_E[k] = link_y_coord; sprite_head_dir[k] = link_y_coord >> 8; SpriteSfx_QueueSfx2WithPan(k, 0x20); } break; case 1: // approach target sprite_z_vel[k] += 3; if (Sprite_CheckTileCollision(k)) goto advance; Sprite_Get16BitCoords(k); uint16 x, y; x = sprite_B[k] | sprite_C[k] << 8; y = sprite_E[k] | sprite_head_dir[k] << 8; if ((uint16)(x - cur_sprite_x + 16) < 32 && (uint16)(y - cur_sprite_y + 16) < 32) { advance: sprite_G[k]++; sprite_delay_main[k] = 16; sprite_x_vel[k] = 0; sprite_y_vel[k] = 0; } break; case 2: // hover sprite_z_vel[k] = 0; if (!sprite_delay_main[k]) sprite_G[k]++; break; case 3: // crush sprite_z_vel[k] = -104; if (!sign8(sprite_z[k])) { sprite_delay_main[k] = 32; sprite_delay_aux4[k] = 32; sprite_G[k] = 0; SpriteSfx_QueueSfx2WithPan(k, 0xc); } break; } } void Sprite_EvilBarrier(int k) { // 9df06b EvilBarrier_Draw(k); if (sprite_graphics[k] == 4) return; sprite_graphics[k] = frame_counter >> 1 & 3; if (Sprite_ReturnIfInactive(k)) return; if (Sprite_CheckDamageFromLink(k) && link_sword_type < 2) { sprite_hit_timer[k] = 0; Sprite_AttemptDamageToLinkPlusRecoil(k); if (!countdown_for_blink) link_electrocute_on_touch = 64; } if ((uint16)(link_y_coord - cur_sprite_y + 8) < 24 && (uint16)(link_x_coord - cur_sprite_x + 32) < 64 && sign8(link_actual_vel_y - 1)) { link_electrocute_on_touch = 64; link_incapacitated_timer = 12; link_auxiliary_state = 1; link_give_damage = 2; link_actual_vel_x = 0; link_actual_vel_y = 48; } } void EvilBarrier_Draw(int k) { // 9df249 static const DrawMultipleData kEvilBarrier_Dmd[45] = { { 0, 0, 0x00e8, 2}, {-29, 3, 0x00ca, 0}, {-29, 11, 0x00da, 0}, { 37, 3, 0x40ca, 0}, { 37, 11, 0x40da, 0}, {-24, -2, 0x00e6, 2}, { -8, -2, 0x00e6, 2}, { 8, -2, 0x40e6, 2}, { 24, -2, 0x40e6, 2}, { 0, 0, 0x00cc, 2}, {-29, 3, 0x00cb, 0}, {-29, 11, 0x00db, 0}, { 37, 3, 0x40cb, 0}, { 37, 11, 0x40db, 0}, { 0, 0, 0x00cc, 2}, { 0, 0, 0x00cc, 2}, { 0, 0, 0x00cc, 2}, { 0, 0, 0x00cc, 2}, { 0, 0, 0x00cc, 2}, {-29, 3, 0x00cb, 0}, {-29, 11, 0x00db, 0}, { 37, 3, 0x40cb, 0}, { 37, 11, 0x40db, 0}, {-24, -2, 0x80e6, 2}, { -8, -2, 0x80e6, 2}, { 8, -2, 0xc0e6, 2}, { 24, -2, 0xc0e6, 2}, { 0, 0, 0x00e8, 2}, {-29, 3, 0x00ca, 0}, {-29, 11, 0x00da, 0}, { 37, 3, 0x40ca, 0}, { 37, 11, 0x40da, 0}, { 0, 0, 0x00e8, 2}, { 0, 0, 0x00e8, 2}, { 0, 0, 0x00e8, 2}, { 0, 0, 0x00e8, 2}, {-29, 3, 0x00cb, 0}, {-29, 11, 0x00db, 0}, { 37, 3, 0x40cb, 0}, { 37, 11, 0x40db, 0}, { 37, 11, 0x40db, 0}, { 37, 11, 0x40db, 0}, { 37, 11, 0x40db, 0}, { 37, 11, 0x40db, 0}, { 37, 11, 0x40db, 0}, }; cur_sprite_y += 8; Sprite_DrawMultiple(k, &kEvilBarrier_Dmd[sprite_graphics[k] * 9], 9, NULL); Sprite_Get16BitCoords(k); } void SpriteDraw_Antfairy(int k) { // 9df395 static const DrawMultipleData kDrawFourAroundOne_Dmd[30] = { { 4, 2, 0x02e1, 0}, { 4, -3, 0x02e3, 0}, {-1, 2, 0x02e3, 0}, { 9, 2, 0x02e3, 0}, { 4, 7, 0x02e3, 0}, { 4, 2, 0x02e1, 0}, { 3, -3, 0x02e3, 0}, { 9, 1, 0x02e3, 0}, {-1, 3, 0x02e3, 0}, { 5, 7, 0x02e3, 0}, { 4, 2, 0x02e1, 0}, { 1, -3, 0x02e3, 0}, { 9, -1, 0x02e3, 0}, {-1, 5, 0x02e3, 0}, { 7, 7, 0x02e3, 0}, { 4, 2, 0x02e1, 0}, { 0, -2, 0x02e3, 0}, { 8, -2, 0x02e3, 0}, { 0, 6, 0x02e3, 0}, { 8, 6, 0x02e3, 0}, { 4, 2, 0x02e1, 0}, { 7, -3, 0x02e3, 0}, {-1, -1, 0x02e3, 0}, { 9, 5, 0x02e3, 0}, { 1, 7, 0x02e3, 0}, { 4, 2, 0x02e1, 0}, { 5, -3, 0x02e3, 0}, {-1, 1, 0x02e3, 0}, { 9, 3, 0x02e3, 0}, { 3, 7, 0x02e3, 0}, }; if (!(++sprite_subtype2[k] & 1 | submodule_index | flag_unk1)) { if (++sprite_graphics[k] == 6) sprite_graphics[k] = 0; } Sprite_DrawMultiple(k, &kDrawFourAroundOne_Dmd[sprite_graphics[k] * 5], 5, NULL); } void Toppo_Flustered(int k) { // 9df3d4 sprite_flags2[k] = 130; sprite_ignore_projectile[k] = 130; sprite_flags3[k] = 73; if (!sprite_subtype[k]) { if (Sprite_CheckDamageToLink(k)) { dialogue_message_index = 0x174; Sprite_ShowMessageMinimal(); sprite_subtype2[k] = 1; } } else if (sprite_subtype[k] < 10) { sprite_subtype[k]++; } else if (sprite_subtype[k] == 10) { sprite_flags5[k] = 0; sprite_state[k] = 6; sprite_delay_main[k] = 15; sprite_flags2[k] += 4; SpriteSfx_QueueSfx2WithPan(k, 0x15); SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x4d, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); ForcePrizeDrop(j, 6, 6); } sprite_subtype[k]++; } sprite_graphics[k] = ((++sprite_subtype2[k] & 4) >> 2) + 3; } void Goriya_Draw(int k) { // 9df589 static const DrawMultipleData kGoriya_Dmd2[3] = { {10, 4, 0x4077, 0}, {-2, 4, 0x0077, 0}, { 4, 4, 0x0076, 0}, }; static const DrawMultipleData kGoriya_Dmd[32] = { {-4, -8, 0x0044, 2}, {12, -8, 0x4044, 0}, {-4, 8, 0x0064, 0}, { 4, 0, 0x4054, 2}, {-4, -8, 0x0044, 2}, {12, -8, 0x4044, 0}, {-4, 8, 0x4074, 0}, { 4, 0, 0x4062, 2}, {-4, -8, 0x0044, 0}, { 4, -8, 0x4044, 2}, {-4, 0, 0x0062, 2}, {12, 8, 0x4064, 0}, {-4, -8, 0x0046, 2}, {12, -8, 0x4046, 0}, {-4, 8, 0x0066, 0}, { 4, 0, 0x4056, 2}, {-4, -8, 0x0046, 2}, {12, -8, 0x4046, 0}, {-4, 8, 0x4075, 0}, { 4, 0, 0x406a, 2}, {-4, -8, 0x0046, 0}, { 4, -8, 0x4046, 2}, {-4, 0, 0x006a, 2}, {12, 8, 0x0075, 0}, {-2, -8, 0x004e, 2}, { 0, 0, 0x006c, 2}, {-2, -7, 0x004e, 2}, { 0, 0, 0x006e, 2}, { 2, -8, 0x404e, 2}, { 0, 0, 0x406c, 2}, { 2, -7, 0x404e, 2}, { 0, 0, 0x406e, 2}, }; static const uint8 kGoriyaDmdOffs[] = { 0, 4, 8, 12, 16, 20, 24, 26, 28, 30, 32 }; if (sprite_delay_aux1[k] && sprite_D[k] != 3) Sprite_DrawMultiple(k, &kGoriya_Dmd2[sprite_D[k]], 1, NULL); PrepOamCoordsRet info; oam_cur_ptr += 4, oam_ext_cur_ptr++; int g = sprite_graphics[k]; Sprite_DrawMultiple(k, &kGoriya_Dmd[kGoriyaDmdOffs[g]], kGoriyaDmdOffs[g + 1] - kGoriyaDmdOffs[g], &info); sprite_flags2[k]--; SpriteDraw_Shadow(k, &info); sprite_flags2[k]++; } void Moldorm_Draw(int k) { // 9df822 static const int8 kMoldorm_Draw_X[16] = {11, 10, 9, 6, 3, 0, -2, -3, -4, -3, -2, 1, 4, 7, 9, 10}; static const int8 kMoldorm_Draw_Y[16] = {4, 6, 9, 10, 11, 10, 9, 6, 3, 0, -2, -3, -4, -3, -2, 1}; static const uint8 kMoldorm_Draw_Char[3] = {0x5d, 0x62, 0x60}; static const int8 kMoldorm_Draw_XY[3] = {4, 0, 0}; static const uint8 kMoldorm_Draw_Ext[3] = {0, 2, 2}; static const uint8 kMoldorm_Draw_GetOffs[3] = {21, 26, 0}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); uint8 base = sprite_D[k] - 1; for (int i = 1; i >= 0; i--, oam++, base += 2) { uint16 x = info.x + kMoldorm_Draw_X[base & 0xf]; int y = info.y + (uint16)kMoldorm_Draw_Y[base & 0xf]; oam->x = x; oam->y = (uint16)(y + 0x10 + ((y >> 16) & 1)) < 0x100 ? y : 0xf0; oam->charnum = 0x4D; oam->flags = info.flags; bytewise_extended_oam[oam - oam_buf] = (x >> 8 & 1); } oam_cur_ptr += 8; oam_ext_cur_ptr += 2; int j = (sprite_subtype2[k] & 0x1f) + k * 32; moldorm_x_lo[j] = sprite_x_lo[k]; moldorm_x_hi[j] = sprite_x_hi[k]; moldorm_y_lo[j] = sprite_y_lo[k]; moldorm_y_hi[j] = sprite_y_hi[k]; for (int i = 2; i >= 0; i--, oam++) { j = ((sprite_subtype2[k] + kMoldorm_Draw_GetOffs[i]) & 0x1f) + k * 32; uint16 x = (moldorm_x_lo[j] | moldorm_x_hi[j] << 8) - BG2HOFS_copy2 + kMoldorm_Draw_XY[i]; uint16 y = (moldorm_y_lo[j] | moldorm_y_hi[j] << 8) - BG2VOFS_copy2 + kMoldorm_Draw_XY[i]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kMoldorm_Draw_Char[i]; oam->flags = info.flags; bytewise_extended_oam[oam - oam_buf] = kMoldorm_Draw_Ext[i] | (x >> 8 & 1); } } void TalkingTree_Mouth(int k) { // 9df956 static const int8 kTalkingTree_Gfx2[4] = {0, 2, 3, 1}; int j; TalkingTree_Draw(k); if (Sprite_ReturnIfInactive(k)) return; sprite_flags4[k] = 0; switch(sprite_ai_state[k]) { case 0: sprite_graphics[k] = 0; if (Sprite_CheckDamageToLink_same_layer(k)) { Link_CancelDash(); link_incapacitated_timer = 16; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 48); link_actual_vel_y = pt.y; link_actual_vel_x = pt.x; SpriteSfx_QueueSfx3WithPan(k, 0x32); sprite_ai_state[k]++; sprite_delay_main[k] = 48; } break; case 1: if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 8; } sprite_graphics[k] = sprite_delay_main[k] >> 1 & 3; break; case 2: sprite_graphics[k] = kTalkingTree_Gfx2[sprite_delay_main[k] >> 1]; // zelda bug wtf if (sprite_delay_main[k] == 7) TalkingTree_SpawnBomb(k); if (!sprite_delay_main[k]) sprite_ai_state[k]++; break; case 3: sprite_flags4[k] = 7; if (!sprite_A[k]) { static const uint8 kTalkingTree_Msgs2[2] = { 0x82, 0x7d }; j = sprite_x_lo[k] >> 4 & 1 ^ 1; sprite_A[k] = j; if (!(Sprite_ShowSolicitedMessage(k, kTalkingTree_Msgs2[j]) & 0x100)) sprite_A[k] = 0; } else { static const uint8 kTalkingTree_Msgs[4] = {0x7e, 0x7f, 0x80, 0x81}; static const uint8 kTalkingTree_Screens[4] = {0x58, 0x5d, 0x72, 0x6b}; j = FindInByteArray(kTalkingTree_Screens, BYTE(overworld_screen_index), 4); Sprite_ShowMessageUnconditional(kTalkingTree_Msgs[j]); sprite_A[k] = 0; } if (!sprite_delay_main[k]) { static const uint8 kTalkingTree_Gfx[8] = { 1, 2, 3, 1, 3, 1, 2, 3 }; static const uint8 kTalkingTree_Delay[8] = { 13, 13, 13, 11, 11, 6, 16, 8 }; sprite_B[k] = j = sprite_B[k] + 1 & 7; sprite_graphics[k] = kTalkingTree_Gfx[j]; sprite_delay_main[k] = kTalkingTree_Delay[j]; } break; } } void TalkingTree_SpawnBomb(int k) { // 9dfa4e SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x4a, &info); if (j >= 0) { Sprite_TransmuteToBomb(j); Sprite_SetSpawnedCoordinates(j, &info); sprite_delay_aux1[j] = 64; sprite_y_vel[j] = 24; sprite_z_vel[j] = 18; } } void TalkingTree_Draw(int k) { // 9dfadb static const DrawMultipleData kTalkingTree_Dmd[12] = { {1, -1, 0x00e8, 0}, {1, 7, 0x00f8, 0}, {7, -1, 0x40e8, 0}, {7, 7, 0x40f8, 0}, {0, -1, 0x00e8, 0}, {0, 7, 0x00f8, 0}, {8, -1, 0x40e8, 0}, {8, 7, 0x40f8, 0}, {0, 0, 0x00e8, 0}, {0, 7, 0x00f8, 0}, {8, 0, 0x40e8, 0}, {8, 7, 0x40f8, 0}, }; int g = sprite_graphics[k] - 1; if (g < 0) return; Sprite_DrawMultiplePlayerDeferred(k, &kTalkingTree_Dmd[g * 4], 4, NULL); } void TalkingTree_Eye(int k) { // 9dfb0a static const int8 kTalkingTree_Type1_X[2] = {9, -9}; SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; int j = sprite_head_dir[k]; Sprite_SetX(k, (sprite_A[k] | sprite_B[k] << 8) + kTalkingTree_Type1_X[j]); Sprite_SetY(k, (sprite_C[k] | sprite_E[k] << 8)); ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 2); if (!sign8(pt.y)) { sprite_D[k] = pt.x + 2; } else if (sprite_D[k] != 2) { sprite_D[k] += (sprite_D[k] >= 2) ? -1 : 1; } static const int8 kTalkingTree_X1[5] = {-2, -1, 0, 1, 2}; static const int8 kTalkingTree_Y1[5] = {-1, 0, 0, 0, -1}; j = sprite_D[k]; Sprite_SetX(k, (sprite_A[k] | sprite_B[k] << 8) + kTalkingTree_X1[j]); Sprite_SetY(k, (sprite_C[k] | sprite_E[k] << 8) + kTalkingTree_Y1[j]); } void SpritePrep_TalkingTree_SpawnEyeball(int k, int dir) { // 9dfb8a static const int8 kTalkingTree_SpawnX[2] = {-4, 14}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x25, &info); if (j >= 0) { sprite_head_dir[j] = dir; int x = info.r0_x + kTalkingTree_SpawnX[dir]; int y = info.r2_y - 11; Sprite_SetX(j, x); Sprite_SetY(j, y); sprite_A[j] = x; sprite_B[j] = x >> 8; sprite_C[j] = y; sprite_E[j] = y >> 8; sprite_subtype2[j] = 1; } } void RupeePull_SpawnPrize(int k) { // 9dfbd7 static const int8 kSpawnRupees_Xvel[4] = {-18, -12, 12, 18}; static const int8 kSpawnRupees_Yvel[4] = {16, 24, 24, 16}; static const uint8 kSpawnRupees_Type[3] = {0xd9, 0xda, 0xdb}; if (num_sprites_killed) { byte_7E0FB6 = num_sprites_killed < 4 ? 0 : number_of_times_hurt_by_sprites ? 1 : 2; tmp_counter = 3; do { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, kSpawnRupees_Type[byte_7E0FB6], &info); if (j < 0) break; Sprite_SetSpawnedCoordinates(j, &info); sprite_x_vel[j] = kSpawnRupees_Xvel[tmp_counter]; sprite_y_vel[j] = kSpawnRupees_Yvel[tmp_counter]; sprite_stunned[j] = 255; sprite_delay_aux4[j] = 32; sprite_delay_aux3[j] = 32; sprite_z_vel[j] = 32; } while (!sign8(--tmp_counter)); } num_sprites_killed = 0; number_of_times_hurt_by_sprites = 0; } void Sprite_D5_DigGameGuy(int k) { // 9dfc38 DiggingGameGuy_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); Sprite_MoveXY(k); sprite_x_vel[k] = 0; switch(sprite_ai_state[k]) { case 0: // intro if ((uint8)(sprite_y_lo[k] + 7) < BYTE(link_y_coord) && Sprite_DirectionToFaceLink(k, NULL) == 2) { if (savegame_tagalong == 0) { if (Sprite_ShowSolicitedMessage(k, 0x187) & 0x100) sprite_ai_state[k]++; } else { Sprite_ShowSolicitedMessage(k, 0x18c); } } break; case 1: // do you want to play if (choice_in_multiselect_box == 0 && link_rupees_goal >= 80) { link_rupees_goal -= 80; Sprite_ShowMessageUnconditional(0x188); sprite_ai_state[k] = 2; sprite_graphics[k] = 1; sprite_delay_main[k] = 80; beamos_x_hi[0] = 0; beamos_x_hi[1] = 0; sprite_delay_aux1[k] = 5; Sprite_InitializeSecondaryItemMinigame(1); music_control = 14; } else { Sprite_ShowMessageUnconditional(0x189); sprite_ai_state[k] = 0; } break; case 2: // move out of the way if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_graphics[k] = 1; } else if (!sprite_delay_aux1[k]) { sprite_graphics[k] ^= 3; if (sprite_graphics[k] & 1) sprite_x_vel[k] = -16; sprite_delay_aux1[k] = 5; } break; case 3: // start timer sprite_ai_state[k]++; super_bomb_indicator_unk1 = 0; super_bomb_indicator_unk2 = 30; break; case 4: // terminate if ((int8)super_bomb_indicator_unk2 > 0 || link_position_mode & 1) return; music_control = 9; sprite_ai_state[k]++; byte_7E03FC = 0; dialogue_message_index = 0x18a; Sprite_ShowMessageMinimal(); super_bomb_indicator_unk2 = 254; break; case 5: // come back later Sprite_ShowSolicitedMessage(k, 0x18b); break; } } void DiggingGameGuy_Draw(int k) { // 9dfe4b static const DrawMultipleData kDiggingGameGuy_Dmd[9] = { { 0, -8, 0x0a40, 2}, { 4, 9, 0x0c56, 0}, { 0, 0, 0x0a42, 2}, { 0, -8, 0x0a40, 2}, { 0, 0, 0x0a42, 2}, { 0, 0, 0x0a42, 2}, {-1, -7, 0x0a40, 2}, {-1, 0, 0x0a44, 2}, {-1, 0, 0x0a44, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kDiggingGameGuy_Dmd[sprite_graphics[k] * 3], 3, &info); SpriteDraw_Shadow(k, &info); } void OldMountainMan_Draw(int k) { // 9dff0e static const DrawMultipleData kOldMountainMan_Dmd0[2] = { {0, 0, 0x00ac, 2}, {0, 8, 0x00ae, 2}, }; static const DrawMultipleData kOldMountainMan_Dmd1[16] = { { 0, 0, 0x0120, 2}, { 0, 8, 0x0122, 2}, { 0, 1, 0x0120, 2}, { 0, 9, 0x4122, 2}, { 0, 0, 0x0120, 2}, { 0, 8, 0x0122, 2}, { 0, 1, 0x0120, 2}, { 0, 9, 0x4122, 2}, {-2, 0, 0x0120, 2}, { 0, 8, 0x0122, 2}, {-2, 1, 0x0120, 2}, { 0, 9, 0x0122, 2}, { 2, 0, 0x4120, 2}, { 0, 8, 0x4122, 2}, { 2, 1, 0x4120, 2}, { 0, 9, 0x4122, 2}, }; static const uint8 kOldMountainMan_Dma[16] = {0x20, 0xc0, 0x20, 0xc0, 0, 0xa0, 0, 0xa0, 0x40, 0x80, 0x40, 0x60, 0x40, 0x80, 0x40, 0x60}; if (sprite_subtype2[k] != 2) { int j = sprite_D[k] * 4 + sprite_graphics[k] * 2; BYTE(dma_var6) = kOldMountainMan_Dma[j + 0]; BYTE(dma_var7) = kOldMountainMan_Dma[j + 1]; Sprite_DrawMultiplePlayerDeferred(k, &kOldMountainMan_Dmd1[j], 2, NULL); } else { Sprite_DrawMultiplePlayerDeferred(k, kOldMountainMan_Dmd0, 2, NULL); } } void HelmasaurKing_Initialize(int k) { // 9e8000 overlord_gen1[7] = 0x30; overlord_gen1[5] = 0x80; overlord_gen1[6] = 0; overlord_gen2[0] = 0; overlord_gen2[3] = 0; overlord_gen2[1] = 0; overlord_gen2[2] = 0; HelmasaurKing_Reinitialize(k); } void HelmasaurKing_Reinitialize(int k) { // 9e8019 uint8 t = sprite_subtype2[k]; for (int i = 3; i >= 0; i--) { overlord_x_lo[i] = kHelmasaur_Tab0[t + i * 8 & 0x1f]; } } void Sprite_92_HelmasaurKing(int k) { // 9e8039 int t, j; if (sign8(sprite_C[k])) { if (sprite_delay_main[k] == 1) sprite_state[k] = 0; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (!(frame_counter & 7 | sprite_delay_aux1[k])) sprite_oam_flags[k] ^= 0x40; Sprite_MoveXYZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_delay_main[k] = 12; sprite_z_vel[k] = 24; sprite_graphics[k] = 6; } return; } if (sprite_C[k] < 3) { sprite_obj_prio[k] &= ~0xE; sprite_flags[k] = 0xA; } else { sprite_flags4[k] = 0x1F; sprite_flags[k] = 2; } HelmasaurKing_Draw(k); if (sprite_state[k] == 6) { t = sprite_delay_main[k]; if (!t) { sprite_state[k] = 4; sprite_A[k] = 0; sprite_delay_main[k] = 224; return; } sprite_hit_timer[k] = t | 240; if (t < 128 && (t & 7) == 0 && (j = overlord_gen2[3]) != 0x10) { overlord_gen2[3]++; cur_sprite_x = Sprite_GetX(k) + (int8)overlord_x_lo[5 + j]; cur_sprite_y = Sprite_GetY(k) + (int8)overlord_y_lo[5 + j]; Sprite_MakeBossExplosion(k); } return; } if (Sprite_ReturnIfInactive(k)) return; static const uint8 kHelmasaurKing_Tab1[13] = {3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1, 1, 0}; t = kHelmasaurKing_Tab1[sprite_health[k] >> 2]; sprite_C[k] = t; if (t == 3) { if (t != sprite_E[k]) { sprite_hit_timer[k] = 0; HelmasaurKing_ExplodeMask(k); } } else { if (t != sprite_E[k]) HelmasaurKing_ChipAwayAtMask(k); } sprite_E[k] = sprite_C[k]; Sprite_CheckDamageFromLink(k); HelmasaurKing_SwingTail(k); HelmasaurKing_AttemptDamage(k); HelmasaurKing_CheckMaskDamageFromHammer(k); if (sprite_delay_aux1[k] == 0) { if (sprite_delay_aux2[k] != 0) { if (sprite_delay_aux2[k] == 0x40) { HelmasaurKing_SpitFireball(k); if (sprite_C[k] >= 3) { anim_clk: if (!sprite_anim_clock[k]) { sprite_anim_clock[k]++; sprite_delay_aux3[k] = 32; } } } return; } } else { if (sprite_delay_aux1[k] == 96) goto anim_clk; return; } static const int8 kHelmasaurKing_Xvel0[8] = {-12, -12, -4, 0, 4, 12, 12, 0}; static const int8 kHelmasaurKing_Yvel0[8] = {0, 4, 12, 12, 12, 4, 0, 12}; switch (sprite_ai_state[k]) { case 0: if ((sprite_hit_timer[k] || !sprite_delay_main[k]) && !HelmasaurKing_MaybeFireball(k)) { j = GetRandomNumber() & 7; sprite_x_vel[k] = kHelmasaurKing_Xvel0[j]; sprite_y_vel[k] = kHelmasaurKing_Yvel0[j]; sprite_delay_main[k] = 64; if (sprite_C[k] >= 3) { sprite_x_vel[k] <<= 1; sprite_y_vel[k] <<= 1; sprite_delay_main[k] >>= 1; } sprite_ai_state[k]++; } break; case 1: HelmasaurKing_HandleMovement(k); if (!sprite_delay_main[k]) { sprite_delay_main[k] = 32; sprite_ai_state[k]++; } break; case 2: if ((sprite_hit_timer[k] || !sprite_delay_main[k]) && !HelmasaurKing_MaybeFireball(k)) { sprite_delay_main[k] = 64; if (sprite_E[k] >= 3) sprite_delay_main[k] >>= 1; sprite_x_vel[k] = -sprite_x_vel[k]; sprite_y_vel[k] = -sprite_y_vel[k]; sprite_ai_state[k]++; } break; case 3: HelmasaurKing_HandleMovement(k); if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 64; } break; } } void HelmasaurKing_HandleMovement(int k) { // 9e81e6 int n = 1 + ((frame_counter & 3) == 0) + (sprite_C[k] >= 3); do { if (!(++sprite_subtype2[k] & 15)) sound_effect_1 = 0x21; } while (--n); Sprite_MoveXY(k); } bool HelmasaurKing_MaybeFireball(int k) { // 9e8253 if (++sprite_subtype[k] != 4) return false; sprite_subtype[k] = 0; if (GetRandomNumber() & 1) { sprite_delay_aux2[k] = 127; SpriteSfx_QueueSfx3WithPan(k, 0x2a); } else { sprite_delay_aux1[k] = 160; } return true; } void HelmasaurKing_SwingTail(int k) { // 9e82a0 overlord_x_lo[4]++; HelmasaurKing_Reinitialize(k); uint8 mask = sprite_anim_clock[k] ? 0 : 1; if (!(frame_counter & mask)) { int j = sprite_D[k] & 1; overlord_gen2[0] += j ? -1 : 1; if (overlord_gen2[0] == (uint8)kFluteBoyAnimal_Xvel[j]) sprite_D[k]++; WORD(overlord_gen1[5]) += (int8)overlord_gen2[0]; } if (!sprite_anim_clock[k]) return; if (!overlord_gen2[0]) SpriteSfx_QueueSfx3WithPan(k, 0x6); if (sprite_anim_clock[k] == 2) { int j = sprite_head_dir[k]; WORD(overlord_gen2[1]) += j ? -4 : 4; if (overlord_gen2[1] == (uint8)(j ? -124 : 124)) sprite_anim_clock[k] = 3; overlord_gen1[7] += 3; } else if (sprite_anim_clock[k] == 3) { int j = sprite_head_dir[k] ^ 1; WORD(overlord_gen2[1]) += j ? -4 : 4; if (overlord_gen2[1] == 0) sprite_anim_clock[k] = 0; overlord_gen1[7] -= 3; } else { if (!(overlord_gen2[0] | sprite_delay_aux3[k])) { sprite_head_dir[k] = overlord_gen1[6] & 1; uint8 dir = Sprite_IsRightOfLink(k).a ^ 1; if (dir == sprite_head_dir[k]) { sprite_anim_clock[k] = 2; sound_effect_2 = Sprite_CalculateSfxPan(k) | 0x26; } } } } void HelmasaurKing_CheckMaskDamageFromHammer(int k) { // 9e8385 if (sprite_C[k] >= 3 || !(link_item_in_hand & 10) || (player_oam_y_offset == 0x80)) return; SpriteHitBox hb; Player_SetupActionHitBox(&hb); uint8 bak = sprite_y_lo[k]; sprite_y_lo[k] += 8; Sprite_SetupHitBox(k, &hb); sprite_y_lo[k] = bak; if (CheckIfHitBoxesOverlap(&hb)) { sprite_health[k]--; sound_effect_2 = 0x21; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 0x30); link_actual_vel_y = pt.y; link_actual_vel_x = pt.x; link_incapacitated_timer = 8; if (!repulsespark_timer) { repulsespark_x_lo = pt.y; repulsespark_y_lo = pt.x; repulsespark_timer = 5; } SpriteSfx_QueueSfx2WithPan(k, 0x5); } } void HelmasaurKing_AttemptDamage(int k) { // 9e83eb if (!(frame_counter & 7) && (uint16)(link_x_coord - cur_sprite_x + 36) < 72 && (uint16)(link_y_coord - cur_sprite_y + 40) < 64) Sprite_AttemptDamageToLinkPlusRecoil(k); } void HelmasaurKing_ChipAwayAtMask(int k) { // 9e847e tmp_counter = sprite_C[k] + 7; HelmasaurKing_SpawnMaskDebris(k); SpriteSfx_QueueSfx2WithPan(k, 0x1f); } void HelmasaurKing_ExplodeMask(int k) { // 9e848c for (int j = 1; j < 16; j++) sprite_state[j] = 0; tmp_counter = 7; do { HelmasaurKing_SpawnMaskDebris(k); } while (!sign8(--tmp_counter)); SpriteSfx_QueueSfx2WithPan(k, 0x1f); } void HelmasaurKing_SpawnMaskDebris(int k) { // 9e84aa static const int8 kHelmasaurKing_Mask_X[10] = {-16, 0, 16, -16, 0, 16, -8, 8, -16, 16}; static const int8 kHelmasaurKing_Mask_Y[10] = {24, 27, 24, 24, 27, 24, 27, 27, 24, 24}; static const int8 kHelmasaurKing_Mask_Z[10] = {29, 32, 29, 13, 16, 13, 0, 0, 13, 13}; static const int8 kHelmasaurKing_Mask_Xvel[10] = {-16, -4, 14, -12, 4, 18, -2, 2, -12, 18}; static const int8 kHelmasaurKing_Mask_Yvel[10] = {-8, -4, -6, 4, 2, 7, 6, 8, 4, 7}; static const int8 kHelmasaurKing_Mask_Zvel[10] = {32, 40, 36, 37, 39, 34, 30, 33, 37, 34}; static const uint8 kHelmasaurKing_Mask_OamFlags[10] = {0, 0, 0x40, 0, 0, 0x40, 0, 0x40, 0, 0x40}; static const uint8 kHelmasaurKing_Mask_Gfx[10] = {0, 1, 0, 2, 3, 2, 4, 4, 5, 5}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x92, &info); if (j >= 0) { int i = tmp_counter; Sprite_SetX(j, info.r0_x + kHelmasaurKing_Mask_X[i]); Sprite_SetY(j, info.r2_y + kHelmasaurKing_Mask_Y[i]); sprite_z[j] = kHelmasaurKing_Mask_Z[i]; sprite_x_vel[j] = kHelmasaurKing_Mask_Xvel[i]; sprite_y_vel[j] = kHelmasaurKing_Mask_Yvel[i]; sprite_z_vel[j] = kHelmasaurKing_Mask_Zvel[i]; sprite_oam_flags[j] = kHelmasaurKing_Mask_OamFlags[i] | 13; sprite_graphics[j] = kHelmasaurKing_Mask_Gfx[i]; sprite_C[j] = 128; sprite_flags2[j] = 0; sprite_delay_aux1[j] = 12; sprite_ignore_projectile[j] = 12; sprite_subtype[j] = tmp_counter; } } void HelmasaurKing_SpitFireball(int k) { // 9e8517 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x70, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); Sprite_SetY(j, info.r2_y + 28); sprite_delay_main[j] = 32; sprite_ignore_projectile[j] = 32; } } void HelmasaurKing_Draw(int k) { // 9e853b oam_cur_ptr = 0x89c; oam_ext_cur_ptr = 0xa47; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; KingHelmasaur_OperateTail(k, &info); SpriteDraw_KingHelmasaur_Eyes(k, &info); KingHelmasaurMask(k, &info); SpriteDraw_KingHelmasaur_Body(k, &info); SpriteDraw_KingHelmasaur_Legs(k, &info); SpriteDraw_KingHelmasaur_Mouth(k, &info); } void SpriteDraw_KingHelmasaur_Eyes(int k, PrepOamCoordsRet *info) { // 9e856b static const int8 kHelmasaurKing_DrawB_X[2] = {-3, 11}; static const uint8 kHelmasaurKing_DrawB_Char[8] = {0xce, 0xcf, 0xde, 0xde, 0xde, 0xde, 0xcf, 0xce}; static const uint8 kHelmasaurKing_DrawB_Flags[2] = {0x3b, 0x7b}; oam_cur_ptr += 0x40, oam_ext_cur_ptr += 0x10; OamEnt *oam = GetOamCurPtr(); for (int i = 1; i >= 0; i--, oam++) { oam->x = info->x + kHelmasaurKing_DrawB_X[i]; oam->y = info->y + 0x14; int j = overlord_x_lo[4] >> 2 & 7; oam->charnum = kHelmasaurKing_DrawB_Char[j]; oam->flags = kHelmasaurKing_DrawB_Flags[i]; bytewise_extended_oam[oam - oam_buf] = 0; } if (submodule_index) Sprite_CorrectOamEntries(k, 1, 0); } void KingHelmasaurMask(int k, PrepOamCoordsRet *info) { // 9e8686 static const DrawMultipleData kHelmasaurKing_DrawC_Dmd[24] = { {-16, -5, 0x0dae, 2}, { 0, -5, 0x0dc0, 2}, { 16, -5, 0x4dae, 2}, {-16, 11, 0x0dc2, 2}, { 0, 11, 0x0dc4, 2}, { 16, 11, 0x4dc2, 2}, { -8, 27, 0x0dc6, 2}, { 8, 27, 0x4dc6, 2}, {-16, -5, 0x0dae, 2}, { 0, -5, 0x0dc0, 2}, { 16, -5, 0x4dae, 2}, {-16, 11, 0x0dc8, 2}, { 0, 11, 0x0dc4, 2}, { 16, 11, 0x4dc2, 2}, { -8, 27, 0x0dc6, 2}, { 8, 27, 0x4dc6, 2}, {-16, -5, 0x0dae, 2}, { 0, -5, 0x0dc0, 2}, { 16, -5, 0x4dae, 2}, {-16, 11, 0x0dc8, 2}, { 0, 11, 0x0dc4, 2}, { 16, 11, 0x4dc8, 2}, { -8, 27, 0x0dc6, 2}, { 8, 27, 0x4dc6, 2}, }; oam_cur_ptr += 8, oam_ext_cur_ptr += 2; if (sprite_C[k] >= 3) return; Sprite_DrawMultiple(k, &kHelmasaurKing_DrawC_Dmd[sprite_C[k] * 8], 8, info); oam_cur_ptr += 0x20, oam_ext_cur_ptr += 8; if (sprite_delay_aux4[k]) return; for (int i = 1; i >= 0; i--) { if (ancilla_type[i] == 7 && (ancilla_x_vel[i] | ancilla_y_vel[i])) { KingHelmasaur_CheckBombDamage(k, i); } } } void KingHelmasaur_CheckBombDamage(int k, int j) { // 9e86e5 SpriteHitBox hb; Sprite_SetupHitBox(k, &hb); int x = (ancilla_x_lo[j] | ancilla_x_hi[j] << 8) - 6; int y = (ancilla_y_lo[j] | ancilla_y_hi[j] << 8) - ancilla_z[j]; hb.r0_xlo = x, hb.r8_xhi = x >> 8; hb.r1_ylo = y, hb.r9_yhi = y >> 8; hb.r2 = 2; hb.r3 = 15; if (CheckIfHitBoxesOverlap(&hb)) { ancilla_x_vel[j] = -ancilla_x_vel[j]; ancilla_y_vel[j] = (int8)-ancilla_y_vel[j] >> 1; sprite_delay_aux4[k] = 32; repulsespark_timer = 5; repulsespark_x_lo = ancilla_x_lo[j]; repulsespark_y_lo = ancilla_y_lo[j] - ancilla_z[j]; sound_effect_1 = 5; } } void SpriteDraw_KingHelmasaur_Body(int k, PrepOamCoordsRet *info) { // 9e87e5 static const DrawMultipleData kHelmasaurKing_DrawD_Dmd[19] = { {-24, -32, 0x0b80, 2}, { -8, -32, 0x0b82, 2}, { 8, -32, 0x4b82, 2}, { 24, -32, 0x4b80, 2}, {-24, -16, 0x0b84, 2}, { -8, -16, 0x0b86, 2}, { 8, -16, 0x4b86, 2}, { 24, -16, 0x4b84, 2}, {-24, 0, 0x0b88, 2}, { -8, 0, 0x0b8a, 2}, { 8, 0, 0x4b8a, 2}, { 24, 0, 0x4b88, 2}, {-24, 16, 0x0b8c, 2}, { -8, 16, 0x0b8e, 2}, { 8, 16, 0x4b8e, 2}, { 24, 16, 0x4b8c, 2}, { -8, 32, 0x0ba0, 2}, { 8, 32, 0x4ba0, 2}, { 0, -40, 0x0bac, 2}, }; Sprite_DrawMultiple(k, kHelmasaurKing_DrawD_Dmd, 19, info); } void SpriteDraw_KingHelmasaur_Legs(int k, PrepOamCoordsRet *info) { // 9e8805 static const int8 kHelmasaurKing_DrawE_X[4] = {-28, -28, 28, 28}; static const int8 kHelmasaurKing_DrawE_Y[4] = {-28, 4, -28, 4}; static const uint8 kHelmasaurKing_DrawE_Char[4] = {0xa2, 0xa6, 0xa2, 0xa6}; static const uint8 kHelmasaurKing_DrawE_Flags[4] = {0xb, 0xb, 0x4b, 0x4b}; oam_cur_ptr += 19 * 4; oam_ext_cur_ptr += 19; OamEnt *oam = GetOamCurPtr(); for (int i = 3; i >= 0; i--, oam += 2) { oam[1].x = oam[0].x = info->x + kHelmasaurKing_DrawE_X[i]; oam[0].y = info->y + kHelmasaurKing_DrawE_Y[i] + overlord_x_lo[i]; oam[1].y = oam[0].y + 0x10; oam[0].charnum = kHelmasaurKing_DrawE_Char[i]; oam[1].charnum = oam[0].charnum + 2; oam[1].flags = oam[0].flags = kHelmasaurKing_DrawE_Flags[i] ^ info->flags; bytewise_extended_oam[oam - oam_buf] = 2; bytewise_extended_oam[oam - oam_buf + 1] = 2; } tmp_counter = 0xff; if (submodule_index) { Sprite_CorrectOamEntries(k, 7, 2); Sprite_PrepOamCoordOrDoubleRet(k, info); } } void SpriteDraw_KingHelmasaur_Mouth(int k, PrepOamCoordsRet *info) { // 9e88bc static const uint8 kHelmasaurKing_DrawF_Y[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, }; if (!sprite_delay_aux2[k]) return; uint8 yd = kHelmasaurKing_DrawF_Y[sprite_delay_aux2[k] >> 2]; Oam_AllocateFromRegionB(4); OamEnt *oam = GetOamCurPtr(); oam->x = info->x; int t = (uint8)info->y + 0x13; oam->y = t + (t >> 8) + yd; oam->charnum = 0xaa; oam->flags = info->flags ^ 0xb; bytewise_extended_oam[oam - oam_buf] = 2; } void KingHelmasaur_OperateTail(int k, PrepOamCoordsRet *info) { // 9e8920 static const uint8 kHelmasaurKing_DrawA_Mult[32] = { 0xff, 0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0xff, 0xf8, 0xf0, 0xe8, 0xe0, 0xd8, 0xd0, 0xc8, 0xbc, 0xb0, 0xa0, 0x90, 0x70, 0x40, 0x20, 0x10, }; static const uint8 kHelmasaurKing_DrawA_MultB[16] = { 0xff, 0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10 }; for (int i = 0; i < 16; i++) { int j = i + (sprite_anim_clock[k] ? 16 : 0); uint16 rs = WORD(overlord_gen1[5]) + WORD(overlord_gen2[1]); uint8 f = (rs >> 8) - 1; uint8 r6 = (uint8)(sign8(f) ? -rs : rs) * kHelmasaurKing_DrawA_Mult[j] >> 8; uint16 angle = (rs & 0xff00) | (sign8(f) ? r6 ^ 0xff : r6); uint8 r15 = overlord_gen1[7] * kHelmasaurKing_DrawA_MultB[i] >> 8; overlord_x_lo[i+5] = HelmasaurSin(angle, r15); overlord_y_lo[i+5] = HelmasaurSin(angle + 0x80, r15) - 40; } OamEnt *oam = GetOamCurPtr(); bool is_hit = false; for (int i = overlord_gen2[3]; i != 16; i++, oam++) { uint8 x = overlord_x_lo[i + 5] + info->x; uint8 y = overlord_y_lo[i + 5] + info->y; oam->x = x; oam->y = y; oam->charnum = (i == overlord_gen2[3]) ? 0xe4 : 0xac; oam->flags = info->flags ^ 0x1b; if (!countdown_for_blink && sprite_anim_clock[k]) { if ((uint8)(link_x_coord - BG2HOFS_copy2 - x + 12) < 24 && (uint8)(link_y_coord - BG2VOFS_copy2 + 8 - y + 8) < 16) { is_hit = true; link_actual_vel_x = 0; link_actual_vel_y = 56; } } } if (is_hit && !flag_block_link_menu) Sprite_AttemptDamageToLinkPlusRecoil(k); Sprite_CorrectOamEntries(k, 16, 2); Sprite_PrepOamCoordOrDoubleRet(k, info); tmp_counter = 16; } void Sprite_MadBatterBolt(int k) { // 9e8a96 static const int8 kMadderBolt_X[8] = {0, 4, 8, 12, 12, 4, 8, 0}; static const int8 kMadderBolt_Y[8] = {0, 4, 8, 12, 12, 4, 8, 0}; if (sprite_subtype2[k] & 16) Oam_AllocateFromRegionB(4); SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; if (!sprite_ai_state[k]) { Sprite_MoveXY(k); if (!sprite_delay_main[k]) sprite_ai_state[k] = 1; } else { if (++sprite_ai_state[k] == 0) sprite_state[k] = 0; int j = ++sprite_subtype2[k]; if (!(j & 7)) sound_effect_2 = 48; Sprite_SetX(k, link_x_coord + kMadderBolt_X[j >> 2 & 7]); Sprite_SetY(k, link_y_coord + kMadderBolt_Y[j >> 4 & 7]); } } void Sprite_AA_Pikit(int k) { // 9e8bbf static const uint8 kPikit_Gfx[24] = { 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, }; static const int8 kPikit_XyOffs[72] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 16, 24, 32, 32, 24, 16, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -12, -16, -24, -32, -32, -24, -16, -12, 0, 0, 0, 0, 0, 0, 0, 0, }; static const uint8 kPikit_Tab0[8] = {24, 24, 0, 48, 48, 48, 0, 24}; static const uint8 kPikit_Tab1[8] = {0, 24, 24, 24, 0, 48, 48, 48}; int j; Pikit_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); switch(sprite_ai_state[k]) { case 0: // set next vel if (!sprite_delay_main[k]) { int j; sprite_ai_state[k]++; if (++sprite_C[k] == 4) { sprite_C[k] = 0; j = Sprite_DirectionToFaceLink(k, NULL); } else { j = GetRandomNumber() & 3; } sprite_x_vel[k] = kFluteBoyAnimal_Xvel[j]; sprite_y_vel[k] = kZazak_Yvel[j]; sprite_z_vel[k] = (GetRandomNumber() & 7) + 19; } sprite_graphics[k] = ++sprite_subtype2[k] >> 3 & 1; break; case 1: // finish jump then attack Sprite_MoveXYZ(k); Sprite_CheckTileCollision(k); sprite_z_vel[k]--; sprite_z_vel[k]--; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = 0; PointU8 pt; Sprite_DirectionToFaceLink(k, &pt); if ((uint8)(pt.x + 48) < 96 && (uint8)(pt.y + 48) < 96) { sprite_ai_state[k]++; ProjectSpeedRet pp = Sprite_ProjectSpeedTowardsLink(k, 31); sprite_D[k] = Sprite_ConvertVelocityToAngle(pp.x, pp.y) >> 1; sprite_delay_main[k] = 95; return; } sprite_ai_state[k] = 0; sprite_delay_main[k] = 16; } sprite_graphics[k] = ++sprite_subtype2[k] >> 3 & 1; break; case 2: { // attempt item grab j = sprite_delay_main[k]; if (!j) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 16; sprite_A[k] = 0; sprite_B[k] = 0; sprite_G[k] = 0; return; } j >>= 2; sprite_graphics[k] = kPikit_Gfx[j]; int8 xo = kPikit_XyOffs[j + kPikit_Tab0[sprite_D[k]]]; int8 yo = kPikit_XyOffs[j + kPikit_Tab1[sprite_D[k]]]; sprite_A[k] = xo; sprite_B[k] = yo; if (!sprite_G[k] && (uint16)(cur_sprite_x + xo - link_x_coord + 12) < 24 && (uint16)(cur_sprite_y + yo - link_y_coord + 12) < 32 && sprite_delay_main[k] < 46) { sound_effect_1 = Link_CalculateSfxPan() | 0x26; j = (GetRandomNumber() & 3) + 1; sprite_E[k] = sprite_G[k] = j; if (j == 1) { if (link_item_bombs) link_item_bombs--; else sprite_G[k] = 0; } else if (j == 2) { if (link_num_arrows) link_num_arrows--; else sprite_G[k] = 0; } else if (j == 3) { if (link_rupees_goal) link_rupees_goal--; else sprite_G[k] = 0; } else { sprite_subtype[k] = link_shield_type; if (link_shield_type != 0 && link_shield_type != 3) link_shield_type = 0; else sprite_G[k] = 0; } } break; } } } void Sprite_A8_GreenZirro(int k) { // 9e8dd2 static const uint8 kBomber_Gfx[4] = {9, 10, 8, 7}; sprite_obj_prio[k] = 0x30; if (sprite_A[k]) { switch (sprite_ai_state[k]) { case 0: // bomberpellet falling SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXY(k); Sprite_MoveZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_ai_state[k]++; sprite_delay_main[k] = 19; sprite_flags2[k]++; SpriteSfx_QueueSfx2WithPan(k, 0xc); } break; case 1: // bomberpellet exploding SpriteDraw_ZirroBomb(k); if (Sprite_ReturnIfInactive(k)) return; if (!(frame_counter & 3)) sprite_delay_main[k]++; Sprite_CheckDamageToLink(k); break; } return; } if (sprite_delay_aux1[k]) sprite_graphics[k] = kBomber_Gfx[sprite_D[k]]; sprite_obj_prio[k] |= 0x30; Bomber_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; if (sprite_delay_aux1[k] == 8) Zirro_DropBomb(k); Sprite_CheckDamageToAndFromLink(k); if (!(frame_counter & 1)) { int j = sprite_G[k] & 1; sprite_z_vel[k] += j ? -1 : 1; if (sprite_z_vel[k] == (uint8)(j ? -8 : 8)) sprite_G[k]++; } Sprite_MoveZ(k); PointU8 pt; Sprite_DirectionToFaceLink(k, &pt); if ((uint8)(pt.x + 40) < 80 && (uint8)(pt.y + 40) < 80 && player_oam_y_offset != 0x80 && (link_is_running || sign8(button_b_frames - 9))) { ProjectSpeedRet pp = Sprite_ProjectSpeedTowardsLink(k, 0x30); sprite_x_vel[k] = -pp.x; sprite_y_vel[k] = -pp.y; sprite_delay_main[k] = 8; sprite_ai_state[k] = 2; } switch(sprite_ai_state[k]) { case 0: if (!sprite_delay_main[k]) { static const int8 kBomber_Xvel[8] = {16, 12, 0, -12, -16, -12, 0, 12}; static const int8 kBomber_Yvel[8] = {0, 12, 16, 12, 0, -12, -16, -12}; static const uint8 kBomber_Tab0[4] = {0, 4, 2, 6}; int j; sprite_ai_state[k]++; sprite_B[k]++; if (sprite_B[k] == 3) { sprite_B[k] = 0; sprite_delay_main[k] = 48; j = kBomber_Tab0[Sprite_DirectionToFaceLink(k, NULL)]; } else { j = GetRandomNumber(); sprite_delay_main[k] = j & 0x1f | 0x20; j &= 7; } sprite_x_vel[k] = kBomber_Xvel[j]; sprite_y_vel[k] = kBomber_Yvel[j]; } goto set_dir; case 1: if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 10; if (sprite_type[k] == 0xa8) sprite_delay_aux1[k] = 16; } else { Sprite_MoveXY(k); set_dir: sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL); sprite_graphics[k] = sprite_D[k] << 1 | ++sprite_subtype2[k] >> 3 & 1; } break; case 2: if (!sprite_delay_main[k]) sprite_ai_state[k] = 0; sprite_subtype2[k] += 2; Sprite_MoveXY(k); goto set_dir; } } void Zirro_DropBomb(int k) { // 9e8f81 static const int8 kBomber_SpawnPellet_X[4] = {14, -6, 4, 4}; static const int8 kBomber_SpawnPellet_Y[4] = {7, 7, 12, -4}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xa8, &info); if (j >= 0) { SpriteSfx_QueueSfx2WithPan(k, 0x20); sprite_z[j] = info.r4_z; int i = sprite_D[j]; Sprite_SetX(j, info.r0_x + kBomber_SpawnPellet_X[i]); Sprite_SetY(j, info.r2_y + kBomber_SpawnPellet_Y[i]); sprite_x_vel[j] = kFluteBoyAnimal_Xvel[i]; sprite_y_vel[j] = kZazak_Yvel[i]; sprite_A[j] = 1; sprite_ignore_projectile[j] = 1; sprite_flags4[j] = 9; sprite_flags3[j] = 0x33; sprite_oam_flags[j] = 0x33 & 15; } } void Sprite_StalfosBone(int k) { // 9e8fdf StalfosBone_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToLink(k); sprite_subtype2[k]++; Sprite_MoveXY(k); if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k)) { sprite_state[k] = 0; Sprite_PlaceWeaponTink(k); } } void StalfosBone_Draw(int k) { // 9e9040 static const DrawMultipleData kStalfosBone_Dmd[8] = { {-4, -2, 0x802f, 0}, { 4, 2, 0x402f, 0}, {-4, 2, 0x002f, 0}, { 4, -2, 0xc02f, 0}, { 2, -4, 0x403f, 0}, {-2, 4, 0x803f, 0}, {-2, -4, 0x003f, 0}, { 2, 4, 0xc03f, 0}, }; Sprite_DrawMultiple(k, &kStalfosBone_Dmd[(sprite_subtype2[k] >> 2 & 3) * 2], 2, NULL); } void Sprite_A7_Stalfos(int k) { // 9e906c if (sprite_A[k]) { Sprite_StalfosBone(k); return; } if (!sprite_E[k]) { Stalfos_Skellington(k); return; } if (!sprite_delay_main[k]) { sprite_x_vel[k] = 1; sprite_y_vel[k] = 1; if (Sprite_CheckTileCollision(k)) { sprite_state[k] = 0; return; } sprite_E[k] = 0; SpriteSfx_QueueSfx2WithPan(k, 0x15); Sprite_SpawnPoofGarnish(k); sprite_delay_aux2[k] = 8; sprite_delay_main[k] = 64; sprite_y_vel[k] = 0; sprite_x_vel[k] = 0; } PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); } void Stalfos_Skellington(int k) { // 9e90b5 static const uint8 kStalfos_AnimState2[4] = {8, 9, 10, 11}; static const uint8 kStalfos_CheckDir[4] = {3, 2, 1, 0}; if (sprite_state[k] == 9 && (uint16)(link_x_coord - cur_sprite_x + 40) < 80 && (uint16)(link_y_coord - cur_sprite_y + 48) < 80 && player_oam_y_offset != 0x80 && !(sprite_z[k] | sprite_pause[k]) && sprite_floor[k] == link_is_on_lower_level) { uint8 dir = Sprite_DirectionToFaceLink(k, NULL); if (!link_is_running) { if (button_b_frames >= 0x90) goto if_1; if (!sign8(button_b_frames - 9)) goto endif_1; } if (dir != kStalfos_CheckDir[link_direction_facing >> 1]) { if_1: sprite_D[k] = dir; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32); sprite_x_vel[k] = -pt.x; sprite_y_vel[k] = -pt.y; sprite_z_vel[k] = 32; SpriteSfx_QueueSfx3WithPan(k, 0x13); sprite_z[k]++; } } endif_1: if (sprite_z[k] == 0) { Sprite_Zazak_Main(k); return; } sprite_graphics[k] = kStalfos_AnimState2[sprite_D[k]]; Stalfos_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_F[k]) sprite_z_vel[k] = 0; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); uint8 t = Sprite_CheckTileCollision(k); if (t & 3) sprite_x_vel[k] = 0; if (t & 12) sprite_y_vel[k] = 0; Sprite_MoveXYZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k] - 1)) { sprite_z[k] = 0; Sprite_ZeroVelocity_XY(k); SpriteSfx_QueueSfx2WithPan(k, 0x21); if (sprite_subtype[k]) { sprite_delay_aux3[k] = 16; sprite_subtype2[k] = 0; } } } void Sprite_Zazak_Main(int k) { // 9e919f static const uint8 kStalfos_AnimState1[8] = {6, 4, 0, 2, 7, 5, 1, 3}; static const uint8 kStalfos_Delay[4] = {16, 32, 64, 32}; static const int8 kZazak_Yvel[4] = {0, 0, 16, -16}; if (sprite_B[k]) { FirePhlegm_Draw(k); if (Sprite_ReturnIfInactive(k)) return; sprite_graphics[k] = frame_counter >> 1 & 1; Sprite_CheckDamageToLink(k); Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) { sprite_state[k] = 0; Sprite_PlaceRupulseSpark_2(k); } return; } int t = sprite_delay_aux3[k]; if (t != 0) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 32; Sprite_ZeroVelocity_XY(k); sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL); } if (t == 1) { Stalfos_ThrowBone(k); sprite_subtype2[k] = 1; } sprite_graphics[k] = kStalfos_AnimState1[(sprite_subtype2[k] & 1) * 4 + sprite_D[k]]; if (sprite_type[k] == 0xa7) Stalfos_Draw(k); else Zazak_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); Sprite_CheckTileCollision(k); switch (sprite_ai_state[k]) { case 0: // walk then track head if (!sprite_delay_main[k]) { sprite_delay_main[k] = kStalfos_Delay[GetRandomNumber() & 3]; sprite_ai_state[k] = 1; int j = sprite_head_dir[k]; sprite_D[k] = j; sprite_x_vel[k] = kFluteBoyAnimal_Xvel[j]; sprite_y_vel[k] = kZazak_Yvel[j]; } break; case 1: // halt and change dir if (sprite_wallcoll[k] != 0) { sprite_delay_main[k] = 16; } else { if (sprite_delay_main[k] != 0) { if (sign8(--sprite_G[k])) { sprite_G[k] = 11; sprite_subtype2[k]++; } return; } else if (sprite_type[k] == 0xa6 && sprite_D[k] == Sprite_DirectionToFaceLink(k, NULL) && sprite_floor[k] == link_is_on_lower_level) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 48; sprite_delay_aux1[k] = 48; sprite_y_vel[k] = sprite_x_vel[k] = 0; return; } sprite_delay_main[k] = 32; } sprite_head_dir[k] = kZazak_Dir2[sprite_D[k] * 2 + (GetRandomNumber() & 1)]; sprite_ai_state[k] = 0; if (++sprite_C[k] == 4) { sprite_C[k] = 0; sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL); sprite_delay_main[k] = 24; } sprite_y_vel[k] = sprite_x_vel[k] = 0; break; case 2: // shoot if (!sprite_delay_main[k]) sprite_ai_state[k] = 0; else if (sprite_delay_main[k] == 24) Sprite_SpawnFirePhlegm(k); break; } } int Sprite_SpawnFirePhlegm(int k) { // 9e92e4 static const int8 kSpawnFirePhlegm_X[4] = {16, -8, 4, 4}; static const int8 kSpawnFirePhlegm_Y[4] = {-2, -2, 8, -20}; static const int8 kSpawnFirePhlegm_Xvel[4] = {48, -48, 0, 0}; static const int8 kSpawnFirePhlegm_Yvel[4] = {0, 0, 48, -48}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xa5, &info); if (j >= 0) { SpriteSfx_QueueSfx3WithPan(k, 0x5); Sprite_SetSpawnedCoordinates(j, &info); int i = sprite_D[k]; Sprite_SetX(j, info.r0_x + kSpawnFirePhlegm_X[i]); Sprite_SetY(j, info.r2_y + kSpawnFirePhlegm_Y[i]); sprite_x_vel[j] = kSpawnFirePhlegm_Xvel[i]; sprite_y_vel[j] = kSpawnFirePhlegm_Yvel[i]; sprite_flags3[j] |= 0x40; sprite_defl_bits[j] = 0x40; sprite_flags2[j] = 0x21; sprite_B[j] = 0x21; sprite_oam_flags[j] = 2; sprite_flags4[j] = 0x14; sprite_ignore_projectile[j] = 20; sprite_bump_damage[j] = 37; if (link_shield_type >= 3) sprite_flags5[j] = 0x20; } return j; } void Stalfos_ThrowBone(int k) { // 9e9379 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xa7, &info); if (j >= 0) { sprite_A[j] = 1; Sprite_SetSpawnedCoordinates(j, &info); Sprite_ApplySpeedTowardsLink(j, 32); sprite_flags2[j] = 0x21; sprite_ignore_projectile[j] = 33; sprite_flags3[j] |= 0x40; sprite_defl_bits[j] = 0x48; sprite_delay_main[j] = 16; sprite_flags4[j] = 0x14; sprite_oam_flags[j] = 7; sprite_bump_damage[j] = 32; SpriteSfx_QueueSfx2WithPan(k, 0x2); } } void FirePhlegm_Draw(int k) { // 9e9443 static const DrawMultipleData kFirePhlegm_Dmd[16] = { { 0, 0, 0x00c3, 0}, {-8, 0, 0x00c2, 0}, { 0, 0, 0x80c3, 0}, {-8, 0, 0x80c2, 0}, { 0, 0, 0x40c3, 0}, { 8, 0, 0x40c2, 0}, { 0, 0, 0xc0c3, 0}, { 8, 0, 0xc0c2, 0}, { 0, 0, 0x00d4, 0}, { 0, -8, 0x00d3, 0}, { 0, 0, 0x40d4, 0}, { 0, -8, 0x40d3, 0}, { 0, 0, 0x80d4, 0}, { 0, 8, 0x80d3, 0}, { 0, 0, 0xc0d4, 0}, { 0, 8, 0xc0d3, 0}, }; Sprite_DrawMultiple(k, &kFirePhlegm_Dmd[sprite_D[k] * 4 + sprite_graphics[k] * 2], 2, NULL); } void Sprite_A3_KholdstareShell(int k) { // 9e9460 if (Sprite_ReturnIfPaused(k)) return; PointU8 pt; Sprite_DirectionToFaceLink(k, &pt); if ((uint8)(pt.x + 32) < 64 && (uint8)(pt.y + 32) < 64) { Sprite_NullifyHookshotDrag(); Sprite_RepelDash(); } Sprite_CheckDamageFromLink(k); if (sprite_ai_state[k] == 0) { if (sprite_state[k] == 6) { sprite_flags3[k] = 0xc0; sprite_ai_state[k] = 1; sprite_state[k] = 9; } else if (sprite_hit_timer[k] != 0) { dung_floor_x_offs = (sprite_hit_timer[k] & 2) ? -1 : 1; dung_hdr_collision_2_mirror = 1; } else { dung_hdr_collision_2_mirror = 0; } } else if (sprite_ai_state[k]++ != 18) { KholdstareShell_PaletteFiltering(); } else { sprite_state[k] = 0; sprite_ai_state[2] = 2; sprite_delay_main[2] = 128; } } void GenerateIceball(int k) { // 9e94dd if (++sprite_subtype2[k] & 127 | sprite_delay_aux1[k]) return; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xa4, &info); if (j >= 0) { Sprite_SetX(j, link_x_coord); Sprite_SetY(j, link_y_coord); sprite_z[j] = -32; sprite_C[j] = -32; SpriteSfx_QueueSfx2WithPan(j, 0x20); } } void Sprite_A2_Kholdstare(int k) { // 9e9518 int j; Kholdstare_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_ai_state[k] < 2) { Kholdstare_SpawnPuffCloudGarnish(k); if (!(frame_counter & 7)) sound_effect_1 = 2; } if (Sprite_ReturnIfRecoiling(k)) return; if (sign8(--sprite_subtype2[k])) { sprite_subtype2[k] = 10; sprite_graphics[k] = sprite_graphics[k] + 1 & 3; } if (!(frame_counter & 3)) { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 31); sprite_A[k] = Sprite_ConvertVelocityToAngle(pt.x, pt.y); } Sprite_MoveXY(k); switch(sprite_ai_state[k]) { case 0: // Accelerate Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = (GetRandomNumber() & 63) + 32; return; } if (sprite_x_vel[k] - sprite_z_vel[k]) sprite_x_vel[k] += sign8(sprite_x_vel[k] - sprite_z_vel[k]) ? 1 : -1; if (sprite_y_vel[k] - sprite_z_subpos[k]) sprite_y_vel[k] += sign8(sprite_y_vel[k] - sprite_z_subpos[k]) ? 1 : -1; check_coll: j = Sprite_CheckTileCollision(k); if (j & 3) { sprite_x_vel[k] = -sprite_x_vel[k]; sprite_z_vel[k] = -sprite_z_vel[k]; } if (j & 12) { sprite_y_vel[k] = -sprite_y_vel[k]; sprite_z_subpos[k] = -sprite_z_subpos[k]; } break; case 1: // Decelerate Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = (GetRandomNumber() & 63) + 96; j = GetRandomNumber(); if (!(j & 0x1c)) { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 24); sprite_z_vel[k] = pt.x; sprite_z_subpos[k] = pt.y; } else { static const int8 kKholdstare_Target_Xvel[4] = {16, 16, -16, -16}; static const int8 kKholdstare_Target_Yvel[4] = {-16, 16, 16, -16}; sprite_z_vel[k] = kKholdstare_Target_Xvel[j & 3]; sprite_z_subpos[k] = kKholdstare_Target_Yvel[j & 3]; } } else { if (sprite_x_vel[k]) sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? 1 : -1; if (sprite_y_vel[k]) sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? 1 : -1; goto check_coll; } break; case 2: // Triplicate if (sprite_delay_main[k] == 1) { sprite_state[k] = 0; sprite_state[k + 1] = 0; sprite_state[k + 2] = 0; for (int i = 2; i >= 0; i--) { static const int8 kKholdstare_Triplicate_Tab0[3] = {32, -32, 0}; static const int8 kKholdstare_Triplicate_Tab1[3] = {-32, -32, 48}; SpriteSpawnInfo info; j = Sprite_SpawnDynamicallyEx(k, 0xa2, &info, 4); assert(j >= 0); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_z_vel[j] = kKholdstare_Triplicate_Tab0[i]; sprite_z_subpos[j] = kKholdstare_Triplicate_Tab1[i]; sprite_delay_main[j] = 32; } } tmp_counter = 0xff; } else { sprite_hit_timer[k] |= 0xe0; } break; } } void Kholdstare_SpawnPuffCloudGarnish(int k) { // 9e96a5 static const int8 kNebuleGarnish_XY[8] = {-8, -6, -4, -2, 0, 2, 4, 6}; if ((k ^ frame_counter) & 3) return; int j = GarnishAllocLow(); if (j < 0) return; garnish_type[j] = 7; garnish_active = 7; garnish_countdown[j] = 31; Garnish_SetX(j, cur_sprite_x + kNebuleGarnish_XY[GetRandomNumber() & 7]); Garnish_SetY(j, cur_sprite_y + kNebuleGarnish_XY[GetRandomNumber() & 7] + 16); garnish_floor[j] = 0; } void Sprite_A4_FallingIce(int k) { // 9e9710 if (!sprite_C[k]) { if (Sprite_ReturnIfInactive(k)) return; if (sprite_state[2] < 9 && sprite_state[3] < 9 && sprite_state[4] < 9) sprite_state[k] = 0; GenerateIceball(k); return; } sprite_ignore_projectile[k] = 1; sprite_obj_prio[k] = 0x30; SpriteDraw_SingleLarge(k); if (!sprite_ai_state[k]) sprite_flags3[k] ^= 16; if (Sprite_ReturnIfInactive(k)) return; if (sprite_delay_main[k]) { if (sprite_delay_main[k] == 1) sprite_state[k] = 0; sprite_graphics[k] = (sprite_delay_main[k] >> 3) + 2; return; } Sprite_MoveXY(k); if (!sprite_ai_state[k] || (Sprite_CheckDamageToLink(k), !Sprite_CheckTileCollision(k))) { uint8 old_z = sprite_z[k]; Sprite_MoveZ(k); if (!sign8(sprite_z_vel[k] + 64)) sprite_z_vel[k] -= 3; if (!(sign8(old_z ^ sprite_z[k]) && sign8(sprite_z[k]))) return; sprite_z[k] = 0; if (!sprite_ai_state[k]) { sprite_state[k] = 0; IceBall_Split(k); return; } } sprite_delay_main[k] = 15; sprite_oam_flags[k] = 4; if (!sound_effect_1) { SpriteSfx_QueueSfx2WithPan(k, 0x1e); sprite_graphics[k] = 3; } } void IceBall_Split(int k) { // 9e97cf static const int8 kIceBall_Quadruplicate_Xvel[8] = {0, 32, 0, -32, 24, 24, -24, -24}; static const int8 kIceBall_Quadruplicate_Yvel[8] = {-32, 0, 32, 0, -24, 24, -24, 24}; SpriteSfx_QueueSfx2WithPan(k, 0x1f); int b = GetRandomNumber() & 4; for (int i = 3; i >= 0; i--) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xa4, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_ai_state[j] = 1; sprite_graphics[j] = 1; sprite_C[j] = 1; sprite_z_vel[j] = 32; sprite_x_vel[j] = kIceBall_Quadruplicate_Xvel[i + b]; sprite_y_vel[j] = kIceBall_Quadruplicate_Yvel[i + b]; sprite_flags4[j] = 0x1c; } } tmp_counter = 0xff; } void Sprite_A1_Freezor(int k) { // 9e981d Freezor_Draw(k); if (sprite_state[k] != 9) { sprite_ai_state[k] = 3; sprite_delay_main[k] = 31; sprite_ignore_projectile[k] = 31; sprite_state[k] = 9; sprite_hit_timer[k] = 0; } if (Sprite_ReturnIfInactive(k)) return; if (sprite_ai_state[k] != 3) { if (Sprite_ReturnIfRecoiling(k)) return; } switch(sprite_ai_state[k]) { case 0: // stasis sprite_ignore_projectile[k]++; if ((uint8)(Sprite_IsRightOfLink(k).b + 16) < 32) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 32; } break; case 1: { // awakening sprite_ignore_projectile[k] = sprite_delay_main[k]; if (!sprite_delay_main[k]) { sprite_ai_state[k] = 2; uint16 x = Sprite_GetX(k) - 5; uint16 y = Sprite_GetY(k); Dungeon_UpdateTileMapWithCommonTile(x, y, 8); sprite_delay_aux1[k] = 96; sprite_D[k] = 2; sprite_delay_main[k] = 80; } else { sprite_x_vel[k] = (sprite_delay_main[k] & 1) ? -16 : 16; Sprite_MoveX(k); } break; } case 2: { // moving static const int8 kFreezor_Xvel[4] = {8, -8, 0, 0}; static const int8 kFreezor_Yvel[4] = {0, 0, 18, -18}; static const uint8 kFreezor_Moving_Gfx[4] = {1, 2, 1, 3}; static const int8 kFreezor_Sparkle_X[8] = {-4, -2, 0, 2, 4, 6, 8, 10}; Sprite_CheckDamageToLink(k); if (Sprite_CheckDamageFromLink(k)) sprite_hit_timer[k] = 0; if (sprite_delay_aux1[k] && !((k ^ frame_counter) & 7)) { Sprite_GarnishSpawn_Sparkle(k, kFreezor_Sparkle_X[GetRandomNumber() & 7], -4); } if (!sprite_delay_main[k]) sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL); int j = sprite_D[k]; sprite_x_vel[k] = kFreezor_Xvel[j]; sprite_y_vel[k] = kFreezor_Yvel[j]; if (!(sprite_wallcoll[k] & 15)) Sprite_MoveXY(k); Sprite_CheckTileCollision(k); sprite_graphics[k] = kFreezor_Moving_Gfx[(k ^ frame_counter) >> 2 & 3]; break; } case 3: { // melting static const uint8 kFreezor_Melting_Gfx[4] = { 6, 5, 4, 7 }; if (!sprite_delay_main[k]) { Sprite_ManuallySetDeathFlagUW(k); sprite_state[k] = 0; } sprite_graphics[k] = kFreezor_Melting_Gfx[sprite_delay_main[k] >> 3]; break; } } } void Sprite_9E_HauntedGroveOstritch(int k) { // 9e995b static const uint8 kFluteBoyOstrich_Gfx[4] = {0, 1, 0, 2}; FluteBoyOstrich_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch (sprite_ai_state[k]) { case 0: // wait sprite_graphics[k] = (frame_counter & 0x18) ? 3 : 0; if (byte_7E0FDD) { sprite_ai_state[k] = 1; sprite_y_vel[k] = -8; sprite_x_vel[k] = -16; } break; case 1: // run away Sprite_MoveXYZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z_vel[k] = 32; sprite_z[k] = 0; sprite_subtype2[k] = 0; sprite_A[k] = 0; } if (!(++sprite_subtype2[k] & 7) && sprite_A[k] != 3) sprite_A[k]++; sprite_graphics[k] = kFluteBoyOstrich_Gfx[sprite_A[k]]; break; } } void FluteBoyOstrich_Draw(int k) { // 9e9a4b static const DrawMultipleData kFluteBoyOstrich_Dmd[16] = { {-4, -8, 0x0080, 2}, { 4, -8, 0x0081, 2}, {-4, 8, 0x00a3, 2}, { 4, 8, 0x00a4, 2}, {-4, -8, 0x0080, 2}, { 4, -8, 0x0081, 2}, {-4, 8, 0x00a0, 2}, { 4, 8, 0x00a1, 2}, {-4, -8, 0x0080, 2}, { 4, -8, 0x0081, 2}, {-4, 8, 0x0083, 2}, { 4, 8, 0x0084, 2}, {-4, -7, 0x0080, 2}, { 4, -7, 0x0081, 2}, {-4, 9, 0x00a3, 2}, { 4, 9, 0x00a4, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kFluteBoyOstrich_Dmd[sprite_graphics[k] * 4], 4, &info); SpriteDraw_Shadow_custom(k, &info, 18); } void Sprite_9F_HauntedGroveRabbit(int k) { // 9e9a6d sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kFluteBoyAnimal_OamFlags[sprite_D[k]]; SpriteDraw_SingleLarge(k); switch (sprite_ai_state[k]) { case 0: // wait sprite_graphics[k] = 3; if (byte_7E0FDD) { sprite_ai_state[k] = 1; sprite_D[k] ^= 1; sprite_x_vel[k] = kFluteBoyAnimal_Xvel[sprite_D[k]]; sprite_y_vel[k] = -8; } break; case 1: // run Sprite_MoveXYZ(k); sprite_z_vel[k]-=3; if (sign8(sprite_z[k])) { sprite_z_vel[k] = 24; sprite_z[k] = 0; sprite_subtype2[k] = 0; sprite_A[k] = 0; } sprite_subtype2[k]++; if (!(sprite_subtype2[k] & 3) && sprite_A[k] != 2) sprite_A[k]++; sprite_graphics[k] = kFluteBoyAnimal_Gfx[sprite_A[k]]; break; } } void Sprite_A0_HauntedGroveBird(int k) { // 9e9aec if (sprite_graphics[k] == 3) HauntedGroveBird_Blink(k); sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kFluteBoyAnimal_OamFlags[sprite_D[k]]; oam_cur_ptr += 4; oam_ext_cur_ptr++; sprite_flags2[k]--; SpriteDraw_SingleLarge(k); sprite_flags2[k]++; Sprite_MoveXYZ(k); switch (sprite_ai_state[k]) { case 0: // wait sprite_graphics[k] = (frame_counter & 0x18) ? 0 : 3; if (byte_7E0FDD) { sprite_ai_state[k] = 1; sprite_D[k] ^= 1; sprite_x_vel[k] = kFluteBoyAnimal_Xvel[sprite_D[k]]; sprite_delay_main[k] = 32; sprite_z_vel[k] = 16; sprite_y_vel[k] = -8; } break; case 1: // rising if (!sprite_delay_main[k]) { sprite_z_vel[k] += 2; if (!sign8(sprite_z_vel[k] - 0x10)) sprite_ai_state[k] = 2; } sprite_graphics[k] = (++sprite_subtype2[k] >> 1 & 1) + 1; break; case 2: // falling sprite_graphics[k] = 1; sprite_z_vel[k] -= 1; if (sign8(sprite_z_vel[k] + 15)) sprite_ai_state[k] = 1; break; } } void HauntedGroveBird_Blink(int k) { // 9e9b9c static const int8 kFluteBoyBird_X[2] = {8, 0}; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int j = sprite_D[k]; oam->x = info.x + kFluteBoyBird_X[j]; oam->y = info.y; oam->charnum = 0xae; oam->flags = info.flags | kFluteBoyAnimal_OamFlags[j]; Sprite_CorrectOamEntries(k, 0, 0); } void Sprite_9C_Zoro(int k) { // 9e9bc8 if (sprite_E[k]) Zoro(k); else Babasu(k); // } void Zoro(int k) { // 9e9bd0 if (!sprite_C[k]) { sprite_C[k]++; if (Sprite_IsBelowLink(k).a != 0) { sprite_state[k] = 0; return; } } SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToAndFromLink(k); sprite_graphics[k] = ++sprite_subtype2[k] >> 1 & 1; sprite_x_vel[k] = kFluteBoyAnimal_Xvel[sprite_subtype2[k] >> 2 & 1]; Sprite_MoveXY(k); if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k)) sprite_state[k] = 0; if (sprite_subtype2[k] & 3) return; int j = GarnishAlloc(); if (j < 0) return; garnish_type[j] = 6; garnish_active = 6; Garnish_SetX(j, Sprite_GetX(k)); Garnish_SetY(j, Sprite_GetY(k) + 16); garnish_countdown[j] = 10; garnish_sprite[j] = k; garnish_floor[j] = sprite_floor[k]; } void Babasu(int k) { // 9e9c6b static const uint8 kBabusu_Gfx[6] = {5, 4, 3, 2, 1, 0}; static const uint8 kBabusu_DirGfx[4] = {6, 6, 0, 0}; static const int8 kBabusu_XyVel[6] = {32, -32, 0, 0, 32, -32}; Babusu_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch(sprite_ai_state[k]) { case 0: // reset sprite_ai_state[k]++; sprite_delay_main[k] = 128; sprite_graphics[k] = 255; break; case 1: // hiding if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 55; } break; case 2: { // terror sprinkles int j = sprite_delay_main[k], i = sprite_D[k]; if (j == 0) { sprite_ai_state[k] = 3; sprite_x_vel[k] = kBabusu_XyVel[i]; sprite_y_vel[k] = kBabusu_XyVel[i + 2]; sprite_delay_main[k] = 32; } if (j >= 32) { sprite_graphics[k] = kBabusu_Gfx[(j - 32) >> 2] + kBabusu_DirGfx[i]; } else { sprite_graphics[k] = 0xff; } break; } case 3: { // scurry across static const uint8 kBabusu_Scurry_Gfx[4] = {18, 14, 12, 16}; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); sprite_graphics[k] = (frame_counter >> 1 & 1) + kBabusu_Scurry_Gfx[sprite_D[k]]; if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k)) { sprite_D[k] ^= 1; sprite_ai_state[k] = 0; } break; } } } void Sprite_9B_Wizzrobe(int k) { // 9e9d1b int j; if (sprite_C[k]) { Sprite_Wizzbeam(k); return; } if (sprite_ai_state[k] == 0 || sprite_ai_state[k] & 1 && sprite_delay_main[k] & 1) { PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); } else { Wizzrobe_Draw(k); } if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; sprite_ignore_projectile[k] = 1; switch(sprite_ai_state[k]) { case 0: // cloaked if (!sprite_delay_main[k]) { sprite_y_vel[k] = sprite_x_vel[k] = 1; if (!Sprite_CheckTileCollision(k)) { static const uint8 kWizzrobe_Cloak_Gfx[4] = {4, 2, 0, 6}; sprite_ai_state[k] = 1; sprite_delay_main[k] = 63; sprite_D[k] = j = Sprite_DirectionToFaceLink(k, NULL); sprite_graphics[k] = kWizzrobe_Cloak_Gfx[j]; } else { sprite_state[k] = 0; } } break; case 1: // phasing in if (!sprite_delay_main[k]) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 63; } break; case 2: { // attack static const uint8 kWizzrobe_Attack_Gfx[8] = {0, 1, 1, 1, 1, 1, 1, 0}; static const uint8 kWizzrobe_Attack_DirGfx[4] = {4, 2, 0, 6}; sprite_ignore_projectile[k] = 0; Sprite_CheckDamageToAndFromLink(k); j = sprite_delay_main[k]; if (!j) { sprite_ai_state[k] = 3; sprite_delay_main[k] = 63; return; } if (j == 32) Wizzrobe_FireBeam(k); sprite_graphics[k] = kWizzrobe_Attack_Gfx[j >> 3] + kWizzrobe_Attack_DirGfx[sprite_D[k]]; break; } case 3: // phasing out if (!sprite_delay_main[k]) { if (sprite_B[k]) sprite_state[k] = 0; sprite_ai_state[k] = 0; sprite_delay_main[k] = (GetRandomNumber() & 31) + 32; } break; } } void Wizzrobe_FireBeam(int k) { // 9e9e15 static const int8 kWizzrobe_Beam_XYvel[6] = {32, -32, 0, 0, 32, -32}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x9b, &info); if (j >= 0) { SpriteSfx_QueueSfx3WithPan(k, 0x36); sprite_C[j] = 1; sprite_ignore_projectile[j] = 1; Sprite_SetX(j, info.r0_x + 4); Sprite_SetY(j, info.r2_y); int i = sprite_D[k]; sprite_x_vel[j] = kWizzrobe_Beam_XYvel[i]; sprite_y_vel[j] = kWizzrobe_Beam_XYvel[i + 2]; sprite_defl_bits[j] = 0x48; sprite_oam_flags[j] = 2; sprite_flags5[j] = link_shield_type == 3 ? 0x20 : 0; sprite_flags4[j] = 0x14; } } void Sprite_9A_Kyameron(int k) { // 9e9e7b PrepOamCoordsRet info; if (!sprite_ai_state[k]) Sprite_PrepOamCoord(k, &info); else Kyameron_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; sprite_ignore_projectile[k] = 1; switch(sprite_ai_state[k]) { case 0: // reset if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = (GetRandomNumber() & 63) + 96; sprite_x_lo[k] = sprite_A[k]; sprite_x_hi[k] = sprite_B[k]; sprite_y_lo[k] = sprite_C[k]; sprite_y_hi[k] = sprite_head_dir[k]; sprite_subtype2[k] = 5; sprite_graphics[k] = 8; } break; case 1: // puddleup if (!sprite_delay_main[k]) { sprite_delay_main[k] = 31; sprite_ai_state[k] = 2; } if (sign8(--sprite_subtype2[k])) { sprite_subtype2[k] = 5; sprite_graphics[k] = (++sprite_graphics[k] & 3) + 8; } break; case 2: { // coagulate static const int8 kKyameron_Coagulate_Gfx[8] = {4, 7, 14, 13, 12, 6, 6, 5}; static const int8 kKyameron_Xvel[4] = {32, -32, 32, -32}; static const int8 kKyameron_Yvel[4] = {32, 32, -32, -32}; int j = sprite_delay_main[k]; if (j == 0) { sprite_ai_state[k] = 3; j = Sprite_IsBelowLink(k).a * 2 + Sprite_IsRightOfLink(k).a; sprite_x_vel[k] = kKyameron_Xvel[j]; sprite_y_vel[k] = kKyameron_Yvel[j]; } else { if (j == 7) Sprite_SetY(k, Sprite_GetY(k) - 29); sprite_graphics[k] = kKyameron_Coagulate_Gfx[j >> 2]; } break; } case 3: { // moving sprite_ignore_projectile[k] = 0; if (!Sprite_CheckDamageToAndFromLink(k)) { Sprite_MoveXY(k); int j = Sprite_CheckTileCollision(k); if (j & 3) { sprite_x_vel[k] = -sprite_x_vel[k]; sprite_anim_clock[k]++; } if (j & 12) { sprite_y_vel[k] = -sprite_y_vel[k]; sprite_anim_clock[k]++; } if (sprite_anim_clock[k] < 3) goto skip_sound; } sprite_ai_state[k] = 4; sprite_delay_main[k] = 15; SpriteSfx_QueueSfx2WithPan(k, 0x28); static const uint8 kKyameron_Moving_Gfx[4] = {3, 2, 1, 0}; skip_sound: sprite_graphics[k] = kKyameron_Moving_Gfx[++sprite_subtype2[k] >> 3 & 3]; if (!((k ^ frame_counter) & 7)) { uint16 x = (GetRandomNumber() & 0xf) - 4; uint16 y = (GetRandomNumber() & 0xf) - 4; Sprite_GarnishSpawn_Sparkle(k, x, y); } break; } case 4: // disperse if (!sprite_delay_main[k]) { sprite_anim_clock[k] = 0; sprite_ai_state[k] = 0; sprite_z[k] = 0; sprite_delay_main[k] = 64; } else { sprite_graphics[k] = (sprite_delay_main[k] >> 2) + 15; } break; } } void Kyameron_Draw(int k) { // 9ea158 static const uint8 kKyameron_OamFlags[12] = {0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0xc0, 0x80}; static const DrawMultipleData kKyameron_Dmd[28] = { { 1, 8, 0x00b4, 0}, { 7, 8, 0x00b5, 0}, { 4, -3, 0x0086, 0}, { 0, -13, 0x80a2, 2}, { 2, 8, 0x00b4, 0}, { 6, 8, 0x00b5, 0}, { 4, -6, 0x0096, 0}, { 0, -20, 0x00a2, 2}, { 4, -1, 0x0096, 0}, { 0, -27, 0x00a2, 2}, { 0, -27, 0x00a2, 2}, { 0, -27, 0x00a2, 2}, {-6, -6, 0x01df, 0}, {14, -6, 0x41df, 0}, {-6, 14, 0x81df, 0}, {14, 14, 0xc1df, 0}, {-6, -6, 0x0096, 0}, {14, -6, 0x4096, 0}, {-6, 14, 0x8096, 0}, {14, 14, 0xc096, 0}, {-4, -4, 0x018d, 0}, {12, -4, 0x418d, 0}, {-4, 12, 0x818d, 0}, {12, 12, 0xc18d, 0}, { 0, 0, 0x018d, 0}, { 8, 0, 0x418d, 0}, { 0, 8, 0x818d, 0}, { 8, 8, 0xc18d, 0}, }; int j = sprite_graphics[k]; if (j < 12) { uint8 bak = sprite_oam_flags[k]; sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kKyameron_OamFlags[j]; SpriteDraw_SingleLarge(k); sprite_oam_flags[k] = bak; } else { Sprite_DrawMultiple(k, &kKyameron_Dmd[(j - 12) * 4], 4, NULL); } } void Sprite_99_Pengator(int k) { // 9ea196 static const uint8 kPengator_Gfx[4] = {5, 0, 10, 15}; sprite_graphics[k] = sprite_A[k] + kPengator_Gfx[sprite_D[k]]; Pengator_Draw(k); if (sprite_F[k] || sprite_wallcoll[k] & 15) { sprite_ai_state[k] = 0; sprite_x_vel[k] = 0; sprite_y_vel[k] = 0; } if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXYZ(k); sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z_vel[k] = 0; sprite_z[k] = 0; } Sprite_CheckTileCollision(k); switch(sprite_ai_state[k]) { case 0: // face player sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL); sprite_ai_state[k] = 1; break; case 1: // speedup if (!((k ^ frame_counter) & 3)) { static const int8 kPengator_XYVel[6] = { 1, -1, 0, 0, 1, -1 }; bool flag = false; int j = sprite_D[k]; if (sprite_x_vel[k] != (uint8)kFluteBoyAnimal_Xvel[j]) sprite_x_vel[k] += kPengator_XYVel[j], flag = true; if (sprite_y_vel[k] != (uint8)kZazak_Yvel[j]) sprite_y_vel[k] += kPengator_XYVel[j + 2], flag = true; if (!flag) { sprite_delay_main[k] = 15; sprite_ai_state[k] = 2; } } sprite_A[k] = (frame_counter & 4) >> 2; break; case 2: { // jump static const uint8 kPengator_Jump[4] = {4, 4, 3, 2}; if (!sprite_delay_main[k]) sprite_ai_state[k]++; else if (sprite_delay_main[k] == 5) sprite_z_vel[k] = 24; sprite_A[k] = kPengator_Jump[sprite_delay_main[k] >> 2]; break; } case 3: // slide and sparkle if (!((k ^ frame_counter) & 7 | sprite_z[k])) { static const int8 kPengator_Garnish_Y[8] = { 8, 10, 12, 14, 12, 12, 12, 12 }; static const int8 kPengator_Garnish_X[8] = { 4, 4, 4, 4, 0, 4, 8, 12 }; int i = sprite_D[k]; int x = kPengator_Garnish_X[(GetRandomNumber() & 3) + (i >= 2) * 4]; int y = kPengator_Garnish_Y[(GetRandomNumber() & 3) + (i >= 2) * 4]; Sprite_GarnishSpawn_Sparkle_limited(k, x, y); } break; } } void Pengator_Draw(int k) { // 9ea415 static const DrawMultipleData kPengator_Dmd0[40] = { {-1, -8, 0x0082, 2}, { 0, 0, 0x0088, 2}, {-1, -7, 0x0082, 2}, { 0, 0, 0x008a, 2}, {-3, -6, 0x0082, 2}, { 0, 0, 0x0088, 2}, {-6, -4, 0x0082, 2}, { 0, 0, 0x008a, 2}, {-4, 0, 0x00a2, 2}, { 4, 0, 0x00a3, 2}, { 1, -8, 0x4082, 2}, { 0, 0, 0x4088, 2}, { 1, -7, 0x4082, 2}, { 0, 0, 0x408a, 2}, { 3, -6, 0x4082, 2}, { 0, 0, 0x4088, 2}, { 6, -4, 0x4082, 2}, { 0, 0, 0x408a, 2}, { 4, 0, 0x40a2, 2}, {-4, 0, 0x40a3, 2}, { 0, -7, 0x0080, 2}, { 0, 0, 0x0086, 2}, { 0, -7, 0x4080, 2}, { 0, 0, 0x4086, 2}, { 0, -4, 0x0080, 2}, { 0, 0, 0x0086, 2}, { 0, -1, 0x0080, 2}, { 0, 0, 0x0086, 2}, {-8, 0, 0x008e, 2}, { 8, 0, 0x408e, 2}, { 0, -8, 0x0084, 2}, { 0, 0, 0x008c, 2}, { 0, -8, 0x4084, 2}, { 0, 0, 0x408c, 2}, { 0, -7, 0x0084, 2}, { 0, 0, 0x008c, 2}, { 0, 0, 0x408c, 2}, { 0, -6, 0x4084, 2}, {-8, 0, 0x00a0, 2}, { 8, 0, 0x40a0, 2}, }; static const DrawMultipleData kPengator_Dmd1[4] = { {0, 16, 0x00b5, 0}, {8, 16, 0x40b5, 0}, {0, -8, 0x00a5, 0}, {8, -8, 0x40a5, 0}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kPengator_Dmd0[sprite_graphics[k] * 2], 2, &info); int i; if ((i = 0, sprite_graphics[k] == 14) || (i = 1, sprite_graphics[k] == 19)) { oam_cur_ptr += 8, oam_ext_cur_ptr += 2; Sprite_DrawMultiple(k, &kPengator_Dmd1[i * 2], 2, &info); } SpriteDraw_Shadow(k, &info); } void Sprite_LaserBeam(int k) { // 9ea462 SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; LaserBeam_BuildUpGarnish(k); Sprite_MoveXY(k); Sprite_CheckDamageToLink_same_layer(k); if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k)) { sprite_state[k] = 0; SpriteSfx_QueueSfx3WithPan(k, 0x26); } } void LaserBeam_BuildUpGarnish(int k) { // 9ea488 int j = GarnishAllocOverwriteOld(); garnish_type[j] = 4; garnish_active = 4; Garnish_SetX(j, Sprite_GetX(k)); Garnish_SetY(j, Sprite_GetY(k) + 16); garnish_countdown[j] = 16; garnish_oam_flags[j] = sprite_graphics[k]; garnish_sprite[j] = k; garnish_floor[j] = sprite_floor[k]; } void Sprite_95_LaserEyeLeft(int k) { // 9ea541 static const uint8 kLaserEye_Dirs[4] = {2, 3, 0, 1}; if (sprite_A[k]) { Sprite_LaserBeam(k); return; } LaserEye_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch(sprite_ai_state[k]) { case 0: // monitor firing zone if (sprite_head_dir[k] == 0 && sprite_D[k] != kLaserEye_Dirs[link_direction_facing >> 1]) { sprite_graphics[k] = 0; } else { uint16 j = (sprite_D[k] < 2) ? link_y_coord - cur_sprite_y : link_x_coord - cur_sprite_x; if ((uint16)(j + 16) < 32) { sprite_delay_main[k] = 32; sprite_ai_state[k] = 1; } else { sprite_graphics[k] = 0; } } break; case 1: // firing beam sprite_graphics[k] = 1; if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; LaserEye_FireBeam(k); sprite_delay_aux4[k] = 12; } break; } } void LaserEye_FireBeam(int k) { // 9ea5d8 static const int8 kLaserEye_SpawnXY[6] = {12, -4, 4, 4, 12, -4}; static const int8 kLaserEye_SpawnXYVel[6] = {112, -112, 0, 0, 112, -112}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x95, &info); if (j >= 0) { int i = sprite_D[k]; sprite_graphics[j] = (i & 2) >> 1; Sprite_SetX(j, info.r0_x + kLaserEye_SpawnXY[i]); Sprite_SetY(j, info.r2_y + kLaserEye_SpawnXY[i + 2]); sprite_x_vel[j] = kLaserEye_SpawnXYVel[i]; sprite_y_vel[j] = kLaserEye_SpawnXYVel[i + 2]; sprite_flags2[j] = 0x20; sprite_A[j] = 0x20; sprite_oam_flags[j] = 5; sprite_defl_bits[j] = 0x48; sprite_ignore_projectile[j] = 0x48; sprite_delay_main[j] = 5; if (link_shield_type == 3) sprite_flags5[j] = 32; SpriteSfx_QueueSfx3WithPan(k, 0x19); } } void LaserEye_Draw(int k) { // 9ea708 static const DrawMultipleData kLaserEye_Dmd[24] = { { 8, -4, 0x40c8, 0}, { 8, 4, 0x40d8, 0}, { 8, 12, 0xc0c8, 0}, { 8, -4, 0x40c9, 0}, { 8, 4, 0x40d9, 0}, { 8, 12, 0xc0c9, 0}, { 0, -4, 0x00c8, 0}, { 0, 4, 0x00d8, 0}, { 0, 12, 0x80c8, 0}, { 0, -4, 0x00c9, 0}, { 0, 4, 0x00d9, 0}, { 0, 12, 0x80c9, 0}, {-4, 8, 0x00d6, 0}, { 4, 8, 0x00d7, 0}, {12, 8, 0x40d6, 0}, {-4, 8, 0x00c6, 0}, { 4, 8, 0x00c7, 0}, {12, 8, 0x40c6, 0}, {-4, 0, 0x80d6, 0}, { 4, 0, 0x80d7, 0}, {12, 0, 0xc0d6, 0}, {-4, 0, 0x80c6, 0}, { 4, 0, 0x80c7, 0}, {12, 0, 0xc0c6, 0}, }; if (sprite_head_dir[k]) sprite_graphics[k] = (sprite_delay_aux4[k] == 0); sprite_obj_prio[k] = 0x30; Sprite_DrawMultiple(k, &kLaserEye_Dmd[(sprite_graphics[k] + sprite_D[k] * 2) * 3], 3, NULL); } void Sprite_94_Pirogusu(int k) { // 9ea742 static const uint8 kPirogusu_A0[4] = {2, 3, 0, 1}; static const uint8 kPirogusu_A1[8] = {9, 11, 5, 7, 5, 11, 7, 9}; static const uint8 kPirogusu_A2[8] = {16, 17, 18, 19, 12, 13, 14, 15}; static const int8 kPirogusu_XYvel[6] = {0, 0, 4, -4, 0, 0}; static const int8 kPirogusu_XYvel2[6] = {2, -2, 0, 0, 2, -2}; static const int8 kPirogusu_XYvel3[6] = {24, -24, 0, 0, 24, -24}; if (sprite_E[k]) { Sprite_94_Tile(k); return; } sprite_obj_prio[k] |= 0x30; Pirogusu_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch(sprite_ai_state[k]) { case 0: // wriggle in hole if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 31; } sprite_ignore_projectile[k] = sprite_delay_main[k]; sprite_A[k] = kPirogusu_A0[sprite_D[k]]; break; case 1: { // emerge if (!sprite_delay_main[k]) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 32; sprite_ignore_projectile[k] = 0; Sprite_ZeroVelocity_XY(k); } else { sprite_A[k] = kPirogusu_A1[sprite_delay_main[k] >> 3 & 1 | sprite_D[k] << 1]; int j = sprite_D[k]; sprite_x_vel[k] = kPirogusu_XYvel[j + 2]; sprite_y_vel[k] = kPirogusu_XYvel[j]; Sprite_MoveXY(k); } break; } case 2: { // splash into play Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); int j = sprite_D[k]; sprite_x_vel[k] += kPirogusu_XYvel2[j]; sprite_y_vel[k] += kPirogusu_XYvel2[j + 2]; if (!sprite_delay_main[k]) { Sprite_SpawnSmallSplash(k); sprite_delay_aux1[k] = 16; sprite_ai_state[k] = 3; } sprite_A[k] = kPirogusu_A2[frame_counter >> 2 & 1 | sprite_D[k] << 1]; break; } case 3: { // swim if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); sprite_A[k] = kPirogusu_A2[frame_counter >> 2 & 1 | sprite_D[k] << 1] + 8; if (!sprite_delay_aux1[k]) { Pirogusu_SpawnSplash(k); Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k) & 15) { static const uint8 kPirogusu_Dir[8] = {2, 3, 2, 3, 0, 1, 0, 1}; sprite_D[k] = kPirogusu_Dir[sprite_D[k] << 1 | GetRandomNumber() & 1]; } int j = sprite_D[k]; sprite_x_vel[k] = kPirogusu_XYvel3[j]; sprite_y_vel[k] = kPirogusu_XYvel3[j + 2]; } break; } } } void Pirogusu_SpawnSplash(int k) { // 9ea897 static const uint8 kPirogusu_Tab0[4] = {3, 4, 5, 4}; if ((k ^ frame_counter) & 3) return; int x = kPirogusu_Tab0[GetRandomNumber() & 3]; int y = kPirogusu_Tab0[GetRandomNumber() & 3]; int j = GarnishAllocLow(); if (j >= 0) { garnish_type[j] = 11; garnish_active = 11; Garnish_SetX(j, Sprite_GetX(k) + x); Garnish_SetY(j, Sprite_GetY(k) + y + 16); garnish_countdown[j] = 15; } } void Pirogusu_Draw(int k) { // 9ea93b static const uint8 kPirogusu_OamFlags[28] = { 0, 0x80, 0x40, 0, 0, 0, 0, 0x80, 0x80, 0xc0, 0x40, 0x40, 0, 0x40, 0x80, 0xc0, 0x40, 0xc0, 0, 0x80, 0, 0x40, 0x80, 0xc0, 0x40, 0xc0, 0, 0x80, }; static const uint8 kPirogusu_Gfx[28] = { 0, 0, 1, 1, 2, 3, 4, 3, 2, 3, 4, 3, 5, 5, 5, 5, 7, 7, 7, 7, 6, 6, 6, 6, 8, 8, 8, 8, }; int j = sprite_A[k]; sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kPirogusu_OamFlags[j]; sprite_graphics[k] = kPirogusu_Gfx[j]; if (j < 4) { cur_sprite_x += 4, cur_sprite_y += 4; SpriteDraw_SingleSmall(k); } else { SpriteDraw_SingleLarge(k); } } void Sprite_93_Bumper(int k) { // 9ea982 static const int8 kBumper_Vels[4] = { 0, 2, -2, 0 }; Bumper_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckTileCollision(k); if (!link_cape_mode && Sprite_CheckDamageToLink_same_layer(k)) { Link_CancelDash(); sprite_delay_main[k] = 32; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 0x30); link_actual_vel_y = pt.y + kBumper_Vels[joypad1H_last >> 2 & 3]; link_actual_vel_x = pt.x + kBumper_Vels[joypad1H_last & 3]; link_incapacitated_timer = 20; Link_ResetSwimmingState(); SpriteSfx_QueueSfx3WithPan(k, 0x32); } for (int j = 15; j >= 0; j--) { if ((j ^ frame_counter) & 3 | sprite_z[j]) continue; if (sprite_state[j] < 9 || (sprite_flags3[j] | sprite_flags4[j]) & 0x40) continue; int x = Sprite_GetX(j), y = Sprite_GetY(j); if ((uint16)(cur_sprite_x - x + 16) < 32 && (uint16)(cur_sprite_y - y + 16) < 32) { sprite_F[j] = 15; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 0x40); sprite_y_recoil[j] = pt.y; sprite_x_recoil[j] = pt.x; sprite_delay_main[k] = 32; SpriteSfx_QueueSfx3WithPan(k, 0x32); } } } void Bumper_Draw(int k) { // 9eaa8b static const DrawMultipleData kBumper_Dmd[8] = { {-8, -8, 0x00ec, 2}, { 8, -8, 0x40ec, 2}, {-8, 8, 0x80ec, 2}, { 8, 8, 0xc0ec, 2}, {-7, -7, 0x00ec, 2}, { 7, -7, 0x40ec, 2}, {-7, 7, 0x80ec, 2}, { 7, 7, 0xc0ec, 2}, }; Sprite_DrawMultiple(k, &kBumper_Dmd[(sprite_delay_main[k] >> 1 & 1) * 4], 4, NULL); } void Sprite_91_StalfosKnight(int k) { // 9eaaa7 int j; if (!sprite_ai_state[k]) { PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); } else { StalfosKnight_Draw(k); } if (Sprite_ReturnIfInactive(k)) return; if ((sprite_hit_timer[k] & 127) == 1) { sprite_hit_timer[k] = 0; sprite_ai_state[k] = 6; sprite_delay_main[k] = 255; sprite_x_vel[k] = 0; sprite_y_vel[k] = 0; enemy_damage_data[0x918] = 2; } if (Sprite_ReturnIfRecoiling(k)) return; switch(sprite_ai_state[k]) { case 0: { // waiting for player sprite_flags4[k] = 9; sprite_ignore_projectile[k] = 9; uint8 bak0 = sprite_flags2[k]; sprite_flags2[k] |= 128; bool flag = Sprite_CheckDamageToLink(k); sprite_flags2[k] = bak0; if (flag) { sprite_z[k] = 144; sprite_ai_state[k] = 1; sprite_head_dir[k] = 2; sprite_graphics[k] = 2; SpriteSfx_QueueSfx2WithPan(k, 0x20); } break; } case 1: { // falling uint8 old_z = sprite_z[k]; Sprite_MoveZ(k); if (!sign8(sprite_z_vel[k] + 64)) sprite_z_vel[k] -= 3; if (sign8(old_z ^ sprite_z[k]) && sign8(sprite_z[k])) { sprite_ai_state[k] = 2; sprite_ignore_projectile[k] = 0; sprite_z[k] = 0; sprite_z_vel[k] = 0; sprite_delay_main[k] = 63; } break; } case 2: { // static const uint8 kStalfosKnight_Case2_Gfx[2] = {0, 1}; enemy_damage_data[0x918] = 0; Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) { sprite_ai_state[k] = 3; sprite_B[k] = GetRandomNumber() & 63; sprite_delay_main[k] = 127; } else { sprite_C[k] = sprite_graphics[k] = kStalfosKnight_Case2_Gfx[sprite_delay_main[k] >> 5]; sprite_head_dir[k] = 2; } break; } case 3: // Sprite_CheckDamageToAndFromLink(k); if (sprite_delay_main[k] == sprite_B[k]) { sprite_head_dir[k] = Sprite_IsRightOfLink(k).a; sprite_ai_state[k] = 4; sprite_delay_main[k] = 32; } else { static const uint8 kStalfosKnight_Case2_Dir[16] = {0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2}; sprite_head_dir[k] = kStalfosKnight_Case2_Dir[sprite_delay_main[k] >> 3]; sprite_C[k] = 0; sprite_graphics[k] = 0; } break; case 4: // Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) { sprite_ai_state[k] = 5; sprite_delay_main[k] = 255; sprite_delay_aux1[k] = 32; } sprite_C[k] = 1; sprite_graphics[k] = 1; break; case 5: // Sprite_CheckDamageToAndFromLink(k); if (sprite_delay_aux1[k] == 0) { Sprite_MoveXYZ(k); Sprite_CheckTileCollision(k); if (!sign8(sprite_z_vel[k] + 64)) sprite_z_vel[k] -= 2; if (sign8(sprite_z[k] - 1)) { sprite_z[k] = 0; sprite_z_vel[k] = 0; if (!sprite_delay_main[k]) goto SetToGround; sprite_delay_aux1[k] = 16; } sprite_graphics[k] = sign8(sprite_z_vel[k] - 24) ? 2 : 0; } else { if (sprite_delay_aux1[k] == 1) { sprite_z_vel[k] = 48; Sprite_ApplySpeedTowardsLink(k, 16); sprite_head_dir[k] = Sprite_IsRightOfLink(k).a; SpriteSfx_QueueSfx3WithPan(k, 0x13); } sprite_C[k] = 1; sprite_graphics[k] = 1; } break; case 6: // Sprite_MoveXYZ(k); Sprite_CheckTileCollision(k); if (!sign8(sprite_z_vel[k] + 64)) sprite_z_vel[k] -= 2; if (sign8(sprite_z[k] - 1)) { sprite_z[k] = 0; sprite_z_vel[k] = 0; } j = sprite_delay_main[k]; if (!j) { if (GetRandomNumber() & 1) goto SetToGround; sprite_ai_state[k] = 7; sprite_delay_main[k] = 80; } else { if (j >= 224 && (j & 3) == 0) SpriteSfx_QueueSfx3WithPan(k, 0x14); static const uint8 kStalfosKnight_Case6_C[32] = { 0, 4, 8, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 12, 8, 4, 0, }; sprite_C[k] = kStalfosKnight_Case6_C[j >> 3]; sprite_graphics[k] = 3; sprite_head_dir[k] = 2; } break; case 7: // if (!sprite_delay_main[k]) { SetToGround: sprite_ai_state[k] = 2; sprite_ignore_projectile[k] = 0; sprite_z[k] = 0; sprite_z_vel[k] = 0; sprite_delay_main[k] = 63; } else { static const uint8 kStalfosKnight_Case7_Gfx[2] = {1, 4}; sprite_graphics[k] = kStalfosKnight_Case7_Gfx[sprite_delay_main[k] >> 2 & 1]; } break; } } void StalfosKnight_Draw(int k) { // 9eae04 static const DrawMultipleData kStalfosKnight_Dmd[35] = { {-4, -8, 0x0064, 0}, {-4, 0, 0x0061, 2}, { 4, 0, 0x0062, 2}, {-3, 16, 0x0074, 0}, {11, 16, 0x4074, 0}, {-4, -7, 0x0064, 0}, {-4, 1, 0x0061, 2}, { 4, 1, 0x0062, 2}, {-3, 16, 0x0065, 0}, {11, 16, 0x4065, 0}, {-4, -8, 0x0048, 2}, { 4, -8, 0x0049, 2}, {-4, 8, 0x004b, 2}, { 4, 8, 0x004c, 2}, { 4, 8, 0x004c, 2}, {-4, 8, 0x0068, 2}, { 4, 8, 0x0069, 2}, { 4, 8, 0x0069, 2}, { 4, 8, 0x0069, 2}, { 4, 8, 0x0069, 2}, {12, -7, 0x4064, 0}, {-4, 1, 0x4062, 2}, { 4, 1, 0x4061, 2}, {-3, 16, 0x0065, 0}, {11, 16, 0x4065, 0}, {12, -8, 0x4064, 0}, {-4, 0, 0x4062, 2}, { 4, 0, 0x4061, 2}, {-3, 16, 0x0074, 0}, {11, 16, 0x4074, 0}, {-4, -8, 0x4049, 2}, { 4, -8, 0x4048, 2}, {-4, 8, 0x404c, 2}, { 4, 8, 0x404b, 2}, { 4, 8, 0x404b, 2}, }; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; SpriteDraw_StalfosKnight_Head(k, &info); oam_cur_ptr += 4, oam_ext_cur_ptr += 1; Sprite_DrawMultiple(k, &kStalfosKnight_Dmd[sprite_graphics[k] * 5], 5, &info); oam_cur_ptr -= 4, oam_ext_cur_ptr -= 1; SpriteDraw_Shadow_custom(k, &info, 18); } void SpriteDraw_StalfosKnight_Head(int k, PrepOamCoordsRet *info) { // 9eae4e static const uint8 kStalfosKnight_DrawHead_Char[4] = {0x66, 0x66, 0x46, 0x46}; static const uint8 kStalfosKnight_DrawHead_Flags[4] = {0x40, 0, 0, 0}; if (sprite_graphics[k] == 2) return; int i = sprite_head_dir[k]; OamEnt *oam = GetOamCurPtr(); oam->x = info->x; oam->y = ClampYForOam(info->y + sprite_C[k] - 12); oam->charnum = kStalfosKnight_DrawHead_Char[i]; oam->flags = info->flags | kStalfosKnight_DrawHead_Flags[i]; bytewise_extended_oam[oam - oam_buf] = 2 | (info->x >> 8 & 1); } void Sprite_90_Wallmaster(int k) { // 9eaea4 sprite_obj_prio[k] |= 0x30; WallMaster_Draw(k); if (sprite_state[k] != 9) { flag_is_link_immobilized = 0; link_disable_sprite_damage = 0; } if (Sprite_ReturnIfInactive(k)) return; if (sprite_A[k]) { link_x_coord = Sprite_GetX(k); link_y_coord = Sprite_GetY(k) - sprite_z[k] + 3; flag_is_link_immobilized = 1; link_disable_sprite_damage = 1; link_incapacitated_timer = 0; link_actual_vel_x = link_actual_vel_y = 0; link_y_vel = link_x_vel = 0; if ((uint16)(link_y_coord - BG2VOFS_copy2 - 16) >= 0x100) { flag_is_link_immobilized = 0; link_disable_sprite_damage = 0; WallMaster_SendPlayerToLastEntrance(); Link_Initialize(); return; } } else { Sprite_CheckDamageFromLink(k); } switch(sprite_ai_state[k]) { case 0: { // Descend uint8 old_z = sprite_z[k]; Sprite_MoveZ(k); if (!sign8(sprite_z_vel[k] + 64)) sprite_z_vel[k] -= 3; if (sign8(old_z ^ sprite_z[k]) && sign8(sprite_z[k])) { sprite_ai_state[k] = 1; sprite_z[k] = 0; sprite_z_vel[k] = 0; sprite_delay_main[k] = 63; } break; } case 1: // Attempt Grab if (!sprite_delay_main[k]) sprite_ai_state[k] = 2; sprite_graphics[k] = (sprite_delay_main[k] & 0x20) ? 0 : 1; if (Sprite_CheckDamageToLink(k)) { sprite_A[k] = 1; sprite_flags3[k] = 64; SpriteSfx_QueueSfx3WithPan(k, 0x2a); } break; case 2: { // Ascend uint8 old_z = sprite_z[k]; Sprite_MoveZ(k); if (sign8(sprite_z_vel[k] - 64)) sprite_z_vel[k] += 2; if (sign8(old_z ^ sprite_z[k]) && !sign8(sprite_z[k])) { sprite_state[k] = 0; } break; } } } void WallMaster_Draw(int k) { // 9eafe4 static const DrawMultipleData kWallMaster_Dmd[8] = { {-4, 0, 0x01a6, 2}, {12, 0, 0x01aa, 0}, {-4, 16, 0x01ba, 0}, { 4, 8, 0x01a8, 2}, {-4, 0, 0x01ab, 2}, {12, 0, 0x01af, 0}, {-4, 16, 0x01bf, 0}, { 4, 8, 0x01ad, 2}, }; Sprite_DrawMultiple(k, &kWallMaster_Dmd[sprite_graphics[k] * 4], 4, NULL); Sprite_DrawLargeShadow2(k); } void Sprite_8F_Blob(int k) { // 9eb002 if (sprite_state[k] == 9 && sprite_E[k]) { sprite_E[k] = 0; sprite_x_vel[k] = 1; uint8 t = Sprite_CheckTileCollision(k); sprite_x_vel[k] = 0; if (t) { sprite_state[k] = 0; return; } SpriteSfx_QueueSfx2WithPan(k, 0x20); } if (sprite_C[k]) sprite_obj_prio[k] = 0x30; Zol_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_ai_state[k] >= 2) { Sprite_CheckDamageFromLink(k); } if (Sprite_ReturnIfRecoiling(k)) return; switch(sprite_ai_state[k]) { case 0: { // hiding unseen uint8 bak = sprite_flags4[k]; sprite_flags4[k] |= 9; sprite_flags2[k] |= 0x80; uint8 t = Sprite_CheckDamageToLink(k); sprite_flags4[k] = bak; if (t) { sprite_ai_state[k]++; sprite_delay_main[k] = 127; sprite_flags2[k] &= ~0x80; Sprite_SetX(k, link_x_coord); Sprite_SetY(k, link_y_coord + 8); sprite_delay_aux4[k] = 48; sprite_ignore_projectile[k] = 0; } break; } case 1: { // popping out if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_z_vel[k] = 32; Sprite_ApplySpeedTowardsLink(k, 16); SpriteSfx_QueueSfx3WithPan(k, 0x30); } else { static const int8 kZol_PoppingOutGfx[16] = {0, 1, 7, 7, 6, 6, 5, 5, 6, 6, 5, 5, 4, 4, 4, 4}; sprite_graphics[k] = kZol_PoppingOutGfx[sprite_delay_main[k] >> 3]; } break; } case 2: { // falling if (sprite_delay_main[k] == 0) { Sprite_CheckDamageFromLink(k); Sprite_MoveXY(k); Sprite_CheckTileCollision(k); uint8 oldz = sprite_z[k]; Sprite_MoveZ(k); if (!sign8(sprite_z_vel[k] + 64)) sprite_z_vel[k] -= 2; if (sign8(sprite_z[k] ^ oldz) && sign8(sprite_z[k])) { sprite_z_vel[k] = 0; sprite_z[k] = 0; sprite_C[k] = 0; sprite_delay_main[k] = 31; sprite_head_dir[k] = 8; } } else if (sprite_delay_main[k] == 1) { sprite_delay_main[k] = 32; sprite_ai_state[k]++; sprite_graphics[k] = 0; } else { static const int8 kZol_FallingXvel[2] = {-8, 8}; static const int8 kZol_FallingGfx[2] = {0, 1}; sprite_graphics[k] = kZol_FallingGfx[(sprite_delay_main[k] - 1) >> 4]; sprite_x_vel[k] = kZol_FallingXvel[frame_counter >> 1 & 1]; Sprite_MoveX(k); } break; } case 3: // active Sprite_CheckDamageToLink(k); if (!sprite_delay_aux1[k]) { Sprite_ApplySpeedTowardsLink(k, 48); sprite_delay_aux1[k] = GetRandomNumber() & 63 | 96; sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | (sign8(sprite_x_vel[k]) ? 0x40 : 0); } if (!sprite_delay_aux2[k]) { sprite_subtype2[k]++; if (!(sprite_subtype2[k] & 14 | sprite_wallcoll[k])) { Sprite_MoveXY(k); if (++sprite_G[k] == sprite_head_dir[k]) { sprite_G[k] = 0; sprite_delay_aux2[k] = (GetRandomNumber() & 31) + 64; sprite_head_dir[k] = GetRandomNumber() & 31 | 16; } } Sprite_CheckTileCollision(k); sprite_graphics[k] = (sprite_subtype2[k] & 8) >> 3; } else { sprite_graphics[k] = sprite_delay_aux2[k] & 0x10 ? 1 : 0; } break; } } void Zol_Draw(int k) { // 9eb1c5 PrepOamCoordsRet info; if (!(sprite_oam_flags[k] & 1) && byte_7E0FC6 >= 3) return; if (sprite_delay_aux4[k]) Oam_AllocateFromRegionB(8); if (!sprite_ai_state[k]) { Sprite_PrepOamCoord(k, &info); return; } uint8 gfx = sprite_graphics[k]; if (gfx < 4) { static const uint8 kZol_OamFlags[4] = {0, 0, 0x40, 0x40}; uint8 bak1 = sprite_oam_flags[k]; sprite_oam_flags[k] = bak1 ^ kZol_OamFlags[gfx]; sprite_graphics[k] = gfx + ((sprite_oam_flags[k] & 1 ^ 1) << 2); SpriteDraw_SingleLarge(k); sprite_graphics[k] = gfx; sprite_oam_flags[k] = bak1; } else { static const DrawMultipleData kZol_Dmd[8] = { {0, 8, 0x036c, 0}, {8, 8, 0x036d, 0}, {0, 8, 0x0060, 0}, {8, 8, 0x0070, 0}, {0, 8, 0x4070, 0}, {8, 8, 0x4060, 0}, {0, 0, 0x0040, 2}, {0, 0, 0x0040, 2}, }; Sprite_DrawMultiple(k, &kZol_Dmd[(gfx - 4) * 2], 2, NULL); } } void Sprite_8E_Terrorpin(int k) { // 9eb26f int j; static const int8 kTerrorpin_Xvel[8] = {8, -8, 0, 0, 12, -12, 0, 0}; static const int8 kTerrorpin_Yvel[8] = {0, 0, 8, -8, 0, 0, 12, -12}; static const uint8 kTerrorpin_Oamflags[2] = {0, 0x40}; static const int8 kTerrorpin_Overturned_Xvel[2] = {8, -8}; SpriteDraw_SingleLarge(k); Sprite_CheckTileCollision(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; if (!sprite_delay_aux2[k]) Sprite_CheckDamageFromLink(k); Terrorpin_CheckForHammer(k); Sprite_MoveXYZ(k); switch (sprite_B[k]) { case 0: // upright if (!sprite_delay_aux4[k]) { sprite_delay_aux4[k] = (GetRandomNumber() & 31) + 32; sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL); } j = sprite_D[k] + sprite_G[k]; sprite_x_vel[k] = kTerrorpin_Xvel[j]; sprite_y_vel[k] = kTerrorpin_Yvel[j]; sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = 0; } sprite_graphics[k] = frame_counter >> (sprite_G[k] ? 2 : 3) & 1; sprite_flags3[k] |= 64; sprite_defl_bits[k] = 4; Sprite_CheckDamageToLink(k); break; case 1: // overturned sprite_flags3[k] &= 191; sprite_defl_bits[k] = 0; if (!sprite_delay_aux4[k]) { sprite_B[k] = 0; sprite_z_vel[k] = 32; sprite_delay_aux4[k] = 64; return; } sprite_z_vel[k] -= 2; if (sign8(sprite_z[k])) { sprite_z[k] = 0; uint8 t = (uint8)-sprite_z_vel[k] >> 1; sprite_z_vel[k] = (t < 9) ? 0 : t; sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1; if (sprite_x_vel[k] == 0xff) sprite_x_vel[k] = 0; sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1; if (sprite_y_vel[k] == 0xff) sprite_y_vel[k] = 0; } if (sprite_delay_aux4[k] < 64) { sprite_x_vel[k] = kTerrorpin_Overturned_Xvel[sprite_delay_aux4[k] >> 1 & 1]; sprite_subtype2[k]++; } sprite_graphics[k] = 2; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kTerrorpin_Oamflags[++sprite_subtype2[k] >> 3 & 1]; break; } } void Terrorpin_CheckForHammer(int k) { // 9eb3a3 if (!(sprite_z[k] | sprite_delay_aux2[k]) && sprite_floor[k] == link_is_on_lower_level && player_oam_y_offset != 0x80 && link_item_in_hand & 0xa) { SpriteHitBox hb; Player_SetupActionHitBox(&hb); Terrorpin_SetUpHammerHitBox(k, &hb); if (CheckIfHitBoxesOverlap(&hb)) { sprite_x_vel[k] = -sprite_x_vel[k]; sprite_y_vel[k] = -sprite_y_vel[k]; sprite_delay_aux2[k] = 32; sprite_z_vel[k] = 32; sprite_G[k] = 4; sprite_B[k] ^= 1; sprite_delay_aux4[k] = sprite_B[k] ? 0xff : 0x40; } } sprite_head_dir[k] = 0; } void Terrorpin_SetUpHammerHitBox(int k, SpriteHitBox *hb) { // 9eb405 int x = Sprite_GetX(k) - 16; int y = Sprite_GetY(k) - 16; hb->r4_spr_xlo = x; hb->r10_spr_xhi = x >> 8; hb->r5_spr_ylo = y; hb->r11_spr_yhi = y >> 8; hb->r6_spr_xsize = hb->r7_spr_ysize = 48; } void Sprite_8C_Arrghus(int k) { // 9eb433 static const uint8 kArrghus_Gfx[9] = {1, 1, 1, 2, 2, 1, 1, 0, 0}; sprite_obj_prio[k] |= 0x30; Arrghus_Draw(k); if (sprite_state[k] != 9 || sprite_z[k] < 96) { if (Sprite_ReturnIfInactive(k)) return; } Arrghus_HandlePuffs(k); overlord_x_lo[4] = 1; if ((sprite_hit_timer[k] & 127) == 2) { sprite_ai_state[k] = 3; SpriteSfx_QueueSfx3WithPan(k, 0x32); sprite_subtype2[k] = 0; sprite_flags3[k] = 64; } if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToLink(k); if (!(sprite_subtype2[k]++ & 3)) { if (++sprite_G[k] == 9) sprite_G[k] = 0; sprite_graphics[k] = kArrghus_Gfx[sprite_G[k]]; } uint8 a = Sprite_CheckTileCollision(k); if (a) { if (sprite_ai_state[k] == 5) { if (a & 3) sprite_x_vel[k] = -sprite_x_vel[k]; else sprite_y_vel[k] = -sprite_y_vel[k]; } else { Sprite_ZeroVelocity_XY(k); } } switch (sprite_ai_state[k]) { case 0: // approach speed if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; sprite_delay_main[k] = 48; } Sprite_MoveXY(k); Sprite_ApproachTargetSpeed(k, sprite_head_dir[k], sprite_D[k]); break; case 1: // decelerate if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; if (!Sprite_CheckIfScreenIsClear()) { if (++overlord_x_lo[3] == 4) { overlord_x_lo[3] = 0; sprite_ai_state[k] = 2; sprite_delay_main[k] = 176; } else { sprite_delay_main[k] = (GetRandomNumber() & 63) + 48; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, (sprite_delay_main[k] & 3) + 8); sprite_head_dir[k] = pt.x; sprite_D[k] = pt.y; } } else { sprite_ai_state[k] = 3; SpriteSfx_QueueSfx3WithPan(k, 0x32); sprite_subtype2[k] = 0; } } else { Sprite_MoveXY(k); Sprite_ApproachTargetSpeed(k, 0, 0); } break; case 2: // case2 overlord_x_lo[4] = 8; if (sprite_delay_main[k] < 32) { if (sign8(--overlord_x_lo[2])) { overlord_x_lo[2] = 0; sprite_ai_state[k] = 1; sprite_delay_main[k] = 112; } } else if (sprite_delay_main[k] < 96) { overlord_x_lo[2]++; } else if (sprite_delay_main[k] == 96) { SpriteSfx_QueueSfx3WithPan(k, 0x26); } else if ((sprite_delay_main[k] & 0xf) == 0) { SpriteSfx_QueueSfx3WithPan(k, 0x6); } break; case 3: // jump way up sprite_z_vel[k] = 120; Sprite_MoveZ(k); if (sprite_z[k] >= 224) { sprite_delay_main[k] = 64; sprite_ai_state[k] = 4; sprite_z_vel[k] = 0; sprite_x_lo[k] = link_x_coord; sprite_y_lo[k] = link_y_coord; } break; case 4: { // swoosh from above if (!(a = sprite_delay_main[k])) { sprite_z_vel[k] = 144; uint8 old_z = sprite_z[k]; Sprite_MoveZ(k); if (sign8(a = old_z ^ sprite_z[k]) && sign8(a = sprite_z[k])) { sprite_z[k] = 0; Sprite_SpawnBigSplash(k); sprite_ai_state[k] = 5; sprite_delay_main[k] = 32; SpriteSfx_QueueSfx3WithPan(k, 0x3); sprite_x_vel[k] = 32; sprite_y_vel[k] = 32; } } if (a == 1) { // wtf SpriteSfx_QueueSfx2WithPan(k, 0x20); } break; } case 5: // swim frantically if (!sprite_delay_main[k]) { sprite_flags3[k] = 0; Sprite_MoveXY(k); Sprite_CheckDamageFromLink(k); if (!(frame_counter & 7)) { SpriteSfx_QueueSfx2WithPan(k, 0x28); int j = GarnishAllocLimit(sign8(sprite_y_vel[k]) ? 29 : 14); if (j >= 0) { garnish_type[j] = 21; garnish_active = 21; garnish_x_lo[j] = sprite_x_lo[k]; garnish_x_hi[j] = sprite_x_hi[k]; garnish_y_lo[j] = sprite_y_lo[k] + 24; // why no carry propagation garnish_y_hi[j] = sprite_y_hi[k]; garnish_countdown[j] = 15; } } } break; } } void Arrghus_Draw(int k) { // 9eb840 static const DrawMultipleData kArrghus_Dmd[5] = { {-8, -4, 0x0080, 2}, { 8, -4, 0x4080, 2}, {-8, 12, 0x00a0, 2}, { 8, 12, 0x40a0, 2}, { 0, 24, 0x00a8, 2}, }; Sprite_DrawMultiple(k, kArrghus_Dmd, 5, NULL); OamEnt *oam = GetOamCurPtr(); uint8 chr = sprite_graphics[k] * 2; for (int i = 0; i < 4; i++) oam[i].charnum += chr; if (sprite_ai_state[k] == 5) oam[4].y = 0xf0; if (sprite_subtype2[k] & 8) oam[4].flags |= 0x40; if (sprite_ai_state[k] != 5) { oam_cur_ptr += 4, oam_ext_cur_ptr += 1; if (sprite_z[k] < 0xa0) { uint8 bak = sprite_oam_flags[k]; sprite_oam_flags[k] &= ~1; SpriteDraw_BigShadow(k, 0); sprite_oam_flags[k] = bak; } } else { Sprite_DrawLargeWaterTurbulence(k); } } void Arrghus_HandlePuffs(int k) { // 9eb8b4 static const uint16 kArrgi_Tab0[13] = {0, 0x40, 0x80, 0xc0, 0x100, 0x140, 0x180, 0x1c0, 0, 0x66, 0xcc, 0x132, 0x198}; static const uint16 kArrgi_Tab1[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0x1ff, 0x1ff, 0x1ff, 0x1ff, 0x1ff}; static const uint8 kArrgi_Tab2[13] = {0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xc, 0xc, 0xc, 0xc, 0xc}; static const int8 kArrgi_Tab3[52] = { 0, -1, -2, -3, -4, -5, -6, -6, -5, -4, -3, -2, -1, 0, -1, -2, -3, -4, -5, -6, -6, -5, -4, -3, -2, -1, 0, -1, -2, -3, -4, -5, -6, -6, -5, -4, -3, -2, -1, 0, -1, -2, -3, -4, -5, -6, -6, -5, -4, -3, -2, -1, }; WORD(overlord_x_lo[0]) += overlord_x_lo[4]; if (!(frame_counter & 3) && ++sprite_A[k] == 13) sprite_A[k] = 0; if (!(frame_counter & 7) && ++sprite_B[k] == 13) sprite_B[k] = 0; for(int i = 0; i != 13; i++) { uint16 r0 = (WORD(overlord_x_lo[0]) + kArrgi_Tab0[i]) ^ kArrgi_Tab1[i]; uint8 r14 = overlord_x_lo[2] + kArrgi_Tab2[i]; int8 sin_val = ArrgiSin(r0 + 0x00, r14 + kArrgi_Tab3[sprite_A[k] + i]); int8 cos_val = ArrgiSin(r0 + 0x80, r14 + kArrgi_Tab3[sprite_B[k] + i]); int tx = Sprite_GetX(k) + sin_val; overlord_x_hi[i] = tx; overlord_y_hi[i] = tx >> 8; int ty = Sprite_GetY(k) + cos_val - 0x10; overlord_gen2[i] = ty; overlord_floor[i] = ty >> 8; } tmp_counter = 13; } void Sprite_8D_Arrghi(int k) { // 9eb8c4 static const uint8 kArrgi_Gfx[8] = {0, 1, 2, 2, 2, 2, 2, 1}; sprite_obj_prio[k] |= 0x30; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; sprite_graphics[k] = kArrgi_Gfx[++sprite_subtype2[k] >> 3 & 7]; if (sprite_B[k]) { int j = sprite_B[k] - 1; if (ancilla_type[j]) { sprite_x_lo[k] = ancilla_x_lo[j]; sprite_x_hi[k] = ancilla_x_hi[j]; sprite_y_lo[k] = ancilla_y_lo[j]; sprite_y_hi[k] = ancilla_y_hi[j]; sprite_oam_flags[k] = 5; sprite_flags3[k] &= ~0x40; return; } sprite_ai_state[k] = 1; sprite_B[k] = 0; sprite_delay_main[k] = 32; } if (!sprite_delay_main[k]) Sprite_CheckDamageToLink(k); if (!sprite_ai_state[k]) { sprite_x_lo[k] = overlord_x_lo[k + 7]; sprite_x_hi[k] = overlord_y_lo[k + 7]; sprite_y_lo[k] = overlord_gen1[k + 7]; sprite_y_hi[k] = overlord_gen3[k + 7]; return; } Sprite_CheckDamageFromLink(k); if (!((k ^ frame_counter) & 3)) { uint16 x = overlord_y_lo[k + 7] << 8 | overlord_x_lo[k + 7]; uint16 y = overlord_gen3[k + 7] << 8 | overlord_gen1[k + 7]; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 4); sprite_y_vel[k] = pt.y; sprite_x_vel[k] = pt.x; if ((uint8)(sprite_x_lo[k] - overlord_x_lo[k + 7] + 8) < 16 && (uint8)(sprite_y_lo[k] - overlord_gen1[k + 7] + 8) < 16) { sprite_ai_state[k] = 0; sprite_oam_flags[k] = 0xd; sprite_flags3[k] |= 0x40; } } Sprite_MoveXY(k); } void Sprite_8B_Gibdo(int k) { // 9eb9a9 Gibdo_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); switch(sprite_ai_state[k]) { case 0: { static const uint8 kGibdo_DirTarget[4] = {2, 6, 4, 0}; static const uint8 kGibdo_Gfx[8] = {4, 8, 11, 10, 0, 6, 3, 7}; sprite_graphics[k] = kGibdo_Gfx[sprite_D[k]]; if (!(frame_counter & 7)) { int j = sprite_A[k]; if (sprite_D[k] - kGibdo_DirTarget[j]) { sprite_D[k] += sign8(sprite_D[k] - kGibdo_DirTarget[j]) ? 1 : -1; } else { sprite_delay_main[k] = (GetRandomNumber() & 31) + 48; sprite_ai_state[k] = 1; } } break; } case 1: { static const int8 kGibdo_XyVel[10] = {-16, 0, 0, 0, 16, 0, 0, 0, -16, 0}; static const uint8 kGibdo_Gfx2[8] = {9, 2, 0, 4, 11, 3, 1, 5}; int j = sprite_D[k]; sprite_x_vel[k] = kGibdo_XyVel[j + 2]; sprite_y_vel[k] = kGibdo_XyVel[j]; Sprite_MoveXY(k); Sprite_CheckTileCollision(k); if ((!sprite_delay_main[k] || sprite_wallcoll[k]) && (j = Sprite_DirectionToFaceLink(k, NULL)) != sprite_A[k]) { sprite_A[k] = j; sprite_ai_state[k] = 0; } else { if (sign8(--sprite_B[k])) { sprite_B[k] = 14; sprite_subtype2[k]++; } sprite_graphics[k] = kGibdo_Gfx2[(sprite_subtype2[k] & 1) << 2 | sprite_A[k]]; } break; } } } void Gibdo_Draw(int k) { // 9ebb20 static const DrawMultipleData kGibdo_Dmd[24] = { {0, -9, 0x0080, 2}, {0, 0, 0x008a, 2}, {0, -8, 0x0080, 2}, {0, 1, 0x408a, 2}, {0, -9, 0x0082, 2}, {0, 0, 0x008c, 2}, {0, -8, 0x0082, 2}, {0, 0, 0x008e, 2}, {0, -9, 0x0084, 2}, {0, 0, 0x00a0, 2}, {0, -8, 0x0084, 2}, {0, 1, 0x40a0, 2}, {0, -9, 0x0086, 2}, {0, 0, 0x00a2, 2}, {0, -9, 0x0088, 2}, {0, 0, 0x00a4, 2}, {0, -9, 0x4088, 2}, {0, 0, 0x40a4, 2}, {0, -9, 0x4082, 2}, {0, 0, 0x408c, 2}, {0, -9, 0x4086, 2}, {0, 0, 0x40a2, 2}, {0, -8, 0x4082, 2}, {0, 1, 0x408e, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kGibdo_Dmd[sprite_graphics[k] * 2], 2, &info); if (!sprite_pause[k]) SpriteDraw_Shadow(k, &info); } void Sprite_89_MothulaBeam(int k) { // 9ebb42 SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToLink(k); if (!(frame_counter & 1)) sprite_oam_flags[k] ^= 0x80; Sprite_MoveXY(k); if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k)) sprite_state[k] = 0; if ((k ^ frame_counter) & 3) return; for (int i = 14; i >= 0; i--) { if (garnish_type[i] == 0) { garnish_type[i] = 2; garnish_active = 2; garnish_x_lo[i] = sprite_x_lo[k]; garnish_x_hi[i] = sprite_x_hi[k]; garnish_y_lo[i] = sprite_y_lo[k]; garnish_y_hi[i] = sprite_y_hi[k]; garnish_countdown[i] = 16; garnish_sprite[i] = k; garnish_floor[i] = sprite_floor[k]; break; } } } void Sprite_94_Tile(int k) { // 9ebbb9 sprite_obj_prio[k] = 0x30; FlyingTile_Draw(k); if (Sprite_ReturnIfPaused(k)) return; if (sprite_hit_timer[k]) goto lbl_a; sprite_ignore_projectile[k] = 1; switch (sprite_ai_state[k]) { case 0: // erase tilemap Dungeon_UpdateTileMapWithCommonTile(Sprite_GetX(k), (sprite_y_lo[k] + 8) & 0xff | (sprite_y_hi[k] << 8), 6); sprite_ai_state[k] = 1; sprite_delay_main[k] = 128; break; case 1: // rise up if (!sprite_delay_main[k]) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 16; Sprite_ApplySpeedTowardsLink(k, 32); } else { if (sprite_delay_main[k] >= 0x40) { sprite_z_vel[k] = 4; Sprite_MoveZ(k); } lbl_b: sprite_graphics[k] = ++sprite_subtype2[k] >> 2 & 1; if (!((k ^ frame_counter) & 7)) SpriteSfx_QueueSfx2WithPan(k, 0x7); } break; case 2: // towards player sprite_ignore_projectile[k] = 0; if (sprite_delay_main[k] && (sprite_delay_main[k] & 3) == 0) Sprite_ApplySpeedTowardsLink(k, 32); if (!Sprite_CheckDamageToAndFromLink(k)) { Sprite_MoveXY(k); cur_sprite_y -= sprite_z[k]; if (!Sprite_CheckTileCollision(k)) goto lbl_b; } lbl_a: SpriteSfx_QueueSfx2WithPan(k, 0x1f); sprite_state[k] = 6; sprite_delay_main[k] = 31; sprite_type[k] = 0xec; sprite_hit_timer[k] = 0; sprite_C[k] = 0x80; break; } } void FlyingTile_Draw(int k) { // 9ebcca static const DrawMultipleData kFlyingTile_Dmd[8] = { {0, 0, 0x00d3, 0}, {8, 0, 0x40d3, 0}, {0, 8, 0x80d3, 0}, {8, 8, 0xc0d3, 0}, {0, 0, 0x00c3, 0}, {8, 0, 0x40c3, 0}, {0, 8, 0x80c3, 0}, {8, 8, 0xc0c3, 0}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kFlyingTile_Dmd[sprite_graphics[k] * 4], 4, &info); SpriteDraw_Shadow(k, &info); } void Sprite_8A_SpikeBlock(int k) { // 9ebce8 if (!sprite_E[k]) { SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToAndFromLink(k); Sprite_MoveXY(k); Sprite_CheckTileCollision(k); if (!sprite_delay_main[k] && (!SpikeBlock_CheckStatueCollision(k) || (sprite_wallcoll[k] & 0xf))) { sprite_delay_main[k] = 4; sprite_x_vel[k] = -sprite_x_vel[k]; SpriteSfx_QueueSfx2WithPan(k, 0x5); } return; } Oam_AllocateFromRegionB(4); SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToAndFromLink(k); if (sprite_ai_state[k] == 0) { Dungeon_UpdateTileMapWithCommonTile(Sprite_GetX(k), Sprite_GetY(k), 0); sprite_ai_state[k] = 1; sprite_delay_main[k] = 64; sprite_delay_aux1[k] = 105; } else if (sprite_delay_main[k] != 0) { if (sprite_delay_main[k] == 1) { sprite_x_lo[k] = sprite_A[k]; sprite_y_lo[k] = sprite_B[k]; } else { sprite_x_vel[k] = (sprite_delay_main[k] >> 1) & 1 ? -8 : 8; Sprite_MoveX(k); sprite_x_vel[k] = 0; } } else if (sprite_ai_state[k] == 1) { static const int8 kSpikeBlock_XVelTarget[4] = {32, -32, 0, 0}; static const int8 kSpikeBlock_YVelTarget[4] = {0, 0, 32, -32}; static const int8 kSpikeBlock_XVelDelta[4] = {1, -1, 0, 0}; static const int8 kSpikeBlock_YVelDelta[4] = {0, 0, 1, -1}; int j = sprite_D[k]; if (sprite_x_vel[k] != (uint8)kSpikeBlock_XVelTarget[j]) sprite_x_vel[k] += kSpikeBlock_XVelDelta[j]; if (sprite_y_vel[k] != (uint8)kSpikeBlock_YVelTarget[j]) sprite_y_vel[k] += kSpikeBlock_YVelDelta[j]; Sprite_MoveXY(k); if (!sprite_delay_aux1[k]) { Sprite_Get16BitCoords(k); if (Sprite_CheckTileCollision(k)) { sprite_ai_state[k] = 2; sprite_delay_aux1[k] = 64; } } } else if (sprite_delay_aux1[k] == 0) { static const int8 kSpikeBlock_XVel[4] = {-16, 16, 0, 0}; static const int8 kSpikeBlock_YVel[4] = {0, 0, -16, 16}; int j = sprite_D[k]; sprite_x_vel[k] = kSpikeBlock_XVel[j]; sprite_y_vel[k] = kSpikeBlock_YVel[j]; Sprite_MoveXY(k); if (sprite_x_lo[k] == sprite_A[k] && sprite_y_lo[k] == sprite_B[k]) { sprite_state[k] = 0; Dungeon_UpdateTileMapWithCommonTile(Sprite_GetX(k), Sprite_GetY(k), 2); } } } bool SpikeBlock_CheckStatueCollision(int k) { // 9ebe19 for (int j = 15; j >= 0; j--) { if (!((j ^ frame_counter) & 1) && sprite_state[j] && sprite_type[j] == 0x1c) { int x0 = Sprite_GetX(k), y0 = Sprite_GetY(k); int x1 = Sprite_GetX(j), y1 = Sprite_GetY(j); if ((uint16)(x0 - x1 + 16) < 32 && (uint16)(y0 - y1 + 16) < 32) return false; } } return true; } void Sprite_88_Mothula(int k) { // 9ebe7e Mothula_Main(k); if (Sprite_ReturnIfInactive(k)) return; Mothula_HandleSpikes(k); } void Mothula_Main(int k) { // 9ebe88 int j; Mothula_Draw(k); if (sprite_state[k] == 11) sprite_ai_state[k] = 0; if (Sprite_ReturnIfInactive(k)) return; sprite_flags3[k] = 0; if (sprite_delay_aux3[k]) sprite_flags3[k] = 64; if ((sprite_F[k] & 127) == 6) { sprite_F[k] = 0; sprite_delay_aux3[k] = 32; sprite_ai_state[k] = 2; sprite_delay_main[k] = 0; sprite_G[k] = 64; } if (Sprite_ReturnIfRecoiling(k)) return; switch(sprite_ai_state[k]) { case 0: // Delay if (!sprite_delay_main[k]) sprite_ai_state[k] = 1; break; case 1: // Ascend sprite_z_vel[k] = 8; Sprite_MoveZ(k); sprite_z_vel[k] = 0; if (sprite_z[k] >= 24) { sprite_G[k] = 128; sprite_ai_state[k] = 2; sprite_ignore_projectile[k] = 0; sprite_delay_main[k] = 64; } Mothula_FlapWings(k); break; case 2: // FlyAbout if (!sprite_G[k]) { sprite_delay_main[k] = 63; sprite_ai_state[k] = 3; return; } sprite_G[k]--; Mothula_FlapWings(k); j = sprite_A[k] & 1; sprite_z_vel[k] += j ? -1 : 1; if (sprite_z_vel[k] == (uint8)(j ? -16 : 16)) sprite_A[k]++; if (!sprite_delay_main[k]) { if (++sprite_C[k] == 7) { sprite_C[k] = 0; Sprite_ApplySpeedTowardsLink(k, 32); sprite_delay_main[k] = 128; } else { static const int8 kMothula_XYvel[10] = {-16, -12, 0, 12, 16, 12, 0, -12, -16, -12}; j = GetRandomNumber() & 7; sprite_x_vel[k] = kMothula_XYvel[j + 2]; sprite_y_vel[k] = kMothula_XYvel[j]; sprite_delay_main[k] = (GetRandomNumber() & 31) + 64; } } if (!sprite_wallcoll[k]) Sprite_MoveXY(k); Sprite_MoveZ(k); if (Sprite_CheckTileCollision(k)) sprite_delay_main[k] = 0; Sprite_CheckDamageToAndFromLink(k); sprite_subtype2[k] += 2; break; case 3: // FireBeams Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) { sprite_ai_state[k]--; sprite_G[k] = GetRandomNumber() & 31 | 64; } else { if (sprite_delay_main[k] == 0x20) Mothula_SpawnBeams(k); Mothula_FlapWings(k); } break; } } void Mothula_FlapWings(int k) { // 9ebf9f static const uint8 kMothula_FlapWingsGfx[4] = {0, 1, 2, 1}; int j = ++sprite_subtype2[k] >> 2 & 3; if (j == 0) SpriteSfx_QueueSfx3WithPan(k, 0x2); sprite_graphics[k] = kMothula_FlapWingsGfx[j]; } void Mothula_SpawnBeams(int k) { // 9ebfdf static const int8 kMothula_Beam_Xvel[3] = {-16, 0, 16}; static const int8 kMothula_Beam_Yvel[3] = {24, 32, 24}; SpriteSfx_QueueSfx3WithPan(k, 0x36); for (int i = 2; i >= 0; i--) { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x89, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_y_lo[j] = info.r2_y - info.r4_z + 3; sprite_delay_main[j] = 16; sprite_ignore_projectile[j] = 16; sprite_x_lo[j] = info.r0_x + kMothula_Beam_Xvel[i]; sprite_x_vel[j] = kMothula_Beam_Xvel[i]; sprite_y_vel[j] = kMothula_Beam_Yvel[i]; sprite_z[j] = 0; } } tmp_counter = 0xff; } void Mothula_HandleSpikes(int k) { // 9ec088 static const uint8 kMothula_Spike_XLo[30] = { 0x38, 0x48, 0x58, 0x68, 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xb8, 0xa8, 0x98, 0x78, 0x68, 0x58, 0x48, 0x38, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, }; static const uint8 kMothula_Spike_YLo[30] = { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x48, 0x58, 0x68, 0x78, 0x98, 0xa8, 0xb8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xb8, 0xa8, 0x98, 0x78, 0x68, 0x58, 0x48, }; static const uint8 kMothula_Spike_Dir[30] = { 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, }; if (--sprite_head_dir[k]) return; sprite_head_dir[k] = 0x40; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x8a, &info); if (j < 0) return; int i = GetRandomNumber() & 0x1f; if (i >= 30) i -= 30; sprite_A[j] = sprite_x_lo[j] = kMothula_Spike_XLo[i]; sprite_B[j] = sprite_y_lo[j] = kMothula_Spike_YLo[i] - 1; sprite_D[j] = kMothula_Spike_Dir[i]; sprite_E[j] = 1; sprite_x_hi[j] = byte_7E0FB0 + 1; sprite_y_hi[j] = byte_7E0FB1 + 1; sprite_x_vel[j] = 1; Sprite_Get16BitCoords(j); Sprite_CheckTileCollision(j); sprite_x_vel[j] = 0; sprite_x_lo[j] = sprite_A[j]; sprite_y_lo[j] = sprite_B[j]; if (!sprite_wallcoll[j]) { sprite_state[j] = 0; sprite_head_dir[k] = 1; } } void Sprite_86_Kodongo(int k) { // 9ec103 static const int8 kKodondo_Xvel[4] = {1, -1, 0, 0}; static const int8 kKodondo_Yvel[4] = {0, 0, 1, -1}; static const uint8 kKodondo_Gfx[8] = {2, 2, 0, 5, 3, 3, 0, 5}; static const uint8 kKodondo_OamFlags[8] = {0x40, 0, 0, 0, 0x40, 0, 0x40, 0x40}; static const uint8 kKodondo_FlameGfx[8] = {2, 2, 0, 5, 4, 4, 1, 6}; int j; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); sprite_flags[k] = 0; switch(sprite_ai_state[k]) { case 0: // choose dir sprite_ai_state[k]++; sprite_D[k] = GetRandomNumber() & 3; sprite_flags[k] = 176; for(;;) { j = sprite_D[k]; sprite_x_vel[k] = kKodondo_Xvel[j]; sprite_y_vel[k] = kKodondo_Yvel[j]; if (!Sprite_CheckTileCollision(k)) break; sprite_D[k] = (sprite_D[k] + 1) & 3; } Kodongo_SetDirection(k); break; case 1: // move Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) { sprite_D[k] ^= 1; Kodongo_SetDirection(k); } if ((sprite_x_lo[k] & 0x1f) == 4 && (sprite_y_lo[k] & 0x1f) == 0x1b && (GetRandomNumber() & 3) == 0) { sprite_delay_main[k] = 111; sprite_ai_state[k] = 2; sprite_A[k] = 0; } j = ++sprite_subtype2[k] & 4 | sprite_D[k]; sprite_graphics[k] = kKodondo_Gfx[j]; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kKodondo_OamFlags[j]; break; case 2: // breathe flame if (!sprite_delay_main[k]) sprite_ai_state[k] = 0; j = (uint8)(sprite_delay_main[k] - 0x20) < 0x30; if (j && (sprite_delay_main[k] & 0xf) == 0) Kodongo_SpawnFire(k); sprite_graphics[k] = kKodondo_FlameGfx[j * 4 + sprite_D[k]]; break; } } void Kodongo_SetDirection(int k) { // 9ec158 int j = sprite_D[k]; sprite_x_vel[k] = kFluteBoyAnimal_Xvel[j]; sprite_y_vel[k] = kZazak_Yvel[j]; } void Kodongo_SpawnFire(int k) { // 9ec223 static const int8 kKodondo_Flame_X[4] = {8, -8, 0, 0}; static const int8 kKodondo_Flame_Y[4] = {0, 0, 8, -8}; static const int8 kKodondo_Flame_Xvel[4] = {24, -24, 0, 0}; static const int8 kKodondo_Flame_Yvel[4] = {0, 0, 24, -24}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamicallyEx(k, 0x87, &info, 13); if (j >= 0) { int i = sprite_D[k]; Sprite_SetX(j, info.r0_x + kKodondo_Flame_X[i]); Sprite_SetY(j, info.r2_y + kKodondo_Flame_Y[i]); sprite_x_vel[j] = kKodondo_Flame_Xvel[i]; sprite_y_vel[j] = kKodondo_Flame_Yvel[i]; sprite_ignore_projectile[j] = 1; } } void Sprite_87_KodongoFire(int k) { // 9ec274 static const uint8 kFlame_OamFlags[4] = { 0, 0x40, 0xc0, 0x80 }; static const int8 kFlame_Gfx[32] = { 5, 4, 3, 1, 2, 0, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, }; if (!sprite_delay_main[k]) { SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kFlame_OamFlags[frame_counter >> 2 & 3]; if (!Sprite_CheckDamageToLink(k)) { Sprite_MoveXY(k); if (!Sprite_CheckTileCollision(k)) return; } sprite_delay_main[k] = 127; sprite_oam_flags[k] &= 63; SpriteSfx_QueueSfx2WithPan(k, 0x2a); } else { if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Carry && !--sprite_delay_main[k] || sprite_delay_main[k] == 1) sprite_state[k] = 0; sprite_graphics[k] = kFlame_Gfx[sprite_delay_main[k] >> 3]; Flame_Draw(k); Sprite_CheckDamageToLink(k); } } void Flame_Draw(int k) { // 9ec35c static const DrawMultipleData kFlame_Dmd[12] = { {0, 0, 0x018e, 2}, {0, 0, 0x018e, 2}, {0, 0, 0x01a0, 2}, {0, 0, 0x01a0, 2}, {0, 0, 0x418e, 2}, {0, 0, 0x418e, 2}, { 0, 0, 0x41a0, 2 }, { 0, 0, 0x41a0, 2 }, { 0, 0, 0x01a2, 2 }, { 0, 0, 0x01a2, 2 }, { 0, -6, 0x01a4, 0 }, { 8, -6, 0x01a5, 0 }, }; Sprite_DrawMultiple(k, &kFlame_Dmd[sprite_graphics[k] * 2], 2, NULL); } void Sprite_85_YellowStalfos(int k) { // 9ec37f static const int8 kYellowStalfos_ObjPrio[6] = {0x30, 0, 0, 0, 0x30, 0}; static const int8 kYellowStalfos_Gfx[32] = { 8, 5, 1, 1, 8, 5, 1, 1, 8, 5, 1, 1, 7, 4, 2, 2, 7, 4, 2, 2, 7, 4, 2, 2, 7, 4, 2, 2, 7, 4, 2, 2, }; static const int8 kYellowStalfos_HeadX[32] = { -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0, 0, 0, 0, }; static const uint8 kYellowStalfos_HeadY[32] = { 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, }; static const int8 kYellowStalfos_NeutralizedGfx[16] = {1, 1, 1, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9}; static const int8 kYellowStalfos_NeutralizedHeadY[16] = {10, 10, 10, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7}; int j; if (!sprite_A[k]) { sprite_x_vel[k] = 1; sprite_y_vel[k] = 1; if (Sprite_CheckTileCollision(k)) { sprite_state[k] = 0; return; } sprite_A[k]++; sprite_C[k] = 10; sprite_flags3[k] |= 64; SpriteSfx_QueueSfx2WithPan(k, 0x20); } sprite_obj_prio[k] |= kYellowStalfos_ObjPrio[sprite_ai_state[k]]; YellowStalfos_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (link_sword_type >= 3) { if (Sprite_ReturnIfRecoiling(k)) return; } else if (sprite_ai_state[k] != 5 && sprite_hit_timer[k]) { sprite_hit_timer[k] = 0; sprite_ai_state[k] = 5; sprite_delay_main[k] = 255; } sprite_ignore_projectile[k] = 1; switch (sprite_ai_state[k]) { case 0: { // descend sprite_head_dir[k] = 2; uint8 bak0 = sprite_z[k]; Sprite_MoveZ(k); if (!sign8(sprite_z_vel[k] - 192)) sprite_z_vel[k] -= 3; if (!sign8(bak0) && sign8(sprite_z[k])) { sprite_ai_state[k]++; sprite_z[k] = 0; sprite_z_vel[k] = 0; sprite_delay_main[k] = 64; YellowStalfos_Animate(k); } break; } case 1: // face player sprite_ignore_projectile[k] = 0; Sprite_CheckDamageToAndFromLink(k); sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL); if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 127; } sprite_flags3[k] &= ~0x40; break; case 2: // pause then detach head sprite_ignore_projectile[k] = 0; Sprite_CheckDamageToAndFromLink(k); j = sprite_delay_main[k]; if (!j) { sprite_ai_state[k]++; sprite_delay_main[k] = 64; return; } if (j == 48) YellowStalfos_EmancipateHead(k); sprite_graphics[k] = kYellowStalfos_Gfx[j >> 2 & ~3 | sprite_D[k]]; j = sprite_delay_main[k] >> 2; sprite_B[k] = kYellowStalfos_HeadX[j]; sprite_C[k] = kYellowStalfos_HeadY[j]; sprite_flags3[k] &= ~0x40; break; case 3: // delay before ascending sprite_ignore_projectile[k] = 0; Sprite_CheckDamageToAndFromLink(k); if (!sprite_delay_main[k]) sprite_ai_state[k]++; YellowStalfos_Animate(k); break; case 4: // ascend sprite_graphics[k] = 0; sprite_head_dir[k] = 2; j = sprite_z[k]; Sprite_MoveZ(k); if (sign8(sprite_z_vel[k] - 64)) sprite_z_vel[k] += 2; if (sign8(j) && !sign8(sprite_z[k])) sprite_state[k] = 0; break; case 5: // neutralized sprite_ignore_projectile[k] = 0; Sprite_CheckDamageFromLink(k); j = sprite_delay_main[k]; if (!j) sprite_ai_state[k]--; sprite_graphics[k] = kYellowStalfos_NeutralizedGfx[j >> 4]; sprite_C[k] = kYellowStalfos_NeutralizedHeadY[j >> 4]; break; } } void YellowStalfos_Animate(int k) { // 9ec509 static const uint8 kYellowStalfos_Gfx2[4] = {6, 3, 1, 1}; sprite_graphics[k] = kYellowStalfos_Gfx2[sprite_D[k]]; sprite_flags3[k] &= ~0x40; } void YellowStalfos_EmancipateHead(int k) { // 9ec580 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 2, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_z[j] = 13; Sprite_ApplySpeedTowardsLink(j, 16); sprite_delay_main[j] = 255; sprite_delay_aux1[j] = 32; } } void YellowStalfos_Draw(int k) { // 9ec655 static const DrawMultipleData kYellowStalfos_Dmd[22] = { {0, 0, 0x000a, 2}, {0, 0, 0x000a, 2}, {0, 0, 0x000c, 2}, {0, 0, 0x000c, 2}, {0, 0, 0x002c, 2}, {0, 0, 0x002c, 2}, {5, 5, 0x002e, 0}, {0, 0, 0x0024, 2}, {4, 1, 0x003e, 0}, {0, 0, 0x0024, 2}, {0, 0, 0x000e, 2}, {0, 0, 0x000e, 2}, {3, 5, 0x402e, 0}, {0, 0, 0x4024, 2}, {4, 1, 0x403e, 0}, {0, 0, 0x4024, 2}, {0, 0, 0x400e, 2}, {0, 0, 0x400e, 2}, {0, 0, 0x002a, 2}, {0, 0, 0x002a, 2}, {0, 0, 0x002a, 2}, {0, 0, 0x002a, 2}, }; oam_cur_ptr += 4, oam_ext_cur_ptr++; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kYellowStalfos_Dmd[sprite_graphics[k] * 2], 2, &info); oam_cur_ptr -= 4, oam_ext_cur_ptr--; if (!sprite_pause[k]) { YellowStalfos_DrawHead(k, &info); SpriteDraw_Shadow(k, &info); } } void YellowStalfos_DrawHead(int k, PrepOamCoordsRet *info) { // 9ec69a static const uint8 kYellowStalfos_Head_Char[4] = {2, 2, 0, 4}; static const uint8 kYellowStalfos_Head_Flags[4] = {0x40, 0, 0, 0}; OamEnt *oam = GetOamCurPtr(); if (sprite_graphics[k] == 10 || sprite_B[k] == 0x80) return; uint16 x = info->x + (int8)sprite_B[k]; uint16 y = info->y - sprite_C[k]; int j = sprite_head_dir[k]; oam->x = x; oam->y = ClampYForOam(y); oam->charnum = kYellowStalfos_Head_Char[j]; oam->flags = kYellowStalfos_Head_Flags[j] | info->flags; bytewise_extended_oam[oam - oam_buf] = 2 | (x >> 8 & 1); } void SpritePrep_Eyegore(int k) { // 9ec700 uint8 t = BYTE(dungeon_room_index2); if (t == 12 || t == 27 || t == 75 || t == 107) { sprite_B[k]++; if (sprite_type[k] == 0x83) sprite_defl_bits[k] = 0; } } void Sprite_83_GreenEyegore(int k) { // 9ec79b static const int8 kGoriya_Xvel[32] = { 0, 16, -16, 0, 0, 13, -13, 0, 0, 13, -13, 0, 0, 0, 0, 0, 0, -24, 24, 0, 0, -16, 16, 0, 0, -16, 16, 0, 0, 0, 0, 0, }; static const int8 kGoriya_Yvel[32] = { 0, 0, 0, 0, -16, -5, -5, 0, 16, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, -24, -16, -16, 0, 24, 16, 16, 0, 0, 0, 0, 0, }; static const uint8 kGoriya_Dir[32] = { 0, 0, 1, 0, 3, 3, 3, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 3, 3, 3, 0, 2, 2, 2, 0, 0, 0, 0, 0, }; static const uint8 kGoriya_Gfx[16] = {8, 6, 0, 3, 9, 7, 1, 4, 8, 6, 0, 3, 9, 7, 2, 5}; if (!sprite_B[k]) { Eyegore_Main(k); return; } Goriya_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; if (sprite_delay_aux1[k] == 8) Sprite_SpawnFirePhlegm(k); if (bitmask_of_dragstate != 0 || !(joypad1H_last & 0xf)) { sprite_A[k] = 0; Sprite_CheckDamageToAndFromLink(k); Sprite_CheckTileCollision(k); return; } int j = (joypad1H_last & 0xf) | (sprite_type[k] == 0x84) * 16; sprite_D[k] = kGoriya_Dir[j]; sprite_x_vel[k] = kGoriya_Xvel[j]; sprite_y_vel[k] = kGoriya_Yvel[j]; if (!sprite_wallcoll[k]) Sprite_MoveXY(k); Sprite_CheckDamageToAndFromLink(k); Sprite_CheckTileCollision(k); sprite_graphics[k] = kGoriya_Gfx[++sprite_subtype2[k] & 12 | sprite_D[k]]; if (sprite_type[k] == 0x84) { PointU8 pt; uint8 dir = Sprite_DirectionToFaceLink(k, &pt); if (((uint8)(pt.x + 8) < 16 || (uint8)(pt.y + 8) < 16) && sprite_D[k] == dir) { if (!(sprite_A[k] & 0x1f)) sprite_delay_aux1[k] = 16; sprite_A[k]++; return; } } sprite_A[k] = 0; } void Eyegore_Main(int k) { // 9ec839 static const uint8 kEyeGore_Closing_Gfx[8] = {0, 0, 1, 1, 2, 2, 2, 2}; static const uint8 kEyeGore_Opening_Gfx[8] = {2, 2, 2, 2, 1, 1, 0, 0}; static const uint8 kEyeGore_Chasing_Gfx[16] = {7, 5, 2, 9, 8, 6, 3, 10, 7, 5, 2, 9, 8, 6, 4, 11}; static const uint8 kEyeGore_Opening_Delay[4] = {0x60, 0x80, 0xa0, 0x80}; Eyegore_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); sprite_flags3[k] |= 64; sprite_defl_bits[k] |= 4; switch (sprite_ai_state[k]) { case 0: // wait until player if (!sprite_delay_main[k]) { PointU8 pt; Sprite_DirectionToFaceLink(k, &pt); if ((uint8)(pt.x + 48) < 96 && (uint8)(pt.y + 48) < 96) { sprite_ai_state[k]++; sprite_delay_main[k] = 63; } } break; case 1: // openig eye if (!sprite_delay_main[k]) { sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL); sprite_ai_state[k] = 2; sprite_delay_main[k] = kEyeGore_Opening_Delay[GetRandomNumber() & 3]; } else { sprite_graphics[k] = kEyeGore_Opening_Gfx[sprite_delay_main[k] >> 3]; } break; case 2: // chase player sprite_flags3[k] &= ~0x40; if (sprite_type[k] != 0x84) sprite_defl_bits[k] &= ~4; if (!sprite_delay_main[k]) { sprite_delay_main[k] = 63; sprite_ai_state[k]++; sprite_graphics[k] = 0; } else { if (!((k ^ frame_counter) & 31)) sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL); int j = sprite_D[k]; sprite_x_vel[k] = kFluteBoyAnimal_Xvel[j]; sprite_y_vel[k] = kZazak_Yvel[j]; if (!sprite_wallcoll[k]) Sprite_MoveXY(k); Sprite_CheckTileCollision(k); sprite_graphics[k] = kEyeGore_Chasing_Gfx[++sprite_subtype2[k] & 12 | sprite_D[k]]; } break; case 3: // closing eye if (!sprite_delay_main[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 96; } else { sprite_graphics[k] = kEyeGore_Closing_Gfx[sprite_delay_main[k] >> 3]; } break; } } void Eyegore_Draw(int k) { // 9ecacf static const DrawMultipleData kEyeGore_Dmd[48] = { {-4, -4, 0x00a2, 2}, { 4, -4, 0x40a2, 2}, {-4, 4, 0x009c, 2}, { 4, 4, 0x409c, 2}, {-4, -4, 0x00a4, 2}, { 4, -4, 0x40a4, 2}, {-4, 4, 0x009c, 2}, { 4, 4, 0x409c, 2}, {-4, -4, 0x008c, 2}, { 4, -4, 0x408c, 2}, {-4, 4, 0x009c, 2}, { 4, 4, 0x409c, 2}, {-4, -3, 0x008c, 2}, {12, -3, 0x408c, 0}, {-4, 13, 0x00bc, 0}, { 4, 5, 0x408a, 2}, {-4, -3, 0x008c, 0}, { 4, -3, 0x408c, 2}, {-4, 5, 0x008a, 2}, {12, 13, 0x40bc, 0}, { 0, -4, 0x00aa, 2}, { 0, 4, 0x00a6, 2}, { 0, -4, 0x00aa, 2}, { 0, 4, 0x00a6, 2}, { 0, -3, 0x00aa, 2}, { 0, 4, 0x00a8, 2}, { 0, -3, 0x00aa, 2}, { 0, 4, 0x00a8, 2}, { 0, -4, 0x40aa, 2}, { 0, 4, 0x40a6, 2}, { 0, -4, 0x40aa, 2}, { 0, 4, 0x40a6, 2}, { 0, -3, 0x40aa, 2}, { 0, 4, 0x40a8, 2}, { 0, -3, 0x40aa, 2}, { 0, 4, 0x40a8, 2}, {-4, -4, 0x008e, 2}, { 4, -4, 0x408e, 2}, {-4, 4, 0x009e, 2}, { 4, 4, 0x409e, 2}, {-4, -3, 0x008e, 2}, {12, -3, 0x408e, 0}, {-4, 13, 0x00bd, 0}, { 4, 5, 0x40a0, 2}, {-4, -3, 0x008e, 0}, { 4, -3, 0x408e, 2}, {-4, 5, 0x00a0, 2}, {12, 13, 0x40bd, 0}, }; PrepOamCoordsRet info; Sprite_DrawMultiple(k, &kEyeGore_Dmd[sprite_graphics[k] * 4], 4, &info); if (!sprite_pause[k]) SpriteDraw_Shadow_custom(k, &info, 14); } void SpritePrep_AntifairyCircle(int k) { // 9ecb0c static const int8 kBubbleGroup_X[3] = {10, 20, 10}; static const int8 kBubbleGroup_Y[3] = {-10, 0, 10}; static const int8 kBubbleGroup_Xvel[3] = {18, 0, -18}; static const int8 kBubbleGroup_Yvel[3] = {0, 18, 0}; static const int8 kBubbleGroup_A[3] = {1, 1, 0}; static const int8 kBubbleGroup_B[3] = { 0, 1, 1 }; Sprite_SetX(k, Sprite_GetX(k) - 10); sprite_y_vel[k] = -18; sprite_x_vel[k] = 0; sprite_A[k] = 0; sprite_B[k] = 0; tmp_counter = 2; do { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x82, &info); if (j >= 0) { int i = tmp_counter; Sprite_SetX(j, info.r0_x + kBubbleGroup_X[i]); Sprite_SetY(j, info.r2_y + kBubbleGroup_Y[i]); sprite_x_vel[j] = kBubbleGroup_Xvel[i]; sprite_y_vel[j] = kBubbleGroup_Yvel[i]; sprite_A[j] = kBubbleGroup_A[i]; sprite_B[j] = kBubbleGroup_B[i]; } } while (!sign8(--tmp_counter)); } void Sprite_82_AntifairyCircle(int k) { // 9ecb97 static const int8 kBubbleGroup_Vel[2] = {1, -1}; static const uint8 kBubbleGroup_VelTarget[2] = {18, (uint8)-18}; SpriteDraw_Antfairy(k); if (Sprite_ReturnIfInactive(k)) return; int j = sprite_A[k] & 1; if ((sprite_x_vel[k] += kBubbleGroup_Vel[j]) == kBubbleGroup_VelTarget[j]) sprite_A[k]++; j = sprite_B[k] & 1; if ((sprite_y_vel[k] += kBubbleGroup_Vel[j]) == kBubbleGroup_VelTarget[j]) sprite_B[k]++; Sprite_MoveXY(k); if (sprite_x_vel[k] && sprite_y_vel[k] && Sprite_CheckIfRoomIsClear()) { sprite_type[k] = 0x15; sprite_x_vel[k] = sign8(sprite_x_vel[k]) ? -16 : 16; sprite_y_vel[k] = sign8(sprite_y_vel[k]) ? -16 : 16; } Sprite_CheckDamageToLink(k); } void Sprite_81_Hover(int k) { // 9ecc02 static const int8 kHover_OamFlags[4] = {0x40, 0, 0x40, 0}; sprite_obj_prio[k] |= 48; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_F[k]) sprite_ai_state[k] = 0; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); if (!sprite_wallcoll[k]) Sprite_MoveXY(k); Sprite_CheckTileCollision(k); sprite_graphics[k] = ++sprite_subtype2[k] >> 3 & 2; switch(sprite_ai_state[k]) { case 0: // stopped if (!sprite_delay_main[k]) { sprite_ai_state[k] = 1; int j = Sprite_IsRightOfLink(k).a + Sprite_IsBelowLink(k).a * 2; sprite_D[k] = j; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kHover_OamFlags[j]; sprite_delay_main[k] = (GetRandomNumber() & 15) + 12; Sprite_ZeroVelocity_XY(k); } break; case 1: { // moving static const int8 kHover_AccelX0[4] = {1, -1, 1, -1}; static const int8 kHover_AccelY0[4] = {1, 1, -1, -1}; static const int8 kHover_AccelX1[4] = {-1, 1, -1, 1}; static const int8 kHover_AccelY1[4] = {-1, -1, 1, 1}; int j = sprite_D[k]; if (sprite_delay_main[k]) { sprite_x_vel[k] += kHover_AccelX0[j]; sprite_y_vel[k] += kHover_AccelY0[j]; sprite_graphics[k] = sprite_subtype2[k] >> 3 & 1; } else { sprite_x_vel[k] += kHover_AccelX1[j]; sprite_y_vel[k] += kHover_AccelY1[j]; if (!sprite_y_vel[k]) { sprite_ai_state[k] = 0; sprite_delay_main[k] = 64; } } break; } } } void Sprite_AB_CrystalMaiden(int k) { // 9ece03 cur_sprite_x -= dung_floor_x_offs; cur_sprite_y -= dung_floor_y_offs; if (sprite_ai_state[k] >= 3) CrystalMaiden_Draw(k); is_nmi_thread_active = 1; if (!BYTE(intro_did_run_step)) { CrystalMaiden_RunCutscene(k); BYTE(intro_did_run_step) = 1; } } void CrystalMaiden_RunCutscene(int k) { // 9ece39 sprite_E[k]++; poly_b += 6; if (submodule_index) return; switch (sprite_ai_state[k]) { case 0: // disable subscreen TS_copy = 0; sprite_ai_state[k]++; break; case 1: // enable subscreen TS_copy = 1; sprite_ai_state[k]++; break; case 2: // generate sparkles if (poly_config1 < 6) { poly_config1 = 0; sprite_ai_state[k]++; } else { poly_config1 -= 3; if (poly_config1 >= 64) AncillaAdd_SwordChargeSparkle(sprite_A[k]); } break; case 3: // filter palette sprite_ai_state[k]++; case 4: if (!(sprite_E[k] & 1)) { PaletteFilter_SP5F(); if (!BYTE(palette_filter_countdown)) { sprite_ai_state[k]++; flag_is_link_immobilized = 1; link_receiveitem_index = 0; link_pose_for_item = 0; link_animation_steps = 0; link_direction_facing = 0; } } break; case 5: { // show message static const uint16 kCrystalMaiden_Msgs[9] = {0x133, 0x132, 0x137, 0x134, 0x136, 0x132, 0x135, 0x138, 0x13c}; int j = BYTE(cur_palace_index_x2) - 10; if (j == 2 && savegame_map_icons_indicator < 7) savegame_map_icons_indicator = 7; if (j == 14 && (link_has_crystals & 0x7f) != 0x7f) j = 16; Sprite_ShowMessageUnconditional(kCrystalMaiden_Msgs[j >> 1]); sprite_ai_state[k]++; if ((link_has_crystals & 0x7f) == 0x7f) savegame_map_icons_indicator = 8; break; } case 6: // reading comprehension exam Sprite_ShowMessageUnconditional(0x13a); sprite_ai_state[k]++; break; case 7: // may the way of the hero if (choice_in_multiselect_box) { sprite_ai_state[k] = 5; } else { Sprite_ShowMessageUnconditional(0x139); sprite_ai_state[k]++; } break; case 8: // initiate dungeon exit TS_copy = 0; PrepareDungeonExitFromBossFight(); sprite_state[k] = 0; break; } } void Sprite_7D_BigSpike(int k) { // 9ecf47 static const int8 kSpikeTrap_Xvel[4] = {32, -32, 0, 0}; static const int8 kSpikeTrap_Xvel2[4] = {-16, 16, 0, 0}; static const int8 kSpikeTrap_Yvel[4] = {0, 0, 32, -32}; static const int8 kSpikeTrap_Yvel2[4] = {0, 0, -16, 16}; static const uint8 kSpikeTrap_Delay[4] = {0x40, 0x40, 0x38, 0x38}; int j; SpikeTrap_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_CheckDamageToAndFromLink(k); if (sprite_ai_state[k] == 0) { PointU8 pt; sprite_D[k] = j = Sprite_DirectionToFaceLink(k, &pt); if ((uint8)(pt.x + 16) < 32 || (uint8)(pt.y + 16) < 32) { sprite_delay_main[k] = kSpikeTrap_Delay[j]; sprite_ai_state[k] = 1; sprite_x_vel[k] = kSpikeTrap_Xvel[j]; sprite_y_vel[k] = kSpikeTrap_Yvel[j]; } } else if (sprite_ai_state[k] == 1) { if (Sprite_CheckTileCollision(k) || !sprite_delay_main[k]) { sprite_ai_state[k] = 2; sprite_delay_main[k] = 96; } Sprite_MoveXY(k); } else { if (!sprite_delay_main[k]) { j = sprite_D[k]; sprite_x_vel[k] = kSpikeTrap_Xvel2[j]; sprite_y_vel[k] = kSpikeTrap_Yvel2[j]; Sprite_MoveXY(k); if (sprite_x_lo[k] == sprite_A[k] && sprite_y_lo[k] == sprite_C[k]) sprite_ai_state[k] = 0; } } } void SpikeTrap_Draw(int k) { // 9ecfff static const DrawMultipleData kSpikeTrap_Dmd[4] = { {-8, -8, 0x00c4, 2}, { 8, -8, 0x40c4, 2}, {-8, 8, 0x80c4, 2}, { 8, 8, 0xc0c4, 2}, }; Sprite_DrawMultiple(k, kSpikeTrap_Dmd, 4, NULL); } void Sprite_7E_Firebar_Clockwise(int k) { // 9ed01a static const int8 kGuruguruBar_incr[4] = {-2, 2, -1, 1}; Firebar_Main(k); if (Sprite_ReturnIfInactive(k)) return; sprite_subtype2[k]++; int j = (sprite_type[k] - 0x7e) + (BYTE(cur_palace_index_x2) == 18) * 2; int t = sprite_A[k] | sprite_B[k] << 8; t = (t + kGuruguruBar_incr[j]) & 0x1ff; sprite_A[k] = t; sprite_B[k] = t >> 8; } void Firebar_Main(int k) { // 9ed049 PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); byte_7E0FB6 = info.flags; BYTE(dungmap_var7) = info.x; HIBYTE(dungmap_var7) = info.y; int angle = sprite_A[k] | sprite_B[k] << 8; int8 sinval = GuruguruBarSin(angle, 0x40); int8 cosval = GuruguruBarSin((angle + 0x80) & 0x1ff, 0x40); uint8 flags = (sprite_subtype2[k] << 4 & 0xc0) | info.flags; for (int i = 3; i >= 0; i--, oam++) { oam->x = info.x + sinval * (i + 1) / 4; oam->y = info.y + cosval * (i + 1) / 4; oam->charnum = 0x28; oam->flags = flags; bytewise_extended_oam[oam - oam_buf] = 2; } Sprite_CorrectOamEntries(k, 3, 0xff); if (!((k ^ frame_counter) & 3 | submodule_index | flag_unk1)) { OamEnt *oam = GetOamCurPtr(); for (int i = 0; i < 4; i++, oam++) { if (bytewise_extended_oam[oam - oam_buf] & 1) continue; if ((uint8)(oam->x + BG2HOFS_copy2 - link_x_coord + 12) < 24 && oam->y < 0xf0 && (uint8)(oam->y + BG2VOFS_copy2 - link_y_coord + 4) < 16) Sprite_AttemptDamageToLinkPlusRecoil(k); } } } void Sprite_80_Firesnake(int k) { // 9ed1d1 static const uint8 kWinder_OamFlags[4] = {0, 0x40, 0x80, 0xc0}; static const int8 kWinder_Xvel[4] = {24, -24, 0, 0}; static const int8 kWinder_Yvel[4] = {0, 0, 24, -24}; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kWinder_OamFlags[frame_counter >> 2 & 3]; if (sprite_A[k]) { sprite_ignore_projectile[k] = sprite_delay_main[k]; if (sprite_delay_main[k] == 0) sprite_state[k] = 0; return; } Sprite_CheckDamageToAndFromLink(k); Firesnake_SpawnFireball(k); if (!sprite_wallcoll[k]) Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) sprite_D[k] = kZazak_Dir2[sprite_D[k] * 2 + (GetRandomNumber() & 1)]; int j = sprite_D[k]; sprite_x_vel[k] = kWinder_Xvel[j]; sprite_y_vel[k] = kWinder_Yvel[j]; } void Firesnake_SpawnFireball(int j) { // 9ed239 if ((j ^ frame_counter) & 7) return; int k = GarnishAlloc(); garnish_type[k] = 1; garnish_active = 1; garnish_x_lo[k] = sprite_x_lo[j]; garnish_x_hi[k] = sprite_x_hi[j]; int y = Sprite_GetY(j) + 16; garnish_y_lo[k] = y; garnish_y_hi[k] = y >> 8; garnish_countdown[k] = 32; garnish_sprite[k] = j; garnish_floor[k] = sprite_floor[j]; } void Sprite_7C_GreenStalfos(int k) { // 9ed299 static const uint8 kGreenStalfos_Dir[4] = {4, 6, 0, 2}; static const uint8 kGreenStalfos_OamFlags[4] = {0x40, 0, 0, 0}; static const uint8 kGreenStalfos_Gfx[4] = {0, 0, 1, 2}; int j = sprite_D[k]; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kGreenStalfos_OamFlags[j]; sprite_graphics[k] = kGreenStalfos_Gfx[j]; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; Sprite_CheckDamageToAndFromLink(k); j = Sprite_DirectionToFaceLink(k, NULL); if (kGreenStalfos_Dir[j] != link_direction_facing) { sprite_A[k] = 0; if (!((k ^ frame_counter) & 7)) { uint8 vel = sprite_B[k]; if (vel != 4) sprite_B[k]++; Sprite_ApplySpeedTowardsLink(k, vel); sprite_D[k] = Sprite_IsRightOfLink(k).a; } } else { sprite_A[k] = 1; if (!((k ^ frame_counter) & 15)) { uint8 vel = sprite_B[k]; if (vel) sprite_B[k]--; Sprite_ApplySpeedTowardsLink(k, vel); sprite_D[k] = Sprite_IsRightOfLink(k).a; } } Sprite_MoveXY(k); } void Sprite_7A_Agahnim(int k) { // 9ed330 int j; uint8 t; static const uint8 kAgahnim_StartState[2] = {1, 6}; static const uint8 kAgahnim_Gfx0[5] = {12, 13, 14, 15, 16}; static const int8 kAgahnim_Tab5[2] = {32, -32}; static const uint8 kAgahnim_Tab6[2] = {9, 11}; static const uint8 kAgahnim_Dir[25] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 1, 1, 4, 4, 0, 2, 2, 4, 4, 3, 2, 2, }; static const uint8 kAgahnim_Gfx1[6] = {2, 10, 8, 0, 4, 6}; static const uint8 kAgahnim_Tab0[16] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0}; static const uint8 kAgahnim_Tab1[16] = {0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 3, 2, 1, 0, 0, 0}; static const uint8 kAgahnim_Tab2[6] = {30, 24, 12, 0, 6, 18}; static const uint8 kAgahnim_Gfx2[5] = {16, 15, 14, 13, 12}; static const uint8 kAgahnim_Tab3[16] = {0x38, 0x38, 0x38, 0x58, 0x78, 0x98, 0xb8, 0xb8, 0xb8, 0x98, 0x58, 0x58, 0x60, 0x90, 0x98, 0x78}; static const uint8 kAgahnim_Tab4[16] = {0xb8, 0x78, 0x58, 0x48, 0x48, 0x48, 0x58, 0x78, 0xb8, 0xb8, 0xb8, 0x90, 0x70, 0x70, 0x90, 0xa0}; static const uint8 kAgahnim_Gfx3[7] = {0, 8, 10, 2, 2, 6, 4}; Agahnim_Draw(k); if (sprite_pause[k]) { sprite_delay_main[k] = 32; sprite_graphics[k] = 0; sprite_D[k] = 3; } if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; sprite_ignore_projectile[k] = 1; switch (sprite_ai_state[k]) { case 0: sprite_ai_state[k] = kAgahnim_StartState[is_in_dark_world]; break; case 1: if (!sprite_delay_main[k]) { dialogue_message_index = 0x13f; Sprite_ShowMessageMinimal(); sprite_ai_state[k] = 3; sprite_delay_main[k] = 32; } break; case 2: byte_7E0FF8 = 0; if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 255; } else { sprite_graphics[k] = kAgahnim_Gfx0[sprite_delay_main[k] >> 3]; } break; case 3: j = sprite_delay_main[k]; if (j == 192) SpriteSfx_QueueSfx3WithPan(k, 0x27); if (j >= 239 || j < 16) { AgahnimWarpShadowFilter(is_in_dark_world ? k : 2); } else { if (!k) { Sprite_CheckDamageToAndFromLink(k); sprite_ignore_projectile[k] = 0; } } if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_delay_main[k] = 39; return; } if (sprite_delay_main[k] >= 128) { Sprite_ApplySpeedTowardsLink(k, 2); sprite_D[k] = kAgahnim_Dir[((int8)sprite_y_vel[k] + 2) * 5 + 2 + (int8)sprite_x_vel[k]]; Sprite_ApplySpeedTowardsLink(k, 32); if (sprite_subtype[k] == 4) sprite_D[k] = 3; } else if (sprite_delay_main[k] == 112) { Agahnim_PerformAttack(k); } j = sprite_delay_main[k] >> 4; sprite_A[k] = kAgahnim_Tab0[j]; t = kAgahnim_Tab1[j]; sprite_head_dir[k] = t ? t + kAgahnim_Tab2[sprite_D[k]] : t ; sprite_graphics[k] = kAgahnim_Gfx1[sprite_D[k]] + sprite_A[k]; break; case 4: sprite_ignore_projectile[k] = sprite_delay_main[k]; if (!sprite_delay_main[k]) { sprite_ai_state[k]++; j = sprite_subtype[k] == 4 ? 4 : GetRandomNumber() & 0xf; sprite_C[k] = kAgahnim_Tab3[j]; sprite_E[k] = kAgahnim_Tab4[j]; sprite_G[k] = 8; } else { sprite_graphics[k] = kAgahnim_Gfx2[sprite_delay_main[k] >> 3]; } break; case 5: { if ((uint16)(sprite_x_lo[k] - sprite_C[k] + 7) < 14 && (uint16)(sprite_y_lo[k] - sprite_E[k] + 7) < 14) { sprite_x_lo[k] = sprite_C[k]; sprite_y_lo[k] = sprite_E[k]; sprite_ai_state[k] = 2; sprite_delay_main[k] = 39; return; } int x = sprite_x_hi[k] << 8 | sprite_C[k]; int y = sprite_y_hi[k] << 8 | sprite_E[k]; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, sprite_G[k]); sprite_y_vel[k] = pt.y; sprite_x_vel[k] = pt.x; if (sprite_G[k] < 64) sprite_G[k]++; Sprite_MoveXY(k); break; } case 6: if (!sprite_delay_main[k]) { dialogue_message_index = 0x141; Sprite_ShowMessageMinimal(); sprite_ai_state[k]++; sprite_delay_main[k] = 80; } break; case 7: if (sprite_anim_clock[k]) { if (!sprite_delay_main[k]) { sprite_ai_state[k] = 3; sprite_delay_main[k] = 32; } else { sprite_x_vel[k] = kAgahnim_Tab5[k - 1]; sprite_y_vel[k] += 2; Sprite_MoveXY(k); j = Sprite_Agahnim_ApplyMotionBlur(k); if (j >= 0) sprite_oam_flags[j] = 4; } } else { if (!sprite_delay_main[k]) { sprite_ai_state[k] = 3; sprite_delay_main[k] = 32; } else if (sprite_delay_main[k] == 64) { sound_effect_2 = 0x28; tmp_counter = 1; do { SpriteSpawnInfo info; j = Sprite_SpawnDynamicallyEx(k, 0x7A, &info, 2); Sprite_SetSpawnedCoordinates(j, &info); sprite_flags3[j] = kAgahnim_Tab6[j - 1]; sprite_anim_clock[j] = sprite_oam_flags[j] = sprite_flags3[j] & 15; sprite_ai_state[j] = sprite_ai_state[k]; sprite_delay_main[j] = 32; } while (!sign8(--tmp_counter)); } } break; case 8: flag_block_link_menu = 2; sprite_head_dir[k] = 0; if (sprite_delay_main[k] >= 64) { sprite_hit_timer[k] |= 0xe0; } else { if (sprite_delay_main[k] == 1) { Sprite_SpawnPhantomGanon(k); music_control = 0x1d; } sprite_hit_timer[k] = 0; sprite_graphics[k] = 17; } break; case 9: { sprite_head_dir[k] = 0; int x = Sprite_GetX(0), y = Sprite_GetY(0); if ((uint16)(cur_sprite_x - x + 4) < 8 && (uint16)(cur_sprite_y - y + 4) < 8) sprite_state[k] = 0; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 0x20); sprite_y_vel[k] = pt.y; sprite_x_vel[k] = pt.x; Sprite_MoveXY(k); Sprite_Agahnim_ApplyMotionBlur(k); break; } case 10: if (!sprite_delay_main[k]) { sprite_state[k] = 0; PrepareDungeonExitFromBossFight(); } if (sprite_delay_main[k] < 16) { CGADSUB_copy = 0x7f; TM_copy = 6; TS_copy = 0x10; PaletteFilter_SP5F(); } if (sprite_z_vel[k] != 0xff) sprite_z_vel[k]++; j = sprite_z_subpos[k] + sprite_z_vel[k]; sprite_z_subpos[k] = j; if (j & 0x100 && ++sprite_subtype2[k] == 7) { sprite_subtype2[k] = 0; SpriteSfx_QueueSfx2WithPan(k, 0x4); } sprite_graphics[k] = kAgahnim_Gfx3[sprite_subtype2[k]]; break; } } void Agahnim_PerformAttack(int k) { // 9ed67a static const int8 kAgahnim_X0[6] = {0, 10, 8, 0, -10, -10}; static const int8 kAgahnim_Y0[6] = {-9, -2, -2, -9, -2, -2}; if (!k) { sprite_subtype[k]++; if (is_in_dark_world) sprite_subtype[k] &= 3; } if (sprite_subtype[k] == 5) { sprite_subtype[k] = 0; SpriteSfx_QueueSfx3WithPan(k, 0x26); for (int i = 0; i < 4; i++) Sprite_SpawnLightning(k); } else { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x7B, &info); if (j >= 0) { SpriteSfx_QueueSfx3WithPan(k, 0x29); int i = sprite_D[k]; Sprite_SetX(j, info.r0_x + kAgahnim_X0[i]); Sprite_SetY(j, info.r2_y + kAgahnim_Y0[i]); sprite_ignore_projectile[j] = sprite_y_hi[j]; sprite_x_vel[j] = sprite_x_vel[k]; sprite_y_vel[j] = sprite_y_vel[k]; if (sprite_subtype[k] >= 2 && !(GetRandomNumber() & 1)) { sprite_B[j] = 1; sprite_delay_main[j] = 32; } } } } void Agahnim_Draw(int k) { // 9ed978 static const int8 kAgahnim_Draw_X0[72] = { -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -6, 6, -6, 6, -8, 8, -8, 8, -6, 6, -6, 6, 0, 8, 0, 8, -8, 8, -8, 8, }; static const int8 kAgahnim_Draw_Y0[72] = { -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -6, -6, 6, 6, -8, -8, 8, 8, -6, -6, 6, 6, 0, 0, 8, 8, 8, 8, 8, 8, }; static const uint8 kAgahnim_Draw_Char0[72] = { 0x82, 0x82, 0xa2, 0xa2, 0x80, 0x80, 0xa0, 0xa0, 0x84, 0x84, 0xa4, 0xa4, 0x86, 0x86, 0xa6, 0xa6, 0x88, 0x8a, 0xa8, 0xaa, 0x8c, 0x8e, 0xac, 0xae, 0xc4, 0xc2, 0xe4, 0xe6, 0xc0, 0xc2, 0xe0, 0xe2, 0x8a, 0x88, 0xaa, 0xa8, 0x8e, 0x8c, 0xae, 0xac, 0xc2, 0xc4, 0xe6, 0xe4, 0xc2, 0xc0, 0xe2, 0xe0, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xdf, 0xdf, 0xdf, 0xdf, 0x40, 0x42, 0x40, 0x42, }; static const uint8 kAgahnim_Draw_Flags0[72] = { 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0, 0, 0, }; static const int8 kAgahnim_Draw_X1[72] = { -7, 15, -11, 11, -11, 11, -8, 8, -4, 4, 0, 0, -10, -1, -14, -5, -14, -5, -12, -7, -10, -7, -10, -10, 16, 8, 12, 4, 12, 4, 10, 6, 9, 7, 8, 8, -6, -6, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, 14, 14, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, -7, 15, -11, 11, -11, 11, -8, 8, -4, 4, 0, 0, }; static const int8 kAgahnim_Draw_Y1[72] = { -5, -5, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -3, 9, -7, 5, -7, 5, -5, 3, -3, 3, -2, -2, -3, 9, -7, 5, -7, 5, -5, 3, -3, 3, -2, -2, -3, 9, -7, 5, -7, 5, -5, 3, -3, 3, -2, -2, -3, 9, -7, 5, -7, 5, -5, 3, -3, 3, -2, -2, -5, -5, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }; static const uint8 kAgahnim_Draw_Char1[36] = { 0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, }; static const uint8 kAgahnim_Draw_Ext1[36] = { 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, }; PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; OamEnt *oam = GetOamCurPtr(); int g = sprite_graphics[k]; for (int i = 3; i >= 0; i--, oam++) { int j = g * 4 + i; oam->x = info.x + kAgahnim_Draw_X0[j]; oam->y = info.y + kAgahnim_Draw_Y0[j]; oam->charnum = kAgahnim_Draw_Char0[j]; oam->flags = info.flags | kAgahnim_Draw_Flags0[j]; bytewise_extended_oam[oam - oam_buf] = (j >= 0x40 && j < 0x44) ? 0 : 2; } if (g < 12) SpriteDraw_Shadow_custom(k, &info, 18); if (submodule_index) Sprite_CorrectOamEntries(k, 3, 0xff); if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; if (sprite_D[k]) Oam_AllocateFromRegionC(8); else Oam_AllocateFromRegionB(8); oam = GetOamCurPtr(); if (!sprite_head_dir[k]) return; g = sprite_head_dir[k] - 1; uint8 flags = (((frame_counter >> 1) & 2) + 2) + 0x31; for (int i = 1; i >= 0; i--, oam++) { oam->x = info.x + kAgahnim_Draw_X1[g * 2 + i]; oam->y = info.y + kAgahnim_Draw_Y1[g * 2 + i]; oam->charnum = kAgahnim_Draw_Char1[g]; oam->flags = flags; bytewise_extended_oam[oam - oam_buf] = kAgahnim_Draw_Ext1[g]; } } void Sprite_7B_AgahnimBalls(int k) { // 9eda42 if (sprite_B[k]) { if (sprite_delay_main[k]) Sprite_ApplySpeedTowardsLink(k, 32); sprite_oam_flags[k] = 5; } else { sprite_oam_flags[k] = (frame_counter >> 1 & 2) + 3; } if (sprite_ai_state[k]) { static const uint8 kEnergyBall_Gfx[16] = {2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0}; if (sprite_graphics[k] != 2) SpriteDraw_SingleLarge(k); else SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; sprite_ignore_projectile[k] = sprite_delay_main[k]; if (!sprite_delay_main[k]) { sprite_state[k] = 0; } else if (sprite_delay_main[k] == 6) { sprite_x_vel[k] = sprite_y_vel[k] = 64; Sprite_MoveXY(k); } sprite_graphics[k] = kEnergyBall_Gfx[sprite_delay_main[k]]; return; } if (sprite_B[k]) SeekerEnergyBall_Draw(k); else SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; sprite_subtype2[k]++; Sprite_MoveXY(k); if (Sprite_CheckTileCollision(k)) { sprite_state[k] = 0; if (sprite_B[k]) { SpriteSfx_QueueSfx3WithPan(k, 0x36); CreateSixBlueBalls(k); return; } } if (sprite_A[k] && !sprite_ignore_projectile[0]) { SpriteHitBox hb; hb.r0_xlo = sprite_x_lo[k]; hb.r8_xhi = sprite_x_hi[k]; hb.r2 = hb.r3 = 15; hb.r1_ylo = sprite_y_lo[k]; hb.r9_yhi = sprite_y_hi[k]; Sprite_SetupHitBox(0, &hb); if (CheckIfHitBoxesOverlap(&hb)) { AgahnimBalls_DamageAgahnim(0, 16, 0xa0); sprite_state[k] = 0; sprite_x_recoil[0] = sprite_x_vel[k]; sprite_y_recoil[0] = sprite_y_vel[k]; } } else { Sprite_CheckDamageToLink(k); if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Carry) { if (sprite_B[k]) { sprite_state[k] = 0; SpriteSfx_QueueSfx3WithPan(k, 0x36); CreateSixBlueBalls(k); return; } SpriteSfx_QueueSfx2WithPan(k, 0x5); SpriteSfx_QueueSfx3WithPan(k, 0x29); Sprite_ApplySpeedTowardsLink(k, 0x30); sprite_x_vel[k] = -sprite_x_vel[k]; sprite_y_vel[k] = -sprite_y_vel[k]; sprite_A[k]++; } } if ((k ^ frame_counter) & 3 | sprite_B[k]) return; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x7B, &info); if (j < 0) return; Sprite_SetSpawnedCoordinates(j, &info); sprite_delay_main[j] = 15; sprite_ai_state[j] = 15; sprite_B[j] = sprite_B[k]; } void CreateSixBlueBalls(int k) { // 9edb96 static const int8 kEnergyBall_SplitXVel[6] = {0, 24, 24, 0, -24, -24}; static const int8 kEnergyBall_SplitYVel[6] = {-32, -16, 16, 32, 16, -16}; SpriteSfx_QueueSfx3WithPan(k, 0x36); tmp_counter = 5; do { SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x55, &info); if (j >= 0) { Sprite_SetX(j, info.r0_x + 4); Sprite_SetY(j, info.r2_y + 4); sprite_flags3[j] = sprite_flags3[j] & ~1 | 0x40; sprite_oam_flags[j] = 4; sprite_delay_aux1[j] = 4; sprite_flags4[j] = 20; sprite_C[j] = 20; sprite_E[j] = 20; sprite_x_vel[j] = kEnergyBall_SplitXVel[tmp_counter]; sprite_y_vel[j] = kEnergyBall_SplitYVel[tmp_counter]; } } while (!sign8(--tmp_counter)); tmp_counter = 0; } void SeekerEnergyBall_Draw(int k) { // 9edc3e static const DrawMultipleData kEnergyBall_Dmd[8] = { { 4, -3, 0x00ce, 0}, {11, 4, 0x00ce, 0}, { 4, 11, 0x00ce, 0}, {-3, 4, 0x00ce, 0}, {-1, -1, 0x00ce, 0}, { 9, -1, 0x00ce, 0}, {-1, 9, 0x00ce, 0}, { 9, 9, 0x00ce, 0}, }; Sprite_DrawMultiple(k, &kEnergyBall_Dmd[(sprite_subtype2[k] >> 2 & 1) * 4], 4, NULL); } void Sprite_79_Bee(int k) { // 9edc5b switch (sprite_ai_state[k]) { case 0: Bee_DormantHive(k); break; case 1: Bee_Main(k); break; case 2: Bee_PutInBottle(k); break; } } void Bee_DormantHive(int k) { // 9edc68 if (sprite_E[k]) return; sprite_state[k] = 0; for (int i = 11; i >= 0; i--) SpawnBeeFromHive(k); } void SpawnBeeFromHive(int k) { // 9edc8f SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x79, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); InitializeSpawnedBee(j); } } void InitializeSpawnedBee(int k) { // 9edc9b sprite_ai_state[k] = 1; sprite_A[k] = sprite_delay_main[k] = kSpawnBee_InitDelay[k & 3]; sprite_delay_aux4[k] = 96; sprite_x_vel[k] = kSpawnBee_InitVel[GetRandomNumber() & 7]; sprite_y_vel[k] = kSpawnBee_InitVel[GetRandomNumber() & 7]; } int ReleaseBeeFromBottle() { // 9edccf static const int8 kSpawnBee_XY[8] = {8, 2, -2, -8, 10, 5, -5, -10}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(0, 0xb2, &info); if (j >= 0) { sprite_floor[j] = link_is_on_lower_level; Sprite_SetX(j, link_x_coord + 8); Sprite_SetY(j, link_y_coord + 16); uint8 t = (&link_item_bow)[hud_cur_item - 1]; if (link_bottle_info[t - 1] == 8) sprite_head_dir[j] = 1; InitializeSpawnedBee(j); sprite_x_vel[j] = kSpawnBee_XY[GetRandomNumber() & 7]; sprite_y_vel[j] = kSpawnBee_XY[GetRandomNumber() & 7]; sprite_delay_main[j] = 64; sprite_A[j] = 64; } return j; } void Bee_Main(int k) { // 9edd45 Bee_HandleZ(k); SpriteDraw_SingleSmall(k); Bee_HandleInteractions(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_ReturnIfRecoiling(k)) return; if (sprite_head_dir[k]) Sprite_SpawnSparkleGarnish(k); Bee_Bzzt(k); Sprite_MoveXY(k); sprite_graphics[k] = (k ^ frame_counter) >> 1 & 1; if (!sprite_delay_aux4[k]) { Sprite_CheckDamageToLink(k); if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Ne) { Sprite_ShowMessageUnconditional(0xc8); sprite_ai_state[k] = 2; // put in bottle return; } } if (!frame_counter && sprite_A[k] != 16) sprite_A[k] -= 8; if (sprite_delay_main[k] == 0) { uint16 x = link_x_coord + (GetRandomNumber() & 3) * 5; uint16 y = link_y_coord + (GetRandomNumber() & 3) * 5; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 20); sprite_y_vel[k] = pt.y; sprite_x_vel[k] = pt.x; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(pt.x) ? 0 : 0x40); sprite_delay_main[k] = k + sprite_A[k]; } } int Sprite_Find_EmptyBottle() { // 9ede2e for (int i = 0; i != 4; i++) if (link_bottle_info[i] == 2) return i; return -1; } void Bee_HandleInteractions(int k) { // 9ede44 if (submodule_index == 2 && (dialogue_message_index == 0xc8 || dialogue_message_index == 0xca)) sprite_delay_aux4[k] = 40; } void Sprite_B2_PlayerBee(int k) { // 9ede63 static const uint8 kGoodBee_Tab0[2] = {0xa, 0x14}; switch (sprite_ai_state[k]) { case 0: // wait if (!sprite_E[k]) { sprite_state[k] = 0; uint8 or_bottle = link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3]; if (!(or_bottle & 8)) GoldBee_SpawnSelf(k); } break; case 1: {// activated sprite_ignore_projectile[k] = 1; Bee_HandleZ(k); SpriteDraw_SingleSmall(k); Bee_HandleInteractions(k); if (Sprite_ReturnIfInactive(k)) return; Bee_Bzzt(k); Sprite_MoveXY(k); sprite_graphics[k] = (k ^ frame_counter) >> 1 & 1; if (sprite_head_dir[k]) Sprite_SpawnSparkleGarnish(k); if (sprite_B[k] >= kGoodBee_Tab0[sprite_head_dir[k]]) { sprite_defl_bits[k] = 64; return; } if (sprite_delay_aux4[k]) return; if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Ne) { Sprite_ShowMessageUnconditional(0xc8); sprite_ai_state[k]++; return; } if ((k ^ frame_counter) & 3) return; Point16U pt2; if (!PlayerBee_FindTarget(k, &pt2)) { pt2.x = link_x_coord + (GetRandomNumber() & 3) * 5; pt2.x = link_y_coord + (GetRandomNumber() & 3) * 5; } if ((k ^ frame_counter) & 7) return; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, pt2.x, pt2.y, 32); sprite_y_vel[k] = pt.y; sprite_x_vel[k] = pt.x; sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(pt.x) ? 0 : 0x40); break; } case 2: // bottle Bee_PutInBottle(k); break; } } void GoldBee_SpawnSelf(int k) { // 9ede90 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0x79, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_ai_state[j] = 1; sprite_delay_main[j] = 64; sprite_A[j] = 64; sprite_delay_aux4[j] = 96; sprite_head_dir[j] = 1; sprite_x_vel[j] = kSpawnBee_InitVel[GetRandomNumber() & 7]; sprite_y_vel[j] = kSpawnBee_InitVel[GetRandomNumber() & 7]; } } void Bee_HandleZ(int k) { // 9edf8a sprite_z[k] = 16; if (sprite_head_dir[k]) sprite_oam_flags[k] = (sprite_oam_flags[k] & 0xf1) | (((frame_counter >> 4 & 3) + 1) << 1); } bool PlayerBee_FindTarget(int k, Point16U *pt) { // 9edfab int n = 16; int j = k * 4 & 0xf; do { if (j == k || sprite_state[j] < 9 || sprite_pause[j]) continue; if (!(sprite_flags2[k] & 0x80)) { if (sprite_floor[k] != sprite_floor[j] || sprite_flags4[j] & 0x40 || sprite_ignore_projectile[j]) continue; } else { if (!sprite_head_dir[j] || !(sprite_bump_damage[j] & 0x40)) continue; } PlayerBee_HoneInOnTarget(j, k); pt->x = Sprite_GetX(j) + (GetRandomNumber() & 3) * 5; pt->y = Sprite_GetY(j) + (GetRandomNumber() & 3) * 5; return true; } while (j = (j - 1) & 0xf, --n); return false; } void Bee_Bzzt(int k) { // 9ee02e if (!((k ^ frame_counter) & 31)) SpriteSfx_QueueSfx3WithPan(k, 0x2c); } void Sprite_B3_PedestalPlaque(int k) { // 9ee044 PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; if (!flag_is_link_immobilized && Sprite_CheckIfLinkIsBusy()) return; link_position_mode &= ~0x20; if (BYTE(overworld_screen_index) != 48) { if (link_direction_facing || !Sprite_CheckDamageToLink_same_layer(k)) return; if (hud_cur_item != 15 || !(filtered_joypad_H & 0x40)) { if (!(filtered_joypad_L & 0x80)) return; Sprite_ShowMessageUnconditional(0xb6); } else { player_handler_timer = 0; link_position_mode = 32; sound_effect_1 = 0; Sprite_ShowMessageUnconditional(0xb7); } } else { if (link_direction_facing || !Sprite_CheckDamageToLink_same_layer(k)) return; if (hud_cur_item != 15 || !(filtered_joypad_H & 0x40)) { if (!(filtered_joypad_L & 0x80)) return; Sprite_ShowMessageUnconditional(0xbc); } else { player_handler_timer = 0; link_position_mode = 32; sound_effect_1 = 0; button_b_frames = 1; link_delay_timer_spin_attack = 0; link_player_handler_state = kPlayerState_OpeningDesertPalace; Sprite_ShowMessageUnconditional(0xbd); } } } void Sprite_B4_PurpleChest(int k) { // 9ee0dd SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (!sprite_ai_state[k]) { if (Sprite_ShowMessageOnContact(k, 0x116) & 0x100 && savegame_tagalong == 0) sprite_ai_state[k] = 1; } else { sprite_state[k] = 0; savegame_tagalong = 12; LoadFollowerGraphics(); Sprite_BecomeFollower(k); } } void Sprite_B5_BombShop(int k) { // 9ee111 switch (sprite_subtype2[k]) { case 0: Sprite_BombShop_Clerk(k); break; case 1: Sprite_BombShop_Bomb(k); break; case 2: Sprite_BombShop_SuperBomb(k); break; case 3: Sprite_BombShop_Huff(k); break; } } void Sprite_BombShop_Clerk(int k) { // 9ee134 static const uint8 kBombShopGuy_Gfx[8] = {0, 1, 0, 1, 0, 1, 0, 1}; static const uint8 kBombShopGuy_Delay[8] = {255, 32, 255, 24, 15, 24, 255, 15}; BombShopEntity_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (!sprite_delay_main[k]) { int j = sprite_E[k]; sprite_E[k] = j + 1 & 7; sprite_delay_main[k] = kBombShopGuy_Delay[j]; sprite_graphics[k] = kBombShopGuy_Gfx[j]; if (sprite_graphics[k] == 0) { SpriteSfx_QueueSfx3WithPan(k, 0x11); BombShop_ClerkExhalation(k); } else { SpriteSfx_QueueSfx3WithPan(k, 0x12); } } bool flag = ((link_has_crystals & 5) == 5 && sram_progress_indicator_3 & 32); Sprite_ShowSolicitedMessage(k, flag ? 0x118 : 0x117); Sprite_BehaveAsBarrier(k); } void Sprite_BombShop_Bomb(int k) { // 9ee190 BombShopEntity_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (!ShopItem_CheckForAPress(k)) return; if (link_item_bombs != kMaxBombsForLevel[link_bomb_upgrades]) { if (!ShopItem_HandleCost(100)) { Sprite_ShowMessageUnconditional(0x17c); ShopItem_PlayBeep(k); } else { link_bomb_filler = 27; sprite_state[k] = 0; Sprite_ShowMessageUnconditional(0x119); ShopItem_HandleReceipt(k, 0x28); } } else { Sprite_ShowMessageUnconditional(0x16e); ShopItem_PlayBeep(k); } } void Sprite_BombShop_SuperBomb(int k) { // 9ee1df BombShopEntity_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (ShopItem_CheckForAPress(k)) { if (!ShopItem_HandleCost(100)) { Sprite_ShowMessageUnconditional(0x17c); ShopItem_PlayBeep(k); } else { savegame_tagalong = 13; LoadFollowerGraphics(); Sprite_BecomeFollower(k); sprite_state[k] = 0; Sprite_ShowMessageUnconditional(0x11a); } } } void Sprite_BombShop_Huff(int k) { // 9ee21a static const uint8 kSnoutPutt_Dmd[4] = {4, 0x44, 0xc4, 0x84}; Oam_AllocateFromRegionC(4); SpriteDraw_SingleSmall(k); if (Sprite_ReturnIfInactive(k)) return; sprite_oam_flags[k] &= 0x30; sprite_oam_flags[k] |= kSnoutPutt_Dmd[frame_counter >> 2 & 3]; sprite_z_vel[k]++; Sprite_MoveZ(k); if (!sprite_delay_main[k]) sprite_state[k] = 0; sprite_graphics[k] = sprite_delay_main[k] >> 3 & 3; } void BombShop_ClerkExhalation(int k) { // 9ee256 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xb5, &info); if (j >= 0) { Sprite_SetX(j, info.r0_x + 4); Sprite_SetY(j, info.r2_y + 16); sprite_subtype2[j] = 3; sprite_ignore_projectile[j] = 3; sprite_z[j] = 4; sprite_z_vel[j] = -12; sprite_delay_main[j] = 23; sprite_flags3[j] &= ~0x11; } } void BombShopEntity_Draw(int k) { // 9ee2c6 static const DrawMultipleData kBombShopEntity_Dmd[6] = { {0, 0, 0x0a48, 2}, {0, 0, 0x0a4c, 2}, {0, 0, 0x04c2, 2}, {0, 0, 0x04c2, 2}, {0, 0, 0x084e, 2}, {0, 0, 0x084e, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kBombShopEntity_Dmd[sprite_subtype2[k] * 2 + sprite_graphics[k]], 1, &info); SpriteDraw_Shadow(k, &info); } void Sprite_B6_Kiki(int k) { // 9ee2ef switch(sprite_subtype2[k]) { case 0: Kiki_LyingInwait(k); break; case 1: Kiki_OfferEntranceService(k); break; case 2: Kiki_OfferInitialService(k); break; case 3: Kiki_Flee(k); break; } } void Kiki_Flee(int k) { // 9ee2fe bool flag = Kiki_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (!sprite_z[k] && (uint16)(cur_sprite_x - 0xc98) < 0xd0 && (uint16)(cur_sprite_y - 0x6a5) < 0xd0) flag = true; if (flag) sprite_state[k] = 0; sprite_z_vel[k]-=2; Sprite_MoveXYZ(k); if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = GetRandomNumber() & 15 | 16; } ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, 0xcf5, 0x6fe, 16); sprite_x_vel[k] = pt.x << 1; sprite_y_vel[k] = pt.y << 1; tagalong_event_flags &= ~3; if (sign8(pt.x)) pt.x = -pt.x; if (sign8(pt.y)) pt.y = -pt.y; sprite_D[k] = (pt.x >= pt.y) ? (sprite_x_vel[k] >> 7) ^ 3 : (sprite_y_vel[k] >> 7) ^ 1; sprite_graphics[k] = frame_counter >> 3 & 1; } void Kiki_OfferInitialService(int k) { // 9ee3af if (!sign8(sprite_ai_state[k] - 2)) Kiki_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXYZ(k); sprite_z_vel[k]--; if (sign8(sprite_z[k])) { sprite_z_vel[k] = 0; sprite_z[k] = 0; } sprite_graphics[k] = frame_counter >> 3 & 1; switch(sprite_ai_state[k]) { case 0: Sprite_ShowMessageUnconditional(0x11e); sprite_ai_state[k]++; break; case 1: if (!choice_in_multiselect_box && ShopItem_HandleCost(10)) { Sprite_ShowMessageUnconditional(0x11f); tagalong_event_flags |= 3; sprite_state[k] = 0; } else { Sprite_ShowMessageUnconditional(0x120); tagalong_event_flags &= ~3; savegame_tagalong = 0; sprite_ai_state[k]++; flag_is_link_immobilized++; } break; case 2: { sprite_ai_state[k]++; ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, 0xc45, 0x6fe, 9); sprite_y_vel[k] = pt.y; sprite_x_vel[k] = pt.x; sprite_D[k] = (pt.x >> 7) ^ 3; sprite_delay_main[k] = 32; break; } case 3: if (!sprite_delay_main[k]) { sprite_ai_state[k]++; sprite_z_vel[k] = 16; sprite_delay_main[k] = 16; } break; case 4: if (!sprite_delay_main[k] && !sprite_z[k]) { sprite_state[k] = 0; flag_is_link_immobilized = 0; } break; } } void Kiki_OfferEntranceService(int k) { // 9ee4c9 int j, t; Kiki_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_MoveXYZ(k); sprite_z_vel[k]--; if (sign8(sprite_z[k])) { sprite_z_vel[k] = 0; sprite_z[k] = 0; } switch(sprite_ai_state[k]) { case 0: // Sprite_ShowMessageUnconditional(0x11b); sprite_ai_state[k]++; break; case 1: // if (choice_in_multiselect_box || !ShopItem_HandleCost(100)) { Sprite_ShowMessageUnconditional(0x11c); sprite_subtype2[k] = 3; } else { Sprite_ShowMessageUnconditional(0x11d); flag_is_link_immobilized++; sprite_ai_state[k]++; sprite_D[k] = 0; } break; case 2: // case 4: // case 6: { // static const uint16 kKiki_Leave_X[3] = {0xf4f, 0xf70, 0xf5d}; static const uint16 kKiki_Leave_Y[3] = { 0x661, 0x64c, 0x624 }; sprite_graphics[k] = frame_counter >> 3 & 1; j = (sprite_ai_state[k] >> 1) - 1; if ((uint8)(kKiki_Leave_X[j] - sprite_x_lo[k] + 2) < 4 && (uint8)(kKiki_Leave_Y[j] - sprite_y_lo[k] + 2) < 4) { sprite_ai_state[k]++; sprite_x_vel[k] = sprite_y_vel[k] = 0; sprite_delay_aux1[k] = 32; SpriteSfx_QueueSfx2WithPan(k, 0x21); return; } ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, kKiki_Leave_X[j], kKiki_Leave_Y[j], 9); sprite_x_vel[k] = pt.x; sprite_y_vel[k] = pt.y; break; } case 3: // case 5: // if (!sprite_delay_aux1[k]) { static const uint8 kKiki_Zvel[2] = {32, 28}; sprite_z_vel[k] = kKiki_Zvel[sprite_ai_state[k]++ >> 1 & 1]; SpriteSfx_QueueSfx2WithPan(k, 0x20); sprite_D[k] = sprite_ai_state[k] >> 1 & 1 | 4; } else { sprite_D[k] = sprite_ai_state[k] >> 1 & 1 | 6; sprite_graphics[k] = frame_counter >> 3 & 1; } break; case 7: { // static const uint8 kKiki_Tab7[3] = {2, 1, 0xff}; static const uint8 kKiki_Delay7[2] = {82, 0}; static const int8 kKiki_Xvel7[4] = {0, 0, -9, 9}; static const int8 kKiki_Yvel7[4] = {-9, 9, 0, 0}; sprite_graphics[k] = frame_counter >> 3 & 1; if (sprite_z[k] || sprite_delay_main[k]) return; j = sprite_A[k]++; t = kKiki_Tab7[j]; if (!sign8(t)) { sprite_D[k] = t; sprite_delay_main[k] = kKiki_Delay7[j]; sprite_x_vel[k] = kKiki_Xvel7[t]; sprite_y_vel[k] = kKiki_Yvel7[t]; } else { sprite_ai_state[k]++; sprite_x_vel[k] = sprite_y_vel[k] = 0; trigger_special_entrance = 1; subsubmodule_index = 0; overworld_entrance_sequence_counter = 0; sprite_D[k] = 0; flag_is_link_immobilized = 0; } break; } case 8: // sprite_D[k] = 8; sprite_graphics[k] = 0; sprite_z_vel[k] = (GetRandomNumber() & 15) + 16; sprite_ai_state[k]++; break; case 9: // if (sign8(sprite_z_vel[k]) && !sprite_z[k]) { sprite_ai_state[k]++; SpriteSfx_QueueSfx3WithPan(k, 0x25); } break; case 10: // break; } } bool Kiki_Draw(int k) { // 9ee859 static const DrawMultipleData kKiki_Dmd1[32] = { { 0, -6, 0x0020, 2}, { 0, 0, 0x0022, 2}, { 0, -6, 0x0020, 2}, { 0, 0, 0x4022, 2}, { 0, -6, 0x0020, 2}, { 0, 0, 0x0022, 2}, { 0, -6, 0x0020, 2}, { 0, 0, 0x4022, 2}, {-1, -6, 0x0020, 2}, { 0, 0, 0x0022, 2}, {-1, -6, 0x0020, 2}, { 0, 0, 0x0022, 2}, { 1, -6, 0x4020, 2}, { 0, 0, 0x4022, 2}, { 1, -6, 0x4020, 2}, { 0, 0, 0x4022, 2}, { 0, -6, 0x01ce, 2}, { 0, 0, 0x01ee, 2}, { 0, -6, 0x01ce, 2}, { 0, 0, 0x01ee, 2}, { 0, -6, 0x41ce, 2}, { 0, 0, 0x41ee, 2}, { 0, -6, 0x41ce, 2}, { 0, 0, 0x41ee, 2}, {-1, -6, 0x01ce, 2}, { 0, 0, 0x01ec, 2}, {-1, -6, 0x41ce, 2}, { 0, 0, 0x01ec, 2}, { 1, -6, 0x41ce, 2}, { 0, 0, 0x41ec, 2}, { 1, -6, 0x01ce, 2}, { 0, 0, 0x41ec, 2}, }; static const DrawMultipleData kKiki_Dmd2[12] = { {0, -6, 0x01ca, 0}, {8, -6, 0x41ca, 0}, {0, 2, 0x01da, 0}, {8, 2, 0x41da, 0}, {0, 10, 0x01cb, 0}, {8, 10, 0x41cb, 0}, {0, -6, 0x01db, 0}, {8, -6, 0x41db, 0}, {0, 2, 0x01cc, 0}, {8, 2, 0x41cc, 0}, {0, 10, 0x01dc, 0}, {8, 10, 0x41dd, 0}, }; static const uint8 kKikiDma[32] = { 0x20, 0xc0, 0x20, 0xc0, 0, 0xa0, 0, 0xa0, 0x40, 0x80, 0x40, 0x60, 0x40, 0x80, 0x40, 0x60, 0, 0, 0xfa, 0xff, 0x20, 0, 0, 2, 0, 0, 0, 0, 0x22, 0, 0, 2 // zelda bug: OOB read }; PrepOamCoordsRet info; if (sprite_D[k] < 8) { int j = sprite_D[k] * 2 + sprite_graphics[k]; BYTE(dma_var6) = kKikiDma[j * 2 + 0]; BYTE(dma_var7) = kKikiDma[j * 2 + 1]; Sprite_DrawMultiple(k, &kKiki_Dmd1[j * 2], 2, &info); if (!sprite_pause[k]) SpriteDraw_Shadow(k, &info); } else { Sprite_DrawMultiple(k, &kKiki_Dmd2[sprite_graphics[k] * 6], 6, &info); if (!sprite_pause[k]) SpriteDraw_Shadow(k, &info); } return ((info.x | info.y) & 0xff00) != 0; } void Sprite_B7_BlindMaiden(int k) { // 9ee8b6 CrystalMaiden_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_TrackBodyToHead(k); sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; if (!sprite_ai_state[k]) { if (Sprite_ShowMessageOnContact(k, 0x122) & 0x100) sprite_ai_state[k] = 1; } else { sprite_state[k] = 0; savegame_tagalong = 6; LoadFollowerGraphics(); Sprite_BecomeFollower(k); } } void OldMan_RevertToSprite(int k) { // 9ee938 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xAD, &info); sprite_D[j] = sprite_head_dir[j] = tagalong_layerbits[k] & 3; Sprite_SetY(j, (tagalong_y_lo[k] | tagalong_y_hi[k] << 8) + 2); Sprite_SetX(j, (tagalong_x_lo[k] | tagalong_x_hi[k] << 8) + 2); sprite_floor[j] = link_is_on_lower_level; sprite_ignore_projectile[j] = 1; sprite_subtype2[j] = 1; OldMan_EnableCutscene(); savegame_tagalong = 0; link_speed_setting = 0; } void OldMan_EnableCutscene() { // 9ee989 flag_is_link_immobilized = 1; link_disable_sprite_damage = 1; } void Sprite_AD_OldMan(int k) { // 9ee992 static const uint16 kOldMountainManMsgs[3] = {0x9e, 0x9f, 0xa0}; int j; OldMountainMan_Draw(k); if (Sprite_ReturnIfInactive(k)) return; switch(sprite_subtype2[k]) { case 0: // lost switch (sprite_ai_state[k]) { case 0: // supplicate Sprite_TrackBodyToHead(k); sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; j = Sprite_ShowMessageOnContact(k, 0x9c); if (j & 0x100) { sprite_D[k] = sprite_head_dir[k] = j; sprite_ai_state[k] = 1; } break; case 1: // switch to tagalong savegame_tagalong = 4; Sprite_BecomeFollower(k); which_starting_point = 5; sprite_state[k] = 0; CacheCameraProperties(); break; } break; case 1: // entering domicile Sprite_MoveXY(k); switch(sprite_ai_state[k]) { case 0: // grant mirror sprite_ai_state[k]++; item_receipt_method = 0; Link_ReceiveItem(0x1a, 0); which_starting_point = 1; OldMan_EnableCutscene(); sprite_delay_main[k] = 48; sprite_x_vel[k] = 8; sprite_y_vel[k] = 4; sprite_D[k] = sprite_head_dir[k] = 3; break; case 1: // shuffle away OldMan_EnableCutscene(); if (!sprite_delay_main[k]) sprite_ai_state[k]++; sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1; break; case 2: { // approach door sprite_head_dir[k] = 0; sprite_D[k] = 0; j = byte_7E0FDE; int x = overlord_x_lo[j] | overlord_x_hi[j] << 8; int y = overlord_y_lo[j] | overlord_y_hi[j] << 8; if (y >= Sprite_GetY(k)) { sprite_ai_state[k]++; sprite_y_vel[k] = sprite_x_vel[k] = 0; } else { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 8); sprite_y_vel[k] = pt.y; sprite_x_vel[k] = pt.x; sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1; OldMan_EnableCutscene(); } break; } case 3: // made it inside sprite_state[k] = 0; flag_is_link_immobilized = 0; link_disable_sprite_damage = 0; break; } break; case 2: // sitting at home Sprite_BehaveAsBarrier(k); if (sprite_ai_state[k]) { link_hearts_filler = 160; sprite_ai_state[k] = 0; } j = sram_progress_indicator >= 3 ? 2 : link_item_moon_pearl; if (Sprite_ShowSolicitedMessage(k, kOldMountainManMsgs[j]) & 0x100) sprite_ai_state[k]++; break; } } void Sprite_B8_DialogueTester(int k) { // 9eeae7 assert(0); } void Sprite_B9_BullyAndPinkBall(int k) { // 9eeb33 switch(sprite_subtype2[k]) { case 0: Sprite_PinkBall(k); return; case 1: PinkBall_Distress(k); return; case 2: Sprite_Bully(k); return; } } void Sprite_PinkBall(int k) { // 9eeb40 Oam_AllocateDeferToPlayer(k); SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; PinkBall_HandleMessage(k); sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x80 | sprite_head_dir[k]; Sprite_MoveXYZ(k); int t = Sprite_CheckTileCollision(k); if (t) { if (!(t & 3)) { sprite_y_vel[k] = -sprite_y_vel[k]; if (sprite_E[k]) goto play_sound; } sprite_x_vel[k] = -sprite_x_vel[k]; if (sprite_E[k]) { play_sound: BallGuy_PlayBounceNoise(k); } } sprite_z_vel[k]--; if (sign8(sprite_z[k])) { sprite_z[k] = 0; sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2; if (sprite_z_vel[k] & 0xfc) BallGuy_PlayBounceNoise(k); PinkBall_HandleDeceleration(k); } if (!sprite_E[k]) { if (!sprite_head_dir[k]) { PinkBall_Distress(k); sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1; if (!((k ^ frame_counter) & 0x3f)) { uint16 x = (link_x_coord & 0xff00) | GetRandomNumber(); uint16 y = (link_y_coord & 0xff00) | GetRandomNumber(); ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 8); sprite_B[k] = pt.x; sprite_A[k] = pt.y; if (pt.y) { sprite_oam_flags[k] |= 64; sprite_oam_flags[k] ^= sprite_x_vel[k] >> 1 & 64; } } sprite_x_vel[k] = sprite_B[k]; sprite_y_vel[k] = sprite_A[k]; } else { PinkBall_Distress(k); if (k ^ frame_counter) { sprite_graphics[k] = (k ^ frame_counter) >> 2 & 1; sprite_x_vel[k] = 0; sprite_y_vel[k] = 0; } else { sprite_head_dir[k] = 0; } } } else { if ((sprite_x_vel[k] | sprite_y_vel[k]) == 0) { sprite_E[k] = 0; } else { sprite_graphics[k] = (k ^ frame_counter) >> 2 & 1; sprite_head_dir[k] = (k ^ frame_counter) << 2 & 128; } } } void PinkBall_HandleDeceleration(int k) { // 9eec4d if (sprite_x_vel[k]) sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? 2 : -2; if (sprite_y_vel[k]) sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? 2 : -2; } void PinkBall_Distress(int k) { // 9eec74 PrepOamCoordsRet info; if (Sprite_PrepOamCoordOrDoubleRet(k, &info)) return; Sprite_DrawDistress_custom(info.x, info.y, frame_counter); } void Sprite_Bully(int k) { // 9eec7c Bully_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Bully_HandleMessage(k); Sprite_MoveXYZ(k); int t = Sprite_CheckTileCollision(k); if (t) { if (!(t & 3)) sprite_y_vel[k] = -sprite_y_vel[k]; else sprite_x_vel[k] = -sprite_x_vel[k]; } switch(sprite_ai_state[k]) { case 0: { // chase sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1; int j = sprite_head_dir[k]; if (!((k ^ frame_counter) & 0x1f)) { ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, Sprite_GetX(j), Sprite_GetY(j), 14); sprite_y_vel[k] = pt.y; sprite_x_vel[k] = pt.x; if (pt.x) sprite_D[k] = sprite_x_vel[k] >> 7; } if (!sprite_z[j]) { if ((uint8)(sprite_x_lo[k] - sprite_x_lo[j] + 8) < 16 && (uint8)(sprite_y_lo[k] - sprite_y_lo[j] + 8) < 16) { sprite_ai_state[k]++; BallGuy_PlayBounceNoise(k); } } break; } case 1: { // kick ball sprite_ai_state[k] = 2; int j = sprite_head_dir[k]; sprite_x_vel[j] = sprite_x_vel[k] << 1; sprite_y_vel[j] = sprite_y_vel[k] << 1; sprite_x_vel[k] = 0; sprite_y_vel[k] = 0; sprite_z_vel[j] = GetRandomNumber() & 31; sprite_delay_main[k] = 96; sprite_graphics[k] = 1; sprite_E[j] = 1; break; } case 2: // waiting if (!sprite_delay_main[k]) sprite_ai_state[k] = 0; break; } } void Bully_Draw(int k) { // 9eed9e static const DrawMultipleData kBully_Dmd[8] = { {0, -7, 0x46e0, 2}, {0, 0, 0x46e2, 2}, {0, -7, 0x46e0, 2}, {0, 0, 0x46c4, 2}, {0, -7, 0x06e0, 2}, {0, 0, 0x06e2, 2}, {0, -7, 0x06e0, 2}, {0, 0, 0x06c4, 2}, }; PrepOamCoordsRet info; Sprite_DrawMultiplePlayerDeferred(k, &kBully_Dmd[sprite_D[k] * 4 + sprite_graphics[k] * 2], 2, &info); SpriteDraw_Shadow(k, &info); } void BallGuy_PlayBounceNoise(int k) { // 9eedc2 SpriteSfx_QueueSfx3WithPan(k, 0x32); } void SpawnBully(int k) { // 9eedc9 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xB9, &info); if (j >= 0) { Sprite_SetSpawnedCoordinates(j, &info); sprite_subtype2[j] = 2; sprite_head_dir[j] = k; sprite_ignore_projectile[j] = 1; } } void PinkBall_HandleMessage(int k) { // 9eede8 if (sprite_delay_aux4[k]) return; int msg = link_item_moon_pearl & 1 ? 0x15c : 0x15b; if (Sprite_ShowMessageOnContact(k, msg) & 0x100) { sprite_x_vel[k] ^= 255; sprite_y_vel[k] ^= 255; if (sprite_E[k]) BallGuy_PlayBounceNoise(k); sprite_delay_aux4[k] = 64; } } void Bully_HandleMessage(int k) { // 9eee25 if (sprite_delay_aux4[k]) return; int msg = link_item_moon_pearl & 1 ? 0x15e : 0x15d; if (Sprite_ShowMessageOnContact(k, msg) & 0x100) { sprite_x_vel[k] ^= 255; sprite_y_vel[k] ^= 255; sprite_delay_aux4[k] = 64; } } void Sprite_BA_Whirlpool(int k) { // 9eee5a static const uint8 kWhirlpool_OamFlags[4] = {0, 0x40, 0xc0, 0x80}; if (BYTE(overworld_screen_index) == 0x1b) { PrepOamCoordsRet info; Sprite_PrepOamCoord(k, &info); if (Sprite_ReturnIfInactive(k)) return; uint16 x = cur_sprite_x - link_x_coord + 0x40; uint16 y = cur_sprite_y - link_y_coord + 0xf; if (x < 0x51 && y < 0x12) { submodule_index = 35; link_triggered_by_whirlpool_sprite = 1; subsubmodule_index = 0; link_actual_vel_y = 0; link_actual_vel_x = 0; link_player_handler_state = 20; last_light_vs_dark_world = overworld_screen_index & 0x40; } } else { sprite_oam_flags[k] = (sprite_oam_flags[k] & 0x3f) | kWhirlpool_OamFlags[frame_counter >> 3 & 3]; Oam_AllocateFromRegionB(4); cur_sprite_x -= 5; SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (Sprite_CheckDamageToLink_same_layer(k)) { if (sprite_A[k] == 0) { submodule_index = 46; subsubmodule_index = 0; } } else { sprite_A[k] = 0; } } } void Sprite_BB_Shopkeeper(int k) { // 9eeeef switch (sprite_subtype2[k]) { case 0: Shopkeeper_StandardClerk(k); break; case 1: ChestGameGuy(k); break; case 2: NiceThiefWithGift(k); break; case 3: MiniChestGameGuy(k); break; case 4: LostWoodsChestGameGuy(k); break; case 5: case 6: NiceThiefUnderRock(k); break; case 7: ShopItem_RedPotion150(k); break; case 8: ShopItem_FighterShield(k); break; case 9: ShopItem_FireShield(k); break; case 10: ShopItem_Heart(k); break; case 11: ShopItem_Arrows(k); break; case 12: ShopItem_Bombs(k); break; case 13: ShopItem_Bee(k); break; } } void Shopkeeper_StandardClerk(int k) { // 9eef12 if (is_in_dark_world) { Oam_AllocateDeferToPlayer(k); SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; sprite_oam_flags[k] = (sprite_oam_flags[k] & 63) | (frame_counter << 3 & 64); } else { sprite_oam_flags[k] = 7; Shopkeeper_Draw(k); if (Sprite_ReturnIfInactive(k)) return; sprite_graphics[k] = frame_counter >> 4 & 1; } Sprite_BehaveAsBarrier(k); int msg = is_in_dark_world == 0 ? 0x165 : 0x15f; Sprite_ShowSolicitedMessage(k, msg); if (sprite_ai_state[k] == 0 && (uint16)(cur_sprite_y + 0x60) >= link_y_coord) { Sprite_ShowMessageUnconditional(msg); sprite_ai_state[k] = 1; } } void ChestGameGuy(int k) { // 9eef90 Oam_AllocateDeferToPlayer(k); SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); sprite_oam_flags[k] = (sprite_oam_flags[k] & 63) | (frame_counter << 3 & 64); switch (sprite_ai_state[k]) { case 0: if ((uint8)(minigame_credits - 1) >= 2 && Sprite_ShowSolicitedMessage(k, 0x160) & 0x100) sprite_ai_state[k] = 1; break; case 1: if (choice_in_multiselect_box == 0 && ShopItem_HandleCost(30)) { minigame_credits = 2; Sprite_ShowMessageUnconditional(0x164); sprite_ai_state[k] = 2; } else { Sprite_ShowMessageUnconditional(0x161); sprite_ai_state[k] = 0; } break; case 2: if (minigame_credits == 0) Sprite_ShowSolicitedMessage(k, 0x163); else Sprite_ShowSolicitedMessage(k, 0x17f); break; } } void NiceThief_Animate(int k) { // 9ef017 if (!(frame_counter & 3)) { sprite_graphics[k] = 2; uint8 dir = Sprite_DirectionToFaceLink(k, NULL); sprite_head_dir[k] = (dir == 3) ? 2 : dir; } Oam_AllocateDeferToPlayer(k); Thief_Draw(k); } void NiceThiefWithGift(int k) { // 9ef038 NiceThief_Animate(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); switch (sprite_ai_state[k]) { case 0: if (Sprite_ShowSolicitedMessage(k, 0x176) & 0x100) sprite_ai_state[k] = 1; break; case 1: if (!(dung_savegame_state_bits & 0x4000)) { dung_savegame_state_bits |= 0x4000; sprite_ai_state[k] = 2; ShopItem_HandleReceipt(k, 0x46); } else { sprite_ai_state[k] = 0; } break; case 2: sprite_ai_state[k] = 0; break; } } void MiniChestGameGuy(int k) { // 9ef078 sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3; sprite_graphics[k] = 0; MazeGameGuy_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); switch (sprite_ai_state[k]) { case 0: if ((uint8)(minigame_credits - 1) >= 2 && Sprite_ShowSolicitedMessage(k, 0x17e) & 0x100) sprite_ai_state[k] = 1; break; case 1: if (choice_in_multiselect_box == 0 && ShopItem_HandleCost(20)) { minigame_credits = 1; Sprite_ShowMessageUnconditional(0x17f); sprite_ai_state[k] = 2; } else { Sprite_ShowMessageUnconditional(0x180); sprite_ai_state[k] = 0; } break; case 2: Sprite_ShowSolicitedMessage(k, (minigame_credits == 0) ? 0x163 : 0x17f); break; } } void LostWoodsChestGameGuy(int k) { // 9ef0f3 NiceThief_Animate(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); switch (sprite_ai_state[k]) { case 0: if ((uint8)(minigame_credits - 1) >= 2 && Sprite_ShowSolicitedMessage(k, 0x181) & 0x100) sprite_ai_state[k] = 1; break; case 1: if (choice_in_multiselect_box == 0 && ShopItem_HandleCost(100)) { minigame_credits = 1; Sprite_ShowMessageUnconditional(0x17f); sprite_ai_state[k] = 2; } else { Sprite_ShowMessageUnconditional(0x180); sprite_ai_state[k] = 0; } break; case 2: Sprite_ShowSolicitedMessage(k, (minigame_credits == 0) ? 0x163 : 0x17f); break; } } void NiceThiefUnderRock(int k) { // 9ef14f NiceThief_Animate(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); Sprite_ShowSolicitedMessage(k, sprite_subtype2[k] == 5 ? 0x177 : 0x178); } void ShopItem_RedPotion150(int k) { // 9ef16e SpriteDraw_ShopItem(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (ShopItem_CheckForAPress(k)) { if (Sprite_Find_EmptyBottle() < 0) { Sprite_ShowMessageUnconditional(0x16d); ShopItem_PlayBeep(k); } else if (ShopItem_HandleCost(150)) { sprite_state[k] = 0; ShopItem_HandleReceipt(k, 0x2e); } else { Sprite_ShowMessageUnconditional(0x17c); ShopItem_PlayBeep(k); } } } void ShopKeeper_SpawnShopItem(int k, int pos, int what) { // 9ef1b3 static const int8 kShopKeeper_ItemX[3] = {-44, 8, 60}; SpriteSpawnInfo info; int j = Sprite_SpawnDynamicallyEx(k, 0xbb, &info, 12); assert(j >= 0); sprite_ignore_projectile[j] = sprite_subtype2[j] = what; Sprite_SetX(j, info.r0_x + kShopKeeper_ItemX[pos]); Sprite_SetY(j, info.r2_y + 0x27); sprite_flags2[j] |= 4; } void ShopItem_FighterShield(int k) { // 9ef1f2 SpriteDraw_ShopItem(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); ShopItem_MakeShieldsDeflect(k); if (ShopItem_CheckForAPress(k)) { if (link_shield_type) { Sprite_ShowMessageUnconditional(0x166); ShopItem_PlayBeep(k); return; } if (!ShopItem_HandleCost(50)) { Sprite_ShowMessageUnconditional(0x17c); ShopItem_PlayBeep(k); return; } sprite_state[k] = 0; ShopItem_HandleReceipt(k, 4); } sprite_flags4[k] = 0x1c; } void ShopItem_FireShield(int k) { // 9ef230 SpriteDraw_ShopItem(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); ShopItem_MakeShieldsDeflect(k); if (ShopItem_CheckForAPress(k)) { if (link_shield_type >= 2) { Sprite_ShowMessageUnconditional(0x166); ShopItem_PlayBeep(k); return; } if (!ShopItem_HandleCost(500)) { Sprite_ShowMessageUnconditional(0x17c); ShopItem_PlayBeep(k); return; } sprite_state[k] = 0; ShopItem_HandleReceipt(k, 5); } sprite_flags4[k] = 0x1c; } void ShopItem_MakeShieldsDeflect(int k) { // 9ef261 sprite_ignore_projectile[k] = 0; sprite_flags[k] = 8; sprite_defl_bits[k] = 4; sprite_flags4[k] = 0x1c; Sprite_CheckDamageFromLink(k); sprite_flags4[k] = 0xa; } void ShopItem_Heart(int k) { // 9ef27d SpriteDraw_ShopItem(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (ShopItem_CheckForAPress(k)) { if (link_health_current == link_health_capacity) { ShopItem_PlayBeep(k); } else if (ShopItem_HandleCost(10)) { sprite_state[k] = 0; ShopItem_HandleReceipt(k, 0x42); } else { Sprite_ShowMessageUnconditional(0x17c); ShopItem_PlayBeep(k); } } } void ShopItem_Arrows(int k) { // 9ef2af SpriteDraw_ShopItem(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (ShopItem_CheckForAPress(k)) { if (link_num_arrows == kMaxArrowsForLevel[link_arrow_upgrades]) { Sprite_ShowSolicitedMessage(k, 0x16e); ShopItem_PlayBeep(k); } else if (ShopItem_HandleCost(30)) { sprite_state[k] = 0; ShopItem_HandleReceipt(k, 0x44); } else { Sprite_ShowMessageUnconditional(0x17c); ShopItem_PlayBeep(k); } } } void ShopItem_Bombs(int k) { // 9ef2f0 SpriteDraw_ShopItem(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (ShopItem_CheckForAPress(k)) { if (link_item_bombs == kMaxBombsForLevel[link_bomb_upgrades]) { Sprite_ShowSolicitedMessage(k, 0x16e); ShopItem_PlayBeep(k); } else if (ShopItem_HandleCost(50)) { sprite_state[k] = 0; ShopItem_HandleReceipt(k, 0x31); } else { Sprite_ShowMessageUnconditional(0x17c); ShopItem_PlayBeep(k); } } } void ShopItem_Bee(int k) { // 9ef322 SpriteDraw_ShopItem(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (ShopItem_CheckForAPress(k)) { if (Sprite_Find_EmptyBottle() < 0) { Sprite_ShowSolicitedMessage(k, 0x16d); ShopItem_PlayBeep(k); } else if (ShopItem_HandleCost(10)) { sprite_state[k] = 0; ShopItem_HandleReceipt(k, 0xe); } else { Sprite_ShowMessageUnconditional(0x17c); ShopItem_PlayBeep(k); } } } void ShopItem_HandleReceipt(int k, uint8 item) { // 9ef366 static const uint16 kShopKeeper_GiveItemMsgs[7] = {0x168, 0x167, 0x167, 0x16c, 0x169, 0x16a, 0x16b}; item_receipt_method = 0; Link_ReceiveItem(item, 0); int j = sprite_subtype2[k]; if (j >= 7) { Sprite_ShowMessageUnconditional(kShopKeeper_GiveItemMsgs[j - 7]); ShopKeeper_RapidTerminateReceiveItem(); } } void ShopItem_PlayBeep(int k) { // 9ef38a SpriteSfx_QueueSfx2WithPan(k, 0x3c); } bool ShopItem_CheckForAPress(int k) { // 9ef391 if (!(filtered_joypad_L & 0x80)) return false; return Sprite_CheckDamageToLink_same_layer(k); } bool ShopItem_HandleCost(int amt) { // 9ef39e if (amt > link_rupees_goal) return false; link_rupees_goal -= amt; return true; } void SpriteDraw_ShopItem(int k) { // 9ef4ce static const DrawMultipleData kShopKeeper_ItemWithPrice_Dmd[35] = { {-4, 16, 0x0231, 0}, { 4, 16, 0x0213, 0}, {12, 16, 0x0230, 0}, { 0, 0, 0x02c0, 2}, { 0, 11, 0x036c, 2}, { 0, 16, 0x0213, 0}, { 0, 16, 0x0213, 0}, { 8, 16, 0x0230, 0}, { 0, 0, 0x04ce, 2}, { 4, 12, 0x0338, 0}, {-4, 16, 0x0213, 0}, { 4, 16, 0x0230, 0}, {12, 16, 0x0230, 0}, { 0, 0, 0x08cc, 2}, { 4, 12, 0x0338, 0}, { 0, 16, 0x0231, 0}, { 0, 16, 0x0231, 0}, { 8, 16, 0x0230, 0}, { 4, 8, 0x0329, 0}, { 4, 11, 0x0338, 0}, {-4, 16, 0x0203, 0}, {-4, 16, 0x0203, 0}, { 4, 16, 0x0230, 0}, { 0, 0, 0x04c4, 2}, { 0, 11, 0x0338, 0}, { 0, 16, 0x0213, 0}, { 0, 16, 0x0213, 0}, { 8, 16, 0x0230, 0}, { 0, 0, 0x04e8, 2}, { 0, 11, 0x036c, 2}, { 0, 16, 0x0231, 0}, { 0, 16, 0x0231, 0}, { 8, 16, 0x0230, 0}, { 4, 8, 0x0ff4, 0}, { 4, 11, 0x0338, 0}, }; Sprite_DrawMultiplePlayerDeferred(k, &kShopKeeper_ItemWithPrice_Dmd[(sprite_subtype2[k] - 7) * 5], 5, NULL); } void Sprite_AC_Apple(int k) { // 9ef515 if (sprite_ai_state[k]) { Sprite_Apple(k); return; } if (sprite_E[k] == 0) { sprite_state[k] = 0; int n = (GetRandomNumber() & 3) + 2; do { SpawnApple(k); } while (--n >= 0); } } void SpawnApple(int k) { // 9ef535 SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xac, &info); if (j < 0) return; Sprite_SetSpawnedCoordinates(j, &info); sprite_ai_state[j] = 1; sprite_A[j] = 255; sprite_z[j] = 8; sprite_z_vel[j] = 22; uint16 x = info.r0_x & ~0xff | GetRandomNumber(); uint16 y = info.r2_y & ~0xff | GetRandomNumber(); ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 10); sprite_x_vel[j] = pt.x; sprite_y_vel[j] = pt.y; } void Sprite_Apple(int k) { // 9ef57c if (sprite_A[k] >= 16 || frame_counter & 2) SpriteDraw_SingleLarge(k); if (Sprite_ReturnIfInactive(k)) return; if (sprite_A[k] == 0) { sprite_state[k] = 0; return; } Sprite_MoveXYZ(k); if (Sprite_CheckDamageToLink(k)) { SpriteSfx_QueueSfx3WithPan(k, 0xb); link_hearts_filler += 8; sprite_state[k] = 0; return; } if (!(frame_counter & 1)) sprite_A[k]--; if (!sign8(sprite_z[k] - 1)) { sprite_z_vel[k] -= 1; return; } sprite_z[k] = 0; uint8 a = sign8(sprite_z_vel[k]) ? sprite_z_vel[k] : 0; sprite_z_vel[k] = (uint8)(-a) >> 1; if (sprite_x_vel[k]) sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? 1 : -1; if (sprite_y_vel[k]) sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? 1 : -1; } void Sprite_BC_Drunkard(int k) { // 9ef603 DrinkingGuy_Draw(k); if (Sprite_ReturnIfInactive(k)) return; Sprite_BehaveAsBarrier(k); if (!GetRandomNumber()) sprite_delay_main[k] = 32; sprite_graphics[k] = sprite_delay_main[k] ? 1 : 0; if (Sprite_ShowSolicitedMessage(k, 0x175) & 0x100) sprite_graphics[k] = 0; } void SomariaPlatform_LocatePath(int k) { // 9ef640 for (;;) { uint8 tiletype = SomariaPlatformAndPipe_CheckTile(k); sprite_E[k] = tiletype; if (tiletype >= 0xb0 && tiletype < 0xbf) break; Sprite_SetX(k, Sprite_GetX(k) + 8); Sprite_SetY(k, Sprite_GetY(k) + 8); } sprite_x_lo[k] = (sprite_x_lo[k] & ~7) + 4; sprite_y_lo[k] = (sprite_y_lo[k] & ~7) + 4; sprite_head_dir[k] = sprite_D[k]; SomariaPlatformAndPipe_HandleMovement(k); sprite_ignore_projectile[k]++; player_on_somaria_platform = 0; sprite_delay_aux4[k] = 14; sprite_graphics[k]++; } void Sprite_SomariaPlatform(int k) { // 9ef6d4 switch(sprite_graphics[k]) { case 0: { SomariaPlatform_LocatePath(k); int j = Sprite_SpawnSuperficialBombBlast(k); if (j >= 0) { Sprite_SetX(j, Sprite_GetX(j) - 8); Sprite_SetY(j, Sprite_GetY(j) - 8); } break; } case 1: SomariaPlatform_Draw(k); if (Sprite_ReturnIfInactive(k)) return; if (!(drag_player_x | drag_player_y) && sign8(player_near_pit_state - 2) && Sprite_CheckDamageToLink_ignore_layer(k)) { sprite_C[k] = 1; Link_CancelDash(); if (link_player_handler_state != kPlayerState_Hookshot && link_player_handler_state != kPlayerState_SpinAttacking) { if (sprite_ai_state[k]) { SomariaPlatformAndPipe_HandleMovement(k); return; } sprite_A[k]++; player_on_somaria_platform = 2; if (!(sprite_A[k] & 7)) { uint8 a = SomariaPlatformAndPipe_CheckTile(k); if (a != sprite_E[k]) { sprite_E[k] = a; sprite_head_dir[k] = sprite_D[k]; SomariaPlatformAndPipe_HandleMovement(k); SomariaPlatform_HandleDrag(k); } } if (BYTE(dungeon_room_index) != 36) { static const int8 kSomariaPlatform_DragX[8] = {0, 0, -1, 1, -1, 1, 1, -1}; static const int8 kSomariaPlatform_DragY[8] = {-1, 1, 0, 0, -1, 1, -1, 1}; int j = sprite_D[k]; drag_player_x += kSomariaPlatform_DragX[j]; drag_player_y += kSomariaPlatform_DragY[j]; Sprite_MoveXY(k); SomariaPlatform_DragLink(k); } else { player_on_somaria_platform = 1; } return; } } if (sprite_C[k]) { player_on_somaria_platform = 0; sprite_C[k] = 0; } break; } } void SomariaPlatformAndPipe_HandleMovement(int k) { // 9ef7af static const int8 kSomariaPlatform_Xvel[8] = {0, 0, -16, 16, -16, 16, 16, -16}; static const int8 kSomariaPlatform_Yvel[8] = {-16, 16, 0, 0, -16, 16, -16, 16}; SomariaPlatform_HandleJunctions(k); int j = sprite_D[k]; sprite_x_vel[k] = kSomariaPlatform_Xvel[j]; sprite_y_vel[k] = kSomariaPlatform_Yvel[j]; } uint8 SomariaPlatformAndPipe_CheckTile(int k) { // 9ef7c2 uint16 x = Sprite_GetX(k), y = Sprite_GetY(k); return GetTileAttribute(0, &x, y); } void SomariaPlatform_Draw(int k) { // 9ef860 static const DrawMultipleData kSomariaPlatform_Dmd[16] = { {-16, -16, 0x00ac, 2}, { 0, -16, 0x40ac, 2}, {-16, 0, 0x80ac, 2}, { 0, 0, 0xc0ac, 2}, {-13, -13, 0x00ac, 2}, { -3, -13, 0x40ac, 2}, {-13, -3, 0x80ac, 2}, { -3, -3, 0xc0ac, 2}, {-10, -10, 0x00ac, 2}, { -6, -10, 0x40ac, 2}, {-10, -6, 0x80ac, 2}, { -6, -6, 0xc0ac, 2}, { -8, -8, 0x00ac, 2}, { -8, -8, 0x40ac, 2}, { -8, -8, 0x80ac, 2}, { -8, -8, 0xc0ac, 2}, }; Oam_AllocateFromRegionB(0x10); Sprite_DrawMultiple(k, &kSomariaPlatform_Dmd[sprite_delay_aux4[k] & 12], 4, NULL); } void SomariaPlatform_HandleJunctions(int k) { // 9ef87d switch (sprite_E[k]) { case 0xb2: case 0xb5: // ZigZagRisingSlope sprite_D[k] ^= 3; break; case 0xb3: case 0xb4: // ZigZagFallingSlope sprite_D[k] ^= 2; break; case 0xb6: { // TransitTile static const uint8 kSomariaPlatform_TransitDir[4] = {4, 8, 1, 2}; sprite_ai_state[k] = 1; if (!link_auxiliary_state && joypad1H_last & kSomariaPlatform_TransitDir[sprite_D[k]]) { sprite_ai_state[k] = 0; sprite_D[k] ^= 1; } link_visibility_status = 0; player_on_somaria_platform = 1; break; } case 0xb7: { // Tjunc_NoUp static const uint8 kSomariaPlatform_Keys1[4] = {3, 7, 6, 5}; uint8 t = joypad1H_last & kSomariaPlatform_Keys1[sprite_D[k]]; if (t & 8) { sprite_D[k] = 0; } else if (t & 4) { sprite_D[k] = 1; } else if (t & 2) { sprite_D[k] = 2; } else if (t & 1) { sprite_D[k] = 3; } else if (sprite_D[k] == 0) { sprite_D[k] = 2; } sprite_ai_state[k] = 0; break; } case 0xb8: { // Tjunc_NoDown static const uint8 kSomariaPlatform_Keys2[4] = {11, 3, 10, 9}; uint8 t = joypad1H_last & kSomariaPlatform_Keys2[sprite_D[k]]; if (t & 8) { sprite_D[k] = 0; } else if (t & 4) { sprite_D[k] = 1; } else if (t & 2) { sprite_D[k] = 2; } else if (t & 1) { sprite_D[k] = 3; } else if (sprite_D[k] == 1) { sprite_D[k] = 2; } sprite_ai_state[k] = 0; break; } case 0xb9: { // Tjunc_NoLeft static const uint8 kSomariaPlatform_Keys3[4] = {9, 5, 12, 13}; uint8 t = joypad1H_last & kSomariaPlatform_Keys3[sprite_D[k]]; if (t & 8) { sprite_D[k] = 0; } else if (t & 4) { sprite_D[k] = 1; } else if (t & 2) { sprite_D[k] = 2; } else if (t & 1) { sprite_D[k] = 3; } else if (sprite_D[k] == 2) { sprite_D[k] = 0; } sprite_ai_state[k] = 0; break; } case 0xba: { // Tjunc_NoRight static const uint8 kSomariaPlatform_Keys4[4] = {0xa, 6, 0xe, 0xc}; uint8 t = joypad1H_last & kSomariaPlatform_Keys4[sprite_D[k]]; if (t & 8) { sprite_D[k] = 0; } else if (t & 4) { sprite_D[k] = 1; } else if (t & 2) { sprite_D[k] = 2; } else if (t & 1) { sprite_D[k] = 3; } else if (sprite_D[k] == 3) { sprite_D[k] = 0; } sprite_ai_state[k] = 0; break; } case 0xbb: { // TransitTileNoBack static const uint8 kSomariaPlatform_Keys5[4] = {0xb, 7, 0xe, 0xd}; uint8 t = joypad1H_last & kSomariaPlatform_Keys5[sprite_D[k]]; if (t & 8) { sprite_D[k] = 0; } else if (t & 4) { sprite_D[k] = 1; } else if (t & 2) { sprite_D[k] = 2; } else if (t & 1) { sprite_D[k] = 3; } break; } case 0xbc: { // TransitTileQuestion static const uint8 kSomariaPlatform_Keys6[4] = {0xc, 0xc, 3, 3}; sprite_ai_state[k] = 1; uint8 t = joypad1H_last & kSomariaPlatform_Keys6[sprite_D[k]]; if (t) { if (t & 8) { sprite_D[k] = 0; } else if (t & 4) { sprite_D[k] = 1; } else if (t & 2) { sprite_D[k] = 2; } else { sprite_D[k] = 3; } sprite_ai_state[k] = 0; } player_on_somaria_platform = 1; break; } case 0xbe: // endpoint sprite_ai_state[k] = 0; sprite_D[k] ^= 1; link_visibility_status = 0; player_on_somaria_platform = 1; break; } } void SomariaPlatform_HandleDragX(int k) { // 9ef8ad if ((sprite_D[k] ^ sprite_head_dir[k]) & 2) { uint8 x = (sprite_x_lo[k] & ~7) + 4; uint8 t = x - sprite_x_lo[k]; if (!t) return; drag_player_x = (int8)t; sprite_x_lo[k] = x; } } void SomariaPlatform_HandleDragY(int k) { // 9ef8d7 if ((sprite_D[k] ^ sprite_head_dir[k]) & 2) { uint8 y = (sprite_y_lo[k] & ~7) + 4; uint8 t = y - sprite_y_lo[k]; if (!t) return; drag_player_y = (int8)t; sprite_y_lo[k] = y; } } void SomariaPlatform_HandleDrag(int k) { // 9ef901 SomariaPlatform_HandleDragX(k); SomariaPlatform_HandleDragY(k); } void SomariaPlatform_DragLink(int k) { // 9efb49 uint16 x = cur_sprite_x - 8 - link_x_coord; if (x) drag_player_x += sign16(x) ? -1 : 1; uint16 y = cur_sprite_y - 16 - link_y_coord; if (y) drag_player_y += sign16(y) ? -1 : 1; } void Sprite_AE_Pipe_Down(int k) { // 9efb7e static const uint8 kPipe_Dirs[4] = {8, 4, 2, 1}; uint8 t; if (Sprite_ReturnIfInactive(k)) return; switch(sprite_graphics[k]) { case 0: // locate transit tile alt_sprite_spawned_flag[0] = 255; sprite_D[k] = sprite_type[k] - 0xae; SomariaPlatform_LocatePath(k); break; case 1: // locate endpoint t = SomariaPlatformAndPipe_CheckTile(k); if (t == 0xbe) { sprite_graphics[k]++; t = (sprite_D[k] ^= 1); } sprite_E[k] = t; sprite_head_dir[k] = sprite_D[k]; SomariaPlatformAndPipe_HandleMovement(k); Sprite_MoveXY(k); break; case 2: // wait for player if (alt_sprite_spawned_flag[0] == 255 && Sprite_CheckDamageToLink_ignore_layer(k)) { if (!Pipe_ValidateEntry()) { sprite_graphics[k]++; sprite_delay_aux1[k] = 4; Link_ResetProperties_A(); flag_is_link_immobilized = 1; link_disable_sprite_damage = 1; alt_sprite_spawned_flag[0] = k; } else { Sprite_HaltAllMovement(); } } break; case 3: // draw player in if (!sprite_delay_aux1[k]) { sprite_graphics[k]++; link_visibility_status = 12; } else { flag_is_link_immobilized = 1; link_disable_sprite_damage = 1; Pipe_HandlePlayerMovement(kPipe_Dirs[sprite_D[k]]); } break; case 4: { // draw player along sprite_subtype2[k] = 3; link_x_coord_safe_return_lo = link_x_coord; link_x_coord_safe_return_hi = link_x_coord >> 8; link_y_coord_safe_return_lo = link_y_coord; link_y_coord_safe_return_hi = link_y_coord >> 8; do { if (!(++sprite_A[k] & 7)) { uint8 t = SomariaPlatformAndPipe_CheckTile(k); if (t >= 0xb2 && t < 0xb6) SpriteSfx_QueueSfx2WithPan(k, 0xb); if (t != sprite_E[k]) { sprite_E[k] = t; if (t == 0xbe) { sprite_graphics[k]++; sprite_delay_aux1[k] = 24; } sprite_head_dir[k] = sprite_D[k]; SomariaPlatformAndPipe_HandleMovement(k); SomariaPlatform_HandleDrag(k); } } Sprite_MoveXY(k); uint16 x = Sprite_GetX(k) - 8; uint16 y = Sprite_GetY(k) - 14; if (x != link_x_coord) link_x_coord += (x < link_x_coord) ? -1 : 1; if (y != link_y_coord) link_y_coord += (y < link_y_coord) ? -1 : 1; } while (--sprite_subtype2[k]); link_x_vel = link_x_coord - link_x_coord_safe_return_lo; link_y_vel = link_y_coord - link_y_coord_safe_return_lo; link_direction_last = kPipe_Dirs[sprite_D[k]]; Link_HandleMovingAnimation_FullLongEntry(); HandleIndoorCameraAndDoors(); Link_CancelDash(); break; } case 5: // if (!sprite_delay_aux1[k]) { flag_is_link_immobilized = 0; player_on_somaria_platform = 0; link_disable_sprite_damage = 0; link_visibility_status = 0; link_x_vel = link_y_vel = 0; alt_sprite_spawned_flag[0] = 255; sprite_graphics[k] = 2; } else { Pipe_HandlePlayerMovement(kPipe_Dirs[sprite_D[k] ^ 1]); } break; } } void Pipe_HandlePlayerMovement(uint8 dir) { // 9efcff link_direction_last = link_direction = dir; Link_HandleVelocity(); Link_HandleMovingAnimation_FullLongEntry(); HandleIndoorCameraAndDoors(); } void Faerie_HandleMovement(int k) { // 9efd1c sprite_graphics[k] = frame_counter >> 3 & 1; if (player_is_indoors && !sprite_delay_aux1[k]) { if (Sprite_CheckTileCollision(k) & 3) { sprite_x_vel[k] = -sprite_x_vel[k]; sprite_D[k] = -sprite_D[k]; sprite_delay_aux1[k] = 32; } if (sprite_wallcoll[k] & 12) { sprite_y_vel[k] = -sprite_y_vel[k]; sprite_A[k] = -sprite_A[k]; sprite_delay_aux1[k] = 32; } } if (sprite_x_vel[k]) { if (sign8(sprite_x_vel[k])) sprite_oam_flags[k] &= ~0x40; else sprite_oam_flags[k] |= 0x40; } Sprite_MoveXY(k); if (!(frame_counter & 63)) { uint16 x = (link_x_coord & ~0xff) + GetRandomNumber(); uint16 y = (link_y_coord & ~0xff) + GetRandomNumber(); ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16); sprite_A[k] = pt.y; sprite_D[k] = pt.x; } if (!(frame_counter & 15)) { sprite_y_vel[k] = ((int8)sprite_A[k] + (int8)sprite_y_vel[k]) >> 1; sprite_x_vel[k] = ((int8)sprite_D[k] + (int8)sprite_x_vel[k]) >> 1; } Sprite_MoveZ(k); sprite_z_vel[k] += (GetRandomNumber() & 1) ? -1 : 1; if (sprite_z[k] < 8) { sprite_z[k] = 8; sprite_z_vel[k] = 5; } else if (sprite_z[k] >= 24) { sprite_z[k] = 24; sprite_z_vel[k] = -5; } }