mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-06-30 21:42:20 +02:00
Reverted a couple doc changes
This commit is contained in:
parent
c2e7c95620
commit
da6443562b
@ -4899,7 +4899,7 @@ export class BlockRedirectAbAttr extends AbAttr { }
|
||||
* @see {@linkcode apply}
|
||||
*/
|
||||
export class ReduceStatusEffectDurationAbAttr extends AbAttr {
|
||||
private statusEffect: StatusEffect;
|
||||
private statusEffect: StatusEffect;
|
||||
|
||||
constructor(statusEffect: StatusEffect) {
|
||||
super(false);
|
||||
@ -5557,7 +5557,7 @@ class ForceSwitchOutHelper {
|
||||
* - If the Pokémon is still alive (hp > 0), and if so, it leaves the field and a new SwitchPhase is initiated.
|
||||
*/
|
||||
if (switchOutTarget instanceof PlayerPokemon) {
|
||||
if (globalScene.getPlayerParty().every(p => !p.isActive(true))) {
|
||||
if (globalScene.getPlayerParty().filter((p) => p.isAllowedInBattle() && !p.isOnField()).length < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -6901,8 +6901,8 @@ export function initAbilities() {
|
||||
new Ability(Abilities.ANALYTIC, 5)
|
||||
.attr(MovePowerBoostAbAttr, (user, target, move) => {
|
||||
// Boost power if all other Pokemon have already moved (no other moves are slated to execute)
|
||||
const laterMovePhase = globalScene.findPhase((phase) => phase instanceof MovePhase && phase.pokemon.id !== user?.id);
|
||||
return isNullOrUndefined(laterMovePhase);
|
||||
const movePhase = globalScene.findPhase((phase) => phase instanceof MovePhase && phase.pokemon.id !== user?.id);
|
||||
return isNullOrUndefined(movePhase);
|
||||
}, 1.3),
|
||||
new Ability(Abilities.ILLUSION, 5)
|
||||
// The Pokemon generate an illusion if it's available
|
||||
|
@ -51,10 +51,6 @@ export enum BattlerTagLapseType {
|
||||
MOVE,
|
||||
PRE_MOVE,
|
||||
AFTER_MOVE,
|
||||
/**
|
||||
* TODO: Stop treating this like a catch-all "semi invulnerability" tag;
|
||||
* we may want to use this for other stuff later
|
||||
*/
|
||||
MOVE_EFFECT,
|
||||
TURN_END,
|
||||
HIT,
|
||||
@ -65,7 +61,7 @@ export enum BattlerTagLapseType {
|
||||
|
||||
export class BattlerTag {
|
||||
public tagType: BattlerTagType;
|
||||
public lapseTypes: BattlerTagLapseType[]; // TODO: Make this a set
|
||||
public lapseTypes: BattlerTagLapseType[];
|
||||
public turnCount: number;
|
||||
public sourceMove: Moves;
|
||||
public sourceId?: number;
|
||||
@ -98,7 +94,7 @@ export class BattlerTag {
|
||||
onOverlap(_pokemon: Pokemon): void {}
|
||||
|
||||
/**
|
||||
* Trigger and tick down this {@linkcode BattlerTag}'s duration.
|
||||
* Tick down this {@linkcode BattlerTag}'s duration.
|
||||
* @returns `true` if the tag should be kept (`turnCount` > 0`)
|
||||
*/
|
||||
lapse(_pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean {
|
||||
@ -186,21 +182,21 @@ export abstract class MoveRestrictionBattlerTag extends BattlerTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this tag is currently restricting a move's use.
|
||||
* Gets whether this tag is restricting a move.
|
||||
*
|
||||
* @param move - The {@linkcode Moves | move ID} whose usability is being checked.
|
||||
* @param user - The {@linkcode Pokemon} using the move.
|
||||
* @returns Whether the given move is restricted by this tag.
|
||||
* @param move - {@linkcode Moves} ID to check restriction for.
|
||||
* @param user - The {@linkcode Pokemon} involved
|
||||
* @returns `true` if the move is restricted by this tag, otherwise `false`.
|
||||
*/
|
||||
public abstract isMoveRestricted(move: Moves, user?: Pokemon): boolean;
|
||||
|
||||
/**
|
||||
* Check if this tag is restricting a move during target selection.
|
||||
* Returns `false` by default unless overridden by a child class.
|
||||
* @param _move - The {@linkcode Moves | move ID} whose selectability is being checked
|
||||
* @param _user - The {@linkcode Pokemon} using the move.
|
||||
* @param _target - The {@linkcode Pokemon} being targeted
|
||||
* @returns Whether the given move should be unselectable when choosing targets.
|
||||
* Checks if this tag is restricting a move based on a user's decisions during the target selection phase
|
||||
*
|
||||
* @param {Moves} _move {@linkcode Moves} move ID to check restriction for
|
||||
* @param {Pokemon} _user {@linkcode Pokemon} the user of the above move
|
||||
* @param {Pokemon} _target {@linkcode Pokemon} the target of the above move
|
||||
* @returns {boolean} `false` unless overridden by the child tag
|
||||
*/
|
||||
isMoveTargetRestricted(_move: Moves, _user: Pokemon, _target: Pokemon): boolean {
|
||||
return false;
|
||||
@ -346,10 +342,9 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
|
||||
|
||||
/**
|
||||
* @override
|
||||
* Display the text that occurs when a move is interrupted via Disable.
|
||||
* @param pokemon - The {@linkcode Pokemon} attempting to use the restricted move
|
||||
* @param move - The {@linkcode Moves | move ID} of the move being interrupted
|
||||
* @returns The text to display when the given move is interrupted
|
||||
* @param {Pokemon} pokemon {@linkcode Pokemon} attempting to use the restricted move
|
||||
* @param {Moves} move {@linkcode Moves} ID of the move being interrupted
|
||||
* @returns {string} text to display when the move is interrupted
|
||||
*/
|
||||
override interruptedText(pokemon: Pokemon, move: Moves): string {
|
||||
return i18next.t("battle:disableInterruptedMove", {
|
||||
@ -367,6 +362,7 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
|
||||
|
||||
/**
|
||||
* Tag used by Gorilla Tactics to restrict the user to using only one move.
|
||||
* @extends MoveRestrictionBattlerTag
|
||||
*/
|
||||
export class GorillaTacticsTag extends MoveRestrictionBattlerTag {
|
||||
private moveId = Moves.NONE;
|
||||
@ -416,10 +412,11 @@ export class GorillaTacticsTag extends MoveRestrictionBattlerTag {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @override
|
||||
* @param pokemon - The {@linkcode Pokemon} attempting to select a move
|
||||
* @param _move - Unused
|
||||
* @returns The text to display when the move is rendered unselectable
|
||||
* @param {Pokemon} pokemon n/a
|
||||
* @param {Moves} _move {@linkcode Moves} ID of the move being denied
|
||||
* @returns {string} text to display when the move is denied
|
||||
*/
|
||||
override selectionDeniedText(pokemon: Pokemon, _move: Moves): string {
|
||||
return i18next.t("battle:canOnlyUseMove", {
|
||||
@ -640,7 +637,7 @@ class NoRetreatTag extends TrappedTag {
|
||||
*/
|
||||
export class FlinchedTag extends BattlerTag {
|
||||
constructor(sourceMove: Moves) {
|
||||
super(BattlerTagType.FLINCHED, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END], 1, sourceMove);
|
||||
super(BattlerTagType.FLINCHED, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END], 0, sourceMove);
|
||||
}
|
||||
|
||||
onAdd(pokemon: Pokemon): void {
|
||||
@ -1481,6 +1478,10 @@ export class WrapTag extends DamagingTrapTag {
|
||||
}
|
||||
|
||||
export abstract class VortexTrapTag extends DamagingTrapTag {
|
||||
constructor(tagType: BattlerTagType, commonAnim: CommonAnim, turnCount: number, sourceMove: Moves, sourceId: number) {
|
||||
super(tagType, commonAnim, turnCount, sourceMove, sourceId);
|
||||
}
|
||||
|
||||
getTrapMessage(pokemon: Pokemon): string {
|
||||
return i18next.t("battlerTags:vortexOnTrap", {
|
||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||
@ -2748,7 +2749,10 @@ export class HealBlockTag extends MoveRestrictionBattlerTag {
|
||||
* @returns `true` if the move has a TRIAGE_MOVE flag and is a status move
|
||||
*/
|
||||
override isMoveRestricted(move: Moves): boolean {
|
||||
return allMoves[move].hasFlag(MoveFlags.TRIAGE_MOVE) && allMoves[move].category === MoveCategory.STATUS;
|
||||
if (allMoves[move].hasFlag(MoveFlags.TRIAGE_MOVE) && allMoves[move].category === MoveCategory.STATUS) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3422,8 +3426,7 @@ export class PsychoShiftTag extends BattlerTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag associated with {@linkcode Moves.MAGIC_COAT | Magic Coat} that reflects certain status moves directed at the user.
|
||||
* TODO: Move Reflection code out of `move-effect-phase` and into here
|
||||
* Tag associated with the move Magic Coat.
|
||||
*/
|
||||
export class MagicCoatTag extends BattlerTag {
|
||||
constructor() {
|
||||
|
@ -702,10 +702,10 @@ export default class Move implements Localizable {
|
||||
|
||||
/**
|
||||
* Sees if a move has a custom failure text (by looking at each {@linkcode MoveAttr} of this move)
|
||||
* @param user - The {@linkcode Pokemon} using this move
|
||||
* @param target - The {@linkcode Pokemon} targeted by this move
|
||||
* @param move - The {@linkcode Move} being used
|
||||
* @returns A string containing the custom failure text, or `undefined` if no custom text exists.
|
||||
* @param user {@linkcode Pokemon} using the move
|
||||
* @param target {@linkcode Pokemon} target of the move
|
||||
* @param move {@linkcode Move} with this attribute
|
||||
* @returns string of the custom failure text, or `null` if it uses the default text ("But it failed!")
|
||||
*/
|
||||
getFailedText(user: Pokemon, target: Pokemon, move: Move): string | undefined {
|
||||
for (const attr of this.attrs) {
|
||||
@ -1373,8 +1373,8 @@ export class PreMoveMessageAttr extends MoveAttr {
|
||||
|
||||
/**
|
||||
* Attribute for moves that can be conditionally interrupted to be considered to
|
||||
* have failed before their "useMove" message is displayed.
|
||||
* Currently used by {@linkcode Moves.FOCUS_PUNCH}.
|
||||
* have failed before their "useMove" message is displayed. Currently used by
|
||||
* Focus Punch.
|
||||
* @extends MoveAttr
|
||||
*/
|
||||
export class PreUseInterruptAttr extends MoveAttr {
|
||||
@ -1383,40 +1383,38 @@ export class PreUseInterruptAttr extends MoveAttr {
|
||||
protected conditionFunc: MoveConditionFunc;
|
||||
|
||||
/**
|
||||
* Create a new PreUseInterruptAttr.
|
||||
* @param message - Custom failure text to display when the move is interrupted, either as a string or a function producing one.
|
||||
* If ommitted, will display the default failure text upon cancellation.
|
||||
* @param conditionFunc - A {@linkcode MoveConditionFunc} that returns `true` if the move should be canceled.
|
||||
* Create a new MoveInterruptedMessageAttr.
|
||||
* @param message The message to display when the move is interrupted, or a function that formats the message based on the user, target, and move.
|
||||
*/
|
||||
constructor(message: string | undefined | ((user: Pokemon, target: Pokemon, move: Move) => string), conditionFunc: MoveConditionFunc) {
|
||||
constructor(message?: string | ((user: Pokemon, target: Pokemon, move: Move) => string), conditionFunc?: MoveConditionFunc) {
|
||||
super();
|
||||
this.message = message;
|
||||
this.conditionFunc = conditionFunc;
|
||||
this.conditionFunc = conditionFunc ?? (() => true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditionally cancel this pokemon's current move.
|
||||
* @param user - The {@linkcode Pokemon} using this move
|
||||
* @param target - The {@linkcode Pokemon} targeted by this move
|
||||
* @param move - The {@linkcode Move} being used
|
||||
* @returns `true` if the move should be cancelled.
|
||||
* Message to display when a move is interrupted.
|
||||
* @param user {@linkcode Pokemon} using the move
|
||||
* @param target {@linkcode Pokemon} target of the move
|
||||
* @param move {@linkcode Move} with this attribute
|
||||
*/
|
||||
override apply(user: Pokemon, target: Pokemon, move: Move): boolean {
|
||||
return this.conditionFunc(user, target, move);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the text displayed upon this move's interruption.
|
||||
* @param user - The {@linkcode Pokemon} using this move
|
||||
* @param target - The {@linkcode Pokemon} targeted by this move
|
||||
* @param move - The {@linkcode Move} being used
|
||||
* @returns A string containing the custom failure text, or `undefined` if no custom text exists.
|
||||
* Message to display when a move is interrupted.
|
||||
* @param user {@linkcode Pokemon} using the move
|
||||
* @param target {@linkcode Pokemon} target of the move
|
||||
* @param move {@linkcode Move} with this attribute
|
||||
*/
|
||||
override getFailedText(user: Pokemon, target: Pokemon, move: Move): string | undefined {
|
||||
if (this.conditionFunc(user, target, move)) {
|
||||
return typeof this.message !== "function"
|
||||
? this.message
|
||||
if (this.message && this.conditionFunc(user, target, move)) {
|
||||
const message =
|
||||
typeof this.message === "string"
|
||||
? (this.message as string)
|
||||
: this.message(user, target, move);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3059,17 +3057,7 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr {
|
||||
this.chargeText = chargeText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the delayed attack, either setting it up or triggering the attack.
|
||||
* @param user - The {@linkcode Pokemon} using the move
|
||||
* @param target - The {@linkcode Pokemon} being targeted
|
||||
* @param move - The {@linkcode Move} being used
|
||||
* @param args -
|
||||
* `[0]` - {@linkcode BooleanHolder} containing whether the move was overriden
|
||||
* `[1]` - Whether the move is supposed to set up a delayed attack (`true`) or activate (`false`)
|
||||
* @returns always `true`
|
||||
*/
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: [BooleanHolder, boolean]): boolean {
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
// Edge case for the move applied on a pokemon that has fainted
|
||||
if (!target) {
|
||||
return true;
|
||||
@ -3105,9 +3093,9 @@ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr {
|
||||
/**
|
||||
* If the user's ally is set to use a different move with this attribute,
|
||||
* defer this move's effects for a combined move on the ally's turn.
|
||||
* @param user - The {@linkcode Pokemon} using the move
|
||||
* @param target - Unused
|
||||
* @param move - The {@linkcode Move} being used
|
||||
* @param user the {@linkcode Pokemon} using this move
|
||||
* @param target n/a
|
||||
* @param move the {@linkcode Move} being used
|
||||
* @param args
|
||||
* - [0] a {@linkcode BooleanHolder} indicating whether the move's base
|
||||
* effects should be overridden this turn.
|
||||
@ -3696,7 +3684,7 @@ export class LessPPMorePowerAttr extends VariablePowerAttr {
|
||||
const ppMax = move.pp;
|
||||
const ppUsed = user.moveset.find((m) => m.moveId === move.id)?.ppUsed ?? 0;
|
||||
|
||||
let ppRemains = ppMax - ppUsed;
|
||||
let ppRemains = ppMax - ppUsed;
|
||||
/** Reduce to 0 to avoid negative numbers if user has 1PP before attack and target has Ability.PRESSURE */
|
||||
if (ppRemains < 0) {
|
||||
ppRemains = 0;
|
||||
@ -3814,31 +3802,27 @@ export class DoublePowerChanceAttr extends VariablePowerAttr {
|
||||
|
||||
export abstract class ConsecutiveUsePowerMultiplierAttr extends MovePowerMultiplierAttr {
|
||||
constructor(limit: number, resetOnFail: boolean, resetOnLimit?: boolean, ...comboMoves: Moves[]) {
|
||||
super((user: Pokemon, _target: Pokemon, move: Move): number => {
|
||||
const moveHistory = user.getLastXMoves(-1).slice(1, limit+1); // don't count the first history entry (ie the current move)
|
||||
super((user: Pokemon, target: Pokemon, move: Move): number => {
|
||||
const moveHistory = user.getLastXMoves(limit + 1).slice(1);
|
||||
|
||||
let count = 1;
|
||||
let count = 0;
|
||||
let turnMove: TurnMove | undefined;
|
||||
|
||||
// TODO: Confirm whether mirror moving an echoed voice counts for and/or resets a boost
|
||||
for (const tm of moveHistory) {
|
||||
if (
|
||||
!(tm.move === move.id || comboMoves.includes(tm.move))
|
||||
|| (resetOnFail && tm.result !== MoveResult.SUCCESS)
|
||||
while (
|
||||
(
|
||||
(turnMove = moveHistory.shift())?.move === move.id
|
||||
|| (comboMoves.length && comboMoves.includes(turnMove?.move ?? Moves.NONE))
|
||||
)
|
||||
&& (!resetOnFail || turnMove?.result === MoveResult.SUCCESS)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (count < limit - 1) {
|
||||
if (count < (limit - 1)) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (resetOnLimit) {
|
||||
} else if (resetOnLimit) {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return this.getMultiplier(count);
|
||||
});
|
||||
@ -4017,7 +4001,7 @@ export class HpPowerAttr extends VariablePowerAttr {
|
||||
|
||||
/**
|
||||
* Attribute used for moves whose base power scales with the opponent's HP
|
||||
* Used for {@linkcode Moves.CRUSH_GRIP}, {@linkcode Moves.WRING_OUT}, and {@linkcode Moves.HARD_PRESS}
|
||||
* Used for Crush Grip, Wring Out, and Hard Press
|
||||
* maxBasePower 100 for Hard Press, 120 for others
|
||||
*/
|
||||
export class OpponentHighHpPowerAttr extends VariablePowerAttr {
|
||||
@ -4333,7 +4317,6 @@ const hasStockpileStacksCondition: MoveConditionFunc = (user) => {
|
||||
return !!hasStockpilingTag && hasStockpilingTag.stockpiledCount > 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Attribute used for multi-hit moves that increase power in increments of the
|
||||
* move's base power for each hit, namely Triple Kick and Triple Axel.
|
||||
@ -5434,17 +5417,11 @@ export class FrenzyAttr extends MoveEffectAttr {
|
||||
}
|
||||
|
||||
// TODO: Disable if used via dancer
|
||||
|
||||
// TODO: Add support for moves that don't add the frenzy tag (Uproar, Rollout, etc.)
|
||||
|
||||
// If frenzy is not in effect and we don't have anything queued up,
|
||||
// add 1-2 extra instances of the move to the move queue.
|
||||
// If frenzy is already in effect, tick down the tag.
|
||||
if (!user.getTag(BattlerTagType.FRENZY) && user.getMoveQueue().length === 0) {
|
||||
const turnCount = user.randSeedIntRange(1, 2); // excludes initial use
|
||||
for (let i = 0; i < turnCount; i++) {
|
||||
user.pushMoveQueue({ move: move.id, targets: [ target.getBattlerIndex() ], useType: MoveUseType.IGNORE_PP });
|
||||
}
|
||||
if (!user.getTag(BattlerTagType.FRENZY) && !user.getMoveQueue().length) {
|
||||
const turnCount = user.randSeedIntRange(1, 2);
|
||||
new Array(turnCount).fill(null).map(() => user.getMoveQueue().push({ move: move.id, targets: [ target.getBattlerIndex() ], ignorePP: true }));
|
||||
user.addTag(BattlerTagType.FRENZY, turnCount, move.id, user.id);
|
||||
} else {
|
||||
applyMoveAttrs(AddBattlerTagAttr, user, target, move, args);
|
||||
@ -5817,24 +5794,23 @@ export class ProtectAttr extends AddBattlerTagAttr {
|
||||
super(tagType, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition to fail a protect usage based on random chance.
|
||||
* Chance starts at 100% and is thirded for each prior successful proctect usage.
|
||||
* @returns a function that fails the function if its proc chance roll fails
|
||||
*/
|
||||
getCondition(): MoveConditionFunc {
|
||||
return ((user, target, move): boolean => {
|
||||
const lastMoves = user.getLastXMoves(-1)
|
||||
let timesUsed = 0;
|
||||
const moveHistory = user.getLastXMoves();
|
||||
let turnMove: TurnMove | undefined;
|
||||
|
||||
let threshold = 1;
|
||||
for (const tm of lastMoves) {
|
||||
if (!allMoves[tm.move].hasAttr(ProtectAttr) || tm.result !== MoveResult.SUCCESS) {
|
||||
while (moveHistory.length) {
|
||||
turnMove = moveHistory.shift();
|
||||
if (!allMoves[turnMove?.move ?? Moves.NONE].hasAttr(ProtectAttr) || turnMove?.result !== MoveResult.SUCCESS) {
|
||||
break;
|
||||
}
|
||||
threshold *= 3;
|
||||
timesUsed++;
|
||||
}
|
||||
|
||||
return threshold === 1 || user.randSeedInt(threshold) === 0;
|
||||
if (timesUsed) {
|
||||
return !user.randSeedInt(Math.pow(3, timesUsed));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -7334,14 +7310,13 @@ export class SketchAttr extends MoveEffectAttr {
|
||||
constructor() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* User copies the opponent's last used move, if possible.
|
||||
* @param user - The {@linkcode Pokemon} using the move
|
||||
* @param target - The {@linkcode Pokemon} being targeted by the move
|
||||
* @param move - The {@linkcoed Move} being used
|
||||
* @param args - Unused
|
||||
* @returns Whether a move was successfully learnt
|
||||
* User copies the opponent's last used move, if possible
|
||||
* @param {Pokemon} user Pokemon that used the move and will replace Sketch with the copied move
|
||||
* @param {Pokemon} target Pokemon that the user wants to copy a move from
|
||||
* @param {Move} move Move being used
|
||||
* @param {any[]} args Unused
|
||||
* @returns {boolean} true if the function succeeds, otherwise false
|
||||
*/
|
||||
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
@ -7881,6 +7856,7 @@ export class AfterYouAttr extends MoveEffectAttr {
|
||||
/**
|
||||
* Move effect to force the target to move last, ignoring priority.
|
||||
* If applied to multiple targets, they move in speed order after all other moves.
|
||||
* @extends MoveEffectAttr
|
||||
*/
|
||||
export class ForceLastAttr extends MoveEffectAttr {
|
||||
/**
|
||||
@ -7927,7 +7903,7 @@ const phaseForcedSlower = (phase: MovePhase, target: Pokemon, trickRoom: boolean
|
||||
let slower: boolean;
|
||||
// quashed pokemon still have speed ties
|
||||
if (phase.pokemon.getEffectiveStat(Stat.SPD) === target.getEffectiveStat(Stat.SPD)) {
|
||||
slower = !target.randSeedInt(2);
|
||||
slower = target.randSeedInt(2) === 0;
|
||||
} else {
|
||||
slower = !trickRoom ? phase.pokemon.getEffectiveStat(Stat.SPD) < target.getEffectiveStat(Stat.SPD) : phase.pokemon.getEffectiveStat(Stat.SPD) > target.getEffectiveStat(Stat.SPD);
|
||||
}
|
||||
|
@ -642,7 +642,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
/**
|
||||
* Checks if a pokemon is fainted (ie: its `hp <= 0`).
|
||||
* It's usually better to call {@linkcode isAllowedInBattle()}
|
||||
* @param checkStatus - Whether to also check the pokemon's status for {@linkcode StatusEffect.FAINT}; default `false`
|
||||
* @param checkStatus `true` to also check that the pokemon's status is {@linkcode StatusEffect.FAINT}
|
||||
* @returns `true` if the pokemon is fainted
|
||||
*/
|
||||
public isFainted(checkStatus = false): boolean {
|
||||
@ -3256,9 +3256,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* If it rolls shiny, or if it's already shiny, also sets a random variant and give the Pokemon the associated luck.
|
||||
*
|
||||
* The base shiny odds are {@linkcode BASE_SHINY_CHANCE} / `65536`
|
||||
* @param thresholdOverride - number that is divided by `2^16` (`65536`) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm)
|
||||
* @param applyModifiersToOverride - Whether to apply Shiny Charm and event modifiers to {@linkcode thresholdOverride}.
|
||||
* Does nothing if {@linkcode thresholdOverride} is not set.
|
||||
* @param thresholdOverride number that is divided by `2^16` (`65536`) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm)
|
||||
* @param applyModifiersToOverride If {@linkcode thresholdOverride} is set and this is true, will apply Shiny Charm and event modifiers to {@linkcode thresholdOverride}
|
||||
* @returns `true` if the Pokemon has been set as a shiny, `false` otherwise
|
||||
*/
|
||||
public trySetShinySeed(
|
||||
@ -3812,7 +3811,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
ui =>
|
||||
ui instanceof BattleInfo &&
|
||||
(ui as BattleInfo) instanceof PlayerBattleInfo === this.isPlayer(),
|
||||
)[0] as Phaser.GameObjects.GameObject | undefined;
|
||||
)
|
||||
.find(() => true);
|
||||
if (!otherBattleInfo || !this.getFieldIndex()) {
|
||||
globalScene.fieldUI.sendToBack(this.battleInfo);
|
||||
globalScene.sendTextToBack(); // Push the top right text objects behind everything else
|
||||
@ -5140,8 +5140,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
/**
|
||||
* Returns a list of the most recent move entries in this Pokemon's move history.
|
||||
* The retrieved move entries are sorted in order from NEWEST to OLDEST.
|
||||
* @param moveCount The number of move entries to retrieve.\
|
||||
* If negative, retrieves the Pokemon's entire move history (equivalent to reversing the output of {@linkcode getMoveHistory()}).
|
||||
* @param moveCount The number of move entries to retrieve.
|
||||
* If negative, retrieve the Pokemon's entire move history (equivalent to reversing the output of {@linkcode getMoveHistory()}).
|
||||
* Default is `1`.
|
||||
* @returns A list of {@linkcode TurnMove}, as specified above.
|
||||
*/
|
||||
@ -5660,19 +5660,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
||||
if (effect === StatusEffect.SLEEP) {
|
||||
sleepTurnsRemaining = new NumberHolder(this.randSeedIntRange(2, 4));
|
||||
|
||||
this.setFrameRate(4);
|
||||
|
||||
// If the user is invulnerable, remove their invulnerability when they fall asleep
|
||||
// and remove the upcoming attack from the move queue.
|
||||
const tag = [
|
||||
// If the user is invulnerable, lets remove their invulnerability when they fall asleep
|
||||
const invulnerableTags = [
|
||||
BattlerTagType.UNDERGROUND,
|
||||
BattlerTagType.UNDERWATER,
|
||||
BattlerTagType.HIDDEN,
|
||||
BattlerTagType.FLYING,
|
||||
].find(t => this.getTag(t));
|
||||
];
|
||||
|
||||
const tag = invulnerableTags.find(t => this.getTag(t));
|
||||
|
||||
if (tag) {
|
||||
this.removeTag(tag);
|
||||
this.getMoveQueue().shift();
|
||||
this.getMoveQueue().pop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -8137,10 +8140,10 @@ export class PokemonMove {
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments this move's {@linkcode ppUsed} variable (up to a maximum of {@link getMovePp}).
|
||||
* @param count - Amount of PP to consume; default `1`
|
||||
* Sets {@link ppUsed} for this move and ensures the value does not exceed {@link getMovePp}
|
||||
* @param count Amount of PP to use
|
||||
*/
|
||||
usePp(count = 1) {
|
||||
usePp(count: number = 1) {
|
||||
this.ppUsed = Math.min(this.ppUsed + count, this.getMovePp());
|
||||
}
|
||||
|
||||
|
@ -135,11 +135,11 @@ export class MoveEffectPhase extends PokemonPhase {
|
||||
* Compute targets and the results of hit checks of the invoked move against all targets,
|
||||
* organized by battler index.
|
||||
*
|
||||
* **This is *not* a pure function** and has the following side effects:
|
||||
* - Sets `this.hitChecks` to the results of the hit checks against each target
|
||||
* - Sets success/failure of `this.moveHistoryEntry` based on the hit check results
|
||||
* - Sets `user.turnData.hitCount` and `user.turnData.hitsLeft` to 1 if the move
|
||||
* was unsuccessful against all targets (effectively canceling it)
|
||||
* **This is *not* a pure function**; it has the following side effects
|
||||
* - `this.hitChecks` - The results of the hit checks against each target
|
||||
* - `this.moveHistoryEntry` - Sets success or failure based on the hit check results
|
||||
* - user.turnData.hitCount and user.turnData.hitsLeft - Both set to 1 if the
|
||||
* move was unsuccessful against all targets
|
||||
*
|
||||
* @returns The targets of the invoked move
|
||||
* @see {@linkcode hitCheck}
|
||||
@ -205,9 +205,9 @@ export class MoveEffectPhase extends PokemonPhase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the move to each of its resolved targets.
|
||||
* Apply the move to each of the resolved targets.
|
||||
* @param targets - The resolved set of targets of the move
|
||||
* @throws - Error if there was an unexpected hit check result
|
||||
* @throws Error if there was an unexpected hit check result
|
||||
*/
|
||||
private applyToTargets(user: Pokemon, targets: Pokemon[]): void {
|
||||
for (const [i, target] of targets.entries()) {
|
||||
@ -229,7 +229,6 @@ export class MoveEffectPhase extends PokemonPhase {
|
||||
case HitCheckResult.NO_EFFECT_NO_MESSAGE:
|
||||
case HitCheckResult.PROTECTED:
|
||||
case HitCheckResult.TARGET_NOT_ON_FIELD:
|
||||
// Apply effects for ineffective moves (e.g. High Jump Kick crash dmg)
|
||||
applyMoveAttrs(NoEffectAttr, user, target, this.move);
|
||||
break;
|
||||
case HitCheckResult.MISS:
|
||||
@ -643,19 +642,22 @@ export class MoveEffectPhase extends PokemonPhase {
|
||||
if (!user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
// No Guard
|
||||
case user.hasAbilityWithAttr(AlwaysHitAbAttr) || target.hasAbilityWithAttr(AlwaysHitAbAttr):
|
||||
// Toxic as poison type
|
||||
case this.move.hasAttr(ToxicAccuracyAttr) && user.isOfType(PokemonType.POISON):
|
||||
// Lock On/Mind Reader
|
||||
case !!user.getTag(BattlerTagType.IGNORE_ACCURACY):
|
||||
// Spikes and company
|
||||
case isFieldTargeted(this.move):
|
||||
if (user.hasAbilityWithAttr(AlwaysHitAbAttr) || target.hasAbilityWithAttr(AlwaysHitAbAttr)) {
|
||||
return true;
|
||||
}
|
||||
if (this.move.hasAttr(ToxicAccuracyAttr) && user.isOfType(PokemonType.POISON)) {
|
||||
return true;
|
||||
}
|
||||
// TODO: Fix lock on / mind reader check.
|
||||
if (
|
||||
user.getTag(BattlerTagType.IGNORE_ACCURACY) &&
|
||||
(user.getLastXMoves().find(() => true)?.targets || []).indexOf(target.getBattlerIndex()) !== -1
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (isFieldTargeted(this.move)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,16 +27,16 @@ export class TurnStartPhase extends FieldPhase {
|
||||
/**
|
||||
* This orders the active Pokemon on the field by speed into an BattlerIndex array and returns that array.
|
||||
* It also checks for Trick Room and reverses the array if it is present.
|
||||
* @returns An array of {@linkcode BattlerIndex}es containing all on-field pokemon sorted in speed order.
|
||||
* @returns {@linkcode BattlerIndex[]} the battle indices of all pokemon on the field ordered by speed
|
||||
*/
|
||||
getSpeedOrder(): BattlerIndex[] {
|
||||
const playerField = globalScene.getPlayerField().filter(p => p.isActive()) as Pokemon[];
|
||||
const enemyField = globalScene.getEnemyField().filter(p => p.isActive()) as Pokemon[];
|
||||
|
||||
// Shuffle the list before sorting so speed ties produce random results
|
||||
// This is seeded with the current turn to prevent an inconsistency with variable turn order
|
||||
// based on how long since you last reloaded
|
||||
// We shuffle the list before sorting so speed ties produce random results
|
||||
let orderedTargets: Pokemon[] = playerField.concat(enemyField);
|
||||
// We seed it with the current turn to prevent an inconsistency where it
|
||||
// was varying based on how long since you last reloaded
|
||||
globalScene.executeWithSeedOffset(
|
||||
() => {
|
||||
orderedTargets = randSeedShuffle(orderedTargets);
|
||||
@ -45,11 +45,11 @@ export class TurnStartPhase extends FieldPhase {
|
||||
globalScene.waveSeed,
|
||||
);
|
||||
|
||||
// Check for Trick Room and reverse sort order if active.
|
||||
// Notably, Pokerogue does NOT have the "outspeed trick room" glitch at >1809 spd.
|
||||
// Next, a check for Trick Room is applied to determine sort order.
|
||||
const speedReversed = new BooleanHolder(false);
|
||||
globalScene.arena.applyTags(TrickRoomTag, false, speedReversed);
|
||||
|
||||
// Adjust the sort function based on whether Trick Room is active.
|
||||
orderedTargets.sort((a: Pokemon, b: Pokemon) => {
|
||||
const aSpeed = a?.getEffectiveStat(Stat.SPD) ?? 0;
|
||||
const bSpeed = b?.getEffectiveStat(Stat.SPD) ?? 0;
|
||||
@ -120,8 +120,7 @@ export class TurnStartPhase extends FieldPhase {
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no difference between the move's calculated priorities,
|
||||
// check for differences in battlerBypassSpeed and returns the result.
|
||||
// If there is no difference between the move's calculated priorities, the game checks for differences in battlerBypassSpeed and returns the result.
|
||||
if (battlerBypassSpeed[a].value !== battlerBypassSpeed[b].value) {
|
||||
return battlerBypassSpeed[a].value ? -1 : 1;
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
|
||||
function confirmSwitch(): void {
|
||||
const [pokemon1, pokemon2] = game.scene.getPlayerParty();
|
||||
|
||||
expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase");
|
||||
|
||||
expect(pokemon1.species.speciesId).not.toBe(Species.WIMPOD);
|
||||
@ -55,34 +56,17 @@ describe("Abilities - Wimp Out", () => {
|
||||
|
||||
function confirmNoSwitch(): void {
|
||||
const [pokemon1, pokemon2] = game.scene.getPlayerParty();
|
||||
|
||||
expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase");
|
||||
|
||||
expect(pokemon2.species.speciesId).not.toBe(Species.WIMPOD);
|
||||
|
||||
expect(pokemon1.species.speciesId).toBe(Species.WIMPOD);
|
||||
expect(pokemon1.isFainted()).toBe(false);
|
||||
expect(pokemon1.getHpRatio()).toBeLessThan(0.5);
|
||||
|
||||
expect(pokemon2.species.speciesId).not.toBe(Species.WIMPOD);
|
||||
}
|
||||
|
||||
it("should switch user out when falling below 50% HP, cancelling any pending moves", async () => {
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
const wimpod = game.scene.getPlayerPokemon()!;
|
||||
wimpod.hp *= 0.51;
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||
await game.phaseInterceptor.to("DamageAnimPhase", false);
|
||||
game.phaseInterceptor.clearLogs();
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
confirmSwitch();
|
||||
expect(wimpod.turnData.acted).toBe(false);
|
||||
expect(game.phaseInterceptor.log).not.toContain("MoveEffectPhase");
|
||||
});
|
||||
|
||||
it("should trigger regenerator passive when switching out", async () => {
|
||||
it("triggers regenerator passive single time when switching out with wimp out", async () => {
|
||||
game.override.passiveAbility(Abilities.REGENERATOR).startingLevel(5).enemyLevel(100);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
@ -96,7 +80,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
confirmSwitch();
|
||||
});
|
||||
|
||||
it("should cause wild pokemon to flee", async () => {
|
||||
it("It makes wild pokemon flee if triggered", async () => {
|
||||
game.override.enemyAbility(Abilities.WIMP_OUT);
|
||||
await game.classicMode.startBattle([Species.GOLISOPOD, Species.TYRUNT]);
|
||||
|
||||
@ -106,11 +90,12 @@ describe("Abilities - Wimp Out", () => {
|
||||
game.move.select(Moves.FALSE_SWIPE);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemyPokemon.visible).toBe(false);
|
||||
expect(enemyPokemon.switchOutStatus).toBe(true);
|
||||
const isVisible = enemyPokemon.visible;
|
||||
const hasFled = enemyPokemon.switchOutStatus;
|
||||
expect(!isVisible && hasFled).toBe(true);
|
||||
});
|
||||
|
||||
it("should not trigger when HP is already below half", async () => {
|
||||
it("Does not trigger when HP already below half", async () => {
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
const wimpod = game.scene.getPlayerPokemon()!;
|
||||
wimpod.hp = 5;
|
||||
@ -122,7 +107,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
confirmNoSwitch();
|
||||
});
|
||||
|
||||
it("should bypass trapping moves and abilities", async () => {
|
||||
it("Trapping moves do not prevent Wimp Out from activating.", async () => {
|
||||
game.override.enemyMoveset([Moves.SPIRIT_SHACKLE]).startingLevel(53).enemyLevel(45);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
@ -137,7 +122,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
confirmSwitch();
|
||||
});
|
||||
|
||||
it("should block switching from U-Turn on activation", async () => {
|
||||
it("If this Ability activates due to being hit by U-turn or Volt Switch, the user of that move will not be switched out.", async () => {
|
||||
game.override.startingLevel(95).enemyMoveset([Moves.U_TURN]);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
@ -151,7 +136,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
confirmSwitch();
|
||||
});
|
||||
|
||||
it("should not block switching from U-Turn on failed activation", async () => {
|
||||
it("If this Ability does not activate due to being hit by U-turn or Volt Switch, the user of that move will be switched out.", async () => {
|
||||
game.override.startingLevel(190).startingWave(8).enemyMoveset([Moves.U_TURN]);
|
||||
await game.classicMode.startBattle([Species.GOLISOPOD, Species.TYRUNT]);
|
||||
const RIVAL_NINJASK1 = game.scene.getEnemyPokemon()?.id;
|
||||
@ -160,7 +145,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
expect(game.scene.getEnemyPokemon()?.id !== RIVAL_NINJASK1);
|
||||
});
|
||||
|
||||
it("Dragon Tail and Circle Throw switch out Pokémon before the Ability activates", async () => {
|
||||
it("Dragon Tail and Circle Throw switch out Pokémon before the Ability activates.", async () => {
|
||||
game.override.startingLevel(69).enemyMoveset([Moves.DRAGON_TAIL]);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
@ -177,7 +162,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
expect(game.scene.getPlayerPokemon()!.species.speciesId).not.toBe(Species.WIMPOD);
|
||||
});
|
||||
|
||||
it("should trigger from recoil damage", async () => {
|
||||
it("triggers when recoil damage is taken", async () => {
|
||||
game.override.moveset([Moves.HEAD_SMASH]).enemyMoveset([Moves.SPLASH]);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
@ -188,7 +173,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
confirmSwitch();
|
||||
});
|
||||
|
||||
it("should not activate when the Pokémon cuts its own HP", async () => {
|
||||
it("It does not activate when the Pokémon cuts its own HP", async () => {
|
||||
game.override.moveset([Moves.SUBSTITUTE]).enemyMoveset([Moves.SPLASH]);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
@ -201,19 +186,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
confirmNoSwitch();
|
||||
});
|
||||
|
||||
it("should not trigger from Sheer Force-boosted moves", async () => {
|
||||
game.override.enemyAbility(Abilities.SHEER_FORCE).enemyMoveset(Moves.SLUDGE_BOMB).startingLevel(95);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
game.scene.getPlayerPokemon()!.hp *= 0.51;
|
||||
|
||||
game.move.select(Moves.ENDURE);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
confirmNoSwitch();
|
||||
});
|
||||
|
||||
it("should not trigger while neutralized", async () => {
|
||||
it("Does not trigger when neutralized", async () => {
|
||||
game.override.enemyAbility(Abilities.NEUTRALIZING_GAS).startingLevel(5);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
@ -250,14 +223,8 @@ describe("Abilities - Wimp Out", () => {
|
||||
},
|
||||
);
|
||||
|
||||
// TODO: Condense into it.eaches
|
||||
describe("Post Turn Damage Checks - ", () => {
|
||||
beforeEach(() => {
|
||||
game.override.enemyMoveset(Moves.SPLASH);
|
||||
});
|
||||
|
||||
it("Wimp Out will activate due to weather damage", async () => {
|
||||
game.override.weather(WeatherType.HAIL);
|
||||
game.override.weather(WeatherType.HAIL).enemyMoveset([Moves.SPLASH]);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
game.scene.getPlayerPokemon()!.hp *= 0.51;
|
||||
@ -269,12 +236,37 @@ describe("Abilities - Wimp Out", () => {
|
||||
confirmSwitch();
|
||||
});
|
||||
|
||||
it("Wimp Out will activate due to post turn status damage", async () => {
|
||||
game.override.statusEffect(StatusEffect.POISON);
|
||||
it("Does not trigger when enemy has sheer force", async () => {
|
||||
game.override.enemyAbility(Abilities.SHEER_FORCE).enemyMoveset(Moves.SLUDGE_BOMB).startingLevel(95);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
game.scene.getPlayerPokemon()!.hp *= 0.51;
|
||||
|
||||
game.move.select(Moves.ENDURE);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
confirmNoSwitch();
|
||||
});
|
||||
|
||||
it("Wimp Out will activate due to post turn status damage", async () => {
|
||||
game.override.statusEffect(StatusEffect.POISON).enemyMoveset([Moves.SPLASH]);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
game.scene.getPlayerPokemon()!.hp *= 0.51;
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.toNextTurn();
|
||||
|
||||
confirmSwitch();
|
||||
});
|
||||
|
||||
it("Wimp Out will activate due to bad dreams", async () => {
|
||||
game.override.statusEffect(StatusEffect.SLEEP).enemyAbility(Abilities.BAD_DREAMS);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
game.scene.getPlayerPokemon()!.hp *= 0.52;
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.toNextTurn();
|
||||
@ -330,6 +322,45 @@ describe("Abilities - Wimp Out", () => {
|
||||
confirmSwitch();
|
||||
});
|
||||
|
||||
it("Magic Guard passive should not allow indirect damage to trigger Wimp Out", async () => {
|
||||
game.scene.arena.addTag(ArenaTagType.STEALTH_ROCK, 1, Moves.STEALTH_ROCK, 0, ArenaTagSide.ENEMY);
|
||||
game.scene.arena.addTag(ArenaTagType.SPIKES, 1, Moves.SPIKES, 0, ArenaTagSide.ENEMY);
|
||||
game.override
|
||||
.passiveAbility(Abilities.MAGIC_GUARD)
|
||||
.enemyMoveset([Moves.LEECH_SEED])
|
||||
.weather(WeatherType.HAIL)
|
||||
.statusEffect(StatusEffect.POISON);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
game.scene.getPlayerPokemon()!.hp *= 0.51;
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(game.scene.getPlayerParty()[0].getHpRatio()).toEqual(0.51);
|
||||
expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase");
|
||||
expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.WIMPOD);
|
||||
});
|
||||
|
||||
it("Wimp Out activating should not cancel a double battle", async () => {
|
||||
game.override.battleStyle("double").enemyAbility(Abilities.WIMP_OUT).enemyMoveset([Moves.SPLASH]).enemyLevel(1);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
const enemyLeadPokemon = game.scene.getEnemyParty()[0];
|
||||
const enemySecPokemon = game.scene.getEnemyParty()[1];
|
||||
|
||||
game.move.select(Moves.FALSE_SWIPE, 0, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.SPLASH, 1);
|
||||
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
const isVisibleLead = enemyLeadPokemon.visible;
|
||||
const hasFledLead = enemyLeadPokemon.switchOutStatus;
|
||||
const isVisibleSec = enemySecPokemon.visible;
|
||||
const hasFledSec = enemySecPokemon.switchOutStatus;
|
||||
expect(!isVisibleLead && hasFledLead && isVisibleSec && !hasFledSec).toBe(true);
|
||||
expect(enemyLeadPokemon.hp).toBeLessThan(enemyLeadPokemon.getMaxHp());
|
||||
expect(enemySecPokemon.hp).toEqual(enemySecPokemon.getMaxHp());
|
||||
});
|
||||
|
||||
it("Wimp Out will activate due to aftermath", async () => {
|
||||
game.override
|
||||
.moveset([Moves.THUNDER_PUNCH])
|
||||
@ -347,19 +378,6 @@ describe("Abilities - Wimp Out", () => {
|
||||
confirmSwitch();
|
||||
});
|
||||
|
||||
it("Wimp Out will activate due to bad dreams", async () => {
|
||||
game.override.statusEffect(StatusEffect.SLEEP).enemyAbility(Abilities.BAD_DREAMS);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
game.scene.getPlayerPokemon()!.hp *= 0.52;
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.toNextTurn();
|
||||
|
||||
confirmSwitch();
|
||||
});
|
||||
|
||||
it("Activates due to entry hazards", async () => {
|
||||
game.scene.arena.addTag(ArenaTagType.STEALTH_ROCK, 1, Moves.STEALTH_ROCK, 0, ArenaTagSide.ENEMY);
|
||||
game.scene.arena.addTag(ArenaTagType.SPIKES, 1, Moves.SPIKES, 0, ArenaTagSide.ENEMY);
|
||||
@ -381,27 +399,6 @@ describe("Abilities - Wimp Out", () => {
|
||||
|
||||
confirmSwitch();
|
||||
});
|
||||
});
|
||||
|
||||
it("should not trigger on Magic Guard-prevented damage", async () => {
|
||||
game.scene.arena.addTag(ArenaTagType.STEALTH_ROCK, 1, Moves.STEALTH_ROCK, 0, ArenaTagSide.ENEMY);
|
||||
game.scene.arena.addTag(ArenaTagType.SPIKES, 1, Moves.SPIKES, 0, ArenaTagSide.ENEMY);
|
||||
game.override
|
||||
.passiveAbility(Abilities.MAGIC_GUARD)
|
||||
.enemyMoveset([Moves.LEECH_SEED])
|
||||
.weather(WeatherType.HAIL)
|
||||
.statusEffect(StatusEffect.POISON);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
game.scene.getPlayerPokemon()!.hp *= 0.51;
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(game.scene.getPlayerParty()[0].getHpRatio()).toEqual(0.51);
|
||||
expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase");
|
||||
expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.WIMPOD);
|
||||
});
|
||||
|
||||
it("triggers status on the wimp out user before a new pokemon is switched in", async () => {
|
||||
game.override.enemyMoveset(Moves.SLUDGE_BOMB).startingLevel(80);
|
||||
@ -416,27 +413,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
confirmSwitch();
|
||||
});
|
||||
|
||||
it("Wimp Out activating should not cancel a double battle", async () => {
|
||||
game.override.battleStyle("double").enemyAbility(Abilities.WIMP_OUT).enemyMoveset([Moves.SPLASH]).enemyLevel(1);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
const enemyLeadPokemon = game.scene.getEnemyParty()[0];
|
||||
const enemySecPokemon = game.scene.getEnemyParty()[1];
|
||||
|
||||
game.move.select(Moves.FALSE_SWIPE, 0, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.SPLASH, 1);
|
||||
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
const isVisibleLead = enemyLeadPokemon.visible;
|
||||
const hasFledLead = enemyLeadPokemon.switchOutStatus;
|
||||
const isVisibleSec = enemySecPokemon.visible;
|
||||
const hasFledSec = enemySecPokemon.switchOutStatus;
|
||||
expect(!isVisibleLead && hasFledLead && isVisibleSec && !hasFledSec).toBe(true);
|
||||
expect(enemyLeadPokemon.hp).toBeLessThan(enemyLeadPokemon.getMaxHp());
|
||||
expect(enemySecPokemon.hp).toEqual(enemySecPokemon.getMaxHp());
|
||||
});
|
||||
|
||||
it("triggers after last hit of multi hit moves", async () => {
|
||||
it("triggers after last hit of multi hit move", async () => {
|
||||
game.override.enemyMoveset(Moves.BULLET_SEED).enemyAbility(Abilities.SKILL_LINK);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
@ -467,7 +444,6 @@ describe("Abilities - Wimp Out", () => {
|
||||
expect(enemyPokemon.turnData.hitCount).toBe(2);
|
||||
confirmSwitch();
|
||||
});
|
||||
|
||||
it("triggers after last hit of Parental Bond", async () => {
|
||||
game.override.enemyMoveset(Moves.TACKLE).enemyAbility(Abilities.PARENTAL_BOND);
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
Loading…
Reference in New Issue
Block a user