/** * @file game.c * @ingroup Tasks * * @brief Game task */ #include "global.h" #include "asm.h" #include "sound.h" #include "screen.h" #include "entity.h" #include "player.h" #include "room.h" #include "main.h" #include "flags.h" #include "save.h" #include "common.h" #include "fileselect.h" #include "menu.h" #include "functions.h" #include "area.h" #include "message.h" #include "game.h" #include "item.h" #include "subtask.h" // Game task typedef void(GameState)(void); typedef void(GameMainState)(void); static GameState GameTask_Transition; static GameState GameTask_Init; static GameState GameTask_Exit; static GameState GameTask_Main; static GameMainState GameMain_InitRoom; static GameMainState GameMain_ChangeRoom; static GameMainState GameMain_Update; static GameMainState GameMain_ChangeArea; GameMainState GameMain_MinishPortal; static GameMainState GameMain_BarrelUpdate; /*static GameMainState 00000000;*/ GameMainState GameMain_Subtask; // Cutscene subtask typedef void(AuxCutsceneState)(void); typedef void(CutsceneMainState)(void); static AuxCutsceneState AuxCutscene_Init; static AuxCutsceneState AuxCutscene_Main; static AuxCutsceneState AuxCutscene_Exit; CutsceneMainState CutsceneMain_Init; CutsceneMainState CutsceneMain_Update; CutsceneMainState CutsceneMain_Exit; // Game Over task typedef void(GameOverState)(void); static GameOverState GameOver_Init; static GameOverState GameOver_FadeIn; static GameOverState GameOver_TextMove; static GameOverState GameOver_Update; static GameOverState GameOver_Exit; extern u8 gUpdateVisibleTiles; extern u16 gUnk_020178E0[]; extern u8 gUnk_02024090[]; extern void** gAreaTilesets[]; extern void** gAreaRoomMaps[]; extern void* gAreaMetatiles[]; extern void* gUnk_080B755C[]; extern void** gExitLists[]; extern void** gAreaTable[]; extern void CreateDialogBox(u32, u32); extern void FinalizeSave(void); extern void ClearArmosData(void); extern void ClearRoomMemory(void); extern void ClearMenuSavestate(void); extern void ResetUI(void); extern void sub_0806FD8C(void); extern void sub_080300C4(void); extern u32 sub_0805BC04(void); extern void DeleteSleepingEntities(void); extern u32 UpdateLightLevel(void); extern void sub_080185F8(void); extern void UpdateDoorTransition(void); extern u32 IsEnterPortal(void); extern void UpdateCarriedObject(void); extern void DrawUI(void); extern u32 CheckPlayerInactive(void); extern void CollisionMain(void); extern void sub_0805BB74(u32); extern void CreateZeldaFollower(void); extern void LoadRoomGfx(void); extern void RecycleEntities(void); extern void sub_0804AF90(void); extern void CallRoomProp6(void); extern void UpdateScroll(void); extern void UpdateBgAnim(void); extern void CleanUpGFXSlots(void); extern void sub_080ADE24(void); extern void InitUI(u32); extern void sub_0801AE44(u32); extern void GenerateAreaHint(void); extern void ForceSetPlayerState(u32); extern void UpdateRoomTracker(void); extern void InitScriptData(void); extern void sub_08054524(void); extern void sub_080186D4(void); extern void sub_0806F364(void); extern void sub_08052FF4(u32 area, u32 room); extern void sub_0807C860(void); extern void sub_0807C740(void); extern void SetBGDefaults(void); extern void LoadItemGfx(void); static void LoadRoomBgm(void); static void sub_08052010(void); static void ResetTmpFlags(void); static void InitializeEntities(void); static void CheckAreaDiscovery(void); static void CreateManagerF(void); static void UpdateWindcrests(void); static void UpdateFakeScroll(void); static void UpdatePlayerMapCoords(void); static void sub_08052C3C(void); static void sub_0805340C(void); static void sub_08051D98(void); static void sub_08051DCC(void); static u32 CheckGameOver(void); static u32 CheckRoomExit(void); static void UpdatePlayerRoomStatus(void); static void sub_0805329C(void); static void InitializePlayer(void); /* static */ void sub_08051F9C(u32 a1, u32 a2, u32 a3, u32 a4); static void DrawGameOverText(void); static u32 StairsAreValid(void); static void ClearFlagArray(const u16*); static void DummyHandler(u32* a1); static void sub_08053434(u32* a1); static void sub_080534E4(u32* a1); static void InitAllRoomResInfo(void); static void InitRoomResInfo(RoomResInfo* info, RoomHeader* hdr, u32 area, u32 room); static void sub_080532E4(void); static void sub_08053460(void); typedef struct { u8 _0; u8 _1; u8 _2; u8 _3; u8 _4; u16 _6; } struct_08127F94; extern struct_08127F94 gUnk_08127F94[]; typedef struct { u16* dest; void* gfx_dest; void* buffer_loc; u32 _c; u16 gfx_src; u8 width; u8 right_align : 1; u8 sm_border : 1; u8 unused : 1; u8 draw_border : 1; u8 border_type : 4; u8 fill_type; u8 _15; u8 _16; u8 stylized; } Font; typedef struct { u8 dest_off[8]; u8 _8; u8 right_align; u16 _a; } PopupOption; typedef struct { u8 area; u8 room; u8 _2; u8 _3; u16 x; u16 y; } CutsceneData; static const CutsceneData sCutsceneData[]; void GameTask(void) { static GameState* const sStates[] = { GameTask_Transition, GameTask_Init, GameTask_Main, GameTask_Exit, }; gRoomTransition.frameCount++; sStates[gMain.state](); #ifdef DEMO_USA if (gSave.demo_timer != 0) { if (--gSave.demo_timer == 0) { SetFade(7, 2); gMain.state = GAMETASK_EXIT; } } #endif } static void GameTask_Transition(void) { // wait for file select to fade out if (gFadeControl.active) return; DispReset(1); InitSoundPlayingInfo(); zMallocInit(); ResetUI(); ClearMenuSavestate(); MemClear(&gRoomTransition, sizeof(gRoomTransition)); ClearRoomMemory(); ClearArmosData(); FinalizeSave(); // spawn in with saved status MemCopy(&gSave.saved_status, &gRoomTransition.player_status, sizeof(gRoomTransition.player_status)); gRoomTransition.type = TRANSITION_FADE_BLACK_SLOW; ResetTmpFlags(); gMain.state = GAMETASK_INIT; gMain.substate = 0; } static void GameTask_Init(void) { DispReset(1); gFadeControl.mask = 0xffffffff; MemClear(&gOAMControls, 0xB74); MemClear(&gUnk_02032EC0, sizeof(gUnk_02032EC0)); EraseAllEntities(); SetBGDefaults(); ClearTilemaps(); ResetPalettes(); ResetPaletteTable(1); sub_0806FD8C(); gRoomControls.area = gRoomTransition.player_status.area_next; gRoomControls.room = gRoomTransition.player_status.room_next; LoadGfxGroups(); gGFXSlots.unk0 = 1; gMain.state = GAMETASK_MAIN; } static void GameTask_Main(void) { static GameMainState* const sStates[] = { GameMain_InitRoom, GameMain_ChangeRoom, GameMain_Update, GameMain_ChangeArea, GameMain_MinishPortal, GameMain_BarrelUpdate, 0, GameMain_Subtask, }; sStates[gMain.substate](); } static void GameMain_InitRoom(void) { SetInitializationPriority(); gScreen.lcd.displayControl = DISPCNT_BG0_ON | DISPCNT_BG1_ON | DISPCNT_BG2_ON | DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP; gMain.substate = GAMEMAIN_CHANGEROOM; gRoomTransition.transitioningOut = 0; gRoomTransition.field_0x4[0] = 0; gRoomTransition.field_0x4[1] = 0; MessageInitialize(); InitRoom(); InitUI(0); InitializeEntities(); #ifndef EU sub_0801855C(); #endif } static void GameMain_ChangeRoom(void) { UpdateEntities(); if (!UpdateLightLevel()) UpdateScroll(); UpdateBgAnim(); UpdateScrollVram(); DrawUI(); UpdateManagers(); FlushSprites(); DrawOAMCmd(); UpdateCarriedObject(); DrawEntities(); CopyOAM(); if (gFadeControl.active || gRoomControls.reload_flags != 0) return; UpdateFakeScroll(); if (gArea.bgm != gArea.queued_bgm) { gArea.bgm = gArea.queued_bgm; SoundReq(gArea.queued_bgm | SONG_PLAY_VOL_RESET); } DeleteSleepingEntities(); if (sub_0805BC04()) return; UpdatePlayerMapCoords(); ResetSystemPriority(); UpdateWindcrests(); sub_080300C4(); gMain.substate = GAMEMAIN_UPDATE; SetPlayerControl(0); gUnk_02034490.unk0 = 0; #if defined(USA) || defined(DEMO_USA) if (gArea.inventoryGfxIdx != 0xff) { sub_0801855C(); } CreateManagerF(); CheckAreaDiscovery(); #elif defined(EU) CheckAreaDiscovery(); sub_0801855C(); #elif defined(JP) CheckAreaDiscovery(); if (gArea.inventoryGfxIdx != 0xff) { sub_0801855C(); } #elif defined(DEMO_JP) if (gRoomTransition.field_0x2c[5]) CheckAreaDiscovery(); if (gArea.inventoryGfxIdx != 0xff) { sub_0801855C(); } CreateManagerF(); #endif if (!gRoomVars.field_0x0) { RequestPriorityDuration(NULL, 1); } } static void GameMain_Update(void) { if (CheckPlayerInactive() || IsEnterPortal()) { return; } sub_0805340C(); // leave early if player is now entering a portal if (gMain.substate != GAMEMAIN_UPDATE) { return; } if ((gMessage.doTextBox & 0x7f) || gPriorityHandler.priority_timer != 0) sub_08078B48(); FlushSprites(); UpdateEntities(); UpdateDoorTransition(); CollisionMain(); UpdateScroll(); UpdateBgAnim(); UpdateScrollVram(); sub_08052C3C(); DrawUI(); UpdateManagers(); DrawOAMCmd(); UpdateCarriedObject(); DrawEntities(); CheckRoomExit(); UpdatePlayerMapCoords(); CheckGameOver(); sub_080185F8(); CopyOAM(); switch (gRoomControls.reload_flags) { case RELOAD_ALL: gPlayerState.queued_action = PLAYER_ROOMTRANSITION; gMain.substate = GAMEMAIN_CHANGEROOM; SetRoomReloadPriority(); sub_08051D98(); break; case RELOAD_ENTITIES: gPlayerState.queued_action = PLAYER_ROOMTRANSITION; gMain.substate = GAMEMAIN_CHANGEROOM; SetRoomReloadPriority(); sub_08051DCC(); break; } } static void GameMain_BarrelUpdate(void) { if (CheckPlayerInactive()) return; UpdateEntities(); CollisionMain(); DrawUI(); UpdateManagers(); FlushSprites(); DrawOAMCmd(); UpdateCarriedObject(); DrawEntities(); CheckRoomExit(); CheckGameOver(); CopyOAM(); if (!gFadeControl.active) ResetSystemPriority(); } static void GameMain_ChangeArea(void) { FlushSprites(); DrawOAMCmd(); DrawEntities(); gMain.pad = 1; CopyOAM(); if (!gFadeControl.active) { DispReset(1); gMain.state = GAMETASK_INIT; gMain.substate = 0; gRoomTransition.transitioningOut = 1; } } static void GameTask_Exit(void) { #ifdef DEMO_USA if (!gFadeControl.active) DoSoftReset(); #else SetFade(7, 8); SetTask(TASK_GAMEOVER); #endif } static void InitializeEntities(void) { sub_08052EA0(); sub_0804AF90(); CallRoomProp6(); InitializePlayer(); gUnk_03004030.unk_00 = NULL; sub_0807C740(); gUpdateVisibleTiles = 1; LoadRoomBgm(); SetColor(0, 0); LoadRoom(); CreateZeldaFollower(); CallRoomProp5And7(); sub_0805329C(); UpdateScrollVram(); sub_0805BB74(0xffffffff); UpdatePlayerRoomStatus(); } static void sub_08051D98(void) { sub_08052EA0(); gRoomVars.field_0x0 = 1; // remove old entities, unless persistent RecycleEntities(); sub_0804AF90(); CallRoomProp6(); LoadRoomGfx(); LoadRoomBgm(); LoadRoom(); CallRoomProp5And7(); SetPlayerControl(1); } static void sub_08051DCC(void) { gRoomControls.area = gRoomTransition.player_status.area_next; gRoomControls.room = gRoomTransition.player_status.room_next; RoomExitCallback(); gRoomTransition.type = TRANSITION_3; InitRoom(); sub_08052EA0(); RecycleEntities(); sub_0804AF90(); CallRoomProp6(); LoadRoomBgm(); } static void UpdateWindcrests(void) { if (AreaIsOverworld()) { struct_08127F94* i; u32 hi_x, hi_y; s32 x, y; x = gPlayerEntity.x.HALF.HI; if (x < 0) x += 0xf; hi_x = x >> 4; y = gPlayerEntity.y.HALF.HI; if (y < 0) y += 0xf; hi_y = y >> 4; for (i = gUnk_08127F94; i->_0 != 0xFF; i++) { if (i->_0 <= hi_x && i->_2 >= hi_x && i->_1 <= hi_y && i->_3 >= hi_y) { gSave.windcrests |= 1 << i->_4; break; } } } } void Subtask_AuxCutscene(void) { static AuxCutsceneState* const sStates[] = { AuxCutscene_Init, AuxCutscene_Main, AuxCutscene_Exit, }; sStates[gMenu.menuType](); } static void AuxCutscene_Init(void) { const CutsceneData* p = &sCutsceneData[gUnk_02032EC0.field_0x3]; gRoomControls.area = p->area; gRoomControls.room = p->room; LoadGfxGroups(); gArea.localFlagOffset = GetFlagBankOffset(gRoomControls.area); SetCurrentRoomPropertyList(p->area, p->room); LoadAuxiliaryRoom(p->area, p->room); gRoomControls.scroll_x = gRoomControls.origin_x + p->x; gRoomControls.scroll_y = gRoomControls.origin_y + p->y; gMenu.field_0x0 = p->_2; gMenu.field_0x3 = p->_3 & 0xf; gMenu.field_0xc = (void*)p; gMenu.menuType++; gMenu.overlayType = 0; gMenu.transitionTimer = 300; AuxCutscene_Main(); // init } static void AuxCutscene_Main(void) { static CutsceneMainState* const sStates[] = { CutsceneMain_Init, CutsceneMain_Update, CutsceneMain_Exit, }; sStates[gMenu.field_0x0](); FlushSprites(); UpdateEntities(); DrawEntities(); CopyOAM(); UpdateScroll(); UpdateBgAnim(); UpdateManagers(); UpdateScrollVram(); } static const CutsceneData sCutsceneData[] = { { AREA_MINISH_WOODS, 0, 0, 0, 336, 528 }, { AREA_HYRULE_FIELD, 1, 1, 0, 472, 312 }, { AREA_HYRULE_CASTLE, 2, 1, 1, 16, 16 }, { AREA_SANCTUARY, 2, 1, 2, 0, 0 }, { AREA_EZLO_CUTSCENE, 0, 1, 3, 0, 0 }, { AREA_HOUSE_INTERIORS_2, 16, 1, 4, 0, 0 }, { AREA_DARK_HYRULE_CASTLE_OUTSIDE, 0, 1, 5, 0, 40 }, { AREA_FORTRESS_OF_WINDS, 28, 2, 0, 0, 0 }, { AREA_FORTRESS_OF_WINDS, 29, 2, 1, 0, 0 }, { AREA_DARK_HYRULE_CASTLE, 14, 2, 2, 16, 16 }, }; static void AuxCutscene_Exit(void) { u32 flag = sCutsceneData[gUnk_02032EC0.field_0x3]._3; if (flag & 0xF0) { MenuFadeIn(2, flag >> 4); } else { gUnk_02032EC0.nextToLoad = 3; SetFadeInverted(0x10); MessageInitialize(); } } void sub_08051F78(u32 a1, u32 a2, u32 a3, u32 a4) { u32 idx = gUnk_02032EC0.field_0x3; const CutsceneData* p = &sCutsceneData[idx]; sub_08051F9C(p->area, p->room, p->x, p->y); } void sub_08051F9C(u32 a1, u32 a2, u32 a3, u32 a4) { u32 tmp = gScreen.lcd.displayControl & (DISPCNT_WIN0_ON | DISPCNT_WIN1_ON); sub_08052FF4(a1, a2); gRoomControls.scroll_x = gRoomControls.origin_x + a3; gRoomControls.scroll_y = gRoomControls.origin_y + a4; sub_0807C740(); gUpdateVisibleTiles = 1; gUsedPalettes = 0; gScreen.lcd.displayControl |= tmp; } void sub_08051FF0(void) { sub_0804B0B0(gMenu.field_0xc[0], gMenu.field_0xc[1]); } void sub_08052004(void) { gMenu.menuType = 2; } static void sub_08052010(void) { InitSoundPlayingInfo(); MessageInitialize(); DispReset(1); MemClear(gBG1Buffer, 0x800); MemClear(gBG2Buffer, 0x800); sub_080A4D34(); LoadPaletteGroup(0xA); SetColor(0, 0); LoadGfxGroup(4); MemClear((void*)0x06000000, 0x20); MemClear(&gMenu, 0x30); gScreen.lcd.displayControl |= DISPCNT_OBJ_ON; gScreen.bg1.control = BGCNT_PRIORITY(1) | BGCNT_SCREENBASE(28) | BGCNT_CHARBASE(0); gScreen.bg2.control = BGCNT_PRIORITY(1) | BGCNT_SCREENBASE(29) | BGCNT_CHARBASE(1); gScreen.bg1.updated = 1; gScreen.bg2.updated = 1; } void GameOverTask(void) { static GameOverState* const sStates[] = { GameOver_Init, GameOver_FadeIn, GameOver_TextMove, GameOver_Update, GameOver_Exit, }; sStates[gMain.state](); if (gMain.state != 0) { FlushSprites(); DrawGameOverText(); CopyOAM(); } } static void switch_state(u32 idx) { gMain.state = idx; SetMenuType(0); } static void GameOver_Init(void) { if (gFadeControl.active) return; sub_08052010(); gGenericMenu.unk10.a[0] = 80; gMenu.transitionTimer = 60; gSave.stats.health = 24; gMain.field_0x5 = 60; SoundReq(BGM_GAMEOVER); SetFadeInverted(4); gFadeControl.mask = 0xFFFF0001; switch_state(1); } static void GameOver_FadeIn(void) { if (gFadeControl.active) return; if (gMain.field_0x5 == 0) { if (gGenericMenu.unk10.a[0] >= 38) { gGenericMenu.unk10.a[0]--; } else { gMenu.transitionTimer--; if (gMenu.transitionTimer == 0) { switch_state(2); #if defined(DEMO_USA) || defined(DEMO_JP) SoundReq(SONG_VOL_FADE_OUT); SetFade(7, 4); #else SetPopupState(0, 0); gScreen.lcd.displayControl |= DISPCNT_BG1_ON | DISPCNT_BG2_ON; gFadeControl.mask = 0x0000ffff; SetFade(4, 16); #endif } } } else { gMain.field_0x5--; } } static void GameOver_TextMove(void) { #if defined(DEMO_USA) || defined(DEMO_JP) if (gFadeControl.active == 0) { DoSoftReset(); } } #else s32 temp3; u32 temp2; if (gFadeControl.active) return; switch (gMenu.menuType) { case 0: gMenu.transitionTimer = 30; gMenu.field_0x3 = 0; SetMenuType(1); SetPopupState(0, 0); gFadeControl.mask = 0xffffffff; return; case 1: if (gMenu.transitionTimer == 0) { u32 temp = gMenu.field_0x3; switch (gInput.newKeys) { case DPAD_UP: temp = 0; break; case DPAD_DOWN: temp = 1; break; case A_BUTTON: if (gMenu.field_0x3 != 0) { temp2 = 4; } else { CreateDialogBox(8, 0); temp2 = 2; } gMenu.transitionTimer = 60; SetMenuType(temp2); SoundReq(SFX_TEXTBOX_SELECT); break; } if (gMenu.field_0x3 != temp) { gMenu.field_0x3 = temp; SetPopupState(0, temp); SoundReq(SFX_TEXTBOX_CHOICE); } return; } gMenu.transitionTimer--; return; case 2: temp3 = HandleSave(0); gMenu.field_0x0 = temp3; switch (temp3) { case 1: SetMenuType(4); break; case -1: gMenu.transitionTimer = 60; CreateDialogBox(9, 0); SetMenuType(3); break; } return; case 3: if (gMenu.transitionTimer != 0) { gMenu.transitionTimer--; } else if (gInput.newKeys & (A_BUTTON | B_BUTTON | START_BUTTON)) { SetMenuType(0); } return; case 4: default: gScreen.lcd.displayControl &= ~DISPCNT_BG1_ON; sub_08050384(); switch_state(3); return; } } #endif static void GameOver_Update(void) { switch (gMenu.menuType) { case 0x0: gMenu.transitionTimer = 0x1e; gMenu.field_0x3 = 0; SetMenuType(1); SetPopupState(1, 0); return; case 0x1: gScreen.lcd.displayControl |= DISPCNT_BG1_ON; if (gMenu.transitionTimer != 0) { gMenu.transitionTimer--; return; } else { u32 temp = gMenu.field_0x3; switch (gInput.newKeys) { case DPAD_UP: temp = 0; break; case DPAD_DOWN: temp = 1; break; case A_BUTTON: SetMenuType(2); SoundReq(SFX_TEXTBOX_SELECT); if (temp == 0) { SetFade(5, 8); } else { SetFade(7, 8); } break; } if (gMenu.field_0x3 != temp) { gMenu.field_0x3 = temp; SetPopupState(1, temp); SoundReq(SFX_TEXTBOX_CHOICE); } } return; case 0x2: default: if (gFadeControl.active == 0) { if (gMenu.field_0x3 == 0) { SetTask(TASK_GAME); } else { DoSoftReset(); } } return; } } // Unused, since task is set above // if we got here, it would be a softlock static void GameOver_Exit(void) { } static void DrawGameOverText(void) { static const u8 sOffsets[] = { 48, 68, 88, 108, 137, 156, 174, 192, }; u32 i; gOamCmd._4 = 0; gOamCmd._6 = 0; gOamCmd._8 = 0x8600; gOamCmd.y = gGenericMenu.unk10.a[0]; for (i = 0; i < 8; ++i) { gOamCmd.x = sOffsets[i]; #ifdef EU DrawDirect(0x1fc, i); #else DrawDirect(0x1fd, i); #endif } } void SetPopupState(u32 type, u32 choice_idx) { static const Font sDefaultFont = { .dest = gBG1Buffer, .gfx_dest = (u16*)0x06006000, .buffer_loc = gTextGfxBuffer, ._c = 0, .gfx_src = 0xD300, .width = 0xE0, .right_align = 0, .sm_border = 0, .unused = 0, .draw_border = 0, .border_type = 0, .fill_type = 6, ._15 = 4, ._16 = 1, .stylized = 0, }; static const PopupOption sPopupOptions[] = { { { 11, 11, 11, 10, 11, 10, 10, 0 }, 8, 0, 16 }, { { 10, 11, 11, 9, 11, 9, 9, 0 }, 8, 0, 17 }, { { 15, 15, 15, 15, 15, 15, 15, 0 }, 5, 1, 13 }, }; Font font; const PopupOption* opt; u32 fakematch; MemClear(gBG1Buffer, sizeof gBG1Buffer); gUnk_020227E8[0]._0.WORD = 0xf; gUnk_020227E8[1]._0.WORD = 0xf; gUnk_020227E8[2]._0.WORD = 0xf; gUnk_020227E8[3]._0.WORD = 0xf; *(&gUnk_020227E8[choice_idx]._0.BYTES.byte0 + 1) = fakematch = 1; MemCopy(&sDefaultFont, &font, sizeof font); opt = &sPopupOptions[type]; font.dest = sDefaultFont.dest + (opt->dest_off[gSaveHeader->language] + opt->_8 * 32); font.right_align = opt->right_align; sub_0805F46C(opt->_a, &font); gScreen.bg1.updated = fakematch; } static void InitializePlayer(void) { static const u8 sPlayerSpawnStates[] = { [PL_SPAWN_DEFAULT] = PLAYER_INIT, [PL_SPAWN_MINISH] = PLAYER_MINISH, [PL_SPAWN_DROP] = PLAYER_INIT, [PL_SPAWN_WALKING] = PLAYER_ROOMTRANSITION, [PL_SPAWN_STEP_IN] = PLAYER_080720DC, [PL_SPAWN_SPECIAL] = PLAYER_08074C44, [PL_SPAWN_DROP_MINISH] = PLAYER_MINISH, [PL_SPAWN_STAIRS_ASCEND] = PLAYER_USEENTRANCE, [PL_SPAWN_STAIRS_DESCEND] = PLAYER_USEENTRANCE, [PL_SPAWN_9] = PLAYER_MINISH, [PL_SPAWN_PARACHUTE_FORWARD] = PLAYER_WARP, [PL_SPAWN_PARACHUTE_UP] = PLAYER_WARP, [PL_SPAWN_FAST_TRAVEL] = PLAYER_WARP, }; Entity* pl; sub_080784C8(); MemClear(&gUnk_03000B80, sizeof gUnk_03000B80); MemClear(&gPlayerState, sizeof gPlayerState); MemFill32(0xffffffff, &gPlayerState.path_memory, sizeof gPlayerState.path_memory); MemClear(&gPlayerEntity, sizeof gPlayerEntity); pl = &gPlayerEntity; gRoomControls.camera_target = pl; gPlayerState.queued_action = sPlayerSpawnStates[gRoomTransition.player_status.spawn_type]; if (!CheckGlobalFlag(EZERO_1ST)) { gPlayerState.flags |= PL_NO_CAP; } switch (gRoomTransition.player_status.spawn_type) { case PL_SPAWN_DROP: case PL_SPAWN_DROP_MINISH: pl->z.HALF.HI = -0xc0; break; case PL_SPAWN_STEP_IN: gPlayerState.field_0x34[4] = 16; pl->direction = Direction8FromAnimationState(gRoomTransition.player_status.start_anim); case PL_SPAWN_WALKING: pl->speed = 224; break; case PL_SPAWN_STAIRS_ASCEND: case PL_SPAWN_STAIRS_DESCEND: gPlayerState.field_0x34[4] = 1; gPlayerState.field_0x34[5] = gRoomTransition.player_status.spawn_type; break; case PL_SPAWN_PARACHUTE_FORWARD: gPlayerState.field_0x34[4] = 1; break; case PL_SPAWN_PARACHUTE_UP: gPlayerState.field_0x34[4] = 3; break; case PL_SPAWN_FAST_TRAVEL: gPlayerState.field_0x34[4] = 4; } pl->kind = PLAYER; pl->flags |= ENT_COLLIDE | ENT_PERSIST; pl->spritePriority.b0 = 4; pl->health = gSave.stats.health; pl->x.HALF.HI = gRoomTransition.player_status.start_pos_x; pl->y.HALF.HI = gRoomTransition.player_status.start_pos_y; pl->animationState = gRoomTransition.player_status.start_anim; pl->collisionLayer = gRoomTransition.player_status.layer; UpdateSpriteForCollisionLayer(pl); AppendEntityToList(pl, 1); RegisterPlayerHitbox(); } bool32 AreaIsOverworld(void) { #ifdef EU return gArea.areaMetadata == 0x01; #else return gArea.areaMetadata == 0x81; #endif } bool32 CheckAreaOverworld(u32 area) { #if EU return gAreaMetadata[area].flags == 0x01; #else return gAreaMetadata[area].flags == 0x81; #endif } #ifndef EU bool32 AreaAllowsWarp(void) { return (gArea.areaMetadata >> 7) & 1; } #endif bool32 AreaIsDungeon(void) { return (gArea.areaMetadata >> 2) & 1; } bool32 AreaHasEnemies(void) { return (gArea.areaMetadata >> 4) & 1; } bool32 AreaHasNoEnemies(void) { return (gArea.areaMetadata >> 6) & 1; } bool32 AreaHasMap(void) { return (gArea.areaMetadata >> 3) & 1; } s32 ModHealth(s32 delta) { s32 newHealth; Stats* stats = &gSave.stats; newHealth = stats->health + delta; if (newHealth < 0) { newHealth = 0; } if (stats->maxHealth < newHealth) { newHealth = (u32)stats->maxHealth; } stats->health = newHealth; gPlayerEntity.health = newHealth; return newHealth; } void ModRupees(s32 delta) { s32 newRupeeCount; Stats* s = &gSave.stats; newRupeeCount = s->rupees + delta; if (newRupeeCount < 0) { newRupeeCount = 0; } else { if (newRupeeCount > gWalletSizes[s->walletType * 2]) { newRupeeCount = gWalletSizes[s->walletType * 2]; } } s->rupees = newRupeeCount; } void sub_080526F8(s32 a1) { if (AreaHasKeys()) { u8* p = &gSave.unk45C[gArea.dungeon_idx]; if (*p + a1 < 0) *p = 0; else *p += a1; } } bool32 AreaHasKeys(void) { return (gArea.areaMetadata >> 1) & 1; } bool32 HasDungeonMap(void) { u32 tmp; if (AreaHasKeys()) tmp = gSave.unk45C[gArea.dungeon_idx]; return tmp ? 1 : 0; } bool32 HasDungeonCompass(void) { u32 tmp; if (AreaHasKeys()) tmp = gSave.unk46C[gArea.dungeon_idx] & 4; return tmp ? 1 : 0; } bool32 HasDungeonBigKey(void) { if (!AreaHasKeys()) return 0; return (gSave.unk46C[gArea.dungeon_idx] >> 1) & 1; } bool32 HasDungeonSmallKey(void) { u32 tmp; if (!AreaHasKeys()) return 0; return gSave.unk46C[gArea.dungeon_idx] & 1; } void RestoreGameTask(u32 a1) { LoadGfxGroups(); #ifndef EU CleanUpGFXSlots(); #endif sub_080ADE24(); InitUI(1); sub_0801AE44(a1); MemCopy(gUnk_02024090, gPaletteBuffer, 1024); gUsedPalettes = 0xffffffff; } static void LoadRoomBgm(void) { gArea.queued_bgm = gAreaMetadata[gRoomControls.area]._3; if (CheckLocalFlagByBank(FLAG_BANK_10, LV6_KANE_START)) { gArea.queued_bgm = BGM_FIGHT_THEME2; } } #ifndef EU void sub_08052878(void) { gArea.bgm = gArea.queued_bgm; SoundReq(SONG_STOP_ALL); } static void sub_0805289C(void) { gArea.queued_bgm = gArea.bgm; } #endif static u32 CheckGameOver(void) { if (gRoomTransition.field_0x4[1]) { InitFade(); gMain.state = 3; gMain.substate = 0; SetFade(5, 8); SoundReq(SONG_STOP_BGM); return 1; } return 0; } void RoomExitCallback(void) { if (gArea.transitionManager != NULL && gArea.onExit != NULL) gArea.onExit(gArea.transitionManager); } static u32 CheckRoomExit(void) { if (gRoomTransition.transitioningOut && gSave.stats.health != 0 && gPlayerState.framestate != PL_STATE_DIE) { if (StairsAreValid()) { gRoomTransition.transitioningOut = 0; return 0; } switch (gRoomTransition.type) { case TRANSITION_CUT: SetFade(13, 8); break; case TRANSITION_CUT_FAST: SetFade(13, 3); break; case TRANSITION_FADE_WHITE_SLOW: SetFade(7, 4); break; case TRANSITION_FADE_BLACK_SLOW: SetFade(5, 4); break; case TRANSITION_FADE_BLACK: SetFade(5, 16); break; case TRANSITION_FADE_BLACK_FAST: SetFade(5, 256); break; case TRANSITION_7: case TRANSITION_FADE_WHITE_FAST: SetFade(7, 256); break; default: SetFade(7, 16); break; } RoomExitCallback(); gMain.substate = 3; *(&gMain.pauseInterval + 1) = 1; return 1; } return 0; } static u32 StairsAreValid(void) { static const u16 sStairTypes[] = { 0x91, PL_SPAWN_STAIRS_ASCEND, 0x92, PL_SPAWN_STAIRS_DESCEND, 0x93, PL_SPAWN_STAIRS_ASCEND, 0x94, PL_SPAWN_STAIRS_DESCEND, 0x95, PL_SPAWN_STAIRS_ASCEND, 0x96, PL_SPAWN_STAIRS_DESCEND, 0x97, PL_SPAWN_STAIRS_ASCEND, 0x98, PL_SPAWN_STAIRS_DESCEND, 0 }; const u16* i; u32 tgt = gRoomTransition.stairs_idx; for (i = sStairTypes; i[0] != 0; i += 2) { if (tgt == i[0]) { gPlayerState.queued_action = PLAYER_USEENTRANCE; gPlayerState.field_0x38 = 0; gPlayerState.field_0x39 = i[1]; if (!gRoomTransition.player_status.spawn_type) gRoomTransition.player_status.spawn_type = i[1]; return 1; } } return 0; } void InitParachuteRoom(void) { gRoomTransition.transitioningOut = 1; gRoomTransition.player_status.start_pos_x = (gPlayerEntity.x.HALF.HI - gRoomControls.origin_x) & 0x3F8; gRoomTransition.player_status.start_pos_y = (gPlayerEntity.y.HALF.HI - gRoomControls.origin_y) & 0x3F8; gRoomTransition.player_status.start_anim = 4; gRoomTransition.player_status.spawn_type = PL_SPAWN_PARACHUTE_FORWARD; gRoomTransition.player_status.area_next = gRoomControls.area; gRoomTransition.player_status.room_next = gRoomControls.room - 1; } static void InitRoomTransition(void) { switch (gRoomTransition.type) { case TRANSITION_CUT: SetFade(12, 8); break; case TRANSITION_CUT_FAST: SetFade(12, 3); break; case TRANSITION_FADE_WHITE_SLOW: SetFade(6, 4); break; case TRANSITION_3: break; case TRANSITION_FADE_BLACK_FAST: SetFade(5, 256); break; case TRANSITION_7: SetFade(7, 256); break; case TRANSITION_FADE_BLACK: SetFade(4, 16); break; case TRANSITION_FADE_WHITE_FAST: SetFade(6, 8); break; default: SetFadeInverted(16); break; } } bool32 CanDispEzloMessage(void) { s32 tmp = PL_STATE_WALK; if (!(gInput.heldKeys & SELECT_BUTTON) || gPlayerState.controlMode != CONTROL_ENABLED || gUnk_02034490.unk0 || gUnk_0200AF00.filler0[1]) return 0; if ((gPlayerState.flags & (PL_NO_CAP | 0x110)) || (gPlayerState.framestate_last > tmp) || gPlayerState.item || gPlayerEntity.field_0x7a.HWORD) return 0; if ((gPlayerEntity.z.HALF.HI & 0x8000) && !gPlayerState.field_0xa) return 0; GenerateAreaHint(); ForceSetPlayerState(PL_STATE_TALKEZLO); SetPlayerEventPriority(); return 1; } void DisplayEzloMessage(void) { u32 height; u32 idx; #if defined(JP) || defined(EU) idx = 0x10; #else idx = 0x11; #endif if (gRoomTransition.player_status.field_0x24[idx] == 0) { height = gPlayerEntity.y.HALF.HI - gRoomControls.scroll_y > 96 ? 1 : 13; } else { height = gRoomTransition.player_status.field_0x24[idx]; } MessageAtHeight(gRoomTransition.hint_idx, height); } #if defined(USA) || defined(DEMO_USA) || defined(DEMO_JP) static void CreateManagerF(void) { Entity* e = NULL; if (gRoomTransition.player_status.field_0x24[13]) return; gRoomTransition.player_status.field_0x24[13] = 1; #ifndef DEMO_JP gRoomTransition.player_status.field_0x24[10] = gArea.locationIndex; #endif e = (Entity*)GetEmptyManager(); if (e == NULL) return; e->kind = MANAGER; e->id = 15; e->type = 15; AppendEntityToList(e, 0); } #endif static void sub_08052C3C(void) { if (gArea.field_0x18 == 0) gArea.unk1A = gArea.field_0x18; if (gArea.unk1A) { gArea.unk1A--; gArea.field_0x18 = 0; } } static void UpdatePlayerMapCoords(void) { if (!AreaHasNoEnemies()) { if (AreaIsOverworld()) { gRoomTransition.player_status.overworld_map_x = gPlayerEntity.x.HALF_U.HI; gRoomTransition.player_status.overworld_map_y = gPlayerEntity.y.HALF_U.HI; } else if (AreaIsDungeon()) { gRoomTransition.player_status.dungeon_map_x = gPlayerEntity.x.HALF.HI; gRoomTransition.player_status.dungeon_map_y = gPlayerEntity.y.HALF.HI; } } } void SetWorldMapPos(u32 area, u32 room, u32 x, u32 y) { RoomHeader* hdr = gAreaRoomHeaders[area] + room; gRoomTransition.player_status.overworld_map_x = hdr->map_x + x; gRoomTransition.player_status.overworld_map_y = hdr->map_y + y; } void SetDungeonMapPos(u32 area, u32 room, u32 x, u32 y) { RoomHeader* hdr = gAreaRoomHeaders[area] + room; gRoomTransition.player_status.dungeon_map_x = hdr->map_x + x; gRoomTransition.player_status.dungeon_map_y = hdr->map_y + y; } void InitRoom(void) { AreaHeader* a_hdr = NULL; MemClear(&gArea, sizeof gArea); a_hdr = &gAreaMetadata[gRoomControls.area]; gArea.areaMetadata = a_hdr->flags; gArea.locationIndex = a_hdr->location; gArea.dungeon_idx = a_hdr->location - 23; gArea.localFlagOffset = gLocalFlagBanks[a_hdr->flag_bank]; gArea.filler[0] = a_hdr->flag_bank; gArea.unk1A = 180; gArea.lightLevel = 256; InitRoomTransition(); InitAllRoomResInfo(); } u32 GetFlagBankOffset(u32 idx) { AreaHeader* a_hdr = &gAreaMetadata[idx]; return gLocalFlagBanks[a_hdr->flag_bank]; } void RegisterTransitionManager(void* mgr, void (*onEnter)(), void (*onExit)()) { if (gMain.substate != 7) { gArea.transitionManager = mgr; gArea.onEnter = onEnter; gArea.onExit = onExit; } } static void InitAllRoomResInfo(void) { RoomHeader* r_hdr = gAreaRoomHeaders[gRoomControls.area]; RoomResInfo* info = gArea.roomResInfos; u32 i; for (i = 0; i < MAX_ROOMS && *(u16*)r_hdr != 0xFFFF; i++, r_hdr++) { if (r_hdr->tileset_id != 0xFFFF) InitRoomResInfo(info, r_hdr, gRoomControls.area, i); info++; } gArea.pCurrentRoomInfo = GetCurrentRoomInfo(); } static void InitRoomResInfo(RoomResInfo* info, RoomHeader* r_hdr, u32 area, u32 room) { info->map_x = r_hdr->map_x; info->map_y = r_hdr->map_y; info->pixel_width = r_hdr->pixel_width; info->pixel_height = r_hdr->pixel_height; info->tileset = *(gAreaTilesets[area] + r_hdr->tileset_id); info->map = *(gAreaRoomMaps[area] + room); info->metatiles = gAreaMetatiles[area]; info->bg_anim = gUnk_080B755C[area]; info->exits = *(gExitLists[area] + room); if (gAreaTable[area] != NULL) { info->properties = *(gAreaTable[area] + room); } } RoomResInfo* GetCurrentRoomInfo(void) { return &gArea.roomResInfos[gRoomControls.room]; } void sub_08052EA0(void) { MemClear(&gRoomVars, sizeof gRoomVars); gRoomVars.unk_10[0] = -1; gRoomVars.unk_10[1] = gRoomVars.unk_10[0]; gRoomVars.unk_10[2] = gRoomVars.unk_10[0]; gRoomVars.unk_10[3] = gRoomVars.unk_10[0]; gRoomVars.lightLevel = 256; gArea.locationIndex = gAreaMetadata[gRoomControls.area].location; UpdateRoomTracker(); InitScriptData(); sub_08054524(); sub_080186D4(); sub_0806F364(); UpdateGlobalProgress(); } static u32 sub_08052EF4(s32 idx) { AreaHeader* a_hdr = NULL; u32 i = idx < 0 ? gRoomControls.area : idx; a_hdr = &gAreaMetadata[i]; return gLocalFlagBanks[a_hdr->flag_bank]; } /** * @brief If enabled, this type of transition does not change the room * and keeps all entities. */ static void UpdateFakeScroll(void) { u32 x, y; LinkedList* ll; Entity* e; if (gArea.unk_0c_0 == 0 || !gRoomVars.field_0x0) return; y = 0; x = 0; // WTF? switch (gRoomControls.scroll_direction) { case 0: y = gArea.pCurrentRoomInfo->pixel_height; case 1: y = gArea.pCurrentRoomInfo->pixel_height; case 2: y = gArea.pCurrentRoomInfo->pixel_height; case 3: x = gArea.pCurrentRoomInfo->pixel_width; } gArea.pCurrentRoomInfo->map_x += x; gArea.pCurrentRoomInfo->map_y += y; gRoomControls.origin_x += x; gRoomControls.origin_y += y; gRoomControls.scroll_x += x; gRoomControls.scroll_y += y; ll = gEntityLists; do { for (e = ll->first; e != (Entity*)ll; e = e->next) { if (e->kind != MANAGER) { e->x.HALF.HI += x; e->y.HALF.HI += y; } } } while (++ll < gEntityLists + 9); } void LoadAuxiliaryRoom(u32 area, u32 room) { sub_08052FF4(area, room); gRoomControls.camera_target = NULL; sub_0807C860(); sub_0807C740(); } void sub_08052FF4(u32 area, u32 room) { RoomHeader* r_hdr = NULL; ClearTilemaps(); SetBGDefaults(); gRoomControls.area = area; gRoomControls.room = room; gScreen.lcd.displayControl = 0x1740; MemClear(&gArea.currentRoomInfo, sizeof gArea.currentRoomInfo); gArea.pCurrentRoomInfo = &gArea.currentRoomInfo; r_hdr = gAreaRoomHeaders[area] + room; gArea.currentRoomInfo.map_x = r_hdr->map_x; gArea.currentRoomInfo.map_y = r_hdr->map_y; gArea.currentRoomInfo.pixel_width = r_hdr->pixel_width; gArea.currentRoomInfo.pixel_height = r_hdr->pixel_height; gArea.currentRoomInfo.tileset = *(gAreaTilesets[area] + r_hdr->tileset_id); gArea.currentRoomInfo.map = *(gAreaRoomMaps[area] + room); gArea.currentRoomInfo.metatiles = gAreaMetatiles[area]; gArea.currentRoomInfo.bg_anim = gUnk_080B755C[area]; } void ChangeLightLevel(s32 lightLevel) { lightLevel += gRoomVars.lightLevel; if (lightLevel < 0) lightLevel = 0; if (lightLevel > 256) lightLevel = 256; gRoomVars.lightLevel = lightLevel; } static void sub_080530B0(void) { static const u16 sMinecartData[] = { 0x189, 0x0, 0x102, 0x4, 0x1af, 0x0, 0x204, 0x0, 0x1cf, 0x0, 0x10, 0x4, 0x0, 0x0, 0x0, 0x0 }; MemCopy(sMinecartData, gRoomTransition.minecart_data, sizeof sMinecartData); } void UpdateGlobalProgress(void) { u8 pcnt = 1; if (CheckLocalFlagByBank(FLAG_BANK_3, SEIIKI_STAINED_GLASS)) { pcnt = 9; } else if (CheckGlobalFlag(LV5_CLEAR)) { pcnt = 8; } else if (CheckLocalFlagByBank(FLAG_BANK_3, OUBO_KAKERA)) { pcnt = 7; } else if (CheckGlobalFlag(LV4_CLEAR)) { pcnt = 6; } else if (CheckGlobalFlag(LV3_CLEAR)) { pcnt = 5; } else if (CheckLocalFlagByBank(FLAG_BANK_1, SOUGEN_08_TORITSUKI)) { pcnt = 4; } else if (CheckGlobalFlag(LV1_CLEAR)) { pcnt = 2; } gSave.global_progress = pcnt; } static u32 sub_08053144(void) { u32 ret; if (CheckGlobalFlag(ENDING)) return 0; ret = 0; if (gArea.locationIndex != 0) ret = !!(gRoomTransition.player_status.field_0x24[10] ^ gArea.locationIndex); return ret; } static void CheckAreaDiscovery(void) { if (!sub_08053144()) return; gRoomTransition.player_status.field_0x24[10] = gArea.locationIndex; if (!CheckGlobalFlag(TABIDACHI)) return; if (!CheckGlobalFlag(ENDING)) { Entity* e = (Entity*)GetEmptyManager(); if (e != NULL) { e->kind = MANAGER; e->id = 0x39; AppendEntityToList(e, 8); if (!gRoomVars.field_0x0 && !ReadBit(gSave.areaVisitFlags, gArea.locationIndex)) { e->type2 = 1; SetPlayerControl(3); SetInitializationPriority(); } } } WriteBit(gSave.areaVisitFlags, gArea.locationIndex); } static void UpdatePlayerRoomStatus(void) { gPlayerState.startPosX = gPlayerEntity.x.HALF.HI; gPlayerState.startPosY = gPlayerEntity.y.HALF.HI; if (sub_08053144()) { MemCopy(&gRoomTransition.player_status, &gSave.saved_status, sizeof gRoomTransition.player_status); if (AreaIsDungeon()) { gRoomTransition.player_status.dungeon_area = gRoomControls.area; gRoomTransition.player_status.dungeon_room = gRoomControls.room; gRoomTransition.player_status.dungeon_x = gPlayerEntity.x.HALF.HI; gRoomTransition.player_status.dungeon_y = gPlayerEntity.y.HALF.HI; } } } void sub_08053250(void) { gRoomTransition.player_status.spawn_type = PL_SPAWN_DEFAULT; gRoomTransition.player_status.start_pos_x = gPlayerEntity.x.HALF.HI - gRoomControls.origin_x; gRoomTransition.player_status.start_pos_y = gPlayerEntity.y.HALF.HI - gRoomControls.origin_y; gRoomTransition.player_status.start_anim = gPlayerEntity.animationState; gRoomTransition.player_status.layer = gPlayerEntity.collisionLayer; gRoomTransition.player_status.area_next = gRoomControls.area; gRoomTransition.player_status.room_next = gRoomControls.room; MemCopy(&gRoomTransition.player_status, &gSave.saved_status, sizeof gRoomTransition.player_status); } static void sub_0805329C(void) { if (sub_08053144()) { switch (gRoomControls.area) { case AREA_DEEPWOOD_SHRINE: gSave.unk7 = 0; break; case AREA_CAVE_OF_FLAMES: sub_080530B0(); break; case AREA_OUTER_FORTRESS_OF_WINDS: sub_080532E4(); break; default: sub_08053460(); break; } } } static void sub_080532E4(void) { s32 x, y; RoomHeader* r_hdr = gAreaRoomHeaders[AREA_FORTRESS_OF_WINDS] + 33; gRoomTransition.player_status.dungeon_area = AREA_FORTRESS_OF_WINDS; gRoomTransition.player_status.dungeon_room = 33; gRoomTransition.player_status.dungeon_x = r_hdr->map_x + r_hdr->pixel_width / 2; gRoomTransition.player_status.dungeon_map_x = gRoomTransition.player_status.dungeon_x; gRoomTransition.player_status.dungeon_y = r_hdr->map_y + r_hdr->pixel_height + 0xa0; gRoomTransition.player_status.dungeon_map_y = gRoomTransition.player_status.dungeon_y; } void LoadGfxGroups(void) { MemClear(&gBG0Buffer, sizeof gBG0Buffer); MemClear(&gBG1Buffer, sizeof gBG1Buffer); MemClear(&gBG2Buffer, sizeof gBG2Buffer); MemClear(&gBG3Buffer, sizeof gBG3Buffer); LoadGfxGroup(16); LoadGfxGroup(23); if (gRoomControls.area == AREA_CASTOR_WILDS) LoadGfxGroup(26); LoadItemGfx(); LoadPaletteGroup(11); LoadPaletteGroup(12); SetColor(0, 0); } void LoadItemGfx(void) { LoadGfxGroup(GetInventoryValue(ITEM_REMOTE_BOMBS) ? 24 : 25); if (GetInventoryValue(ITEM_LIGHT_ARROW)) LoadGfxGroup(29); LoadGfxGroup(GetInventoryValue(ITEM_MAGIC_BOOMERANG) ? 28 : 27); } void sub_080533CC(void) { u16* p1 = gUnk_020178E0; u16* p2 = gUnk_020178E0 - 0x100; *p2++ = *p1++; *p2++ = *p1++; *p2++ = *p1++; *p2++ = *p1++; *p2++ = *p1++; gUsedPalettes |= 8; } static void sub_0805340C(void) { static void (*const sHandlers[])(u32*) = { sub_08053434, DummyHandler, sub_080534E4, DummyHandler, DummyHandler, DummyHandler, DummyHandler, DummyHandler, }; u32* p; u32 i; p = gSave.timers; for (i = 0; i < 8; i++, p++) { (sHandlers[i])(p); } } static void DummyHandler(u32* a1) { } static void sub_08053434(u32* a1) { if (gArea.locationIndex == 29 && *a1) { if (!--*a1) { sub_08053460(); MenuFadeIn(5, 6); } } } static void sub_08053460(void) { static const u16 sClearFlags[] = { FLAG_BANK_10, LV6_GUFUU1_GISHIKI, FLAG_BANK_10, LV6_GUFUU1_DEMO, FLAG_BANK_10, LV6_ZELDA_DISCURSE, FLAG_BANK_10, LV6_00_ESCAPE, FLAG_BANK_10, LV6_GUFUU2_DEAD, FLAG_BANK_G, ENDING, FLAG_BANK_10, LV6_KANE_START, FLAG_BANK_10, LV6_KANE_1ST, FLAG_BANK_10, LV6_KANE_2ND, FLAG_BANK_10, LV6_SOTO_ENDING, 0xFFFF }; gSave.timers[0] = 0; if (CheckLocalFlagByBank(FLAG_BANK_10, LV6_ZELDA_DISCURSE)) ClearGlobalFlag(ZELDA_CHASE); ClearFlagArray(sClearFlags); } void sub_08053494(void) { gSave.timers[0] = 10800; } void sub_080534AC(void) { if (CheckLocalFlagByBank(FLAG_BANK_10, LV6_KANE_START)) { ClearLocalFlagByBank(FLAG_BANK_10, LV6_KANE_START); gSave.timers[0] = 0; SoundReq(SONG_STOP_BGM); } } static void sub_080534E4(u32* a1) { if (gRoomControls.area != AREA_VEIL_FALLS_TOP) { if (*a1) --*a1; } } void InitBiggoronTimer(void) { gSave.timers[2] = 36000; } static void ResetTmpFlags(void) { static const u16 sClearFlags[] = { FLAG_BANK_2, BILL00_SHICHOU_00, FLAG_BANK_2, BILL0A_YADO_TAKARA_00, FLAG_BANK_2, BILL0C_SCHOOLR_00, FLAG_BANK_1, MACHI00_00, FLAG_BANK_1, MACHI00_02, FLAG_BANK_2, MHOUSE06_00, FLAG_BANK_2, MHOUSE14_00, FLAG_BANK_2, MHOUSE2_00_02, FLAG_BANK_2, MHOUSE2_01_T0, FLAG_BANK_2, MHOUSE2_02_KAME, FLAG_BANK_2, SHOP00_ITEM_01, FLAG_BANK_2, SHOP01_CAFE_01, 0xFFFF }; sub_08053460(); ClearFlagArray(sClearFlags); if (!CheckGlobalFlag(WATERBEAN_PUT)) ClearGlobalFlag(WATERBEAN_OUT); if (!GetInventoryValue(0x40u)) ClearGlobalFlag(LV1_CLEAR); if (!GetInventoryValue(0x41u)) ClearGlobalFlag(LV2_CLEAR); if (!GetInventoryValue(0x42u)) ClearGlobalFlag(LV4_CLEAR); } static void ClearFlagArray(const u16* p) { const u16* i; for (i = p; i[0] != 0xFFFF; i += 2) ClearLocalFlagByBank(i[0], i[1]); }