From 5eb42434b0154b2627aee171221466a94c62f9bf Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Thu, 14 Aug 2025 08:47:31 -0400 Subject: [PATCH] Add missing files for Aus version --- src/AUS/game/m_collision_bg.c | 1965 +++++++++++++++++++++ src/AUS/game/m_collision_bg_block.c_inc | 88 + src/AUS/game/m_collision_bg_column.c_inc | 578 ++++++ src/AUS/game/m_collision_bg_info.c_inc | 1146 ++++++++++++ src/AUS/game/m_collision_bg_line.c_inc | 593 +++++++ src/AUS/game/m_collision_bg_math.c | 457 +++++ src/AUS/game/m_collision_bg_move.c_inc | 496 ++++++ src/AUS/game/m_collision_bg_rewrite.c_inc | 183 ++ src/AUS/game/m_collision_bg_wall.c_inc | 662 +++++++ src/AUS/game/m_collision_bg_water.c_inc | 184 ++ 10 files changed, 6352 insertions(+) create mode 100644 src/AUS/game/m_collision_bg.c create mode 100644 src/AUS/game/m_collision_bg_block.c_inc create mode 100644 src/AUS/game/m_collision_bg_column.c_inc create mode 100644 src/AUS/game/m_collision_bg_info.c_inc create mode 100644 src/AUS/game/m_collision_bg_line.c_inc create mode 100644 src/AUS/game/m_collision_bg_math.c create mode 100644 src/AUS/game/m_collision_bg_move.c_inc create mode 100644 src/AUS/game/m_collision_bg_rewrite.c_inc create mode 100644 src/AUS/game/m_collision_bg_wall.c_inc create mode 100644 src/AUS/game/m_collision_bg_water.c_inc diff --git a/src/AUS/game/m_collision_bg.c b/src/AUS/game/m_collision_bg.c new file mode 100644 index 00000000..f78a87d3 --- /dev/null +++ b/src/AUS/game/m_collision_bg.c @@ -0,0 +1,1965 @@ +#include "m_collision_bg.h" + +#include "m_field_info.h" +#include "m_name_table.h" +#include "m_actor.h" +#include "libultra/libultra.h" +#include "m_common_data.h" +#include "m_random_field.h" +#include "sys_matrix.h" + +typedef struct { + xyz_t pos; + f32 height; + f32 radius; + s16 atr_wall; + int ux; + int uz; +} mCoBG_column_c; + +typedef struct { + f32 start_top; + f32 start_btm; + f32 end_top; + f32 end_btm; + }mCoBG_WallBounds_c; + +typedef struct { + f32 start[2]; + f32 end[2]; + mCoBG_WallBounds_c wall_bounds; + f32 normal[2]; + s16 normal_angle; + u8 wall_name; + mCoBG_bg_regist_c* regist_p; + u8 atr_wall; +} mCoBG_unit_vec_info_c; + +typedef struct { + f32 start[2]; + f32 end[2]; +} mCoBG_angle_vec_info_c; + +#define mCoBG_UNIT_VEC_INFO_MAX 128 + +typedef struct { + int unit_count; + mCoBG_unit_vec_info_c unit[mCoBG_UNIT_VEC_INFO_MAX]; + int col_count; + mCoBG_column_c column[16]; + mCoBG_angle_vec_info_c angle_vec; +} mCoBG_vec_info_c; + +typedef struct { + f32 t0; + f32 t1; +} mCoBG_tab_c; + +static mCoBG_tab_c mCoBG_tab_data[] = { { 5.0f, 10.0f }, { 0.000001f, 0.000002f } }; + +static mCoBG_vec_info_c l_VecInf; +static mCoBG_ActorInf_c l_ActorInf; +static mCoBG_mBgMgr_c l_mBgMgr; + +static void mCoBG_SetMoveBgContactSide(mCoBG_bg_regist_c* regist_p, ACTOR* actorx, s16 angle); +static void mCoBG_MakeUnitVector(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, s16 unit_count, u8 check_type, s16 atr_wall, s16 old_on_ground, s16 old_in_water); +static void mCoBG_MakeMoveBgVector(mCoBG_vec_info_c* vec_info, mCoBG_mBgMgr_c* mbg_mgr, const xyz_t* pos, u8 check_type); +static void mCoBG_MakeColumnCollisionData(mCoBG_column_c* column, int* column_count, mCoBG_UnitInfo_c* ut_info, int unit_count, int old_on_ground, mCoBG_COLUMN_CHECK_ITEM_TYPE_PROC check_item_proc, int start, int end); +static void mCoBG_MakeCircleDefenceWall(mCoBG_ActorInf_c* actor_info, s16 attr_wall); +static void mCoBG_ColumnWallCheck(xyz_t* rev, mCoBG_ActorInf_c* actor_info, const xyz_t* pos, mCoBG_column_c* column, int column_count, s16 atr_wall); +static f32 mCoBG_GetBGHeight_Column(const xyz_t* pos, mCoBG_UnitInfo_c* unit_info); +static void mCoBG_MoveBgGroundCheck(xyz_t* rev_pos, mCoBG_ActorInf_c* actor_info, ACTOR* actorx, mCoBG_CheckResult_c* result, s_xyz* angle); + +static u8 mCoBG_bridge_search_water[] = { 3, 6, 12, 9, 240, 1, 8, 2, 4, 3, 6, 12, 9 }; +static u8 mCoBG_grass3_search_water[] = { 3, 6, 12, 9 }; + +typedef struct { + s16 norm_angle; + f32 norm[2]; + u8 wall_name; +} mCoBG_forbid_vec_data_c; + +static mCoBG_forbid_vec_data_c mCoBG_make_vector_table[] = { + {DEG2SHORT_ANGLE2(0.0f), {0.0f, 1.0f}, mCoBG_WALL_UP}, + {DEG2SHORT_ANGLE2(-90.0f), {-1.0f, 0.0f}, mCoBG_WALL_RIGHT}, + {DEG2SHORT_ANGLE2(90.0f), {1.0f, 0.0f}, mCoBG_WALL_LEFT}, + {DEG2SHORT_ANGLE2(180.0f), {0.0f, -1.0f}, mCoBG_WALL_DOWN}, + {DEG2SHORT_ANGLE2(45.0f), {SQRT_OF_2_DIV_2, SQRT_OF_2_DIV_2}, mCoBG_WALL_SLATE_UP}, + {DEG2SHORT_ANGLE2(135.0f), {SQRT_OF_2_DIV_2, -SQRT_OF_2_DIV_2}, mCoBG_WALL_SLATE_DOWN}, + {DEG2SHORT_ANGLE2(225.0f), {-SQRT_OF_2_DIV_2, -SQRT_OF_2_DIV_2}, mCoBG_WALL_SLATE_UP}, + {DEG2SHORT_ANGLE2(315.0f), {-SQRT_OF_2_DIV_2, SQRT_OF_2_DIV_2}, mCoBG_WALL_SLATE_DOWN}, +}; + +static s16 mCoBG_forbid_vector_idx[][2] = { + {4, -1}, {5, -1}, {6, -1}, {7, -1}, {-1, -1}, {0, -1}, {1, -1}, {2, -1}, + {3, -1}, {3, -1}, {6, -1}, {5, -1}, {4, -1}, {5, -1}, {6, -1}, {7, -1}, + {0, -1}, {1, -1}, {2, -1}, {3, -1}, {0, -1}, {1, -1}, {2, -1}, {3, -1}, + {0, 2}, {3, 2}, {3, 1}, {0, 1}, {4, -1}, {5, -1}, {6, -1}, {7, -1}, + {0, 2}, {3, 2}, {3, 1}, {0, 1}, +}; + +static xyz_t mCoBG_unit_offset[mCoBG_DIRECT_NUM] = { + { 0.0f, 0.0f, -mFI_UNIT_BASE_SIZE_F }, + { -mFI_UNIT_BASE_SIZE_F, 0.0f, 0.0f }, + { 0.0f, 0.0f, mFI_UNIT_BASE_SIZE_F }, + { mFI_UNIT_BASE_SIZE_F, 0.0f, 0.0f }, + { -mFI_UNIT_BASE_SIZE_F, 0.0f, -mFI_UNIT_BASE_SIZE_F }, + { -mFI_UNIT_BASE_SIZE_F, 0.0f, mFI_UNIT_BASE_SIZE_F }, + { mFI_UNIT_BASE_SIZE_F, 0.0f, mFI_UNIT_BASE_SIZE_F }, + { mFI_UNIT_BASE_SIZE_F, 0.0f, -mFI_UNIT_BASE_SIZE_F } +}; + +static void mCoBG_PlussDirectOffset(xyz_t* ofs_wpos, xyz_t wpos, int direct) { + if (ofs_wpos != NULL && direct >= 0 && direct < mCoBG_DIRECT_NUM) { + ofs_wpos->x = wpos.x + mCoBG_unit_offset[direct].x; + ofs_wpos->y = wpos.y + mCoBG_unit_offset[direct].y; + ofs_wpos->z = wpos.z + mCoBG_unit_offset[direct].z; + } +} + +static void mCoBG_SetXyz_t(xyz_t* pos, f32 x, f32 y, f32 z) { + pos->x = x; + pos->y = y; + pos->z = z; +} + +static void mCoBG_SetXZ(f32* xz, f32 x, f32 z) { + xz[0] = x; + xz[1] = z; +} + +static void mCoBG_Wpos2Upos(xyz_t* upos, xyz_t wpos, int ut_x, int ut_z) { + upos->x = wpos.x - (ut_x * mFI_UT_WORLDSIZE_X_F); + upos->z = wpos.z - (ut_z * mFI_UT_WORLDSIZE_Z_F); + + upos->x -= mFI_UT_WORLDSIZE_HALF_X_F; + upos->z -= mFI_UT_WORLDSIZE_HALF_Z_F; +} + +static void mCoBG_Unit2UnitInfo_OutOfUnitPos(mCoBG_UnitInfo_c* unit_info, int ut_x, int ut_z) { + mActor_name_t* item_p; + + unit_info->ut_x = ut_x; + unit_info->ut_z = ut_z; + unit_info->collision = mFI_UtNum2UtCol(ut_x, ut_z); + unit_info->base_height = mFI_UtNum2BaseHeight(ut_x, ut_z); + unit_info->leftUp_offset = unit_info->collision->data.top_left * 10.0f + unit_info->base_height; + unit_info->leftDown_offset = unit_info->collision->data.bot_left * 10.0f + unit_info->base_height; + unit_info->rightDown_offset = unit_info->collision->data.bot_right * 10.0f + unit_info->base_height; + unit_info->rightUp_offset = unit_info->collision->data.top_right * 10.0f + unit_info->base_height; + unit_info->slate_flag = unit_info->collision->data.slate_flag; + unit_info->attribute = unit_info->collision->data.unit_attribute; + + item_p = mFI_UtNum2UtFG(ut_x, ut_z); + + if (item_p != NULL) { + unit_info->item = *item_p; + } + else { + unit_info->item = EMPTY_NO; + } +} + +static void mCoBG_Wpos2UnitInfo(mCoBG_UnitInfo_c* unit_info, xyz_t wpos) { + xyz_t upos = { 0.0f, 0.0f, 0.0f }; + int ut_x; + int ut_z; + + mFI_Wpos2UtNum(&ut_x, &ut_z, wpos); + mCoBG_Unit2UnitInfo_OutOfUnitPos(unit_info, ut_x, ut_z); + mCoBG_Wpos2Upos(&upos, wpos, ut_x, ut_z); + unit_info->unit_pos[0] = upos.x; + unit_info->unit_pos[1] = upos.z; +} + + +/* +Area unit triangle + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 +1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 +1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 +1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 +1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 +1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 +1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 +1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 +1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 +1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 +1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 + +Bias towards the top and left triangles. +Top: 440 +Left: 419 +Bottom: 361 +Right: 380 + +NOTE: The top of the triangle is denoted as the "bottom" by the devs as it is in the -Z direction. +*/ + +/* This function works on a "unit position" which is [-20.0f, 20.0f) in XZ */ +static void mCoBG_GetUnitArea(mCoBG_UnitInfo_c* unit_info, s16* unit_area) { + f32 x = unit_info->unit_pos[0]; + f32 z = unit_info->unit_pos[1]; + + // Determine the triangle based on the x and z coordinates + if (x < z) { + if (z > -x) { + unit_area[0] = mCoBG_AREA_S; + } + else { + unit_area[0] = mCoBG_AREA_W; + } + } + else if (z > -x) { + unit_area[0] = mCoBG_AREA_E; + } + else { // z <= x && z <= -x + unit_area[0] = mCoBG_AREA_N; + } +} + + +static void mCoBG_GetGroundAngleFromVtx3(s_xyz* ground_angle, f32* v0, f32* v1, f32* v2, s16 unit_area) { + if (ground_angle != NULL) { + xyz_t avg; + f32 a0; + f32 a1; + + ground_angle->y = 0; + avg.x = 0.5f * (v1[0] + v2[0]); + avg.y = 0.5f * (v1[1] + v2[1]); + avg.z = 0.5f * (v1[2] + v2[2]); + + switch (unit_area) { + case mCoBG_AREA_N: + { + a0 = v0[2] - avg.z; + a1 = v0[1] - avg.y; + ground_angle->x = atans_table(a0, -a1); + + a0 = v1[0] - v2[0]; + a1 = v1[1] - v2[1]; + ground_angle->z = atans_table(a0, a1); + break; + } + + case mCoBG_AREA_S: + { + a0 = avg.z - v0[2]; + a1 = -(avg.y - v0[1]); + ground_angle->x = atans_table(a0, a1); + + a0 = v2[0] - v1[0]; + a1 = v2[1] - v1[1]; + ground_angle->z = atans_table(a0, a1); + break; + } + + case mCoBG_AREA_W: + { + a0 = v2[2] - v1[2]; + a1 = v2[1] - v1[1]; + ground_angle->x = atans_table(a0, -a1); + + a0 = v0[0] - avg.x; + a1 = v0[1] - avg.y; + ground_angle->z = atans_table(a0, a1); + break; + } + + case mCoBG_AREA_E: + { + a0 = v1[2] - v2[2]; + a1 = -(v1[1] - v2[1]); + ground_angle->x = atans_table(a0, a1); + + a0 = avg.x - v0[0]; + a1 = avg.y - v0[1]; + ground_angle->z = atans_table(a0, a1); + break; + } + } + } +} + +static void mCoBG_GetArea3Point(s16 area, f32* v0, f32* v1, f32* v2, mCoBG_Collision_u* col) { + switch (area) { + case mCoBG_AREA_N: + { + v0[1] = col->data.center * 10.0f; + v1[0] = mFI_UT_WORLDSIZE_HALF_X_F; + v1[1] = col->data.top_right * 10.0f; + v1[2] = -mFI_UT_WORLDSIZE_HALF_Z_F; + v2[0] = -mFI_UT_WORLDSIZE_HALF_X_F; + v2[1] = col->data.top_left * 10.0f; /* BUG? Shouldn't this be bot_left (top = +Z, bot = -Z) of the triangle */ + v2[2] = -mFI_UT_WORLDSIZE_HALF_Z_F; + break; + } + + case mCoBG_AREA_W: + { + v0[1] = col->data.center * 10.0f; + v1[0] = -mFI_UT_WORLDSIZE_HALF_X_F; + v1[1] = col->data.top_left * 10.0f; + v1[2] = -mFI_UT_WORLDSIZE_HALF_Z_F; + v2[0] = -mFI_UT_WORLDSIZE_HALF_X_F; + v2[1] = col->data.bot_left * 10.0f; + v2[2] = mFI_UT_WORLDSIZE_HALF_Z_F; + break; + } + + case mCoBG_AREA_S: + { + v0[1] = col->data.center * 10.0f; + v1[0] = -mFI_UT_WORLDSIZE_HALF_X_F; + v1[1] = col->data.bot_left * 10.0f; /* BUG? Shouldn't this be top_left (top = +Z, bot = -Z) of the triangle */ + v1[2] = mFI_UT_WORLDSIZE_HALF_Z_F; + v2[0] = mFI_UT_WORLDSIZE_HALF_X_F; + v2[1] = col->data.bot_right * 10.0f; + v2[2] = mFI_UT_WORLDSIZE_HALF_Z_F; + break; + } + + case mCoBG_AREA_E: + { + v0[1] = col->data.center * 10.0f; + v1[0] = mFI_UT_WORLDSIZE_HALF_X_F; + v1[1] = col->data.bot_right * 10.0f; + v1[2] = mFI_UT_WORLDSIZE_HALF_Z_F; + v2[0] = mFI_UT_WORLDSIZE_HALF_X_F; + v2[1] = col->data.top_right * 10.0f; + v2[2] = -mFI_UT_WORLDSIZE_HALF_Z_F; + break; + } + } +} + +static void mCoBG_GetNormTriangle(xyz_t* norm, s_xyz* ground_angle, mCoBG_Collision_u* col, s16 area) { + f32 v0[3] = { 0.0f, 0.0f, 0.0f }; + f32 v1[3] = { 0.0f, 0.0f, 0.0f }; + f32 v2[3] = { 0.0f, 0.0f, 0.0f }; + + mCoBG_GetArea3Point(area, v0, v1, v2, col); + mCoBG_GetNorm_By3Point(norm, v0, v1, v2); + mCoBG_GetGroundAngleFromVtx3(ground_angle, v0, v1, v2, area); +} + +static mCoBG_ActorInf_c l_ActorInf; + +static void mCoBG_AdjustActorY(xyz_t* rev_pos, ACTOR* actor, f32 ground_y, f32 water_y, f32 ground_dist, mCoBG_CheckResult_c* check_res, mCoBG_ActorInf_c* actor_info, int check_water) { + actor->bg_collision_check.ground_y = ground_y; + + if (check_water) { + f32 actor_y = actor->world.position.y; + f32 actor_foot_y = actor_y + ground_dist; + f32 water_ground_y = (water_y - (mFI_UNIT_BASE_SIZE_F / 2.0f)); + + if (water_ground_y >= actor_foot_y) { + rev_pos->y = (water_ground_y - ground_dist) - actor_y; + check_res->is_in_water = TRUE; + check_res->on_ground = TRUE; + actor->position_speed.y = 0.0f; + } + else if (water_y >= actor_foot_y) { + check_res->is_in_water = TRUE; + } + } + else { + f32 actor_y = actor->world.position.y; + f32 actor_foot_y = actor_y + ground_dist; + + if (ground_y >= actor_foot_y) { + rev_pos->y = (ground_y - ground_dist) - actor_y; + check_res->on_ground = TRUE; + actor->position_speed.y = 0.0f; // stop actor from moving downward anymore + } + else if (actor_info->old_on_ground && actor_info->old_ground_y > actor_info->ground_y) { + f32 dist_to_ground = ABS(ground_y - actor_foot_y); + f32 xz_vel = sqrtf(SQ(actor_info->speed_xz0[0]) + SQ(actor_info->speed_xz0[1])); + + if (dist_to_ground <= xz_vel) { + rev_pos->y = (ground_y - ground_dist) - actor->world.position.y; + check_res->on_ground = TRUE; + actor->position_speed.y = 0.0f; + } + } + } +} + +static f32 mCoBG_GroundPolygonInfo2BgHeight(xyz_t* norm, mCoBG_UnitInfo_c* unit_info) { + f32 dot = -(norm->y * (unit_info->collision->data.center * 10.0f)) + (norm->x * unit_info->unit_pos[0] + norm->z * unit_info->unit_pos[1]); + return dot / -norm->y; // dot product scaled by y normal +} + +static void mCoBG_GetSpeedByWpos(f32* speed, ACTOR* actor) { + speed[0] = actor->world.position.x - actor->last_world_position.x; + speed[1] = actor->world.position.z - actor->last_world_position.z; +} + +static void mCoBG_CarryOutReverse(ACTOR* actor, xyz_t rev_pos, s16 type) { + if (type == 0) { + actor->world.position.x += rev_pos.x; + actor->world.position.y += rev_pos.y; + actor->world.position.z += rev_pos.z; + } + + if (actor->bg_collision_check.result.unit_attribute >= mCoBG_ATTRIBUTE_WATER && actor->bg_collision_check.result.unit_attribute <= mCoBG_ATTRIBUTE_RIVER_NE) { + xyz_t pos = actor->world.position; + + f32 water_height = mCoBG_GetWaterHeight_File(pos, __FILE__, 1303); + if ((pos.y + l_ActorInf.ground_dist) <= water_height) { + actor->bg_collision_check.result.is_in_water = TRUE; + } + } +} + +static void mCoBG_InitRevpos(xyz_t* rev_pos) { + rev_pos->x = 0.0f; + rev_pos->y = 0.0f; + rev_pos->z = 0.0f; +} + +static void mCoBG_MakeSizeUnitInfo(mCoBG_UnitInfo_c *unit_info, int ut_x, int ut_z, s16 size) { + int x; + int z; + int start_x; + int start_z; + int end_x; + int end_z; + + start_z = ut_z - (size >> 1); + start_x = ut_x - (size >> 1); + end_z = start_z + size; + end_x = start_x + size; + + for (z = start_z; z < end_z; z++) { + for (x = start_x; x < end_x; x++) { + mCoBG_Unit2UnitInfo_OutOfUnitPos(unit_info, x, z); + unit_info++; + } + } +} + + +static void mCoBG_MakeTab2MoveTail(f32* dst_xz, f32* src_xz) { + f32 x_bias = ABS(src_xz[0]) / (ABS(src_xz[0]) + ABS(src_xz[1])); + f32 z_bias = 1.0f - x_bias; + + if (src_xz[0] > 0.0f) { + dst_xz[0] -= x_bias * 0.2f; + } + else if (src_xz[0] < 0.0f) { + dst_xz[0] += x_bias * 0.2f; + } + + if (src_xz[1] > 0.0f) { + dst_xz[1] -= z_bias * 0.2f; + } + else if (src_xz[1] < 0.0f) { + dst_xz[1] += z_bias * 0.2f; + } +} + +static u32 mCoBG_SearchAttribute(xyz_t wpos, int direct, s8* cant_dig) { + xyz_t next_ut; + + wpos.y = 0.0f; + mCoBG_PlussDirectOffset(&next_ut, wpos, direct); + return mCoBG_Wpos2Attribute(next_ut, cant_dig); +} + +static void mCoBG_RegistCollisionWallInfo(mCoBG_ActorInf_c* actor_inf, mCoBG_WallInfo_c* wall_info, mCoBG_WallHeight_c* wall_height, s16 angle_y, s16 atr) { + int i; + int count; + + if (wall_height != NULL) { + actor_inf->wall_height = *wall_height; + } + + count = 0; + for (i = 0; i < mCoBG_WALL_COL_NUM; i++) { + if (angle_y == wall_info[i].angleY) { + count++; + } + } + + if (count == 0) { + for (i = 0; i < mCoBG_WALL_COL_NUM; i++) { + if (wall_info[i].angleY == 0xB6) { + wall_info[i].angleY = angle_y; + wall_info[i].type = atr; + break; + } + } + } +} + +#include "../src/AUS/game/m_collision_bg_wall.c_inc" +#include "../src/AUS/game/m_collision_bg_move.c_inc" +#include "../src/AUS/game/m_collision_bg_column.c_inc" + +static int mCoBG_JudgeWallFromVector(f32* speed, f32* normal) { + f32 y = mCoBG_Get2VectorAngleF(speed, normal, mCoBG_UNIT_DEGREE); + + if (ABS(y) > 89.5f) { + return TRUE; + } + + return FALSE; +} + +static int mCoBG_RoughCheckWallHeight(f32 bot_y, mCoBG_WallBounds_c* bounds) { + f32 y = bot_y + 3.0f; + + if (y <= bounds->start_top || y <= bounds->end_top) { + return TRUE; + } + + return FALSE; +} + +static void mCoBG_GetWallHeight(mCoBG_WallHeight_c* wall_height, mCoBG_unit_vec_info_c* unit_vec, f32* point) { + mCoBG_WallBounds_c* bounds = &unit_vec->wall_bounds; + f32* start = unit_vec->start; + f32* end = unit_vec->end; + f32 cross[2]; + + if (mCoBG_GetCrossLineAndPerpendicular(cross, unit_vec->start, unit_vec->end, point)) { + xyz_t vec; + f32 p; + f32 t; + + vec.x = end[0] - start[0]; + vec.z = end[1] - start[1]; + + if (F32_IS_ZERO(vec.x)) { + p = (cross[1] - start[1]) / vec.z; + } else { + p = (cross[0] - start[0]) / vec.x; + } + + // not sure what's up the need for 't' on z but not on x + vec.x = bounds->end_top - bounds->start_top; + vec.x *= p; + wall_height->top = bounds->start_top + vec.x; + + t = bounds->start_btm; + vec.z = bounds->end_btm - t; + vec.z *= p; + wall_height->bot = t + vec.z; + } +} + +static int mCoBG_CheckHeightExactly(mCoBG_WallHeight_c* wall_height, f32 pos_y, mCoBG_unit_vec_info_c* unit_vec, f32* point) { + mCoBG_WallBounds_c* bounds = &unit_vec->wall_bounds; + f32* start = unit_vec->start; + f32* end = unit_vec->end; + f32 div; + + if (unit_vec->regist_p != NULL) { + wall_height->top = bounds->end_top; + wall_height->bot = bounds->end_btm; + + if (pos_y + 3.0f <= wall_height->top) { + return TRUE; + } + } else { + switch(unit_vec->wall_name) { + case mCoBG_WALL_LEFT: + case mCoBG_WALL_RIGHT: + div = end[1] - start[1]; + if (!F32_IS_ZERO(div)) { + wall_height->top = bounds->start_top + (point[1] - start[1]) * ((bounds->end_top - bounds->start_top) / (end[1] - start[1])); + wall_height->bot = bounds->start_btm + (point[1] - start[1]) * ((bounds->end_btm - bounds->start_btm) / (end[1] - start[1])); + + if (pos_y + 3.0f <= wall_height->top) { + return TRUE; + } + } + break; + case mCoBG_WALL_UP: + case mCoBG_WALL_DOWN: + div = end[0] - start[0]; + if (!F32_IS_ZERO(div)) { + wall_height->top = bounds->start_top + (point[0] - start[0]) * ((bounds->end_top - bounds->start_top) / (end[0] - start[0])); + wall_height->bot = bounds->start_btm + (point[0] - start[0]) * ((bounds->end_btm - bounds->start_btm) / (end[0] - start[0])); + + if (pos_y + 3.0f <= wall_height->top) { + return TRUE; + } + } + break; + case mCoBG_WALL_SLATE_UP: + case mCoBG_WALL_SLATE_DOWN: + mCoBG_GetWallHeight(wall_height, unit_vec, point); + if (pos_y + 3.0f <= wall_height->top) { + return TRUE; + } + break; + } + } + + return FALSE; +} + +static int mCoBG_SearchWallFront(f32* point, mCoBG_unit_vec_info_c* unit_vec) { + return mCoBG_GetPointInfoFrontLine(unit_vec->start, point, unit_vec->normal); +} + +static int mCoBG_Check45Angle(s16 angle0, s16 angle1) { + if (ABS(angle1 - angle0) <= (u16)DEG2SHORT_ANGLE(45.0f) || ABS(angle1 - angle0) >= (u16)(DEG2SHORT_ANGLE(-45.0f) - 1)) { + return TRUE; + } + + return FALSE; +} + +static void mCoBG_RegistWallCount(mCoBG_CheckResult_c* col_res, mCoBG_WallInfo_c* info, s16 angle) { + int i; + u32 count; + + count = 0; + for (i = 0; i < mCoBG_WALL_COL_NUM; i++) { + if (info[i].angleY != 0xB6) { + count++; + } + } + + col_res->hit_wall_count = count; + if (count == 2) { + f32 r0 = SHORT2RAD_ANGLE2(info[0].angleY); + f32 x0 = sinf_table(r0); + f32 z0 = cosf_table(r0); + f32 r1 = SHORT2RAD_ANGLE2(info[1].angleY); + f32 x1 = sinf_table(r1); + f32 z1 = cosf_table(r1); + s16 avg_angle = atans_table((z0 + z1) * 0.5f, (x0 + x1) * 0.5f); + + if (mCoBG_Check45Angle((DEG2SHORT_ANGLE2(180.0f)-1) + avg_angle, angle)) { + col_res->unk_flag4 = TRUE; + } + } +} + +static void mCoBG_MakeHitWallFalg(mCoBG_CheckResult_c* col_res, mCoBG_WallInfo_c* wall_info) { + int i; + + for (i = 0; i < mCoBG_WALL_COL_NUM; i++) { + switch (wall_info[i].type) { + case mCoBG_WALL_TYPE0: + col_res->hit_wall |= mCoBG_HIT_WALL; + break; + case mCoBG_WALL_TYPE1: + col_res->hit_attribute_wall |= mCoBG_HIT_WALL; + break; + } + } +} + +static void mCoBG_SearchColOwnPart(s16 actor_angleY, s16 wall_angleY, mCoBG_Check_c* check_p, s16 wall_type) { + if (mCoBG_Check45Angle((wall_angleY + DEG2SHORT_ANGLE2(180.0f)-1), actor_angleY)) { + if (wall_type == mCoBG_WALL_TYPE0) { + check_p->result.hit_wall |= mCoBG_HIT_WALL_FRONT; + check_p->in_front_wall_angle_y = wall_angleY; + check_p->result.unk_flag4 = TRUE; + } else { + check_p->result.hit_attribute_wall |= mCoBG_HIT_WALL_FRONT; + check_p->in_front_wall_angle_y = wall_angleY; + check_p->result.unk_flag4 = TRUE; + } + } else if (mCoBG_Check45Angle((wall_angleY + DEG2SHORT_ANGLE2(-90.0f)), actor_angleY)) { + if (wall_type == mCoBG_WALL_TYPE0) { + check_p->result.hit_wall |= mCoBG_HIT_WALL_RIGHT; + } else { + check_p->result.hit_attribute_wall |= mCoBG_HIT_WALL_RIGHT; + } + } else if (mCoBG_Check45Angle((wall_angleY + DEG2SHORT_ANGLE2(90.0f)), actor_angleY)) { + if (wall_type == mCoBG_WALL_TYPE0) { + check_p->result.hit_wall |= mCoBG_HIT_WALL_LEFT; + } else { + check_p->result.hit_attribute_wall |= mCoBG_HIT_WALL_LEFT; + } + } else if (mCoBG_Check45Angle(wall_angleY, actor_angleY)) { + if (wall_type == mCoBG_WALL_TYPE0) { + check_p->result.hit_wall |= mCoBG_HIT_WALL_BACK; + } else { + check_p->result.hit_attribute_wall |= mCoBG_HIT_WALL_BACK; + } + } +} + +static void mCoBG_MakePartDirectHitWallFlag(ACTOR* actorx) { + mCoBG_Check_c* check_p = &actorx->bg_collision_check; + int count = check_p->result.hit_wall_count; + s16 wall_angleY; + s16 wall_type; + s16 actor_angleY = actorx->shape_info.rotation.y; + int i; + + if (check_p->result.hit_wall != mCoBG_DIDNT_HIT_WALL || check_p->result.hit_attribute_wall != mCoBG_DIDNT_HIT_WALL) { + for (i = 0; i < count; i++) { + wall_angleY = check_p->wall_info[i].angleY; + wall_type = check_p->wall_info[i].type; + mCoBG_SearchColOwnPart(actor_angleY, wall_angleY, check_p, wall_type); + } + } + + if (count == 2) { + u16 dangle = check_p->wall_info[0].angleY - check_p->wall_info[1].angleY; + + if (dangle > (DEG2SHORT_ANGLE2(180.0f)-3) && dangle < (DEG2SHORT_ANGLE2(180.0f)+3)) { + check_p->result.unk_flag2 = TRUE; + } + + if (check_p->wall_info[0].type == mCoBG_WALL_TYPE0 && check_p->wall_info[1].type == mCoBG_WALL_TYPE0 && dangle < DEG2SHORT_ANGLE2(67.5f)) { + check_p->result.unk_flag2 = TRUE; + } + } +} + +enum { + mCoBG_WALL_KIND_NORMAL, + mCoBG_WALL_KIND_ATTRIBUTE, + mCoBG_WALL_KIND_MOVE, + + mCoBG_WALL_KIND_NUM +}; + +static s16 mCoBG_GetWallKind(mCoBG_unit_vec_info_c* unit_vec) { + if (unit_vec->regist_p != NULL) { + return mCoBG_WALL_KIND_MOVE; + } + + if (unit_vec->atr_wall) { + return mCoBG_WALL_KIND_ATTRIBUTE; + } + + return mCoBG_WALL_KIND_NORMAL; +} + +static void mCoBG_Cross2Reverse_NormalWall(f32* reverse, mCoBG_unit_vec_info_c* unit_vec, f32* actor_start, f32* actor_end, mCoBG_ActorInf_c* actor_inf, ACTOR* actorx) { + + if (mCoBG_RoughCheckWallHeight(actor_inf->old_ground_y - 5.0f, &unit_vec->wall_bounds)) { + mCoBG_WallHeight_c height; + + if (mCoBG_CheckHeightExactly(&height, actor_inf->old_ground_y - 5.0f, unit_vec, actor_start)) { + if (mCoBG_GetCrossJudge_2Vector(actor_start, actor_end, unit_vec->start, unit_vec->end)) { + f32 dist; + f32 rev_dist; + + mCoBG_GetDistPointAndLine2D_Norm(&dist, unit_vec->start, unit_vec->end, unit_vec->normal, actor_end); + rev_dist = actor_inf->range + dist + 0.00001f; + + reverse[0] = unit_vec->normal[0] * rev_dist; + reverse[1] = unit_vec->normal[1] * rev_dist; + mCoBG_RegistCollisionWallInfo(actor_inf, actor_inf->wall_info, &height, unit_vec->normal_angle, unit_vec->atr_wall); + if (unit_vec->regist_p != NULL) { + mCoBG_SetMoveBgContactSide(unit_vec->regist_p, actorx, unit_vec->normal_angle); + } + } + } + } +} + +static void mCoBG_Cross2Reverse_AttributeWall(f32* reverse, mCoBG_unit_vec_info_c* unit_vec, f32* actor_start, f32* actor_end, mCoBG_ActorInf_c* actor_inf, ACTOR* actorx) { + if (mCoBG_GetCrossJudge_2Vector(actor_start, actor_end, unit_vec->start, unit_vec->end)) { + f32 cross[2]; + + mCoBG_GetCross2Line(cross, actor_start, actor_end, unit_vec->start, unit_vec->end); + reverse[0] = cross[0] - actor_end[0]; + reverse[1] = cross[1] - actor_end[1]; + mCoBG_RegistCollisionWallInfo(actor_inf, actor_inf->wall_info, NULL, unit_vec->normal_angle, unit_vec->atr_wall); + } +} + +typedef void (*mCoBG_CROSS_REV_PROC)(f32* reverse, mCoBG_unit_vec_info_c* unit_vec, f32* actor_start, f32* actor_end, mCoBG_ActorInf_c* actor_inf, ACTOR* actorx); + +static void mCoBG_Cross2Reverse(f32* reverse, mCoBG_unit_vec_info_c* unit_vec, int unit, f32* actor_start, f32* actor_end, mCoBG_ActorInf_c* actor_info, ACTOR* actorx) { + f32 speed[2]; + + speed[0] = actor_end[0] - actor_start[0]; + speed[1] = actor_end[1] - actor_start[1]; + + if (mCoBG_GetPointInfoFrontLine(unit_vec->start, actor_start, unit_vec->normal) && mCoBG_JudgeWallFromVector(speed, unit_vec->normal)) { + static mCoBG_CROSS_REV_PROC cross_rev_proc[] = { &mCoBG_Cross2Reverse_NormalWall, &mCoBG_Cross2Reverse_AttributeWall, &mCoBG_Cross2Reverse_NormalWall }; + s16 kind = mCoBG_GetWallKind(unit_vec); + + (*cross_rev_proc[kind])(reverse, unit_vec, actor_start, actor_end, actor_info, actorx); + } +} + +static int mCoBG_Distance2Reverse_NormalWall(f32* reverse, mCoBG_unit_vec_info_c* unit_vec, f32* actor_start, f32* actor_end, mCoBG_ActorInf_c* actor_info, ACTOR* actorx) { + f32 dist; + + if (mCoBG_GetDistPointAndLine2D_Norm(&dist, unit_vec->start, unit_vec->end, unit_vec->normal, actor_end)) { + mCoBG_WallHeight_c height; + + if (dist < actor_info->range) { + + if (mCoBG_RoughCheckWallHeight(actor_info->old_ground_y - 5.0f, &unit_vec->wall_bounds) && mCoBG_CheckHeightExactly(&height, actor_info->old_ground_y - 5.0f, unit_vec, actor_end)) { + f32 rev_dist = (actor_info->range - dist) + 0.00001f; + + reverse[0] = unit_vec->normal[0] * rev_dist; + reverse[1] = unit_vec->normal[1] * rev_dist; + mCoBG_RegistCollisionWallInfo(actor_info, actor_info->wall_info, &height, unit_vec->normal_angle, unit_vec->atr_wall); + + if (unit_vec->regist_p != NULL) { + mCoBG_SetMoveBgContactSide(unit_vec->regist_p, actorx, unit_vec->normal_angle); + } + + return TRUE; + } + } else if (ABS(dist - actor_info->range) < 2.7f && mCoBG_RoughCheckWallHeight(actor_info->old_ground_y - 5.0f, &unit_vec->wall_bounds) && mCoBG_CheckHeightExactly(&height, actor_info->old_ground_y - 5.0f, unit_vec, actor_end)) { + mCoBG_RegistCollisionWallInfo(actor_info, actor_info->wall_info, &height, unit_vec->normal_angle, unit_vec->atr_wall); + + if (unit_vec->regist_p != NULL) { + mCoBG_SetMoveBgContactSide(unit_vec->regist_p, actorx, unit_vec->normal_angle); + } + + return TRUE; + } + } + + return FALSE; +} + +static void mCoBG_GetSpecialDistanceReverse(f32* reverse, f32* actor_end, mCoBG_unit_vec_info_c* unit_vec, f32* cross0, f32* cross1, f32* edge) { + if (!mCoBG_GetPointInfoFrontLine(unit_vec->start, cross0, unit_vec->normal)) { + reverse[0] = edge[0] - cross0[0]; + reverse[1] = edge[1] - cross0[1]; + } else if (!mCoBG_GetPointInfoFrontLine(unit_vec->start, cross1, unit_vec->normal)) { + reverse[0] = edge[0] - cross1[0]; + reverse[1] = edge[1] - cross1[1]; + } +} + +static int mCoBG_CheckDistSPCheck(mCoBG_unit_vec_info_c* unit_vec, f32* point) { + int count = l_VecInf.unit_count; + mCoBG_unit_vec_info_c* cur_unit_vec_p = l_VecInf.unit; + f32* start; + f32* end; + int i; + + for (i = 0; i < count; i++) { + if (cur_unit_vec_p != unit_vec) { + start = cur_unit_vec_p->start; + end = cur_unit_vec_p->end; + + if ((ABS(start[0] - point[0]) < 0.1f && ABS(start[1] - point[1]) < 0.1f) || + (ABS(end[0] - point[0]) < 0.1f && ABS(end[1] - point[1]) < 0.1f)) { + if ((u16)(unit_vec->normal_angle - cur_unit_vec_p->normal_angle) < (DEG2SHORT_ANGLE2(90.0f)-0x100)) { + return FALSE; + } + } + } + + cur_unit_vec_p++; + } + + return TRUE; +} + +static int mCoBG_Distance2Reverse_NormalWall_Special(f32* reverse, mCoBG_unit_vec_info_c* unit_vec, f32* actor_start, f32* actor_end, mCoBG_ActorInf_c* actor_info, ACTOR* actorx) { + if (mCoBG_GetPointInfoFrontLine(unit_vec->start, actor_end, unit_vec->normal) && mCoBG_GetPointInfoFrontLine(unit_vec->start, actor_start, unit_vec->normal)) { + f32 dist; + + mCoBG_GetDistPointAndLine2D_Norm(&dist, unit_vec->start, unit_vec->end, unit_vec->normal, actor_end); + if (dist < actor_info->range) { + f32 cross0[2]; + f32 cross1[2]; + + if (mCoBG_JudgePointInCircle(unit_vec->start, actor_end, actor_info->range)) { + if (!mCoBG_CheckDistSPCheck(unit_vec, actor_end)) { + return FALSE; + } + + if (mCoBG_GetCrossCircleAndLine2Dvector(cross0, cross1, unit_vec->start, unit_vec->normal, actor_end, actor_info->range)) { + mCoBG_WallHeight_c height; + + height.top = unit_vec->wall_bounds.start_top; + height.bot = unit_vec->wall_bounds.start_btm; + if ((actor_info->old_ground_y - 5.0f) + 3.0f <= height.top) { + mCoBG_GetSpecialDistanceReverse(reverse, actor_end, unit_vec, cross0, cross1, unit_vec->start); + mCoBG_RegistCollisionWallInfo(actor_info, actor_info->wall_info, &height, unit_vec->normal_angle, unit_vec->atr_wall); + if (unit_vec->regist_p != NULL) { + mCoBG_SetMoveBgContactSide(unit_vec->regist_p, actorx, unit_vec->normal_angle); + } + + return TRUE; + } + } + } else if (mCoBG_JudgePointInCircle(unit_vec->end, actor_end, actor_info->range)) { + if (!mCoBG_CheckDistSPCheck(unit_vec, actor_end)) { + return FALSE; + } + + if (mCoBG_GetCrossCircleAndLine2Dvector(cross0, cross1, unit_vec->end, unit_vec->normal, actor_end, actor_info->range)) { + mCoBG_WallHeight_c height; + + height.top = unit_vec->wall_bounds.end_top; + height.bot = unit_vec->wall_bounds.end_btm; + if ((actor_info->old_ground_y - 5.0f) + 3.0f <= height.top) { + mCoBG_GetSpecialDistanceReverse(reverse, actor_end, unit_vec, cross0, cross1, unit_vec->end); + mCoBG_RegistCollisionWallInfo(actor_info, actor_info->wall_info, &height, unit_vec->normal_angle, unit_vec->atr_wall); + if (unit_vec->regist_p != NULL) { + mCoBG_SetMoveBgContactSide(unit_vec->regist_p, actorx, unit_vec->normal_angle); + } + + return TRUE; + } + } + } + } + } + + return FALSE; +} + +static int mCoBG_Distance2Reverse_AttributeWall(f32* reverse, mCoBG_unit_vec_info_c* unit_vec, f32* actor_start, f32* actor_end, mCoBG_ActorInf_c* actor_info, ACTOR* actorx) { + f32 dist; + + if (mCoBG_GetDistPointAndLine2D_Norm(&dist, unit_vec->start, unit_vec->end, unit_vec->normal, actor_end)) { + if (dist < actor_info->range) { + f32 rev_dist = (actor_info->range - dist) + 0.00001f; + + reverse[0] = unit_vec->normal[0] * rev_dist; + reverse[1] = unit_vec->normal[1] * rev_dist; + mCoBG_RegistCollisionWallInfo(actor_info, actor_info->wall_info, NULL, unit_vec->normal_angle, unit_vec->atr_wall); + return TRUE; + } else if (ABS(dist - actor_info->range) < 2.7f) { + mCoBG_RegistCollisionWallInfo(actor_info, actor_info->wall_info, NULL, unit_vec->normal_angle, unit_vec->atr_wall); + return TRUE; + } + } + + return FALSE; +} + +static int mCoBG_Distance2Reverse_AttributeWall_Special(f32* reverse, mCoBG_unit_vec_info_c* unit_vec, f32* actor_start, f32* actor_end, mCoBG_ActorInf_c* actor_info, ACTOR* actorx) { + if (mCoBG_GetPointInfoFrontLine(unit_vec->start, actor_end, unit_vec->normal) && mCoBG_GetPointInfoFrontLine(unit_vec->start, actor_start, unit_vec->normal)) { + f32 dist; + + mCoBG_GetDistPointAndLine2D_Norm(&dist, unit_vec->start, unit_vec->end, unit_vec->normal, actor_end); + if (dist < actor_info->range) { + f32 cross0[2]; + f32 cross1[2]; + + if (mCoBG_JudgePointInCircle(unit_vec->start, actor_end, actor_info->range)) { + if (!mCoBG_CheckDistSPCheck(unit_vec, actor_end)) { + return FALSE; + } + + if (mCoBG_GetCrossCircleAndLine2Dvector(cross0, cross1, unit_vec->start, unit_vec->normal, actor_end, actor_info->range)) { + mCoBG_GetSpecialDistanceReverse(reverse, actor_end, unit_vec, cross0, cross1, unit_vec->start); + mCoBG_RegistCollisionWallInfo(actor_info, actor_info->wall_info, NULL, unit_vec->normal_angle, unit_vec->atr_wall); + return TRUE; + } + } else if (mCoBG_JudgePointInCircle(unit_vec->end, actor_end, actor_info->range)) { + if (!mCoBG_CheckDistSPCheck(unit_vec, actor_end)) { + return FALSE; + } + + if (mCoBG_GetCrossCircleAndLine2Dvector(cross0, cross1, unit_vec->end, unit_vec->normal, actor_end, actor_info->range)) { + mCoBG_GetSpecialDistanceReverse(reverse, actor_end, unit_vec, cross0, cross1, unit_vec->end); + mCoBG_RegistCollisionWallInfo(actor_info, actor_info->wall_info, NULL, unit_vec->normal_angle, unit_vec->atr_wall); + return TRUE; + } + } + } + } + + return FALSE; +} + +typedef int (*mCoBG_DIST_REV_PROC)(f32* reverse, mCoBG_unit_vec_info_c* unit_vec, f32* actor_start, f32* actor_end, mCoBG_ActorInf_c* actor_info, ACTOR* actorx); +typedef int (*mCoBG_DIST_REV_PLAYER_PROC)(f32* reverse, mCoBG_unit_vec_info_c* unit_vec, f32* actor_start, f32* actor_end, mCoBG_ActorInf_c* actor_info, ACTOR* actorx); + +static void mCoBG_Distance2Reverse(f32* reverse, mCoBG_unit_vec_info_c* unit_vec, int unit, f32* actor_start, f32* actor_end, mCoBG_ActorInf_c* actor_info, ACTOR* actorx) { + static mCoBG_DIST_REV_PROC dist_rev_proc[] = { &mCoBG_Distance2Reverse_NormalWall, &mCoBG_Distance2Reverse_AttributeWall, &mCoBG_Distance2Reverse_NormalWall }; + static mCoBG_DIST_REV_PLAYER_PROC dist_rev_proc_player[] = { &mCoBG_Distance2Reverse_NormalWall_Special, &mCoBG_Distance2Reverse_AttributeWall_Special, &mCoBG_Distance2Reverse_NormalWall_Special }; + s16 kind; + + if (mCoBG_GetPointInfoFrontLine(unit_vec->start, actor_start, unit_vec->normal)) { + switch (actor_info->check_type) { + case mCoBG_CHECK_TYPE_NORMAL: + if (mCoBG_RangeCheckLinePoint(unit_vec->start, unit_vec->end, actor_start)) { + kind = mCoBG_GetWallKind(unit_vec); + (*dist_rev_proc[kind])(reverse, unit_vec, actor_start, actor_end, actor_info, actorx); + } + break; + default: + kind = mCoBG_GetWallKind(unit_vec); + (*dist_rev_proc_player[kind])(reverse, unit_vec, actor_start, actor_end, actor_info, actorx); + break; + } + } +} + +static f32 pre_work[65]; +static f32 bk_work[65]; + +static void mCoBG_MergeSortFloat(f32* data, int first, int last) { + if (first < last) { + int middle = (first + last) >> 1; + int pre_count = 0; + int bk_count = 0; + int set = first; + int pre; + int bk; + + mCoBG_MergeSortFloat(data, first, middle); + mCoBG_MergeSortFloat(data, middle + 1, last); + + // load in the obttom half of the data + for (pre = first; pre <= middle; pre++) { + pre_work[pre_count++] = data[pre]; + } + + // load in the top half of the data + for (bk = middle + 1; bk <= last; bk++) { + bk_work[bk_count++] = data[bk]; + } + + // compare each item that was pre sorted + pre = 0; + bk = 0; + while (pre < pre_count && bk < bk_count) { + if (pre_work[pre] <= bk_work[bk]) { + data[set++] = pre_work[pre++]; + } else { + data[set++] = bk_work[bk++]; + } + } + + while (pre < pre_count) { + data[set++] = pre_work[pre++]; + } + + while (bk < bk_count) { + data[set++] = bk_work[bk++]; + } + } +} + +static void mCoBG_GetWallPriority(u8* prio_tbl, mCoBG_vec_info_c* vec_info, f32* actor_start) { + static f32 dist_table[mCoBG_UNIT_VEC_INFO_MAX]; + static f32 merge_dist_table[mCoBG_UNIT_VEC_INFO_MAX]; + u64 flag = 0; + mCoBG_unit_vec_info_c* unit_vec = vec_info->unit; + int count = vec_info->unit_count; + int unit = 0; + int i; + f32 center[2]; + f32 dist[2]; + f32* start; + f32* end; + + for (unit = 0; unit < count; unit++) { + start = unit_vec->start; + end = unit_vec->end; + + center[0] = (start[0] + end[0]) * 0.5f; + center[1] = (start[1] + end[1]) * 0.5f; + dist[0] = center[0] - actor_start[0]; + dist[1] = center[1] - actor_start[1]; + dist_table[unit] = SQ(dist[0]) + SQ(dist[1]); + merge_dist_table[unit] = dist_table[unit]; + unit_vec++; + } + + mCoBG_MergeSortFloat(merge_dist_table, 0, count - 1); + + for (unit = 0; unit < count; unit++) { + prio_tbl[unit] = 0; + } + + for (i = 0; i < count; i++) { + prio_tbl[i] = 0; + for (unit = 0; unit < count; unit++) { + if (dist_table[unit] == merge_dist_table[i] && ((flag >> (u64)unit) & 1) == 0) { + flag |= 1 << (u64)unit; + prio_tbl[i] = unit; + break; + } + } + } +} + +static void mCoBG_GetWallReverse(mCoBG_ActorInf_c* actor_info, const xyz_t* pos, mCoBG_vec_info_c* vec_info, ACTOR* actorx) { + mCoBG_unit_vec_info_c* unit_vec; + f32 actor_start[2]; + f32 actor_end[2]; + f32 speed[2]; + f32 end[2]; + int count = vec_info->unit_count; + int unit; + + actor_start[0] = actorx->last_world_position.x; + actor_start[1] = actorx->last_world_position.z; + actor_end[0] = pos->x; + actor_end[1] = pos->z; + speed[0] = actor_end[0] - actor_start[0]; + speed[1] = actor_end[1] - actor_start[1]; + mCoBG_MakeTab2MoveTail(actor_start, speed); + end[0] = actor_end[0]; + end[1] = actor_end[1]; + + if (actor_info->check_type == mCoBG_CHECK_TYPE_PLAYER) { + u8 prio_tbl[mCoBG_UNIT_VEC_INFO_MAX]; + int i; + int j; + f32 rev[2]; + + actor_info->check_type = mCoBG_CHECK_TYPE_NORMAL; + unit_vec = vec_info->unit; + for (i = 0; i < count; i++) { + rev[0] = 0.0f; + rev[1] = 0.0f; + mCoBG_Distance2Reverse(rev, unit_vec, i, actor_start, actor_end, actor_info, actorx); + actor_end[0] += rev[0]; + actor_end[1] += rev[1]; + unit_vec++; + } + + mCoBG_GetWallPriority(prio_tbl, vec_info, actor_start); + actor_info->check_type = mCoBG_CHECK_TYPE_PLAYER; + unit_vec = vec_info->unit; + for (j = 0; j < count; j++) { + rev[0] = 0.0f; + rev[1] = 0.0f; + mCoBG_Distance2Reverse(rev, &unit_vec[prio_tbl[j]], prio_tbl[j], actor_start, actor_end, actor_info, actorx); + actor_end[0] += rev[0]; + actor_end[1] += rev[1]; + } + + + unit_vec = vec_info->unit; + for (i = 0; i < count; i++) { + rev[0] = 0.0f; + rev[1] = 0.0f; + mCoBG_Cross2Reverse(rev, unit_vec, i, actor_start, actor_end, actor_info, actorx); + actor_end[0] += rev[0]; + actor_end[1] += rev[1]; + unit_vec++; + } + } else { + f32 rev[2]; + f32 spd = sqrtf(SQ(speed[0]) + SQ(speed[1])); + + if (spd > actor_info->range * 0.5f) { + unit_vec = vec_info->unit; + for (unit = 0; unit < count; unit++) { + rev[0] = 0.0f; + rev[1] = 0.0f; + mCoBG_Cross2Reverse(rev, unit_vec, unit, actor_start, actor_end, actor_info, actorx); + actor_end[0] += rev[0]; + actor_end[1] += rev[1]; + unit_vec++; + } + } + + unit_vec = vec_info->unit; + for (unit = 0; unit < count; unit++) { + if (unit_vec->regist_p == NULL) { + rev[0] = 0.0f; + rev[1] = 0.0f; + mCoBG_Distance2Reverse(rev, unit_vec, unit, actor_start, actor_end, actor_info, actorx); + actor_end[0] += rev[0]; + actor_end[1] += rev[1]; + } + unit_vec++; + } + + unit_vec = vec_info->unit; + for (unit = 0; unit < count; unit++) { + if (unit_vec->regist_p != NULL) { + rev[0] = 0.0f; + rev[1] = 0.0f; + mCoBG_Distance2Reverse(rev, unit_vec, unit, actor_start, actor_end, actor_info, actorx); + actor_end[0] += rev[0]; + actor_end[1] += rev[1]; + } + unit_vec++; + } + } + + actor_info->rev_pos.x = actor_end[0] - end[0]; + actor_info->rev_pos.z = actor_end[1] - end[1]; +} + +static mCoBG_UnitInfo_c l_crtutInf[50]; + +static void mCoBG_WallCheck(ACTOR* actorx, mCoBG_ActorInf_c* actor_info, s16 atr_wall, mCoBG_Check_c* check_p) { + int ux; + int uz; + + bzero(l_crtutInf, sizeof(l_crtutInf)); + bzero(&l_VecInf, sizeof(l_VecInf)); + mCoBG_GetSpeedByWpos(l_ActorInf.speed_xz0, actorx); + mFI_Wpos2UtNum(&ux, &uz, actor_info->center_pos); + mCoBG_MakeSizeUnitInfo(l_crtutInf, ux, uz, actor_info->ut_count); + if (actorx->id == mAc_PROFILE_PLAYER && (ABS(l_ActorInf.speed_xz0[0]) > 100.0f || ABS(l_ActorInf.speed_xz0[1]) > 100.0f)) { + return; + } + + mCoBG_MakeUnitVector(&l_VecInf, l_crtutInf, actor_info->ut_count, actor_info->check_type, atr_wall, actor_info->old_on_ground, actor_info->old_in_water); + if (actorx->id != mAc_PROFILE_GYOEI) { + mCoBG_MakeMoveBgVector(&l_VecInf, &l_mBgMgr, &actorx->world.position, actor_info->check_type); + } + + mCoBG_MakeColumnCollisionData(l_VecInf.column, &l_VecInf.col_count, l_crtutInf, actor_info->ut_count, actor_info->old_on_ground, NULL, l_ActorInf._68, l_ActorInf._6C); + mCoBG_MakeCircleDefenceWall(actor_info, atr_wall); + + { + xyz_t pos; + xyz_t rev0 = { 0.0f, 0.0f, 0.0f }; + xyz_t rev1 = { 0.0f, 0.0f, 0.0f }; + + pos.x = actorx->world.position.x + actor_info->rev_pos.x; + pos.y = actorx->world.position.y + actor_info->rev_pos.y; + pos.z = actorx->world.position.z + actor_info->rev_pos.z; + mCoBG_ColumnWallCheck(&rev0, actor_info, &pos, l_VecInf.column, l_VecInf.col_count, atr_wall); + actor_info->rev_pos.x += rev0.x; + actor_info->rev_pos.y += rev0.y; + actor_info->rev_pos.z += rev0.z; + + pos.x = actorx->world.position.x + actor_info->rev_pos.x; + pos.y = actorx->world.position.y + actor_info->rev_pos.y; + pos.z = actorx->world.position.z + actor_info->rev_pos.z; + mCoBG_ColumnWallCheck(&rev1, actor_info, &pos, mCoBG_decal_circle, mCoBG_regist_decal_circle_count, atr_wall); + actor_info->rev_pos.x += rev1.x; + actor_info->rev_pos.y += rev1.y; + actor_info->rev_pos.z += rev1.z; + + actorx->world.position.x += actor_info->rev_pos.x; + actorx->world.position.y += actor_info->rev_pos.y; + actorx->world.position.z += actor_info->rev_pos.z; + mCoBG_GetWallReverse(actor_info, &actorx->world.position, &l_VecInf, actorx); + mCoBG_MakeHitWallFalg(&actorx->bg_collision_check.result, actor_info->wall_info); + + actorx->bg_collision_check.wall_bottom_y = actor_info->wall_height.bot; + actorx->bg_collision_check.wall_top_y = actor_info->wall_height.top; + actorx->bg_collision_check.wall_info[0].angleY = actor_info->wall_info[0].angleY; + actorx->bg_collision_check.wall_info[1].angleY = actor_info->wall_info[1].angleY; + actorx->bg_collision_check.wall_info[0].type = actor_info->wall_info[0].type; + actorx->bg_collision_check.wall_info[1].type = actor_info->wall_info[1].type; + + mCoBG_RegistWallCount(&actorx->bg_collision_check.result, actor_info->wall_info, actorx->shape_info.rotation.y); + mCoBG_MakePartDirectHitWallFlag(actorx); + } +} + +static f32 mCoBG_GetAreaYSlatingUnit(mCoBG_UnitInfo_c* unit_info, s16 type, s16 area) { + switch (type) { + case mCoBG_WALL_SLATE_UP: + switch (area) { + case mCoBG_AREA_S: + case mCoBG_AREA_E: + return unit_info->collision->data.bot_right * 10.0f; + case mCoBG_AREA_N: + case mCoBG_AREA_W: + return unit_info->collision->data.top_left * 10.0f; + default: + break; + } + // fallthrough + case mCoBG_WALL_SLATE_DOWN: + switch (area) { + case mCoBG_AREA_N: + case mCoBG_AREA_E: + return unit_info->collision->data.top_right * 10.0f; + case mCoBG_AREA_W: + case mCoBG_AREA_S: + return unit_info->collision->data.bot_left * 10.0f; + default: + break; + } + break; + } + + return 0.0f; +} + +static void mCoBG_GetCurrentCenterPosition(xyz_t* current_center_pos, ACTOR* actorx) { + *current_center_pos = actorx->world.position; +} + +static void mCoBG_GetOldCenterPosition(xyz_t* old_center_pos, ACTOR* actorx) { + *old_center_pos = actorx->last_world_position; +} + +static f32 mCoBG_GetBGHeight_Normal_NormalGround(s_xyz* angle, mCoBG_UnitInfo_c* unit_info) { + xyz_t normal; + s16 area; + f32 ground_normal_y; + + if ( + unit_info->collision->data.center != unit_info->collision->data.top_left || + unit_info->collision->data.center != unit_info->collision->data.bot_left || + unit_info->collision->data.center != unit_info->collision->data.bot_right || + unit_info->collision->data.center != unit_info->collision->data.top_right + ) { + mCoBG_GetUnitArea(unit_info, &area); + mCoBG_GetNormTriangle(&normal, angle, unit_info->collision, area); + ground_normal_y = mCoBG_GroundPolygonInfo2BgHeight(&normal, unit_info) + mFI_UtNum2BaseHeight(unit_info->ut_x, unit_info->ut_z); + } else { + ground_normal_y = unit_info->collision->data.center * 10.0f + mFI_UtNum2BaseHeight(unit_info->ut_x, unit_info->ut_z); + if (angle != NULL) { + angle->x = 0; + angle->y = 0; + angle->z = 0; + } + } + + return ground_normal_y; +} + +static f32 mCoBG_GetBGHeight_Normal_SlateGround(s_xyz* angle, mCoBG_UnitInfo_c* unit_info) { + s16 area; + f32 ground_normal_y; + + if (unit_info->collision->data.top_left != unit_info->collision->data.bot_right) { + mCoBG_GetUnitArea(unit_info, &area); + ground_normal_y = mCoBG_GetAreaYSlatingUnit(unit_info, mCoBG_WALL_SLATE_UP, area) + mFI_UtNum2BaseHeight(unit_info->ut_x, unit_info->ut_z); + } else { + mCoBG_GetUnitArea(unit_info, &area); + ground_normal_y = mCoBG_GetAreaYSlatingUnit(unit_info, mCoBG_WALL_SLATE_DOWN, area) + mFI_UtNum2BaseHeight(unit_info->ut_x, unit_info->ut_z); + } + + if (angle != NULL) { + angle->x = 0; + angle->y = 0; + angle->z = 0; + } + + return ground_normal_y; +} + +typedef f32 (*mCoBG_GET_BG_Y_NORMAL_PROC)(s_xyz* angle, mCoBG_UnitInfo_c* unit_info); + +static f32 mCoBG_GetBGHeight_Normal(s_xyz* angle, mCoBG_UnitInfo_c* unit_info) { + static mCoBG_GET_BG_Y_NORMAL_PROC get_bg_y_normal_proc[] = { &mCoBG_GetBGHeight_Normal_NormalGround, &mCoBG_GetBGHeight_Normal_SlateGround }; + + return (*get_bg_y_normal_proc[unit_info->collision->data.slate_flag])(angle, unit_info); +} + +static void mCoBG_MakeJumpFlag_NotOldOnGround(mCoBG_CheckResult_c* result, mCoBG_ActorInf_c* actor_info, xyz_t* rev, f32 ground_normal_y) { + // nothing +} + +static void mCoBG_MakeJumpFlag_OldOnGround(mCoBG_CheckResult_c* result, mCoBG_ActorInf_c* actor_info, xyz_t* rev, f32 ground_normal_y) { + if (actor_info->ground_y + rev->y > (ground_normal_y + 0.01f)) { + result->jump_flag = TRUE; + } +} + +typedef void (*mCoBG_MAKE_JUMP_FLAG_PROC)(mCoBG_CheckResult_c* result, mCoBG_ActorInf_c* actor_info, xyz_t* rev, f32 ground_normal_y); + +static void mCoBG_MakeJumpFlag(mCoBG_CheckResult_c* result, mCoBG_ActorInf_c* actor_info, xyz_t* rev, f32 ground_normal_y) { + static mCoBG_MAKE_JUMP_FLAG_PROC make_jump_flag_proc[] = { &mCoBG_MakeJumpFlag_NotOldOnGround, &mCoBG_MakeJumpFlag_OldOnGround }; + + (*make_jump_flag_proc[actor_info->old_on_ground & 1])(result, actor_info, rev, ground_normal_y); +} + +static int mCoBG_Pos2UnitPos(xyz_t* unit_pos, const xyz_t* pos) { + static const xyz_t pos0 = { 0.0f, 0.0f, 0.0f }; + xyz_t center_pos = pos0; + + *unit_pos = pos0; + if (mFI_Wpos2UtCenterWpos(¢er_pos, *pos)) { + unit_pos->x = pos->x - center_pos.x; + unit_pos->z = pos->z - center_pos.z; + return TRUE; + } + + return FALSE; +} + +typedef struct { + xyz_t low; + xyz_t high; +} mCoBG_wave_c; + +static u32 mCoBG_CheckWaveAtrDetail(xyz_t* point, mCoBG_wave_c* wave_p) { + f32 wave_cos = mCoBG_WaveCos(); + f32 rate = (1.0f + wave_cos) * 0.5f; + f32 cross[2]; + f32 high[2]; + f32 low[2]; + f32 p[2]; + + high[0] = wave_p->high.x; + high[1] = wave_p->high.z; + low[0] = wave_p->low.x; + low[1] = wave_p->low.z; + p[0] = point->x; + p[1] = point->z; + + if (mCoBG_GetCrossLineAndPerpendicular(cross, high, low, p)) { + f32 dx = SQ(high[0] - low[0]); + f32 dz = SQ(high[1] - low[1]); + f32 dist = sqrtf(dx + dz); + f32 dpx = SQ(cross[0] - low[0]); + f32 dpz = SQ(cross[1] - low[1]); + f32 dist_point = sqrtf(dpx + dpz); + f32 pos_rate; + + if (F32_IS_ZERO(dist) == FALSE) { + pos_rate = 1.1f * (dist_point / dist); + } else { + pos_rate = -1.0f; + } + + if (pos_rate <= 0.0f) { + return mCoBG_ATTRIBUTE_SEA; + } + + if (pos_rate >= 1.1f) { + return mCoBG_ATTRIBUTE_SAND; + } + + if (pos_rate <= rate) { + return mCoBG_ATTRIBUTE_WAVE; + } + + return mCoBG_ATTRIBUTE_SAND; + } + + return mCoBG_ATTRIBUTE_SEA; +} + +static u32 mCoBG_GetWaveDynamicAttr(u32 orig_attr, xyz_t* pos) { + if (orig_attr == mCoBG_ATTRIBUTE_36) { + static mCoBG_wave_c wave_s_info = { { 0.0f, 0.0f, mFI_UT_WORLDSIZE_HALF_Z_F }, { 0.0f, 0.0f, -mFI_UT_WORLDSIZE_HALF_Z_F } }; + + return mCoBG_CheckWaveAtrDetail(pos, &wave_s_info); + } + + if (orig_attr == mCoBG_ATTRIBUTE_37) { + static mCoBG_wave_c wave_se_info = { { 0.0f, 0.0f, 0.0f }, { -mFI_UT_WORLDSIZE_HALF_X_F, 0.0f, -mFI_UT_WORLDSIZE_HALF_Z_F } }; + + return mCoBG_CheckWaveAtrDetail(pos, &wave_se_info); + } + + if (orig_attr == mCoBG_ATTRIBUTE_38) { + static mCoBG_wave_c wave_sw_info = { { 0.0f, 0.0f, 0.0f }, { mFI_UT_WORLDSIZE_HALF_X_F, 0.0f, mFI_UT_WORLDSIZE_HALF_Z_F } }; + + return mCoBG_CheckWaveAtrDetail(pos, &wave_sw_info); + } + + if (orig_attr == mCoBG_ATTRIBUTE_25) { + static mCoBG_wave_c wave_se2_info = { { mFI_UT_WORLDSIZE_HALF_X_F, 0.0f, mFI_UT_WORLDSIZE_HALF_Z_F }, { 0.0f, 0.0f, 0.0f } }; + + return mCoBG_CheckWaveAtrDetail(pos, &wave_se2_info); + } + + if (orig_attr == mCoBG_ATTRIBUTE_26) { + static mCoBG_wave_c wave_sw2_info = { { -mFI_UT_WORLDSIZE_HALF_X_F, 0.0f, mFI_UT_WORLDSIZE_HALF_Z_F }, { 0.0f, 0.0f, 0.0f } }; + + return mCoBG_CheckWaveAtrDetail(pos, &wave_sw2_info); + } + + return mCoBG_ATTRIBUTE_SEA; +} + +// clang-format off +static u8 mCoBG_woodb_water_info[][4] = { + { mCoBG_ATTRIBUTE_RIVER_NW, mCoBG_ATTRIBUTE_RIVER_NW, mCoBG_ATTRIBUTE_WOOD, mCoBG_ATTRIBUTE_WOOD }, + { mCoBG_ATTRIBUTE_WOOD, mCoBG_ATTRIBUTE_RIVER_SW, mCoBG_ATTRIBUTE_RIVER_SW, mCoBG_ATTRIBUTE_WOOD }, + { mCoBG_ATTRIBUTE_WOOD, mCoBG_ATTRIBUTE_WOOD, mCoBG_ATTRIBUTE_RIVER_SE, mCoBG_ATTRIBUTE_RIVER_SE }, + { mCoBG_ATTRIBUTE_RIVER_NE, mCoBG_ATTRIBUTE_WOOD, mCoBG_ATTRIBUTE_WOOD, mCoBG_ATTRIBUTE_RIVER_NE }, + { mCoBG_ATTRIBUTE_WOOD, mCoBG_ATTRIBUTE_WOOD, mCoBG_ATTRIBUTE_WOOD, mCoBG_ATTRIBUTE_WOOD }, + { mCoBG_ATTRIBUTE_WOOD, mCoBG_ATTRIBUTE_WOOD, mCoBG_ATTRIBUTE_WOOD, mCoBG_ATTRIBUTE_WOOD }, +}; +// clang-format on + +// clang-format off +static u8 mCoBG_grass3_water_info[][4] = { + { mCoBG_ATTRIBUTE_RIVER_NW, mCoBG_ATTRIBUTE_RIVER_NW, mCoBG_ATTRIBUTE_GRASS2, mCoBG_ATTRIBUTE_GRASS2 }, + { mCoBG_ATTRIBUTE_GRASS2, mCoBG_ATTRIBUTE_RIVER_SW, mCoBG_ATTRIBUTE_RIVER_SW, mCoBG_ATTRIBUTE_GRASS2 }, + { mCoBG_ATTRIBUTE_GRASS2, mCoBG_ATTRIBUTE_GRASS2, mCoBG_ATTRIBUTE_RIVER_SE, mCoBG_ATTRIBUTE_RIVER_SE }, + { mCoBG_ATTRIBUTE_RIVER_NE, mCoBG_ATTRIBUTE_GRASS2, mCoBG_ATTRIBUTE_GRASS2, mCoBG_ATTRIBUTE_RIVER_NE }, +}; +// clang-format on + +extern u32 mCoBG_Wpos2Attribute(xyz_t pos, s8* cant_dig) { + mCoBG_UnitInfo_c unit_info; + u32 attr; + s16 area; + + pos.y = 0.0f; + mCoBG_Wpos2UnitInfo(&unit_info, pos); + attr = unit_info.collision->data.unit_attribute; + if (cant_dig != NULL) { + *cant_dig = FALSE; + } + + if (attr == mCoBG_ATTRIBUTE_HOLE) { + if (Common_Get(field_type) != mFI_FIELDTYPE2_FG) { + return mCoBG_ATTRIBUTE_FLOOR; + } else { + return mCoBG_ATTRIBUTE_GRASS2; + } + } + + if (attr == mCoBG_ATTRIBUTE_63) { + mCoBG_GetUnitArea(&unit_info, &area); + return mCoBG_SearchAttribute(pos, area, cant_dig); + } + + if (attr >= mCoBG_ATTRIBUTE_25 && attr <= mCoBG_ATTRIBUTE_26) { + xyz_t unit_pos; + + if (mCoBG_Pos2UnitPos(&unit_pos, &pos)) { + return mCoBG_GetWaveDynamicAttr(attr, &unit_pos); + } else { + return mCoBG_ATTRIBUTE_SAND; + } + } + + if (attr >= mCoBG_ATTRIBUTE_27 && attr <= mCoBG_ATTRIBUTE_62) { + if (cant_dig != NULL) { + *cant_dig = TRUE; + } + + if (attr >= mCoBG_ATTRIBUTE_43 && attr <= mCoBG_ATTRIBUTE_62) { + if (Common_Get(field_type) != mFI_FIELDTYPE2_FG) { + return mCoBG_ATTRIBUTE_FLOOR; + } else { + return mCoBG_ATTRIBUTE_GRASS2; + } + } + + if (attr >= mCoBG_ATTRIBUTE_27 && attr <= mCoBG_ATTRIBUTE_31) { + int idx; + + mCoBG_GetUnitArea(&unit_info, &area); + idx = attr - mCoBG_ATTRIBUTE_27; + return mCoBG_woodb_water_info[idx][area]; + } + + if (attr >= mCoBG_ATTRIBUTE_32 && attr <= mCoBG_ATTRIBUTE_35) { + return mCoBG_ATTRIBUTE_STONE; + } + + if (attr >= mCoBG_ATTRIBUTE_36 && attr <= mCoBG_ATTRIBUTE_38) { + xyz_t unit_pos; + + if (mCoBG_Pos2UnitPos(&unit_pos, &pos)) { + return mCoBG_GetWaveDynamicAttr(attr, &unit_pos); + } + + return mCoBG_ATTRIBUTE_SAND; + } + + if (attr >= mCoBG_ATTRIBUTE_39 && attr <= mCoBG_ATTRIBUTE_42) { + int idx; + + mCoBG_GetUnitArea(&unit_info, &area); + idx = attr - mCoBG_ATTRIBUTE_39; + + if ((mCoBG_grass3_water_info[idx][area] <= mCoBG_ATTRIBUTE_GRASS3 && Common_Get(field_type) != mFI_FIELDTYPE2_FG) == FALSE) { + return mCoBG_grass3_water_info[idx][area]; + } else { + return mCoBG_ATTRIBUTE_FLOOR; + } + } + } + + if ((attr <= mCoBG_ATTRIBUTE_GRASS3 && Common_Get(field_type) != mFI_FIELDTYPE2_FG) == FALSE) { + return attr; + } else { + return mCoBG_ATTRIBUTE_FLOOR; + } +} + +// clang-format off +static u8 mCoBG_unit_attribute_water_info[] = { + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_WATER, + mCoBG_ATTRIBUTE_WATERFALL, + mCoBG_ATTRIBUTE_RIVER_N, + mCoBG_ATTRIBUTE_RIVER_NW, + mCoBG_ATTRIBUTE_RIVER_W, + mCoBG_ATTRIBUTE_RIVER_SW, + mCoBG_ATTRIBUTE_RIVER_S, + mCoBG_ATTRIBUTE_RIVER_SE, + mCoBG_ATTRIBUTE_RIVER_E, + mCoBG_ATTRIBUTE_RIVER_NE, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_RIVER_NW, + mCoBG_ATTRIBUTE_RIVER_SW, + mCoBG_ATTRIBUTE_RIVER_SE, + mCoBG_ATTRIBUTE_RIVER_NE, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_RIVER_NW, + mCoBG_ATTRIBUTE_RIVER_SW, + mCoBG_ATTRIBUTE_RIVER_SE, + mCoBG_ATTRIBUTE_RIVER_NE, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, + mCoBG_ATTRIBUTE_GRASS0, +}; +// clang-format on + +static u32 mCoBG_SearchWaterAttributeFrom4Area(xyz_t pos) { + mCoBG_UnitInfo_c unit_info; + u32 attr; + + mCoBG_Wpos2UnitInfo(&unit_info, pos); + attr = unit_info.collision->data.unit_attribute; + return mCoBG_unit_attribute_water_info[attr]; +} + +#include "../src/AUS/game/m_collision_bg_info.c_inc" +#include "../src/AUS/game/m_collision_bg_rewrite.c_inc" + +static f32 mCoBG_GetBGHeight_NormalColumn(mCoBG_UnitInfo_c* unit_info, s_xyz* ground_angle, const xyz_t* pos) { + static s_xyz ground_angle0; // @BUG - shouldn't this be initialized? + s_xyz normal_ground_angle; + f32 normal_ground_y = mCoBG_GetBGHeight_Normal(&normal_ground_angle, unit_info); + f32 column_ground_y; + + if (unit_info->ut_x == l_ActorInf._68 && unit_info->ut_z == l_ActorInf._6C) { + column_ground_y = 0.0f; + } else { + column_ground_y = mCoBG_GetBGHeight_Column(pos, unit_info); + } + + if (normal_ground_y > column_ground_y) { + if (ground_angle != NULL) { + *ground_angle = normal_ground_angle; + } + return normal_ground_y; + } else { + if (ground_angle != NULL) { + *ground_angle = ground_angle0; + } + return column_ground_y; + } +} + +static void mCoBG_GroundCheck(xyz_t* rev, mCoBG_ActorInf_c* actor_info, ACTOR* actorx, f32 actor_ground_dist, mCoBG_CheckResult_c* result, s_xyz* angle, s16 attribute_wall) { + mCoBG_UnitInfo_c unit_info; + xyz_t pos; + f32 ground_y; + u32 attr; + u32 next_unit_attr = mCoBG_ATTRIBUTE_GRASS0; + BOOL water_flag = FALSE; + f32 water_y = 0.0f; + + pos.x = actorx->world.position.x + rev->x; + pos.y = 0.0f; + pos.z = actorx->world.position.z + rev->z; + mCoBG_Wpos2UnitInfo(&unit_info, pos); + attr = unit_info.collision->data.unit_attribute; + + if (attr == mCoBG_ATTRIBUTE_63 || (attr >= mCoBG_ATTRIBUTE_27 && attr <= mCoBG_ATTRIBUTE_62)) { + if (attribute_wall == FALSE && actor_info->old_in_water == TRUE && (attr >= mCoBG_ATTRIBUTE_27 && attr <= mCoBG_ATTRIBUTE_35)) { + int idx = attr - mCoBG_ATTRIBUTE_27; + int flags = mCoBG_bridge_search_water[idx]; + xyz_t next_pos; + int i; + + for (i = 0; i < 8; i++) { + if ((flags & (1 << i)) != 0) { + mCoBG_PlussDirectOffset(&next_pos, pos, i); + next_unit_attr = mCoBG_SearchWaterAttributeFrom4Area(next_pos); + if (next_unit_attr >= mCoBG_ATTRIBUTE_WATER && next_unit_attr <= mCoBG_ATTRIBUTE_RIVER_NE) { + water_flag = TRUE; + water_y = mCoBG_GetWaterHeight_File(pos, __FILE__, 3883); + } + } + + if (water_flag) { + actorx->bg_collision_check.result.unit_attribute = next_unit_attr; + break; + } + } + } else { + actorx->bg_collision_check.result.unit_attribute = mCoBG_Wpos2Attribute(pos, NULL); + } + } else { + if (attr >= mCoBG_ATTRIBUTE_WATER && attr <= mCoBG_ATTRIBUTE_RIVER_NE) { + water_flag = TRUE; + water_y = 20.0f + mCoBG_GetBgY_AngleS_FromWpos(NULL, pos, 0.0f); + } else if (attr == mCoBG_ATTRIBUTE_SEA) { + water_flag = TRUE; + water_y = 20.0f; + } else { + attr = mCoBG_Wpos2Attribute(pos, NULL); + } + + actorx->bg_collision_check.result.unit_attribute = attr; + } + + ground_y = mCoBG_GetBGHeight_NormalColumn(&unit_info, angle, &pos); + mCoBG_AdjustActorY(rev, actorx, ground_y, water_y, actor_ground_dist, result, actor_info, water_flag); + mCoBG_MakeJumpFlag(result, actor_info, rev, ground_y); +} + +#include "../src/AUS/game/m_collision_bg_block.c_inc" +#include "../src/AUS/game/m_collision_bg_line.c_inc" +#include "../src/AUS/game/m_collision_bg_water.c_inc" + +extern void mCoBG_InitBgCheckResult(mCoBG_CheckResult_c* result) { + result->on_ground = FALSE; + result->is_on_move_bg_obj = FALSE; + result->hit_wall = 0; + result->hit_attribute_wall = 0; + result->jump_flag = FALSE; + result->is_in_water = FALSE; + result->unit_attribute = 0; + result->hit_wall_count = 0; + // result->unk_flag1 = FALSE; + result->unk_flag2 = FALSE; + result->unk_flag3 = FALSE; + result->unk_flag4 = FALSE; + result->unk_flag5 = FALSE; +} + +static void mCoBG_InitBgCheckClass(mCoBG_Check_c* check) { + check->wall_bottom_y = 0.0f; + check->wall_top_y = 0.0f; + check->ground_y = 0.0f; + check->wall_info[0].angleY = 0xB6; + check->wall_info[1].angleY = 0xB6; + check->wall_info[0].type = mCoBG_WALL_TYPE_NUM; + check->wall_info[1].type = mCoBG_WALL_TYPE_NUM; +} + +static s16 mCoBG_ActorFearture2CheckRange(mCoBG_ActorInf_c* actor_info) { + f32 range = actor_info->range; + + if (range <= 40.0f) { + return 3; + } + + if (range <= 80.0f) { + return 5; + } + + return 7; +} + +static void mCoBG_MakeActorInf(mCoBG_ActorInf_c* actor_info, ACTOR* actorx, f32 range, f32 ground_dist, s16 check_type, int ux, int uz) { + actor_info->_68 = ux; + actor_info->_6C = uz; + actor_info->old_in_water = actorx->bg_collision_check.result.is_in_water; + actor_info->old_on_ground = actorx->bg_collision_check.result.on_ground; + mCoBG_InitBgCheckResult(&actorx->bg_collision_check.result); + mCoBG_InitBgCheckClass(&actorx->bg_collision_check); + actor_info->name = actorx->id; + actor_info->check_res_p = &actorx->bg_collision_check.result; + mCoBG_GetSpeedByWpos(l_ActorInf.speed_xz1, actorx); + actor_info->range = range; + actor_info->ground_dist = ground_dist; + actor_info->old_ground_y = actorx->last_world_position.y + ground_dist; + actor_info->ground_y = actorx->world.position.y + ground_dist; + actor_info->ut_count = mCoBG_ActorFearture2CheckRange(actor_info); + actor_info->wall_height.top = 0.0f; + actor_info->wall_height.bot = 0.0f; + actor_info->wall_info[0].angleY = 0xB6; + actor_info->wall_info[1].angleY = 0xB6; + actor_info->wall_info[0].type = mCoBG_WALL_TYPE_NUM; + actor_info->wall_info[1].type = mCoBG_WALL_TYPE_NUM; + actor_info->check_type = check_type; + if (F32_IS_ZERO(actor_info->speed_xz1[0]) && F32_IS_ZERO(actor_info->speed_xz1[1])) { + actor_info->_64 = 1; + } else { + actor_info->_64 = 0; + } +} + +static void mCoBG_GiveRevposToActor(xyz_t* actor_revpos, xyz_t revpos) { + if (actor_revpos != NULL) { + *actor_revpos = revpos; + } +} + +static void mCoBG_MoveActorWithMoveBg_NotOnMoveBg(ACTOR* actorx) { + // nothing +} + +static void mCoBG_MoveActorWithMoveBg_OnMoveBg(ACTOR* actorx) { + mCoBG_bg_regist_c* regist = mCoBG_Idx2RegistPointer(actorx->shape_info.move_bg_idx); + + if (regist != NULL) { + xyz_t move; + xyz_t* pos_p = regist->wpos; + xyz_t* last_pos_p = regist->last_wpos; + + if (pos_p != NULL && last_pos_p != NULL) { + move.x = pos_p->x - last_pos_p->x; + move.y = pos_p->y - last_pos_p->y; + move.z = pos_p->z - last_pos_p->z; + + actorx->world.position.x += move.x; + actorx->world.position.y += move.y; + actorx->world.position.z += move.z; + } + } +} + +typedef void (*mCoBG_MOVE_BG_MOVE_ACTOR_PROC)(ACTOR* actorx); + +static void mCoBG_MoveActorWithMoveBg(ACTOR* actorx) { + static mCoBG_MOVE_BG_MOVE_ACTOR_PROC move_bg_move_actor_proc[] = { &mCoBG_MoveActorWithMoveBg_NotOnMoveBg, &mCoBG_MoveActorWithMoveBg_OnMoveBg }; + + (*move_bg_move_actor_proc[actorx->bg_collision_check.result.is_on_move_bg_obj])(actorx); +} + +static void mCoBG_RoomScopeCheck(ACTOR* actorx, f32 range, f32 ground_dist) { + if (actorx->id == mAc_PROFILE_HOUSE_GOKI) { + int scene = Save_Get(scene_no); + static xyz_t base_pos = { mFI_UT_WORLDSIZE_X_F, 0.0f, mFI_UT_WORLDSIZE_Z_F }; + + if (scene == SCENE_MY_ROOM_S) { + mCoBG_ScopeWallCheck(actorx, &base_pos, 160.0f, 160.0f, range, ground_dist); + } else if (scene == SCENE_MY_ROOM_M || scene == SCENE_MY_ROOM_LL2) { + mCoBG_ScopeWallCheck(actorx, &base_pos, 240.0f, 240.0f, range, ground_dist); + } else if (scene == SCENE_MY_ROOM_L || scene == SCENE_MY_ROOM_LL1) { + mCoBG_ScopeWallCheck(actorx, &base_pos, 320.0f, 320.0f, range, ground_dist); + } + } +} + +extern void mCoBG_BgCheckControll_RemoveDirectedUnitColumn(xyz_t* actor_revpos, ACTOR* actorx, f32 range, f32 ground_dist, s16 attr_wall, s16 rev_type, s16 check_type, int ux, int uz) { + s_xyz angle = { 0.0f, 0.0f, 0.0f }; + mCoBG_Check_c prev_check = actorx->bg_collision_check; + + mCoBG_MoveActorWithMoveBg(actorx); + mCoBG_InitRevpos(&l_ActorInf.rev_pos); + mCoBG_GetCurrentCenterPosition(&l_ActorInf.center_pos, actorx); + mCoBG_GetOldCenterPosition(&l_ActorInf.old_center_pos, actorx); + mCoBG_MakeActorInf(&l_ActorInf, actorx, range, ground_dist, check_type, ux, uz); + mCoBG_WallCheck(actorx, &l_ActorInf, attr_wall, &prev_check); + actorx->bg_collision_check.result.unk_flag1 = l_ActorInf._64; + mCoBG_GroundCheck(&l_ActorInf.rev_pos, &l_ActorInf, actorx, ground_dist, &actorx->bg_collision_check.result, &angle, attr_wall); + mCoBG_MoveBgGroundCheck(&l_ActorInf.rev_pos, &l_ActorInf, actorx, &actorx->bg_collision_check.result, &angle); + mCoBG_CarryOutReverse(actorx, l_ActorInf.rev_pos, rev_type); + mCoBG_GiveRevposToActor(actor_revpos, l_ActorInf.rev_pos); + mCoBG_RoomScopeCheck(actorx, range, ground_dist); + l_ActorInf._68 = -1; + l_ActorInf._6C = -1; +} + +extern void mCoBG_BgCheckControll(xyz_t* actor_revpos, ACTOR* actorx, f32 range, f32 ground_dist, s16 attr_wall, s16 rev_type, s16 check_type) { + mCoBG_BgCheckControll_RemoveDirectedUnitColumn(actor_revpos, actorx, range, ground_dist, attr_wall, rev_type, check_type, -1, -1); +} + +extern void mCoBG_WallCheckOnly(xyz_t* actor_revpos, ACTOR* actorx, f32 range, f32 ground_dist, s16 rev_type, s16 check_type) { + s16 attr_wall = FALSE; + mCoBG_Check_c prev_check = actorx->bg_collision_check; + + mCoBG_InitRevpos(&l_ActorInf.rev_pos); + mCoBG_GetCurrentCenterPosition(&l_ActorInf.center_pos, actorx); + mCoBG_GetOldCenterPosition(&l_ActorInf.old_center_pos, actorx); + mCoBG_MakeActorInf(&l_ActorInf, actorx, range, ground_dist, check_type, -1, -1); + mCoBG_WallCheck(actorx, &l_ActorInf, attr_wall, &prev_check); + actorx->bg_collision_check.result.unk_flag1 = l_ActorInf._64; + mCoBG_CarryOutReverse(actorx, l_ActorInf.rev_pos, rev_type); + mCoBG_GiveRevposToActor(actor_revpos, l_ActorInf.rev_pos); + mCoBG_RoomScopeCheck(actorx, range, ground_dist); +} + +extern void mCoBG_GroundCheckOnly(xyz_t* actor_revpos, ACTOR* actorx, f32 range, f32 ground_dist, s16 rev_type) { + s_xyz angle = { 0.0f, 0.0f, 0.0f }; + + mCoBG_MoveActorWithMoveBg(actorx); + mCoBG_InitRevpos(&l_ActorInf.rev_pos); + mCoBG_GetCurrentCenterPosition(&l_ActorInf.center_pos, actorx); + mCoBG_GetOldCenterPosition(&l_ActorInf.old_center_pos, actorx); + mCoBG_GetSpeedByWpos(l_ActorInf.speed_xz0, actorx); + mCoBG_MakeActorInf(&l_ActorInf, actorx, 0.0f, ground_dist, mCoBG_CHECK_TYPE_NORMAL, -1, -1); + mCoBG_GroundCheck(&l_ActorInf.rev_pos, &l_ActorInf, actorx, ground_dist, &actorx->bg_collision_check.result, &angle, FALSE); + mCoBG_CarryOutReverse(actorx, l_ActorInf.rev_pos, rev_type); + mCoBG_GiveRevposToActor(actor_revpos, l_ActorInf.rev_pos); +} + +static ACTOR Virtual_Actor; + +extern void mCoBG_VirtualBGCheck(xyz_t* rev_pos_p, mCoBG_Check_c* bg_check, const xyz_t* start_pos_p, + const xyz_t* end_pos_p, s16 angle_y, s16 water_flag, s16 ground_flag, f32 range, + f32 ground_dist, s16 attr_wall, s16 rev_type, s16 check_type) { + ACTOR* actorx = &Virtual_Actor; + + bzero(actorx, sizeof(ACTOR)); + actorx->world.position = *end_pos_p; + actorx->last_world_position = *start_pos_p; + actorx->bg_collision_check.result.is_in_water = (s16)water_flag; + actorx->bg_collision_check.result.on_ground = (s16)ground_flag; + actorx->shape_info.rotation.y = angle_y; + mCoBG_BgCheckControll(rev_pos_p, actorx, range, ground_dist, attr_wall, rev_type, check_type); + *bg_check = actorx->bg_collision_check; +} diff --git a/src/AUS/game/m_collision_bg_block.c_inc b/src/AUS/game/m_collision_bg_block.c_inc new file mode 100644 index 00000000..a4978635 --- /dev/null +++ b/src/AUS/game/m_collision_bg_block.c_inc @@ -0,0 +1,88 @@ +int mCoBG_block_bgcheck_mode = mCoBG_BLOCK_BGCHECK_MODE_NORMAL; + +extern void mCoBG_InitBlockBgCheckMode(void) { + mCoBG_block_bgcheck_mode = mCoBG_BLOCK_BGCHECK_MODE_NORMAL; +} + +extern int mCoBG_ChangeBlockBgCheckMode(int mode) { + mCoBG_block_bgcheck_mode = mode & 1; + return mCoBG_block_bgcheck_mode; +} + +extern int mCoBG_GetBlockBgCheckMode(void) { + return mCoBG_block_bgcheck_mode & 1; +} + +extern xyz_t mCoBG_UniqueWallCheck(ACTOR* actorx, f32 range, f32 y_ofs) { + int bx; + int bz; + xyz_t ret = { 0.0f, 0.0f, 0.0f }; + + mCoBG_InitRevpos(&l_ActorInf.rev_pos); + mCoBG_GetCurrentCenterPosition(&l_ActorInf.center_pos, actorx); + mCoBG_GetOldCenterPosition(&l_ActorInf.old_center_pos, actorx); + mCoBG_GetSpeedByWpos(l_ActorInf.speed_xz0, actorx); + + if (mFI_Wpos2BlockNum(&bx, &bz, l_ActorInf.old_center_pos)) { + xyz_t block_base = { 0.0f, 0.0f, 0.0f }; + + mCoBG_SetXyz_t(&l_ActorInf.rev_pos, 0.0f, 0.0f, 0.0f); + mFI_BkNum2WposXZ(&block_base.x, &block_base.z, bx, bz); + if (mCoBG_GetBlockBgCheckMode() == mCoBG_BLOCK_BGCHECK_MODE_INTRO_DEMO && + (mFI_BkNum2BlockKind(bx, bz) & mRF_BLOCKKIND_PLAYER) != 0 + ) { + block_base.x += mFI_UT_WORLDSIZE_X_F; + block_base.z += mFI_UT_WORLDSIZE_Z_F; + return mCoBG_ScopeWallCheck(actorx, &block_base, mFI_BK_WORLDSIZE_X - 2 * mFI_UT_WORLDSIZE_X, mFI_BK_WORLDSIZE_Z - 2 * mFI_UT_WORLDSIZE_Z, range, y_ofs); + } else { + return mCoBG_ScopeWallCheck(actorx, &block_base, mFI_BK_WORLDSIZE_X, mFI_BK_WORLDSIZE_Z, range, y_ofs); + } + } + + return ret; +} + +extern xyz_t mCoBG_ScopeWallCheck(ACTOR* actorx, const xyz_t* base_pos, f32 x, f32 z, f32 range, f32 y_ofs) { + f32 start[2]; + f32 end[2]; + s16 rev_type; + xyz_t rev = { 0.0f, 0.0f, 0.0f }; + + mCoBG_InitRevpos(&l_ActorInf.rev_pos); + mCoBG_GetCurrentCenterPosition(&l_ActorInf.center_pos, actorx); + mCoBG_GetOldCenterPosition(&l_ActorInf.old_center_pos, actorx); + mCoBG_GetSpeedByWpos(l_ActorInf.speed_xz0, actorx); + + if (l_ActorInf.speed_xz0[0] != 0.0f || l_ActorInf.speed_xz0[1] != 0.0f) { + start[0] = (base_pos->x); + start[1] = (base_pos->z); + end[0] = start[0] + x; + end[1] = start[1] + z; + + start[0] += range; + start[1] += range; + + end[0] -= range; + end[1] -= range; + + mCoBG_SetXyz_t(&l_ActorInf.rev_pos, 0.0f, 0.0f, 0.0f); + + if (l_ActorInf.center_pos.x < start[0]) { + l_ActorInf.rev_pos.x = start[0] - l_ActorInf.center_pos.x; + } else if (l_ActorInf.center_pos.x > end[0]) { + l_ActorInf.rev_pos.x = end[0] - l_ActorInf.center_pos.x; + } + + if (l_ActorInf.center_pos.z < start[1]) { + l_ActorInf.rev_pos.z = start[1] - l_ActorInf.center_pos.z; + } else if (l_ActorInf.center_pos.z > end[1]) { + l_ActorInf.rev_pos.z = end[1] - l_ActorInf.center_pos.z; + } + + mCoBG_GroundCheck(&l_ActorInf.rev_pos, &l_ActorInf, actorx, y_ofs, &actorx->bg_collision_check.result, NULL, FALSE); + mCoBG_CarryOutReverse(actorx, l_ActorInf.rev_pos, mCoBG_REVERSE_TYPE_REVERSE); + return l_ActorInf.rev_pos; + } + + return rev; +} diff --git a/src/AUS/game/m_collision_bg_column.c_inc b/src/AUS/game/m_collision_bg_column.c_inc new file mode 100644 index 00000000..e8eea076 --- /dev/null +++ b/src/AUS/game/m_collision_bg_column.c_inc @@ -0,0 +1,578 @@ +typedef struct { + xyz_t pos; + int in_use; + f32 start_radius; + f32 end_radius; + f32 now_radius; + s16 start_timer; + s16 now_timer; +} mCoBG_regist_circle_info_c; + +static int mCoBG_regist_decal_circle_count = 0; +static mCoBG_regist_circle_info_c mCoBG_regist_circle_info[3]; +static mCoBG_column_c mCoBG_decal_circle[3]; + +static f32 mCoBG_CalcAdjust(s16 now_a, s16 start_a, s16 end_a, f32 start_val, f32 end_val) { + if (start_a == end_a) { + return start_val; + } + + if (now_a <= start_a) { + return start_val; + } + + if (now_a >= end_a) { + return end_val; + } + + { + f32 d_a = now_a - start_a; + f32 n_a = end_a - start_a; + f32 n_val = end_val - start_val; + + return start_val + d_a * (n_val / n_a); + } +} + +static void mCoBG_CalcTimerDecalCircleOne(mCoBG_regist_circle_info_c* regist, mCoBG_column_c* col_circle) { + if (regist->in_use == TRUE) { + if (regist->start_timer != -100) { + regist->now_radius = mCoBG_CalcAdjust(regist->start_timer - regist->now_timer, 0, regist->start_timer, regist->start_radius, regist->end_radius); + col_circle->pos = regist->pos; + col_circle->height = regist->pos.y; + col_circle->radius = regist->now_radius; + col_circle->atr_wall = TRUE; + col_circle->ux = (int)(col_circle->pos.x / mFI_UT_WORLDSIZE_X_F); + col_circle->uz = (int)(col_circle->pos.z / mFI_UT_WORLDSIZE_Z_F); + regist->now_timer--; + if (regist->now_timer < 0) { + regist->in_use = FALSE; + mCoBG_regist_decal_circle_count--; + } + } + } +} + +extern void mCoBG_CalcTimerDecalCircle(void) { + int i; + mCoBG_regist_circle_info_c* regist = mCoBG_regist_circle_info; + mCoBG_column_c* col_circle = mCoBG_decal_circle; + + if (mCoBG_regist_decal_circle_count > 0) { + for (i = 0; i < 3; i++) { + mCoBG_CalcTimerDecalCircleOne(regist, col_circle); + regist++; + col_circle++; + } + } +} + +extern int mCoBG_RegistDecalCircle(const xyz_t* pos, f32 start_radius, f32 end_radius, s16 timer) { + int i; + mCoBG_regist_circle_info_c* regist = mCoBG_regist_circle_info; + mCoBG_column_c* col_circle = mCoBG_decal_circle; + + if (mCoBG_regist_decal_circle_count < 3) { + for (i = 0; i < 3; i++) { + if (regist->in_use == FALSE) { + // @BUG - this will clobber data below mCoBG_regist_circle_info??? + // because we don't break/return after finding a free + // circle and we clear the WHOLE array, we can clear into + // mCoBG_decal_circle's data. +#ifndef BUGFIXES + bzero(regist, sizeof(mCoBG_regist_circle_info)); +#else + bzero(regist, sizeof(mCoBG_regist_circle_info_c)); +#endif + bzero(col_circle, sizeof(mCoBG_column_c)); + + regist->in_use = TRUE; + regist->pos = *pos; + regist->start_radius = start_radius; + regist->end_radius = end_radius; + regist->now_radius = start_radius; + regist->start_timer = timer; + regist->now_timer = timer; + mCoBG_CalcTimerDecalCircleOne(regist, col_circle); + mCoBG_regist_decal_circle_count++; + // @BUG - shouldn't this exit immediately? + // As it stands, all free 'decal circle' collision columns + // will be utilized. +#ifdef BUGFIXES + return i; +#endif + } + + regist++; + col_circle++; + } + } + + return -1; +} + +extern void mCoBG_InitDecalCircle(void) { + // @BUG - they incorrectly clear 3x the memory necessary. + // I'm guessing that they did 3 * sizeof(array) rather than + // 3 * sizeof(struct). +#ifndef BUGFIXES + bzero(mCoBG_regist_circle_info, 3 * sizeof(mCoBG_regist_circle_info)); +#else + bzero(mCoBG_regist_circle_info, sizeof(mCoBG_regist_circle_info_c)); +#endif + bzero(mCoBG_decal_circle, sizeof(mCoBG_decal_circle)); + mCoBG_regist_decal_circle_count = 0; +} + +// @unused, @fabricated +extern void mCoBG_CrossOffDecalCircle(int idx) { + if (idx >= 0 && idx < 3) { + bzero(&mCoBG_regist_circle_info[idx], sizeof(mCoBG_regist_circle_info_c)); + bzero(&mCoBG_decal_circle[idx], sizeof(mCoBG_decal_circle)); + mCoBG_regist_decal_circle_count--; + } +} + +static int mCoBG_MakeOneColumnCollisionData(mCoBG_column_c* col, mCoBG_UnitInfo_c* ut_info, int old_on_ground, mCoBG_COLUMN_CHECK_ITEM_TYPE_PROC check_proc, int ux, int uz) { + if ((check_proc != NULL && (*check_proc)(ut_info->item) == FALSE) || check_proc == NULL) { + if (ut_info->ut_x == ux && ut_info->ut_z == uz) { + return FALSE; + } + + if (old_on_ground == TRUE && (ITEM_IS_HOLE(ut_info->item) || ut_info->item == HOLE_SHINE || ut_info->item == RSV_HOLE)) { + col->pos.x = mFI_UT_WORLDSIZE_HALF_X_F + mFI_UT_WORLDSIZE_X_F * ut_info->ut_x; + col->pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + mFI_UT_WORLDSIZE_Z_F * ut_info->ut_z; + col->pos.y = 0.0f; + col->ux = ut_info->ut_x; + col->uz = ut_info->ut_z; + col->pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(col->pos, 0.0f); + col->height = col->pos.y; + col->radius = 19.0f; + col->atr_wall = TRUE; + return TRUE; + } + + if (IS_ITEM_SMALL_TREE(ut_info->item)) { + col->pos.x = mFI_UT_WORLDSIZE_HALF_X_F + mFI_UT_WORLDSIZE_X_F * ut_info->ut_x; + col->pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + mFI_UT_WORLDSIZE_Z_F * ut_info->ut_z; + col->pos.y = 0.0f; + col->pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(col->pos, 0.0f); + col->height = col->pos.y + 30.0f; + col->ux = ut_info->ut_x; + col->uz = ut_info->ut_z; + col->radius = 19.0f; + col->atr_wall = FALSE; + return TRUE; + } + + if (IS_ITEM_MED_TREE(ut_info->item)) { + col->pos.x = mFI_UT_WORLDSIZE_HALF_X_F + mFI_UT_WORLDSIZE_X_F * ut_info->ut_x; + col->pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + mFI_UT_WORLDSIZE_Z_F * ut_info->ut_z; + col->pos.y = 0.0f; + col->pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(col->pos, 0.0f); + col->height = col->pos.y + 40.0f; + col->ux = ut_info->ut_x; + col->uz = ut_info->ut_z; + col->radius = 19.0f; + col->atr_wall = FALSE; + return TRUE; + } + + if (IS_ITEM_LARGE_TREE(ut_info->item)) { + col->pos.x = mFI_UT_WORLDSIZE_HALF_X_F + mFI_UT_WORLDSIZE_X_F * ut_info->ut_x; + col->pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + mFI_UT_WORLDSIZE_Z_F * ut_info->ut_z; + col->pos.y = 0.0f; + col->pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(col->pos, 0.0f); + col->height = col->pos.y + 60.0f; + col->ux = ut_info->ut_x; + col->uz = ut_info->ut_z; + col->radius = 19.0f; + col->atr_wall = FALSE; + return TRUE; + } + + if (IS_ITEM_FULL_TREE(ut_info->item) || ut_info->item == RSV_TREE) { + col->pos.x = mFI_UT_WORLDSIZE_HALF_X_F + mFI_UT_WORLDSIZE_X_F * ut_info->ut_x; + col->pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + mFI_UT_WORLDSIZE_Z_F * ut_info->ut_z; + col->pos.y = 0.0f; + col->pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(col->pos, 0.0f); + col->height = col->pos.y + 80.0f; + col->ux = ut_info->ut_x; + col->uz = ut_info->ut_z; + col->radius = 19.0f; + col->atr_wall = FALSE; + return TRUE; + } + + if (IS_ITEM_TREE_STUMP(ut_info->item)) { + col->pos.x = mFI_UT_WORLDSIZE_HALF_X_F + mFI_UT_WORLDSIZE_X_F * ut_info->ut_x; + col->pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + mFI_UT_WORLDSIZE_Z_F * ut_info->ut_z; + col->pos.y = 0.0f; + col->pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(col->pos, 0.0f); + col->ux = ut_info->ut_x; + col->uz = ut_info->ut_z; + + if (ut_info->item == TREE_STUMP001 || ut_info->item == TREE_PALM_STUMP001 || ut_info->item == CEDAR_TREE_STUMP001 || ut_info->item == GOLD_TREE_STUMP001) { + col->radius = 10.0f; + col->height = col->pos.y + 30.0f; + } else { + col->radius = 18.0f; + col->height = col->pos.y + 30.0f; + } + col->atr_wall = FALSE; + return TRUE; + } + + if (IS_ITEM_ROCK(ut_info->item)) { + col->pos.x = mFI_UT_WORLDSIZE_HALF_X_F + mFI_UT_WORLDSIZE_X_F * ut_info->ut_x; + col->pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + mFI_UT_WORLDSIZE_Z_F * ut_info->ut_z; + col->pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(col->pos, 0.0f); + col->ux = ut_info->ut_x; + col->uz = ut_info->ut_z; + col->radius = 19.0f; + col->height = col->pos.y + 31.5f; + col->atr_wall = FALSE; + return TRUE; + } + + if (ut_info->item == DUMMY_MAILBOX0 || ut_info->item == DUMMY_MAILBOX1 || ut_info->item == DUMMY_MAILBOX2 || ut_info->item == DUMMY_MAILBOX3) { + col->pos.x = mFI_UT_WORLDSIZE_HALF_X_F + mFI_UT_WORLDSIZE_X_F * ut_info->ut_x; + col->pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + mFI_UT_WORLDSIZE_Z_F * ut_info->ut_z; + col->pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(col->pos, 0.0f); + col->ux = ut_info->ut_x; + col->uz = ut_info->ut_z; + col->radius = 15.0f; + col->height = col->pos.y + 50.0f; + col->atr_wall = FALSE; + return TRUE; + } + + if (ITEM_IS_SIGN(ut_info->item)) { + col->pos.x = mFI_UT_WORLDSIZE_HALF_X_F + mFI_UT_WORLDSIZE_X_F * ut_info->ut_x; + col->pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + mFI_UT_WORLDSIZE_Z_F * ut_info->ut_z; + col->pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(col->pos, 0.0f); + col->radius = 19.0f; + col->height = col->pos.y + 45.0f; + col->ux = ut_info->ut_x; + col->uz = ut_info->ut_z; + col->atr_wall = FALSE; + return TRUE; + } + + if (ut_info->item == RSV_SIGNBOARD) { + col->pos.x = mFI_UT_WORLDSIZE_HALF_X_F + mFI_UT_WORLDSIZE_X_F * ut_info->ut_x; + col->pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + mFI_UT_WORLDSIZE_Z_F * ut_info->ut_z; + col->pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(col->pos, 0.0f); + col->radius = 10.0f; + col->height = col->pos.y + 45.0f; + col->ux = ut_info->ut_x; + col->uz = ut_info->ut_z; + col->atr_wall = FALSE; + return TRUE; + } + + if (ut_info->item == DUMMY_KOINOBORI || ut_info->item == DUMMY_FLAG) { + col->pos.x = mFI_UT_WORLDSIZE_HALF_X_F + mFI_UT_WORLDSIZE_X_F * ut_info->ut_x; + col->pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + mFI_UT_WORLDSIZE_Z_F * ut_info->ut_z; + col->pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(col->pos, 0.0f); + col->radius = 19.0f; + col->height = col->pos.y + 160.0f; + col->ux = ut_info->ut_x; + col->uz = ut_info->ut_z; + col->atr_wall = FALSE; + return TRUE; + } + } + + return FALSE; +} + +static void mCoBG_MakeColumnCollisionData(mCoBG_column_c* col, int* col_count_p, mCoBG_UnitInfo_c* ut_info, int count, int old_on_ground, mCoBG_COLUMN_CHECK_ITEM_TYPE_PROC check_item_proc, int ux, int uz) { + int count_sq = SQ(count); + int i; + + *col_count_p = 0; + for (i = 0; i < count_sq; i++) { + if (*col_count_p < 16) { + mCoBG_MakeOneColumnCollisionData(col, ut_info, old_on_ground, check_item_proc, ux, uz); + col++; + (*col_count_p)++; + } + + ut_info++; + } +} + +static void mCoBG_ColumnCheck_NormalWall(xyz_t* rev, mCoBG_ActorInf_c* actor_info, const xyz_t* pos, const xyz_t* old_pos, mCoBG_column_c* col, s16 attr_wall) { + f32 ground_dist = actor_info->ground_dist; + f32 now_y = ground_dist + pos->y; + + if (mCoBG_JudgePointInCircle_Xyz(old_pos, &col->pos, col->radius) == FALSE && (col->height >= (now_y + 3.0f))) { + f32 dx = pos->x - col->pos.x; + f32 dz = pos->z - col->pos.z; + f32 dist = sqrtf(SQ(dx) + SQ(dz)); + f32 check_dist = actor_info->range + col->radius; + + if (dist < check_dist) { + xyz_t rev_vec; + f32 rev_dist = check_dist - dist; + xyz_t rev_unit_vec; + mCoBG_WallHeight_c height; + s16 angle = atans_table(dz, dx); + f32 div; + + rev_vec.x = pos->x - col->pos.x; + rev_vec.y = 0.0f; + rev_vec.z = pos->z - col->pos.z; + + if (F32_IS_ZERO(dist)) { + div = 1.0f; + } else { + div = 1.0f / dist; + } + + rev_unit_vec.x = rev_vec.x * div; + rev_unit_vec.y = 0.0f; + rev_unit_vec.z = rev_vec.z * div; + + rev->x = rev_unit_vec.x * rev_dist; + rev->y = rev_unit_vec.y * rev_dist; + rev->z = rev_unit_vec.z * rev_dist; + height.top = col->height; + height.bot = col->pos.y; + mCoBG_RegistCollisionWallInfo(actor_info, actor_info->wall_info, &height, angle, FALSE); + } else { + f32 diff = dist - check_dist; + + if (diff > 0.0f && diff < 2.7f) { + mCoBG_WallHeight_c height; + s16 angle = atans_table(dz, dx); + + height.top = col->height; + height.bot = col->pos.y; + mCoBG_RegistCollisionWallInfo(actor_info, actor_info->wall_info, &height, angle, FALSE); + } + } + } +} + +static void mCoBG_ColumnCheckOldOnGround_AttrWall(xyz_t* rev, mCoBG_ActorInf_c* actor_info, const xyz_t* pos, const xyz_t* old_pos, mCoBG_column_c* col) { + if (mCoBG_JudgePointInCircle_Xyz(old_pos, &col->pos, col->radius) == FALSE) { + f32 dx = pos->x - col->pos.x; + f32 dz = pos->z - col->pos.z; + f32 dist = sqrtf(SQ(dx) + SQ(dz)); + f32 check_dist = actor_info->range + col->radius; + + if (dist < check_dist) { + xyz_t rev_vec; + f32 rev_dist = check_dist - dist; + xyz_t rev_unit_vec; + s16 angle = atans_table(dz, dx); + f32 div; + + rev_vec.x = pos->x - col->pos.x; + rev_vec.y = 0.0f; + rev_vec.z = pos->z - col->pos.z; + + if (F32_IS_ZERO(dist)) { + div = 1.0f; + } else { + div = 1.0f / dist; + } + + rev_unit_vec.x = rev_vec.x * div; + rev_unit_vec.y = 0.0f; + rev_unit_vec.z = rev_vec.z * div; + + rev->x = rev_unit_vec.x * rev_dist; + rev->y = rev_unit_vec.y * rev_dist; + rev->z = rev_unit_vec.z * rev_dist; + mCoBG_RegistCollisionWallInfo(actor_info, actor_info->wall_info, NULL, angle, TRUE); + } else { + f32 diff = dist - check_dist; + + if (diff > 0.0f && diff < 2.7f) { + s16 angle = atans_table(dz, dx); + + mCoBG_RegistCollisionWallInfo(actor_info, actor_info->wall_info, NULL, angle, TRUE); + } + } + } +} + +static void mCoBG_ColumnCheckNotOldOnGround_AttrWall(xyz_t* rev, mCoBG_ActorInf_c* actor_info, const xyz_t* pos, const xyz_t* old_pos, mCoBG_column_c* col) { + // nothing +} + +typedef void (*mCoBG_ATR_COLUMN_SUB_PROC)(xyz_t* rev, mCoBG_ActorInf_c* actor_info, const xyz_t* pos, const xyz_t* old_pos, mCoBG_column_c* col); + +static void mCoBG_ColumnCheck_AttrWall(xyz_t* rev, mCoBG_ActorInf_c* actor_info, const xyz_t* pos, const xyz_t* old_pos, mCoBG_column_c* col, s16 attr_wall) { + if (attr_wall != FALSE) { + static mCoBG_ATR_COLUMN_SUB_PROC atr_column_sub_proc_table[] = { &mCoBG_ColumnCheckNotOldOnGround_AttrWall, &mCoBG_ColumnCheckOldOnGround_AttrWall }; + + (*atr_column_sub_proc_table[actor_info->old_on_ground])(rev, actor_info, pos, old_pos, col); + } +} + +typedef void (*mCoBG_WALL_CHECK_PROC)(xyz_t* rev, mCoBG_ActorInf_c* actor_info, const xyz_t* pos, const xyz_t* old_pos, mCoBG_column_c* col, s16 attr_wall); + +static void mCoBG_ColumnWallCheck(xyz_t* rev, mCoBG_ActorInf_c* actor_info, const xyz_t* pos, mCoBG_column_c* col, int col_count, s16 attr_wall) { + static mCoBG_WALL_CHECK_PROC column_wall_check_func[] = { &mCoBG_ColumnCheck_NormalWall, &mCoBG_ColumnCheck_AttrWall }; + static xyz_t reverse0 = { 0.0f, 0.0f, 0.0f }; + + *rev = reverse0; + if (col_count != 0) { + int i; + + for (i = 0; i < col_count; i++) { + xyz_t reverse = { 0.0f, 0.0f, 0.0f }; + xyz_t tmp_pos; + + tmp_pos.x = pos->x + rev->x; + tmp_pos.y = pos->y + rev->y; + tmp_pos.z = pos->z + rev->z; + (*column_wall_check_func[col->atr_wall])(&reverse, actor_info, &tmp_pos, &actor_info->old_center_pos, col, attr_wall); + rev->x += reverse.x; + rev->z += reverse.z; + rev->y = 0.0f; + + col++; + } + } +} + +static f32 mCoBG_GetBGHeight_Column(const xyz_t* pos, mCoBG_UnitInfo_c* ut_info) { + mCoBG_column_c col; + + if (mCoBG_MakeOneColumnCollisionData(&col, ut_info, FALSE, NULL, -1, -1) && mCoBG_JudgePointInCircle_Xyz(pos, &col.pos, col.radius)) { + return col.height; + } + + return 0.0f; +} + +static int mCoBG_LineWallCheck_Column(xyz_t* rev, mCoBG_column_c* col, int col_count, const xyz_t* start_pos, const xyz_t* end_pos) { + int i; + xyz_t vec_end_start; + xyz_t tmp_end; + static xyz_t reverse0 = { 0.0f, 0.0f, 0.0f }; + xyz_t reverse = reverse0; + + for (i = 0; i < col_count; i++) { + f32 vec_end_start_len_xz; + + tmp_end.x = end_pos->x + reverse.x; + tmp_end.y = end_pos->y + reverse.y; + tmp_end.z = end_pos->z + reverse.z; + + reverse = reverse0; + + vec_end_start.x = start_pos->x - tmp_end.x; + vec_end_start.y = start_pos->y - tmp_end.y; + vec_end_start.z = start_pos->z - tmp_end.z; + + vec_end_start_len_xz = sqrtf(SQ(vec_end_start.x) + SQ(vec_end_start.z)); + if (!F32_IS_ZERO(vec_end_start_len_xz)) { + xyz_t cross0; + xyz_t cross1; + + if (mCoBG_JudgePointInCircle_Xyz(start_pos, &col->pos, col->radius) == FALSE && + mCoBG_GetCrossCircleAndLine2DvectorPlaneXZ_Xyz(&cross0, &cross1, start_pos, &vec_end_start, &col->pos, col->radius)) { + f32 rev_dist_xz; + xyz_t reverse_vec; + xyz_t delta_cross0_xz; + xyz_t delta_cross1_xz; + f32 dist_sq_cross0_xz; + f32 dist_sq_cross1_xz; + + delta_cross0_xz.x = cross0.x - start_pos->x; + delta_cross0_xz.z = cross0.z - start_pos->z; + delta_cross1_xz.x = cross1.x - start_pos->x; + delta_cross1_xz.z = cross1.z - start_pos->z; + dist_sq_cross0_xz = SQ(delta_cross0_xz.x) + SQ(delta_cross0_xz.z); + dist_sq_cross1_xz = SQ(delta_cross1_xz.x) + SQ(delta_cross1_xz.z); + + if (dist_sq_cross0_xz < dist_sq_cross1_xz) { + if (((cross0.x >= start_pos->x && cross0.x <= tmp_end.x) || (cross0.x >= tmp_end.x && cross0.x <= start_pos->x)) && + ((cross0.z >= start_pos->z && cross0.z <= tmp_end.z) || (cross0.z >= tmp_end.z && cross0.z <= start_pos->z)) + ) { + f32 mult; + + rev_dist_xz = vec_end_start_len_xz - sqrtf(dist_sq_cross0_xz); + mult = rev_dist_xz / vec_end_start_len_xz; + + reverse_vec.x = vec_end_start.x * mult; + reverse_vec.y = vec_end_start.y * mult; + reverse_vec.z = vec_end_start.z * mult; + if ((end_pos->y + reverse_vec.y) <= col->height) { + *rev = reverse_vec; + return TRUE; + } + } + } else { + if (((cross1.x >= start_pos->x && cross1.x <= tmp_end.x) || (cross1.x >= tmp_end.x && cross1.x <= start_pos->x)) && + ((cross1.z >= start_pos->z && cross1.z <= tmp_end.z) || (cross1.z >= tmp_end.z && cross1.z <= start_pos->z)) + ) { + f32 mult; + + rev_dist_xz = vec_end_start_len_xz - sqrtf(dist_sq_cross1_xz); + mult = rev_dist_xz / vec_end_start_len_xz; + + reverse_vec.x = vec_end_start.x * mult; + reverse_vec.y = vec_end_start.y * mult; + reverse_vec.z = vec_end_start.z * mult; + if ((end_pos->y + reverse_vec.y) <= col->height) { + *rev = reverse_vec; + return TRUE; + } + } + } + } + + col++; + } + } + + return FALSE; +} + +static int mCoBG_LineGroundCheck_Column(xyz_t* rev, mCoBG_column_c* col, int col_count, const xyz_t* start_pos, const xyz_t* end_pos) { + int i; + static xyz_t reverse0; // @BUG - isn't this supposed to be initialized with data? + xyz_t reverse; + xyz_t tmp_end; + xyz_t vec_end_start; + + reverse = reverse0; + for (i = 0; i < col_count; i++) { + if (start_pos->y > col->height && end_pos->y < col->height) { + f32 vec_y; + + tmp_end.x = end_pos->x + reverse.x; + tmp_end.y = end_pos->y + reverse.y; + tmp_end.z = end_pos->z + reverse.z; + + reverse = reverse0; + vec_end_start.x = start_pos->x - tmp_end.x; + vec_end_start.y = start_pos->y - tmp_end.y; + vec_end_start.z = start_pos->z - tmp_end.z; + + vec_y = col->height - tmp_end.y; + if (!F32_IS_ZERO(vec_end_start.y)) { + f32 mult = vec_y / vec_end_start.y; + + reverse.x = vec_end_start.x * mult; + reverse.y = vec_end_start.y * mult; + reverse.z = vec_end_start.z * mult; + *rev = reverse; + return TRUE; + } + + return FALSE; + } + + col++; + } + + return FALSE; +} diff --git a/src/AUS/game/m_collision_bg_info.c_inc b/src/AUS/game/m_collision_bg_info.c_inc new file mode 100644 index 00000000..83ef04f7 --- /dev/null +++ b/src/AUS/game/m_collision_bg_info.c_inc @@ -0,0 +1,1146 @@ +// @unused, @fabricated, size mismatch +extern void mCoBG_GetSlopeSlideVector(xyz_t* vec, xyz_t pos) { + xyz_t normal; + xyz_t v1; + f32 vec_len; + f32 mult; + + mCoBG_GetBgNorm_FromWpos(&normal, pos); + *vec = normal; + vec->y *= -1.0f; + if (vec->x != 0.0f || vec->y != 0.0f || vec->z != 0.0f) { + mult = 3.0f / sqrtf(SQ(vec->x) + SQ(vec->y) + sqrt(vec->z)); + + v1.x = vec->x * mult; + v1.y = (vec->y * 5.0f) * mult; + v1.z = vec->z * mult; + *vec = v1; + } +} + +extern f32 mCoBG_GetBgY_AngleS_FromWpos(s_xyz* ground_angle, xyz_t pos, f32 ground_dist) { + mCoBG_UnitInfo_c ut_info; + s_xyz normal_ground_angle; + f32 normal_y; + f32 column_y; + f32 move_y; + static s_xyz ground_angle0 = { 0, 0, 0 }; + + if (ground_angle != NULL) { + *ground_angle = ground_angle0; + } + + mCoBG_Wpos2UnitInfo(&ut_info, pos); + normal_y = mCoBG_GetBGHeight_Normal(&normal_ground_angle, &ut_info); + column_y = mCoBG_GetBGHeight_Column(&pos, &ut_info); + mCoBG_GetMoveBgHeight(&move_y, &pos); + + if (ground_angle != NULL && normal_y >= column_y && normal_y >= move_y) { + *ground_angle = normal_ground_angle; + return normal_y - ground_dist; + } + + return MAX(MAX(normal_y, column_y), MAX(normal_y, move_y)) - ground_dist; +} + +extern f32 mCoBG_GetBgY_OnlyCenter_FromWpos(xyz_t pos, f32 ground_dist) { + f32 y; + mCoBG_Collision_u* collision; + int ux; + int uz; + + + mFI_Wpos2UtNum(&ux, &uz, pos); + collision = mFI_UtNum2UtCol(ux, uz); + y = 10.0f * collision->data.center; + return (y + mFI_UtNum2BaseHeight(ux, uz)) - ground_dist; +} + +extern f32 mCoBG_Wpos2BgUtCenterHeight_AddColumn(xyz_t pos) { + f32 y; + mCoBG_UnitInfo_c ut_info; + mCoBG_column_c column; + + mCoBG_Wpos2UnitInfo(&ut_info, pos); + if (mCoBG_MakeOneColumnCollisionData(&column, &ut_info, FALSE, NULL, -1, -1)) { + return column.height; + } + + y = 10.0f * ut_info.collision->data.center; + return y + mFI_UtNum2BaseHeight(ut_info.ut_x, ut_info.ut_z); +} + +extern f32 mCoBG_GetBgY_OnlyCenter_FromWpos2(xyz_t pos, f32 ground_dist) { + int ux; + int uz; + + mFI_Wpos2UtNum(&ux, &uz, pos); + return (mFI_UtNum2UtKeepH(ux, uz) * 10.0f + mFI_UtNum2BaseHeight(ux, uz)) - ground_dist; +} + +extern void mCoBG_GetBgNorm_FromWpos(xyz_t* norm, xyz_t wpos) { + static xyz_t norm0 = { 0.0f, 0.0f, 0.0f }; + mCoBG_UnitInfo_c ut_info; + s16 area; + + *norm = norm0; // @unnecessary + mCoBG_Wpos2UnitInfo(&ut_info, wpos); + mCoBG_GetUnitArea(&ut_info, &area); + + switch (ut_info.collision->data.slate_flag) { + case 0: + if ( + ut_info.collision->data.center != ut_info.collision->data.top_left || + ut_info.collision->data.center != ut_info.collision->data.bot_left || + ut_info.collision->data.center != ut_info.collision->data.bot_right || + ut_info.collision->data.center != ut_info.collision->data.top_right + ) { + mCoBG_GetNormTriangle(norm, NULL, ut_info.collision, area); + norm->x *= 0.1f; + norm->y *= 0.1f; + norm->z *= 0.1f; + } else { + mCoBG_SetXyz_t(norm, 0.0f, 100.0f, 0.0f); + } + break; + case 1: + mCoBG_SetXyz_t(norm, 0.0f, 100.0f, 0.0f); + break; + default: + // this is impossible to hit because slate_flag is only 1 bit + mCoBG_SetXyz_t(norm, 0.0f, 0.0f, 0.0f); + break; + } +} + +extern int mCoBG_ScrollCheck(xyz_t start, xyz_t end, f32 radius) { + int ux; + int uz; + f32 speed[2]; + + speed[0] = end.x - start.x; + speed[1] = end.z - start.z; + + if (ABS(speed[0]) == 0.0f && ABS(speed[1]) == 0.0f) { + return FALSE; + } + + mFI_Wpos2UtNum(&ux, &uz, end); + mCoBG_MakeSizeUnitInfo(l_crtutInf, ux, uz, 3); + mCoBG_MakeUnitVector(&l_VecInf, l_crtutInf, 3, mCoBG_CHECK_TYPE_NORMAL, TRUE, TRUE, FALSE); + + { + f32 startp[2]; + f32 endp[2]; + int count = l_VecInf.unit_count; + mCoBG_unit_vec_info_c* unit_vec = l_VecInf.unit; + mCoBG_column_c* column; + int i; + + startp[0] = start.x; + startp[1] = start.z; + endp[0] = end.x; + endp[1] = end.z; + for (i = 0; i < count; i++) { + f32 dist; + + if (mCoBG_RangeCheckLinePoint(unit_vec->start, unit_vec->end, endp) && + mCoBG_GetDistPointAndLine2D_Norm(&dist, unit_vec->start, unit_vec->end, unit_vec->normal, endp) && + dist <= (radius - 0.1f)) { + return FALSE; + } + + if (mCoBG_GetCrossJudge_2Vector(startp, endp, unit_vec->start, unit_vec->end)) { + return FALSE; + } + + unit_vec++; + } + + { + mCoBG_column_c* col2; + int count; + + column = l_VecInf.column; + mCoBG_MakeColumnCollisionData(column, &l_VecInf.col_count, l_crtutInf, 3, TRUE, NULL, -1, -1); + count = l_VecInf.col_count; + if (count != 0) { + col2 = column; + for (i = 0; i < count; i++) { + f32 dx = end.x - col2->pos.x; + f32 dz = end.z - col2->pos.z; + f32 check_dist = radius + col2->radius; + f32 dist = sqrtf(SQ(dx) + SQ(dz)); + + if (dist <= check_dist) { + return FALSE; + } + + col2++; + } + } + } + } + + return TRUE; +} + +static u8 l_attribute_action_info[64] = { + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT4, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT2, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT4, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT2, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NO_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NO_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, + mCoBG_ATR_NPC | mCoBG_ATR_NO_PLACE | mCoBG_KILL_PLANT, + mCoBG_ATR_NPC | mCoBG_ATR_PLACE | mCoBG_PLANT0, +}; + +static int mCoBG_CheckPlace_OrgAttr(u32 org_attr) { + return (l_attribute_action_info[org_attr] >> 3) & 1; +} + +extern int mCoBG_CheckPlace(xyz_t pos) { + mCoBG_Collision_u* collision = mFI_GetUnitCol(pos); + u32 org_attr = collision->data.unit_attribute; + + return mCoBG_CheckPlace_OrgAttr(org_attr); +} + +// @unused, @fabricated +extern int mCoBG_UtCheckPlace(int ux, int uz) { + mCoBG_Collision_u* collision = mFI_UtNum2UtCol(ux, uz); + u32 org_attr = collision->data.unit_attribute; + + return mCoBG_CheckPlace_OrgAttr(org_attr); +} + +extern int mCoBG_Attribute2CheckPlant(u32 attr, const xyz_t* pos) { + if (mFI_GET_TYPE(mFI_GetFieldId()) == mFI_FIELDTYPE2_FG) { + u8 info = l_attribute_action_info[attr]; + u8 plant = info & 7; + + if (attr == mCoBG_ATTRIBUTE_63) { + mCoBG_Collision_u* col; + u32 new_attr; + xyz_t new_pos; + + new_pos = *pos; + new_pos.z +=mFI_UT_WORLDSIZE_Z_F; + col = mFI_GetUnitCol(new_pos); + new_attr = col->data.unit_attribute; + return mCoBG_Attribute2CheckPlant(new_attr, &new_pos); + } else { + if (plant != mCoBG_KILL_PLANT) { + return plant; + } + + return -1; + } + } + + return -1; +} + +extern int mCoBG_CheckPlant(xyz_t pos) { + mCoBG_Collision_u* collision = mFI_GetUnitCol(pos); + u32 org_attr = collision->data.unit_attribute; + + return mCoBG_Attribute2CheckPlant(org_attr, &pos); +} + +// @unused, @fabricated +extern int mCoBG_Unit2CheckNpc(int ux, int uz) { + mCoBG_Collision_u* collision = mFI_UtNum2UtCol(ux, uz); + u32 org_attr = collision->data.unit_attribute; + + return mCoBG_Attr2CheckPlaceNpc(org_attr); +} + +extern int mCoBG_Wpos2CheckNpc(xyz_t pos) { + mCoBG_Collision_u* collision = mFI_GetUnitCol(pos); + u32 org_attr = collision->data.unit_attribute; + + return mCoBG_Attr2CheckPlaceNpc(org_attr); +} + +// @unused, @fabricated +extern int mCoBG_Attr2CheckPoorGround(u32 attr) { + u8 info = l_attribute_action_info[attr]; + u8 plant = info & 7; + + if (plant == mCoBG_KILL_PLANT || plant == mCoBG_PLANT0) { + return TRUE; + } + + return FALSE; +} + +extern int mCoBG_Attr2CheckPlaceNpc(u32 attr) { + u8 info = l_attribute_action_info[attr & 0x3F]; + + return (info >> 4) & 1; +} + +extern int mCoBG_UtNum2BgAttr(int ux, int uz) { + mCoBG_Collision_u* col = mFI_UtNum2UtCol(ux, uz); + + if (col != NULL) { + return col->data.unit_attribute; + } + + return mCoBG_ATTRIBUTE_GRASS0; +} + +extern f32 mCoBG_UtNum2UtCenterY(int ux, int uz) { + f32 pos_x = (f32)ux; + f32 pos_z = (f32)uz; + xyz_t pos; + + pos.x = mFI_UT_WORLDSIZE_HALF_X_F + pos_x * mFI_UT_WORLDSIZE_X_F; + pos.y = 0.0f; + pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + pos_z * mFI_UT_WORLDSIZE_Z_F; + if (uz >= (FG_BLOCK_Z_NUM + 1) * UT_Z_NUM) { + return 40.0f; + } + + return mCoBG_GetBgY_OnlyCenter_FromWpos(pos, 0.0f); +} + +extern f32 mCoBG_UtNum2UtCenterY_Keep(int ux, int uz) { + f32 pos_x = (f32)ux; + f32 pos_z = (f32)uz; + xyz_t pos; + + pos.x = mFI_UT_WORLDSIZE_HALF_X_F + pos_x * mFI_UT_WORLDSIZE_X_F; + pos.y = 0.0f; + pos.z = mFI_UT_WORLDSIZE_HALF_Z_F + pos_z * mFI_UT_WORLDSIZE_Z_F; + return mCoBG_GetBgY_OnlyCenter_FromWpos2(pos, 0.0f); +} + +extern u32 mCoBG_Wpos2BgAttribute_Original(xyz_t pos) { + mCoBG_Collision_u* col = mFI_GetUnitCol(pos); + + return col->data.unit_attribute; +} + +static u32 mCoBG_SelectBiggerUnint(u32 a, u32 b) { + if (a > b) { + return a; + } else { + return b; + } +} + +static u32 mCoBG_SelectSmallerUnint(u32 a, u32 b) { + if (a < b) { + return a; + } else { + return b; + } +} + +static u32 mCoBG_GetMaxOffset(u32 p0, u32 p1, u32 p2, u32 p3, u32 p4) { + return mCoBG_SelectBiggerUnint( + mCoBG_SelectBiggerUnint(mCoBG_SelectBiggerUnint(p0, p1), mCoBG_SelectBiggerUnint(p2, p3)), + p4 + ); +} + +static u32 mCoBG_GetMinOffset(u32 p0, u32 p1, u32 p2, u32 p3, u32 p4) { + return mCoBG_SelectSmallerUnint( + mCoBG_SelectSmallerUnint(mCoBG_SelectSmallerUnint(p0, p1), mCoBG_SelectSmallerUnint(p2, p3)), + p4 + ); +} + +// clang-format off +static mCoBG_Collision_u mCoBG_hole_data[] = { + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 1, 2, 0, 0, 2, 0 }, + { 0, 1, 0, 2, 2, 0, 0 }, + { 0, 1, 0, 0, 2, 2, 0 }, + { 0, 1, 2, 2, 0, 0, 0 }, + { 0, 2, 2, 0, 2, 4, 0 }, + { 0, 2, 4, 2, 0, 2, 0 }, + { 0, 2, 0, 2, 4, 2, 0 }, + { 0, 2, 2, 4, 2, 0, 0 }, + { 0, 2, 2, 0, 2, 2, 0 }, + { 0, 2, 2, 2, 0, 2, 0 }, + { 0, 2, 0, 2, 2, 2, 0 }, + { 0, 2, 2, 2, 2, 0, 0 }, + { 0, 0, 0, 0, 0, 2, 0 }, + { 0, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 2, 0, 0 }, + { 0, 0, 0, 2, 0, 0, 0 }, + { 0, 1, 0, 0, 0, 2, 0 }, + { 0, 1, 2, 0, 0, 0, 0 }, + { 0, 1, 0, 0, 2, 0, 0 }, + { 0, 1, 0, 2, 0, 0, 0 }, + { 0, 1, 2, 2, 0, 2, 0 }, + { 0, 1, 2, 0, 2, 2, 0 }, + { 0, 1, 2, 2, 2, 0, 0 }, + { 0, 1, 0, 2, 2, 2, 0 }, +}; +// clang-format on + +extern int mCoBG_GetHoleNumber_ClData(mCoBG_Collision_u* col) { + mCoBG_Collision_u check_col; + int i; + u32 min; + u32 attr; + + attr = col->data.unit_attribute; + check_col = *col; + min = mCoBG_GetMinOffset(col->data.center, col->data.top_left, col->data.bot_left, col->data.bot_right, col->data.top_right); + check_col.data.center -= min; + check_col.data.bot_right -= min; + check_col.data.top_left -= min; + check_col.data.bot_left -= min; + check_col.data.top_right -= min; + + for (i = 0; i < ARRAY_COUNT(mCoBG_hole_data); i++) { + if (attr == (check_col.raw - mCoBG_hole_data[i].raw)) { + return i; + } + } + + return -1; +} + +extern int mCoBG_GetHoleNumber(xyz_t pos) { + mCoBG_Collision_u* col = mFI_GetUnitCol(pos); + + return mCoBG_GetHoleNumber_ClData(col); +} + +extern int mCoBG_BnumUnum2HoleNumber(int bx, int bz, int b_ux, int b_uz) { + int ux = bx * UT_X_NUM + b_ux; + int uz = bz * UT_Z_NUM + b_uz; + mCoBG_Collision_u* col = mFI_UtNum2UtCol(ux, uz); + + if (col != NULL) { + return mCoBG_GetHoleNumber_ClData(col); + } else { + return -1; + } +} + +extern int mCoBG_CheckHole_OrgAttr(u32 attr) { + switch (attr) { + case mCoBG_ATTRIBUTE_HOLE: + case mCoBG_ATTRIBUTE_GRASS0: + case mCoBG_ATTRIBUTE_GRASS1: + case mCoBG_ATTRIBUTE_GRASS2: + case mCoBG_ATTRIBUTE_SOIL0: + case mCoBG_ATTRIBUTE_SOIL1: + case mCoBG_ATTRIBUTE_SOIL2: + case mCoBG_ATTRIBUTE_SAND: + case mCoBG_ATTRIBUTE_25: + case mCoBG_ATTRIBUTE_26: + case mCoBG_ATTRIBUTE_36: + case mCoBG_ATTRIBUTE_43: + case mCoBG_ATTRIBUTE_44: + case mCoBG_ATTRIBUTE_45: + case mCoBG_ATTRIBUTE_46: + case mCoBG_ATTRIBUTE_59: + case mCoBG_ATTRIBUTE_60: + case mCoBG_ATTRIBUTE_61: + case mCoBG_ATTRIBUTE_62: + return TRUE; + default: + return FALSE; + } +} + +extern int mCoBG_CheckSandUt_ForFish(xyz_t* pos) { + mCoBG_Collision_u* col = mFI_GetUnitCol(*pos); + u32 attr = col->data.unit_attribute; + + switch (attr) { + case mCoBG_ATTRIBUTE_HOLE: + case mCoBG_ATTRIBUTE_SAND: + case mCoBG_ATTRIBUTE_25: + case mCoBG_ATTRIBUTE_26: + case mCoBG_ATTRIBUTE_36: + case mCoBG_ATTRIBUTE_37: + case mCoBG_ATTRIBUTE_38: + return TRUE; + default: + return FALSE; + } +} + +extern int mCoBG_CheckSandHole_ClData(mCoBG_Collision_u* col) { + u32 attr = col->data.unit_attribute; + + switch (attr) { + case mCoBG_ATTRIBUTE_HOLE: + case mCoBG_ATTRIBUTE_SAND: + case mCoBG_ATTRIBUTE_25: + case mCoBG_ATTRIBUTE_26: + case mCoBG_ATTRIBUTE_36: + return TRUE; + default: + return FALSE; + } +} + +// @unused, @fabricated +extern int mCoBG_BnumUnum2SandHole(int bx, int bz, int b_ux, int b_uz) { + int ux = bx * UT_X_NUM + b_ux; + int uz = bz * UT_Z_NUM + b_uz; + mCoBG_Collision_u* col = mFI_UtNum2UtCol(ux, uz); + + if (col != NULL) { + return mCoBG_CheckSandHole_ClData(col); + } else { + return FALSE; + } +} + +extern int mCoBG_CheckHole(xyz_t pos) { + mCoBG_Collision_u* col = mFI_GetUnitCol(pos); + u32 attr = col->data.unit_attribute; + + if (mCoBG_CheckHole_OrgAttr(attr)) { + return TRUE; + } + + if (attr == mCoBG_ATTRIBUTE_63) { + static const xyz_t area_offset_table[mCoBG_AREA_NUM] = { + { 10.0f, 0.0f, 0.0f }, + { -10.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 10.0f }, + { 0.0f, 0.0f, -10.0f }, + }; + + int i; + xyz_t center = { 0.0f, 0.0f, 0.0f }; + xyz_t check = { 0.0f, 0.0f, 0.0f }; + + // @enhancement - why are we setting the values to 0.0f when they're already initialized to 0? + center.x = 0.0f; + center.y = 0.0f; + center.z = 0.0f; + if (mFI_Wpos2UtCenterWpos(¢er, pos)) { + center.y = 0.0f; + for (i = 0; i < mCoBG_AREA_NUM; i++) { + check.x = center.x + area_offset_table[i].x; + check.y = center.y + area_offset_table[i].y; + check.z = center.z + area_offset_table[i].z; + if (mCoBG_CheckHole_OrgAttr(mCoBG_Wpos2Attribute(check, NULL)) == FALSE) { + return FALSE; + } + } + + return TRUE; + } + } + + return FALSE; +} + +extern int mCoBG_CheckSkySwing(xyz_t pos) { + mCoBG_Collision_u* col = mFI_GetUnitCol(pos); + u32 attr = col->data.unit_attribute; + + if (attr >= mCoBG_ATTRIBUTE_WAVE && attr <= mCoBG_ATTRIBUTE_RIVER_NE) { + return TRUE; + } + + if (attr == mCoBG_ATTRIBUTE_SEA || attr == mCoBG_ATTRIBUTE_37 || attr == mCoBG_ATTRIBUTE_38) { + return TRUE; + } + + if (attr >= mCoBG_ATTRIBUTE_39 && attr <= mCoBG_ATTRIBUTE_62) { + if (attr >= mCoBG_ATTRIBUTE_47 && attr <= mCoBG_ATTRIBUTE_54) { + return FALSE; + } else { + return TRUE; + } + } + + return FALSE; +} + +extern int mCoBG_CheckGrassX_ClData(mCoBG_Collision_u* col) { + u32 attr = col->data.unit_attribute; + + switch (attr) { + case mCoBG_ATTRIBUTE_GRASS3: + case mCoBG_ATTRIBUTE_47: + case mCoBG_ATTRIBUTE_48: + case mCoBG_ATTRIBUTE_49: + case mCoBG_ATTRIBUTE_50: + case mCoBG_ATTRIBUTE_51: + case mCoBG_ATTRIBUTE_52: + case mCoBG_ATTRIBUTE_53: + case mCoBG_ATTRIBUTE_54: + return TRUE; + default: + return FALSE; + } +} + +extern int mCoBG_CheckGrassX(const xyz_t* pos) { + mCoBG_Collision_u* col = mFI_GetUnitCol(*pos); + + return mCoBG_CheckGrassX_ClData(col); +} + +extern int mCoBG_CheckWave_ClData(mCoBG_Collision_u* col) { + u32 attr = col->data.unit_attribute; + + switch (attr) { + case mCoBG_ATTRIBUTE_WAVE: + case mCoBG_ATTRIBUTE_25: + case mCoBG_ATTRIBUTE_26: + case mCoBG_ATTRIBUTE_36: + case mCoBG_ATTRIBUTE_37: + case mCoBG_ATTRIBUTE_38: + return TRUE; + default: + return FALSE; + } +} + +extern int mCoBG_CheckWave(const xyz_t* pos) { + mCoBG_Collision_u* col = mFI_GetUnitCol(*pos); + + return mCoBG_CheckWave_ClData(col); +} + +extern int mCoBG_CheckAcceptDesignSign(const xyz_t* pos_p) { + int ux; + int uz; + int bx; + int bz; + + if (mFI_Wpos2BkandUtNuminBlock(&bx, &bz, &ux, &uz, *pos_p)) { + mRF_gate_c* gate; + int gate_count = 0; + u8 block_type = mFI_BkNum2BlockType(bx, bz); + int i; + int j; + int ut = uz * UT_X_NUM + ux; + + // Check location in player house block + if (bx == 3 && bz == 2) { + // check bottom center units + if ( + // clang-format off + ut == UNITXZ_2_UNIT(6, 14) || ut == UNITXZ_2_UNIT(7, 14) || ut == UNITXZ_2_UNIT(8, 14) || ut == UNITXZ_2_UNIT(9, 14) || + ut == UNITXZ_2_UNIT(6, 15) || ut == UNITXZ_2_UNIT(7, 15) || ut == UNITXZ_2_UNIT(8, 15) || ut == UNITXZ_2_UNIT(9, 15) + // clang-format on + ) { + return FALSE; + } + } else if (bx == 3 && bz == 3) { // acre directly below player house block + // check top center units + if ( + // clang-format off + ut == UNITXZ_2_UNIT(7, 0) || ut == UNITXZ_2_UNIT(8, 0) || + ut == UNITXZ_2_UNIT(7, 1) || ut == UNITXZ_2_UNIT(8, 1) || + ut == UNITXZ_2_UNIT(7, 2) || ut == UNITXZ_2_UNIT(8, 2) + // clang-format on + ) { + return FALSE; + } + } + + for (i = 0; i < mRF_DIRECT_NUM; i++) { + gate = mRF_BlockTypeDirect2GateData(&gate_count, block_type, i); + if (gate != NULL) { + for (j = 0; j < gate_count; j++) { + if (ut == gate[j].ut0 || ut == gate[j].ut1) { + return FALSE; + } + } + } + } + + if (mCoBG_CheckGrassX(pos_p) == FALSE && mCoBG_CheckWave(pos_p) == FALSE) { + return TRUE; + } + } + + return FALSE; +} + +extern f32 mCoBG_GetBgHeightGapBetweenNowDefault(xyz_t pos) { + return mCoBG_Wpos2BgUtCenterHeight_AddColumn(pos) - mCoBG_GetBgY_OnlyCenter_FromWpos2(pos, 0.0f); +} + +extern int mCoBG_ExistHeightGap_KeepAndNow(xyz_t pos) { + if ((int)mCoBG_GetBgHeightGapBetweenNowDefault(pos) != 0) { + return TRUE; + } + + return FALSE; +} + +extern int mCoBG_SearchWaterLimitDistN(xyz_t* water_pos, xyz_t pos, s16 angle, f32 dist_limit, int divide) { + static xyz_t pos0 = { 0.0f, 0.0f, 0.0f }; + static xyz_t offset[] = { + { 12.0f, 0.0f, 12.0f }, + { 12.0f, 0.0f, -12.0f }, + { -12.0f, 0.0f, -12.0f }, + { -12.0f, 0.0f, 12.0f }, + }; + + *water_pos = pos0; + pos.y = 0.0f; + if (divide >= 1) { + f32 divide_dist = dist_limit / (f32)divide; + xyz_t vec = { 0.0f, 0.0f, 1.0f }; + xyz_t search; + int i; + u32 attr; + + sMath_RotateY(&vec, SHORT2RAD_ANGLE2(angle)); + for (i = 0; i <= divide; i++) { + search.x = pos.x + vec.x * (divide_dist * i); + search.y = pos.y + vec.y * (divide_dist * i); + search.z = pos.z + vec.z * (divide_dist * i); + attr = mCoBG_Wpos2Attribute(search, NULL); + if (mCoBG_CheckWaterAttribute(attr)) { + xyz_t search2; + int j; + int water_count = 0; + + for (j = 0; j < ARRAY_COUNT(offset); j++) { + search2 = search; + search2.x += offset[j].x; + search2.z += offset[j].z; + attr = mCoBG_Wpos2Attribute(search2, NULL); + if (mCoBG_CheckWaterAttribute(attr) == FALSE) { + break; + } + + water_count++; + } + + if (water_count == ARRAY_COUNT(offset)) { + *water_pos = search; + water_pos->y = mCoBG_GetWaterHeight_File(search, __FILE__, 1137); + return TRUE; + } + + } + } + + return FALSE; + } + + return FALSE; +} + +// @unused, @fabricated +extern int mCoBG_CheckRoughPathInRoom(const xyz_t* pos) { + static xyz_t pos_offset_table[] = { + { 0.0f, 0.0f, -mFI_UT_WORLDSIZE_Z_F }, + { -mFI_UT_WORLDSIZE_X_F, 0.0f, 0.0f }, + { 0.0f, 0.0f, mFI_UT_WORLDSIZE_Z_F }, + { mFI_UT_WORLDSIZE_X_F, 0.0f, 0.0f }, + }; + + f32 y = mCoBG_GetBgY_AngleS_FromWpos(NULL, *pos, 0.0f); + f32 check_y; + xyz_t check_pos; + int i; + int p = 0; + + for (i = 0; i < 4; i++) { + check_pos.x = pos->x + pos_offset_table[i].x; + check_pos.z = pos->z + pos_offset_table[i].z; + check_y = mCoBG_GetBgY_AngleS_FromWpos(NULL, check_pos, 0.0f); + if (check_y <= y) { + p |= (1 << i); + } + } + + return p; +} + +extern f32 mCoBG_GetBalloonGroundY(const xyz_t* pos) { + mCoBG_UnitInfo_c ut_info; + s_xyz normal_ground_angle; + f32 normal_y; + u32 attr; + int bx; + int bz; + + attr = mCoBG_Wpos2Attribute(*pos, NULL); + if (mFI_Wpos2BlockNum(&bx, &bz, *pos)) { + u32 block_kind = mFI_BkNum2BlockKind(bx, bz); + + if ((block_kind & mRF_BLOCKKIND_MARINE) != 0) { + if (mCoBG_CheckWaterAttribute(attr) == TRUE || attr == mCoBG_ATTRIBUTE_WAVE || attr == mCoBG_ATTRIBUTE_SAND || attr == mCoBG_ATTRIBUTE_SEA) { + return mFI_UNIT_BASE_SIZE_F; + } + } + } + + mCoBG_Wpos2UnitInfo(&ut_info, *pos); + normal_y = mCoBG_GetBGHeight_Normal(&normal_ground_angle, &ut_info); + if (mCoBG_CheckWaterAttribute(attr)) { + return mFI_UNIT_BASE_SIZE_F + normal_y; + } + + return normal_y; +} + +extern int mCoBG_CheckAttribute_BallRolling(s16* angle, const xyz_t* pos) { + u32 attr = mCoBG_Wpos2BgAttribute_Original(*pos); + + angle[0] = -1; + angle[1] = -1; + + if (attr >= mCoBG_ATTRIBUTE_27 && attr <= mCoBG_ATTRIBUTE_62) { + int i; + int idx = attr - mCoBG_ATTRIBUTE_27; + int idx2; + + for (i = 0; i < 2; i++) { + idx2 = mCoBG_forbid_vector_idx[idx][i]; + + if (idx2 != -1) { + angle[i] = mCoBG_make_vector_table[idx2 & 7].norm_angle + DEG2SHORT_ANGLE2(180.0f); + } + } + } + + if (angle[0] != -1 || angle[1] != -1) { + return TRUE; + } + + return FALSE; +} + +static f32 mCoBG_CheckBallRollingAreaRate(const xyz_t* pos, const xyz_t* start_pos, const xyz_t* end_pos) { + f32 cross[2]; + f32 end[2]; + f32 start[2]; + f32 point[2]; + + end[0] = end_pos->x; + end[1] = end_pos->z; + start[0] = start_pos->x; + start[1] = start_pos->z; + point[0] = pos->x; + point[1] = pos->z; + + if (mCoBG_GetCrossLineAndPerpendicular(cross, end, start, point)) { + f32 dist_start_end_x = end[0] - start[0]; + f32 dist_start_end_z = end[1] - start[1]; + f32 dist_start_end = sqrtf(SQ(dist_start_end_x) + SQ(dist_start_end_z)); + f32 dist_start_cross_x = cross[0] - start[0]; + f32 dist_start_cross_z = cross[1] - start[1]; + f32 dist_start_cross = sqrtf(SQ(dist_start_cross_x) + SQ(dist_start_cross_z)); + f32 rate; + + if (F32_IS_ZERO(dist_start_end) == FALSE) { + rate = dist_start_cross / dist_start_end; + } else { + rate = -1.0f; + } + + if (mCoBG_RangeCheckLinePoint(start, end, cross) == FALSE) { + rate = -1.0f; + } + + return rate; + } + + return 1.0f; +} + +extern f32 mCoBG_CheckBallRollingArea(s16 angle, const xyz_t* pos) { + xyz_t center; + + if (angle != -1) { + if (mFI_Wpos2UtCenterWpos(¢er, *pos)) { + xyz_t pos_in_unit; + + pos_in_unit.x = pos->x - center.x; + pos_in_unit.y = pos->y - center.y; + pos_in_unit.z = pos->z - center.z; + + if (angle == DEG2SHORT_ANGLE(0.0f)) { + static xyz_t start_pos = { 0.0f, 0.0f, mFI_UT_WORLDSIZE_HALF_Z_F }; + static xyz_t end_pos = { 0.0f, 0.0f, -mFI_UT_WORLDSIZE_HALF_Z_F }; + + return mCoBG_CheckBallRollingAreaRate(&pos_in_unit, &start_pos, &end_pos); + } + + if (angle == DEG2SHORT_ANGLE(45.0f)) { + static xyz_t start_pos = { 0.0f, 0.0f, 0.0f }; + static xyz_t end_pos = { -mFI_UT_WORLDSIZE_HALF_X_F, 0.0f, 0.0f }; + + return mCoBG_CheckBallRollingAreaRate(&pos_in_unit, &start_pos, &end_pos); + } + + if (angle == DEG2SHORT_ANGLE(90.0f)) { + static xyz_t start_pos = { mFI_UT_WORLDSIZE_HALF_X_F, 0.0f, 0.0f }; + static xyz_t end_pos = { -mFI_UT_WORLDSIZE_HALF_X_F, 0.0f, 0.0f }; + + return mCoBG_CheckBallRollingAreaRate(&pos_in_unit, &start_pos, &end_pos); + } + + if (angle == DEG2SHORT_ANGLE(135.0f)) { + static xyz_t start_pos = { 0.0f, 0.0f, 0.0f }; + static xyz_t end_pos = { -mFI_UT_WORLDSIZE_HALF_X_F, 0.0f, mFI_UT_WORLDSIZE_HALF_Z_F }; + + return mCoBG_CheckBallRollingAreaRate(&pos_in_unit, &start_pos, &end_pos); + } + + if (angle == DEG2SHORT_ANGLE(-180.0f)) { + static xyz_t start_pos = { 0.0f, 0.0f, -mFI_UT_WORLDSIZE_HALF_Z_F }; + static xyz_t end_pos = { 0.0f, 0.0f, mFI_UT_WORLDSIZE_HALF_Z_F }; + + return mCoBG_CheckBallRollingAreaRate(&pos_in_unit, &start_pos, &end_pos); + } + + if (angle == DEG2SHORT_ANGLE(-135.0f)) { + static xyz_t start_pos = { 0.0f, 0.0f, 0.0f }; + static xyz_t end_pos = { -mFI_UT_WORLDSIZE_HALF_X_F, 0.0f, -mFI_UT_WORLDSIZE_HALF_Z_F }; + + return mCoBG_CheckBallRollingAreaRate(&pos_in_unit, &start_pos, &end_pos); + } + + if (angle == DEG2SHORT_ANGLE(-90.0f)) { + static xyz_t start_pos = { -mFI_UT_WORLDSIZE_HALF_X_F, 0.0f, 0.0f }; + static xyz_t end_pos = { mFI_UT_WORLDSIZE_HALF_X_F, 0.0f, 0.0f }; + + return mCoBG_CheckBallRollingAreaRate(&pos_in_unit, &start_pos, &end_pos); + } + + if (angle == DEG2SHORT_ANGLE(-45.0f)) { + static xyz_t start_pos = { 0.0f, 0.0f, 0.0f }; + static xyz_t end_pos = { mFI_UT_WORLDSIZE_HALF_X_F, 0.0f, -mFI_UT_WORLDSIZE_HALF_Z_F }; + + return mCoBG_CheckBallRollingAreaRate(&pos_in_unit, &start_pos, &end_pos); + } + } + } + + return 1.0f; +} + +extern f32 mCoBG_Wpos2GroundCheckOnly(const xyz_t* pos, f32 ground_dist) { + f32 ground_y = mCoBG_GetBgY_AngleS_FromWpos(NULL, *pos, ground_dist); + + if (pos->y < ground_y) { + return ground_y - pos->y; + } + + return 0.0f; +} + +extern int mCoBG_ExistHeightGap_KeepAndNow_Detail(xyz_t pos) { + mCoBG_UnitInfo_c ut_info; + f32 center_height; + + center_height = mCoBG_Wpos2BgUtCenterHeight_AddColumn(pos); + mCoBG_Wpos2UnitInfo(&ut_info, pos); + + if (ut_info.attribute >= mCoBG_ATTRIBUTE_27 && ut_info.attribute <= mCoBG_ATTRIBUTE_31) { + return FALSE; + } + + if (mCoBG_ExistHeightGap_KeepAndNow(pos) == FALSE) { + return FALSE; + } + + if (ut_info.slate_flag) { + xyz_t center; + xyz_t vec; + f32 corner0; + f32 corner1; + + mFI_Wpos2UtCenterWpos(¢er, pos); + xyz_t_sub(&pos, ¢er, &vec); + + corner0 = (vec.x - vec.z >= 0.0f) ? ut_info.rightUp_offset : ut_info.leftDown_offset; + corner1 = (vec.x + vec.z >= 0.0f) ? ut_info.rightDown_offset : ut_info.leftUp_offset; + if (corner0 < center_height || corner1 < center_height) { + return FALSE; + } + + } + + return TRUE; +} + +extern int mCoBG_Wpos2CheckSlateCol(const xyz_t* pos, int check_attr) { + mCoBG_Collision_u* col = mFI_GetUnitCol(*pos); + u32 attr = col->data.unit_attribute; + + if (col->data.slate_flag) { + return TRUE; + } + + if (check_attr) { + switch (attr) { + case mCoBG_ATTRIBUTE_27: + case mCoBG_ATTRIBUTE_28: + case mCoBG_ATTRIBUTE_29: + case mCoBG_ATTRIBUTE_30: + case mCoBG_ATTRIBUTE_37: + case mCoBG_ATTRIBUTE_38: + case mCoBG_ATTRIBUTE_39: + case mCoBG_ATTRIBUTE_40: + case mCoBG_ATTRIBUTE_41: + case mCoBG_ATTRIBUTE_42: + case mCoBG_ATTRIBUTE_55: + case mCoBG_ATTRIBUTE_56: + case mCoBG_ATTRIBUTE_57: + case mCoBG_ATTRIBUTE_58: + return TRUE; + default: + return FALSE; + } + } + return FALSE; +} + +extern int mCoBG_WoodSoundEffect(const xyz_t* pos) { + u32 attr = mCoBG_Wpos2BgAttribute_Original(*pos); + + switch (attr) { + case mCoBG_ATTRIBUTE_WOOD: + case mCoBG_ATTRIBUTE_27: + case mCoBG_ATTRIBUTE_28: + case mCoBG_ATTRIBUTE_29: + case mCoBG_ATTRIBUTE_30: + case mCoBG_ATTRIBUTE_31: + return TRUE; + default: + return FALSE; + } +} + +extern int mCoBG_CheckCliffAttr(u32 attr) { + if (attr >= mCoBG_ATTRIBUTE_47 && attr <= mCoBG_ATTRIBUTE_54) { + return TRUE; + } + + if (attr == mCoBG_ATTRIBUTE_55 || attr == mCoBG_ATTRIBUTE_56 || attr == mCoBG_ATTRIBUTE_57 || attr == mCoBG_ATTRIBUTE_58) { + return TRUE; + } + + return FALSE; +} + +extern f32 mCoBG_GetShadowBgY_AngleS_FromWpos(s_xyz* ground_angle, xyz_t pos, f32 ground_dist) { + mCoBG_UnitInfo_c ut_info; + s_xyz angle0 = { 0, 0, 0 }; + + mCoBG_Wpos2UnitInfo(&ut_info, pos); + if (ground_angle != NULL) { + *ground_angle = angle0; + } + + if (ut_info.collision->data.center != mFI_UtNum2UtKeepH(ut_info.ut_x, ut_info.ut_z)) { + if (ut_info.attribute >= mCoBG_ATTRIBUTE_27 && ut_info.attribute <= mCoBG_ATTRIBUTE_31) { + return mCoBG_GetBGHeight_Normal(ground_angle, &ut_info) - ground_dist; + } + + return mFI_UtNum2UtKeepH(ut_info.ut_x, ut_info.ut_z) * 10.0f + mFI_UtNum2BaseHeight(ut_info.ut_x, ut_info.ut_z) - ground_dist; + } + + return mCoBG_GetBGHeight_Normal(ground_angle, &ut_info) - ground_dist; +} + +extern int mCoBG_CheckUtFlat(const xyz_t* pos) { + mCoBG_Collision_u* col = mFI_GetUnitCol(*pos); + + // clang-format off + if ( + col->data.center == col->data.top_left && + col->data.center == col->data.bot_left && + col->data.center == col->data.bot_right && + col->data.center == col->data.top_right + ) { + return TRUE; + } + + return FALSE; +} + +extern int mCoBG_Height2GetLayer(f32 height) { + if (height < 100.0f) { + return mCoBG_LAYER0; + } else { + if (mRF_CheckFieldStep3()) { + if (height < 220.0f) { + return mCoBG_LAYER1; + } else { + return mCoBG_LAYER2; + } + } else { + return mCoBG_LAYER1; + } + } +} + +extern int mCoBG_GetLayer(const xyz_t* pos) { + return mCoBG_Height2GetLayer(mCoBG_GetBgY_OnlyCenter_FromWpos2(*pos, 0.0f)); +} diff --git a/src/AUS/game/m_collision_bg_line.c_inc b/src/AUS/game/m_collision_bg_line.c_inc new file mode 100644 index 00000000..9fa215f7 --- /dev/null +++ b/src/AUS/game/m_collision_bg_line.c_inc @@ -0,0 +1,593 @@ +static void mCoBG_GetSpeedXZ(f32* speed, xyz_t* start, xyz_t* end) { + speed[0] = end->x - start->x; + speed[1] = end->z - start->z; +} + +static void mCoBG_TransCenter(int* x, int* z, f32* speed, int ut_count) { + int count = ut_count >> 1; + + if (!F32_IS_ZERO(speed[0])) { + if (speed[0] > 0.0f) { + (*x) += count; + } else { + (*x) -= count; + } + } + + if (!F32_IS_ZERO(speed[1])) { + if (speed[1] > 0.0f) { + (*z) += count; + } else { + (*z) -= count; + } + } +} + +static int mCoBG_UvecInf2PolygonVtx(xyz_t* v0, xyz_t* v1, xyz_t* v2, int idx, mCoBG_unit_vec_info_c* unit_vec) { + switch (idx & 1) { + case 0: + if (unit_vec->wall_bounds.start_top != unit_vec->wall_bounds.start_btm) { + v0->x = unit_vec->start[0]; + v0->y = unit_vec->wall_bounds.start_top; + v0->z = unit_vec->start[1]; + + v1->x = unit_vec->start[0]; + v1->y = unit_vec->wall_bounds.start_btm; + v1->z = unit_vec->start[1]; + + v2->x = unit_vec->end[0]; + v2->y = unit_vec->wall_bounds.end_top; + v2->z = unit_vec->end[1]; + return TRUE; + } + break; + case 1: + default: + if (unit_vec->wall_bounds.end_top != unit_vec->wall_bounds.end_btm) { + v0->x = unit_vec->end[0]; + v0->y = unit_vec->wall_bounds.end_top; + v0->z = unit_vec->end[1]; + + v1->x = unit_vec->start[0]; + v1->y = unit_vec->wall_bounds.start_btm; + v1->z = unit_vec->start[1]; + + v2->x = unit_vec->end[0]; + v2->y = unit_vec->wall_bounds.end_btm; + v2->z = unit_vec->end[1]; + return TRUE; + } + break; + } + + return FALSE; +} + +static int mCoBG_GetRevWallPlaneAndVector(xyz_t* rev, mCoBG_unit_vec_info_c* unit_vec, xyz_t start_pos, xyz_t end_pos, f32* start, f32* end) { + xyz_t rev0 = { 0.0f, 0.0f, 0.0f }; + + *rev = rev0; + if (mCoBG_SearchWallFront(start, unit_vec) == TRUE && mCoBG_SearchWallFront(end, unit_vec) == FALSE) { + xyz_t v0; + xyz_t v1; + xyz_t v2; + xyz_t cross; + int i; + + for (i = 0; i < 2; i++) { + if (mCoBG_UvecInf2PolygonVtx(&v0, &v1, &v2, i, unit_vec)) { + if (mCoBG_GetCrossTriangleAndLine3D(&cross, v0, v1, v2, start_pos, end_pos)) { + rev->x = cross.x - end_pos.x; + rev->y = cross.y - end_pos.y; + rev->z = cross.z - end_pos.z; + return TRUE; + } + } + } + } + + return FALSE; +} + +static int mCoBG_LineWallCheck(xyz_t* rev, xyz_t start_pos, xyz_t end_pos) { + int i; + int count = l_VecInf.unit_count; + mCoBG_unit_vec_info_c* unit_vec = l_VecInf.unit; + f32 start[2]; + f32 end[2]; + + + start[0] = start_pos.x; + start[1] = start_pos.z; + end[0] = end_pos.x; + end[1] = end_pos.z; + for (i = 0; i < count; i++) { + xyz_t tmp_rev = { 0.0f, 0.0f, 0.0f }; + if (mCoBG_GetRevWallPlaneAndVector(&tmp_rev, unit_vec, start_pos, end_pos, start, end)) { + rev->x = tmp_rev.x; + rev->y = tmp_rev.y; + rev->z = tmp_rev.z; + return TRUE; + } + + unit_vec++; + } + + return FALSE; +} + +static void mCoBG_GetAreaPolygon(xyz_t* v0, xyz_t* v1, xyz_t* v2, mCoBG_UnitInfo_c* ut_info, int area) { + mCoBG_Collision_u* col = ut_info->collision; + f32 x = ut_info->ut_x * mFI_UT_WORLDSIZE_X_F; + f32 z = ut_info->ut_z * mFI_UT_WORLDSIZE_Z_F; + f32 center_y = col->data.center * 10.0f + ut_info->base_height; + + if (ut_info->slate_flag == FALSE) { + switch (area) { + case mCoBG_AREA_N: + v0->x = x; + v0->y = ut_info->leftUp_offset; + v0->z = z; + + v1->x = x + mFI_UT_WORLDSIZE_HALF_X_F; + v1->y = center_y; + v1->z = z + mFI_UT_WORLDSIZE_HALF_Z_F; + + v2->x = x + mFI_UT_WORLDSIZE_X_F; + v2->y = ut_info->rightUp_offset; + v2->z = z; + break; + case mCoBG_AREA_W: + v0->x = x; + v0->y = ut_info->leftUp_offset; + v0->z = z; + + v1->x = x; + v1->y = ut_info->leftDown_offset; + v1->z = z + mFI_UT_WORLDSIZE_Z_F; + + v2->x = x + mFI_UT_WORLDSIZE_HALF_X_F; + v2->y = center_y; + v2->z = z + mFI_UT_WORLDSIZE_HALF_Z_F; + break; + case mCoBG_AREA_S: + v0->x = x + mFI_UT_WORLDSIZE_HALF_X_F; + v0->y = center_y; + v0->z = z + mFI_UT_WORLDSIZE_HALF_Z_F; + + v1->x = x; + v1->y = ut_info->leftDown_offset; + v2->z = z + mFI_UT_WORLDSIZE_Z_F; + + v2->x = x + mFI_UT_WORLDSIZE_X_F; + v2->y = ut_info->rightDown_offset; + v1->z = z + mFI_UT_WORLDSIZE_Z_F; + break; + default: + // case mCoBG_AREA_E: + v0->x = x + mFI_UT_WORLDSIZE_HALF_X_F; + v0->y = center_y; + v0->z = z + mFI_UT_WORLDSIZE_HALF_Z_F; + + v1->x = x + mFI_UT_WORLDSIZE_X_F; + v1->y = ut_info->rightDown_offset; + v1->z = z + mFI_UT_WORLDSIZE_Z_F; + + v2->x = x + mFI_UT_WORLDSIZE_X_F; + v2->y = ut_info->rightUp_offset; + v2->z = z; + break; + } + } else { + switch (area) { + case mCoBG_AREA_N: + v0->x = x; + v0->y = ut_info->leftUp_offset; + v0->z = z; + + v1->x = x + mFI_UT_WORLDSIZE_HALF_X_F; + v1->y = center_y; + v1->z = z + mFI_UT_WORLDSIZE_HALF_Z_F; + + v2->x = x + mFI_UT_WORLDSIZE_X_F; + v2->y = ut_info->rightUp_offset; + v2->z = z; + + if (ut_info->leftUp_offset < ut_info->rightUp_offset) { + v0->y = v1->y; + v2->y = v1->y; + } else if (ut_info->leftUp_offset > ut_info->rightUp_offset) { + v0->y = v2->y; + v1->y = v2->y; + } + break; + case mCoBG_AREA_W: + v0->x = x; + v0->y = ut_info->leftUp_offset; + v0->z = z; + + v1->x = x; + v1->y = ut_info->leftDown_offset; + v1->z = z + mFI_UT_WORLDSIZE_Z_F; + + v2->x = x + mFI_UT_WORLDSIZE_HALF_X_F; + v2->y = center_y; + v2->z = z + mFI_UT_WORLDSIZE_HALF_Z_F; + + if (ut_info->leftUp_offset > ut_info->leftDown_offset) { + v0->y = v1->y; + // @BUG - this should be v2->y = v1->y +#ifndef BUGFXIES + v0->y = v1->y; +#else + v2->y = v1->y; +#endif + } else if (ut_info->leftUp_offset < ut_info->leftDown_offset) { + v1->y = v0->y; + v2->y = v0->y; + } + break; + case mCoBG_AREA_S: + v0->x = x + mFI_UT_WORLDSIZE_HALF_X_F; + v0->y = center_y; + v0->z = z + mFI_UT_WORLDSIZE_HALF_Z_F; + + v1->x = x; + v1->y = ut_info->leftDown_offset; + v2->z = z + mFI_UT_WORLDSIZE_Z_F; + + v2->x = x + mFI_UT_WORLDSIZE_X_F; + v2->y = ut_info->rightDown_offset; + v1->z = z + mFI_UT_WORLDSIZE_Z_F; + + if (ut_info->leftDown_offset < ut_info->rightDown_offset) { + v0->y = v1->y; + v2->y = v1->y; + } else if (ut_info->leftDown_offset > ut_info->rightDown_offset) { + v0->y = v2->y; + v1->y = v2->y; + } + + break; + // case mCoBG_AREA_E: + default: + v0->x = x + mFI_UT_WORLDSIZE_HALF_X_F; + v0->y = center_y; + v0->z = z + mFI_UT_WORLDSIZE_HALF_Z_F; + + v1->x = x + mFI_UT_WORLDSIZE_X_F; + v1->y = ut_info->rightDown_offset; + v1->z = z + mFI_UT_WORLDSIZE_Z_F; + + v2->x = x + mFI_UT_WORLDSIZE_X_F; + v2->y = ut_info->rightUp_offset; + v2->z = z; + + if (ut_info->rightUp_offset < ut_info->rightDown_offset) { + v0->y = v2->y; + v1->y = v2->y; + } else if (ut_info->rightUp_offset > ut_info->rightDown_offset) { + v0->y = v1->y; + v2->y = v1->y; + } + break; + } + } +} + +static void mCoBG_GetFlatGroundPolygon(xyz_t* v0, xyz_t* v1, xyz_t* v2, f32 bg_y, f32 x, f32 z, int type) { + static xyz_t offset_from_base[][3] = { + { { 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 40.0f}, {40.0f, 0.0f, 0.0f} }, + { {40.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 40.0f}, {40.0f, 0.0f, 40.0f} }, + }; + xyz_t* ofs = offset_from_base[type & 1]; + + v0->x = x + ofs[0].x; + v0->y = bg_y; + v0->z = z + ofs[0].z; + + v1->x = x + ofs[1].x; + v1->y = bg_y; + v1->z = z + ofs[1].z; + + v2->x = x + ofs[2].x; + v2->y = bg_y; + v2->z = z + ofs[2].z; +} + +static int mCoBG_GetRevGroundAndLine(xyz_t* rev, mCoBG_UnitInfo_c* ut_info, xyz_t start_pos, xyz_t end_pos) { + xyz_t v0; + xyz_t v1; + xyz_t v2; + xyz_t cross = { 0.0f, 0.0f, 0.0f }; + int area; + f32 a; + f32 b; + f32 c; + f32 d; + f32 dist_start; + f32 dist_end; + + if ( + // clang-format off + ut_info->collision->data.center == ut_info->collision->data.top_left && + ut_info->collision->data.center == ut_info->collision->data.bot_left && + ut_info->collision->data.center == ut_info->collision->data.bot_right && + ut_info->collision->data.center == ut_info->collision->data.top_right + // clang-format on + ) { + f32 bg_y; + f32 x; + f32 z; + int i; + + if (start_pos.y >= end_pos.y) { + bg_y = ut_info->leftUp_offset; + x = ut_info->ut_x * mFI_UT_WORLDSIZE_X_F; + z = ut_info->ut_z * mFI_UT_WORLDSIZE_Z_F; + + for (i = 0; i < 2; i++) { + mCoBG_GetFlatGroundPolygon(&v0, &v1, &v2, bg_y, x, z, i); + Math3DPlane(&v0, &v1, &v2, &a, &b, &c, &d); + + dist_start = Math3DSignedLengthPlaneAndPos(a, b, c, d, &start_pos); + dist_end = Math3DSignedLengthPlaneAndPos(a, b, c, d, &end_pos); + if (dist_start >= 0.0f && dist_end <= 0.0f) { + if (mCoBG_GetCrossTriangleAndLine3D(&cross, v0, v1, v2, start_pos, end_pos)) { + rev->x = cross.x - end_pos.x; + rev->y = cross.y - end_pos.y; + rev->z = cross.z - end_pos.z; + return TRUE; + } + } + } + } + } else { + for (area = mCoBG_AREA_N; area < mCoBG_AREA_NUM; area++) { + mCoBG_GetAreaPolygon(&v0, &v1, &v2, ut_info, area); + Math3DPlane(&v0, &v1, &v2, &a, &b, &c, &d); + + dist_start = Math3DSignedLengthPlaneAndPos(a, b, c, d, &start_pos); + dist_end = Math3DSignedLengthPlaneAndPos(a, b, c, d, &end_pos); + if (dist_start >= 0.0f && dist_end <= 0.0f) { + if (mCoBG_GetCrossTriangleAndLine3D(&cross, v0, v1, v2, start_pos, end_pos)) { + rev->x = cross.x - end_pos.x; + rev->y = cross.y - end_pos.y; + rev->z = cross.z - end_pos.z; + return TRUE; + } + } + } + } + + return FALSE; +} + +static int mCoBG_LineGroundCheck_Move(xyz_t* rev, xyz_t* start_pos, xyz_t* end_pos) { + mCoBG_bg_regist_c* regist_p; + mCoBG_mBgMgr_c* bg_mgr = &l_mBgMgr; + mCoBG_bg_regist_c** regist_pp = bg_mgr->regist_p; + xyz_t ofs; + xyz_t p0; + xyz_t p1; + xyz_t p2; + xyz_t p3; + xyz_t v0; + xyz_t v1; + xyz_t v2; + xyz_t v3; + xyz_t cross; + f32 a; + f32 b; + f32 c; + f32 d; + f32 dist_start; + f32 dist_end; + f32 start[2]; + f32 end[2]; + f32 point[2]; + int i; + mCoBG_bg_size_c* size_p; + f32 rate; + xyz_t* pos_p; + s16 angle; + + start[0] = start_pos->x; + start[1] = start_pos->z; + end[0] = end_pos->x; + end[1] = end_pos->z; + + if (bg_mgr->count != 0) { + for (i = 0; i < mCoBG_MOVE_REGIST_MAX; i++) { + regist_p = *regist_pp; // might be regist_pp[i] + + if (regist_p != NULL) { + static xyz_t xyz0 = { 0.0f, 0.0f, 0.0f }; + + size_p = regist_p->bg_size; + ofs = regist_p->base_ofs != NULL ? *regist_p->base_ofs : xyz0; + angle = regist_p->angle_y != NULL ? *regist_p->angle_y : 0; + rate = regist_p->scale_percent != NULL ? *regist_p->scale_percent : 1.0f; + pos_p = regist_p->wpos; + point[0] = pos_p->x; + point[1] = pos_p->z; + + if (mCoBG_JudgeMoveBgGroundCheck(point, start, regist_p->active_dist) || mCoBG_JudgeMoveBgGroundCheck(point, end, regist_p->active_dist)) { + Matrix_translate(pos_p->x, pos_p->y, pos_p->z, MTX_LOAD); + Matrix_RotateY(angle, MTX_MULT); + Matrix_translate(ofs.x, ofs.y, ofs.z, MTX_MULT); + + p0 = xyz0; + p1 = xyz0; + p2 = xyz0; + p3 = xyz0; + + p0.x -= size_p->left_size * rate; + p0.z -= size_p->up_size * rate; + p0.y += regist_p->height; + Matrix_Position(&p0, &v0); + + p1.x -= size_p->left_size * rate; + p1.z += size_p->down_size * rate; + p1.y += regist_p->height; + Matrix_Position(&p1, &v1); + + p2.x += size_p->right_size * rate; + p2.z += size_p->down_size * rate; + p2.y += regist_p->height; + Matrix_Position(&p2, &v2); + + p3.x += size_p->right_size * rate; + p3.z -= size_p->up_size * rate; + p3.y += regist_p->height; + Matrix_Position(&p3, &v3); + + Math3DPlane(&v0, &v1, &v2, &a, &b, &c, &d); + dist_start = Math3DSignedLengthPlaneAndPos(a, b, c, d, start_pos); + dist_end = Math3DSignedLengthPlaneAndPos(a, b, c, d, end_pos); + + if (dist_start >= 0.0f && dist_end <= 0.0f) { + if (mCoBG_GetCrossTriangleAndLine3D(&cross, v0, v1, v2, *start_pos, *end_pos)) { + rev->x = cross.x - end_pos->x; + rev->y = cross.y - end_pos->y; + rev->z = cross.z - end_pos->z; + return TRUE; + } + } + + Math3DPlane(&v0, &v2, &v3, &a, &b, &c, &d); + dist_start = Math3DSignedLengthPlaneAndPos(a, b, c, d, start_pos); + dist_end = Math3DSignedLengthPlaneAndPos(a, b, c, d, end_pos); + + if (dist_start >= 0.0f && dist_end <= 0.0f) { + if (mCoBG_GetCrossTriangleAndLine3D(&cross, v0, v2, v3, *start_pos, *end_pos)) { + rev->x = cross.x - end_pos->x; + rev->y = cross.y - end_pos->y; + rev->z = cross.z - end_pos->z; + return TRUE; + } + } + } + + regist_pp++; + } + } + } + + return FALSE; +} + +static int mCoBG_LineGroundCheck(xyz_t* rev, xyz_t start_pos, xyz_t end_pos) { + mCoBG_UnitInfo_c* ut_info = l_crtutInf; + int i; + xyz_t ground_rev = { 0.0f, 0.0f, 0.0f }; + xyz_t move_rev = { 0.0f, 0.0f, 0.0f }; + + for (i = 0; i < 9; i++) { + if (mCoBG_GetRevGroundAndLine(&ground_rev, ut_info, start_pos, end_pos)) { + *rev = ground_rev; + return TRUE; + } + + ut_info++; + } + + if (mCoBG_LineGroundCheck_Move(&move_rev, &start_pos, &end_pos)) { + *rev = move_rev; + return TRUE; + } + + return FALSE; +} + +static void mCoBG_MakeLineCheckCollisionData(xyz_t start_pos, xyz_t end_pos) { + int ux; + int uz; + f32 speed[2]; + + mCoBG_GetSpeedXZ(speed, &start_pos, &end_pos); + mFI_Wpos2UtNum(&ux, &uz, start_pos); + mCoBG_TransCenter(&ux, &uz, speed, 3); + mCoBG_MakeSizeUnitInfo(l_crtutInf, ux, uz, 3); + mCoBG_MakeUnitVector(&l_VecInf, l_crtutInf, 3, mCoBG_CHECK_TYPE_NORMAL, TRUE, FALSE, FALSE); +} + +static int mCoBG_JudgeStartLineCheck(xyz_t* rev, xyz_t start_pos, xyz_t end_pos) { + if (rev != NULL) { + mCoBG_InitRevpos(rev); + } + + if (F32_IS_ZERO(start_pos.x - end_pos.x) && F32_IS_ZERO(start_pos.y - end_pos.y) && F32_IS_ZERO(start_pos.z - end_pos.z)) { + return FALSE; + } + + return TRUE; +} + +static void mCoBG_SetWallGroundReverse(xyz_t* rev, const xyz_t* wall_rev, const xyz_t* ground_rev, const xyz_t* wall_col_rev, const xyz_t* ground_col_rev) { + if (rev != NULL) { + rev->x = wall_rev->x + ground_rev->x + wall_col_rev->x + ground_col_rev->x; + rev->y = wall_rev->y + ground_rev->y + wall_col_rev->y + ground_col_rev->y; + rev->z = wall_rev->z + ground_rev->z + wall_col_rev->z + ground_col_rev->z; + } +} + +extern int mCoBG_LineCheck_RemoveFg(xyz_t* rev, xyz_t start_pos, xyz_t end_pos, mCoBG_COLUMN_CHECK_ITEM_TYPE_PROC check_proc, int line_check_type) { + int ret = 0; + + bzero(l_crtutInf, sizeof(l_crtutInf)); + bzero(&l_VecInf, sizeof(l_VecInf)); + + if (mCoBG_JudgeStartLineCheck(rev, start_pos, end_pos)) { + xyz_t wall_rev = { 0.0f, 0.0f, 0.0f }; + xyz_t ground_rev = { 0.0f, 0.0f, 0.0f }; + xyz_t wall_col_rev = { 0.0f, 0.0f, 0.0f }; + xyz_t ground_col_rev = { 0.0f, 0.0f, 0.0f }; + + mCoBG_MakeLineCheckCollisionData(start_pos, end_pos); + mCoBG_MakeMoveBgVector(&l_VecInf, &l_mBgMgr, &end_pos, mCoBG_CHECK_TYPE_PLAYER); + mCoBG_MakeColumnCollisionData(l_VecInf.column, &l_VecInf.col_count, l_crtutInf, 3, FALSE, check_proc, -1, -1); + + if ((line_check_type & mCoBG_LINE_CHECK_WALL) != 0) { + if (mCoBG_LineWallCheck(&wall_rev, start_pos, end_pos)) { + ret |= mCoBG_LINE_CHECK_WALL; + } + mCoBG_PlusEqualPos(&end_pos, &wall_rev); + + if (mCoBG_LineWallCheck_Column(&wall_col_rev, l_VecInf.column, l_VecInf.col_count, &start_pos, &end_pos)) { + ret |= mCoBG_LINE_CHECK_WALL; + } + mCoBG_PlusEqualPos(&end_pos, &wall_col_rev); + } + + if ((line_check_type & mCoBG_LINE_CHECK_GROUND) != 0) { + if (mCoBG_LineGroundCheck(&ground_rev, start_pos, end_pos)) { + ret |= mCoBG_LINE_CHECK_GROUND; + } + mCoBG_PlusEqualPos(&end_pos, &ground_rev); + + if (mCoBG_LineGroundCheck_Column(&ground_col_rev, l_VecInf.column, l_VecInf.col_count, &start_pos, &end_pos)) { + ret |= mCoBG_LINE_CHECK_GROUND; + } + mCoBG_PlusEqualPos(&end_pos, &ground_col_rev); + } + + if ((line_check_type & mCoBG_LINE_CHECK_WATER) != 0) { + if ((end_pos.y <= 21.0f && start_pos.y >= 19.0f) || (start_pos.y <= 21.0f && end_pos.y >= 19.0f)) { + ret |= mCoBG_LINE_CHECK_WATER; + } else { + if (mCoBG_CheckWaterAttribute(mCoBG_Wpos2Attribute(end_pos, NULL))) { + f32 water_y = mCoBG_GetWaterHeight_File(end_pos, __FILE__, 880); + + if (end_pos.y <= water_y + 1.0f) { + ret |= mCoBG_LINE_CHECK_UNDERWATER; + } + } + } + } + + mCoBG_SetWallGroundReverse(rev, &wall_rev, &ground_rev, &wall_col_rev, &ground_col_rev); + } + + return ret; +} diff --git a/src/AUS/game/m_collision_bg_math.c b/src/AUS/game/m_collision_bg_math.c new file mode 100644 index 00000000..2767aaca --- /dev/null +++ b/src/AUS/game/m_collision_bg_math.c @@ -0,0 +1,457 @@ +#include "m_collision_bg.h" +#include "sys_math3d.h" + +extern void mCoBG_RotateY(f32* pos, f32 rad) { + f32 p[2]; + f32 cos; + f32 sin; + + cos = cosf_table(rad); + sin = sinf_table(rad); + p[0] = pos[0]; + p[1] = pos[1]; + + pos[0] = p[0] * cos + p[1] * sin; + pos[1] = -p[0] * sin + p[1] * cos; +} + +extern f32 mCoBG_GetVectorProductin2D(f32* vec0_xz, f32* vec1_xz) { + return vec0_xz[0] * vec1_xz[1] - vec0_xz[1] * vec1_xz[0]; +} + +static void mCoBG_JudgeCrossTriangleAndLine2D_XY(f32* m0, f32* m1, const xyz_t* v0, const xyz_t* v1, const xyz_t* v2) { + *m0 = (v0->x * v1->y - v0->y * v1->x) * (v0->x * v2->y - v0->y * v2->x); + *m1 = (v2->x * v0->y - v2->y * v0->x) * (v2->x * v1->y - v2->y * v1->x); +} + +static void mCoBG_JudgeCrossTriangleAndLine2D_XZ(f32* m0, f32* m1, const xyz_t* v0, const xyz_t* v1, const xyz_t* v2) { + *m0 = (v0->x * v1->z - v0->z * v1->x) * (v0->x * v2->z - v0->z * v2->x); + *m1 = (v2->x * v0->z - v2->z * v0->x) * (v2->x * v1->z - v2->z * v1->x); +} + +static void mCoBG_JudgeCrossTriangleAndLine2D_YZ(f32* m0, f32* m1, const xyz_t* v0, const xyz_t* v1, const xyz_t* v2) { + *m0 = (v0->y * v1->z - v0->z * v1->y) * (v0->y * v2->z - v0->z * v2->y); + *m1 = (v2->y * v0->z - v2->z * v0->y) * (v2->y * v1->z - v2->z * v1->y); +} + +typedef void (*mCoBG_PRO_DIMENSION_PROC)(f32* m0, f32* m1, const xyz_t* v0, const xyz_t* v1, const xyz_t* v2); + +static mCoBG_PRO_DIMENSION_PROC mCoBG_pro_dimension_proc[] = { + &mCoBG_JudgeCrossTriangleAndLine2D_XY, + &mCoBG_JudgeCrossTriangleAndLine2D_XZ, + &mCoBG_JudgeCrossTriangleAndLine2D_YZ, + NULL, +}; + +extern int mCoBG_JudgeCrossTriangleAndLine2D(xyz_t v0, xyz_t v1, xyz_t v2, xyz_t p, int dim) { + xyz_t vec0; + xyz_t vec1; + xyz_t vec2; + + vec0.x = v0.x - p.x; + vec0.y = v0.y - p.y; + vec0.z = v0.z - p.z; + + vec1.x = v1.x - p.x; + vec1.y = v1.y - p.y; + vec1.z = v1.z - p.z; + + vec2.x = v2.x - p.x; + vec2.y = v2.y - p.y; + vec2.z = v2.z - p.z; + + // Doesn't this mean the mCoBG_DIM_ALL path can never be hit? + if (CLAMP(dim, 0, dim) > mCoBG_DIM_YZ) { + dim = mCoBG_DIM_YZ; + } else { + dim = CLAMP(dim, 0, dim); + } + + if (dim == mCoBG_DIM_ALL) { + f32 m0; + f32 m1; + + (*mCoBG_pro_dimension_proc[mCoBG_DIM_XZ])(&m0, &m1, &vec0, &vec1, &vec2); + if (m0 <= 0.0f && m1 <= 0.0f) { + (*mCoBG_pro_dimension_proc[mCoBG_DIM_XY])(&m0, &m1, &vec0, &vec1, &vec2); + if (m0 <= 0.0f && m1 <= 0.0f) { + (*mCoBG_pro_dimension_proc[mCoBG_DIM_YZ])(&m0, &m1, &vec0, &vec1, &vec2); + if (m0 <= 0.0f && m1 <= 0.0f) { + return TRUE; + } + } + } + } else { + f32 m0 = 0.0f; + f32 m1 = 0.0f; + + (*mCoBG_pro_dimension_proc[dim])(&m0, &m1, &vec0, &vec1, &vec2); + if (m0 <= 0.0f && m1 <= 0.0f) { + return TRUE; + } + } + + return FALSE; +} + +extern int mCoBG_GetDimension2Idx(f32 p0, f32 p1, f32 p2) { + if (F32_IS_ZERO(p0) && F32_IS_ZERO(p2)) { + return mCoBG_DIM_XZ; + } + + if (F32_IS_ZERO(p0) && F32_IS_ZERO(p1)) { + return mCoBG_DIM_XY; + } + + if (F32_IS_ZERO(p1) && F32_IS_ZERO(p2)) { + return mCoBG_DIM_YZ; + } + + return mCoBG_DIM_ALL; +} + +extern int mCoBG_GetCrossTriangleAndLine3D(xyz_t* cross, xyz_t v0, xyz_t v1, xyz_t v2, xyz_t line0, xyz_t line1) { + f32 x; + f32 y; + f32 z; + f32 nox; + f32 noy; + f32 noz; + f32 dist; + f32 ldist; + f32 t; + f32 scale; + + cross->x = 0.0f; + cross->y = 0.0f; + cross->z = 0.0f; + + Math3DPlane(&v0, &v1, &v2, &nox, &noy, &noz, &dist); + t = (nox * line0.x + noy * line0.y + noz * line0.z) + dist; + x = line0.x - line1.x; + y = line0.y - line1.y; + z = line0.z - line1.z; + ldist = nox * x + noy * y + noz * z; + if (!F32_IS_ZERO(ldist)) { + int dim; + + scale = -(t / ldist); + cross->x = line0.x + x * scale; + cross->y = line0.y + y * scale; + cross->z = line0.z + z * scale; + dim = mCoBG_GetDimension2Idx(nox, noy, noz); + return mCoBG_JudgeCrossTriangleAndLine2D(v0, v1, v2, *cross, dim); + } + + return FALSE; +} + +extern f32 mCoBG_GetVectorScalar2D(f32* v0, f32* v1) { + return v0[0] * v1[0] + v0[1] * v1[1]; +} + +extern int mCoBG_GetCrossJudge_2Vector(f32* vec0_p0, f32* vec0_p1, f32* vec1_p0, f32* vec1_p1) { + f32 v0[2]; + f32 v1[2]; + f32 v2[2]; + f32 product0; + f32 product1; + + v0[0] = vec1_p1[0] - vec0_p0[0]; + v0[1] = vec1_p1[1] - vec0_p0[1]; + v1[0] = vec0_p1[0] - vec0_p0[0]; + v1[1] = vec0_p1[1] - vec0_p0[1]; + v2[0] = vec1_p0[0] - vec0_p0[0]; + v2[1] = vec1_p0[1] - vec0_p0[1]; + product0 = mCoBG_GetVectorProductin2D(v1, v0) * mCoBG_GetVectorProductin2D(v1, v2); + + v0[0] = vec0_p1[0] - vec1_p0[0]; + v0[1] = vec0_p1[1] - vec1_p0[1]; + v1[0] = vec1_p1[0] - vec1_p0[0]; + v1[1] = vec1_p1[1] - vec1_p0[1]; + v2[0] = vec0_p0[0] - vec1_p0[0]; + v2[1] = vec0_p0[1] - vec1_p0[1]; + product1 = mCoBG_GetVectorProductin2D(v1, v0) * mCoBG_GetVectorProductin2D(v1, v2); + + if (product0 < 0.0f && product1 < 0.0f) { + return TRUE; + } + + return FALSE; +} + +extern void mCoBG_GetCross2Line(f32* cross, + f32* line0_p0, + f32* line0_p1, + f32* line1_p0, + f32* line1_p1) +{ + f32 t; + f32 vec[2]; + + vec[0] = line0_p1[0] - line0_p0[0]; + vec[1] = line0_p1[1] - line0_p0[1]; + + t = + ( + ( ( line1_p0[0] - line0_p0[0] ) * ( line1_p1[1] - line1_p0[1] ) ) + + ( ( line1_p1[0] - line1_p0[0] ) * ( line0_p0[1] - line1_p0[1] ) ) + ) + / + ( + ( (line1_p1[1] - line1_p0[1]) * ( line0_p1[0] - line0_p0[0] ) ) - + ( (line0_p1[1] - line0_p0[1]) * ( line1_p1[0] - line1_p0[0] ) ) + ); + + cross[0] = line0_p0[0] + t * vec[0]; + cross[1] = line0_p0[1] + t * vec[1]; +} + +extern f32 mCoBG_Get2VectorAngleF(f32* v0, f32* v1, u8 unit) { + if (v0[0] != 0.0f || v0[1] != 0.0f || v1[0] != 0.0f || v1[1] != 0.0f) { + switch (unit) { + case mCoBG_UNIT_RADIAN: + return atanf_table(mCoBG_GetVectorScalar2D(v0, v1), mCoBG_GetVectorProductin2D(v0, v1)); + case mCoBG_UNIT_DEGREE: + return RAD2DEG(atanf_table(mCoBG_GetVectorScalar2D(v0, v1), mCoBG_GetVectorProductin2D(v0, v1))); + default: + return 1.0f; + } + } + + return 1.0f; +} + +// @unused, @fabricated +extern s16 mCoBG_Get2VectorAngleS(f32* v0, f32* v1) { + if (v0[0] != 0.0f || v0[1] != 0.0f || v1[0] != 0.0f || v1[1] != 0.0f) { + return atans_table(mCoBG_GetVectorScalar2D(v0, v1), mCoBG_GetVectorProductin2D(v0, v1)); + } + + return 1; +} + +extern int mCoBG_GetCrossLineAndPerpendicular(f32* cross, f32* p0, f32* p1, f32* target) { + f32 vec[2]; + f32 len; + f32 t; + + vec[0] = p1[0] - p0[0]; + vec[1] = p1[1] - p0[1]; + len = SQ(vec[0]) + SQ(vec[1]); + if (len != 0.0f) { + t = (-vec[0] * (p0[0] - target[0]) + -vec[1] * (p0[1] - target[1])) / len; + cross[0] = p0[0] + t * vec[0]; + cross[1] = p0[1] + t * vec[1]; + return TRUE; + } + + cross[0] = 0.0f; + cross[1] = 0.0f; + return FALSE; +} + +extern int mCoBG_GetPointInfoFrontLine(f32* start, f32* point, f32* normal) { + f32 a = normal[0]; + f32 b = normal[1]; + f32 a2 = a * point[0]; + f32 b2 = b * point[1]; + f32 c = -(a * start[0] + b * start[1]); + + if ((a2 + b2) + c >= 0.0f) { + return TRUE; + } + + return FALSE; +} + +/* @unused, @fabricated */ +extern int mCoBG_GetDistPointAndLine2D(f32* dist, f32* line0, f32* line1, f32* point) { + f32 cross[2]; + f32 dist_xy[2]; + + if (mCoBG_GetCrossLineAndPerpendicular(cross, line0, line1, point)) { + dist_xy[0] = point[0] - cross[0]; + dist_xy[1] = point[1] - cross[1]; + + dist[0] = ABS(sqrtf(SQ(dist_xy[0]) + SQ(dist_xy[1]))); + return TRUE; + } + + dist[0] = 0.0f; + dist[1] = 0.0f; + return FALSE; +} + +extern int mCoBG_GetDistPointAndLine2D_Norm(f32* dist, f32* line0, f32* line1, f32* normal, f32* point) { + f32 a = normal[0]; + f32 b = normal[1]; + f32 a2 = a * point[0]; + f32 b2 = b * point[1]; + f32 c = -(a * line0[0] + b * line0[1]); + f32 d = (a2 + b2) + c; + + dist[0] = ABS(d); + return TRUE; +} + +extern int mCoBG_GetCrossCircleAndLine2Dvector(f32* cross0, f32* cross1, f32* point, f32* vec, f32* center, f32 radius) { + // a = x^2 + y^2 + f32 A = SQ(vec[0]) + SQ(vec[1]); + // b = 2 * ((vec.x * point.x) - (vec.x * center.x)) + ((vec.y * point.y) - (vec.y * center.y)) + f32 B = 2.0f * (vec[0] * point[0] - vec[0] * center[0] + vec[1] * point[1] - vec[1] * center[1]); + // c = (point.x - center.x)^2 + (point.y - center.y)^2 - radius^2 + f32 C = SQ(point[0] - center[0]) + SQ(point[1] - center[1]) - SQ(radius); + f32 R = SQ(B) - 4.0f*A*C; // b^2 - 4*a*c + f32 t0; + f32 t1; + + if (R >= 0.0f) { + // sqrt(b^2 - 4*a*c) + f32 root = ABS(sqrtf(R)); + + if (A != 0.0f) { + // (-b +- sqrt(b^2 - 4*a*c)) / 2a + t0 = (-B + root) / (2.0f * A); + t1 = (-B - root) / (2.0f * A); + + cross0[0] = point[0] + t0 * vec[0]; + cross0[1] = point[1] + t0 * vec[1]; + cross1[0] = point[0] + t1 * vec[0]; + cross1[1] = point[1] + t1 * vec[1]; + return TRUE; + } + } + + return FALSE; +} + +extern int mCoBG_GetCrossCircleAndLine2DvectorPlaneXZ_Xyz(xyz_t* cross1, xyz_t* cross2, const xyz_t* point, const xyz_t* vec, const xyz_t* center, f32 radius) { + static xyz_t cross0 = { 0.0f, 0.0f, 0.0f }; + f32 cross1_xz[2]; + f32 cross2_xz[2]; + f32 point_xz[2]; + f32 vec_xz[2]; + f32 center_xz[2]; + + *cross1 = cross0; + *cross2 = cross0; + + point_xz[0] = point->x; + point_xz[1] = point->z; + vec_xz[0] = vec->x; + vec_xz[1] = vec->z; + center_xz[0] = center->x; + center_xz[1] = center->z; + + if (mCoBG_GetCrossCircleAndLine2Dvector(cross1_xz, cross2_xz, point_xz, vec_xz, center_xz, radius)) { + cross1->x = cross1_xz[0]; + cross1->z = cross1_xz[1]; + cross2->x = cross2_xz[0]; + cross2->z = cross2_xz[1]; + return TRUE; + } + + return FALSE; +} + +// @unused, @fabricated +extern int mCoBG_GetCrossCircleAndLine2D(f32* cross0, f32* cross1, f32* p0, f32* p1, f32* center, f32 radius) { + f32 vec[2]; + + vec[0] = p1[0] - p0[0]; + vec[1] = p1[1] - p0[1]; + return mCoBG_GetCrossCircleAndLine2Dvector(cross0, cross1, p0, vec, center, radius); +} + +// @unused, @fabricated +extern void mCoBG_GetReverseVector2D(f32* vec) { + vec[0] *= -1.0f; + vec[1] *= -1.0f; +} + +// @unused, @fabricated +extern void mCoBG_GetUnitVector2D(f32* vec) { + f32 len = sqrtf(SQ(vec[0]) + SQ(vec[1])); + + if (!F32_IS_ZERO(len)) { + vec[0] /= len; + vec[1] /= len; + } +} + +extern int mCoBG_JudgePointInCircle_Xyz(const xyz_t* p, const xyz_t* center, f32 radius) { + f32 dx = p->x - center->x; + f32 dz = p->z - center->z; + + if (SQ(dx) + SQ(dz) <= SQ(radius)) { + return TRUE; + } + + return FALSE; +} + +extern int mCoBG_JudgePointInCircle(f32* p, f32* center, f32 radius) { + f32 dx = p[0] - center[0]; + f32 dz = p[1] - center[1]; + + if (SQ(dx) + SQ(dz) <= SQ(radius)) { + return TRUE; + } + + return FALSE; +} + +// @unused, @fabricated +extern f32 mCoBG_GetAbsBiggerF(f32 a, f32 b) { + if (ABS(a) > ABS(b)) { + return a; + } else { + return b; + } +} + +static void mCoBG_GetDeffVec(f32* v0, f32* v1, f32* v2, f32* vec0, f32* vec1) { + vec0[0] = v0[0] - v1[0]; + vec1[0] = v1[0] - v2[0]; + vec0[1] = v0[1] - v1[1]; + vec1[1] = v1[1] - v2[1]; + vec0[2] = v0[2] - v1[2]; + vec1[2] = v1[2] - v2[2]; +} + +extern void mCoBG_GetNorm_By2Vector(f32* v0, f32* v1, xyz_t* normal) { + if (normal != NULL) { + normal->x = v0[1] * v1[2] - v0[2] * v1[1]; + normal->y = v0[2] * v1[0] - v0[0] * v1[2]; + normal->z = v0[0] * v1[1] - v0[1] * v1[0]; + } +} + +extern void mCoBG_GetNorm_By3Point(xyz_t* normal, f32* v0, f32* v1, f32* v2) { + static f32 vec1[3]; + static f32 vec2[3]; + + if (normal != NULL) { + mCoBG_GetDeffVec(v0, v1, v2, vec1, vec2); + mCoBG_GetNorm_By2Vector(vec1, vec2, normal); + } +} + +extern int mCoBG_RangeCheckLinePoint(f32* start, f32* end, f32* point) { + f32 normal01[2]; + + normal01[0] = end[0] - start[0]; + normal01[1] = end[1] - start[1]; + if (mCoBG_GetPointInfoFrontLine(start, point, normal01)) { + f32 normal10[2]; + + normal10[0] = start[0] - end[0]; + normal10[1] = start[1] - end[1]; + if (mCoBG_GetPointInfoFrontLine(end, point, normal10)) { + return TRUE; + } + } + + return FALSE; +} diff --git a/src/AUS/game/m_collision_bg_move.c_inc b/src/AUS/game/m_collision_bg_move.c_inc new file mode 100644 index 00000000..75e11199 --- /dev/null +++ b/src/AUS/game/m_collision_bg_move.c_inc @@ -0,0 +1,496 @@ +static mCoBG_bg_size_c mCoBG_mBgDataA = { 20.0f, 20.0f, 20.0f, 20.0f }; +static mCoBG_bg_size_c mCoBG_mBgDataB_0 = { 60.0f, 20.0f, 20.0f, 20.0f }; +static mCoBG_bg_size_c mCoBG_mBgDataB_180 = { 20.0f, 60.0f, 20.0f, 20.0f }; +static mCoBG_bg_size_c mCoBG_mBgDataB_270 = { 20.0f, 20.0f, 20.0f, 60.0f }; +static mCoBG_bg_size_c mCoBG_mBgDataB_90 = { 20.0f, 20.0f, 60.0f, 20.0f }; +static mCoBG_bg_size_c mCoBG_mBgDataC = { 40.0f, 40.0f, 40.0f, 40.0f }; + +static mCoBG_bg_size_c* mCoBG_mBg_data[] = { + &mCoBG_mBgDataA, &mCoBG_mBgDataB_0, &mCoBG_mBgDataB_180, &mCoBG_mBgDataB_270, &mCoBG_mBgDataB_90, &mCoBG_mBgDataC, +}; + +extern int mCoBG_JudgeMoveBgGroundCheck(f32* point, f32* goal, f32 dist) { + f32 delta[2]; + + delta[0] = ABS(point[0] - goal[0]); + delta[1] = ABS(point[1] - goal[1]); + if (delta[0] < dist && delta[1] < dist) { + return TRUE; + } + + return FALSE; +} + +static void mCoBG_SetLinePos(f32* line, f32 x, f32 z) { + line[0] = x; + line[1] = z; +} + +static void mCoBG_PlusLinePos(f32* line, f32 x, f32 z) { + line[0] += x; + line[1] += z; +} + +static void mCoBG_PlusEqualPos(xyz_t* p0, xyz_t* p1) { + p0->x += p1->x; + p0->y += p1->y; + p0->z += p1->z; +} + +extern int mCoBG_GetMoveBgHeight(f32* move_bg_height, xyz_t* pos_p) { + mCoBG_mBgMgr_c* bg_mgr = &l_mBgMgr; + mCoBG_bg_regist_c* regist_p; + xyz_t* wpos; + mCoBG_bg_regist_c** regist_pp = bg_mgr->regist_p; + f32 pos[2]; + int i; + f32 left; + f32 right; + f32 up; + f32 down; + int move_bg_idx = -1; + xyz_t* base_ofs; + mCoBG_bg_size_c* size_p; + f32 base[2]; + f32 angleY_rad; + f32 rate; + + *move_bg_height = -500.0f; + pos[0] = pos_p->x; + pos[1] = pos_p->z; + if (bg_mgr->count != 0) { + for (i = 0; i < mCoBG_MOVE_REGIST_MAX; i++) { + regist_p = *regist_pp; + if (regist_p != NULL) { + wpos = regist_p->wpos; + size_p = regist_p->bg_size; + base_ofs = regist_p->base_ofs; + base[0] = wpos->x; + base[1] = wpos->z; + + if (mCoBG_JudgeMoveBgGroundCheck(base, pos, regist_p->active_dist)) { + f32 leftUp_pos[2]; + f32 leftDown_pos[2]; + f32 rightDown_pos[2]; + + angleY_rad = SHORT2RAD_ANGLE2(*regist_p->angle_y); + rate = regist_p->scale_percent != NULL ? *regist_p->scale_percent : 1.0f; + left = size_p->left_size * rate; + right = size_p->right_size * rate; + up = size_p->up_size * rate; + down = size_p->down_size * rate; + + mCoBG_SetLinePos(leftUp_pos, -left, -up); + mCoBG_SetLinePos(leftDown_pos, -left, down); + mCoBG_SetLinePos(rightDown_pos, right, down); + if (base_ofs != NULL) { + mCoBG_PlusLinePos(leftUp_pos, base_ofs->x, base_ofs->z); + mCoBG_PlusLinePos(leftDown_pos, base_ofs->x, base_ofs->z); + mCoBG_PlusLinePos(rightDown_pos, base_ofs->x, base_ofs->z); + } + + if (angleY_rad != 0.0f) { + mCoBG_RotateY(leftUp_pos, angleY_rad); + mCoBG_RotateY(leftDown_pos, angleY_rad); + mCoBG_RotateY(rightDown_pos, angleY_rad); + } + + mCoBG_PlusLinePos(leftUp_pos, wpos->x, wpos->z); + mCoBG_PlusLinePos(leftDown_pos, wpos->x, wpos->z); + mCoBG_PlusLinePos(rightDown_pos, wpos->x, wpos->z); + + if (mCoBG_RangeCheckLinePoint(leftUp_pos, leftDown_pos, pos) && + mCoBG_RangeCheckLinePoint(leftDown_pos, rightDown_pos, pos)) { + *move_bg_height = wpos->y + regist_p->height; + move_bg_idx = i; + } + } + } + + regist_pp++; + } + } + + return move_bg_idx; +} + +// @unused, @fabricated +extern void mCoBG_InitMoveBgContact(mCoBG_bg_contact_c* contact) { + bzero(contact, sizeof(mCoBG_bg_contact_c)); + bzero(&l_VecInf, sizeof(mCoBG_vec_info_c)); + bzero(&l_ActorInf, sizeof(mCoBG_ActorInf_c)); + bzero(&l_mBgMgr, sizeof(mCoBG_mBgMgr_c)); +} + +extern int mCoBG_RegistMoveBg(mCoBG_bg_regist_c* regist, xyz_t* wpos, xyz_t* old_wpos, s16* angleY, f32 height, + mCoBG_bg_size_c* size, f32* scale_percent, mCoBG_bg_contact_c* contact, xyz_t* base_ofs, + int type, u32 attribute, f32 check_dist) { + mCoBG_mBgMgr_c* bg_mgr = &l_mBgMgr; + mCoBG_bg_regist_c** regist_pp = bg_mgr->regist_p; + int i; + + if (bg_mgr->count < mCoBG_MOVE_REGIST_MAX) { + for (i = 0; i < mCoBG_MOVE_REGIST_MAX; i++) { + if (regist_pp[i] == NULL) { + regist_pp[i] = regist; + if (type == mCoBG_FTR_TYPE_NUM) { + regist_pp[i]->bg_size = size; + } else { + regist_pp[i]->bg_size = mCoBG_mBg_data[type]; + } + + regist_pp[i]->height = height; + regist_pp[i]->base_ofs = base_ofs; + regist_pp[i]->contact = contact; + regist_pp[i]->wpos = wpos; + regist_pp[i]->last_wpos = old_wpos; + regist_pp[i]->angle_y = angleY; + regist_pp[i]->attribute = attribute; + regist_pp[i]->active_dist = check_dist; + regist_pp[i]->scale_percent = scale_percent; + if (regist_pp[i]->contact != NULL) { + bzero(regist_pp[i]->contact, sizeof(mCoBG_bg_contact_c)); + } + + bg_mgr->count++; + return i; + } + } + } + + return -1; +} + +extern mCoBG_bg_regist_c* mCoBG_Idx2RegistPointer(int move_bg_idx) { + mCoBG_mBgMgr_c* bg_mgr = &l_mBgMgr; + mCoBG_bg_regist_c** regist_pp = bg_mgr->regist_p; + + if (bg_mgr->count != 0 && move_bg_idx >= 0 && move_bg_idx < mCoBG_MOVE_REGIST_MAX) { + return regist_pp[move_bg_idx]; + } + + return NULL; +} + +extern void mCoBG_CrossOffMoveBg(int move_bg_idx) { + mCoBG_mBgMgr_c* bg_mgr = &l_mBgMgr; + mCoBG_bg_regist_c** regist_pp = bg_mgr->regist_p; + + if (move_bg_idx > -1 && move_bg_idx < mCoBG_MOVE_REGIST_MAX && bg_mgr->count != 0 && + move_bg_idx < mCoBG_MOVE_REGIST_MAX) { + if (regist_pp[move_bg_idx] != NULL) { + bzero(regist_pp[move_bg_idx], sizeof(mCoBG_bg_regist_c)); + regist_pp[move_bg_idx] = NULL; + bg_mgr->count--; + } + } +} + +extern void mCoBG_InitMoveBgData(void) { + mCoBG_mBgMgr_c* bg_mgr = &l_mBgMgr; + mCoBG_bg_regist_c** regist_pp = bg_mgr->regist_p; + int i; + + bg_mgr->count = 0; + for (i = 0; i < mCoBG_MOVE_REGIST_MAX; i++) { + regist_pp[i] = NULL; + } +} + +static void mCoBG_SetBaseOffset(f32* start, f32* end, xyz_t* base_ofs) { + if (base_ofs != NULL) { + mCoBG_PlusLinePos(start, base_ofs->x, base_ofs->z); + mCoBG_PlusLinePos(end, base_ofs->x, base_ofs->z); + } +} + +static void mCoBG_MakeCommonData(mCoBG_unit_vec_info_c* unit_vec, mCoBG_bg_regist_c* regist) { + unit_vec->regist_p = regist; + unit_vec->atr_wall = FALSE; +} + +static f32 norm_up[2] = { 0.0f, -1.0f }; +static f32 norm_lt[2] = { -1.0f, 0.0f }; +static f32 norm_dn[2] = { 0.0f, 1.0f }; +static f32 norm_rt[2] = { 1.0f, 0.0f }; +static f32* norm_table[4] = { norm_up, norm_lt, norm_dn, norm_rt }; + +static void mCoBG_GetNorm(f32* norm, int direct) { + f32* np = norm_table[direct & 3]; + + norm[0] = np[0]; + norm[1] = np[1]; +} + +static void mCoBG_SetMoveBgHeightInf(mCoBG_WallBounds_c* bounds, xyz_t* pos, f32 height) { + bounds->start_top = pos->y + height; + bounds->start_btm = pos->y; + bounds->end_top = bounds->start_top; + bounds->end_btm = pos->y; +} + +static void mCoBG_SetMoveBgContactSide(mCoBG_bg_regist_c* regist, ACTOR* actorx, s16 angle) { + mCoBG_bg_contact_c* contact = regist->contact; + + if (contact != NULL) { + mCoBG_side_contact_c* side_contact = contact->side_contact; + int* count = &contact->side_count; + + if (*count < 5) { + side_contact[*count].name = actorx->id; + side_contact[*count].angle = angle; + (*count)++; + } + } +} + +static void mCoBG_SetMoveBgContactOn(mCoBG_bg_regist_c* regist, ACTOR* actorx) { + mCoBG_bg_contact_c* contact = regist->contact; + + if (contact != NULL) { + mCoBG_on_contact_info_c* info = &contact->on_contact; + mCoBG_on_contact_c* on_contact = info->contact; + int* count = &info->count; + + if (*count < 5) { + on_contact[*count].name = actorx->id; + (*count)++; + } + } +} + +static void mCoBG_MoveBgGroundCheck(xyz_t* rev, mCoBG_ActorInf_c* actor_info, ACTOR* actorx, + mCoBG_CheckResult_c* result, s_xyz* angle) { + f32 height = -500.0f; + f32 dist = actor_info->ground_dist; + xyz_t pos; + int on_move_bg_idx; + + pos.x = actorx->world.position.x + rev->x; + pos.y = 0.0f; + pos.z = actorx->world.position.z + rev->z; + if (actorx->id != mAc_PROFILE_GYOEI) { + on_move_bg_idx = mCoBG_GetMoveBgHeight(&height, &pos); + if (on_move_bg_idx != -1 && (actorx->world.position.y + dist + rev->y) <= height) { + mCoBG_bg_regist_c* on_regist = mCoBG_Idx2RegistPointer(on_move_bg_idx); + + if (on_regist != NULL) { + s_xyz angle0 = { 0, 0, 0 }; + + rev->y = (height - dist) - actorx->world.position.y; + *angle = angle0; + result->on_ground = TRUE; + result->is_on_move_bg_obj = TRUE; + result->unit_attribute = on_regist->attribute; + actorx->shape_info.move_bg_idx = on_move_bg_idx; + actorx->position_speed.y = 0.0f; + mCoBG_SetMoveBgContactOn(on_regist, actorx); + } + } + } +} + +static void mCoBG_RotateMoveBgCollisionData(mCoBG_unit_vec_info_c* unit_vec, f32 rad) { + f32* normal = unit_vec->normal; + f32* start = unit_vec->start; + f32* end = unit_vec->end; + + if (ABS(RAD2DEG(rad)) >= 0.05f) { + mCoBG_RotateY(normal, rad); + mCoBG_RotateY(start, rad); + mCoBG_RotateY(end, rad); + } +} + +static void mCoBG_SizeData2CollisionData(mCoBG_bg_regist_c* regist, mCoBG_vec_info_c* vec_info, u8 check_type, + int move_bg_idx) { + int* unit_count_p; + mCoBG_unit_vec_info_c* unit_vec; + xyz_t pos; + f32* start; + f32* end; + f32* normal; + mCoBG_WallBounds_c* bounds; + mCoBG_unit_vec_info_c* ut_vec_p; + s16 angleY; + f32 angleY_rad; + f32 height; + xyz_t* base_ofs; + mCoBG_bg_size_c* size; + mCoBG_tab_c tab_data; + f32 rate; + + unit_count_p = &vec_info->unit_count; + unit_vec = vec_info->unit; + pos = *regist->wpos; + angleY = *regist->angle_y; + angleY_rad = SHORT2RAD_ANGLE2(angleY); + height = regist->height; + base_ofs = regist->base_ofs; + size = regist->bg_size; + tab_data = mCoBG_tab_data[check_type]; + rate = 1.0f; + + if (regist->scale_percent != NULL) { + rate = *regist->scale_percent; + } + + if (*unit_count_p < mCoBG_UNIT_VEC_INFO_MAX) { + ut_vec_p = &unit_vec[*unit_count_p]; + start = ut_vec_p->start; + end = ut_vec_p->end; + normal = ut_vec_p->normal; + bounds = &ut_vec_p->wall_bounds; + + mCoBG_SetLinePos(start, -(size->left_size * rate) - tab_data.t0, -(size->up_size * rate)); + mCoBG_SetLinePos(end, (size->right_size * rate) + tab_data.t0, -(size->up_size * rate)); + mCoBG_SetBaseOffset(start, end, base_ofs); + mCoBG_SetMoveBgHeightInf(bounds, &pos, height); + mCoBG_GetNorm(normal, mCoBG_NORM_DIRECT_UP); + ut_vec_p->wall_name = mCoBG_WALL_UP; + ut_vec_p->normal_angle = DEG2SHORT_ANGLE2(180.0f); + mCoBG_MakeCommonData(ut_vec_p, regist); + mCoBG_RotateMoveBgCollisionData(ut_vec_p, angleY_rad); + ut_vec_p->normal_angle += angleY; + mCoBG_PlusLinePos(start, pos.x, pos.z); + mCoBG_PlusLinePos(end, pos.x, pos.z); + (*unit_count_p)++; + } + + if (*unit_count_p < mCoBG_UNIT_VEC_INFO_MAX) { + ut_vec_p = &unit_vec[*unit_count_p]; + start = ut_vec_p->start; + end = ut_vec_p->end; + normal = ut_vec_p->normal; + bounds = &ut_vec_p->wall_bounds; + + mCoBG_SetLinePos(start, -(size->left_size * rate), (size->down_size * rate) + tab_data.t0); + mCoBG_SetLinePos(end, -(size->left_size * rate), -(size->up_size * rate) - tab_data.t0); + mCoBG_SetBaseOffset(start, end, base_ofs); + mCoBG_SetMoveBgHeightInf(bounds, &pos, height); + mCoBG_GetNorm(normal, mCoBG_NORM_DIRECT_LEFT); + ut_vec_p->wall_name = mCoBG_WALL_LEFT; + ut_vec_p->normal_angle = DEG2SHORT_ANGLE2(-90.0f); + mCoBG_MakeCommonData(ut_vec_p, regist); + mCoBG_RotateMoveBgCollisionData(ut_vec_p, angleY_rad); + ut_vec_p->normal_angle += angleY; + mCoBG_PlusLinePos(start, pos.x, pos.z); + mCoBG_PlusLinePos(end, pos.x, pos.z); + (*unit_count_p)++; + } + + if (*unit_count_p < mCoBG_UNIT_VEC_INFO_MAX) { + ut_vec_p = &unit_vec[*unit_count_p]; + start = ut_vec_p->start; + end = ut_vec_p->end; + normal = ut_vec_p->normal; + bounds = &ut_vec_p->wall_bounds; + + mCoBG_SetLinePos(start, (size->right_size * rate) + tab_data.t0, (size->down_size * rate)); + mCoBG_SetLinePos(end, -(size->left_size * rate) - tab_data.t0, (size->down_size * rate)); + mCoBG_SetBaseOffset(start, end, base_ofs); + mCoBG_SetMoveBgHeightInf(bounds, &pos, height); + mCoBG_GetNorm(normal, mCoBG_NORM_DIRECT_DOWN); + ut_vec_p->wall_name = mCoBG_WALL_DOWN; + ut_vec_p->normal_angle = DEG2SHORT_ANGLE2(0.0f); + mCoBG_MakeCommonData(ut_vec_p, regist); + mCoBG_RotateMoveBgCollisionData(ut_vec_p, angleY_rad); + ut_vec_p->normal_angle += angleY; + mCoBG_PlusLinePos(start, pos.x, pos.z); + mCoBG_PlusLinePos(end, pos.x, pos.z); + (*unit_count_p)++; + } + + if (*unit_count_p < mCoBG_UNIT_VEC_INFO_MAX) { + ut_vec_p = &unit_vec[*unit_count_p]; + start = ut_vec_p->start; + end = ut_vec_p->end; + normal = ut_vec_p->normal; + bounds = &ut_vec_p->wall_bounds; + + mCoBG_SetLinePos(start, (size->right_size * rate), -(size->up_size * rate) - tab_data.t0); + mCoBG_SetLinePos(end, (size->right_size * rate), (size->down_size * rate) + tab_data.t0); + mCoBG_SetBaseOffset(start, end, base_ofs); + mCoBG_SetMoveBgHeightInf(bounds, &pos, height); + mCoBG_GetNorm(normal, mCoBG_NORM_DIRECT_RIGHT); + ut_vec_p->wall_name = mCoBG_WALL_RIGHT; + ut_vec_p->normal_angle = DEG2SHORT_ANGLE2(90.0f); + mCoBG_MakeCommonData(ut_vec_p, regist); + mCoBG_RotateMoveBgCollisionData(ut_vec_p, angleY_rad); + ut_vec_p->normal_angle += angleY; + mCoBG_PlusLinePos(start, pos.x, pos.z); + mCoBG_PlusLinePos(end, pos.x, pos.z); + (*unit_count_p)++; + } +} + +static void mCoBG_MakeMoveBgVector(mCoBG_vec_info_c* vec_info, mCoBG_mBgMgr_c* bg_mgr, const xyz_t* pos, + u8 check_type) { + int bg_count = bg_mgr->count; + int i; + int count = 0; + mCoBG_bg_regist_c** regist_pp = bg_mgr->regist_p; + + if (bg_count != 0) { + for (i = 0; i < mCoBG_MOVE_REGIST_MAX; i++) { + if (regist_pp[i] != NULL) { + xyz_t* regist_pos = regist_pp[i]->wpos; + + if (Math3DLength2D(pos->x, pos->z, regist_pos->x, regist_pos->z) < regist_pp[i]->active_dist) { + mCoBG_SizeData2CollisionData(regist_pp[i], vec_info, check_type, i); + count++; + if (count >= bg_count) { + break; + } + } + } + } + } +} + +typedef struct { + ACTOR* actor; + int move_bg_idx; + mCoBG_bg_regist_c regist; +} mCoBG_boat_collision_c; + +static mCoBG_boat_collision_c l_mCoBG_boat_move_bg_data[2]; + +static mCoBG_bg_size_c l_mCoBG_boat_size = { 20.0f, 20.0f, 40.0f, 40.0f }; + +extern void mCoBG_InitBoatCollision(void) { + int i; + + for (i = 0; i < 2; i++) { + bzero(&l_mCoBG_boat_move_bg_data[i], sizeof(mCoBG_boat_collision_c)); + l_mCoBG_boat_move_bg_data[i].move_bg_idx = -1; + } + + bzero(&l_mBgMgr, sizeof(l_mBgMgr)); +} + +extern void mCoBG_MakeBoatCollision(ACTOR* actor, xyz_t* pos, s16* angle_y) { + int i; + + for (i = 0; i < 2; i++) { + if (l_mCoBG_boat_move_bg_data[i].move_bg_idx == -1) { + l_mCoBG_boat_move_bg_data[i].move_bg_idx = + mCoBG_RegistMoveBg(&l_mCoBG_boat_move_bg_data[i].regist, pos, pos, angle_y, 30.0f, &l_mCoBG_boat_size, + NULL, NULL, NULL, mCoBG_FTR_TYPE_NUM, mCoBG_ATTRIBUTE_SAND, 120.0f); + l_mCoBG_boat_move_bg_data[i].actor = actor; + break; + } + } +} + +extern void mCoBG_DeleteBoatCollision(ACTOR* actor) { + int i; + + for (i = 0; i < 2; i++) { + if (actor == l_mCoBG_boat_move_bg_data[i].actor) { + mCoBG_CrossOffMoveBg(l_mCoBG_boat_move_bg_data[i].move_bg_idx); + l_mCoBG_boat_move_bg_data[i].move_bg_idx = -1; + break; + } + } +} diff --git a/src/AUS/game/m_collision_bg_rewrite.c_inc b/src/AUS/game/m_collision_bg_rewrite.c_inc new file mode 100644 index 00000000..0422f1ca --- /dev/null +++ b/src/AUS/game/m_collision_bg_rewrite.c_inc @@ -0,0 +1,183 @@ +static u32 mCoBG_OffsetInRule(int ofs) { + if (ofs > 31) { + return 31; + } + + return CLAMP(ofs, 0, ofs); +} + +static void mCoBG_SetBestBgY(mCoBG_Collision_u* col, s16* change_ofs) { + u32 max = mCoBG_GetMaxOffset(col->data.center, col->data.top_left, col->data.bot_left, col->data.bot_right, col->data.top_right); + u32 min = mCoBG_GetMinOffset(col->data.center, col->data.top_left, col->data.bot_left, col->data.bot_right, col->data.top_right); +} + +static void mCoBG_TidyChangeOffset(s16* change_ofs, mCoBG_Collision_u* col) { + if ( + // clang-format off + col->data.center + *change_ofs > 31 || + col->data.top_left + *change_ofs > 31 || + col->data.bot_left + *change_ofs > 31 || + col->data.bot_right + *change_ofs > 31 || + col->data.top_right + *change_ofs > 31 || + col->data.center + *change_ofs < 0 || + col->data.top_left + *change_ofs < 0 || + col->data.bot_left + *change_ofs < 0 || + col->data.bot_right + *change_ofs < 0 || + col->data.top_right + *change_ofs < 0 + // clang-format on + ) { + mCoBG_SetBestBgY(col, change_ofs); + } +} + +// @unused, @fabricated +extern void mCoBG_Ut2SetPlussOffset(int ux, int uz, s16 change_ofs, s16 attr) { + xyz_t pos = { 0.0f, 0.0f, 0.0f }; + + if (mFI_UtNum2CenterWpos(&pos, ux, uz)) { + mCoBG_SetPlussOffset(pos, change_ofs, attr); + } +} + +extern void mCoBG_SetPlussOffset(xyz_t wpos, s16 change_ofs, s16 attr) { + int ux; + int uz; + + if (mFI_Wpos2UtNum(&ux, &uz, wpos)) { + mCoBG_Collision_u* col = mFI_UtNum2UtCol(ux, uz); + u8 keep_h = mFI_UtNum2UtKeepH(ux, uz); + + if (keep_h == col->data.center) { + mCoBG_TidyChangeOffset(&change_ofs, col); + } else { + u32 gap = keep_h - col->data.center; + + col->data.center = (u8)keep_h; + col->data.top_left += gap; + col->data.bot_left += gap; + col->data.bot_right += gap; + col->data.top_right += gap; + mCoBG_TidyChangeOffset(&change_ofs, col); + } + + col->data.center += change_ofs; + col->data.bot_left += change_ofs; + col->data.top_left += change_ofs; + col->data.top_right += change_ofs; + col->data.bot_right += change_ofs; + + if (attr != mCoBG_ATTRIBUTE_NONE) { + col->data.unit_attribute = (s16)attr; + } + + } +} + +extern void mCoBG_SetAttribute(xyz_t pos, s16 attr) { + mCoBG_Collision_u* col; + int ux; + int uz; + + if (mFI_Wpos2UtNum(&ux, &uz, pos)) { + col = mFI_UtNum2UtCol(ux, uz); + if (attr != mCoBG_ATTRIBUTE_NONE) { + col->data.unit_attribute = (s16)attr; + } + } +} + +extern void mCoBG_Ut2SetPluss5PointOffset_file(int ux, int uz, mCoBG_OffsetTable_c ofs_data, char* file, int line) { + xyz_t pos = { 0.0f, 0.0f, 0.0f }; + + if (mFI_UtNum2CenterWpos(&pos, ux, uz)) { + mCoBG_SetPluss5PointOffset_file(pos, ofs_data, file, line); + } +} + +extern void mCoBG_SetPluss5PointOffset_file(xyz_t pos, mCoBG_OffsetTable_c ofs_data, char* file, int line) { + int ux; + int uz; + + if (mFI_Wpos2UtNum(&ux, &uz, pos)) { + u8 keep_h = mFI_UtNum2UtKeepH(ux, uz); + mCoBG_Collision_u* col = mFI_UtNum2UtCol(ux, uz); + + if ( + // clang-format off + col->data.center == col->data.top_left && + col->data.center == col->data.bot_left && + col->data.center == col->data.bot_right && + col->data.center == col->data.top_right + // clang-format on + ) { + col->data.center = mCoBG_OffsetInRule(keep_h + ofs_data.centerRight_offset); + col->data.top_left = mCoBG_OffsetInRule(keep_h + ofs_data.leftUp_offset); + col->data.bot_left = mCoBG_OffsetInRule(keep_h + ofs_data.leftDown_offset); + col->data.bot_right = mCoBG_OffsetInRule(keep_h + ofs_data.rightDown_offset); + col->data.top_right = mCoBG_OffsetInRule(keep_h + ofs_data.rightUp_offset); + col->data.slate_flag = (s8)ofs_data.shape; + + if (ofs_data.unit_attribute != mCoBG_ATTRIBUTE_NONE) { + col->data.unit_attribute = ofs_data.unit_attribute; + } + } else if ( + // clang-format off + ofs_data.centerRight_offset == 0 && + ofs_data.leftUp_offset == 0 && + ofs_data.leftDown_offset == 0 && + ofs_data.rightDown_offset == 0 && + ofs_data.rightUp_offset == 0 + // clang-format on + ) { + if (col->data.slate_flag) { + col->data.center = keep_h; + col->data.top_left = keep_h; + col->data.bot_left = keep_h; + col->data.bot_right = keep_h; + col->data.top_right = keep_h; + col->data.slate_flag = FALSE; + } else { + col->data.center = keep_h; + col->data.top_left = keep_h; + col->data.bot_left = keep_h; + col->data.bot_right = keep_h; + col->data.top_right = keep_h; + } + + if (ofs_data.unit_attribute != mCoBG_ATTRIBUTE_NONE) { + col->data.unit_attribute = ofs_data.unit_attribute; + } + } + } +} + +typedef struct { + u8 src; + u8 dst; +} mCoBG_change_poor_c; + +extern int mCoBG_Change2PoorAttr(mCoBG_Collision_u* col) { + static mCoBG_change_poor_c change_data[] = { + { mCoBG_ATTRIBUTE_GRASS0, mCoBG_ATTRIBUTE_GRASS2 }, + { mCoBG_ATTRIBUTE_GRASS1, mCoBG_ATTRIBUTE_GRASS2 }, + { mCoBG_ATTRIBUTE_SOIL0, mCoBG_ATTRIBUTE_SOIL2 }, + { mCoBG_ATTRIBUTE_SOIL1, mCoBG_ATTRIBUTE_SOIL2 }, + }; + u8 attr = col->data.unit_attribute; + int i; + + for (i = 0; i < ARRAY_COUNT(change_data); i++) { + if (attr == change_data[i].src) { + col->data.unit_attribute = change_data[i].dst; + return TRUE; + } + } + + return FALSE; +} + +extern void mCoBG_Ut2SetDefaultOffset(int ux, int uz) { + static mCoBG_OffsetTable_c offset_data = { mCoBG_ATTRIBUTE_NONE, 0, 0, 0, 0, 0, FALSE }; + + mCoBG_Ut2SetPluss5PointOffset_file(ux, uz, offset_data, __FILE__, 515); +} diff --git a/src/AUS/game/m_collision_bg_wall.c_inc b/src/AUS/game/m_collision_bg_wall.c_inc new file mode 100644 index 00000000..8fefa0b3 --- /dev/null +++ b/src/AUS/game/m_collision_bg_wall.c_inc @@ -0,0 +1,662 @@ +static void mCoBG_UnitNoName2StartEnd(f32* start, f32* end, f32 ux, f32 uz, u8 wall_name, u8 check_type) { + mCoBG_tab_c tab = mCoBG_tab_data[check_type]; + + switch (wall_name) { + case mCoBG_WALL_UP: + start[0] = ux * mFI_UT_WORLDSIZE_X_F - tab.t0; + start[1] = uz * mFI_UT_WORLDSIZE_Z_F; + end[0] = start[0] + mFI_UT_WORLDSIZE_X_F + tab.t1; + end[1] = start[1]; + break; + case mCoBG_WALL_LEFT: + start[0] = ux * mFI_UT_WORLDSIZE_X_F; + start[1] = uz * mFI_UT_WORLDSIZE_Z_F - tab.t0; + end[0] = start[0]; + end[1] = start[1] + mFI_UT_WORLDSIZE_Z_F + tab.t1; + break; + case mCoBG_WALL_DOWN: + end[0] = ux * mFI_UT_WORLDSIZE_X_F - tab.t0; + end[1] = (uz + 1) * mFI_UT_WORLDSIZE_Z_F; + start[0] = end[0] + mFI_UT_WORLDSIZE_X_F + tab.t1; + start[1] = end[1]; + break; + case mCoBG_WALL_RIGHT: + start[0] = (ux + 1) * mFI_UT_WORLDSIZE_X_F; + start[1] = uz * mFI_UT_WORLDSIZE_Z_F - tab.t0; + end[0] = start[0]; + end[1] = start[1] + mFI_UT_WORLDSIZE_Z_F + tab.t1; + break; + case mCoBG_WALL_SLATE_UP: + start[0] = ux * mFI_UT_WORLDSIZE_X_F - tab.t0; + end[0] = start[0] + tab.t1 + mFI_UT_WORLDSIZE_X_F; + start[1] = (uz + 1) * mFI_UT_WORLDSIZE_Z_F + tab.t0; + end[1] = start[1] - mFI_UT_WORLDSIZE_Z_F - tab.t1; + break; + case mCoBG_WALL_SLATE_DOWN: + start[0] = ux * mFI_UT_WORLDSIZE_X_F - tab.t0; + end[0] = start[0] + tab.t1 + mFI_UT_WORLDSIZE_X_F; + start[1] = uz * mFI_UT_WORLDSIZE_Z_F - tab.t0; + end[1] = start[1] + mFI_UT_WORLDSIZE_Z_F + tab.t1; + break; + } +} + +static u8 l_make33_coldata[9] = { + 0x00, 0x02, 0x02, 0x01, 0x03, 0x03, 0x01, 0x03, + 0x03, +}; + +static u8 l_make55_coldata[25] = { + 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x03, 0x03, + 0x03, 0x03, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, + 0x03, 0x03, 0x03, 0x03, 0x01, 0x03, 0x03, 0x03, + 0x03, +}; + +static u8 l_make77_coldata[49] = { + 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x01, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x01, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, +}; + +static u8 mCoBG_SearchSlateDetail(mCoBG_CollisionData_c* col) { + if (col->bot_right != col->top_left) { + return mCoBG_WALL_SLATE_UP; + } else if (col->top_right != col->bot_left) { + return mCoBG_WALL_SLATE_DOWN; + } else { + return mCoBG_WALL_SLATE_UP; + } +} + +static u8 mCoBG_SearchWallFlag(mCoBG_unit_vec_info_c* unit_vec, mCoBG_UnitInfo_c* ut_info0, mCoBG_UnitInfo_c* ut_info1, u8 wall_name) { + switch (wall_name) { + case mCoBG_WALL_UP: + if (ut_info0->leftUp_offset != ut_info1->leftDown_offset || ut_info0->rightUp_offset != ut_info1->rightDown_offset) { + if (ut_info1->leftDown_offset > ut_info0->leftUp_offset || ut_info1->rightDown_offset > ut_info0->rightUp_offset) { + mCoBG_SetXZ(unit_vec->normal, 0.0f, 1.0f); + unit_vec->normal_angle = DEG2SHORT_ANGLE2(0.0f); + return TRUE; + } else { + mCoBG_SetXZ(unit_vec->normal, 0.0f, -1.0f); + unit_vec->normal_angle = DEG2SHORT_ANGLE2(180.0f); + return TRUE; + } + } + break; + case mCoBG_WALL_LEFT: + if (ut_info0->leftUp_offset != ut_info1->rightUp_offset || ut_info0->leftDown_offset != ut_info1->rightDown_offset) { + if (ut_info1->rightUp_offset > ut_info0->leftUp_offset || ut_info1->rightDown_offset > ut_info0->leftDown_offset) { + mCoBG_SetXZ(unit_vec->normal, 1.0f, 0.0f); + unit_vec->normal_angle = DEG2SHORT_ANGLE2(90.0f); + return TRUE; + } else { + mCoBG_SetXZ(unit_vec->normal, -1.0f, 0.0f); + unit_vec->normal_angle = DEG2SHORT_ANGLE2(-90.0f); + return TRUE; + } + } + break; + case mCoBG_WALL_DOWN: + if (ut_info0->leftDown_offset != ut_info1->leftUp_offset || ut_info0->rightDown_offset != ut_info1->rightUp_offset) { + if (ut_info1->leftUp_offset > ut_info0->leftDown_offset || ut_info1->rightUp_offset > ut_info0->rightDown_offset) { + mCoBG_SetXZ(unit_vec->normal, 0.0f, -1.0f); + unit_vec->normal_angle = DEG2SHORT_ANGLE2(180.0f); + return TRUE; + } else { + mCoBG_SetXZ(unit_vec->normal, 0.0f, 1.0f); + unit_vec->normal_angle = DEG2SHORT_ANGLE2(0.0f); + return TRUE; + } + } + break; + case mCoBG_WALL_RIGHT: + if (ut_info0->rightUp_offset != ut_info1->leftUp_offset || ut_info0->rightDown_offset != ut_info1->leftDown_offset) { + if (ut_info1->leftUp_offset > ut_info0->leftDown_offset || ut_info1->rightUp_offset > ut_info0->rightDown_offset) { + mCoBG_SetXZ(unit_vec->normal, -1.0f, 0.0f); + unit_vec->normal_angle = DEG2SHORT_ANGLE2(-90.0f); + return TRUE; + } else { + mCoBG_SetXZ(unit_vec->normal, 1.0f, 0.0f); + unit_vec->normal_angle = DEG2SHORT_ANGLE2(90.0f); + return TRUE; + } + } + break; + } + + return FALSE; +} + +static void mCoBG_SetTopBtm(mCoBG_WallBounds_c* bounds, f32 start_top, f32 end_top, f32 start_btm, f32 end_btm) { + bounds->start_top = start_top; + bounds->end_top = end_top; + bounds->start_btm = start_btm; + bounds->end_btm = end_btm; +} + +static void mCoBG_GetUnitVecInf_SlatingWall(mCoBG_unit_vec_info_c* unit_vec, mCoBG_UnitInfo_c* unit_info, u8 name, u8 check_type) { + f32 ux = unit_info->ut_x; + f32 uz = unit_info->ut_z; + f32* start = unit_vec->start; + f32* end = unit_vec->end; + f32* normal = unit_vec->normal; + mCoBG_WallBounds_c* bounds = &unit_vec->wall_bounds; + + unit_vec->wall_name = name; + switch (name) { + case mCoBG_WALL_SLATE_UP: + mCoBG_UnitNoName2StartEnd(start, end, ux, uz, mCoBG_WALL_SLATE_UP, check_type); + if (unit_info->leftUp_offset > unit_info->rightDown_offset) { + mCoBG_SetXZ(normal, SQRT_OF_2_DIV_2, SQRT_OF_2_DIV_2); + unit_vec->normal_angle = DEG2SHORT_ANGLE2(45.0f); + mCoBG_SetTopBtm(bounds, unit_info->leftUp_offset, unit_info->leftUp_offset, unit_info->rightDown_offset, unit_info->rightDown_offset); + } else { + mCoBG_SetXZ(normal, -SQRT_OF_2_DIV_2, -SQRT_OF_2_DIV_2); + unit_vec->normal_angle = DEG2SHORT_ANGLE2(-135.0f); + mCoBG_SetTopBtm(bounds, unit_info->rightDown_offset, unit_info->rightDown_offset, unit_info->leftUp_offset, unit_info->leftUp_offset); + } + break; + case mCoBG_WALL_SLATE_DOWN: + mCoBG_UnitNoName2StartEnd(start, end, ux, uz, mCoBG_WALL_SLATE_DOWN, check_type); + if (unit_info->leftDown_offset > unit_info->rightUp_offset) { + mCoBG_SetXZ(normal, SQRT_OF_2_DIV_2, -SQRT_OF_2_DIV_2); + unit_vec->normal_angle = DEG2SHORT_ANGLE2(135.0f); + mCoBG_SetTopBtm(bounds, unit_info->leftDown_offset, unit_info->leftDown_offset, unit_info->rightUp_offset, unit_info->rightUp_offset); + } else { + mCoBG_SetXZ(normal, -SQRT_OF_2_DIV_2, SQRT_OF_2_DIV_2); + unit_vec->normal_angle = DEG2SHORT_ANGLE2(-45.0f); + mCoBG_SetTopBtm(bounds, unit_info->rightUp_offset, unit_info->rightUp_offset, unit_info->leftDown_offset, unit_info->leftDown_offset); + } + break; + } +} + +static void mCoBG_JudgeTopAndSet(f32* top, f32* bot, f32 y0, f32 y1) { + if (y0 >= y1) { + *top = y0; + *bot = y1; + } else { + *top = y1; + *bot = y0; + } +} + +static void mCoBG_UtInf2NormalWallVector(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* unit_info0, mCoBG_UnitInfo_c* unit_info1, s16 wall_name, u8 check_type) { + f32 ux = unit_info0->ut_x; + f32 uz = unit_info0->ut_z; + int count = vec_info->unit_count; + mCoBG_unit_vec_info_c* unit_vec = &vec_info->unit[count]; + mCoBG_WallBounds_c* bounds = &unit_vec->wall_bounds; + f32* start = unit_vec->start; + f32* end = unit_vec->end; + + unit_vec->regist_p = NULL; + unit_vec->atr_wall = FALSE; + + switch (wall_name) { + case mCoBG_WALL_UP: + if (mCoBG_SearchWallFlag(unit_vec, unit_info0, unit_info1, mCoBG_WALL_UP)) { + // @BUG - isn't this missing? + // unit_vec->wall_name = mCoBG_WALL_UP; + mCoBG_UnitNoName2StartEnd(start, end, ux, uz, mCoBG_WALL_UP, check_type); + mCoBG_JudgeTopAndSet(&bounds->start_top, &bounds->start_btm, unit_info0->leftUp_offset, unit_info1->leftDown_offset); + mCoBG_JudgeTopAndSet(&bounds->end_top, &bounds->end_btm, unit_info0->rightUp_offset, unit_info1->rightDown_offset); + unit_vec->regist_p = NULL; + unit_vec->atr_wall = FALSE; + vec_info->unit_count++; + } + break; + case mCoBG_WALL_LEFT: + if (mCoBG_SearchWallFlag(unit_vec, unit_info0, unit_info1, mCoBG_WALL_LEFT)) { + unit_vec->wall_name = mCoBG_WALL_LEFT; + mCoBG_UnitNoName2StartEnd(start, end, ux, uz, mCoBG_WALL_LEFT, check_type); + mCoBG_JudgeTopAndSet(&bounds->start_top, &bounds->start_btm, unit_info0->leftUp_offset, unit_info1->rightUp_offset); + mCoBG_JudgeTopAndSet(&bounds->end_top, &bounds->end_btm, unit_info0->leftDown_offset, unit_info1->rightDown_offset); + unit_vec->regist_p = NULL; + unit_vec->atr_wall = FALSE; + vec_info->unit_count++; + } + break; + case mCoBG_WALL_DOWN: + if (mCoBG_SearchWallFlag(unit_vec, unit_info0, unit_info1, mCoBG_WALL_DOWN)) { + unit_vec->wall_name = mCoBG_WALL_DOWN; + mCoBG_UnitNoName2StartEnd(start, end, ux, uz, mCoBG_WALL_DOWN, check_type); + mCoBG_JudgeTopAndSet(&bounds->start_top, &bounds->start_btm, unit_info0->leftDown_offset, unit_info1->leftUp_offset); + mCoBG_JudgeTopAndSet(&bounds->end_top, &bounds->end_btm, unit_info0->rightDown_offset, unit_info1->rightUp_offset); + unit_vec->regist_p = NULL; + unit_vec->atr_wall = FALSE; + vec_info->unit_count++; + } + break; + case mCoBG_WALL_RIGHT: + if (mCoBG_SearchWallFlag(unit_vec, unit_info0, unit_info1, mCoBG_WALL_RIGHT)) { + unit_vec->wall_name = mCoBG_WALL_RIGHT; + mCoBG_UnitNoName2StartEnd(start, end, ux, uz, mCoBG_WALL_RIGHT, check_type); + mCoBG_JudgeTopAndSet(&bounds->start_top, &bounds->start_btm, unit_info0->rightUp_offset, unit_info1->leftUp_offset); + mCoBG_JudgeTopAndSet(&bounds->end_top, &bounds->end_btm, unit_info0->rightDown_offset, unit_info1->leftDown_offset); + unit_vec->regist_p = NULL; + unit_vec->atr_wall = FALSE; + vec_info->unit_count++; + } + break; + } +} + +static void mCoBG_UtInf2NormalSlateWallVector(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info0, mCoBG_UnitInfo_c* ut_info1, s16 wall_name, u8 check_type) { + mCoBG_UnitInfo_c tmp_ut_info; + + if (ut_info0->slate_flag == FALSE && ut_info1->slate_flag == TRUE) { + u8 slateDir = mCoBG_SearchSlateDetail(&ut_info1->collision->data); + + tmp_ut_info = *ut_info1; + switch (wall_name) { + case mCoBG_WALL_UP: + if (slateDir == mCoBG_WALL_SLATE_UP) { + tmp_ut_info.leftDown_offset = tmp_ut_info.rightDown_offset; + } else { + tmp_ut_info.rightDown_offset = tmp_ut_info.leftDown_offset; + } + break; + case mCoBG_WALL_LEFT: + if (slateDir == mCoBG_WALL_SLATE_UP) { + tmp_ut_info.rightUp_offset = tmp_ut_info.rightDown_offset; + } else { + tmp_ut_info.rightDown_offset = tmp_ut_info.rightUp_offset; + } + break; + case mCoBG_WALL_DOWN: + if (slateDir == mCoBG_WALL_SLATE_UP) { + tmp_ut_info.rightUp_offset = tmp_ut_info.leftUp_offset; + } else { + tmp_ut_info.leftUp_offset = tmp_ut_info.rightUp_offset; + } + break; + case mCoBG_WALL_RIGHT: + if (slateDir == mCoBG_WALL_SLATE_UP) { + tmp_ut_info.leftDown_offset = tmp_ut_info.leftUp_offset; + } else { + tmp_ut_info.leftUp_offset = tmp_ut_info.leftDown_offset; + } + break; + } + + mCoBG_UtInf2NormalWallVector(vec_info, ut_info0, &tmp_ut_info, wall_name, check_type); + } else if (ut_info0->slate_flag == TRUE && ut_info1->slate_flag == FALSE) { + u8 slateDir = mCoBG_SearchSlateDetail(&ut_info0->collision->data); + + tmp_ut_info = *ut_info0; + switch (wall_name) { + case mCoBG_WALL_UP: + if (slateDir == mCoBG_WALL_SLATE_UP) { + tmp_ut_info.rightUp_offset = tmp_ut_info.leftUp_offset; + } else { + tmp_ut_info.leftUp_offset = tmp_ut_info.rightUp_offset; + } + break; + case mCoBG_WALL_LEFT: + if (slateDir == mCoBG_WALL_SLATE_UP) { + tmp_ut_info.leftDown_offset = tmp_ut_info.leftUp_offset; + } else { + tmp_ut_info.leftUp_offset = tmp_ut_info.leftDown_offset; + } + break; + case mCoBG_WALL_DOWN: + if (slateDir == mCoBG_WALL_SLATE_UP) { + tmp_ut_info.leftDown_offset = tmp_ut_info.rightDown_offset; + } else { + tmp_ut_info.rightDown_offset = tmp_ut_info.leftDown_offset; + } + break; + case mCoBG_WALL_RIGHT: + if (slateDir == mCoBG_WALL_SLATE_UP) { + tmp_ut_info.rightDown_offset = tmp_ut_info.rightUp_offset; + } else { + tmp_ut_info.rightUp_offset = tmp_ut_info.rightDown_offset; + } + break; + } + + mCoBG_UtInf2NormalWallVector(vec_info, &tmp_ut_info, ut_info1, wall_name, check_type); + } +} + +typedef void (*mCoBG_MAKE_NORMAL_WALL_PROC)(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info0, mCoBG_UnitInfo_c* ut_info1, s16 wall_name, u8 check_type); + +static void mCoBG_RegistNormalWallVector_AttributeOn(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info0, mCoBG_UnitInfo_c* ut_info1, s16 wall_name, u8 check_type, s16 old_in_water) { + static mCoBG_MAKE_NORMAL_WALL_PROC make_normal_wall_proc[] = { &mCoBG_UtInf2NormalWallVector, &mCoBG_UtInf2NormalSlateWallVector }; + + if (vec_info->unit_count < mCoBG_UNIT_VEC_INFO_MAX) { + int proc = ut_info0->slate_flag | ut_info1->slate_flag; + + (*make_normal_wall_proc[proc & 1])(vec_info, ut_info0, ut_info1, wall_name, check_type); + } +} + +static void mCoBG_UnitInf2NormalVector(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info0, mCoBG_UnitInfo_c* ut_info1, s16 wall_name, u8 check_type) { + static mCoBG_MAKE_NORMAL_WALL_PROC make_normal_wall_proc[] = { &mCoBG_UtInf2NormalWallVector, &mCoBG_UtInf2NormalSlateWallVector }; + int proc = ut_info0->slate_flag | ut_info1->slate_flag; + + (*make_normal_wall_proc[proc & 1])(vec_info, ut_info0, ut_info1, wall_name, check_type); +} + +static void mCoBG_RegistNormalWallVector_AttributeOff(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info0, mCoBG_UnitInfo_c* ut_info1, s16 wall_name, u8 check_type, s16 old_in_water) { + if (vec_info->unit_count < mCoBG_UNIT_VEC_INFO_MAX) { + if (old_in_water) { + if (ut_info0->attribute == mCoBG_ATTRIBUTE_WOOD && ut_info1->attribute >= mCoBG_ATTRIBUTE_27 && ut_info1->attribute <= mCoBG_ATTRIBUTE_35) { + mCoBG_UnitInfo_c tmp_ut_info = *ut_info1; + f32 min_h = MIN(MIN(tmp_ut_info.leftDown_offset, tmp_ut_info.leftUp_offset), MIN(tmp_ut_info.rightDown_offset, tmp_ut_info.rightUp_offset)); + + tmp_ut_info.slate_flag = FALSE; + tmp_ut_info.leftDown_offset = min_h; + tmp_ut_info.leftUp_offset = min_h; + tmp_ut_info.rightDown_offset = min_h; + tmp_ut_info.rightUp_offset = min_h; + mCoBG_UnitInf2NormalVector(vec_info, ut_info0, &tmp_ut_info, wall_name, check_type); + } else if (ut_info1->attribute == mCoBG_ATTRIBUTE_WOOD && ut_info0->attribute >= mCoBG_ATTRIBUTE_27 && ut_info0->attribute <= mCoBG_ATTRIBUTE_35) { + mCoBG_UnitInfo_c tmp_ut_info = *ut_info0; + f32 min_h = MIN(MIN(tmp_ut_info.leftDown_offset, tmp_ut_info.leftUp_offset), MIN(tmp_ut_info.rightDown_offset, tmp_ut_info.rightUp_offset)); + + tmp_ut_info.slate_flag = FALSE; + tmp_ut_info.leftDown_offset = min_h; + tmp_ut_info.leftUp_offset = min_h; + tmp_ut_info.rightDown_offset = min_h; + tmp_ut_info.rightUp_offset = min_h; + mCoBG_UnitInf2NormalVector(vec_info, &tmp_ut_info, ut_info1, wall_name, check_type); + } else if (!(ut_info0->attribute >= mCoBG_ATTRIBUTE_27 && ut_info0->attribute <= mCoBG_ATTRIBUTE_35) && !(ut_info1->attribute >= mCoBG_ATTRIBUTE_27 && ut_info1->attribute <= mCoBG_ATTRIBUTE_35)) { + mCoBG_UnitInf2NormalVector(vec_info, ut_info0, ut_info1, wall_name, check_type); + } + } else { + mCoBG_UnitInf2NormalVector(vec_info, ut_info0, ut_info1, wall_name, check_type); + } + } +} + +static void mCoBG_RegistSlatingWallVector_AttributeOn_NoSlate(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, u8 check_type, s16 old_in_water) { + // nothing +} + +static void mCoBG_RegistSlatingWallVector_AttributeOn_Slate(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, u8 check_type, s16 old_in_water) { + if (vec_info->unit_count < mCoBG_UNIT_VEC_INFO_MAX) { + mCoBG_unit_vec_info_c* unit_vec = vec_info->unit; + int* unit_count_p = &vec_info->unit_count; + + unit_vec[*unit_count_p].wall_name = mCoBG_SearchSlateDetail(&ut_info->collision->data); + mCoBG_GetUnitVecInf_SlatingWall(&unit_vec[*unit_count_p], ut_info, unit_vec[*unit_count_p].wall_name, check_type); + unit_vec[0].regist_p = NULL; // @BUG: ??? shouldn't this be unit_vec->regist_p = NULL; + (*unit_count_p)++; + } +} + +typedef void (*mCoBG_ATTRON_MAKE_SLATE_WALL_PROC)(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, u8 check_type, s16 old_in_water); + +static void mCoBG_RegistSlatingWallVector_AttributeOn(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, u8 check_type, s16 old_in_water) { + static mCoBG_ATTRON_MAKE_SLATE_WALL_PROC attron_make_slate_wall_proc_table[] = { &mCoBG_RegistSlatingWallVector_AttributeOn_NoSlate, &mCoBG_RegistSlatingWallVector_AttributeOn_Slate }; + + (*attron_make_slate_wall_proc_table[ut_info->slate_flag & 1])(vec_info, ut_info, check_type, old_in_water); +} + +static void mCoBG_RegistSlatingWallVector_AttributeOff_Slate_NoOldInWater(mCoBG_unit_vec_info_c* unit_vec, mCoBG_UnitInfo_c* ut_info, int* unit_count_p, u8 check_type) { + unit_vec->wall_name = mCoBG_SearchSlateDetail(&ut_info->collision->data); + mCoBG_GetUnitVecInf_SlatingWall(unit_vec, ut_info, unit_vec->wall_name, check_type); + unit_vec->regist_p = NULL; + (*unit_count_p)++; +} + +static void mCoBG_RegistSlatingWallVector_AttributeOff_Slate_OldInWater(mCoBG_unit_vec_info_c* unit_vec, mCoBG_UnitInfo_c* ut_info, int* unit_count_p, u8 check_type) { + if (ut_info->attribute >= mCoBG_ATTRIBUTE_27 && ut_info->attribute <= mCoBG_ATTRIBUTE_35) { + return; + } + + unit_vec->wall_name = mCoBG_SearchSlateDetail(&ut_info->collision->data); + mCoBG_GetUnitVecInf_SlatingWall(unit_vec, ut_info, unit_vec->wall_name, check_type); + unit_vec->regist_p = NULL; + (*unit_count_p)++; +} + +typedef void (*mCoBG_MAKE_SLATE_WALL_PROC2)(mCoBG_unit_vec_info_c* unit_vec, mCoBG_UnitInfo_c* ut_info, int* unit_count_p, u8 check_type); + +static void mCoBG_RegistSlatingWallVector_AttributeOff_Slate(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, u8 check_type, s16 old_in_water) { + static mCoBG_MAKE_SLATE_WALL_PROC2 make_slate_wall_proc_table2[] = { &mCoBG_RegistSlatingWallVector_AttributeOff_Slate_NoOldInWater, &mCoBG_RegistSlatingWallVector_AttributeOff_Slate_OldInWater }; + mCoBG_unit_vec_info_c* all_unit_vec = vec_info->unit; + int* unit_count_p = &vec_info->unit_count; + mCoBG_unit_vec_info_c* unit_vec = &all_unit_vec[*unit_count_p]; + + if (*unit_count_p < mCoBG_UNIT_VEC_INFO_MAX) { + (*make_slate_wall_proc_table2[old_in_water & 1])(unit_vec, ut_info, unit_count_p, check_type); + } +} + +static void mCoBG_RegistSlatingWallVector_AttributeOff_NoSlate(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, u8 check_type, s16 old_in_water) { + // nothing +} + +static void mCoBG_RegistSlatingWallVector_AttributeOff(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, u8 check_type, s16 old_in_water) { + static mCoBG_ATTRON_MAKE_SLATE_WALL_PROC make_slate_wall_proc_table[] = { &mCoBG_RegistSlatingWallVector_AttributeOff_NoSlate, &mCoBG_RegistSlatingWallVector_AttributeOff_Slate }; + + (*make_slate_wall_proc_table[ut_info->slate_flag & 1])(vec_info, ut_info, check_type, old_in_water); +} + +static u8* mCoBG_GetUnitInfSearchData(int count) { + switch (count) { + case 3: + return l_make33_coldata; + case 5: + return l_make55_coldata; + case 7: + return l_make77_coldata; + default: + return l_make33_coldata; + } +} + +static void mCoBG_MakeForbidVectorData(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, u8 check_type) { + u8 attribute = ut_info->attribute; + int* unit_count_p = &vec_info->unit_count; + mCoBG_unit_vec_info_c* unit_vec = &vec_info->unit[*unit_count_p]; + f32 ux = ut_info->ut_x; + f32 uz = ut_info->ut_z; + int forbid_idx_idx = attribute - mCoBG_ATTRIBUTE_27; + int i; + + for (i = 0; i < 2; i++) { + s16* data = mCoBG_forbid_vector_idx[forbid_idx_idx]; + s16 idx = data[i]; + + if (idx != -1) { + mCoBG_forbid_vec_data_c* forbid_data = &mCoBG_make_vector_table[idx]; + + unit_vec->normal[0] = forbid_data->norm[0]; + unit_vec->normal[1] = forbid_data->norm[1]; + unit_vec->normal_angle = forbid_data->norm_angle; + unit_vec->wall_name = forbid_data->wall_name; + mCoBG_UnitNoName2StartEnd(unit_vec->start, unit_vec->end, ux, uz, unit_vec->wall_name, check_type); + unit_vec->atr_wall = TRUE; + unit_vec->regist_p = NULL; + unit_vec++; + (*unit_count_p)++; + } + } +} + +static void mCoBG_MakeForbidAttrVector_DUMMY(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, u8 check_type) { + // nothing +} + +static void mCoBG_MakeForbidAttrVector(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, u8 check_type) { + u32 attribute = ut_info->attribute; + + if (attribute >= mCoBG_ATTRIBUTE_27 && attribute <= mCoBG_ATTRIBUTE_62) { + mCoBG_MakeForbidVectorData(vec_info, ut_info, check_type); + } +} + +typedef void (*mCoBG_REGIST_NORMAL_WALL_PROC)(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info0, mCoBG_UnitInfo_c* ut_info1, s16 wall_name, u8 check_type, s16 old_in_water); +typedef void (*mCoBG_REGIST_SLATE_WALL_PROC)(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, u8 check_type, s16 old_in_water); +typedef void (*mCoBG_MAKE_FORBID_ATTR_VECTOR_PROC)(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, u8 check_type); + +static void mCoBG_MakeUnitVector(mCoBG_vec_info_c* vec_info, mCoBG_UnitInfo_c* ut_info, s16 ut_count, u8 check_type, s16 attr_wall, s16 old_on_ground, s16 old_in_water) { + static mCoBG_REGIST_NORMAL_WALL_PROC make_normal_wall[] = { &mCoBG_RegistNormalWallVector_AttributeOff, &mCoBG_RegistNormalWallVector_AttributeOn }; + static mCoBG_REGIST_SLATE_WALL_PROC make_slate_wall[] = { &mCoBG_RegistSlatingWallVector_AttributeOff, &mCoBG_RegistSlatingWallVector_AttributeOn }; + int unit; + int ut_count2 = SQ(ut_count); + u8* make_info_p; + int forbid_proc = (old_on_ground & attr_wall) & 1; + mCoBG_UnitInfo_c* ut_info_p = ut_info; + int bx; + int bz; + + vec_info->unit_count = 0; + make_info_p = mCoBG_GetUnitInfSearchData(ut_count); + if (mFI_Wpos2BlockNum(&bx, &bz, l_ActorInf.center_pos)) { + u32 kind = mFI_BkNum2BlockKind(bx, bz); + + if ((kind & mRF_BLOCKKIND_DOCK) != 0 || (kind & mRF_BLOCKKIND_ISLAND) != 0) { + old_in_water = FALSE; + } + } + + for (unit = 0; unit < ut_count2; unit++) { + static mCoBG_MAKE_FORBID_ATTR_VECTOR_PROC make_forbid_atr_vector_proc[] = { &mCoBG_MakeForbidAttrVector_DUMMY, &mCoBG_MakeForbidAttrVector }; + + (*make_slate_wall[attr_wall])(vec_info, ut_info_p, check_type, old_in_water); + if (make_info_p[0] & 1) { + (*make_normal_wall[attr_wall])(vec_info, ut_info_p, &ut_info[unit - ut_count], mCoBG_WALL_UP, check_type, old_in_water); + } + + if (make_info_p[0] & 2) { + (*make_normal_wall[attr_wall])(vec_info, ut_info_p, &ut_info[unit - 1], mCoBG_WALL_LEFT, check_type, old_in_water); + } + + if (make_info_p[0] & 4) { + (*make_normal_wall[attr_wall])(vec_info, ut_info_p, &ut_info[unit + ut_count], mCoBG_WALL_DOWN, check_type, old_in_water); + } + + if (make_info_p[0] & 8) { + (*make_normal_wall[attr_wall])(vec_info, ut_info_p, &ut_info[unit + 1], mCoBG_WALL_RIGHT, check_type, old_in_water); + } + + (*make_forbid_atr_vector_proc[forbid_proc])(vec_info, ut_info_p, check_type); + make_info_p++; + ut_info_p++; + } +} + +typedef struct { + int dx; + int dz; + + s16 normal_angle0; + f32 normal0[2]; + u8 wall_name0; + + s16 normal_angle1; + f32 normal1[2]; + u8 wall_name1; +} mCoBG_defence_wall_info_c; + +static int mCoBG_CircleDefenceWallIdx(int dx, int dz, s16* normal0_p, f32* normal0, u8* wall_name0_p, s16* normal1_p, f32* normal1, u8* wall_name1_p) { + int i; + // clang-format off + static mCoBG_defence_wall_info_c defence_wall_info[] = { + { 1, 0, DEG2SHORT_ANGLE2(0.0f), { 0.0f, 1.0f}, mCoBG_WALL_UP, DEG2SHORT_ANGLE2(180.0f), { 0.0f, -1.0f}, mCoBG_WALL_UP}, + {-1, 0, DEG2SHORT_ANGLE2(0.0f), { 0.0f, 1.0f}, mCoBG_WALL_UP, DEG2SHORT_ANGLE2(180.0f), { 0.0f, -1.0f}, mCoBG_WALL_UP}, + { 0, 1, DEG2SHORT_ANGLE2(90.0f), { 1.0f, 0.0f}, mCoBG_WALL_RIGHT, DEG2SHORT_ANGLE2(-90.0f), { -1.0f, 0.0f}, mCoBG_WALL_RIGHT}, + { 0, -1, DEG2SHORT_ANGLE2(90.0f), { 1.0f, 0.0f}, mCoBG_WALL_RIGHT, DEG2SHORT_ANGLE2(-90.0f), { -1.0f, 0.0f}, mCoBG_WALL_RIGHT}, + { 1, 1, DEG2SHORT_ANGLE2(135.0f), { SQRT_OF_2_DIV_2, -SQRT_OF_2_DIV_2}, mCoBG_WALL_SLATE_DOWN, DEG2SHORT_ANGLE2(-45.0f), {-SQRT_OF_2_DIV_2, SQRT_OF_2_DIV_2}, mCoBG_WALL_SLATE_DOWN}, + {-1, -1, DEG2SHORT_ANGLE2(135.0f), { SQRT_OF_2_DIV_2, -SQRT_OF_2_DIV_2}, mCoBG_WALL_SLATE_DOWN, DEG2SHORT_ANGLE2(-45.0f), {-SQRT_OF_2_DIV_2, SQRT_OF_2_DIV_2}, mCoBG_WALL_SLATE_DOWN}, + { 1, -1, DEG2SHORT_ANGLE2(-135.0f), {-SQRT_OF_2_DIV_2, -SQRT_OF_2_DIV_2}, mCoBG_WALL_SLATE_UP, DEG2SHORT_ANGLE2(45.0f), { SQRT_OF_2_DIV_2, SQRT_OF_2_DIV_2}, mCoBG_WALL_SLATE_UP}, + {-1, 1, DEG2SHORT_ANGLE2(-135.0f), {-SQRT_OF_2_DIV_2, -SQRT_OF_2_DIV_2}, mCoBG_WALL_SLATE_UP, DEG2SHORT_ANGLE2(45.0f), { SQRT_OF_2_DIV_2, SQRT_OF_2_DIV_2}, mCoBG_WALL_SLATE_UP}, + }; + // clang-format on + mCoBG_defence_wall_info_c* defence_p = defence_wall_info; + + for (i = 0; i < ARRAY_COUNT(defence_wall_info); i++) { + if (dx == defence_p->dx && dz == defence_p->dz) { + *normal0_p = defence_p->normal_angle0; + normal0[0] = defence_p->normal0[0]; + normal0[1] = defence_p->normal0[1]; + *wall_name0_p = defence_p->wall_name0; + + *normal1_p = defence_p->normal_angle1; + normal1[0] = defence_p->normal1[0]; + normal1[1] = defence_p->normal1[1]; + *wall_name1_p = defence_p->wall_name1; + + return i; + } + + defence_p++; + } + + return -1; +} + +static void mCoBG_MakeCircleDefenceWall(mCoBG_ActorInf_c* actor_info, s16 attr_wall) { + if (attr_wall && actor_info->old_on_ground) { + mCoBG_column_c* col0; + mCoBG_column_c* col1; + int col_count = l_VecInf.col_count; + mCoBG_unit_vec_info_c* all_unit_vec = l_VecInf.unit; + int* unit_count_p = &l_VecInf.unit_count; + mCoBG_unit_vec_info_c* unit_vec; + int i0; + int i1; + int dx; + int dz; + s16 normal_angle0; + s16 normal_angle1; + f32 normal0[2]; + f32 normal1[2]; + u8 wall_name0; + u8 wall_name1; + + col0 = l_VecInf.column; + for (i0 = 0; i0 < col_count; i0++) { + col1 = l_VecInf.column; + for (i1 = 0; i1 < col_count; i1++) { + if (i0 != i1 && mCoBG_CircleDefenceWallIdx(col0->ux - col1->ux, col0->uz - col1->uz, &normal_angle0, normal0, &wall_name0, &normal_angle1, normal1, &wall_name1) != -1) { + if (*unit_count_p < mCoBG_UNIT_VEC_INFO_MAX) { + unit_vec = &all_unit_vec[*unit_count_p]; + + unit_vec->start[0] = col0->pos.x; + unit_vec->start[1] = col0->pos.z; + unit_vec->end[0] = col1->pos.x; + unit_vec->end[1] = col1->pos.z; + unit_vec->normal[0] = normal0[0]; + unit_vec->normal[1] = normal0[1]; + unit_vec->normal_angle = normal_angle0; + unit_vec->regist_p = NULL; + unit_vec->atr_wall = TRUE; + unit_vec->wall_name = wall_name0; + (*unit_count_p)++; + } + + if (*unit_count_p < mCoBG_UNIT_VEC_INFO_MAX) { + unit_vec = &all_unit_vec[*unit_count_p]; + + unit_vec->start[0] = col0->pos.x; + unit_vec->start[1] = col0->pos.z; + unit_vec->end[0] = col1->pos.x; + unit_vec->end[1] = col1->pos.z; + unit_vec->normal[0] = normal1[0]; + unit_vec->normal[1] = normal1[1]; + unit_vec->normal_angle = normal_angle1; + unit_vec->regist_p = NULL; + unit_vec->atr_wall = TRUE; + unit_vec->wall_name = wall_name1; + (*unit_count_p)++; + } + } + + col1++; + } + + col0++; + } + } +} diff --git a/src/AUS/game/m_collision_bg_water.c_inc b/src/AUS/game/m_collision_bg_water.c_inc new file mode 100644 index 00000000..a6bfc7a3 --- /dev/null +++ b/src/AUS/game/m_collision_bg_water.c_inc @@ -0,0 +1,184 @@ +extern f32 mCoBG_GetBgY_AngleS_FromWpos2(s_xyz* ground_angle, xyz_t pos, f32 ground_dist) { + mCoBG_UnitInfo_c ut_info; + s_xyz normal_ground_angle; + f32 normal_y; + f32 column_y; + static s_xyz ground_angle0 = { 0, 0, 0 }; + f32 t0; + f32 t1; + f32 ret; + + if (ground_angle != NULL) { + *ground_angle = ground_angle0; + } + + mCoBG_Wpos2UnitInfo(&ut_info, pos); + normal_y = mCoBG_GetBGHeight_Normal(&normal_ground_angle, &ut_info); + column_y = mCoBG_GetBGHeight_Column(&pos, &ut_info); + + if (ground_angle != NULL && normal_y >= column_y && normal_y >= -100.0f) { + *ground_angle = normal_ground_angle; + return normal_y - ground_dist; + } + + t0 = MAX(normal_y, -100.0f); + t1 = MAX(normal_y, column_y); + if (t1 > t0) { + ret = MAX(normal_y, column_y); + } else { + ret = MAX(normal_y, -100.0f); + } + + return ret - ground_dist; +} + +extern f32 mCoBG_GetWaterHeight_File(xyz_t pos, char* file, int line) { + u32 attr; + int ux; + int uz; + mCoBG_Collision_u* col; + xyz_t mod_pos = pos; + + mFI_Wpos2UtNum(&ux, &uz, pos); + col = mFI_UtNum2UtCol(ux, uz); + attr = col->data.unit_attribute; + + if (attr == mCoBG_ATTRIBUTE_SEA || attr == mCoBG_ATTRIBUTE_37 || attr == mCoBG_ATTRIBUTE_38) { + return 20.0f; + } + + if (attr >= mCoBG_ATTRIBUTE_WATER && attr <= mCoBG_ATTRIBUTE_RIVER_NE) { + return 20.0f + mCoBG_GetBgY_AngleS_FromWpos2(NULL, pos, 0.0f); + } + + if (attr >= mCoBG_ATTRIBUTE_27 && attr <= mCoBG_ATTRIBUTE_35) { + int idx = attr - mCoBG_ATTRIBUTE_27; + int search = mCoBG_bridge_search_water[idx]; + u32 new_attr; + int i; + + for (i = 0; i < mSc_DIRECT_NUM; i++) { + if ((search & (1 << i)) != 0) { + int ux; + int uz; + + mCoBG_PlussDirectOffset(&mod_pos, pos, i); + mFI_Wpos2UtNum(&ux, &uz, mod_pos); + new_attr = mFI_UtNum2UtCol(ux, uz)->data.unit_attribute; + + if (new_attr >= mCoBG_ATTRIBUTE_WATER && new_attr <= mCoBG_ATTRIBUTE_RIVER_NE) { + return 20.0f + mCoBG_GetBgY_AngleS_FromWpos2(NULL, mod_pos, 0.0f); + } + } + } + } else if (attr >= mCoBG_ATTRIBUTE_39 && attr <= mCoBG_ATTRIBUTE_42) { + u32 attr2 = mCoBG_Wpos2Attribute(pos, NULL); + + if (attr2 >= mCoBG_ATTRIBUTE_WATER && attr2 <= mCoBG_ATTRIBUTE_RIVER_NE) { + int i; + u32 new_attr; + xyz_t new_pos; + int idx = attr - mCoBG_ATTRIBUTE_39; + int search = mCoBG_grass3_search_water[idx]; + + for (i = 0; i < mSc_DIRECT_NUM; i++) { + if ((search & (1 << i)) != 0) { + int ux; + int uz; + + mCoBG_PlussDirectOffset(&new_pos, pos, i); + mFI_Wpos2UtNum(&ux, &uz, new_pos); + new_attr = mFI_UtNum2UtCol(ux, uz)->data.unit_attribute; + + if (new_attr >= mCoBG_ATTRIBUTE_WATER && new_attr <= mCoBG_ATTRIBUTE_RIVER_NE) { + return 20.0f + mCoBG_GetBgY_AngleS_FromWpos2(NULL, new_pos, 0.0f); + } + } + } + } + } + + return -100.0f; +} + + +extern int mCoBG_CheckWaterAttribute(u32 attr) { + if (attr == mCoBG_ATTRIBUTE_SEA) { + return TRUE; + } + + if (attr >= mCoBG_ATTRIBUTE_WATER && attr <= mCoBG_ATTRIBUTE_RIVER_NE) { + return TRUE; + } + + return FALSE; +} + +extern int mCoBG_CheckWaterAttribute_OutOfSea(u32 attr) { + if (attr >= mCoBG_ATTRIBUTE_WATER && attr <= mCoBG_ATTRIBUTE_RIVER_NE) { + return TRUE; + } + + return FALSE; +} + +static f32 mCoBG_wave_cos = 0.0f; + +extern void mCoBG_WaveCos2BgCheck(f32 value) { + mCoBG_wave_cos = value; +} + +extern f32 mCoBG_WaveCos(void) { + return mCoBG_wave_cos; +} + +extern int mCoBG_GetWaterFlow(xyz_t* flow, u32 attr) { + static xyz_t flow_data[] = { + {0.0f, 0.0f, 0.0f}, + {0.0f, -5.0f, 0.0f}, + {0.0f, 0.0f, -0.5f}, + {-0.35355338f, 0.0f, -0.35355338f}, + {-0.5f, 0.0f, 0.0f}, + {-0.35355338f, 0.0f, 0.35355338f}, + {0.0f, 0.0f, 0.5f}, + {0.35355338f, 0.0f, 0.35355338f}, + {0.5f, 0.0f, 0.0f}, + {0.35355338f, 0.0f, -0.35355338f}, + }; + + if (attr == mCoBG_ATTRIBUTE_SEA) { + static const xyz_t sea_flow = { 0.0f, 0.0f, -1.0f }; + + *flow = sea_flow; + return TRUE; + } + + if (mCoBG_CheckWaterAttribute(attr)) { + int idx = attr - mCoBG_ATTRIBUTE_WATER; + + *flow = flow_data[idx]; + return TRUE; + } + + *flow = flow_data[0]; + return FALSE; +} + +extern int mCoBG_CheckWaveAttr(u32 attr) { + if (attr == mCoBG_ATTRIBUTE_WAVE || attr == mCoBG_ATTRIBUTE_36 || attr == mCoBG_ATTRIBUTE_25 || attr == mCoBG_ATTRIBUTE_26) { + return TRUE; + } + + return FALSE; +} + +// @unused, @fabricated +extern int mCoBG_CheckSand2Sea(xyz_t* pos) { + u32 attr = mCoBG_Wpos2BgAttribute_Original(*pos); + + if (attr == mCoBG_ATTRIBUTE_SEA || mCoBG_CheckWaveAttr(attr)) { + return TRUE; + } + + return FALSE; +}