tmc/src/game.c

2609 lines
69 KiB
C

/**
* @file game.c
* @ingroup Tasks
*
* @brief Game task
*/
#include "global.h"
#include "area.h"
#include "asm.h"
#include "common.h"
#include "droptables.h"
#include "enemy.h"
#include "entity.h"
#include "fileselect.h"
#include "flags.h"
#include "functions.h"
#include "game.h"
#include "item.h"
#include "itemMetaData.h"
#include "main.h"
#include "menu.h"
#include "message.h"
#include "object.h"
#include "player.h"
#include "room.h"
#include "save.h"
#include "screen.h"
#include "sound.h"
#include "subtask.h"
#include "itemMetaData.h"
#include "player.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 bool32 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 CloneMapData(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 bool32 CheckGameOver(void);
static bool32 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[];
extern u8 gUnk_0200AF13;
extern u8 gUnk_0200AF14;
extern u8 gUnk_080FE1C6[];
extern void (*const gUnk_080FE2AC[])(void);
/** @see Item */
void ForceEquipItem(u32, u32);
extern void SetInventoryValue(u32, u32);
extern u8 gUnk_080FE1DD[];
extern void (*const gUnk_080FE2A0[])(void);
extern void (*const gUnk_080FCBB4[])(void);
extern const EntityData gUnk_080FCB94[];
void sub_08052004(void);
extern void (*const gUnk_080FCCFC[])(void);
extern void (*const gUnk_080FCD38[])(void);
extern const EntityData gUnk_080FCC54[];
void sub_08051FF0(void);
extern void (*const gUnk_080FCD40[])(void);
extern const EntityData gUnk_080FCBC4[];
void sub_08051F78(void);
extern const EntityData gUnk_080FCC14[];
extern void DeleteAllEntities(void);
extern void (*const gUnk_080FCDD4[])(void);
extern const EntityData gUnk_080FCD84[];
extern void (*const gUnk_080FCEB0[])(void);
extern const EntityData gUnk_080FCDE0[];
extern void (*const gUnk_080FCEEC[])(void);
extern const EntityData gUnk_080FCEBC[];
extern void (*const gUnk_080FCEF8[])(void);
extern void (*const gUnk_080FCFA4[])(void);
extern void* GetRoomProperty(u32, u32, u32);
extern void (*const gUnk_080FD108[])(void);
extern const EntityData* gUnk_080FCFB8[];
extern void (*const gUnk_080FD138[])(void);
extern const u16 gUnk_080FD964[];
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 = 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(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 = GAMEMAIN_INITROOM;
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[gUI.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[gUI.field_0x3]._3;
if (flag & 0xF0) {
MenuFadeIn(2, flag >> 4);
} else {
gUI.nextToLoad = 3;
SetFadeInverted(0x10);
MessageInitialize();
}
}
void sub_08051F78(void) {
u32 idx = gUI.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 != GAMETASK_TRANSITION) {
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(GAMETASK_INIT);
}
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(GAMETASK_MAIN);
#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(GAMETASK_EXIT);
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_0x38 = 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_0x38 = 1;
gPlayerState.field_0x39 = gRoomTransition.player_status.spawn_type;
break;
case PL_SPAWN_PARACHUTE_FORWARD:
gPlayerState.field_0x38 = 1;
break;
case PL_SPAWN_PARACHUTE_UP:
gPlayerState.field_0x38 = 3;
break;
case PL_SPAWN_FAST_TRAVEL:
gPlayerState.field_0x38 = 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 bool32 CheckGameOver(void) {
if (gRoomTransition.field_0x4[1]) {
InitFade();
gMain.state = GAMETASK_EXIT;
gMain.substate = GAMEMAIN_INITROOM;
SetFade(5, 8);
SoundReq(SONG_STOP_BGM);
return TRUE;
}
return FALSE;
}
void RoomExitCallback(void) {
if (gArea.transitionManager != NULL && gArea.onExit != NULL)
gArea.onExit(gArea.transitionManager);
}
static bool32 CheckRoomExit(void) {
if (gRoomTransition.transitioningOut && gSave.stats.health != 0 && gPlayerState.framestate != PL_STATE_DIE) {
if (StairsAreValid()) {
gRoomTransition.transitioningOut = 0;
return FALSE;
}
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 = GAMEMAIN_CHANGEAREA;
*(&gMain.pauseInterval + 1) = 1;
return TRUE;
}
return FALSE;
}
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 != GAMEMAIN_SUBTASK) {
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;
CloneMapData();
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(ITEM_EARTH_ELEMENT))
ClearGlobalFlag(LV1_CLEAR);
if (!GetInventoryValue(ITEM_FIRE_ELEMENT))
ClearGlobalFlag(LV2_CLEAR);
if (!GetInventoryValue(ITEM_WATER_ELEMENT))
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]);
}
void CutsceneMain_Init(void) {
gUnk_080FCBB4[gMenu.overlayType]();
}
void sub_080535AC(void) {
gMenu.overlayType = 1;
gMenu.transitionTimer = 0x78;
gUI.field_0x6 = 1;
gUpdateVisibleTiles = 1;
gScreen.lcd.displayControl &= 0xfeff;
LoadRoomEntityList((EntityData*)gUnk_080FCB94);
SetFade(6, 8);
}
void sub_080535F4(void) {
if (gFadeControl.active == 0) {
ResetSystemPriority();
gMenu.overlayType = 2;
}
}
void nullsub_481(void) {
}
void sub_08053618(void) {
gMenu.transitionTimer--;
if (gMenu.transitionTimer == 0) {
sub_08052004();
}
}
void sub_08053634(void) {
gUI.nextToLoad = 3;
MessageInitialize();
}
void sub_08053648(void) {
Entity* obj = CreateObject(SMOKE, 0, 0);
if (obj != NULL) {
obj->x.HALF.HI = gRoomControls.origin_x + 0x2d0;
obj->y.HALF.HI = gRoomControls.origin_y + 0x148;
}
}
void sub_0805367C(void) {
gMenu.overlayType++;
}
void sub_0805368C(void) {
Entity* entity = FindEntityByID(OBJECT, HOUSE_DOOR_INT, 6);
if (entity != NULL) {
DeleteEntity(entity);
SoundReq(SFX_F0);
}
}
void sub_080536A8(void) {
sub_080A71C4(5, 5, 4, 0x10);
}
void sub_080536B8(void) {
sub_080A71C4(5, 3, 4, 4);
SetFade(5, 0x100);
}
void sub_080536D4(void) {
gUnk_080FCCFC[gMenu.overlayType]();
}
void sub_080536F0(void) {
gUnk_080FCD38[gMenu.overlayType]();
}
void sub_0805370C(void) {
gMenu.overlayType++;
gUpdateVisibleTiles = 1;
sub_08051FF0();
LoadRoomEntityList((EntityData*)gUnk_080FCC54);
SetFade(4, 0x10);
}
void sub_0805373C(void) {
gUnk_080FCD40[gMenu.overlayType]();
}
ASM_FUNC("asm/non_matching/game/sub_08053758.inc", void sub_08053758())
ASM_FUNC("asm/non_matching/game/sub_08053800.inc", void sub_08053800())
ASM_FUNC("asm/non_matching/game/sub_08053894.inc", void sub_08053894())
ASM_FUNC("asm/non_matching/game/sub_08053904.inc", void sub_08053904())
void sub_08053974(void) {
if (gFadeControl.active == 0) {
InitFade();
DispReset(1);
SetBGDefaults();
sub_08051F78();
LoadRoomEntityList((EntityData*)&gUnk_080FCBC4);
SetFade(5, 0x100);
gMenu.overlayType++;
}
}
void nullsub_482(void) {
}
void sub_080539BC(void) {
SetBGDefaults();
DeleteAllEntities();
sub_08051F9C(0x22, 0x11, 0, 0);
sub_0804B0B0(0x22, 0x11);
LoadRoomEntityList((EntityData*)&gUnk_080FCC14);
gMenu.overlayType++;
}
void sub_080539F4(void) {
if (gFadeControl.active == 0) {
DispReset(1);
gMenu.overlayType++;
gMenu.transitionTimer = 0x3c;
}
}
void sub_08053A1C(void) {
gMenu.transitionTimer--;
if (gMenu.transitionTimer == 0) {
gMenu.overlayType++;
gMenu.transitionTimer = 8;
MessageFromTarget(0xf07);
gMessage.textWindowPosX = 1;
gMessage.textWindowPosY = 8;
SetFade(4, 8);
}
}
void sub_08053A5C(void) {
if (((gMessage.doTextBox & 0x7f) == 0) && --gMenu.transitionTimer == 0) {
gMenu.overlayType++;
SetFade(5, 8);
}
}
void sub_08053A90(void) {
if (gFadeControl.active == 0) {
gUI.nextToLoad = 3;
SetBGDefaults();
}
}
void sub_08053AB0(void) {
gUnk_080FCDD4[gMenu.overlayType]();
}
void sub_08053ACC(void) {
gMenu.overlayType++;
gUpdateVisibleTiles = 1;
sub_08051FF0();
LoadRoomEntityList((EntityData*)&gUnk_080FCD84);
SetFade(5, 0x100);
}
void sub_08053B00(void) {
gMenu.overlayType++;
}
void sub_08053B10(void) {
if (CheckRoomFlag(1)) {
gMenu.menuType++;
DispReset(1);
SetFade(4, 0x100);
}
}
void sub_08053B3C(void) {
sub_080A71C4(5, 4, 5, 0x100);
SetFade(5, 0x100);
}
void sub_08053B58(void) {
gUnk_080FCEB0[gMenu.overlayType]();
}
void sub_08053B74(void) {
gMenu.overlayType++;
gUpdateVisibleTiles = 1;
LoadRoomEntityList((EntityData*)&gUnk_080FCDE0);
ResetSystemPriority();
ResetEntityPriority();
SetFade(5, 0x100);
}
void sub_08053BAC(void) {
gMenu.overlayType++;
}
void sub_08053BBC(void) {
if (CheckRoomFlag(0)) {
gMenu.menuType++;
DispReset(1);
SetFade(4, 0x100);
}
}
void sub_08053BE8(void) {
sub_080A71C4(5, 2, 5, 0x100);
SetFade(5, 0x100);
}
void sub_08053C04(void) {
gUnk_080FCEEC[gMenu.overlayType]();
}
void sub_08053C20(void) {
gMenu.overlayType = 1;
gMenu.transitionTimer = 0x78;
gUpdateVisibleTiles = 1;
sub_08051FF0();
sub_0805B4D0(4);
LoadRoomEntityList((EntityData*)&gUnk_080FCEBC);
SetFade(4, 0x10);
SoundReq(BGM_FIGHT_THEME2);
}
void nullsub_483(void) {
}
void sub_08053C60(void) {
SetFade(5, 2);
SoundReq(SFX_SUMMON);
SoundReq(SONG_STOP_BGM);
SetTask(3);
}
void sub_08053C84(void) {
gMenu.overlayType = 2;
}
void CutsceneMain_Exit(void) {
gUnk_080FCEF8[gMenu.field_0x3]();
}
void sub_08053CAC(void) {
gUnk_080FCFA4[gMenu.overlayType]();
}
ASM_FUNC("asm/non_matching/game/sub_08053CC8.inc", void sub_08053CC8())
void sub_08053D34(void) {
if (gMenu.field_0xa != 0) {
gMenu.field_0xa = 0;
if (CheckLocalFlagByBank(0x680, 0x3d)) {
SetTileType(0x74, 0xc4, 1);
}
if (CheckLocalFlagByBank(0x680, 0x3e)) {
SetTileType(0x74, 0xcc, 1);
}
}
if (gFadeControl.active == 0) {
gMenu.transitionTimer = 0x78;
gMenu.overlayType++;
}
}
void sub_08053D90(void) {
gMenu.transitionTimer--;
if (gMenu.transitionTimer == 0) {
gMenu.overlayType++;
SetFadeInverted(0x10);
}
}
void sub_08053DB4(void) {
if (gFadeControl.active == 0) {
u8* ptr = gMenu.field_0xc;
sub_08052FF4(gMenu.field_0xc[4], gMenu.field_0xc[5]);
sub_0807C740();
gUpdateVisibleTiles = 1;
gRoomControls.scroll_x = (s8)ptr[6] + gRoomControls.scroll_x;
gRoomControls.scroll_y = (s8)ptr[7] + gRoomControls.scroll_y;
LoadRoomEntityList(*(EntityData**)ptr);
LoadRoomEntityList((EntityData*)GetRoomProperty(ptr[4], ptr[5], 1));
LoadRoomEntityList((EntityData*)GetRoomProperty(ptr[4], ptr[5], 2));
gMenu.transitionTimer = 0x78;
gMenu.overlayType++;
SetFadeInverted(0x10);
}
}
void sub_08053E30(void) {
if ((gFadeControl.active == 0) && --gMenu.transitionTimer == 0) {
gMenu.menuType++;
}
}
void sub_08053E58(void) {
gUnk_080FD108[gMenu.overlayType]();
}
void sub_08053E74(void) {
const EntityData** ptr = gUnk_080FCFB8;
gMenu.field_0xc = (u8*)ptr;
LoadRoomEntityList((EntityData*)ptr[0]);
gMenu.transitionTimer = 0x78;
gMenu.field_0xa = 0x3c;
gMenu.overlayType++;
gScreen.lcd.displayControl &= 0xfeff;
gUpdateVisibleTiles = 1;
SetMinPriority(1);
SetFade(4, 8);
}
void sub_08053EC4(void) {
EntityData** data;
if ((gFadeControl.active == 0) && (--gMenu.field_0xa == 0)) {
data = (EntityData**)(gMenu.field_0xc + 4);
gMenu.field_0xc += 0xc;
LoadRoomEntityList(*data);
gMenu.overlayType++;
}
}
void sub_08053EFC(void) {
if (--gMenu.transitionTimer == 0) {
gMenu.overlayType++;
SetFadeInverted(8);
}
}
void sub_08053F20(void) {
u8* ptr;
if (gFadeControl.active == 0) {
DeleteAllEntities();
ptr = gMenu.field_0xc;
sub_08052FF4(gMenu.field_0xc[8], gMenu.field_0xc[9]);
sub_0807C740();
gUpdateVisibleTiles = 1;
gRoomControls.scroll_x = (s8)ptr[10] + gRoomControls.scroll_x;
gRoomControls.scroll_y = (s8)ptr[0xb] + gRoomControls.scroll_y;
LoadRoomEntityList(*(EntityData**)ptr);
gMenu.transitionTimer = 0x78;
gMenu.field_0xa = 0x3c;
gMenu.overlayType++;
SetFadeInverted(8);
}
}
void sub_08053F88(void) {
if ((gFadeControl.active == 0) && --gMenu.transitionTimer == 0) {
gMenu.menuType++;
ResetEntityPriority();
}
}
void CutsceneMain_Update(void) {
gUnk_080FD138[gMenu.field_0x3]();
}
u32 GetSaleItemConfirmMessageID(u32 item) {
const u16* ptr = &gUnk_080FD964[item * 4];
return ptr[2];
}
s32 GetItemPrice(u32 item) {
const u16* ptr = &gUnk_080FD964[item * 4];
return ptr[0];
}
ASM_FUNC("asm/non_matching/game/GiveItem.inc", void GiveItem(u32 a, u32 b))
// TODO Adapt ItemMetaData struct
void sub_08054288(s32 param_1) {
const ItemMetaData* ptr1 = gItemMetaData;
u16* ptr = (u16*)&((ptr1)[param_1]);
MessageFromTarget(ptr[3]);
}
u32 sub_0805429C(s32 param_1) {
const ItemMetaData* ptr1 = gItemMetaData;
u16* ptr = (u16*)&((ptr1)[param_1]);
return ptr[2];
}
u32 sub_080542AC(u32 param_1) {
const ItemMetaData* ptr1 = gItemMetaData;
u8* ptr = (u8*)&((ptr1)[param_1]);
return ptr[3] & 1;
}
void ModShells(s32 shells) {
if (shells == 0) {
shells = 1;
}
shells += gSave.stats.shells;
if (shells < 0) {
shells = 0;
} else if (999 < shells) {
shells = 999;
}
gSave.stats.shells = shells;
}
void ModBombs(s32 bombs) {
s32 bombCount = bombs;
s32 bagSize;
bombCount += gSave.stats.bombCount;
bagSize = gBombBagSizes[gSave.stats.bombBagType];
if (bombCount < 0) {
bombCount = 0;
} else if (bagSize < bombCount) {
bombCount = bagSize;
}
gSave.stats.bombCount = bombCount;
}
void ModArrows(s32 arrows) {
s32 quiverSize;
s32 arrowCount = arrows;
arrowCount += gSave.stats.arrowCount;
quiverSize = gQuiverSizes[gSave.stats.quiverType];
if (arrowCount < 0) {
arrowCount = 0;
} else if (quiverSize < arrowCount) {
arrowCount = quiverSize;
}
gSave.stats.arrowCount = arrowCount;
}
/**
* @brief Returns the slot the item is equipped in.
*
* 0: A
* 1: B
* 2: Not equipped
*/
u32 IsItemEquipped(u32 itemID) {
u32 itemSlot;
if (itemID == gSave.stats.itemButtons[SLOT_A])
itemSlot = 0;
else if (itemID == gSave.stats.itemButtons[SLOT_B])
itemSlot = 1;
else
itemSlot = 2;
return itemSlot;
}
void PutItemOnSlot(u32 itemID) {
u32 itemSlot;
u32 itemID2 = itemID;
if (itemID2 < 0x47) {
SetInventoryValue(0, 1);
}
if (itemID2 - 1 < 0x1f) {
itemSlot = 2;
if (gSave.stats.itemButtons[SLOT_A] == 0) {
itemSlot = 0;
} else if (gSave.stats.itemButtons[SLOT_B] == 0) {
itemSlot = 1;
}
if (itemSlot == 2) {
u32 temp = gItemMetaData[itemID2].menuSlot;
if (temp == gItemMetaData[gSave.stats.itemButtons[SLOT_A]].menuSlot) {
itemSlot = 0;
} else {
if (temp == gItemMetaData[gSave.stats.itemButtons[SLOT_B]].menuSlot) {
itemSlot = 1;
}
}
if (itemSlot == 2) {
return;
}
}
ForceEquipItem(itemID2, itemSlot);
}
}
void ForceEquipItem(u32 itemID, u32 itemSlot) {
u32 otherItem;
u32 otherItemIndex;
u32 replacedItem;
if ((itemID - 1 < 0x1f) && (itemSlot < 2)) {
otherItemIndex = itemSlot == 0;
replacedItem = gSave.stats.itemButtons[itemSlot];
otherItem = gSave.stats.itemButtons[otherItemIndex];
if (gItemMetaData[otherItem].menuSlot == gItemMetaData[itemID].menuSlot) {
otherItem = replacedItem;
}
gSave.stats.itemButtons[itemSlot] = itemID;
gSave.stats.itemButtons[otherItemIndex] = otherItem;
gUnk_0200AF00.filler0[0x13] = 0x7f;
gUnk_0200AF00.filler0[0x14] = 0x7f;
}
}
u32 SetBottleContents(u32 itemID, u32 bottleIndex) {
if (bottleIndex > 3) {
bottleIndex = 0;
if (gSave.stats.bottles[0] != 0x20) {
do {
bottleIndex++;
if (bottleIndex > 3) {
return bottleIndex;
}
} while (gSave.stats.bottles[bottleIndex] != 0x20);
}
if (bottleIndex > 3) {
return bottleIndex;
}
}
gSave.stats.bottles[bottleIndex] = itemID;
return bottleIndex;
}
bool32 ItemIsSword(u32 item) {
switch (item) {
case ITEM_SMITH_SWORD:
case ITEM_GREEN_SWORD:
case ITEM_RED_SWORD:
case ITEM_BLUE_SWORD:
case ITEM_FOURSWORD:
return TRUE;
default:
return FALSE;
}
}
bool32 ItemIsShield(u32 id) {
switch (id) {
case 13:
case 14:
return 1;
default:
return 0;
}
}
bool32 ItemIsBottle(u32 id) {
switch (id) {
case 28:
case 29:
case 30:
case 31:
return 1;
default:
return 0;
}
}
u32 GetBottleContaining(u32 id) {
if (id == gSave.stats.bottles[0]) {
return 1;
} else if (id == gSave.stats.bottles[1]) {
return 2;
} else if (id == gSave.stats.bottles[2]) {
return 3;
} else if (id == gSave.stats.bottles[3]) {
return 4;
} else {
return 0;
}
}
void sub_08054524(void) {
u32 bVar1;
bVar1 = gArea.locationIndex;
if (gArea.locationIndex == 0) {
bVar1 = gRoomTransition.player_status.field_0x24[0xa];
}
if (bVar1 > 0x16) {
bVar1 = 0;
}
bVar1 = gUnk_080FE1C6[bVar1];
MemCopy(&gAreaDroptables[bVar1], &gRoomVars.currentAreaDroptable, 0x20);
}
void sub_08054564(void) {
gRoomVars.field_0x2 = 1;
}
void sub_08054570(void) {
gRoomVars.field_0x2 = 0;
}
extern void sub_08000F14(s16*, const s16*, const s16*, const s16*);
extern u32 sub_08000F2C(s16*, const s16*, const s16*, const s16*);
u32 CreateItemDrop(Entity* arg0, u32 itemID, u32 itemParameter);
u32 CreateRandomItemDrop(Entity* arg0, u32 arg1) {
extern const u8 gUnk_080FE1B4[] /* = {
ITEM_NONE, ITEM_RUPEE1, ITEM_RUPEE5, ITEM_RUPEE20, ITEM_HEART, ITEM_FAIRY,
ITEM_BOMBS5, ITEM_ARROWS5, ITEM_SHELLS, ITEM_KINSTONE_GREEN, ITEM_KINSTONE_BLUE, ITEM_KINSTONE_RED,
ITEM_ENEMY_BEETLE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE,
}*/;
int r0, r1, rand, summOdds, item;
u32 r3;
const Droptable *ptr2, *ptr3, *ptr4;
Droptable droptable;
r3 = arg1;
if (gRoomVars.field_0x2 != 1) {
ptr2 = &gDroptableModifiers[DROPTABLE_NONE];
ptr4 = NULL;
switch (r3) {
case 1 ... 12:
ptr4 = &gEnemyDroptables[r3];
break;
#ifndef EU
case 24:
case 25:
r0 = gRoomVars.unk2;
ptr4 = &gUnk_0800191C[0];
if (r0) {
ptr4++;
}
break;
#endif
case 16 ... 23:
#ifdef EU
case 24:
#endif
ptr2 = &gObjectDroptables[r3 - 16];
case 15:
ptr4 = &gRoomVars.currentAreaDroptable;
break;
case 0:
default:
break;
}
if (ptr4 != 0) {
if ((r1 = gSave.stats.picolyteType) == 0) {
// nop
ptr3 = &gDroptableModifiers[DROPTABLE_NONE];
} else {
#ifdef EU
ptr3 = &gEnemyDroptables[r1 + 9];
#else
ptr3 = &gEnemyDroptables[r1 + 6];
#endif
}
// vector addition, s0 = ptr4 + ptr2 + ptr3
sub_08000F14(droptable.a, ptr4->a, ptr2->a, ptr3->a);
if (gSave.stats.health <= 8) {
droptable.s.hearts += 5;
}
if (gSave.stats.bombCount == 0) {
droptable.s.bombs += 3;
}
if (gSave.stats.arrowCount == 0) {
droptable.s.arrows += 3;
}
if (gSave.stats.rupees <= 10) {
droptable.s.rupee5 += 1;
}
ptr2 = &gDroptableModifiers[DROPTABLE_NONE];
r0 = gSave.stats.hasAllFigurines;
ptr3 = &gDroptableModifiers[DROPTABLE_NONE];
// don't drop shells anymore
if (r0 != 0) {
ptr2 = &gDroptableModifiers[DROPTABLE_NO_SHELLS];
}
// don't drop kinstones anymore
if (gSave.didAllFusions != 0) {
ptr3 = &gDroptableModifiers[DROPTABLE_NO_KINSTONES];
}
// vector addition, s0 = s0 + ptr2 + ptr3
// resulting values are clamped to be >= 0
// returns sum over s0
summOdds = sub_08000F2C(droptable.a, droptable.a, ptr2->a, ptr3->a);
rand = Random();
item = (rand >> 0x18);
item &= 0xF;
rand = rand % summOdds;
{
u32 r3;
for (r3 = 0, r1 = 0; r3 < 0x10; r3++, item = (item + 1) & 0xF) {
if ((r1 += droptable.a[item]) > rand) {
break;
}
}
}
r1 = gUnk_080FE1B4[item];
if (r1 != ITEM_NONE) {
return CreateItemDrop(arg0, r1, 0);
}
}
}
return ITEM_NONE;
}
u32 CreateItemDrop(Entity* arg0, u32 itemID, u32 itemParameter) {
u32 adjustedParam = itemParameter;
Entity* itemEntity;
switch (itemID) {
case ITEM_ENEMY_BEETLE:
if (!GetInventoryValue(ITEM_SMITH_SWORD)) {
return ITEM_NONE;
}
break;
case ITEM_BOMBS5:
if (!GetInventoryValue(ITEM_BOMBBAG)) {
return ITEM_NONE;
}
break;
case ITEM_ARROWS5:
if (!GetInventoryValue(ITEM_BOW)) {
return ITEM_NONE;
}
break;
case ITEM_SHELLS: {
if (!GetInventoryValue(ITEM_EARTH_ELEMENT)) {
return ITEM_NONE;
}
if (itemParameter == 0) {
adjustedParam = 1;
}
break;
}
case ITEM_KINSTONE:
case ITEM_KINSTONE_GREEN ... ITEM_KINSTONE_RED: {
u32 rand;
if (GetInventoryValue(ITEM_KINSTONE_BAG) == 0) {
return ITEM_NONE;
}
if (3 < gRoomVars.filler1[0]) {
return ITEM_NONE;
}
if (itemID != ITEM_KINSTONE) {
adjustedParam = itemID - ITEM_KINSTONE_GREEN;
rand = (Random() & 0x3f);
adjustedParam = gUnk_080FE1DD[(rand + adjustedParam * 0x40)];
if (adjustedParam == 0) {
itemID = ITEM_NONE;
} else {
itemID = ITEM_KINSTONE;
}
}
break;
}
}
if (itemID != ITEM_NONE) {
if (itemID != ITEM_ENEMY_BEETLE) {
itemEntity = CreateObject(GROUND_ITEM, itemID, adjustedParam);
if (itemEntity != NULL) {
if (arg0 == &gPlayerEntity) {
itemEntity->actionDelay = 1;
} else {
itemEntity->actionDelay = 0;
}
if (arg0->kind == OBJECT) {
if (arg0->id == 99) {
arg0->child = itemEntity;
} else if (arg0->id == 0x1e) {
itemEntity->direction = arg0->animationState << 3 | 0x80;
itemEntity->speed = 0xc0;
itemEntity->zVelocity = Q_16_16(1.5);
}
}
CopyPosition(arg0, itemEntity);
}
} else {
itemEntity = CreateEnemy(BEETLE, 0);
if (itemEntity != NULL) {
itemEntity->x.HALF.HI = arg0->x.HALF.HI;
itemEntity->y.HALF.HI = arg0->y.HALF.HI;
itemEntity->collisionLayer = arg0->collisionLayer;
UpdateSpriteForCollisionLayer(itemEntity);
}
}
}
return itemID;
}
void Subtask_WorldEvent(void) {
#if !(defined(DEMO_USA) || defined(DEMO_JP))
gUnk_080FE2A0[gMenu.menuType]();
#endif
}
ASM_FUNC("asm/non_matching/game/sub_0805488C.inc", void sub_0805488C())
void sub_080548E8(void) {
gUnk_080FE2AC[gMenu.field_0x0]();
FlushSprites();
UpdateEntities();
DrawEntities();
CopyOAM();
UpdateScroll();
UpdateBgAnim();
UpdateScrollVram();
}
ASM_FUNC("asm/non_matching/game/sub_08054920.inc", void sub_08054920())
void sub_08054968(void) {
gMenu.menuType = 2;
}
ASM_FUNC("asm/non_matching/game/sub_08054974.inc", void sub_08054974())
ASM_FUNC("asm/non_matching/game/sub_08054A14.inc", void sub_08054A14())