From cd0166b3f3d793406068cc0547796a6c04d03790 Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Tue, 30 Apr 2024 15:02:34 -0400 Subject: [PATCH] Implement & link ac_ins_ka --- config/rel_slices.yml | 4 + include/ac_ins_ka.h | 17 +++ include/audio_defs.h | 3 + include/m_player_lib.h | 2 + src/ac_ins_ka.c | 296 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 322 insertions(+) create mode 100644 include/ac_ins_ka.h create mode 100644 src/ac_ins_ka.c diff --git a/config/rel_slices.yml b/config/rel_slices.yml index d28ebe95..f821bf94 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -778,6 +778,10 @@ ac_ins_hitodama.c: .text: [0x8059A8E8, 0x8059B354] .rodata: [0x8064A090, 0x8064A108] .data: [0x806C3460, 0x806C34B0] +ac_ins_ka.c: + .text: [0x8059C174, 0x8059C9EC] + .rodata: [0x8064A1A8, 0x8064A1F0] + .data: [0x806C3550, 0x806C3580] ac_boat.c: .text: [0x805A6CF4, 0x805A856C] .rodata: [0x8064A5B0, 0x8064A630] diff --git a/include/ac_ins_ka.h b/include/ac_ins_ka.h new file mode 100644 index 00000000..c9f6c400 --- /dev/null +++ b/include/ac_ins_ka.h @@ -0,0 +1,17 @@ +#ifndef AC_INS_KA_H +#define AC_INS_KA_H + +#include "types.h" +#include "ac_insect_h.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void aIKA_actor_init(ACTOR* actorx, GAME* game); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/audio_defs.h b/include/audio_defs.h index 500dffd2..5fe0bfec 100644 --- a/include/audio_defs.h +++ b/include/audio_defs.h @@ -59,6 +59,7 @@ typedef enum audio_sound_effects { NA_SE_60 = 0x60, NA_SE_GASAGOSO = 0x69, + NA_SE_6A = 0x6A, NA_SE_TOILE_CHAIR_STANDUP = 0x72, @@ -69,6 +70,8 @@ typedef enum audio_sound_effects { NA_SE_STONECOIN_ROLL = 0x7D, NA_SE_STONECOIN_DRAG = 0x7E, + NA_SE_CF = 0xCF, + NA_SE_ROD_STROKE = 0x109, NA_SE_ROD_BACK, diff --git a/include/m_player_lib.h b/include/m_player_lib.h index d6eeafe8..28214ad9 100644 --- a/include/m_player_lib.h +++ b/include/m_player_lib.h @@ -72,6 +72,8 @@ extern int mPlib_request_main_sitdown_type1(GAME* game, int direct, const xyz_t* extern int mPlib_request_main_lie_bed_type1(GAME* game, int direct, const xyz_t* pos, int head_direct, int ftr_no); extern void mPlib_change_player_cloth(GAME* game, int idx); extern u32 mPlib_Get_item_net_catch_label(void); +extern int mPlib_Check_stung_mosquito(ACTOR* actorx); +extern int mPlib_request_main_stung_mosquito_type1(ACTOR* actorx); extern mPlayer_change_data_from_submenu_c* mPlib_Get_change_data_from_submenu_p(); diff --git a/src/ac_ins_ka.c b/src/ac_ins_ka.c new file mode 100644 index 00000000..f899b9ae --- /dev/null +++ b/src/ac_ins_ka.c @@ -0,0 +1,296 @@ +#include "ac_ins_ka.h" + +#include "m_field_info.h" +#include "m_name_table.h" +#include "m_common_data.h" +#include "m_player_lib.h" + +enum { + aIKA_ACTION_AVOID, + aIKA_ACTION_LET_ESCAPE, + aIKA_ACTION_FLY, + aIKA_ACTION_SEARCH, + aIKA_ACTION_ATTACK_WAIT, + aIKA_ACTION_ATTACK, + + aIKA_ACTION_NUM +}; + +#define aIKA_ATTACK_DIST (mFI_UNIT_BASE_SIZE_F / 2) +#define aIKA_ATTACK_TIME (180) +#define aIKA_IS_DEMO_ACTIVE() (Common_Get(clip).demo_clip != NULL || Common_Get(clip).demo_clip2 != NULL) + +#define aIKA_RANDOM_ANGLE() ((s16)((fqrand() - 0.5f) * (f32)DEG2SHORT_ANGLE2(120.0f))) + +#define aIKA_ANGLE(insect) ((insect)->s32_work0) +#define aIKA_ATTACK_TIMER(insect) ((insect)->s32_work1) +#define aIKA_TURN_SPEED(insect) ((insect)->f32_work0) +#define aIKA_SPEED(insect) ((insect)->f32_work1) + +static void aIKA_setupAction(aINS_INSECT_ACTOR* insect, int action, GAME* game); +static void aIKA_actor_move(ACTOR* actorx, GAME* game); + +extern void aIKA_actor_init(ACTOR* actorx, GAME* game) { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; + int act; + + if (actorx->actor_specific == 0) { + actorx->world.position.y = mCoBG_GetBgY_OnlyCenter_FromWpos(actorx->world.position, 30.0f); + act = aIKA_ACTION_FLY; + } else { + act = aIKA_ACTION_LET_ESCAPE; + } + + insect->bg_range = 6.0f; + insect->bg_height = -14.0f; + insect->bg_type = 1; + insect->item = ITM_INSECT39; + xyz_t_move(&actorx->home.position, &actorx->world.position); + actorx->mv_proc = &aIKA_actor_move; + aIKA_setupAction(insect, act, game); +} + +static void aIKA_fuwafuwa(aINS_INSECT_ACTOR* insect) { + s16 angle = aIKA_ANGLE(insect); + f32 last_spd_angle = aIKA_TURN_SPEED(insect) * sin_s(angle); + f32 now_spd_angle; + + aIKA_ANGLE(insect) = (s16)(angle + 0x180); + if ((s16)(angle + 0x180) < 0 && angle >= 0) { + aIKA_TURN_SPEED(insect) = 10.0f + RANDOM_F(10.0f); + } + + angle += 0x180; + now_spd_angle = aIKA_TURN_SPEED(insect) * sin_s(angle); + chase_f(&aIKA_SPEED(insect), insect->tools_actor.actor_class.max_velocity_y, + insect->tools_actor.actor_class.gravity * 0.5f); + insect->tools_actor.actor_class.position_speed.y = aIKA_SPEED(insect) + (now_spd_angle - last_spd_angle); +} + +static void aIKA_anime_proc(aINS_INSECT_ACTOR* insect) { + insect->_1E0 += 0.2f; + if (insect->_1E0 >= 2.0f) { + insect->_1E0 -= 2.0f; + } +} + +static void aIKA_BGcheck(aINS_INSECT_ACTOR* insect) { + if ((insect->tools_actor.actor_class.bg_collision_check.result.hit_wall & mCoBG_HIT_WALL_FRONT) != 0 || + (insect->tools_actor.actor_class.bg_collision_check.result.hit_attribute_wall & mCoBG_HIT_WALL_FRONT) != 0 || + (insect->tools_actor.actor_class.bg_collision_check.result.on_ground)) { + s16 new_dir = insect->tools_actor.actor_class.world.angle.y + DEG2SHORT_ANGLE2(180.0f); // turn around + insect->tools_actor.actor_class.world.angle.y = new_dir; + insect->tools_actor.actor_class.shape_info.rotation.y = new_dir; + } +} + +static int aIKA_check_condition(aINS_INSECT_ACTOR* insect, GAME_PLAY* play) { + ACTOR* actorx = (ACTOR*)insect; + int res = FALSE; + + if (actorx->block_x == play->block_table.block_x && actorx->block_z == play->block_table.block_z) { + if (ABS(actorx->player_distance_y) < 60.0f) { + res = TRUE; + } + } + + return res; +} + +static void aIKA_calc_angle_search_player(ACTOR* actorx, s16 step) { + s16 angle = actorx->shape_info.rotation.y; + + chase_angle(&angle, actorx->player_angle_y, step); + actorx->shape_info.rotation.y = angle; + actorx->world.angle.y = angle; +} + +static void aIKA_avoid(ACTOR* actorx, GAME* game) { + f32 grav = actorx->gravity; + + grav *= 1.1f; + if (grav > 12.0f) { + grav = 12.0f; + } + + actorx->gravity = grav; +} + +static void aIKA_fly(ACTOR* actorx, GAME* game) { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + PLAYER_ACTOR* player = GET_PLAYER_ACTOR(play); + + aIKA_BGcheck(insect); + + /* Check that no demo is active */ + if (aIKA_IS_DEMO_ACTIVE()) { + /* A demo is active (including chores), so despawn mosquito */ + aIKA_setupAction(insect, aIKA_ACTION_AVOID, game); + } else if (player != NULL && aIKA_check_condition(insect, play) == TRUE) { + aIKA_setupAction(insect, aIKA_ACTION_SEARCH, game); + } else { + s16 angle = actorx->shape_info.rotation.y + 0x80; + + actorx->shape_info.rotation.y = angle; + actorx->world.angle.y = angle; + } +} + +static void aIKA_search(ACTOR* actorx, GAME* game) { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + /* Check that no demo is active */ + if (aIKA_IS_DEMO_ACTIVE()) { + /* A demo is active (including chores), so despawn mosquito */ + aIKA_setupAction(insect, aIKA_ACTION_AVOID, game); + } else if (aIKA_check_condition(insect, play) == FALSE) { + aIKA_setupAction(insect, aIKA_ACTION_FLY, game); + } else if (actorx->player_distance_xz <= aIKA_ATTACK_DIST) { + aIKA_setupAction(insect, aIKA_ACTION_ATTACK_WAIT, game); + } else { + s16 step; + + if (actorx->player_distance_xz <= mFI_UNIT_BASE_SIZE_F) { + step = 0x100; + } else { + step = 0x200; + } + + aIKA_calc_angle_search_player(actorx, step); + } +} + +static void aIKA_attack_wait(ACTOR* actorx, GAME* game) { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + /* Check that no demo is active */ + if (aIKA_IS_DEMO_ACTIVE()) { + /* A demo is active (including chores), so despawn mosquito */ + aIKA_setupAction(insect, aIKA_ACTION_AVOID, game); + } else if (aIKA_check_condition(insect, play) == FALSE) { + aIKA_setupAction(insect, aIKA_ACTION_FLY, game); + } else if (actorx->player_distance_xz > aIKA_ATTACK_DIST) { + aIKA_setupAction(insect, aIKA_ACTION_SEARCH, game); + } else { + aIKA_calc_angle_search_player(actorx, 0x600); + aIKA_ATTACK_TIMER(insect)++; + + if (aIKA_ATTACK_TIMER(insect) > aIKA_ATTACK_TIME) { + if (mPlib_Check_stung_mosquito(actorx)) { + aIKA_setupAction(insect, aIKA_ACTION_ATTACK, game); + } else { + mPlib_request_main_stung_mosquito_type1(actorx); + aIKA_ATTACK_TIMER(insect) = aIKA_ATTACK_TIME; + } + } + } +} + +static void aIKA_attack(ACTOR* actorx, GAME* game) { + if (mPlib_Check_stung_mosquito(actorx) == FALSE) { + aIKA_setupAction((aINS_INSECT_ACTOR*)actorx, aIKA_ACTION_AVOID, game); + } +} + +static void aIKA_avoid_init(aINS_INSECT_ACTOR* insect, GAME* game) { + ACTOR* actorx = (ACTOR*)insect; + GAME_PLAY* play = (GAME_PLAY*)game; + PLAYER_ACTOR* player; + + insect->life_time = 0; + insect->alpha_time = 80; + actorx->gravity = 0.06f; + actorx->max_velocity_y = 12.0f; + actorx->speed = 4.0f; + actorx->shape_info.rotation.x = 0; + aIKA_SPEED(insect) = actorx->position_speed.y; + + player = GET_PLAYER_ACTOR(play); + if (player != NULL) { + s16 rnd_angle = player->actor_class.shape_info.rotation.y + aIKA_RANDOM_ANGLE(); + + actorx->world.angle.y = rnd_angle; + actorx->shape_info.rotation.y = rnd_angle; + } + + insect->insect_flags.bit_1 = TRUE; + insect->insect_flags.bit_2 = TRUE; +} + +static void aIKA_fly_init(aINS_INSECT_ACTOR* insect, GAME* game) { + insect->tools_actor.actor_class.speed = 1.2f; +} + +static void aIKA_attack_wait_init(aINS_INSECT_ACTOR* insect, GAME* game) { + aIKA_ATTACK_TIMER(insect) = 0; +} + +static void aIKA_attack_init(aINS_INSECT_ACTOR* insect, GAME* game) { + insect->tools_actor.actor_class.speed = 0.0f; + insect->target_speed = 0.0f; + insect->speed_step = 0.0f; + insect->tools_actor.actor_class.position_speed.y = 0.0f; + sAdo_OngenTrgStart(NA_SE_6A, &insect->tools_actor.actor_class.world.position); +} + +typedef void (*aIKA_INIT_PROC)(aINS_INSECT_ACTOR*, GAME*); + +static void aIKA_setupAction(aINS_INSECT_ACTOR* insect, int action, GAME* game) { + // clang-format off + static aIKA_INIT_PROC init_proc[] = { + &aIKA_avoid_init, + &aIKA_avoid_init, + &aIKA_fly_init, + (aIKA_INIT_PROC)&none_proc1, + &aIKA_attack_wait_init, + &aIKA_attack_init, + }; + // clang-format on + + // clang-format off + static aINS_ACTION_PROC act_proc[] = { + &aIKA_avoid, + &aIKA_avoid, + &aIKA_fly, + &aIKA_search, + &aIKA_attack_wait, + &aIKA_attack, + }; + // clang-format on + + insect->action = action; + insect->action_proc = act_proc[action]; + (*init_proc[action])(insect, game); +} + +static void aIKA_actor_move(ACTOR* actorx, GAME* game) { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + u32 label; + + if (mPlib_get_player_actor_main_index(game) != mPlayer_INDEX_PUTAWAY_NET && insect->action != aIKA_ACTION_ATTACK) { + aIKA_anime_proc(insect); + aIKA_fuwafuwa(insect); + } else { + insect->_1E0 = 0; + } + + label = mPlib_Get_item_net_catch_label(); + if (label == (u32)actorx) { + aIKA_setupAction(insect, aIKA_ACTION_LET_ESCAPE, game); + } else { + if (insect->action != aIKA_ACTION_ATTACK) { + sAdo_OngenPos((u32)actorx, NA_SE_CF, &actorx->world.position); + } + + if (insect->insect_flags.bit_3 == TRUE && insect->insect_flags.bit_2 == FALSE && + insect->action != aIKA_ACTION_LET_ESCAPE) { + aIKA_setupAction(insect, aIKA_ACTION_LET_ESCAPE, game); + } else { + (*insect->action_proc)(actorx, game); + } + } +}