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

@ -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);

View file

@ -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

@ -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;

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

@ -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);