add cancels to HOOK_BEFORE_PHYS_STEP allowing for custom step systems (#400)

* add cancels to HOOK_BEFORE_PHYS_STEP allowing for custom step systems

* give lua mods access to stepArg and nextPos from hanging and air step; fix a crash when m.floor is null
This commit is contained in:
Isaac0-dev 2023-06-01 14:10:06 +10:00 committed by GitHub
parent aaaf59e1e4
commit 05f4c42f81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 124 additions and 18 deletions

View file

@ -8126,6 +8126,18 @@ PARTICLE_WATER_SPLASH = (1 << 6)
--- @type integer
PARTICLE_WAVE_TRAIL = (1 << 10)
--- @type integer
STEP_TYPE_AIR = 2
--- @type integer
STEP_TYPE_GROUND = 1
--- @type integer
STEP_TYPE_HANG = 4
--- @type integer
STEP_TYPE_WATER = 3
--- @type integer
VALID_BUTTONS = (A_BUTTON | B_BUTTON | Z_TRIG | START_BUTTON | U_JPAD | D_JPAD | L_JPAD | R_JPAD | L_TRIG | R_TRIG | X_BUTTON | Y_BUTTON | U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS )

View file

@ -2894,6 +2894,10 @@
- PARTICLE_VERTICAL_STAR
- PARTICLE_WATER_SPLASH
- PARTICLE_WAVE_TRAIL
- STEP_TYPE_AIR
- STEP_TYPE_GROUND
- STEP_TYPE_HANG
- STEP_TYPE_WATER
- VALID_BUTTONS
- WATER_STEP_CANCELLED
- WATER_STEP_HIT_CEILING

View file

@ -91,7 +91,7 @@ The lua functions sent to `hook_event()` will be automatically called by SM64 wh
| HOOK_MARIO_UPDATE | Called once per player per frame at the end of a mario update | [MarioState](structs.md#MarioState) mario |
| HOOK_BEFORE_MARIO_UPDATE | Called once per player per frame at the beginning of a mario update | [MarioState](structs.md#MarioState) mario |
| HOOK_ON_SET_MARIO_ACTION | Called every time a player's current action is changed | [MarioState](structs.md#MarioState) mario |
| HOOK_BEFORE_PHYS_STEP | Called once per player per frame before physics code is run | [MarioState](structs.md#MarioState) mario |
| HOOK_BEFORE_PHYS_STEP | Called once per player per frame before physics code is run, return an integer to cancel it with your own step result | [MarioState](structs.md#MarioState) mario, `integer` stepType |
| HOOK_ALLOW_PVP_ATTACK | Called when one player attacks another, return `true` to allow the attack | [MarioState](structs.md#MarioState) attacker, [MarioState](structs.md#MarioState) victim |
| HOOK_ON_PVP_ATTACK | Called when one player attacks another | [MarioState](structs.md#MarioState) attacker, [MarioState](structs.md#MarioState) victim |
| HOOK_ON_PLAYER_CONNECTED | Called when a player connects | [MarioState](structs.md#MarioState) connector |

View file

@ -88,6 +88,11 @@
#define WATER_STEP_CANCELLED 3
#define WATER_STEP_HIT_WALL 4
#define STEP_TYPE_GROUND 1
#define STEP_TYPE_AIR 2
#define STEP_TYPE_WATER 3
#define STEP_TYPE_HANG 4
#define PARTICLE_DUST /* 0x00000001 */ (1 << 0)
#define PARTICLE_VERTICAL_STAR /* 0x00000002 */ (1 << 1)
#define PARTICLE_2 /* 0x00000004 */ (1 << 2)

View file

@ -631,7 +631,7 @@ struct Surface *resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 ra
if (find_wall_collisions(&collisionData)) {
wall = collisionData.walls[collisionData.numWalls - 1];
}
// I'm not sure if this code is actually ever used or not.
pos[0] = collisionData.x;
pos[1] = collisionData.y;
@ -1143,7 +1143,7 @@ u32 set_mario_action(struct MarioState *m, u32 action, u32 actionArg) {
u32 returnValue = 0;
smlua_call_event_hooks_mario_action_params_ret_int(HOOK_BEFORE_SET_MARIO_ACTION, m, action, &returnValue);
if (returnValue == 1) { return TRUE; } else if (returnValue) { action = returnValue; }
switch (action & ACT_GROUP_MASK) {
case ACT_GROUP_MOVING:
action = set_mario_action_moving(m, action, actionArg);
@ -2187,14 +2187,14 @@ s32 execute_mario_action(UNUSED struct Object *o) {
// Both of the wind handling portions play wind audio only in
// non-Japanese releases.
extern bool gDjuiInMainMenu;
if (gMarioState->floor->type == SURFACE_HORIZONTAL_WIND && !gDjuiInMainMenu) {
if (gMarioState->floor && gMarioState->floor->type == SURFACE_HORIZONTAL_WIND && !gDjuiInMainMenu) {
spawn_wind_particles(0, (gMarioState->floor->force << 8));
#ifndef VERSION_JP
play_sound(SOUND_ENV_WIND2, gMarioState->marioObj->header.gfx.cameraToObject);
#endif
}
if (gMarioState->floor->type == SURFACE_VERTICAL_WIND) {
if (gMarioState->floor && gMarioState->floor->type == SURFACE_VERTICAL_WIND) {
spawn_wind_particles(1, 0);
#ifndef VERSION_JP
play_sound(SOUND_ENV_WIND2, gMarioState->marioObj->header.gfx.cameraToObject);
@ -2240,7 +2240,7 @@ void init_single_mario(struct MarioState* m) {
m->invincTimer = 0;
m->visibleToEnemies = TRUE;
if (m->cap & (SAVE_FLAG_CAP_ON_GROUND | SAVE_FLAG_CAP_ON_KLEPTO | SAVE_FLAG_CAP_ON_UKIKI | SAVE_FLAG_CAP_ON_MR_BLIZZARD)) {
m->flags = 0;
} else {

View file

@ -69,7 +69,7 @@ void play_climbing_sounds(struct MarioState *m, s32 b) {
s32 set_pole_position(struct MarioState *m, f32 offsetY) {
if (!m) { return 0; }
if (m->usedObj == NULL) { m->usedObj = cur_obj_find_nearest_pole(); }
// This is here so if somehow a pole despawns while you are on it.
// You will just drop from it.
if (m->usedObj == NULL) {
@ -340,7 +340,8 @@ s32 perform_hanging_step(struct MarioState *m, Vec3f nextPos) {
f32 floorHeight;
f32 ceilOffset;
smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, m);
s32 returnValue = 0;
if (smlua_call_event_hooks_mario_param_and_int_ret_int(HOOK_BEFORE_PHYS_STEP, m, STEP_TYPE_HANG, &returnValue)) return returnValue;
if (gServerSettings.enableCheats && gCheats.superSpeed && m->playerIndex == 0) {
m->vel[0] *= SUPER_SPEED_MULTIPLIER;

View file

@ -26,9 +26,9 @@
#define MIN_SWIM_STRENGTH 160
#define MIN_SWIM_SPEED 16.0f
static s16 sWasAtSurface[MAX_PLAYERS] = { FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE,
static s16 sWasAtSurface[MAX_PLAYERS] = { FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE };
static s16 sSwimStrength[MAX_PLAYERS] = { MIN_SWIM_STRENGTH, MIN_SWIM_STRENGTH, MIN_SWIM_STRENGTH, MIN_SWIM_STRENGTH,
MIN_SWIM_STRENGTH, MIN_SWIM_STRENGTH, MIN_SWIM_STRENGTH, MIN_SWIM_STRENGTH,
@ -192,7 +192,8 @@ u32 perform_water_step(struct MarioState *m) {
Vec3f step;
struct Object *marioObj = m->marioObj;
smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, m);
s32 returnValue = 0;
if (smlua_call_event_hooks_mario_param_and_int_ret_int(HOOK_BEFORE_PHYS_STEP, m, STEP_TYPE_WATER, &returnValue)) return (u32) returnValue;
if (gServerSettings.enableCheats && gCheats.superSpeed && m->playerIndex == 0) {
m->vel[0] *= SUPER_SPEED_MULTIPLIER;
@ -552,7 +553,7 @@ static s32 check_water_jump(struct MarioState *m) {
static s32 act_breaststroke(struct MarioState *m) {
if (!m) { return 0; }
u16 pIndex = m->playerIndex;
if (m->actionArg == 0) {
sSwimStrength[pIndex] = MIN_SWIM_STRENGTH;
}
@ -613,7 +614,7 @@ static s32 act_breaststroke(struct MarioState *m) {
static s32 act_swimming_end(struct MarioState *m) {
if (!m) { return 0; }
u16 pIndex = m->playerIndex;
if (m->flags & MARIO_METAL_CAP) {
return set_mario_action(m, ACT_METAL_WATER_FALLING, 1);
}
@ -653,7 +654,7 @@ static s32 act_swimming_end(struct MarioState *m) {
static s32 act_flutter_kick(struct MarioState *m) {
if (!m) { return 0; }
u16 pIndex = m->playerIndex;
if (m->flags & MARIO_METAL_CAP) {
return set_mario_action(m, ACT_METAL_WATER_FALLING, 1);
}

View file

@ -350,7 +350,8 @@ s32 perform_ground_step(struct MarioState *m) {
u32 stepResult;
Vec3f intendedPos;
smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, 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;
if (gServerSettings.enableCheats && gCheats.superSpeed && m->playerIndex == 0 && m->action != ACT_BUBBLED) {
m->vel[0] *= SUPER_SPEED_MULTIPLIER;
@ -708,7 +709,8 @@ s32 perform_air_step(struct MarioState *m, u32 stepArg) {
s32 quarterStepResult;
s32 stepResult = AIR_STEP_NONE;
smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, m);
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;
if (gServerSettings.enableCheats && gCheats.superSpeed && m->playerIndex == 0 && m->action != ACT_BUBBLED) {
m->vel[0] *= SUPER_SPEED_MULTIPLIER;

View file

@ -2582,6 +2582,10 @@ char gSmluaConstants[] = ""
"WATER_STEP_HIT_CEILING = 2\n"
"WATER_STEP_CANCELLED = 3\n"
"WATER_STEP_HIT_WALL = 4\n"
"STEP_TYPE_GROUND = 1\n"
"STEP_TYPE_AIR = 2\n"
"STEP_TYPE_WATER = 3\n"
"STEP_TYPE_HANG = 4\n"
"PARTICLE_DUST = (1 << 0)\n"
"PARTICLE_VERTICAL_STAR = (1 << 1)\n"
"PARTICLE_2 = (1 << 2)\n"

View file

@ -677,7 +677,7 @@ bool smlua_call_event_hooks_mario_character_sound_param_ret_int(enum LuaHookedEv
lua_pushinteger(L, m->playerIndex);
lua_gettable(L, -2);
lua_remove(L, -2);
// push character sound
lua_pushinteger(L, characterSound);
@ -765,6 +765,81 @@ void smlua_call_event_hooks_mario_param_and_int_ret_bool(enum LuaHookedEventType
}
}
bool smlua_call_event_hooks_mario_param_and_int_ret_int(enum LuaHookedEventType hookType, struct MarioState* m, s32 param, s32* returnValue) {
lua_State* L = gLuaState;
if (L == NULL) { return false; }
struct LuaHookedEvent* hook = &sHookedEvents[hookType];
for (int i = 0; i < hook->count; i++) {
s32 prevTop = lua_gettop(L);
// push the callback onto the stack
lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
// push mario state
lua_getglobal(L, "gMarioStates");
lua_pushinteger(L, m->playerIndex);
lua_gettable(L, -2);
lua_remove(L, -2);
// push param
lua_pushinteger(L, param);
// call the callback
if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i])) {
LOG_LUA("Failed to call the callback: %u", hookType);
continue;
}
// output the return value
if (lua_type(L, -1) == LUA_TNUMBER) {
*returnValue = smlua_to_integer(L, -1);
lua_settop(L, prevTop);
return true;
}
lua_settop(L, prevTop);
}
return false;
}
bool smlua_call_event_hooks_mario_param_and_int_and_int_ret_int(enum LuaHookedEventType hookType, struct MarioState* m, s32 param, u32 args, s32* returnValue) {
lua_State* L = gLuaState;
if (L == NULL) { return false; }
struct LuaHookedEvent* hook = &sHookedEvents[hookType];
for (int i = 0; i < hook->count; i++) {
s32 prevTop = lua_gettop(L);
// push the callback onto the stack
lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
// push mario state
lua_getglobal(L, "gMarioStates");
lua_pushinteger(L, m->playerIndex);
lua_gettable(L, -2);
lua_remove(L, -2);
// push param
lua_pushinteger(L, param);
// push args
lua_pushinteger(L, args);
// call the callback
if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i])) {
LOG_LUA("Failed to call the callback: %u", hookType);
continue;
}
// output the return value
if (lua_type(L, -1) == LUA_TNUMBER) {
*returnValue = smlua_to_integer(L, -1);
lua_settop(L, prevTop);
return true;
}
lua_settop(L, prevTop);
}
return false;
}
////////////////////
// hooked actions //
////////////////////

View file

@ -122,6 +122,8 @@ void smlua_call_event_hooks_on_chat_message(enum LuaHookedEventType hookType, st
bool smlua_call_event_hooks_mario_character_sound_param_ret_int(enum LuaHookedEventType hookType, struct MarioState* m, enum CharacterSound characterSound, s32* returnValue);
void smlua_call_event_hooks_mario_action_params_ret_int(enum LuaHookedEventType hookType, struct MarioState *m, u32 action, u32* returnValue);
void smlua_call_event_hooks_mario_param_and_int_ret_bool(enum LuaHookedEventType hookType, struct MarioState* m, s32 param, bool* returnValue);
bool smlua_call_event_hooks_mario_param_and_int_ret_int(enum LuaHookedEventType hookType, struct MarioState* m, s32 param, s32* returnValue);
bool smlua_call_event_hooks_mario_param_and_int_and_int_ret_int(enum LuaHookedEventType hookType, struct MarioState* m, s32 param, u32 args, s32* returnValue);
enum BehaviorId smlua_get_original_behavior_id(const BehaviorScript* behavior);
const BehaviorScript* smlua_override_behavior(const BehaviorScript* behavior);