[Enhancement] Add support for simulated calls to Abilities (#3529)
* Adds simulated tag support to all abilities
* Fix compiler errors in ability.ts
Most things are still on fire 😢
* Fix errors left over after merge
* Another pass through simulated ability call logic
* Fix leftover errors from merge resolution
* Another gh pages issue :pikamad:
* Simulated call fixes based on Kev's feedback
* RIP phases.ts
---------
Co-authored-by: Xavion3 <xavion333@gmail.com>
This commit is contained in:
parent
1487d7f51c
commit
051d38e0a2
|
@ -1100,7 +1100,7 @@ export default class BattleScene extends SceneBase {
|
|||
} else if (trainerConfigs[trainerType].hasDouble) {
|
||||
const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8);
|
||||
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
|
||||
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance));
|
||||
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance));
|
||||
doubleTrainer = !Utils.randSeedInt(doubleChance.value);
|
||||
// Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance
|
||||
if (trainerConfigs[trainerType].trainerTypeDouble && ![ TrainerType.TATE, TrainerType.LIZA ].includes(trainerType)) {
|
||||
|
@ -1116,7 +1116,7 @@ export default class BattleScene extends SceneBase {
|
|||
if (newBattleType === BattleType.WILD && !this.gameMode.isWaveFinal(newWaveIndex)) {
|
||||
const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8);
|
||||
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
|
||||
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance));
|
||||
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance));
|
||||
newDouble = !Utils.randSeedInt(doubleChance.value);
|
||||
} else if (newBattleType === BattleType.TRAINER) {
|
||||
newDouble = newTrainer?.variant === TrainerVariant.DOUBLE;
|
||||
|
@ -2136,7 +2136,7 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
pushMovePhase(movePhase: MovePhase, priorityOverride?: integer): void {
|
||||
const movePriority = new Utils.IntegerHolder(priorityOverride !== undefined ? priorityOverride : movePhase.move.getMove().priority);
|
||||
applyAbAttrs(ChangeMovePriorityAbAttr, movePhase.pokemon, null, movePhase.move.getMove(), movePriority);
|
||||
applyAbAttrs(ChangeMovePriorityAbAttr, movePhase.pokemon, null, false, movePhase.move.getMove(), movePriority);
|
||||
const lowerPriorityPhase = this.phaseQueue.find(p => p instanceof MovePhase && p.move.getMove().priority < movePriority.value);
|
||||
if (lowerPriorityPhase) {
|
||||
this.phaseQueue.splice(this.phaseQueue.indexOf(lowerPriorityPhase), 0, movePhase);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -269,7 +269,7 @@ const QuickGuardConditionFunc: ProtectConditionFunc = (arena, moveId) => {
|
|||
if (effectPhase instanceof MoveEffectPhase) {
|
||||
const attacker = effectPhase.getUserPokemon()!;
|
||||
applyMoveAttrs(IncrementMovePriorityAttr, attacker, null, move, priority);
|
||||
applyAbAttrs(ChangeMovePriorityAbAttr, attacker, null, move, priority);
|
||||
applyAbAttrs(ChangeMovePriorityAbAttr, attacker, null, false, move, priority);
|
||||
}
|
||||
return priority.value > 0;
|
||||
};
|
||||
|
|
|
@ -36,25 +36,25 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
|
|||
return (pokemon: Pokemon) => {
|
||||
const threshold = new Utils.NumberHolder(0.25);
|
||||
const battleStat = (berryType - BerryType.LIECHI) as BattleStat;
|
||||
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
|
||||
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
|
||||
return pokemon.getHpRatio() < threshold.value && pokemon.summonData.battleStats[battleStat] < 6;
|
||||
};
|
||||
case BerryType.LANSAT:
|
||||
return (pokemon: Pokemon) => {
|
||||
const threshold = new Utils.NumberHolder(0.25);
|
||||
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
|
||||
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
|
||||
return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST);
|
||||
};
|
||||
case BerryType.STARF:
|
||||
return (pokemon: Pokemon) => {
|
||||
const threshold = new Utils.NumberHolder(0.25);
|
||||
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
|
||||
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
|
||||
return pokemon.getHpRatio() < 0.25;
|
||||
};
|
||||
case BerryType.LEPPA:
|
||||
return (pokemon: Pokemon) => {
|
||||
const threshold = new Utils.NumberHolder(0.25);
|
||||
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
|
||||
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
|
||||
return !!pokemon.getMoveset().find(m => !m?.getPpRatio());
|
||||
};
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
|
|||
pokemon.battleData.berriesEaten.push(berryType);
|
||||
}
|
||||
const hpHealed = new Utils.NumberHolder(Math.floor(pokemon.getMaxHp() / 4));
|
||||
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, hpHealed);
|
||||
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed);
|
||||
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(),
|
||||
hpHealed.value, i18next.t("battle:hpHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: getBerryName(berryType) }), true));
|
||||
};
|
||||
|
@ -97,7 +97,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
|
|||
}
|
||||
const battleStat = (berryType - BerryType.LIECHI) as BattleStat;
|
||||
const statLevels = new Utils.NumberHolder(1);
|
||||
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, statLevels);
|
||||
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statLevels);
|
||||
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ battleStat ], statLevels.value));
|
||||
};
|
||||
case BerryType.LANSAT:
|
||||
|
@ -113,7 +113,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
|
|||
pokemon.battleData.berriesEaten.push(berryType);
|
||||
}
|
||||
const statLevels = new Utils.NumberHolder(2);
|
||||
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, statLevels);
|
||||
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statLevels);
|
||||
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ BattleStat.RAND ], statLevels.value));
|
||||
};
|
||||
case BerryType.LEPPA:
|
||||
|
|
|
@ -590,7 +590,7 @@ export default class Move implements Localizable {
|
|||
case MoveFlags.IGNORE_ABILITIES:
|
||||
if (user.hasAbilityWithAttr(MoveAbilityBypassAbAttr)) {
|
||||
const abilityEffectsIgnored = new Utils.BooleanHolder(false);
|
||||
applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, this);
|
||||
applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, false, this);
|
||||
if (abilityEffectsIgnored.value) {
|
||||
return true;
|
||||
}
|
||||
|
@ -686,11 +686,11 @@ export default class Move implements Localizable {
|
|||
* @param target {@linkcode Pokemon} The Pokémon being targeted by the move.
|
||||
* @returns The calculated accuracy of the move.
|
||||
*/
|
||||
calculateBattleAccuracy(user: Pokemon, target: Pokemon) {
|
||||
calculateBattleAccuracy(user: Pokemon, target: Pokemon, simulated: boolean = false) {
|
||||
const moveAccuracy = new Utils.NumberHolder(this.accuracy);
|
||||
|
||||
applyMoveAttrs(VariableAccuracyAttr, user, target, this, moveAccuracy);
|
||||
applyPreDefendAbAttrs(WonderSkinAbAttr, target, user, this, { value: false }, moveAccuracy);
|
||||
applyPreDefendAbAttrs(WonderSkinAbAttr, target, user, this, { value: false }, simulated, moveAccuracy);
|
||||
|
||||
if (moveAccuracy.value === -1) {
|
||||
return moveAccuracy.value;
|
||||
|
@ -724,7 +724,7 @@ export default class Move implements Localizable {
|
|||
* @param target {@linkcode Pokemon} The Pokémon being targeted by the move.
|
||||
* @returns The calculated power of the move.
|
||||
*/
|
||||
calculateBattlePower(source: Pokemon, target: Pokemon): number {
|
||||
calculateBattlePower(source: Pokemon, target: Pokemon, simulated: boolean = false): number {
|
||||
if (this.category === MoveCategory.STATUS) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -732,17 +732,17 @@ export default class Move implements Localizable {
|
|||
const power = new Utils.NumberHolder(this.power);
|
||||
const typeChangeMovePowerMultiplier = new Utils.NumberHolder(1);
|
||||
|
||||
applyPreAttackAbAttrs(MoveTypeChangeAttr, source, target, this, typeChangeMovePowerMultiplier);
|
||||
applyPreAttackAbAttrs(MoveTypeChangeAttr, source, target, this, simulated, typeChangeMovePowerMultiplier);
|
||||
|
||||
const sourceTeraType = source.getTeraType();
|
||||
if (sourceTeraType !== Type.UNKNOWN && sourceTeraType === this.type && power.value < 60 && this.priority <= 0 && !this.hasAttr(MultiHitAttr) && !source.scene.findModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) {
|
||||
power.value = 60;
|
||||
}
|
||||
|
||||
applyPreAttackAbAttrs(VariableMovePowerAbAttr, source, target, this, power);
|
||||
applyPreAttackAbAttrs(VariableMovePowerAbAttr, source, target, this, simulated, power);
|
||||
|
||||
if (source.getAlly()) {
|
||||
applyPreAttackAbAttrs(AllyMoveCategoryPowerBoostAbAttr, source.getAlly(), target, this, power);
|
||||
applyPreAttackAbAttrs(AllyMoveCategoryPowerBoostAbAttr, source.getAlly(), target, this, simulated, power);
|
||||
}
|
||||
|
||||
const fieldAuras = new Set(
|
||||
|
@ -752,11 +752,11 @@ export default class Move implements Localizable {
|
|||
);
|
||||
for (const aura of fieldAuras) {
|
||||
// The only relevant values are `move` and the `power` holder
|
||||
aura.applyPreAttack(null, null, null, this, [power]);
|
||||
aura.applyPreAttack(null, null, simulated, null, this, [power]);
|
||||
}
|
||||
|
||||
const alliedField: Pokemon[] = source instanceof PlayerPokemon ? source.scene.getPlayerField() : source.scene.getEnemyField();
|
||||
alliedField.forEach(p => applyPreAttackAbAttrs(UserFieldMoveTypePowerBoostAbAttr, p, target, this, power));
|
||||
alliedField.forEach(p => applyPreAttackAbAttrs(UserFieldMoveTypePowerBoostAbAttr, p, target, this, simulated, power));
|
||||
|
||||
power.value *= typeChangeMovePowerMultiplier.value;
|
||||
|
||||
|
@ -984,9 +984,9 @@ export class MoveEffectAttr extends MoveAttr {
|
|||
*/
|
||||
getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean, showAbility?: Boolean): integer {
|
||||
const moveChance = new Utils.NumberHolder(move.chance);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, moveChance, move, target, selfEffect, showAbility);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, false, moveChance, move, target, selfEffect, showAbility);
|
||||
if (!selfEffect) {
|
||||
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, target, user, null, null, moveChance);
|
||||
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, target, user, null, null, false, moveChance);
|
||||
}
|
||||
return moveChance.value;
|
||||
}
|
||||
|
@ -1883,7 +1883,7 @@ export class MultiHitAttr extends MoveAttr {
|
|||
{
|
||||
const rand = user.randSeedInt(16);
|
||||
const hitValue = new Utils.IntegerHolder(rand);
|
||||
applyAbAttrs(MaxMultiHitAbAttr, user, null, hitValue);
|
||||
applyAbAttrs(MaxMultiHitAbAttr, user, null, false, hitValue);
|
||||
if (hitValue.value >= 10) {
|
||||
return 2;
|
||||
} else if (hitValue.value >= 4) {
|
||||
|
@ -1954,7 +1954,7 @@ export class StatusEffectAttr extends MoveEffectAttr {
|
|||
}
|
||||
if ((!pokemon.status || (pokemon.status.effect === this.effect && moveChance < 0))
|
||||
&& pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) {
|
||||
applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, this.effect);
|
||||
applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, false, this.effect);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ export class Terrain {
|
|||
case TerrainType.PSYCHIC:
|
||||
if (!move.hasAttr(ProtectAttr)) {
|
||||
const priority = new Utils.IntegerHolder(move.priority);
|
||||
applyAbAttrs(ChangeMovePriorityAbAttr, user, null, move, priority);
|
||||
applyAbAttrs(ChangeMovePriorityAbAttr, user, null, false, move, priority);
|
||||
// Cancels move if the move has positive priority and targets a Pokemon grounded on the Psychic Terrain
|
||||
return priority.value > 0 && user.getOpponents().some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded());
|
||||
}
|
||||
|
|
|
@ -694,7 +694,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
break;
|
||||
}
|
||||
}
|
||||
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, opponent, null, statLevel);
|
||||
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, opponent, null, false, statLevel);
|
||||
if (move) {
|
||||
applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, opponent, move, statLevel);
|
||||
}
|
||||
|
@ -1122,10 +1122,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
const suppressed = new Utils.BooleanHolder(false);
|
||||
this.scene.getField(true).filter(p => p !== this).map(p => {
|
||||
if (p.getAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility()) {
|
||||
p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, suppressed, [ability]));
|
||||
p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, false, suppressed, [ability]));
|
||||
}
|
||||
if (p.getPassiveAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility(true)) {
|
||||
p.getPassiveAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, true, suppressed, [ability]));
|
||||
p.getPassiveAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, true, false, suppressed, [ability]));
|
||||
}
|
||||
});
|
||||
if (suppressed.value) {
|
||||
|
@ -1177,7 +1177,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
getWeight(): number {
|
||||
const weight = new Utils.NumberHolder(this.species.weight);
|
||||
// This will trigger the ability overlay so only call this function when necessary
|
||||
applyAbAttrs(WeightMultiplierAbAttr, this, null, weight);
|
||||
applyAbAttrs(WeightMultiplierAbAttr, this, null, false, weight);
|
||||
return weight.value;
|
||||
}
|
||||
|
||||
|
@ -1237,10 +1237,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
const cancelled = new Utils.BooleanHolder(false);
|
||||
applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier);
|
||||
if (!typeless && !ignoreAbility) {
|
||||
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true);
|
||||
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, true, typeMultiplier);
|
||||
}
|
||||
if (!cancelled.value && !ignoreAbility) {
|
||||
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true);
|
||||
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, true, typeMultiplier);
|
||||
}
|
||||
|
||||
return (!cancelled.value ? Number(typeMultiplier.value) : 0) as TypeDamageMultiplier;
|
||||
|
@ -1281,7 +1281,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
if (source) {
|
||||
const ignoreImmunity = new Utils.BooleanHolder(false);
|
||||
if (source.isActive(true) && source.hasAbilityWithAttr(IgnoreTypeImmunityAbAttr)) {
|
||||
applyAbAttrs(IgnoreTypeImmunityAbAttr, source, ignoreImmunity, moveType, defType);
|
||||
applyAbAttrs(IgnoreTypeImmunityAbAttr, source, ignoreImmunity, false, moveType, defType);
|
||||
}
|
||||
if (ignoreImmunity.value) {
|
||||
return 1;
|
||||
|
@ -1922,9 +1922,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
const userAccuracyLevel = new Utils.IntegerHolder(this.summonData.battleStats[BattleStat.ACC]);
|
||||
const targetEvasionLevel = new Utils.IntegerHolder(target.summonData.battleStats[BattleStat.EVA]);
|
||||
|
||||
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, target, null, userAccuracyLevel);
|
||||
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, this, null, targetEvasionLevel);
|
||||
applyAbAttrs(IgnoreOpponentEvasionAbAttr, this, null, targetEvasionLevel);
|
||||
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, target, null, false, userAccuracyLevel);
|
||||
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, this, null, false, targetEvasionLevel);
|
||||
applyAbAttrs(IgnoreOpponentEvasionAbAttr, this, null, false, targetEvasionLevel);
|
||||
applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, target, sourceMove, targetEvasionLevel);
|
||||
this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), TempBattleStat.ACC, userAccuracyLevel);
|
||||
|
||||
|
@ -1939,7 +1939,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
: 3 / (3 + Math.min(targetEvasionLevel.value - userAccuracyLevel.value, 6));
|
||||
}
|
||||
|
||||
applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this, BattleStat.ACC, accuracyMultiplier, sourceMove);
|
||||
applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this, BattleStat.ACC, accuracyMultiplier, false, sourceMove);
|
||||
|
||||
const evasionMultiplier = new Utils.NumberHolder(1);
|
||||
applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, target, BattleStat.EVA, evasionMultiplier);
|
||||
|
@ -1949,6 +1949,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
return accuracyMultiplier.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the results of a move to this pokemon
|
||||
* @param {Pokemon} source The pokemon using the move
|
||||
* @param {PokemonMove} battlerMove The move being used
|
||||
* @returns {HitResult} The result of the attack
|
||||
*/
|
||||
apply(source: Pokemon, move: Move): HitResult {
|
||||
let result: HitResult;
|
||||
const damage = new Utils.NumberHolder(0);
|
||||
|
@ -1984,12 +1990,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
const sourceTeraType = source.getTeraType();
|
||||
|
||||
if (!typeless) {
|
||||
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier);
|
||||
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier);
|
||||
applyMoveAttrs(NeutralDamageAgainstFlyingTypeMultiplierAttr, source, this, move, typeMultiplier);
|
||||
}
|
||||
if (!cancelled.value) {
|
||||
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier);
|
||||
defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, typeMultiplier));
|
||||
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier);
|
||||
defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, false, typeMultiplier));
|
||||
}
|
||||
|
||||
if (cancelled.value) {
|
||||
|
@ -2012,7 +2018,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
const critOnly = new Utils.BooleanHolder(false);
|
||||
const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT);
|
||||
applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly);
|
||||
applyAbAttrs(ConditionalCritAbAttr, source, null, critOnly, this, move);
|
||||
applyAbAttrs(ConditionalCritAbAttr, source, null, false, critOnly, this, move);
|
||||
if (critOnly.value || critAlways) {
|
||||
isCritical = true;
|
||||
} else {
|
||||
|
@ -2022,7 +2028,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
this.scene.applyModifiers(TempBattleStatBoosterModifier, source.isPlayer(), TempBattleStat.CRIT, critLevel);
|
||||
const bonusCrit = new Utils.BooleanHolder(false);
|
||||
//@ts-ignore
|
||||
if (applyAbAttrs(BonusCritAbAttr, source, null, bonusCrit)) { // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus.
|
||||
if (applyAbAttrs(BonusCritAbAttr, source, null, false, bonusCrit)) { // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus.
|
||||
if (bonusCrit.value) {
|
||||
critLevel.value += 1;
|
||||
}
|
||||
|
@ -2040,7 +2046,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
if (isCritical) {
|
||||
const noCritTag = this.scene.arena.getTagOnSide(NoCritTag, defendingSide);
|
||||
const blockCrit = new Utils.BooleanHolder(false);
|
||||
applyAbAttrs(BlockCritAbAttr, this, null, blockCrit);
|
||||
applyAbAttrs(BlockCritAbAttr, this, null, false, blockCrit);
|
||||
if (noCritTag || blockCrit.value) {
|
||||
isCritical = false;
|
||||
}
|
||||
|
@ -2048,7 +2054,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
const sourceAtk = new Utils.IntegerHolder(source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this, undefined, isCritical));
|
||||
const targetDef = new Utils.IntegerHolder(this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source, move, isCritical));
|
||||
const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1);
|
||||
applyAbAttrs(MultCritAbAttr, source, null, criticalMultiplier);
|
||||
applyAbAttrs(MultCritAbAttr, source, null, false, criticalMultiplier);
|
||||
const screenMultiplier = new Utils.NumberHolder(1);
|
||||
if (!isCritical) {
|
||||
this.scene.arena.applyTagsForSide(WeakenMoveScreenTag, defendingSide, move.category, this.scene.currentBattle.double, screenMultiplier);
|
||||
|
@ -2063,7 +2069,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
stabMultiplier.value += 0.5;
|
||||
}
|
||||
|
||||
applyAbAttrs(StabBoostAbAttr, source, null, stabMultiplier);
|
||||
applyAbAttrs(StabBoostAbAttr, source, null, false, stabMultiplier);
|
||||
|
||||
if (sourceTeraType !== Type.UNKNOWN && matchesSourceType) {
|
||||
stabMultiplier.value = Math.min(stabMultiplier.value + 0.5, 2.25);
|
||||
|
@ -2081,7 +2087,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
numTargets = effectPhase.getTargets().length;
|
||||
}
|
||||
const twoStrikeMultiplier = new Utils.NumberHolder(1);
|
||||
applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, numTargets, new Utils.IntegerHolder(0), twoStrikeMultiplier);
|
||||
applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, false, numTargets, new Utils.IntegerHolder(0), twoStrikeMultiplier);
|
||||
|
||||
if (!isTypeImmune) {
|
||||
const levelMultiplier = (2 * source.level / 5 + 2);
|
||||
|
@ -2100,14 +2106,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
if (isPhysical && source.status && source.status.effect === StatusEffect.BURN) {
|
||||
if (!move.hasAttr(BypassBurnDamageReductionAttr)) {
|
||||
const burnDamageReductionCancelled = new Utils.BooleanHolder(false);
|
||||
applyAbAttrs(BypassBurnDamageReductionAbAttr, source, burnDamageReductionCancelled);
|
||||
applyAbAttrs(BypassBurnDamageReductionAbAttr, source, burnDamageReductionCancelled, false);
|
||||
if (!burnDamageReductionCancelled.value) {
|
||||
damage.value = Math.floor(damage.value / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
applyPreAttackAbAttrs(DamageBoostAbAttr, source, this, move, damage);
|
||||
applyPreAttackAbAttrs(DamageBoostAbAttr, source, this, move, false, damage);
|
||||
|
||||
/**
|
||||
* For each {@link HitsTagAttr} the move has, doubles the damage of the move if:
|
||||
|
@ -2165,7 +2171,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
this.scene.applyModifiers(EnemyDamageReducerModifier, false, damage);
|
||||
}
|
||||
|
||||
applyPreDefendAbAttrs(ReceivedMoveDamageMultiplierAbAttr, this, source, move, cancelled, damage);
|
||||
applyPreDefendAbAttrs(ReceivedMoveDamageMultiplierAbAttr, this, source, move, cancelled, false, damage);
|
||||
}
|
||||
|
||||
// This attribute may modify damage arbitrarily, so be careful about changing its order of application.
|
||||
|
@ -2178,7 +2184,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
|
||||
if (damage.value) {
|
||||
if (this.isFullHp()) {
|
||||
applyPreDefendAbAttrs(PreDefendFullHpEndureAbAttr, this, source, move, cancelled, damage);
|
||||
applyPreDefendAbAttrs(PreDefendFullHpEndureAbAttr, this, source, move, cancelled, false, damage);
|
||||
} else if (!this.isPlayer() && damage.value >= this.hp) {
|
||||
this.scene.applyModifiers(EnemyEndureChanceModifier, false, this);
|
||||
}
|
||||
|
@ -2245,11 +2251,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
break;
|
||||
case MoveCategory.STATUS:
|
||||
if (!typeless) {
|
||||
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier);
|
||||
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier);
|
||||
}
|
||||
if (!cancelled.value) {
|
||||
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier);
|
||||
defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, typeMultiplier));
|
||||
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier);
|
||||
defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, false, typeMultiplier));
|
||||
}
|
||||
if (!typeMultiplier.value) {
|
||||
this.scene.queueMessage(i18next.t("battle:hitResultNoEffect", { pokemonName: getPokemonNameWithAffix(this) }));
|
||||
|
@ -2341,6 +2347,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
return maxForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && maxForms.includes(this.getFusionFormKey()!));
|
||||
}
|
||||
|
||||
canAddTag(tagType: BattlerTagType): boolean {
|
||||
if (this.getTag(tagType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const stubTag = new BattlerTag(tagType, 0, 0);
|
||||
|
||||
const cancelled = new Utils.BooleanHolder(false);
|
||||
applyPreApplyBattlerTagAbAttrs(BattlerTagImmunityAbAttr, this, stubTag, cancelled, true);
|
||||
|
||||
const userField = this.getAlliedField();
|
||||
userField.forEach(pokemon => applyPreApplyBattlerTagAbAttrs(UserFieldBattlerTagImmunityAbAttr, pokemon, stubTag, cancelled, true));
|
||||
|
||||
return !cancelled.value;
|
||||
}
|
||||
|
||||
addTag(tagType: BattlerTagType, turnCount: integer = 0, sourceMove?: Moves, sourceId?: integer): boolean {
|
||||
const existingTag = this.getTag(tagType);
|
||||
if (existingTag) {
|
||||
|
@ -2727,7 +2749,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
// Check if the source Pokemon has an ability that cancels the Poison/Toxic immunity
|
||||
const cancelImmunity = new Utils.BooleanHolder(false);
|
||||
if (sourcePokemon) {
|
||||
applyAbAttrs(IgnoreTypeStatusEffectImmunityAbAttr, sourcePokemon, cancelImmunity, effect, defType);
|
||||
applyAbAttrs(IgnoreTypeStatusEffectImmunityAbAttr, sourcePokemon, cancelImmunity, false, effect, defType);
|
||||
if (cancelImmunity.value) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2799,7 +2821,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
|
||||
if (effect === StatusEffect.SLEEP) {
|
||||
statusCureTurn = new Utils.IntegerHolder(this.randSeedIntRange(2, 4));
|
||||
applyAbAttrs(ReduceStatusEffectDurationAbAttr, this, null, effect, statusCureTurn);
|
||||
applyAbAttrs(ReduceStatusEffectDurationAbAttr, this, null, false, effect, statusCureTurn);
|
||||
|
||||
this.setFrameRate(4);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ export class AttemptRunPhase extends PokemonPhase {
|
|||
const enemySpeed = enemyField.reduce((total: integer, enemyPokemon: Pokemon) => total + enemyPokemon.getStat(Stat.SPD), 0) / enemyField.length;
|
||||
|
||||
const escapeChance = new Utils.IntegerHolder((((playerPokemon.getStat(Stat.SPD) * 128) / enemySpeed) + (30 * this.scene.currentBattle.escapeAttempts++)) % 256);
|
||||
applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, escapeChance);
|
||||
applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, false, escapeChance);
|
||||
|
||||
if (playerPokemon.randSeedInt(256) < escapeChance.value) {
|
||||
this.scene.playSound("flee");
|
||||
|
|
|
@ -189,7 +189,7 @@ export class CommandPhase extends FieldPhase {
|
|||
const batonPass = isSwitch && args[0] as boolean;
|
||||
const trappedAbMessages: string[] = [];
|
||||
if (!batonPass) {
|
||||
enemyField.forEach(enemyPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trapped, playerPokemon, true, trappedAbMessages));
|
||||
enemyField.forEach(enemyPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trapped, playerPokemon, trappedAbMessages, true));
|
||||
}
|
||||
if (batonPass || (!trapTag && !trapped.value)) {
|
||||
this.scene.currentBattle.turnCommands[this.fieldIndex] = isSwitch
|
||||
|
|
|
@ -67,7 +67,7 @@ export class EncounterPhase extends BattlePhase {
|
|||
battle.enemyParty[e].ivs = new Array(6).fill(31);
|
||||
}
|
||||
this.scene.getParty().slice(0, !battle.double ? 1 : 2).reverse().forEach(playerPokemon => {
|
||||
applyAbAttrs(SyncEncounterNatureAbAttr, playerPokemon, null, battle.enemyParty[e]);
|
||||
applyAbAttrs(SyncEncounterNatureAbAttr, playerPokemon, null, false, battle.enemyParty[e]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ export class EnemyCommandPhase extends FieldPhase {
|
|||
|
||||
const trapTag = enemyPokemon.findTag(t => t instanceof TrappedTag) as TrappedTag;
|
||||
const trapped = new Utils.BooleanHolder(false);
|
||||
opponents.forEach(playerPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, playerPokemon, trapped, enemyPokemon, true, []));
|
||||
opponents.forEach(playerPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, playerPokemon, trapped, enemyPokemon, [], true));
|
||||
if (!trapTag && !trapped.value) {
|
||||
const partyMemberScores = trainer.getPartyMemberMatchupScores(enemyPokemon.trainerSlot, true);
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||
// Assume single target for multi hit
|
||||
applyMoveAttrs(MultiHitAttr, user, this.getTarget() ?? null, move, hitCount);
|
||||
// If Parental Bond is applicable, double the hit count
|
||||
applyPreAttackAbAttrs(AddSecondStrikeAbAttr, user, null, move, targets.length, hitCount, new Utils.IntegerHolder(0));
|
||||
applyPreAttackAbAttrs(AddSecondStrikeAbAttr, user, null, move, false, targets.length, hitCount, new Utils.IntegerHolder(0));
|
||||
// If Multi-Lens is applicable, multiply the hit count by 1 + the number of Multi-Lenses held by the user
|
||||
if (move instanceof AttackMove && !move.hasAttr(FixedDamageAttr)) {
|
||||
this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, hitCount, new Utils.IntegerHolder(0));
|
||||
|
|
|
@ -90,7 +90,7 @@ export class MovePhase extends BattlePhase {
|
|||
: null;
|
||||
if (moveTarget) {
|
||||
const oldTarget = moveTarget.value;
|
||||
this.scene.getField(true).filter(p => p !== this.pokemon).forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, this.move.moveId, moveTarget));
|
||||
this.scene.getField(true).filter(p => p !== this.pokemon).forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, false, this.move.moveId, moveTarget));
|
||||
this.pokemon.getOpponents().forEach(p => {
|
||||
const redirectTag = p.getTag(CenterOfAttentionTag) as CenterOfAttentionTag;
|
||||
if (redirectTag && (!redirectTag.powder || (!this.pokemon.isOfType(Type.GRASS) && !this.pokemon.hasAbility(Abilities.OVERCOAT)))) {
|
||||
|
|
|
@ -34,7 +34,7 @@ export class PostTurnStatusEffectPhase extends PokemonPhase {
|
|||
break;
|
||||
case StatusEffect.BURN:
|
||||
damage.value = Math.max(pokemon.getMaxHp() >> 4, 1);
|
||||
applyAbAttrs(ReduceBurnDamageAbAttr, pokemon, null, damage);
|
||||
applyAbAttrs(ReduceBurnDamageAbAttr, pokemon, null, false, damage);
|
||||
break;
|
||||
}
|
||||
if (damage.value) {
|
||||
|
|
|
@ -68,7 +68,7 @@ export class StatChangePhase extends PokemonPhase {
|
|||
const levels = new Utils.IntegerHolder(this.levels);
|
||||
|
||||
if (!this.ignoreAbilities) {
|
||||
applyAbAttrs(StatChangeMultiplierAbAttr, pokemon, null, levels);
|
||||
applyAbAttrs(StatChangeMultiplierAbAttr, pokemon, null, false, levels);
|
||||
}
|
||||
|
||||
const battleStats = this.getPokemon().summonData.battleStats;
|
||||
|
@ -90,7 +90,7 @@ export class StatChangePhase extends PokemonPhase {
|
|||
|
||||
if (levels.value > 0 && this.canBeCopied) {
|
||||
for (const opponent of pokemon.getOpponents()) {
|
||||
applyAbAttrs(StatChangeCopyAbAttr, opponent, null, this.stats, levels.value);
|
||||
applyAbAttrs(StatChangeCopyAbAttr, opponent, null, false, this.stats, levels.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,8 @@ export class TurnStartPhase extends FieldPhase {
|
|||
this.scene.getField(true).filter(p => p.summonData).map(p => {
|
||||
const bypassSpeed = new Utils.BooleanHolder(false);
|
||||
const canCheckHeldItems = new Utils.BooleanHolder(true);
|
||||
applyAbAttrs(BypassSpeedChanceAbAttr, p, null, bypassSpeed);
|
||||
applyAbAttrs(PreventBypassSpeedChanceAbAttr, p, null, bypassSpeed, canCheckHeldItems);
|
||||
applyAbAttrs(BypassSpeedChanceAbAttr, p, null, false, bypassSpeed);
|
||||
applyAbAttrs(PreventBypassSpeedChanceAbAttr, p, null, false, bypassSpeed, canCheckHeldItems);
|
||||
if (canCheckHeldItems.value) {
|
||||
this.scene.applyModifiers(BypassSpeedChanceModifier, p.isPlayer(), p, bypassSpeed);
|
||||
}
|
||||
|
@ -64,8 +64,8 @@ export class TurnStartPhase extends FieldPhase {
|
|||
applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here?
|
||||
applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here?
|
||||
|
||||
applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here?
|
||||
applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here?
|
||||
applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, false, aMove, aPriority); //TODO: is the bang correct here?
|
||||
applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, false, bMove, bPriority); //TODO: is the bang correct here?
|
||||
|
||||
if (aPriority.value !== bPriority.value) {
|
||||
const bracketDifference = Math.ceil(aPriority.value) - Math.ceil(bPriority.value);
|
||||
|
|
|
@ -52,7 +52,7 @@ describe("Abilities - Sand Veil", () => {
|
|||
|
||||
const sandVeilAttr = allAbilities[Abilities.SAND_VEIL].getAttrs(BattleStatMultiplierAbAttr)[0];
|
||||
vi.spyOn(sandVeilAttr, "applyBattleStat").mockImplementation(
|
||||
(pokemon, passive, battleStat, statValue, args) => {
|
||||
(pokemon, passive, simulated, battleStat, statValue, args) => {
|
||||
if (battleStat === BattleStat.EVA && game.scene.arena.weather?.weatherType === WeatherType.SANDSTORM) {
|
||||
statValue.value *= -1; // will make all attacks miss
|
||||
return true;
|
||||
|
|
|
@ -67,7 +67,7 @@ describe("Abilities - Serene Grace", () => {
|
|||
|
||||
const chance = new Utils.IntegerHolder(move.chance);
|
||||
console.log(move.chance + " Their ability is " + phase.getUserPokemon()!.getAbility().name);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false);
|
||||
expect(chance.value).toBe(30);
|
||||
|
||||
}, 20000);
|
||||
|
@ -99,7 +99,7 @@ describe("Abilities - Serene Grace", () => {
|
|||
expect(move.id).toBe(Moves.AIR_SLASH);
|
||||
|
||||
const chance = new Utils.IntegerHolder(move.chance);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false);
|
||||
expect(chance.value).toBe(60);
|
||||
|
||||
}, 20000);
|
||||
|
|
|
@ -69,8 +69,8 @@ describe("Abilities - Sheer Force", () => {
|
|||
const power = new Utils.IntegerHolder(move.power);
|
||||
const chance = new Utils.IntegerHolder(move.chance);
|
||||
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false);
|
||||
applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, power);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false);
|
||||
applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, false, power);
|
||||
|
||||
expect(chance.value).toBe(0);
|
||||
expect(power.value).toBe(move.power * 5461/4096);
|
||||
|
@ -108,8 +108,8 @@ describe("Abilities - Sheer Force", () => {
|
|||
const power = new Utils.IntegerHolder(move.power);
|
||||
const chance = new Utils.IntegerHolder(move.chance);
|
||||
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false);
|
||||
applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, power);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false);
|
||||
applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, false, power);
|
||||
|
||||
expect(chance.value).toBe(-1);
|
||||
expect(power.value).toBe(move.power);
|
||||
|
@ -147,8 +147,8 @@ describe("Abilities - Sheer Force", () => {
|
|||
const power = new Utils.IntegerHolder(move.power);
|
||||
const chance = new Utils.IntegerHolder(move.chance);
|
||||
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false);
|
||||
applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, power);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false);
|
||||
applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, false, power);
|
||||
|
||||
expect(chance.value).toBe(-1);
|
||||
expect(power.value).toBe(move.power);
|
||||
|
@ -191,8 +191,8 @@ describe("Abilities - Sheer Force", () => {
|
|||
const target = phase.getTarget()!;
|
||||
const opponentType = target.getTypes()[0];
|
||||
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, chance, move, target, false);
|
||||
applyPreAttackAbAttrs(MovePowerBoostAbAttr, user, target, move, power);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, false, chance, move, target, false);
|
||||
applyPreAttackAbAttrs(MovePowerBoostAbAttr, user, target, move, false, power);
|
||||
applyPostDefendAbAttrs(PostDefendTypeChangeAbAttr, target, user, move, target.apply(user, move));
|
||||
|
||||
expect(chance.value).toBe(0);
|
||||
|
|
|
@ -67,8 +67,8 @@ describe("Abilities - Shield Dust", () => {
|
|||
expect(move.id).toBe(Moves.AIR_SLASH);
|
||||
|
||||
const chance = new Utils.IntegerHolder(move.chance);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false);
|
||||
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, phase.getTarget()!, phase.getUserPokemon()!, null!, null!, chance);
|
||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false);
|
||||
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, phase.getTarget()!, phase.getUserPokemon()!, null, null, false, chance);
|
||||
expect(chance.value).toBe(0);
|
||||
|
||||
}, 20000);
|
||||
|
|
Loading…
Reference in New Issue