mirror of
https://gitlab.com/ryandwyer/perfect-dark
synced 2026-06-13 05:46:01 -04:00
4279 lines
109 KiB
C
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);
|
|
}
|