Faint bypass on canApplyAbility

This commit is contained in:
Frederico Santos 2024-05-22 00:13:42 +01:00
parent 83c00398fc
commit 7fb33b0542
4 changed files with 26 additions and 51 deletions

View File

@ -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)

View File

@ -2783,7 +2783,7 @@ export class IgnoreTypeStatusEffectImmunityAbAttr extends AbAttr {
function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any[]): TAttr },
pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise<void> {
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)

View File

@ -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));
}
/**

View File

@ -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)) {