pokerogue/src/phases/summon-phase.ts

251 lines
9.4 KiB
TypeScript
Raw Normal View History

2024-08-19 03:23:52 +01:00
import BattleScene from "#app/battle-scene.js";
import { BattleType } from "#app/battle.js";
import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball.js";
import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms.js";
import { TrainerSlot } from "#app/data/trainer-config.js";
import { PlayerGender } from "#app/enums/player-gender.js";
import { addPokeballOpenParticles } from "#app/field/anims.js";
import Pokemon, { FieldPosition } from "#app/field/pokemon.js";
import { getPokemonNameWithAffix } from "#app/messages.js";
import i18next from "i18next";
import { PartyMemberPokemonPhase } from "./party-member-pokemon-phase";
import { PostSummonPhase } from "./post-summon-phase";
import { GameOverPhase } from "./game-over-phase";
import { ShinySparklePhase } from "./shiny-sparkle-phase";
2024-08-22 14:13:58 -04:00
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
2024-08-19 03:23:52 +01:00
export class SummonPhase extends PartyMemberPokemonPhase {
private loaded: boolean;
constructor(scene: BattleScene, fieldIndex: integer, player: boolean = true, loaded: boolean = false) {
super(scene, fieldIndex, player);
this.loaded = loaded;
}
start() {
super.start();
this.preSummon();
}
/**
* Sends out a Pokemon before the battle begins and shows the appropriate messages
*/
preSummon(): void {
const partyMember = this.getPokemon();
2024-08-22 14:13:58 -04:00
// If the Pokemon about to be sent out is fainted, illegal under a challenge, or no longer in the party for some reason, switch to the first non-fainted legal Pokemon
if (!partyMember.isAllowedInBattle() || (this.player && !this.getParty().some(p => p.id === partyMember.id))) {
2024-08-19 03:23:52 +01:00
console.warn("The Pokemon about to be sent out is fainted or illegal under a challenge. Attempting to resolve...");
// First check if they're somehow still in play, if so remove them.
if (partyMember.isOnField()) {
partyMember.leaveField();
}
const party = this.getParty();
// Find the first non-fainted Pokemon index above the current one
const legalIndex = party.findIndex((p, i) => i > this.partyMemberIndex && p.isAllowedInBattle());
if (legalIndex === -1) {
console.error("Party Details:\n", party);
console.error("All available Pokemon were fainted or illegal!");
this.scene.clearPhaseQueue();
this.scene.unshiftPhase(new GameOverPhase(this.scene));
this.end();
return;
}
// Swaps the fainted Pokemon and the first non-fainted legal Pokemon in the party
[party[this.partyMemberIndex], party[legalIndex]] = [party[legalIndex], party[this.partyMemberIndex]];
console.warn("Swapped %s %O with %s %O", getPokemonNameWithAffix(partyMember), partyMember, getPokemonNameWithAffix(party[0]), party[0]);
}
if (this.player) {
this.scene.ui.showText(i18next.t("battle:playerGo", { pokemonName: getPokemonNameWithAffix(this.getPokemon()) }));
if (this.player) {
this.scene.pbTray.hide();
}
this.scene.trainer.setTexture(`trainer_${this.scene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}_back_pb`);
this.scene.time.delayedCall(562, () => {
this.scene.trainer.setFrame("2");
this.scene.time.delayedCall(64, () => {
this.scene.trainer.setFrame("3");
});
});
this.scene.tweens.add({
targets: this.scene.trainer,
x: -36,
duration: 1000,
onComplete: () => this.scene.trainer.setVisible(false)
});
this.scene.time.delayedCall(750, () => this.summon());
2024-08-22 14:13:58 -04:00
} else if (this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
2024-08-19 03:23:52 +01:00
const trainerName = this.scene.currentBattle.trainer?.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER);
const pokemonName = this.getPokemon().getNameToRender();
const message = i18next.t("battle:trainerSendOut", { trainerName, pokemonName });
this.scene.pbTrayEnemy.hide();
this.scene.ui.showText(message, null, () => this.summon());
2024-08-22 14:13:58 -04:00
} else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER) {
this.scene.pbTrayEnemy.hide();
this.summonWild();
2024-08-19 03:23:52 +01:00
}
}
summon(): void {
const pokemon = this.getPokemon();
const pokeball = this.scene.addFieldSprite(this.player ? 36 : 248, this.player ? 80 : 44, "pb", getPokeballAtlasKey(pokemon.pokeball));
pokeball.setVisible(false);
pokeball.setOrigin(0.5, 0.625);
this.scene.field.add(pokeball);
if (this.fieldIndex === 1) {
pokemon.setFieldPosition(FieldPosition.RIGHT, 0);
} else {
const availablePartyMembers = this.getParty().filter(p => p.isAllowedInBattle()).length;
pokemon.setFieldPosition(!this.scene.currentBattle.double || availablePartyMembers === 1 ? FieldPosition.CENTER : FieldPosition.LEFT);
}
const fpOffset = pokemon.getFieldPositionOffset();
pokeball.setVisible(true);
this.scene.tweens.add({
targets: pokeball,
duration: 650,
x: (this.player ? 100 : 236) + fpOffset[0]
});
this.scene.tweens.add({
targets: pokeball,
duration: 150,
ease: "Cubic.easeOut",
y: (this.player ? 70 : 34) + fpOffset[1],
onComplete: () => {
this.scene.tweens.add({
targets: pokeball,
duration: 500,
ease: "Cubic.easeIn",
angle: 1440,
y: (this.player ? 132 : 86) + fpOffset[1],
onComplete: () => {
[Refactor][QoL] Game Audio + New Settings (#3527) * Changed how non-BGM are loaded into the game + moved into directories * some leftovers * Apply suggestions from code review Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> * Added setting for Field Volume + rewrote playSound() and updateSoundVolume() functions to reflect the new settings. * Main -> Beta (#3635) * Fixed issue with falsy issue within condition to get a stat for IV scanner * add fix setting code to prevent form/variant bug when default form/variant setting is wrong. in addition, that fix code include gender fix, so i revert old gender fix. update wrong log message. * [Hotfix] Fix Memory Mushroom not showing relearner moves (#3619) * Fix Memory Mushroom not showing relearner moves * Fix rollout test * Rewrite player faint logic in FaintPhase (#3614) * 867 runerigus sprite (#3629) cropped static frames, fixed cropped sprite set runerigus exp to use the shiny exp's animation verified all hex colors are unchanged - fixed ultra necrozma exp front variant swapped arrays. - xatu female eye color fix * [Bug] Preventing the MBH from being stolen in Endless (#3630) * Endless MBH Fix * add import * Revert "add import" This reverts commit 814a4059c2830e972c348d698259535e117850bf. * Revert "Endless MBH Fix" This reverts commit 8eb448130132ff9eed614a2ec576926814008df0. * removed newline --------- Co-authored-by: Frederico Santos <frederico.f.santos@tecnico.ulisboa.pt> Co-authored-by: frutescens <info@laptop> * [Bug] Fix type-hints for immunity (#3620) * enable mock containers to be found by name * enable mock text to be found by name * add test coverage for type-hints Only for "immunity" and "status moves" * fix wrong message key of curse(ghost type) (#3631) Co-authored-by: Frederico Santos <frederico.f.santos@tecnico.ulisboa.pt> * [Hotfix] Steal-able Mini Black Hole Pt 2 (#3632) * Still have no idea where Eternatus is given the MBH.... * typedocs --------- Co-authored-by: frutescens <info@laptop> * [Hotfix] Abilities that prevent ATK drops no longer stop other stat drops (#3624) * Abilities that prevent ATK drops no longer stop other stat drops * Apply suggestions from code review Co-authored-by: Mumble <kimjoanne@protonmail.com> * Add `isNullOrUndefined()` utility function --------- * Grip Claw now shows the proper pokemon nickname (#3634) Co-authored-by: frutescens <info@laptop> --------- Co-authored-by: Opaque02 <66582645+Opaque02@users.noreply.github.com> Co-authored-by: KimJeongSun <leo@atlaslabs.ai> Co-authored-by: Frederico Santos <frederico.f.santos@tecnico.ulisboa.pt> Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> Co-authored-by: cam <lrlrliwoo@gmail.com> Co-authored-by: Mumble <kimjoanne@protonmail.com> Co-authored-by: frutescens <info@laptop> Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> Co-authored-by: Enoch <enoch.jwsong@gmail.com> Co-authored-by: Mumble <171087428+frutescens@users.noreply.github.com> * [Bug] Preventing the MBH from being stolen in Endless (#3630) * Endless MBH Fix * add import * Revert "add import" This reverts commit 814a4059c2830e972c348d698259535e117850bf. * Revert "Endless MBH Fix" This reverts commit 8eb448130132ff9eed614a2ec576926814008df0. * removed newline --------- Co-authored-by: Frederico Santos <frederico.f.santos@tecnico.ulisboa.pt> Co-authored-by: frutescens <info@laptop> * [Hotfix] Steal-able Mini Black Hole Pt 2 (#3632) * Still have no idea where Eternatus is given the MBH.... * typedocs --------- Co-authored-by: frutescens <info@laptop> * Deleted phases.ts (#3618) * Updated sound terms * Added space for localization * Update src/locales/ko/settings.ts Co-authored-by: Enoch <enoch.jwsong@gmail.com> * Update src/locales/zh_TW/settings.ts Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Update src/locales/pt_BR/settings.ts Co-authored-by: José Ricardo Fleury Oliveira <josefleury@discente.ufg.br> * Update src/locales/zh_CN/settings.ts Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Update src/locales/de/settings.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * Update src/locales/ko/settings.ts Co-authored-by: returntoice <dieandbecome@gmail.com> * Update src/locales/fr/settings.ts Co-authored-by: Lugiad' <adrien.grivel@hotmail.fr> * Update src/locales/it/settings.ts Co-authored-by: Niccolò <123510358+NicusPulcis@users.noreply.github.com> * Include sound effects that were loaded in as BGM. * Removed stray placeholder localization --------- Co-authored-by: Frutescens <info@laptop> Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: Opaque02 <66582645+Opaque02@users.noreply.github.com> Co-authored-by: KimJeongSun <leo@atlaslabs.ai> Co-authored-by: Frederico Santos <frederico.f.santos@tecnico.ulisboa.pt> Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> Co-authored-by: cam <lrlrliwoo@gmail.com> Co-authored-by: Enoch <enoch.jwsong@gmail.com> Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> Co-authored-by: José Ricardo Fleury Oliveira <josefleury@discente.ufg.br> Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: returntoice <dieandbecome@gmail.com> Co-authored-by: Lugiad' <adrien.grivel@hotmail.fr> Co-authored-by: Niccolò <123510358+NicusPulcis@users.noreply.github.com>
2024-08-25 09:40:14 -07:00
this.scene.playSound("se/pb_rel");
2024-08-19 03:23:52 +01:00
pokeball.destroy();
this.scene.add.existing(pokemon);
this.scene.field.add(pokemon);
if (!this.player) {
const playerPokemon = this.scene.getPlayerPokemon() as Pokemon;
if (playerPokemon?.visible) {
this.scene.field.moveBelow(pokemon, playerPokemon);
}
this.scene.currentBattle.seenEnemyPartyMemberIds.add(pokemon.id);
}
addPokeballOpenParticles(this.scene, pokemon.x, pokemon.y - 16, pokemon.pokeball);
this.scene.updateModifiers(this.player);
this.scene.updateFieldScale();
pokemon.showInfo();
pokemon.playAnim();
pokemon.setVisible(true);
pokemon.getSprite().setVisible(true);
pokemon.setScale(0.5);
pokemon.tint(getPokeballTintColor(pokemon.pokeball));
pokemon.untint(250, "Sine.easeIn");
this.scene.updateFieldScale();
this.scene.tweens.add({
targets: pokemon,
duration: 250,
ease: "Sine.easeIn",
scale: pokemon.getSpriteScale(),
onComplete: () => {
pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 });
pokemon.getSprite().clearTint();
pokemon.resetSummonData();
this.scene.time.delayedCall(1000, () => this.end());
}
});
}
});
}
});
}
2024-08-22 14:13:58 -04:00
summonWild(): void {
const pokemon = this.getPokemon();
if (this.fieldIndex === 1) {
pokemon.setFieldPosition(FieldPosition.RIGHT, 0);
} else {
const availablePartyMembers = this.getParty().filter(p => !p.isFainted()).length;
pokemon.setFieldPosition(!this.scene.currentBattle.double || availablePartyMembers === 1 ? FieldPosition.CENTER : FieldPosition.LEFT);
}
this.scene.add.existing(pokemon);
this.scene.field.add(pokemon);
if (!this.player) {
const playerPokemon = this.scene.getPlayerPokemon() as Pokemon;
if (playerPokemon?.visible) {
this.scene.field.moveBelow(pokemon, playerPokemon);
}
this.scene.currentBattle.seenEnemyPartyMemberIds.add(pokemon.id);
}
this.scene.updateModifiers(this.player);
this.scene.updateFieldScale();
pokemon.showInfo();
pokemon.playAnim();
pokemon.setVisible(true);
pokemon.getSprite().setVisible(true);
pokemon.setScale(0.75);
pokemon.tint(getPokeballTintColor(pokemon.pokeball));
pokemon.untint(250, "Sine.easeIn");
this.scene.updateFieldScale();
pokemon.x += 16;
pokemon.y -= 20;
pokemon.alpha = 0;
// Ease pokemon in
this.scene.tweens.add({
targets: pokemon,
x: "-=16",
y: "+=16",
alpha: 1,
duration: 1000,
ease: "Sine.easeIn",
scale: pokemon.getSpriteScale(),
onComplete: () => {
pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 });
pokemon.getSprite().clearTint();
pokemon.resetSummonData();
this.scene.updateFieldScale();
this.scene.time.delayedCall(1000, () => this.end());
}
});
}
2024-08-19 03:23:52 +01:00
onEnd(): void {
const pokemon = this.getPokemon();
if (pokemon.isShiny()) {
this.scene.unshiftPhase(new ShinySparklePhase(this.scene, pokemon.getBattlerIndex()));
}
pokemon.resetTurnData();
2024-08-22 14:13:58 -04:00
if (!this.loaded || this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER || (this.scene.currentBattle.waveIndex % 10) === 1) {
2024-08-19 03:23:52 +01:00
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
this.queuePostSummon();
}
}
queuePostSummon(): void {
this.scene.pushPhase(new PostSummonPhase(this.scene, this.getPokemon().getBattlerIndex()));
}
end() {
this.onEnd();
super.end();
}
}