diff options
author | GriffinR <griffin.g.richards@gmail.com> | 2021-10-17 03:00:48 -0400 |
---|---|---|
committer | GriffinR <griffin.g.richards@gmail.com> | 2021-10-17 03:00:48 -0400 |
commit | ece7ef3410eb9b114cf328426c4fc16c972f71c6 (patch) | |
tree | 1a6b3b96d60ccb13e4695e4c8ad1f9b56e9a3971 /src | |
parent | d0455485c3ea862d4089b2b4bb02bb00f3005599 (diff) |
Correct usage of MysteryEvent to MysteryGift
Diffstat (limited to 'src')
-rw-r--r-- | src/cable_club.c | 2 | ||||
-rw-r--r-- | src/easy_chat.c | 2 | ||||
-rwxr-xr-x | src/ereader_screen.c | 2 | ||||
-rw-r--r-- | src/field_specials.c | 4 | ||||
-rw-r--r-- | src/link_rfu_2.c | 2 | ||||
-rw-r--r-- | src/main_menu.c | 2 | ||||
-rwxr-xr-x | src/mevent2.c | 662 | ||||
-rw-r--r-- | src/mystery_event_msg.c | 22 | ||||
-rw-r--r-- | src/mystery_event_script.c | 24 | ||||
-rwxr-xr-x[-rw-r--r--] | src/mystery_gift.c | 1924 | ||||
-rw-r--r-- | src/mystery_gift_client.c (renamed from src/mevent_client.c) | 24 | ||||
-rw-r--r-- | src/mystery_gift_link.c (renamed from src/mevent_server_helpers.c) | 4 | ||||
-rw-r--r-- | src/mystery_gift_menu.c | 1618 | ||||
-rw-r--r-- | src/mystery_gift_scripts.c (renamed from src/mevent_scripts.c) | 6 | ||||
-rw-r--r-- | src/mystery_gift_server.c (renamed from src/mevent_server.c) | 6 | ||||
-rw-r--r-- | src/mystery_gift_view.c (renamed from src/wonder_transfer.c) | 6 | ||||
-rw-r--r-- | src/new_game.c | 2 | ||||
-rw-r--r-- | src/script.c | 2 | ||||
-rw-r--r-- | src/trade.c | 2 | ||||
-rw-r--r-- | src/union_room.c | 2 | ||||
-rw-r--r-- | src/wonder_news.c (renamed from src/mevent_news.c) | 4 |
21 files changed, 2161 insertions, 2161 deletions
diff --git a/src/cable_club.c b/src/cable_club.c index 69fcb660b..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 "mevent.h" +#include "mystery_gift.h" #include "script.h" #include "script_pokemon_util.h" #include "sound.h" 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 a76fb09c8..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" diff --git a/src/field_specials.c b/src/field_specials.c index 5d7829d12..2789411a5 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" diff --git a/src/link_rfu_2.c b/src/link_rfu_2.c index 0ab452a8d..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, diff --git a/src/main_menu.c b/src/main_menu.c index 8fd25abe1..b245a1666 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 diff --git a/src/mevent2.c b/src/mevent2.c deleted file mode 100755 index ce41a0fcd..000000000 --- a/src/mevent2.c +++ /dev/null @@ -1,662 +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 sStatsEnabled = 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); - -#define CALC_CRC(data) CalcCRC16WithTable((void *)&(data), sizeof(data)) - -void ClearMysteryGift(void) -{ - CpuFill32(0, &gSaveBlock1Ptr->mysteryGift, sizeof(gSaveBlock1Ptr->mysteryGift)); - ClearSavedWonderNewsMetadata(); // Clear is redundant, InitSavedWonderNews would be sufficient - InitQuestionnaireWords(); -} - -struct WonderNews *GetSavedWonderNews(void) -{ - return &gSaveBlock1Ptr->mysteryGift.news; -} - -struct WonderCard *GetSavedWonderCard(void) -{ - return &gSaveBlock1Ptr->mysteryGift.card; -} - -struct WonderCardMetadata *GetSavedWonderCardMetadata(void) -{ - return &gSaveBlock1Ptr->mysteryGift.cardMetadata; -} - -struct WonderNewsMetadata *GetSavedWonderNewsMetadata(void) -{ - return &gSaveBlock1Ptr->mysteryGift.newsMetadata; -} - -u16 *GetQuestionnaireWordsPtr(void) -{ - return gSaveBlock1Ptr->mysteryGift.questionnaireWords; -} - -// Equivalent to ClearSavedWonderCardAndRelated, but nothing else to clear -void ClearSavedWonderNewsAndRelated(void) -{ - ClearSavedWonderNews(); -} - -bool32 SaveWonderNews(const struct WonderNews *news) -{ - if (!ValidateWonderNews(news)) - return FALSE; - - ClearSavedWonderNews(); - gSaveBlock1Ptr->mysteryGift.news = *news; - gSaveBlock1Ptr->mysteryGift.newsCrc = CALC_CRC(gSaveBlock1Ptr->mysteryGift.news); - return TRUE; -} - -bool32 ValidateSavedWonderNews(void) -{ - if (CALC_CRC(gSaveBlock1Ptr->mysteryGift.news) != gSaveBlock1Ptr->mysteryGift.newsCrc) - return FALSE; - if (!ValidateWonderNews(&gSaveBlock1Ptr->mysteryGift.news)) - return FALSE; - - return TRUE; -} - -static bool32 ValidateWonderNews(const struct WonderNews *news) -{ - if (news->id == 0) - return FALSE; - - return TRUE; -} - -bool32 IsSendingSavedWonderNewsAllowed(void) -{ - const struct WonderNews *news = &gSaveBlock1Ptr->mysteryGift.news; - if (news->sendType == SEND_TYPE_DISALLOWED) - return FALSE; - - return TRUE; -} - -static void ClearSavedWonderNews(void) -{ - CpuFill32(0, GetSavedWonderNews(), sizeof(gSaveBlock1Ptr->mysteryGift.news)); - gSaveBlock1Ptr->mysteryGift.newsCrc = 0; -} - -static void ClearSavedWonderNewsMetadata(void) -{ - CpuFill32(0, GetSavedWonderNewsMetadata(), sizeof(gSaveBlock1Ptr->mysteryGift.newsMetadata)); - InitSavedWonderNews(); -} - -bool32 IsWonderNewsSameAsSaved(const u8 *news) -{ - const u8 *savedNews = (const u8 *)&gSaveBlock1Ptr->mysteryGift.news; - u32 i; - if (!ValidateSavedWonderNews()) - return FALSE; - - for (i = 0; i < sizeof(gSaveBlock1Ptr->mysteryGift.news); i++) - { - if (savedNews[i] != news[i]) - return FALSE; - } - - return TRUE; -} - -void ClearSavedWonderCardAndRelated(void) -{ - ClearSavedWonderCard(); - ClearSavedWonderCardMetadata(); - ClearSavedTrainerIds(); - ClearRamScript(); - ClearMysteryGiftFlags(); - ClearMysteryGiftVars(); - ClearEReaderTrainer(&gSaveBlock2Ptr->frontier.ereaderTrainer); -} - -bool32 SaveWonderCard(const struct WonderCard *card) -{ - struct WonderCardMetadata *metadata; - if (!ValidateWonderCard(card)) - return FALSE; - - 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; -} - -bool32 ValidateSavedWonderCard(void) -{ - if (gSaveBlock1Ptr->mysteryGift.cardCrc != CALC_CRC(gSaveBlock1Ptr->mysteryGift.card)) - return FALSE; - if (!ValidateWonderCard(&gSaveBlock1Ptr->mysteryGift.card)) - return FALSE; - if (!ValidateSavedRamScript()) - return FALSE; - - return TRUE; -} - -static bool32 ValidateWonderCard(const struct WonderCard *card) -{ - 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; -} - -bool32 IsSendingSavedWonderCardAllowed(void) -{ - const struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; - if (card->sendType == SEND_TYPE_DISALLOWED) - return FALSE; - - return TRUE; -} - -static void ClearSavedWonderCard(void) -{ - CpuFill32(0, &gSaveBlock1Ptr->mysteryGift.card, sizeof(gSaveBlock1Ptr->mysteryGift.card)); - gSaveBlock1Ptr->mysteryGift.cardCrc = 0; -} - -static void ClearSavedWonderCardMetadata(void) -{ - CpuFill32(0, GetSavedWonderCardMetadata(), sizeof(gSaveBlock1Ptr->mysteryGift.cardMetadata)); - gSaveBlock1Ptr->mysteryGift.cardMetadataCrc = 0; -} - -u16 GetWonderCardFlagID(void) -{ - if (ValidateSavedWonderCard()) - return gSaveBlock1Ptr->mysteryGift.card.flagId; - - return 0; -} - -void DisableWonderCardSending(struct WonderCard *card) -{ - if (card->sendType == SEND_TYPE_ALLOWED) - card->sendType = SEND_TYPE_DISALLOWED; -} - -static bool32 IsWonderCardFlagIDInValidRange(u16 flagId) -{ - if (flagId >= WONDER_CARD_FLAG_OFFSET && flagId < WONDER_CARD_FLAG_OFFSET + NUM_WONDER_CARD_FLAGS) - return TRUE; - - return FALSE; -} - -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) -{ - 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 int GetNumStampsInMetadata(const struct WonderCardMetadata *data, int size) -{ - 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; -} - -static bool32 IsStampInMetadata(const struct WonderCardMetadata *metadata, const u16 *stamp, int maxStamps) -{ - int i; - for (i = 0; i < maxStamps; i++) - { - 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 ValidateStamp(const u16 *stamp) -{ - 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 int GetNumStampsInSavedCard(void) -{ - struct WonderCard *card; - if (!ValidateSavedWonderCard()) - return 0; - - card = &gSaveBlock1Ptr->mysteryGift.card; - if (card->type != CARD_TYPE_STAMP) - return 0; - - return GetNumStampsInMetadata(&gSaveBlock1Ptr->mysteryGift.cardMetadata, card->maxStamps); -} - -bool32 MysteryGift_TrySaveStamp(const u16 *stamp) -{ - 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; - - for (i = 0; i < maxStamps; i++) - { - if (gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_ID][i] == 0 - && gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_SPECIES][i] == SPECIES_NONE) - { - gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_ID][i] = stamp[STAMP_ID]; - gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_SPECIES][i] = stamp[STAMP_SPECIES]; - return TRUE; - } - } - - return FALSE; -} - -#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) -{ - int i; - CpuFill32(0, data, sizeof(*data)); - data->validationVar = GAME_DATA_VALID_VAR; - data->validationFlag1 = 1; - data->validationFlag2 = 1; - - if (isWonderNews) - { - // 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; - } - - if (ValidateSavedWonderCard()) - { - data->flagId = GetSavedWonderCard()->flagId; - data->cardMetadata = *GetSavedWonderCardMetadata(); - data->maxStamps = GetSavedWonderCard()->maxStamps; - } - else - { - 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; -} - -bool32 MysteryGift_ValidateLinkGameData(const struct MysteryGiftLinkGameData *data, bool32 isWonderNews) -{ - if (data->validationVar != GAME_DATA_VALID_VAR) - return FALSE; - - if (!(data->validationFlag1 & 1)) - return FALSE; - - if (!(data->validationFlag2 & 1)) - return FALSE; - - if (!isWonderNews) - { - if (!(data->validationGiftType1 & GAME_DATA_VALID_GIFT_TYPE_1)) - return FALSE; - - if (!(data->validationGiftType2 & (GAME_DATA_VALID_GIFT_TYPE_2 | 0x180))) - return FALSE; - } - - return TRUE; -} - -u32 MysteryGift_CompareCardFlags(const u16 *flagId, const struct MysteryGiftLinkGameData *data, const void *unused) -{ - // 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; -} - -// 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) -{ - 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 (data->questionnaireWords[i] != words[i]) - return FALSE; - } - - return TRUE; -} - -static int GetNumStampsInLinkData(const struct MysteryGiftLinkGameData *data) -{ - return GetNumStampsInMetadata(&data->cardMetadata, data->maxStamps); -} - -u16 MysteryGift_GetCardStatFromLinkData(const struct MysteryGiftLinkGameData *data, u32 stat) -{ - switch (stat) - { - 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 void IncrementCardStat(u32 statType) -{ - struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; - if (card->type == CARD_TYPE_LINK_STAT) - { - u16 *stat = NULL; - switch (statType) - { - 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; - } - - if (stat == NULL) - AGB_ASSERT(0); - else if (++(*stat) > MAX_WONDER_CARD_STAT) - *stat = MAX_WONDER_CARD_STAT; - } -} - -u16 MysteryGift_GetCardStat(u32 stat) -{ - switch (stat) - { - case CARD_STAT_BATTLES_WON: - { - struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; - if (card->type == CARD_TYPE_LINK_STAT) - { - struct WonderCardMetadata *metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata; - return metadata->battlesWon; - } - break; - } - case CARD_STAT_BATTLES_LOST: - { - struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; - if (card->type == CARD_TYPE_LINK_STAT) - { - struct WonderCardMetadata *metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata; - return metadata->battlesLost; - } - break; - } - case CARD_STAT_NUM_TRADES: - { - struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; - if (card->type == CARD_TYPE_LINK_STAT) - { - struct WonderCardMetadata *metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata; - return metadata->numTrades; - } - break; - } - case CARD_STAT_NUM_STAMPS: - { - struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; - if (card->type == CARD_TYPE_STAMP) - return GetNumStampsInSavedCard(); - break; - } - case CARD_STAT_MAX_STAMPS: - { - struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; - if (card->type == CARD_TYPE_STAMP) - return card->maxStamps; - break; - } - } - - AGB_ASSERT(0); - return 0; -} - -void MysteryGift_DisableStats(void) -{ - sStatsEnabled = FALSE; -} - -bool32 MysteryGift_TryEnableStatsByFlagId(u16 flagId) -{ - sStatsEnabled = FALSE; - if (flagId == 0) - return FALSE; - - if (!ValidateSavedWonderCard()) - return FALSE; - - if (gSaveBlock1Ptr->mysteryGift.card.flagId != flagId) - return FALSE; - - sStatsEnabled = TRUE; - return TRUE; -} - -void MysteryGift_TryIncrementStat(u32 stat, u32 trainerId) -{ - if (sStatsEnabled) - { - switch (stat) - { - case CARD_STAT_NUM_TRADES: - IncrementCardStatForNewTrainer(CARD_STAT_NUM_TRADES, - trainerId, - gSaveBlock1Ptr->mysteryGift.trainerIds[1], - ARRAY_COUNT(gSaveBlock1Ptr->mysteryGift.trainerIds[1])); - break; - case CARD_STAT_BATTLES_WON: - IncrementCardStatForNewTrainer(CARD_STAT_BATTLES_WON, - trainerId, - gSaveBlock1Ptr->mysteryGift.trainerIds[0], - ARRAY_COUNT(gSaveBlock1Ptr->mysteryGift.trainerIds[0])); - break; - case CARD_STAT_BATTLES_LOST: - IncrementCardStatForNewTrainer(CARD_STAT_BATTLES_LOST, - trainerId, - gSaveBlock1Ptr->mysteryGift.trainerIds[0], - ARRAY_COUNT(gSaveBlock1Ptr->mysteryGift.trainerIds[0])); - break; - default: - AGB_ASSERT(0); - break; - } - } -} - -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++) - { - if (trainerIds[i] == trainerId) - 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]; - - trainerIds[0] = trainerId; - return FALSE; - } -} - -static void IncrementCardStatForNewTrainer(u32 stat, u32 trainerId, u32 *trainerIds, int size) -{ - if (RecordTrainerId(trainerId, trainerIds, size)) - IncrementCardStat(stat); -} 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 7b5e8ebe5..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,12 +65,12 @@ static bool32 RunMysteryEventScriptCommand(struct ScriptContext *ctx) return FALSE; } -void InitMysteryGiftScriptContext(u8 *script) +void InitMysteryEventScriptContext(u8 *script) { InitMysteryEventScript(&sMysteryEventScriptContext, script); } -bool32 RunMysteryGiftScriptContextCommand(u32 *script) +bool32 RunMysteryEventScriptContextCommand(u32 *script) { bool32 ret = RunMysteryEventScriptCommand(&sMysteryEventScriptContext); *script = sMysteryEventScriptContext.data[2]; @@ -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 bc6e8c44b..1df6533d9 100644..100755 --- a/src/mystery_gift.c +++ b/src/mystery_gift.c @@ -1,1618 +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 "wonder_transfer.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" - -#define LIST_MENU_TILE_NUM 10 -#define LIST_MENU_PAL_NUM 224 +#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" -static void LoadMysteryGiftTextboxBorder(u8 bgId); -static void CreateMysteryGiftTask(void); -static void Task_MysteryGift(u8 taskId); +static EWRAM_DATA bool32 sStatsEnabled = FALSE; -EWRAM_DATA static 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 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"); +#define CALC_CRC(data) CalcCRC16WithTable((void *)&(data), sizeof(data)) -struct MysteryGiftTaskData +void ClearMysteryGift(void) { - 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 -}; + CpuFill32(0, &gSaveBlock1Ptr->mysteryGift, sizeof(gSaveBlock1Ptr->mysteryGift)); + ClearSavedWonderNewsMetadata(); // Clear is redundant, InitSavedWonderNews would be sufficient + InitQuestionnaireWords(); +} -static const struct WindowTemplate sWindowTemplate_GiftSelect_1Option = { - .bg = 0, - .tilemapLeft = 22, - .tilemapTop = 15, - .width = 7, - .height = 4, - .paletteNum = 12, - .baseBlock = 0x0155 -}; +struct WonderNews *GetSavedWonderNews(void) +{ + return &gSaveBlock1Ptr->mysteryGift.news; +} -static const struct ListMenuItem sListMenuItems_CardsOrNews[] = { - { gText_WonderCards, 0 }, - { gText_WonderNews, 1 }, - { gText_Exit3, LIST_CANCEL } -}; +struct WonderCard *GetSavedWonderCard(void) +{ + return &gSaveBlock1Ptr->mysteryGift.card; +} -static const struct ListMenuItem sListMenuItems_WirelessOrFriend[] = { - { gText_WirelessCommunication, 0 }, - { gText_Friend2, 1 }, - { gText_Cancel2, LIST_CANCEL } -}; +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, LIST_CANCEL } -}; +u16 *GetQuestionnaireWordsPtr(void) +{ + return gSaveBlock1Ptr->mysteryGift.questionnaireWords; +} -static const struct ListMenuItem sListMenuItems_ReceiveToss[] = { - { gText_Receive, 0 }, - { gText_Toss, 2 }, - { gText_Cancel2, LIST_CANCEL } -}; +// 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, LIST_CANCEL } -}; +bool32 SaveWonderNews(const struct WonderNews *news) +{ + if (!ValidateWonderNews(news)) + return FALSE; -static const struct ListMenuItem sListMenuItems_Receive[] = { - { gText_Receive, 0 }, - { gText_Cancel2, LIST_CANCEL } -}; + 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) 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 }; + return TRUE; +} -static void VBlankCB_MysteryGiftEReader(void) +static void ClearSavedWonderNews(void) { - ProcessSpriteCopyRequests(); - LoadOam(); - TransferPlttBuffer(); + CpuFill32(0, GetSavedWonderNews(), sizeof(gSaveBlock1Ptr->mysteryGift.news)); + gSaveBlock1Ptr->mysteryGift.newsCrc = 0; } -void CB2_MysteryGiftEReader(void) +static void ClearSavedWonderNewsMetadata(void) { - RunTasks(); - RunTextPrinters(); - AnimateSprites(); - BuildOamBuffer(); + CpuFill32(0, GetSavedWonderNewsMetadata(), sizeof(gSaveBlock1Ptr->mysteryGift.newsMetadata)); + InitSavedWonderNews(); } -static bool32 HandleMysteryGiftOrEReaderSetup(s32 isEReader) +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)); - - 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; + if (savedNews[i] != news[i]) + return FALSE; } - return FALSE; + return TRUE; } -void CB2_InitMysteryGift(void) +void ClearSavedWonderCardAndRelated(void) { - if (HandleMysteryGiftOrEReaderSetup(FALSE)) - { - SetMainCallback2(CB2_MysteryGiftEReader); - gGiftIsFromEReader = FALSE; - CreateMysteryGiftTask(); - } - RunTasks(); + ClearSavedWonderCard(); + ClearSavedWonderCardMetadata(); + ClearSavedTrainerIds(); + ClearRamScript(); + ClearMysteryGiftFlags(); + ClearMysteryGiftVars(); + ClearEReaderTrainer(&gSaveBlock2Ptr->frontier.ereaderTrainer); } -void CB2_InitEReader(void) +bool32 SaveWonderCard(const struct WonderCard *card) { - if (HandleMysteryGiftOrEReaderSetup(TRUE)) - { - SetMainCallback2(CB2_MysteryGiftEReader); - gGiftIsFromEReader = TRUE; - CreateEReaderTask(); - } -} + 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 isEReader, bool32 useCancel) +bool32 ValidateSavedWonderCard(void) { - 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; - } + 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, 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); + 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; - - FillBgTilemapBufferRect(bg, 0x003, 0, 0, 32, 2, 0x11); + const struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->sendType == SEND_TYPE_DISALLOWED) + return FALSE; - 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); - } - } + return TRUE; } -static void ClearScreenInBg0(bool32 ignoreTopTwoRows) +static void ClearSavedWonderCard(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, &gSaveBlock1Ptr->mysteryGift.card, sizeof(gSaveBlock1Ptr->mysteryGift.card)); + gSaveBlock1Ptr->mysteryGift.cardCrc = 0; } -void AddTextPrinterToWindow1(const u8 *str) +static void ClearSavedWonderCardMetadata(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); + CpuFill32(0, GetSavedWonderCardMetadata(), sizeof(gSaveBlock1Ptr->mysteryGift.cardMetadata)); + gSaveBlock1Ptr->mysteryGift.cardMetadataCrc = 0; } -static void ClearTextWindow(void) +u16 GetWonderCardFlagID(void) { - rbox_fill_rectangle(1); - ClearWindowTilemap(1); - CopyWindowToVram(1, 1); + if (ValidateSavedWonderCard()) + return gSaveBlock1Ptr->mysteryGift.card.flagId; + + return 0; } -#define DOWN_ARROW_X 208 -#define DOWN_ARROW_Y 20 +void DisableWonderCardSending(struct WonderCard *card) +{ + if (card->sendType == SEND_TYPE_ALLOWED) + card->sendType = SEND_TYPE_DISALLOWED; +} -bool32 PrintMysteryGiftMenuMessage(u8 *textState, const u8 *str) +static bool32 IsWonderCardFlagIDInValidRange(u16 flagId) { - 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(); + 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, DOWN_ARROW_X, DOWN_ARROW_Y, 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, DOWN_ARROW_X, DOWN_ARROW_Y, 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; } -// Unused -static bool32 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, LIST_MENU_TILE_NUM, LIST_MENU_PAL_NUM); - if (response != LIST_NOTHING_CHOSEN) - { - ClearWindowTilemap(2); - CopyWindowToVram(2, 1); - } - return response; + return GetNumStampsInMetadata(&gSaveBlock1Ptr->mysteryGift.cardMetadata, card->maxStamps); } -s8 DoMysteryGiftYesNo(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; - switch (*textState) + if (IsStampInMetadata(&gSaveBlock1Ptr->mysteryGift.cardMetadata, stamp, maxStamps)) + return FALSE; + + for (i = 0; i < maxStamps; i++) { - 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) + 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 0xFF: - *textState = 0; - rbox_fill_rectangle(*windowId); - ClearWindowTilemap(*windowId); - CopyWindowToVram(*windowId, 1); - RemoveWindow(*windowId); - return MENU_B_PRESSED; } - return MENU_NOTHING_CHOSEN; + return FALSE; } -// Handle the "Receive/Send/Toss" menu that appears when selecting Wonder Card/News -static s32 HandleGiftSelectMenu(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: - // 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; + // 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 LIST_NOTHING_CHOSEN; -} - -static bool32 ValidateCardOrNews(bool32 isWonderNews) -{ - if (!isWonderNews) - return ValidateSavedWonderCard(); + if (ValidateSavedWonderCard()) + { + data->flagId = GetSavedWonderCard()->flagId; + data->cardMetadata = *GetSavedWonderCardMetadata(); + data->maxStamps = GetSavedWonderCard()->maxStamps; + } 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; + data->flagId = 0; } - return FALSE; -} + for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++) + data->questionnaireWords[i] = gSaveBlock1Ptr->mysteryGift.questionnaireWords[i]; -static bool32 ClearSavedNewsOrCard(bool32 isWonderNews) -{ - if (!isWonderNews) - ClearSavedWonderCardAndRelated(); - else - ClearSavedWonderNewsAndRelated(); - return TRUE; + 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 ExitWonderCardOrNews(bool32 isWonderNews, bool32 useCancel) +bool32 MysteryGift_ValidateLinkGameData(const struct MysteryGiftLinkGameData *data, bool32 isWonderNews) { + if (data->validationVar != GAME_DATA_VALID_VAR) + return FALSE; + + if (!(data->validationFlag1 & 1)) + return FALSE; + + if (!(data->validationFlag2 & 1)) + return FALSE; + if (!isWonderNews) { - if (WonderCard_Exit(useCancel)) - { - WonderCard_Destroy(); - return TRUE; - } - else - { + if (!(data->validationGiftType1 & GAME_DATA_VALID_GIFT_TYPE_1)) return FALSE; - } - } - else - { - if (WonderNews_Exit(useCancel)) - { - WonderNews_Destroy(); - return TRUE; - } - else - { + + if (!(data->validationGiftType2 & (GAME_DATA_VALID_GIFT_TYPE_2 | 0x180))) return FALSE; - } } + + return TRUE; } -static s32 AskDiscardGift(u8 * textState, u16 * windowId, bool32 isWonderNews) +u32 MysteryGift_CompareCardFlags(const u16 *flagId, const struct MysteryGiftLinkGameData *data, const void *unused) { - if (!isWonderNews) - return DoMysteryGiftYesNo(textState, windowId, TRUE, gText_IfThrowAwayCardEventWontHappen); - else - return DoMysteryGiftYesNo(textState, windowId, TRUE, gText_OkayToDiscardNews); + // 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 PrintThrownAway(u8 * textState, bool32 isWonderNews) +// 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 (!isWonderNews) - return PrintMysteryGiftMenuMessage(textState, gText_WonderCardThrownAway); - else - return PrintMysteryGiftMenuMessage(textState, gText_WonderNewsThrownAway); + 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; } -static bool32 SaveOnMysteryGiftMenu(u8 * state) +bool32 MysteryGift_DoesQuestionnaireMatch(const struct MysteryGiftLinkGameData *data, const u16 *words) { - switch (*state) + int i; + for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++) { - 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; + if (data->questionnaireWords[i] != words[i]) + return FALSE; } - return FALSE; + return TRUE; } -static const u8 * GetClientResultMessage(bool32 * successMsg, bool8 isWonderNews, bool8 sourceIsFriend, u32 msgId) +static int GetNumStampsInLinkData(const struct MysteryGiftLinkGameData *data) { - const u8 * msg = NULL; - *successMsg = FALSE; + return GetNumStampsInMetadata(&data->cardMetadata, data->maxStamps); +} - switch (msgId) +u16 MysteryGift_GetCardStatFromLinkData(const struct MysteryGiftLinkGameData *data, u32 stat) +{ + switch (stat) { - 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; + 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; } - - return msg; } -static bool32 PrintSuccessMessage(u8 * state, const u8 * msg, u16 * timer) +static void IncrementCardStat(u32 statType) { - switch (*state) + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type == CARD_TYPE_LINK_STAT) { - 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()) + u16 *stat = NULL; + switch (statType) { - *state = 0; - ClearTextWindow(); - return TRUE; + 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; + + if (stat == NULL) + AGB_ASSERT(0); + else if (++(*stat) > MAX_WONDER_CARD_STAT) + *stat = MAX_WONDER_CARD_STAT; } - return FALSE; } -static const u8 * GetServerResultMessage(bool32 * wonderSuccess, bool8 sourceIsFriend, u32 msgId) +u16 MysteryGift_GetCardStat(u32 stat) { - const u8 * result = gText_CommunicationError; - *wonderSuccess = FALSE; - switch (msgId) + switch (stat) { - 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; + case CARD_STAT_BATTLES_WON: + { + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type == CARD_TYPE_LINK_STAT) + { + struct WonderCardMetadata *metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata; + return metadata->battlesWon; + } break; - case SVR_MSG_COMM_ERROR: - result = gText_CommunicationError; + } + case CARD_STAT_BATTLES_LOST: + { + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type == CARD_TYPE_LINK_STAT) + { + struct WonderCardMetadata *metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata; + return metadata->battlesLost; + } break; - case SVR_MSG_GIFT_SENT_1: - result = gText_GiftSentTo; + } + case CARD_STAT_NUM_TRADES: + { + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type == CARD_TYPE_LINK_STAT) + { + struct WonderCardMetadata *metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata; + return metadata->numTrades; + } break; - case SVR_MSG_GIFT_SENT_2: - result = gText_GiftSentTo; + } + case CARD_STAT_NUM_STAMPS: + { + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type == CARD_TYPE_STAMP) + return GetNumStampsInSavedCard(); break; - case SVR_MSG_CANT_SEND_GIFT_2: - result = gText_CantSendGiftToTrainer; + } + case CARD_STAT_MAX_STAMPS: + { + struct WonderCard *card = &gSaveBlock1Ptr->mysteryGift.card; + if (card->type == CARD_TYPE_STAMP) + return card->maxStamps; break; } - return result; + } + + AGB_ASSERT(0); + return 0; } -static bool32 PrintServerResultMessage(u8 * state, u16 * timer, bool8 sourceIsFriend, u32 msgId) +void MysteryGift_DisableStats(void) { - bool32 wonderSuccess; - const u8 * str = GetServerResultMessage(&wonderSuccess, sourceIsFriend, msgId); - if (wonderSuccess) - return PrintSuccessMessage(state, str, timer); - else - return PrintMysteryGiftMenuMessage(state, str); + sStatsEnabled = FALSE; } -// States for Task_MysteryGift. -// CLIENT states are for when the player is receiving a gift, and use mevent_client.c link functions. -// SERVER states are for when the player is sending a gift, and use mevent_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) +bool32 MysteryGift_TryEnableStatsByFlagId(u16 flagId) { - 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); + sStatsEnabled = FALSE; + if (flagId == 0) + return FALSE; + + if (!ValidateSavedWonderCard()) + return FALSE; + + if (gSaveBlock1Ptr->mysteryGift.card.flagId != flagId) + return FALSE; + + sStatsEnabled = TRUE; + return TRUE; } -static void Task_MysteryGift(u8 taskId) +void MysteryGift_TryIncrementStat(u32 stat, u32 trainerId) { - struct MysteryGiftTaskData *data = (void *)gTasks[taskId].data; - u32 successMsg, input; - const u8 *msg; - - switch (data->state) + if (sStatsEnabled) { - 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)) + switch (stat) { - case 0: // "Wonder Cards" - data->isWonderNews = FALSE; - if (ValidateSavedWonderCard() == TRUE) - data->state = MG_STATE_LOAD_GIFT; - else - data->state = MG_STATE_DONT_HAVE_ANY; + case CARD_STAT_NUM_TRADES: + IncrementCardStatForNewTrainer(CARD_STAT_NUM_TRADES, + trainerId, + gSaveBlock1Ptr->mysteryGift.trainerIds[1], + ARRAY_COUNT(gSaveBlock1Ptr->mysteryGift.trainerIds[1])); 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; + case CARD_STAT_BATTLES_WON: + IncrementCardStatForNewTrainer(CARD_STAT_BATTLES_WON, + trainerId, + gSaveBlock1Ptr->mysteryGift.trainerIds[0], + ARRAY_COUNT(gSaveBlock1Ptr->mysteryGift.trainerIds[0])); break; - case LIST_CANCEL: - data->state = MG_STATE_EXIT; + case CARD_STAT_BATTLES_LOST: + IncrementCardStatForNewTrainer(CARD_STAT_BATTLES_LOST, + trainerId, + gSaveBlock1Ptr->mysteryGift.trainerIds[0], + ARRAY_COUNT(gSaveBlock1Ptr->mysteryGift.trainerIds[0])); 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); - } + default: + AGB_ASSERT(0); 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: +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++) { - // 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; + if (trainerIds[i] == trainerId) 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; + 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; + } } -static void LoadMysteryGiftTextboxBorder(u8 bgId) +static void IncrementCardStatForNewTrainer(u32 stat, u32 trainerId, u32 *trainerIds, int size) { - DecompressAndLoadBgGfxUsingHeap(bgId, sTextboxBorder_Gfx, 0x100, 0, 0); + if (RecordTrainerId(trainerId, trainerIds, size)) + IncrementCardStat(stat); } diff --git a/src/mevent_client.c b/src/mystery_gift_client.c index e260f073f..adf3ce8a6 100644 --- a/src/mevent_client.c +++ b/src/mystery_gift_client.c @@ -4,9 +4,9 @@ #include "overworld.h" #include "script.h" #include "battle_tower.h" -#include "mevent.h" +#include "mystery_gift.h" #include "mystery_event_script.h" -#include "mevent_client.h" +#include "mystery_gift_client.h" enum { FUNC_INIT, @@ -15,8 +15,8 @@ enum { FUNC_SEND, FUNC_RUN, FUNC_WAIT, - FUNC_RUN_GIFT_SCRIPT, - FUNC_RUN_BUFF_SCRIPT, + FUNC_RUN_MEVENT, + FUNC_RUN_BUFFER, }; EWRAM_DATA static struct MysteryGiftClient * sClient = NULL; @@ -222,8 +222,8 @@ static u32 Client_Run(struct MysteryGiftClient * client) MysteryGiftClient_InitSendWord(client, MG_LINKID_RESPONSE, TRUE); } break; - case CLI_RUN_GIFT_SCRIPT: - client->funcId = FUNC_RUN_GIFT_SCRIPT; + case CLI_RUN_MEVENT_SCRIPT: + client->funcId = FUNC_RUN_MEVENT; client->funcState = 0; break; case CLI_SAVE_STAMP: @@ -238,7 +238,7 @@ static u32 Client_Run(struct MysteryGiftClient * client) break; case CLI_RUN_BUFFER_SCRIPT: memcpy(gDecompressionBuffer, client->recvBuffer, MG_LINK_BUFFER_SIZE); - client->funcId = FUNC_RUN_BUFF_SCRIPT; + client->funcId = FUNC_RUN_BUFFER; client->funcState = 0; break; } @@ -256,16 +256,16 @@ static u32 Client_Wait(struct MysteryGiftClient * client) return CLI_RET_ACTIVE; } -static u32 Client_RunGiftScript(struct MysteryGiftClient * client) +static u32 Client_RunMysteryEventScript(struct MysteryGiftClient * client) { switch (client->funcState) { case 0: - InitMysteryGiftScriptContext(client->recvBuffer); + InitMysteryEventScriptContext(client->recvBuffer); client->funcState++; break; case 1: - if (!RunMysteryGiftScriptContextCommand(&client->param)) + if (!RunMysteryEventScriptContextCommand(&client->param)) { client->funcId = FUNC_RUN; client->funcState = 0; @@ -296,8 +296,8 @@ static u32 MysteryGiftClient_CallFunc(struct MysteryGiftClient * client) [FUNC_SEND] = Client_Send, [FUNC_RUN] = Client_Run, [FUNC_WAIT] = Client_Wait, - [FUNC_RUN_GIFT_SCRIPT] = Client_RunGiftScript, - [FUNC_RUN_BUFF_SCRIPT] = Client_RunBufferScript + [FUNC_RUN_MEVENT] = Client_RunMysteryEventScript, + [FUNC_RUN_BUFFER] = Client_RunBufferScript }; return funcs[client->funcId](client); } diff --git a/src/mevent_server_helpers.c b/src/mystery_gift_link.c index c1fe88368..55f4b7852 100644 --- a/src/mevent_server_helpers.c +++ b/src/mystery_gift_link.c @@ -8,8 +8,8 @@ #include "script.h" #include "battle_tower.h" #include "mystery_event_script.h" -#include "mevent.h" -#include "mevent_server_helpers.h" +#include "mystery_gift.h" +#include "mystery_gift_link.h" /* Handles the link connection functions used by the Mystery Gift client/server. 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/mevent_scripts.c b/src/mystery_gift_scripts.c index 23e0d97a5..fcd7f568d 100644 --- a/src/mevent_scripts.c +++ b/src/mystery_gift_scripts.c @@ -1,7 +1,7 @@ #include "global.h" -#include "mevent_client.h" -#include "mevent_server.h" -#include "mevent.h" +#include "mystery_gift_client.h" +#include "mystery_gift_server.h" +#include "mystery_gift.h" static const u8 sText_CanceledReadingCard[] = _("Canceled reading\nthe Card."); diff --git a/src/mevent_server.c b/src/mystery_gift_server.c index 5313e02f7..0e0acb642 100644 --- a/src/mevent_server.c +++ b/src/mystery_gift_server.c @@ -1,9 +1,9 @@ #include "global.h" #include "malloc.h" #include "script.h" -#include "mevent.h" -#include "mevent_server.h" -#include "mevent_server_helpers.h" +#include "mystery_gift.h" +#include "mystery_gift_server.h" +#include "mystery_gift_link.h" enum { FUNC_INIT, diff --git a/src/wonder_transfer.c b/src/mystery_gift_view.c index c1fc69ca7..1bd3e2a21 100644 --- a/src/wonder_transfer.c +++ b/src/mystery_gift_view.c @@ -11,11 +11,11 @@ #include "text_window.h" #include "string_util.h" #include "link_rfu.h" -#include "mevent.h" #include "mystery_gift.h" -#include "wonder_transfer.h" +#include "mystery_gift_menu.h" +#include "mystery_gift_view.h" #include "constants/rgb.h" -#include "constants/mevent.h" +#include "constants/mystery_gift.h" struct WonderGraphics { diff --git a/src/new_game.c b/src/new_game.c index c4622820c..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[]; diff --git a/src/script.c b/src/script.c index a3e223768..b10e0db49 100644 --- a/src/script.c +++ b/src/script.c @@ -1,7 +1,7 @@ #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" diff --git a/src/trade.c b/src/trade.c index acae292e5..3fdb15c45 100644 --- a/src/trade.c +++ b/src/trade.c @@ -19,8 +19,8 @@ #include "load_save.h" #include "mail.h" #include "main.h" -#include "mevent.h" #include "mystery_gift.h" +#include "mystery_gift_menu.h" #include "overworld.h" #include "palette.h" #include "party_menu.h" diff --git a/src/union_room.c b/src/union_room.c index 1a7ccc8e3..881a1d58e 100644 --- a/src/union_room.c +++ b/src/union_room.c @@ -23,8 +23,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" diff --git a/src/mevent_news.c b/src/wonder_news.c index 27b22566d..ec93d293e 100644 --- a/src/mevent_news.c +++ b/src/wonder_news.c @@ -1,8 +1,8 @@ #include "global.h" -#include "mevent.h" +#include "mystery_gift.h" #include "random.h" #include "event_data.h" -#include "mevent_news.h" +#include "wonder_news.h" /* Wonder News related functions. |