Properly implement Soul-Heart, Fix Opponent Stage boosts on faints (#53)
* Properly implement Soul-Heart, Fix Opponent Stage boosts on faints add phases.ts remove unused import spacing fix * simplify alivePlayFieldpull/57/head
parent
d41101083e
commit
fb9f5dad11
|
@ -795,6 +795,33 @@ class PostVictoryStatChangeAbAttr extends PostVictoryAbAttr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class PostKnockOutAbAttr extends AbAttr {
|
||||||
|
applyPostKnockOut(pokemon: Pokemon, args: any[]): boolean | Promise<boolean> {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PostKnockOutStatChangeAbAttr extends PostKnockOutAbAttr {
|
||||||
|
private stat: BattleStat | ((p: Pokemon) => BattleStat);
|
||||||
|
private levels: integer;
|
||||||
|
|
||||||
|
constructor(stat: BattleStat | ((p: Pokemon) => BattleStat), levels: integer) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.stat = stat;
|
||||||
|
this.levels = levels;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPostKnockOut(pokemon: Pokemon, args: any[]): boolean | Promise<boolean> {
|
||||||
|
const stat = typeof this.stat === 'function'
|
||||||
|
? this.stat(pokemon)
|
||||||
|
: this.stat;
|
||||||
|
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ stat ], this.levels));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class IgnoreOpponentStatChangesAbAttr extends AbAttr {
|
export class IgnoreOpponentStatChangesAbAttr extends AbAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(false);
|
super(false);
|
||||||
|
@ -1696,6 +1723,11 @@ export function applyPostAttackAbAttrs(attrType: { new(...args: any[]): PostAtta
|
||||||
return applyAbAttrsInternal<PostAttackAbAttr>(attrType, pokemon, attr => attr.applyPostAttack(pokemon, defender, move, hitResult, args), args);
|
return applyAbAttrsInternal<PostAttackAbAttr>(attrType, pokemon, attr => attr.applyPostAttack(pokemon, defender, move, hitResult, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function applyPostKnockOutAbAttrs(attrType: { new(...args: any[]): PostKnockOutAbAttr },
|
||||||
|
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
||||||
|
return applyAbAttrsInternal<PostKnockOutAbAttr>(attrType, pokemon, attr => attr.applyPostKnockOut(pokemon, args), args);
|
||||||
|
}
|
||||||
|
|
||||||
export function applyPostVictoryAbAttrs(attrType: { new(...args: any[]): PostVictoryAbAttr },
|
export function applyPostVictoryAbAttrs(attrType: { new(...args: any[]): PostVictoryAbAttr },
|
||||||
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostVictoryAbAttr>(attrType, pokemon, attr => attr.applyPostVictory(pokemon, args), args);
|
return applyAbAttrsInternal<PostVictoryAbAttr>(attrType, pokemon, attr => attr.applyPostVictory(pokemon, args), args);
|
||||||
|
@ -2571,8 +2603,8 @@ export function initAbilities() {
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.DAZZLING, "Dazzling (N)", "Surprises the opposing Pokémon, making it unable to attack using priority moves.", 7)
|
new Ability(Abilities.DAZZLING, "Dazzling (N)", "Surprises the opposing Pokémon, making it unable to attack using priority moves.", 7)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.SOUL_HEART, "Soul-Heart (P)", "Boosts its Sp. Atk stat every time a Pokémon faints.", 7)
|
new Ability(Abilities.SOUL_HEART, "Soul-Heart", "Boosts its Sp. Atk stat every time a Pokémon faints.", 7)
|
||||||
.attr(PostVictoryStatChangeAbAttr, BattleStat.SPATK, 1),
|
.attr(PostKnockOutStatChangeAbAttr, BattleStat.SPATK, 1),
|
||||||
new Ability(Abilities.TANGLING_HAIR, "Tangling Hair", "Contact with the Pokémon lowers the attacker's Speed stat.", 7)
|
new Ability(Abilities.TANGLING_HAIR, "Tangling Hair", "Contact with the Pokémon lowers the attacker's Speed stat.", 7)
|
||||||
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), BattleStat.SPD, -1, false),
|
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), BattleStat.SPD, -1, false),
|
||||||
new Ability(Abilities.RECEIVER, "Receiver (N)", "The Pokémon copies the Ability of a defeated ally.", 7),
|
new Ability(Abilities.RECEIVER, "Receiver (N)", "The Pokémon copies the Ability of a defeated ally.", 7),
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, get
|
||||||
import { TempBattleStat } from "./data/temp-battle-stat";
|
import { TempBattleStat } from "./data/temp-battle-stat";
|
||||||
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
|
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
|
||||||
import { ArenaTagType } from "./data/enums/arena-tag-type";
|
import { ArenaTagType } from "./data/enums/arena-tag-type";
|
||||||
import { Abilities, CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr } from "./data/ability";
|
import { Abilities, CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr } from "./data/ability";
|
||||||
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
||||||
import { getBiomeKey } from "./field/arena";
|
import { getBiomeKey } from "./field/arena";
|
||||||
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
||||||
|
@ -2869,6 +2869,14 @@ export class FaintPhase extends PokemonPhase {
|
||||||
|
|
||||||
this.scene.queueMessage(getPokemonMessage(pokemon, ' fainted!'), null, true);
|
this.scene.queueMessage(getPokemonMessage(pokemon, ' fainted!'), null, true);
|
||||||
|
|
||||||
|
const alivePlayField = this.scene.getField(true);
|
||||||
|
alivePlayField.forEach(p => applyPostKnockOutAbAttrs(PostKnockOutAbAttr, p));
|
||||||
|
if (pokemon.turnData?.attacksReceived?.length) {
|
||||||
|
const defeatSource = this.scene.getPokemonById(pokemon.turnData.attacksReceived[0].sourceId);
|
||||||
|
if (defeatSource?.isOnField())
|
||||||
|
applyPostVictoryAbAttrs(PostVictoryAbAttr, defeatSource);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.player) {
|
if (this.player) {
|
||||||
const nonFaintedPartyMembers = this.scene.getParty().filter(p => !p.isFainted());
|
const nonFaintedPartyMembers = this.scene.getParty().filter(p => !p.isFainted());
|
||||||
const nonFaintedPartyMemberCount = nonFaintedPartyMembers.length;
|
const nonFaintedPartyMemberCount = nonFaintedPartyMembers.length;
|
||||||
|
@ -3033,13 +3041,6 @@ export class VictoryPhase extends PokemonPhase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const defeatedPokemon = this.getPokemon();
|
|
||||||
if (defeatedPokemon.turnData?.attacksReceived?.length) {
|
|
||||||
const defeatSource = this.scene.getPokemonById(defeatedPokemon.turnData.attacksReceived[0].sourceId);
|
|
||||||
if (defeatSource?.isOnField())
|
|
||||||
applyPostVictoryAbAttrs(PostVictoryAbAttr, defeatSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.scene.getEnemyParty().find(p => this.scene.currentBattle.battleType ? !p?.isFainted(true) : p.isOnField())) {
|
if (!this.scene.getEnemyParty().find(p => this.scene.currentBattle.battleType ? !p?.isFainted(true) : p.isOnField())) {
|
||||||
this.scene.pushPhase(new BattleEndPhase(this.scene));
|
this.scene.pushPhase(new BattleEndPhase(this.scene));
|
||||||
if (this.scene.currentBattle.battleType === BattleType.TRAINER)
|
if (this.scene.currentBattle.battleType === BattleType.TRAINER)
|
||||||
|
|
Loading…
Reference in New Issue