diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 38dcb579..92e1e980 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -774,6 +774,10 @@ ac_ins_amenbo.c: .text: [0x80595C74, 0x80596388] .rodata: [0x80649E70, 0x80649EC8] .data: [0x806C3200, 0x806C3230] +ac_ins_goki.c: + .text: [0x80599A2C, 0x8059A8E8] + .rodata: [0x8064A028, 0x8064A090] + .data: [0x806C33C8, 0x806C3460] ac_ins_hitodama.c: .text: [0x8059A8E8, 0x8059B354] .rodata: [0x8064A090, 0x8064A108] diff --git a/include/ac_ins_goki.h b/include/ac_ins_goki.h new file mode 100644 index 00000000..c7414039 --- /dev/null +++ b/include/ac_ins_goki.h @@ -0,0 +1,17 @@ +#ifndef AC_INS_GOKI_H +#define AC_INS_GOKI_H + +#include "types.h" +#include "ac_insect_h.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void aIGK_actor_init(ACTOR* actorx, GAME* game); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ac_set_ovl_insect.h b/include/ac_set_ovl_insect.h index 64ff4838..bb8ec2e7 100644 --- a/include/ac_set_ovl_insect.h +++ b/include/ac_set_ovl_insect.h @@ -13,92 +13,97 @@ extern "C" { #define aSOI_INSECT_TYPE_INVALID -1 enum insect_type { - aSOI_INSECT_TYPE_COMMON_BUTTERFLY, - aSOI_INSECT_TYPE_YELLOW_BUTTERFLY, - aSOI_INSECT_TYPE_TIGER_BUTTERFLY, - aSOI_INSECT_TYPE_PURPLE_BUTTERFLY, - aSOI_INSECT_TYPE_ROBUST_CICADA, - aSOI_INSECT_TYPE_WALKER_CICADA, - aSOI_INSECT_TYPE_EVENING_CICADA, - aSOI_INSECT_TYPE_BROWN_CICADA, - aSOI_INSECT_TYPE_BEE, - aSOI_INSECT_TYPE_COMMON_DRAGONFLY, - aSOI_INSECT_TYPE_RED_DRAGONFLY, - aSOI_INSECT_TYPE_DARNER_DRAGONFLY, - aSOI_INSECT_TYPE_BANDED_DRAGONFLY, - aSOI_INSECT_TYPE_LONG_LOCUST, - aSOI_INSECT_TYPE_MIGRATORY_LOCUST, - aSOI_INSECT_TYPE_CRICKET, - aSOI_INSECT_TYPE_GRASSHOPPER, - aSOI_INSECT_TYPE_BELL_CRICKET, - aSOI_INSECT_TYPE_PINE_CRICKET, - aSOI_INSECT_TYPE_DRONE_BEETLE, - aSOI_INSECT_TYPE_DYNASTID_BEETLE, - aSOI_INSECT_TYPE_FLAT_STAG_BEETLE, - aSOI_INSECT_TYPE_JEWEL_BEETLE, - aSOI_INSECT_TYPE_LONGHORN_BEETLE, - aSOI_INSECT_TYPE_LADYBUG, - aSOI_INSECT_TYPE_SPOTTED_LADYBUG, - aSOI_INSECT_TYPE_MANTIS, - aSOI_INSECT_TYPE_FIREFLY, - aSOI_INSECT_TYPE_COCKROACH, - aSOI_INSECT_TYPE_SAW_STAG_BEETLE, - aSOI_INSECT_TYPE_MOUNTAIN_BEETLE, - aSOI_INSECT_TYPE_GIANT_BEETLE, - aSOI_INSECT_TYPE_SNAIL, - aSOI_INSECT_TYPE_MOLE_CRICKET, - aSOI_INSECT_TYPE_POND_SKATER, - aSOI_INSECT_TYPE_BAGWORM, - aSOI_INSECT_TYPE_PILL_BUG, - aSOI_INSECT_TYPE_SPIDER, - aSOI_INSECT_TYPE_ANT, - aSOI_INSECT_TYPE_MOSQUITO, - aSOI_INSECT_TYPE_NUM, + aSOI_INSECT_TYPE_COMMON_BUTTERFLY, + aSOI_INSECT_TYPE_YELLOW_BUTTERFLY, + aSOI_INSECT_TYPE_TIGER_BUTTERFLY, + aSOI_INSECT_TYPE_PURPLE_BUTTERFLY, + aSOI_INSECT_TYPE_ROBUST_CICADA, + aSOI_INSECT_TYPE_WALKER_CICADA, + aSOI_INSECT_TYPE_EVENING_CICADA, + aSOI_INSECT_TYPE_BROWN_CICADA, + aSOI_INSECT_TYPE_BEE, + aSOI_INSECT_TYPE_COMMON_DRAGONFLY, + aSOI_INSECT_TYPE_RED_DRAGONFLY, + aSOI_INSECT_TYPE_DARNER_DRAGONFLY, + aSOI_INSECT_TYPE_BANDED_DRAGONFLY, + aSOI_INSECT_TYPE_LONG_LOCUST, + aSOI_INSECT_TYPE_MIGRATORY_LOCUST, + aSOI_INSECT_TYPE_CRICKET, + aSOI_INSECT_TYPE_GRASSHOPPER, + aSOI_INSECT_TYPE_BELL_CRICKET, + aSOI_INSECT_TYPE_PINE_CRICKET, + aSOI_INSECT_TYPE_DRONE_BEETLE, + aSOI_INSECT_TYPE_DYNASTID_BEETLE, + aSOI_INSECT_TYPE_FLAT_STAG_BEETLE, + aSOI_INSECT_TYPE_JEWEL_BEETLE, + aSOI_INSECT_TYPE_LONGHORN_BEETLE, + aSOI_INSECT_TYPE_LADYBUG, + aSOI_INSECT_TYPE_SPOTTED_LADYBUG, + aSOI_INSECT_TYPE_MANTIS, + aSOI_INSECT_TYPE_FIREFLY, + aSOI_INSECT_TYPE_COCKROACH, + aSOI_INSECT_TYPE_SAW_STAG_BEETLE, + aSOI_INSECT_TYPE_MOUNTAIN_BEETLE, + aSOI_INSECT_TYPE_GIANT_BEETLE, + aSOI_INSECT_TYPE_SNAIL, + aSOI_INSECT_TYPE_MOLE_CRICKET, + aSOI_INSECT_TYPE_POND_SKATER, + aSOI_INSECT_TYPE_BAGWORM, + aSOI_INSECT_TYPE_PILL_BUG, + aSOI_INSECT_TYPE_SPIDER, + aSOI_INSECT_TYPE_ANT, + aSOI_INSECT_TYPE_MOSQUITO, + aSOI_INSECT_TYPE_NUM, - aSOI_INSECT_TYPE_SPIRIT = aSOI_INSECT_TYPE_NUM, - aSOI_INSECT_TYPE_NONE, - aSOI_INSECT_TYPE_EXTENDED_NUM + aSOI_INSECT_TYPE_SPIRIT = aSOI_INSECT_TYPE_NUM, + aSOI_INSECT_TYPE_NONE, + aSOI_INSECT_TYPE_EXTENDED_NUM }; #define aSOI_SPAWN_AREA_INVALID -1 enum insect_spawn_area { - aSOI_SPAWN_AREA_ON_TREE, - aSOI_SPAWN_AREA_ON_FLOWER, - aSOI_SPAWN_AREA_RAINING_ON_FLOWER, - aSOI_SPAWN_AREA_FLYING, - aSOI_SPAWN_AREA_ON_GROUND, - aSOI_SPAWN_AREA_IN_BUSH, - aSOI_SPAWN_AREA_FLYING_NEAR_WATER, - aSOI_SPAWN_AREA_ON_WATER, - aSOI_SPAWN_AREA_ON_CANDY, - aSOI_SPAWN_AREA_ON_TRASH, - aSOI_SPAWN_AREA_UNDER_ROCK, - aSOI_SPAWN_AREA_UNDERGROUND, - aSOI_SPAWN_AREA_FLYING_NEAR_FLOWERS_OR_AROUND, /* this prefers flowers, but will default to "FLYING" if no flowers are in the acre */ - aSOI_SPAWN_AREA_NOTHING, + aSOI_SPAWN_AREA_ON_TREE, + aSOI_SPAWN_AREA_ON_FLOWER, + aSOI_SPAWN_AREA_RAINING_ON_FLOWER, + aSOI_SPAWN_AREA_FLYING, + aSOI_SPAWN_AREA_ON_GROUND, + aSOI_SPAWN_AREA_IN_BUSH, + aSOI_SPAWN_AREA_FLYING_NEAR_WATER, + aSOI_SPAWN_AREA_ON_WATER, + aSOI_SPAWN_AREA_ON_CANDY, + aSOI_SPAWN_AREA_ON_TRASH, + aSOI_SPAWN_AREA_UNDER_ROCK, + aSOI_SPAWN_AREA_UNDERGROUND, + aSOI_SPAWN_AREA_FLYING_NEAR_FLOWERS_OR_AROUND, /* this prefers flowers, but will default to "FLYING" if no flowers + are in the acre */ + aSOI_SPAWN_AREA_NOTHING, - aSOI_SPAWN_AREA_NUM + aSOI_SPAWN_AREA_NUM }; enum insect_spawn_type { - aSOI_SPAWN_TYPE_NONE, /* none/unused? */ - aSOI_SPAWN_TYPE_TOWN, /* pull from town spawns */ - aSOI_SPAWN_TYPE_ISLAND, /* pull from island spawns */ - aSOI_SPAWN_TYPE_SPIRIT, /* pull from town spawns but force spirit if Wisp is active */ + aSOI_SPAWN_TYPE_NONE, /* none/unused? */ + aSOI_SPAWN_TYPE_TOWN, /* pull from town spawns */ + aSOI_SPAWN_TYPE_ISLAND, /* pull from island spawns */ + aSOI_SPAWN_TYPE_SPIRIT, /* pull from town spawns but force spirit if Wisp is active */ - aSOI_SPAWN_TYPE_NUM + aSOI_SPAWN_TYPE_NUM }; enum insect_spawn_category { - aSOI_SPAWN_CATEGORY_FG_ITEM_RANGE, - aSOI_SPAWN_CATEGORY_UT_ATTRIBUTE, - aSOI_SPAWN_CATEGORY_TREE, - aSOI_SPAWN_CATEGORY_UT_ATTRIBUTE_AND_FG_ITEM_RANGE, + aSOI_SPAWN_CATEGORY_FG_ITEM_RANGE, + aSOI_SPAWN_CATEGORY_UT_ATTRIBUTE, + aSOI_SPAWN_CATEGORY_TREE, + aSOI_SPAWN_CATEGORY_UT_ATTRIBUTE_AND_FG_ITEM_RANGE, - aSOI_SPAWN_CATEGORY_NUM + aSOI_SPAWN_CATEGORY_NUM }; +#define aSOI_SPAWN_NORMAL 0 +#define aSOI_SPAWN_TREE 4 +#define aSOI_SPAWN_ITEM 6 + /** * Insect term periods: * TERM0: 11PM-4AM (5 hours) @@ -109,28 +114,28 @@ enum insect_spawn_category { * TERM5: 7PM-11PM (4 hours) **/ -#define aSOI_TERM0_START_HR 11+12 // 11:00PM -#define aSOI_TERM0_END_HR 3 // 03:59AM -#define aSOI_TERM1_START_HR 4 // 04:00AM -#define aSOI_TERM1_END_HR 7 // 07:59AM -#define aSOI_TERM2_START_HR 8 // 08:00AM -#define aSOI_TERM2_END_HR 3+12 // 03:59PM -#define aSOI_TERM3_START_HR 4+12 // 04:00PM -#define aSOI_TERM3_END_HR 4+12 // 04:59PM -#define aSOI_TERM4_START_HR 5+12 // 05:00PM -#define aSOI_TERM4_END_HR 6+12 // 06:59PM -#define aSOI_TERM5_START_HR 7+12 // 07:00PM -#define aSOI_TERM5_END_HR 10+12 // 10:59PM +#define aSOI_TERM0_START_HR 11 + 12 // 11:00PM +#define aSOI_TERM0_END_HR 3 // 03:59AM +#define aSOI_TERM1_START_HR 4 // 04:00AM +#define aSOI_TERM1_END_HR 7 // 07:59AM +#define aSOI_TERM2_START_HR 8 // 08:00AM +#define aSOI_TERM2_END_HR 3 + 12 // 03:59PM +#define aSOI_TERM3_START_HR 4 + 12 // 04:00PM +#define aSOI_TERM3_END_HR 4 + 12 // 04:59PM +#define aSOI_TERM4_START_HR 5 + 12 // 05:00PM +#define aSOI_TERM4_END_HR 6 + 12 // 06:59PM +#define aSOI_TERM5_START_HR 7 + 12 // 07:00PM +#define aSOI_TERM5_END_HR 10 + 12 // 10:59PM enum insect_term { - aSOI_TERM0, - aSOI_TERM1, - aSOI_TERM2, - aSOI_TERM3, - aSOI_TERM4, - aSOI_TERM5, + aSOI_TERM0, + aSOI_TERM1, + aSOI_TERM2, + aSOI_TERM3, + aSOI_TERM4, + aSOI_TERM5, - aSOI_TERM_NUM + aSOI_TERM_NUM }; extern int aSOI_insect_set(SET_MANAGER* set_manager, GAME_PLAY* play); diff --git a/include/audio_defs.h b/include/audio_defs.h index 5fe0bfec..332b6aa8 100644 --- a/include/audio_defs.h +++ b/include/audio_defs.h @@ -36,6 +36,7 @@ typedef enum audio_sound_effects { NA_SE_LIGHT_OFF, NA_SE_25 = 0x25, + NA_SE_26 = 0x26, NA_SE_DRAWER_SHUT = 0x3A, @@ -70,6 +71,8 @@ typedef enum audio_sound_effects { NA_SE_STONECOIN_ROLL = 0x7D, NA_SE_STONECOIN_DRAG = 0x7E, + NA_SE_A8 = 0xA8, + NA_SE_CF = 0xCF, NA_SE_ROD_STROKE = 0x109, diff --git a/src/ac_ins_goki.c b/src/ac_ins_goki.c new file mode 100644 index 00000000..1857804c --- /dev/null +++ b/src/ac_ins_goki.c @@ -0,0 +1,474 @@ +#include "ac_ins_goki.h" + +#include "m_field_info.h" +#include "m_name_table.h" +#include "m_common_data.h" +#include "m_player_lib.h" +#include "ac_set_ovl_insect.h" + +enum { + aIGK_INIT_TREE, + aIGK_INIT_CEDAR, + + aIGK_INIT_NUM +}; + +enum { + aIGK_ACTION_AVOID, + aIGK_ACTION_LET_ESCAPE, + aIGK_ACTION_WAIT_ON_FLOWER, + aIGK_ACTION_MOVE_ON_FLOWER, + aIGK_ACTION_WAIT_ON_TREE, + aIGK_ACTION_MOVE_ON_TREE, + aIGK_ACTION_WAIT_ON_ITEM, + aIGK_ACTION_MOVE_ON_ITEM, + + aIGK_ACTION_NUM +}; + +#define aIGK_PLACE_TREE 4 +#define aIGK_PLACE_FLOWER 5 +#define aIGK_PLACE_ITEM 6 + +#define aIGK_BALL_SCARE_DIST (60.0f) +#define aIGK_NET_SCARE_DIST (70.0f) +#define aIGK_SCOOP_SCARE_DIST (30.0f) +#define aIGK_VIB_SCARE_DIST (150.0f) +#define aIGK_MAX_PATIENCE (90.0f) /* Patience threshold for scaring away */ + +#define aIGK_RANDOM_ANGLE() ((int)((fqrand() - 0.5f) * 2 * (f32)DEG2SHORT_ANGLE2(90.0f))) +#define aIGK_RANDOM_ANGLE2() ((s16)((fqrand() - 0.5f) * (f32)DEG2SHORT_ANGLE2(120.0f))) + +#define aIGK_TARGET_ANGLE(insect) ((insect)->s32_work0) +#define aIGK_CHANGE_WAIT_TIMER(insect) ((insect)->s32_work1) +#define aIGK_MOVE_TIMER(insect) ((insect)->s32_work2) +#define aIGK_GET_ITEM_P(insect) ((insect)->s32_work3) +#define aIGK_SET_ITEM_P(insect, item_p) ((insect)->s32_work3 = (int)item_p) + +static void aIGK_actor_move(ACTOR* actorx, GAME* game); +static void aIGK_setupAction(aINS_INSECT_ACTOR* insect, int action, GAME* game); + +extern void aIGK_actor_init(ACTOR* actorx, GAME* game) { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; + int act; + + insect->item = ITM_INSECT28; + actorx->mv_proc = &aIGK_actor_move; + insect->bg_range = 6.0f; + + switch (actorx->actor_specific) { + case aSOI_SPAWN_NORMAL: { + /* Spawn on flower */ + insect->bg_type = 2; + actorx->world.position.y = 6.0f + mCoBG_GetBgY_OnlyCenter_FromWpos(actorx->world.position, -19.0f); + xyz_t_move(&actorx->home.position, &actorx->world.position); + actorx->shape_info.draw_shadow = FALSE; + insect->flag = aIGK_PLACE_FLOWER; + actorx->actor_specific = 0; + act = aIGK_ACTION_WAIT_ON_FLOWER; + break; + } + case aSOI_SPAWN_TREE: { + /* Spawn insect on tree */ + static f32 init_posY[aIGK_INIT_NUM] = { 35.0f, 30.0f }; + static f32 init_posZ[aIGK_INIT_NUM] = { -2.0f, 8.0f }; + mActor_name_t* fg_p = mFI_GetUnitFG(actorx->world.position); + int type; + + if (fg_p != NULL && *fg_p == CEDAR_TREE) { + type = aIGK_INIT_CEDAR; + } else { + type = aIGK_INIT_TREE; + } + + actorx->world.position.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(actorx->world.position, -init_posY[type]); + actorx->world.position.z += init_posZ[type]; + xyz_t_move(&actorx->home.position, &actorx->world.position); + actorx->shape_info.draw_shadow = FALSE; + insect->flag = aIGK_PLACE_TREE; + actorx->actor_specific = 0; + actorx->shape_info.rotation.y = DEG2SHORT_ANGLE2(-180.0f); + actorx->shape_info.rotation.x = DEG2SHORT_ANGLE2(90.0f); + act = aIGK_ACTION_WAIT_ON_TREE; + break; + } + case aSOI_SPAWN_ITEM: { + /* Spawn insect on ground item */ + actorx->world.position.y = 5.0f + mCoBG_GetBgY_OnlyCenter_FromWpos2(actorx->world.position, -2.0f); + xyz_t_move(&actorx->home.position, &actorx->world.position); + actorx->shape_info.draw_shadow = FALSE; + insect->flag = aIGK_PLACE_ITEM; + actorx->actor_specific = 0; + + aIGK_SET_ITEM_P(insect, mFI_GetUnitFG(actorx->world.position)); + if (aIGK_GET_ITEM_P(insect) == 0) { + Actor_delete(actorx); + return; + } + + actorx->shape_info.rotation.y = DEG2SHORT_ANGLE2(-180.0f); + actorx->shape_info.rotation.x = DEG2SHORT_ANGLE2(45.0f); + act = aIGK_ACTION_WAIT_ON_ITEM; + break; + } + default: { + act = aIGK_ACTION_LET_ESCAPE; + break; + } + } + + aIGK_setupAction(insect, act, game); +} + +static void aIGK_anime_proc(aINS_INSECT_ACTOR* insect) { + insect->_1E0 += 0.5f; + if (insect->_1E0 >= 2.0f) { + insect->_1E0 -= 2.0f; + } +} + +static int aIGK_check_tree_shaken(aINS_INSECT_ACTOR* insect) { + int res = FALSE; + + if (insect->flag == aIGK_PLACE_TREE) { + if (mPlib_Check_tree_shaken(&insect->tools_actor.actor_class.world.position) == TRUE) { + res = TRUE; + } else if (mPlib_Check_VibUnit_OneFrame(&insect->tools_actor.actor_class.world.position) == TRUE && + insect->tools_actor.actor_class.player_distance_xz < aIGK_VIB_SCARE_DIST) { + res = TRUE; + } + } + + return res; +} + +static int aIGK_check_ball(aINS_INSECT_ACTOR* insect) { + f32 dX = Common_Get(ball_pos).x - insect->tools_actor.actor_class.world.position.x; + f32 dZ = Common_Get(ball_pos).z - insect->tools_actor.actor_class.world.position.z; + int res = FALSE; + + if ((SQ(dX) + SQ(dZ)) < SQ(aIGK_BALL_SCARE_DIST)) { + res = TRUE; + } + + return res; +} + +static int aIGK_check_player_net(aINS_INSECT_ACTOR* insect) { + xyz_t net_pos; + int res = FALSE; + + if (mPlib_Check_StopNet(&net_pos) == TRUE) { + u32 label = mPlib_Get_item_net_catch_label(); + + if (label != (u32)insect) { + f32 dX = net_pos.x - insect->tools_actor.actor_class.world.position.x; + f32 dZ = net_pos.z - insect->tools_actor.actor_class.world.position.z; + + if ((SQ(dX) + SQ(dZ)) < SQ(aIGK_NET_SCARE_DIST)) { + res = TRUE; + } + } + } + + return res; +} + +static int aIGK_check_player_scoop(aINS_INSECT_ACTOR* insect) { + xyz_t scoop_pos; + int res = FALSE; + + if (mPlib_Check_DigScoop(&scoop_pos) == TRUE) { + f32 dX = scoop_pos.x - insect->tools_actor.actor_class.world.position.x; + f32 dZ = scoop_pos.z - insect->tools_actor.actor_class.world.position.z; + + if ((SQ(dX) + SQ(dZ)) < SQ(aIGK_SCOOP_SCARE_DIST)) { + res = TRUE; + } + } + + return res; +} + +static int aIGK_check_patience(aINS_INSECT_ACTOR* insect) { + int res = FALSE; + + /* Check that no action which would scare the insect away has occurred */ + if (aIGK_check_tree_shaken(insect) == TRUE) { + insect->patience = 100.0f; + } else if (aIGK_check_ball(insect) == TRUE) { + insect->patience = 100.0f; + } else if (aIGK_check_player_net(insect) == TRUE) { + insect->patience = 100.0f; + } else if (aIGK_check_player_scoop(insect) == TRUE) { + insect->patience = 100.0f; + } else if (insect->flag == aIGK_PLACE_ITEM && *(mActor_name_t*)aIGK_GET_ITEM_P(insect) != ITM_KABU_SPOILED) { + insect->patience = 100.0f; + } + + if (insect->patience >= aIGK_MAX_PATIENCE) { + res = TRUE; + } + + return res; +} + +static void aIGK_avoid(ACTOR* actorx, GAME* game) { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; + f32 grav; + + grav = actorx->gravity; + grav *= 1.1f; + if (grav > 12.0f) { + grav = 12.0f; + } + + actorx->gravity = grav; + sAdo_OngenPos((u32)actorx, NA_SE_26, &actorx->world.position); + aIGK_anime_proc(insect); + + if (insect->bg_type == 0) { + int h_ut_x; + int h_ut_z; + int now_ut_x; + int now_ut_z; + + mFI_Wpos2UtNum(&h_ut_x, &h_ut_z, actorx->home.position); + mFI_Wpos2UtNum(&now_ut_x, &now_ut_z, actorx->world.position); + + if (h_ut_x != now_ut_x || h_ut_z != now_ut_z) { + insect->bg_type = 1; + } + } +} + +static void aIGK_wait_on_flower(ACTOR* actorx, GAME* game) { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; + + if (aIGK_check_patience(insect) == TRUE) { + aIGK_setupAction(insect, aIGK_ACTION_AVOID, game); + } else { + insect->timer--; + + if (insect->timer <= 0) { + aIGK_setupAction(insect, aIGK_ACTION_MOVE_ON_FLOWER, game); + } else { + chase_angle(&actorx->world.angle.y, aIGK_TARGET_ANGLE(insect), DEG2SHORT_ANGLE2(8.4375f)); + actorx->shape_info.rotation.y = actorx->world.angle.y; + } + } +} + +static void aIGK_move_on_flower(ACTOR* actorx, GAME* game) { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; + + if (aIGK_check_patience(insect) == TRUE) { + aIGK_setupAction(insect, aIGK_ACTION_AVOID, game); + } else { + aIGK_MOVE_TIMER(insect)--; + + if (aIGK_MOVE_TIMER(insect) <= 0) { + sAdo_OngenPos((u32)actorx, NA_SE_A8, &actorx->world.position); + insect->timer = (int)(2 * (90.0f + RANDOM_F(90.0f))); + aIGK_setupAction(insect, aIGK_ACTION_WAIT_ON_FLOWER, game); + } else { + int flag = 0; + f32 dX = actorx->world.position.x - actorx->home.position.x; + f32 dZ = actorx->world.position.z - actorx->home.position.z; + + if (ABS(dX) >= 15.0f) { + if (dX < 0.0f) { + actorx->world.position.x = actorx->home.position.x - 14.0f; + flag = 1; + } else { + actorx->world.position.x = actorx->home.position.x + 14.0f; + flag = 2; + } + } + + if (ABS(dZ) >= 15.0f) { + if (dZ < 0.0f) { + actorx->world.position.z = actorx->home.position.z - 14.0f; + flag |= 4; + } else { + actorx->world.position.z = actorx->home.position.z + 14.0f; + flag |= 8; + } + } + + if (flag != 0) { + // clang-format off + static int ref_angl[16] = { + DEG2SHORT_ANGLE2(0.0f), DEG2SHORT_ANGLE2(90.0f), DEG2SHORT_ANGLE2(-90.0f), DEG2SHORT_ANGLE2(0.0f), + DEG2SHORT_ANGLE2(0.0f), DEG2SHORT_ANGLE2(45.0f), DEG2SHORT_ANGLE2(-45.0f), DEG2SHORT_ANGLE2(0.0f), + DEG2SHORT_ANGLE2(180.0f), DEG2SHORT_ANGLE2(135.0f), DEG2SHORT_ANGLE2(-135.0f), DEG2SHORT_ANGLE2(180.0f), + DEG2SHORT_ANGLE2(90.0f), DEG2SHORT_ANGLE2(90.0f), DEG2SHORT_ANGLE2(-90.0f), DEG2SHORT_ANGLE2(0.0f), + }; + // clang-format on + + aIGK_TARGET_ANGLE(insect) = ref_angl[flag]; + insect->timer = 10; + aIGK_setupAction(insect, aIGK_ACTION_WAIT_ON_FLOWER, game); + } else { + int done = chase_angle(&actorx->world.angle.y, aIGK_TARGET_ANGLE(insect), DEG2SHORT_ANGLE2(8.4375f)); + + if (done == TRUE) { + aIGK_TARGET_ANGLE(insect) = actorx->world.angle.y + aIGK_RANDOM_ANGLE(); + } + + actorx->shape_info.rotation.y = actorx->world.angle.y; + } + } + } +} + +static void aIGK_wait_on_tree(ACTOR* actorx, GAME* game) { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; + + if (aIGK_check_patience(insect) == TRUE) { + aIGK_setupAction(insect, aIGK_ACTION_AVOID, game); + } else { + insect->timer--; + if (insect->timer <= 0) { + aIGK_setupAction(insect, insect->action + 1, game); + } + } +} + +static void aIGK_move_on_tree(ACTOR* actorx, GAME* game) { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; + + if (aIGK_check_patience(insect) == TRUE) { + aIGK_setupAction(insect, aIGK_ACTION_AVOID, game); + } else { + chase_angle(&actorx->shape_info.rotation.y, aIGK_TARGET_ANGLE(insect), 128); + aIGK_MOVE_TIMER(insect)--; + + if (aIGK_MOVE_TIMER(insect) <= 0) { + aIGK_CHANGE_WAIT_TIMER(insect)--; + if (aIGK_CHANGE_WAIT_TIMER(insect) <= 0) { + aIGK_setupAction(insect, insect->action - 1, game); + } else { + aIGK_TARGET_ANGLE(insect) = -aIGK_TARGET_ANGLE(insect); + aIGK_MOVE_TIMER(insect) = 30; + } + } + } +} + +static void aIGK_avoid_init(aINS_INSECT_ACTOR* insect, GAME* game) { + static f32 base_angl[2] = { DEG2SHORT_ANGLE2(-22.5f), DEG2SHORT_ANGLE2(22.5f) }; + f32 rnd; + s16 angl; + + insect->tools_actor.actor_class.shape_info.draw_shadow = TRUE; + insect->tools_actor.actor_class.speed = 4.0f; + insect->tools_actor.actor_class.max_velocity_y = 12.0f; + insect->tools_actor.actor_class.gravity = 0.06f; + insect->tools_actor.actor_class.shape_info.rotation.x = 0; + insect->tools_actor.actor_class.position_speed.y = 0.0f; + rnd = fqrand(); + insect->life_time = 0; + insect->alpha_time = 80; + angl = (int)(rnd * DEG2SHORT_ANGLE2(90.0f) - (f32)DEG2SHORT_ANGLE2(45.0f) + base_angl[rnd >= 0.5f]); + + insect->tools_actor.actor_class.world.angle.y = angl; + insect->tools_actor.actor_class.shape_info.rotation.y = angl; + insect->insect_flags.bit_1 = TRUE; +} + +static void aIGK_let_escape_init(aINS_INSECT_ACTOR* insect, GAME* game) { + PLAYER_ACTOR* player; + + insect->tools_actor.actor_class.shape_info.draw_shadow = TRUE; + insect->life_time = 0; + insect->alpha_time = 80; + insect->tools_actor.actor_class.speed = 4.0f; + insect->tools_actor.actor_class.max_velocity_y = 12.0f; + insect->tools_actor.actor_class.gravity = 0.06f; + insect->tools_actor.actor_class.shape_info.rotation.x = 0; + insect->tools_actor.actor_class.position_speed.y = 0.0f; + + player = GET_PLAYER_ACTOR_GAME(game); + if (player != NULL) { + s16 angl = player->actor_class.shape_info.rotation.y + aIGK_RANDOM_ANGLE2(); + + insect->tools_actor.actor_class.world.angle.y = angl; + insect->tools_actor.actor_class.shape_info.rotation.y = angl; + } + + insect->insect_flags.bit_1 = TRUE; + insect->insect_flags.bit_2 = TRUE; +} + +static void aIGK_wait_on_flower_init(aINS_INSECT_ACTOR* insect, GAME* game) { + insect->tools_actor.actor_class.speed = 0.0f; + insect->speed_step = 0.0f; + insect->target_speed = 0.0f; +} + +static void aIGK_move_on_flower_init(aINS_INSECT_ACTOR* insect, GAME* game) { + if (aIGK_MOVE_TIMER(insect) == 0) { + aIGK_MOVE_TIMER(insect) = (int)(2 * (90.0f + RANDOM_F(210.0f))); + } + + insect->target_speed = 0.4f; + insect->speed_step = 0.1f; +} + +static void aIGK_wait_on_tree_init(aINS_INSECT_ACTOR* insect, GAME* game) { + insect->timer = (int)(2 * (10.0f + RANDOM_F(10.0f))); +} + +static void aIGK_move_on_tree_init(aINS_INSECT_ACTOR* insect, GAME* game) { + aIGK_TARGET_ANGLE(insect) = DEG2SHORT_ANGLE2(175.78125f); + aIGK_CHANGE_WAIT_TIMER(insect) = 3 + RANDOM(2); + aIGK_MOVE_TIMER(insect) = 30; +} + +typedef void (*aIGK_INIT_PROC)(aINS_INSECT_ACTOR* insect, GAME* game); + +static void aIGK_setupAction(aINS_INSECT_ACTOR* insect, int action, GAME* game) { + // clang-format off + static aIGK_INIT_PROC init_proc[aIGK_ACTION_NUM] = { + &aIGK_avoid_init, + &aIGK_let_escape_init, + &aIGK_wait_on_flower_init, + &aIGK_move_on_flower_init, + &aIGK_wait_on_tree_init, + &aIGK_move_on_tree_init, + &aIGK_wait_on_tree_init, + &aIGK_move_on_tree_init, + }; + // clang-format on + + // clang-format off + static aINS_ACTION_PROC act_proc[aIGK_ACTION_NUM] = { + &aIGK_avoid, + &aIGK_avoid, + &aIGK_wait_on_flower, + &aIGK_move_on_flower, + &aIGK_wait_on_tree, + &aIGK_move_on_tree, + &aIGK_wait_on_tree, + &aIGK_move_on_tree, + }; + // clang-format on + + insect->action = action; + insect->action_proc = act_proc[action]; + (*init_proc[action])(insect, game); +} + +static void aIGK_actor_move(ACTOR* actorx, GAME* game) { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; + u32 label = mPlib_Get_item_net_catch_label(); + + if (label == (u32)actorx) { + aIGK_setupAction(insect, aIGK_ACTION_LET_ESCAPE, game); + } else if (insect->insect_flags.bit_3 == TRUE && insect->insect_flags.bit_2 == FALSE) { + aIGK_setupAction(insect, aIGK_ACTION_LET_ESCAPE, game); + } else { + (*insect->action_proc)(actorx, game); + } +}