Files
perfect-dark/src/lib/collision.c
T
2024-10-27 21:02:45 +10:00

4279 lines
109 KiB
C

#include <ultra64.h>
#include "constants.h"
#include "game/prop.h"
#include "game/text.h"
#include "game/bg.h"
#include "bss.h"
#include "lib/dma.h"
#include "lib/memp.h"
#include "lib/mtx.h"
#include "lib/lib_17ce0.h"
#include "lib/anim.h"
#include "lib/collision.h"
#include "lib/lib_2f490.h"
#include "lib/libc/ll.h"
#include "data.h"
#include "types.h"
#define SURFACE_FLOOR 0
#define SURFACE_CEILING 1
struct debugtri {
s16 vertices[3][3];
u8 unk12;
};
union filedataptr g_TileFileData;
s32 g_TileNumRooms;
u32 *g_TileRooms;
bool var8009a8ac;
f32 var8009a8b0;
s32 var8009a8b4;
struct coord g_CdEdgeVtx1;
s32 var8009a8c4;
struct coord g_CdEdgeVtx2;
struct prop *g_CdObstacleProp;
s32 var8009a8d8;
s32 var8009a8dc;
struct coord g_CdObstaclePos;
s32 var8009a8ec;
f32 var8009a8f0;
bool g_CdHasSavedPos;
struct coord g_CdPos1;
s32 var8009a904;
struct coord g_CdPos2;
s32 var8009a914;
struct geoblock g_CdSavedBlock;
struct geo *g_CdObstacleGeo;
s32 var8009a968;
s32 var8009a96c;
s32 var8005f030 = 0;
bool g_CdHasSavedBlock = false;
s32 var8005f038 = 0;
void cd_get_geo_normal(struct geo *geo, struct coord *normal);
f32 cd_00024e40(void)
{
return var8009a8f0;
}
void cd_get_edge(struct coord *vtx1, struct coord *vtx2, u32 line, char *file)
{
vtx1->x = g_CdEdgeVtx1.x;
vtx1->y = g_CdEdgeVtx1.y;
vtx1->z = g_CdEdgeVtx1.z;
vtx2->x = g_CdEdgeVtx2.x;
vtx2->y = g_CdEdgeVtx2.y;
vtx2->z = g_CdEdgeVtx2.z;
}
f32 cd_get_distance(void)
{
return var8009a8b0;
}
bool cd_has_distance(void)
{
return var8009a8ac;
}
struct prop *cd_get_obstacle_prop(void)
{
return g_CdObstacleProp;
}
void cd_get_pos(struct coord *pos, u32 line, char *file)
{
pos->x = g_CdObstaclePos.x;
pos->y = g_CdObstaclePos.y;
pos->z = g_CdObstaclePos.z;
}
void cd_get_obstacle_normal(struct coord *normal)
{
cd_get_geo_normal(g_CdObstacleGeo, normal);
}
u32 cd_get_geo_flags(void)
{
u32 flags = 0;
switch (g_CdObstacleGeo->type) {
case GEOTYPE_TILE_I:
flags = g_CdObstacleGeo->flags;
break;
case GEOTYPE_TILE_F:
flags = g_CdObstacleGeo->flags;
break;
case GEOTYPE_BLOCK:
flags = GEOFLAG_WALL | GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT;
break;
case GEOTYPE_CYL:
flags = g_CdObstacleGeo->flags;
break;
}
return flags;
}
void cd_clear_results(void)
{
var8009a8b4 = 0;
var8009a8ac = false;
g_CdObstacleProp = NULL;
var8009a8d8 = 0;
var8009a8ec = 0;
g_CdHasSavedPos = false;
g_CdHasSavedBlock = false;
var8005f038 = 0;
}
void cd_set_obstacle_vtx_prop(struct coord *vtx1, struct coord *vtx2, struct prop *prop)
{
g_CdEdgeVtx1.x = vtx1->x;
g_CdEdgeVtx1.y = vtx1->y;
g_CdEdgeVtx1.z = vtx1->z;
g_CdEdgeVtx2.x = vtx2->x;
g_CdEdgeVtx2.y = vtx2->y;
g_CdEdgeVtx2.z = vtx2->z;
var8009a8b4 = 1;
var8009a8ac = false;
g_CdObstacleProp = prop;
var8009a8d8 = 0;
var8009a8ec = 0;
g_CdHasSavedPos = false;
g_CdHasSavedBlock = false;
var8005f038 = 0;
}
void cd_set_obstacle_vtx_prop_flt(struct coord *vtx1, struct coord *vtx2, struct prop *prop, f32 arg3)
{
var8009a8b0 = arg3;
g_CdEdgeVtx1.x = vtx1->x;
g_CdEdgeVtx1.y = vtx1->y;
g_CdEdgeVtx1.z = vtx1->z;
g_CdEdgeVtx2.x = vtx2->x;
g_CdEdgeVtx2.y = vtx2->y;
g_CdEdgeVtx2.z = vtx2->z;
var8009a8b4 = 1;
var8009a8ac = true;
g_CdObstacleProp = prop;
var8009a8d8 = 0;
var8009a8ec = 0;
g_CdHasSavedPos = false;
g_CdHasSavedBlock = false;
var8005f038 = 0;
}
void cd_000250cc(struct coord *arg0, struct coord *arg1, f32 width)
{
struct widthxz sp34;
struct xz sp2c;
struct xz sp24;
struct xz sp1c;
sp34.width = width;
sp34.x = arg0->x;
sp34.z = arg0->z;
sp1c.x = arg1->x;
sp1c.z = arg1->z;
sp2c.x = g_CdEdgeVtx1.x;
sp2c.z = g_CdEdgeVtx1.z;
sp24.x = g_CdEdgeVtx2.x;
sp24.z = g_CdEdgeVtx2.z;
var8009a8b0 = func0f1579cc(&sp34, &sp2c, &sp24, &sp1c);
var8009a8ac = true;
}
void cd_set_obstacle_prop(struct prop *prop)
{
var8009a8b4 = 0;
var8009a8ac = false;
g_CdObstacleProp = prop;
var8009a8d8 = 0;
var8009a8ec = 0;
g_CdHasSavedPos = false;
g_CdHasSavedBlock = false;
var8005f038 = 0;
}
void cd_set_obstacle_vtx_col_prop(struct coord *vtxpos1, struct coord *vtxpos2, struct coord *collisionpos, struct prop *prop)
{
g_CdEdgeVtx1.x = vtxpos1->x;
g_CdEdgeVtx1.y = vtxpos1->y;
g_CdEdgeVtx1.z = vtxpos1->z;
g_CdEdgeVtx2.x = vtxpos2->x;
g_CdEdgeVtx2.y = vtxpos2->y;
g_CdEdgeVtx2.z = vtxpos2->z;
g_CdObstaclePos.x = collisionpos->x;
g_CdObstaclePos.y = collisionpos->y;
g_CdObstaclePos.z = collisionpos->z;
var8009a8b4 = 1;
var8009a8ac = false;
g_CdObstacleProp = prop;
var8009a8d8 = 1;
var8009a8ec = 0;
g_CdHasSavedPos = false;
g_CdHasSavedBlock = false;
var8005f038 = 0;
}
void cd_set_obstacle_vtx_col_prop_flt_geo(struct coord *vtxpos1, struct coord *vtxpos2, struct coord *collisionpos, struct prop *prop, f32 arg4, struct geo *geo)
{
g_CdEdgeVtx1.x = vtxpos1->x;
g_CdEdgeVtx1.y = vtxpos1->y;
g_CdEdgeVtx1.z = vtxpos1->z;
g_CdEdgeVtx2.x = vtxpos2->x;
g_CdEdgeVtx2.y = vtxpos2->y;
g_CdEdgeVtx2.z = vtxpos2->z;
g_CdObstaclePos.x = collisionpos->x;
g_CdObstaclePos.y = collisionpos->y;
g_CdObstaclePos.z = collisionpos->z;
var8009a8b4 = 1;
var8009a8ac = false;
g_CdObstacleProp = prop;
var8009a8d8 = 1;
var8009a8f0 = arg4;
var8009a8ec = 1;
g_CdHasSavedPos = false;
g_CdHasSavedBlock = false;
g_CdObstacleGeo = geo;
var8005f038 = 1;
}
void cd_set_saved_pos(struct coord *pos1, struct coord *pos2)
{
g_CdPos1.x = pos1->x;
g_CdPos1.y = pos1->y;
g_CdPos1.z = pos1->z;
g_CdPos2.x = pos2->x;
g_CdPos2.y = pos2->y;
g_CdPos2.z = pos2->z;
g_CdHasSavedPos = true;
}
bool cd_get_saved_pos(struct coord *pos1, struct coord *pos2)
{
if (g_CdHasSavedPos) {
pos1->x = g_CdPos1.x;
pos1->y = g_CdPos1.y;
pos1->z = g_CdPos1.z;
pos2->x = g_CdPos2.x;
pos2->y = g_CdPos2.y;
pos2->z = g_CdPos2.z;
}
return g_CdHasSavedPos;
}
void cd_set_saved_block(struct geoblock *block)
{
g_CdSavedBlock = *block;
g_CdHasSavedBlock = true;
}
s32 cd_00025410(f32 arg0, f32 arg1, f32 arg2, f32 arg3)
{
f32 f0 = arg0 * arg3;
f32 f2 = arg1 * arg2;
if (f2 < f0) {
return 1;
}
if (f2 > f0) {
return -1;
}
if (arg0 * arg2 < 0.0f || arg1 * arg3 < 0.0f) {
return -1;
}
if (arg0 * arg0 + arg1 * arg1 < arg2 * arg2 + arg3 * arg3) {
return 1;
}
return 0;
}
s32 cd_000254d8(struct coord *arg0, struct coord *arg1, f32 arg2, f32 arg3, f32 arg4, f32 arg5, s32 *arg6)
{
f32 sp54;
f32 sp50;
f32 sp4c;
f32 sp48;
s32 sp44;
s32 sp40;
s32 sp3c;
s32 sp38;
s32 sp34;
s32 sp30;
bool result = false;
sp54 = arg0->x - arg2;
sp50 = arg0->z - arg3;
sp3c = cd_00025410(arg4 - arg2, arg5 - arg3, sp54, sp50);
sp44 = cd_00025410(arg4 - arg2, arg5 - arg3, arg1->x - arg2, arg1->z - arg3);
sp38 = sp3c * sp44;
if (sp38 <= 0) {
sp4c = arg1->x - arg0->x;
sp48 = arg1->z - arg0->z;
sp34 = cd_00025410(sp4c, sp48, -sp54, -sp50);
sp40 = cd_00025410(sp4c, sp48, arg4 - arg0->x, arg5 - arg0->z);
sp30 = sp34 * sp40;
if (sp30 <= 0) {
result = true;
}
}
if (*arg6 && (result || sp3c <= 0)) {
*arg6 = 0;
}
return result;
}
f32 cd_00025654(f32 x1, f32 z1, f32 x2, f32 z2, f32 x3, f32 z3)
{
u32 stack[8];
f32 result;
result = sqrtf((x2 - x1) * (x2 - x1) + (z2 - z1) * (z2 - z1));
if (result == 0.0f) {
return sqrtf((x3 - x2) * (x3 - x2) + (z3 - z2) * (z3 - z2));
}
return ((x3 - x1) * (z2 - z1) + -(x2 - x1) * (z3 - z1)) / result;
}
f32 cd_00025724(f32 x1, f32 z1, f32 x2, f32 z2)
{
x2 -= x1;
z2 -= z1;
return sqrtf(x2 * x2 + z2 * z2);
}
bool cd_00025774(f32 x1, f32 z1, f32 x2, f32 z2, f32 x3, f32 z3)
{
f32 f0;
f32 f2;
f32 f16;
f32 f18;
x3 -= x1;
z3 -= z1;
f0 = x2 - x1;
f2 = z2 - z1;
f16 = x3 * f0 + z3 * f2;
f18 = f0 * f0 + f2 * f2;
return (f18 < f16 && f16 < 0) || (f16 > 0 && f16 < f18);
}
void cd_00025848(f32 tilex, f32 tilez, f32 tilewidth, f32 posx, f32 posz, f32 *x1, f32 *z1, f32 *x2, f32 *z2)
{
posx -= tilex;
posz -= tilez;
if (posx != 0 || posz != 0) {
f32 dist = sqrtf(posx * posx + posz * posz);
if (dist > 0) {
dist = tilewidth / dist;
posx *= dist;
posz *= dist;
}
}
*x1 = tilex + posx + posz;
*z1 = tilez + posz - posx;
*x2 = tilex + posx - posz;
*z2 = tilez + posz + posx;
}
void cd_get_geo_normal(struct geo *geo, struct coord *normal)
{
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) geo;
s32 sp38[3];
s32 sp2c[3];
s32 sp20[3];
sp38[0] = tile->vertices[1][0] - tile->vertices[0][0];
sp38[1] = tile->vertices[1][1] - tile->vertices[0][1];
sp38[2] = tile->vertices[1][2] - tile->vertices[0][2];
sp2c[0] = tile->vertices[2][0] - tile->vertices[0][0];
sp2c[1] = tile->vertices[2][1] - tile->vertices[0][1];
sp2c[2] = tile->vertices[2][2] - tile->vertices[0][2];
sp20[0] = sp38[1] * sp2c[2] - sp38[2] * sp2c[1];
sp20[1] = sp38[2] * sp2c[0] - sp38[0] * sp2c[2];
sp20[2] = sp38[0] * sp2c[1] - sp38[1] * sp2c[0];
normal->x = sp20[0];
normal->y = sp20[1];
normal->z = sp20[2];
} else if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) geo;
f32 sp10[3];
f32 sp04[3];
sp10[0] = tile->vertices[1].x - tile->vertices[0].x;
sp10[1] = tile->vertices[1].y - tile->vertices[0].y;
sp10[2] = tile->vertices[1].z - tile->vertices[0].z;
sp04[0] = tile->vertices[2].x - tile->vertices[0].x;
sp04[1] = tile->vertices[2].y - tile->vertices[0].y;
sp04[2] = tile->vertices[2].z - tile->vertices[0].z;
normal->x = sp10[1] * sp04[2] - sp10[2] * sp04[1];
normal->y = sp10[2] * sp04[0] - sp10[0] * sp04[2];
normal->z = sp10[0] * sp04[1] - sp10[1] * sp04[0];
} else if (geo->type == GEOTYPE_BLOCK) {
normal->x = 0;
normal->y = 1;
normal->z = 0;
} else if (geo->type == GEOTYPE_CYL) {
normal->x = 0;
normal->y = 1;
normal->z = 0;
}
}
void cd_get_floor_col(struct geo *geo, u16 *floorcol)
{
if (geo == NULL) {
*floorcol = 0xfff;
return;
}
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) geo;
*floorcol = tile->floorcol;
return;
}
if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) geo;
*floorcol = tile->floorcol;
return;
}
if (geo->type == GEOTYPE_BLOCK) {
*floorcol = 0xfff;
return;
}
if (geo->type == GEOTYPE_CYL) {
*floorcol = 0xfff;
}
}
void cd_get_floor_type(struct geo *geo, u8 *floortype)
{
bool water = false;
if (geo && (geo->flags & GEOFLAG_UNDERWATER)) {
water = true;
}
if (geo == NULL) {
*floortype = 0xff;
return;
}
if (water) {
*floortype = FLOORTYPE_WATER;
return;
}
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile0 = (struct geotilei *) geo;
*floortype = tile0->floortype;
return;
}
if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile1 = (struct geotilef *) geo;
*floortype = tile1->floortype;
return;
}
if (geo->type == GEOTYPE_BLOCK) {
*floortype = 0xff;
return;
}
if (geo->type == GEOTYPE_CYL) {
*floortype = 0xff;
}
}
f32 cd_find_ground_in_int_tile_at_vertex(struct geotilei *tile, f32 x, f32 z, s32 vertexindex)
{
struct coord sp7c;
struct coord sp70;
s64 sp68;
s64 sp60;
s64 sp58;
s64 tmp;
f32 ground;
s32 next;
if (vertexindex == 0) {
vertexindex = 1;
}
next = (vertexindex + 1) % tile->header.numvertices;
if (next == 0) {
next = 1;
}
sp7c.x = tile->vertices[vertexindex][0] - tile->vertices[0][0];
sp7c.y = tile->vertices[vertexindex][1] - tile->vertices[0][1];
sp7c.z = tile->vertices[vertexindex][2] - tile->vertices[0][2];
sp70.x = tile->vertices[next][0] - tile->vertices[0][0];
sp70.y = tile->vertices[next][1] - tile->vertices[0][1];
sp70.z = tile->vertices[next][2] - tile->vertices[0][2];
sp58 = sp7c.f[1] * sp70.f[2] - sp7c.f[2] * sp70.f[1];
sp60 = sp7c.f[2] * sp70.f[0] - sp7c.f[0] * sp70.f[2];
sp68 = sp7c.f[0] * sp70.f[1] - sp7c.f[1] * sp70.f[0];
tmp = sp58 * tile->vertices[0][0]
+ sp60 * tile->vertices[0][1]
+ sp68 * tile->vertices[0][2];
if (sp60 == 0) {
return *(s16 *)(tile->ymax + (uintptr_t)tile);
}
ground = (tmp - (f64)x * sp58 - (f64)z * sp68) / sp60;
if (ground > *(s16 *)(tile->ymax + (uintptr_t)tile)) {
ground = *(s16 *)(tile->ymax + (uintptr_t)tile);
} else if (ground < *(s16 *)(tile->ymin + (uintptr_t)tile)) {
ground = *(s16 *)(tile->ymin + (uintptr_t)tile);
}
return ground;
}
#if VERSION < VERSION_NTSC_1_0
f32 cd_find_ground_in_tile_type0_at_vertex1(struct geotilei *tile, f32 x, f32 z)
{
return cd_find_ground_in_int_tile_at_vertex(tile, x, z, 1);
}
#endif
f32 cd_find_ground_in_int_tile(struct geotilei *tile, f32 x, f32 z)
{
s32 i = 1;
s32 ival = -1;
struct geotilei *tile2 = tile;
if (tile->header.numvertices >= 4) {
while (i < tile->header.numvertices) {
f32 tmpz = tile2->vertices[i][2];
f32 tmpx = tile2->vertices[i][0];
f32 fval = ((tile->vertices[0][2] - tmpz) * (x - tmpx))
- ((tile2->vertices[0][0] - tmpx) * (0, z - tmpz));
if (fval != 0) {
if (ival < 0) {
ival = (fval > 0);
} else if (ival != 0 && fval < 0) {
i--;
break;
} else if (ival == 0 && fval > 0) {
i--;
break;
}
}
i++;
}
}
return cd_find_ground_in_int_tile_at_vertex(tile, x, z, i);
}
f32 cd_find_ground_in_flt_tile(struct geotilef *tile, f32 x, f32 z)
{
struct coord sp24;
struct coord sp18;
struct coord sp0c;
f32 tmp;
f32 ground;
sp24.x = tile->vertices[1].x - tile->vertices[0].x;
sp24.y = tile->vertices[1].y - tile->vertices[0].y;
sp24.z = tile->vertices[1].z - tile->vertices[0].z;
sp18.x = tile->vertices[2].x - tile->vertices[0].x;
sp18.y = tile->vertices[2].y - tile->vertices[0].y;
sp18.z = tile->vertices[2].z - tile->vertices[0].z;
sp0c.x = sp24.f[1] * sp18.f[2] - sp24.f[2] * sp18.f[1];
sp0c.y = sp24.f[2] * sp18.f[0] - sp24.f[0] * sp18.f[2];
sp0c.z = sp24.f[0] * sp18.f[1] - sp24.f[1] * sp18.f[0];
tmp = sp0c.f[0] * tile->vertices[0].f[0]
+ sp0c.f[1] * tile->vertices[0].f[1]
+ sp0c.f[2] * tile->vertices[0].f[2];
if (sp0c.f[1] == 0) {
return tile->vertices[tile->max[1]].y;
}
ground = (tmp - (f64)x * (f64)sp0c.f[0] - (f64)z * (f64)sp0c.f[2]) / (f64)sp0c.f[1];
if (ground > tile->vertices[tile->max[1]].y) {
ground = tile->vertices[tile->max[1]].y;
} else if (ground < tile->vertices[tile->min[1]].y) {
ground = tile->vertices[tile->min[1]].y;
}
return ground;
}
bool cd_is2d_point_in_int_tile(struct geotilei *tile, f32 x, f32 z)
{
s32 result = -1;
s32 numvertices = tile->header.numvertices;
s32 i;
for (i = 0; i < numvertices; i++) {
s32 next = (i + 1) % numvertices;
f32 value = ((f32)tile->vertices[next][2] - (f32)tile->vertices[i][2]) * (x - tile->vertices[i][0])
- ((f32)tile->vertices[next][0] - (f32)tile->vertices[i][0]) * (z - tile->vertices[i][2]);
if (value != 0) {
if (i == 0 || result < 0) {
result = (value > 0);
} else {
if (result != 0 && value < 0) {
return false;
}
if (result == 0 && value > 0) {
return false;
}
}
}
}
if (result < 0) {
return false;
}
return true;
}
bool cd_is2d_point_in_flt_tile(struct geotilef *tile, f32 x, f32 z)
{
s32 result = -1;
s32 numvertices = tile->header.numvertices;
s32 i;
for (i = 0; i < numvertices; i++) {
s32 next = (i + 1) % numvertices;
f32 value = (tile->vertices[next].z - tile->vertices[i].z) * (x - tile->vertices[i].x)
- (tile->vertices[next].x - tile->vertices[i].x) * (z - tile->vertices[i].z);
if (value != 0) {
if (i == 0 || result < 0) {
result = (value > 0);
} else {
if (result != 0 && value < 0) {
return false;
}
if (result == 0 && value > 0) {
return false;
}
}
}
}
if (result < 0) {
return false;
}
return true;
}
bool cd_is_2d_point_in_block(struct geoblock *tile, f32 x, f32 z)
{
s32 result = -1;
s32 numvertices = tile->header.numvertices;
s32 i;
for (i = 0; i < numvertices; i++) {
s32 next = (i + 1) % numvertices;
f32 value = (tile->vertices[next][1] - tile->vertices[i][1]) * (x - tile->vertices[i][0])
- (tile->vertices[next][0] - tile->vertices[i][0]) * (z - tile->vertices[i][1]);
if (value != 0) {
if (i == 0 || result < 0) {
result = (value > 0);
} else {
if (result != 0 && value < 0) {
return false;
}
if (result == 0 && value > 0) {
return false;
}
}
}
}
if (result < 0) {
return false;
}
return true;
}
bool cd_is_2d_point_in_cyl(struct geocyl *cyl, f32 x, f32 z)
{
f32 xdiff = x - cyl->x;
f32 zdiff = z - cyl->z;
return xdiff * xdiff + zdiff * zdiff <= cyl->radius * cyl->radius;
}
bool cd_is_2d_point_in_geo(f32 x, f32 z, struct geo *geo)
{
if (geo == NULL) {
return false;
}
if (geo->type == GEOTYPE_BLOCK) {
return cd_is_2d_point_in_block((struct geoblock *) geo, x, z);
}
if (geo->type == GEOTYPE_CYL) {
return cd_is_2d_point_in_cyl((struct geocyl *) geo, x, z);
}
return false;
}
/**
* For a lift or escalator step, find the props which are riding on it.
*/
void cd_get_props_on_platform(struct prop *platform, s16 *propnums, s32 maxlen)
{
u8 *start;
u8 *end;
s16 roompropnums[257];
struct prop *prop;
s16 *roompropnumptr;
struct geo *geo;
s32 len = 0;
if (prop_get_geometry(platform, &start, &end)) {
room_get_props(platform->rooms, roompropnums, 256);
roompropnumptr = roompropnums;
while (*roompropnumptr >= 0) {
prop = &g_Vars.props[*roompropnumptr];
if (prop != platform) {
geo = (struct geo *) start;
while (geo < (struct geo *) end) {
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) geo;
geo = (struct geo *)((uintptr_t)geo + sizeof(struct geotilei) + sizeof(tile->vertices[0]) * (tile->header.numvertices - ARRAYCOUNT(tile->vertices)));
} else if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) geo;
struct coord *pos = &prop->pos;
if ((geo->flags & (GEOFLAG_FLOOR1 | GEOFLAG_FLOOR2))
&& pos->x >= tile->vertices[tile->min[0]].x
&& pos->x <= tile->vertices[tile->max[0]].x
&& pos->z >= tile->vertices[tile->min[2]].z
&& pos->z <= tile->vertices[tile->max[2]].z
&& pos->y >= tile->vertices[tile->min[1]].y
&& cd_is2d_point_in_flt_tile(tile, pos->x, pos->z)
&& pos->y >= cd_find_ground_in_flt_tile(tile, pos->x, pos->z)) {
break;
}
geo = (struct geo *)((uintptr_t)geo + sizeof(struct geotilef) + sizeof(struct coord) * (tile->header.numvertices - ARRAYCOUNT(tile->vertices)));
} else if (geo->type == GEOTYPE_BLOCK) {
geo = (struct geo *)((uintptr_t)geo + sizeof(struct geoblock));
} else if (geo->type == GEOTYPE_CYL) {
geo = (struct geo *)((uintptr_t)geo + sizeof(struct geocyl));
}
}
if (geo < (struct geo *) end) {
if (len < maxlen - 2) {
propnums[len] = *roompropnumptr;
len++;
} else {
break;
}
}
}
roompropnumptr++;
}
}
propnums[len] = -1;
}
#if VERSION < VERSION_NTSC_1_0
void cd_set_prop_y_bounds(struct prop *prop, f32 ymax, f32 ymin)
{
u8 *start;
u8 *end;
if (prop_get_geometry(prop, &start, &end)) {
struct geo *geo = (struct geo *) start;
while (geo < (struct geo *) end) {
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) geo;
geo = (struct geo *)((uintptr_t)geo + sizeof(struct geotilei) + sizeof(tile->vertices[0]) * (tile->header.numvertices - ARRAYCOUNT(tile->vertices)));
} else if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) geo;
geo = (struct geo *)((uintptr_t)geo + sizeof(struct geotilef) + sizeof(struct coord) * (tile->header.numvertices - ARRAYCOUNT(tile->vertices)));
} else if (geo->type == GEOTYPE_BLOCK) {
struct geoblock *block = (struct geoblock *) geo;
block->ymax = ymax;
block->ymin = ymin;
geo = (struct geo *)((uintptr_t)geo + sizeof(struct geoblock));
} else if (geo->type == GEOTYPE_CYL) {
struct geocyl *cyl = (struct geocyl *) geo;
cyl->ymax = ymax;
cyl->ymin = ymin;
geo = (struct geo *)((uintptr_t)geo + sizeof(struct geocyl));
}
}
}
}
#endif
bool cd_00026a04(struct coord *pos, u8 *start, u8 *end, u16 geoflags, s32 room, struct geo **tileptr, s32 *roomptr, f32 *groundptr, bool ceiling)
{
bool result = false;
struct geo *geo = (struct geo *) start;
if (room);
while (geo < (struct geo *) end) {
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) geo;
if ((geo->flags & geoflags)
&& pos->x >= *(s16 *)(tile->xmin + (uintptr_t)tile)
&& pos->x <= *(s16 *)(tile->xmax + (uintptr_t)tile)
&& pos->z >= *(s16 *)(tile->zmin + (uintptr_t)tile)
&& pos->z <= *(s16 *)(tile->zmax + (uintptr_t)tile)) {
if ((!ceiling && pos->y >= *(s16 *)(tile->ymin + (uintptr_t)tile))
|| (ceiling && pos->y <= *(s16 *)(tile->ymax + (uintptr_t)tile))) {
if (cd_is2d_point_in_int_tile(tile, pos->x, pos->z)) {
f32 ground = cd_find_ground_in_int_tile(tile, pos->x, pos->z);
if ((!ceiling && ground <= pos->y && ground > *groundptr)
|| (ceiling && ground >= pos->y && ground < *groundptr)) {
*groundptr = ground;
*tileptr = geo;
*roomptr = room;
result = true;
}
}
}
}
geo = (struct geo *)((uintptr_t)geo + sizeof(struct geotilei) + sizeof(tile->vertices[0]) * (tile->header.numvertices - ARRAYCOUNT(tile->vertices)));
} else if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) geo;
if ((geo->flags & geoflags)
&& pos->x >= tile->vertices[tile->min[0]].x
&& pos->x <= tile->vertices[tile->max[0]].x
&& pos->z >= tile->vertices[tile->min[2]].z
&& pos->z <= tile->vertices[tile->max[2]].z) {
if ((!ceiling && pos->y >= tile->vertices[tile->min[1]].y)
|| (ceiling && pos->y <= tile->vertices[tile->max[1]].y)) {
if (cd_is2d_point_in_flt_tile(tile, pos->x, pos->z)) {
f32 ground = cd_find_ground_in_flt_tile(tile, pos->x, pos->z);
if ((!ceiling && pos->y >= ground && ground > *groundptr)
|| (ceiling && pos->y <= ground && ground < *groundptr)) {
*groundptr = ground;
*tileptr = geo;
*roomptr = room;
result = true;
}
}
}
}
geo = (struct geo *)((uintptr_t)geo + sizeof(struct geotilef) + sizeof(struct coord) * (tile->header.numvertices - ARRAYCOUNT(tile->vertices)));
} else if (geo->type == GEOTYPE_BLOCK) {
geo = (struct geo *)((uintptr_t)geo + sizeof(struct geoblock));
} else if (geo->type == GEOTYPE_CYL) {
geo = (struct geo *)((uintptr_t)geo + sizeof(struct geocyl));
}
}
return result;
}
void cd_find_closest_vertical(struct coord *pos, RoomNum *rooms, u16 geoflags, struct geo **geoptr, RoomNum *roomptr, f32 *groundptr, struct prop **propptr, bool ceiling)
{
RoomNum *roomptr2;
s32 roomnum;
u8 *start;
u8 *end;
f32 closesty;
struct geo *geo = NULL;
s32 room = 0;
struct prop *bestprop = NULL;
s16 *propnumptr;
s16 propnums[256];
if (ceiling) {
closesty = 4294967296;
} else {
closesty = -4294967296;
}
roomptr2 = rooms;
roomnum = rooms[0];
while (roomnum != -1) {
if (roomnum < g_TileNumRooms) {
start = g_TileFileData.u8 + g_TileRooms[roomnum];
end = g_TileFileData.u8 + g_TileRooms[roomnum + 1];
cd_00026a04(pos, start, end, geoflags, roomnum, &geo, &room, &closesty, ceiling);
}
roomptr2++;
roomnum = *roomptr2;
}
room_get_props(rooms, propnums, 256);
propnumptr = propnums;
while (*propnumptr >= 0) {
struct prop *prop = &g_Vars.props[*propnumptr];
if (prop_get_geometry(prop, &start, &end)
&& cd_00026a04(pos, start, end, geoflags, prop->rooms[0], &geo, &room, &closesty, ceiling)) {
bestprop = prop;
}
propnumptr++;
}
*geoptr = geo;
*roomptr = room;
*groundptr = closesty;
if (propptr != NULL) {
*propptr = bestprop;
}
}
bool cd_0002709c_int_tile(struct geotilei *tile, f32 x, f32 z, f32 radius, struct prop *prop, struct collision *collision)
{
bool result = false;
if (cd_is2d_point_in_int_tile(tile, x, z)) {
collision->geo = &tile->header;
collision->vertexindex = 0;
collision->prop = prop;
result = true;
} else {
s32 numvertices = tile->header.numvertices;
s32 i;
for (i = 0; i < numvertices; i++) {
s32 next = (i + 1) % numvertices;
f32 value = cd_00025654(tile->vertices[i][0], tile->vertices[i][2], tile->vertices[next][0], tile->vertices[next][2], x, z);
if (value < 0) {
value = -value;
}
if (value <= radius
&& (cd_00025724(tile->vertices[i][0], tile->vertices[i][2], x, z) <= radius
|| cd_00025724(tile->vertices[next][0], tile->vertices[next][2], x, z) <= radius
|| cd_00025774(tile->vertices[i][0], tile->vertices[i][2], tile->vertices[next][0], tile->vertices[next][2], x, z))) {
collision->geo = &tile->header;
collision->vertexindex = i;
collision->prop = prop;
result = true;
break;
}
}
}
return result;
}
bool cd_000272f8_flt_tile(struct geotilef *tile, f32 x, f32 z, f32 radius, struct prop *prop, struct collision *collision)
{
bool result = false;
if (cd_is2d_point_in_flt_tile(tile, x, z)) {
collision->geo = &tile->header;
collision->vertexindex = 0;
collision->prop = prop;
result = true;
} else {
s32 numvertices = tile->header.numvertices;
s32 i;
for (i = 0; i < numvertices; i++) {
s32 next = (i + 1) % numvertices;
f32 value = cd_00025654(tile->vertices[i].x, tile->vertices[i].z, tile->vertices[next].x, tile->vertices[next].z, x, z);
if (value < 0) {
value = -value;
}
if (value <= radius
&& (cd_00025724(tile->vertices[i].x, tile->vertices[i].z, x, z) <= radius
|| cd_00025724(tile->vertices[next].x, tile->vertices[next].z, x, z) <= radius
|| cd_00025774(tile->vertices[i].x, tile->vertices[i].z, tile->vertices[next].x, tile->vertices[next].z, x, z))) {
collision->geo = &tile->header;
collision->vertexindex = i;
collision->prop = prop;
result = true;
break;
}
}
}
return result;
}
s32 cd_000274e0_block(struct geoblock *tile, f32 x, f32 z, f32 radius, struct prop *prop, struct collision *collision)
{
bool result = false;
if (cd_is_2d_point_in_block(tile, x, z)) {
if (collision) {
collision->geo = &tile->header;
collision->vertexindex = 0;
collision->prop = prop;
}
result = true;
} else {
s32 numvertices = tile->header.numvertices;
s32 i;
for (i = 0; i < numvertices; i++) {
s32 next = (i + 1) % numvertices;
f32 value = cd_00025654(tile->vertices[i][0], tile->vertices[i][1],
tile->vertices[next][0], tile->vertices[next][1],
x, z);
if (value < 0) {
value = -value;
}
if (value <= radius
&& (cd_00025724(tile->vertices[i][0], tile->vertices[i][1], x, z) <= radius
|| cd_00025724(tile->vertices[next][0], tile->vertices[next][1], x, z) <= radius
|| cd_00025774(tile->vertices[i][0], tile->vertices[i][1], tile->vertices[next][0], tile->vertices[next][1], x, z))) {
if (collision) {
collision->geo = &tile->header;
collision->vertexindex = i;
collision->prop = prop;
}
result = true;
break;
}
}
}
return result;
}
bool cd_000276c8_cyl(struct geocyl *cyl, f32 x, f32 z, f32 radius, struct prop *prop, struct collision *collision)
{
bool result = false;
f32 sumx = x - cyl->x;
f32 sumz = z - cyl->z;
f32 sumwidth = cyl->radius + radius;
if (sumx * sumx + sumz * sumz <= sumwidth * sumwidth) {
result = true;
if (collision) {
collision->geo = &cyl->header;
collision->vertexindex = 0;
collision->prop = prop;
}
}
return result;
}
s32 cd_test_ramp_wall(struct geotilei *tile, struct coord *pos, f32 width, f32 y1, f32 y2);
void cd_collect_geo_for_cyl_from_list(struct coord *pos, f32 radius, u8 *start, u8 *end, u16 geoflags,
bool checkvertical, f32 arg6, f32 arg7, struct prop *prop,
struct collision *collisions, s32 maxcollisions, s32 *numcollisions, s32 roomnum)
{
struct geo *geo = (struct geo *) start;
s32 result;
while (geo < (struct geo *) end) {
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) geo;
if ((geo->flags & geoflags)
&& pos->x >= *(s16 *)(tile->xmin + (uintptr_t)tile) - radius
&& pos->x <= *(s16 *)(tile->xmax + (uintptr_t)tile) + radius
&& pos->z >= *(s16 *)(tile->zmin + (uintptr_t)tile) - radius
&& pos->z <= *(s16 *)(tile->zmax + (uintptr_t)tile) + radius
&& (!checkvertical || (pos->y + arg6 >= *(s16 *)(tile->ymin + (uintptr_t)tile)
&& pos->y + arg7 <= *(s16 *)(tile->ymax + (uintptr_t)tile)))) {
if (geo->flags & GEOFLAG_RAMPWALL) {
result = cd_test_ramp_wall(tile, pos, radius, pos->y + arg7, pos->y + arg6);
} else {
result = 1;
}
if (result != 0) {
if (cd_0002709c_int_tile(tile, pos->x, pos->z, radius, prop, &collisions[*numcollisions])) {
collisions[*numcollisions].room = roomnum;
*numcollisions = *numcollisions + 1;
if (*numcollisions >= maxcollisions) {
break;
}
}
}
}
geo = (struct geo *)((uintptr_t)geo + GEOTILEI_SIZE(tile));
} else if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) geo;
if ((geo->flags & geoflags)
&& pos->x >= tile->vertices[tile->min[0]].x - radius
&& pos->x <= tile->vertices[tile->max[0]].x + radius
&& pos->z >= tile->vertices[tile->min[2]].z - radius
&& pos->z <= tile->vertices[tile->max[2]].z + radius
&& (!checkvertical || (pos->y + arg6 >= tile->vertices[tile->min[1]].y
&& pos->y + arg7 <= tile->vertices[tile->max[1]].y))) {
result = cd_000272f8_flt_tile(tile, pos->x, pos->z, radius, prop, &collisions[*numcollisions]);
if (result != 0) {
collisions[*numcollisions].room = roomnum;
*numcollisions = *numcollisions + 1;
if (*numcollisions >= maxcollisions) {
break;
}
}
}
geo = (struct geo *)((uintptr_t)geo + GEOTILEF_SIZE(tile));
} else if (geo->type == GEOTYPE_BLOCK) {
struct geoblock *block = (struct geoblock *) geo;
if ((geoflags & (GEOFLAG_WALL | GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT))
&& (!checkvertical || (pos->y + arg6 >= block->ymin && pos->y + arg7 <= block->ymax))) {
result = cd_000274e0_block(block, pos->x, pos->z, radius, prop, &collisions[*numcollisions]);
if (result) {
collisions[*numcollisions].room = roomnum;
*numcollisions = *numcollisions + 1;
if (*numcollisions >= maxcollisions) {
break;
}
}
}
geo = (struct geo *)((uintptr_t)geo + GEOBLOCK_SIZE(block));
} else if (geo->type == GEOTYPE_CYL) {
struct geocyl *cyl = (struct geocyl *) geo;
if ((geoflags & geo->flags)
&& (!checkvertical || (pos->y + arg6 >= cyl->ymin && pos->y + arg7 <= cyl->ymax))) {
result = cd_000276c8_cyl(cyl, pos->x, pos->z, radius, prop, &collisions[*numcollisions]);
if (result) {
collisions[*numcollisions].room = roomnum;
*numcollisions = *numcollisions + 1;
if (*numcollisions >= maxcollisions) {
break;
}
}
}
geo = (struct geo *)((uintptr_t)geo + GEOCYL_SIZE(cyl));
}
}
}
void cd_collect_geo_for_cyl(struct coord *pos, f32 radius, RoomNum *rooms, u32 types, u16 geoflags, bool checkvertical, f32 ymax, f32 ymin, struct collision *collisions, s32 maxcollisions)
{
RoomNum *roomptr;
s32 roomnum;
u8 *start;
u8 *end;
s32 numcollisions = 0;
s16 *propnumptr;
s16 propnums[256];
// Check BG
if (types & CDTYPE_BG) {
roomptr = rooms;
roomnum = rooms[0];
while (roomnum != -1) {
if (roomnum < g_TileNumRooms) {
start = g_TileFileData.u8 + g_TileRooms[roomnum];
end = g_TileFileData.u8 + g_TileRooms[roomnum + 1];
cd_collect_geo_for_cyl_from_list(pos, radius, start, end, geoflags, checkvertical, ymax, ymin, NULL, collisions, maxcollisions, &numcollisions, roomnum);
if (numcollisions >= maxcollisions) {
goto end;
}
}
roomptr++;
roomnum = *roomptr;
}
}
// Check props
room_get_props(rooms, propnums, 256);
propnumptr = propnums;
while (*propnumptr >= 0) {
struct prop *prop = &g_Vars.props[*propnumptr];
if (prop_is_of_cd_type(prop, types) && prop_get_geometry(prop, &start, &end)) {
cd_collect_geo_for_cyl_from_list(pos, radius, start, end, geoflags, checkvertical, ymax, ymin, prop, collisions, maxcollisions, &numcollisions, prop->rooms[0]);
if (numcollisions >= maxcollisions) {
break;
}
}
propnumptr++;
}
end:
collisions[numcollisions].geo = NULL;
}
void cd_00027f78(struct geotilei *tile, f32 arg1, f32 arg2, f32 arg3, struct prop *prop, struct collision *collisions, s32 maxcollisions, s32 *numcollisions)
{
s32 i;
s32 numvertices = tile->header.numvertices;
for (i = 0; i < numvertices; i++) {
s32 next = (i + 1) % numvertices;
if (tile->vertices[i][0] != tile->vertices[next][0] || tile->vertices[i][2] != tile->vertices[next][2]) {
f32 f0 = cd_00025654(tile->vertices[i][0], tile->vertices[i][2], tile->vertices[next][0], tile->vertices[next][2], arg1, arg2);
if (f0 < 0.0f) {
f0 = -f0;
}
if (f0 <= arg3
&& (cd_00025724(tile->vertices[i][0], tile->vertices[i][2], arg1, arg2) <= arg3
|| cd_00025724(tile->vertices[next][0], tile->vertices[next][2], arg1, arg2) <= arg3
|| cd_00025774(tile->vertices[i][0], tile->vertices[i][2], tile->vertices[next][0], tile->vertices[next][2], arg1, arg2))) {
if (*numcollisions < maxcollisions) {
collisions[*numcollisions].geo = &tile->header;
collisions[*numcollisions].vertexindex = i;
collisions[*numcollisions].prop = prop;
*numcollisions += 1;
} else {
break;
}
}
}
}
}
/**
* Triangular wall tiles are generally implemented with just a bounding box check,
* but this means if the player gets on top of one they can walk across it.
* This is a problem for ramps that the player can jump off at any height
* such as the Air Base staircase near the baggage terminal.
*
* To handle this, the ramp wall tiles are flagged with GEOFLAG_RAMPWALL.
* When collision checks are being done, tiles with this flag are passed to
* this function which does a more extensive check.
*/
s32 cd_test_ramp_wall(struct geotilei *tile, struct coord *pos, f32 width, f32 y1, f32 y2)
{
s32 count;
s32 i;
s32 y1count;
s32 y2count;
s32 numverts;
if (!g_Vars.enableslopes && (tile->header.flags & GEOFLAG_SLOPE)) {
return 0;
}
numverts = tile->header.numvertices;
y2count = 0;
y1count = 0;
count = 0;
for (i = 0; i < numverts; i++) {
s32 next = i + 1;
s32 last = numverts - 1;
f32 posval;
f32 thisvals[2];
f32 nextvals[2];
f32 somefloat;
f32 somefloat2;
s32 xdiff;
s32 zdiff;
if (i == last) {
next = 0;
}
xdiff = tile->vertices[next][0] - tile->vertices[i][0];
zdiff = tile->vertices[next][2] - tile->vertices[i][2];
if (xdiff < 0) {
xdiff = -xdiff;
}
if (zdiff < 0) {
zdiff = -zdiff;
}
if (xdiff || zdiff) {
thisvals[1] = tile->vertices[i][1];
nextvals[1] = tile->vertices[next][1];
if (zdiff < xdiff) {
thisvals[0] = tile->vertices[i][0];
nextvals[0] = tile->vertices[next][0];
posval = pos->x;
} else {
thisvals[0] = tile->vertices[i][2];
nextvals[0] = tile->vertices[next][2];
posval = pos->z;
}
somefloat = (posval - thisvals[0]) / (nextvals[0] - thisvals[0]);
if (somefloat <= 1.0f && somefloat >= 0.0f) {
somefloat2 = thisvals[1] + (nextvals[1] - thisvals[1]) * somefloat;
if (somefloat2 >= y2 - 1.0f) {
y2count++;
if (y1count != 0) {
count++;
}
} else if (somefloat2 <= y1 + 1.0f) {
y1count++;
if (y2count != 0) {
count++;
}
} else {
count++;
}
}
}
}
return count;
}
void cd_0002840c(struct geotilef *tile, f32 arg1, f32 arg2, f32 arg3, struct prop *prop, struct collision *collisions, s32 maxcollisions, s32 *numcollisions)
{
s32 i;
s32 numvertices = tile->header.numvertices;
for (i = 0; i < numvertices; i++) {
s32 next = (i + 1) % numvertices;
if (tile->vertices[i].x != tile->vertices[next].x || tile->vertices[i].z != tile->vertices[next].z) {
f32 f0 = cd_00025654(tile->vertices[i].x, tile->vertices[i].z, tile->vertices[next].x, tile->vertices[next].z, arg1, arg2);
if (f0 < 0.0f) {
f0 = -f0;
}
if (f0 <= arg3
&& (cd_00025724(tile->vertices[i].x, tile->vertices[i].z, arg1, arg2) <= arg3
|| cd_00025724(tile->vertices[next].x, tile->vertices[next].z, arg1, arg2) <= arg3
|| cd_00025774(tile->vertices[i].x, tile->vertices[i].z, tile->vertices[next].x, tile->vertices[next].z, arg1, arg2))) {
if (*numcollisions < maxcollisions) {
collisions[*numcollisions].geo = &tile->header;
collisions[*numcollisions].vertexindex = i;
collisions[*numcollisions].prop = prop;
*numcollisions += 1;
} else {
break;
}
}
}
}
}
void cd_00028638(struct geoblock *block, f32 arg1, f32 arg2, f32 arg3, struct prop *prop, struct collision *collisions, s32 maxcollisions, s32 *numcollisions)
{
s32 i;
s32 numvertices = block->header.numvertices;
for (i = 0; i < numvertices; i++) {
s32 next = (i + 1) % numvertices;
if (block->vertices[i][0] != block->vertices[next][0] || block->vertices[i][1] != block->vertices[next][1]) {
f32 f0 = cd_00025654(block->vertices[i][0], block->vertices[i][1], block->vertices[next][0], block->vertices[next][1], arg1, arg2);
if (f0 < 0.0f) {
f0 = -f0;
}
if (f0 <= arg3
&& (cd_00025724(block->vertices[i][0], block->vertices[i][1], arg1, arg2) <= arg3
|| cd_00025724(block->vertices[next][0], block->vertices[next][1], arg1, arg2) <= arg3
|| cd_00025774(block->vertices[i][0], block->vertices[i][1], block->vertices[next][0], block->vertices[next][1], arg1, arg2))) {
if (*numcollisions < maxcollisions) {
collisions[*numcollisions].geo = &block->header;
collisions[*numcollisions].vertexindex = i;
collisions[*numcollisions].prop = prop;
*numcollisions += 1;
} else {
break;
}
}
}
}
}
void cd_0002885c(struct geocyl *cyl, f32 x, f32 z, f32 arg3, struct prop *prop, struct collision *collisions, s32 maxcollisions, s32 *numcollisions)
{
f32 xdiff = x - cyl->x;
f32 zdiff = z - cyl->z;
f32 f16 = arg3 + cyl->radius;
if (xdiff * xdiff + zdiff * zdiff <= f16 * f16) {
if (*numcollisions < maxcollisions) {
collisions[*numcollisions].geo = &cyl->header;
collisions[*numcollisions].vertexindex = 0;
collisions[*numcollisions].prop = prop;
*numcollisions += 1;
}
}
}
void cd_collect_geo_for_cyl_move_from_list(u8 *start, u8 *end, struct coord *pos, f32 radius, u16 geoflags,
bool checkvertical, f32 arg6, f32 arg7, struct prop *prop,
struct collision *collisions, s32 maxcollisions, s32 *numcollisions)
{
struct geo *geo = (struct geo *) start;
while (geo < (struct geo *) end) {
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) geo;
if (geo->flags & geoflags) {
if (pos->x >= *(s16 *)(tile->xmin + (uintptr_t)tile) - radius
&& pos->x <= *(s16 *)(tile->xmax + (uintptr_t)tile) + radius
&& pos->z >= *(s16 *)(tile->zmin + (uintptr_t)tile) - radius
&& pos->z <= *(s16 *)(tile->zmax + (uintptr_t)tile) + radius
&& (!checkvertical || (pos->y + arg6 >= *(s16 *)(tile->ymin + (uintptr_t)tile)
&& pos->y + arg7 <= *(s16 *)(tile->ymax + (uintptr_t)tile)))) {
bool pass;
if (geo->flags & GEOFLAG_RAMPWALL) {
pass = cd_test_ramp_wall(tile, pos, radius, pos->y + arg7, pos->y + arg6);
} else {
pass = true;
}
if (pass) {
cd_00027f78(tile, pos->x, pos->z, radius, prop, collisions, maxcollisions, numcollisions);
}
}
}
geo = (struct geo *)((uintptr_t)geo + GEOTILEI_SIZE(tile));
} else if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) geo;
if ((geo->flags & geoflags)
&& pos->x >= tile->vertices[tile->min[0]].x - radius
&& pos->x <= tile->vertices[tile->max[0]].x + radius
&& pos->z >= tile->vertices[tile->min[2]].z - radius
&& pos->z <= tile->vertices[tile->max[2]].z + radius
&& (!checkvertical || (pos->y + arg6 >= tile->vertices[tile->min[1]].y
&& pos->y + arg7 <= tile->vertices[tile->max[1]].y))) {
cd_0002840c(tile, pos->x, pos->z, radius, prop, collisions, maxcollisions, numcollisions);
}
geo = (struct geo *)((uintptr_t)geo + GEOTILEF_SIZE(tile));
} else if (geo->type == GEOTYPE_BLOCK) {
struct geoblock *block = (struct geoblock *) geo;
if ((geoflags & (GEOFLAG_WALL | GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT))
&& (!checkvertical || (pos->y + arg6 >= block->ymin && pos->y + arg7 <= block->ymax))) {
cd_00028638(block, pos->x, pos->z, radius, prop, collisions, maxcollisions, numcollisions);
}
geo = (struct geo *)((uintptr_t)geo + GEOBLOCK_SIZE(block));
} else if (geo->type == GEOTYPE_CYL) {
struct geocyl *cyl = (struct geocyl *) geo;
if ((geoflags & geo->flags)
&& (!checkvertical || (pos->y + arg6 >= cyl->ymin && pos->y + arg7 <= cyl->ymax))) {
cd_0002885c(cyl, pos->x, pos->z, radius, prop, collisions, maxcollisions, numcollisions);
}
geo = (struct geo *)((uintptr_t)geo + GEOCYL_SIZE(cyl));
}
}
}
void cd_collect_geo_for_cyl_move(struct coord *pos, f32 width, RoomNum *rooms, u32 types, u16 geoflags, bool checkvertical, f32 ymax, f32 ymin, struct collision *collisions, s32 maxcollisions)
{
RoomNum *roomptr;
s32 roomnum;
u8 *start;
u8 *end;
s32 numcollisions = 0;
s16 *propnumptr;
s16 propnums[256];
// Check BG
if (types & CDTYPE_BG) {
roomptr = rooms;
roomnum = rooms[0];
while (roomnum != -1) {
if (roomnum < g_TileNumRooms) {
start = g_TileFileData.u8 + g_TileRooms[roomnum];
end = g_TileFileData.u8 + g_TileRooms[roomnum + 1];
cd_collect_geo_for_cyl_move_from_list(start, end, pos, width, geoflags, checkvertical, ymax, ymin, NULL, collisions, maxcollisions, &numcollisions);
}
roomptr++;
roomnum = *roomptr;
}
}
// Check props
room_get_props(rooms, propnums, 256);
propnumptr = propnums;
while (*propnumptr >= 0) {
struct prop *prop = &g_Vars.props[*propnumptr];
if (prop_is_of_cd_type(prop, types) && prop_get_geometry(prop, &start, &end)) {
cd_collect_geo_for_cyl_move_from_list(start, end, pos, width, geoflags, checkvertical, ymax, ymin, prop, collisions, maxcollisions, &numcollisions);
}
propnumptr++;
}
collisions[numcollisions].geo = NULL;
}
void cd_0002901c(struct coord *pos, struct coord *dist, f32 width, struct collision *collisions)
{
s32 i;
struct widthxz spf8;
struct xz spf0;
struct xz spe8;
struct xz spe0;
f32 bestvalue = 0.0f;
s32 bestindex = -1;
u32 stack;
f32 value;
s32 curr;
s32 next;
struct coord vtx1;
struct coord vtx2;
struct geo *geo;
for (i = 0; (geo = collisions[i].geo) != NULL; i++) {
if (1);
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) geo;
spf8.width = width;
spf8.x = pos->x;
spf8.z = pos->z;
spe0.x = dist->x;
spe0.z = dist->z;
curr = collisions[i].vertexindex;
next = (curr + 1) % tile->header.numvertices;
spf0.x = tile->vertices[curr][0];
spf0.z = tile->vertices[curr][2];
spe8.x = tile->vertices[next][0];
spe8.z = tile->vertices[next][2];
value = func0f1579cc(&spf8, &spf0, &spe8, &spe0);
if (bestindex < 0 || value < bestvalue) {
bestvalue = value;
bestindex = i;
}
} else if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) geo;
spf8.width = width;
spf8.x = pos->x;
spf8.z = pos->z;
spe0.x = dist->x;
spe0.z = dist->z;
curr = collisions[i].vertexindex;
next = (curr + 1) % tile->header.numvertices;
spf0.x = tile->vertices[curr].x;
spf0.z = tile->vertices[curr].z;
spe8.x = tile->vertices[next].x;
spe8.z = tile->vertices[next].z;
value = func0f1579cc(&spf8, &spf0, &spe8, &spe0);
if (bestindex < 0 || value < bestvalue) {
bestvalue = value;
bestindex = i;
}
} else if (geo->type == GEOTYPE_BLOCK) {
struct geoblock *block = (struct geoblock *) geo;
spf8.width = width;
spf8.x = pos->x;
spf8.z = pos->z;
spe0.x = dist->x;
spe0.z = dist->z;
curr = collisions[i].vertexindex;
next = (curr + 1) % block->header.numvertices;
spf0.x = block->vertices[curr][0];
spf0.z = block->vertices[curr][1];
spe8.x = block->vertices[next][0];
spe8.z = block->vertices[next][1];
value = func0f1579cc(&spf8, &spf0, &spe8, &spe0);
if (bestindex < 0 || value < bestvalue) {
bestvalue = value;
bestindex = i;
}
} else if (geo->type == GEOTYPE_CYL) {
struct geocyl *cyl = (struct geocyl *) geo;
spf8.width = cyl->radius + width;
spf8.x = pos->x;
spf8.z = pos->z;
spe0.x = dist->x;
spe0.z = dist->z;
spf0.x = cyl->x;
spf0.z = cyl->z;
spe8.x = cyl->x;
spe8.z = cyl->z;
value = func0f1579cc(&spf8, &spf0, &spe8, &spe0);
if (bestindex < 0 || value < bestvalue) {
bestvalue = value;
bestindex = i;
}
}
}
if (collisions[bestindex].geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) collisions[bestindex].geo;
s32 curr = collisions[bestindex].vertexindex;
s32 next = (curr + 1) % tile->header.numvertices;
vtx1.x = tile->vertices[curr][0];
vtx1.y = tile->vertices[curr][1];
vtx1.z = tile->vertices[curr][2];
vtx2.x = tile->vertices[next][0];
vtx2.y = tile->vertices[next][1];
vtx2.z = tile->vertices[next][2];
} else if (collisions[bestindex].geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) collisions[bestindex].geo;
s32 curr = collisions[bestindex].vertexindex;
s32 next = (curr + 1) % tile->header.numvertices;
vtx1.x = tile->vertices[curr].x;
vtx1.y = tile->vertices[curr].y;
vtx1.z = tile->vertices[curr].z;
vtx2.x = tile->vertices[next].x;
vtx2.y = tile->vertices[next].y;
vtx2.z = tile->vertices[next].z;
} else if (collisions[bestindex].geo->type == GEOTYPE_BLOCK) {
struct geoblock *block = (struct geoblock *) collisions[bestindex].geo;
s32 curr = collisions[bestindex].vertexindex;
s32 next = (curr + 1) % block->header.numvertices;
vtx1.x = block->vertices[curr][0];
vtx1.y = pos->y;
vtx1.z = block->vertices[curr][1];
vtx2.x = block->vertices[next][0];
vtx2.y = pos->y;
vtx2.z = block->vertices[next][1];
} else if (collisions[bestindex].geo->type == GEOTYPE_CYL) {
struct geocyl *cyl = (struct geocyl *) collisions[bestindex].geo;
cd_00025848(cyl->x, cyl->z, cyl->radius, pos->x, pos->z, &vtx1.x, &vtx1.z, &vtx2.x, &vtx2.z);
vtx1.y = pos->y;
vtx2.y = pos->y;
}
cd_set_obstacle_vtx_prop_flt(&vtx1, &vtx2, collisions[bestindex].prop, bestvalue);
}
f32 cd_find_ground_from_list(struct collision *collisions, struct coord *pos, struct collision **collisionptr, f32 width)
{
struct collision *collision;
s32 i;
f32 curground = -4294967296;
bool hasground = false;
bool anyintile = false;
bool hasflag0100 = false;
#if VERSION >= VERSION_NTSC_1_0
bool hasdie = false;
bool hasgroundfromearlier;
bool isdie;
#else
u32 unused1;
#endif
f32 nextvalue;
f32 spe4;
f32 f30;
f32 x;
f32 z;
f32 spd4;
f32 f14;
f32 spb4;
f32 thisvalue;
u32 unused2;
s32 next;
s32 numvertices;
f32 spb8;
#if VERSION >= VERSION_NTSC_1_0
u32 unused3[8];
#else
u32 unused3[7];
#endif
f32 sp94;
u32 unused4[6];
f32 sp78;
f32 sp74;
f32 nextx;
f32 nextz;
f32 ground;
u32 unused5[5];
f32 thisx;
f32 thisz;
*collisionptr = NULL;
for (collision = collisions; collision->geo != NULL; collision++) {
if (collision->geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) collision->geo;
if (tile->header.flags & GEOFLAG_DIE) {
collision->intile = false;
} else {
if (tile->header.flags & GEOFLAG_SLOPE) {
hasflag0100 = true;
}
collision->intile = cd_is2d_point_in_int_tile(tile, pos->x, pos->z);
if (collision->intile) {
anyintile = true;
}
}
} else if (collision->geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) collision->geo;
collision->intile = cd_is2d_point_in_flt_tile(tile, pos->x, pos->z);
if (collision->intile) {
anyintile = true;
}
}
}
if (anyintile) {
for (collision = collisions; collision->geo != NULL; collision++) {
if (collision->intile) {
if (collision->geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) collision->geo;
if ((tile->header.flags & GEOFLAG_STEP) == 0) {
ground = cd_find_ground_in_int_tile((void *)collision->geo, pos->x, pos->z);
if (ground >= curground && ground < pos->y) {
curground = ground;
*collisionptr = collision;
hasground = true;
}
}
} else if (collision->geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) collision->geo;
ground = cd_find_ground_in_flt_tile((void *)collision->geo, pos->x, pos->z);
if (ground >= curground && ground < pos->y) {
curground = ground;
*collisionptr = collision;
hasground = true;
}
}
}
}
for (collision = collisions; collision->geo != NULL; collision++) {
if (collision->intile) {
if (collision->geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) collision->geo;
if (tile->header.flags & GEOFLAG_STEP) {
ground = cd_find_ground_in_int_tile((void *)collision->geo, pos->x, pos->z);
if (ground >= curground && (ground < pos->y || !hasground)) {
curground = ground;
*collisionptr = collision;
hasground = true;
}
}
}
}
}
}
#if VERSION >= VERSION_NTSC_1_0
hasgroundfromearlier = hasground;
#endif
if (!hasground || hasflag0100) {
spe4 = 4294967296.0f;
for (collision = collisions; collision->geo != NULL; collision++) {
#if VERSION >= VERSION_NTSC_1_0
if (collision->intile == false
&& (!hasgroundfromearlier || (collision->geo->type == GEOTYPE_TILE_I && (collision->geo->flags & GEOFLAG_SLOPE))))
#else
if (collision->intile == false
&& (!hasground || (collision->geo->type == GEOTYPE_TILE_I && (collision->geo->flags & GEOFLAG_SLOPE))))
#endif
{
if (collision->geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) collision->geo;
numvertices = tile->header.numvertices;
#if VERSION >= VERSION_NTSC_1_0
isdie = (tile->header.flags & GEOFLAG_DIE) != 0;
#endif
#if VERSION >= VERSION_NTSC_1_0
if (!isdie || !hasground)
#endif
{
for (i = 0; i < numvertices; i++) {
thisx = tile->vertices[i][0];
thisz = tile->vertices[i][2];
next = (i + 1) % numvertices;
nextx = tile->vertices[next][0];
nextz = tile->vertices[next][2];
spd4 = cd_00025654(thisx, thisz, nextx, nextz, pos->x, pos->z);
f30 = spd4;
if (f30 < 0.0f) {
f30 = -f30;
}
#if VERSION >= VERSION_NTSC_1_0
if (f30 < spe4 || hasdie)
#else
if (f30 < spe4)
#endif
{
if (cd_00025774(thisx, thisz, nextx, nextz, pos->x, pos->z)) {
spb8 = nextx - thisx;
spb4 = nextz - thisz;
f14 = spd4 / sqrtf(spb8 * spb8 + spb4 * spb4);
x = pos->x + f14 * -spb4;
z = pos->z + f14 * spb8;
ground = cd_find_ground_in_int_tile_at_vertex(tile, x, z, i);
if (ground < pos->y || (collision->geo->flags & GEOFLAG_STEP)) {
curground = ground;
*collisionptr = collision;
spe4 = f30;
#if VERSION >= VERSION_NTSC_1_0
hasground = true;
hasdie = isdie;
#endif
}
} else {
thisvalue = cd_00025724(thisx, thisz, pos->x, pos->z);
nextvalue = cd_00025724(nextx, nextz, pos->x, pos->z);
if (thisvalue < nextvalue) {
#if VERSION >= VERSION_NTSC_1_0
if (thisvalue < spe4 || hasdie)
#else
if (thisvalue < spe4)
#endif
{
x = tile->vertices[i][0];
z = tile->vertices[i][2];
ground = cd_find_ground_in_int_tile_at_vertex(tile, x, z, i);
if (ground < pos->y || (collision->geo->flags & GEOFLAG_STEP)) {
curground = ground;
*collisionptr = collision;
spe4 = thisvalue;
#if VERSION >= VERSION_NTSC_1_0
hasground = true;
hasdie = isdie;
#endif
}
}
} else {
#if VERSION >= VERSION_NTSC_1_0
if (nextvalue < spe4 || hasdie)
#else
if (nextvalue < spe4)
#endif
{
x = tile->vertices[next][0];
z = tile->vertices[next][2];
ground = cd_find_ground_in_int_tile_at_vertex(tile, x, z, i);
if (ground < pos->y || (collision->geo->flags & GEOFLAG_STEP)) {
curground = ground;
*collisionptr = collision;
spe4 = nextvalue;
#if VERSION >= VERSION_NTSC_1_0
hasground = true;
hasdie = isdie;
#endif
}
}
}
}
}
}
}
} else if (collision->geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) collision->geo;
s32 numvertices = tile->header.numvertices;
s32 i;
for (i = 0; i < numvertices; i++) {
thisx = tile->vertices[i].x;
thisz = tile->vertices[i].z;
next = (i + 1) % numvertices;
nextx = tile->vertices[next].x;
nextz = tile->vertices[next].z;
sp94 = cd_00025654(thisx, thisz, nextx, nextz, pos->x, pos->z);
f30 = sp94;
if (f30 < 0.0f) {
f30 = -f30;
}
if (f30 < spe4) {
if (cd_00025774(thisx, thisz, nextx, nextz, pos->x, pos->z)) {
sp78 = nextx - thisx;
sp74 = nextz - thisz;
f14 = sp94 / sqrtf(sp78 * sp78 + sp74 * sp74);
x = pos->x + f14 * -sp74;
z = pos->z + f14 * sp78;
ground = cd_find_ground_in_flt_tile(tile, x, z);
if (ground < pos->y) {
curground = ground;
*collisionptr = collision;
spe4 = f30;
#if VERSION >= VERSION_NTSC_1_0
hasground = true;
hasdie = false;
#endif
}
} else {
thisvalue = cd_00025724(thisx, thisz, pos->x, pos->z);
nextvalue = cd_00025724(nextx, nextz, pos->x, pos->z);
if (thisvalue < nextvalue) {
if (thisvalue < spe4) {
x = tile->vertices[i].x;
z = tile->vertices[i].z;
ground = cd_find_ground_in_flt_tile(tile, x, z);
if (ground < pos->y) {
curground = ground;
*collisionptr = collision;
spe4 = thisvalue;
#if VERSION >= VERSION_NTSC_1_0
hasground = true;
hasdie = false;
#endif
}
}
} else {
if (nextvalue < spe4) {
x = tile->vertices[next].x;
z = tile->vertices[next].z;
ground = cd_find_ground_in_flt_tile(tile, x, z);
if (ground < pos->y) {
curground = ground;
*collisionptr = collision;
spe4 = nextvalue;
#if VERSION >= VERSION_NTSC_1_0
hasground = true;
hasdie = false;
#else
if (numvertices);
#endif
}
}
}
}
}
}
}
}
}
}
return curground;
}
/**
* Test if the given cylinder is intersecting a tile with the given geoflags.
* If so, populate the laddernormal argument and return true.
*
* There is nothing specific to ladders in this function, but it's only used
* for finding ladders.
*/
bool cd_find_ladder(struct coord *pos, f32 width, f32 ymax, f32 ymin, RoomNum *rooms, u16 geoflags, struct coord *laddernormal)
{
struct collision collisions[2];
cd_collect_geo_for_cyl(pos, width, rooms, CDTYPE_BG, geoflags, CHECKVERTICAL_YES, ymax, ymin, collisions, 1);
if (collisions[0].geo) {
struct geotilei *tile = (struct geotilei *) collisions[0].geo;
struct coord dist;
cd_get_geo_normal(collisions[0].geo, laddernormal);
dist.x = pos->x - tile->vertices[0][0];
dist.y = pos->y - tile->vertices[0][1];
dist.z = pos->z - tile->vertices[0][2];
if (dist.f[0] * laddernormal->f[0] + dist.f[1] * laddernormal->f[1] + dist.f[2] * laddernormal->f[2] < 0) {
laddernormal->x = -laddernormal->x;
laddernormal->y = -laddernormal->y;
laddernormal->z = -laddernormal->z;
}
return true;
}
return false;
}
bool cd_0002a13c(struct coord *pos, f32 radius, f32 ymax, f32 ymin, RoomNum *rooms, u16 geoflags)
{
struct collision collisions[2];
cd_collect_geo_for_cyl(pos, radius, rooms, CDTYPE_BG, geoflags, CHECKVERTICAL_YES, ymax, ymin, collisions, 1);
if (collisions[0].geo) {
return true;
}
return false;
}
f32 cd_find_ground_info_at_cyl(struct coord *pos, f32 radius, RoomNum *rooms, u16 *floorcol,
u8 *floortype, u16 *floorflags, RoomNum *floorroom, s32 *inlift, struct prop **lift)
{
struct collision collisions[21];
struct collision *sp72 = NULL;
f32 ground;
struct geo *geo = NULL;
cd_collect_geo_for_cyl(pos, radius, rooms, CDTYPE_ALL, GEOFLAG_FLOOR1 | GEOFLAG_FLOOR2, CHECKVERTICAL_NO, 0, 0, collisions, 20);
ground = cd_find_ground_from_list(collisions, pos, &sp72, radius);
if (sp72) {
geo = sp72->geo;
}
if (floorcol) {
cd_get_floor_col(geo, floorcol);
}
if (floortype) {
cd_get_floor_type(geo, floortype);
}
if (floorflags && geo) {
*floorflags = geo->flags;
}
if (floorroom) {
if (sp72) {
*floorroom = sp72->room;
} else {
*floorroom = -1;
}
}
if (inlift) {
if (geo && geo->type == GEOTYPE_TILE_F && (geo->flags & GEOFLAG_LIFTFLOOR)) {
*inlift = true;
*lift = sp72->prop;
if (*lift && (*lift)->obj->modelnum == MODEL_ESCA_STEP && floortype) {
*floortype = FLOORTYPE_METAL;
}
} else {
*inlift = false;
*lift = NULL;
}
}
return ground;
}
/**
* This function must come immediately after cd_find_ground_info_at_cyl.
*
* A piracy check looks for this function, then backtracks two instructions to
* nop the jr ra at the end of cd_find_ground_info_at_cyl, causing it to flow into this
* function and return 0.
*/
f32 cd_return_zero(void)
{
return 0;
}
f32 cd_find_ground_at_cyl(struct coord *pos, f32 radius, RoomNum *rooms, u16 *floorcol, u8 *floortype)
{
return cd_find_ground_info_at_cyl(pos, radius, rooms, floorcol, floortype, NULL, NULL, NULL, NULL);
}
f32 cd_find_floor_y_colour_type_at_pos(struct coord *pos, RoomNum *rooms, u16 *floorcol, u8 *floortype)
{
struct geo *geo;
RoomNum sp30[2];
f32 sp2c;
f32 result = -4294967296;
cd_find_closest_vertical(pos, rooms, GEOFLAG_FLOOR1 | GEOFLAG_FLOOR2, &geo, &sp30[1], &sp2c, NULL, SURFACE_FLOOR);
if (geo) {
result = sp2c;
}
if (floorcol) {
cd_get_floor_col(geo, floorcol);
}
if (floortype) {
cd_get_floor_type(geo, floortype);
}
return result;
}
s32 cd_find_floor_room_at_pos(struct coord *pos, RoomNum *nearrooms)
{
struct geo *geo;
RoomNum room;
f32 sp2c;
cd_find_closest_vertical(pos, nearrooms, GEOFLAG_FLOOR1 | GEOFLAG_FLOOR2, &geo, &room, &sp2c, 0, SURFACE_FLOOR);
return room;
}
#if VERSION >= VERSION_NTSC_1_0
RoomNum cd_find_floor_room_y_colour_flags_at_pos(struct coord *pos, RoomNum *rooms, f32 *arg2, u16 *floorcolptr, u16 *flagsptr)
#else
RoomNum cd_find_floor_room_y_colour_flags_at_pos(struct coord *pos, RoomNum *rooms, f32 *arg2, u16 *floorcolptr)
#endif
{
struct geo *geo;
RoomNum room;
f32 sp2c;
cd_find_closest_vertical(pos, rooms, GEOFLAG_FLOOR1 | GEOFLAG_FLOOR2, &geo, &room, &sp2c, NULL, SURFACE_FLOOR);
if (geo != NULL) {
*arg2 = sp2c;
}
if (floorcolptr != NULL) {
cd_get_floor_col(geo, floorcolptr);
}
#if VERSION >= VERSION_NTSC_1_0
if (flagsptr != NULL && geo != NULL) {
*flagsptr = geo->flags;
}
#endif
return room;
}
#if VERSION >= VERSION_NTSC_1_0
RoomNum cd_find_ceiling_room_y_colour_flags_at_pos(struct coord *pos, RoomNum *rooms, f32 *arg2, u16 *floorcolptr, u16 *flagsptr)
#else
RoomNum cd_find_ceiling_room_y_colour_flags_at_pos(struct coord *pos, RoomNum *rooms, f32 *arg2, u16 *floorcolptr)
#endif
{
struct geo *geo;
RoomNum sp32;
f32 sp2c;
cd_find_closest_vertical(pos, rooms, GEOFLAG_FLOOR1 | GEOFLAG_FLOOR2, &geo, &sp32, &sp2c, NULL, SURFACE_CEILING);
if (geo != NULL) {
*arg2 = sp2c;
}
if (floorcolptr != NULL) {
cd_get_floor_col(geo, floorcolptr);
}
#if VERSION >= VERSION_NTSC_1_0
if (flagsptr != NULL && geo != NULL) {
*flagsptr = geo->flags;
}
#endif
return sp32;
}
RoomNum cd_find_floor_room_y_colour_normal_prop_at_pos(struct coord *pos, RoomNum *rooms, f32 *arg2, u16 *floorcol, struct coord *normal, struct prop **propptr)
{
struct geo *geo;
RoomNum room;
f32 sp2c;
cd_find_closest_vertical(pos, rooms, GEOFLAG_FLOOR1 | GEOFLAG_FLOOR2, &geo, &room, &sp2c, propptr, SURFACE_FLOOR);
if (geo) {
*arg2 = sp2c;
cd_get_geo_normal(geo, normal);
}
if (floorcol) {
cd_get_floor_col(geo, floorcol);
}
return room;
}
RoomNum cd_find_ceiling_room_y_colour_flags_normal_at_pos(struct coord *pos, RoomNum *rooms, f32 *arg2, u16 *floorcol, u16 *flagsptr, struct coord *normal)
{
struct geo *geo;
RoomNum sp32;
f32 sp2c;
cd_find_closest_vertical(pos, rooms, GEOFLAG_FLOOR1 | GEOFLAG_FLOOR2, &geo, &sp32, &sp2c, NULL, SURFACE_CEILING);
if (geo) {
*arg2 = sp2c;
cd_get_geo_normal(geo, normal);
}
if (floorcol) {
cd_get_floor_col(geo, floorcol);
}
if (flagsptr != NULL && geo != NULL) {
*flagsptr = geo->flags;
}
return sp32;
}
/**
* Tests if a cylinder volume fits in the given position.
*/
s32 cd_test_volume(struct coord *pos, f32 width, RoomNum *rooms, s32 types, bool checkvertical, f32 ymax, f32 ymin)
{
struct collision collisions[2];
bool result = true;
cd_collect_geo_for_cyl(pos, width, rooms, types, GEOFLAG_WALL, checkvertical, ymax, ymin, collisions, 1);
if (collisions[0].geo) {
result = false;
cd_set_obstacle_prop(collisions[0].prop);
}
return result;
}
s32 cd_exam_cyl_move01(struct coord *pos, struct coord *pos2, f32 radius, RoomNum *rooms, s32 types, bool checkvertical, f32 ymax, f32 ymin)
{
struct collision collisions[2];
s32 cdresult;
struct coord sp70;
struct coord sp64;
cdresult = CDRESULT_NOCOLLISION;
cd_collect_geo_for_cyl(pos2, radius, rooms, types, GEOFLAG_WALL, checkvertical, ymax, ymin, collisions, 1);
if (collisions[0].geo != NULL) {
cdresult = CDRESULT_COLLISION;
if (collisions[0].geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) collisions[0].geo;
s32 this = collisions[0].vertexindex;
s32 next = (this + 1) % tile->header.numvertices;
sp70.x = tile->vertices[this][0];
sp70.y = tile->vertices[this][1];
sp70.z = tile->vertices[this][2];
sp64.x = tile->vertices[next][0];
sp64.y = tile->vertices[next][1];
sp64.z = tile->vertices[next][2];
} else if (collisions[0].geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) collisions[0].geo;
s32 this = collisions[0].vertexindex;
s32 next = (this + 1) % tile->header.numvertices;
sp70.x = tile->vertices[this].x;
sp70.y = tile->vertices[this].y;
sp70.z = tile->vertices[this].z;
sp64.x = tile->vertices[next].x;
sp64.y = tile->vertices[next].y;
sp64.z = tile->vertices[next].z;
} else if (collisions[0].geo->type == GEOTYPE_BLOCK) {
struct geoblock *block = (struct geoblock *) collisions[0].geo;
s32 this = collisions[0].vertexindex;
s32 next = (this + 1) % block->header.numvertices;
sp70.x = block->vertices[this][0];
sp70.y = pos->y;
sp70.z = block->vertices[this][1];
sp64.x = block->vertices[next][0];
sp64.y = pos->y;
sp64.z = block->vertices[next][1];
} else if (collisions[0].geo->type == GEOTYPE_CYL) {
struct geocyl *cyl = (struct geocyl *) collisions[0].geo;
cd_00025848(cyl->x, cyl->z, cyl->radius, pos->x, pos->z, &sp70.x, &sp70.z, &sp64.x, &sp64.z);
sp70.y = pos->y;
sp64.y = pos->y;
}
cd_set_obstacle_vtx_prop(&sp70, &sp64, collisions[0].prop);
}
return cdresult;
}
s32 cd_exam_cyl_move02(struct coord *origpos, struct coord *dstpos, f32 width, RoomNum *dstrooms, s32 types, bool checkvertical, f32 ymax, f32 ymin)
{
struct collision collisions[21];
struct coord dist;
s32 result = CDRESULT_NOCOLLISION;
cd_collect_geo_for_cyl_move(dstpos, width, dstrooms, types, GEOFLAG_WALL, checkvertical, ymax, ymin, collisions, 20);
if (collisions[0].geo) {
result = CDRESULT_COLLISION;
dist.x = dstpos->x - origpos->x;
dist.y = dstpos->y - origpos->y;
dist.z = dstpos->z - origpos->z;
cd_0002901c(origpos, &dist, width, collisions);
}
return result;
}
bool cd_0002aac0_int_tile(struct coord *arg0, struct coord *arg1, struct coord *arg2, struct geotilei *tile, struct coord *arg4, struct coord *arg5)
{
s32 i;
u8 numvertices = tile->header.numvertices;
for (i = 2; i < numvertices; i++) {
if (func0002f490((struct vec3s16 *)&tile->vertices[0][0],
(struct vec3s16 *)&tile->vertices[i - 1][0],
(struct vec3s16 *)&tile->vertices[i][0],
NULL, arg0, arg1, arg2, arg4, arg5)) {
return true;
}
}
return false;
}
bool cd_0002ab98_flt_tile(struct coord *arg0, struct coord *arg1, struct coord *arg2, struct geotilef *tile, struct coord *arg4, struct coord *arg5)
{
s32 i;
u8 numvertices = tile->header.numvertices;
for (i = 2; i < numvertices; i++) {
if (func0002f560(&tile->vertices[0], &tile->vertices[i - 1], &tile->vertices[i],
NULL, arg0, arg1, arg2, arg4, arg5)) {
return true;
}
}
return false;
}
bool cd_0002ac70_int_tile(struct coord *arg0, struct coord *arg1, struct coord *arg2, struct geotilei *tile,
struct coord *arg4, struct coord *arg5, struct coord *arg6, bool arg7, f32 arg8, f32 arg9)
{
bool result = false;
s32 i;
f32 f0;
s32 numvertices = tile->header.numvertices;
s32 next;
s32 spb8 = 1;
f32 f22 = 1.0f;
s32 spb0;
f32 spac;
f32 spa8;
f32 ymax = *(s16 *)(tile->ymax + (uintptr_t)tile);
f32 ymin = *(s16 *)(tile->ymin + (uintptr_t)tile);
f32 spa0[2];
f32 sp98[2];
f32 sp90[2];
f32 sp88[2];
if (!arg7
|| (arg0->y + arg8 >= ymin && arg1->y + arg9 <= ymax)
|| (arg0->y + arg9 <= ymax && arg1->y + arg8 >= ymin)) {
for (i = 0; i < numvertices; i++) {
next = (i + 1) % numvertices;
if (cd_000254d8(arg0, arg1, tile->vertices[i][0], tile->vertices[i][2], tile->vertices[next][0], tile->vertices[next][2], &spb8)) {
spa0[0] = arg0->x;
spa0[1] = arg0->z;
sp98[0] = arg1->x;
sp98[1] = arg1->z;
sp90[0] = tile->vertices[i][0];
sp90[1] = tile->vertices[i][2];
sp88[0] = tile->vertices[next][0];
sp88[1] = tile->vertices[next][2];
f0 = func0f1577f0(spa0, sp98, sp90, sp88);
if (f0 < f22) {
if (arg7) {
spa8 = (arg1->y - arg0->y) * f0 + arg0->y;
spac = spa8 + arg8;
spa8 = spa8 + arg9;
}
if (!arg7 || (!(spa8 >= ymax) && !(spac <= ymin))) {
result = true;
f22 = f0;
spb0 = i;
}
}
}
}
if (result) {
arg4->x = arg0->x + arg2->f[0] * f22;
arg4->y = arg0->y + arg2->f[1] * f22;
arg4->z = arg0->z + arg2->f[2] * f22;
if (arg5 != NULL && arg6 != NULL) {
arg5->x = tile->vertices[spb0][0];
arg5->y = arg4->y;
arg5->z = tile->vertices[spb0][2];
arg6->x = tile->vertices[(spb0 + 1) % numvertices][0];
arg6->y = arg4->y;
arg6->z = tile->vertices[(spb0 + 1) % numvertices][2];
}
} else if (!result && spb8) {
result = true;
arg4->x = arg0->x;
arg4->y = arg0->y;
arg4->z = arg0->z;
if (arg5 != NULL && arg6 != NULL) {
arg5->x = arg0->x;
arg5->y = arg0->y;
arg5->z = arg0->z;
arg6->x = arg0->x;
arg6->y = arg0->y;
arg6->z = arg0->z;
}
}
}
return result;
}
bool cd_0002b128_flt_tile(struct coord *arg0, struct coord *arg1, struct coord *arg2, struct geotilef *tile,
struct coord *arg4, struct coord *arg5, struct coord *arg6, bool arg7, f32 arg8, f32 arg9)
{
bool result = false;
s32 i;
f32 f0;
s32 numvertices = tile->header.numvertices;
s32 next;
s32 spb8 = 1;
f32 f22 = 1.0f;
s32 spb0;
f32 spac;
f32 spa8;
f32 ymax = tile->vertices[tile->max[1]].y;
f32 ymin = tile->vertices[tile->min[1]].y;
f32 spa0[2];
f32 sp98[2];
f32 sp90[2];
f32 sp88[2];
if (!arg7
|| (arg0->y + arg8 >= ymin && arg1->y + arg9 <= ymax)
|| (arg0->y + arg9 <= ymax && arg1->y + arg8 >= ymin)) {
for (i = 0; i < numvertices; i++) {
next = (i + 1) % numvertices;
if (cd_000254d8(arg0, arg1, tile->vertices[i].x, tile->vertices[i].z, tile->vertices[next].x, tile->vertices[next].z, &spb8)) {
spa0[0] = arg0->x;
spa0[1] = arg0->z;
sp98[0] = arg1->x;
sp98[1] = arg1->z;
sp90[0] = tile->vertices[i].x;
sp90[1] = tile->vertices[i].z;
sp88[0] = tile->vertices[next].x;
sp88[1] = tile->vertices[next].z;
f0 = func0f1577f0(spa0, sp98, sp90, sp88);
if (f0 < f22) {
if (arg7) {
spa8 = (arg1->y - arg0->y) * f0 + arg0->y;
spac = spa8 + arg8;
spa8 = spa8 + arg9;
}
if (!arg7 || (!(spa8 >= ymax) && !(spac <= ymin))) {
result = true;
f22 = f0;
spb0 = i;
}
}
}
}
if (result) {
arg4->x = arg0->x + arg2->f[0] * f22;
arg4->y = arg0->y + arg2->f[1] * f22;
arg4->z = arg0->z + arg2->f[2] * f22;
if (arg5 != NULL && arg6 != NULL) {
arg5->x = tile->vertices[spb0].x;
arg5->y = arg4->y;
arg5->z = tile->vertices[spb0].z;
arg6->x = tile->vertices[(spb0 + 1) % numvertices].x;
arg6->y = arg4->y;
arg6->z = tile->vertices[(spb0 + 1) % numvertices].z;
}
} else if (!result && spb8) {
result = true;
arg4->x = arg0->x;
arg4->y = arg0->y;
arg4->z = arg0->z;
if (arg5 != NULL && arg6 != NULL) {
arg5->x = arg0->x;
arg5->y = arg0->y;
arg5->z = arg0->z;
arg6->x = arg0->x;
arg6->y = arg0->y;
arg6->z = arg0->z;
}
}
}
return result;
}
bool cd_0002b560_block(struct coord *arg0, struct coord *arg1, struct coord *arg2, struct geoblock *block,
struct coord *arg4, struct coord *arg5, struct coord *arg6, bool arg7, f32 arg8, f32 arg9)
{
bool result = false;
s32 i;
f32 f0;
s32 numvertices = block->header.numvertices;
s32 next;
s32 spb8 = 1;
f32 f22 = 1.0f;
s32 spb0;
f32 spac;
f32 spa8;
f32 spa0[2];
f32 sp98[2];
f32 sp90[2];
f32 sp88[2];
if (!arg7
|| (arg0->y + arg8 >= block->ymin && arg1->y + arg9 <= block->ymax)
|| (arg0->y + arg9 <= block->ymax && arg1->y + arg8 >= block->ymin)) {
for (i = 0; i < numvertices; i++) {
next = (i + 1) % numvertices;
if (cd_000254d8(arg0, arg1, block->vertices[i][0], block->vertices[i][1], block->vertices[next][0], block->vertices[next][1], &spb8)) {
spa0[0] = arg0->x;
spa0[1] = arg0->z;
sp98[0] = arg1->x;
sp98[1] = arg1->z;
sp90[0] = block->vertices[i][0];
sp90[1] = block->vertices[i][1];
sp88[0] = block->vertices[next][0];
sp88[1] = block->vertices[next][1];
f0 = func0f1577f0(spa0, sp98, sp90, sp88);
if (f0 < f22) {
if (arg7) {
spa8 = (arg1->y - arg0->y) * f0 + arg0->y;
spac = spa8 + arg8;
spa8 = spa8 + arg9;
}
if (!arg7 || (!(spa8 >= block->ymax) && !(spac <= block->ymin))) {
result = true;
f22 = f0;
spb0 = i;
}
}
}
}
if (result) {
arg4->x = arg0->x + arg2->f[0] * f22;
arg4->y = arg0->y + arg2->f[1] * f22;
arg4->z = arg0->z + arg2->f[2] * f22;
if (arg5 != NULL && arg6 != NULL) {
arg5->x = block->vertices[spb0][0];
arg5->y = arg4->y;
arg5->z = block->vertices[spb0][1];
arg6->x = block->vertices[(spb0 + 1) % numvertices][0];
arg6->y = arg4->y;
arg6->z = block->vertices[(spb0 + 1) % numvertices][1];
}
} else if (!result && spb8) {
result = true;
arg4->x = arg0->x;
arg4->y = arg0->y;
arg4->z = arg0->z;
if (arg5 != NULL && arg6 != NULL) {
arg5->x = arg0->x;
arg5->y = arg0->y;
arg5->z = arg0->z;
arg6->x = arg0->x;
arg6->y = arg0->y;
arg6->z = arg0->z;
}
}
}
return result;
}
bool cd_0002b954_cyl(struct coord *arg0, struct coord *arg1, struct coord *arg2, struct geocyl *cyl,
struct coord *arg4, struct coord *arg5, struct coord *arg6, bool arg7, f32 arg8, f32 arg9)
{
bool result = false;
f32 mult;
f32 sp74;
f32 x = cyl->x;
f32 z = cyl->z;
f32 radius = cyl->radius;
if (!arg7
|| (arg0->y + arg8 >= cyl->ymin && arg1->y + arg9 <= cyl->ymax)
|| (arg0->y + arg9 <= cyl->ymax && arg1->y + arg8 >= cyl->ymin)) {
sp74 = cd_00025654(arg0->x, arg0->z, arg1->x, arg1->z, x, z);
if (sp74 < 0.0f) {
sp74 = -sp74;
}
if (sp74 < radius
&& (cd_00025724(arg0->x, arg0->z, x, z) < radius
|| cd_00025724(arg1->x, arg1->z, x, z) < radius
|| cd_00025774(arg0->x, arg0->z, arg1->x, arg1->z, x, z))) {
f32 xdiff = arg1->x - arg0->x;
f32 zdiff = arg1->z - arg0->z;
f32 sqdist;
f32 dist;
u32 stack;
f32 sp50;
f32 sp4c;
f32 sp48;
sp50 = sqrtf(xdiff * xdiff + zdiff * zdiff);
if (sp50 > 0.0f) {
xdiff = x - arg0->x;
zdiff = z - arg0->z;
sqdist = xdiff * xdiff + zdiff * zdiff;
if (sp74 * sp74 <= sqdist) {
dist = sqrtf(sqdist - sp74 * sp74) - sqrtf(radius * radius - sp74 * sp74);
} else {
dist = 0.0f;
}
mult = dist / sp50;
} else {
mult = 0.0f;
}
if (mult < 1.0f) {
if (arg7) {
sp48 = (arg1->y - arg0->y) * mult + arg0->y;
sp4c = sp48 + arg8;
sp48 = sp48 + arg9;
}
if (!arg7 || (!(sp48 >= cyl->ymax) && !(sp4c <= cyl->ymin))) {
result = true;
arg4->x = arg0->x + arg2->f[0] * mult;
arg4->y = arg0->y + arg2->f[1] * mult;
arg4->z = arg0->z + arg2->f[2] * mult;
if (arg5 != NULL && arg6 != NULL) {
cd_00025848(x, z, radius, arg0->x, arg0->z, &arg5->x, &arg5->z, &arg6->x, &arg6->z);
arg5->y = arg4->y;
arg6->y = arg4->y;
}
}
}
}
}
return result;
}
bool cd_test_a_to_b_geolist(u8 *start, u8 *end, struct coord *arg2, struct coord *arg3, struct coord *arg4, u16 geoflags, bool checkvertical, s32 arg7, f32 arg8, f32 arg9)
{
struct geo *geo = (struct geo *) start;
while (geo < (struct geo *) end) {
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) geo;
struct coord min;
struct coord max;
struct coord spc4;
struct coord spb8;
if (tile->header.flags & geoflags) {
min.x = *(s16 *)(tile->xmin + (uintptr_t)tile);
if ((!(arg2->x < min.x)) || !(arg3->x < min.x)) {
max.x = *(s16 *)(tile->xmax + (uintptr_t)tile);
if ((!(arg2->x > max.x)) || !(arg3->x > max.x)) {
min.z = *(s16 *)(tile->zmin + (uintptr_t)tile);
if ((!(arg2->z < min.z)) || !(arg3->z < min.z)) {
max.z = *(s16 *)(tile->zmax + (uintptr_t)tile);
if ((!(arg2->z > max.z)) || !(arg3->z > max.z)) {
if (1);
if (checkvertical) {
min.y = *(s16 *)(tile->ymin + (uintptr_t)tile);
max.y = *(s16 *)(tile->ymax + (uintptr_t)tile);
if ((!(arg2->y < min.y) || !(arg3->y < min.y))
&& (!(arg2->y > max.y) || !(arg3->y > max.y))
&& bg_test_line_intersects_bbox(arg2, arg4, &min, &max)
&& cd_0002aac0_int_tile(arg2, arg3, arg4, tile, &spc4, &spb8)) {
return false;
}
} else if (cd_0002ac70_int_tile(arg2, arg3, arg4, tile, &spc4, 0, 0, arg7, arg8, arg9)) {
return false;
}
}
}
}
}
}
geo = (struct geo *)((uintptr_t)geo + GEOTILEI_SIZE(tile));
} else if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) geo;
struct coord min;
struct coord max;
struct coord sp90;
struct coord sp84;
if (tile->header.flags & geoflags) {
min.x = tile->vertices[tile->min[0]].x;
max.x = tile->vertices[tile->max[0]].x;
min.z = tile->vertices[tile->min[2]].z;
max.z = tile->vertices[tile->max[2]].z;
if (((!(arg2->x < min.x)) || !(arg3->x < min.x))
&& (!(arg2->x > max.x) || !(arg3->x > max.x))
&& ((!(arg2->z < min.z)) || !(arg3->z < min.z))
&& (!(arg2->z > max.z) || !(arg3->z > max.z))) {
if (checkvertical) {
min.y = tile->vertices[tile->min[1]].y;
max.y = tile->vertices[tile->max[1]].y;
if ((!(arg2->y < min.y) || !(arg3->y < min.y))
&& (!(arg2->y > max.y) || !(arg3->y > max.y))
&& bg_test_line_intersects_bbox(arg2, arg4, &min, &max)
&& cd_0002ab98_flt_tile(arg2, arg3, arg4, tile, &sp90, &sp84)) {
return false;
}
} else if (cd_0002b128_flt_tile(arg2, arg3, arg4, tile, &sp90, 0, 0, arg7, arg8, arg9)) {
return false;
}
}
}
geo = (struct geo *)((uintptr_t)geo + GEOTILEF_SIZE(tile));
} else if (geo->type == GEOTYPE_BLOCK) {
struct coord sp78;
struct geoblock *block = (struct geoblock *) geo;
if ((geoflags & (GEOFLAG_WALL | GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT))
&& cd_0002b560_block(arg2, arg3, arg4, block, &sp78, 0, 0, arg7, arg8, arg9)) {
return false;
}
geo = (struct geo *)((uintptr_t)geo + GEOBLOCK_SIZE(block));
} else if (geo->type == GEOTYPE_CYL) {
struct coord sp68;
struct geocyl *cyl = (struct geocyl *) geo;
if ((geoflags & cyl->header.flags)
&& cd_0002b954_cyl(arg2, arg3, arg4, cyl, &sp68, 0, 0, arg7, arg8, arg9)) {
return false;
}
geo = (struct geo *)((uintptr_t)geo + GEOCYL_SIZE(cyl));
}
}
return true;
}
void cd_0002c328_int_tile(struct geotilei *tile, struct coord *arg1, struct coord *arg2, struct coord *arg3, struct coord *arg4)
{
struct coord sp3c;
u32 stack[2];
u8 numvertices;
f32 max = 0.0f;
f32 min = 0.0f;
f32 dist;
s32 i;
if (arg2->x != 0.0f || arg2->z != 0.0f) {
sp3c.x = arg2->z;
sp3c.y = 0.0f;
sp3c.z = -arg2->x;
dist = sqrtf(sp3c.f[0] * sp3c.f[0] + sp3c.f[2] * sp3c.f[2]);
if (dist > 0.0f) {
sp3c.x *= 1.0f / dist;
sp3c.z *= 1.0f / dist;
} else {
sp3c.x = 0.0f;
sp3c.y = 0.0f;
sp3c.z = 1.0f;
}
} else {
sp3c.x = 0.0f;
sp3c.y = 0.0f;
sp3c.z = 1.0f;
}
numvertices = tile->header.numvertices;
for (i = 0; i < numvertices; i++) {
f32 xdiff = tile->vertices[i][0] - arg1->x;
f32 zdiff = tile->vertices[i][2] - arg1->z;
f32 f0 = xdiff * sp3c.f[0] + zdiff * sp3c.f[2];
if (f0 > max) {
max = f0;
} else if (f0 < min) {
min = f0;
}
}
arg3->x = arg1->x + sp3c.f[0] * max;
arg3->y = arg1->y;
arg3->z = arg1->z + sp3c.f[2] * max;
arg4->x = arg1->x + sp3c.f[0] * min;
arg4->y = arg1->y;
arg4->z = arg1->z + sp3c.f[2] * min;
}
void cd_0002c528_flt_tile(struct geotilef *tile, struct coord *arg1, struct coord *arg2, struct coord *arg3, struct coord *arg4)
{
struct coord sp3c;
u32 stack[2];
u8 numvertices;
f32 max = 0.0f;
f32 min = 0.0f;
f32 dist;
s32 i;
if (arg2->x != 0.0f || arg2->z != 0.0f) {
sp3c.x = arg2->z;
sp3c.y = 0.0f;
sp3c.z = -arg2->x;
dist = sqrtf(sp3c.f[0] * sp3c.f[0] + sp3c.f[2] * sp3c.f[2]);
if (dist > 0.0f) {
sp3c.x *= 1.0f / dist;
sp3c.z *= 1.0f / dist;
} else {
sp3c.x = 0.0f;
sp3c.y = 0.0f;
sp3c.z = 1.0f;
}
} else {
sp3c.x = 0.0f;
sp3c.y = 0.0f;
sp3c.z = 1.0f;
}
numvertices = tile->header.numvertices;
for (i = 0; i < numvertices; i++) {
f32 xdiff = tile->vertices[i].x - arg1->x;
f32 zdiff = tile->vertices[i].z - arg1->z;
f32 f0 = xdiff * sp3c.f[0] + zdiff * sp3c.f[2];
if (f0 > max) {
max = f0;
} else if (f0 < min) {
min = f0;
}
}
arg3->x = arg1->x + sp3c.f[0] * max;
arg3->y = arg1->y;
arg3->z = arg1->z + sp3c.f[2] * max;
arg4->x = arg1->x + sp3c.f[0] * min;
arg4->y = arg1->y;
arg4->z = arg1->z + sp3c.f[2] * min;
}
bool cd_exam_a_to_b_geolist(u8 *start, u8 *end, struct coord *arg2, struct coord *arg3, struct coord *arg4,
u16 geoflags, bool checkvertical, s32 arg7, f32 ymax, f32 ymin, f32 *arg10, struct coord *arg11,
struct coord *arg12, struct coord *arg13, struct geo **geoptr, s32 roomnum)
{
struct geo *geo;
f32 x;
f32 y;
f32 z;
f32 sum;
bool ok;
bool result = false;
geo = (struct geo *) start;
while (geo < (struct geo *) end) {
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) geo;
struct coord min;
struct coord max;
struct coord sp12c;
struct coord sp120;
struct coord sp114;
struct coord sp108;
if (geo->flags & GEOFLAG_RAMPWALL) {
ok = cd_test_ramp_wall(tile, arg2, 0, arg2->y + ymin, arg2->y + ymax);
} else {
ok = true;
}
if (ok && (geo->flags & geoflags)) {
min.x = *(s16 *)(tile->xmin + (uintptr_t)tile);
if (!(arg2->x < min.x) || !(arg3->x < min.x)) {
max.x = *(s16 *)(tile->xmax + (uintptr_t)tile);
if (!(arg2->x > max.x) || !(arg3->x > max.x)) {
min.z = *(s16 *)(tile->zmin + (uintptr_t)tile);
if (!(arg2->z < min.z) || !(arg3->z < min.z)) {
max.z = *(s16 *)(tile->zmax + (uintptr_t)tile);
if (!(arg2->z > max.z) || !(arg3->z > max.z)) {
if (checkvertical) {
min.y = *(s16 *)(tile->ymin + (uintptr_t)tile);
max.y = *(s16 *)(tile->ymax + (uintptr_t)tile);
if ((!(arg2->y < min.y) || !(arg3->y < min.y))
&& (!(arg2->y > max.y) || !(arg3->y > max.y))
&& bg_test_line_intersects_bbox(arg2, arg4, &min, &max)
&& cd_0002aac0_int_tile(arg2, arg3, arg4, tile, &sp12c, &sp120)) {
x = sp12c.x - arg2->x;
y = sp12c.y - arg2->y;
z = sp12c.z - arg2->z;
sum = x * x + y * y + z * z;
if (sum < *arg10) {
result = true;
*arg10 = sum;
arg11->x = sp12c.x;
arg11->y = sp12c.y;
arg11->z = sp12c.z;
cd_0002c328_int_tile(tile, &sp12c, &sp120, arg12, arg13);
*geoptr = geo;
}
}
} else if (cd_0002ac70_int_tile(arg2, arg3, arg4, tile, &sp12c, &sp114, &sp108, arg7, ymax, ymin)) {
x = sp12c.x - arg2->x;
y = sp12c.y - arg2->y;
z = sp12c.z - arg2->z;
sum = x * x + y * y + z * z;
if (sum < *arg10) {
result = true;
*arg10 = sum;
arg11->x = sp12c.x;
arg11->y = sp12c.y;
arg11->z = sp12c.z;
arg12->x = sp114.x;
arg12->y = sp114.y;
arg12->z = sp114.z;
arg13->x = sp108.x;
arg13->y = sp108.y;
arg13->z = sp108.z;
*geoptr = geo;
}
}
}
}
}
}
}
geo = (struct geo *)((uintptr_t)geo + GEOTILEI_SIZE(tile));
} else if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) geo;
struct coord min;
struct coord max;
struct coord spe0;
struct coord spd4;
struct coord spc8;
struct coord spbc;
if (geo->flags & geoflags) {
min.x = tile->vertices[tile->min[0]].x;
max.x = tile->vertices[tile->max[0]].x;
min.z = tile->vertices[tile->min[2]].z;
max.z = tile->vertices[tile->max[2]].z;
if ((!(arg2->x < min.x) || !(arg3->x < min.x))
&& (!(arg2->x > max.x) || !(arg3->x > max.x))
&& (!(arg2->z < min.z) || !(arg3->z < min.z))
&& (!(arg2->z > max.z) || !(arg3->z > max.z))) {
if (checkvertical) {
min.y = tile->vertices[tile->min[1]].y;
max.y = tile->vertices[tile->max[1]].y;
if ((!(arg2->y < min.y) || !(arg3->y < min.y))
&& (!(arg2->y > max.y) || !(arg3->y > max.y))
&& bg_test_line_intersects_bbox(arg2, arg4, &min, &max)
&& cd_0002ab98_flt_tile(arg2, arg3, arg4, tile, &spe0, &spd4)) {
x = spe0.x - arg2->x;
y = spe0.y - arg2->y;
z = spe0.z - arg2->z;
sum = x * x + y * y + z * z;
if (sum < *arg10) {
result = true;
*arg10 = sum;
arg11->x = spe0.x;
arg11->y = spe0.y;
arg11->z = spe0.z;
cd_0002c528_flt_tile(tile, &spe0, &spd4, arg12, arg13);
*geoptr = geo;
}
}
} else if (cd_0002b128_flt_tile(arg2, arg3, arg4, tile, &spe0, &spc8, &spbc, arg7, ymax, ymin)) {
x = spe0.x - arg2->x;
y = spe0.y - arg2->y;
z = spe0.z - arg2->z;
sum = x * x + y * y + z * z;
if (sum < *arg10) {
result = true;
*arg10 = sum;
arg11->x = spe0.x;
arg11->y = spe0.y;
arg11->z = spe0.z;
arg12->x = spc8.x;
arg12->y = spc8.y;
arg12->z = spc8.z;
arg13->x = spbc.x;
arg13->y = spbc.y;
arg13->z = spbc.z;
*geoptr = geo;
}
}
}
}
geo = (struct geo *)((uintptr_t)geo + GEOTILEF_SIZE(tile));
} else if (geo->type == GEOTYPE_BLOCK) {
struct coord spb0;
struct coord spa4;
struct coord sp98;
if ((geoflags & (GEOFLAG_WALL | GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT))
&& (cd_0002b560_block(arg2, arg3, arg4, (struct geoblock *)geo, &spb0, &spa4, &sp98, arg7, ymax, ymin))) {
x = spb0.x - arg2->x;
y = spb0.y - arg2->y;
z = spb0.z - arg2->z;
sum = x * x + y * y + z * z;
if (sum < *arg10) {
result = true;
*arg10 = sum;
arg11->x = spb0.x;
arg11->y = spb0.y;
arg11->z = spb0.z;
arg12->x = spa4.x;
arg12->y = spa4.y;
arg12->z = spa4.z;
arg13->x = sp98.x;
arg13->y = sp98.y;
arg13->z = sp98.z;
*geoptr = geo;
}
}
geo = (struct geo *)((uintptr_t)geo + GEOBLOCK_SIZE(geo));
} else if (geo->type == GEOTYPE_CYL) {
struct geocyl *cyl = (struct geocyl *) geo;
struct coord sp88;
struct coord sp7c;
struct coord sp70;
if ((geoflags & geo->flags)
&& cd_0002b954_cyl(arg2, arg3, arg4, cyl, &sp88, &sp7c, &sp70, arg7, ymax, ymin)) {
x = sp88.x - arg2->x;
y = sp88.y - arg2->y;
z = sp88.z - arg2->z;
sum = x * x + y * y + z * z;
if (sum < *arg10) {
result = true;
*arg10 = sum;
arg11->x = sp88.x;
arg11->y = sp88.y;
arg11->z = sp88.z;
arg12->x = sp7c.x;
arg12->y = sp7c.y;
arg12->z = sp7c.z;
arg13->x = sp70.x;
arg13->y = sp70.y;
arg13->z = sp70.z;
*geoptr = geo;
}
}
geo = (struct geo *)((uintptr_t)geo + GEOCYL_SIZE(cyl));
}
}
return !result;
}
bool cd_test_a_to_b(struct coord *pos, struct coord *coord2, RoomNum *rooms, u32 types, u16 geoflags, bool checkvertical, s32 arg6, f32 ymax, f32 ymin)
{
s32 roomnum;
RoomNum *roomptr;
u8 *start;
u8 *end;
struct coord sp27c;
s16 *propnumptr;
s16 propnums[256];
sp27c.x = coord2->x - pos->x;
sp27c.y = coord2->y - pos->y;
sp27c.z = coord2->z - pos->z;
if (types & CDTYPE_BG) {
roomptr = rooms;
roomnum = rooms[0];
while (roomnum != -1) {
if (roomnum < g_TileNumRooms) {
start = g_TileFileData.u8 + g_TileRooms[roomnum];
end = g_TileFileData.u8 + g_TileRooms[roomnum + 1];
if (cd_test_a_to_b_geolist(start, end, pos, coord2, &sp27c, geoflags, checkvertical, arg6, ymax, ymin) == 0) {
cd_set_obstacle_prop(NULL);
return false;
}
}
roomptr++;
roomnum = *roomptr;
}
}
room_get_props(rooms, propnums, 256);
propnumptr = propnums;
while (*propnumptr >= 0) {
struct prop *prop = &g_Vars.props[*propnumptr];
if (prop_is_of_cd_type(prop, types)
&& prop_get_geometry(prop, &start, &end)
&& cd_test_a_to_b_geolist(start, end, pos, coord2, &sp27c, geoflags, checkvertical, arg6, ymax, ymin) == 0) {
cd_set_obstacle_prop(prop);
return false;
}
propnumptr++;
}
return true;
}
s32 cd_exam_a_to_b(struct coord *arg0, struct coord *arg1, RoomNum *rooms, s32 types, u16 geoflags, bool checkvertical, s32 arg6, f32 ymax, f32 ymin)
{
s32 roomnum;
RoomNum *roomptr;
u8 *start;
u8 *end;
struct coord sp2c4;
bool sp2c0 = false;
struct coord sp2b4;
struct coord sp2a8;
struct coord sp29c;
f32 sp298 = 4294967296;
struct geo *sp294;
s16 *propnumptr;
s16 propnums[256];
sp2c4.x = arg1->x - arg0->x;
sp2c4.y = arg1->y - arg0->y;
sp2c4.z = arg1->z - arg0->z;
if (types & CDTYPE_BG) {
roomptr = rooms;
roomnum = rooms[0];
while (roomnum != -1) {
if (roomnum < g_TileNumRooms) {
u32 *ptr = &g_TileRooms[roomnum];
start = g_TileFileData.u8 + ptr[0];
end = g_TileFileData.u8 + ptr[1];
if (!cd_exam_a_to_b_geolist(start, end, arg0, arg1, &sp2c4, geoflags, checkvertical, arg6, ymax, ymin, &sp298, &sp2b4, &sp2a8, &sp29c, &sp294, roomnum)) {
sp2c0 = true;
cd_set_obstacle_vtx_col_prop_flt_geo(&sp2a8, &sp29c, &sp2b4, NULL, sp298, sp294);
}
}
roomptr++;
roomnum = *roomptr;
}
}
room_get_props(rooms, propnums, 256);
propnumptr = propnums;
while (*propnumptr >= 0) {
struct prop *prop = &g_Vars.props[*propnumptr];
if (prop_is_of_cd_type(prop, types)
&& prop_get_geometry(prop, &start, &end)
&& !cd_exam_a_to_b_geolist(start, end, arg0, arg1, &sp2c4, geoflags, checkvertical, arg6, ymax, ymin, &sp298, &sp2b4, &sp2a8, &sp29c, &sp294, -999)) {
sp2c0 = true;
cd_set_obstacle_vtx_col_prop_flt_geo(&sp2a8, &sp29c, &sp2b4, prop, sp298, sp294);
}
propnumptr++;
}
return !sp2c0;
}
bool cd_test_cyl_move01(struct coord *pos, RoomNum *rooms, struct coord *targetpos, u32 types, u32 arg4, f32 ymax, f32 ymin)
{
RoomNum sp44[21];
RoomNum sp34[8];
portal_find_rooms(pos, targetpos, rooms, sp34, sp44, 20);
return cd_test_a_to_b(pos, targetpos, sp44, types, GEOFLAG_WALL, CHECKVERTICAL_NO, arg4, ymax, ymin);
}
s32 cd_test_cyl_move02(struct coord *pos, RoomNum *rooms, struct coord *coord2, RoomNum *rooms2, u32 types, s32 arg5, f32 ymax, f32 ymin)
{
s32 result;
RoomNum sp44[20];
RoomNum sp34[8];
los_find_intersecting_rooms_properly(pos, rooms, coord2, sp34, sp44, 20);
if (array_intersects(sp34, rooms2)) {
result = cd_test_a_to_b(pos, coord2, sp44, types, GEOFLAG_WALL, CHECKVERTICAL_NO, arg5, ymax, ymin);
} else {
result = CDRESULT_COLLISION;
}
return result;
}
s32 cd_exam_cyl_move03(struct coord *pos, RoomNum *rooms, struct coord *arg2, u32 types, u32 arg4, f32 ymax, f32 ymin)
{
RoomNum sp44[21];
RoomNum sp34[8];
portal_find_rooms(pos, arg2, rooms, sp34, sp44, 20);
return cd_exam_a_to_b(pos, arg2, sp44, types, GEOFLAG_WALL, CHECKVERTICAL_NO, arg4, ymax, ymin);
}
s32 cd_test_cyl_move04(struct coord *arg0, RoomNum *arg1, struct coord *arg2, RoomNum *arg3, u32 types, s32 arg5, f32 ymax, f32 ymin)
{
RoomNum rooms[21];
portal_find_rooms(arg0, arg2, arg1, arg3, rooms, 20);
return cd_test_a_to_b(arg0, arg2, rooms, types, GEOFLAG_WALL, CHECKVERTICAL_NO, arg5, ymax, ymin);
}
s32 cd_exam_cyl_move05(struct coord *pos, RoomNum *rooms, struct coord *pos2, RoomNum *rooms2, s32 types, bool arg5, f32 ymax, f32 ymin)
{
RoomNum sp44[21];
RoomNum sp34[8];
s32 result;
los_find_intersecting_rooms_properly(pos, rooms, pos2, sp34, sp44, 20);
result = cd_exam_a_to_b(pos, pos2, sp44, types, GEOFLAG_WALL, CHECKVERTICAL_NO, arg5, ymax, ymin);
if (result != CDRESULT_COLLISION && !array_intersects(sp34, rooms2)) {
cd_clear_results();
result = CDRESULT_ERROR;
}
return result;
}
s32 cd_exam_cyl_move06(struct coord *arg0, RoomNum *arg1, struct coord *arg2, RoomNum *arg3, f32 width, s32 types, s32 arg6, f32 ymax, f32 ymin)
{
RoomNum sp5c[21];
RoomNum sp4c[8];
struct coord sp40;
s32 result;
los_find_intersecting_rooms_properly(arg0, arg1, arg2, sp4c, sp5c, 20);
result = cd_exam_a_to_b(arg0, arg2, sp5c, types, GEOFLAG_WALL, CHECKVERTICAL_NO, arg6, ymax, ymin);
if (result == CDRESULT_COLLISION) {
sp40.x = arg2->x - arg0->x;
sp40.y = arg2->y - arg0->y;
sp40.z = arg2->z - arg0->z;
cd_000250cc(arg0, &sp40, width);
} else if (!array_intersects(sp4c, arg3)) {
cd_clear_results();
result = CDRESULT_ERROR;
}
return result;
}
s32 cd_exam_cyl_move07(struct coord *arg0, RoomNum *arg1, struct coord *arg2, RoomNum *arg3, u32 types, s32 arg5, f32 ymax, f32 ymin)
{
RoomNum rooms[21];
portal_find_rooms(arg0, arg2, arg1, arg3, rooms, 20);
return cd_exam_a_to_b(arg0, arg2, rooms, types, GEOFLAG_WALL, CHECKVERTICAL_NO, arg5, ymax, ymin);
}
s32 cd_exam_cyl_move08(struct coord *arg0, RoomNum *arg1, struct coord *arg2, RoomNum *arg3, f32 width, u32 types, s32 arg6, f32 ymax, f32 ymin)
{
RoomNum rooms[21];
struct coord sp40;
s32 result;
portal_find_rooms(arg0, arg2, arg1, arg3, rooms, 20);
result = cd_exam_a_to_b(arg0, arg2, rooms, types, GEOFLAG_WALL, CHECKVERTICAL_NO, arg6, ymax, ymin);
if (result == CDRESULT_COLLISION) {
sp40.x = arg2->x - arg0->x;
sp40.y = arg2->y - arg0->y;
sp40.z = arg2->z - arg0->z;
cd_000250cc(arg0, &sp40, width);
}
return result;
}
bool cd_test_los03(struct coord *viewpos, RoomNum *rooms, struct coord *targetpos, u32 types, u16 geoflags)
{
RoomNum sp44[21];
RoomNum sp34[8];
portal_find_rooms(viewpos, targetpos, rooms, sp34, sp44, 20);
return cd_test_a_to_b(viewpos, targetpos, sp44, types, geoflags, CHECKVERTICAL_YES, 1, 0, 0);
}
bool cd_test_los04(struct coord *frompos, RoomNum *fromrooms, struct coord *topos, s32 types)
{
return cd_test_los03(frompos, fromrooms, topos, types, GEOFLAG_WALL | GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT);
}
bool cd_test_los05(struct coord *coord, RoomNum *rooms, struct coord *coord2, RoomNum *rooms2, s32 types, u16 geoflags)
{
bool result;
RoomNum sp44[20];
RoomNum sp34[8];
los_find_intersecting_rooms_properly(coord, rooms, coord2, sp34, sp44, 20);
if (array_intersects(sp34, rooms2)) {
result = cd_test_a_to_b(coord, coord2, sp44, types, geoflags, CHECKVERTICAL_YES, 1, 0, 0);
} else {
result = false;
}
return result;
}
bool cd_test_los06(struct coord *arg0, RoomNum *rooms1, struct coord *arg2, RoomNum *rooms2, u32 types)
{
return cd_test_los05(arg0, rooms1, arg2, rooms2, types, GEOFLAG_WALL | GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT);
}
bool cd_test_los07(struct coord *pos, RoomNum *rooms, struct coord *pos2, RoomNum *rooms2, RoomNum *rooms3, u32 types, u16 geoflags)
{
bool result;
RoomNum sp34[20];
los_find_intersecting_rooms_properly(pos, rooms, pos2, rooms3, sp34, 20);
if (array_intersects(rooms3, rooms2)) {
result = cd_test_a_to_b(pos, pos2, sp34, types, geoflags, CHECKVERTICAL_YES, 1, 0, 0);
} else {
result = false;
}
return result;
}
s32 cd_exam_los08(struct coord *pos, RoomNum *rooms, struct coord *pos2, u32 types, u16 geoflags)
{
RoomNum sp44[21];
RoomNum sp34[8];
portal_find_rooms(pos, pos2, rooms, sp34, sp44, 20);
return cd_exam_a_to_b(pos, pos2, sp44, types, geoflags, CHECKVERTICAL_YES, 1, 0, 0);
}
s32 cd_exam_los09(struct coord *pos, RoomNum *rooms, struct coord *pos2, u32 types)
{
return cd_exam_los08(pos, rooms, pos2, types, GEOFLAG_WALL | GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT);
}
s32 cd_test_los10(struct coord *arg0, RoomNum *arg1, struct coord *arg2, RoomNum *arg3, u32 types, u16 geoflags)
{
RoomNum rooms[21];
portal_find_rooms(arg0, arg2, arg1, arg3, rooms, 20);
return cd_test_a_to_b(arg0, arg2, rooms, types, geoflags, CHECKVERTICAL_YES, 1, 0, 0);
}
s32 cd_test_los11(struct coord *arg0, RoomNum *arg1, struct coord *arg2, RoomNum *arg3, u32 types)
{
return cd_test_los10(arg0, arg1, arg2, arg3, types, GEOFLAG_WALL | GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT);
}
bool cd_0002ded8(struct coord *arg0, struct coord *arg1, struct prop *prop)
{
u8 *start;
u8 *end;
struct coord sp7c;
bool result = false;
struct coord sp6c;
struct coord sp60;
struct coord sp54;
f32 sp50 = 4294967296;
struct geo *geo;
sp7c.x = arg1->x - arg0->x;
sp7c.y = arg1->y - arg0->y;
sp7c.z = arg1->z - arg0->z;
if (prop_get_geometry(prop, &start, &end)) {
if (!cd_exam_a_to_b_geolist(start, end, arg0, arg1, &sp7c,
GEOFLAG_WALL | GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT,
CHECKVERTICAL_YES, 1, 0, 0, &sp50, &sp6c, &sp60, &sp54, &geo, -999)) {
result = true;
cd_set_obstacle_vtx_col_prop_flt_geo(&sp60, &sp54, &sp6c, prop, sp50, geo);
}
}
return !result;
}
/**
* Return true if both blocks are not intersecting on the X/Z plane.
*/
bool cd_block_excludes_block_laterally(struct geoblock *block1, struct geoblock *block2)
{
u32 stack[4];
f32 zero = 0.0f;
s32 numvertices0 = block1->header.numvertices;
s32 numvertices1 = block2->header.numvertices;
s32 i;
for (i = 0; i < numvertices0; i++) {
s32 next = (i + 1) % numvertices0;
f64 diff1;
f64 diff2;
diff1 = block1->vertices[next][1] - (f64)block1->vertices[i][1];
diff2 = block1->vertices[i][0] - (f64)block1->vertices[next][0];
if (diff1 == zero && diff2 == zero) {
if (cd_is_2d_point_in_block(block2, block1->vertices[i][0], block1->vertices[i][1])) {
return false;
}
} else {
f64 sum1 = block1->vertices[i][0] * diff1 + block1->vertices[i][1] * diff2;
f64 sum2;
s32 j = (next + 1) % numvertices0;
s32 k;
while (j != i) {
sum2 = block1->vertices[j][0] * diff1 + block1->vertices[j][1] * diff2;
if (1);
if (1);
if (1);
if (sum2 != sum1) {
break;
}
j = (j + 1) % numvertices0;
}
for (k = 0; k < numvertices1; k++) {
f64 sum3 = block2->vertices[k][0] * diff1 + block2->vertices[k][1] * diff2;
if (sum2 == sum1) {
sum2 = sum1 - sum3 + sum1;
}
if ((sum3 < sum1 && sum2 < sum1) || (sum3 > sum1 && sum2 > sum1)) {
break;
}
}
if (k == numvertices1) {
return true;
}
}
}
return false;
}
s32 cd_test_block_overlaps_geolist(u8 *start, u8 *end, struct geoblock *block, u16 geoflags)
{
struct geo *geo = (struct geo *) start;
while (geo < (struct geo *) end) {
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *) geo;
geo = (struct geo *)((uintptr_t)geo + GEOTILEI_SIZE(tile));
} else if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *) geo;
geo = (struct geo *)((uintptr_t)geo + GEOTILEF_SIZE(tile));
} else if (geo->type == GEOTYPE_BLOCK) {
struct geoblock *thisblock = (struct geoblock *) geo;
if ((geoflags & (GEOFLAG_WALL | GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT))
&& thisblock->ymax >= block->ymin
&& thisblock->ymin <= block->ymax) {
// Tiles are overlapping vertically
s32 i;
for (i = 0; i < block->header.numvertices; i++) {
if (cd_is_2d_point_in_block(thisblock, block->vertices[i][0], block->vertices[i][1])) {
return CDRESULT_COLLISION;
}
}
for (i = 0; i < thisblock->header.numvertices; i++) {
if (cd_is_2d_point_in_block(block, thisblock->vertices[i][0], thisblock->vertices[i][1])) {
return CDRESULT_COLLISION;
}
}
// This is a bit wasteful...
// If A excludes B, there's no point checking if B excludes A.
if (!cd_block_excludes_block_laterally(block, thisblock) && !cd_block_excludes_block_laterally(thisblock, block)) {
return CDRESULT_COLLISION;
}
}
geo = (struct geo *)((uintptr_t)geo + GEOBLOCK_SIZE(thisblock));
} else if (geo->type == GEOTYPE_CYL) {
struct geocyl *cyl = (struct geocyl *) geo;
if ((geoflags & geo->flags)
&& cyl->ymax >= block->ymin
&& cyl->ymin <= block->ymax
&& cd_000274e0_block(block, cyl->x, cyl->z, cyl->radius, NULL, NULL)) {
return CDRESULT_COLLISION;
}
geo = (struct geo *)((uintptr_t)geo + GEOCYL_SIZE(cyl));
}
}
return CDRESULT_NOCOLLISION;
}
/**
* Test if the given block overlaps any prop. Set the saved obstacle prop if so.
*
* The BG tests are pointless and not used, as cd_test_block_overlaps_geolist only
* tests blocks and cylinders.
*
* The function is used to check if a door is being blocked by another prop,
* and is also used in a sanity check to make sure a moved object hasn't moved
* into the player's position.
*/
s32 cd_test_block_overlaps_any_prop(struct geoblock *geo, RoomNum *rooms, u32 types)
{
s32 result = CDRESULT_NOCOLLISION;
s32 roomnum;
u8 *start;
u8 *end;
RoomNum *roomptr;
s16 propnums[256];
s16 *propnumptr;
// Check BG
if (types & CDTYPE_BG) {
roomptr = rooms;
roomnum = rooms[0];
while (roomnum != -1) {
if (roomnum < g_TileNumRooms) {
start = g_TileFileData.u8 + g_TileRooms[roomnum];
end = g_TileFileData.u8 + g_TileRooms[roomnum + 1];
result = cd_test_block_overlaps_geolist(start, end, geo, GEOFLAG_WALL);
if (result == CDRESULT_COLLISION) {
cd_set_obstacle_prop(NULL);
break;
}
}
roomptr++;
roomnum = *roomptr;
}
}
// Check props
if (result != CDRESULT_COLLISION) {
room_get_props(rooms, propnums, 256);
propnumptr = propnums;
while (*propnumptr >= 0) {
struct prop *prop = &g_Vars.props[*propnumptr];
if (prop_is_of_cd_type(prop, types) && prop_get_geometry(prop, &start, &end)) {
result = cd_test_block_overlaps_geolist(start, end, geo, GEOFLAG_WALL);
if (result == CDRESULT_COLLISION) {
cd_set_obstacle_prop(prop);
break;
}
}
propnumptr++;
}
}
return result;
}
bool cd_0002e680_int_tile(struct geotilei *tile, s32 numvertices, struct coord *verts, struct coord *diffs, struct prop *prop, struct geoblock *block)
{
bool result = false;
s32 i;
s32 next;
s32 curr;
struct coord sp84;
struct coord sp78;
struct coord sp6c;
for (i = 0; i < numvertices; i++) {
if (var8005f030) {
s32 remaining = numvertices - i;
next = (remaining + numvertices - 2) % numvertices;
curr = remaining - 1;
} else {
next = (i + 1) % numvertices;
curr = i;
}
if (cd_0002ac70_int_tile((struct coord *)((uintptr_t)verts + curr * sizeof(struct coord)),
(struct coord *)((uintptr_t)verts + next * sizeof(struct coord)),
(struct coord *)((uintptr_t)diffs + curr * sizeof(struct coord)),
tile, &sp6c, &sp84, &sp78, 0, 0.0f, 0.0f)) {
cd_set_obstacle_vtx_col_prop(&sp84, &sp78, &sp6c, prop);
cd_set_saved_pos((struct coord *)((uintptr_t)verts + curr * sizeof(struct coord)), (struct coord *)((uintptr_t)verts + next * sizeof(struct coord)));
cd_set_saved_block(block);
result = true;
break;
}
}
return result;
}
bool cd_0002e82c_int_tile(struct geotilef *tile, s32 numvertices, struct coord *verts, struct coord *diffs, struct prop *prop, struct geoblock *block)
{
bool result = false;
s32 i;
s32 next;
s32 curr;
struct coord sp84;
struct coord sp78;
struct coord sp6c;
for (i = 0; i < numvertices; i++) {
if (var8005f030) {
s32 remaining = numvertices - i;
next = (remaining + numvertices - 2) % numvertices;
curr = remaining - 1;
} else {
next = (i + 1) % numvertices;
curr = i;
}
if (cd_0002b128_flt_tile((struct coord *)((uintptr_t)verts + curr * sizeof(struct coord)),
(struct coord *)((uintptr_t)verts + next * sizeof(struct coord)),
(struct coord *)((uintptr_t)diffs + curr * sizeof(struct coord)),
tile, &sp6c, &sp84, &sp78, 0, 0.0f, 0.0f)) {
cd_set_obstacle_vtx_col_prop(&sp84, &sp78, &sp6c, prop);
cd_set_saved_pos((struct coord *)((uintptr_t)verts + curr * sizeof(struct coord)), (struct coord *)((uintptr_t)verts + next * sizeof(struct coord)));
cd_set_saved_block(block);
result = true;
break;
}
}
return result;
}
bool cd_0002e9d8_block(struct geoblock *thisblock, s32 numvertices, struct coord *verts, struct coord *diffs, struct prop *prop, struct geoblock *block)
{
bool result = false;
s32 i;
s32 next;
s32 curr;
struct coord sp84;
struct coord sp78;
struct coord sp6c;
for (i = 0; i < numvertices; i++) {
if (var8005f030) {
s32 remaining = numvertices - i;
next = (remaining + numvertices - 2) % numvertices;
curr = remaining - 1;
} else {
next = (i + 1) % numvertices;
curr = i;
}
if (cd_0002b560_block((struct coord *)((uintptr_t)verts + curr * sizeof(struct coord)),
(struct coord *)((uintptr_t)verts + next * sizeof(struct coord)),
(struct coord *)((uintptr_t)diffs + curr * sizeof(struct coord)),
thisblock, &sp6c, &sp84, &sp78, 0, 0.0f, 0.0f)) {
cd_set_obstacle_vtx_col_prop(&sp84, &sp78, &sp6c, prop);
cd_set_saved_pos((struct coord *)((uintptr_t)verts + curr * sizeof(struct coord)), (struct coord *)((uintptr_t)verts + next * sizeof(struct coord)));
cd_set_saved_block(block);
result = true;
break;
}
}
return result;
}
bool cd_0002eb84_cyl(struct geocyl *cyl, s32 numvertices, struct coord *arg2, struct coord *arg3, struct prop *prop, struct geoblock *block)
{
bool result = false;
s32 i;
s32 next;
s32 curr;
struct coord sp84;
struct coord sp78;
struct coord sp6c;
for (i = 0; i < numvertices; i++) {
if (var8005f030) {
s32 remaining = numvertices - i;
next = (remaining + numvertices - 2) % numvertices;
curr = remaining - 1;
} else {
next = (i + 1) % numvertices;
curr = i;
}
if (cd_0002b954_cyl((struct coord *)((uintptr_t)arg2 + curr * sizeof(struct coord)),
(struct coord *)((uintptr_t)arg2 + next * sizeof(struct coord)),
(struct coord *)((uintptr_t)arg3 + curr * sizeof(struct coord)),
cyl, &sp6c, &sp84, &sp78, 0, 0.0f, 0.0f)) {
cd_set_obstacle_vtx_col_prop(&sp84, &sp78, &sp6c, prop);
cd_set_saved_pos((struct coord *)((uintptr_t)arg2 + curr * sizeof(struct coord)), (struct coord *)((uintptr_t)arg2 + next * sizeof(struct coord)));
cd_set_saved_block(block);
result = true;
break;
}
}
return result;
}
bool cd_0002ed30(u8 *start, u8 *end, struct geoblock *block, s32 numvertices, struct coord *verts, struct coord *diffs, u16 geoflags, struct prop *prop)
{
struct geo *geo = (struct geo *) start;
while (geo < (struct geo *) end) {
if (1);
if (geo->type == GEOTYPE_TILE_I) {
struct geotilei *tile = (struct geotilei *)geo;
if ((geoflags & geo->flags)
&& *(s16 *)(tile->ymax + (uintptr_t)tile) >= block->ymin
&& *(s16 *)(tile->ymin + (uintptr_t)tile) <= block->ymax
&& cd_0002e680_int_tile(tile, numvertices, verts, diffs, prop, block)) {
return false;
}
geo = (struct geo *)((uintptr_t)geo + GEOTILEI_SIZE(tile));
} else if (geo->type == GEOTYPE_TILE_F) {
struct geotilef *tile = (struct geotilef *)geo;
if ((geoflags & geo->flags)
&& tile->vertices[tile->max[1]].y >= block->ymin
&& tile->vertices[tile->min[1]].y <= block->ymax
&& cd_0002e82c_int_tile(tile, numvertices, verts, diffs, prop, block)) {
return false;
}
geo = (struct geo *)((uintptr_t)geo + GEOTILEF_SIZE(tile));
} else if (geo->type == GEOTYPE_BLOCK) {
struct geoblock *block2 = (struct geoblock *)geo;
if ((geoflags & (GEOFLAG_WALL | GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT))
&& block2->ymax >= block->ymin
&& block2->ymin <= block->ymax
&& cd_0002e9d8_block(block2, numvertices, verts, diffs, prop, block)) {
return false;
}
geo = (struct geo *)((uintptr_t)geo + GEOBLOCK_SIZE(block2));
} else if (geo->type == GEOTYPE_CYL) {
struct geocyl *cyl = (struct geocyl *)geo;
if ((geoflags & geo->flags)
&& cyl->ymax >= block->ymin
&& cyl->ymin <= block->ymax
&& cd_0002eb84_cyl(cyl, numvertices, verts, diffs, prop, block)) {
return false;
}
geo = (struct geo *)((uintptr_t)geo + GEOCYL_SIZE(cyl));
}
}
return true;
}
bool cd_0002f02c(struct geoblock *block, RoomNum *rooms, s32 types)
{
s32 numvertices = block->header.numvertices;
s32 i;
u8 *start;
u8 *end;
s32 next;
s16 propnums[256];
s16 *propnumptr;
bool result = true;
struct coord verts[8];
struct coord diffs[8];
for (i = 0; i < numvertices; i++) {
verts[i].x = block->vertices[i][0];
verts[i].y = block->ymax;
verts[i].z = block->vertices[i][1];
}
for (i = 0; i < numvertices; i++) {
next = (i + 1) % numvertices;
diffs[i].x = verts[next].x - verts[i].x;
diffs[i].y = verts[next].y - verts[i].y;
diffs[i].z = verts[next].z - verts[i].z;
}
if (types & CDTYPE_BG) {
RoomNum *roomsptr = rooms;
s32 roomnum = *roomsptr;
while (roomnum != -1) {
if (roomnum < g_TileNumRooms) {
start = g_TileFileData.u8 + g_TileRooms[roomnum];
end = g_TileFileData.u8 + g_TileRooms[roomnum + 1];
result = cd_0002ed30(start, end, block, numvertices, verts, diffs, GEOFLAG_WALL, NULL);
if (!result) {
break;
}
}
roomsptr++;
roomnum = *roomsptr;
}
}
if (result) {
room_get_props(rooms, propnums, 256);
propnumptr = propnums;
while (*propnumptr >= 0) {
struct prop *prop = &g_Vars.props[*propnumptr];
if (prop_is_of_cd_type(prop, types)) {
if (prop_get_geometry(prop, &start, &end)) {
result = cd_0002ed30(start, end, block, numvertices, verts, diffs, GEOFLAG_WALL, prop);
if (!result) {
break;
}
}
}
propnumptr++;
}
}
return result;
}
#if VERSION < VERSION_NTSC_1_0
struct debugtri *cd_read_int_tile_vertices(struct debugtri *ptr, s32 *remaining, struct geotilei *tile)
{
if (tile->header.flags & (GEOFLAG_FLOOR1 | GEOFLAG_WALL)) {
s32 i;
s32 numvertices = tile->header.numvertices;
s16 vertices[16][3];
if (numvertices > 16) {
numvertices = 16;
}
for (i = 0; i < numvertices; i++) {
vertices[i][0] = tile->vertices[i][0] - g_Vars.currentplayer->globaldrawworldoffset.x;
vertices[i][1] = tile->vertices[i][1] - g_Vars.currentplayer->globaldrawworldoffset.y;
vertices[i][2] = tile->vertices[i][2] - g_Vars.currentplayer->globaldrawworldoffset.z;
}
for (i = 2; i < numvertices; i++) {
if (*remaining > 0) {
ptr->vertices[0][0] = vertices[0][0];
ptr->vertices[0][1] = vertices[0][1];
ptr->vertices[0][2] = vertices[0][2];
ptr->vertices[1][0] = vertices[i - 1][0];
ptr->vertices[1][1] = vertices[i - 1][1];
ptr->vertices[1][2] = vertices[i - 1][2];
ptr->vertices[2][0] = vertices[i][0];
ptr->vertices[2][1] = vertices[i][1];
ptr->vertices[2][2] = vertices[i][2];
ptr->unk12 = 0;
ptr++;
}
*remaining -= 1;
}
}
return ptr;
}
#endif
#if VERSION < VERSION_NTSC_1_0
struct debugtri *cd_read_flt_tile_vertices(struct debugtri *ptr, s32 *remaining, struct geotilef *tile)
{
if (tile->header.flags & (GEOFLAG_FLOOR1 | GEOFLAG_WALL)) {
s32 i;
s32 numvertices = tile->header.numvertices;
s16 vertices[16][3];
if (numvertices > 16) {
numvertices = 16;
}
for (i = 0; i < numvertices; i++) {
vertices[i][0] = tile->vertices[i].x - g_Vars.currentplayer->globaldrawworldoffset.x;
vertices[i][1] = tile->vertices[i].y - g_Vars.currentplayer->globaldrawworldoffset.y;
vertices[i][2] = tile->vertices[i].z - g_Vars.currentplayer->globaldrawworldoffset.z;
}
for (i = 2; i < numvertices; i++) {
if (*remaining > 0) {
ptr->vertices[0][0] = vertices[0][0];
ptr->vertices[0][1] = vertices[0][1];
ptr->vertices[0][2] = vertices[0][2];
ptr->vertices[1][0] = vertices[i - 1][0];
ptr->vertices[1][1] = vertices[i - 1][1];
ptr->vertices[1][2] = vertices[i - 1][2];
ptr->vertices[2][0] = vertices[i][0];
ptr->vertices[2][1] = vertices[i][1];
ptr->vertices[2][2] = vertices[i][2];
ptr->unk12 = 0;
ptr++;
}
*remaining -= 1;
}
}
return ptr;
}
#endif
Gfx *cd_render(Gfx *gdl, u32 arg1, u32 arg2, u32 arg3)
{
return gdl;
}
void cd_0002f2fc(u32 arg0, u32 arg1)
{
// empty
}
bool cd_is_nearly_in_sight_with_flags(struct coord *viewpos, RoomNum *rooms, struct coord *targetpos, f32 distance, s32 types, u16 geoflags)
{
struct coord diff;
f32 x;
f32 z;
struct coord vector;
if (cd_test_los03(viewpos, rooms, targetpos, types, geoflags)) {
return true;
}
vector.x = targetpos->x - viewpos->x;
vector.y = 0;
vector.z = targetpos->z - viewpos->z;
guNormalize(&vector.x, &vector.y, &vector.z);
x = vector.f[0] * distance;
z = vector.f[2] * distance;
diff.x = targetpos->x - z;
diff.y = targetpos->y;
diff.z = targetpos->z + x;
if (cd_test_los03(viewpos, rooms, &diff, types, geoflags)) {
return true;
}
diff.x = targetpos->x + z;
diff.y = targetpos->y;
diff.z = targetpos->z - x;
if (cd_test_los03(viewpos, rooms, &diff, types, geoflags)) {
return true;
}
return false;
}
bool cd_is_nearly_in_sight(struct coord *viewpos, RoomNum *rooms, struct coord *targetpos, f32 distance, s32 types)
{
return cd_is_nearly_in_sight_with_flags(viewpos, rooms, targetpos, distance, types, GEOFLAG_BLOCK_SIGHT);
}