diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua
index e7a840861..ca61340b4 100644
--- a/autogen/lua_definitions/constants.lua
+++ b/autogen/lua_definitions/constants.lua
@@ -10364,19 +10364,22 @@ HOOK_MAX = 53
--- @class LuaModMenuElementType
--- @type LuaModMenuElementType
-MOD_MENU_ELEMENT_BUTTON = 0
+MOD_MENU_ELEMENT_TEXT = 0
--- @type LuaModMenuElementType
-MOD_MENU_ELEMENT_CHECKBOX = 1
+MOD_MENU_ELEMENT_BUTTON = 1
--- @type LuaModMenuElementType
-MOD_MENU_ELEMENT_SLIDER = 2
+MOD_MENU_ELEMENT_CHECKBOX = 2
--- @type LuaModMenuElementType
-MOD_MENU_ELEMENT_INPUTBOX = 3
+MOD_MENU_ELEMENT_SLIDER = 3
--- @type LuaModMenuElementType
-MOD_MENU_ELEMENT_MAX = 4
+MOD_MENU_ELEMENT_INPUTBOX = 4
+
+--- @type LuaModMenuElementType
+MOD_MENU_ELEMENT_MAX = 5
--- @class HudDisplayFlags
diff --git a/autogen/lua_definitions/manual.lua b/autogen/lua_definitions/manual.lua
index 2f1b0bd85..452789335 100644
--- a/autogen/lua_definitions/manual.lua
+++ b/autogen/lua_definitions/manual.lua
@@ -160,8 +160,16 @@ function hook_on_sync_table_change(syncTable, field, tag, func)
-- ...
end
+--- @param message string The message for the text to show
+--- @return integer
+--- Hooks DJUI text into the mod menu
+function hook_mod_menu_text(message)
+ -- ...
+end
+
--- @param name string The text to show on the button
--- @param func fun(index:integer) The function that is called when the button is pressed
+--- @return integer
--- Hooks a DJUI button into the mod menu
function hook_mod_menu_button(name, func)
-- ...
@@ -170,6 +178,7 @@ end
--- @param name string The text to show on the left
--- @param defaultValue boolean The default state of the checkbox
--- @param func fun(index:integer, value:boolean) The function that is called when the checkbox is changed
+--- @return integer
--- Hooks a DJUI checkbox into the mod menu
function hook_mod_menu_checkbox(name, defaultValue, func)
-- ...
@@ -180,6 +189,7 @@ end
--- @param min integer The lowest the slider can go
--- @param max integer The highest the slider can go
--- @param func fun(index:integer, value:integer) The function that is called when the value of the slider changes
+--- @return integer
--- Hooks a DJUI slider into the mod menu
function hook_mod_menu_slider(name, defaultValue, min, max, func)
-- ...
@@ -189,6 +199,7 @@ end
--- @param defaultValue string The default text in the inputbox
--- @param stringLength integer The max length of the inputbox
--- @param func fun(index:integer, value:string) The function that is called when the value of the inputbox changes
+--- @return integer
--- Hooks a DJUI inputbox into the mod menu
function hook_mod_menu_inputbox(name, defaultValue, stringLength, func)
-- ...
diff --git a/docs/lua/constants.md b/docs/lua/constants.md
index 91480a8a1..de77b2f1a 100644
--- a/docs/lua/constants.md
+++ b/docs/lua/constants.md
@@ -3756,11 +3756,12 @@
### [enum LuaModMenuElementType](#LuaModMenuElementType)
| Identifier | Value |
| :--------- | :---- |
-| MOD_MENU_ELEMENT_BUTTON | 0 |
-| MOD_MENU_ELEMENT_CHECKBOX | 1 |
-| MOD_MENU_ELEMENT_SLIDER | 2 |
-| MOD_MENU_ELEMENT_INPUTBOX | 3 |
-| MOD_MENU_ELEMENT_MAX | 4 |
+| MOD_MENU_ELEMENT_TEXT | 0 |
+| MOD_MENU_ELEMENT_BUTTON | 1 |
+| MOD_MENU_ELEMENT_CHECKBOX | 2 |
+| MOD_MENU_ELEMENT_SLIDER | 3 |
+| MOD_MENU_ELEMENT_INPUTBOX | 4 |
+| MOD_MENU_ELEMENT_MAX | 5 |
[:arrow_up_small:](#)
diff --git a/docs/lua/guides/hooks.md b/docs/lua/guides/hooks.md
index 6033e553a..020a86c59 100644
--- a/docs/lua/guides/hooks.md
+++ b/docs/lua/guides/hooks.md
@@ -9,6 +9,7 @@ Hooks are a way for SM64 to trigger Lua code, whereas the functions listed in [f
- [hook_event](#hook_event)
- [hook_mario_action](#hook_mario_action)
- [hook_on_sync_table_change](#hook_on_sync_table_change)
+- [hook_mod_menu_text](#hook_mod_menu_text)
- [hook_mod_menu_button](#hook_mod_menu_button)
- [hook_mod_menu_checkbox](#hook_mod_menu_checkbox)
- [hook_mod_menu_slider](#hook_mod_menu_slider)
@@ -286,6 +287,25 @@ gGlobalSyncTable.testingField = "hello"
+## [hook_mod_menu_text](#hook_mod_menu_text)
+`hook_mod_menu_text()` allows Lua to add text labels to their designated mod menu submenu.
+
+### Parameters
+
+| Field | Type |
+| ----- | ---- |
+| message | `string` |
+
+### Lua Example
+
+```lua
+hook_mod_menu_text("Rise and shine, Mr. Freeman.")
+```
+
+[:arrow_up_small:](#)
+
+
+
## [hook_mod_menu_button](#hook_mod_menu_button)
`hook_mod_menu_button()` allows Lua to add buttons to their designated mod menu submenu.
@@ -293,7 +313,7 @@ gGlobalSyncTable.testingField = "hello"
| Field | Type |
| ----- | ---- |
-| message | `string` |
+| name | `string` |
| func | `Lua Function` (`integer` index) |
### Lua Example
@@ -329,7 +349,7 @@ hook_mod_menu_button("Open Menu 2", on_open_menu)
| Field | Type |
| ----- | ---- |
-| message | `string` |
+| name | `string` |
| defaultValue | `boolean` |
| func | `Lua Function` (`integer` index, `boolean` value) |
@@ -365,7 +385,7 @@ hook_mod_menu_checkbox("Noclip Mode", false, on_set_player_mode)
| Field | Type |
| ----- | ---- |
-| message | `string` |
+| name | `string` |
| defaultValue | `integer` |
| min | `integer` |
| max | `integer` |
@@ -394,7 +414,7 @@ hook_mod_menu_slider("Time Scale", 1, 0, 10, on_set_time_scale)
| Field | Type |
| ----- | ---- |
-| message | `string` |
+| name | `string` |
| defaultValue | `string` |
| stringLength | `integer` |
| func | `Lua Function` (`integer` index, `string` value) |
diff --git a/src/pc/djui/djui_panel_mod_menu.c b/src/pc/djui/djui_panel_mod_menu.c
index a2ff23fd8..9ee16acb3 100644
--- a/src/pc/djui/djui_panel_mod_menu.c
+++ b/src/pc/djui/djui_panel_mod_menu.c
@@ -28,14 +28,14 @@ void djui_panel_mod_menu_mod_button(struct DjuiBase* caller) {
}
}
-void djui_panel_mod_menu_mod_checkbox(struct DjuiBase* caller) {
+static void djui_panel_mod_menu_mod_checkbox(struct DjuiBase* caller) {
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[caller->tag];
smlua_call_mod_menu_element_hook(hooked, caller->tag);
struct DjuiCheckbox* checkbox = (struct DjuiCheckbox*)caller;
djui_text_set_text(checkbox->text, hooked->name);
}
-void djui_panel_mod_menu_mod_slider(struct DjuiBase* caller) {
+static void djui_panel_mod_menu_mod_slider(struct DjuiBase* caller) {
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[caller->tag];
smlua_call_mod_menu_element_hook(hooked, caller->tag);
struct DjuiSlider* slider = (struct DjuiSlider*)caller;
@@ -52,6 +52,17 @@ static void djui_panel_mod_menu_mod_inputbox(struct DjuiBase* caller) {
static void djui_panel_mod_menu_mod_create_element(struct DjuiBase* parent, int i) {
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[i];
switch (hooked->element) {
+ case MOD_MENU_ELEMENT_TEXT: {
+ struct DjuiText* text = djui_text_create(parent, hooked->name);
+ djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_color(&text->base, 220, 220, 220, 255);
+ djui_base_set_size(&text->base, 1.0f, 64);
+ djui_base_set_alignment(&text->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
+ djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP);
+ djui_text_set_drop_shadow(text, 64, 64, 64, 100);
+ text->base.tag = i;
+ break;
+ }
case MOD_MENU_ELEMENT_BUTTON: {
struct DjuiButton* button = djui_button_create(parent, hooked->name, DJUI_BUTTON_STYLE_NORMAL, djui_panel_mod_menu_mod_button);
button->base.tag = i;
diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c
index ff8753821..5f8aa12d5 100644
--- a/src/pc/lua/smlua_constants_autogen.c
+++ b/src/pc/lua/smlua_constants_autogen.c
@@ -3621,11 +3621,12 @@ char gSmluaConstants[] = ""
"ACTION_HOOK_EVERY_FRAME=0\n"
"ACTION_HOOK_GRAVITY=1\n"
"ACTION_HOOK_MAX=2\n"
-"MOD_MENU_ELEMENT_BUTTON=0\n"
-"MOD_MENU_ELEMENT_CHECKBOX=1\n"
-"MOD_MENU_ELEMENT_SLIDER=2\n"
-"MOD_MENU_ELEMENT_INPUTBOX=3\n"
-"MOD_MENU_ELEMENT_MAX=4\n"
+"MOD_MENU_ELEMENT_TEXT=0\n"
+"MOD_MENU_ELEMENT_BUTTON=1\n"
+"MOD_MENU_ELEMENT_CHECKBOX=2\n"
+"MOD_MENU_ELEMENT_SLIDER=3\n"
+"MOD_MENU_ELEMENT_INPUTBOX=4\n"
+"MOD_MENU_ELEMENT_MAX=5\n"
"HUD_DISPLAY_LIVES=0\n"
"HUD_DISPLAY_COINS=1\n"
"HUD_DISPLAY_STARS=2\n"
diff --git a/src/pc/lua/smlua_hooks.c b/src/pc/lua/smlua_hooks.c
index 39d68e636..6eee3dbaa 100644
--- a/src/pc/lua/smlua_hooks.c
+++ b/src/pc/lua/smlua_hooks.c
@@ -1984,6 +1984,38 @@ int smlua_hook_on_sync_table_change(lua_State* L) {
struct LuaHookedModMenuElement gHookedModMenuElements[MAX_HOOKED_MOD_MENU_ELEMENTS] = { 0 };
int gHookedModMenuElementsCount = 0;
+int smlua_hook_mod_menu_text(lua_State* L) {
+ if (L == NULL) { return 0; }
+ if (!smlua_functions_valid_param_count(L, 1)) { return 0; }
+
+ if (gHookedModMenuElementsCount >= MAX_HOOKED_MOD_MENU_ELEMENTS) {
+ LOG_LUA_LINE("Hooked mod menu element exceeded maximum references!");
+ return 0;
+ }
+
+ const char* name = smlua_to_string(L, 1);
+ if (name == NULL || strlen(name) == 0 || !gSmLuaConvertSuccess) {
+ LOG_LUA_LINE("Hook mod menu element: tried to hook invalid element");
+ return 0;
+ }
+
+ struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[gHookedModMenuElementsCount];
+ hooked->element = MOD_MENU_ELEMENT_TEXT;
+ snprintf(hooked->name, 64, "%s", name);
+ hooked->boolValue = false;
+ hooked->uintValue = 0;
+ hooked->stringValue[0] = '\0';
+ hooked->length = 0;
+ hooked->sliderMin = 0;
+ hooked->sliderMax = 0;
+ hooked->reference = 0;
+ hooked->mod = gLuaActiveMod;
+
+ lua_pushinteger(L, gHookedModMenuElementsCount);
+ gHookedModMenuElementsCount++;
+ return 1;
+}
+
int smlua_hook_mod_menu_button(lua_State* L) {
if (L == NULL) { return 0; }
if (!smlua_functions_valid_param_count(L, 2)) { return 0; }
@@ -2017,6 +2049,7 @@ int smlua_hook_mod_menu_button(lua_State* L) {
hooked->reference = ref;
hooked->mod = gLuaActiveMod;
+ lua_pushinteger(L, gHookedModMenuElementsCount);
gHookedModMenuElementsCount++;
return 1;
}
@@ -2060,6 +2093,7 @@ int smlua_hook_mod_menu_checkbox(lua_State* L) {
hooked->reference = ref;
hooked->mod = gLuaActiveMod;
+ lua_pushinteger(L, gHookedModMenuElementsCount);
gHookedModMenuElementsCount++;
return 1;
}
@@ -2115,6 +2149,7 @@ int smlua_hook_mod_menu_slider(lua_State* L) {
hooked->reference = ref;
hooked->mod = gLuaActiveMod;
+ lua_pushinteger(L, gHookedModMenuElementsCount);
gHookedModMenuElementsCount++;
return 1;
}
@@ -2165,6 +2200,7 @@ int smlua_hook_mod_menu_inputbox(lua_State* L) {
hooked->reference = ref;
hooked->mod = gLuaActiveMod;
+ lua_pushinteger(L, gHookedModMenuElementsCount);
gHookedModMenuElementsCount++;
return 1;
}
@@ -2275,6 +2311,8 @@ void smlua_call_mod_menu_element_hook(struct LuaHookedModMenuElement* hooked, in
u8 params = 2;
lua_pushinteger(L, index);
switch (hooked->element) {
+ case MOD_MENU_ELEMENT_TEXT:
+ params = 1;
case MOD_MENU_ELEMENT_BUTTON:
params = 1;
break;
@@ -2336,7 +2374,7 @@ void smlua_clear_hooks(void) {
for (int i = 0; i < gHookedModMenuElementsCount; i++) {
struct LuaHookedModMenuElement* hooked = &gHookedModMenuElements[i];
- hooked->element = MOD_MENU_ELEMENT_BUTTON;
+ hooked->element = MOD_MENU_ELEMENT_TEXT;
hooked->name[0] = '\0';
hooked->boolValue = false;
hooked->uintValue = 0;
@@ -2388,6 +2426,7 @@ void smlua_bind_hooks(void) {
smlua_bind_function(L, "hook_chat_command", smlua_hook_chat_command);
smlua_bind_function(L, "hook_on_sync_table_change", smlua_hook_on_sync_table_change);
smlua_bind_function(L, "hook_behavior", smlua_hook_behavior);
+ smlua_bind_function(L, "hook_mod_menu_text", smlua_hook_mod_menu_text);
smlua_bind_function(L, "hook_mod_menu_button", smlua_hook_mod_menu_button);
smlua_bind_function(L, "hook_mod_menu_checkbox", smlua_hook_mod_menu_checkbox);
smlua_bind_function(L, "hook_mod_menu_slider", smlua_hook_mod_menu_slider);
diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h
index f55ad4981..eb7119fac 100644
--- a/src/pc/lua/smlua_hooks.h
+++ b/src/pc/lua/smlua_hooks.h
@@ -140,6 +140,7 @@ static const char* LuaActionHookTypeArgName[] = {
#define MAX_HOOKED_MOD_MENU_ELEMENTS 256
enum LuaModMenuElementType {
+ MOD_MENU_ELEMENT_TEXT,
MOD_MENU_ELEMENT_BUTTON,
MOD_MENU_ELEMENT_CHECKBOX,
MOD_MENU_ELEMENT_SLIDER,