diff --git a/src/data/ability.ts b/src/data/ability.ts index eec1240e1..04c3c18fc 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -2472,6 +2472,14 @@ export class NoFusionAbilityAbAttr extends AbAttr { } } +export class MagicBounceAbAttr extends AbAttr { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + (args[0] as Utils.BooleanHolder).value = true; + + return true; + } +} + 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 => { @@ -3103,7 +3111,7 @@ export function initAbilities() { .attr(PostIntimidateStatChangeAbAttr, [BattleStat.SPD], 1), new Ability(Abilities.MAGIC_BOUNCE, 5) .ignorable() - .unimplemented(), + .attr(MagicBounceAbAttr), new Ability(Abilities.SAP_SIPPER, 5) .attr(TypeImmunityStatChangeAbAttr, Type.GRASS, BattleStat.ATK, 1) .ignorable(), diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 0fea80c37..15545f616 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -182,7 +182,7 @@ export class InterruptedTag extends BattlerTag { lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { super.lapse(pokemon, lapseType); (pokemon.scene.getCurrentPhase() as MovePhase).cancel(); - return true + return true } } @@ -790,6 +790,18 @@ export class ContactBurnProtectedTag extends ProtectedTag { } } +export class MagicCoatTag extends BattlerTag { + constructor(sourceMove: Moves, tagType: BattlerTagType = BattlerTagType.MAGIC_COAT) { + super(tagType, BattlerTagLapseType.CUSTOM, 0, sourceMove); + } + + onAdd(pokemon: Pokemon): void { + super.onAdd(pokemon); + + pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' shrouded\nitself with Magic Coat!')); + } +} + export class EnduringTag extends BattlerTag { constructor(sourceMove: Moves) { super(BattlerTagType.ENDURING, BattlerTagLapseType.TURN_END, 0, sourceMove); @@ -1226,6 +1238,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc return new TypeBoostTag(tagType, sourceMove, Type.ELECTRIC, 2, true); case BattlerTagType.MAGNET_RISEN: return new MagnetRisenTag(tagType, sourceMove); + case BattlerTagType.MAGIC_COAT: + return new MagicCoatTag(sourceMove); case BattlerTagType.NONE: default: return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId); diff --git a/src/data/enums/battler-tag-type.ts b/src/data/enums/battler-tag-type.ts index d18ccf1c5..603209b6a 100644 --- a/src/data/enums/battler-tag-type.ts +++ b/src/data/enums/battler-tag-type.ts @@ -55,5 +55,6 @@ export enum BattlerTagType { CURSED = "CURSED", CHARGED = "CHARGED", GROUNDED = "GROUNDED", - MAGNET_RISEN = "MAGNET_RISEN" + MAGNET_RISEN = "MAGNET_RISEN", + MAGIC_COAT = "MAGIC_COAT" } diff --git a/src/data/move.ts b/src/data/move.ts index 653ffc93c..5832c1481 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -69,7 +69,9 @@ export enum MoveFlags { DANCE_MOVE = 4096, WIND_MOVE = 8192, TRIAGE_MOVE = 16384, - IGNORE_ABILITIES = 32768 + IGNORE_ABILITIES = 32768, + MAGIC_COAT_MOVE = 65536 + } type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean; @@ -294,6 +296,11 @@ export default class Move implements Localizable { return this; } + magicCoatMove(magicCoatMove?: boolean): this { + this.setFlag(MoveFlags.MAGIC_COAT_MOVE, magicCoatMove); + return this; + } + ignoresAbilities(ignoresAbilities?: boolean): this { this.setFlag(MoveFlags.IGNORE_ABILITIES, ignoresAbilities); return this; @@ -1558,7 +1565,7 @@ export class AcupressureStatChangeAttr extends MoveEffectAttr { return true; } return false; - } + } } export class GrowthStatChangeAttr extends StatChangeAttr { @@ -2090,9 +2097,9 @@ export class KnockOffPowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if(target.getHeldItems().length > 0){ (args[0] as Utils.NumberHolder).value *= 1.5; - return true; + return true; } - + return false; } } @@ -3999,7 +4006,8 @@ export function initMoves() { .attr(ForceSwitchOutAttr) .attr(HitsTagAttr, BattlerTagType.FLYING, false) .hidesTarget() - .windMove(), + .windMove() + .magicCoatMove(), new AttackMove(Moves.FLY, Type.FLYING, MoveCategory.PHYSICAL, 90, 95, 15, -1, 0, 1) .attr(ChargeAttr, ChargeAnim.FLY_CHARGING, 'flew\nup high!', BattlerTagType.FLYING) .condition(failOnGravityCondition) @@ -4020,7 +4028,8 @@ export function initMoves() { new AttackMove(Moves.ROLLING_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 85, 15, 30, 0, 1) .attr(FlinchAttr), new StatusMove(Moves.SAND_ATTACK, Type.GROUND, 100, 15, -1, 0, 1) - .attr(StatChangeAttr, BattleStat.ACC, -1), + .attr(StatChangeAttr, BattleStat.ACC, -1) + .magicCoatMove(), new AttackMove(Moves.HEADBUTT, Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 15, 30, 0, 1) .attr(FlinchAttr), new AttackMove(Moves.HORN_ATTACK, Type.NORMAL, MoveCategory.PHYSICAL, 65, 100, 25, -1, 0, 1), @@ -4044,7 +4053,8 @@ export function initMoves() { .attr(RecoilAttr, false, 0.33), new StatusMove(Moves.TAIL_WHIP, Type.NORMAL, 100, 30, -1, 0, 1) .attr(StatChangeAttr, BattleStat.DEF, -1) - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new AttackMove(Moves.POISON_STING, Type.POISON, MoveCategory.PHYSICAL, 15, 100, 35, 30, 0, 1) .attr(StatusEffectAttr, StatusEffect.POISON) .makesContact(false), @@ -4057,29 +4067,35 @@ export function initMoves() { .makesContact(false), new StatusMove(Moves.LEER, Type.NORMAL, 100, 30, 100, 0, 1) .attr(StatChangeAttr, BattleStat.DEF, -1) - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new AttackMove(Moves.BITE, Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, 30, 0, 1) .attr(FlinchAttr) .bitingMove(), new StatusMove(Moves.GROWL, Type.NORMAL, 100, 40, -1, 0, 1) .attr(StatChangeAttr, BattleStat.ATK, -1) .soundBased() - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new StatusMove(Moves.ROAR, Type.NORMAL, -1, 20, -1, -6, 1) .attr(ForceSwitchOutAttr) .soundBased() - .hidesTarget(), + .hidesTarget() + .magicCoatMove(), new StatusMove(Moves.SING, Type.NORMAL, 55, 15, -1, 0, 1) .attr(StatusEffectAttr, StatusEffect.SLEEP) - .soundBased(), + .soundBased() + .magicCoatMove(), new StatusMove(Moves.SUPERSONIC, Type.NORMAL, 55, 20, -1, 0, 1) .attr(ConfuseAttr) - .soundBased(), + .soundBased() + .magicCoatMove(), new AttackMove(Moves.SONIC_BOOM, Type.NORMAL, MoveCategory.SPECIAL, -1, 90, 20, -1, 0, 1) .attr(FixedDamageAttr, 20), new StatusMove(Moves.DISABLE, Type.NORMAL, 100, 20, -1, 0, 1) .attr(DisableMoveAttr) - .condition(failOnMaxCondition), + .condition(failOnMaxCondition) + .magicCoatMove(), new AttackMove(Moves.ACID, Type.POISON, MoveCategory.SPECIAL, 40, 100, 30, 10, 0, 1) .attr(StatChangeAttr, BattleStat.SPDEF, -1) .target(MoveTarget.ALL_NEAR_ENEMIES), @@ -4131,7 +4147,8 @@ export function initMoves() { .triageMove(), new StatusMove(Moves.LEECH_SEED, Type.GRASS, 90, 10, -1, 0, 1) .attr(AddBattlerTagAttr, BattlerTagType.SEEDED) - .condition((user, target, move) => !target.getTag(BattlerTagType.SEEDED) && !target.isOfType(Type.GRASS)), + .condition((user, target, move) => !target.getTag(BattlerTagType.SEEDED) && !target.isOfType(Type.GRASS)) + .magicCoatMove(), new SelfStatusMove(Moves.GROWTH, Type.NORMAL, -1, 20, -1, 0, 1) .attr(GrowthStatChangeAttr), new AttackMove(Moves.RAZOR_LEAF, Type.GRASS, MoveCategory.PHYSICAL, 55, 95, 25, -1, 0, 1) @@ -4145,13 +4162,16 @@ export function initMoves() { .ignoresVirtual(), new StatusMove(Moves.POISON_POWDER, Type.POISON, 75, 35, -1, 0, 1) .attr(StatusEffectAttr, StatusEffect.POISON) - .powderMove(), + .powderMove() + .magicCoatMove(), new StatusMove(Moves.STUN_SPORE, Type.GRASS, 75, 30, -1, 0, 1) .attr(StatusEffectAttr, StatusEffect.PARALYSIS) - .powderMove(), + .powderMove() + .magicCoatMove(), new StatusMove(Moves.SLEEP_POWDER, Type.GRASS, 75, 15, -1, 0, 1) .attr(StatusEffectAttr, StatusEffect.SLEEP) - .powderMove(), + .powderMove() + .magicCoatMove(), new AttackMove(Moves.PETAL_DANCE, Type.GRASS, MoveCategory.SPECIAL, 120, 100, 10, -1, 0, 1) .attr(FrenzyAttr) .attr(MissEffectAttr, frenzyMissFunc) @@ -4160,7 +4180,8 @@ export function initMoves() { .target(MoveTarget.RANDOM_NEAR_ENEMY), new StatusMove(Moves.STRING_SHOT, Type.BUG, 95, 40, -1, 0, 1) .attr(StatChangeAttr, BattleStat.SPD, -2) - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new AttackMove(Moves.DRAGON_RAGE, Type.DRAGON, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 1) .attr(FixedDamageAttr, 40), new AttackMove(Moves.FIRE_SPIN, Type.FIRE, MoveCategory.SPECIAL, 35, 85, 15, 100, 0, 1) @@ -4171,7 +4192,8 @@ export function initMoves() { .attr(StatusEffectAttr, StatusEffect.PARALYSIS), new StatusMove(Moves.THUNDER_WAVE, Type.ELECTRIC, 90, 20, -1, 0, 1) .attr(StatusEffectAttr, StatusEffect.PARALYSIS) - .attr(StatusMoveTypeImmunityAttr, Type.GROUND), + .attr(StatusMoveTypeImmunityAttr, Type.GROUND) + .magicCoatMove(), new AttackMove(Moves.THUNDER, Type.ELECTRIC, MoveCategory.SPECIAL, 110, 70, 10, 30, 0, 1) .attr(StatusEffectAttr, StatusEffect.PARALYSIS) .attr(ThunderAccuracyAttr) @@ -4191,6 +4213,7 @@ export function initMoves() { .attr(ChargeAttr, ChargeAnim.DIG_CHARGING, 'dug a hole!', BattlerTagType.UNDERGROUND) .ignoresVirtual(), new StatusMove(Moves.TOXIC, Type.POISON, 90, 10, -1, 0, 1) + .magicCoatMove() .attr(StatusEffectAttr, StatusEffect.TOXIC) .attr(ToxicAccuracyAttr), new AttackMove(Moves.CONFUSION, Type.PSYCHIC, MoveCategory.SPECIAL, 50, 100, 25, 10, 0, 1) @@ -4198,7 +4221,8 @@ export function initMoves() { new AttackMove(Moves.PSYCHIC, Type.PSYCHIC, MoveCategory.SPECIAL, 90, 100, 10, 10, 0, 1) .attr(StatChangeAttr, BattleStat.SPDEF, -1), new StatusMove(Moves.HYPNOSIS, Type.PSYCHIC, 60, 20, -1, 0, 1) - .attr(StatusEffectAttr, StatusEffect.SLEEP), + .attr(StatusEffectAttr, StatusEffect.SLEEP) + .magicCoatMove(), new SelfStatusMove(Moves.MEDITATE, Type.PSYCHIC, -1, 40, -1, 0, 1) .attr(StatChangeAttr, BattleStat.ATK, 1, true), new SelfStatusMove(Moves.AGILITY, Type.PSYCHIC, -1, 30, -1, 0, 1) @@ -4216,7 +4240,8 @@ export function initMoves() { .ignoresVirtual(), new StatusMove(Moves.SCREECH, Type.NORMAL, 85, 40, -1, 0, 1) .attr(StatChangeAttr, BattleStat.DEF, -2) - .soundBased(), + .soundBased() + .magicCoatMove(), new SelfStatusMove(Moves.DOUBLE_TEAM, Type.NORMAL, -1, 15, -1, 0, 1) .attr(StatChangeAttr, BattleStat.EVA, 1, true), new SelfStatusMove(Moves.RECOVER, Type.NORMAL, -1, 5, -1, 0, 1) @@ -4227,9 +4252,11 @@ export function initMoves() { new SelfStatusMove(Moves.MINIMIZE, Type.NORMAL, -1, 10, -1, 0, 1) .attr(StatChangeAttr, BattleStat.EVA, 2, true), new StatusMove(Moves.SMOKESCREEN, Type.NORMAL, 100, 20, -1, 0, 1) - .attr(StatChangeAttr, BattleStat.ACC, -1), + .attr(StatChangeAttr, BattleStat.ACC, -1) + .magicCoatMove(), new StatusMove(Moves.CONFUSE_RAY, Type.GHOST, 100, 10, -1, 0, 1) - .attr(ConfuseAttr), + .attr(ConfuseAttr) + .magicCoatMove(), new SelfStatusMove(Moves.WITHDRAW, Type.WATER, -1, 40, -1, 0, 1) .attr(StatChangeAttr, BattleStat.DEF, 1, true), new SelfStatusMove(Moves.DEFENSE_CURL, Type.NORMAL, -1, 40, -1, 0, 1) @@ -4294,7 +4321,8 @@ export function initMoves() { new SelfStatusMove(Moves.AMNESIA, Type.PSYCHIC, -1, 20, -1, 0, 1) .attr(StatChangeAttr, BattleStat.SPDEF, 2, true), new StatusMove(Moves.KINESIS, Type.PSYCHIC, 80, 15, -1, 0, 1) - .attr(StatChangeAttr, BattleStat.ACC, -1), + .attr(StatChangeAttr, BattleStat.ACC, -1) + .magicCoatMove(), new SelfStatusMove(Moves.SOFT_BOILED, Type.NORMAL, -1, 5, -1, 0, 1) .attr(HealAttr, 0.5) .triageMove(), @@ -4303,14 +4331,16 @@ export function initMoves() { .attr(NoEffectAttr, crashDamageFunc) .condition(failOnGravityCondition), new StatusMove(Moves.GLARE, Type.NORMAL, 100, 30, -1, 0, 1) - .attr(StatusEffectAttr, StatusEffect.PARALYSIS), + .attr(StatusEffectAttr, StatusEffect.PARALYSIS) + .magicCoatMove(), new AttackMove(Moves.DREAM_EATER, Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 15, -1, 0, 1) .attr(HitHealAttr) .condition((user, target, move) => target.status?.effect === StatusEffect.SLEEP) .triageMove(), new StatusMove(Moves.POISON_GAS, Type.POISON, 90, 40, -1, 0, 1) .attr(StatusEffectAttr, StatusEffect.POISON) - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new AttackMove(Moves.BARRAGE, Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, -1, 0, 1) .attr(MultiHitAttr) .makesContact(false) @@ -4319,7 +4349,8 @@ export function initMoves() { .attr(HitHealAttr) .triageMove(), new StatusMove(Moves.LOVELY_KISS, Type.NORMAL, 75, 10, -1, 0, 1) - .attr(StatusEffectAttr, StatusEffect.SLEEP), + .attr(StatusEffectAttr, StatusEffect.SLEEP) + .magicCoatMove(), new AttackMove(Moves.SKY_ATTACK, Type.FLYING, MoveCategory.PHYSICAL, 140, 90, 5, 30, 0, 1) .attr(ChargeAttr, ChargeAnim.SKY_ATTACK_CHARGING, 'is glowing!') .attr(HighCritAttr) @@ -4337,9 +4368,11 @@ export function initMoves() { .punchingMove(), new StatusMove(Moves.SPORE, Type.GRASS, 100, 15, -1, 0, 1) .attr(StatusEffectAttr, StatusEffect.SLEEP) - .powderMove(), + .powderMove() + .magicCoatMove(), new StatusMove(Moves.FLASH, Type.NORMAL, 100, 20, -1, 0, 1) - .attr(StatChangeAttr, BattleStat.ACC, -1), + .attr(StatChangeAttr, BattleStat.ACC, -1) + .magicCoatMove(), new AttackMove(Moves.PSYWAVE, Type.PSYCHIC, MoveCategory.SPECIAL, -1, 100, 15, -1, 0, 1) .attr(RandomLevelDamageAttr), new SelfStatusMove(Moves.SPLASH, Type.NORMAL, -1, 40, -1, 0, 1) @@ -4402,7 +4435,8 @@ export function initMoves() { new AttackMove(Moves.THIEF, Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, -1, 0, 2) .attr(StealHeldItemChanceAttr, 0.3), new StatusMove(Moves.SPIDER_WEB, Type.BUG, -1, 10, -1, 0, 2) - .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1), + .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1) + .magicCoatMove(), new StatusMove(Moves.MIND_READER, Type.NORMAL, -1, 5, -1, 0, 2) .attr(IgnoreAccuracyAttr), new StatusMove(Moves.NIGHTMARE, Type.GHOST, 100, 15, -1, 0, 2) @@ -4428,11 +4462,13 @@ export function initMoves() { new StatusMove(Moves.COTTON_SPORE, Type.GRASS, 100, 40, -1, 0, 2) .attr(StatChangeAttr, BattleStat.SPD, -2) .powderMove() - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new AttackMove(Moves.REVERSAL, Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 15, -1, 0, 2) .attr(LowHpPowerAttr), new StatusMove(Moves.SPITE, Type.GHOST, 100, 10, -1, 0, 2) - .attr(ReducePpMoveAttr), + .attr(ReducePpMoveAttr) + .magicCoatMove(), new AttackMove(Moves.POWDER_SNOW, Type.ICE, MoveCategory.SPECIAL, 40, 100, 25, 10, 0, 2) .attr(StatusEffectAttr, StatusEffect.FREEZE) .target(MoveTarget.ALL_NEAR_ENEMIES), @@ -4441,10 +4477,12 @@ export function initMoves() { new AttackMove(Moves.MACH_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 30, -1, 1, 2) .punchingMove(), new StatusMove(Moves.SCARY_FACE, Type.NORMAL, 100, 10, -1, 0, 2) - .attr(StatChangeAttr, BattleStat.SPD, -2), + .attr(StatChangeAttr, BattleStat.SPD, -2) + .magicCoatMove(), new AttackMove(Moves.FEINT_ATTACK, Type.DARK, MoveCategory.PHYSICAL, 60, -1, 20, -1, 0, 2), new StatusMove(Moves.SWEET_KISS, Type.FAIRY, 75, 10, -1, 0, 2) - .attr(ConfuseAttr), + .attr(ConfuseAttr) + .magicCoatMove(), new SelfStatusMove(Moves.BELLY_DRUM, Type.NORMAL, -1, 10, -1, 0, 2) .attr(HalfHpStatMaxAttr, BattleStat.ATK), new AttackMove(Moves.SLUDGE_BOMB, Type.POISON, MoveCategory.SPECIAL, 90, 100, 10, 30, 0, 2) @@ -4462,6 +4500,7 @@ export function initMoves() { .attr(StatusEffectAttr, StatusEffect.PARALYSIS) .ballBombMove(), new StatusMove(Moves.FORESIGHT, Type.NORMAL, -1, 40, -1, 0, 2) + .magicCoatMove() .unimplemented(), new SelfStatusMove(Moves.DESTINY_BOND, Type.GHOST, -1, 5, -1, 0, 2) .ignoresProtect() @@ -4497,14 +4536,16 @@ export function initMoves() { new SelfStatusMove(Moves.ENDURE, Type.NORMAL, -1, 10, -1, 4, 2) .attr(EndureAttr), new StatusMove(Moves.CHARM, Type.FAIRY, 100, 20, -1, 0, 2) - .attr(StatChangeAttr, BattleStat.ATK, -2), + .attr(StatChangeAttr, BattleStat.ATK, -2) + .magicCoatMove(), new AttackMove(Moves.ROLLOUT, Type.ROCK, MoveCategory.PHYSICAL, 30, 90, 20, -1, 0, 2) .attr(ConsecutiveUseDoublePowerAttr, 5, true, true, Moves.DEFENSE_CURL), new AttackMove(Moves.FALSE_SWIPE, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 40, -1, 0, 2) .attr(SurviveDamageAttr), new StatusMove(Moves.SWAGGER, Type.NORMAL, 85, 15, -1, 0, 2) .attr(StatChangeAttr, BattleStat.ATK, 2) - .attr(ConfuseAttr), + .attr(ConfuseAttr) + .magicCoatMove(), new SelfStatusMove(Moves.MILK_DRINK, Type.NORMAL, -1, 5, -1, 0, 2) .attr(HealAttr, 0.5) .triageMove(), @@ -4516,8 +4557,10 @@ export function initMoves() { new AttackMove(Moves.STEEL_WING, Type.STEEL, MoveCategory.PHYSICAL, 70, 90, 25, 10, 0, 2) .attr(StatChangeAttr, BattleStat.DEF, 1, true), new StatusMove(Moves.MEAN_LOOK, Type.NORMAL, -1, 5, -1, 0, 2) - .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1), + .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1) + .magicCoatMove(), new StatusMove(Moves.ATTRACT, Type.NORMAL, 100, 15, -1, 0, 2) + .magicCoatMove() .attr(AddBattlerTagAttr, BattlerTagType.INFATUATED) .condition((user, target, move) => user.isOppositeGender(target)), new SelfStatusMove(Moves.SLEEP_TALK, Type.NORMAL, -1, 10, -1, 0, 2) @@ -4563,7 +4606,8 @@ export function initMoves() { .hidesUser(), new StatusMove(Moves.ENCORE, Type.NORMAL, 100, 5, -1, 0, 2) .attr(AddBattlerTagAttr, BattlerTagType.ENCORE, false, true) - .condition((user, target, move) => new EncoreTag(user.id).canAdd(target)), + .condition((user, target, move) => new EncoreTag(user.id).canAdd(target)) + .magicCoatMove(), new AttackMove(Moves.PURSUIT, Type.DARK, MoveCategory.PHYSICAL, 40, 100, 20, -1, 0, 2) .partial(), new AttackMove(Moves.RAPID_SPIN, Type.NORMAL, MoveCategory.PHYSICAL, 50, 100, 40, 100, 0, 2) @@ -4584,7 +4628,8 @@ export function initMoves() { .partial(), new StatusMove(Moves.SWEET_SCENT, Type.NORMAL, 100, 20, -1, 0, 2) .attr(StatChangeAttr, BattleStat.EVA, -1) - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new AttackMove(Moves.IRON_TAIL, Type.STEEL, MoveCategory.PHYSICAL, 100, 75, 15, 30, 0, 2) .attr(StatChangeAttr, BattleStat.DEF, -1), new AttackMove(Moves.METAL_CLAW, Type.STEEL, MoveCategory.PHYSICAL, 50, 95, 35, 10, 0, 2) @@ -4662,12 +4707,15 @@ export function initMoves() { .attr(WeatherChangeAttr, WeatherType.HAIL) .target(MoveTarget.BOTH_SIDES), new StatusMove(Moves.TORMENT, Type.DARK, 100, 15, -1, 0, 3) + .magicCoatMove() .unimplemented(), new StatusMove(Moves.FLATTER, Type.DARK, 100, 15, -1, 0, 3) .attr(StatChangeAttr, BattleStat.SPATK, 1) - .attr(ConfuseAttr), + .attr(ConfuseAttr) + .magicCoatMove(), new StatusMove(Moves.WILL_O_WISP, Type.FIRE, 85, 15, -1, 0, 3) - .attr(StatusEffectAttr, StatusEffect.BURN), + .attr(StatusEffectAttr, StatusEffect.BURN) + .magicCoatMove(), new StatusMove(Moves.MEMENTO, Type.DARK, 100, 10, -1, 0, 3) .attr(SacrificialAttr) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -2), @@ -4690,6 +4738,7 @@ export function initMoves() { .attr(StatChangeAttr, BattleStat.SPDEF, 1, true) .attr(AddBattlerTagAttr, BattlerTagType.CHARGED, true, true), new StatusMove(Moves.TAUNT, Type.DARK, 100, 20, -1, 0, 3) + .magicCoatMove() .unimplemented(), new StatusMove(Moves.HELPING_HAND, Type.NORMAL, -1, 20, -1, 5, 3) .attr(AddBattlerTagAttr, BattlerTagType.HELPING_HAND) @@ -4709,7 +4758,7 @@ export function initMoves() { new AttackMove(Moves.SUPERPOWER, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 3) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1, true), new SelfStatusMove(Moves.MAGIC_COAT, Type.PSYCHIC, -1, 15, -1, 4, 3) - .unimplemented(), + .attr(AddBattlerTagAttr, BattlerTagType.MAGIC_COAT), new SelfStatusMove(Moves.RECYCLE, Type.NORMAL, -1, 10, -1, 0, 3) .unimplemented(), new AttackMove(Moves.REVENGE, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, -4, 3) @@ -4718,7 +4767,8 @@ export function initMoves() { .attr(RemoveScreensAttr), new StatusMove(Moves.YAWN, Type.NORMAL, -1, 10, -1, 0, 3) .attr(AddBattlerTagAttr, BattlerTagType.DROWSY, false, true) - .condition((user, target, move) => !target.status), + .condition((user, target, move) => !target.status) + .magicCoatMove(), new AttackMove(Moves.KNOCK_OFF, Type.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, 0, 3) .attr(KnockOffPowerAttr) .partial(), @@ -4758,7 +4808,8 @@ export function initMoves() { .ballBombMove(), new StatusMove(Moves.FEATHER_DANCE, Type.FLYING, 100, 15, -1, 0, 3) .attr(StatChangeAttr, BattleStat.ATK, -2) - .danceMove(), + .danceMove() + .magicCoatMove(), new StatusMove(Moves.TEETER_DANCE, Type.NORMAL, 100, 20, -1, 0, 3) .attr(ConfuseAttr) .danceMove() @@ -4802,7 +4853,8 @@ export function initMoves() { .target(MoveTarget.USER_AND_ALLIES) .unimplemented(), new StatusMove(Moves.FAKE_TEARS, Type.DARK, 100, 20, -1, 0, 3) - .attr(StatChangeAttr, BattleStat.SPDEF, -2), + .attr(StatChangeAttr, BattleStat.SPDEF, -2) + .magicCoatMove(), new AttackMove(Moves.AIR_CUTTER, Type.FLYING, MoveCategory.SPECIAL, 60, 95, 25, -1, 0, 3) .attr(HighCritAttr) .slicingMove() @@ -4812,6 +4864,7 @@ export function initMoves() { .attr(StatChangeAttr, BattleStat.SPATK, -2, true) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE), new StatusMove(Moves.ODOR_SLEUTH, Type.NORMAL, -1, 40, -1, 0, 3) + .magicCoatMove() .unimplemented(), new AttackMove(Moves.ROCK_TOMB, Type.ROCK, MoveCategory.PHYSICAL, 60, 95, 15, 100, 0, 3) .attr(StatChangeAttr, BattleStat.SPD, -1) @@ -4821,12 +4874,15 @@ export function initMoves() { .windMove(), new StatusMove(Moves.METAL_SOUND, Type.STEEL, 85, 40, -1, 0, 3) .attr(StatChangeAttr, BattleStat.SPDEF, -2) - .soundBased(), + .soundBased() + .magicCoatMove(), new StatusMove(Moves.GRASS_WHISTLE, Type.GRASS, 55, 15, -1, 0, 3) .attr(StatusEffectAttr, StatusEffect.SLEEP) - .soundBased(), + .soundBased() + .magicCoatMove(), new StatusMove(Moves.TICKLE, Type.NORMAL, 100, 20, -1, 0, 3) - .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1), + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1) + .magicCoatMove(), new SelfStatusMove(Moves.COSMIC_POWER, Type.PSYCHIC, -1, 20, -1, 0, 3) .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, true), new AttackMove(Moves.WATER_SPOUT, Type.WATER, MoveCategory.SPECIAL, 150, 100, 5, -1, 0, 3) @@ -4862,6 +4918,7 @@ export function initMoves() { new SelfStatusMove(Moves.IRON_DEFENSE, Type.STEEL, -1, 15, -1, 0, 3) .attr(StatChangeAttr, BattleStat.DEF, 2, true), new StatusMove(Moves.BLOCK, Type.NORMAL, -1, 5, -1, 0, 3) + .magicCoatMove() .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1), new StatusMove(Moves.HOWL, Type.NORMAL, -1, 40, -1, 0, 3) .attr(StatChangeAttr, BattleStat.ATK, 1) @@ -4919,6 +4976,7 @@ export function initMoves() { .attr(AddArenaTagAttr, ArenaTagType.GRAVITY, 5) .target(MoveTarget.BOTH_SIDES), new StatusMove(Moves.MIRACLE_EYE, Type.PSYCHIC, -1, 40, -1, 0, 4) + .magicCoatMove() .unimplemented(), new AttackMove(Moves.WAKE_UP_SLAP, Type.FIGHTING, MoveCategory.PHYSICAL, 70, 100, 10, -1, 0, 4) .attr(MovePowerMultiplierAttr, (user, target, move) => target.status?.effect === StatusEffect.SLEEP ? 2 : 1) @@ -4963,6 +5021,7 @@ export function initMoves() { new AttackMove(Moves.ASSURANCE, Type.DARK, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 4) .attr(MovePowerMultiplierAttr, (user, target, move) => target.turnData.damageTaken > 0 ? 2 : 1), new StatusMove(Moves.EMBARGO, Type.DARK, 100, 15, -1, 0, 4) + .magicCoatMove() .unimplemented(), new AttackMove(Moves.FLING, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 4) .makesContact(false) @@ -4981,6 +5040,7 @@ export function initMoves() { .unimplemented(), new StatusMove(Moves.HEAL_BLOCK, Type.PSYCHIC, 100, 15, -1, 0, 4) .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove() .unimplemented(), new AttackMove(Moves.WRING_OUT, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 5, -1, 0, 4) .attr(OpponentHighHpPowerAttr) @@ -4988,7 +5048,8 @@ export function initMoves() { new SelfStatusMove(Moves.POWER_TRICK, Type.PSYCHIC, -1, 10, -1, 0, 4) .unimplemented(), new StatusMove(Moves.GASTRO_ACID, Type.POISON, 100, 10, -1, 0, 4) - .attr(SuppressAbilitiesAttr), + .attr(SuppressAbilitiesAttr) + .magicCoatMove(), new StatusMove(Moves.LUCKY_CHANT, Type.NORMAL, -1, 30, -1, 0, 4) .attr(AddBattlerTagAttr, BattlerTagType.NO_CRIT, false, false, 5) .target(MoveTarget.USER_SIDE) @@ -5009,10 +5070,12 @@ export function initMoves() { new AttackMove(Moves.LAST_RESORT, Type.NORMAL, MoveCategory.PHYSICAL, 140, 100, 5, -1, 0, 4) .attr(LastResortAttr), new StatusMove(Moves.WORRY_SEED, Type.GRASS, 100, 10, -1, 0, 4) - .attr(AbilityChangeAttr, Abilities.INSOMNIA), + .attr(AbilityChangeAttr, Abilities.INSOMNIA) + .magicCoatMove(), new AttackMove(Moves.SUCKER_PUNCH, Type.DARK, MoveCategory.PHYSICAL, 70, 100, 5, -1, 1, 4) .condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS), new StatusMove(Moves.TOXIC_SPIKES, Type.POISON, -1, 20, -1, 0, 4) + .magicCoatMove() .attr(AddArenaTrapTagAttr, ArenaTagType.TOXIC_SPIKES) .target(MoveTarget.ENEMY_SIDE), new StatusMove(Moves.HEART_SWAP, Type.PSYCHIC, -1, 10, -1, 0, 4) @@ -5021,7 +5084,7 @@ export function initMoves() { .attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true), new SelfStatusMove(Moves.MAGNET_RISE, Type.ELECTRIC, -1, 10, -1, 0, 4) .attr(AddBattlerTagAttr, BattlerTagType.MAGNET_RISEN, true, true) - .condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) && + .condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) && !user.getTag(BattlerTagType.IGNORE_FLYING) && !user.getTag(BattlerTagType.INGRAIN) && !user.getTag(BattlerTagType.MAGNET_RISEN)) .unimplemented(), @@ -5123,7 +5186,8 @@ export function initMoves() { .attr(StatChangeAttr, BattleStat.EVA, -1) .attr(ClearWeatherAttr, WeatherType.FOG) .attr(ClearTerrainAttr) - .attr(RemoveScreensAttr, true), + .attr(RemoveScreensAttr, true) + .magicCoatMove(), new StatusMove(Moves.TRICK_ROOM, Type.PSYCHIC, -1, 5, -1, -7, 4) .attr(AddArenaTagAttr, ArenaTagType.TRICK_ROOM, 5) .ignoresProtect() @@ -5161,10 +5225,12 @@ export function initMoves() { new StatusMove(Moves.CAPTIVATE, Type.NORMAL, 100, 20, -1, 0, 4) .attr(StatChangeAttr, BattleStat.SPATK, -2) .condition((user, target, move) => target.isOppositeGender(user)) - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new StatusMove(Moves.STEALTH_ROCK, Type.ROCK, -1, 20, -1, 0, 4) .attr(AddArenaTrapTagAttr, ArenaTagType.STEALTH_ROCK) - .target(MoveTarget.ENEMY_SIDE), + .target(MoveTarget.ENEMY_SIDE) + .magicCoatMove(), new AttackMove(Moves.GRASS_KNOT, Type.GRASS, MoveCategory.SPECIAL, -1, 100, 20, -1, 0, 4) .attr(WeightPowerAttr) .makesContact() @@ -5208,7 +5274,8 @@ export function initMoves() { .attr(TrapAttr, BattlerTagType.MAGMA_STORM), new StatusMove(Moves.DARK_VOID, Type.DARK, 50, 10, -1, 0, 4) .attr(StatusEffectAttr, StatusEffect.SLEEP) - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new AttackMove(Moves.SEED_FLARE, Type.GRASS, MoveCategory.SPECIAL, 120, 85, 5, 40, 0, 4) .attr(StatChangeAttr, BattleStat.SPDEF, -1), new AttackMove(Moves.OMINOUS_WIND, Type.GHOST, MoveCategory.SPECIAL, 60, 100, 5, 10, 0, 4) @@ -5243,6 +5310,7 @@ export function initMoves() { .unimplemented(), new StatusMove(Moves.TELEKINESIS, Type.PSYCHIC, -1, 15, -1, 0, 5) .condition(failOnGravityCondition) + .magicCoatMove() .unimplemented(), new StatusMove(Moves.MAGIC_ROOM, Type.PSYCHIC, -1, 10, -1, 0, 5) .ignoresProtect() @@ -5275,7 +5343,8 @@ export function initMoves() { .attr(BattleStatRatioPowerAttr, Stat.SPD) .ballBombMove(), new StatusMove(Moves.SOAK, Type.WATER, 100, 20, -1, 0, 5) - .attr(ChangeTypeAttr, Type.WATER), + .attr(ChangeTypeAttr, Type.WATER) + .magicCoatMove(), new AttackMove(Moves.FLAME_CHARGE, Type.FIRE, MoveCategory.PHYSICAL, 50, 100, 20, 100, 0, 5) .attr(StatChangeAttr, BattleStat.SPD, 1, true), new SelfStatusMove(Moves.COIL, Type.POISON, -1, 20, -1, 0, 5) @@ -5288,9 +5357,11 @@ export function initMoves() { new AttackMove(Moves.FOUL_PLAY, Type.DARK, MoveCategory.PHYSICAL, 95, 100, 15, -1, 0, 5) .attr(TargetAtkUserAtkAttr), new StatusMove(Moves.SIMPLE_BEAM, Type.NORMAL, 100, 15, -1, 0, 5) - .attr(AbilityChangeAttr, Abilities.SIMPLE), + .attr(AbilityChangeAttr, Abilities.SIMPLE) + .magicCoatMove(), new StatusMove(Moves.ENTRAINMENT, Type.NORMAL, 100, 15, -1, 0, 5) - .attr(AbilityGiveAttr), + .attr(AbilityGiveAttr) + .magicCoatMove(), new StatusMove(Moves.AFTER_YOU, Type.NORMAL, -1, 15, -1, 0, 5) .ignoresProtect() .unimplemented(), @@ -5322,7 +5393,8 @@ export function initMoves() { new StatusMove(Moves.HEAL_PULSE, Type.PSYCHIC, -1, 10, -1, 0, 5) .attr(HealAttr, 0.5, false, false) .pulseMove() - .triageMove(), + .triageMove() + .magicCoatMove(), new AttackMove(Moves.HEX, Type.GHOST, MoveCategory.SPECIAL, 65, 100, 10, -1, 0, 5) .attr(MovePowerMultiplierAttr, (user, target, move) => target.status ? 2 : 1), new AttackMove(Moves.SKY_DROP, Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 5) @@ -5485,10 +5557,12 @@ export function initMoves() { .ignoresVirtual(), new StatusMove(Moves.TRICK_OR_TREAT, Type.GHOST, 100, 20, -1, 0, 6) .attr(AddTypeAttr, Type.GHOST) + .magicCoatMove() .partial(), new StatusMove(Moves.NOBLE_ROAR, Type.NORMAL, 100, 30, 100, 0, 6) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1) - .soundBased(), + .soundBased() + .magicCoatMove(), new StatusMove(Moves.ION_DELUGE, Type.ELECTRIC, -1, 25, -1, 1, 6) .target(MoveTarget.BOTH_SIDES) .unimplemented(), @@ -5498,6 +5572,7 @@ export function initMoves() { .triageMove(), new StatusMove(Moves.FORESTS_CURSE, Type.GRASS, 100, 20, -1, 0, 6) .attr(AddTypeAttr, Type.GRASS) + .magicCoatMove() .partial(), new AttackMove(Moves.PETAL_BLIZZARD, Type.GRASS, MoveCategory.PHYSICAL, 90, 100, 15, -1, 0, 6) .windMove() @@ -5512,9 +5587,11 @@ export function initMoves() { new StatusMove(Moves.PARTING_SHOT, Type.DARK, 100, 20, 100, 0, 6) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1, false, null, true, true, MoveEffectTrigger.PRE_APPLY) .attr(ForceSwitchOutAttr, true, false) - .soundBased(), + .soundBased() + .magicCoatMove(), new StatusMove(Moves.TOPSY_TURVY, Type.DARK, -1, 20, -1, 0, 6) - .attr(InvertStatsAttr), + .attr(InvertStatsAttr) + .magicCoatMove(), new AttackMove(Moves.DRAINING_KISS, Type.FAIRY, MoveCategory.SPECIAL, 50, 100, 10, -1, 0, 6) .attr(HitHealAttr, 0.75) .makesContact() @@ -5548,10 +5625,12 @@ export function initMoves() { new SelfStatusMove(Moves.KINGS_SHIELD, Type.STEEL, -1, 10, -1, 4, 6) .attr(ProtectAttr, BattlerTagType.KINGS_SHIELD), new StatusMove(Moves.PLAY_NICE, Type.NORMAL, -1, 20, 100, 0, 6) - .attr(StatChangeAttr, BattleStat.ATK, -1), + .attr(StatChangeAttr, BattleStat.ATK, -1) + .magicCoatMove(), new StatusMove(Moves.CONFIDE, Type.NORMAL, -1, 20, 100, 0, 6) .attr(StatChangeAttr, BattleStat.SPATK, -1) - .soundBased(), + .soundBased() + .magicCoatMove(), new AttackMove(Moves.DIAMOND_STORM, Type.ROCK, MoveCategory.PHYSICAL, 100, 95, 5, 50, 0, 6) .attr(StatChangeAttr, BattleStat.DEF, 2, true) .makesContact(false) @@ -5573,12 +5652,15 @@ export function initMoves() { .attr(StatChangeAttr, BattleStat.SPDEF, 1) .target(MoveTarget.NEAR_ALLY), new StatusMove(Moves.EERIE_IMPULSE, Type.ELECTRIC, 100, 15, -1, 0, 6) - .attr(StatChangeAttr, BattleStat.SPATK, -2), + .attr(StatChangeAttr, BattleStat.SPATK, -2) + .magicCoatMove(), new StatusMove(Moves.VENOM_DRENCH, Type.POISON, 100, 20, 100, 0, 6) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], -1, false, (user, target, move) => target.status?.effect === StatusEffect.POISON || target.status?.effect === StatusEffect.TOXIC) - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new StatusMove(Moves.POWDER, Type.BUG, 100, 20, -1, 1, 6) .powderMove() + .magicCoatMove() .unimplemented(), new SelfStatusMove(Moves.GEOMANCY, Type.FAIRY, -1, 10, -1, 0, 6) .attr(ChargeAttr, ChargeAnim.GEOMANCY_CHARGING, "is charging its power!") @@ -5600,6 +5682,7 @@ export function initMoves() { new StatusMove(Moves.HOLD_HANDS, Type.NORMAL, -1, 40, -1, 0, 6) .target(MoveTarget.NEAR_ALLY), new StatusMove(Moves.BABY_DOLL_EYES, Type.FAIRY, 100, 30, -1, 1, 6) + .magicCoatMove() .attr(StatChangeAttr, BattleStat.ATK, -1), new AttackMove(Moves.NUZZLE, Type.ELECTRIC, MoveCategory.PHYSICAL, 20, 100, 20, 100, 0, 6) .attr(StatusEffectAttr, StatusEffect.PARALYSIS), @@ -5739,13 +5822,15 @@ export function initMoves() { new StatusMove(Moves.FLORAL_HEALING, Type.FAIRY, -1, 10, -1, 0, 7) .attr(HealAttr, 0.5, true, false) .triageMove() + .magicCoatMove() .partial(), new AttackMove(Moves.HIGH_HORSEPOWER, Type.GROUND, MoveCategory.PHYSICAL, 95, 95, 10, -1, 0, 7), new StatusMove(Moves.STRENGTH_SAP, Type.GRASS, 100, 10, 100, 0, 7) .attr(StrengthSapHealAttr) .attr(StatChangeAttr, BattleStat.ATK, -1) .condition((user, target, move) => target.summonData.battleStats[BattleStat.ATK] > -6) - .triageMove(), + .triageMove() + .magicCoatMove(), new AttackMove(Moves.SOLAR_BLADE, Type.GRASS, MoveCategory.PHYSICAL, 125, 100, 10, -1, 0, 7) .attr(SunlightChargeAttr, ChargeAnim.SOLAR_BLADE_CHARGING, "is glowing!") .attr(AntiSunlightPowerDecreaseAttr) @@ -5753,10 +5838,12 @@ export function initMoves() { new AttackMove(Moves.LEAFAGE, Type.GRASS, MoveCategory.PHYSICAL, 40, 100, 40, -1, 0, 7) .makesContact(false), new StatusMove(Moves.SPOTLIGHT, Type.NORMAL, -1, 15, -1, 3, 7) + .magicCoatMove() .unimplemented(), new StatusMove(Moves.TOXIC_THREAD, Type.POISON, 100, 20, 100, 0, 7) .attr(StatusEffectAttr, StatusEffect.POISON) - .attr(StatChangeAttr, BattleStat.SPD, -1), + .attr(StatChangeAttr, BattleStat.SPD, -1) + .magicCoatMove(), new SelfStatusMove(Moves.LASER_FOCUS, Type.NORMAL, -1, 30, -1, 0, 7) .attr(AddBattlerTagAttr, BattlerTagType.ALWAYS_CRIT, true, false), new StatusMove(Moves.GEAR_UP, Type.STEEL, -1, 20, -1, 0, 7) @@ -5793,6 +5880,7 @@ export function initMoves() { new AttackMove(Moves.SMART_STRIKE, Type.STEEL, MoveCategory.PHYSICAL, 70, -1, 10, -1, 0, 7), new StatusMove(Moves.PURIFY, Type.POISON, -1, 20, -1, 0, 7) .triageMove() + .magicCoatMove() .unimplemented(), new AttackMove(Moves.REVELATION_DANCE, Type.NORMAL, MoveCategory.SPECIAL, 90, 100, 15, -1, 0, 7) .danceMove() @@ -5868,7 +5956,8 @@ export function initMoves() { .ignoresAbilities() .partial(), new StatusMove(Moves.TEARFUL_LOOK, Type.NORMAL, -1, 20, 100, 0, 7) - .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1), + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1) + .magicCoatMove(), new AttackMove(Moves.ZING_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 80, 100, 10, 30, 0, 7) .attr(FlinchAttr), new AttackMove(Moves.NATURES_MADNESS, Type.FAIRY, MoveCategory.SPECIAL, -1, 90, 10, -1, 0, 7) @@ -5962,10 +6051,12 @@ export function initMoves() { .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, true, 1), new StatusMove(Moves.TAR_SHOT, Type.ROCK, 100, 15, 100, 0, 8) .attr(StatChangeAttr, BattleStat.SPD, -1) + .magicCoatMove() .partial(), new StatusMove(Moves.MAGIC_POWDER, Type.PSYCHIC, 100, 20, -1, 0, 8) .attr(ChangeTypeAttr, Type.PSYCHIC) - .powderMove(), + .powderMove() + .magicCoatMove(), new AttackMove(Moves.DRAGON_DARTS, Type.DRAGON, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 8) .attr(MultiHitAttr, MultiHitType._2) .makesContact(false) @@ -6140,6 +6231,7 @@ export function initMoves() { .partial(), new StatusMove(Moves.CORROSIVE_GAS, Type.POISON, 100, 40, -1, 0, 8) .target(MoveTarget.ALL_NEAR_OTHERS) + .magicCoatMove() .unimplemented(), new StatusMove(Moves.COACHING, Type.FIGHTING, -1, 10, 100, 0, 8) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], 1) diff --git a/src/phases.ts b/src/phases.ts index 751cac166..6b197107e 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -21,7 +21,7 @@ import { Biome } from "./data/enums/biome"; import { ModifierTier } from "./modifier/modifier-tier"; import { FusePokemonModifierType, ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, RememberMoveModifierType, TmModifierType, getDailyRunStarterModifiers, getEnemyBuffModifierForWave, getModifierType, getPlayerModifierTypeOptions, getPlayerShopModifierTypeOptionsForWave, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; -import { BattlerTagLapseType, EncoreTag, HideSpriteTag as HiddenTag, ProtectedTag, TrappedTag } from "./data/battler-tags"; +import { BattlerTag, BattlerTagLapseType, MagicCoatTag, EncoreTag, HideSpriteTag as HiddenTag, ProtectedTag, TrappedTag } from "./data/battler-tags"; import { BattlerTagType } from "./data/enums/battler-tag-type"; import { getPokemonMessage } from "./messages"; import { Starter } from "./ui/starter-select-ui-handler"; @@ -30,7 +30,7 @@ import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, get import { TempBattleStat } from "./data/temp-battle-stat"; import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag"; import { ArenaTagType } from "./data/enums/arena-tag-type"; -import { CheckTrappedAbAttr, 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, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr } from "./data/ability"; +import { CheckTrappedAbAttr, 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, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, MagicBounceAbAttr, MaxMultiHitAbAttr } from "./data/ability"; import { Unlockables, getUnlockableName } from "./system/unlockables"; import { getBiomeKey } from "./field/arena"; import { BattleType, BattlerIndex, TurnCommand } from "./battle"; @@ -2385,8 +2385,8 @@ export class MoveEffectPhase extends PokemonPhase { start() { super.start(); - const user = this.getUserPokemon(); - const targets = this.getTargets(); + let user = this.getUserPokemon(); + let targets = this.getTargets(); if (!user?.isOnField()) return super.end(); @@ -2429,12 +2429,40 @@ export class MoveEffectPhase extends PokemonPhase { return this.end(); } + let isBounced: BattlerTag | boolean = false; + for (let opponent of targets) { + const targetHasMagicBounce = new Utils.BooleanHolder(false); + applyAbAttrs(MagicBounceAbAttr, opponent, null, targetHasMagicBounce); + isBounced = this.move.getMove().hasFlag(MoveFlags.MAGIC_COAT_MOVE) && (opponent.findTags(t => t instanceof MagicCoatTag).find(t => opponent.lapseTag(t.tagType)) || targetHasMagicBounce.value); + if (isBounced) { + this.scene.queueMessage(getPokemonMessage(opponent, '\nbounced the move back!')); + if (this.move.getMove().isMultiTarget()){ + this.targets = getMoveTargets(opponent, this.move.moveId).targets; + targets = []; + for (let index of this.targets){ + const target = this.scene.getField()[index]; + if (target) + targets.push(target); + } + } else { + this.targets = [user.getBattlerIndex()]; + targets = [user]; + } + user = opponent; + if (!this.move.getMove().applyConditions(user, opponent, this.move.getMove())) { + this.scene.queueMessage(i18next.t('menu:attackFailed')); + return this.end(); + } + break; + } + } + const applyAttrs: Promise[] = []; // Move animation only needs one target new MoveAnim(this.move.getMove().id as Moves, user, this.getTarget()?.getBattlerIndex()).play(this.scene, () => { for (let target of targets) { - if (!targetHitChecks[target.getBattlerIndex()]) { + if (!targetHitChecks[target.getBattlerIndex()] && !isBounced) { user.turnData.hitCount = 1; user.turnData.hitsLeft = 1; this.scene.queueMessage(getPokemonMessage(user, '\'s\nattack missed!')); @@ -2740,9 +2768,9 @@ export class StatChangePhase extends PokemonPhase { if (levels.value > 0 && this.canBeCopied) for (let opponent of pokemon.getOpponents()) applyAbAttrs(StatChangeCopyAbAttr, opponent, null, this.stats, levels.value); - + applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget); - + pokemon.updateInfo(); handleTutorial(this.scene, Tutorial.Stat_Change).then(() => super.end());