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 { loadPositionalTag } from "#data/positional-tags/load-positional-tag";
import type { PositionalTag } from "#data/positional-tags/positional-tag"; import type { PositionalTag } from "#data/positional-tags/positional-tag";
import type { BattlerIndex } from "#enums/battler-index"; import type { BattlerIndex } from "#enums/battler-index";
import type { MoveId } from "#enums/move-id";
import type { PositionalTagType } from "#enums/positional-tag-type"; import type { PositionalTagType } from "#enums/positional-tag-type";
/** A manager for the {@linkcode PositionalTag}s in the arena. */ /** A manager for the {@linkcode PositionalTag}s in the arena. */
export class PositionalTagManager { 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[] = []; public tags: PositionalTag[] = [];
/** /**
@ -22,23 +23,22 @@ export class PositionalTagManager {
* Check whether a new {@linkcode PositionalTag} can be added to the battlefield. * Check whether a new {@linkcode PositionalTag} can be added to the battlefield.
* @param tagType - The {@linkcode PositionalTagType} being created * @param tagType - The {@linkcode PositionalTagType} being created
* @param targetIndex - The {@linkcode BattlerIndex} being targeted * @param targetIndex - The {@linkcode BattlerIndex} being targeted
* @param sourceMove - The {@linkcode MoveId} causing the attack
* @returns Whether the tag can be added. * @returns Whether the tag can be added.
*/ */
public canAddTag(tagType: PositionalTagType, targetIndex: BattlerIndex, sourceMove: MoveId): boolean { public canAddTag(tagType: PositionalTagType, targetIndex: BattlerIndex): boolean {
return !this.tags.some(t => t.tagType === tagType && t.overlapsWith(targetIndex, sourceMove)); return !this.tags.some(t => t.tagType === tagType && t.targetIndex === targetIndex);
} }
/** /**
* Decrement turn counts of and activate all pending {@linkcode PositionalTag}s on field. * Decrement turn counts of and activate all pending {@linkcode PositionalTag}s on field.
* @remarks * @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>)) * (Source: [Smogon](<https://www.smogon.com/forums/threads/sword-shield-battle-mechanics-research.3655528/page-64#post-9244179>))
*/ */
public triggerAllTags(): void { public triggerAllTags(): void {
const leftoverTags: PositionalTag[] = []; const leftoverTags: PositionalTag[] = [];
for (const tag of this.tags) { 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()) { if (tag.shouldDisappear()) {
continue; continue;
} }
@ -51,5 +51,6 @@ export class PositionalTagManager {
tag.trigger(); tag.trigger();
} }
this.tags = leftoverTags;
} }
} }

View File

@ -58,17 +58,7 @@ export abstract class PositionalTag implements PositionalTagBaseArgs {
*/ */
abstract shouldDisappear(): boolean; abstract shouldDisappear(): boolean;
/** protected getTarget(): Pokemon | undefined {
* 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 {
return globalScene.getField()[this.targetIndex]; return globalScene.getField()[this.targetIndex];
} }
} }
@ -131,9 +121,7 @@ export class DelayedAttackTag extends PositionalTag implements DelayedAttackArgs
interface WishArgs extends PositionalTagBaseArgs { 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. */ /** The amount of {@linkcode Stat.HP | HP} to heal; set to 50% of the user's max HP during move usage. */
healHp: number; healHp: number;
/** /** The name of the {@linkcode Pokemon} having created the tag. */
* The name of the {@linkcode Pokemon} having created the tag..
*/
pokemonName: string; pokemonName: string;
} }
@ -153,10 +141,10 @@ export class WishTag extends PositionalTag implements WishArgs {
} }
public trigger(): void { 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( globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:wishTagOnAdd", { i18next.t("arenaTag:wishTagOnAdd", {
pokemonName: this.pokemonName, pokemonNameWithAffix: this.pokemonName,
}), }),
); );
@ -166,6 +154,6 @@ export class WishTag extends PositionalTag implements WishArgs {
public shouldDisappear(): boolean { public shouldDisappear(): boolean {
// Disappear if no target. // Disappear if no target.
// The source need not exist at the time of activation (since all we need is a simple message) // 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} * 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); const overridden = new BooleanHolder(false);
console.log(this.useMode);
// Apply effects to override a move effect. // Apply effects to override a move effect.
// Assuming single target here works as this is (currently) // Assuming single target here works as this is (currently)
// only used for Future Sight, calling and Pledge moves. // 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 { AbilityId } from "#enums/ability-id";
import { BattlerIndex } from "#enums/battler-index"; import { BattlerIndex } from "#enums/battler-index";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import { MoveResult } from "#enums/move-result";
import { PositionalTagType } from "#enums/positional-tag-type"; import { PositionalTagType } from "#enums/positional-tag-type";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
@ -65,13 +66,31 @@ describe("Move - Wish", () => {
expectWishActive(0); expectWishActive(0);
expect(game.textInterceptor.logs).toContain( expect(game.textInterceptor.logs).toContain(
i18next.t("arenaTag:wishTagOnAdd", { i18next.t("arenaTag:wishTagOnAdd", {
pokemonName: getPokemonNameWithAffix(blissey), pokemonNameWithAffix: getPokemonNameWithAffix(alomomola),
}), }),
); );
expect(alomomola.hp).toBe(1); expect(alomomola.hp).toBe(1);
expect(blissey.hp).toBe(toDmgValue(alomomola.getMaxHp() / 2) + 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 () => { it("should function independently of Future Sight", async () => {
await game.classicMode.startBattle([SpeciesId.ALOMOMOLA, SpeciesId.BLISSEY]); await game.classicMode.startBattle([SpeciesId.ALOMOMOLA, SpeciesId.BLISSEY]);
@ -81,13 +100,13 @@ describe("Move - Wish", () => {
game.move.use(MoveId.WISH); game.move.use(MoveId.WISH);
await game.move.forceEnemyMove(MoveId.FUTURE_SIGHT); await game.move.forceEnemyMove(MoveId.FUTURE_SIGHT);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.toNextTurn(); await game.toNextTurn();
expectWishActive(1); 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"); game.override.battleStyle("double");
await game.classicMode.startBattle([SpeciesId.ALOMOMOLA, SpeciesId.BLISSEY]); 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(alomomola.hp).toBe(toDmgValue(alomomola.getMaxHp() / 2) + 1);
expect(blissey.hp).toBe(toDmgValue(blissey.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);
});
}); });