Implement & link ac_npc_station_master

This commit is contained in:
Cuyler36
2025-06-14 07:18:38 -04:00
parent c130410fa3
commit 29783fb14c
6 changed files with 746 additions and 1 deletions
+1 -1
View File
@@ -1142,7 +1142,7 @@ config.libs = [
Object(Matching, "actor/npc/ac_npc_shop_mastersp.c"),
Object(Matching, "actor/npc/ac_npc_sleep_obaba.c"),
Object(Matching, "actor/npc/ac_npc_soncho.c"),
Object(NonMatching, "actor/npc/ac_npc_station_master.c"),
Object(Matching, "actor/npc/ac_npc_station_master.c"),
Object(Matching, "actor/npc/ac_npc_super_master.c"),
Object(Matching, "actor/npc/ac_npc_totakeke.c"),
Object(Matching, "actor/npc/ac_present_npc.c"),
+8
View File
@@ -46,6 +46,14 @@ enum {
aSTM_THINK_PROC_NUM
};
enum {
aSTM_TALK_REQUEST_NONE,
aSTM_TALK_REQUEST_NORM,
aSTM_TALK_REQUEST_FORCE,
aSTM_TALK_REQUEST_NUM,
};
typedef struct npc_station_actor_s NPC_STATION_MASTER_ACTOR;
typedef void (*aSTM_TALK_PROC)(NPC_STATION_MASTER_ACTOR*, GAME_PLAY*);
+126
View File
@@ -0,0 +1,126 @@
#include "ac_npc_station_master.h"
#include "libultra/libultra.h"
#include "m_common_data.h"
#include "m_msg.h"
#include "m_font.h"
#include "m_player_lib.h"
#include "m_string.h"
#include "m_bgm.h"
#include "m_train_control.h"
#include "ac_intro_demo.h"
#include "ac_ride_off_demo.h"
enum {
aSTM_THINK_GET_OFF_WAIT,
aSTM_THINK_TURN,
aSTM_THINK_2,
aSTM_THINK_3,
aSTM_THINK_4,
aSTM_THINK_5,
aSTM_THINK_INTERRUPT_TURN,
aSTM_THINK_INTERRUPT_MOVE,
aSTM_THINK_8,
aSTM_THINK_9,
aSTM_THINK_MAKE_TRAIN_BF,
aSTM_THINK_MAKE_TRAIN,
aSTM_THINK_TRAIN_ARRIVE_WAIT,
aSTM_THINK_MOVE_TURN_BF,
aSTM_THINK_14,
aSTM_THINK_MOVE,
aSTM_THINK_16,
aSTM_THINK_17,
aSTM_THINK_IN_TRAIN,
aSTM_THINK_IN_TRAIN2,
aSTM_THINK_SEE_OFF,
aSTM_THINK_GAME_END,
aSTM_THINK_NUM
};
static void aSTM_actor_ct(ACTOR* actorx, GAME* game);
static void aSTM_actor_dt(ACTOR* actorx, GAME* game);
static void aSTM_actor_init(ACTOR* actorx, GAME* game);
static void aSTM_actor_save(ACTOR* actorx, GAME* game);
static void aSTM_actor_move(ACTOR* actorx, GAME* game);
static void aSTM_actor_draw(ACTOR* actorx, GAME* game);
static int aSTM_talk_init(ACTOR* actorx, GAME* game);
static int aSTM_talk_end_chk(ACTOR* actorx, GAME* game);
static void aSTM_schedule_proc(NPC_ACTOR*, GAME_PLAY*, int);
static void aSTM_talk_request(ACTOR* actorx, GAME* game);
static int aSTM_change_talk_proc(NPC_STATION_MASTER_ACTOR*, u8);
static void aSTM_setup_think_proc(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play, u8 think_idx);
// clang-format off
ACTOR_PROFILE Npc_Station_Master_Profile = {
mAc_PROFILE_NPC_STATION_MASTER,
ACTOR_PART_NPC,
ACTOR_STATE_NONE,
SP_NPC_STATION_MASTER,
ACTOR_OBJ_BANK_KEEP,
sizeof(NPC_STATION_MASTER_ACTOR),
aSTM_actor_ct,
aSTM_actor_dt,
aSTM_actor_init,
mActor_NONE_PROC1,
aSTM_actor_save
};
// clang-format on
static void aSTM_actor_ct(ACTOR* actorx, GAME* game) {
// clang-format off
static aNPC_ct_data_c ct_data = {
aSTM_actor_move,
aSTM_actor_draw,
aNPC_CT_SCHED_TYPE_SPECIAL,
(aNPC_TALK_REQUEST_PROC)none_proc1,
aSTM_talk_init,
aSTM_talk_end_chk,
0
};
// clang-format on
if (NPC_CLIP->birth_check_proc(actorx, game) == TRUE) {
NPC_STATION_MASTER_ACTOR* actor = (NPC_STATION_MASTER_ACTOR*)actorx;
actor->npc_class.schedule.schedule_proc = aSTM_schedule_proc;
NPC_CLIP->ct_proc(actorx, game, &ct_data);
actor->sound = 0;
actor->happening_sound = 0;
actor->melody_save = 0;
actor->npc_class.palActorIgnoreTimer = -1;
}
}
static void aSTM_actor_save(ACTOR* actorx, GAME* game) {
mNpc_RenewalSetNpc(actorx);
}
static void aSTM_actor_dt(ACTOR* actorx, GAME* game) {
NPC_STATION_MASTER_ACTOR* actor = (NPC_STATION_MASTER_ACTOR*)actorx;
if (actor->sound != 0) {
mBGMPsComp_delete_ps_demo(actor->sound, 0x168);
}
switch (actor->happening_sound) {
case BGM_INTRO_ARRIVE:
case BGM_INTRO_NEW_TOWN:
mBGMPsComp_delete_ps_happening(actor->happening_sound, 0x168);
break;
}
NPC_CLIP->dt_proc(actorx, game);
}
static void aSTM_actor_init(ACTOR* actorx, GAME* game) {
NPC_CLIP->init_proc(actorx, game);
}
static void aSTM_actor_draw(ACTOR* actorx, GAME* game) {
NPC_CLIP->draw_proc(actorx, game);
}
#include "../src/actor/npc/ac_npc_station_master_move.c_inc"
#include "../src/actor/npc/ac_npc_station_master_talk.c_inc"
#include "../src/actor/npc/ac_npc_station_master_schedule.c_inc"
@@ -0,0 +1,24 @@
static int aSTM_set_request_act(NPC_STATION_MASTER_ACTOR* actor, u8 priority, u8 act_idx, u8 act_type, u16 act_obj, s16 move_x, s16 move_z) {
int ret = FALSE;
if (priority >= actor->npc_class.request.act_priority) {
u16 arg_data[aNPC_REQUEST_ARG_NUM];
bzero(arg_data, sizeof(arg_data));
arg_data[0] = act_obj;
arg_data[2] = move_x;
arg_data[3] = move_z;
actor->npc_class.request.act_priority = priority;
actor->npc_class.request.act_idx = act_idx;
actor->npc_class.request.act_type = act_type;
mem_copy((u8*)actor->npc_class.request.act_args, (u8*)arg_data, sizeof(arg_data));
ret = TRUE;
}
return ret;
}
static void aSTM_actor_move(ACTOR* actorx, GAME* game) {
NPC_CLIP->move_proc(actorx, game);
}
@@ -0,0 +1,463 @@
static void aSTM_Change_sound(NPC_STATION_MASTER_ACTOR* actor, u8 sound) {
if (actor->sound != sound) {
mBGMPsComp_make_ps_demo(sound, 0x168);
if (actor->sound == BGM_FIELD_00) {
mBGMPsComp_delete_ps_quiet();
}
actor->sound = sound;
}
}
typedef struct npc_p_sel2_door_data_s {
int scene_no;
u8 drt;
u8 type;
u16 arg;
s16 pos_x;
s16 pos_z;
} aNPS2_door_data_c;
static void aNPS2_make_door_data(Door_data_c* door_data) {
static aNPS2_door_data_c demo2_data = { SCENE_START_DEMO3, mSc_DIRECT_NORTH, 0, 0, 120, 340 };
door_data->next_scene_id = demo2_data.scene_no;
door_data->exit_orientation = demo2_data.drt;
door_data->exit_type = demo2_data.type;
door_data->extra_data = demo2_data.arg;
door_data->exit_position.x = demo2_data.pos_x;
door_data->exit_position.y = 0;
door_data->exit_position.z = demo2_data.pos_z;
door_data->door_actor_name = EMPTY_NO;
door_data->wipe_type = 5;
Common_Get(transition).wipe_type = 3;
}
static int aNPS2_setup_game_start(GAME_PLAY* play) {
Door_data_c door_data;
aNPS2_make_door_data(&door_data);
if (goto_other_scene(play, &door_data, TRUE) != TRUE) {
return FALSE;
}
mBGMPsComp_make_ps_wipe(0x328A);
return TRUE;
}
static void aSTM_look_player(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
if (actor->npc_class.action.step == aNPC_ACTION_END_STEP) {
s16 diff_angle = DIFF_SHORT_ANGLE(actor->npc_class.actor_class.player_angle_y, actor->npc_class.actor_class.shape_info.rotation.y);
u8 action = aNPC_ACT_TURN2;
if (ABS(diff_angle) < DEG2SHORT_ANGLE2(67.5f)) {
action = aNPC_ACT_WAIT;
} else {
actor->npc_class.condition_info.demo_flg |= aNPC_COND_DEMO_SKIP_FOOTSTEPS;
}
aSTM_set_request_act(actor, 4, action, aNPC_ACT_TYPE_SEARCH, aNPC_ACT_OBJ_PLAYER, 0, 0);
}
}
static void aSTM_talk_wait(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
ACTOR* playerx = GET_PLAYER_ACTOR_ACTOR(play);
aSTM_look_player(actor, play);
if (actor->happening_sound == BGM_INTRO_ARRIVE || actor->happening_sound == BGM_INTRO_NEW_TOWN) {
if (playerx != NULL && playerx->world.position.z >= 970.0f) {
if (actor->happening_sound == BGM_INTRO_ARRIVE) {
mBGMPsComp_delete_ps_happening(BGM_INTRO_ARRIVE, 0x384);
} else {
mBGMPsComp_delete_ps_happening(BGM_INTRO_NEW_TOWN, 0x528A);
}
mBGMPsComp_make_ps_co_quiet(0x384, 0x12C);
actor->happening_sound = BGM_SILENCE;
}
}
}
static f32 player_x_drt(NPC_STATION_MASTER_ACTOR* actor) {
if (actor->npc_class.actor_class.player_angle_y < 0) {
return 1.0f;
} else {
return -1.0f;
}
}
static void aSTM_get_off_wait(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
aSTM_look_player(actor, play);
if (CLIP(demo_clip) != NULL) {
ACTOR* demox = (ACTOR*)CLIP(demo_clip)->demo_class;
if (demox != NULL) {
switch (CLIP(demo_clip)->type) {
case mDemo_CLIP_TYPE_INTRO_DEMO: {
INTRO_DEMO_ACTOR* demo_actor = (INTRO_DEMO_ACTOR*)demox;
// train1 arg0 is passenger flag
if (mEv_CheckFirstIntro() && demo_actor->train1_actor_p != NULL && !demo_actor->train1_actor_p->arg0) {
if (mPlib_get_player_actor_main_index((GAME*)play) != mPlayer_INDEX_DEMO_GETOFF_TRAIN) {
aSTM_setup_think_proc(actor, play, aSTM_THINK_TURN);
}
}
break;
}
case mDemo_CLIP_TYPE_RIDE_OFF_DEMO: {
RIDE_OFF_DEMO_ACTOR* demo_actor = (RIDE_OFF_DEMO_ACTOR*)demox;
actor->happening_sound = mBGMPsComp_execute_bgm_num_get();
// train1 arg0 is passenger flag
if (demo_actor->train_actor != NULL && !demo_actor->train_actor->arg0) {
if (mPlib_get_player_actor_main_index((GAME*)play) != mPlayer_INDEX_DEMO_GETOFF_TRAIN) {
aSTM_setup_think_proc(actor, play, aSTM_THINK_TURN);
mBGMPsComp_scene_mode(1);
if (Common_Get(player_no) != mPr_FOREIGNER) {
actor->next_think_idx = aSTM_THINK_3;
}
}
}
break;
}
}
}
}
}
static void aSTM_turn(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
aSTM_setup_think_proc(actor, play, actor->next_think_idx);
}
static void aSTM_interrupt_turn(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
aSTM_setup_think_proc(actor, play, actor->think_idx + 1);
}
static void aSTM_interrupt_move(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
u8 think_idx = aSTM_THINK_9;
mEv_UnSetGateway();
if (mEv_CheckFirstIntro() == TRUE) {
think_idx = aSTM_THINK_4;
} else if (Common_Get(player_no) < mPr_FOREIGNER) {
think_idx = aSTM_THINK_8;
}
actor->npc_class.condition_info.demo_flg = 0;
play->submenu.start_refuse = FALSE;
aSTM_setup_think_proc(actor, play, think_idx);
}
static void aSTM_make_train_bf(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
STRUCTURE_ACTOR* train1 = (STRUCTURE_ACTOR*)Actor_info_fgName_search(&play->actor_info, TRAIN1, ACTOR_PART_ITEM);
if (actor->timer != 0) {
actor->timer--;
} else if (train1 == NULL || train1->action > 5) { // TODO: train1 needs action enum
actor->train_actor_p = NULL;
aSTM_setup_think_proc(actor, play, aSTM_THINK_MAKE_TRAIN);
} else {
actor->train_actor_p = (ACTOR*)train1;
Common_Set(train_coming_flag, 2);
aSTM_setup_think_proc(actor, play, aSTM_THINK_TRAIN_ARRIVE_WAIT);
aSTM_Change_sound(actor, BGM_TRAIN_PULL_INTO_TOWN);
}
}
static void aSTM_make_train(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
STRUCTURE_ACTOR* train1 = (STRUCTURE_ACTOR*)Actor_info_fgName_search(&play->actor_info, TRAIN1, ACTOR_PART_ITEM);
if (train1 != NULL && train1->action <= 5) {
actor->train_actor_p = (ACTOR*)train1;
aSTM_setup_think_proc(actor, play, aSTM_THINK_TRAIN_ARRIVE_WAIT);
}
if (Common_Get(train_approaching_flag) == TRUE) {
aSTM_Change_sound(actor, BGM_TRAIN_PULL_INTO_TOWN);
}
}
static void aSTM_train_arrive_wait(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
STRUCTURE_ACTOR* train1 = (STRUCTURE_ACTOR*)actor->train_actor_p;
if (train1 != NULL && train1->action == 5) {
aSTM_setup_think_proc(actor, play, aSTM_THINK_14);
}
if (Common_Get(train_approaching_flag) == TRUE) {
aSTM_Change_sound(actor, BGM_TRAIN_PULL_INTO_TOWN);
}
}
static void aSTM_move_turn_bf(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
aSTM_setup_think_proc(actor, play, aSTM_THINK_14);
}
static void aSTM_move(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
if (mPlib_get_player_actor_main_index((GAME*)play) != mPlayer_INDEX_DEMO_WALK) {
mPlib_request_main_demo_walk_type1((GAME*)play, actor->npc_class.actor_class.home.position.x + mFI_UT_WORLDSIZE_X_F, actor->train_actor_p->world.position.z + 2 * mFI_UT_WORLDSIZE_Z_F, 2.0f, FALSE);
} else {
aSTM_setup_think_proc(actor, play, aSTM_THINK_16);
}
}
static void aSTM_in_train(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
xyz_t pos;
aSTM_look_player(actor, play);
if (mPlib_get_player_actor_main_index((GAME*)play) != mPlayer_INDEX_DEMO_GETON_TRAIN) {
pos.x = actor->npc_class.actor_class.home.position.x + mFI_UT_WORLDSIZE_X_F;
pos.y = actor->train_actor_p->world.position.y + 20.0f;
pos.z = actor->train_actor_p->world.position.z + 2 * mFI_UT_WORLDSIZE_Z_F;
mPlib_request_main_demo_geton_train_type1((GAME*)play, &pos);
} else {
aSTM_setup_think_proc(actor, play, aSTM_THINK_IN_TRAIN2);
}
}
static void aSTM_in_train2(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
aSTM_look_player(actor, play);
if (mPlib_get_player_actor_main_index((GAME*)play) != mPlayer_INDEX_DEMO_GETON_TRAIN) {
aSTM_setup_think_proc(actor, play, aSTM_THINK_SEE_OFF);
}
}
static void aSTM_see_off(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
f32 dist = 315.5f - (actor->npc_class.actor_class.world.position.x - actor->npc_class.actor_class.home.position.x);
aSTM_look_player(actor, play);
if (actor->npc_class.actor_class.player_distance_xz > dist) {
aSTM_setup_think_proc(actor, play, aSTM_THINK_GAME_END);
}
}
typedef void (*aSTM_THINK_PROC)(NPC_STATION_MASTER_ACTOR*, GAME_PLAY*);
// clang-format off
static aSTM_THINK_PROC proc_table[] = {
(aSTM_THINK_PROC)none_proc1,
aSTM_get_off_wait,
aSTM_turn,
aSTM_look_player,
aSTM_interrupt_turn,
aSTM_interrupt_move,
aSTM_make_train_bf,
aSTM_make_train,
aSTM_train_arrive_wait,
aSTM_move_turn_bf,
aSTM_move,
aSTM_in_train,
aSTM_in_train2,
aSTM_see_off,
aSTM_talk_wait,
};
// clang-format on
static void aSTM_think_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) {
NPC_STATION_MASTER_ACTOR* actor = (NPC_STATION_MASTER_ACTOR*)nactorx;
if (nactorx->action.step == aNPC_ACTION_END_STEP || actor->think_idx == aSTM_THINK_SEE_OFF) {
(*proc_table[actor->think_proc_idx])(actor, play);
}
}
static void aSTM_think_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) {
NPC_STATION_MASTER_ACTOR* actor = (NPC_STATION_MASTER_ACTOR*)nactorx;
u8 think_idx;
ACTOR* actorx = (ACTOR*)actor;
if (mEv_CheckFirstIntro() == TRUE || Actor_info_name_search(&play->actor_info, mAc_PROFILE_RIDE_OFF_DEMO, ACTOR_PART_CONTROL) != NULL) {
think_idx = aSTM_THINK_GET_OFF_WAIT;
actorx->shape_info.rotation.y += DEG2SHORT_ANGLE2(-90.0f);
actorx->world.angle.y += DEG2SHORT_ANGLE2(-90.0f);
} else if (mEv_CheckFirstJob() == TRUE) {
think_idx = aSTM_THINK_5;
} else {
if (mEv_CheckTitleDemo() <= 0) {
actorx->world.position.x += mFI_UT_WORLDSIZE_X_F;
}
if (Common_Get(player_no) < mPr_FOREIGNER) {
think_idx = aSTM_THINK_8;
} else {
think_idx = aSTM_THINK_9;
}
}
actorx->status_data.weight = MASSTYPE_IMMOVABLE;
nactorx->condition_info.hide_request = FALSE;
aSTM_setup_think_proc(actor, play, think_idx);
}
static void aSTM_get_off_wait_init(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
actor->npc_class.condition_info.demo_flg |= aNPC_COND_DEMO_SKIP_FOOTSTEPS;
aSTM_set_request_act(actor, 4, aNPC_ACT_TURN2, aNPC_ACT_TYPE_SEARCH, aNPC_ACT_OBJ_PLAYER, 0, 0);
}
static void aSTM_intro_demo_wait_init(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
static xyz_t enter_pos = { 54.5f * mFI_UT_WORLDSIZE_X_F, 0.0f, 20.5f * mFI_UT_WORLDSIZE_Z_F };
aSTM_get_off_wait_init(actor, play);
mCoBG_SetAttribute(enter_pos, mCoBG_ATTRIBUTE_32);
}
static void aSTM_interrupt_turn_init(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
actor->npc_class.condition_info.demo_flg |= aNPC_COND_DEMO_SKIP_FOOTSTEPS;
aSTM_set_request_act(actor, 4, aNPC_ACT_TURN2, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, actor->npc_class.actor_class.world.position.x + mFI_UT_WORLDSIZE_X_F, actor->npc_class.actor_class.world.position.z);
}
static void aSTM_interrupt_move_init(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
actor->npc_class.condition_info.demo_flg = aNPC_COND_DEMO_SKIP_FORWARD_CHECK | aNPC_COND_DEMO_SKIP_OBJ_COL_CHECK;
aSTM_set_request_act(actor, 4, aNPC_ACT_WALK, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, actor->npc_class.actor_class.world.position.x + mFI_UT_WORLDSIZE_X_F, actor->npc_class.actor_class.world.position.z);
actor->npc_class.condition_info.demo_flg &= ~aNPC_COND_DEMO_SKIP_FOOTSTEPS; // @unnecessary
}
static void aSTM_make_train_bf_init(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
actor->timer = 60;
play->submenu.start_refuse = TRUE;
}
static void aSTM_make_train_init(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
play->submenu.start_refuse = TRUE;
Common_Set(train_coming_flag, 2);
}
static void aSTM_move_turn_init(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
play->submenu.start_refuse = TRUE;
actor->move_ofs_x = player_x_drt(actor) * mFI_UNIT_BASE_SIZE_F;
actor->npc_class.movement.avoid_pos_x = actor->npc_class.actor_class.home.position.x + mFI_UT_WORLDSIZE_X_F + actor->move_ofs_x;
actor->npc_class.movement.avoid_pos_z = actor->train_actor_p->world.position.z + 2 * mFI_UT_WORLDSIZE_Z_F;
aSTM_set_request_act(actor, 4, aNPC_ACT_TURN2, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, actor->npc_class.movement.avoid_pos_x, actor->npc_class.movement.avoid_pos_z);
}
static void aSTM_move_init(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
aSTM_set_request_act(actor, 4, aNPC_ACT_WALK, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, actor->npc_class.movement.avoid_pos_x, actor->npc_class.movement.avoid_pos_z);
actor->npc_class.condition_info.demo_flg &= ~aNPC_COND_DEMO_SKIP_FOOTSTEPS;
}
static void aSTM_see_off_init(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
STRUCTURE_ACTOR* train1 = (STRUCTURE_ACTOR*)actor->train_actor_p;
// TODO: train1 arg1 = 'player boarding' flag
train1->arg1 = TRUE;
Common_Set(train_control_state, 0);
aSTM_get_off_wait_init(actor, play);
actor->npc_class.actor_class.state_bitfield |= ACTOR_STATE_NO_MOVE_WHILE_CULLED;
}
static void aSTM_game_end_init(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play) {
if (actor->station_check_res == TRUE) {
aNPS2_setup_game_start(play);
} else {
mBGMPsComp_make_ps_wipe(0x328A);
play->fb_fade_type = 5;
play->fb_wipe_type = 5;
mPlib_request_main_invade_type1((GAME*)play);
}
mBGMPsComp_scene_mode(11);
}
typedef struct {
u8 think_proc_idx;
u8 think_init_idx;
u8 talk_request_idx;
u8 talk_idx;
u8 think_idx_after_talk;
} aSTM_think_data_c;
// clang-format off
static aSTM_think_data_c dt_tbl[] = {
{aSTM_THINK_PROC_GET_OFF_WAIT, aSTM_THINK_INIT_GET_OFF_WAIT, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_GET_OFF_WAIT},
{aSTM_THINK_PROC_TURN, aSTM_THINK_INIT_NONE, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_2},
{aSTM_THINK_PROC_NONE, aSTM_THINK_INIT_NONE, aSTM_TALK_REQUEST_FORCE, 0x00, aSTM_THINK_INTERRUPT_TURN},
{aSTM_THINK_PROC_NONE, aSTM_THINK_INIT_NONE, aSTM_TALK_REQUEST_FORCE, 0x01, aSTM_THINK_INTERRUPT_TURN},
{aSTM_THINK_PROC_TALK_WAIT, aSTM_THINK_INIT_INTRO_DEMO_WAIT, aSTM_TALK_REQUEST_NORM, 0x00, aSTM_THINK_4},
{aSTM_THINK_PROC_TALK_WAIT, aSTM_THINK_INIT_GET_OFF_WAIT, aSTM_TALK_REQUEST_NORM, 0x01, aSTM_THINK_5},
{aSTM_THINK_PROC_INTERRUPT_TURN, aSTM_THINK_INIT_INTERRUPT_TURN, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_INTERRUPT_TURN},
{aSTM_THINK_PROC_INTERRUPT_MOVE, aSTM_THINK_INIT_INTERRUPT_MOVE, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_INTERRUPT_MOVE},
{aSTM_THINK_PROC_TALK_WAIT, aSTM_THINK_INIT_GET_OFF_WAIT, aSTM_TALK_REQUEST_NORM, 0x02, aSTM_THINK_8},
{aSTM_THINK_PROC_TALK_WAIT, aSTM_THINK_INIT_GET_OFF_WAIT, aSTM_TALK_REQUEST_NORM, 0x03, aSTM_THINK_9},
{aSTM_THINK_PROC_MAKE_TRAIN_BF, aSTM_THINK_INIT_MAKE_TRAIN_BF, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_MAKE_TRAIN_BF},
{aSTM_THINK_PROC_MAKE_TRAIN, aSTM_THINK_INIT_MAKE_TRAIN, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_MAKE_TRAIN},
{aSTM_THINK_PROC_TRAIN_ARRIVE_WAIT, aSTM_THINK_INIT_NONE, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_TRAIN_ARRIVE_WAIT},
{aSTM_THINK_PROC_MOVE_TURN_BF, aSTM_THINK_INIT_MAKE_TRAIN, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_14},
{aSTM_THINK_PROC_INTERRUPT_TURN, aSTM_THINK_INIT_MOVE_TURN, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_14},
{aSTM_THINK_PROC_MOVE, aSTM_THINK_INIT_MOVE, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_MOVE},
{aSTM_THINK_PROC_INTERRUPT_TURN, aSTM_THINK_INIT_LOOK_P, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_16},
{aSTM_THINK_PROC_NONE, aSTM_THINK_INIT_NONE, aSTM_TALK_REQUEST_FORCE, 0x02, aSTM_THINK_IN_TRAIN},
{aSTM_THINK_PROC_IN_TRAIN, aSTM_THINK_INIT_NONE, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_IN_TRAIN},
{aSTM_THINK_PROC_IN_TRAIN2, aSTM_THINK_INIT_NONE, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_IN_TRAIN2},
{aSTM_THINK_PROC_SEE_OFF, aSTM_THINK_INIT_SEE_OFF, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_SEE_OFF},
{aSTM_THINK_PROC_LOOK_PLAYER, aSTM_THINK_INIT_GAME_END, aSTM_TALK_REQUEST_NONE, 0x00, aSTM_THINK_GAME_END},
};
// clang-format on
typedef void (*aSTM_THINK_INIT_PROC)(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play);
// clang-format off
static aSTM_THINK_INIT_PROC init_table[] = {
(aSTM_THINK_INIT_PROC)none_proc1,
aSTM_get_off_wait_init,
aSTM_intro_demo_wait_init,
aSTM_interrupt_turn_init,
aSTM_interrupt_move_init,
aSTM_make_train_init,
aSTM_make_train_bf_init,
aSTM_move_turn_init,
aSTM_move_init,
aSTM_look_player,
aSTM_see_off_init,
aSTM_game_end_init,
};
// clang-format on
static void aSTM_setup_think_proc(NPC_STATION_MASTER_ACTOR* actor, GAME_PLAY* play, u8 think_idx) {
aSTM_think_data_c* data_p = &dt_tbl[think_idx];
// clang-format off
static aNPC_TALK_REQUEST_PROC talk_request_table[] = {
(aNPC_TALK_REQUEST_PROC)none_proc1,
aSTM_norm_talk_request,
aSTM_force_talk_request,
};
// clang-format on
actor->think_idx = think_idx;
actor->think_proc_idx = data_p->think_proc_idx;
actor->talk_proc_idx = data_p->talk_request_idx;
actor->npc_class.talk_info.talk_request_proc = talk_request_table[data_p->talk_request_idx];
actor->talk_idx = data_p->talk_idx;
actor->next_think_idx = data_p->think_idx_after_talk;
(*init_table[data_p->think_init_idx])(actor, play);
}
static void aSTM_think_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) {
static aNPC_SUB_PROC think_proc[] = { aSTM_think_init_proc, aSTM_think_main_proc };
(*think_proc[type])(nactorx, play);
}
static void aSTM_schedule_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) {
nactorx->think.think_proc = aSTM_think_proc;
NPC_CLIP->think_proc(nactorx, play, aNPC_THINK_SPECIAL, aNPC_THINK_TYPE_INIT);
}
static void aSTM_schedule_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) {
if (!NPC_CLIP->think_proc(nactorx, play, -1, aNPC_THINK_TYPE_CHK_INTERRUPT)) {
NPC_CLIP->think_proc(nactorx, play, -1, aNPC_THINK_TYPE_MAIN);
}
}
static void aSTM_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) {
static aNPC_SUB_PROC sche_proc[] = { aSTM_schedule_init_proc, aSTM_schedule_main_proc };
(*sche_proc[type])(nactorx, play);
}
@@ -0,0 +1,124 @@
static void aSTM_train_go_ok(void) {
Common_Set(train_control_state, 0);
Common_Set(train_last_control_state, 0);
}
typedef struct {
int msg_no;
u8 talk_idx;
u8 cam_type;
} aSTM_talk_data_c;
static void aSTM_set_force_talk_info(ACTOR* actorx) {
// clang-format off
static aSTM_talk_data_c dt_tbl[] = {
{0x07DD, aSTM_TALK_END_WAIT, CAMERA2_PROCESS_NORMAL},
{0x0966, aSTM_TALK_END_WAIT, CAMERA2_PROCESS_NORMAL},
{0x0965, aSTM_TALK_SAYONARA, CAMERA2_PROCESS_TALK},
};
// clang-format on
NPC_STATION_MASTER_ACTOR* actor = (NPC_STATION_MASTER_ACTOR*)actorx;
aSTM_talk_data_c* data_p = &dt_tbl[actor->talk_idx];
if (CLIP(station_clip) != NULL) {
CLIP(station_clip)->change_talk_proc((ACTOR*)actor, data_p->talk_idx);
} else {
actor->talk_proc = (aSTM_TALK_PROC)none_proc1;
}
mDemo_Set_msg_num(data_p->msg_no);
mDemo_Set_talk_turn(TRUE);
mDemo_Set_camera(data_p->cam_type);
mDemo_Set_talk_return_demo_wait(TRUE);
if (actor->talk_idx == 2) {
if (actor->npc_class.talk_info.melody_inst != 0) {
actor->melody_save = actor->npc_class.talk_info.melody_inst;
}
actor->npc_class.talk_info.melody_inst = 0;
}
}
static void aSTM_force_talk_request(ACTOR* actorx, GAME* game) {
mDemo_Request(mDemo_TYPE_SPEAK, actorx, aSTM_set_force_talk_info);
}
static void aSTM_set_norm_talk_info(ACTOR* actorx) {
// clang-format off
static aSTM_talk_data_c dt_tbl[] = {
{0x0831, aSTM_TALK_END_WAIT, CAMERA2_PROCESS_TALK},
{0x07ED, aSTM_TALK_END_WAIT, CAMERA2_PROCESS_TALK},
{0x0943, aSTM_TALK_CHK_LEAVE_TALK, CAMERA2_PROCESS_TALK},
{0x095C, aSTM_TALK_CHK_LEAVE_TALK, CAMERA2_PROCESS_TALK},
};
// clang-format on
NPC_STATION_MASTER_ACTOR* actor = (NPC_STATION_MASTER_ACTOR*)actorx;
aSTM_talk_data_c* data_p = &dt_tbl[actor->talk_idx];
if (CLIP(aprilfool_control_clip) != NULL && !CLIP(aprilfool_control_clip)->talk_chk_proc(SP_NPC_STATION_MASTER)) {
mDemo_Set_msg_num(CLIP(aprilfool_control_clip)->get_msg_num_proc(SP_NPC_STATION_MASTER, TRUE));
CLIP(station_clip)->change_talk_proc(actorx, aSTM_TALK_END_WAIT);
} else {
if (actor->talk_idx == 2 && !Save_Get(save_exist)) {
mDemo_Set_msg_num(0x0945);
actor->talk_proc = (aSTM_TALK_PROC)none_proc1;
} else {
mDemo_Set_msg_num(data_p->msg_no);
if (CLIP(station_clip) != NULL) {
CLIP(station_clip)->change_talk_proc(actorx, data_p->talk_idx);
} else {
actor->talk_proc = (aSTM_TALK_PROC)none_proc1;
}
}
}
mDemo_Set_talk_turn(TRUE);
mDemo_Set_camera(CAMERA2_PROCESS_TALK);
}
static void aSTM_norm_talk_request(ACTOR* actorx, GAME* game) {
mDemo_Request(mDemo_TYPE_TALK, actorx, aSTM_set_norm_talk_info);
}
static int aSTM_talk_init(ACTOR* actorx, GAME* game) {
NPC_STATION_MASTER_ACTOR* actor = (NPC_STATION_MASTER_ACTOR*)actorx;
actor->npc_class.talk_info.talk_request_proc = (aNPC_TALK_REQUEST_PROC)none_proc1;
mDemo_Set_ListenAble();
mDemo_Start(actorx);
if (actor->talk_proc_idx == 1 && !mEv_CheckFirstJob()) {
actor->happening_sound = mBGMPsComp_execute_bgm_num_get();
}
return TRUE;
}
static int aSTM_talk_end_chk(ACTOR* actorx, GAME* game) {
NPC_STATION_MASTER_ACTOR* actor = (NPC_STATION_MASTER_ACTOR*)actorx;
GAME_PLAY* play = (GAME_PLAY*)game;
int ret = FALSE;
actor->talk_proc(actor, play);
if (mDemo_CAN_ACTOR_TALK(actorx)) {
switch (actor->next_think_idx) {
case aSTM_THINK_8:
case aSTM_THINK_9:
aSTM_train_go_ok();
break;
}
aSTM_setup_think_proc(actor, play, actor->next_think_idx);
if (actor->melody_save != 0) {
actor->npc_class.talk_info.melody_inst = actor->melody_save;
actor->melody_save = 0;
}
ret = TRUE;
}
return ret;
}