diff --git a/autogen/convert_functions.py b/autogen/convert_functions.py
index 78f1e1fc..e5f2b250 100644
--- a/autogen/convert_functions.py
+++ b/autogen/convert_functions.py
@@ -41,6 +41,7 @@ in_files = [
"src/pc/lua/utils/smlua_collision_utils.h",
"src/pc/lua/utils/smlua_model_utils.h",
"src/pc/lua/utils/smlua_text_utils.h",
+ "src/pc/lua/utils/smlua_audio_utils.h",
"src/game/object_helpers.c",
"src/game/obj_behaviors.c",
"src/game/obj_behaviors_2.c",
@@ -58,7 +59,7 @@ override_allowed_functions = {
"src/game/save_file.h": [ "save_file_get_", "save_file_set_flags", "save_file_clear_flags" ],
"src/pc/lua/utils/smlua_model_utils.h": [ "smlua_model_util_get_id" ],
"src/game/object_list_processor.h": [ "set_object_respawn_info_bits" ],
- "src/game/mario_misc.h": [ "bhv_toad.*", "bhv_unlock_door.*" ]
+ "src/game/mario_misc.h": [ "bhv_toad.*", "bhv_unlock_door.*" ],
}
override_disallowed_functions = {
@@ -84,7 +85,8 @@ override_disallowed_functions = {
"src/game/spawn_sound.c": [ "spawner" ],
"src/pc/lua/utils/smlua_obj_utils.h": [ "spawn_object_remember_field" ],
"src/game/camera.h": [ "update_camera", "init_camera", "stub_camera", "^reset_camera", "move_point_along_spline" ],
- "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"],
}
lua_function_params = {
diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua
index 25c923b2..dd93f768 100644
--- a/autogen/lua_definitions/functions.lua
+++ b/autogen/lua_definitions/functions.lua
@@ -7017,6 +7017,14 @@ function save_file_set_flags(flags)
-- ...
end
+--- @param sequenceId integer
+--- @param bankId integer
+--- @param m64Name string
+--- @return nil
+function smlua_audio_utils_replace_sequence(sequenceId, bankId, m64Name)
+ -- ...
+end
+
--- @param startX number
--- @param startY number
--- @param startZ number
diff --git a/docs/lua/functions.md b/docs/lua/functions.md
index 65ef7ac0..b66f80f7 100644
--- a/docs/lua/functions.md
+++ b/docs/lua/functions.md
@@ -1302,6 +1302,11 @@
+- smlua_audio_utils.h
+ - [smlua_audio_utils_replace_sequence](#smlua_audio_utils_replace_sequence)
+
+
+
- smlua_collision_utils.h
- [collision_find_surface_on_ray](#collision_find_surface_on_ray)
- [get_water_surface_pseudo_floor](#get_water_surface_pseudo_floor)
@@ -24550,6 +24555,34 @@ The `reliable` field will ensure that the packet arrives, but should be used spa
+---
+# functions from smlua_audio_utils.h
+
+
+
+
+## [smlua_audio_utils_replace_sequence](#smlua_audio_utils_replace_sequence)
+
+### Lua Example
+`smlua_audio_utils_replace_sequence(sequenceId, bankId, m64Name)`
+
+### Parameters
+| Field | Type |
+| ----- | ---- |
+| sequenceId | `integer` |
+| bankId | `integer` |
+| m64Name | `string` |
+
+### Returns
+- None
+
+### C Prototype
+`void smlua_audio_utils_replace_sequence(u8 sequenceId, u8 bankId, const char* m64Name);`
+
+[:arrow_up_small:](#)
+
+
+
---
# functions from smlua_collision_utils.h
diff --git a/src/audio/load.c b/src/audio/load.c
index 00bd0327..ba2ffbb8 100644
--- a/src/audio/load.c
+++ b/src/audio/load.c
@@ -10,6 +10,7 @@
#include "pc/platform.h"
#include "pc/fs/fs.h"
+#include "pc/lua/utils/smlua_audio_utils.h"
#define ALIGN16(val) (((val) + 0xF) & ~0xF)
@@ -1374,6 +1375,7 @@ void *sequence_dma_immediate(s32 seqId, s32 arg1) {
seqLength = gSeqFileHeader->seqArray[seqId].len + 0xf;
seqLength = ALIGN16(seqLength);
seqData = gSeqFileHeader->seqArray[seqId].offset;
+
ptr = alloc_bank_or_seq(&gSeqLoadedPool, 1, seqLength, arg1, seqId);
if (ptr == NULL) {
return NULL;
@@ -1396,6 +1398,7 @@ void *sequence_dma_async(s32 seqId, s32 arg1, struct SequencePlayer *seqPlayer)
seqLength = gSeqFileHeader->seqArray[seqId].len + 0xf;
seqLength = ALIGN16(seqLength);
seqData = gSeqFileHeader->seqArray[seqId].offset;
+
ptr = alloc_bank_or_seq(&gSeqLoadedPool, 1, seqLength, arg1, seqId);
if (ptr == NULL) {
eu_stubbed_printf_0("Heap Overflow Error\n");
@@ -1558,6 +1561,25 @@ void load_sequence_internal(u32 player, u32 seqId, s32 loadAsync) {
struct SequencePlayer *seqPlayer = &gSequencePlayers[player];
UNUSED u32 padding[2];
+ // do custom music override
+ {
+ s32 bankId = 0;
+ if (smlua_audio_utils_override(seqId, &bankId, &sequenceData)) {
+ sequence_player_disable(seqPlayer);
+ seqPlayer->defaultBank[0] = bankId;
+ if (!bank_load_immediate(bankId, 2)) { return; }
+ seqPlayer->seqId = seqId;
+ gSeqLoadStatus[seqId] = SOUND_LOAD_STATUS_COMPLETE;
+ init_sequence_player(player);
+ seqPlayer->scriptState.depth = 0;
+ seqPlayer->delay = 0;
+ seqPlayer->enabled = TRUE;
+ seqPlayer->seqData = sequenceData;
+ seqPlayer->scriptState.pc = sequenceData;
+ return;
+ }
+ }
+
if (seqId >= gSequenceCount) {
return;
}
diff --git a/src/game/level_update.c b/src/game/level_update.c
index 84e07148..9a9e0fbd 100644
--- a/src/game/level_update.c
+++ b/src/game/level_update.c
@@ -1561,4 +1561,7 @@ void fake_lvl_init_from_save_file(void) {
save_file_move_cap_to_default_location();
select_mario_cam_mode();
set_yoshi_as_not_dead();
+ fadeout_music(30);
+
+ gChangeLevel = gLevelValues.entryLevel;
}
diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c
index 5a4fea1d..dd5dfdc6 100644
--- a/src/pc/lua/smlua.c
+++ b/src/pc/lua/smlua.c
@@ -143,6 +143,7 @@ void smlua_update(void) {
void smlua_shutdown(void) {
smlua_text_utils_reset_all();
+ smlua_audio_utils_reset_all();
smlua_cobject_allowlist_shutdown();
smlua_cpointer_allowlist_shutdown();
lua_State* L = gLuaState;
diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c
index 7c23fb56..5a50f171 100644
--- a/src/pc/lua/smlua_functions_autogen.c
+++ b/src/pc/lua/smlua_functions_autogen.c
@@ -24,6 +24,7 @@
#include "src/pc/lua/utils/smlua_collision_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_audio_utils.h"
#include "src/engine/surface_load.h"
#include "src/game/object_list_processor.h"
#include "src/game/behavior_actions.h"
@@ -13182,6 +13183,24 @@ int smlua_func_find_unimportant_object(UNUSED lua_State* L) {
return 1;
}
+/*
+int smlua_func_geo_choose_area_ext(lua_State* L) {
+ if(!smlua_functions_valid_param_count(L, 3)) { return 0; }
+
+ s32 callContext = smlua_to_integer(L, 1);
+ if (!gSmLuaConvertSuccess) { return 0; }
+ struct GraphNode* node = (struct GraphNode*)smlua_to_cobject(L, 2, LOT_GRAPHNODE);
+ if (!gSmLuaConvertSuccess) { return 0; }
+// Mat4 mtx = (Mat4)smlua_to_cobject(L, 3, LOT_???); <--- UNIMPLEMENTED
+ if (!gSmLuaConvertSuccess) { return 0; }
+
+ extern Gfx *geo_choose_area_ext(UNUSED s32 callContext, struct GraphNode *node, UNUSED Mat4 mtx);
+ UNIMPLEMENTED -->(L, geo_choose_area_ext(callContext, node, mtx));
+
+ return 1;
+}
+*/
+
int smlua_func_geo_offset_klepto_debug(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 3)) { return 0; }
@@ -14597,6 +14616,25 @@ int smlua_func_save_file_set_flags(lua_State* L) {
return 1;
}
+ /////////////////////////
+ // smlua_audio_utils.h //
+/////////////////////////
+
+int smlua_func_smlua_audio_utils_replace_sequence(lua_State* L) {
+ if(!smlua_functions_valid_param_count(L, 3)) { return 0; }
+
+ u8 sequenceId = smlua_to_integer(L, 1);
+ if (!gSmLuaConvertSuccess) { return 0; }
+ u8 bankId = smlua_to_integer(L, 2);
+ if (!gSmLuaConvertSuccess) { return 0; }
+ const char* m64Name = smlua_to_string(L, 3);
+ if (!gSmLuaConvertSuccess) { return 0; }
+
+ smlua_audio_utils_replace_sequence(sequenceId, bankId, m64Name);
+
+ return 1;
+}
+
/////////////////////////////
// smlua_collision_utils.h //
/////////////////////////////
@@ -16827,6 +16865,7 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "enable_time_stop_including_mario", smlua_func_enable_time_stop_including_mario);
smlua_bind_function(L, "find_object_with_behavior", smlua_func_find_object_with_behavior);
smlua_bind_function(L, "find_unimportant_object", smlua_func_find_unimportant_object);
+ //smlua_bind_function(L, "geo_choose_area_ext", smlua_func_geo_choose_area_ext); <--- UNIMPLEMENTED
smlua_bind_function(L, "geo_offset_klepto_debug", smlua_func_geo_offset_klepto_debug);
//smlua_bind_function(L, "geo_offset_klepto_held_object", smlua_func_geo_offset_klepto_held_object); <--- UNIMPLEMENTED
//smlua_bind_function(L, "geo_switch_anim_state", smlua_func_geo_switch_anim_state); <--- UNIMPLEMENTED
@@ -16930,6 +16969,9 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "save_file_get_total_star_count", smlua_func_save_file_get_total_star_count);
smlua_bind_function(L, "save_file_set_flags", smlua_func_save_file_set_flags);
+ // smlua_audio_utils.h
+ smlua_bind_function(L, "smlua_audio_utils_replace_sequence", smlua_func_smlua_audio_utils_replace_sequence);
+
// smlua_collision_utils.h
smlua_bind_function(L, "collision_find_surface_on_ray", smlua_func_collision_find_surface_on_ray);
smlua_bind_function(L, "get_water_surface_pseudo_floor", smlua_func_get_water_surface_pseudo_floor);
diff --git a/src/pc/lua/utils/smlua_audio_utils.c b/src/pc/lua/utils/smlua_audio_utils.c
new file mode 100644
index 00000000..7bb2e394
--- /dev/null
+++ b/src/pc/lua/utils/smlua_audio_utils.c
@@ -0,0 +1,119 @@
+#include "types.h"
+#include "pc/mods/mods.h"
+#include "pc/lua/smlua.h"
+#include "pc/debuglog.h"
+
+#define MAX_OVERRIDE 64
+
+struct AudioOverride {
+ bool enabled;
+ bool loaded;
+ const char* filename;
+ u64 length;
+ u8 bank;
+ u8* buffer;
+};
+
+struct AudioOverride sAudioOverrides[MAX_OVERRIDE] = { 0 };
+
+static smlua_audio_utils_reset(struct AudioOverride* override) {
+ if (override == NULL) { return; }
+
+ override->enabled = false;
+ override->loaded = false;
+
+ if (override->filename) {
+ free(override->filename);
+ override->filename = NULL;
+ }
+
+ override->length = 0;
+ override->bank = 0;
+
+ if (override->buffer != NULL) {
+ free(override->filename);
+ override->filename = NULL;
+ }
+}
+
+void smlua_audio_utils_reset_all(void) {
+ for (s32 i = 0; i < MAX_OVERRIDE; i++) {
+ smlua_audio_utils_reset(&sAudioOverrides[i]);
+ }
+}
+
+bool smlua_audio_utils_override(u8 sequenceId, s32* bankId, void** seqData) {
+ if (sequenceId >= MAX_OVERRIDE) { return false; }
+ struct AudioOverride* override = &sAudioOverrides[sequenceId];
+ if (!override->enabled) { return false; }
+
+ if (override->loaded) {
+ *seqData = override->buffer;
+ *bankId = override->bank;
+ return true;
+ }
+
+ static u8* buffer = NULL;
+ static long int length = 0;
+
+ FILE* fp = fopen(override->filename, "rb");
+ if (!fp) { return false; }
+ fseek(fp, 0L, SEEK_END);
+ length = ftell(fp);
+
+ buffer = malloc(length+1);
+ if (buffer == NULL) {
+ LOG_ERROR("Failed to malloc m64 sound file");
+ fclose(fp);
+ return false;
+ }
+
+ fseek(fp, 0L, SEEK_SET);
+ fread(buffer, length, 1, fp);
+
+ fclose(fp);
+
+ // cache
+ override->loaded = true;
+ override->buffer = buffer;
+ override->length = length;
+
+ *seqData = buffer;
+ *bankId = override->bank;
+ return true;
+}
+
+void smlua_audio_utils_replace_sequence(u8 sequenceId, u8 bankId, const char* m64Name) {
+ if (gLuaActiveMod == NULL) { return; }
+ if (sequenceId >= MAX_OVERRIDE) {
+ LOG_LUA("Invalid sequenceId given to smlua_audio_utils_replace_sequence(): %d", sequenceId);
+ return;
+ }
+
+ char m64path[SYS_MAX_PATH] = { 0 };
+ if (snprintf(m64path, SYS_MAX_PATH-1, "sound/%s.m64", m64Name) < 0) {
+ LOG_LUA("Could not find m64 at path: %s", m64path);
+ return;
+ }
+
+ for (s32 i = 0; i < gLuaActiveMod->fileCount; i++) {
+ struct ModFile* file = &gLuaActiveMod->files[i];
+ if (!strcmp(file->relativePath, m64path)) {
+
+ char fullPath[SYS_MAX_PATH] = { 0 };
+ if (snprintf(fullPath, SYS_MAX_PATH - 1, "%s/%s", gLuaActiveMod->basePath, m64path) < 0) {
+ LOG_ERROR("Failed to concat full path to m64: %s", m64Name);
+ return;
+ }
+
+ struct AudioOverride* override = &sAudioOverrides[sequenceId];
+ smlua_audio_utils_reset(override);
+ override->filename = strdup(fullPath);
+ override->enabled = true;
+ override->bank = bankId;
+ return;
+ }
+ }
+
+ LOG_LUA("Could not find m64 at path: %s", m64path);
+}
diff --git a/src/pc/lua/utils/smlua_audio_utils.h b/src/pc/lua/utils/smlua_audio_utils.h
new file mode 100644
index 00000000..c2891cc3
--- /dev/null
+++ b/src/pc/lua/utils/smlua_audio_utils.h
@@ -0,0 +1,8 @@
+#ifndef SMLUA_AUDIO_UTILS_H
+#define SMLUA_AUDIO_UTILS_H
+
+bool smlua_audio_utils_override(u8 sequenceId, s32* bankId, void** seqData);
+
+void smlua_audio_utils_replace_sequence(u8 sequenceId, u8 bankId, const char* m64Name);
+
+#endif
\ No newline at end of file
diff --git a/src/pc/mods/mod.c b/src/pc/mods/mod.c
index 1af16c45..c0b33fb6 100644
--- a/src/pc/mods/mod.c
+++ b/src/pc/mods/mod.c
@@ -295,6 +295,44 @@ static bool mod_load_files(struct Mod* mod, char* modName, char* fullPath) {
closedir(d);
}
}
+
+ // deal with sound directory
+ {
+ // concat sound directory
+ char soundPath[SYS_MAX_PATH] = { 0 };
+ if (!concat_path(soundPath, fullPath, "sound")) {
+ LOG_ERROR("Could not concat directory '%s' + '%s'", fullPath, "sound");
+ return false;
+ }
+
+ // open sound directory
+ struct dirent* dir = NULL;
+ DIR* d = opendir(soundPath);
+ if (d) {
+ // iterate mod directory
+ char path[SYS_MAX_PATH] = { 0 };
+ char relativePath[SYS_MAX_PATH] = { 0 };
+ while ((dir = readdir(d)) != NULL) {
+ // sanity check / fill path[]
+ if (!directory_sanity_check(dir, soundPath, path)) { continue; }
+ if (snprintf(relativePath, SYS_MAX_PATH - 1, "sound/%s", dir->d_name) < 0) {
+ LOG_ERROR("Could not concat sound path!");
+ return false;
+ }
+
+ // only consider m64 files
+ if (!str_ends_with(path, ".m64")) {
+ continue;
+ }
+
+ // allocate file
+ struct ModFile* file = mod_allocate_file(mod, relativePath);
+ if (file == NULL) { return false; }
+ }
+
+ closedir(d);
+ }
+ }
return true;
}
diff --git a/src/pc/network/network.c b/src/pc/network/network.c
index d4412299..dfa37403 100644
--- a/src/pc/network/network.c
+++ b/src/pc/network/network.c
@@ -4,6 +4,7 @@
#include "object_fields.h"
#include "object_constants.h"
#include "behavior_table.h"
+#include "src/game/hardcoded.h"
#ifdef DISCORD_SDK
#include "discord/discord.h"
#endif