/** * @file game.c * @ingroup Tasks * * @brief Game task */ #include "game.h" #include "area.h" #include "asm.h" #include "backgroundAnimations.h" #include "common.h" #include "droptables.h" #include "enemy.h" #include "entity.h" #include "fileselect.h" #include "flags.h" #include "functions.h" #include "item.h" #include "itemMetaData.h" #include "itemMetaData.h" #include "kinstone.h" #include "main.h" #include "manager/diggingCaveEntranceManager.h" #include "menu.h" #include "message.h" #include "npc.h" #include "object.h" #include "player.h" #include "player.h" #include "room.h" #include "roomid.h" #include "save.h" #include "screen.h" #include "sound.h" #include "subtask.h" #include "transitions.h" #include "ui.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; extern u8 gUpdateVisibleTiles; 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 bool32 UpdateLightLevel(void); extern void sub_080185F8(void); extern void UpdateDoorTransition(void); extern bool32 CheckInitPortal(void); extern void UpdateCarriedObject(void); extern void CollisionMain(void); extern void sub_0805BB74(s32); extern void CreateZeldaFollower(void); extern void LoadRoomGfx(void); extern void RecycleEntities(void); extern void sub_0804AF90(void); extern void CallRoomProp6(void); static void UpdateWindcrests(void); static void InitializeEntities(void); static void sub_08051D98(void); static void sub_08051DCC(void); void sub_08054974(u32 worldEventId, bool32 param_2); 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(FADE_IN_OUT | FADE_BLACK_WHITE | FADE_INSTANT, 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 = GAMEMAIN_INITROOM; } static void GameTask_Init(void) { DispReset(1); gFadeControl.mask = 0xffffffff; MemClear(&gOAMControls, 0xB74); MemClear(&gUI, sizeof(gUI)); 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(FALSE); InitializeEntities(); #ifndef EU sub_0801855C(); #endif } static void GameMain_ChangeRoom(void) { UpdateEntities(); if (!UpdateLightLevel()) UpdateScroll(); UpdateBgAnimations(); UpdateScrollVram(); DrawUI(); UpdateManagers(); FlushSprites(); DrawUIElements(); 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); gPauseMenuOptions.disabled = 0; #if defined(USA) || defined(DEMO_USA) if (gArea.unk28.textBaseIndex != 0xff) { sub_0801855C(); } CreateMiscManager(); CheckAreaDiscovery(); #elif defined(EU) CheckAreaDiscovery(); sub_0801855C(); #elif defined(JP) CheckAreaDiscovery(); if (gArea.unk28.textBaseIndex != 0xff) { sub_0801855C(); } #elif defined(DEMO_JP) if (gRoomTransition.field_0x2c[4]) CheckAreaDiscovery(); if (gArea.unk28.textBaseIndex != 0xff) { sub_0801855C(); } CreateMiscManager(); #endif if (!gRoomVars.field_0x0) { RequestPriorityDuration(NULL, 1); } } static void GameMain_Update(void) { if (CheckInitPauseMenu() || CheckInitPortal()) { return; } UpdateTimerCallbacks(); // 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(); UpdateBgAnimations(); UpdateScrollVram(); DecreasePortalTimer(); DrawUI(); UpdateManagers(); DrawUIElements(); 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 (CheckInitPauseMenu()) return; UpdateEntities(); CollisionMain(); DrawUI(); UpdateManagers(); FlushSprites(); DrawUIElements(); UpdateCarriedObject(); DrawEntities(); CheckRoomExit(); CheckGameOver(); CopyOAM(); if (!gFadeControl.active) ResetSystemPriority(); } static void GameMain_ChangeArea(void) { FlushSprites(); DrawUIElements(); DrawEntities(); gMain.pad = 1; CopyOAM(); if (!gFadeControl.active) { DispReset(1); gMain.state = GAMETASK_INIT; gMain.substate = GAMEMAIN_INITROOM; gRoomTransition.transitioningOut = 1; } } static void GameTask_Exit(void) { #ifdef DEMO_USA if (!gFadeControl.active) DoSoftReset(); #else SetFade(FADE_IN_OUT | FADE_BLACK_WHITE | FADE_INSTANT, 8); SetTask(TASK_GAMEOVER); #endif } // TODO End of GameTask? static void InitializeEntities(void) { sub_08052EA0(); sub_0804AF90(); CallRoomProp6(); InitializePlayer(); gDiggingCaveEntranceTransition.entrance = NULL; InitializeCamera(); gUpdateVisibleTiles = 1; LoadRoomBgm(); SetColor(0, 0); LoadRoom(); CreateZeldaFollower(); CallRoomProp5And7(); sub_0805329C(); UpdateScrollVram(); sub_0805BB74(-1); 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; } } } }