mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-06-20 06:41:06 -04:00
1282 lines
41 KiB
C
1282 lines
41 KiB
C
#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);
|
|
}
|