"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var moves_exports = {};
__export(moves_exports, {
  Moves: () => Moves
});
module.exports = __toCommonJS(moves_exports);
const Moves = {
  direclaw: {
    shortDesc: "Sets a layer of Toxic Spikes.",
    num: -1005,
    accuracy: 100,
    basePower: 65,
    category: "Physical",
    name: "Dire Claw",
    desc: "Sets a layer of Toxic Spikes on the opponent's side of the field.",
    pp: 15,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
    onAfterHit(target, source, move) {
      if (!move.hasSheerForce && source.hp && !target.hasItem("covertcloak")) {
        for (const side of source.side.foeSidesWithConditions()) {
          side.addSideCondition("toxicspikes");
        }
      }
    },
    onAfterSubDamage(damage, target, source, move) {
      if (!move.hasSheerForce && source.hp && !target.hasItem("covertcloak")) {
        for (const side of source.side.foeSidesWithConditions()) {
          side.addSideCondition("toxicspikes");
        }
      }
    },
    secondary: {},
    target: "normal",
    type: "Poison",
    contestType: "Clever"
  },
  ceaselessedge: {
    num: 845,
    accuracy: 100,
    basePower: 65,
    category: "Physical",
    shortDesc: "Sets a layer of Spikes on the opposing side.",
    name: "Ceaseless Edge",
    pp: 15,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, slicing: 1 },
    onAfterHit(target, source, move) {
      if (!move.hasSheerForce && source.hp && !target.hasItem("covertcloak")) {
        for (const side of source.side.foeSidesWithConditions()) {
          side.addSideCondition("spikes");
        }
      }
    },
    onAfterSubDamage(damage, target, source, move) {
      if (!move.hasSheerForce && source.hp && !target.hasItem("covertcloak")) {
        for (const side of source.side.foeSidesWithConditions()) {
          side.addSideCondition("spikes");
        }
      }
    },
    secondary: {},
    target: "normal",
    type: "Dark"
  },
  stoneaxe: {
    num: 830,
    accuracy: 100,
    basePower: 65,
    category: "Physical",
    name: "Stone Axe",
    desc: "If this move is successful, it sets up a hazard on the opposing side of the field, damaging each opposing Pokemon that switches in. Foes lose 1/32, 1/16, 1/8, 1/4, or 1/2 of their maximum HP, rounded down, based on their weakness to the Rock type; 0.25x, 0.5x, neutral, 2x, or 4x, respectively. Can be removed from the opposing side if any opposing Pokemon uses Rapid Spin or Defog successfully, or is hit by Defog.",
    shortDesc: "Sets Stealth Rock on the target's side.",
    pp: 15,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, slicing: 1 },
    secondary: {
      chance: 100,
      sideCondition: "stealthrock"
    },
    target: "adjacentFoe",
    type: "Rock",
    contestType: "Tough"
  },
  electroweb: {
    num: 527,
    accuracy: 95,
    basePower: 65,
    category: "Special",
    shortDesc: "Sets Sticky Web on the target's side.",
    name: "Electroweb",
    pp: 15,
    priority: 0,
    flags: { protect: 1, mirror: 1, metronome: 1 },
    secondary: {
      chance: 100,
      sideCondition: "stickyweb"
    },
    target: "allAdjacentFoes",
    type: "Electric",
    contestType: "Beautiful"
  },
  skullbash: {
    num: 130,
    accuracy: 90,
    basePower: 120,
    category: "Physical",
    shortDesc: "Raises user's Atk by 1 on turn 1. Hits turn 2.",
    isNonstandard: null,
    name: "Skull Bash",
    pp: 10,
    priority: 0,
    flags: { contact: 1, charge: 1, protect: 1, mirror: 1, metronome: 1 },
    onTryMove(attacker, defender, move) {
      if (attacker.removeVolatile(move.id)) {
        return;
      }
      this.add("-prepare", attacker, move.name);
      this.boost({ atk: 1 }, attacker, attacker, move);
      if (!this.runEvent("ChargeMove", attacker, defender, move)) {
        return;
      }
      attacker.addVolatile("twoturnmove", defender);
      return null;
    },
    secondary: null,
    target: "normal",
    type: "Steel",
    contestType: "Tough"
  },
  shelter: {
    num: 842,
    accuracy: true,
    basePower: 0,
    category: "Status",
    shortDesc: "Removes Spikes and Stealth Rock from the field. +1 Def for every type of hazard cleared.",
    name: "Shelter",
    pp: 10,
    priority: 0,
    flags: { snatch: 1, metronome: 1 },
    onHit(pokemon) {
      const somesideConditions = ["spikes", "stealthrock"];
      const sides = [pokemon.side];
      for (const side of sides) {
        for (const sideCondition of somesideConditions) {
          if (sideCondition) {
            this.add("-message", `This sides Stealth Rock and Spikes will be removed!`);
          }
          if (side.removeSideCondition("spikes")) {
            this.add("-sideend", side, this.dex.conditions.get("spikes"));
            this.boost({ def: 1 }, pokemon);
          }
          if (side.removeSideCondition("stealthrock")) {
            this.add("-sideend", side, this.dex.conditions.get("stealthrock"));
            this.boost({ def: 1 }, pokemon);
          }
        }
      }
    },
    secondary: null,
    target: "self",
    type: "Steel"
  },
  healingstones: {
    num: -191,
    accuracy: true,
    basePower: 0,
    category: "Status",
    desc: "Sets healing stones on the user's side, healing Pokemon that switch in for 1/8th of their max HP.",
    shortDesc: "Heals allies on switch-in.",
    name: "Healing Stones",
    pp: 20,
    priority: 0,
    flags: { snatch: 1, heal: 1, nonsky: 1, metronome: 1 },
    sideCondition: "healingstones",
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Stealth Rock", target);
    },
    condition: {
      onSideStart(side) {
        this.add("-sidestart", side, "Healing Stones");
        this.effectState.layers = 1;
      },
      onSideRestart(side) {
        if (this.effectState.layers >= 1)
          return false;
        this.add("-sidestart", side, "Healing Stones");
        this.effectState.layers++;
      },
      onEntryHazard(pokemon) {
        if (pokemon.hasItem("heavydutyboots") || pokemon.hasAbility("overcoat") || pokemon.hasItem("mantisclaw"))
          return;
        const healAmounts = [0, 3];
        this.heal(healAmounts[this.effectState.layers] * pokemon.maxhp / 24);
      }
    },
    secondary: null,
    target: "allySide",
    type: "Fairy",
    contestType: "Clever"
  },
  junglehealing: {
    num: 816,
    accuracy: true,
    basePower: 0,
    category: "Status",
    shortDesc: "User and allies: healed 1/3 max HP, status cured.",
    name: "Jungle Healing",
    pp: 10,
    priority: 0,
    flags: { heal: 1, bypasssub: 1, allyanim: 1 },
    onHit(pokemon) {
      const success = !!this.heal(this.modify(pokemon.maxhp, 0.33));
      return pokemon.cureStatus() || success;
    },
    secondary: null,
    target: "allies",
    type: "Grass"
  },
  lifedew: {
    num: 791,
    accuracy: true,
    basePower: 0,
    category: "Status",
    shortDesc: "User: healed 1/3 max HP. Next switch-in: healed 1/4 max HP.",
    name: "Life Dew",
    pp: 10,
    priority: 0,
    flags: { snatch: 1, heal: 1, bypasssub: 1 },
    heal: [1, 3],
    slotCondition: "lifedew",
    condition: {
      onSwap(target) {
        if (!target.fainted) {
          const source = this.effectState.source;
          const damage = this.heal(target.baseMaxhp / 4, target, target);
          if (damage)
            this.add("-heal", target, target.getHealth, "[from] move: Life Dew", "[of] " + source);
          target.side.removeSlotCondition(target, "lifedew");
        }
      }
    },
    secondary: null,
    target: "self",
    type: "Water"
  },
  shrapnelshot: {
    accuracy: 90,
    basePower: 15,
    category: "Physical",
    shortDesc: "Hits 2-5 times. First hit lowers the foe's Defense by 1 stage.",
    name: "Shrapnel Shot",
    pp: 20,
    priority: 0,
    flags: { protect: 1, mirror: 1, metronome: 1, bullet: 1 },
    multihit: [2, 5],
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Spikes", target);
    },
    secondary: {
      chance: 100,
      onHit(target, source, move) {
        if (move.hit < 2) {
          this.boost({ def: -1 }, target);
        }
        return false;
      }
    },
    target: "normal",
    type: "Steel",
    zMove: { basePower: 140 },
    maxMove: { basePower: 130 },
    contestType: "Cool"
  },
  stormthrow: {
    num: 480,
    accuracy: true,
    basePower: 70,
    category: "Physical",
    isNonstandard: null,
    name: "Storm Throw",
    pp: 10,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
    willCrit: true,
    secondary: null,
    target: "normal",
    type: "Fighting",
    contestType: "Cool"
  },
  frostbreath: {
    num: 524,
    accuracy: true,
    basePower: 70,
    category: "Special",
    name: "Frost Breath",
    pp: 10,
    priority: 0,
    flags: { protect: 1, mirror: 1, metronome: 1 },
    willCrit: true,
    secondary: null,
    target: "normal",
    type: "Ice",
    contestType: "Beautiful"
  },
  snipeshot: {
    num: 745,
    accuracy: true,
    basePower: 70,
    category: "Special",
    shortDesc: "Always critically hits.",
    name: "Snipe Shot",
    pp: 10,
    priority: 0,
    flags: { protect: 1, mirror: 1, metronome: 1, pulse: 1 },
    willCrit: true,
    tracksTarget: true,
    secondary: null,
    target: "normal",
    type: "Water"
  },
  falsesurrender: {
    num: 793,
    accuracy: true,
    basePower: 70,
    category: "Physical",
    shortDesc: "Always critically hits.",
    name: "False Surrender",
    pp: 10,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1 },
    willCrit: true,
    secondary: null,
    target: "normal",
    type: "Dark"
  },
  choke: {
    accuracy: 100,
    basePower: 80,
    category: "Physical",
    shortDesc: "Inflicts the Heal Block effect.",
    name: "Choke",
    pp: 15,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Sky Uppercut", target);
      this.add("-anim", source, "Hex", target);
    },
    secondary: {
      chance: 100,
      onHit(target) {
        target.addVolatile("healblock");
      }
    },
    target: "normal",
    type: "Ghost",
    contestType: "Clever"
  },
  cuttingremark: {
    accuracy: 100,
    basePower: 40,
    category: "Physical",
    overrideDefensiveStat: "spd",
    shortDesc: "Usually goes first. Targets the foe's Special Defense.",
    name: "Cutting Remark",
    pp: 25,
    priority: 1,
    flags: { protect: 1, mirror: 1, sound: 1, bypasssub: 1, metronome: 1, slicing: 1 },
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Psycho Cut", target);
    },
    self: {
      sideCondition: "echochamber"
    },
    secondary: null,
    target: "normal",
    type: "Psychic",
    contestType: "Cool"
  },
  chainlightning: {
    accuracy: 100,
    basePower: 15,
    category: "Physical",
    shortDesc: "Usually goes first. Hits 2-5 times.",
    name: "Chain Lightning",
    pp: 20,
    priority: 1,
    flags: { protect: 1, mirror: 1, metronome: 1 },
    multihit: [2, 5],
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Thunder Shock", target);
    },
    secondary: null,
    target: "normal",
    type: "Electric",
    contestType: "Cool"
  },
  pluck: {
    num: 365,
    accuracy: 100,
    basePower: 70,
    category: "Physical",
    shortDesc: "Heals the user by 75% of the damage dealt.",
    name: "Pluck",
    pp: 10,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, heal: 1, metronome: 1 },
    drain: [3, 4],
    secondary: null,
    target: "normal",
    type: "Flying",
    contestType: "Cute"
  },
  throatchop: {
    num: 675,
    accuracy: 100,
    basePower: 85,
    category: "Physical",
    shortDesc: "Foe can't use Sound moves or Yawn for 3 turns.",
    name: "Throat Chop",
    pp: 10,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
    condition: {
      duration: 3,
      onStart(target) {
        this.add("-start", target, "Throat Chop", "[silent]");
      },
      onDisableMove(pokemon) {
        for (const moveSlot of pokemon.moveSlots) {
          if (this.dex.moves.get(moveSlot.id).flags["sound"]) {
            pokemon.disableMove(moveSlot.id);
          }
        }
      },
      onBeforeMovePriority: 6,
      onBeforeMove(pokemon, target, move) {
        if (!move.isZ && !move.isMax && (move.flags["sound"] || move.id === "yawn")) {
          this.add("cant", pokemon, "move: Throat Chop");
          return false;
        }
      },
      onResidualOrder: 22,
      onEnd(target) {
        this.add("-end", target, "Throat Chop", "[silent]");
      }
    },
    secondary: {
      chance: 100,
      onHit(target) {
        target.addVolatile("throatchop");
      }
    },
    target: "normal",
    type: "Dark",
    contestType: "Clever"
  },
  windbreaker: {
    accuracy: 100,
    basePower: 85,
    category: "Special",
    shortDesc: "Foe can't use Wind moves for 3 turns.",
    name: "Wind Breaker",
    pp: 10,
    priority: 0,
    flags: { protect: 1, mirror: 1, metronome: 1, wind: 1 },
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Gust", target);
    },
    condition: {
      duration: 3,
      onStart(target) {
        this.add("-start", target, "Wind Breaker", "[silent]");
      },
      onDisableMove(pokemon) {
        for (const moveSlot of pokemon.moveSlots) {
          if (this.dex.moves.get(moveSlot.id).flags["wind"]) {
            pokemon.disableMove(moveSlot.id);
          }
        }
      },
      onBeforeMovePriority: 6,
      onBeforeMove(pokemon, target, move) {
        if (!move.isZ && !move.isMax && move.flags["wind"]) {
          this.add("cant", pokemon, "move: Wind Breaker");
          return false;
        }
      },
      onResidualOrder: 22,
      onEnd(target) {
        this.add("-end", target, "Wind Breaker", "[silent]");
      }
    },
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    },
    secondary: {
      chance: 100,
      onHit(target) {
        target.addVolatile("windbreaker");
      }
    },
    target: "normal",
    type: "Flying",
    contestType: "Clever"
  },
  hazardouswaste: {
    accuracy: 100,
    basePower: 50,
    basePowerCallback(pokemon, target, move) {
      const yourSide = pokemon.side;
      const targetSide = target.side;
      let allLayers = 0;
      if (yourSide.getSideCondition("stealthrock"))
        allLayers++;
      if (yourSide.getSideCondition("healingstones"))
        allLayers++;
      if (yourSide.getSideCondition("stickyweb"))
        allLayers++;
      if (yourSide.sideConditions["spikes"]) {
        allLayers += yourSide.sideConditions["spikes"].layers;
      }
      if (yourSide.sideConditions["toxicspikes"]) {
        allLayers += yourSide.sideConditions["toxicspikes"].layers;
      }
      if (targetSide.getSideCondition("stealthrock"))
        allLayers++;
      if (targetSide.getSideCondition("healingstones"))
        allLayers++;
      if (targetSide.getSideCondition("stickyweb"))
        allLayers++;
      if (targetSide.sideConditions["spikes"]) {
        allLayers += targetSide.sideConditions["spikes"].layers;
      }
      if (targetSide.sideConditions["toxicspikes"]) {
        allLayers += targetSide.sideConditions["toxicspikes"].layers;
      }
      this.debug("Hazardous Waste damage boost");
      return Math.min(400, 50 + 50 * allLayers);
    },
    category: "Physical",
    shortDesc: "+50 power for each hazard layer on the field. Caps at 400.",
    name: "Hazardous Waste",
    pp: 10,
    priority: 0,
    flags: { protect: 1, mirror: 1, metronome: 1 },
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Acid Downpour", target);
    },
    onHit(target, source, move) {
      const yourSide = source.side;
      const targetSide = target.side;
      let allLayers = 0;
      if (yourSide.getSideCondition("stealthrock"))
        allLayers++;
      if (yourSide.getSideCondition("healingstones"))
        allLayers++;
      if (yourSide.getSideCondition("stickyweb"))
        allLayers++;
      if (yourSide.sideConditions["spikes"]) {
        allLayers += yourSide.sideConditions["spikes"].layers;
      }
      if (yourSide.sideConditions["toxicspikes"]) {
        allLayers += yourSide.sideConditions["toxicspikes"].layers;
      }
      if (targetSide.getSideCondition("stealthrock"))
        allLayers++;
      if (targetSide.getSideCondition("healingstones"))
        allLayers++;
      if (targetSide.getSideCondition("stickyweb"))
        allLayers++;
      if (targetSide.sideConditions["spikes"]) {
        allLayers += targetSide.sideConditions["spikes"].layers;
      }
      if (targetSide.sideConditions["toxicspikes"]) {
        allLayers += targetSide.sideConditions["toxicspikes"].layers;
      }
      const bp = Math.min(400, 50 + 50 * allLayers);
      this.add("-message", `Hazardous Waste currently has a BP of ${bp}!`);
    },
    secondary: null,
    target: "normal",
    type: "Poison",
    contestType: "Tough"
  },
  chisel: {
    accuracy: 100,
    basePower: 45,
    category: "Physical",
    shortDesc: "Gives the foe a Substitute, then hits 4 times.",
    name: "Chisel",
    pp: 10,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
    multihit: 4,
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Salt Cure", target);
      target.addVolatile("substitute");
      this.add("-anim", source, "Stone Axe", target);
    },
    secondary: null,
    target: "normal",
    type: "Rock",
    contestType: "Cool"
  },
  peekaboo: {
    accuracy: 100,
    basePower: 140,
    category: "Physical",
    shortDesc: "Deal halved damage if the user takes damage before it hits.",
    name: "Peekaboo",
    pp: 20,
    priority: -3,
    flags: {
      contact: 1,
      protect: 1,
      metronome: 1,
      failmefirst: 1,
      nosleeptalk: 1,
      noassist: 1,
      failcopycat: 1,
      failinstruct: 1
    },
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Heart Stamp", target);
    },
    priorityChargeCallback(pokemon) {
      pokemon.addVolatile("peekaboo");
    },
    condition: {
      duration: 1,
      onStart(pokemon) {
        this.add("-singleturn", pokemon, "move: Peekaboo");
      },
      onHit(pokemon, source, move) {
        if (move.category !== "Status") {
          this.effectState.lostSurprise = true;
        }
      },
      onBasePower(basePower, pokemon) {
        if (pokemon.volatiles["peekaboo"]?.lostSurprise) {
          this.debug("halved power");
          return this.chainModify(0.5);
        }
      }
    },
    secondary: null,
    target: "normal",
    type: "Fairy",
    contestType: "Tough"
  },
  psychoboost: {
    num: 354,
    accuracy: 100,
    basePower: 120,
    shortDesc: "Lowers the user's Sp. Atk by 1. Hits foe(s).",
    category: "Special",
    isNonstandard: null,
    name: "Psycho Boost",
    pp: 5,
    priority: 0,
    flags: { protect: 1, mirror: 1, metronome: 1 },
    self: {
      boosts: {
        spa: -1
      }
    },
    secondary: null,
    target: "allAdjacentFoes",
    type: "Psychic",
    contestType: "Clever"
  },
  ragefist: {
    num: 889,
    accuracy: 100,
    basePower: 50,
    basePowerCallback(pokemon) {
      return Math.min(200, 50 + 50 * pokemon.timesAttacked);
    },
    shortDesc: "+50 power for each time user was hit. Max 3 hits.",
    category: "Physical",
    name: "Rage Fist",
    pp: 10,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, punch: 1 },
    onHit(target, source, move) {
      const bp = Math.min(200, 50 + 50 * source.timesAttacked);
      this.add("-message", `Rage Fist currently has a BP of ${bp}!`);
    },
    secondary: null,
    target: "normal",
    type: "Ghost"
  },
  ragingfury: {
    num: 833,
    accuracy: 100,
    basePower: 50,
    basePowerCallback(pokemon) {
      return Math.min(200, 50 + 50 * pokemon.timesAttacked);
    },
    shortDesc: "+50 power for each time user was hit. Max 3 hits.",
    category: "Physical",
    name: "Raging Fury",
    pp: 10,
    priority: 0,
    flags: { protect: 1, mirror: 1 },
    onHit(target, source, move) {
      const bp = Math.min(200, 50 + 50 * source.timesAttacked);
      this.add("-message", `Raging Fury currently has a BP of ${bp}!`);
    },
    secondary: null,
    target: "normal",
    type: "Fire"
  },
  parry: {
    accuracy: 100,
    basePower: 80,
    category: "Physical",
    shortDesc: "If the foe used a priority move, this move hits before that move and flinches the foe.",
    name: "Parry",
    pp: 10,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Mach Punch", target);
    },
    priorityChargeCallback(pokemon) {
      this.add("-anim", pokemon, "Imprison", pokemon);
      this.add("-message", `${pokemon.name} is attempting to parry!`);
      pokemon.addVolatile("parry");
    },
    secondary: {},
    // sheer force boosted
    condition: {
      duration: 1,
      onStart(target, source) {
        this.add("-singleturn", source, "Parry");
      },
      onFoeTryMove(target, source, move) {
        const targetAllExceptions = ["perishsong", "flowershield", "rototiller"];
        if (move.target === "foeSide" || move.target === "all" && !targetAllExceptions.includes(move.id)) {
          return;
        }
        const parryHolder = this.effectState.target;
        if ((source.isAlly(parryHolder) || move.target === "all") && (!source.hasAbility("innerfocus") || !source.hasAbility("shielddust") || !source.hasAbility("steadfast") || !source.hasItem("covertcloak") || !source.hasAbility("sandveil") && !this.field.isWeather("sandstorm") || !source.hasAbility("sunblock") && !this.field.isWeather("sunnyday") || !source.hasAbility("snowcloak") && !this.field.isWeather("snow")) && move.priority > 0.1) {
          this.attrLastMove("[still]");
          this.add("cant", parryHolder, "move: Parry", move, "[of] " + target);
          return false;
        }
      }
    },
    target: "normal",
    type: "Fighting",
    contestType: "Clever"
  },
  rollout: {
    num: 205,
    accuracy: 100,
    basePower: 50,
    basePowerCallback(pokemon, target, move) {
      if (pokemon.volatiles["defensecurl"]) {
        this.debug("BP doubled");
        return move.basePower * 2;
      }
      return move.basePower;
    },
    category: "Physical",
    shortDesc: "Switches the user out. 2x power if Rollout or Defense Curl was used last turn.",
    name: "Rollout",
    pp: 15,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, failinstruct: 1, noparentalbond: 1 },
    self: {
      sideCondition: "rollout"
    },
    selfSwitch: true,
    condition: {
      duration: 2,
      onBasePowerPriority: 1,
      onBasePower(basePower, attacker, defender, move) {
        if (move.id === "rollout" && !attacker.volatiles["defensecurl"]) {
          return this.chainModify(2);
        }
      }
    },
    secondary: null,
    target: "normal",
    type: "Rock",
    contestType: "Cute"
  },
  round: {
    num: 496,
    accuracy: 100,
    basePower: 50,
    category: "Special",
    shortDesc: "Switches the user out. 2x power if Round was used last turn.",
    name: "Round",
    pp: 15,
    priority: 0,
    flags: { protect: 1, mirror: 1, sound: 1, bypasssub: 1, metronome: 1 },
    self: {
      sideCondition: "round"
    },
    selfSwitch: true,
    condition: {
      duration: 2,
      onBasePowerPriority: 1,
      onBasePower(basePower, attacker, defender, move) {
        if (move.id === "round" || move.id === "echochamber") {
          return this.chainModify(2);
        }
      }
    },
    secondary: null,
    target: "normal",
    type: "Normal",
    contestType: "Beautiful"
  },
  rekindleheal: {
    accuracy: true,
    basePower: 0,
    category: "Status",
    shortDesc: "Healing from Rekindle.",
    name: "Rekindle Heal",
    pp: 5,
    priority: 0,
    flags: { metronome: 1 },
    volatileStatus: "rekindleheal",
    condition: {
      onStart(pokemon) {
        this.add("-start", pokemon, "Rekindle");
      },
      onResidualOrder: 6,
      onResidual(pokemon) {
        this.heal(pokemon.baseMaxhp / 8);
      }
    },
    secondary: null,
    target: "self",
    type: "Fire"
  },
  rekindle: {
    accuracy: true,
    basePower: 0,
    category: "Status",
    shortDesc: "Heals 33% then 12.5% every turn. Burns foes that make contact.",
    name: "Rekindle",
    pp: 10,
    priority: 0,
    flags: { snatch: 1, heal: 1, metronome: 1 },
    heal: [1, 3],
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Morning Sun", target);
    },
    self: {
      onHit(pokemon, source, move) {
        pokemon.addVolatile("rekindleheal");
        pokemon.addVolatile("rekindle");
        this.add("-message", `${pokemon.name}'s flames burn brightly!`);
      }
    },
    condition: {
      duration: 1,
      onDamagingHit(damage, target, source, move) {
        if (this.checkMoveMakesContact(move, source, target)) {
          source.trySetStatus("brn", target);
          this.add("-message", `${target.name}'s flames burnt its attacker!`);
          target.removeVolatile("rekindleheal");
          this.add("-message", `${target.name}'s flames were put out!`);
        }
      }
    },
    secondary: null,
    target: "all",
    type: "Fire",
    contestType: "Clever"
  },
  meteorbeam: {
    num: 800,
    accuracy: 90,
    basePower: 120,
    category: "Special",
    shortDesc: "Raises user's Sp. Atk by 1 on turn 1. Hits turn 2. Hits in 1 turn in Sand.",
    name: "Meteor Beam",
    pp: 10,
    priority: 0,
    flags: { charge: 1, protect: 1, mirror: 1, metronome: 1 },
    onTryMove(attacker, defender, move) {
      if (attacker.removeVolatile(move.id)) {
        return;
      }
      this.add("-prepare", attacker, move.name);
      this.boost({ spa: 1 }, attacker, attacker, move);
      if (this.field.isWeather("sandstorm")) {
        this.attrLastMove("[still]");
        this.addMove("-anim", attacker, move.name, defender);
        return;
      }
      if (!this.runEvent("ChargeMove", attacker, defender, move)) {
        return;
      }
      attacker.addVolatile("twoturnmove", defender);
      return null;
    },
    secondary: null,
    target: "normal",
    type: "Rock"
  },
  rebuild: {
    accuracy: true,
    basePower: 0,
    category: "Status",
    shortDesc: "Restores HP equal to the user's level \xD7 1.25.",
    name: "Rebuild",
    pp: 10,
    priority: 0,
    flags: { snatch: 1, heal: 1, metronome: 1 },
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Iron Defense", target);
    },
    onHit(pokemon) {
      this.heal(pokemon.level * 1.25);
    },
    secondary: null,
    target: "self",
    type: "Steel",
    contestType: "Clever"
  },
  washaway: {
    accuracy: 100,
    basePower: 80,
    category: "Special",
    shortDesc: "Removes hazards and terrains, then forces out target.",
    name: "Wash Away",
    pp: 10,
    priority: -6,
    flags: { protect: 1, mirror: 1, metronome: 1, noassist: 1, failcopycat: 1 },
    forceSwitch: true,
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Surf", target);
    },
    onHit(target, source, move) {
      let success = false;
      const removeTarget = [
        "spikes",
        "toxicspikes",
        "stealthrock",
        "stickyweb",
        "gmaxsteelsurge",
        "healingstones"
      ];
      const removeAll = [
        "spikes",
        "toxicspikes",
        "stealthrock",
        "stickyweb",
        "gmaxsteelsurge",
        "healingstones"
      ];
      for (const targetCondition of removeTarget) {
        if (target.side.removeSideCondition(targetCondition)) {
          if (!removeAll.includes(targetCondition))
            continue;
          this.add("-sideend", target.side, this.dex.conditions.get(targetCondition).name, "[from] move: Wash Away", "[of] " + source);
          success = true;
        }
      }
      for (const sideCondition of removeAll) {
        if (source.side.removeSideCondition(sideCondition)) {
          this.add("-sideend", source.side, this.dex.conditions.get(sideCondition).name, "[from] move: Wash Away", "[of] " + source);
          success = true;
        }
      }
      this.field.clearTerrain();
      return success;
    },
    target: "normal",
    type: "Water",
    contestType: "Tough"
  },
  echochamber: {
    accuracy: 100,
    basePower: 90,
    category: "Special",
    shortDesc: "1.5x power if a sound move was used last turn.",
    name: "Echo Chamber",
    pp: 10,
    priority: 0,
    flags: { protect: 1, mirror: 1, sound: 1, bypasssub: 1, metronome: 1 },
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Hyper Voice", target);
    },
    self: {
      sideCondition: "echochamber"
    },
    condition: {
      duration: 2,
      onBasePowerPriority: 1,
      onBasePower(basePower, attacker, defender, move) {
        if (move.id === "echochamber") {
          return this.chainModify(1.5);
        }
      }
    },
    secondary: null,
    target: "normal",
    type: "Steel",
    contestType: "Cool"
  },
  brickbreak: {
    inherit: true,
    basePower: 90
  },
  psychicfangs: {
    inherit: true,
    basePower: 90,
    flags: { protect: 1, mirror: 1, metronome: 1, bite: 1 }
  },
  sledgehammerblow: {
    accuracy: 100,
    basePower: 90,
    category: "Physical",
    shortDesc: "Destroys screens, unless the target is immune.",
    name: "Sledgehammer Blow",
    pp: 10,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Gigaton Hammer", target);
    },
    onTryHit(pokemon) {
      pokemon.side.removeSideCondition("reflect");
      pokemon.side.removeSideCondition("lightscreen");
      pokemon.side.removeSideCondition("auroraveil");
    },
    secondary: null,
    target: "normal",
    type: "Steel",
    contestType: "Clever"
  },
  desertstorm: {
    accuracy: 100,
    basePower: 90,
    category: "Physical",
    shortDesc: "(Partially functional placeholder) Hits two turns after being used. Sets sands when it hits, even if the target is immune.",
    name: "Desert Storm",
    pp: 15,
    priority: 0,
    flags: { allyanim: 1, metronome: 1, futuremove: 1 },
    ignoreImmunity: true,
    onTry(source, target) {
      if (!target.side.addSlotCondition(target, "futuremove"))
        return false;
      Object.assign(target.side.slotConditions[target.position]["futuremove"], {
        duration: 3,
        move: "desertstorm",
        source,
        moveData: {
          id: "desertstorm",
          name: "Desert Storm",
          accuracy: 100,
          basePower: 90,
          category: "Physical",
          priority: 0,
          flags: { allyanim: 1, futuremove: 1 },
          ignoreImmunity: false,
          self: {
            sideCondition: "desertstorm"
          },
          effectType: "Move",
          type: "Ground"
        }
      });
      this.add("-start", source, "move: Desert Storm");
      return this.NOT_FAIL;
    },
    condition: {
      duration: 1,
      onStart(source) {
        this.field.setWeather("sandstorm");
      }
    },
    secondary: null,
    target: "normal",
    type: "Ground",
    contestType: "Clever"
  },
  dragonrage: {
    num: 82,
    accuracy: 100,
    basePower: 85,
    category: "Special",
    shortDesc: "If the user is hit this turn, +1 SpA.",
    isNonstandard: null,
    name: "Dragon Rage",
    pp: 10,
    priority: 0,
    flags: { protect: 1, mirror: 1, metronome: 1 },
    priorityChargeCallback(pokemon) {
      pokemon.addVolatile("dragonrage");
    },
    condition: {
      duration: 1,
      onStart(pokemon) {
        this.add("-singleturn", pokemon, "move: Dragon Rage");
      },
      onHit(target, source, move) {
        if (target !== source && move.category !== "Status") {
          this.boost({ spa: 1 });
        }
      }
    },
    secondary: null,
    target: "normal",
    type: "Dragon",
    contestType: "Cool"
  },
  rage: {
    num: 99,
    accuracy: 100,
    basePower: 85,
    category: "Physical",
    shortDesc: "If the user is hit this turn, +1 Atk.",
    isNonstandard: null,
    name: "Rage",
    pp: 10,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
    priorityChargeCallback(pokemon) {
      pokemon.addVolatile("rage");
    },
    condition: {
      duration: 1,
      onStart(pokemon) {
        this.add("-singleturn", pokemon, "move: Rage");
      },
      onHit(target, source, move) {
        if (target !== source && move.category !== "Status") {
          this.boost({ atk: 1 });
        }
      }
    },
    secondary: null,
    target: "normal",
    type: "Normal",
    contestType: "Tough"
  },
  latentvenom: {
    accuracy: 100,
    basePower: 0,
    category: "Status",
    shortDesc: "Hits two turns after being used. Foe: badly poisoned and -1 Def & SpD.",
    name: "Latent Venom",
    pp: 5,
    priority: 0,
    flags: { snatch: 1, allyanim: 1, metronome: 1, futuremove: 1 },
    ignoreImmunity: true,
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Acid Spray", target);
    },
    onTry(source, target) {
      if (!target.side.addSlotCondition(target, "futuremove"))
        return false;
      Object.assign(target.side.slotConditions[target.position]["futuremove"], {
        duration: 3,
        move: "latentvenom",
        source,
        moveData: {
          id: "latentvenom",
          name: "Latent Venom",
          accuracy: 100,
          basePower: 0,
          category: "Status",
          priority: 0,
          flags: { allyanim: 1, futuremove: 1 },
          ignoreImmunity: false,
          status: "tox",
          boosts: {
            def: -1,
            spd: -1
          },
          effectType: "Move",
          type: "Poison"
        }
      });
      this.add("-start", source, "move: Latent Venom");
      return this.NOT_FAIL;
    },
    secondary: null,
    target: "normal",
    type: "Poison",
    contestType: "Cool"
  },
  pivotfail: {
    accuracy: true,
    basePower: 0,
    category: "Status",
    shortDesc: "Prevents pivoting moves from being used for the rest of the turn.",
    name: "Pivot Fail",
    pp: 5,
    priority: 0,
    flags: { metronome: 1 },
    volatileStatus: "pivotfail",
    condition: {
      duration: 1,
      onStart(pokemon) {
        this.add("-message", `${pokemon.name}'s pivoting moves will fail for the rest of the turn!`);
      },
      onBeforeMovePriority: 6,
      onBeforeMove(pokemon, target, move) {
        if (!move.isZ && !move.isMax && move.selfSwitch) {
          this.add("cant", pokemon, "move: Smack Down");
          return false;
        }
      },
      onModifyMove(move, pokemon, target) {
        if (!move.isZ && !move.isMax && move.selfSwitch) {
          this.add("cant", pokemon, "move: Smack Down");
          return false;
        }
      }
    },
    secondary: null,
    target: "self",
    type: "Rock"
  },
  smackdown: {
    num: 479,
    accuracy: 100,
    basePower: 65,
    category: "Physical",
    shortDesc: "Removes the target's Ground immunity and causes pivoting moves to fail.",
    name: "Smack Down",
    pp: 15,
    priority: 0,
    flags: { protect: 1, mirror: 1, nonsky: 1, metronome: 1 },
    volatileStatus: "smackdown",
    onHit(target) {
      target.addVolatile("pivotfail");
    },
    condition: {
      noCopy: true,
      onStart(pokemon) {
        let applies = false;
        if (pokemon.hasType("Flying") || pokemon.hasAbility("levitate"))
          applies = true;
        if (pokemon.hasItem("ironball") || pokemon.volatiles["ingrain"] || this.field.getPseudoWeather("gravity"))
          applies = false;
        if (pokemon.removeVolatile("fly") || pokemon.removeVolatile("bounce")) {
          applies = true;
          this.queue.cancelMove(pokemon);
          pokemon.removeVolatile("twoturnmove");
        }
        if (pokemon.volatiles["magnetrise"]) {
          applies = true;
          delete pokemon.volatiles["magnetrise"];
        }
        if (pokemon.volatiles["telekinesis"]) {
          applies = true;
          delete pokemon.volatiles["telekinesis"];
        }
        if (!applies)
          return false;
        this.add("-start", pokemon, "Smack Down");
      },
      onRestart(pokemon) {
        if (pokemon.removeVolatile("fly") || pokemon.removeVolatile("bounce")) {
          this.queue.cancelMove(pokemon);
          pokemon.removeVolatile("twoturnmove");
          this.add("-start", pokemon, "Smack Down");
        }
      }
      // groundedness implemented in battle.engine.js:BattlePokemon#isGrounded
    },
    secondary: null,
    target: "normal",
    type: "Rock",
    contestType: "Tough"
  },
  rootpull: {
    accuracy: 100,
    basePower: 90,
    category: "Physical",
    shortDesc: "100% chance to lower the target's Speed by 1 (2 if Flying-type).",
    name: "Root Pull",
    pp: 10,
    priority: 0,
    flags: { protect: 1, mirror: 1, metronome: 1 },
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Trailblaze", target);
    },
    onHit(target) {
      if (target.hasType("Flying") && !target.hasItem("covertcloak") && !target.hasAbility("shielddust")) {
        this.boost({ spe: -1 }, target);
      }
    },
    secondary: {
      chance: 100,
      boosts: {
        spe: -1
      }
    },
    target: "normal",
    type: "Grass"
  },
  snatch: {
    num: 289,
    accuracy: 100,
    basePower: 30,
    category: "Physical",
    isNonstandard: null,
    name: "Snatch",
    pp: 10,
    priority: 2,
    flags: { protect: 1, mirror: 1, bypasssub: 1, mustpressure: 1, noassist: 1, failcopycat: 1 },
    self: {
      onHit(pokemon, source, move) {
        pokemon.addVolatile("snatch");
      }
    },
    condition: {
      duration: 1,
      onStart(pokemon) {
        this.add("-singleturn", pokemon, "Snatch");
      },
      onAnyPrepareHitPriority: -1,
      onAnyPrepareHit(source, target, move) {
        const snatchUser = this.effectState.source;
        if (snatchUser.isSkyDropped())
          return;
        if (!move || move.isZ || move.isMax || !move.flags["snatch"] || move.sourceEffect === "snatch") {
          return;
        }
        snatchUser.removeVolatile("snatch");
        this.add("-activate", snatchUser, "move: Snatch", "[of] " + source);
        this.actions.useMove(move.id, snatchUser);
        return null;
      }
    },
    secondary: null,
    target: "normal",
    type: "Dark",
    contestType: "Clever"
  },
  tailslap: {
    inherit: true,
    accuracy: 100
  },
  pinmissile: {
    inherit: true,
    accuracy: 100
  },
  rockblast: {
    inherit: true,
    accuracy: 100
  },
  signalbeam: {
    num: 324,
    accuracy: 100,
    basePower: 75,
    category: "Special",
    shortDesc: "Nullifies the target's Ability.",
    isNonstandard: null,
    name: "Signal Beam",
    pp: 10,
    priority: 0,
    flags: { protect: 1, mirror: 1, metronome: 1 },
    onHit(target) {
      if (target.getAbility().flags["cantsuppress"])
        return;
      target.addVolatile("gastroacid");
    },
    onAfterSubDamage(damage, target) {
      if (target.getAbility().flags["cantsuppress"])
        return;
      target.addVolatile("gastroacid");
    },
    secondary: null,
    target: "normal",
    type: "Bug",
    contestType: "Beautiful"
  },
  flyingpress: {
    num: 560,
    accuracy: 95,
    basePower: 100,
    category: "Physical",
    shortDesc: "Either Fighting or Flying-type, whichever is more effective.",
    name: "Flying Press",
    pp: 10,
    flags: { contact: 1, protect: 1, mirror: 1, gravity: 1, distance: 1, nonsky: 1, metronome: 1 },
    onModifyType(move, pokemon) {
      for (const target of pokemon.side.foe.active) {
        const type1 = "Fighting";
        const type2 = "Flying";
        if (this.dex.getEffectiveness(type1, target) < this.dex.getEffectiveness(type2, target)) {
          move.type = "Flying";
        } else if (target.hasType("Ghost") && !pokemon.hasAbility("scrappy") && !pokemon.hasAbility("mindseye") && !target.hasItem("ringtarget")) {
          move.type = "Flying";
        } else if (this.dex.getEffectiveness(type1, target) === this.dex.getEffectiveness(type2, target)) {
          if (pokemon.hasType("Flying") && !pokemon.hasType("Fighting")) {
            move.type = "Flying";
          }
        }
      }
    },
    onHit(target, source, move) {
      this.add("-message", `Flying Press dealt ${move.type}-type damage!`);
    },
    priority: 0,
    secondary: null,
    target: "any",
    type: "Fighting",
    zMove: { basePower: 170 },
    contestType: "Tough"
  },
  softwarecrash: {
    num: 560,
    accuracy: 95,
    basePower: 100,
    category: "Special",
    shortDesc: "Either Bug or Electric-type, whichever is more effective.",
    name: "Software Crash",
    pp: 10,
    flags: { protect: 1, mirror: 1, metronome: 1 },
    onPrepareHit(target, source, move) {
      this.attrLastMove("[still]");
      this.add("-anim", source, "Hyper Beam", target);
    },
    onModifyType(move, pokemon) {
      for (const target of pokemon.side.foe.active) {
        const type1 = "Bug";
        const type2 = "Electric";
        if (this.dex.getEffectiveness(type1, target) < this.dex.getEffectiveness(type2, target)) {
          if (!target.hasType("Ground") && !target.hasItem("ringtarget")) {
            move.type = "Electric";
          }
        } else if (this.dex.getEffectiveness(type1, target) === this.dex.getEffectiveness(type2, target)) {
          if (pokemon.hasType("Electric") && !pokemon.hasType("Bug")) {
            move.type = "Electric";
          }
        }
      }
    },
    onHit(target, source, move) {
      this.add("-message", `Software Crash dealt ${move.type}-type damage!`);
    },
    priority: 0,
    secondary: null,
    target: "any",
    type: "Bug",
    zMove: { basePower: 170 },
    contestType: "Tough"
  },
  lashout: {
    num: 808,
    accuracy: 100,
    basePower: 70,
    category: "Physical",
    shortDesc: "2x power if the user has negative stat changes or a status.",
    name: "Lash Out",
    pp: 10,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
    onBasePower(basePower, pokemon) {
      const negativeVolatiles = [
        "confusion",
        "taunt",
        "torment",
        "trapped",
        "partiallytrapped",
        "leechseed",
        "sandspit",
        "attract",
        "curse",
        "disable",
        "electrify",
        "embargo",
        "encore",
        "foresight",
        "gastroacid",
        "foresight",
        "miracleeye",
        "glaiverush",
        "healblock",
        "throatchop",
        "windbreaker",
        "nightmare",
        "octolock",
        "powder",
        "saltcure",
        "smackdown",
        "syrupbomb",
        "tarshot",
        "telekinesis",
        "yawn"
      ];
      let i;
      for (i in pokemon.boosts) {
        for (const volatile of negativeVolatiles) {
          if (pokemon.status && pokemon.status !== "brn" || pokemon.volatiles[volatile] || pokemon.boosts[i] < 0) {
            return this.chainModify(2);
          } else if (pokemon.status === "brn") {
            return this.chainModify(4);
          }
        }
      }
    },
    secondary: null,
    target: "normal",
    type: "Dark"
  },
  naturalgift: {
    num: 363,
    accuracy: 100,
    basePower: 0,
    category: "Physical",
    shortDesc: "Type and power based on user's berry.",
    isNonstandard: null,
    name: "Natural Gift",
    pp: 15,
    priority: 0,
    flags: { protect: 1, mirror: 1, metronome: 1 },
    onModifyType(move, pokemon) {
      if (pokemon.ignoringItem())
        return;
      const item = pokemon.getItem();
      if (!item.naturalGift)
        return;
      move.type = item.naturalGift.type;
    },
    onPrepareHit(target, pokemon, move) {
      if (pokemon.ignoringItem())
        return false;
      const item = pokemon.getItem();
      if (!item.naturalGift)
        return false;
      move.basePower = item.naturalGift.basePower;
      this.debug("BP: " + move.basePower);
    },
    onBasePower(basePower, pokemon) {
      if (pokemon.hasAbility("ripen") || pokemon.hasAbility("harvest")) {
        return this.chainModify(2);
      }
    },
    secondary: null,
    target: "normal",
    type: "Normal",
    zMove: { basePower: 160 },
    maxMove: { basePower: 130 },
    contestType: "Clever"
  },
  // all edited unchanged moves
  stealthrock: {
    num: 446,
    accuracy: true,
    basePower: 0,
    category: "Status",
    name: "Stealth Rock",
    pp: 20,
    priority: 0,
    flags: { reflectable: 1, snatch: 1, metronome: 1 },
    sideCondition: "stealthrock",
    condition: {
      // this is a side condition
      onSideStart(side) {
        this.add("-sidestart", side, "move: Stealth Rock");
      },
      onEntryHazard(pokemon) {
        if (pokemon.hasItem("heavydutyboots") || pokemon.hasAbility("overcoat") || pokemon.hasItem("mantisclaw"))
          return;
        const typeMod = this.clampIntRange(pokemon.runEffectiveness(this.dex.getActiveMove("stealthrock")), -6, 6);
        if (pokemon.hasAbility("smelt")) {
          const fireHazard = this.dex.getActiveMove("Stealth Rock");
          fireHazard.type = "Fire";
          const smeltMod = this.clampIntRange(pokemon.runEffectiveness(fireHazard), -6, 6);
          this.damage(pokemon.maxhp * Math.pow(2, smeltMod) / 8);
        } else {
          this.damage(pokemon.maxhp * Math.pow(2, typeMod) / 8);
        }
      }
    },
    secondary: null,
    target: "foeSide",
    type: "Rock",
    zMove: { boost: { def: 1 } },
    contestType: "Cool"
  },
  spikes: {
    num: 191,
    accuracy: true,
    basePower: 0,
    category: "Status",
    name: "Spikes",
    pp: 20,
    priority: 0,
    flags: { reflectable: 1, snatch: 1, nonsky: 1, metronome: 1, mustpressure: 1 },
    sideCondition: "spikes",
    condition: {
      // this is a side condition
      onSideStart(side) {
        this.add("-sidestart", side, "Spikes");
        this.effectState.layers = 1;
      },
      onSideRestart(side) {
        if (this.effectState.layers >= 3)
          return false;
        this.add("-sidestart", side, "Spikes");
        this.effectState.layers++;
      },
      onEntryHazard(pokemon) {
        if (!pokemon.isGrounded())
          return;
        if (pokemon.hasItem("heavydutyboots") || pokemon.hasAbility("overcoat") || pokemon.hasItem("mantisclaw"))
          return;
        const damageAmounts = [0, 3, 4, 6];
        this.damage(damageAmounts[this.effectState.layers] * pokemon.maxhp / 24);
      }
    },
    secondary: null,
    target: "foeSide",
    type: "Ground",
    zMove: { boost: { def: 1 } },
    contestType: "Clever"
  },
  toxicspikes: {
    num: 390,
    accuracy: true,
    basePower: 0,
    category: "Status",
    name: "Toxic Spikes",
    pp: 20,
    priority: 0,
    flags: { reflectable: 1, snatch: 1, nonsky: 1, metronome: 1, mustpressure: 1 },
    sideCondition: "toxicspikes",
    condition: {
      // this is a side condition
      onSideStart(side) {
        this.add("-sidestart", side, "move: Toxic Spikes");
        this.effectState.layers = 1;
      },
      onSideRestart(side) {
        if (this.effectState.layers >= 2)
          return false;
        this.add("-sidestart", side, "move: Toxic Spikes");
        this.effectState.layers++;
      },
      onEntryHazard(pokemon) {
        if (!pokemon.isGrounded())
          return;
        if (pokemon.hasType("Poison")) {
          this.add("-sideend", pokemon.side, "move: Toxic Spikes", "[of] " + pokemon);
          pokemon.side.removeSideCondition("toxicspikes");
        } else if (pokemon.hasType("Steel") || pokemon.hasItem("heavydutyboots") || pokemon.hasAbility("overcoat") || pokemon.hasItem("mantisclaw")) {
          return;
        } else if (this.effectState.layers >= 2) {
          pokemon.trySetStatus("tox", pokemon.side.foe.active[0]);
        } else {
          pokemon.trySetStatus("psn", pokemon.side.foe.active[0]);
        }
      }
    },
    secondary: null,
    target: "foeSide",
    type: "Poison",
    zMove: { boost: { def: 1 } },
    contestType: "Clever"
  },
  stickyweb: {
    num: 564,
    accuracy: true,
    basePower: 0,
    category: "Status",
    name: "Sticky Web",
    pp: 20,
    priority: 0,
    flags: { reflectable: 1, snatch: 1, metronome: 1 },
    sideCondition: "stickyweb",
    condition: {
      onSideStart(side) {
        this.add("-sidestart", side, "move: Sticky Web");
      },
      onEntryHazard(pokemon) {
        if (!pokemon.isGrounded() || pokemon.hasItem("heavydutyboots") || pokemon.hasAbility("overcoat") || pokemon.hasItem("mantisclaw"))
          return;
        this.add("-activate", pokemon, "move: Sticky Web");
        this.boost({ spe: -1 }, pokemon, this.effectState.source, this.dex.getActiveMove("stickyweb"));
      }
    },
    secondary: null,
    target: "foeSide",
    type: "Bug",
    zMove: { boost: { spe: 1 } },
    contestType: "Tough"
  },
  defog: {
    num: 432,
    accuracy: true,
    basePower: 0,
    category: "Status",
    name: "Defog",
    pp: 15,
    priority: 0,
    flags: { protect: 1, reflectable: 1, mirror: 1, bypasssub: 1, metronome: 1, wind: 1 },
    onHit(target, source, move) {
      let success = false;
      if (!target.volatiles["substitute"] || move.infiltrates)
        success = !!this.boost({ evasion: -1 });
      const removeTarget = [
        "reflect",
        "lightscreen",
        "auroraveil",
        "safeguard",
        "mist",
        "spikes",
        "toxicspikes",
        "stealthrock",
        "stickyweb",
        "gmaxsteelsurge",
        "healingstones"
      ];
      const removeAll = [
        "spikes",
        "toxicspikes",
        "stealthrock",
        "stickyweb",
        "gmaxsteelsurge",
        "healingstones"
      ];
      for (const targetCondition of removeTarget) {
        if (target.side.removeSideCondition(targetCondition)) {
          if (!removeAll.includes(targetCondition))
            continue;
          this.add("-sideend", target.side, this.dex.conditions.get(targetCondition).name, "[from] move: Defog", "[of] " + source);
          success = true;
        }
      }
      for (const sideCondition of removeAll) {
        if (source.side.removeSideCondition(sideCondition)) {
          this.add("-sideend", source.side, this.dex.conditions.get(sideCondition).name, "[from] move: Defog", "[of] " + source);
          success = true;
        }
      }
      this.field.clearTerrain();
      return success;
    },
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    },
    secondary: null,
    target: "normal",
    type: "Flying",
    zMove: { boost: { accuracy: 1 } },
    contestType: "Cool"
  },
  blazingtorque: {
    inherit: true,
    isNonstandard: null
  },
  wickedtorque: {
    inherit: true,
    isNonstandard: null
  },
  noxioustorque: {
    inherit: true,
    isNonstandard: null
  },
  combattorque: {
    inherit: true,
    isNonstandard: null
  },
  magicaltorque: {
    inherit: true,
    isNonstandard: null
  },
  rapidspin: {
    num: 229,
    accuracy: 100,
    basePower: 50,
    category: "Physical",
    name: "Rapid Spin",
    pp: 40,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
    onAfterHit(target, pokemon, move) {
      if (!move.hasSheerForce) {
        if (pokemon.hp && pokemon.removeVolatile("leechseed")) {
          this.add("-end", pokemon, "Leech Seed", "[from] move: Rapid Spin", "[of] " + pokemon);
        }
        const sideConditions = ["spikes", "toxicspikes", "stealthrock", "stickyweb", "gmaxsteelsurge", "healingstones"];
        for (const condition of sideConditions) {
          if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
            this.add("-sideend", pokemon.side, this.dex.conditions.get(condition).name, "[from] move: Rapid Spin", "[of] " + pokemon);
          }
        }
        if (pokemon.hp && pokemon.volatiles["partiallytrapped"]) {
          pokemon.removeVolatile("partiallytrapped");
        }
      }
    },
    onAfterSubDamage(damage, target, pokemon, move) {
      if (!move.hasSheerForce) {
        if (pokemon.hp && pokemon.removeVolatile("leechseed")) {
          this.add("-end", pokemon, "Leech Seed", "[from] move: Rapid Spin", "[of] " + pokemon);
        }
        const sideConditions = ["spikes", "toxicspikes", "stealthrock", "stickyweb", "gmaxsteelsurge", "healingstones"];
        for (const condition of sideConditions) {
          if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
            this.add("-sideend", pokemon.side, this.dex.conditions.get(condition).name, "[from] move: Rapid Spin", "[of] " + pokemon);
          }
        }
        if (pokemon.hp && pokemon.volatiles["partiallytrapped"]) {
          pokemon.removeVolatile("partiallytrapped");
        }
      }
    },
    secondary: {
      chance: 100,
      self: {
        boosts: {
          spe: 1
        }
      }
    },
    target: "normal",
    type: "Normal",
    contestType: "Cool"
  },
  mortalspin: {
    num: 866,
    accuracy: 100,
    basePower: 30,
    category: "Physical",
    name: "Mortal Spin",
    pp: 15,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
    onAfterHit(target, pokemon, move) {
      if (!move.hasSheerForce) {
        if (pokemon.hp && pokemon.removeVolatile("leechseed")) {
          this.add("-end", pokemon, "Leech Seed", "[from] move: Mortal Spin", "[of] " + pokemon);
        }
        const sideConditions = ["spikes", "toxicspikes", "stealthrock", "stickyweb", "gmaxsteelsurge", "healingstones"];
        for (const condition of sideConditions) {
          if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
            this.add("-sideend", pokemon.side, this.dex.conditions.get(condition).name, "[from] move: Mortal Spin", "[of] " + pokemon);
          }
        }
        if (pokemon.hp && pokemon.volatiles["partiallytrapped"]) {
          pokemon.removeVolatile("partiallytrapped");
        }
      }
    },
    onAfterSubDamage(damage, target, pokemon, move) {
      if (!move.hasSheerForce) {
        if (pokemon.hp && pokemon.removeVolatile("leechseed")) {
          this.add("-end", pokemon, "Leech Seed", "[from] move: Mortal Spin", "[of] " + pokemon);
        }
        const sideConditions = ["spikes", "toxicspikes", "stealthrock", "stickyweb", "gmaxsteelsurge", "healingstones"];
        for (const condition of sideConditions) {
          if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
            this.add("-sideend", pokemon.side, this.dex.conditions.get(condition).name, "[from] move: Mortal Spin", "[of] " + pokemon);
          }
        }
        if (pokemon.hp && pokemon.volatiles["partiallytrapped"]) {
          pokemon.removeVolatile("partiallytrapped");
        }
      }
    },
    secondary: {
      chance: 100,
      status: "psn"
    },
    target: "allAdjacentFoes",
    type: "Poison"
  },
  tidyup: {
    num: 882,
    accuracy: true,
    basePower: 0,
    category: "Status",
    name: "Tidy Up",
    pp: 10,
    priority: 0,
    flags: {},
    onHit(pokemon) {
      let success = false;
      for (const active of this.getAllActive()) {
        if (active.removeVolatile("substitute"))
          success = true;
      }
      const removeAll = ["spikes", "toxicspikes", "stealthrock", "stickyweb", "gmaxsteelsurge", "healingstones"];
      const sides = [pokemon.side, ...pokemon.side.foeSidesWithConditions()];
      for (const side of sides) {
        for (const sideCondition of removeAll) {
          if (side.removeSideCondition(sideCondition)) {
            this.add("-sideend", side, this.dex.conditions.get(sideCondition).name);
            success = true;
          }
        }
      }
      if (success)
        this.add("-activate", pokemon, "move: Tidy Up");
      return !!this.boost({ atk: 1, spe: 1 }, pokemon, pokemon, null, false, true) || success;
    },
    secondary: null,
    target: "self",
    type: "Normal"
  },
  courtchange: {
    num: 756,
    accuracy: 100,
    basePower: 0,
    category: "Status",
    name: "Court Change",
    pp: 10,
    priority: 0,
    flags: { mirror: 1, metronome: 1 },
    onHitField(target, source) {
      const sideConditions = [
        "mist",
        "lightscreen",
        "reflect",
        "spikes",
        "safeguard",
        "tailwind",
        "toxicspikes",
        "stealthrock",
        "waterpledge",
        "firepledge",
        "grasspledge",
        "stickyweb",
        "auroraveil",
        "gmaxsteelsurge",
        "gmaxcannonade",
        "gmaxvinelash",
        "gmaxwildfire",
        "healingstones"
      ];
      let success = false;
      if (this.gameType === "freeforall") {
        const offset = this.random(3) + 1;
        const sides = [this.sides[0], this.sides[2], this.sides[1], this.sides[3]];
        const temp = { 0: {}, 1: {}, 2: {}, 3: {} };
        for (const side of sides) {
          for (const id in side.sideConditions) {
            if (!sideConditions.includes(id))
              continue;
            temp[side.n][id] = side.sideConditions[id];
            delete side.sideConditions[id];
            const effectName = this.dex.conditions.get(id).name;
            this.add("-sideend", side, effectName, "[silent]");
            success = true;
          }
        }
        for (let i = 0; i < 4; i++) {
          const sourceSideConditions = temp[sides[i].n];
          const targetSide = sides[(i + offset) % 4];
          for (const id in sourceSideConditions) {
            targetSide.sideConditions[id] = sourceSideConditions[id];
            const effectName = this.dex.conditions.get(id).name;
            let layers = sourceSideConditions[id].layers || 1;
            for (; layers > 0; layers--)
              this.add("-sidestart", targetSide, effectName, "[silent]");
          }
        }
      } else {
        const sourceSideConditions = source.side.sideConditions;
        const targetSideConditions = source.side.foe.sideConditions;
        const sourceTemp = {};
        const targetTemp = {};
        for (const id in sourceSideConditions) {
          if (!sideConditions.includes(id))
            continue;
          sourceTemp[id] = sourceSideConditions[id];
          delete sourceSideConditions[id];
          success = true;
        }
        for (const id in targetSideConditions) {
          if (!sideConditions.includes(id))
            continue;
          targetTemp[id] = targetSideConditions[id];
          delete targetSideConditions[id];
          success = true;
        }
        for (const id in sourceTemp) {
          targetSideConditions[id] = sourceTemp[id];
        }
        for (const id in targetTemp) {
          sourceSideConditions[id] = targetTemp[id];
        }
        this.add("-swapsideconditions");
      }
      if (!success)
        return false;
      this.add("-activate", source, "move: Court Change");
    },
    secondary: null,
    target: "all",
    type: "Normal"
  },
  healblock: {
    num: 377,
    accuracy: 100,
    basePower: 0,
    category: "Status",
    isNonstandard: "Past",
    name: "Heal Block",
    pp: 15,
    priority: 0,
    flags: { protect: 1, reflectable: 1, mirror: 1, metronome: 1 },
    volatileStatus: "healblock",
    condition: {
      duration: 5,
      durationCallback(target, source, effect) {
        if (source?.hasAbility("persistent")) {
          this.add("-activate", source, "ability: Persistent", "[move] Heal Block");
          return 7;
        }
        if (effect && effect.id === "deathaura") {
          return 0;
        }
        return 5;
      },
      onStart(pokemon, source) {
        this.add("-start", pokemon, "move: Heal Block");
        source.moveThisTurnResult = true;
      },
      onDisableMove(pokemon) {
        for (const moveSlot of pokemon.moveSlots) {
          if (this.dex.moves.get(moveSlot.id).flags["heal"]) {
            pokemon.disableMove(moveSlot.id);
          }
        }
      },
      onBeforeMovePriority: 6,
      onBeforeMove(pokemon, target, move) {
        if ((move.flags["heal"] || move.id === "bitterblade") && !move.isZ && !move.isMax) {
          this.add("cant", pokemon, "move: Heal Block", move);
          return false;
        }
      },
      onModifyMove(move, pokemon, target) {
        if ((move.flags["heal"] || move.id === "bitterblade") && !move.isZ && !move.isMax) {
          this.add("cant", pokemon, "move: Heal Block", move);
          return false;
        }
      },
      onResidualOrder: 20,
      onEnd(pokemon) {
        this.add("-end", pokemon, "move: Heal Block");
      },
      onTryHeal(damage, target, source, effect) {
        if (effect?.id === "zpower" || this.effectState.isZ)
          return damage;
        return false;
      },
      onRestart(target, source) {
        this.add("-fail", target, "move: Heal Block");
        if (!source.moveThisTurnResult) {
          source.moveThisTurnResult = false;
        }
      }
    },
    secondary: null,
    target: "allAdjacentFoes",
    type: "Psychic",
    zMove: { boost: { spa: 2 } },
    contestType: "Clever"
  },
  electricterrain: {
    num: 604,
    accuracy: true,
    basePower: 0,
    category: "Status",
    name: "Electric Terrain",
    pp: 10,
    priority: 0,
    flags: { nonsky: 1, metronome: 1 },
    terrain: "electricterrain",
    condition: {
      duration: 5,
      durationCallback(source, effect) {
        if (source?.hasItem("terrainextender")) {
          return 8;
        }
        return 5;
      },
      onSetStatus(status, target, source, effect) {
        if (status.id === "slp" && target.isGrounded() && !target.isSemiInvulnerable()) {
          if (effect.id === "yawn" || effect.effectType === "Move" && !effect.secondaries) {
            for (const active of this.getAllActive()) {
              if (active.hasAbility("cloudnine")) {
                return;
              }
            }
            this.add("-activate", target, "move: Electric Terrain");
          }
          for (const active of this.getAllActive()) {
            if (active.hasAbility("cloudnine")) {
              this.add("-message", `${active.name} suppresses the effects of the terrain!`);
              return;
            }
          }
          return false;
        }
      },
      onTryAddVolatile(status, target) {
        if (!target.isGrounded() || target.isSemiInvulnerable())
          return;
        if (status.id === "yawn") {
          this.add("-activate", target, "move: Electric Terrain");
          for (const active of this.getAllActive()) {
            if (active.hasAbility("cloudnine")) {
              this.add("-message", `${active.name} suppresses the effects of the terrain!`);
              return;
            }
          }
          return null;
        }
      },
      onBasePowerPriority: 6,
      onBasePower(basePower, attacker, defender, move) {
        if (move.type === "Electric" && attacker.isGrounded() && !attacker.isSemiInvulnerable()) {
          for (const active of this.getAllActive()) {
            if (active.hasAbility("cloudnine")) {
              this.add("-message", `${active.name} suppresses the effects of the terrain!`);
              return;
            }
          }
          this.debug("electric terrain boost");
          return this.chainModify([5325, 4096]);
        }
      },
      onFieldStart(field, source, effect) {
        if (effect?.effectType === "Ability") {
          this.add("-fieldstart", "move: Electric Terrain", "[from] ability: " + effect.name, "[of] " + source);
        } else {
          this.add("-fieldstart", "move: Electric Terrain");
        }
      },
      onFieldResidualOrder: 27,
      onFieldResidualSubOrder: 7,
      onFieldEnd() {
        this.add("-fieldend", "move: Electric Terrain");
      }
    },
    secondary: null,
    target: "all",
    type: "Electric",
    zMove: { boost: { spe: 1 } },
    contestType: "Clever"
  },
  psychicterrain: {
    num: 678,
    accuracy: true,
    basePower: 0,
    category: "Status",
    name: "Psychic Terrain",
    pp: 10,
    priority: 0,
    flags: { nonsky: 1, metronome: 1 },
    terrain: "psychicterrain",
    condition: {
      duration: 5,
      durationCallback(source, effect) {
        if (source?.hasItem("terrainextender")) {
          return 8;
        }
        return 5;
      },
      onTryHitPriority: 4,
      onTryHit(target, source, effect) {
        if (effect && (effect.priority <= 0.1 || effect.target === "self")) {
          return;
        }
        if (target.isSemiInvulnerable() || target.isAlly(source))
          return;
        if (!target.isGrounded()) {
          const baseMove = this.dex.moves.get(effect.id);
          if (baseMove.priority > 0) {
            this.hint("Psychic Terrain doesn't affect Pok\xE9mon immune to Ground.");
          }
          return;
        }
        for (const active of this.getAllActive()) {
          if (active.hasAbility("cloudnine")) {
            this.add("-message", `${active.name} suppresses the effects of the terrain!`);
            return;
          }
        }
        this.add("-activate", target, "move: Psychic Terrain");
        return null;
      },
      onBasePowerPriority: 6,
      onBasePower(basePower, attacker, defender, move) {
        if (move.type === "Psychic" && attacker.isGrounded() && !attacker.isSemiInvulnerable()) {
          for (const active of this.getAllActive()) {
            if (active.hasAbility("cloudnine")) {
              this.add("-message", `${active.name} suppresses the effects of the terrain!`);
              return;
            }
          }
          this.debug("psychic terrain boost");
          return this.chainModify([5325, 4096]);
        }
      },
      onFieldStart(field, source, effect) {
        if (effect?.effectType === "Ability") {
          this.add("-fieldstart", "move: Psychic Terrain", "[from] ability: " + effect.name, "[of] " + source);
        } else {
          this.add("-fieldstart", "move: Psychic Terrain");
        }
      },
      onFieldResidualOrder: 27,
      onFieldResidualSubOrder: 7,
      onFieldEnd() {
        this.add("-fieldend", "move: Psychic Terrain");
      }
    },
    secondary: null,
    target: "all",
    type: "Psychic",
    zMove: { boost: { spa: 1 } },
    contestType: "Clever"
  },
  grassyterrain: {
    num: 580,
    accuracy: true,
    basePower: 0,
    category: "Status",
    name: "Grassy Terrain",
    pp: 10,
    priority: 0,
    flags: { nonsky: 1, metronome: 1 },
    terrain: "grassyterrain",
    condition: {
      duration: 5,
      durationCallback(source, effect) {
        if (source?.hasItem("terrainextender")) {
          return 8;
        }
        return 5;
      },
      onBasePowerPriority: 6,
      onBasePower(basePower, attacker, defender, move) {
        const weakenedMoves = ["earthquake", "bulldoze", "magnitude"];
        if (weakenedMoves.includes(move.id) && defender.isGrounded() && !defender.isSemiInvulnerable()) {
          for (const target of this.getAllActive()) {
            if (target.hasAbility("cloudnine")) {
              this.add("-message", `${target.name} suppresses the effects of the terrain!`);
              return;
            }
          }
          this.debug("move weakened by grassy terrain");
          return this.chainModify(0.5);
        }
        if (move.type === "Grass" && attacker.isGrounded()) {
          for (const target of this.getAllActive()) {
            if (target.hasAbility("cloudnine")) {
              this.add("-message", `${target.name} suppresses the effects of the terrain!`);
              return;
            }
          }
          this.debug("grassy terrain boost");
          return this.chainModify([5325, 4096]);
        }
      },
      onFieldStart(field, source, effect) {
        if (effect?.effectType === "Ability") {
          this.add("-fieldstart", "move: Grassy Terrain", "[from] ability: " + effect.name, "[of] " + source);
        } else {
          this.add("-fieldstart", "move: Grassy Terrain");
        }
      },
      onResidualOrder: 5,
      onResidualSubOrder: 2,
      onResidual(pokemon) {
        for (const target of this.getAllActive()) {
          if (target.hasAbility("cloudnine")) {
            this.add("-message", `${target.name} suppresses the effects of the terrain!`);
            return;
          }
        }
        if (pokemon.isGrounded() && !pokemon.isSemiInvulnerable()) {
          this.heal(pokemon.baseMaxhp / 16, pokemon, pokemon);
        } else {
          this.debug(`Pokemon semi-invuln or not grounded; Grassy Terrain skipped`);
        }
      },
      onFieldResidualOrder: 27,
      onFieldResidualSubOrder: 7,
      onFieldEnd() {
        this.add("-fieldend", "move: Grassy Terrain");
      }
    },
    secondary: null,
    target: "all",
    type: "Grass",
    zMove: { boost: { def: 1 } },
    contestType: "Beautiful"
  },
  mistyterrain: {
    num: 581,
    accuracy: true,
    basePower: 0,
    category: "Status",
    name: "Misty Terrain",
    pp: 10,
    priority: 0,
    flags: { nonsky: 1, metronome: 1 },
    terrain: "mistyterrain",
    condition: {
      duration: 5,
      durationCallback(source, effect) {
        if (source?.hasItem("terrainextender")) {
          return 8;
        }
        return 5;
      },
      onSetStatus(status, target, source, effect) {
        if (!target.isGrounded() || target.isSemiInvulnerable())
          return;
        if (effect && (effect.status || effect.id === "yawn")) {
          for (const active of this.getAllActive()) {
            if (active.hasAbility("cloudnine")) {
              return;
            }
          }
          this.add("-activate", target, "move: Misty Terrain");
        }
        for (const active of this.getAllActive()) {
          if (active.hasAbility("cloudnine")) {
            this.add("-message", `${active.name} suppresses the effects of the terrain!`);
            return;
          }
        }
        return false;
      },
      onTryAddVolatile(status, target, source, effect) {
        if (!target.isGrounded() || target.isSemiInvulnerable())
          return;
        if (status.id === "confusion") {
          for (const active of this.getAllActive()) {
            if (active.hasAbility("cloudnine")) {
              this.add("-message", `${active.name} suppresses the effects of the terrain!`);
              return;
            }
          }
          if (effect.effectType === "Move" && !effect.secondaries)
            this.add("-activate", target, "move: Misty Terrain");
          return null;
        }
      },
      onBasePowerPriority: 6,
      onBasePower(basePower, attacker, defender, move) {
        if (move.type === "Dragon" && defender.isGrounded() && !defender.isSemiInvulnerable()) {
          for (const target of this.getAllActive()) {
            if (target.hasAbility("cloudnine")) {
              this.add("-message", `${target.name} suppresses the effects of the terrain!`);
              return;
            }
          }
          this.debug("misty terrain weaken");
          return this.chainModify(0.5);
        }
      },
      onFieldStart(field, source, effect) {
        if (effect?.effectType === "Ability") {
          this.add("-fieldstart", "move: Misty Terrain", "[from] ability: " + effect.name, "[of] " + source);
        } else {
          this.add("-fieldstart", "move: Misty Terrain");
        }
      },
      onFieldResidualOrder: 27,
      onFieldResidualSubOrder: 7,
      onFieldEnd() {
        this.add("-fieldend", "Misty Terrain");
      }
    },
    secondary: null,
    target: "all",
    type: "Fairy",
    zMove: { boost: { spd: 1 } },
    contestType: "Beautiful"
  },
  camouflage: {
    inherit: true,
    onHit(target) {
      let newType = "Normal";
      if (this.field.isTerrain("electricterrain")) {
        newType = "Electric";
      } else if (this.field.isTerrain("grassyterrain")) {
        newType = "Grass";
      } else if (this.field.isTerrain("mistyterrain")) {
        newType = "Fairy";
      } else if (this.field.isTerrain("psychicterrain")) {
        newType = "Psychic";
      }
      for (const active of this.getAllActive()) {
        if (active.hasAbility("cloudnine")) {
          this.add("-message", `${target.name} suppresses the effects of the terrain!`);
          newType = "Normal";
        }
      }
      if (target.getTypes().join() === newType || !target.setType(newType))
        return false;
      this.add("-start", target, "typechange", newType);
    }
  },
  expandingforce: {
    inherit: true,
    onBasePower(basePower, source) {
      if (this.getAllActive().some((x) => x.hasAbility("cloudnine")))
        return;
      if (this.field.isTerrain("psychicterrain") && source.isGrounded()) {
        this.debug("terrain buff");
        return this.chainModify(1.5);
      }
    },
    onModifyMove(move, source, target) {
      if (this.getAllActive().some((x) => x.hasAbility("cloudnine")))
        return;
      if (this.field.isTerrain("psychicterrain") && source.isGrounded()) {
        move.target = "allAdjacentFoes";
      }
    }
  },
  floralhealing: {
    inherit: true,
    onHit(target, source) {
      let success = false;
      if (this.field.isTerrain("grassyterrain")) {
        if (this.getAllActive().some((x) => x.hasAbility("cloudnine"))) {
          this.add("-message", `${target.name} suppresses the effects of the terrain!`);
          return success;
        }
        success = !!this.heal(this.modify(target.baseMaxhp, 0.667));
      } else {
        success = !!this.heal(Math.ceil(target.baseMaxhp * 0.5));
      }
      if (success && target.side !== source.side) {
        target.staleness = "external";
      }
      return success;
    }
  },
  grassyglide: {
    inherit: true,
    onModifyPriority(priority, source, target, move) {
      if (this.getAllActive().some((x) => x.hasAbility("cloudnine")))
        return priority;
      if (this.field.isTerrain("grassyterrain") && source.isGrounded()) {
        return priority + 1;
      }
    }
  },
  mistyexplosion: {
    inherit: true,
    onBasePower(basePower, source) {
      if (this.getAllActive().some((x) => x.hasAbility("cloudnine")))
        return;
      if (this.field.isTerrain("mistyterrain") && source.isGrounded()) {
        this.debug("misty terrain boost");
        return this.chainModify(1.5);
      }
    }
  },
  naturepower: {
    inherit: true,
    onTryHit(target, pokemon) {
      let move = "triattack";
      if (this.field.isTerrain("electricterrain")) {
        move = "thunderbolt";
      } else if (this.field.isTerrain("grassyterrain")) {
        move = "energyball";
      } else if (this.field.isTerrain("mistyterrain")) {
        move = "moonblast";
      } else if (this.field.isTerrain("psychicterrain")) {
        move = "psychic";
      }
      for (const active of this.getAllActive()) {
        if (active.hasAbility("cloudnine")) {
          this.add("-message", `${active.name} suppresses the effects of the terrain!`);
          move = "triattack";
        }
      }
      this.actions.useMove(move, pokemon, target);
      return null;
    }
  },
  risingvoltage: {
    inherit: true,
    onBasePower(basePower, pokemon, target) {
      if (this.getAllActive().some((x) => x.hasAbility("cloudnine")))
        return;
      if (this.field.isTerrain("electricterrain") && target.isGrounded()) {
        this.debug("terrain buff");
        return this.chainModify(2);
      }
    }
  },
  secretpower: {
    inherit: true,
    onModifyMove(move, pokemon) {
      if (this.field.isTerrain(""))
        return;
      for (const target of this.getAllActive()) {
        if (target.hasAbility("cloudnine")) {
          this.add("-message", `${target.name} suppresses the effects of the terrain!`);
          return;
        }
      }
      move.secondaries = [];
      if (this.field.isTerrain("electricterrain")) {
        move.secondaries.push({
          chance: 30,
          status: "par"
        });
      } else if (this.field.isTerrain("grassyterrain")) {
        move.secondaries.push({
          chance: 30,
          status: "slp"
        });
      } else if (this.field.isTerrain("mistyterrain")) {
        move.secondaries.push({
          chance: 30,
          boosts: {
            spa: -1
          }
        });
      } else if (this.field.isTerrain("psychicterrain")) {
        move.secondaries.push({
          chance: 30,
          boosts: {
            spe: -1
          }
        });
      }
    }
  },
  steelroller: {
    inherit: true,
    onTryHit() {
      if (this.field.isTerrain(""))
        return false;
      for (const target of this.getAllActive()) {
        if (target.hasAbility("cloudnine")) {
          this.add("-message", `${target.name} suppresses the effects of the terrain!`);
          return false;
        }
      }
    }
  },
  terrainpulse: {
    inherit: true,
    onModifyType(move, pokemon) {
      if (!pokemon.isGrounded())
        return;
      if (this.getAllActive().some((x) => x.hasAbility("cloudnine")))
        return;
      switch (this.field.terrain) {
        case "electricterrain":
          move.type = "Electric";
          break;
        case "grassyterrain":
          move.type = "Grass";
          break;
        case "mistyterrain":
          move.type = "Fairy";
          break;
        case "psychicterrain":
          move.type = "Psychic";
          break;
      }
    },
    onModifyMove(move, pokemon) {
      if (this.field.terrain && pokemon.isGrounded()) {
        for (const target of this.getAllActive()) {
          if (target.hasAbility("cloudnine")) {
            this.add("-message", `${target.name} suppresses the effects of the terrain!`);
            return;
          }
        }
        move.basePower *= 2;
      }
    }
  },
  bleakwindstorm: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  sandsearstorm: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  springtidestorm: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  wildboltstorm: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  aircutter: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  fairywind: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  gust: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  heatwave: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  hurricane: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  icywind: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  petalblizzard: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  sandstorm: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  tailwind: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  twister: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  whirlwind: {
    inherit: true,
    self: {
      onHit(pokemon, source, move) {
        if (source.hasItem("airfreshener")) {
          this.add("-activate", source, "move: Aromatherapy");
          for (const ally of source.side.pokemon) {
            if (ally !== source && (ally.volatiles["substitute"] && !move.infiltrates)) {
              continue;
            }
            ally.cureStatus();
          }
        }
      }
    }
  },
  boomburst: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  bugbuzz: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  clangingscales: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  clangoroussoul: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  confide: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  disarmingvoice: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  echoedvoice: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  eeriespell: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  growl: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  healbell: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  hypervoice: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  metalsound: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  howl: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  nobleroar: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  overdrive: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  partingshot: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  perishsong: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  relicsong: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  roar: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  screech: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  sing: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  snarl: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  snore: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  sparklingaria: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  chatter: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  supersonic: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  torchsong: {
    inherit: true,
    self: {
      sideCondition: "echochamber"
    }
  },
  uproar: {
    inherit: true,
    self: {
      sideCondition: "echochamber",
      volatileStatus: "uproar"
    }
  },
  revivalblessing: {
    inherit: true,
    flags: { snatch: 1 }
  },
  shedtail: {
    inherit: true,
    flags: { snatch: 1 }
  },
  aromaticmist: {
    inherit: true,
    flags: { snatch: 1, bypasssub: 1, metronome: 1 }
  },
  terablast: {
    num: 851,
    accuracy: 100,
    basePower: 80,
    category: "Special",
    name: "Tera Blast",
    pp: 10,
    priority: 0,
    flags: { protect: 1, mirror: 1, metronome: 1, mustpressure: 1 },
    onPrepareHit(target, source, move) {
      if (source.terastallized) {
        this.attrLastMove("[anim] Tera Blast " + source.teraType);
      }
    },
    onModifyType(move, pokemon, target) {
      if (pokemon.terastallized) {
        move.type = pokemon.teraType;
      }
    },
    onModifyMove(move, pokemon) {
      if ((pokemon.terastallized || pokemon.hasItem("terashard")) && pokemon.getStat("atk", false, true) > pokemon.getStat("spa", false, true)) {
        move.category = "Physical";
      }
    },
    secondary: null,
    target: "normal",
    type: "Normal"
  },
  doubleshock: {
    num: 892,
    accuracy: 100,
    basePower: 120,
    category: "Physical",
    name: "Double Shock",
    pp: 5,
    priority: 0,
    flags: { contact: 1, protect: 1, mirror: 1 },
    onTryMove(pokemon, target, move) {
      if (pokemon.hasType("Electric"))
        return;
      this.add("-fail", pokemon, "move: Double Shock");
      this.attrLastMove("[still]");
      return null;
    },
    self: {
      onHit(pokemon) {
        if (pokemon.hasItem("terashard") && pokemon.teraType === "Electric")
          return;
        pokemon.setType(pokemon.getTypes(true).map((type) => type === "Electric" ? "???" : type));
        this.add("-start", pokemon, "typechange", pokemon.getTypes().join("/"), "[from] move: Double Shock");
      }
    },
    secondary: null,
    target: "normal",
    type: "Electric",
    contestType: "Clever"
  },
  burnup: {
    num: 682,
    accuracy: 100,
    basePower: 130,
    category: "Special",
    name: "Burn Up",
    pp: 5,
    priority: 0,
    flags: { protect: 1, mirror: 1, defrost: 1, metronome: 1 },
    onTryMove(pokemon, target, move) {
      if (pokemon.hasType("Fire"))
        return;
      this.add("-fail", pokemon, "move: Burn Up");
      this.attrLastMove("[still]");
      return null;
    },
    self: {
      onHit(pokemon) {
        if (pokemon.hasItem("terashard") && pokemon.teraType === "Fire")
          return;
        pokemon.setType(pokemon.getTypes(true).map((type) => type === "Fire" ? "???" : type));
        this.add("-start", pokemon, "typechange", pokemon.getTypes().join("/"), "[from] move: Burn Up");
      }
    },
    secondary: null,
    target: "normal",
    type: "Fire",
    contestType: "Clever"
  },
  roost: {
    num: 355,
    accuracy: true,
    basePower: 0,
    category: "Status",
    name: "Roost",
    pp: 5,
    priority: 0,
    flags: { snatch: 1, heal: 1, metronome: 1 },
    heal: [1, 2],
    self: {
      volatileStatus: "roost"
    },
    condition: {
      duration: 1,
      onResidualOrder: 25,
      onStart(target) {
        if (!target.terastallized && !target.hasItem("terashard")) {
          this.add("-singleturn", target, "move: Roost");
        } else if (target.terastallized === "Flying" || target.hasItem("terashard")) {
          this.add("-hint", "If a Flying Terastallized Pokemon uses Roost, it remains Flying-type.");
        }
      },
      onTypePriority: -1,
      onType(types, pokemon) {
        this.effectState.typeWas = types;
        return types.filter((type) => type !== "Flying");
      }
    },
    secondary: null,
    target: "self",
    type: "Flying",
    zMove: { effect: "clearnegativeboost" },
    contestType: "Clever"
  }
};
//# sourceMappingURL=moves.js.map
