Implement & link ac_ins_tentou

This commit is contained in:
Cuyler36
2025-01-28 02:52:13 -05:00
parent c09ba92ea3
commit f22b553428
4 changed files with 544 additions and 2 deletions
+17
View File
@@ -0,0 +1,17 @@
#ifndef AC_INS_TENTOU_H
#define AC_INS_TENTOU_H
#include "types.h"
#include "ac_insect_h.h"
#ifdef __cplusplus
extern "C" {
#endif
extern void aITT_actor_init(ACTOR* actorx, GAME* game);
#ifdef __cplusplus
}
#endif
#endif
+7
View File
@@ -69,6 +69,13 @@ enum {
aINS_MAKE_NUM
};
enum {
aINS_INIT_NORMAL,
aINS_INIT_RELEASE,
aINS_INIT_NUM
};
enum {
aINS_PROGRAM_CHOU,
aINS_PROGRAM_BATTA,
+518
View File
@@ -0,0 +1,518 @@
/**
* @file ac_ins_tentou.c
* @brief Implements flower-based insect behaviors.
*
* Handles ladybugs, spotted ladybugs, mantises, and snails which are insects
* found on flowers. These insects will move on flowers and escape when
* disturbed by the player.
*/
#include "ac_ins_tentou.h"
#include "m_name_table.h"
#include "m_common_data.h"
#include "m_player_lib.h"
enum {
aITT_ACT_AVOID,
aITT_ACT_AVOID_MAIMAI,
aITT_ACT_LET_ESCAPE,
aITT_ACT_LET_ESCAPE_MAIMAI,
aITT_ACT_MOVE,
aITT_ACT_WAIT,
aITT_ACT_NUM
};
// Flower insect specific variables
#define aITT_BALL_SCARE_DIST 60.0f // Distance threshold to be scared by ball
#define aITT_NET_SCARE_DIST 70.0f // Distance threshold to be scared by net
#define aITT_SCOOP_SCARE_DIST 60.0f // Distance threshold to be scared by scoop
// Actor-specific work variable getters
#define aITT_TARGET_ANGLE(ins) ((ins)->s32_work1)
#define aITT_TURN_DELAY(ins) ((ins)->s32_work2)
static void aITT_actor_move(ACTOR* actorx, GAME* game);
static void aITT_setupAction(aINS_INSECT_ACTOR* insect, int action, GAME* game);
/**
* Initializes a flower-based insect actor.
* Sets initial position and type-specific properties.
*
* @param actorx Actor to initialize
* @param game Current game context
*/
extern void aITT_actor_init(ACTOR* actorx, GAME* game) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
int action;
actorx->mv_proc = aITT_actor_move;
insect->bg_type = aINS_BG_CHECK_TYPE_REG_NO_ATTR;
switch (insect->type) {
case aINS_INSECT_TYPE_LADYBUG:
insect->item = ITM_INSECT24;
break;
case aINS_INSECT_TYPE_SPOTTED_LADYBUG:
insect->item = ITM_INSECT25;
break;
case aINS_INSECT_TYPE_MANTIS:
insect->item = ITM_INSECT26;
break;
case aINS_INSECT_TYPE_SNAIL:
insect->item = ITM_INSECT32;
break;
}
if (actorx->actor_specific == aINS_INIT_NORMAL) {
actorx->world.position.y = 6.0f + mCoBG_GetBgY_OnlyCenter_FromWpos(actorx->world.position, -19.0f);
actorx->shape_info.draw_shadow = FALSE;
xyz_t_move(&actorx->home.position, &actorx->world.position);
action = aITT_ACT_WAIT;
} else {
// aINS_INIT_RELEASE
switch (insect->type) {
case aINS_INSECT_TYPE_SNAIL:
actorx->world.position.y = mCoBG_GetBgY_OnlyCenter_FromWpos(actorx->world.position, 0.0f);
actorx->home.position.y = actorx->world.position.y;
action = aITT_ACT_LET_ESCAPE_MAIMAI;
break;
default:
action = aITT_ACT_LET_ESCAPE;
break;
}
}
aITT_setupAction(insect, action, game);
}
/**
* Updates the insect's animation cycle.
*
* @param insect Insect actor to animate
*/
static void aITT_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 enough to scare the insect.
*
* @param actorx Actor to check
* @return TRUE if ball is within scare range
*/
static int aITT_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(aITT_BALL_SCARE_DIST)) {
ret = TRUE;
}
return ret;
}
/**
* Checks if player's net is near enough to scare the insect.
*
* @param actorx Actor to check
* @return TRUE if net is within scare range
*/
static int aITT_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) {
f32 dx = net_pos.x - actorx->world.position.x;
f32 dz = net_pos.z - actorx->world.position.z;
if (SQ(dx) + SQ(dz) < SQ(aITT_NET_SCARE_DIST)) {
ret = TRUE;
}
}
}
return ret;
}
/**
* Checks if player's scoop is near enough to scare the insect.
*
* @param actorx Actor to check
* @return TRUE if scoop is within scare range
*/
static int aITT_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(aITT_SCOOP_SCARE_DIST)) {
ret = TRUE;
}
}
return ret;
}
/**
* Checks if the insect is on a flower.
*
* @param actorx Actor to check
* @return TRUE if on a flower, FALSE otherwise
*/
static int aITT_check_flower(ACTOR* actorx) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
mActor_name_t* fg_p = mFI_GetUnitFG(actorx->world.position);
int ret = TRUE;
if (fg_p != NULL && !IS_ITEM_FLOWER(*fg_p)) {
ret = FALSE;
}
return ret;
}
/**
* Checks various conditions that might scare the insect.
*
* @param actorx Actor to check
* @param game Current game context
* @return TRUE if insect should be scared
*/
static int aITT_check_patience(ACTOR* actorx, GAME* game) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
int ret = FALSE;
switch (insect->type) {
case aINS_INSECT_TYPE_SNAIL:
if (aITT_check_flower(actorx) == FALSE) {
aITT_setupAction(insect, aITT_ACT_AVOID_MAIMAI, game);
insect->target_speed = 0.1f;
insect->speed_step = 0.025f;
ret = TRUE;
}
break;
default:
if (aITT_check_ball(actorx) == TRUE) {
insect->patience = 100.0f;
} else if (aITT_check_player_net(actorx) == TRUE) {
insect->patience = 100.0f;
} else if (aITT_check_player_scoop(actorx) == TRUE) {
insect->patience = 100.0f;
}
if (insect->patience > 90.0f) {
aITT_setupAction(insect, aITT_ACT_AVOID, game);
ret = TRUE;
}
break;
}
return ret;
}
/**
* Calculates new direction angles when colliding with walls.
*
* @param actorx Actor to update
*/
static void aITT_calc_direction_angl(ACTOR* actorx) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
if (actorx->bg_collision_check.result.hit_wall & mCoBG_HIT_WALL_FRONT) {
int count = actorx->bg_collision_check.result.hit_wall_count;
int i;
if (count != 0) {
for (i = 0; i < count; i++) {
if (actorx->bg_collision_check.wall_info[i].type == mCoBG_WALL_TYPE0) {
actorx->world.angle.y = DEG2SHORT_ANGLE2(90.0f) + actorx->bg_collision_check.wall_info[i].angleY;
break;
}
}
}
}
chase_angle(&actorx->shape_info.rotation.y, actorx->world.angle.y, 0x800);
}
/**
* Avoid behavior when scared by player.
*/
static void aITT_avoid(ACTOR* actorx, GAME* game) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
f32 gravity;
aITT_anime_proc(insect);
gravity = actorx->gravity;
gravity *= 1.1f;
if (gravity > 12.0f) {
gravity = 12.0f;
}
actorx->gravity = gravity;
switch (insect->type) {
case aINS_INSECT_TYPE_LADYBUG:
case aINS_INSECT_TYPE_SPOTTED_LADYBUG:
case aINS_INSECT_TYPE_MANTIS:
sAdo_OngenPos((u32)actorx, NA_SE_26, &actorx->world.position);
break;
}
}
/**
* Special avoid behavior for snails.
*/
static void aITT_avoid_maimai(ACTOR* actorx, GAME* game) {
aITT_calc_direction_angl(actorx);
}
/**
* Normal movement behavior between flowers.
*/
static void aITT_move(ACTOR* actorx, GAME* game) {
static int ref_angl[] = {
// clang-format off
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
};
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
if (aITT_check_patience(actorx, game) == FALSE) {
if (insect->timer <= 0) {
aITT_setupAction(insect, aITT_ACT_WAIT, game);
} else {
f32 dx;
f32 dz;
int collision;
s16 step;
insect->timer--;
dx = actorx->world.position.x - actorx->home.position.x;
dz = actorx->world.position.z - actorx->home.position.z;
collision = 0;
if (ABS(dx) >= 15.0f) {
if (dx < 0.0f) {
actorx->world.position.x = actorx->home.position.x - 14.0f;
collision = 1;
} else {
actorx->world.position.x = actorx->home.position.x + 14.0f;
collision = 2;
}
}
if (ABS(dz) >= 15.0f) {
if (dz < 0.0f) {
actorx->world.position.z = actorx->home.position.z - 14.0f;
collision |= 4;
} else {
actorx->world.position.z = actorx->home.position.z + 14.0f;
collision |= 8;
}
}
actorx->world.position.y = 6.0f + mCoBG_GetBgY_OnlyCenter_FromWpos(actorx->world.position, -19.0f);
if (collision != 0) {
aITT_TARGET_ANGLE(insect) = ref_angl[collision];
aITT_TURN_DELAY(insect) = 10;
insect->speed_step = 0.0f;
actorx->speed = 0.0f;
} else if (actorx->world.angle.y == aITT_TARGET_ANGLE(insect)) {
aITT_TARGET_ANGLE(insect) = actorx->world.angle.y + (int)(RANDOM_CENTER_F(2.0f) * DEG2SHORT_ANGLE2(90.0f));
}
step = 0x600;
if (insect->type == aINS_INSECT_TYPE_SNAIL) {
step = 0x180;
}
chase_angle(&actorx->world.angle.y, aITT_TARGET_ANGLE(insect), step);
actorx->shape_info.rotation.y = actorx->world.angle.y;
if (aITT_TURN_DELAY(insect) == 0) {
insect->speed_step = 0.1f;
} else {
aITT_TURN_DELAY(insect)--;
}
}
}
}
/**
* Waiting behavior while on flowers.
*/
static void aITT_wait(ACTOR* actorx, GAME* game) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
if (aITT_check_patience(actorx, game) == FALSE) {
if (insect->timer <= 0) {
aITT_setupAction(insect, aITT_ACT_MOVE, game);
} else {
insect->timer--;
}
}
}
/**
* Initializes avoid state parameters.
*/
static void aITT_avoid_init(aINS_INSECT_ACTOR* insect, GAME* game) {
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;
{
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->tools_actor.actor_class.shape_info.draw_shadow = TRUE;
insect->insect_flags.bit_1 = TRUE;
insect->insect_flags.bit_2 = TRUE;
}
/**
* Initializes snail-specific avoid parameters.
*/
static void aITT_avoid_maimai_init(aINS_INSECT_ACTOR* insect, GAME* game) {
aITT_avoid_init(insect, game);
insect->tools_actor.actor_class.gravity = 2.0f;
insect->tools_actor.actor_class.max_velocity_y = -20.0f;
insect->tools_actor.actor_class.speed = 0.2f;
insect->target_speed = 0.2f;
insect->speed_step = 0.05f;
insect->insect_flags.bit_4 = FALSE;
}
/**
* Initializes movement state parameters.
*/
static void aITT_move_init(aINS_INSECT_ACTOR* insect, GAME* game) {
GAME_PLAY* play = (GAME_PLAY*)game;
insect->timer = ((90 + (int)(play->game_frame % 60)) * 2.0f);
aITT_TURN_DELAY(insect) = 0;
insect->target_speed = 0.4f;
insect->speed_step = 0.1f;
if (insect->type == aINS_INSECT_TYPE_SNAIL) {
insect->target_speed *= 0.25f;
insect->speed_step *= 0.25f;
}
}
/**
* Initializes waiting state parameters.
*/
static void aITT_wait_init(aINS_INSECT_ACTOR* insect, GAME* game) {
insect->timer = (90 + RANDOM_F(90.0f)) * 2.0f;
insect->tools_actor.actor_class.speed = 0.0f;
insect->speed_step = 0.0f;
}
typedef void (*aITT_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 aITT_setupAction(aINS_INSECT_ACTOR* insect, int action, GAME* game) {
static aITT_INIT_PROC init_proc[] = {
aITT_avoid_init,
aITT_avoid_maimai_init,
aITT_avoid_init,
aITT_avoid_maimai_init,
aITT_move_init,
aITT_wait_init,
};
static aINS_ACTION_PROC act_proc[] = {
aITT_avoid,
aITT_avoid_maimai,
aITT_avoid,
aITT_avoid_maimai,
aITT_move,
aITT_wait,
};
insect->action = action;
insect->action_proc = act_proc[action];
(*init_proc[action])(insect, game);
}
/**
* Main movement update function for flower-based insect actors.
*
* @param actorx Actor to update
* @param game Current game context
*/
static void aITT_actor_move(ACTOR* actorx, GAME* game) {
aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx;
u32 catch_label = mPlib_Get_item_net_catch_label();
if (catch_label == (u32)actorx) {
// @BUG - They forgot to make a separate case for the snail,
// so it uses the ladybug/spotted ladybug/mantis let escape behavior.
// This was fixed in the Australian release.
#ifndef BUGFIXES
aITT_setupAction(insect, aITT_ACT_LET_ESCAPE, game);
#else
int action;
switch (insect->type) {
case aINS_INSECT_TYPE_SNAIL:
actorx->world.position.y = mCoBG_GetBgY_OnlyCenter_FromWpos(actorx->world.position, 0.0f);
insect->home.position.y = actorx->world.position.y;
action = aITT_ACT_LET_ESCAPE_MAIMAI;
break;
default:
action = aITT_ACT_LET_ESCAPE;
break;
}
aITT_setupAction(insect, action, game);
#endif
} else if (insect->insect_flags.bit_3 == TRUE && insect->insect_flags.bit_2 == FALSE) {
aITT_setupAction(insect, aITT_ACT_LET_ESCAPE, game);
} else {
insect->action_proc(actorx, game);
}
}
+2 -2
View File
@@ -3,10 +3,10 @@ static ACTOR* aINS_make_actor(GAME* game, int type, xyz_t* pos) {
xyz_t_move(&init_data.position, pos);
init_data.insect_type = type;
init_data.extra_data = 1;
init_data.extra_data = aINS_INIT_RELEASE;
init_data.game = game;
return aINS_CLIP->make_insect_proc(&init_data, 1);
return aINS_CLIP->make_insect_proc(&init_data, aINS_MAKE_EXIST);
}
static int aINS_get_free_idx_set_block_table(mEv_gst_hitodama_block_c* block_table) {