diff --git a/include/pokemon_storage_system.h b/include/pokemon_storage_system.h index a0e4f8947..b7fca2331 100644 --- a/include/pokemon_storage_system.h +++ b/include/pokemon_storage_system.h @@ -5,6 +5,7 @@ #define IN_BOX_ROWS 5 // Number of rows, 6 Pokémon per row #define IN_BOX_COLUMNS 6 // Number of columns, 5 Pokémon per column #define IN_BOX_COUNT (IN_BOX_ROWS * IN_BOX_COLUMNS) +#define BOX_NAME_LENGTH 8 /* COLUMNS @@ -19,7 +20,7 @@ struct PokemonStorage { /*0x0000*/ u8 currentBox; /*0x0001*/ struct BoxPokemon boxes[TOTAL_BOXES_COUNT][IN_BOX_COUNT]; - /*0x8344*/ u8 boxNames[TOTAL_BOXES_COUNT][9]; + /*0x8344*/ u8 boxNames[TOTAL_BOXES_COUNT][BOX_NAME_LENGTH + 1]; /*0x83C2*/ u8 boxWallpapers[TOTAL_BOXES_COUNT]; }; diff --git a/include/walda_phrase.h b/include/walda_phrase.h index 3d7701123..1cfd8af48 100644 --- a/include/walda_phrase.h +++ b/include/walda_phrase.h @@ -1,6 +1,8 @@ #ifndef GUARD_WALDA_PHRASE_H #define GUARD_WALDA_PHRASE_H +#define WALDA_PHRASE_LENGTH 15 + u16 TryBufferWaldaPhrase(void); void DoWaldaNamingScreen(void); u16 TryGetWallpaperWithWaldaPhrase(void); diff --git a/src/menu_specialized.c b/src/menu_specialized.c index 2fd12f2fd..c9d895e19 100644 --- a/src/menu_specialized.c +++ b/src/menu_specialized.c @@ -997,7 +997,7 @@ void GetConditionMenuMonNameAndLocString(u8 *locationDst, u8 *nameDst, u16 boxId if (box == TOTAL_BOXES_COUNT) // Party mon. BufferConditionMenuSpacedStringN(&locationDst[5], gText_InParty, 8); else - BufferConditionMenuSpacedStringN(&locationDst[5], GetBoxNamePtr(box), 8); + BufferConditionMenuSpacedStringN(&locationDst[5], GetBoxNamePtr(box), BOX_NAME_LENGTH); } else { diff --git a/src/naming_screen.c b/src/naming_screen.c index 5a297789a..0d0ec7fca 100644 --- a/src/naming_screen.c +++ b/src/naming_screen.c @@ -25,6 +25,7 @@ #include "menu.h" #include "text_window.h" #include "overworld.h" +#include "walda_phrase.h" #include "constants/event_objects.h" #include "constants/rgb.h" @@ -2089,7 +2090,7 @@ static void Debug_NamingScreenNickname(void) static const struct NamingScreenTemplate sPlayerNamingScreenTemplate = { .copyExistingString = FALSE, - .maxChars = 7, + .maxChars = PLAYER_NAME_LENGTH, .iconFunction = 1, .addGenderIcon = FALSE, .initialPage = KBPAGE_LETTERS_UPPER, @@ -2100,7 +2101,7 @@ static const struct NamingScreenTemplate sPlayerNamingScreenTemplate = static const struct NamingScreenTemplate sPCBoxNamingTemplate = { .copyExistingString = FALSE, - .maxChars = 8, + .maxChars = BOX_NAME_LENGTH, .iconFunction = 2, .addGenderIcon = FALSE, .initialPage = KBPAGE_LETTERS_UPPER, @@ -2111,7 +2112,7 @@ static const struct NamingScreenTemplate sPCBoxNamingTemplate = static const struct NamingScreenTemplate sMonNamingScreenTemplate = { .copyExistingString = FALSE, - .maxChars = 10, + .maxChars = POKEMON_NAME_LENGTH, .iconFunction = 3, .addGenderIcon = TRUE, .initialPage = KBPAGE_LETTERS_UPPER, @@ -2122,7 +2123,7 @@ static const struct NamingScreenTemplate sMonNamingScreenTemplate = static const struct NamingScreenTemplate sWaldaWordsScreenTemplate = { .copyExistingString = TRUE, - .maxChars = 15, + .maxChars = WALDA_PHRASE_LENGTH, .iconFunction = 4, .addGenderIcon = FALSE, .initialPage = KBPAGE_LETTERS_UPPER, diff --git a/src/pokemon_storage_system.c b/src/pokemon_storage_system.c index a58187d8b..cf5beb4fe 100644 --- a/src/pokemon_storage_system.c +++ b/src/pokemon_storage_system.c @@ -5512,7 +5512,7 @@ static void InitBoxTitle(u8 boxId) sStorage->boxTitleAltPalOffset = 0x10e + 16 * tagIndex; sStorage->wallpaperPalBits |= 0x10000 << tagIndex; - StringCopyPadded(sStorage->boxTitleText, GetBoxNamePtr(boxId), 0, 8); + StringCopyPadded(sStorage->boxTitleText, GetBoxNamePtr(boxId), 0, BOX_NAME_LENGTH); DrawTextWindowAndBufferTiles(sStorage->boxTitleText, sStorage->boxTitleTiles, 0, 0, 2); LoadSpriteSheet(&spriteSheet); x = GetBoxTitleBaseX(GetBoxNamePtr(boxId)); @@ -5557,7 +5557,7 @@ static void CreateIncomingBoxTitle(u8 boxId, s8 direction) template.paletteTag = PALTAG_BOX_TITLE; } - StringCopyPadded(sStorage->boxTitleText, GetBoxNamePtr(boxId), 0, 8); + StringCopyPadded(sStorage->boxTitleText, GetBoxNamePtr(boxId), 0, BOX_NAME_LENGTH); DrawTextWindowAndBufferTiles(sStorage->boxTitleText, sStorage->boxTitleTiles, 0, 0, 2); LoadSpriteSheet(&spriteSheet); LoadPalette(sBoxTitleColors[GetBoxWallpaper(boxId)], palOffset, sizeof(sBoxTitleColors[0])); diff --git a/src/pokenav_conditions_1.c b/src/pokenav_conditions_1.c index c415de1ac..d2424629a 100644 --- a/src/pokenav_conditions_1.c +++ b/src/pokenav_conditions_1.c @@ -435,7 +435,7 @@ void CopyMonNameGenderLocation(s16 id, u8 arg1) if (boxId == TOTAL_BOXES_COUNT) CopyStringLeftAlignedToConditionData(&structPtr->searchLocBuffer[arg1][5], gText_InParty, 8); else - CopyStringLeftAlignedToConditionData(&structPtr->searchLocBuffer[arg1][5], GetBoxNamePtr(boxId), 8); + CopyStringLeftAlignedToConditionData(&structPtr->searchLocBuffer[arg1][5], GetBoxNamePtr(boxId), BOX_NAME_LENGTH); } else { diff --git a/src/walda_phrase.c b/src/walda_phrase.c index 18fb2791b..aa85c0d60 100644 --- a/src/walda_phrase.c +++ b/src/walda_phrase.c @@ -12,17 +12,20 @@ extern const u8 gText_Peekaboo[]; -// this file's functions static void CB2_HandleGivenWaldaPhrase(void); -static u32 GetWaldaPhraseInputCase(u8 *inputPtr); -static bool32 TryCalculateWallpaper(u16* backgroundClr, u16 *foregroundClr, u8 *iconId, u8 *patternId, u16 trainerId, u8 *phrase); -static void sub_81D9D5C(u8 *array, u8 *letterTableIds, u32 arg2, u32 arg3, u32 loopCount); -static u32 sub_81D9DAC(u8 *array, u32 arg1, u32 loopCount); -static void sub_81D9C90(u8 *array, s32 arg1, s32 arg2); -static void sub_81D9CDC(u8 *array, u32 loopCount, u8 arg2); +static u32 GetWaldaPhraseInputCase(u8 *); +static bool32 TryCalculateWallpaper(u16 *, u16 *, u8 *, u8 *, u16, u8 *); +static void SetWallpaperDataFromLetter(u8 *, u8 *, u32, u32, u32); +static u32 GetWallpaperDataBits(u8 *, u32, u32); +static void RotateWallpaperDataLeft(u8 *, s32, s32); +static void MaskWallpaperData(u8 *, u32, u8); -// only consonants are allowed, no vowels, some lowercase letters are missing -static const u8 sWaldaLettersTable[] = +// There are 32 (2^5) unique letters allowed in a successful phrase for Walda. +#define BITS_PER_LETTER 5 + +// The letters allowed in a successful phrase for Walda +// All vowels are excluded, as well as X/x, Y/y, l, r, t, v, w, and z. +static const u8 sWaldaLettersTable[1 << BITS_PER_LETTER] = { CHAR_B, CHAR_C, CHAR_D, CHAR_F, CHAR_G, CHAR_H, CHAR_J, CHAR_K, CHAR_L, CHAR_M, CHAR_N, CHAR_P, CHAR_Q, CHAR_R, CHAR_S, CHAR_T, CHAR_V, CHAR_W, CHAR_Z, CHAR_b, CHAR_c, CHAR_d, CHAR_f, CHAR_g, CHAR_h, CHAR_j, CHAR_k, CHAR_m, CHAR_n, CHAR_p, CHAR_q, CHAR_s @@ -30,9 +33,9 @@ static const u8 sWaldaLettersTable[] = enum { - PHRASE_GIVEN_NEW, + PHRASE_CHANGED, PHRASE_NO_CHANGE, - PHRASE_FIRST_ATTEMPT + PHRASE_EMPTY }; u16 TryBufferWaldaPhrase(void) @@ -56,13 +59,15 @@ static void CB2_HandleGivenWaldaPhrase(void) switch (gSpecialVar_0x8004) { - case PHRASE_FIRST_ATTEMPT: + case PHRASE_EMPTY: + // If saved phrase is also empty, set default phrase + // Otherwise keep saved phrase if (IsWaldaPhraseEmpty()) SetWaldaPhrase(gText_Peekaboo); else gSpecialVar_0x8004 = PHRASE_NO_CHANGE; break; - case PHRASE_GIVEN_NEW: + case PHRASE_CHANGED: SetWaldaPhrase(gStringVar2); break; case PHRASE_NO_CHANGE: @@ -76,12 +81,16 @@ static void CB2_HandleGivenWaldaPhrase(void) static u32 GetWaldaPhraseInputCase(u8 *inputPtr) { + // No input given if (inputPtr[0] == EOS) - return PHRASE_FIRST_ATTEMPT; + return PHRASE_EMPTY; + + // Input given is the same as saved phrase if (StringCompare(inputPtr, GetWaldaPhrasePtr()) == 0) return PHRASE_NO_CHANGE; - return PHRASE_GIVEN_NEW; + // Input is new phrase + return PHRASE_CHANGED; } u16 TryGetWallpaperWithWaldaPhrase(void) @@ -99,7 +108,7 @@ u16 TryGetWallpaperWithWaldaPhrase(void) } SetWaldaWallpaperLockedOrUnlocked(gSpecialVar_Result); - return (bool8)(gSpecialVar_Result); + return (bool8)gSpecialVar_Result; } static u8 GetLetterTableId(u8 letter) @@ -115,132 +124,155 @@ static u8 GetLetterTableId(u8 letter) return ARRAY_COUNT(sWaldaLettersTable); } +// Attempts to generate a wallpaper based on the given trainer id and phrase. +// Returns TRUE if successful and sets the wallpaper results to the given pointers. +// Returns FALSE if no wallpaper was generated (Walda "didn't like" the phrase). +// A 9-byte array is used to calculate the wallpaper's data. +// The elements of this array are defined below. +#define BG_COLOR_LO data[0] +#define BG_COLOR_HI data[1] +#define FG_COLOR_LO data[2] +#define FG_COLOR_HI data[3] +#define ICON_ID data[4] +#define PATTERN_ID data[5] +#define TID_CHECK_HI data[6] +#define TID_CHECK_LO data[7] +#define KEY data[8] +#define NUM_WALLPAPER_DATA_BYTES 9 +#define TO_BIT_OFFSET(i) (3 + (8 * (i))) // Convert a position in the phrase to a bit number into the wallpaper data array static bool32 TryCalculateWallpaper(u16* backgroundClr, u16 *foregroundClr, u8 *iconId, u8 *patternId, u16 trainerId, u8 *phrase) { s32 i; - ALIGNED(2) u8 array[12]; - u8 charsByTableId[16]; + ALIGNED(2) u8 data[NUM_WALLPAPER_DATA_BYTES]; + u8 charsByTableId[WALDA_PHRASE_LENGTH]; u16 *ptr; - if (StringLength(phrase) != 15) + // Reject any phrase that does not use the full length + if (StringLength(phrase) != WALDA_PHRASE_LENGTH) return FALSE; - for (i = 0; i < 15; i++) + // Reject any phrase that uses characters not in sWaldaLettersTable + for (i = 0; i < WALDA_PHRASE_LENGTH; i++) { charsByTableId[i] = GetLetterTableId(phrase[i]); if (charsByTableId[i] == ARRAY_COUNT(sWaldaLettersTable)) return FALSE; } - for (i = 0; i < 14; i++) - { - sub_81D9D5C(array, charsByTableId, (5 * i), 3 + (8 * i), 5); - } + // Use the given phrase to populate the wallpaper data array + // The data array is 9 bytes (72 bits) long, and each letter contributes to 5 bits of the array + // Because the phrase is 15 letters long there are 75 bits from the phrase to distribute + // Therefore the last letter contributes to the last 2 bits of the array, and the remaining 3 bits wrap around + for (i = 0; i < WALDA_PHRASE_LENGTH - 1; i++) + SetWallpaperDataFromLetter(data, charsByTableId, BITS_PER_LETTER * i, TO_BIT_OFFSET(i), BITS_PER_LETTER); - sub_81D9D5C(array, charsByTableId, 70, 115, 2); + // Do first 2 bits of the last letter + SetWallpaperDataFromLetter(data, charsByTableId, BITS_PER_LETTER * (WALDA_PHRASE_LENGTH - 1), TO_BIT_OFFSET(WALDA_PHRASE_LENGTH - 1), 2); - if (sub_81D9DAC(array, 0, 3) != sub_81D9DAC(charsByTableId, 117, 3)) + // Check the first 3 bits of the data array against the remaining 3 bits of the last letter + // Reject the phrase if they are not already the same + if (GetWallpaperDataBits(data, 0, 3) != GetWallpaperDataBits(charsByTableId, TO_BIT_OFFSET(WALDA_PHRASE_LENGTH - 1) + 2, 3)) return FALSE; - sub_81D9C90(array, 9, 21); - sub_81D9C90(array, 8, array[8] & 0xF); - sub_81D9CDC(array, 8, array[8] >> 4); + // Perform some relatively arbitrary changes to the wallpaper data using the last byte (KEY) + RotateWallpaperDataLeft(data, NUM_WALLPAPER_DATA_BYTES, 21); + RotateWallpaperDataLeft(data, NUM_WALLPAPER_DATA_BYTES - 1, KEY & 0xF); + MaskWallpaperData(data, NUM_WALLPAPER_DATA_BYTES - 1, KEY >> 4); - if (array[6] != (array[0] ^ array[2] ^ array[4] ^ (trainerId >> 8))) + // Reject the results of any phrase that are 'incompatible' with the player's trainer id + if (TID_CHECK_HI != (BG_COLOR_LO ^ FG_COLOR_LO ^ ICON_ID ^ (trainerId >> 8))) + return FALSE; + if (TID_CHECK_LO != (BG_COLOR_HI ^ FG_COLOR_HI ^ PATTERN_ID ^ (trainerId & 0xFF))) return FALSE; - if (array[7] != (array[1] ^ array[3] ^ array[5] ^ (trainerId & 0xFF))) - return FALSE; - - ptr = (u16*)(&array[0]); + // Successful phrase, save resulting wallpaper + ptr = (u16*) &BG_COLOR_LO; *backgroundClr = *ptr; - ptr = (u16*)(&array[2]); + ptr = (u16*) &FG_COLOR_LO; *foregroundClr = *ptr; - *iconId = array[4]; - *patternId = array[5]; + *iconId = ICON_ID; + *patternId = PATTERN_ID; return TRUE; } -static void sub_81D9C90(u8 *array, s32 arg1, s32 arg2) +static void RotateWallpaperDataLeft(u8 *data, s32 size, s32 numShifts) { s32 i, j; - u8 var1, var2; + u8 temp1, temp2; - for (i = arg2 - 1; i != -1; i--) + for (i = numShifts - 1; i != -1; i--) { - var1 = (array[0] & 0x80) >> 7; + temp1 = (data[0] & (1 << 7)) >> 7; - for (j = arg1 - 1; j >= 0; j--) + for (j = size - 1; j >= 0; j--) { - var2 = (array[j] & 0x80) >> 7; - array[j] <<= 1; - array[j] |= var1; - var1 = var2; + temp2 = (data[j] & (1 << 7)) >> 7; + data[j] <<= 1; + data[j] |= temp1; + temp1 = temp2; } } } -static void sub_81D9CDC(u8 *array, u32 loopCount, u8 arg2) +static void MaskWallpaperData(u8 *data, u32 size, u8 mask) { u32 i; - arg2 |= (arg2 << 4); + mask |= (mask << 4); - for (i = 0; i < loopCount; i++) - { - array[i] ^= arg2; - } + for (i = 0; i < size; i++) + data[i] ^= mask; } -static bool8 sub_81D9D0C(u8 *array, u32 arg1) +static bool8 GetWallpaperDataBit(u8 *data, u32 bitNum) { - u32 arrayId = arg1 >> 3; - u32 bits = 0x80 >> (7 & arg1); + u32 i = bitNum / 8; + u32 flag = (1 << 7) >> (bitNum % 8); - return ((array[arrayId] & bits) != 0); + return (data[i] & flag) != 0; } -static void sub_81D9D28(u8 *array, u32 arg1) +static void SetWallpaperDataBit(u8 *data, u32 bitNum) { - u32 arrayId = arg1 >> 3; - u8 bits = 0x80 >> (7 & arg1); + u32 i = bitNum / 8; + u8 flag = (1 << 7) >> (bitNum % 8); - array[arrayId] |= bits; + data[i] |= flag; } -static void sub_81D9D40(u8 *array, u32 arg1) +static void ClearWallpaperDataBit(u8 *data, u32 bitNum) { - u32 arrayId = arg1 >> 3; - u8 bits = ~(0x80 >> (7 & arg1)); + u32 i = bitNum / 8; + u8 mask = ~((1 << 7) >> (bitNum % 8)); - array[arrayId] &= bits; + data[i] &= mask; } -static void sub_81D9D5C(u8 *array, u8 *letterTableIds, u32 arg2, u32 arg3, u32 loopCount) +static void SetWallpaperDataFromLetter(u8 *data, u8 *letterTableIds, u32 setOffset, u32 getOffset, u32 numBits) { u32 i; - for (i = 0; i < loopCount; i++) + for (i = 0; i < numBits; i++) { - if (sub_81D9D0C(letterTableIds, arg3 + i)) - sub_81D9D28(array, arg2 + i); + if (GetWallpaperDataBit(letterTableIds, getOffset + i)) + SetWallpaperDataBit(data, setOffset + i); else - sub_81D9D40(array, arg2 + i); + ClearWallpaperDataBit(data, setOffset + i); } } -static u32 sub_81D9DAC(u8 *array, u32 arg1, u32 loopCount) +static u32 GetWallpaperDataBits(u8 *data, u32 offset, u32 numBits) { - u32 ret, i; + u32 bits, i; - for (ret = 0, i = 0; i < loopCount; i++) + for (bits = 0, i = 0; i < numBits; i++) { - ret <<= 1; - ret |= sub_81D9D0C(array, arg1 + i); + bits <<= 1; + bits |= GetWallpaperDataBit(data, offset + i); } - return ret; + return bits; }