Refactor damage calculations aruguments by using a struct context (#7108)
This commit is contained in:
parent
75982721cd
commit
e1b542944f
@ -159,7 +159,7 @@ enum {
|
||||
|
||||
extern const struct TypePower gNaturalGiftTable[];
|
||||
|
||||
struct DamageCalculationData
|
||||
struct DamageContext
|
||||
{
|
||||
u32 battlerAtk:3;
|
||||
u32 battlerDef:3;
|
||||
@ -168,9 +168,16 @@ struct DamageCalculationData
|
||||
u32 isCrit:1;
|
||||
u32 randomFactor:1;
|
||||
u32 updateFlags:1;
|
||||
u32 padding:2;
|
||||
u32 padding1:2;
|
||||
u32 weather:16;
|
||||
u32 fixedBasePower:8;
|
||||
u32 padding2:8;
|
||||
uq4_12_t typeEffectivenessModifier;
|
||||
u32 abilityAtk:16;
|
||||
u32 abilityDef:16;
|
||||
enum ItemHoldEffect holdEffectAtk:16;
|
||||
enum ItemHoldEffect holdEffectDef:16;
|
||||
};
|
||||
STATIC_ASSERT(sizeof(struct DamageCalculationData) <= 4, StructExceedsFourBytes);
|
||||
|
||||
enum SleepClauseBlock
|
||||
{
|
||||
@ -272,10 +279,9 @@ u32 GetMoveSlot(u16 *moves, u32 move);
|
||||
u32 GetBattlerWeight(u32 battler);
|
||||
u32 CalcRolloutBasePower(u32 battlerAtk, u32 basePower, u32 rolloutTimer);
|
||||
u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter);
|
||||
s32 CalculateMoveDamage(struct DamageCalculationData *damageCalcData, u32 fixedBasePower);
|
||||
s32 CalculateMoveDamageVars(struct DamageCalculationData *damageCalcData, u32 fixedBasePower, uq4_12_t typeEffectivenessModifier,
|
||||
u32 weather, enum ItemHoldEffect holdEffectAtk, enum ItemHoldEffect holdEffectDef, u32 abilityAtk, u32 abilityDef);
|
||||
s32 ApplyModifiersAfterDmgRoll(s32 dmg, struct DamageCalculationData *damageCalcData, uq4_12_t typeEffectivenessModifier, u32 abilityAtk, u32 abilityDef, enum ItemHoldEffect holdEffectAtk, enum ItemHoldEffect holdEffectDef);
|
||||
s32 CalculateMoveDamage(struct DamageContext *ctx);
|
||||
s32 CalculateMoveDamageVars(struct DamageContext *ctx);
|
||||
s32 ApplyModifiersAfterDmgRoll(struct DamageContext *ctx, s32 dmg);
|
||||
uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 defAbility, bool32 recordAbilities);
|
||||
uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef);
|
||||
uq4_12_t GetTypeModifier(u32 atkType, u32 defType);
|
||||
|
||||
@ -616,10 +616,9 @@ static inline void AI_RestoreBattlerTypes(u32 battlerAtk, u32 *types)
|
||||
gBattleMons[battlerAtk].types[2] = types[2];
|
||||
}
|
||||
|
||||
static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCalcData, u16 *medianDamage, u16 *minimumDamage, u16 *maximumDamage, enum ItemHoldEffect holdEffectAtk, u32 abilityAtk)
|
||||
static inline void CalcDynamicMoveDamage(struct DamageContext *ctx, u16 *medianDamage, u16 *minimumDamage, u16 *maximumDamage)
|
||||
{
|
||||
u32 move = damageCalcData->move;
|
||||
enum BattleMoveEffects effect = GetMoveEffect(move);
|
||||
enum BattleMoveEffects effect = GetMoveEffect(ctx->move);
|
||||
u16 median = *medianDamage;
|
||||
u16 minimum = *minimumDamage;
|
||||
u16 maximum = *maximumDamage;
|
||||
@ -627,19 +626,19 @@ static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCal
|
||||
switch (effect)
|
||||
{
|
||||
case EFFECT_MULTI_HIT:
|
||||
if (move == MOVE_WATER_SHURIKEN && gBattleMons[damageCalcData->battlerAtk].species == SPECIES_GRENINJA_ASH)
|
||||
if (ctx->move == MOVE_WATER_SHURIKEN && gBattleMons[ctx->battlerAtk].species == SPECIES_GRENINJA_ASH)
|
||||
{
|
||||
median *= 3;
|
||||
minimum *= 3;
|
||||
maximum *= 3;
|
||||
}
|
||||
else if (abilityAtk == ABILITY_SKILL_LINK)
|
||||
else if (ctx->abilityAtk == ABILITY_SKILL_LINK)
|
||||
{
|
||||
median *= 5;
|
||||
minimum *= 5;
|
||||
maximum *= 5;
|
||||
}
|
||||
else if (holdEffectAtk == HOLD_EFFECT_LOADED_DICE)
|
||||
else if (ctx->holdEffectAtk == HOLD_EFFECT_LOADED_DICE)
|
||||
{
|
||||
median *= 9;
|
||||
median /= 2;
|
||||
@ -655,18 +654,19 @@ static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCal
|
||||
break;
|
||||
case EFFECT_ENDEAVOR:
|
||||
// If target has less HP than user, Endeavor does no damage
|
||||
median = maximum = minimum = max(0, gBattleMons[damageCalcData->battlerDef].hp - gBattleMons[damageCalcData->battlerAtk].hp);
|
||||
median = maximum = minimum = max(0, gBattleMons[ctx->battlerDef].hp - gBattleMons[ctx->battlerAtk].hp);
|
||||
break;
|
||||
case EFFECT_BEAT_UP:
|
||||
if (B_BEAT_UP >= GEN_5)
|
||||
{
|
||||
u32 partyCount = CalculatePartyCount(GetBattlerParty(damageCalcData->battlerAtk));
|
||||
u32 partyCount = CalculatePartyCount(GetBattlerParty(ctx->battlerAtk));
|
||||
u32 i;
|
||||
gBattleStruct->beatUpSlot = 0;
|
||||
damageCalcData->isCrit = FALSE;
|
||||
ctx->isCrit = FALSE;
|
||||
ctx->fixedBasePower = 0;
|
||||
median = 0;
|
||||
for (i = 0; i < partyCount; i++)
|
||||
median += CalculateMoveDamage(damageCalcData, 0);
|
||||
median += CalculateMoveDamage(ctx);
|
||||
maximum = minimum = median;
|
||||
gBattleStruct->beatUpSlot = 0;
|
||||
}
|
||||
@ -676,7 +676,7 @@ static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCal
|
||||
}
|
||||
|
||||
// Handle other multi-strike moves
|
||||
u32 strikeCount = GetMoveStrikeCount(move);
|
||||
u32 strikeCount = GetMoveStrikeCount(ctx->move);
|
||||
if (strikeCount > 1 && effect != EFFECT_TRIPLE_KICK)
|
||||
{
|
||||
median *= strikeCount;
|
||||
@ -684,11 +684,11 @@ static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCal
|
||||
maximum *= strikeCount;
|
||||
}
|
||||
|
||||
if (abilityAtk == ABILITY_PARENTAL_BOND
|
||||
if (ctx->abilityAtk == ABILITY_PARENTAL_BOND
|
||||
&& !strikeCount
|
||||
&& effect != EFFECT_TRIPLE_KICK
|
||||
&& effect != EFFECT_MULTI_HIT
|
||||
&& !AI_IsDoubleSpreadMove(damageCalcData->battlerAtk, move))
|
||||
&& !AI_IsDoubleSpreadMove(ctx->battlerAtk, ctx->move))
|
||||
{
|
||||
median += median / (B_PARENTAL_BOND_DMG >= GEN_7 ? 4 : 2);
|
||||
minimum += minimum / (B_PARENTAL_BOND_DMG >= GEN_7 ? 4 : 2);
|
||||
@ -781,14 +781,21 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
||||
ProteanTryChangeType(battlerAtk, aiData->abilities[battlerAtk], move, moveType);
|
||||
s32 fixedBasePower = SetFixedMoveBasePower(battlerAtk, move);
|
||||
|
||||
struct DamageCalculationData damageCalcData;
|
||||
damageCalcData.battlerAtk = battlerAtk;
|
||||
damageCalcData.battlerDef = battlerDef;
|
||||
damageCalcData.move = move;
|
||||
damageCalcData.moveType = moveType;
|
||||
damageCalcData.isCrit = ShouldCalcCritDamage(battlerAtk, battlerDef, move, aiData);
|
||||
damageCalcData.randomFactor = FALSE;
|
||||
damageCalcData.updateFlags = FALSE;
|
||||
struct DamageContext ctx;
|
||||
ctx.battlerAtk = battlerAtk;
|
||||
ctx.battlerDef = battlerDef;
|
||||
ctx.move = move;
|
||||
ctx.moveType = moveType;
|
||||
ctx.isCrit = ShouldCalcCritDamage(battlerAtk, battlerDef, move, aiData);
|
||||
ctx.randomFactor = FALSE;
|
||||
ctx.updateFlags = FALSE;
|
||||
ctx.weather = weather;
|
||||
ctx.fixedBasePower = fixedBasePower;
|
||||
ctx.typeEffectivenessModifier = effectivenessMultiplier;
|
||||
ctx.abilityAtk = aiData->abilities[battlerAtk];
|
||||
ctx.abilityDef = aiData->abilities[battlerDef];
|
||||
ctx.holdEffectAtk = aiData->holdEffects[battlerAtk];
|
||||
ctx.holdEffectDef = aiData->holdEffects[battlerDef];
|
||||
|
||||
if (moveEffect == EFFECT_TRIPLE_KICK)
|
||||
{
|
||||
@ -796,59 +803,34 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
||||
{
|
||||
s32 damageByRollType = 0;
|
||||
|
||||
s32 oneTripleKickHit = CalculateMoveDamageVars(&damageCalcData, fixedBasePower,
|
||||
effectivenessMultiplier, weather,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
s32 oneTripleKickHit = CalculateMoveDamageVars(&ctx);
|
||||
|
||||
damageByRollType = GetDamageByRollType(oneTripleKickHit, DMG_ROLL_LOWEST);
|
||||
simDamage.minimum += ApplyModifiersAfterDmgRoll(damageByRollType, &damageCalcData, effectivenessMultiplier,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
simDamage.minimum += ApplyModifiersAfterDmgRoll(&ctx, damageByRollType);
|
||||
|
||||
damageByRollType = GetDamageByRollType(oneTripleKickHit, DMG_ROLL_DEFAULT);
|
||||
simDamage.median += ApplyModifiersAfterDmgRoll(damageByRollType, &damageCalcData, effectivenessMultiplier,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
simDamage.median += ApplyModifiersAfterDmgRoll(&ctx, damageByRollType);
|
||||
|
||||
damageByRollType = GetDamageByRollType(oneTripleKickHit, DMG_ROLL_HIGHEST);
|
||||
simDamage.maximum += ApplyModifiersAfterDmgRoll(damageByRollType, &damageCalcData, effectivenessMultiplier,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
simDamage.maximum += ApplyModifiersAfterDmgRoll(&ctx, damageByRollType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 damage = CalculateMoveDamageVars(&damageCalcData, fixedBasePower,
|
||||
effectivenessMultiplier, weather,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
u32 damage = CalculateMoveDamageVars(&ctx);
|
||||
|
||||
simDamage.minimum = GetDamageByRollType(damage, DMG_ROLL_LOWEST);
|
||||
simDamage.minimum = ApplyModifiersAfterDmgRoll(simDamage.minimum, &damageCalcData, effectivenessMultiplier,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
simDamage.minimum = ApplyModifiersAfterDmgRoll(&ctx, simDamage.minimum);
|
||||
|
||||
simDamage.median = GetDamageByRollType(damage, DMG_ROLL_DEFAULT);
|
||||
simDamage.median = ApplyModifiersAfterDmgRoll(simDamage.median, &damageCalcData, effectivenessMultiplier,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
simDamage.median = ApplyModifiersAfterDmgRoll(&ctx, simDamage.median);
|
||||
|
||||
simDamage.maximum = GetDamageByRollType(damage, DMG_ROLL_HIGHEST);
|
||||
simDamage.maximum = ApplyModifiersAfterDmgRoll(simDamage.maximum, &damageCalcData, effectivenessMultiplier,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
simDamage.maximum = ApplyModifiersAfterDmgRoll(&ctx, simDamage.maximum);
|
||||
}
|
||||
|
||||
if (GetActiveGimmick(battlerAtk) != GIMMICK_Z_MOVE)
|
||||
{
|
||||
CalcDynamicMoveDamage(&damageCalcData,
|
||||
&simDamage.median,
|
||||
&simDamage.minimum,
|
||||
&simDamage.maximum,
|
||||
aiData->holdEffects[battlerAtk],
|
||||
aiData->abilities[battlerAtk]);
|
||||
}
|
||||
CalcDynamicMoveDamage(&ctx, &simDamage.median, &simDamage.minimum, &simDamage.maximum);
|
||||
|
||||
AI_RestoreBattlerTypes(battlerAtk, types);
|
||||
}
|
||||
|
||||
@ -2063,18 +2063,18 @@ static void Cmd_critcalc(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static inline void CalculateAndSetMoveDamage(struct DamageCalculationData *damageCalcData, u32 battlerDef)
|
||||
static inline void CalculateAndSetMoveDamage(struct DamageContext *ctx)
|
||||
{
|
||||
SetDynamicMoveCategory(gBattlerAttacker, battlerDef, gCurrentMove);
|
||||
damageCalcData->battlerDef = battlerDef;
|
||||
damageCalcData->isCrit = gSpecialStatuses[battlerDef].criticalHit;
|
||||
gBattleStruct->moveDamage[battlerDef] = CalculateMoveDamage(damageCalcData, 0);
|
||||
SetDynamicMoveCategory(gBattlerAttacker, ctx->battlerDef, gCurrentMove);
|
||||
ctx->isCrit = gSpecialStatuses[ctx->battlerDef].criticalHit;
|
||||
ctx->fixedBasePower = 0;
|
||||
gBattleStruct->moveDamage[ctx->battlerDef] = CalculateMoveDamage(ctx);
|
||||
|
||||
// Slighly hacky but we need to check move result flags for distortion match-up as well but it can only be done after damage calcs
|
||||
if (gSpecialStatuses[battlerDef].distortedTypeMatchups && gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT)
|
||||
if (gSpecialStatuses[ctx->battlerDef].distortedTypeMatchups && gBattleStruct->moveResultFlags[ctx->battlerDef] & MOVE_RESULT_NO_EFFECT)
|
||||
{
|
||||
gSpecialStatuses[battlerDef].distortedTypeMatchups = FALSE;
|
||||
gSpecialStatuses[battlerDef].teraShellAbilityDone = FALSE;
|
||||
gSpecialStatuses[ctx->battlerDef].distortedTypeMatchups = FALSE;
|
||||
gSpecialStatuses[ctx->battlerDef].teraShellAbilityDone = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2090,12 +2090,12 @@ static void Cmd_damagecalc(void)
|
||||
|
||||
u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
|
||||
|
||||
struct DamageCalculationData damageCalcData;
|
||||
damageCalcData.battlerAtk = gBattlerAttacker;
|
||||
damageCalcData.move = gCurrentMove;
|
||||
damageCalcData.moveType = GetBattleMoveType(gCurrentMove);
|
||||
damageCalcData.randomFactor = TRUE;
|
||||
damageCalcData.updateFlags = TRUE;
|
||||
struct DamageContext ctx;
|
||||
ctx.battlerAtk = gBattlerAttacker;
|
||||
ctx.move = gCurrentMove;
|
||||
ctx.moveType = GetBattleMoveType(gCurrentMove);
|
||||
ctx.randomFactor = TRUE;
|
||||
ctx.updateFlags = TRUE;
|
||||
|
||||
if (IsSpreadMove(moveTarget))
|
||||
{
|
||||
@ -2107,12 +2107,14 @@ static void Cmd_damagecalc(void)
|
||||
|| gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT)
|
||||
continue;
|
||||
|
||||
CalculateAndSetMoveDamage(&damageCalcData, battlerDef);
|
||||
ctx.battlerDef = battlerDef;
|
||||
CalculateAndSetMoveDamage(&ctx);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CalculateAndSetMoveDamage(&damageCalcData, gBattlerTarget);
|
||||
ctx.battlerDef = gBattlerTarget;
|
||||
CalculateAndSetMoveDamage(&ctx);
|
||||
}
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
|
||||
@ -1261,15 +1261,16 @@ static void TrySetBattleSeminarShow(void)
|
||||
powerOverride = 0;
|
||||
if (ShouldCalculateDamage(gCurrentMove, &dmgByMove[i], &powerOverride))
|
||||
{
|
||||
struct DamageCalculationData damageCalcData;
|
||||
damageCalcData.battlerAtk = gBattlerAttacker;
|
||||
damageCalcData.battlerDef = gBattlerTarget;
|
||||
damageCalcData.move = gCurrentMove;
|
||||
damageCalcData.moveType = GetMoveType(gCurrentMove);
|
||||
damageCalcData.isCrit = FALSE;
|
||||
damageCalcData.randomFactor = FALSE;
|
||||
damageCalcData.updateFlags = FALSE;
|
||||
gBattleStruct->moveDamage[gBattlerTarget] = CalculateMoveDamage(&damageCalcData, powerOverride);
|
||||
struct DamageContext ctx;
|
||||
ctx.battlerAtk = gBattlerAttacker;
|
||||
ctx.battlerDef = gBattlerTarget;
|
||||
ctx.move = gCurrentMove;
|
||||
ctx.moveType = GetMoveType(gCurrentMove);
|
||||
ctx.isCrit = FALSE;
|
||||
ctx.randomFactor = FALSE;
|
||||
ctx.updateFlags = FALSE;
|
||||
ctx.fixedBasePower = powerOverride;
|
||||
gBattleStruct->moveDamage[gBattlerTarget] = CalculateMoveDamage(&ctx);
|
||||
dmgByMove[i] = gBattleStruct->moveDamage[gBattlerTarget];
|
||||
if (dmgByMove[i] == 0 && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
|
||||
dmgByMove[i] = 1;
|
||||
|
||||
@ -1969,14 +1969,15 @@ static void CancellerObedience(u32 *effect)
|
||||
break;
|
||||
case DISOBEYS_HITS_SELF:
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
struct DamageCalculationData damageCalcData;
|
||||
damageCalcData.battlerAtk = damageCalcData.battlerDef = gBattlerAttacker;
|
||||
damageCalcData.move = MOVE_NONE;
|
||||
damageCalcData.moveType = TYPE_MYSTERY;
|
||||
damageCalcData.isCrit = FALSE;
|
||||
damageCalcData.randomFactor = FALSE;
|
||||
damageCalcData.updateFlags = TRUE;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = CalculateMoveDamage(&damageCalcData, 40);
|
||||
struct DamageContext ctx;
|
||||
ctx.battlerAtk = ctx.battlerDef = gBattlerAttacker;
|
||||
ctx.move = MOVE_NONE;
|
||||
ctx.moveType = TYPE_MYSTERY;
|
||||
ctx.isCrit = FALSE;
|
||||
ctx.randomFactor = FALSE;
|
||||
ctx.updateFlags = TRUE;
|
||||
ctx.fixedBasePower = 40;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = CalculateMoveDamage(&ctx);
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
@ -2145,14 +2146,15 @@ static void CancellerConfused(u32 *effect)
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = TRUE;
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
struct DamageCalculationData damageCalcData;
|
||||
damageCalcData.battlerAtk = damageCalcData.battlerDef = gBattlerAttacker;
|
||||
damageCalcData.move = MOVE_NONE;
|
||||
damageCalcData.moveType = TYPE_MYSTERY;
|
||||
damageCalcData.isCrit = FALSE;
|
||||
damageCalcData.randomFactor = FALSE;
|
||||
damageCalcData.updateFlags = TRUE;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = CalculateMoveDamage(&damageCalcData, 40);
|
||||
struct DamageContext ctx;
|
||||
ctx.battlerAtk = ctx.battlerDef = gBattlerAttacker;
|
||||
ctx.move = MOVE_NONE;
|
||||
ctx.moveType = TYPE_MYSTERY;
|
||||
ctx.isCrit = FALSE;
|
||||
ctx.randomFactor = FALSE;
|
||||
ctx.updateFlags = TRUE;
|
||||
ctx.fixedBasePower = 40;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = CalculateMoveDamage(&ctx);
|
||||
gProtectStructs[gBattlerAttacker].confusionSelfDmg = TRUE;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfused;
|
||||
@ -7776,11 +7778,11 @@ u32 CountBattlerStatIncreases(u32 battler, bool32 countEvasionAcc)
|
||||
return count;
|
||||
}
|
||||
|
||||
u32 GetMoveTargetCount(struct DamageCalculationData *damageCalcData)
|
||||
u32 GetMoveTargetCount(struct DamageContext *ctx)
|
||||
{
|
||||
u32 battlerAtk = damageCalcData->battlerAtk;
|
||||
u32 battlerDef = damageCalcData->battlerDef;
|
||||
u32 move = damageCalcData->move;
|
||||
u32 battlerAtk = ctx->battlerAtk;
|
||||
u32 battlerDef = ctx->battlerDef;
|
||||
u32 move = ctx->move;
|
||||
|
||||
switch (GetBattlerMoveTargetType(battlerAtk, move))
|
||||
{
|
||||
@ -7919,11 +7921,11 @@ u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter)
|
||||
return basePower;
|
||||
}
|
||||
|
||||
static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData, u32 abilityDef, u32 weather)
|
||||
static inline u32 CalcMoveBasePower(struct DamageContext *ctx)
|
||||
{
|
||||
u32 battlerAtk = damageCalcData->battlerAtk;
|
||||
u32 battlerDef = damageCalcData->battlerDef;
|
||||
u32 move = damageCalcData->move;
|
||||
u32 battlerAtk = ctx->battlerAtk;
|
||||
u32 battlerDef = ctx->battlerDef;
|
||||
u32 move = ctx->move;
|
||||
|
||||
u32 i;
|
||||
u32 basePower = GetMovePower(move);
|
||||
@ -7988,7 +7990,7 @@ static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData
|
||||
basePower *= 2;
|
||||
break;
|
||||
case EFFECT_WEATHER_BALL:
|
||||
if (weather & B_WEATHER_ANY)
|
||||
if (ctx->weather & B_WEATHER_ANY)
|
||||
basePower *= 2;
|
||||
break;
|
||||
case EFFECT_PURSUIT:
|
||||
@ -8000,7 +8002,7 @@ static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData
|
||||
break;
|
||||
case EFFECT_DOUBLE_POWER_ON_ARG_STATUS:
|
||||
// Comatose targets treated as if asleep
|
||||
if ((gBattleMons[battlerDef].status1 | (STATUS1_SLEEP * (abilityDef == ABILITY_COMATOSE))) & GetMoveEffectArg_Status(move)
|
||||
if ((gBattleMons[battlerDef].status1 | (STATUS1_SLEEP * (ctx->abilityDef == ABILITY_COMATOSE))) & GetMoveEffectArg_Status(move)
|
||||
&& !((GetMoveAdditionalEffectById(move, 0)->moveEffect == MOVE_EFFECT_REMOVE_STATUS) && DoesSubstituteBlockMove(battlerAtk, battlerDef, move)))
|
||||
basePower *= 2;
|
||||
break;
|
||||
@ -8185,14 +8187,14 @@ static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData
|
||||
return basePower;
|
||||
}
|
||||
|
||||
static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData *damageCalcData, u32 atkAbility, u32 defAbility, enum ItemHoldEffect holdEffectAtk, u32 weather)
|
||||
static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx)
|
||||
{
|
||||
u32 holdEffectParamAtk;
|
||||
u32 basePower = CalcMoveBasePower(damageCalcData, defAbility, weather);
|
||||
u32 battlerAtk = damageCalcData->battlerAtk;
|
||||
u32 battlerDef = damageCalcData->battlerDef;
|
||||
u32 move = damageCalcData->move;
|
||||
u32 moveType = damageCalcData->moveType;
|
||||
u32 basePower = CalcMoveBasePower(ctx);
|
||||
u32 battlerAtk = ctx->battlerAtk;
|
||||
u32 battlerDef = ctx->battlerDef;
|
||||
u32 move = ctx->move;
|
||||
u32 moveType = ctx->moveType;
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
|
||||
|
||||
uq4_12_t holdEffectModifier;
|
||||
@ -8263,7 +8265,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData *
|
||||
modifier = uq4_12_multiply(modifier, UQ_4_12(B_SPORT_DMG_REDUCTION >= GEN_5 ? 0.33 : 0.5));
|
||||
|
||||
// attacker's abilities
|
||||
switch (atkAbility)
|
||||
switch (ctx->abilityAtk)
|
||||
{
|
||||
case ABILITY_TECHNICIAN:
|
||||
if (basePower <= 60)
|
||||
@ -8291,7 +8293,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData *
|
||||
break;
|
||||
case ABILITY_SAND_FORCE:
|
||||
if ((moveType == TYPE_STEEL || moveType == TYPE_ROCK || moveType == TYPE_GROUND)
|
||||
&& weather & B_WEATHER_SANDSTORM)
|
||||
&& ctx->weather & B_WEATHER_SANDSTORM)
|
||||
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
|
||||
break;
|
||||
case ABILITY_RIVALRY:
|
||||
@ -8391,15 +8393,15 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData *
|
||||
}
|
||||
|
||||
// target's abilities
|
||||
switch (defAbility)
|
||||
switch (ctx->abilityDef)
|
||||
{
|
||||
case ABILITY_HEATPROOF:
|
||||
case ABILITY_WATER_BUBBLE:
|
||||
if (moveType == TYPE_FIRE)
|
||||
{
|
||||
modifier = uq4_12_multiply(modifier, UQ_4_12(0.5));
|
||||
if (damageCalcData->updateFlags)
|
||||
RecordAbilityBattle(battlerDef, defAbility);
|
||||
if (ctx->updateFlags)
|
||||
RecordAbilityBattle(battlerDef, ctx->abilityDef);
|
||||
}
|
||||
break;
|
||||
case ABILITY_DRY_SKIN:
|
||||
@ -8409,7 +8411,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData *
|
||||
case ABILITY_PROTOSYNTHESIS:
|
||||
{
|
||||
u8 defHighestStat = GetHighestStatId(battlerDef);
|
||||
if (((weather & B_WEATHER_SUN && HasWeatherEffect()) || gDisableStructs[battlerDef].boosterEnergyActivates)
|
||||
if (((ctx->weather & B_WEATHER_SUN && HasWeatherEffect()) || gDisableStructs[battlerDef].boosterEnergyActivates)
|
||||
&& ((IsBattleMovePhysical(move) && defHighestStat == STAT_DEF) || (IsBattleMoveSpecial(move) && defHighestStat == STAT_SPDEF))
|
||||
&& !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED))
|
||||
modifier = uq4_12_multiply(modifier, UQ_4_12(0.7));
|
||||
@ -8433,7 +8435,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData *
|
||||
holdEffectModifier = uq4_12_add(UQ_4_12(1.0), PercentToUQ4_12(holdEffectParamAtk));
|
||||
|
||||
// attacker's hold effect
|
||||
switch (holdEffectAtk)
|
||||
switch (ctx->holdEffectAtk)
|
||||
{
|
||||
case HOLD_EFFECT_MUSCLE_BAND:
|
||||
if (IsBattleMovePhysical(move))
|
||||
@ -8496,16 +8498,16 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData *
|
||||
return uq4_12_multiply_by_int_half_down(modifier, basePower);
|
||||
}
|
||||
|
||||
static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u32 atkAbility, u32 defAbility, enum ItemHoldEffect holdEffectAtk, u32 weather)
|
||||
static inline u32 CalcAttackStat(struct DamageContext *ctx)
|
||||
{
|
||||
u8 atkStage;
|
||||
u32 atkStat;
|
||||
uq4_12_t modifier;
|
||||
u16 atkBaseSpeciesId;
|
||||
u32 battlerAtk = damageCalcData->battlerAtk;
|
||||
u32 battlerDef = damageCalcData->battlerDef;
|
||||
u32 move = damageCalcData->move;
|
||||
u32 moveType = damageCalcData->moveType;
|
||||
u32 battlerAtk = ctx->battlerAtk;
|
||||
u32 battlerDef = ctx->battlerDef;
|
||||
u32 move = ctx->move;
|
||||
u32 moveType = ctx->moveType;
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
|
||||
|
||||
atkBaseSpeciesId = GET_BASE_SPECIES_ID(gBattleMons[battlerAtk].species);
|
||||
@ -8555,10 +8557,10 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u
|
||||
}
|
||||
|
||||
// critical hits ignore attack stat's stage drops
|
||||
if (damageCalcData->isCrit && atkStage < DEFAULT_STAT_STAGE)
|
||||
if (ctx->isCrit && atkStage < DEFAULT_STAT_STAGE)
|
||||
atkStage = DEFAULT_STAT_STAGE;
|
||||
// pokemon with unaware ignore attack stat changes while taking damage
|
||||
if (defAbility == ABILITY_UNAWARE)
|
||||
if (ctx->abilityDef == ABILITY_UNAWARE)
|
||||
atkStage = DEFAULT_STAT_STAGE;
|
||||
|
||||
atkStat *= gStatStageRatios[atkStage][0];
|
||||
@ -8568,7 +8570,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u
|
||||
modifier = UQ_4_12(1.0);
|
||||
|
||||
// attacker's abilities
|
||||
switch (atkAbility)
|
||||
switch (ctx->abilityAtk)
|
||||
{
|
||||
case ABILITY_HUGE_POWER:
|
||||
case ABILITY_PURE_POWER:
|
||||
@ -8666,7 +8668,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u
|
||||
if (!(gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED))
|
||||
{
|
||||
u32 atkHighestStat = GetHighestStatId(battlerAtk);
|
||||
if (((weather & B_WEATHER_SUN) && HasWeatherEffect()) || gDisableStructs[battlerAtk].boosterEnergyActivates)
|
||||
if (((ctx->weather & B_WEATHER_SUN) && HasWeatherEffect()) || gDisableStructs[battlerAtk].boosterEnergyActivates)
|
||||
{
|
||||
if ((IsBattleMovePhysical(move) && atkHighestStat == STAT_ATK) || (IsBattleMoveSpecial(move) && atkHighestStat == STAT_SPATK))
|
||||
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
|
||||
@ -8685,7 +8687,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u
|
||||
}
|
||||
break;
|
||||
case ABILITY_ORICHALCUM_PULSE:
|
||||
if ((weather & B_WEATHER_SUN) && HasWeatherEffect() && IsBattleMovePhysical(move))
|
||||
if ((ctx->weather & B_WEATHER_SUN) && HasWeatherEffect() && IsBattleMovePhysical(move))
|
||||
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3333));
|
||||
break;
|
||||
case ABILITY_HADRON_ENGINE:
|
||||
@ -8695,13 +8697,13 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u
|
||||
}
|
||||
|
||||
// target's abilities
|
||||
switch (defAbility)
|
||||
switch (ctx->abilityDef)
|
||||
{
|
||||
case ABILITY_THICK_FAT:
|
||||
if (moveType == TYPE_FIRE || moveType == TYPE_ICE)
|
||||
{
|
||||
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.5));
|
||||
if (damageCalcData->updateFlags)
|
||||
if (ctx->updateFlags)
|
||||
RecordAbilityBattle(battlerDef, ABILITY_THICK_FAT);
|
||||
}
|
||||
break;
|
||||
@ -8720,14 +8722,14 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u
|
||||
}
|
||||
|
||||
// field abilities
|
||||
if (IsAbilityOnField(ABILITY_VESSEL_OF_RUIN) && atkAbility != ABILITY_VESSEL_OF_RUIN && IsBattleMoveSpecial(move))
|
||||
if (IsAbilityOnField(ABILITY_VESSEL_OF_RUIN) && ctx->abilityAtk != ABILITY_VESSEL_OF_RUIN && IsBattleMoveSpecial(move))
|
||||
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.75));
|
||||
|
||||
if (IsAbilityOnField(ABILITY_TABLETS_OF_RUIN) && atkAbility != ABILITY_TABLETS_OF_RUIN && IsBattleMovePhysical(move))
|
||||
if (IsAbilityOnField(ABILITY_TABLETS_OF_RUIN) && ctx->abilityAtk != ABILITY_TABLETS_OF_RUIN && IsBattleMovePhysical(move))
|
||||
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.75));
|
||||
|
||||
// attacker's hold effect
|
||||
switch (holdEffectAtk)
|
||||
switch (ctx->holdEffectAtk)
|
||||
{
|
||||
case HOLD_EFFECT_THICK_CLUB:
|
||||
if ((atkBaseSpeciesId == SPECIES_CUBONE || atkBaseSpeciesId == SPECIES_MAROWAK) && IsBattleMovePhysical(move))
|
||||
@ -8779,15 +8781,15 @@ static bool32 CanEvolve(u32 species)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline u32 CalcDefenseStat(struct DamageCalculationData *damageCalcData, u32 atkAbility, u32 defAbility, enum ItemHoldEffect holdEffectDef, u32 weather)
|
||||
static inline u32 CalcDefenseStat(struct DamageContext *ctx)
|
||||
{
|
||||
bool32 usesDefStat;
|
||||
u8 defStage;
|
||||
u32 defStat, def, spDef;
|
||||
uq4_12_t modifier;
|
||||
u32 battlerDef = damageCalcData->battlerDef;
|
||||
u32 move = damageCalcData->move;
|
||||
u32 moveType = damageCalcData->moveType;
|
||||
u32 battlerDef = ctx->battlerDef;
|
||||
u32 move = ctx->move;
|
||||
u32 moveType = ctx->moveType;
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
|
||||
|
||||
if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM) // the defense stats are swapped
|
||||
@ -8820,10 +8822,10 @@ static inline u32 CalcDefenseStat(struct DamageCalculationData *damageCalcData,
|
||||
defStat /= 2;
|
||||
|
||||
// critical hits ignore positive stat changes
|
||||
if (damageCalcData->isCrit && defStage > DEFAULT_STAT_STAGE)
|
||||
if (ctx->isCrit && defStage > DEFAULT_STAT_STAGE)
|
||||
defStage = DEFAULT_STAT_STAGE;
|
||||
// pokemon with unaware ignore defense stat changes while dealing damage
|
||||
if (atkAbility == ABILITY_UNAWARE)
|
||||
if (ctx->abilityAtk == ABILITY_UNAWARE)
|
||||
defStage = DEFAULT_STAT_STAGE;
|
||||
// certain moves also ignore stat changes
|
||||
if (MoveIgnoresDefenseEvasionStages(move))
|
||||
@ -8836,13 +8838,13 @@ static inline u32 CalcDefenseStat(struct DamageCalculationData *damageCalcData,
|
||||
modifier = UQ_4_12(1.0);
|
||||
|
||||
// target's abilities
|
||||
switch (defAbility)
|
||||
switch (ctx->abilityDef)
|
||||
{
|
||||
case ABILITY_MARVEL_SCALE:
|
||||
if (gBattleMons[battlerDef].status1 & STATUS1_ANY && usesDefStat)
|
||||
{
|
||||
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5));
|
||||
if (damageCalcData->updateFlags)
|
||||
if (ctx->updateFlags)
|
||||
RecordAbilityBattle(battlerDef, ABILITY_MARVEL_SCALE);
|
||||
}
|
||||
break;
|
||||
@ -8850,7 +8852,7 @@ static inline u32 CalcDefenseStat(struct DamageCalculationData *damageCalcData,
|
||||
if (usesDefStat)
|
||||
{
|
||||
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0));
|
||||
if (damageCalcData->updateFlags)
|
||||
if (ctx->updateFlags)
|
||||
RecordAbilityBattle(battlerDef, ABILITY_FUR_COAT);
|
||||
}
|
||||
break;
|
||||
@ -8858,7 +8860,7 @@ static inline u32 CalcDefenseStat(struct DamageCalculationData *damageCalcData,
|
||||
if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && usesDefStat)
|
||||
{
|
||||
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5));
|
||||
if (damageCalcData->updateFlags)
|
||||
if (ctx->updateFlags)
|
||||
RecordAbilityBattle(battlerDef, ABILITY_GRASS_PELT);
|
||||
}
|
||||
break;
|
||||
@ -8885,14 +8887,14 @@ static inline u32 CalcDefenseStat(struct DamageCalculationData *damageCalcData,
|
||||
}
|
||||
|
||||
// field abilities
|
||||
if (IsAbilityOnField(ABILITY_SWORD_OF_RUIN) && defAbility != ABILITY_SWORD_OF_RUIN && usesDefStat)
|
||||
if (IsAbilityOnField(ABILITY_SWORD_OF_RUIN) && ctx->abilityDef != ABILITY_SWORD_OF_RUIN && usesDefStat)
|
||||
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.75));
|
||||
|
||||
if (IsAbilityOnField(ABILITY_BEADS_OF_RUIN) && defAbility != ABILITY_BEADS_OF_RUIN && !usesDefStat)
|
||||
if (IsAbilityOnField(ABILITY_BEADS_OF_RUIN) && ctx->abilityDef != ABILITY_BEADS_OF_RUIN && !usesDefStat)
|
||||
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.75));
|
||||
|
||||
// target's hold effects
|
||||
switch (holdEffectDef)
|
||||
switch (ctx->holdEffectDef)
|
||||
{
|
||||
case HOLD_EFFECT_DEEP_SEA_SCALE:
|
||||
if (gBattleMons[battlerDef].species == SPECIES_CLAMPERL && !usesDefStat)
|
||||
@ -8943,9 +8945,9 @@ static inline s32 CalculateBaseDamage(u32 power, u32 userFinalAttack, u32 level,
|
||||
return power * userFinalAttack * (2 * level / 5 + 2) / targetFinalDefense / 50 + 2;
|
||||
}
|
||||
|
||||
static inline uq4_12_t GetTargetDamageModifier(struct DamageCalculationData *damageCalcData)
|
||||
static inline uq4_12_t GetTargetDamageModifier(struct DamageContext *ctx)
|
||||
{
|
||||
if (IsDoubleBattle() && GetMoveTargetCount(damageCalcData) >= 2)
|
||||
if (IsDoubleBattle() && GetMoveTargetCount(ctx) >= 2)
|
||||
return B_MULTIPLE_TARGETS_DMG >= GEN_4 ? UQ_4_12(0.75) : UQ_4_12(0.5);
|
||||
return UQ_4_12(1.0);
|
||||
}
|
||||
@ -8957,62 +8959,53 @@ static inline uq4_12_t GetParentalBondModifier(u32 battlerAtk)
|
||||
return B_PARENTAL_BOND_DMG >= GEN_7 ? UQ_4_12(0.25) : UQ_4_12(0.5);
|
||||
}
|
||||
|
||||
static inline uq4_12_t GetSameTypeAttackBonusModifier(struct DamageCalculationData *damageCalcData, u32 abilityAtk)
|
||||
static inline uq4_12_t GetSameTypeAttackBonusModifier(struct DamageContext *ctx)
|
||||
{
|
||||
u32 battlerAtk = damageCalcData->battlerAtk;
|
||||
u32 move = damageCalcData->move;
|
||||
u32 moveType = damageCalcData->moveType;
|
||||
|
||||
if (moveType == TYPE_MYSTERY)
|
||||
if (ctx->moveType == TYPE_MYSTERY)
|
||||
return UQ_4_12(1.0);
|
||||
else if (gBattleStruct->pledgeMove && IS_BATTLER_OF_TYPE(BATTLE_PARTNER(battlerAtk), moveType))
|
||||
return (abilityAtk == ABILITY_ADAPTABILITY) ? UQ_4_12(2.0) : UQ_4_12(1.5);
|
||||
else if (!IS_BATTLER_OF_TYPE(battlerAtk, moveType) || move == MOVE_STRUGGLE || move == MOVE_NONE)
|
||||
else if (gBattleStruct->pledgeMove && IS_BATTLER_OF_TYPE(BATTLE_PARTNER(ctx->battlerAtk), ctx->moveType))
|
||||
return (ctx->abilityAtk == ABILITY_ADAPTABILITY) ? UQ_4_12(2.0) : UQ_4_12(1.5);
|
||||
else if (!IS_BATTLER_OF_TYPE(ctx->battlerAtk, ctx->moveType) || ctx->move == MOVE_STRUGGLE || ctx->move == MOVE_NONE)
|
||||
return UQ_4_12(1.0);
|
||||
return (abilityAtk == ABILITY_ADAPTABILITY) ? UQ_4_12(2.0) : UQ_4_12(1.5);
|
||||
return (ctx->abilityAtk == ABILITY_ADAPTABILITY) ? UQ_4_12(2.0) : UQ_4_12(1.5);
|
||||
}
|
||||
|
||||
// Utility Umbrella holders take normal damage from what would be rain- and sun-weakened attacks.
|
||||
static uq4_12_t GetWeatherDamageModifier(struct DamageCalculationData *damageCalcData, enum ItemHoldEffect holdEffectAtk, enum ItemHoldEffect holdEffectDef, u32 weather)
|
||||
static uq4_12_t GetWeatherDamageModifier(struct DamageContext *ctx)
|
||||
{
|
||||
u32 move = damageCalcData->move;
|
||||
u32 moveType = damageCalcData->moveType;
|
||||
|
||||
if (weather == B_WEATHER_NONE)
|
||||
if (ctx->weather == B_WEATHER_NONE)
|
||||
return UQ_4_12(1.0);
|
||||
if (GetMoveEffect(move) == EFFECT_HYDRO_STEAM && (weather & B_WEATHER_SUN) && holdEffectAtk != HOLD_EFFECT_UTILITY_UMBRELLA)
|
||||
if (GetMoveEffect(ctx->move) == EFFECT_HYDRO_STEAM && (ctx->weather & B_WEATHER_SUN) && ctx->holdEffectAtk != HOLD_EFFECT_UTILITY_UMBRELLA)
|
||||
return UQ_4_12(1.5);
|
||||
if (holdEffectDef == HOLD_EFFECT_UTILITY_UMBRELLA)
|
||||
if (ctx->holdEffectDef == HOLD_EFFECT_UTILITY_UMBRELLA)
|
||||
return UQ_4_12(1.0);
|
||||
|
||||
if (weather & B_WEATHER_RAIN)
|
||||
if (ctx->weather & B_WEATHER_RAIN)
|
||||
{
|
||||
if (moveType != TYPE_FIRE && moveType != TYPE_WATER)
|
||||
if (ctx->moveType != TYPE_FIRE && ctx->moveType != TYPE_WATER)
|
||||
return UQ_4_12(1.0);
|
||||
return (moveType == TYPE_FIRE) ? UQ_4_12(0.5) : UQ_4_12(1.5);
|
||||
return (ctx->moveType == TYPE_FIRE) ? UQ_4_12(0.5) : UQ_4_12(1.5);
|
||||
}
|
||||
if (weather & B_WEATHER_SUN)
|
||||
if (ctx->weather & B_WEATHER_SUN)
|
||||
{
|
||||
if (moveType != TYPE_FIRE && moveType != TYPE_WATER)
|
||||
if (ctx->moveType != TYPE_FIRE && ctx->moveType != TYPE_WATER)
|
||||
return UQ_4_12(1.0);
|
||||
return (moveType == TYPE_WATER) ? UQ_4_12(0.5) : UQ_4_12(1.5);
|
||||
return (ctx->moveType == TYPE_WATER) ? UQ_4_12(0.5) : UQ_4_12(1.5);
|
||||
}
|
||||
return UQ_4_12(1.0);
|
||||
}
|
||||
|
||||
static inline uq4_12_t GetBurnOrFrostBiteModifier(struct DamageCalculationData *damageCalcData, u32 abilityAtk)
|
||||
static inline uq4_12_t GetBurnOrFrostBiteModifier(struct DamageContext *ctx)
|
||||
{
|
||||
u32 battlerAtk = damageCalcData->battlerAtk;
|
||||
u32 move = damageCalcData->move;
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(ctx->move);
|
||||
|
||||
if (gBattleMons[battlerAtk].status1 & STATUS1_BURN
|
||||
&& IsBattleMovePhysical(move)
|
||||
if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_BURN
|
||||
&& IsBattleMovePhysical(ctx->move)
|
||||
&& (B_BURN_FACADE_DMG < GEN_6 || moveEffect != EFFECT_FACADE)
|
||||
&& abilityAtk != ABILITY_GUTS)
|
||||
&& ctx->abilityAtk != ABILITY_GUTS)
|
||||
return UQ_4_12(0.5);
|
||||
if (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE
|
||||
&& IsBattleMoveSpecial(move)
|
||||
if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_FROSTBITE
|
||||
&& IsBattleMoveSpecial(ctx->move)
|
||||
&& (B_BURN_FACADE_DMG < GEN_6 || moveEffect != EFFECT_FACADE))
|
||||
return UQ_4_12(0.5);
|
||||
return UQ_4_12(1.0);
|
||||
@ -9032,12 +9025,12 @@ static inline uq4_12_t GetGlaiveRushModifier(u32 battlerDef)
|
||||
return UQ_4_12(1.0);
|
||||
}
|
||||
|
||||
static inline uq4_12_t GetZMaxMoveAgainstProtectionModifier(struct DamageCalculationData *damageCalcData)
|
||||
static inline uq4_12_t GetZMaxMoveAgainstProtectionModifier(struct DamageContext *ctx)
|
||||
{
|
||||
if (!IsZMove(damageCalcData->move) && !IsMaxMove(damageCalcData->move))
|
||||
if (!IsZMove(ctx->move) && !IsMaxMove(ctx->move))
|
||||
return UQ_4_12(1.0);
|
||||
|
||||
u32 protected = gProtectStructs[damageCalcData->battlerDef].protected;
|
||||
u32 protected = gProtectStructs[ctx->battlerDef].protected;
|
||||
if (GetProtectType(protected) == PROTECT_TYPE_SINGLE && protected != PROTECT_MAX_GUARD)
|
||||
return UQ_4_12(0.25);
|
||||
return UQ_4_12(1.0);
|
||||
@ -9071,14 +9064,14 @@ static inline uq4_12_t GetAirborneModifier(u32 move, u32 battlerDef)
|
||||
return UQ_4_12(1.0);
|
||||
}
|
||||
|
||||
static inline uq4_12_t GetScreensModifier(u32 move, u32 battlerAtk, u32 battlerDef, bool32 isCrit, u32 abilityAtk)
|
||||
static inline uq4_12_t GetScreensModifier(struct DamageContext *ctx)
|
||||
{
|
||||
u32 sideStatus = gSideStatuses[GetBattlerSide(battlerDef)];
|
||||
bool32 lightScreen = (sideStatus & SIDE_STATUS_LIGHTSCREEN) && IsBattleMoveSpecial(move);
|
||||
bool32 reflect = (sideStatus & SIDE_STATUS_REFLECT) && IsBattleMovePhysical(move);
|
||||
u32 sideStatus = gSideStatuses[GetBattlerSide(ctx->battlerDef)];
|
||||
bool32 lightScreen = (sideStatus & SIDE_STATUS_LIGHTSCREEN) && IsBattleMoveSpecial(ctx->move);
|
||||
bool32 reflect = (sideStatus & SIDE_STATUS_REFLECT) && IsBattleMovePhysical(ctx->move);
|
||||
bool32 auroraVeil = sideStatus & SIDE_STATUS_AURORA_VEIL;
|
||||
|
||||
if (isCrit || abilityAtk == ABILITY_INFILTRATOR || gProtectStructs[battlerAtk].confusionSelfDmg)
|
||||
if (ctx->isCrit || ctx->abilityAtk == ABILITY_INFILTRATOR || gProtectStructs[ctx->battlerAtk].confusionSelfDmg)
|
||||
return UQ_4_12(1.0);
|
||||
if (reflect || lightScreen || auroraVeil)
|
||||
return (IsDoubleBattle()) ? UQ_4_12(0.667) : UQ_4_12(0.5);
|
||||
@ -9112,33 +9105,33 @@ static inline uq4_12_t GetAttackerAbilitiesModifier(u32 battlerAtk, uq4_12_t typ
|
||||
return UQ_4_12(1.0);
|
||||
}
|
||||
|
||||
static inline uq4_12_t GetDefenderAbilitiesModifier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, uq4_12_t typeEffectivenessModifier, u32 abilityDef)
|
||||
static inline uq4_12_t GetDefenderAbilitiesModifier(struct DamageContext *ctx)
|
||||
{
|
||||
switch (abilityDef)
|
||||
switch (ctx->abilityDef)
|
||||
{
|
||||
case ABILITY_MULTISCALE:
|
||||
case ABILITY_SHADOW_SHIELD:
|
||||
if (IsBattlerAtMaxHp(battlerDef))
|
||||
if (IsBattlerAtMaxHp(ctx->battlerDef))
|
||||
return UQ_4_12(0.5);
|
||||
break;
|
||||
case ABILITY_FILTER:
|
||||
case ABILITY_SOLID_ROCK:
|
||||
case ABILITY_PRISM_ARMOR:
|
||||
if (typeEffectivenessModifier >= UQ_4_12(2.0))
|
||||
if (ctx->typeEffectivenessModifier >= UQ_4_12(2.0))
|
||||
return UQ_4_12(0.75);
|
||||
break;
|
||||
case ABILITY_FLUFFY:
|
||||
if (!IsMoveMakingContact(move, battlerAtk) && moveType == TYPE_FIRE)
|
||||
if (!IsMoveMakingContact(ctx->move, ctx->battlerAtk) && ctx->moveType == TYPE_FIRE)
|
||||
return UQ_4_12(2.0);
|
||||
if (IsMoveMakingContact(move, battlerAtk) && moveType != TYPE_FIRE)
|
||||
if (IsMoveMakingContact(ctx->move, ctx->battlerAtk) && ctx->moveType != TYPE_FIRE)
|
||||
return UQ_4_12(0.5);
|
||||
break;
|
||||
case ABILITY_PUNK_ROCK:
|
||||
if (IsSoundMove(move))
|
||||
if (IsSoundMove(ctx->move))
|
||||
return UQ_4_12(0.5);
|
||||
break;
|
||||
case ABILITY_ICE_SCALES:
|
||||
if (IsBattleMoveSpecial(move))
|
||||
if (IsBattleMoveSpecial(ctx->move))
|
||||
return UQ_4_12(0.5);
|
||||
break;
|
||||
}
|
||||
@ -9185,24 +9178,18 @@ static inline uq4_12_t GetAttackerItemsModifier(u32 battlerAtk, uq4_12_t typeEff
|
||||
return UQ_4_12(1.0);
|
||||
}
|
||||
|
||||
static inline uq4_12_t GetDefenderItemsModifier(struct DamageCalculationData *damageCalcData, uq4_12_t typeEffectivenessModifier, u32 abilityDef, enum ItemHoldEffect holdEffectDef)
|
||||
static inline uq4_12_t GetDefenderItemsModifier(struct DamageContext *ctx)
|
||||
{
|
||||
u32 battlerDef = damageCalcData->battlerDef;
|
||||
u32 moveType = damageCalcData->moveType;
|
||||
|
||||
u32 holdEffectDefParam = GetBattlerHoldEffectParam(battlerDef);
|
||||
u32 itemDef = gBattleMons[battlerDef].item;
|
||||
|
||||
switch (holdEffectDef)
|
||||
switch (ctx->holdEffectDef)
|
||||
{
|
||||
case HOLD_EFFECT_RESIST_BERRY:
|
||||
if (UnnerveOn(battlerDef, itemDef))
|
||||
if (UnnerveOn(ctx->battlerDef, gBattleMons[ctx->battlerDef].item))
|
||||
return UQ_4_12(1.0);
|
||||
if (moveType == holdEffectDefParam && (moveType == TYPE_NORMAL || typeEffectivenessModifier >= UQ_4_12(2.0)))
|
||||
if (ctx->moveType == GetBattlerHoldEffectParam(ctx->battlerDef) && (ctx->moveType == TYPE_NORMAL || ctx->typeEffectivenessModifier >= UQ_4_12(2.0)))
|
||||
{
|
||||
if (damageCalcData->updateFlags)
|
||||
gSpecialStatuses[battlerDef].berryReduced = TRUE;
|
||||
return (abilityDef == ABILITY_RIPEN) ? UQ_4_12(0.25) : UQ_4_12(0.5);
|
||||
if (ctx->updateFlags)
|
||||
gSpecialStatuses[ctx->battlerDef].berryReduced = TRUE;
|
||||
return (ctx->abilityDef == ABILITY_RIPEN) ? UQ_4_12(0.25) : UQ_4_12(0.5);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -9221,42 +9208,36 @@ static inline uq4_12_t GetDefenderItemsModifier(struct DamageCalculationData *da
|
||||
// https://bulbapedia.bulbagarden.net/wiki/Damage#Generation_V_onward
|
||||
// Please Note: Fixed Point Multiplication is not associative.
|
||||
// The order of operations is relevant.
|
||||
static inline uq4_12_t GetOtherModifiers(struct DamageCalculationData *damageCalcData, uq4_12_t typeEffectivenessModifier,
|
||||
u32 abilityAtk, u32 abilityDef, enum ItemHoldEffect holdEffectAtk, enum ItemHoldEffect holdEffectDef)
|
||||
static inline uq4_12_t GetOtherModifiers(struct DamageContext *ctx)
|
||||
{
|
||||
u32 battlerAtk = damageCalcData->battlerAtk;
|
||||
u32 battlerDef = damageCalcData->battlerDef;
|
||||
u32 move = damageCalcData->move;
|
||||
u32 moveType = damageCalcData->moveType;
|
||||
u32 isCrit = damageCalcData->isCrit;
|
||||
|
||||
uq4_12_t finalModifier = UQ_4_12(1.0);
|
||||
u32 battlerDefPartner = BATTLE_PARTNER(battlerDef);
|
||||
u32 unmodifiedAttackerSpeed = gBattleMons[battlerAtk].speed;
|
||||
u32 unmodifiedDefenderSpeed = gBattleMons[battlerDef].speed;
|
||||
u32 battlerDefPartner = BATTLE_PARTNER(ctx->battlerDef);
|
||||
u32 unmodifiedAttackerSpeed = gBattleMons[ctx->battlerAtk].speed;
|
||||
u32 unmodifiedDefenderSpeed = gBattleMons[ctx->battlerDef].speed;
|
||||
|
||||
//TODO: Behemoth Blade, Behemoth Bash, Dynamax Cannon (Dynamax)
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetMinimizeModifier(move, battlerDef));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetUndergroundModifier(move, battlerDef));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetDiveModifier(move, battlerDef));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetAirborneModifier(move, battlerDef));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetScreensModifier(move, battlerAtk, battlerDef, isCrit, abilityAtk));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetCollisionCourseElectroDriftModifier(move, typeEffectivenessModifier));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetMinimizeModifier(ctx->move, ctx->battlerDef));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetUndergroundModifier(ctx->move, ctx->battlerDef));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetDiveModifier(ctx->move, ctx->battlerDef));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetAirborneModifier(ctx->move, ctx->battlerDef));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetScreensModifier(ctx));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetCollisionCourseElectroDriftModifier(ctx->move, ctx->typeEffectivenessModifier));
|
||||
|
||||
if (unmodifiedAttackerSpeed >= unmodifiedDefenderSpeed)
|
||||
{
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetAttackerAbilitiesModifier(battlerAtk, typeEffectivenessModifier, isCrit, abilityAtk));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetDefenderAbilitiesModifier(move, moveType, battlerAtk, battlerDef, typeEffectivenessModifier, abilityDef));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetAttackerAbilitiesModifier(ctx->battlerAtk, ctx->typeEffectivenessModifier, ctx->isCrit, ctx->abilityAtk));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetDefenderAbilitiesModifier(ctx));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetDefenderPartnerAbilitiesModifier(battlerDefPartner));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetAttackerItemsModifier(battlerAtk, typeEffectivenessModifier, holdEffectAtk));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetDefenderItemsModifier(damageCalcData, typeEffectivenessModifier, abilityDef, holdEffectDef));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetAttackerItemsModifier(ctx->battlerAtk, ctx->typeEffectivenessModifier, ctx->holdEffectAtk));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetDefenderItemsModifier(ctx));
|
||||
}
|
||||
else
|
||||
{
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetDefenderAbilitiesModifier(move, moveType, battlerAtk, battlerDef, typeEffectivenessModifier, abilityDef));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetDefenderAbilitiesModifier(ctx));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetDefenderPartnerAbilitiesModifier(battlerDefPartner));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetAttackerAbilitiesModifier(battlerAtk, typeEffectivenessModifier, isCrit, abilityAtk));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetDefenderItemsModifier(damageCalcData, typeEffectivenessModifier, abilityDef, holdEffectDef));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetAttackerItemsModifier(battlerAtk, typeEffectivenessModifier, holdEffectAtk));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetAttackerAbilitiesModifier(ctx->battlerAtk, ctx->typeEffectivenessModifier, ctx->isCrit, ctx->abilityAtk));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetDefenderItemsModifier(ctx));
|
||||
DAMAGE_MULTIPLY_MODIFIER(GetAttackerItemsModifier(ctx->battlerAtk, ctx->typeEffectivenessModifier, ctx->holdEffectAtk));
|
||||
}
|
||||
return finalModifier;
|
||||
}
|
||||
@ -9267,31 +9248,28 @@ static inline uq4_12_t GetOtherModifiers(struct DamageCalculationData *damageCal
|
||||
dmg = uq4_12_multiply_by_int_half_down(modifier, dmg); \
|
||||
} while (0)
|
||||
|
||||
static inline s32 DoMoveDamageCalcVars(struct DamageCalculationData *damageCalcData, u32 fixedBasePower, uq4_12_t typeEffectivenessModifier, u32 weather,
|
||||
enum ItemHoldEffect holdEffectAtk, enum ItemHoldEffect holdEffectDef, u32 abilityAtk, u32 abilityDef)
|
||||
static inline s32 DoMoveDamageCalcVars(struct DamageContext *ctx)
|
||||
{
|
||||
s32 dmg;
|
||||
u32 userFinalAttack;
|
||||
u32 targetFinalDefense;
|
||||
u32 battlerAtk = damageCalcData->battlerAtk;
|
||||
u32 battlerDef = damageCalcData->battlerDef;
|
||||
|
||||
if (fixedBasePower)
|
||||
gBattleMovePower = fixedBasePower;
|
||||
if (ctx->fixedBasePower)
|
||||
gBattleMovePower = ctx->fixedBasePower;
|
||||
else
|
||||
gBattleMovePower = CalcMoveBasePowerAfterModifiers(damageCalcData, abilityAtk, abilityDef, holdEffectAtk, weather);
|
||||
gBattleMovePower = CalcMoveBasePowerAfterModifiers(ctx);
|
||||
|
||||
userFinalAttack = CalcAttackStat(damageCalcData, abilityAtk, abilityDef, holdEffectAtk, weather);
|
||||
targetFinalDefense = CalcDefenseStat(damageCalcData, abilityAtk, abilityDef, holdEffectDef, weather);
|
||||
userFinalAttack = CalcAttackStat(ctx);
|
||||
targetFinalDefense = CalcDefenseStat(ctx);
|
||||
|
||||
dmg = CalculateBaseDamage(gBattleMovePower, userFinalAttack, gBattleMons[battlerAtk].level, targetFinalDefense);
|
||||
DAMAGE_APPLY_MODIFIER(GetTargetDamageModifier(damageCalcData));
|
||||
DAMAGE_APPLY_MODIFIER(GetParentalBondModifier(battlerAtk));
|
||||
DAMAGE_APPLY_MODIFIER(GetWeatherDamageModifier(damageCalcData, holdEffectAtk, holdEffectDef, weather));
|
||||
DAMAGE_APPLY_MODIFIER(GetCriticalModifier(damageCalcData->isCrit));
|
||||
DAMAGE_APPLY_MODIFIER(GetGlaiveRushModifier(battlerDef));
|
||||
dmg = CalculateBaseDamage(gBattleMovePower, userFinalAttack, gBattleMons[ctx->battlerAtk].level, targetFinalDefense);
|
||||
DAMAGE_APPLY_MODIFIER(GetTargetDamageModifier(ctx));
|
||||
DAMAGE_APPLY_MODIFIER(GetParentalBondModifier(ctx->battlerAtk));
|
||||
DAMAGE_APPLY_MODIFIER(GetWeatherDamageModifier(ctx));
|
||||
DAMAGE_APPLY_MODIFIER(GetCriticalModifier(ctx->isCrit));
|
||||
DAMAGE_APPLY_MODIFIER(GetGlaiveRushModifier(ctx->battlerDef));
|
||||
|
||||
if (damageCalcData->randomFactor)
|
||||
if (ctx->randomFactor)
|
||||
{
|
||||
dmg *= DMG_ROLL_PERCENT_HI - RandomUniform(RNG_DAMAGE_MODIFIER, 0, DMG_ROLL_PERCENT_HI - DMG_ROLL_PERCENT_LO);
|
||||
dmg /= 100;
|
||||
@ -9303,55 +9281,55 @@ static inline s32 DoMoveDamageCalcVars(struct DamageCalculationData *damageCalcD
|
||||
return dmg;
|
||||
}
|
||||
|
||||
dmg = ApplyModifiersAfterDmgRoll(dmg, damageCalcData, typeEffectivenessModifier, abilityAtk, abilityDef, holdEffectAtk, holdEffectDef);
|
||||
dmg = ApplyModifiersAfterDmgRoll(ctx, dmg);
|
||||
|
||||
if (dmg == 0)
|
||||
dmg = 1;
|
||||
return dmg;
|
||||
}
|
||||
|
||||
s32 ApplyModifiersAfterDmgRoll(s32 dmg, struct DamageCalculationData *damageCalcData, uq4_12_t typeEffectivenessModifier, u32 abilityAtk, u32 abilityDef, enum ItemHoldEffect holdEffectAtk, enum ItemHoldEffect holdEffectDef)
|
||||
s32 ApplyModifiersAfterDmgRoll(struct DamageContext *ctx, s32 dmg)
|
||||
{
|
||||
if (GetActiveGimmick(damageCalcData->battlerAtk) == GIMMICK_TERA)
|
||||
DAMAGE_APPLY_MODIFIER(GetTeraMultiplier(damageCalcData->battlerAtk, damageCalcData->moveType));
|
||||
if (GetActiveGimmick(ctx->battlerAtk) == GIMMICK_TERA)
|
||||
DAMAGE_APPLY_MODIFIER(GetTeraMultiplier(ctx->battlerAtk, ctx->moveType));
|
||||
else
|
||||
DAMAGE_APPLY_MODIFIER(GetSameTypeAttackBonusModifier(damageCalcData, abilityAtk));
|
||||
DAMAGE_APPLY_MODIFIER(typeEffectivenessModifier);
|
||||
DAMAGE_APPLY_MODIFIER(GetBurnOrFrostBiteModifier(damageCalcData, abilityAtk));
|
||||
DAMAGE_APPLY_MODIFIER(GetZMaxMoveAgainstProtectionModifier(damageCalcData));
|
||||
DAMAGE_APPLY_MODIFIER(GetOtherModifiers(damageCalcData, typeEffectivenessModifier, abilityAtk, abilityDef, holdEffectAtk, holdEffectDef));
|
||||
DAMAGE_APPLY_MODIFIER(GetSameTypeAttackBonusModifier(ctx));
|
||||
DAMAGE_APPLY_MODIFIER(ctx->typeEffectivenessModifier);
|
||||
DAMAGE_APPLY_MODIFIER(GetBurnOrFrostBiteModifier(ctx));
|
||||
DAMAGE_APPLY_MODIFIER(GetZMaxMoveAgainstProtectionModifier(ctx));
|
||||
DAMAGE_APPLY_MODIFIER(GetOtherModifiers(ctx));
|
||||
|
||||
return dmg;
|
||||
}
|
||||
|
||||
static inline s32 DoFixedDamageMoveCalc(struct DamageCalculationData *damageCalcData)
|
||||
static inline s32 DoFixedDamageMoveCalc(struct DamageContext *ctx)
|
||||
{
|
||||
s32 dmg = 0;
|
||||
s32 randDamage;
|
||||
|
||||
switch (GetMoveEffect(damageCalcData->move))
|
||||
switch (GetMoveEffect(ctx->move))
|
||||
{
|
||||
case EFFECT_LEVEL_DAMAGE:
|
||||
dmg = gBattleMons[damageCalcData->battlerAtk].level;
|
||||
dmg = gBattleMons[ctx->battlerAtk].level;
|
||||
break;
|
||||
case EFFECT_PSYWAVE:
|
||||
randDamage = B_PSYWAVE_DMG >= GEN_6 ? (Random() % 101) : ((Random() % 11) * 10);
|
||||
dmg = gBattleMons[damageCalcData->battlerAtk].level * (randDamage + 50) / 100;
|
||||
dmg = gBattleMons[ctx->battlerAtk].level * (randDamage + 50) / 100;
|
||||
break;
|
||||
case EFFECT_FIXED_HP_DAMAGE:
|
||||
dmg = GetMoveFixedHPDamage(damageCalcData->move);
|
||||
dmg = GetMoveFixedHPDamage(ctx->move);
|
||||
break;
|
||||
case EFFECT_FIXED_PERCENT_DAMAGE:
|
||||
dmg = GetNonDynamaxHP(damageCalcData->battlerDef) * GetMoveDamagePercentage(damageCalcData->move) / 100;
|
||||
dmg = GetNonDynamaxHP(ctx->battlerDef) * GetMoveDamagePercentage(ctx->move) / 100;
|
||||
break;
|
||||
case EFFECT_FINAL_GAMBIT:
|
||||
dmg = GetNonDynamaxHP(damageCalcData->battlerAtk);
|
||||
dmg = GetNonDynamaxHP(ctx->battlerAtk);
|
||||
break;
|
||||
default:
|
||||
return INT32_MAX;
|
||||
}
|
||||
|
||||
gBattleStruct->moveResultFlags[damageCalcData->battlerDef] &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE);
|
||||
gBattleStruct->moveResultFlags[ctx->battlerDef] &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE);
|
||||
|
||||
if (dmg == 0)
|
||||
dmg = 1;
|
||||
@ -9359,36 +9337,32 @@ static inline s32 DoFixedDamageMoveCalc(struct DamageCalculationData *damageCalc
|
||||
return dmg;
|
||||
}
|
||||
|
||||
static inline s32 DoMoveDamageCalc(struct DamageCalculationData *damageCalcData, u32 fixedBasePower, uq4_12_t typeEffectivenessModifier, u32 weather)
|
||||
static inline s32 DoMoveDamageCalc(struct DamageContext *ctx)
|
||||
{
|
||||
enum ItemHoldEffect holdEffectAtk, holdEffectDef;
|
||||
u32 abilityAtk, abilityDef;
|
||||
|
||||
if (typeEffectivenessModifier == UQ_4_12(0.0))
|
||||
if (ctx->typeEffectivenessModifier == UQ_4_12(0.0))
|
||||
return 0;
|
||||
|
||||
s32 dmg = DoFixedDamageMoveCalc(damageCalcData);
|
||||
s32 dmg = DoFixedDamageMoveCalc(ctx);
|
||||
if (dmg != INT32_MAX)
|
||||
return dmg;
|
||||
|
||||
holdEffectAtk = GetBattlerHoldEffect(damageCalcData->battlerAtk, TRUE);
|
||||
holdEffectDef = GetBattlerHoldEffect(damageCalcData->battlerDef, TRUE);
|
||||
abilityAtk = GetBattlerAbility(damageCalcData->battlerAtk);
|
||||
abilityDef = GetBattlerAbility(damageCalcData->battlerDef);
|
||||
ctx->holdEffectAtk = GetBattlerHoldEffect(ctx->battlerAtk, TRUE);
|
||||
ctx->holdEffectDef = GetBattlerHoldEffect(ctx->battlerDef, TRUE);
|
||||
ctx->abilityAtk = GetBattlerAbility(ctx->battlerAtk);
|
||||
ctx->abilityDef = GetBattlerAbility(ctx->battlerDef);
|
||||
|
||||
return DoMoveDamageCalcVars(damageCalcData, fixedBasePower, typeEffectivenessModifier, weather, holdEffectAtk, holdEffectDef, abilityAtk, abilityDef);
|
||||
return DoMoveDamageCalcVars(ctx);
|
||||
}
|
||||
|
||||
static inline s32 DoFutureSightAttackDamageCalcVars(struct DamageCalculationData *damageCalcData, uq4_12_t typeEffectivenessModifier,
|
||||
u32 weather, enum ItemHoldEffect holdEffectDef, u32 abilityDef)
|
||||
static inline s32 DoFutureSightAttackDamageCalcVars(struct DamageContext *ctx)
|
||||
{
|
||||
s32 dmg;
|
||||
u32 userFinalAttack;
|
||||
u32 targetFinalDefense;
|
||||
u32 battlerAtk = damageCalcData->battlerAtk;
|
||||
u32 battlerDef = damageCalcData->battlerDef;
|
||||
u32 move = damageCalcData->move;
|
||||
u32 moveType = damageCalcData->moveType;
|
||||
u32 battlerAtk = ctx->battlerAtk;
|
||||
u32 battlerDef = ctx->battlerDef;
|
||||
u32 move = ctx->move;
|
||||
u32 moveType = ctx->moveType;
|
||||
|
||||
struct Pokemon *party = GetBattlerParty(battlerAtk);
|
||||
struct Pokemon *partyMon = &party[gWishFutureKnock.futureSightPartyIndex[battlerDef]];
|
||||
@ -9401,12 +9375,12 @@ static inline s32 DoFutureSightAttackDamageCalcVars(struct DamageCalculationData
|
||||
else
|
||||
userFinalAttack = GetMonData(partyMon, MON_DATA_SPATK, NULL);
|
||||
|
||||
targetFinalDefense = CalcDefenseStat(damageCalcData, ABILITY_NONE, abilityDef, holdEffectDef, weather);
|
||||
targetFinalDefense = CalcDefenseStat(ctx);
|
||||
dmg = CalculateBaseDamage(gBattleMovePower, userFinalAttack, partyMonLevel, targetFinalDefense);
|
||||
|
||||
DAMAGE_APPLY_MODIFIER(GetCriticalModifier(damageCalcData->isCrit));
|
||||
DAMAGE_APPLY_MODIFIER(GetCriticalModifier(ctx->isCrit));
|
||||
|
||||
if (damageCalcData->randomFactor)
|
||||
if (ctx->randomFactor)
|
||||
{
|
||||
dmg *= DMG_ROLL_PERCENT_HI - RandomUniform(RNG_DAMAGE_MODIFIER, 0, DMG_ROLL_PERCENT_HI - DMG_ROLL_PERCENT_LO);
|
||||
dmg /= 100;
|
||||
@ -9417,7 +9391,7 @@ static inline s32 DoFutureSightAttackDamageCalcVars(struct DamageCalculationData
|
||||
DAMAGE_APPLY_MODIFIER(UQ_4_12(1.5));
|
||||
else
|
||||
DAMAGE_APPLY_MODIFIER(UQ_4_12(1.0));
|
||||
DAMAGE_APPLY_MODIFIER(typeEffectivenessModifier);
|
||||
DAMAGE_APPLY_MODIFIER(ctx->typeEffectivenessModifier);
|
||||
|
||||
if (dmg == 0)
|
||||
dmg = 1;
|
||||
@ -9425,18 +9399,12 @@ static inline s32 DoFutureSightAttackDamageCalcVars(struct DamageCalculationData
|
||||
return dmg;
|
||||
}
|
||||
|
||||
static inline s32 DoFutureSightAttackDamageCalc(struct DamageCalculationData *damageCalcData, uq4_12_t typeEffectivenessModifier, u32 weather)
|
||||
static inline s32 DoFutureSightAttackDamageCalc(struct DamageContext *ctx)
|
||||
{
|
||||
enum ItemHoldEffect holdEffectDef;
|
||||
u32 abilityDef;
|
||||
|
||||
if (typeEffectivenessModifier == UQ_4_12(0.0))
|
||||
if (ctx->typeEffectivenessModifier == UQ_4_12(0.0))
|
||||
return 0;
|
||||
|
||||
holdEffectDef = GetBattlerHoldEffect(damageCalcData->battlerDef, TRUE);
|
||||
abilityDef = GetBattlerAbility(damageCalcData->battlerDef);
|
||||
|
||||
return DoFutureSightAttackDamageCalcVars(damageCalcData, typeEffectivenessModifier, weather, holdEffectDef, abilityDef);
|
||||
return DoFutureSightAttackDamageCalcVars(ctx);
|
||||
}
|
||||
|
||||
#undef DAMAGE_APPLY_MODIFIER
|
||||
@ -9459,31 +9427,36 @@ bool32 IsFutureSightAttackerInParty(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
&& &party[gWishFutureKnock.futureSightPartyIndex[battlerDef]] != &party[BATTLE_PARTNER(gBattlerPartyIndexes[battlerAtk])];
|
||||
}
|
||||
|
||||
s32 CalculateMoveDamage(struct DamageCalculationData *damageCalcData, u32 fixedBasePower)
|
||||
s32 CalculateMoveDamage(struct DamageContext *ctx)
|
||||
{
|
||||
u32 typeEffectivenessMultiplier = CalcTypeEffectivenessMultiplier(damageCalcData->move,
|
||||
damageCalcData->moveType,
|
||||
damageCalcData->battlerAtk,
|
||||
damageCalcData->battlerDef,
|
||||
GetBattlerAbility(damageCalcData->battlerDef),
|
||||
damageCalcData->updateFlags);
|
||||
ctx->weather = GetWeather();
|
||||
ctx->abilityAtk = GetBattlerAbility(ctx->battlerAtk);
|
||||
ctx->abilityDef = GetBattlerAbility(ctx->battlerDef);
|
||||
ctx->holdEffectAtk = GetItemHoldEffect(ctx->battlerAtk);
|
||||
ctx->holdEffectDef = GetItemHoldEffect(ctx->battlerDef);
|
||||
|
||||
if (IsFutureSightAttackerInParty(damageCalcData->battlerAtk, damageCalcData->battlerDef, damageCalcData->move))
|
||||
return DoFutureSightAttackDamageCalc(damageCalcData, typeEffectivenessMultiplier, GetWeather());
|
||||
ctx->typeEffectivenessModifier = CalcTypeEffectivenessMultiplier(
|
||||
ctx->move,
|
||||
ctx->moveType,
|
||||
ctx->battlerAtk,
|
||||
ctx->battlerDef,
|
||||
ctx->abilityDef,
|
||||
ctx->updateFlags);
|
||||
|
||||
return DoMoveDamageCalc(damageCalcData, fixedBasePower, typeEffectivenessMultiplier, GetWeather());
|
||||
if (IsFutureSightAttackerInParty(ctx->battlerAtk, ctx->battlerDef, ctx->move))
|
||||
return DoFutureSightAttackDamageCalc(ctx);
|
||||
|
||||
return DoMoveDamageCalc(ctx);
|
||||
}
|
||||
|
||||
// for AI so that typeEffectivenessModifier, weather, abilities and holdEffects are calculated only once
|
||||
s32 CalculateMoveDamageVars(struct DamageCalculationData *damageCalcData, u32 fixedBasePower, uq4_12_t typeEffectivenessModifier,
|
||||
u32 weather, enum ItemHoldEffect holdEffectAtk, enum ItemHoldEffect holdEffectDef, u32 abilityAtk, u32 abilityDef)
|
||||
s32 CalculateMoveDamageVars(struct DamageContext *ctx)
|
||||
{
|
||||
s32 dmg = DoFixedDamageMoveCalc(damageCalcData);
|
||||
s32 dmg = DoFixedDamageMoveCalc(ctx);
|
||||
if (dmg != INT32_MAX)
|
||||
return dmg;
|
||||
|
||||
return DoMoveDamageCalcVars(damageCalcData, fixedBasePower, typeEffectivenessModifier, weather,
|
||||
holdEffectAtk, holdEffectDef, abilityAtk, abilityDef);
|
||||
return DoMoveDamageCalcVars(ctx);
|
||||
}
|
||||
|
||||
static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 moveType, u32 battlerDef, u32 defAbility, u32 defType, u32 battlerAtk, bool32 recordAbilities)
|
||||
@ -10715,6 +10688,7 @@ bool32 PickupHasValidTarget(u32 battler)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// TODO: Pass down weather as an arg
|
||||
bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags)
|
||||
{
|
||||
if (gBattleWeather & weatherFlags && HasWeatherEffect())
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user