Implement & link m_npc_walk.c

This commit is contained in:
Cuyler36
2023-07-28 21:53:12 -04:00
parent 9d2c21adc4
commit a50058847b
6 changed files with 788 additions and 7 deletions
+5
View File
@@ -107,6 +107,11 @@ m_needlework.c:
m_npc_schedule.c:
.text: [0x803D7570, 0x803D7890]
.data: [0x8065B638, 0x8065B7F0]
m_npc_walk.c:
.text: [0x803D7890, 0x803D88E8]
.rodata: [0x806429F0, 0x80642A00]
.data: [0x8065B7F0, 0x8065B9A0]
.bss: [0x8129CC48, 0x8129CC98]
m_olib.c:
.text: [0x803D88E8, 0x803D8A34]
.rodata: [0x80642A00, 0x80642A10]
+1 -1
View File
@@ -137,7 +137,7 @@ extern int mFI_GetBlockUtNum2FG(mActor_name_t* fg_item, int block_x, int block_z
extern void mFI_UtNum2CenterWpos(xyz_t* wpos, int ut_x, int ut_z);
extern u8 mFI_GetBlockXMax();
extern u8 mFI_GetBlockZMax();
extern u8 mFI_BkNum2BlockType();
extern u8 mFI_BkNum2BlockType(int block_x, int block_z);
extern mFI_sound_source_info_c* mFI_GetSoundSourcePBlockNum(int block_x,int block_z);
extern int mFI_Wpos2UtNum(int* ut_x, int* ut_z, xyz_t wpos);
extern void mFI_ClearFieldData();
+3 -2
View File
@@ -18,8 +18,9 @@ extern "C" {
#define FG_BLOCK_Z_NUM (BLOCK_Z_NUM - 4) /* 6 */
#define FG_BLOCK_TOTAL_NUM (FG_BLOCK_X_NUM * FG_BLOCK_Z_NUM)
#define UT_X_NUM 16 /* Spaces per block (acre) in x direction */
#define UT_Z_NUM 16 /* Spaces per block (acre) in z direction */
#define UT_BASE_NUM 16
#define UT_X_NUM UT_BASE_NUM /* Spaces per block (acre) in x direction */
#define UT_Z_NUM UT_BASE_NUM /* Spaces per block (acre) in z direction */
#define UT_TOTAL_NUM (UT_X_NUM * UT_Z_NUM)
#define IDX_2_UT_X(idx) ((idx) & (UT_X_NUM - 1))
+2
View File
@@ -210,6 +210,8 @@ extern void mNpc_SendMailtoNpc(Mail_c* mail);
extern void mNpc_SetNpcinfo(ACTOR* actor, s8 npc_info_idx);
extern void mNpc_InitNpcAllInfo(int malloc_flag);
extern void mNpc_SetRemoveAnimalNo(u8* remove_animal_no, Animal_c* animals, int remove_no);
extern void mNpc_ClearAnimalPersonalID(AnmPersonalID_c* id);
extern int mNpc_CheckCmpAnimalPersonalID(AnmPersonalID_c* id0, AnmPersonalID_c* id1);
extern void mNpc_PrintRemoveInfo(gfxprint_t* gfxprint);
extern void mNpc_PrintFriendship_fdebug(gfxprint_t* gfxprint);
+49 -4
View File
@@ -21,7 +21,7 @@ typedef struct goal_data_s {
typedef struct goal_data_table_s {
mNpcW_GoalData_c* data_p;
int count;
} mNpc_GoalDataTable_c;
} mNpcW_GoalDataTable_c;
enum {
mNpcW_GOAL_SHRINE, /* Shrine/Wishing Well acre */
@@ -32,15 +32,50 @@ enum {
mNpcW_GOAL_NUM
};
enum {
mNpcW_GOAL_BLOCK_SHRINE,
mNpcW_GOAL_BLOCK_HOME,
mNpcW_GOAL_BLOCK_NUM
};
/* TODO: figure out remaining enums */
enum {
mNpcW_APPEAR_STATUS_0,
mNpcW_APPEAR_STATUS_1,
mNpcW_APPEAR_STATUS_NUM
};
enum {
mNpcW_APPEAR_WAY_UP,
mNpcW_APPEAR_WAY_DOWN,
mNpcW_APPEAR_WAY_LEFT,
mNpcW_APPEAR_WAY_RIGHT,
mNpcW_APPEAR_WAY_NUM
};
/* TODO: figure out remaining enums */
enum {
mNpcW_INFO_STATUS_0,
mNpcW_INFO_STATUS_WALKING,
mNpcW_INFO_STATUS_2,
mNpcW_INFO_STATUS_3,
mNpcW_INFO_STATUS_4,
mNpcW_INFO_STATUS_NUM
};
typedef struct npc_walk_appear_s {
u8 state;
u8 target_direction;
u8 status;
u8 way;
} mNpcW_appear_c;
typedef struct npc_walk_information_s {
AnmPersonalID_c id;
int idx;
u8 state;
u8 status;
u8 goal_type;
u8 goal_block_x;
u8 goal_block_z;
@@ -54,6 +89,16 @@ typedef struct npc_walk_s {
u8 info_max;
} mNpc_walk_c;
extern void mNpcW_ClearNpcWalkInfo(mNpcW_info_c* info, int num);
extern int mNpcW_GetNpcWalkInfoIdx(mNpcW_info_c* info, int num, AnmPersonalID_c* anm_id);
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 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);
#ifdef __cplusplus
}
#endif
+728
View File
@@ -0,0 +1,728 @@
#include "m_npc_walk.h"
#include "libultra/libultra.h"
#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 int l_goal_block[mNpcW_GOAL_BLOCK_NUM][2];
#define mNpcW_TIME_2_SEC(hour, min, sec) ((hour) * 3600 + (min) * 60 + (sec))
#define mNpcW_MAKE_SCHEDULE_TABLE(goal_data) { goal_data, ARRAY_SIZE(goal_data, mNpcW_GoalData_c) }
static u8 l_girl_time_12[] = { mNpcW_GOAL_SHRINE, mNpcW_GOAL_HOME, mNpcW_GOAL_ALONE };
static u8 l_girl_time_18_30[] = { mNpcW_GOAL_SHRINE, mNpcW_GOAL_HOME };
static mNpcW_GoalData_c l_girl_goal_data[] = {
{ NULL, 0, mNpcW_TIME_2_SEC(6, 0, 0) },
{ l_girl_time_12, ARRAY_SIZE(l_girl_time_12, u8), mNpcW_TIME_2_SEC(12, 0, 0) },
{ NULL, 0, mNpcW_TIME_2_SEC(13, 0, 0) },
{ l_girl_time_18_30, ARRAY_SIZE(l_girl_time_18_30, u8), mNpcW_TIME_2_SEC(18, 30, 0) },
{ NULL, 0, mNpcW_TIME_2_SEC(24, 0, 0) }
};
static mNpcW_GoalDataTable_c l_girl_goal_table = mNpcW_MAKE_SCHEDULE_TABLE(l_girl_goal_data);
static u8 l_kogirl_time_ed[] = { mNpcW_GOAL_SHRINE, mNpcW_GOAL_HOME };
static mNpcW_GoalData_c l_kogirl_goal_data[] = {
{ l_kogirl_time_ed, ARRAY_SIZE(l_kogirl_time_ed, u8), mNpcW_TIME_2_SEC(24, 0, 0) }
};
static mNpcW_GoalDataTable_c l_kogirl_goal_table = mNpcW_MAKE_SCHEDULE_TABLE(l_kogirl_goal_data);
static u8 l_boy_time_12[] = { mNpcW_GOAL_ALONE };
static u8 l_boy_time_19_30[] = { mNpcW_GOAL_SHRINE, mNpcW_GOAL_HOME };
static mNpcW_GoalData_c l_boy_goal_data[] = {
{ NULL, 0, mNpcW_TIME_2_SEC(9, 0, 0) },
{ l_boy_time_12, ARRAY_SIZE(l_boy_time_12, u8), mNpcW_TIME_2_SEC(12, 0, 0) },
{ NULL, 0, mNpcW_TIME_2_SEC(14, 0, 0) },
{ l_boy_time_19_30, ARRAY_SIZE(l_boy_time_19_30, u8), mNpcW_TIME_2_SEC(19, 30, 0) },
{ NULL, 0, mNpcW_TIME_2_SEC(24, 0, 0) }
};
static mNpcW_GoalDataTable_c l_boy_goal_table = mNpcW_MAKE_SCHEDULE_TABLE(l_boy_goal_data);
static u8 l_sports_man_time_12[] = { mNpcW_GOAL_SHRINE, mNpcW_GOAL_HOME, mNpcW_GOAL_ALONE, mNpcW_GOAL_ALONE };
static u8 l_sports_man_time_23[] = { mNpcW_GOAL_SHRINE, mNpcW_GOAL_SHRINE, mNpcW_GOAL_HOME, mNpcW_GOAL_HOME, mNpcW_GOAL_ALONE };
static mNpcW_GoalData_c l_sports_man_goal_data[] = {
{ NULL, 0, mNpcW_TIME_2_SEC(6, 30, 0) },
{ l_sports_man_time_12, ARRAY_SIZE(l_sports_man_time_12, u8), mNpcW_TIME_2_SEC(12, 0, 0) },
{ NULL, 0, mNpcW_TIME_2_SEC(12, 30, 0) },
{ l_sports_man_time_23, ARRAY_SIZE(l_sports_man_time_23, u8), mNpcW_TIME_2_SEC(23, 0, 0) },
{ NULL, 0, mNpcW_TIME_2_SEC(24, 0, 0) }
};
static mNpcW_GoalDataTable_c l_sports_man_goal_table = mNpcW_MAKE_SCHEDULE_TABLE(l_sports_man_goal_data);
static u8 l_grim_man_time_ed[] = { mNpcW_GOAL_SHRINE, mNpcW_GOAL_SHRINE, mNpcW_GOAL_SHRINE, mNpcW_GOAL_ALONE, mNpcW_GOAL_ALONE, mNpcW_GOAL_ALONE, mNpcW_GOAL_ALONE, mNpcW_GOAL_ALONE, mNpcW_GOAL_ALONE, mNpcW_GOAL_ALONE };
static mNpcW_GoalData_c l_grim_man_goal_data[] = {
{ l_grim_man_time_ed, ARRAY_SIZE(l_grim_man_time_ed, u8), mNpcW_TIME_2_SEC(24, 0, 0) }
};
static mNpcW_GoalDataTable_c l_grim_man_goal_table = mNpcW_MAKE_SCHEDULE_TABLE(l_grim_man_goal_data);
static u8 l_naniwa_lady_time_1_30[] = { mNpcW_GOAL_SHRINE, mNpcW_GOAL_SHRINE, mNpcW_GOAL_SHRINE, mNpcW_GOAL_SHRINE, mNpcW_GOAL_SHRINE, mNpcW_GOAL_SHRINE, mNpcW_GOAL_SHRINE, mNpcW_GOAL_ALONE, mNpcW_GOAL_ALONE, mNpcW_GOAL_ALONE };
static u8 l_naniwa_lady_time_13[] = { mNpcW_GOAL_HOME };
static u8 l_naniwa_lady_time_21[] = { mNpcW_GOAL_SHRINE, mNpcW_GOAL_SHRINE, mNpcW_GOAL_HOME, mNpcW_GOAL_HOME, mNpcW_GOAL_ALONE };
static mNpcW_GoalData_c l_naniwa_lady_goal_data[] = {
{ l_naniwa_lady_time_1_30, ARRAY_SIZE(l_naniwa_lady_time_1_30, u8), mNpcW_TIME_2_SEC(1, 30, 0) },
{ NULL, 0, mNpcW_TIME_2_SEC(10, 0, 0) },
{ l_naniwa_lady_time_13, ARRAY_SIZE(l_naniwa_lady_time_13, u8), mNpcW_TIME_2_SEC(13, 0, 0) },
{ NULL, 0, mNpcW_TIME_2_SEC(14, 0, 0) },
{ l_naniwa_lady_time_21, ARRAY_SIZE(l_naniwa_lady_time_21, u8), mNpcW_TIME_2_SEC(21, 0, 0) },
{ NULL, 0, mNpcW_TIME_2_SEC(22, 0, 0) },
{ l_naniwa_lady_time_1_30, ARRAY_SIZE(l_naniwa_lady_time_1_30, u8), mNpcW_TIME_2_SEC(24, 0, 0) }
};
static mNpcW_GoalDataTable_c l_naniwa_lady_goal_table = mNpcW_MAKE_SCHEDULE_TABLE(l_naniwa_lady_goal_data);
static mNpcW_GoalDataTable_c* l_looks_goal_table[mNpc_LOOKS_NUM] = {
&l_girl_goal_table,
&l_kogirl_goal_table,
&l_boy_goal_table,
&l_sports_man_goal_table,
&l_grim_man_goal_table,
&l_naniwa_lady_goal_table
};
static mNpcW_GoalData_c* mNpcW_GetGoalDataInfo(int looks, int now_sec) {
int goal_num = l_looks_goal_table[looks]->count;
mNpcW_GoalData_c* goal_data_save = l_looks_goal_table[looks]->data_p;
mNpcW_GoalData_c* goal_data = goal_data_save;
int i;
for (i = 0; i < goal_num; i++) {
if (goal_data->end_time > now_sec) {
break;
}
goal_data++;
}
if (i != goal_num) {
return goal_data;
}
return &goal_data_save[goal_num - 1];
}
static void mNpcW_ClearNpcWalkAppear(mNpcW_appear_c* appear) {
appear->status = mNpcW_APPEAR_STATUS_NUM;
appear->way = mNpcW_APPEAR_WAY_NUM;
}
extern void mNpcW_ClearNpcWalkInfo(mNpcW_info_c* info, int num) {
for (num; num != 0 && info != NULL; num--) {
bzero(info, sizeof(mNpcW_info_c));
mNpc_ClearAnimalPersonalID(&info->id);
info->idx = -1;
info->status = mNpcW_INFO_STATUS_NUM;
info->goal_type = mNpcW_GOAL_NUM;
mNpcW_ClearNpcWalkAppear(&info->appear_info);
info++;
}
}
static void mNpcW_ClearNpcWalk(mNpc_walk_c* walk_info) {
bzero(walk_info, sizeof(mNpc_walk_c));
mNpcW_ClearNpcWalkInfo(walk_info->info, mNpcW_MAX);
}
static int mNpcW_CheckFreeNpcWalkInfo(mNpcW_info_c* info) {
int res = FALSE;
if (info != NULL) {
res = mNpc_CheckFreeAnimalPersonalID(&info->id);
}
return res;
}
static int mNpcW_GetFreeNpcWalkInfoIdx(mNpcW_info_c* info, int num) {
int idx = -1;
int i;
for (i = 0; i < num; i++) {
if (mNpcW_CheckFreeNpcWalkInfo(info) == TRUE) {
idx = i;
break;
}
info++;
}
return idx;
}
extern int mNpcW_GetNpcWalkInfoIdx(mNpcW_info_c* info, int num, AnmPersonalID_c* anm_id) {
int idx = -1;
int i;
if (anm_id != NULL && mNpc_CheckFreeAnimalPersonalID(anm_id) == FALSE) {
for (i = 0; i < num; i++) {
if (mNpc_CheckCmpAnimalPersonalID(anm_id, &info->id) == TRUE) {
idx = i;
break;
}
info++;
}
}
return idx;
}
static int mNpcW_DecideNpc(Animal_c* animal, u16 used) {
int idx;
u16 exist;
u16 possible_goal;
int unused;
int now_sec;
int i;
now_sec = Common_Get(time.now_sec);
exist = 0;
possible_goal = 0;
unused = 0;
idx = -1;
for (i = 0; i < ANIMAL_NUM_MAX; i++) {
if (mNpc_CheckFreeAnimalPersonalID(&animal->id) == FALSE) {
mNpcW_GoalData_c* goal_data;
exist |= (1 << i);
goal_data = mNpcW_GetGoalDataInfo(animal->id.looks, now_sec);
if (goal_data != NULL) {
if (goal_data->count != 0) {
possible_goal |= (1 << i);
if (((used >> i) & 1) == FALSE) {
unused++;
}
}
}
}
animal++;
}
if (unused > 0) {
int selected_num;
u32 selection_field = possible_goal & (exist & ~used); /* clear the possible bitfield to only include unused existing villagers */
selected_num = RANDOM(unused) + 1;
while (selected_num != 0) {
if ((selection_field & 1) == TRUE) {
selected_num--;
}
selection_field >>= 1;
idx++;
}
}
return idx;
}
static void mNpcW_SetNpcWalkInfo(mNpcW_info_c* info, Animal_c* animal, int idx) {
int now_sec = Common_Get(time.now_sec);
mNpcW_GoalData_c* goal_data;
mNpc_CopyAnimalPersonalID(&info->id, &animal->id);
info->idx = idx;
goal_data = mNpcW_GetGoalDataInfo(animal->id.looks, now_sec);
if (goal_data != NULL && goal_data->count != 0) {
info->goal_type = goal_data->types[RANDOM(goal_data->count)];
}
else {
info->goal_type = mNpcW_GOAL_MY_HOME; /* Default to acre the villager's house is in */
}
info->status = mNpcW_INFO_STATUS_WALKING;
}
extern int mNpcW_ChangeNpcWalk(mNpc_walk_c* walk, mNpcW_info_c* info) {
mNpcW_info_c* walk_info = walk->info;
int free_idx;
Animal_c* animals;
int idx = -1;
mNpcW_ClearNpcWalkInfo(info, 1);
free_idx = mNpcW_GetFreeNpcWalkInfoIdx(walk_info, mNpcW_MAX);
if (free_idx != -1) {
mNpcW_info_c* free_info = &walk_info[free_idx];
mNpcW_ClearNpcWalkInfo(free_info, 1);
animals = Save_Get(animals);
idx = mNpcW_DecideNpc(animals, walk->used_idx_bitfield);
if (idx == -1) {
int i;
walk->used_idx_bitfield = 0;
for (i = 0; i < mNpcW_MAX; i++) {
int animal_idx = walk_info[i].idx;
if (animal_idx >= 0 && animal_idx < ANIMAL_NUM_MAX) {
walk->used_idx_bitfield |= (1 << animal_idx);
}
}
idx = mNpcW_DecideNpc(animals, walk->used_idx_bitfield);
}
if (idx != -1) {
mNpcW_SetNpcWalkInfo(free_info, Save_GetPointer(animals[idx]), idx);
walk->used_idx_bitfield |= (1 << idx);
mNpcW_SetGoalBlock(free_info);
}
}
return idx;
}
static int mNpcW_GetAloneBlock(u8* goal_block_x, u8* goal_block_z) {
u8 block_field[FG_BLOCK_Z_NUM + 2];
Animal_c* animal = Save_Get(animals);
mNpc_NpcList_c* npclist = Common_Get(npclist);
u8 animal_count = 0;
int selected;
int bz;
int bx;
int i;
int z;
// 0 1 2 3 4 5 6
// Q - - - - - - -
// A - - - - - - -
// B - - - - - - -
// C - - - - - - -
// D - - - x - - -
// E - - - - - - -
// F - - - - - - -
// Z - - - - - - -
/* Default goal block is D-3 */
*goal_block_x = 3;
*goal_block_z = 4;
bzero(block_field, FG_BLOCK_Z_NUM + 2);
/* Log all acres which currently have a villager in them */
for (i = 0; i < ANIMAL_NUM_MAX; i++) {
if (mNpc_CheckFreeAnimalPersonalID(&animal->id) == FALSE) {
int block_x;
int block_z;
if (mFI_Wpos2BlockNum(&block_x, &block_z, npclist->position) == TRUE) {
animal_count++;
block_field[block_z] |= (1 << block_x);
}
}
animal++;
npclist++;
}
/* Select a random empty acre to go to */
z = 1;
selected = RANDOM(FG_BLOCK_TOTAL_NUM - animal_count);
/* Find the random acre and set output */
for (bz = 1; bz < BLOCK_Z_NUM - 3; bz++) {
for (bx = 1; bx < BLOCK_X_NUM - 1; bx++) {
if ((((block_field[z]) >> bx) & 1) == 0) {
if (selected <= 0) {
*goal_block_x = bx;
*goal_block_z = bz;
return TRUE;
}
else {
selected--;
}
}
}
z++;
}
return FALSE;
}
static void mNpcW_GetBlockXZNumExceptHome(int* goal_block_x, int* goal_block_z, Animal_c* animal) {
u8 possible_x = 0b11111111;
u8 possible_z = 0b11111111;
int x_num = 0;
int z_num = 0;
int selected_x;
int selected_z;
int i;
for (i = 0; i < ANIMAL_NUM_MAX; i++) {
if (mNpc_CheckFreeAnimalPersonalID(&animal->id) == FALSE) {
u8 home_block_x = animal->home_info.block_x - 1;
u8 home_block_z = animal->home_info.block_z - 1;
if (((possible_x >> home_block_x) & 1) == 1) {
x_num++;
possible_x &= ~(1 << home_block_x);
}
if (((possible_z >> home_block_z) & 1) == 1) {
z_num++;
possible_z &= ~(1 << home_block_z);
}
}
animal++;
}
selected_x = RANDOM(FG_BLOCK_X_NUM - x_num);
selected_z = RANDOM(FG_BLOCK_Z_NUM - z_num);
for (i = 0; i < FG_BLOCK_X_NUM; i++) {
if (((possible_x >> i) & 1) == 1) {
if (selected_x <= 0) {
break;
}
else {
selected_x--;
}
}
}
*goal_block_x = i + 1;
for (i = 0; i < FG_BLOCK_Z_NUM; i++) {
if (((possible_z >> i) & 1) == 1) {
if (selected_z <= 0) {
break;
}
else {
selected_z--;
}
}
}
*goal_block_z = i + 1;
if (*goal_block_x <= 0 || *goal_block_x >= BLOCK_X_NUM || *goal_block_z <= 0 || *goal_block_z >= (BLOCK_Z_NUM - 2)) {
*goal_block_x = 4;
*goal_block_z = 3;
}
}
static int mNpcW_CheckDiffBlockWalkNpcHome(int block_x, int block_z, mNpcW_info_c* info) {
int res = FALSE;
Anmhome_c* home;
int i;
for (i = 0; i < mNpcW_MAX; i++) {
if (info->idx != -1) {
home = Save_GetPointer(animals[info->idx].home_info);
if (home->block_x == block_x && home->block_z == block_z) {
break;
}
}
info++;
}
if (i == mNpcW_MAX) {
res = TRUE;
}
return res;
}
static void mNpcW_SetHomeBlockSource(mNpc_walk_c* walk, Animal_c* animal) {
Animal_c* animal_p = animal;
u16 diff_animal_field;
int diff_animal_num;
int i;
l_goal_block[mNpcW_GOAL_BLOCK_HOME][0] = 0;
l_goal_block[mNpcW_GOAL_BLOCK_HOME][1] = 0;
animal = animal_p;
diff_animal_field = 0;
diff_animal_num = 0;
for (i = 0; i < ANIMAL_NUM_MAX; i++) {
if (mNpc_CheckFreeAnimalPersonalID(&animal->id) == FALSE) {
Anmhome_c* home = &animal->home_info;
if (home->block_x != 0xFF && home->block_z != 0xFF) {
if (mNpcW_CheckDiffBlockWalkNpcHome(home->block_x, home->block_z, walk->info) == TRUE) {
diff_animal_num++;
diff_animal_field |= (1 << i);
}
}
}
animal++;
}
if (diff_animal_num > 0) {
int selected = RANDOM(diff_animal_num);
animal = animal_p;
for (i = 0; i < ANIMAL_NUM_MAX; i++) {
if (((diff_animal_field >> i) & 1) == 1) {
if (selected == 0) {
l_goal_block[mNpcW_GOAL_BLOCK_HOME][0] = animal->home_info.block_x;
l_goal_block[mNpcW_GOAL_BLOCK_HOME][1] = animal->home_info.block_z;
break;
}
else {
selected--;
}
}
animal++;
}
}
if (l_goal_block[mNpcW_GOAL_BLOCK_HOME][0] == 0 || l_goal_block[mNpcW_GOAL_BLOCK_HOME][1] == 0) {
mNpcW_GetBlockXZNumExceptHome(&l_goal_block[mNpcW_GOAL_BLOCK_HOME][0], &l_goal_block[mNpcW_GOAL_BLOCK_HOME][1], animal_p);
}
if (
l_goal_block[mNpcW_GOAL_BLOCK_HOME][0] <= 0 || l_goal_block[mNpcW_GOAL_BLOCK_HOME][0] >= BLOCK_X_NUM ||
l_goal_block[mNpcW_GOAL_BLOCK_HOME][1] <= 0 || l_goal_block[mNpcW_GOAL_BLOCK_HOME][1] >= (BLOCK_Z_NUM - 2)
) {
l_goal_block[mNpcW_GOAL_BLOCK_HOME][0] = 4;
l_goal_block[mNpcW_GOAL_BLOCK_HOME][1] = 3;
}
}
static void mNpcW_InitGoalBlockSource(mNpc_walk_c* walk, Animal_c* animal) {
int shrine_x;
int shrine_z;
if (mFI_BlockKind2BkNum(&shrine_x, &shrine_z, mRF_BLOCKKIND_SHRINE) == FALSE) {
shrine_x = 4;
shrine_z = 3;
}
l_goal_block[mNpcW_GOAL_BLOCK_SHRINE][0] = shrine_x;
l_goal_block[mNpcW_GOAL_BLOCK_SHRINE][1] = shrine_z;
mNpcW_SetHomeBlockSource(walk, animal);
}
extern void mNpcW_SetGoalBlock(mNpcW_info_c* info) {
switch (info->goal_type) {
case mNpcW_GOAL_SHRINE:
{
info->goal_block_x = l_goal_block[mNpcW_GOAL_BLOCK_SHRINE][0];
info->goal_block_z = l_goal_block[mNpcW_GOAL_BLOCK_SHRINE][1];
break;
}
case mNpcW_GOAL_HOME:
{
info->goal_block_x = l_goal_block[mNpcW_GOAL_BLOCK_HOME][0];
info->goal_block_z = l_goal_block[mNpcW_GOAL_BLOCK_HOME][1];
break;
}
case mNpcW_GOAL_ALONE:
{
mNpcW_GetAloneBlock(&info->goal_block_x, &info->goal_block_z);
break;
}
case mNpcW_GOAL_MY_HOME:
{
int idx = info->idx;
if (idx == -1) {
idx = 0;
}
info->goal_block_x = Save_Get(animals[idx]).home_info.block_x;
info->goal_block_z = Save_Get(animals[idx]).home_info.block_z;
break;
}
default:
{
info->goal_block_x = 4;
info->goal_block_z = 3;
break;
}
}
if (info->goal_block_x <= 0 || info->goal_block_x >= BLOCK_X_NUM || info->goal_block_z <= 0 || info->goal_block_z >= (BLOCK_Z_NUM - 2)) {
info->goal_block_x = 4;
info->goal_block_z = 3;
}
}
extern void mNpcW_InitNpcWalk(mNpc_walk_c* walk) {
Animal_c* animal;
int npc_max;
mNpcW_info_c* info = walk->info;
int idx;
int i;
mNpcW_ClearNpcWalk(walk);
bzero(l_goal_block, sizeof(l_goal_block));
bzero(l_arrive_stay_count, sizeof(l_arrive_stay_count));
animal = Save_Get(animals);
npc_max = mNpcW_GET_WALK_NUM(Save_Get(now_npc_max));
for (i = 0; i < npc_max; i++) {
idx = mNpcW_DecideNpc(animal, walk->used_idx_bitfield);
if (idx == -1) {
break;
}
mNpcW_SetNpcWalkInfo(info, Save_GetPointer(animals[idx]), idx);
walk->used_idx_bitfield |= (1 << idx);
info++;
}
mNpcW_InitGoalBlockSource(walk, animal);
}
extern int mNpcW_GetAppearStatusWay(u8* status, u8* way, Animal_c* animal) {
mNpc_walk_c* walk = Common_GetPointer(npc_walk);
int info_idx;
int res = FALSE;
*status = mNpcW_APPEAR_STATUS_NUM;
info_idx = mNpcW_GetNpcWalkInfoIdx(walk->info, mNpcW_MAX, &animal->id);
if (info_idx >= 0) {
*status = walk->info[info_idx].appear_info.status;
*way = walk->info[info_idx].appear_info.way;
res = TRUE;
}
else {
*status = mNpcW_APPEAR_STATUS_0;
*way = mNpcW_APPEAR_WAY_NUM;
}
return res;
}
extern int* mNpcW_GetArriveStayCountP(int idx) {
if (idx >= 0 && idx < ANIMAL_NUM_MAX) {
return &l_arrive_stay_count[idx];
}
return NULL;
}
extern int mNpcW_GetWalkInfoStatusGoalAnimalIdx(int* status, int* goal, int idx) {
int res;
*status = mNpcW_INFO_STATUS_NUM;
*goal = mNpcW_GOAL_NUM;
res = FALSE;
if (idx >= 0 && idx < ANIMAL_NUM_MAX) {
mNpc_walk_c* walk = Common_GetPointer(npc_walk);
int info_idx = mNpcW_GetNpcWalkInfoIdx(walk->info, mNpcW_MAX, &Save_Get(animals[idx]).id);
if (info_idx >= 0) {
res = TRUE;
*status = walk->info[info_idx].status;
*goal = walk->info[info_idx].goal_type;
}
}
return res;
}
extern int mNpcW_GetNearGate(int* target_ut_x, int* target_ut_z, int block_x, int block_z, int ut_x, int ut_z) {
u8 block_type;
int t_ut_x;
int t_ut_z;
mRF_gate_c* gate;
int gate_count;
int x;
int z;
int i;
int direction;
int res = FALSE;
*target_ut_x = UT_X_NUM;
*target_ut_z = UT_Z_NUM;
if (ut_x >= 0 && ut_x < UT_X_NUM && ut_z >= 0 && ut_z < UT_Z_NUM) {
block_type = mFI_BkNum2BlockType(block_x, block_z);
t_ut_x = ut_x < (UT_X_NUM / 2) ? ut_x : UT_X_NUM - ut_x;
t_ut_z = ut_z < (UT_Z_NUM / 2) ? ut_z : UT_Z_NUM - ut_z;
if (t_ut_x < t_ut_z) {
if (ut_x < (UT_X_NUM / 2)) {
direction = mRF_DIRECT_WEST;
}
else {
direction = mRF_DIRECT_EAST;
}
}
else {
if (ut_z < (UT_Z_NUM / 2)) {
direction = mRF_DIRECT_NORTH;
}
else {
direction = mRF_DIRECT_SOUTH;
}
}
gate = mRF_BlockTypeDirect2GateData(&gate_count, block_type, direction);
if (gate != NULL && gate_count > 0) {
for (i = 0; i < gate_count; i++) {
int difference;
x = gate->ut1 & 0xF;
z = gate->ut1 >> 4;
/* BUG: this is likely meant to be 'if (direction == mRF_DIRECT_WEST || direction == mRF_DIRECT_EAST)' */
#ifndef BUGFIXES
if (direction == mRF_DIRECT_WEST || direction == mRF_DIRECT_WEST) {
#else
if (direction == mRF_DIRECT_WEST || direction == mRF_DIRECT_EAST) {
#endif
difference = ut_z - z;
difference = ABS(difference);
}
else {
difference = ut_x - x;
difference = ABS(difference);
}
if (difference < UT_BASE_NUM) {
*target_ut_x = x;
*target_ut_z = z;
res = TRUE;
}
gate++;
}
}
}
return res;
}