pokefirered/src/quest_log.c
2022-10-05 15:00:58 -04:00

1701 lines
50 KiB
C

#include "global.h"
#include "gflib.h"
#include "task.h"
#include "menu.h"
#include "menu_helpers.h"
#include "text_window.h"
#include "event_data.h"
#include "script.h"
#include "overworld.h"
#include "field_fadetransition.h"
#include "field_weather.h"
#include "event_object_movement.h"
#include "event_object_lock.h"
#include "field_player_avatar.h"
#include "item.h"
#include "region_map.h"
#include "map_name_popup.h"
#include "wild_encounter.h"
#include "help_system.h"
#include "pokemon_storage_system.h"
#include "save.h"
#include "quest_log_objects.h"
#include "quest_log_player.h"
#include "quest_log.h"
#include "new_menu_helpers.h"
#include "strings.h"
#include "constants/event_objects.h"
#include "constants/maps.h"
#include "constants/quest_log.h"
#include "constants/field_weather.h"
#include "constants/event_object_movement.h"
struct TrainerFanClub
{
u8 timer:7;
u8 gotInitialFans:1;
u8 fanFlags;
};
#define TRAINER_FAN_CLUB ((struct TrainerFanClub *)GetVarPointer(VAR_FANCLUB_FAN_COUNTER))
#define GET_TRAINER_FAN_CLUB_FLAG(flag) (fanClub->fanFlags >> (flag) & 1)
#define SET_TRAINER_FAN_CLUB_FLAG(flag) (fanClub->fanFlags |= 1 << (flag))
#define FLIP_TRAINER_FAN_CLUB_FLAG(flag)(fanClub->fanFlags ^= 1 << (flag))
struct UnkStruct_203AE94
{
u8 playbackSubstate:4;
u8 playingEvent:2;
u8 sceneEndMode:2;
u8 cursor;
u8 timer;
u8 overlapTimer;
};
struct FlagOrVarRecord
{
u16 idx:15;
u16 isFlag:1;
u16 value;
};
u8 gQuestLogPlaybackState;
u16 sNumEventsInLogEntry;
struct FieldInput gQuestLogFieldInput;
struct QuestLogEntry * sCurQuestLogEntry;
static struct FlagOrVarRecord * sFlagOrVarRecords;
static u16 sNumFlagsOrVars;
static EWRAM_DATA u8 sCurrentSceneNum = 0;
static EWRAM_DATA u8 sNumScenes = 0;
EWRAM_DATA u8 gQuestLogState = 0;
static EWRAM_DATA u16 gUnknown_203ADFC = 0;
static EWRAM_DATA u8 sQuestLogHeaderWindowIds[3] = {0};
EWRAM_DATA u16 *gUnknown_203AE04 = NULL;
EWRAM_DATA u16 *sEventRecordingPointer = NULL;
static EWRAM_DATA u16 *gUnknown_203AE0C[32] = {NULL};
static EWRAM_DATA void (* sQuestLogCB)(void) = NULL;
static EWRAM_DATA u16 *sPalettesBackup = NULL;
static EWRAM_DATA struct UnkStruct_203AE94 sQuestLogCurrentScene = {0};
static EWRAM_DATA struct QuestLogEntry sQuestLogSceneRecordBuffer[32] = {0};
EWRAM_DATA u16 sQuestLogCursor = 0;
static EWRAM_DATA u8 sMovementScripts[64][2] = {{0}};
static EWRAM_DATA u16 sNextStepDelay = 0;
static EWRAM_DATA u16 sLastQuestLogCursor = 0;
static EWRAM_DATA u16 sFlagOrVarPlayhead = 0;
static void QLogCB_Recording(void);
static void QLogCB_Playback(void);
static void SetPlayerInitialCoordsAtScene(u8);
static void SetNPCInitialCoordsAtScene(u8);
static void TryRecordEvent39_GoToNextScene(void);
static void BackUpTrainerRematchesToVars(void);
static void BackUpMapLayoutToVar(void);
static void SetGameStateAtScene(u8);
static u8 TryRecordQuestLogEntrySequence(struct QuestLogEntry *);
static void Task_BeginQuestLogPlayback(u8);
static void QuestLogPlaybackSetObjectEventTemplates(u8);
static void QLPlayback_InitOverworldState(void);
static void QuestLog_GetSaneMonCounts(void);
static u16 QuestLog_GetSanePartyCount(void);
static u16 QuestLog_GetSaneBoxCount(void);
static void sub_8111688(void);
static void ReadQuestLogScriptFromSav1(u8, struct QuestLogEntry *);
static void QuestLog_BeginFadeAtEndOfScene(s8 delay);
static void QuestLog_AdvancePlayhead(void);
static void QuestLog_StartFinalScene(void);
static void Task_RunPlaybackCB(u8);
static void QuestLog_PlayCurrentEvent(void);
static void HandleShowQuestLogMessage(void);
static u8 GetQuestLogTextDisplayDuration(void);
static void DrawQuestLogSceneDescription(void);
static void sub_8111D90(u8);
static void QuestLog_CloseTextWindow(void);
static void QuestLog_SkipToEndOfPlayback(s8 delay);
static void QuestLog_WaitFadeAndCancelPlayback(void);
static bool8 FieldCB2_FinalScene(void);
static void Task_FinalScene_WaitFade(u8);
static void Task_QuestLogScene_SavedGame(u8);
static void Task_WaitAtEndOfQuestLog(u8);
static void Task_EndQuestLog(u8);
static bool8 sub_81121D8(u8);
static void QL_SlightlyDarkenSomePals(void);
static void TogglePlaybackStateForOverworldLock(u8);
static void SetUpQuestLogEntry(u8, struct QuestLogEntry *, u16);
static bool8 RecordHeadAtEndOfEntryOrScriptContext2Enabled(void);
static bool8 RecordHeadAtEndOfEntry(void);
static void TryLoseFansFromPlayTimeAfterLinkBattle(struct TrainerFanClub *);
static void UpdateTrainerFanClubGameClear(struct TrainerFanClub *);
static u8 PlayerGainRandomTrainerFan(struct TrainerFanClub *);
static u16 GetNumFansOfPlayerInTrainerFanClub(struct TrainerFanClub *);
static void TryLoseFansFromPlayTime(struct TrainerFanClub *);
static bool16 IsFanClubMemberFanOfPlayer(struct TrainerFanClub *);
static void SetInitialFansOfPlayer(struct TrainerFanClub *);
static void BufferFanClubTrainerName(struct LinkBattleRecords *, u8, u8);
static void UpdateTrainerFansAfterLinkBattle(struct TrainerFanClub *);
static bool8 DidPlayerGetFirstFans(struct TrainerFanClub * );
static void SetPlayerGotFirstFans(struct TrainerFanClub *);
static bool8 InQuestLogDisabledLocation(void);
static bool8 TrySetLinkQuestLogEvent(u16, const u16 *);
static bool8 TrySetTrainerBattleQuestLogEvent(u16, const u16 *);
static const struct WindowTemplate sQuestLogHeaderWindowTemplates[3] = {
{ 0, 0, 0, 30, 2, 15, 0x0e9 },
{ 0, 0, 18, 30, 2, 15, 0x0ad },
{ 0, 0, 14, 30, 6, 15, 0x14c }
};
static const u8 sTextColors[3] = {TEXT_DYNAMIC_COLOR_6, TEXT_COLOR_WHITE, TEXT_DYNAMIC_COLOR_3};
static const u16 sUnknown_8456638[] = INCBIN_U16("graphics/unknown/unknown_8456638.bin");
static const u8 sQuestLogTextLineYCoords[] = {17, 10, 3};
void SetQuestLogRecordAndPlaybackPointers(void *oldPointer)
{
ptrdiff_t offset = (void *)gSaveBlock1Ptr - oldPointer;
if (gUnknown_203AE04)
gUnknown_203AE04 = (void *)gUnknown_203AE04 + offset;
if (gQuestLogState != 0)
{
if (sEventRecordingPointer)
sEventRecordingPointer = (void *)sEventRecordingPointer + offset;
if (gQuestLogState == QL_STATE_PLAYBACK)
{
int r3;
for (r3 = 0; r3 < (int)NELEMS(gUnknown_203AE0C); r3++)
if (gUnknown_203AE0C[r3])
gUnknown_203AE0C[r3] = (void *)gUnknown_203AE0C[r3] + offset;
}
}
}
void ResetQuestLog(void)
{
memset(gSaveBlock1Ptr->questLog, 0, sizeof(gSaveBlock1Ptr->questLog));
sCurrentSceneNum = 0;
gQuestLogState = 0;
sQuestLogCB = NULL;
sEventRecordingPointer = NULL;
gUnknown_203AE04 = NULL;
sub_8113BD8();
ResetDeferredLinkEvent();
}
static void DestroySav1QuestLogEntry(u8 a0)
{
memset(gSaveBlock1Ptr->questLog + a0, 0, sizeof(struct QuestLog));
gUnknown_203AE04 = NULL;
}
void sub_8110920(void)
{
gUnknown_203AE04 = NULL;
}
void RunQuestLogCB(void)
{
if (sQuestLogCB != NULL)
sQuestLogCB();
}
bool8 sub_8110944(const void *a0, size_t cmdSize)
{
void *r2 = gSaveBlock1Ptr->questLog[sCurrentSceneNum].script;
void *r0 = gSaveBlock1Ptr->questLog[sCurrentSceneNum].end;
r0 -= cmdSize;
if ((const void *)a0 < r2 || (const void *)a0 > r0)
return FALSE;
return TRUE;
}
bool8 WillCommandOfSizeFitInSav1Record(u16 *cursor, size_t size)
{
void *start = gSaveBlock1Ptr->questLog[sCurrentSceneNum].script;
void *end = gSaveBlock1Ptr->questLog[sCurrentSceneNum].end;
end -= size;
if ((void *)cursor < start || (void *)cursor > end)
return FALSE;
return TRUE;
}
static void SetQuestLogState(u8 state)
{
gQuestLogState = state;
if (state == QL_STATE_RECORDING)
sQuestLogCB = QLogCB_Recording;
else
sQuestLogCB = QLogCB_Playback;
}
static void QLogCB_Recording(void)
{
if (TryRecordQuestLogEntrySequence(sQuestLogSceneRecordBuffer) != 1)
{
gQuestLogPlaybackState = 0;
TryRecordEvent39_GoToNextScene();
gQuestLogState = 0;
sQuestLogCB = NULL;
}
}
static void QLogCB_Playback(void)
{
if (sQuestLogCurrentScene.playbackSubstate == 2)
sQuestLogCurrentScene.playbackSubstate = 0;
if (sQuestLogCurrentScene.sceneEndMode == 0)
{
if (gQuestLogPlaybackState != 0
|| sQuestLogCurrentScene.playbackSubstate == 1
|| (sQuestLogCurrentScene.cursor < NELEMS(gUnknown_203AE0C)
&& gUnknown_203AE0C[sQuestLogCurrentScene.cursor] != NULL))
QuestLog_PlayCurrentEvent();
else
{
sQuestLogCurrentScene.sceneEndMode = 2;
LockPlayerFieldControls();
QuestLog_BeginFadeAtEndOfScene(0);
}
}
}
void GetQuestLogState(void)
{
gSpecialVar_Result = gQuestLogState;
}
u8 GetQuestLogStartType(void)
{
return gSaveBlock1Ptr->questLog[sCurrentSceneNum].startType;
}
void StartRecordingQuestLogEntry(u16 eventId)
{
if (sCurrentSceneNum >= QUEST_LOG_SCENE_COUNT)
sCurrentSceneNum = 0;
DestroySav1QuestLogEntry(sCurrentSceneNum);
ResetUnk203B044();
sEventRecordingPointer = gSaveBlock1Ptr->questLog[sCurrentSceneNum].script;
if (IS_LINK_QL_EVENT(eventId) || eventId == QL_EVENT_DEPARTED)
gSaveBlock1Ptr->questLog[sCurrentSceneNum].startType = QL_START_WARP;
else
gSaveBlock1Ptr->questLog[sCurrentSceneNum].startType = QL_START_NORMAL;
QuestLog_GetSaneMonCounts();
SetPlayerInitialCoordsAtScene(sCurrentSceneNum);
SetNPCInitialCoordsAtScene(sCurrentSceneNum);
BackUpTrainerRematchesToVars();
BackUpMapLayoutToVar();
SetGameStateAtScene(sCurrentSceneNum);
gUnknown_203ADFC = 0;
SetUpQuestLogEntry(2, sQuestLogSceneRecordBuffer, 0x100);
TryRecordQuestLogEntrySequence(sQuestLogSceneRecordBuffer);
SetQuestLogState(QL_STATE_RECORDING);
}
static void SetPlayerInitialCoordsAtScene(u8 sceneNum)
{
struct QuestLog * questLog = &gSaveBlock1Ptr->questLog[sceneNum];
questLog->mapGroup = gSaveBlock1Ptr->location.mapGroup;
questLog->mapNum = gSaveBlock1Ptr->location.mapNum;
questLog->warpId = gSaveBlock1Ptr->location.warpId;
questLog->x = gSaveBlock1Ptr->pos.x;
questLog->y = gSaveBlock1Ptr->pos.y;
}
static void SetNPCInitialCoordsAtScene(u8 sceneNum)
{
struct QuestLog * questLog = &gSaveBlock1Ptr->questLog[sceneNum];
u16 i;
SetQuestLogObjectEventsData(questLog);
for (i = 0; i < NELEMS(gSaveBlock1Ptr->objectEventTemplates); i++)
{
if (gSaveBlock1Ptr->objectEventTemplates[i].x < 0)
{
questLog->npcData[i].x = -1 * gSaveBlock1Ptr->objectEventTemplates[i].x;
questLog->npcData[i].negx = TRUE;
}
else
{
questLog->npcData[i].x = (u8)gSaveBlock1Ptr->objectEventTemplates[i].x;
questLog->npcData[i].negx = FALSE;
}
if (gSaveBlock1Ptr->objectEventTemplates[i].y < 0)
{
questLog->npcData[i].y = (-gSaveBlock1Ptr->objectEventTemplates[i].y << 24) >> 24;
questLog->npcData[i].negy = TRUE;
}
else
{
questLog->npcData[i].y = (u8)gSaveBlock1Ptr->objectEventTemplates[i].y;
questLog->npcData[i].negy = FALSE;
}
questLog->npcData[i].elevation = gSaveBlock1Ptr->objectEventTemplates[i].elevation;
questLog->npcData[i].movementType = gSaveBlock1Ptr->objectEventTemplates[i].movementType;
}
}
static void SetGameStateAtScene(u8 sceneNum)
{
struct QuestLog * questLog = &gSaveBlock1Ptr->questLog[sceneNum];
CpuCopy16(gSaveBlock1Ptr->flags, questLog->flags, NUM_FLAG_BYTES * sizeof(u8));
CpuCopy16(gSaveBlock1Ptr->vars, questLog->vars, VARS_COUNT * sizeof(u16));
}
static void BackUpTrainerRematchesToVars(void)
{
u16 i, j;
u16 sp0[4];
for (i = 0; i < 4; i++)
{
sp0[i] = 0;
for (j = 0; j < 16; j++)
{
if (gSaveBlock1Ptr->trainerRematches[16 * i + j])
{
sp0[i] += (1 << j);
}
}
VarSet(VAR_QLBAK_TRAINER_REMATCHES + i, sp0[i]);
}
}
static void BackUpMapLayoutToVar(void)
{
VarSet(VAR_QLBAK_MAP_LAYOUT, gSaveBlock1Ptr->mapLayoutId);
}
static void TryRecordEvent39_GoToNextScene(void)
{
TryRecordEvent39_NoParams(sEventRecordingPointer);
if (++sCurrentSceneNum >= QUEST_LOG_SCENE_COUNT)
sCurrentSceneNum = 0;
}
static bool8 TryRecordQuestLogEntrySequence(struct QuestLogEntry * entry)
{
u16 i;
for (i = gUnknown_203ADFC; i < sQuestLogCursor; i++)
{
if (sEventRecordingPointer == NULL)
return FALSE;
switch (entry[i].command)
{
case 0:
case 1:
sEventRecordingPointer = sub_8113D48(sEventRecordingPointer, &entry[i]);
break;
default:
sEventRecordingPointer = sub_8113CC8(sEventRecordingPointer, &entry[i]);
break;
}
if (sEventRecordingPointer == NULL)
{
gQuestLogPlaybackState = 0;
return FALSE;
}
}
if (gQuestLogPlaybackState == 0)
{
sEventRecordingPointer = TryRecordEvent39_NoParams(sEventRecordingPointer);
return FALSE;
}
gUnknown_203ADFC = sQuestLogCursor;
return TRUE;
}
void TrySetUpQuestLogScenes_ElseContinueFromSave(u8 taskId)
{
u8 i;
QL_EnableRecordingSteps();
sNumScenes = 0;
for (i = 0; i < QUEST_LOG_SCENE_COUNT; i++)
{
if (gSaveBlock1Ptr->questLog[i].startType != 0)
sNumScenes++;
}
if (sNumScenes != 0)
{
gHelpSystemEnabled = FALSE;
Task_BeginQuestLogPlayback(taskId);
DestroyTask(taskId);
}
else
{
SetMainCallback2(CB2_ContinueSavedGame);
DestroyTask(taskId);
}
}
static void Task_BeginQuestLogPlayback(u8 taskId)
{
gSaveBlock1Ptr->location.mapGroup = MAP_GROUP(ROUTE1);
gSaveBlock1Ptr->location.mapNum = MAP_NUM(ROUTE1);
gSaveBlock1Ptr->location.warpId = -1;
sCurrentSceneNum = 0;
gDisableMapMusicChangeOnMapLoad = 1;
DisableWildEncounters(TRUE);
QLPlayback_InitOverworldState();
}
void sub_8110FCC(void)
{
ReadQuestLogScriptFromSav1(sCurrentSceneNum, sQuestLogSceneRecordBuffer);
ResetUnk203B044();
SetUpQuestLogEntry(1, sQuestLogSceneRecordBuffer, 0x100);
QuestLogPlaybackSetObjectEventTemplates(sCurrentSceneNum);
}
static bool8 FieldCB2_QuestLogStartPlaybackWithWarpExit(void)
{
LoadPalette(GetTextWindowPalette(4), 0xF0, 0x20);
SetQuestLogState(QL_STATE_PLAYBACK);
FieldCB_DefaultWarpExit();
sQuestLogCurrentScene = (struct UnkStruct_203AE94){};
sQuestLogCurrentScene.playbackSubstate = 2;
return 1;
}
static bool8 FieldCB2_QuestLogStartPlaybackStandingInPlace(void)
{
LoadPalette(GetTextWindowPalette(4), 0xF0, 0x20);
SetQuestLogState(QL_STATE_PLAYBACK);
FieldCB_WarpExitFadeFromBlack();
sQuestLogCurrentScene = (struct UnkStruct_203AE94){};
sQuestLogCurrentScene.playbackSubstate = 2;
return 1;
}
void DrawPreviouslyOnQuestHeader(u8 sceneNum)
{
u8 i;
for (i = 0; i < NELEMS(sQuestLogHeaderWindowTemplates); i++)
{
sQuestLogHeaderWindowIds[i] = AddWindow(&sQuestLogHeaderWindowTemplates[i]);
FillWindowPixelRect(sQuestLogHeaderWindowIds[i], 15, 0, 0, sQuestLogHeaderWindowTemplates[i].width * 8, sQuestLogHeaderWindowTemplates[i].height * 8);
}
StringExpandPlaceholders(gStringVar4, gText_QuestLog_PreviouslyOnYourQuest);
// Scene numbers count from 4 to 0, 0 being where the player saved
if (sceneNum != 0)
{
ConvertIntToDecimalStringN(gStringVar1, sceneNum, STR_CONV_MODE_LEFT_ALIGN, 1);
StringAppend(gStringVar4, gStringVar1);
}
AddTextPrinterParameterized4(sQuestLogHeaderWindowIds[0], FONT_2, 2, 2, 1, 2, sTextColors, 0, gStringVar4);
PutWindowTilemap(sQuestLogHeaderWindowIds[0]);
PutWindowTilemap(sQuestLogHeaderWindowIds[1]);
CopyWindowToVram(sQuestLogHeaderWindowIds[0], COPYWIN_GFX);
CopyWindowToVram(sQuestLogHeaderWindowIds[2], COPYWIN_GFX);
CopyWindowToVram(sQuestLogHeaderWindowIds[1], COPYWIN_FULL);
}
void CommitQuestLogWindow1(void)
{
PutWindowTilemap(sQuestLogHeaderWindowIds[1]);
CopyWindowToVram(sQuestLogHeaderWindowIds[1], COPYWIN_MAP);
}
static void QuestLogPlaybackSetObjectEventTemplates(u8 sceneNum)
{
struct QuestLog *questLog = &gSaveBlock1Ptr->questLog[sceneNum];
u16 i;
for (i = 0; i < 64; i++)
{
if (questLog->npcData[i].negx)
gSaveBlock1Ptr->objectEventTemplates[i].x = -questLog->npcData[i].x;
else
gSaveBlock1Ptr->objectEventTemplates[i].x = questLog->npcData[i].x;
if (questLog->npcData[i].negy)
gSaveBlock1Ptr->objectEventTemplates[i].y = -(u8)questLog->npcData[i].y;
else
gSaveBlock1Ptr->objectEventTemplates[i].y = questLog->npcData[i].y;
gSaveBlock1Ptr->objectEventTemplates[i].elevation = questLog->npcData[i].elevation;
gSaveBlock1Ptr->objectEventTemplates[i].movementType = questLog->npcData[i].movementType;
}
SetSav1ObjectEventsFromQuestLog(questLog, gSaveBlock1Ptr->objectEventTemplates);
}
static void QLPlayback_SetInitialPlayerPosition(u8 sceneNum, bool8 isWarp)
{
struct WarpData sp0;
if (!isWarp)
{
gSaveBlock1Ptr->location.mapGroup = gSaveBlock1Ptr->questLog[sceneNum].mapGroup;
gSaveBlock1Ptr->location.mapNum = gSaveBlock1Ptr->questLog[sceneNum].mapNum;
gSaveBlock1Ptr->location.warpId = gSaveBlock1Ptr->questLog[sceneNum].warpId;
gSaveBlock1Ptr->pos.x = gSaveBlock1Ptr->questLog[sceneNum].x;
gSaveBlock1Ptr->pos.y = gSaveBlock1Ptr->questLog[sceneNum].y;
}
else
{
sp0.mapGroup = gSaveBlock1Ptr->questLog[sceneNum].mapGroup;
sp0.mapNum = gSaveBlock1Ptr->questLog[sceneNum].mapNum;
sp0.warpId = gSaveBlock1Ptr->questLog[sceneNum].warpId;
sp0.x = gSaveBlock1Ptr->questLog[sceneNum].x;
sp0.y = gSaveBlock1Ptr->questLog[sceneNum].y;
Overworld_SetWarpDestinationFromWarp(&sp0);
}
}
static void QLPlayback_InitOverworldState(void)
{
gQuestLogState = QL_STATE_PLAYBACK;
ResetSpecialVars();
ClearBag();
ClearPCItemSlots();
if (GetQuestLogStartType() == QL_START_NORMAL)
{
QLPlayback_SetInitialPlayerPosition(sCurrentSceneNum, FALSE);
gFieldCallback2 = FieldCB2_QuestLogStartPlaybackStandingInPlace;
SetMainCallback2(CB2_SetUpOverworldForQLPlayback);
}
else
{
QLPlayback_SetInitialPlayerPosition(sCurrentSceneNum, TRUE);
WarpIntoMap();
gFieldCallback2 = FieldCB2_QuestLogStartPlaybackWithWarpExit;
SetMainCallback2(CB2_SetUpOverworldForQLPlaybackWithWarpExit);
}
}
void sub_81113E4(void)
{
struct QuestLog * questLog = &gSaveBlock1Ptr->questLog[sCurrentSceneNum];
CpuCopy16(questLog->flags, gSaveBlock1Ptr->flags, NUM_FLAG_BYTES * sizeof(u8));
CpuCopy16(questLog->vars, gSaveBlock1Ptr->vars, VARS_COUNT * sizeof(u16));
sub_8111688();
}
struct PokemonAndSomethingElse
{
struct Pokemon mon;
u16 sanePartyCount;
u16 saneBoxesCount;
};
void sub_8111438(void)
{
struct PokemonAndSomethingElse *r9 = AllocZeroed(sizeof(struct PokemonAndSomethingElse));
u16 r0, r3, r5, r6;
CreateMon(&r9->mon, SPECIES_RATTATA, 1, 0x20, FALSE, 0, 0, 0);
r0 = VarGet(VAR_QUEST_LOG_MON_COUNTS);
r9->sanePartyCount = r0 >> 12;
r9->saneBoxesCount = r0 % 0x1000;
r5 = QuestLog_GetSanePartyCount();
if (r5 > r9->sanePartyCount)
{
for (r3 = 0; r3 < r5 - r9->sanePartyCount; r3++)
{
ZeroMonData(&gPlayerParty[5 - r3]);
}
}
else if (r5 < r9->sanePartyCount)
{
for (r3 = 0; r3 < 5; r3++)
{
ZeroBoxMonAt(0, r3);
}
for (r3 = r5; r3 < r9->sanePartyCount; r3++)
{
CopyMon(&gPlayerParty[r3], &r9->mon, sizeof(struct Pokemon));
}
}
r5 = QuestLog_GetSaneBoxCount();
if (r5 > r9->saneBoxesCount)
{
for (r3 = 0; r3 < 14; r3++)
{
for (r6 = 0; r6 < 30; r6++)
{
if (GetBoxMonDataAt(r3, r6, MON_DATA_SANITY_HAS_SPECIES))
{
ZeroBoxMonAt(r3, r6);
r5--;
if (r5 == r9->saneBoxesCount)
break;
}
}
if (r5 == r9->saneBoxesCount)
break;
}
}
else if (r5 < r9->saneBoxesCount)
{
for (r3 = 0; r3 < TOTAL_BOXES_COUNT; r3++)
{
for (r6 = 0; r6 < IN_BOX_COUNT; r6++)
{
struct BoxPokemon * boxMon = GetBoxedMonPtr(r3, r6);
if (!GetBoxMonData(boxMon, MON_DATA_SANITY_HAS_SPECIES))
{
CopyMon(boxMon, &r9->mon.box, sizeof(struct BoxPokemon));
r5++;
if (r5 == r9->saneBoxesCount)
break;
}
}
if (r5 == r9->saneBoxesCount)
break;
}
}
Free(r9);
}
static void QuestLog_GetSaneMonCounts(void)
{
u16 partyCount = QuestLog_GetSanePartyCount();
u16 boxesCount = QuestLog_GetSaneBoxCount();
VarSet(VAR_QUEST_LOG_MON_COUNTS, (partyCount << 12) + boxesCount);
}
static u16 QuestLog_GetSanePartyCount(void)
{
u16 count = 0;
u16 i;
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SANITY_HAS_SPECIES))
count++;
}
return count;
}
static u16 QuestLog_GetSaneBoxCount(void)
{
u16 count = 0;
u16 i, j;
for (i = 0; i < TOTAL_BOXES_COUNT; i++)
{
for (j = 0; j < IN_BOX_COUNT; j++)
{
if (GetBoxMonDataAt(i, j, MON_DATA_SANITY_HAS_SPECIES))
count++;
}
}
return count;
}
static void sub_8111688(void)
{
u16 i, j;
u16 sp0[4];
for (i = 0; i < 4; i++)
{
sp0[i] = VarGet(VAR_QLBAK_TRAINER_REMATCHES + i);
for (j = 0; j < 16; j++)
{
if (sp0[i] & 1)
gSaveBlock1Ptr->trainerRematches[16 * i + j] = 30;
else
gSaveBlock1Ptr->trainerRematches[16 * i + j] = 0;
sp0[i] >>= 1;
}
}
}
void sub_8111708(void)
{
struct MapHeader sp0;
gSaveBlock1Ptr->mapLayoutId = VarGet(VAR_QLBAK_MAP_LAYOUT);
if (gSaveBlock1Ptr->mapLayoutId == 0)
{
sp0 = *Overworld_GetMapHeaderByGroupAndId(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum);
gSaveBlock1Ptr->mapLayoutId = sp0.mapLayoutId;
}
}
static void ReadQuestLogScriptFromSav1(u8 sceneNum, struct QuestLogEntry * a1)
{
u16 i;
u16 *r4;
u16 r6 = 0;
u16 r9 = 0;
memset(a1, 0, 32 * sizeof(struct QuestLogEntry));
for (i = 0; i < NELEMS(gUnknown_203AE0C); i++)
{
gUnknown_203AE0C[i] = NULL;
}
r4 = gSaveBlock1Ptr->questLog[sceneNum].script;
for (i = 0; i < 32; i++)
{
switch (r4[0] & 0xFFF)
{
case QL_EVENT_0:
r4 = sub_8113D08(r4, &a1[r6]);
r6++;
break;
case QL_EVENT_1:
case QL_EVENT_2:
r4 = sub_8113D94(r4, &a1[r6]);
r6++;
break;
case QL_EVENT_39:
r4 = sub_8113C20(r4, &a1[r6]);
r6++;
break;
case QL_EVENT_41:
r4 = sub_8113C8C(r4, &a1[r6]);
r6++;
break;
default:
r4 = QuestLog_SkipCommand(r4, &gUnknown_203AE0C[r9]);
if (r9 == 0)
sub_8113ABC(gUnknown_203AE0C[0]);
r9++;
break;
}
if (r4 == NULL)
break;
}
}
static void QuestLog_BeginFadeAtEndOfScene(s8 delay)
{
FadeScreen(FADE_TO_BLACK, delay);
sQuestLogCB = QuestLog_AdvancePlayhead;
}
static void QuestLog_AdvancePlayhead(void)
{
if (!gPaletteFade.active)
{
LockPlayerFieldControls();
if (++sCurrentSceneNum < QUEST_LOG_SCENE_COUNT && gSaveBlock1Ptr->questLog[sCurrentSceneNum].startType != 0)
{
sNumScenes--;
QLPlayback_InitOverworldState();
}
else
{
gQuestLogPlaybackState = 0;
QuestLog_StartFinalScene();
}
}
}
static void QuestLog_StartFinalScene(void)
{
ResetSpecialVars();
Save_ResetSaveCounters();
LoadGameSave(SAVE_NORMAL);
SetMainCallback2(CB2_EnterFieldFromQuestLog);
gFieldCallback2 = FieldCB2_FinalScene;
FreeAllWindowBuffers();
gQuestLogState = QL_STATE_PLAYBACK_LAST;
sQuestLogCB = NULL;
}
void QuestLog_AdvancePlayhead_(void)
{
QuestLog_AdvancePlayhead();
}
bool8 QuestLog_SchedulePlaybackCB(void (*callback)(void))
{
u8 taskId;
switch (gQuestLogState)
{
case QL_STATE_RECORDING:
QuestLog_CutRecording();
break;
case QL_STATE_PLAYBACK:
gQuestLogPlaybackState = 3;
taskId = CreateTask(Task_RunPlaybackCB, 80);
gTasks[taskId].data[0] = 0;
gTasks[taskId].data[1] = 0;
SetWordTaskArg(taskId, 14, (uintptr_t)callback);
return TRUE;
}
return FALSE;
}
static void Task_RunPlaybackCB(u8 taskId)
{
void (*routine)(void);
s16 *data = gTasks[taskId].data;
switch (data[1])
{
case 0:
if (++data[0] == 0x7F)
{
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, 0);
sQuestLogCurrentScene.sceneEndMode = 2;
data[1]++;
}
break;
case 1:
if (!gPaletteFade.active)
{
gQuestLogPlaybackState = 0;
routine = (void (*)(void)) GetWordTaskArg(taskId, 14);
if (routine != NULL)
routine();
DestroyTask(taskId);
sQuestLogCB = QuestLog_AdvancePlayhead;
}
break;
}
}
static void QuestLog_PlayCurrentEvent(void)
{
if (sQuestLogCurrentScene.playbackSubstate == 1)
{
if (--sQuestLogCurrentScene.timer != 0)
return;
sQuestLogCurrentScene.playbackSubstate = 0;
sQuestLogCurrentScene.playingEvent = 1;
TogglePlaybackStateForOverworldLock(2);
}
if (sQuestLogCurrentScene.playingEvent == 1)
{
if (++sQuestLogCurrentScene.overlapTimer > 15)
{
QuestLog_CloseTextWindow();
sQuestLogCurrentScene.playingEvent = 0;
sQuestLogCurrentScene.overlapTimer = 0;
}
}
if (sQuestLogCurrentScene.cursor < NELEMS(gUnknown_203AE0C))
{
if (sub_8113B44(gUnknown_203AE0C[sQuestLogCurrentScene.cursor]) == 1)
HandleShowQuestLogMessage();
else if (sub_8113AE8(gUnknown_203AE0C[sQuestLogCurrentScene.cursor]) == 1)
HandleShowQuestLogMessage();
}
}
static void HandleShowQuestLogMessage(void)
{
if (sQuestLogCurrentScene.playbackSubstate == 0)
{
sQuestLogCurrentScene.playbackSubstate = 1;
sQuestLogCurrentScene.playingEvent = 0;
sQuestLogCurrentScene.overlapTimer = 0;
sQuestLogCurrentScene.timer = GetQuestLogTextDisplayDuration();
if (gUnknown_203B044.unk_2 == 0)
sQuestLogCurrentScene.cursor++;
if (sQuestLogCurrentScene.cursor > 32)
return;
DrawQuestLogSceneDescription();
}
TogglePlaybackStateForOverworldLock(1); // lock
}
static u8 GetQuestLogTextDisplayDuration(void)
{
u16 i;
u16 count = 0;
for (i = 0; i < 0x400 && gStringVar4[i] != EOS; i++)
{
if (gStringVar4[i] != CHAR_NEWLINE)
count++;
}
if (count < 20)
return 0x5F;
if (count < 36)
return 0x7F;
if (count < 46)
return 0xBF;
return 0xFF;
}
bool8 sub_8111C2C(void)
{
if (gQuestLogState != QL_STATE_PLAYBACK)
return FALSE;
if (gQuestLogPlaybackState == 0 || sQuestLogCurrentScene.playbackSubstate == 1 || sQuestLogCurrentScene.playbackSubstate == 2)
return TRUE;
return FALSE;
}
void sub_8111C68(void)
{
if (sQuestLogCurrentScene.sceneEndMode == 0)
{
if (JOY_NEW(A_BUTTON))
{
sQuestLogCurrentScene.sceneEndMode = 2;
gQuestLogPlaybackState = 0;
QuestLog_BeginFadeAtEndOfScene(-3);
}
else if (JOY_NEW(B_BUTTON))
{
sQuestLogCurrentScene.sceneEndMode = 1;
gQuestLogPlaybackState = 0;
QuestLog_SkipToEndOfPlayback(-3);
}
}
}
bool8 QuestLogScenePlaybackIsEnding(void)
{
if (sQuestLogCurrentScene.sceneEndMode != 0)
return TRUE;
return FALSE;
}
void QuestLog_DrawPreviouslyOnQuestHeaderIfInPlaybackMode(void)
{
if (gQuestLogState == QL_STATE_PLAYBACK)
DrawPreviouslyOnQuestHeader(sNumScenes);
}
static void DrawQuestLogSceneDescription(void)
{
u16 i;
u8 numLines = 0;
for (i = 0; i < 0x100 && gStringVar4[i] != EOS; i++)
{
if (gStringVar4[i] == CHAR_NEWLINE)
numLines++;
}
PutWindowTilemap(sQuestLogHeaderWindowIds[2]);
sub_8111D90(sQuestLogHeaderWindowIds[2]);
AddTextPrinterParameterized4(sQuestLogHeaderWindowIds[2], FONT_2, 2, sQuestLogTextLineYCoords[numLines], 1, 0, sTextColors, 0, gStringVar4);
ScheduleBgCopyTilemapToVram(0);
}
static void sub_8111D90(u8 a0)
{
const u16 *src = sUnknown_8456638;
u16 *buffer = Alloc(0x1680);
u8 i, j, y;
if (buffer)
{
for (i = 0; i < 6; i++)
{
switch (i)
{
default:
y = 1;
break;
case 0:
y = 0;
break;
case 5:
y = 2;
break;
}
// r6 = y * 32
// r5 = 2 * (i % 16)
// r4 = j
for (j = 0; j < 30; j++)
{
CpuCopy32(src + 16 * y, buffer + 16 * (2 * (15 * i) + j), 32);
}
}
CopyToWindowPixelBuffer(a0, (const u8 *)buffer, 0x1680, 0);
Free(buffer);
}
}
static void QuestLog_CloseTextWindow(void)
{
ClearWindowTilemap(sQuestLogHeaderWindowIds[2]);
FillWindowPixelRect(sQuestLogHeaderWindowIds[2], 15, 0, 0, 0xf0, 0x30);
CopyWindowToVram(sQuestLogHeaderWindowIds[2], COPYWIN_GFX);
PutWindowTilemap(sQuestLogHeaderWindowIds[1]);
CopyWindowToVram(sQuestLogHeaderWindowIds[1], COPYWIN_MAP);
}
static void QuestLog_SkipToEndOfPlayback(s8 delay)
{
FadeScreen(FADE_TO_BLACK, delay);
sQuestLogCB = QuestLog_WaitFadeAndCancelPlayback;
}
static void QuestLog_WaitFadeAndCancelPlayback(void)
{
if (!gPaletteFade.active)
{
LockPlayerFieldControls();
for (sCurrentSceneNum = sCurrentSceneNum; sCurrentSceneNum < QUEST_LOG_SCENE_COUNT; sCurrentSceneNum++)
{
if (gSaveBlock1Ptr->questLog[sCurrentSceneNum].startType == 0)
break;
ReadQuestLogScriptFromSav1(sCurrentSceneNum, sQuestLogSceneRecordBuffer);
}
gQuestLogPlaybackState = 0;
QuestLog_StartFinalScene();
}
}
void QuestLog_InitPalettesBackup(void)
{
if (gQuestLogState == QL_STATE_PLAYBACK_LAST)
sPalettesBackup = AllocZeroed(PLTT_SIZE);
}
void QuestLog_BackUpPalette(u16 offset, u16 size)
{
CpuCopy16(gPlttBufferUnfaded + offset, sPalettesBackup + offset, size * 2);
}
static bool8 FieldCB2_FinalScene(void)
{
LoadPalette(GetTextWindowPalette(4), 0xF0, 0x20);
DrawPreviouslyOnQuestHeader(0);
FieldCB_WarpExitFadeFromBlack();
CreateTask(Task_FinalScene_WaitFade, 0xFF);
return TRUE;
}
static void Task_FinalScene_WaitFade(u8 taskId)
{
struct Task *task = &gTasks[taskId];
if (ArePlayerFieldControlsLocked() != TRUE)
{
FreezeObjectEvents();
HandleEnforcedLookDirectionOnPlayerStopMoving();
StopPlayerAvatar();
LockPlayerFieldControls();
task->func = Task_QuestLogScene_SavedGame;
}
}
static void Task_QuestLogScene_SavedGame(u8 taskId)
{
struct Task *task = &gTasks[taskId];
if (!gPaletteFade.active)
{
if (sQuestLogCurrentScene.sceneEndMode != 1)
{
GetMapNameGeneric(gStringVar1, gMapHeader.regionMapSectionId);
StringExpandPlaceholders(gStringVar4, gText_QuestLog_SavedGameAtLocation);
DrawQuestLogSceneDescription();
}
task->data[0] = 0;
task->data[1] = 0;
task->func = Task_WaitAtEndOfQuestLog;
FreezeObjectEvents();
LockPlayerFieldControls();
}
}
#define tTimer data[0]
static void Task_WaitAtEndOfQuestLog(u8 taskId)
{
struct Task *task = &gTasks[taskId];
if (JOY_NEW(A_BUTTON | B_BUTTON) || task->tTimer >= 127 || sQuestLogCurrentScene.sceneEndMode == 1)
{
QuestLog_CloseTextWindow();
task->tTimer = 0;
task->func = Task_EndQuestLog;
gQuestLogState = 0;
}
else
task->tTimer++;
}
#undef tTimer
#define tState data[0]
#define tTimer data[1]
static void Task_EndQuestLog(u8 taskId)
{
s16 *data = gTasks[taskId].data;
u8 i;
switch (tState)
{
case 0:
gDisableMapMusicChangeOnMapLoad = 0;
Overworld_PlaySpecialMapMusic();
QL_SlightlyDarkenSomePals();
FillWindowPixelRect(sQuestLogHeaderWindowIds[0], 0xF, 0, 0, sQuestLogHeaderWindowTemplates[0].width * 8, sQuestLogHeaderWindowTemplates[0].height * 8);
tState++;
break;
case 1:
if (sub_81121D8(taskId))
{
for (i = 0; i < 3; i++)
{
ClearWindowTilemap(sQuestLogHeaderWindowIds[i]);
CopyWindowToVram(sQuestLogHeaderWindowIds[i], COPYWIN_MAP);
RemoveWindow(sQuestLogHeaderWindowIds[i]);
}
tTimer = 0;
tState++;
}
break;
case 2:
if (tTimer < 32)
tTimer++;
else
tState++;
break;
default:
if (sQuestLogCurrentScene.sceneEndMode == 1)
ShowMapNamePopup(TRUE);
CpuCopy16(sPalettesBackup, gPlttBufferUnfaded, PLTT_SIZE);
Free(sPalettesBackup);
sQuestLogCurrentScene = (struct UnkStruct_203AE94){};
ClearPlayerHeldMovementAndUnfreezeObjectEvents();
UnlockPlayerFieldControls();
gTextFlags.autoScroll = FALSE;
gGlobalFieldTintMode = QL_TINT_NONE;
DisableWildEncounters(FALSE);
gHelpSystemEnabled = TRUE;
DestroyTask(taskId);
break;
}
}
#undef tState
#undef tTimer
static bool8 sub_81121D8(u8 taskId)
{
s16 *data = gTasks[taskId].data;
if (data[1] > 15)
return TRUE;
CopyPaletteInvertedTint(gPlttBufferUnfaded + 0x01, gPlttBufferFaded + 0x01, 0xDF, 0x0F - data[1]);
CopyPaletteInvertedTint(gPlttBufferUnfaded + 0x100, gPlttBufferFaded + 0x100, 0x100, 0x0F - data[1]);
FillWindowPixelRect(sQuestLogHeaderWindowIds[0], 0x00, 0, sQuestLogHeaderWindowTemplates[0].height * 8 - 1 - data[1], sQuestLogHeaderWindowTemplates[0].width * 8, 1);
FillWindowPixelRect(sQuestLogHeaderWindowIds[1], 0x00, 0, data[1], sQuestLogHeaderWindowTemplates[1].width * 8, 1);
CopyWindowToVram(sQuestLogHeaderWindowIds[0], COPYWIN_GFX);
CopyWindowToVram(sQuestLogHeaderWindowIds[1], COPYWIN_GFX);
data[1]++;
return FALSE;
}
static void QL_SlightlyDarkenSomePals(void)
{
u16 *buffer = Alloc(PLTT_SIZE);
CpuCopy16(sPalettesBackup, buffer, PLTT_SIZE);
SlightlyDarkenPalsInWeather(sPalettesBackup, sPalettesBackup, 13 * 16);
SlightlyDarkenPalsInWeather(sPalettesBackup + 17 * 16, sPalettesBackup + 17 * 16, 1 * 16);
SlightlyDarkenPalsInWeather(sPalettesBackup + 22 * 16, sPalettesBackup + 22 * 16, 4 * 16);
SlightlyDarkenPalsInWeather(sPalettesBackup + 27 * 16, sPalettesBackup + 27 * 16, 5 * 16);
CpuCopy16(sPalettesBackup, gPlttBufferUnfaded, PLTT_SIZE);
CpuCopy16(buffer, sPalettesBackup, PLTT_SIZE);
Free(buffer);
}
void FinishRecordingQuestLogScene(void)
{
if (gQuestLogState == QL_STATE_RECORDING)
{
TryRecordQuestLogEntrySequence(sQuestLogSceneRecordBuffer);
TryRecordEvent39_GoToNextScene();
gQuestLogState = 0;
sQuestLogCB = NULL;
gUnknown_203AE04 = NULL;
sEventRecordingPointer = NULL;
gQuestLogPlaybackState = 0;
}
}
void QuestLog_CutRecording(void)
{
if (gQuestLogPlaybackState != 0 && gQuestLogState == QL_STATE_RECORDING)
{
TryRecordQuestLogEntrySequence(sQuestLogSceneRecordBuffer);
TryRecordEvent41_IncCursor(1);
TryRecordEvent39_GoToNextScene();
gQuestLogPlaybackState = 0;
gQuestLogState = 0;
sQuestLogCB = NULL;
}
gUnknown_203AE04 = NULL;
sEventRecordingPointer = NULL;
}
static void SortQuestLogInSav1(void)
{
struct QuestLog * buffer = AllocZeroed(QUEST_LOG_SCENE_COUNT * sizeof(struct QuestLog));
u8 i;
u8 sceneNum = sCurrentSceneNum;
u8 count = 0;
for (i = 0; i < QUEST_LOG_SCENE_COUNT; i++)
{
if (sceneNum >= QUEST_LOG_SCENE_COUNT)
sceneNum = 0;
if (gSaveBlock1Ptr->questLog[sceneNum].startType != 0)
{
buffer[count] = gSaveBlock1Ptr->questLog[sceneNum];
count++;
}
sceneNum++;
}
sCurrentSceneNum = count % QUEST_LOG_SCENE_COUNT;
CpuCopy16(buffer, gSaveBlock1Ptr->questLog, QUEST_LOG_SCENE_COUNT * sizeof(struct QuestLog));
Free(buffer);
}
void SaveQuestLogData(void)
{
if (MenuHelpers_LinkSomething() != TRUE)
{
QuestLog_CutRecording();
SortQuestLogInSav1();
}
}
void sub_811246C(struct Sprite *sprite)
{
struct ObjectEvent *objectEvent = &gObjectEvents[sprite->data[0]];
if (objectEvent->localId == OBJ_EVENT_ID_PLAYER)
{
if (sMovementScripts[0][0] != 0xFF)
{
ObjectEventSetHeldMovement(objectEvent, sMovementScripts[0][0]);
sMovementScripts[0][0] = 0xFF;
}
if (sMovementScripts[0][1] != 0xFF)
{
QuestLogUpdatePlayerSprite(sMovementScripts[0][1]);
sMovementScripts[0][1] = 0xFF;
}
sub_8063E28(objectEvent, sprite);
}
else
{
if (sMovementScripts[objectEvent->localId][0] != 0xFF)
{
ObjectEventSetHeldMovement(objectEvent, sMovementScripts[objectEvent->localId][0]);
sMovementScripts[objectEvent->localId][0] = 0xFF;
}
sub_8063E28(objectEvent, sprite);
}
}
void QuestLogRecordNPCStep(u8 localId, u8 mapNum, u8 mapGroup, u8 movementActionId)
{
if (!RecordHeadAtEndOfEntryOrScriptContext2Enabled())
{
sCurQuestLogEntry[sQuestLogCursor].duration = sNextStepDelay;
sCurQuestLogEntry[sQuestLogCursor].command = 0;
sCurQuestLogEntry[sQuestLogCursor].localId = localId;
sCurQuestLogEntry[sQuestLogCursor].mapNum = mapNum;
sCurQuestLogEntry[sQuestLogCursor].mapGroup = mapGroup;
sCurQuestLogEntry[sQuestLogCursor].animId = movementActionId;
sQuestLogCursor++;
sNextStepDelay = 0;
}
}
void QuestLogRecordNPCStepWithDuration(u8 localId, u8 mapNum, u8 mapGroup, u8 movementActionId, u8 duration)
{
if (!RecordHeadAtEndOfEntry())
{
sCurQuestLogEntry[sQuestLogCursor].duration = sNextStepDelay;
sCurQuestLogEntry[sQuestLogCursor].command = 0;
sCurQuestLogEntry[sQuestLogCursor].localId = localId;
sCurQuestLogEntry[sQuestLogCursor].mapNum = mapNum;
sCurQuestLogEntry[sQuestLogCursor].mapGroup = mapGroup;
sCurQuestLogEntry[sQuestLogCursor].animId = movementActionId;
sQuestLogCursor++;
sNextStepDelay = duration;
}
}
void QuestLogRecordPlayerStep(u8 movementActionId)
{
if (!RecordHeadAtEndOfEntryOrScriptContext2Enabled())
{
if (movementActionId != sCurQuestLogEntry[sLastQuestLogCursor].animId || movementActionId > MOVEMENT_ACTION_FACE_RIGHT)
{
sCurQuestLogEntry[sQuestLogCursor].duration = sNextStepDelay;
sCurQuestLogEntry[sQuestLogCursor].command = 0;
sCurQuestLogEntry[sQuestLogCursor].localId = 0;
sCurQuestLogEntry[sQuestLogCursor].animId = movementActionId;
sLastQuestLogCursor = sQuestLogCursor;
sQuestLogCursor++;
sNextStepDelay = 0;
}
}
}
void QuestLogRecordPlayerStepWithDuration(u8 movementActionId, u8 duration)
{
if (!RecordHeadAtEndOfEntry())
{
sCurQuestLogEntry[sQuestLogCursor].duration = sNextStepDelay;
sCurQuestLogEntry[sQuestLogCursor].command = 0;
sCurQuestLogEntry[sQuestLogCursor].localId = 0;
sCurQuestLogEntry[sQuestLogCursor].animId = movementActionId;
sLastQuestLogCursor = sQuestLogCursor;
sQuestLogCursor++;
sNextStepDelay = duration;
}
}
void QuestLogRecordPlayerAvatarGfxTransition(u8 movementActionId)
{
if (!RecordHeadAtEndOfEntry())
{
sCurQuestLogEntry[sQuestLogCursor].duration = sNextStepDelay;
sCurQuestLogEntry[sQuestLogCursor].command = 1;
sCurQuestLogEntry[sQuestLogCursor].localId = 0;
sCurQuestLogEntry[sQuestLogCursor].animId = movementActionId;
sQuestLogCursor++;
sNextStepDelay = 0;
}
}
void QuestLogRecordPlayerAvatarGfxTransitionWithDuration(u8 movementActionId, u8 duration)
{
if (!RecordHeadAtEndOfEntry())
{
sCurQuestLogEntry[sQuestLogCursor].duration = sNextStepDelay;
sCurQuestLogEntry[sQuestLogCursor].command = 1;
sCurQuestLogEntry[sQuestLogCursor].localId = 0;
sCurQuestLogEntry[sQuestLogCursor].animId = movementActionId;
sQuestLogCursor++;
sNextStepDelay = duration;
}
}
void sub_81127F8(struct FieldInput * a0)
{
if (sQuestLogCursor < sNumEventsInLogEntry)
{
// Retain only the following fields:
// - pressedAButton
// - checkStandardWildEncounter
// - heldDirection
// - heldDirection2
// - tookStep
// - pressedBButton
// - dpadDirection
u32 r2 = *(u32 *)a0 & 0x00FF00F3;
sCurQuestLogEntry[sQuestLogCursor].duration = sNextStepDelay;
sCurQuestLogEntry[sQuestLogCursor].command = 2;
sCurQuestLogEntry[sQuestLogCursor].localId = r2;
sCurQuestLogEntry[sQuestLogCursor].mapNum = r2 >> 8; // always 0
sCurQuestLogEntry[sQuestLogCursor].mapGroup = r2 >> 16;
sCurQuestLogEntry[sQuestLogCursor].animId = r2 >> 24; // always 0
sQuestLogCursor++;
if (ArePlayerFieldControlsLocked())
sNextStepDelay = TRUE;
else
sNextStepDelay = FALSE;
}
}
static void TogglePlaybackStateForOverworldLock(u8 a0)
{
switch (a0)
{
case 1:
if (gQuestLogPlaybackState == 1)
gQuestLogPlaybackState = 3; // Message visible, overworld locked
break;
case 2:
if (gQuestLogPlaybackState == 3)
gQuestLogPlaybackState = 1; // Overworld unlocked
break;
}
}
void QuestLog_OnEscalatorWarp(u8 direction)
{
u8 r1 = sub_8112CAC();
switch (direction)
{
case QL_ESCALATOR_OUT: // warp out
if (r1 == 1)
gQuestLogPlaybackState = 3;
else if (r1 == 2)
{
sCurQuestLogEntry[sQuestLogCursor].duration = sNextStepDelay;
sCurQuestLogEntry[sQuestLogCursor].command = 3;
sQuestLogCursor++;
sNextStepDelay = 0;
gQuestLogPlaybackState = 4;
}
break;
case QL_ESCALATOR_IN: // warp in
if (r1 == 1)
gQuestLogPlaybackState = 1;
else if (r1 == 2)
gQuestLogPlaybackState = 2;
break;
}
}
static void SetUpQuestLogEntry(u8 kind, struct QuestLogEntry *entry, u16 size)
{
int i;
switch (kind)
{
default:
gQuestLogPlaybackState = 0;
break;
case 1:
sCurQuestLogEntry = entry;
sNumEventsInLogEntry = size / sizeof(*sCurQuestLogEntry);
for (i = 0; i < (s32)NELEMS(sMovementScripts); i++)
{
sMovementScripts[i][0] |= 0xFF;
sMovementScripts[i][1] |= 0xFF;
}
sQuestLogCursor = 0;
sLastQuestLogCursor = 0;
gQuestLogFieldInput = (struct FieldInput){};
sNextStepDelay = sCurQuestLogEntry[sQuestLogCursor].duration;
sMovementScripts[0][0] = sCurQuestLogEntry[sQuestLogCursor].animId;
sMovementScripts[0][1] = 0xFF;
gQuestLogPlaybackState = 1;
break;
case 2:
sCurQuestLogEntry = entry;
sNumEventsInLogEntry = size / sizeof(*sCurQuestLogEntry);
for (i = 0; i < sNumEventsInLogEntry; i++)
{
sCurQuestLogEntry[i] = (struct QuestLogEntry){ 0, 0, 0, 0, 0xFFFF, 0xFF };
}
sQuestLogCursor = 0;
sNextStepDelay = 0;
sCurQuestLogEntry[sQuestLogCursor].duration = 0;
sCurQuestLogEntry[sQuestLogCursor].command = 0;
sCurQuestLogEntry[sQuestLogCursor].localId = 0;
switch (GetPlayerFacingDirection())
{
case DIR_NONE:
case DIR_SOUTH:
sCurQuestLogEntry[sQuestLogCursor].animId = MOVEMENT_ACTION_FACE_DOWN;
break;
case DIR_EAST:
sCurQuestLogEntry[sQuestLogCursor].animId = MOVEMENT_ACTION_FACE_RIGHT;
break;
case DIR_NORTH:
sCurQuestLogEntry[sQuestLogCursor].animId = MOVEMENT_ACTION_FACE_UP;
break;
case DIR_WEST:
sCurQuestLogEntry[sQuestLogCursor].animId = MOVEMENT_ACTION_FACE_LEFT;
break;
}
sLastQuestLogCursor = 0;
sQuestLogCursor++;
sCurQuestLogEntry[sQuestLogCursor].duration = 0;
sCurQuestLogEntry[sQuestLogCursor].command = 2;
sCurQuestLogEntry[sQuestLogCursor].localId = 0;
sCurQuestLogEntry[sQuestLogCursor].mapNum = 0;
sCurQuestLogEntry[sQuestLogCursor].mapGroup = 0;
sCurQuestLogEntry[sQuestLogCursor].animId = 0;
sQuestLogCursor++;
gQuestLogPlaybackState = 2;
break;
}
}
void sub_8112B3C(void)
{
switch (gQuestLogPlaybackState)
{
case 0:
break;
case 1:
if (!RecordHeadAtEndOfEntryOrScriptContext2Enabled())
{
if (sNextStepDelay != 0)
sNextStepDelay--;
else
{
do
{
switch (sCurQuestLogEntry[sQuestLogCursor].command)
{
case 0:
// NPC movement action
sMovementScripts[sCurQuestLogEntry[sQuestLogCursor].localId][0] = sCurQuestLogEntry[sQuestLogCursor].animId;
break;
case 1:
// State transition
sMovementScripts[sCurQuestLogEntry[sQuestLogCursor].localId][1] = sCurQuestLogEntry[sQuestLogCursor].animId;
break;
case 2:
// Player input command
*(u32 *)&gQuestLogFieldInput = ((sCurQuestLogEntry[sQuestLogCursor].animId << 24) | (sCurQuestLogEntry[sQuestLogCursor].mapGroup << 16) | (sCurQuestLogEntry[sQuestLogCursor].mapNum << 8) | (sCurQuestLogEntry[sQuestLogCursor].localId << 0));
break;
case 3:
// End
gQuestLogPlaybackState = 3;
break;
case 0xFE:
break;
case 0xFF:
gQuestLogPlaybackState = 0;
break;
}
if (gQuestLogPlaybackState == 0)
break;
if (++sQuestLogCursor >= sNumEventsInLogEntry)
{
gQuestLogPlaybackState = 0;
break;
}
sNextStepDelay = sCurQuestLogEntry[sQuestLogCursor].duration;
} while (gQuestLogPlaybackState != 3
&& (sNextStepDelay == 0 || sNextStepDelay == 0xFFFF));
}
}
else if (sQuestLogCursor >= sNumEventsInLogEntry)
{
gQuestLogPlaybackState = 0;
}
break;
case 2:
if (ArePlayerFieldControlsLocked() != TRUE)
{
sNextStepDelay++;
if (sQuestLogCursor >= sNumEventsInLogEntry)
gQuestLogPlaybackState = 0;
}
break;
case 3:
break;
case 4:
break;
}
}
void QL_AfterRecordFishActionSuccessful(void)
{
sNextStepDelay++;
}
u8 sub_8112CAC(void)
{
switch (gQuestLogPlaybackState)
{
case 0:
default:
return 0;
case 1:
case 3:
return 1;
case 2:
case 4:
return 2;
}
}
static bool8 RecordHeadAtEndOfEntryOrScriptContext2Enabled(void)
{
if (sQuestLogCursor >= sNumEventsInLogEntry || ArePlayerFieldControlsLocked() == TRUE)
return TRUE;
return FALSE;
}
static bool8 RecordHeadAtEndOfEntry(void)
{
if (sQuestLogCursor >= sNumEventsInLogEntry)
return TRUE;
return FALSE;
}
static const struct FlagOrVarRecord sDummyFlagOrVarRecord = {
0,
FALSE,
0x7FFF
};
void *QuestLogGetFlagOrVarPtr(bool8 isFlag, u16 idx)
{
void *response;
if (sQuestLogCursor == 0)
return NULL;
if (sQuestLogCursor >= sNumEventsInLogEntry)
return NULL;
if (sFlagOrVarPlayhead >= sNumFlagsOrVars)
return NULL;
if (sFlagOrVarRecords[sFlagOrVarPlayhead].idx == idx && sFlagOrVarRecords[sFlagOrVarPlayhead].isFlag == isFlag)
{
response = &sFlagOrVarRecords[sFlagOrVarPlayhead].value;
sFlagOrVarPlayhead++;
}
else
response = NULL;
return response;
}
void QuestLogSetFlagOrVar(bool8 isFlag, u16 idx, u16 value)
{
if (sQuestLogCursor == 0)
return;
if (sQuestLogCursor >= sNumEventsInLogEntry)
return;
if (sFlagOrVarPlayhead >= sNumFlagsOrVars)
return;
sFlagOrVarRecords[sFlagOrVarPlayhead].idx = idx;
sFlagOrVarRecords[sFlagOrVarPlayhead].isFlag = isFlag;
sFlagOrVarRecords[sFlagOrVarPlayhead].value = value;
sFlagOrVarPlayhead++;
}
void sub_8112E3C(u8 state, struct FlagOrVarRecord * records, u16 size)
{
s32 i;
if (state == 0 || state > QL_STATE_PLAYBACK)
gQuestLogPlaybackState = 0;
else
{
sFlagOrVarRecords = records;
sNumFlagsOrVars = size >> 2;
sFlagOrVarPlayhead = 0;
if (state == QL_STATE_PLAYBACK)
{
for (i = 0; i < sNumEventsInLogEntry; i++)
{
sFlagOrVarRecords[i] = sDummyFlagOrVarRecord;
}
}
}
}