ref: 02754b2f0937d94bb90f7f742f4f7aa6dad06bd4
dir: /src/tagalong.c/
#include "tagalong.h" #include "sprite_main.h" #include "sprite.h" #include "zelda_rtl.h" #include "variables.h" #include "snes/snes_regs.h" #include "dungeon.h" #include "overworld.h" #include "ancilla.h" #include "player.h" #include "misc.h" static const uint8 kTagalongFlags[4] = {0x20, 0x10, 0x30, 0x20}; static const uint8 kTagalong_Tab5[15] = {0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const uint8 kTagalong_Tab4[15] = {0, 0, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const uint8 kTagalong_Tab0[3] = {5, 9, 0xa}; static const uint16 kTagalong_Tab1[3] = {0xdf3, 0x6f9, 0xdf3}; static const uint16 kTagalong_Msg[3] = {0x20, 0x108, 0x11d}; static const TagalongMessageInfo kTagalong_IndoorInfos[12] = { {0x1ef0, 0x288, 1, 0x99, 4}, {0x1e58, 0x2f0, 2, 0x9a, 4}, {0x1ea8, 0x3b8, 4, 0x9b, 4}, {0xcf8, 0x25b, 1, 0x21, 1}, {0xcf8, 0x39d, 2, 0x21, 1}, {0xc78, 0x238, 4, 0x21, 1}, {0xa30, 0x2f8, 1, 0x22, 1}, {0x178, 0x550, 1, 0x23, 1}, {0x168, 0x4f8, 2, 0x2a, 1}, {0x1bd8, 0x16fc, 1, 0x124, 6}, {0x1520, 0x167c, 1, 0x124, 6}, {0x5ac, 0x4fc, 1, 0x29, 1}, }; static const TagalongMessageInfo kTagalong_OutdoorInfos[5] = { {0x3c0, 0x730, 1, 0x9d, 4}, {0x648, 0xf50, 0, 0xffff, 0xa}, {0x6c8, 0xd78, 1, 0xffff, 0xa}, {0x688, 0xc78, 2, 0xffff, 0xa}, {0xe8, 0x90, 0, 0x28, 0xe}, }; static const uint8 kTagalong_IndoorOffsets[8] = {0, 3, 6, 7, 9, 10, 11, 12}; static const uint8 kTagalong_OutdoorOffsets[4] = {0, 1, 4, 5}; static const uint16 kTagalong_IndoorRooms[7] = {0xf1, 0x61, 0x51, 2, 0xdb, 0xab, 0x22}; static const uint16 kTagalong_OutdoorRooms[3] = {3, 0x5e, 0}; typedef struct TagalongSprXY { int8 y1, x1, y2, x2; } TagalongSprXY; typedef struct TagalongDmaFlags { uint8 dma6, dma7; uint8 flags; } TagalongDmaFlags; static const TagalongSprXY kTagalongDraw_SprXY[56] = { {-2, 0, 0, 0}, {-2, 0, 0, 0}, {-2, 0, 0, 0}, {-2, 0, 0, 0}, {-1, 0, 1, 0}, {-1, 0, 1, 0}, {-1, 0, 1, 0}, {-1, 0, 1, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, -3, 0, 0}, {0, 3, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 0}, {1, -3, 1, 0}, {1, 3, 1, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {-1, 0, 0, 0}, {-1, 0, 0, 0}, {-1, 0, 0, 0}, {-1, 0, 0, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {2, 0, 0, 0}, {2, 0, 0, 0}, {2, -1, 0, 0}, {2, 1, 0, 0}, {3, 0, 1, 0}, {3, 0, 1, 0}, {3, -1, 1, 0}, {3, 1, 1, 0}, }; static const TagalongDmaFlags kTagalongDmaAndFlags[16] = { {0x20, 0xc0, 0x00}, {0x00, 0xa0, 0x00}, {0x40, 0x60, 0x00}, {0x40, 0x60, 0x44}, {0x20, 0xc0, 0x04}, {0x00, 0xa0, 0x04}, {0x40, 0x80, 0x00}, {0x40, 0x80, 0x44}, {0x20, 0xe0, 0x00}, {0x00, 0xe0, 0x00}, {0x40, 0xe0, 0x00}, {0x40, 0xe0, 0x44}, {0x20, 0xe0, 0x04}, {0x00, 0xe0, 0x04}, {0x40, 0xe0, 0x04}, {0x40, 0xe0, 0x40}, }; static const uint8 kTagalongDraw_Pals[14] = {0, 4, 4, 4, 4, 0, 7, 4, 4, 3, 4, 4, 4, 4}; static const uint16 kTagalongDraw_Offs[14] = {0, 0, 0x80, 0x80, 0x80, 0, 0, 0xc0, 0xc0, 0x100, 0x180, 0x180, 0x140, 0x140}; static const uint8 kTagalongDraw_SprInfo0[24] = { 0xd8, 0x24, 0xd8, 0x64, 0xd9, 0x24, 0xd9, 0x64, 0xda, 0x24, 0xda, 0x64, 0xc8, 0x22, 0xc8, 0x62, 0xc9, 0x22, 0xc9, 0x62, 0xca, 0x22, 0xca, 0x62, }; static const uint16 kTagalongDraw_SprOffs0[2] = {0x170, 0xc0}; static const uint16 kTagalongDraw_SprOffs1[2] = {0x1c0, 0x110}; bool Tagalong_IsFollowing() { uint8 main = main_module_index; uint8 sub = submodule_index; return !flag_is_link_immobilized && sub != 10 && !(main == 9 && sub == 0x23) && !(main == 14 && (sub == 1 || sub == 2)); } bool Follower_ValidateMessageFreedom() { // 87f46f uint8 ps = link_player_handler_state; if (ps != kPlayerState_Ground && ps != kPlayerState_Swimming && ps != kPlayerState_StartDash) return false; uint8 t = button_mask_b_y & 0x80 | link_unk_master_sword | link_item_in_hand | link_position_mode | flag_is_ancilla_to_pick_up | flag_is_sprite_to_pick_up | link_state_bits | link_grabbing_wall; return t == 0; } void Follower_MoveTowardsLink() { // 88f91a for(;;) { int k = 9; int j = tagalong_var1; ancilla_y_lo[k] = tagalong_y_lo[j]; ancilla_y_hi[k] = tagalong_y_hi[j]; ancilla_x_lo[k] = tagalong_x_lo[j]; ancilla_x_hi[k] = tagalong_x_hi[j]; ProjectSpeedRet pt = Ancilla_ProjectSpeedTowardsPlayer(k, 24); ancilla_x_vel[k] = pt.x; ancilla_y_vel[k] = pt.y; Ancilla_MoveY(k); Ancilla_MoveX(k); uint16 x = Ancilla_GetX(k); uint16 y = Ancilla_GetY(k); if (abs16(x - link_x_coord) < 2 && abs16(y - link_y_coord) < 2) return; k = ++tagalong_var1; if (k == 18) return; tagalong_y_lo[k] = y; tagalong_y_hi[k] = y >> 8; tagalong_x_lo[k] = x; tagalong_x_hi[k] = x >> 8; static const uint8 kTagalongLayerBits[4] = {0x20, 0x10, 0x30, 0x20}; tagalong_layerbits[k] = kTagalongLayerBits[link_is_on_lower_level] >> 2 | 1; } } bool Follower_CheckBlindTrigger() { // 899e90 int k = tagalong_var2; uint16 x = tagalong_x_hi[k] << 8 | tagalong_x_lo[k]; uint16 y = tagalong_y_hi[k] << 8 | tagalong_y_lo[k]; uint16 z = (int8)tagalong_z[k]; y += z + 12; x += 8; return abs16(0x1568 - y) < 24 && abs16(0x1980 - x) < 24; } void Follower_Initialize() { // 899efc tagalong_y_lo[0] = link_y_coord; tagalong_y_hi[0] = link_y_coord >> 8; tagalong_x_lo[0] = link_x_coord; tagalong_x_hi[0] = link_x_coord >> 8; tagalong_layerbits[0] = kTagalongFlags[link_is_on_lower_level] >> 2 | (link_direction_facing >> 1); timer_tagalong_reacquire = 64; tagalong_var2 = 0; tagalong_var1 = 0; tagalong_var3 = 0; tagalong_var4 = 0; link_speed_setting = 0; if (enhanced_features0 & kFeatures0_TurnWhileDashing) { link_player_handler_state = kPlayerState_Ground; link_is_running = false; } } void Sprite_BecomeFollower(int k) { // 899f39 tagalong_var5 = 0; int y = Sprite_GetY(k) - 6; tagalong_y_lo[0] = y, tagalong_y_hi[0] = (y >> 8); int x = Sprite_GetX(k) + 1; tagalong_x_lo[0] = x, tagalong_x_hi[0] = (x >> 8); tagalong_layerbits[0] = kTagalongFlags[link_is_on_lower_level] >> 2 | 1; timer_tagalong_reacquire = 64; tagalong_var1 = 0; tagalong_var2 = 0; tagalong_var3 = 0; tagalong_var4 = 0; link_speed_setting = 0; tagalong_var5 = 0; follower_dropped = 0; Follower_MoveTowardsLink(); } void Follower_Main() { // 899fc4 if (!follower_indicator) return; if (follower_indicator == 0xe) { Follower_HandleTrigger(); return; } int j = FindInByteArray(kTagalong_Tab0, follower_indicator, 3); if (j >= 0 && submodule_index == 0 && !(j == 2 && overworld_screen_index & 0x40) && sign16(--word_7E02CD)) { if (!Follower_ValidateMessageFreedom()) { word_7E02CD = 0; } else { word_7E02CD = kTagalong_Tab1[j]; dialogue_message_index = kTagalong_Msg[j]; Main_ShowTextMessage(); } } if (j != 0) Follower_NoTimedMessage(); } void Follower_NoTimedMessage() { // 89a02b int k; if (follower_dropped) { Follower_NotFollowing(); return; } if (follower_indicator == 12) { if (link_auxiliary_state != 0) goto label_a; } else if (follower_indicator == 13) { if (link_auxiliary_state == 2 || player_near_pit_state == 2) goto label_c; } else { goto label_a; } if (submodule_index != 0 || link_auxiliary_state == 1 || (link_state_bits & 0x80) || tagalong_var5 || tagalong_var3 || (int8)tagalong_z[tagalong_var2] > 0 || !(filtered_joypad_L & 0x80)) goto label_a; label_c: if (follower_indicator == 13 && !player_is_indoors) { if (link_player_handler_state == kPlayerState_Ether || link_player_handler_state == kPlayerState_Bombos || link_player_handler_state == kPlayerState_Quake) goto label_a; super_bomb_indicator_unk2 = 3; super_bomb_indicator_unk1 = 0xbb; } follower_dropped = 128; timer_tagalong_reacquire = 64; k = tagalong_var2; saved_tagalong_y = tagalong_y_lo[k] | tagalong_y_hi[k] << 8; saved_tagalong_x = tagalong_x_lo[k] | tagalong_x_hi[k] << 8; saved_tagalong_floor = link_is_on_lower_level; saved_tagalong_indoors = player_is_indoors; Follower_NotFollowing(); return; label_a: Follower_CheckGameMode(); } void Follower_CheckGameMode() { // 89a0e1 if (Tagalong_IsFollowing() && (link_x_vel | link_y_vel)) { int k = tagalong_var1 + 1; if (k == 20) k = 0; tagalong_var1 = k; uint8 z = link_z_coord; if (z >= 0xf0) z = 0; tagalong_z[k] = z; uint16 y = link_y_coord - z; tagalong_y_lo[k] = y; tagalong_y_hi[k] = y >> 8; uint16 x = link_x_coord; tagalong_x_lo[k] = x; tagalong_x_hi[k] = x >> 8; uint8 layerbits = link_direction_facing >> 1 | kTagalongFlags[link_is_on_lower_level] >> 2; if (link_player_handler_state == kPlayerState_Swimming) { layerbits |= 0x20; } else { if (link_player_handler_state == kPlayerState_Hookshot && related_to_hookshot) layerbits |= 0x10; if (draw_water_ripples_or_grass) layerbits |= (draw_water_ripples_or_grass == 1) ? 0x80 : 0x40; } tagalong_layerbits[k] = layerbits; } switch (follower_indicator) { case 2: case 4: Follower_OldMan(); return; case 3: case 11: Follower_OldManUnused(); return; case 5: case 14: assert(0); // Y is unknown here... return; default: Follower_BasicMover(); return; } } void Follower_BasicMover() { // 89a197 int k; if (!Tagalong_IsFollowing()) { Tagalong_Draw(); return; } Follower_HandleTrigger(); if (follower_indicator == 10 && link_auxiliary_state && countdown_for_blink) { int k = tagalong_var2 + 1 == 20 ? 0 : tagalong_var2 + 1; Kiki_SpawnHandler_B(k); follower_indicator = 0; return; } if (follower_indicator == 6 && dungeon_room_index == 0xac && (save_dung_info[101] & 0x100) && Follower_CheckBlindTrigger()) { int k = tagalong_var2; uint16 x = tagalong_x_lo[k] | tagalong_x_hi[k] << 8; uint16 y = tagalong_y_lo[k] | tagalong_y_hi[k] << 8; follower_indicator = 0; Blind_SpawnFromMaiden(x, y); BYTE(dung_flag_trapdoors_down)++; BYTE(dung_cur_door_pos) = 0; BYTE(door_animation_step_indicator) = 0; submodule_index = 5; music_control = 21; return; } if (!tagalong_var3) { if (link_player_handler_state == kPlayerState_Hookshot && related_to_hookshot) { tagalong_var3 = 1; goto label_e; } } else { if (link_player_handler_state == kPlayerState_Hookshot) goto label_e; if (tagalong_var7 != tagalong_var2) goto label_d; tagalong_var3 = 0; } k = tagalong_var2; if ((int8)tagalong_z[k] > 0) { if (tagalong_var1 != k) goto label_d; tagalong_z[k] = 0; uint16 y = link_y_coord, x = link_x_coord; tagalong_y_lo[k] = y; tagalong_y_hi[k] = y >> 8; tagalong_x_lo[k] = x; tagalong_x_hi[k] = x >> 8; } if (link_x_vel | link_y_vel) { uint8 t; label_e: t = tagalong_var1 - 15; if (sign8(t)) t += 20; if (t == tagalong_var2) { label_d: tagalong_var2 = (tagalong_var2 + 1 == 20) ? 0 : tagalong_var2 + 1; } } Tagalong_Draw(); } void Follower_NotFollowing() { // 89a2b2 if (saved_tagalong_indoors != player_is_indoors) return; if (!link_is_running && !Follower_CheckProximityToLink()) { Follower_Initialize(); saved_tagalong_indoors = player_is_indoors; if (follower_indicator == 13) { super_bomb_indicator_unk2 = 254; super_bomb_indicator_unk1 = 0; } follower_dropped = 0; Tagalong_Draw(); } else { if (follower_indicator == 13 && !player_is_indoors && !super_bomb_indicator_unk2) { // Fixed so we wait a little bit if we can't spawn the ancilla if (AncillaAdd_SuperBombExplosion(0x3a, 0) >= 0) { follower_dropped = 0; // A ticking super bomb will cancel and teleport back to you as a follower if you do // any of these at count 0: (1) change screen via walking, mirror, or bird travel // (2) fill all ancillary slots // (3) die with a bottled faerie. // Fixed this by clearing the follower indicator here, instead of in the ancilla // bomb code. if (enhanced_features0 & kFeatures0_MiscBugFixes) { follower_indicator = 0; return; } } else { super_bomb_indicator_unk1 = 1; } } Follower_DoLayers(); } } void Follower_OldMan() { // 89a318 uint8 t; if (!Tagalong_IsFollowing()) { Tagalong_Draw(); return; } if (link_speed_setting != 4) link_speed_setting = 12; Follower_HandleTrigger(); if (follower_indicator == 0) { return; } else if (follower_indicator == 4) { if ((int8)tagalong_z[tagalong_var2] > 0 && tagalong_var1 != tagalong_var2) { tagalong_var2 = (tagalong_var2 + 1 >= 20) ? 0 : tagalong_var2 + 1; Tagalong_Draw(); return; } } else { // tagalong type 2 if ((link_auxiliary_state & 1) && link_player_handler_state == kPlayerState_RecoilOther) { if (tagalong_var1 != tagalong_var2) goto transform; assert(0); // X is undefined here } if (link_auxiliary_state & 2) { transform: follower_indicator = kTagalong_Tab4[follower_indicator]; timer_tagalong_reacquire = 64; int k = tagalong_var2; saved_tagalong_y = tagalong_y_lo[k] | tagalong_y_hi[k] << 8; saved_tagalong_x = tagalong_x_lo[k] | tagalong_x_hi[k] << 8; saved_tagalong_floor = link_is_on_lower_level; Follower_OldManUnused(); return; } } if (link_x_vel | link_y_vel) { t = tagalong_var1 - 20; if (sign8(t)) t += 20; if (t == tagalong_var2) { tagalong_var2 = (tagalong_var2 + 1 >= 20) ? 0 : tagalong_var2 + 1; } } else if ((frame_counter & 3) == 0 && tagalong_var1 != tagalong_var2) { t = tagalong_var1 - 9; if (sign8(t)) t += 20; if (t != tagalong_var2) { tagalong_var2 = (tagalong_var2 + 1 >= 20) ? 0 : tagalong_var2 + 1; } } Tagalong_Draw(); } void Follower_OldManUnused() { // 89a41f link_speed_setting = 16; if (!link_is_running && !link_auxiliary_state && link_player_handler_state != kPlayerState_Swimming) { link_speed_setting = 0; if (link_player_handler_state != kPlayerState_Hookshot && !Follower_CheckProximityToLink()) { Follower_Initialize(); follower_indicator = kTagalong_Tab5[follower_indicator]; return; } } Follower_DoLayers(); } void Follower_DoLayers() { // 89a450 oam_priority_value = kTagalongFlags[saved_tagalong_floor] << 8; uint8 a = (follower_indicator == 12 || follower_indicator == 13) ? 2 : 1; Follower_AnimateMovement_preserved(a, saved_tagalong_x, saved_tagalong_y); } bool Follower_CheckProximityToLink() { // 89a48e if (!sign8(--timer_tagalong_reacquire)) return true; timer_tagalong_reacquire = 0; if ((uint16)(saved_tagalong_y - 1) >= link_y_coord || (uint16)(saved_tagalong_y + 19) < link_y_coord || (uint16)(saved_tagalong_x - 1) >= link_x_coord || (uint16)(saved_tagalong_x + 19) < link_x_coord) return true; return false; } void Follower_HandleTrigger() { // 89a59e if (submodule_index) return; const TagalongMessageInfo *tmi, *tmi_end; if (player_is_indoors) { int j = FindInWordArray(kTagalong_IndoorRooms, dungeon_room_index, 7); if (j < 0) return; tmi = kTagalong_IndoorInfos + kTagalong_IndoorOffsets[j]; tmi_end = kTagalong_IndoorInfos + kTagalong_IndoorOffsets[j + 1]; } else { int j = FindInWordArray(kTagalong_OutdoorRooms, overworld_screen_index, 3); if (j < 0) return; tmi = kTagalong_OutdoorInfos + kTagalong_OutdoorOffsets[j]; tmi_end = kTagalong_OutdoorInfos + kTagalong_OutdoorOffsets[j + 1]; } int st = (tagalong_var2 + 1 >= 20) ? 0 : tagalong_var2 + 1; do { if (tmi->tagalong == follower_indicator && Follower_CheckForTrigger(tmi)) { if (tmi->bit & tagalong_event_flags) return; tagalong_event_flags |= tmi->bit; dialogue_message_index = tmi->msg; if (tmi->msg == 0xffff) { if (!(tmi->bit & 3)) Kiki_RevertToSprite(st); else if (!(save_ow_event_info[BYTE(overworld_screen_index)] & 1)) Kiki_SpawnHandler_A(st); return; } if (tmi->msg == 0x9d) { OldMan_RevertToSprite(st); } else if (tmi->msg == 0x28) { follower_indicator = 0; } Main_ShowTextMessage(); return; } } while (++tmi != tmi_end); } void Tagalong_Draw() { // 89a907 if (tagalong_var5) return; oam_priority_value = ((tagalong_z[tagalong_var2] && !player_is_indoors) ? 0x20 : (submodule_index == 14) ? kTagalongFlags[link_is_on_lower_level] : (tagalong_layerbits[tagalong_var2] & 0xc) << 2) << 8; int k = tagalong_var2; if (sign8(k)) k = 0; uint16 x = tagalong_x_lo[k] | tagalong_x_hi[k] << 8; uint16 y = tagalong_y_lo[k] | tagalong_y_hi[k] << 8; uint8 a = tagalong_layerbits[k]; Follower_AnimateMovement_preserved(a, x, y); } static inline void SetOam_Follower(OamEnt *oam, uint16 x, uint16 y, uint8 charnum, uint8 flags, uint8 big) { oam->x = x; oam->y = (uint16)(x + 0x80) < 0x180 && (big |= x >> 8 & 1, (uint16)(y + 0x10) < 0x100) ? y : 0xf0; oam->charnum = charnum; oam->flags = flags; bytewise_extended_oam[oam - oam_buf] = big; } void Follower_AnimateMovement_preserved(uint8 ain, uint16 xin, uint16 yin) { // 89a959 uint8 yt = 0, av = 0; uint8 sc = 0; if ((ain >> 2 & 8) && (follower_indicator == 6 || follower_indicator == 1)) { yt = 8; if (swimcoll_var7[0] | swimcoll_var7[1]) av = (frame_counter >> 1) & 4; else av = (frame_counter >> 2) & 4; } else if (submodule_index == 8 || submodule_index == 14 || submodule_index == 16) { av = link_is_running ? (frame_counter & 4) : ((frame_counter >> 1) & 4); } else if (follower_indicator == 11) { av = (frame_counter >> 1) & 4; } else if ((follower_indicator == 12 || follower_indicator == 13) && follower_dropped || flag_is_link_immobilized || submodule_index == 10 || main_module_index == 9 && submodule_index == 0x23 || main_module_index == 14 && (submodule_index == 1 || submodule_index == 2) || (link_y_vel | link_x_vel) == 0) { av = sc = 4; } else { av = link_is_running ? (frame_counter & 4) : ((frame_counter >> 1) & 4); } uint8 frame = (ain & 3) + av + yt; int spr_offs = (link_y_coord == yin && !(ain & 3) || link_y_coord < yin) ? kTagalongDraw_SprOffs0[sort_sprites_setting] >> 2: kTagalongDraw_SprOffs1[sort_sprites_setting] >> 2; oam_ext_cur_ptr = 0xa20 + spr_offs; oam_cur_ptr = 0x800 + spr_offs * 4; OamEnt *oam = GetOamCurPtr(); uint16 scrolly = yin - BG2VOFS_copy2; uint16 scrollx = xin - BG2HOFS_copy2; const uint8 *sk = kTagalongDraw_SprInfo0; if (follower_indicator == 1 || follower_indicator == 6 || !(ain & 0x20)) { if (!(ain & 0xc0)) goto skip_first_sprites; if ((ain & 0x80) || (sk += 12, sc == 0)) goto incr; byte_7E02D7 = 0; } else { incr: if (!(frame_counter & 7) && ++byte_7E02D7 == 3) byte_7E02D7 = 0; } sk += byte_7E02D7 * 4; SetOam_Follower(oam + 0, scrollx, scrolly + 16, sk[0], sk[1], 0); SetOam_Follower(oam + 1, scrollx + 8, scrolly + 16, sk[2], sk[3], 0); oam += 2; uint8 pal; skip_first_sprites: pal = kTagalongDraw_Pals[follower_indicator]; if (pal == 7 && palette_swap_flag) pal = 0; if (follower_indicator == 13) { // Display colorful superbomb palette also on frame 0. if (enhanced_features0 & kFeatures0_MiscBugFixes ? (super_bomb_indicator_unk2 <= 1) : (super_bomb_indicator_unk2 == 1)) pal = (frame_counter & 7); } const TagalongSprXY *sprd = kTagalongDraw_SprXY + frame + (kTagalongDraw_Offs[follower_indicator] >> 3); const TagalongDmaFlags *sprf = kTagalongDmaAndFlags + frame; if (follower_indicator != 12 && follower_indicator != 13) { SetOam_Follower(oam, scrollx + sprd->x1, scrolly + sprd->y1, 0x20, (sprf->flags & 0xf0) | pal << 1 | (oam_priority_value >> 8), 2); oam++; BYTE(dma_var6) = sprf->dma6; } { SetOam_Follower(oam, scrollx + sprd->x2, scrolly + sprd->y2 + 8, 0x22, ((sprf->flags & 0xf) << 4) | pal << 1 | (oam_priority_value >> 8), 2); BYTE(dma_var7) = sprf->dma7; } } bool Follower_CheckForTrigger(const TagalongMessageInfo *info) { // 89ac26 uint16 x = link_x_coord + 12 - (info->x + 8); uint16 y = link_y_coord + 12 - (info->y + 8); if (sign16(x)) x = -x; if (sign16(y)) y = -y; return x < 24 && y < 28; } void Follower_Disable() { // 89acf3 if (follower_indicator == 9 || follower_indicator == 10) follower_indicator = 0; } void Blind_SpawnFromMaiden(uint16 x, uint16 y) { // 9da03c int k = 0; sprite_state[k] = 9; sprite_type[k] = 206; Sprite_SetX(k, x); Sprite_SetY(k, y - 16); SpritePrep_LoadProperties(k); sprite_delay_aux2[k] = 192; sprite_graphics[k] = 21; sprite_D[k] = 2; sprite_ignore_projectile[k] = 2; dung_savegame_state_bits |= 0x2000; byte_7E0B69 = 0; } void Kiki_RevertToSprite(int k) { // 9ee66b int j = Kiki_SpawnHandlerMonke(k); sprite_subtype2[j] = 1; follower_indicator = 0; } int Kiki_SpawnHandlerMonke(int k) { // 9ee67a SpriteSpawnInfo info; int j = Sprite_SpawnDynamically(k, 0xb6, &info); if (j >= 0) { sprite_head_dir[j] = tagalong_layerbits[k] & 3; sprite_D[j] = tagalong_layerbits[k] & 3; int x = tagalong_x_hi[k] << 8 | tagalong_x_lo[k]; int y = tagalong_y_hi[k] << 8 | tagalong_y_lo[k]; Sprite_SetX(j, x + 2); Sprite_SetY(j, y + 2); sprite_floor[j] = link_is_on_lower_level; sprite_ignore_projectile[j] = 1; sprite_floor[j] = 2; link_speed_setting = 0; } return j; } void Kiki_SpawnHandler_A(int k) { // 9ee6c7 int j = Kiki_SpawnHandlerMonke(k); sprite_subtype2[j] = 2; } void Kiki_SpawnHandler_B(int k) { // 9ee6d0 int j = Kiki_SpawnHandlerMonke(k); sprite_z[j] = 1; sprite_z_vel[j] = 16; sprite_subtype2[j] = 3; follower_indicator = 0; }