mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-12-25 02:59:22 +01:00
* Grabbed reverted changes from stuff
* Added version migrator for rage fist data + deepMergeSpriteData tests
* fixed formattign
* Fied a few
* Fixed constructor (maybe), moved deepCopy and deepMergeSpriteData to own file
`common.ts` is hella bloated so seems legit
* Moved empty moveset verification mapping thing to upgrade script bc i wanted to
* Fixed tests
* test added
* Fixed summondata being cleared inside summonPhase, removed `summonDataPrimer`
like seriously how come no-one checked this
* Fixed test
I forgot that we outsped and oneshot
* Fixed test
* huhjjjjjb
* Hopefully fixed bug
my sanity and homework are paying the price for this lol
* added commented out console.log statement
uncomment to see new berry data
* Fixed migrate script, re-added deprecated attributes out of necessity
* Fixed failing test by not trying to mock rng
* Fixed test
* Fixed tests
* Update ability.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update ability.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update overrides.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update berry-phase.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update encounter-phase.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update game-data.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update move-phase.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Added utility function `randSeedFloat`
basically just `Phaser.math.RND.realInRange(0, 1)`
* Applied review comments, cleaned up code a bit
* Removed unnecessary null checks for turnData and co.
I explicitly made them initialized by default for this very reason
* Added tests for Last Resort regarding moveHistory
* Update pokemon.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update pokemon.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update pokemon.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update pokemon.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update pokemon.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update pokemon.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update pokemon.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update pokemon.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update battle-scene.ts
Co-authored-by: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com>
* Update the-winstrate-challenge-encounter.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update pokemon.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update pokemon.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update pokemon.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update ability.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update move.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update move.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update move.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update battle-anims.ts
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
* Update pokemon.ts comments
* Fixed a few outstanding issues with documentation
* Updated switch summon phase comment
* Re-added BattleSummonData as TempSummonData
* Hppefully fixed -1 sprite scale glitch
* Fixed comment
* Reveted `pokemon-forms.ts`
* Fuxed constructor
* fixed -1 bug
* Revert "Added utility function `randSeedFloat`"
This reverts commit 4c3447c851.
---------
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
Co-authored-by: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com>
252 lines
9.1 KiB
TypeScript
252 lines
9.1 KiB
TypeScript
import type { BattlerIndex } from "#app/battle";
|
|
import { BattleType } from "#enums/battle-type";
|
|
import { globalScene } from "#app/global-scene";
|
|
import {
|
|
applyPostFaintAbAttrs,
|
|
applyPostKnockOutAbAttrs,
|
|
applyPostVictoryAbAttrs,
|
|
PostFaintAbAttr,
|
|
PostKnockOutAbAttr,
|
|
PostVictoryAbAttr,
|
|
} from "#app/data/abilities/ability";
|
|
import { BattlerTagLapseType } from "#app/data/battler-tags";
|
|
import { battleSpecDialogue } from "#app/data/dialogue";
|
|
import { allMoves, PostVictoryStatStageChangeAttr } from "#app/data/moves/move";
|
|
import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms";
|
|
import { BattleSpec } from "#app/enums/battle-spec";
|
|
import { StatusEffect } from "#app/enums/status-effect";
|
|
import type { EnemyPokemon } from "#app/field/pokemon";
|
|
import type Pokemon from "#app/field/pokemon";
|
|
import { HitResult, PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
|
import { getPokemonNameWithAffix } from "#app/messages";
|
|
import { PokemonInstantReviveModifier } from "#app/modifier/modifier";
|
|
import { SwitchType } from "#enums/switch-type";
|
|
import i18next from "i18next";
|
|
import { DamageAnimPhase } from "./damage-anim-phase";
|
|
import { GameOverPhase } from "./game-over-phase";
|
|
import { PokemonPhase } from "./pokemon-phase";
|
|
import { SwitchPhase } from "./switch-phase";
|
|
import { SwitchSummonPhase } from "./switch-summon-phase";
|
|
import { ToggleDoublePositionPhase } from "./toggle-double-position-phase";
|
|
import { VictoryPhase } from "./victory-phase";
|
|
import { isNullOrUndefined } from "#app/utils/common";
|
|
import { FRIENDSHIP_LOSS_FROM_FAINT } from "#app/data/balance/starters";
|
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
|
|
|
export class FaintPhase extends PokemonPhase {
|
|
/**
|
|
* Whether or not instant revive should be prevented
|
|
*/
|
|
private preventInstantRevive: boolean;
|
|
|
|
/**
|
|
* The source Pokemon that dealt fatal damage
|
|
*/
|
|
private source?: Pokemon;
|
|
|
|
constructor(battlerIndex: BattlerIndex, preventInstantRevive = false, source?: Pokemon) {
|
|
super(battlerIndex);
|
|
|
|
this.preventInstantRevive = preventInstantRevive;
|
|
this.source = source;
|
|
}
|
|
|
|
start() {
|
|
super.start();
|
|
|
|
const faintPokemon = this.getPokemon();
|
|
|
|
if (this.source) {
|
|
faintPokemon.getTag(BattlerTagType.DESTINY_BOND)?.lapse(this.source, BattlerTagLapseType.CUSTOM);
|
|
faintPokemon.getTag(BattlerTagType.GRUDGE)?.lapse(faintPokemon, BattlerTagLapseType.CUSTOM, this.source);
|
|
}
|
|
|
|
faintPokemon.resetSummonData();
|
|
|
|
if (!this.preventInstantRevive) {
|
|
const instantReviveModifier = globalScene.applyModifier(
|
|
PokemonInstantReviveModifier,
|
|
this.player,
|
|
faintPokemon,
|
|
) as PokemonInstantReviveModifier;
|
|
|
|
if (instantReviveModifier) {
|
|
faintPokemon.loseHeldItem(instantReviveModifier);
|
|
globalScene.updateModifiers(this.player);
|
|
return this.end();
|
|
}
|
|
}
|
|
|
|
/** In case the current pokemon was just switched in, make sure it is counted as participating in the combat */
|
|
for (const pokemon of globalScene.getPlayerField()) {
|
|
if (pokemon?.isActive(true) && pokemon.isPlayer()) {
|
|
globalScene.currentBattle.addParticipant(pokemon as PlayerPokemon);
|
|
}
|
|
}
|
|
|
|
if (!this.tryOverrideForBattleSpec()) {
|
|
this.doFaint();
|
|
}
|
|
}
|
|
|
|
doFaint(): void {
|
|
const pokemon = this.getPokemon();
|
|
|
|
// Track total times pokemon have been KO'd for Last Respects/Supreme Overlord
|
|
if (pokemon.isPlayer()) {
|
|
globalScene.arena.playerFaints += 1;
|
|
globalScene.currentBattle.playerFaintsHistory.push({
|
|
pokemon: pokemon,
|
|
turn: globalScene.currentBattle.turn,
|
|
});
|
|
} else {
|
|
globalScene.currentBattle.enemyFaints += 1;
|
|
globalScene.currentBattle.enemyFaintsHistory.push({
|
|
pokemon: pokemon,
|
|
turn: globalScene.currentBattle.turn,
|
|
});
|
|
}
|
|
|
|
globalScene.queueMessage(
|
|
i18next.t("battle:fainted", {
|
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
|
}),
|
|
null,
|
|
true,
|
|
);
|
|
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
|
|
|
|
pokemon.resetTera();
|
|
|
|
if (pokemon.turnData.attacksReceived?.length) {
|
|
const lastAttack = pokemon.turnData.attacksReceived[0];
|
|
applyPostFaintAbAttrs(
|
|
PostFaintAbAttr,
|
|
pokemon,
|
|
globalScene.getPokemonById(lastAttack.sourceId)!,
|
|
new PokemonMove(lastAttack.move).getMove(),
|
|
lastAttack.result,
|
|
); // TODO: is this bang correct?
|
|
} else {
|
|
//If killed by indirect damage, apply post-faint abilities without providing a last move
|
|
applyPostFaintAbAttrs(PostFaintAbAttr, pokemon);
|
|
}
|
|
|
|
const alivePlayField = globalScene.getField(true);
|
|
for (const p of alivePlayField) {
|
|
applyPostKnockOutAbAttrs(PostKnockOutAbAttr, p, pokemon);
|
|
}
|
|
if (pokemon.turnData.attacksReceived?.length) {
|
|
const defeatSource = this.source;
|
|
|
|
if (defeatSource?.isOnField()) {
|
|
applyPostVictoryAbAttrs(PostVictoryAbAttr, defeatSource);
|
|
const pvmove = allMoves[pokemon.turnData.attacksReceived[0].move];
|
|
const pvattrs = pvmove.getAttrs(PostVictoryStatStageChangeAttr);
|
|
if (pvattrs.length) {
|
|
for (const pvattr of pvattrs) {
|
|
pvattr.applyPostVictory(defeatSource, defeatSource, pvmove);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this.player) {
|
|
/** The total number of Pokemon in the player's party that can legally fight */
|
|
const legalPlayerPokemon = globalScene.getPokemonAllowedInBattle();
|
|
/** The total number of legal player Pokemon that aren't currently on the field */
|
|
const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true));
|
|
if (!legalPlayerPokemon.length) {
|
|
/** If the player doesn't have any legal Pokemon, end the game */
|
|
globalScene.unshiftPhase(new GameOverPhase());
|
|
} else if (
|
|
globalScene.currentBattle.double &&
|
|
legalPlayerPokemon.length === 1 &&
|
|
legalPlayerPartyPokemon.length === 0
|
|
) {
|
|
/**
|
|
* If the player has exactly one Pokemon in total at this point in a double battle, and that Pokemon
|
|
* is already on the field, unshift a phase that moves that Pokemon to center position.
|
|
*/
|
|
globalScene.unshiftPhase(new ToggleDoublePositionPhase(true));
|
|
} else if (legalPlayerPartyPokemon.length > 0) {
|
|
/**
|
|
* If previous conditions weren't met, and the player has at least 1 legal Pokemon off the field,
|
|
* push a phase that prompts the player to summon a Pokemon from their party.
|
|
*/
|
|
globalScene.pushPhase(new SwitchPhase(SwitchType.SWITCH, this.fieldIndex, true, false));
|
|
}
|
|
} else {
|
|
globalScene.unshiftPhase(new VictoryPhase(this.battlerIndex));
|
|
if ([BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) {
|
|
const hasReservePartyMember = !!globalScene
|
|
.getEnemyParty()
|
|
.filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot)
|
|
.length;
|
|
if (hasReservePartyMember) {
|
|
globalScene.pushPhase(new SwitchSummonPhase(SwitchType.SWITCH, this.fieldIndex, -1, false, false));
|
|
}
|
|
}
|
|
}
|
|
|
|
// in double battles redirect potential moves off fainted pokemon
|
|
const allyPokemon = pokemon.getAlly();
|
|
if (globalScene.currentBattle.double && !isNullOrUndefined(allyPokemon)) {
|
|
globalScene.redirectPokemonMoves(pokemon, allyPokemon);
|
|
}
|
|
|
|
pokemon.faintCry(() => {
|
|
if (pokemon instanceof PlayerPokemon) {
|
|
pokemon.addFriendship(-FRIENDSHIP_LOSS_FROM_FAINT);
|
|
}
|
|
pokemon.hideInfo();
|
|
globalScene.playSound("se/faint");
|
|
globalScene.tweens.add({
|
|
targets: pokemon,
|
|
duration: 500,
|
|
y: pokemon.y + 150,
|
|
ease: "Sine.easeIn",
|
|
onComplete: () => {
|
|
pokemon.lapseTags(BattlerTagLapseType.FAINT);
|
|
|
|
pokemon.y -= 150;
|
|
pokemon.trySetStatus(StatusEffect.FAINT);
|
|
if (pokemon.isPlayer()) {
|
|
globalScene.currentBattle.removeFaintedParticipant(pokemon as PlayerPokemon);
|
|
} else {
|
|
globalScene.addFaintedEnemyScore(pokemon as EnemyPokemon);
|
|
globalScene.currentBattle.addPostBattleLoot(pokemon as EnemyPokemon);
|
|
}
|
|
pokemon.leaveField();
|
|
this.end();
|
|
},
|
|
});
|
|
});
|
|
}
|
|
|
|
tryOverrideForBattleSpec(): boolean {
|
|
switch (globalScene.currentBattle.battleSpec) {
|
|
case BattleSpec.FINAL_BOSS:
|
|
if (!this.player) {
|
|
const enemy = this.getPokemon();
|
|
if (enemy.formIndex) {
|
|
globalScene.ui.showDialogue(
|
|
battleSpecDialogue[BattleSpec.FINAL_BOSS].secondStageWin,
|
|
enemy.species.name,
|
|
null,
|
|
() => this.doFaint(),
|
|
);
|
|
} else {
|
|
// Final boss' HP threshold has been bypassed; cancel faint and force check for 2nd phase
|
|
enemy.hp++;
|
|
globalScene.unshiftPhase(new DamageAnimPhase(enemy.getBattlerIndex(), 0, HitResult.INDIRECT));
|
|
this.end();
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|