[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 c9ec53f945
3 changed files with 62 additions and 26 deletions

View File

@ -4,7 +4,7 @@ import Pokemon, { MoveResult, HitResult } from "../field/pokemon";
import { Stat, getStatName } from "./pokemon-stat";
import { StatusEffect } from "./status-effect";
import * as Utils from "../utils";
import { ChargeAttr, MoveFlags, allMoves } from "./move";
import Move, { ChargeAttr, MoveFlags, allMoves, MoveCategory } from "./move";
import { Type } from "./type";
import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs } from "./ability";
import { TerrainType } from "./terrain";
@ -31,6 +31,7 @@ export enum BattlerTagLapseType {
AFTER_MOVE,
MOVE_EFFECT,
TURN_END,
ON_GET_HIT,
CUSTOM
}
@ -123,6 +124,7 @@ export class RechargingTag extends BattlerTag {
}
}
/**
* BattlerTag representing the "charge phase" of Beak Blast.
* Pokemon with this tag will inflict BURN status on any attacker that makes contact.
@ -130,7 +132,7 @@ export class RechargingTag extends BattlerTag {
*/
export class BeakBlastChargingTag extends BattlerTag {
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 {
@ -146,14 +148,13 @@ export class BeakBlastChargingTag extends BattlerTag {
* 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 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 {
if (lapseType === BattlerTagLapseType.CUSTOM) {
const effectPhase = pokemon.scene.getCurrentPhase();
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) {
const attacker = effectPhase.getPokemon();
attacker.trySetStatus(StatusEffect.BURN, true, pokemon);
if (lapseType === BattlerTagLapseType.ON_GET_HIT) {
const phaseData = getMoveEffectPhaseData(pokemon);
if (phaseData?.move.hasFlag(MoveFlags.MAKES_CONTACT)) {
phaseData.attacker.trySetStatus(StatusEffect.BURN, true, pokemon);
}
return true;
}
@ -170,7 +171,7 @@ export class ShellTrapTag extends BattlerTag {
public activated: boolean;
constructor() {
super(BattlerTagType.SHELL_TRAP, BattlerTagLapseType.TURN_END, 1);
super(BattlerTagType.SHELL_TRAP, [BattlerTagLapseType.TURN_END, BattlerTagLapseType.ON_GET_HIT], 1);
this.activated = false;
}
@ -185,7 +186,20 @@ export class ShellTrapTag extends BattlerTag {
* @returns `true` if invoked with the `CUSTOM` lapse type; `false` otherwise
*/
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(
phase => phase instanceof MovePhase && phase.pokemon === pokemon
);
@ -199,9 +213,6 @@ export class ShellTrapTag extends BattlerTag {
}
this.activated = true;
return true;
}
return super.lapse(pokemon, lapseType);
}
}
@ -1827,7 +1838,6 @@ export class ExposedTag extends BattlerTag {
}
}
export function getBattlerTag(tagType: BattlerTagType, turnCount: number, sourceMove: Moves, sourceId: number): BattlerTag {
switch (tagType) {
case BattlerTagType.RECHARGING:
@ -1978,3 +1988,22 @@ export function loadBattlerTag(source: BattlerTag | any): BattlerTag {
tag.loadTag(source);
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);
}
/**
* 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 {
const ret = this.getOpponents()[targetIndex];
if (ret.summonData) {

View File

@ -4,7 +4,7 @@ import { applyPreAttackAbAttrs, AddSecondStrikeAbAttr, IgnoreMoveEffectsAbAttr,
import { ArenaTagSide, ConditionalProtectTag } from "#app/data/arena-tag.js";
import { MoveAnim } from "#app/data/battle-anims.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 { BattlerTagType } from "#app/enums/battler-tag-type.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)
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
target.lapseTag(BattlerTagType.BEAK_BLAST_CHARGING);
if (move.category === MoveCategory.PHYSICAL && user.isPlayer() !== target.isPlayer()) {
target.lapseTag(BattlerTagType.SHELL_TRAP);
}
target.lapseTags(BattlerTagLapseType.ON_GET_HIT);
if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) {
user.scene.applyShuffledModifiers(this.scene, EnemyAttackStatusEffectChanceModifier, false, target);
}