#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; }