diff --git a/src/data/ability.ts b/src/data/ability.ts index 7ac3e7218..b140590a5 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -304,19 +304,28 @@ export class ReceivedTypeDamageMultiplierAbAttr extends ReceivedMoveDamageMultip } } -export class PreDefendMovePowerToOneAbAttr extends ReceivedMoveDamageMultiplierAbAttr { +export class PreDefendReceivedMoveNullifierAbAttr extends PreDefendAbAttr { + protected condition: PokemonDefendCondition; + constructor(condition: PokemonDefendCondition) { - super(condition, 1); + super(); + + this.condition = condition; } applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { - if (this.condition(pokemon, attacker, move.getMove())) { + if (this.condition(pokemon, attacker, move.getMove()) && (args[1] as Utils.NumberHolder).value != HitResult.NO_EFFECT && (args[1] as Utils.NumberHolder).value != HitResult.FAIL) { (args[0] as Utils.NumberHolder).value = 1; + (args[1] as Utils.NumberHolder).value = HitResult.EFFECTIVE; return true; } return false; } + + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + return `Its disguise served it as a decoy!`; + } } export class TypeImmunityAbAttr extends PreDefendAbAttr { @@ -445,19 +454,27 @@ export class PostDefendAbAttr extends AbAttr { } export class PostDefendDisguiseAbAttr extends PostDefendAbAttr { + protected condition: PokemonDefendCondition; + + constructor(condition: PokemonDefendCondition) { + super(true); + this.condition = condition; + } applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { - if (pokemon.formIndex == 0 && pokemon.battleData.hitCount != 0 && (move.getMove().category == MoveCategory.SPECIAL || move.getMove().category == MoveCategory.PHYSICAL)) { - - const recoilDamage = Math.ceil((pokemon.getMaxHp() / 8) - attacker.turnData.damageDealt); + + if (this.condition(pokemon, attacker, move.getMove()) && (hitResult == HitResult.EFFECTIVE)) { + const damageDealt = attacker.turnData.damageDealt; + let recoilDamage = Math.round(pokemon.getMaxHp() / 8 - damageDealt); if (!recoilDamage) - return false; + return false; + pokemon.damageAndUpdate(recoilDamage, HitResult.OTHER); + pokemon.battleData.abilityTriggered = true; pokemon.turnData.damageTaken += recoilDamage; pokemon.scene.queueMessage(getPokemonMessage(pokemon, '\'s disguise was busted!')); return true; } - return false; } } @@ -1666,6 +1683,25 @@ export class BlockNonDirectDamageAbAttr extends AbAttr { } } +export class DisguiseConfusionDamageInteractionAbAttr extends AbAttr { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + + if(pokemon.battleData.abilityTriggered == true) + return false; + + cancelled.value = true; + pokemon.damageAndUpdate(Math.round(pokemon.getMaxHp() / 8), HitResult.OTHER); + pokemon.battleData.abilityTriggered = true; + pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); + pokemon.scene.queueMessage(`Its disguise served it as a decoy!`); + return true; + } + + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + return `${pokemon.name}\'s disguise was busted!`; + } +} + export class BlockOneHitKOAbAttr extends AbAttr { apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; @@ -3143,12 +3179,13 @@ export function initAbilities() { .attr(UnsuppressableAbilityAbAttr) .attr(NoFusionAbilityAbAttr), new Ability(Abilities.DISGUISE, 7) - .attr(PreDefendMovePowerToOneAbAttr, (target, user, move) => target.formIndex == 0 && target.getAttackTypeEffectiveness(move.type) > 0) - .attr(PostSummonFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) - .attr(PostBattleInitFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) - .attr(PostDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) - .attr(PreDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) - .attr(PostDefendDisguiseAbAttr) + .attr(DisguiseConfusionDamageInteractionAbAttr) + .attr(PreDefendReceivedMoveNullifierAbAttr, (target, user, move) => target.battleData.abilityTriggered == false) + .attr(PostDefendDisguiseAbAttr, (target, user, move) => target.battleData.abilityTriggered == false) + .attr(PreDefendFormChangeAbAttr, p => p.battleData.abilityTriggered == false ? 0 : 1) + .attr(PostSummonFormChangeAbAttr, p => p.battleData.abilityTriggered == false ? 0 : 1) + .attr(PostBattleInitFormChangeAbAttr, p => p.battleData.abilityTriggered == false ? 0 : 1) + .attr(PostDefendFormChangeAbAttr, p => p.battleData.abilityTriggered == false ? 0 : 1) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) .attr(UnsuppressableAbilityAbAttr) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 8ff684394..01c88d0db 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -8,7 +8,7 @@ import * as Utils from "../utils"; import { Moves } from "./enums/moves"; import { ChargeAttr, MoveFlags, allMoves } from "./move"; import { Type } from "./type"; -import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs } from "./ability"; +import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs, DisguiseConfusionDamageInteractionAbAttr } from "./ability"; import { Abilities } from "./enums/abilities"; import { BattlerTagType } from "./enums/battler-tag-type"; import { TerrainType } from "./terrain"; @@ -226,8 +226,15 @@ export class ConfusedTag extends BattlerTag { const def = pokemon.getBattleStat(Stat.DEF); const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100)); pokemon.scene.queueMessage('It hurt itself in its\nconfusion!'); - pokemon.damageAndUpdate(damage); - pokemon.battleData.hitCount++; + + const cancelled = new Utils.BooleanHolder(false); + applyAbAttrs(DisguiseConfusionDamageInteractionAbAttr, pokemon, cancelled); + + if (!cancelled.value) { + pokemon.damageAndUpdate(damage); + pokemon.battleData.hitCount++; + } + (pokemon.scene.getCurrentPhase() as MovePhase).cancel(); } } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 909d255ee..0f775e2da 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -27,7 +27,7 @@ import { TempBattleStat } from '../data/temp-battle-stat'; import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag'; import { ArenaTagType } from "../data/enums/arena-tag-type"; import { Biome } from "../data/enums/biome"; -import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr } from '../data/ability'; +import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, PreDefendReceivedMoveNullifierAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr } from '../data/ability'; import { Abilities } from "#app/data/enums/abilities"; import PokemonData from '../system/pokemon-data'; import Battle, { BattlerIndex } from '../battle'; @@ -1411,7 +1411,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (power.value === 0) { damage.value = 0; } - + + let preResult = new Utils.NumberHolder(result); + applyPreDefendAbAttrs(PreDefendReceivedMoveNullifierAbAttr, this, source, battlerMove, cancelled, damage , preResult); + result = (preResult as Utils.NumberHolder).value; + console.log('damage', damage.value, move.name, power.value, sourceAtk, targetDef); if (damage.value) { @@ -3054,6 +3058,7 @@ export class PokemonBattleData { public hitCount: integer = 0; public endured: boolean = false; public berriesEaten: BerryType[] = []; + public abilityTriggered: boolean = false; } export class PokemonBattleSummonData {