pokeemerald/src/mauville_old_man.c

1433 lines
41 KiB
C
Raw Normal View History

2018-05-02 17:31:58 +02:00
#include "global.h"
#include "main.h"
2018-05-03 23:03:52 +02:00
#include "constants/songs.h"
2018-05-02 17:31:58 +02:00
#include "constants/easy_chat.h"
#include "constants/event_objects.h"
2018-05-03 23:03:52 +02:00
#include "constants/vars.h"
2018-05-02 17:31:58 +02:00
#include "mauville_old_man.h"
2018-05-02 22:57:34 +02:00
#include "event_data.h"
#include "string_util.h"
#include "text.h"
#include "easy_chat.h"
#include "script.h"
#include "random.h"
#include "event_scripts.h"
2018-05-03 19:40:08 +02:00
#include "task.h"
#include "menu.h"
#include "m4a.h"
#include "bard_music.h"
2018-05-03 23:03:52 +02:00
#include "sound.h"
#include "strings.h"
2018-05-03 23:51:14 +02:00
#include "overworld.h"
2018-05-04 00:05:07 +02:00
#include "field_message_box.h"
#include "script_menu.h"
#include "trader.h"
2019-10-20 22:11:07 +02:00
#include "constants/mauville_old_man.h"
2018-05-02 22:57:34 +02:00
#define CHAR_SONG_WORD_SEPARATOR 0x37
2018-05-02 17:31:58 +02:00
2018-05-03 19:40:08 +02:00
extern struct MusicPlayerInfo gMPlayInfo_SE2;
static void InitGiddyTaleList(void);
static void StartBardSong(bool8 useTemporaryLyrics);
static void Task_BardSong(u8 taskId);
static void StorytellerSetup(void);
static void Storyteller_ResetFlag(void);
2018-05-02 17:31:58 +02:00
static u8 sSelectedStory;
2018-05-04 00:05:07 +02:00
struct BardSong gBardSong;
2018-05-03 23:03:52 +02:00
static EWRAM_DATA u16 sUnknownBardRelated = 0;
static EWRAM_DATA struct MauvilleManStoryteller * sStorytellerPtr = NULL;
static EWRAM_DATA u8 sStorytellerWindowId = 0;
2018-05-03 23:03:52 +02:00
2019-10-20 22:11:07 +02:00
static const u16 sDefaultBardSongLyrics[BARD_SONG_LENGTH] = {
2018-05-02 17:31:58 +02:00
EC_WORD_SHAKE,
EC_WORD_IT,
EC_WORD_DO,
EC_WORD_THE,
EC_WORD_DIET,
EC_WORD_DANCE
};
2018-05-02 22:57:34 +02:00
static const u8 * const sGiddyAdjectives[] = {
gText_SoPretty,
gText_SoDarling,
gText_SoRelaxed,
gText_SoSunny,
gText_SoDesirable,
gText_SoExciting,
gText_SoAmusing,
gText_SoMagical
};
static const u8 * const sGiddyQuestions[] = {
2018-12-10 21:50:10 +01:00
gMauvilleManText_ISoWantToGoOnAVacation,
gMauvilleManText_IBoughtCrayonsWith120Colors,
gMauvilleManText_WouldntItBeNiceIfWeCouldFloat,
gMauvilleManText_WhenYouWriteOnASandyBeach,
gMauvilleManText_WhatsTheBottomOfTheSeaLike,
gMauvilleManText_WhenYouSeeTheSettingSunDoesIt,
gMauvilleManText_LyingBackInTheGreenGrass,
gMauvilleManText_SecretBasesAreSoWonderful
2018-05-02 22:57:34 +02:00
};
2018-05-02 17:31:58 +02:00
static void SetupBard(void)
{
u16 i;
struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
bard->id = MAUVILLE_MAN_BARD;
bard->hasChangedSong = FALSE;
bard->language = gGameLanguage;
2019-10-20 22:11:07 +02:00
for (i = 0; i < BARD_SONG_LENGTH; i++)
2018-05-02 17:31:58 +02:00
bard->songLyrics[i] = sDefaultBardSongLyrics[i];
}
static void SetupHipster(void)
{
struct MauvilleManHipster *hipster = &gSaveBlock1Ptr->oldMan.hipster;
hipster->id = MAUVILLE_MAN_HIPSTER;
hipster->alreadySpoken = FALSE;
hipster->language = gGameLanguage;
}
static void SetupStoryteller(void)
{
StorytellerSetup();
2018-05-02 17:31:58 +02:00
}
static void SetupGiddy(void)
{
struct MauvilleManGiddy *giddy = &gSaveBlock1Ptr->oldMan.giddy;
giddy->id = MAUVILLE_MAN_GIDDY;
giddy->taleCounter = 0;
giddy->language = gGameLanguage;
}
static void SetupTrader(void)
{
TraderSetup();
2018-05-02 17:31:58 +02:00
}
void SetMauvilleOldMan(void)
{
u16 trainerId = (gSaveBlock2Ptr->playerTrainerId[1] << 8) | gSaveBlock2Ptr->playerTrainerId[0];
// Determine man based on the last digit of the player's trainer ID.
switch ((trainerId % 10) / 2)
{
case MAUVILLE_MAN_BARD:
SetupBard();
break;
case MAUVILLE_MAN_HIPSTER:
SetupHipster();
break;
case MAUVILLE_MAN_TRADER:
SetupTrader();
break;
case MAUVILLE_MAN_STORYTELLER:
SetupStoryteller();
break;
case MAUVILLE_MAN_GIDDY:
SetupGiddy();
break;
}
ScrSpecial_SetMauvilleOldManEventObjGfx();
2018-05-02 17:31:58 +02:00
}
2018-05-02 22:57:34 +02:00
u8 GetCurrentMauvilleOldMan(void)
2018-05-02 22:57:34 +02:00
{
struct MauvilleManCommon *common = &gSaveBlock1Ptr->oldMan.common;
return common->id;
}
void ScrSpecial_GetCurrentMauvilleMan(void)
2018-05-02 22:57:34 +02:00
{
gSpecialVar_Result = GetCurrentMauvilleOldMan();
2018-05-02 22:57:34 +02:00
}
void ScrSpecial_HasBardSongBeenChanged(void)
2018-05-02 22:57:34 +02:00
{
u16 *scriptResult = &gSpecialVar_Result; // why??
struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
*scriptResult = bard->hasChangedSong;
}
void ScrSpecial_SaveBardSongLyrics(void)
2018-05-02 22:57:34 +02:00
{
u16 i;
struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
StringCopy(bard->playerName, gSaveBlock2Ptr->playerName);
2019-10-20 22:11:07 +02:00
for (i = 0; i < TRAINER_ID_LENGTH; i++)
2018-05-02 22:57:34 +02:00
bard->playerTrainerId[i] = gSaveBlock2Ptr->playerTrainerId[i];
2019-10-20 22:11:07 +02:00
for (i = 0; i < BARD_SONG_LENGTH; i++)
2018-05-02 22:57:34 +02:00
bard->songLyrics[i] = bard->temporaryLyrics[i];
bard->hasChangedSong = TRUE;
}
// Copies lyrics into gStringVar4
static void PrepareSongText(void)
2018-05-02 22:57:34 +02:00
{
struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
u16 * lyrics = gSpecialVar_0x8004 == 0 ? bard->songLyrics : bard->temporaryLyrics;
u8 * wordEnd = gStringVar4;
u8 * str = wordEnd;
2018-05-02 22:57:34 +02:00
u16 lineNum;
2018-05-02 22:57:34 +02:00
// Put three words on each line
for (lineNum = 0; lineNum < 2; lineNum++)
{
wordEnd = CopyEasyChatWord(wordEnd, *(lyrics++));
while (wordEnd != str)
{
if (*str == CHAR_SPACE)
*str = CHAR_SONG_WORD_SEPARATOR;
str++;
}
str++;
*(wordEnd++) = CHAR_SPACE;
wordEnd = CopyEasyChatWord(wordEnd, *(lyrics++));
while (wordEnd != str)
{
if (*str == CHAR_SPACE)
*str = CHAR_SONG_WORD_SEPARATOR;
str++;
}
str++;
*(wordEnd++) = CHAR_NEWLINE;
wordEnd = CopyEasyChatWord(wordEnd, *(lyrics++));
while (wordEnd != str)
{
if (*str == CHAR_SPACE)
*str = CHAR_SONG_WORD_SEPARATOR;
str++;
}
if (lineNum == 0)
{
*(wordEnd++) = EXT_CTRL_CODE_BEGIN;
*(wordEnd++) = 15;
}
}
}
void ScrSpecial_PlayBardSong(void)
2018-05-02 22:57:34 +02:00
{
StartBardSong(gSpecialVar_0x8004);
2018-05-02 22:57:34 +02:00
ScriptContext1_Stop();
}
void ScrSpecial_GetHipsterSpokenFlag(void)
2018-05-02 22:57:34 +02:00
{
u16 *scriptResult = &gSpecialVar_Result; // again??
struct MauvilleManHipster *hipster = &gSaveBlock1Ptr->oldMan.hipster;
*scriptResult = hipster->alreadySpoken;
}
void ScrSpecial_SetHipsterSpokenFlag(void)
2018-05-02 22:57:34 +02:00
{
struct MauvilleManHipster *hipster = &gSaveBlock1Ptr->oldMan.hipster;
hipster->alreadySpoken = TRUE;
}
void ScrSpecial_HipsterTeachWord(void)
2018-05-02 22:57:34 +02:00
{
2019-10-20 22:11:07 +02:00
u16 phrase = GetNewHipsterPhraseToTeach();
2018-05-02 22:57:34 +02:00
2019-10-20 22:11:07 +02:00
if (phrase == 0xFFFF)
2018-05-02 22:57:34 +02:00
{
gSpecialVar_Result = FALSE;
}
else
{
2019-10-20 22:11:07 +02:00
CopyEasyChatWord(gStringVar1, phrase);
2018-05-02 22:57:34 +02:00
gSpecialVar_Result = TRUE;
}
}
void ScrSpecial_GiddyShouldTellAnotherTale(void)
2018-05-02 22:57:34 +02:00
{
struct MauvilleManGiddy *giddy = &gSaveBlock1Ptr->oldMan.giddy;
if (giddy->taleCounter == 10)
{
gSpecialVar_Result = FALSE;
giddy->taleCounter = 0;
}
else
{
gSpecialVar_Result = TRUE;
}
}
void ScrSpecial_GenerateGiddyLine(void)
2018-05-02 22:57:34 +02:00
{
struct MauvilleManGiddy *giddy = &gSaveBlock1Ptr->oldMan.giddy;
if (giddy->taleCounter == 0)
InitGiddyTaleList();
2018-05-02 22:57:34 +02:00
if (giddy->randomWords[giddy->taleCounter] != 0xFFFF) // is not the last element of the array?
{
u8 *stringPtr;
u32 adjective = Random();
adjective %= 8;
stringPtr = CopyEasyChatWord(gStringVar4, giddy->randomWords[giddy->taleCounter]);
stringPtr = StringCopy(stringPtr, gOtherText_Is);
stringPtr = StringCopy(stringPtr, sGiddyAdjectives[adjective]);
StringCopy(stringPtr, gOtherText_DontYouAgree);
}
else
{
StringCopy(gStringVar4, sGiddyQuestions[giddy->questionList[giddy->questionNum++]]);
}
if (!(Random() % 10))
giddy->taleCounter = 10;
else
giddy->taleCounter++;
gSpecialVar_Result = TRUE;
}
2018-05-03 19:40:08 +02:00
static void InitGiddyTaleList(void)
2018-05-03 19:40:08 +02:00
{
struct MauvilleManGiddy *giddy = &gSaveBlock1Ptr->oldMan.giddy;
u16 arr[][2] = {
{EC_GROUP_POKEMON, 0},
{EC_GROUP_LIFESTYLE, 0},
{EC_GROUP_HOBBIES, 0},
{EC_GROUP_MOVE_1, 0},
{EC_GROUP_MOVE_2, 0},
{EC_GROUP_POKEMON_2, 0}
};
u16 i;
u16 r10;
u16 r7;
u16 r1;
for (i = 0; i < 8; i++)
giddy->questionList[i] = i;
for (i = 0; i < 8; i++)
{
r1 = Random() % (i + 1);
r7 = giddy->questionList[i];
giddy->questionList[i] = giddy->questionList[r1];
giddy->questionList[r1] = r7;
}
r10 = 0;
for (i = 0; i < 6; i++)
{
arr[i][1] = EasyChat_GetNumWordsInGroup(arr[i][0]);
r10 += arr[i][1];
}
giddy->questionNum = 0;
r7 = 0;
for (i = 0; i < 10; i++)
{
r1 = Random() % 10;
if (r1 < 3 && r7 < 8)
{
giddy->randomWords[i] = 0xFFFF;
r7++;
}
else
{
s16 r2 = Random() % r10;
for (r1 = 0; i < 6; r1++)
if ((r2 -= arr[r1][1]) <= 0)
break;
if (r1 == 6)
r1 = 0;
giddy->randomWords[i] = sub_811EE90(arr[r1][0]);
}
}
}
static void ResetBardFlag(void)
2018-05-03 19:40:08 +02:00
{
struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
bard->hasChangedSong = FALSE;
}
static void ResetHipsterFlag(void)
2018-05-03 19:40:08 +02:00
{
struct MauvilleManHipster *hipster = &gSaveBlock1Ptr->oldMan.hipster;
hipster->alreadySpoken = FALSE;
}
static void ResetTraderFlag(void)
2018-05-03 19:40:08 +02:00
{
Trader_ResetFlag();
2018-05-03 19:40:08 +02:00
}
static void ResetStorytellerFlag(void)
2018-05-03 19:40:08 +02:00
{
Storyteller_ResetFlag();
2018-05-03 19:40:08 +02:00
}
2018-05-19 12:32:44 +02:00
void ResetMauvilleOldManFlag(void)
2018-05-03 19:40:08 +02:00
{
switch (GetCurrentMauvilleOldMan())
2018-05-03 19:40:08 +02:00
{
case MAUVILLE_MAN_BARD:
ResetBardFlag();
2018-05-03 19:40:08 +02:00
break;
case MAUVILLE_MAN_HIPSTER:
ResetHipsterFlag();
2018-05-03 19:40:08 +02:00
break;
case MAUVILLE_MAN_STORYTELLER:
ResetStorytellerFlag();
2018-05-03 19:40:08 +02:00
break;
case MAUVILLE_MAN_TRADER:
ResetTraderFlag();
2018-05-03 19:40:08 +02:00
break;
case MAUVILLE_MAN_GIDDY:
break;
}
ScrSpecial_SetMauvilleOldManEventObjGfx();
2018-05-03 19:40:08 +02:00
}
#define tState data[0]
#define tCharIndex data[3]
#define tCurrWord data[4]
#define tUseTemporaryLyrics data[5]
#define MACRO1(a) (((a) & 3) + (((a) / 8) & 1))
2018-05-03 23:03:52 +02:00
#define MACRO2(a) (((a) % 4) + (((a) / 8) & 1))
2018-05-03 19:40:08 +02:00
static void StartBardSong(bool8 useTemporaryLyrics)
2018-05-03 19:40:08 +02:00
{
u8 taskId = CreateTask(Task_BardSong, 80);
2018-05-03 19:40:08 +02:00
gTasks[taskId].tUseTemporaryLyrics = useTemporaryLyrics;
}
static void sub_81206F0(void)
2018-05-03 19:40:08 +02:00
{
gUnknown_03002F84 = FALSE;
}
2018-11-06 17:44:48 +01:00
static void BardSong_TextSubPrinter(struct TextPrinterTemplate * printer, u16 a1)
2018-05-03 19:40:08 +02:00
{
gUnknown_03002F84 = TRUE;
}
static void sub_8120708(const u8 * src)
2018-05-03 19:40:08 +02:00
{
DrawDialogueFrame(0, 0);
AddTextPrinterParameterized(0, 1, src, 0, 1, 1, BardSong_TextSubPrinter);
2018-05-03 19:40:08 +02:00
gUnknown_03002F84 = TRUE;
CopyWindowToVram(0, 3);
}
static void BardSing(struct Task *task, struct BardSong *song)
2018-05-03 19:40:08 +02:00
{
switch (task->tState)
{
case 0: // Initialize song
{
struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
u16 *lyrics;
s32 i;
// Copy lyrics
if (gSpecialVar_0x8004 == 0)
lyrics = bard->songLyrics;
else
lyrics = bard->temporaryLyrics;
2019-10-20 22:11:07 +02:00
for (i = 0; i < BARD_SONG_LENGTH; i++)
2018-05-03 19:40:08 +02:00
song->lyrics[i] = lyrics[i];
song->currWord = 0;
}
break;
case 1: // Wait for BGM to end
break;
case 2: // Initialize word
{
u16 word = song->lyrics[song->currWord];
song->sound = GetWordSounds(word);
GetWordPhonemes(song, MACRO1(word));
song->currWord++;
if (song->sound->var00 != 0xFF)
song->state = 0;
else
{
song->state = 3;
song->phonemeTimer = 2;
}
break;
}
case 3:
case 4:
{
const struct BardSound *sound = &song->sound[song->currPhoneme];
switch (song->state)
{
case 0:
song->phonemeTimer = song->phonemes[song->currPhoneme].length;
if (sound->var00 <= 50)
{
u8 num = sound->var00 / 3;
m4aSongNumStart(PH_TRAP_HELD + 3 * num);
}
song->state = 2;
song->phonemeTimer--;
break;
case 2:
song->state = 1;
if (sound->var00 <= 50)
{
song->volume = 0x100 + sound->volume * 16;
m4aMPlayVolumeControl(&gMPlayInfo_SE2, 0xFFFF, song->volume);
song->pitch = 0x200 + song->phonemes[song->currPhoneme].pitch;
m4aMPlayPitchControl(&gMPlayInfo_SE2, 0xFFFF, song->pitch);
}
break;
case 1:
if (song->voiceInflection > 10)
song->volume -= 2;
if (song->voiceInflection & 1)
song->pitch += 64;
else
song->pitch -= 64;
m4aMPlayVolumeControl(&gMPlayInfo_SE2, 0xFFFF, song->volume);
m4aMPlayPitchControl(&gMPlayInfo_SE2, 0xFFFF, song->pitch);
song->voiceInflection++;
song->phonemeTimer--;
if (song->phonemeTimer == 0)
{
song->currPhoneme++;
if (song->currPhoneme != 6 && song->sound[song->currPhoneme].var00 != 0xFF)
song->state = 0;
else
{
song->state = 3;
song->phonemeTimer = 2;
}
}
break;
case 3:
song->phonemeTimer--;
if (song->phonemeTimer == 0)
{
m4aMPlayStop(&gMPlayInfo_SE2);
song->state = 4;
}
break;
}
}
break;
case 5:
break;
}
}
2018-05-03 23:03:52 +02:00
static void Task_BardSong(u8 taskId)
2018-05-03 23:03:52 +02:00
{
struct Task *task = &gTasks[taskId]; // r5
BardSing(task, &gBardSong);
2018-05-03 23:03:52 +02:00
switch (task->tState)
{
case 0: // Initialize song
PrepareSongText();
2018-05-03 23:03:52 +02:00
sub_8120708(gStringVar4);
task->data[1] = 0;
task->data[2] = 0;
task->tCharIndex = 0;
task->tCurrWord = 0;
FadeOutBGMTemporarily(4);
task->tState = 1;
break;
case 1: // Wait for BGM to end
if (IsBGMPausedOrStopped())
task->tState = 2;
break;
case 2: // Initialize word
{
struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
u8 *str = gStringVar4 + task->tCharIndex;
u16 wordLen = 0;
while (*str != CHAR_SPACE
&& *str != CHAR_NEWLINE
&& *str != EXT_CTRL_CODE_BEGIN
&& *str != EOS)
{
str++;
wordLen++;
}
if (!task->tUseTemporaryLyrics)
sUnknownBardRelated = MACRO2(bard->songLyrics[task->tCurrWord]);
2018-05-03 23:03:52 +02:00
else
sUnknownBardRelated = MACRO2(bard->temporaryLyrics[task->tCurrWord]);
2019-02-01 11:56:02 +01:00
gBardSong.length /= wordLen;
if (gBardSong.length <= 0)
gBardSong.length = 1;
2018-05-03 23:03:52 +02:00
task->tCurrWord++;
2019-02-01 11:56:02 +01:00
2018-05-03 23:03:52 +02:00
if (task->data[2] == 0)
2019-02-01 11:56:02 +01:00
{
2018-05-03 23:03:52 +02:00
task->tState = 3;
2019-02-01 11:56:02 +01:00
task->data[1] = 0;
}
2018-05-03 23:03:52 +02:00
else
2019-02-01 11:56:02 +01:00
{
2018-05-03 23:03:52 +02:00
task->tState = 5;
2019-02-01 11:56:02 +01:00
task->data[1] = 0;
}
2018-05-03 23:03:52 +02:00
}
break;
case 5:
if (task->data[2] == 0)
task->tState = 3;
else
task->data[2]--;
break;
case 3:
if (gStringVar4[task->tCharIndex] == EOS)
{
FadeInBGM(6);
m4aMPlayFadeOutTemporarily(&gMPlayInfo_SE2, 2);
EnableBothScriptContexts();
DestroyTask(taskId);
}
else if (gStringVar4[task->tCharIndex] == CHAR_SPACE)
{
sub_81206F0();
task->tCharIndex++;
task->tState = 2;
task->data[2] = 0;
}
else if (gStringVar4[task->tCharIndex] == CHAR_NEWLINE)
{
task->tCharIndex++;
task->tState = 2;
task->data[2] = 0;
}
else if (gStringVar4[task->tCharIndex] == EXT_CTRL_CODE_BEGIN)
{
task->tCharIndex += 2; // skip over control codes
task->tState = 2;
task->data[2] = 8;
}
else if (gStringVar4[task->tCharIndex] == CHAR_SONG_WORD_SEPARATOR)
{
gStringVar4[task->tCharIndex] = CHAR_SPACE; // restore it back to a space
sub_81206F0();
task->tCharIndex++;
task->data[2] = 0;
}
else
{
switch (task->data[1])
{
case 0:
sub_81206F0();
task->data[1]++;
break;
case 1:
task->data[1]++;
break;
case 2:
task->tCharIndex++;
task->data[1] = 0;
task->data[2] = gBardSong.length;
2018-05-03 23:03:52 +02:00
task->tState = 4;
break;
}
}
break;
case 4:
task->data[2]--;
if (task->data[2] == 0)
task->tState = 3;
break;
}
2018-09-14 19:15:46 +02:00
RunTextPrintersAndIsPrinter0Active();
2018-05-03 23:03:52 +02:00
}
void ScrSpecial_SetMauvilleOldManEventObjGfx(void)
2018-05-03 23:03:52 +02:00
{
VarSet(VAR_OBJ_GFX_ID_0, EVENT_OBJ_GFX_BARD);
2018-05-03 23:03:52 +02:00
}
// Language fixers?
2018-05-03 23:03:52 +02:00
void sub_8120B70(union OldMan * oldMan)
{
s32 i;
2019-10-22 00:09:57 +02:00
u8 playerName[PLAYER_NAME_LENGTH + 1];
2018-05-03 23:03:52 +02:00
switch (oldMan->common.id)
{
case MAUVILLE_MAN_TRADER:
{
struct MauvilleOldManTrader * trader = &oldMan->trader;
2019-10-20 22:11:07 +02:00
for (i = 0; i < NUM_TRADER_ITEMS; i++)
2018-05-03 23:03:52 +02:00
{
if (trader->language[i] == LANGUAGE_JAPANESE)
2018-05-03 23:03:52 +02:00
{
ConvertInternationalString(trader->playerNames[i], LANGUAGE_JAPANESE);
2018-05-03 23:03:52 +02:00
}
}
}
break;
case MAUVILLE_MAN_STORYTELLER:
{
struct MauvilleManStoryteller * storyteller = &oldMan->storyteller;
2019-10-20 22:11:07 +02:00
for (i = 0; i < NUM_STORYTELLER_TALES; i++)
2018-05-03 23:03:52 +02:00
{
if (storyteller->gameStatIDs[i] != 0)
{
2019-10-22 00:09:57 +02:00
memcpy(playerName, storyteller->trainerNames[i], PLAYER_NAME_LENGTH);
playerName[PLAYER_NAME_LENGTH] = EOS;
if (IsStringJapanese(playerName))
2018-05-03 23:03:52 +02:00
{
2019-10-22 00:09:57 +02:00
memset(playerName, CHAR_SPACE, PLAYER_NAME_LENGTH + 1);
StringCopy(playerName, gText_Friend);
memcpy(storyteller->trainerNames[i], playerName, PLAYER_NAME_LENGTH);
storyteller->language[i] = GAME_LANGUAGE;
2018-05-03 23:03:52 +02:00
}
}
}
}
break;
}
}
void sub_8120C0C(union OldMan * oldMan, u32 r8, u32 r7, u32 r3)
{
s32 i;
switch (oldMan->common.id)
{
case MAUVILLE_MAN_TRADER:
{
struct MauvilleOldManTrader * trader = &oldMan->trader;
2019-10-20 22:11:07 +02:00
for (i = 0; i < NUM_TRADER_ITEMS; i++)
2018-05-03 23:03:52 +02:00
{
if (IsStringJapanese(trader->playerNames[i]))
2018-05-03 23:03:52 +02:00
{
trader->language[i] = r8;
2018-05-03 23:03:52 +02:00
}
else
{
trader->language[i] = r7;
2018-05-03 23:03:52 +02:00
}
}
}
break;
case MAUVILLE_MAN_STORYTELLER:
{
struct MauvilleManStoryteller * storyteller = &oldMan->storyteller;
2019-10-20 22:11:07 +02:00
for (i = 0; i < NUM_STORYTELLER_TALES; i++)
2018-05-03 23:03:52 +02:00
{
if (IsStringJapanese(storyteller->trainerNames[i]))
{
storyteller->language[i] = r8;
2018-05-03 23:03:52 +02:00
}
else
{
storyteller->language[i] = r7;
2018-05-03 23:03:52 +02:00
}
}
}
break;
case MAUVILLE_MAN_BARD:
{
struct MauvilleManBard * bard = &oldMan->bard;
if (r3 == LANGUAGE_JAPANESE)
bard->language = r8;
else
bard->language = r7;
}
break;
case MAUVILLE_MAN_HIPSTER:
{
struct MauvilleManHipster * hipster = &oldMan->hipster;
if (r3 == LANGUAGE_JAPANESE)
hipster->language = r8;
else
hipster->language = r7;
}
break;
case MAUVILLE_MAN_GIDDY:
{
struct MauvilleManGiddy * giddy = &oldMan->giddy;
if (r3 == LANGUAGE_JAPANESE)
giddy->language = r8;
else
giddy->language = r7;
}
break;
}
}
2018-05-03 23:26:02 +02:00
2018-05-26 00:25:36 +02:00
void SanitizeReceivedEmeraldOldMan(union OldMan * oldMan, u32 version, u32 language)
2018-05-03 23:26:02 +02:00
{
2019-10-22 00:09:57 +02:00
u8 playerName[PLAYER_NAME_LENGTH + 1];
2018-05-03 23:26:02 +02:00
s32 i;
2018-05-26 00:25:36 +02:00
if (oldMan->common.id == MAUVILLE_MAN_STORYTELLER && language == LANGUAGE_JAPANESE)
2018-05-03 23:26:02 +02:00
{
struct MauvilleManStoryteller * storyteller = &oldMan->storyteller;
2019-10-20 22:11:07 +02:00
for (i = 0; i < NUM_STORYTELLER_TALES; i++)
2018-05-03 23:26:02 +02:00
{
if (storyteller->gameStatIDs[i] != 0)
{
2019-10-22 00:09:57 +02:00
memcpy(playerName, storyteller->trainerNames[i], PLAYER_NAME_LENGTH);
playerName[PLAYER_NAME_LENGTH] = EOS;
if (IsStringJapanese(playerName))
storyteller->language[i] = LANGUAGE_JAPANESE;
2018-05-03 23:26:02 +02:00
else
storyteller->language[i] = GAME_LANGUAGE;
2018-05-03 23:26:02 +02:00
}
}
}
}
2018-05-26 00:25:36 +02:00
void SanitizeReceivedRubyOldMan(union OldMan * oldMan, u32 version, u32 language)
2018-05-03 23:26:02 +02:00
{
2018-05-26 00:25:36 +02:00
bool32 isRuby = (version == VERSION_SAPPHIRE || version == VERSION_RUBY);
2018-05-03 23:26:02 +02:00
switch (oldMan->common.id)
{
case MAUVILLE_MAN_TRADER:
{
struct MauvilleOldManTrader * trader = &oldMan->trader;
s32 i;
2018-05-26 00:25:36 +02:00
if (isRuby)
2018-05-03 23:26:02 +02:00
{
2019-10-20 22:11:07 +02:00
for (i = 0; i < NUM_TRADER_ITEMS; i++)
2018-05-03 23:26:02 +02:00
{
u8 * str = trader->playerNames[i];
2018-05-03 23:26:02 +02:00
if (str[0] == EXT_CTRL_CODE_BEGIN && str[1] == EXT_CTRL_CODE_JPN)
{
StripExtCtrlCodes(str);
trader->language[i] = LANGUAGE_JAPANESE;
2018-05-03 23:26:02 +02:00
}
else
2018-05-26 00:25:36 +02:00
trader->language[i] = language;
2018-05-03 23:26:02 +02:00
}
}
else
{
2019-10-20 22:11:07 +02:00
for (i = 0; i < NUM_TRADER_ITEMS; i++)
2018-05-03 23:26:02 +02:00
{
if (trader->language[i] == LANGUAGE_JAPANESE)
2018-05-03 23:26:02 +02:00
{
StripExtCtrlCodes(trader->playerNames[i]);
2018-05-03 23:26:02 +02:00
}
}
}
}
break;
case MAUVILLE_MAN_STORYTELLER:
{
struct MauvilleManStoryteller * storyteller = &oldMan->storyteller;
s32 i;
2018-05-26 00:25:36 +02:00
if (isRuby)
2018-05-03 23:26:02 +02:00
{
2019-10-20 22:11:07 +02:00
for (i = 0; i < NUM_STORYTELLER_TALES; i++)
2018-05-03 23:26:02 +02:00
{
if (storyteller->gameStatIDs[i] != 0)
2018-05-26 00:25:36 +02:00
storyteller->language[i] = language;
2018-05-03 23:26:02 +02:00
}
}
}
break;
case MAUVILLE_MAN_BARD:
{
struct MauvilleManBard * bard = &oldMan->bard;
2018-05-26 00:25:36 +02:00
if (isRuby)
2018-05-03 23:26:02 +02:00
{
2018-05-26 00:25:36 +02:00
bard->language = language;
2018-05-03 23:26:02 +02:00
}
}
break;
case MAUVILLE_MAN_HIPSTER:
{
struct MauvilleManHipster * hipster = &oldMan->hipster;
2018-05-26 00:25:36 +02:00
if (isRuby)
2018-05-03 23:26:02 +02:00
{
2018-05-26 00:25:36 +02:00
hipster->language = language;
2018-05-03 23:26:02 +02:00
}
}
break;
case MAUVILLE_MAN_GIDDY:
{
struct MauvilleManGiddy * giddy = &oldMan->giddy;
2018-05-26 00:25:36 +02:00
if (isRuby)
2018-05-03 23:26:02 +02:00
{
2018-05-26 00:25:36 +02:00
giddy->language = language;
2018-05-03 23:26:02 +02:00
}
}
break;
}
}
struct Story
{
u8 stat;
u8 minVal;
const u8 *title;
const u8 *action;
const u8 *fullText;
};
static const struct Story sStorytellerStories[] = {
2019-10-20 22:11:07 +02:00
// The 50 below is replaced with GAME_STAT_SAVED_GAME
{
50, 1,
MauvilleCity_PokemonCenter_1F_Text_SavedGameTitle,
MauvilleCity_PokemonCenter_1F_Text_SavedGameAction,
MauvilleCity_PokemonCenter_1F_Text_SavedGameStory
},
{
GAME_STAT_STARTED_TRENDS, 1,
MauvilleCity_PokemonCenter_1F_Text_TrendsStartedTitle,
MauvilleCity_PokemonCenter_1F_Text_TrendsStartedAction,
MauvilleCity_PokemonCenter_1F_Text_TrendsStartedStory
},
{
GAME_STAT_PLANTED_BERRIES, 1,
MauvilleCity_PokemonCenter_1F_Text_BerriesPlantedTitle,
MauvilleCity_PokemonCenter_1F_Text_BerriesPlantedAction,
MauvilleCity_PokemonCenter_1F_Text_BerriesPlantedStory
},
{
GAME_STAT_TRADED_BIKES, 1,
MauvilleCity_PokemonCenter_1F_Text_BikeTradesTitle,
MauvilleCity_PokemonCenter_1F_Text_BikeTradesAction,
MauvilleCity_PokemonCenter_1F_Text_BikeTradesStory
},
{
GAME_STAT_GOT_INTERVIEWED, 1,
MauvilleCity_PokemonCenter_1F_Text_InterviewsTitle,
MauvilleCity_PokemonCenter_1F_Text_InterviewsAction,
MauvilleCity_PokemonCenter_1F_Text_InterviewsStory
},
{
GAME_STAT_TRAINER_BATTLES, 1,
MauvilleCity_PokemonCenter_1F_Text_TrainerBattlesTitle,
MauvilleCity_PokemonCenter_1F_Text_TrainerBattlesAction,
MauvilleCity_PokemonCenter_1F_Text_TrainerBattlesStory
},
{
GAME_STAT_POKEMON_CAPTURES, 1,
MauvilleCity_PokemonCenter_1F_Text_PokemonCaughtTitle,
MauvilleCity_PokemonCenter_1F_Text_PokemonCaughtAction,
MauvilleCity_PokemonCenter_1F_Text_PokemonCaughtStory
},
{
GAME_STAT_FISHING_CAPTURES, 1,
MauvilleCity_PokemonCenter_1F_Text_FishingPokemonCaughtTitle,
MauvilleCity_PokemonCenter_1F_Text_FishingPokemonCaughtAction,
MauvilleCity_PokemonCenter_1F_Text_FishingPokemonCaughtStory
},
{
GAME_STAT_HATCHED_EGGS, 1,
MauvilleCity_PokemonCenter_1F_Text_EggsHatchedTitle,
MauvilleCity_PokemonCenter_1F_Text_EggsHatchedAction,
MauvilleCity_PokemonCenter_1F_Text_EggsHatchedStory
},
{
GAME_STAT_EVOLVED_POKEMON, 1,
MauvilleCity_PokemonCenter_1F_Text_PokemonEvolvedTitle,
MauvilleCity_PokemonCenter_1F_Text_PokemonEvolvedAction,
MauvilleCity_PokemonCenter_1F_Text_PokemonEvolvedStory
},
{
GAME_STAT_USED_POKECENTER, 1,
MauvilleCity_PokemonCenter_1F_Text_UsedPokemonCenterTitle,
MauvilleCity_PokemonCenter_1F_Text_UsedPokemonCenterAction,
MauvilleCity_PokemonCenter_1F_Text_UsedPokemonCenterStory
},
{
GAME_STAT_RESTED_AT_HOME, 1,
MauvilleCity_PokemonCenter_1F_Text_RestedAtHomeTitle,
MauvilleCity_PokemonCenter_1F_Text_RestedAtHomeAction,
MauvilleCity_PokemonCenter_1F_Text_RestedAtHomeStory
},
{
GAME_STAT_ENTERED_SAFARI_ZONE, 1,
MauvilleCity_PokemonCenter_1F_Text_SafariGamesTitle,
MauvilleCity_PokemonCenter_1F_Text_SafariGamesAction,
MauvilleCity_PokemonCenter_1F_Text_SafariGamesStory
},
{
GAME_STAT_USED_CUT, 1,
MauvilleCity_PokemonCenter_1F_Text_UsedCutTitle,
MauvilleCity_PokemonCenter_1F_Text_UsedCutAction,
MauvilleCity_PokemonCenter_1F_Text_UsedCutStory
},
{
GAME_STAT_USED_ROCK_SMASH, 1,
MauvilleCity_PokemonCenter_1F_Text_UsedRockSmashTitle,
MauvilleCity_PokemonCenter_1F_Text_UsedRockSmashAction,
MauvilleCity_PokemonCenter_1F_Text_UsedRockSmashStory
},
{
GAME_STAT_MOVED_SECRET_BASE, 1,
MauvilleCity_PokemonCenter_1F_Text_MovedBasesTitle,
MauvilleCity_PokemonCenter_1F_Text_MovedBasesAction,
MauvilleCity_PokemonCenter_1F_Text_MovedBasesStory
},
{
GAME_STAT_USED_SPLASH, 1,
MauvilleCity_PokemonCenter_1F_Text_UsedSplashTitle,
MauvilleCity_PokemonCenter_1F_Text_UsedSplashAction,
MauvilleCity_PokemonCenter_1F_Text_UsedSplashStory
},
{
GAME_STAT_USED_STRUGGLE, 1,
MauvilleCity_PokemonCenter_1F_Text_UsedStruggleTitle,
MauvilleCity_PokemonCenter_1F_Text_UsedStruggleAction,
MauvilleCity_PokemonCenter_1F_Text_UsedStruggleStory
},
{
GAME_STAT_SLOT_JACKPOTS, 1,
MauvilleCity_PokemonCenter_1F_Text_SlotJackpotsTitle,
MauvilleCity_PokemonCenter_1F_Text_SlotJackpotsAction,
MauvilleCity_PokemonCenter_1F_Text_SlotJackpotsStory
},
{
GAME_STAT_CONSECUTIVE_ROULETTE_WINS, 2,
MauvilleCity_PokemonCenter_1F_Text_RouletteWinsTitle,
MauvilleCity_PokemonCenter_1F_Text_RouletteWinsAction,
MauvilleCity_PokemonCenter_1F_Text_RouletteWinsStory
},
{
GAME_STAT_ENTERED_BATTLE_TOWER, 1,
MauvilleCity_PokemonCenter_1F_Text_BattleTowerChallengesTitle,
MauvilleCity_PokemonCenter_1F_Text_BattleTowerChallengesAction,
MauvilleCity_PokemonCenter_1F_Text_BattleTowerChallengesStory
},
{
GAME_STAT_POKEBLOCKS, 1,
MauvilleCity_PokemonCenter_1F_Text_MadePokeblocksTitle,
MauvilleCity_PokemonCenter_1F_Text_MadePokeblocksAction,
MauvilleCity_PokemonCenter_1F_Text_MadePokeblocksStory
},
{
GAME_STAT_ENTERED_CONTEST, 1,
MauvilleCity_PokemonCenter_1F_Text_EnteredContestsTitle,
MauvilleCity_PokemonCenter_1F_Text_EnteredContestsAction,
MauvilleCity_PokemonCenter_1F_Text_EnteredContestsStory
},
{
GAME_STAT_WON_CONTEST, 1,
MauvilleCity_PokemonCenter_1F_Text_WonContestsTitle,
MauvilleCity_PokemonCenter_1F_Text_WonContestsAction,
MauvilleCity_PokemonCenter_1F_Text_WonContestsStory
},
{
GAME_STAT_SHOPPED, 1,
MauvilleCity_PokemonCenter_1F_Text_TimesShoppedTitle,
MauvilleCity_PokemonCenter_1F_Text_TimesShoppedAction,
MauvilleCity_PokemonCenter_1F_Text_TimesShoppedStory
},
{
GAME_STAT_USED_ITEMFINDER, 1,
MauvilleCity_PokemonCenter_1F_Text_UsedItemFinderTitle,
MauvilleCity_PokemonCenter_1F_Text_UsedItemFinderAction,
MauvilleCity_PokemonCenter_1F_Text_UsedItemFinderStory
},
{
GAME_STAT_GOT_RAINED_ON, 1,
MauvilleCity_PokemonCenter_1F_Text_TimesRainedTitle,
MauvilleCity_PokemonCenter_1F_Text_TimesRainedAction,
MauvilleCity_PokemonCenter_1F_Text_TimesRainedStory
},
{
GAME_STAT_CHECKED_POKEDEX, 1,
MauvilleCity_PokemonCenter_1F_Text_CheckedPokedexTitle,
MauvilleCity_PokemonCenter_1F_Text_CheckedPokedexAction,
MauvilleCity_PokemonCenter_1F_Text_CheckedPokedexStory
},
{
GAME_STAT_RECEIVED_RIBBONS, 1,
MauvilleCity_PokemonCenter_1F_Text_ReceivedRibbonsTitle,
MauvilleCity_PokemonCenter_1F_Text_ReceivedRibbonsAction,
MauvilleCity_PokemonCenter_1F_Text_ReceivedRibbonsStory
},
{
GAME_STAT_JUMPED_DOWN_LEDGES, 1,
MauvilleCity_PokemonCenter_1F_Text_LedgesJumpedTitle,
MauvilleCity_PokemonCenter_1F_Text_LedgesJumpedAction,
MauvilleCity_PokemonCenter_1F_Text_LedgesJumpedStory
},
{
GAME_STAT_WATCHED_TV, 1,
MauvilleCity_PokemonCenter_1F_Text_TVWatchedTitle,
MauvilleCity_PokemonCenter_1F_Text_TVWatchedAction,
MauvilleCity_PokemonCenter_1F_Text_TVWatchedStory
},
{
GAME_STAT_CHECKED_CLOCK, 1,
MauvilleCity_PokemonCenter_1F_Text_CheckedClockTitle,
MauvilleCity_PokemonCenter_1F_Text_CheckedClockAction,
MauvilleCity_PokemonCenter_1F_Text_CheckedClockStory
},
{
GAME_STAT_WON_POKEMON_LOTTERY, 1,
MauvilleCity_PokemonCenter_1F_Text_WonLotteryTitle,
MauvilleCity_PokemonCenter_1F_Text_WonLotteryAction,
MauvilleCity_PokemonCenter_1F_Text_WonLotteryStory
},
{
GAME_STAT_USED_DAYCARE, 1,
MauvilleCity_PokemonCenter_1F_Text_UsedDaycareTitle,
MauvilleCity_PokemonCenter_1F_Text_UsedDaycareAction,
MauvilleCity_PokemonCenter_1F_Text_UsedDaycareStory
},
{
GAME_STAT_RODE_CABLE_CAR, 1,
MauvilleCity_PokemonCenter_1F_Text_RodeCableCarTitle,
MauvilleCity_PokemonCenter_1F_Text_RodeCableCarAction,
MauvilleCity_PokemonCenter_1F_Text_RodeCableCarStory
},
{
GAME_STAT_ENTERED_HOT_SPRINGS, 1,
MauvilleCity_PokemonCenter_1F_Text_HotSpringsTitle,
MauvilleCity_PokemonCenter_1F_Text_HotSpringsAction,
MauvilleCity_PokemonCenter_1F_Text_HotSpringsStory
}
2018-05-03 23:26:02 +02:00
};
2018-05-03 23:51:14 +02:00
static void StorytellerSetup(void)
2018-05-03 23:51:14 +02:00
{
s32 i;
sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller;
2018-05-03 23:51:14 +02:00
sStorytellerPtr->id = MAUVILLE_MAN_STORYTELLER;
sStorytellerPtr->alreadyRecorded = FALSE;
2019-10-20 22:11:07 +02:00
for (i = 0; i < NUM_STORYTELLER_TALES; i++)
2018-05-03 23:51:14 +02:00
{
sStorytellerPtr->gameStatIDs[i] = 0;
sStorytellerPtr->trainerNames[0][i] = EOS; // Maybe they meant storyteller->trainerNames[i][0] instead?
2018-05-03 23:51:14 +02:00
}
}
static void Storyteller_ResetFlag(void)
2018-05-03 23:51:14 +02:00
{
sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller;
2018-05-03 23:51:14 +02:00
sStorytellerPtr->id = MAUVILLE_MAN_STORYTELLER;
sStorytellerPtr->alreadyRecorded = FALSE;
2018-05-03 23:51:14 +02:00
}
static u32 StorytellerGetGameStat(u8 stat)
2018-05-03 23:51:14 +02:00
{
if (stat == 50)
2019-10-20 22:11:07 +02:00
stat = GAME_STAT_SAVED_GAME;
2018-05-03 23:51:14 +02:00
return GetGameStat(stat);
}
static const struct Story *GetStoryByStat(u32 stat)
2018-05-03 23:51:14 +02:00
{
s32 i;
2019-10-20 22:11:07 +02:00
for (i = 0; i < (int)ARRAY_COUNT(sStorytellerStories); i++)
2018-05-03 23:51:14 +02:00
{
if (sStorytellerStories[i].stat == stat)
return &sStorytellerStories[i];
2018-05-03 23:51:14 +02:00
}
2019-10-20 22:11:07 +02:00
return &sStorytellerStories[ARRAY_COUNT(sStorytellerStories) - 1];
2018-05-03 23:51:14 +02:00
}
static const u8 *GetStoryTitleByStat(u32 stat)
2018-05-03 23:51:14 +02:00
{
return GetStoryByStat(stat)->title;
2018-05-03 23:51:14 +02:00
}
static const u8 *GetStoryTextByStat(u32 stat)
2018-05-03 23:51:14 +02:00
{
return GetStoryByStat(stat)->fullText;
2018-05-03 23:51:14 +02:00
}
static const u8 *GetStoryActionByStat(u32 stat)
2018-05-03 23:51:14 +02:00
{
return GetStoryByStat(stat)->action;
2018-05-03 23:51:14 +02:00
}
static u8 GetFreeStorySlot(void)
2018-05-03 23:51:14 +02:00
{
u8 i;
2019-10-20 22:11:07 +02:00
for (i = 0; i < NUM_STORYTELLER_TALES; i++)
2018-05-03 23:51:14 +02:00
{
if (sStorytellerPtr->gameStatIDs[i] == 0)
2018-05-03 23:51:14 +02:00
break;
}
return i;
}
static u32 StorytellerGetRecordedTrainerStat(u32 trainer)
2018-05-03 23:51:14 +02:00
{
u8 *ptr = sStorytellerPtr->statValues[trainer];
2018-05-03 23:51:14 +02:00
return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
}
static void StorytellerSetRecordedTrainerStat(u32 trainer, u32 val)
2018-05-03 23:51:14 +02:00
{
u8 *ptr = sStorytellerPtr->statValues[trainer];
2018-05-03 23:51:14 +02:00
ptr[0] = val;
ptr[1] = val >> 8;
ptr[2] = val >> 16;
ptr[3] = val >> 24;
}
static bool32 HasTrainerStatIncreased(u32 trainer)
2018-05-03 23:51:14 +02:00
{
if (StorytellerGetGameStat(sStorytellerPtr->gameStatIDs[trainer]) > StorytellerGetRecordedTrainerStat(trainer))
2018-05-03 23:51:14 +02:00
return TRUE;
else
return FALSE;
}
static void GetStoryByStattellerPlayerName(u32 player, void *dst)
2018-05-03 23:51:14 +02:00
{
u8 *name = sStorytellerPtr->trainerNames[player];
2018-05-03 23:51:14 +02:00
2019-10-20 22:11:07 +02:00
memset(dst, EOS, PLAYER_NAME_LENGTH + 1);
memcpy(dst, name, PLAYER_NAME_LENGTH);
2018-05-03 23:51:14 +02:00
}
static void StorytellerSetPlayerName(u32 player, const u8 * src)
2018-05-03 23:51:14 +02:00
{
u8 * name = sStorytellerPtr->trainerNames[player];
2019-10-20 22:11:07 +02:00
memset(name, EOS, PLAYER_NAME_LENGTH);
memcpy(name, src, PLAYER_NAME_LENGTH);
2018-05-03 23:51:14 +02:00
}
static void StorytellerRecordNewStat(u32 player, u32 stat)
2018-05-03 23:51:14 +02:00
{
sStorytellerPtr->gameStatIDs[player] = stat;
StorytellerSetPlayerName(player, gSaveBlock2Ptr->playerName);
StorytellerSetRecordedTrainerStat(player, StorytellerGetGameStat(stat));
ConvertIntToDecimalStringN(gStringVar1, StorytellerGetGameStat(stat), STR_CONV_MODE_LEFT_ALIGN, 10);
StringCopy(gStringVar2, GetStoryActionByStat(stat));
sStorytellerPtr->language[player] = gGameLanguage;
2018-05-03 23:51:14 +02:00
}
static void ScrambleStatList(u8 * arr, s32 count)
2018-05-03 23:51:14 +02:00
{
s32 i;
for (i = 0; i < count; i++)
arr[i] = i;
for (i = 0; i < count; i++)
{
u32 a = Random() % count;
u32 b = Random() % count;
u8 temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}
2018-05-04 00:05:07 +02:00
struct UnknownStruct_0859F288
{
s32 length;
2018-05-04 00:05:07 +02:00
u32 unused2;
};
static const struct UnknownStruct_0859F288 sStorytellerStuff = {
ARRAY_COUNT(sStorytellerStories),
sizeof(sStorytellerStuff)
2018-05-04 00:05:07 +02:00
};
static bool8 StorytellerInitializeRandomStat(void)
2018-05-04 00:05:07 +02:00
{
u8 arr[sStorytellerStuff.length];
2018-05-04 00:05:07 +02:00
s32 i;
s32 j;
ScrambleStatList(arr, ARRAY_COUNT(sStorytellerStories));
for (i = 0; i < (s32)ARRAY_COUNT(sStorytellerStories); i++)
2018-05-04 00:05:07 +02:00
{
u8 stat = sStorytellerStories[arr[i]].stat;
u8 minVal = sStorytellerStories[arr[i]].minVal;
2018-05-04 00:05:07 +02:00
2019-10-20 22:11:07 +02:00
for (j = 0; j < NUM_STORYTELLER_TALES; j++)
2018-05-04 00:05:07 +02:00
{
if (sStorytellerPtr->gameStatIDs[j] == stat)
2018-05-04 00:05:07 +02:00
break;
}
2019-10-20 22:11:07 +02:00
if (j == NUM_STORYTELLER_TALES && StorytellerGetGameStat(stat) >= minVal)
2018-05-04 00:05:07 +02:00
{
sStorytellerPtr->alreadyRecorded = TRUE;
2019-10-20 22:11:07 +02:00
if (GetFreeStorySlot() == NUM_STORYTELLER_TALES)
StorytellerRecordNewStat(sSelectedStory, stat);
2018-05-04 00:05:07 +02:00
else
StorytellerRecordNewStat(GetFreeStorySlot(), stat);
2018-05-04 00:05:07 +02:00
return TRUE;
}
}
return FALSE;
}
static void StorytellerDisplayStory(u32 player)
2018-05-04 00:05:07 +02:00
{
u8 stat = sStorytellerPtr->gameStatIDs[player];
2018-05-04 00:05:07 +02:00
2019-09-30 21:43:44 +02:00
ConvertIntToDecimalStringN(gStringVar1, StorytellerGetRecordedTrainerStat(player), STR_CONV_MODE_LEFT_ALIGN, 10);
StringCopy(gStringVar2, GetStoryActionByStat(stat));
GetStoryByStattellerPlayerName(player, gStringVar3);
ConvertInternationalString(gStringVar3, sStorytellerPtr->language[player]);
ShowFieldMessage(GetStoryTextByStat(stat));
2018-05-04 00:05:07 +02:00
}
static void PrintStoryList(void)
{
s32 i;
s32 width = GetStringWidth(1, gText_Exit, 0);
u8 tileWidth;
2019-10-20 22:11:07 +02:00
for (i = 0; i < NUM_STORYTELLER_TALES; i++)
{
s32 curWidth;
u16 gameStatID = sStorytellerPtr->gameStatIDs[i];
if (gameStatID == 0)
break;
curWidth = GetStringWidth(1, GetStoryTitleByStat(gameStatID), 0);
if (curWidth > width)
width = curWidth;
}
sStorytellerWindowId = CreateWindowFromRect(0, 0, ConvertPixelWidthToTileWidth(width), GetFreeStorySlot() * 2 + 2);
SetStandardWindowBorderStyle(sStorytellerWindowId, 0);
2019-10-20 22:11:07 +02:00
for (i = 0; i < NUM_STORYTELLER_TALES; i++)
{
u16 gameStatID = sStorytellerPtr->gameStatIDs[i];
if (gameStatID == 0)
break;
AddTextPrinterParameterized(sStorytellerWindowId, 1, GetStoryTitleByStat(gameStatID), 8, 16 * i + 1, 0xFF, NULL);
}
AddTextPrinterParameterized(sStorytellerWindowId, 1, gText_Exit, 8, 16 * i + 1, 0xFF, NULL);
InitMenuInUpperLeftCornerPlaySoundWhenAPressed(sStorytellerWindowId, GetFreeStorySlot() + 1, 0);
CopyWindowToVram(sStorytellerWindowId, 3);
}
2019-10-20 22:11:07 +02:00
static void Task_StoryListMenu(u8 taskId)
{
struct Task *task = &gTasks[taskId];
s32 selection;
switch (task->data[0])
{
case 0:
PrintStoryList();
task->data[0]++;
break;
case 1:
2018-11-05 21:45:54 +01:00
selection = Menu_ProcessInput();
2019-02-02 11:04:38 +01:00
if (selection == MENU_NOTHING_CHOSEN)
break;
2019-02-02 11:04:38 +01:00
if (selection == MENU_B_PRESSED || selection == GetFreeStorySlot())
{
gSpecialVar_Result = 0;
}
else
{
gSpecialVar_Result = 1;
sSelectedStory = selection;
}
ClearToTransparentAndRemoveWindow(sStorytellerWindowId);
DestroyTask(taskId);
EnableBothScriptContexts();
break;
}
}
// Sets gSpecialVar_Result to TRUE if player selected a story
void ScrSpecial_StorytellerStoryListMenu(void)
{
CreateTask(Task_StoryListMenu, 80);
}
void ScrSpecial_StorytellerDisplayStory(void)
{
StorytellerDisplayStory(sSelectedStory);
}
u8 ScrSpecial_StorytellerGetFreeStorySlot(void)
{
sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller;
return GetFreeStorySlot();
}
// Returns TRUE if stat has increased
bool8 ScrSpecial_StorytellerUpdateStat(void)
{
u8 r4;
sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller;
r4 = sStorytellerPtr->gameStatIDs[sSelectedStory];
if (HasTrainerStatIncreased(sSelectedStory) == TRUE)
{
StorytellerRecordNewStat(sSelectedStory, r4);
return TRUE;
}
return FALSE;
}
bool8 ScrSpecial_HasStorytellerAlreadyRecorded(void)
{
sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller;
if (sStorytellerPtr->alreadyRecorded == FALSE)
return FALSE;
else
return TRUE;
}
bool8 ScrSpecial_StorytellerInitializeRandomStat(void)
{
sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller;
return StorytellerInitializeRandomStat();
}