diff options
author | GriffinR <griffin.g.richards@gmail.com> | 2021-10-24 15:50:39 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-24 15:50:39 -0400 |
commit | ab802649218507237cd2c07e318ef65e1caca5fe (patch) | |
tree | 48104eb5c96c07611ba511f11fc56e9cce6404d6 /src | |
parent | 3834cc2957b27c771c59027935b0b3a86a19b273 (diff) | |
parent | 6067aa65b4d16649785f39fc2e8ff253abb34327 (diff) |
Merge pull request #1519 from GriffinRichards/doc-mgift
Document Mystery Gift
Diffstat (limited to 'src')
-rw-r--r-- | src/cable_club.c | 12 | ||||
-rw-r--r-- | src/crt0.s | 2 | ||||
-rw-r--r-- | src/easy_chat.c | 2 | ||||
-rwxr-xr-x | src/ereader_screen.c | 32 | ||||
-rw-r--r-- | src/event_data.c | 60 | ||||
-rw-r--r-- | src/field_specials.c | 20 | ||||
-rw-r--r-- | src/link_rfu_2.c | 4 | ||||
-rw-r--r-- | src/main_menu.c | 8 | ||||
-rwxr-xr-x | src/mevent2.c | 630 | ||||
-rw-r--r-- | src/mevent_801BAAC.c | 826 | ||||
-rw-r--r-- | src/mevent_client.c | 291 | ||||
-rw-r--r-- | src/mevent_news.c | 148 | ||||
-rw-r--r-- | src/mevent_scripts.c | 191 | ||||
-rw-r--r-- | src/mevent_server.c | 295 | ||||
-rw-r--r-- | src/mevent_server_helpers.c | 211 | ||||
-rw-r--r-- | src/mystery_event_msg.c | 22 | ||||
-rw-r--r-- | src/mystery_event_script.c | 26 | ||||
-rwxr-xr-x[-rw-r--r--] | src/mystery_gift.c | 1966 | ||||
-rw-r--r-- | src/mystery_gift_client.c | 303 | ||||
-rw-r--r-- | src/mystery_gift_link.c | 222 | ||||
-rw-r--r-- | src/mystery_gift_menu.c | 1618 | ||||
-rw-r--r-- | src/mystery_gift_scripts.c | 217 | ||||
-rw-r--r-- | src/mystery_gift_server.c | 291 | ||||
-rw-r--r-- | src/mystery_gift_view.c | 936 | ||||
-rw-r--r-- | src/new_game.c | 4 | ||||
-rw-r--r-- | src/scrcmd.c | 2 | ||||
-rw-r--r-- | src/script.c | 15 | ||||
-rw-r--r-- | src/trade.c | 7 | ||||
-rwxr-xr-x | src/trainer_card.c | 34 | ||||
-rw-r--r-- | src/union_room.c | 50 | ||||
-rw-r--r-- | src/wonder_news.c | 160 |
31 files changed, 4378 insertions, 4227 deletions
diff --git a/src/cable_club.c b/src/cable_club.c index 8db583989..3083ed9c0 100644 --- a/src/cable_club.c +++ b/src/cable_club.c @@ -18,7 +18,7 @@ #include "overworld.h" #include "palette.h" #include "union_room.h" -#include "mevent2.h" +#include "mystery_gift.h" #include "script.h" #include "script_pokemon_util.h" #include "sound.h" @@ -372,7 +372,7 @@ static void Task_LinkupExchangeDataWithLeader(u8 taskId) gLocalLinkPlayerId = GetMultiplayerId(); SaveLinkPlayers(gFieldLinkPlayerCount); card = (struct TrainerCard *)gBlockSendBuffer; - TrainerCard_GenerateCardForPlayer(card); + TrainerCard_GenerateCardForLinkPlayer(card); card->monSpecies[0] = GetMonData(&gPlayerParty[gSelectedOrderFromParty[0] - 1], MON_DATA_SPECIES, NULL); card->monSpecies[1] = GetMonData(&gPlayerParty[gSelectedOrderFromParty[1] - 1], MON_DATA_SPECIES, NULL); gTasks[taskId].func = Task_LinkupAwaitTrainerCardData; @@ -420,7 +420,7 @@ static void Task_LinkupCheckStatusAfterConfirm(u8 taskId) gLocalLinkPlayerId = GetMultiplayerId(); SaveLinkPlayers(gFieldLinkPlayerCount); card = (struct TrainerCard *)gBlockSendBuffer; - TrainerCard_GenerateCardForPlayer(card); + TrainerCard_GenerateCardForLinkPlayer(card); card->monSpecies[0] = GetMonData(&gPlayerParty[gSelectedOrderFromParty[0] - 1], MON_DATA_SPECIES, NULL); card->monSpecies[1] = GetMonData(&gPlayerParty[gSelectedOrderFromParty[1] - 1], MON_DATA_SPECIES, NULL); gTasks[taskId].func = Task_LinkupAwaitTrainerCardData; @@ -518,7 +518,7 @@ static void Task_LinkupAwaitTrainerCardData(u8 taskId) for (index = 0; index < GetLinkPlayerCount(); index++) { - CopyTrainerCardData(&gTrainerCards[index], gBlockRecvBuffer[index], gLinkPlayers[index].version); + CopyTrainerCardData(&gTrainerCards[index], (struct TrainerCard *)gBlockRecvBuffer[index], gLinkPlayers[index].version); } SetSuppressLinkErrorMessage(FALSE); @@ -1004,10 +1004,10 @@ void CB2_ReturnFromCableClubBattle(void) switch (gBattleOutcome) { case B_OUTCOME_WON: - RecordIdOfWonderCardSenderByEventType(0, gLinkPlayers[GetMultiplayerId() ^ 1].trainerId); + MysteryGift_TryIncrementStat(CARD_STAT_BATTLES_WON, gLinkPlayers[GetMultiplayerId() ^ 1].trainerId); break; case B_OUTCOME_LOST: - RecordIdOfWonderCardSenderByEventType(1, gLinkPlayers[GetMultiplayerId() ^ 1].trainerId); + MysteryGift_TryIncrementStat(CARD_STAT_BATTLES_LOST, gLinkPlayers[GetMultiplayerId() ^ 1].trainerId); break; } } diff --git a/src/crt0.s b/src/crt0.s index 835522589..672fc94f2 100644 --- a/src/crt0.s +++ b/src/crt0.s @@ -94,7 +94,7 @@ GPIOPortReadEnable: @ 80000C8 .byte 0x1e, 0x1e, 0x10, 0x40 - .4byte 0x0000322e @ offsetof(struct SaveBlock1, ? part-way into unk_322C) + .4byte 0x0000322e @ offsetof(struct SaveBlock1, ? part-way into mysteryGift) .4byte 0x00000498 @ offsetof(struct SaveBlock1, pcItems) .4byte 0x000031a8 @ offsetof(struct SaveBlock1, giftRibbons) .4byte 0x000031f8 @ offsetof(struct SaveBlock1, enigmaBerry) diff --git a/src/easy_chat.c b/src/easy_chat.c index 79300bd52..b18d09b83 100644 --- a/src/easy_chat.c +++ b/src/easy_chat.c @@ -15,7 +15,7 @@ #include "graphics.h" #include "international_string_util.h" #include "main.h" -#include "mevent.h" +#include "mystery_gift.h" #include "menu.h" #include "overworld.h" #include "palette.h" diff --git a/src/ereader_screen.c b/src/ereader_screen.c index f5edbc628..73a1b870e 100755 --- a/src/ereader_screen.c +++ b/src/ereader_screen.c @@ -4,7 +4,7 @@ #include "ereader_helpers.h" #include "link.h" #include "main.h" -#include "mystery_gift.h" +#include "mystery_gift_menu.h" #include "save.h" #include "sound.h" #include "sprite.h" @@ -13,7 +13,7 @@ #include "util.h" #include "constants/songs.h" -struct Unk81D5014 +struct EReaderTaskData { u16 unk0; u16 unk2; @@ -36,7 +36,7 @@ struct Unk03006370 u32 *unk8; }; -static void sub_81D5084(u8); +static void Task_EReader(u8); struct Unk03006370 gUnknown_03006370; @@ -209,11 +209,11 @@ static u32 sub_81D4EE4(u8 *arg0, u16 *arg1) return 0; } -void task_add_00_ereader(void) +void CreateEReaderTask(void) { - struct Unk81D5014 *data; - u8 taskId = CreateTask(sub_81D5084, 0); - data = (struct Unk81D5014 *)gTasks[taskId].data; + struct EReaderTaskData *data; + u8 taskId = CreateTask(Task_EReader, 0); + data = (struct EReaderTaskData *)gTasks[taskId].data; data->unk8 = 0; data->unk9 = 0; data->unkA = 0; @@ -244,13 +244,13 @@ static bool32 sub_81D5064(u16 *arg0, u16 arg1) return FALSE; } -static void sub_81D5084(u8 taskId) +static void Task_EReader(u8 taskId) { - struct Unk81D5014 *data = (struct Unk81D5014 *)gTasks[taskId].data; + struct EReaderTaskData *data = (struct EReaderTaskData *)gTasks[taskId].data; switch (data->unk8) { case 0: - if (MG_PrintTextOnWindow1AndWaitButton(&data->unk9, gJPText_ReceiveMysteryGiftWithEReader)) + if (PrintMysteryGiftMenuMessage(&data->unk9, gJPText_ReceiveMysteryGiftWithEReader)) data->unk8 = 1; break; case 1: @@ -274,7 +274,7 @@ static void sub_81D5084(u8 taskId) } break; case 4: - if (MG_PrintTextOnWindow1AndWaitButton(&data->unk9, gJPText_SelectConnectFromEReaderMenu)) + if (PrintMysteryGiftMenuMessage(&data->unk9, gJPText_SelectConnectFromEReaderMenu)) { AddTextPrinterToWindow1(gJPText_SelectConnectWithGBA); sub_81D505C(&data->unk0); @@ -323,7 +323,7 @@ static void sub_81D5084(u8 taskId) } break; case 7: - if (MG_PrintTextOnWindow1AndWaitButton(&data->unk9, gJPText_LinkIsIncorrect)) + if (PrintMysteryGiftMenuMessage(&data->unk9, gJPText_LinkIsIncorrect)) data->unk8 = 4; break; case 8: @@ -439,19 +439,19 @@ static void sub_81D5084(u8 taskId) data->unk8 = 26; break; case 23: - if (MG_PrintTextOnWindow1AndWaitButton(&data->unk9, gJPText_CardReadingHasBeenHalted)) + if (PrintMysteryGiftMenuMessage(&data->unk9, gJPText_CardReadingHasBeenHalted)) data->unk8 = 26; break; case 20: - if (MG_PrintTextOnWindow1AndWaitButton(&data->unk9, gJPText_ConnectionErrorCheckLink)) + if (PrintMysteryGiftMenuMessage(&data->unk9, gJPText_ConnectionErrorCheckLink)) data->unk8 = 0; break; case 21: - if (MG_PrintTextOnWindow1AndWaitButton(&data->unk9, gJPText_ConnectionErrorTryAgain)) + if (PrintMysteryGiftMenuMessage(&data->unk9, gJPText_ConnectionErrorTryAgain)) data->unk8 = 0; break; case 22: - if (MG_PrintTextOnWindow1AndWaitButton(&data->unk9, gJPText_WriteErrorUnableToSaveData)) + if (PrintMysteryGiftMenuMessage(&data->unk9, gJPText_WriteErrorUnableToSaveData)) data->unk8 = 0; break; case 26: diff --git a/src/event_data.c b/src/event_data.c index 2bde09012..e2af6c3d0 100644 --- a/src/event_data.c +++ b/src/event_data.c @@ -114,36 +114,36 @@ bool32 IsMysteryGiftEnabled(void) return FlagGet(FLAG_SYS_MYSTERY_GIFT_ENABLE); } -void ClearMysteryEventFlags(void) -{ - FlagClear(FLAG_MYSTERY_EVENT_DONE); - FlagClear(FLAG_MYSTERY_EVENT_1); - FlagClear(FLAG_MYSTERY_EVENT_2); - FlagClear(FLAG_MYSTERY_EVENT_3); - FlagClear(FLAG_MYSTERY_EVENT_4); - FlagClear(FLAG_MYSTERY_EVENT_5); - FlagClear(FLAG_MYSTERY_EVENT_6); - FlagClear(FLAG_MYSTERY_EVENT_7); - FlagClear(FLAG_MYSTERY_EVENT_8); - FlagClear(FLAG_MYSTERY_EVENT_9); - FlagClear(FLAG_MYSTERY_EVENT_10); - FlagClear(FLAG_MYSTERY_EVENT_11); - FlagClear(FLAG_MYSTERY_EVENT_12); - FlagClear(FLAG_MYSTERY_EVENT_13); - FlagClear(FLAG_MYSTERY_EVENT_14); - FlagClear(FLAG_MYSTERY_EVENT_15); -} - -void ClearMysteryEventVars(void) -{ - VarSet(VAR_EVENT_PICHU_SLOT, 0); - VarSet(VAR_NEVER_READ_0x40DE, 0); - VarSet(VAR_NEVER_READ_0x40DF, 0); - VarSet(VAR_NEVER_READ_0x40E0, 0); - VarSet(VAR_NEVER_READ_0x40E1, 0); - VarSet(VAR_NEVER_READ_0x40E2, 0); - VarSet(VAR_NEVER_READ_0x40E3, 0); - VarSet(VAR_NEVER_READ_0x40E4, 0); +void ClearMysteryGiftFlags(void) +{ + FlagClear(FLAG_MYSTERY_GIFT_DONE); + FlagClear(FLAG_MYSTERY_GIFT_1); + FlagClear(FLAG_MYSTERY_GIFT_2); + FlagClear(FLAG_MYSTERY_GIFT_3); + FlagClear(FLAG_MYSTERY_GIFT_4); + FlagClear(FLAG_MYSTERY_GIFT_5); + FlagClear(FLAG_MYSTERY_GIFT_6); + FlagClear(FLAG_MYSTERY_GIFT_7); + FlagClear(FLAG_MYSTERY_GIFT_8); + FlagClear(FLAG_MYSTERY_GIFT_9); + FlagClear(FLAG_MYSTERY_GIFT_10); + FlagClear(FLAG_MYSTERY_GIFT_11); + FlagClear(FLAG_MYSTERY_GIFT_12); + FlagClear(FLAG_MYSTERY_GIFT_13); + FlagClear(FLAG_MYSTERY_GIFT_14); + FlagClear(FLAG_MYSTERY_GIFT_15); +} + +void ClearMysteryGiftVars(void) +{ + VarSet(VAR_GIFT_PICHU_SLOT, 0); + VarSet(VAR_GIFT_UNUSED_1, 0); + VarSet(VAR_GIFT_UNUSED_2, 0); + VarSet(VAR_GIFT_UNUSED_3, 0); + VarSet(VAR_GIFT_UNUSED_4, 0); + VarSet(VAR_GIFT_UNUSED_5, 0); + VarSet(VAR_GIFT_UNUSED_6, 0); + VarSet(VAR_GIFT_UNUSED_7, 0); } void DisableResetRTC(void) diff --git a/src/field_specials.c b/src/field_specials.c index ab02f9938..97fba6b10 100644 --- a/src/field_specials.c +++ b/src/field_specials.c @@ -22,7 +22,7 @@ #include "link.h" #include "list_menu.h" #include "main.h" -#include "mevent.h" +#include "mystery_gift.h" #include "match_call.h" #include "menu.h" #include "overworld.h" @@ -56,7 +56,7 @@ #include "constants/heal_locations.h" #include "constants/map_types.h" #include "constants/maps.h" -#include "constants/mevent.h" +#include "constants/mystery_gift.h" #include "constants/script_menu.h" #include "constants/slot_machine.h" #include "constants/songs.h" @@ -1655,20 +1655,20 @@ void BufferLottoTicketNumber(void) } } -u16 GetMysteryEventCardVal(void) +u16 GetMysteryGiftCardStat(void) { switch (gSpecialVar_Result) { case GET_NUM_STAMPS: - return mevent_081445C0(GET_NUM_STAMPS_INTERNAL); + return MysteryGift_GetCardStat(CARD_STAT_NUM_STAMPS); case GET_MAX_STAMPS: - return mevent_081445C0(GET_MAX_STAMPS_INTERNAL); + return MysteryGift_GetCardStat(CARD_STAT_MAX_STAMPS); case GET_CARD_BATTLES_WON: - return mevent_081445C0(GET_CARD_BATTLES_WON_INTERNAL); - case 3: // Never occurs - return mevent_081445C0(1); - case 4: // Never occurs - return mevent_081445C0(2); + return MysteryGift_GetCardStat(CARD_STAT_BATTLES_WON); + case GET_CARD_BATTLES_LOST: // Never occurs + return MysteryGift_GetCardStat(CARD_STAT_BATTLES_LOST); + case GET_CARD_NUM_TRADES: // Never occurs + return MysteryGift_GetCardStat(CARD_STAT_NUM_TRADES); default: return 0; } diff --git a/src/link_rfu_2.c b/src/link_rfu_2.c index f2caef949..87e9f8e9d 100644 --- a/src/link_rfu_2.c +++ b/src/link_rfu_2.c @@ -16,7 +16,7 @@ #include "task.h" #include "text.h" #include "save.h" -#include "mystery_gift.h" +#include "mystery_gift_menu.h" enum { RFUSTATE_INIT, @@ -1981,7 +1981,7 @@ static void RfuCheckErrorStatus(void) { if (gRfu.errorState == RFU_ERROR_STATE_OCCURRED && lman.childClockSlave_flag == 0) { - if (gMain.callback2 == c2_mystery_gift_e_reader_run || lman.init_param->mboot_flag) + if (gMain.callback2 == CB2_MysteryGiftEReader || lman.init_param->mboot_flag) gWirelessCommType = 2; SetMainCallback2(CB2_LinkError); gMain.savedCallback = CB2_LinkError; diff --git a/src/main_menu.c b/src/main_menu.c index f6dff3d44..a74ba9ec3 100644 --- a/src/main_menu.c +++ b/src/main_menu.c @@ -35,7 +35,7 @@ #include "text_window.h" #include "title_screen.h" #include "window.h" -#include "mystery_gift.h" +#include "mystery_gift_menu.h" /* * Main menu state machine @@ -90,7 +90,7 @@ * - If the user selected New Game, advance to Task_NewGameBirchSpeech_Init. * - If the user selected Continue, advance to CB2_ContinueSavedGame. * - If the user selected the Options menu, advance to CB2_InitOptionMenu. - * - If the user selected Mystery Gift, advance to CB2_MysteryGift. However, + * - If the user selected Mystery Gift, advance to CB2_InitMysteryGift. However, * if the wireless adapter was removed, instead advance to * Task_DisplayMainMenuInvalidActionError. * - Code to start a Mystery Event is present here, but is unreachable in this @@ -1070,7 +1070,7 @@ static void Task_HandleMainMenuAPressed(u8 taskId) DestroyTask(taskId); break; case ACTION_MYSTERY_GIFT: - SetMainCallback2(c2_mystery_gift); + SetMainCallback2(CB2_InitMysteryGift); DestroyTask(taskId); break; case ACTION_MYSTERY_EVENTS: @@ -1078,7 +1078,7 @@ static void Task_HandleMainMenuAPressed(u8 taskId) DestroyTask(taskId); break; case ACTION_EREADER: - SetMainCallback2(c2_ereader); + SetMainCallback2(CB2_InitEReader); DestroyTask(taskId); break; case ACTION_INVALID: diff --git a/src/mevent2.c b/src/mevent2.c deleted file mode 100755 index d2c020858..000000000 --- a/src/mevent2.c +++ /dev/null @@ -1,630 +0,0 @@ -#include "global.h" -#include "util.h" -#include "main.h" -#include "event_data.h" -#include "easy_chat.h" -#include "script.h" -#include "battle_tower.h" -#include "mevent_news.h" -#include "string_util.h" -#include "new_game.h" -#include "mevent.h" -#include "constants/mevent.h" - -static EWRAM_DATA bool32 gUnknown_02022C70 = FALSE; - -static void sub_801B180(void); -static void s_DestroyWonderNews(void); -static bool32 sub_801B114(const struct WonderNews *data); -static bool32 sub_801B2CC(const struct WonderCard *data); -static void sub_801B330(void); -static void sub_801B368(void); -static void sub_801B9F8(void); -static void sub_801BA8C(u32 a0, u32 a1, u32 *a2, int a3); - -void sub_801AFD8(void) -{ - CpuFill32(0, &gSaveBlock1Ptr->unk_322C, sizeof(gSaveBlock1Ptr->unk_322C)); - sub_801B180(); - InitQuestionnaireWords(); -} - -struct WonderNews *GetSavedWonderNews(void) -{ - return &gSaveBlock1Ptr->unk_322C.wonderNews.data; -} - -struct WonderCard *GetSavedWonderCard(void) -{ - return &gSaveBlock1Ptr->unk_322C.wonderCard.data; -} - -struct MEventBuffer_3430_Sub *sav1_get_mevent_buffer_2(void) -{ - return &gSaveBlock1Ptr->unk_322C.buffer_310.data; -} - -struct MysteryEventStruct *sub_801B044(void) -{ - return &gSaveBlock1Ptr->unk_322C.unk_340; -} - -u16 *GetQuestionnaireWordsPtr(void) -{ - return gSaveBlock1Ptr->unk_322C.questionnaireWords; -} - -void DestroyWonderNews(void) -{ - s_DestroyWonderNews(); -} - -bool32 sub_801B078(const struct WonderNews *src) -{ - if (!sub_801B114(src)) - return FALSE; - - s_DestroyWonderNews(); - gSaveBlock1Ptr->unk_322C.wonderNews.data = *src; - gSaveBlock1Ptr->unk_322C.wonderNews.crc = CalcCRC16WithTable((void *)&gSaveBlock1Ptr->unk_322C.wonderNews.data, sizeof(struct WonderNews)); - return TRUE; -} - -bool32 ValidateReceivedWonderNews(void) -{ - if (CalcCRC16WithTable((void *)&gSaveBlock1Ptr->unk_322C.wonderNews.data, sizeof(struct WonderNews)) != gSaveBlock1Ptr->unk_322C.wonderNews.crc) - return FALSE; - if (!sub_801B114(&gSaveBlock1Ptr->unk_322C.wonderNews.data)) - return FALSE; - - return TRUE; -} - -static bool32 sub_801B114(const struct WonderNews *data) -{ - if (data->unk_00 == 0) - return FALSE; - - return TRUE; -} - -bool32 WonderNews_Test_Unk_02(void) -{ - const struct WonderNews *data = &gSaveBlock1Ptr->unk_322C.wonderNews.data; - if (data->unk_02 == 0) - return FALSE; - - return TRUE; -} - -static void s_DestroyWonderNews(void) -{ - CpuFill32(0, GetSavedWonderNews(), sizeof(gSaveBlock1Ptr->unk_322C.wonderNews.data)); - gSaveBlock1Ptr->unk_322C.wonderNews.crc = 0; -} - -static void sub_801B180(void) -{ - CpuFill32(0, sub_801B044(), sizeof(struct MysteryEventStruct)); - sub_801DBC0(); -} - -bool32 sub_801B1A4(const u8 *src) -{ - const u8 *r5 = (const u8 *)&gSaveBlock1Ptr->unk_322C.wonderNews.data; - u32 i; - if (!ValidateReceivedWonderNews()) - return FALSE; - - for (i = 0; i < sizeof(struct WonderNews); i++) - { - if (r5[i] != src[i]) - return FALSE; - } - - return TRUE; -} - -void DestroyWonderCard(void) -{ - sub_801B330(); - sub_801B368(); - sub_801B9F8(); - ClearRamScript(); - ClearMysteryEventFlags(); - ClearMysteryEventVars(); - ClearEReaderTrainer(&gSaveBlock2Ptr->frontier.ereaderTrainer); -} - -bool32 sub_801B21C(const struct WonderCard *data) -{ - struct MEventBuffer_3430_Sub *r2; - struct WonderCard *r1; - if (!sub_801B2CC(data)) - return FALSE; - - DestroyWonderCard(); - memcpy(&gSaveBlock1Ptr->unk_322C.wonderCard.data, data, sizeof(struct WonderCard)); - gSaveBlock1Ptr->unk_322C.wonderCard.crc = CalcCRC16WithTable((void *)&gSaveBlock1Ptr->unk_322C.wonderCard.data, sizeof(struct WonderCard)); - r2 = &gSaveBlock1Ptr->unk_322C.buffer_310.data; - r1 = &gSaveBlock1Ptr->unk_322C.wonderCard.data; - r2->unk_06 = r1->unk_02; - return TRUE; -} - -bool32 ValidateReceivedWonderCard(void) -{ - if (gSaveBlock1Ptr->unk_322C.wonderCard.crc != CalcCRC16WithTable((void *)&gSaveBlock1Ptr->unk_322C.wonderCard.data, sizeof(struct WonderCard))) - return FALSE; - if (!sub_801B2CC(&gSaveBlock1Ptr->unk_322C.wonderCard.data)) - return FALSE; - if (!ValidateSavedRamScript()) - return FALSE; - - return TRUE; -} - -static bool32 sub_801B2CC(const struct WonderCard *data) -{ - if (data->unk_00 == 0) - return FALSE; - if (data->unk_08_0 > 2) - return FALSE; - if (!(data->unk_08_6 == 0 || data->unk_08_6 == 1 || data->unk_08_6 == 2)) - return FALSE; - if (data->unk_08_2 > 7) - return FALSE; - if (data->unk_09 > 7) - return FALSE; - - return TRUE; -} - -bool32 WonderCard_Test_Unk_08_6(void) -{ - const struct WonderCard *data = &gSaveBlock1Ptr->unk_322C.wonderCard.data; - if (data->unk_08_6 == 0) - return FALSE; - - return TRUE; -} - -static void sub_801B330(void) -{ - CpuFill32(0, &gSaveBlock1Ptr->unk_322C.wonderCard.data, sizeof(struct WonderCard)); - gSaveBlock1Ptr->unk_322C.wonderCard.crc = 0; -} - -static void sub_801B368(void) -{ - CpuFill32(0, sav1_get_mevent_buffer_2(), 18 *sizeof(u16)); - gSaveBlock1Ptr->unk_322C.buffer_310.crc = 0; -} - -u16 GetWonderCardFlagID(void) -{ - if (ValidateReceivedWonderCard()) - return gSaveBlock1Ptr->unk_322C.wonderCard.data.unk_00; - - return 0; -} - -void WonderCard_ResetInternalReceivedFlag(struct WonderCard *buffer) -{ - if (buffer->unk_08_6 == 1) - buffer->unk_08_6 = 0; -} - -static bool32 IsWonderCardFlagIDInValidRange(u16 a0) -{ - if (a0 >= 1000 && a0 < 1020) - return TRUE; - - return FALSE; -} - -static const u16 sMysteryGiftFlags[] = -{ - FLAG_RECEIVED_AURORA_TICKET, - FLAG_RECEIVED_MYSTIC_TICKET, - FLAG_RECEIVED_OLD_SEA_MAP, - FLAG_UNUSED_MYSTERY_GIFT_0x13D, - FLAG_UNUSED_MYSTERY_GIFT_0x13E, - FLAG_UNUSED_MYSTERY_GIFT_0x13F, - FLAG_UNUSED_MYSTERY_GIFT_0x140, - FLAG_UNUSED_MYSTERY_GIFT_0x141, - FLAG_UNUSED_MYSTERY_GIFT_0x142, - FLAG_UNUSED_MYSTERY_GIFT_0x143, - FLAG_UNUSED_MYSTERY_GIFT_0x144, - FLAG_UNUSED_MYSTERY_GIFT_0x145, - FLAG_UNUSED_MYSTERY_GIFT_0x146, - FLAG_UNUSED_MYSTERY_GIFT_0x147, - FLAG_UNUSED_MYSTERY_GIFT_0x148, - FLAG_UNUSED_MYSTERY_GIFT_0x149, - FLAG_UNUSED_MYSTERY_GIFT_0x14A, - FLAG_UNUSED_MYSTERY_GIFT_0x14B, - FLAG_UNUSED_MYSTERY_GIFT_0x14C, - FLAG_UNUSED_MYSTERY_GIFT_0x14D, -}; - -bool32 CheckReceivedGiftFromWonderCard(void) -{ - u16 value = GetWonderCardFlagID(); - if (!IsWonderCardFlagIDInValidRange(value)) - return FALSE; - - if (FlagGet(sMysteryGiftFlags[value - 1000]) == TRUE) - return FALSE; - - return TRUE; -} - -static int sub_801B438(const struct MEventBuffer_3430_Sub *data, int size) -{ - int r3 = 0; - int i; - for (i = 0; i < size; i++) - { - if (data->unk_08[1][i] && data->unk_08[0][i]) - r3++; - } - - return r3; -} - -static bool32 sub_801B460(const struct MEventBuffer_3430_Sub *data1, const u16 *data2, int size) -{ - int i; - for (i = 0; i < size; i++) - { - if (data1->unk_08[1][i] == data2[1]) - return TRUE; - if (data1->unk_08[0][i] == data2[0]) - return TRUE; - } - - return FALSE; -} - -static bool32 sub_801B4A4(const u16 *data) -{ - if (data[1] == 0) - return FALSE; - if (data[0] == 0) - return FALSE; - if (data[0] >= NUM_SPECIES) - return FALSE; - return TRUE; -} - -static int sub_801B4CC(void) -{ - struct WonderCard *data; - if (!ValidateReceivedWonderCard()) - return 0; - - data = &gSaveBlock1Ptr->unk_322C.wonderCard.data; - if (data->unk_08_0 != 1) - return 0; - - return sub_801B438(&gSaveBlock1Ptr->unk_322C.buffer_310.data, data->unk_09); -} - -bool32 sub_801B508(const u16 *data) -{ - struct WonderCard *buffer = &gSaveBlock1Ptr->unk_322C.wonderCard.data; - int size = buffer->unk_09; - int i; - if (!sub_801B4A4(data)) - return FALSE; - - if (sub_801B460(&gSaveBlock1Ptr->unk_322C.buffer_310.data, data, size)) - return FALSE; - - for (i = 0; i < size; i++) - { - if (gSaveBlock1Ptr->unk_322C.buffer_310.data.unk_08[1][i] == 0 && gSaveBlock1Ptr->unk_322C.buffer_310.data.unk_08[0][i] == 0) - { - gSaveBlock1Ptr->unk_322C.buffer_310.data.unk_08[1][i] = data[1]; - gSaveBlock1Ptr->unk_322C.buffer_310.data.unk_08[0][i] = data[0]; - return TRUE; - } - } - - return FALSE; -} - -void sub_801B580(struct MEventStruct_Unk1442CC *data, bool32 a1) -{ - int i; - CpuFill32(0, data, sizeof(struct MEventStruct_Unk1442CC)); - data->unk_00 = 0x101; - data->unk_04 = 1; - data->unk_08 = 1; - - if (a1) - { - data->unk_0C = 5; - data->unk_10 = 0x0201; - } - else - { - data->unk_0C = 4; - data->unk_10 = 0x0200; - } - - if (ValidateReceivedWonderCard()) - { - data->unk_14 = GetSavedWonderCard()->unk_00; - data->unk_20 = *sav1_get_mevent_buffer_2(); - data->unk_44 = GetSavedWonderCard()->unk_09; - } - else - { - data->unk_14 = 0; - } - - for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++) - data->unk_16[i] = gSaveBlock1Ptr->unk_322C.questionnaireWords[i]; - - CopyTrainerId(data->unk_4C, gSaveBlock2Ptr->playerTrainerId); - StringCopy(data->unk_45, gSaveBlock2Ptr->playerName); - for (i = 0; i < 6; i++) - data->unk_50[i] = gSaveBlock1Ptr->easyChatProfile[i]; - - memcpy(data->unk_5C, RomHeaderGameCode, 4); - data->unk_60 = RomHeaderSoftwareVersion; -} - -bool32 sub_801B6A0(const struct MEventStruct_Unk1442CC *data, bool32 a1) -{ - if (data->unk_00 != 0x101) - return FALSE; - - if (!(data->unk_04 & 1)) - return FALSE; - - if (!(data->unk_08 & 1)) - return FALSE; - - if (!a1) - { - if (!(data->unk_0C & 4)) - return FALSE; - - if (!(data->unk_10 & 0x380)) - return FALSE; - } - - return TRUE; -} - -u32 sub_801B6EC(const u16 *a0, const struct MEventStruct_Unk1442CC *a1, const void *unused) -{ - if (a1->unk_14 == 0) - return 0; - - if (*a0 == a1->unk_14) - return 1; - - return 2; -} - -u32 sub_801B708(const u16 *a0, const struct MEventStruct_Unk1442CC *a1, const void *unused) -{ - int r4 = a1->unk_44 - sub_801B438(&a1->unk_20, a1->unk_44); - if (r4 == 0) - return 1; - if (sub_801B460(&a1->unk_20, a0, a1->unk_44)) - return 3; - if (r4 == 1) - return 4; - return 2; -} - -bool32 MEventStruct_Unk1442CC_CompareField_unk_16(const struct MEventStruct_Unk1442CC *a0, const u16 *a1) -{ - int i; - for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++) - { - if (a0->unk_16[i] != a1[i]) - return FALSE; - } - - return TRUE; -} - -static int sub_801B770(const struct MEventStruct_Unk1442CC *a0) -{ - return sub_801B438(&a0->unk_20, a0->unk_44); -} - -u16 MEventStruct_Unk1442CC_GetValueNFrom_unk_20(const struct MEventStruct_Unk1442CC *a0, u32 command) -{ - switch (command) - { - case 0: - return a0->unk_20.unk_00; - case 1: - return a0->unk_20.unk_02; - case 2: - return a0->unk_20.unk_04; - case 3: - return sub_801B770(a0); - case 4: - return a0->unk_44; - default: - AGB_ASSERT(0); - return 0; - } -} - -static void sub_801B7D8(u32 command) -{ - struct WonderCard *data = &gSaveBlock1Ptr->unk_322C.wonderCard.data; - if (data->unk_08_0 == 2) - { - u16 *dest = NULL; - switch (command) - { - case 0: - dest = &gSaveBlock1Ptr->unk_322C.buffer_310.data.unk_00; - break; - case 1: - dest = &gSaveBlock1Ptr->unk_322C.buffer_310.data.unk_02; - break; - case 2: - dest = &gSaveBlock1Ptr->unk_322C.buffer_310.data.unk_04; - break; - case 3: - break; - case 4: - break; - } - - if (dest == NULL) - { - AGB_ASSERT(0); - } - else if (++(*dest) > 999) - { - *dest = 999; - } - } -} - -u16 mevent_081445C0(u32 command) -{ - switch (command) - { - case GET_CARD_BATTLES_WON_INTERNAL: - { - struct WonderCard *data = &gSaveBlock1Ptr->unk_322C.wonderCard.data; - if (data->unk_08_0 == 2) - { - struct MEventBuffer_3430_Sub *buffer = &gSaveBlock1Ptr->unk_322C.buffer_310.data; - return buffer->unk_00; - } - break; - } - case 1: // Never occurs - { - struct WonderCard *data = &gSaveBlock1Ptr->unk_322C.wonderCard.data; - if (data->unk_08_0 == 2) - { - struct MEventBuffer_3430_Sub *buffer = &gSaveBlock1Ptr->unk_322C.buffer_310.data; - return buffer->unk_02; - } - break; - } - case 2: // Never occurs - { - struct WonderCard *data = &gSaveBlock1Ptr->unk_322C.wonderCard.data; - if (data->unk_08_0 == 2) - { - struct MEventBuffer_3430_Sub *buffer = &gSaveBlock1Ptr->unk_322C.buffer_310.data; - return buffer->unk_04; - } - break; - } - case GET_NUM_STAMPS_INTERNAL: - { - struct WonderCard *data = &gSaveBlock1Ptr->unk_322C.wonderCard.data; - if (data->unk_08_0 == 1) - return sub_801B4CC(); - break; - } - case GET_MAX_STAMPS_INTERNAL: - { - struct WonderCard *data = &gSaveBlock1Ptr->unk_322C.wonderCard.data; - if (data->unk_08_0 == 1) - return data->unk_09; - break; - } - } - - AGB_ASSERT(0); - return 0; -} - -void ResetReceivedWonderCardFlag(void) -{ - gUnknown_02022C70 = FALSE; -} - -bool32 MEventHandleReceivedWonderCard(u16 a0) -{ - gUnknown_02022C70 = FALSE; - if (a0 == 0) - return FALSE; - - if (!ValidateReceivedWonderCard()) - return FALSE; - - if (gSaveBlock1Ptr->unk_322C.wonderCard.data.unk_00 != a0) - return FALSE; - - gUnknown_02022C70 = TRUE; - return TRUE; -} - -void RecordIdOfWonderCardSenderByEventType(u32 a0, u32 a1) -{ - if (gUnknown_02022C70) - { - switch (a0) - { - case 2: - sub_801BA8C(2, a1, gSaveBlock1Ptr->unk_322C.unk_344[1], 5); - break; - case 0: - sub_801BA8C(0, a1, gSaveBlock1Ptr->unk_322C.unk_344[0], 5); - break; - case 1: - sub_801BA8C(1, a1, gSaveBlock1Ptr->unk_322C.unk_344[0], 5); - break; - default: - AGB_ASSERT(0); - } - } -} - -static void sub_801B9F8(void) -{ - CpuFill32(0, gSaveBlock1Ptr->unk_322C.unk_344, sizeof(gSaveBlock1Ptr->unk_322C.unk_344)); -} - -static bool32 sub_801BA24(u32 a0, u32 *a1, int size) -{ - int i; - int j; - - for (i = 0; i < size; i++) - { - if (a1[i] == a0) - break; - } - - if (i == size) - { - for (j = size - 1; j > 0; j--) - a1[j] = a1[j - 1]; - - a1[0] = a0; - return TRUE; - } - else - { - for (j = i; j > 0; j--) - a1[j] = a1[j - 1]; - - a1[0] = a0; - return FALSE; - } -} - -static void sub_801BA8C(u32 a0, u32 a1, u32 *a2, int a3) -{ - if (sub_801BA24(a1, a2, a3)) - sub_801B7D8(a0); -} diff --git a/src/mevent_801BAAC.c b/src/mevent_801BAAC.c deleted file mode 100644 index a3e6ee0b6..000000000 --- a/src/mevent_801BAAC.c +++ /dev/null @@ -1,826 +0,0 @@ -#include "global.h" -#include "bg.h" -#include "gpu_regs.h" -#include "palette.h" -#include "decompress.h" -#include "malloc.h" -#include "menu.h" -#include "pokemon_icon.h" -#include "union_room.h" -#include "list_menu.h" -#include "text_window.h" -#include "string_util.h" -#include "link_rfu.h" -#include "mevent.h" -#include "mystery_gift.h" -#include "constants/rgb.h" - -struct UnkStruct_8467FB8 -{ - u8 textPal1:4; - u8 textPal2:4; - u8 textPal3:4; - u8 textPal4:4; - const u32 * tiles; - const u32 * map; - const u16 * pal; -}; - -struct UnkStruct_203F3C8_02DC -{ - u8 unk_00; - u8 unk_01[41]; - u8 unk_42[4]; -}; - -struct UnkStruct_203F3C8 -{ - /*0000*/ struct WonderCard unk_0000; - /*014c*/ struct MEventBuffer_3430_Sub unk_014C; - /*0170*/ const struct UnkStruct_8467FB8 * unk_0170; - /*0174*/ u8 unk_0174; - /*0175*/ u8 unk_0175; - /*0176*/ u16 unk_0176[3]; - /*017C*/ u8 unk_017C; - /*017D*/ u8 unk_017D[7][2]; - /*018B*/ u8 unk_018B[41]; - /*01B4*/ u8 unk_01B4[41]; - /*01DD*/ u8 unk_01DD[7]; - /*01E4*/ u8 unk_01E4[4][41]; - /*0288*/ u8 unk_0288[41]; - /*02B1*/ u8 unk_02B1[41]; - /*02DC*/ struct UnkStruct_203F3C8_02DC unk_02DC[8]; - /*045C*/ u8 buffer_045C[0x1000]; -}; - -EWRAM_DATA struct UnkStruct_203F3C8 * sWonderCardData = NULL; - -void sub_801BEF8(void); -void sub_801C178(u8 whichWindow); -void sub_801C4C0(void); -void sub_801C61C(void); - -extern const struct OamData gOamData_AffineOff_ObjNormal_32x16; - -const u8 sTextColorTable[][3] = { - {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY}, - {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY} -}; -const u8 ALIGNED(4) gUnknown_082F0E18[3] = {7, 4, 7}; -const struct WindowTemplate gUnknown_082F0E1C[] = { - { - .bg = 1, - .tilemapLeft = 1, - .tilemapTop = 1, - .width = 25, - .height = 4, - .paletteNum = 2, - .baseBlock = 0x029c - }, { - .bg = 1, - .tilemapLeft = 1, - .tilemapTop = 6, - .width = 28, - .height = 8, - .paletteNum = 2, - .baseBlock = 0x01bc - }, { - .bg = 1, - .tilemapLeft = 1, - .tilemapTop = 14, - .width = 28, - .height = 5, - .paletteNum = 2, - .baseBlock = 0x0130 - } -}; - -const u16 gWonderCardBgPal1[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_1.gbapal"); -const u16 gWonderCardBgPal2[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_2.gbapal"); -const u16 gWonderCardBgPal3[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_3.gbapal"); -const u16 gWonderCardBgPal4[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_4.gbapal"); -const u16 gWonderCardBgPal5[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_5.gbapal"); -const u16 gWonderCardBgPal6[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_6.gbapal"); -const u16 gWonderCardBgPal7[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_7.gbapal"); -const u16 gWonderCardBgPal8[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_8.gbapal"); -const u32 gWonderCardBgGfx1[] = INCBIN_U32("graphics/wonder_transfers/wonder_card_1.4bpp.lz"); -const u32 gWonderCardBgTilemap1[] = INCBIN_U32("graphics/wonder_transfers/wonder_card_1.bin.lz"); -const u32 gWonderCardBgGfx2[] = INCBIN_U32("graphics/wonder_transfers/wonder_card_2.4bpp.lz"); -const u32 gWonderCardBgTilemap2[] = INCBIN_U32("graphics/wonder_transfers/wonder_card_2.bin.lz"); -const u32 gWonderCardBgGfx3[] = INCBIN_U32("graphics/wonder_transfers/wonder_card_3.4bpp.lz"); -const u32 gWonderCardBgTilemap3[] = INCBIN_U32("graphics/wonder_transfers/wonder_card_3.bin.lz"); -const u32 gWonderCardBgGfx7[] = INCBIN_U32("graphics/wonder_transfers/wonder_card_7.4bpp.lz"); -const u32 gWonderCardBgTilemap7[] = INCBIN_U32("graphics/wonder_transfers/wonder_card_7.bin.lz"); -const u32 gWonderCardBgGfx8[] = INCBIN_U32("graphics/wonder_transfers/wonder_card_8.4bpp.lz"); -const u32 gWonderCardBgTilemap8[] = INCBIN_U32("graphics/wonder_transfers/wonder_card_8.bin.lz"); -const u16 gWonderCardShadowPal1[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_shadow_1.gbapal"); -const u16 gWonderCardShadowPal2[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_shadow_2.gbapal"); -const u16 gWonderCardShadowPal3[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_shadow_3.gbapal"); -const u16 gWonderCardShadowPal4[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_shadow_4.gbapal"); -const u16 gWonderCardShadowPal5[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_shadow_5.gbapal"); -const u16 gWonderCardShadowPal6[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_shadow_6.gbapal"); -const u16 gWonderCardShadowPal7[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_shadow_7.gbapal"); -const u16 gWonderCardShadowPal8[] = INCBIN_U16("graphics/wonder_transfers/wonder_card_shadow_8.gbapal"); -const u32 gWonderCardShadowGfx[] = INCBIN_U32("graphics/wonder_transfers/wonder_card_shadow.4bpp.lz"); - -const struct CompressedSpriteSheet gUnknown_082F1D00 = { - gWonderCardShadowGfx, 0x100, 0x8000 -}; -const struct SpritePalette gUnknown_082F1D08[] = { - {gWonderCardShadowPal1, 0x8000}, - {gWonderCardShadowPal2, 0x8000}, - {gWonderCardShadowPal3, 0x8000}, - {gWonderCardShadowPal4, 0x8000}, - {gWonderCardShadowPal5, 0x8000}, - {gWonderCardShadowPal6, 0x8000}, - {gWonderCardShadowPal7, 0x8000}, - {gWonderCardShadowPal8, 0x8000} -}; -const struct SpriteTemplate gUnknown_082F1D48 = { - 0x8000, 0x8000, &gOamData_AffineOff_ObjNormal_32x16, gDummySpriteAnimTable, NULL, gDummySpriteAffineAnimTable, SpriteCallbackDummy -}; -const struct UnkStruct_8467FB8 gUnknown_082F1D60[8] = { - {1, 0, 0, 0, gWonderCardBgGfx1, gWonderCardBgTilemap1, gWonderCardBgPal1}, - {1, 0, 0, 1, gWonderCardBgGfx2, gWonderCardBgTilemap2, gWonderCardBgPal2}, - {1, 0, 0, 2, gWonderCardBgGfx3, gWonderCardBgTilemap3, gWonderCardBgPal3}, - {1, 0, 0, 3, gWonderCardBgGfx3, gWonderCardBgTilemap3, gWonderCardBgPal4}, - {1, 0, 0, 4, gWonderCardBgGfx3, gWonderCardBgTilemap3, gWonderCardBgPal5}, - {1, 0, 0, 5, gWonderCardBgGfx3, gWonderCardBgTilemap3, gWonderCardBgPal6}, - {1, 0, 0, 6, gWonderCardBgGfx7, gWonderCardBgTilemap7, gWonderCardBgPal7}, - {1, 0, 0, 7, gWonderCardBgGfx8, gWonderCardBgTilemap8, gWonderCardBgPal8} -}; - -bool32 InitWonderCardResources(struct WonderCard * r5, struct MEventBuffer_3430_Sub * r6) -{ - if (r5 == NULL || r6 == NULL) - return FALSE; - sWonderCardData = AllocZeroed(sizeof(struct UnkStruct_203F3C8)); - if (sWonderCardData == NULL) - return FALSE; - sWonderCardData->unk_0000 = *r5; - sWonderCardData->unk_014C = *r6; - if (sWonderCardData->unk_0000.unk_08_2 >= ARRAY_COUNT(gUnknown_082F1D60)) - sWonderCardData->unk_0000.unk_08_2 = 0; - if (sWonderCardData->unk_0000.unk_08_0 >= ARRAY_COUNT(gUnknown_082F0E18)) - sWonderCardData->unk_0000.unk_08_0 = 0; - if (sWonderCardData->unk_0000.unk_09 > ARRAY_COUNT(sWonderCardData->unk_017D)) - sWonderCardData->unk_0000.unk_09 = 0; - sWonderCardData->unk_0170 = &gUnknown_082F1D60[sWonderCardData->unk_0000.unk_08_2]; - return TRUE; -} - -void DestroyWonderCardResources(void) -{ - if (sWonderCardData != NULL) - { - *sWonderCardData = (struct UnkStruct_203F3C8){}; - Free(sWonderCardData); - sWonderCardData = NULL; - } -} - -s32 FadeToWonderCardMenu(void) -{ - if (sWonderCardData == NULL) - return -1; - switch(sWonderCardData->unk_0174) - { - case 0: - BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - break; - case 1: - if (UpdatePaletteFade()) - return 0; - break; - case 2: - FillBgTilemapBufferRect_Palette0(0, 0x000, 0, 0, 30, 20); - FillBgTilemapBufferRect_Palette0(1, 0x000, 0, 0, 30, 20); - FillBgTilemapBufferRect_Palette0(2, 0x000, 0, 0, 30, 20); - CopyBgTilemapBufferToVram(0); - CopyBgTilemapBufferToVram(1); - CopyBgTilemapBufferToVram(2); - DecompressAndCopyTileDataToVram(2, sWonderCardData->unk_0170->tiles, 0, 0x008, 0); - sWonderCardData->unk_0176[0] = AddWindow(&gUnknown_082F0E1C[0]); - sWonderCardData->unk_0176[1] = AddWindow(&gUnknown_082F0E1C[1]); - sWonderCardData->unk_0176[2] = AddWindow(&gUnknown_082F0E1C[2]); - break; - case 3: - if (FreeTempTileDataBuffersIfPossible()) - return 0; - LoadPalette(GetTextWindowPalette(1), 0x20, 0x20); - gPaletteFade.bufferTransferDisabled = TRUE; - LoadPalette(sWonderCardData->unk_0170->pal, 0x10, 0x20); - LZ77UnCompWram(sWonderCardData->unk_0170->map, sWonderCardData->buffer_045C); - CopyRectToBgTilemapBufferRect(2, sWonderCardData->buffer_045C, 0, 0, 30, 20, 0, 0, 30, 20, 1, 0x008, 0); - CopyBgTilemapBufferToVram(2); - break; - case 4: - sub_801BEF8(); - break; - case 5: - sub_801C178(0); - sub_801C178(1); - sub_801C178(2); - CopyBgTilemapBufferToVram(1); - break; - case 6: - LoadMonIconPalettes(); - break; - case 7: - ShowBg(1); - ShowBg(2); - gPaletteFade.bufferTransferDisabled = FALSE; - sub_801C4C0(); - BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); - UpdatePaletteFade(); - break; - default: - if (UpdatePaletteFade()) - return 0; - sWonderCardData->unk_0174 = 0; - return 1; - } - ++sWonderCardData->unk_0174; - return 0; -} - -s32 FadeOutFromWonderCard(bool32 flag) -{ - if (sWonderCardData == NULL) - return -1; - switch (sWonderCardData->unk_0174) - { - case 0: - BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - break; - case 1: - if (UpdatePaletteFade()) - return 0; - break; - case 2: - FillBgTilemapBufferRect_Palette0(0, 0x000, 0, 0, 30, 20); - FillBgTilemapBufferRect_Palette0(1, 0x000, 0, 0, 30, 20); - FillBgTilemapBufferRect_Palette0(2, 0x000, 0, 0, 30, 20); - CopyBgTilemapBufferToVram(0); - CopyBgTilemapBufferToVram(1); - CopyBgTilemapBufferToVram(2); - break; - case 3: - HideBg(1); - HideBg(2); - RemoveWindow(sWonderCardData->unk_0176[2]); - RemoveWindow(sWonderCardData->unk_0176[1]); - RemoveWindow(sWonderCardData->unk_0176[0]); - break; - case 4: - sub_801C61C(); - FreeMonIconPalettes(); - break; - case 5: - PrintMysteryGiftOrEReaderTopMenu(gGiftIsFromEReader, flag); - CopyBgTilemapBufferToVram(0); - BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); - break; - default: - if (UpdatePaletteFade()) - return 0; - sWonderCardData->unk_0174 = 0; - return 1; - } - ++sWonderCardData->unk_0174; - return 0; -} - -void sub_801BEF8(void) -{ - u16 i = 0; - u16 r6; - u16 sp0[3] = {0, 0, 0}; - - memcpy(sWonderCardData->unk_018B, sWonderCardData->unk_0000.unk_0A, 40); - sWonderCardData->unk_018B[40] = EOS; - memcpy(sWonderCardData->unk_01B4, sWonderCardData->unk_0000.unk_32, 40); - sWonderCardData->unk_01B4[40] = EOS; - if (sWonderCardData->unk_0000.unk_04 > 999999) - sWonderCardData->unk_0000.unk_04 = 999999; - ConvertIntToDecimalStringN(sWonderCardData->unk_01DD, sWonderCardData->unk_0000.unk_04, STR_CONV_MODE_LEFT_ALIGN, 6); - for (i = 0; i < 4; i++) - { - memcpy(sWonderCardData->unk_01E4[i], sWonderCardData->unk_0000.unk_5A[i], 40); - sWonderCardData->unk_01E4[i][40] = EOS; - } - memcpy(sWonderCardData->unk_0288, sWonderCardData->unk_0000.unk_FA, 40); - sWonderCardData->unk_0288[40] = EOS; - switch (sWonderCardData->unk_0000.unk_08_0) - { - case 0: - memcpy(sWonderCardData->unk_02B1, sWonderCardData->unk_0000.unk_122, 40); - sWonderCardData->unk_02B1[40] = EOS; - break; - case 1: - sWonderCardData->unk_02B1[00] = EOS; - break; - case 2: - sWonderCardData->unk_02B1[00] = EOS; - sp0[0] = sWonderCardData->unk_014C.unk_00 < 999 ? sWonderCardData->unk_014C.unk_00 : 999; - sp0[1] = sWonderCardData->unk_014C.unk_02 < 999 ? sWonderCardData->unk_014C.unk_02 : 999; - sp0[2] = sWonderCardData->unk_014C.unk_04 < 999 ? sWonderCardData->unk_014C.unk_04 : 999; - for (i = 0; i < 8; i++) - { - memset(sWonderCardData->unk_02DC[i].unk_42, EOS, 4); - memset(sWonderCardData->unk_02DC[i].unk_01, EOS, 41); - } - for (i = 0, r6 = 0; i < 40; i++) - { - if (sWonderCardData->unk_0000.unk_122[i] != 0xF7) - { - sWonderCardData->unk_02DC[sWonderCardData->unk_0175].unk_01[r6] = sWonderCardData->unk_0000.unk_122[i]; - r6++; - } - else - { - u8 r3 = sWonderCardData->unk_0000.unk_122[i + 1]; - if (r3 > 2) - { - i += 2; - } - else - { - ConvertIntToDecimalStringN(sWonderCardData->unk_02DC[sWonderCardData->unk_0175].unk_42, sp0[r3], STR_CONV_MODE_LEADING_ZEROS, 3); - sWonderCardData->unk_02DC[sWonderCardData->unk_0175].unk_00 = sWonderCardData->unk_0000.unk_122[i + 2]; - sWonderCardData->unk_0175++; - if (sWonderCardData->unk_0175 > 7) - break; - r6 = 0; - i += 2; - } - } - } - } -} - -void sub_801C178(u8 whichWindow) -{ - s8 sp0C = 0; - s32 windowId = sWonderCardData->unk_0176[whichWindow]; - PutWindowTilemap(windowId); - FillWindowPixelBuffer(windowId, 0); - switch (whichWindow) - { - case 0: - { - s32 x; - AddTextPrinterParameterized3(windowId, 3, 0, 1, sTextColorTable[sWonderCardData->unk_0170->textPal1], 0, sWonderCardData->unk_018B); - x = 160 - GetStringWidth(3, sWonderCardData->unk_01B4, GetFontAttribute(3, 2)); - if (x < 0) - x = 0; - AddTextPrinterParameterized3(windowId, 3, x, 17, sTextColorTable[sWonderCardData->unk_0170->textPal1], 0, sWonderCardData->unk_01B4); - if (sWonderCardData->unk_0000.unk_04 != 0) - { - AddTextPrinterParameterized3(windowId, 1, 166, 17, sTextColorTable[sWonderCardData->unk_0170->textPal1], 0, sWonderCardData->unk_01DD); - } - break; - } - case 1: - for (; sp0C < 4; sp0C++) - { - AddTextPrinterParameterized3(windowId, 3, 0, 16 * sp0C + 2, sTextColorTable[sWonderCardData->unk_0170->textPal2], 0, sWonderCardData->unk_01E4[sp0C]); - } - break; - case 2: - AddTextPrinterParameterized3(windowId, 3, 0, gUnknown_082F0E18[sWonderCardData->unk_0000.unk_08_0], sTextColorTable[sWonderCardData->unk_0170->textPal3], 0, sWonderCardData->unk_0288); - if (sWonderCardData->unk_0000.unk_08_0 != 2) - { - AddTextPrinterParameterized3(windowId, 3, 0, 16 + gUnknown_082F0E18[sWonderCardData->unk_0000.unk_08_0], sTextColorTable[sWonderCardData->unk_0170->textPal3], 0, sWonderCardData->unk_02B1); - } - else - { - s32 x = 0; - s32 y = gUnknown_082F0E18[sWonderCardData->unk_0000.unk_08_0] + 16; - s32 spacing = GetFontAttribute(3, 2); - for (; sp0C < sWonderCardData->unk_0175; sp0C++) - { - AddTextPrinterParameterized3(windowId, 3, x, y, sTextColorTable[sWonderCardData->unk_0170->textPal3], 0, sWonderCardData->unk_02DC[sp0C].unk_01); - if (sWonderCardData->unk_02DC[sp0C].unk_42[0] != EOS) - { - x += GetStringWidth(3, sWonderCardData->unk_02DC[sp0C].unk_01, spacing); - AddTextPrinterParameterized3(windowId, 3, x, y, sTextColorTable[sWonderCardData->unk_0170->textPal3], 0, sWonderCardData->unk_02DC[sp0C].unk_42); - x += GetStringWidth(3, sWonderCardData->unk_02DC[sp0C].unk_42, spacing) + sWonderCardData->unk_02DC[sp0C].unk_00; - } - } - } - break; - } - CopyWindowToVram(windowId, 3); -} - -void sub_801C4C0(void) -{ - u8 r7 = 0; - sWonderCardData->unk_017C = 0xFF; - if (sWonderCardData->unk_014C.unk_06 != SPECIES_NONE) - { - sWonderCardData->unk_017C = CreateMonIconNoPersonality(GetIconSpeciesNoPersonality(sWonderCardData->unk_014C.unk_06), SpriteCallbackDummy, 0xDC, 0x14, 0, FALSE); - gSprites[sWonderCardData->unk_017C].oam.priority = 2; - } - if (sWonderCardData->unk_0000.unk_09 != 0 && sWonderCardData->unk_0000.unk_08_0 == 1) - { - LoadCompressedSpriteSheetUsingHeap(&gUnknown_082F1D00); - LoadSpritePalette(&gUnknown_082F1D08[sWonderCardData->unk_0170->textPal4]); - for (; r7 < sWonderCardData->unk_0000.unk_09; r7++) - { - sWonderCardData->unk_017D[r7][0] = 0xFF; - sWonderCardData->unk_017D[r7][1] = 0xFF; - sWonderCardData->unk_017D[r7][0] = CreateSprite(&gUnknown_082F1D48, 0xd8 - 32 * r7, 0x90, 8); - if (sWonderCardData->unk_014C.unk_08[0][r7] != 0) - { - sWonderCardData->unk_017D[r7][1] = CreateMonIconNoPersonality(GetIconSpeciesNoPersonality(sWonderCardData->unk_014C.unk_08[0][r7]), SpriteCallbackDummy, 0xd8 - 32 * r7, 0x88, 0, 0); - } - } - } -} - -void sub_801C61C(void) -{ - u8 r6 = 0; - if (sWonderCardData->unk_017C != 0xFF) - FreeAndDestroyMonIconSprite(&gSprites[sWonderCardData->unk_017C]); - if (sWonderCardData->unk_0000.unk_09 != 0 && sWonderCardData->unk_0000.unk_08_0 == 1) - { - for (; r6 < sWonderCardData->unk_0000.unk_09; r6++) - { - if (sWonderCardData->unk_017D[r6][0] != 0xFF) - { - DestroySprite(&gSprites[sWonderCardData->unk_017D[r6][0]]); - } - if (sWonderCardData->unk_017D[r6][1] != 0xFF) - { - FreeAndDestroyMonIconSprite(&gSprites[sWonderCardData->unk_017D[r6][1]]); - } - } - FreeSpriteTilesByTag(0x8000); - FreeSpritePaletteByTag(0x8000); - } -} - -struct UnkStruct_203F3CC -{ - /*0000*/ struct WonderNews unk_0000; - /*01bc*/ const struct UnkStruct_8467FB8 * unk_01BC; - /*01c0*/ u8 unk_01C0_0:1; - u8 unk_01C0_1:7; - /*01c1*/ u8 unk_01C1; - /*01c2*/ u8 unk_01C2_0:1; - u8 unk_01C2_1:7; - /*01c3*/ u8 unk_01C3_0:1; - u8 unk_01C3_1:7; - /*01c4*/ u16 unk_01C4; - /*01c6*/ u16 unk_01C6; - /*01c8*/ u16 unk_01C8[2]; - /*01cc*/ u8 filler_01CC[2]; - /*01ce*/ u8 unk_01CE[41]; - /*01f7*/ u8 unk_01F7[10][41]; - /*0394*/ struct ScrollArrowsTemplate unk_0394; - /*03a4*/ u8 buffer_03A4[0x1000]; -}; - -EWRAM_DATA struct UnkStruct_203F3CC * sWonderNewsData = NULL; - -void sub_801CDCC(void); -void sub_801CE7C(void); -void sub_801CFA4(void); - -const u8 gUnknown_082F1DE0[][3] = { - {0, 2, 3}, - {0, 1, 2} -}; -const struct WindowTemplate gUnknown_082F1DE8[] = { - { - .bg = 0, - .tilemapLeft = 1, - .tilemapTop = 0, - .width = 28, - .height = 3, - .paletteNum = 2, - .baseBlock = 0x2AC - }, { - .bg = 2, - .tilemapLeft = 1, - .tilemapTop = 3, - .width = 28, - .height = 20, - .paletteNum = 2, - .baseBlock = 0x07C - } -}; -const struct ScrollArrowsTemplate gUnknown_082F1DF8 = { - 0x02, 0xe8, 0x18, 0x03, 0xe8, 0x98, - 0x0000, 0x0002, 0x1000, 0x1000, 0x0 -}; -const u16 gWonderNewsPal1[] = INCBIN_U16("graphics/wonder_transfers/wonder_news_1.gbapal"); -const u16 gWonderNewsPal7[] = INCBIN_U16("graphics/wonder_transfers/wonder_news_7.gbapal"); -const u16 gWonderNewsPal8[] = INCBIN_U16("graphics/wonder_transfers/wonder_news_8.gbapal"); -const u32 gWonderNewsGfx1[] = INCBIN_U32("graphics/wonder_transfers/wonder_news_1.4bpp.lz"); -const u32 gWonderNewsTilemap1[] = INCBIN_U32("graphics/wonder_transfers/wonder_news_1.bin.lz"); -const u32 gWonderNewsGfx2[] = INCBIN_U32("graphics/wonder_transfers/wonder_news_2.4bpp.lz"); -const u32 gWonderNewsTilemap2[] = INCBIN_U32("graphics/wonder_transfers/wonder_news_2.bin.lz"); -const u32 gWonderNewsGfx3[] = INCBIN_U32("graphics/wonder_transfers/wonder_news_3.4bpp.lz"); -const u32 gWonderNewsTilemap3[] = INCBIN_U32("graphics/wonder_transfers/wonder_news_3.bin.lz"); -const u32 gWonderNewsGfx7[] = INCBIN_U32("graphics/wonder_transfers/wonder_news_7.4bpp.lz"); -const u32 gWonderNewsTilemap7[] = INCBIN_U32("graphics/wonder_transfers/wonder_news_7.bin.lz"); -const u32 gWonderNewsGfx8[] = INCBIN_U32("graphics/wonder_transfers/wonder_news_8.4bpp.lz"); -const u32 gWonderNewsTilemap8[] = INCBIN_U32("graphics/wonder_transfers/wonder_news_8.bin.lz"); - -const struct UnkStruct_8467FB8 gUnknown_082F24C8[] = { - {1, 0, 0, 0, gWonderNewsGfx1, gWonderNewsTilemap1, gWonderNewsPal1}, - {1, 0, 0, 0, gWonderNewsGfx2, gWonderNewsTilemap2, gWonderCardBgPal2}, - {1, 0, 0, 0, gWonderNewsGfx3, gWonderNewsTilemap3, gWonderCardBgPal3}, - {1, 0, 0, 0, gWonderNewsGfx3, gWonderNewsTilemap3, gWonderCardBgPal4}, - {1, 0, 0, 0, gWonderNewsGfx3, gWonderNewsTilemap3, gWonderCardBgPal5}, - {1, 0, 0, 0, gWonderNewsGfx3, gWonderNewsTilemap3, gWonderCardBgPal6}, - {1, 0, 0, 0, gWonderNewsGfx7, gWonderNewsTilemap7, gWonderNewsPal7}, - {1, 0, 0, 0, gWonderNewsGfx8, gWonderNewsTilemap8, gWonderNewsPal8} -}; - -bool32 InitWonderNewsResources(const struct WonderNews * a0) -{ - if (a0 == NULL) - return FALSE; - sWonderNewsData = AllocZeroed(sizeof(struct UnkStruct_203F3CC)); - if (sWonderNewsData == NULL) - return FALSE; - sWonderNewsData->unk_0000 = *a0; - if (sWonderNewsData->unk_0000.unk_03 >= ARRAY_COUNT(gUnknown_082F24C8)) - sWonderNewsData->unk_0000.unk_03 = 0; - sWonderNewsData->unk_01BC = &gUnknown_082F24C8[sWonderNewsData->unk_0000.unk_03]; - sWonderNewsData->unk_01C1 = 0xFF; - return TRUE; -} - -void DestroyWonderNewsResources(void) -{ - if (sWonderNewsData != NULL) - { - *sWonderNewsData = (struct UnkStruct_203F3CC){}; - Free(sWonderNewsData); - sWonderNewsData = NULL; - } -} - -s32 FadeToWonderNewsMenu(void) -{ - if (sWonderNewsData == NULL) - return -1; - - switch (sWonderNewsData->unk_01C0_1) - { - case 0: - BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - break; - case 1: - if (UpdatePaletteFade()) - return 0; - ChangeBgY(0, 0, 0); - ChangeBgY(1, 0, 0); - ChangeBgY(2, 0, 0); - ChangeBgY(3, 0, 0); - SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(0, DISPLAY_WIDTH)); - SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(26, 152)); - SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ); - SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WIN01_BG1 | WINOUT_WIN01_BG3 | WINOUT_WIN01_OBJ); - SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); - break; - case 2: - FillBgTilemapBufferRect_Palette0(0, 0x000, 0, 0, 30, 20); - FillBgTilemapBufferRect_Palette0(1, 0x000, 0, 0, 30, 20); - FillBgTilemapBufferRect_Palette0(2, 0x000, 0, 0, 30, 20); - FillBgTilemapBufferRect_Palette0(3, 0x000, 0, 0, 30, 20); - CopyBgTilemapBufferToVram(0); - CopyBgTilemapBufferToVram(1); - CopyBgTilemapBufferToVram(2); - CopyBgTilemapBufferToVram(3); - DecompressAndCopyTileDataToVram(3, sWonderNewsData->unk_01BC->tiles, 0, 8, 0); - sWonderNewsData->unk_01C8[0] = AddWindow(&gUnknown_082F1DE8[0]); - sWonderNewsData->unk_01C8[1] = AddWindow(&gUnknown_082F1DE8[1]); - break; - case 3: - if (FreeTempTileDataBuffersIfPossible()) - return 0; - LoadPalette(GetTextWindowPalette(1), 0x20, 0x20); - gPaletteFade.bufferTransferDisabled = TRUE; - LoadPalette(sWonderNewsData->unk_01BC->pal, 0x10, 0x20); - LZ77UnCompWram(sWonderNewsData->unk_01BC->map, sWonderNewsData->buffer_03A4); - CopyRectToBgTilemapBufferRect(1, sWonderNewsData->buffer_03A4, 0, 0, 30, 3, 0, 0, 30, 3, 1, 8, 0); - CopyRectToBgTilemapBufferRect(3, sWonderNewsData->buffer_03A4, 0, 3, 30, 23, 0, 3, 30, 23, 1, 8, 0); - CopyBgTilemapBufferToVram(1); - CopyBgTilemapBufferToVram(3); - break; - case 4: - sub_801CDCC(); - break; - case 5: - sub_801CE7C(); - CopyBgTilemapBufferToVram(0); - CopyBgTilemapBufferToVram(2); - break; - case 6: - ShowBg(1); - ShowBg(2); - ShowBg(3); - gPaletteFade.bufferTransferDisabled = FALSE; - sWonderNewsData->unk_01C1 = AddScrollIndicatorArrowPair(&sWonderNewsData->unk_0394, &sWonderNewsData->unk_01C6); - BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); - UpdatePaletteFade(); - break; - default: - if (UpdatePaletteFade()) - return 0; - sWonderNewsData->unk_01C0_1 = 0; - return 1; - } - - ++sWonderNewsData->unk_01C0_1; - return 0; -} - -s32 FadeOutFromWonderNews(bool32 flag) -{ - if (sWonderNewsData == NULL) - return -1; - switch (sWonderNewsData->unk_01C0_1) - { - case 0: - BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - break; - case 1: - if (UpdatePaletteFade()) - return 0; - ChangeBgY(2, 0, 0); - SetGpuReg(REG_OFFSET_WIN0H, 0); - SetGpuReg(REG_OFFSET_WIN0V, 0); - SetGpuReg(REG_OFFSET_WININ, 0); - SetGpuReg(REG_OFFSET_WINOUT, 0); - ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); - break; - case 2: - FillBgTilemapBufferRect_Palette0(0, 0x000, 0, 0, 30, 20); - FillBgTilemapBufferRect_Palette0(1, 0x000, 0, 0, 30, 20); - FillBgTilemapBufferRect_Palette0(2, 0x000, 0, 0, 30, 24); - FillBgTilemapBufferRect_Palette0(3, 0x000, 0, 0, 30, 24); - CopyBgTilemapBufferToVram(0); - CopyBgTilemapBufferToVram(1); - CopyBgTilemapBufferToVram(2); - CopyBgTilemapBufferToVram(3); - break; - case 3: - HideBg(1); - HideBg(2); - RemoveWindow(sWonderNewsData->unk_01C8[1]); - RemoveWindow(sWonderNewsData->unk_01C8[0]); - break; - case 4: - ChangeBgY(2, 0, 0); - ChangeBgY(3, 0, 0); - if (sWonderNewsData->unk_01C1 != 0xFF) - { - RemoveScrollIndicatorArrowPair(sWonderNewsData->unk_01C1); - sWonderNewsData->unk_01C1 = 0xFF; - } - break; - case 5: - PrintMysteryGiftOrEReaderTopMenu(gGiftIsFromEReader, flag); - MG_DrawCheckerboardPattern(3); - CopyBgTilemapBufferToVram(0); - CopyBgTilemapBufferToVram(3); - BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); - break; - default: - if (UpdatePaletteFade()) - return 0; - sWonderNewsData->unk_01C0_1 = 0; - return 1; - } - ++sWonderNewsData->unk_01C0_1; - return 0; -} - -void MENews_RemoveScrollIndicatorArrowPair(void) -{ - if (!sWonderNewsData->unk_01C0_0 && sWonderNewsData->unk_01C1 != 0xFF) - { - RemoveScrollIndicatorArrowPair(sWonderNewsData->unk_01C1); - sWonderNewsData->unk_01C1 = 0xFF; - sWonderNewsData->unk_01C0_0 = TRUE; - } -} - - -void MENews_AddScrollIndicatorArrowPair(void) -{ - if (sWonderNewsData->unk_01C0_0) - { - sWonderNewsData->unk_01C1 = AddScrollIndicatorArrowPair(&sWonderNewsData->unk_0394, &sWonderNewsData->unk_01C6); - sWonderNewsData->unk_01C0_0 = FALSE; - } -} - -u32 MENews_GetInput(u16 input) -{ - if (sWonderNewsData->unk_01C2_0) - { - sub_801CFA4(); - return 0xFF; - } - switch (input) - { - case A_BUTTON: - return 0; - case B_BUTTON: - return 1; - case DPAD_UP: - if (sWonderNewsData->unk_01C6 == 0) - return 0xFF; - if (sWonderNewsData->unk_01C0_0) - return 0xFF; - sWonderNewsData->unk_01C3_0 = FALSE; - break; - case DPAD_DOWN: - if (sWonderNewsData->unk_01C6 == sWonderNewsData->unk_01C4) - return 0xFF; - if (sWonderNewsData->unk_01C0_0) - return 0xFF; - sWonderNewsData->unk_01C3_0 = TRUE; - break; - default: - return 0xFF; - } - sWonderNewsData->unk_01C2_0 = TRUE; - sWonderNewsData->unk_01C2_1 = 2; - sWonderNewsData->unk_01C3_1 = 0; - if (sWonderNewsData->unk_01C3_0 == FALSE) - return 2; - else - return 3; -} - -void sub_801CDCC(void) -{ - u8 i = 0; - memcpy(sWonderNewsData->unk_01CE, sWonderNewsData->unk_0000.unk_04, 40); - sWonderNewsData->unk_01CE[40] = EOS; - for (; i < 10; ++i) - { - memcpy(sWonderNewsData->unk_01F7[i], sWonderNewsData->unk_0000.unk_2C[i], 40); - sWonderNewsData->unk_01F7[i][40] = EOS; - if (i > 7 && sWonderNewsData->unk_01F7[i][0] != EOS) - ++sWonderNewsData->unk_01C4; - } - sWonderNewsData->unk_0394 = gUnknown_082F1DF8; - sWonderNewsData->unk_0394.fullyDownThreshold = sWonderNewsData->unk_01C4; -} - -void sub_801CE7C(void) -{ - u8 i = 0; - s32 x; - PutWindowTilemap(sWonderNewsData->unk_01C8[0]); - PutWindowTilemap(sWonderNewsData->unk_01C8[1]); - FillWindowPixelBuffer(sWonderNewsData->unk_01C8[0], 0); - FillWindowPixelBuffer(sWonderNewsData->unk_01C8[1], 0); - x = (0xe0 - GetStringWidth(3, sWonderNewsData->unk_01CE, GetFontAttribute(3, 2))) / 2; - if (x < 0) - x = 0; - AddTextPrinterParameterized3(sWonderNewsData->unk_01C8[0], 3, x, 6, gUnknown_082F1DE0[sWonderNewsData->unk_01BC->textPal1], 0, sWonderNewsData->unk_01CE); - for (; i < 10; ++i) - { - AddTextPrinterParameterized3(sWonderNewsData->unk_01C8[1], 3, 0, 16 * i + 2, gUnknown_082F1DE0[sWonderNewsData->unk_01BC->textPal2], 0, sWonderNewsData->unk_01F7[i]); - } - CopyWindowToVram(sWonderNewsData->unk_01C8[0], 3); - CopyWindowToVram(sWonderNewsData->unk_01C8[1], 3); -} - -void sub_801CFA4(void) -{ - u16 r4 = sWonderNewsData->unk_01C2_1; - r4 <<= 8; - if (sWonderNewsData->unk_01C3_0) - { - ChangeBgY(2, r4, 1); - ChangeBgY(3, r4, 1); - } - else - { - ChangeBgY(2, r4, 2); - ChangeBgY(3, r4, 2); - } - sWonderNewsData->unk_01C3_1 += sWonderNewsData->unk_01C2_1; - if (sWonderNewsData->unk_01C3_1 > 15) - { - if (sWonderNewsData->unk_01C3_0) - ++sWonderNewsData->unk_01C6; - else - --sWonderNewsData->unk_01C6; - sWonderNewsData->unk_01C2_0 = FALSE; - sWonderNewsData->unk_01C3_1 = 0; - } -} diff --git a/src/mevent_client.c b/src/mevent_client.c deleted file mode 100644 index 9a62bf18e..000000000 --- a/src/mevent_client.c +++ /dev/null @@ -1,291 +0,0 @@ -#include "global.h" -#include "malloc.h" -#include "decompress.h" -#include "overworld.h" -#include "script.h" -#include "battle_tower.h" -#include "mevent.h" -#include "mystery_event_script.h" -#include "mevent_client.h" - -EWRAM_DATA struct mevent_client * s_mevent_client_ptr = NULL; - -static void mevent_client_init(struct mevent_client *, u32, u32); -static u32 mevent_client_exec(struct mevent_client *); -static void mevent_client_free_resources(struct mevent_client *); - -extern const struct mevent_client_cmd gUnknown_082F2598[]; - -void mevent_client_do_init(u32 arg) -{ - s_mevent_client_ptr = AllocZeroed(sizeof(struct mevent_client)); - mevent_client_init(s_mevent_client_ptr, 1, 0); - s_mevent_client_ptr->unk_4C = arg; -} - -u32 mevent_client_do_exec(u16 * a0) -{ - u32 result; - if (s_mevent_client_ptr == NULL) - return 6; - result = mevent_client_exec(s_mevent_client_ptr); - if (result == 6) - { - *a0 = s_mevent_client_ptr->param; - mevent_client_free_resources(s_mevent_client_ptr); - Free(s_mevent_client_ptr); - s_mevent_client_ptr = NULL; - } - return result; -} - -void mevent_client_inc_flag(void) -{ - s_mevent_client_ptr->flag++; -} - -void * mevent_client_get_buffer(void) -{ - return s_mevent_client_ptr->buffer; -} - -void mevent_client_set_param(u32 a0) -{ - s_mevent_client_ptr->param = a0; -} - -static void mevent_client_init(struct mevent_client * svr, u32 sendPlayerNo, u32 recvPlayerNo) -{ - svr->unk_00 = 0; - svr->mainseqno = 0; - svr->flag = 0; - svr->sendBuffer = AllocZeroed(ME_SEND_BUF_SIZE); - svr->recvBuffer = AllocZeroed(ME_SEND_BUF_SIZE); - svr->cmdBuffer = AllocZeroed(ME_SEND_BUF_SIZE); - svr->buffer = AllocZeroed(0x40); - mevent_srv_sub_init(&svr->manager, sendPlayerNo, recvPlayerNo); -} - -static void mevent_client_free_resources(struct mevent_client * svr) -{ - Free(svr->sendBuffer); - Free(svr->recvBuffer); - Free(svr->cmdBuffer); - Free(svr->buffer); -} - -static void mevent_client_jmp_buffer(struct mevent_client * svr) -{ - memcpy(svr->cmdBuffer, svr->recvBuffer, ME_SEND_BUF_SIZE); - svr->cmdidx = 0; -} - -static void mevent_client_send_word(struct mevent_client * svr, u32 ident, u32 word) -{ - CpuFill32(0, svr->sendBuffer, ME_SEND_BUF_SIZE); - *(u32 *)svr->sendBuffer = word; - mevent_srv_sub_init_send(&svr->manager, ident, svr->sendBuffer, sizeof(u32)); -} - -static u32 mainseq_0(struct mevent_client * svr) -{ - // init - memcpy(svr->cmdBuffer, gUnknown_082F2598, ME_SEND_BUF_SIZE); - svr->cmdidx = 0; - svr->mainseqno = 4; - svr->flag = 0; - return 0; -} - -static u32 mainseq_1(struct mevent_client * svr) -{ - // done - return 6; -} - - -static u32 mainseq_2(struct mevent_client * svr) -{ - // do recv - if (mevent_srv_sub_recv(&svr->manager)) - { - svr->mainseqno = 4; - svr->flag = 0; - } - return 1; -} - -static u32 mainseq_3(struct mevent_client * svr) -{ - // do send - if (mevent_srv_sub_send(&svr->manager)) - { - svr->mainseqno = 4; - svr->flag = 0; - } - return 1; -} - -static u32 mainseq_4(struct mevent_client * svr) -{ - // process command - struct mevent_client_cmd * cmd = &svr->cmdBuffer[svr->cmdidx]; - ++svr->cmdidx; - switch (cmd->instr) - { - case 0: - break; - case 1: - svr->param = cmd->parameter; - svr->mainseqno = 1; - svr->flag = 0; - break; - case 2: - mevent_srv_sub_init_recv(&svr->manager, cmd->parameter, svr->recvBuffer); - svr->mainseqno = 2; - svr->flag = 0; - break; - case 3: - svr->mainseqno = 3; - svr->flag = 0; - break; - case 20: - mevent_srv_sub_init_send(&svr->manager, 0x14, svr->sendBuffer, 0); - svr->mainseqno = 3; - svr->flag = 0; - break; - case 19: - mevent_client_send_word(svr, 0x12, GetGameStat(cmd->parameter)); - svr->mainseqno = 3; - svr->flag = 0; - break; - case 6: - if (svr->param == 0) - mevent_client_jmp_buffer(svr); - break; - case 7: - if (svr->param == 1) - mevent_client_jmp_buffer(svr); - break; - case 4: - mevent_client_jmp_buffer(svr); - break; - case 5: - memcpy(svr->buffer, svr->recvBuffer, 0x40); - svr->mainseqno = 5; - svr->flag = 0; - return 2; - case 11: - memcpy(svr->buffer, svr->recvBuffer, 0x40); - svr->mainseqno = 5; - svr->flag = 0; - return 3; - case 12: - memcpy(svr->buffer, svr->recvBuffer, 0x40); - svr->mainseqno = 5; - svr->flag = 0; - return 5; - case 13: - svr->mainseqno = 5; - svr->flag = 0; - return 4; - case 8: - sub_801B580(svr->sendBuffer, svr->unk_4C); - mevent_srv_sub_init_send(&svr->manager, 0x11, svr->sendBuffer, sizeof(struct MEventStruct_Unk1442CC)); - break; - case 14: - mevent_client_send_word(svr, 0x13, svr->param); - break; - case 10: - sub_801B21C(svr->recvBuffer); - break; - case 9: - if (!sub_801B1A4(svr->recvBuffer)) - { - sub_801B078(svr->recvBuffer); - mevent_client_send_word(svr, 0x13, 0); - } - else - mevent_client_send_word(svr, 0x13, 1); - break; - case 15: - svr->mainseqno = 6; - svr->flag = 0; - break; - case 16: - sub_801B508(svr->recvBuffer); - break; - case 17: - InitRamScript_NoObjectEvent(svr->recvBuffer, 1000); - break; - case 18: - memcpy(&gSaveBlock2Ptr->frontier.ereaderTrainer, svr->recvBuffer, 0xbc); - ValidateEReaderTrainer(); - break; - case 21: - memcpy(gDecompressionBuffer, svr->recvBuffer, ME_SEND_BUF_SIZE); - svr->mainseqno = 7; - svr->flag = 0; - break; - } - - return 1; -} - -static u32 mainseq_5(struct mevent_client * svr) -{ - // wait flag - if (svr->flag) - { - svr->mainseqno = 4; - svr->flag = 0; - } - return 1; -} - -static u32 mainseq_6(struct mevent_client * svr) -{ - // ??? - switch (svr->flag) - { - case 0: - sub_8153870(svr->recvBuffer); - ++svr->flag; - break; - case 1: - if (!sub_8153884(&svr->param)) - { - svr->mainseqno = 4; - svr->flag = 0; - } - break; - } - return 1; -} - -static u32 mainseq_7(struct mevent_client * svr) -{ - // exec arbitrary code - u32 (*func)(u32 *, struct SaveBlock2 *, struct SaveBlock1 *) = (void *)gDecompressionBuffer; - if (func(&svr->param, gSaveBlock2Ptr, gSaveBlock1Ptr) == 1) - { - svr->mainseqno = 4; - svr->flag = 0; - } - return 1; -} - -static u32 mevent_client_exec(struct mevent_client * svr) -{ - u32 (*funcs[])(struct mevent_client *) = { - mainseq_0, - mainseq_1, - mainseq_2, - mainseq_3, - mainseq_4, - mainseq_5, - mainseq_6, - mainseq_7 - }; - return funcs[svr->mainseqno](svr); -} diff --git a/src/mevent_news.c b/src/mevent_news.c deleted file mode 100644 index 9e78cf406..000000000 --- a/src/mevent_news.c +++ /dev/null @@ -1,148 +0,0 @@ -#include "global.h" -#include "mevent.h" -#include "random.h" -#include "event_data.h" -#include "mevent_news.h" - -static u32 sub_801DCAC(struct MysteryEventStruct *); -static void sub_801DD10(struct MysteryEventStruct *); -static u32 sub_801DD44(struct MysteryEventStruct *); -static void sub_801DCD8(struct MysteryEventStruct *); -static void sub_801DCCC(struct MysteryEventStruct *); - -void GenerateRandomNews(u32 a0) -{ - struct MysteryEventStruct *r5 = sub_801B044(); - - r5->unk_0_0 = a0; - switch (a0) - { - case 0: - break; - case 1: - case 2: - r5->unk_1 = (Random() % 15) + 16; - break; - case 3: - r5->unk_1 = (Random() % 15) + 1; - break; - } -} - -void sub_801DBC0(void) -{ - struct MysteryEventStruct *r5 = sub_801B044(); - - r5->unk_0_0 = 0; - r5->unk_0_2 = 0; - r5->unk_0_5 = 0; - r5->unk_1 = 0; - VarSet(VAR_0x402E, 0); -} - -void sub_801DBDC(void) -{ - u16 *r4 = GetVarPointer(VAR_0x402E); - struct MysteryEventStruct *r2 = sub_801B044(); - struct MysteryEventStruct r0 = *r2; - - if ((u8)r0.unk_0_5 > 4 && ++(*r4) > 0x1f3) - { - r2->unk_0_5 = 0; - *r4 = 0; - } -} - -// Unused -u16 sub_801DC20(void) -{ - u16 *r6 = &gSpecialVar_Result; - struct MysteryEventStruct *r4 = sub_801B044(); - u16 r5; - - if (!IsMysteryEventEnabled() || !ValidateReceivedWonderNews()) - return 0; - - r5 = sub_801DD44(r4); - - switch (r5) - { - case 0: - break; - case 1: - *r6 = sub_801DCAC(r4); - break; - case 2: - *r6 = sub_801DCAC(r4); - break; - case 3: - break; - case 4: - *r6 = sub_801DCAC(r4); - sub_801DCD8(r4); - break; - case 5: - *r6 = sub_801DCAC(r4); - sub_801DCCC(r4); - break; - case 6: - break; - } - - return r5; -} - -static u32 sub_801DCAC(struct MysteryEventStruct *a0) -{ - u32 r4; - - a0->unk_0_0 = 0; - r4 = a0->unk_1 + 0x84; - a0->unk_1 = 0; - sub_801DD10(a0); - return r4; -} - -static void sub_801DCCC(struct MysteryEventStruct *a0) -{ - a0->unk_0_2 = 0; -} - -static void sub_801DCD8(struct MysteryEventStruct *a0) -{ - a0->unk_0_2++; - if ((u8)a0->unk_0_2 > 4) - a0->unk_0_2 = 4; -} - -static void sub_801DD10(struct MysteryEventStruct *a0) -{ - a0->unk_0_5++; - if ((u8)a0->unk_0_5 > 5) - a0->unk_0_5 = 5; -} - -static u32 sub_801DD44(struct MysteryEventStruct *a0) -{ - struct MysteryEventStruct r0; - if ((u8)a0->unk_0_5 == 5) - return 6; - - r0 = *a0; - switch (r0.unk_0_0) - { - case 0: - return 3; - case 1: - return 1; - case 2: - return 2; - case 3: - if ((u8)r0.unk_0_2 < 3) - return 4; - return 5; - default: - AGB_ASSERT(0); - return 0; - } -} diff --git a/src/mevent_scripts.c b/src/mevent_scripts.c deleted file mode 100644 index 41a5ddd51..000000000 --- a/src/mevent_scripts.c +++ /dev/null @@ -1,191 +0,0 @@ -#include "global.h" -#include "mevent_client.h" -#include "mevent_server.h" - -const u8 gText_CanceledReadingCard[] = _("Canceled reading\nthe Card."); - - -const struct mevent_client_cmd gUnknown_082F2598[] = { - {.instr = 2, .parameter = 16}, - {.instr = 4, .parameter = 0} -}; - -const struct mevent_client_cmd gUnknown_082F25A8[] = { - {.instr = 8, .parameter = 0}, - {.instr = 3, .parameter = 0}, - {.instr = 2, .parameter = 16}, - {.instr = 4, .parameter = 0} -}; - -const struct mevent_client_cmd gUnknown_082F25C8[] = { - {.instr = 20, .parameter = 0}, - {.instr = 1, .parameter = 10} -}; - -const struct mevent_client_cmd gUnknown_082F25D8[] = { - {.instr = 20, .parameter = 0}, - {.instr = 1, .parameter = 11} -}; - -const struct mevent_client_cmd gUnknown_082F25E8[] = { - {.instr = 20, .parameter = 0}, - {.instr = 1, .parameter = 0} -}; - -const struct mevent_client_cmd gUnknown_082F25F8[] = { - {.instr = 2, .parameter = 22}, - {.instr = 10, .parameter = 0}, - {.instr = 2, .parameter = 25}, - {.instr = 17, .parameter = 0}, - {.instr = 20, .parameter = 0}, - {.instr = 1, .parameter = 2} -}; - -const struct mevent_client_cmd gUnknown_082F2628[] = { - {.instr = 2, .parameter = 23}, - {.instr = 9, .parameter = 0}, - {.instr = 3, .parameter = 0}, - {.instr = 2, .parameter = 16}, - {.instr = 4, .parameter = 0} -}; - -const struct mevent_client_cmd gUnknown_082F2650[] = { - {.instr = 20, .parameter = 0}, - {.instr = 1, .parameter = 7} -}; - -const struct mevent_client_cmd gUnknown_082F2660[] = { - {.instr = 20, .parameter = 0}, - {.instr = 1, .parameter = 3} -}; - -const struct mevent_client_cmd gUnknown_082F2670[] = { - {.instr = 13, .parameter = 0}, - {.instr = 14, .parameter = 0}, - {.instr = 3, .parameter = 0}, - {.instr = 2, .parameter = 16}, - {.instr = 4, .parameter = 0} -}; - -const struct mevent_client_cmd gUnknown_082F2698[] = { - {.instr = 20, .parameter = 0}, - {.instr = 1, .parameter = 9} -}; - -const struct mevent_client_cmd gUnknown_082F26A8[] = { - {.instr = 20, .parameter = 0}, - {.instr = 1, .parameter = 5} -}; - -const struct mevent_client_cmd gUnknown_082F26B8[] = { - {.instr = 2, .parameter = 21}, - {.instr = 12, .parameter = 0}, - {.instr = 20, .parameter = 0}, - {.instr = 1, .parameter = 14}, - {.instr = 2, .parameter = 21}, - {.instr = 12, .parameter = 0}, - {.instr = 20, .parameter = 0}, - {.instr = 1, .parameter = 13} -}; - -const struct mevent_cmd gUnknown_082F26F8[] = { - {.instr = 18, .flag = 0x10, .parameter = gUnknown_082F25C8}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x14, .parameter = NULL}, - {.instr = 0, .flag = 0x0a, .parameter = NULL}, - {.instr = 18, .flag = 0x10, .parameter = gUnknown_082F25D8}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x14, .parameter = NULL}, - {.instr = 0, .flag = 0x0b, .parameter = NULL}, - {.instr = 18, .flag = 0x10, .parameter = gUnknown_082F2698}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x14, .parameter = NULL}, - {.instr = 0, .flag = 0x09, .parameter = NULL} -}; - -const struct mevent_cmd gUnknown_082F2788[] = { - {.instr = 18, .flag = 0x20, .parameter = gUnknown_082F26B8}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 20, .flag = 0x1b, .parameter = gText_CanceledReadingCard}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x14, .parameter = NULL}, - {.instr = 0, .flag = 0x09, .parameter = NULL} -}; - -const struct mevent_cmd gUnknown_082F27D0[] = { - {.instr = 18, .flag = 0x10, .parameter = gUnknown_082F2650}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x14, .parameter = NULL}, - {.instr = 0, .flag = 0x07, .parameter = NULL} -}; - -const struct mevent_cmd gUnknown_082F2800[] = { - {.instr = 18, .flag = 0x28, .parameter = gUnknown_082F2628}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 14, .flag = 0x00, .parameter = NULL}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x13, .parameter = NULL}, - {.instr = 8, .flag = 0x00, .parameter = NULL}, - {.instr = 4, .flag = 0x01, .parameter = gUnknown_082F27D0}, - {.instr = 18, .flag = 0x10, .parameter = gUnknown_082F2660}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x14, .parameter = NULL}, - {.instr = 0, .flag = 0x03, .parameter = NULL} -}; - -const struct mevent_cmd gUnknown_082F2884[] = { - {.instr = 18, .flag = 0x30, .parameter = gUnknown_082F25F8}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 13, .flag = 0x00, .parameter = NULL}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 15, .flag = 0x00, .parameter = NULL}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x14, .parameter = NULL}, - {.instr = 0, .flag = 0x02, .parameter = NULL} -}; - -const struct mevent_cmd gUnknown_082F28E4[] = { - {.instr = 18, .flag = 0x28, .parameter = gUnknown_082F2670}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x13, .parameter = NULL}, - {.instr = 8, .flag = 0x00, .parameter = NULL}, - {.instr = 4, .flag = 0x00, .parameter = gUnknown_082F2884}, - {.instr = 3, .flag = 0x00, .parameter = gUnknown_082F2788} -}; - -const struct mevent_cmd gUnknown_082F292C[] = { - {.instr = 18, .flag = 0x10, .parameter = gUnknown_082F26A8}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x14, .parameter = NULL}, - {.instr = 0, .flag = 0x05, .parameter = NULL}, - {.instr = 18, .flag = 0x10, .parameter = gUnknown_082F25E8}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x14, .parameter = NULL}, - {.instr = 0, .flag = 0x00, .parameter = NULL} -}; - -const struct mevent_cmd s_mevent_wonder_news[] = { - {.instr = 27, .flag = 0x00, .parameter = NULL}, - {.instr = 18, .flag = 0x20, .parameter = gUnknown_082F25A8}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x11, .parameter = NULL}, - {.instr = 5, .flag = 0x00, .parameter = NULL}, - {.instr = 30, .flag = 0x00, .parameter = NULL}, - {.instr = 4, .flag = 0x00, .parameter = gUnknown_082F26F8}, - {.instr = 3, .flag = 0x00, .parameter = gUnknown_082F2800} -}; - -const struct mevent_cmd s_mevent_wonder_card[] = { - {.instr = 26, .flag = 0x00, .parameter = NULL}, - {.instr = 28, .flag = 0x00, .parameter = NULL}, - {.instr = 18, .flag = 0x20, .parameter = gUnknown_082F25A8}, - {.instr = 1, .flag = 0x00, .parameter = NULL}, - {.instr = 2, .flag = 0x11, .parameter = NULL}, - {.instr = 5, .flag = 0x00, .parameter = NULL}, - {.instr = 6, .flag = 0x00, .parameter = NULL}, - {.instr = 4, .flag = 0x00, .parameter = gUnknown_082F26F8}, - {.instr = 7, .flag = 0x00, .parameter = NULL}, - {.instr = 4, .flag = 0x02, .parameter = gUnknown_082F28E4}, - {.instr = 4, .flag = 0x00, .parameter = gUnknown_082F2884}, - {.instr = 3, .flag = 0x00, .parameter = gUnknown_082F292C} -}; diff --git a/src/mevent_server.c b/src/mevent_server.c deleted file mode 100644 index 2e7b3d89a..000000000 --- a/src/mevent_server.c +++ /dev/null @@ -1,295 +0,0 @@ -#include "global.h" -#include "malloc.h" -#include "script.h" -#include "mevent.h" -#include "mevent_server.h" -#include "mevent_server_helpers.h" - -EWRAM_DATA struct mevent_srv_common * s_mevent_srv_common_ptr = NULL; - -static void mevent_srv_init_common(struct mevent_srv_common *, const void *, u32, u32); -static void mevent_srv_free_resources(struct mevent_srv_common *); -static u32 mevent_srv_exec_common(struct mevent_srv_common *); - -extern const struct mevent_cmd s_mevent_wonder_news[]; -extern const struct mevent_cmd s_mevent_wonder_card[]; - -void mevent_srv_init_wnews(void) -{ - s_mevent_srv_common_ptr = AllocZeroed(sizeof(struct mevent_srv_common)); - mevent_srv_init_common(s_mevent_srv_common_ptr, s_mevent_wonder_news, 0, 1); -} - -void mevent_srv_new_wcard(void) -{ - s_mevent_srv_common_ptr = AllocZeroed(sizeof(struct mevent_srv_common)); - mevent_srv_init_common(s_mevent_srv_common_ptr, s_mevent_wonder_card, 0, 1); -} - -u32 mevent_srv_common_do_exec(u16 * a0) -{ - u32 result; - if (s_mevent_srv_common_ptr == NULL) - return 3; - result = mevent_srv_exec_common(s_mevent_srv_common_ptr); - if (result == 3) - { - *a0 = s_mevent_srv_common_ptr->param; - mevent_srv_free_resources(s_mevent_srv_common_ptr); - Free(s_mevent_srv_common_ptr); - s_mevent_srv_common_ptr = NULL; - } - return result; -} - -static void mevent_srv_init_common(struct mevent_srv_common * svr, const void * cmdBuffer, u32 sendPlayerNo, u32 recvPlayerNo) -{ - svr->unk_00 = 0; - svr->mainseqno = 0; - svr->wonder_card = AllocZeroed(sizeof(struct WonderCard)); - svr->wonder_news = AllocZeroed(sizeof(struct WonderNews)); - svr->recvBuffer = AllocZeroed(ME_SEND_BUF_SIZE); - svr->mevent_unk1442cc = AllocZeroed(sizeof(struct MEventStruct_Unk1442CC)); - svr->cmdBuffer = cmdBuffer; - svr->cmdidx = 0; - mevent_srv_sub_init(&svr->manager, sendPlayerNo, recvPlayerNo); -} - -static void mevent_srv_free_resources(struct mevent_srv_common * svr) -{ - Free(svr->wonder_card); - Free(svr->wonder_news); - Free(svr->recvBuffer); - Free(svr->mevent_unk1442cc); -} - -void mevent_srv_common_init_send(struct mevent_srv_common * svr, u32 ident, const void * src, u32 size) -{ - AGB_ASSERT(size <= ME_SEND_BUF_SIZE); - mevent_srv_sub_init_send(&svr->manager, ident, src, size); -} - -static const void * mevent_first_if_not_null_else_second(const void * a0, const void * a1) -{ - if (a0 != NULL) - return a0; - else - return a1; -} - -static u32 mevent_compare_pointers(const void * a0, const void * a1) -{ - if (a1 < a0) - return 0; - else if (a1 == a0) - return 1; - else - return 2; -} - -static u32 common_mainseq_0(struct mevent_srv_common * svr) -{ - // start - svr->mainseqno = 4; - return 0; -} - -static u32 common_mainseq_1(struct mevent_srv_common * svr) -{ - // done - return 3; -} - -static u32 common_mainseq_2(struct mevent_srv_common * svr) -{ - // do recv - if (mevent_srv_sub_recv(&svr->manager)) - svr->mainseqno = 4; - return 1; -} - -static u32 common_mainseq_3(struct mevent_srv_common * svr) -{ - // do send - if (mevent_srv_sub_send(&svr->manager)) - svr->mainseqno = 4; - return 1; -} - -static u32 common_mainseq_4(struct mevent_srv_common * svr) -{ - // process command - const struct mevent_cmd * cmd = &svr->cmdBuffer[svr->cmdidx]; - const void * ptr; - svr->cmdidx++; - - switch (cmd->instr) - { - case 0: - // end - AGB_ASSERT(cmd->parameter == NULL); - svr->mainseqno = 1; - svr->param = cmd->flag; - break; - case 1: - // wait_send - svr->mainseqno = 3; - break; - case 2: - // receive - AGB_ASSERT(cmd->parameter == NULL); - mevent_srv_sub_init_recv(&svr->manager, cmd->flag, svr->recvBuffer); - svr->mainseqno = 2; - break; - case 3: - // jump - AGB_ASSERT(cmd->flag == FALSE); - svr->cmdidx = 0; - svr->cmdBuffer = cmd->parameter; - break; - case 5: - // get_1442CC - AGB_ASSERT(cmd->flag == FALSE); - AGB_ASSERT(cmd->parameter == NULL); - memcpy(svr->mevent_unk1442cc, svr->recvBuffer, sizeof(struct MEventStruct_Unk1442CC)); - break; - case 6: - // check_header__pass_false - AGB_ASSERT(cmd->flag == FALSE); - AGB_ASSERT(cmd->parameter == NULL); - svr->param = sub_801B6A0(svr->mevent_unk1442cc, FALSE); - break; - case 30: - // check_header__pass_true - AGB_ASSERT(cmd->flag == FALSE); - AGB_ASSERT(cmd->parameter == NULL); - svr->param = sub_801B6A0(svr->mevent_unk1442cc, TRUE); - break; - case 4: - // jump_if_eq - if (svr->param == cmd->flag) - { - svr->cmdidx = 0; - svr->cmdBuffer = cmd->parameter; - } - break; - case 7: - // check_crc - AGB_ASSERT(cmd->flag == FALSE); - ptr = mevent_first_if_not_null_else_second(cmd->parameter, svr->wonder_card); - svr->param = sub_801B6EC(ptr, svr->mevent_unk1442cc, ptr); - break; - case 8: - // read_word - AGB_ASSERT(cmd->flag == FALSE); - AGB_ASSERT(cmd->parameter == NULL); - svr->param = *(u32 *)svr->recvBuffer; - break; - case 9: - AGB_ASSERT(cmd->flag == FALSE); - ptr = mevent_first_if_not_null_else_second(cmd->parameter, &svr->sendWord); - svr->param = sub_801B708(ptr, svr->mevent_unk1442cc, ptr); - break; - case 10: - AGB_ASSERT(cmd->parameter == NULL); - svr->param = MEventStruct_Unk1442CC_GetValueNFrom_unk_20(svr->mevent_unk1442cc, cmd->flag); - break; - case 11: - AGB_ASSERT(cmd->flag == FALSE); - svr->param = MEventStruct_Unk1442CC_CompareField_unk_16(svr->mevent_unk1442cc, cmd->parameter); - break; - case 12: - AGB_ASSERT(cmd->flag == FALSE); - svr->param = mevent_compare_pointers(cmd->parameter, *(void **)svr->recvBuffer); - break; - case 14: - AGB_ASSERT(cmd->flag == FALSE); - mevent_srv_common_init_send(svr, 0x17, mevent_first_if_not_null_else_second(cmd->parameter, svr->wonder_news), sizeof(struct WonderNews)); - break; - case 13: - AGB_ASSERT(cmd->flag == FALSE); - mevent_srv_common_init_send(svr, 0x16, mevent_first_if_not_null_else_second(cmd->parameter, svr->wonder_card), sizeof(struct WonderCard)); - break; - case 16: - AGB_ASSERT(cmd->flag == FALSE); - mevent_srv_common_init_send(svr, 0x18, mevent_first_if_not_null_else_second(cmd->parameter, &svr->sendWord), 4); - break; - case 15: - if (cmd->parameter == NULL) - mevent_srv_common_init_send(svr, 0x19, svr->sendBuffer1, svr->sendBuffer1Size); - else - mevent_srv_common_init_send(svr, 0x19, cmd->parameter, cmd->flag); - break; - case 18: - if (cmd->parameter == NULL) - mevent_srv_common_init_send(svr, 0x10, svr->sendBuffer2, svr->sendBuffer2Size); - else - mevent_srv_common_init_send(svr, 0x10, cmd->parameter, cmd->flag); - break; - case 19: - AGB_ASSERT(cmd->flag == FALSE); - mevent_srv_common_init_send(svr, 0x1a, cmd->parameter, 188); - break; - case 20: - mevent_srv_common_init_send(svr, 0x15, cmd->parameter, cmd->flag); - break; - case 17: - mevent_srv_common_init_send(svr, 0x1c, cmd->parameter, cmd->flag); - break; - case 22: - AGB_ASSERT(cmd->flag == FALSE); - memcpy(svr->wonder_card, cmd->parameter, 332); - break; - case 23: - AGB_ASSERT(cmd->flag == FALSE); - memcpy(svr->wonder_news, cmd->parameter, 444); - break; - case 21: - AGB_ASSERT(cmd->flag == FALSE); - svr->sendWord = *(u32 *)cmd->parameter; - break; - case 24: - svr->sendBuffer1 = cmd->parameter; - svr->sendBuffer1Size = cmd->flag; - break; - case 25: - svr->sendBuffer2 = cmd->parameter; - svr->sendBuffer2Size = cmd->flag; - break; - case 26: - AGB_ASSERT(cmd->flag == FALSE && cmd->parameter == NULL); - memcpy(svr->wonder_card, GetSavedWonderCard(), 332); - WonderCard_ResetInternalReceivedFlag(svr->wonder_card); - break; - case 27: - AGB_ASSERT(cmd->flag == FALSE && cmd->parameter == NULL); - memcpy(svr->wonder_news, GetSavedWonderNews(), 444); - break; - case 28: - AGB_ASSERT(cmd->flag == FALSE && cmd->parameter == NULL); - svr->sendBuffer1 = GetSavedRamScriptIfValid(); - break; - case 29: - mevent_srv_common_init_send(svr, 0x1b, cmd->parameter, cmd->flag); - break; - } - - return 1; -} - -static u32 (*const func_tbl[])(struct mevent_srv_common *) = { - common_mainseq_0, - common_mainseq_1, - common_mainseq_2, - common_mainseq_3, - common_mainseq_4 -}; - -static u32 mevent_srv_exec_common(struct mevent_srv_common * svr) -{ - u32 response; - AGB_ASSERT(svr->mainseqno < ARRAY_COUNT(func_tbl)); - response = func_tbl[svr->mainseqno](svr); - AGB_ASSERT(svr->mainseqno < ARRAY_COUNT(func_tbl)); - return response; -} diff --git a/src/mevent_server_helpers.c b/src/mevent_server_helpers.c deleted file mode 100644 index 616f394f7..000000000 --- a/src/mevent_server_helpers.c +++ /dev/null @@ -1,211 +0,0 @@ -#include "global.h" -#include "malloc.h" -#include "decompress.h" -#include "util.h" -#include "link.h" -#include "link_rfu.h" -#include "overworld.h" -#include "script.h" -#include "battle_tower.h" -#include "mystery_event_script.h" -#include "mevent.h" -#include "mevent_server_helpers.h" - -static u32 mevent_receive_func(struct mevent_srv_sub *); -static u32 mevent_send_func(struct mevent_srv_sub *); - -u32 mevent_srv_sub_recv(struct mevent_srv_sub * svr) -{ - return svr->recvFunc(svr); -} - -u32 mevent_srv_sub_send(struct mevent_srv_sub * svr) -{ - return svr->sendFunc(svr); -} - -void mevent_srv_sub_init(struct mevent_srv_sub * svr, u32 sendPlayerNo, u32 recvPlayerNo) -{ - svr->sendPlayerNo = sendPlayerNo; - svr->recvPlayerNo = recvPlayerNo; - svr->seqno = 0; - svr->sendCRC = 0; - svr->sendSize = 0; - svr->sendCounter = 0; - svr->recvCRC = 0; - svr->recvSize = 0; - svr->recvCounter = 0; - svr->sendBfr = NULL; - svr->recvBfr = NULL; - svr->sendFunc = mevent_send_func; - svr->recvFunc = mevent_receive_func; -} - -void mevent_srv_sub_init_send(struct mevent_srv_sub * svr, u32 ident, const void * src, u32 size) -{ - svr->seqno = 0; - svr->sendIdent = ident; - svr->sendCounter = 0; - svr->sendCRC = 0; - if (size != 0) - svr->sendSize = size; - else - svr->sendSize = ME_SEND_BUF_SIZE; - svr->sendBfr = src; -} - -void mevent_srv_sub_init_recv(struct mevent_srv_sub * svr, u32 ident, void * dest) -{ - svr->seqno = 0; - svr->recvIdent = ident; - svr->recvCounter = 0; - svr->recvCRC = 0; - svr->recvSize = 0; - svr->recvBfr = dest; -} - -static void mevent_recv_block(u32 recv_idx, void * dest, size_t size) -{ - memcpy(dest, gBlockRecvBuffer[recv_idx], size); -} - -static bool32 mevent_has_received(u32 recv_idx) -{ - if ((GetBlockReceivedStatus() >> recv_idx) & 1) - return TRUE; - else - return FALSE; -} - -static void mevent_reset_recv(u32 recv_idx) -{ - ResetBlockReceivedFlag(recv_idx); -} - -static bool32 mevent_receive_func(struct mevent_srv_sub * svr) -{ - struct send_recv_header header; - - switch (svr->seqno) - { - case 0: - if (mevent_has_received(svr->recvPlayerNo)) - { - mevent_recv_block(svr->recvPlayerNo, &header, sizeof(header)); - svr->recvSize = header.size; - svr->recvCRC = header.crc; - if (svr->recvSize > ME_SEND_BUF_SIZE) - { - LinkRfu_FatalError(); - return FALSE; - } - else if (svr->recvIdent != header.ident) - { - LinkRfu_FatalError(); - return FALSE; - } - else - { - svr->recvCounter = 0; - mevent_reset_recv(svr->recvPlayerNo); - ++svr->seqno; - } - } - break; - case 1: - if (mevent_has_received(svr->recvPlayerNo)) - { - size_t blocksiz = svr->recvCounter * 252; - if (svr->recvSize - blocksiz <= 252) - { - mevent_recv_block(svr->recvPlayerNo, svr->recvBfr + blocksiz, svr->recvSize - blocksiz); - ++svr->recvCounter; - ++svr->seqno; - } - else - { - mevent_recv_block(svr->recvPlayerNo, svr->recvBfr + blocksiz, 252); - ++svr->recvCounter; - } - mevent_reset_recv(svr->recvPlayerNo); - } - break; - case 2: - if (CalcCRC16WithTable(svr->recvBfr, svr->recvSize) != svr->recvCRC) - { - LinkRfu_FatalError(); - return FALSE; - } - else - { - svr->seqno = 0; - return TRUE; - } - break; - - } - - return FALSE; -} - -static bool32 mevent_send_func(struct mevent_srv_sub * svr) -{ - struct send_recv_header header; - - switch (svr->seqno) - { - case 0: - if (IsLinkTaskFinished()) - { - header.ident = svr->sendIdent; - header.size = svr->sendSize; - header.crc = CalcCRC16WithTable(svr->sendBfr, svr->sendSize); - svr->sendCRC = header.crc; - svr->sendCounter = 0; - SendBlock(0, &header, sizeof(header)); - ++svr->seqno; - } - break; - case 1: - if (IsLinkTaskFinished()) - { - if (mevent_has_received(svr->sendPlayerNo)) - { - size_t blocksiz; - mevent_reset_recv(svr->sendPlayerNo); - blocksiz = 252 * svr->sendCounter; - if (svr->sendSize - blocksiz <= 252) - { - SendBlock(0, svr->sendBfr + blocksiz, svr->sendSize - blocksiz); - ++svr->sendCounter; - ++svr->seqno; - } - else - { - SendBlock(0, svr->sendBfr + blocksiz, 252); - ++svr->sendCounter; - } - } - } - break; - case 2: - if (IsLinkTaskFinished()) - { - if (CalcCRC16WithTable(svr->sendBfr, svr->sendSize) != svr->sendCRC) - LinkRfu_FatalError(); - else - ++svr->seqno; - } - break; - case 3: - if (mevent_has_received(svr->sendPlayerNo)) - { - mevent_reset_recv(svr->sendPlayerNo); - svr->seqno = 0; - return TRUE; - } - break; - } - - return FALSE; -} diff --git a/src/mystery_event_msg.c b/src/mystery_event_msg.c index e0e70a218..51141bb77 100644 --- a/src/mystery_event_msg.c +++ b/src/mystery_event_msg.c @@ -1,13 +1,13 @@ #include "global.h" -const u8 gText_MysteryGiftBerry[] = _("Obtained a {STR_VAR_2} BERRY!\nDad has it at PETALBURG GYM."); -const u8 gText_MysteryGiftBerryTransform[] = _("The {STR_VAR_1} BERRY transformed into\none {STR_VAR_2} BERRY."); -const u8 gText_MysteryGiftBerryObtained[] = _("The {STR_VAR_1} BERRY has already been\nobtained."); -const u8 gText_MysteryGiftSpecialRibbon[] = _("A special RIBBON was awarded to\nyour party POKéMON."); -const u8 gText_MysteryGiftNationalDex[] = _("The POKéDEX has been upgraded\nwith the NATIONAL MODE."); -const u8 gText_MysteryGiftRareWord[] = _("A rare word has been added."); -const u8 gText_MysteryGiftSentOver[] = _("{STR_VAR_1} was sent over!"); -const u8 gText_MysteryGiftFullParty[] = _("Your party is full.\n{STR_VAR_1} could not be sent over."); -const u8 gText_MysteryGiftNewTrainer[] = _("A new TRAINER has arrived in\nHOENN."); -const u8 gText_MysteryGiftNewAdversaryInBattleTower[] = _("A new adversary has arrived in the\nBATTLE TOWER."); -const u8 gText_MysteryGiftCantBeUsed[] = _("This data can't be used in\nthis version."); +const u8 gText_MysteryEventBerry[] = _("Obtained a {STR_VAR_2} BERRY!\nDad has it at PETALBURG GYM."); +const u8 gText_MysteryEventBerryTransform[] = _("The {STR_VAR_1} BERRY transformed into\none {STR_VAR_2} BERRY."); +const u8 gText_MysteryEventBerryObtained[] = _("The {STR_VAR_1} BERRY has already been\nobtained."); +const u8 gText_MysteryEventSpecialRibbon[] = _("A special RIBBON was awarded to\nyour party POKéMON."); +const u8 gText_MysteryEventNationalDex[] = _("The POKéDEX has been upgraded\nwith the NATIONAL MODE."); +const u8 gText_MysteryEventRareWord[] = _("A rare word has been added."); +const u8 gText_MysteryEventSentOver[] = _("{STR_VAR_1} was sent over!"); +const u8 gText_MysteryEventFullParty[] = _("Your party is full.\n{STR_VAR_1} could not be sent over."); +const u8 gText_MysteryEventNewTrainer[] = _("A new TRAINER has arrived in\nHOENN."); +const u8 gText_MysteryEventNewAdversaryInBattleTower[] = _("A new adversary has arrived in the\nBATTLE TOWER."); +const u8 gText_MysteryEventCantBeUsed[] = _("This data can't be used in\nthis version."); diff --git a/src/mystery_event_script.c b/src/mystery_event_script.c index 176eab7fc..f80240006 100644 --- a/src/mystery_event_script.c +++ b/src/mystery_event_script.c @@ -43,7 +43,7 @@ static bool32 CheckCompatibility(u16 a1, u32 a2, u16 a3, u32 a4) static void SetIncompatible(void) { - StringExpandPlaceholders(gStringVar4, gText_MysteryGiftCantBeUsed); + StringExpandPlaceholders(gStringVar4, gText_MysteryEventCantBeUsed); SetMysteryEventScriptStatus(3); } @@ -65,15 +65,15 @@ static bool32 RunMysteryEventScriptCommand(struct ScriptContext *ctx) return FALSE; } -void sub_8153870(u8 *script) +void InitMysteryEventScriptContext(u8 *script) { InitMysteryEventScript(&sMysteryEventScriptContext, script); } -bool32 sub_8153884(u32 *a0) +bool32 RunMysteryEventScriptContextCommand(u32 *script) { bool32 ret = RunMysteryEventScriptCommand(&sMysteryEventScriptContext); - *a0 = sMysteryEventScriptContext.data[2]; + *script = sMysteryEventScriptContext.data[2]; return ret; } @@ -229,17 +229,17 @@ bool8 MEScrCmd_setenigmaberry(struct ScriptContext *ctx) if (!haveBerry) { str = gStringVar4; - message = gText_MysteryGiftBerry; + message = gText_MysteryEventBerry; } else if (StringCompare(gStringVar1, gStringVar2)) { str = gStringVar4; - message = gText_MysteryGiftBerryTransform; + message = gText_MysteryEventBerryTransform; } else { str = gStringVar4; - message = gText_MysteryGiftBerryObtained; + message = gText_MysteryEventBerryObtained; } StringExpandPlaceholders(str, message); @@ -259,7 +259,7 @@ bool8 MEScrCmd_giveribbon(struct ScriptContext *ctx) u8 index = ScriptReadByte(ctx); u8 ribbonId = ScriptReadByte(ctx); GiveGiftRibbonToParty(index, ribbonId); - StringExpandPlaceholders(gStringVar4, gText_MysteryGiftSpecialRibbon); + StringExpandPlaceholders(gStringVar4, gText_MysteryEventSpecialRibbon); ctx->data[2] = 2; return FALSE; } @@ -278,7 +278,7 @@ bool8 MEScrCmd_initramscript(struct ScriptContext *ctx) bool8 MEScrCmd_givenationaldex(struct ScriptContext *ctx) { EnableNationalPokedex(); - StringExpandPlaceholders(gStringVar4, gText_MysteryGiftNationalDex); + StringExpandPlaceholders(gStringVar4, gText_MysteryEventNationalDex); ctx->data[2] = 2; return FALSE; } @@ -286,7 +286,7 @@ bool8 MEScrCmd_givenationaldex(struct ScriptContext *ctx) bool8 MEScrCmd_addrareword(struct ScriptContext *ctx) { UnlockAdditionalPhrase(ScriptReadByte(ctx)); - StringExpandPlaceholders(gStringVar4, gText_MysteryGiftRareWord); + StringExpandPlaceholders(gStringVar4, gText_MysteryEventRareWord); ctx->data[2] = 2; return FALSE; } @@ -320,7 +320,7 @@ bool8 MEScrCmd_givepokemon(struct ScriptContext *ctx) if (gPlayerPartyCount == PARTY_SIZE) { - StringExpandPlaceholders(gStringVar4, gText_MysteryGiftFullParty); + StringExpandPlaceholders(gStringVar4, gText_MysteryEventFullParty); ctx->data[2] = 3; } else @@ -340,7 +340,7 @@ bool8 MEScrCmd_givepokemon(struct ScriptContext *ctx) GiveMailToMon2(&gPlayerParty[PARTY_SIZE - 1], &mail); CompactPartySlots(); CalculatePlayerPartyCount(); - StringExpandPlaceholders(gStringVar4, gText_MysteryGiftSentOver); + StringExpandPlaceholders(gStringVar4, gText_MysteryEventSentOver); ctx->data[2] = 2; } @@ -352,7 +352,7 @@ bool8 MEScrCmd_addtrainer(struct ScriptContext *ctx) u32 data = ScriptReadWord(ctx) - ctx->data[1] + ctx->data[0]; memcpy(&gSaveBlock2Ptr->frontier.ereaderTrainer, (void *)data, sizeof(gSaveBlock2Ptr->frontier.ereaderTrainer)); ValidateEReaderTrainer(); - StringExpandPlaceholders(gStringVar4, gText_MysteryGiftNewTrainer); + StringExpandPlaceholders(gStringVar4, gText_MysteryEventNewTrainer); ctx->data[2] = 2; return FALSE; } diff --git a/src/mystery_gift.c b/src/mystery_gift.c index 6ae6a9534..1df6533d9 100644..100755 --- a/src/mystery_gift.c +++ b/src/mystery_gift.c @@ -1,1672 +1,662 @@ #include "global.h" +#include "util.h" #include "main.h" -#include "text.h" -#include "task.h" -#include "malloc.h" -#include "gpu_regs.h" -#include "scanline_effect.h" -#include "text_window.h" -#include "bg.h" -#include "window.h" -#include "strings.h" -#include "text_window.h" -#include "menu.h" -#include "palette.h" -#include "constants/songs.h" -#include "sound.h" -#include "mystery_gift.h" -#include "union_room.h" -#include "title_screen.h" -#include "ereader_screen.h" -#include "international_string_util.h" -#include "list_menu.h" -#include "string_util.h" -#include "mevent.h" -#include "mevent_801BAAC.h" -#include "save.h" -#include "link.h" -#include "mevent_client.h" #include "event_data.h" -#include "link_rfu.h" -#include "mevent_news.h" -#include "mevent_server.h" -#include "constants/cable_club.h" +#include "easy_chat.h" +#include "script.h" +#include "battle_tower.h" +#include "wonder_news.h" +#include "string_util.h" +#include "new_game.h" +#include "mystery_gift.h" +#include "constants/mystery_gift.h" -void bgid_upload_textbox_1(u8 bgId); -void task_add_00_mystery_gift(void); -void task00_mystery_gift(u8 taskId); +static EWRAM_DATA bool32 sStatsEnabled = FALSE; -EWRAM_DATA u8 sDownArrowCounterAndYCoordIdx[8] = {}; -EWRAM_DATA bool8 gGiftIsFromEReader = FALSE; +static void ClearSavedWonderNewsMetadata(void); +static void ClearSavedWonderNews(void); +static void ClearSavedWonderCard(void); +static bool32 ValidateWonderNews(const struct WonderNews *); +static bool32 ValidateWonderCard(const struct WonderCard *); +static void ClearSavedWonderCardMetadata(void); +static void ClearSavedTrainerIds(void); +static void IncrementCardStatForNewTrainer(u32, u32, u32 *, int); -static const u16 gUnkTextboxBorderPal[] = INCBIN_U16("graphics/interface/unk_textbox_border.gbapal"); -static const u32 gUnkTextboxBorderGfx[] = INCBIN_U32("graphics/interface/unk_textbox_border.4bpp.lz"); +#define CALC_CRC(data) CalcCRC16WithTable((void *)&(data), sizeof(data)) -struct MysteryGiftTaskData +void ClearMysteryGift(void) { - u16 curPromptWindowId; - u16 unk2; - u16 unk4; - u16 unk6; - u8 state; - u8 textState; - u8 unkA; - u8 unkB; - u8 IsCardOrNews; - u8 source; - u8 prevPromptWindowId; - u8 * buffer; -}; - -static const struct BgTemplate sBGTemplates[] = { - { - .bg = 0, - .charBaseIndex = 2, - .mapBaseIndex = 15, - .screenSize = 0, - .paletteMode = 0, - .priority = 0, - .baseTile = 0x000 - }, { - .bg = 1, - .charBaseIndex = 0, - .mapBaseIndex = 14, - .screenSize = 0, - .paletteMode = 0, - .priority = 1, - .baseTile = 0x000 - }, { - .bg = 2, - .charBaseIndex = 0, - .mapBaseIndex = 13, - .screenSize = 0, - .paletteMode = 0, - .priority = 2, - .baseTile = 0x000 - }, { - .bg = 3, - .charBaseIndex = 0, - .mapBaseIndex = 12, - .screenSize = 0, - .paletteMode = 0, - .priority = 3, - .baseTile = 0x000 - } -}; - -static const struct WindowTemplate sMainWindows[] = { - { - .bg = 0x00, - .tilemapLeft = 0x00, - .tilemapTop = 0x00, - .width = 0x1e, - .height = 0x02, - .paletteNum = 0x0c, - .baseBlock = 0x0013 - }, { - .bg = 0x00, - .tilemapLeft = 0x01, - .tilemapTop = 0x0f, - .width = 0x1c, - .height = 0x04, - .paletteNum = 0x0c, - .baseBlock = 0x004f - }, { - .bg = 0x00, - .tilemapLeft = 0x00, - .tilemapTop = 0x0f, - .width = 0x1e, - .height = 0x05, - .paletteNum = 0x0d, - .baseBlock = 0x004f - }, { - 0xFF - } -}; - -static const struct WindowTemplate sWindowTemplate_PromptYesOrNo_Width28 = { - .bg = 0x00, - .tilemapLeft = 0x01, - .tilemapTop = 0x0f, - .width = 0x1c, - .height = 0x04, - .paletteNum = 0x0c, - .baseBlock = 0x00e5 -}; - -static const struct WindowTemplate sWindowTemplate_PromptYesOrNo_Width20 = { - .bg = 0x00, - .tilemapLeft = 0x01, - .tilemapTop = 0x0f, - .width = 0x14, - .height = 0x04, - .paletteNum = 0x0c, - .baseBlock = 0x00e5 -}; - -static const struct WindowTemplate sMysteryGiftMenuWindowTemplate = { - .bg = 0x00, - .tilemapLeft = 0x01, - .tilemapTop = 0x0f, - .width = 0x13, - .height = 0x04, - .paletteNum = 0x0c, - .baseBlock = 0x00e5 -}; - -static const struct WindowTemplate sWindowTemplate_ThreeOptions = { - .bg = 0x00, - .tilemapLeft = 0x08, - .tilemapTop = 0x06, - .width = 0x0e, - .height = 0x06, - .paletteNum = 0x0c, - .baseBlock = 0x0155 -}; - -static const struct WindowTemplate sWindowTemplate_YesNoBox = { - .bg = 0x00, - .tilemapLeft = 0x17, - .tilemapTop = 0x0f, - .width = 0x06, - .height = 0x04, - .paletteNum = 0x0c, - .baseBlock = 0x0155 -}; - -static const struct WindowTemplate sWindowTemplate_7by8 = { - .bg = 0x00, - .tilemapLeft = 0x16, - .tilemapTop = 0x0b, - .width = 0x07, - .height = 0x08, - .paletteNum = 0x0c, - .baseBlock = 0x0155 -}; - -static const struct WindowTemplate sWindowTemplate_7by6 = { - .bg = 0x00, - .tilemapLeft = 0x16, - .tilemapTop = 0x0d, - .width = 0x07, - .height = 0x06, - .paletteNum = 0x0c, - .baseBlock = 0x0155 -}; + CpuFill32(0, &gSaveBlock1Ptr->mysteryGift, sizeof(gSaveBlock1Ptr->mysteryGift)); + ClearSavedWonderNewsMetadata(); // Clear is redundant, InitSavedWonderNews would be sufficient + InitQuestionnaireWords(); +} -static const struct WindowTemplate sWindowTemplate_7by4 = { - .bg = 0x00, - .tilemapLeft = 0x16, - .tilemapTop = 0x0f, - .width = 0x07, - .height = 0x04, - .paletteNum = 0x0c, - .baseBlock = 0x0155 -}; +struct WonderNews *GetSavedWonderNews(void) +{ + return &gSaveBlock1Ptr->mysteryGift.news; +} -static const struct ListMenuItem sListMenuItems_CardsOrNews[] = { - { gText_WonderCards, 0 }, - { gText_WonderNews, 1 }, - { gText_Exit3, -2 } -}; +struct WonderCard *GetSavedWonderCard(void) +{ + return &gSaveBlock1Ptr->mysteryGift.card; +} -static const struct ListMenuItem sListMenuItems_WirelessOrFriend[] = { - { gText_WirelessCommunication, 0 }, - { gText_Friend2, 1 }, - { gText_Cancel2, -2 } -}; +struct WonderCardMetadata *GetSavedWonderCardMetadata(void) +{ + return &gSaveBlock1Ptr->mysteryGift.cardMetadata; +} -static const struct ListMenuTemplate sListMenuTemplate_ThreeOptions = { - .items = NULL, - .moveCursorFunc = ListMenuDefaultCursorMoveFunc, - .itemPrintFunc = NULL, - .totalItems = 3, - .maxShowed = 3, - .windowId = 0, - .header_X = 0, - .item_X = 8, - .cursor_X = 0, - .upText_Y = 1, - .cursorPal = 2, - .fillValue = 1, - .cursorShadowPal = 3, - .lettersSpacing = 0, - .itemVerticalPadding = 0, - .scrollMultiple = 0, - .fontId = 1, - .cursorKind = 0 -}; +struct WonderNewsMetadata *GetSavedWonderNewsMetadata(void) +{ + return &gSaveBlock1Ptr->mysteryGift.newsMetadata; +} -static const struct ListMenuItem sListMenuItems_ReceiveSendToss[] = { - { gText_Receive, 0 }, - { gText_Send, 1 }, - { gText_Toss, 2 }, - { gText_Cancel2, -2 } -}; +u16 *GetQuestionnaireWordsPtr(void) +{ + return gSaveBlock1Ptr->mysteryGift.questionnaireWords; +} -static const struct ListMenuItem sListMenuItems_ReceiveToss[] = { - { gText_Receive, 0 }, - { gText_Toss, 2 }, - { gText_Cancel2, -2 } -}; +// Equivalent to ClearSavedWonderCardAndRelated, but nothing else to clear +void ClearSavedWonderNewsAndRelated(void) +{ + ClearSavedWonderNews(); +} -static const struct ListMenuItem sListMenuItems_ReceiveSend[] = { - { gText_Receive, 0 }, - { gText_Send, 1 }, - { gText_Cancel2, -2 } -}; +bool32 SaveWonderNews(const struct WonderNews *news) +{ + if (!ValidateWonderNews(news)) + return FALSE; -static const struct ListMenuItem sListMenuItems_Receive[] = { - { gText_Receive, 0 }, - { gText_Cancel2, -2 } -}; + ClearSavedWonderNews(); + gSaveBlock1Ptr->mysteryGift.news = *news; + gSaveBlock1Ptr->mysteryGift.newsCrc = CALC_CRC(gSaveBlock1Ptr->mysteryGift.news); + return TRUE; +} -static const struct ListMenuTemplate sListMenu_ReceiveSendToss = { - .items = sListMenuItems_ReceiveSendToss, - .moveCursorFunc = ListMenuDefaultCursorMoveFunc, - .itemPrintFunc = NULL, - .totalItems = 4, - .maxShowed = 4, - .windowId = 0, - .header_X = 0, - .item_X = 8, - .cursor_X = 0, - .upText_Y = 1, - .cursorPal = 2, - .fillValue = 1, - .cursorShadowPal = 3, - .lettersSpacing = 0, - .itemVerticalPadding = 0, - .scrollMultiple = 0, - .fontId = 1, - .cursorKind = 0 -}; +bool32 ValidateSavedWonderNews(void) +{ + if (CALC_CRC(gSaveBlock1Ptr->mysteryGift.news) != gSaveBlock1Ptr->mysteryGift.newsCrc) + return FALSE; + if (!ValidateWonderNews(&gSaveBlock1Ptr->mysteryGift.news)) + return FALSE; -static const struct ListMenuTemplate sListMenu_ReceiveToss = { - .items = sListMenuItems_ReceiveToss, - .moveCursorFunc = ListMenuDefaultCursorMoveFunc, - .itemPrintFunc = NULL, - .totalItems = 3, - .maxShowed = 3, - .windowId = 0, - .header_X = 0, - .item_X = 8, - .cursor_X = 0, - .upText_Y = 1, - .cursorPal = 2, - .fillValue = 1, - .cursorShadowPal = 3, - .lettersSpacing = 0, - .itemVerticalPadding = 0, - .scrollMultiple = 0, - .fontId = 1, - .cursorKind = 0 -}; + return TRUE; +} -static const struct ListMenuTemplate sListMenu_ReceiveSend = { - .items = sListMenuItems_ReceiveSend, - .moveCursorFunc = ListMenuDefaultCursorMoveFunc, - .itemPrintFunc = NULL, - .totalItems = 3, - .maxShowed = 3, - .windowId = 0, - .header_X = 0, - .item_X = 8, - .cursor_X = 0, - .upText_Y = 1, - .cursorPal = 2, - .fillValue = 1, - .cursorShadowPal = 3, - .lettersSpacing = 0, - .itemVerticalPadding = 0, - .scrollMultiple = 0, - .fontId = 1, - .cursorKind = 0 -}; +static bool32 ValidateWonderNews(const struct WonderNews *news) +{ + if (news->id == 0) + return FALSE; -static const struct ListMenuTemplate sListMenu_Receive = { - .items = sListMenuItems_Receive, - .moveCursorFunc = ListMenuDefaultCursorMoveFunc, - .itemPrintFunc = NULL, - .totalItems = 2, - .maxShowed = 2, - .windowId = 0, - .header_X = 0, - .item_X = 8, - .cursor_X = 0, - .upText_Y = 1, - .cursorPal = 2, - .fillValue = 1, - .cursorShadowPal = 3, - .lettersSpacing = 0, - .itemVerticalPadding = 0, - .scrollMultiple = 0, - .fontId = 1, - .cursorKind = 0 -}; + return TRUE; +} -static const u8 *const Unref_082F0710[] = { - gText_VarietyOfEventsImportedWireless, - gText_WonderCardsInPossession, - gText_ReadNewsThatArrived, - gText_ReturnToTitle -}; +bool32 IsSendingSavedWonderNewsAllowed(void) +{ + const struct WonderNews *news = &gSaveBlock1Ptr->mysteryGift.news; + if (news->sendType == SEND_TYPE_DISALLOWED) + return FALSE; -ALIGNED(2) const u8 sMG_Ereader_TextColor_1[] = { 0, 1, 2 }; -ALIGNED(2) const u8 sMG_Ereader_TextColor_1_Copy[] = { 0, 1, 2 }; -ALIGNED(2) const u8 sMG_Ereader_TextColor_2[] = { 1, 2, 3 }; + return TRUE; +} -void vblankcb_mystery_gift_e_reader_run(void) +static void ClearSavedWonderNews(void) { - ProcessSpriteCopyRequests(); - LoadOam(); - TransferPlttBuffer(); + CpuFill32(0, GetSavedWonderNews(), sizeof(gSaveBlock1Ptr->mysteryGift.news)); + gSaveBlock1Ptr->mysteryGift.newsCrc = 0; } -void c2_mystery_gift_e_reader_run(void) +static void ClearSavedWonderNewsMetadata(void) { - RunTasks(); - RunTextPrinters(); - AnimateSprites(); - BuildOamBuffer(); + CpuFill32(0, GetSavedWonderNewsMetadata(), sizeof(gSaveBlock1Ptr->mysteryGift.newsMetadata)); + InitSavedWonderNews(); } -bool32 HandleMysteryGiftOrEReaderSetup(s32 mg_or_ereader) +bool32 IsWonderNewsSameAsSaved(const u8 *news) { - switch (gMain.state) + const u8 *savedNews = (const u8 *)&gSaveBlock1Ptr->mysteryGift.news; + u32 i; + if (!ValidateSavedWonderNews()) + return FALSE; + + for (i = 0; i < sizeof(gSaveBlock1Ptr->mysteryGift.news); i++) { - case 0: - SetVBlankCallback(NULL); - ResetPaletteFade(); - ResetSpriteData(); - FreeAllSpritePalettes(); - ResetTasks(); - ScanlineEffect_Stop(); - ResetBgsAndClearDma3BusyFlags(0); - - InitBgsFromTemplates(0, sBGTemplates, ARRAY_COUNT(sBGTemplates)); - ChangeBgX(0, 0, 0); - ChangeBgY(0, 0, 0); - ChangeBgX(1, 0, 0); - ChangeBgY(1, 0, 0); - ChangeBgX(2, 0, 0); - ChangeBgY(2, 0, 0); - ChangeBgX(3, 0, 0); - ChangeBgY(3, 0, 0); - - SetBgTilemapBuffer(3, Alloc(BG_SCREEN_SIZE)); - SetBgTilemapBuffer(2, Alloc(BG_SCREEN_SIZE)); - SetBgTilemapBuffer(1, Alloc(BG_SCREEN_SIZE)); - SetBgTilemapBuffer(0, Alloc(BG_SCREEN_SIZE)); - - bgid_upload_textbox_1(3); - InitWindows(sMainWindows); - DeactivateAllTextPrinters(); - ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON | DISPCNT_WIN1_ON); - SetGpuReg(REG_OFFSET_BLDCNT, 0); - SetGpuReg(REG_OFFSET_BLDALPHA, 0); - SetGpuReg(REG_OFFSET_BLDY, 0); - gMain.state++; - break; - case 1: - LoadPalette(gUnkTextboxBorderPal, 0, 0x20); - LoadPalette(GetTextWindowPalette(2), 0xd0, 0x20); - Menu_LoadStdPalAt(0xC0); - LoadUserWindowBorderGfx(0, 0xA, 0xE0); - LoadUserWindowBorderGfx_(0, 0x1, 0xF0); - FillBgTilemapBufferRect(0, 0x000, 0, 0, 32, 32, 0x11); - FillBgTilemapBufferRect(1, 0x000, 0, 0, 32, 32, 0x11); - FillBgTilemapBufferRect(2, 0x000, 0, 0, 32, 32, 0x11); - MG_DrawCheckerboardPattern(3); - PrintMysteryGiftOrEReaderTopMenu(mg_or_ereader, 0); - gMain.state++; - break; - case 2: - CopyBgTilemapBufferToVram(3); - CopyBgTilemapBufferToVram(2); - CopyBgTilemapBufferToVram(1); - CopyBgTilemapBufferToVram(0); - gMain.state++; - break; - case 3: - ShowBg(0); - ShowBg(3); - PlayBGM(MUS_RG_MYSTERY_GIFT); - SetVBlankCallback(vblankcb_mystery_gift_e_reader_run); - EnableInterrupts(INTR_FLAG_VBLANK | INTR_FLAG_VCOUNT | INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL); - return TRUE; + if (savedNews[i] != news[i]) + return FALSE; } - return FALSE; + return TRUE; } -void c2_mystery_gift(void) +void ClearSavedWonderCardAndRelated(void) { - if (HandleMysteryGiftOrEReaderSetup(0)) - { - SetMainCallback2(c2_mystery_gift_e_reader_run); - gGiftIsFromEReader = FALSE; - task_add_00_mystery_gift(); - } - RunTasks(); + ClearSavedWonderCard(); + ClearSavedWonderCardMetadata(); + ClearSavedTrainerIds(); + ClearRamScript(); + ClearMysteryGiftFlags(); + ClearMysteryGiftVars(); + ClearEReaderTrainer(&gSaveBlock2Ptr->frontier.ereaderTrainer); } -void c2_ereader(void) +bool32 SaveWonderCard(const struct WonderCard *card) { - if (HandleMysteryGiftOrEReaderSetup(1)) - { - SetMainCallback2(c2_mystery_gift_e_reader_run); - gGiftIsFromEReader = TRUE; - task_add_00_ereader(); - } -} + struct WonderCardMetadata *metadata; + if (!ValidateWonderCard(card)) + return FALSE; -void MainCB_FreeAllBuffersAndReturnToInitTitleScreen(void) -{ - gGiftIsFromEReader = FALSE; - FreeAllWindowBuffers(); - Free(GetBgTilemapBuffer(0)); - Free(GetBgTilemapBuffer(1)); - Free(GetBgTilemapBuffer(2)); - Free(GetBgTilemapBuffer(3)); - SetMainCallback2(CB2_InitTitleScreen); + ClearSavedWonderCardAndRelated(); + memcpy(&gSaveBlock1Ptr->mysteryGift.card, card, sizeof(struct WonderCard)); + gSaveBlock1Ptr->mysteryGift.cardCrc = CALC_CRC(gSaveBlock1Ptr->mysteryGift.card); + metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata; + metadata->iconSpecies = (&gSaveBlock1Ptr->mysteryGift.card)->iconSpecies; + return TRUE; } -void PrintMysteryGiftOrEReaderTopMenu(bool8 mg_or_ereader, bool32 usePickOkCancel) +bool32 ValidateSavedWonderCard(void) { - const u8 * header; - const u8 * options; - FillWindowPixelBuffer(0, 0); - if (mg_or_ereader == 0) - { - header = gText_MysteryGift; - options = !usePickOkCancel ? gText_PickOKExit : gText_PickOKCancel; - } - else - { - header = gJPText_MysteryGift; - options = gJPText_DecideStop; - } + if (gSaveBlock1Ptr->mysteryGift.cardCrc != CALC_CRC(gSaveBlock1Ptr->mysteryGift.card)) + return FALSE; + if (!ValidateWonderCard(&gSaveBlock1Ptr->mysteryGift.card)) + return FALSE; + if (!ValidateSavedRamScript()) + return FALSE; - AddTextPrinterParameterized4(0, 1, 4, 1, 0, 0, sMG_Ereader_TextColor_1, -1, header); - AddTextPrinterParameterized4(0, 0, GetStringRightAlignXOffset(0, options, 0xDE), 1, 0, 0, sMG_Ereader_TextColor_1, -1, options); - CopyWindowToVram(0, 2); - PutWindowTilemap(0); + return TRUE; } -void MG_DrawTextBorder(u8 windowId) +static bool32 ValidateWonderCard(const struct WonderCard *card) { - DrawTextBorderOuter(windowId, 0x01, 0xF); + if (card->flagId == 0) + return FALSE; + if (card->type >= CARD_TYPE_COUNT) + return FALSE; + if (!(card->sendType == SEND_TYPE_DISALLOWED + || card->sendType == SEND_TYPE_ALLOWED + || card->sendType == SEND_TYPE_ALLOWED_ALWAYS)) + return FALSE; + if (card->bgType >= NUM_WONDER_BGS) + return FALSE; + if (card->maxStamps > MAX_STAMP_CARD_STAMPS) + return FALSE; + + return TRUE; } -void MG_DrawCheckerboardPattern(u32 bg) +bool32 IsSendingSavedWonderCardAllowed(void) { - s32 i = 0, j; + const struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->sendType == SEND_TYPE_DISALLOWED) + return FALSE; - FillBgTilemapBufferRect(bg, 0x003, 0, 0, 32, 2, 0x11); + return TRUE; +} - for (i = 0; i < 18; i++) - { - for (j = 0; j < 32; j++) - { - if ((i & 1) != (j & 1)) - FillBgTilemapBufferRect(bg, 1, j, i + 2, 1, 1, 0x11); - else - FillBgTilemapBufferRect(bg, 2, j, i + 2, 1, 1, 0x11); - } - } +static void ClearSavedWonderCard(void) +{ + CpuFill32(0, &gSaveBlock1Ptr->mysteryGift.card, sizeof(gSaveBlock1Ptr->mysteryGift.card)); + gSaveBlock1Ptr->mysteryGift.cardCrc = 0; } -void ClearScreenInBg0(bool32 ignoreTopTwoRows) +static void ClearSavedWonderCardMetadata(void) { - switch (ignoreTopTwoRows) - { - case 0: - FillBgTilemapBufferRect(0, 0, 0, 0, 32, 32, 0x11); - break; - case 1: - FillBgTilemapBufferRect(0, 0, 0, 2, 32, 30, 0x11); - break; - } - CopyBgTilemapBufferToVram(0); + CpuFill32(0, GetSavedWonderCardMetadata(), sizeof(gSaveBlock1Ptr->mysteryGift.cardMetadata)); + gSaveBlock1Ptr->mysteryGift.cardMetadataCrc = 0; } -void AddTextPrinterToWindow1(const u8 *str) +u16 GetWonderCardFlagID(void) { - StringExpandPlaceholders(gStringVar4, str); - FillWindowPixelBuffer(1, 0x11); - AddTextPrinterParameterized4(1, 1, 0, 1, 0, 0, sMG_Ereader_TextColor_2, 0, gStringVar4); - DrawTextBorderOuter(1, 0x001, 0xF); - PutWindowTilemap(1); - CopyWindowToVram(1, 3); + if (ValidateSavedWonderCard()) + return gSaveBlock1Ptr->mysteryGift.card.flagId; + + return 0; } -static void ClearTextWindow(void) +void DisableWonderCardSending(struct WonderCard *card) { - rbox_fill_rectangle(1); - ClearWindowTilemap(1); - CopyWindowToVram(1, 1); + if (card->sendType == SEND_TYPE_ALLOWED) + card->sendType = SEND_TYPE_DISALLOWED; } -bool32 MG_PrintTextOnWindow1AndWaitButton(u8 *textState, const u8 *str) +static bool32 IsWonderCardFlagIDInValidRange(u16 flagId) { - switch (*textState) - { - case 0: - AddTextPrinterToWindow1(str); - (*textState)++; - break; - case 1: - DrawDownArrow(1, 0xD0, 0x14, 1, FALSE, &sDownArrowCounterAndYCoordIdx[0], &sDownArrowCounterAndYCoordIdx[1]); - if (({JOY_NEW(A_BUTTON | B_BUTTON);})) - (*textState)++; - break; - case 2: - DrawDownArrow(1, 0xD0, 0x14, 1, TRUE, &sDownArrowCounterAndYCoordIdx[0], &sDownArrowCounterAndYCoordIdx[1]); - *textState = 0; - ClearTextWindow(); + if (flagId >= WONDER_CARD_FLAG_OFFSET && flagId < WONDER_CARD_FLAG_OFFSET + NUM_WONDER_CARD_FLAGS) return TRUE; - case 0xFF: - *textState = 2; - return FALSE; - } + return FALSE; } -static void HideDownArrow(void) +static const u16 sReceivedGiftFlags[] = +{ + FLAG_RECEIVED_AURORA_TICKET, + FLAG_RECEIVED_MYSTIC_TICKET, + FLAG_RECEIVED_OLD_SEA_MAP, + FLAG_WONDER_CARD_UNUSED_1, + FLAG_WONDER_CARD_UNUSED_2, + FLAG_WONDER_CARD_UNUSED_3, + FLAG_WONDER_CARD_UNUSED_4, + FLAG_WONDER_CARD_UNUSED_5, + FLAG_WONDER_CARD_UNUSED_6, + FLAG_WONDER_CARD_UNUSED_7, + FLAG_WONDER_CARD_UNUSED_8, + FLAG_WONDER_CARD_UNUSED_9, + FLAG_WONDER_CARD_UNUSED_10, + FLAG_WONDER_CARD_UNUSED_11, + FLAG_WONDER_CARD_UNUSED_12, + FLAG_WONDER_CARD_UNUSED_13, + FLAG_WONDER_CARD_UNUSED_14, + FLAG_WONDER_CARD_UNUSED_15, + FLAG_WONDER_CARD_UNUSED_16, + FLAG_WONDER_CARD_UNUSED_17, +}; + +bool32 IsSavedWonderCardGiftNotReceived(void) { - DrawDownArrow(1, 0xD0, 0x14, 1, FALSE, &sDownArrowCounterAndYCoordIdx[0], &sDownArrowCounterAndYCoordIdx[1]); + u16 value = GetWonderCardFlagID(); + if (!IsWonderCardFlagIDInValidRange(value)) + return FALSE; + + // If flag is set, player has received gift from this card + if (FlagGet(sReceivedGiftFlags[value - WONDER_CARD_FLAG_OFFSET]) == TRUE) + return FALSE; + + return TRUE; } -static void ShowDownArrow(void) +static int GetNumStampsInMetadata(const struct WonderCardMetadata *data, int size) { - DrawDownArrow(1, 0xD0, 0x14, 1, TRUE, &sDownArrowCounterAndYCoordIdx[0], &sDownArrowCounterAndYCoordIdx[1]); + int numStamps = 0; + int i; + for (i = 0; i < size; i++) + { + if (data->stampData[STAMP_ID][i] && data->stampData[STAMP_SPECIES][i] != SPECIES_NONE) + numStamps++; + } + + return numStamps; } -bool32 unref_HideDownArrowAndWaitButton(u8 * textState) +static bool32 IsStampInMetadata(const struct WonderCardMetadata *metadata, const u16 *stamp, int maxStamps) { - switch (*textState) + int i; + for (i = 0; i < maxStamps; i++) { - case 0: - HideDownArrow(); - if (JOY_NEW(A_BUTTON | B_BUTTON)) - (*textState)++; - break; - case 1: - ShowDownArrow(); - *textState = 0; - return TRUE; + if (metadata->stampData[STAMP_ID][i] == stamp[STAMP_ID]) + return TRUE; + if (metadata->stampData[STAMP_SPECIES][i] == stamp[STAMP_SPECIES]) + return TRUE; } + return FALSE; } -static bool32 PrintStringAndWait2Seconds(u8 * counter, const u8 * str) +static bool32 ValidateStamp(const u16 *stamp) { - if (*counter == 0) - AddTextPrinterToWindow1(str); - - if (++(*counter) > 120) - { - *counter = 0; - ClearTextWindow(); - return TRUE; - } - else - { + if (stamp[STAMP_ID] == 0) return FALSE; - } + if (stamp[STAMP_SPECIES] == SPECIES_NONE) + return FALSE; + if (stamp[STAMP_SPECIES] >= NUM_SPECIES) + return FALSE; + return TRUE; } -static u32 MysteryGift_HandleThreeOptionMenu(u8 * unused0, u16 * unused1, u8 whichMenu) +static int GetNumStampsInSavedCard(void) { - struct ListMenuTemplate listMenuTemplate = sListMenuTemplate_ThreeOptions; - struct WindowTemplate windowTemplate = sWindowTemplate_ThreeOptions; - s32 width; - s32 response; + struct WonderCard *card; + if (!ValidateSavedWonderCard()) + return 0; - if (whichMenu == 0) - listMenuTemplate.items = sListMenuItems_CardsOrNews; - else - listMenuTemplate.items = sListMenuItems_WirelessOrFriend; - - width = Intl_GetListMenuWidth(&listMenuTemplate); - if (width & 1) - width++; - - windowTemplate.width = width; - if (width < 30) - windowTemplate.tilemapLeft = (30 - width) / 2; - else - windowTemplate.tilemapLeft = 0; + card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type != CARD_TYPE_STAMP) + return 0; - response = DoMysteryGiftListMenu(&windowTemplate, &listMenuTemplate, 1, 0x00A, 0xE0); - if (response != -1) - { - ClearWindowTilemap(2); - CopyWindowToVram(2, 1); - } - return response; + return GetNumStampsInMetadata(&gSaveBlock1Ptr->mysteryGift.cardMetadata, card->maxStamps); } -s8 mevent_message_print_and_prompt_yes_no(u8 * textState, u16 * windowId, bool8 yesNoBoxPlacement, const u8 * str) +bool32 MysteryGift_TrySaveStamp(const u16 *stamp) { - struct WindowTemplate windowTemplate; - s8 input; + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + int maxStamps = card->maxStamps; + int i; + if (!ValidateStamp(stamp)) + return FALSE; + + if (IsStampInMetadata(&gSaveBlock1Ptr->mysteryGift.cardMetadata, stamp, maxStamps)) + return FALSE; - switch (*textState) + for (i = 0; i < maxStamps; i++) { - case 0: - StringExpandPlaceholders(gStringVar4, str); - if (yesNoBoxPlacement == 0) - *windowId = AddWindow(&sWindowTemplate_PromptYesOrNo_Width28); - else - *windowId = AddWindow(&sWindowTemplate_PromptYesOrNo_Width20); - FillWindowPixelBuffer(*windowId, 0x11); - AddTextPrinterParameterized4(*windowId, 1, 0, 1, 0, 0, sMG_Ereader_TextColor_2, 0, gStringVar4); - DrawTextBorderOuter(*windowId, 0x001, 0x0F); - CopyWindowToVram(*windowId, 2); - PutWindowTilemap(*windowId); - (*textState)++; - break; - case 1: - windowTemplate = sWindowTemplate_YesNoBox; - if (yesNoBoxPlacement == 0) - windowTemplate.tilemapTop = 9; - else - windowTemplate.tilemapTop = 15; - CreateYesNoMenu(&windowTemplate, 10, 14, 0); - (*textState)++; - break; - case 2: - input = Menu_ProcessInputNoWrapClearOnChoose(); - if (input == MENU_B_PRESSED || input == 0 || input == 1) + if (gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_ID][i] == 0 + && gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_SPECIES][i] == SPECIES_NONE) { - *textState = 0; - rbox_fill_rectangle(*windowId); - ClearWindowTilemap(*windowId); - CopyWindowToVram(*windowId, 1); - RemoveWindow(*windowId); - return input; + gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_ID][i] = stamp[STAMP_ID]; + gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_SPECIES][i] = stamp[STAMP_SPECIES]; + return TRUE; } - break; - case (u8)MENU_B_PRESSED: - *textState = 0; - rbox_fill_rectangle(*windowId); - ClearWindowTilemap(*windowId); - CopyWindowToVram(*windowId, 1); - RemoveWindow(*windowId); - return MENU_B_PRESSED; } - return MENU_NOTHING_CHOSEN; + return FALSE; } -static s32 HandleMysteryGiftListMenu(u8 * textState, u16 * windowId, bool32 cannotToss, bool32 cannotSend) +#define GAME_DATA_VALID_VAR 0x101 +#define GAME_DATA_VALID_GIFT_TYPE_1 (1 << 2) +#define GAME_DATA_VALID_GIFT_TYPE_2 (1 << 9) + +void MysteryGift_LoadLinkGameData(struct MysteryGiftLinkGameData *data, bool32 isWonderNews) { - struct WindowTemplate windowTemplate; - s32 input; + int i; + CpuFill32(0, data, sizeof(*data)); + data->validationVar = GAME_DATA_VALID_VAR; + data->validationFlag1 = 1; + data->validationFlag2 = 1; - switch (*textState) + if (isWonderNews) { - case 0: - if (cannotToss == 0) - { - StringExpandPlaceholders(gStringVar4, gText_WhatToDoWithCards); - } - else - { - StringExpandPlaceholders(gStringVar4, gText_WhatToDoWithNews); - } - *windowId = AddWindow(&sMysteryGiftMenuWindowTemplate); - FillWindowPixelBuffer(*windowId, 0x11); - AddTextPrinterParameterized4(*windowId, 1, 0, 1, 0, 0, sMG_Ereader_TextColor_2, 0, gStringVar4); - DrawTextBorderOuter(*windowId, 0x001, 0x0F); - CopyWindowToVram(*windowId, 2); - PutWindowTilemap(*windowId); - (*textState)++; - break; - case 1: - windowTemplate = sWindowTemplate_YesNoBox; - if (cannotSend) - { - if (cannotToss == 0) - { - input = DoMysteryGiftListMenu(&sWindowTemplate_7by6, &sListMenu_ReceiveToss, 1, 0x00A, 0xE0); - } - else - { - input = DoMysteryGiftListMenu(&sWindowTemplate_7by4, &sListMenu_Receive, 1, 0x00A, 0xE0); - } - } - else - { - if (cannotToss == 0) - { - input = DoMysteryGiftListMenu(&sWindowTemplate_7by8, &sListMenu_ReceiveSendToss, 1, 0x00A, 0xE0); - } - else - { - input = DoMysteryGiftListMenu(&sWindowTemplate_7by6, &sListMenu_ReceiveSend, 1, 0x00A, 0xE0); - } - } - if (input != -1) - { - *textState = 0; - rbox_fill_rectangle(*windowId); - ClearWindowTilemap(*windowId); - CopyWindowToVram(*windowId, 1); - RemoveWindow(*windowId); - return input; - } - break; - case 0xFF: - *textState = 0; - rbox_fill_rectangle(*windowId); - ClearWindowTilemap(*windowId); - CopyWindowToVram(*windowId, 1); - RemoveWindow(*windowId); - return -2; + // Despite setting these for News, they are + // only ever checked for Cards + data->validationGiftType1 = GAME_DATA_VALID_GIFT_TYPE_1 | 1; + data->validationGiftType2 = GAME_DATA_VALID_GIFT_TYPE_2 | 1; + } + else // Wonder Card + { + data->validationGiftType1 = GAME_DATA_VALID_GIFT_TYPE_1; + data->validationGiftType2 = GAME_DATA_VALID_GIFT_TYPE_2; } - return -1; -} - -static bool32 ValidateCardOrNews(bool32 cardOrNews) -{ - if (cardOrNews == 0) + if (ValidateSavedWonderCard()) { - return ValidateReceivedWonderCard(); + data->flagId = GetSavedWonderCard()->flagId; + data->cardMetadata = *GetSavedWonderCardMetadata(); + data->maxStamps = GetSavedWonderCard()->maxStamps; } else { - return ValidateReceivedWonderNews(); + data->flagId = 0; } + + for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++) + data->questionnaireWords[i] = gSaveBlock1Ptr->mysteryGift.questionnaireWords[i]; + + CopyTrainerId(data->playerTrainerId, gSaveBlock2Ptr->playerTrainerId); + StringCopy(data->playerName, gSaveBlock2Ptr->playerName); + for (i = 0; i < EASY_CHAT_BATTLE_WORDS_COUNT; i++) + data->easyChatProfile[i] = gSaveBlock1Ptr->easyChatProfile[i]; + + memcpy(data->romHeaderGameCode, RomHeaderGameCode, GAME_CODE_LENGTH); + data->romHeaderSoftwareVersion = RomHeaderSoftwareVersion; } -static bool32 HandleLoadWonderCardOrNews(u8 * state, bool32 cardOrNews) +bool32 MysteryGift_ValidateLinkGameData(const struct MysteryGiftLinkGameData *data, bool32 isWonderNews) { - switch (*state) + if (data->validationVar != GAME_DATA_VALID_VAR) + return FALSE; + + if (!(data->validationFlag1 & 1)) + return FALSE; + + if (!(data->validationFlag2 & 1)) + return FALSE; + + if (!isWonderNews) { - case 0: - if (cardOrNews == 0) - { - InitWonderCardResources(GetSavedWonderCard(), sav1_get_mevent_buffer_2()); - } - else - { - InitWonderNewsResources(GetSavedWonderNews()); - } - (*state)++; - break; - case 1: - if (cardOrNews == 0) - { - if (!FadeToWonderCardMenu()) - { - return FALSE; - } - } - else - { - if (!FadeToWonderNewsMenu()) - { - return FALSE; - } - } - *state = 0; - return TRUE; + if (!(data->validationGiftType1 & GAME_DATA_VALID_GIFT_TYPE_1)) + return FALSE; + + if (!(data->validationGiftType2 & (GAME_DATA_VALID_GIFT_TYPE_2 | 0x180))) + return FALSE; } - return FALSE; + return TRUE; } -static bool32 DestroyNewsOrCard(bool32 cardOrNews) +u32 MysteryGift_CompareCardFlags(const u16 *flagId, const struct MysteryGiftLinkGameData *data, const void *unused) { - if (cardOrNews == 0) - { - DestroyWonderCard(); - } - else - { - DestroyWonderNews(); - } - return TRUE; + // Has a Wonder Card already? + if (data->flagId == 0) + return HAS_NO_CARD; + + // Has this Wonder Card already? + if (*flagId == data->flagId) + return HAS_SAME_CARD; + + // Player has a different Wonder Card + return HAS_DIFF_CARD; } -static bool32 TearDownCardOrNews_ReturnToTopMenu(bool32 cardOrNews, bool32 arg1) +// This is referenced by the Mystery Gift server, but the instruction it's referenced in is never used, +// so the return values here are never checked by anything. +u32 MysteryGift_CheckStamps(const u16 *stamp, const struct MysteryGiftLinkGameData *data, const void *unused) { - if (cardOrNews == 0) - { - if (FadeOutFromWonderCard(arg1) != 0) - { - DestroyWonderCardResources(); - return TRUE; - } - else - { - return FALSE; - } - } - else + int stampsMissing = data->maxStamps - GetNumStampsInMetadata(&data->cardMetadata, data->maxStamps); + + // Has full stamp card? + if (stampsMissing == 0) + return 1; + + // Already has stamp? + if (IsStampInMetadata(&data->cardMetadata, stamp, data->maxStamps)) + return 3; + + // Only 1 empty stamp left? + if (stampsMissing == 1) + return 4; + + // This is a new stamp + return 2; +} + +bool32 MysteryGift_DoesQuestionnaireMatch(const struct MysteryGiftLinkGameData *data, const u16 *words) +{ + int i; + for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++) { - if (FadeOutFromWonderNews(arg1) != 0) - { - DestroyWonderNewsResources(); - return TRUE; - } - else - { + if (data->questionnaireWords[i] != words[i]) return FALSE; - } } + + return TRUE; } -static s32 mevent_message_prompt_discard(u8 * textState, u16 * windowId, bool32 cardOrNews) +static int GetNumStampsInLinkData(const struct MysteryGiftLinkGameData *data) { - if (cardOrNews == 0) - { - return mevent_message_print_and_prompt_yes_no(textState, windowId, TRUE, gText_IfThrowAwayCardEventWontHappen); - } - else - { - return mevent_message_print_and_prompt_yes_no(textState, windowId, TRUE, gText_OkayToDiscardNews); - } + return GetNumStampsInMetadata(&data->cardMetadata, data->maxStamps); } -static bool32 mevent_message_was_thrown_away(u8 * textState, bool32 cardOrNews) +u16 MysteryGift_GetCardStatFromLinkData(const struct MysteryGiftLinkGameData *data, u32 stat) { - if (cardOrNews == 0) - { - return MG_PrintTextOnWindow1AndWaitButton(textState, gText_WonderCardThrownAway); - } - else + switch (stat) { - return MG_PrintTextOnWindow1AndWaitButton(textState, gText_WonderNewsThrownAway); + case CARD_STAT_BATTLES_WON: + return data->cardMetadata.battlesWon; + case CARD_STAT_BATTLES_LOST: + return data->cardMetadata.battlesLost; + case CARD_STAT_NUM_TRADES: + return data->cardMetadata.numTrades; + case CARD_STAT_NUM_STAMPS: + return GetNumStampsInLinkData(data); + case CARD_STAT_MAX_STAMPS: + return data->maxStamps; + default: + AGB_ASSERT(0); + return 0; } } -static bool32 mevent_save_game(u8 * state) +static void IncrementCardStat(u32 statType) { - switch (*state) + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type == CARD_TYPE_LINK_STAT) { - case 0: - AddTextPrinterToWindow1(gText_DataWillBeSaved); - (*state)++; - break; - case 1: - TrySavingData(SAVE_NORMAL); - (*state)++; - break; - case 2: - AddTextPrinterToWindow1(gText_SaveCompletedPressA); - (*state)++; - break; - case 3: - if (({JOY_NEW(A_BUTTON | B_BUTTON);})) + u16 *stat = NULL; + switch (statType) { - (*state)++; + case CARD_STAT_BATTLES_WON: + stat = &gSaveBlock1Ptr->mysteryGift.cardMetadata.battlesWon; + break; + case CARD_STAT_BATTLES_LOST: + stat = &gSaveBlock1Ptr->mysteryGift.cardMetadata.battlesLost; + break; + case CARD_STAT_NUM_TRADES: + stat = &gSaveBlock1Ptr->mysteryGift.cardMetadata.numTrades; + break; + case CARD_STAT_NUM_STAMPS: // Unused + case CARD_STAT_MAX_STAMPS: // Unused + break; } - break; - case 4: - *state = 0; - ClearTextWindow(); - return TRUE; - } - - return FALSE; -} - -static const u8 * mevent_message(u32 * a0, u8 a1, u8 cardOrNews, u32 msgId) -{ - const u8 * msg = NULL; - *a0 = 0; - switch (msgId) - { - case 0: - *a0 = 0; - msg = gText_NothingSentOver; - break; - case 1: - *a0 = 0; - msg = gText_RecordUploadedViaWireless; - break; - case 2: - *a0 = 1; - msg = cardOrNews == 0 ? gText_WonderCardReceived : gText_WonderCardReceivedFrom; - break; - case 3: - *a0 = 1; - msg = cardOrNews == 0 ? gText_WonderNewsReceived : gText_WonderNewsReceivedFrom; - break; - case 4: - *a0 = 1; - msg = gText_NewStampReceived; - break; - case 5: - *a0 = 0; - msg = gText_AlreadyHadCard; - break; - case 6: - *a0 = 0; - msg = gText_AlreadyHadStamp; - break; - case 7: - *a0 = 0; - msg = gText_AlreadyHadNews; - break; - case 8: - *a0 = 0; - msg = gText_NoMoreRoomForStamps; - break; - case 9: - *a0 = 0; - msg = gText_CommunicationCanceled; - break; - case 10: - *a0 = 0; - msg = a1 == 0 ? gText_CantAcceptCardFromTrainer : gText_CantAcceptNewsFromTrainer; - break; - case 11: - *a0 = 0; - msg = gText_CommunicationError; - break; - case 12: - *a0 = 1; - msg = gText_NewTrainerReceived; - break; - case 13: - *a0 = 1; - break; - case 14: - *a0 = 0; - break; + if (stat == NULL) + AGB_ASSERT(0); + else if (++(*stat) > MAX_WONDER_CARD_STAT) + *stat = MAX_WONDER_CARD_STAT; } - - return msg; } -static bool32 PrintMGSuccessMessage(u8 * state, const u8 * arg1, u16 * arg2) +u16 MysteryGift_GetCardStat(u32 stat) { - switch (*state) + switch (stat) { - case 0: - if (arg1 != NULL) + case CARD_STAT_BATTLES_WON: + { + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type == CARD_TYPE_LINK_STAT) { - AddTextPrinterToWindow1(arg1); + struct WonderCardMetadata *metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata; + return metadata->battlesWon; } - PlayFanfare(MUS_OBTAIN_ITEM); - *arg2 = 0; - (*state)++; break; - case 1: - if (++(*arg2) > 0xF0) + } + case CARD_STAT_BATTLES_LOST: + { + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type == CARD_TYPE_LINK_STAT) { - (*state)++; + struct WonderCardMetadata *metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata; + return metadata->battlesLost; } break; - case 2: - if (IsFanfareTaskInactive()) + } + case CARD_STAT_NUM_TRADES: + { + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type == CARD_TYPE_LINK_STAT) { - *state = 0; - ClearTextWindow(); - return TRUE; + struct WonderCardMetadata *metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata; + return metadata->numTrades; } break; } - return FALSE; -} - -static const u8 * mevent_message_stamp_card_etc_send_status(u32 * a0, u8 unused, u32 msgId) -{ - const u8 * result = gText_CommunicationError; - *a0 = 0; - switch (msgId) + case CARD_STAT_NUM_STAMPS: { - case 0: - result = gText_NothingSentOver; - break; - case 1: - result = gText_RecordUploadedViaWireless; - break; - case 2: - result = gText_WonderCardSentTo; - *a0 = 1; - break; - case 3: - result = gText_WonderNewsSentTo; - *a0 = 1; - break; - case 4: - result = gText_StampSentTo; - break; - case 5: - result = gText_OtherTrainerHasCard; - break; - case 6: - result = gText_OtherTrainerHasStamp; - break; - case 7: - result = gText_OtherTrainerHasNews; - break; - case 8: - result = gText_NoMoreRoomForStamps; - break; - case 9: - result = gText_OtherTrainerCanceled; - break; - case 10: - result = gText_CantSendGiftToTrainer; - break; - case 11: - result = gText_CommunicationError; - break; - case 12: - result = gText_GiftSentTo; - break; - case 13: - result = gText_GiftSentTo; - break; - case 14: - result = gText_CantSendGiftToTrainer; + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type == CARD_TYPE_STAMP) + return GetNumStampsInSavedCard(); break; } - return result; -} - -static bool32 PrintMGSendStatus(u8 * state, u16 * arg1, u8 arg2, u32 msgId) -{ - u32 flag; - const u8 * str = mevent_message_stamp_card_etc_send_status(&flag, arg2, msgId); - if (flag) + case CARD_STAT_MAX_STAMPS: { - return PrintMGSuccessMessage(state, str, arg1); + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type == CARD_TYPE_STAMP) + return card->maxStamps; + break; } - else - { - return MG_PrintTextOnWindow1AndWaitButton(state, str); } + + AGB_ASSERT(0); + return 0; } -void task_add_00_mystery_gift(void) +void MysteryGift_DisableStats(void) { - u8 taskId = CreateTask(task00_mystery_gift, 0); - struct MysteryGiftTaskData * data = (void *)gTasks[taskId].data; - data->state = 0; - data->textState = 0; - data->unkA = 0; - data->unkB = 0; - data->IsCardOrNews = 0; - data->source = 0; - data->curPromptWindowId = 0; - data->unk2 = 0; - data->unk4 = 0; - data->unk6 = 0; - data->prevPromptWindowId = 0; - data->buffer = AllocZeroed(0x40); + sStatsEnabled = FALSE; } -void task00_mystery_gift(u8 taskId) +bool32 MysteryGift_TryEnableStatsByFlagId(u16 flagId) { - struct MysteryGiftTaskData *data = (void *)gTasks[taskId].data; - u32 sp0, flag; - const u8 *r1; + sStatsEnabled = FALSE; + if (flagId == 0) + return FALSE; + + if (!ValidateSavedWonderCard()) + return FALSE; + + if (gSaveBlock1Ptr->mysteryGift.card.flagId != flagId) + return FALSE; - switch (data->state) + sStatsEnabled = TRUE; + return TRUE; +} + +void MysteryGift_TryIncrementStat(u32 stat, u32 trainerId) +{ + if (sStatsEnabled) { - case 0: - data->state = 1; - break; - case 1: - switch (MysteryGift_HandleThreeOptionMenu(&data->textState, &data->curPromptWindowId, FALSE)) + switch (stat) { - case 0: - data->IsCardOrNews = 0; - if (ValidateReceivedWonderCard() == TRUE) - { - data->state = 18; - } - else - { - data->state = 2; - } - break; - case 1: - data->IsCardOrNews = 1; - if (ValidateReceivedWonderNews() == TRUE) - { - data->state = 18; - } - else - { - data->state = 2; - } - break; - case -2u: - data->state = 37; + case CARD_STAT_NUM_TRADES: + IncrementCardStatForNewTrainer(CARD_STAT_NUM_TRADES, + trainerId, + gSaveBlock1Ptr->mysteryGift.trainerIds[1], + ARRAY_COUNT(gSaveBlock1Ptr->mysteryGift.trainerIds[1])); break; - } - break; - case 2: - { - if (data->IsCardOrNews == 0) - { - if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, gText_DontHaveCardNewOneInput)) - { - data->state = 3; - PrintMysteryGiftOrEReaderTopMenu(0, 1); - } - } - else - { - if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, gText_DontHaveNewsNewOneInput)) - { - data->state = 3; - PrintMysteryGiftOrEReaderTopMenu(0, 1); - } - } - break; - } - case 3: - if (data->IsCardOrNews == 0) - { - AddTextPrinterToWindow1(gText_WhereShouldCardBeAccessed); - } - else - { - AddTextPrinterToWindow1(gText_WhereShouldNewsBeAccessed); - } - data->state = 4; - break; - case 4: - switch (MysteryGift_HandleThreeOptionMenu(&data->textState, &data->curPromptWindowId, TRUE)) - { - case 0: - ClearTextWindow(); - data->state = 5; - data->source = 0; + case CARD_STAT_BATTLES_WON: + IncrementCardStatForNewTrainer(CARD_STAT_BATTLES_WON, + trainerId, + gSaveBlock1Ptr->mysteryGift.trainerIds[0], + ARRAY_COUNT(gSaveBlock1Ptr->mysteryGift.trainerIds[0])); break; - case 1: - ClearTextWindow(); - data->state = 5; - data->source = 1; + case CARD_STAT_BATTLES_LOST: + IncrementCardStatForNewTrainer(CARD_STAT_BATTLES_LOST, + trainerId, + gSaveBlock1Ptr->mysteryGift.trainerIds[0], + ARRAY_COUNT(gSaveBlock1Ptr->mysteryGift.trainerIds[0])); break; - case -2u: - ClearTextWindow(); - if (ValidateCardOrNews(data->IsCardOrNews)) - { - data->state = 18; - } - else - { - data->state = 0; - PrintMysteryGiftOrEReaderTopMenu(0, 0); - } + default: + AGB_ASSERT(0); break; } - break; - case 5: - *gStringVar1 = EOS; - *gStringVar2 = EOS; - *gStringVar3 = EOS; + } +} - switch (data->IsCardOrNews) - { - case 0: - if (data->source == 1) - { - MEvent_CreateTask_CardOrNewsWithFriend(ACTIVITY_WONDER_CARD); - } - else if (data->source == 0) - { - MEvent_CreateTask_CardOrNewsOverWireless(ACTIVITY_WONDER_CARD); - } - break; - case 1: - if (data->source == 1) - { - MEvent_CreateTask_CardOrNewsWithFriend(ACTIVITY_WONDER_NEWS); - } - else if (data->source == 0) - { - MEvent_CreateTask_CardOrNewsOverWireless(ACTIVITY_WONDER_NEWS); - } - break; - } - data->state = 6; - break; - case 6: - if (gReceivedRemoteLinkPlayers != 0) - { - ClearScreenInBg0(TRUE); - data->state = 7; - mevent_client_do_init(data->IsCardOrNews); - } - else if (gSpecialVar_Result == LINKUP_FAILED) - { - ClearScreenInBg0(TRUE); - data->state = 3; - } - break; - case 7: - AddTextPrinterToWindow1(gText_Communicating); - data->state = 8; - break; - case 8: - switch (mevent_client_do_exec(&data->curPromptWindowId)) - { - case 6: - Rfu_SetCloseLinkCallback(); - data->prevPromptWindowId = data->curPromptWindowId; - data->state = 13; - break; - case 5: - memcpy(data->buffer, mevent_client_get_buffer(), 0x40); - mevent_client_inc_flag(); - break; - case 3: - data->state = 10; - break; - case 2: - data->state = 9; - break; - case 4: - data->state = 11; - StringCopy(gStringVar1, gLinkPlayers[0].name); - break; - } - break; - case 9: - flag = mevent_message_print_and_prompt_yes_no(&data->textState, &data->curPromptWindowId, FALSE, mevent_client_get_buffer()); - switch (flag) - { - case 0: - mevent_client_set_param(0); - mevent_client_inc_flag(); - data->state = 7; - break; - case 1: - mevent_client_set_param(1); - mevent_client_inc_flag(); - data->state = 7; - break; - case -1u: - mevent_client_set_param(1); - mevent_client_inc_flag(); - data->state = 7; - break; - } - break; - case 10: - if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, mevent_client_get_buffer())) - { - mevent_client_inc_flag(); - data->state = 7; - } - break; - case 11: - flag = mevent_message_print_and_prompt_yes_no(&data->textState, &data->curPromptWindowId, FALSE, gText_ThrowAwayWonderCard); - switch (flag) - { - case 0: - if (CheckReceivedGiftFromWonderCard() == TRUE) - { - data->state = 12; - } - else - { - mevent_client_set_param(0); - mevent_client_inc_flag(); - data->state = 7; - } - break; - case 1: - mevent_client_set_param(1); - mevent_client_inc_flag(); - data->state = 7; - break; - case -1u: - mevent_client_set_param(1); - mevent_client_inc_flag(); - data->state = 7; - break; - } - break; - case 12: - flag = mevent_message_print_and_prompt_yes_no(&data->textState, &data->curPromptWindowId, FALSE, gText_HaventReceivedCardsGift); - switch (flag) - { - case 0: - mevent_client_set_param(0); - mevent_client_inc_flag(); - data->state = 7; - break; - case 1: - mevent_client_set_param(1); - mevent_client_inc_flag(); - data->state = 7; - break; - case -1u: - mevent_client_set_param(1); - mevent_client_inc_flag(); - data->state = 7; - break; - } - break; - case 13: - if (gReceivedRemoteLinkPlayers == 0) - { - DestroyWirelessStatusIndicatorSprite(); - data->state = 14; - } - break; - case 14: - if (PrintStringAndWait2Seconds(&data->textState, gText_CommunicationCompleted)) - { - if (data->source == 1) - { - StringCopy(gStringVar1, gLinkPlayers[0].name); - } - data->state = 15; - } - break; - case 15: - r1 = mevent_message(&sp0, data->IsCardOrNews, data->source, data->prevPromptWindowId); - if (r1 == NULL) - { - r1 = data->buffer; - } - if (sp0) - { - flag = PrintMGSuccessMessage(&data->textState, r1, &data->curPromptWindowId); - } - else - { - flag = MG_PrintTextOnWindow1AndWaitButton(&data->textState, r1); - } - if (flag) - { - if (data->prevPromptWindowId == 3) - { - if (data->source == 1) - { - GenerateRandomNews(1); - } - else - { - GenerateRandomNews(2); - } - } - if (!sp0) - { - data->state = 0; - PrintMysteryGiftOrEReaderTopMenu(0, 0); - } - else - { - data->state = 17; - } - } - break; - case 16: - if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, gText_CommunicationError)) - { - data->state = 0; - PrintMysteryGiftOrEReaderTopMenu(0, 0); - } - break; - case 17: - if (mevent_save_game(&data->textState)) - { - data->state = 18; - } - break; - case 18: - if (HandleLoadWonderCardOrNews(&data->textState, data->IsCardOrNews)) - { - data->state = 20; - } - break; - case 20: - if (data->IsCardOrNews == 0) - { - if (({JOY_NEW(A_BUTTON);})) - { - data->state = 21; - } - if (({JOY_NEW(B_BUTTON);})) - { - data->state = 27; - } - } - else - { - switch (MENews_GetInput(gMain.newKeys)) - { - case 0: - MENews_RemoveScrollIndicatorArrowPair(); - data->state = 21; - break; - case 1: - data->state = 27; - break; - } - } - break; - case 21: +static void ClearSavedTrainerIds(void) +{ + CpuFill32(0, gSaveBlock1Ptr->mysteryGift.trainerIds, sizeof(gSaveBlock1Ptr->mysteryGift.trainerIds)); +} + +// Returns TRUE if it's a new trainer id, FALSE if an existing one. +// In either case the given trainerId is saved in element 0 +static bool32 RecordTrainerId(u32 trainerId, u32 *trainerIds, int size) +{ + int i, j; + + for (i = 0; i < size; i++) { - u32 result; - if (data->IsCardOrNews == 0) - { - if (WonderCard_Test_Unk_08_6()) - { - result = HandleMysteryGiftListMenu(&data->textState, &data->curPromptWindowId, data->IsCardOrNews, FALSE); - } - else - { - result = HandleMysteryGiftListMenu(&data->textState, &data->curPromptWindowId, data->IsCardOrNews, TRUE); - } - } - else - { - if (WonderNews_Test_Unk_02()) - { - result = HandleMysteryGiftListMenu(&data->textState, &data->curPromptWindowId, data->IsCardOrNews, FALSE); - } - else - { - result = HandleMysteryGiftListMenu(&data->textState, &data->curPromptWindowId, data->IsCardOrNews, TRUE); - } - } - switch (result) - { - case 0: - data->state = 28; - break; - case 1: - data->state = 29; + if (trainerIds[i] == trainerId) break; - case 2: - data->state = 22; - break; - case -2u: - if (data->IsCardOrNews == 1) - { - MENews_AddScrollIndicatorArrowPair(); - } - data->state = 20; - break; - } - break; } - case 22: - switch (mevent_message_prompt_discard(&data->textState, &data->curPromptWindowId, data->IsCardOrNews)) - { - case 0: - if (data->IsCardOrNews == 0 && CheckReceivedGiftFromWonderCard() == TRUE) - { - data->state = 23; - } - else - { - data->state = 24; - } - break; - case 1: - data->state = 21; - break; - case -1: - data->state = 21; - break; - } - break; - case 23: - switch ((u32)mevent_message_print_and_prompt_yes_no(&data->textState, &data->curPromptWindowId, TRUE, gText_HaventReceivedGiftOkayToDiscard)) - { - case 0: - data->state = 24; - break; - case 1: - data->state = 21; - break; - case -1u: - data->state = 21; - break; - } - break; - case 24: - if (TearDownCardOrNews_ReturnToTopMenu(data->IsCardOrNews, 1)) - { - DestroyNewsOrCard(data->IsCardOrNews); - data->state = 25; - } - break; - case 25: - if (mevent_save_game(&data->textState)) - { - data->state = 26; - } - break; - case 26: - if (mevent_message_was_thrown_away(&data->textState, data->IsCardOrNews)) - { - data->state = 0; - PrintMysteryGiftOrEReaderTopMenu(0, 0); - } - break; - case 27: - if (TearDownCardOrNews_ReturnToTopMenu(data->IsCardOrNews, 0)) - { - data->state = 0; - } - break; - case 28: - if (TearDownCardOrNews_ReturnToTopMenu(data->IsCardOrNews, 1)) - { - data->state = 3; - } - break; - case 29: - if (TearDownCardOrNews_ReturnToTopMenu(data->IsCardOrNews, 1)) - { - switch (data->IsCardOrNews) - { - case 0: - MEvent_CreateTask_Leader(ACTIVITY_WONDER_CARD); - break; - case 1: - MEvent_CreateTask_Leader(ACTIVITY_WONDER_NEWS); - break; - } - data->source = 1; - data->state = 30; - } - break; - case 30: - if (gReceivedRemoteLinkPlayers != 0) - { - ClearScreenInBg0(1); - data->state = 31; - } - else if (gSpecialVar_Result == LINKUP_FAILED) - { - ClearScreenInBg0(1); - data->state = 18; - } - break; - case 31: - *gStringVar1 = EOS; - *gStringVar2 = EOS; - *gStringVar3 = EOS; - if (data->IsCardOrNews == 0) - { - AddTextPrinterToWindow1(gText_SendingWonderCard); - mevent_srv_new_wcard(); - } - else - { - AddTextPrinterToWindow1(gText_SendingWonderNews); - mevent_srv_init_wnews(); - } - data->state = 32; - break; - case 32: - if (mevent_srv_common_do_exec(&data->curPromptWindowId) == 3) - { - data->prevPromptWindowId = data->curPromptWindowId; - data->state = 33; - } - break; - case 33: - Rfu_SetCloseLinkCallback(); - StringCopy(gStringVar1, gLinkPlayers[1].name); - data->state = 34; - break; - case 34: - if (gReceivedRemoteLinkPlayers == 0) - { - DestroyWirelessStatusIndicatorSprite(); - data->state = 35; - } - break; - case 35: - if (PrintMGSendStatus(&data->textState, &data->curPromptWindowId, data->source, data->prevPromptWindowId)) - { - if (data->source == 1 && data->prevPromptWindowId == 3) - { - GenerateRandomNews(3); - data->state = 17; - } - else - { - data->state = 0; - PrintMysteryGiftOrEReaderTopMenu(0, 0); - } - } - break; - case 36: - if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, gText_CommunicationError)) - { - data->state = 0; - PrintMysteryGiftOrEReaderTopMenu(0, 0); - } - break; - case 37: - CloseLink(); - Free(data->buffer); - DestroyTask(taskId); - SetMainCallback2(MainCB_FreeAllBuffersAndReturnToInitTitleScreen); - break; + if (i == size) + { + // New trainer, shift array and insert new id at front + for (j = size - 1; j > 0; j--) + trainerIds[j] = trainerIds[j - 1]; + + trainerIds[0] = trainerId; + return TRUE; } -} + else + { + // Existing trainer, shift back to old slot and move id to front + for (j = i; j > 0; j--) + trainerIds[j] = trainerIds[j - 1]; -u16 GetMysteryGiftBaseBlock(void) -{ - return 0x1A9; + trainerIds[0] = trainerId; + return FALSE; + } } -void bgid_upload_textbox_1(u8 bgId) +static void IncrementCardStatForNewTrainer(u32 stat, u32 trainerId, u32 *trainerIds, int size) { - DecompressAndLoadBgGfxUsingHeap(bgId, gUnkTextboxBorderGfx, 0x100, 0, 0); + if (RecordTrainerId(trainerId, trainerIds, size)) + IncrementCardStat(stat); } diff --git a/src/mystery_gift_client.c b/src/mystery_gift_client.c new file mode 100644 index 000000000..adf3ce8a6 --- /dev/null +++ b/src/mystery_gift_client.c @@ -0,0 +1,303 @@ +#include "global.h" +#include "malloc.h" +#include "decompress.h" +#include "overworld.h" +#include "script.h" +#include "battle_tower.h" +#include "mystery_gift.h" +#include "mystery_event_script.h" +#include "mystery_gift_client.h" + +enum { + FUNC_INIT, + FUNC_DONE, + FUNC_RECV, + FUNC_SEND, + FUNC_RUN, + FUNC_WAIT, + FUNC_RUN_MEVENT, + FUNC_RUN_BUFFER, +}; + +EWRAM_DATA static struct MysteryGiftClient * sClient = NULL; + +static void MysteryGiftClient_Init(struct MysteryGiftClient *, u32, u32); +static u32 MysteryGiftClient_CallFunc(struct MysteryGiftClient *); +static void MysteryGiftClient_Free(struct MysteryGiftClient *); + +extern const struct MysteryGiftClientCmd gMysteryGiftClientScript_Init[]; + +void MysteryGiftClient_Create(bool32 isWonderNews) +{ + sClient = AllocZeroed(sizeof(*sClient)); + MysteryGiftClient_Init(sClient, 1, 0); + sClient->isWonderNews = isWonderNews; +} + +u32 MysteryGiftClient_Run(u16 * endVal) +{ + u32 result; + if (sClient == NULL) + return CLI_RET_END; + result = MysteryGiftClient_CallFunc(sClient); + if (result == CLI_RET_END) + { + *endVal = sClient->param; + MysteryGiftClient_Free(sClient); + Free(sClient); + sClient = NULL; + } + return result; +} + +void MysteryGiftClient_AdvanceState(void) +{ + sClient->funcState++; +} + +void * MysteryGiftClient_GetMsg(void) +{ + return sClient->msg; +} + +void MysteryGiftClient_SetParam(u32 val) +{ + sClient->param = val; +} + +static void MysteryGiftClient_Init(struct MysteryGiftClient * client, u32 sendPlayerId, u32 recvPlayerId) +{ + client->unused = 0; + client->funcId = FUNC_INIT; + client->funcState = 0; + client->sendBuffer = AllocZeroed(MG_LINK_BUFFER_SIZE); + client->recvBuffer = AllocZeroed(MG_LINK_BUFFER_SIZE); + client->script = AllocZeroed(MG_LINK_BUFFER_SIZE); + client->msg = AllocZeroed(CLIENT_MAX_MSG_SIZE); + MysteryGiftLink_Init(&client->link, sendPlayerId, recvPlayerId); +} + +static void MysteryGiftClient_Free(struct MysteryGiftClient * client) +{ + Free(client->sendBuffer); + Free(client->recvBuffer); + Free(client->script); + Free(client->msg); +} + +static void MysteryGiftClient_CopyRecvScript(struct MysteryGiftClient * client) +{ + memcpy(client->script, client->recvBuffer, MG_LINK_BUFFER_SIZE); + client->cmdidx = 0; +} + +static void MysteryGiftClient_InitSendWord(struct MysteryGiftClient * client, u32 ident, u32 word) +{ + CpuFill32(0, client->sendBuffer, MG_LINK_BUFFER_SIZE); + *(u32 *)client->sendBuffer = word; + MysteryGiftLink_InitSend(&client->link, ident, client->sendBuffer, sizeof(word)); +} + +static u32 Client_Init(struct MysteryGiftClient * client) +{ + memcpy(client->script, gMysteryGiftClientScript_Init, MG_LINK_BUFFER_SIZE); + client->cmdidx = 0; + client->funcId = FUNC_RUN; + client->funcState = 0; + return CLI_RET_INIT; +} + +static u32 Client_Done(struct MysteryGiftClient * client) +{ + return CLI_RET_END; +} + + +static u32 Client_Recv(struct MysteryGiftClient * client) +{ + if (MysteryGiftLink_Recv(&client->link)) + { + client->funcId = FUNC_RUN; + client->funcState = 0; + } + return CLI_RET_ACTIVE; +} + +static u32 Client_Send(struct MysteryGiftClient * client) +{ + if (MysteryGiftLink_Send(&client->link)) + { + client->funcId = FUNC_RUN; + client->funcState = 0; + } + return CLI_RET_ACTIVE; +} + +static u32 Client_Run(struct MysteryGiftClient * client) +{ + // process command + struct MysteryGiftClientCmd * cmd = &client->script[client->cmdidx]; + client->cmdidx++; + switch (cmd->instr) + { + case CLI_NONE: + break; + case CLI_RETURN: + client->param = cmd->parameter; // Set for endVal in MysteryGiftClient_Run + client->funcId = FUNC_DONE; + client->funcState = 0; + break; + case CLI_RECV: + MysteryGiftLink_InitRecv(&client->link, cmd->parameter, client->recvBuffer); + client->funcId = FUNC_RECV; + client->funcState = 0; + break; + case CLI_SEND_LOADED: + // Send without a MysteryGiftLink_InitSend + // Sends whatever has been loaded already + client->funcId = FUNC_SEND; + client->funcState = 0; + break; + case CLI_SEND_READY_END: + MysteryGiftLink_InitSend(&client->link, MG_LINKID_READY_END, client->sendBuffer, 0); + client->funcId = FUNC_SEND; + client->funcState = 0; + break; + case CLI_SEND_STAT: + MysteryGiftClient_InitSendWord(client, MG_LINKID_GAME_STAT, GetGameStat(cmd->parameter)); + client->funcId = FUNC_SEND; + client->funcState = 0; + break; + case CLI_COPY_RECV_IF_N: + if (client->param == FALSE) + MysteryGiftClient_CopyRecvScript(client); + break; + case CLI_COPY_RECV_IF: + if (client->param == TRUE) + MysteryGiftClient_CopyRecvScript(client); + break; + case CLI_COPY_RECV: + MysteryGiftClient_CopyRecvScript(client); + break; + case CLI_YES_NO: + memcpy(client->msg, client->recvBuffer, CLIENT_MAX_MSG_SIZE); + client->funcId = FUNC_WAIT; + client->funcState = 0; + return CLI_RET_YES_NO; + case CLI_PRINT_MSG: + memcpy(client->msg, client->recvBuffer, CLIENT_MAX_MSG_SIZE); + client->funcId = FUNC_WAIT; + client->funcState = 0; + return CLI_RET_PRINT_MSG; + case CLI_COPY_MSG: + memcpy(client->msg, client->recvBuffer, CLIENT_MAX_MSG_SIZE); + client->funcId = FUNC_WAIT; + client->funcState = 0; + return CLI_RET_COPY_MSG; + case CLI_ASK_TOSS: + client->funcId = FUNC_WAIT; + client->funcState = 0; + return CLI_RET_ASK_TOSS; + case CLI_LOAD_GAME_DATA: + MysteryGift_LoadLinkGameData(client->sendBuffer, client->isWonderNews); + MysteryGiftLink_InitSend(&client->link, MG_LINKID_GAME_DATA, client->sendBuffer, sizeof(struct MysteryGiftLinkGameData)); + break; + case CLI_LOAD_TOSS_RESPONSE: + // param here is set by MG_STATE_LINK_ASK_TOSS or MG_STATE_LINK_ASK_TOSS_UNRECEIVED + MysteryGiftClient_InitSendWord(client, MG_LINKID_RESPONSE, client->param); + break; + case CLI_SAVE_CARD: + SaveWonderCard(client->recvBuffer); + break; + case CLI_SAVE_NEWS: + if (!IsWonderNewsSameAsSaved(client->recvBuffer)) + { + SaveWonderNews(client->recvBuffer); + MysteryGiftClient_InitSendWord(client, MG_LINKID_RESPONSE, FALSE); + } + else + { + // Wonder News has already been saved (or is invalid). + // Prepare a signal to indicate it was not saved. + MysteryGiftClient_InitSendWord(client, MG_LINKID_RESPONSE, TRUE); + } + break; + case CLI_RUN_MEVENT_SCRIPT: + client->funcId = FUNC_RUN_MEVENT; + client->funcState = 0; + break; + case CLI_SAVE_STAMP: + MysteryGift_TrySaveStamp(client->recvBuffer); + break; + case CLI_SAVE_RAM_SCRIPT: + InitRamScript_NoObjectEvent(client->recvBuffer, 1000); + break; + case CLI_RECV_EREADER_TRAINER: + memcpy(&gSaveBlock2Ptr->frontier.ereaderTrainer, client->recvBuffer, sizeof(gSaveBlock2Ptr->frontier.ereaderTrainer)); + ValidateEReaderTrainer(); + break; + case CLI_RUN_BUFFER_SCRIPT: + memcpy(gDecompressionBuffer, client->recvBuffer, MG_LINK_BUFFER_SIZE); + client->funcId = FUNC_RUN_BUFFER; + client->funcState = 0; + break; + } + + return CLI_RET_ACTIVE; +} + +static u32 Client_Wait(struct MysteryGiftClient * client) +{ + if (client->funcState) + { + client->funcId = FUNC_RUN; + client->funcState = 0; + } + return CLI_RET_ACTIVE; +} + +static u32 Client_RunMysteryEventScript(struct MysteryGiftClient * client) +{ + switch (client->funcState) + { + case 0: + InitMysteryEventScriptContext(client->recvBuffer); + client->funcState++; + break; + case 1: + if (!RunMysteryEventScriptContextCommand(&client->param)) + { + client->funcId = FUNC_RUN; + client->funcState = 0; + } + break; + } + return CLI_RET_ACTIVE; +} + +static u32 Client_RunBufferScript(struct MysteryGiftClient * client) +{ + // exec arbitrary code + u32 (*func)(u32 *, struct SaveBlock2 *, struct SaveBlock1 *) = (void *)gDecompressionBuffer; + if (func(&client->param, gSaveBlock2Ptr, gSaveBlock1Ptr) == 1) + { + client->funcId = FUNC_RUN; + client->funcState = 0; + } + return CLI_RET_ACTIVE; +} + +static u32 MysteryGiftClient_CallFunc(struct MysteryGiftClient * client) +{ + u32 (*funcs[])(struct MysteryGiftClient *) = { + [FUNC_INIT] = Client_Init, + [FUNC_DONE] = Client_Done, + [FUNC_RECV] = Client_Recv, + [FUNC_SEND] = Client_Send, + [FUNC_RUN] = Client_Run, + [FUNC_WAIT] = Client_Wait, + [FUNC_RUN_MEVENT] = Client_RunMysteryEventScript, + [FUNC_RUN_BUFFER] = Client_RunBufferScript + }; + return funcs[client->funcId](client); +} diff --git a/src/mystery_gift_link.c b/src/mystery_gift_link.c new file mode 100644 index 000000000..55f4b7852 --- /dev/null +++ b/src/mystery_gift_link.c @@ -0,0 +1,222 @@ +#include "global.h" +#include "malloc.h" +#include "decompress.h" +#include "util.h" +#include "link.h" +#include "link_rfu.h" +#include "overworld.h" +#include "script.h" +#include "battle_tower.h" +#include "mystery_event_script.h" +#include "mystery_gift.h" +#include "mystery_gift_link.h" + +/* + Handles the link connection functions used by the Mystery Gift client/server. + Note: MysteryGiftLink is shortened to MGL for internal functions. +*/ + +struct SendRecvHeader +{ + u16 ident; + u16 crc; + u16 size; +}; + +static u32 MGL_Receive(struct MysteryGiftLink *); +static u32 MGL_Send(struct MysteryGiftLink *); + +u32 MysteryGiftLink_Recv(struct MysteryGiftLink * link) +{ + return link->recvFunc(link); +} + +u32 MysteryGiftLink_Send(struct MysteryGiftLink * link) +{ + return link->sendFunc(link); +} + +void MysteryGiftLink_Init(struct MysteryGiftLink * link, u32 sendPlayerId, u32 recvPlayerId) +{ + link->sendPlayerId = sendPlayerId; + link->recvPlayerId = recvPlayerId; + link->state = 0; + link->sendCRC = 0; + link->sendSize = 0; + link->sendCounter = 0; + link->recvCRC = 0; + link->recvSize = 0; + link->recvCounter = 0; + link->sendBuffer = NULL; + link->recvBuffer = NULL; + link->sendFunc = MGL_Send; + link->recvFunc = MGL_Receive; +} + +void MysteryGiftLink_InitSend(struct MysteryGiftLink * link, u32 ident, const void * src, u32 size) +{ + link->state = 0; + link->sendIdent = ident; + link->sendCounter = 0; + link->sendCRC = 0; + if (size != 0) + link->sendSize = size; + else + link->sendSize = MG_LINK_BUFFER_SIZE; + link->sendBuffer = src; +} + +void MysteryGiftLink_InitRecv(struct MysteryGiftLink * link, u32 ident, void * dest) +{ + link->state = 0; + link->recvIdent = ident; + link->recvCounter = 0; + link->recvCRC = 0; + link->recvSize = 0; + link->recvBuffer = dest; +} + +static void MGL_ReceiveBlock(u32 playerId, void * dest, size_t size) +{ + memcpy(dest, gBlockRecvBuffer[playerId], size); +} + +static bool32 MGL_HasReceived(u32 playerId) +{ + if ((GetBlockReceivedStatus() >> playerId) & 1) + return TRUE; + else + return FALSE; +} + +static void MGL_ResetReceived(u32 playerId) +{ + ResetBlockReceivedFlag(playerId); +} + +static bool32 MGL_Receive(struct MysteryGiftLink * link) +{ + struct SendRecvHeader header; + + switch (link->state) + { + case 0: + if (MGL_HasReceived(link->recvPlayerId)) + { + MGL_ReceiveBlock(link->recvPlayerId, &header, sizeof(header)); + link->recvSize = header.size; + link->recvCRC = header.crc; + if (link->recvSize > MG_LINK_BUFFER_SIZE) + { + LinkRfu_FatalError(); + return FALSE; + } + else if (link->recvIdent != header.ident) + { + LinkRfu_FatalError(); + return FALSE; + } + else + { + link->recvCounter = 0; + MGL_ResetReceived(link->recvPlayerId); + link->state++; + } + } + break; + case 1: + if (MGL_HasReceived(link->recvPlayerId)) + { + size_t blocksize = link->recvCounter * 252; + if (link->recvSize - blocksize <= 252) + { + MGL_ReceiveBlock(link->recvPlayerId, link->recvBuffer + blocksize, link->recvSize - blocksize); + link->recvCounter++; + link->state++; + } + else + { + MGL_ReceiveBlock(link->recvPlayerId, link->recvBuffer + blocksize, 252); + link->recvCounter++; + } + MGL_ResetReceived(link->recvPlayerId); + } + break; + case 2: + if (CalcCRC16WithTable(link->recvBuffer, link->recvSize) != link->recvCRC) + { + LinkRfu_FatalError(); + return FALSE; + } + else + { + link->state = 0; + return TRUE; + } + break; + } + + return FALSE; +} + +static bool32 MGL_Send(struct MysteryGiftLink * link) +{ + struct SendRecvHeader header; + + switch (link->state) + { + case 0: + if (IsLinkTaskFinished()) + { + header.ident = link->sendIdent; + header.size = link->sendSize; + header.crc = CalcCRC16WithTable(link->sendBuffer, link->sendSize); + link->sendCRC = header.crc; + link->sendCounter = 0; + SendBlock(0, &header, sizeof(header)); + link->state++; + } + break; + case 1: + if (IsLinkTaskFinished()) + { + if (MGL_HasReceived(link->sendPlayerId)) + { + size_t blocksize; + MGL_ResetReceived(link->sendPlayerId); + blocksize = 252 * link->sendCounter; + if (link->sendSize - blocksize <= 252) + { + SendBlock(0, link->sendBuffer + blocksize, link->sendSize - blocksize); + link->sendCounter++; + link->state++; + } + else + { + SendBlock(0, link->sendBuffer + blocksize, 252); + link->sendCounter++; + } + } + } + break; + case 2: + if (IsLinkTaskFinished()) + { + if (CalcCRC16WithTable(link->sendBuffer, link->sendSize) != link->sendCRC) + LinkRfu_FatalError(); + else + link->state++; + } + break; + case 3: + if (MGL_HasReceived(link->sendPlayerId)) + { + MGL_ResetReceived(link->sendPlayerId); + link->state = 0; + return TRUE; + } + break; + } + + return FALSE; +} diff --git a/src/mystery_gift_menu.c b/src/mystery_gift_menu.c new file mode 100644 index 000000000..e1236adfd --- /dev/null +++ b/src/mystery_gift_menu.c @@ -0,0 +1,1618 @@ +#include "global.h" +#include "main.h" +#include "text.h" +#include "task.h" +#include "malloc.h" +#include "gpu_regs.h" +#include "scanline_effect.h" +#include "text_window.h" +#include "bg.h" +#include "window.h" +#include "strings.h" +#include "text_window.h" +#include "menu.h" +#include "palette.h" +#include "constants/songs.h" +#include "sound.h" +#include "mystery_gift_menu.h" +#include "union_room.h" +#include "title_screen.h" +#include "ereader_screen.h" +#include "international_string_util.h" +#include "list_menu.h" +#include "string_util.h" +#include "mystery_gift.h" +#include "mystery_gift_view.h" +#include "save.h" +#include "link.h" +#include "mystery_gift_client.h" +#include "mystery_gift_server.h" +#include "event_data.h" +#include "link_rfu.h" +#include "wonder_news.h" +#include "constants/cable_club.h" + +#define LIST_MENU_TILE_NUM 10 +#define LIST_MENU_PAL_NUM 224 + +static void LoadMysteryGiftTextboxBorder(u8 bgId); +static void CreateMysteryGiftTask(void); +static void Task_MysteryGift(u8 taskId); + +EWRAM_DATA static u8 sDownArrowCounterAndYCoordIdx[8] = {}; +EWRAM_DATA bool8 gGiftIsFromEReader = FALSE; + +static const u16 sTextboxBorder_Pal[] = INCBIN_U16("graphics/interface/mystery_gift_textbox_border.gbapal"); +static const u32 sTextboxBorder_Gfx[] = INCBIN_U32("graphics/interface/mystery_gift_textbox_border.4bpp.lz"); + +struct MysteryGiftTaskData +{ + u16 var; // Multipurpose + u16 unused1; + u16 unused2; + u16 unused3; + u8 state; + u8 textState; + u8 unused4; + u8 unused5; + bool8 isWonderNews; + bool8 sourceIsFriend; + u8 msgId; + u8 * clientMsg; +}; + +static const struct BgTemplate sBGTemplates[] = { + { + .bg = 0, + .charBaseIndex = 2, + .mapBaseIndex = 15, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0x000 + }, { + .bg = 1, + .charBaseIndex = 0, + .mapBaseIndex = 14, + .screenSize = 0, + .paletteMode = 0, + .priority = 1, + .baseTile = 0x000 + }, { + .bg = 2, + .charBaseIndex = 0, + .mapBaseIndex = 13, + .screenSize = 0, + .paletteMode = 0, + .priority = 2, + .baseTile = 0x000 + }, { + .bg = 3, + .charBaseIndex = 0, + .mapBaseIndex = 12, + .screenSize = 0, + .paletteMode = 0, + .priority = 3, + .baseTile = 0x000 + } +}; + +static const struct WindowTemplate sMainWindows[] = { + { + .bg = 0, + .tilemapLeft = 0, + .tilemapTop = 0, + .width = 30, + .height = 2, + .paletteNum = 12, + .baseBlock = 0x0013 + }, { + .bg = 0, + .tilemapLeft = 1, + .tilemapTop = 15, + .width = 28, + .height = 4, + .paletteNum = 12, + .baseBlock = 0x004f + }, { + .bg = 0, + .tilemapLeft = 0, + .tilemapTop = 15, + .width = 30, + .height = 5, + .paletteNum = 13, + .baseBlock = 0x004f + }, + DUMMY_WIN_TEMPLATE +}; + +static const struct WindowTemplate sWindowTemplate_YesNoMsg_Wide = { + .bg = 0, + .tilemapLeft = 1, + .tilemapTop = 15, + .width = 28, + .height = 4, + .paletteNum = 12, + .baseBlock = 0x00e5 +}; + +static const struct WindowTemplate sWindowTemplate_YesNoMsg = { + .bg = 0, + .tilemapLeft = 1, + .tilemapTop = 15, + .width = 20, + .height = 4, + .paletteNum = 12, + .baseBlock = 0x00e5 +}; + +static const struct WindowTemplate sWindowTemplate_GiftSelect = { + .bg = 0, + .tilemapLeft = 1, + .tilemapTop = 15, + .width = 19, + .height = 4, + .paletteNum = 12, + .baseBlock = 0x00e5 +}; + +static const struct WindowTemplate sWindowTemplate_ThreeOptions = { + .bg = 0, + .tilemapLeft = 8, + .tilemapTop = 6, + .width = 14, + .height = 6, + .paletteNum = 12, + .baseBlock = 0x0155 +}; + +static const struct WindowTemplate sWindowTemplate_YesNoBox = { + .bg = 0, + .tilemapLeft = 23, + .tilemapTop = 15, + .width = 6, + .height = 4, + .paletteNum = 12, + .baseBlock = 0x0155 +}; + +static const struct WindowTemplate sWindowTemplate_GiftSelect_3Options = { + .bg = 0, + .tilemapLeft = 22, + .tilemapTop = 11, + .width = 7, + .height = 8, + .paletteNum = 12, + .baseBlock = 0x0155 +}; + +static const struct WindowTemplate sWindowTemplate_GiftSelect_2Options = { + .bg = 0, + .tilemapLeft = 22, + .tilemapTop = 13, + .width = 7, + .height = 6, + .paletteNum = 12, + .baseBlock = 0x0155 +}; + +static const struct WindowTemplate sWindowTemplate_GiftSelect_1Option = { + .bg = 0, + .tilemapLeft = 22, + .tilemapTop = 15, + .width = 7, + .height = 4, + .paletteNum = 12, + .baseBlock = 0x0155 +}; + +static const struct ListMenuItem sListMenuItems_CardsOrNews[] = { + { gText_WonderCards, 0 }, + { gText_WonderNews, 1 }, + { gText_Exit3, LIST_CANCEL } +}; + +static const struct ListMenuItem sListMenuItems_WirelessOrFriend[] = { + { gText_WirelessCommunication, 0 }, + { gText_Friend2, 1 }, + { gText_Cancel2, LIST_CANCEL } +}; + +static const struct ListMenuTemplate sListMenuTemplate_ThreeOptions = { + .items = NULL, + .moveCursorFunc = ListMenuDefaultCursorMoveFunc, + .itemPrintFunc = NULL, + .totalItems = 3, + .maxShowed = 3, + .windowId = 0, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 1, + .cursorPal = 2, + .fillValue = 1, + .cursorShadowPal = 3, + .lettersSpacing = 0, + .itemVerticalPadding = 0, + .scrollMultiple = 0, + .fontId = 1, + .cursorKind = 0 +}; + +static const struct ListMenuItem sListMenuItems_ReceiveSendToss[] = { + { gText_Receive, 0 }, + { gText_Send, 1 }, + { gText_Toss, 2 }, + { gText_Cancel2, LIST_CANCEL } +}; + +static const struct ListMenuItem sListMenuItems_ReceiveToss[] = { + { gText_Receive, 0 }, + { gText_Toss, 2 }, + { gText_Cancel2, LIST_CANCEL } +}; + +static const struct ListMenuItem sListMenuItems_ReceiveSend[] = { + { gText_Receive, 0 }, + { gText_Send, 1 }, + { gText_Cancel2, LIST_CANCEL } +}; + +static const struct ListMenuItem sListMenuItems_Receive[] = { + { gText_Receive, 0 }, + { gText_Cancel2, LIST_CANCEL } +}; + +static const struct ListMenuTemplate sListMenu_ReceiveSendToss = { + .items = sListMenuItems_ReceiveSendToss, + .moveCursorFunc = ListMenuDefaultCursorMoveFunc, + .itemPrintFunc = NULL, + .totalItems = 4, + .maxShowed = 4, + .windowId = 0, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 1, + .cursorPal = 2, + .fillValue = 1, + .cursorShadowPal = 3, + .lettersSpacing = 0, + .itemVerticalPadding = 0, + .scrollMultiple = 0, + .fontId = 1, + .cursorKind = 0 +}; + +static const struct ListMenuTemplate sListMenu_ReceiveToss = { + .items = sListMenuItems_ReceiveToss, + .moveCursorFunc = ListMenuDefaultCursorMoveFunc, + .itemPrintFunc = NULL, + .totalItems = 3, + .maxShowed = 3, + .windowId = 0, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 1, + .cursorPal = 2, + .fillValue = 1, + .cursorShadowPal = 3, + .lettersSpacing = 0, + .itemVerticalPadding = 0, + .scrollMultiple = 0, + .fontId = 1, + .cursorKind = 0 +}; + +static const struct ListMenuTemplate sListMenu_ReceiveSend = { + .items = sListMenuItems_ReceiveSend, + .moveCursorFunc = ListMenuDefaultCursorMoveFunc, + .itemPrintFunc = NULL, + .totalItems = 3, + .maxShowed = 3, + .windowId = 0, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 1, + .cursorPal = 2, + .fillValue = 1, + .cursorShadowPal = 3, + .lettersSpacing = 0, + .itemVerticalPadding = 0, + .scrollMultiple = 0, + .fontId = 1, + .cursorKind = 0 +}; + +static const struct ListMenuTemplate sListMenu_Receive = { + .items = sListMenuItems_Receive, + .moveCursorFunc = ListMenuDefaultCursorMoveFunc, + .itemPrintFunc = NULL, + .totalItems = 2, + .maxShowed = 2, + .windowId = 0, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 1, + .cursorPal = 2, + .fillValue = 1, + .cursorShadowPal = 3, + .lettersSpacing = 0, + .itemVerticalPadding = 0, + .scrollMultiple = 0, + .fontId = 1, + .cursorKind = 0 +}; + +static const u8 *const Unref_082F0710[] = { + gText_VarietyOfEventsImportedWireless, + gText_WonderCardsInPossession, + gText_ReadNewsThatArrived, + gText_ReturnToTitle +}; + +ALIGNED(2) static const u8 sTextColors_TopMenu[] = { TEXT_COLOR_TRANSPARENT, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY }; +ALIGNED(2) static const u8 sTextColors_TopMenu_Copy[] = { TEXT_COLOR_TRANSPARENT, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY }; +ALIGNED(2) static const u8 sMG_Ereader_TextColor_2[] = { TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY }; + +static void VBlankCB_MysteryGiftEReader(void) +{ + ProcessSpriteCopyRequests(); + LoadOam(); + TransferPlttBuffer(); +} + +void CB2_MysteryGiftEReader(void) +{ + RunTasks(); + RunTextPrinters(); + AnimateSprites(); + BuildOamBuffer(); +} + +static bool32 HandleMysteryGiftOrEReaderSetup(s32 isEReader) +{ + switch (gMain.state) + { + case 0: + SetVBlankCallback(NULL); + ResetPaletteFade(); + ResetSpriteData(); + FreeAllSpritePalettes(); + ResetTasks(); + ScanlineEffect_Stop(); + ResetBgsAndClearDma3BusyFlags(0); + + InitBgsFromTemplates(0, sBGTemplates, ARRAY_COUNT(sBGTemplates)); + ChangeBgX(0, 0, 0); + ChangeBgY(0, 0, 0); + ChangeBgX(1, 0, 0); + ChangeBgY(1, 0, 0); + ChangeBgX(2, 0, 0); + ChangeBgY(2, 0, 0); + ChangeBgX(3, 0, 0); + ChangeBgY(3, 0, 0); + + SetBgTilemapBuffer(3, Alloc(BG_SCREEN_SIZE)); + SetBgTilemapBuffer(2, Alloc(BG_SCREEN_SIZE)); + SetBgTilemapBuffer(1, Alloc(BG_SCREEN_SIZE)); + SetBgTilemapBuffer(0, Alloc(BG_SCREEN_SIZE)); + + LoadMysteryGiftTextboxBorder(3); + InitWindows(sMainWindows); + DeactivateAllTextPrinters(); + ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON | DISPCNT_WIN1_ON); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); + SetGpuReg(REG_OFFSET_BLDY, 0); + gMain.state++; + break; + case 1: + LoadPalette(sTextboxBorder_Pal, 0, 0x20); + LoadPalette(GetTextWindowPalette(2), 0xd0, 0x20); + Menu_LoadStdPalAt(0xC0); + LoadUserWindowBorderGfx(0, 0xA, 0xE0); + LoadUserWindowBorderGfx_(0, 0x1, 0xF0); + FillBgTilemapBufferRect(0, 0x000, 0, 0, 32, 32, 0x11); + FillBgTilemapBufferRect(1, 0x000, 0, 0, 32, 32, 0x11); + FillBgTilemapBufferRect(2, 0x000, 0, 0, 32, 32, 0x11); + MG_DrawCheckerboardPattern(3); + PrintMysteryGiftOrEReaderTopMenu(isEReader, FALSE); + gMain.state++; + break; + case 2: + CopyBgTilemapBufferToVram(3); + CopyBgTilemapBufferToVram(2); + CopyBgTilemapBufferToVram(1); + CopyBgTilemapBufferToVram(0); + gMain.state++; + break; + case 3: + ShowBg(0); + ShowBg(3); + PlayBGM(MUS_RG_MYSTERY_GIFT); + SetVBlankCallback(VBlankCB_MysteryGiftEReader); + EnableInterrupts(INTR_FLAG_VBLANK | INTR_FLAG_VCOUNT | INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL); + return TRUE; + } + + return FALSE; +} + +void CB2_InitMysteryGift(void) +{ + if (HandleMysteryGiftOrEReaderSetup(FALSE)) + { + SetMainCallback2(CB2_MysteryGiftEReader); + gGiftIsFromEReader = FALSE; + CreateMysteryGiftTask(); + } + RunTasks(); +} + +void CB2_InitEReader(void) +{ + if (HandleMysteryGiftOrEReaderSetup(TRUE)) + { + SetMainCallback2(CB2_MysteryGiftEReader); + gGiftIsFromEReader = TRUE; + CreateEReaderTask(); + } +} + +void MainCB_FreeAllBuffersAndReturnToInitTitleScreen(void) +{ + gGiftIsFromEReader = FALSE; + FreeAllWindowBuffers(); + Free(GetBgTilemapBuffer(0)); + Free(GetBgTilemapBuffer(1)); + Free(GetBgTilemapBuffer(2)); + Free(GetBgTilemapBuffer(3)); + SetMainCallback2(CB2_InitTitleScreen); +} + +void PrintMysteryGiftOrEReaderTopMenu(bool8 isEReader, bool32 useCancel) +{ + const u8 * header; + const u8 * options; + FillWindowPixelBuffer(0, 0); + if (!isEReader) + { + header = gText_MysteryGift; + options = !useCancel ? gText_PickOKExit : gText_PickOKCancel; + } + else + { + header = gJPText_MysteryGift; + options = gJPText_DecideStop; + } + + AddTextPrinterParameterized4(0, 1, 4, 1, 0, 0, sTextColors_TopMenu, TEXT_SPEED_FF, header); + AddTextPrinterParameterized4(0, 0, GetStringRightAlignXOffset(0, options, 0xDE), 1, 0, 0, sTextColors_TopMenu, TEXT_SPEED_FF, options); + CopyWindowToVram(0, 2); + PutWindowTilemap(0); +} + +void MG_DrawTextBorder(u8 windowId) +{ + DrawTextBorderOuter(windowId, 0x01, 0xF); +} + +void MG_DrawCheckerboardPattern(u32 bg) +{ + s32 i = 0, j; + + FillBgTilemapBufferRect(bg, 0x003, 0, 0, 32, 2, 0x11); + + for (i = 0; i < 18; i++) + { + for (j = 0; j < 32; j++) + { + if ((i & 1) != (j & 1)) + FillBgTilemapBufferRect(bg, 1, j, i + 2, 1, 1, 0x11); + else + FillBgTilemapBufferRect(bg, 2, j, i + 2, 1, 1, 0x11); + } + } +} + +static void ClearScreenInBg0(bool32 ignoreTopTwoRows) +{ + switch (ignoreTopTwoRows) + { + case 0: + FillBgTilemapBufferRect(0, 0, 0, 0, 32, 32, 0x11); + break; + case 1: + FillBgTilemapBufferRect(0, 0, 0, 2, 32, 30, 0x11); + break; + } + CopyBgTilemapBufferToVram(0); +} + +void AddTextPrinterToWindow1(const u8 *str) +{ + StringExpandPlaceholders(gStringVar4, str); + FillWindowPixelBuffer(1, 0x11); + AddTextPrinterParameterized4(1, 1, 0, 1, 0, 0, sMG_Ereader_TextColor_2, 0, gStringVar4); + DrawTextBorderOuter(1, 0x001, 0xF); + PutWindowTilemap(1); + CopyWindowToVram(1, 3); +} + +static void ClearTextWindow(void) +{ + rbox_fill_rectangle(1); + ClearWindowTilemap(1); + CopyWindowToVram(1, 1); +} + +#define DOWN_ARROW_X 208 +#define DOWN_ARROW_Y 20 + +bool32 PrintMysteryGiftMenuMessage(u8 *textState, const u8 *str) +{ + switch (*textState) + { + case 0: + AddTextPrinterToWindow1(str); + (*textState)++; + break; + case 1: + DrawDownArrow(1, DOWN_ARROW_X, DOWN_ARROW_Y, 1, FALSE, &sDownArrowCounterAndYCoordIdx[0], &sDownArrowCounterAndYCoordIdx[1]); + if (({JOY_NEW(A_BUTTON | B_BUTTON);})) + (*textState)++; + break; + case 2: + DrawDownArrow(1, DOWN_ARROW_X, DOWN_ARROW_Y, 1, TRUE, &sDownArrowCounterAndYCoordIdx[0], &sDownArrowCounterAndYCoordIdx[1]); + *textState = 0; + ClearTextWindow(); + return TRUE; + case 0xFF: + *textState = 2; + return FALSE; + } + return FALSE; +} + +static void HideDownArrow(void) +{ + DrawDownArrow(1, DOWN_ARROW_X, DOWN_ARROW_Y, 1, FALSE, &sDownArrowCounterAndYCoordIdx[0], &sDownArrowCounterAndYCoordIdx[1]); +} + +static void ShowDownArrow(void) +{ + DrawDownArrow(1, DOWN_ARROW_X, DOWN_ARROW_Y, 1, TRUE, &sDownArrowCounterAndYCoordIdx[0], &sDownArrowCounterAndYCoordIdx[1]); +} + +// Unused +static bool32 HideDownArrowAndWaitButton(u8 * textState) +{ + switch (*textState) + { + case 0: + HideDownArrow(); + if (JOY_NEW(A_BUTTON | B_BUTTON)) + (*textState)++; + break; + case 1: + ShowDownArrow(); + *textState = 0; + return TRUE; + } + return FALSE; +} + +static bool32 PrintStringAndWait2Seconds(u8 * counter, const u8 * str) +{ + if (*counter == 0) + AddTextPrinterToWindow1(str); + + if (++(*counter) > 120) + { + *counter = 0; + ClearTextWindow(); + return TRUE; + } + else + { + return FALSE; + } +} + +static u32 MysteryGift_HandleThreeOptionMenu(u8 * unused0, u16 * unused1, u8 whichMenu) +{ + struct ListMenuTemplate listMenuTemplate = sListMenuTemplate_ThreeOptions; + struct WindowTemplate windowTemplate = sWindowTemplate_ThreeOptions; + s32 width; + s32 response; + + if (whichMenu == 0) + listMenuTemplate.items = sListMenuItems_CardsOrNews; + else + listMenuTemplate.items = sListMenuItems_WirelessOrFriend; + + width = Intl_GetListMenuWidth(&listMenuTemplate); + if (width & 1) + width++; + + windowTemplate.width = width; + if (width < 30) + windowTemplate.tilemapLeft = (30 - width) / 2; + else + windowTemplate.tilemapLeft = 0; + + response = DoMysteryGiftListMenu(&windowTemplate, &listMenuTemplate, 1, LIST_MENU_TILE_NUM, LIST_MENU_PAL_NUM); + if (response != LIST_NOTHING_CHOSEN) + { + ClearWindowTilemap(2); + CopyWindowToVram(2, 1); + } + return response; +} + +s8 DoMysteryGiftYesNo(u8 * textState, u16 * windowId, bool8 yesNoBoxPlacement, const u8 * str) +{ + struct WindowTemplate windowTemplate; + s8 input; + + switch (*textState) + { + case 0: + // Print question message + StringExpandPlaceholders(gStringVar4, str); + if (yesNoBoxPlacement == 0) + *windowId = AddWindow(&sWindowTemplate_YesNoMsg_Wide); + else + *windowId = AddWindow(&sWindowTemplate_YesNoMsg); + FillWindowPixelBuffer(*windowId, 0x11); + AddTextPrinterParameterized4(*windowId, 1, 0, 1, 0, 0, sMG_Ereader_TextColor_2, 0, gStringVar4); + DrawTextBorderOuter(*windowId, 0x001, 0x0F); + CopyWindowToVram(*windowId, 2); + PutWindowTilemap(*windowId); + (*textState)++; + break; + case 1: + // Create Yes/No + windowTemplate = sWindowTemplate_YesNoBox; + if (yesNoBoxPlacement == 0) + windowTemplate.tilemapTop = 9; + else + windowTemplate.tilemapTop = 15; + CreateYesNoMenu(&windowTemplate, 10, 14, 0); + (*textState)++; + break; + case 2: + // Handle Yes/No input + input = Menu_ProcessInputNoWrapClearOnChoose(); + if (input == MENU_B_PRESSED || input == 0 || input == 1) + { + *textState = 0; + rbox_fill_rectangle(*windowId); + ClearWindowTilemap(*windowId); + CopyWindowToVram(*windowId, 1); + RemoveWindow(*windowId); + return input; + } + break; + case 0xFF: + *textState = 0; + rbox_fill_rectangle(*windowId); + ClearWindowTilemap(*windowId); + CopyWindowToVram(*windowId, 1); + RemoveWindow(*windowId); + return MENU_B_PRESSED; + } + + return MENU_NOTHING_CHOSEN; +} + +// Handle the "Receive/Send/Toss" menu that appears when selecting Wonder Card/News +static s32 HandleGiftSelectMenu(u8 * textState, u16 * windowId, bool32 cannotToss, bool32 cannotSend) +{ + struct WindowTemplate windowTemplate; + s32 input; + + switch (*textState) + { + case 0: + // Print menu message + if (!cannotToss) + StringExpandPlaceholders(gStringVar4, gText_WhatToDoWithCards); + else + StringExpandPlaceholders(gStringVar4, gText_WhatToDoWithNews); + *windowId = AddWindow(&sWindowTemplate_GiftSelect); + FillWindowPixelBuffer(*windowId, 0x11); + AddTextPrinterParameterized4(*windowId, 1, 0, 1, 0, 0, sMG_Ereader_TextColor_2, 0, gStringVar4); + DrawTextBorderOuter(*windowId, 0x001, 0x0F); + CopyWindowToVram(*windowId, 2); + PutWindowTilemap(*windowId); + (*textState)++; + break; + case 1: + windowTemplate = sWindowTemplate_YesNoBox; + if (cannotSend) + { + if (!cannotToss) + input = DoMysteryGiftListMenu(&sWindowTemplate_GiftSelect_2Options, &sListMenu_ReceiveToss, 1, LIST_MENU_TILE_NUM, LIST_MENU_PAL_NUM); + else + input = DoMysteryGiftListMenu(&sWindowTemplate_GiftSelect_1Option, &sListMenu_Receive, 1, LIST_MENU_TILE_NUM, LIST_MENU_PAL_NUM); + } + else + { + if (!cannotToss) + input = DoMysteryGiftListMenu(&sWindowTemplate_GiftSelect_3Options, &sListMenu_ReceiveSendToss, 1, LIST_MENU_TILE_NUM, LIST_MENU_PAL_NUM); + else + input = DoMysteryGiftListMenu(&sWindowTemplate_GiftSelect_2Options, &sListMenu_ReceiveSend, 1, LIST_MENU_TILE_NUM, LIST_MENU_PAL_NUM); + } + if (input != LIST_NOTHING_CHOSEN) + { + *textState = 0; + rbox_fill_rectangle(*windowId); + ClearWindowTilemap(*windowId); + CopyWindowToVram(*windowId, 1); + RemoveWindow(*windowId); + return input; + } + break; + case 0xFF: + *textState = 0; + rbox_fill_rectangle(*windowId); + ClearWindowTilemap(*windowId); + CopyWindowToVram(*windowId, 1); + RemoveWindow(*windowId); + return LIST_CANCEL; + } + + return LIST_NOTHING_CHOSEN; +} + +static bool32 ValidateCardOrNews(bool32 isWonderNews) +{ + if (!isWonderNews) + return ValidateSavedWonderCard(); + else + return ValidateSavedWonderNews(); +} + +static bool32 HandleLoadWonderCardOrNews(u8 * state, bool32 isWonderNews) +{ + switch (*state) + { + case 0: + if (!isWonderNews) + WonderCard_Init(GetSavedWonderCard(), GetSavedWonderCardMetadata()); + else + WonderNews_Init(GetSavedWonderNews()); + (*state)++; + break; + case 1: + if (!isWonderNews) + { + if (!WonderCard_Enter()) + return FALSE; + } + else + { + if (!WonderNews_Enter()) + return FALSE; + } + *state = 0; + return TRUE; + } + + return FALSE; +} + +static bool32 ClearSavedNewsOrCard(bool32 isWonderNews) +{ + if (!isWonderNews) + ClearSavedWonderCardAndRelated(); + else + ClearSavedWonderNewsAndRelated(); + return TRUE; +} + +static bool32 ExitWonderCardOrNews(bool32 isWonderNews, bool32 useCancel) +{ + if (!isWonderNews) + { + if (WonderCard_Exit(useCancel)) + { + WonderCard_Destroy(); + return TRUE; + } + else + { + return FALSE; + } + } + else + { + if (WonderNews_Exit(useCancel)) + { + WonderNews_Destroy(); + return TRUE; + } + else + { + return FALSE; + } + } +} + +static s32 AskDiscardGift(u8 * textState, u16 * windowId, bool32 isWonderNews) +{ + if (!isWonderNews) + return DoMysteryGiftYesNo(textState, windowId, TRUE, gText_IfThrowAwayCardEventWontHappen); + else + return DoMysteryGiftYesNo(textState, windowId, TRUE, gText_OkayToDiscardNews); +} + +static bool32 PrintThrownAway(u8 * textState, bool32 isWonderNews) +{ + if (!isWonderNews) + return PrintMysteryGiftMenuMessage(textState, gText_WonderCardThrownAway); + else + return PrintMysteryGiftMenuMessage(textState, gText_WonderNewsThrownAway); +} + +static bool32 SaveOnMysteryGiftMenu(u8 * state) +{ + switch (*state) + { + case 0: + AddTextPrinterToWindow1(gText_DataWillBeSaved); + (*state)++; + break; + case 1: + TrySavingData(SAVE_NORMAL); + (*state)++; + break; + case 2: + AddTextPrinterToWindow1(gText_SaveCompletedPressA); + (*state)++; + break; + case 3: + if (JOY_NEW(A_BUTTON | B_BUTTON)) + (*state)++; + break; + case 4: + *state = 0; + ClearTextWindow(); + return TRUE; + } + + return FALSE; +} + +static const u8 * GetClientResultMessage(bool32 * successMsg, bool8 isWonderNews, bool8 sourceIsFriend, u32 msgId) +{ + const u8 * msg = NULL; + *successMsg = FALSE; + + switch (msgId) + { + case CLI_MSG_NOTHING_SENT: + *successMsg = FALSE; + msg = gText_NothingSentOver; + break; + case CLI_MSG_RECORD_UPLOADED: + *successMsg = FALSE; + msg = gText_RecordUploadedViaWireless; + break; + case CLI_MSG_CARD_RECEIVED: + *successMsg = TRUE; + msg = !sourceIsFriend ? gText_WonderCardReceived : gText_WonderCardReceivedFrom; + break; + case CLI_MSG_NEWS_RECEIVED: + *successMsg = TRUE; + msg = !sourceIsFriend ? gText_WonderNewsReceived : gText_WonderNewsReceivedFrom; + break; + case CLI_MSG_STAMP_RECEIVED: + *successMsg = TRUE; + msg = gText_NewStampReceived; + break; + case CLI_MSG_HAD_CARD: + *successMsg = FALSE; + msg = gText_AlreadyHadCard; + break; + case CLI_MSG_HAD_STAMP: + *successMsg = FALSE; + msg = gText_AlreadyHadStamp; + break; + case CLI_MSG_HAD_NEWS: + *successMsg = FALSE; + msg = gText_AlreadyHadNews; + break; + case CLI_MSG_NO_ROOM_STAMPS: + *successMsg = FALSE; + msg = gText_NoMoreRoomForStamps; + break; + case CLI_MSG_COMM_CANCELED: + *successMsg = FALSE; + msg = gText_CommunicationCanceled; + break; + case CLI_MSG_CANT_ACCEPT: + *successMsg = FALSE; + msg = !isWonderNews ? gText_CantAcceptCardFromTrainer : gText_CantAcceptNewsFromTrainer; + break; + case CLI_MSG_COMM_ERROR: + *successMsg = FALSE; + msg = gText_CommunicationError; + break; + case CLI_MSG_TRAINER_RECEIVED: + *successMsg = TRUE; + msg = gText_NewTrainerReceived; + break; + case CLI_MSG_BUFFER_SUCCESS: + *successMsg = TRUE; + // msg is NULL, use buffer + break; + case CLI_MSG_BUFFER_FAILURE: + *successMsg = FALSE; + // msg is NULL, use buffer + break; + } + + return msg; +} + +static bool32 PrintSuccessMessage(u8 * state, const u8 * msg, u16 * timer) +{ + switch (*state) + { + case 0: + if (msg != NULL) + AddTextPrinterToWindow1(msg); + PlayFanfare(MUS_OBTAIN_ITEM); + *timer = 0; + (*state)++; + break; + case 1: + if (++(*timer) > 240) + (*state)++; + break; + case 2: + if (IsFanfareTaskInactive()) + { + *state = 0; + ClearTextWindow(); + return TRUE; + } + break; + } + return FALSE; +} + +static const u8 * GetServerResultMessage(bool32 * wonderSuccess, bool8 sourceIsFriend, u32 msgId) +{ + const u8 * result = gText_CommunicationError; + *wonderSuccess = FALSE; + switch (msgId) + { + case SVR_MSG_NOTHING_SENT: + result = gText_NothingSentOver; + break; + case SVR_MSG_RECORD_UPLOADED: + result = gText_RecordUploadedViaWireless; + break; + case SVR_MSG_CARD_SENT: + result = gText_WonderCardSentTo; + *wonderSuccess = TRUE; + break; + case SVR_MSG_NEWS_SENT: + result = gText_WonderNewsSentTo; + *wonderSuccess = TRUE; + break; + case SVR_MSG_STAMP_SENT: + result = gText_StampSentTo; + break; + case SVR_MSG_HAS_CARD: + result = gText_OtherTrainerHasCard; + break; + case SVR_MSG_HAS_STAMP: + result = gText_OtherTrainerHasStamp; + break; + case SVR_MSG_HAS_NEWS: + result = gText_OtherTrainerHasNews; + break; + case SVR_MSG_NO_ROOM_STAMPS: + result = gText_NoMoreRoomForStamps; + break; + case SVR_MSG_CLIENT_CANCELED: + result = gText_OtherTrainerCanceled; + break; + case SVR_MSG_CANT_SEND_GIFT_1: + result = gText_CantSendGiftToTrainer; + break; + case SVR_MSG_COMM_ERROR: + result = gText_CommunicationError; + break; + case SVR_MSG_GIFT_SENT_1: + result = gText_GiftSentTo; + break; + case SVR_MSG_GIFT_SENT_2: + result = gText_GiftSentTo; + break; + case SVR_MSG_CANT_SEND_GIFT_2: + result = gText_CantSendGiftToTrainer; + break; + } + return result; +} + +static bool32 PrintServerResultMessage(u8 * state, u16 * timer, bool8 sourceIsFriend, u32 msgId) +{ + bool32 wonderSuccess; + const u8 * str = GetServerResultMessage(&wonderSuccess, sourceIsFriend, msgId); + if (wonderSuccess) + return PrintSuccessMessage(state, str, timer); + else + return PrintMysteryGiftMenuMessage(state, str); +} + +// States for Task_MysteryGift. +// CLIENT states are for when the player is receiving a gift, and use mystery_gift_client.c link functions. +// SERVER states are for when the player is sending a gift, and use mystery_gift_server.c link functions. +// Other states handle the general Mystery Gift menu usage. +enum { + MG_STATE_TO_MAIN_MENU, + MG_STATE_MAIN_MENU, + MG_STATE_DONT_HAVE_ANY, + MG_STATE_SOURCE_PROMPT, + MG_STATE_SOURCE_PROMPT_INPUT, + MG_STATE_CLIENT_LINK_START, + MG_STATE_CLIENT_LINK_WAIT, + MG_STATE_CLIENT_COMMUNICATING, + MG_STATE_CLIENT_LINK, + MG_STATE_CLIENT_YES_NO, + MG_STATE_CLIENT_MESSAGE, + MG_STATE_CLIENT_ASK_TOSS, + MG_STATE_CLIENT_ASK_TOSS_UNRECEIVED, + MG_STATE_CLIENT_LINK_END, + MG_STATE_CLIENT_COMM_COMPLETED, + MG_STATE_CLIENT_RESULT_MSG, + MG_STATE_CLIENT_ERROR, + MG_STATE_SAVE_LOAD_GIFT, + MG_STATE_LOAD_GIFT, + MG_STATE_UNUSED, + MG_STATE_HANDLE_GIFT_INPUT, + MG_STATE_HANDLE_GIFT_SELECT, + MG_STATE_ASK_TOSS, + MG_STATE_ASK_TOSS_UNRECEIVED, + MG_STATE_TOSS, + MG_STATE_TOSS_SAVE, + MG_STATE_TOSSED, + MG_STATE_GIFT_INPUT_EXIT, + MG_STATE_RECEIVE, + MG_STATE_SEND, + MG_STATE_SERVER_LINK_WAIT, + MG_STATE_SERVER_LINK_START, + MG_STATE_SERVER_LINK, + MG_STATE_SERVER_LINK_END, + MG_STATE_SERVER_LINK_END_WAIT, + MG_STATE_SERVER_RESULT_MSG, + MG_STATE_SERVER_ERROR, + MG_STATE_EXIT, +}; + +static void CreateMysteryGiftTask(void) +{ + u8 taskId = CreateTask(Task_MysteryGift, 0); + struct MysteryGiftTaskData * data = (void *)gTasks[taskId].data; + data->state = MG_STATE_TO_MAIN_MENU; + data->textState = 0; + data->unused4 = 0; + data->unused5 = 0; + data->isWonderNews = 0; + data->sourceIsFriend = 0; + data->var = 0; + data->unused1 = 0; + data->unused2 = 0; + data->unused3 = 0; + data->msgId = 0; + data->clientMsg = AllocZeroed(CLIENT_MAX_MSG_SIZE); +} + +static void Task_MysteryGift(u8 taskId) +{ + struct MysteryGiftTaskData *data = (void *)gTasks[taskId].data; + u32 successMsg, input; + const u8 *msg; + + switch (data->state) + { + case MG_STATE_TO_MAIN_MENU: + data->state = MG_STATE_MAIN_MENU; + break; + case MG_STATE_MAIN_MENU: + // Main Mystery Gift menu, player can select Wonder Cards or News (or exit) + switch (MysteryGift_HandleThreeOptionMenu(&data->textState, &data->var, FALSE)) + { + case 0: // "Wonder Cards" + data->isWonderNews = FALSE; + if (ValidateSavedWonderCard() == TRUE) + data->state = MG_STATE_LOAD_GIFT; + else + data->state = MG_STATE_DONT_HAVE_ANY; + break; + case 1: // "Wonder News" + data->isWonderNews = TRUE; + if (ValidateSavedWonderNews() == TRUE) + data->state = MG_STATE_LOAD_GIFT; + else + data->state = MG_STATE_DONT_HAVE_ANY; + break; + case LIST_CANCEL: + data->state = MG_STATE_EXIT; + break; + } + break; + case MG_STATE_DONT_HAVE_ANY: + { + // Player doesn't have any Wonder Card/News + // Start prompt to ask where to read one from + if (!data->isWonderNews) + { + if (PrintMysteryGiftMenuMessage(&data->textState, gText_DontHaveCardNewOneInput)) + { + data->state = MG_STATE_SOURCE_PROMPT; + PrintMysteryGiftOrEReaderTopMenu(FALSE, TRUE); + } + } + else + { + if (PrintMysteryGiftMenuMessage(&data->textState, gText_DontHaveNewsNewOneInput)) + { + data->state = MG_STATE_SOURCE_PROMPT; + PrintMysteryGiftOrEReaderTopMenu(FALSE, TRUE); + } + } + break; + } + case MG_STATE_SOURCE_PROMPT: + if (!data->isWonderNews) + AddTextPrinterToWindow1(gText_WhereShouldCardBeAccessed); + else + AddTextPrinterToWindow1(gText_WhereShouldNewsBeAccessed); + data->state = MG_STATE_SOURCE_PROMPT_INPUT; + break; + case MG_STATE_SOURCE_PROMPT_INPUT: + // Choose where to access the Wonder Card/News from + switch (MysteryGift_HandleThreeOptionMenu(&data->textState, &data->var, TRUE)) + { + case 0: // "Wireless Communication" + ClearTextWindow(); + data->state = MG_STATE_CLIENT_LINK_START; + data->sourceIsFriend = FALSE; + break; + case 1: // "Friend" + ClearTextWindow(); + data->state = MG_STATE_CLIENT_LINK_START; + data->sourceIsFriend = TRUE; + break; + case LIST_CANCEL: + ClearTextWindow(); + if (ValidateCardOrNews(data->isWonderNews)) + { + data->state = MG_STATE_LOAD_GIFT; + } + else + { + data->state = MG_STATE_TO_MAIN_MENU; + PrintMysteryGiftOrEReaderTopMenu(FALSE, FALSE); + } + break; + } + break; + case MG_STATE_CLIENT_LINK_START: + *gStringVar1 = EOS; + *gStringVar2 = EOS; + *gStringVar3 = EOS; + + switch (data->isWonderNews) + { + case FALSE: + if (data->sourceIsFriend == TRUE) + CreateTask_LinkMysteryGiftWithFriend(ACTIVITY_WONDER_CARD); + else if (data->sourceIsFriend == FALSE) + CreateTask_LinkMysteryGiftOverWireless(ACTIVITY_WONDER_CARD); + break; + case TRUE: + if (data->sourceIsFriend == TRUE) + CreateTask_LinkMysteryGiftWithFriend(ACTIVITY_WONDER_NEWS); + else if (data->sourceIsFriend == FALSE) + CreateTask_LinkMysteryGiftOverWireless(ACTIVITY_WONDER_NEWS); + break; + } + data->state = MG_STATE_CLIENT_LINK_WAIT; + break; + case MG_STATE_CLIENT_LINK_WAIT: + if (gReceivedRemoteLinkPlayers != 0) + { + ClearScreenInBg0(TRUE); + data->state = MG_STATE_CLIENT_COMMUNICATING; + MysteryGiftClient_Create(data->isWonderNews); + } + else if (gSpecialVar_Result == LINKUP_FAILED) + { + // Link failed, return to link start menu + ClearScreenInBg0(TRUE); + data->state = MG_STATE_SOURCE_PROMPT; + } + break; + case MG_STATE_CLIENT_COMMUNICATING: + AddTextPrinterToWindow1(gText_Communicating); + data->state = MG_STATE_CLIENT_LINK; + break; + case MG_STATE_CLIENT_LINK: + switch (MysteryGiftClient_Run(&data->var)) + { + case CLI_RET_END: + Rfu_SetCloseLinkCallback(); + data->msgId = data->var; + data->state = MG_STATE_CLIENT_LINK_END; + break; + case CLI_RET_COPY_MSG: + memcpy(data->clientMsg, MysteryGiftClient_GetMsg(), 0x40); + MysteryGiftClient_AdvanceState(); + break; + case CLI_RET_PRINT_MSG: + data->state = MG_STATE_CLIENT_MESSAGE; + break; + case CLI_RET_YES_NO: + data->state = MG_STATE_CLIENT_YES_NO; + break; + case CLI_RET_ASK_TOSS: + data->state = MG_STATE_CLIENT_ASK_TOSS; + StringCopy(gStringVar1, gLinkPlayers[0].name); + break; + } + break; + case MG_STATE_CLIENT_YES_NO: + input = DoMysteryGiftYesNo(&data->textState, &data->var, FALSE, MysteryGiftClient_GetMsg()); + switch (input) + { + case 0: // Yes + MysteryGiftClient_SetParam(FALSE); + MysteryGiftClient_AdvanceState(); + data->state = MG_STATE_CLIENT_COMMUNICATING; + break; + case 1: // No + case MENU_B_PRESSED: + MysteryGiftClient_SetParam(TRUE); + MysteryGiftClient_AdvanceState(); + data->state = MG_STATE_CLIENT_COMMUNICATING; + break; + } + break; + case MG_STATE_CLIENT_MESSAGE: + if (PrintMysteryGiftMenuMessage(&data->textState, MysteryGiftClient_GetMsg())) + { + MysteryGiftClient_AdvanceState(); + data->state = MG_STATE_CLIENT_COMMUNICATING; + } + break; + case MG_STATE_CLIENT_ASK_TOSS: + // Player is receiving a new Wonder Card/News but needs to toss an existing one to make room. + // Ask for confirmation. + input = DoMysteryGiftYesNo(&data->textState, &data->var, FALSE, gText_ThrowAwayWonderCard); + switch (input) + { + case 0: // Yes + if (IsSavedWonderCardGiftNotReceived() == TRUE) + { + data->state = MG_STATE_CLIENT_ASK_TOSS_UNRECEIVED; + } + else + { + MysteryGiftClient_SetParam(FALSE); + MysteryGiftClient_AdvanceState(); + data->state = MG_STATE_CLIENT_COMMUNICATING; + } + break; + case 1: // No + case MENU_B_PRESSED: + MysteryGiftClient_SetParam(TRUE); + MysteryGiftClient_AdvanceState(); + data->state = MG_STATE_CLIENT_COMMUNICATING; + break; + } + break; + case MG_STATE_CLIENT_ASK_TOSS_UNRECEIVED: + // Player has selected to toss a Wonder Card that they haven't received the gift for. + // Ask for confirmation again. + input = DoMysteryGiftYesNo(&data->textState, &data->var, FALSE, gText_HaventReceivedCardsGift); + switch (input) + { + case 0: // Yes + MysteryGiftClient_SetParam(FALSE); + MysteryGiftClient_AdvanceState(); + data->state = MG_STATE_CLIENT_COMMUNICATING; + break; + case 1: // No + case MENU_B_PRESSED: + MysteryGiftClient_SetParam(TRUE); + MysteryGiftClient_AdvanceState(); + data->state = MG_STATE_CLIENT_COMMUNICATING; + break; + } + break; + case MG_STATE_CLIENT_LINK_END: + if (gReceivedRemoteLinkPlayers == 0) + { + DestroyWirelessStatusIndicatorSprite(); + data->state = MG_STATE_CLIENT_COMM_COMPLETED; + } + break; + case MG_STATE_CLIENT_COMM_COMPLETED: + if (PrintStringAndWait2Seconds(&data->textState, gText_CommunicationCompleted)) + { + if (data->sourceIsFriend == TRUE) + StringCopy(gStringVar1, gLinkPlayers[0].name); + data->state = MG_STATE_CLIENT_RESULT_MSG; + } + break; + case MG_STATE_CLIENT_RESULT_MSG: + msg = GetClientResultMessage(&successMsg, data->isWonderNews, data->sourceIsFriend, data->msgId); + if (msg == NULL) + msg = data->clientMsg; + if (successMsg) + input = PrintSuccessMessage(&data->textState, msg, &data->var); + else + input = PrintMysteryGiftMenuMessage(&data->textState, msg); + // input var re-used, here it is TRUE if the message is finished + if (input) + { + if (data->msgId == CLI_MSG_NEWS_RECEIVED) + { + if (data->sourceIsFriend == TRUE) + GenerateRandomWonderNews(WONDER_NEWS_RECV_FRIEND); + else + GenerateRandomWonderNews(WONDER_NEWS_RECV_WIRELESS); + } + if (!successMsg) + { + // Did not receive card/news, return to main menu + data->state = MG_STATE_TO_MAIN_MENU; + PrintMysteryGiftOrEReaderTopMenu(FALSE, FALSE); + } + else + { + data->state = MG_STATE_SAVE_LOAD_GIFT; + } + } + break; + case MG_STATE_SAVE_LOAD_GIFT: + if (SaveOnMysteryGiftMenu(&data->textState)) + data->state = MG_STATE_LOAD_GIFT; + break; + case MG_STATE_LOAD_GIFT: + if (HandleLoadWonderCardOrNews(&data->textState, data->isWonderNews)) + data->state = MG_STATE_HANDLE_GIFT_INPUT; + break; + case MG_STATE_HANDLE_GIFT_INPUT: + if (!data->isWonderNews) + { + // Handle Wonder Card input + if (JOY_NEW(A_BUTTON)) + data->state = MG_STATE_HANDLE_GIFT_SELECT; + if (JOY_NEW(B_BUTTON)) + data->state = MG_STATE_GIFT_INPUT_EXIT; + } + else + { + switch (WonderNews_GetInput(gMain.newKeys)) + { + case NEWS_INPUT_A: + WonderNews_RemoveScrollIndicatorArrowPair(); + data->state = MG_STATE_HANDLE_GIFT_SELECT; + break; + case NEWS_INPUT_B: + data->state = MG_STATE_GIFT_INPUT_EXIT; + break; + } + } + break; + case MG_STATE_HANDLE_GIFT_SELECT: + { + // A Wonder Card/News has been selected, handle its menu + u32 result; + if (!data->isWonderNews) + { + if (IsSendingSavedWonderCardAllowed()) + result = HandleGiftSelectMenu(&data->textState, &data->var, data->isWonderNews, FALSE); + else + result = HandleGiftSelectMenu(&data->textState, &data->var, data->isWonderNews, TRUE); + } + else + { + if (IsSendingSavedWonderNewsAllowed()) + result = HandleGiftSelectMenu(&data->textState, &data->var, data->isWonderNews, FALSE); + else + result = HandleGiftSelectMenu(&data->textState, &data->var, data->isWonderNews, TRUE); + } + switch (result) + { + case 0: // Receive + data->state = MG_STATE_RECEIVE; + break; + case 1: // Send + data->state = MG_STATE_SEND; + break; + case 2: // Toss + data->state = MG_STATE_ASK_TOSS; + break; + case LIST_CANCEL: + if (data->isWonderNews == TRUE) + WonderNews_AddScrollIndicatorArrowPair(); + data->state = MG_STATE_HANDLE_GIFT_INPUT; + break; + } + break; + } + case MG_STATE_ASK_TOSS: + // Player is attempting to discard a saved Wonder Card/News + switch (AskDiscardGift(&data->textState, &data->var, data->isWonderNews)) + { + case 0: // Yes + if (!data->isWonderNews && IsSavedWonderCardGiftNotReceived() == TRUE) + data->state = MG_STATE_ASK_TOSS_UNRECEIVED; + else + data->state = MG_STATE_TOSS; + break; + case 1: // No + case MENU_B_PRESSED: + data->state = MG_STATE_HANDLE_GIFT_SELECT; + break; + } + break; + case MG_STATE_ASK_TOSS_UNRECEIVED: + // Player has selected to toss a Wonder Card that they haven't received the gift for. + // Ask for confirmation again. + switch ((u32)DoMysteryGiftYesNo(&data->textState, &data->var, TRUE, gText_HaventReceivedGiftOkayToDiscard)) + { + case 0: // Yes + data->state = MG_STATE_TOSS; + break; + case 1: // No + case MENU_B_PRESSED: + data->state = MG_STATE_HANDLE_GIFT_SELECT; + break; + } + break; + case MG_STATE_TOSS: + if (ExitWonderCardOrNews(data->isWonderNews, TRUE)) + { + ClearSavedNewsOrCard(data->isWonderNews); + data->state = MG_STATE_TOSS_SAVE; + } + break; + case MG_STATE_TOSS_SAVE: + if (SaveOnMysteryGiftMenu(&data->textState)) + data->state = MG_STATE_TOSSED; + break; + case MG_STATE_TOSSED: + if (PrintThrownAway(&data->textState, data->isWonderNews)) + { + data->state = MG_STATE_TO_MAIN_MENU; + PrintMysteryGiftOrEReaderTopMenu(FALSE, FALSE); + } + break; + case MG_STATE_GIFT_INPUT_EXIT: + if (ExitWonderCardOrNews(data->isWonderNews, FALSE)) + data->state = MG_STATE_TO_MAIN_MENU; + break; + case MG_STATE_RECEIVE: + if (ExitWonderCardOrNews(data->isWonderNews, TRUE)) + data->state = MG_STATE_SOURCE_PROMPT; + break; + case MG_STATE_SEND: + if (ExitWonderCardOrNews(data->isWonderNews, TRUE)) + { + switch (data->isWonderNews) + { + case FALSE: + CreateTask_SendMysteryGift(ACTIVITY_WONDER_CARD); + break; + case TRUE: + CreateTask_SendMysteryGift(ACTIVITY_WONDER_NEWS); + break; + } + data->sourceIsFriend = TRUE; + data->state = MG_STATE_SERVER_LINK_WAIT; + } + break; + case MG_STATE_SERVER_LINK_WAIT: + if (gReceivedRemoteLinkPlayers != 0) + { + ClearScreenInBg0(TRUE); + data->state = MG_STATE_SERVER_LINK_START; + } + else if (gSpecialVar_Result == LINKUP_FAILED) + { + ClearScreenInBg0(TRUE); + data->state = MG_STATE_LOAD_GIFT; + } + break; + case MG_STATE_SERVER_LINK_START: + *gStringVar1 = EOS; + *gStringVar2 = EOS; + *gStringVar3 = EOS; + + if (!data->isWonderNews) + { + AddTextPrinterToWindow1(gText_SendingWonderCard); + MysterGiftServer_CreateForCard(); + } + else + { + AddTextPrinterToWindow1(gText_SendingWonderNews); + MysterGiftServer_CreateForNews(); + } + data->state = MG_STATE_SERVER_LINK; + break; + case MG_STATE_SERVER_LINK: + if (MysterGiftServer_Run(&data->var) == SVR_RET_END) + { + data->msgId = data->var; + data->state = MG_STATE_SERVER_LINK_END; + } + break; + case MG_STATE_SERVER_LINK_END: + Rfu_SetCloseLinkCallback(); + StringCopy(gStringVar1, gLinkPlayers[1].name); + data->state = MG_STATE_SERVER_LINK_END_WAIT; + break; + case MG_STATE_SERVER_LINK_END_WAIT: + if (gReceivedRemoteLinkPlayers == 0) + { + DestroyWirelessStatusIndicatorSprite(); + data->state = MG_STATE_SERVER_RESULT_MSG; + } + break; + case MG_STATE_SERVER_RESULT_MSG: + if (PrintServerResultMessage(&data->textState, &data->var, data->sourceIsFriend, data->msgId)) + { + if (data->sourceIsFriend == TRUE && data->msgId == SVR_MSG_NEWS_SENT) + { + GenerateRandomWonderNews(WONDER_NEWS_SENT); + data->state = MG_STATE_SAVE_LOAD_GIFT; + } + else + { + data->state = MG_STATE_TO_MAIN_MENU; + PrintMysteryGiftOrEReaderTopMenu(FALSE, FALSE); + } + } + break; + case MG_STATE_CLIENT_ERROR: + case MG_STATE_SERVER_ERROR: + if (PrintMysteryGiftMenuMessage(&data->textState, gText_CommunicationError)) + { + data->state = MG_STATE_TO_MAIN_MENU; + PrintMysteryGiftOrEReaderTopMenu(FALSE, FALSE); + } + break; + case MG_STATE_EXIT: + CloseLink(); + Free(data->clientMsg); + DestroyTask(taskId); + SetMainCallback2(MainCB_FreeAllBuffersAndReturnToInitTitleScreen); + break; + } +} + +u16 GetMysteryGiftBaseBlock(void) +{ + return 0x1A9; +} + +static void LoadMysteryGiftTextboxBorder(u8 bgId) +{ + DecompressAndLoadBgGfxUsingHeap(bgId, sTextboxBorder_Gfx, 0x100, 0, 0); +} diff --git a/src/mystery_gift_scripts.c b/src/mystery_gift_scripts.c new file mode 100644 index 000000000..fcd7f568d --- /dev/null +++ b/src/mystery_gift_scripts.c @@ -0,0 +1,217 @@ +#include "global.h" +#include "mystery_gift_client.h" +#include "mystery_gift_server.h" +#include "mystery_gift.h" + +static const u8 sText_CanceledReadingCard[] = _("Canceled reading\nthe Card."); + + +//================== +// Client scripts +//================== + +const struct MysteryGiftClientCmd gMysteryGiftClientScript_Init[] = { + {CLI_RECV, MG_LINKID_CLIENT_SCRIPT}, + {CLI_COPY_RECV} +}; + +static const struct MysteryGiftClientCmd sClientScript_SendGameData[] = { + {CLI_LOAD_GAME_DATA}, + {CLI_SEND_LOADED}, + {CLI_RECV, MG_LINKID_CLIENT_SCRIPT}, + {CLI_COPY_RECV} +}; + +static const struct MysteryGiftClientCmd sClientScript_CantAccept[] = { + {CLI_SEND_READY_END}, + {CLI_RETURN, CLI_MSG_CANT_ACCEPT} +}; + +static const struct MysteryGiftClientCmd sClientScript_CommError[] = { + {CLI_SEND_READY_END}, + {CLI_RETURN, CLI_MSG_COMM_ERROR} +}; + +static const struct MysteryGiftClientCmd sClientScript_NothingSent[] = { + {CLI_SEND_READY_END}, + {CLI_RETURN, CLI_MSG_NOTHING_SENT} +}; + +static const struct MysteryGiftClientCmd sClientScript_SaveCard[] = { + {CLI_RECV, MG_LINKID_CARD}, + {CLI_SAVE_CARD}, + {CLI_RECV, MG_LINKID_RAM_SCRIPT}, + {CLI_SAVE_RAM_SCRIPT}, + {CLI_SEND_READY_END}, + {CLI_RETURN, CLI_MSG_CARD_RECEIVED} +}; + +static const struct MysteryGiftClientCmd sClientScript_SaveNews[] = { + {CLI_RECV, MG_LINKID_NEWS}, + {CLI_SAVE_NEWS}, + {CLI_SEND_LOADED}, // Send whether or not the News was saved (read by sServerScript_SendNews) + {CLI_RECV, MG_LINKID_CLIENT_SCRIPT}, + {CLI_COPY_RECV} +}; + +static const struct MysteryGiftClientCmd sClientScript_HadNews[] = { + {CLI_SEND_READY_END}, + {CLI_RETURN, CLI_MSG_HAD_NEWS} +}; + +static const struct MysteryGiftClientCmd sClientScript_NewsReceived[] = { + {CLI_SEND_READY_END}, + {CLI_RETURN, CLI_MSG_NEWS_RECEIVED} +}; + +static const struct MysteryGiftClientCmd sClientScript_AskToss[] = { + {CLI_ASK_TOSS}, + {CLI_LOAD_TOSS_RESPONSE}, + {CLI_SEND_LOADED}, + {CLI_RECV, MG_LINKID_CLIENT_SCRIPT}, + {CLI_COPY_RECV} +}; + +static const struct MysteryGiftClientCmd sClientScript_Canceled[] = { + {CLI_SEND_READY_END}, + {CLI_RETURN, CLI_MSG_COMM_CANCELED} +}; + +static const struct MysteryGiftClientCmd sClientScript_HadCard[] = { + {CLI_SEND_READY_END}, + {CLI_RETURN, CLI_MSG_HAD_CARD} +}; + +static const struct MysteryGiftClientCmd sClientScript_DynamicError[] = { + {CLI_RECV, MG_LINKID_DYNAMIC_MSG}, + {CLI_COPY_MSG}, + {CLI_SEND_READY_END}, + {CLI_RETURN, CLI_MSG_BUFFER_FAILURE} +}; + +static const struct MysteryGiftClientCmd sClientScript_DynamicSuccess[] = { + {CLI_RECV, MG_LINKID_DYNAMIC_MSG}, + {CLI_COPY_MSG}, + {CLI_SEND_READY_END}, + {CLI_RETURN, CLI_MSG_BUFFER_SUCCESS} +}; + + +//================== +// Server scripts +//================== + +// Create arguments for SVR_LOAD_CLIENT_SCRIPT or SVR_LOAD_MSG +// (a script/text size and pointer to send to the client) +#define PTR_ARG(pointer) .parameter = sizeof(pointer), .ptr = pointer + +static const struct MysteryGiftServerCmd sServerScript_CantSend[] = { + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_CantAccept)}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_READY_END}, + {SVR_RETURN, SVR_MSG_CANT_SEND_GIFT_1} +}; + +static const struct MysteryGiftServerCmd sServerScript_CommError[] = { + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_CommError)}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_READY_END}, + {SVR_RETURN, SVR_MSG_COMM_ERROR} +}; + +static const struct MysteryGiftServerCmd sServerScript_ClientCanceledNews[] = { + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_Canceled)}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_READY_END}, + {SVR_RETURN, SVR_MSG_CLIENT_CANCELED} +}; + +static const struct MysteryGiftServerCmd sServerScript_ClientCanceledCard[] = { + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_DynamicError)}, + {SVR_SEND}, + {SVR_LOAD_MSG, PTR_ARG(sText_CanceledReadingCard)}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_READY_END}, + {SVR_RETURN, SVR_MSG_CLIENT_CANCELED} +}; + +static const struct MysteryGiftServerCmd sServerScript_HasNews[] = { + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_HadNews)}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_READY_END}, + {SVR_RETURN, SVR_MSG_HAS_NEWS} +}; + +static const struct MysteryGiftServerCmd sServerScript_SendNews[] = { + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_SaveNews)}, + {SVR_SEND}, + {SVR_LOAD_NEWS}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_RESPONSE}, + {SVR_READ_RESPONSE}, + {SVR_GOTO_IF_EQ, TRUE, sServerScript_HasNews}, // Wonder News was not saved + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_NewsReceived)}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_READY_END}, + {SVR_RETURN, SVR_MSG_NEWS_SENT} +}; + +static const struct MysteryGiftServerCmd sServerScript_SendCard[] = { + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_SaveCard)}, + {SVR_SEND}, + {SVR_LOAD_CARD}, + {SVR_SEND}, + {SVR_LOAD_RAM_SCRIPT}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_READY_END}, + {SVR_RETURN, SVR_MSG_CARD_SENT} +}; + +static const struct MysteryGiftServerCmd sServerScript_TossPrompt[] = { + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_AskToss)}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_RESPONSE}, + {SVR_READ_RESPONSE}, + {SVR_GOTO_IF_EQ, FALSE, sServerScript_SendCard}, // Tossed old card, send new one + {SVR_GOTO, .ptr = sServerScript_ClientCanceledCard} // Kept old card, cancel new one +}; + +static const struct MysteryGiftServerCmd sServerScript_HasCard[] = { + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_HadCard)}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_READY_END}, + {SVR_RETURN, SVR_MSG_HAS_CARD} +}; + +static const struct MysteryGiftServerCmd sServerScript_NothingSent[] = { + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_NothingSent)}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_READY_END}, + {SVR_RETURN, SVR_MSG_NOTHING_SENT} +}; + +const struct MysteryGiftServerCmd gMysteryGiftServerScript_SendWonderNews[] = { + {SVR_COPY_SAVED_NEWS}, + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_SendGameData)}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_GAME_DATA}, + {SVR_COPY_GAME_DATA}, + {SVR_CHECK_GAME_DATA_NEWS}, + {SVR_GOTO_IF_EQ, FALSE, sServerScript_CantSend}, + {SVR_GOTO, .ptr = sServerScript_SendNews} +}; + +const struct MysteryGiftServerCmd gMysteryGiftServerScript_SendWonderCard[] = { + {SVR_COPY_SAVED_CARD}, + {SVR_COPY_SAVED_RAM_SCRIPT}, + {SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_SendGameData)}, + {SVR_SEND}, + {SVR_RECV, MG_LINKID_GAME_DATA}, + {SVR_COPY_GAME_DATA}, + {SVR_CHECK_GAME_DATA_CARD}, + {SVR_GOTO_IF_EQ, FALSE, sServerScript_CantSend}, + {SVR_CHECK_EXISTING_CARD}, + {SVR_GOTO_IF_EQ, HAS_DIFF_CARD, sServerScript_TossPrompt}, + {SVR_GOTO_IF_EQ, HAS_NO_CARD, sServerScript_SendCard}, + {SVR_GOTO, .ptr = sServerScript_HasCard} // HAS_SAME_CARD +}; diff --git a/src/mystery_gift_server.c b/src/mystery_gift_server.c new file mode 100644 index 000000000..0e0acb642 --- /dev/null +++ b/src/mystery_gift_server.c @@ -0,0 +1,291 @@ +#include "global.h" +#include "malloc.h" +#include "script.h" +#include "mystery_gift.h" +#include "mystery_gift_server.h" +#include "mystery_gift_link.h" + +enum { + FUNC_INIT, + FUNC_DONE, + FUNC_RECV, + FUNC_SEND, + FUNC_RUN, +}; + +EWRAM_DATA static struct MysteryGiftServer * sServer = NULL; + +static void MysteryGiftServer_Init(struct MysteryGiftServer *, const void *, u32, u32); +static void MysteryGiftServer_Free(struct MysteryGiftServer *); +static u32 MysteryGiftServer_CallFunc(struct MysteryGiftServer *); + +extern const struct MysteryGiftServerCmd gMysteryGiftServerScript_SendWonderNews[]; +extern const struct MysteryGiftServerCmd gMysteryGiftServerScript_SendWonderCard[]; + +void MysterGiftServer_CreateForNews(void) +{ + sServer = AllocZeroed(sizeof(*sServer)); + MysteryGiftServer_Init(sServer, gMysteryGiftServerScript_SendWonderNews, 0, 1); +} + +void MysterGiftServer_CreateForCard(void) +{ + sServer = AllocZeroed(sizeof(*sServer)); + MysteryGiftServer_Init(sServer, gMysteryGiftServerScript_SendWonderCard, 0, 1); +} + +u32 MysterGiftServer_Run(u16 * endVal) +{ + u32 result; + if (sServer == NULL) + return SVR_RET_END; + result = MysteryGiftServer_CallFunc(sServer); + if (result == SVR_RET_END) + { + *endVal = sServer->param; + MysteryGiftServer_Free(sServer); + Free(sServer); + sServer = NULL; + } + return result; +} + +static void MysteryGiftServer_Init(struct MysteryGiftServer * svr, const void * script, u32 sendPlayerId, u32 recvPlayerId) +{ + svr->unused = 0; + svr->funcId = FUNC_INIT; + svr->card = AllocZeroed(sizeof(*svr->card)); + svr->news = AllocZeroed(sizeof(*svr->news)); + svr->recvBuffer = AllocZeroed(MG_LINK_BUFFER_SIZE); + svr->linkGameData = AllocZeroed(sizeof(*svr->linkGameData)); + svr->script = script; + svr->cmdidx = 0; + MysteryGiftLink_Init(&svr->link, sendPlayerId, recvPlayerId); +} + +static void MysteryGiftServer_Free(struct MysteryGiftServer * svr) +{ + Free(svr->card); + Free(svr->news); + Free(svr->recvBuffer); + Free(svr->linkGameData); +} + +static void MysteryGiftServer_InitSend(struct MysteryGiftServer * svr, u32 ident, const void * src, u32 size) +{ + AGB_ASSERT(size <= MG_LINK_BUFFER_SIZE); + MysteryGiftLink_InitSend(&svr->link, ident, src, size); +} + +// Given the command pointer parameter and the 'default' normal data. +// If the command's pointer is not empty use that as the send data, otherwise use the default. +static const void * MysteryGiftServer_GetSendData(const void * dynamicData, const void * defaultData) +{ + if (dynamicData != NULL) + return dynamicData; + else + return defaultData; +} + +static u32 MysteryGiftServer_Compare(const void * a, const void * b) +{ + if (b < a) + return 0; + else if (b == a) + return 1; + else + return 2; +} + +static u32 Server_Init(struct MysteryGiftServer * svr) +{ + svr->funcId = FUNC_RUN; + return SVR_RET_INIT; +} + +static u32 Server_Done(struct MysteryGiftServer * svr) +{ + return SVR_RET_END; +} + +static u32 Server_Recv(struct MysteryGiftServer * svr) +{ + if (MysteryGiftLink_Recv(&svr->link)) + svr->funcId = FUNC_RUN; + return SVR_RET_ACTIVE; +} + +static u32 Server_Send(struct MysteryGiftServer * svr) +{ + if (MysteryGiftLink_Send(&svr->link)) + svr->funcId = FUNC_RUN; + return SVR_RET_ACTIVE; +} + +static u32 Server_Run(struct MysteryGiftServer * svr) +{ + // process command + const struct MysteryGiftServerCmd * cmd = &svr->script[svr->cmdidx]; + const void * ptr; + svr->cmdidx++; + + switch (cmd->instr) + { + case SVR_RETURN: + AGB_ASSERT(cmd->ptr == NULL); + svr->funcId = FUNC_DONE; + svr->param = cmd->parameter; // Set for endVal in MysteryGiftServer_Run + break; + case SVR_SEND: + svr->funcId = FUNC_SEND; + break; + case SVR_RECV: + AGB_ASSERT(cmd->ptr == NULL); + MysteryGiftLink_InitRecv(&svr->link, cmd->parameter, svr->recvBuffer); + svr->funcId = FUNC_RECV; + break; + case SVR_GOTO: + AGB_ASSERT(cmd->parameter == 0); + svr->cmdidx = 0; + svr->script = cmd->ptr; + break; + case SVR_COPY_GAME_DATA: + AGB_ASSERT(cmd->parameter == 0); + AGB_ASSERT(cmd->ptr == NULL); + memcpy(svr->linkGameData, svr->recvBuffer, sizeof(*svr->linkGameData)); + break; + case SVR_CHECK_GAME_DATA_CARD: + AGB_ASSERT(cmd->parameter == 0); + AGB_ASSERT(cmd->ptr == NULL); + svr->param = MysteryGift_ValidateLinkGameData(svr->linkGameData, FALSE); + break; + case SVR_CHECK_GAME_DATA_NEWS: + AGB_ASSERT(cmd->parameter == 0); + AGB_ASSERT(cmd->ptr == NULL); + svr->param = MysteryGift_ValidateLinkGameData(svr->linkGameData, TRUE); + break; + case SVR_GOTO_IF_EQ: + if (svr->param == cmd->parameter) + { + svr->cmdidx = 0; + svr->script = cmd->ptr; + } + break; + case SVR_CHECK_EXISTING_CARD: + AGB_ASSERT(cmd->parameter == 0); + ptr = MysteryGiftServer_GetSendData(cmd->ptr, svr->card); + svr->param = MysteryGift_CompareCardFlags(ptr, svr->linkGameData, ptr); + break; + case SVR_READ_RESPONSE: + AGB_ASSERT(cmd->parameter == 0); + AGB_ASSERT(cmd->ptr == NULL); + svr->param = *(u32 *)svr->recvBuffer; + break; + case SVR_CHECK_EXISTING_STAMPS: + AGB_ASSERT(cmd->parameter == 0); + ptr = MysteryGiftServer_GetSendData(cmd->ptr, &svr->stamp); + svr->param = MysteryGift_CheckStamps(ptr, svr->linkGameData, ptr); + break; + case SVR_GET_CARD_STAT: + AGB_ASSERT(cmd->ptr == NULL); + svr->param = MysteryGift_GetCardStatFromLinkData(svr->linkGameData, cmd->parameter); + break; + case SVR_CHECK_QUESTIONNAIRE: + AGB_ASSERT(cmd->parameter == 0); + svr->param = MysteryGift_DoesQuestionnaireMatch(svr->linkGameData, cmd->ptr); + break; + case SVR_COMPARE: + AGB_ASSERT(cmd->parameter == 0); + svr->param = MysteryGiftServer_Compare(cmd->ptr, *(void **)svr->recvBuffer); + break; + case SVR_LOAD_NEWS: + AGB_ASSERT(cmd->parameter == 0); + MysteryGiftServer_InitSend(svr, MG_LINKID_NEWS, MysteryGiftServer_GetSendData(cmd->ptr, svr->news), sizeof(*svr->news)); + break; + case SVR_LOAD_CARD: + AGB_ASSERT(cmd->parameter == 0); + MysteryGiftServer_InitSend(svr, MG_LINKID_CARD, MysteryGiftServer_GetSendData(cmd->ptr, svr->card), sizeof(*svr->card)); + break; + case SVR_LOAD_STAMP: + AGB_ASSERT(cmd->parameter == 0); + MysteryGiftServer_InitSend(svr, MG_LINKID_STAMP, MysteryGiftServer_GetSendData(cmd->ptr, &svr->stamp), sizeof(svr->stamp)); + break; + case SVR_LOAD_RAM_SCRIPT: + if (cmd->ptr == NULL) + MysteryGiftServer_InitSend(svr, MG_LINKID_RAM_SCRIPT, svr->ramScript, svr->ramScriptSize); + else + MysteryGiftServer_InitSend(svr, MG_LINKID_RAM_SCRIPT, cmd->ptr, cmd->parameter); + break; + case SVR_LOAD_CLIENT_SCRIPT: + if (cmd->ptr == NULL) + MysteryGiftServer_InitSend(svr, MG_LINKID_CLIENT_SCRIPT, svr->clientScript, svr->clientScriptSize); + else + MysteryGiftServer_InitSend(svr, MG_LINKID_CLIENT_SCRIPT, cmd->ptr, cmd->parameter); + break; + case SVR_LOAD_EREADER_TRAINER: + AGB_ASSERT(cmd->parameter == 0); + MysteryGiftServer_InitSend(svr, MG_LINKID_EREADER_TRAINER, cmd->ptr, sizeof(struct BattleTowerEReaderTrainer)); + break; + case SVR_LOAD_MSG: + MysteryGiftServer_InitSend(svr, MG_LINKID_DYNAMIC_MSG, cmd->ptr, cmd->parameter); + break; + case SVR_LOAD_UNK_2: + MysteryGiftServer_InitSend(svr, MG_LINKID_UNK_2, cmd->ptr, cmd->parameter); + break; + case SVR_COPY_CARD: + AGB_ASSERT(cmd->parameter == 0); + memcpy(svr->card, cmd->ptr, sizeof(*svr->card)); + break; + case SVR_COPY_NEWS: + AGB_ASSERT(cmd->parameter == 0); + memcpy(svr->news, cmd->ptr, sizeof(*svr->news)); + break; + case SVR_COPY_STAMP: + AGB_ASSERT(cmd->parameter == 0); + svr->stamp = *(u32 *)cmd->ptr; + break; + case SVR_SET_RAM_SCRIPT: + svr->ramScript = cmd->ptr; + svr->ramScriptSize = cmd->parameter; + break; + case SVR_SET_CLIENT_SCRIPT: + svr->clientScript = cmd->ptr; + svr->clientScriptSize = cmd->parameter; + break; + case SVR_COPY_SAVED_CARD: + AGB_ASSERT(cmd->parameter == 0 && cmd->ptr == NULL); + memcpy(svr->card, GetSavedWonderCard(), sizeof(*svr->card)); + DisableWonderCardSending(svr->card); + break; + case SVR_COPY_SAVED_NEWS: + AGB_ASSERT(cmd->parameter == 0 && cmd->ptr == NULL); + memcpy(svr->news, GetSavedWonderNews(), sizeof(*svr->news)); + break; + case SVR_COPY_SAVED_RAM_SCRIPT: + AGB_ASSERT(cmd->parameter == 0 && cmd->ptr == NULL); + svr->ramScript = GetSavedRamScriptIfValid(); + break; + case SVR_LOAD_UNK_1: + MysteryGiftServer_InitSend(svr, MG_LINKID_UNK_1, cmd->ptr, cmd->parameter); + break; + } + + return SVR_RET_ACTIVE; +} + +static u32 (*const sFuncTable[])(struct MysteryGiftServer *) = { + [FUNC_INIT] = Server_Init, + [FUNC_DONE] = Server_Done, + [FUNC_RECV] = Server_Recv, + [FUNC_SEND] = Server_Send, + [FUNC_RUN] = Server_Run +}; + +static u32 MysteryGiftServer_CallFunc(struct MysteryGiftServer * svr) +{ + u32 response; + AGB_ASSERT(svr->funcId < ARRAY_COUNT(sFuncTable)); + response = sFuncTable[svr->funcId](svr); + AGB_ASSERT(svr->funcId < ARRAY_COUNT(sFuncTable)); + return response; +} diff --git a/src/mystery_gift_view.c b/src/mystery_gift_view.c new file mode 100644 index 000000000..0e1c11520 --- /dev/null +++ b/src/mystery_gift_view.c @@ -0,0 +1,936 @@ +#include "global.h" +#include "bg.h" +#include "gpu_regs.h" +#include "palette.h" +#include "decompress.h" +#include "malloc.h" +#include "menu.h" +#include "pokemon_icon.h" +#include "union_room.h" +#include "list_menu.h" +#include "text_window.h" +#include "string_util.h" +#include "link_rfu.h" +#include "mystery_gift.h" +#include "mystery_gift_menu.h" +#include "mystery_gift_view.h" +#include "constants/rgb.h" +#include "constants/mystery_gift.h" + +struct WonderGraphics +{ + u8 titleTextPal:4; + u8 bodyTextPal:4; + u8 footerTextPal:4; // Card only + u8 stampShadowPal:4; // Card only + const u32 * tiles; + const u32 * map; + const u16 * pal; +}; + +//====================== +// Wonder Cards +//====================== + +enum { + CARD_WIN_HEADER, + CARD_WIN_BODY, + CARD_WIN_FOOTER, + CARD_WIN_COUNT +}; + +#define TAG_STAMP_SHADOW 0x8000 + +struct CardStatTextData +{ + u8 width; + u8 statText[WONDER_CARD_TEXT_LENGTH + 1]; + u8 statNumberText[4]; +}; + +struct WonderCardData +{ + /*0000*/ struct WonderCard card; + /*014c*/ struct WonderCardMetadata cardMetadata; + /*0170*/ const struct WonderGraphics * gfx; + /*0174*/ u8 enterExitState; + /*0175*/ u8 statFooterWidth; + /*0176*/ u16 windowIds[CARD_WIN_COUNT]; + /*017C*/ u8 monIconSpriteId; + /*017D*/ u8 stampSpriteIds[MAX_STAMP_CARD_STAMPS][2]; // 2 sprites each, 1 for the shadow and 1 for the Pokémon + /*018B*/ u8 titleText[WONDER_CARD_TEXT_LENGTH + 1]; + /*01B4*/ u8 subtitleText[WONDER_CARD_TEXT_LENGTH + 1]; + /*01DD*/ u8 idNumberText[7]; + /*01E4*/ u8 bodyText[WONDER_CARD_BODY_TEXT_LINES][WONDER_CARD_TEXT_LENGTH + 1]; + /*0288*/ u8 footerLine1Text[WONDER_CARD_TEXT_LENGTH + 1]; + /*02B1*/ u8 giftText[WONDER_CARD_TEXT_LENGTH + 1]; + /*02DC*/ struct CardStatTextData statTextData[8]; + /*045C*/ u8 bgTilemapBuffer[0x1000]; +}; + +EWRAM_DATA static struct WonderCardData * sWonderCardData = NULL; + +static void BufferCardText(void); +static void DrawCardWindow(u8 whichWindow); +static void CreateCardSprites(void); +static void DestroyCardSprites(void); + +extern const struct OamData gOamData_AffineOff_ObjNormal_32x16; + +static const u8 sCard_TextColorTable[][3] = { + {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY}, + {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY} +}; + +static const u8 ALIGNED(4) sCard_FooterTextOffsets[CARD_TYPE_COUNT] = +{ + [CARD_TYPE_GIFT] = 7, + [CARD_TYPE_STAMP] = 4, + [CARD_TYPE_LINK_STAT] = 7 +}; + +static const struct WindowTemplate sCard_WindowTemplates[] = { + [CARD_WIN_HEADER] = { + .bg = 1, + .tilemapLeft = 1, + .tilemapTop = 1, + .width = 25, + .height = 4, + .paletteNum = 2, + .baseBlock = 0x029c + }, + [CARD_WIN_BODY] = { + .bg = 1, + .tilemapLeft = 1, + .tilemapTop = 6, + .width = 28, + .height = 8, + .paletteNum = 2, + .baseBlock = 0x01bc + }, + [CARD_WIN_FOOTER] = { + .bg = 1, + .tilemapLeft = 1, + .tilemapTop = 14, + .width = 28, + .height = 5, + .paletteNum = 2, + .baseBlock = 0x0130 + } +}; + +static const u16 sWonderCardBgPal1[] = INCBIN_U16("graphics/wonder_card/bg1.gbapal"); +static const u16 sWonderCardBgPal2[] = INCBIN_U16("graphics/wonder_card/bg2.gbapal"); +static const u16 sWonderCardBgPal3[] = INCBIN_U16("graphics/wonder_card/bg3.gbapal"); +static const u16 sWonderCardBgPal4[] = INCBIN_U16("graphics/wonder_card/bg4.gbapal"); +static const u16 sWonderCardBgPal5[] = INCBIN_U16("graphics/wonder_card/bg5.gbapal"); +static const u16 sWonderCardBgPal6[] = INCBIN_U16("graphics/wonder_card/bg6.gbapal"); +static const u16 sWonderCardBgPal7[] = INCBIN_U16("graphics/wonder_card/bg7.gbapal"); +static const u16 sWonderCardBgPal8[] = INCBIN_U16("graphics/wonder_card/bg8.gbapal"); +static const u32 sWonderCardBgGfx1[] = INCBIN_U32("graphics/wonder_card/bg1.4bpp.lz"); +static const u32 sWonderCardBgTilemap1[] = INCBIN_U32("graphics/wonder_card/bg1.bin.lz"); +static const u32 sWonderCardBgGfx2[] = INCBIN_U32("graphics/wonder_card/bg2.4bpp.lz"); +static const u32 sWonderCardBgTilemap2[] = INCBIN_U32("graphics/wonder_card/bg2.bin.lz"); +static const u32 sWonderCardBgGfx3[] = INCBIN_U32("graphics/wonder_card/bg3.4bpp.lz"); +static const u32 sWonderCardBgTilemap3[] = INCBIN_U32("graphics/wonder_card/bg3.bin.lz"); +static const u32 sWonderCardBgGfx7[] = INCBIN_U32("graphics/wonder_card/bg7.4bpp.lz"); +static const u32 sWonderCardBgTilemap7[] = INCBIN_U32("graphics/wonder_card/bg7.bin.lz"); +static const u32 sWonderCardBgGfx8[] = INCBIN_U32("graphics/wonder_card/bg8.4bpp.lz"); +static const u32 sWonderCardBgTilemap8[] = INCBIN_U32("graphics/wonder_card/bg8.bin.lz"); +static const u16 sStampShadowPal1[] = INCBIN_U16("graphics/wonder_card/stamp_shadow_1.gbapal"); +static const u16 sStampShadowPal2[] = INCBIN_U16("graphics/wonder_card/stamp_shadow_2.gbapal"); +static const u16 sStampShadowPal3[] = INCBIN_U16("graphics/wonder_card/stamp_shadow_3.gbapal"); +static const u16 sStampShadowPal4[] = INCBIN_U16("graphics/wonder_card/stamp_shadow_4.gbapal"); +static const u16 sStampShadowPal5[] = INCBIN_U16("graphics/wonder_card/stamp_shadow_5.gbapal"); +static const u16 sStampShadowPal6[] = INCBIN_U16("graphics/wonder_card/stamp_shadow_6.gbapal"); +static const u16 sStampShadowPal7[] = INCBIN_U16("graphics/wonder_card/stamp_shadow_7.gbapal"); +static const u16 sStampShadowPal8[] = INCBIN_U16("graphics/wonder_card/stamp_shadow_8.gbapal"); +static const u32 sStampShadowGfx[] = INCBIN_U32("graphics/wonder_card/stamp_shadow.4bpp.lz"); + +static const struct CompressedSpriteSheet sSpriteSheet_StampShadow = { + sStampShadowGfx, 0x100, TAG_STAMP_SHADOW +}; + +static const struct SpritePalette sSpritePalettes_StampShadow[] = { + {sStampShadowPal1, TAG_STAMP_SHADOW}, + {sStampShadowPal2, TAG_STAMP_SHADOW}, + {sStampShadowPal3, TAG_STAMP_SHADOW}, + {sStampShadowPal4, TAG_STAMP_SHADOW}, + {sStampShadowPal5, TAG_STAMP_SHADOW}, + {sStampShadowPal6, TAG_STAMP_SHADOW}, + {sStampShadowPal7, TAG_STAMP_SHADOW}, + {sStampShadowPal8, TAG_STAMP_SHADOW} +}; + +static const struct SpriteTemplate sSpriteTemplate_StampShadow = { + .tileTag = TAG_STAMP_SHADOW, + .paletteTag = TAG_STAMP_SHADOW, + .oam = &gOamData_AffineOff_ObjNormal_32x16, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy +}; + +static const struct WonderGraphics sCardGraphics[NUM_WONDER_BGS] = { + {.titleTextPal = 1, .bodyTextPal = 0, .footerTextPal = 0, .stampShadowPal = 0, .tiles = sWonderCardBgGfx1, .map = sWonderCardBgTilemap1, .pal = sWonderCardBgPal1}, + {.titleTextPal = 1, .bodyTextPal = 0, .footerTextPal = 0, .stampShadowPal = 1, .tiles = sWonderCardBgGfx2, .map = sWonderCardBgTilemap2, .pal = sWonderCardBgPal2}, + {.titleTextPal = 1, .bodyTextPal = 0, .footerTextPal = 0, .stampShadowPal = 2, .tiles = sWonderCardBgGfx3, .map = sWonderCardBgTilemap3, .pal = sWonderCardBgPal3}, + {.titleTextPal = 1, .bodyTextPal = 0, .footerTextPal = 0, .stampShadowPal = 3, .tiles = sWonderCardBgGfx3, .map = sWonderCardBgTilemap3, .pal = sWonderCardBgPal4}, + {.titleTextPal = 1, .bodyTextPal = 0, .footerTextPal = 0, .stampShadowPal = 4, .tiles = sWonderCardBgGfx3, .map = sWonderCardBgTilemap3, .pal = sWonderCardBgPal5}, + {.titleTextPal = 1, .bodyTextPal = 0, .footerTextPal = 0, .stampShadowPal = 5, .tiles = sWonderCardBgGfx3, .map = sWonderCardBgTilemap3, .pal = sWonderCardBgPal6}, + {.titleTextPal = 1, .bodyTextPal = 0, .footerTextPal = 0, .stampShadowPal = 6, .tiles = sWonderCardBgGfx7, .map = sWonderCardBgTilemap7, .pal = sWonderCardBgPal7}, + {.titleTextPal = 1, .bodyTextPal = 0, .footerTextPal = 0, .stampShadowPal = 7, .tiles = sWonderCardBgGfx8, .map = sWonderCardBgTilemap8, .pal = sWonderCardBgPal8} +}; + +bool32 WonderCard_Init(struct WonderCard * card, struct WonderCardMetadata * metadata) +{ + if (card == NULL || metadata == NULL) + return FALSE; + sWonderCardData = AllocZeroed(sizeof(*sWonderCardData)); + if (sWonderCardData == NULL) + return FALSE; + sWonderCardData->card = *card; + sWonderCardData->cardMetadata = *metadata; + if (sWonderCardData->card.bgType >= NUM_WONDER_BGS) + sWonderCardData->card.bgType = 0; + if (sWonderCardData->card.type >= CARD_TYPE_COUNT) + sWonderCardData->card.type = 0; + if (sWonderCardData->card.maxStamps > MAX_STAMP_CARD_STAMPS) + sWonderCardData->card.maxStamps = 0; + sWonderCardData->gfx = &sCardGraphics[sWonderCardData->card.bgType]; + return TRUE; +} + +void WonderCard_Destroy(void) +{ + if (sWonderCardData != NULL) + { + *sWonderCardData = (struct WonderCardData){}; + Free(sWonderCardData); + sWonderCardData = NULL; + } +} + +s32 WonderCard_Enter(void) +{ + if (sWonderCardData == NULL) + return -1; + switch(sWonderCardData->enterExitState) + { + case 0: + BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); + break; + case 1: + if (UpdatePaletteFade()) + return 0; + break; + case 2: + FillBgTilemapBufferRect_Palette0(0, 0x000, 0, 0, 30, 20); + FillBgTilemapBufferRect_Palette0(1, 0x000, 0, 0, 30, 20); + FillBgTilemapBufferRect_Palette0(2, 0x000, 0, 0, 30, 20); + CopyBgTilemapBufferToVram(0); + CopyBgTilemapBufferToVram(1); + CopyBgTilemapBufferToVram(2); + DecompressAndCopyTileDataToVram(2, sWonderCardData->gfx->tiles, 0, 0x008, 0); + sWonderCardData->windowIds[CARD_WIN_HEADER] = AddWindow(&sCard_WindowTemplates[CARD_WIN_HEADER]); + sWonderCardData->windowIds[CARD_WIN_BODY] = AddWindow(&sCard_WindowTemplates[CARD_WIN_BODY]); + sWonderCardData->windowIds[CARD_WIN_FOOTER] = AddWindow(&sCard_WindowTemplates[CARD_WIN_FOOTER]); + break; + case 3: + if (FreeTempTileDataBuffersIfPossible()) + return 0; + LoadPalette(GetTextWindowPalette(1), 0x20, 0x20); + gPaletteFade.bufferTransferDisabled = TRUE; + LoadPalette(sWonderCardData->gfx->pal, 0x10, 0x20); + LZ77UnCompWram(sWonderCardData->gfx->map, sWonderCardData->bgTilemapBuffer); + CopyRectToBgTilemapBufferRect(2, sWonderCardData->bgTilemapBuffer, 0, 0, 30, 20, 0, 0, 30, 20, 1, 0x008, 0); + CopyBgTilemapBufferToVram(2); + break; + case 4: + BufferCardText(); + break; + case 5: + DrawCardWindow(CARD_WIN_HEADER); + DrawCardWindow(CARD_WIN_BODY); + DrawCardWindow(CARD_WIN_FOOTER); + CopyBgTilemapBufferToVram(1); + break; + case 6: + LoadMonIconPalettes(); + break; + case 7: + ShowBg(1); + ShowBg(2); + gPaletteFade.bufferTransferDisabled = FALSE; + CreateCardSprites(); + BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); + UpdatePaletteFade(); + break; + default: + if (UpdatePaletteFade()) + return 0; + sWonderCardData->enterExitState = 0; + return 1; + } + sWonderCardData->enterExitState++; + return 0; +} + +s32 WonderCard_Exit(bool32 useCancel) +{ + if (sWonderCardData == NULL) + return -1; + switch (sWonderCardData->enterExitState) + { + case 0: + BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); + break; + case 1: + if (UpdatePaletteFade()) + return 0; + break; + case 2: + FillBgTilemapBufferRect_Palette0(0, 0x000, 0, 0, 30, 20); + FillBgTilemapBufferRect_Palette0(1, 0x000, 0, 0, 30, 20); + FillBgTilemapBufferRect_Palette0(2, 0x000, 0, 0, 30, 20); + CopyBgTilemapBufferToVram(0); + CopyBgTilemapBufferToVram(1); + CopyBgTilemapBufferToVram(2); + break; + case 3: + HideBg(1); + HideBg(2); + RemoveWindow(sWonderCardData->windowIds[CARD_WIN_FOOTER]); + RemoveWindow(sWonderCardData->windowIds[CARD_WIN_BODY]); + RemoveWindow(sWonderCardData->windowIds[CARD_WIN_HEADER]); + break; + case 4: + DestroyCardSprites(); + FreeMonIconPalettes(); + break; + case 5: + PrintMysteryGiftOrEReaderTopMenu(gGiftIsFromEReader, useCancel); + CopyBgTilemapBufferToVram(0); + BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); + break; + default: + if (UpdatePaletteFade()) + return 0; + sWonderCardData->enterExitState = 0; + return 1; + } + sWonderCardData->enterExitState++; + return 0; +} + +static void BufferCardText(void) +{ + u16 i = 0; + u16 charsUntilStat; + u16 stats[3] = {0, 0, 0}; + + // Copy title/subtitle text + memcpy(sWonderCardData->titleText, sWonderCardData->card.titleText, WONDER_CARD_TEXT_LENGTH); + sWonderCardData->titleText[WONDER_CARD_TEXT_LENGTH] = EOS; + memcpy(sWonderCardData->subtitleText, sWonderCardData->card.subtitleText, WONDER_CARD_TEXT_LENGTH); + sWonderCardData->subtitleText[WONDER_CARD_TEXT_LENGTH] = EOS; + + // Copy card id number + if (sWonderCardData->card.idNumber > 999999) + sWonderCardData->card.idNumber = 999999; + ConvertIntToDecimalStringN(sWonderCardData->idNumberText, sWonderCardData->card.idNumber, STR_CONV_MODE_LEFT_ALIGN, 6); + + // Copy body text + for (i = 0; i < WONDER_CARD_BODY_TEXT_LINES; i++) + { + memcpy(sWonderCardData->bodyText[i], sWonderCardData->card.bodyText[i], WONDER_CARD_TEXT_LENGTH); + sWonderCardData->bodyText[i][WONDER_CARD_TEXT_LENGTH] = EOS; + } + + // Copy footer line 1 + memcpy(sWonderCardData->footerLine1Text, sWonderCardData->card.footerLine1Text, WONDER_CARD_TEXT_LENGTH); + sWonderCardData->footerLine1Text[WONDER_CARD_TEXT_LENGTH] = EOS; + + // Copy footer line 2 + switch (sWonderCardData->card.type) + { + case CARD_TYPE_GIFT: + memcpy(sWonderCardData->giftText, sWonderCardData->card.footerLine2Text, WONDER_CARD_TEXT_LENGTH); + sWonderCardData->giftText[WONDER_CARD_TEXT_LENGTH] = EOS; + break; + case CARD_TYPE_STAMP: + sWonderCardData->giftText[0] = EOS; + break; + case CARD_TYPE_LINK_STAT: + sWonderCardData->giftText[0] = EOS; + + // Load stats + stats[0] = sWonderCardData->cardMetadata.battlesWon < MAX_WONDER_CARD_STAT ? sWonderCardData->cardMetadata.battlesWon : MAX_WONDER_CARD_STAT; + stats[1] = sWonderCardData->cardMetadata.battlesLost < MAX_WONDER_CARD_STAT ? sWonderCardData->cardMetadata.battlesLost : MAX_WONDER_CARD_STAT; + stats[2] = sWonderCardData->cardMetadata.numTrades < MAX_WONDER_CARD_STAT ? sWonderCardData->cardMetadata.numTrades : MAX_WONDER_CARD_STAT; + + // Init stat text arrays + for (i = 0; i < ARRAY_COUNT(sWonderCardData->statTextData); i++) + { + memset(sWonderCardData->statTextData[i].statNumberText, EOS, sizeof(sWonderCardData->statTextData[i].statNumberText)); + memset(sWonderCardData->statTextData[i].statText, EOS, sizeof(sWonderCardData->statTextData[i].statText)); + } + + // Copy stat texts + for (i = 0, charsUntilStat = 0; i < WONDER_CARD_TEXT_LENGTH; i++) + { + if (sWonderCardData->card.footerLine2Text[i] != CHAR_DYNAMIC) + { + // Regular text, just copy as is + sWonderCardData->statTextData[sWonderCardData->statFooterWidth].statText[charsUntilStat] = sWonderCardData->card.footerLine2Text[i]; + charsUntilStat++; + } + else + { + // Dynamic char encountered + // These are used to give the id of which stat to print + u8 id = sWonderCardData->card.footerLine2Text[i + 1]; + if (id >= ARRAY_COUNT(stats)) + { + // Invalid stat id, skip ahead + i += 2; + } + else + { + // Copy stat number + ConvertIntToDecimalStringN(sWonderCardData->statTextData[sWonderCardData->statFooterWidth].statNumberText, stats[id], STR_CONV_MODE_LEADING_ZEROS, 3); + sWonderCardData->statTextData[sWonderCardData->statFooterWidth].width = sWonderCardData->card.footerLine2Text[i + 2]; + sWonderCardData->statFooterWidth++; + if (sWonderCardData->statFooterWidth >= ARRAY_COUNT(sWonderCardData->statTextData)) + break; + charsUntilStat = 0; + i += 2; + } + } + } + } +} + +static void DrawCardWindow(u8 whichWindow) +{ + s8 i = 0; + s32 windowId = sWonderCardData->windowIds[whichWindow]; + PutWindowTilemap(windowId); + FillWindowPixelBuffer(windowId, 0); + switch (whichWindow) + { + case CARD_WIN_HEADER: + { + // Print card title/subtitle + s32 x; + AddTextPrinterParameterized3(windowId, 3, 0, 1, sCard_TextColorTable[sWonderCardData->gfx->titleTextPal], 0, sWonderCardData->titleText); + x = 160 - GetStringWidth(3, sWonderCardData->subtitleText, GetFontAttribute(3, FONTATTR_LETTER_SPACING)); + if (x < 0) + x = 0; + AddTextPrinterParameterized3(windowId, 3, x, 17, sCard_TextColorTable[sWonderCardData->gfx->titleTextPal], 0, sWonderCardData->subtitleText); + + // Print id number + if (sWonderCardData->card.idNumber != 0) + AddTextPrinterParameterized3(windowId, 1, 166, 17, sCard_TextColorTable[sWonderCardData->gfx->titleTextPal], 0, sWonderCardData->idNumberText); + break; + } + case CARD_WIN_BODY: + // Print body text + for (; i < WONDER_CARD_BODY_TEXT_LINES; i++) + AddTextPrinterParameterized3(windowId, 3, 0, 16 * i + 2, sCard_TextColorTable[sWonderCardData->gfx->bodyTextPal], 0, sWonderCardData->bodyText[i]); + break; + case CARD_WIN_FOOTER: + // Print footer line 1 + AddTextPrinterParameterized3(windowId, 3, 0, + sCard_FooterTextOffsets[sWonderCardData->card.type], + sCard_TextColorTable[sWonderCardData->gfx->footerTextPal], + 0, sWonderCardData->footerLine1Text); + + // Print footer line 2 + if (sWonderCardData->card.type != CARD_TYPE_LINK_STAT) + { + // Print gift text + // Odd that CARD_TYPE_STAMP is not ignored, it has empty text for this + AddTextPrinterParameterized3(windowId, 3, 0, + 16 + sCard_FooterTextOffsets[sWonderCardData->card.type], + sCard_TextColorTable[sWonderCardData->gfx->footerTextPal], + 0, sWonderCardData->giftText); + } + else + { + s32 x = 0; + s32 y = sCard_FooterTextOffsets[sWonderCardData->card.type] + 16; + s32 spacing = GetFontAttribute(3, FONTATTR_LETTER_SPACING); + for (; i < sWonderCardData->statFooterWidth; i++) + { + // Print stat text + AddTextPrinterParameterized3(windowId, 3, x, y, sCard_TextColorTable[sWonderCardData->gfx->footerTextPal], 0, sWonderCardData->statTextData[i].statText); + if (sWonderCardData->statTextData[i].statNumberText[0] != EOS) + { + // Print stat number + x += GetStringWidth(3, sWonderCardData->statTextData[i].statText, spacing); + AddTextPrinterParameterized3(windowId, 3, x, y, + sCard_TextColorTable[sWonderCardData->gfx->footerTextPal], + 0, sWonderCardData->statTextData[i].statNumberText); + x += GetStringWidth(3, sWonderCardData->statTextData[i].statNumberText, spacing) + sWonderCardData->statTextData[i].width; + } + } + } + break; + } + CopyWindowToVram(windowId, 3); +} + +static void CreateCardSprites(void) +{ + u8 i = 0; + sWonderCardData->monIconSpriteId = SPRITE_NONE; + + // Create icon sprite + if (sWonderCardData->cardMetadata.iconSpecies != SPECIES_NONE) + { + sWonderCardData->monIconSpriteId = CreateMonIconNoPersonality(GetIconSpeciesNoPersonality(sWonderCardData->cardMetadata.iconSpecies), SpriteCallbackDummy, 220, 20, 0, FALSE); + gSprites[sWonderCardData->monIconSpriteId].oam.priority = 2; + } + + // Create stamp sprites + if (sWonderCardData->card.maxStamps != 0 && sWonderCardData->card.type == CARD_TYPE_STAMP) + { + LoadCompressedSpriteSheetUsingHeap(&sSpriteSheet_StampShadow); + LoadSpritePalette(&sSpritePalettes_StampShadow[sWonderCardData->gfx->stampShadowPal]); + for (; i < sWonderCardData->card.maxStamps; i++) + { + sWonderCardData->stampSpriteIds[i][0] = SPRITE_NONE; + sWonderCardData->stampSpriteIds[i][1] = SPRITE_NONE; + sWonderCardData->stampSpriteIds[i][0] = CreateSprite(&sSpriteTemplate_StampShadow, 216 - 32 * i, 144, 8); + if (sWonderCardData->cardMetadata.stampData[STAMP_SPECIES][i] != SPECIES_NONE) + sWonderCardData->stampSpriteIds[i][1] = CreateMonIconNoPersonality(GetIconSpeciesNoPersonality(sWonderCardData->cardMetadata.stampData[STAMP_SPECIES][i]), + SpriteCallbackDummy, + 216 - 32 * i, + 136, 0, 0); + } + } +} + +static void DestroyCardSprites(void) +{ + u8 i = 0; + + // Destroy icon sprite + if (sWonderCardData->monIconSpriteId != SPRITE_NONE) + FreeAndDestroyMonIconSprite(&gSprites[sWonderCardData->monIconSpriteId]); + + // Destroy stamp sprites + if (sWonderCardData->card.maxStamps != 0 && sWonderCardData->card.type == CARD_TYPE_STAMP) + { + for (; i < sWonderCardData->card.maxStamps; i++) + { + if (sWonderCardData->stampSpriteIds[i][0] != SPRITE_NONE) + DestroySprite(&gSprites[sWonderCardData->stampSpriteIds[i][0]]); + if (sWonderCardData->stampSpriteIds[i][1] != SPRITE_NONE) + FreeAndDestroyMonIconSprite(&gSprites[sWonderCardData->stampSpriteIds[i][1]]); + } + FreeSpriteTilesByTag(TAG_STAMP_SHADOW); + FreeSpritePaletteByTag(TAG_STAMP_SHADOW); + } +} + +//====================== +// Wonder News +//====================== + +enum { + NEWS_WIN_TITLE, + NEWS_WIN_BODY, + NEWS_WIN_COUNT +}; + +#define TAG_ARROWS 0x1000 + +struct WonderNewsData +{ + /*0000*/ struct WonderNews news; + /*01bc*/ const struct WonderGraphics * gfx; + /*01c0*/ u8 arrowsRemoved:1; + u8 enterExitState:7; + /*01c1*/ u8 arrowTaskId; + /*01c2*/ bool8 scrolling:1; + u8 scrollIncrement:7; + /*01c3*/ bool8 scrollingDown:1; + u8 scrollTotal:7; + /*01c4*/ u16 scrollEnd; + /*01c6*/ u16 scrollOffset; + /*01c8*/ u16 windowIds[NEWS_WIN_COUNT]; + /*01cc*/ u8 unused[2]; + /*01ce*/ u8 titleText[WONDER_NEWS_TEXT_LENGTH + 1]; + /*01f7*/ u8 bodyText[WONDER_NEWS_BODY_TEXT_LINES][WONDER_NEWS_TEXT_LENGTH + 1]; + /*0394*/ struct ScrollArrowsTemplate arrowsTemplate; + /*03a4*/ u8 bgTilemapBuffer[0x1000]; +}; + +EWRAM_DATA static struct WonderNewsData * sWonderNewsData = NULL; + +static void BufferNewsText(void); +static void DrawNewsWindows(void); +static void UpdateNewsScroll(void); + +static const u8 sNews_TextColorTable[][3] = { + {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY}, + {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY} +}; + +static const struct WindowTemplate sNews_WindowTemplates[] = { + [NEWS_WIN_TITLE] = { + .bg = 0, + .tilemapLeft = 1, + .tilemapTop = 0, + .width = 28, + .height = 3, + .paletteNum = 2, + .baseBlock = 0x2AC + }, + [NEWS_WIN_BODY] = { + .bg = 2, + .tilemapLeft = 1, + .tilemapTop = 3, + .width = 28, + .height = 20, + .paletteNum = 2, + .baseBlock = 0x07C + } +}; + +static const struct ScrollArrowsTemplate sNews_ArrowsTemplate = { + .firstArrowType = SCROLL_ARROW_UP, + .firstX = 232, + .firstY = 24, + .secondArrowType = SCROLL_ARROW_DOWN, + .secondX = 232, + .secondY = 152, + .fullyUpThreshold = 0, + .fullyDownThreshold = 2, + .tileTag = TAG_ARROWS, + .palTag = TAG_ARROWS, + .palNum = 0 +}; + +static const u16 sWonderNewsPal1[] = INCBIN_U16("graphics/wonder_news/bg1.gbapal"); +static const u16 sWonderNewsPal7[] = INCBIN_U16("graphics/wonder_news/bg7.gbapal"); +static const u16 sWonderNewsPal8[] = INCBIN_U16("graphics/wonder_news/bg8.gbapal"); +static const u32 sWonderNewsGfx1[] = INCBIN_U32("graphics/wonder_news/bg1.4bpp.lz"); +static const u32 sWonderNewsTilemap1[] = INCBIN_U32("graphics/wonder_news/bg1.bin.lz"); +static const u32 sWonderNewsGfx2[] = INCBIN_U32("graphics/wonder_news/bg2.4bpp.lz"); +static const u32 sWonderNewsTilemap2[] = INCBIN_U32("graphics/wonder_news/bg2.bin.lz"); +static const u32 sWonderNewsGfx3[] = INCBIN_U32("graphics/wonder_news/bg3.4bpp.lz"); +static const u32 sWonderNewsTilemap3[] = INCBIN_U32("graphics/wonder_news/bg3.bin.lz"); +static const u32 sWonderNewsGfx7[] = INCBIN_U32("graphics/wonder_news/bg7.4bpp.lz"); +static const u32 sWonderNewsTilemap7[] = INCBIN_U32("graphics/wonder_news/bg7.bin.lz"); +static const u32 sWonderNewsGfx8[] = INCBIN_U32("graphics/wonder_news/bg8.4bpp.lz"); +static const u32 sWonderNewsTilemap8[] = INCBIN_U32("graphics/wonder_news/bg8.bin.lz"); + +static const struct WonderGraphics sNewsGraphics[NUM_WONDER_BGS] = { + {.titleTextPal = 1, .bodyTextPal = 0, .tiles = sWonderNewsGfx1, .map = sWonderNewsTilemap1, .pal = sWonderNewsPal1}, + {.titleTextPal = 1, .bodyTextPal = 0, .tiles = sWonderNewsGfx2, .map = sWonderNewsTilemap2, .pal = sWonderCardBgPal2}, + {.titleTextPal = 1, .bodyTextPal = 0, .tiles = sWonderNewsGfx3, .map = sWonderNewsTilemap3, .pal = sWonderCardBgPal3}, + {.titleTextPal = 1, .bodyTextPal = 0, .tiles = sWonderNewsGfx3, .map = sWonderNewsTilemap3, .pal = sWonderCardBgPal4}, + {.titleTextPal = 1, .bodyTextPal = 0, .tiles = sWonderNewsGfx3, .map = sWonderNewsTilemap3, .pal = sWonderCardBgPal5}, + {.titleTextPal = 1, .bodyTextPal = 0, .tiles = sWonderNewsGfx3, .map = sWonderNewsTilemap3, .pal = sWonderCardBgPal6}, + {.titleTextPal = 1, .bodyTextPal = 0, .tiles = sWonderNewsGfx7, .map = sWonderNewsTilemap7, .pal = sWonderNewsPal7}, + {.titleTextPal = 1, .bodyTextPal = 0, .tiles = sWonderNewsGfx8, .map = sWonderNewsTilemap8, .pal = sWonderNewsPal8} +}; + +bool32 WonderNews_Init(const struct WonderNews * news) +{ + if (news == NULL) + return FALSE; + sWonderNewsData = AllocZeroed(sizeof(*sWonderNewsData)); + if (sWonderNewsData == NULL) + return FALSE; + sWonderNewsData->news = *news; + if (sWonderNewsData->news.bgType >= NUM_WONDER_BGS) + sWonderNewsData->news.bgType = 0; + sWonderNewsData->gfx = &sNewsGraphics[sWonderNewsData->news.bgType]; + sWonderNewsData->arrowTaskId = TASK_NONE; + return TRUE; +} + +void WonderNews_Destroy(void) +{ + if (sWonderNewsData != NULL) + { + *sWonderNewsData = (struct WonderNewsData){}; + Free(sWonderNewsData); + sWonderNewsData = NULL; + } +} + +s32 WonderNews_Enter(void) +{ + if (sWonderNewsData == NULL) + return -1; + + switch (sWonderNewsData->enterExitState) + { + case 0: + BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); + break; + case 1: + if (UpdatePaletteFade()) + return 0; + ChangeBgY(0, 0, 0); + ChangeBgY(1, 0, 0); + ChangeBgY(2, 0, 0); + ChangeBgY(3, 0, 0); + SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(0, DISPLAY_WIDTH)); + SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(26, 152)); + SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ); + SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WIN01_BG1 | WINOUT_WIN01_BG3 | WINOUT_WIN01_OBJ); + SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); + break; + case 2: + FillBgTilemapBufferRect_Palette0(0, 0x000, 0, 0, 30, 20); + FillBgTilemapBufferRect_Palette0(1, 0x000, 0, 0, 30, 20); + FillBgTilemapBufferRect_Palette0(2, 0x000, 0, 0, 30, 20); + FillBgTilemapBufferRect_Palette0(3, 0x000, 0, 0, 30, 20); + CopyBgTilemapBufferToVram(0); + CopyBgTilemapBufferToVram(1); + CopyBgTilemapBufferToVram(2); + CopyBgTilemapBufferToVram(3); + DecompressAndCopyTileDataToVram(3, sWonderNewsData->gfx->tiles, 0, 8, 0); + sWonderNewsData->windowIds[NEWS_WIN_TITLE] = AddWindow(&sNews_WindowTemplates[NEWS_WIN_TITLE]); + sWonderNewsData->windowIds[NEWS_WIN_BODY] = AddWindow(&sNews_WindowTemplates[NEWS_WIN_BODY]); + break; + case 3: + if (FreeTempTileDataBuffersIfPossible()) + return 0; + LoadPalette(GetTextWindowPalette(1), 0x20, 0x20); + gPaletteFade.bufferTransferDisabled = TRUE; + LoadPalette(sWonderNewsData->gfx->pal, 0x10, 0x20); + LZ77UnCompWram(sWonderNewsData->gfx->map, sWonderNewsData->bgTilemapBuffer); + CopyRectToBgTilemapBufferRect(1, sWonderNewsData->bgTilemapBuffer, 0, 0, 30, 3, 0, 0, 30, 3, 1, 8, 0); + CopyRectToBgTilemapBufferRect(3, sWonderNewsData->bgTilemapBuffer, 0, 3, 30, 23, 0, 3, 30, 23, 1, 8, 0); + CopyBgTilemapBufferToVram(1); + CopyBgTilemapBufferToVram(3); + break; + case 4: + BufferNewsText(); + break; + case 5: + DrawNewsWindows(); + CopyBgTilemapBufferToVram(0); + CopyBgTilemapBufferToVram(2); + break; + case 6: + ShowBg(1); + ShowBg(2); + ShowBg(3); + gPaletteFade.bufferTransferDisabled = FALSE; + sWonderNewsData->arrowTaskId = AddScrollIndicatorArrowPair(&sWonderNewsData->arrowsTemplate, &sWonderNewsData->scrollOffset); + BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); + UpdatePaletteFade(); + break; + default: + if (UpdatePaletteFade()) + return 0; + sWonderNewsData->enterExitState = 0; + return 1; + } + + sWonderNewsData->enterExitState++; + return 0; +} + +s32 WonderNews_Exit(bool32 useCancel) +{ + if (sWonderNewsData == NULL) + return -1; + switch (sWonderNewsData->enterExitState) + { + case 0: + BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); + break; + case 1: + if (UpdatePaletteFade()) + return 0; + ChangeBgY(2, 0, 0); + SetGpuReg(REG_OFFSET_WIN0H, 0); + SetGpuReg(REG_OFFSET_WIN0V, 0); + SetGpuReg(REG_OFFSET_WININ, 0); + SetGpuReg(REG_OFFSET_WINOUT, 0); + ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); + break; + case 2: + FillBgTilemapBufferRect_Palette0(0, 0x000, 0, 0, 30, 20); + FillBgTilemapBufferRect_Palette0(1, 0x000, 0, 0, 30, 20); + FillBgTilemapBufferRect_Palette0(2, 0x000, 0, 0, 30, 24); + FillBgTilemapBufferRect_Palette0(3, 0x000, 0, 0, 30, 24); + CopyBgTilemapBufferToVram(0); + CopyBgTilemapBufferToVram(1); + CopyBgTilemapBufferToVram(2); + CopyBgTilemapBufferToVram(3); + break; + case 3: + HideBg(1); + HideBg(2); + RemoveWindow(sWonderNewsData->windowIds[NEWS_WIN_BODY]); + RemoveWindow(sWonderNewsData->windowIds[NEWS_WIN_TITLE]); + break; + case 4: + ChangeBgY(2, 0, 0); + ChangeBgY(3, 0, 0); + if (sWonderNewsData->arrowTaskId != TASK_NONE) + { + RemoveScrollIndicatorArrowPair(sWonderNewsData->arrowTaskId); + sWonderNewsData->arrowTaskId = TASK_NONE; + } + break; + case 5: + PrintMysteryGiftOrEReaderTopMenu(gGiftIsFromEReader, useCancel); + MG_DrawCheckerboardPattern(3); + CopyBgTilemapBufferToVram(0); + CopyBgTilemapBufferToVram(3); + BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); + break; + default: + if (UpdatePaletteFade()) + return 0; + sWonderNewsData->enterExitState = 0; + return 1; + } + sWonderNewsData->enterExitState++; + return 0; +} + +void WonderNews_RemoveScrollIndicatorArrowPair(void) +{ + if (!sWonderNewsData->arrowsRemoved && sWonderNewsData->arrowTaskId != TASK_NONE) + { + RemoveScrollIndicatorArrowPair(sWonderNewsData->arrowTaskId); + sWonderNewsData->arrowTaskId = TASK_NONE; + sWonderNewsData->arrowsRemoved = TRUE; + } +} + + +void WonderNews_AddScrollIndicatorArrowPair(void) +{ + if (sWonderNewsData->arrowsRemoved) + { + sWonderNewsData->arrowTaskId = AddScrollIndicatorArrowPair(&sWonderNewsData->arrowsTemplate, &sWonderNewsData->scrollOffset); + sWonderNewsData->arrowsRemoved = FALSE; + } +} + +u32 WonderNews_GetInput(u16 input) +{ + if (sWonderNewsData->scrolling) + { + UpdateNewsScroll(); + return NEWS_INPUT_NONE; + } + switch (input) + { + case A_BUTTON: + return NEWS_INPUT_A; + case B_BUTTON: + return NEWS_INPUT_B; + case DPAD_UP: + if (sWonderNewsData->scrollOffset == 0) + return NEWS_INPUT_NONE; + if (sWonderNewsData->arrowsRemoved) + return NEWS_INPUT_NONE; + sWonderNewsData->scrollingDown = FALSE; + break; + case DPAD_DOWN: + if (sWonderNewsData->scrollOffset == sWonderNewsData->scrollEnd) + return NEWS_INPUT_NONE; + if (sWonderNewsData->arrowsRemoved) + return NEWS_INPUT_NONE; + sWonderNewsData->scrollingDown = TRUE; + break; + default: + return NEWS_INPUT_NONE; + } + + // Init scroll + sWonderNewsData->scrolling = TRUE; + sWonderNewsData->scrollIncrement = 2; + sWonderNewsData->scrollTotal = 0; + if (!sWonderNewsData->scrollingDown) + return NEWS_INPUT_SCROLL_UP; + else + return NEWS_INPUT_SCROLL_DOWN; +} + +static void BufferNewsText(void) +{ + u8 i = 0; + + // Copy title text + memcpy(sWonderNewsData->titleText, sWonderNewsData->news.titleText, WONDER_NEWS_TEXT_LENGTH); + sWonderNewsData->titleText[WONDER_NEWS_TEXT_LENGTH] = EOS; + + // Copy body text + for (; i < WONDER_NEWS_BODY_TEXT_LINES; i++) + { + memcpy(sWonderNewsData->bodyText[i], sWonderNewsData->news.bodyText[i], WONDER_NEWS_TEXT_LENGTH); + sWonderNewsData->bodyText[i][WONDER_NEWS_TEXT_LENGTH] = EOS; + if (i > 7 && sWonderNewsData->bodyText[i][0] != EOS) + sWonderNewsData->scrollEnd++; + } + sWonderNewsData->arrowsTemplate = sNews_ArrowsTemplate; + sWonderNewsData->arrowsTemplate.fullyDownThreshold = sWonderNewsData->scrollEnd; +} + +static void DrawNewsWindows(void) +{ + u8 i = 0; + s32 x; + PutWindowTilemap(sWonderNewsData->windowIds[NEWS_WIN_TITLE]); + PutWindowTilemap(sWonderNewsData->windowIds[NEWS_WIN_BODY]); + FillWindowPixelBuffer(sWonderNewsData->windowIds[NEWS_WIN_TITLE], 0); + FillWindowPixelBuffer(sWonderNewsData->windowIds[NEWS_WIN_BODY], 0); + + // Print title text + x = (224 - GetStringWidth(3, sWonderNewsData->titleText, GetFontAttribute(3, FONTATTR_LETTER_SPACING))) / 2; + if (x < 0) + x = 0; + AddTextPrinterParameterized3(sWonderNewsData->windowIds[NEWS_WIN_TITLE], 3, x, 6, sNews_TextColorTable[sWonderNewsData->gfx->titleTextPal], 0, sWonderNewsData->titleText); + + // Print body text + for (; i < WONDER_NEWS_BODY_TEXT_LINES; i++) + AddTextPrinterParameterized3(sWonderNewsData->windowIds[NEWS_WIN_BODY], 3, 0, + 16 * i + 2, + sNews_TextColorTable[sWonderNewsData->gfx->bodyTextPal], + 0, sWonderNewsData->bodyText[i]); + + CopyWindowToVram(sWonderNewsData->windowIds[NEWS_WIN_TITLE], 3); + CopyWindowToVram(sWonderNewsData->windowIds[NEWS_WIN_BODY], 3); +} + +static void UpdateNewsScroll(void) +{ + u16 bgMove = sWonderNewsData->scrollIncrement; + bgMove *= 256; + if (sWonderNewsData->scrollingDown) + { + ChangeBgY(2, bgMove, BG_COORD_ADD); + ChangeBgY(3, bgMove, BG_COORD_ADD); + } + else + { + ChangeBgY(2, bgMove, BG_COORD_SUB); + ChangeBgY(3, bgMove, BG_COORD_SUB); + } + sWonderNewsData->scrollTotal += sWonderNewsData->scrollIncrement; + if (sWonderNewsData->scrollTotal > 15) + { + if (sWonderNewsData->scrollingDown) + sWonderNewsData->scrollOffset++; + else + sWonderNewsData->scrollOffset--; + sWonderNewsData->scrolling = FALSE; + sWonderNewsData->scrollTotal = 0; + } +} diff --git a/src/new_game.c b/src/new_game.c index 2a950efbc..1362c492d 100644 --- a/src/new_game.c +++ b/src/new_game.c @@ -43,7 +43,7 @@ #include "player_pc.h" #include "field_specials.h" #include "berry_powder.h" -#include "mevent.h" +#include "mystery_gift.h" #include "union_room_chat.h" extern const u8 EventScript_ResetAllMapFlags[]; @@ -200,7 +200,7 @@ void NewGameInitData(void) ResetAllApprenticeData(); ClearRankingHallRecords(); InitMatchCallCounters(); - sub_801AFD8(); + ClearMysteryGift(); WipeTrainerNameRecords(); ResetTrainerHillResults(); ResetContestLinkResults(); diff --git a/src/scrcmd.c b/src/scrcmd.c index de0ec7c26..3e3beee59 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -2230,7 +2230,7 @@ bool8 ScrCmd_checkmoneventlegal(struct ScriptContext *ctx) } // TODO: Should be renamed. Name implies general usage, but its specifically for Wonder Card -// See GetSavedRamScriptIfValid, which is NULL if ValidateReceivedWonderCard returns FALSE +// See GetSavedRamScriptIfValid, which is NULL if ValidateSavedWonderCard returns FALSE bool8 ScrCmd_gotoram(struct ScriptContext *ctx) { const u8* script = GetSavedRamScriptIfValid(); diff --git a/src/script.c b/src/script.c index 726c06543..b10e0db49 100644 --- a/src/script.c +++ b/src/script.c @@ -1,8 +1,9 @@ #include "global.h" #include "script.h" #include "event_data.h" -#include "mevent.h" +#include "mystery_gift.h" #include "util.h" +#include "constants/maps.h" #include "constants/map_scripts.h" #define RAM_SCRIPT_MAGIC 51 @@ -403,9 +404,9 @@ bool32 ValidateSavedRamScript(void) struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data; if (scriptData->magic != RAM_SCRIPT_MAGIC) return FALSE; - if (scriptData->mapGroup != 0xFF) + if (scriptData->mapGroup != MAP_GROUP(UNDEFINED)) return FALSE; - if (scriptData->mapNum != 0xFF) + if (scriptData->mapNum != MAP_NUM(UNDEFINED)) return FALSE; if (scriptData->objectId != 0xFF) return FALSE; @@ -417,13 +418,13 @@ bool32 ValidateSavedRamScript(void) u8 *GetSavedRamScriptIfValid(void) { struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data; - if (!ValidateReceivedWonderCard()) + if (!ValidateSavedWonderCard()) return NULL; if (scriptData->magic != RAM_SCRIPT_MAGIC) return NULL; - if (scriptData->mapGroup != 0xFF) + if (scriptData->mapGroup != MAP_GROUP(UNDEFINED)) return NULL; - if (scriptData->mapNum != 0xFF) + if (scriptData->mapNum != MAP_NUM(UNDEFINED)) return NULL; if (scriptData->objectId != 0xFF) return NULL; @@ -442,5 +443,5 @@ void InitRamScript_NoObjectEvent(u8 *script, u16 scriptSize) { if (scriptSize > sizeof(gSaveBlock1Ptr->ramScript.data.script)) scriptSize = sizeof(gSaveBlock1Ptr->ramScript.data.script); - InitRamScript(script, scriptSize, 0xFF, 0xFF, 0xFF); + InitRamScript(script, scriptSize, MAP_GROUP(UNDEFINED), MAP_NUM(UNDEFINED), 0xFF); } diff --git a/src/trade.c b/src/trade.c index d1fc14efe..9c6bb78d0 100644 --- a/src/trade.c +++ b/src/trade.c @@ -19,8 +19,8 @@ #include "load_save.h" #include "mail.h" #include "main.h" -#include "mevent2.h" #include "mystery_gift.h" +#include "mystery_gift_menu.h" #include "overworld.h" #include "palette.h" #include "party_menu.h" @@ -4655,9 +4655,8 @@ static void CB2_SaveAndEndTrade(void) if (!InUnionRoom()) IncrementGameStat(GAME_STAT_POKEMON_TRADES); if (gWirelessCommType) - { - RecordIdOfWonderCardSenderByEventType(2, gLinkPlayers[GetMultiplayerId() ^ 1].trainerId); - } + MysteryGift_TryIncrementStat(CARD_STAT_NUM_TRADES, gLinkPlayers[GetMultiplayerId() ^ 1].trainerId); + SetContinueGameWarpStatusToDynamicWarp(); sub_8153380(); gMain.state++; diff --git a/src/trainer_card.c b/src/trainer_card.c index c11ee83c0..bad015644 100755 --- a/src/trainer_card.c +++ b/src/trainer_card.c @@ -110,7 +110,7 @@ static bool8 HasAllFrontierSymbols(void); static u8 GetRubyTrainerStars(struct TrainerCard*); static u16 GetCaughtMonsCount(void); static void SetPlayerCardData(struct TrainerCard*, u8); -static void TrainerCard_GenerateCardForLinkPlayer(struct TrainerCard*); +static void TrainerCard_GenerateCardForPlayer(struct TrainerCard*); static u8 VersionToCardType(u8); static void SetDataFromTrainerCard(void); static void InitGpuRegs(void); @@ -750,14 +750,14 @@ static void SetPlayerCardData(struct TrainerCard *trainerCard, u8 cardType) } } -static void TrainerCard_GenerateCardForLinkPlayer(struct TrainerCard *trainerCard) +static void TrainerCard_GenerateCardForPlayer(struct TrainerCard *trainerCard) { memset(trainerCard, 0, sizeof(struct TrainerCard)); trainerCard->version = GAME_VERSION; SetPlayerCardData(trainerCard, CARD_TYPE_EMERALD); - trainerCard->hasAllSymbols = HasAllFrontierSymbols(); + trainerCard->hasAllFrontierSymbols = HasAllFrontierSymbols(); trainerCard->frontierBP = gSaveBlock2Ptr->frontier.cardBattlePoints; - if (trainerCard->hasAllSymbols) + if (trainerCard->hasAllFrontierSymbols) trainerCard->stars++; if (trainerCard->gender == FEMALE) @@ -766,14 +766,14 @@ static void TrainerCard_GenerateCardForLinkPlayer(struct TrainerCard *trainerCar trainerCard->facilityClass = gLinkPlayerFacilityClasses[trainerCard->trainerId % NUM_MALE_LINK_FACILITY_CLASSES]; } -void TrainerCard_GenerateCardForPlayer(struct TrainerCard *trainerCard) +void TrainerCard_GenerateCardForLinkPlayer(struct TrainerCard *trainerCard) { memset(trainerCard, 0, 0x60); trainerCard->version = GAME_VERSION; SetPlayerCardData(trainerCard, CARD_TYPE_EMERALD); - trainerCard->hasAllFrontierSymbols = HasAllFrontierSymbols(); - *((u16*)&trainerCard->berryCrushPoints) = gSaveBlock2Ptr->frontier.cardBattlePoints; - if (trainerCard->hasAllFrontierSymbols) + trainerCard->linkHasAllFrontierSymbols = HasAllFrontierSymbols(); + *((u16*)&trainerCard->linkPoints.frontier) = gSaveBlock2Ptr->frontier.cardBattlePoints; + if (trainerCard->linkHasAllFrontierSymbols) trainerCard->stars++; if (trainerCard->gender == FEMALE) @@ -782,7 +782,7 @@ void TrainerCard_GenerateCardForPlayer(struct TrainerCard *trainerCard) trainerCard->facilityClass = gLinkPlayerFacilityClasses[trainerCard->trainerId % NUM_MALE_LINK_FACILITY_CLASSES]; } -void CopyTrainerCardData(struct TrainerCard *dst, u16 *src, u8 gameVersion) +void CopyTrainerCardData(struct TrainerCard *dst, struct TrainerCard *src, u8 gameVersion) { memset(dst, 0, sizeof(struct TrainerCard)); dst->version = gameVersion; @@ -797,9 +797,9 @@ void CopyTrainerCardData(struct TrainerCard *dst, u16 *src, u8 gameVersion) break; case CARD_TYPE_EMERALD: memcpy(dst, src, 0x60); - dst->berryCrushPoints = 0; - dst->hasAllSymbols = src[29]; - dst->frontierBP = src[30]; + dst->linkPoints.frontier = 0; + dst->hasAllFrontierSymbols = src->linkHasAllFrontierSymbols; + dst->frontierBP = *((u16*)&src->linkPoints.frontier); break; } } @@ -1243,13 +1243,13 @@ static void PrintTradesStringOnCard(void) static void BufferBerryCrushPoints(void) { - if (sData->cardType == CARD_TYPE_FRLG && sData->trainerCard.berryCrushPoints) - ConvertIntToDecimalStringN(sData->textBerryCrushPts, sData->trainerCard.berryCrushPoints, STR_CONV_MODE_RIGHT_ALIGN, 5); + if (sData->cardType == CARD_TYPE_FRLG && sData->trainerCard.linkPoints.berryCrush) + ConvertIntToDecimalStringN(sData->textBerryCrushPts, sData->trainerCard.linkPoints.berryCrush, STR_CONV_MODE_RIGHT_ALIGN, 5); } static void PrintBerryCrushStringOnCard(void) { - if (sData->cardType == CARD_TYPE_FRLG && sData->trainerCard.berryCrushPoints) + if (sData->cardType == CARD_TYPE_FRLG && sData->trainerCard.linkPoints.berryCrush) PrintStatOnBackOfCard(4, gText_BerryCrush, sData->textBerryCrushPts, sTrainerCardStatColors); } @@ -1524,7 +1524,7 @@ static void DrawCardBackStats(void) FillBgTilemapBufferRect(3, 141, 27, 9, 1, 1, 1); FillBgTilemapBufferRect(3, 157, 27, 10, 1, 1, 1); } - if (sData->trainerCard.berryCrushPoints) + if (sData->trainerCard.linkPoints.berryCrush) { FillBgTilemapBufferRect(3, 141, 21, 13, 1, 1, 1); FillBgTilemapBufferRect(3, 157, 21, 14, 1, 1, 1); @@ -1803,7 +1803,7 @@ void ShowPlayerTrainerCard(void (*callback)(void)) sData->isLink = FALSE; sData->language = GAME_LANGUAGE; - TrainerCard_GenerateCardForLinkPlayer(&sData->trainerCard); + TrainerCard_GenerateCardForPlayer(&sData->trainerCard); SetMainCallback2(CB2_InitTrainerCard); } diff --git a/src/union_room.c b/src/union_room.c index db2d0247b..6cc54d07c 100644 --- a/src/union_room.c +++ b/src/union_room.c @@ -24,8 +24,8 @@ #include "load_save.h" #include "menu.h" #include "menu_helpers.h" -#include "mevent.h" #include "mystery_gift.h" +#include "mystery_gift_menu.h" #include "overworld.h" #include "palette.h" #include "party_menu.h" @@ -219,7 +219,7 @@ static u16 ReadAsU16(const u8 *); static void Task_TryBecomeLinkLeader(u8); static void Task_TryJoinLinkGroup(u8); static void Task_ListenToWireless(u8); -static void Task_MEvent_Leader(u8); +static void Task_SendMysteryGift(u8); static void Task_CardOrNewsWithFriend(u8); static void Task_CardOrNewsOverWireless(u8); static void Task_RunUnionRoom(u8); @@ -1533,17 +1533,21 @@ static void Task_ExchangeCards(u8 taskId) for (i = 0; i < GetLinkPlayerCount(); i++) { recvBuff = gBlockRecvBuffer[i]; - CopyTrainerCardData(&gTrainerCards[i], recvBuff, gLinkPlayers[i].version); + CopyTrainerCardData(&gTrainerCards[i], (struct TrainerCard *)recvBuff, gLinkPlayers[i].version); } if (GetLinkPlayerCount() == 2) { + // Note: hasAllFrontierSymbols is a re-used field. + // Here it is set by CreateTrainerCardInBuffer. + // If the player has a saved Wonder Card and it is the same Wonder Card + // as their partner then mystery gift stats are enabled. recvBuff = gBlockRecvBuffer[GetMultiplayerId() ^ 1]; - MEventHandleReceivedWonderCard(recvBuff[48]); + MysteryGift_TryEnableStatsByFlagId(((struct TrainerCard *)recvBuff)->hasAllFrontierSymbols); } else { - ResetReceivedWonderCardFlag(); + MysteryGift_DisableStats(); } ResetBlockReceivedFlags(); @@ -1627,18 +1631,19 @@ static void CB2_TransitionToCableClub(void) static void CreateTrainerCardInBuffer(void *dest, bool32 setWonderCard) { - u16 *argAsU16Ptr = dest; + struct TrainerCard * card = (struct TrainerCard *)dest; + TrainerCard_GenerateCardForLinkPlayer(card); - TrainerCard_GenerateCardForPlayer((struct TrainerCard *)argAsU16Ptr); + // Below field is re-used, to be read by Task_ExchangeCards if (setWonderCard) - argAsU16Ptr[48] = GetWonderCardFlagID(); + card->hasAllFrontierSymbols = GetWonderCardFlagID(); else - argAsU16Ptr[48] = 0; + card->hasAllFrontierSymbols = 0; } static void Task_StartActivity(u8 taskId) { - ResetReceivedWonderCardFlag(); + MysteryGift_DisableStats(); switch (gPlayerCurrActivity) { case ACTIVITY_BATTLE_SINGLE: @@ -1858,12 +1863,13 @@ static void CreateTask_StartActivity(void) gTasks[taskId].data[0] = 0; } -void MEvent_CreateTask_Leader(u32 activity) +// Sending Wonder Card/News +void CreateTask_SendMysteryGift(u32 activity) { u8 taskId; struct WirelessLink_Leader *data; - taskId = CreateTask(Task_MEvent_Leader, 0); + taskId = CreateTask(Task_SendMysteryGift, 0); sWirelessLinkMain.leader = data = (void*)(gTasks[taskId].data); data->state = 0; @@ -1872,7 +1878,7 @@ void MEvent_CreateTask_Leader(u32 activity) gSpecialVar_Result = LINKUP_ONGOING; } -static void Task_MEvent_Leader(u8 taskId) +static void Task_SendMysteryGift(u8 taskId) { struct WirelessLink_Leader *data = sWirelessLinkMain.leader; struct WindowTemplate winTemplate; @@ -1934,7 +1940,7 @@ static void Task_MEvent_Leader(u8 taskId) } break; case 6: - if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, sText_LinkWithFriendDropped)) + if (PrintMysteryGiftMenuMessage(&data->textState, sText_LinkWithFriendDropped)) { data->playerCount = LeaderPrunePlayerList(data->playerList); RedrawListMenu(data->listTaskId); @@ -1945,7 +1951,7 @@ static void Task_MEvent_Leader(u8 taskId) data->state = 7; break; case 7: - switch (mevent_message_print_and_prompt_yes_no(&data->textState, &data->yesNoWindowId, 0, gStringVar4)) + switch (DoMysteryGiftYesNo(&data->textState, &data->yesNoWindowId, 0, gStringVar4)) { case 0: LoadWirelessStatusIndicatorSpriteGfx(); @@ -2031,7 +2037,7 @@ static void Task_MEvent_Leader(u8 taskId) data->state++; break; case 14: - if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, sText_PleaseStartOver)) + if (PrintMysteryGiftMenuMessage(&data->textState, sText_PleaseStartOver)) { DestroyTask(taskId); gSpecialVar_Result = LINKUP_FAILED; @@ -2066,7 +2072,7 @@ static void Task_MEvent_Leader(u8 taskId) } } -void MEvent_CreateTask_CardOrNewsWithFriend(u32 activity) +void CreateTask_LinkMysteryGiftWithFriend(u32 activity) { u8 taskId; struct WirelessLink_Group *data; @@ -2209,7 +2215,7 @@ static void Task_CardOrNewsWithFriend(u8 taskId) data->state++; break; case 9: - if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, sLinkDroppedTexts[RfuGetStatus()])) + if (PrintMysteryGiftMenuMessage(&data->textState, sLinkDroppedTexts[RfuGetStatus()])) { DestroyWirelessStatusIndicatorSprite(); DestroyTask(taskId); @@ -2235,7 +2241,7 @@ static void Task_CardOrNewsWithFriend(u8 taskId) } } -void MEvent_CreateTask_CardOrNewsOverWireless(u32 activity) +void CreateTask_LinkMysteryGiftOverWireless(u32 activity) { u8 taskId; struct WirelessLink_Group *data; @@ -2377,7 +2383,7 @@ static void Task_CardOrNewsOverWireless(u8 taskId) data->state++; break; case 9: - if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, sText_WirelessLinkDropped)) + if (PrintMysteryGiftMenuMessage(&data->textState, sText_WirelessLinkDropped)) { DestroyWirelessStatusIndicatorSprite(); DestroyTask(taskId); @@ -2386,7 +2392,7 @@ static void Task_CardOrNewsOverWireless(u8 taskId) } break; case 7: - if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, sText_WirelessSearchCanceled)) + if (PrintMysteryGiftMenuMessage(&data->textState, sText_WirelessSearchCanceled)) { DestroyWirelessStatusIndicatorSprite(); DestroyTask(taskId); @@ -2395,7 +2401,7 @@ static void Task_CardOrNewsOverWireless(u8 taskId) } break; case 11: - if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, sNoWonderSharedTexts[data->isWonderNews])) + if (PrintMysteryGiftMenuMessage(&data->textState, sNoWonderSharedTexts[data->isWonderNews])) { DestroyWirelessStatusIndicatorSprite(); DestroyTask(taskId); diff --git a/src/wonder_news.c b/src/wonder_news.c new file mode 100644 index 000000000..ec93d293e --- /dev/null +++ b/src/wonder_news.c @@ -0,0 +1,160 @@ +#include "global.h" +#include "mystery_gift.h" +#include "random.h" +#include "event_data.h" +#include "wonder_news.h" + +/* + Wonder News related functions. + Because this feature is largely unused, the names in here are + mostly nebulous and without a real indication of purpose. +*/ + +enum { + NEWS_VAL_INVALID, + NEWS_VAL_RECV_FRIEND, + NEWS_VAL_RECV_WIRELESS, + NEWS_VAL_NONE, + NEWS_VAL_SENT, + NEWS_VAL_SENT_MAX, + NEWS_VAL_GET_MAX, +}; + +static u32 GetNewsId(struct WonderNewsMetadata *); +static void IncrementGetNewsCounter(struct WonderNewsMetadata *); +static u32 GetNewsValByNewsType(struct WonderNewsMetadata *); +static void IncrementSentNewsCounter(struct WonderNewsMetadata *); +static void ResetSentNewsCounter(struct WonderNewsMetadata *); + +void GenerateRandomWonderNews(u32 newsType) +{ + struct WonderNewsMetadata *data = GetSavedWonderNewsMetadata(); + + data->newsType = newsType; + switch (newsType) + { + case WONDER_NEWS_NONE: + break; + case WONDER_NEWS_RECV_FRIEND: + case WONDER_NEWS_RECV_WIRELESS: + data->rand = (Random() % 15) + 16; + break; + case WONDER_NEWS_SENT: + data->rand = (Random() % 15) + 1; + break; + } +} + +void InitSavedWonderNews(void) +{ + struct WonderNewsMetadata *data = GetSavedWonderNewsMetadata(); + + data->newsType = WONDER_NEWS_NONE; + data->sentCounter = 0; + data->getCounter = 0; + data->rand = 0; + VarSet(VAR_WONDER_NEWS_COUNTER, 0); +} + +// Unused +static void TryIncrementWonderNewsVar(void) +{ + u16 *var = GetVarPointer(VAR_WONDER_NEWS_COUNTER); + struct WonderNewsMetadata *data = GetSavedWonderNewsMetadata(); + + if (data->getCounter > 4 && ++(*var) >= 500) + { + data->getCounter = 0; + *var = 0; + } +} + +// Unused +u16 RetrieveWonderNewsVal(void) +{ + u16 *result = &gSpecialVar_Result; + struct WonderNewsMetadata *data = GetSavedWonderNewsMetadata(); + u16 newsVal; + + // Checks if Mystery Event is enabled, not Mystery Gift? + if (!IsMysteryEventEnabled() || !ValidateSavedWonderNews()) + return 0; + + newsVal = GetNewsValByNewsType(data); + + switch (newsVal) + { + case NEWS_VAL_RECV_FRIEND: + *result = GetNewsId(data); + break; + case NEWS_VAL_RECV_WIRELESS: + *result = GetNewsId(data); + break; + case NEWS_VAL_SENT: + *result = GetNewsId(data); + IncrementSentNewsCounter(data); + break; + case NEWS_VAL_SENT_MAX: + *result = GetNewsId(data); + ResetSentNewsCounter(data); + break; + case NEWS_VAL_INVALID: + case NEWS_VAL_NONE: + case NEWS_VAL_GET_MAX: + break; + } + + return newsVal; +} + +static u32 GetNewsId(struct WonderNewsMetadata *data) +{ + u32 id; + data->newsType = WONDER_NEWS_NONE; + id = data->rand + 132; + data->rand = 0; + IncrementGetNewsCounter(data); + return id; +} + +static void ResetSentNewsCounter(struct WonderNewsMetadata *data) +{ + data->sentCounter = 0; +} + +static void IncrementSentNewsCounter(struct WonderNewsMetadata *data) +{ + data->sentCounter++; + if (data->sentCounter > 4) + data->sentCounter = 4; +} + +static void IncrementGetNewsCounter(struct WonderNewsMetadata *data) +{ + data->getCounter++; + if (data->getCounter > 5) + data->getCounter = 5; +} + +static u32 GetNewsValByNewsType(struct WonderNewsMetadata *data) +{ + if (data->getCounter == 5) + return NEWS_VAL_GET_MAX; + + switch (data->newsType) + { + case WONDER_NEWS_NONE: + return NEWS_VAL_NONE; + case WONDER_NEWS_RECV_FRIEND: + return NEWS_VAL_RECV_FRIEND; + case WONDER_NEWS_RECV_WIRELESS: + return NEWS_VAL_RECV_WIRELESS; + case WONDER_NEWS_SENT: + if (data->sentCounter < 3) + return NEWS_VAL_SENT; + return NEWS_VAL_SENT_MAX; + default: + AGB_ASSERT(0); + return NEWS_VAL_INVALID; + } +} |