Document walda_phrase

This commit is contained in:
GriffinR 2021-09-26 16:20:39 -04:00
parent 09fd4fc4c5
commit 8a79ca3818
7 changed files with 120 additions and 84 deletions

View File

@ -5,6 +5,7 @@
#define IN_BOX_ROWS 5 // Number of rows, 6 Pokémon per row #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_COLUMNS 6 // Number of columns, 5 Pokémon per column
#define IN_BOX_COUNT (IN_BOX_ROWS * IN_BOX_COLUMNS) #define IN_BOX_COUNT (IN_BOX_ROWS * IN_BOX_COLUMNS)
#define BOX_NAME_LENGTH 8
/* /*
COLUMNS COLUMNS
@ -19,7 +20,7 @@ struct PokemonStorage
{ {
/*0x0000*/ u8 currentBox; /*0x0000*/ u8 currentBox;
/*0x0001*/ struct BoxPokemon boxes[TOTAL_BOXES_COUNT][IN_BOX_COUNT]; /*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]; /*0x83C2*/ u8 boxWallpapers[TOTAL_BOXES_COUNT];
}; };

View File

@ -1,6 +1,8 @@
#ifndef GUARD_WALDA_PHRASE_H #ifndef GUARD_WALDA_PHRASE_H
#define GUARD_WALDA_PHRASE_H #define GUARD_WALDA_PHRASE_H
#define WALDA_PHRASE_LENGTH 15
u16 TryBufferWaldaPhrase(void); u16 TryBufferWaldaPhrase(void);
void DoWaldaNamingScreen(void); void DoWaldaNamingScreen(void);
u16 TryGetWallpaperWithWaldaPhrase(void); u16 TryGetWallpaperWithWaldaPhrase(void);

View File

@ -997,7 +997,7 @@ void GetConditionMenuMonNameAndLocString(u8 *locationDst, u8 *nameDst, u16 boxId
if (box == TOTAL_BOXES_COUNT) // Party mon. if (box == TOTAL_BOXES_COUNT) // Party mon.
BufferConditionMenuSpacedStringN(&locationDst[5], gText_InParty, 8); BufferConditionMenuSpacedStringN(&locationDst[5], gText_InParty, 8);
else else
BufferConditionMenuSpacedStringN(&locationDst[5], GetBoxNamePtr(box), 8); BufferConditionMenuSpacedStringN(&locationDst[5], GetBoxNamePtr(box), BOX_NAME_LENGTH);
} }
else else
{ {

View File

@ -25,6 +25,7 @@
#include "menu.h" #include "menu.h"
#include "text_window.h" #include "text_window.h"
#include "overworld.h" #include "overworld.h"
#include "walda_phrase.h"
#include "constants/event_objects.h" #include "constants/event_objects.h"
#include "constants/rgb.h" #include "constants/rgb.h"
@ -2089,7 +2090,7 @@ static void Debug_NamingScreenNickname(void)
static const struct NamingScreenTemplate sPlayerNamingScreenTemplate = static const struct NamingScreenTemplate sPlayerNamingScreenTemplate =
{ {
.copyExistingString = FALSE, .copyExistingString = FALSE,
.maxChars = 7, .maxChars = PLAYER_NAME_LENGTH,
.iconFunction = 1, .iconFunction = 1,
.addGenderIcon = FALSE, .addGenderIcon = FALSE,
.initialPage = KBPAGE_LETTERS_UPPER, .initialPage = KBPAGE_LETTERS_UPPER,
@ -2100,7 +2101,7 @@ static const struct NamingScreenTemplate sPlayerNamingScreenTemplate =
static const struct NamingScreenTemplate sPCBoxNamingTemplate = static const struct NamingScreenTemplate sPCBoxNamingTemplate =
{ {
.copyExistingString = FALSE, .copyExistingString = FALSE,
.maxChars = 8, .maxChars = BOX_NAME_LENGTH,
.iconFunction = 2, .iconFunction = 2,
.addGenderIcon = FALSE, .addGenderIcon = FALSE,
.initialPage = KBPAGE_LETTERS_UPPER, .initialPage = KBPAGE_LETTERS_UPPER,
@ -2111,7 +2112,7 @@ static const struct NamingScreenTemplate sPCBoxNamingTemplate =
static const struct NamingScreenTemplate sMonNamingScreenTemplate = static const struct NamingScreenTemplate sMonNamingScreenTemplate =
{ {
.copyExistingString = FALSE, .copyExistingString = FALSE,
.maxChars = 10, .maxChars = POKEMON_NAME_LENGTH,
.iconFunction = 3, .iconFunction = 3,
.addGenderIcon = TRUE, .addGenderIcon = TRUE,
.initialPage = KBPAGE_LETTERS_UPPER, .initialPage = KBPAGE_LETTERS_UPPER,
@ -2122,7 +2123,7 @@ static const struct NamingScreenTemplate sMonNamingScreenTemplate =
static const struct NamingScreenTemplate sWaldaWordsScreenTemplate = static const struct NamingScreenTemplate sWaldaWordsScreenTemplate =
{ {
.copyExistingString = TRUE, .copyExistingString = TRUE,
.maxChars = 15, .maxChars = WALDA_PHRASE_LENGTH,
.iconFunction = 4, .iconFunction = 4,
.addGenderIcon = FALSE, .addGenderIcon = FALSE,
.initialPage = KBPAGE_LETTERS_UPPER, .initialPage = KBPAGE_LETTERS_UPPER,

View File

@ -5512,7 +5512,7 @@ static void InitBoxTitle(u8 boxId)
sStorage->boxTitleAltPalOffset = 0x10e + 16 * tagIndex; sStorage->boxTitleAltPalOffset = 0x10e + 16 * tagIndex;
sStorage->wallpaperPalBits |= 0x10000 << 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); DrawTextWindowAndBufferTiles(sStorage->boxTitleText, sStorage->boxTitleTiles, 0, 0, 2);
LoadSpriteSheet(&spriteSheet); LoadSpriteSheet(&spriteSheet);
x = GetBoxTitleBaseX(GetBoxNamePtr(boxId)); x = GetBoxTitleBaseX(GetBoxNamePtr(boxId));
@ -5557,7 +5557,7 @@ static void CreateIncomingBoxTitle(u8 boxId, s8 direction)
template.paletteTag = PALTAG_BOX_TITLE; 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); DrawTextWindowAndBufferTiles(sStorage->boxTitleText, sStorage->boxTitleTiles, 0, 0, 2);
LoadSpriteSheet(&spriteSheet); LoadSpriteSheet(&spriteSheet);
LoadPalette(sBoxTitleColors[GetBoxWallpaper(boxId)], palOffset, sizeof(sBoxTitleColors[0])); LoadPalette(sBoxTitleColors[GetBoxWallpaper(boxId)], palOffset, sizeof(sBoxTitleColors[0]));

View File

@ -435,7 +435,7 @@ void CopyMonNameGenderLocation(s16 id, u8 arg1)
if (boxId == TOTAL_BOXES_COUNT) if (boxId == TOTAL_BOXES_COUNT)
CopyStringLeftAlignedToConditionData(&structPtr->searchLocBuffer[arg1][5], gText_InParty, 8); CopyStringLeftAlignedToConditionData(&structPtr->searchLocBuffer[arg1][5], gText_InParty, 8);
else else
CopyStringLeftAlignedToConditionData(&structPtr->searchLocBuffer[arg1][5], GetBoxNamePtr(boxId), 8); CopyStringLeftAlignedToConditionData(&structPtr->searchLocBuffer[arg1][5], GetBoxNamePtr(boxId), BOX_NAME_LENGTH);
} }
else else
{ {

View File

@ -12,17 +12,20 @@
extern const u8 gText_Peekaboo[]; extern const u8 gText_Peekaboo[];
// this file's functions
static void CB2_HandleGivenWaldaPhrase(void); static void CB2_HandleGivenWaldaPhrase(void);
static u32 GetWaldaPhraseInputCase(u8 *inputPtr); static u32 GetWaldaPhraseInputCase(u8 *);
static bool32 TryCalculateWallpaper(u16* backgroundClr, u16 *foregroundClr, u8 *iconId, u8 *patternId, u16 trainerId, u8 *phrase); static bool32 TryCalculateWallpaper(u16 *, u16 *, u8 *, u8 *, u16, u8 *);
static void sub_81D9D5C(u8 *array, u8 *letterTableIds, u32 arg2, u32 arg3, u32 loopCount); static void SetWallpaperDataFromLetter(u8 *, u8 *, u32, u32, u32);
static u32 sub_81D9DAC(u8 *array, u32 arg1, u32 loopCount); static u32 GetWallpaperDataBits(u8 *, u32, u32);
static void sub_81D9C90(u8 *array, s32 arg1, s32 arg2); static void RotateWallpaperDataLeft(u8 *, s32, s32);
static void sub_81D9CDC(u8 *array, u32 loopCount, u8 arg2); static void MaskWallpaperData(u8 *, u32, u8);
// only consonants are allowed, no vowels, some lowercase letters are missing // There are 32 (2^5) unique letters allowed in a successful phrase for Walda.
static const u8 sWaldaLettersTable[] = #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_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 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 enum
{ {
PHRASE_GIVEN_NEW, PHRASE_CHANGED,
PHRASE_NO_CHANGE, PHRASE_NO_CHANGE,
PHRASE_FIRST_ATTEMPT PHRASE_EMPTY
}; };
u16 TryBufferWaldaPhrase(void) u16 TryBufferWaldaPhrase(void)
@ -56,13 +59,15 @@ static void CB2_HandleGivenWaldaPhrase(void)
switch (gSpecialVar_0x8004) 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()) if (IsWaldaPhraseEmpty())
SetWaldaPhrase(gText_Peekaboo); SetWaldaPhrase(gText_Peekaboo);
else else
gSpecialVar_0x8004 = PHRASE_NO_CHANGE; gSpecialVar_0x8004 = PHRASE_NO_CHANGE;
break; break;
case PHRASE_GIVEN_NEW: case PHRASE_CHANGED:
SetWaldaPhrase(gStringVar2); SetWaldaPhrase(gStringVar2);
break; break;
case PHRASE_NO_CHANGE: case PHRASE_NO_CHANGE:
@ -76,12 +81,16 @@ static void CB2_HandleGivenWaldaPhrase(void)
static u32 GetWaldaPhraseInputCase(u8 *inputPtr) static u32 GetWaldaPhraseInputCase(u8 *inputPtr)
{ {
// No input given
if (inputPtr[0] == EOS) if (inputPtr[0] == EOS)
return PHRASE_FIRST_ATTEMPT; return PHRASE_EMPTY;
// Input given is the same as saved phrase
if (StringCompare(inputPtr, GetWaldaPhrasePtr()) == 0) if (StringCompare(inputPtr, GetWaldaPhrasePtr()) == 0)
return PHRASE_NO_CHANGE; return PHRASE_NO_CHANGE;
return PHRASE_GIVEN_NEW; // Input is new phrase
return PHRASE_CHANGED;
} }
u16 TryGetWallpaperWithWaldaPhrase(void) u16 TryGetWallpaperWithWaldaPhrase(void)
@ -99,7 +108,7 @@ u16 TryGetWallpaperWithWaldaPhrase(void)
} }
SetWaldaWallpaperLockedOrUnlocked(gSpecialVar_Result); SetWaldaWallpaperLockedOrUnlocked(gSpecialVar_Result);
return (bool8)(gSpecialVar_Result); return (bool8)gSpecialVar_Result;
} }
static u8 GetLetterTableId(u8 letter) static u8 GetLetterTableId(u8 letter)
@ -115,132 +124,155 @@ static u8 GetLetterTableId(u8 letter)
return ARRAY_COUNT(sWaldaLettersTable); 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) static bool32 TryCalculateWallpaper(u16* backgroundClr, u16 *foregroundClr, u8 *iconId, u8 *patternId, u16 trainerId, u8 *phrase)
{ {
s32 i; s32 i;
ALIGNED(2) u8 array[12]; ALIGNED(2) u8 data[NUM_WALLPAPER_DATA_BYTES];
u8 charsByTableId[16]; u8 charsByTableId[WALDA_PHRASE_LENGTH];
u16 *ptr; u16 *ptr;
if (StringLength(phrase) != 15) // Reject any phrase that does not use the full length
if (StringLength(phrase) != WALDA_PHRASE_LENGTH)
return FALSE; 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]); charsByTableId[i] = GetLetterTableId(phrase[i]);
if (charsByTableId[i] == ARRAY_COUNT(sWaldaLettersTable)) if (charsByTableId[i] == ARRAY_COUNT(sWaldaLettersTable))
return FALSE; return FALSE;
} }
for (i = 0; i < 14; i++) // 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
sub_81D9D5C(array, charsByTableId, (5 * i), 3 + (8 * i), 5); // 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; return FALSE;
sub_81D9C90(array, 9, 21); // Perform some relatively arbitrary changes to the wallpaper data using the last byte (KEY)
sub_81D9C90(array, 8, array[8] & 0xF); RotateWallpaperDataLeft(data, NUM_WALLPAPER_DATA_BYTES, 21);
sub_81D9CDC(array, 8, array[8] >> 4); 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; return FALSE;
if (array[7] != (array[1] ^ array[3] ^ array[5] ^ (trainerId & 0xFF))) // Successful phrase, save resulting wallpaper
return FALSE; ptr = (u16*) &BG_COLOR_LO;
ptr = (u16*)(&array[0]);
*backgroundClr = *ptr; *backgroundClr = *ptr;
ptr = (u16*)(&array[2]); ptr = (u16*) &FG_COLOR_LO;
*foregroundClr = *ptr; *foregroundClr = *ptr;
*iconId = array[4]; *iconId = ICON_ID;
*patternId = array[5]; *patternId = PATTERN_ID;
return TRUE; return TRUE;
} }
static void sub_81D9C90(u8 *array, s32 arg1, s32 arg2) static void RotateWallpaperDataLeft(u8 *data, s32 size, s32 numShifts)
{ {
s32 i, j; 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; temp2 = (data[j] & (1 << 7)) >> 7;
array[j] <<= 1; data[j] <<= 1;
array[j] |= var1; data[j] |= temp1;
var1 = var2; temp1 = temp2;
} }
} }
} }
static void sub_81D9CDC(u8 *array, u32 loopCount, u8 arg2) static void MaskWallpaperData(u8 *data, u32 size, u8 mask)
{ {
u32 i; u32 i;
arg2 |= (arg2 << 4); mask |= (mask << 4);
for (i = 0; i < loopCount; i++) for (i = 0; i < size; i++)
{ data[i] ^= mask;
array[i] ^= arg2;
}
} }
static bool8 sub_81D9D0C(u8 *array, u32 arg1) static bool8 GetWallpaperDataBit(u8 *data, u32 bitNum)
{ {
u32 arrayId = arg1 >> 3; u32 i = bitNum / 8;
u32 bits = 0x80 >> (7 & arg1); 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; u32 i = bitNum / 8;
u8 bits = 0x80 >> (7 & arg1); 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; u32 i = bitNum / 8;
u8 bits = ~(0x80 >> (7 & arg1)); 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; u32 i;
for (i = 0; i < loopCount; i++) for (i = 0; i < numBits; i++)
{ {
if (sub_81D9D0C(letterTableIds, arg3 + i)) if (GetWallpaperDataBit(letterTableIds, getOffset + i))
sub_81D9D28(array, arg2 + i); SetWallpaperDataBit(data, setOffset + i);
else 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; bits <<= 1;
ret |= sub_81D9D0C(array, arg1 + i); bits |= GetWallpaperDataBit(data, offset + i);
} }
return ret; return bits;
} }