From a03d7ac9ef446736fd1dcf5b370a9fcb6f55e8a6 Mon Sep 17 00:00:00 2001 From: NxKarim <43686802+NxKarim@users.noreply.github.com> Date: Fri, 3 May 2024 17:24:56 -0600 Subject: [PATCH] Implemented Merciless Attribute CritIfTargetIsPoisonedAbAttr Fix BlockCritAbAttr --- src/data/ability.ts | 25 ++++++++++++++++++++++++- src/field/pokemon.ts | 15 ++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 0ff03ed67..eb8def1be 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1822,6 +1822,29 @@ export class MultCritAbAttr extends AbAttr { } } +/** + * Attribute used by Merciless + * Guarantees a critical hit if the target is poisoned, except if target prevents critical hits. + */ +export class CritIfTargetPoisonedAbAttr extends AbAttr { + /** + * Multiplies the base additional effect chance by the given multiplier. + * @param {Pokemon} pokemon N/A + * @param {boolean} passive N/A + * @param {cancelled} cancelled N/A + * @param {any[]} args args[0]: BooleanHolder, If true critical hit is guaranteed. args[1]: Target Pokémon. + * @returns {boolean} true if function succeeds. + */ + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + const target = (args[1] as Pokemon); + if(target.status) + if(!(target.status.effect === StatusEffect.TOXIC || target.status.effect === StatusEffect.POISON)) + return false; + + (args[0] as Utils.BooleanHolder).value = true; + return true; + } +} export class BlockNonDirectDamageAbAttr extends AbAttr { apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { @@ -3442,7 +3465,7 @@ export function initAbilities() { new Ability(Abilities.WATER_COMPACTION, 7) .attr(PostDefendStatChangeAbAttr, (target, user, move) => move.type === Type.WATER && move.category !== MoveCategory.STATUS, BattleStat.DEF, 2), new Ability(Abilities.MERCILESS, 7) - .unimplemented(), + .attr(CritIfTargetPoisonedAbAttr), new Ability(Abilities.SHIELDS_DOWN, 7) .attr(PostBattleInitFormChangeAbAttr, p => p.formIndex % 7 + (p.getHpRatio() <= 0.5 ? 7 : 0)) .attr(PostSummonFormChangeAbAttr, p => p.formIndex % 7 + (p.getHpRatio() <= 0.5 ? 7 : 0)) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 97d94bdba..8531cb573 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, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr } from '../data/ability'; +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, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, CritIfTargetPoisonedAbAttr } from '../data/ability'; import { Abilities } from "#app/data/enums/abilities"; import PokemonData from '../system/pokemon-data'; import Battle, { BattlerIndex } from '../battle'; @@ -1484,6 +1484,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const critOnly = new Utils.BooleanHolder(false); const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT); applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly); + applyAbAttrs(CritIfTargetPoisonedAbAttr, source, null, critOnly, this); if (critOnly.value || critAlways) isCritical = true; else { @@ -1499,12 +1500,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { critLevel.value += 2; const critChance = [24, 8, 2, 1][Math.max(0, Math.min(critLevel.value, 3))]; isCritical = !source.getTag(BattlerTagType.NO_CRIT) && (critChance === 1 || !this.scene.randBattleSeedInt(critChance)); - if (isCritical) { - const blockCrit = new Utils.BooleanHolder(false); - applyAbAttrs(BlockCritAbAttr, this, null, blockCrit); - if (blockCrit.value) - isCritical = false; - } + } + if (isCritical) { + const blockCrit = new Utils.BooleanHolder(false); + applyAbAttrs(BlockCritAbAttr, this, null, blockCrit); + if (blockCrit.value) + isCritical = false; } const sourceAtk = new Utils.IntegerHolder(source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this, null, isCritical)); const targetDef = new Utils.IntegerHolder(this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source, move, isCritical));