Implement & link ac_ins_semi

This commit is contained in:
Cuyler36
2025-01-26 17:29:27 -05:00
parent 44227e89a6
commit 8d1a3b99f9
5 changed files with 412 additions and 1 deletions
+1 -1
View File
@@ -1001,7 +1001,7 @@ config.libs = [
Object(Matching, "actor/ac_ins_kabuto.c"),
Object(NonMatching, "actor/ac_ins_kera.c"),
Object(NonMatching, "actor/ac_ins_mino.c"),
Object(NonMatching, "actor/ac_ins_semi.c"),
Object(Matching, "actor/ac_ins_semi.c"),
Object(NonMatching, "actor/ac_ins_tentou.c"),
Object(Matching, "actor/ac_ins_tonbo.c"),
Object(Matching, "actor/ac_insect.c"),
+17
View File
@@ -0,0 +1,17 @@
#ifndef AC_INS_SEMI_H
#define AC_INS_SEMI_H
#include "types.h"
#include "ac_insect_h.h"
#ifdef __cplusplus
extern "C" {
#endif
extern void aISM_actor_init(ACTOR* actorx, GAME* game);
#ifdef __cplusplus
}
#endif
#endif
+7
View File
@@ -124,6 +124,12 @@ typedef enum audio_sound_effects {
NA_SE_TRAIN_RIDE = 0x8D,
NA_SE_SEMI0_CRY = 0x97,
NA_SE_SEMI1_CRY = 0x98,
NA_SE_SEMI2_CRY = 0x9A,
NA_SE_SEMI3_CRY = 0x9B,
NA_SE_GOKI_MOVE = 0xA8,
NA_SE_B0 = 0xB0,
@@ -142,6 +148,7 @@ typedef enum audio_sound_effects {
NA_SE_HANABI3 = HANABI(0x112),
NA_SE_EAT = 0x113,
NA_SE_114 = 0x114,
NA_SE_SEMI_ESCAPE = 0x115,
NA_SE_11B = 0x11B,
NA_SE_WEAR = 0x11C,
+382
View File
@@ -0,0 +1,382 @@
/**
* @file ac_ins_semi.c
* @brief Implements cicada and bee actor behaviors.
*
* This file handles cicadas (semi) and bee actors, including their initialization,
* movement patterns, and reactions to player actions. These insects typically stay
* stationary on trees until disturbed, at which point they escape.
*/
#include "ac_ins_semi.h"
#include "m_name_table.h"
#include "m_common_data.h"
#include "m_player_lib.h"
enum {
aISM_ACT_AVOID,
aISM_ACT_LET_ESCAPE,
aISM_ACT_WAIT,
aISM_ACT_NUM
};
// Cicada variables
#define aISM_CRY_TIMER 60 // Frames between cicada cries
#define aISM_BALL_SCARE_DIST 60.0f // Distance threshold for cicada to be scared by ball
#define aISM_NET_SCARE_DIST 70.0f // Distance threshold for cicada to be scared by net
#define aISM_SCOOP_SCARE_DIST 30.0f // distance threshold for cicada to be scared by scoop
#define aISM_AXE_SCARE_DIST 150.0f // Distance threshold for cicada to be scared by axe
// Cicada-specific work variables
#define aISM_IS_CAUGHT(ins) ((ins)->s32_work0)
static void aISM_actor_move(ACTOR* actorx, GAME* game);
static void aISM_setupAction(aINS_INSECT_ACTOR* insect, int action, GAME* game);
/**
* Initializes a cicada or bee actor.
* Sets up initial position, type-specific properties and starting action.
*
* @param actorx Actor to initialize
* @param game Current game context
*/
extern void aISM_actor_init(ACTOR* actorx, GAME* game) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
int action;
actorx->mv_proc = &aISM_actor_move;
switch (insect->type) {
case aINS_INSECT_TYPE_ROBUST_CICADA:
insect->item = ITM_INSECT04;
break;
case aINS_INSECT_TYPE_WALKER_CICADA:
insect->item = ITM_INSECT05;
break;
case aINS_INSECT_TYPE_EVENING_CICADA:
insect->item = ITM_INSECT06;
break;
case aINS_INSECT_TYPE_BROWN_CICADA:
insect->item = ITM_INSECT07;
break;
case aINS_INSECT_TYPE_BEE: // why is bee here?
insect->item = ITM_INSECT08;
break;
}
if (actorx->actor_specific == 0) {
static f32 init_posY[] = { 35.0f, 30.0f };
static f32 init_posZ[] = { -2.0f, 8.0f };
mActor_name_t* fg_p = mFI_GetUnitFG(actorx->world.position);
int idx;
if (fg_p != NULL && *fg_p == CEDAR_TREE) {
idx = 1;
} else {
idx = 0;
}
actorx->world.position.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(actorx->world.position, -init_posY[idx]);
actorx->world.position.z += init_posZ[idx];
xyz_t_move(&actorx->home.position, &actorx->world.position);
actorx->shape_info.draw_shadow = FALSE;
actorx->shape_info.rotation.x = DEG2SHORT_ANGLE2(90.0f);
action = aISM_ACT_WAIT;
} else {
// cicada was released
if (insect->type != aINS_INSECT_TYPE_BEE) {
sAdo_OngenTrgStart(NA_SE_SEMI_ESCAPE, &actorx->world.position);
}
action = aISM_ACT_LET_ESCAPE;
}
aISM_setupAction(insect, action, game);
}
/**
* Processes animation updates for the insect.
* Updates the animation cycle timer.
*
* @param insect Insect actor to animate
*/
static void aISM_anime_proc(aINS_INSECT_ACTOR* insect) {
insect->_1E0 += 0.5f;
if (insect->_1E0 >= 2.0f) {
insect->_1E0 -= 2.0f;
}
}
/**
* Checks if a ball is near the insect.
*
* @param actorx Actor to check
* @return TRUE if ball is within range
*/
static int aISM_check_ball(ACTOR* actorx) {
int ret = FALSE;
f32 dx = Common_Get(ball_pos).x - actorx->world.position.x;
f32 dz = Common_Get(ball_pos).z - actorx->world.position.z;
if (SQ(dx) + SQ(dz) < SQ(aISM_BALL_SCARE_DIST)) {
ret = TRUE;
}
return ret;
}
/**
* Checks if the player's net is near or hitting the insect.
*
* @param actorx Actor to check
* @return TRUE if net is within range
*/
static int aISM_check_player_net(ACTOR* actorx) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
xyz_t net_pos;
int ret = FALSE;
if (mPlib_Check_StopNet(&net_pos) == TRUE) {
u32 catch_label = mPlib_Get_item_net_catch_label();
if (catch_label == (u32)actorx) {
aISM_IS_CAUGHT(insect) = TRUE;
} else {
f32 dx = net_pos.x - actorx->world.position.x;
f32 dz = net_pos.z - actorx->world.position.z;
if (SQ(dx) + SQ(dz) < SQ(aISM_NET_SCARE_DIST)) {
ret = TRUE;
}
}
}
return ret;
}
/**
* Checks if the player's scoop is near the insect.
*
* @param actorx Actor to check
* @return TRUE if scoop is within range
*/
static int aISM_check_player_scoop(ACTOR* actorx) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
xyz_t scoop_pos;
int ret = FALSE;
if (mPlib_Check_DigScoop(&scoop_pos) == TRUE) {
f32 dx = scoop_pos.x - actorx->world.position.x;
f32 dz = scoop_pos.z - actorx->world.position.z;
if (SQ(dx) + SQ(dz) < SQ(aISM_SCOOP_SCARE_DIST)) {
ret = TRUE;
}
}
return ret;
}
/**
* Checks various conditions that affect the insect's patience.
* Includes tree shaking, vibrations, nearby items, and tools.
*
* @param actorx Actor to check
* @return TRUE if patience threshold exceeded
*/
static int aISM_check_patience(ACTOR* actorx) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
int ret = FALSE;
if (mPlib_Check_tree_shaken(&actorx->world.position) == TRUE) {
insect->patience = 100.0f;
} else if (mPlib_Check_VibUnit_OneFrame(&actorx->world.position) == TRUE && actorx->player_distance_xz < aISM_AXE_SCARE_DIST) {
insect->patience = 100.0f;
} else if (aISM_check_ball(actorx) == TRUE) {
insect->patience = 100.0f;
} else if (aISM_check_player_net(actorx) == TRUE) {
insect->patience = 100.0f;
} else if (aISM_check_player_scoop(actorx) == TRUE) {
insect->patience = 100.0f;
}
if (insect->patience > 90.0f) {
ret = TRUE;
}
return ret;
}
/**
* Avoidance behavior when insect is disturbed.
* Handles escape movement and sounds.
*
* @param actorx Actor performing avoidance
* @param game Current game context
*/
static void aISM_avoid(ACTOR* actorx, GAME* game) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
f32 gravity;
aISM_anime_proc(insect);
gravity = actorx->gravity;
gravity *= 1.1f;
if (gravity > 12.0f) {
gravity = 12.0f;
}
actorx->gravity = gravity;
if (insect->bg_type == aINS_BG_CHECK_TYPE_NONE) {
int home_ux;
int home_uz;
int cur_ux;
int cur_uz;
mFI_Wpos2UtNum(&home_ux, &home_uz, actorx->home.position);
mFI_Wpos2UtNum(&cur_ux, &cur_uz, actorx->world.position);
if (home_ux != cur_ux || home_uz != cur_uz) {
insect->bg_type = aINS_BG_CHECK_TYPE_REG_NO_ATTR;
}
}
if (insect->type == aINS_INSECT_TYPE_BEE) {
sAdo_OngenPos((u32)actorx, NA_SE_26, &actorx->world.position);
}
}
/**
* Waiting behavior for stationary insect.
* Handles sound effects and checks for disturbances.
*
* @param actorx Actor in waiting state
* @param game Current game context
*/
static void aISM_wait(ACTOR* actorx, GAME* game) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
if (aISM_check_patience(actorx) == TRUE) {
if (insect->type != aINS_INSECT_TYPE_BEE) {
sAdo_OngenTrgStart(NA_SE_SEMI_ESCAPE, &actorx->world.position);
}
aISM_setupAction(insect, aISM_ACT_AVOID, game);
} else {
if (insect->type != aINS_INSECT_TYPE_BEE && aISM_IS_CAUGHT(insect) == FALSE) {
if (insect->patience < 50.0f) {
insect->timer--;
if (Common_Get(weather) != mEnv_WEATHER_RAIN && insect->timer < 0) {
static u8 semi_sound_data[] = { NA_SE_SEMI3_CRY, NA_SE_SEMI2_CRY, NA_SE_SEMI1_CRY, NA_SE_SEMI0_CRY };
int semi_idx = insect->type - aINS_INSECT_TYPE_ROBUST_CICADA;
insect->timer = 0;
sAdo_OngenPos((u32)actorx, semi_sound_data[semi_idx], &actorx->world.position);
actorx->world.position.x = actorx->home.position.x + RANDOM_F(0.4f);
}
} else {
insect->timer = aISM_CRY_TIMER;
}
}
}
}
/**
* Initializes avoidance behavior parameters.
*
* @param insect Insect to initialize
* @param game Current game context
*/
static void aISM_avoid_init(aINS_INSECT_ACTOR* insect, GAME* game) {
static f32 base_angl[] = { -DEG2SHORT_ANGLE2(22.5f), DEG2SHORT_ANGLE2(22.5f) };
f32 rand = fqrand();
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;
if (insect->action == aISM_ACT_AVOID) {
insect->tools_actor.actor_class.shape_info.rotation.y = (rand * DEG2SHORT_ANGLE2(90.0f) - DEG2SHORT_ANGLE2(45.0f)) + base_angl[rand >= 0.5f];
insect->tools_actor.actor_class.world.angle.y = insect->tools_actor.actor_class.shape_info.rotation.y;
} else {
ACTOR* playerx = GET_PLAYER_ACTOR_GAME_ACTOR(game);
if (playerx != NULL) {
insect->tools_actor.actor_class.shape_info.rotation.y = insect->tools_actor.actor_class.world.angle.y = playerx->shape_info.rotation.y + (s16)RANDOM_CENTER_F(DEG2SHORT_ANGLE2(120.0f));
}
}
insect->insect_flags.bit_1 = TRUE;
insect->tools_actor.actor_class.shape_info.draw_shadow = TRUE;
}
/**
* Initializes escape behavior parameters.
*
* @param insect Insect to initialize
* @param game Current game context
*/
static void aISM_let_escape_init(aINS_INSECT_ACTOR* insect, GAME* game) {
aISM_avoid_init(insect, game);
insect->insect_flags.bit_2 = TRUE;
}
/**
* Initializes waiting behavior parameters.
*
* @param insect Insect to initialize
* @param game Current game context
*/
static void aISM_wait_init(aINS_INSECT_ACTOR* insect, GAME* game) {
insect->tools_actor.actor_class.shape_info.rotation.y = DEG2SHORT_ANGLE2(180.0f);
}
typedef void (*aISM_INIT_PROC)(aINS_INSECT_ACTOR* insect, GAME* game);
/**
* Sets up a new action state for the insect.
*
* @param insect Insect to update
* @param action New action to perform
* @param game Current game context
*/
static void aISM_setupAction(aINS_INSECT_ACTOR* insect, int action, GAME* game) {
static aISM_INIT_PROC init_proc[] = {
aISM_avoid_init,
aISM_let_escape_init,
aISM_wait_init,
};
static aINS_ACTION_PROC act_proc[] = {
aISM_avoid,
aISM_avoid,
aISM_wait,
};
insect->action = action;
insect->action_proc = act_proc[action];
init_proc[action](insect, game);
}
/**
* Main movement update function for cicada/bee actors.
* Handles state changes and updates current behavior.
*
* @param actorx Actor to update
* @param game Current game context
*/
static void aISM_actor_move(ACTOR* actorx, GAME* game) {
aINS_INSECT_ACTOR* ins = (aINS_INSECT_ACTOR*)actorx;
u32 catch_label = (u32)mPlib_Get_item_net_catch_label();
if (catch_label == (u32)ins) {
aISM_setupAction(ins, aISM_ACT_LET_ESCAPE, game);
} else if (ins->insect_flags.bit_3 == TRUE && ins->insect_flags.bit_2 == FALSE) {
aISM_setupAction(ins, aISM_ACT_LET_ESCAPE, game);
} else {
ins->action_proc(actorx, game);
}
}
+5
View File
@@ -2731,6 +2731,11 @@ extern int mPlib_Check_HitAxe(xyz_t* pos_p) {
return GET_PLAYER_ACTOR_NOW()->Check_HitAxe_proc(GET_PLAYER_ACTOR_NOW_ACTOR(), pos_p);
}
/**
* @brief Checks if the player hit something with their axe in the same block
* @param pos_p Position to check
* @return TRUE if the player hit something with their axe in the same block, FALSE otherwise
*/
extern int mPlib_Check_VibUnit_OneFrame(const xyz_t* pos_p) {
return GET_PLAYER_ACTOR_NOW()->Check_VibUnit_OneFrame_proc(GET_PLAYER_ACTOR_NOW_ACTOR(), pos_p);
}