Fix inconsistent mapping between sSm64CharMap and str_ascii_to_dialog (#892)
Some checks are pending
Build coop / build-linux (push) Waiting to run
Build coop / build-steamos (push) Waiting to run
Build coop / build-windows-opengl (push) Waiting to run
Build coop / build-windows-directx (push) Waiting to run
Build coop / build-macos-arm (push) Waiting to run
Build coop / build-macos-intel (push) Waiting to run

This fixes inconsistent mappings between `sSm64CharMap` and `str_ascii_to_dialog` (used in `smlua_text_utils_dialog_replace`) to make the `text` field of `dialogEntry` consistent

`str_ascii_to_dialog` now also has mappings for the interpunct (`•`) and the double opening (`<<`) and closing (`>>`) quotes, which were missing before.
This commit is contained in:
Beckowl 2025-07-28 22:53:53 -03:00 committed by GitHub
parent c9db7006a3
commit 3d458d0212
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 15 additions and 188 deletions

View file

@ -3,100 +3,6 @@ extern "C" {
#include "game/scroll_targets.h"
}
//
// String
//
static const struct { const char *mStr; u8 mChar64; s32 mWidth; } sSm64CharMap[] = {
{ "0", 0x00, 7 }, { "1", 0x01, 7 }, { "2", 0x02, 7 }, { "3", 0x03, 7 }, { "4", 0x04, 7 }, { "5", 0x05, 7 },
{ "6", 0x06, 7 }, { "7", 0x07, 7 }, { "8", 0x08, 7 }, { "9", 0x09, 7 }, { "A", 0x0A, 6 }, { "B", 0x0B, 6 },
{ "C", 0x0C, 6 }, { "D", 0x0D, 6 }, { "E", 0x0E, 6 }, { "F", 0x0F, 6 }, { "G", 0x10, 6 }, { "H", 0x11, 6 },
{ "I", 0x12, 5 }, { "J", 0x13, 6 }, { "K", 0x14, 6 }, { "L", 0x15, 5 }, { "M", 0x16, 8 }, { "N", 0x17, 8 },
{ "O", 0x18, 6 }, { "P", 0x19, 6 }, { "Q", 0x1A, 6 }, { "R", 0x1B, 6 }, { "S", 0x1C, 6 }, { "T", 0x1D, 5 },
{ "U", 0x1E, 6 }, { "V", 0x1F, 6 }, { "W", 0x20, 8 }, { "X", 0x21, 7 }, { "Y", 0x22, 6 }, { "Z", 0x23, 6 },
{ "a", 0x24, 6 }, { "b", 0x25, 5 }, { "c", 0x26, 5 }, { "d", 0x27, 6 }, { "e", 0x28, 5 }, { "f", 0x29, 5 },
{ "g", 0x2A, 6 }, { "h", 0x2B, 5 }, { "i", 0x2C, 4 }, { "j", 0x2D, 5 }, { "k", 0x2E, 5 }, { "l", 0x2F, 3 },
{ "m", 0x30, 7 }, { "n", 0x31, 5 }, { "o", 0x32, 5 }, { "p", 0x33, 5 }, { "q", 0x34, 6 }, { "r", 0x35, 5 },
{ "s", 0x36, 5 }, { "t", 0x37, 5 }, { "u", 0x38, 5 }, { "v", 0x39, 5 }, { "w", 0x3A, 7 }, { "x", 0x3B, 7 },
{ "y", 0x3C, 5 }, { "z", 0x3D, 5 }, { "\'", 0x3E, 4 }, { ".", 0x3F, 4 }, { "^", 0x50, 8 }, { "|", 0x51, 8 },
{ "<", 0x52, 8 }, { ">", 0x53, 8 }, { "[A]", 0x54, 7 }, { "[B]", 0x55, 7 }, { "[C]", 0x56, 6 }, { "[Z]", 0x57, 7 },
{ "[R]", 0x58, 7 }, { ",", 0x6F, 4 }, { " ", 0x9E, 5 }, { "-", 0x9F, 6 }, { "/", 0xD0, 10 }, { "[%]", 0xE0, 7 },
{ "(", 0xE1, 5 }, { ")(", 0xE2, 10 }, { ")", 0xE3, 5 }, { "+", 0xE4, 9 }, { "&", 0xE5, 8 }, { ":", 0xE6, 4 },
{ "!", 0xF2, 5 }, { "%", 0xF3, 7 }, { "?", 0xF4, 7 }, { "~", 0xF7, 8 }, { "$", 0xF9, 8 }, { "@", 0xFA, 10 },
{ "*", 0xFB, 6 }, { "=", 0xFD, 10 }, { "\n", 0xFE, 0 },
};
static const char *DynOS_String_AddChar64(u8 *aStr64, const char *pStr, s32 &aIndex) {
for (const auto &c : sSm64CharMap) {
if (strstr(pStr, c.mStr) == pStr) {
aStr64[aIndex++] = c.mChar64;
return pStr + strlen(c.mStr);
}
}
// Put a space by default
aStr64[aIndex++] = 0x9E;
return pStr + 1;
}
u8 *DynOS_String_Convert(const char *aString, bool aHeapAlloc) {
// Allocation
static u8 sStringBuffer[8][2048];
static u32 sStringBufferIndex = 0;
u8 *_Str64;
if (aHeapAlloc) {
_Str64 = New<u8>(2048);
} else {
_Str64 = sStringBuffer[sStringBufferIndex];
sStringBufferIndex = (sStringBufferIndex + 1) % 8;
}
// Conversion
memset(_Str64, 0xFF, 2048);
const char *pStr = aString;
for (s32 i = 0; *pStr != 0 && i < 2047;) {
pStr = DynOS_String_AddChar64(_Str64, pStr, i);
}
return _Str64;
}
u8 *DynOS_String_Decapitalize(u8 *aStr64) {
bool _WasSpace = true;
for (u8 *pStr64 = aStr64; *pStr64 != 0xFF; pStr64++) {
if (*pStr64 >= 10 && *pStr64 <= 35) {
if (_WasSpace) _WasSpace = false;
else *pStr64 += 26;
} else if (*pStr64 >= 63) {
_WasSpace = true;
}
}
return aStr64;
}
s32 DynOS_String_Length(const u8 *aStr64) {
s32 _Length = 0;
for (; aStr64 && *aStr64 != 255; aStr64++, _Length++);
return _Length;
}
s32 DynOS_String_WidthChar64(u8 aChar64) {
for (const auto &c : sSm64CharMap) {
if (c.mChar64 == aChar64) {
return c.mWidth;
}
}
return 0;
}
s32 DynOS_String_Width(const u8 *aStr64) {
s32 _Width = 0;
for (; *aStr64 != 0xFF; aStr64++) {
_Width += DynOS_String_WidthChar64(*aStr64);
}
return _Width;
}
//
// Scroll Targets
//

View file

@ -448,86 +448,6 @@ void render_multi_text_string(s16 *xPos, s16 *yPos, s8 multiTextID)
}
#endif
u8 str_ascii_char_to_dialog(char c) {
switch (c) {
case '/': return 0xD0;
case '>': return 0x53;
case '<': return 0x52;
case '|': return 0x51;
case '^': return 0x50;
case '\n': return 0xFE;
case '$': return 0xF9;
case '~': return 0xF7;
case '?': return 0xF4;
case '%': return 0xF3;
case '!': return 0xF2;
case ':': return 0xE6;
case '&': return 0xE5;
case '+': return 0xE4;
case ')': return 0xE3;
case '(': return 0xE1;
case '-': return 0x9F;
case ' ': return 0x9E;
case ',': return 0x6F;
case '.': return 0x3F;
case '@': return 0xFA;
case '*': return 0xFB;
case '=': return 0xFD;
case '\'': return 0x3E;
case '\0': return DIALOG_CHAR_TERMINATOR;
default: return ((u8)c < 0xF0) ? ASCII_TO_DIALOG(c) : c;
}
}
void str_ascii_to_dialog(const char* string, u8* dialog, u16 length) {
const char* c = string;
u8* d = dialog;
u16 converted = 0;
while (*c != '\0' && converted < (length - 1)) {
if (!strncmp(c, "you", 3) && (c[3] < 'a' || c[3] > 'z')) {
*d = 0xD2;
c += 2;
} else if (!strncmp(c, "the", 3) && (c[3] < 'a' || c[3] > 'z')) {
*d = 0xD1;
c += 2;
} else if (!strncmp(c, "[R]", 3)) {
*d = 0x58;
c += 2;
} else if (!strncmp(c, "[Z]", 3)) {
*d = 0x57;
c += 2;
} else if (!strncmp(c, "[C]", 3)) {
*d = 0x56;
c += 2;
} else if (!strncmp(c, "[B]", 3)) {
*d = 0x55;
c += 2;
} else if (!strncmp(c, "[A]", 3)) {
*d = 0x54;
c += 2;
} else if (!strncmp(c, "[Z]", 3)) {
*d = 0x57;
c += 2;
} else if (!strncmp(c, ")(", 2)) {
*d = 0xE2;
c += 1;
} else if (!strncmp(c, "[%]", 3)) {
*d = 0xE0;
c += 2;
} else if (!strncmp(c, "", 2)) {
*d = 0xFA;
c += 2;
} else {
*d = str_ascii_char_to_dialog(*c);
}
d++;
c++;
converted++;
}
*d = DIALOG_CHAR_TERMINATOR;
}
f32 get_generic_dialog_width(u8* dialog) {
#ifdef VERSION_JP
return 0;
@ -551,7 +471,7 @@ f32 get_generic_dialog_width(u8* dialog) {
f32 get_generic_ascii_string_width(const char* ascii) {
u8 dialog[256] = { DIALOG_CHAR_TERMINATOR };
str_ascii_to_dialog(ascii, dialog, strlen(ascii));
convert_string_ascii_to_sm64(dialog, ascii, false);
return get_generic_dialog_width(dialog);
}
@ -567,13 +487,13 @@ f32 get_generic_dialog_height(u8* dialog) {
f32 get_generic_ascii_string_height(const char* ascii) {
u8 dialog[256] = { DIALOG_CHAR_TERMINATOR };
str_ascii_to_dialog(ascii, dialog, strlen(ascii));
convert_string_ascii_to_sm64(dialog, ascii, false);
return get_generic_dialog_height(dialog);
}
void print_generic_ascii_string(s16 x, s16 y, const char* ascii) {
u8 dialog[256] = { DIALOG_CHAR_TERMINATOR };
str_ascii_to_dialog(ascii, dialog, strlen(ascii));
convert_string_ascii_to_sm64(dialog, ascii, false);
print_generic_string(x, y, dialog);
}
@ -2637,7 +2557,7 @@ void render_pause_camera_options(s16 x, s16 y, s8 *index, s16 xIndex) {
void render_pause_course_options(s16 x, s16 y, s8 *index, s16 yIndex) {
u8 TEXT_EXIT_TO_CASTLE[16] = { DIALOG_CHAR_TERMINATOR };
str_ascii_to_dialog("EXIT TO CASTLE", TEXT_EXIT_TO_CASTLE, 15);
convert_string_ascii_to_sm64(TEXT_EXIT_TO_CASTLE, "EXIT TO CASTLE", false);
#ifdef VERSION_EU
u8 textContinue[][10] = {

View file

@ -40,7 +40,7 @@ const struct { const char *str; u8 c; u8 menu; } sSm64CharMap[] = {
{ "z", 0x3D, 0 },
// Punctuation
{ "...", 0xE6, 0 }, // ellipsis
{ ":", 0xE6, 0 }, // colon
{ ")(", 0xE2, 0 }, // close-open parentheses
{ "<<", 0xF5, 0 }, // double quote open
{ ">>", 0xF6, 0 }, // double quote close
@ -67,16 +67,17 @@ const struct { const char *str; u8 c; u8 menu; } sSm64CharMap[] = {
{ "[C]", 0x56, 0 }, // bold C
{ "[Z]", 0x57, 0 }, // bold Z
{ "[R]", 0x58, 0 }, // bold R
{ "<->", 0xE4, 0 }, // left-right arrow
{ "+", 0xE4, 0 }, // left-right arrow
{ "^", 0x50, 0 }, // up arrow
{ "|", 0x51, 0 }, // down arrow
{ "<", 0x52, 0 }, // left arrow
{ ">", 0x53, 0 }, // right arrow
{ "+", 0xF9, 1 }, // coin
{ "@", 0xFA, 1 }, // star filled
{ "$", 0xF9, 1 }, // coin
{ "", 0xFA, 1 }, // star filled
{ "@", 0xFA, 1 }, // star filled (both ★ and @ match 0xFA)
{ "*", 0xFB, 1 }, // multiply
{ "", 0xFC, 0 },
{ "$", 0xFD, 0 }, // star empty
{ "", 0xFC, 0 }, // interpunct (unused)
{ "=", 0xFD, 0 }, // star empty
{ "\n", 0xFE, 1 }, // New line
{ NULL, 0xFF, 1 }, // Null terminator
};

View file

@ -7,6 +7,8 @@ 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);
void convert_string_ascii_to_sm64(u8 *str64, const char *strAscii, bool menu);
void convert_string_sm64_to_ascii(char *strAscii, const u8 *str64);
/* |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

View file

@ -21,7 +21,6 @@ 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;
@ -146,9 +145,8 @@ void smlua_text_utils_shutdown(void) {
}
static u8* smlua_text_utils_convert(const char* str) {
s32 len = strlen(str);
u8* dialogStr = calloc(len + 2, sizeof(u8));
str_ascii_to_dialog(str, dialogStr, len + 1);
u8* dialogStr = calloc(strlen(str) + 2, sizeof(u8));
convert_string_ascii_to_sm64(dialogStr, str, false);
return dialogStr;
}