Multiple refactors

- Added a general GetBattleFormChangeTargetSpecies instead of getting specific ones for Mega Evolution and Primal Reversion.
- Added FORM_CHANGE_BATTLE_HP_PERCENT, to replace ShouldChangeFormHpBased.
- Cleaned ifdefs for hold effects.
- Finally removed UndoMegaEvolution.
- FORM_CHANGE_FAINT and FORM_CHANGE_BATTLE_END restore to the first form before a battle form change if species isn't specified.
- When changing from a form with more HP to one with less, now current HP is kept to fix Zygarde edge case. (Will likely need to be reworked for Dynamax, as it behaves differently)
- Uses DoesSpeciesUseHoldItemToChangeForm in CanBattlerGetOrLoseItem.
This commit is contained in:
Eduardo Quezada 2022-11-05 20:00:12 -03:00
parent 271bff5675
commit 42f8e8c114
11 changed files with 272 additions and 208 deletions

View File

@ -144,14 +144,12 @@ u16 CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 bat
u16 CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef);
u16 GetTypeModifier(u8 atkType, u8 defType);
s32 GetStealthHazardDamage(u8 hazardType, u8 battlerId);
u16 GetMegaEvolutionSpecies(u16 preEvoSpecies, u16 heldItemId);
u16 GetPrimalReversionSpecies(u16 preSpecies, u16 heldItemId);
u16 GetWishMegaEvolutionSpecies(u16 preEvoSpecies, u16 moveId1, u16 moveId2, u16 moveId3, u16 moveId4);
bool32 DoesSpeciesUseHoldItemToChangeForm(u16 species, u16 heldItemId);
bool32 CanMegaEvolve(u8 battlerId);
void UndoMegaEvolution(u32 monId);
bool32 IsBattlerMegaEvolved(u8 battlerId);
bool32 IsBattlerPrimalReverted(u8 battlerId);
void TryBattleFormChange(u8 battlerId, u16 method);
u16 GetBattleFormChangeTargetSpecies(u8 battlerId, u16 method);
bool32 TryBattleFormChange(u8 battlerId, u16 method);
bool32 DoBattlersShareType(u32 battler1, u32 battler2);
bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId);
struct Pokemon *GetIllusionMonPtr(u32 battlerId);

View File

@ -323,9 +323,14 @@
#define FORM_CHANGE_BATTLE_BEGIN 6
#define FORM_CHANGE_BATTLE_END 7
#define FORM_CHANGE_BATTLE_SWITCH 8
#define FORM_CHANGE_MEGA_EVOLUTION_ITEM 9
#define FORM_CHANGE_MEGA_EVOLUTION_MOVE 10
#define FORM_CHANGE_PRIMAL_REVERSION 11
#define FORM_CHANGE_BATTLE_HP_PERCENT 9
#define FORM_CHANGE_MEGA_EVOLUTION_ITEM 10
#define FORM_CHANGE_MEGA_EVOLUTION_MOVE 11
#define FORM_CHANGE_PRIMAL_REVERSION 12
// FORM_CHANGE_BATTLE_HP_PERCENT param2 arguments
#define HP_HIGHER_THAN 1
#define HP_LOWER_EQ_THAN 2
#define MON_PIC_WIDTH 64
#define MON_PIC_HEIGHT 64

View File

@ -562,7 +562,8 @@ u8 *MonSpritesGfxManager_GetSpritePtr(u8 managerId, u8 spriteNum);
u16 GetFormSpeciesId(u16 speciesId, u8 formId);
u8 GetFormIdFromFormSpeciesId(u16 formSpeciesId);
u16 GetFormChangeTargetSpecies(struct Pokemon *mon, u16 method, u32 arg);
u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *mon, u16 method, u32 arg);
u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32 arg);
bool32 DoesSpeciesHaveFormChangeMethod(u16 species, u16 method);
u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove);
bool32 ShouldShowFemaleDifferences(u16 species, u32 personality);
bool32 TryFormChange(u32 monId, u32 side, u16 method);

View File

@ -3043,12 +3043,8 @@ static bool32 IsPinchBerryItemEffect(u16 holdEffect)
case HOLD_EFFECT_SP_DEFENSE_UP:
case HOLD_EFFECT_CRITICAL_UP:
case HOLD_EFFECT_RANDOM_STAT_UP:
#ifdef HOLD_EFFECT_CUSTAP_BERRY
case HOLD_EFFECT_CUSTAP_BERRY:
#endif
#ifdef HOLD_EFFECT_MICLE_BERRY
case HOLD_EFFECT_MICLE_BERRY:
#endif
return TRUE;
}

View File

@ -3248,8 +3248,6 @@ void FaintClearSetData(void)
Ai_UpdateFaintData(gActiveBattler);
TryBattleFormChange(gActiveBattler, FORM_CHANGE_FAINT);
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
UndoMegaEvolution(gBattlerPartyIndexes[gActiveBattler]);
gBattleStruct->overwrittenAbilities[gActiveBattler] = ABILITY_NONE;
@ -3683,7 +3681,7 @@ static void TryDoEventsBeforeFirstTurn(void)
for (i = 0; i < gBattlersCount; i++)
{
if (GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_PRIMAL_ORB
&& GetPrimalReversionSpecies(gBattleMons[i].species, gBattleMons[i].item) != SPECIES_NONE)
&& GetBattleFormChangeTargetSpecies(i, FORM_CHANGE_PRIMAL_REVERSION) != SPECIES_NONE)
{
gBattlerAttacker = i;
BattleScriptExecute(BattleScript_PrimalReversion);
@ -5200,16 +5198,15 @@ static void HandleEndTurn_FinishBattle(void)
#endif
for (i = 0; i < PARTY_SIZE; i++)
{
UndoMegaEvolution(i);
TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_BATTLE_END);
bool32 changedForm = TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_BATTLE_END);
DoBurmyFormChange(i);
// Clear original species field
gBattleStruct->changedSpecies[i] = SPECIES_NONE;
#if B_RECALCULATE_STATS >= GEN_5
// Recalculate the stats of every party member before the end
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) != SPECIES_NONE
&& GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) != SPECIES_EGG)
{
if (!changedForm)
CalculateMonStats(&gPlayerParty[i]);
}
#endif
}
// Clear battle mon species to avoid a bug on the next battle that causes

View File

@ -8800,10 +8800,10 @@ static void Cmd_various(void)
if (gBattlescriptCurrInstr[3] == 0)
{
//Checks regular Mega Evolution
u16 megaSpecies = GetMegaEvolutionSpecies(gBattleMons[gActiveBattler].species, gBattleMons[gActiveBattler].item);
u16 megaSpecies = GetBattleFormChangeTargetSpecies(gActiveBattler, FORM_CHANGE_MEGA_EVOLUTION_ITEM);
//Checks Wish Mega Evolution
if (megaSpecies == SPECIES_NONE)
megaSpecies = GetWishMegaEvolutionSpecies(gBattleMons[gActiveBattler].species, gBattleMons[gActiveBattler].moves[0], gBattleMons[gActiveBattler].moves[1], gBattleMons[gActiveBattler].moves[2], gBattleMons[gActiveBattler].moves[3]);
megaSpecies = GetBattleFormChangeTargetSpecies(gActiveBattler, FORM_CHANGE_MEGA_EVOLUTION_MOVE);
gBattleMons[gActiveBattler].species = megaSpecies;
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gActiveBattler].species);
@ -8836,7 +8836,7 @@ static void Cmd_various(void)
// Change species.
if (gBattlescriptCurrInstr[3] == 0)
{
gBattleMons[gActiveBattler].species = GetPrimalReversionSpecies(gBattleMons[gActiveBattler].species, gBattleMons[gActiveBattler].item);
gBattleMons[gActiveBattler].species = GetBattleFormChangeTargetSpecies(gActiveBattler, FORM_CHANGE_PRIMAL_REVERSION);
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gActiveBattler].species);
BtlController_EmitSetMonData(BUFFER_A, REQUEST_SPECIES_BATTLE, gBitTable[gBattlerPartyIndexes[gActiveBattler]], sizeof(gBattleMons[gActiveBattler].species), &gBattleMons[gActiveBattler].species);
@ -9561,7 +9561,7 @@ static void Cmd_various(void)
return;
case VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL:
{
if (GetPrimalReversionSpecies(gBattleMons[gActiveBattler].species, gBattleMons[gActiveBattler].item) == SPECIES_NONE)
if (GetBattleFormChangeTargetSpecies(gActiveBattler, FORM_CHANGE_PRIMAL_REVERSION) == SPECIES_NONE)
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
else
gBattlescriptCurrInstr += 7;

View File

@ -4170,51 +4170,6 @@ static bool32 TryChangeBattleTerrain(u32 battler, u32 statusFlag, u8 *timer)
return FALSE;
}
static bool32 ShouldChangeFormHpBased(u32 battler)
{
// Ability, form >, form <=, hp divided
static const u16 forms[][4] =
{
{ABILITY_ZEN_MODE, SPECIES_DARMANITAN, SPECIES_DARMANITAN_ZEN_MODE, 2},
{ABILITY_SHIELDS_DOWN, SPECIES_MINIOR, SPECIES_MINIOR_CORE_RED, 2},
{ABILITY_SHIELDS_DOWN, SPECIES_MINIOR_METEOR_BLUE, SPECIES_MINIOR_CORE_BLUE, 2},
{ABILITY_SHIELDS_DOWN, SPECIES_MINIOR_METEOR_GREEN, SPECIES_MINIOR_CORE_GREEN, 2},
{ABILITY_SHIELDS_DOWN, SPECIES_MINIOR_METEOR_INDIGO, SPECIES_MINIOR_CORE_INDIGO, 2},
{ABILITY_SHIELDS_DOWN, SPECIES_MINIOR_METEOR_ORANGE, SPECIES_MINIOR_CORE_ORANGE, 2},
{ABILITY_SHIELDS_DOWN, SPECIES_MINIOR_METEOR_VIOLET, SPECIES_MINIOR_CORE_VIOLET, 2},
{ABILITY_SHIELDS_DOWN, SPECIES_MINIOR_METEOR_YELLOW, SPECIES_MINIOR_CORE_YELLOW, 2},
{ABILITY_SCHOOLING, SPECIES_WISHIWASHI_SCHOOL, SPECIES_WISHIWASHI, 4},
{ABILITY_GULP_MISSILE, SPECIES_CRAMORANT, SPECIES_CRAMORANT_GORGING, 2},
{ABILITY_GULP_MISSILE, SPECIES_CRAMORANT, SPECIES_CRAMORANT_GULPING, 1},
{ABILITY_ZEN_MODE, SPECIES_DARMANITAN_GALARIAN, SPECIES_DARMANITAN_ZEN_MODE_GALARIAN, 2},
};
u32 i;
u16 battlerAbility = GetBattlerAbility(battler);
if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED)
return FALSE;
for (i = 0; i < ARRAY_COUNT(forms); i++)
{
if (battlerAbility == forms[i][0])
{
if (gBattleMons[battler].species == forms[i][2]
&& gBattleMons[battler].hp > gBattleMons[battler].maxHP / forms[i][3])
{
gBattleMons[battler].species = forms[i][1];
return TRUE;
}
if (gBattleMons[battler].species == forms[i][1]
&& gBattleMons[battler].hp <= gBattleMons[battler].maxHP / forms[i][3])
{
gBattleMons[battler].species = forms[i][2];
return TRUE;
}
}
}
return FALSE;
}
static u8 ForewarnChooseMove(u32 battler)
{
struct Forewarn {
@ -4738,7 +4693,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
// Fallthrough
case ABILITY_ZEN_MODE:
case ABILITY_SHIELDS_DOWN:
if (ShouldChangeFormHpBased(battler))
if (TryBattleFormChange(battler, FORM_CHANGE_BATTLE_HP_PERCENT))
{
BattleScriptPushCursorAndCallback(BattleScript_AttackerFormChangeEnd3);
effect++;
@ -4959,15 +4914,9 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
// Fallthrough
case ABILITY_ZEN_MODE:
case ABILITY_SHIELDS_DOWN:
if ((effect = ShouldChangeFormHpBased(battler)))
BattleScriptPushCursorAndCallback(BattleScript_AttackerFormChangeEnd3);
break;
case ABILITY_POWER_CONSTRUCT:
if ((gBattleMons[battler].species == SPECIES_ZYGARDE || gBattleMons[battler].species == SPECIES_ZYGARDE_10)
&& gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 2)
if (TryBattleFormChange(battler, FORM_CHANGE_BATTLE_HP_PERCENT))
{
gBattleStruct->changedSpecies[gBattlerPartyIndexes[battler]] = gBattleMons[battler].species;
gBattleMons[battler].species = SPECIES_ZYGARDE_COMPLETE;
BattleScriptPushCursorAndCallback(BattleScript_AttackerFormChangeEnd3);
effect++;
}
@ -5614,7 +5563,6 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
{
if (gBattleMons[gBattlerTarget].species == SPECIES_CRAMORANT_GORGING)
{
gBattleStruct->changedSpecies[gBattlerPartyIndexes[gBattlerTarget]] = gBattleMons[gBattlerTarget].species;
gBattleMons[gBattlerTarget].species = SPECIES_CRAMORANT;
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
{
@ -5628,7 +5576,6 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
}
else if (gBattleMons[gBattlerTarget].species == SPECIES_CRAMORANT_GULPING)
{
gBattleStruct->changedSpecies[gBattlerPartyIndexes[gBattlerTarget]] = gBattleMons[gBattlerTarget].species;
gBattleMons[gBattlerTarget].species = SPECIES_CRAMORANT;
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
{
@ -5681,7 +5628,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
break;
case ABILITY_GULP_MISSILE:
if (((gCurrentMove == MOVE_SURF && TARGET_TURN_DAMAGED) || gStatuses3[gBattlerAttacker] & STATUS3_UNDERWATER)
&& (effect = ShouldChangeFormHpBased(gBattlerAttacker)))
&& TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_HP_PERCENT))
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_AttackerFormChange;
@ -9552,59 +9499,27 @@ bool32 IsPartnerMonFromSameTrainer(u8 battlerId)
return TRUE;
}
u16 GetMegaEvolutionSpecies(u16 preEvoSpecies, u16 heldItemId)
bool32 DoesSpeciesUseHoldItemToChangeForm(u16 species, u16 heldItemId)
{
u32 i;
const struct FormChange *formChanges = gFormChangeTablePointers[preEvoSpecies];
const struct FormChange *formChanges = gFormChangeTablePointers[species];
if (formChanges != NULL)
{
for (i = 0; formChanges[i].method != FORM_CHANGE_END; i++)
{
if ((formChanges[i].method == FORM_CHANGE_MEGA_EVOLUTION_ITEM
&& formChanges[i].param1 == heldItemId)
&& formChanges[i].targetSpecies != preEvoSpecies)
return formChanges[i].targetSpecies;
}
}
return SPECIES_NONE;
}
u16 GetPrimalReversionSpecies(u16 preSpecies, u16 heldItemId)
switch (formChanges[i].method)
{
u32 i;
const struct FormChange *formChanges = gFormChangeTablePointers[preSpecies];
if (formChanges != NULL)
{
for (i = 0; formChanges[i].method != FORM_CHANGE_END; i++)
{
if (formChanges[i].method == FORM_CHANGE_PRIMAL_REVERSION
&& formChanges[i].param1 == heldItemId
&& formChanges[i].targetSpecies != preSpecies)
return formChanges[i].targetSpecies;
case FORM_CHANGE_MEGA_EVOLUTION_ITEM:
case FORM_CHANGE_PRIMAL_REVERSION:
case FORM_CHANGE_ITEM_HOLD:
if (formChanges[i].param1 == heldItemId)
return TRUE;
break;
}
}
return SPECIES_NONE;
}
u16 GetWishMegaEvolutionSpecies(u16 preEvoSpecies, u16 moveId1, u16 moveId2, u16 moveId3, u16 moveId4)
{
u32 i, param;
const struct FormChange *formChanges = gFormChangeTablePointers[preEvoSpecies];
if (formChanges != NULL)
{
for (i = 0; formChanges[i].method != FORM_CHANGE_END; i++)
{
param = formChanges[i].param1;
if ((formChanges[i].method == FORM_CHANGE_MEGA_EVOLUTION_MOVE
&& (param == moveId1 || param == moveId2 || param == moveId3 || param == moveId4))
&& formChanges[i].targetSpecies != preEvoSpecies)
return formChanges[i].targetSpecies;
}
}
return SPECIES_NONE;
return FALSE;
}
bool32 CanMegaEvolve(u8 battlerId)
@ -9647,7 +9562,7 @@ bool32 CanMegaEvolve(u8 battlerId)
itemId = GetMonData(mon, MON_DATA_HELD_ITEM);
// Check if there is an entry in the evolution table for regular Mega Evolution.
if (GetMegaEvolutionSpecies(species, itemId) != SPECIES_NONE)
if (GetBattleFormChangeTargetSpecies(battlerId, FORM_CHANGE_MEGA_EVOLUTION_ITEM) != SPECIES_NONE)
{
#if B_ENABLE_DEBUG == TRUE
if (B_ENABLE_DEBUG && gBattleStruct->debugHoldEffects[battlerId])
@ -9668,7 +9583,7 @@ bool32 CanMegaEvolve(u8 battlerId)
}
// Check if there is an entry in the evolution table for Wish Mega Evolution.
if (GetWishMegaEvolutionSpecies(species, GetMonData(mon, MON_DATA_MOVE1), GetMonData(mon, MON_DATA_MOVE2), GetMonData(mon, MON_DATA_MOVE3), GetMonData(mon, MON_DATA_MOVE4)))
if (GetBattleFormChangeTargetSpecies(battlerId, FORM_CHANGE_MEGA_EVOLUTION_MOVE) != SPECIES_NONE)
{
gBattleStruct->mega.isWishMegaEvo = TRUE;
return TRUE;
@ -9678,17 +9593,6 @@ bool32 CanMegaEvolve(u8 battlerId)
return FALSE;
}
void UndoMegaEvolution(u32 monId)
{
// While not exactly a mega evolution, Zygarde follows the same rules.
if (GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, NULL) == SPECIES_ZYGARDE_COMPLETE)
{
SetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, &gBattleStruct->changedSpecies[monId]);
gBattleStruct->changedSpecies[monId] = 0;
CalculateMonStats(&gPlayerParty[monId]);
}
}
bool32 IsBattlerMegaEvolved(u8 battlerId)
{
return (gBaseStats[gBattleMons[battlerId].species].flags & SPECIES_FLAG_MEGA_EVOLUTION);
@ -9699,17 +9603,121 @@ bool32 IsBattlerPrimalReverted(u8 battlerId)
return (gBaseStats[gBattleMons[battlerId].species].flags & SPECIES_FLAG_PRIMAL_REVERSION);
}
void TryBattleFormChange(u8 battlerId, u16 method)
// Returns SPECIES_NONE if no form change is possible
u16 GetBattleFormChangeTargetSpecies(u8 battlerId, u16 method)
{
u32 i, j;
u16 targetSpecies = SPECIES_NONE;
u16 species = gBattleMons[battlerId].species;
const struct FormChange *formChanges = gFormChangeTablePointers[species];
u16 heldItem;
u32 ability;
if (formChanges != NULL)
{
heldItem = gBattleMons[battlerId].item;
ability = GetBattlerAbility(battlerId);
for (i = 0; formChanges[i].method != FORM_CHANGE_END; i++)
{
if (method == formChanges[i].method && species != formChanges[i].targetSpecies)
{
switch (method)
{
case FORM_CHANGE_MEGA_EVOLUTION_ITEM:
case FORM_CHANGE_PRIMAL_REVERSION:
if (heldItem == formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_MEGA_EVOLUTION_MOVE:
if (gBattleMons[battlerId].moves[0] == formChanges[i].param1
|| gBattleMons[battlerId].moves[1] == formChanges[i].param1
|| gBattleMons[battlerId].moves[2] == formChanges[i].param1
|| gBattleMons[battlerId].moves[3] == formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_SWITCH:
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_HP_PERCENT:
{
if (formChanges[i].param1 == GetBattlerAbility(battlerId))
{
// We multiply by 100 to make sure that integer division doesn't mess with the health check.
u32 hpCheck = gBattleMons[battlerId].hp * 100 * 100 / gBattleMons[battlerId].maxHP;
switch(formChanges[i].param2)
{
case HP_HIGHER_THAN:
if (hpCheck > formChanges[i].param3 * 100)
targetSpecies = formChanges[i].targetSpecies;
break;
case HP_LOWER_EQ_THAN:
if (hpCheck <= formChanges[i].param3 * 100)
targetSpecies = formChanges[i].targetSpecies;
break;
}
}
break;
}
}
}
}
}
return targetSpecies;
}
bool32 TryBattleFormChange(u8 battlerId, u16 method)
{
u8 monId = gBattlerPartyIndexes[battlerId];
u8 side = GET_BATTLER_SIDE(battlerId);
struct Pokemon *party = (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty;
u16 targetSpecies;
if (TryFormChange(monId, side, method))
// Can't change form if transformed.
if (gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED)
return FALSE;
if (!DoesSpeciesHaveFormChangeMethod(gBattleMons[battlerId].species, method))
return FALSE;
targetSpecies = GetBattleFormChangeTargetSpecies(battlerId, method);
if (targetSpecies != SPECIES_NONE)
{
CopyMonLevelAndBaseStatsToBattleMon(battlerId, &party[monId]);
CopyMonAbilityAndTypesToBattleMon(battlerId, &party[monId]);
// Saves the original species on the first form change.
if (gBattleStruct->changedSpecies[monId] == SPECIES_NONE)
gBattleStruct->changedSpecies[monId] = gBattleMons[battlerId].species;
TryToSetBattleFormChangeMoves(&party[monId], method);
SetMonData(&party[monId], MON_DATA_SPECIES, &targetSpecies);
gBattleMons[battlerId].species = targetSpecies;
RecalcBattlerStats(battlerId, &party[monId]);
return TRUE;
}
targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0);
if (targetSpecies != SPECIES_NONE)
{
// Saves the original species on the first form change.
if (gBattleStruct->changedSpecies[monId] == SPECIES_NONE)
gBattleStruct->changedSpecies[monId] = targetSpecies;
TryToSetBattleFormChangeMoves(&party[monId], method);
SetMonData(&party[monId], MON_DATA_SPECIES, &targetSpecies);
gBattleMons[battlerId].species = targetSpecies;
RecalcBattlerStats(battlerId, &party[monId]);
return TRUE;
}
else if ((method == FORM_CHANGE_BATTLE_END || method == FORM_CHANGE_FAINT)
&& gBattleStruct->changedSpecies[monId] != SPECIES_NONE)
{
TryToSetBattleFormChangeMoves(&party[monId], method);
SetMonData(&party[monId], MON_DATA_SPECIES, &gBattleStruct->changedSpecies[monId]);
RecalcBattlerStats(battlerId, &party[monId]);
return TRUE;
}
return FALSE;
}
bool32 DoBattlersShareType(u32 battler1, u32 battler2)
@ -9740,24 +9748,10 @@ bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId)
// Mail can be stolen now
if (itemId == ITEM_ENIGMA_BERRY_E_READER)
return FALSE;
// Primal Reversion inducing items cannot be lost if pokemon's base species can undergo primal reversion with it.
else if (holdEffect == HOLD_EFFECT_PRIMAL_ORB && (GetPrimalReversionSpecies(GET_BASE_SPECIES_ID(species), itemId) != SPECIES_NONE))
else if (DoesSpeciesUseHoldItemToChangeForm(species, itemId))
return FALSE;
// Mega stone cannot be lost if pokemon's base species can mega evolve with it.
else if (holdEffect == HOLD_EFFECT_MEGA_STONE && (GetMegaEvolutionSpecies(GET_BASE_SPECIES_ID(species), itemId) != SPECIES_NONE))
return FALSE;
else if (GET_BASE_SPECIES_ID(species) == SPECIES_GIRATINA && itemId == ITEM_GRISEOUS_ORB)
return FALSE;
else if (GET_BASE_SPECIES_ID(species) == SPECIES_GENESECT && holdEffect == HOLD_EFFECT_DRIVE)
return FALSE;
else if (GET_BASE_SPECIES_ID(species) == SPECIES_SILVALLY && holdEffect == HOLD_EFFECT_MEMORY)
return FALSE;
else if (GET_BASE_SPECIES_ID(species) == SPECIES_ARCEUS && holdEffect == HOLD_EFFECT_PLATE)
return FALSE;
#ifdef HOLD_EFFECT_Z_CRYSTAL
else if (holdEffect == HOLD_EFFECT_Z_CRYSTAL)
return FALSE;
#endif
else
return TRUE;
}

View File

@ -148,6 +148,9 @@ const struct FormChange *const gFormChangeTablePointers[NUM_SPECIES] =
[SPECIES_AEGISLASH_BLADE] = sAegislashFormChangeTable,
[SPECIES_XERNEAS] = sXerneasFormChangeTable,
[SPECIES_XERNEAS_ACTIVE] = sXerneasFormChangeTable,
[SPECIES_ZYGARDE_10_POWER_CONSTRUCT] = sZygardePowerConstructFormChangeTable,
[SPECIES_ZYGARDE_50_POWER_CONSTRUCT] = sZygardePowerConstructFormChangeTable,
[SPECIES_ZYGARDE_COMPLETE] = sZygardePowerConstructFormChangeTable,
[SPECIES_DIANCIE] = sDiancieFormChangeTable,
[SPECIES_DIANCIE_MEGA] = sDiancieFormChangeTable,
[SPECIES_HOOPA] = sHoopaFormChangeTable,

View File

@ -24,6 +24,8 @@ FORM_CHANGE_WITHDRAW:
FORM_CHANGE_FAINT:
Form change activates when the Pokémon faints, either in battle or in the overworld by poison.
If species is not specified and it's on the player's side, it will try to use the value
saved in gBattleStruct->changedSpecies from a previous form change.
No parameters.
FORM_CHANGE_BATTLE_BEGIN:
@ -33,7 +35,8 @@ FORM_CHANGE_BATTLE_BEGIN:
param3 = a new move to replace it with, optional
FORM_CHANGE_BATTLE_END:
Form change activates at the end of a battle
Form change activates at the end of a battle. If species is not specified and it's on the player's side,
it will try to use the value saved in gBattleStruct->changedSpecies from a previous form change.
param1 = item to hold, optional
param2 = a move that will be replaced, optional
param3 = a new move to replace it with, optional
@ -42,10 +45,27 @@ FORM_CHANGE_BATTLE_SWITCH:
Form change activates when the Pokémon is switched out in battle.
No parameters.
FORM_CHANGE_BATTLE_HP_PERCENT:
Form change activates when the Pokémon's HP % passes a certain threshold.
param1 = Ability to check.
param2 = HP_HIGHER_THAN if the form triggers when the current HP is higher than the specified threshold.
HP_LOWER_EQ_THAN if the form triggers when the current HP is lower or equal than the specified threshold.
param3 = HP percentage threshold.
FORM_CHANGE_MEGA_EVOLUTION_ITEM:
Form change activates when the mon has the defined item. If it's on the player's side, it also requires
ITEM_MEGA_RING in the user's bag and for the player to choose to enable it.
param1 = item to hold.
FORM_CHANGE_MEGA_EVOLUTION_MOVE:
Form change activates when the mon has the defined move. If it's on the player's side, it also requires
ITEM_MEGA_RING in the user's bag and for the player to choose to enable it.
param1 = move to have.
FORM_CHANGE_PRIMAL_REVERSION:
Form change activates when entering battle with the specified item. If the item is a Red Orb,
Form change activates automatically when entering battle with the specified item. If the item is a Red Orb,
it uses the Omega Symbol for the animation and icon. Otherwise, it defaults to Alpha.
param1 = item to hold, required.
param1 = item to hold.
*/
// FORM_CHANGE_MOVE param2 Arguments
@ -440,14 +460,16 @@ static const struct FormChange sAudinoFormChangeTable[] = {
};
static const struct FormChange sDarmanitanFormChangeTable[] = {
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_DARMANITAN},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_DARMANITAN, ABILITY_ZEN_MODE, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_DARMANITAN_ZEN_MODE, ABILITY_ZEN_MODE, HP_LOWER_EQ_THAN, 50},
{FORM_CHANGE_FAINT, SPECIES_DARMANITAN},
{FORM_CHANGE_BATTLE_END, SPECIES_DARMANITAN},
{FORM_CHANGE_END},
};
static const struct FormChange sDarmanitanGalarianFormChangeTable[] = {
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_DARMANITAN_GALARIAN},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_DARMANITAN_GALARIAN, ABILITY_ZEN_MODE, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_DARMANITAN_ZEN_MODE_GALARIAN, ABILITY_ZEN_MODE, HP_LOWER_EQ_THAN, 50},
{FORM_CHANGE_FAINT, SPECIES_DARMANITAN_GALARIAN},
{FORM_CHANGE_BATTLE_END, SPECIES_DARMANITAN_GALARIAN},
{FORM_CHANGE_END},
@ -513,6 +535,13 @@ static const struct FormChange sXerneasFormChangeTable[] = {
{FORM_CHANGE_END},
};
static const struct FormChange sZygardePowerConstructFormChangeTable[] = {
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_ZYGARDE_COMPLETE, ABILITY_POWER_CONSTRUCT, HP_LOWER_EQ_THAN, 50},
{FORM_CHANGE_FAINT},
{FORM_CHANGE_BATTLE_END},
{FORM_CHANGE_END},
};
static const struct FormChange sDiancieFormChangeTable[] = {
{FORM_CHANGE_MEGA_EVOLUTION_ITEM, SPECIES_DIANCIE_MEGA, ITEM_DIANCITE},
{FORM_CHANGE_FAINT, SPECIES_DIANCIE},
@ -536,6 +565,8 @@ static const struct FormChange sOricorioFormChangeTable[] = {
{FORM_CHANGE_END},
};
static const struct FormChange sWishiwashiFormChangeTable[] = {
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_WISHIWASHI_SCHOOL, ABILITY_SCHOOLING, HP_HIGHER_THAN, 25},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_WISHIWASHI, ABILITY_SCHOOLING, HP_LOWER_EQ_THAN, 25},
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_WISHIWASHI},
{FORM_CHANGE_FAINT, SPECIES_WISHIWASHI},
{FORM_CHANGE_BATTLE_END, SPECIES_WISHIWASHI},
@ -571,52 +602,67 @@ static const struct FormChange sMimikyuFormChangeTable[] = {
};
static const struct FormChange sMiniorRedFormChangeTable[] = {
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_RED, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_RED},
{FORM_CHANGE_FAINT, SPECIES_MINIOR_CORE_RED},
{FORM_CHANGE_BATTLE_END, SPECIES_MINIOR_CORE_RED},
{FORM_CHANGE_END},
};
static const struct FormChange sMiniorBlueFormChangeTable[] = {
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_BLUE, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_BLUE, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_BLUE},
{FORM_CHANGE_FAINT, SPECIES_MINIOR_CORE_BLUE},
{FORM_CHANGE_BATTLE_END, SPECIES_MINIOR_CORE_BLUE},
{FORM_CHANGE_END},
};
static const struct FormChange sMiniorGreenFormChangeTable[] = {
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_GREEN, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_GREEN, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_GREEN},
{FORM_CHANGE_FAINT, SPECIES_MINIOR_CORE_GREEN},
{FORM_CHANGE_BATTLE_END, SPECIES_MINIOR_CORE_GREEN},
{FORM_CHANGE_END},
};
static const struct FormChange sMiniorIndigoFormChangeTable[] = {
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_INDIGO, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_INDIGO, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_INDIGO},
{FORM_CHANGE_FAINT, SPECIES_MINIOR_CORE_INDIGO},
{FORM_CHANGE_BATTLE_END, SPECIES_MINIOR_CORE_INDIGO},
{FORM_CHANGE_END},
};
static const struct FormChange sMiniorOrangeFormChangeTable[] = {
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_ORANGE, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_ORANGE, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_ORANGE},
{FORM_CHANGE_FAINT, SPECIES_MINIOR_CORE_ORANGE},
{FORM_CHANGE_BATTLE_END, SPECIES_MINIOR_CORE_ORANGE},
{FORM_CHANGE_END},
};
static const struct FormChange sMiniorVioletFormChangeTable[] = {
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_VIOLET, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_VIOLET, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_VIOLET},
{FORM_CHANGE_FAINT, SPECIES_MINIOR_CORE_VIOLET},
{FORM_CHANGE_BATTLE_END, SPECIES_MINIOR_CORE_VIOLET},
{FORM_CHANGE_END},
};
static const struct FormChange sMiniorYellowFormChangeTable[] = {
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_YELLOW, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_YELLOW, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_YELLOW},
{FORM_CHANGE_FAINT, SPECIES_MINIOR_CORE_YELLOW},
{FORM_CHANGE_BATTLE_END, SPECIES_MINIOR_CORE_YELLOW},
{FORM_CHANGE_END},
};
#endif
#if P_GEN_8_POKEMON == TRUE
static const struct FormChange sCramorantFormChangeTable[] = {
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_CRAMORANT_GULPING, ABILITY_GULP_MISSILE, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_CRAMORANT_GORGING, ABILITY_GULP_MISSILE, HP_LOWER_EQ_THAN, 50},
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_CRAMORANT},
{FORM_CHANGE_FAINT, SPECIES_CRAMORANT},
{FORM_CHANGE_BATTLE_END, SPECIES_CRAMORANT},

View File

@ -256,7 +256,8 @@ static u16 TakeSelectedPokemonFromDaycare(struct DaycareMon *daycareMon)
BoxMonToMon(&daycareMon->mon, &pokemon);
newSpecies = GetFormChangeTargetSpecies(&pokemon, FORM_CHANGE_WITHDRAW, 0);
if (newSpecies != SPECIES_NONE) {
if (newSpecies != SPECIES_NONE)
{
SetMonData(&pokemon, MON_DATA_SPECIES, &newSpecies);
CalculateMonStats(&pokemon);
species = newSpecies;

View File

@ -3999,13 +3999,14 @@ void CalculateMonStats(struct Pokemon *mon)
{
if (currentHP == 0 && oldMaxHP == 0)
currentHP = newMaxHP;
else if (currentHP != 0) {
// BUG: currentHP is unintentionally able to become <= 0 after the instruction below. This causes the pomeg berry glitch.
else if (currentHP != 0)
{
if (newMaxHP > oldMaxHP)
currentHP += newMaxHP - oldMaxHP;
#ifdef BUGFIX
if (currentHP <= 0)
currentHP = 1;
#endif
if (currentHP > newMaxHP)
currentHP = newMaxHP;
}
else
return;
@ -8398,12 +8399,7 @@ u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32
if (heldItem == formChanges[i].param1 || formChanges[i].param1 == ITEM_NONE)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_PRIMAL_REVERSION:
if (arg == formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_WITHDRAW:
case FORM_CHANGE_BATTLE_SWITCH:
case FORM_CHANGE_FAINT:
targetSpecies = formChanges[i].targetSpecies;
break;
@ -8415,6 +8411,23 @@ u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32
return targetSpecies;
}
bool32 DoesSpeciesHaveFormChangeMethod(u16 species, u16 method)
{
u32 i, j;
const struct FormChange *formChanges = gFormChangeTablePointers[species];
if (formChanges != NULL)
{
for (i = 0; formChanges[i].method != FORM_CHANGE_END; i++)
{
if (method == formChanges[i].method && species != formChanges[i].targetSpecies)
return TRUE;
}
}
return FALSE;
}
u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove)
{
u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
@ -8495,12 +8508,21 @@ bool32 ShouldShowFemaleDifferences(u16 species, u32 personality)
return (gBaseStats[species].flags & SPECIES_FLAG_GENDER_DIFFERENCE) && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE;
}
// Returns species that it transformed into. If it didn't, returns SPECIES_NONE.
bool32 TryFormChange(u32 monId, u32 side, u16 method)
{
u32 targetSpecies;
struct Pokemon *party = (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty;
u16 targetSpecies;
if (GetMonData(&party[monId], MON_DATA_SPECIES2, 0) == SPECIES_NONE
|| GetMonData(&party[monId], MON_DATA_SPECIES2, 0) == SPECIES_EGG)
return FALSE;
targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0);
if (targetSpecies == SPECIES_NONE)
targetSpecies = gBattleStruct->changedSpecies[monId];
if (targetSpecies != SPECIES_NONE)
{
TryToSetBattleFormChangeMoves(&party[monId], method);
@ -8508,6 +8530,7 @@ bool32 TryFormChange(u32 monId, u32 side, u16 method)
CalculateMonStats(&party[monId]);
return TRUE;
}
return FALSE;
}