Added ability to have completely custom levels that don't override anything

This commit is contained in:
MysterD 2022-06-05 21:55:31 -07:00
parent a40c3cf121
commit 946f16329c
28 changed files with 726 additions and 214 deletions

View file

@ -42,6 +42,7 @@ in_files = [
"src/pc/lua/utils/smlua_model_utils.h", "src/pc/lua/utils/smlua_model_utils.h",
"src/pc/lua/utils/smlua_text_utils.h", "src/pc/lua/utils/smlua_text_utils.h",
"src/pc/lua/utils/smlua_audio_utils.h", "src/pc/lua/utils/smlua_audio_utils.h",
"src/pc/lua/utils/smlua_level_utils.h",
"src/game/object_helpers.c", "src/game/object_helpers.c",
"src/game/obj_behaviors.c", "src/game/obj_behaviors.c",
"src/game/obj_behaviors_2.c", "src/game/obj_behaviors_2.c",
@ -88,6 +89,7 @@ override_disallowed_functions = {
"src/game/behavior_actions.h": [ "bhv_dust_smoke_loop", "bhv_init_room" ], "src/game/behavior_actions.h": [ "bhv_dust_smoke_loop", "bhv_init_room" ],
"src/pc/lua/utils/smlua_audio_utils.h": [ "smlua_audio_utils_override", "audio_custom_shutdown"], "src/pc/lua/utils/smlua_audio_utils.h": [ "smlua_audio_utils_override", "audio_custom_shutdown"],
"src/pc/djui/djui_hud_utils.h": [ "djui_hud_render_texture", "djui_hud_render_texture_raw" ], "src/pc/djui/djui_hud_utils.h": [ "djui_hud_render_texture", "djui_hud_render_texture_raw" ],
"src/pc/lua/utils/smlua_level_utils.h": [ "smlua_level_util_reset" ],
} }
lua_function_params = { lua_function_params = {

View file

@ -18,6 +18,7 @@ in_files = [
'src/pc/lua/utils/smlua_anim_utils.h', 'src/pc/lua/utils/smlua_anim_utils.h',
'src/pc/lua/utils/smlua_misc_utils.h', 'src/pc/lua/utils/smlua_misc_utils.h',
'src/pc/lua/utils/smlua_collision_utils.h', 'src/pc/lua/utils/smlua_collision_utils.h',
'src/pc/lua/utils/smlua_level_utils.h',
'src/game/spawn_sound.h', 'src/game/spawn_sound.h',
'src/pc/network/network.h', 'src/pc/network/network.h',
'src/game/hardcoded.h', 'src/game/hardcoded.h',

View file

@ -7330,6 +7330,56 @@ function smlua_collision_util_get(name)
-- ... -- ...
end end
--- @param scriptEntryName string
--- @param courseNum integer
--- @param fullName string
--- @param shortName string
--- @param acousticReach integer
--- @param echoLevel1 integer
--- @param echoLevel2 integer
--- @param echoLevel3 integer
--- @return integer
function level_register(scriptEntryName, courseNum, fullName, shortName, acousticReach, echoLevel1, echoLevel2, echoLevel3)
-- ...
end
--- @param levelNum integer
--- @return CustomLevelInfo
function smlua_level_util_get_info(levelNum)
-- ...
end
--- @param shortName string
--- @return CustomLevelInfo
function smlua_level_util_get_info_from_short_name(shortName)
-- ...
end
--- @param aDelay integer
--- @return boolean
function warp_exit_level(aDelay)
-- ...
end
--- @return boolean
function warp_restart_level()
-- ...
end
--- @param aLevel integer
--- @return boolean
function warp_to_castle(aLevel)
-- ...
end
--- @param aLevel integer
--- @param aArea integer
--- @param aAct integer
--- @return boolean
function warp_to_level(aLevel, aArea, aAct)
-- ...
end
--- @param actFlags integer --- @param actFlags integer
--- @return integer --- @return integer
function allocate_mario_action(actFlags) function allocate_mario_action(actFlags)
@ -7593,31 +7643,6 @@ function set_override_near(near)
-- ... -- ...
end end
--- @param aDelay integer
--- @return boolean
function warp_exit_level(aDelay)
-- ...
end
--- @return boolean
function warp_restart_level()
-- ...
end
--- @param aLevel integer
--- @return boolean
function warp_to_castle(aLevel)
-- ...
end
--- @param aLevel integer
--- @param aArea integer
--- @param aAct integer
--- @return boolean
function warp_to_level(aLevel, aArea, aAct)
-- ...
end
--- @param name string --- @param name string
--- @return integer --- @return integer
function smlua_model_util_get_id(name) function smlua_model_util_get_id(name)

View file

@ -327,6 +327,19 @@
--- @field public stickX number --- @field public stickX number
--- @field public stickY number --- @field public stickY number
--- @class CustomLevelInfo
--- @field public acousticReach integer
--- @field public courseNum integer
--- @field public echoLevel1 integer
--- @field public echoLevel2 integer
--- @field public echoLevel3 integer
--- @field public fullName string
--- @field public levelNum integer
--- @field public next CustomLevelInfo
--- @field public script Pointer_LevelScript
--- @field public scriptEntryName string
--- @field public shortName string
--- @class Cutscene --- @class Cutscene
--- @field public duration integer --- @field public duration integer
@ -1777,6 +1790,7 @@
--- @class Pointer_integer --- @class Pointer_integer
--- @class Pointer_Trajectory --- @class Pointer_Trajectory
--- @class Pointer_LevelScript
--- @class Pointer_ObjectAnimPointer --- @class Pointer_ObjectAnimPointer
--- @class Pointer_Collision --- @class Pointer_Collision
--- @class Pointer_BehaviorScript --- @class Pointer_BehaviorScript

View file

@ -17,6 +17,7 @@ s32 dynos_tex_import(void **output, void *ptr, s32 tile, void *grapi, void **h
void dynos_gfx_swap_animations(void *ptr); void dynos_gfx_swap_animations(void *ptr);
// -- warps -- // // -- warps -- //
LevelScript* dynos_get_level_script(char* scriptEntryName);
bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct); bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct);
bool dynos_warp_restart_level(void); bool dynos_warp_restart_level(void);
bool dynos_warp_exit_level(s32 aDelay); bool dynos_warp_exit_level(s32 aDelay);

View file

@ -815,6 +815,7 @@ void DynOS_Tex_ModShutdown();
// //
Array<Pair<const char*, GfxData*>> &DynOS_Lvl_GetArray(); Array<Pair<const char*, GfxData*>> &DynOS_Lvl_GetArray();
LevelScript* DynOS_Lvl_GetScript(char* aScriptEntryName);
void DynOS_Lvl_Activate(s32 modIndex, const SysPath &aFilePath, const char *aLevelName); void DynOS_Lvl_Activate(s32 modIndex, const SysPath &aFilePath, const char *aLevelName);
GfxData* DynOS_Lvl_GetActiveGfx(void); GfxData* DynOS_Lvl_GetActiveGfx(void);
const char* DynOS_Lvl_GetToken(u32 index); const char* DynOS_Lvl_GetToken(u32 index);

View file

@ -30,6 +30,10 @@ void dynos_gfx_swap_animations(void *ptr) {
// -- warps -- // // -- warps -- //
LevelScript* dynos_get_level_script(char* scriptEntryName) {
return DynOS_Lvl_GetScript(scriptEntryName);
}
bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct) { bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct) {
return DynOS_Warp_ToLevel(aLevel, aArea, aAct); return DynOS_Warp_ToLevel(aLevel, aArea, aAct);
} }

View file

@ -3,6 +3,7 @@ extern "C" {
#include "game/segment2.h" #include "game/segment2.h"
#include "game/save_file.h" #include "game/save_file.h"
#include "levels/scripts.h" #include "levels/scripts.h"
#include "pc/lua/utils/smlua_level_utils.h"
} }
// //
@ -198,7 +199,7 @@ static void DynOS_Level_Init() {
for (s32 i = COURSE_MIN; i <= COURSE_MAX; ++i) { for (s32 i = COURSE_MIN; i <= COURSE_MAX; ++i) {
if (i == COURSE_CAKE_END) continue; if (i == COURSE_CAKE_END) continue;
for (s32 j = 1; j != LEVEL_COUNT; ++j) { for (s32 j = 1; j != LEVEL_COUNT; ++j) {
if (gLevelToCourseNumTable[j - 1] == i) { if (get_level_course_num(j - 1) == i) {
sDynosLevelList.Add(j); sDynosLevelList.Add(j);
} }
} }
@ -249,6 +250,12 @@ void DynOS_Level_Unoverride() {
} }
const void *DynOS_Level_GetScript(s32 aLevel) { const void *DynOS_Level_GetScript(s32 aLevel) {
if (aLevel >= CUSTOM_LEVEL_NUM_START) {
struct CustomLevelInfo* info = smlua_level_util_get_info(aLevel);
if (!info || !info->script) { return NULL; }
return info->script;
}
DynOS_Level_Init(); DynOS_Level_Init();
return sDynosLevelScripts[aLevel]; return sDynosLevelScripts[aLevel];
} }
@ -844,6 +851,21 @@ static void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFuncti
// //
s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, u8 aWarpId) { s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, u8 aWarpId) {
if (aLevel >= CUSTOM_LEVEL_NUM_START) {
struct CustomLevelInfo* info = smlua_level_util_get_info(aLevel);
if (!info || !info->script) { return NULL; }
sDynosCurrentLevelNum = 1;
DynOS_Level_ParseScript(info->script, DynOS_Level_PreprocessScript);
for (const auto &_Warp : sDynosLevelWarps[1]) {
if (_Warp.mArea == aArea) {
if (_Warp.mId == aWarpId) {
return (s16 *) &_Warp;
}
}
}
return NULL;
}
DynOS_Level_Init(); DynOS_Level_Init();
for (const auto &_Warp : sDynosLevelWarps[aLevel]) { for (const auto &_Warp : sDynosLevelWarps[aLevel]) {
if (_Warp.mArea == aArea) { if (_Warp.mArea == aArea) {

View file

@ -21,6 +21,19 @@ Array<Pair<const char*, GfxData*>> &DynOS_Lvl_GetArray() {
return sDynosCustomLevelScripts; return sDynosCustomLevelScripts;
} }
LevelScript* DynOS_Lvl_GetScript(char* aScriptEntryName) {
auto& _CustomLevelScripts = DynOS_Lvl_GetArray();
for (s32 i = 0; i < _CustomLevelScripts.Count(); ++i) {
auto& pair = _CustomLevelScripts[i];
if (!strcmp(pair.first, aScriptEntryName)) {
auto& newScripts = pair.second->mLevelScripts;
auto& newScriptNode = newScripts[newScripts.Count() - 1];
return newScriptNode->mData;
}
}
return NULL;
}
void DynOS_Lvl_ModShutdown() { void DynOS_Lvl_ModShutdown() {
DynOS_Level_Unoverride(); DynOS_Level_Unoverride();
@ -66,6 +79,7 @@ void DynOS_Lvl_Activate(s32 modIndex, const SysPath &aFilename, const char *aLev
// Add to levels // Add to levels
_CustomLevelScripts.Add({ levelName, _Node }); _CustomLevelScripts.Add({ levelName, _Node });
DynOS_Tex_Valid(_Node);
// Override vanilla script // Override vanilla script
auto& newScripts = _Node->mLevelScripts; auto& newScripts = _Node->mLevelScripts;
@ -78,7 +92,6 @@ void DynOS_Lvl_Activate(s32 modIndex, const SysPath &aFilename, const char *aLev
DynOS_Level_Override((void*)originalScript, newScriptNode->mData); DynOS_Level_Override((void*)originalScript, newScriptNode->mData);
_OverrideLevelScripts.Add({ originalScript, newScriptNode->mData, _Node}); _OverrideLevelScripts.Add({ originalScript, newScriptNode->mData, _Node});
DynOS_Tex_Valid(_Node);
} }
GfxData* DynOS_Lvl_GetActiveGfx(void) { GfxData* DynOS_Lvl_GetActiveGfx(void) {
@ -170,3 +183,4 @@ void *DynOS_Lvl_Override(void *aCmd) {
} }
return aCmd; return aCmd;
} }

View file

@ -6073,6 +6073,159 @@
<br /> <br />
---
# functions from smlua_level_utils.h
<br />
## [level_register](#level_register)
### Lua Example
`local integerValue = level_register(scriptEntryName, courseNum, fullName, shortName, acousticReach, echoLevel1, echoLevel2, echoLevel3)`
### Parameters
| Field | Type |
| ----- | ---- |
| scriptEntryName | `string` |
| courseNum | `integer` |
| fullName | `string` |
| shortName | `string` |
| acousticReach | `integer` |
| echoLevel1 | `integer` |
| echoLevel2 | `integer` |
| echoLevel3 | `integer` |
### Returns
- `integer`
### C Prototype
`s16 level_register(const char* scriptEntryName, s16 courseNum, const char* fullName, const char* shortName, u32 acousticReach, u32 echoLevel1, u32 echoLevel2, u32 echoLevel3);`
[:arrow_up_small:](#)
<br />
## [smlua_level_util_get_info](#smlua_level_util_get_info)
### Lua Example
`local CustomLevelInfoValue = smlua_level_util_get_info(levelNum)`
### Parameters
| Field | Type |
| ----- | ---- |
| levelNum | `integer` |
### Returns
[CustomLevelInfo](structs.md#CustomLevelInfo)
### C Prototype
`struct CustomLevelInfo* smlua_level_util_get_info(s16 levelNum);`
[:arrow_up_small:](#)
<br />
## [smlua_level_util_get_info_from_short_name](#smlua_level_util_get_info_from_short_name)
### Lua Example
`local CustomLevelInfoValue = smlua_level_util_get_info_from_short_name(shortName)`
### Parameters
| Field | Type |
| ----- | ---- |
| shortName | `string` |
### Returns
[CustomLevelInfo](structs.md#CustomLevelInfo)
### C Prototype
`struct CustomLevelInfo* smlua_level_util_get_info_from_short_name(char* shortName);`
[:arrow_up_small:](#)
<br />
## [warp_exit_level](#warp_exit_level)
### Lua Example
`local booleanValue = warp_exit_level(aDelay)`
### Parameters
| Field | Type |
| ----- | ---- |
| aDelay | `integer` |
### Returns
- `boolean`
### C Prototype
`bool warp_exit_level(s32 aDelay);`
[:arrow_up_small:](#)
<br />
## [warp_restart_level](#warp_restart_level)
### Lua Example
`local booleanValue = warp_restart_level()`
### Parameters
- None
### Returns
- `boolean`
### C Prototype
`bool warp_restart_level(void);`
[:arrow_up_small:](#)
<br />
## [warp_to_castle](#warp_to_castle)
### Lua Example
`local booleanValue = warp_to_castle(aLevel)`
### Parameters
| Field | Type |
| ----- | ---- |
| aLevel | `integer` |
### Returns
- `boolean`
### C Prototype
`bool warp_to_castle(s32 aLevel);`
[:arrow_up_small:](#)
<br />
## [warp_to_level](#warp_to_level)
### Lua Example
`local booleanValue = warp_to_level(aLevel, aArea, aAct)`
### Parameters
| Field | Type |
| ----- | ---- |
| aLevel | `integer` |
| aArea | `integer` |
| aAct | `integer` |
### Returns
- `boolean`
### C Prototype
`bool warp_to_level(s32 aLevel, s32 aArea, s32 aAct);`
[:arrow_up_small:](#)
<br />
--- ---
# functions from smlua_misc_utils.h # functions from smlua_misc_utils.h
@ -6941,86 +7094,6 @@
<br /> <br />
## [warp_exit_level](#warp_exit_level)
### Lua Example
`local booleanValue = warp_exit_level(aDelay)`
### Parameters
| Field | Type |
| ----- | ---- |
| aDelay | `integer` |
### Returns
- `boolean`
### C Prototype
`bool warp_exit_level(s32 aDelay);`
[:arrow_up_small:](#)
<br />
## [warp_restart_level](#warp_restart_level)
### Lua Example
`local booleanValue = warp_restart_level()`
### Parameters
- None
### Returns
- `boolean`
### C Prototype
`bool warp_restart_level(void);`
[:arrow_up_small:](#)
<br />
## [warp_to_castle](#warp_to_castle)
### Lua Example
`local booleanValue = warp_to_castle(aLevel)`
### Parameters
| Field | Type |
| ----- | ---- |
| aLevel | `integer` |
### Returns
- `boolean`
### C Prototype
`bool warp_to_castle(s32 aLevel);`
[:arrow_up_small:](#)
<br />
## [warp_to_level](#warp_to_level)
### Lua Example
`local booleanValue = warp_to_level(aLevel, aArea, aAct)`
### Parameters
| Field | Type |
| ----- | ---- |
| aLevel | `integer` |
| aArea | `integer` |
| aAct | `integer` |
### Returns
- `boolean`
### C Prototype
`bool warp_to_level(s32 aLevel, s32 aArea, s32 aAct);`
[:arrow_up_small:](#)
<br />
--- ---
# functions from smlua_model_utils.h # functions from smlua_model_utils.h

View file

@ -1368,6 +1368,17 @@
<br /> <br />
- smlua_level_utils.h
- [level_register](functions-4.md#level_register)
- [smlua_level_util_get_info](functions-4.md#smlua_level_util_get_info)
- [smlua_level_util_get_info_from_short_name](functions-4.md#smlua_level_util_get_info_from_short_name)
- [warp_exit_level](functions-4.md#warp_exit_level)
- [warp_restart_level](functions-4.md#warp_restart_level)
- [warp_to_castle](functions-4.md#warp_to_castle)
- [warp_to_level](functions-4.md#warp_to_level)
<br />
- smlua_misc_utils.h - smlua_misc_utils.h
- [allocate_mario_action](functions-4.md#allocate_mario_action) - [allocate_mario_action](functions-4.md#allocate_mario_action)
- [camera_config_enable_analog_cam](functions-4.md#camera_config_enable_analog_cam) - [camera_config_enable_analog_cam](functions-4.md#camera_config_enable_analog_cam)
@ -1413,10 +1424,6 @@
- [set_override_far](functions-4.md#set_override_far) - [set_override_far](functions-4.md#set_override_far)
- [set_override_fov](functions-4.md#set_override_fov) - [set_override_fov](functions-4.md#set_override_fov)
- [set_override_near](functions-4.md#set_override_near) - [set_override_near](functions-4.md#set_override_near)
- [warp_exit_level](functions-4.md#warp_exit_level)
- [warp_restart_level](functions-4.md#warp_restart_level)
- [warp_to_castle](functions-4.md#warp_to_castle)
- [warp_to_level](functions-4.md#warp_to_level)
<br /> <br />

View file

@ -16,6 +16,7 @@
- [ChainSegment](#ChainSegment) - [ChainSegment](#ChainSegment)
- [Character](#Character) - [Character](#Character)
- [Controller](#Controller) - [Controller](#Controller)
- [CustomLevelInfo](#CustomLevelInfo)
- [Cutscene](#Cutscene) - [Cutscene](#Cutscene)
- [CutsceneSplinePoint](#CutsceneSplinePoint) - [CutsceneSplinePoint](#CutsceneSplinePoint)
- [CutsceneVariable](#CutsceneVariable) - [CutsceneVariable](#CutsceneVariable)
@ -506,6 +507,26 @@
<br /> <br />
## [CustomLevelInfo](#CustomLevelInfo)
| Field | Type | Access |
| ----- | ---- | ------ |
| acousticReach | `integer` | |
| courseNum | `integer` | |
| echoLevel1 | `integer` | |
| echoLevel2 | `integer` | |
| echoLevel3 | `integer` | |
| fullName | `string` | read-only |
| levelNum | `integer` | |
| next | [CustomLevelInfo](structs.md#CustomLevelInfo) | |
| script | `Pointer` <`LevelScript`> | read-only |
| scriptEntryName | `string` | read-only |
| shortName | `string` | read-only |
[:arrow_up_small:](#)
<br />
## [Cutscene](#Cutscene) ## [Cutscene](#Cutscene)
| Field | Type | Access | | Field | Type | Access |

View file

@ -14,6 +14,7 @@
#include "seq_ids.h" #include "seq_ids.h"
#include "dialog_ids.h" #include "dialog_ids.h"
#include "level_table.h" #include "level_table.h"
#include "pc/lua/utils/smlua_level_utils.h"
#if defined(VERSION_EU) || defined(VERSION_SH) #if defined(VERSION_EU) || defined(VERSION_SH)
#define EU_FLOAT(x) x##f #define EU_FLOAT(x) x##f
@ -511,6 +512,50 @@ void process_level_music_dynamics(void);
static u8 begin_background_music_fade(u16 fadeDuration); static u8 begin_background_music_fade(u16 fadeDuration);
void func_80320ED8(void); void func_80320ED8(void);
static s16 get_level_dynamics(s16 levelNum, s16 index) {
if (levelNum < 0 || levelNum >= LEVEL_COUNT) {
return 0;
}
return sLevelDynamics[levelNum][index];
}
static u8 get_level_area_reverb(s16 levelNum, s16 index) {
if (levelNum >= CUSTOM_LEVEL_NUM_START) {
struct CustomLevelInfo* info = smlua_level_util_get_info(levelNum);
if (!info) { return 0x00; }
switch (index) {
case 0: return info->echoLevel1; break;
case 1: return info->echoLevel2; break;
case 2: return info->echoLevel3; break;
}
return 0x00;
}
if (levelNum < 0 || levelNum >= LEVEL_COUNT) {
return 0x00;
}
if (index < 0 || index >= 3) {
return 0x00;
}
return sLevelAreaReverbs[levelNum][index];
}
static u16 get_level_acoustic_reaches(s16 levelNum) {
if (levelNum >= CUSTOM_LEVEL_NUM_START) {
struct CustomLevelInfo* info = smlua_level_util_get_info(levelNum);
return (info ? info->acousticReach : 20000);
}
if (levelNum < 0 || levelNum >= LEVEL_COUNT) {
return 20000;
}
return sLevelAcousticReaches[levelNum];
}
#ifndef VERSION_JP #ifndef VERSION_JP
void unused_8031E4F0(void) { void unused_8031E4F0(void) {
// This is a debug function which is almost entirely optimized away, // This is a debug function which is almost entirely optimized away,
@ -1215,7 +1260,7 @@ static f32 get_sound_volume(u8 bank, u8 soundIndex, f32 volumeRange) {
if (!(sSoundBanks[bank][soundIndex].soundBits & SOUND_NO_VOLUME_LOSS)) { if (!(sSoundBanks[bank][soundIndex].soundBits & SOUND_NO_VOLUME_LOSS)) {
#ifdef VERSION_JP #ifdef VERSION_JP
// Intensity linearly lowers from 1 at the camera to 0 at maxSoundDistance // Intensity linearly lowers from 1 at the camera to 0 at maxSoundDistance
maxSoundDistance = sLevelAcousticReaches[gCurrLevelNum]; maxSoundDistance = get_level_acoustic_reaches(gCurrLevelNum);
if (maxSoundDistance < sSoundBanks[bank][soundIndex].distance) { if (maxSoundDistance < sSoundBanks[bank][soundIndex].distance) {
intensity = 0.0f; intensity = 0.0f;
} else { } else {
@ -1227,7 +1272,7 @@ static f32 get_sound_volume(u8 bank, u8 soundIndex, f32 volumeRange) {
if (sSoundBanks[bank][soundIndex].distance > AUDIO_MAX_DISTANCE) { if (sSoundBanks[bank][soundIndex].distance > AUDIO_MAX_DISTANCE) {
intensity = 0.0f; intensity = 0.0f;
} else { } else {
maxSoundDistance = sLevelAcousticReaches[gCurrLevelNum] / div; maxSoundDistance = get_level_acoustic_reaches(gCurrLevelNum) / div;
if (maxSoundDistance < sSoundBanks[bank][soundIndex].distance) { if (maxSoundDistance < sSoundBanks[bank][soundIndex].distance) {
intensity = ((AUDIO_MAX_DISTANCE - sSoundBanks[bank][soundIndex].distance) intensity = ((AUDIO_MAX_DISTANCE - sSoundBanks[bank][soundIndex].distance)
/ (AUDIO_MAX_DISTANCE - maxSoundDistance)) / (AUDIO_MAX_DISTANCE - maxSoundDistance))
@ -1305,7 +1350,7 @@ static u8 get_sound_reverb(UNUSED u8 bank, UNUSED u8 soundIndex, u8 channelIndex
// The volume-dependent value is 0 when volume is at maximum, and raises to // The volume-dependent value is 0 when volume is at maximum, and raises to
// LOW_VOLUME_REVERB when the volume is 0 // LOW_VOLUME_REVERB when the volume is 0
reverb = (u8)((u8) gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->soundScriptIO[5] reverb = (u8)((u8) gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->soundScriptIO[5]
+ sLevelAreaReverbs[level][area] + get_level_area_reverb(level, area)
+ (US_FLOAT(1.0) - gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->volume) + (US_FLOAT(1.0) - gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->volume)
* LOW_VOLUME_REVERB); * LOW_VOLUME_REVERB);
@ -1867,12 +1912,12 @@ void process_level_music_dynamics(void) {
sBackgroundMusicForDynamics = sCurrentBackgroundMusicSeqId; sBackgroundMusicForDynamics = sCurrentBackgroundMusicSeqId;
} }
if (sBackgroundMusicForDynamics != sLevelDynamics[gCurrLevelNum][0]) { if (sBackgroundMusicForDynamics != get_level_dynamics(gCurrLevelNum, 0)) {
return; return;
} }
conditionBits = sLevelDynamics[gCurrLevelNum][1] & 0xff00; conditionBits = get_level_dynamics(gCurrLevelNum, 1) & 0xff00;
musicDynIndex = (u8) sLevelDynamics[gCurrLevelNum][1] & 0xff; musicDynIndex = (u8) get_level_dynamics(gCurrLevelNum, 1) & 0xff;
i = 2; i = 2;
while (conditionBits & 0xff00) { while (conditionBits & 0xff00) {
j = 0; j = 0;
@ -1880,7 +1925,7 @@ void process_level_music_dynamics(void) {
bit = 0x8000; bit = 0x8000;
while (j < 8) { while (j < 8) {
if (conditionBits & bit) { if (conditionBits & bit) {
conditionValues[condIndex] = sLevelDynamics[gCurrLevelNum][i++]; conditionValues[condIndex] = get_level_dynamics(gCurrLevelNum, i++);
conditionTypes[condIndex] = j; conditionTypes[condIndex] = j;
condIndex++; condIndex++;
} }
@ -1946,8 +1991,8 @@ void process_level_music_dynamics(void) {
// The area matches. Break out of the loop. // The area matches. Break out of the loop.
tempBits = 0; tempBits = 0;
} else { } else {
tempBits = sLevelDynamics[gCurrLevelNum][i] & 0xff00; tempBits = get_level_dynamics(gCurrLevelNum, i) & 0xff00;
musicDynIndex = sLevelDynamics[gCurrLevelNum][i] & 0xff; musicDynIndex = get_level_dynamics(gCurrLevelNum, i) & 0xff;
i++; i++;
} }
@ -2809,7 +2854,7 @@ f32 sound_get_level_intensity(f32 distance) {
} }
f32 volumeRange = VOLUME_RANGE_UNK1; f32 volumeRange = VOLUME_RANGE_UNK1;
f32 maxSoundDistance = sLevelAcousticReaches[gCurrLevelNum] / 2.0f; f32 maxSoundDistance = get_level_acoustic_reaches(gCurrLevelNum) / 2.0f;
if (maxSoundDistance < distance) { if (maxSoundDistance < distance) {
intensity = ((AUDIO_MAX_DISTANCE - distance) / (AUDIO_MAX_DISTANCE - maxSoundDistance)) * (1.0f - volumeRange); intensity = ((AUDIO_MAX_DISTANCE - distance) / (AUDIO_MAX_DISTANCE - maxSoundDistance)) * (1.0f - volumeRange);
} else { } else {

View file

@ -6610,6 +6610,14 @@ struct CutsceneSplinePoint sEndingLookAtSkyFocus[] = {
{ -1, 0, { 636, 2027, -415 } } { -1, 0, { 636, 2027, -415 } }
}; };
static struct CameraTrigger* get_camera_trigger(s16 levelNum) {
if (levelNum < 0 || levelNum >= LEVEL_COUNT + 2) {
return NULL;
}
return sCameraTriggers[levelNum];
}
/** /**
* Activates any CameraTriggers that Mario is inside. * Activates any CameraTriggers that Mario is inside.
* Then, applies area-specific processing to the camera, such as setting the default mode, or changing * Then, applies area-specific processing to the camera, such as setting the default mode, or changing
@ -6638,40 +6646,41 @@ s16 camera_course_processing(struct Camera *c) {
level = LEVEL_COUNT + 1; level = LEVEL_COUNT + 1;
} }
if (sCameraTriggers[level] != NULL) { if (get_camera_trigger(level) != NULL) {
b = 0; b = 0;
// Process positional triggers. // Process positional triggers.
// All triggered events are called, not just the first one. // All triggered events are called, not just the first one.
while (sCameraTriggers[level][b].event != NULL) { struct CameraTrigger* camTrigger = get_camera_trigger(level);
while (camTrigger[b].event != NULL) {
// Check only the current area's triggers // Check only the current area's triggers
if (sCameraTriggers[level][b].area == area) { if (camTrigger[b].area == area) {
// Copy the bounding box into center and bounds // Copy the bounding box into center and bounds
vec3f_set(center, sCameraTriggers[level][b].centerX, vec3f_set(center, camTrigger[b].centerX,
sCameraTriggers[level][b].centerY, camTrigger[b].centerY,
sCameraTriggers[level][b].centerZ); camTrigger[b].centerZ);
vec3f_set(bounds, sCameraTriggers[level][b].boundsX, vec3f_set(bounds, camTrigger[b].boundsX,
sCameraTriggers[level][b].boundsY, camTrigger[b].boundsY,
sCameraTriggers[level][b].boundsZ); camTrigger[b].boundsZ);
// Check if Mario is inside the bounds // Check if Mario is inside the bounds
if (is_pos_in_bounds(sMarioCamState->pos, center, bounds, if (is_pos_in_bounds(sMarioCamState->pos, center, bounds,
sCameraTriggers[level][b].boundsYaw) == TRUE) { camTrigger[b].boundsYaw) == TRUE) {
//! This should be checked before calling is_pos_in_bounds. (It doesn't belong //! This should be checked before calling is_pos_in_bounds. (It doesn't belong
//! outside the while loop because some events disable area processing) //! outside the while loop because some events disable area processing)
if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) { if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) {
sCameraTriggers[level][b].event(c); camTrigger[b].event(c);
insideBounds = TRUE; insideBounds = TRUE;
} }
} }
} }
if ((sCameraTriggers[level])[b].area == -1) { if ((camTrigger)[b].area == -1) {
// Default triggers are only active if Mario is not already inside another trigger // Default triggers are only active if Mario is not already inside another trigger
if (!insideBounds) { if (!insideBounds) {
if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) { if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) {
sCameraTriggers[level][b].event(c); camTrigger[b].event(c);
} }
} }
} }

View file

@ -7,6 +7,7 @@
#include "level_info.h" #include "level_info.h"
#include "level_table.h" #include "level_table.h"
#include "types.h" #include "types.h"
#include "pc/lua/utils/smlua_level_utils.h"
#ifdef VERSION_EU #ifdef VERSION_EU
extern u8 *course_name_table_eu_en[]; extern u8 *course_name_table_eu_en[];
@ -165,7 +166,17 @@ const char *get_level_name_ascii(s16 courseNum, s16 levelNum, s16 areaIndex, s16
// Valid course: BOB to RR, Bowser stages and Secret courses // Valid course: BOB to RR, Bowser stages and Secret courses
// There is no course name for Cake Ending, make it defaults to "Peach's Castle" // There is no course name for Cake Ending, make it defaults to "Peach's Castle"
if (courseNum >= COURSE_MIN && courseNum < COURSE_MAX) {
bool hasCustomName = false;
if (levelNum >= CUSTOM_LEVEL_NUM_START) {
struct CustomLevelInfo* info = smlua_level_util_get_info(levelNum);
if (info) {
hasCustomName = true;
snprintf(output, 256, info->fullName);
}
}
if (!hasCustomName && courseNum >= COURSE_MIN && courseNum < COURSE_MAX) {
void **courseNameTbl = NULL; void **courseNameTbl = NULL;
#ifdef VERSION_EU #ifdef VERSION_EU
switch (gInGameLanguage) { switch (gInGameLanguage) {
@ -181,7 +192,7 @@ const char *get_level_name_ascii(s16 courseNum, s16 levelNum, s16 areaIndex, s16
} }
// Castle level // Castle level
else if (courseNum == COURSE_NONE) { else if (!hasCustomName && courseNum == COURSE_NONE) {
switch (levelNum) { switch (levelNum) {
case LEVEL_CASTLE: { case LEVEL_CASTLE: {
switch (areaIndex) { switch (areaIndex) {
@ -198,7 +209,7 @@ const char *get_level_name_ascii(s16 courseNum, s16 levelNum, s16 areaIndex, s16
} }
// Default // Default
else { else if (!hasCustomName) {
snprintf(output, 256, "Peach's Castle"); snprintf(output, 256, "Peach's Castle");
} }

View file

@ -1525,7 +1525,7 @@ s32 lvl_set_current_level(UNUSED s16 arg0, s32 levelNum) {
sWarpCheckpointActive = FALSE; sWarpCheckpointActive = FALSE;
gCurrLevelNum = levelNum; gCurrLevelNum = levelNum;
gCurrCourseNum = gLevelToCourseNumTable[levelNum - 1]; gCurrCourseNum = get_level_course_num(levelNum - 1);
if (gCurrDemoInput != NULL || gCurrCreditsEntry != NULL || gCurrCourseNum == COURSE_NONE) { if (gCurrDemoInput != NULL || gCurrCreditsEntry != NULL || gCurrCourseNum == COURSE_NONE) {
return 0; return 0;

View file

@ -13,6 +13,7 @@
#include "macros.h" #include "macros.h"
#include "pc/ini.h" #include "pc/ini.h"
#include "pc/network/network.h" #include "pc/network/network.h"
#include "pc/lua/utils/smlua_level_utils.h"
#ifndef bcopy #ifndef bcopy
#define bcopy(b1,b2,len) (memmove((b2), (b1), (len)), (void) 0) #define bcopy(b1,b2,len) (memmove((b2), (b1), (len)), (void) 0)
@ -50,6 +51,19 @@ s8 gLevelToCourseNumTable[] = {
STATIC_ASSERT(ARRAY_COUNT(gLevelToCourseNumTable) == LEVEL_COUNT - 1, STATIC_ASSERT(ARRAY_COUNT(gLevelToCourseNumTable) == LEVEL_COUNT - 1,
"change this array if you are adding levels"); "change this array if you are adding levels");
s8 get_level_course_num(s16 levelNum) {
if (levelNum >= CUSTOM_LEVEL_NUM_START) {
struct CustomLevelInfo* info = smlua_level_util_get_info(levelNum);
return (info ? info->courseNum : COURSE_NONE);
}
if (levelNum < 0 || levelNum >= LEVEL_COUNT) {
return COURSE_NONE;
}
return gLevelToCourseNumTable[levelNum];
}
// This was probably used to set progress to 100% for debugging, but // This was probably used to set progress to 100% for debugging, but
// it was removed from the release ROM. // it was removed from the release ROM.
static void stub_save_file_1(void) { static void stub_save_file_1(void) {
@ -745,7 +759,7 @@ void check_if_should_set_warp_checkpoint(struct WarpNode *warpNode) {
*/ */
s32 check_warp_checkpoint(struct WarpNode *warpNode) { s32 check_warp_checkpoint(struct WarpNode *warpNode) {
s16 warpCheckpointActive = FALSE; s16 warpCheckpointActive = FALSE;
s16 currCourseNum = gLevelToCourseNumTable[(warpNode->destLevel & 0x7F) - 1]; s16 currCourseNum = get_level_course_num((warpNode->destLevel & 0x7F) - 1);
// gSavedCourseNum is only used in this function. // gSavedCourseNum is only used in this function.
if (gWarpCheckpoint.courseNum != COURSE_NONE && gSavedCourseNum == currCourseNum if (gWarpCheckpoint.courseNum != COURSE_NONE && gSavedCourseNum == currCourseNum

View file

@ -128,6 +128,7 @@ extern struct WarpCheckpoint gWarpCheckpoint;
extern s8 gMainMenuDataModified; extern s8 gMainMenuDataModified;
extern s8 gSaveFileModified; extern s8 gSaveFileModified;
s8 get_level_course_num(s16 levelNum);
void save_file_do_save(s32 fileIndex, s8 forceSave); void save_file_do_save(s32 fileIndex, s8 forceSave);
void save_file_erase(s32 fileIndex); void save_file_erase(s32 fileIndex);
BAD_RETURN(s32) save_file_copy(s32 srcFileIndex, s32 destFileIndex); BAD_RETURN(s32) save_file_copy(s32 srcFileIndex, s32 destFileIndex);

View file

@ -14,6 +14,7 @@
#include "level_table.h" #include "level_table.h"
#include "seq_ids.h" #include "seq_ids.h"
#include "sm64.h" #include "sm64.h"
#include "pc/lua/utils/smlua_level_utils.h"
#define PRESS_START_DEMO_TIMER 800 #define PRESS_START_DEMO_TIMER 800
@ -32,6 +33,19 @@ static s16 D_U_801A7C34 = 1;
static s16 gameOverNotPlayed = 1; static s16 gameOverNotPlayed = 1;
#endif #endif
static char* get_level_stage_names(s16 levelNum) {
if (levelNum >= CUSTOM_LEVEL_NUM_START) {
struct CustomLevelInfo* info = smlua_level_util_get_info(levelNum);
return (info ? info->fullName : "Unknown");
}
if (levelNum < 0 || levelNum >= LEVEL_COUNT) {
return "Unknown";
}
return gLevelSelect_StageNamesText[levelNum];
}
// run the demo timer on the PRESS START screen. // run the demo timer on the PRESS START screen.
// this function will return a non-0 timer once // this function will return a non-0 timer once
// the demo starts, signaling to the subsystem that // the demo starts, signaling to the subsystem that
@ -140,7 +154,7 @@ s16 level_select_input_loop(void) {
print_text_centered(160, 80, "SELECT STAGE"); print_text_centered(160, 80, "SELECT STAGE");
print_text_centered(160, 30, "PRESS START BUTTON"); print_text_centered(160, 30, "PRESS START BUTTON");
print_text_fmt_int(40, 60, "%2d", gCurrLevelNum); print_text_fmt_int(40, 60, "%2d", gCurrLevelNum);
print_text(80, 60, gLevelSelect_StageNamesText[gCurrLevelNum - 1]); // print stage name print_text(80, 60, get_level_stage_names(gCurrLevelNum - 1)); // print stage name
#define QUIT_LEVEL_SELECT_COMBO (Z_TRIG | START_BUTTON | L_CBUTTONS | R_CBUTTONS) #define QUIT_LEVEL_SELECT_COMBO (Z_TRIG | START_BUTTON | L_CBUTTONS | R_CBUTTONS)

View file

@ -6,6 +6,7 @@
#include "pc/network/ban_list.h" #include "pc/network/ban_list.h"
#include "pc/network/moderator_list.h" #include "pc/network/moderator_list.h"
#include "pc/debuglog.h" #include "pc/debuglog.h"
#include "pc/lua/utils/smlua_level_utils.h"
#include "level_table.h" #include "level_table.h"
@ -265,6 +266,12 @@ bool exec_chat_command(char* command) {
break; break;
} }
} }
if (level == -1) {
struct CustomLevelInfo* info = smlua_level_util_get_info_from_short_name(paramLevel);
if (info != NULL) {
level = info->levelNum;
}
}
if (level == -1) { if (level == -1) {
char message[256]; char message[256];
snprintf(message, 256, "Invalid [LEVEL] parameter: %s", paramLevel); snprintf(message, 256, "Invalid [LEVEL] parameter: %s", paramLevel);

View file

@ -6,6 +6,7 @@
#include "pc/lua/utils/smlua_text_utils.h" #include "pc/lua/utils/smlua_text_utils.h"
#include "pc/lua/utils/smlua_audio_utils.h" #include "pc/lua/utils/smlua_audio_utils.h"
#include "pc/lua/utils/smlua_model_utils.h" #include "pc/lua/utils/smlua_model_utils.h"
#include "pc/lua/utils/smlua_level_utils.h"
#include "pc/djui/djui.h" #include "pc/djui/djui.h"
lua_State* gLuaState = NULL; lua_State* gLuaState = NULL;
@ -188,6 +189,7 @@ void smlua_shutdown(void) {
smlua_cpointer_allowlist_shutdown(); smlua_cpointer_allowlist_shutdown();
smlua_clear_hooks(); smlua_clear_hooks();
smlua_model_util_reset(); smlua_model_util_reset();
smlua_level_util_reset();
lua_State* L = gLuaState; lua_State* L = gLuaState;
if (L != NULL) { if (L != NULL) {
lua_close(L); lua_close(L);

View file

@ -13,6 +13,7 @@
#include "src/pc/lua/utils/smlua_anim_utils.h" #include "src/pc/lua/utils/smlua_anim_utils.h"
#include "src/pc/lua/utils/smlua_misc_utils.h" #include "src/pc/lua/utils/smlua_misc_utils.h"
#include "src/pc/lua/utils/smlua_collision_utils.h" #include "src/pc/lua/utils/smlua_collision_utils.h"
#include "src/pc/lua/utils/smlua_level_utils.h"
#include "src/game/spawn_sound.h" #include "src/game/spawn_sound.h"
#include "src/pc/network/network.h" #include "src/pc/network/network.h"
#include "src/game/hardcoded.h" #include "src/game/hardcoded.h"
@ -392,6 +393,21 @@ static struct LuaObjectField sControllerFields[LUA_CONTROLLER_FIELD_COUNT] = {
{ "stickY", LVT_F32, offsetof(struct Controller, stickY), false, LOT_NONE }, { "stickY", LVT_F32, offsetof(struct Controller, stickY), false, LOT_NONE },
}; };
#define LUA_CUSTOM_LEVEL_INFO_FIELD_COUNT 11
static struct LuaObjectField sCustomLevelInfoFields[LUA_CUSTOM_LEVEL_INFO_FIELD_COUNT] = {
{ "acousticReach", LVT_U32, offsetof(struct CustomLevelInfo, acousticReach), false, LOT_NONE },
{ "courseNum", LVT_S16, offsetof(struct CustomLevelInfo, courseNum), false, LOT_NONE },
{ "echoLevel1", LVT_U32, offsetof(struct CustomLevelInfo, echoLevel1), false, LOT_NONE },
{ "echoLevel2", LVT_U32, offsetof(struct CustomLevelInfo, echoLevel2), false, LOT_NONE },
{ "echoLevel3", LVT_U32, offsetof(struct CustomLevelInfo, echoLevel3), false, LOT_NONE },
{ "fullName", LVT_STRING_P, offsetof(struct CustomLevelInfo, fullName), true, LOT_NONE },
{ "levelNum", LVT_S16, offsetof(struct CustomLevelInfo, levelNum), false, LOT_NONE },
{ "next", LVT_COBJECT_P, offsetof(struct CustomLevelInfo, next), false, LOT_CUSTOMLEVELINFO },
{ "script", LVT_LEVELSCRIPT_P, offsetof(struct CustomLevelInfo, script), true, LOT_POINTER },
{ "scriptEntryName", LVT_STRING_P, offsetof(struct CustomLevelInfo, scriptEntryName), true, LOT_NONE },
{ "shortName", LVT_STRING_P, offsetof(struct CustomLevelInfo, shortName), true, LOT_NONE },
};
#define LUA_CUTSCENE_FIELD_COUNT 1 #define LUA_CUTSCENE_FIELD_COUNT 1
static struct LuaObjectField sCutsceneFields[LUA_CUTSCENE_FIELD_COUNT] = { static struct LuaObjectField sCutsceneFields[LUA_CUTSCENE_FIELD_COUNT] = {
{ "duration", LVT_S16, offsetof(struct Cutscene, duration), false, LOT_NONE }, { "duration", LVT_S16, offsetof(struct Cutscene, duration), false, LOT_NONE },
@ -1979,6 +1995,7 @@ struct LuaObjectTable sLuaObjectAutogenTable[LOT_AUTOGEN_MAX - LOT_AUTOGEN_MIN]
{ LOT_CHAINSEGMENT, sChainSegmentFields, LUA_CHAIN_SEGMENT_FIELD_COUNT }, { LOT_CHAINSEGMENT, sChainSegmentFields, LUA_CHAIN_SEGMENT_FIELD_COUNT },
{ LOT_CHARACTER, sCharacterFields, LUA_CHARACTER_FIELD_COUNT }, { LOT_CHARACTER, sCharacterFields, LUA_CHARACTER_FIELD_COUNT },
{ LOT_CONTROLLER, sControllerFields, LUA_CONTROLLER_FIELD_COUNT }, { LOT_CONTROLLER, sControllerFields, LUA_CONTROLLER_FIELD_COUNT },
{ LOT_CUSTOMLEVELINFO, sCustomLevelInfoFields, LUA_CUSTOM_LEVEL_INFO_FIELD_COUNT },
{ LOT_CUTSCENE, sCutsceneFields, LUA_CUTSCENE_FIELD_COUNT }, { LOT_CUTSCENE, sCutsceneFields, LUA_CUTSCENE_FIELD_COUNT },
{ LOT_CUTSCENESPLINEPOINT, sCutsceneSplinePointFields, LUA_CUTSCENE_SPLINE_POINT_FIELD_COUNT }, { LOT_CUTSCENESPLINEPOINT, sCutsceneSplinePointFields, LUA_CUTSCENE_SPLINE_POINT_FIELD_COUNT },
{ LOT_CUTSCENEVARIABLE, sCutsceneVariableFields, LUA_CUTSCENE_VARIABLE_FIELD_COUNT }, { LOT_CUTSCENEVARIABLE, sCutsceneVariableFields, LUA_CUTSCENE_VARIABLE_FIELD_COUNT },

View file

@ -20,6 +20,7 @@ enum LuaObjectAutogenType {
LOT_CHAINSEGMENT, LOT_CHAINSEGMENT,
LOT_CHARACTER, LOT_CHARACTER,
LOT_CONTROLLER, LOT_CONTROLLER,
LOT_CUSTOMLEVELINFO,
LOT_CUTSCENE, LOT_CUTSCENE,
LOT_CUTSCENESPLINEPOINT, LOT_CUTSCENESPLINEPOINT,
LOT_CUTSCENEVARIABLE, LOT_CUTSCENEVARIABLE,

View file

@ -25,6 +25,7 @@
#include "src/pc/lua/utils/smlua_model_utils.h" #include "src/pc/lua/utils/smlua_model_utils.h"
#include "src/pc/lua/utils/smlua_text_utils.h" #include "src/pc/lua/utils/smlua_text_utils.h"
#include "src/pc/lua/utils/smlua_audio_utils.h" #include "src/pc/lua/utils/smlua_audio_utils.h"
#include "src/pc/lua/utils/smlua_level_utils.h"
#include "src/engine/surface_load.h" #include "src/engine/surface_load.h"
#include "src/game/object_list_processor.h" #include "src/game/object_list_processor.h"
#include "src/game/behavior_actions.h" #include "src/game/behavior_actions.h"
@ -15108,6 +15109,103 @@ int smlua_func_smlua_collision_util_get(lua_State* L) {
return 1; return 1;
} }
/////////////////////////
// smlua_level_utils.h //
/////////////////////////
int smlua_func_level_register(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 8)) { return 0; }
const char* scriptEntryName = smlua_to_string(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
s16 courseNum = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; }
const char* fullName = smlua_to_string(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 3"); return 0; }
const char* shortName = smlua_to_string(L, 4);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 4"); return 0; }
u32 acousticReach = smlua_to_integer(L, 5);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 5"); return 0; }
u32 echoLevel1 = smlua_to_integer(L, 6);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 6"); return 0; }
u32 echoLevel2 = smlua_to_integer(L, 7);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 7"); return 0; }
u32 echoLevel3 = smlua_to_integer(L, 8);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 8"); return 0; }
lua_pushinteger(L, level_register(scriptEntryName, courseNum, fullName, shortName, acousticReach, echoLevel1, echoLevel2, echoLevel3));
return 1;
}
int smlua_func_smlua_level_util_get_info(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
s16 levelNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
smlua_push_object(L, LOT_CUSTOMLEVELINFO, smlua_level_util_get_info(levelNum));
return 1;
}
int smlua_func_smlua_level_util_get_info_from_short_name(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
char* shortName = (char*)smlua_to_cobject(L, 1, LOT_NONE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
smlua_push_object(L, LOT_CUSTOMLEVELINFO, smlua_level_util_get_info_from_short_name(shortName));
return 1;
}
int smlua_func_warp_exit_level(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
s32 aDelay = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
lua_pushboolean(L, warp_exit_level(aDelay));
return 1;
}
int smlua_func_warp_restart_level(UNUSED lua_State* L) {
if(!smlua_functions_valid_param_count(L, 0)) { return 0; }
lua_pushboolean(L, warp_restart_level());
return 1;
}
int smlua_func_warp_to_castle(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
s32 aLevel = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
lua_pushboolean(L, warp_to_castle(aLevel));
return 1;
}
int smlua_func_warp_to_level(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 3)) { return 0; }
s32 aLevel = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
s32 aArea = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; }
s32 aAct = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 3"); return 0; }
lua_pushboolean(L, warp_to_level(aLevel, aArea, aAct));
return 1;
}
//////////////////////// ////////////////////////
// smlua_misc_utils.h // // smlua_misc_utils.h //
//////////////////////// ////////////////////////
@ -15594,52 +15692,6 @@ int smlua_func_set_override_near(lua_State* L) {
return 1; return 1;
} }
int smlua_func_warp_exit_level(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
s32 aDelay = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
lua_pushboolean(L, warp_exit_level(aDelay));
return 1;
}
int smlua_func_warp_restart_level(UNUSED lua_State* L) {
if(!smlua_functions_valid_param_count(L, 0)) { return 0; }
lua_pushboolean(L, warp_restart_level());
return 1;
}
int smlua_func_warp_to_castle(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
s32 aLevel = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
lua_pushboolean(L, warp_to_castle(aLevel));
return 1;
}
int smlua_func_warp_to_level(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 3)) { return 0; }
s32 aLevel = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
s32 aArea = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; }
s32 aAct = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 3"); return 0; }
lua_pushboolean(L, warp_to_level(aLevel, aArea, aAct));
return 1;
}
///////////////////////// /////////////////////////
// smlua_model_utils.h // // smlua_model_utils.h //
///////////////////////// /////////////////////////
@ -17847,6 +17899,15 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "get_water_surface_pseudo_floor", smlua_func_get_water_surface_pseudo_floor); smlua_bind_function(L, "get_water_surface_pseudo_floor", smlua_func_get_water_surface_pseudo_floor);
smlua_bind_function(L, "smlua_collision_util_get", smlua_func_smlua_collision_util_get); smlua_bind_function(L, "smlua_collision_util_get", smlua_func_smlua_collision_util_get);
// smlua_level_utils.h
smlua_bind_function(L, "level_register", smlua_func_level_register);
smlua_bind_function(L, "smlua_level_util_get_info", smlua_func_smlua_level_util_get_info);
smlua_bind_function(L, "smlua_level_util_get_info_from_short_name", smlua_func_smlua_level_util_get_info_from_short_name);
smlua_bind_function(L, "warp_exit_level", smlua_func_warp_exit_level);
smlua_bind_function(L, "warp_restart_level", smlua_func_warp_restart_level);
smlua_bind_function(L, "warp_to_castle", smlua_func_warp_to_castle);
smlua_bind_function(L, "warp_to_level", smlua_func_warp_to_level);
// smlua_misc_utils.h // smlua_misc_utils.h
smlua_bind_function(L, "allocate_mario_action", smlua_func_allocate_mario_action); smlua_bind_function(L, "allocate_mario_action", smlua_func_allocate_mario_action);
smlua_bind_function(L, "camera_config_enable_analog_cam", smlua_func_camera_config_enable_analog_cam); smlua_bind_function(L, "camera_config_enable_analog_cam", smlua_func_camera_config_enable_analog_cam);
@ -17892,10 +17953,6 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "set_override_far", smlua_func_set_override_far); smlua_bind_function(L, "set_override_far", smlua_func_set_override_far);
smlua_bind_function(L, "set_override_fov", smlua_func_set_override_fov); smlua_bind_function(L, "set_override_fov", smlua_func_set_override_fov);
smlua_bind_function(L, "set_override_near", smlua_func_set_override_near); smlua_bind_function(L, "set_override_near", smlua_func_set_override_near);
smlua_bind_function(L, "warp_exit_level", smlua_func_warp_exit_level);
smlua_bind_function(L, "warp_restart_level", smlua_func_warp_restart_level);
smlua_bind_function(L, "warp_to_castle", smlua_func_warp_to_castle);
smlua_bind_function(L, "warp_to_level", smlua_func_warp_to_level);
// smlua_model_utils.h // smlua_model_utils.h
smlua_bind_function(L, "smlua_model_util_get_id", smlua_func_smlua_model_util_get_id); smlua_bind_function(L, "smlua_model_util_get_id", smlua_func_smlua_model_util_get_id);

View file

@ -0,0 +1,143 @@
#include "sm64.h"
#include "types.h"
#include "smlua_level_utils.h"
#include "pc/lua/smlua.h"
struct CustomLevelInfo* sCustomLevelHead = NULL;
static s16 sCustomLevelNumNext = CUSTOM_LEVEL_NUM_START;
void smlua_level_util_reset(void) {
struct CustomLevelInfo* node = sCustomLevelHead;
while (node != NULL) {
struct CustomLevelInfo* next = node->next;
if (node->scriptEntryName) {
free(node->scriptEntryName);
node->scriptEntryName = NULL;
}
if (node->fullName) {
free(node->fullName);
node->fullName = NULL;
}
if (node->shortName) {
free(node->shortName);
node->shortName = NULL;
}
free(node);
node = next;
}
sCustomLevelHead = NULL;
sCustomLevelNumNext = CUSTOM_LEVEL_NUM_START;
}
struct CustomLevelInfo* smlua_level_util_get_info(s16 levelNum) {
struct CustomLevelInfo* node = sCustomLevelHead;
while (node != NULL) {
if (node->levelNum == levelNum) {
return node;
}
node = node->next;
}
return NULL;
}
struct CustomLevelInfo* smlua_level_util_get_info_from_short_name(char* shortName) {
struct CustomLevelInfo* node = sCustomLevelHead;
while (node != NULL) {
if (!strcmp(node->shortName, shortName)) {
return node;
}
node = node->next;
}
return NULL;
}
static struct CustomLevelInfo* smlua_level_util_get_info_from_script(char* scriptEntryName) {
struct CustomLevelInfo* node = sCustomLevelHead;
while (node != NULL) {
if (!strcmp(node->scriptEntryName, scriptEntryName)) {
return node;
}
node = node->next;
}
return NULL;
}
s16 level_register(const char* scriptEntryName, s16 courseNum, const char* fullName, const char* shortName, u32 acousticReach, u32 echoLevel1, u32 echoLevel2, u32 echoLevel3) {
// validate params
if (scriptEntryName == NULL) {
LOG_LUA("Provided nil scriptEntryName");
return 0;
}
if (fullName == NULL) {
LOG_LUA("Provided nil fullName");
return 0;
}
if (shortName == NULL) {
LOG_LUA("Provided nil shortName");
return 0;
}
// find duplicate
struct CustomLevelInfo* info = smlua_level_util_get_info_from_script((char*)scriptEntryName);
if (info != NULL) {
return info->levelNum;
}
// find script
LevelScript* script = dynos_get_level_script((char*)scriptEntryName);
if (script == NULL) {
LOG_LUA("Failed to find script: %s", scriptEntryName);
return 0;
}
// allocate and fill
info = calloc(1, sizeof(struct CustomLevelInfo));
info->script = script;
info->scriptEntryName = strdup(scriptEntryName);
info->courseNum = courseNum;
info->levelNum = sCustomLevelNumNext++;
info->fullName = strdup(fullName);
info->shortName = strdup(shortName);
info->acousticReach = acousticReach;
info->echoLevel1 = echoLevel1;
info->echoLevel2 = echoLevel2;
info->echoLevel3 = echoLevel3;
// add to list
if (!sCustomLevelHead) {
sCustomLevelHead = info;
return info->levelNum;
}
struct CustomLevelInfo* node = sCustomLevelHead;
while (node) {
if (!node->next) {
node->next = info;
return info->levelNum;
}
node = node->next;
}
// just in case, should never trigger
return 0;
}
bool warp_to_level(s32 aLevel, s32 aArea, s32 aAct) {
return dynos_warp_to_level(aLevel, aArea, aAct);
}
bool warp_restart_level(void) {
return dynos_warp_restart_level();
}
bool warp_exit_level(s32 aDelay) {
return dynos_warp_exit_level(aDelay);
}
bool warp_to_castle(s32 aLevel) {
return dynos_warp_to_castle(aLevel);
}

View file

@ -0,0 +1,29 @@
#ifndef SMLUA_LEVEL_UTILS_H
#define SMLUA_LEVEL_UTILS_H
struct CustomLevelInfo {
LevelScript* script;
char* scriptEntryName;
s16 courseNum;
s16 levelNum;
char* fullName;
char* shortName;
u32 acousticReach;
u32 echoLevel1;
u32 echoLevel2;
u32 echoLevel3;
struct CustomLevelInfo* next;
};
#define CUSTOM_LEVEL_NUM_START 50
void smlua_level_util_reset(void);
struct CustomLevelInfo* smlua_level_util_get_info(s16 levelNum);
struct CustomLevelInfo* smlua_level_util_get_info_from_short_name(char* shortName);
s16 level_register(const char* scriptEntryName, s16 courseNum, const char* fullName, const char* shortName, u32 acousticReach, u32 echoLevel1, u32 echoLevel2, u32 echoLevel3);
bool warp_to_level(s32 aLevel, s32 aArea, s32 aAct);
bool warp_restart_level(void);
bool warp_exit_level(s32 aDelay);
bool warp_to_castle(s32 aLevel);
#endif

View file

@ -272,24 +272,6 @@ bool is_game_paused(void) {
/// ///
bool warp_to_level(s32 aLevel, s32 aArea, s32 aAct) {
return dynos_warp_to_level(aLevel, aArea, aAct);
}
bool warp_restart_level(void) {
return dynos_warp_restart_level();
}
bool warp_exit_level(s32 aDelay) {
return dynos_warp_exit_level(aDelay);
}
bool warp_to_castle(s32 aLevel) {
return dynos_warp_to_castle(aLevel);
}
///
u32 allocate_mario_action(u32 actFlags) { u32 allocate_mario_action(u32 actFlags) {
actFlags = actFlags & (~((u32)0xFF)); actFlags = actFlags & (~((u32)0xFF));
return actFlags | ACT_FLAG_CUSTOM_ACTION | gLuaMarioActionIndex++; return actFlags | ACT_FLAG_CUSTOM_ACTION | gLuaMarioActionIndex++;

View file

@ -63,11 +63,6 @@ void camera_config_set_deceleration(u32 value);
bool is_game_paused(void); bool is_game_paused(void);
bool warp_to_level(s32 aLevel, s32 aArea, s32 aAct);
bool warp_restart_level(void);
bool warp_exit_level(s32 aDelay);
bool warp_to_castle(s32 aLevel);
u32 allocate_mario_action(u32 actFlags); u32 allocate_mario_action(u32 actFlags);
f32 get_hand_foot_pos_x(struct MarioState* m, u8 index); f32 get_hand_foot_pos_x(struct MarioState* m, u8 index);