static void aINS_position_move(ACTOR* actorx) { aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; s16 angleY = actorx->world.angle.y; xyz_t_move(&actorx->last_world_position, &actorx->world.position); chase_f(&actorx->speed, insect->target_speed, insect->speed_step * 0.5f); actorx->position_speed.x = actorx->speed * sin_s(angleY); actorx->position_speed.z = actorx->speed * cos_s(angleY); switch (insect->type) { case aSOI_INSECT_TYPE_COMMON_BUTTERFLY: case aSOI_INSECT_TYPE_YELLOW_BUTTERFLY: case aSOI_INSECT_TYPE_TIGER_BUTTERFLY: case aSOI_INSECT_TYPE_PURPLE_BUTTERFLY: case aSOI_INSECT_TYPE_FIREFLY: case aSOI_INSECT_TYPE_MOSQUITO: case aSOI_INSECT_TYPE_SPIRIT: break; default: chase_f(&actorx->position_speed.y, actorx->max_velocity_y, actorx->gravity * 0.5f); break; } Actor_position_move(actorx); } static void aINS_set_player_info(ACTOR* actorx, PLAYER_ACTOR* player) { if (player != NULL) { f32 distXZ; f32 distY; distXZ = search_position_distanceXZ(&actorx->world.position, &player->actor_class.world.position); actorx->player_distance_xz = distXZ; distY = player->actor_class.world.position.y - actorx->world.position.y; actorx->player_distance_y = distY; actorx->player_distance = SQ(distXZ) + SQ(distY); actorx->player_angle_y = search_position_angleY(&actorx->world.position, &player->actor_class.world.position); } else { actorx->player_distance_xz = 0.0f; actorx->player_distance_y = 0.0f; actorx->player_distance = 0.0f; actorx->player_angle_y = 0; } } static void aINS_BGcheck(ACTOR* actorx) { aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; switch (insect->bg_type) { case 1: mCoBG_BgCheckControll(NULL, actorx, insect->bg_range, insect->bg_height, TRUE, FALSE, 1); break; case 2: mCoBG_BgCheckControll(NULL, actorx, insect->bg_range, insect->bg_height, FALSE, FALSE, 1); break; case 3: mCoBG_BgCheckControll_RemoveDirectedUnitColumn(NULL, actorx, insect->bg_range, insect->bg_height, TRUE, FALSE, 1, insect->ut_x, insect->ut_z); break; case 4: mCoBG_BgCheckControll_RemoveDirectedUnitColumn(NULL, actorx, insect->bg_range, insect->bg_height, FALSE, FALSE, 1, insect->ut_x, insect->ut_z); break; } if (insect->insect_flags.bit_2 == FALSE && insect->insect_flags.bit_4 == TRUE) { mCoBG_UniqueWallCheck(actorx, insect->bg_range, 0.0f); } } // clang-format off static f32 catch_ME_data[] = { 0.0, 0.0, 0.0, 0.0, 10.0, 10.0, 10.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, 0.0, 0.0, -20.0, -20.0, -20.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0f, }; // clang-format on static void aINS_get_stress_sub(f32* stress, Actor_list* actor_list, xyz_t* pos, aINS_INSECT_ACTOR* insect) { static f32 calc_table[] = { 0.3f, 1.0f, 2.0f, 5.0f, 10.0f }; f32 min_dist = aINS_MAX_STRESS_DIST; ACTOR* actor; min_dist += catch_ME_data[insect->type]; /* Calculate the greatest stress caused by any nearby actors */ for (actor = actor_list->actor; actor != NULL; actor = actor->next_actor) { f32 dist = search_position_distance(pos, &actor->world.position); if (dist < min_dist) { f32 tmp0; int idx; f32 dX; f32 dZ; f32 calc_stress; tmp0 = dist - mFI_UNIT_BASE_SIZE_F; if (tmp0 < 0.0f) { tmp0 = 0.0f; } idx = (int)((min_dist - mFI_UNIT_BASE_SIZE_F) - tmp0) / 20; if (idx > ARRAY_COUNT(calc_table) - 1) { idx = ARRAY_COUNT(calc_table) - 1; } dX = actor->world.position.x - actor->last_world_position.x; dZ = actor->world.position.z - actor->last_world_position.z; calc_stress = sqrtf(SQ(dX) + SQ(dZ)) * calc_table[idx]; /* Stress is modified by the amount of movement over a single frame */ if (calc_stress > *stress) { *stress = calc_stress; } } } } static f32 aINS_get_stress(ACTOR* actorx, GAME* game) { Actor_info* actor_info = &((GAME_PLAY*)game)->actor_info; int i; aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; f32 stress = 0.0f; /* Calculate max stress on the insect from specific types of actors */ for (i = 0; i < ACTOR_PART_NUM; i++) { switch (i) { case ACTOR_PART_UNUSED: case ACTOR_PART_PLAYER: case ACTOR_PART_NPC: case ACTOR_PART_BG: aINS_get_stress_sub(&stress, &actor_info->list[i], &actorx->world.position, insect); break; } } return stress; /* return the max stress */ } static void aINS_calc_patience(ACTOR* actorx, GAME* game) { aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; f32 stress = aINS_get_stress(actorx, game); if (F32_IS_ZERO(stress)) { insect->patience -= aINS_PATIENCE_STEP; if (insect->patience < 0.0f) { insect->patience = 0.0f; } } else { insect->patience += stress * aINS_PATIENCE_STEP; if (insect->patience > 100.0f) { insect->patience = 100.0f; } } } static void aINS_calc_life_time(aINS_INSECT_ACTOR* insect) { insect->life_time--; if (insect->life_time <= 0) { insect->insect_flags.bit_3 = TRUE; insect->life_time = 0; } } static void aINS_calc_alpha_time(aINS_INSECT_ACTOR* insect) { if (insect->life_time != 0) { return; } if (insect->alpha_time <= 0) { return; } insect->alpha_time--; if (insect->alpha_time >= 24) { return; } switch (insect->type) { case aSOI_INSECT_TYPE_FIREFLY: { int alpha = insect->alpha2; alpha += 11; if (alpha >= 255) { alpha = 255; insect->alpha0 = 0; insect->alpha1 = 0; insect->insect_flags.destruct = TRUE; } insect->alpha2 = alpha; break; } default: { int alpha = insect->alpha0; alpha -= 11; if (alpha <= 0) { alpha = 0; insect->insect_flags.destruct = TRUE; } insect->alpha0 = alpha; } } } static void aINS_cull_check(ACTOR* actorx, GAME* game) { aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; GAME_PLAY* play = (GAME_PLAY*)game; Skin_Matrix_PrjMulVector(&play->projection_matrix, &actorx->world.position, &actorx->camera_position, &actorx->camera_w); if (insect->insect_flags.destruct && (ACTOR*)mPlib_Get_item_net_catch_label() != actorx) { aINS_destruct(actorx, game); } if (Actor_draw_actor_no_culling_check(actorx) == FALSE) { if (actorx->actor_specific == 1) { if ((ACTOR*)mPlib_Get_item_net_catch_label() != actorx) { aINS_destruct(actorx, game); } } else { if ((ACTOR*)mPlib_Get_item_net_catch_label() != actorx) { /* Allow actor to be culled since it's not been caught */ actorx->state_bitfield &= ~ACTOR_STATE_NO_CULL; } /* Despawn if player is more than 15 units away and in another acre and has not caught it */ if (actorx->player_distance_xz > 600.0f && (actorx->block_x != play->block_table.block_x || actorx->block_z != play->block_table.block_z) && (ACTOR*)mPlib_Get_item_net_catch_label() != actorx) { aINS_destruct(actorx, game); } } } else { /* Don't cull if the actor is still visible on the camera */ actorx->state_bitfield |= ACTOR_STATE_NO_CULL; } } static f32 aINS_get_catch_range_sub(ACTOR* actorx) { f32 range = 24.0f; s16 dAngleY = ABS((s16)(actorx->world.angle.y - actorx->player_angle_y)); /* Player must be facing within 90 degrees of the insect */ if (dAngleY > DEG2SHORT_ANGLE2(90.0f)) { range = 0.0f; } return range; } static f32 aINS_get_catch_range(ACTOR* actorx) { aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; f32 range = 8.0f; switch (insect->type) { case aSOI_INSECT_TYPE_COMMON_BUTTERFLY: case aSOI_INSECT_TYPE_YELLOW_BUTTERFLY: range = 24.0f; break; case aSOI_INSECT_TYPE_ROBUST_CICADA: case aSOI_INSECT_TYPE_WALKER_CICADA: case aSOI_INSECT_TYPE_EVENING_CICADA: case aSOI_INSECT_TYPE_BROWN_CICADA: case aSOI_INSECT_TYPE_BEE: case aSOI_INSECT_TYPE_DRONE_BEETLE: case aSOI_INSECT_TYPE_DYNASTID_BEETLE: case aSOI_INSECT_TYPE_FLAT_STAG_BEETLE: case aSOI_INSECT_TYPE_JEWEL_BEETLE: case aSOI_INSECT_TYPE_LONGHORN_BEETLE: case aSOI_INSECT_TYPE_SAW_STAG_BEETLE: case aSOI_INSECT_TYPE_MOUNTAIN_BEETLE: case aSOI_INSECT_TYPE_GIANT_BEETLE: range = aINS_get_catch_range_sub(actorx); break; case aSOI_INSECT_TYPE_COCKROACH: if (insect->flag == 4) { range = aINS_get_catch_range_sub(actorx); } break; } return range; } static void aINS_set_catch_range(ACTOR* actorx) { aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)actorx; if (insect->insect_flags.bit_1 == FALSE) { f32 catch_range = aINS_get_catch_range(actorx); if (!F32_IS_ZERO(catch_range)) { GET_PLAYER_ACTOR_NOW()->Set_Item_net_catch_request_table_proc( (ACTOR*)GET_PLAYER_ACTOR_NOW(), gamePT, (u32)actorx, 0, &actorx->world.position, catch_range); } } } static void aINS_check_birth_ant(GAME* game) { GAME_PLAY* play = (GAME_PLAY*)game; if (aINS_CLIP->ant_spawn_pending == TRUE) { aINS_Init_c* init = &aINS_CLIP->ant_spawn_info; ACTOR* actorx = Actor_info_make_actor(&play->actor_info, game, mAc_PROFILE_ANT, init->position.x, init->position.y, init->position.z, 0, 0, 0, aINS_CLIP->ant_bx, aINS_CLIP->ant_bz, -1, EMPTY_NO, -1, -1, -1); if (actorx != NULL) { aINS_CLIP->ant_spawn_pending = FALSE; } } } static void aINS_actor_move(ACTOR* actorx, GAME* game) { aINS_CTRL_ACTOR* ctrl_actor = (aINS_CTRL_ACTOR*)actorx; GAME_PLAY* play = (GAME_PLAY*)game; PLAYER_ACTOR* player = GET_PLAYER_ACTOR(play); aINS_INSECT_ACTOR* insect = ctrl_actor->insect_actor; int i; for (i = 0; i < aINS_ACTOR_NUM; i++) { ACTOR* actorx = (ACTOR*)insect; if (insect->exist_flag == TRUE) { actorx->state_bitfield &= ~ACTOR_STATE_24; if ((actorx->state_bitfield & (ACTOR_STATE_NO_MOVE_WHILE_CULLED | ACTOR_STATE_NO_CULL))) { if (insect->tools_actor.init_matrix == FALSE) { (*insect->move_proc)(actorx); } aINS_set_player_info(actorx, player); aINS_BGcheck(actorx); aINS_calc_patience(actorx, game); aINS_calc_life_time(insect); aINS_calc_alpha_time(insect); (*actorx->mv_proc)(actorx, game); Actor_world_to_eye(actorx, 0.0f); aINS_set_catch_range(actorx); } aINS_cull_check(actorx, game); } insect++; } aINS_check_birth_ant(game); aINS_set_pl_act_tim(0, -1, -1); }