mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-05-23 06:34:18 -04:00
Implement & link ac_ins_semi
This commit is contained in:
+1
-1
@@ -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"),
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user