Add support for legendary fusion (#3274)
* Legendary Mon Fusion Evolution Compatibility Added Kyurem, Calyrex, and Necrozma Fusions have been implemented, however, the animation for the the process is incomplete, the party menu screen needs to be updated while the screen is whited out and it has proved beyond me right now. Smh * Added Fusion Move Prompts Handles cases for learning the fusion moves from the other fused mon and deleting the move when you unfuse (plus learning confusion (well a set choice in the data struct) if there are no moves left after deleting one) * Fix Bug With Fusion Mon Move Learning If the main fusion came after the fused mon in the party order it would try to teach the move to the next member in the party * Apply suggestions from code review Co-authored-by: LOuroboros <lunosouroboros@gmail.com> * Fix build * Fix fusion items being used up * Fixed animations * RefreshPartyMenu * Apply suggestions from code review Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com> * Apply suggestions * Update form_change_tables.h * Fix animation and simplify fusion tables * Fix party full message * Remove trailing whitespaces * Update party_menu.c * Update party_menu.c * Make IsFusionMon better * Apply suggestions from code review Co-authored-by: Bassoonian <iasperbassoonian@gmail.com> --------- Co-authored-by: TeamAquasHideout <jonathonheddings@gmail.com> Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com> Co-authored-by: LOuroboros <lunosouroboros@gmail.com> Co-authored-by: Bassoonian <iasperbassoonian@gmail.com>
This commit is contained in:
parent
8d6cb9692a
commit
b6ff973f38
14 changed files with 509 additions and 9 deletions
|
@ -11,6 +11,7 @@
|
|||
#define DAY 1
|
||||
#define NIGHT 2
|
||||
|
||||
#define FUSION_TERMINATOR 0xFF
|
||||
#define FORM_CHANGE_TERMINATOR 0
|
||||
|
||||
// Form change that activates when the specified item is given to or taken from the selected Pokémon.
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
#define PARTY_MSG_DO_WHAT_WITH_MAIL 25
|
||||
#define PARTY_MSG_ALREADY_HOLDING_ONE 26
|
||||
#define PARTY_MSG_WHICH_APPLIANCE 27
|
||||
#define PARTY_MSG_CHOOSE_SECOND_FUSION 28
|
||||
#define PARTY_MSG_NONE 127
|
||||
|
||||
// IDs for DisplayPartyPokemonDescriptionText, to display a message in the party pokemon's box
|
||||
|
|
|
@ -31,6 +31,7 @@ void ItemUseOutOfBattle_FormChange(u8);
|
|||
void ItemUseOutOfBattle_FormChange_ConsumedOnUse(u8);
|
||||
void ItemUseOutOfBattle_RotomCatalog(u8);
|
||||
void ItemUseOutOfBattle_ZygardeCube(u8);
|
||||
void ItemUseOutOfBattle_Fusion(u8);
|
||||
void ItemUseOutOfBattle_Honey(u8);
|
||||
void ItemUseOutOfBattle_CannotUse(u8);
|
||||
void ItemUseOutOfBattle_ExpShare(u8);
|
||||
|
|
|
@ -68,6 +68,7 @@ void ItemUseCB_FormChange(u8 taskId, TaskFunc task);
|
|||
void ItemUseCB_FormChange_ConsumedOnUse(u8 taskId, TaskFunc task);
|
||||
void ItemUseCB_RotomCatalog(u8 taskId, TaskFunc task);
|
||||
void ItemUseCB_ZygardeCube(u8 taskId, TaskFunc task);
|
||||
void ItemUseCB_Fusion(u8 taskId, TaskFunc task);
|
||||
const u8* GetItemEffect(u16 item);
|
||||
u8 GetItemEffectType(u16 item);
|
||||
void CB2_PartyMenuFromStartMenu(void);
|
||||
|
|
|
@ -426,6 +426,19 @@ struct FormChange
|
|||
u16 param3;
|
||||
};
|
||||
|
||||
struct Fusion
|
||||
{
|
||||
u16 fusionStorageIndex;
|
||||
u16 itemId;
|
||||
u16 targetSpecies1;
|
||||
u16 targetSpecies2;
|
||||
u16 fusingIntoMon;
|
||||
u16 fusionMove;
|
||||
u16 unfuseForgetMove;
|
||||
};
|
||||
|
||||
extern const struct Fusion *const gFusionTablePointers[NUM_SPECIES];
|
||||
|
||||
#define NUM_UNOWN_FORMS 28
|
||||
|
||||
#define GET_UNOWN_LETTER(personality) (( \
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define IN_BOX_COLUMNS 6 // Number of columns, 5 Pokémon per column
|
||||
#define IN_BOX_COUNT (IN_BOX_ROWS * IN_BOX_COLUMNS)
|
||||
#define BOX_NAME_LENGTH 8
|
||||
#define MAX_FUSION_STORAGE 4
|
||||
|
||||
/*
|
||||
COLUMNS
|
||||
|
@ -22,6 +23,7 @@ struct PokemonStorage
|
|||
/*0x0001*/ struct BoxPokemon boxes[TOTAL_BOXES_COUNT][IN_BOX_COUNT];
|
||||
/*0x8344*/ u8 boxNames[TOTAL_BOXES_COUNT][BOX_NAME_LENGTH + 1];
|
||||
/*0x83C2*/ u8 boxWallpapers[TOTAL_BOXES_COUNT];
|
||||
/*0x8432*/ struct Pokemon fusions[MAX_FUSION_STORAGE];
|
||||
};
|
||||
|
||||
extern struct PokemonStorage *gPokemonStoragePtr;
|
||||
|
|
|
@ -944,6 +944,7 @@ extern const u8 gText_UsedVar2WildLured[];
|
|||
extern const u8 gText_UsedVar2WildRepelled[];
|
||||
extern const u8 gText_BoxFull[];
|
||||
extern const u8 gText_WontHaveEffect[];
|
||||
extern const u8 gText_NextFusionMon[];
|
||||
|
||||
extern const u8 gText_LevelSymbol[];
|
||||
extern const u8 gText_PkmnInfo[];
|
||||
|
|
|
@ -8502,6 +8502,7 @@ const struct Item gItems[] =
|
|||
{
|
||||
.name = _("Gracidea"),
|
||||
.price = 0,
|
||||
.importance = 1,
|
||||
.description = sGracideaDesc,
|
||||
.pocket = POCKET_KEY_ITEMS,
|
||||
.type = ITEM_USE_PARTY_MENU,
|
||||
|
@ -8512,6 +8513,7 @@ const struct Item gItems[] =
|
|||
{
|
||||
.name = _("Reveal Glass"),
|
||||
.price = 0,
|
||||
.importance = 1,
|
||||
.description = sRevealGlassDesc,
|
||||
.pocket = POCKET_KEY_ITEMS,
|
||||
.type = ITEM_USE_PARTY_MENU,
|
||||
|
@ -8522,10 +8524,11 @@ const struct Item gItems[] =
|
|||
{
|
||||
.name = _("DNA Splicers"),
|
||||
.price = 0,
|
||||
.importance = 1,
|
||||
.description = sDNASplicersDesc,
|
||||
.pocket = POCKET_KEY_ITEMS,
|
||||
.type = ITEM_USE_BAG_MENU,
|
||||
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo: ItemUseOutOfBattle_FormChange_Fusion
|
||||
.type = ITEM_USE_PARTY_MENU,
|
||||
.fieldUseFunc = ItemUseOutOfBattle_Fusion,
|
||||
},
|
||||
|
||||
[ITEM_ZYGARDE_CUBE] =
|
||||
|
@ -8543,6 +8546,7 @@ const struct Item gItems[] =
|
|||
{
|
||||
.name = _("Prison Bottle"),
|
||||
.price = 0,
|
||||
.importance = 1,
|
||||
.description = sPrisonBottleDesc,
|
||||
.pocket = POCKET_KEY_ITEMS,
|
||||
.type = ITEM_USE_PARTY_MENU,
|
||||
|
@ -8553,30 +8557,33 @@ const struct Item gItems[] =
|
|||
{
|
||||
.name = _("N-Solarizer"),
|
||||
.price = 0,
|
||||
.importance = 1,
|
||||
.description = sNSolarizerDesc,
|
||||
.pocket = POCKET_KEY_ITEMS,
|
||||
.type = ITEM_USE_BAG_MENU,
|
||||
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo: ItemUseOutOfBattle_FormChange_Fusion
|
||||
.type = ITEM_USE_PARTY_MENU,
|
||||
.fieldUseFunc = ItemUseOutOfBattle_Fusion,
|
||||
},
|
||||
|
||||
[ITEM_N_LUNARIZER] =
|
||||
{
|
||||
.name = _("N-Lunarizer"),
|
||||
.price = 0,
|
||||
.importance = 1,
|
||||
.description = sNLunarizerDesc,
|
||||
.pocket = POCKET_KEY_ITEMS,
|
||||
.type = ITEM_USE_BAG_MENU,
|
||||
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo: ItemUseOutOfBattle_FormChange_Fusion
|
||||
.type = ITEM_USE_PARTY_MENU,
|
||||
.fieldUseFunc = ItemUseOutOfBattle_Fusion,
|
||||
},
|
||||
|
||||
[ITEM_REINS_OF_UNITY] =
|
||||
{
|
||||
.name = _("ReinsOfUnity"),
|
||||
.price = 0,
|
||||
.importance = 1,
|
||||
.description = sReinsOfUnityDesc,
|
||||
.pocket = POCKET_KEY_ITEMS,
|
||||
.type = ITEM_USE_BAG_MENU,
|
||||
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo: ItemUseOutOfBattle_FormChange_Fusion
|
||||
.type = ITEM_USE_PARTY_MENU,
|
||||
.fieldUseFunc = ItemUseOutOfBattle_Fusion,
|
||||
},
|
||||
|
||||
// Battle Mechanic Key Items
|
||||
|
|
|
@ -658,6 +658,7 @@ static const u8 *const sActionStringTable[] =
|
|||
[PARTY_MSG_DO_WHAT_WITH_MAIL] = gText_DoWhatWithMail,
|
||||
[PARTY_MSG_ALREADY_HOLDING_ONE] = gText_AlreadyHoldingOne,
|
||||
[PARTY_MSG_WHICH_APPLIANCE] = gText_WhichAppliance,
|
||||
[PARTY_MSG_CHOOSE_SECOND_FUSION] = gText_NextFusionMon,
|
||||
};
|
||||
|
||||
static const u8 *const sDescriptionStringTable[] =
|
||||
|
|
|
@ -375,3 +375,28 @@ const struct FormChange *const gFormChangeTablePointers[NUM_SPECIES] =
|
|||
[SPECIES_OGERPON_CORNERSTONE_MASK_TERA] = sOgerponFormChangeTable,
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct Fusion *const gFusionTablePointers[NUM_SPECIES] =
|
||||
{
|
||||
#if P_GEN_5_POKEMON == TRUE
|
||||
[SPECIES_KYUREM] = sKyuremFusionTable,
|
||||
[SPECIES_KYUREM_BLACK] = sKyuremFusionTable,
|
||||
[SPECIES_KYUREM_WHITE] = sKyuremFusionTable,
|
||||
[SPECIES_RESHIRAM] = sKyuremFusionTable,
|
||||
[SPECIES_ZEKROM] = sKyuremFusionTable,
|
||||
#endif
|
||||
#if P_GEN_7_POKEMON == TRUE
|
||||
[SPECIES_NECROZMA] = sNecrozmaFusionTable,
|
||||
[SPECIES_NECROZMA_DAWN_WINGS] = sNecrozmaFusionTable,
|
||||
[SPECIES_NECROZMA_DUSK_MANE] = sNecrozmaFusionTable,
|
||||
[SPECIES_SOLGALEO] = sNecrozmaFusionTable,
|
||||
[SPECIES_LUNALA] = sNecrozmaFusionTable,
|
||||
#endif
|
||||
#if P_GEN_8_POKEMON == TRUE
|
||||
[SPECIES_CALYREX] = sCalyrexFusionTable,
|
||||
[SPECIES_CALYREX_ICE_RIDER] = sCalyrexFusionTable,
|
||||
[SPECIES_CALYREX_SHADOW_RIDER] = sCalyrexFusionTable,
|
||||
[SPECIES_SPECTRIER] = sCalyrexFusionTable,
|
||||
[SPECIES_GLASTRIER] = sCalyrexFusionTable,
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -407,6 +407,12 @@ static const struct FormChange sLandorusFormChangeTable[] = {
|
|||
{FORM_CHANGE_TERMINATOR},
|
||||
};
|
||||
|
||||
static const struct Fusion sKyuremFusionTable[] = {
|
||||
{0, ITEM_DNA_SPLICERS, SPECIES_KYUREM, SPECIES_RESHIRAM, SPECIES_KYUREM_WHITE},
|
||||
{0, ITEM_DNA_SPLICERS, SPECIES_KYUREM, SPECIES_ZEKROM, SPECIES_KYUREM_BLACK},
|
||||
{FUSION_TERMINATOR},
|
||||
};
|
||||
|
||||
static const struct FormChange sKeldeoFormChangeTable[] = {
|
||||
{FORM_CHANGE_MOVE, SPECIES_KELDEO_RESOLUTE, MOVE_SECRET_SWORD, WHEN_LEARNED},
|
||||
{FORM_CHANGE_MOVE, SPECIES_KELDEO_ORDINARY, MOVE_SECRET_SWORD, WHEN_FORGOTTEN},
|
||||
|
@ -588,6 +594,13 @@ static const struct FormChange sMiniorYellowFormChangeTable[] = {
|
|||
{FORM_CHANGE_END_BATTLE, SPECIES_MINIOR_CORE_YELLOW},
|
||||
{FORM_CHANGE_TERMINATOR},
|
||||
};
|
||||
|
||||
static const struct Fusion sNecrozmaFusionTable[] = {
|
||||
{1, ITEM_N_SOLARIZER, SPECIES_NECROZMA, SPECIES_SOLGALEO, SPECIES_NECROZMA_DUSK_MANE, MOVE_SUNSTEEL_STRIKE, MOVE_CONFUSION},
|
||||
{2, ITEM_N_LUNARIZER, SPECIES_NECROZMA, SPECIES_LUNALA, SPECIES_NECROZMA_DAWN_WINGS, MOVE_MOONGEIST_BEAM, MOVE_CONFUSION},
|
||||
{FUSION_TERMINATOR},
|
||||
};
|
||||
|
||||
static const struct FormChange sNecrozmaDuskManeFormChangeTable[] = {
|
||||
{FORM_CHANGE_BATTLE_ULTRA_BURST, SPECIES_NECROZMA_ULTRA, ITEM_ULTRANECROZIUM_Z},
|
||||
{FORM_CHANGE_TERMINATOR},
|
||||
|
@ -635,6 +648,12 @@ static const struct FormChange sZamazentaFormChangeTable[] = {
|
|||
{FORM_CHANGE_TERMINATOR},
|
||||
};
|
||||
|
||||
static const struct Fusion sCalyrexFusionTable[] = {
|
||||
{3, ITEM_REINS_OF_UNITY, SPECIES_CALYREX, SPECIES_GLASTRIER, SPECIES_CALYREX_ICE_RIDER, MOVE_GLACIAL_LANCE, MOVE_CONFUSION},
|
||||
{3, ITEM_REINS_OF_UNITY, SPECIES_CALYREX, SPECIES_SPECTRIER, SPECIES_CALYREX_SHADOW_RIDER, MOVE_ASTRAL_BARRAGE, MOVE_CONFUSION},
|
||||
{FUSION_TERMINATOR},
|
||||
};
|
||||
|
||||
static const struct FormChange sEnamorusFormChangeTable[] = {
|
||||
{FORM_CHANGE_ITEM_USE, SPECIES_ENAMORUS_INCARNATE, ITEM_REVEAL_GLASS},
|
||||
{FORM_CHANGE_ITEM_USE, SPECIES_ENAMORUS_THERIAN, ITEM_REVEAL_GLASS},
|
||||
|
|
|
@ -1344,6 +1344,13 @@ void ItemUseOutOfBattle_ZygardeCube(u8 taskId)
|
|||
}
|
||||
}
|
||||
|
||||
void ItemUseOutOfBattle_Fusion(u8 taskId)
|
||||
{
|
||||
gItemUseCB = ItemUseCB_Fusion;
|
||||
gTasks[taskId].data[0] = FALSE;
|
||||
SetUpItemUseCallback(taskId);
|
||||
}
|
||||
|
||||
void Task_UseHoneyOnField(u8 taskId)
|
||||
{
|
||||
//ResetInitialPlayerAvatarState();
|
||||
|
|
420
src/party_menu.c
420
src/party_menu.c
|
@ -247,7 +247,9 @@ void (*gItemUseCB)(u8, TaskFunc);
|
|||
|
||||
static void ResetPartyMenu(void);
|
||||
static void CB2_InitPartyMenu(void);
|
||||
static void CB2_ReloadPartyMenu(void);
|
||||
static bool8 ShowPartyMenu(void);
|
||||
static bool8 ReloadPartyMenu(void);
|
||||
static void SetPartyMonsAllowedInMinigame(void);
|
||||
static void ExitPartyMenu(void);
|
||||
static bool8 AllocPartyMenuBg(void);
|
||||
|
@ -552,6 +554,25 @@ static void InitPartyMenu(u8 menuType, u8 layout, u8 partyAction, bool8 keepCurs
|
|||
}
|
||||
}
|
||||
|
||||
static void RefreshPartyMenu(void) //Refreshes the party menu without restarting tasks
|
||||
{
|
||||
u16 i;
|
||||
|
||||
sPartyMenuInternal->exitCallback = NULL;
|
||||
sPartyMenuInternal->lastSelectedSlot = 0;
|
||||
sPartyMenuInternal->spriteIdConfirmPokeball = 0x7F;
|
||||
sPartyMenuInternal->spriteIdCancelPokeball = 0x7F;
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(sPartyMenuInternal->data); i++)
|
||||
sPartyMenuInternal->data[i] = 0;
|
||||
for (i = 0; i < ARRAY_COUNT(sPartyMenuInternal->windowId); i++)
|
||||
sPartyMenuInternal->windowId[i] = WINDOW_NONE;
|
||||
|
||||
gTextFlags.autoScroll = 0;
|
||||
CalculatePlayerPartyCount();
|
||||
SetMainCallback2(CB2_ReloadPartyMenu);
|
||||
}
|
||||
|
||||
static void CB2_UpdatePartyMenu(void)
|
||||
{
|
||||
RunTasks();
|
||||
|
@ -577,6 +598,15 @@ static void CB2_InitPartyMenu(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void CB2_ReloadPartyMenu(void)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
if (MenuHelpers_ShouldWaitForLinkRecv() == TRUE || ReloadPartyMenu() == TRUE || MenuHelpers_IsLinkActive() == TRUE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool8 ShowPartyMenu(void)
|
||||
{
|
||||
switch (gMain.state)
|
||||
|
@ -701,6 +731,119 @@ static bool8 ShowPartyMenu(void)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static bool8 ReloadPartyMenu(void)
|
||||
{
|
||||
switch (gMain.state)
|
||||
{
|
||||
case 0:
|
||||
SetVBlankHBlankCallbacksToNull();
|
||||
ClearScheduledBgCopiesToVram();
|
||||
gMain.state++;
|
||||
break;
|
||||
case 1:
|
||||
ScanlineEffect_Stop();
|
||||
gMain.state++;
|
||||
break;
|
||||
case 2:
|
||||
ResetPaletteFade();
|
||||
gPaletteFade.bufferTransferDisabled = TRUE;
|
||||
gMain.state++;
|
||||
break;
|
||||
case 3:
|
||||
ResetSpriteData();
|
||||
gMain.state++;
|
||||
break;
|
||||
case 4:
|
||||
FreeAllSpritePalettes();
|
||||
gMain.state++;
|
||||
break;
|
||||
case 5:
|
||||
SetPartyMonsAllowedInMinigame();
|
||||
gMain.state++;
|
||||
break;
|
||||
case 6:
|
||||
if (!AllocPartyMenuBg())
|
||||
{
|
||||
ExitPartyMenu();
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
sPartyMenuInternal->data[0] = 0;
|
||||
gMain.state++;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (AllocPartyMenuBgGfx())
|
||||
gMain.state++;
|
||||
break;
|
||||
case 8:
|
||||
InitPartyMenuWindows(gPartyMenu.layout);
|
||||
gMain.state++;
|
||||
break;
|
||||
case 9:
|
||||
InitPartyMenuBoxes(gPartyMenu.layout);
|
||||
sPartyMenuInternal->data[0] = 0;
|
||||
gMain.state++;
|
||||
break;
|
||||
case 10:
|
||||
LoadHeldItemIcons();
|
||||
gMain.state++;
|
||||
break;
|
||||
case 11:
|
||||
LoadPartyMenuPokeballGfx();
|
||||
gMain.state++;
|
||||
break;
|
||||
case 12:
|
||||
LoadPartyMenuAilmentGfx();
|
||||
gMain.state++;
|
||||
break;
|
||||
case 13:
|
||||
LoadMonIconPalettes();
|
||||
gMain.state++;
|
||||
break;
|
||||
case 14:
|
||||
if (CreatePartyMonSpritesLoop())
|
||||
{
|
||||
sPartyMenuInternal->data[0] = 0;
|
||||
gMain.state++;
|
||||
}
|
||||
break;
|
||||
case 15:
|
||||
if (RenderPartyMenuBoxes())
|
||||
{
|
||||
sPartyMenuInternal->data[0] = 0;
|
||||
gMain.state++;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
CreateCancelConfirmPokeballSprites();
|
||||
gMain.state++;
|
||||
break;
|
||||
case 17:
|
||||
CreateCancelConfirmWindows(sPartyMenuInternal->chooseHalf);
|
||||
gMain.state++;
|
||||
break;
|
||||
case 18:
|
||||
gMain.state++;
|
||||
break;
|
||||
case 19:
|
||||
BlendPalettes(PALETTES_ALL, 16, RGB_WHITEALPHA);
|
||||
gPaletteFade.bufferTransferDisabled = FALSE;
|
||||
gMain.state++;
|
||||
break;
|
||||
case 20:
|
||||
BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_WHITEALPHA);
|
||||
gMain.state++;
|
||||
break;
|
||||
default:
|
||||
SetVBlankCallback(VBlankCB_PartyMenu);
|
||||
SetMainCallback2(CB2_UpdatePartyMenu);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ExitPartyMenu(void)
|
||||
{
|
||||
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
|
||||
|
@ -5707,11 +5850,44 @@ void ItemUseCB_EvolutionStone(u8 taskId, TaskFunc task)
|
|||
}
|
||||
}
|
||||
|
||||
#define FUSE_MON 1
|
||||
#define UNFUSE_MON 2
|
||||
#define SECOND_FUSE_MON 3
|
||||
|
||||
#define tState data[0]
|
||||
#define tTargetSpecies data[1]
|
||||
#define tAnimWait data[2]
|
||||
#define tNextFunc 3
|
||||
|
||||
#define fusionType data[7]
|
||||
#define firstFusion data[8]
|
||||
#define firstFusionSlot data[9]
|
||||
#define fusionResult data[10]
|
||||
#define secondFusionSlot data[11]
|
||||
#define unfuseSecondMon data[12]
|
||||
#define moveToLearn data[13]
|
||||
#define forgetMove data[14]
|
||||
#define storageIndex data[15]
|
||||
|
||||
static void Task_TryItemUseFusionChange(u8 taskId);
|
||||
static void SpriteCB_FormChangeIconMosaic(struct Sprite *sprite);
|
||||
|
||||
u8 IsFusionMon(u16 species)
|
||||
{
|
||||
u16 i;
|
||||
const struct Fusion *itemFusion = gFusionTablePointers[species];
|
||||
for (i = 0; itemFusion[i].fusionStorageIndex != FUSION_TERMINATOR; i++)
|
||||
{
|
||||
if (itemFusion[i].fusingIntoMon == species)
|
||||
return UNFUSE_MON;
|
||||
else if (itemFusion[i].targetSpecies1 == species)
|
||||
return FUSE_MON;
|
||||
else if (itemFusion[i].targetSpecies2 == species)
|
||||
return SECOND_FUSE_MON;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void FormChangeTeachMove(u8 taskId, u32 move, u32 slot)
|
||||
{
|
||||
struct Pokemon *mon;
|
||||
|
@ -5771,6 +5947,250 @@ bool32 DoesMonHaveAnyMoves(struct Pokemon *mon)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 TryItemUseFusionChange(u8 taskId, TaskFunc task)
|
||||
{
|
||||
u16 targetSpecies = gTasks[taskId].fusionResult;
|
||||
s8 *slotPtr = GetCurrentPartySlotPtr();
|
||||
*slotPtr = gTasks[taskId].firstFusionSlot;
|
||||
if (gTasks[taskId].fusionType == FUSE_MON)
|
||||
AnimatePartySlot(gTasks[taskId].secondFusionSlot, 0);
|
||||
AnimatePartySlot(*slotPtr, 1);
|
||||
|
||||
if (targetSpecies != SPECIES_NONE)
|
||||
{
|
||||
gPartyMenuUseExitCallback = TRUE;
|
||||
SetWordTaskArg(taskId, tNextFunc, (u32)task);
|
||||
gTasks[taskId].func = Task_TryItemUseFusionChange;
|
||||
gTasks[taskId].tState = 0;
|
||||
gTasks[taskId].tTargetSpecies = targetSpecies;
|
||||
gTasks[taskId].tAnimWait = 0;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gPartyMenuUseExitCallback = FALSE;
|
||||
PlaySE(SE_SELECT);
|
||||
DisplayPartyMenuMessage(gText_WontHaveEffect, TRUE);
|
||||
ScheduleBgCopyTilemapToVram(2);
|
||||
gTasks[taskId].func = task;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void Task_TryItemUseFusionChange(u8 taskId)
|
||||
{
|
||||
struct Pokemon *mon = &gPlayerParty[gTasks[taskId].firstFusionSlot];
|
||||
struct Sprite *icon = &gSprites[sPartyMenuBoxes[gTasks[taskId].firstFusionSlot].monSpriteId];
|
||||
struct Pokemon *mon2;
|
||||
struct Sprite *icon2 = &gSprites[sPartyMenuBoxes[gTasks[taskId].secondFusionSlot].monSpriteId];
|
||||
u16 targetSpecies;
|
||||
|
||||
switch (gTasks[taskId].tState)
|
||||
{
|
||||
case 0:
|
||||
if (gTasks[taskId].fusionType == FUSE_MON)
|
||||
{
|
||||
mon2 = &gPlayerParty[gTasks[taskId].secondFusionSlot];
|
||||
CopyMon(&gPokemonStoragePtr->fusions[gTasks[taskId].storageIndex], mon2, sizeof(*mon2));
|
||||
ZeroMonData(&gPlayerParty[gTasks[taskId].secondFusionSlot]);
|
||||
}
|
||||
else
|
||||
{
|
||||
mon2 = &gPokemonStoragePtr->fusions[gTasks[taskId].storageIndex];
|
||||
GiveMonToPlayer(mon2);
|
||||
ZeroMonData(&gPokemonStoragePtr->fusions[gTasks[taskId].storageIndex]);
|
||||
}
|
||||
targetSpecies = gTasks[taskId].tTargetSpecies;
|
||||
SetMonData(mon, MON_DATA_SPECIES, &targetSpecies);
|
||||
CalculateMonStats(mon);
|
||||
CompactPartySlots();
|
||||
CalculatePlayerPartyCount();
|
||||
gTasks[taskId].tState++;
|
||||
PlaySE(SE_M_TELEPORT);
|
||||
break;
|
||||
case 1:
|
||||
targetSpecies = gTasks[taskId].tTargetSpecies;
|
||||
if (gTasks[taskId].tAnimWait == 0)
|
||||
{
|
||||
icon->oam.mosaic = TRUE;
|
||||
icon->data[0] = 10;
|
||||
icon->data[1] = 1;
|
||||
icon->data[2] = taskId;
|
||||
icon->callback = SpriteCB_FormChangeIconMosaic;
|
||||
SetGpuReg(REG_OFFSET_MOSAIC, (icon->data[0] << 12) | (icon->data[1] << 8));
|
||||
if (gTasks[taskId].fusionType == FUSE_MON)
|
||||
{
|
||||
icon2->oam.mosaic = TRUE;
|
||||
icon2->data[0] = 10;
|
||||
icon2->data[1] = 1;
|
||||
icon2->data[2] = taskId;
|
||||
icon2->callback = SpriteCB_FormChangeIconMosaic;
|
||||
SetGpuReg(REG_OFFSET_MOSAIC, (icon2->data[0] << 12) | (icon2->data[1] << 8));
|
||||
}
|
||||
}
|
||||
|
||||
if (++gTasks[taskId].tAnimWait == 60)
|
||||
{
|
||||
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_WHITEALPHA);
|
||||
gTasks[taskId].tState++;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (gPaletteFade.active)
|
||||
break;
|
||||
if (gTasks[taskId].fusionType == FUSE_MON && gTasks[taskId].firstFusionSlot > gTasks[taskId].secondFusionSlot)
|
||||
{
|
||||
gTasks[taskId].firstFusionSlot--;
|
||||
gPartyMenu.slotId--;
|
||||
}
|
||||
RefreshPartyMenu();
|
||||
gTasks[taskId].tState++;
|
||||
break;
|
||||
case 3:
|
||||
BeginNormalPaletteFade(PALETTES_ALL, 16, 0, 0, RGB_WHITEALPHA);
|
||||
gTasks[taskId].tState++;
|
||||
break;
|
||||
case 4:
|
||||
targetSpecies = gTasks[taskId].tTargetSpecies;
|
||||
PlayCry_Normal(targetSpecies, 0);
|
||||
gTasks[taskId].tState++;
|
||||
break;
|
||||
case 5:
|
||||
if (IsCryFinished())
|
||||
{
|
||||
GetMonNickname(mon, gStringVar1);
|
||||
StringExpandPlaceholders(gStringVar4, gText_PkmnTransformed);
|
||||
DisplayPartyMenuMessage(gStringVar4, FALSE);
|
||||
ScheduleBgCopyTilemapToVram(2);
|
||||
gTasks[taskId].tState++;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (!IsPartyMenuTextPrinterActive())
|
||||
{
|
||||
if (gTasks[taskId].moveToLearn != 0)
|
||||
{
|
||||
if (gTasks[taskId].fusionType == FUSE_MON)
|
||||
FormChangeTeachMove(taskId, gTasks[taskId].moveToLearn, gTasks[taskId].firstFusionSlot);
|
||||
else
|
||||
{
|
||||
DeleteMove(mon, gTasks[taskId].forgetMove);
|
||||
if (!DoesMonHaveAnyMoves(mon))
|
||||
FormChangeTeachMove(taskId, gTasks[taskId].moveToLearn, gTasks[taskId].firstFusionSlot);
|
||||
}
|
||||
}
|
||||
gTasks[taskId].tState++;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
gTasks[taskId].func = (void *)GetWordTaskArg(taskId, tNextFunc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ItemUseCB_Fusion(u8 taskId, TaskFunc taskFunc)
|
||||
{
|
||||
u16 i;
|
||||
struct Task *task = &gTasks[taskId];
|
||||
u16 species = GetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_SPECIES);
|
||||
const struct Fusion *itemFusion = gFusionTablePointers[species];
|
||||
|
||||
PlaySE(SE_SELECT);
|
||||
switch (IsFusionMon(species))
|
||||
{
|
||||
case FALSE: // Cancel if Not a Fuse Mon
|
||||
break;
|
||||
case UNFUSE_MON:
|
||||
if (task->fusionType == FUSE_MON) // Cancel if An already Fused Mon Is Chosen For The Second Fusion Mon
|
||||
break;
|
||||
if (gPlayerPartyCount == PARTY_SIZE)
|
||||
{
|
||||
gPartyMenuUseExitCallback = FALSE;
|
||||
DisplayPartyMenuMessage(gText_YourPartysFull, TRUE);
|
||||
ScheduleBgCopyTilemapToVram(2);
|
||||
task->func = taskFunc;
|
||||
return;
|
||||
}
|
||||
for (i = 0; itemFusion[i].fusionStorageIndex != FUSION_TERMINATOR; i++) // Loops through fusion table and checks if the mon can be unfused
|
||||
{
|
||||
if (gPokemonStoragePtr->fusions[itemFusion[i].fusionStorageIndex].level == 0)
|
||||
continue;
|
||||
if (itemFusion[i].itemId == gSpecialVar_ItemId && GetMonData(&gPokemonStoragePtr->fusions[itemFusion[i].fusionStorageIndex], MON_DATA_SPECIES) == itemFusion[i].targetSpecies2)
|
||||
{
|
||||
task->fusionType = UNFUSE_MON;
|
||||
task->firstFusion = species;
|
||||
task->firstFusionSlot = gPartyMenu.slotId;
|
||||
task->storageIndex = itemFusion[i].fusionStorageIndex;
|
||||
task->fusionResult = itemFusion[i].targetSpecies1;
|
||||
task->unfuseSecondMon = itemFusion[i].targetSpecies2;
|
||||
task->moveToLearn = itemFusion[i].unfuseForgetMove;
|
||||
task->forgetMove = itemFusion[i].fusionMove;
|
||||
TryItemUseFusionChange(taskId, taskFunc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FUSE_MON:
|
||||
if (task->fusionType == FUSE_MON) // Cancel If Second Mon is Another First Fusion Mon
|
||||
break;
|
||||
for (i = 0; itemFusion[i].fusionStorageIndex != FUSION_TERMINATOR; i++) // Run through the Fusion table for each species and check if the item matches one of the entries
|
||||
{
|
||||
if (itemFusion[i].itemId == gSpecialVar_ItemId)
|
||||
{
|
||||
task->fusionType = FUSE_MON;
|
||||
task->firstFusion = species;
|
||||
task->firstFusionSlot = gPartyMenu.slotId;
|
||||
task->storageIndex = itemFusion[i].fusionStorageIndex;
|
||||
task->func = Task_HandleChooseMonInput;
|
||||
gPartyMenuUseExitCallback = FALSE;
|
||||
sPartyMenuInternal->exitCallback = NULL;
|
||||
PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[0]);
|
||||
DisplayPartyMenuStdMessage(PARTY_MSG_CHOOSE_SECOND_FUSION);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SECOND_FUSE_MON:
|
||||
if (task->fusionType != FUSE_MON) // Cancel if Secondary Fusion Mon Chosen First
|
||||
break;
|
||||
for (i = 0; itemFusion[i].fusionStorageIndex != FUSION_TERMINATOR; i++) // run through fusion table and check if the fusion works
|
||||
{
|
||||
if (gPokemonStoragePtr->fusions[itemFusion[i].fusionStorageIndex].level != 0)
|
||||
continue;
|
||||
if (itemFusion[i].itemId == gSpecialVar_ItemId && itemFusion[i].targetSpecies1 == task->firstFusion)
|
||||
{
|
||||
task->storageIndex = itemFusion[i].fusionStorageIndex;
|
||||
task->fusionResult = itemFusion[i].fusingIntoMon;
|
||||
task->secondFusionSlot = gPartyMenu.slotId;
|
||||
task->moveToLearn = itemFusion[i].fusionMove;
|
||||
// Start Fusion
|
||||
TryItemUseFusionChange(taskId, taskFunc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// No Effect Exit
|
||||
gPartyMenuUseExitCallback = FALSE;
|
||||
DisplayPartyMenuMessage(gText_WontHaveEffect, TRUE);
|
||||
ScheduleBgCopyTilemapToVram(2);
|
||||
task->func = taskFunc;
|
||||
return;
|
||||
}
|
||||
|
||||
#undef FUSE_MON
|
||||
#undef UNFUSE_MON
|
||||
#undef SECOND_FUSE_MON
|
||||
|
||||
#undef fusionType
|
||||
#undef firstFusion
|
||||
#undef firstFusionSlot
|
||||
#undef fusionResult
|
||||
#undef secondFusionSlot
|
||||
#undef unfuseSecondMon
|
||||
#undef moveToLearn
|
||||
#undef forgetMove
|
||||
#undef storageIndex
|
||||
|
||||
static void SpriteCB_FormChangeIconMosaic(struct Sprite *sprite)
|
||||
{
|
||||
|
|
|
@ -377,6 +377,7 @@ const u8 gText_HP3[] = _("HP");
|
|||
const u8 gText_SpAtk3[] = _("SP. ATK");
|
||||
const u8 gText_SpDef3[] = _("SP. DEF");
|
||||
const u8 gText_WontHaveEffect[] = _("It won't have any effect.{PAUSE_UNTIL_PRESS}");
|
||||
const u8 gText_NextFusionMon[] = _("Choose {PKMN} to fuse with.");
|
||||
const u8 gText_CantBeUsedOnPkmn[] = _("This can't be used on\nthat POKéMON.{PAUSE_UNTIL_PRESS}");
|
||||
const u8 gText_PkmnCantSwitchOut[] = _("{STR_VAR_1} can't be switched\nout!{PAUSE_UNTIL_PRESS}");
|
||||
const u8 gText_PkmnAlreadyInBattle[] = _("{STR_VAR_1} is already\nin battle!{PAUSE_UNTIL_PRESS}");
|
||||
|
@ -881,7 +882,7 @@ const u8 gText_PkmnWasReleased[] = _("{DYNAMIC 0} was released.");
|
|||
const u8 gText_ByeByePkmn[] = _("Bye-bye, {DYNAMIC 0}!");
|
||||
const u8 gText_MarkYourPkmn[] = _("Mark your POKéMON.");
|
||||
const u8 gText_ThatsYourLastPkmn[] = _("That's your last POKéMON!");
|
||||
const u8 gText_YourPartysFull[] = _("Your party's full!");
|
||||
const u8 gText_YourPartysFull[] = _("Your party's full!{PAUSE_UNTIL_PRESS}");
|
||||
const u8 gText_YoureHoldingAPkmn[] = _("You're holding a POKéMON!");
|
||||
const u8 gText_WhichOneWillYouTake[] = _("Which one will you take?");
|
||||
const u8 gText_YouCantReleaseAnEgg[] = _("You can't release an EGG.");
|
||||
|
|
Loading…
Reference in a new issue