Fixed tests for good
This commit is contained in:
Bertie690 2025-07-22 11:17:15 -04:00
parent 68495eb05f
commit dca1d3470b
5 changed files with 66 additions and 29 deletions

View File

@ -1,12 +1,13 @@
import { loadPositionalTag } from "#data/positional-tags/load-positional-tag";
import type { PositionalTag } from "#data/positional-tags/positional-tag";
import type { BattlerIndex } from "#enums/battler-index";
import type { MoveId } from "#enums/move-id";
import type { PositionalTagType } from "#enums/positional-tag-type";
/** A manager for the {@linkcode PositionalTag}s in the arena. */
export class PositionalTagManager {
/** Array containing all pending unactivated {@linkcode PositionalTag}s, sorted by order of creation. */
/**
* Array containing all pending unactivated {@linkcode PositionalTag}s,
* sorted by order of creation (oldest first). */
public tags: PositionalTag[] = [];
/**
@ -22,23 +23,22 @@ export class PositionalTagManager {
* Check whether a new {@linkcode PositionalTag} can be added to the battlefield.
* @param tagType - The {@linkcode PositionalTagType} being created
* @param targetIndex - The {@linkcode BattlerIndex} being targeted
* @param sourceMove - The {@linkcode MoveId} causing the attack
* @returns Whether the tag can be added.
*/
public canAddTag(tagType: PositionalTagType, targetIndex: BattlerIndex, sourceMove: MoveId): boolean {
return !this.tags.some(t => t.tagType === tagType && t.overlapsWith(targetIndex, sourceMove));
public canAddTag(tagType: PositionalTagType, targetIndex: BattlerIndex): boolean {
return !this.tags.some(t => t.tagType === tagType && t.targetIndex === targetIndex);
}
/**
* Decrement turn counts of and activate all pending {@linkcode PositionalTag}s on field.
* @remarks
* If multiple tags trigger simultaneously, they will activate **in order of initial creation**, NOT speed order.
* If multiple tags trigger simultaneously, they will activate **in order of initial creation**, regardless of speed order.
* (Source: [Smogon](<https://www.smogon.com/forums/threads/sword-shield-battle-mechanics-research.3655528/page-64#post-9244179>))
*/
public triggerAllTags(): void {
const leftoverTags: PositionalTag[] = [];
for (const tag of this.tags) {
// Check for silent removal, immediately removing tags that.
// Check for silent removal, immediately removing invalid tags.
if (tag.shouldDisappear()) {
continue;
}
@ -51,5 +51,6 @@ export class PositionalTagManager {
tag.trigger();
}
this.tags = leftoverTags;
}
}

View File

@ -58,17 +58,7 @@ export abstract class PositionalTag implements PositionalTagBaseArgs {
*/
abstract shouldDisappear(): boolean;
/**
* Check whether this {@linkcode PositionalTag} would overlap with another one.
* @param targetIndex - The {@linkcode BattlerIndex} being targeted
* @param sourceMove - The {@linkcode MoveId} causing the attack
* @returns Whether this tag would overlap with a newly created one.
*/
public overlapsWith(targetIndex: BattlerIndex, _sourceMove: MoveId): boolean {
return this.targetIndex === targetIndex;
}
public getTarget(): Pokemon | undefined {
protected getTarget(): Pokemon | undefined {
return globalScene.getField()[this.targetIndex];
}
}
@ -131,9 +121,7 @@ export class DelayedAttackTag extends PositionalTag implements DelayedAttackArgs
interface WishArgs extends PositionalTagBaseArgs {
/** The amount of {@linkcode Stat.HP | HP} to heal; set to 50% of the user's max HP during move usage. */
healHp: number;
/**
* The name of the {@linkcode Pokemon} having created the tag..
*/
/** The name of the {@linkcode Pokemon} having created the tag. */
pokemonName: string;
}
@ -153,10 +141,10 @@ export class WishTag extends PositionalTag implements WishArgs {
}
public trigger(): void {
// TODO: Rename this locales key - wish shows a message on REMOVAL, dumbass
// TODO: Rename this locales key - wish shows a message on REMOVAL, not addition
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:wishTagOnAdd", {
pokemonName: this.pokemonName,
pokemonNameWithAffix: this.pokemonName,
}),
);
@ -166,6 +154,6 @@ export class WishTag extends PositionalTag implements WishArgs {
public shouldDisappear(): boolean {
// Disappear if no target.
// The source need not exist at the time of activation (since all we need is a simple message)
return !!this.getTarget();
return !this.getTarget();
}
}

View File

@ -44,7 +44,9 @@ import { Variant } from "#sprites/variant";
* }
* ```
*/
const overrides = {} satisfies Partial<InstanceType<OverridesType>>;
const overrides = {
MOVESET_OVERRIDE: [MoveId.FUTURE_SIGHT, MoveId.WISH, MoveId.DOOM_DESIRE, MoveId.AGILITY],
} satisfies Partial<InstanceType<OverridesType>>;
/**
* If you need to add Overrides values for local testing do that inside {@linkcode overrides}

View File

@ -263,7 +263,6 @@ export class MoveEffectPhase extends PokemonPhase {
*/
const overridden = new BooleanHolder(false);
console.log(this.useMode);
// Apply effects to override a move effect.
// Assuming single target here works as this is (currently)
// only used for Future Sight, calling and Pledge moves.

View File

@ -2,6 +2,7 @@ import { getPokemonNameWithAffix } from "#app/messages";
import { AbilityId } from "#enums/ability-id";
import { BattlerIndex } from "#enums/battler-index";
import { MoveId } from "#enums/move-id";
import { MoveResult } from "#enums/move-result";
import { PositionalTagType } from "#enums/positional-tag-type";
import { SpeciesId } from "#enums/species-id";
import { Stat } from "#enums/stat";
@ -65,13 +66,31 @@ describe("Move - Wish", () => {
expectWishActive(0);
expect(game.textInterceptor.logs).toContain(
i18next.t("arenaTag:wishTagOnAdd", {
pokemonName: getPokemonNameWithAffix(blissey),
pokemonNameWithAffix: getPokemonNameWithAffix(alomomola),
}),
);
expect(alomomola.hp).toBe(1);
expect(blissey.hp).toBe(toDmgValue(alomomola.getMaxHp() / 2) + 1);
});
it("should work if the user has full HP, but not if it already has an active Wish", async () => {
await game.classicMode.startBattle([SpeciesId.ALOMOMOLA, SpeciesId.BLISSEY]);
const alomomola = game.field.getPlayerPokemon();
alomomola.hp = 1;
game.move.use(MoveId.WISH);
await game.toNextTurn();
expectWishActive();
game.move.use(MoveId.WISH);
await game.toEndOfTurn();
expect(alomomola.hp).toBe(toDmgValue(alomomola.getMaxHp() / 2) + 1);
expect(alomomola.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
});
it("should function independently of Future Sight", async () => {
await game.classicMode.startBattle([SpeciesId.ALOMOMOLA, SpeciesId.BLISSEY]);
@ -81,13 +100,13 @@ describe("Move - Wish", () => {
game.move.use(MoveId.WISH);
await game.move.forceEnemyMove(MoveId.FUTURE_SIGHT);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.toNextTurn();
expectWishActive(1);
});
it("should work in double battles and triggerin order of creation", async () => {
it("should work in double battles and trigger in order of creation", async () => {
game.override.battleStyle("double");
await game.classicMode.startBattle([SpeciesId.ALOMOMOLA, SpeciesId.BLISSEY]);
@ -126,4 +145,32 @@ describe("Move - Wish", () => {
expect(alomomola.hp).toBe(toDmgValue(alomomola.getMaxHp() / 2) + 1);
expect(blissey.hp).toBe(toDmgValue(blissey.getMaxHp() / 2) + 1);
});
it("should vanish if slot is empty", async () => {
game.override.battleStyle("double");
await game.classicMode.startBattle([SpeciesId.ALOMOMOLA, SpeciesId.BLISSEY]);
const [alomomola, blissey] = game.scene.getPlayerParty();
alomomola.hp = 1;
blissey.hp = 1;
game.move.use(MoveId.SPLASH, BattlerIndex.PLAYER);
game.move.use(MoveId.WISH, BattlerIndex.PLAYER_2);
await game.toNextTurn();
expectWishActive();
game.move.use(MoveId.SPLASH, BattlerIndex.PLAYER);
game.move.use(MoveId.MEMENTO, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2);
await game.toEndOfTurn();
// Wish went away without doing anything
expectWishActive(0);
expect(game.textInterceptor.logs).not.toContain(
i18next.t("arenaTag:wishTagOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(blissey),
}),
);
expect(alomomola.hp).toBe(1);
});
});