Consider all walls when doing quarter steps (fixCollisionBugs)
This commit is contained in:
parent
4add33fa19
commit
57b507ba1d
|
@ -4182,8 +4182,9 @@ end
|
|||
--- @param pos Vec3f
|
||||
--- @param offset number
|
||||
--- @param radius number
|
||||
--- @return Surface
|
||||
function resolve_and_return_wall_collisions(pos, offset, radius)
|
||||
--- @param collisionData WallCollisionData
|
||||
--- @return nil
|
||||
function resolve_and_return_wall_collisions(pos, offset, radius, collisionData)
|
||||
-- ...
|
||||
end
|
||||
|
||||
|
|
|
@ -3915,7 +3915,7 @@
|
|||
## [resolve_and_return_wall_collisions](#resolve_and_return_wall_collisions)
|
||||
|
||||
### Lua Example
|
||||
`local SurfaceValue = resolve_and_return_wall_collisions(pos, offset, radius)`
|
||||
`resolve_and_return_wall_collisions(pos, offset, radius, collisionData)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
|
@ -3923,12 +3923,13 @@
|
|||
| pos | [Vec3f](structs.md#Vec3f) |
|
||||
| offset | `number` |
|
||||
| radius | `number` |
|
||||
| collisionData | [WallCollisionData](structs.md#WallCollisionData) |
|
||||
|
||||
### Returns
|
||||
[Surface](structs.md#Surface)
|
||||
- None
|
||||
|
||||
### C Prototype
|
||||
`struct Surface *resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius);`
|
||||
`void resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius, struct WallCollisionData* collisionData);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
|
|
|
@ -146,8 +146,13 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode,
|
|||
|
||||
//! (Wall Overlaps) Because this doesn't update the x and z local variables,
|
||||
// multiple walls can push mario more than is required.
|
||||
// <Fixed when gServerSettings.fixCollisionBugs != 0>
|
||||
data->x += surf->normal.x * (radius - offset);
|
||||
data->z += surf->normal.z * (radius - offset);
|
||||
if (gServerSettings.fixCollisionBugs) {
|
||||
x = data->x;
|
||||
z = data->z;
|
||||
}
|
||||
|
||||
//! (Unreferenced Walls) Since this only returns the first four walls,
|
||||
// this can lead to wall interaction being missed. Typically unreferenced walls
|
||||
|
@ -305,10 +310,8 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32
|
|||
// as interacting with a ceiling, ceilings far below can cause
|
||||
// "invisible walls" that are really just exposed ceilings.
|
||||
// <Fixed when gServerSettings.fixCollisionBugs != 0>
|
||||
if (gServerSettings.fixCollisionBugs) {
|
||||
if (y > height) { continue; }
|
||||
} else {
|
||||
if (y - (height - -78.0f) > 0.0f) { continue; }
|
||||
if (y - (height - -78.0f) > 0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*pheight = height;
|
||||
|
|
|
@ -736,8 +736,12 @@ void push_mario_out_of_object(struct MarioState *m, struct Object *o, f32 paddin
|
|||
if (floor != NULL) {
|
||||
//! Doesn't update Mario's referenced floor (allows oob death when
|
||||
// an object pushes you into a steep slope while in a ground action)
|
||||
// <Fixed when gServerSettings.fixCollisionBugs != 0>
|
||||
m->pos[0] = newMarioX;
|
||||
m->pos[2] = newMarioZ;
|
||||
if (gServerSettings.fixCollisionBugs) {
|
||||
m->floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &m->floor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2138,7 +2142,9 @@ void check_kick_or_punch_wall(struct MarioState *m) {
|
|||
detector[2] = m->pos[2] + 50.0f * coss(m->faceAngle[1]);
|
||||
detector[1] = m->pos[1];
|
||||
|
||||
if (resolve_and_return_wall_collisions(detector, 80.0f, 5.0f) != NULL) {
|
||||
struct WallCollisionData wcd = { 0 };
|
||||
resolve_and_return_wall_collisions(detector, 80.0f, 5.0f, &wcd);
|
||||
if (wcd.numWalls > 0) {
|
||||
if (m->action != ACT_MOVE_PUNCHING || m->forwardVel >= 0.0f) {
|
||||
if (m->action == ACT_PUNCHING) {
|
||||
m->action = ACT_MOVE_PUNCHING;
|
||||
|
|
|
@ -591,27 +591,20 @@ u32 mario_get_terrain_sound_addend(struct MarioState *m) {
|
|||
/**
|
||||
* Collides with walls and returns the most recent wall.
|
||||
*/
|
||||
struct Surface *resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius) {
|
||||
struct WallCollisionData collisionData;
|
||||
struct Surface *wall = NULL;
|
||||
void resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius, struct WallCollisionData* collisionData) {
|
||||
if (!collisionData || !pos) { return; }
|
||||
|
||||
collisionData.x = pos[0];
|
||||
collisionData.y = pos[1];
|
||||
collisionData.z = pos[2];
|
||||
collisionData.radius = radius;
|
||||
collisionData.offsetY = offset;
|
||||
collisionData->x = pos[0];
|
||||
collisionData->y = pos[1];
|
||||
collisionData->z = pos[2];
|
||||
collisionData->radius = radius;
|
||||
collisionData->offsetY = offset;
|
||||
|
||||
if (find_wall_collisions(&collisionData)) {
|
||||
wall = collisionData.walls[collisionData.numWalls - 1];
|
||||
}
|
||||
find_wall_collisions(collisionData);
|
||||
|
||||
pos[0] = collisionData.x;
|
||||
pos[1] = collisionData.y;
|
||||
pos[2] = collisionData.z;
|
||||
|
||||
// This only returns the most recent wall and can also return NULL
|
||||
// there are no wall collisions.
|
||||
return wall;
|
||||
pos[0] = collisionData->x;
|
||||
pos[1] = collisionData->y;
|
||||
pos[2] = collisionData->z;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -630,7 +623,7 @@ f32 vec3f_find_ceil(Vec3f pos, f32 height, struct Surface **ceil) {
|
|||
// Prevent exposed ceilings
|
||||
f32 vec3f_mario_ceil(Vec3f pos, f32 height, struct Surface **ceil) {
|
||||
if (gServerSettings.fixCollisionBugs) {
|
||||
height = MAX(height, pos[1]) + 3.0f;
|
||||
height = MAX(height, pos[1]);
|
||||
}
|
||||
return vec3f_find_ceil(pos, height, ceil);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "types.h"
|
||||
|
||||
extern u16 gLocalBubbleCounter;
|
||||
struct WallCollisionData;
|
||||
|
||||
s32 is_anim_at_end(struct MarioState *m);
|
||||
s32 is_anim_past_end(struct MarioState *m);
|
||||
|
@ -32,7 +33,7 @@ void mario_set_bubbled(struct MarioState* m);
|
|||
void mario_set_forward_vel(struct MarioState *m, f32 speed);
|
||||
s32 mario_get_floor_class(struct MarioState *m);
|
||||
u32 mario_get_terrain_sound_addend(struct MarioState *m);
|
||||
struct Surface *resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius);
|
||||
void resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius, struct WallCollisionData* collisionData);
|
||||
f32 vec3f_find_ceil(Vec3f pos, f32 height, struct Surface **ceil);
|
||||
f32 vec3f_mario_ceil(Vec3f pos, f32 height, struct Surface **ceil);
|
||||
s32 mario_facing_downhill(struct MarioState *m, s32 turnYaw);
|
||||
|
|
|
@ -331,7 +331,12 @@ s32 perform_hanging_step(struct MarioState *m, Vec3f nextPos) {
|
|||
|
||||
smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, m);
|
||||
|
||||
m->wall = resolve_and_return_wall_collisions(nextPos, 50.0f, 50.0f);
|
||||
struct WallCollisionData wcd = { 0 };
|
||||
resolve_and_return_wall_collisions(nextPos, 50.0f, 50.0f, &wcd);
|
||||
m->wall = (wcd.numWalls > 0)
|
||||
? wcd.walls[wcd.numWalls - 1]
|
||||
: NULL;
|
||||
|
||||
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
|
||||
ceilHeight = vec3f_mario_ceil(nextPos, floorHeight, &ceil);
|
||||
|
||||
|
|
|
@ -637,7 +637,8 @@ s32 act_debug_free_move(struct MarioState *m) {
|
|||
pos[2] += 26.0f * speed * coss(m->intendedYaw);
|
||||
}
|
||||
|
||||
resolve_and_return_wall_collisions(pos, 60.0f, 50.0f);
|
||||
struct WallCollisionData wcd = { 0 };
|
||||
resolve_and_return_wall_collisions(pos, 60.0f, 50.0f, &wcd);
|
||||
|
||||
struct Surface *surf = NULL;
|
||||
f32 floorHeight = find_floor(pos[0], pos[1], pos[2], &surf);
|
||||
|
|
|
@ -81,13 +81,13 @@ static f32 get_buoyancy(struct MarioState *m) {
|
|||
}
|
||||
|
||||
u32 perform_water_full_step(struct MarioState *m, Vec3f nextPos) {
|
||||
struct Surface *wall;
|
||||
struct WallCollisionData wcd = { 0 };
|
||||
struct Surface *ceil;
|
||||
struct Surface *floor;
|
||||
f32 ceilHeight;
|
||||
f32 floorHeight;
|
||||
|
||||
wall = resolve_and_return_wall_collisions(nextPos, 10.0f, 110.0f);
|
||||
resolve_and_return_wall_collisions(nextPos, 10.0f, 110.0f, &wcd);
|
||||
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
|
||||
ceilHeight = vec3f_mario_ceil(nextPos, floorHeight, &ceil);
|
||||
|
||||
|
@ -101,7 +101,7 @@ u32 perform_water_full_step(struct MarioState *m, Vec3f nextPos) {
|
|||
m->floor = floor;
|
||||
m->floorHeight = floorHeight;
|
||||
|
||||
if (wall != NULL) {
|
||||
if (wcd.numWalls > 0) {
|
||||
return WATER_STEP_HIT_WALL;
|
||||
} else {
|
||||
return WATER_STEP_NONE;
|
||||
|
|
|
@ -258,23 +258,25 @@ s32 stationary_ground_step(struct MarioState *m) {
|
|||
}
|
||||
|
||||
static s32 perform_ground_quarter_step(struct MarioState *m, Vec3f nextPos) {
|
||||
UNUSED struct Surface *lowerWall;
|
||||
struct Surface *upperWall;
|
||||
struct WallCollisionData lowerWcd = { 0 };
|
||||
struct WallCollisionData upperWcd = { 0 };
|
||||
struct Surface *ceil;
|
||||
struct Surface *floor;
|
||||
f32 ceilHeight;
|
||||
f32 floorHeight;
|
||||
f32 waterLevel;
|
||||
|
||||
lowerWall = resolve_and_return_wall_collisions(nextPos, 30.0f, 24.0f);
|
||||
upperWall = resolve_and_return_wall_collisions(nextPos, 60.0f, 50.0f);
|
||||
resolve_and_return_wall_collisions(nextPos, 30.0f, 24.0f, &lowerWcd);
|
||||
resolve_and_return_wall_collisions(nextPos, 60.0f, 50.0f, &upperWcd);
|
||||
|
||||
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
|
||||
ceilHeight = vec3f_mario_ceil(nextPos, floorHeight, &ceil);
|
||||
|
||||
waterLevel = find_water_level(nextPos[0], nextPos[2]);
|
||||
|
||||
m->wall = upperWall;
|
||||
m->wall = (upperWcd.numWalls > 0)
|
||||
? upperWcd.walls[upperWcd.numWalls - 1]
|
||||
: NULL;
|
||||
|
||||
if (floor == NULL) {
|
||||
return GROUND_STEP_HIT_WALL_STOP_QSTEPS;
|
||||
|
@ -305,17 +307,22 @@ static s32 perform_ground_quarter_step(struct MarioState *m, Vec3f nextPos) {
|
|||
m->floor = floor;
|
||||
m->floorHeight = floorHeight;
|
||||
|
||||
if (upperWall != NULL) {
|
||||
s16 wallDYaw = atan2s(upperWall->normal.z, upperWall->normal.x) - m->faceAngle[1];
|
||||
if (upperWcd.numWalls > 0) {
|
||||
for (u8 i = 0; i < upperWcd.numWalls; i++) {
|
||||
if (!gServerSettings.fixCollisionBugs) {
|
||||
i = (upperWcd.numWalls - 1);
|
||||
}
|
||||
struct Surface* wall = upperWcd.walls[i];
|
||||
s16 wallDYaw = atan2s(wall->normal.z, wall->normal.x) - m->faceAngle[1];
|
||||
|
||||
if (wallDYaw >= 0x2AAA && wallDYaw <= 0x5555) {
|
||||
return GROUND_STEP_NONE;
|
||||
if (wallDYaw >= 0x2AAA && wallDYaw <= 0x5555) {
|
||||
// nothing
|
||||
} else if (wallDYaw <= -0x2AAA && wallDYaw >= -0x5555) {
|
||||
// nothing
|
||||
} else {
|
||||
return GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS;
|
||||
}
|
||||
}
|
||||
if (wallDYaw <= -0x2AAA && wallDYaw >= -0x5555) {
|
||||
return GROUND_STEP_NONE;
|
||||
}
|
||||
|
||||
return GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS;
|
||||
}
|
||||
|
||||
return GROUND_STEP_NONE;
|
||||
|
@ -392,8 +399,8 @@ u32 check_ledge_grab(struct MarioState *m, struct Surface *wall, Vec3f intendedP
|
|||
s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepArg) {
|
||||
s16 wallDYaw;
|
||||
Vec3f nextPos;
|
||||
struct Surface *upperWall;
|
||||
struct Surface *lowerWall;
|
||||
struct WallCollisionData lowerWcd = { 0 };
|
||||
struct WallCollisionData upperWcd = { 0 };
|
||||
struct Surface *ceil;
|
||||
struct Surface *floor;
|
||||
f32 ceilHeight;
|
||||
|
@ -402,8 +409,8 @@ s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepAr
|
|||
|
||||
vec3f_copy(nextPos, intendedPos);
|
||||
|
||||
upperWall = resolve_and_return_wall_collisions(nextPos, 150.0f, 50.0f);
|
||||
lowerWall = resolve_and_return_wall_collisions(nextPos, 30.0f, 50.0f);
|
||||
resolve_and_return_wall_collisions(nextPos, 150.0f, 50.0f, &upperWcd);
|
||||
resolve_and_return_wall_collisions(nextPos, 30.0f, 50.0f, &lowerWcd);
|
||||
|
||||
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
|
||||
ceilHeight = vec3f_mario_ceil(nextPos, floorHeight, &ceil);
|
||||
|
@ -472,9 +479,15 @@ s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepAr
|
|||
|
||||
//! When the wall is not completely vertical or there is a slight wall
|
||||
// misalignment, you can activate these conditions in unexpected situations
|
||||
if ((stepArg & AIR_STEP_CHECK_LEDGE_GRAB) && upperWall == NULL && lowerWall != NULL) {
|
||||
if (check_ledge_grab(m, lowerWall, intendedPos, nextPos)) {
|
||||
return AIR_STEP_GRABBED_LEDGE;
|
||||
if ((stepArg & AIR_STEP_CHECK_LEDGE_GRAB) && upperWcd.numWalls == 0 && lowerWcd.numWalls > 0) {
|
||||
for (u8 i = 0; i < lowerWcd.numWalls; i++) {
|
||||
if (!gServerSettings.fixCollisionBugs) {
|
||||
i = (lowerWcd.numWalls - 1);
|
||||
}
|
||||
struct Surface* wall = lowerWcd.walls[i];
|
||||
if (check_ledge_grab(m, wall, intendedPos, nextPos)) {
|
||||
return AIR_STEP_GRABBED_LEDGE;
|
||||
}
|
||||
}
|
||||
|
||||
vec3f_copy(m->pos, nextPos);
|
||||
|
@ -487,17 +500,45 @@ s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepAr
|
|||
m->floor = floor;
|
||||
m->floorHeight = floorHeight;
|
||||
|
||||
if (upperWall != NULL || lowerWall != NULL) {
|
||||
m->wall = upperWall != NULL ? upperWall : lowerWall;
|
||||
wallDYaw = atan2s(m->wall->normal.z, m->wall->normal.x) - m->faceAngle[1];
|
||||
if (upperWcd.numWalls > 0) {
|
||||
for (u8 i = 0; i < upperWcd.numWalls; i++) {
|
||||
if (!gServerSettings.fixCollisionBugs) {
|
||||
i = (upperWcd.numWalls - 1);
|
||||
}
|
||||
|
||||
if (m->wall->type == SURFACE_BURNING) {
|
||||
return AIR_STEP_HIT_LAVA_WALL;
|
||||
struct Surface* wall = upperWcd.walls[i];
|
||||
m->wall = wall;
|
||||
|
||||
wallDYaw = atan2s(m->wall->normal.z, m->wall->normal.x) - m->faceAngle[1];
|
||||
|
||||
if (m->wall->type == SURFACE_BURNING) {
|
||||
return AIR_STEP_HIT_LAVA_WALL;
|
||||
}
|
||||
|
||||
if (wallDYaw < -0x6000 || wallDYaw > 0x6000) {
|
||||
m->flags |= MARIO_UNKNOWN_30;
|
||||
return AIR_STEP_HIT_WALL;
|
||||
}
|
||||
}
|
||||
} else if (lowerWcd.numWalls > 0) {
|
||||
for (u8 i = 0; i < lowerWcd.numWalls; i++) {
|
||||
if (!gServerSettings.fixCollisionBugs) {
|
||||
i = (lowerWcd.numWalls - 1);
|
||||
}
|
||||
|
||||
if (wallDYaw < -0x6000 || wallDYaw > 0x6000) {
|
||||
m->flags |= MARIO_UNKNOWN_30;
|
||||
return AIR_STEP_HIT_WALL;
|
||||
struct Surface* wall = lowerWcd.walls[i];
|
||||
m->wall = wall;
|
||||
|
||||
wallDYaw = atan2s(m->wall->normal.z, m->wall->normal.x) - m->faceAngle[1];
|
||||
|
||||
if (m->wall->type == SURFACE_BURNING) {
|
||||
return AIR_STEP_HIT_LAVA_WALL;
|
||||
}
|
||||
|
||||
if (wallDYaw < -0x6000 || wallDYaw > 0x6000) {
|
||||
m->flags |= MARIO_UNKNOWN_30;
|
||||
return AIR_STEP_HIT_WALL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8383,7 +8383,7 @@ int smlua_func_play_sound_if_no_flag(lua_State* L) {
|
|||
}
|
||||
|
||||
int smlua_func_resolve_and_return_wall_collisions(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 3)) { return 0; }
|
||||
if(!smlua_functions_valid_param_count(L, 4)) { return 0; }
|
||||
|
||||
|
||||
f32* pos = smlua_get_vec3f_from_buffer();
|
||||
|
@ -8395,8 +8395,10 @@ int smlua_func_resolve_and_return_wall_collisions(lua_State* L) {
|
|||
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; }
|
||||
f32 radius = smlua_to_number(L, 3);
|
||||
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 3"); return 0; }
|
||||
struct WallCollisionData* collisionData = (struct WallCollisionData*)smlua_to_cobject(L, 4, LOT_WALLCOLLISIONDATA);
|
||||
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 4"); return 0; }
|
||||
|
||||
smlua_push_object(L, LOT_SURFACE, resolve_and_return_wall_collisions(pos, offset, radius));
|
||||
resolve_and_return_wall_collisions(pos, offset, radius, collisionData);
|
||||
|
||||
smlua_push_number_field(1, "x", pos[0]);
|
||||
smlua_push_number_field(1, "y", pos[1]);
|
||||
|
|
Loading…
Reference in New Issue