From a3903b61323925368223f891743e1c9a0f618d84 Mon Sep 17 00:00:00 2001 From: Philippe Symons Date: Tue, 4 Mar 2025 20:13:02 +0100 Subject: [PATCH] Add mystery gift --- include/menu/MenuEntries.h | 4 +- include/menu/MenuFunctions.h | 11 ++++- libpokemegb | 2 +- src/menu/MenuEntries.cpp | 22 +++++---- src/menu/MenuFunctions.cpp | 92 ++++++++++++++++++++++++++++++++++-- 5 files changed, 115 insertions(+), 16 deletions(-) diff --git a/include/menu/MenuEntries.h b/include/menu/MenuEntries.h index 4038a2b..79ff34e 100755 --- a/include/menu/MenuEntries.h +++ b/include/menu/MenuEntries.h @@ -15,8 +15,8 @@ extern const uint32_t gen2MenuEntriesSize; extern MenuItemData gen2CrystalMenuEntries[]; extern const uint32_t gen2CrystalMenuEntriesSize; -extern MenuItemData gen2DecorationMenuEntries[]; -extern const uint32_t gen2DecorationMenuEntriesSize; +extern MenuItemData gen2MysteryGiftMenuEntries[]; +extern const uint32_t gen2MysteryGiftMenuEntriesSize; extern MenuItemData backupRestoreMenuEntries[]; extern const uint32_t backupRestoreMenuEntriesSize; diff --git a/include/menu/MenuFunctions.h b/include/menu/MenuFunctions.h index f46f841..7164078 100755 --- a/include/menu/MenuFunctions.h +++ b/include/menu/MenuFunctions.h @@ -32,7 +32,7 @@ void goToGen1MovesMenu(void* context, const void* param); void goToGen1DistributionPokemonMenu(void* context, const void* param); void goToGen2DistributionPokemonMenu(void* context, const void* param); void goToGen2PCNYDistributionPokemonMenu(void* context, const void* param); -void goToGen2DecorationMenu(void* context, const void* param); +void goToGen2MysteryGiftMenu(void* context, const void* param); void goToBackupRestoreMenu(void* context, const void* param); /** @@ -116,6 +116,15 @@ void askConfirmationWipeSave(void* context, const void* param); */ void resetRTC(void* context, const void* param); +/** + * @brief This function will activate the mystery gift functionality. + * If the player hasn't hit the 5-gift limit yet, he/she will obtain a random mystery gift + * + * @param context a MenuScene* context + * @param param a nullpointer (dummy param) + */ +void gen2ReceiveMysteryGift(void* context, const void* param); + void printClock(void* context, const void* param); #endif \ No newline at end of file diff --git a/libpokemegb b/libpokemegb index 58fa35f..067246a 160000 --- a/libpokemegb +++ b/libpokemegb @@ -1 +1 @@ -Subproject commit 58fa35f882a83f2baaa0c2aded494189f7b22372 +Subproject commit 067246a68abd5bc61902573994c055ecc4dfcf15 diff --git a/src/menu/MenuEntries.cpp b/src/menu/MenuEntries.cpp index abbbeb1..16d6b78 100755 --- a/src/menu/MenuEntries.cpp +++ b/src/menu/MenuEntries.cpp @@ -59,8 +59,8 @@ MenuItemData gen2MenuEntries[] = { .onConfirmAction = goToGen2PCNYDistributionPokemonMenu }, { - .title = "Unlock Decoration", - .onConfirmAction = goToGen2DecorationMenu + .title = "Mystery Gift", + .onConfirmAction = goToGen2MysteryGiftMenu }, { .title = "Gen 3 Transfer Info", @@ -100,8 +100,8 @@ MenuItemData gen2CrystalMenuEntries[] = { .onConfirmAction = gen2ReceiveGSBall }, { - .title = "Unlock Decoration", - .onConfirmAction = goToGen2DecorationMenu + .title = "Mystery Gift", + .onConfirmAction = goToGen2MysteryGiftMenu }, { .title = "Gen 3 Transfer Info", @@ -123,25 +123,29 @@ MenuItemData gen2CrystalMenuEntries[] = { const uint32_t gen2CrystalMenuEntriesSize = sizeof(gen2CrystalMenuEntries); -MenuItemData gen2DecorationMenuEntries[] = { +MenuItemData gen2MysteryGiftMenuEntries[] = { { - .title = "Pikachu Bed", + .title = "Get Mystery Gift", + .onConfirmAction = gen2ReceiveMysteryGift + }, + { + .title = "Get Pikachu Bed", .onConfirmAction = gen2SetEventFlag, .itemParam = &GEN2_EVENTFLAG_DECORATION_PIKACHU_BED }, { - .title = "Unown Doll", + .title = "Get Unown Doll", .onConfirmAction = gen2SetEventFlag, .itemParam = &GEN2_EVENTFLAG_DECORATION_UNOWN_DOLL }, { - .title = "Tentacool Doll", + .title = "Get Tentacool Doll", .onConfirmAction = gen2SetEventFlag, .itemParam = &GEN2_EVENTFLAG_DECORATION_TENTACOOL_DOLL } }; -const uint32_t gen2DecorationMenuEntriesSize = sizeof(gen2DecorationMenuEntries); +const uint32_t gen2MysteryGiftMenuEntriesSize = sizeof(gen2MysteryGiftMenuEntries); MenuItemData backupRestoreMenuEntries[] = { { diff --git a/src/menu/MenuFunctions.cpp b/src/menu/MenuFunctions.cpp index 0a13305..66923e4 100755 --- a/src/menu/MenuFunctions.cpp +++ b/src/menu/MenuFunctions.cpp @@ -7,6 +7,7 @@ #include "scenes/SelectFileScene.h" #include "scenes/SceneManager.h" #include "gen2/Gen2GameReader.h" +#include "gen2/Gen2Items.h" #include "transferpak/TransferPakManager.h" #include "transferpak/TransferPakRomReader.h" #include "transferpak/TransferPakSaveManager.h" @@ -219,12 +220,12 @@ void goToGen2PCNYDistributionPokemonMenu(void* context, const void* param) goToDistributionPokemonListMenu(context, DistributionPokemonListType::GEN2_POKEMON_CENTER_NEW_YORK); } -void goToGen2DecorationMenu(void* context, const void* param) +void goToGen2MysteryGiftMenu(void* context, const void* param) { MenuScene* scene = static_cast(context); auto newSceneContext = new MenuSceneContext{ - .menuEntries = gen2DecorationMenuEntries, - .numMenuEntries = gen2DecorationMenuEntriesSize / sizeof(gen2DecorationMenuEntries[0]) + .menuEntries = gen2MysteryGiftMenuEntries, + .numMenuEntries = gen2MysteryGiftMenuEntriesSize / sizeof(gen2MysteryGiftMenuEntries[0]) }; scene->getDependencies().sceneManager.switchScene(SceneType::MENU, deleteMenuSceneContext, newSceneContext); @@ -735,7 +736,28 @@ void gen2SetEventFlag(void* context, const void* param) } else { + Gen2MysteryGiftManager mysteryGiftManager = gameReader.getMysteryGiftManager(); gameReader.setEventFlag(eventFlagIndex, true); + + // For the decoration eventflags, also set the mysterygift decorationsReceived flag. + // PokeMe64 has allowed to obtain these 3 decorations directly from the main menu from before version 0.3. + // to keep this funtionality intact while also supporting mystery gift, we need to ensure these mystery gift flags are + // maintained correctly. + switch(eventFlagIndex) + { + case GEN2_EVENTFLAG_DECORATION_PIKACHU_BED: + mysteryGiftManager.setDecorationIDReceivedFlag((uint8_t)Gen2Decoration::PIKACHU_BED); + break; + case GEN2_EVENTFLAG_DECORATION_TENTACOOL_DOLL: + mysteryGiftManager.setDecorationIDReceivedFlag((uint8_t)Gen2Decoration::TENTACOOL_DOLL); + break; + case GEN2_EVENTFLAG_DECORATION_UNOWN_DOLL: + mysteryGiftManager.setDecorationIDReceivedFlag((uint8_t)Gen2Decoration::UNOWN_DOLL); + break; + default: + break; + } + gameReader.finishSave(); tpakManager.finishWrites(); @@ -808,6 +830,70 @@ void resetRTC(void* context, const void* param) scene->showDialog(diag); } +void gen2ReceiveMysteryGift(void* context, const void* param) +{ + MenuScene* scene = static_cast(context); + const char* trainerName; + + auto diag = new DialogData{ + .shouldDeleteWhenDone = true + }; + + if(scene->getDependencies().generation != 2) + { + setDialogDataText(*diag, "Sorry! This is only supported for Gen 2 Pokémon games!"); + scene->showDialog(diag); + return; + } + + const Gen2GameType gameType = static_cast(scene->getDependencies().specificGenVersion); + const Gen2LocalizationLanguage language = static_cast(scene->getDependencies().localization); + TransferPakManager& tpakManager = scene->getDependencies().tpakManager; + TransferPakRomReader romReader(tpakManager); + TransferPakSaveManager saveManager(tpakManager); + TransferPakRTCReader rtcReader(tpakManager); + Gen2GameReader gameReader(romReader, saveManager, gameType, language); + Gen2MysteryGiftManager mysteryGiftManager = gameReader.getMysteryGiftManager(); + + tpakManager.setRAMEnabled(true); + trainerName = gameReader.getTrainerName(); + if(!mysteryGiftManager.isUnlocked()) + { + mysteryGiftManager.unlock(); + } + + const MysteryGiftSelection selectedGift = selectRandomGift(); + MysteryGiftResult result = mysteryGiftManager.obtain(gameReader, rtcReader, selectedGift); + + switch(result) + { + case MYSTERYGIFT_RESULT_DECORATION: + setDialogDataText(*diag, "A %s was transferred to %s's house!", getGen2DecorationString((Gen2Decoration)selectedGift.decorationID), trainerName); + break; + case MYSTERYGIFT_RESULT_ITEM_ITEMPOCKET: + setDialogDataText(*diag, "%s received a %s! %s put the %s in the ITEM POCKET.", trainerName, getGen2ItemString((Gen2Items)selectedGift.itemID), trainerName, getGen2ItemString((Gen2Items)selectedGift.itemID)); + break; + case MYSTERYGIFT_RESULT_ITEM_BALLPOCKET: + setDialogDataText(*diag, "%s received a %s! %s put the %s in the BALL POCKET.", trainerName, getGen2ItemString((Gen2Items)selectedGift.itemID), trainerName, getGen2ItemString((Gen2Items)selectedGift.itemID)); + break; + case MYSTERYGIFT_RESULT_ERROR_NOT_UNLOCKED: + // should never happen, given that we unlocked it earlier in this function + setDialogDataText(*diag, "Sorry! It seems you don't have access to Mystery Gift yet! Unlock it and try again!"); + break; + case MYSTERYGIFT_RESULT_ERROR_TOO_MANY_GIFTS: + setDialogDataText(*diag, "Sorry! I'm out of gifts today. Try again tomorrow!"); + break; + case MYSTERYGIFT_RESULT_ERROR_NO_ROOM_FOR_ITEM: + setDialogDataText(*diag, "It seems you have no room for the item! Please get rid of an item first!"); + break; + } + + gameReader.finishSave(); + tpakManager.finishWrites(); + tpakManager.setRAMEnabled(false); + scene->showDialog(diag); +} + void printClock(void* context, const void* param) { MenuScene* scene = static_cast(context);