diff --git a/configure.py b/configure.py index 9b9802d8..3de9233b 100644 --- a/configure.py +++ b/configure.py @@ -1043,7 +1043,7 @@ config.libs = [ Object(Matching, "actor/ac_s_car.c"), Object(Matching, "actor/ac_sample.c"), Object(Matching, "actor/ac_set_manager.c"), - Object(NonMatching, "actor/ac_set_npc_manager.c"), + Object(Matching, "actor/ac_set_npc_manager.c"), Object(Matching, "actor/ac_set_ovl_gyoei.c"), Object(Matching, "actor/ac_set_ovl_insect.c"), Object(Matching, "actor/ac_shop.c"), diff --git a/include/ac_set_npc_manager.h b/include/ac_set_npc_manager.h index b65c0d2b..b51cb5bb 100644 --- a/include/ac_set_npc_manager.h +++ b/include/ac_set_npc_manager.h @@ -3,6 +3,10 @@ #include "types.h" #include "m_actor.h" +#include "m_field_info.h" +#include "m_npc.h" +#include "m_npc_schedule.h" +#include "m_npc_walk.h" #ifdef __cplusplus extern "C" { @@ -10,10 +14,77 @@ extern "C" { #define aSNMgr_EVENT_NORMAL_NPC_NUM mNpc_EVENT_NPC_NUM +enum { + aSNMgr_SET_MODE_NONE, + aSNMgr_SET_MODE_REGULAR, + aSNMgr_SET_MODE_GUEST, + + aSNMgr_SET_MODE_NUM +}; + +typedef struct set_npc_manager_actor_s SET_NPC_MANAGER_ACTOR; + +typedef struct set_npc_scope_s { + f32 edge[2][2]; +} aSNMgr_scope_c; + typedef struct set_npc_event_save_s { u8 animal_idx[aSNMgr_EVENT_NORMAL_NPC_NUM]; } aSNMgr_event_save_c; +typedef struct set_npc_event_info_s { + aSNMgr_event_save_c* save_p; + int type; + int event_map_idx; + int joint_npc_max; + xyz_t pos[mNpc_EVENT_NPC_NUM]; +} aSNMgr_event_info_c; + +typedef struct set_npc_make_s { + mActor_name_t name; + mActor_name_t make_name; + int bx; + int bz; + int ux; + int uz; + int idx; +} aSNMgr_make_c; + +typedef struct set_npc_npc_info_s { + Animal_c* animal_p; + mNpc_NpcList_c* list_p; + mNPS_schedule_c* schedule_p; + mNpc_walk_c* walk_p; + mNpcW_info_c* winfo_p[ANIMAL_NUM_MAX]; + u8 in_block_num[BLOCK_Z_NUM - 2][BLOCK_X_NUM]; + u8 to_block[ANIMAL_NUM_MAX][2]; + u32* count_p[ANIMAL_NUM_MAX]; + u16 exist; + u16 appear; + u16 joint_event; + aSNMgr_make_c make[mNpc_EVENT_NPC_NUM]; + aSNMgr_event_info_c event_info; + int timer[ANIMAL_NUM_MAX]; +} aSNMgr_npc_info_c; + +typedef struct set_npc_player_pos_s { + xyz_t pos; + int next_block[2]; + int now_block[2]; +} aSNMgr_player_pos_c; + +typedef void (*aSNMgr_SET_PROC)(SET_NPC_MANAGER_ACTOR*); + +struct set_npc_manager_actor_s { + ACTOR actor_class; + int set_mode; + aSNMgr_SET_PROC set_proc; + aSNMgr_player_pos_c player_pos; + aSNMgr_scope_c scope; + aSNMgr_scope_c guest_scope; + aSNMgr_npc_info_c npc_info; +}; + extern ACTOR_PROFILE Set_Npc_Manager_Profile; #ifdef __cplusplus diff --git a/include/m_field_info.h b/include/m_field_info.h index 490ef92a..45210878 100644 --- a/include/m_field_info.h +++ b/include/m_field_info.h @@ -34,6 +34,12 @@ extern "C" { #define mFI_BK_WORLDSIZE_X_F mFI_BK_WORLDSIZE_BASE_F #define mFI_BK_WORLDSIZE_Z_F mFI_BK_WORLDSIZE_BASE_F +#define mFI_BK_WORLDSIZE_HALF_X (mFI_BK_WORLDSIZE_X / 2) +#define mFI_BK_WORLDSIZE_HALF_Z (mFI_BK_WORLDSIZE_Z / 2) + +#define mFI_BK_WORLDSIZE_HALF_X_F (mFI_BK_WORLDSIZE_X_F / 2.0f) +#define mFI_BK_WORLDSIZE_HALF_Z_F (mFI_BK_WORLDSIZE_Z_F / 2.0f) + #define mFI_POS2UT(pos) ((int)((pos) / mFI_UNIT_BASE_SIZE_F)) #define mFI_ROW_TO_CHARSTR(row) ((row) + 'A') diff --git a/include/m_npc_walk.h b/include/m_npc_walk.h index 15197ec1..d830d207 100644 --- a/include/m_npc_walk.h +++ b/include/m_npc_walk.h @@ -41,8 +41,8 @@ enum { /* TODO: figure out remaining enums */ enum { - mNpcW_APPEAR_STATUS_0, - mNpcW_APPEAR_STATUS_1, + mNpcW_APPEAR_STATUS_REGULAR, + mNpcW_APPEAR_STATUS_GUEST, mNpcW_APPEAR_STATUS_NUM }; @@ -58,10 +58,10 @@ enum { /* TODO: figure out remaining enums */ enum { - mNpcW_INFO_STATUS_0, + mNpcW_INFO_STATUS_NONE, mNpcW_INFO_STATUS_WALKING, - mNpcW_INFO_STATUS_2, - mNpcW_INFO_STATUS_3, + mNpcW_INFO_STATUS_STAY_IN_BLOCK, + mNpcW_INFO_STATUS_ARRIVE, mNpcW_INFO_STATUS_4, mNpcW_INFO_STATUS_NUM @@ -95,7 +95,7 @@ extern int mNpcW_ChangeNpcWalk(mNpc_walk_c* walk, mNpcW_info_c* info); extern void mNpcW_SetGoalBlock(mNpcW_info_c* info); extern void mNpcW_InitNpcWalk(mNpc_walk_c* walk); extern int mNpcW_GetAppearStatusWay(u8* status, u8* way, Animal_c* animal); -extern int* mNpcW_GetArriveStayCountP(int idx); +extern u32* mNpcW_GetArriveStayCountP(int idx); extern int mNpcW_GetWalkInfoStatusGoalAnimalIdx(int* status, int* goal, int idx); extern int mNpcW_GetNearGate(int* target_ut_x, int* target_ut_z, int block_x, int block_z, int ut_x, int ut_z); diff --git a/src/actor/ac_set_npc_manager.c b/src/actor/ac_set_npc_manager.c new file mode 100644 index 00000000..7103f659 --- /dev/null +++ b/src/actor/ac_set_npc_manager.c @@ -0,0 +1,1281 @@ +#include "ac_set_npc_manager.h" + +#include "m_name_table.h" +#include "m_player_lib.h" +#include "m_field_info.h" +#include "m_common_data.h" +#include "libultra/libultra.h" +#include "m_random_field.h" +#include "m_event_map_npc.h" + +static void aSNMgr_actor_ct(ACTOR* actorx, GAME* game); +static void aSNMgr_actor_dt(ACTOR* actorx, GAME* game); +static void aSNMgr_actor_move(ACTOR* actorx, GAME* game); + +// clang-format off +ACTOR_PROFILE Set_Npc_Manager_Profile = { + mAc_PROFILE_SET_NPC_MANAGER, + ACTOR_PART_CONTROL, + ACTOR_STATE_CAN_MOVE_IN_DEMO_SCENES | ACTOR_STATE_NO_DRAW_WHILE_CULLED | ACTOR_STATE_NO_MOVE_WHILE_CULLED, + EMPTY_NO, + ACTOR_OBJ_BANK_KEEP, + sizeof(SET_NPC_MANAGER_ACTOR), + &aSNMgr_actor_ct, + &aSNMgr_actor_dt, + &aSNMgr_actor_move, + mActor_NONE_PROC1, + NULL, +}; +// clang-format on + +static int aSNMgr_get_player_pos(xyz_t* pos_p, GAME* game); +static void aSNMgr_renewal_player_now_block(SET_NPC_MANAGER_ACTOR* manager); +static void aSNMgr_renewal_set_scope(SET_NPC_MANAGER_ACTOR* manager); +static void aSNMgr_init_winfo_p(SET_NPC_MANAGER_ACTOR* manager); +static void aSNMgr_set_npc_exist(SET_NPC_MANAGER_ACTOR* manager); +static void aSNMgr_clear_make_npc(aSNMgr_make_c* make_p, int count); +static void aSNMgr_clear_event_info(aSNMgr_event_info_c* info_p); +static void aSNMgr_move_event_set(SET_NPC_MANAGER_ACTOR* manager); +static void aSNMgr_force_go_home_event_start(SET_NPC_MANAGER_ACTOR* manager); +static void aSNMgr_setup_set_proc(SET_NPC_MANAGER_ACTOR* manager, int mode); +static void aSNMgr_reset_event_npc_pos(SET_NPC_MANAGER_ACTOR* manager); + +static void aSNMgr_actor_ct(ACTOR* actorx, GAME* game) { + SET_NPC_MANAGER_ACTOR* manager = (SET_NPC_MANAGER_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + int i; + + aSNMgr_get_player_pos(&manager->player_pos.pos, game); + aSNMgr_renewal_player_now_block(manager); + mFI_Wpos2BlockNum(&manager->player_pos.next_block[0], &manager->player_pos.next_block[1], manager->player_pos.pos); + aSNMgr_renewal_set_scope(manager); + manager->npc_info.animal_p = Save_Get(animals); + manager->npc_info.list_p = Common_Get(npclist); + manager->npc_info.schedule_p = Common_Get(npc_schedule); + manager->npc_info.walk_p = Common_GetPointer(npc_walk); + aSNMgr_init_winfo_p(manager); + bzero(manager->npc_info.in_block_num, sizeof(manager->npc_info.in_block_num)); + bzero(manager->npc_info.to_block, sizeof(manager->npc_info.to_block)); + + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + manager->npc_info.count_p[i] = mNpcW_GetArriveStayCountP(i); + } + + aSNMgr_set_npc_exist(manager); + manager->npc_info.appear = 0; + manager->npc_info.joint_event = 0; + aSNMgr_clear_make_npc(manager->npc_info.make, mNpc_EVENT_NPC_NUM); + aSNMgr_clear_event_info(&manager->npc_info.event_info); + + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (manager->npc_info.winfo_p[i] != NULL) { + mNpcW_SetGoalBlock(manager->npc_info.winfo_p[i]); + } + } + + bzero(manager->npc_info.timer, sizeof(manager->npc_info.timer)); + + if (play->fb_wipe_type == 6) { + aSNMgr_move_event_set(manager); + aSNMgr_force_go_home_event_start(manager); + } + + aSNMgr_setup_set_proc(manager, aSNMgr_SET_MODE_REGULAR); +} + +static void aSNMgr_actor_dt(ACTOR* actorx, GAME* game) { + SET_NPC_MANAGER_ACTOR* manager = (SET_NPC_MANAGER_ACTOR*)actorx; + + aSNMgr_reset_event_npc_pos(manager); +} + +static void aSNMgr_init_winfo_p(SET_NPC_MANAGER_ACTOR* manager) { + mNpcW_info_c** winfo_p = manager->npc_info.winfo_p; + mNpc_walk_c* walk_p = manager->npc_info.walk_p; + Animal_c* animal_p = manager->npc_info.animal_p; + int i; + + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + int idx = mNpcW_GetNpcWalkInfoIdx(walk_p->info, mNpc_EVENT_NPC_NUM, &animal_p->id); + + if (idx != -1) { + *winfo_p = &walk_p->info[idx]; + } else { + *winfo_p = NULL; + } + + winfo_p++; + animal_p++; + } +} + +static void aSNMgr_set_npc_exist(SET_NPC_MANAGER_ACTOR* manager) { + Animal_c* animal_p = manager->npc_info.animal_p; + u16 exist = 0; + int i; + + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (!mNpc_CheckFreeAnimalPersonalID(&animal_p->id)) { + exist |= 1 << i; + } + + animal_p++; + } + + manager->npc_info.exist = exist; +} + +static void aSNMgr_clear_event_info(aSNMgr_event_info_c* info_p) { + info_p->save_p = NULL; + info_p->type = mEv_EVENT_NUM; + info_p->event_map_idx = -1; + info_p->joint_npc_max = 0; +} + +static int aSNMgr_get_event_npc_idx(u8* idx_p, int count, int animal_idx) { + int i; + int ret = -1; + + for (i = 0; i < count; i++) { + if (*idx_p == animal_idx) { + ret = i; + break; + } + + idx_p++; + } + + return ret; +} + +static void aSNMgr_reset_event_npc_pos(SET_NPC_MANAGER_ACTOR* manager) { + mNpc_NpcList_c* list_p = manager->npc_info.list_p; + aSNMgr_event_info_c* info_p = &manager->npc_info.event_info; + aSNMgr_event_save_c* save_p = manager->npc_info.event_info.save_p; + int idx; + int i; + + if (info_p->type != mEv_EVENT_NUM && list_p != NULL && save_p != NULL) { + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + idx = aSNMgr_get_event_npc_idx(save_p->animal_idx, info_p->joint_npc_max, i); + + if (idx != -1) { + list_p[i].position.x = list_p[i].house_position.x; + list_p[i].position.y = list_p[i].house_position.y; + list_p[i].position.z = list_p[i].house_position.z; + } + } + } +} + +static int aSNMgr_chk_exist_and_appear(SET_NPC_MANAGER_ACTOR* manager, int appear_type, int idx) { + int ret = FALSE; + + if (((manager->npc_info.exist >> idx) & 1) == 1 && appear_type == ((manager->npc_info.appear >> idx) & 1) && + manager->npc_info.list_p[idx].appear_flag == TRUE) { + ret = TRUE; + } + + return ret; +} + +static int aSNMgr_chk_exist_and_appear_and_event(SET_NPC_MANAGER_ACTOR* manager, int appear_type, int idx) { + int ret = FALSE; + + if (aSNMgr_chk_exist_and_appear(manager, appear_type, idx) && ((manager->npc_info.joint_event >> idx) & 1) == 0) { + ret = TRUE; + } + + return ret; +} + +static int aSNMgr_chk_arbeit_and_demo_and_halloween(void) { + int ret = TRUE; + + if (!mEv_CheckArbeit() && !mEv_CheckFirstIntro() && CLIP(demo_clip) == NULL && CLIP(demo_clip2) == NULL && + !mEv_check_status(mEv_EVENT_HALLOWEEN, mEv_STATUS_ACTIVE)) { + ret = FALSE; + } + + return ret; +} + +static int aSNMgr_get_player_pos(xyz_t* pos_p, GAME* game) { + int ret; + ACTOR* player = GET_PLAYER_ACTOR_GAME_ACTOR(game); + + ret = FALSE; + if (player != NULL) { + *pos_p = player->world.position; + ret = TRUE; + } + + return ret; +} + +static void aSNMgr_renewal_player_now_block(SET_NPC_MANAGER_ACTOR* manager) { + mFI_Wpos2BlockNum(&manager->player_pos.now_block[0], &manager->player_pos.now_block[1], manager->player_pos.pos); +} + +static void aSNMgr_renewal_player_next_block(SET_NPC_MANAGER_ACTOR* manager) { + mFI_GetNextBlockNum(&manager->player_pos.next_block[0], &manager->player_pos.next_block[1]); +} + +static void aSNMgr_renewal_set_scope(SET_NPC_MANAGER_ACTOR* manager) { + static int block_wh[] = { mFI_BK_WORLDSIZE_X, mFI_BK_WORLDSIZE_Z }; + static f32 half_block_wh[] = { mFI_BK_WORLDSIZE_HALF_X_F, mFI_BK_WORLDSIZE_HALF_Z_F }; + static f32 r_add[] = { -mFI_BK_WORLDSIZE_HALF_X_F, mFI_BK_WORLDSIZE_HALF_Z_F }; + static f32 gr_add[] = { -mFI_UT_WORLDSIZE_X_F, mFI_UT_WORLDSIZE_Z_F }; + int* next_block_p = manager->player_pos.next_block; + aSNMgr_scope_c* scope_p = &manager->scope; + aSNMgr_scope_c* guest_scope_p = &manager->guest_scope; + f32 center; + int i; + int j; + + for (i = 0; i < 2; i++) { + center = next_block_p[i] * block_wh[i] + half_block_wh[i]; + + for (j = 0; j < 2; j++) { + scope_p->edge[i][j] = center + r_add[j]; + guest_scope_p->edge[i][j] = scope_p->edge[i][j] + gr_add[j]; + } + } +} + +static int aSNMgr_check_in(f32 chk_pos, f32* scope_pos_p) { + int ret = FALSE; + + if (chk_pos >= scope_pos_p[0] && chk_pos < scope_pos_p[1]) { + ret = TRUE; + } + + return ret; +} + +static int aSNMgr_check_in_scope(xyz_t chk_pos, aSNMgr_scope_c* scope_p) { + int ret = FALSE; + + if (aSNMgr_check_in(chk_pos.x, scope_p->edge[0]) == TRUE && + aSNMgr_check_in(chk_pos.z, scope_p->edge[1]) == TRUE) { + ret = TRUE; + } + + return ret; +} + +static void aSNMgr_set_in_block_npc_num(u8* in_block_num_p, mNpc_NpcList_c* list_p, u16 exist) { + int bx; + int bz; + int block; + int i; + + bzero(in_block_num_p, (BLOCK_Z_NUM - 2) * BLOCK_X_NUM); + + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (((exist >> i) & 1) == 1) { + if (mFI_Wpos2BlockNum(&bx, &bz, list_p->position) == TRUE) { + block = mFI_GetBlockNum(bx, bz); + in_block_num_p[block]++; + } + } + + list_p++; + } +} + +static int aSNMgr_check_move_npc_schedule(mNPS_schedule_c* sched_p, Animal_c* animal_p) { + int ret = FALSE; + + if (sched_p->current_type == mNPS_SCHED_FIELD && animal_p != NULL && !animal_p->is_home) { + ret = TRUE; + } + + return ret; +} + +static void aSNMgr_get_block_ut_num_set_npc(int* bx, int* bz, int* ux, int* uz, mNpc_NpcList_c* list_p) { + if (mFI_Wpos2BlockNum(bx, bz, list_p->position) == TRUE) { + mFI_Wpos2UtNum_inBlock(ux, uz, list_p->position); + } +} + +static int aSNMgr_set_appear_info_regular(SET_NPC_MANAGER_ACTOR* manager, int bx, int bz, int idx) { + int player_bx = manager->player_pos.next_block[0]; + int player_bz = manager->player_pos.next_block[1]; + int ret = FALSE; + + if (bx == player_bx && bz == player_bz) { + mNpcW_info_c* info_p = manager->npc_info.winfo_p[idx]; + + if (info_p != NULL) { + if (((manager->npc_info.joint_event >> idx) & 1) == 1) { + info_p->appear_info.status = mNpcW_APPEAR_STATUS_REGULAR; + ret = TRUE; + } else { + switch (info_p->status) { + case mNpcW_INFO_STATUS_WALKING: + case mNpcW_INFO_STATUS_STAY_IN_BLOCK: + case mNpcW_INFO_STATUS_ARRIVE: + info_p->appear_info.status = mNpcW_APPEAR_STATUS_REGULAR; + ret = TRUE; + break; + } + } + } else { + ret = TRUE; + } + } + + return ret; +} + +static int aSNMgr_set_appear_info_guest(SET_NPC_MANAGER_ACTOR* manager, mNpcW_info_c* info_p, int bx, int bz) { + int ret = FALSE; + + if (info_p != NULL) { + int diff_bx; + int diff_bz; + int player_bx = manager->player_pos.next_block[0]; + int player_bz = manager->player_pos.next_block[1]; + + switch (info_p->status) { + case mNpcW_INFO_STATUS_STAY_IN_BLOCK: + case mNpcW_INFO_STATUS_ARRIVE: + case mNpcW_INFO_STATUS_4: + default: + break; + case mNpcW_INFO_STATUS_WALKING: { + diff_bx = bx - player_bx; + diff_bz = bz - player_bz; + + if (diff_bx == 0) { + if (diff_bz == -1) { + info_p->appear_info.status = mNpcW_APPEAR_STATUS_GUEST; + info_p->appear_info.way = mNpcW_APPEAR_WAY_DOWN; + ret = TRUE; + } else if (diff_bz == 1) { + info_p->appear_info.status = mNpcW_APPEAR_STATUS_GUEST; + info_p->appear_info.way = mNpcW_APPEAR_WAY_UP; + ret = TRUE; + } + } else if (diff_bz == 0) { + if (diff_bx == -1) { + info_p->appear_info.status = mNpcW_APPEAR_STATUS_GUEST; + info_p->appear_info.way = mNpcW_APPEAR_WAY_RIGHT; + ret = TRUE; + } else if (diff_bx == 1) { + info_p->appear_info.status = mNpcW_APPEAR_STATUS_GUEST; + info_p->appear_info.way = mNpcW_APPEAR_WAY_LEFT; + ret = TRUE; + } + } + } + } + } + + return ret; +} + +static int aSNMgr_check_safe_ut(int bx, int bz, int ux, int uz, mActor_name_t item, mCoBG_Collision_u* col_p) { + int ret = FALSE; + + if (col_p != NULL) { + xyz_t pos; + + if (mNpc_CheckNpcSet_fgcol(item, col_p->data.unit_attribute)) { + mFI_BkandUtNum2Wpos(&pos, bx, bz, ux, uz); + + if (!mCoBG_ExistHeightGap_KeepAndNow(pos)) { + ret = TRUE; + } + } + } + + return ret; +} + +static void aSNMgr_get_safe_sp_event_structure_4x4(int* safe_ux, int* safe_uz, int ux, int uz) { + int chk_ux = *safe_ux; + int chk_uz = *safe_uz; + + + + if (ux >= 1 && ux <= (UT_X_NUM - 1) && (ux - 1 <= chk_ux) && (ux + 1 >= chk_ux) && + uz >= 1 && uz <= (UT_Z_NUM - 2) && (uz - 1 <= chk_uz) && (uz + 2 >= chk_uz) + ) { + if (ux >= chk_ux) { + *safe_ux = ux - 1; + } else { + *safe_ux = ux + 1; + } + + *safe_uz = uz + 4; + } +} + +static void aSNMgr_get_safe_sp_event_structure(int* safe_ux, int* safe_uz, mActor_name_t* fg_p) { + static mActor_name_t sp_event_fg[] = { BROKER_TENT, DUMMY_BROKER_SHOP, DESIGNER_CAR, DUMMY_CAR }; + int i; + int j; + + if (fg_p != NULL) { + for (i = 0; i < UT_TOTAL_NUM; i++) { + for (j = 0; j < ARRAY_COUNT(sp_event_fg); j++) { + if (*fg_p == sp_event_fg[j]) { + aSNMgr_get_safe_sp_event_structure_4x4(safe_ux, safe_uz, i & 0xF, i >> 4); + i = UT_TOTAL_NUM; + break; + } + } + + fg_p++; + } + } +} + +static int aSNMgr_get_safe_utnum_3x3(int* safe_ux, int* safe_uz, int bx, int bz) { + mCoBG_Collision_u* col_p = mFI_GetBkNum2ColTop(bx, bz); + mActor_name_t* fg_p = mFI_BkNumtoUtFGTop(bx, bz); + static int ux_table[] = { 0, 1, -1, 0, 1, -1, 0, 1, -1 }; + static int uz_table[] = { 0, 0, 0, 1, 1, 1, -1, -1, -1 }; + int n_ux; + int n_uz; + int i; + int ret = FALSE; + int ut; + int ux; + int uz; + + if (col_p != NULL && fg_p != NULL) { + ux = *safe_ux; + uz = *safe_uz; + + for (i = 0; i < 9; i++) { + n_ux = ux + ux_table[i]; + n_uz = uz + uz_table[i]; + + if (n_ux >= 1 && n_ux < (UT_X_NUM - 1) && n_uz >= 1 && n_uz < (UT_Z_NUM - 1)) { + ut = n_uz * UT_X_NUM + n_ux; + + if (aSNMgr_check_safe_ut(bx, bz, n_ux, n_uz, fg_p[ut], &col_p[ut]) == TRUE) { + *safe_ux = n_ux; + *safe_uz = n_uz; + ret = TRUE; + break; + } + } + } + } + + return ret; +} + +static int aSNMgr_get_safe_utnum_in_block(int* safe_ux, int* safe_uz, int bx, int bz) { + static u16 candidate_ut[16]; + u16* candidate_ut_p = candidate_ut; + int candidate_num = 0; + mCoBG_Collision_u* col_p = mFI_GetBkNum2ColTop(bx, bz); + mActor_name_t* fg_p = mFI_BkNumtoUtFGTop(bx, bz); + int idx; + int ret = FALSE; + int i; + int j; + + if (col_p != NULL && fg_p != NULL) { + bzero(candidate_ut, sizeof(candidate_ut)); + for (i = 0; i < UT_Z_NUM; i++) { + for (j = 0; j < UT_X_NUM; j++) { + if (j >= 1 && j < (UT_X_NUM - 1) && i >= 1 && i < (UT_Z_NUM - 1)) { + if (aSNMgr_check_safe_ut(bx, bz, j, i, *fg_p, col_p) == TRUE) { + (*candidate_ut_p) |= 1 << j; + candidate_num++; + } + } + + fg_p++; + col_p++; + } + + candidate_ut_p++; + } + + if (candidate_num > 0) { + candidate_ut_p = candidate_ut; + idx = RANDOM(candidate_num); + + for (i = 0; i < UT_Z_NUM; i++) { + for (j = 0; j < UT_X_NUM; j++) { + if ((((*candidate_ut_p) >> j) & 1) == 1) { + if (idx <= 0) { + *safe_ux = j; + *safe_uz = i; + ret = TRUE; + i = UT_Z_NUM; + break; + } + + idx--; + } + } + + candidate_ut_p++; + } + } + } + + return ret; +} + +static int aSNMgr_get_safe_utnum_regular(int* safe_ux, int* safe_uz, int bx, int bz) { + int ret; + + aSNMgr_get_safe_sp_event_structure(safe_ux, safe_uz, mFI_BkNumtoUtFGTop(bx, bz)); + ret = aSNMgr_get_safe_utnum_3x3(safe_ux, safe_uz, bx, bz); + if (!ret) { + ret = aSNMgr_get_safe_utnum_in_block(safe_ux, safe_uz, bx, bz); + } + + return ret; +} + +static int aSNMgr_get_safe_utnum_guest(int* safe_ux, int* safe_uz, int bx, int bz, int way) { + static u8 l_gate_direct[] = { mRF_DIRECT_NORTH, mRF_DIRECT_SOUTH, mRF_DIRECT_WEST, mRF_DIRECT_EAST }; + int ret = FALSE; + u8 type = mFI_BkNum2BlockType(bx, bz); + int gate_count; + mRF_gate_c* gate_p = mRF_BlockTypeDirect2GateData(&gate_count, type, l_gate_direct[way]); + + if (gate_p != NULL) { + int idx = RANDOM(gate_count); + + *safe_ux = gate_p[idx].ut0 & 0xF; + *safe_uz = gate_p[idx].ut0 >> 4; + ret = TRUE; + } + + return ret; +} + +static int aSNMgr_get_safe_utnum(int* safe_ux, int* safe_uz, int bx, int bz, mNpcW_info_c* info_p) { + int status; + int way; + + way = mNpcW_APPEAR_WAY_UP; + if (info_p != NULL) { + status = info_p->appear_info.status; + way = info_p->appear_info.way; + } else { + status = mNpcW_APPEAR_STATUS_REGULAR; + } + + if (status == mNpcW_APPEAR_STATUS_GUEST) { + return aSNMgr_get_safe_utnum_guest(safe_ux, safe_uz, bx, bz, way); + } else { + return aSNMgr_get_safe_utnum_regular(safe_ux, safe_uz, bx, bz); + } +} + +static int aSNMgr_set_event_info(aSNMgr_event_info_c* info_p) { + int ret = FALSE; + int type; + int i; + + if (info_p->type == mEv_EVENT_NUM) { + type = mEvMN_GetEventTypeMap(); + if (type != -1) { + info_p->type = type; + info_p->event_map_idx = mEvMN_GetMapIdx(type); + if (info_p->event_map_idx != -1) { + info_p->save_p = (aSNMgr_event_save_c*)mEv_get_save_area(type, 0xF); + if (info_p->save_p == NULL) { + info_p->save_p = (aSNMgr_event_save_c*)mEv_reserve_save_area(type, 0xF); + for (i = 0; i < aSNMgr_EVENT_NORMAL_NPC_NUM; i++) { + info_p->save_p->animal_idx[i] = 0xFF; + } + mEvMN_GetNpcJointEv(info_p->save_p, type); + } else { + mEvMN_SetNpcJointEv(info_p->save_p, type); + } + + ret = TRUE; + } + } + } + + return ret; +} + +static void aSNMgr_set_npc_event(Animal_c* animal_p, mNpc_NpcList_c* list_p, aSNMgr_event_info_c* info_p, int idx) { + int event_npc_idx = aSNMgr_get_event_npc_idx(info_p->save_p->animal_idx, info_p->joint_npc_max, idx); + + if (event_npc_idx != -1) { + list_p->position.x = info_p->pos[event_npc_idx].x; + list_p->position.y = info_p->pos[event_npc_idx].y; + list_p->position.z = info_p->pos[event_npc_idx].z; + animal_p->is_home = FALSE; + } +} + +static void aSNMgr_move_event_arrange(SET_NPC_MANAGER_ACTOR* manager, int bx, int bz) { + Animal_c* animal_p = manager->npc_info.animal_p; + mNpc_NpcList_c* list_p = manager->npc_info.list_p; + aSNMgr_event_info_c* info_p = &manager->npc_info.event_info; + u16 joint_event = manager->npc_info.joint_event; + u8* idx_p = info_p->save_p->animal_idx; + int idx; + int ux; + int uz; + int set_ret; + int i; + + for (i = 0; i < info_p->joint_npc_max; i++) { + set_ret = mEvMN_GetEventSetUtInBlockMapIdx(&ux, &uz, info_p->event_map_idx, i); + if (set_ret == TRUE) { + idx = *idx_p; + mFI_BkandUtNum2Wpos(&list_p[idx].position, bx, bz, ux, uz); + info_p->pos[i].x = list_p[idx].position.x; + info_p->pos[i].y = list_p[idx].position.y; + info_p->pos[i].z = list_p[idx].position.z; + animal_p[idx].is_home = FALSE; + joint_event |= 1 << idx; + } + + idx_p++; + } + + manager->npc_info.joint_event = joint_event; +} + +static void aSNMgr_move_event_set(SET_NPC_MANAGER_ACTOR* manager) { + aSNMgr_event_info_c* info_p = &manager->npc_info.event_info; + u32 kind; + int bx; + int bz; + + if (aSNMgr_set_event_info(info_p) == TRUE && info_p->event_map_idx != -1) { + kind = mEvMN_GetEventBlockKind(info_p->event_map_idx); + mFI_BlockKind2BkNum(&bx, &bz, kind); + info_p->joint_npc_max = mEvMN_GetJointNpcMax(info_p->event_map_idx); + aSNMgr_move_event_arrange(manager, bx, bz); + } +} + +static void aSNMgr_get_event_name(mActor_name_t* name_p, aSNMgr_event_info_c* info_p, int animal_idx) { + int idx = -1; + + if (info_p->type != mEv_EVENT_NUM && info_p->type != mEv_EVENT_KAMAKURA) { + if (info_p->event_map_idx != -1) { + idx = aSNMgr_get_event_npc_idx(info_p->save_p->animal_idx, info_p->joint_npc_max, animal_idx); + } + + mEvMN_GetEventNpcName(name_p, info_p->type, animal_idx, idx); + } +} + +static void aSNMgr_clear_make_npc(aSNMgr_make_c* make_p, int count) { + while (count > 0) { + make_p->name = EMPTY_NO; + make_p->make_name = EMPTY_NO; + make_p->bx = -1; + make_p->bz = -1; + make_p->ux = -1; + make_p->uz = -1; + make_p->idx = -1; + + make_p++; + count--; + } +} + +static int aSNMgr_get_make_npc_idx(mActor_name_t name, int animal_idx, aSNMgr_make_c* make_p) { + int ret = -1; + int i; + + for (i = 0; i < aSNMgr_EVENT_NORMAL_NPC_NUM; i++) { + if (make_p->name == name && make_p->idx == animal_idx) { + ret = i; + break; + } + + make_p++; + } + + return ret; +} + +static int aSNMgr_set_make_npc(aSNMgr_make_c* make_p, mActor_name_t name, int bx, int bz, int ux, int uz, aSNMgr_event_info_c* info_p, int animal_idx) { + aSNMgr_make_c* sel_make_p; + int idx = aSNMgr_get_make_npc_idx(EMPTY_NO, -1, make_p); + + if (idx != -1) { + sel_make_p = &make_p[idx]; + + sel_make_p->name = name; + sel_make_p->make_name = name; + aSNMgr_get_event_name(&sel_make_p->make_name, info_p, animal_idx); + sel_make_p->bx = bx; + sel_make_p->bz = bz; + sel_make_p->ux = ux; + sel_make_p->uz = uz; + sel_make_p->idx = animal_idx; + } + + return idx; +} + +static void aSNMgr_make_npc(SET_NPC_MANAGER_ACTOR* manager, GAME_PLAY* play) { + aSNMgr_make_c* make_p = manager->npc_info.make; + mNpc_NpcList_c* list_p = manager->npc_info.list_p; + int idx; + int make_ret; + int i; + + if (CLIP(npc_clip) != NULL && CLIP(npc_clip)->setupActor_proc != NULL) { + for (i = 0; i < aSNMgr_EVENT_NORMAL_NPC_NUM; i++) { + switch (ITEM_NAME_GET_TYPE(make_p->name)) { + case NAME_TYPE_SPNPC: + case NAME_TYPE_NPC: + idx = make_p->idx; + if (idx != -1) { + make_ret = CLIP(npc_clip)->setupActor_proc(play, make_p->make_name, idx, idx, -1, make_p->bx, make_p->bz, make_p->ux, make_p->uz); + if (make_ret == TRUE) { + aSNMgr_clear_make_npc(make_p, 1); + list_p[idx].appear_flag = FALSE; + } + } + break; + default: + if (make_p->name != EMPTY_NO) { + aSNMgr_clear_make_npc(make_p, 1); + } + break; + } + + make_p++; + } + } +} + +static void aSNMgr_set_to_block(u8* to_block_p, xyz_t pos, u8 goal_bx, u8 goal_bz) { + int bx; + int bz; + int diff[2]; + int idx; + + if (mFI_Wpos2BlockNum(&bx, &bz, pos) == TRUE) { + if (to_block_p[0] == 0 && to_block_p[1] == 0) { + to_block_p[0] = bx; + to_block_p[1] = bz; + } + + if (bx == to_block_p[0] && bz == to_block_p[1]) { + diff[0] = goal_bx - bx; + diff[1] = goal_bz - bz; + + idx = 0; + if (ABS(diff[0]) < ABS(diff[1])) { + idx = 1; + } + + if (diff[idx] > 0) { + to_block_p[idx]++; + } else { + to_block_p[idx]--; + } + } + } +} + +static void aSNMgr_walk_to_next_block(xyz_t* pos_p, u8* to_block_p, u8* in_block_p, SET_NPC_MANAGER_ACTOR* manager) { + aSNMgr_player_pos_c* player_pos_p = &manager->player_pos; + int block[2]; + int prev_block[2]; + int idx; + int unit[2]; + int i; + int change_block = FALSE; + + if (mFI_Wpos2BkandUtNuminBlock(&block[0], &block[1], &unit[0], &unit[1], *pos_p) == TRUE) { + for (i = 0; i < 2; i++) { + unit[i] += (to_block_p[i] - block[i]); + prev_block[i] = block[i]; + if (unit[i] < 0) { + block[i]--; + unit[i] = (UT_BASE_NUM - 2); + change_block = TRUE; + } else if (unit[i] >= UT_BASE_NUM) { + block[i]++; + unit[i] = 1; + change_block = TRUE; + } + } + + if (block[0] != player_pos_p->now_block[0] || block[1] != player_pos_p->now_block[1]) { + mFI_BkandUtNum2CenterWpos(pos_p, block[0], block[1], unit[0], unit[1]); + + if (change_block == TRUE) { + idx = mFI_GetBlockNum(prev_block[0], prev_block[1]); + in_block_p[idx]--; + + idx = mFI_GetBlockNum(block[0], block[1]); + in_block_p[idx]++; + if (in_block_p[idx] >= ANIMAL_NUM_MAX) { + in_block_p[idx] = 14; + } + } + } + } +} + +static void aSNMgr_check_set_arrive(u8* status_p, xyz_t pos, u8 goal_bx, u8 goal_bz) { + int bx; + int bz; + + if (mFI_Wpos2BlockNum(&bx, &bz, pos) == TRUE && bx == goal_bx && bz == goal_bz) { + *status_p = mNpcW_INFO_STATUS_ARRIVE; + } +} + +static void aSNMgr_go_back_home_sub(mNpc_walk_c* walk_p, mNpcW_info_c** winfo_pp, mNpcW_info_c** winfo_src_pp) { + int anm_idx; + int info_idx; + + anm_idx = mNpcW_ChangeNpcWalk(walk_p, *winfo_pp); + *winfo_pp = NULL; + if (anm_idx >= 0) { + info_idx = mNpcW_GetNpcWalkInfoIdx(walk_p->info, mNpcW_MAX, &Save_Get(animals[anm_idx]).id); + if (info_idx != -1) { + winfo_src_pp[anm_idx] = &walk_p->info[info_idx]; + } + } +} + +static void aSNMgr_go_back_home(mNpc_walk_c* walk_p, mNpcW_info_c** winfo_pp, mNpcW_info_c** winfo_src_pp, u32* count_p) { + if (*count_p > 108000) { + if ((*winfo_pp)->goal_type == mNpcW_GOAL_MY_HOME) { + aSNMgr_go_back_home_sub(walk_p, winfo_pp, winfo_src_pp); + } else { + (*winfo_pp)->status = mNpcW_INFO_STATUS_WALKING; + (*winfo_pp)->goal_type = mNpcW_GOAL_MY_HOME; + *count_p = 0; + mNpcW_SetGoalBlock(*winfo_pp); + } + } else { + (*count_p)++; + } +} + +static void aSNMgr_check_into_block_npc_sum(u8* status_p, u8* to_block_p, u8* in_block_p) { + int block = mFI_GetBlockNum(to_block_p[0], to_block_p[1]); + + if (in_block_p[block] >= 3) { + if (*status_p == mNpcW_INFO_STATUS_WALKING) { + *status_p = mNpcW_INFO_STATUS_STAY_IN_BLOCK; + } + } else { + if (*status_p == mNpcW_INFO_STATUS_STAY_IN_BLOCK) { + *status_p = mNpcW_INFO_STATUS_WALKING; + } + } +} + +static int aSNMgr_check_in_block_max(int bx, int bz, u8* in_block_p) { + int ret = FALSE; + int block = mFI_GetBlockNum(bx, bz); + + if (in_block_p[block] >= 3) { + ret = TRUE; + } + + return ret; +} + +static void aSNMgr_walk_to_goal_npc(mNpc_NpcList_c* list_p, mNpcW_info_c* winfo_p, u8* to_block_p, u8* in_block_p, SET_NPC_MANAGER_ACTOR* manager, int walk_flag) { + aSNMgr_set_to_block(to_block_p, list_p->position, winfo_p->goal_block_x, winfo_p->goal_block_z); + + if (walk_flag == TRUE) { + aSNMgr_walk_to_next_block(&list_p->position, to_block_p, in_block_p, manager); + aSNMgr_check_set_arrive(&winfo_p->status, list_p->position, winfo_p->goal_block_x, winfo_p->goal_block_z); + } +} + +static void aSNMgr_walk_npc(SET_NPC_MANAGER_ACTOR* manager, GAME* game) { + mNPS_schedule_c* schedule_p = manager->npc_info.schedule_p; + Animal_c* animal_p = manager->npc_info.animal_p; + mNpc_NpcList_c* list_p = manager->npc_info.list_p; + mNpcW_info_c** winfo_p = manager->npc_info.winfo_p; + u32** count_p = manager->npc_info.count_p; + int* timer_p = manager->npc_info.timer; + int walk_flag = FALSE; + int i; + + aSNMgr_set_in_block_npc_num((u8*)manager->npc_info.in_block_num, list_p, manager->npc_info.exist); + if ((game->frame_counter % (7 * FRAMES_PER_SECOND)) == 0) { + walk_flag = TRUE; + } + + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (aSNMgr_chk_exist_and_appear_and_event(manager, mNpcW_APPEAR_STATUS_REGULAR, i) == TRUE && + aSNMgr_check_move_npc_schedule(schedule_p, animal_p) == TRUE && + *winfo_p != NULL + ) { + if ((*winfo_p)->status == mNpcW_INFO_STATUS_WALKING || (*winfo_p)->status == mNpcW_INFO_STATUS_STAY_IN_BLOCK) { + aSNMgr_check_into_block_npc_sum(&(*winfo_p)->status, (u8*)&manager->npc_info.to_block[i], (u8*)manager->npc_info.in_block_num); + } + + switch ((*winfo_p)->status) { + case mNpcW_INFO_STATUS_NONE: + break; + case mNpcW_INFO_STATUS_WALKING: + if (*timer_p == 0) { + aSNMgr_walk_to_goal_npc(list_p, *winfo_p, (u8*)&manager->npc_info.to_block[i], (u8*)manager->npc_info.in_block_num, manager, walk_flag); + } else { + (*timer_p)--; + if (*timer_p < 0) { + *timer_p = 0; + } + } + break; + case mNpcW_INFO_STATUS_STAY_IN_BLOCK: + break; + case mNpcW_INFO_STATUS_ARRIVE: + aSNMgr_go_back_home(manager->npc_info.walk_p, winfo_p, manager->npc_info.winfo_p, *count_p); + break; + case mNpcW_INFO_STATUS_4: + break; + } + } + + schedule_p++; + animal_p++; + list_p++; + winfo_p++; + count_p++; + timer_p++; + } +} + +static int aSNMgr_set_go_home_status_sub(SET_NPC_MANAGER_ACTOR* manager, int anm_idx, int bx, int bz, int status) { + int ux; + int uz; + xyz_t pos; + int ret = FALSE; + + + if (aSNMgr_get_safe_utnum_in_block(&ux, &uz, bx, bz) == TRUE) { + mNpc_NpcList_c* list_p = &manager->npc_info.list_p[anm_idx]; + mNpcW_info_c* winfo_p = manager->npc_info.winfo_p[anm_idx]; + + mFI_BkandUtNum2Wpos(&pos, bx, bz, ux, uz); + list_p->position.x = pos.x; + list_p->position.z = pos.z; + + if (winfo_p != NULL) { + u32* count_p = manager->npc_info.count_p[anm_idx]; + + winfo_p->status = status; + winfo_p->goal_type = mNpcW_GOAL_MY_HOME; + winfo_p->goal_block_x = bx; + winfo_p->goal_block_z = bz; + *count_p = 108001; + } + + ret = TRUE; + } + + return ret; +} + +static int aSNMgr_set_go_home_status(SET_NPC_MANAGER_ACTOR* manager, int anm_idx, int bx, int bz, int player_bx, int player_bz) { + // clang-format off + static int add_bx[] = { 0, 0, 0, -1, 1 }; + static int add_bz[] = { 0, -1, 1, 0, 0 }; + static u8 walk_status[] = { + mNpcW_INFO_STATUS_ARRIVE, + mNpcW_INFO_STATUS_WALKING, + mNpcW_INFO_STATUS_WALKING, + mNpcW_INFO_STATUS_WALKING, + mNpcW_INFO_STATUS_WALKING, + }; + // clang-format on + Animal_c* animal_p = &manager->npc_info.animal_p[anm_idx]; + int home_bx = animal_p->home_info.block_x; + int home_bz = animal_p->home_info.block_z; + int chk_bx; + int chk_bz; + int i; + int ret = FALSE; + + for (i = 0; i < 5; i++) { + chk_bx = home_bx + add_bx[i]; + chk_bz = home_bz + add_bz[i]; + + if (mFI_BlockCheck(chk_bx, chk_bz) == TRUE) { + if ((chk_bx != bx || chk_bz != bz) && (chk_bx != player_bx || chk_bz != player_bz)) { + if (aSNMgr_set_go_home_status_sub(manager, anm_idx, chk_bx, chk_bz, walk_status[i]) == TRUE) { + ret = TRUE; + break; + } + } + } + } + + return ret; +} + +static void aSNMgr_set_stay_home_status(SET_NPC_MANAGER_ACTOR* manager, int anm_idx) { + mNpc_NpcList_c* list_p = &manager->npc_info.list_p[anm_idx]; + mNpcW_info_c* winfo_p = manager->npc_info.winfo_p[anm_idx]; + Animal_c* animal_p = &manager->npc_info.animal_p[anm_idx]; + u32* count_p; + + list_p->position = list_p->house_position; + animal_p->is_home = TRUE; + if (winfo_p != NULL) { + mNpcW_ClearNpcWalkInfo(winfo_p, 1); + count_p = manager->npc_info.count_p[anm_idx]; + *count_p = 108001; + } +} + +static void aSNMgr_force_go_home_event_start(SET_NPC_MANAGER_ACTOR* manager) { + Animal_c* animal_p = manager->npc_info.animal_p; + mNpc_NpcList_c* list_p = manager->npc_info.list_p; + int player_bx = manager->player_pos.now_block[0]; + int player_bz = manager->player_pos.now_block[1]; + int now_bx; + int now_bz; + int goal_bx = 0; + int goal_bz = 0; + int event_type; + int event_map_idx; + u32 block_kind; + int i; + + event_type = mEvMN_GetEventTypeMap(); + if (event_type != -1) { + event_map_idx = mEvMN_GetMapIdx(event_type); + if (event_map_idx != -1) { + block_kind = mEvMN_GetEventBlockKind(event_map_idx); + mFI_BlockKind2BkNum(&goal_bx, &goal_bz, block_kind); + } + } + + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (((manager->npc_info.exist >> i) & 1) == 1 && ((manager->npc_info.joint_event >> i) & 1) == 0) { + if (mFI_Wpos2BlockNum(&now_bx, &now_bz, list_p->position) == TRUE && !animal_p->is_home) { + if (now_bx == goal_bx && now_bz == goal_bz) { + if (animal_p->home_info.block_x != now_bx || animal_p->home_info.block_z != now_bz) { + if (!aSNMgr_set_go_home_status(manager, i, goal_bx, goal_bz, player_bx, player_bz)) { + aSNMgr_set_stay_home_status(manager, i); + } + } + } + } + } + + animal_p++; + list_p++; + } +} + +static void aSNMgr_force_go_home(SET_NPC_MANAGER_ACTOR* manager) { + mNPS_schedule_c* schedule_p = manager->npc_info.schedule_p; + Animal_c* animal_p = manager->npc_info.animal_p; + mNpc_NpcList_c* list_p = manager->npc_info.list_p; + mNpcW_info_c** winfo_p = manager->npc_info.winfo_p; + int* timer_p = manager->npc_info.timer; + int player_bx = manager->player_pos.now_block[0]; + int player_bz = manager->player_pos.now_block[1]; + int bx; + int bz; + int i; + + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (aSNMgr_chk_exist_and_appear_and_event(manager, mNpcW_APPEAR_STATUS_REGULAR, i) == TRUE) { + if (mFI_Wpos2BlockNum(&bx, &bz, list_p->position) == TRUE) { + if (!aSNMgr_check_move_npc_schedule(schedule_p, animal_p) && *timer_p == 0) { + if (animal_p->home_info.block_x != bx || animal_p->home_info.block_z != bz) { + aSNMgr_set_go_home_status(manager, i, -1, -1, player_bx, player_bz); + } else if ((bx != player_bx || bz != player_bz) && animal_p->is_home == TRUE && *winfo_p != NULL) { + aSNMgr_go_back_home_sub(manager->npc_info.walk_p, winfo_p, manager->npc_info.winfo_p); + } + } + } + } + + schedule_p++; + animal_p++; + list_p++; + winfo_p++; + timer_p++; + } +} + +static void aSNMgr_reset_npc(SET_NPC_MANAGER_ACTOR* manager) { + mNpc_NpcList_c* list_p = manager->npc_info.list_p; + aSNMgr_make_c* make_p = manager->npc_info.make; + u16 appear; + int* timer_p = manager->npc_info.timer; + int i; + + appear = manager->npc_info.appear; + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (aSNMgr_chk_exist_and_appear(manager, mNpcW_APPEAR_STATUS_GUEST, i) == TRUE) { + if (aSNMgr_get_make_npc_idx(list_p->name, i, make_p) == -1) { + appear &= ~(1 << i); + *timer_p = 10800; // is this supposed to be 108001? + } + } + + list_p++; + timer_p++; + } + + manager->npc_info.appear = appear; +} + +static void aSNMgr_set_npc_regular(SET_NPC_MANAGER_ACTOR* manager) { + aSNMgr_npc_info_c* npc_info_p = &manager->npc_info; + Animal_c* animal_p = npc_info_p->animal_p; + mNpc_NpcList_c* list_p = npc_info_p->list_p; + mNpcW_info_c** winfo_p = npc_info_p->winfo_p; + aSNMgr_event_info_c* info_p = &npc_info_p->event_info; + u16 joint_event = npc_info_p->joint_event; + int bx; + int bz; + int ux; + int uz; + int i; + + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + int set = TRUE; + + if (aSNMgr_chk_exist_and_appear(manager, mNpcW_APPEAR_STATUS_REGULAR, i) == TRUE) { + if (aSNMgr_check_in_scope(list_p->position, &manager->scope) == TRUE) { + if (((joint_event >> i) & 1) == 1) { + if (info_p->type != mEv_EVENT_KAMAKURA) { + aSNMgr_set_npc_event(animal_p, list_p, info_p, i); + } else { + set = FALSE; + } + } + + if (set == TRUE) { + int make_flag; + + aSNMgr_get_block_ut_num_set_npc(&bx, &bz, &ux, &uz, list_p); + make_flag = aSNMgr_set_appear_info_regular(manager, bx, bz, i); + if (make_flag == TRUE) { + if (((joint_event >> i) & 1) == 0) { + make_flag = aSNMgr_get_safe_utnum(&ux, &uz, bx, bz, *winfo_p); + } + + if (make_flag == TRUE && + aSNMgr_set_make_npc(manager->npc_info.make, animal_p->id.npc_id, bx, bz, ux, uz, info_p, i) != -1) { + manager->npc_info.appear |= 1 << i; + } + } + } + } + } + + animal_p++; + list_p++; + winfo_p++; + } + + switch (mFI_GetPlayerWade()) { + case mFI_WADE_NONE: + aSNMgr_setup_set_proc(manager, aSNMgr_SET_MODE_GUEST); + break; + default: + aSNMgr_setup_set_proc(manager, aSNMgr_SET_MODE_NONE); + break; + } +} + +static void aSNMgr_set_npc_guest(SET_NPC_MANAGER_ACTOR* manager) { + aSNMgr_npc_info_c* npc_info_p = &manager->npc_info; + Animal_c* animal_p = npc_info_p->animal_p; + mNpc_NpcList_c* list_p = npc_info_p->list_p; + mNpcW_info_c** winfo_p = npc_info_p->winfo_p; + aSNMgr_scope_c* scope_p = &manager->guest_scope; + aSNMgr_event_info_c* info_p = &npc_info_p->event_info; + int bx; + int bz; + int ux; + int uz; + int i; + + if (!aSNMgr_chk_arbeit_and_demo_and_halloween() && + !aSNMgr_check_in_block_max(manager->player_pos.now_block[0], manager->player_pos.now_block[1], (u8*)manager->npc_info.in_block_num)) { + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (aSNMgr_chk_exist_and_appear_and_event(manager, mNpcW_APPEAR_STATUS_REGULAR, i) == TRUE) { + if (aSNMgr_check_in_scope(list_p->position, scope_p) == TRUE) { + aSNMgr_get_block_ut_num_set_npc(&bx, &bz, &ux, &uz, list_p); + if (aSNMgr_set_appear_info_guest(manager, *winfo_p, bx, bz) == TRUE && + aSNMgr_get_safe_utnum(&ux, &uz, bx, bz, *winfo_p) == TRUE && + aSNMgr_set_make_npc(manager->npc_info.make, animal_p->id.npc_id, bx, bz, ux, uz, info_p, i) != -1) { + manager->npc_info.appear |= 1 << i; + } + } + } + + animal_p++; + list_p++; + winfo_p++; + } + } +} + +static void aSNMgr_setup_set_proc(SET_NPC_MANAGER_ACTOR* manager, int set_mode) { + // clang-format off + static aSNMgr_SET_PROC set_proc[] = { + (aSNMgr_SET_PROC)&none_proc1, + &aSNMgr_set_npc_regular, + &aSNMgr_set_npc_guest, + }; + // clang-format on + + if (set_mode < 0 || set_mode >= aSNMgr_SET_MODE_NUM) { + set_mode = aSNMgr_SET_MODE_REGULAR; + } + + manager->set_mode = set_mode; + manager->set_proc = set_proc[set_mode]; +} + +static void aSNMgr_actor_move(ACTOR* actorx, GAME* game) { + SET_NPC_MANAGER_ACTOR* manager = (SET_NPC_MANAGER_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + aSNMgr_get_player_pos(&manager->player_pos.pos, game); + switch (mFI_GetPlayerWade()) { + case mFI_WADE_START: + aSNMgr_clear_make_npc(manager->npc_info.make, aSNMgr_EVENT_NORMAL_NPC_NUM); + aSNMgr_renewal_player_next_block(manager); + aSNMgr_renewal_set_scope(manager); + aSNMgr_setup_set_proc(manager, aSNMgr_SET_MODE_REGULAR); + break; + case mFI_WADE_END: + aSNMgr_renewal_player_now_block(manager); + aSNMgr_setup_set_proc(manager, aSNMgr_SET_MODE_GUEST); + break; + case mFI_WADE_NONE: + if (play->fb_fade_type == 0) { + aSNMgr_clear_make_npc(manager->npc_info.make, aSNMgr_EVENT_NORMAL_NPC_NUM); + if (!aSNMgr_chk_arbeit_and_demo_and_halloween()) { + aSNMgr_force_go_home(manager); + aSNMgr_walk_npc(manager, game); + } + } + break; + } + + aSNMgr_move_event_set(manager); + (*manager->set_proc)(manager); + aSNMgr_make_npc(manager, play); + aSNMgr_reset_npc(manager); +} diff --git a/src/game/m_npc_walk.c b/src/game/m_npc_walk.c index ed81a7d2..aa816821 100644 --- a/src/game/m_npc_walk.c +++ b/src/game/m_npc_walk.c @@ -4,7 +4,7 @@ #include "m_random_field.h" #include "m_common_data.h" -static int l_arrive_stay_count[ANIMAL_NUM_MAX]; /* TODO: swap with l_goal_block when bss ordering is fixed */ +static u32 l_arrive_stay_count[ANIMAL_NUM_MAX]; /* TODO: swap with l_goal_block when bss ordering is fixed */ static int l_goal_block[mNpcW_GOAL_BLOCK_NUM][2]; #define mNpcW_TIME_2_SEC(hour, min, sec) ((hour) * 3600 + (min) * 60 + (sec)) @@ -616,14 +616,14 @@ extern int mNpcW_GetAppearStatusWay(u8* status, u8* way, Animal_c* animal) { res = TRUE; } else { - *status = mNpcW_APPEAR_STATUS_0; + *status = mNpcW_APPEAR_STATUS_REGULAR; *way = mNpcW_APPEAR_WAY_NUM; } return res; } -extern int* mNpcW_GetArriveStayCountP(int idx) { +extern u32* mNpcW_GetArriveStayCountP(int idx) { if (idx >= 0 && idx < ANIMAL_NUM_MAX) { return &l_arrive_stay_count[idx]; }