From 81bbadf75dd9db3f5e952df4b2185cb59c5bd9ec Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Sat, 25 Jan 2025 22:24:46 -0500 Subject: [PATCH] Implement & link m_collision_bg --- configure.py | 2 +- include/libc64/math64.h | 1 + include/m_actor.h | 2 +- include/m_collision_bg.h | 165 ++- include/m_field_make.h | 1 + include/m_name_table.h | 9 + include/sys_matrix.h | 2 +- src/actor/ac_my_room_move.c_inc | 2 +- src/effect/ef_footprint.c | 2 +- src/game/m_actor.c | 2 +- src/game/m_actor_shadow.c | 4 +- src/game/m_all_grow_ovl.c | 4 +- src/game/m_collision_bg.c | 1729 +++++++++++++++++++++++-- src/game/m_collision_bg_block.c_inc | 88 ++ src/game/m_collision_bg_column.c_inc | 578 +++++++++ src/game/m_collision_bg_info.c_inc | 1116 ++++++++++++++++ src/game/m_collision_bg_line.c_inc | 593 +++++++++ src/game/m_collision_bg_math.c_inc | 500 +++++++ src/game/m_collision_bg_move.c_inc | 480 +++++++ src/game/m_collision_bg_rewrite.c_inc | 183 +++ src/game/m_collision_bg_wall.c_inc | 662 ++++++++++ src/game/m_collision_bg_water.c_inc | 184 +++ src/game/m_npc.c | 4 +- src/game/m_player_other_func.c_inc | 6 +- src/system/sys_matrix.c | 22 +- 25 files changed, 6203 insertions(+), 138 deletions(-) create mode 100644 src/game/m_collision_bg_block.c_inc create mode 100644 src/game/m_collision_bg_column.c_inc create mode 100644 src/game/m_collision_bg_info.c_inc create mode 100644 src/game/m_collision_bg_line.c_inc create mode 100644 src/game/m_collision_bg_math.c_inc create mode 100644 src/game/m_collision_bg_move.c_inc create mode 100644 src/game/m_collision_bg_rewrite.c_inc create mode 100644 src/game/m_collision_bg_wall.c_inc create mode 100644 src/game/m_collision_bg_water.c_inc diff --git a/configure.py b/configure.py index e96ecfd6..b382b912 100644 --- a/configure.py +++ b/configure.py @@ -1383,7 +1383,7 @@ config.libs = [ Object(Matching, "game/m_choice.c"), Object(Matching, "game/m_clip.c"), Object(Matching, "game/m_cockroach.c"), - Object(NonMatching, "game/m_collision_bg.c"), + Object(Matching, "game/m_collision_bg.c"), Object(Matching, "game/m_collision_obj.c"), Object(Matching, "game/m_common_data.c"), Object(Matching, "game/m_controller.c"), diff --git a/include/libc64/math64.h b/include/libc64/math64.h index 28c6d488..829736cb 100644 --- a/include/libc64/math64.h +++ b/include/libc64/math64.h @@ -7,6 +7,7 @@ extern "C" { #include "types.h" +#define SQRT_OF_2_DIV_2 0.70710678118654752440f #define SQRT_OF_2_F 1.41421356237309504880f #define SQRT_OF_3_F 1.73205080756887729353f diff --git a/include/m_actor.h b/include/m_actor.h index 27d6976c..eaf54f28 100644 --- a/include/m_actor.h +++ b/include/m_actor.h @@ -1077,7 +1077,7 @@ typedef struct actor_shape_info_s { /* 0x1C */ f32 shadow_alpha_change_rate; /* 0x20 */ int unk_20; /* 0x24 */ xyz_t* shadow_position; - /* 0x28 */ int unk_28; + /* 0x28 */ int move_bg_idx; /* 0x2C */ u8 draw_shadow; /* TRUE = shadow is drawn, FALSE = shadow is not drawn */ /* 0x2D */ u8 unk_2D; /* 0x2E */ u8 diff --git a/include/m_collision_bg.h b/include/m_collision_bg.h index aff84748..51bcbd27 100644 --- a/include/m_collision_bg.h +++ b/include/m_collision_bg.h @@ -10,6 +10,22 @@ extern "C" { #define mCoBG_HEIGHT_MAX 31 +#define mCoBG_ATR_NO_PLACE (0 << 3) +#define mCoBG_ATR_PLACE (1 << 3) + +#define mCoBG_ATR_NO_NPC (0 << 4) +#define mCoBG_ATR_NPC (1 << 4) + +enum { + mCoBG_PLANT0 = 0, /* Stay a sapling */ + mCoBG_PLANT1 = 1, /* Grow until the first stage of growth */ + mCoBG_PLANT2 = 2, /* Grow until the second stage of growth */ + mCoBG_PLANT3 = 3, /* Grow until the third stage of growth */ + mCoBG_PLANT4 = 4, /* Fully grow */ + + mCoBG_KILL_PLANT = 7 /* No growth, all plants die on this unit */ +}; + enum field_layer { mCoBG_LAYER0, mCoBG_LAYER1, @@ -103,13 +119,12 @@ enum background_attribute { }; enum { - mCoBG_PLANT0 = 0, /* Stay a sapling */ - mCoBG_PLANT1 = 1, /* Grow until the first stage of growth */ - mCoBG_PLANT2 = 2, /* Grow until the second stage of growth */ - mCoBG_PLANT3 = 3, /* Grow until the third stage of growth */ - mCoBG_PLANT4 = 4, /* Fully grow */ + mCoBG_DIM_XY, + mCoBG_DIM_XZ, + mCoBG_DIM_YZ, + mCoBG_DIM_ALL, - mCoBG_KILL_PLANT = 7 /* No growth, all plants die on this unit */ + mCoBG_DIM_NUM }; enum { @@ -141,14 +156,16 @@ enum { mCoBG_BLOCK_BGCHECK_MODE_NUM }; +extern int mCoBG_block_bgcheck_mode; + /* sizeof(mCoBG_CollisionData_c) == 4*/ typedef struct collision_bg_data_s { - /* 1------- -------- -------- -------- */ u32 shape : 1; /* collision shape */ + /* 1------- -------- -------- -------- */ u32 slate_flag : 1; /* collision shape */ /* -11111-- -------- -------- -------- */ u32 center : 5; /* ------11 111----- -------- -------- */ u32 top_left : 5; /* -------- ---11111 -------- -------- */ u32 bot_left : 5; - /* -------- -------- 11111--- -------- */ u32 top_right : 5; - /* -------- -------- -----111 11------ */ u32 bot_right : 5; + /* -------- -------- 11111--- -------- */ u32 bot_right : 5; + /* -------- -------- -----111 11------ */ u32 top_right : 5; /* -------- -------- -------- --111111 */ u32 unit_attribute : 6; /* background_attribute type */ } mCoBG_CollisionData_c; @@ -165,11 +182,10 @@ typedef struct collision_unit_info_s { f32 rightDown_offset; f32 rightUp_offset; f32 base_height; - f32 pos_x; - f32 pos_z; + f32 unit_pos[2]; int ut_x; int ut_z; - int shape; + u32 slate_flag; u8 attribute; mActor_name_t item; } mCoBG_UnitInfo_c; @@ -187,7 +203,7 @@ typedef struct collision_bg_check_result_s { // u32 hit_wall : 5; // 2 bits in prev byte u32 hit_wall_count : 3; - u32 unk_flag0 : 1; + u32 jump_flag : 1; // u32 unit_attribute : 6; // 1 bit in prev byte u32 is_on_move_bg_obj : 1; @@ -214,6 +230,26 @@ enum { mCoBG_WALL_TYPE_NUM }; +enum { + mCoBG_WALL_UP, + mCoBG_WALL_LEFT, + mCoBG_WALL_DOWN, + mCoBG_WALL_RIGHT, + mCoBG_WALL_SLATE_UP, + mCoBG_WALL_SLATE_DOWN, + + mCoBG_WALL_NUM +}; + +enum { + mCoBG_NORM_DIRECT_UP, + mCoBG_NORM_DIRECT_LEFT, + mCoBG_NORM_DIRECT_DOWN, + mCoBG_NORM_DIRECT_RIGHT, + + mCoBG_NORM_DIRECT_NUM +}; + typedef struct collision_bg_check_s { mCoBG_Collision_u collision_units[5]; mCoBG_CheckResult_c result; @@ -229,11 +265,19 @@ typedef struct bg_side_contact_s { s16 angle; } mCoBG_side_contact_c; +typedef struct bg_on_contact_s { + s16 name; +} mCoBG_on_contact_c; + +typedef struct bg_on_contact_inf_s { + mCoBG_on_contact_c contact[5]; + int count; +} mCoBG_on_contact_info_c; + typedef struct bg_contact_s { mCoBG_side_contact_c side_contact[5]; int side_count; - s16 on_contact_names[5]; - int on_count; + mCoBG_on_contact_info_c on_contact; } mCoBG_bg_contact_c; typedef struct bg_size_s { @@ -256,6 +300,12 @@ typedef struct bg_register_s { f32* scale_percent; } mCoBG_bg_regist_c; +#define mCoBG_MOVE_REGIST_MAX 64 +typedef struct bg_mgr_s { + mCoBG_bg_regist_c* regist_p[mCoBG_MOVE_REGIST_MAX]; + int count; +} mCoBG_mBgMgr_c; + typedef struct collision_offset_table_s { u8 unit_attribute; s8 centerRight_offset; @@ -266,31 +316,72 @@ typedef struct collision_offset_table_s { s8 shape; } mCoBG_OffsetTable_c; +typedef struct wall_height_s { + f32 top; + f32 bot; +} mCoBG_WallHeight_c; + +#define mCoBG_WALL_COL_NUM 2 + typedef struct collision_actor_info_s { - mActor_name_t name_id; - u8 _02; - u8 on_ground; + s16 name; + u8 check_type; + u8 old_on_ground; u8 _04; - u8 in_water; - u8 _06[2]; // alignment? + u8 old_in_water; + // u8 _06[2]; // alignment? mCoBG_CheckResult_c* check_res_p; - xz_t speed_xz0; - xz_t speed_xz1; + f32 speed_xz0[2]; + f32 speed_xz1[2]; xyz_t center_pos; xyz_t old_center_pos; xyz_t rev_pos; - u8 _40[4]; - f32 _44; - f32 _48; - f32 _4C; - u8 _50[0x20]; + f32 range; + f32 ground_dist; + f32 old_ground_y; + f32 ground_y; + mCoBG_WallHeight_c wall_height; + mCoBG_WallInfo_c wall_info[mCoBG_WALL_COL_NUM]; + s16 ut_count; + u32 _64; + int _68; + int _6C; } mCoBG_ActorInf_c; +enum { + mCoBG_UNIT_RADIAN, + mCoBG_UNIT_DEGREE, + mCoBG_UNIT_SHORT, + + mCoBG_UNIT_NUM +}; + +enum { + mCoBG_CHECK_TYPE_NORMAL, + mCoBG_CHECK_TYPE_PLAYER, + + mCoBG_CHECK_TYPE_NUM +}; + +enum { + mCoBG_REVERSE_TYPE_REVERSE, + mCoBG_REVERSE_TYPE_NO_REVERSE, + + mCoBG_REVERSE_TYPE_NUM +}; + +#define mCoBG_LINE_CHECK_WALL (1 << 0) +#define mCoBG_LINE_CHECK_GROUND (1 << 1) +#define mCoBG_LINE_CHECK_WATER (1 << 2) +#define mCoBG_LINE_CHECK_UNDERWATER (1 << 3) + +typedef int (*mCoBG_COLUMN_CHECK_ITEM_TYPE_PROC)(mActor_name_t item); + extern u32 mCoBG_Wpos2BgAttribute_Original(xyz_t wpos); -extern u32 mCoBG_Wpos2Attribute(xyz_t wpos, s8* is_diggable); +extern u32 mCoBG_Wpos2Attribute(xyz_t wpos, s8* cant_dig); extern int mCoBG_CheckWaterAttribute(u32 attribute); extern f32 mCoBG_GetBgY_AngleS_FromWpos(s_xyz* angle_to_ground, xyz_t wpos, f32 offset_y); -extern f32 mCoBG_GetShadowBgY_AngleS_FromWpos(f32, s_xyz*, xyz_t); +extern f32 mCoBG_GetShadowBgY_AngleS_FromWpos(s_xyz*, xyz_t, f32); extern int mCoBG_CheckWaterAttribute_OutOfSea(u32 attribute); extern int mCoBG_CheckHole_OrgAttr(u32 attribute); extern f32 mCoBG_GetBgY_OnlyCenter_FromWpos(xyz_t wpos, f32 dist); @@ -302,11 +393,11 @@ extern int mCoBG_Height2GetLayer(f32 height); extern void mCoBG_SetPlussOffset(xyz_t wpos, s16 offset, s16 new_attrib); extern int mCoBG_GetLayer(const xyz_t* wpos); extern int mCoBG_BnumUnum2HoleNumber(int block_x, int block_z, int ut_x, int ut_z); -extern u32 mCoBG_UtNum2BgAttr(int ut_x, int ut_z); +extern int mCoBG_UtNum2BgAttr(int ut_x, int ut_z); extern f32 mCoBG_UtNum2UtCenterY(int ut_x, int ut_z); extern int mCoBG_CheckCliffAttr(u32 attribute); -extern void mCoBG_SetPluss5PointOffset_file(xyz_t pos, mCoBG_OffsetTable_c offsetptr, const char* file, int line); -#define mCoBG_SetPluss5PointOffset(pos, offsetptr) mCoBG_SetPluss5PointOffset_file(pos, offsetptr, __FILE__, __LINE__); +extern void mCoBG_SetPluss5PointOffset_file(xyz_t pos, mCoBG_OffsetTable_c ofs_data, char* file, int line); +#define mCoBG_SetPluss5PointOffset(pos, ofs_data) mCoBG_SetPluss5PointOffset_file(pos, offsetptr, __FILE__, __LINE__); extern int mCoBG_Change2PoorAttr(mCoBG_Collision_u* col); extern int mCoBG_CheckHole(xyz_t wpos); extern int mCoBG_CheckSkySwing(xyz_t wpos); @@ -320,7 +411,7 @@ extern int mCoBG_ExistHeightGap_KeepAndNow_Detail(xyz_t wpos); extern int mCoBG_GetHoleNumber(xyz_t wpos); extern int mCoBG_Attr2CheckPlaceNpc(u32 attribute); extern int mCoBG_ExistHeightGap_KeepAndNow(xyz_t wpos); -extern void mCoBG_GetNorm_By3Point(xyz_t* norm, xyz_t* p0, xyz_t* p1, xyz_t* p2); +extern void mCoBG_GetNorm_By3Point(xyz_t* normal, f32* v0, f32* v1, f32* v2); extern int mCoBG_SearchWaterLimitDistN(xyz_t* water_pos, xyz_t wpos, s16 angle, float max_dist, int divisor); extern f32 mCoBG_GetBalloonGroundY(const xyz_t* pos); extern void mCoBG_MakeBoatCollision(ACTOR* actor, xyz_t* pos, s16* angle_y); @@ -335,7 +426,7 @@ extern int mCoBG_CheckSandHole_ClData(mCoBG_Collision_u* col); extern int mCoBG_GetHoleNumber_ClData(mCoBG_Collision_u* col); extern void mCoBG_GetBgNorm_FromWpos(xyz_t* norm, xyz_t wpos); extern int mCoBG_GetWaterFlow(xyz_t* water_flow, u32 attr); -extern void mCoBG_SetAttribute(xyz_t pos, u32 attr); +extern void mCoBG_SetAttribute(xyz_t pos, s16 attr); extern int mCoBG_GetPointInfoFrontLine(f32* line, f32* check_pos, f32* norm); extern int mCoBG_GetCrossCircleAndLine2Dvector(f32* cross0_xz, f32* cross1_xz, f32* point_xz, f32* vec_xz, f32* center_xz, f32 radius); @@ -363,6 +454,12 @@ extern void mCoBG_VirtualBGCheck(xyz_t* rev_pos_p, mCoBG_Check_c* bg_check, cons extern f32 mCoBG_Wpos2GroundCheckOnly(const xyz_t* pos_p, f32 ground_dist); extern int mCoBG_Wpos2CheckNpc(xyz_t wpos); extern void mCoBG_WallCheckOnly(xyz_t* rev_pos_p, ACTOR* actor, f32 range, f32 ground_dist, s16 rev_type, s16 check_type); +extern int mCoBG_GetCrossJudge_2Vector(f32* vec0_p0, f32* vec0_p1, f32* vec1_p0, f32* vec1_p1); +extern void mCoBG_GetCross2Line(f32* cross, f32* line0_p0, f32* line0_p1, f32* line1_p0, f32* line1_p1); +extern int mCoBG_GetPointInfoFrontLine(f32* start, f32* point, f32* normal); +extern int mCoBG_JudgePointInCircle(f32* point, f32* center, f32 radius); +extern f32 mCoBG_WaveCos(void); +extern mCoBG_bg_regist_c* mCoBG_Idx2RegistPointer(int move_bg_idx); typedef int (*mCoBG_LINECHECK_PROC)(mActor_name_t); diff --git a/include/m_field_make.h b/include/m_field_make.h index 1ac5254a..1d031c8f 100644 --- a/include/m_field_make.h +++ b/include/m_field_make.h @@ -34,6 +34,7 @@ extern "C" { #define FGBLOCKXZ_2_FGIDX(x, z) ((z) * FG_BLOCK_X_NUM + (x)) #define BLOCKXZ_2_BLOCKIDX(x, z) ((z) * BLOCK_X_NUM + (x)) +#define UNITXZ_2_UNIT(x, z) ((z) * UT_X_NUM + (x)) #define mFM_VISIBLE_BLOCK_NUM 4 /* number of visible blocks (nearest to the Player) */ #define mFM_SOUND_SOURCE_NUM 6 diff --git a/include/m_name_table.h b/include/m_name_table.h index a61723d4..e9f77557 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -549,6 +549,9 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define ITEM_IS_PAINT(item) ((item) >= ITM_RED_PAINT && (item) <= ITM_BROWN_PAINT) #define ITEM_IS_TOOL(item) ((item) >= ITM_TOOL_START && (item) < ITM_TOOL_END) +#define ITEM_IS_DUMMY_MAILBOX(item) ((item) >= DUMMY_MAILBOX0 && (item) <= DUMMY_MAILBOX3) +#define ITEM_IS_SIGN(item) ((item) == DUMMY_RESERVE || ITEM_IS_SIGNBOARD(item)) + #define BG_CATEGORY 0 #define ENV_CATEGORY 8 @@ -3047,6 +3050,10 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define NPC_END (NPC_START + 236) #define DUMMY_START 0xF000 +#define DUMMY_MAILBOX0 (DUMMY_START + 1) // 0xF001 +#define DUMMY_MAILBOX1 (DUMMY_START + 2) // 0xF002 +#define DUMMY_MAILBOX2 (DUMMY_START + 3) // 0xF003 +#define DUMMY_MAILBOX3 (DUMMY_START + 4) // 0xF004 #define DUMMY_NPC_HOUSE_START (DUMMY_START + 5) // 0xF005 #define DUMMY_NPC_HOUSE_000 (DUMMY_START + 5) // F005 #define DUMMY_NPC_HOUSE_001 (DUMMY_START + 6) // F006 @@ -3390,6 +3397,8 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define RSV_SHOP_SOLD_UMBRELLA 0xFE16 #define RSV_SHOP_SOLD_PAINT 0xFE17 #define RSV_SHOP_SOLD_SIGNBOARD 0xFE18 +#define RSV_HOLE 0xFE19 +#define RSV_TREE 0xFE1A #define RSV_DOOR 0xFE1B #define RSV_FE1C 0xFE1C #define RSV_FE1F 0xFE1F diff --git a/include/sys_matrix.h b/include/sys_matrix.h index 77fd30c2..7e7f004e 100644 --- a/include/sys_matrix.h +++ b/include/sys_matrix.h @@ -31,7 +31,7 @@ extern void Matrix_softcv3_load(s_xyz* src, f32 x, f32 y, f32 z); extern Mtx* _MtxF_to_Mtx(MtxF* src, Mtx* dest); extern Mtx* _Matrix_to_Mtx(Mtx* dest); extern Mtx* _Matrix_to_Mtx_new(GRAPH* graph); -extern void Matrix_Position(xyz_t* old_pos, xyz_t* new_pos); +extern void Matrix_Position(xyz_t* input_position, xyz_t* output_position); extern void Matrix_Position_Zero(xyz_t* screen_pos); extern void Matrix_Position_VecX(f32 x, xyz_t* screen_pos); extern void Matrix_Position_VecZ(f32 z, xyz_t* screen_pos); diff --git a/src/actor/ac_my_room_move.c_inc b/src/actor/ac_my_room_move.c_inc index 54bb82ff..c5acea27 100644 --- a/src/actor/ac_my_room_move.c_inc +++ b/src/actor/ac_my_room_move.c_inc @@ -676,7 +676,7 @@ static int aMR_GroundFlat(xyz_t* pos) { mCoBG_Collision_u* col = mFI_GetUnitCol(*pos); if (col->data.center == col->data.top_left && col->data.center == col->data.bot_left && - col->data.center == col->data.top_right && col->data.center == col->data.bot_right) { + col->data.center == col->data.bot_right && col->data.center == col->data.top_right) { return TRUE; } diff --git a/src/effect/ef_footprint.c b/src/effect/ef_footprint.c index 602d8439..507773e9 100644 --- a/src/effect/ef_footprint.c +++ b/src/effect/ef_footprint.c @@ -55,7 +55,7 @@ static void eFootPrint_ct(eEC_Effect_c* effect, GAME* game, void* ct_arg) { int sum_angle_x = 0; int sum_angle_z = 0; - effect->position.y = 2.0f + mCoBG_GetShadowBgY_AngleS_FromWpos(0.0f, NULL, effect->position); + effect->position.y = 2.0f + mCoBG_GetShadowBgY_AngleS_FromWpos(NULL, effect->position, 0.0f); effect->effect_specific[2] = data->angle; /* Get the total ground angle (x & z) in a triangle around the effect position */ diff --git a/src/game/m_actor.c b/src/game/m_actor.c index 347156ce..7a72c94a 100644 --- a/src/game/m_actor.c +++ b/src/game/m_actor.c @@ -100,7 +100,7 @@ extern void Shape_Info_init(ACTOR* actor, f32 ofs_y, mActor_shadow_proc shadow_p actor->shape_info.shadow_position = &actor->world.position; // ??? #endif - actor->shape_info.unk_28 = -1; + actor->shape_info.move_bg_idx = -1; actor->shape_info.unk_2D = 0; } diff --git a/src/game/m_actor_shadow.c b/src/game/m_actor_shadow.c index 64bd649c..2152d208 100644 --- a/src/game/m_actor_shadow.c +++ b/src/game/m_actor_shadow.c @@ -148,7 +148,7 @@ void mActorShadow_GetShadowTopPos_GetSlideS(Shadow_Info* shadow) { wpos.y = shadow->position.y + base.y; wpos.z = shadow->position.z + base.z; res = 0; - bg_y = mCoBG_GetShadowBgY_AngleS_FromWpos(0.0f, NULL, wpos); + bg_y = mCoBG_GetShadowBgY_AngleS_FromWpos(NULL, wpos, 0.0f); if ((shadow->position.y - bg_y) > 20.0f) { shadow->unk34 = 28; return; @@ -292,7 +292,7 @@ int mActorShadow_GetShadowKind(void) { } f32 mAc_GetShadowGroundY_NoneForce(const Shadow_Info* shadow) { - f32 res = mCoBG_GetShadowBgY_AngleS_FromWpos(0.0f, NULL, shadow->position); + f32 res = mCoBG_GetShadowBgY_AngleS_FromWpos(NULL, shadow->position, 0.0f); return res; } diff --git a/src/game/m_all_grow_ovl.c b/src/game/m_all_grow_ovl.c index c1eea0af..64d4aec9 100644 --- a/src/game/m_all_grow_ovl.c +++ b/src/game/m_all_grow_ovl.c @@ -2268,7 +2268,7 @@ static void mAGrw_GetDepositAbleFlatNum(u8* candidate_num, u8* flat_num, mActor_ /* Check if the unit collision data is a flat square */ if ((col->data.center == col->data.top_left) && (col->data.center == col->data.bot_left) && - (col->data.center == col->data.top_right) && (col->data.center == col->data.bot_right) && + (col->data.center == col->data.bot_right) && (col->data.center == col->data.top_right) && (mCoBG_CheckSandHole_ClData(col) != TRUE)) { flat_num[0]++; } @@ -2298,7 +2298,7 @@ static void mAGrw_SetShineGroundBlock(mAGrw_SSPosInfo_c* pos_info, mActor_name_t (mCoBG_CheckHole_OrgAttr(col->data.unit_attribute))) { /* Check if the unit collision data is a flat square */ if ((col->data.center == col->data.top_left) && (col->data.center == col->data.bot_left) && - (col->data.center == col->data.top_right) && (col->data.center == col->data.bot_right) && + (col->data.center == col->data.bot_right) && (col->data.center == col->data.top_right) && (mCoBG_CheckSandHole_ClData(col) != TRUE)) { if (selected_ut == 0) { pos_info->ut_x = ut_x; diff --git a/src/game/m_collision_bg.c b/src/game/m_collision_bg.c index b1746996..08274c5c 100644 --- a/src/game/m_collision_bg.c +++ b/src/game/m_collision_bg.c @@ -3,6 +3,102 @@ #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}, +}; + +#include "../src/game/m_collision_bg_math.c_inc" static xyz_t mCoBG_unit_offset[mCoBG_DIRECT_NUM] = { { 0.0f, 0.0f, -mFI_UNIT_BASE_SIZE_F }, @@ -16,7 +112,6 @@ static xyz_t mCoBG_unit_offset[mCoBG_DIRECT_NUM] = { }; 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; @@ -30,9 +125,9 @@ static void mCoBG_SetXyz_t(xyz_t* pos, f32 x, f32 y, f32 z) { pos->z = z; } -static void mCoBG_SetXZ(xz_t* xz, f32 x, f32 z) { - xz->x = x; - xz->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) { @@ -52,9 +147,9 @@ static void mCoBG_Unit2UnitInfo_OutOfUnitPos(mCoBG_UnitInfo_c* unit_info, int ut 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->rightUp_offset = unit_info->collision->data.top_right * 10.0f + unit_info->base_height; unit_info->rightDown_offset = unit_info->collision->data.bot_right * 10.0f + unit_info->base_height; - unit_info->shape = unit_info->collision->data.shape; + 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); @@ -75,8 +170,8 @@ static void mCoBG_Wpos2UnitInfo(mCoBG_UnitInfo_c* unit_info, xyz_t wpos) { 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->pos_x = upos.x; - unit_info->pos_z = upos.z; + unit_info->unit_pos[0] = upos.x; + unit_info->unit_pos[1] = upos.z; } @@ -135,8 +230,8 @@ NOTE: The top of the triangle is denoted as the "bottom" by the devs as it is in /* 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->pos_x; - f32 z = unit_info->pos_z; + 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) { @@ -156,62 +251,62 @@ static void mCoBG_GetUnitArea(mCoBG_UnitInfo_c* unit_info, s16* unit_area) { } -static void mCoBG_GetGroundAngleFromVtx3(s_xyz* ground_angle, xyz_t* v0, xyz_t* v1, xyz_t* v2, s16 unit_area) { +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->x + v2->x); - avg.y = 0.5f * (v1->y + v2->y); - avg.z = 0.5f * (v1->z + v2->z); + 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->z - avg.z; - a1 = v0->y - avg.y; + a0 = v0[2] - avg.z; + a1 = v0[1] - avg.y; ground_angle->x = atans_table(a0, -a1); - a0 = v1->x - v2->x; - a1 = v1->y - v2->y; + 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->z; - a1 = -(avg.y - v0->y); + a0 = avg.z - v0[2]; + a1 = -(avg.y - v0[1]); ground_angle->x = atans_table(a0, a1); - a0 = v2->x - v1->x; - a1 = v2->y - v1->y; + a0 = v2[0] - v1[0]; + a1 = v2[1] - v1[1]; ground_angle->z = atans_table(a0, a1); break; } case mCoBG_AREA_W: { - a0 = v2->z - v1->z; - a1 = v2->y - v1->y; + a0 = v2[2] - v1[2]; + a1 = v2[1] - v1[1]; ground_angle->x = atans_table(a0, -a1); - a0 = v0->x - avg.x; - a1 = v0->y - avg.y; + a0 = v0[0] - avg.x; + a1 = v0[1] - avg.y; ground_angle->z = atans_table(a0, a1); break; } case mCoBG_AREA_E: { - a0 = v1->z - v2->z; - a1 = -(v1->y - v2->y); + a0 = v1[2] - v2[2]; + a1 = -(v1[1] - v2[1]); ground_angle->x = atans_table(a0, a1); - a0 = avg.x - v0->x; - a1 = avg.y - v0->y; + a0 = avg.x - v0[0]; + a1 = avg.y - v0[1]; ground_angle->z = atans_table(a0, a1); break; } @@ -219,66 +314,66 @@ static void mCoBG_GetGroundAngleFromVtx3(s_xyz* ground_angle, xyz_t* v0, xyz_t* } } -static void mCoBG_GetArea3Point(s16 area, xyz_t* v0, xyz_t* v1, xyz_t* v2, mCoBG_Collision_u* col) { +static void mCoBG_GetArea3Point(s16 area, f32* v0, f32* v1, f32* v2, mCoBG_Collision_u* col) { switch (area) { case mCoBG_AREA_N: { - v0->y = col->data.center * 10.0f; - v1->x = mFI_UT_WORLDSIZE_HALF_X_F; - v1->y = col->data.bot_right * 10.0f; - v1->z = -mFI_UT_WORLDSIZE_HALF_Z_F; - v2->x = -mFI_UT_WORLDSIZE_HALF_X_F; - v2->y = col->data.top_left * 10.0f; /* BUG? Shouldn't this be bot_left (top = +Z, bot = -Z) of the triangle */ - v2->z = -mFI_UT_WORLDSIZE_HALF_Z_F; + 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->y = col->data.center * 10.0f; - v1->x = -mFI_UT_WORLDSIZE_HALF_X_F; - v1->y = col->data.top_left * 10.0f; - v1->z = -mFI_UT_WORLDSIZE_HALF_Z_F; - v2->x = -mFI_UT_WORLDSIZE_HALF_X_F; - v2->y = col->data.bot_left * 10.0f; - v2->z = mFI_UT_WORLDSIZE_HALF_Z_F; + 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->y = col->data.center * 10.0f; - v1->x = -mFI_UT_WORLDSIZE_HALF_X_F; - v1->y = col->data.bot_left * 10.0f; /* BUG? Shouldn't this be top_left (top = +Z, bot = -Z) of the triangle */ - v1->z = mFI_UT_WORLDSIZE_HALF_Z_F; - v2->x = mFI_UT_WORLDSIZE_HALF_X_F; - v2->y = col->data.top_right * 10.0f; - v2->z = mFI_UT_WORLDSIZE_HALF_Z_F; + 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->y = col->data.center * 10.0f; - v1->x = mFI_UT_WORLDSIZE_HALF_X_F; - v1->y = col->data.top_right * 10.0f; - v1->z = mFI_UT_WORLDSIZE_HALF_Z_F; - v2->x = mFI_UT_WORLDSIZE_HALF_X_F; - v2->y = col->data.bot_right * 10.0f; - v2->z = -mFI_UT_WORLDSIZE_HALF_Z_F; + 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) { - xyz_t v0 = { 0.0f, 0.0f, 0.0f }; - xyz_t v1 = { 0.0f, 0.0f, 0.0f }; - xyz_t v2 = { 0.0f, 0.0f, 0.0f }; + 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); + 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; @@ -310,9 +405,9 @@ static void mCoBG_AdjustActorY(xyz_t* rev_pos, ACTOR* actor, f32 ground_y, f32 w check_res->on_ground = TRUE; actor->position_speed.y = 0.0f; // stop actor from moving downward anymore } - else if (actor_info->on_ground && actor_info->_48 > actor_info->_4C) { + 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(actor_info->speed_xz0.x * actor_info->speed_xz0.x + actor_info->speed_xz0.z * actor_info->speed_xz0.z); + 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; @@ -324,13 +419,13 @@ static void mCoBG_AdjustActorY(xyz_t* rev_pos, ACTOR* actor, f32 ground_y, f32 w } 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->pos_x + norm->z * unit_info->pos_z); + 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(xz_t* speed, ACTOR* actor) { - speed->x = actor->world.position.x - actor->last_world_position.x; - speed->z = actor->world.position.z - actor->last_world_position.z; +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) { @@ -344,7 +439,7 @@ static void mCoBG_CarryOutReverse(ACTOR* actor, xyz_t rev_pos, s16 type) { xyz_t pos = actor->world.position; f32 water_height = mCoBG_GetWaterHeight_File(pos, __FILE__, 1303); - if ((pos.y + l_ActorInf._44) <= water_height) { + if ((pos.y + l_ActorInf.ground_dist) <= water_height) { actor->bg_collision_check.result.is_in_water = TRUE; } } @@ -378,29 +473,1495 @@ static void mCoBG_MakeSizeUnitInfo(mCoBG_UnitInfo_c *unit_info, int ut_x, int ut } -static void mCoBG_MakeTab2MoveTail(xz_t* dst_xz, xz_t* src_xz) { - f32 x_bias = ABS(src_xz->x) / (ABS(src_xz->x) + ABS(src_xz->z)); +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->x > 0.0f) { - dst_xz->x -= x_bias * 0.2f; + if (src_xz[0] > 0.0f) { + dst_xz[0] -= x_bias * 0.2f; } - else if (src_xz->x < 0.0f) { - dst_xz->x += x_bias * 0.2f; + else if (src_xz[0] < 0.0f) { + dst_xz[0] += x_bias * 0.2f; } - if (src_xz->z > 0.0f) { - dst_xz->z -= z_bias * 0.2f; + if (src_xz[1] > 0.0f) { + dst_xz[1] -= z_bias * 0.2f; } - else if (src_xz->z < 0.0f) { - dst_xz->z += 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* can_dig) { +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, can_dig); + 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/game/m_collision_bg_wall.c_inc" +#include "../src/game/m_collision_bg_move.c_inc" +#include "../src/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/game/m_collision_bg_info.c_inc" +#include "../src/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/game/m_collision_bg_block.c_inc" +#include "../src/game/m_collision_bg_line.c_inc" +#include "../src/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/game/m_collision_bg_block.c_inc b/src/game/m_collision_bg_block.c_inc new file mode 100644 index 00000000..a4978635 --- /dev/null +++ b/src/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/game/m_collision_bg_column.c_inc b/src/game/m_collision_bg_column.c_inc new file mode 100644 index 00000000..e8eea076 --- /dev/null +++ b/src/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/game/m_collision_bg_info.c_inc b/src/game/m_collision_bg_info.c_inc new file mode 100644 index 00000000..8c43eb4b --- /dev/null +++ b/src/game/m_collision_bg_info.c_inc @@ -0,0 +1,1116 @@ +// @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; +} + +// 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/game/m_collision_bg_line.c_inc b/src/game/m_collision_bg_line.c_inc new file mode 100644 index 00000000..7c42abf1 --- /dev/null +++ b/src/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, 0); + Matrix_RotateY(angle, 1); + Matrix_translate(ofs.x, ofs.y, ofs.z, 1); + + 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/game/m_collision_bg_math.c_inc b/src/game/m_collision_bg_math.c_inc new file mode 100644 index 00000000..b8772777 --- /dev/null +++ b/src/game/m_collision_bg_math.c_inc @@ -0,0 +1,500 @@ +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; +} + +static 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); + } +} + +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 + ); +} + +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; +} + +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; +} diff --git a/src/game/m_collision_bg_move.c_inc b/src/game/m_collision_bg_move.c_inc new file mode 100644 index 00000000..11bbd97b --- /dev/null +++ b/src/game/m_collision_bg_move.c_inc @@ -0,0 +1,480 @@ +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; +} + +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/game/m_collision_bg_rewrite.c_inc b/src/game/m_collision_bg_rewrite.c_inc new file mode 100644 index 00000000..0422f1ca --- /dev/null +++ b/src/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/game/m_collision_bg_wall.c_inc b/src/game/m_collision_bg_wall.c_inc new file mode 100644 index 00000000..8fefa0b3 --- /dev/null +++ b/src/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/game/m_collision_bg_water.c_inc b/src/game/m_collision_bg_water.c_inc new file mode 100644 index 00000000..a6bfc7a3 --- /dev/null +++ b/src/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; +} diff --git a/src/game/m_npc.c b/src/game/m_npc.c index 1829fb8e..3211304d 100644 --- a/src/game/m_npc.c +++ b/src/game/m_npc.c @@ -4650,7 +4650,7 @@ extern int mNpc_GetMakeUtNuminBlock_hard_area(int* ut_x, int* ut_z, int bx, int /* Check that the height of each point on the unit is equal*/ if ((int)center == col_p->data.top_left && center == col_p->data.bot_left && - center == col_p->data.top_right && (int)center == col_p->data.bot_right) { + center == col_p->data.bot_right && (int)center == col_p->data.top_right) { now_ut_x = 8 - j; now_ut_z = 8 - i; @@ -4839,7 +4839,7 @@ extern int mNpc_GetMakeUtNuminBlock_hide_hard_area(int* ut_x, int* ut_z, int bx, /* Check that the height of each point on the unit is equal*/ if ((int)center == col_p->data.top_left && center == col_p->data.bot_left && - center == col_p->data.top_right && (int)center == col_p->data.bot_right && + center == col_p->data.bot_right && (int)center == col_p->data.top_right && ((hide_ut_bit[i] >> j) & 1) == 1) { now_ut_x = 8 - j; diff --git a/src/game/m_player_other_func.c_inc b/src/game/m_player_other_func.c_inc index 4b7af85d..22d395b7 100644 --- a/src/game/m_player_other_func.c_inc +++ b/src/game/m_player_other_func.c_inc @@ -160,7 +160,7 @@ static int Player_actor_check_bg_for_next_goto(ACTOR* actor, mActor_name_t door) if (door >= DOOR_START && door < EXIT_DOOR) { col = mFI_GetUnitCol(actor->world.position); if (col->data.center != col->data.top_left || col->data.center != col->data.bot_left || - col->data.center != col->data.top_right || col->data.center != col->data.bot_right) { + col->data.center != col->data.bot_right || col->data.center != col->data.top_right) { return TRUE; } return FALSE; @@ -190,9 +190,9 @@ static void Player_actor_check_nextgoto(ACTOR* actor, GAME* game) { mFI_GetUnitCol(actor->world.position)->data.center != mFI_GetUnitCol(actor->world.position)->data.bot_left || mFI_GetUnitCol(actor->world.position)->data.center != - mFI_GetUnitCol(actor->world.position)->data.top_right || + mFI_GetUnitCol(actor->world.position)->data.bot_right || mFI_GetUnitCol(actor->world.position)->data.center != - mFI_GetUnitCol(actor->world.position)->data.bot_right) && + mFI_GetUnitCol(actor->world.position)->data.top_right) && mFI_GET_TYPE(mFI_GetFieldId()) == mFI_FIELD_PLAYER0_ROOM) { aMR_SaveWaltzTempo2(); mBGMPsComp_make_ps_wipe(0x10E); diff --git a/src/system/sys_matrix.c b/src/system/sys_matrix.c index bdb48780..ee337197 100644 --- a/src/system/sys_matrix.c +++ b/src/system/sys_matrix.c @@ -609,14 +609,26 @@ Mtx* _Matrix_to_Mtx_new(GRAPH* graph) { return _Matrix_to_Mtx(GRAPH_ALLOC(graph, sizeof(Mtx))); } -void Matrix_Position(xyz_t* old_pos, xyz_t* new_pos) { - MtxF* curm = Matrix_now; +void Matrix_Position(xyz_t* input_position, xyz_t* output_position) { + MtxF* current_matrix = Matrix_now; - new_pos->x = (curm->xx * old_pos->x) + (curm->xy * old_pos->y) + (curm->xz * old_pos->z) + curm->xw; - new_pos->y = (curm->yx * old_pos->x) + (curm->yy * old_pos->y) + (curm->yz * old_pos->z) + curm->yw; - new_pos->z = (curm->zx * old_pos->x) + (curm->zy * old_pos->y) + (curm->zz * old_pos->z) + curm->zw; + output_position->x = (current_matrix->xx * input_position->x) + + (current_matrix->xy * input_position->y) + + (current_matrix->xz * input_position->z) + + current_matrix->xw; + + output_position->y = (current_matrix->yx * input_position->x) + + (current_matrix->yy * input_position->y) + + (current_matrix->yz * input_position->z) + + current_matrix->yw; + + output_position->z = (current_matrix->zx * input_position->x) + + (current_matrix->zy * input_position->y) + + (current_matrix->zz * input_position->z) + + current_matrix->zw; } + void Matrix_Position_Zero(xyz_t* v) { MtxF* curm = Matrix_now;