mirror of https://github.com/zeldaret/tmc.git
1726 lines
47 KiB
C
1726 lines
47 KiB
C
#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) {
|
|
DoFade(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[0] = 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
|
|
DoFade(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);
|
|
LoadCutsceneRoom(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;
|
|
sub_080500F4(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;
|
|
sub_080A7114(0);
|
|
}
|
|
|
|
static void GameOver_Init(void) {
|
|
if (gFadeControl.active)
|
|
return;
|
|
sub_08052010();
|
|
gMenu.focusCoords[0] = 80;
|
|
gMenu.transitionTimer = 60;
|
|
gSave.stats.health = 24;
|
|
gMain.field_0x5 = 60;
|
|
SoundReq(BGM_GAMEOVER);
|
|
sub_080500F4(4);
|
|
gFadeControl.mask = 0xFFFF0001;
|
|
switch_state(1);
|
|
}
|
|
|
|
static void GameOver_FadeIn(void) {
|
|
if (gFadeControl.active)
|
|
return;
|
|
|
|
if (gMain.field_0x5 == 0) {
|
|
if (gMenu.focusCoords[0] >= 38) {
|
|
gMenu.focusCoords[0]--;
|
|
} else {
|
|
gMenu.transitionTimer--;
|
|
if (gMenu.transitionTimer == 0) {
|
|
switch_state(2);
|
|
#if defined(DEMO_USA) || defined(DEMO_JP)
|
|
SoundReq(SONG_VOL_FADE_OUT);
|
|
DoFade(7, 4);
|
|
#else
|
|
SetPopupState(0, 0);
|
|
gScreen.lcd.displayControl |= DISPCNT_BG1_ON | DISPCNT_BG2_ON;
|
|
gFadeControl.mask = 0x0000ffff;
|
|
DoFade(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;
|
|
sub_080A7114(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;
|
|
sub_080A7114(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:
|
|
sub_080A7114(4);
|
|
break;
|
|
case -1:
|
|
gMenu.transitionTimer = 60;
|
|
CreateDialogBox(9, 0);
|
|
sub_080A7114(3);
|
|
break;
|
|
}
|
|
return;
|
|
case 3:
|
|
if (gMenu.transitionTimer != 0) {
|
|
gMenu.transitionTimer--;
|
|
} else if (gInput.newKeys & (A_BUTTON | B_BUTTON | START_BUTTON)) {
|
|
sub_080A7114(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;
|
|
sub_080A7114(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:
|
|
sub_080A7114(2);
|
|
SoundReq(SFX_TEXTBOX_SELECT);
|
|
if (temp == 0) {
|
|
DoFade(5, 8);
|
|
} else {
|
|
DoFade(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 = gMenu.focusCoords[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;
|
|
DoFade(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:
|
|
DoFade(13, 8);
|
|
break;
|
|
case TRANSITION_CUT_FAST:
|
|
DoFade(13, 3);
|
|
break;
|
|
case TRANSITION_FADE_WHITE_SLOW:
|
|
DoFade(7, 4);
|
|
break;
|
|
case TRANSITION_FADE_BLACK_SLOW:
|
|
DoFade(5, 4);
|
|
break;
|
|
case TRANSITION_FADE_BLACK:
|
|
DoFade(5, 16);
|
|
break;
|
|
case TRANSITION_FADE_BLACK_FAST:
|
|
DoFade(5, 256);
|
|
break;
|
|
case TRANSITION_7:
|
|
case TRANSITION_FADE_WHITE_FAST:
|
|
DoFade(7, 256);
|
|
break;
|
|
default:
|
|
DoFade(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:
|
|
DoFade(12, 8);
|
|
break;
|
|
case TRANSITION_CUT_FAST:
|
|
DoFade(12, 3);
|
|
break;
|
|
case TRANSITION_FADE_WHITE_SLOW:
|
|
DoFade(6, 4);
|
|
break;
|
|
case TRANSITION_3:
|
|
break;
|
|
case TRANSITION_FADE_BLACK_FAST:
|
|
DoFade(5, 256);
|
|
break;
|
|
case TRANSITION_7:
|
|
DoFade(7, 256);
|
|
break;
|
|
case TRANSITION_FADE_BLACK:
|
|
DoFade(4, 16);
|
|
break;
|
|
case TRANSITION_FADE_WHITE_FAST:
|
|
DoFade(6, 8);
|
|
break;
|
|
default:
|
|
sub_080500F4(16);
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool32 CanDispEzloMessage(void) {
|
|
s32 tmp = PL_STATE_WALK;
|
|
|
|
if (!(gInput.heldKeys & SELECT_BUTTON) || gPlayerState.controlMode != CONTROL_ENABLED || gUnk_02034490[0] ||
|
|
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.unk_0a = 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.filler3[1] & 1) == 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 LoadCutsceneRoom(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]);
|
|
}
|