Reformatted for code review. Moved config to include/config/decap.h.

This commit is contained in:
Ariel A 2024-01-17 01:12:04 -05:00
parent 499b4a6d42
commit 8a52316dd2
10 changed files with 130 additions and 111 deletions

View File

@ -29,7 +29,8 @@ static const s32 sPowersOfTen[] =
// Tries to determine whether `str` is safe to prepend a ctrl char to
// gStringVarX are always safe, as well as stack allocated IWRAM
// (if `length mod 4` is 1 or 2)
bool32 IsStringAddrSafe(u8 *str, u32 length) {
bool32 IsStringAddrSafe(u8 *str, u32 length)
{
if (((u32)str) >> 24 == 3)
return (str >= gStackBase && (length & 3) && (length & 3) <= 2);
return (str >= gStringVar1 && str < sUnknownStringVar);
@ -40,7 +41,8 @@ u8 *StringCopy_Nickname(u8 *dest, const u8 *src)
u32 i;
u32 limit = POKEMON_NAME_LENGTH;
if (DECAP_ENABLED && !DECAP_NICKNAMES) {
if (DECAP_ENABLED && !DECAP_NICKNAMES)
{
if (IsStringAddrSafe(dest, limit) && *src != CHAR_FIXED_CASE)
*dest++ = CHAR_FIXED_CASE;
else if (*src == CHAR_FIXED_CASE)
@ -64,10 +66,8 @@ u8 *StringGet_Nickname(u8 *str)
u8 i;
u32 limit = POKEMON_NAME_LENGTH;
if (DECAP_ENABLED && !DECAP_NICKNAMES) {
if (*str == CHAR_FIXED_CASE)
str++;
}
if (DECAP_ENABLED && !DECAP_NICKNAMES && *str == CHAR_FIXED_CASE)
str++;
for (i = 0; i < limit; i++)
if (str[i] == EOS)
@ -82,10 +82,8 @@ u8 *StringCopy_PlayerName(u8 *dest, const u8 *src)
s32 i;
s32 limit = PLAYER_NAME_LENGTH;
if (DECAP_ENABLED && !DECAP_NICKNAMES) {
if (IsStringAddrSafe(dest, limit) && *src != CHAR_FIXED_CASE)
*dest++ = CHAR_FIXED_CASE;
}
if (DECAP_ENABLED && !DECAP_NICKNAMES && IsStringAddrSafe(dest, limit) && *src != CHAR_FIXED_CASE)
*dest++ = CHAR_FIXED_CASE;
for (i = 0; i < limit; i++)
{
@ -101,11 +99,10 @@ u8 *StringCopy_PlayerName(u8 *dest, const u8 *src)
u8 *StringCopy(u8 *dest, const u8 *src)
{
if (DECAP_ENABLED && DECAP_MIRRORING) {
// If `src` is mirrored, prepend fixed-case char
if (IsMirrorPtr(src) && *src != CHAR_FIXED_CASE)
*dest++ = CHAR_FIXED_CASE;
}
// If `src` is mirrored, prepend fixed-case char
if (DECAP_ENABLED && DECAP_MIRRORING && IsMirrorPtr(src) && *src != CHAR_FIXED_CASE)
*dest++ = CHAR_FIXED_CASE;
while (*src != EOS)
{
*dest = *src;
@ -156,7 +153,8 @@ u16 StringLength(const u8 *str)
s32 StringCompare(const u8 *str1, const u8 *str2)
{
// Ignore leading fixed-case char
if (DECAP_ENABLED) {
if (DECAP_ENABLED)
{
if (*str1 == CHAR_FIXED_CASE)
str1++;
if (*str2 == CHAR_FIXED_CASE)
@ -176,7 +174,8 @@ s32 StringCompare(const u8 *str1, const u8 *str2)
s32 StringCompareN(const u8 *str1, const u8 *str2, u32 n)
{
// Ignore leading fixed-case char
if (DECAP_ENABLED) {
if (DECAP_ENABLED)
{
if (*str1 == CHAR_FIXED_CASE)
str1++;
if (*str2 == CHAR_FIXED_CASE)
@ -391,9 +390,11 @@ u8 *StringExpandPlaceholders(u8 *dest, const u8 *src)
{
case PLACEHOLDER_BEGIN:
placeholderId = *src++;
if (DECAP_ENABLED) {
if (DECAP_ENABLED)
{
// Handle fixed-case versions of placeholders
if (!fixedCase && (placeholderId & PLACEHOLDER_FIXED_MASK || placeholderId == PLACEHOLDER_ID_PLAYER)) {
if (!fixedCase && (placeholderId & PLACEHOLDER_FIXED_MASK || placeholderId == PLACEHOLDER_ID_PLAYER))
{
*dest++ = CHAR_FIXED_CASE;
expandedString = GetExpandedPlaceholder(placeholderId & ~PLACEHOLDER_FIXED_MASK);
dest = StringExpandPlaceholders(dest, expandedString);
@ -429,11 +430,11 @@ u8 *StringExpandPlaceholders(u8 *dest, const u8 *src)
}
break;
case EOS:
#if DECAP_ENABLED
if (fixedCase)
if (DECAP_ENABLED && fixedCase)
*dest++ = CHAR_UNFIX_CASE;
*dest = EOS;
return dest;
#if DECAP_ENABLED
case CHAR_UNFIX_CASE:
fixedCase = FALSE;
*dest++ = c;
@ -441,9 +442,6 @@ u8 *StringExpandPlaceholders(u8 *dest, const u8 *src)
case CHAR_FIXED_CASE:
fixedCase = TRUE;
// fallthrough
#else
*dest = EOS;
return dest;
#endif
case CHAR_PROMPT_SCROLL:
case CHAR_PROMPT_CLEAR:
@ -770,11 +768,9 @@ static const u8 *SkipExtCtrlCode(const u8 *s)
s++;
s += GetExtCtrlCodeLength(*s);
}
if (DECAP_ENABLED) {
while (*s == CHAR_FIXED_CASE || *s == CHAR_UNFIX_CASE)
s++;
}
while (DECAP_ENABLED && (*s == CHAR_FIXED_CASE || *s == CHAR_UNFIX_CASE))
s++;
return s;
}

View File

@ -241,23 +241,30 @@ static void SetFontsPointer(const struct FontInfo *fonts)
gFonts = fonts;
}
void * MirrorPtr(const void *ptr) {
if (((u32)ptr) >> 27) // ROM
// Any ROM address must have bit 27 set (0x8000000)
// so this is used to check if a pointer points to ROM
#define IS_ROM_PTR(ptr) (((u32)ptr) >> 27)
void * MirrorPtr(const void *ptr)
{
if (IS_ROM_PTR(ptr)) // ROM
return ROM_MIRROR_PTR(ptr);
else // RAM
return RAM_MIRROR_PTR(ptr);
}
void * UnmirrorPtr(const void *ptr) {
void * UnmirrorPtr(const void *ptr)
{
u32 value = (u32) ptr;
if (value >> 27) // ROM
if (IS_ROM_PTR(ptr)) // ROM
return (void*)(value & ~ROM_MIRROR_MASK);
else // RAM
return (void*)(value & ~RAM_MIRROR_MASK);
}
bool32 IsMirrorPtr(const void *ptr) {
if (((u32)ptr) >> 27)
bool32 IsMirrorPtr(const void *ptr)
{
if (IS_ROM_PTR(ptr))
return ((u32)ptr) & ROM_MIRROR_MASK;
else
return ((u32)ptr) & RAM_MIRROR_MASK;
@ -290,7 +297,8 @@ u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8
return AddTextPrinter(&printerTemplate, speed, callback);
}
u16 AddTextPrinterFixedCaseParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) {
u16 AddTextPrinterFixedCaseParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16))
{
return AddTextPrinterParameterized(windowId, fontId, MirrorPtr(str), x, y, speed, callback);
}
@ -307,16 +315,14 @@ bool16 AddTextPrinter(struct TextPrinterTemplate *printerTemplate, u8 speed, voi
sTempTextPrinter.textSpeed = speed;
sTempTextPrinter.delayCounter = 0;
sTempTextPrinter.scrollDistance = 0;
if (DECAP_ENABLED) {
if (DECAP_MIRRORING) {
// string address is mirrored; treat it as a fixed-case string
if (IsMirrorPtr(printerTemplate->currentChar)) {
sTempTextPrinter.lastChar = CHAR_FIXED_CASE;
// Techhnically, unmirroring isn't necessary;
// but older emulators may not support mirroring
// printerTemplate->currentChar = UnmirrorPtr(printerTemplate->currentChar);
}
}
if (DECAP_ENABLED)
{
// string address is mirrored; treat it as a fixed-case string
// Technically, unmirroring isn't necessary;
// but older emulators may not support mirroring
// printerTemplate->currentChar = UnmirrorPtr(printerTemplate->currentChar);
if (DECAP_MIRRORING && IsMirrorPtr(printerTemplate->currentChar))
sTempTextPrinter.lastChar = CHAR_FIXED_CASE;
sTempTextPrinter.lastChar = 0;
}
@ -976,8 +982,8 @@ const u16 gLowercaseDiffTable[] = {
[CHAR_SPACER] = 0,
[CHAR_A ... CHAR_Z] = CHAR_a - CHAR_A,
// é treated as uppercase so POKéDEX, POKéMON, etc. decapped
[CHAR_e_ACUTE] = 0x100,
[CHAR_SGL_QUOTE_RIGHT] = 0x100,
[CHAR_e_ACUTE] = 0 | MARK_UPPER_FLAG,
[CHAR_SGL_QUOTE_RIGHT] = 0 | MARK_UPPER_FLAG,
// International
[CHAR_A_GRAVE ... CHAR_A_ACUTE] = CHAR_a_GRAVE - CHAR_A_GRAVE,
[CHAR_A_CIRCUMFLEX] = CHAR_a_CIRCUMFLEX,
@ -1020,7 +1026,8 @@ static u16 RenderText(struct TextPrinter *textPrinter)
currChar = *textPrinter->printerTemplate.currentChar;
textPrinter->printerTemplate.currentChar++;
if (DECAP_ENABLED) {
if (DECAP_ENABLED)
{
lastChar = textPrinter->lastChar;
if (lastChar != CHAR_FIXED_CASE)
textPrinter->lastChar = currChar;
@ -1184,7 +1191,7 @@ static u16 RenderText(struct TextPrinter *textPrinter)
// Clear fixed case
textPrinter->lastChar = currChar;
return RENDER_FINISH;
#if DECAP_ENABLED
#if DECAP_ENABLED
// Disable/enable decapitalization
// In vanilla these are 1-2 pixel spaces
case CHAR_FIXED_CASE:
@ -1212,14 +1219,15 @@ static u16 RenderText(struct TextPrinter *textPrinter)
if (lastChar == CHAR_P) // PC, PP, PM
lastChar = 0;
break;
#endif
}
// If not Japanese or fixed case, try to decap
if (!textPrinter->japanese && lastChar != CHAR_FIXED_CASE) {
if (DECAP_ENABLED && !textPrinter->japanese && lastChar != CHAR_FIXED_CASE)
{
// Two consecutive uppercase chars; lowercase this one
if (IS_UPPER(currChar) && IS_UPPER(lastChar))
currChar = TO_LOWER(currChar);
#endif
}
switch (subStruct->fontId)

View File

@ -7,20 +7,7 @@
// loaded at once but not copied to vram yet.
#define TEXT_SKIP_DRAW 0xFF
/*
Enable automatic decapitalization of *all* text
Exceptions:
- Several bigrams: TV, TM, HP, HM, PC, PP, PM
- Player names, nicknames, box names
- Strings beginning with {FIXED_CASE}:
- C strings that use `_C` or `__C`
- ASM strings that use `.fixstr`
- If mirroring enabled, string addresses passed through MirrorPtr
*/
#define DECAP_ENABLED TRUE
// Enables signaling that a string's case should be preserved
// by *mirroring* its address: i.e 08xxxxxx to 0Axxxxxx
#define DECAP_MIRRORING TRUE
// See include/config/decap.h for decap configuration
#if DECAP_MIRRORING
#define ROM_MIRROR_MASK (0x02000000)
#define RAM_MIRROR_MASK (0x00800000)
@ -28,20 +15,6 @@ Exceptions:
#define RAM_MIRROR_PTR(x) ((void*)(((u32)(x)) | RAM_MIRROR_MASK))
#endif
// If TRUE, *all* Pokemon nicknames and player names will be decapitalized.
// Otherwise, their case will be preserved. Default FALSE
#define DECAP_NICKNAMES FALSE
#define DECAP_MAIN_MENU TRUE // main menu options
#define DECAP_OPTION_MENU TRUE // Option menu texts
#define DECAP_START_MENU TRUE // Start menu options/save menu text
#define DECAP_PARTY_MENU TRUE // Party menu texts
#define DECAP_MAP_NAMES TRUE // Map/location names
#define DECAP_EASY_CHAT TRUE // Both words and interface
#define DECAP_FIELD_MSG TRUE // Field messages (including scripts!)
#define DECAP_SUMMARY TRUE // Summary interface
#define DECAP_ITEM_NAMES TRUE // Via ItemId_GetName
enum {
FONT_SMALL,
FONT_NORMAL,
@ -172,8 +145,12 @@ extern u8 gDisableTextPrinters;
extern struct TextGlyph gCurGlyph;
extern const u16 gLowercaseDiffTable[];
#define IS_UPPER(x) (gLowercaseDiffTable[(x) & 0xFF])
#define TO_LOWER(x) (((x) + gLowercaseDiffTable[(x)]) & 0xFF)
// in gLowercaseDiffTable, 0x100 represents a character treated as uppercase,
// but that maps to itself; only the lower 8 bits are used for mapping
#define MARK_UPPER_FLAG 0x100
#define LOWERCASE_DIFF_MASK 0xFF
#define IS_UPPER(x) (gLowercaseDiffTable[(x) & LOWERCASE_DIFF_MASK])
#define TO_LOWER(x) (((x) + gLowercaseDiffTable[(x)]) & LOWERCASE_DIFF_MASK)
void * UnmirrorPtr(const void * ptr);
void * MirrorPtr(const void * ptr);

35
include/config/decap.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef GUARD_CONFIG_DECAP_H
#define GUARD_CONFIG_DECAP_H
/*
Enable automatic decapitalization of *all* text
Exceptions:
- Several bigrams: TV, TM, HP, HM, PC, PP, PM
- Player names, nicknames, box names
- Strings beginning with {FIXED_CASE}
- C strings that use `_C` or `__C`
- ASM strings that use `.fixstr`
- If mirroring enabled, string addresses passed through MirrorPtr
*/
#define DECAP_ENABLED TRUE
// Enables signaling that a string's case should be preserved
// by *mirroring* its address: i.e 08xxxxxx to 0Axxxxxx
// Unless you are targeting a different platform than the GBA,
// there aren't many reasons to disable this
#define DECAP_MIRRORING TRUE
// If TRUE, *all* Pokemon nicknames and player names will be decapitalized.
// Otherwise, their case will be preserved. Default FALSE
#define DECAP_NICKNAMES FALSE
#define DECAP_MAIN_MENU TRUE // Main menu text.
#define DECAP_OPTION_MENU TRUE // Option menu text.
#define DECAP_START_MENU TRUE // Start menu options & Save menu text.
#define DECAP_PARTY_MENU TRUE // Party menu text.
#define DECAP_MAP_NAMES TRUE // Map and location names.
#define DECAP_EASY_CHAT TRUE // Easy Chat words and interface.
#define DECAP_FIELD_MSG TRUE // Field messages (including scripts!).
#define DECAP_SUMMARY TRUE // Summary interface text.
#define DECAP_ITEM_NAMES TRUE // Item names (obtained via ItemId_GetName).
#endif // GUARD_CONFIG_DECAP_H

View File

@ -6,6 +6,7 @@
#include "config/item.h"
#include "config/pokemon.h"
#include "config/overworld.h"
#include "config/decap.h"
// Invalid Versions show as "----------" in Gen 4 and Gen 5's summary screen.
// In Gens 6 and 7, invalid versions instead show "a distant land" in the summary screen.

View File

@ -3198,12 +3198,11 @@ static const u8 *BattleStringGetPlayerName(u8 *text, u8 battler)
break;
}
if (DECAP_ENABLED && !DECAP_NICKNAMES) {
if (toCpy != text && *toCpy != CHAR_FIXED_CASE) {
*text = CHAR_FIXED_CASE;
StringCopyN(text+1, toCpy, PLAYER_NAME_LENGTH);
toCpy = text;
}
if (DECAP_ENABLED && !DECAP_NICKNAMES && toCpy != text && *toCpy != CHAR_FIXED_CASE)
{
*text = CHAR_FIXED_CASE;
StringCopyN(text+1, toCpy, PLAYER_NAME_LENGTH);
toCpy = text;
}
return toCpy;
@ -3637,13 +3636,15 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
if (toCpy != NULL)
{
if (DECAP_ENABLED) {
if (DECAP_ENABLED)
{
bool32 fixedCase = *src & PLACEHOLDER_FIXED_MASK;
if (fixedCase)
dst[dstID++] = CHAR_FIXED_CASE;
while (*toCpy != EOS) {
while (*toCpy != EOS)
{
if (*toCpy == CHAR_FIXED_CASE)
fixedCase = TRUE;
else if (*toCpy == CHAR_UNFIX_CASE)
@ -3652,7 +3653,9 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
}
if (fixedCase)
dst[dstID++] = CHAR_UNFIX_CASE;
} else {
}
else
{
while (*toCpy != EOS)
dst[dstID++] = *toCpy++;
}

View File

@ -117,10 +117,13 @@ bool8 ShowFieldMessageFromBuffer(void)
static void ExpandStringAndStartDrawFieldMessage(const u8 *str, bool32 allowSkippingDelayWithButtonPress)
{
if (DECAP_ENABLED && DECAP_MIRRORING && !DECAP_FIELD_MSG) {
if (DECAP_ENABLED && DECAP_MIRRORING && !DECAP_FIELD_MSG)
{
gStringVar4[0] = CHAR_FIXED_CASE;
StringExpandPlaceholders(gStringVar4+1, str);
} else {
}
else
{
StringExpandPlaceholders(gStringVar4, str);
}
AddTextPrinterForMessage(allowSkippingDelayWithButtonPress);

View File

@ -1857,16 +1857,16 @@ static void SaveInputText(void)
if (sNamingScreen->textBuffer[i] != CHAR_SPACE && sNamingScreen->textBuffer[i] != EOS)
{
// If there is space, prepend fixed-case character
#if (DECAP_ENABLED) && !(DECAP_NICKNAMES)
if ((sNamingScreen->templateNum == NAMING_SCREEN_PLAYER
if (DECAP_ENABLED && !DECAP_NICKNAMES
&& (sNamingScreen->templateNum == NAMING_SCREEN_PLAYER
|| sNamingScreen->templateNum == NAMING_SCREEN_NICKNAME
|| sNamingScreen->templateNum == NAMING_SCREEN_CAUGHT_MON
) && sNamingScreen->textBuffer[GetTextEntryPosition()] == EOS)
|| sNamingScreen->templateNum == NAMING_SCREEN_CAUGHT_MON)
&& sNamingScreen->textBuffer[GetTextEntryPosition()] == EOS)
{
*sNamingScreen->destBuffer = CHAR_FIXED_CASE;
StringCopyN(sNamingScreen->destBuffer + 1, sNamingScreen->textBuffer, sNamingScreen->template->maxChars + 0);
} else
#endif
}
else
StringCopyN(sNamingScreen->destBuffer, sNamingScreen->textBuffer, sNamingScreen->template->maxChars + 1);
break;
}

View File

@ -2154,10 +2154,8 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
}
else
{
if (DECAP_ENABLED && !DECAP_NICKNAMES) {
if (IsStringAddrSafe(data, POKEMON_NAME_LENGTH))
if (DECAP_ENABLED && !DECAP_NICKNAMES && IsStringAddrSafe(data, POKEMON_NAME_LENGTH))
*data++ = CHAR_FIXED_CASE;
}
retVal = 0;
while (retVal < min(sizeof(boxMon->nickname), POKEMON_NAME_LENGTH))
{
@ -2520,10 +2518,8 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
break;
case MON_DATA_OT_NAME:
{
if (DECAP_ENABLED && !DECAP_NICKNAMES) {
if (IsStringAddrSafe(data, PLAYER_NAME_LENGTH))
*data++ = CHAR_FIXED_CASE;
}
if (DECAP_ENABLED && !DECAP_NICKNAMES && IsStringAddrSafe(data, PLAYER_NAME_LENGTH))
*data++ = CHAR_FIXED_CASE;
retVal = 0;
while (retVal < PLAYER_NAME_LENGTH)

View File

@ -1186,12 +1186,12 @@ static s32 TryMessage(s32 i, s32 n, const u8 *string)
if (string[j] == CHAR_PROMPT_CLEAR)
j++;
}
if (DECAP_ENABLED) {
// ignore case-fixing characters in string
if (string[j] == CHAR_FIXED_CASE || string[j] == CHAR_UNFIX_CASE) {
k--; // will be incremented in 'continue'
continue;
}
if (DECAP_ENABLED && (string[j] == CHAR_FIXED_CASE || string[j] == CHAR_UNFIX_CASE))
{
// Ignores case-fixing characters in string
// k will be incremented in 'continue'
k--;
continue;
}
if (string[j] != event->pattern[k])
{