diff --git a/src/battle-scene.ts b/src/battle-scene.ts index afca4340d5c..1a30701a0f4 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -933,7 +933,7 @@ export default class BattleScene extends SceneBase { if (resetArenaState) { pokemon.resetBattleData(); - this.resetPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger); + applyPostBattleInitAbAttrs(PostBattleInitFormChangeAbAttr, pokemon, true); } this.triggerPokemonFormChange(pokemon, SpeciesFormChangeTimeOfDayTrigger); } @@ -1964,32 +1964,6 @@ export default class BattleScene extends SceneBase { return false; } - resetPokemonFormChange(pokemon: Pokemon, formChangeTriggerType: {new( ... args: any[]): SpeciesFormChangeTrigger}, delayed: boolean = false, modal: boolean = false): boolean { - if (pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId)) { - - // Find the base form that matches the same ability - const matchingFormChange = pokemonFormChanges[pokemon.species.speciesId].find(fc => fc.findTrigger(formChangeTriggerType) && - fc.formKey === pokemon.species.forms[0].formKey && - fc.canChange(pokemon)); - if (matchingFormChange) { - let phase: Phase; - if (pokemon instanceof PlayerPokemon && !matchingFormChange.quiet) - phase = new FormChangePhase(this, pokemon, matchingFormChange, modal); - else - phase = new QuietFormChangePhase(this, pokemon, matchingFormChange); - if (pokemon instanceof PlayerPokemon && !matchingFormChange.quiet && modal) - this.overridePhase(phase); - else if (delayed) - this.pushPhase(phase); - else - this.unshiftPhase(phase); - return true; - } - } - - return false; - } - validateAchvs(achvType: { new(...args: any[]): Achv }, ...args: any[]): void { const filteredAchvs = Object.values(achvs).filter(a => a instanceof achvType); for (let achv of filteredAchvs) diff --git a/src/data/ability.ts b/src/data/ability.ts index 228e7c801ad..ea49a529014 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -2783,7 +2783,7 @@ export class IgnoreTypeStatusEffectImmunityAbAttr extends AbAttr { function applyAbAttrsInternal(attrType: { new(...args: any[]): TAttr }, pokemon: Pokemon, applyFunc: AbAttrApplyFunc, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise { return new Promise(resolve => { - if (!pokemon.canApplyAbility(passive)) { + if (!pokemon.canApplyAbility(passive, args[0])) { if (!passive) return applyAbAttrsInternal(attrType, pokemon, applyFunc, args, isAsync, showAbilityInstant, quiet, true).then(() => resolve()); else @@ -3436,7 +3436,7 @@ export function initAbilities() { .attr(PostDefendContactDamageAbAttr, 8) .bypassFaint(), new Ability(Abilities.ZEN_MODE, 5) - .attr(PostBattleInitFormChangeAbAttr, p => p.getHpRatio() <= 0.5 ? 1 : 0) + .attr(PostBattleInitFormChangeAbAttr, () => 0) .attr(PostSummonFormChangeAbAttr, p => p.getHpRatio() <= 0.5 ? 1 : 0) .attr(PostTurnFormChangeAbAttr, p => p.getHpRatio() <= 0.5 ? 1 : 0) .attr(UncopiableAbilityAbAttr) @@ -3534,7 +3534,7 @@ export function initAbilities() { new Ability(Abilities.MERCILESS, 7) .attr(ConditionalCritAbAttr, (user, target, move) => target.status?.effect === StatusEffect.TOXIC || target.status?.effect === StatusEffect.POISON), new Ability(Abilities.SHIELDS_DOWN, 7) - .attr(PostBattleInitFormChangeAbAttr, p => p.formIndex % 7 + (p.getHpRatio() <= 0.5 ? 7 : 0)) + .attr(PostBattleInitFormChangeAbAttr, () => 0) .attr(PostSummonFormChangeAbAttr, p => p.formIndex % 7 + (p.getHpRatio() <= 0.5 ? 7 : 0)) .attr(PostTurnFormChangeAbAttr, p => p.formIndex % 7 + (p.getHpRatio() <= 0.5 ? 7 : 0)) .attr(UncopiableAbilityAbAttr) @@ -3567,7 +3567,7 @@ export function initAbilities() { new Ability(Abilities.SURGE_SURFER, 7) .conditionalAttr(getTerrainCondition(TerrainType.ELECTRIC), BattleStatMultiplierAbAttr, BattleStat.SPD, 2), new Ability(Abilities.SCHOOLING, 7) - .attr(PostBattleInitFormChangeAbAttr, p => p.level < 20 || p.getHpRatio() <= 0.25 ? 0 : 1) + .attr(PostBattleInitFormChangeAbAttr, () => 0) .attr(PostSummonFormChangeAbAttr, p => p.level < 20 || p.getHpRatio() <= 0.25 ? 0 : 1) .attr(PostTurnFormChangeAbAttr, p => p.level < 20 || p.getHpRatio() <= 0.25 ? 0 : 1) .attr(UncopiableAbilityAbAttr) @@ -3577,7 +3577,7 @@ export function initAbilities() { new Ability(Abilities.DISGUISE, 7) .attr(PreDefendMovePowerToOneAbAttr, (target, user, move) => target.formIndex == 0 && target.getAttackTypeEffectiveness(move.type, user) > 0) .attr(PostSummonFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) - .attr(PostBattleInitFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) + .attr(PostBattleInitFormChangeAbAttr, () => 0) .attr(PostDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) .attr(PreDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) .attr(PostDefendDisguiseAbAttr) @@ -3589,15 +3589,16 @@ export function initAbilities() { .ignorable() .partial(), new Ability(Abilities.BATTLE_BOND, 7) - .attr(PostVictoryFormChangeAbAttr, p => p.getFormKey() ? 2 : 1) + .attr(PostVictoryFormChangeAbAttr, () => 2) + .attr(PostBattleInitFormChangeAbAttr, () => 1) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) .attr(UnsuppressableAbilityAbAttr) .attr(NoFusionAbilityAbAttr), new Ability(Abilities.POWER_CONSTRUCT, 7) // TODO: 10% Power Construct Zygarde isn't accounted for yet. If changed, update Zygarde's getSpeciesFormIndex entry accordingly - .attr(PostBattleInitFormChangeAbAttr, p => p.getHpRatio() <= 0.5 || p.getFormKey() === 'complete' ? 4 : 0) - .attr(PostSummonFormChangeAbAttr, p => p.getHpRatio() <= 0.5 || p.getFormKey() === 'complete' ? 4 : 0) - .attr(PostTurnFormChangeAbAttr, p => p.getHpRatio() <= 0.5 || p.getFormKey() === 'complete' ? 4 : 0) + .attr(PostBattleInitFormChangeAbAttr, () => 2) + .attr(PostSummonFormChangeAbAttr, p => p.getHpRatio() <= 0.5 || p.getFormKey() === 'complete' ? 4 : 2) + .attr(PostTurnFormChangeAbAttr, p => p.getHpRatio() <= 0.5 || p.getFormKey() === 'complete' ? 4 : 2) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) .attr(UnsuppressableAbilityAbAttr) @@ -3823,7 +3824,8 @@ export function initAbilities() { .attr(UnsuppressableAbilityAbAttr) .attr(NoTransformAbilityAbAttr) .attr(NoFusionAbilityAbAttr) - .attr(PreSwitchOutFormChangeAbAttr, p => p.getFormKey() ? 1 : 0), + .attr(PostBattleInitFormChangeAbAttr, () => 0) + .attr(PreSwitchOutFormChangeAbAttr, () => 1), new Ability(Abilities.COMMANDER, 9) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) @@ -3905,22 +3907,26 @@ export function initAbilities() { .attr(PostBattleInitStatChangeAbAttr, BattleStat.SPD, 1, true) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) - .attr(NoTransformAbilityAbAttr), + .attr(NoTransformAbilityAbAttr) + .partial(), new Ability(Abilities.EMBODY_ASPECT_WELLSPRING, 9) .attr(PostBattleInitStatChangeAbAttr, BattleStat.SPDEF, 1, true) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) - .attr(NoTransformAbilityAbAttr), + .attr(NoTransformAbilityAbAttr) + .partial(), new Ability(Abilities.EMBODY_ASPECT_HEARTHFLAME, 9) .attr(PostBattleInitStatChangeAbAttr, BattleStat.ATK, 1, true) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) - .attr(NoTransformAbilityAbAttr), + .attr(NoTransformAbilityAbAttr) + .partial(), new Ability(Abilities.EMBODY_ASPECT_CORNERSTONE, 9) .attr(PostBattleInitStatChangeAbAttr, BattleStat.DEF, 1, true) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) - .attr(NoTransformAbilityAbAttr), + .attr(NoTransformAbilityAbAttr) + .partial(), new Ability(Abilities.TERA_SHIFT, 9) .attr(PostSummonFormChangeAbAttr, p => p.getFormKey() ? 0 : 1) .attr(UncopiableAbilityAbAttr) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index a1347bcd256..9d9b5712848 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -890,7 +890,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param {boolean} passive If true, check if passive can be applied instead of non-passive * @returns {Ability} The passive ability of the pokemon */ - canApplyAbility(passive: boolean = false): boolean { + canApplyAbility(passive: boolean = false, forceBypass: boolean = false): boolean { if (passive && !this.hasPassive()) return false; const ability = (!passive ? this.getAbility() : this.getPassiveAbility()); @@ -911,7 +911,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (suppressed.value) return false; } - return (this.hp || ability.isBypassFaint) && !ability.conditions.find(condition => !condition(this)); + return (this.hp || ability.isBypassFaint || forceBypass) && !ability.conditions.find(condition => !condition(this)); } /** diff --git a/src/phases.ts b/src/phases.ts index 744b6b5fb9d..26660100e2d 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -936,17 +936,13 @@ export class EncounterPhase extends BattlePhase { if (!this.loaded) { const availablePartyMembers = this.scene.getParty().filter(p => !p.isFainted()); - if (availablePartyMembers[0].isOnField()) - applyPostBattleInitAbAttrs(PostBattleInitAbAttr, availablePartyMembers[0]); - else + if (!availablePartyMembers[0].isOnField()) this.scene.pushPhase(new SummonPhase(this.scene, 0)); if (this.scene.currentBattle.double) { if (availablePartyMembers.length > 1) { this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, true)); - if (availablePartyMembers[1].isOnField()) - applyPostBattleInitAbAttrs(PostBattleInitAbAttr, availablePartyMembers[1]); - else + if (!availablePartyMembers[1].isOnField()) this.scene.pushPhase(new SummonPhase(this.scene, 1)); } } else { @@ -1397,8 +1393,6 @@ export class SwitchSummonPhase extends SummonPhase { if (!this.batonPass) (this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.removeTagsBySourceId(pokemon.id)); - applyPreSwitchOutAbAttrs(PreSwitchOutAbAttr, pokemon); - this.scene.ui.showText(this.player ? i18next.t('battle:playerComeBack', { pokemonName: pokemon.name }) : i18next.t('battle:trainerComeBack', { @@ -1427,6 +1421,7 @@ export class SwitchSummonPhase extends SummonPhase { const party = this.player ? this.getParty() : this.scene.getEnemyParty(); const switchedPokemon = party[this.slotIndex]; this.lastPokemon = this.getPokemon(); + applyPreSwitchOutAbAttrs(PreSwitchOutAbAttr, this.lastPokemon); if (this.batonPass && switchedPokemon) { (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)) {