Implement & link ac_npc_guide2

This commit is contained in:
Cuyler36
2024-07-08 20:24:31 -04:00
parent e9412bf5a6
commit 8422652bbf
6 changed files with 1041 additions and 2 deletions
+4
View File
@@ -764,6 +764,10 @@ ac_npc_guide.c:
.text: [0x80552B5C, 0x80554B00]
.rodata: [0x80649620, 0x806496A0]
.data: [0x806A6208, 0x806A6508]
ac_npc_guide2.c:
.text: [0x80554B00, 0x80556714]
.rodata: [0x806496A0, 0x80649720]
.data: [0x806A6508, 0x806A67E0]
ac_npc_rcn_guide.c:
.text: [0x8056EED0, 0x8056FFF0]
.rodata: [0x806499C0, 0x806499E8]
+27 -1
View File
@@ -3,11 +3,38 @@
#include "types.h"
#include "m_actor.h"
#include "ac_npc.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct npc_guide2_actor_s NPC_GUIDE2_ACTOR;
typedef void (*aNG2_PROC)(NPC_GUIDE2_ACTOR*, GAME_PLAY*);
struct npc_guide2_actor_s {
NPC_ACTOR npc_class;
int action;
int next_action;
aNG2_PROC proc;
int lock_camera_flag;
int camera_morph_counter;
s16 camera_move;
s8 camera_move_cnt;
s8 camera_move_set_counter;
f32 camera_move_y;
f32 camera_move_range;
s16 camera_tilt_cur_angle;
s16 camera_tilt_goal_angle;
s16 camera_tilt_add;
int answer_flags;
ACTOR* train_door_actor;
int obj_look_type;
f32 obj_dist_ground;
int camera_eyes_flag;
};
extern ACTOR_PROFILE Npc_Guide2_Profile;
#ifdef __cplusplus
@@ -15,4 +42,3 @@ extern ACTOR_PROFILE Npc_Guide2_Profile;
#endif
#endif
+138
View File
@@ -0,0 +1,138 @@
#include "ac_npc_guide2.h"
#include "m_play.h"
#include "m_common_data.h"
#include "ac_train_door.h"
#include "m_player_lib.h"
#include "m_font.h"
#include "m_msg.h"
#include "m_timeIn_ovl.h"
#include "m_ledit_ovl.h"
#include "libultra/libultra.h"
#include "m_bgm.h"
#include "m_soncho.h"
enum {
aNG2_ACTION_ENTER,
aNG2_ACTION_APPROACH,
aNG2_ACTION_TALK_START_WAIT,
aNG2_ACTION_WAIT_PERMISSION,
aNG2_ACTION_SITDOWN,
aNG2_ACTION_SDON_AND_PB_WAIT,
aNG2_ACTION_PNAME_MENU_OPEN_WAIT,
aNG2_ACTION_PNAME_MENU_CLOSE_WAIT,
aNG2_ACTION_MSG_WIN_OPEN_WAIT,
aNG2_ACTION_PNAME_NG,
aNG2_ACTION_SEX_SELECT_WAIT,
aNG2_ACTION_SEX_SELECT_WAIT2,
aNG2_ACTION_SEX_SELECT_AFTER,
aNG2_ACTION_STANDUP_START_WAIT,
aNG2_ACTION_STANDUP,
aNG2_ACTION_MOVE_READY,
aNG2_ACTION_MOVE_TO_AISLE,
aNG2_ACTION_MOVE_TO_DOOR,
aNG2_ACTION_MOVE_TO_DECK,
aNG2_ACTION_KEITAI_ON,
aNG2_ACTION_KEITAI_TALK,
aNG2_ACTION_KEITAI_OFF,
aNG2_ACTION_OPEN_DOOR,
aNG2_ACTION_RETURN_APPROACH,
aNG2_ACTION_LAST_TALK_START_WAIT,
aNG2_ACTION_SITDOWN2_START_WAIT,
aNG2_ACTION_SITDOWN2,
aNG2_ACTION_LAST_TALK_END_WAIT,
aNG2_ACTION_SCENE_CHANGE_WAIT,
aNG2_ACTION_NUM
};
enum {
aNG2_OBJ_LOOK_TYPE_NORMAL,
aNG2_OBJ_LOOK_TYPE_TALK,
aNG2_OBJ_LOOK_TYPE_NUM
};
static void aNG2_actor_ct(ACTOR* actorx, GAME* game);
static void aNG2_actor_dt(ACTOR* actorx, GAME* game);
static void aNG2_actor_init(ACTOR* actorx, GAME* game);
static void aNG2_actor_save(ACTOR* actorx, GAME* game);
// clang-format off
ACTOR_PROFILE Npc_Guide2_Profile = {
mAc_PROFILE_NPC_GUIDE2,
ACTOR_PART_NPC,
ACTOR_STATE_NO_DRAW_WHILE_CULLED | ACTOR_STATE_NO_MOVE_WHILE_CULLED,
SP_NPC_GUIDE2,
ACTOR_OBJ_BANK_KEEP,
sizeof(NPC_GUIDE2_ACTOR),
&aNG2_actor_ct,
&aNG2_actor_dt,
&aNG2_actor_init,
mActor_NONE_PROC1,
&aNG2_actor_save,
};
// clang-format on
static void aNG2_actor_move(ACTOR* actorx, GAME* game);
static void aNG2_actor_draw(ACTOR* actorx, GAME* game);
static void aNG2_setupAction(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play, int action);
static void aNG2_actor_ct(ACTOR* actorx, GAME* game) {
static aNPC_ct_data_c ct_data = { &aNG2_actor_move, &aNG2_actor_draw, 0, NULL, NULL, NULL, 0 };
NPC_GUIDE2_ACTOR* guide2 = (NPC_GUIDE2_ACTOR*)actorx;
GAME_PLAY* play = (GAME_PLAY*)game;
PLAYER_ACTOR* player;
Common_Get(clip).npc_clip->ct_proc(actorx, game, &ct_data);
guide2->npc_class.condition_info.hide_flg = FALSE; // show guide2 actor
guide2->npc_class.condition_info.demo_flg =
aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | aNPC_COND_DEMO_SKIP_TALK_CHECK |
aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | aNPC_COND_DEMO_SKIP_BGCHECK |
aNPC_COND_DEMO_SKIP_OBJ_COL_CHECK | aNPC_COND_DEMO_SKIP_MOVE_Y | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV |
aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK;
guide2->camera_morph_counter = 40;
guide2->obj_look_type = aNG2_OBJ_LOOK_TYPE_NORMAL;
guide2->npc_class.eye_y = 30.0f;
guide2->camera_move_set_counter = 1;
guide2->npc_class.palActorIgnoreTimer = -1;
guide2->train_door_actor = Actor_info_fgName_search(&play->actor_info, TRAIN_DOOR, ACTOR_PART_BG);
guide2->npc_class.actor_class.shape_info.draw_shadow = TRUE;
guide2->npc_class.actor_class.world.position.z = 130.0f;
/* Put the player into demo wait state */
mPlib_request_main_demo_wait_type1(game, 0, NULL);
player = GET_PLAYER_ACTOR(play);
if (player != NULL) {
/* Make the player invisible during the intro train ride */
player->actor_class.state_bitfield |= ACTOR_STATE_INVISIBLE;
}
aNG2_setupAction(guide2, play, aNG2_ACTION_ENTER);
/* Play train noises sfx repeatedly */
sAdo_SysLevStart(NA_SE_TRAIN_RIDE);
}
static void aNG2_actor_save(ACTOR* actorx, GAME* game) {
Common_Get(clip).npc_clip->save_proc(actorx, game);
}
static void aNG2_actor_dt(ACTOR* actorx, GAME* game) {
Common_Get(clip).npc_clip->dt_proc(actorx, game);
/* Stop train noise sfx */
sAdo_SysLevStop(NA_SE_TRAIN_RIDE);
}
static void aNG2_actor_init(ACTOR* actorx, GAME* game) {
Common_Get(clip).npc_clip->init_proc(actorx, game);
}
static void aNG2_actor_draw(ACTOR* actorx, GAME* game) {
Common_Get(clip).npc_clip->draw_proc(actorx, game);
}
#include "../src/ac_npc_guide2_animation.c_inc"
#include "../src/ac_npc_guide2_move.c_inc"
+45
View File
@@ -0,0 +1,45 @@
typedef struct npc_guide_animation_s {
int anim_id;
int talk_flag;
} aNG2_anime_c;
static void aNG2_set_animation(NPC_GUIDE2_ACTOR* guide2, int action) {
// clang-format off
static aNG2_anime_c anime[] = {
{ aNPC_ANIM_OPEN_D1, FALSE },
{ aNPC_ANIM_WALK1, FALSE },
{ aNPC_ANIM_WAIT1, TRUE },
{ aNPC_ANIM_WAIT1, TRUE },
{ aNPC_ANIM_SITDOWN_D1, TRUE },
{ aNPC_ANIM_SITDOWN_WAIT_D1, TRUE },
{ aNPC_ANIM_SITDOWN_WAIT_D1, TRUE },
{ aNPC_ANIM_SITDOWN_WAIT_D1, TRUE },
{ aNPC_ANIM_SITDOWN_WAIT_D1, TRUE },
{ aNPC_ANIM_SITDOWN_WAIT_D1, TRUE },
{ aNPC_ANIM_SITDOWN_WAIT_D1, TRUE },
{ aNPC_ANIM_SITDOWN_WAIT_D1, TRUE },
{ aNPC_ANIM_SITDOWN_WAIT_D1, TRUE },
{ aNPC_ANIM_SITDOWN_WAIT_D1, TRUE },
{ aNPC_ANIM_STANDUP_D1, FALSE },
{ aNPC_ANIM_WAIT1, FALSE },
{ aNPC_ANIM_WALK1, FALSE },
{ aNPC_ANIM_WALK1, FALSE },
{ aNPC_ANIM_TO_DECK_D1, FALSE },
{ aNPC_ANIM_KEITAI_ON1, FALSE },
{ aNPC_ANIM_KEITAI_TALK1, TRUE },
{ aNPC_ANIM_KEITAI_OFF1, FALSE },
{ aNPC_ANIM_OPEN_D2, FALSE },
{ aNPC_ANIM_WALK1, FALSE },
{ aNPC_ANIM_WAIT1, FALSE },
{ aNPC_ANIM_WAIT1, TRUE },
{ aNPC_ANIM_SITDOWN_D1, TRUE },
{ aNPC_ANIM_SITDOWN_WAIT_D1, TRUE },
{ aNPC_ANIM_SITDOWN_WAIT_D1, FALSE },
};
// clang-format on
aNG2_anime_c* anime_info = &anime[action];
Common_Get(clip).npc_clip->animation_init_proc(&guide2->npc_class.actor_class, anime_info->anim_id,
anime_info->talk_flag);
}
+823
View File
@@ -0,0 +1,823 @@
static void aNG2_set_camera(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
static s8 mov_def_cnt[] = { 3, 0 };
static f32 obj_look_y_max[] = { 30.0f, 20.0f };
static f32 obj_look_y_spd[] = { 0.5f, 2.5f };
xyz_t eye;
xyz_t pos;
xyz_t ground;
s16 move;
f32 moveX;
f32 moveY;
int obj_look_type = guide2->obj_look_type;
s16 cur_angle;
f32 inter;
f32 sin;
f32 ground_y;
s16 angle;
move = guide2->camera_move;
guide2->camera_move += 0xE20;
angle = move;
angle += 0xE20;
moveX = cos_s(angle) * 0.1f;
angle = move;
angle += 0xE20;
moveY = sin_s(angle) * guide2->camera_move_range;
if (guide2->camera_move_y <= 0.0f && moveY >= 0.0f) {
s8 cnt = guide2->camera_move_cnt;
cnt--;
if (cnt < 0) {
s8 set_cnt = guide2->camera_move_set_counter;
set_cnt--;
if (set_cnt < 0) {
set_cnt = ARRAY_COUNT(mov_def_cnt) - 1;
}
guide2->camera_move_set_counter = set_cnt;
cnt = mov_def_cnt[set_cnt];
guide2->camera_move_range = 0.3f;
} else {
guide2->camera_move_range *= 0.35f;
}
guide2->camera_move_cnt = cnt;
}
guide2->camera_move_y = moveY;
cur_angle = guide2->camera_tilt_cur_angle;
chase_angle(&cur_angle, guide2->camera_tilt_goal_angle, guide2->camera_tilt_add);
guide2->camera_tilt_cur_angle = cur_angle;
sin = sin_s(cur_angle);
/* Set camera eye pos */
eye.x = moveX + sin * 20.0f + 100.0f;
eye.y = moveY + sin * -5.0f + 80.0f;
eye.z = 400.0f;
/* Move NPC head to current target */
chase_f(&guide2->npc_class.eye_y, obj_look_y_max[obj_look_type], obj_look_y_spd[obj_look_type] * 0.5f);
/* Set ground pos */
ground.x = guide2->npc_class.draw.shadow_pos.x;
ground.z = guide2->npc_class.draw.shadow_pos.z;
if (obj_look_type == aNG2_OBJ_LOOK_TYPE_TALK) {
/* Use the guide2's NPC shadow position for Y */
ground_y = guide2->npc_class.draw.shadow_pos.y;
} else {
/* Get the ground position for Y */
ground_y = mCoBG_GetBgY_OnlyCenter_FromWpos2(ground, 0.0f);
}
chase_f(&guide2->obj_dist_ground, ground_y, 0.5f);
ground.y = guide2->obj_dist_ground;
/* Set camera center pos */
if (guide2->lock_camera_flag == TRUE) {
pos.x = ground.x;
pos.y = ground.y + guide2->npc_class.eye_y;
pos.z = ground.z;
} else if (mDemo_Check(mDemo_TYPE_SPEAK, &guide2->npc_class.actor_class) == TRUE) {
int morph_counter = guide2->camera_morph_counter;
f32 r;
guide2->camera_morph_counter = morph_counter - 1;
if ((morph_counter - 1) == 0) {
guide2->lock_camera_flag = TRUE;
}
r = (40.0f - (f32)(morph_counter - 1)) / 40.0f;
inter = cKF_HermitCalc(r, 1.0f, 0.0f, 1.0f, 3.2f, 0.0f);
pos.x = (ground.x - 90.0f) * inter + 90.0f;
pos.y = ((ground.y + guide2->npc_class.eye_y) - 80.0f) * inter + 80.0f;
pos.z = (ground.z - 280.0f) * inter + 280.0f;
} else {
/* Default position */
pos.x = 90.0f;
pos.y = 80.0f;
pos.z = 280.0f;
}
pos.x += moveX;
pos.y += moveY;
Camera2_change_priority(play, 0);
Camera2_request_main_lock(play, &pos, &eye, 40.0f, 0, 60.0f, 800.0f, 5);
}
static void aNG2_set_camera_eyes(NPC_GUIDE2_ACTOR* guide2) {
if (guide2->camera_eyes_flag == TRUE) {
guide2->npc_class.request.head_pos.x = 100.0f;
guide2->npc_class.request.head_pos.y = guide2->npc_class.actor_class.eye.position.y;
guide2->npc_class.request.head_pos.z = 400.0f;
guide2->npc_class.request.head_priority = 3;
guide2->npc_class.request.head_type = 2;
}
}
static void aNG2_set_walk_spd(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->npc_class.movement.max_speed = 1.0f;
guide2->npc_class.movement.acceleration = 0.1f;
guide2->npc_class.movement.deceleration = 0.2f;
}
static void aNG2_set_walk_spd2(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->npc_class.movement.max_speed = 1.5f;
guide2->npc_class.movement.acceleration = 0.15f;
guide2->npc_class.movement.deceleration = 0.3f;
}
static void aNG2_set_stop_spd(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->npc_class.actor_class.speed = 0.0f;
guide2->npc_class.movement.max_speed = 0.0f;
guide2->npc_class.movement.acceleration = 0.0f;
guide2->npc_class.movement.deceleration = 0.0f;
}
static int aNG2_make_keitai(NPC_GUIDE2_ACTOR* guide2, GAME* game) {
int res = FALSE;
if (guide2->npc_class.right_hand.item_actor_p == NULL) {
if (Common_Get(clip).tools_clip != NULL) {
ACTOR* keitai = Common_Get(clip).tools_clip->aTOL_birth_proc(
TOOL_KEITAI, aTOL_ACTION_TAKEOUT, &guide2->npc_class.actor_class, game, -1, NULL);
if (keitai != NULL) {
guide2->npc_class.right_hand.item_actor_p = keitai;
res = TRUE;
}
}
} else {
res = TRUE;
}
return res;
}
static int aNG2_chg_cond_keitai(NPC_GUIDE2_ACTOR* guide2, int cond) {
int res = FALSE;
if (Common_Get(clip).tools_clip != NULL) {
if (Common_Get(clip).tools_clip->aTOL_chg_request_mode_proc(
&guide2->npc_class.actor_class, guide2->npc_class.right_hand.item_actor_p, cond) == TRUE) {
res = TRUE;
}
}
return res;
}
static void aNG2_talk_demo_proc(ACTOR* actorx) {
if (mDemo_Check(mDemo_TYPE_SPEAK, actorx) == TRUE) {
Common_Get(clip).npc_clip->talk_demo_proc(actorx);
}
}
static u8* aNG2_getP_other_pl_name(void) {
Private_c* priv;
u32 player_no;
int i;
player_no = Common_Get(player_no);
priv = Save_Get(private_data) + player_no;
/* Search for players before this one's player no */
for (i = player_no; i != 0; i--) {
priv--;
if (mPr_NullCheckPersonalID(&priv->player_ID) != TRUE) {
return priv->player_ID.player_name;
}
}
priv = Save_Get(private_data) + player_no;
/* Search for players after this one's player no */
for (i = (PLAYER_NUM - 1) - player_no; i != 0; i--) {
priv++;
if (mPr_NullCheckPersonalID(&priv->player_ID) != TRUE) {
return priv->player_ID.player_name;
}
}
/* No other players to reference */
return NULL;
}
static int aNG2_check_pname(void) {
int ok = TRUE;
int i;
for (i = 0; i < PLAYER_NUM; i++) {
Private_c* priv = Save_GetPointer(private_data[i]);
if (i != Common_Get(player_no)) {
if (mem_cmp(Now_Private->player_ID.player_name, priv->player_ID.player_name, PLAYER_NAME_LEN) == TRUE) {
/* Another player has the same name in this town */
ok = FALSE;
break;
}
}
}
return ok;
}
static void aNG2_check_talk_msg_no(NPC_GUIDE2_ACTOR* guide2) {
if (mDemo_Check(mDemo_TYPE_SPEAK, &guide2->npc_class.actor_class) == TRUE) {
int msg_no = mMsg_GET_MSG_NUM();
int flags;
switch (msg_no) {
case 0x2AC9:
flags = (1 << 3);
break;
case 0x2ADB:
flags = (1 << 2);
break;
case 0x2ADD:
flags = (1 << 1);
break;
case 0x2AD3:
flags = (1 << 0);
break;
default:
flags = 0;
break;
}
guide2->answer_flags |= flags;
}
}
static void aNG2_set_pl_face_type(NPC_GUIDE2_ACTOR* guide2) {
static int face_type_table[mPr_SEX_NUM][mPr_FACE_TYPE_NUM] = {
/* Male faces */
{
mPr_FACE_TYPE5,
mPr_FACE_TYPE6,
mPr_FACE_TYPE1,
mPr_FACE_TYPE4,
mPr_FACE_TYPE0,
mPr_FACE_TYPE2,
mPr_FACE_TYPE7,
mPr_FACE_TYPE3,
},
/* Female faces */
{
mPr_FACE_TYPE0,
mPr_FACE_TYPE5,
mPr_FACE_TYPE2,
mPr_FACE_TYPE6,
mPr_FACE_TYPE4,
mPr_FACE_TYPE7,
mPr_FACE_TYPE3,
mPr_FACE_TYPE1,
},
};
int answer_flags = guide2->answer_flags;
int face_type;
if ((answer_flags & 1) == 0) {
/* Select a random face for the player */
face_type = RANDOM(mPr_FACE_TYPE_NUM);
} else {
/* Select a face based on choices */
face_type = face_type_table[Now_Private->gender][answer_flags >> 1];
}
Now_Private->face = face_type;
}
static void aNG2_calc_body_angl(NPC_GUIDE2_ACTOR* guide2, f32 pos_x, f32 pos_z) {
f32 dX = pos_x - guide2->npc_class.actor_class.world.position.x;
f32 dZ = pos_z - guide2->npc_class.actor_class.world.position.z;
s16 angl = atans_table(dZ, dX);
chase_angle(&guide2->npc_class.actor_class.shape_info.rotation.y, angl, DEG2SHORT_ANGLE2(11.25f));
guide2->npc_class.actor_class.world.angle.y = guide2->npc_class.actor_class.shape_info.rotation.y;
}
static void aNG2_set_default_talk_info(void) {
mDemo_Set_camera(CAMERA2_PROCESS_NUM);
mDemo_Set_talk_change_player(FALSE);
mDemo_Set_use_zoom_sound(TRUE);
}
static void aNG2_enter(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
if (guide2->npc_class.draw.main_animation_state == cKF_STATE_STOPPED) {
guide2->camera_eyes_flag = TRUE;
aNG2_setupAction(guide2, play, aNG2_ACTION_APPROACH);
} else if (cKF_FrameControl_passCheck_now(&guide2->npc_class.draw.main_animation.keyframe.frame_control, 20.0f) ==
TRUE) {
TRAINDOOR_ACTOR* train_door = (TRAINDOOR_ACTOR*)guide2->train_door_actor;
train_door->open_flag = TRUE;
}
}
static void aNG2_approach(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
if (guide2->npc_class.actor_class.world.position.z >= 290.0f) {
guide2->npc_class.actor_class.world.position.z = 290.0f;
aNG2_setupAction(guide2, play, aNG2_ACTION_TALK_START_WAIT);
}
}
static void aNG2_set_talk_info_talk_start_wait(ACTOR* actorx) {
mMsg_SET_FREE_STR(mMsg_FREE_STR0, aNG2_getP_other_pl_name(), PLAYER_NAME_LEN);
mDemo_Set_msg_num(0x2AD5);
aNG2_set_default_talk_info();
((NPC_GUIDE2_ACTOR*)actorx)->obj_look_type = aNG2_OBJ_LOOK_TYPE_TALK;
}
static void aNG2_talk_start_wait(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
ACTOR* actorx = (ACTOR*)guide2;
if (mDemo_Check(mDemo_TYPE_SPEAK, actorx) == TRUE) {
if (mDemo_Check_ListenAble() == FALSE &&
chase_angle(&actorx->shape_info.rotation.y, actorx->player_angle_y, 0x400) == TRUE) {
guide2->camera_eyes_flag = FALSE;
aNG2_setupAction(guide2, play, aNG2_ACTION_WAIT_PERMISSION);
mDemo_Set_ListenAble();
}
} else {
mDemo_Request(mDemo_TYPE_SPEAK, actorx, &aNG2_set_talk_info_talk_start_wait);
}
}
static void aNG2_wait_permission(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
if (mMsg_CHECK_MAINNORMALCONTINUE() == TRUE) {
aNG2_setupAction(guide2, play, aNG2_ACTION_SITDOWN);
}
}
static void aNG2_sitdown(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->npc_class.actor_class.world.position.x = 100.0f;
guide2->npc_class.actor_class.world.position.z = 280.0f;
guide2->npc_class.actor_class.shape_info.rotation.y = 0;
/* Wait for the sit animation to finish before continuing */
if (guide2->npc_class.draw.main_animation_state == cKF_STATE_STOPPED) {
mMsg_UNSET_LOCKCONTINUE();
guide2->next_action = aNG2_ACTION_PNAME_MENU_OPEN_WAIT;
aNG2_setupAction(guide2, play, aNG2_ACTION_SDON_AND_PB_WAIT);
}
}
static void aNG2_sdon_and_pb_wait(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
u16 order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9);
if (order != 0 && mMsg_CHECK_MAINNORMALCONTINUE()) {
aNG2_setupAction(guide2, play, guide2->next_action);
mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0);
}
}
static void aNG2_pname_menu_open_wait(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
if (mMsg_CHECK_MAIN_WAIT() == TRUE) {
aNG2_setupAction(guide2, play, 7);
}
}
static void aNG2_pname_menu_close_wait(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
if (play->submenu.open_flag == FALSE) {
aNG2_setupAction(guide2, play, 8);
}
}
static void aNG2_msg_win_open_wait(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
static int msg_no[] = { 0x2ACA, 0x2AE2 };
static int next_act_idx[] = { 10, 9 };
mMsg_Window_c* msg_p = mMsg_Get_base_window_p();
if (mMsg_Check_not_series_main_wait(msg_p) == TRUE) {
int idx = 0;
mMsg_Unset_LockContinue(msg_p);
/* Check if the player's name already exists in town */
if (aNG2_check_pname() == FALSE) {
idx = 1;
}
mMsg_Set_continue_msg_num(msg_p, msg_no[idx]);
mMsg_Set_ForceNext(msg_p);
aNG2_setupAction(guide2, play, next_act_idx[idx]);
}
}
static void aNG2_sex_select_wait(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
if (mMsg_CHECK_MAINNORMALCONTINUE() == TRUE) {
switch (mChoice_GET_CHOSENUM()) {
case mChoice_CHOICE0: // male
case mChoice_CHOICE1: // female
aNG2_setupAction(guide2, play, aNG2_ACTION_SEX_SELECT_WAIT2);
break;
case mChoice_CHOICE2: // 'That's not right'
guide2->next_action = aNG2_ACTION_PNAME_MENU_OPEN_WAIT;
aNG2_setupAction(guide2, play, aNG2_ACTION_SDON_AND_PB_WAIT);
break;
}
}
}
static void aNG2_sex_select_wait2(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
static int next_act_idx[] = { aNG2_ACTION_STANDUP_START_WAIT, aNG2_ACTION_SEX_SELECT_AFTER };
int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9);
if (order != 0) {
mMsg_Window_c* msg_p = mMsg_Get_base_window_p();
if (mMsg_Check_MainNormalContinue(msg_p) == TRUE) {
int idx = -1;
switch (mChoice_GET_CHOSENUM()) {
case mChoice_CHOICE0: // male
switch (order) {
case 1: // That's right
Now_Private->gender = mPr_SEX_MALE;
break;
case 2: // I'm not a boy
Now_Private->gender = mPr_SEX_FEMALE;
break;
}
idx = 0;
mMsg_Set_continue_msg_num(msg_p, 0x2AD9);
mMsg_Set_ForceNext(msg_p);
break;
case mChoice_CHOICE1: // female
switch (order) {
case 1: // That's right
Now_Private->gender = mPr_SEX_FEMALE;
break;
case 2: // I'm not a girl
Now_Private->gender = mPr_SEX_MALE;
break;
}
idx = 1;
break;
}
if (idx != -1) {
aNG2_setupAction(guide2, play, next_act_idx[idx]);
mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0);
}
}
}
}
static void aNG2_sex_select_after(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
mMsg_Window_c* msg_p = mMsg_Get_base_window_p();
u16 order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9);
if (order != 0 && mMsg_Check_MainNormalContinue(msg_p)) {
aNG2_setupAction(guide2, play, aNG2_ACTION_STANDUP_START_WAIT);
mMsg_Set_continue_msg_num(msg_p, 0x2AD9);
mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0);
}
}
static void aNG2_standup_start_wait(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
/* Wait for guide2 to stop speaking to us */
if (mDemo_Check(mDemo_TYPE_SPEAK, &guide2->npc_class.actor_class) == FALSE) {
guide2->obj_look_type = aNG2_OBJ_LOOK_TYPE_NORMAL;
aNG2_setupAction(guide2, play, aNG2_ACTION_STANDUP);
}
}
static void aNG2_standup(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
/* Wait for animation to finish */
if (guide2->npc_class.draw.main_animation_state == cKF_STATE_STOPPED) {
aNG2_setupAction(guide2, play, guide2->next_action);
}
}
static void aNG2_move_ready(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->npc_class.actor_class.world.position.x = 100.0f;
guide2->npc_class.actor_class.world.position.z = 300.0f;
aNG2_setupAction(guide2, play, aNG2_ACTION_MOVE_TO_AISLE);
}
static void aNG2_move_to_aisle(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
aNG2_calc_body_angl(guide2, 140.0f, 290.0f);
if (guide2->npc_class.actor_class.world.position.x > 140.0f) {
aNG2_setupAction(guide2, play, aNG2_ACTION_MOVE_TO_DOOR);
}
}
static void aNG2_move_to_door(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
aNG2_calc_body_angl(guide2, 140.0f, 130.0f);
/* Check if we reached the door */
if (guide2->npc_class.actor_class.world.position.z < 130.0f) {
aNG2_setupAction(guide2, play, aNG2_ACTION_MOVE_TO_DECK);
}
/* Check if we should start rotating */
if (guide2->npc_class.draw.shadow_pos.z < 140.0f) {
guide2->camera_tilt_goal_angle = DEG2SHORT_ANGLE2(90.0f);
guide2->camera_tilt_add = DEG2SHORT_ANGLE2(2.8125f);
}
}
static void aNG2_move_to_deck(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
if (cKF_FrameControl_passCheck_now(&guide2->npc_class.draw.main_animation.keyframe.frame_control, 9.0f) == TRUE) {
TRAINDOOR_ACTOR* train_door = (TRAINDOOR_ACTOR*)guide2->train_door_actor;
train_door->open_flag = TRUE;
}
/* Reuse standup state to wait for animation to finish */
aNG2_standup(guide2, play);
}
static void aNG2_set_talk_info_keitai_on(ACTOR* actorx) {
mDemo_Set_msg_num(0x2ADE);
aNG2_set_default_talk_info();
}
static void aNG2_keitai_on(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
static f32 anmSpd[] = { 0.0f, 0.5f };
int idx = aNG2_make_keitai(guide2, &play->game);
guide2->npc_class.draw.main_animation.keyframe.frame_control.speed = anmSpd[idx];
if (idx != 0) {
if (mDemo_Check(mDemo_TYPE_SPEAK, (ACTOR*)guide2) == TRUE) {
if (mDemo_Check_ListenAble() == FALSE) {
mDemo_Set_ListenAble();
}
} else {
/* Request to start speaking */
mDemo_Request(mDemo_TYPE_SPEAK, (ACTOR*)guide2, &aNG2_set_talk_info_keitai_on);
}
}
/* Wait for animation to finish */
if (guide2->npc_class.draw.main_animation_state == cKF_STATE_STOPPED) {
aNG2_setupAction(guide2, play, aNG2_ACTION_KEITAI_TALK);
}
}
static void aNG2_keitai_talk(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
if (mDemo_Check(mDemo_TYPE_SPEAK, &guide2->npc_class.actor_class) == FALSE) {
aNG2_setupAction(guide2, play, aNG2_ACTION_KEITAI_OFF);
} else if (guide2->npc_class.draw.main_animation_state == cKF_STATE_STOPPED) {
Common_Get(clip).npc_clip->animation_init_proc(&guide2->npc_class.actor_class, aNPC_ANIM_KEITAI_TALK2, TRUE);
}
}
static void aNG2_open_door(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
chase_angle(&guide2->npc_class.actor_class.shape_info.rotation.y, DEG2SHORT_ANGLE2(-180.0f),
DEG2SHORT_ANGLE2(0.703125f));
if (cKF_FrameControl_passCheck_now(&guide2->npc_class.draw.main_animation.keyframe.frame_control, 22.0f) == TRUE) {
TRAINDOOR_ACTOR* train_door = (TRAINDOOR_ACTOR*)guide2->train_door_actor;
train_door->open_flag = TRUE;
if (guide2->npc_class.draw.shadow_pos.z < 140.0f) {
guide2->camera_tilt_goal_angle = 0;
guide2->camera_tilt_add = 0x600;
}
}
/* Reuse standup state to wait for animation to finish */
aNG2_standup(guide2, play);
}
static void aNG2_return_approach(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->npc_class.actor_class.world.position.x = 140.0f;
guide2->npc_class.actor_class.world.angle.y = 0;
guide2->npc_class.actor_class.shape_info.rotation.y = 0;
if (guide2->npc_class.actor_class.world.position.z > 290.0f) {
aNG2_setupAction(guide2, play, aNG2_ACTION_LAST_TALK_START_WAIT);
}
}
static void aNG2_set_talk_info_last_talk_start_wait(ACTOR* actorx) {
mDemo_Set_msg_num(0x2AD1);
aNG2_set_default_talk_info();
((NPC_GUIDE2_ACTOR*)actorx)->obj_look_type = aNG2_OBJ_LOOK_TYPE_TALK;
}
static void aNG2_last_talk_start_wait(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
ACTOR* actorx = (ACTOR*)guide2;
if (mDemo_Check(mDemo_TYPE_SPEAK, actorx) == TRUE) {
if (mDemo_Check_ListenAble() == FALSE &&
chase_angle(&actorx->shape_info.rotation.y, actorx->player_angle_y, 0x400) == TRUE) {
guide2->camera_eyes_flag = FALSE;
aNG2_setupAction(guide2, play, aNG2_ACTION_SITDOWN2_START_WAIT);
mDemo_Set_ListenAble();
}
} else {
mDemo_Request(mDemo_TYPE_SPEAK, actorx, &aNG2_set_talk_info_last_talk_start_wait);
}
}
static void aNG2_sitdown2_start_wait(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
u16 order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9);
if (order != 0) {
aNG2_setupAction(guide2, play, aNG2_ACTION_SITDOWN2);
mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0);
}
}
static void aNG2_sitdown2(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->npc_class.actor_class.world.position.x = 100.0f;
guide2->npc_class.actor_class.world.position.z = 280.0f;
guide2->npc_class.actor_class.shape_info.rotation.y = 0;
/* Wait for animation to finish */
aNG2_standup(guide2, play);
}
static void aNG2_last_talk_end_wait(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
if (mDemo_Check(mDemo_TYPE_SPEAK, &guide2->npc_class.actor_class) == FALSE) {
aNG2_setupAction(guide2, play, aNG2_ACTION_SCENE_CHANGE_WAIT);
}
}
/* Init procs */
static void aNG2_sitdown_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
mMsg_SET_LOCKCONTINUE();
}
static void aNG2_pname_menu_open_wait_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
mMsg_Window_c* msg_p = mMsg_Get_base_window_p();
mMsg_Set_LockContinue(msg_p);
mMsg_request_main_disappear_wait_type1(msg_p);
}
static void aNG2_pname_menu_close_wait_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
Submenu* submenu = &play->submenu;
mSM_open_submenu(submenu, mSM_OVL_LEDIT, mLE_TYPE_PLAYER_NAME, 0);
}
static void aNG2_msg_win_open_wait_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
mMsg_REQUEST_MAIN_APPEAR_WAIT_TYPE1();
}
static void aNG2_pname_ng_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->next_action = 6;
}
static void aNG2_standup_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->next_action = aNG2_ACTION_MOVE_READY;
}
static void aNG2_move_ready_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->npc_class.draw.main_animation.keyframe.morph_counter = 0.0f;
}
static void aNG2_move_to_aisle_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
aNG2_set_walk_spd2(guide2, play);
}
static void aNG2_move_to_deck_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
aNG2_set_stop_spd(guide2, play);
guide2->npc_class.actor_class.world.position.x = 140.0f;
guide2->npc_class.actor_class.world.position.z = 130.0f;
guide2->next_action = aNG2_ACTION_KEITAI_ON;
}
static void aNG2_keitai_off_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
aNG2_chg_cond_keitai(guide2, aTOL_ACTION_PUTAWAY);
guide2->next_action = aNG2_ACTION_OPEN_DOOR;
}
static void aNG2_open_door_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->next_action = aNG2_ACTION_RETURN_APPROACH;
}
static void aNG2_return_approach_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->camera_eyes_flag = TRUE;
aNG2_set_walk_spd2(guide2, play);
guide2->npc_class.draw.main_animation.keyframe.morph_counter = 0.0f;
}
static void aNG2_sitdown2_start_wait_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0);
}
static void aNG2_sitdown2_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
guide2->npc_class.draw.main_animation.keyframe.morph_counter = 0.0f;
guide2->next_action = aNG2_ACTION_LAST_TALK_END_WAIT;
}
static void aNG2_last_talk_end_wait_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
aNG2_chg_cond_keitai(guide2, aTOL_ACTION_DESTRUCT);
guide2->npc_class.right_hand.item_actor_p = NULL;
}
static void aNG2_scene_change_wait_init(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) {
/* Init next scene transition */
goto_next_scene(play, 0, 1);
play->fb_wipe_type = 3;
Common_Get(transition).wipe_type = 4;
mEv_SetFirstJob();
mEv_SetFirstIntro();
mEnv_DecideWeather_NormalGameStart();
aNG2_set_pl_face_type(guide2);
mPr_SetNowPrivateCloth();
Common_Set(submenu_disabled, TRUE);
mBGMPsComp_make_ps_wipe(0x41C2);
mBGMPsComp_scene_mode(18);
}
typedef void (*aNG2_INIT_PROC)(NPC_GUIDE2_ACTOR*, GAME_PLAY*);
static void aNG2_init_proc(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play, int action) {
static aNG2_INIT_PROC init_proc[] = {
(aNG2_INIT_PROC)&none_proc1,
&aNG2_set_walk_spd,
&aNG2_set_stop_spd,
(aNG2_INIT_PROC)&none_proc1,
&aNG2_sitdown_init,
(aNG2_INIT_PROC)&none_proc1,
&aNG2_pname_menu_open_wait_init,
&aNG2_pname_menu_close_wait_init,
&aNG2_msg_win_open_wait_init,
&aNG2_pname_ng_init,
(aNG2_INIT_PROC)&none_proc1,
(aNG2_INIT_PROC)&none_proc1,
(aNG2_INIT_PROC)&none_proc1,
(aNG2_INIT_PROC)&none_proc1,
&aNG2_standup_init,
&aNG2_move_ready_init,
&aNG2_move_to_aisle_init,
(aNG2_INIT_PROC)&none_proc1,
&aNG2_move_to_deck_init,
(aNG2_INIT_PROC)&none_proc1,
(aNG2_INIT_PROC)&none_proc1,
&aNG2_keitai_off_init,
&aNG2_open_door_init,
&aNG2_return_approach_init,
&aNG2_set_stop_spd,
&aNG2_sitdown2_start_wait_init,
&aNG2_sitdown2_init,
&aNG2_last_talk_end_wait_init,
&aNG2_scene_change_wait_init,
};
(*init_proc[action])(guide2, play);
}
static void aNG2_setupAction(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play, int action) {
static aNG2_PROC process[] = {
&aNG2_enter,
&aNG2_approach,
&aNG2_talk_start_wait,
&aNG2_wait_permission,
&aNG2_sitdown,
&aNG2_sdon_and_pb_wait,
&aNG2_pname_menu_open_wait,
&aNG2_pname_menu_close_wait,
&aNG2_msg_win_open_wait,
&aNG2_sdon_and_pb_wait,
&aNG2_sex_select_wait,
&aNG2_sex_select_wait2,
&aNG2_sex_select_after,
&aNG2_standup_start_wait,
&aNG2_standup,
&aNG2_move_ready,
&aNG2_move_to_aisle,
&aNG2_move_to_door,
&aNG2_move_to_deck,
&aNG2_keitai_on,
&aNG2_keitai_talk,
&aNG2_standup,
&aNG2_open_door,
&aNG2_return_approach,
&aNG2_last_talk_start_wait,
&aNG2_sitdown2_start_wait,
&aNG2_sitdown2,
&aNG2_last_talk_end_wait,
(aNG2_PROC)&none_proc1,
};
guide2->action = action;
guide2->proc = process[action];
aNG2_set_animation(guide2, action);
aNG2_init_proc(guide2, play, action);
}
static void aNG2_actor_move(ACTOR* actorx, GAME* game) {
NPC_GUIDE2_ACTOR* guide2 = (NPC_GUIDE2_ACTOR*)actorx;
GAME_PLAY* play = (GAME_PLAY*)game;
Common_Get(clip).npc_clip->move_before_proc(actorx, game);
aNG2_talk_demo_proc(actorx);
aNG2_check_talk_msg_no(guide2);
(*guide2->proc)(guide2, play);
Common_Get(clip).npc_clip->move_after_proc(actorx, game);
aNG2_set_camera(guide2, play);
aNG2_set_camera_eyes(guide2);
mSC_change_player_freeze(play);
}
+4 -1
View File
@@ -47,7 +47,10 @@ static void aNGD_set_animation(NPC_GUIDE_ACTOR* guide, int action) {
int anim_id = anime_info->anim_id;
int talk_flag = anime_info->talk_flag;
if ((action == 4 || action == 7 || action == 8) && guide->next_action != 5 && guide->next_action != 6) {
if ((action == aNGD_ACTION_SDON_AND_PB_WAIT || action == aNGD_ACTION_MSG_WIN_OPEN_WAIT ||
action == aNGD_ACTION_CONFIRM_INPUT_DATA) &&
guide->next_action != aNGD_ACTION_TIME_MENU_OPEN_WAIT &&
guide->next_action != aNGD_ACTION_TIME_MENU_CLOSE_WAIT) {
anim_id = aNPC_ANIM_SITDOWN_WAIT_D1;
talk_flag = TRUE;
}