From 26e0dafb5a7bbc3f18468d1a2a3300eaf09beee5 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Wed, 14 Feb 2024 16:42:42 -0800 Subject: [PATCH 01/25] Add COLLISION_IMPROVEMENTS define, implement ROUNDED_WALL_CORNERS and ADD_CEILING_MARGINS subdefines --- include/config/config_movement.h | 5 + include/surface_terrains.h | 1 + src/engine/surface_collision.c | 158 ++++++++++++++++++++++--------- src/engine/surface_load.c | 6 ++ src/engine/surface_load.h | 15 +++ 5 files changed, 139 insertions(+), 46 deletions(-) diff --git a/include/config/config_movement.h b/include/config/config_movement.h index 7034d1d866..9ba87ad6fa 100644 --- a/include/config/config_movement.h +++ b/include/config/config_movement.h @@ -113,6 +113,11 @@ */ #define DONT_LEDGE_GRAB_STEEP_SLOPES +/** + * General collision improvements. See "src/engine/surface_load.h" to toggle specific changes. + */ +#define COLLISION_IMPROVEMENTS + /** * Buffers an A input if you jump off a slope during the landing lag */ diff --git a/include/surface_terrains.h b/include/surface_terrains.h index 765abacdd2..ca314827d6 100644 --- a/include/surface_terrains.h +++ b/include/surface_terrains.h @@ -257,6 +257,7 @@ enum SurfaceFlags { SURFACE_FLAGS_NONE = (0 << 0), // 0x0000 SURFACE_FLAG_DYNAMIC = (1 << 0), // 0x0001 SURFACE_FLAG_NO_CAM_COLLISION = (1 << 1), // 0x0002 + SURFACE_FLAG_X_PROJECTION = (1 << 3), // 0x0008 }; // These are effectively unique "surface" types like those defined higher diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 8b54ef8aff..ac4e89426b 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -10,27 +10,32 @@ #include "surface_load.h" #include "game/puppyprint.h" + /************************************************** * WALLS * **************************************************/ -static s32 check_wall_vw(f32 d00, f32 d01, f32 d11, f32 d20, f32 d21, f32 invDenom) { +#ifdef ROUNDED_WALL_CORNERS + +static s32 check_wall_triangle_vw(f32 d00, f32 d01, f32 d11, f32 d20, f32 d21, f32 invDenom) { f32 v = ((d11 * d20) - (d01 * d21)) * invDenom; if (v < 0.0f || v > 1.0f) { return TRUE; } f32 w = ((d00 * d21) - (d01 * d20)) * invDenom; - if (w < 0.0f || w > 1.0f || v + w > 1.0f) { + if (w < 0.0f || w > 1.0f || (v + w) > 1.0f) { return TRUE; } return FALSE; } -s32 check_wall_edge(Vec3f vert, Vec3f v2, f32 *d00, f32 *d01, f32 *invDenom, f32 *offset, f32 margin_radius) { - if (FLT_IS_NONZERO(vert[1])) { - f32 v = (v2[1] / vert[1]); +s32 check_wall_triangle_edge(Vec3f vert, Vec3f v2, f32 *d00, f32 *d01, f32 *invDenom, f32 *offset, f32 margin_radius) { + f32 y = vert[1]; + + if (FLT_IS_NONZERO(y)) { + f32 v = (v2[1] / y); if (v < 0.0f || v > 1.0f) { return TRUE; } @@ -46,24 +51,35 @@ s32 check_wall_edge(Vec3f vert, Vec3f v2, f32 *d00, f32 *d01, f32 *invDenom, f32 return TRUE; } +#endif + /** * Iterate through the list of walls until all walls are checked and * have given their wall push. */ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struct WallCollisionData *data) { - const f32 corner_threshold = -0.9f; - struct Surface *surf; - f32 offset; + struct Surface *surf = NULL; f32 radius = data->radius; - Vec3f pos = { data->x, data->y + data->offsetY, data->z }; - Vec3f v0, v1, v2; - f32 d00, d01, d11, d20, d21; - f32 invDenom; TerrainData type = SURFACE_DEFAULT; s32 numCols = 0; - +#ifdef ROUNDED_WALL_CORNERS + const f32 corner_threshold = -0.9f; f32 margin_radius = radius - 1.0f; +#endif + + s32 checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); + s32 returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); + + // Check whether the object will be able to pass through certain walls. + struct Object* obj = o; + s32 passVanishWalls = ( + (obj != NULL) && ( + (obj->activeFlags & ACTIVE_FLAG_MOVE_THROUGH_GRATE) || + (obj == gMarioObject && (gMarioState->flags & MARIO_VANISH_CAP)) + ) + ); + // Stay in this loop until out of walls. while (surfaceNode != NULL) { @@ -75,59 +91,54 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc if (pos[1] < surf->lowerY || pos[1] > surf->upperY) continue; // Determine if checking for the camera or not. - if (gCollisionFlags & COLLISION_FLAG_CAMERA) { + if (checkingForCamera) { if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) continue; } else { // Ignore camera only surfaces. if (type == SURFACE_CAMERA_BOUNDARY) continue; // If an object can pass through a vanish cap wall, pass through. - if (type == SURFACE_VANISH_CAP_WALLS && o != NULL) { - // If an object can pass through a vanish cap wall, pass through. - if (o->activeFlags & ACTIVE_FLAG_MOVE_THROUGH_GRATE) continue; - // If Mario has a vanish cap, pass through the vanish cap wall. - if (o == gMarioObject && gMarioState->flags & MARIO_VANISH_CAP) continue; - } + if (passVanishWalls && (type == SURFACE_VANISH_CAP_WALLS)) continue; } // Dot of normal and pos, + origin offset - offset = (surf->normal.x * pos[0]) - + (surf->normal.y * pos[1]) - + (surf->normal.z * pos[2]) - + surf->originOffset; + f32 offset = (surf->normal.x * pos[0]) + + (surf->normal.y * pos[1]) + + (surf->normal.z * pos[2]) + + surf->originOffset; // Exclude surfaces outside of the radius. if (offset < -radius || offset > radius) continue; +#ifdef ROUNDED_WALL_CORNERS + Vec3f v0, v1, v2; vec3_diff(v0, surf->vertex2, surf->vertex1); vec3_diff(v1, surf->vertex3, surf->vertex1); vec3_diff(v2, pos, surf->vertex1); // Face - d00 = vec3_dot(v0, v0); - d01 = vec3_dot(v0, v1); - d11 = vec3_dot(v1, v1); - d20 = vec3_dot(v2, v0); - d21 = vec3_dot(v2, v1); + f32 d00 = vec3_dot(v0, v0); + f32 d01 = vec3_dot(v0, v1); + f32 d11 = vec3_dot(v1, v1); + f32 d20 = vec3_dot(v2, v0); + f32 d21 = vec3_dot(v2, v1); - invDenom = (d00 * d11) - (d01 * d01); + f32 invDenom = (d00 * d11) - (d01 * d01); if (FLT_IS_NONZERO(invDenom)) { invDenom = 1.0f / invDenom; } - if (check_wall_vw(d00, d01, d11, d20, d21, invDenom)) { - if (offset < 0) { - continue; - } + if (check_wall_triangle_vw(d00, d01, d11, d20, d21, invDenom)) { + if (offset < 0) continue; // Edge 1-2 - if (check_wall_edge(v0, v2, &d00, &d01, &invDenom, &offset, margin_radius)) { + if (check_wall_triangle_edge(v0, v2, &d00, &d01, &invDenom, &offset, margin_radius)) { // Edge 1-3 - if (check_wall_edge(v1, v2, &d00, &d01, &invDenom, &offset, margin_radius)) { + if (check_wall_triangle_edge(v1, v2, &d00, &d01, &invDenom, &offset, margin_radius)) { vec3_diff(v1, surf->vertex3, surf->vertex2); vec3_diff(v2, pos, surf->vertex2); // Edge 2-3 - if (check_wall_edge(v1, v2, &d00, &d01, &invDenom, &offset, margin_radius)) { + if (check_wall_triangle_edge(v1, v2, &d00, &d01, &invDenom, &offset, margin_radius)) { continue; } } @@ -151,6 +162,56 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc pos[0] += surf->normal.x * (radius - offset); pos[2] += surf->normal.z * (radius - offset); } +#else + f32 x = pos[0]; + f32 y = pos[1]; + f32 z = pos[2]; + f32 w1, w2, w3; + f32 y1, y2, y3; + + //! (Quantum Tunneling) Due to issues with the vertices walls choose and + // the fact they are floating point, certain floating point positions + // along the seam of two walls may collide with neither wall or both walls. + if (surf->flags & SURFACE_FLAG_X_PROJECTION) { + w1 = -surf->vertex1[2]; w2 = -surf->vertex2[2]; w3 = -surf->vertex3[2]; + y1 = surf->vertex1[1]; y2 = surf->vertex2[1]; y3 = surf->vertex3[1]; + + if (surf->normal.x > 0.0f) { + if ( + ((((y1 - y) * (w2 - w1)) - ((w1 - -z) * (y2 - y1))) > 0.0f) || + ((((y2 - y) * (w3 - w2)) - ((w2 - -z) * (y3 - y2))) > 0.0f) || + ((((y3 - y) * (w1 - w3)) - ((w3 - -z) * (y1 - y3))) > 0.0f) + ) continue; + } else { + if ( + ((((y1 - y) * (w2 - w1)) - ((w1 - -z) * (y2 - y1))) < 0.0f) || + ((((y2 - y) * (w3 - w2)) - ((w2 - -z) * (y3 - y2))) < 0.0f) || + ((((y3 - y) * (w1 - w3)) - ((w3 - -z) * (y1 - y3))) < 0.0f) + ) continue; + } + } else { + w1 = surf->vertex1[0]; w2 = surf->vertex2[0]; w3 = surf->vertex3[0]; + y1 = surf->vertex1[1]; y2 = surf->vertex2[1]; y3 = surf->vertex3[1]; + + if (surf->normal.z > 0.0f) { + if ( + ((((y1 - y) * (w2 - w1)) - ((w1 - x) * (y2 - y1))) > 0.0f) || + ((((y2 - y) * (w3 - w2)) - ((w2 - x) * (y3 - y2))) > 0.0f) || + ((((y3 - y) * (w1 - w3)) - ((w3 - x) * (y1 - y3))) > 0.0f) + ) continue; + } else { + if ( + ((((y1 - y) * (w2 - w1)) - ((w1 - x) * (y2 - y1))) < 0.0f) || + ((((y2 - y) * (w3 - w2)) - ((w2 - x) * (y3 - y2))) < 0.0f) || + ((((y3 - y) * (w1 - w3)) - ((w3 - x) * (y1 - y3))) < 0.0f) + ) continue; + } + } + + // Update pos + pos[0] += surf->normal.x * (radius - offset); + pos[2] += surf->normal.z * (radius - offset); +#endif // Has collision if (data->numWalls < MAX_REFERENCED_WALLS) { @@ -158,13 +219,14 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc } numCols++; - if (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST) { + if (returnFirst) { break; } } data->x = pos[0]; data->z = pos[2]; + return numCols; } @@ -211,10 +273,11 @@ s32 find_wall_collisions(struct WallCollisionData *colData) { } // World (level) consists of a 16x16 grid. Find where the collision is on the grid (round toward -inf) - s32 minCellX = GET_CELL_COORD(x - colData->radius); - s32 minCellZ = GET_CELL_COORD(z - colData->radius); - s32 maxCellX = GET_CELL_COORD(x + colData->radius); - s32 maxCellZ = GET_CELL_COORD(z + colData->radius); + s32 radius = colData->radius; + s32 minCellX = GET_CELL_COORD(x - radius); + s32 minCellZ = GET_CELL_COORD(z - radius); + s32 maxCellX = GET_CELL_COORD(x + radius); + s32 maxCellZ = GET_CELL_COORD(z + radius); for (s32 cellX = minCellX; cellX <= maxCellX; cellX++) { for (s32 cellZ = minCellZ; cellZ <= maxCellZ; cellZ++) { @@ -262,16 +325,19 @@ void resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius, struc **************************************************/ void add_ceil_margin(s32 *x, s32 *z, Vec3s target1, Vec3s target2, f32 margin) { - register f32 diff_x = target1[0] - *x + target2[0] - *x; - register f32 diff_z = target1[2] - *z + target2[2] - *z; - register f32 invDenom = margin / sqrtf(sqr(diff_x) + sqr(diff_z)); +#ifndef ADD_CEILING_MARGINS + return; +#endif + f32 diff_x = (target1[0] - *x) + (target2[0] - *x); + f32 diff_z = (target1[2] - *z) + (target2[2] - *z); + f32 invDenom = margin / sqrtf(sqr(diff_x) + sqr(diff_z)); *x += diff_x * invDenom; *z += diff_z * invDenom; } static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *surf, f32 margin) { - s32 addMargin = surf->type != SURFACE_HANGABLE && !FLT_IS_NONZERO(margin); + s32 addMargin = ((surf->type != SURFACE_HANGABLE) && !FLT_IS_NONZERO(margin)); Vec3i vx, vz; vx[0] = surf->vertex1[0]; vz[0] = surf->vertex1[2]; diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c index a68362d698..e52e19c174 100644 --- a/src/engine/surface_load.c +++ b/src/engine/surface_load.c @@ -134,6 +134,12 @@ static void add_surface_to_cell(s32 dynamic, s32 cellX, s32 cellZ, struct Surfac } else { listIndex = SPATIAL_PARTITION_WALLS; sortDir = 0; // insertion order + +#ifndef ROUNDED_WALL_CORNERS + if (surface->normal.x < -COS45 || surface->normal.x > COS45) { + surface->flags |= SURFACE_FLAG_X_PROJECTION; + } +#endif } s32 surfacePriority = surface->upperY * sortDir; diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index fcfc3c7f89..fc9b4252d8 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -6,6 +6,21 @@ #include "surface_collision.h" #include "types.h" + +#ifdef COLLISION_IMPROVEMENTS + // Improves the handling of convex wall corners by rounding the seams. + #define ROUNDED_WALL_CORNERS + // Improves the handling of concave wall corners by properly handling simultaneous collision with multiple walls. + #define SIMULTANEOUS_WALL_COLLISIONS //! TODO: + // When finding a floor surface under the source height, get the highest floor instead of just the first floor in the list. + #define SLOPE_FIX //! TODO: + // Makes the area above ceilings without a floor not count as OOB. + #define EXPOSED_CEILINGS_FIX //! TODO: + // Adds a margin to ceilings + #define ADD_CEILING_MARGINS +#endif + + #define SURFACE_VERTICAL_BUFFER 5 #define NORMAL_FLOOR_THRESHOLD 0.01f From 02f524b4476d17322c51f1731426716b5722c2c6 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 02:39:59 -0800 Subject: [PATCH 02/25] Add SLOPE_FIX define and remove add_ceil_margin --- include/config/config_movement.h | 2 +- src/engine/surface_collision.c | 83 +++++++++++++++++--------------- src/engine/surface_load.h | 6 +-- 3 files changed, 47 insertions(+), 44 deletions(-) diff --git a/include/config/config_movement.h b/include/config/config_movement.h index 9ba87ad6fa..fb9609864a 100644 --- a/include/config/config_movement.h +++ b/include/config/config_movement.h @@ -114,7 +114,7 @@ #define DONT_LEDGE_GRAB_STEEP_SLOPES /** - * General collision improvements. See "src/engine/surface_load.h" to toggle specific changes. + * General collision improvements. See "src/engine/surface_load.h" to toggle specific changes. Disable this to use vanilla collision handling. */ #define COLLISION_IMPROVEMENTS diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index ac4e89426b..6f2358be55 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -68,12 +68,12 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc f32 margin_radius = radius - 1.0f; #endif - s32 checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); - s32 returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); + _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); + _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); // Check whether the object will be able to pass through certain walls. struct Object* obj = o; - s32 passVanishWalls = ( + _Bool canPassVanishWalls = ( (obj != NULL) && ( (obj->activeFlags & ACTIVE_FLAG_MOVE_THROUGH_GRATE) || (obj == gMarioObject && (gMarioState->flags & MARIO_VANISH_CAP)) @@ -98,7 +98,7 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc if (type == SURFACE_CAMERA_BOUNDARY) continue; // If an object can pass through a vanish cap wall, pass through. - if (passVanishWalls && (type == SURFACE_VANISH_CAP_WALLS)) continue; + if (canPassVanishWalls && (type == SURFACE_VANISH_CAP_WALLS)) continue; } // Dot of normal and pos, + origin offset @@ -324,28 +324,12 @@ void resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius, struc * CEILINGS * **************************************************/ -void add_ceil_margin(s32 *x, s32 *z, Vec3s target1, Vec3s target2, f32 margin) { -#ifndef ADD_CEILING_MARGINS - return; -#endif - f32 diff_x = (target1[0] - *x) + (target2[0] - *x); - f32 diff_z = (target1[2] - *z) + (target2[2] - *z); - f32 invDenom = margin / sqrtf(sqr(diff_x) + sqr(diff_z)); - - *x += diff_x * invDenom; - *z += diff_z * invDenom; -} - -static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *surf, f32 margin) { - s32 addMargin = ((surf->type != SURFACE_HANGABLE) && !FLT_IS_NONZERO(margin)); +static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *surf) { Vec3i vx, vz; vx[0] = surf->vertex1[0]; vz[0] = surf->vertex1[2]; - if (addMargin) add_ceil_margin(&vx[0], &vz[0], surf->vertex2, surf->vertex3, margin); - vx[1] = surf->vertex2[0]; vz[1] = surf->vertex2[2]; - if (addMargin) add_ceil_margin(&vx[1], &vz[1], surf->vertex3, surf->vertex1, margin); // Checking if point is in bounds of the triangle laterally. if (((vz[0] - z) * (vx[1] - vx[0]) - (vx[0] - x) * (vz[1] - vz[0])) > 0) return FALSE; @@ -353,7 +337,6 @@ static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *surf, // Slight optimization by checking these later. vx[2] = surf->vertex3[0]; vz[2] = surf->vertex3[2]; - if (addMargin) add_ceil_margin(&vx[2], &vz[2], surf->vertex1, surf->vertex2, margin); if (((vz[1] - z) * (vx[2] - vx[1]) - (vx[1] - x) * (vz[2] - vz[1])) > 0) return FALSE; if (((vz[2] - z) * (vx[0] - vx[2]) - (vx[2] - x) * (vz[0] - vz[2])) > 0) return FALSE; @@ -365,21 +348,25 @@ static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *surf, * Iterate through the list of ceilings and find the first ceiling over a given point. */ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) { - register struct Surface *surf, *ceil = NULL; - register f32 height; + struct Surface *surf, *ceil = NULL; + f32 height; SurfaceType type = SURFACE_DEFAULT; *pheight = CELL_HEIGHT_LIMIT; + + _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); + _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); + // Stay in this loop until out of ceilings. while (surfaceNode != NULL) { - surf = surfaceNode->surface; + surf = surfaceNode->surface; surfaceNode = surfaceNode->next; - type = surf->type; + type = surf->type; // Exclude all ceilings below the point if (y > surf->upperY) continue; // Determine if checking for the camera or not - if (gCollisionFlags & COLLISION_FLAG_CAMERA) { + if (checkingForCamera) { if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) { continue; } @@ -389,7 +376,7 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 } // Check that the point is within the triangle bounds - if (!check_within_ceil_triangle_bounds(x, z, surf, 1.5f)) continue; + if (!check_within_ceil_triangle_bounds(x, z, surf)) continue; // Find the height of the ceil at the given location height = get_surface_height_at_location(x, z, surf); @@ -407,8 +394,12 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 // Exit the loop if it's not possible for another ceiling to be closer // to the original point, or if COLLISION_FLAG_RETURN_FIRST. - if (height == y || (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST)) break; + if (height == y) break; +#ifdef SLOPE_FIX + if (returnFirst) break; +#endif } + return ceil; } @@ -484,13 +475,16 @@ static s32 check_within_floor_triangle_bounds(s32 x, s32 z, struct Surface *surf vx[1] = surf->vertex2[0]; vz[1] = surf->vertex2[2]; + // Checking if point is in bounds of the triangle laterally. if (((vz[0] - z) * (vx[1] - vx[0]) - (vx[0] - x) * (vz[1] - vz[0])) < 0) return FALSE; + // Slight optimization by checking these later. vx[2] = surf->vertex3[0]; vz[2] = surf->vertex3[2]; if (((vz[1] - z) * (vx[2] - vx[1]) - (vx[1] - x) * (vz[2] - vz[1])) < 0) return FALSE; if (((vz[2] - z) * (vx[0] - vx[2]) - (vx[2] - x) * (vz[0] - vz[2])) < 0) return FALSE; + return TRUE; } @@ -498,26 +492,30 @@ static s32 check_within_floor_triangle_bounds(s32 x, s32 z, struct Surface *surf * Iterate through the list of floors and find the first floor under a given point. */ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) { - register struct Surface *surf, *floor = NULL; - register SurfaceType type = SURFACE_DEFAULT; - register f32 height; - register s32 bufferY = y + FIND_FLOOR_BUFFER; + struct Surface *surf, *floor = NULL; + SurfaceType type = SURFACE_DEFAULT; + f32 height; + s32 bufferY = y + FIND_FLOOR_BUFFER; + + _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); + _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); + _Bool skipIntangible = !(gCollisionFlags & COLLISION_FLAG_INCLUDE_INTANGIBLE); // Iterate through the list of floors until there are no more floors. while (surfaceNode != NULL) { - surf = surfaceNode->surface; + surf = surfaceNode->surface; surfaceNode = surfaceNode->next; type = surf->type; // To prevent the Merry-Go-Round room from loading when Mario passes above the hole that leads // there, SURFACE_INTANGIBLE is used. This prevent the wrong room from loading, but can also allow // Mario to pass through. - if (!(gCollisionFlags & COLLISION_FLAG_INCLUDE_INTANGIBLE) && (type == SURFACE_INTANGIBLE)) { + if (skipIntangible && (type == SURFACE_INTANGIBLE)) { continue; } // Determine if we are checking for the camera or not. - if (gCollisionFlags & COLLISION_FLAG_CAMERA) { + if (checkingForCamera) { if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) { continue; } @@ -527,6 +525,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 // Exclude all floors above the point. if (bufferY < surf->lowerY) continue; + // Check that the point is within the triangle bounds. if (!check_within_floor_triangle_bounds(x, z, surf)) continue; @@ -545,15 +544,21 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 // Exit the loop if it's not possible for another floor to be closer // to the original point, or if COLLISION_FLAG_RETURN_FIRST. - if ((height == bufferY) || (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST)) break; + if (height == bufferY) break; +#ifdef SLOPE_FIX + if (returnFirst) break; +#else + break; +#endif } + return floor; } // Generic triangle bounds func ALWAYS_INLINE static s32 check_within_bounds_y_norm(s32 x, s32 z, struct Surface *surf) { if (surf->normal.y >= NORMAL_FLOOR_THRESHOLD) return check_within_floor_triangle_bounds(x, z, surf); - return check_within_ceil_triangle_bounds(x, z, surf, 0); + return check_within_ceil_triangle_bounds(x, z, surf); } /** @@ -887,7 +892,7 @@ s32 find_poison_gas_level(s32 x, s32 z) { p += 6; } } - + profiler_collision_update(first); return gasLevel; } diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index fc9b4252d8..d83a677958 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -13,11 +13,9 @@ // Improves the handling of concave wall corners by properly handling simultaneous collision with multiple walls. #define SIMULTANEOUS_WALL_COLLISIONS //! TODO: // When finding a floor surface under the source height, get the highest floor instead of just the first floor in the list. - #define SLOPE_FIX //! TODO: - // Makes the area above ceilings without a floor not count as OOB. + #define SLOPE_FIX + // Makes the area above ceilings without a floor not count as OOB. #define EXPOSED_CEILINGS_FIX //! TODO: - // Adds a margin to ceilings - #define ADD_CEILING_MARGINS #endif From 21d3c14ade017b370a84b41cccd820366a21e0ee Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 14:07:48 -0800 Subject: [PATCH 03/25] Avoid calculating FIND_FLOOR_BUFFER twice --- src/engine/surface_collision.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 6f2358be55..ca86312723 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -495,7 +495,6 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 struct Surface *surf, *floor = NULL; SurfaceType type = SURFACE_DEFAULT; f32 height; - s32 bufferY = y + FIND_FLOOR_BUFFER; _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); @@ -524,7 +523,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 } // Exclude all floors above the point. - if (bufferY < surf->lowerY) continue; + if (y < surf->lowerY) continue; // Check that the point is within the triangle bounds. if (!check_within_floor_triangle_bounds(x, z, surf)) continue; @@ -536,7 +535,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 if (height <= *pheight) continue; // Checks for floor interaction with a FIND_FLOOR_BUFFER unit buffer. - if (bufferY < height) continue; + if (y < height) continue; // Use the current floor *pheight = height; @@ -544,7 +543,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 // Exit the loop if it's not possible for another floor to be closer // to the original point, or if COLLISION_FLAG_RETURN_FIRST. - if (height == bufferY) break; + if (height == y) break; #ifdef SLOPE_FIX if (returnFirst) break; #else @@ -565,7 +564,7 @@ ALWAYS_INLINE static s32 check_within_bounds_y_norm(s32 x, s32 z, struct Surface * Iterate through the list of water floors and find the first water floor under a given point. */ struct Surface *find_water_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) { - register struct Surface *surf; + struct Surface *surf; struct Surface *floor = NULL; struct SurfaceNode *topSurfaceNode = surfaceNode; struct SurfaceNode *bottomSurfaceNode = surfaceNode; @@ -637,7 +636,7 @@ f32 unused_find_dynamic_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfl // Would normally cause PUs, but dynamic floors unload at that range. s32 x = xPos; - s32 y = yPos; + s32 y = yPos + FIND_FLOOR_BUFFER; s32 z = zPos; // Each level is split into cells to limit load, find the appropriate cell. @@ -661,11 +660,11 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { f32 height = FLOOR_LOWER_LIMIT; f32 dynamicHeight = FLOOR_LOWER_LIMIT; - //! (Parallel Universes) Because position is casted to an s16, reaching higher + //! (Parallel Universes) Because position is casted to an s32, reaching higher // float locations can return floors despite them not existing there. // (Dynamic floors will unload due to the range.) s32 x = xPos; - s32 y = yPos; + s32 y = yPos + FIND_FLOOR_BUFFER; s32 z = zPos; *pfloor = NULL; From 96f19dcecd81d0ad9bb998f90357c94c4ccded48 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 14:40:29 -0800 Subject: [PATCH 04/25] Make find_ceil consistent with find_floor --- src/engine/surface_collision.c | 37 +++++++++++++++++----------------- src/engine/surface_load.h | 8 ++++---- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index ca86312723..e8e7c2b0bb 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -356,39 +356,37 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); - // Stay in this loop until out of ceilings. + // Iterate through the list of ceilings until there are no more ceilings. while (surfaceNode != NULL) { surf = surfaceNode->surface; surfaceNode = surfaceNode->next; type = surf->type; - // Exclude all ceilings below the point - if (y > surf->upperY) continue; - - // Determine if checking for the camera or not + // Determine if checking for the camera or not. if (checkingForCamera) { if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) { continue; } } else if (type == SURFACE_CAMERA_BOUNDARY) { - // Ignore camera only surfaces - continue; + continue; // If we are not checking for the camera, ignore camera only ceilings. } - // Check that the point is within the triangle bounds + // Exclude all ceilings below the point. + if (y > surf->upperY) continue; + + // Check that the point is within the triangle bounds. if (!check_within_ceil_triangle_bounds(x, z, surf)) continue; - // Find the height of the ceil at the given location + // Find the height of the ceiling above the current location. height = get_surface_height_at_location(x, z, surf); - // Exclude ceilings above the previous lowest ceiling + // Exclude ceilings above the previous lowest ceiling. if (height > *pheight) continue; - // Checks for ceiling interaction + // Checks for ceiling interaction. if (y > height) continue; - - // Use the current ceiling + // Use the current ceiling. *pheight = height; ceil = surf; @@ -407,13 +405,16 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 * Find the lowest ceiling above a given position and return the height. */ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) { - f32 height = CELL_HEIGHT_LIMIT; - f32 dynamicHeight = CELL_HEIGHT_LIMIT; PUPPYPRINT_ADD_COUNTER(gPuppyCallCounter.collision_ceil); PUPPYPRINT_GET_SNAPSHOT(); + + f32 height = CELL_HEIGHT_LIMIT; + f32 dynamicHeight = CELL_HEIGHT_LIMIT; + s32 x = posX; s32 y = posY; s32 z = posZ; + *pceil = NULL; if (is_outside_level_bounds(x, z)) { @@ -537,7 +538,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 // Checks for floor interaction with a FIND_FLOOR_BUFFER unit buffer. if (y < height) continue; - // Use the current floor + // Use the current floor. *pheight = height; floor = surf; @@ -660,9 +661,6 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { f32 height = FLOOR_LOWER_LIMIT; f32 dynamicHeight = FLOOR_LOWER_LIMIT; - //! (Parallel Universes) Because position is casted to an s32, reaching higher - // float locations can return floors despite them not existing there. - // (Dynamic floors will unload due to the range.) s32 x = xPos; s32 y = yPos + FIND_FLOOR_BUFFER; s32 z = zPos; @@ -673,6 +671,7 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { profiler_collision_update(first); return height; } + // Each level is split into cells to limit load, find the appropriate cell. s32 cellX = GET_CELL_COORD(x); s32 cellZ = GET_CELL_COORD(z); diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index d83a677958..101448fdc4 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -10,12 +10,12 @@ #ifdef COLLISION_IMPROVEMENTS // Improves the handling of convex wall corners by rounding the seams. #define ROUNDED_WALL_CORNERS - // Improves the handling of concave wall corners by properly handling simultaneous collision with multiple walls. - #define SIMULTANEOUS_WALL_COLLISIONS //! TODO: + //! TODO: Improves the handling of concave wall corners by properly handling simultaneous collision with multiple walls. + #define SIMULTANEOUS_WALL_COLLISIONS // When finding a floor surface under the source height, get the highest floor instead of just the first floor in the list. #define SLOPE_FIX - // Makes the area above ceilings without a floor not count as OOB. - #define EXPOSED_CEILINGS_FIX //! TODO: + //! TODO: Makes the area above ceilings without a floor not count as OOB. + #define EXPOSED_CEILINGS_FIX #endif From b0018756b37904914b3e8a4030ce75dc3bbb4698 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 17:38:26 -0800 Subject: [PATCH 05/25] Improved debug free move --- src/game/camera.c | 4 ++- src/game/mario_actions_cutscene.c | 54 ++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/game/camera.c b/src/game/camera.c index 8cd629d0af..478f3dd7f4 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -710,6 +710,8 @@ void set_camera_height(struct Camera *c, f32 goalHeight) { } approach_camera_height(c, goalHeight, 5.f); + } else if (sMarioCamState->action == ACT_DEBUG_FREE_MOVE) { + c->pos[1] = goalHeight; } else { camFloorHeight = find_floor(c->pos[0], c->pos[1] + 100.f, c->pos[2], &surface) + baseOff; marioFloorHeight = baseOff + sMarioGeometry.currFloorHeight; @@ -1135,7 +1137,7 @@ void mode_8_directions_camera(struct Camera *c) { } #ifdef PARALLEL_LAKITU_CAM // extra functionality - else if (gPlayer1Controller->buttonPressed & U_JPAD) { + else if ((gPlayer1Controller->buttonPressed & U_JPAD) && (gMarioState->action != ACT_DEBUG_FREE_MOVE)) { s8DirModeYawOffset = 0; s8DirModeYawOffset = gMarioState->faceAngle[1] - 0x8000; } diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index 06684a9ae3..ca80fb51c5 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -514,24 +514,35 @@ s32 act_reading_sign(struct MarioState *m) { } s32 act_debug_free_move(struct MarioState *m) { + struct Controller *controller = m->controller; struct WallCollisionData wallData; struct Surface *floor, *ceil; Vec3f pos; + f32 speed = 1.0f; + _Bool checkCollisions = TRUE; - f32 speed = (gPlayer1Controller->buttonDown & B_BUTTON) ? 4.0f : 1.0f; - if (gPlayer1Controller->buttonDown & Z_TRIG) speed = 0.01f; - if (m->area->camera->mode != CAMERA_MODE_8_DIRECTIONS) set_camera_mode(m->area->camera, CAMERA_MODE_8_DIRECTIONS, 1); + if (m->area->camera->mode != CAMERA_MODE_8_DIRECTIONS) { + set_camera_mode(m->area->camera, CAMERA_MODE_8_DIRECTIONS, 1); + } set_mario_animation(m, MARIO_ANIM_A_POSE); vec3f_copy(pos, m->pos); - if (gPlayer1Controller->buttonDown & U_JPAD) { + if (controller->buttonDown & B_BUTTON) { + speed = 4.0f; + checkCollisions = FALSE; + } + if (controller->buttonDown & Z_TRIG) { + speed = 0.01f; + } + if (controller->buttonDown & U_JPAD) { pos[1] += 16.0f * speed; } - if (gPlayer1Controller->buttonDown & D_JPAD) { + if (controller->buttonDown & D_JPAD) { pos[1] -= 16.0f * speed; } - if (gPlayer1Controller->buttonPressed & A_BUTTON) { + + if ((controller->buttonPressed & A_BUTTON) && (m->floor != NULL)) { vec3_zero(m->vel); m->forwardVel = 0.0f; @@ -544,7 +555,7 @@ s32 act_debug_free_move(struct MarioState *m) { } else { // slight upwards boost to get you some hover time m->vel[1] = 20.0f; - gPlayer1Controller->buttonDown &= ~U_JPAD; + controller->buttonDown &= ~U_JPAD; return set_mario_action(m, ACT_FREEFALL, 0); } } @@ -553,31 +564,38 @@ s32 act_debug_free_move(struct MarioState *m) { speed *= m->intendedMag * 2.0f; pos[0] += speed * sins(m->intendedYaw); pos[2] += speed * coss(m->intendedYaw); + m->faceAngle[1] = m->intendedYaw; + vec3s_set(m->marioObj->header.gfx.angle, 0x0, m->faceAngle[1], 0x0); } // TODO: Add ability to ignore collision - // - spawn pseudo floor object to prevent OOB death - resolve_and_return_wall_collisions(pos, 60.0f, 50.0f, &wallData); + // - spawn pseudo floor object to prevent OOB death + if (checkCollisions) { + resolve_and_return_wall_collisions(pos, 60.0f, 50.0f, &wallData); + set_mario_wall(m, ((wallData.numWalls > 0) ? wallData.walls[0] : NULL)); + } - set_mario_wall(m, ((wallData.numWalls > 0) ? wallData.walls[0] : NULL)); f32 floorHeight = find_floor(pos[0], pos[1], pos[2], &floor); f32 ceilHeight = find_mario_ceil(pos, floorHeight, &ceil); - if (floor == NULL) return FALSE; + if (floor == NULL) { + return FALSE; + } - if (ceilHeight - floorHeight >= 160.0f) { - if (floor != NULL && pos[1] < floorHeight) { + if (checkCollisions) { + if ((ceilHeight - floorHeight) < 160.0f) { + return FALSE; + } + if ((floor != NULL) && (pos[1] < floorHeight)) { pos[1] = floorHeight; } - if (ceil != NULL && pos[1] + 160.0f > ceilHeight) { + if ((ceil != NULL) && ((pos[1] + 160.0f) > ceilHeight) && (pos[1] < ceilHeight)) { pos[1] = ceilHeight - 160.0f; } - vec3f_copy(m->pos, pos); } - m->faceAngle[1] = m->intendedYaw; - vec3f_copy(m->marioObj->header.gfx.pos, m->pos); - vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0); + vec3f_copy(m->pos, pos); + vec3f_copy(m->marioObj->header.gfx.pos, pos); return FALSE; } From d9ac2bf3466542d5d84c46eaf318857983207d78 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 17:53:56 -0800 Subject: [PATCH 06/25] Implement EXPOSED_CEILINGS_FIX and DISABLE_CEILING_BONKS defines --- src/engine/surface_collision.h | 5 +++++ src/engine/surface_load.h | 9 ++++++--- src/game/mario_step.c | 14 +++++++++++--- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/engine/surface_collision.h b/src/engine/surface_collision.h index 4078163d67..438f5791ee 100644 --- a/src/engine/surface_collision.h +++ b/src/engine/surface_collision.h @@ -6,6 +6,7 @@ #include "types.h" #include "config/config_world.h" +#include "surface_load.h" // The y coord is moved upward by this amount when finding floors. // Vanilla value is 78. @@ -49,7 +50,11 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil); // Finds the ceiling from a vec3f and a minimum height (with 3 unit vertical buffer). ALWAYS_INLINE f32 find_mario_ceil(Vec3f pos, f32 height, struct Surface **ceil) { +#ifdef EXPOSED_CEILINGS_FIX return find_ceil(pos[0], MAX(height, pos[1]) + 3.0f, pos[2], ceil); +#else + return find_ceil(pos[0], (height + 3.0f), pos[2], ceil); +#endif } f32 find_floor_height(f32 x, f32 y, f32 z); diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index 101448fdc4..5d20dc877f 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -8,14 +8,17 @@ #ifdef COLLISION_IMPROVEMENTS - // Improves the handling of convex wall corners by rounding the seams. + // Improves the handling of convex wall corners by rounding collision at the edges to close the seams. #define ROUNDED_WALL_CORNERS - //! TODO: Improves the handling of concave wall corners by properly handling simultaneous collision with multiple walls. + //! TODO: Improves the handling of concave wall corners by properly handling simultaneous collision with multiple walls (eg. concave wall corners or narrow tunnels). #define SIMULTANEOUS_WALL_COLLISIONS // When finding a floor surface under the source height, get the highest floor instead of just the first floor in the list. #define SLOPE_FIX - //! TODO: Makes the area above ceilings without a floor not count as OOB. + // Fixes a bug where entering any area above a ceiling without an intermediate floor would count as hitting a ceiling. + // NOTE: This causes Mario to potentially clip through the vertical part of the rocking JRB ship at cettain angles. #define EXPOSED_CEILINGS_FIX + // Makes ceilings interaction separate than wall interaction so that Mario doesn't bonk on ceilings. + #define DISABLE_CEILING_BONKS #endif diff --git a/src/game/mario_step.c b/src/game/mario_step.c index 9b43b9cae7..d3c9f38def 100644 --- a/src/game/mario_step.c +++ b/src/game/mario_step.c @@ -511,12 +511,16 @@ s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepAr if (m->vel[1] >= 0.0f) { m->vel[1] = 0.0f; + if ( + (ceil != NULL) && + (ceil->type == SURFACE_HANGABLE) && #ifdef HANGING_FIX - // Grab ceiling unless they just were grabbing a ceiling - if (!(m->prevAction & ACT_FLAG_HANGING) && ceil != NULL && ceil->type == SURFACE_HANGABLE) { + // Grab ceiling unless they just were grabbing a ceiling. + !(m->prevAction & ACT_FLAG_HANGING) #else - if ((stepArg & AIR_STEP_CHECK_HANG) && ceil != NULL && ceil->type == SURFACE_HANGABLE) { + (stepArg & AIR_STEP_CHECK_HANG) #endif + ) { return AIR_STEP_GRABBED_CEILING; } @@ -530,7 +534,11 @@ s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepAr } m->pos[1] = nextPos[1]; +#ifdef DISABLE_CEILING_BONKS return AIR_STEP_HIT_CEILING; +#else + return AIR_STEP_HIT_WALL; +#endif } //! When the wall is not completely vertical or there is a slight wall From b247c4d9bd1a2a739012046430fc4df3780150c4 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 18:01:20 -0800 Subject: [PATCH 07/25] Improve SLOPE_FIX ifdefs + small optimization --- src/engine/surface_collision.c | 41 ++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index e8e7c2b0bb..c7581e2387 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -349,13 +349,16 @@ static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *surf) */ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) { struct Surface *surf, *ceil = NULL; - f32 height; SurfaceType type = SURFACE_DEFAULT; - *pheight = CELL_HEIGHT_LIMIT; + f32 height, highest = *pheight; _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); +#ifndef SLOPE_FIX + returnFirst = TRUE; +#endif + // Iterate through the list of ceilings until there are no more ceilings. while (surfaceNode != NULL) { surf = surfaceNode->surface; @@ -381,23 +384,24 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 height = get_surface_height_at_location(x, z, surf); // Exclude ceilings above the previous lowest ceiling. - if (height > *pheight) continue; + if (height > highest) continue; // Checks for ceiling interaction. - if (y > height) continue; + if (height < y) continue; // Use the current ceiling. - *pheight = height; + highest = height; ceil = surf; // Exit the loop if it's not possible for another ceiling to be closer - // to the original point, or if COLLISION_FLAG_RETURN_FIRST. + // to the original point. if (height == y) break; -#ifdef SLOPE_FIX + if (returnFirst) break; -#endif } + *pheight = highest; + return ceil; } @@ -495,12 +499,16 @@ static s32 check_within_floor_triangle_bounds(s32 x, s32 z, struct Surface *surf static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) { struct Surface *surf, *floor = NULL; SurfaceType type = SURFACE_DEFAULT; - f32 height; + f32 height, highest = *pheight; _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); _Bool skipIntangible = !(gCollisionFlags & COLLISION_FLAG_INCLUDE_INTANGIBLE); +#ifndef SLOPE_FIX + returnFirst = TRUE; +#endif + // Iterate through the list of floors until there are no more floors. while (surfaceNode != NULL) { surf = surfaceNode->surface; @@ -533,25 +541,24 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 height = get_surface_height_at_location(x, z, surf); // Exclude floors lower than the previous highest floor. - if (height <= *pheight) continue; + if (height <= highest) continue; // Checks for floor interaction with a FIND_FLOOR_BUFFER unit buffer. - if (y < height) continue; + if (height > y) continue; // Use the current floor. - *pheight = height; + highest = height; floor = surf; // Exit the loop if it's not possible for another floor to be closer - // to the original point, or if COLLISION_FLAG_RETURN_FIRST. + // to the original point. if (height == y) break; -#ifdef SLOPE_FIX + if (returnFirst) break; -#else - break; -#endif } + *pheight = highest; + return floor; } From abfe05bbc3ea330ed429252ca2334d8f9e072e53 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 18:01:32 -0800 Subject: [PATCH 08/25] Improve define descriptions --- src/engine/surface_load.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index 5d20dc877f..af7b1085c7 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -8,16 +8,16 @@ #ifdef COLLISION_IMPROVEMENTS - // Improves the handling of convex wall corners by rounding collision at the edges to close the seams. + // Improves the handling of convex wall corners by rounding wall collision at triangle edges to close the seams. #define ROUNDED_WALL_CORNERS - //! TODO: Improves the handling of concave wall corners by properly handling simultaneous collision with multiple walls (eg. concave wall corners or narrow tunnels). + //! TODO: Pproperly handles simultaneous collision with multiple walls (eg. concave wall corners or narrow tunnels). #define SIMULTANEOUS_WALL_COLLISIONS - // When finding a floor surface under the source height, get the highest floor instead of just the first floor in the list. + // Uses the surface closest to the source height when searching for a floor or ceiling, instead of just using the first applicable surface in the list. #define SLOPE_FIX - // Fixes a bug where entering any area above a ceiling without an intermediate floor would count as hitting a ceiling. + // Fixes an issue where entering any area above a ceiling without an intermediate floor would count as hitting a ceiling. // NOTE: This causes Mario to potentially clip through the vertical part of the rocking JRB ship at cettain angles. #define EXPOSED_CEILINGS_FIX - // Makes ceilings interaction separate than wall interaction so that Mario doesn't bonk on ceilings. + // Disables bonking on sloped ceilings by separating the handling of ceiling interactions and wall interactions. #define DISABLE_CEILING_BONKS #endif From 93dceb102be659b5c7bf81c301bef7b714cab170 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 18:24:27 -0800 Subject: [PATCH 09/25] Fix Mario getting stuck squished if entering debug free move --- src/game/mario_actions_cutscene.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index ca80fb51c5..99fc59fac2 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -525,6 +525,7 @@ s32 act_debug_free_move(struct MarioState *m) { set_camera_mode(m->area->camera, CAMERA_MODE_8_DIRECTIONS, 1); } + m->squishTimer = 0; set_mario_animation(m, MARIO_ANIM_A_POSE); vec3f_copy(pos, m->pos); From 182c4fdbe371c99dbe8b540a2811ffda0f8906ea Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 18:29:47 -0800 Subject: [PATCH 10/25] Improve collision define comments --- src/engine/surface_load.h | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index af7b1085c7..cbdfb03690 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -8,16 +8,26 @@ #ifdef COLLISION_IMPROVEMENTS - // Improves the handling of convex wall corners by rounding wall collision at triangle edges to close the seams. + /** + * Improves the handling of convex wall corners by rounding wall collision at triangle edges to close the seams. + */ #define ROUNDED_WALL_CORNERS - //! TODO: Pproperly handles simultaneous collision with multiple walls (eg. concave wall corners or narrow tunnels). + /** + * TODO: Pproperly handles simultaneous collision with multiple walls (eg. concave wall corners or narrow tunnels). + */ #define SIMULTANEOUS_WALL_COLLISIONS - // Uses the surface closest to the source height when searching for a floor or ceiling, instead of just using the first applicable surface in the list. + /** + * Uses the surface closest to the source height when searching for a floor or ceiling, instead of just using the first applicable surface in the list. + */ #define SLOPE_FIX - // Fixes an issue where entering any area above a ceiling without an intermediate floor would count as hitting a ceiling. - // NOTE: This causes Mario to potentially clip through the vertical part of the rocking JRB ship at cettain angles. + /** + * Fixes an issue where entering any area above a ceiling without an intermediate floor would count as hitting a ceiling. + * NOTE: This causes Mario to potentially clip through the vertical part of the rocking JRB ship at cettain angles. + */ #define EXPOSED_CEILINGS_FIX - // Disables bonking on sloped ceilings by separating the handling of ceiling interactions and wall interactions. + /** + * Disables bonking on sloped ceilings by separating the handling of ceiling interactions and wall interactions. + */ #define DISABLE_CEILING_BONKS #endif From 3d677ecbeed231d812ac201d88d33886db09c783 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 18:30:25 -0800 Subject: [PATCH 11/25] Revert removal of 78 unit buffer for ceiling checks --- src/engine/surface_collision.c | 16 ++++++++++------ src/engine/surface_collision.h | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index c7581e2387..06966bb7b6 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -397,6 +397,7 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 // to the original point. if (height == y) break; + // If we're only looking for the closest ceiling, exit the loop. if (returnFirst) break; } @@ -416,7 +417,7 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) { f32 dynamicHeight = CELL_HEIGHT_LIMIT; s32 x = posX; - s32 y = posY; + s32 y = posY - FIND_FLOOR_BUFFER; s32 z = posZ; *pceil = NULL; @@ -460,6 +461,7 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) { // Return the ceiling. *pceil = ceil; + #ifdef VANILLA_DEBUG // Increment the debug tracker. gNumCalls.ceil++; @@ -543,7 +545,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 // Exclude floors lower than the previous highest floor. if (height <= highest) continue; - // Checks for floor interaction with a FIND_FLOOR_BUFFER unit buffer. + // Checks for floor interaction. if (height > y) continue; // Use the current floor. @@ -554,6 +556,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 // to the original point. if (height == y) break; + // If we're only looking for the closest floor, exit the loop. if (returnFirst) break; } @@ -710,14 +713,15 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { // To prevent accidentally leaving the floor tangible, stop checking for it. gCollisionFlags &= ~(COLLISION_FLAG_RETURN_FIRST | COLLISION_FLAG_EXCLUDE_DYNAMIC | COLLISION_FLAG_INCLUDE_INTANGIBLE); - // If a floor was missed, increment the debug counter. - if (floor == NULL) { - gNumFindFloorMisses++; - } // Return the floor. *pfloor = floor; + #ifdef VANILLA_DEBUG + // If a floor was missed, increment the debug counter. + if (floor == NULL) { + gNumFindFloorMisses++; + } // Increment the debug tracker. gNumCalls.floor++; #endif diff --git a/src/engine/surface_collision.h b/src/engine/surface_collision.h index 438f5791ee..a419554236 100644 --- a/src/engine/surface_collision.h +++ b/src/engine/surface_collision.h @@ -53,7 +53,7 @@ ALWAYS_INLINE f32 find_mario_ceil(Vec3f pos, f32 height, struct Surface **ceil) #ifdef EXPOSED_CEILINGS_FIX return find_ceil(pos[0], MAX(height, pos[1]) + 3.0f, pos[2], ceil); #else - return find_ceil(pos[0], (height + 3.0f), pos[2], ceil); + return find_ceil(pos[0], height, pos[2], ceil); #endif } From 068f9a5cc2218e9d87f9644efd981562b3dd7938 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 18:31:23 -0800 Subject: [PATCH 12/25] Rename 'EXPOSED_CEILINGS_FIX' to 'FIX_EXPOSED_CEILINGS' --- src/engine/surface_collision.h | 2 +- src/engine/surface_load.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/surface_collision.h b/src/engine/surface_collision.h index a419554236..a5c2a94fbf 100644 --- a/src/engine/surface_collision.h +++ b/src/engine/surface_collision.h @@ -50,7 +50,7 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil); // Finds the ceiling from a vec3f and a minimum height (with 3 unit vertical buffer). ALWAYS_INLINE f32 find_mario_ceil(Vec3f pos, f32 height, struct Surface **ceil) { -#ifdef EXPOSED_CEILINGS_FIX +#ifdef FIX_EXPOSED_CEILINGS return find_ceil(pos[0], MAX(height, pos[1]) + 3.0f, pos[2], ceil); #else return find_ceil(pos[0], height, pos[2], ceil); diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index cbdfb03690..0282d9dc1c 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -24,7 +24,7 @@ * Fixes an issue where entering any area above a ceiling without an intermediate floor would count as hitting a ceiling. * NOTE: This causes Mario to potentially clip through the vertical part of the rocking JRB ship at cettain angles. */ - #define EXPOSED_CEILINGS_FIX + #define FIX_EXPOSED_CEILINGS /** * Disables bonking on sloped ceilings by separating the handling of ceiling interactions and wall interactions. */ From d670157c07e7c3023c104217205131841531de26 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 18:47:08 -0800 Subject: [PATCH 13/25] Revert reverting ceiling buffer --- src/engine/surface_collision.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 06966bb7b6..65c03a2da1 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -417,7 +417,7 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) { f32 dynamicHeight = CELL_HEIGHT_LIMIT; s32 x = posX; - s32 y = posY - FIND_FLOOR_BUFFER; + s32 y = posY; s32 z = posZ; *pceil = NULL; From 6a3e2f6e279e6057183acc1ad14dbf2ca4f5d021 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 18:48:42 -0800 Subject: [PATCH 14/25] Move 'DISABLE_CEILING_BONKS' to config_movement.h --- include/config/config_movement.h | 7 ++++++- src/engine/surface_load.h | 5 +---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/config/config_movement.h b/include/config/config_movement.h index fb9609864a..f1cc8fbeea 100644 --- a/include/config/config_movement.h +++ b/include/config/config_movement.h @@ -114,10 +114,15 @@ #define DONT_LEDGE_GRAB_STEEP_SLOPES /** - * General collision improvements. See "src/engine/surface_load.h" to toggle specific changes. Disable this to use vanilla collision handling. + * General collision improvements. See "src/engine/surface_load.h" to toggle specific changes. Disable this to use close to vanilla collision handling. */ #define COLLISION_IMPROVEMENTS +/** + * Disables bonking on sloped ceilings by separating the handling of ceiling interactions and wall interactions. + */ +#define DISABLE_CEILING_BONKS + /** * Buffers an A input if you jump off a slope during the landing lag */ diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index 0282d9dc1c..43073d5b2e 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -7,6 +7,7 @@ #include "types.h" +// See include/config/config_movement.h #ifdef COLLISION_IMPROVEMENTS /** * Improves the handling of convex wall corners by rounding wall collision at triangle edges to close the seams. @@ -25,10 +26,6 @@ * NOTE: This causes Mario to potentially clip through the vertical part of the rocking JRB ship at cettain angles. */ #define FIX_EXPOSED_CEILINGS - /** - * Disables bonking on sloped ceilings by separating the handling of ceiling interactions and wall interactions. - */ - #define DISABLE_CEILING_BONKS #endif From ac663c4ee0bf4c1762091b5bf0ad4041ce9b0852 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 18:52:57 -0800 Subject: [PATCH 15/25] Implement SIMULTANEOUS_WALL_COLLISIONS (maybe) --- src/engine/surface_collision.c | 4 ++++ src/engine/surface_load.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 65c03a2da1..db2177f86b 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -71,6 +71,10 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); +#ifdef SIMULTANEOUS_WALL_COLLISIONS + returnFirst = TRUE; +#endif + // Check whether the object will be able to pass through certain walls. struct Object* obj = o; _Bool canPassVanishWalls = ( diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index 43073d5b2e..d806ccc238 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -14,7 +14,7 @@ */ #define ROUNDED_WALL_CORNERS /** - * TODO: Pproperly handles simultaneous collision with multiple walls (eg. concave wall corners or narrow tunnels). + * Properly handles simultaneous collision with multiple walls (eg. concave wall corners or narrow tunnels). */ #define SIMULTANEOUS_WALL_COLLISIONS /** From 032316a509cec7d23b624c65d481c78ddc2d0b53 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 18:58:30 -0800 Subject: [PATCH 16/25] Fix SIMULTANEOUS_WALL_COLLISIONS ifdef --- src/engine/surface_collision.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index db2177f86b..423e24060d 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -71,7 +71,7 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); -#ifdef SIMULTANEOUS_WALL_COLLISIONS +#ifndef SIMULTANEOUS_WALL_COLLISIONS returnFirst = TRUE; #endif From eb3a4bf7a166c7a8db692a313225f93405c1eb21 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Thu, 22 Feb 2024 19:13:35 -0800 Subject: [PATCH 17/25] Remove SIMULTANEOUS_WALL_COLLISIONS --- src/engine/surface_collision.c | 4 ---- src/engine/surface_load.h | 5 +---- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 423e24060d..65c03a2da1 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -71,10 +71,6 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); -#ifndef SIMULTANEOUS_WALL_COLLISIONS - returnFirst = TRUE; -#endif - // Check whether the object will be able to pass through certain walls. struct Object* obj = o; _Bool canPassVanishWalls = ( diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index d806ccc238..4405ec5c23 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -11,12 +11,9 @@ #ifdef COLLISION_IMPROVEMENTS /** * Improves the handling of convex wall corners by rounding wall collision at triangle edges to close the seams. + * Also properly handles simultaneous collisions with multiple walls (eg. concave wall corners or narrow tunnels). */ #define ROUNDED_WALL_CORNERS - /** - * Properly handles simultaneous collision with multiple walls (eg. concave wall corners or narrow tunnels). - */ - #define SIMULTANEOUS_WALL_COLLISIONS /** * Uses the surface closest to the source height when searching for a floor or ceiling, instead of just using the first applicable surface in the list. */ From 751854de7a26760cf23855d157a7f7293934a554 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Mon, 26 Feb 2024 16:00:11 -0800 Subject: [PATCH 18/25] bounds check comments --- src/engine/surface_collision.c | 46 ++++++++++++++++------------------ 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 65c03a2da1..269f17369d 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -172,39 +172,33 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc //! (Quantum Tunneling) Due to issues with the vertices walls choose and // the fact they are floating point, certain floating point positions // along the seam of two walls may collide with neither wall or both walls. - if (surf->flags & SURFACE_FLAG_X_PROJECTION) { - w1 = -surf->vertex1[2]; w2 = -surf->vertex2[2]; w3 = -surf->vertex3[2]; - y1 = surf->vertex1[1]; y2 = surf->vertex2[1]; y3 = surf->vertex3[1]; + if (surf->flags & SURFACE_FLAG_X_PROJECTION) { // ((surface->normal.x < -COS45) || (surface->normal.x > COS45)) + // Raycast along X axis. (y, -z) + w1 = -surf->vertex1[2]; w2 = -surf->vertex2[2]; w3 = -surf->vertex3[2]; // -v1z -v2z -v3z + y1 = surf->vertex1[1]; y2 = surf->vertex2[1]; y3 = surf->vertex3[1]; // v1y v2y v3y if (surf->normal.x > 0.0f) { - if ( - ((((y1 - y) * (w2 - w1)) - ((w1 - -z) * (y2 - y1))) > 0.0f) || - ((((y2 - y) * (w3 - w2)) - ((w2 - -z) * (y3 - y2))) > 0.0f) || - ((((y3 - y) * (w1 - w3)) - ((w3 - -z) * (y1 - y3))) > 0.0f) - ) continue; + if ((((y1 - y) * (w2 - w1)) - ((w1 - -z) * (y2 - y1))) > 0.0f) continue; + if ((((y2 - y) * (w3 - w2)) - ((w2 - -z) * (y3 - y2))) > 0.0f) continue; + if ((((y3 - y) * (w1 - w3)) - ((w3 - -z) * (y1 - y3))) > 0.0f) continue; } else { - if ( - ((((y1 - y) * (w2 - w1)) - ((w1 - -z) * (y2 - y1))) < 0.0f) || - ((((y2 - y) * (w3 - w2)) - ((w2 - -z) * (y3 - y2))) < 0.0f) || - ((((y3 - y) * (w1 - w3)) - ((w3 - -z) * (y1 - y3))) < 0.0f) - ) continue; + if ((((y1 - y) * (w2 - w1)) - ((w1 - -z) * (y2 - y1))) < 0.0f) continue; + if ((((y2 - y) * (w3 - w2)) - ((w2 - -z) * (y3 - y2))) < 0.0f) continue; + if ((((y3 - y) * (w1 - w3)) - ((w3 - -z) * (y1 - y3))) < 0.0f) continue; } } else { - w1 = surf->vertex1[0]; w2 = surf->vertex2[0]; w3 = surf->vertex3[0]; - y1 = surf->vertex1[1]; y2 = surf->vertex2[1]; y3 = surf->vertex3[1]; + // Raycast along Z axis. (y, x) + w1 = surf->vertex1[0]; w2 = surf->vertex2[0]; w3 = surf->vertex3[0]; // v1x v2x v3x + y1 = surf->vertex1[1]; y2 = surf->vertex2[1]; y3 = surf->vertex3[1]; // v1y v2y v3y if (surf->normal.z > 0.0f) { - if ( - ((((y1 - y) * (w2 - w1)) - ((w1 - x) * (y2 - y1))) > 0.0f) || - ((((y2 - y) * (w3 - w2)) - ((w2 - x) * (y3 - y2))) > 0.0f) || - ((((y3 - y) * (w1 - w3)) - ((w3 - x) * (y1 - y3))) > 0.0f) - ) continue; + if ((((y1 - y) * (w2 - w1)) - ((w1 - x) * (y2 - y1))) > 0.0f) continue; + if ((((y2 - y) * (w3 - w2)) - ((w2 - x) * (y3 - y2))) > 0.0f) continue; + if ((((y3 - y) * (w1 - w3)) - ((w3 - x) * (y1 - y3))) > 0.0f) continue; } else { - if ( - ((((y1 - y) * (w2 - w1)) - ((w1 - x) * (y2 - y1))) < 0.0f) || - ((((y2 - y) * (w3 - w2)) - ((w2 - x) * (y3 - y2))) < 0.0f) || - ((((y3 - y) * (w1 - w3)) - ((w3 - x) * (y1 - y3))) < 0.0f) - ) continue; + if ((((y1 - y) * (w2 - w1)) - ((w1 - x) * (y2 - y1))) < 0.0f) continue; + if ((((y2 - y) * (w3 - w2)) - ((w2 - x) * (y3 - y2))) < 0.0f) continue; + if ((((y3 - y) * (w1 - w3)) - ((w3 - x) * (y1 - y3))) < 0.0f) continue; } } @@ -324,6 +318,7 @@ void resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius, struc * CEILINGS * **************************************************/ +// Upward raycast along Y axis. static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *surf) { Vec3i vx, vz; vx[0] = surf->vertex1[0]; @@ -475,6 +470,7 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) { * FLOORS * **************************************************/ +// Downward raycast along Y axis. static s32 check_within_floor_triangle_bounds(s32 x, s32 z, struct Surface *surf) { Vec3i vx, vz; vx[0] = surf->vertex1[0]; From d1ad8b3500b6388335ef4f15d9623421e1c0ddb6 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Mon, 26 Feb 2024 16:30:17 -0800 Subject: [PATCH 19/25] Add FIX_FALSE_LEDGE_GRABS define (not implemented yet) --- src/engine/surface_load.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index 4405ec5c23..7f808c46e5 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -23,6 +23,11 @@ * NOTE: This causes Mario to potentially clip through the vertical part of the rocking JRB ship at cettain angles. */ #define FIX_EXPOSED_CEILINGS + /** + * Fixes false ledge grabs by making the "start ledge grab" check the same as the "stay in ledge grab" check. + * TODO: implement + */ + #define FIX_FALSE_LEDGE_GRABS #endif From 2565dc74fc12bce229c7f42940e375da82db2a3b Mon Sep 17 00:00:00 2001 From: Arceveti Date: Mon, 26 Feb 2024 18:22:02 -0800 Subject: [PATCH 20/25] Improve check ordering --- src/engine/surface_collision.c | 56 +++++++++++++++++----------------- src/engine/surface_load.h | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 269f17369d..2536fbfcca 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -59,14 +59,17 @@ s32 check_wall_triangle_edge(Vec3f vert, Vec3f v2, f32 *d00, f32 *d01, f32 *invD */ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struct WallCollisionData *data) { struct Surface *surf = NULL; - f32 radius = data->radius; - Vec3f pos = { data->x, data->y + data->offsetY, data->z }; - TerrainData type = SURFACE_DEFAULT; - s32 numCols = 0; + const f32 radius = data->radius; #ifdef ROUNDED_WALL_CORNERS const f32 corner_threshold = -0.9f; f32 margin_radius = radius - 1.0f; #endif + Vec3f pos = { + data->x, + data->y + data->offsetY, + data->z + }; + s32 numCols = 0; _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); @@ -85,7 +88,6 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc while (surfaceNode != NULL) { surf = surfaceNode->surface; surfaceNode = surfaceNode->next; - type = surf->type; // Exclude a large number of walls immediately to optimize. if (pos[1] < surf->lowerY || pos[1] > surf->upperY) continue; @@ -94,6 +96,8 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc if (checkingForCamera) { if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) continue; } else { + TerrainData type = surf->type; + // Ignore camera only surfaces. if (type == SURFACE_CAMERA_BOUNDARY) continue; @@ -166,16 +170,14 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc f32 x = pos[0]; f32 y = pos[1]; f32 z = pos[2]; - f32 w1, w2, w3; - f32 y1, y2, y3; //! (Quantum Tunneling) Due to issues with the vertices walls choose and // the fact they are floating point, certain floating point positions // along the seam of two walls may collide with neither wall or both walls. if (surf->flags & SURFACE_FLAG_X_PROJECTION) { // ((surface->normal.x < -COS45) || (surface->normal.x > COS45)) // Raycast along X axis. (y, -z) - w1 = -surf->vertex1[2]; w2 = -surf->vertex2[2]; w3 = -surf->vertex3[2]; // -v1z -v2z -v3z - y1 = surf->vertex1[1]; y2 = surf->vertex2[1]; y3 = surf->vertex3[1]; // v1y v2y v3y + f32 w1 = -surf->vertex1[2], w2 = -surf->vertex2[2], w3 = -surf->vertex3[2]; // -v1z -v2z -v3z + f32 y1 = surf->vertex1[1], y2 = surf->vertex2[1], y3 = surf->vertex3[1]; // v1y v2y v3y if (surf->normal.x > 0.0f) { if ((((y1 - y) * (w2 - w1)) - ((w1 - -z) * (y2 - y1))) > 0.0f) continue; @@ -188,8 +190,8 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc } } else { // Raycast along Z axis. (y, x) - w1 = surf->vertex1[0]; w2 = surf->vertex2[0]; w3 = surf->vertex3[0]; // v1x v2x v3x - y1 = surf->vertex1[1]; y2 = surf->vertex2[1]; y3 = surf->vertex3[1]; // v1y v2y v3y + f32 w1 = surf->vertex1[0], w2 = surf->vertex2[0], w3 = surf->vertex3[0]; // v1x v2x v3x + f32 y1 = surf->vertex1[1], y2 = surf->vertex2[1], y3 = surf->vertex3[1]; // v1y v2y v3y if (surf->normal.z > 0.0f) { if ((((y1 - y) * (w2 - w1)) - ((w1 - x) * (y2 - y1))) > 0.0f) continue; @@ -344,8 +346,7 @@ static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *surf) */ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) { struct Surface *surf, *ceil = NULL; - SurfaceType type = SURFACE_DEFAULT; - f32 height, highest = *pheight; + f32 highest = *pheight; _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); @@ -358,14 +359,13 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 while (surfaceNode != NULL) { surf = surfaceNode->surface; surfaceNode = surfaceNode->next; - type = surf->type; // Determine if checking for the camera or not. if (checkingForCamera) { if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) { continue; } - } else if (type == SURFACE_CAMERA_BOUNDARY) { + } else if (surf->type == SURFACE_CAMERA_BOUNDARY) { continue; // If we are not checking for the camera, ignore camera only ceilings. } @@ -376,7 +376,7 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 if (!check_within_ceil_triangle_bounds(x, z, surf)) continue; // Find the height of the ceiling above the current location. - height = get_surface_height_at_location(x, z, surf); + f32 height = get_surface_height_at_location(x, z, surf); // Exclude ceilings above the previous lowest ceiling. if (height > highest) continue; @@ -385,15 +385,15 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 if (height < y) continue; // Use the current ceiling. - highest = height; ceil = surf; + highest = height; + + // If we're only looking for the closest ceiling, exit the loop. + if (returnFirst) break; // Exit the loop if it's not possible for another ceiling to be closer // to the original point. if (height == y) break; - - // If we're only looking for the closest ceiling, exit the loop. - if (returnFirst) break; } *pheight = highest; @@ -496,8 +496,7 @@ static s32 check_within_floor_triangle_bounds(s32 x, s32 z, struct Surface *surf */ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) { struct Surface *surf, *floor = NULL; - SurfaceType type = SURFACE_DEFAULT; - f32 height, highest = *pheight; + f32 highest = *pheight; _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); @@ -511,7 +510,8 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 while (surfaceNode != NULL) { surf = surfaceNode->surface; surfaceNode = surfaceNode->next; - type = surf->type; + + TerrainData type = surf->type; // To prevent the Merry-Go-Round room from loading when Mario passes above the hole that leads // there, SURFACE_INTANGIBLE is used. This prevent the wrong room from loading, but can also allow @@ -536,7 +536,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 if (!check_within_floor_triangle_bounds(x, z, surf)) continue; // Get the height of the floor under the current location. - height = get_surface_height_at_location(x, z, surf); + f32 height = get_surface_height_at_location(x, z, surf); // Exclude floors lower than the previous highest floor. if (height <= highest) continue; @@ -545,15 +545,15 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 if (height > y) continue; // Use the current floor. - highest = height; floor = surf; + highest = height; + + // If we're only looking for the closest floor, exit the loop. + if (returnFirst) break; // Exit the loop if it's not possible for another floor to be closer // to the original point. if (height == y) break; - - // If we're only looking for the closest floor, exit the loop. - if (returnFirst) break; } *pheight = highest; diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index 7f808c46e5..68ea55c557 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -20,7 +20,7 @@ #define SLOPE_FIX /** * Fixes an issue where entering any area above a ceiling without an intermediate floor would count as hitting a ceiling. - * NOTE: This causes Mario to potentially clip through the vertical part of the rocking JRB ship at cettain angles. + * NOTE: This may allow Mario to clip through the wall on the deck of the the rocking JRB ship. */ #define FIX_EXPOSED_CEILINGS /** From 2239f1c877c525932ff285ce63285fa7c675f717 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Sat, 2 Mar 2024 14:14:25 -0800 Subject: [PATCH 21/25] Rename 'SLOPE_FIX' to 'FIX_SURFACE_CUCKING' --- src/engine/surface_collision.c | 4 ++-- src/engine/surface_load.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 2536fbfcca..a6ce63523d 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -351,7 +351,7 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); -#ifndef SLOPE_FIX +#ifndef FIX_SURFACE_CUCKING returnFirst = TRUE; #endif @@ -502,7 +502,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); _Bool skipIntangible = !(gCollisionFlags & COLLISION_FLAG_INCLUDE_INTANGIBLE); -#ifndef SLOPE_FIX +#ifndef FIX_SURFACE_CUCKING returnFirst = TRUE; #endif diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index 68ea55c557..15dfc50cd8 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -17,9 +17,9 @@ /** * Uses the surface closest to the source height when searching for a floor or ceiling, instead of just using the first applicable surface in the list. */ - #define SLOPE_FIX + #define FIX_SURFACE_CUCKING /** - * Fixes an issue where entering any area above a ceiling without an intermediate floor would count as hitting a ceiling. + * Fixes an issue where entering an area above a ceiling without an intermediate floor would count as hitting a ceiling. * NOTE: This may allow Mario to clip through the wall on the deck of the the rocking JRB ship. */ #define FIX_EXPOSED_CEILINGS From 0dbd237051334ff28026a085c31369b8929aede3 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Sat, 2 Mar 2024 18:01:31 -0800 Subject: [PATCH 22/25] Remove FIX_SURFACE_CUCKING define + variable renames --- src/engine/surface_collision.c | 158 +++++++++++++------------------ src/engine/surface_collision.h | 6 +- src/engine/surface_load.c | 2 +- src/engine/surface_load.h | 9 -- src/game/mario_step.c | 4 +- src/game/object_list_processor.h | 7 +- src/game/shadow.c | 1 - 7 files changed, 76 insertions(+), 111 deletions(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index a6ce63523d..4ebe4504e6 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -16,7 +16,6 @@ **************************************************/ #ifdef ROUNDED_WALL_CORNERS - static s32 check_wall_triangle_vw(f32 d00, f32 d01, f32 d11, f32 d20, f32 d21, f32 invDenom) { f32 v = ((d11 * d20) - (d01 * d21)) * invDenom; if (v < 0.0f || v > 1.0f) { @@ -50,8 +49,7 @@ s32 check_wall_triangle_edge(Vec3f vert, Vec3f v2, f32 *d00, f32 *d01, f32 *invD return TRUE; } - -#endif +#endif // ROUNDED_WALL_CORNERS /** * Iterate through the list of walls until all walls are checked and @@ -63,7 +61,7 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc #ifdef ROUNDED_WALL_CORNERS const f32 corner_threshold = -0.9f; f32 margin_radius = radius - 1.0f; -#endif +#endif // ROUNDED_WALL_CORNERS Vec3f pos = { data->x, data->y + data->offsetY, @@ -72,7 +70,6 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc s32 numCols = 0; _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); - _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); // Check whether the object will be able to pass through certain walls. struct Object* obj = o; @@ -166,7 +163,7 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc pos[0] += surf->normal.x * (radius - offset); pos[2] += surf->normal.z * (radius - offset); } -#else +#else // !ROUNDED_WALL_CORNERS f32 x = pos[0]; f32 y = pos[1]; f32 z = pos[2]; @@ -207,17 +204,13 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc // Update pos pos[0] += surf->normal.x * (radius - offset); pos[2] += surf->normal.z * (radius - offset); -#endif +#endif // !ROUNDED_WALL_CORNERS // Has collision if (data->numWalls < MAX_REFERENCED_WALLS) { data->walls[data->numWalls++] = surf; } numCols++; - - if (returnFirst) { - break; - } } data->x = pos[0]; @@ -289,7 +282,7 @@ s32 find_wall_collisions(struct WallCollisionData *colData) { } } - gCollisionFlags &= ~(COLLISION_FLAG_RETURN_FIRST | COLLISION_FLAG_EXCLUDE_DYNAMIC | COLLISION_FLAG_INCLUDE_INTANGIBLE); + gCollisionFlags &= ~(COLLISION_FLAG_EXCLUDE_DYNAMIC | COLLISION_FLAG_INCLUDE_INTANGIBLE); #ifdef VANILLA_DEBUG // Increment the debug tracker. gNumCalls.wall++; @@ -321,19 +314,19 @@ void resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius, struc **************************************************/ // Upward raycast along Y axis. -static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *surf) { +static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *ceil) { Vec3i vx, vz; - vx[0] = surf->vertex1[0]; - vz[0] = surf->vertex1[2]; - vx[1] = surf->vertex2[0]; - vz[1] = surf->vertex2[2]; + vx[0] = ceil->vertex1[0]; + vz[0] = ceil->vertex1[2]; + vx[1] = ceil->vertex2[0]; + vz[1] = ceil->vertex2[2]; // Checking if point is in bounds of the triangle laterally. if (((vz[0] - z) * (vx[1] - vx[0]) - (vx[0] - x) * (vz[1] - vz[0])) > 0) return FALSE; // Slight optimization by checking these later. - vx[2] = surf->vertex3[0]; - vz[2] = surf->vertex3[2]; + vx[2] = ceil->vertex3[0]; + vz[2] = ceil->vertex3[2]; if (((vz[1] - z) * (vx[2] - vx[1]) - (vx[1] - x) * (vz[2] - vz[1])) > 0) return FALSE; if (((vz[2] - z) * (vx[0] - vx[2]) - (vx[2] - x) * (vz[0] - vz[2])) > 0) return FALSE; @@ -345,60 +338,52 @@ static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *surf) * Iterate through the list of ceilings and find the first ceiling over a given point. */ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) { - struct Surface *surf, *ceil = NULL; - f32 highest = *pheight; + struct Surface *ceil = NULL; + struct Surface *lowestCeil = NULL; + f32 lowestCeilHeight = *pheight; - _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); -#ifndef FIX_SURFACE_CUCKING - returnFirst = TRUE; -#endif - // Iterate through the list of ceilings until there are no more ceilings. while (surfaceNode != NULL) { - surf = surfaceNode->surface; + ceil = surfaceNode->surface; surfaceNode = surfaceNode->next; // Determine if checking for the camera or not. if (checkingForCamera) { - if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) { + if (ceil->flags & SURFACE_FLAG_NO_CAM_COLLISION) { continue; } - } else if (surf->type == SURFACE_CAMERA_BOUNDARY) { + } else if (ceil->type == SURFACE_CAMERA_BOUNDARY) { continue; // If we are not checking for the camera, ignore camera only ceilings. } - // Exclude all ceilings below the point. - if (y > surf->upperY) continue; + // Exclude all ceilings below the check height. + if (y > ceil->upperY) continue; // Check that the point is within the triangle bounds. - if (!check_within_ceil_triangle_bounds(x, z, surf)) continue; + if (!check_within_ceil_triangle_bounds(x, z, ceil)) continue; // Find the height of the ceiling above the current location. - f32 height = get_surface_height_at_location(x, z, surf); - - // Exclude ceilings above the previous lowest ceiling. - if (height > highest) continue; - - // Checks for ceiling interaction. - if (height < y) continue; + f32 ceilHeight = get_surface_height_at_location(x, z, ceil); - // Use the current ceiling. - ceil = surf; - highest = height; + // Exclude ceiling heights that are: + if ( + (ceilHeight < y) || // Lower than the check height. + (ceilHeight >= lowestCeilHeight) // Higher than the previous lowest ceiling. + ) continue; - // If we're only looking for the closest ceiling, exit the loop. - if (returnFirst) break; + // Update the lowest found ceiling. + lowestCeil = ceil; + lowestCeilHeight = ceilHeight; - // Exit the loop if it's not possible for another ceiling to be closer - // to the original point. - if (height == y) break; + // Exit the loop if it's not possible for another ceiling to be closer to the check height. + if (ceilHeight == y) break; } - *pheight = highest; + *pheight = lowestCeilHeight; - return ceil; + return lowestCeil; } /** @@ -452,7 +437,7 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) { } // To prevent accidentally leaving the floor tangible, stop checking for it. - gCollisionFlags &= ~(COLLISION_FLAG_RETURN_FIRST | COLLISION_FLAG_EXCLUDE_DYNAMIC | COLLISION_FLAG_INCLUDE_INTANGIBLE); + gCollisionFlags &= ~(COLLISION_FLAG_EXCLUDE_DYNAMIC | COLLISION_FLAG_INCLUDE_INTANGIBLE); // Return the ceiling. *pceil = ceil; @@ -471,19 +456,19 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) { **************************************************/ // Downward raycast along Y axis. -static s32 check_within_floor_triangle_bounds(s32 x, s32 z, struct Surface *surf) { +static s32 check_within_floor_triangle_bounds(s32 x, s32 z, struct Surface *floor) { Vec3i vx, vz; - vx[0] = surf->vertex1[0]; - vz[0] = surf->vertex1[2]; - vx[1] = surf->vertex2[0]; - vz[1] = surf->vertex2[2]; + vx[0] = floor->vertex1[0]; + vz[0] = floor->vertex1[2]; + vx[1] = floor->vertex2[0]; + vz[1] = floor->vertex2[2]; // Checking if point is in bounds of the triangle laterally. if (((vz[0] - z) * (vx[1] - vx[0]) - (vx[0] - x) * (vz[1] - vz[0])) < 0) return FALSE; // Slight optimization by checking these later. - vx[2] = surf->vertex3[0]; - vz[2] = surf->vertex3[2]; + vx[2] = floor->vertex3[0]; + vz[2] = floor->vertex3[2]; if (((vz[1] - z) * (vx[2] - vx[1]) - (vx[1] - x) * (vz[2] - vz[1])) < 0) return FALSE; if (((vz[2] - z) * (vx[0] - vx[2]) - (vx[2] - x) * (vz[0] - vz[2])) < 0) return FALSE; @@ -495,70 +480,61 @@ static s32 check_within_floor_triangle_bounds(s32 x, s32 z, struct Surface *surf * Iterate through the list of floors and find the first floor under a given point. */ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) { - struct Surface *surf, *floor = NULL; - f32 highest = *pheight; + struct Surface *floor = NULL; + struct Surface *highestFloor = NULL; + f32 highestFloorHeight = *pheight; - _Bool returnFirst = (gCollisionFlags & COLLISION_FLAG_RETURN_FIRST); _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); _Bool skipIntangible = !(gCollisionFlags & COLLISION_FLAG_INCLUDE_INTANGIBLE); -#ifndef FIX_SURFACE_CUCKING - returnFirst = TRUE; -#endif - // Iterate through the list of floors until there are no more floors. while (surfaceNode != NULL) { - surf = surfaceNode->surface; + floor = surfaceNode->surface; surfaceNode = surfaceNode->next; - TerrainData type = surf->type; + TerrainData type = floor->type; - // To prevent the Merry-Go-Round room from loading when Mario passes above the hole that leads - // there, SURFACE_INTANGIBLE is used. This prevent the wrong room from loading, but can also allow - // Mario to pass through. + // To prevent the Merry-Go-Round room from loading when Mario is above the hole that leads there, SURFACE_INTANGIBLE is used. + // This prevents the wrong room from loading, but can also allow Mario to pass through. if (skipIntangible && (type == SURFACE_INTANGIBLE)) { continue; } // Determine if we are checking for the camera or not. if (checkingForCamera) { - if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) { + if (floor->flags & SURFACE_FLAG_NO_CAM_COLLISION) { continue; } } else if (type == SURFACE_CAMERA_BOUNDARY) { continue; // If we are not checking for the camera, ignore camera only floors. } - // Exclude all floors above the point. - if (y < surf->lowerY) continue; + // Exclude all floors above the check height. + if (y < floor->lowerY) continue; // Check that the point is within the triangle bounds. - if (!check_within_floor_triangle_bounds(x, z, surf)) continue; + if (!check_within_floor_triangle_bounds(x, z, floor)) continue; // Get the height of the floor under the current location. - f32 height = get_surface_height_at_location(x, z, surf); - - // Exclude floors lower than the previous highest floor. - if (height <= highest) continue; + f32 floorHeight = get_surface_height_at_location(x, z, floor); - // Checks for floor interaction. - if (height > y) continue; + // Exclude floor heights that are: + if ( + (floorHeight > y) || // Higher than the check height. + (floorHeight <= highestFloorHeight) // Lower than the previous highest floor. + ) continue; - // Use the current floor. - floor = surf; - highest = height; + // Update the highest found floor. + highestFloor = floor; + highestFloorHeight = floorHeight; - // If we're only looking for the closest floor, exit the loop. - if (returnFirst) break; - - // Exit the loop if it's not possible for another floor to be closer - // to the original point. - if (height == y) break; + // Exit the loop if it's not possible for another floor to be closer to the check height (eg. standing on a floor). + if (floorHeight == y) break; } - *pheight = highest; + *pheight = highestFloorHeight; - return floor; + return highestFloor; } // Generic triangle bounds func @@ -708,7 +684,7 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { } // To prevent accidentally leaving the floor tangible, stop checking for it. - gCollisionFlags &= ~(COLLISION_FLAG_RETURN_FIRST | COLLISION_FLAG_EXCLUDE_DYNAMIC | COLLISION_FLAG_INCLUDE_INTANGIBLE); + gCollisionFlags &= ~(COLLISION_FLAG_EXCLUDE_DYNAMIC | COLLISION_FLAG_INCLUDE_INTANGIBLE); // Return the floor. *pfloor = floor; diff --git a/src/engine/surface_collision.h b/src/engine/surface_collision.h index a5c2a94fbf..4bc111ccc6 100644 --- a/src/engine/surface_collision.h +++ b/src/engine/surface_collision.h @@ -51,10 +51,10 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil); // Finds the ceiling from a vec3f and a minimum height (with 3 unit vertical buffer). ALWAYS_INLINE f32 find_mario_ceil(Vec3f pos, f32 height, struct Surface **ceil) { #ifdef FIX_EXPOSED_CEILINGS - return find_ceil(pos[0], MAX(height, pos[1]) + 3.0f, pos[2], ceil); -#else + return find_ceil(pos[0], (MAX(height, pos[1]) + 3.0f), pos[2], ceil); +#else // !FIX_EXPOSED_CEILINGS return find_ceil(pos[0], height, pos[2], ceil); -#endif +#endif // !FIX_EXPOSED_CEILINGS } f32 find_floor_height(f32 x, f32 y, f32 z); diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c index e52e19c174..2d8a17793d 100644 --- a/src/engine/surface_load.c +++ b/src/engine/surface_load.c @@ -139,7 +139,7 @@ static void add_surface_to_cell(s32 dynamic, s32 cellX, s32 cellZ, struct Surfac if (surface->normal.x < -COS45 || surface->normal.x > COS45) { surface->flags |= SURFACE_FLAG_X_PROJECTION; } -#endif +#endif // !ROUNDED_WALL_CORNERS } s32 surfacePriority = surface->upperY * sortDir; diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index 15dfc50cd8..4d11f03cb6 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -14,20 +14,11 @@ * Also properly handles simultaneous collisions with multiple walls (eg. concave wall corners or narrow tunnels). */ #define ROUNDED_WALL_CORNERS - /** - * Uses the surface closest to the source height when searching for a floor or ceiling, instead of just using the first applicable surface in the list. - */ - #define FIX_SURFACE_CUCKING /** * Fixes an issue where entering an area above a ceiling without an intermediate floor would count as hitting a ceiling. * NOTE: This may allow Mario to clip through the wall on the deck of the the rocking JRB ship. */ #define FIX_EXPOSED_CEILINGS - /** - * Fixes false ledge grabs by making the "start ledge grab" check the same as the "stay in ledge grab" check. - * TODO: implement - */ - #define FIX_FALSE_LEDGE_GRABS #endif diff --git a/src/game/mario_step.c b/src/game/mario_step.c index d3c9f38def..ffc0728c43 100644 --- a/src/game/mario_step.c +++ b/src/game/mario_step.c @@ -536,9 +536,9 @@ s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepAr m->pos[1] = nextPos[1]; #ifdef DISABLE_CEILING_BONKS return AIR_STEP_HIT_CEILING; -#else +#else // !DISABLE_CEILING_BONKS return AIR_STEP_HIT_WALL; -#endif +#endif // !DISABLE_CEILING_BONKS } //! When the wall is not completely vertical or there is a slight wall diff --git a/src/game/object_list_processor.h b/src/game/object_list_processor.h index 83aec87023..215af73b98 100644 --- a/src/game/object_list_processor.h +++ b/src/game/object_list_processor.h @@ -102,10 +102,9 @@ extern struct MemoryPool *gObjectMemoryPool; enum CollisionFlags { COLLISION_FLAGS_NONE = (0 << 0), - COLLISION_FLAG_RETURN_FIRST = (1 << 1), - COLLISION_FLAG_CAMERA = (1 << 2), - COLLISION_FLAG_INCLUDE_INTANGIBLE = (1 << 3), - COLLISION_FLAG_EXCLUDE_DYNAMIC = (1 << 4), + COLLISION_FLAG_CAMERA = (1 << 1), + COLLISION_FLAG_INCLUDE_INTANGIBLE = (1 << 2), + COLLISION_FLAG_EXCLUDE_DYNAMIC = (1 << 3), }; extern s16 gCollisionFlags; diff --git a/src/game/shadow.c b/src/game/shadow.c index 001b01914e..dc90416e27 100644 --- a/src/game/shadow.c +++ b/src/game/shadow.c @@ -214,7 +214,6 @@ Gfx *create_shadow_below_xyz(Vec3f pos, s16 shadowScale, u8 shadowSolidity, s8 s floorHeight = obj->oFloorHeight; } else { // The object has no referenced floor, so find a new one. - // gCollisionFlags |= COLLISION_FLAG_RETURN_FIRST; floorHeight = find_floor(x, y, z, &floor); // No shadow if the position is OOB. From 97174684235abf2f2dbad4dc83edca6a66ba4c80 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Sat, 2 Mar 2024 18:06:05 -0800 Subject: [PATCH 23/25] Move defines into config_movement.h --- include/config/config_movement.h | 18 ++++++++++++------ src/engine/surface_collision.c | 22 +++++++++------------- src/engine/surface_load.h | 15 --------------- 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/include/config/config_movement.h b/include/config/config_movement.h index f1cc8fbeea..edc0ae5e48 100644 --- a/include/config/config_movement.h +++ b/include/config/config_movement.h @@ -113,11 +113,6 @@ */ #define DONT_LEDGE_GRAB_STEEP_SLOPES -/** - * General collision improvements. See "src/engine/surface_load.h" to toggle specific changes. Disable this to use close to vanilla collision handling. - */ -#define COLLISION_IMPROVEMENTS - /** * Disables bonking on sloped ceilings by separating the handling of ceiling interactions and wall interactions. */ @@ -138,7 +133,7 @@ */ // #define WATER_PLUNGE_UPWARP -/** +/** * This bug allows mario to move when initiating a dialog, * just as long as mario doesn't enter an action that can * be interrupted with text @@ -157,3 +152,14 @@ */ #define MARIO_INERTIA_UPWARD // #define MARIO_INERTIA_LATERAL + +/** + * Improves the handling of convex wall corners by rounding wall collision at triangle edges to close the seams. + * Also properly handles simultaneous collisions with multiple walls (eg. concave wall corners or narrow tunnels). + */ +#define ROUNDED_WALL_CORNERS +/** + * Fixes an issue where entering an area above a ceiling without an intermediate floor would count as hitting a ceiling. + * NOTE: This may allow Mario to clip through the wall on the deck of the the rocking JRB ship. + */ +#define FIX_EXPOSED_CEILINGS diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 4ebe4504e6..8b09cfb9a7 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -351,11 +351,10 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 // Determine if checking for the camera or not. if (checkingForCamera) { - if (ceil->flags & SURFACE_FLAG_NO_CAM_COLLISION) { - continue; - } - } else if (ceil->type == SURFACE_CAMERA_BOUNDARY) { - continue; // If we are not checking for the camera, ignore camera only ceilings. + if (ceil->flags & SURFACE_FLAG_NO_CAM_COLLISION) continue; + } else { + // If we are not checking for the camera, ignore camera only ceilings. + if (ceil->type == SURFACE_CAMERA_BOUNDARY) continue; } // Exclude all ceilings below the check height. @@ -496,17 +495,14 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 // To prevent the Merry-Go-Round room from loading when Mario is above the hole that leads there, SURFACE_INTANGIBLE is used. // This prevents the wrong room from loading, but can also allow Mario to pass through. - if (skipIntangible && (type == SURFACE_INTANGIBLE)) { - continue; - } + if (skipIntangible && (type == SURFACE_INTANGIBLE)) continue; // Determine if we are checking for the camera or not. if (checkingForCamera) { - if (floor->flags & SURFACE_FLAG_NO_CAM_COLLISION) { - continue; - } - } else if (type == SURFACE_CAMERA_BOUNDARY) { - continue; // If we are not checking for the camera, ignore camera only floors. + if (floor->flags & SURFACE_FLAG_NO_CAM_COLLISION) continue; + } else { + // If we are not checking for the camera, ignore camera only floors. + if (type == SURFACE_CAMERA_BOUNDARY) continue; } // Exclude all floors above the check height. diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index 4d11f03cb6..f0555c6a5e 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -7,21 +7,6 @@ #include "types.h" -// See include/config/config_movement.h -#ifdef COLLISION_IMPROVEMENTS - /** - * Improves the handling of convex wall corners by rounding wall collision at triangle edges to close the seams. - * Also properly handles simultaneous collisions with multiple walls (eg. concave wall corners or narrow tunnels). - */ - #define ROUNDED_WALL_CORNERS - /** - * Fixes an issue where entering an area above a ceiling without an intermediate floor would count as hitting a ceiling. - * NOTE: This may allow Mario to clip through the wall on the deck of the the rocking JRB ship. - */ - #define FIX_EXPOSED_CEILINGS -#endif - - #define SURFACE_VERTICAL_BUFFER 5 #define NORMAL_FLOOR_THRESHOLD 0.01f From da74568be471bfba2a4d7bfaf5f40c0ced4f6eac Mon Sep 17 00:00:00 2001 From: Arceveti Date: Sun, 28 Apr 2024 23:52:00 -0700 Subject: [PATCH 24/25] Cleaner 'FIX_EXPOSED_CEILINGS' ifdef --- src/engine/surface_collision.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/engine/surface_collision.h b/src/engine/surface_collision.h index 4bc111ccc6..243a853425 100644 --- a/src/engine/surface_collision.h +++ b/src/engine/surface_collision.h @@ -51,10 +51,9 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil); // Finds the ceiling from a vec3f and a minimum height (with 3 unit vertical buffer). ALWAYS_INLINE f32 find_mario_ceil(Vec3f pos, f32 height, struct Surface **ceil) { #ifdef FIX_EXPOSED_CEILINGS - return find_ceil(pos[0], (MAX(height, pos[1]) + 3.0f), pos[2], ceil); -#else // !FIX_EXPOSED_CEILINGS - return find_ceil(pos[0], height, pos[2], ceil); -#endif // !FIX_EXPOSED_CEILINGS + height = MAX(height, pos[1]); +#endif // FIX_EXPOSED_CEILINGS + return find_ceil(pos[0], (height + 3.0f), pos[2], ceil); } f32 find_floor_height(f32 x, f32 y, f32 z); From 57a648eea2a6cb016fe0378acfe5547cc5fd4ad7 Mon Sep 17 00:00:00 2001 From: Arceveti Date: Wed, 1 May 2024 00:27:04 -0700 Subject: [PATCH 25/25] Formatting changes :) --- include/config/config_collision.h | 12 ++++ include/config/config_movement.h | 11 ---- src/engine/surface_collision.c | 102 ++++++++++++++++++++---------- src/game/object_list_processor.h | 2 +- 4 files changed, 83 insertions(+), 44 deletions(-) diff --git a/include/config/config_collision.h b/include/config/config_collision.h index 41288a3616..58520dc2b8 100644 --- a/include/config/config_collision.h +++ b/include/config/config_collision.h @@ -4,6 +4,18 @@ * COLLISION SETTINGS * **********************/ +/** + * Improves the handling of convex wall corners by rounding wall collision at triangle edges to close the seams. + * Also properly handles simultaneous collisions with multiple walls (eg. concave wall corners or narrow tunnels). + */ +#define ROUNDED_WALL_CORNERS + +/** + * Fixes an issue where entering an area above a ceiling without an intermediate floor would count as hitting a ceiling. + * NOTE: This may allow Mario to clip through the wall on the deck of the the rocking JRB ship. + */ +#define FIX_EXPOSED_CEILINGS + /** * Reduces some find_floor calls, at the cost of some barely noticeable smoothness in Mario's visual movement in a few actions at higher speeds. * The defined number is the forward speed threshold before the change is active, since it's only noticeable at lower speeds. diff --git a/include/config/config_movement.h b/include/config/config_movement.h index 9ba0fa704e..73e48b47a0 100644 --- a/include/config/config_movement.h +++ b/include/config/config_movement.h @@ -146,14 +146,3 @@ */ #define MARIO_INERTIA_UPWARD // #define MARIO_INERTIA_LATERAL - -/** - * Improves the handling of convex wall corners by rounding wall collision at triangle edges to close the seams. - * Also properly handles simultaneous collisions with multiple walls (eg. concave wall corners or narrow tunnels). - */ -#define ROUNDED_WALL_CORNERS -/** - * Fixes an issue where entering an area above a ceiling without an intermediate floor would count as hitting a ceiling. - * NOTE: This may allow Mario to clip through the wall on the deck of the the rocking JRB ship. - */ -#define FIX_EXPOSED_CEILINGS diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 15ddec03d0..53397feae0 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -69,14 +69,14 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc }; s32 numCols = 0; - _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); + s32 checkingForCamera = ((gCollisionFlags & COLLISION_FLAG_CAMERA) != 0); // Check whether the object will be able to pass through certain walls. struct Object* obj = o; - _Bool canPassVanishWalls = ( + s32 canPassVanishWalls = ( (obj != NULL) && ( (obj->activeFlags & ACTIVE_FLAG_MOVE_THROUGH_GRATE) || - (obj == gMarioObject && (gMarioState->flags & MARIO_VANISH_CAP)) + ((obj == gMarioObject) && (gMarioState->flags & MARIO_VANISH_CAP)) ) ); @@ -87,19 +87,27 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc surfaceNode = surfaceNode->next; // Exclude a large number of walls immediately to optimize. - if (pos[1] < surf->lowerY || pos[1] > surf->upperY) continue; + if ((pos[1] < surf->lowerY) || (pos[1] > surf->upperY)) { + continue; + } // Determine if checking for the camera or not. if (checkingForCamera) { - if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) continue; + if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) { + continue; + } } else { TerrainData type = surf->type; // Ignore camera only surfaces. - if (type == SURFACE_CAMERA_BOUNDARY) continue; + if (type == SURFACE_CAMERA_BOUNDARY) { + continue; + } // If an object can pass through a vanish cap wall, pass through. - if (canPassVanishWalls && (type == SURFACE_VANISH_CAP_WALLS)) continue; + if (canPassVanishWalls && (type == SURFACE_VANISH_CAP_WALLS)) { + continue; + } } // Dot of normal and pos, + origin offset @@ -109,7 +117,9 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc surf->originOffset; // Exclude surfaces outside of the radius. - if (offset < -radius || offset > radius) continue; + if ((offset < -radius) || (offset > radius)) { + continue; + } #ifdef ROUNDED_WALL_CORNERS Vec3f v0, v1, v2; @@ -126,11 +136,13 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc f32 invDenom = (d00 * d11) - (d01 * d01); if (FLT_IS_NONZERO(invDenom)) { - invDenom = 1.0f / invDenom; + invDenom = (1.0f / invDenom); } if (check_wall_triangle_vw(d00, d01, d11, d20, d21, invDenom)) { - if (offset < 0) continue; + if (offset < 0) { + continue; + } // Edge 1-2 if (check_wall_triangle_edge(v0, v2, &d00, &d01, &invDenom, &offset, margin_radius)) { @@ -322,14 +334,14 @@ static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *ceil) vz[1] = ceil->vertex2[2]; // Checking if point is in bounds of the triangle laterally. - if (((vz[0] - z) * (vx[1] - vx[0]) - (vx[0] - x) * (vz[1] - vz[0])) > 0) return FALSE; + if ((((vz[0] - z) * (vx[1] - vx[0])) - ((vx[0] - x) * (vz[1] - vz[0]))) > 0) return FALSE; // Slight optimization by checking these later. vx[2] = ceil->vertex3[0]; vz[2] = ceil->vertex3[2]; - if (((vz[1] - z) * (vx[2] - vx[1]) - (vx[1] - x) * (vz[2] - vz[1])) > 0) return FALSE; - if (((vz[2] - z) * (vx[0] - vx[2]) - (vx[2] - x) * (vz[0] - vz[2])) > 0) return FALSE; + if ((((vz[1] - z) * (vx[2] - vx[1])) - ((vx[1] - x) * (vz[2] - vz[1]))) > 0) return FALSE; + if ((((vz[2] - z) * (vx[0] - vx[2])) - ((vx[2] - x) * (vz[0] - vz[2]))) > 0) return FALSE; return TRUE; } @@ -342,7 +354,7 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 struct Surface *lowestCeil = NULL; f32 lowestCeilHeight = *pheight; - _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); + s32 checkingForCamera = ((gCollisionFlags & COLLISION_FLAG_CAMERA) != 0); // Iterate through the list of ceilings until there are no more ceilings. while (surfaceNode != NULL) { @@ -351,17 +363,25 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 // Determine if checking for the camera or not. if (checkingForCamera) { - if (ceil->flags & SURFACE_FLAG_NO_CAM_COLLISION) continue; + if (ceil->flags & SURFACE_FLAG_NO_CAM_COLLISION) { + continue; + } } else { // If we are not checking for the camera, ignore camera only ceilings. - if (ceil->type == SURFACE_CAMERA_BOUNDARY) continue; + if (ceil->type == SURFACE_CAMERA_BOUNDARY) { + continue; + } } // Exclude all ceilings below the check height. - if (y > ceil->upperY) continue; + if (y > ceil->upperY) { + continue; + } // Check that the point is within the triangle bounds. - if (!check_within_ceil_triangle_bounds(x, z, ceil)) continue; + if (!check_within_ceil_triangle_bounds(x, z, ceil)) { + continue; + } // Find the height of the ceiling above the current location. f32 ceilHeight = get_surface_height_at_location(x, z, ceil); @@ -370,14 +390,18 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 if ( (ceilHeight < y) || // Lower than the check height. (ceilHeight >= lowestCeilHeight) // Higher than the previous lowest ceiling. - ) continue; + ) { + continue; + } // Update the lowest found ceiling. lowestCeil = ceil; lowestCeilHeight = ceilHeight; // Exit the loop if it's not possible for another ceiling to be closer to the check height. - if (ceilHeight == y) break; + if (ceilHeight == y) { + break; + } } *pheight = lowestCeilHeight; @@ -463,14 +487,14 @@ static s32 check_within_floor_triangle_bounds(s32 x, s32 z, struct Surface *floo vz[1] = floor->vertex2[2]; // Checking if point is in bounds of the triangle laterally. - if (((vz[0] - z) * (vx[1] - vx[0]) - (vx[0] - x) * (vz[1] - vz[0])) < 0) return FALSE; + if ((((vz[0] - z) * (vx[1] - vx[0])) - ((vx[0] - x) * (vz[1] - vz[0]))) < 0) return FALSE; // Slight optimization by checking these later. vx[2] = floor->vertex3[0]; vz[2] = floor->vertex3[2]; - if (((vz[1] - z) * (vx[2] - vx[1]) - (vx[1] - x) * (vz[2] - vz[1])) < 0) return FALSE; - if (((vz[2] - z) * (vx[0] - vx[2]) - (vx[2] - x) * (vz[0] - vz[2])) < 0) return FALSE; + if ((((vz[1] - z) * (vx[2] - vx[1])) - ((vx[1] - x) * (vz[2] - vz[1]))) < 0) return FALSE; + if ((((vz[2] - z) * (vx[0] - vx[2])) - ((vx[2] - x) * (vz[0] - vz[2]))) < 0) return FALSE; return TRUE; } @@ -483,8 +507,8 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 struct Surface *highestFloor = NULL; f32 highestFloorHeight = *pheight; - _Bool checkingForCamera = (gCollisionFlags & COLLISION_FLAG_CAMERA); - _Bool skipIntangible = !(gCollisionFlags & COLLISION_FLAG_INCLUDE_INTANGIBLE); + s32 checkingForCamera = ((gCollisionFlags & COLLISION_FLAG_CAMERA) != 0); + s32 skipIntangible = ((gCollisionFlags & COLLISION_FLAG_INCLUDE_INTANGIBLE) == 0); // Iterate through the list of floors until there are no more floors. while (surfaceNode != NULL) { @@ -495,21 +519,31 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 // To prevent the Merry-Go-Round room from loading when Mario is above the hole that leads there, SURFACE_INTANGIBLE is used. // This prevents the wrong room from loading, but can also allow Mario to pass through. - if (skipIntangible && (type == SURFACE_INTANGIBLE)) continue; + if (skipIntangible && (type == SURFACE_INTANGIBLE)) { + continue; + } // Determine if we are checking for the camera or not. if (checkingForCamera) { - if (floor->flags & SURFACE_FLAG_NO_CAM_COLLISION) continue; + if (floor->flags & SURFACE_FLAG_NO_CAM_COLLISION) { + continue; + } } else { // If we are not checking for the camera, ignore camera only floors. - if (type == SURFACE_CAMERA_BOUNDARY) continue; + if (type == SURFACE_CAMERA_BOUNDARY) { + continue; + } } // Exclude all floors above the check height. - if (y < floor->lowerY) continue; + if (y < floor->lowerY) { + continue; + } // Check that the point is within the triangle bounds. - if (!check_within_floor_triangle_bounds(x, z, floor)) continue; + if (!check_within_floor_triangle_bounds(x, z, floor)) { + continue; + } // Get the height of the floor under the current location. f32 floorHeight = get_surface_height_at_location(x, z, floor); @@ -518,14 +552,18 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 if ( (floorHeight > y) || // Higher than the check height. (floorHeight <= highestFloorHeight) // Lower than the previous highest floor. - ) continue; + ) { + continue; + } // Update the highest found floor. highestFloor = floor; highestFloorHeight = floorHeight; // Exit the loop if it's not possible for another floor to be closer to the check height (eg. standing on a floor). - if (floorHeight == y) break; + if (floorHeight == y) { + break; + } } *pheight = highestFloorHeight; diff --git a/src/game/object_list_processor.h b/src/game/object_list_processor.h index 215af73b98..147aa6367e 100644 --- a/src/game/object_list_processor.h +++ b/src/game/object_list_processor.h @@ -102,9 +102,9 @@ extern struct MemoryPool *gObjectMemoryPool; enum CollisionFlags { COLLISION_FLAGS_NONE = (0 << 0), + COLLISION_FLAG_EXCLUDE_DYNAMIC = (1 << 0), COLLISION_FLAG_CAMERA = (1 << 1), COLLISION_FLAG_INCLUDE_INTANGIBLE = (1 << 2), - COLLISION_FLAG_EXCLUDE_DYNAMIC = (1 << 3), }; extern s16 gCollisionFlags;