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:
Isaac0-dev 2023-01-31 22:24:56 +10:00 committed by GitHub
parent 3283ec9950
commit 0b6f0dcf0e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 161 additions and 6 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -62,6 +62,7 @@ struct LevelValues {
s16 floorLowerLimit;
s16 floorLowerLimitMisc;
s16 floorLowerLimitShadow;
bool disableActs;
};
extern struct LevelValues gLevelValues;

View file

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

View file

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