Trainers switch out their Pokemon when at a disadvantage

pull/14/head
Flashfyre 2024-01-15 00:20:26 -05:00
parent f49a3e5127
commit 8c4f336cd6
4 changed files with 66 additions and 9 deletions

View File

@ -967,7 +967,7 @@ export class SwitchSummonPhase extends SummonPhase {
if (!this.player && this.slotIndex === -1)
this.slotIndex = this.scene.currentBattle.trainer.getNextSummonIndex();
if (!this.doReturn || (this.slotIndex !== -1 && !this.scene.getParty()[this.slotIndex])) {
if (!this.doReturn || (this.slotIndex !== -1 && !(this.player ? this.scene.getParty() : this.scene.getEnemyParty())[this.slotIndex])) {
this.switchAndSummon();
return;
}
@ -975,7 +975,7 @@ export class SwitchSummonPhase extends SummonPhase {
const pokemon = this.getPokemon();
if (!this.batonPass)
this.scene.getEnemyField().forEach(enemyPokemon => enemyPokemon.removeTagsBySourceId(pokemon.id));
(this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.removeTagsBySourceId(pokemon.id));
this.scene.ui.showText(this.player ? `Come back, ${pokemon.name}!` : `${this.scene.currentBattle.trainer.getName()}\nwithdrew ${pokemon.name}!`);
this.scene.playSound('pb_rel');
@ -996,11 +996,11 @@ export class SwitchSummonPhase extends SummonPhase {
}
switchAndSummon() {
const party = this.getParty();
const party = this.player ? this.getParty() : this.scene.getEnemyParty();
const switchedPokemon = party[this.slotIndex];
this.lastPokemon = this.getPokemon();
if (this.batonPass && switchedPokemon) {
this.scene.getEnemyField().forEach(enemyPokemon => enemyPokemon.transferTagsBySourceId(this.lastPokemon.id, switchedPokemon.id));
(this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.transferTagsBySourceId(this.lastPokemon.id, switchedPokemon.id));
if (!this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedPokemon.id)) {
const batonPassModifier = this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier
&& (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id) as SwitchEffectTransferModifier;
@ -1427,6 +1427,40 @@ export class EnemyCommandPhase extends FieldPhase {
const enemyPokemon = this.scene.getEnemyField()[this.fieldIndex];
const trainer = this.scene.currentBattle.trainer;
if (trainer) {
const opponents = enemyPokemon.getOpponents();
const trapTag = enemyPokemon.findTag(t => t instanceof TrappedTag) as TrappedTag;
const trapped = new Utils.BooleanHolder(false);
opponents.forEach(playerPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, playerPokemon, trapped));
if (enemyPokemon.moveset.find(m => m.moveId === Moves.BATON_PASS && m.isUsable(enemyPokemon)) && (enemyPokemon.summonData.battleStats.reduce((total, stat) => total += stat, 0) >= 0 || trapTag || trapped.value)) {
this.scene.currentBattle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] =
{ command: Command.FIGHT, move: { move: Moves.BATON_PASS, targets: enemyPokemon.getNextTargets(Moves.BATON_PASS) } };
return this.end();
} else if (!trapTag && !trapped.value) {
const partyMemberScores = trainer.getPartyMemberMatchupScores();
if (partyMemberScores.length) {
const matchupScores = opponents.map(opp => enemyPokemon.getMatchupScore(opp));
const matchupScore = matchupScores.reduce((total, score) => total += score, 0) / matchupScores.length;
const sortedPartyMemberScores = trainer.getSortedPartyMemberMatchupScores(partyMemberScores);
if (sortedPartyMemberScores[0][1] >= matchupScore * (trainer.config.isBoss ? 2 : 3)) {
const index = trainer.getNextSummonIndex(partyMemberScores);
this.scene.currentBattle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] =
{ command: Command.POKEMON, cursor: index, args: [ false ] };
return this.end();
}
}
}
}
const nextMove = enemyPokemon.getNextMove();
this.scene.currentBattle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] =
@ -1527,7 +1561,7 @@ export class TurnStartPhase extends FieldPhase {
case Command.RUN:
const isSwitch = turnCommand.command === Command.POKEMON;
if (isSwitch)
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, pokemon.getFieldIndex(), turnCommand.cursor, true, turnCommand.args[0] as boolean));
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, pokemon.getFieldIndex(), turnCommand.cursor, true, turnCommand.args[0] as boolean, pokemon.isPlayer()));
else
this.scene.unshiftPhase(new AttemptRunPhase(this.scene, pokemon.getFieldIndex()));
break;

View File

@ -1737,6 +1737,10 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
return (!player && !user.scene.currentBattle.battleType) || party.filter(p => !p.isFainted()).length > user.scene.currentBattle.getBattlerCount();
};
}
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
return -100; // Overridden in switch logic
}
}
export class CopyTypeAttr extends MoveEffectAttr {

View File

@ -902,7 +902,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (this.battleInfo.visible) {
this.scene.tweens.add({
targets: this.battleInfo,
x: this.isPlayer() ? '+=150' : `-=${!this.isBoss() ? 150 : 198}`,
x: this.isPlayer() ? '+=150' : `-=${!this.isBoss() ? 150 : 246}`,
duration: 500,
ease: 'Sine.easeIn',
onComplete: () => {

View File

@ -198,21 +198,27 @@ export default class Trainer extends Phaser.GameObjects.Container {
return ret;
}
getNextSummonIndex(): integer {
getPartyMemberMatchupScores(): [integer, integer][] {
const party = this.scene.getEnemyParty();
const nonFaintedPartyMembers = party.slice(this.scene.currentBattle.getBattlerCount()).filter(p => !p.isFainted());
const partyMemberScores = nonFaintedPartyMembers.map(p => {
const playerField = this.scene.getPlayerField();
let score = 0;
let ret: [integer, integer];
for (let playerPokemon of playerField) {
score += p.getMatchupScore(playerPokemon);
if (playerPokemon.species.legendary)
score /= 2;
}
score /= playerField.length;
return [ party.indexOf(p), score ];
ret = [ party.indexOf(p), score ];
return ret;
});
return partyMemberScores;
}
getSortedPartyMemberMatchupScores(partyMemberScores: [integer, integer][] = this.getPartyMemberMatchupScores()) {
const sortedPartyMemberScores = partyMemberScores.slice(0);
sortedPartyMemberScores.sort((a, b) => {
const scoreA = a[1];
@ -220,8 +226,21 @@ export default class Trainer extends Phaser.GameObjects.Container {
return scoreA < scoreB ? 1 : scoreA > scoreB ? -1 : 0;
});
return sortedPartyMemberScores;
}
getNextSummonIndex(partyMemberScores: [integer, integer][] = this.getPartyMemberMatchupScores()): integer {
const sortedPartyMemberScores = this.getSortedPartyMemberMatchupScores(partyMemberScores);
const maxScorePartyMemberIndexes = partyMemberScores.filter(pms => pms[1] === sortedPartyMemberScores[0][1]).map(pms => pms[0]);
return maxScorePartyMemberIndexes[Utils.randSeedInt(maxScorePartyMemberIndexes.length)];
if (maxScorePartyMemberIndexes.length > 1) {
let rand: integer;
this.scene.executeWithSeedOffset(() => rand = Utils.randSeedInt(maxScorePartyMemberIndexes.length), this.scene.currentBattle.turn << 2);
return maxScorePartyMemberIndexes[rand];
}
return maxScorePartyMemberIndexes[0];
}
getPartyMemberModifierChanceMultiplier(index: integer): number {