Trainers switch out their Pokemon when at a disadvantage
This commit is contained in:
parent
f49a3e5127
commit
8c4f336cd6
|
@ -967,7 +967,7 @@ export class SwitchSummonPhase extends SummonPhase {
|
||||||
if (!this.player && this.slotIndex === -1)
|
if (!this.player && this.slotIndex === -1)
|
||||||
this.slotIndex = this.scene.currentBattle.trainer.getNextSummonIndex();
|
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();
|
this.switchAndSummon();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -975,7 +975,7 @@ export class SwitchSummonPhase extends SummonPhase {
|
||||||
const pokemon = this.getPokemon();
|
const pokemon = this.getPokemon();
|
||||||
|
|
||||||
if (!this.batonPass)
|
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.ui.showText(this.player ? `Come back, ${pokemon.name}!` : `${this.scene.currentBattle.trainer.getName()}\nwithdrew ${pokemon.name}!`);
|
||||||
this.scene.playSound('pb_rel');
|
this.scene.playSound('pb_rel');
|
||||||
|
@ -996,11 +996,11 @@ export class SwitchSummonPhase extends SummonPhase {
|
||||||
}
|
}
|
||||||
|
|
||||||
switchAndSummon() {
|
switchAndSummon() {
|
||||||
const party = this.getParty();
|
const party = this.player ? this.getParty() : this.scene.getEnemyParty();
|
||||||
const switchedPokemon = party[this.slotIndex];
|
const switchedPokemon = party[this.slotIndex];
|
||||||
this.lastPokemon = this.getPokemon();
|
this.lastPokemon = this.getPokemon();
|
||||||
if (this.batonPass && switchedPokemon) {
|
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)) {
|
if (!this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedPokemon.id)) {
|
||||||
const batonPassModifier = this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier
|
const batonPassModifier = this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier
|
||||||
&& (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id) as 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 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();
|
const nextMove = enemyPokemon.getNextMove();
|
||||||
|
|
||||||
this.scene.currentBattle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] =
|
this.scene.currentBattle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] =
|
||||||
|
@ -1527,7 +1561,7 @@ export class TurnStartPhase extends FieldPhase {
|
||||||
case Command.RUN:
|
case Command.RUN:
|
||||||
const isSwitch = turnCommand.command === Command.POKEMON;
|
const isSwitch = turnCommand.command === Command.POKEMON;
|
||||||
if (isSwitch)
|
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
|
else
|
||||||
this.scene.unshiftPhase(new AttemptRunPhase(this.scene, pokemon.getFieldIndex()));
|
this.scene.unshiftPhase(new AttemptRunPhase(this.scene, pokemon.getFieldIndex()));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -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();
|
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 {
|
export class CopyTypeAttr extends MoveEffectAttr {
|
||||||
|
|
|
@ -902,7 +902,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
if (this.battleInfo.visible) {
|
if (this.battleInfo.visible) {
|
||||||
this.scene.tweens.add({
|
this.scene.tweens.add({
|
||||||
targets: this.battleInfo,
|
targets: this.battleInfo,
|
||||||
x: this.isPlayer() ? '+=150' : `-=${!this.isBoss() ? 150 : 198}`,
|
x: this.isPlayer() ? '+=150' : `-=${!this.isBoss() ? 150 : 246}`,
|
||||||
duration: 500,
|
duration: 500,
|
||||||
ease: 'Sine.easeIn',
|
ease: 'Sine.easeIn',
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
|
|
|
@ -198,21 +198,27 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
getNextSummonIndex(): integer {
|
getPartyMemberMatchupScores(): [integer, integer][] {
|
||||||
const party = this.scene.getEnemyParty();
|
const party = this.scene.getEnemyParty();
|
||||||
const nonFaintedPartyMembers = party.slice(this.scene.currentBattle.getBattlerCount()).filter(p => !p.isFainted());
|
const nonFaintedPartyMembers = party.slice(this.scene.currentBattle.getBattlerCount()).filter(p => !p.isFainted());
|
||||||
const partyMemberScores = nonFaintedPartyMembers.map(p => {
|
const partyMemberScores = nonFaintedPartyMembers.map(p => {
|
||||||
const playerField = this.scene.getPlayerField();
|
const playerField = this.scene.getPlayerField();
|
||||||
let score = 0;
|
let score = 0;
|
||||||
|
let ret: [integer, integer];
|
||||||
for (let playerPokemon of playerField) {
|
for (let playerPokemon of playerField) {
|
||||||
score += p.getMatchupScore(playerPokemon);
|
score += p.getMatchupScore(playerPokemon);
|
||||||
if (playerPokemon.species.legendary)
|
if (playerPokemon.species.legendary)
|
||||||
score /= 2;
|
score /= 2;
|
||||||
}
|
}
|
||||||
score /= playerField.length;
|
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);
|
const sortedPartyMemberScores = partyMemberScores.slice(0);
|
||||||
sortedPartyMemberScores.sort((a, b) => {
|
sortedPartyMemberScores.sort((a, b) => {
|
||||||
const scoreA = a[1];
|
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 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]);
|
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 {
|
getPartyMemberModifierChanceMultiplier(index: integer): number {
|
||||||
|
|
Loading…
Reference in New Issue