|
|
|
@@ -0,0 +1,595 @@
|
|
|
|
|
#include "ac_fuusen.h"
|
|
|
|
|
|
|
|
|
|
#include "m_actor_shadow.h"
|
|
|
|
|
#include "m_common_data.h"
|
|
|
|
|
#include "m_debug_display.h"
|
|
|
|
|
#include "m_fuusen.h"
|
|
|
|
|
#include "m_play.h"
|
|
|
|
|
#include "m_player_lib.h"
|
|
|
|
|
#include "m_rcp.h"
|
|
|
|
|
#include "sys_matrix.h"
|
|
|
|
|
#include "zurumode.h"
|
|
|
|
|
|
|
|
|
|
static void aFSN_actor_ct(ACTOR* actorx, GAME* game);
|
|
|
|
|
static void aFSN_actor_dt(ACTOR* actorx, GAME* game);
|
|
|
|
|
static void aFSN_actor_move(ACTOR* actorx, GAME* game);
|
|
|
|
|
static void aFSN_actor_draw(ACTOR* actorx, GAME* game);
|
|
|
|
|
|
|
|
|
|
ACTOR_PROFILE Fuusen_Profile = {
|
|
|
|
|
mAc_PROFILE_FUUSEN,
|
|
|
|
|
ACTOR_PART_CONTROL,
|
|
|
|
|
ACTOR_STATE_NO_MOVE_WHILE_CULLED,
|
|
|
|
|
EMPTY_NO,
|
|
|
|
|
ACTOR_OBJ_BANK_FUUSEN,
|
|
|
|
|
sizeof(FUUSEN_ACTOR),
|
|
|
|
|
&aFSN_actor_ct,
|
|
|
|
|
&aFSN_actor_dt,
|
|
|
|
|
&aFSN_actor_move,
|
|
|
|
|
&aFSN_actor_draw,
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void aFSN_setupAction(FUUSEN_ACTOR* fuusen_actor, GAME* game, int action);
|
|
|
|
|
|
|
|
|
|
extern cKF_Skeleton_R_c cKF_bs_r_act_balloon;
|
|
|
|
|
extern cKF_Animation_R_c cKF_ba_r_act_balloon;
|
|
|
|
|
|
|
|
|
|
static void aFSN_actor_ct(ACTOR* actorx, GAME* game) {
|
|
|
|
|
FUUSEN_ACTOR* fuusen = (FUUSEN_ACTOR*)actorx;
|
|
|
|
|
cKF_SkeletonInfo_R_c* keyframe_p = &fuusen->keyframe;
|
|
|
|
|
static xyz_t Init_Size = { 0.01f, 0.01f, 0.01f };
|
|
|
|
|
f32 balloon_ground_y = mCoBG_GetBalloonGroundY(&actorx->world.position);
|
|
|
|
|
|
|
|
|
|
fuusen->escape_timer = 2000;
|
|
|
|
|
cKF_SkeletonInfo_R_ct(keyframe_p, &cKF_bs_r_act_balloon, &cKF_ba_r_act_balloon, fuusen->work, fuusen->morph);
|
|
|
|
|
cKF_SkeletonInfo_R_init_standard_repeat(keyframe_p, &cKF_ba_r_act_balloon, NULL);
|
|
|
|
|
Shape_Info_init(actorx, 0.0f, &mAc_ActorShadowCircle, 10.0f, 10.0f);
|
|
|
|
|
actorx->shape_info.draw_shadow = FALSE;
|
|
|
|
|
cKF_SkeletonInfo_R_play(keyframe_p);
|
|
|
|
|
keyframe_p->frame_control.speed = 1.0f;
|
|
|
|
|
xyz_t_move(&actorx->scale, &Init_Size);
|
|
|
|
|
actorx->world.position.y = balloon_ground_y + 200.0f;
|
|
|
|
|
fuusen->y_offset = 110.0f;
|
|
|
|
|
fuusen->segment_p = ((GAME_PLAY*)game)->object_exchange.banks[actorx->data_bank_id].ram_start;
|
|
|
|
|
aFSN_setupAction(fuusen, game, aFSN_ACTION_BIRTH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aFSN_actor_dt(ACTOR* actorx, GAME* game) {
|
|
|
|
|
FUUSEN_ACTOR* fuusen = (FUUSEN_ACTOR*)actorx;
|
|
|
|
|
|
|
|
|
|
if (fuusen->look_up_flag == TRUE) {
|
|
|
|
|
Balloon_look_up();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Balloon_kill();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aFSN_birth(ACTOR* actorx, GAME* game) {
|
|
|
|
|
FUUSEN_ACTOR* fuusen = (FUUSEN_ACTOR*)actorx;
|
|
|
|
|
|
|
|
|
|
aFSN_setupAction(fuusen, game, aFSN_ACTION_MOVING);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aFSN_moving(ACTOR* actorx, GAME* game) {
|
|
|
|
|
FUUSEN_ACTOR* fuusen = (FUUSEN_ACTOR*)actorx;
|
|
|
|
|
GAME_PLAY* play = (GAME_PLAY*)game;
|
|
|
|
|
f32 balloon_y = mCoBG_GetBalloonGroundY(&actorx->world.position) + fuusen->y_offset;
|
|
|
|
|
xyz_t screen_pos;
|
|
|
|
|
mActor_name_t* fg_item_p;
|
|
|
|
|
|
|
|
|
|
if (fuusen->escape_timer > 0) {
|
|
|
|
|
fuusen->escape_timer--;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Escape if flown to the edge of the map */
|
|
|
|
|
if (
|
|
|
|
|
(actorx->world.position.x <= 660.0f || actorx->world.position.x >= 3820.0f) ||
|
|
|
|
|
(actorx->world.position.z <= 660.0f || actorx->world.position.z >= 4460.0f)
|
|
|
|
|
) {
|
|
|
|
|
fuusen->escape_timer = aFSN_ESCAPE_TIMER;
|
|
|
|
|
aFSN_setupAction(fuusen, game, aFSN_ACTION_ESCAPE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Escape if flown into the train station acre? */
|
|
|
|
|
if (
|
|
|
|
|
(actorx->world.position.x <= 2440.0f && actorx->world.position.x >= 2040.0f) &&
|
|
|
|
|
(actorx->world.position.z <= 960.0f && actorx->world.position.z >= 800.0f)
|
|
|
|
|
) {
|
|
|
|
|
fuusen->escape_timer = aFSN_ESCAPE_TIMER;
|
|
|
|
|
aFSN_setupAction(fuusen, game, aFSN_ACTION_ESCAPE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fuusen->wind_power = mEnv_GetWindPowerF();
|
|
|
|
|
actorx->speed = fuusen->wind_power * 0.5f + 1.0f;
|
|
|
|
|
fuusen->fuwafuwa_cycle += 250;
|
|
|
|
|
add_calc(
|
|
|
|
|
&actorx->world.position.y,
|
|
|
|
|
balloon_y + sin_s(fuusen->fuwafuwa_cycle) * 10.0f,
|
|
|
|
|
1.0f - sqrtf(0.7f),
|
|
|
|
|
0.5f, 0.0f
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Game_play_Projection_Trans(play, &actorx->world.position, &screen_pos);
|
|
|
|
|
|
|
|
|
|
if (-40.0f > screen_pos.x || screen_pos.x > 360.0f || -40.0f > screen_pos.y || screen_pos.y > 280.0f) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mCoBG_BgCheckControll(NULL, actorx, 12.0f, 0.0f, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
(actorx->bg_collision_check.result.hit_wall & mCoBG_HIT_WALL) ||
|
|
|
|
|
(actorx->bg_collision_check.result.hit_attribute_wall & mCoBG_HIT_WALL)
|
|
|
|
|
) {
|
|
|
|
|
fuusen->y_offset += 0.05f; // raise quickly over walls
|
|
|
|
|
|
|
|
|
|
if (fuusen->y_offset >= 300.0f) {
|
|
|
|
|
fuusen->y_offset = 300.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (fuusen->y_offset > 110.0f) {
|
|
|
|
|
fuusen->y_offset -= 0.005f; // slowly fall
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fg_item_p = mFI_GetUnitFG(actorx->world.position);
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
fg_item_p != NULL &&
|
|
|
|
|
(
|
|
|
|
|
*fg_item_p == TREE ||
|
|
|
|
|
*fg_item_p == TREE_APPLE_NOFRUIT_0 ||
|
|
|
|
|
*fg_item_p == TREE_APPLE_NOFRUIT_1 ||
|
|
|
|
|
*fg_item_p == TREE_APPLE_NOFRUIT_2 ||
|
|
|
|
|
*fg_item_p == TREE_ORANGE_NOFRUIT_0 ||
|
|
|
|
|
*fg_item_p == TREE_ORANGE_NOFRUIT_1 ||
|
|
|
|
|
*fg_item_p == TREE_ORANGE_NOFRUIT_2 ||
|
|
|
|
|
*fg_item_p == TREE_PEACH_NOFRUIT_0 ||
|
|
|
|
|
*fg_item_p == TREE_PEACH_NOFRUIT_1 ||
|
|
|
|
|
*fg_item_p == TREE_PEACH_NOFRUIT_2 ||
|
|
|
|
|
*fg_item_p == TREE_PEAR_NOFRUIT_0 ||
|
|
|
|
|
*fg_item_p == TREE_PEAR_NOFRUIT_1 ||
|
|
|
|
|
*fg_item_p == TREE_PEAR_NOFRUIT_2 ||
|
|
|
|
|
*fg_item_p == TREE_CHERRY_NOFRUIT_0 ||
|
|
|
|
|
*fg_item_p == TREE_CHERRY_NOFRUIT_1 ||
|
|
|
|
|
*fg_item_p == TREE_CHERRY_NOFRUIT_2 ||
|
|
|
|
|
*fg_item_p == TREE_PALM_NOFRUIT_0 ||
|
|
|
|
|
*fg_item_p == TREE_PALM_NOFRUIT_1 ||
|
|
|
|
|
*fg_item_p == TREE_PALM_NOFRUIT_2 ||
|
|
|
|
|
*fg_item_p == CEDAR_TREE ||
|
|
|
|
|
*fg_item_p == GOLD_TREE
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
f32 dx;
|
|
|
|
|
f32 dy;
|
|
|
|
|
f32 dz;
|
|
|
|
|
|
|
|
|
|
mFI_Wpos2UtCenterWpos(&screen_pos, actorx->world.position);
|
|
|
|
|
|
|
|
|
|
if (*fg_item_p == CEDAR_TREE) {
|
|
|
|
|
screen_pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(actorx->world.position, 0.0f) + 100.0f;
|
|
|
|
|
screen_pos.z += 20.0f;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
screen_pos.x -= 2.5f;
|
|
|
|
|
screen_pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(actorx->world.position, 0.0f) + 97.5f;
|
|
|
|
|
screen_pos.z += 7.5f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dx = screen_pos.x - actorx->world.position.x;
|
|
|
|
|
dy = screen_pos.y - actorx->world.position.y;
|
|
|
|
|
dz = screen_pos.z - actorx->world.position.z;
|
|
|
|
|
|
|
|
|
|
if (*fg_item_p == CEDAR_TREE) {
|
|
|
|
|
if (dx * dx + dz * dz < 484.0f && dy * dy < 225.0f) {
|
|
|
|
|
aFSN_setupAction(fuusen, game, aFSN_ACTION_WOOD_STOP);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (dx * dx + dz * dz < 225.0f && dy * dy < 225.0f) {
|
|
|
|
|
aFSN_setupAction(fuusen, game, aFSN_ACTION_WOOD_STOP);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (fuusen->wind_change_flag == FALSE) {
|
|
|
|
|
static int senkou_check_data[] = { -2500, 0, 2500 };
|
|
|
|
|
s16 new_angle;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_COUNT(senkou_check_data); i++) {
|
|
|
|
|
xyz_t_move(&screen_pos, &actorx->world.position);
|
|
|
|
|
new_angle = (int)actorx->world.angle.y + (s16)senkou_check_data[i];
|
|
|
|
|
screen_pos.x += 80.0f * sin_s(new_angle);
|
|
|
|
|
screen_pos.z += 80.0f * cos_s(new_angle);
|
|
|
|
|
|
|
|
|
|
fg_item_p = mFI_GetUnitFG(screen_pos);
|
|
|
|
|
if (
|
|
|
|
|
fg_item_p != NULL &&
|
|
|
|
|
(
|
|
|
|
|
*fg_item_p == TREE ||
|
|
|
|
|
*fg_item_p == TREE_APPLE_NOFRUIT_0 ||
|
|
|
|
|
*fg_item_p == TREE_APPLE_NOFRUIT_1 ||
|
|
|
|
|
*fg_item_p == TREE_APPLE_NOFRUIT_2 ||
|
|
|
|
|
*fg_item_p == TREE_ORANGE_NOFRUIT_0 ||
|
|
|
|
|
*fg_item_p == TREE_ORANGE_NOFRUIT_1 ||
|
|
|
|
|
*fg_item_p == TREE_ORANGE_NOFRUIT_2 ||
|
|
|
|
|
*fg_item_p == TREE_PEACH_NOFRUIT_0 ||
|
|
|
|
|
*fg_item_p == TREE_PEACH_NOFRUIT_1 ||
|
|
|
|
|
*fg_item_p == TREE_PEACH_NOFRUIT_2 ||
|
|
|
|
|
*fg_item_p == TREE_PEAR_NOFRUIT_0 ||
|
|
|
|
|
*fg_item_p == TREE_PEAR_NOFRUIT_1 ||
|
|
|
|
|
*fg_item_p == TREE_PEAR_NOFRUIT_2 ||
|
|
|
|
|
*fg_item_p == TREE_CHERRY_NOFRUIT_0 ||
|
|
|
|
|
*fg_item_p == TREE_CHERRY_NOFRUIT_1 ||
|
|
|
|
|
*fg_item_p == TREE_CHERRY_NOFRUIT_2 ||
|
|
|
|
|
*fg_item_p == TREE_PALM_NOFRUIT_0 ||
|
|
|
|
|
*fg_item_p == TREE_PALM_NOFRUIT_1 ||
|
|
|
|
|
*fg_item_p == TREE_PALM_NOFRUIT_2 ||
|
|
|
|
|
*fg_item_p == CEDAR_TREE ||
|
|
|
|
|
*fg_item_p == GOLD_TREE
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
actorx->world.angle.y = new_angle;
|
|
|
|
|
fuusen->wind_change_flag = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fuusen->wind_change_flag == FALSE) {
|
|
|
|
|
actorx->world.angle.y = mEnv_GetWindAngleS();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aFSN_wood_stop(ACTOR* actorx, GAME* game) {
|
|
|
|
|
FUUSEN_ACTOR* fuusen = (FUUSEN_ACTOR*)actorx;
|
|
|
|
|
|
|
|
|
|
fuusen->escape_timer--;
|
|
|
|
|
|
|
|
|
|
if (fuusen->escape_timer <= aFSN_ESCAPE_TIMER) {
|
|
|
|
|
fuusen->escape_timer = aFSN_ESCAPE_TIMER;
|
|
|
|
|
aFSN_setupAction(fuusen, game, aFSN_ACTION_ESCAPE);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
xyz_t pos;
|
|
|
|
|
xyz_t pos2;
|
|
|
|
|
mActor_name_t* fg_item_p;
|
|
|
|
|
f32 dx;
|
|
|
|
|
f32 dz;
|
|
|
|
|
|
|
|
|
|
mFI_Wpos2UtCenterWpos(&pos, actorx->world.position);
|
|
|
|
|
xyz_t_move(&pos2, &pos);
|
|
|
|
|
fg_item_p = mFI_GetUnitFG(actorx->world.position);
|
|
|
|
|
|
|
|
|
|
if (fg_item_p != NULL && *fg_item_p == CEDAR_TREE) {
|
|
|
|
|
pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(actorx->world.position, 0.0f) + 100.0f;
|
|
|
|
|
pos.z += 20.0f;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
pos.x -= 2.5f;
|
|
|
|
|
pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(actorx->world.position, 0.0f) + 97.5f;
|
|
|
|
|
pos.z += 7.5f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dx = actorx->world.position.x - pos.x;
|
|
|
|
|
dz = actorx->world.position.z - pos.z;
|
|
|
|
|
|
|
|
|
|
if (sqrtf(dx * dx + dz * dz) > 2.0f) {
|
|
|
|
|
add_calc(&actorx->world.position.x, pos.x, 1.0f - sqrtf(0.7f), 0.5f, 0.0f);
|
|
|
|
|
add_calc(&actorx->world.position.y, pos.y, 1.0f - sqrtf(0.7f), 0.5f, 0.0f);
|
|
|
|
|
add_calc(&actorx->world.position.z, pos.z, 1.0f - sqrtf(0.7f), 0.5f, 0.0f);
|
|
|
|
|
}
|
|
|
|
|
else if (mPlib_Check_tree_shaken_big(&pos2)) {
|
|
|
|
|
actorx->shape_info.rotation.z = 0;
|
|
|
|
|
aFSN_setupAction(fuusen, game, aFSN_ACTION_ESCAPE);
|
|
|
|
|
}
|
|
|
|
|
else if (mPlib_Check_tree_shaken_little(&pos2)) {
|
|
|
|
|
if ((fuusen->count & 4) == 0) {
|
|
|
|
|
actorx->shape_info.rotation.z = 500;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
actorx->shape_info.rotation.z = -500;
|
|
|
|
|
actorx->shape_info.rotation.z = 0; // set again???
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fuusen->count++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
actorx->shape_info.rotation.z = 0;
|
|
|
|
|
fuusen->count = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aFSN_escape(ACTOR* actorx, GAME* game) {
|
|
|
|
|
FUUSEN_ACTOR* fuusen = (FUUSEN_ACTOR*)actorx;
|
|
|
|
|
f32 balloon_y = mCoBG_GetBalloonGroundY(&actorx->world.position);
|
|
|
|
|
|
|
|
|
|
if (fuusen->count == 0) {
|
|
|
|
|
xyz_t pos;
|
|
|
|
|
|
|
|
|
|
mFI_Wpos2UtCenterWpos(&pos, actorx->world.position);
|
|
|
|
|
if (Common_Get(clip).bg_item_clip != NULL && Common_Get(clip).bg_item_clip->item_tree_fruit_drop_proc != NULL) {
|
|
|
|
|
int ut_x;
|
|
|
|
|
int ut_z;
|
|
|
|
|
|
|
|
|
|
if (mFI_Wpos2UtNum(&ut_x, &ut_z, pos)) {
|
|
|
|
|
(*Common_Get(clip).bg_item_clip->fruit_set_proc)(ITM_PRESENT, ut_x, ut_z, 1, 1);
|
|
|
|
|
fuusen->count = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fuusen->count == 1 && actorx->world.position.y > balloon_y + 500.0f) {
|
|
|
|
|
Actor_delete(actorx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aFSN_birth_init(FUUSEN_ACTOR* fuusen, GAME* game) {
|
|
|
|
|
static int data_index_data[16] = {
|
|
|
|
|
0, 1, 1, 2,
|
|
|
|
|
2, 3, 3, 4,
|
|
|
|
|
4, 5, 5, 6,
|
|
|
|
|
6, 7, 7, 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static xyz_t birth_pos_data[8] = {
|
|
|
|
|
{ 1600.0f, 100.0f, 500.0f }, /* X:2.5, Z:0.8 - Acre Q-2 (above A-2) */
|
|
|
|
|
{ 500.0f, 100.0f, 500.0f }, /* X:0.8, Z:0.8 - Acre Q-0 (top-left corner acre) */
|
|
|
|
|
{ 500.0f, 100.0f, 1600.0f }, /* X:0.8, Z:2.5 - Acre B-0 (left of B-1) */
|
|
|
|
|
{ 500.0f, 100.0f, 4620.0f }, /* X:0.8, Z:7.2 - Acre G-0 (bottom-left corner acre)*/
|
|
|
|
|
{ 1600.0f, 100.0f, 4620.0f }, /* X:2.5, Z:7.2 - Acre G-2 (below F-2)*/
|
|
|
|
|
{ 3980.0f, 100.0f, 4620.0f }, /* X:6.2, Z:7.2 - Acre F-6 (bottom-right corner) */
|
|
|
|
|
{ 3980.0f, 100.0f, 1600.0f }, /* X:6.2, Z:2.5 - Acre B-6 (right of B-5) */
|
|
|
|
|
{ 3980.0f, 100.0f, 500.0f } /* X:6.2, Z:0.8 - Acre Q-6 (top-right corner)*/
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static xyz_t birth_pos_random_data[8] = {
|
|
|
|
|
{ 1280.0f, 100.0f, 0.0f },
|
|
|
|
|
{ 960.0f, 100.0f, 960.0f },
|
|
|
|
|
{ 0.0f, 100.0f, 1920.0f },
|
|
|
|
|
{ 960.0f, 100.0f, -960.0f },
|
|
|
|
|
{ 1280.0f, 100.0f, 0.0f },
|
|
|
|
|
{ -960.0f, 100.0f, -960.0f },
|
|
|
|
|
{ 0.0f, 100.0f, 1920.0f },
|
|
|
|
|
{ -960.0f, 100.0f, 960.0f }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
GAME_PLAY* play = (GAME_PLAY*)game;
|
|
|
|
|
f32 balloon_y = mCoBG_GetBalloonGroundY(&fuusen->actor_class.world.position);
|
|
|
|
|
int randomize_z;
|
|
|
|
|
|
|
|
|
|
fuusen->actor_class.world.angle.y = mEnv_GetWindAngleS();
|
|
|
|
|
fuusen->wind_idx = ((s16)(fuusen->actor_class.world.angle.y & 0xF000)) >> 12;
|
|
|
|
|
fuusen->wind_idx &= 0xF;
|
|
|
|
|
fuusen->wind_idx = data_index_data[fuusen->wind_idx];
|
|
|
|
|
|
|
|
|
|
xyz_t_move(&fuusen->actor_class.world.position, &birth_pos_data[fuusen->wind_idx]);
|
|
|
|
|
randomize_z = FALSE;
|
|
|
|
|
fuusen->actor_class.world.position.y = balloon_y + 200.0f;
|
|
|
|
|
fuusen->type_idx = play->game_frame % 5;
|
|
|
|
|
fuusen->timer = 10;
|
|
|
|
|
|
|
|
|
|
if (birth_pos_random_data[fuusen->wind_idx].x != 0.0f && birth_pos_random_data[fuusen->wind_idx].z != 0.0f) {
|
|
|
|
|
randomize_z = play->game_frame & 1; // randomly choose between X & Z
|
|
|
|
|
}
|
|
|
|
|
else if (birth_pos_random_data[fuusen->wind_idx].z != 0.0f) {
|
|
|
|
|
randomize_z = TRUE; // only Z can be randomized
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (randomize_z == FALSE) {
|
|
|
|
|
/* Adjust X position */
|
|
|
|
|
if (birth_pos_random_data[fuusen->wind_idx].x != 0.0f) {
|
|
|
|
|
f32 rng = fqrand() * fabsf(birth_pos_random_data[fuusen->wind_idx].x);
|
|
|
|
|
|
|
|
|
|
if (birth_pos_random_data[fuusen->wind_idx].x > 0.0f) {
|
|
|
|
|
fuusen->actor_class.world.position.x += rng;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
fuusen->actor_class.world.position.x -= rng;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Adjust Z position */
|
|
|
|
|
if (birth_pos_random_data[fuusen->wind_idx].z != 0.0f) {
|
|
|
|
|
f32 rng = fqrand() * fabsf(birth_pos_random_data[fuusen->wind_idx].z);
|
|
|
|
|
|
|
|
|
|
if (birth_pos_random_data[fuusen->wind_idx].z > 0.0f) {
|
|
|
|
|
fuusen->actor_class.world.position.z += rng;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
fuusen->actor_class.world.position.z -= rng;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aFSN_moving_init(FUUSEN_ACTOR* fuusen, GAME* game) {
|
|
|
|
|
fuusen->wind_change_flag = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aFSN_wood_stop_init(FUUSEN_ACTOR* fuusen, GAME* game) {
|
|
|
|
|
fuusen->actor_class.speed = 0.0f;
|
|
|
|
|
fuusen->escape_timer = 18000 + aFSN_ESCAPE_TIMER;
|
|
|
|
|
sAdo_OngenTrgStart(0x402, &fuusen->actor_class.world.position);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aFSN_escape_init(FUUSEN_ACTOR* fuusen, GAME* game) {
|
|
|
|
|
PLAYER_ACTOR* player = GET_PLAYER_ACTOR((GAME_PLAY*)game);
|
|
|
|
|
ACTOR* actorx = (ACTOR*)fuusen;
|
|
|
|
|
f32 dx = player->actor_class.world.position.x - actorx->world.position.x;
|
|
|
|
|
f32 dz = player->actor_class.world.position.z - actorx->world.position.z;
|
|
|
|
|
|
|
|
|
|
fuusen->count = 0;
|
|
|
|
|
actorx->max_velocity_y = 5.0f;
|
|
|
|
|
actorx->gravity = 0.5f;
|
|
|
|
|
fuusen->look_up_flag = FALSE;
|
|
|
|
|
|
|
|
|
|
if (fuusen->escape_timer == aFSN_ESCAPE_TIMER) {
|
|
|
|
|
fuusen->count = 1;
|
|
|
|
|
|
|
|
|
|
/* If the balloon is within 1 acre of distance to the player when it flies away, the 'look up flag' is set */
|
|
|
|
|
if (sqrtf(dx * dx + dz * dz) < (mFI_UNIT_BASE_SIZE_F * UT_BASE_NUM)) {
|
|
|
|
|
fuusen->look_up_flag = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef void (*aFSN_INIT_PROC)(FUUSEN_ACTOR*, GAME*);
|
|
|
|
|
|
|
|
|
|
static void aFSN_setupAction(FUUSEN_ACTOR* fuusen, GAME* game, int action) {
|
|
|
|
|
static aFSN_INIT_PROC init_proc[aFSN_ACTION_NUM] = {
|
|
|
|
|
&aFSN_birth_init,
|
|
|
|
|
&aFSN_moving_init,
|
|
|
|
|
&aFSN_wood_stop_init,
|
|
|
|
|
&aFSN_escape_init
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static mActor_proc act_proc[aFSN_ACTION_NUM] = {
|
|
|
|
|
&aFSN_birth,
|
|
|
|
|
&aFSN_moving,
|
|
|
|
|
&aFSN_wood_stop,
|
|
|
|
|
&aFSN_escape
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
fuusen->action = action;
|
|
|
|
|
fuusen->action_proc = act_proc[action];
|
|
|
|
|
(*init_proc[action])(fuusen, game);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aFSN_actor_move(ACTOR* actorx, GAME* game) {
|
|
|
|
|
FUUSEN_ACTOR* fuusen = (FUUSEN_ACTOR*)actorx;
|
|
|
|
|
cKF_SkeletonInfo_R_c* keyframe_p = &fuusen->keyframe;
|
|
|
|
|
|
|
|
|
|
if (fuusen->timer == 0) {
|
|
|
|
|
Actor_position_moveF(actorx);
|
|
|
|
|
}
|
|
|
|
|
else if (fuusen->timer > 0) {
|
|
|
|
|
fuusen->timer--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fuusen_DEBUG_mode_flag != FALSE && zurumode_flag != 0) {
|
|
|
|
|
PLAYER_ACTOR* player = GET_PLAYER_ACTOR((GAME_PLAY*)game);
|
|
|
|
|
int rot_y = (int)actorx->player_angle_y - (s16)-0x8000;
|
|
|
|
|
|
|
|
|
|
Debug_Display_new(
|
|
|
|
|
player->actor_class.world.position.x + sin_s(actorx->player_angle_y - (s16)-0x8000) * 30.0f,
|
|
|
|
|
player->actor_class.world.position.y + 60.0f,
|
|
|
|
|
player->actor_class.world.position.z + cos_s(actorx->player_angle_y - (s16)-0x8000) * 30.0f,
|
|
|
|
|
1.0f, 1.0f, 1.0f,
|
|
|
|
|
0, rot_y, 0,
|
|
|
|
|
250, 100, 120, 128,
|
|
|
|
|
4,
|
|
|
|
|
game->graph
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cKF_SkeletonInfo_R_play(keyframe_p);
|
|
|
|
|
(*fuusen->action_proc)(actorx, game);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int aFSN_actor_draw_before(GAME* game, cKF_SkeletonInfo_R_c* keyframe, int joint_num, Gfx** gfx_pp, u8* data_p, void* arg, s_xyz* joint_p, xyz_t* pos_p) {
|
|
|
|
|
static rgba_t balloon_prim_data[] = {
|
|
|
|
|
{ 255, 210, 200, 255 },
|
|
|
|
|
{ 200, 230, 200, 255 },
|
|
|
|
|
{ 255, 250, 200, 255 },
|
|
|
|
|
{ 220, 255, 200, 255 },
|
|
|
|
|
{ 240, 210, 255, 255 }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static rgba_t balloon_env_data[] = {
|
|
|
|
|
{ 255, 40, 0, 255 },
|
|
|
|
|
{ 0, 180, 255, 255 },
|
|
|
|
|
{ 255, 200, 0, 255 },
|
|
|
|
|
{ 100, 255, 0, 255 },
|
|
|
|
|
{ 200, 30, 255, 255 }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FUUSEN_ACTOR* fuusen = (FUUSEN_ACTOR*)arg;
|
|
|
|
|
GRAPH* graph = game->graph;
|
|
|
|
|
Gfx* gfx;
|
|
|
|
|
|
|
|
|
|
if (joint_num == 3) {
|
|
|
|
|
OPEN_DISP(graph);
|
|
|
|
|
gfx = NOW_POLY_OPA_DISP;
|
|
|
|
|
|
|
|
|
|
gDPSetPrimColor(gfx++, 0, 255, balloon_prim_data[fuusen->type_idx].r, balloon_prim_data[fuusen->type_idx].g, balloon_prim_data[fuusen->type_idx].b, balloon_prim_data[fuusen->type_idx].a);
|
|
|
|
|
gDPSetEnvColor(gfx++, balloon_env_data[fuusen->type_idx].r, balloon_env_data[fuusen->type_idx].g, balloon_env_data[fuusen->type_idx].b, balloon_env_data[fuusen->type_idx].a);
|
|
|
|
|
|
|
|
|
|
SET_POLY_OPA_DISP(gfx);
|
|
|
|
|
CLOSE_DISP(graph);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OPEN_DISP(graph);
|
|
|
|
|
gfx = NOW_POLY_OPA_DISP;
|
|
|
|
|
|
|
|
|
|
if (joint_num != 3) {
|
|
|
|
|
gDPSetTexEdgeAlpha(gfx++, 80);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
gDPSetTexEdgeAlpha(gfx++, 144);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SET_POLY_OPA_DISP(gfx);
|
|
|
|
|
CLOSE_DISP(graph);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern Gfx present_DL_mode[];
|
|
|
|
|
extern Gfx present_DL_vtx[];
|
|
|
|
|
|
|
|
|
|
static void aFSN_actor_draw(ACTOR* actorx, GAME* game) {
|
|
|
|
|
static xyz_t offset0 = { 0.0f, 0.0f, 0.0f };
|
|
|
|
|
|
|
|
|
|
FUUSEN_ACTOR* fuusen = (FUUSEN_ACTOR*)actorx;
|
|
|
|
|
Mtx* mtx = fuusen->mtx[game->frame_counter & 1];
|
|
|
|
|
GAME_PLAY* play = (GAME_PLAY*)game;
|
|
|
|
|
GRAPH* graph = game->graph;
|
|
|
|
|
Gfx* gfx;
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
Camera2_CheckCullingMode() == FALSE ||
|
|
|
|
|
Camera2_CheckEnterCullingArea(actorx->world.position.x, actorx->world.position.z, 60.0f) == FALSE
|
|
|
|
|
) {
|
|
|
|
|
Matrix_push();
|
|
|
|
|
|
|
|
|
|
if (fuusen->action != aFSN_ACTION_ESCAPE || fuusen->escape_timer == aFSN_ESCAPE_TIMER || (fuusen->action == aFSN_ACTION_ESCAPE && fuusen->count == 0)) {
|
|
|
|
|
/* Draw present */
|
|
|
|
|
Matrix_translate(actorx->world.position.x, actorx->world.position.y, actorx->world.position.z, 0);
|
|
|
|
|
Matrix_scale(0.01f, 0.01f, 0.01f, 1);
|
|
|
|
|
Matrix_RotateX(actorx->shape_info.rotation.x, 1);
|
|
|
|
|
Matrix_RotateZ(actorx->shape_info.rotation.z, 1);
|
|
|
|
|
Matrix_RotateY(actorx->shape_info.rotation.y, 1);
|
|
|
|
|
_texture_z_light_fog_prim(graph);
|
|
|
|
|
|
|
|
|
|
OPEN_DISP(graph);
|
|
|
|
|
gfx = NOW_POLY_OPA_DISP;
|
|
|
|
|
|
|
|
|
|
gSPMatrix(gfx++, _Matrix_to_Mtx_new(graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
|
|
|
gSPDisplayList(gfx++, present_DL_mode);
|
|
|
|
|
gSPDisplayList(gfx++, present_DL_vtx);
|
|
|
|
|
|
|
|
|
|
SET_POLY_OPA_DISP(gfx);
|
|
|
|
|
CLOSE_DISP(graph);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Setpos_HiliteReflect_init(&actorx->world.position, (GAME_PLAY*)game);
|
|
|
|
|
cKF_Si3_draw_R_SV(game, &fuusen->keyframe, mtx, &aFSN_actor_draw_before, NULL, actorx);
|
|
|
|
|
|
|
|
|
|
OPEN_DISP(graph);
|
|
|
|
|
gfx = NOW_POLY_OPA_DISP;
|
|
|
|
|
|
|
|
|
|
gDPSetTexEdgeAlpha(gfx++, 144);
|
|
|
|
|
|
|
|
|
|
SET_POLY_OPA_DISP(gfx);
|
|
|
|
|
CLOSE_DISP(graph);
|
|
|
|
|
|
|
|
|
|
mAc_ActorShadowDraw_ShadowDrawFlagOn(actorx, play, 0, offset0, 170.0f);
|
|
|
|
|
Matrix_pull();
|
|
|
|
|
}
|
|
|
|
|
}
|