Add smlua_text_utils_dialog_get_text and some other dialog functions (#860)

* Add new dialog functions

* Add missing symbols to charmap

* Fix the crashing

* Add braces to if statement

* Implement Isaac's suggestion

* Add override return type to autogen

* Update comment

* Add text field to `DialogEntry`

* wtf??

* Peachy requests
This commit is contained in:
Beckowl 2025-06-28 09:28:28 -03:00 committed by GitHub
parent 075e76b71a
commit 7fdded5a8e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 219 additions and 10 deletions

View file

@ -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" ]
}

View file

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

View file

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

View file

@ -6429,6 +6429,29 @@ Resets every modified dialog back to vanilla
<br />
## [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:](#)
<br />
## [smlua_text_utils_dialog_replace](#smlua_text_utils_dialog_replace)
### Description
@ -6457,6 +6480,29 @@ Replaces `dialogId` with a custom one
<br />
## [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:](#)
<br />
## [smlua_text_utils_course_acts_replace](#smlua_text_utils_course_acts_replace)
### Description

View file

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

View file

@ -23,6 +23,7 @@
- [CutsceneSplinePoint](#CutsceneSplinePoint)
- [CutsceneVariable](#CutsceneVariable)
- [DateTime](#DateTime)
- [DialogEntry](#DialogEntry)
- [DisplayListNode](#DisplayListNode)
- [DjuiColor](#DjuiColor)
- [DjuiInteractableTheme](#DjuiInteractableTheme)
@ -877,6 +878,20 @@
<br />
## [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:](#)
<br />
## [DisplayListNode](#DisplayListNode)
| Field | Type | Access |

View file

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

View file

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

View file

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

View file

@ -44,6 +44,7 @@ enum LuaObjectAutogenType {
LOT_CUTSCENESPLINEPOINT,
LOT_CUTSCENEVARIABLE,
LOT_DATETIME,
LOT_DIALOGENTRY,
LOT_DISPLAYLISTNODE,
LOT_DJUICOLOR,
LOT_DJUIINTERACTABLETHEME,

View file

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

View file

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

View file

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

View file

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