From 075e76b71a30172b909250cd0871f61df83ffcdb Mon Sep 17 00:00:00 2001
From: PeachyPeach <72323920+PeachyPeachSM64@users.noreply.github.com>
Date: Fri, 27 Jun 2025 19:00:58 +0200
Subject: [PATCH] fix custom course and act names (#869)
---
autogen/lua_definitions/functions.lua | 37 ++++
docs/lua/functions-6.md | 132 ++++++++++++
docs/lua/functions.md | 6 +
src/game/level_info.c | 46 +++-
src/game/level_info.h | 6 +-
src/pc/lua/smlua_functions_autogen.c | 102 +++++++++
src/pc/lua/utils/smlua_text_utils.c | 300 ++++++++++++++------------
src/pc/lua/utils/smlua_text_utils.h | 36 +++-
8 files changed, 507 insertions(+), 158 deletions(-)
diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua
index c0b532b10..59c0e2bbd 100644
--- a/autogen/lua_definitions/functions.lua
+++ b/autogen/lua_definitions/functions.lua
@@ -11616,6 +11616,23 @@ function smlua_text_utils_castle_secret_stars_replace(name)
-- ...
end
+--- @return string
+--- Gets the castle secret stars text
+function smlua_text_utils_castle_secret_stars_get()
+ -- ...
+end
+
+--- @return integer
+--- Gets the index of the mod that replaced the castle secret stars text
+function smlua_text_utils_castle_secret_stars_mod_index()
+ -- ...
+end
+
+--- Resets the castle secret stars text
+function smlua_text_utils_castle_secret_stars_reset()
+ -- ...
+end
+
--- @param index integer
--- @param text string
--- Replace extra text (e.g. one of the castle's secret stars) with `text`
@@ -11623,6 +11640,26 @@ function smlua_text_utils_extra_text_replace(index, text)
-- ...
end
+--- @param index integer
+--- @return string
+--- Gets the extra text at `index`
+function smlua_text_utils_extra_text_get(index)
+ -- ...
+end
+
+--- @param index integer
+--- @return integer
+--- Gets the index of the mod that replaced the extra text at `index`
+function smlua_text_utils_extra_text_mod_index(index)
+ -- ...
+end
+
+--- @param index integer
+--- Resets the extra text at `index`
+function smlua_text_utils_extra_text_reset(index)
+ -- ...
+end
+
--- @return string
--- Gets the current language
function smlua_text_utils_get_language()
diff --git a/docs/lua/functions-6.md b/docs/lua/functions-6.md
index 46f2aef50..6883780e3 100644
--- a/docs/lua/functions-6.md
+++ b/docs/lua/functions-6.md
@@ -6724,6 +6724,69 @@ Replaces the castle secret stars text with `name`
+## [smlua_text_utils_castle_secret_stars_get](#smlua_text_utils_castle_secret_stars_get)
+
+### Description
+Gets the castle secret stars text
+
+### Lua Example
+`local stringValue = smlua_text_utils_castle_secret_stars_get()`
+
+### Parameters
+- None
+
+### Returns
+- `string`
+
+### C Prototype
+`const char* smlua_text_utils_castle_secret_stars_get();`
+
+[:arrow_up_small:](#)
+
+
+
+## [smlua_text_utils_castle_secret_stars_mod_index](#smlua_text_utils_castle_secret_stars_mod_index)
+
+### Description
+Gets the index of the mod that replaced the castle secret stars text
+
+### Lua Example
+`local integerValue = smlua_text_utils_castle_secret_stars_mod_index()`
+
+### Parameters
+- None
+
+### Returns
+- `integer`
+
+### C Prototype
+`s32 smlua_text_utils_castle_secret_stars_mod_index();`
+
+[:arrow_up_small:](#)
+
+
+
+## [smlua_text_utils_castle_secret_stars_reset](#smlua_text_utils_castle_secret_stars_reset)
+
+### Description
+Resets the castle secret stars text
+
+### Lua Example
+`smlua_text_utils_castle_secret_stars_reset()`
+
+### Parameters
+- None
+
+### Returns
+- None
+
+### C Prototype
+`void smlua_text_utils_castle_secret_stars_reset();`
+
+[:arrow_up_small:](#)
+
+
+
## [smlua_text_utils_extra_text_replace](#smlua_text_utils_extra_text_replace)
### Description
@@ -6748,6 +6811,75 @@ Replace extra text (e.g. one of the castle's secret stars) with `text`
+## [smlua_text_utils_extra_text_get](#smlua_text_utils_extra_text_get)
+
+### Description
+Gets the extra text at `index`
+
+### Lua Example
+`local stringValue = smlua_text_utils_extra_text_get(index)`
+
+### Parameters
+| Field | Type |
+| ----- | ---- |
+| index | `integer` |
+
+### Returns
+- `string`
+
+### C Prototype
+`const char* smlua_text_utils_extra_text_get(s16 index);`
+
+[:arrow_up_small:](#)
+
+
+
+## [smlua_text_utils_extra_text_mod_index](#smlua_text_utils_extra_text_mod_index)
+
+### Description
+Gets the index of the mod that replaced the extra text at `index`
+
+### Lua Example
+`local integerValue = smlua_text_utils_extra_text_mod_index(index)`
+
+### Parameters
+| Field | Type |
+| ----- | ---- |
+| index | `integer` |
+
+### Returns
+- `integer`
+
+### C Prototype
+`s32 smlua_text_utils_extra_text_mod_index(s16 index);`
+
+[:arrow_up_small:](#)
+
+
+
+## [smlua_text_utils_extra_text_reset](#smlua_text_utils_extra_text_reset)
+
+### Description
+Resets the extra text at `index`
+
+### Lua Example
+`smlua_text_utils_extra_text_reset(index)`
+
+### Parameters
+| Field | Type |
+| ----- | ---- |
+| index | `integer` |
+
+### Returns
+- None
+
+### C Prototype
+`void smlua_text_utils_extra_text_reset(s16 index);`
+
+[:arrow_up_small:](#)
+
+
+
## [smlua_text_utils_get_language](#smlua_text_utils_get_language)
### Description
diff --git a/docs/lua/functions.md b/docs/lua/functions.md
index bbef2c349..2f17aca04 100644
--- a/docs/lua/functions.md
+++ b/docs/lua/functions.md
@@ -2069,7 +2069,13 @@
- [smlua_text_utils_act_name_mod_index](functions-6.md#smlua_text_utils_act_name_mod_index)
- [smlua_text_utils_act_name_reset](functions-6.md#smlua_text_utils_act_name_reset)
- [smlua_text_utils_castle_secret_stars_replace](functions-6.md#smlua_text_utils_castle_secret_stars_replace)
+ - [smlua_text_utils_castle_secret_stars_get](functions-6.md#smlua_text_utils_castle_secret_stars_get)
+ - [smlua_text_utils_castle_secret_stars_mod_index](functions-6.md#smlua_text_utils_castle_secret_stars_mod_index)
+ - [smlua_text_utils_castle_secret_stars_reset](functions-6.md#smlua_text_utils_castle_secret_stars_reset)
- [smlua_text_utils_extra_text_replace](functions-6.md#smlua_text_utils_extra_text_replace)
+ - [smlua_text_utils_extra_text_get](functions-6.md#smlua_text_utils_extra_text_get)
+ - [smlua_text_utils_extra_text_mod_index](functions-6.md#smlua_text_utils_extra_text_mod_index)
+ - [smlua_text_utils_extra_text_reset](functions-6.md#smlua_text_utils_extra_text_reset)
- [smlua_text_utils_get_language](functions-6.md#smlua_text_utils_get_language)
diff --git a/src/game/level_info.c b/src/game/level_info.c
index f7a467c30..835ceca31 100644
--- a/src/game/level_info.c
+++ b/src/game/level_info.c
@@ -4,6 +4,7 @@
#include "course_table.h"
#include "game/hardcoded.h"
#include "game/memory.h"
+#include "game/segment2.h"
#include "level_info.h"
#include "level_table.h"
#include "save_file.h"
@@ -14,9 +15,6 @@
#ifdef VERSION_EU
extern s32 gInGameLanguage;
#include "eu_translation.h"
-#else
-extern u8 *seg2_course_name_table[];
-extern u8 *seg2_act_name_table[];
#endif
static const struct { const char *str; u8 c; u8 menu; } sSm64CharMap[] = {
@@ -160,7 +158,7 @@ static void decapitalize_string_sm64(u8 *str64) {
}
}
-void *get_course_name_table(void) {
+void **get_course_name_table(void) {
void **courseNameTbl = segmented_to_virtual(seg2_course_name_table);
#ifdef VERSION_EU
@@ -174,7 +172,21 @@ void *get_course_name_table(void) {
return courseNameTbl;
}
-void *get_act_name_table(void) {
+void **get_course_name_table_original(void) {
+ void **courseNameTblOrig = segmented_to_virtual(seg2_course_name_table_original);
+
+#ifdef VERSION_EU
+ switch (gInGameLanguage) {
+ case LANGUAGE_ENGLISH: courseNameTblOrig = segmented_to_virtual(course_name_table_eu_en_original); break;
+ case LANGUAGE_FRENCH: courseNameTblOrig = segmented_to_virtual(course_name_table_eu_fr_original); break;
+ case LANGUAGE_GERMAN: courseNameTblOrig = segmented_to_virtual(course_name_table_eu_de_original); break;
+ }
+#endif
+
+ return courseNameTblOrig;
+}
+
+void **get_act_name_table(void) {
void **actNameTbl = segmented_to_virtual(seg2_act_name_table);
#ifdef VERSION_EU
@@ -188,6 +200,20 @@ void *get_act_name_table(void) {
return actNameTbl;
}
+void **get_act_name_table_original(void) {
+ void **actNameTblOrig = segmented_to_virtual(seg2_act_name_table_original);
+
+#ifdef VERSION_EU
+ switch (gInGameLanguage) {
+ case LANGUAGE_ENGLISH: actNameTblOrig = segmented_to_virtual(act_name_table_eu_en_original); break;
+ case LANGUAGE_FRENCH: actNameTblOrig = segmented_to_virtual(act_name_table_eu_fr_original); break;
+ case LANGUAGE_GERMAN: actNameTblOrig = segmented_to_virtual(act_name_table_eu_de_original); break;
+ }
+#endif
+
+ return actNameTblOrig;
+}
+
const char *get_level_name_ascii(s16 courseNum, s16 levelNum, s16 areaIndex, s16 charCase) {
static char output[256];
@@ -201,8 +227,8 @@ const char *get_level_name_ascii(s16 courseNum, s16 levelNum, s16 areaIndex, s16
}
}
- if (courseNum >= 0 && courseNum <= COURSE_MAX && gReplacedActNameTable[courseNum]->modIndex != -1) {
- snprintf(output, 256, "%s", gReplacedActNameTable[courseNum]->name);
+ if (courseNum >= 0 && courseNum <= COURSE_MAX && gReplacedCourseActNameTable[courseNum].courseName.modNum != 0) {
+ snprintf(output, 256, "%s", gReplacedCourseActNameTable[courseNum].courseName.name.value);
}
else if (!hasCustomName) {
@@ -266,9 +292,9 @@ const char *get_star_name_ascii(s16 courseNum, s16 starNum, s16 charCase) {
s16 starIndex = starNum - 1;
if (starIndex >= 0 && starIndex < MAX_ACTS_AND_100_COINS &&
- courseNum >= 0 && courseNum < COURSE_END &&
- gReplacedActNameTable[courseNum]->actName && gReplacedActNameTable[courseNum]->actName[starIndex].modIndex != -1) {
- snprintf(output, 256, "%s", gReplacedActNameTable[courseNum]->actName[starIndex].name);
+ courseNum >= 0 && courseNum <= COURSE_MAX &&
+ gReplacedCourseActNameTable[courseNum].actName[starIndex].modNum != 0) {
+ snprintf(output, 256, "%s", gReplacedCourseActNameTable[courseNum].actName[starIndex].name.value);
}
// Main courses: BOB to RR
diff --git a/src/game/level_info.h b/src/game/level_info.h
index 49b760f87..9ffb3afe9 100644
--- a/src/game/level_info.h
+++ b/src/game/level_info.h
@@ -3,8 +3,10 @@
#include
-void *get_course_name_table(void);
-void *get_act_name_table(void);
+void **get_course_name_table(void);
+void **get_course_name_table_original(void);
+void **get_act_name_table(void);
+void **get_act_name_table_original(void);
/* |description|
Returns the name of the level corresponding to `courseNum`, `levelNum` and `areaIndex` as an ASCII (human readable) string.
Set `charCase` to 1 to capitalize or -1 to decapitalize the returned string
diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c
index 16f3e16d5..f02fa04d6 100644
--- a/src/pc/lua/smlua_functions_autogen.c
+++ b/src/pc/lua/smlua_functions_autogen.c
@@ -34564,6 +34564,51 @@ int smlua_func_smlua_text_utils_castle_secret_stars_replace(lua_State* L) {
return 1;
}
+int smlua_func_smlua_text_utils_castle_secret_stars_get(UNUSED lua_State* L) {
+ if (L == NULL) { return 0; }
+
+ int top = lua_gettop(L);
+ if (top != 0) {
+ LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_castle_secret_stars_get", 0, top);
+ return 0;
+ }
+
+
+ lua_pushstring(L, smlua_text_utils_castle_secret_stars_get());
+
+ return 1;
+}
+
+int smlua_func_smlua_text_utils_castle_secret_stars_mod_index(UNUSED lua_State* L) {
+ if (L == NULL) { return 0; }
+
+ int top = lua_gettop(L);
+ if (top != 0) {
+ LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_castle_secret_stars_mod_index", 0, top);
+ return 0;
+ }
+
+
+ lua_pushinteger(L, smlua_text_utils_castle_secret_stars_mod_index());
+
+ return 1;
+}
+
+int smlua_func_smlua_text_utils_castle_secret_stars_reset(UNUSED lua_State* L) {
+ if (L == NULL) { return 0; }
+
+ int top = lua_gettop(L);
+ if (top != 0) {
+ LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_castle_secret_stars_reset", 0, top);
+ return 0;
+ }
+
+
+ smlua_text_utils_castle_secret_stars_reset();
+
+ return 1;
+}
+
int smlua_func_smlua_text_utils_extra_text_replace(lua_State* L) {
if (L == NULL) { return 0; }
@@ -34583,6 +34628,57 @@ int smlua_func_smlua_text_utils_extra_text_replace(lua_State* L) {
return 1;
}
+int smlua_func_smlua_text_utils_extra_text_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_extra_text_get", 1, top);
+ return 0;
+ }
+
+ s16 index = smlua_to_integer(L, 1);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_extra_text_get"); return 0; }
+
+ lua_pushstring(L, smlua_text_utils_extra_text_get(index));
+
+ return 1;
+}
+
+int smlua_func_smlua_text_utils_extra_text_mod_index(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_extra_text_mod_index", 1, top);
+ return 0;
+ }
+
+ s16 index = smlua_to_integer(L, 1);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_extra_text_mod_index"); return 0; }
+
+ lua_pushinteger(L, smlua_text_utils_extra_text_mod_index(index));
+
+ return 1;
+}
+
+int smlua_func_smlua_text_utils_extra_text_reset(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_extra_text_reset", 1, top);
+ return 0;
+ }
+
+ s16 index = smlua_to_integer(L, 1);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_extra_text_reset"); return 0; }
+
+ smlua_text_utils_extra_text_reset(index);
+
+ return 1;
+}
+
int smlua_func_smlua_text_utils_get_language(UNUSED lua_State* L) {
if (L == NULL) { return 0; }
@@ -37302,7 +37398,13 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "smlua_text_utils_act_name_mod_index", smlua_func_smlua_text_utils_act_name_mod_index);
smlua_bind_function(L, "smlua_text_utils_act_name_reset", smlua_func_smlua_text_utils_act_name_reset);
smlua_bind_function(L, "smlua_text_utils_castle_secret_stars_replace", smlua_func_smlua_text_utils_castle_secret_stars_replace);
+ smlua_bind_function(L, "smlua_text_utils_castle_secret_stars_get", smlua_func_smlua_text_utils_castle_secret_stars_get);
+ smlua_bind_function(L, "smlua_text_utils_castle_secret_stars_mod_index", smlua_func_smlua_text_utils_castle_secret_stars_mod_index);
+ smlua_bind_function(L, "smlua_text_utils_castle_secret_stars_reset", smlua_func_smlua_text_utils_castle_secret_stars_reset);
smlua_bind_function(L, "smlua_text_utils_extra_text_replace", smlua_func_smlua_text_utils_extra_text_replace);
+ smlua_bind_function(L, "smlua_text_utils_extra_text_get", smlua_func_smlua_text_utils_extra_text_get);
+ smlua_bind_function(L, "smlua_text_utils_extra_text_mod_index", smlua_func_smlua_text_utils_extra_text_mod_index);
+ smlua_bind_function(L, "smlua_text_utils_extra_text_reset", smlua_func_smlua_text_utils_extra_text_reset);
smlua_bind_function(L, "smlua_text_utils_get_language", smlua_func_smlua_text_utils_get_language);
// sound_init.h
diff --git a/src/pc/lua/utils/smlua_text_utils.c b/src/pc/lua/utils/smlua_text_utils.c
index 573c9b0b3..89d525f9c 100644
--- a/src/pc/lua/utils/smlua_text_utils.c
+++ b/src/pc/lua/utils/smlua_text_utils.c
@@ -17,55 +17,90 @@ extern s32 gInGameLanguage;
#endif
static bool sReplacedDialog[DIALOG_COUNT] = { 0 };
-static bool sReplacedCourseName[COURSE_COUNT+2] = { 0 };
-static bool sReplacedActName[(COURSE_RR+2)*6] = { 0 };
-
-#define INVALID_COURSE_NUM(courseNum) (smlua_level_util_get_info_from_course_num(courseNum) == NULL && !COURSE_IS_VALID_COURSE(courseNum))
void convert_string_sm64_to_ascii(char *strAscii, const u8 *str64);
-struct CourseName *gReplacedActNameTable[COURSE_END];
+/*
+---------------------------------------------------
+Mapping gReplacedCourseActNameTable <-> seg2 tables
+---------------------------------------------------
+
+For courseNum from COURSE_BOB to COURSE_RR:
+- gReplacedCourseActNameTable[courseNum].courseName <-> seg2_course_name_table[courseNum - 1]
+- gReplacedCourseActNameTable[courseNum].actName[0..5] <-> seg2_act_name_table[(courseNum - 1) * 6 + (0..5)]
+ (7th act name doesn't map to anything, but can be retrieved with `smlua_text_utils_act_name_get`)
+
+For courseNum from COURSE_BITDW to COURSE_CAKE_END:
+- gReplacedCourseActNameTable[courseNum].courseName <-> seg2_course_name_table[courseNum - 1]
+- gReplacedCourseActNameTable[courseNum].actName[0..6] don't map to anything, but they can be retrieved with `smlua_text_utils_act_name_get`
+
+For castle secret stars and extra text:
+- gReplacedCourseActNameTable[COURSE_END].courseName <-> seg2_course_name_table[COURSE_MAX] (which is seg2_course_name_table_castle_secret_stars)
+- gReplacedCourseActNameTable[COURSE_END].actName[0..6] <-> seg2_act_name_table[COURSE_STAGES_MAX * 6 + (0..6)] (which are extra_text_0~6)
+*/
+struct CourseActNames gReplacedCourseActNameTable[COURSE_END + 1] = { 0 };
static bool sSmluaTextUtilsInited = false;
+#define smlua_text_utils_init_from_vanilla(obj, tableFunc, tableOrigFunc, tableOffset) { \
+ char buffer[50]; \
+ convert_string_sm64_to_ascii(buffer, tableOrigFunc()[tableOffset]); \
+ snprintf(obj.name.value, sizeof(obj.name.value), "%s", buffer); \
+ obj.name.get_table = tableFunc; \
+ obj.name.offset = tableOffset; \
+ snprintf(obj.orig.value, sizeof(obj.orig.value), "%s", buffer); \
+ obj.orig.get_table = tableOrigFunc; \
+ obj.orig.offset = tableOffset; \
+ tableFunc()[tableOffset] = tableOrigFunc()[tableOffset]; \
+}
+
// Save all vanilla act names and course names
void smlua_text_utils_init(void) {
- void **actNameTbl = get_act_name_table();
- void **courseNameTbl = get_course_name_table();
- char courseBuffer[50];
- char actBuffer[50];
+ memset(gReplacedCourseActNameTable, 0, sizeof(gReplacedCourseActNameTable));
- // Course/Star names
- for (s16 courseNum = 0; courseNum < COURSE_END; courseNum++) {
- gReplacedActNameTable[courseNum] = calloc(1, sizeof(struct CourseName));
- struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
- convert_string_sm64_to_ascii(courseBuffer, segmented_to_virtual(courseNameTbl[courseNum]));
- snprintf(courseActNames->name, 50, "%s", courseBuffer);
- snprintf(courseActNames->orig, 50, "%s", courseBuffer);
- courseActNames->modIndex = -1;
- courseActNames->actName = NULL;
+ // Vanilla courses
+ for (s16 courseNum = COURSE_MIN; courseNum <= COURSE_MAX; ++courseNum) {
+ smlua_text_utils_init_from_vanilla(
+ gReplacedCourseActNameTable[courseNum].courseName,
+ get_course_name_table,
+ get_course_name_table_original,
+ courseNum - 1
+ );
- // Individual acts
+ // Vanilla acts
if (COURSE_IS_MAIN_COURSE(courseNum)) {
- courseActNames->actName = calloc(MAX_ACTS_AND_100_COINS, sizeof(struct ActName));
- for (s16 actNum = 0; actNum < MAX_ACTS; actNum++) {
- convert_string_sm64_to_ascii(actBuffer, segmented_to_virtual(actNameTbl[courseNum * MAX_ACTS + actNum]));
- snprintf(courseActNames->actName[actNum].name, 50, "%s", actBuffer);
- snprintf(courseActNames->actName[actNum].orig, 50, "%s", actBuffer);
- courseActNames->actName[actNum].modIndex = -1;
+ for (s16 actIndex = 0; actIndex < MAX_ACTS; ++actIndex) {
+ smlua_text_utils_init_from_vanilla(
+ gReplacedCourseActNameTable[courseNum].actName[actIndex],
+ get_act_name_table,
+ get_act_name_table_original,
+ (courseNum - 1) * MAX_ACTS + actIndex
+ );
}
- courseActNames->actName[MAX_ACTS_AND_100_COINS - 1].modIndex = -1;
}
}
+
+ // Vanilla castle secrets and extras
+ smlua_text_utils_init_from_vanilla(
+ gReplacedCourseActNameTable[COURSE_END].courseName,
+ get_course_name_table,
+ get_course_name_table_original,
+ COURSE_MAX
+ );
+ for (s16 actIndex = 0; actIndex < MAX_ACTS_AND_100_COINS; ++actIndex) {
+ smlua_text_utils_init_from_vanilla(
+ gReplacedCourseActNameTable[COURSE_END].actName[actIndex],
+ get_act_name_table,
+ get_act_name_table_original,
+ COURSE_STAGES_MAX * MAX_ACTS + actIndex
+ );
+ }
+
sSmluaTextUtilsInited = true;
}
void smlua_text_utils_shutdown(void) {
if (sSmluaTextUtilsInited) {
- for (s16 courseNum = 0; courseNum < COURSE_END; courseNum++) {
- free(gReplacedActNameTable[courseNum]->actName);
- free(gReplacedActNameTable[courseNum]);
- }
sSmluaTextUtilsInited = false;
}
}
@@ -85,48 +120,55 @@ static bool str_starts_with_spaces(const char* str) {
return true;
}
+static void smlua_text_utils_reset_course_or_act_name(struct ReplacedName *name) {
+ if (name->name.get_table && name->orig.get_table) {
+ void **tblName = name->name.get_table() + name->name.offset;
+ void **tblOrig = name->orig.get_table() + name->orig.offset;
+ if (*tblName != *tblOrig) {
+ free(*tblName);
+ *tblName = *tblOrig;
+ }
+ }
+ memcpy(name->name.value, name->orig.value, sizeof(name->name.value));
+ name->modNum = 0;
+}
+
+static void smlua_text_utils_replace_course_or_act_name(struct ReplacedName *name, const char *replacement, s32 modIndex) {
+ replacement += 3 * str_starts_with_spaces(replacement);
+ if (name->name.get_table && name->orig.get_table) {
+ void **tblName = name->name.get_table() + name->name.offset;
+ void **tblOrig = name->orig.get_table() + name->orig.offset;
+ if (*tblName != *tblOrig) {
+ free(*tblName);
+ }
+ *tblName = smlua_text_utils_convert(replacement);
+ }
+ snprintf(name->name.value, sizeof(name->name.value), "%s", replacement);
+ name->modNum = modIndex + 1;
+}
+
void smlua_text_utils_reset_all(void) {
void **dialogTable = NULL;
- void **actNameTbl = NULL;
- void **courseNameTbl = NULL;
void **dialogTableOrg = NULL;
- void **actNameTblOrg = NULL;
- void **courseNameTblOrg = NULL;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
dialogTable = segmented_to_virtual(dialog_table_eu_en);
- actNameTbl = segmented_to_virtual(act_name_table_eu_en);
- courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
dialogTableOrg = segmented_to_virtual(dialog_table_eu_en_original);
- actNameTblOrg = segmented_to_virtual(act_name_table_eu_en_original);
- courseNameTblOrg = segmented_to_virtual(course_name_table_eu_en_original);
break;
case LANGUAGE_FRENCH:
dialogTable = segmented_to_virtual(dialog_table_eu_fr);
- actNameTbl = segmented_to_virtual(act_name_table_eu_fr);
- courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
dialogTableOrg = segmented_to_virtual(dialog_table_eu_fr_original);
- actNameTblOrg = segmented_to_virtual(act_name_table_eu_fr_original);
- courseNameTblOrg = segmented_to_virtual(course_name_table_eu_fr_original);
break;
case LANGUAGE_GERMAN:
dialogTable = segmented_to_virtual(dialog_table_eu_de);
- actNameTbl = segmented_to_virtual(act_name_table_eu_de);
- courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
dialogTableOrg = segmented_to_virtual(dialog_table_eu_de_original);
- actNameTblOrg = segmented_to_virtual(act_name_table_eu_de_original);
- courseNameTblOrg = segmented_to_virtual(course_name_table_eu_de_original);
break;
}
#else
dialogTable = segmented_to_virtual(seg2_dialog_table);
- actNameTbl = segmented_to_virtual(seg2_act_name_table);
- courseNameTbl = segmented_to_virtual(seg2_course_name_table);
dialogTableOrg = segmented_to_virtual(seg2_dialog_original);
- actNameTblOrg = segmented_to_virtual(seg2_act_name_table_original);
- courseNameTblOrg = segmented_to_virtual(seg2_course_name_table_original);
#endif
for (s32 i = 0; i < DIALOG_COUNT; i++) {
@@ -138,32 +180,17 @@ void smlua_text_utils_reset_all(void) {
sReplacedDialog[i] = false;
}
- for (s32 i = 0; i < COURSE_COUNT+2; i++) {
- if (!sReplacedCourseName[i]) { continue; }
- free((u8*)courseNameTbl[i]);
- courseNameTbl[i] = segmented_to_virtual(courseNameTblOrg[i]);
- sReplacedCourseName[i] = false;
- }
-
- for (s32 i = 0; i < (COURSE_RR+2)*6; i++) {
- if (!sReplacedActName[i]) { continue; }
- free((u8*)actNameTbl[i]);
- actNameTbl[i] = segmented_to_virtual(actNameTblOrg[i]);
- sReplacedActName[i] = false;
- }
-
if (sSmluaTextUtilsInited) {
- for (s32 courseNum = 0; courseNum < COURSE_COUNT; courseNum++) {
- struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
- snprintf(courseActNames->name, 50, "%s", courseActNames->orig);
- courseActNames->modIndex = -1;
+ for (s16 courseNum = 0; courseNum < COURSE_END; courseNum++) {
- // Individual acts
- if (COURSE_IS_MAIN_COURSE(courseNum)) {
- for (s16 actNum = 0; actNum < MAX_ACTS_AND_100_COINS; actNum++) {
- snprintf(courseActNames->actName[actNum].name, 50, "%s", courseActNames->actName[actNum].orig);
- courseActNames->actName[actNum].modIndex = -1;
- }
+ // Restore vanilla course names
+ struct ReplacedName *courseName = &gReplacedCourseActNameTable[courseNum].courseName;
+ smlua_text_utils_reset_course_or_act_name(courseName);
+
+ // Restore vanilla act names
+ for (s16 actIndex = 0; actIndex < MAX_ACTS_AND_100_COINS; actIndex++) {
+ struct ReplacedName *actName = &gReplacedCourseActNameTable[courseNum].actName[actIndex];
+ smlua_text_utils_reset_course_or_act_name(actName);
}
}
}
@@ -205,14 +232,13 @@ void smlua_text_utils_dialog_replace(enum DialogId dialogId, UNUSED u32 unused,
}
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 (courseNum <= 0 || courseNum > COURSE_RR) { return; }
- struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
- snprintf(courseActNames->name, 256, "%s", courseName + (3 * (strlen(courseName) > 3)));
- courseActNames->modIndex = gLuaActiveMod->index;
+ if (!COURSE_IS_VALID_COURSE(courseNum)) { return; }
+
+ struct CourseActNames *courseActNames = &gReplacedCourseActNameTable[courseNum];
+ smlua_text_utils_replace_course_or_act_name(&courseActNames->courseName, courseName, gLuaActiveMod->index);
#define REPLACE_ACT_NAME(i) { \
- snprintf(courseActNames->actName[i-1].name, 256, "%s", act##i); \
- courseActNames->actName[i-1].modIndex = gLuaActiveMod->index; \
+ smlua_text_utils_replace_course_or_act_name(&courseActNames->actName[i - 1], act##i, gLuaActiveMod->index); \
}
REPLACE_ACT_NAME(1);
@@ -224,107 +250,109 @@ void smlua_text_utils_course_acts_replace(s16 courseNum, const char* courseName,
}
void smlua_text_utils_course_name_replace(s16 courseNum, const char* name) {
- if (INVALID_COURSE_NUM(courseNum)) { return; }
+ if (!COURSE_IS_VALID_COURSE(courseNum)) { return; }
- struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
- snprintf(courseActNames->name, 256, "%s", name);
- courseActNames->modIndex = gLuaActiveMod->index;
+ struct CourseActNames *courseActNames = &gReplacedCourseActNameTable[courseNum];
+ smlua_text_utils_replace_course_or_act_name(&courseActNames->courseName, name, gLuaActiveMod->index);
}
const char* smlua_text_utils_course_name_get(s16 courseNum) {
- if (INVALID_COURSE_NUM(courseNum)) { return NULL; }
+ if (!COURSE_IS_VALID_COURSE(courseNum)) { return NULL; }
- return gReplacedActNameTable[courseNum]->name;
+ return gReplacedCourseActNameTable[courseNum].courseName.name.value;
}
s32 smlua_text_utils_course_name_mod_index(s16 courseNum) {
- if (INVALID_COURSE_NUM(courseNum)) { return -1; }
+ if (!COURSE_IS_VALID_COURSE(courseNum)) { return -1; }
- return gReplacedActNameTable[courseNum]->modIndex;
+ return (s32) gReplacedCourseActNameTable[courseNum].courseName.modNum - 1;
}
void smlua_text_utils_course_name_reset(s16 courseNum) {
- if (INVALID_COURSE_NUM(courseNum)) { return; }
+ if (!COURSE_IS_VALID_COURSE(courseNum)) { return; }
- struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
- snprintf(courseActNames->name, 50, "%s", courseActNames->orig);
- courseActNames->modIndex = -1;
+ struct CourseActNames *courseActNames = &gReplacedCourseActNameTable[courseNum];
+ smlua_text_utils_reset_course_or_act_name(&courseActNames->courseName);
}
void smlua_text_utils_act_name_replace(s16 courseNum, u8 actNum, const char* name) {
- if (INVALID_COURSE_NUM(courseNum) || actNum >= MAX_ACTS_AND_100_COINS) { return; }
+ if (!COURSE_IS_VALID_COURSE(courseNum)) { return; }
+ if (actNum < 1 || actNum > MAX_ACTS_AND_100_COINS) { return; }
- struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
-
- snprintf(courseActNames->actName[actNum].name, 256, "%s", name);
- courseActNames->actName[actNum].modIndex = gLuaActiveMod->index;
+ struct CourseActNames *courseActNames = &gReplacedCourseActNameTable[courseNum];
+ smlua_text_utils_replace_course_or_act_name(&courseActNames->actName[actNum - 1], name, gLuaActiveMod->index);
}
const char* smlua_text_utils_act_name_get(s16 courseNum, u8 actNum) {
- if (INVALID_COURSE_NUM(courseNum) || actNum >= MAX_ACTS_AND_100_COINS) { return NULL; }
+ if (!COURSE_IS_VALID_COURSE(courseNum)) { return NULL; }
+ if (actNum < 1 || actNum > MAX_ACTS_AND_100_COINS) { return NULL; }
- return gReplacedActNameTable[courseNum]->actName[actNum].name;
+ return gReplacedCourseActNameTable[courseNum].actName[actNum - 1].name.value;
}
s32 smlua_text_utils_act_name_mod_index(s16 courseNum, u8 actNum) {
- if (INVALID_COURSE_NUM(courseNum) || actNum >= MAX_ACTS_AND_100_COINS) { return false; }
+ if (!COURSE_IS_VALID_COURSE(courseNum)) { return -1; }
+ if (actNum < 1 || actNum > MAX_ACTS_AND_100_COINS) { return -1; }
- return gReplacedActNameTable[courseNum]->actName[actNum].modIndex;
+ return (s32) gReplacedCourseActNameTable[courseNum].actName[actNum - 1].modNum - 1;
}
void smlua_text_utils_act_name_reset(s16 courseNum, u8 actNum) {
- if (INVALID_COURSE_NUM(courseNum) || actNum >= MAX_ACTS_AND_100_COINS) { return; }
+ if (!COURSE_IS_VALID_COURSE(courseNum)) { return; }
+ if (actNum < 1 || actNum > MAX_ACTS_AND_100_COINS) { return; }
- struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
- snprintf(courseActNames->actName[actNum].name, 50, "%s", courseActNames->actName[actNum].orig);
- courseActNames->actName[actNum].modIndex = gLuaActiveMod->index;
+ struct CourseActNames *courseActNames = &gReplacedCourseActNameTable[courseNum];
+ smlua_text_utils_reset_course_or_act_name(&courseActNames->actName[actNum - 1]);
}
void smlua_text_utils_secret_star_replace(s16 courseNum, const char* courseName) {
- if (courseNum <= COURSE_RR || courseNum > COURSE_COUNT) { return; }
- /*
- s16 courseOffset = courseNum - 1;
+ if (courseNum <= COURSE_STAGES_MAX || courseNum > COURSE_MAX) { return; }
- void **courseNameTbl = get_course_name_table();
-
- if (sReplacedCourseName[courseOffset]) {
- free(courseNameTbl[courseOffset]);
- }
-
- courseNameTbl[courseOffset] = smlua_text_utils_convert(courseName);
- sReplacedCourseName[courseOffset] = true;
- */
-
- struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
- snprintf(courseActNames->name, 256, "%s", courseName + (3 * str_starts_with_spaces(courseName)));
- courseActNames->modIndex = gLuaActiveMod->index;
+ smlua_text_utils_course_name_replace(courseNum, courseName);
}
void smlua_text_utils_castle_secret_stars_replace(const char* name) {
- s16 courseOffset = COURSE_COUNT;
+ struct CourseActNames *courseActNames = &gReplacedCourseActNameTable[COURSE_END];
+ smlua_text_utils_replace_course_or_act_name(&courseActNames->courseName, name, gLuaActiveMod->index);
+}
- void **courseNameTbl = get_course_name_table();
+const char* smlua_text_utils_castle_secret_stars_get() {
+ return gReplacedCourseActNameTable[COURSE_END].courseName.name.value;
+}
- if (sReplacedCourseName[courseOffset]) {
- free(courseNameTbl[courseOffset]);
- }
+s32 smlua_text_utils_castle_secret_stars_mod_index() {
+ return (s32) gReplacedCourseActNameTable[COURSE_END].courseName.modNum - 1;
+}
- courseNameTbl[courseOffset] = smlua_text_utils_convert(name);
- sReplacedCourseName[courseOffset] = true;
+void smlua_text_utils_castle_secret_stars_reset() {
+ struct CourseActNames *courseActNames = &gReplacedCourseActNameTable[COURSE_END];
+ smlua_text_utils_reset_course_or_act_name(&courseActNames->courseName);
}
void smlua_text_utils_extra_text_replace(s16 index, const char* text) {
- if (index < 0 || index > 6) { return; }
- index = (COURSE_RR * 6 + index);
+ if (index < 0 || index > MAX_ACTS_AND_100_COINS) { return; }
- void **actNameTbl = get_act_name_table();
+ struct CourseActNames *courseActNames = &gReplacedCourseActNameTable[COURSE_END];
+ smlua_text_utils_replace_course_or_act_name(&courseActNames->actName[index], text, gLuaActiveMod->index);
+}
- if (sReplacedActName[index]) {
- free(actNameTbl[index]);
- }
+const char* smlua_text_utils_extra_text_get(s16 index) {
+ if (index < 0 || index > MAX_ACTS_AND_100_COINS) { return NULL; }
- actNameTbl[index] = smlua_text_utils_convert(text);
- sReplacedActName[index] = true;
+ return gReplacedCourseActNameTable[COURSE_END].actName[index].name.value;
+}
+
+s32 smlua_text_utils_extra_text_mod_index(s16 index) {
+ if (index < 0 || index > MAX_ACTS_AND_100_COINS) { return -1; }
+
+ return (s32) gReplacedCourseActNameTable[COURSE_END].actName[index].modNum - 1;
+}
+
+void smlua_text_utils_extra_text_reset(s16 index) {
+ if (index < 0 || index > MAX_ACTS_AND_100_COINS) { return; }
+
+ struct CourseActNames *courseActNames = &gReplacedCourseActNameTable[COURSE_END];
+ smlua_text_utils_reset_course_or_act_name(&courseActNames->actName[index]);
}
const char* smlua_text_utils_get_language(void) {
diff --git a/src/pc/lua/utils/smlua_text_utils.h b/src/pc/lua/utils/smlua_text_utils.h
index b2a61e0f1..f6cc69901 100644
--- a/src/pc/lua/utils/smlua_text_utils.h
+++ b/src/pc/lua/utils/smlua_text_utils.h
@@ -7,20 +7,24 @@
#define MAX_ACTS 6
#define MAX_ACTS_AND_100_COINS 7
-struct ActName {
- char name[256];
- char orig[256];
- s32 modIndex;
+struct NameTable {
+ char value[256];
+ void **(*get_table)(void);
+ u32 offset;
};
-struct CourseName {
- struct ActName *actName;
- char name[256];
- char orig[256];
- s32 modIndex;
+struct ReplacedName {
+ struct NameTable name;
+ struct NameTable orig;
+ u32 modNum; // modIndex + 1 (default value of 0 is more convenient than -1)
};
-extern struct CourseName *gReplacedActNameTable[];
+struct CourseActNames {
+ struct ReplacedName courseName;
+ struct ReplacedName actName[MAX_ACTS_AND_100_COINS]; // indexed by actIndex (actNum - 1)
+};
+
+extern struct CourseActNames gReplacedCourseActNameTable[]; // indexed by COURSE_* constants
void smlua_text_utils_init(void);
void smlua_text_utils_shutdown(void);
@@ -50,8 +54,20 @@ s32 smlua_text_utils_act_name_mod_index(s16 courseNum, u8 actNum);
void smlua_text_utils_act_name_reset(s16 courseNum, u8 actNum);
/* |description|Replaces the castle secret stars text with `name`|descriptionEnd| */
void smlua_text_utils_castle_secret_stars_replace(const char* name);
+/* |description|Gets the castle secret stars text|descriptionEnd| */
+const char* smlua_text_utils_castle_secret_stars_get();
+/* |description|Gets the index of the mod that replaced the castle secret stars text|descriptionEnd| */
+s32 smlua_text_utils_castle_secret_stars_mod_index();
+/* |description|Resets the castle secret stars text|descriptionEnd| */
+void smlua_text_utils_castle_secret_stars_reset();
/* |description|Replace extra text (e.g. one of the castle's secret stars) with `text`|descriptionEnd| */
void smlua_text_utils_extra_text_replace(s16 index, const char* text);
+/* |description|Gets the extra text at `index`|descriptionEnd| */
+const char* smlua_text_utils_extra_text_get(s16 index);
+/* |description|Gets the index of the mod that replaced the extra text at `index`|descriptionEnd| */
+s32 smlua_text_utils_extra_text_mod_index(s16 index);
+/* |description|Resets the extra text at `index`|descriptionEnd| */
+void smlua_text_utils_extra_text_reset(s16 index);
/* |description|Gets the current language|descriptionEnd| */
const char* smlua_text_utils_get_language(void);