|
|
|
|
@@ -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;
|
|
|
|
|
}
|
|
|
|
|
|