added HP-based damage/healing interactions with Dynamax Pokemon

This commit is contained in:
AgustinGDLV 2023-03-21 11:36:04 -07:00
parent 69fd63a922
commit 788642347b
5 changed files with 211 additions and 77 deletions

View File

@ -60,6 +60,8 @@ bool32 IsDynamaxed(u16 battlerId);
bool32 CanDynamax(u16 battlerId);
void ApplyDynamaxHPMultiplier(u16 battlerId, struct Pokemon* mon);
void PrepareBattlerForDynamax(u16 battlerId);
u16 GetNonDynamaxHP(u16 battlerId);
u16 GetNonDynamaxMaxHP(u16 battlerId);
void UndoDynamax(u16 battlerId);
bool32 IsMoveBlockedByDynamax(u16 move);

View File

@ -132,6 +132,32 @@ void ApplyDynamaxHPMultiplier(u16 battlerId, struct Pokemon* mon)
}
}
// Returns the non-Dynamax HP of a Pokemon.
u16 GetNonDynamaxHP(u16 battlerId)
{
if (!IsDynamaxed(battlerId) || gBattleMons[battlerId].species == SPECIES_SHEDINJA)
return gBattleMons[battlerId].hp;
else
{
u16 mult = UQ_4_12(1.0/1.5); // placeholder
u16 hp = UQ_4_12_TO_INT((gBattleMons[battlerId].hp * mult) + UQ_4_12_ROUND);
return hp;
}
}
// Returns the non-Dynamax Max HP of a Pokemon.
u16 GetNonDynamaxMaxHP(u16 battlerId)
{
if (!IsDynamaxed(battlerId) || gBattleMons[battlerId].species == SPECIES_SHEDINJA)
return gBattleMons[battlerId].maxHP;
else
{
u16 mult = UQ_4_12(1.0/1.5); // placeholder
u16 maxHP = UQ_4_12_TO_INT((gBattleMons[battlerId].maxHP * mult) + UQ_4_12_ROUND);
return maxHP;
}
}
// Sets flags used for Dynamaxing and checks Gigantamax forms.
void PrepareBattlerForDynamax(u16 battlerId)
{

View File

@ -5400,7 +5400,7 @@ static void Cmd_moveend(void)
if (gProtectStructs[gBattlerTarget].spikyShielded && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
{
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_SPIKY_SHIELD);
@ -7030,7 +7030,7 @@ static void Cmd_switchineffects(void)
&& IsBattlerGrounded(gActiveBattler))
{
u8 spikesDmg = (5 - gSideTimers[GetBattlerSide(gActiveBattler)].spikesAmount) * 2;
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / (spikesDmg);
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / (spikesDmg);
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
@ -7819,7 +7819,7 @@ static bool32 TryCheekPouch(u32 battlerId, u32 itemId)
&& gBattleStruct->ateBerry[GetBattlerSide(battlerId)] & gBitTable[gBattlerPartyIndexes[battlerId]]
&& !BATTLER_MAX_HP(battlerId))
{
gBattleMoveDamage = gBattleMons[battlerId].maxHP / 3;
gBattleMoveDamage = GetNonDynamaxMaxHP(battlerId) / 3;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
@ -9018,7 +9018,7 @@ static void Cmd_various(void)
}
else
{
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
@ -9653,9 +9653,9 @@ static void Cmd_various(void)
else
{
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_MEGA_LAUNCHER && gBattleMoves[gCurrentMove].flags & FLAG_MEGA_LAUNCHER_BOOST)
gBattleMoveDamage = -(gBattleMons[gActiveBattler].maxHP * 75 / 100);
gBattleMoveDamage = -(GetNonDynamaxMaxHP(gActiveBattler) * 75 / 100);
else
gBattleMoveDamage = -(gBattleMons[gActiveBattler].maxHP / 2);
gBattleMoveDamage = -(GetNonDynamaxMaxHP(gActiveBattler) / 2);
if (gBattleMoveDamage == 0)
gBattleMoveDamage = -1;
@ -10408,7 +10408,7 @@ static void Cmd_various(void)
case VARIOUS_TRY_HEAL_QUARTER_HP:
{
VARIOUS_ARGS(const u8 *failInstr);
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 4;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
@ -10738,7 +10738,7 @@ static void Cmd_various(void)
VARIOUS_ARGS(const u8 *failInstr);
bool8 atLeastOneStatBoosted = FALSE;
u16 hpFraction = max(1, gBattleMons[gBattlerAttacker].maxHP / 3);
u16 hpFraction = max(1, GetNonDynamaxMaxHP(gBattlerAttacker) / 3);
for (i = 1; i < NUM_STATS; i++)
{
@ -11170,7 +11170,7 @@ static void Cmd_various(void)
&& IsBattlerAlive(gBattlerAttacker)
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 6;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 6;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
}
@ -11293,6 +11293,7 @@ static void Cmd_various(void)
case VARIOUS_TRY_HEAL_SIXTH_HP:
{
VARIOUS_ARGS(const u8 *failInstr);
// This heals based on Dynamaxed HP!
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 6;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
@ -11526,7 +11527,7 @@ static void Cmd_tryhealhalfhealth(void)
if (cmd->battler == BS_ATTACKER)
gBattlerTarget = gBattlerAttacker;
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerTarget) / 2;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
@ -11661,10 +11662,10 @@ static void Cmd_manipulatedamage(void)
break;
case DMG_RECOIL_FROM_MISS:
#if B_RECOIL_IF_MISS_DMG >= GEN_5
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
#elif B_RECOIL_IF_MISS_DMG == GEN_4
if ((gBattleMons[gBattlerTarget].maxHP / 2) < gBattleMoveDamage)
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerTarget) / 2;
#else
gBattleMoveDamage /= 2;
#endif
@ -11675,24 +11676,24 @@ static void Cmd_manipulatedamage(void)
gBattleMoveDamage *= 2;
break;
case DMG_1_8_TARGET_HP:
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerTarget) / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
break;
case DMG_FULL_ATTACKER_HP:
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker);
break;
case DMG_CURR_ATTACKER_HP:
gBattleMoveDamage = gBattleMons[gBattlerAttacker].hp;
gBattleMoveDamage = GetNonDynamaxHP(gBattlerAttacker);
break;
case DMG_BIG_ROOT:
gBattleMoveDamage = GetDrainedBigRootHp(gBattlerAttacker, gBattleMoveDamage);
break;
case DMG_1_2_ATTACKER_HP:
gBattleMoveDamage = (gBattleMons[gBattlerAttacker].maxHP + 1) / 2; // Half of Max HP Rounded UP
gBattleMoveDamage = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP
break;
case DMG_RECOIL_FROM_IMMUNE:
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerTarget) / 2;
break;
}
@ -11877,7 +11878,7 @@ static void Cmd_stockpiletohpheal(void)
}
else
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / (1 << (3 - gDisableStructs[gBattlerAttacker].stockpileCounter));
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / (1 << (3 - gDisableStructs[gBattlerAttacker].stockpileCounter));
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
@ -12785,7 +12786,7 @@ static void Cmd_damagetohalftargethp(void)
{
CMD_ARGS();
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp / 2;
gBattleMoveDamage = GetNonDynamaxHP(gBattlerTarget) / 2;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
@ -12829,7 +12830,7 @@ static void Cmd_weatherdamage(void)
&& !(gStatuses3[gBattlerAttacker] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER))
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES)
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 16;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
}
@ -12842,7 +12843,7 @@ static void Cmd_weatherdamage(void)
&& !(gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK))
{
gBattlerAbility = gBattlerAttacker;
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 16;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
@ -12854,7 +12855,7 @@ static void Cmd_weatherdamage(void)
&& !(gStatuses3[gBattlerAttacker] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER))
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES)
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 16;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
}
@ -13035,8 +13036,8 @@ static void Cmd_setsubstitute(void)
{
CMD_ARGS();
u32 hp = gBattleMons[gBattlerAttacker].maxHP / 4;
if (gBattleMons[gBattlerAttacker].maxHP / 4 == 0)
u32 hp = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
if (GetNonDynamaxMaxHP(gBattlerAttacker) / 4 == 0)
hp = 1;
if (gBattleMons[gBattlerAttacker].hp <= hp)
@ -13046,7 +13047,7 @@ static void Cmd_setsubstitute(void)
}
else
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 4; // one bit value will only work for pokemon which max hp can go to 1020(which is more than possible in games)
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; // one bit value will only work for pokemon which max hp can go to 1020(which is more than possible in games)
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
@ -13300,7 +13301,7 @@ static void Cmd_painsplitdmgcalc(void)
if (!(DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove)))
{
s32 hpDiff = (gBattleMons[gBattlerAttacker].hp + gBattleMons[gBattlerTarget].hp) / 2;
s32 hpDiff = (gBattleMons[gBattlerAttacker].hp + GetNonDynamaxHP(gBattlerTarget)) / 2;
s32 painSplitHp = gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - hpDiff;
u8 *storeLoc = (void *)(&gBattleScripting.painSplitHp);
@ -13749,7 +13750,7 @@ static void Cmd_cursetarget(void)
else
{
gBattleMons[gBattlerTarget].status2 |= STATUS2_CURSED;
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
@ -13915,7 +13916,7 @@ static void Cmd_presentdamagecalculation(void)
}
else
{
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 4;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerTarget) / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
@ -14081,9 +14082,9 @@ static void Cmd_maxattackhalvehp(void)
{
CMD_ARGS(const u8 *failInstr);
u32 halfHp = gBattleMons[gBattlerAttacker].maxHP / 2;
u32 halfHp = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
if (!(gBattleMons[gBattlerAttacker].maxHP / 2))
if (!(GetNonDynamaxMaxHP(gBattlerAttacker) / 2))
halfHp = 1;
// Belly Drum fails if the user's current HP is less than half its maximum, or if the user's Attack is already at +6 (even if the user has Contrary).
@ -14091,7 +14092,7 @@ static void Cmd_maxattackhalvehp(void)
&& gBattleMons[gBattlerAttacker].hp > halfHp)
{
gBattleMons[gBattlerAttacker].statStages[STAT_ATK] = MAX_STAT_STAGE;
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
@ -14199,18 +14200,18 @@ static void Cmd_recoverbasedonsunlight(void)
if (gCurrentMove == MOVE_SHORE_UP)
{
if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SANDSTORM)
gBattleMoveDamage = 20 * gBattleMons[gBattlerAttacker].maxHP / 30;
gBattleMoveDamage = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30;
else
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
}
else
{
if (!(gBattleWeather & B_WEATHER_ANY) || !WEATHER_HAS_EFFECT || GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_UTILITY_UMBRELLA)
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
else if (gBattleWeather & B_WEATHER_SUN)
gBattleMoveDamage = 20 * gBattleMons[gBattlerAttacker].maxHP / 30;
gBattleMoveDamage = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30;
else // not sunny weather
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 4;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
}
if (gBattleMoveDamage == 0)
@ -14737,7 +14738,7 @@ static void Cmd_trywish(void)
else
gBattleMoveDamage = max(1, GetMonData(&gEnemyParty[gWishFutureKnock.wishPartyId[gBattlerTarget]], MON_DATA_MAX_HP) / 2);
#else
gBattleMoveDamage = max(1, gBattleMons[gBattlerTarget].maxHP / 2);
gBattleMoveDamage = max(1, GetNonDynamaxMaxHP(gBattlerAttacker) / 2);
#endif
gBattleMoveDamage *= -1;
@ -14817,13 +14818,13 @@ static void Cmd_setdamagetohealthdifference(void)
{
CMD_ARGS(const u8 *failInstr);
if (gBattleMons[gBattlerTarget].hp <= gBattleMons[gBattlerAttacker].hp)
if (GetNonDynamaxHP(gBattlerTarget) <= gBattleMons[gBattlerAttacker].hp)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else
{
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - gBattleMons[gBattlerAttacker].hp;
gBattleMoveDamage = GetNonDynamaxHP(gBattlerTarget) - gBattleMons[gBattlerAttacker].hp;
gBattlescriptCurrInstr = cmd->nextInstr;
}
}
@ -15091,7 +15092,7 @@ static void Cmd_switchoutabilities(void)
MarkBattlerForControllerExec(gActiveBattler);
break;
case ABILITY_REGENERATOR:
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 3;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 3;
gBattleMoveDamage += gBattleMons[gActiveBattler].hp;
if (gBattleMoveDamage > gBattleMons[gActiveBattler].maxHP)
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP;

View File

@ -2707,7 +2707,7 @@ u8 DoBattlerEndTurnEffects(void)
&& !(gStatuses3[gActiveBattler] & STATUS3_HEAL_BLOCK)
&& gBattleMons[gActiveBattler].hp != 0)
{
gBattleMoveDamage = GetDrainedBigRootHp(gActiveBattler, gBattleMons[gActiveBattler].maxHP / 16);
gBattleMoveDamage = GetDrainedBigRootHp(gActiveBattler, GetNonDynamaxMaxHP(gActiveBattler) / 16);
BattleScriptExecute(BattleScript_IngrainTurnHeal);
effect++;
}
@ -2719,7 +2719,7 @@ u8 DoBattlerEndTurnEffects(void)
&& !(gStatuses3[gActiveBattler] & STATUS3_HEAL_BLOCK)
&& gBattleMons[gActiveBattler].hp != 0)
{
gBattleMoveDamage = GetDrainedBigRootHp(gActiveBattler, gBattleMons[gActiveBattler].maxHP / 16);
gBattleMoveDamage = GetDrainedBigRootHp(gActiveBattler, GetNonDynamaxMaxHP(gActiveBattler) / 16);
BattleScriptExecute(BattleScript_AquaRingHeal);
effect++;
}
@ -2753,7 +2753,7 @@ u8 DoBattlerEndTurnEffects(void)
MAGIC_GUARD_CHECK;
gBattlerTarget = gStatuses3[gActiveBattler] & STATUS3_LEECHSEED_BATTLER; // Notice gBattlerTarget is actually the HP receiver.
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleScripting.animArg1 = gBattlerTarget;
@ -2773,7 +2773,7 @@ u8 DoBattlerEndTurnEffects(void)
{
if (!BATTLER_MAX_HP(gActiveBattler) && !(gStatuses3[gActiveBattler] & STATUS3_HEAL_BLOCK))
{
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
@ -2783,7 +2783,7 @@ u8 DoBattlerEndTurnEffects(void)
}
else
{
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptExecute(BattleScript_PoisonTurnDmg);
@ -2802,7 +2802,7 @@ u8 DoBattlerEndTurnEffects(void)
{
if (!BATTLER_MAX_HP(gActiveBattler) && !(gStatuses3[gActiveBattler] & STATUS3_HEAL_BLOCK))
{
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
@ -2812,7 +2812,7 @@ u8 DoBattlerEndTurnEffects(void)
}
else
{
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
if ((gBattleMons[gActiveBattler].status1 & STATUS1_TOXIC_COUNTER) != STATUS1_TOXIC_TURN(15)) // not 16 turns
@ -2830,9 +2830,9 @@ u8 DoBattlerEndTurnEffects(void)
{
MAGIC_GUARD_CHECK;
#if B_BURN_DAMAGE >= GEN_7
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 16;
#else
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 8;
#endif
if (ability == ABILITY_HEATPROOF)
{
@ -2856,7 +2856,7 @@ u8 DoBattlerEndTurnEffects(void)
// persist even after the affected Pokemon has been awakened by Shed Skin.
if (gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP)
{
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 4;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptExecute(BattleScript_NightmareTurnDmg);
@ -2874,7 +2874,7 @@ u8 DoBattlerEndTurnEffects(void)
&& gBattleMons[gActiveBattler].hp != 0)
{
MAGIC_GUARD_CHECK;
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 4;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptExecute(BattleScript_CurseTurnDmg);
@ -2895,13 +2895,13 @@ u8 DoBattlerEndTurnEffects(void)
gBattlescriptCurrInstr = BattleScript_WrapTurnDmg;
if (GetBattlerHoldEffect(gBattleStruct->wrappedBy[gActiveBattler], TRUE) == HOLD_EFFECT_BINDING_BAND)
#if B_BINDING_DAMAGE >= GEN_6
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 6;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 6;
else
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 8;
#else
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 8;
else
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16;
gBattleMoveDamage = GetNonDynamaxMaxHP(gActiveBattler) / 16;
#endif
if (gBattleMoveDamage == 0)
@ -3795,7 +3795,7 @@ u8 AtkCanceller_UnableToUseMove(void)
if (moveType == TYPE_FIRE)
{
gProtectStructs[gBattlerAttacker].powderSelfDmg = TRUE;
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 4;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
gBattlescriptCurrInstr = BattleScript_MoveUsedPowder;
effect = 1;
}
@ -4961,7 +4961,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
&& !(gStatuses3[battler] & STATUS3_HEAL_BLOCK))
{
BattleScriptPushCursorAndCallback(BattleScript_RainDishActivates);
gBattleMoveDamage = gBattleMons[battler].maxHP / (gLastUsedAbility == ABILITY_RAIN_DISH ? 16 : 8);
gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / (gLastUsedAbility == ABILITY_RAIN_DISH ? 16 : 8);
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
@ -5065,7 +5065,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
if (IsBattlerWeatherAffected(battler, B_WEATHER_SUN))
{
BattleScriptPushCursorAndCallback(BattleScript_SolarPowerActivates);
gBattleMoveDamage = gBattleMons[battler].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
effect++;
@ -5275,7 +5275,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
else
gBattlescriptCurrInstr = BattleScript_MoveHPDrain_PPLoss;
gBattleMoveDamage = gBattleMons[battler].maxHP / 4;
gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
@ -5567,9 +5567,9 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
&& IsMoveMakingContact(move, gBattlerAttacker))
{
#if B_ROUGH_SKIN_DMG >= GEN_4
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 8;
#else
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 16;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 16;
#endif
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
@ -5594,7 +5594,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
}
else
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 4;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptPushCursor();
@ -5800,7 +5800,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
gBattleMons[gBattlerTarget].species = SPECIES_CRAMORANT;
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 4;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
}
@ -5813,7 +5813,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
gBattleMons[gBattlerTarget].species = SPECIES_CRAMORANT;
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 4;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
}
@ -6597,7 +6597,7 @@ static u8 HealConfuseBerry(u32 battlerId, u32 itemId, u8 flavorId, bool32 end2)
{
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, flavorId);
gBattleMoveDamage = gBattleMons[battlerId].maxHP / GetBattlerItemHoldEffectParam(battlerId, itemId);
gBattleMoveDamage = GetNonDynamaxMaxHP(battlerId) / GetBattlerItemHoldEffectParam(battlerId, itemId);
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
@ -6788,7 +6788,7 @@ static u8 ItemHealHp(u32 battlerId, u32 itemId, bool32 end2, bool32 percentHeal)
&& HasEnoughHpToEatBerry(battlerId, 2, itemId))
{
if (percentHeal)
gBattleMoveDamage = (gBattleMons[battlerId].maxHP * GetBattlerItemHoldEffectParam(battlerId, itemId) / 100) * -1;
gBattleMoveDamage = (GetNonDynamaxMaxHP(battlerId) * GetBattlerItemHoldEffectParam(battlerId, itemId) / 100) * -1;
else
gBattleMoveDamage = GetBattlerItemHoldEffectParam(battlerId, itemId) * -1;
@ -7389,7 +7389,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
}
else if (GetBattlerAbility(battlerId) != ABILITY_MAGIC_GUARD && !moveTurn)
{
gBattleMoveDamage = gBattleMons[battlerId].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(battlerId) / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptExecute(BattleScript_ItemHurtEnd2);
@ -7406,7 +7406,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn)
#endif
{
gBattleMoveDamage = gBattleMons[battlerId].maxHP / 16;
gBattleMoveDamage = GetNonDynamaxMaxHP(battlerId) / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
@ -7695,7 +7695,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD
&& gSpecialStatuses[gBattlerAttacker].damagedMons)
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 10;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 10;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
effect = ITEM_HP_CHANGE;
@ -7741,7 +7741,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
&& IsBattlerAlive(gBattlerAttacker)
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 6;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 6;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
effect = ITEM_HP_CHANGE;
@ -7812,7 +7812,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
&& IS_MOVE_PHYSICAL(gCurrentMove)
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
if (GetBattlerAbility(battlerId) == ABILITY_RIPEN)
@ -7832,7 +7832,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
&& IS_MOVE_SPECIAL(gCurrentMove)
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
if (GetBattlerAbility(battlerId) == ABILITY_RIPEN)
@ -7897,7 +7897,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
case HOLD_EFFECT_STICKY_BARB: // Not an orb per se, but similar effect, and needs to NOT activate with pickpocket
if (battlerAbility != ABILITY_MAGIC_GUARD)
{
gBattleMoveDamage = gBattleMons[battlerId].maxHP / 8;
gBattleMoveDamage = GetNonDynamaxMaxHP(battlerId) / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptExecute(BattleScript_ItemHurtEnd2);

View File

@ -2,10 +2,20 @@
#include "test_battle.h"
// TODO:
// Max Guard protects against Transform, Block (not Mean Look), Flower Shield, Gear Up, and so on (see Bulba).
// Imprison doesn't stop Max Moves.
// Max Moves change type as you'd expect with Normalize, Weather Ball, etc.
// (Unrelated) Refactor code to remove dynamax.usingMaxMove?
// TEST: Max Guard protects against Transform, Block (not Mean Look), Flower Shield, Gear Up, and so on (see Bulba).
// TEST: Imprison doesn't stop Max Moves. (how?)
// TEST: Max Moves change type as you'd expect with Normalize, Weather Ball, etc.
// TEST: Reverting HP after Dynamax rounds up, so does Endeavor?
// TEST: You use Struggle while Dynamaxed if out of PP.
// Refactor code to remove dynamax.usingMaxMove? Might keep for Raids
// Ditto cannot turn into a Gigantamax form.
// Interactions with a Dynamaxed Pokemon with Magic Bounce.
// Dynamax should not reset Speed Swap, Soak, or anything else from form changing.
// Multi Attack is treated in Max Move power calcs like a Fighting or Poison type move.
// Max Moves cannot be used against allies.
// G-Max Befuddle applies statuses before considering immunities.
// G-Max Replenish guarantees either both allies' berries or neithers.
// G-Max Sandwhatever still keeps Sand Tomb up when Sandaconda switches.
// ============= DYNAMAX AND MAX MOVE INTERACTIONS ===================
SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax increases HP and max HP by 1.5x")
@ -353,6 +363,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon take double damage from Dynamax
PARAMETRIZE { dynamaxed = FALSE; }
PARAMETRIZE { dynamaxed = TRUE; }
GIVEN {
ASSUME(gBattleMoves[MOVE_DYNAMAX_CANNON].effect == EFFECT_DYNAMAX_DOUBLE_DMG);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -511,6 +522,100 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot use Max Guard while holdi
}
}
// Almost anything that calculates gBattleMoveDamage based on HP has been changed to non-Dynamax HP.
// This includes Leftovers, Life Orb, Heal Pulse, Rocky Helmet, Sandstorm, etc. etc.
// There are some redundant cases (i.e Substitute) that can never be used by a Dynamaxed pokemon.
// Anything that is conditional based off max HP still uses gBattleMons[battler].maxHP.
// Below are some tests, but very far from all encompassing:
SINGLE_BATTLE_TEST("(DYNAMAX) Endeavor uses a Pokemon's non-Dynamax HP")
{
s16 damage;
GIVEN {
ASSUME(gBattleMoves[MOVE_ENDEAVOR].effect == EFFECT_ENDEAVOR);
PLAYER(SPECIES_WOBBUFFET) { MaxHP(100); Speed(50); }
OPPONENT(SPECIES_WOBBUFFET) { HP(1); MaxHP(100); Speed(100); }
} WHEN {
TURN { MOVE(opponent, MOVE_ENDEAVOR); MOVE(player, MOVE_TACKLE, dynamax: TRUE); }
} SCENE {
MESSAGE("Foe Wobbuffet used Endeavor!");
HP_BAR(player, captureDamage: &damage);
} FINALLY {
EXPECT_EQ(damage, 99); // difference between foe's HP and player's non-dynamax HP
}
}
SINGLE_BATTLE_TEST("(DYNAMAX) Super Fang uses a Pokemon's non-Dynamax HP")
{
s16 damage;
GIVEN {
ASSUME(gBattleMoves[MOVE_SUPER_FANG].effect == EFFECT_SUPER_FANG);
PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(100); Speed(50); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(100); }
} WHEN {
TURN { MOVE(opponent, MOVE_SUPER_FANG); MOVE(player, MOVE_TACKLE, dynamax: TRUE); }
} SCENE {
MESSAGE("Foe Wobbuffet used Super Fang!");
HP_BAR(player, captureDamage: &damage);
} FINALLY {
EXPECT_EQ(damage, 25);
}
}
SINGLE_BATTLE_TEST("(DYNAMAX) Pain Split uses a Pokemon's non-Dynamax HP")
{
s16 damage;
GIVEN {
ASSUME(gBattleMoves[MOVE_PAIN_SPLIT].effect == EFFECT_PAIN_SPLIT);
PLAYER(SPECIES_WOBBUFFET) { HP(60); MaxHP(100); Speed(50); }
OPPONENT(SPECIES_WOBBUFFET) { HP(40); MaxHP(100); Speed(100); }
} WHEN {
TURN { MOVE(opponent, MOVE_PAIN_SPLIT); MOVE(player, MOVE_TACKLE, dynamax: TRUE); }
} SCENE {
MESSAGE("Foe Wobbuffet used Pain Split!");
HP_BAR(player, captureDamage: &damage);
} FINALLY {
EXPECT_EQ(damage, 10);
}
}
SINGLE_BATTLE_TEST("(DYNAMAX) Sitrus Berries heal based on a Pokemon's non-Dynamax HP")
{
s16 damage;
GIVEN {
ASSUME(I_SITRUS_BERRY_HEAL >= GEN_4);
ASSUME(gItems[ITEM_SITRUS_BERRY].holdEffect == HOLD_EFFECT_RESTORE_PCT_HP);
PLAYER(SPECIES_WOBBUFFET) { HP(60); MaxHP(100); Speed(50); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_WOBBUFFET) { HP(40); MaxHP(100); Speed(100); }
} WHEN {
TURN { MOVE(opponent, MOVE_PAIN_SPLIT); MOVE(player, MOVE_TACKLE, dynamax: TRUE); }
} SCENE {
MESSAGE("Foe Wobbuffet used Pain Split!");
HP_BAR(player);
MESSAGE("Wobbuffet's Sitrus Berry restored health!");
HP_BAR(player, captureDamage: &damage);
} FINALLY {
EXPECT_EQ(damage, 25);
}
}
SINGLE_BATTLE_TEST("(DYNAMAX) Heal Pulse heals based on a Pokemon's non-Dynamax HP")
{
s16 damage;
GIVEN {
ASSUME(gBattleMoves[MOVE_HEAL_PULSE].effect == EFFECT_HEAL_PULSE);
PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(100); Speed(50); }
OPPONENT(SPECIES_WOBBUFFET) { MaxHP(100); Speed(100); }
} WHEN {
TURN { MOVE(opponent, MOVE_HEAL_PULSE); MOVE(player, MOVE_TACKLE, dynamax: TRUE); }
} SCENE {
MESSAGE("Foe Wobbuffet used Heal Pulse!");
HP_BAR(player, captureDamage: &damage);
} FINALLY {
EXPECT_EQ(damage, 50);
}
}
// ============= MAX MOVE EFFECTS ==========================================
SINGLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers single opponent's speed")
{