diff --git a/include/pokemon.h b/include/pokemon.h index c05628a59..9ebaa52a0 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -366,11 +366,13 @@ struct Evolution u16 targetSpecies; }; -struct FormChange { +struct FormChange +{ u16 method; u16 targetSpecies; u16 param1; u16 param2; + u16 param3; }; #define NUM_UNOWN_FORMS 28 @@ -559,5 +561,6 @@ u16 GetFormChangeTargetSpecies(struct Pokemon *mon, u16 method, u32 arg); u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *mon, u16 method, u32 arg); u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove); bool32 ShouldShowFemaleDifferences(u16 species, u32 personality); +void TryToSetBattleFormChangeMoves(struct Pokemon *mon); #endif // GUARD_POKEMON_H diff --git a/src/battle_main.c b/src/battle_main.c index f75a7ae80..84af5ae74 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -578,11 +578,19 @@ static void CB2_InitBattleInternal(void) // Player's side targetSpecies = GetFormChangeTargetSpecies(&gPlayerParty[i], FORM_BATTLE_BEGIN, 0); if (targetSpecies != SPECIES_NONE) + { SetMonData(&gPlayerParty[i], MON_DATA_SPECIES, &targetSpecies); + CalculateMonStats(&gPlayerParty[i]); + TryToSetBattleFormChangeMoves(&gPlayerParty[i]); + } // Opponent's side targetSpecies = GetFormChangeTargetSpecies(&gEnemyParty[i], FORM_BATTLE_BEGIN, 0); if (targetSpecies != SPECIES_NONE) + { SetMonData(&gEnemyParty[i], MON_DATA_SPECIES, &targetSpecies); + CalculateMonStats(&gEnemyParty[i]); + TryToSetBattleFormChangeMoves(&gEnemyParty[i]); + } } gBattleCommunication[MULTIUSE_STATE] = 0; diff --git a/src/battle_util.c b/src/battle_util.c index dff9d71da..c9b4435f4 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -9624,17 +9624,12 @@ void UndoFormChange(u32 monId, u32 side, bool32 isSwitchingOut) } if (!isSwitchingOut) { - // Apply party-wide end-of-battle form changes - for (i = 0; i < PARTY_SIZE; i++) + targetSpecies = GetFormChangeTargetSpecies(&party[monId], FORM_BATTLE_END, 0); + if (targetSpecies != SPECIES_NONE) { - // Player's side - targetSpecies = GetFormChangeTargetSpecies(&gPlayerParty[i], FORM_BATTLE_END, 0); - if (targetSpecies != SPECIES_NONE) - SetMonData(&gPlayerParty[i], MON_DATA_SPECIES, &targetSpecies); - // Opponent's side - targetSpecies = GetFormChangeTargetSpecies(&gEnemyParty[i], FORM_BATTLE_END, 0); - if (targetSpecies != SPECIES_NONE) - SetMonData(&gEnemyParty[i], MON_DATA_SPECIES, &targetSpecies); + SetMonData(&party[monId], MON_DATA_SPECIES, &targetSpecies); + CalculateMonStats(&party[monId]); + TryToSetBattleFormChangeMoves(&party[monId]); } } } diff --git a/src/data/pokemon/form_change_tables.h b/src/data/pokemon/form_change_tables.h index be76cc995..914ca6d99 100644 --- a/src/data/pokemon/form_change_tables.h +++ b/src/data/pokemon/form_change_tables.h @@ -37,10 +37,14 @@ FORM_ITEM_USE_TIME: FORM_BATTLE_BEGIN: Form change activates when the Pokémon is sent out at the beginning of a battle param1 = item to hold, optional + param2 = a move that will be replaced, optional + param3 = a new move to replace it with, optional FORM_BATTLE_END: Form change activates at the end of a battle param1 = item to hold, optional + param2 = a move that will be replaced, optional + param3 = a new move to replace it with, optional */ // FORM_MOVE param2 Arguments @@ -194,20 +198,20 @@ static const struct FormChange sSilvallyFormChangeTable[] = { #endif static const struct FormChange sXerneasFormChangeTable[] = { - {FORM_BATTLE_BEGIN, SPECIES_XERNEAS_ACTIVE, ITEM_NONE}, - {FORM_BATTLE_END, SPECIES_XERNEAS, ITEM_NONE}, + {FORM_BATTLE_BEGIN, SPECIES_XERNEAS_ACTIVE}, + {FORM_BATTLE_END, SPECIES_XERNEAS, }, {FORM_CHANGE_END}, }; static const struct FormChange sZacianFormChangeTable[] = { - {FORM_BATTLE_BEGIN, SPECIES_ZACIAN_CROWNED_SWORD, ITEM_RUSTED_SWORD}, - {FORM_BATTLE_END, SPECIES_ZACIAN, ITEM_RUSTED_SWORD}, + {FORM_BATTLE_BEGIN, SPECIES_ZACIAN_CROWNED_SWORD, ITEM_RUSTED_SWORD, MOVE_IRON_HEAD, MOVE_BEHEMOTH_BLADE}, + {FORM_BATTLE_END, SPECIES_ZACIAN, ITEM_RUSTED_SWORD, MOVE_BEHEMOTH_BLADE, MOVE_IRON_HEAD}, {FORM_CHANGE_END}, }; static const struct FormChange sZamazentaFormChangeTable[] = { - {FORM_BATTLE_BEGIN, SPECIES_ZAMAZENTA_CROWNED_SHIELD, ITEM_RUSTED_SHIELD}, - {FORM_BATTLE_END, SPECIES_ZAMAZENTA, ITEM_RUSTED_SHIELD}, + {FORM_BATTLE_BEGIN, SPECIES_ZAMAZENTA_CROWNED_SHIELD, ITEM_RUSTED_SHIELD, MOVE_IRON_HEAD, MOVE_BEHEMOTH_BASH}, + {FORM_BATTLE_END, SPECIES_ZAMAZENTA, ITEM_RUSTED_SHIELD, MOVE_BEHEMOTH_BASH, MOVE_IRON_HEAD}, {FORM_CHANGE_END}, }; diff --git a/src/data/text/move_descriptions.h b/src/data/text/move_descriptions.h index 7d890b1d3..0a1d38504 100644 --- a/src/data/text/move_descriptions.h +++ b/src/data/text/move_descriptions.h @@ -2791,12 +2791,12 @@ static const u8 sPyroBallDescription[] = _( "target. It may cause a burn."); static const u8 sBehemothBladeDescription[] = _( - "Strikes as a sword. It deals\n" - "2x damage to Dynamaxed foes."); + "Strikes as a sword. Deals 2x\n" + "damage to Dynamaxed foes."); static const u8 sBehemothBashDescription[] = _( - "Attacks as a shield. Deals\n" - "2x damage to Dynamaxed foes."); + "Attacks as a shield. Deals 2x\n" + "damage to Dynamaxed foes."); static const u8 sAuraWheelDescription[] = _( "Raises Speed to attack. The\n" diff --git a/src/pokemon.c b/src/pokemon.c index 06e75dbc3..d1aa0abb0 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -8243,19 +8243,19 @@ u16 GetFormChangeTargetSpecies(struct Pokemon *mon, u16 method, u32 arg) } // Returns SPECIES_NONE if no form change is possible -u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *mon, u16 method, u32 arg) +u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32 arg) { - u32 i; + u32 i, j; u16 targetSpecies = SPECIES_NONE; - u16 species = GetBoxMonData(mon, MON_DATA_SPECIES, NULL); + u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL); const struct FormChange *formChanges = gFormChangeTablePointers[species]; u16 heldItem; u32 ability; if (formChanges != NULL) { - heldItem = GetBoxMonData(mon, MON_DATA_HELD_ITEM, NULL); - ability = GetAbilityBySpecies(species, GetBoxMonData(mon, MON_DATA_ABILITY_NUM, NULL)); + heldItem = GetBoxMonData(boxMon, MON_DATA_HELD_ITEM, NULL); + ability = GetAbilityBySpecies(species, GetBoxMonData(boxMon, MON_DATA_ABILITY_NUM, NULL)); for (i = 0; formChanges[i].method != FORM_CHANGE_END; i++) { @@ -8264,8 +8264,6 @@ u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *mon, u16 method, u32 arg switch (method) { case FORM_ITEM_HOLD: - case FORM_BATTLE_BEGIN: - case FORM_BATTLE_END: if (heldItem == formChanges[i].param1 || formChanges[i].param1 == ITEM_NONE) targetSpecies = formChanges[i].targetSpecies; break; @@ -8274,7 +8272,7 @@ u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *mon, u16 method, u32 arg targetSpecies = formChanges[i].targetSpecies; break; case FORM_MOVE: - if (BoxMonKnowsMove(mon, formChanges[i].param1) != formChanges[i].param2) + if (BoxMonKnowsMove(boxMon, formChanges[i].param1) != formChanges[i].param2) targetSpecies = formChanges[i].targetSpecies; break; case FORM_ITEM_HOLD_ABILITY: @@ -8299,6 +8297,10 @@ u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *mon, u16 method, u32 arg } } break; + case FORM_BATTLE_BEGIN: + case FORM_BATTLE_END: + if (heldItem == formChanges[i].param1 || formChanges[i].param1 == ITEM_NONE) + targetSpecies = formChanges[i].targetSpecies; } } } @@ -8358,7 +8360,7 @@ void TrySpecialOverworldEvo(void) u8 i; u8 evoMethod = gSpecialVar_0x8000; u16 canStopEvo = gSpecialVar_0x8001; - u16 tryMultiple = gSpecialVar_0x8002; + u16 tryMultiple = gSpecialVar_0x8002; for (i = 0; i < PARTY_SIZE; i++) { @@ -8375,7 +8377,7 @@ void TrySpecialOverworldEvo(void) else gCB2_AfterEvolution = CB2_ReturnToField; return; - } + } } sTriedEvolving = 0; @@ -8386,3 +8388,43 @@ bool32 ShouldShowFemaleDifferences(u16 species, u32 personality) { return (gBaseStats[species].flags & FLAG_GENDER_DIFFERENCE) && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE; } + +void TryToSetBattleFormChangeMoves(struct Pokemon *mon) +{ + int i, j; + u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); + const struct FormChange *formChanges = gFormChangeTablePointers[species]; + u8 ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES, NULL); + + if (formChanges == NULL) + return; + + for (i = 0; formChanges[i].method != FORM_CHANGE_END; i++) + { + if ((formChanges[i].method == FORM_BATTLE_BEGIN || formChanges[i].method == FORM_BATTLE_END) + && formChanges[i].param2 && formChanges[i].param3 && formChanges[i].targetSpecies == species) + { + u16 originalMove = formChanges[i].param2; + u16 newMove = formChanges[i].param3; + + for (j = 0; j < MAX_MON_MOVES; j++) + { + u16 currMove = GetMonData(mon, MON_DATA_MOVE1 + j, NULL); + u8 totalPp = gBattleMoves[currMove].pp; // Get current move's max PP + u8 currPp = GetMonData(mon, MON_DATA_PP1 + j, NULL); // Get current move's remaining PP + u8 diffPp = totalPp - currPp; // Current move's PP difference + u8 finalPp = gBattleMoves[newMove].pp - diffPp; // Apply the PP difference to the new move + + if (currMove == originalMove) + { + if (finalPp > gBattleMoves[newMove].pp) + finalPp = 0; + SetMonMoveSlot(mon, newMove, j); + SetMonData(mon, MON_DATA_PP1 + j, &finalPp); + } + } + SetMonData(mon, MON_DATA_PP_BONUSES, &ppBonuses); + break; + } + } +}