mostly implemented (missing some edge cases/interactions)
This commit is contained in:
parent
a3a42931ba
commit
7517e16c84
|
@ -4927,26 +4927,65 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
||||||
return resolve(false);
|
return resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the switch out logic inside the conditional block
|
|
||||||
// This ensures that the switch out only happens when the conditions are met
|
|
||||||
const switchOutTarget = this.user ? user : target;
|
const switchOutTarget = this.user ? user : target;
|
||||||
|
|
||||||
|
let willBePursued = false;
|
||||||
|
if (switchOutTarget.hp > 0 && !this.batonPass && this.user && move.id !== Moves.TELEPORT) {
|
||||||
|
switchOutTarget.addTag(BattlerTagType.ESCAPING);
|
||||||
|
|
||||||
|
const opposingField = user.isPlayer() ? user.scene.getEnemyField() : user.scene.getPlayerField();
|
||||||
|
const opposingPursuitUsers = opposingField
|
||||||
|
.filter((op: Pokemon) => op.getTag(BattlerTagType.ANTICIPATING_ACTION)?.sourceMove === Moves.PURSUIT)
|
||||||
|
.sort((a, b) => b.turnData.order - a.turnData.order);
|
||||||
|
if (opposingPursuitUsers.length) {
|
||||||
|
willBePursued = true;
|
||||||
|
opposingPursuitUsers.forEach(pursuiter => {
|
||||||
|
if (user.scene.tryRemovePhase(p => p instanceof MovePhase && p.pokemon.id === pursuiter.id)) {
|
||||||
|
user.scene.prependToPhase(new MovePhase(user.scene, pursuiter, [switchOutTarget.getBattlerIndex()], pursuiter.getMoveset().find(m => m.moveId === Moves.PURSUIT) || new PokemonMove(Moves.PURSUIT), false, false), MoveEndPhase);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (switchOutTarget instanceof PlayerPokemon) {
|
if (switchOutTarget instanceof PlayerPokemon) {
|
||||||
|
if (!willBePursued) {
|
||||||
switchOutTarget.leaveField(!this.batonPass);
|
switchOutTarget.leaveField(!this.batonPass);
|
||||||
|
}
|
||||||
|
|
||||||
if (switchOutTarget.hp > 0) {
|
if (switchOutTarget.hp > 0) {
|
||||||
user.scene.prependToPhase(new SwitchPhase(user.scene, switchOutTarget.getFieldIndex(), true, true), MoveEndPhase);
|
user.scene.prependToPhase(
|
||||||
|
new SwitchPhase(user.scene, switchOutTarget.getFieldIndex(), true, willBePursued),
|
||||||
|
MoveEndPhase
|
||||||
|
);
|
||||||
resolve(true);
|
resolve(true);
|
||||||
} else {
|
} else {
|
||||||
resolve(false);
|
resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else if (user.scene.currentBattle.battleType !== BattleType.WILD) {
|
} else if (user.scene.currentBattle.battleType !== BattleType.WILD) {
|
||||||
|
if (!user.scene.currentBattle.trainer) {
|
||||||
|
return resolve(false); // what are we even doing here
|
||||||
|
}
|
||||||
|
|
||||||
// Switch out logic for trainer battles
|
// Switch out logic for trainer battles
|
||||||
|
if (!willBePursued) {
|
||||||
switchOutTarget.leaveField(!this.batonPass);
|
switchOutTarget.leaveField(!this.batonPass);
|
||||||
|
}
|
||||||
|
|
||||||
if (switchOutTarget.hp > 0) {
|
if (switchOutTarget.hp > 0) {
|
||||||
// for opponent switching out
|
// for opponent switching out
|
||||||
user.scene.prependToPhase(new SwitchSummonPhase(user.scene, switchOutTarget.getFieldIndex(), (user.scene.currentBattle.trainer ? user.scene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot) : 0), false, this.batonPass, false), MoveEndPhase);
|
user.scene.prependToPhase(
|
||||||
|
new SwitchSummonPhase(
|
||||||
|
user.scene,
|
||||||
|
switchOutTarget.getFieldIndex(),
|
||||||
|
user.scene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot),
|
||||||
|
willBePursued,
|
||||||
|
this.batonPass,
|
||||||
|
false
|
||||||
|
),
|
||||||
|
MoveEndPhase
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Switch out logic for everything else (eg: WILD battles)
|
// Switch out logic for everything else (eg: WILD battles)
|
||||||
|
|
|
@ -2332,14 +2332,22 @@ export class TurnStartPhase extends FieldPhase {
|
||||||
const moveOrder = order.slice(0);
|
const moveOrder = order.slice(0);
|
||||||
|
|
||||||
moveOrder.sort((a, b) => {
|
moveOrder.sort((a, b) => {
|
||||||
const aCommand = this.scene.currentBattle.turnCommands[a];
|
const aCommand = this.scene.currentBattle.turnCommands[a]!;
|
||||||
const bCommand = this.scene.currentBattle.turnCommands[b];
|
const bCommand = this.scene.currentBattle.turnCommands[b]!;
|
||||||
|
|
||||||
if (aCommand?.command !== bCommand?.command) {
|
if (aCommand.command !== bCommand.command) {
|
||||||
if (aCommand?.command === Command.FIGHT) {
|
if (aCommand.command === Command.FIGHT) {
|
||||||
return 1;
|
if (aCommand.move?.move === Moves.PURSUIT && bCommand.command === Command.POKEMON) {
|
||||||
} else if (bCommand?.command === Command.FIGHT) {
|
|
||||||
return -1;
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (bCommand.command === Command.FIGHT) {
|
||||||
|
if (bCommand.move?.move === Moves.PURSUIT && aCommand.command === Command.POKEMON) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (aCommand?.command === Command.FIGHT) {
|
} else if (aCommand?.command === Command.FIGHT) {
|
||||||
const aMove = allMoves[aCommand.move!.move];//TODO: is the bang correct here?
|
const aMove = allMoves[aCommand.move!.move];//TODO: is the bang correct here?
|
||||||
|
@ -2396,22 +2404,50 @@ export class TurnStartPhase extends FieldPhase {
|
||||||
if (move.getMove().hasAttr(MoveHeaderAttr)) {
|
if (move.getMove().hasAttr(MoveHeaderAttr)) {
|
||||||
this.scene.unshiftPhase(new MoveHeaderPhase(this.scene, pokemon, move));
|
this.scene.unshiftPhase(new MoveHeaderPhase(this.scene, pokemon, move));
|
||||||
}
|
}
|
||||||
|
// even though pursuit is ordered before Pokemon commands in the move
|
||||||
|
// order, the SwitchSummonPhase is unshifted onto the phase list, which
|
||||||
|
// would cause it to run before pursuit if pursuit was pushed normally.
|
||||||
|
// the SwitchSummonPhase can't be changed to a push either, because then
|
||||||
|
// the MoveHeaderPhase for all moves would run prior to the switch-out,
|
||||||
|
// which is not correct (eg, when focus punching a switching opponent,
|
||||||
|
// the correct order is switch -> tightening focus message -> attack
|
||||||
|
// fires, not focus -> switch -> attack). so, we have to specifically
|
||||||
|
// unshift pursuit when there are other pokemon commands after it, as
|
||||||
|
// well as order it before any Pokemon commands, otherwise it won't go first.
|
||||||
|
const remainingMoves = moveOrder.slice(moveOrder.findIndex(mo => mo === o) + 1);
|
||||||
|
const pendingOpposingPokemonCommands = remainingMoves.filter(o =>
|
||||||
|
this.scene.currentBattle.turnCommands[o]!.command === Command.POKEMON
|
||||||
|
&& (pokemon.isPlayer() ? o >= BattlerIndex.ENEMY : o < BattlerIndex.ENEMY)
|
||||||
|
);
|
||||||
|
const arePokemonCommandsLeftInQueue = Boolean(pendingOpposingPokemonCommands.length);
|
||||||
|
const addPhase = (
|
||||||
|
queuedMove.move === Moves.PURSUIT && arePokemonCommandsLeftInQueue
|
||||||
|
? this.scene.unshiftPhase
|
||||||
|
: this.scene.pushPhase
|
||||||
|
).bind(this.scene);
|
||||||
|
|
||||||
|
// pursuit also hits the first pokemon to switch out in doubles,
|
||||||
|
// regardless of original target
|
||||||
|
const targets = queuedMove.move === Moves.PURSUIT && arePokemonCommandsLeftInQueue
|
||||||
|
? [pendingOpposingPokemonCommands[0]]
|
||||||
|
: turnCommand.targets || turnCommand.move!.targets;
|
||||||
if (pokemon.isPlayer()) {
|
if (pokemon.isPlayer()) {
|
||||||
if (turnCommand.cursor === -1) {
|
if (turnCommand.cursor === -1) {
|
||||||
this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move));//TODO: is the bang correct here?
|
addPhase(new MovePhase(this.scene, pokemon, targets, move));
|
||||||
} else {
|
} else {
|
||||||
const playerPhase = new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move, false, queuedMove.ignorePP);//TODO: is the bang correct here?
|
const playerPhase = new MovePhase(this.scene, pokemon, targets, move, false, queuedMove.ignorePP);
|
||||||
this.scene.pushPhase(playerPhase);
|
addPhase(playerPhase);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move, false, queuedMove.ignorePP));//TODO: is the bang correct here?
|
addPhase(new MovePhase(this.scene, pokemon, targets, move, false, queuedMove.ignorePP));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Command.BALL:
|
case Command.BALL:
|
||||||
this.scene.unshiftPhase(new AttemptCapturePhase(this.scene, turnCommand.targets![0] % 2, turnCommand.cursor!));//TODO: is the bang correct here?
|
this.scene.unshiftPhase(new AttemptCapturePhase(this.scene, turnCommand.targets![0] % 2, turnCommand.cursor!));//TODO: is the bang correct here?
|
||||||
break;
|
break;
|
||||||
case Command.POKEMON:
|
case Command.POKEMON:
|
||||||
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, pokemon.getFieldIndex(), turnCommand.cursor!, true, turnCommand.args![0] as boolean, pokemon.isPlayer()));//TODO: is the bang correct here?
|
pokemon.addTag(BattlerTagType.ESCAPING);
|
||||||
|
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, pokemon.getFieldIndex(), turnCommand.cursor!, true, turnCommand.args![0] as boolean, pokemon.isPlayer()));
|
||||||
break;
|
break;
|
||||||
case Command.RUN:
|
case Command.RUN:
|
||||||
let runningPokemon = pokemon;
|
let runningPokemon = pokemon;
|
||||||
|
@ -4694,8 +4730,9 @@ export class SwitchPhase extends BattlePhase {
|
||||||
* @param fieldIndex Field index to switch out
|
* @param fieldIndex Field index to switch out
|
||||||
* @param isModal Indicates if the switch should be forced (true) or is
|
* @param isModal Indicates if the switch should be forced (true) or is
|
||||||
* optional (false).
|
* optional (false).
|
||||||
* @param doReturn Indicates if the party member on the field should be
|
* @param doReturn Indicates if this switch should call back the pokemon at
|
||||||
* recalled to ball or has already left the field. Passed to {@linkcode SwitchSummonPhase}.
|
* the {@linkcode fieldIndex} (true), or if the mon has already been recalled
|
||||||
|
* (false).
|
||||||
*/
|
*/
|
||||||
constructor(scene: BattleScene, fieldIndex: integer, isModal: boolean, doReturn: boolean) {
|
constructor(scene: BattleScene, fieldIndex: integer, isModal: boolean, doReturn: boolean) {
|
||||||
super(scene);
|
super(scene);
|
||||||
|
@ -4723,7 +4760,9 @@ export class SwitchPhase extends BattlePhase {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there is any space still in field
|
// Check if there is any space still in field
|
||||||
if (this.isModal && this.scene.getPlayerField().filter(p => p.isAllowedInBattle() && p.isActive(true)).length >= this.scene.currentBattle.getBattlerCount()) {
|
const numActiveBattlers = this.scene.getPlayerField().filter(p => p.isAllowedInBattle() && p.isActive(true)).length;
|
||||||
|
const willReturnModifer = (this.doReturn ? 1 : 0); // need to subtract this if doReturn is true, because the pokemon in the given index hasn't left the field yet. (used for volt switch + pursuit, etc)
|
||||||
|
if (this.isModal && numActiveBattlers - willReturnModifer >= this.scene.currentBattle.getBattlerCount()) {
|
||||||
return super.end();
|
return super.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue