diff --git a/autogen/convert_structs.py b/autogen/convert_structs.py index 20dc2fed8..4f53c2906 100644 --- a/autogen/convert_structs.py +++ b/autogen/convert_structs.py @@ -17,6 +17,7 @@ in_files = [ "src/pc/djui/djui_theme.h", "src/game/object_helpers.h", "src/game/mario_step.h", + "src/game/ingame_menu.h", "src/pc/lua/utils/smlua_anim_utils.h", "src/pc/lua/utils/smlua_misc_utils.h", "src/pc/lua/utils/smlua_camera_utils.h", @@ -96,6 +97,7 @@ override_field_invisible = { "FnGraphNode": [ "luaTokenIndex" ], "Object": [ "firstSurface" ], "ModAudio": [ "sound", "decoder", "buffer", "bufferSize", "sampleCopiesTail" ], + "DialogEntry": [ "str" ] } override_field_deprecated = { @@ -135,6 +137,7 @@ override_field_immutable = { "FirstPersonCamera": [ "enabled" ], "ModAudio": [ "isStream", "loaded" ], "Gfx": [ "w0", "w1" ], # to protect from invalid type conversions + "DialogEntry": [ "unused", "linesPerBox", "leftOffset", "width", "str", "text"] } override_field_version_excludes = { @@ -146,6 +149,7 @@ override_allowed_structs = { "src/pc/network/network.h": [ "ServerSettings", "NametagsSettings" ], "src/pc/djui/djui_types.h": [ "DjuiColor" ], "src/game/player_palette.h": [ "PlayerPalette" ], + "src/game/ingame_menu.h" : [ "DialogEntry" ], "include/PR/gbi.h": [ "Gfx", "Vtx" ] } diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 59c0e2bbd..72671d418 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -11521,6 +11521,13 @@ function smlua_text_utils_reset_all() -- ... end +--- @param dialogId DialogId +--- @return DialogEntry +--- Gets the DialogEntry struct for the given `dialogId` +function smlua_text_utils_dialog_get(dialogId) + -- ... +end + --- @param dialogId DialogId --- @param unused integer --- @param linesPerBox integer @@ -11532,6 +11539,13 @@ function smlua_text_utils_dialog_replace(dialogId, unused, linesPerBox, leftOffs -- ... end +--- @param dialogId DialogId +--- @return boolean +--- Returns whether the dialog with the given ID has been replaced +function smlua_text_utils_dialog_is_replaced(dialogId) + -- ... +end + --- @param courseNum integer --- @param courseName string --- @param act1 string diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua index be9dc46a9..46f71ca88 100644 --- a/autogen/lua_definitions/structs.lua +++ b/autogen/lua_definitions/structs.lua @@ -592,6 +592,13 @@ --- @field public second integer --- @field public year integer +--- @class DialogEntry +--- @field public leftOffset integer +--- @field public linesPerBox integer +--- @field public text string +--- @field public unused integer +--- @field public width integer + --- @class DisplayListNode --- @field public displayList Pointer_Gfx --- @field public next DisplayListNode diff --git a/docs/lua/functions-6.md b/docs/lua/functions-6.md index 6883780e3..031d8310a 100644 --- a/docs/lua/functions-6.md +++ b/docs/lua/functions-6.md @@ -6429,6 +6429,29 @@ Resets every modified dialog back to vanilla
+## [smlua_text_utils_dialog_get](#smlua_text_utils_dialog_get) + +### Description +Gets the DialogEntry struct for the given `dialogId` + +### Lua Example +`local DialogEntryValue = smlua_text_utils_dialog_get(dialogId)` + +### Parameters +| Field | Type | +| ----- | ---- | +| dialogId | [enum DialogId](constants.md#enum-DialogId) | + +### Returns +[DialogEntry](structs.md#DialogEntry) + +### C Prototype +`struct DialogEntry* smlua_text_utils_dialog_get(enum DialogId dialogId);` + +[:arrow_up_small:](#) + +
+ ## [smlua_text_utils_dialog_replace](#smlua_text_utils_dialog_replace) ### Description @@ -6457,6 +6480,29 @@ Replaces `dialogId` with a custom one
+## [smlua_text_utils_dialog_is_replaced](#smlua_text_utils_dialog_is_replaced) + +### Description +Returns whether the dialog with the given ID has been replaced + +### Lua Example +`local booleanValue = smlua_text_utils_dialog_is_replaced(dialogId)` + +### Parameters +| Field | Type | +| ----- | ---- | +| dialogId | [enum DialogId](constants.md#enum-DialogId) | + +### Returns +- `boolean` + +### C Prototype +`bool smlua_text_utils_dialog_is_replaced(enum DialogId dialogId);` + +[:arrow_up_small:](#) + +
+ ## [smlua_text_utils_course_acts_replace](#smlua_text_utils_course_acts_replace) ### Description diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 2f17aca04..3d4ded489 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -2057,7 +2057,9 @@ - smlua_text_utils.h - [smlua_text_utils_reset_all](functions-6.md#smlua_text_utils_reset_all) + - [smlua_text_utils_dialog_get](functions-6.md#smlua_text_utils_dialog_get) - [smlua_text_utils_dialog_replace](functions-6.md#smlua_text_utils_dialog_replace) + - [smlua_text_utils_dialog_is_replaced](functions-6.md#smlua_text_utils_dialog_is_replaced) - [smlua_text_utils_course_acts_replace](functions-6.md#smlua_text_utils_course_acts_replace) - [smlua_text_utils_secret_star_replace](functions-6.md#smlua_text_utils_secret_star_replace) - [smlua_text_utils_course_name_replace](functions-6.md#smlua_text_utils_course_name_replace) diff --git a/docs/lua/structs.md b/docs/lua/structs.md index 65bf417a1..f9fa72a49 100644 --- a/docs/lua/structs.md +++ b/docs/lua/structs.md @@ -23,6 +23,7 @@ - [CutsceneSplinePoint](#CutsceneSplinePoint) - [CutsceneVariable](#CutsceneVariable) - [DateTime](#DateTime) +- [DialogEntry](#DialogEntry) - [DisplayListNode](#DisplayListNode) - [DjuiColor](#DjuiColor) - [DjuiInteractableTheme](#DjuiInteractableTheme) @@ -877,6 +878,20 @@
+## [DialogEntry](#DialogEntry) + +| Field | Type | Access | +| ----- | ---- | ------ | +| leftOffset | `integer` | read-only | +| linesPerBox | `integer` | read-only | +| text | `string` | read-only | +| unused | `integer` | read-only | +| width | `integer` | read-only | + +[:arrow_up_small:](#) + +
+ ## [DisplayListNode](#DisplayListNode) | Field | Type | Access | diff --git a/src/game/ingame_menu.h b/src/game/ingame_menu.h index 6185607ab..a3816fc6f 100644 --- a/src/game/ingame_menu.h +++ b/src/game/ingame_menu.h @@ -39,11 +39,12 @@ extern s8 gHudFlash; struct DialogEntry { - /*0x00*/ u32 unused; - /*0x04*/ s8 linesPerBox; - /*0x06*/ s16 leftOffset; - /*0x08*/ s16 width; - /*0x0C*/ const u8 *str; + u32 unused; /*0x00*/ + s8 linesPerBox; /*0x04*/ + s16 leftOffset; /*0x06*/ + s16 width; /*0x08*/ + const u8 *str; /*0x0C*/ + char* text; }; // EU only diff --git a/src/game/level_info.c b/src/game/level_info.c index 835ceca31..98aaeb962 100644 --- a/src/game/level_info.c +++ b/src/game/level_info.c @@ -17,7 +17,7 @@ extern s32 gInGameLanguage; #include "eu_translation.h" #endif -static const struct { const char *str; u8 c; u8 menu; } sSm64CharMap[] = { +const struct { const char *str; u8 c; u8 menu; } sSm64CharMap[] = { // Digits { "0", 0x00, 1 }, { "1", 0x01, 1 }, { "2", 0x02, 1 }, { "3", 0x03, 1 }, { "4", 0x04, 1 }, @@ -58,6 +58,10 @@ static const struct { const char *str; u8 c; u8 menu; } sSm64CharMap[] = { { "~", 0xF7, 0 }, // tilde // Symbols + { "/", 0xD0, 0 }, + { "the", 0xD1, 0 }, + { "you", 0xD2, 0 }, + { "[%]", 0xE0, 0 }, // The number of extra stars required to unlock a star door { "[A]", 0x54, 0 }, // bold A { "[B]", 0x55, 0 }, // bold B { "[C]", 0x56, 0 }, // bold C @@ -71,6 +75,7 @@ static const struct { const char *str; u8 c; u8 menu; } sSm64CharMap[] = { { "+", 0xF9, 1 }, // coin { "@", 0xFA, 1 }, // star filled { "*", 0xFB, 1 }, // multiply + { "•", 0xFC, 0 }, { "$", 0xFD, 0 }, // star empty { "\n", 0xFE, 1 }, // New line { NULL, 0xFF, 1 }, // Null terminator diff --git a/src/pc/lua/smlua_cobject_autogen.c b/src/pc/lua/smlua_cobject_autogen.c index 8a8d49574..4d77a56a0 100644 --- a/src/pc/lua/smlua_cobject_autogen.c +++ b/src/pc/lua/smlua_cobject_autogen.c @@ -11,6 +11,7 @@ #include "src/pc/djui/djui_theme.h" #include "src/game/object_helpers.h" #include "src/game/mario_step.h" +#include "src/game/ingame_menu.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_camera_utils.h" @@ -803,6 +804,15 @@ static struct LuaObjectField sDateTimeFields[LUA_DATE_TIME_FIELD_COUNT] = { { "year", LVT_S32, offsetof(struct DateTime, year), false, LOT_NONE, 1, sizeof(s32) }, }; +#define LUA_DIALOG_ENTRY_FIELD_COUNT 5 +static struct LuaObjectField sDialogEntryFields[LUA_DIALOG_ENTRY_FIELD_COUNT] = { + { "leftOffset", LVT_S16, offsetof(struct DialogEntry, leftOffset), true, LOT_NONE, 1, sizeof(s16) }, + { "linesPerBox", LVT_S8, offsetof(struct DialogEntry, linesPerBox), true, LOT_NONE, 1, sizeof(s8) }, + { "text", LVT_STRING_P, offsetof(struct DialogEntry, text), true, LOT_NONE, 1, sizeof(char*) }, + { "unused", LVT_U32, offsetof(struct DialogEntry, unused), true, LOT_NONE, 1, sizeof(u32) }, + { "width", LVT_S16, offsetof(struct DialogEntry, width), true, LOT_NONE, 1, sizeof(s16) }, +}; + #define LUA_DISPLAY_LIST_NODE_FIELD_COUNT 3 static struct LuaObjectField sDisplayListNodeFields[LUA_DISPLAY_LIST_NODE_FIELD_COUNT] = { { "displayList", LVT_COBJECT_P, offsetof(struct DisplayListNode, displayList), false, LOT_GFX, 1, sizeof(Gfx*) }, @@ -2863,6 +2873,7 @@ struct LuaObjectTable sLuaObjectAutogenTable[LOT_AUTOGEN_MAX - LOT_AUTOGEN_MIN] { LOT_CUTSCENESPLINEPOINT, sCutsceneSplinePointFields, LUA_CUTSCENE_SPLINE_POINT_FIELD_COUNT }, { LOT_CUTSCENEVARIABLE, sCutsceneVariableFields, LUA_CUTSCENE_VARIABLE_FIELD_COUNT }, { LOT_DATETIME, sDateTimeFields, LUA_DATE_TIME_FIELD_COUNT }, + { LOT_DIALOGENTRY, sDialogEntryFields, LUA_DIALOG_ENTRY_FIELD_COUNT }, { LOT_DISPLAYLISTNODE, sDisplayListNodeFields, LUA_DISPLAY_LIST_NODE_FIELD_COUNT }, { LOT_DJUICOLOR, sDjuiColorFields, LUA_DJUI_COLOR_FIELD_COUNT }, { LOT_DJUIINTERACTABLETHEME, sDjuiInteractableThemeFields, LUA_DJUI_INTERACTABLE_THEME_FIELD_COUNT }, @@ -2988,6 +2999,7 @@ const char *sLuaLotNames[] = { [LOT_CUTSCENESPLINEPOINT] = "CutsceneSplinePoint", [LOT_CUTSCENEVARIABLE] = "CutsceneVariable", [LOT_DATETIME] = "DateTime", + [LOT_DIALOGENTRY] = "DialogEntry", [LOT_DISPLAYLISTNODE] = "DisplayListNode", [LOT_DJUICOLOR] = "DjuiColor", [LOT_DJUIINTERACTABLETHEME] = "DjuiInteractableTheme", diff --git a/src/pc/lua/smlua_cobject_autogen.h b/src/pc/lua/smlua_cobject_autogen.h index 098f79cce..ff6fb9490 100644 --- a/src/pc/lua/smlua_cobject_autogen.h +++ b/src/pc/lua/smlua_cobject_autogen.h @@ -44,6 +44,7 @@ enum LuaObjectAutogenType { LOT_CUTSCENESPLINEPOINT, LOT_CUTSCENEVARIABLE, LOT_DATETIME, + LOT_DIALOGENTRY, LOT_DISPLAYLISTNODE, LOT_DJUICOLOR, LOT_DJUIINTERACTABLETHEME, diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index f02fa04d6..18e3d3019 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -34322,6 +34322,23 @@ int smlua_func_smlua_text_utils_reset_all(UNUSED lua_State* L) { return 1; } +int smlua_func_smlua_text_utils_dialog_get(lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 1) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_dialog_get", 1, top); + return 0; + } + + int dialogId = smlua_to_integer(L, 1); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_dialog_get"); return 0; } + + smlua_push_object(L, LOT_DIALOGENTRY, smlua_text_utils_dialog_get(dialogId), NULL); + + return 1; +} + int smlua_func_smlua_text_utils_dialog_replace(lua_State* L) { if (L == NULL) { return 0; } @@ -34349,6 +34366,23 @@ int smlua_func_smlua_text_utils_dialog_replace(lua_State* L) { return 1; } +int smlua_func_smlua_text_utils_dialog_is_replaced(lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 1) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_dialog_is_replaced", 1, top); + return 0; + } + + int dialogId = smlua_to_integer(L, 1); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_dialog_is_replaced"); return 0; } + + lua_pushboolean(L, smlua_text_utils_dialog_is_replaced(dialogId)); + + return 1; +} + int smlua_func_smlua_text_utils_course_acts_replace(lua_State* L) { if (L == NULL) { return 0; } @@ -37386,7 +37420,9 @@ void smlua_bind_functions_autogen(void) { // smlua_text_utils.h smlua_bind_function(L, "smlua_text_utils_reset_all", smlua_func_smlua_text_utils_reset_all); + smlua_bind_function(L, "smlua_text_utils_dialog_get", smlua_func_smlua_text_utils_dialog_get); smlua_bind_function(L, "smlua_text_utils_dialog_replace", smlua_func_smlua_text_utils_dialog_replace); + smlua_bind_function(L, "smlua_text_utils_dialog_is_replaced", smlua_func_smlua_text_utils_dialog_is_replaced); smlua_bind_function(L, "smlua_text_utils_course_acts_replace", smlua_func_smlua_text_utils_course_acts_replace); smlua_bind_function(L, "smlua_text_utils_secret_star_replace", smlua_func_smlua_text_utils_secret_star_replace); smlua_bind_function(L, "smlua_text_utils_course_name_replace", smlua_func_smlua_text_utils_course_name_replace); diff --git a/src/pc/lua/utils/smlua_text_utils.c b/src/pc/lua/utils/smlua_text_utils.c index 89d525f9c..6c72f7ef0 100644 --- a/src/pc/lua/utils/smlua_text_utils.c +++ b/src/pc/lua/utils/smlua_text_utils.c @@ -18,8 +18,39 @@ extern s32 gInGameLanguage; static bool sReplacedDialog[DIALOG_COUNT] = { 0 }; +#define INVALID_COURSE_NUM(courseNum) (smlua_level_util_get_info_from_course_num(courseNum) == NULL && !COURSE_IS_VALID_COURSE(courseNum)) + +extern const struct { const char *str; u8 c; u8 menu; } sSm64CharMap[]; void convert_string_sm64_to_ascii(char *strAscii, const u8 *str64); +static size_t measure_converted_sm64_string(const u8* str64) { + size_t len = 0; + + for (size_t i = 0; str64[i] != 0xFF; i++) { + for (s32 j = 0; sSm64CharMap[j].str != NULL; j++) { + if (sSm64CharMap[j].c == str64[i]) { + len += strlen(sSm64CharMap[j].str); + break; + } + } + } + + return len; +} + +char* get_dialog_text_ascii(struct DialogEntry *dialog) { + if (!dialog) { return NULL; } + + size_t len = measure_converted_sm64_string(dialog->str); + + char* asciiStr = malloc(len + 1); + if (!asciiStr) return NULL; + + convert_string_sm64_to_ascii(asciiStr, dialog->str); + + return asciiStr; +} + /* --------------------------------------------------- Mapping gReplacedCourseActNameTable <-> seg2 tables @@ -96,6 +127,15 @@ void smlua_text_utils_init(void) { ); } + for (s32 i = 0; i < DIALOG_COUNT; i++) { + struct DialogEntry *dialog = smlua_text_utils_dialog_get(i); + char* dialogText = get_dialog_text_ascii(dialog); + + free(dialog->text); + + dialog->text = dialogText; + } + sSmluaTextUtilsInited = true; } @@ -176,7 +216,10 @@ void smlua_text_utils_reset_all(void) { const struct DialogEntry *dialogOrig = segmented_to_virtual(dialogTableOrg[i]); struct DialogEntry *dialog = segmented_to_virtual(dialogTable[i]); free((u8*)dialog->str); + free(dialog->text); + memcpy(dialog, dialogOrig, sizeof(struct DialogEntry)); + dialog->text = get_dialog_text_ascii(dialog); sReplacedDialog[i] = false; } @@ -196,8 +239,8 @@ void smlua_text_utils_reset_all(void) { } } -void smlua_text_utils_dialog_replace(enum DialogId dialogId, UNUSED u32 unused, s8 linesPerBox, s16 leftOffset, s16 width, const char* str) { - if (dialogId >= DIALOG_COUNT) { return; } +struct DialogEntry* smlua_text_utils_dialog_get(enum DialogId dialogId){ + if (dialogId >= DIALOG_COUNT) { return NULL; } void **dialogTable = NULL; @@ -218,19 +261,38 @@ void smlua_text_utils_dialog_replace(enum DialogId dialogId, UNUSED u32 unused, #endif struct DialogEntry *dialog = segmented_to_virtual(dialogTable[dialogId]); + return dialog; +} + +void smlua_text_utils_dialog_replace(enum DialogId dialogId, UNUSED u32 unused, s8 linesPerBox, s16 leftOffset, s16 width, const char* str) { + struct DialogEntry *dialog = smlua_text_utils_dialog_get(dialogId); + + if (!dialog) { return; } if (sReplacedDialog[dialogId]) { free((u8*)dialog->str); } + free(dialog->text); + dialog->unused = unused; dialog->linesPerBox = linesPerBox; dialog->leftOffset = leftOffset; dialog->width = width; dialog->str = smlua_text_utils_convert(str); + dialog->text = strdup(str); + sReplacedDialog[dialogId] = true; } +bool smlua_text_utils_dialog_is_replaced(enum DialogId dialogId) { + if (dialogId >= DIALOG_COUNT) { + return false; + } + + return sReplacedDialog[dialogId]; +} + void smlua_text_utils_course_acts_replace(s16 courseNum, const char* courseName, const char* act1, const char* act2, const char* act3, const char* act4, const char* act5, const char* act6) { if (!COURSE_IS_VALID_COURSE(courseNum)) { return; } diff --git a/src/pc/lua/utils/smlua_text_utils.h b/src/pc/lua/utils/smlua_text_utils.h index f6cc69901..6d9d53a17 100644 --- a/src/pc/lua/utils/smlua_text_utils.h +++ b/src/pc/lua/utils/smlua_text_utils.h @@ -30,8 +30,12 @@ void smlua_text_utils_init(void); void smlua_text_utils_shutdown(void); /* |description|Resets every modified dialog back to vanilla|descriptionEnd|*/ void smlua_text_utils_reset_all(void); +/* |description|Gets the DialogEntry struct for the given `dialogId`|descriptionEnd| */ +struct DialogEntry* smlua_text_utils_dialog_get(enum DialogId dialogId); /* |description|Replaces `dialogId` with a custom one|descriptionEnd| */ void smlua_text_utils_dialog_replace(enum DialogId dialogId, u32 unused, s8 linesPerBox, s16 leftOffset, s16 width, const char* str); +/* |description|Returns whether the dialog with the given ID has been replaced|descriptionEnd| */ +bool smlua_text_utils_dialog_is_replaced(enum DialogId dialogId); /* |description|Replaces the act names of `courseNum`|descriptionEnd| */ void smlua_text_utils_course_acts_replace(s16 courseNum, const char* courseName, const char* act1, const char* act2, const char* act3, const char* act4, const char* act5, const char* act6); /* |description|Replaces the secret star course name of `courseNum` with `courseName`|descriptionEnd| */ diff --git a/text/define_text.inc.c b/text/define_text.inc.c index 3ac7fdc84..4a932ffb5 100644 --- a/text/define_text.inc.c +++ b/text/define_text.inc.c @@ -9,7 +9,7 @@ #undef DEFINE_DIALOG #define DEFINE_DIALOG(id, unused, linesPerBox, leftOffset, width, _) \ static const struct DialogEntry dialog_entry_orig_ ## id = { \ - unused, linesPerBox, leftOffset, width, dialog_text_ ## id \ + unused, linesPerBox, leftOffset, width, dialog_text_ ## id, NULL \ }; #include "dialogs.h" @@ -17,7 +17,7 @@ #undef DEFINE_DIALOG #define DEFINE_DIALOG(id, unused, linesPerBox, leftOffset, width, _) \ static struct DialogEntry dialog_entry_ ## id = { \ - unused, linesPerBox, leftOffset, width, dialog_text_ ## id \ + unused, linesPerBox, leftOffset, width, dialog_text_ ## id, NULL \ }; #include "dialogs.h"