fix follow me with pursuit
This commit is contained in:
parent
b057c144ac
commit
f0eac00179
|
@ -4203,8 +4203,21 @@ export class TypelessAttr extends MoveAttr { }
|
||||||
/**
|
/**
|
||||||
* Attribute used for moves which ignore redirection effects, and always target their original target, i.e. Snipe Shot
|
* Attribute used for moves which ignore redirection effects, and always target their original target, i.e. Snipe Shot
|
||||||
* Bypasses Storm Drain, Follow Me, Ally Switch, and the like.
|
* Bypasses Storm Drain, Follow Me, Ally Switch, and the like.
|
||||||
|
*
|
||||||
|
* Optionally accepts a function to run which can be used to conditionally bypass redirection effects.
|
||||||
*/
|
*/
|
||||||
export class BypassRedirectAttr extends MoveAttr { }
|
export class BypassRedirectAttr extends MoveAttr {
|
||||||
|
private bypassConditionFn?: (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean;
|
||||||
|
|
||||||
|
constructor(bypassConditionFn?: (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean) {
|
||||||
|
super();
|
||||||
|
this.bypassConditionFn = bypassConditionFn;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(user: Pokemon | null, target: Pokemon | null, move: Move) {
|
||||||
|
return this.bypassConditionFn?.(user, target, move) ?? true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class DisableMoveAttr extends MoveEffectAttr {
|
export class DisableMoveAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -6876,6 +6889,7 @@ export function initMoves() {
|
||||||
.condition((user, target, move) => new EncoreTag(user.id).canAdd(target)),
|
.condition((user, target, move) => new EncoreTag(user.id).canAdd(target)),
|
||||||
new AttackMove(Moves.PURSUIT, Type.DARK, MoveCategory.PHYSICAL, 40, 100, 20, -1, 0, 2)
|
new AttackMove(Moves.PURSUIT, Type.DARK, MoveCategory.PHYSICAL, 40, 100, 20, -1, 0, 2)
|
||||||
.attr(PursuitAccuracyAttr)
|
.attr(PursuitAccuracyAttr)
|
||||||
|
.attr(BypassRedirectAttr, (user, target) => Boolean(user && target && isPursuingFunc(user, target)))
|
||||||
.attr(AddBattlerTagHeaderAttr, BattlerTagType.ANTICIPATING_ACTION)
|
.attr(AddBattlerTagHeaderAttr, BattlerTagType.ANTICIPATING_ACTION)
|
||||||
.attr(RemoveBattlerTagAttr, [BattlerTagType.ANTICIPATING_ACTION], true, MoveEffectTrigger.POST_APPLY)
|
.attr(RemoveBattlerTagAttr, [BattlerTagType.ANTICIPATING_ACTION], true, MoveEffectTrigger.POST_APPLY)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target) => isPursuingFunc(user, target) ? 2 : 1),
|
.attr(MovePowerMultiplierAttr, (user, target) => isPursuingFunc(user, target) ? 2 : 1),
|
||||||
|
|
|
@ -2777,9 +2777,11 @@ export class MovePhase extends BattlePhase {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//Check if this move is immune to being redirected, and restore its target to the intended target if it is.
|
//Check if this move is immune to being redirected, and restore its target to the intended target if it is.
|
||||||
if ((this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr) || this.move.getMove().hasAttr(BypassRedirectAttr))) {
|
const abilityRedirectImmune = this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr);
|
||||||
|
const moveRedirectImmune = this.move.getMove().getAttrs(BypassRedirectAttr).some(attr => attr.apply(this.pokemon, this.scene.getField(false)[oldTarget], this.move.getMove()));
|
||||||
|
if (abilityRedirectImmune || moveRedirectImmune) {
|
||||||
//If an ability prevented this move from being redirected, display its ability pop up.
|
//If an ability prevented this move from being redirected, display its ability pop up.
|
||||||
if ((this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr) && !this.move.getMove().hasAttr(BypassRedirectAttr)) && oldTarget !== moveTarget.value) {
|
if (abilityRedirectImmune && !moveRedirectImmune && oldTarget !== moveTarget.value) {
|
||||||
this.scene.unshiftPhase(new ShowAbilityPhase(this.scene, this.pokemon.getBattlerIndex(), this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr)));
|
this.scene.unshiftPhase(new ShowAbilityPhase(this.scene, this.pokemon.getBattlerIndex(), this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr)));
|
||||||
}
|
}
|
||||||
moveTarget.value = oldTarget;
|
moveTarget.value = oldTarget;
|
||||||
|
|
|
@ -495,7 +495,6 @@ describe("Moves - Pursuit", () => {
|
||||||
game.override.battleType("double");
|
game.override.battleType("double");
|
||||||
});
|
});
|
||||||
|
|
||||||
// fails: pursuit does not ignore follow me
|
|
||||||
it("should bypass follow me when hitting a switching target", async () => {
|
it("should bypass follow me when hitting a switching target", async () => {
|
||||||
// arrange
|
// arrange
|
||||||
await startBattle();
|
await startBattle();
|
||||||
|
@ -509,13 +508,32 @@ describe("Moves - Pursuit", () => {
|
||||||
await runCombatTurn(game.scene.getEnemyField()[1]);
|
await runCombatTurn(game.scene.getEnemyField()[1]);
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
expectPursuitPowerUnchanged();
|
expectPursuitPowerDoubled();
|
||||||
expectWasHit(findPartyMember(game.scene.getParty(), Species.RAICHU))
|
expectWasHit(findPartyMember(game.scene.getParty(), Species.RAICHU))
|
||||||
.and(expectNotOnField);
|
.and(expectNotOnField);
|
||||||
expectWasNotHit(findPartyMember(game.scene.getParty(), playerLead));
|
expectWasNotHit(findPartyMember(game.scene.getParty(), playerLead));
|
||||||
});
|
});
|
||||||
|
|
||||||
// fails: fainting a pursuiter still runs the enemy SwitchSummonPhase
|
it("should not bypass follow me when hitting a non-switching target", async () => {
|
||||||
|
// arrange
|
||||||
|
await startBattle();
|
||||||
|
forceMovesLast(game.scene.getEnemyPokemon());
|
||||||
|
|
||||||
|
// act
|
||||||
|
game.override.moveset([Moves.FOLLOW_ME, Moves.SPLASH]);
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.FOLLOW_ME));
|
||||||
|
game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
|
||||||
|
enemyUses(Moves.PURSUIT);
|
||||||
|
game.move.forceAiTargets(game.scene.getEnemyPokemon(), BattlerIndex.PLAYER_2);
|
||||||
|
await runCombatTurn(game.scene.getEnemyField()[1]);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expectPursuitPowerUnchanged();
|
||||||
|
expectWasHit(findPartyMember(game.scene.getParty(), playerLead));
|
||||||
|
expectWasNotHit(findPartyMember(game.scene.getParty(), Species.RAICHU));
|
||||||
|
});
|
||||||
|
|
||||||
|
// fails: fainting an escapee still runs the enemy SwitchSummonPhase
|
||||||
it("should fail if both pokemon use pursuit on a target that is switching out and it faints after the first one", async () => {
|
it("should fail if both pokemon use pursuit on a target that is switching out and it faints after the first one", async () => {
|
||||||
// arrange
|
// arrange
|
||||||
await startBattle();
|
await startBattle();
|
||||||
|
|
Loading…
Reference in New Issue