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