From aac33a924572d72273293ebfc509b10384d65db3 Mon Sep 17 00:00:00 2001 From: Prince Frizzy Date: Wed, 12 Jun 2024 01:51:28 -0400 Subject: [PATCH 1/6] Initial testing branch for new step system. --- autogen/lua_definitions/constants.lua | 60 ++++-- autogen/lua_definitions/functions.lua | 9 + docs/lua/constants.md | 12 ++ docs/lua/functions-3.md | 23 +++ docs/lua/functions.md | 1 + include/sm64.h | 37 ++-- src/engine/surface_collision.c | 86 +++++++- src/engine/surface_collision.h | 3 +- src/game/bettercamera.inc.h | 6 +- src/game/camera.c | 4 +- src/game/mario.c | 11 +- src/game/mario_step.c | 80 ++++++-- src/game/mario_step.h | 1 + src/game/mario_step_new.c | 250 +++++++++++++++++++++++ src/game/mario_step_new.h | 35 ++++ src/pc/lua/smlua_constants_autogen.c | 36 ++-- src/pc/lua/smlua_functions_autogen.c | 76 ++++++- src/pc/lua/utils/smlua_collision_utils.c | 2 +- 18 files changed, 654 insertions(+), 78 deletions(-) create mode 100644 src/game/mario_step_new.c create mode 100644 src/game/mario_step_new.h diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index b49c4ee23..b5a28c9a7 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -8807,28 +8807,28 @@ ACT_WATER_SHOCKED = 0x300222C8 ACT_WATER_THROW = 0x300024E0 --- @type integer -AIR_STEP_CHECK_HANG = 0x00000002 +AIR_STEP_CHECK_HANG = STEP_CHECK_HANG --- @type integer -AIR_STEP_CHECK_LEDGE_GRAB = 0x00000001 +AIR_STEP_CHECK_LEDGE_GRAB = STEP_CHECK_LEDGE_GRAB --- @type integer -AIR_STEP_GRABBED_CEILING = 4 +AIR_STEP_GRABBED_CEILING = STEP_GRAB_CEILING --- @type integer -AIR_STEP_GRABBED_LEDGE = 3 +AIR_STEP_GRABBED_LEDGE = STEP_GRAB_LEDGE --- @type integer -AIR_STEP_HIT_LAVA_WALL = 6 +AIR_STEP_HIT_LAVA_WALL = STEP_HIT_LAVA --- @type integer -AIR_STEP_HIT_WALL = 2 +AIR_STEP_HIT_WALL = STEP_HIT_WALL --- @type integer -AIR_STEP_LANDED = 1 +AIR_STEP_LANDED = STEP_ON_GROUND --- @type integer -AIR_STEP_NONE = 0 +AIR_STEP_NONE = STEP_IN_AIR --- @type integer C_BUTTONS = (U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS ) @@ -8837,19 +8837,19 @@ C_BUTTONS = (U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS ) END_DEMO = (1 << 7) --- @type integer -GROUND_STEP_HIT_WALL = 2 +GROUND_STEP_HIT_WALL = STEP_HIT_WALL --- @type integer GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS = 3 --- @type integer -GROUND_STEP_HIT_WALL_STOP_QSTEPS = 2 +GROUND_STEP_HIT_WALL_STOP_QSTEPS = STEP_HIT_CEILING --- @type integer -GROUND_STEP_LEFT_GROUND = 0 +GROUND_STEP_LEFT_GROUND = STEP_IN_AIR --- @type integer -GROUND_STEP_NONE = 1 +GROUND_STEP_NONE = STEP_ON_GROUND --- @type integer INPUT_ABOVE_SLIDE = 0x0008 @@ -9052,6 +9052,39 @@ PARTICLE_WATER_SPLASH = (1 << 6) --- @type integer PARTICLE_WAVE_TRAIL = (1 << 10) +--- @type integer +STEP_CHECK_HANG = 0x00000002 + +--- @type integer +STEP_CHECK_LEDGE_GRAB = 0x00000001 + +--- @type integer +STEP_GRAB_CEILING = 4 + +--- @type integer +STEP_GRAB_LEDGE = 3 + +--- @type integer +STEP_HIT_CEILING = 6 + +--- @type integer +STEP_HIT_LAVA = 5 + +--- @type integer +STEP_HIT_WALL = 2 + +--- @type integer +STEP_IN_AIR = 0 + +--- @type integer +STEP_NO_GRAVITY = 0x00000004 + +--- @type integer +STEP_ON_GROUND = 1 + +--- @type integer +STEP_SNAP_TO_FLOOR = 0x00000008 + --- @type integer STEP_TYPE_AIR = 2 @@ -9082,6 +9115,9 @@ WATER_STEP_HIT_WALL = 4 --- @type integer WATER_STEP_NONE = 0 +--- @type integer +MAX_HOOKED_MOD_MENU_ELEMENTS = 256 + --- @class LuaActionHookType --- @type LuaActionHookType diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 66ded312b..5b2265342 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -4843,6 +4843,15 @@ function bhv_unlock_door_star_loop() -- ... end +--- @param m MarioState +--- @param wall Surface +--- @param intendedPos Vec3f +--- @param nextPos Vec3f +--- @return integer +function check_ledge_grab(m, wall, intendedPos, nextPos) + -- ... +end + --- @return number function get_additive_y_vel_for_jumps() -- ... diff --git a/docs/lua/constants.md b/docs/lua/constants.md index c8a207952..f8ebf63ed 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -3223,6 +3223,17 @@ - PARTICLE_VERTICAL_STAR - PARTICLE_WATER_SPLASH - PARTICLE_WAVE_TRAIL +- STEP_CHECK_HANG +- STEP_CHECK_LEDGE_GRAB +- STEP_GRAB_CEILING +- STEP_GRAB_LEDGE +- STEP_HIT_CEILING +- STEP_HIT_LAVA +- STEP_HIT_WALL +- STEP_IN_AIR +- STEP_NO_GRAVITY +- STEP_ON_GROUND +- STEP_SNAP_TO_FLOOR - STEP_TYPE_AIR - STEP_TYPE_GROUND - STEP_TYPE_HANG @@ -3239,6 +3250,7 @@
## [smlua_hooks.h](#smlua_hooks.h) +- MAX_HOOKED_MOD_MENU_ELEMENTS ### [enum LuaActionHookType](#LuaActionHookType) | Identifier | Value | diff --git a/docs/lua/functions-3.md b/docs/lua/functions-3.md index 1e99c6bec..e2d4d580e 100644 --- a/docs/lua/functions-3.md +++ b/docs/lua/functions-3.md @@ -8181,6 +8181,29 @@
+## [check_ledge_grab](#check_ledge_grab) + +### Lua Example +`local integerValue = check_ledge_grab(m, wall, intendedPos, nextPos)` + +### Parameters +| Field | Type | +| ----- | ---- | +| m | [MarioState](structs.md#MarioState) | +| wall | [Surface](structs.md#Surface) | +| intendedPos | [Vec3f](structs.md#Vec3f) | +| nextPos | [Vec3f](structs.md#Vec3f) | + +### Returns +- `integer` + +### C Prototype +`u32 check_ledge_grab(struct MarioState *m, struct Surface *wall, Vec3f intendedPos, Vec3f nextPos);` + +[:arrow_up_small:](#) + +
+ ## [get_additive_y_vel_for_jumps](#get_additive_y_vel_for_jumps) ### Lua Example diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 94d68a08f..533d671cd 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -1095,6 +1095,7 @@
- mario_step.h + - [check_ledge_grab](functions-3.md#check_ledge_grab) - [get_additive_y_vel_for_jumps](functions-3.md#get_additive_y_vel_for_jumps) - [init_bully_collision_data](functions-3.md#init_bully_collision_data) - [mario_bonk_reflection](functions-3.md#mario_bonk_reflection) diff --git a/include/sm64.h b/include/sm64.h index b3a2c68ad..3ec5ff3d6 100644 --- a/include/sm64.h +++ b/include/sm64.h @@ -66,21 +66,34 @@ #define INPUT_Z_DOWN 0x4000 #define INPUT_Z_PRESSED 0x8000 -#define GROUND_STEP_LEFT_GROUND 0 -#define GROUND_STEP_NONE 1 -#define GROUND_STEP_HIT_WALL 2 -#define GROUND_STEP_HIT_WALL_STOP_QSTEPS 2 +#define STEP_IN_AIR 0 +#define STEP_ON_GROUND 1 +#define STEP_HIT_WALL 2 +#define STEP_GRAB_LEDGE 3 +#define STEP_GRAB_CEILING 4 +#define STEP_HIT_LAVA 5 +#define STEP_HIT_CEILING 6 + +#define STEP_CHECK_LEDGE_GRAB 0x00000001 +#define STEP_CHECK_HANG 0x00000002 +#define STEP_NO_GRAVITY 0x00000004 +#define STEP_SNAP_TO_FLOOR 0x00000008 + +#define GROUND_STEP_LEFT_GROUND STEP_IN_AIR +#define GROUND_STEP_NONE STEP_ON_GROUND +#define GROUND_STEP_HIT_WALL STEP_HIT_WALL +#define GROUND_STEP_HIT_WALL_STOP_QSTEPS STEP_HIT_CEILING #define GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS 3 -#define AIR_STEP_CHECK_LEDGE_GRAB 0x00000001 -#define AIR_STEP_CHECK_HANG 0x00000002 +#define AIR_STEP_CHECK_LEDGE_GRAB STEP_CHECK_LEDGE_GRAB +#define AIR_STEP_CHECK_HANG STEP_CHECK_HANG -#define AIR_STEP_NONE 0 -#define AIR_STEP_LANDED 1 -#define AIR_STEP_HIT_WALL 2 -#define AIR_STEP_GRABBED_LEDGE 3 -#define AIR_STEP_GRABBED_CEILING 4 -#define AIR_STEP_HIT_LAVA_WALL 6 +#define AIR_STEP_NONE STEP_IN_AIR +#define AIR_STEP_LANDED STEP_ON_GROUND +#define AIR_STEP_HIT_WALL STEP_HIT_WALL +#define AIR_STEP_GRABBED_LEDGE STEP_GRAB_LEDGE +#define AIR_STEP_GRABBED_CEILING STEP_GRAB_CEILING +#define AIR_STEP_HIT_LAVA_WALL STEP_HIT_LAVA #define WATER_STEP_NONE 0 #define WATER_STEP_HIT_FLOOR 1 diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 464da2c90..4a20dd606 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -177,7 +177,6 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, if (!gFindWallDirectionActive && vec3f_dot(norm, cNorm) < 0) { continue; } } else { - offset = surf->normal.x * x + surf->normal.y * y + surf->normal.z * z + surf->originOffset; if (offset < -radius || offset > radius) { @@ -877,6 +876,86 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { return height; } +/** + * Find the highest floor under a given position and return the height. + */ +f32 find_floor_air(f32 xPos, f32 yPos, f32 zPos, f32 velocity, struct Surface **pfloor) { + s16 cellZ, cellX; + + struct Surface *floor, *dynamicFloor; + struct SurfaceNode *surfaceList; + + f32 height = gLevelValues.floorLowerLimit;// + 9000.0f; + f32 dynamicHeight = gLevelValues.floorLowerLimit;// + 9000.0f; + + //! (Parallel Universes) Because position is casted to an s16, reaching higher + // float locations can return floors despite them not existing there. + //(Dynamic floors will unload due to the range.) + s16 x = (s16) xPos; + s16 y = (s16) yPos; + s16 z = (s16) zPos; + + *pfloor = NULL; + +#if EXTENDED_BOUNDS_MODE != 3 + if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) { + return height; + } + if (z <= -LEVEL_BOUNDARY_MAX || z >= LEVEL_BOUNDARY_MAX) { + return height; + } +#endif + + // Each level is split into cells to limit load, find the appropriate cell. + cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + + // Check for surfaces belonging to objects. + surfaceList = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next; + if (velocity < 10.f) { + dynamicFloor = find_floor_from_list(surfaceList, x, y, z, &dynamicHeight); + } else { + dynamicFloor = 0; + } + + // Check for surfaces that are a part of level geometry. + surfaceList = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next; + floor = find_floor_from_list(surfaceList, x, y, z, &height); + + // 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 (!gFindFloorIncludeSurfaceIntangible) { + //! (BBH Crash) Most NULL checking is done by checking the height of the floor returned + // instead of checking directly for a NULL floor. If this check returns a NULL floor + // (happens when there is no floor under the SURFACE_INTANGIBLE floor) but returns the height + // of the SURFACE_INTANGIBLE floor instead of the typical -11000 returned for a NULL floor. + if (floor != NULL && floor->type == SURFACE_INTANGIBLE) { + floor = find_floor_from_list(surfaceList, x, (s32)(height - 200.0f), z, &height); + } + } else { + // To prevent accidentally leaving the floor tangible, stop checking for it. + gFindFloorIncludeSurfaceIntangible = FALSE; + } + + // If a floor was missed, increment the debug counter. + if (floor == NULL) { + gNumFindFloorMisses += 1; + } + + if (dynamicHeight > height) { + floor = dynamicFloor; + height = dynamicHeight; + } + + *pfloor = floor; + + // Increment the debug tracker. + gNumCalls.floor += 1; + + return height; +} + /************************************************** * ENVIRONMENTAL BOXES * **************************************************/ @@ -1190,7 +1269,7 @@ void find_surface_on_ray_cell(s16 cellX, s16 cellZ, Vec3f orig, Vec3f normalized } } -void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos) +void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos, f32 precision) { f32 max_length; s16 cellZ, cellX; @@ -1223,9 +1302,6 @@ void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Ve return; } - // increase collision checking precision (normally 1) - f32 precision = 3; - // Get cells we cross using DDA if (absx(dir[0]) >= absx(dir[2])) step = precision * absx(dir[0]) / CELL_SIZE; diff --git a/src/engine/surface_collision.h b/src/engine/surface_collision.h index 4f58f6595..9d9bf04fa 100644 --- a/src/engine/surface_collision.h +++ b/src/engine/surface_collision.h @@ -49,9 +49,10 @@ f32 find_ceil_height(f32 x, f32 y, f32 z); f32 find_floor_height_and_data(f32 xPos, f32 yPos, f32 zPos, struct FloorGeometry **floorGeo); f32 find_floor_height(f32 x, f32 y, f32 z); f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor); +f32 find_floor_air(f32 xPos, f32 yPos, f32 zPos, f32 velocity, struct Surface **pfloor); f32 find_water_level(f32 x, f32 z); f32 find_poison_gas_level(f32 x, f32 z); void debug_surface_list_info(f32 xPos, f32 zPos); -void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos); +void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos, f32 precision); #endif // SURFACE_COLLISION_H diff --git a/src/game/bettercamera.inc.h b/src/game/bettercamera.inc.h index 2bddce8fc..ebe47088b 100644 --- a/src/game/bettercamera.inc.h +++ b/src/game/bettercamera.inc.h @@ -553,7 +553,7 @@ static void newcam_collision(void) { offset[1], offset[2] * 1.2f, }; - find_surface_on_ray(newcam_pos_target, move, &surf, hitpos); + find_surface_on_ray(newcam_pos_target, move, &surf, hitpos, 3.0f); vec3f_copy(offset, hitpos); vec3f_sub(offset, newcam_pos_target); if (surf) { @@ -576,7 +576,7 @@ static void newcam_collision(void) { struct Surface* surf; Vec3f hitpos; - find_surface_on_ray(camorig, camray, &surf, hitpos); + find_surface_on_ray(camorig, camray, &surf, hitpos, 3.0f); if (surf == NULL) { allhit = false; @@ -594,7 +594,7 @@ static void newcam_collision(void) { struct Surface *surf = NULL; Vec3f hitpos; - find_surface_on_ray(newcam_lookat, camdir, &surf, hitpos); + find_surface_on_ray(newcam_lookat, camdir, &surf, hitpos, 3.0f); if (surf) { // offset the hit pos by the hit normal diff --git a/src/game/camera.c b/src/game/camera.c index b8727b77f..7f56a0681 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -12181,7 +12181,7 @@ static u8 rom_hack_cam_can_see_mario(Vec3f desiredPos) { camdir[2] = target[2] - desiredPos[2]; Vec3f hitpos; - find_surface_on_ray(desiredPos, camdir, &surf, hitpos); + find_surface_on_ray(desiredPos, camdir, &surf, hitpos, 3.0f); if (surf == NULL) { return true; } @@ -12200,7 +12200,7 @@ void rom_hack_cam_walk(Vec3f pos, Vec3f dir, f32 dist) { struct Surface* surf = NULL; Vec3f hitpos; - find_surface_on_ray(pos, movement, &surf, hitpos); + find_surface_on_ray(pos, movement, &surf, hitpos, 3.0f); if (surf == NULL) { pos[0] += movement[0]; diff --git a/src/game/mario.c b/src/game/mario.c index 2e49f535c..9e7ef2905 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -778,19 +778,16 @@ s32 mario_floor_is_steep(struct MarioState *m) { if (!mario_facing_downhill(m, FALSE)) { switch (mario_get_floor_class(m)) { case SURFACE_VERY_SLIPPERY: - normY = 0.9659258f; // ~cos(15 deg) + normY = 0.9659258f; // ~cos(15 deg) or ~sin(75 deg) break; case SURFACE_SLIPPERY: - normY = 0.9396926f; // ~cos(20 deg) - break; - - default: - normY = 0.8660254f; // ~cos(30 deg) + normY = 0.9396926f; // ~cos(20 deg) or ~sin(70 deg) break; case SURFACE_NOT_SLIPPERY: - normY = 0.8660254f; // ~cos(30 deg) + default: + normY = 0.8660254f; // ~cos(30 deg) or ~sin(60 deg) break; } diff --git a/src/game/mario_step.c b/src/game/mario_step.c index b84d9d533..fc9aea091 100644 --- a/src/game/mario_step.c +++ b/src/game/mario_step.c @@ -8,6 +8,7 @@ #include "game_init.h" #include "interaction.h" #include "mario_step.h" +#include "mario_step_new.h" #include "pc/lua/smlua.h" #include "game/hardcoded.h" @@ -170,7 +171,7 @@ u32 mario_update_quicksand(struct MarioState *m, f32 sinkingSpeed) { u32 mario_push_off_steep_floor(struct MarioState *m, u32 action, u32 actionArg) { if (!m) { return 0; } s16 floorDYaw = m->floorAngle - m->faceAngle[1]; - + if (floorDYaw > -0x4000 && floorDYaw < 0x4000) { m->forwardVel = 16.0f; m->faceAngle[1] = m->floorAngle; @@ -352,14 +353,14 @@ static s32 perform_ground_quarter_step(struct MarioState *m, Vec3f nextPos) { s32 perform_ground_step(struct MarioState *m) { if (!m) { return 0; } - s32 i; u32 stepResult; Vec3f intendedPos; s32 returnValue = 0; if (smlua_call_event_hooks_mario_param_and_int_ret_int(HOOK_BEFORE_PHYS_STEP, m, STEP_TYPE_GROUND, &returnValue)) return returnValue; - - for (i = 0; i < 4; i++) { + + /* + for (s32 i = 0; i < 4; i++) { Vec3f step = { 0 }; if (m->floor) { f32 floorNormal; @@ -386,14 +387,38 @@ s32 perform_ground_step(struct MarioState *m) { break; } } + + if (stepResult == GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS) { + stepResult = GROUND_STEP_HIT_WALL; + } + */ + + Vec3f step = { 0 }; + if (m->floor) { + f32 floorNormal; + if (!smlua_call_event_hooks_mario_param_ret_float(HOOK_OVERRIDE_PHYS_STEP_DEFACTO_SPEED, m, &floorNormal)) { + floorNormal = m->floor->normal.y; + } + step[0] = floorNormal * m->vel[0]; + step[2] = floorNormal * m->vel[2]; + } + + intendedPos[0] = m->pos[0] + step[0]; + intendedPos[1] = m->pos[1]; + intendedPos[2] = m->pos[2] + step[2]; + + vec3f_normalize(step); + + vec3f_copy(gFindWallDirection, step); + + gFindWallDirectionActive = true; + stepResult = PerformStep(m, intendedPos, STEP_SNAP_TO_FLOOR); + gFindWallDirectionActive = false; m->terrainSoundAddend = mario_get_terrain_sound_addend(m); vec3f_copy(m->marioObj->header.gfx.pos, m->pos); vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0); - - if (stepResult == GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS) { - stepResult = GROUND_STEP_HIT_WALL; - } + return stepResult; } @@ -724,16 +749,15 @@ void apply_vertical_wind(struct MarioState *m) { s32 perform_air_step(struct MarioState *m, u32 stepArg) { if (!m) { return 0; } Vec3f intendedPos; - s32 i; - s32 quarterStepResult; s32 stepResult = AIR_STEP_NONE; s32 returnValue = 0; if (smlua_call_event_hooks_mario_param_and_int_and_int_ret_int(HOOK_BEFORE_PHYS_STEP, m, STEP_TYPE_AIR, stepArg, &returnValue)) return returnValue; m->wall = NULL; - - for (i = 0; i < 4; i++) { + + /* + for (s32 i = 0; i < 4; i++) { Vec3f step = { m->vel[0] / 4.0f, m->vel[1] / 4.0f, @@ -749,7 +773,7 @@ s32 perform_air_step(struct MarioState *m, u32 stepArg) { gFindWallDirectionActive = true; gFindWallDirectionAirborne = true; - quarterStepResult = perform_air_quarter_step(m, intendedPos, stepArg); + stepResult = perform_air_quarter_step(m, intendedPos, stepArg); gFindWallDirectionAirborne = false; gFindWallDirectionActive = false; @@ -757,16 +781,32 @@ s32 perform_air_step(struct MarioState *m, u32 stepArg) { // getting 0s until your last qf. Graze a wall on your last qf, and it will // return the stored 2 with a sharply angled reference wall. (some gwks) - if (quarterStepResult != AIR_STEP_NONE) { - stepResult = quarterStepResult; - } - - if (quarterStepResult == AIR_STEP_LANDED || quarterStepResult == AIR_STEP_GRABBED_LEDGE - || quarterStepResult == AIR_STEP_GRABBED_CEILING - || quarterStepResult == AIR_STEP_HIT_LAVA_WALL) { + if (stepResult == AIR_STEP_LANDED || stepResult == AIR_STEP_GRABBED_LEDGE + || stepResult == AIR_STEP_GRABBED_CEILING + || stepResult == AIR_STEP_HIT_LAVA_WALL) { break; } } + */ + + Vec3f step = { + m->vel[0], + m->vel[1], + m->vel[2], + }; + + intendedPos[0] = m->pos[0] + step[0]; + intendedPos[1] = m->pos[1] + step[1]; + intendedPos[2] = m->pos[2] + step[2]; + + vec3f_normalize(step); + vec3f_copy(gFindWallDirection, step); + + gFindWallDirectionActive = true; + gFindWallDirectionAirborne = true; + stepResult = PerformStep(m, intendedPos, stepArg); + gFindWallDirectionAirborne = false; + gFindWallDirectionActive = false; if (m->vel[1] >= 0.0f) { m->peakHeight = m->pos[1]; diff --git a/src/game/mario_step.h b/src/game/mario_step.h index 9be6f8e74..fb1dc5ad1 100644 --- a/src/game/mario_step.h +++ b/src/game/mario_step.h @@ -31,6 +31,7 @@ u32 mario_update_windy_ground(struct MarioState *); void stop_and_set_height_to_floor(struct MarioState *); s32 stationary_ground_step(struct MarioState *); s32 perform_ground_step(struct MarioState *); +u32 check_ledge_grab(struct MarioState *m, struct Surface *wall, Vec3f intendedPos, Vec3f nextPos); s32 perform_air_step(struct MarioState *, u32); void set_vel_from_pitch_and_yaw(struct MarioState* m); diff --git a/src/game/mario_step_new.c b/src/game/mario_step_new.c new file mode 100644 index 000000000..267e49d52 --- /dev/null +++ b/src/game/mario_step_new.c @@ -0,0 +1,250 @@ +#include + +#include "sm64.h" +#include "engine/math_util.h" +#include "engine/surface_collision.h" +#include "mario.h" +#include "audio/external.h" +#include "game_init.h" +#include "interaction.h" +#include "mario_step.h" +#include "mario_step_new.h" +#include "pc/lua/smlua.h" +#include "game/hardcoded.h" +#include "game/object_helpers.h" +#include "pc/debuglog.h" + +// New system to verify Mario's moves. Inspired by UE5's MoveUpdatedComponent function. +// Advantage: +// 1. Can no longer clip ceilings and steep floors +// 2. No more high speed clips +// 3. Consistently lands on steep floors +// 4. SM64 has an error up to 25% for moving mario. This has an error up to 1.56%. +// 5. Runs 4 collision calls per tick instead of 16 (95% of the time) +// 6. Consistent between swimming, aerial and ground step +// 7. Gets rid of quarterstep oddities +// +// Credit to Kaze Emanuar + +// Snap to the first collision in direction +void CheckMoveEndPosition(struct MarioState *m, struct MoveData *MoveResult) { + MoveResult->HitSurface = 0; + Vec3f MoveVector; + MoveVector[0] = MoveResult->IntendedPos[0] - m->pos[0]; + MoveVector[1] = MoveResult->IntendedPos[1] - m->pos[1]; + MoveVector[2] = MoveResult->IntendedPos[2] - m->pos[2]; + f32 MoveSize = vec3f_length(MoveVector); + // If we have no movement, Don't continue. + if (MoveSize <= 0.0f) { return; } + + // Scale up move size to account for mario's size + f32 ScaledMoveSize = ((MoveSize + MoveResult->MarioWidth) / MoveSize); + // Seperate clipvector saves us some multiplications down the line! + Vec3f ClipVector; + ClipVector[0] = MoveVector[0] * ScaledMoveSize; + ClipVector[1] = MoveVector[1] * ScaledMoveSize; + ClipVector[2] = MoveVector[2] * ScaledMoveSize; + + // Use the middle of Mario's to most represent his hitbox (idealls this would be a capsule cast) + m->pos[1] += MoveResult->MarioHeight / 2; + Vec3f HitPos; + find_surface_on_ray(m->pos, ClipVector, &MoveResult->HitSurface, HitPos, 8.f); + m->pos[1] -= MoveResult->MarioHeight / 2; + + // Don't clip if no collision was found. + if (MoveResult->HitSurface == NULL) { return; } + + //LOG_DEBUG("%f", (MoveResult->HitSurface)->normal.y); + + // Check for around ~cos(76.65 deg), If we as steep or any steeper. + // We want to reject movement up the slope. + if (absf((MoveResult->HitSurface)->normal.y) <= 0.23f) { + const f32 DistanceMoved = sqrtf(sqr(HitPos[0] - MoveResult->IntendedPos[0]) + + sqr(HitPos[1] - MoveResult->IntendedPos[1]) + + sqr(HitPos[2] - MoveResult->IntendedPos[2])); + + // Move back either by as wide as Mario is or the whole distance, Whatever is less. + f32 MoveBackScale = (MIN(DistanceMoved, MoveResult->MarioWidth) / MoveSize); + + MoveResult->IntendedPos[0] = HitPos[0] - MoveVector[0] * MoveBackScale; + //MoveResult->IntendedPos[1] = HitPos[1] - MoveVector[1] * MoveBackScale - MoveResult->MarioHeight / 2; + MoveResult->IntendedPos[1] = HitPos[1] - ((f32) FLOOR_SNAP_OFFSET) / 2.f; + MoveResult->IntendedPos[2] = HitPos[2] - MoveVector[2] * MoveBackScale; + } else if ((MoveResult->HitSurface)->normal.y < 0.f) { + // Let the binary search find a good position towards Mario's direction. + MoveResult->IntendedPos[0] = HitPos[0] + MoveResult->HitSurface->normal.x; + MoveResult->IntendedPos[1] = HitPos[1] + MoveResult->HitSurface->normal.y - MoveResult->MarioHeight / 2; + MoveResult->IntendedPos[2] = HitPos[2] + MoveResult->HitSurface->normal.z; + } else { + MoveResult->IntendedPos[0] = HitPos[0]; + // Snap far enough down to guarantee find_floor will find a bigger value. + MoveResult->IntendedPos[1] = HitPos[1] - ((f32) FLOOR_SNAP_OFFSET) / 2.f; + MoveResult->IntendedPos[2] = HitPos[2]; + } +} + +// Checks if the new position is valid. +s32 CheckMoveValid(struct MarioState *m, struct MoveData *MoveResult) { + // Wall collision happens first since walls will never prevent a move. + resolve_and_return_wall_collisions_data(MoveResult->IntendedPos, (60.0f), MoveResult->MarioWidth + 10.f, &MoveResult->WallCDs); + MoveResult->FloorHeight = find_floor_air(MoveResult->IntendedPos[0], MoveResult->IntendedPos[1], MoveResult->IntendedPos[2], m->vel[1], &MoveResult->Floor); + // OOB is invalid + if (!MoveResult->Floor) + return 0; + // A special check for if we're riding a shell. + MoveResult->WaterHeight = find_water_level(MoveResult->IntendedPos[0], MoveResult->IntendedPos[2]); + if ((m->action & ACT_FLAG_RIDING_SHELL) && MoveResult->FloorHeight < MoveResult->WaterHeight) { + MoveResult->FloorHeight = MoveResult->WaterHeight; + MoveResult->Floor = &gWaterSurfacePseudoFloor; + MoveResult->Floor->originOffset = MoveResult->FloorHeight; //! Wrong origin offset (no effect) + } + // Snap up early to make sure ceiling test happens from the right spot + if ((MoveResult->StepArgs & STEP_SNAP_TO_FLOOR) && MoveResult->IntendedPos[1] < MoveResult->FloorHeight + FLOOR_SNAP_OFFSET) { + MoveResult->IntendedPos[1] = MoveResult->FloorHeight; + } else if (MoveResult->IntendedPos[1] < MoveResult->FloorHeight) { + MoveResult->IntendedPos[1] = MoveResult->FloorHeight; + } + MoveResult->CeilHeight = vec3f_mario_ceil(MoveResult->IntendedPos, MoveResult->IntendedPos[1], &MoveResult->Ceil); + // Mario does not fit here! + if (MoveResult->FloorHeight + MoveResult->MarioHeight >= MoveResult->CeilHeight) + return 0; + + return 1; +} + +// Scales the move. The Y is assumed to always be valid (if not, we are ceiling bonking anyway) +s32 ScaleMove(struct MarioState *m, struct MoveData *MoveResult, f32 Scale) { + MoveResult->IntendedPos[0] = (MoveResult->GoalPos[0] - m->pos[0]) * Scale + m->pos[0]; + MoveResult->IntendedPos[1] = MoveResult->GoalPos[1]; + MoveResult->IntendedPos[2] = (MoveResult->GoalPos[2] - m->pos[2]) * Scale + m->pos[2]; +} + +s32 FinishMove(struct MarioState *m, struct MoveData *MoveResult) { + m->floor = MoveResult->Floor; + m->ceil = MoveResult->Ceil; + m->floorHeight = MoveResult->FloorHeight; + m->ceilHeight = MoveResult->CeilHeight; + // Optional, But adding this will scale Mario's movement relative to the steepness of a slope from the interacting floor. + // But it doesn't seem to work with really steep slopes :< + /*if (m->pos[1] <= m->floorHeight) { + MoveResult->IntendedPos[0] = (MoveResult->IntendedPos[0] - m->pos[0]) * absf(m->floor->normal.y) + m->pos[0]; + MoveResult->IntendedPos[2] = (MoveResult->IntendedPos[2] - m->pos[2]) * absf(m->floor->normal.y) + m->pos[2]; + }*/ + + vec3f_copy(m->pos, MoveResult->IntendedPos); + + mario_update_wall(m, &MoveResult->WallCDs); + + if (m->ceilHeight < m->pos[1] + MoveResult->MarioHeight) { + m->pos[1] = m->ceilHeight - MoveResult->MarioHeight; + m->vel[1] = 0.0f; + if ((MoveResult->StepArgs & STEP_CHECK_HANG) && m->ceil != NULL && ((m->ceil->type == SURFACE_HANGABLE))) { + return STEP_GRAB_CEILING; + } + } + + // If we are not set to snap to the floor but landed despite that, on ground takes priority! + if (!(MoveResult->StepArgs & STEP_SNAP_TO_FLOOR) && (m->pos[1] <= m->floorHeight)) + return STEP_ON_GROUND; + + for (u8 i = 0; i < MoveResult->WallCDs.numWalls; i++) { + m->wall = MoveResult->WallCDs.walls[i]; + + if (m->wall->type == SURFACE_BURNING) { + return STEP_HIT_LAVA; + } + if (MoveResult->StepArgs & STEP_CHECK_LEDGE_GRAB) { + if (check_ledge_grab(m, m->wall, MoveResult->GoalPos, MoveResult->IntendedPos)) { + return STEP_GRAB_LEDGE; + } + } + + s16 wallDYaw = (s16)(atan2s(m->wall->normal.z, m->wall->normal.x) - m->faceAngle[1]); + + if (wallDYaw >= 0x2AAA && wallDYaw <= 0x5555) { + // nothing + } else if (wallDYaw <= -0x2AAA && wallDYaw >= -0x5555) { + // nothing + } else { + return STEP_HIT_WALL; + } + + /* + u16 WallAngleMaxDiff = MoveResult->StepArgs & STEP_SNAP_TO_FLOOR ? 0x8000 - 23 : 0x8000 - 23; + if (absi((s16) (atan2s(m->wall->normal.z, m->wall->normal.x) - m->faceAngle[1])) >= WallAngleMaxDiff) { + return STEP_HIT_WALL; + } + */ + } + + // If we haven't moved, we hit either oob or a ceiling. +#define ZERO_POINT_FIVE_TO_THE_POWER_OF_MINUS_NUM_SEARCHES 0.015625f + if (MoveResult->BiggestValidMove < ZERO_POINT_FIVE_TO_THE_POWER_OF_MINUS_NUM_SEARCHES) { + return STEP_HIT_WALL; + } + + return m->pos[1] <= m->floorHeight ? STEP_ON_GROUND : STEP_IN_AIR; +} + +// Performs a generic step and returns the step result +// [StepArgs] checks for special interactions like ceilings, ledges and floor snapping +s32 PerformStep(struct MarioState *m, Vec3f GoalPos, const s32 StepArgs) { + struct MoveData MoveResult = { 0 }; + MoveResult.MarioHeight = (m->action & ACT_FLAG_SHORT_HITBOX) ? MARIOHEIGHT / 2.f : MARIOHEIGHT; + //MoveResult.MarioHeight = m->marioObj->hitboxHeight; + MoveResult.MarioWidth = m->marioObj->hitboxRadius; + MoveResult.StepArgs = StepArgs; + vec3f_copy(MoveResult.IntendedPos, GoalPos); + s32 IterationsRemaining = 2; +DoItAgain: + CheckMoveEndPosition(m, &MoveResult); + vec3f_copy(MoveResult.GoalPos, MoveResult.IntendedPos); + + // If the move is outright valid (VAST MAJORITY OF MOVES), just exit instantly. + if (CheckMoveValid(m, &MoveResult)) { + if (MoveResult.HitSurface) { + struct Surface *HitSurface; + Vec3f HitPos; + Vec3f ClipVector; + ClipVector[0] = MoveResult.GoalPos[0] - m->pos[0]; + // Move back up because floors in HitSurface move Mario down (ensures snapping) + ClipVector[1] = MoveResult.GoalPos[1] - m->pos[1] + (MoveResult.HitSurface->normal.y > 23 ? FLOOR_SNAP_OFFSET / 2.f + 4.f : 0.f); + ClipVector[2] = MoveResult.GoalPos[2] - m->pos[2]; + find_surface_on_ray(m->pos, ClipVector, &HitSurface, HitPos, 8.f); + // Ensure nothing moved mario's feet through a surface. + // (Ledgegrabs may teleport mario, but they happen in FinishMove) + if (HitSurface) { + // Give it another try, we do want to move as much as possible. + vec3f_copy(MoveResult.GoalPos, HitPos); + IterationsRemaining--; + if (IterationsRemaining) + goto DoItAgain; + // No valid moves managed to be made. Emergency exit! + return STEP_HIT_WALL; + } + } + // Full move happened + MoveResult.BiggestValidMove = 1.f; + return FinishMove(m, &MoveResult); + } + // Move was unsuccessful. Scale it down to a precision of 2^-NUM_SEARCHES + f32 CurrentMoveSize = 0.5f; + MoveResult.BiggestValidMove = 0.f; +#define NUM_SEARCHES 6 + for (s32 BinarySplitsReamining = NUM_SEARCHES; BinarySplitsReamining > 0; BinarySplitsReamining--) { + ScaleMove(m, &MoveResult, MoveResult.BiggestValidMove + CurrentMoveSize); + if (CheckMoveValid(m, &MoveResult)) { + MoveResult.BiggestValidMove += CurrentMoveSize; + } + CurrentMoveSize *= 0.5f; + } + ScaleMove(m, &MoveResult, MoveResult.BiggestValidMove); + // No valid move can be made. We are stuck OOB. + // This should only happen if a platform OOB teleported away. + // Mario should die here. + if (!CheckMoveValid(m, &MoveResult)) { + return STEP_HIT_WALL; + } + // We've moved, but not the full distance. + return FinishMove(m, &MoveResult); +} \ No newline at end of file diff --git a/src/game/mario_step_new.h b/src/game/mario_step_new.h new file mode 100644 index 000000000..69d71a679 --- /dev/null +++ b/src/game/mario_step_new.h @@ -0,0 +1,35 @@ +#ifndef MARIO_STEP_NEW_H +#define MARIO_STEP_NEW_H + +#include + +#include "types.h" + +#define WALLMAXNORMAL 0.08f +#define FLOOR_SNAP_OFFSET 78 + +// how tall mario is for the purpose of collision +#define MARIOWIDENESS (FLOOR_SNAP_OFFSET * 2.f - 1.f) +#define MARIOHEIGHT (FLOOR_SNAP_OFFSET * 2.f - 1.f) + +// Movedata lets us pass by struct to reduce arg passing overhead +struct MoveData { + struct WallCollisionData WallCDs; + struct Surface *HitSurface; // Raycast hit result + //struct Surface *Wall; + struct Surface *Floor; + struct Surface *Ceil; + f32 IntendedPos[3]; // Position we believe to be a good enough approximation for where mario can go + f32 GoalPos[3]; // Position we originally wanted to move towards + f32 FloorHeight; + f32 CeilHeight; + f32 WaterHeight; + f32 MarioHeight; + f32 MarioWidth; + s32 StepArgs; + f32 BiggestValidMove; // How much we managed to move +}; + +s32 PerformStep(struct MarioState *m, Vec3f GoalPos, const s32 StepArgs); + +#endif // MARIO_STEP_NEW_H diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index a9c4e5ea5..3772e8c89 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -2908,19 +2908,30 @@ char gSmluaConstants[] = "" "INPUT_B_PRESSED = 0x2000\n" "INPUT_Z_DOWN = 0x4000\n" "INPUT_Z_PRESSED = 0x8000\n" -"GROUND_STEP_LEFT_GROUND = 0\n" -"GROUND_STEP_NONE = 1\n" -"GROUND_STEP_HIT_WALL = 2\n" -"GROUND_STEP_HIT_WALL_STOP_QSTEPS = 2\n" +"STEP_IN_AIR = 0\n" +"STEP_ON_GROUND = 1\n" +"STEP_HIT_WALL = 2\n" +"STEP_GRAB_LEDGE = 3\n" +"STEP_GRAB_CEILING = 4\n" +"STEP_HIT_LAVA = 5\n" +"STEP_HIT_CEILING = 6\n" +"STEP_CHECK_LEDGE_GRAB = 0x00000001\n" +"STEP_CHECK_HANG = 0x00000002\n" +"STEP_NO_GRAVITY = 0x00000004\n" +"STEP_SNAP_TO_FLOOR = 0x00000008\n" +"GROUND_STEP_LEFT_GROUND = STEP_IN_AIR\n" +"GROUND_STEP_NONE = STEP_ON_GROUND\n" +"GROUND_STEP_HIT_WALL = STEP_HIT_WALL\n" +"GROUND_STEP_HIT_WALL_STOP_QSTEPS = STEP_HIT_CEILING\n" "GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS = 3\n" -"AIR_STEP_CHECK_LEDGE_GRAB = 0x00000001\n" -"AIR_STEP_CHECK_HANG = 0x00000002\n" -"AIR_STEP_NONE = 0\n" -"AIR_STEP_LANDED = 1\n" -"AIR_STEP_HIT_WALL = 2\n" -"AIR_STEP_GRABBED_LEDGE = 3\n" -"AIR_STEP_GRABBED_CEILING = 4\n" -"AIR_STEP_HIT_LAVA_WALL = 6\n" +"AIR_STEP_CHECK_LEDGE_GRAB = STEP_CHECK_LEDGE_GRAB\n" +"AIR_STEP_CHECK_HANG = STEP_CHECK_HANG\n" +"AIR_STEP_NONE = STEP_IN_AIR\n" +"AIR_STEP_LANDED = STEP_ON_GROUND\n" +"AIR_STEP_HIT_WALL = STEP_HIT_WALL\n" +"AIR_STEP_GRABBED_LEDGE = STEP_GRAB_LEDGE\n" +"AIR_STEP_GRABBED_CEILING = STEP_GRAB_CEILING\n" +"AIR_STEP_HIT_LAVA_WALL = STEP_HIT_LAVA\n" "WATER_STEP_NONE = 0\n" "WATER_STEP_HIT_FLOOR = 1\n" "WATER_STEP_HIT_CEILING = 2\n" @@ -3296,6 +3307,7 @@ char gSmluaConstants[] = "" "ACTION_HOOK_EVERY_FRAME = 0\n" "ACTION_HOOK_GRAVITY = 1\n" "ACTION_HOOK_MAX = 2\n" +"MAX_HOOKED_MOD_MENU_ELEMENTS = 256\n" "MOD_MENU_ELEMENT_BUTTON = 0\n" "MOD_MENU_ELEMENT_CHECKBOX = 1\n" "MOD_MENU_ELEMENT_SLIDER = 2\n" diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 440ceb83d..7818f390a 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -17816,6 +17816,45 @@ int smlua_func_bhv_unlock_door_star_loop(UNUSED lua_State* L) { // mario_step.h // ////////////////// +int smlua_func_check_ledge_grab(lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 4) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "check_ledge_grab", 4, top); + return 0; + } + + struct MarioState* m = (struct MarioState*)smlua_to_cobject(L, 1, LOT_MARIOSTATE); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "check_ledge_grab"); return 0; } + struct Surface* wall = (struct Surface*)smlua_to_cobject(L, 2, LOT_SURFACE); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "check_ledge_grab"); return 0; } + + f32* intendedPos = smlua_get_vec3f_from_buffer(); + intendedPos[0] = smlua_get_number_field(3, "x"); + intendedPos[1] = smlua_get_number_field(3, "y"); + intendedPos[2] = smlua_get_number_field(3, "z"); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "check_ledge_grab"); return 0; } + + f32* nextPos = smlua_get_vec3f_from_buffer(); + nextPos[0] = smlua_get_number_field(4, "x"); + nextPos[1] = smlua_get_number_field(4, "y"); + nextPos[2] = smlua_get_number_field(4, "z"); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 4, "check_ledge_grab"); return 0; } + + lua_pushinteger(L, check_ledge_grab(m, wall, intendedPos, nextPos)); + + smlua_push_number_field(3, "x", intendedPos[0]); + smlua_push_number_field(3, "y", intendedPos[1]); + smlua_push_number_field(3, "z", intendedPos[2]); + + smlua_push_number_field(4, "x", nextPos[0]); + smlua_push_number_field(4, "y", nextPos[1]); + smlua_push_number_field(4, "z", nextPos[2]); + + return 1; +} + int smlua_func_get_additive_y_vel_for_jumps(UNUSED lua_State* L) { if (L == NULL) { return 0; } @@ -32329,6 +32368,33 @@ int smlua_func_find_floor(lua_State* L) { } */ +/* +int smlua_func_find_floor_air(lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 5) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "find_floor_air", 5, top); + return 0; + } + + f32 xPos = smlua_to_number(L, 1); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "find_floor_air"); return 0; } + f32 yPos = smlua_to_number(L, 2); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "find_floor_air"); return 0; } + f32 zPos = smlua_to_number(L, 3); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "find_floor_air"); return 0; } + f32 velocity = smlua_to_number(L, 4); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 4, "find_floor_air"); return 0; } +// struct Surface** pfloor = (struct Surface**)smlua_to_cobject(L, 5, LOT_???); <--- UNIMPLEMENTED + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 5, "find_floor_air"); return 0; } + + lua_pushnumber(L, find_floor_air(xPos, yPos, zPos, velocity, pfloor)); + + return 1; +} +*/ + int smlua_func_find_floor_height(lua_State* L) { if (L == NULL) { return 0; } @@ -32399,8 +32465,8 @@ int smlua_func_find_surface_on_ray(lua_State* L) { if (L == NULL) { return 0; } int top = lua_gettop(L); - if (top != 4) { - LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "find_surface_on_ray", 4, top); + if (top != 5) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "find_surface_on_ray", 5, top); return 0; } @@ -32424,8 +32490,10 @@ int smlua_func_find_surface_on_ray(lua_State* L) { hit_pos[1] = smlua_get_number_field(4, "y"); hit_pos[2] = smlua_get_number_field(4, "z"); if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 4, "find_surface_on_ray"); return 0; } + f32 precision = smlua_to_number(L, 5); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 5, "find_surface_on_ray"); return 0; } - find_surface_on_ray(orig, dir, hit_surface, hit_pos); + find_surface_on_ray(orig, dir, hit_surface, hit_pos, precision); smlua_push_number_field(1, "x", orig[0]); smlua_push_number_field(1, "y", orig[1]); @@ -33627,6 +33695,7 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "bhv_unlock_door_star_loop", smlua_func_bhv_unlock_door_star_loop); // mario_step.h + smlua_bind_function(L, "check_ledge_grab", smlua_func_check_ledge_grab); smlua_bind_function(L, "get_additive_y_vel_for_jumps", smlua_func_get_additive_y_vel_for_jumps); smlua_bind_function(L, "init_bully_collision_data", smlua_func_init_bully_collision_data); smlua_bind_function(L, "mario_bonk_reflection", smlua_func_mario_bonk_reflection); @@ -34347,6 +34416,7 @@ void smlua_bind_functions_autogen(void) { //smlua_bind_function(L, "find_ceil", smlua_func_find_ceil); <--- UNIMPLEMENTED smlua_bind_function(L, "find_ceil_height", smlua_func_find_ceil_height); //smlua_bind_function(L, "find_floor", smlua_func_find_floor); <--- UNIMPLEMENTED + //smlua_bind_function(L, "find_floor_air", smlua_func_find_floor_air); <--- UNIMPLEMENTED smlua_bind_function(L, "find_floor_height", smlua_func_find_floor_height); //smlua_bind_function(L, "find_floor_height_and_data", smlua_func_find_floor_height_and_data); <--- UNIMPLEMENTED smlua_bind_function(L, "find_poison_gas_level", smlua_func_find_poison_gas_level); diff --git a/src/pc/lua/utils/smlua_collision_utils.c b/src/pc/lua/utils/smlua_collision_utils.c index 824be2a84..1e2cb0d45 100644 --- a/src/pc/lua/utils/smlua_collision_utils.c +++ b/src/pc/lua/utils/smlua_collision_utils.c @@ -161,7 +161,7 @@ struct RayIntersectionInfo* collision_find_surface_on_ray(f32 startX, f32 startY static struct RayIntersectionInfo info = { 0 }; Vec3f orig = { startX, startY, startZ }; Vec3f dir = { dirX, dirY, dirZ }; - find_surface_on_ray(orig, dir, &info.surface, info.hitPos); + find_surface_on_ray(orig, dir, &info.surface, info.hitPos, 3.0f); return &info; } From 1a7e876b3363754dfb14149d2e9617823c5e0bf8 Mon Sep 17 00:00:00 2001 From: Prince Frizzy Date: Thu, 27 Jun 2024 20:46:48 -0400 Subject: [PATCH 2/6] Fix some inaccuracies with the new step system, And reorganize some code. --- build64_us-dev.bat | 95 +++++++++++++++++++++++++++ src/game/mario_step_new.c | 133 +++++++++++++++++++------------------- src/game/mario_step_new.h | 2 +- 3 files changed, 163 insertions(+), 67 deletions(-) create mode 100644 build64_us-dev.bat diff --git a/build64_us-dev.bat b/build64_us-dev.bat new file mode 100644 index 000000000..4588f8583 --- /dev/null +++ b/build64_us-dev.bat @@ -0,0 +1,95 @@ +@echo off + +REM Opens MSYS2 shell. +C:\msys64\msys2_shell.cmd -mingw64 -here + +REM Opens MSYS2 in cmd, However anything in this file will not execute after. +rem C:\msys64\usr\bin\bash.exe --login -i -here + +REM Clean our previous build of the game. +rem make -C tools clean && make clean + +REM Make our game. + +REM ######################## US ######################## + +REM make VERSION=us COMPILER=gcc EXTERNAL_DATA=1 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/us_pc/sm64coopdx.exe + +REM make VERSION=us COMPILER=clang EXTERNAL_DATA=1 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/us_pc/sm64.us.f3dex2e.exe + +REM make VERSION=us COMPILER=clang EXTERNAL_DATA=1 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/us_pc/sm64.us.f3dex2e.exe + +REM make VERSION=us COMPILER=clang EXTERNAL_DATA=1 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/us_pc/sm64.us.f3dex2e.exe + +REM #### US (D3D11) ##### + +REM make VERSION=us RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/us_pc/sm64.us.f3dex2e.exe + +REM make VERSION=us RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/us_pc/sm64.us.f3dex2e.exe + +REM make VERSION=us RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/us_pc/sm64.us.f3dex2e.exe + +REM make VERSION=us RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/us_pc/sm64.us.f3dex2e.exe + + +REM ######################## EU ######################## + +REM make VERSION=eu COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/eu_pc/sm64.eu.f3dex2e.exe + +REM make VERSION=eu COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/eu_pc/sm64.eu.f3dex2e.exe + +REM make VERSION=eu COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/eu_pc/sm64.eu.f3dex2e.exe + +REM make VERSION=eu COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/eu_pc/sm64.eu.f3dex2e.exe + +REM #### EU (D3D11) #### + +REM make VERSION=eu RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/eu_pc/sm64.eu.f3dex2e.exe + +REM make VERSION=eu RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/eu_pc/sm64.eu.f3dex2e.exe + +REM make VERSION=eu RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/eu_pc/sm64.eu.f3dex2e.exe + +REM make VERSION=eu RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/eu_pc/sm64.eu.f3dex2e.exe + + +REM ######################## JP ######################## + +REM make VERSION=jp COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/jp_pc/sm64.jp.f3dex2e.exe + +REM make VERSION=jp COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/jp_pc/sm64.jp.f3dex2e.exe + +REM make VERSION=jp COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/jp_pc/sm64.jp.f3dex2e.exe + +REM make VERSION=jp COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/jp_pc/sm64.jp.f3dex2e.exe + +REM ##### JP (D3D11) ##### + +REM make VERSION=jp RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/jp_pc/sm64.jp.f3dex2e.exe + +REM make VERSION=jp RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/jp_pc/sm64.jp.f3dex2e.exe + +REM make VERSION=jp RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/jp_pc/sm64.jp.f3dex2e.exe + +REM make VERSION=jp RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/jp_pc/sm64.jp.f3dex2e.exe + + +REM ######################## SH ######################## + +REM make VERSION=sh COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/sh_pc/sm64.sh.f3dex2e.exe + +REM make VERSION=sh COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/sh_pc/sm64.sh.f3dex2e.exe + +REM make VERSION=sh COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/sh_pc/sm64.sh.f3dex2e.exe + +REM make VERSION=sh COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/sh_pc/sm64.sh.f3dex2e.exe + +REM ##### SH (D3D11) ##### + +REM make VERSION=sh RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/sh_pc/sm64.sh.f3dex2e.exe + +REM make VERSION=sh RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/sh_pc/sm64.sh.f3dex2e.exe + +REM make VERSION=sh RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/sh_pc/sm64.sh.f3dex2e.exe + +REM make VERSION=sh RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/sh_pc/sm64.sh.f3dex2e.exe \ No newline at end of file diff --git a/src/game/mario_step_new.c b/src/game/mario_step_new.c index 267e49d52..c5b1bda27 100644 --- a/src/game/mario_step_new.c +++ b/src/game/mario_step_new.c @@ -57,7 +57,7 @@ void CheckMoveEndPosition(struct MarioState *m, struct MoveData *MoveResult) { //LOG_DEBUG("%f", (MoveResult->HitSurface)->normal.y); // Check for around ~cos(76.65 deg), If we as steep or any steeper. - // We want to reject movement up the slope. + // We want to reject movement up/into the slope. if (absf((MoveResult->HitSurface)->normal.y) <= 0.23f) { const f32 DistanceMoved = sqrtf(sqr(HitPos[0] - MoveResult->IntendedPos[0]) + sqr(HitPos[1] - MoveResult->IntendedPos[1]) + @@ -67,8 +67,7 @@ void CheckMoveEndPosition(struct MarioState *m, struct MoveData *MoveResult) { f32 MoveBackScale = (MIN(DistanceMoved, MoveResult->MarioWidth) / MoveSize); MoveResult->IntendedPos[0] = HitPos[0] - MoveVector[0] * MoveBackScale; - //MoveResult->IntendedPos[1] = HitPos[1] - MoveVector[1] * MoveBackScale - MoveResult->MarioHeight / 2; - MoveResult->IntendedPos[1] = HitPos[1] - ((f32) FLOOR_SNAP_OFFSET) / 2.f; + MoveResult->IntendedPos[1] = HitPos[1] - MoveVector[1] * MoveBackScale - MoveResult->MarioHeight / 2; MoveResult->IntendedPos[2] = HitPos[2] - MoveVector[2] * MoveBackScale; } else if ((MoveResult->HitSurface)->normal.y < 0.f) { // Let the binary search find a good position towards Mario's direction. @@ -76,10 +75,14 @@ void CheckMoveEndPosition(struct MarioState *m, struct MoveData *MoveResult) { MoveResult->IntendedPos[1] = HitPos[1] + MoveResult->HitSurface->normal.y - MoveResult->MarioHeight / 2; MoveResult->IntendedPos[2] = HitPos[2] + MoveResult->HitSurface->normal.z; } else { - MoveResult->IntendedPos[0] = HitPos[0]; // Snap far enough down to guarantee find_floor will find a bigger value. MoveResult->IntendedPos[1] = HitPos[1] - ((f32) FLOOR_SNAP_OFFSET) / 2.f; - MoveResult->IntendedPos[2] = HitPos[2]; + + //! This causes issues with vanilla Super Mario 64. + // Mario will zip up slopes very quickly when he is not supposed too. + // This adds additionial offset to Mario's movement when it already accounts for slopes. + //MoveResult->IntendedPos[0] = HitPos[0]; + //MoveResult->IntendedPos[2] = HitPos[2]; } } @@ -124,17 +127,11 @@ s32 FinishMove(struct MarioState *m, struct MoveData *MoveResult) { m->ceil = MoveResult->Ceil; m->floorHeight = MoveResult->FloorHeight; m->ceilHeight = MoveResult->CeilHeight; - // Optional, But adding this will scale Mario's movement relative to the steepness of a slope from the interacting floor. - // But it doesn't seem to work with really steep slopes :< - /*if (m->pos[1] <= m->floorHeight) { - MoveResult->IntendedPos[0] = (MoveResult->IntendedPos[0] - m->pos[0]) * absf(m->floor->normal.y) + m->pos[0]; - MoveResult->IntendedPos[2] = (MoveResult->IntendedPos[2] - m->pos[2]) * absf(m->floor->normal.y) + m->pos[2]; - }*/ - + vec3f_copy(m->pos, MoveResult->IntendedPos); - + mario_update_wall(m, &MoveResult->WallCDs); - + if (m->ceilHeight < m->pos[1] + MoveResult->MarioHeight) { m->pos[1] = m->ceilHeight - MoveResult->MarioHeight; m->vel[1] = 0.0f; @@ -142,25 +139,24 @@ s32 FinishMove(struct MarioState *m, struct MoveData *MoveResult) { return STEP_GRAB_CEILING; } } - + // If we are not set to snap to the floor but landed despite that, on ground takes priority! - if (!(MoveResult->StepArgs & STEP_SNAP_TO_FLOOR) && (m->pos[1] <= m->floorHeight)) + if (!(MoveResult->StepArgs & STEP_SNAP_TO_FLOOR) && (m->pos[1] <= m->floorHeight)) { return STEP_ON_GROUND; - + } + for (u8 i = 0; i < MoveResult->WallCDs.numWalls; i++) { m->wall = MoveResult->WallCDs.walls[i]; - + if (m->wall->type == SURFACE_BURNING) { return STEP_HIT_LAVA; } - if (MoveResult->StepArgs & STEP_CHECK_LEDGE_GRAB) { - if (check_ledge_grab(m, m->wall, MoveResult->GoalPos, MoveResult->IntendedPos)) { - return STEP_GRAB_LEDGE; - } - } + if (MoveResult->StepArgs & STEP_CHECK_LEDGE_GRAB && check_ledge_grab(m, m->wall, MoveResult->GoalPos, MoveResult->IntendedPos)) { + return STEP_GRAB_LEDGE; + } + s16 wallDYaw = (s16)(atan2s(m->wall->normal.z, m->wall->normal.x) - m->faceAngle[1]); - if (wallDYaw >= 0x2AAA && wallDYaw <= 0x5555) { // nothing } else if (wallDYaw <= -0x2AAA && wallDYaw >= -0x5555) { @@ -168,7 +164,7 @@ s32 FinishMove(struct MarioState *m, struct MoveData *MoveResult) { } else { return STEP_HIT_WALL; } - + /* u16 WallAngleMaxDiff = MoveResult->StepArgs & STEP_SNAP_TO_FLOOR ? 0x8000 - 23 : 0x8000 - 23; if (absi((s16) (atan2s(m->wall->normal.z, m->wall->normal.x) - m->faceAngle[1])) >= WallAngleMaxDiff) { @@ -200,51 +196,56 @@ s32 PerformStep(struct MarioState *m, Vec3f GoalPos, const s32 StepArgs) { CheckMoveEndPosition(m, &MoveResult); vec3f_copy(MoveResult.GoalPos, MoveResult.IntendedPos); - // If the move is outright valid (VAST MAJORITY OF MOVES), just exit instantly. - if (CheckMoveValid(m, &MoveResult)) { - if (MoveResult.HitSurface) { - struct Surface *HitSurface; - Vec3f HitPos; - Vec3f ClipVector; - ClipVector[0] = MoveResult.GoalPos[0] - m->pos[0]; - // Move back up because floors in HitSurface move Mario down (ensures snapping) - ClipVector[1] = MoveResult.GoalPos[1] - m->pos[1] + (MoveResult.HitSurface->normal.y > 23 ? FLOOR_SNAP_OFFSET / 2.f + 4.f : 0.f); - ClipVector[2] = MoveResult.GoalPos[2] - m->pos[2]; - find_surface_on_ray(m->pos, ClipVector, &HitSurface, HitPos, 8.f); - // Ensure nothing moved mario's feet through a surface. - // (Ledgegrabs may teleport mario, but they happen in FinishMove) - if (HitSurface) { - // Give it another try, we do want to move as much as possible. - vec3f_copy(MoveResult.GoalPos, HitPos); - IterationsRemaining--; - if (IterationsRemaining) - goto DoItAgain; - // No valid moves managed to be made. Emergency exit! - return STEP_HIT_WALL; + if (!CheckMoveValid(m, &MoveResult)) { + // Move was unsuccessful. Scale it down to a precision of 2^-NUM_SEARCHES + f32 CurrentMoveSize = 0.5f; + MoveResult.BiggestValidMove = 0.f; +#define NUM_SEARCHES 6 + for (s32 BinarySplitsReamining = NUM_SEARCHES; BinarySplitsReamining > 0; BinarySplitsReamining--) { + ScaleMove(m, &MoveResult, MoveResult.BiggestValidMove + CurrentMoveSize); + if (CheckMoveValid(m, &MoveResult)) { + MoveResult.BiggestValidMove += CurrentMoveSize; } + CurrentMoveSize *= 0.5f; + } + ScaleMove(m, &MoveResult, MoveResult.BiggestValidMove); + // No valid move can be made. We are stuck OOB. + // This should only happen if a platform OOB teleported away. + // Mario should die here. + if (!CheckMoveValid(m, &MoveResult)) { + return STEP_HIT_WALL; } - // Full move happened - MoveResult.BiggestValidMove = 1.f; + // We've moved, but not the full distance. return FinishMove(m, &MoveResult); } - // Move was unsuccessful. Scale it down to a precision of 2^-NUM_SEARCHES - f32 CurrentMoveSize = 0.5f; - MoveResult.BiggestValidMove = 0.f; -#define NUM_SEARCHES 6 - for (s32 BinarySplitsReamining = NUM_SEARCHES; BinarySplitsReamining > 0; BinarySplitsReamining--) { - ScaleMove(m, &MoveResult, MoveResult.BiggestValidMove + CurrentMoveSize); - if (CheckMoveValid(m, &MoveResult)) { - MoveResult.BiggestValidMove += CurrentMoveSize; - } - CurrentMoveSize *= 0.5f; + + // If the move is outright valid (VAST MAJORITY OF MOVES), just exit instantly. + + // Full move happened + MoveResult.BiggestValidMove = 1.f; + if (!MoveResult.HitSurface) { + return FinishMove(m, &MoveResult); } - ScaleMove(m, &MoveResult, MoveResult.BiggestValidMove); - // No valid move can be made. We are stuck OOB. - // This should only happen if a platform OOB teleported away. - // Mario should die here. - if (!CheckMoveValid(m, &MoveResult)) { - return STEP_HIT_WALL; + + // Ensure nothing moved mario's feet through a surface. + // (Ledgegrabs may teleport mario, but they happen in FinishMove) + struct Surface *HitSurface = NULL; + Vec3f HitPos = { 0.f }; + Vec3f ClipVector = { 0.f }; + ClipVector[0] = MoveResult.GoalPos[0] - m->pos[0]; + // Move back up because floors in HitSurface move Mario down (ensures snapping) + ClipVector[1] = MoveResult.GoalPos[1] - m->pos[1] + (MoveResult.HitSurface->normal.y > 23 ? FLOOR_SNAP_OFFSET / 2.f + 4.f : 0.f); + ClipVector[2] = MoveResult.GoalPos[2] - m->pos[2]; + find_surface_on_ray(m->pos, ClipVector, &HitSurface, HitPos, 8.f); + if (!HitSurface) { + return FinishMove(m, &MoveResult); + } + // Give it another try, we do want to move as much as possible. + vec3f_copy(MoveResult.GoalPos, HitPos); + IterationsRemaining--; + if (IterationsRemaining) { + goto DoItAgain; } - // We've moved, but not the full distance. - return FinishMove(m, &MoveResult); + // No valid moves managed to be made. Emergency exit! + return STEP_HIT_WALL; } \ No newline at end of file diff --git a/src/game/mario_step_new.h b/src/game/mario_step_new.h index 69d71a679..3d9f98ac2 100644 --- a/src/game/mario_step_new.h +++ b/src/game/mario_step_new.h @@ -19,7 +19,7 @@ struct MoveData { //struct Surface *Wall; struct Surface *Floor; struct Surface *Ceil; - f32 IntendedPos[3]; // Position we believe to be a good enough approximation for where mario can go + f32 IntendedPos[3]; // Position we believe to be a good enough approximation for where Mario can go f32 GoalPos[3]; // Position we originally wanted to move towards f32 FloorHeight; f32 CeilHeight; From 3bc352d61ceb4985ee792c1c0a7bf23891658630 Mon Sep 17 00:00:00 2001 From: Prince Frizzy Date: Thu, 27 Jun 2024 20:49:45 -0400 Subject: [PATCH 3/6] Remove dev file. --- build64_us-dev.bat | 95 ---------------------------------------------- 1 file changed, 95 deletions(-) delete mode 100644 build64_us-dev.bat diff --git a/build64_us-dev.bat b/build64_us-dev.bat deleted file mode 100644 index 4588f8583..000000000 --- a/build64_us-dev.bat +++ /dev/null @@ -1,95 +0,0 @@ -@echo off - -REM Opens MSYS2 shell. -C:\msys64\msys2_shell.cmd -mingw64 -here - -REM Opens MSYS2 in cmd, However anything in this file will not execute after. -rem C:\msys64\usr\bin\bash.exe --login -i -here - -REM Clean our previous build of the game. -rem make -C tools clean && make clean - -REM Make our game. - -REM ######################## US ######################## - -REM make VERSION=us COMPILER=gcc EXTERNAL_DATA=1 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/us_pc/sm64coopdx.exe - -REM make VERSION=us COMPILER=clang EXTERNAL_DATA=1 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/us_pc/sm64.us.f3dex2e.exe - -REM make VERSION=us COMPILER=clang EXTERNAL_DATA=1 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/us_pc/sm64.us.f3dex2e.exe - -REM make VERSION=us COMPILER=clang EXTERNAL_DATA=1 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/us_pc/sm64.us.f3dex2e.exe - -REM #### US (D3D11) ##### - -REM make VERSION=us RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/us_pc/sm64.us.f3dex2e.exe - -REM make VERSION=us RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/us_pc/sm64.us.f3dex2e.exe - -REM make VERSION=us RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/us_pc/sm64.us.f3dex2e.exe - -REM make VERSION=us RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/us_pc/sm64.us.f3dex2e.exe - - -REM ######################## EU ######################## - -REM make VERSION=eu COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/eu_pc/sm64.eu.f3dex2e.exe - -REM make VERSION=eu COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/eu_pc/sm64.eu.f3dex2e.exe - -REM make VERSION=eu COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/eu_pc/sm64.eu.f3dex2e.exe - -REM make VERSION=eu COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/eu_pc/sm64.eu.f3dex2e.exe - -REM #### EU (D3D11) #### - -REM make VERSION=eu RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/eu_pc/sm64.eu.f3dex2e.exe - -REM make VERSION=eu RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/eu_pc/sm64.eu.f3dex2e.exe - -REM make VERSION=eu RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/eu_pc/sm64.eu.f3dex2e.exe - -REM make VERSION=eu RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/eu_pc/sm64.eu.f3dex2e.exe - - -REM ######################## JP ######################## - -REM make VERSION=jp COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/jp_pc/sm64.jp.f3dex2e.exe - -REM make VERSION=jp COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/jp_pc/sm64.jp.f3dex2e.exe - -REM make VERSION=jp COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/jp_pc/sm64.jp.f3dex2e.exe - -REM make VERSION=jp COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/jp_pc/sm64.jp.f3dex2e.exe - -REM ##### JP (D3D11) ##### - -REM make VERSION=jp RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/jp_pc/sm64.jp.f3dex2e.exe - -REM make VERSION=jp RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/jp_pc/sm64.jp.f3dex2e.exe - -REM make VERSION=jp RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/jp_pc/sm64.jp.f3dex2e.exe - -REM make VERSION=jp RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/jp_pc/sm64.jp.f3dex2e.exe - - -REM ######################## SH ######################## - -REM make VERSION=sh COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/sh_pc/sm64.sh.f3dex2e.exe - -REM make VERSION=sh COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/sh_pc/sm64.sh.f3dex2e.exe - -REM make VERSION=sh COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/sh_pc/sm64.sh.f3dex2e.exe - -REM make VERSION=sh COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/sh_pc/sm64.sh.f3dex2e.exe - -REM ##### SH (D3D11) ##### - -REM make VERSION=sh RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=1 -j9 && gdb ./build/sh_pc/sm64.sh.f3dex2e.exe - -REM make VERSION=sh RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=1 DEVELOPMENT=0 -j9 && ./build/sh_pc/sm64.sh.f3dex2e.exe - -REM make VERSION=sh RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=1 -j9 && ./build/sh_pc/sm64.sh.f3dex2e.exe - -REM make VERSION=sh RENDER_API=D3D11 COMPILER=clang EXTERNAL_DATA=0 COMPARE=0 BETTERCAMERA=1 NODRAWINGDISTANCE=1 IMMEDIATELOAD=1 DEBUG=0 DEVELOPMENT=0 -j9 && ./build/sh_pc/sm64.sh.f3dex2e.exe \ No newline at end of file From 6e607d967113e00ec0e0562d0ca1001c44f07f24 Mon Sep 17 00:00:00 2001 From: Prince Frizzy Date: Sat, 9 Nov 2024 04:46:05 -0500 Subject: [PATCH 4/6] game: Fix compile error. --- src/game/mario_step.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/mario_step.c b/src/game/mario_step.c index 5e6850d23..1ea3f76c8 100644 --- a/src/game/mario_step.c +++ b/src/game/mario_step.c @@ -396,7 +396,7 @@ s32 perform_ground_step(struct MarioState *m) { Vec3f step = { 0 }; if (m->floor) { f32 floorNormal; - if (!smlua_call_event_hooks_mario_param_ret_float(HOOK_OVERRIDE_PHYS_STEP_DEFACTO_SPEED, m, &floorNormal)) { + if (!smlua_call_event_hooks_mario_param_ret_float(HOOK_MARIO_OVERRIDE_PHYS_STEP_DEFACTO_SPEED, m, &floorNormal)) { floorNormal = m->floor->normal.y; } step[0] = floorNormal * m->vel[0]; From 6d803cd855c3aa98633e15a5256576da0c8b0b27 Mon Sep 17 00:00:00 2001 From: Prince Frizzy Date: Fri, 15 Nov 2024 04:45:39 -0500 Subject: [PATCH 5/6] game: New step system is ready for PR and testing. --- autogen/lua_definitions/constants.lua | 11 +- autogen/lua_definitions/structs.lua | 1 + docs/lua/constants.md | 1 - docs/lua/structs.md | 1 + include/sm64.h | 8 +- src/engine/math_util.h | 7 ++ src/engine/surface_collision.c | 35 +++++- src/game/camera.h | 7 +- src/game/hardcoded.c | 1 + src/game/hardcoded.h | 1 + src/game/mario_actions_submerged.c | 10 +- src/game/mario_step.c | 140 ++++++++++++------------ src/game/mario_step_new.c | 151 +++++++++++++++++++++----- src/game/mario_step_new.h | 19 +++- src/pc/lua/smlua_cobject_autogen.c | 3 +- src/pc/lua/smlua_constants_autogen.c | 9 +- 16 files changed, 274 insertions(+), 131 deletions(-) diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index 9ec8feefb..ab028a262 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -9031,19 +9031,16 @@ VALID_BUTTONS = (A_BUTTON | B_BUTTON | Z_TRIG | START_BUTTON | U_JPAD | D_JPAD | WATER_STEP_CANCELLED = 3 --- @type integer -WATER_STEP_HIT_CEILING = 2 +WATER_STEP_HIT_CEILING = STEP_HIT_CEILING --- @type integer -WATER_STEP_HIT_FLOOR = 1 +WATER_STEP_HIT_FLOOR = STEP_ON_GROUND --- @type integer -WATER_STEP_HIT_WALL = 4 +WATER_STEP_HIT_WALL = STEP_HIT_WALL --- @type integer -WATER_STEP_NONE = 0 - ---- @type integer -MAX_HOOKED_MOD_MENU_ELEMENTS = 256 +WATER_STEP_NONE = STEP_IN_AIR --- @class LuaActionHookType diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua index bbb761c31..fa79e42c4 100644 --- a/autogen/lua_definitions/structs.lua +++ b/autogen/lua_definitions/structs.lua @@ -184,6 +184,7 @@ --- @field public KoopaBobAgility number --- @field public KoopaCatchupAgility number --- @field public KoopaThiAgility number +--- @field public MarioRaycastSteps integer --- @field public MipsStar1Requirement integer --- @field public MipsStar2Requirement integer --- @field public MultipleCapCollection integer diff --git a/docs/lua/constants.md b/docs/lua/constants.md index 753b44fde..3c6dcc60d 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -3252,7 +3252,6 @@
## [smlua_hooks.h](#smlua_hooks.h) -- MAX_HOOKED_MOD_MENU_ELEMENTS ### [enum LuaActionHookType](#LuaActionHookType) | Identifier | Value | diff --git a/docs/lua/structs.md b/docs/lua/structs.md index ea9e66cf9..ed41d709d 100644 --- a/docs/lua/structs.md +++ b/docs/lua/structs.md @@ -317,6 +317,7 @@ | KoopaBobAgility | `number` | | | KoopaCatchupAgility | `number` | | | KoopaThiAgility | `number` | | +| MarioRaycastSteps | `integer` | | | MipsStar1Requirement | `integer` | | | MipsStar2Requirement | `integer` | | | MultipleCapCollection | `integer` | | diff --git a/include/sm64.h b/include/sm64.h index 3ec5ff3d6..75fd22640 100644 --- a/include/sm64.h +++ b/include/sm64.h @@ -95,11 +95,11 @@ #define AIR_STEP_GRABBED_CEILING STEP_GRAB_CEILING #define AIR_STEP_HIT_LAVA_WALL STEP_HIT_LAVA -#define WATER_STEP_NONE 0 -#define WATER_STEP_HIT_FLOOR 1 -#define WATER_STEP_HIT_CEILING 2 +#define WATER_STEP_NONE STEP_IN_AIR +#define WATER_STEP_HIT_FLOOR STEP_ON_GROUND +#define WATER_STEP_HIT_CEILING STEP_HIT_CEILING #define WATER_STEP_CANCELLED 3 -#define WATER_STEP_HIT_WALL 4 +#define WATER_STEP_HIT_WALL STEP_HIT_WALL #define STEP_TYPE_GROUND 1 #define STEP_TYPE_AIR 2 diff --git a/src/engine/math_util.h b/src/engine/math_util.h index 6df41f3af..4d02215e5 100644 --- a/src/engine/math_util.h +++ b/src/engine/math_util.h @@ -5,6 +5,13 @@ #include "types.h" +/** + * Converts an angle in degrees to sm64's s16 angle units. For example, DEGREES(90) == 0x4000 + * This should be used mainly to make camera code clearer at first glance. + */ +// #define DEGREES(x) ((x) * 0x10000 / 360) +#define DEGREES(x) ((x) * 0x2000 / 45) + /* * The sine and cosine tables overlap, but "#define gCosineTable (gSineTable + * 0x400)" doesn't give expected codegen; gSineTable and gCosineTable need to diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 4a20dd606..184946063 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -1230,9 +1230,38 @@ void find_surface_on_ray_list(struct SurfaceNode *list, Vec3f orig, Vec3f dir, f if (list->surface->lowerY > top || list->surface->upperY < bottom) continue; - // Reject no-cam collision surfaces - if (gCheckingSurfaceCollisionsForCamera && (list->surface->flags & SURFACE_FLAG_NO_CAM_COLLISION)) - continue; + // Determine if checking for the camera or not. + if (gCheckingSurfaceCollisionsForCamera) { + // Reject no-cam collision surfaces + if (list->surface->flags & SURFACE_FLAG_NO_CAM_COLLISION) { + continue; + } + } else { + // Ignore camera only surfaces. + if (list->surface->type == SURFACE_CAMERA_BOUNDARY || list->surface->type == SURFACE_RAYCAST) { + continue; + } + + // If an object can pass through a vanish cap wall, pass through. + if (list->surface->type == SURFACE_VANISH_CAP_WALLS) { + // If an object can pass through a vanish cap wall, pass through. + if (gCurrentObject != NULL + && (gCurrentObject->activeFlags & ACTIVE_FLAG_MOVE_THROUGH_GRATE)) { + continue; + } + + // If Mario has a vanish cap, pass through the vanish cap wall. + u8 passThroughWall = FALSE; + for (s32 i = 0; i < MAX_PLAYERS; i++) { + if (gCurrentObject != NULL && gCurrentObject == gMarioStates[i].marioObj + && (gMarioStates[i].flags & MARIO_VANISH_CAP)) { + passThroughWall = TRUE; + break; + } + } + if (passThroughWall) { continue; } + } + } // Check intersection between the ray and this surface if ((hit = ray_surface_intersect(orig, dir, dir_length, list->surface, chk_hit_pos, &length)) != 0) diff --git a/src/game/camera.h b/src/game/camera.h index e69636762..727399252 100644 --- a/src/game/camera.h +++ b/src/game/camera.h @@ -7,6 +7,7 @@ #include "area.h" #include "engine/geo_layout.h" #include "engine/graph_node.h" +#include "engine/math_util.h" #include "level_table.h" @@ -31,12 +32,6 @@ extern u8 gRomhackCameraAllowDpad; #define ABS(x) ((x) > 0.f ? (x) : -(x)) #define ABS2(x) ((x) >= 0.f ? (x) : -(x)) -/** - * Converts an angle in degrees to sm64's s16 angle units. For example, DEGREES(90) == 0x4000 - * This should be used mainly to make camera code clearer at first glance. - */ -#define DEGREES(x) ((x) * 0x10000 / 360) - #define LEVEL_AREA_INDEX(levelNum, areaNum) (((levelNum) << 4) + (areaNum)) /** diff --git a/src/game/hardcoded.c b/src/game/hardcoded.c index c6e2d707c..f8db1ce56 100644 --- a/src/game/hardcoded.c +++ b/src/game/hardcoded.c @@ -158,6 +158,7 @@ struct BehaviorValues gDefaultBehaviorValues = { .BowlingBallThiSmallSpeed = 10.0f, .GrateStarRequirement = 120, .ChillBullyDeathPosY = 1030.0f, + .MarioRaycastSteps = FALSE, .ShowStarMilestones = TRUE, .ShowStarDialog = TRUE, .RespawnShellBoxes = TRUE, diff --git a/src/game/hardcoded.h b/src/game/hardcoded.h index 98aec62e2..a2d99858a 100644 --- a/src/game/hardcoded.h +++ b/src/game/hardcoded.h @@ -253,6 +253,7 @@ struct BehaviorValues { f32 BowlingBallThiSmallSpeed; u16 GrateStarRequirement; f32 ChillBullyDeathPosY; + u8 MarioRaycastSteps; u8 ShowStarMilestones; u8 ShowStarDialog; u8 RespawnShellBoxes; diff --git a/src/game/mario_actions_submerged.c b/src/game/mario_actions_submerged.c index 54468b5bc..738088a48 100644 --- a/src/game/mario_actions_submerged.c +++ b/src/game/mario_actions_submerged.c @@ -11,6 +11,7 @@ #include "interaction.h" #include "mario.h" #include "mario_step.h" +#include "mario_step_new.h" #include "camera.h" #include "audio/external.h" #include "behavior_data.h" @@ -21,6 +22,7 @@ #include "pc/network/network.h" #include "pc/lua/smlua.h" #include "pc/lua/smlua_hooks.h" +#include "game/hardcoded.h" #define MIN_SWIM_STRENGTH 160 #define MIN_SWIM_SPEED 16.0f @@ -208,8 +210,12 @@ u32 perform_water_step(struct MarioState *m) { nextPos[1] = m->waterLevel - 80; m->vel[1] = 0.0f; } - - stepResult = perform_water_full_step(m, nextPos); + + if (gBehaviorValues.MarioRaycastSteps) { + stepResult = PerformStep(m, nextPos, STEP_NO_GRAVITY); + } else { + stepResult = perform_water_full_step(m, nextPos); + } vec3f_copy(marioObj->header.gfx.pos, m->pos); vec3s_set(marioObj->header.gfx.angle, -m->faceAngle[0], m->faceAngle[1], m->faceAngle[2]); diff --git a/src/game/mario_step.c b/src/game/mario_step.c index 1ea3f76c8..613144b80 100644 --- a/src/game/mario_step.c +++ b/src/game/mario_step.c @@ -359,61 +359,61 @@ s32 perform_ground_step(struct MarioState *m) { s32 returnValue = 0; if (smlua_call_event_hooks_mario_param_and_int_ret_int(HOOK_BEFORE_PHYS_STEP, m, STEP_TYPE_GROUND, &returnValue)) return returnValue; - /* - for (s32 i = 0; i < 4; i++) { + if (gBehaviorValues.MarioRaycastSteps) { Vec3f step = { 0 }; if (m->floor) { f32 floorNormal; if (!smlua_call_event_hooks_mario_param_ret_float(HOOK_MARIO_OVERRIDE_PHYS_STEP_DEFACTO_SPEED, m, &floorNormal)) { floorNormal = m->floor->normal.y; } - step[0] = floorNormal * (m->vel[0] / 4.0f); - step[2] = floorNormal * (m->vel[2] / 4.0f); + step[0] = floorNormal * m->vel[0]; + step[2] = floorNormal * m->vel[2]; } - + intendedPos[0] = m->pos[0] + step[0]; intendedPos[1] = m->pos[1]; intendedPos[2] = m->pos[2] + step[2]; - + vec3f_normalize(step); vec3f_copy(gFindWallDirection, step); gFindWallDirectionActive = true; - stepResult = perform_ground_quarter_step(m, intendedPos); + stepResult = PerformStep(m, intendedPos, STEP_SNAP_TO_FLOOR); gFindWallDirectionActive = false; + } else { + for (s32 i = 0; i < 4; i++) { + Vec3f step = { 0 }; + if (m->floor) { + f32 floorNormal; + if (!smlua_call_event_hooks_mario_param_ret_float(HOOK_MARIO_OVERRIDE_PHYS_STEP_DEFACTO_SPEED, m, &floorNormal)) { + floorNormal = m->floor->normal.y; + } + step[0] = floorNormal * (m->vel[0] / 4.0f); + step[2] = floorNormal * (m->vel[2] / 4.0f); + } + + intendedPos[0] = m->pos[0] + step[0]; + intendedPos[1] = m->pos[1]; + intendedPos[2] = m->pos[2] + step[2]; + + vec3f_normalize(step); - if (stepResult == GROUND_STEP_LEFT_GROUND || stepResult == GROUND_STEP_HIT_WALL_STOP_QSTEPS) { - break; + vec3f_copy(gFindWallDirection, step); + + gFindWallDirectionActive = true; + stepResult = perform_ground_quarter_step(m, intendedPos); + gFindWallDirectionActive = false; + + if (stepResult == GROUND_STEP_LEFT_GROUND || stepResult == GROUND_STEP_HIT_WALL_STOP_QSTEPS) { + break; + } } - } - - if (stepResult == GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS) { - stepResult = GROUND_STEP_HIT_WALL; - } - */ - - Vec3f step = { 0 }; - if (m->floor) { - f32 floorNormal; - if (!smlua_call_event_hooks_mario_param_ret_float(HOOK_MARIO_OVERRIDE_PHYS_STEP_DEFACTO_SPEED, m, &floorNormal)) { - floorNormal = m->floor->normal.y; + + if (stepResult == GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS) { + stepResult = GROUND_STEP_HIT_WALL; } - step[0] = floorNormal * m->vel[0]; - step[2] = floorNormal * m->vel[2]; } - - intendedPos[0] = m->pos[0] + step[0]; - intendedPos[1] = m->pos[1]; - intendedPos[2] = m->pos[2] + step[2]; - - vec3f_normalize(step); - - vec3f_copy(gFindWallDirection, step); - - gFindWallDirectionActive = true; - stepResult = PerformStep(m, intendedPos, STEP_SNAP_TO_FLOOR); - gFindWallDirectionActive = false; m->terrainSoundAddend = mario_get_terrain_sound_addend(m); vec3f_copy(m->marioObj->header.gfx.pos, m->pos); @@ -756,12 +756,11 @@ s32 perform_air_step(struct MarioState *m, u32 stepArg) { m->wall = NULL; - /* - for (s32 i = 0; i < 4; i++) { + if (gBehaviorValues.MarioRaycastSteps) { Vec3f step = { - m->vel[0] / 4.0f, - m->vel[1] / 4.0f, - m->vel[2] / 4.0f, + m->vel[0], + m->vel[1], + m->vel[2], }; intendedPos[0] = m->pos[0] + step[0]; @@ -773,40 +772,41 @@ s32 perform_air_step(struct MarioState *m, u32 stepArg) { gFindWallDirectionActive = true; gFindWallDirectionAirborne = true; - stepResult = perform_air_quarter_step(m, intendedPos, stepArg); + stepResult = PerformStep(m, intendedPos, stepArg); gFindWallDirectionAirborne = false; gFindWallDirectionActive = false; - - //! On one qf, hit OOB/ceil/wall to store the 2 return value, and continue - // getting 0s until your last qf. Graze a wall on your last qf, and it will - // return the stored 2 with a sharply angled reference wall. (some gwks) - - if (stepResult == AIR_STEP_LANDED || stepResult == AIR_STEP_GRABBED_LEDGE - || stepResult == AIR_STEP_GRABBED_CEILING - || stepResult == AIR_STEP_HIT_LAVA_WALL) { - break; + } else { + for (s32 i = 0; i < 4; i++) { + Vec3f step = { + m->vel[0] / 4.0f, + m->vel[1] / 4.0f, + m->vel[2] / 4.0f, + }; + + intendedPos[0] = m->pos[0] + step[0]; + intendedPos[1] = m->pos[1] + step[1]; + intendedPos[2] = m->pos[2] + step[2]; + + vec3f_normalize(step); + vec3f_copy(gFindWallDirection, step); + + gFindWallDirectionActive = true; + gFindWallDirectionAirborne = true; + stepResult = perform_air_quarter_step(m, intendedPos, stepArg); + gFindWallDirectionAirborne = false; + gFindWallDirectionActive = false; + + //! On one qf, hit OOB/ceil/wall to store the 2 return value, and continue + // getting 0s until your last qf. Graze a wall on your last qf, and it will + // return the stored 2 with a sharply angled reference wall. (some gwks) + + if (stepResult == AIR_STEP_LANDED || stepResult == AIR_STEP_GRABBED_LEDGE + || stepResult == AIR_STEP_GRABBED_CEILING + || stepResult == AIR_STEP_HIT_LAVA_WALL) { + break; + } } } - */ - - Vec3f step = { - m->vel[0], - m->vel[1], - m->vel[2], - }; - - intendedPos[0] = m->pos[0] + step[0]; - intendedPos[1] = m->pos[1] + step[1]; - intendedPos[2] = m->pos[2] + step[2]; - - vec3f_normalize(step); - vec3f_copy(gFindWallDirection, step); - - gFindWallDirectionActive = true; - gFindWallDirectionAirborne = true; - stepResult = PerformStep(m, intendedPos, stepArg); - gFindWallDirectionAirborne = false; - gFindWallDirectionActive = false; if (m->vel[1] >= 0.0f) { m->peakHeight = m->pos[1]; diff --git a/src/game/mario_step_new.c b/src/game/mario_step_new.c index c5b1bda27..548c18a5d 100644 --- a/src/game/mario_step_new.c +++ b/src/game/mario_step_new.c @@ -1,8 +1,7 @@ #include -#include "sm64.h" -#include "engine/math_util.h" -#include "engine/surface_collision.h" +#include "mario_step_new.h" + #include "mario.h" #include "audio/external.h" #include "game_init.h" @@ -26,6 +25,74 @@ // // Credit to Kaze Emanuar +// Co-Op Additions: +// 1. Smart Ledge Grabs - No longer can grab through floors. + +u32 CheckLedgeGrab(struct MarioState *m, Vec3f intendedPos, Vec3f nextPos) { + if (!m || m->vel[1] > 0.0f) { + return FALSE; + } + + f32 displacementX = nextPos[0] - intendedPos[0]; + f32 displacementZ = nextPos[2] - intendedPos[2]; + + // Only ledge grab if the wall displaced Mario in the opposite direction of + // his velocity. + if (displacementX * m->vel[0] + displacementZ * m->vel[2] > 0.0f) { + return FALSE; + } + + struct Surface *ledgeFloor = NULL; + Vec3f ledgePos; + ledgePos[0] = nextPos[0] - m->wall->normal.x * 60.0f; + ledgePos[2] = nextPos[2] - m->wall->normal.z * 60.0f; + ledgePos[1] = find_floor(ledgePos[0], nextPos[1] + m->marioObj->hitboxHeight, ledgePos[2], &ledgeFloor); + + if (!ledgeFloor || ledgePos[1] - nextPos[1] <= 100.0f) { + return FALSE; + } + + if (gLevelValues.fixCollisionBugs && gLevelValues.fixCollisionBugsFalseLedgeGrab) { + // fix false ledge grabs + if (ledgeFloor->normal.y < 0.90630779f) { + return FALSE; + } + } + + // We'll cast a ray from the top of our height to the ledge grab position. + // If we hit a surface. We aren't allowed to ledge grab. + struct Surface *hitSurface = NULL; + Vec3f HitPos; + + nextPos[1] += m->marioObj->hitboxHeight; + find_surface_on_ray(nextPos, ledgePos, &hitSurface, HitPos, 8.f); + nextPos[1] -= m->marioObj->hitboxHeight; + + // Don't grab the ledge if collision was found, and it's not the wall we wish to grab. + if (hitSurface && hitSurface != m->wall) { return FALSE; } + + vec3f_copy(m->pos, ledgePos); + m->floor = ledgeFloor; + m->floorHeight = ledgePos[1]; + m->floorAngle = atan2s(ledgeFloor->normal.z, ledgeFloor->normal.x); + + m->faceAngle[0] = 0; + m->faceAngle[1] = atan2s(m->wall->normal.z, m->wall->normal.x) + 0x8000; + return TRUE; +} + +// CheckMoveEndPosition + +// This function checks Mario's final position for collisions. + +// Collision Adjustment: +// Calculates MoveVector, the vector from Mario’s position to IntendedPos. +// If MoveVector is non-zero, scales it to account for Mario's hitbox width. +// Adjusts Mario’s Y position for accurate collision checking based on Mario’s height. +// Raycasting for Collision: +// Raycasts from Mario's position to ClipVector to detect potential collisions. +// If a collision is detected, adjusts IntendedPos based on the collision normal to prevent Mario from clipping through walls or floors. + // Snap to the first collision in direction void CheckMoveEndPosition(struct MarioState *m, struct MoveData *MoveResult) { MoveResult->HitSurface = 0; @@ -56,11 +123,12 @@ void CheckMoveEndPosition(struct MarioState *m, struct MoveData *MoveResult) { //LOG_DEBUG("%f", (MoveResult->HitSurface)->normal.y); - // Check for around ~cos(76.65 deg), If we as steep or any steeper. + /* + // Check for around ~cos(72.49 deg), If we as steep or any steeper. // We want to reject movement up/into the slope. - if (absf((MoveResult->HitSurface)->normal.y) <= 0.23f) { + if (absf((MoveResult->HitSurface)->normal.y) <= WALLMAXNORMAL) { const f32 DistanceMoved = sqrtf(sqr(HitPos[0] - MoveResult->IntendedPos[0]) + - sqr(HitPos[1] - MoveResult->IntendedPos[1]) + + sqr(HitPos[1] - - MoveResult->MarioHeight / 2 - MoveResult->IntendedPos[1]) + sqr(HitPos[2] - MoveResult->IntendedPos[2])); // Move back either by as wide as Mario is or the whole distance, Whatever is less. @@ -69,7 +137,10 @@ void CheckMoveEndPosition(struct MarioState *m, struct MoveData *MoveResult) { MoveResult->IntendedPos[0] = HitPos[0] - MoveVector[0] * MoveBackScale; MoveResult->IntendedPos[1] = HitPos[1] - MoveVector[1] * MoveBackScale - MoveResult->MarioHeight / 2; MoveResult->IntendedPos[2] = HitPos[2] - MoveVector[2] * MoveBackScale; - } else if ((MoveResult->HitSurface)->normal.y < 0.f) { + } + */ + + if ((MoveResult->HitSurface)->normal.y < 0.f) { // Let the binary search find a good position towards Mario's direction. MoveResult->IntendedPos[0] = HitPos[0] + MoveResult->HitSurface->normal.x; MoveResult->IntendedPos[1] = HitPos[1] + MoveResult->HitSurface->normal.y - MoveResult->MarioHeight / 2; @@ -89,7 +160,11 @@ void CheckMoveEndPosition(struct MarioState *m, struct MoveData *MoveResult) { // Checks if the new position is valid. s32 CheckMoveValid(struct MarioState *m, struct MoveData *MoveResult) { // Wall collision happens first since walls will never prevent a move. - resolve_and_return_wall_collisions_data(MoveResult->IntendedPos, (60.0f), MoveResult->MarioWidth + 10.f, &MoveResult->WallCDs); + if ((m->action & ACT_GROUP_MASK) == ACT_GROUP_SUBMERGED) { + resolve_and_return_wall_collisions_data(MoveResult->IntendedPos, 10.0f, 110.0f, &MoveResult->WallCDs); + } else { + resolve_and_return_wall_collisions_data(MoveResult->IntendedPos, 60.0f, MoveResult->MarioWidth + 10.f, &MoveResult->WallCDs); + } MoveResult->FloorHeight = find_floor_air(MoveResult->IntendedPos[0], MoveResult->IntendedPos[1], MoveResult->IntendedPos[2], m->vel[1], &MoveResult->Floor); // OOB is invalid if (!MoveResult->Floor) @@ -122,6 +197,15 @@ s32 ScaleMove(struct MarioState *m, struct MoveData *MoveResult, f32 Scale) { MoveResult->IntendedPos[2] = (MoveResult->GoalPos[2] - m->pos[2]) * Scale + m->pos[2]; } +// FinishMove + +// This final function updates Mario’s state based on the collision results from MoveData. + +// Updating Mario's Position and Collision State: +// Sets Mario's floor, ceiling, and wall collision data. +// Checks if Mario hits a ceiling during upward movement and removes his velocity if the ceiling is sloped toward him. +// If IntendedPos is a valid ground position, finalizes Mario’s location there; otherwise, he remains airborne. + s32 FinishMove(struct MarioState *m, struct MoveData *MoveResult) { m->floor = MoveResult->Floor; m->ceil = MoveResult->Ceil; @@ -131,13 +215,34 @@ s32 FinishMove(struct MarioState *m, struct MoveData *MoveResult) { vec3f_copy(m->pos, MoveResult->IntendedPos); mario_update_wall(m, &MoveResult->WallCDs); - - if (m->ceilHeight < m->pos[1] + MoveResult->MarioHeight) { - m->pos[1] = m->ceilHeight - MoveResult->MarioHeight; - m->vel[1] = 0.0f; + + //LOG_DEBUG("\nPOS: (%f, %f, %f)\nVEL: (%f, %f, %f)\nCEIL HEIGHT: %f\nFLOOR HEIGHT: %f\n", + // m->pos[0], m->pos[1], m->pos[2], m->vel[0], m->vel[1], m->vel[2], m->ceilHeight, m->floorHeight); + + const float CeilDist = m->ceilHeight - m->pos[1]; + if (CeilDist < MoveResult->MarioHeight) { + const float MissingDist = MoveResult->MarioHeight - CeilDist; + m->pos[0] += m->ceil->normal.x * MissingDist/2; + m->pos[1] += m->ceil->normal.y * MissingDist/2; + m->pos[2] += m->ceil->normal.z * MissingDist/2; if ((MoveResult->StepArgs & STEP_CHECK_HANG) && m->ceil != NULL && ((m->ceil->type == SURFACE_HANGABLE))) { + m->vel[1] = 0.0f; return STEP_GRAB_CEILING; } + + f32 VelocitySize = vec3f_length(m->vel); + if (VelocitySize > 0.f) { + float DotProduct = m->vel[0] * m->ceil->normal.x + + m->vel[1] * m->ceil->normal.y + + m->vel[2] * m->ceil->normal.z; + m->vel[0] -= DotProduct * m->ceil->normal.x; + m->vel[1] -= MAX(0, DotProduct * m->ceil->normal.y); + m->vel[2] -= DotProduct * m->ceil->normal.z; + } + + if ((m->action & ACT_GROUP_MASK) == ACT_GROUP_SUBMERGED) { + return STEP_HIT_CEILING; + } } // If we are not set to snap to the floor but landed despite that, on ground takes priority! @@ -152,25 +257,16 @@ s32 FinishMove(struct MarioState *m, struct MoveData *MoveResult) { return STEP_HIT_LAVA; } - if (MoveResult->StepArgs & STEP_CHECK_LEDGE_GRAB && check_ledge_grab(m, m->wall, MoveResult->GoalPos, MoveResult->IntendedPos)) { + if (MoveResult->StepArgs & STEP_CHECK_LEDGE_GRAB && CheckLedgeGrab(m, MoveResult->GoalPos, MoveResult->IntendedPos)) { return STEP_GRAB_LEDGE; } - - s16 wallDYaw = (s16)(atan2s(m->wall->normal.z, m->wall->normal.x) - m->faceAngle[1]); - if (wallDYaw >= 0x2AAA && wallDYaw <= 0x5555) { - // nothing - } else if (wallDYaw <= -0x2AAA && wallDYaw >= -0x5555) { - // nothing - } else { - return STEP_HIT_WALL; - } - /* - u16 WallAngleMaxDiff = MoveResult->StepArgs & STEP_SNAP_TO_FLOOR ? 0x8000 - 23 : 0x8000 - 23; + u16 WallAngleMaxDiff = MoveResult->StepArgs & STEP_SNAP_TO_FLOOR + ? 0x8000 - MAX_ANGLE_DIFF_FOR_WALL_COLLISION_ON_GROUND + : 0x8000 - MAX_ANGLE_DIFF_FOR_WALL_COLLISION_IN_AIR; if (absi((s16) (atan2s(m->wall->normal.z, m->wall->normal.x) - m->faceAngle[1])) >= WallAngleMaxDiff) { return STEP_HIT_WALL; } - */ } // If we haven't moved, we hit either oob or a ceiling. @@ -186,8 +282,7 @@ s32 FinishMove(struct MarioState *m, struct MoveData *MoveResult) { // [StepArgs] checks for special interactions like ceilings, ledges and floor snapping s32 PerformStep(struct MarioState *m, Vec3f GoalPos, const s32 StepArgs) { struct MoveData MoveResult = { 0 }; - MoveResult.MarioHeight = (m->action & ACT_FLAG_SHORT_HITBOX) ? MARIOHEIGHT / 2.f : MARIOHEIGHT; - //MoveResult.MarioHeight = m->marioObj->hitboxHeight; + MoveResult.MarioHeight = m->marioObj->hitboxHeight; MoveResult.MarioWidth = m->marioObj->hitboxRadius; MoveResult.StepArgs = StepArgs; vec3f_copy(MoveResult.IntendedPos, GoalPos); @@ -234,7 +329,7 @@ s32 PerformStep(struct MarioState *m, Vec3f GoalPos, const s32 StepArgs) { Vec3f ClipVector = { 0.f }; ClipVector[0] = MoveResult.GoalPos[0] - m->pos[0]; // Move back up because floors in HitSurface move Mario down (ensures snapping) - ClipVector[1] = MoveResult.GoalPos[1] - m->pos[1] + (MoveResult.HitSurface->normal.y > 23 ? FLOOR_SNAP_OFFSET / 2.f + 4.f : 0.f); + ClipVector[1] = MoveResult.GoalPos[1] - m->pos[1] + (MoveResult.HitSurface->normal.y > WALLMAXNORMAL ? FLOOR_SNAP_OFFSET / 2.f + 4.f : 0.f); ClipVector[2] = MoveResult.GoalPos[2] - m->pos[2]; find_surface_on_ray(m->pos, ClipVector, &HitSurface, HitPos, 8.f); if (!HitSurface) { diff --git a/src/game/mario_step_new.h b/src/game/mario_step_new.h index 3d9f98ac2..feb17c3c4 100644 --- a/src/game/mario_step_new.h +++ b/src/game/mario_step_new.h @@ -3,14 +3,25 @@ #include +#include "sm64.h" +#include "engine/math_util.h" +#include "engine/surface_collision.h" #include "types.h" -#define WALLMAXNORMAL 0.08f +// Strict - cos(72.49 deg) 0.30087224993 +// Lax - cos(76.65 deg) 0.23089890826 +#define WALLMAXNORMAL 0.30f + +// Negative Y displacement added to make Mario snap to the nearest floor. #define FLOOR_SNAP_OFFSET 78 -// how tall mario is for the purpose of collision -#define MARIOWIDENESS (FLOOR_SNAP_OFFSET * 2.f - 1.f) -#define MARIOHEIGHT (FLOOR_SNAP_OFFSET * 2.f - 1.f) +// When grounded, what the angle difference between the wall and Mario's head needs to be for wall collision to occur +// i.e. the angle below which Mario bonks and above which he slides along the wall +#define MAX_ANGLE_DIFF_FOR_WALL_COLLISION_ON_GROUND DEGREES(60) + +// When airborne, what the angle difference between the wall and Mario's head needs to be for wall collision to occur +// Tends to be larger as you can't mantle a wall while airborne +#define MAX_ANGLE_DIFF_FOR_WALL_COLLISION_IN_AIR DEGREES(135) // Movedata lets us pass by struct to reduce arg passing overhead struct MoveData { diff --git a/src/pc/lua/smlua_cobject_autogen.c b/src/pc/lua/smlua_cobject_autogen.c index eaece9f8b..50c8315b1 100644 --- a/src/pc/lua/smlua_cobject_autogen.c +++ b/src/pc/lua/smlua_cobject_autogen.c @@ -211,7 +211,7 @@ static struct LuaObjectField sBehaviorTrajectoriesFields[LUA_BEHAVIOR_TRAJECTORI { "UnagiTrajectory", LVT_TRAJECTORY_P, offsetof(struct BehaviorTrajectories, UnagiTrajectory), false, LOT_POINTER }, }; -#define LUA_BEHAVIOR_VALUES_FIELD_COUNT 32 +#define LUA_BEHAVIOR_VALUES_FIELD_COUNT 33 static struct LuaObjectField sBehaviorValuesFields[LUA_BEHAVIOR_VALUES_FIELD_COUNT] = { { "BowlingBallBob2Speed", LVT_F32, offsetof(struct BehaviorValues, BowlingBallBob2Speed), false, LOT_NONE }, { "BowlingBallBobSpeed", LVT_F32, offsetof(struct BehaviorValues, BowlingBallBobSpeed), false, LOT_NONE }, @@ -229,6 +229,7 @@ static struct LuaObjectField sBehaviorValuesFields[LUA_BEHAVIOR_VALUES_FIELD_COU { "KoopaBobAgility", LVT_F32, offsetof(struct BehaviorValues, KoopaBobAgility), false, LOT_NONE }, { "KoopaCatchupAgility", LVT_F32, offsetof(struct BehaviorValues, KoopaCatchupAgility), false, LOT_NONE }, { "KoopaThiAgility", LVT_F32, offsetof(struct BehaviorValues, KoopaThiAgility), false, LOT_NONE }, + { "MarioRaycastSteps", LVT_U8, offsetof(struct BehaviorValues, MarioRaycastSteps), false, LOT_NONE }, { "MipsStar1Requirement", LVT_S16, offsetof(struct BehaviorValues, MipsStar1Requirement), false, LOT_NONE }, { "MipsStar2Requirement", LVT_S16, offsetof(struct BehaviorValues, MipsStar2Requirement), false, LOT_NONE }, { "MultipleCapCollection", LVT_U8, offsetof(struct BehaviorValues, MultipleCapCollection), false, LOT_NONE }, diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index 2ffbdc937..7968d038b 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -2870,11 +2870,11 @@ char gSmluaConstants[] = "" "AIR_STEP_GRABBED_LEDGE = STEP_GRAB_LEDGE\n" "AIR_STEP_GRABBED_CEILING = STEP_GRAB_CEILING\n" "AIR_STEP_HIT_LAVA_WALL = STEP_HIT_LAVA\n" -"WATER_STEP_NONE = 0\n" -"WATER_STEP_HIT_FLOOR = 1\n" -"WATER_STEP_HIT_CEILING = 2\n" +"WATER_STEP_NONE = STEP_IN_AIR\n" +"WATER_STEP_HIT_FLOOR = STEP_ON_GROUND\n" +"WATER_STEP_HIT_CEILING = STEP_HIT_CEILING\n" "WATER_STEP_CANCELLED = 3\n" -"WATER_STEP_HIT_WALL = 4\n" +"WATER_STEP_HIT_WALL = STEP_HIT_WALL\n" "STEP_TYPE_GROUND = 1\n" "STEP_TYPE_AIR = 2\n" "STEP_TYPE_WATER = 3\n" @@ -3247,7 +3247,6 @@ char gSmluaConstants[] = "" "ACTION_HOOK_EVERY_FRAME = 0\n" "ACTION_HOOK_GRAVITY = 1\n" "ACTION_HOOK_MAX = 2\n" -"MAX_HOOKED_MOD_MENU_ELEMENTS = 256\n" "MOD_MENU_ELEMENT_BUTTON = 0\n" "MOD_MENU_ELEMENT_CHECKBOX = 1\n" "MOD_MENU_ELEMENT_SLIDER = 2\n" From 53e5685543510b714e36303c7cf0691a27ecad55 Mon Sep 17 00:00:00 2001 From: Prince Frizzy Date: Thu, 21 Nov 2024 20:06:32 -0500 Subject: [PATCH 6/6] Fix some issues --- include/sm64.h | 14 +++--- src/game/hardcoded.c | 1 + src/game/hardcoded.h | 1 + src/game/mario_step.c | 30 +++++++------ src/game/mario_step_new.c | 94 ++++++++++++++++++++++++--------------- 5 files changed, 85 insertions(+), 55 deletions(-) diff --git a/include/sm64.h b/include/sm64.h index 75fd22640..b13a7e911 100644 --- a/include/sm64.h +++ b/include/sm64.h @@ -69,10 +69,12 @@ #define STEP_IN_AIR 0 #define STEP_ON_GROUND 1 #define STEP_HIT_WALL 2 -#define STEP_GRAB_LEDGE 3 -#define STEP_GRAB_CEILING 4 -#define STEP_HIT_LAVA 5 -#define STEP_HIT_CEILING 6 +#define STEP_HIT_WALL_CONTINUE 3 +#define STEP_HIT_CEILING 3 +#define STEP_GRAB_LEDGE 5 +#define STEP_GRAB_CEILING 6 +#define STEP_HIT_LAVA 7 +#define STEP_CANCEL 8 #define STEP_CHECK_LEDGE_GRAB 0x00000001 #define STEP_CHECK_HANG 0x00000002 @@ -83,7 +85,7 @@ #define GROUND_STEP_NONE STEP_ON_GROUND #define GROUND_STEP_HIT_WALL STEP_HIT_WALL #define GROUND_STEP_HIT_WALL_STOP_QSTEPS STEP_HIT_CEILING -#define GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS 3 +#define GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS STEP_HIT_WALL_CONTINUE #define AIR_STEP_CHECK_LEDGE_GRAB STEP_CHECK_LEDGE_GRAB #define AIR_STEP_CHECK_HANG STEP_CHECK_HANG @@ -98,7 +100,7 @@ #define WATER_STEP_NONE STEP_IN_AIR #define WATER_STEP_HIT_FLOOR STEP_ON_GROUND #define WATER_STEP_HIT_CEILING STEP_HIT_CEILING -#define WATER_STEP_CANCELLED 3 +#define WATER_STEP_CANCELLED STEP_CANCEL #define WATER_STEP_HIT_WALL STEP_HIT_WALL #define STEP_TYPE_GROUND 1 diff --git a/src/game/hardcoded.c b/src/game/hardcoded.c index f8db1ce56..609f03426 100644 --- a/src/game/hardcoded.c +++ b/src/game/hardcoded.c @@ -47,6 +47,7 @@ struct LevelValues gDefaultLevelValues = { .fixCollisionBugs = FALSE, .fixCollisionBugsRoundedCorners = TRUE, .fixCollisionBugsFalseLedgeGrab = TRUE, + .fixCollisionBugsClipLedgeGrabs = TRUE, .fixCollisionBugsGroundPoundBonks = TRUE, .fixCollisionBugsPickBestWall = TRUE, .fixVanishFloors = FALSE, diff --git a/src/game/hardcoded.h b/src/game/hardcoded.h index a2d99858a..f2ae26cbc 100644 --- a/src/game/hardcoded.h +++ b/src/game/hardcoded.h @@ -43,6 +43,7 @@ struct LevelValues { u8 fixCollisionBugs; u8 fixCollisionBugsRoundedCorners; u8 fixCollisionBugsFalseLedgeGrab; + u8 fixCollisionBugsClipLedgeGrabs; u8 fixCollisionBugsGroundPoundBonks; u8 fixCollisionBugsPickBestWall; u8 fixVanishFloors; diff --git a/src/game/mario_step.c b/src/game/mario_step.c index 613144b80..d8d5953ba 100644 --- a/src/game/mario_step.c +++ b/src/game/mario_step.c @@ -423,18 +423,12 @@ s32 perform_ground_step(struct MarioState *m) { } u32 check_ledge_grab(struct MarioState *m, struct Surface *wall, Vec3f intendedPos, Vec3f nextPos) { - if (!m) { return 0; } - struct Surface *ledgeFloor; - Vec3f ledgePos; - f32 displacementX; - f32 displacementZ; - - if (m->vel[1] > 0) { + if (!m || m->vel[1] > 0 || wall == NULL) { return FALSE; } - displacementX = nextPos[0] - intendedPos[0]; - displacementZ = nextPos[2] - intendedPos[2]; + f32 displacementX = nextPos[0] - intendedPos[0]; + f32 displacementZ = nextPos[2] - intendedPos[2]; // Only ledge grab if the wall displaced Mario in the opposite direction of // his velocity. @@ -444,16 +438,26 @@ u32 check_ledge_grab(struct MarioState *m, struct Surface *wall, Vec3f intendedP //! Since the search for floors starts at y + m->marioObj->hitboxHeight (160.0f), we will sometimes grab // a higher ledge than expected (glitchy ledge grab) + struct Surface *ledgeFloor = NULL; + Vec3f ledgePos; ledgePos[0] = nextPos[0] - wall->normal.x * 60.0f; ledgePos[2] = nextPos[2] - wall->normal.z * 60.0f; ledgePos[1] = find_floor(ledgePos[0], nextPos[1] + m->marioObj->hitboxHeight, ledgePos[2], &ledgeFloor); if (!ledgeFloor) { return FALSE; } - if (gLevelValues.fixCollisionBugs && gLevelValues.fixCollisionBugsFalseLedgeGrab) { - // fix false ledge grabs - if (!ledgeFloor || ledgeFloor->normal.y < 0.90630779f) { - return FALSE; + if (gLevelValues.fixCollisionBugs) { + if (gLevelValues.fixCollisionBugsFalseLedgeGrab) { + // fix false ledge grabs + if (!ledgeFloor || ledgeFloor->normal.y < 0.90630779f) { + return FALSE; + } + } + + if (gLevelValues.fixCollisionBugsClipLedgeGrabs) { + if (ledgePos[1] - nextPos[1] <= 80.0f - m->vel[1]) { + return FALSE; + } } } diff --git a/src/game/mario_step_new.c b/src/game/mario_step_new.c index 548c18a5d..341be70f1 100644 --- a/src/game/mario_step_new.c +++ b/src/game/mario_step_new.c @@ -28,9 +28,23 @@ // Co-Op Additions: // 1. Smart Ledge Grabs - No longer can grab through floors. -u32 CheckLedgeGrab(struct MarioState *m, Vec3f intendedPos, Vec3f nextPos) { - if (!m || m->vel[1] > 0.0f) { - return FALSE; +#define hdot(x1, x2, z1, z2) ((x1 * x2) + (z1 * z2)) +#define hdot_surf(surf, vec) hdot((surf)->normal.x, (vec)[0], (surf)->normal.z, (vec)[2]) + +u32 CheckLedgeGrab(struct MarioState *m, struct Surface *prevWall, struct Surface *wall, Vec3f intendedPos, Vec3f nextPos) { + struct Surface *ledgeWall = wall; + + if (!m || m->vel[1] > 0 || wall == NULL) { + return FALSE; + } + + if (prevWall == NULL) { + prevWall = wall; + } else { + // Return the already grabbed wall if Mario is moving into it more than the newly tested wall. + if (hdot_surf(prevWall, m->vel) < hdot_surf(wall, m->vel)) { + ledgeWall = prevWall; + } } f32 displacementX = nextPos[0] - intendedPos[0]; @@ -38,46 +52,59 @@ u32 CheckLedgeGrab(struct MarioState *m, Vec3f intendedPos, Vec3f nextPos) { // Only ledge grab if the wall displaced Mario in the opposite direction of // his velocity. - if (displacementX * m->vel[0] + displacementZ * m->vel[2] > 0.0f) { + if (hdot(displacementX, m->vel[0], displacementZ, m->vel[2]) > 0.0f) { return FALSE; } + //! Since the search for floors starts at y + m->marioObj->hitboxHeight (160.0f), we will sometimes grab + // a higher ledge than expected (glitchy ledge grab) struct Surface *ledgeFloor = NULL; Vec3f ledgePos; - ledgePos[0] = nextPos[0] - m->wall->normal.x * 60.0f; - ledgePos[2] = nextPos[2] - m->wall->normal.z * 60.0f; + ledgePos[0] = nextPos[0] - ledgeWall->normal.x * 60.0f; + ledgePos[2] = nextPos[2] - ledgeWall->normal.z * 60.0f; ledgePos[1] = find_floor(ledgePos[0], nextPos[1] + m->marioObj->hitboxHeight, ledgePos[2], &ledgeFloor); - if (!ledgeFloor || ledgePos[1] - nextPos[1] <= 100.0f) { - return FALSE; - } - - if (gLevelValues.fixCollisionBugs && gLevelValues.fixCollisionBugsFalseLedgeGrab) { - // fix false ledge grabs - if (ledgeFloor->normal.y < 0.90630779f) { - return FALSE; + if (!ledgeFloor) { return FALSE; } + + if (gLevelValues.fixCollisionBugs) { + if (gLevelValues.fixCollisionBugsFalseLedgeGrab) { + // fix false ledge grabs + if (!ledgeFloor || ledgeFloor->normal.y < 0.90630779f) { + return FALSE; + } + } + + if (gLevelValues.fixCollisionBugsClipLedgeGrabs) { + if (ledgePos[1] - nextPos[1] <= 80.0f - m->vel[1]) { + return FALSE; + } + + // We'll cast a ray from the top of our height to the ledge grab position. + // If we hit a surface. We aren't allowed to ledge grab. + struct Surface *hitSurface = NULL; + Vec3f HitPos; + + nextPos[1] += m->marioObj->hitboxHeight; + find_surface_on_ray(nextPos, ledgePos, &hitSurface, HitPos, 8.f); + nextPos[1] -= m->marioObj->hitboxHeight; + + // Don't grab the ledge if collision was found, and it's not the wall we wish to grab. + if (hitSurface && hitSurface != m->wall) { return FALSE; } } } - - // We'll cast a ray from the top of our height to the ledge grab position. - // If we hit a surface. We aren't allowed to ledge grab. - struct Surface *hitSurface = NULL; - Vec3f HitPos; - - nextPos[1] += m->marioObj->hitboxHeight; - find_surface_on_ray(nextPos, ledgePos, &hitSurface, HitPos, 8.f); - nextPos[1] -= m->marioObj->hitboxHeight; - // Don't grab the ledge if collision was found, and it's not the wall we wish to grab. - if (hitSurface && hitSurface != m->wall) { return FALSE; } + if (ledgePos[1] - nextPos[1] <= 100.0f) { + return FALSE; + } vec3f_copy(m->pos, ledgePos); m->floor = ledgeFloor; m->floorHeight = ledgePos[1]; + m->floorAngle = atan2s(ledgeFloor->normal.z, ledgeFloor->normal.x); m->faceAngle[0] = 0; - m->faceAngle[1] = atan2s(m->wall->normal.z, m->wall->normal.x) + 0x8000; + m->faceAngle[1] = atan2s(ledgeWall->normal.z, ledgeWall->normal.x) + 0x8000; return TRUE; } @@ -121,14 +148,11 @@ void CheckMoveEndPosition(struct MarioState *m, struct MoveData *MoveResult) { // Don't clip if no collision was found. if (MoveResult->HitSurface == NULL) { return; } - //LOG_DEBUG("%f", (MoveResult->HitSurface)->normal.y); - - /* // Check for around ~cos(72.49 deg), If we as steep or any steeper. // We want to reject movement up/into the slope. if (absf((MoveResult->HitSurface)->normal.y) <= WALLMAXNORMAL) { const f32 DistanceMoved = sqrtf(sqr(HitPos[0] - MoveResult->IntendedPos[0]) + - sqr(HitPos[1] - - MoveResult->MarioHeight / 2 - MoveResult->IntendedPos[1]) + + sqr(HitPos[1] - MoveResult->MarioHeight / 2 - MoveResult->IntendedPos[1]) + sqr(HitPos[2] - MoveResult->IntendedPos[2])); // Move back either by as wide as Mario is or the whole distance, Whatever is less. @@ -137,10 +161,7 @@ void CheckMoveEndPosition(struct MarioState *m, struct MoveData *MoveResult) { MoveResult->IntendedPos[0] = HitPos[0] - MoveVector[0] * MoveBackScale; MoveResult->IntendedPos[1] = HitPos[1] - MoveVector[1] * MoveBackScale - MoveResult->MarioHeight / 2; MoveResult->IntendedPos[2] = HitPos[2] - MoveVector[2] * MoveBackScale; - } - */ - - if ((MoveResult->HitSurface)->normal.y < 0.f) { + } else if ((MoveResult->HitSurface)->normal.y < 0.f) { // Let the binary search find a good position towards Mario's direction. MoveResult->IntendedPos[0] = HitPos[0] + MoveResult->HitSurface->normal.x; MoveResult->IntendedPos[1] = HitPos[1] + MoveResult->HitSurface->normal.y - MoveResult->MarioHeight / 2; @@ -251,16 +272,17 @@ s32 FinishMove(struct MarioState *m, struct MoveData *MoveResult) { } for (u8 i = 0; i < MoveResult->WallCDs.numWalls; i++) { + struct Surface *prevWall = m->wall; m->wall = MoveResult->WallCDs.walls[i]; if (m->wall->type == SURFACE_BURNING) { return STEP_HIT_LAVA; } - if (MoveResult->StepArgs & STEP_CHECK_LEDGE_GRAB && CheckLedgeGrab(m, MoveResult->GoalPos, MoveResult->IntendedPos)) { + if (MoveResult->StepArgs & STEP_CHECK_LEDGE_GRAB && CheckLedgeGrab(m, prevWall, m->wall, MoveResult->GoalPos, MoveResult->IntendedPos)) { return STEP_GRAB_LEDGE; } - + u16 WallAngleMaxDiff = MoveResult->StepArgs & STEP_SNAP_TO_FLOOR ? 0x8000 - MAX_ANGLE_DIFF_FOR_WALL_COLLISION_ON_GROUND : 0x8000 - MAX_ANGLE_DIFF_FOR_WALL_COLLISION_IN_AIR;