mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-06-30 13:33:01 +02:00
Merge remote-tracking branch 'upstream/beta' into move-use-type
This commit is contained in:
commit
3e05489e9e
@ -70,14 +70,14 @@ import { CommonAnim } from "../battle-anims";
|
|||||||
import { getBerryEffectFunc } from "#app/data/berry";
|
import { getBerryEffectFunc } from "#app/data/berry";
|
||||||
import { BerryUsedEvent } from "#app/events/battle-scene";
|
import { BerryUsedEvent } from "#app/events/battle-scene";
|
||||||
import { noAbilityTypeOverrideMoves } from "#app/data/moves/invalid-moves";
|
import { noAbilityTypeOverrideMoves } from "#app/data/moves/invalid-moves";
|
||||||
import { MoveUseMode } from "#enums/move-use-mode";
|
import { isVirtual, MoveUseMode } from "#enums/move-use-mode";
|
||||||
|
|
||||||
// Type imports
|
// Type imports
|
||||||
import type { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import type { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
import type { BattleStat, EffectiveStat } from "#enums/stat";
|
import type { BattleStat, EffectiveStat } from "#enums/stat";
|
||||||
import type { BerryType } from "#enums/berry-type";
|
import type { BerryType } from "#enums/berry-type";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import type { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
import type { EnemyPokemon, PokemonMove, TurnMove } from "#app/field/pokemon";
|
||||||
import type { Weather } from "#app/data/weather";
|
import type { Weather } from "#app/data/weather";
|
||||||
import type { BattlerTag } from "#app/data/battler-tags";
|
import type { BattlerTag } from "#app/data/battler-tags";
|
||||||
import type {
|
import type {
|
||||||
@ -2536,48 +2536,32 @@ export class AllyStatMultiplierAbAttr extends AbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ability attribute for Gorilla Tactics
|
* Takes effect whenever a move succesfully executes, such as gorilla tactics' move-locking.
|
||||||
* @extends PostAttackAbAttr
|
* (More specifically, whenever a move is pushed to the move history)
|
||||||
*/
|
*/
|
||||||
export class GorillaTacticsAbAttr extends PostAttackAbAttr {
|
export class ExecutedMoveAbAttr extends AbAttr {
|
||||||
constructor() {
|
canApplyExecutedMove(_pokemon: Pokemon, _simulated: boolean): boolean {
|
||||||
super((_user, _target, _move) => true, false);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
override canApplyPostAttack(
|
applyExecutedMove(_pokemon: Pokemon, _simulated: boolean): void {}
|
||||||
pokemon: Pokemon,
|
}
|
||||||
passive: boolean,
|
|
||||||
simulated: boolean,
|
/**
|
||||||
defender: Pokemon,
|
* Ability attribute for {@linkcode AbilityId.GORILLA_TACTICS | Gorilla Tactics}
|
||||||
move: Move,
|
* to lock the user into its first selected move.
|
||||||
hitResult: HitResult | null,
|
*/
|
||||||
args: any[],
|
export class GorillaTacticsAbAttr extends ExecutedMoveAbAttr {
|
||||||
): boolean {
|
constructor(showAbility = false) {
|
||||||
return (
|
super(showAbility);
|
||||||
(super.canApplyPostAttack(pokemon, passive, simulated, defender, move, hitResult, args) && simulated) ||
|
|
||||||
!pokemon.getTag(BattlerTagType.GORILLA_TACTICS)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override canApplyExecutedMove(pokemon: Pokemon, _simulated: boolean): boolean {
|
||||||
*
|
// Gorilla Tactics does not trigger on called/reflected moves, only the calling move.
|
||||||
* @param {Pokemon} pokemon the {@linkcode Pokemon} with this ability
|
return !pokemon.canAddTag(BattlerTagType.GORILLA_TACTICS);
|
||||||
* @param _passive n/a
|
}
|
||||||
* @param simulated whether the ability is being simulated
|
|
||||||
* @param _defender n/a
|
override applyExecutedMove(pokemon: Pokemon, simulated: boolean): void {
|
||||||
* @param _move n/a
|
|
||||||
* @param _hitResult n/a
|
|
||||||
* @param _args n/a
|
|
||||||
*/
|
|
||||||
override applyPostAttack(
|
|
||||||
pokemon: Pokemon,
|
|
||||||
_passive: boolean,
|
|
||||||
simulated: boolean,
|
|
||||||
_defender: Pokemon,
|
|
||||||
_move: Move,
|
|
||||||
_hitResult: HitResult | null,
|
|
||||||
_args: any[],
|
|
||||||
): void {
|
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
pokemon.addTag(BattlerTagType.GORILLA_TACTICS);
|
pokemon.addTag(BattlerTagType.GORILLA_TACTICS);
|
||||||
}
|
}
|
||||||
@ -7800,6 +7784,22 @@ export function applyPreAttackAbAttrs(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function applyExecutedMoveAbAttrs(
|
||||||
|
attrType: Constructor<ExecutedMoveAbAttr>,
|
||||||
|
pokemon: Pokemon,
|
||||||
|
simulated: boolean = false,
|
||||||
|
...args: any[]
|
||||||
|
): void {
|
||||||
|
applyAbAttrsInternal<ExecutedMoveAbAttr>(
|
||||||
|
attrType,
|
||||||
|
pokemon,
|
||||||
|
attr => attr.applyExecutedMove(pokemon, simulated),
|
||||||
|
attr => attr.canApplyExecutedMove(pokemon, simulated),
|
||||||
|
args,
|
||||||
|
simulated,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function applyPostAttackAbAttrs(
|
export function applyPostAttackAbAttrs(
|
||||||
attrType: Constructor<PostAttackAbAttr>,
|
attrType: Constructor<PostAttackAbAttr>,
|
||||||
pokemon: Pokemon,
|
pokemon: Pokemon,
|
||||||
|
@ -362,7 +362,6 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag used by Gorilla Tactics to restrict the user to using only one move.
|
* Tag used by Gorilla Tactics to restrict the user to using only one move.
|
||||||
* @extends MoveRestrictionBattlerTag
|
|
||||||
*/
|
*/
|
||||||
export class GorillaTacticsTag extends MoveRestrictionBattlerTag {
|
export class GorillaTacticsTag extends MoveRestrictionBattlerTag {
|
||||||
private moveId = MoveId.NONE;
|
private moveId = MoveId.NONE;
|
||||||
@ -371,7 +370,6 @@ export class GorillaTacticsTag extends MoveRestrictionBattlerTag {
|
|||||||
super(BattlerTagType.GORILLA_TACTICS, BattlerTagLapseType.CUSTOM, 0);
|
super(BattlerTagType.GORILLA_TACTICS, BattlerTagLapseType.CUSTOM, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
|
||||||
override isMoveRestricted(move: MoveId): boolean {
|
override isMoveRestricted(move: MoveId): boolean {
|
||||||
return move !== this.moveId;
|
return move !== this.moveId;
|
||||||
}
|
}
|
||||||
@ -386,8 +384,7 @@ export class GorillaTacticsTag extends MoveRestrictionBattlerTag {
|
|||||||
const lastSelectedMove = pokemon.getLastNonVirtualMove();
|
const lastSelectedMove = pokemon.getLastNonVirtualMove();
|
||||||
return (
|
return (
|
||||||
!isNullOrUndefined(lastSelectedMove) &&
|
!isNullOrUndefined(lastSelectedMove) &&
|
||||||
lastSelectedMove.move !== MoveId.STRUGGLE &&
|
lastSelectedMove.move !== MoveId.STRUGGLE
|
||||||
!pokemon.getTag(GorillaTacticsTag)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,19 +405,17 @@ export class GorillaTacticsTag extends MoveRestrictionBattlerTag {
|
|||||||
* @override
|
* @override
|
||||||
* @param source Gorilla Tactics' {@linkcode BattlerTag} information
|
* @param source Gorilla Tactics' {@linkcode BattlerTag} information
|
||||||
*/
|
*/
|
||||||
public override loadTag(source: BattlerTag | any): void {
|
override loadTag(source: BattlerTag | any): void {
|
||||||
super.loadTag(source);
|
super.loadTag(source);
|
||||||
this.moveId = source.moveId;
|
this.moveId = source.moveId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Return the text displayed when a move is restricted.
|
||||||
* @override
|
* @param pokemon - The {@linkcode Pokemon} with this tag.
|
||||||
* @param {Pokemon} pokemon n/a
|
* @returns A string containing the text to display when the move is denied
|
||||||
* @param {MoveId} _move {@linkcode MoveId} ID of the move being denied
|
|
||||||
* @returns {string} text to display when the move is denied
|
|
||||||
*/
|
*/
|
||||||
override selectionDeniedText(pokemon: Pokemon, _move: MoveId): string {
|
override selectionDeniedText(pokemon: Pokemon): string {
|
||||||
return i18next.t("battle:canOnlyUseMove", {
|
return i18next.t("battle:canOnlyUseMove", {
|
||||||
moveName: allMoves[this.moveId].name,
|
moveName: allMoves[this.moveId].name,
|
||||||
pokemonName: getPokemonNameWithAffix(pokemon),
|
pokemonName: getPokemonNameWithAffix(pokemon),
|
||||||
|
@ -3,10 +3,12 @@ import { globalScene } from "#app/global-scene";
|
|||||||
import {
|
import {
|
||||||
AddSecondStrikeAbAttr,
|
AddSecondStrikeAbAttr,
|
||||||
AlwaysHitAbAttr,
|
AlwaysHitAbAttr,
|
||||||
|
applyExecutedMoveAbAttrs,
|
||||||
applyPostAttackAbAttrs,
|
applyPostAttackAbAttrs,
|
||||||
applyPostDamageAbAttrs,
|
applyPostDamageAbAttrs,
|
||||||
applyPostDefendAbAttrs,
|
applyPostDefendAbAttrs,
|
||||||
applyPreAttackAbAttrs,
|
applyPreAttackAbAttrs,
|
||||||
|
ExecutedMoveAbAttr,
|
||||||
IgnoreMoveEffectsAbAttr,
|
IgnoreMoveEffectsAbAttr,
|
||||||
MaxMultiHitAbAttr,
|
MaxMultiHitAbAttr,
|
||||||
PostAttackAbAttr,
|
PostAttackAbAttr,
|
||||||
@ -389,6 +391,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
// Add to the move history entry
|
// Add to the move history entry
|
||||||
if (this.firstHit) {
|
if (this.firstHit) {
|
||||||
user.pushMoveHistory(this.moveHistoryEntry);
|
user.pushMoveHistory(this.moveHistoryEntry);
|
||||||
|
applyExecutedMoveAbAttrs(ExecutedMoveAbAttr, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -7,6 +7,8 @@ import { Stat } from "#app/enums/stat";
|
|||||||
import GameManager from "#test/testUtils/gameManager";
|
import GameManager from "#test/testUtils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import { MoveResult } from "#app/field/pokemon";
|
||||||
|
import { MoveUseMode } from "#enums/move-use-mode";
|
||||||
|
|
||||||
describe("Abilities - Gorilla Tactics", () => {
|
describe("Abilities - Gorilla Tactics", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
@ -40,7 +42,7 @@ describe("Abilities - Gorilla Tactics", () => {
|
|||||||
|
|
||||||
game.move.select(MoveId.SPLASH);
|
game.move.select(MoveId.SPLASH);
|
||||||
await game.move.forceEnemyMove(MoveId.SPLASH);
|
await game.move.forceEnemyMove(MoveId.SPLASH);
|
||||||
await game.toEndOfTurn()
|
await game.toEndOfTurn();
|
||||||
|
|
||||||
expect(darmanitan.getStat(Stat.ATK, false)).toBeCloseTo(initialAtkStat * 1.5);
|
expect(darmanitan.getStat(Stat.ATK, false)).toBeCloseTo(initialAtkStat * 1.5);
|
||||||
// Other moves should be restricted
|
// Other moves should be restricted
|
||||||
@ -69,6 +71,7 @@ describe("Abilities - Gorilla Tactics", () => {
|
|||||||
|
|
||||||
// Third turn, Struggle is used
|
// Third turn, Struggle is used
|
||||||
game.move.select(MoveId.TACKLE);
|
game.move.select(MoveId.TACKLE);
|
||||||
|
await game.move.forceEnemyMove(MoveId.SPLASH); //prevent protect from being used by the enemy
|
||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
await game.phaseInterceptor.to("MoveEndPhase");
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
|
||||||
@ -90,5 +93,37 @@ describe("Abilities - Gorilla Tactics", () => {
|
|||||||
// Gorilla Tactics should bypass dancer and instruct
|
// Gorilla Tactics should bypass dancer and instruct
|
||||||
expect(darmanitan.isMoveRestricted(MoveId.TACKLE)).toBe(true);
|
expect(darmanitan.isMoveRestricted(MoveId.TACKLE)).toBe(true);
|
||||||
expect(darmanitan.isMoveRestricted(MoveId.METRONOME)).toBe(false);
|
expect(darmanitan.isMoveRestricted(MoveId.METRONOME)).toBe(false);
|
||||||
|
expect(darmanitan.getLastXMoves(-1)).toEqual([
|
||||||
|
expect.objectContaining({ move: MoveId.TACKLE, result: MoveResult.SUCCESS, useMode: MoveUseMode.FOLLOW_UP }),
|
||||||
|
expect.objectContaining({ move: MoveId.METRONOME, result: MoveResult.SUCCESS, useMode: MoveUseMode.NORMAL }),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should activate when the opponenet protects", async () => {
|
||||||
|
await game.classicMode.startBattle([SpeciesId.GALAR_DARMANITAN]);
|
||||||
|
|
||||||
|
const darmanitan = game.field.getPlayerPokemon();
|
||||||
|
|
||||||
|
game.move.select(MoveId.TACKLE);
|
||||||
|
await game.move.selectEnemyMove(MoveId.PROTECT);
|
||||||
|
|
||||||
|
await game.toEndOfTurn();
|
||||||
|
expect(darmanitan.isMoveRestricted(MoveId.SPLASH)).toBe(true);
|
||||||
|
expect(darmanitan.isMoveRestricted(MoveId.TACKLE)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should activate when a move is succesfully executed but misses", async () => {
|
||||||
|
await game.classicMode.startBattle([SpeciesId.GALAR_DARMANITAN]);
|
||||||
|
|
||||||
|
const darmanitan = game.field.getPlayerPokemon();
|
||||||
|
|
||||||
|
game.move.select(MoveId.TACKLE);
|
||||||
|
await game.move.selectEnemyMove(MoveId.SPLASH);
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
|
await game.move.forceMiss();
|
||||||
|
await game.toEndOfTurn();
|
||||||
|
|
||||||
|
expect(darmanitan.isMoveRestricted(MoveId.SPLASH)).toBe(true);
|
||||||
|
expect(darmanitan.isMoveRestricted(MoveId.TACKLE)).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user