mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-11-18 20:47:40 +01:00
575 lines
13 KiB
C
575 lines
13 KiB
C
#include "global.h"
|
|
#include "alloc.h"
|
|
#include "task.h"
|
|
#include "main.h"
|
|
#include "overworld.h"
|
|
#include "field_weather.h"
|
|
#include "palette.h"
|
|
#include "pokemon_storage_system.h"
|
|
#include "pokenav.h"
|
|
|
|
#define LOOPED_TASK_DECODE_STATE(action) (action - 5)
|
|
|
|
#define LOOPED_TASK_ID(primary, secondary) (((secondary) << 16) |(primary))
|
|
#define LOOPED_TASK_PRIMARY_ID(taskId) (taskId & 0xFFFF)
|
|
#define LOOPED_TASK_SECONDARY_ID(taskId) (taskId >> 16)
|
|
|
|
#define SUBSTRUCT_COUNT 19
|
|
|
|
struct PokenavResources
|
|
{
|
|
u32 (*currentMenuCb1)(void);
|
|
u32 currentMenuIndex;
|
|
u16 mode;
|
|
u16 fieldA;
|
|
bool32 hasAnyRibbons;
|
|
void *field10[SUBSTRUCT_COUNT];
|
|
};
|
|
|
|
struct UnknownPokenavCallbackStruct
|
|
{
|
|
bool32 (*unk0)(void);
|
|
u32 (*unk4)(void);
|
|
bool32 (*unk8)(void);
|
|
void (*unkC)(s32);
|
|
u32 (*unk10)(void);
|
|
void (*unk14)(void);
|
|
void (*unk18)(void);
|
|
};
|
|
|
|
static u32 sub_81C75E0(void);
|
|
static u32 sub_81C75D4(void);
|
|
static bool32 SetActivePokenavMenu(u32 menuId);
|
|
static bool32 AnyMonHasRibbon(void);
|
|
static void InitPokenavResources(struct PokenavResources *a0);
|
|
static void InitKeys_(void);
|
|
static void FreePokenavResources(void);
|
|
static void VBlankCB_Pokenav(void);
|
|
static void CB2_Pokenav(void);
|
|
static void Task_RunLoopedTask_LinkMode(u8 a0);
|
|
static void Task_RunLoopedTask(u8 taskId);
|
|
static void sub_81C742C(u8 taskId);
|
|
static void sub_81C72BC(void);
|
|
|
|
const struct UnknownPokenavCallbackStruct PokenavMenuCallbacks[15] =
|
|
{
|
|
{
|
|
.unk0 = PokenavCallback_Init_0,
|
|
.unk4 = sub_81C941C,
|
|
.unk8 = sub_81C9924,
|
|
.unkC = sub_81C9990,
|
|
.unk10 = sub_81C99C0,
|
|
.unk14 = sub_81C9430,
|
|
.unk18 = sub_81C99D4,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_0,
|
|
.unk4 = sub_81C941C,
|
|
.unk8 = sub_81C9940,
|
|
.unkC = sub_81C9990,
|
|
.unk10 = sub_81C99C0,
|
|
.unk14 = sub_81C9430,
|
|
.unk18 = sub_81C99D4,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_2,
|
|
.unk4 = sub_81C941C,
|
|
.unk8 = sub_81C9940,
|
|
.unkC = sub_81C9990,
|
|
.unk10 = sub_81C99C0,
|
|
.unk14 = sub_81C9430,
|
|
.unk18 = sub_81C99D4,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_3,
|
|
.unk4 = sub_81C941C,
|
|
.unk8 = sub_81C9940,
|
|
.unkC = sub_81C9990,
|
|
.unk10 = sub_81C99C0,
|
|
.unk14 = sub_81C9430,
|
|
.unk18 = sub_81C99D4,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_4,
|
|
.unk4 = sub_81C941C,
|
|
.unk8 = sub_81C9940,
|
|
.unkC = sub_81C9990,
|
|
.unk10 = sub_81C99C0,
|
|
.unk14 = sub_81C9430,
|
|
.unk18 = sub_81C99D4,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_5,
|
|
.unk4 = sub_81C941C,
|
|
.unk8 = sub_81C9940,
|
|
.unkC = sub_81C9990,
|
|
.unk10 = sub_81C99C0,
|
|
.unk14 = sub_81C9430,
|
|
.unk18 = sub_81C99D4,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_6,
|
|
.unk4 = sub_81CC554,
|
|
.unk8 = sub_81CC5F4,
|
|
.unkC = sub_81CC62C,
|
|
.unk10 = sub_81CC65C,
|
|
.unk14 = sub_81CC524,
|
|
.unk18 = sub_81CC670,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_7,
|
|
.unk4 = sub_81CD070,
|
|
.unk8 = sub_81CDDD4,
|
|
.unkC = sub_81CDE2C,
|
|
.unk10 = sub_81CDE64,
|
|
.unk14 = sub_81CD1C0,
|
|
.unk18 = sub_81CECA0,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_8,
|
|
.unk4 = sub_81CEFDC,
|
|
.unk8 = sub_81CF330,
|
|
.unkC = sub_81CF3A0,
|
|
.unk10 = sub_81CF3D0,
|
|
.unk14 = sub_81CEFF0,
|
|
.unk18 = sub_81CF3F8,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_9,
|
|
.unk4 = sub_81CD070,
|
|
.unk8 = sub_81CDDD4,
|
|
.unkC = sub_81CDE2C,
|
|
.unk10 = sub_81CDE64,
|
|
.unk14 = sub_81CD1C0,
|
|
.unk18 = sub_81CECA0,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_10,
|
|
.unk4 = sub_81CEFDC,
|
|
.unk8 = sub_81CF368,
|
|
.unkC = sub_81CF3A0,
|
|
.unk10 = sub_81CF3D0,
|
|
.unk14 = sub_81CEFF0,
|
|
.unk18 = sub_81CF3F8,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_11,
|
|
.unk4 = sub_81CAB24,
|
|
.unk8 = sub_81CB260,
|
|
.unkC = sub_81CB29C,
|
|
.unk10 = sub_81CB2CC,
|
|
.unk14 = sub_81CAB38,
|
|
.unk18 = sub_81CB2E0,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_12,
|
|
.unk4 = sub_81CFA34,
|
|
.unk8 = sub_81CFDD0,
|
|
.unkC = sub_81CFE40,
|
|
.unk10 = sub_81CFE70,
|
|
.unk14 = sub_81CFA48,
|
|
.unk18 = sub_81CFE98,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_13,
|
|
.unk4 = sub_81D04A0,
|
|
.unk8 = sub_81D0978,
|
|
.unkC = sub_81D09B0,
|
|
.unk10 = sub_81D09E0,
|
|
.unk14 = sub_81D04B8,
|
|
.unk18 = sub_81D09F4,
|
|
},
|
|
{
|
|
.unk0 = PokenavCallback_Init_14,
|
|
.unk4 = sub_81CFA34,
|
|
.unk8 = sub_81CFE08,
|
|
.unkC = sub_81CFE40,
|
|
.unk10 = sub_81CFE70,
|
|
.unk14 = sub_81CFA48,
|
|
.unk18 = sub_81CFE98,
|
|
},
|
|
};
|
|
|
|
EWRAM_DATA u8 gNextLoopedTaskId = 0;
|
|
EWRAM_DATA struct PokenavResources *gPokenavResources = NULL;
|
|
|
|
// code
|
|
u32 CreateLoopedTask(LoopedTask loopedTask, u32 priority)
|
|
{
|
|
u16 taskId;
|
|
|
|
if (!IsUpdateLinkStateCBActive())
|
|
taskId = CreateTask(Task_RunLoopedTask, priority);
|
|
else
|
|
taskId = CreateTask(Task_RunLoopedTask_LinkMode, priority);
|
|
|
|
SetWordTaskArg(taskId, 1, (u32)loopedTask);
|
|
|
|
gTasks[taskId].data[3] = gNextLoopedTaskId;
|
|
return LOOPED_TASK_ID(taskId, gNextLoopedTaskId++);
|
|
}
|
|
|
|
bool32 IsLoopedTaskActive(u32 taskId)
|
|
{
|
|
u32 primaryId = LOOPED_TASK_PRIMARY_ID(taskId);
|
|
u32 secondaryId = LOOPED_TASK_SECONDARY_ID(taskId);
|
|
|
|
if (gTasks[primaryId].isActive
|
|
&& (gTasks[primaryId].func == Task_RunLoopedTask || gTasks[primaryId].func == Task_RunLoopedTask_LinkMode)
|
|
&& gTasks[primaryId].data[3] == secondaryId)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
bool32 FuncIsActiveLoopedTask(LoopedTask func)
|
|
{
|
|
int i;
|
|
for (i = 0; i < NUM_TASKS; i++)
|
|
{
|
|
if (gTasks[i].isActive
|
|
&& (gTasks[i].func == Task_RunLoopedTask || gTasks[i].func == Task_RunLoopedTask_LinkMode)
|
|
&& (LoopedTask)GetWordTaskArg(i, 1) == func)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void Task_RunLoopedTask(u8 taskId)
|
|
{
|
|
LoopedTask loopedTask = (LoopedTask)GetWordTaskArg(taskId, 1);
|
|
s16 *state = &gTasks[taskId].data[0];
|
|
bool32 exitLoop = FALSE;
|
|
|
|
while (!exitLoop)
|
|
{
|
|
u32 action = loopedTask(*state);
|
|
switch (action)
|
|
{
|
|
case LT_INC_AND_CONTINUE:
|
|
(*state)++;
|
|
break;
|
|
case LT_INC_AND_PAUSE:
|
|
(*state)++;
|
|
return;
|
|
case LT_FINISH:
|
|
DestroyTask(taskId);
|
|
return;
|
|
// case LT_SET_STATE:
|
|
default:
|
|
*state = LOOPED_TASK_DECODE_STATE(action);
|
|
break;
|
|
case LT_CONTINUE:
|
|
break;
|
|
case LT_PAUSE:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Every "Continue" action pauses instead.
|
|
static void Task_RunLoopedTask_LinkMode(u8 taskId)
|
|
{
|
|
LoopedTask task;
|
|
s16 *state;
|
|
u32 action;
|
|
|
|
if (sub_8087598())
|
|
return;
|
|
|
|
task = (LoopedTask)GetWordTaskArg(taskId, 1);
|
|
state = &gTasks[taskId].data[0];
|
|
action = task(*state);
|
|
switch (action)
|
|
{
|
|
case LT_INC_AND_PAUSE:
|
|
case LT_INC_AND_CONTINUE:
|
|
(*state)++;
|
|
break;
|
|
case LT_FINISH:
|
|
DestroyTask(taskId);
|
|
break;
|
|
// case: LT_SET_STATE:
|
|
default:
|
|
*state = LOOPED_TASK_DECODE_STATE(action);
|
|
break;
|
|
case LT_PAUSE:
|
|
case LT_CONTINUE:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CB2_InitPokeNav(void)
|
|
{
|
|
gPokenavResources = Alloc(sizeof(*gPokenavResources));
|
|
if (gPokenavResources == NULL)
|
|
{
|
|
SetMainCallback2(CB2_ReturnToFieldWithOpenMenu);
|
|
}
|
|
else
|
|
{
|
|
InitPokenavResources(gPokenavResources);
|
|
ResetTasks();
|
|
SetVBlankCallback(NULL);
|
|
CreateTask(sub_81C742C, 0);
|
|
SetMainCallback2(CB2_Pokenav);
|
|
SetVBlankCallback(VBlankCB_Pokenav);
|
|
}
|
|
}
|
|
|
|
void sub_81C72A4(void)
|
|
{
|
|
SetMainCallback2(sub_81C72BC);
|
|
FadeScreen(1, 0);
|
|
}
|
|
|
|
static void sub_81C72BC(void)
|
|
{
|
|
UpdatePaletteFade();
|
|
if (gPaletteFade.active)
|
|
return;
|
|
|
|
gPokenavResources = Alloc(sizeof(*gPokenavResources));
|
|
if (gPokenavResources == NULL)
|
|
{
|
|
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
|
|
}
|
|
else
|
|
{
|
|
InitPokenavResources(gPokenavResources);
|
|
gPokenavResources->mode = POKENAV_MODE_FORCE_CALL_1;
|
|
ResetTasks();
|
|
ResetSpriteData();
|
|
FreeAllSpritePalettes();
|
|
SetVBlankCallback(NULL);
|
|
CreateTask(sub_81C742C, 0);
|
|
SetMainCallback2(CB2_Pokenav);
|
|
SetVBlankCallback(VBlankCB_Pokenav);
|
|
}
|
|
}
|
|
|
|
static void FreePokenavResources(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < SUBSTRUCT_COUNT; i++)
|
|
FreePokenavSubstruct(i);
|
|
|
|
FREE_AND_SET_NULL(gPokenavResources);
|
|
InitKeys();
|
|
}
|
|
|
|
static void InitPokenavResources(struct PokenavResources *a0)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < SUBSTRUCT_COUNT; i++)
|
|
a0->field10[i] = NULL;
|
|
|
|
a0->mode = POKENAV_MODE_NORMAL;
|
|
a0->currentMenuIndex = 0;
|
|
a0->hasAnyRibbons = AnyMonHasRibbon();
|
|
a0->currentMenuCb1 = NULL;
|
|
}
|
|
|
|
static bool32 AnyMonHasRibbon(void)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < PARTY_SIZE; i++)
|
|
{
|
|
if (GetMonData(&gPlayerParty[i], MON_DATA_SANITY_HAS_SPECIES)
|
|
&& !GetMonData(&gPlayerParty[i], MON_DATA_SANITY_IS_EGG)
|
|
&& GetMonData(&gPlayerParty[i], MON_DATA_RIBBON_COUNT) != 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < TOTAL_BOXES_COUNT; j++)
|
|
{
|
|
for (i = 0; i < IN_BOX_COUNT; i++)
|
|
{
|
|
if (CheckBoxMonSanityAt(j, i)
|
|
&& GetBoxMonDataAt(j, i, MON_DATA_RIBBON_COUNT) != 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void CB2_Pokenav(void)
|
|
{
|
|
RunTasks();
|
|
AnimateSprites();
|
|
BuildOamBuffer();
|
|
UpdatePaletteFade();
|
|
}
|
|
|
|
static void VBlankCB_Pokenav(void)
|
|
{
|
|
TransferPlttBuffer();
|
|
LoadOam();
|
|
ProcessSpriteCopyRequests();
|
|
}
|
|
|
|
static void sub_81C742C(u8 taskId)
|
|
{
|
|
u32 v1;
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
switch (data[0])
|
|
{
|
|
case 0:
|
|
InitPokenavMainMenu();
|
|
data[0] = 1;
|
|
break;
|
|
case 1:
|
|
// Wait for LoopedTask_InitPokenavMenu to finish
|
|
if (PokenavMainMenuLoopedTaskIsActive())
|
|
break;
|
|
SetActivePokenavMenu(POKENAV_MENU_0);
|
|
data[0] = 4;
|
|
break;
|
|
case 2:
|
|
if (sub_81C786C())
|
|
break;
|
|
data[0] = 3;
|
|
case 3:
|
|
v1 = sub_81C75E0();
|
|
if (v1 == -1)
|
|
{
|
|
ShutdownPokenav();
|
|
data[0] = 5;
|
|
}
|
|
else if (v1 >= POKENAV_MENU_IDS_START)
|
|
{
|
|
PokenavMenuCallbacks[gPokenavResources->currentMenuIndex].unk18();
|
|
PokenavMenuCallbacks[gPokenavResources->currentMenuIndex].unk14();
|
|
if (SetActivePokenavMenu(v1))
|
|
{
|
|
data[0] = 4;
|
|
}
|
|
else
|
|
{
|
|
ShutdownPokenav();
|
|
data[0] = 5;
|
|
}
|
|
}
|
|
else if (v1 != 0)
|
|
{
|
|
sub_81C7850(v1);
|
|
if (sub_81C786C())
|
|
data[0] = 2;
|
|
}
|
|
break;
|
|
case 4:
|
|
if (!sub_81C75D4())
|
|
data[0] = 3;
|
|
break;
|
|
case 5:
|
|
if (!WaitForPokenavShutdownFade())
|
|
{
|
|
bool32 calledFromScript = (gPokenavResources->mode != POKENAV_MODE_NORMAL);
|
|
|
|
sub_81C9430();
|
|
FreePokenavResources();
|
|
if (calledFromScript)
|
|
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
|
|
else
|
|
SetMainCallback2(CB2_ReturnToFieldWithOpenMenu);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bool32 SetActivePokenavMenu(u32 menuId)
|
|
{
|
|
u32 index = menuId - POKENAV_MENU_IDS_START;
|
|
|
|
InitKeys_();
|
|
if (!PokenavMenuCallbacks[index].unk0())
|
|
return FALSE;
|
|
if (!PokenavMenuCallbacks[index].unk8())
|
|
return FALSE;
|
|
|
|
sub_81C7834(PokenavMenuCallbacks[index].unkC, PokenavMenuCallbacks[index].unk10);
|
|
gPokenavResources->currentMenuCb1 = PokenavMenuCallbacks[index].unk4;
|
|
gPokenavResources->currentMenuIndex = index;
|
|
return TRUE;
|
|
}
|
|
|
|
static u32 sub_81C75D4(void)
|
|
{
|
|
return sub_81C786C();
|
|
}
|
|
|
|
static u32 sub_81C75E0(void)
|
|
{
|
|
return gPokenavResources->currentMenuCb1();
|
|
}
|
|
|
|
static void InitKeys_(void)
|
|
{
|
|
InitKeys();
|
|
}
|
|
|
|
void SetVBlankCallback_(IntrCallback callback)
|
|
{
|
|
SetVBlankCallback(callback);
|
|
}
|
|
|
|
void SetPokenavVBlankCallback(void)
|
|
{
|
|
SetVBlankCallback(VBlankCB_Pokenav);
|
|
}
|
|
|
|
void *AllocSubstruct(u32 index, u32 size)
|
|
{
|
|
gPokenavResources->field10[index] = Alloc(size);
|
|
return gPokenavResources->field10[index];
|
|
}
|
|
|
|
void *GetSubstructPtr(u32 index)
|
|
{
|
|
return gPokenavResources->field10[index];
|
|
}
|
|
|
|
void FreePokenavSubstruct(u32 index)
|
|
{
|
|
if (gPokenavResources->field10[index] != NULL)
|
|
FREE_AND_SET_NULL(gPokenavResources->field10[index]);
|
|
}
|
|
|
|
u32 GetPokenavMode(void)
|
|
{
|
|
return gPokenavResources->mode;
|
|
}
|
|
|
|
void SetPokenavMode(u16 mode)
|
|
{
|
|
gPokenavResources->mode = mode;
|
|
}
|
|
|
|
void sub_81C7694(u32 a0)
|
|
{
|
|
u32 value = a0;
|
|
|
|
if (value > 4)
|
|
value = 0;
|
|
gPokenavResources->fieldA = value;
|
|
}
|
|
|
|
u32 sub_81C76AC(void)
|
|
{
|
|
return gPokenavResources->fieldA;
|
|
}
|
|
|
|
bool32 CanViewRibbonsMenu(void)
|
|
{
|
|
return gPokenavResources->hasAnyRibbons;
|
|
}
|