diff --git a/src/battle-phases.ts b/src/battle-phases.ts index 0b818a9b5..36fc5e206 100644 --- a/src/battle-phases.ts +++ b/src/battle-phases.ts @@ -1,7 +1,7 @@ import BattleScene, { maxExpLevel, startingLevel, startingWave } from "./battle-scene"; import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult } from "./pokemon"; import * as Utils from './utils'; -import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveCategory, MoveEffectAttr, MoveFlags, MoveHitEffectAttr, Moves, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet } from "./data/move"; +import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveCategory, MoveEffectAttr, MoveFlags, Moves, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger } from "./data/move"; import { Mode } from './ui/ui'; import { Command } from "./ui/command-ui-handler"; import { Stat } from "./data/pokemon-stat"; @@ -1321,6 +1321,9 @@ class MoveEffectPhase extends PokemonPhase { const isProtected = !this.move.getMove().hasFlag(MoveFlags.IGNORE_PROTECT) && target.lapseTag(BattlerTagType.PROTECTED); moveHistoryEntry.result = MoveResult.SUCCESS; + + applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.PRE_APPLY, + user, target, this.move.getMove()); const hitResult = !isProtected ? target.apply(user, this.move) : HitResult.NO_EFFECT; @@ -1328,9 +1331,11 @@ class MoveEffectPhase extends PokemonPhase { const chargeEffect = !!this.move.getMove().getAttrs(ChargeAttr).find(ca => (ca as ChargeAttr).chargeEffect); // Charge attribute with charge effect takes all effect attributes and applies them to charge stage, so ignore them if this is present if (!chargeEffect) - applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).selfTarget, user, target, this.move.getMove()); + applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.POST_APPLY + && (attr as MoveEffectAttr).selfTarget, user, target, this.move.getMove()); if (hitResult !== HitResult.NO_EFFECT) { - applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && !(attr as MoveEffectAttr).selfTarget, user, target, this.move.getMove()); + applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.POST_APPLY + && !(attr as MoveEffectAttr).selfTarget, user, target, this.move.getMove()); if (hitResult < HitResult.NO_EFFECT) { const flinched = new Utils.BooleanHolder(false); user.scene.applyModifiers(FlinchChanceModifier, user.isPlayer(), user, flinched); @@ -1338,7 +1343,8 @@ class MoveEffectPhase extends PokemonPhase { target.addTag(BattlerTagType.FLINCHED, undefined, this.move.moveId, user.id); } if (!isProtected && !chargeEffect) { - applyMoveAttrs(MoveHitEffectAttr, user, target, this.move.getMove()); + applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.HIT, + user, target, this.move.getMove()); if (!target.isFainted()) applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move, hitResult); if (this.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) diff --git a/src/data/move.ts b/src/data/move.ts index e85f01c35..062b23139 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -3,7 +3,7 @@ import { DamagePhase, MovePhase, ObtainStatusEffectPhase, PokemonHealPhase, Stat import { BattleStat } from "./battle-stat"; import { BattlerTagType } from "./battler-tag"; import { getPokemonMessage } from "../messages"; -import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../pokemon"; +import Pokemon, { AttackMoveResult, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../pokemon"; import { StatusEffect, getStatusEffectDescriptor } from "./status-effect"; import { Type } from "./type"; import * as Utils from "../utils"; @@ -822,13 +822,21 @@ export abstract class MoveAttr { } } +export enum MoveEffectTrigger { + PRE_APPLY, + POST_APPLY, + HIT +} + export class MoveEffectAttr extends MoveAttr { public selfTarget: boolean; + public trigger: MoveEffectTrigger; - constructor(selfTarget?: boolean) { + constructor(selfTarget?: boolean, trigger?: MoveEffectTrigger) { super(); this.selfTarget = !!selfTarget; + this.trigger = trigger !== undefined ? trigger : MoveEffectTrigger.POST_APPLY; } canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) { @@ -841,25 +849,6 @@ export class MoveEffectAttr extends MoveAttr { } } -export class MoveHitEffectAttr extends MoveAttr { - public selfTarget: boolean; - - constructor(selfTarget?: boolean) { - super(); - - this.selfTarget = !!selfTarget; - } - - canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) { - return !!(this.selfTarget ? user.hp : target.hp) - && (this.selfTarget || !target.getTag(BattlerTagType.PROTECTED) || move.hasFlag(MoveFlags.IGNORE_PROTECT)); - } - - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]) { - return this.canApply(user, target, move, args); - } -} - export class HighCritAttr extends MoveAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { (args[0] as Utils.IntegerHolder).value++; @@ -1005,7 +994,7 @@ export class RecoilAttr extends MoveEffectAttr { export class SacrificialAttr extends MoveEffectAttr { constructor() { - super(true); + super(true, MoveEffectTrigger.PRE_APPLY); } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -1082,11 +1071,11 @@ export class WeatherHealAttr extends HealAttr { } } -export class HitHealAttr extends MoveHitEffectAttr { +export class HitHealAttr extends MoveEffectAttr { private healRatio: number; constructor(healRatio?: number) { - super(true); + super(true, MoveEffectTrigger.HIT); this.healRatio = healRatio || 0.5; } @@ -1142,12 +1131,12 @@ export class MultiHitAttr extends MoveAttr { } } -export class StatusEffectAttr extends MoveHitEffectAttr { +export class StatusEffectAttr extends MoveEffectAttr { public effect: StatusEffect; public cureTurn: integer; constructor(effect: StatusEffect, selfTarget?: boolean, cureTurn?: integer) { - super(selfTarget); + super(selfTarget, MoveEffectTrigger.HIT); this.effect = effect; this.cureTurn = cureTurn; @@ -1170,9 +1159,9 @@ export class StatusEffectAttr extends MoveHitEffectAttr { } } -export class StealHeldItemAttr extends MoveHitEffectAttr { +export class StealHeldItemAttr extends MoveEffectAttr { constructor() { - super(false); + super(false, MoveEffectTrigger.HIT); } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -1280,7 +1269,11 @@ export class ClearWeatherAttr extends MoveEffectAttr { } } -export class OneHitKOAttr extends MoveHitEffectAttr { +export class OneHitKOAttr extends MoveEffectAttr { + constructor() { + super(false, MoveEffectTrigger.HIT); + } + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { target.damage(target.hp, true); user.scene.queueMessage('It\'s a one-hit KO!'); @@ -1342,12 +1335,12 @@ export class SolarBeamChargeAttr extends ChargeAttr { } } -export class StatChangeAttr extends MoveHitEffectAttr { +export class StatChangeAttr extends MoveEffectAttr { public stats: BattleStat[]; public levels: integer; constructor(stats: BattleStat | BattleStat[], levels: integer, selfTarget?: boolean) { - super(selfTarget); + super(selfTarget, MoveEffectTrigger.HIT); this.stats = typeof(stats) === 'number' ? [ stats as BattleStat ] : stats as BattleStat[]; @@ -1660,9 +1653,9 @@ export class DisableMoveAttr extends MoveEffectAttr { } } -export class FrenzyAttr extends MoveHitEffectAttr { +export class FrenzyAttr extends MoveEffectAttr { constructor() { - super(true); + super(true, MoveEffectTrigger.HIT); } canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) {