mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-22 03:55:11 +00:00
Give Lua mods access to a form of level script preprocessing (#258)
* Give Lua mods access to a form of level script preprocessing * Disable acts setting
This commit is contained in:
parent
3283ec9950
commit
0b6f0dcf0e
12 changed files with 161 additions and 6 deletions
|
@ -214,3 +214,10 @@ end
|
|||
function djui_hud_render_texture_tile_interpolated(texInfo, prevX, prevY, prevScaleW, prevScaleH, x, y, scaleW, scaleH, tileX, tileY, tileW, tileH)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param levelNum number
|
||||
--- @param func fun(areaNum:number, bhv:table)
|
||||
--- @return nil
|
||||
function level_script_parse(levelNum, func)
|
||||
-- ...
|
||||
end
|
||||
|
|
|
@ -629,6 +629,7 @@
|
|||
--- @class LevelValues
|
||||
--- @field public cellHeightLimit integer
|
||||
--- @field public coinsRequiredForCoinStar integer
|
||||
--- @field public disableActs boolean
|
||||
--- @field public entryLevel LevelNum
|
||||
--- @field public exitCastleArea integer
|
||||
--- @field public exitCastleLevel LevelNum
|
||||
|
|
|
@ -57,6 +57,10 @@ void dynos_add_level(s32 modIndex, const char *filePath, const char* levelName);
|
|||
const char* dynos_level_get_token(u32 index);
|
||||
Trajectory* dynos_level_get_trajectory(const char* name);
|
||||
void dynos_level_load_background(void *ptr);
|
||||
u64 dynos_level_cmd_get(void *cmd, u64 offset);
|
||||
void dynos_level_cmd_next(void *cmd, u64 cmdsize);
|
||||
void dynos_level_parse_script(const void *script, s32 (*aPreprocessFunction)(u8, void *));
|
||||
void* dynos_level_get_script(s32 level);
|
||||
|
||||
// -- behaviors -- //
|
||||
void dynos_add_behavior(s32 modIndex, const char *filePath, const char *behaviorName);
|
||||
|
|
|
@ -822,6 +822,9 @@ const u8 *DynOS_Level_GetAreaName(s32 aLevel, s32 aArea, bool aDecaps);
|
|||
s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, u8 aWarpId);
|
||||
s16 *DynOS_Level_GetWarpEntry(s32 aLevel, s32 aArea);
|
||||
s16 *DynOS_Level_GetWarpDeath(s32 aLevel, s32 aArea);
|
||||
u64 DynOS_Level_CmdGet(void *aCmd, u64 aOffset);
|
||||
void *DynOS_Level_CmdNext(void *aCmd, u64 aCmdSize);
|
||||
void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *));
|
||||
|
||||
//
|
||||
// Warps
|
||||
|
|
|
@ -179,6 +179,22 @@ void dynos_level_load_background(void *ptr) {
|
|||
DynOS_Lvl_LoadBackground(ptr);
|
||||
}
|
||||
|
||||
u64 dynos_level_cmd_get(void *cmd, u64 offset) {
|
||||
return DynOS_Level_CmdGet(cmd, offset);
|
||||
}
|
||||
|
||||
void dynos_level_cmd_next(void *cmd, u64 cmdsize) {
|
||||
DynOS_Level_CmdNext(cmd, cmdsize);
|
||||
}
|
||||
|
||||
void dynos_level_parse_script(const void *script, s32 (*aPreprocessFunction)(u8, void *)) {
|
||||
DynOS_Level_ParseScript(script, aPreprocessFunction);
|
||||
}
|
||||
|
||||
void* dynos_level_get_script(s32 level) {
|
||||
return (void *) DynOS_Level_GetScript(level);
|
||||
}
|
||||
|
||||
// -- Behaviors -- //
|
||||
|
||||
void dynos_add_behavior(s32 modIndex, const char *filePath, const char *behaviorName) {
|
||||
|
|
|
@ -51,17 +51,17 @@ static void *sDynosLevelScriptsOriginal[LEVEL_COUNT] = { NULL };
|
|||
static Array<DynosWarp> sDynosLevelWarps[LEVEL_COUNT] = { Array<DynosWarp>() };
|
||||
static Array<s32> sDynosLevelList = Array<s32>(); // Ordered by Course Id, COURSE_NONE excluded
|
||||
|
||||
static u64 DynOS_Level_CmdGet(void *aCmd, u64 aOffset) {
|
||||
u64 DynOS_Level_CmdGet(void *aCmd, u64 aOffset) {
|
||||
u64 _Offset = (((aOffset) & 3llu) | (((aOffset) & ~3llu) << (sizeof(void *) >> 3llu)));
|
||||
return *((u64 *) (u64(aCmd) + _Offset));
|
||||
}
|
||||
|
||||
static void *DynOS_Level_CmdNext(void *aCmd, u64 aCmdSize) {
|
||||
void *DynOS_Level_CmdNext(void *aCmd, u64 aCmdSize) {
|
||||
u64 _Offset = (((aCmdSize) & 3llu) | (((aCmdSize) & ~3llu) << (sizeof(void *) >> 3llu)));
|
||||
return (void *) (u64(aCmd) + _Offset);
|
||||
}
|
||||
|
||||
static void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *));
|
||||
void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *));
|
||||
|
||||
//
|
||||
// Init
|
||||
|
@ -752,7 +752,7 @@ static LvlCmd *DynOS_Level_CmdJumpArea(Stack &aStack, LvlCmd *aCmd, s32 (*aPrepr
|
|||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *)) {
|
||||
void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *)) {
|
||||
Stack _Stack;
|
||||
_Stack.mBaseIndex = -1;
|
||||
_Stack.mTopIndex = 0;
|
||||
|
|
|
@ -924,6 +924,7 @@
|
|||
| ----- | ---- | ------ |
|
||||
| cellHeightLimit | `integer` | |
|
||||
| coinsRequiredForCoinStar | `integer` | |
|
||||
| disableActs | `boolean` | |
|
||||
| entryLevel | [enum LevelNum](constants.md#enum-LevelNum) | |
|
||||
| exitCastleArea | `integer` | |
|
||||
| exitCastleLevel | [enum LevelNum](constants.md#enum-LevelNum) | |
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "src/pc/lua/utils/smlua_model_utils.h"
|
||||
#include "src/pc/lua/smlua.h"
|
||||
#include "src/pc/djui/djui.h"
|
||||
#include "game/hardcoded.h"
|
||||
|
||||
#define CMD_GET(type, offset) (*(type *) (CMD_PROCESS_OFFSET(offset) + (u8 *) sCurrentCmd))
|
||||
|
||||
|
@ -506,7 +507,7 @@ static void level_cmd_place_object(void) {
|
|||
u16 model;
|
||||
struct SpawnInfo *spawnInfo;
|
||||
|
||||
if (sCurrAreaIndex != -1 && ((CMD_GET(u8, 2) & val7) || CMD_GET(u8, 2) == 0x1F)) {
|
||||
if (sCurrAreaIndex != -1 && (gLevelValues.disableActs || (CMD_GET(u8, 2) & val7) || CMD_GET(u8, 2) == 0x1F)) {
|
||||
model = CMD_GET(u8, 3);
|
||||
spawnInfo = alloc_only_pool_alloc(sLevelPool, sizeof(struct SpawnInfo));
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ struct LevelValues gDefaultLevelValues = {
|
|||
.floorLowerLimit = FLOOR_LOWER_LIMIT,
|
||||
.floorLowerLimitMisc = FLOOR_LOWER_LIMIT_MISC,
|
||||
.floorLowerLimitShadow = FLOOR_LOWER_LIMIT_SHADOW,
|
||||
.disableActs = false,
|
||||
};
|
||||
|
||||
struct LevelValues gLevelValues = { 0 };
|
||||
|
|
|
@ -62,6 +62,7 @@ struct LevelValues {
|
|||
s16 floorLowerLimit;
|
||||
s16 floorLowerLimitMisc;
|
||||
s16 floorLowerLimitShadow;
|
||||
bool disableActs;
|
||||
};
|
||||
|
||||
extern struct LevelValues gLevelValues;
|
||||
|
|
|
@ -726,10 +726,11 @@ static struct LuaObjectField sLakituStateFields[LUA_LAKITU_STATE_FIELD_COUNT] =
|
|||
{ "yaw", LVT_S16, offsetof(struct LakituState, yaw), false, LOT_NONE },
|
||||
};
|
||||
|
||||
#define LUA_LEVEL_VALUES_FIELD_COUNT 24
|
||||
#define LUA_LEVEL_VALUES_FIELD_COUNT 25
|
||||
static struct LuaObjectField sLevelValuesFields[LUA_LEVEL_VALUES_FIELD_COUNT] = {
|
||||
{ "cellHeightLimit", LVT_S16, offsetof(struct LevelValues, cellHeightLimit), false, LOT_NONE },
|
||||
{ "coinsRequiredForCoinStar", LVT_S16, offsetof(struct LevelValues, coinsRequiredForCoinStar), false, LOT_NONE },
|
||||
{ "disableActs", LVT_BOOL, offsetof(struct LevelValues, disableActs), false, LOT_NONE },
|
||||
{ "entryLevel", LVT_S32, offsetof(struct LevelValues, entryLevel), false, LOT_NONE },
|
||||
{ "exitCastleArea", LVT_S16, offsetof(struct LevelValues, exitCastleArea), false, LOT_NONE },
|
||||
{ "exitCastleLevel", LVT_S32, offsetof(struct LevelValues, exitCastleLevel), false, LOT_NONE },
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "object_fields.h"
|
||||
#include "engine/math_util.h"
|
||||
#include "pc/djui/djui_hud_utils.h"
|
||||
#include "include/level_misc_macros.h"
|
||||
#include "include/macro_presets.h"
|
||||
|
||||
bool smlua_functions_valid_param_count(lua_State* L, int expected) {
|
||||
int top = lua_gettop(L);
|
||||
|
@ -459,6 +461,122 @@ int smlua_func_djui_hud_render_texture_tile_interpolated(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// level script preprocessing //
|
||||
////////////////////////////////
|
||||
|
||||
struct LuaLevelScriptParse {
|
||||
int reference;
|
||||
struct Mod* mod;
|
||||
};
|
||||
|
||||
struct LuaLevelScriptParse sLevelScriptParse = { 0 };
|
||||
|
||||
s32 smlua_func_level_script_parse_callback(u8 type, void *cmd) {
|
||||
if (type != 0x24 && type != 0x39 && type != 0x1F) {
|
||||
return 0;
|
||||
}
|
||||
lua_State* L = gLuaState;
|
||||
if (L == NULL) { return 0; }
|
||||
struct LuaLevelScriptParse* preprocess = &sLevelScriptParse;
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, preprocess->reference);
|
||||
|
||||
if (type == 0x1F) {
|
||||
u8 area = (u8) dynos_level_cmd_get(cmd, 2);
|
||||
lua_pushinteger(L, area);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
if (type == 0x24) {
|
||||
const BehaviorScript *bhv = (const BehaviorScript *) dynos_level_cmd_get(cmd, 20);
|
||||
u32 behaviorArg = (u32) dynos_level_cmd_get(cmd, 16);
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
lua_pushstring(L, "behavior");
|
||||
lua_pushinteger(L, get_id_from_behavior(bhv));
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "behaviorArg");
|
||||
lua_pushinteger(L, behaviorArg);
|
||||
lua_settable(L, -3);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
if (type == 0x39) {
|
||||
MacroObject *data = (MacroObject *) dynos_level_cmd_get(cmd, 4);
|
||||
int i = 0;
|
||||
s32 len = 0;
|
||||
|
||||
lua_newtable(L);
|
||||
int t = lua_gettop(gLuaState);
|
||||
|
||||
lua_newtable(L);
|
||||
int args = lua_gettop(gLuaState);
|
||||
while (data[len++] != MACRO_OBJECT_END()) {
|
||||
s32 presetId = (s32) ((data[len - 1] & 0x1FF) - 0x1F);
|
||||
const BehaviorScript *bhv = (const BehaviorScript *) MacroObjectPresets[presetId].behavior;
|
||||
s32 presetParams = MacroObjectPresets[presetId].param;
|
||||
s32 objParams = (data[4] & 0xFF00) + (presetParams & 0x00FF);
|
||||
u32 behaviorArg = ((objParams & 0x00FF) << 16) + (objParams & 0xFF00);
|
||||
|
||||
lua_pushinteger(L, i);
|
||||
lua_pushinteger(L, get_id_from_behavior(bhv));
|
||||
lua_settable(L, t);
|
||||
|
||||
lua_pushinteger(L, i);
|
||||
lua_pushinteger(L, behaviorArg);
|
||||
lua_settable(L, args);
|
||||
|
||||
i++;
|
||||
len += 4;
|
||||
}
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
// call the callback
|
||||
if (0 != smlua_call_hook(L, 4, 0, 0, preprocess->mod)) {
|
||||
LOG_LUA("Failed to call the callback behaviors: %u", type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void smlua_func_level_script_parse(lua_State* L) {
|
||||
if (!smlua_functions_valid_param_count(L, 2)) { return; }
|
||||
|
||||
lua_Integer levelNum = smlua_to_integer(L, 1);
|
||||
if (!gSmLuaConvertSuccess) {
|
||||
LOG_LUA_LINE("Invalid level script name");
|
||||
return;
|
||||
}
|
||||
|
||||
struct LuaLevelScriptParse* preprocess = &sLevelScriptParse;
|
||||
preprocess->reference = LUA_NOREF;
|
||||
|
||||
lua_pushvalue(L, 2);
|
||||
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
|
||||
if (ref == -1) {
|
||||
LOG_LUA_LINE("Level Script Parse: %lld tried to parse using undefined function", levelNum);
|
||||
return;
|
||||
}
|
||||
|
||||
preprocess->reference = ref;
|
||||
preprocess->mod = gLuaActiveMod;
|
||||
|
||||
void *script = dynos_level_get_script(levelNum);
|
||||
if (script == NULL) {
|
||||
LOG_LUA("Failed to find script: %lld", levelNum);
|
||||
return;
|
||||
}
|
||||
dynos_level_parse_script(script, smlua_func_level_script_parse_callback);
|
||||
}
|
||||
|
||||
//////////
|
||||
// bind //
|
||||
//////////
|
||||
|
@ -482,4 +600,5 @@ void smlua_bind_functions(void) {
|
|||
smlua_bind_function(L, "djui_hud_render_texture_tile", smlua_func_djui_hud_render_texture_tile);
|
||||
smlua_bind_function(L, "djui_hud_render_texture_interpolated", smlua_func_djui_hud_render_texture_interpolated);
|
||||
smlua_bind_function(L, "djui_hud_render_texture_tile_interpolated", smlua_func_djui_hud_render_texture_tile_interpolated);
|
||||
smlua_bind_function(L, "level_script_parse", smlua_func_level_script_parse);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue