[Refactor] Added ON_GET_HIT BattlerTagLapseType

Adjusted BeakBlastChargingTag and ShellTrapTag to use new lapse type

Adjusted MoveEffectPhase to now lapse all tags with the ON_GET_HIT lapse type
This commit is contained in:
Mason 2024-08-19 19:36:36 -04:00
parent ae2ab120dc
commit 404199d227
3 changed files with 89 additions and 48 deletions

View File

@ -1,28 +1,33 @@
import { ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim } from "./battle-anims"; import {ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim} from "./battle-anims";
import { getPokemonNameWithAffix } from "../messages"; import {getPokemonNameWithAffix} from "../messages";
import Pokemon, { MoveResult, HitResult } from "../field/pokemon"; import Pokemon, {HitResult, MoveResult} from "../field/pokemon";
import { Stat, getStatName } from "./pokemon-stat"; import {getStatName, Stat} from "./pokemon-stat";
import { StatusEffect } from "./status-effect"; import {StatusEffect} from "./status-effect";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { ChargeAttr, MoveFlags, allMoves } from "./move"; import Move, {allMoves, ChargeAttr, MoveCategory, MoveFlags} from "./move";
import { Type } from "./type"; import {Type} from "./type";
import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs } from "./ability"; import {
import { TerrainType } from "./terrain"; allAbilities,
import { WeatherType } from "./weather"; applyAbAttrs,
import { BattleStat } from "./battle-stat"; BlockNonDirectDamageAbAttr,
import { allAbilities } from "./ability"; FlinchEffectAbAttr,
import { SpeciesFormChangeManualTrigger } from "./pokemon-forms"; ReverseDrainAbAttr
import { Abilities } from "#enums/abilities"; } from "./ability";
import { BattlerTagType } from "#enums/battler-tag-type"; import {TerrainType} from "./terrain";
import { Moves } from "#enums/moves"; import {WeatherType} from "./weather";
import { Species } from "#enums/species"; import {BattleStat} from "./battle-stat";
import {SpeciesFormChangeManualTrigger} from "./pokemon-forms";
import {Abilities} from "#enums/abilities";
import {BattlerTagType} from "#enums/battler-tag-type";
import {Moves} from "#enums/moves";
import {Species} from "#enums/species";
import i18next from "#app/plugins/i18n.js"; import i18next from "#app/plugins/i18n.js";
import { CommonAnimPhase } from "#app/phases/common-anim-phase.js"; import {CommonAnimPhase} from "#app/phases/common-anim-phase.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import {MoveEffectPhase} from "#app/phases/move-effect-phase.js";
import { MovePhase } from "#app/phases/move-phase.js"; import {MovePhase} from "#app/phases/move-phase.js";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js"; import {PokemonHealPhase} from "#app/phases/pokemon-heal-phase.js";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase.js"; import {ShowAbilityPhase} from "#app/phases/show-ability-phase.js";
import { StatChangePhase, StatChangeCallback } from "#app/phases/stat-change-phase.js"; import {StatChangeCallback, StatChangePhase} from "#app/phases/stat-change-phase.js";
export enum BattlerTagLapseType { export enum BattlerTagLapseType {
FAINT, FAINT,
@ -31,6 +36,7 @@ export enum BattlerTagLapseType {
AFTER_MOVE, AFTER_MOVE,
MOVE_EFFECT, MOVE_EFFECT,
TURN_END, TURN_END,
ON_GET_HIT,
CUSTOM CUSTOM
} }
@ -123,6 +129,7 @@ export class RechargingTag extends BattlerTag {
} }
} }
/** /**
* BattlerTag representing the "charge phase" of Beak Blast. * BattlerTag representing the "charge phase" of Beak Blast.
* Pokemon with this tag will inflict BURN status on any attacker that makes contact. * Pokemon with this tag will inflict BURN status on any attacker that makes contact.
@ -130,7 +137,7 @@ export class RechargingTag extends BattlerTag {
*/ */
export class BeakBlastChargingTag extends BattlerTag { export class BeakBlastChargingTag extends BattlerTag {
constructor() { constructor() {
super(BattlerTagType.BEAK_BLAST_CHARGING, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END ], 1, Moves.BEAK_BLAST); super(BattlerTagType.BEAK_BLAST_CHARGING, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END, BattlerTagLapseType.ON_GET_HIT], 1, Moves.BEAK_BLAST);
} }
onAdd(pokemon: Pokemon): void { onAdd(pokemon: Pokemon): void {
@ -146,14 +153,13 @@ export class BeakBlastChargingTag extends BattlerTag {
* to be removed after the source makes a move (or the turn ends, whichever comes first) * to be removed after the source makes a move (or the turn ends, whichever comes first)
* @param pokemon {@linkcode Pokemon} the owner of this tag * @param pokemon {@linkcode Pokemon} the owner of this tag
* @param lapseType {@linkcode BattlerTagLapseType} the type of functionality invoked in battle * @param lapseType {@linkcode BattlerTagLapseType} the type of functionality invoked in battle
* @returns `true` if invoked with the CUSTOM lapse type; `false` otherwise * @returns `true` if invoked with the ON_GET_HIT lapse type; `false` otherwise
*/ */
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.CUSTOM) { if (lapseType === BattlerTagLapseType.ON_GET_HIT) {
const effectPhase = pokemon.scene.getCurrentPhase(); const phaseData = getMoveEffectPhaseData(pokemon);
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { if (phaseData?.move.hasFlag(MoveFlags.MAKES_CONTACT)) {
const attacker = effectPhase.getPokemon(); phaseData.attacker.trySetStatus(StatusEffect.BURN, true, pokemon);
attacker.trySetStatus(StatusEffect.BURN, true, pokemon);
} }
return true; return true;
} }
@ -170,7 +176,7 @@ export class ShellTrapTag extends BattlerTag {
public activated: boolean; public activated: boolean;
constructor() { constructor() {
super(BattlerTagType.SHELL_TRAP, BattlerTagLapseType.TURN_END, 1); super(BattlerTagType.SHELL_TRAP, [BattlerTagLapseType.TURN_END, BattlerTagLapseType.ON_GET_HIT], 1);
this.activated = false; this.activated = false;
} }
@ -185,7 +191,20 @@ export class ShellTrapTag extends BattlerTag {
* @returns `true` if invoked with the `CUSTOM` lapse type; `false` otherwise * @returns `true` if invoked with the `CUSTOM` lapse type; `false` otherwise
*/ */
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.CUSTOM) { if (lapseType === BattlerTagLapseType.ON_GET_HIT) {
const phaseData = getMoveEffectPhaseData(pokemon);
/* Trap should only be triggered by opponent's Physical moves */
if (phaseData?.move.category === MoveCategory.PHYSICAL && pokemon.isOpponentTo(phaseData.attacker)) {
this.triggerTrap(pokemon);
}
return true;
}
return super.lapse(pokemon, lapseType);
}
private triggerTrap(pokemon: Pokemon) {
const shellTrapPhaseIndex = pokemon.scene.phaseQueue.findIndex( const shellTrapPhaseIndex = pokemon.scene.phaseQueue.findIndex(
phase => phase instanceof MovePhase && phase.pokemon === pokemon phase => phase instanceof MovePhase && phase.pokemon === pokemon
); );
@ -199,9 +218,6 @@ export class ShellTrapTag extends BattlerTag {
} }
this.activated = true; this.activated = true;
return true;
}
return super.lapse(pokemon, lapseType);
} }
} }
@ -1827,7 +1843,6 @@ export class ExposedTag extends BattlerTag {
} }
} }
export function getBattlerTag(tagType: BattlerTagType, turnCount: number, sourceMove: Moves, sourceId: number): BattlerTag { export function getBattlerTag(tagType: BattlerTagType, turnCount: number, sourceMove: Moves, sourceId: number): BattlerTag {
switch (tagType) { switch (tagType) {
case BattlerTagType.RECHARGING: case BattlerTagType.RECHARGING:
@ -1978,3 +1993,22 @@ export function loadBattlerTag(source: BattlerTag | any): BattlerTag {
tag.loadTag(source); tag.loadTag(source);
return tag; return tag;
} }
/**
* Helper function to verify that the current phase is a MoveEffectPhase and provide quick access to commonly used fields
*
* @param pokemon {@linkcode Pokemon} The Pokémon used to access the current phase
* @returns null if current phase is not MoveEffectPhase, otherwise Object containing the {@linkcode MoveEffectPhase}, and its
* corresponding {@linkcode Move} and user {@linkcode Pokemon}
*/
function getMoveEffectPhaseData(pokemon : Pokemon) : {phase : MoveEffectPhase, attacker: Pokemon, move: Move } | null {
const phase = pokemon.scene.getCurrentPhase();
if (phase instanceof MoveEffectPhase) {
return {
phase : phase,
attacker : phase.getPokemon(),
move : phase.move.getMove()
};
}
return null;
}

View File

@ -1866,6 +1866,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.levelExp = this.exp - getLevelTotalExp(this.level, this.species.growthRate); this.levelExp = this.exp - getLevelTotalExp(this.level, this.species.growthRate);
} }
/**
* Compares if 'this' and {@linkcode target} are on the same team.
* @param target the {@linkcode Pokemon} to compare against.
* @returns true if the two pokemon are both player owned or both not, false otherwise
*/
isOpponentTo(target: Pokemon) : boolean {
return this.isPlayer() !== target.isPlayer();
}
getOpponent(targetIndex: integer): Pokemon | null { getOpponent(targetIndex: integer): Pokemon | null {
const ret = this.getOpponents()[targetIndex]; const ret = this.getOpponents()[targetIndex];
if (ret.summonData) { if (ret.summonData) {

View File

@ -4,7 +4,7 @@ import { applyPreAttackAbAttrs, AddSecondStrikeAbAttr, IgnoreMoveEffectsAbAttr,
import { ArenaTagSide, ConditionalProtectTag } from "#app/data/arena-tag.js"; import { ArenaTagSide, ConditionalProtectTag } from "#app/data/arena-tag.js";
import { MoveAnim } from "#app/data/battle-anims.js"; import { MoveAnim } from "#app/data/battle-anims.js";
import { BattlerTagLapseType, ProtectedTag, SemiInvulnerableTag } from "#app/data/battler-tags.js"; import { BattlerTagLapseType, ProtectedTag, SemiInvulnerableTag } from "#app/data/battler-tags.js";
import { MoveTarget, applyMoveAttrs, OverrideMoveEffectAttr, MultiHitAttr, AttackMove, FixedDamageAttr, VariableTargetAttr, MissEffectAttr, MoveFlags, applyFilteredMoveAttrs, MoveAttr, MoveEffectAttr, MoveEffectTrigger, ChargeAttr, MoveCategory, NoEffectAttr, HitsTagAttr } from "#app/data/move.js"; import { MoveTarget, applyMoveAttrs, OverrideMoveEffectAttr, MultiHitAttr, AttackMove, FixedDamageAttr, VariableTargetAttr, MissEffectAttr, MoveFlags, applyFilteredMoveAttrs, MoveAttr, MoveEffectAttr, MoveEffectTrigger, ChargeAttr, NoEffectAttr, HitsTagAttr } from "#app/data/move.js";
import { SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms.js"; import { SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms.js";
import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js";
import { Moves } from "#app/enums/moves.js"; import { Moves } from "#app/enums/moves.js";
@ -258,10 +258,8 @@ export class MoveEffectPhase extends PokemonPhase {
// Apply the target's post-defend ability effects (as long as the target is active or can otherwise apply them) // Apply the target's post-defend ability effects (as long as the target is active or can otherwise apply them)
return Utils.executeIf(!target.isFainted() || target.canApplyAbility(), () => applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move.getMove(), hitResult).then(() => { return Utils.executeIf(!target.isFainted() || target.canApplyAbility(), () => applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move.getMove(), hitResult).then(() => {
// If the invoked move is an enemy attack, apply the enemy's status effect-inflicting tags and tokens // If the invoked move is an enemy attack, apply the enemy's status effect-inflicting tags and tokens
target.lapseTag(BattlerTagType.BEAK_BLAST_CHARGING); target.lapseTags(BattlerTagLapseType.ON_GET_HIT);
if (move.category === MoveCategory.PHYSICAL && user.isPlayer() !== target.isPlayer()) {
target.lapseTag(BattlerTagType.SHELL_TRAP);
}
if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) { if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) {
user.scene.applyShuffledModifiers(this.scene, EnemyAttackStatusEffectChanceModifier, false, target); user.scene.applyShuffledModifiers(this.scene, EnemyAttackStatusEffectChanceModifier, false, target);
} }