Cleaned up comments and such

This commit is contained in:
Bertie690 2025-05-27 09:25:34 -04:00
parent db927e8adb
commit 47c45bc63e
3 changed files with 114 additions and 79 deletions

View File

@ -2466,6 +2466,19 @@ export class StatusEffectAttr extends MoveEffectAttr {
return false; return false;
} }
/**
* Wrapper function to attempt to set status of a pokemon.
* Exists to allow super classes to override parameters.
* @param pokemon - The {@linkcode Pokemon} being statused.
* @param source - The {@linkcode Pokemon} doing the statusing.
* @param quiet - Whether to suppress messages for status immunities.
* @returns Whether the status was sucessfully applied.
* @see {@linkcode Pokemon.trySetStatus}
*/
protected doSetStatus(pokemon: Pokemon, source: Pokemon, quiet: boolean): boolean {
return pokemon.trySetStatus(this.effect, true, source, undefined, null, false, quiet)
}
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, false); const moveChance = this.getMoveChance(user, target, move, this.selfTarget, false);
const score = moveChance < 0 ? -10 : Math.floor(moveChance * -0.1); const score = moveChance < 0 ? -10 : Math.floor(moveChance * -0.1);
@ -2473,19 +2486,6 @@ export class StatusEffectAttr extends MoveEffectAttr {
return pokemon.canSetStatus(this.effect, true, false, user) ? score : 0; return pokemon.canSetStatus(this.effect, true, false, user) ? score : 0;
} }
/**
* Wrapper function to attempt to set status of a pokemon.
* Exists to allow super classes to override parameters.
* @param pokemon - The {@linkcode Pokemon} being statused.
* @param user - The {@linkcode Pokemon} doing the statusing.
* @param quiet - Whether to suppress messages for status immunities.
* @returns Whether the status was sucessfully applied.
* @see {@linkcode Pokemon.trySetStatus}
*/
protected doSetStatus(pokemon: Pokemon, user: Pokemon, quiet: boolean): boolean {
return pokemon.trySetStatus(this.effect, true, user, undefined, null, false, quiet)
}
} }
/** /**
@ -2501,13 +2501,16 @@ export class RestAttr extends StatusEffectAttr {
this.duration = duration; this.duration = duration;
} }
// TODO: Add custom text for rest and make `HealAttr` no longer cause status // TODO: Add custom text for rest and make `HealAttr` no longer show the message
protected override doSetStatus(pokemon: Pokemon, user: Pokemon, quiet: boolean): boolean { protected override doSetStatus(pokemon: Pokemon, user: Pokemon, quiet: boolean): boolean {
return pokemon.trySetStatus(this.effect, true, user, this.duration, null, true, quiet) return pokemon.trySetStatus(this.effect, true, user, this.duration, null, true, quiet)
} }
} }
/**
* Attribute to randomly apply one of several statuses to the target.
* Used for {@linkcode Moves.TRI_ATTACK} and {@linkcode Moves.DIRE_CLAW}.
*/
export class MultiStatusEffectAttr extends StatusEffectAttr { export class MultiStatusEffectAttr extends StatusEffectAttr {
public effects: StatusEffect[]; public effects: StatusEffect[];

View File

@ -5406,12 +5406,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
// TODO: Add messages for misty/electric terrain // TODO: Add messages for misty/electric terrain
private queueImmuneMessage(quiet: boolean, effect?: StatusEffect): void { private queueImmuneMessage(quiet: boolean, effect: StatusEffect): void {
if (!effect || quiet) { if (!effect || quiet) {
return; return;
} }
const message = effect && this.status?.effect === effect const message = this.status?.effect === effect
? getStatusEffectOverlapText(effect ?? StatusEffect.NONE, getPokemonNameWithAffix(this)) ? getStatusEffectOverlapText(effect, getPokemonNameWithAffix(this))
: i18next.t("abilityTriggers:moveImmunity", { : i18next.t("abilityTriggers:moveImmunity", {
pokemonNameWithAffix: getPokemonNameWithAffix(this), pokemonNameWithAffix: getPokemonNameWithAffix(this),
}); });
@ -5419,13 +5419,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
/** /**
* Check if a status effect can be applied to this {@linckode Pokemon}. * Check if a status effect can be applied to this {@linkcode Pokemon}.
* *
* @param effect - The {@linkcode StatusEffect} whose applicability is being checked * @param effect - The {@linkcode StatusEffect} whose applicability is being checked.
* @param quiet - Whether to suppress in-battle messages for status checks; default `false` * @param quiet - Whether to suppress in-battle messages for status checks; default `false`.
* @param overrideStatus - Whether to allow overriding the Pokemon's current status with a different one; default `false` * @param overrideStatus - Whether to allow overriding the Pokemon's current status with a different one; default `false`.
* @param sourcePokemon - The {@linkcode Pokemon} applying the status effect to the target * @param sourcePokemon - The {@linkcode Pokemon} applying the status effect to the target,
* @param ignoreField Whether any field effects (weather, terrain, etc.) should be considered * or `null` if the status is applied from a non-Pokemon source (hazards, etc.); default `null`.
* @param ignoreField - Whether to ignore field effects (weather, terrain, etc.) preventing status application;
* default `false`
* @returns Whether {@linkcode effect} can be applied to this Pokemon.
*/ */
// TODO: Review and verify the message order precedence in mainline if multiple status-blocking effects are present at once // TODO: Review and verify the message order precedence in mainline if multiple status-blocking effects are present at once
canSetStatus( canSetStatus(
@ -5436,11 +5439,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
ignoreField = false, ignoreField = false,
): boolean { ): boolean {
if (effect !== StatusEffect.FAINT) { if (effect !== StatusEffect.FAINT) {
// Status-overriding moves (ie Rest) fail if their respective status already exists // Status-overriding moves (ie Rest) fail if their respective status already exists;
// all other moves fail if the target already has _any_ status
if (overrideStatus ? this.status?.effect === effect : this.status) { if (overrideStatus ? this.status?.effect === effect : this.status) {
this.queueImmuneMessage(quiet, effect); this.queueImmuneMessage(quiet, effect);
return false; return false;
} }
if ( if (
this.isGrounded() && this.isGrounded() &&
!ignoreField && !ignoreField &&
@ -5453,13 +5458,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const types = this.getTypes(true, true); const types = this.getTypes(true, true);
// Check for specific immunities for certain statuses /* Whether the target is immune to the specific status being applied. */
let isImmune = false; let isImmune = false;
switch (effect) { switch (effect) {
case StatusEffect.POISON: case StatusEffect.POISON:
case StatusEffect.TOXIC: case StatusEffect.TOXIC:
// Check for type based immunities and/or Corrosion // Check for type based immunities and/or Corrosion from the applier
isImmune = types.some(defType => { isImmune = types.some((defType) => {
if (defType !== PokemonType.POISON && defType !== PokemonType.STEEL) { if (defType !== PokemonType.POISON && defType !== PokemonType.STEEL) {
return false; return false;
} }
@ -5469,40 +5475,41 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
const cancelImmunity = new BooleanHolder(false); const cancelImmunity = new BooleanHolder(false);
applyAbAttrs( applyAbAttrs(
IgnoreTypeStatusEffectImmunityAbAttr, IgnoreTypeStatusEffectImmunityAbAttr,
sourcePokemon, sourcePokemon,
cancelImmunity, cancelImmunity,
false, false,
effect, effect,
defType, defType,
); );
return cancelImmunity.value; return cancelImmunity.value;
}); });
break; break;
case StatusEffect.PARALYSIS: case StatusEffect.PARALYSIS:
isImmune = this.isOfType(PokemonType.ELECTRIC) isImmune = this.isOfType(PokemonType.ELECTRIC);
break; break;
case StatusEffect.SLEEP: case StatusEffect.SLEEP:
isImmune = isImmune =
this.isGrounded() && this.isGrounded() &&
globalScene.arena.terrain?.terrainType === TerrainType.ELECTRIC; globalScene.arena.terrain?.terrainType === TerrainType.ELECTRIC;
break; break;
case StatusEffect.FREEZE: case StatusEffect.FREEZE: {
const weatherType = globalScene.arena.weather?.weatherType;
isImmune = isImmune =
this.isOfType(PokemonType.ICE) || this.isOfType(PokemonType.ICE) ||
!ignoreField && (!ignoreField &&
[WeatherType.SUNNY, WeatherType.HARSH_SUN].includes( (weatherType === WeatherType.SUNNY ||
globalScene.arena.weather?.weatherType ?? WeatherType.NONE, weatherType === WeatherType.HARSH_SUN));
)
break; break;
}
case StatusEffect.BURN: case StatusEffect.BURN:
isImmune = this.isOfType(PokemonType.FIRE) isImmune = this.isOfType(PokemonType.FIRE);
break; break;
} }
if (isImmune) { if (isImmune) {
this.queueImmuneMessage(quiet, effect) this.queueImmuneMessage(quiet, effect);
return false; return false;
} }
@ -5525,8 +5532,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
pokemon, pokemon,
effect, effect,
cancelled, cancelled,
quiet, this, sourcePokemon, quiet,
) this,
sourcePokemon,
);
if (cancelled.value) { if (cancelled.value) {
return false; return false;
} }
@ -5540,7 +5549,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
) { ) {
if (!quiet) { if (!quiet) {
globalScene.queueMessage( globalScene.queueMessage(
i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(this)}) i18next.t("moveTriggers:safeguard", {
targetName: getPokemonNameWithAffix(this),
}),
); );
} }
return false; return false;
@ -5549,12 +5560,27 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return true; return true;
} }
// TODO: Make this take a destructured object as args to condense all these optional args... /**
* Attempt to set this Pokemon's status to the specified condition.
* @param effect - The {@linkcode StatusEffect} to set.
* @param asPhase - Whether to set the status in a new {@linkcode ObtainStatusEffectPhase} or immediately; default `false`.
* If `false`, will not display most messages associated with status setting.
* @param sourcePokemon - The {@linkcode Pokemon} applying the status effect to the target,
* or `null` if the status is applied from a non-Pokemon source (hazards, etc.); default `null`.
* @param sleepTurnsRemaining - The number of turns to set {@linkcode StatusEffect.SLEEP} for;
* defaults to a random number between 2 and 4 and is unused for non-Sleep statuses.
* @param sourceText - The text to show for the source of the status effect, if any;
* defaults to `null` and is unused if `asPhase=false`.
* @param overrideStatus - Whether to allow overriding the Pokemon's current status with a different one; default `false`.
* @param quiet - Whether to suppress in-battle messages for status checks; default `false`.
* @returns Whether the status effect was successfully applied (or a phase for it)
*/
// TODO: Make this take a destructured object for params and make it same order as `canSetStatus`
trySetStatus( trySetStatus(
effect: StatusEffect, effect: StatusEffect,
asPhase = false, asPhase = false,
sourcePokemon: Pokemon | null = null, sourcePokemon: Pokemon | null = null,
turnsRemaining?: number, sleepTurnsRemaining?: number,
sourceText: string | null = null, sourceText: string | null = null,
overrideStatus?: boolean, overrideStatus?: boolean,
quiet = true, quiet = true,
@ -5579,22 +5605,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
} }
if (asPhase) { if (overrideStatus) {
if (overrideStatus) { this.resetStatus(false);
this.resetStatus(false); }
}
if (asPhase) {
globalScene.unshiftPhase( globalScene.unshiftPhase(
new ObtainStatusEffectPhase( new ObtainStatusEffectPhase(
this.getBattlerIndex(), this.getBattlerIndex(),
effect, effect,
turnsRemaining, sleepTurnsRemaining,
sourceText, sourceText,
sourcePokemon, sourcePokemon,
), ),
); );
} else { } else {
this.doSetStatus(effect, turnsRemaining) this.doSetStatus(effect, sleepTurnsRemaining)
} }
return true; return true;
@ -5611,7 +5637,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* Attempt to give the specified Pokemon the given status effect. * Attempt to give the specified Pokemon the given status effect.
* Does **NOT** perform any feasibility checks whatsoever, and should thus never be called directly * Does **NOT** perform any feasibility checks whatsoever, and should thus never be called directly
* unless conditions are known to be met. * unless conditions are known to be met.
* @param effect - StatusEffect.SLEEP * @param effect - {@linkcode StatusEffect.SLEEP}
* @param sleepTurnsRemaining - The number of turns to inflict sleep for; defaults to a random number between 2 and 4. * @param sleepTurnsRemaining - The number of turns to inflict sleep for; defaults to a random number between 2 and 4.
*/ */
doSetStatus(effect: StatusEffect.SLEEP, sleepTurnsRemaining?: number): void; doSetStatus(effect: StatusEffect.SLEEP, sleepTurnsRemaining?: number): void;
@ -5620,7 +5646,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* Does **NOT** perform any feasibility checks whatsoever, and should thus never be called directly * Does **NOT** perform any feasibility checks whatsoever, and should thus never be called directly
* unless conditions are known to be met. * unless conditions are known to be met.
* @param effect - The {@linkcode StatusEffect} to set * @param effect - The {@linkcode StatusEffect} to set
* @param sleepTurnsRemaining - The number of turns to inflict sleep for; defaults to a random number between 2 and 4. * @param sleepTurnsRemaining - The number of turns to inflict sleep for; defaults to a random number between 2 and 4
* and is unused for all non-sleep Statuses.
*/ */
doSetStatus(effect: StatusEffect, sleepTurnsRemaining?: number): void; doSetStatus(effect: StatusEffect, sleepTurnsRemaining?: number): void;
/** /**
@ -5628,13 +5655,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* Does **NOT** perform any feasibility checks whatsoever, and should thus never be called directly * Does **NOT** perform any feasibility checks whatsoever, and should thus never be called directly
* unless conditions are known to be met. * unless conditions are known to be met.
* @param effect - The {@linkcode StatusEffect} to set * @param effect - The {@linkcode StatusEffect} to set
* @param sleepTurnsRemaining - The number of turns to inflict sleep for; defaults to a random number between 2 and 4. * @param sleepTurnsRemaining - The number of turns to inflict sleep for; defaults to a random number between 2 and 4
* and is unused for all non-sleep Statuses.
*/ */
doSetStatus(effect: StatusEffect, sleepTurnsRemaining = this.randBattleSeedIntRange(2, 4)): void { doSetStatus(effect: StatusEffect, sleepTurnsRemaining = effect !== StatusEffect.SLEEP ? 0 : this.randBattleSeedIntRange(2, 4)): void {
if (effect === StatusEffect.SLEEP) { if (effect === StatusEffect.SLEEP) {
this.setFrameRate(4); this.setFrameRate(4);
// If the user is invulnerable, remove their invulnerability when they fall asleep // If the user is semi-invulnerable when put asleep (such as due to Yawm),
// remove their invulnerability and cancel the upcoming move from the queue
const invulnTag = [ const invulnTag = [
BattlerTagType.UNDERGROUND, BattlerTagType.UNDERGROUND,
BattlerTagType.UNDERWATER, BattlerTagType.UNDERWATER,
@ -5651,8 +5680,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.status = new Status(effect, 0, sleepTurnsRemaining); this.status = new Status(effect, 0, sleepTurnsRemaining);
} }
/** /**
* Resets the status of a pokemon. * Resets the status of a pokemon.
* @param revive Whether revive should be cured; defaults to true. * @param revive Whether revive should be cured; defaults to true.

View File

@ -1,60 +1,65 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { BattlerIndex } from "#app/battle"; import type { BattlerIndex } from "#app/battle";
import { CommonBattleAnim, CommonAnim } from "#app/data/battle-anims"; import { CommonBattleAnim, CommonAnim } from "#app/data/battle-anims";
import { getStatusEffectObtainText, getStatusEffectOverlapText } from "#app/data/status-effect"; import { getStatusEffectObtainText } from "#app/data/status-effect";
import { StatusEffect } from "#app/enums/status-effect"; import { StatusEffect } from "#app/enums/status-effect";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
import { SpeciesFormChangeStatusEffectTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeStatusEffectTrigger } from "#app/data/pokemon-forms";
import { applyPostSetStatusAbAttrs, PostSetStatusAbAttr } from "#app/data/abilities/ability"; import { applyPostSetStatusAbAttrs, PostSetStatusAbAttr } from "#app/data/abilities/ability";
import { isNullOrUndefined } from "#app/utils/common";
/** The phase where pokemon obtain status effects. */ /** The phase where pokemon obtain status effects. */
export class ObtainStatusEffectPhase extends PokemonPhase { export class ObtainStatusEffectPhase extends PokemonPhase {
private statusEffect: StatusEffect; private statusEffect: StatusEffect;
private turnsRemaining?: number; private sleepTurnsRemaining?: number;
private sourceText?: string | null; private sourceText?: string | null;
private sourcePokemon?: Pokemon | null; private sourcePokemon?: Pokemon | null;
/**
* Create a new ObtainStatusEffectPhase.
* @param battlerIndex - The {@linkcode BattlerIndex} of the Pokemon obtaining the status effect.
* @param statusEffect - The {@linkcode StatusEffect} being applied.
* @param sleepTurnsRemaining - The number of turns to set {@linkcode StatusEffect.SLEEP} for;
* defaults to a random number between 2 and 4 and is unused for non-Sleep statuses.
* @param sourceText
* @param sourcePokemon
*/
constructor( constructor(
battlerIndex: BattlerIndex, battlerIndex: BattlerIndex,
statusEffect: StatusEffect, statusEffect: StatusEffect,
turnsRemaining?: number, sleepTurnsRemaining?: number,
sourceText?: string | null, sourceText?: string | null,
sourcePokemon?: Pokemon | null, sourcePokemon?: Pokemon | null,
) { ) {
super(battlerIndex); super(battlerIndex);
this.statusEffect = statusEffect; this.statusEffect = statusEffect;
this.turnsRemaining = turnsRemaining; this.sleepTurnsRemaining = sleepTurnsRemaining;
this.sourceText = sourceText; this.sourceText = sourceText;
this.sourcePokemon = sourcePokemon; this.sourcePokemon = sourcePokemon;
} }
start() { start() {
const pokemon = this.getPokemon(); const pokemon = this.getPokemon();
if (pokemon.status?.effect === this.statusEffect) { // No need to override status as the calling `trySetStatus` call will do it for us
globalScene.queueMessage(getStatusEffectOverlapText(this.statusEffect, getPokemonNameWithAffix(pokemon))); // TODO: Consider changing this
this.end();
return;
}
if (!pokemon.canSetStatus(this.statusEffect, false, false, this.sourcePokemon)) { if (!pokemon.canSetStatus(this.statusEffect, false, false, this.sourcePokemon)) {
// status application fails
this.end(); this.end();
return; return;
} }
pokemon.doSetStatus(this.statusEffect, this.turnsRemaining); pokemon.doSetStatus(this.statusEffect, this.sleepTurnsRemaining);
pokemon.updateInfo(true); pokemon.updateInfo(true);
new CommonBattleAnim(CommonAnim.POISON + (this.statusEffect! - 1), pokemon).play(false, () => { new CommonBattleAnim(CommonAnim.POISON + (this.statusEffect! - 1), pokemon).play(false, () => {
globalScene.queueMessage( globalScene.queueMessage(
getStatusEffectObtainText(this.statusEffect, getPokemonNameWithAffix(pokemon), this.sourceText ?? undefined), getStatusEffectObtainText(this.statusEffect, getPokemonNameWithAffix(pokemon), this.sourceText ?? undefined),
); );
if (!isNullOrUndefined(this.statusEffect) && this.statusEffect !== StatusEffect.FAINT) { if (this.statusEffect && this.statusEffect !== StatusEffect.FAINT) {
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeStatusEffectTrigger, true); globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeStatusEffectTrigger, true);
// If the status was applied from a move, ensure abilities are not ignored for follow-up triggers.
// (This is fine as this phase only runs after the MoveEffectPhase concludes and all effects have been applied.)
globalScene.arena.setIgnoreAbilities(false); globalScene.arena.setIgnoreAbilities(false);
applyPostSetStatusAbAttrs(PostSetStatusAbAttr, pokemon, this.statusEffect, this.sourcePokemon); applyPostSetStatusAbAttrs(PostSetStatusAbAttr, pokemon, this.statusEffect, this.sourcePokemon);
} }