Pokemon_server / dist /data /abilities.js
Jofthomas's picture
Jofthomas HF staff
Upload 4781 files
5c2ed06 verified
"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 abilities_exports = {};
__export(abilities_exports, {
Abilities: () => Abilities
});
module.exports = __toCommonJS(abilities_exports);
const Abilities = {
noability: {
isNonstandard: "Past",
flags: {},
name: "No Ability",
rating: 0.1,
num: 0
},
adaptability: {
onModifySTAB(stab, source, target, move) {
if (move.forceSTAB || source.hasType(move.type)) {
if (stab === 2) {
return 2.25;
}
return 2;
}
},
flags: {},
name: "Adaptability",
rating: 4,
num: 91
},
aerilate: {
onModifyTypePriority: -1,
onModifyType(move, pokemon) {
const noModifyType = [
"judgment",
"multiattack",
"naturalgift",
"revelationdance",
"technoblast",
"terrainpulse",
"weatherball"
];
if (move.type === "Normal" && !noModifyType.includes(move.id) && !(move.isZ && move.category !== "Status") && !(move.name === "Tera Blast" && pokemon.terastallized)) {
move.type = "Flying";
move.typeChangerBoosted = this.effect;
}
},
onBasePowerPriority: 23,
onBasePower(basePower, pokemon, target, move) {
if (move.typeChangerBoosted === this.effect)
return this.chainModify([4915, 4096]);
},
flags: {},
name: "Aerilate",
rating: 4,
num: 184
},
aftermath: {
onDamagingHitOrder: 1,
onDamagingHit(damage, target, source, move) {
if (!target.hp && this.checkMoveMakesContact(move, source, target, true)) {
this.damage(source.baseMaxhp / 4, source, target);
}
},
flags: {},
name: "Aftermath",
rating: 2,
num: 106
},
airlock: {
onSwitchIn(pokemon) {
this.add("-ability", pokemon, "Air Lock");
this.effect.onStart.call(this, pokemon);
},
onStart(pokemon) {
pokemon.abilityState.ending = false;
this.eachEvent("WeatherChange", this.effect);
},
onEnd(pokemon) {
pokemon.abilityState.ending = true;
this.eachEvent("WeatherChange", this.effect);
},
suppressWeather: true,
flags: {},
name: "Air Lock",
rating: 1.5,
num: 76
},
analytic: {
onBasePowerPriority: 21,
onBasePower(basePower, pokemon) {
let boosted = true;
for (const target of this.getAllActive()) {
if (target === pokemon)
continue;
if (this.queue.willMove(target)) {
boosted = false;
break;
}
}
if (boosted) {
this.debug("Analytic boost");
return this.chainModify([5325, 4096]);
}
},
flags: {},
name: "Analytic",
rating: 2.5,
num: 148
},
angerpoint: {
onHit(target, source, move) {
if (!target.hp)
return;
if (move?.effectType === "Move" && target.getMoveHitData(move).crit) {
this.boost({ atk: 12 }, target, target);
}
},
flags: {},
name: "Anger Point",
rating: 1,
num: 83
},
angershell: {
onDamage(damage, target, source, effect) {
if (effect.effectType === "Move" && !effect.multihit && (!effect.negateSecondary && !(effect.hasSheerForce && source.hasAbility("sheerforce")))) {
this.effectState.checkedAngerShell = false;
} else {
this.effectState.checkedAngerShell = true;
}
},
onTryEatItem(item) {
const healingItems = [
"aguavberry",
"enigmaberry",
"figyberry",
"iapapaberry",
"magoberry",
"sitrusberry",
"wikiberry",
"oranberry",
"berryjuice"
];
if (healingItems.includes(item.id)) {
return this.effectState.checkedAngerShell;
}
return true;
},
onAfterMoveSecondary(target, source, move) {
this.effectState.checkedAngerShell = true;
if (!source || source === target || !target.hp || !move.totalDamage)
return;
const lastAttackedBy = target.getLastAttackedBy();
if (!lastAttackedBy)
return;
const damage = move.multihit ? move.totalDamage : lastAttackedBy.damage;
if (target.hp <= target.maxhp / 2 && target.hp + damage > target.maxhp / 2) {
this.boost({ atk: 1, spa: 1, spe: 1, def: -1, spd: -1 }, target, target);
}
},
flags: {},
name: "Anger Shell",
rating: 3,
num: 271
},
anticipation: {
onStart(pokemon) {
for (const target of pokemon.foes()) {
for (const moveSlot of target.moveSlots) {
const move = this.dex.moves.get(moveSlot.move);
if (move.category === "Status")
continue;
const moveType = move.id === "hiddenpower" ? target.hpType : move.type;
if (this.dex.getImmunity(moveType, pokemon) && this.dex.getEffectiveness(moveType, pokemon) > 0 || move.ohko) {
this.add("-ability", pokemon, "Anticipation");
return;
}
}
}
},
flags: {},
name: "Anticipation",
rating: 0.5,
num: 107
},
arenatrap: {
onFoeTrapPokemon(pokemon) {
if (!pokemon.isAdjacent(this.effectState.target))
return;
if (pokemon.isGrounded()) {
pokemon.tryTrap(true);
}
},
onFoeMaybeTrapPokemon(pokemon, source) {
if (!source)
source = this.effectState.target;
if (!source || !pokemon.isAdjacent(source))
return;
if (pokemon.isGrounded(!pokemon.knownType)) {
pokemon.maybeTrapped = true;
}
},
flags: {},
name: "Arena Trap",
rating: 5,
num: 71
},
armortail: {
onFoeTryMove(target, source, move) {
const targetAllExceptions = ["perishsong", "flowershield", "rototiller"];
if (move.target === "foeSide" || move.target === "all" && !targetAllExceptions.includes(move.id)) {
return;
}
const armorTailHolder = this.effectState.target;
if ((source.isAlly(armorTailHolder) || move.target === "all") && move.priority > 0.1) {
this.attrLastMove("[still]");
this.add("cant", armorTailHolder, "ability: Armor Tail", move, `[of] ${target}`);
return false;
}
},
flags: { breakable: 1 },
name: "Armor Tail",
rating: 2.5,
num: 296
},
aromaveil: {
onAllyTryAddVolatile(status, target, source, effect) {
if (["attract", "disable", "encore", "healblock", "taunt", "torment"].includes(status.id)) {
if (effect.effectType === "Move") {
const effectHolder = this.effectState.target;
this.add("-block", target, "ability: Aroma Veil", `[of] ${effectHolder}`);
}
return null;
}
},
flags: { breakable: 1 },
name: "Aroma Veil",
rating: 2,
num: 165
},
asoneglastrier: {
onSwitchInPriority: 1,
onStart(pokemon) {
if (this.effectState.unnerved)
return;
this.add("-ability", pokemon, "As One");
this.add("-ability", pokemon, "Unnerve");
this.effectState.unnerved = true;
},
onEnd() {
this.effectState.unnerved = false;
},
onFoeTryEatItem() {
return !this.effectState.unnerved;
},
onSourceAfterFaint(length, target, source, effect) {
if (effect && effect.effectType === "Move") {
this.boost({ atk: length }, source, source, this.dex.abilities.get("chillingneigh"));
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "As One (Glastrier)",
rating: 3.5,
num: 266
},
asonespectrier: {
onSwitchInPriority: 1,
onStart(pokemon) {
if (this.effectState.unnerved)
return;
this.add("-ability", pokemon, "As One");
this.add("-ability", pokemon, "Unnerve");
this.effectState.unnerved = true;
},
onEnd() {
this.effectState.unnerved = false;
},
onFoeTryEatItem() {
return !this.effectState.unnerved;
},
onSourceAfterFaint(length, target, source, effect) {
if (effect && effect.effectType === "Move") {
this.boost({ spa: length }, source, source, this.dex.abilities.get("grimneigh"));
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "As One (Spectrier)",
rating: 3.5,
num: 267
},
aurabreak: {
onStart(pokemon) {
if (this.suppressingAbility(pokemon))
return;
this.add("-ability", pokemon, "Aura Break");
},
onAnyTryPrimaryHit(target, source, move) {
if (target === source || move.category === "Status")
return;
move.hasAuraBreak = true;
},
flags: { breakable: 1 },
name: "Aura Break",
rating: 1,
num: 188
},
baddreams: {
onResidualOrder: 28,
onResidualSubOrder: 2,
onResidual(pokemon) {
if (!pokemon.hp)
return;
for (const target of pokemon.foes()) {
if (target.status === "slp" || target.hasAbility("comatose")) {
this.damage(target.baseMaxhp / 8, target, pokemon);
}
}
},
flags: {},
name: "Bad Dreams",
rating: 1.5,
num: 123
},
ballfetch: {
flags: {},
name: "Ball Fetch",
rating: 0,
num: 237
},
battery: {
onAllyBasePowerPriority: 22,
onAllyBasePower(basePower, attacker, defender, move) {
if (attacker !== this.effectState.target && move.category === "Special") {
this.debug("Battery boost");
return this.chainModify([5325, 4096]);
}
},
flags: {},
name: "Battery",
rating: 0,
num: 217
},
battlearmor: {
onCriticalHit: false,
flags: { breakable: 1 },
name: "Battle Armor",
rating: 1,
num: 4
},
battlebond: {
onSourceAfterFaint(length, target, source, effect) {
if (effect?.effectType !== "Move")
return;
if (source.abilityState.battleBondTriggered)
return;
if (source.species.id === "greninjabond" && source.hp && !source.transformed && source.side.foePokemonLeft()) {
this.boost({ atk: 1, spa: 1, spe: 1 }, source, source, this.effect);
this.add("-activate", source, "ability: Battle Bond");
source.abilityState.battleBondTriggered = true;
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "Battle Bond",
rating: 3.5,
num: 210
},
beadsofruin: {
onStart(pokemon) {
if (this.suppressingAbility(pokemon))
return;
this.add("-ability", pokemon, "Beads of Ruin");
},
onAnyModifySpD(spd, target, source, move) {
const abilityHolder = this.effectState.target;
if (target.hasAbility("Beads of Ruin"))
return;
if (!move.ruinedSpD?.hasAbility("Beads of Ruin"))
move.ruinedSpD = abilityHolder;
if (move.ruinedSpD !== abilityHolder)
return;
this.debug("Beads of Ruin SpD drop");
return this.chainModify(0.75);
},
flags: {},
name: "Beads of Ruin",
rating: 4.5,
num: 284
},
beastboost: {
onSourceAfterFaint(length, target, source, effect) {
if (effect && effect.effectType === "Move") {
const bestStat = source.getBestStat(true, true);
this.boost({ [bestStat]: length }, source);
}
},
flags: {},
name: "Beast Boost",
rating: 3.5,
num: 224
},
berserk: {
onDamage(damage, target, source, effect) {
if (effect.effectType === "Move" && !effect.multihit && (!effect.negateSecondary && !(effect.hasSheerForce && source.hasAbility("sheerforce")))) {
this.effectState.checkedBerserk = false;
} else {
this.effectState.checkedBerserk = true;
}
},
onTryEatItem(item) {
const healingItems = [
"aguavberry",
"enigmaberry",
"figyberry",
"iapapaberry",
"magoberry",
"sitrusberry",
"wikiberry",
"oranberry",
"berryjuice"
];
if (healingItems.includes(item.id)) {
return this.effectState.checkedBerserk;
}
return true;
},
onAfterMoveSecondary(target, source, move) {
this.effectState.checkedBerserk = true;
if (!source || source === target || !target.hp || !move.totalDamage)
return;
const lastAttackedBy = target.getLastAttackedBy();
if (!lastAttackedBy)
return;
const damage = move.multihit && !move.smartTarget ? move.totalDamage : lastAttackedBy.damage;
if (target.hp <= target.maxhp / 2 && target.hp + damage > target.maxhp / 2) {
this.boost({ spa: 1 }, target, target);
}
},
flags: {},
name: "Berserk",
rating: 2,
num: 201
},
bigpecks: {
onTryBoost(boost, target, source, effect) {
if (source && target === source)
return;
if (boost.def && boost.def < 0) {
delete boost.def;
if (!effect.secondaries && effect.id !== "octolock") {
this.add("-fail", target, "unboost", "Defense", "[from] ability: Big Pecks", `[of] ${target}`);
}
}
},
flags: { breakable: 1 },
name: "Big Pecks",
rating: 0.5,
num: 145
},
blaze: {
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender, move) {
if (move.type === "Fire" && attacker.hp <= attacker.maxhp / 3) {
this.debug("Blaze boost");
return this.chainModify(1.5);
}
},
onModifySpAPriority: 5,
onModifySpA(atk, attacker, defender, move) {
if (move.type === "Fire" && attacker.hp <= attacker.maxhp / 3) {
this.debug("Blaze boost");
return this.chainModify(1.5);
}
},
flags: {},
name: "Blaze",
rating: 2,
num: 66
},
bulletproof: {
onTryHit(pokemon, target, move) {
if (move.flags["bullet"]) {
this.add("-immune", pokemon, "[from] ability: Bulletproof");
return null;
}
},
flags: { breakable: 1 },
name: "Bulletproof",
rating: 3,
num: 171
},
cheekpouch: {
onEatItem(item, pokemon) {
this.heal(pokemon.baseMaxhp / 3);
},
flags: {},
name: "Cheek Pouch",
rating: 2,
num: 167
},
chillingneigh: {
onSourceAfterFaint(length, target, source, effect) {
if (effect && effect.effectType === "Move") {
this.boost({ atk: length }, source);
}
},
flags: {},
name: "Chilling Neigh",
rating: 3,
num: 264
},
chlorophyll: {
onModifySpe(spe, pokemon) {
if (["sunnyday", "desolateland"].includes(pokemon.effectiveWeather())) {
return this.chainModify(2);
}
},
flags: {},
name: "Chlorophyll",
rating: 3,
num: 34
},
clearbody: {
onTryBoost(boost, target, source, effect) {
if (source && target === source)
return;
let showMsg = false;
let i;
for (i in boost) {
if (boost[i] < 0) {
delete boost[i];
showMsg = true;
}
}
if (showMsg && !effect.secondaries && effect.id !== "octolock") {
this.add("-fail", target, "unboost", "[from] ability: Clear Body", `[of] ${target}`);
}
},
flags: { breakable: 1 },
name: "Clear Body",
rating: 2,
num: 29
},
cloudnine: {
onSwitchIn(pokemon) {
this.add("-ability", pokemon, "Cloud Nine");
this.effect.onStart.call(this, pokemon);
},
onStart(pokemon) {
pokemon.abilityState.ending = false;
this.eachEvent("WeatherChange", this.effect);
},
onEnd(pokemon) {
pokemon.abilityState.ending = true;
this.eachEvent("WeatherChange", this.effect);
},
suppressWeather: true,
flags: {},
name: "Cloud Nine",
rating: 1.5,
num: 13
},
colorchange: {
onAfterMoveSecondary(target, source, move) {
if (!target.hp)
return;
const type = move.type;
if (target.isActive && move.effectType === "Move" && move.category !== "Status" && type !== "???" && !target.hasType(type)) {
if (!target.setType(type))
return false;
this.add("-start", target, "typechange", type, "[from] ability: Color Change");
if (target.side.active.length === 2 && target.position === 1) {
const action = this.queue.willMove(target);
if (action && action.move.id === "curse") {
action.targetLoc = -1;
}
}
}
},
flags: {},
name: "Color Change",
rating: 0,
num: 16
},
comatose: {
onStart(pokemon) {
this.add("-ability", pokemon, "Comatose");
},
onSetStatus(status, target, source, effect) {
if (effect?.status) {
this.add("-immune", target, "[from] ability: Comatose");
}
return false;
},
// Permanent sleep "status" implemented in the relevant sleep-checking effects
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "Comatose",
rating: 4,
num: 213
},
commander: {
onAnySwitchInPriority: -2,
onAnySwitchIn() {
this.effect.onUpdate.call(this, this.effectState.target);
},
onStart(pokemon) {
this.effect.onUpdate.call(this, pokemon);
},
onUpdate(pokemon) {
if (this.gameType !== "doubles")
return;
if (this.queue.peek()?.choice === "runSwitch")
return;
const ally = pokemon.allies()[0];
if (pokemon.switchFlag || ally?.switchFlag)
return;
if (!ally || pokemon.baseSpecies.baseSpecies !== "Tatsugiri" || ally.baseSpecies.baseSpecies !== "Dondozo") {
if (pokemon.getVolatile("commanding"))
pokemon.removeVolatile("commanding");
return;
}
if (!pokemon.getVolatile("commanding")) {
if (ally.getVolatile("commanded"))
return;
this.queue.cancelAction(pokemon);
this.add("-activate", pokemon, "ability: Commander", `[of] ${ally}`);
pokemon.addVolatile("commanding");
ally.addVolatile("commanded", pokemon);
} else {
if (!ally.fainted)
return;
pokemon.removeVolatile("commanding");
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1 },
name: "Commander",
rating: 0,
num: 279
},
competitive: {
onAfterEachBoost(boost, target, source, effect) {
if (!source || target.isAlly(source)) {
return;
}
let statsLowered = false;
let i;
for (i in boost) {
if (boost[i] < 0) {
statsLowered = true;
}
}
if (statsLowered) {
this.boost({ spa: 2 }, target, target, null, false, true);
}
},
flags: {},
name: "Competitive",
rating: 2.5,
num: 172
},
compoundeyes: {
onSourceModifyAccuracyPriority: -1,
onSourceModifyAccuracy(accuracy) {
if (typeof accuracy !== "number")
return;
this.debug("compoundeyes - enhancing accuracy");
return this.chainModify([5325, 4096]);
},
flags: {},
name: "Compound Eyes",
rating: 3,
num: 14
},
contrary: {
onChangeBoost(boost, target, source, effect) {
if (effect && effect.id === "zpower")
return;
let i;
for (i in boost) {
boost[i] *= -1;
}
},
flags: { breakable: 1 },
name: "Contrary",
rating: 4.5,
num: 126
},
corrosion: {
// Implemented in sim/pokemon.js:Pokemon#setStatus
flags: {},
name: "Corrosion",
rating: 2.5,
num: 212
},
costar: {
onSwitchInPriority: -2,
onStart(pokemon) {
const ally = pokemon.allies()[0];
if (!ally)
return;
let i;
for (i in ally.boosts) {
pokemon.boosts[i] = ally.boosts[i];
}
const volatilesToCopy = ["dragoncheer", "focusenergy", "gmaxchistrike", "laserfocus"];
for (const volatile of volatilesToCopy)
pokemon.removeVolatile(volatile);
for (const volatile of volatilesToCopy) {
if (ally.volatiles[volatile]) {
pokemon.addVolatile(volatile);
if (volatile === "gmaxchistrike")
pokemon.volatiles[volatile].layers = ally.volatiles[volatile].layers;
if (volatile === "dragoncheer")
pokemon.volatiles[volatile].hasDragonType = ally.volatiles[volatile].hasDragonType;
}
}
this.add("-copyboost", pokemon, ally, "[from] ability: Costar");
},
flags: {},
name: "Costar",
rating: 0,
num: 294
},
cottondown: {
onDamagingHit(damage, target, source, move) {
let activated = false;
for (const pokemon of this.getAllActive()) {
if (pokemon === target || pokemon.fainted)
continue;
if (!activated) {
this.add("-ability", target, "Cotton Down");
activated = true;
}
this.boost({ spe: -1 }, pokemon, target, null, true);
}
},
flags: {},
name: "Cotton Down",
rating: 2,
num: 238
},
cudchew: {
onEatItem(item, pokemon) {
if (item.isBerry && pokemon.addVolatile("cudchew")) {
pokemon.volatiles["cudchew"].berry = item;
}
},
onEnd(pokemon) {
delete pokemon.volatiles["cudchew"];
},
condition: {
noCopy: true,
duration: 2,
onRestart() {
this.effectState.duration = 2;
},
onResidualOrder: 28,
onResidualSubOrder: 2,
onEnd(pokemon) {
if (pokemon.hp) {
const item = this.effectState.berry;
this.add("-activate", pokemon, "ability: Cud Chew");
this.add("-enditem", pokemon, item.name, "[eat]");
if (this.singleEvent("Eat", item, null, pokemon, null, null)) {
this.runEvent("EatItem", pokemon, null, null, item);
}
if (item.onEat)
pokemon.ateBerry = true;
}
}
},
flags: {},
name: "Cud Chew",
rating: 2,
num: 291
},
curiousmedicine: {
onStart(pokemon) {
for (const ally of pokemon.adjacentAllies()) {
ally.clearBoosts();
this.add("-clearboost", ally, "[from] ability: Curious Medicine", `[of] ${pokemon}`);
}
},
flags: {},
name: "Curious Medicine",
rating: 0,
num: 261
},
cursedbody: {
onDamagingHit(damage, target, source, move) {
if (source.volatiles["disable"])
return;
if (!move.isMax && !move.flags["futuremove"] && move.id !== "struggle") {
if (this.randomChance(3, 10)) {
source.addVolatile("disable", this.effectState.target);
}
}
},
flags: {},
name: "Cursed Body",
rating: 2,
num: 130
},
cutecharm: {
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target)) {
if (this.randomChance(3, 10)) {
source.addVolatile("attract", this.effectState.target);
}
}
},
flags: {},
name: "Cute Charm",
rating: 0.5,
num: 56
},
damp: {
onAnyTryMove(target, source, effect) {
if (["explosion", "mindblown", "mistyexplosion", "selfdestruct"].includes(effect.id)) {
this.attrLastMove("[still]");
this.add("cant", this.effectState.target, "ability: Damp", effect, `[of] ${target}`);
return false;
}
},
onAnyDamage(damage, target, source, effect) {
if (effect && effect.name === "Aftermath") {
return false;
}
},
flags: { breakable: 1 },
name: "Damp",
rating: 0.5,
num: 6
},
dancer: {
flags: {},
name: "Dancer",
// implemented in runMove in scripts.js
rating: 1.5,
num: 216
},
darkaura: {
onStart(pokemon) {
if (this.suppressingAbility(pokemon))
return;
this.add("-ability", pokemon, "Dark Aura");
},
onAnyBasePowerPriority: 20,
onAnyBasePower(basePower, source, target, move) {
if (target === source || move.category === "Status" || move.type !== "Dark")
return;
if (!move.auraBooster?.hasAbility("Dark Aura"))
move.auraBooster = this.effectState.target;
if (move.auraBooster !== this.effectState.target)
return;
return this.chainModify([move.hasAuraBreak ? 3072 : 5448, 4096]);
},
flags: {},
name: "Dark Aura",
rating: 3,
num: 186
},
dauntlessshield: {
onStart(pokemon) {
if (pokemon.shieldBoost)
return;
pokemon.shieldBoost = true;
this.boost({ def: 1 }, pokemon);
},
flags: {},
name: "Dauntless Shield",
rating: 3.5,
num: 235
},
dazzling: {
onFoeTryMove(target, source, move) {
const targetAllExceptions = ["perishsong", "flowershield", "rototiller"];
if (move.target === "foeSide" || move.target === "all" && !targetAllExceptions.includes(move.id)) {
return;
}
const dazzlingHolder = this.effectState.target;
if ((source.isAlly(dazzlingHolder) || move.target === "all") && move.priority > 0.1) {
this.attrLastMove("[still]");
this.add("cant", dazzlingHolder, "ability: Dazzling", move, `[of] ${target}`);
return false;
}
},
flags: { breakable: 1 },
name: "Dazzling",
rating: 2.5,
num: 219
},
defeatist: {
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
if (pokemon.hp <= pokemon.maxhp / 2) {
return this.chainModify(0.5);
}
},
onModifySpAPriority: 5,
onModifySpA(atk, pokemon) {
if (pokemon.hp <= pokemon.maxhp / 2) {
return this.chainModify(0.5);
}
},
flags: {},
name: "Defeatist",
rating: -1,
num: 129
},
defiant: {
onAfterEachBoost(boost, target, source, effect) {
if (!source || target.isAlly(source)) {
return;
}
let statsLowered = false;
let i;
for (i in boost) {
if (boost[i] < 0) {
statsLowered = true;
}
}
if (statsLowered) {
this.boost({ atk: 2 }, target, target, null, false, true);
}
},
flags: {},
name: "Defiant",
rating: 3,
num: 128
},
deltastream: {
onStart(source) {
this.field.setWeather("deltastream");
},
onAnySetWeather(target, source, weather) {
const strongWeathers = ["desolateland", "primordialsea", "deltastream"];
if (this.field.getWeather().id === "deltastream" && !strongWeathers.includes(weather.id))
return false;
},
onEnd(pokemon) {
if (this.field.weatherState.source !== pokemon)
return;
for (const target of this.getAllActive()) {
if (target === pokemon)
continue;
if (target.hasAbility("deltastream")) {
this.field.weatherState.source = target;
return;
}
}
this.field.clearWeather();
},
flags: {},
name: "Delta Stream",
rating: 4,
num: 191
},
desolateland: {
onStart(source) {
this.field.setWeather("desolateland");
},
onAnySetWeather(target, source, weather) {
const strongWeathers = ["desolateland", "primordialsea", "deltastream"];
if (this.field.getWeather().id === "desolateland" && !strongWeathers.includes(weather.id))
return false;
},
onEnd(pokemon) {
if (this.field.weatherState.source !== pokemon)
return;
for (const target of this.getAllActive()) {
if (target === pokemon)
continue;
if (target.hasAbility("desolateland")) {
this.field.weatherState.source = target;
return;
}
}
this.field.clearWeather();
},
flags: {},
name: "Desolate Land",
rating: 4.5,
num: 190
},
disguise: {
onDamagePriority: 1,
onDamage(damage, target, source, effect) {
if (effect?.effectType === "Move" && ["mimikyu", "mimikyutotem"].includes(target.species.id)) {
this.add("-activate", target, "ability: Disguise");
this.effectState.busted = true;
return 0;
}
},
onCriticalHit(target, source, move) {
if (!target)
return;
if (!["mimikyu", "mimikyutotem"].includes(target.species.id)) {
return;
}
const hitSub = target.volatiles["substitute"] && !move.flags["bypasssub"] && !(move.infiltrates && this.gen >= 6);
if (hitSub)
return;
if (!target.runImmunity(move.type))
return;
return false;
},
onEffectiveness(typeMod, target, type, move) {
if (!target || move.category === "Status")
return;
if (!["mimikyu", "mimikyutotem"].includes(target.species.id)) {
return;
}
const hitSub = target.volatiles["substitute"] && !move.flags["bypasssub"] && !(move.infiltrates && this.gen >= 6);
if (hitSub)
return;
if (!target.runImmunity(move.type))
return;
return 0;
},
onUpdate(pokemon) {
if (["mimikyu", "mimikyutotem"].includes(pokemon.species.id) && this.effectState.busted) {
const speciesid = pokemon.species.id === "mimikyutotem" ? "Mimikyu-Busted-Totem" : "Mimikyu-Busted";
pokemon.formeChange(speciesid, this.effect, true);
this.damage(pokemon.baseMaxhp / 8, pokemon, pokemon, this.dex.species.get(speciesid));
}
},
flags: {
failroleplay: 1,
noreceiver: 1,
noentrain: 1,
notrace: 1,
failskillswap: 1,
cantsuppress: 1,
breakable: 1,
notransform: 1
},
name: "Disguise",
rating: 3.5,
num: 209
},
download: {
onStart(pokemon) {
let totaldef = 0;
let totalspd = 0;
for (const target of pokemon.foes()) {
totaldef += target.getStat("def", false, true);
totalspd += target.getStat("spd", false, true);
}
if (totaldef && totaldef >= totalspd) {
this.boost({ spa: 1 });
} else if (totalspd) {
this.boost({ atk: 1 });
}
},
flags: {},
name: "Download",
rating: 3.5,
num: 88
},
dragonsmaw: {
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender, move) {
if (move.type === "Dragon") {
this.debug("Dragon's Maw boost");
return this.chainModify(1.5);
}
},
onModifySpAPriority: 5,
onModifySpA(atk, attacker, defender, move) {
if (move.type === "Dragon") {
this.debug("Dragon's Maw boost");
return this.chainModify(1.5);
}
},
flags: {},
name: "Dragon's Maw",
rating: 3.5,
num: 263
},
drizzle: {
onStart(source) {
if (source.species.id === "kyogre" && source.item === "blueorb")
return;
this.field.setWeather("raindance");
},
flags: {},
name: "Drizzle",
rating: 4,
num: 2
},
drought: {
onStart(source) {
if (source.species.id === "groudon" && source.item === "redorb")
return;
this.field.setWeather("sunnyday");
},
flags: {},
name: "Drought",
rating: 4,
num: 70
},
dryskin: {
onTryHit(target, source, move) {
if (target !== source && move.type === "Water") {
if (!this.heal(target.baseMaxhp / 4)) {
this.add("-immune", target, "[from] ability: Dry Skin");
}
return null;
}
},
onSourceBasePowerPriority: 17,
onSourceBasePower(basePower, attacker, defender, move) {
if (move.type === "Fire") {
return this.chainModify(1.25);
}
},
onWeather(target, source, effect) {
if (target.hasItem("utilityumbrella"))
return;
if (effect.id === "raindance" || effect.id === "primordialsea") {
this.heal(target.baseMaxhp / 8);
} else if (effect.id === "sunnyday" || effect.id === "desolateland") {
this.damage(target.baseMaxhp / 8, target, target);
}
},
flags: { breakable: 1 },
name: "Dry Skin",
rating: 3,
num: 87
},
earlybird: {
flags: {},
name: "Early Bird",
// Implemented in statuses.js
rating: 1.5,
num: 48
},
eartheater: {
onTryHit(target, source, move) {
if (target !== source && move.type === "Ground") {
if (!this.heal(target.baseMaxhp / 4)) {
this.add("-immune", target, "[from] ability: Earth Eater");
}
return null;
}
},
flags: { breakable: 1 },
name: "Earth Eater",
rating: 3.5,
num: 297
},
effectspore: {
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target) && !source.status && source.runStatusImmunity("powder")) {
const r = this.random(100);
if (r < 11) {
source.setStatus("slp", target);
} else if (r < 21) {
source.setStatus("par", target);
} else if (r < 30) {
source.setStatus("psn", target);
}
}
},
flags: {},
name: "Effect Spore",
rating: 2,
num: 27
},
electricsurge: {
onStart(source) {
this.field.setTerrain("electricterrain");
},
flags: {},
name: "Electric Surge",
rating: 4,
num: 226
},
electromorphosis: {
onDamagingHitOrder: 1,
onDamagingHit(damage, target, source, move) {
target.addVolatile("charge");
},
flags: {},
name: "Electromorphosis",
rating: 3,
num: 280
},
embodyaspectcornerstone: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === "Ogerpon-Cornerstone-Tera" && this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({ def: 1 }, pokemon);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1 },
name: "Embody Aspect (Cornerstone)",
rating: 3.5,
num: 304
},
embodyaspecthearthflame: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === "Ogerpon-Hearthflame-Tera" && this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({ atk: 1 }, pokemon);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1 },
name: "Embody Aspect (Hearthflame)",
rating: 3.5,
num: 303
},
embodyaspectteal: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === "Ogerpon-Teal-Tera" && this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({ spe: 1 }, pokemon);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1 },
name: "Embody Aspect (Teal)",
rating: 3.5,
num: 301
},
embodyaspectwellspring: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === "Ogerpon-Wellspring-Tera" && this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({ spd: 1 }, pokemon);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1 },
name: "Embody Aspect (Wellspring)",
rating: 3.5,
num: 302
},
emergencyexit: {
onEmergencyExit(target) {
if (!this.canSwitch(target.side) || target.forceSwitchFlag || target.switchFlag)
return;
for (const side of this.sides) {
for (const active of side.active) {
active.switchFlag = false;
}
}
target.switchFlag = true;
this.add("-activate", target, "ability: Emergency Exit");
},
flags: {},
name: "Emergency Exit",
rating: 1,
num: 194
},
fairyaura: {
onStart(pokemon) {
if (this.suppressingAbility(pokemon))
return;
this.add("-ability", pokemon, "Fairy Aura");
},
onAnyBasePowerPriority: 20,
onAnyBasePower(basePower, source, target, move) {
if (target === source || move.category === "Status" || move.type !== "Fairy")
return;
if (!move.auraBooster?.hasAbility("Fairy Aura"))
move.auraBooster = this.effectState.target;
if (move.auraBooster !== this.effectState.target)
return;
return this.chainModify([move.hasAuraBreak ? 3072 : 5448, 4096]);
},
flags: {},
name: "Fairy Aura",
rating: 3,
num: 187
},
filter: {
onSourceModifyDamage(damage, source, target, move) {
if (target.getMoveHitData(move).typeMod > 0) {
this.debug("Filter neutralize");
return this.chainModify(0.75);
}
},
flags: { breakable: 1 },
name: "Filter",
rating: 3,
num: 111
},
flamebody: {
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target)) {
if (this.randomChance(3, 10)) {
source.trySetStatus("brn", target);
}
}
},
flags: {},
name: "Flame Body",
rating: 2,
num: 49
},
flareboost: {
onBasePowerPriority: 19,
onBasePower(basePower, attacker, defender, move) {
if (attacker.status === "brn" && move.category === "Special") {
return this.chainModify(1.5);
}
},
flags: {},
name: "Flare Boost",
rating: 2,
num: 138
},
flashfire: {
onTryHit(target, source, move) {
if (target !== source && move.type === "Fire") {
move.accuracy = true;
if (!target.addVolatile("flashfire")) {
this.add("-immune", target, "[from] ability: Flash Fire");
}
return null;
}
},
onEnd(pokemon) {
pokemon.removeVolatile("flashfire");
},
condition: {
noCopy: true,
// doesn't get copied by Baton Pass
onStart(target) {
this.add("-start", target, "ability: Flash Fire");
},
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender, move) {
if (move.type === "Fire" && attacker.hasAbility("flashfire")) {
this.debug("Flash Fire boost");
return this.chainModify(1.5);
}
},
onModifySpAPriority: 5,
onModifySpA(atk, attacker, defender, move) {
if (move.type === "Fire" && attacker.hasAbility("flashfire")) {
this.debug("Flash Fire boost");
return this.chainModify(1.5);
}
},
onEnd(target) {
this.add("-end", target, "ability: Flash Fire", "[silent]");
}
},
flags: { breakable: 1 },
name: "Flash Fire",
rating: 3.5,
num: 18
},
flowergift: {
onSwitchInPriority: -2,
onStart(pokemon) {
this.singleEvent("WeatherChange", this.effect, this.effectState, pokemon);
},
onWeatherChange(pokemon) {
if (!pokemon.isActive || pokemon.baseSpecies.baseSpecies !== "Cherrim" || pokemon.transformed)
return;
if (!pokemon.hp)
return;
if (["sunnyday", "desolateland"].includes(pokemon.effectiveWeather())) {
if (pokemon.species.id !== "cherrimsunshine") {
pokemon.formeChange("Cherrim-Sunshine", this.effect, false, "0", "[msg]");
}
} else {
if (pokemon.species.id === "cherrimsunshine") {
pokemon.formeChange("Cherrim", this.effect, false, "0", "[msg]");
}
}
},
onAllyModifyAtkPriority: 3,
onAllyModifyAtk(atk, pokemon) {
if (this.effectState.target.baseSpecies.baseSpecies !== "Cherrim")
return;
if (["sunnyday", "desolateland"].includes(pokemon.effectiveWeather())) {
return this.chainModify(1.5);
}
},
onAllyModifySpDPriority: 4,
onAllyModifySpD(spd, pokemon) {
if (this.effectState.target.baseSpecies.baseSpecies !== "Cherrim")
return;
if (["sunnyday", "desolateland"].includes(pokemon.effectiveWeather())) {
return this.chainModify(1.5);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, breakable: 1 },
name: "Flower Gift",
rating: 1,
num: 122
},
flowerveil: {
onAllyTryBoost(boost, target, source, effect) {
if (source && target === source || !target.hasType("Grass"))
return;
let showMsg = false;
let i;
for (i in boost) {
if (boost[i] < 0) {
delete boost[i];
showMsg = true;
}
}
if (showMsg && !effect.secondaries) {
const effectHolder = this.effectState.target;
this.add("-block", target, "ability: Flower Veil", `[of] ${effectHolder}`);
}
},
onAllySetStatus(status, target, source, effect) {
if (target.hasType("Grass") && source && target !== source && effect && effect.id !== "yawn") {
this.debug("interrupting setStatus with Flower Veil");
if (effect.name === "Synchronize" || effect.effectType === "Move" && !effect.secondaries) {
const effectHolder = this.effectState.target;
this.add("-block", target, "ability: Flower Veil", `[of] ${effectHolder}`);
}
return null;
}
},
onAllyTryAddVolatile(status, target) {
if (target.hasType("Grass") && status.id === "yawn") {
this.debug("Flower Veil blocking yawn");
const effectHolder = this.effectState.target;
this.add("-block", target, "ability: Flower Veil", `[of] ${effectHolder}`);
return null;
}
},
flags: { breakable: 1 },
name: "Flower Veil",
rating: 0,
num: 166
},
fluffy: {
onSourceModifyDamage(damage, source, target, move) {
let mod = 1;
if (move.type === "Fire")
mod *= 2;
if (move.flags["contact"])
mod /= 2;
return this.chainModify(mod);
},
flags: { breakable: 1 },
name: "Fluffy",
rating: 3.5,
num: 218
},
forecast: {
onSwitchInPriority: -2,
onStart(pokemon) {
this.singleEvent("WeatherChange", this.effect, this.effectState, pokemon);
},
onWeatherChange(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== "Castform" || pokemon.transformed)
return;
let forme = null;
switch (pokemon.effectiveWeather()) {
case "sunnyday":
case "desolateland":
if (pokemon.species.id !== "castformsunny")
forme = "Castform-Sunny";
break;
case "raindance":
case "primordialsea":
if (pokemon.species.id !== "castformrainy")
forme = "Castform-Rainy";
break;
case "hail":
case "snowscape":
if (pokemon.species.id !== "castformsnowy")
forme = "Castform-Snowy";
break;
default:
if (pokemon.species.id !== "castform")
forme = "Castform";
break;
}
if (pokemon.isActive && forme) {
pokemon.formeChange(forme, this.effect, false, "0", "[msg]");
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
name: "Forecast",
rating: 2,
num: 59
},
forewarn: {
onStart(pokemon) {
let warnMoves = [];
let warnBp = 1;
for (const target of pokemon.foes()) {
for (const moveSlot of target.moveSlots) {
const move = this.dex.moves.get(moveSlot.move);
let bp = move.basePower;
if (move.ohko)
bp = 150;
if (move.id === "counter" || move.id === "metalburst" || move.id === "mirrorcoat")
bp = 120;
if (bp === 1)
bp = 80;
if (!bp && move.category !== "Status")
bp = 80;
if (bp > warnBp) {
warnMoves = [[move, target]];
warnBp = bp;
} else if (bp === warnBp) {
warnMoves.push([move, target]);
}
}
}
if (!warnMoves.length)
return;
const [warnMoveName, warnTarget] = this.sample(warnMoves);
this.add("-activate", pokemon, "ability: Forewarn", warnMoveName, `[of] ${warnTarget}`);
},
flags: {},
name: "Forewarn",
rating: 0.5,
num: 108
},
friendguard: {
onAnyModifyDamage(damage, source, target, move) {
if (target !== this.effectState.target && target.isAlly(this.effectState.target)) {
this.debug("Friend Guard weaken");
return this.chainModify(0.75);
}
},
flags: { breakable: 1 },
name: "Friend Guard",
rating: 0,
num: 132
},
frisk: {
onStart(pokemon) {
for (const target of pokemon.foes()) {
if (target.item) {
this.add("-item", target, target.getItem().name, "[from] ability: Frisk", `[of] ${pokemon}`);
}
}
},
flags: {},
name: "Frisk",
rating: 1.5,
num: 119
},
fullmetalbody: {
onTryBoost(boost, target, source, effect) {
if (source && target === source)
return;
let showMsg = false;
let i;
for (i in boost) {
if (boost[i] < 0) {
delete boost[i];
showMsg = true;
}
}
if (showMsg && !effect.secondaries && effect.id !== "octolock") {
this.add("-fail", target, "unboost", "[from] ability: Full Metal Body", `[of] ${target}`);
}
},
flags: {},
name: "Full Metal Body",
rating: 2,
num: 230
},
furcoat: {
onModifyDefPriority: 6,
onModifyDef(def) {
return this.chainModify(2);
},
flags: { breakable: 1 },
name: "Fur Coat",
rating: 4,
num: 169
},
galewings: {
onModifyPriority(priority, pokemon, target, move) {
if (move?.type === "Flying" && pokemon.hp === pokemon.maxhp)
return priority + 1;
},
flags: {},
name: "Gale Wings",
rating: 1.5,
num: 177
},
galvanize: {
onModifyTypePriority: -1,
onModifyType(move, pokemon) {
const noModifyType = [
"judgment",
"multiattack",
"naturalgift",
"revelationdance",
"technoblast",
"terrainpulse",
"weatherball"
];
if (move.type === "Normal" && !noModifyType.includes(move.id) && !(move.isZ && move.category !== "Status") && !(move.name === "Tera Blast" && pokemon.terastallized)) {
move.type = "Electric";
move.typeChangerBoosted = this.effect;
}
},
onBasePowerPriority: 23,
onBasePower(basePower, pokemon, target, move) {
if (move.typeChangerBoosted === this.effect)
return this.chainModify([4915, 4096]);
},
flags: {},
name: "Galvanize",
rating: 4,
num: 206
},
gluttony: {
onStart(pokemon) {
pokemon.abilityState.gluttony = true;
},
onDamage(item, pokemon) {
pokemon.abilityState.gluttony = true;
},
flags: {},
name: "Gluttony",
rating: 1.5,
num: 82
},
goodasgold: {
onTryHit(target, source, move) {
if (move.category === "Status" && target !== source) {
this.add("-immune", target, "[from] ability: Good as Gold");
return null;
}
},
flags: { breakable: 1 },
name: "Good as Gold",
rating: 5,
num: 283
},
gooey: {
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target, true)) {
this.add("-ability", target, "Gooey");
this.boost({ spe: -1 }, source, target, null, true);
}
},
flags: {},
name: "Gooey",
rating: 2,
num: 183
},
gorillatactics: {
onStart(pokemon) {
pokemon.abilityState.choiceLock = "";
},
onBeforeMove(pokemon, target, move) {
if (move.isZOrMaxPowered || move.id === "struggle")
return;
if (pokemon.abilityState.choiceLock && pokemon.abilityState.choiceLock !== move.id) {
this.addMove("move", pokemon, move.name);
this.attrLastMove("[still]");
this.debug("Disabled by Gorilla Tactics");
this.add("-fail", pokemon);
return false;
}
},
onModifyMove(move, pokemon) {
if (pokemon.abilityState.choiceLock || move.isZOrMaxPowered || move.id === "struggle")
return;
pokemon.abilityState.choiceLock = move.id;
},
onModifyAtkPriority: 1,
onModifyAtk(atk, pokemon) {
if (pokemon.volatiles["dynamax"])
return;
this.debug("Gorilla Tactics Atk Boost");
return this.chainModify(1.5);
},
onDisableMove(pokemon) {
if (!pokemon.abilityState.choiceLock)
return;
if (pokemon.volatiles["dynamax"])
return;
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== pokemon.abilityState.choiceLock) {
pokemon.disableMove(moveSlot.id, false, this.effectState.sourceEffect);
}
}
},
onEnd(pokemon) {
pokemon.abilityState.choiceLock = "";
},
flags: {},
name: "Gorilla Tactics",
rating: 4.5,
num: 255
},
grasspelt: {
onModifyDefPriority: 6,
onModifyDef(pokemon) {
if (this.field.isTerrain("grassyterrain"))
return this.chainModify(1.5);
},
flags: { breakable: 1 },
name: "Grass Pelt",
rating: 0.5,
num: 179
},
grassysurge: {
onStart(source) {
this.field.setTerrain("grassyterrain");
},
flags: {},
name: "Grassy Surge",
rating: 4,
num: 229
},
grimneigh: {
onSourceAfterFaint(length, target, source, effect) {
if (effect && effect.effectType === "Move") {
this.boost({ spa: length }, source);
}
},
flags: {},
name: "Grim Neigh",
rating: 3,
num: 265
},
guarddog: {
onDragOutPriority: 1,
onDragOut(pokemon) {
this.add("-activate", pokemon, "ability: Guard Dog");
return null;
},
onTryBoostPriority: 2,
onTryBoost(boost, target, source, effect) {
if (effect.name === "Intimidate" && boost.atk) {
delete boost.atk;
this.boost({ atk: 1 }, target, target, null, false, true);
}
},
flags: { breakable: 1 },
name: "Guard Dog",
rating: 2,
num: 275
},
gulpmissile: {
onDamagingHit(damage, target, source, move) {
if (!source.hp || !source.isActive || target.isSemiInvulnerable())
return;
if (["cramorantgulping", "cramorantgorging"].includes(target.species.id)) {
this.damage(source.baseMaxhp / 4, source, target);
if (target.species.id === "cramorantgulping") {
this.boost({ def: -1 }, source, target, null, true);
} else {
source.trySetStatus("par", target, move);
}
target.formeChange("cramorant", move);
}
},
// The Dive part of this mechanic is implemented in Dive's `onTryMove` in moves.ts
onSourceTryPrimaryHit(target, source, effect) {
if (effect?.id === "surf" && source.hasAbility("gulpmissile") && source.species.name === "Cramorant") {
const forme = source.hp <= source.maxhp / 2 ? "cramorantgorging" : "cramorantgulping";
source.formeChange(forme, effect);
}
},
flags: { cantsuppress: 1, notransform: 1 },
name: "Gulp Missile",
rating: 2.5,
num: 241
},
guts: {
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
if (pokemon.status) {
return this.chainModify(1.5);
}
},
flags: {},
name: "Guts",
rating: 3.5,
num: 62
},
hadronengine: {
onStart(pokemon) {
if (!this.field.setTerrain("electricterrain") && this.field.isTerrain("electricterrain")) {
this.add("-activate", pokemon, "ability: Hadron Engine");
}
},
onModifySpAPriority: 5,
onModifySpA(atk, attacker, defender, move) {
if (this.field.isTerrain("electricterrain")) {
this.debug("Hadron Engine boost");
return this.chainModify([5461, 4096]);
}
},
flags: {},
name: "Hadron Engine",
rating: 4.5,
num: 289
},
harvest: {
onResidualOrder: 28,
onResidualSubOrder: 2,
onResidual(pokemon) {
if (this.field.isWeather(["sunnyday", "desolateland"]) || this.randomChance(1, 2)) {
if (pokemon.hp && !pokemon.item && this.dex.items.get(pokemon.lastItem).isBerry) {
pokemon.setItem(pokemon.lastItem);
pokemon.lastItem = "";
this.add("-item", pokemon, pokemon.getItem(), "[from] ability: Harvest");
}
}
},
flags: {},
name: "Harvest",
rating: 2.5,
num: 139
},
healer: {
onResidualOrder: 5,
onResidualSubOrder: 3,
onResidual(pokemon) {
for (const allyActive of pokemon.adjacentAllies()) {
if (allyActive.status && this.randomChance(3, 10)) {
this.add("-activate", pokemon, "ability: Healer");
allyActive.cureStatus();
}
}
},
flags: {},
name: "Healer",
rating: 0,
num: 131
},
heatproof: {
onSourceModifyAtkPriority: 6,
onSourceModifyAtk(atk, attacker, defender, move) {
if (move.type === "Fire") {
this.debug("Heatproof Atk weaken");
return this.chainModify(0.5);
}
},
onSourceModifySpAPriority: 5,
onSourceModifySpA(atk, attacker, defender, move) {
if (move.type === "Fire") {
this.debug("Heatproof SpA weaken");
return this.chainModify(0.5);
}
},
onDamage(damage, target, source, effect) {
if (effect && effect.id === "brn") {
return damage / 2;
}
},
flags: { breakable: 1 },
name: "Heatproof",
rating: 2,
num: 85
},
heavymetal: {
onModifyWeightPriority: 1,
onModifyWeight(weighthg) {
return weighthg * 2;
},
flags: { breakable: 1 },
name: "Heavy Metal",
rating: 0,
num: 134
},
honeygather: {
flags: {},
name: "Honey Gather",
rating: 0,
num: 118
},
hospitality: {
onSwitchInPriority: -2,
onStart(pokemon) {
for (const ally of pokemon.adjacentAllies()) {
this.heal(ally.baseMaxhp / 4, ally, pokemon);
}
},
flags: {},
name: "Hospitality",
rating: 0,
num: 299
},
hugepower: {
onModifyAtkPriority: 5,
onModifyAtk(atk) {
return this.chainModify(2);
},
flags: {},
name: "Huge Power",
rating: 5,
num: 37
},
hungerswitch: {
onResidualOrder: 29,
onResidual(pokemon) {
if (pokemon.species.baseSpecies !== "Morpeko" || pokemon.terastallized)
return;
const targetForme = pokemon.species.name === "Morpeko" ? "Morpeko-Hangry" : "Morpeko";
pokemon.formeChange(targetForme);
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1 },
name: "Hunger Switch",
rating: 1,
num: 258
},
hustle: {
// This should be applied directly to the stat as opposed to chaining with the others
onModifyAtkPriority: 5,
onModifyAtk(atk) {
return this.modify(atk, 1.5);
},
onSourceModifyAccuracyPriority: -1,
onSourceModifyAccuracy(accuracy, target, source, move) {
if (move.category === "Physical" && typeof accuracy === "number") {
return this.chainModify([3277, 4096]);
}
},
flags: {},
name: "Hustle",
rating: 3.5,
num: 55
},
hydration: {
onResidualOrder: 5,
onResidualSubOrder: 3,
onResidual(pokemon) {
if (pokemon.status && ["raindance", "primordialsea"].includes(pokemon.effectiveWeather())) {
this.debug("hydration");
this.add("-activate", pokemon, "ability: Hydration");
pokemon.cureStatus();
}
},
flags: {},
name: "Hydration",
rating: 1.5,
num: 93
},
hypercutter: {
onTryBoost(boost, target, source, effect) {
if (source && target === source)
return;
if (boost.atk && boost.atk < 0) {
delete boost.atk;
if (!effect.secondaries) {
this.add("-fail", target, "unboost", "Attack", "[from] ability: Hyper Cutter", `[of] ${target}`);
}
}
},
flags: { breakable: 1 },
name: "Hyper Cutter",
rating: 1.5,
num: 52
},
icebody: {
onWeather(target, source, effect) {
if (effect.id === "hail" || effect.id === "snowscape") {
this.heal(target.baseMaxhp / 16);
}
},
onImmunity(type, pokemon) {
if (type === "hail")
return false;
},
flags: {},
name: "Ice Body",
rating: 1,
num: 115
},
iceface: {
onSwitchInPriority: -2,
onStart(pokemon) {
if (this.field.isWeather(["hail", "snowscape"]) && pokemon.species.id === "eiscuenoice") {
this.add("-activate", pokemon, "ability: Ice Face");
this.effectState.busted = false;
pokemon.formeChange("Eiscue", this.effect, true);
}
},
onDamagePriority: 1,
onDamage(damage, target, source, effect) {
if (effect?.effectType === "Move" && effect.category === "Physical" && target.species.id === "eiscue") {
this.add("-activate", target, "ability: Ice Face");
this.effectState.busted = true;
return 0;
}
},
onCriticalHit(target, type, move) {
if (!target)
return;
if (move.category !== "Physical" || target.species.id !== "eiscue")
return;
if (target.volatiles["substitute"] && !(move.flags["bypasssub"] || move.infiltrates))
return;
if (!target.runImmunity(move.type))
return;
return false;
},
onEffectiveness(typeMod, target, type, move) {
if (!target)
return;
if (move.category !== "Physical" || target.species.id !== "eiscue")
return;
const hitSub = target.volatiles["substitute"] && !move.flags["bypasssub"] && !(move.infiltrates && this.gen >= 6);
if (hitSub)
return;
if (!target.runImmunity(move.type))
return;
return 0;
},
onUpdate(pokemon) {
if (pokemon.species.id === "eiscue" && this.effectState.busted) {
pokemon.formeChange("Eiscue-Noice", this.effect, true);
}
},
onWeatherChange(pokemon, source, sourceEffect) {
if (sourceEffect?.suppressWeather)
return;
if (!pokemon.hp)
return;
if (this.field.isWeather(["hail", "snowscape"]) && pokemon.species.id === "eiscuenoice") {
this.add("-activate", pokemon, "ability: Ice Face");
this.effectState.busted = false;
pokemon.formeChange("Eiscue", this.effect, true);
}
},
flags: {
failroleplay: 1,
noreceiver: 1,
noentrain: 1,
notrace: 1,
failskillswap: 1,
cantsuppress: 1,
breakable: 1,
notransform: 1
},
name: "Ice Face",
rating: 3,
num: 248
},
icescales: {
onSourceModifyDamage(damage, source, target, move) {
if (move.category === "Special") {
return this.chainModify(0.5);
}
},
flags: { breakable: 1 },
name: "Ice Scales",
rating: 4,
num: 246
},
illuminate: {
onTryBoost(boost, target, source, effect) {
if (source && target === source)
return;
if (boost.accuracy && boost.accuracy < 0) {
delete boost.accuracy;
if (!effect.secondaries) {
this.add("-fail", target, "unboost", "accuracy", "[from] ability: Illuminate", `[of] ${target}`);
}
}
},
onModifyMove(move) {
move.ignoreEvasion = true;
},
flags: { breakable: 1 },
name: "Illuminate",
rating: 0.5,
num: 35
},
illusion: {
onBeforeSwitchIn(pokemon) {
pokemon.illusion = null;
for (let i = pokemon.side.pokemon.length - 1; i > pokemon.position; i--) {
const possibleTarget = pokemon.side.pokemon[i];
if (!possibleTarget.fainted) {
if (!pokemon.terastallized || possibleTarget.species.baseSpecies !== "Ogerpon") {
pokemon.illusion = possibleTarget;
}
break;
}
}
},
onDamagingHit(damage, target, source, move) {
if (target.illusion) {
this.singleEvent("End", this.dex.abilities.get("Illusion"), target.abilityState, target, source, move);
}
},
onEnd(pokemon) {
if (pokemon.illusion) {
this.debug("illusion cleared");
pokemon.illusion = null;
const details = pokemon.getUpdatedDetails();
this.add("replace", pokemon, details);
this.add("-end", pokemon, "Illusion");
if (this.ruleTable.has("illusionlevelmod")) {
this.hint("Illusion Level Mod is active, so this Pok\xE9mon's true level was hidden.", true);
}
}
},
onFaint(pokemon) {
pokemon.illusion = null;
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1 },
name: "Illusion",
rating: 4.5,
num: 149
},
immunity: {
onUpdate(pokemon) {
if (pokemon.status === "psn" || pokemon.status === "tox") {
this.add("-activate", pokemon, "ability: Immunity");
pokemon.cureStatus();
}
},
onSetStatus(status, target, source, effect) {
if (status.id !== "psn" && status.id !== "tox")
return;
if (effect?.status) {
this.add("-immune", target, "[from] ability: Immunity");
}
return false;
},
flags: { breakable: 1 },
name: "Immunity",
rating: 2,
num: 17
},
imposter: {
onSwitchIn(pokemon) {
const target = pokemon.side.foe.active[pokemon.side.foe.active.length - 1 - pokemon.position];
if (target) {
pokemon.transformInto(target, this.dex.abilities.get("imposter"));
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
name: "Imposter",
rating: 5,
num: 150
},
infiltrator: {
onModifyMove(move) {
move.infiltrates = true;
},
flags: {},
name: "Infiltrator",
rating: 2.5,
num: 151
},
innardsout: {
onDamagingHitOrder: 1,
onDamagingHit(damage, target, source, move) {
if (!target.hp) {
this.damage(target.getUndynamaxedHP(damage), source, target);
}
},
flags: {},
name: "Innards Out",
rating: 4,
num: 215
},
innerfocus: {
onTryAddVolatile(status, pokemon) {
if (status.id === "flinch")
return null;
},
onTryBoost(boost, target, source, effect) {
if (effect.name === "Intimidate" && boost.atk) {
delete boost.atk;
this.add("-fail", target, "unboost", "Attack", "[from] ability: Inner Focus", `[of] ${target}`);
}
},
flags: { breakable: 1 },
name: "Inner Focus",
rating: 1,
num: 39
},
insomnia: {
onUpdate(pokemon) {
if (pokemon.status === "slp") {
this.add("-activate", pokemon, "ability: Insomnia");
pokemon.cureStatus();
}
},
onSetStatus(status, target, source, effect) {
if (status.id !== "slp")
return;
if (effect?.status) {
this.add("-immune", target, "[from] ability: Insomnia");
}
return false;
},
onTryAddVolatile(status, target) {
if (status.id === "yawn") {
this.add("-immune", target, "[from] ability: Insomnia");
return null;
}
},
flags: { breakable: 1 },
name: "Insomnia",
rating: 1.5,
num: 15
},
intimidate: {
onStart(pokemon) {
let activated = false;
for (const target of pokemon.adjacentFoes()) {
if (!activated) {
this.add("-ability", pokemon, "Intimidate", "boost");
activated = true;
}
if (target.volatiles["substitute"]) {
this.add("-immune", target);
} else {
this.boost({ atk: -1 }, target, pokemon, null, true);
}
}
},
flags: {},
name: "Intimidate",
rating: 3.5,
num: 22
},
intrepidsword: {
onStart(pokemon) {
if (pokemon.swordBoost)
return;
pokemon.swordBoost = true;
this.boost({ atk: 1 }, pokemon);
},
flags: {},
name: "Intrepid Sword",
rating: 4,
num: 234
},
ironbarbs: {
onDamagingHitOrder: 1,
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target, true)) {
this.damage(source.baseMaxhp / 8, source, target);
}
},
flags: {},
name: "Iron Barbs",
rating: 2.5,
num: 160
},
ironfist: {
onBasePowerPriority: 23,
onBasePower(basePower, attacker, defender, move) {
if (move.flags["punch"]) {
this.debug("Iron Fist boost");
return this.chainModify([4915, 4096]);
}
},
flags: {},
name: "Iron Fist",
rating: 3,
num: 89
},
justified: {
onDamagingHit(damage, target, source, move) {
if (move.type === "Dark") {
this.boost({ atk: 1 });
}
},
flags: {},
name: "Justified",
rating: 2.5,
num: 154
},
keeneye: {
onTryBoost(boost, target, source, effect) {
if (source && target === source)
return;
if (boost.accuracy && boost.accuracy < 0) {
delete boost.accuracy;
if (!effect.secondaries) {
this.add("-fail", target, "unboost", "accuracy", "[from] ability: Keen Eye", `[of] ${target}`);
}
}
},
onModifyMove(move) {
move.ignoreEvasion = true;
},
flags: { breakable: 1 },
name: "Keen Eye",
rating: 0.5,
num: 51
},
klutz: {
// Klutz isn't technically active immediately in-game, but it activates early enough to beat all items
// we should keep an eye out in future gens for items that activate on switch-in before Unnerve
onSwitchInPriority: 1,
// Item suppression implemented in Pokemon.ignoringItem() within sim/pokemon.js
onStart(pokemon) {
this.singleEvent("End", pokemon.getItem(), pokemon.itemState, pokemon);
},
flags: {},
name: "Klutz",
rating: -1,
num: 103
},
leafguard: {
onSetStatus(status, target, source, effect) {
if (["sunnyday", "desolateland"].includes(target.effectiveWeather())) {
if (effect?.status) {
this.add("-immune", target, "[from] ability: Leaf Guard");
}
return false;
}
},
onTryAddVolatile(status, target) {
if (status.id === "yawn" && ["sunnyday", "desolateland"].includes(target.effectiveWeather())) {
this.add("-immune", target, "[from] ability: Leaf Guard");
return null;
}
},
flags: { breakable: 1 },
name: "Leaf Guard",
rating: 0.5,
num: 102
},
levitate: {
// airborneness implemented in sim/pokemon.js:Pokemon#isGrounded
flags: { breakable: 1 },
name: "Levitate",
rating: 3.5,
num: 26
},
libero: {
onPrepareHit(source, target, move) {
if (this.effectState.libero === source.previouslySwitchedIn)
return;
if (move.hasBounced || move.flags["futuremove"] || move.sourceEffect === "snatch" || move.callsMove)
return;
const type = move.type;
if (type && type !== "???" && source.getTypes().join() !== type) {
if (!source.setType(type))
return;
this.effectState.libero = source.previouslySwitchedIn;
this.add("-start", source, "typechange", type, "[from] ability: Libero");
}
},
flags: {},
name: "Libero",
rating: 4,
num: 236
},
lightmetal: {
onModifyWeight(weighthg) {
return this.trunc(weighthg / 2);
},
flags: { breakable: 1 },
name: "Light Metal",
rating: 1,
num: 135
},
lightningrod: {
onTryHit(target, source, move) {
if (target !== source && move.type === "Electric") {
if (!this.boost({ spa: 1 })) {
this.add("-immune", target, "[from] ability: Lightning Rod");
}
return null;
}
},
onAnyRedirectTarget(target, source, source2, move) {
if (move.type !== "Electric" || move.flags["pledgecombo"])
return;
const redirectTarget = ["randomNormal", "adjacentFoe"].includes(move.target) ? "normal" : move.target;
if (this.validTarget(this.effectState.target, source, redirectTarget)) {
if (move.smartTarget)
move.smartTarget = false;
if (this.effectState.target !== target) {
this.add("-activate", this.effectState.target, "ability: Lightning Rod");
}
return this.effectState.target;
}
},
flags: { breakable: 1 },
name: "Lightning Rod",
rating: 3,
num: 31
},
limber: {
onUpdate(pokemon) {
if (pokemon.status === "par") {
this.add("-activate", pokemon, "ability: Limber");
pokemon.cureStatus();
}
},
onSetStatus(status, target, source, effect) {
if (status.id !== "par")
return;
if (effect?.status) {
this.add("-immune", target, "[from] ability: Limber");
}
return false;
},
flags: { breakable: 1 },
name: "Limber",
rating: 2,
num: 7
},
lingeringaroma: {
onDamagingHit(damage, target, source, move) {
const sourceAbility = source.getAbility();
if (sourceAbility.flags["cantsuppress"] || sourceAbility.id === "lingeringaroma") {
return;
}
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
const oldAbility = source.setAbility("lingeringaroma", target);
if (oldAbility) {
this.add("-activate", target, "ability: Lingering Aroma", this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
}
}
},
flags: {},
name: "Lingering Aroma",
rating: 2,
num: 268
},
liquidooze: {
onSourceTryHeal(damage, target, source, effect) {
this.debug(`Heal is occurring: ${target} <- ${source} :: ${effect.id}`);
const canOoze = ["drain", "leechseed", "strengthsap"];
if (canOoze.includes(effect.id)) {
this.damage(damage);
return 0;
}
},
flags: {},
name: "Liquid Ooze",
rating: 2.5,
num: 64
},
liquidvoice: {
onModifyTypePriority: -1,
onModifyType(move, pokemon) {
if (move.flags["sound"] && !pokemon.volatiles["dynamax"]) {
move.type = "Water";
}
},
flags: {},
name: "Liquid Voice",
rating: 1.5,
num: 204
},
longreach: {
onModifyMove(move) {
delete move.flags["contact"];
},
flags: {},
name: "Long Reach",
rating: 1,
num: 203
},
magicbounce: {
onTryHitPriority: 1,
onTryHit(target, source, move) {
if (target === source || move.hasBounced || !move.flags["reflectable"] || target.isSemiInvulnerable()) {
return;
}
const newMove = this.dex.getActiveMove(move.id);
newMove.hasBounced = true;
newMove.pranksterBoosted = false;
this.actions.useMove(newMove, target, { target: source });
return null;
},
onAllyTryHitSide(target, source, move) {
if (target.isAlly(source) || move.hasBounced || !move.flags["reflectable"] || target.isSemiInvulnerable()) {
return;
}
const newMove = this.dex.getActiveMove(move.id);
newMove.hasBounced = true;
newMove.pranksterBoosted = false;
this.actions.useMove(newMove, this.effectState.target, { target: source });
return null;
},
condition: {
duration: 1
},
flags: { breakable: 1 },
name: "Magic Bounce",
rating: 4,
num: 156
},
magicguard: {
onDamage(damage, target, source, effect) {
if (effect.effectType !== "Move") {
if (effect.effectType === "Ability")
this.add("-activate", source, "ability: " + effect.name);
return false;
}
},
flags: {},
name: "Magic Guard",
rating: 4,
num: 98
},
magician: {
onAfterMoveSecondarySelf(source, target, move) {
if (!move || !target || source.switchFlag === true)
return;
if (target !== source && move.category !== "Status") {
if (source.item || source.volatiles["gem"] || move.id === "fling")
return;
const yourItem = target.takeItem(source);
if (!yourItem)
return;
if (!source.setItem(yourItem)) {
target.item = yourItem.id;
return;
}
this.add("-item", source, yourItem, "[from] ability: Magician", `[of] ${target}`);
}
},
flags: {},
name: "Magician",
rating: 1,
num: 170
},
magmaarmor: {
onUpdate(pokemon) {
if (pokemon.status === "frz") {
this.add("-activate", pokemon, "ability: Magma Armor");
pokemon.cureStatus();
}
},
onImmunity(type, pokemon) {
if (type === "frz")
return false;
},
flags: { breakable: 1 },
name: "Magma Armor",
rating: 0.5,
num: 40
},
magnetpull: {
onFoeTrapPokemon(pokemon) {
if (pokemon.hasType("Steel") && pokemon.isAdjacent(this.effectState.target)) {
pokemon.tryTrap(true);
}
},
onFoeMaybeTrapPokemon(pokemon, source) {
if (!source)
source = this.effectState.target;
if (!source || !pokemon.isAdjacent(source))
return;
if (!pokemon.knownType || pokemon.hasType("Steel")) {
pokemon.maybeTrapped = true;
}
},
flags: {},
name: "Magnet Pull",
rating: 4,
num: 42
},
marvelscale: {
onModifyDefPriority: 6,
onModifyDef(def, pokemon) {
if (pokemon.status) {
return this.chainModify(1.5);
}
},
flags: { breakable: 1 },
name: "Marvel Scale",
rating: 2.5,
num: 63
},
megalauncher: {
onBasePowerPriority: 19,
onBasePower(basePower, attacker, defender, move) {
if (move.flags["pulse"]) {
return this.chainModify(1.5);
}
},
flags: {},
name: "Mega Launcher",
rating: 3,
num: 178
},
merciless: {
onModifyCritRatio(critRatio, source, target) {
if (target && ["psn", "tox"].includes(target.status))
return 5;
},
flags: {},
name: "Merciless",
rating: 1.5,
num: 196
},
mimicry: {
onSwitchInPriority: -1,
onStart(pokemon) {
this.singleEvent("TerrainChange", this.effect, this.effectState, pokemon);
},
onTerrainChange(pokemon) {
let types;
switch (this.field.terrain) {
case "electricterrain":
types = ["Electric"];
break;
case "grassyterrain":
types = ["Grass"];
break;
case "mistyterrain":
types = ["Fairy"];
break;
case "psychicterrain":
types = ["Psychic"];
break;
default:
types = pokemon.baseSpecies.types;
}
const oldTypes = pokemon.getTypes();
if (oldTypes.join() === types.join() || !pokemon.setType(types))
return;
if (this.field.terrain || pokemon.transformed) {
this.add("-start", pokemon, "typechange", types.join("/"), "[from] ability: Mimicry");
if (!this.field.terrain)
this.hint("Transform Mimicry changes you to your original un-transformed types.");
} else {
this.add("-activate", pokemon, "ability: Mimicry");
this.add("-end", pokemon, "typechange", "[silent]");
}
},
flags: {},
name: "Mimicry",
rating: 0,
num: 250
},
mindseye: {
onTryBoost(boost, target, source, effect) {
if (source && target === source)
return;
if (boost.accuracy && boost.accuracy < 0) {
delete boost.accuracy;
if (!effect.secondaries) {
this.add("-fail", target, "unboost", "accuracy", "[from] ability: Mind's Eye", `[of] ${target}`);
}
}
},
onModifyMovePriority: -5,
onModifyMove(move) {
move.ignoreEvasion = true;
if (!move.ignoreImmunity)
move.ignoreImmunity = {};
if (move.ignoreImmunity !== true) {
move.ignoreImmunity["Fighting"] = true;
move.ignoreImmunity["Normal"] = true;
}
},
flags: { breakable: 1 },
name: "Mind's Eye",
rating: 0,
num: 300
},
minus: {
onModifySpAPriority: 5,
onModifySpA(spa, pokemon) {
for (const allyActive of pokemon.allies()) {
if (allyActive.hasAbility(["minus", "plus"])) {
return this.chainModify(1.5);
}
}
},
flags: {},
name: "Minus",
rating: 0,
num: 58
},
mirrorarmor: {
onTryBoost(boost, target, source, effect) {
if (!source || target === source || !boost || effect.name === "Mirror Armor")
return;
let b;
for (b in boost) {
if (boost[b] < 0) {
if (target.boosts[b] === -6)
continue;
const negativeBoost = {};
negativeBoost[b] = boost[b];
delete boost[b];
if (source.hp) {
this.add("-ability", target, "Mirror Armor");
this.boost(negativeBoost, source, target, null, true);
}
}
}
},
flags: { breakable: 1 },
name: "Mirror Armor",
rating: 2,
num: 240
},
mistysurge: {
onStart(source) {
this.field.setTerrain("mistyterrain");
},
flags: {},
name: "Misty Surge",
rating: 3.5,
num: 228
},
moldbreaker: {
onStart(pokemon) {
this.add("-ability", pokemon, "Mold Breaker");
},
onModifyMove(move) {
move.ignoreAbility = true;
},
flags: {},
name: "Mold Breaker",
rating: 3,
num: 104
},
moody: {
onResidualOrder: 28,
onResidualSubOrder: 2,
onResidual(pokemon) {
let stats = [];
const boost = {};
let statPlus;
for (statPlus in pokemon.boosts) {
if (statPlus === "accuracy" || statPlus === "evasion")
continue;
if (pokemon.boosts[statPlus] < 6) {
stats.push(statPlus);
}
}
let randomStat = stats.length ? this.sample(stats) : void 0;
if (randomStat)
boost[randomStat] = 2;
stats = [];
let statMinus;
for (statMinus in pokemon.boosts) {
if (statMinus === "accuracy" || statMinus === "evasion")
continue;
if (pokemon.boosts[statMinus] > -6 && statMinus !== randomStat) {
stats.push(statMinus);
}
}
randomStat = stats.length ? this.sample(stats) : void 0;
if (randomStat)
boost[randomStat] = -1;
this.boost(boost, pokemon, pokemon);
},
flags: {},
name: "Moody",
rating: 5,
num: 141
},
motordrive: {
onTryHit(target, source, move) {
if (target !== source && move.type === "Electric") {
if (!this.boost({ spe: 1 })) {
this.add("-immune", target, "[from] ability: Motor Drive");
}
return null;
}
},
flags: { breakable: 1 },
name: "Motor Drive",
rating: 3,
num: 78
},
moxie: {
onSourceAfterFaint(length, target, source, effect) {
if (effect && effect.effectType === "Move") {
this.boost({ atk: length }, source);
}
},
flags: {},
name: "Moxie",
rating: 3,
num: 153
},
multiscale: {
onSourceModifyDamage(damage, source, target, move) {
if (target.hp >= target.maxhp) {
this.debug("Multiscale weaken");
return this.chainModify(0.5);
}
},
flags: { breakable: 1 },
name: "Multiscale",
rating: 3.5,
num: 136
},
multitype: {
// Multitype's type-changing itself is implemented in statuses.js
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "Multitype",
rating: 4,
num: 121
},
mummy: {
onDamagingHit(damage, target, source, move) {
const sourceAbility = source.getAbility();
if (sourceAbility.flags["cantsuppress"] || sourceAbility.id === "mummy") {
return;
}
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
const oldAbility = source.setAbility("mummy", target);
if (oldAbility) {
this.add("-activate", target, "ability: Mummy", this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
}
}
},
flags: {},
name: "Mummy",
rating: 2,
num: 152
},
myceliummight: {
onFractionalPriorityPriority: -1,
onFractionalPriority(priority, pokemon, target, move) {
if (move.category === "Status") {
return -0.1;
}
},
onModifyMove(move) {
if (move.category === "Status") {
move.ignoreAbility = true;
}
},
flags: {},
name: "Mycelium Might",
rating: 2,
num: 298
},
naturalcure: {
onCheckShow(pokemon) {
if (pokemon.side.active.length === 1)
return;
if (pokemon.showCure === true || pokemon.showCure === false)
return;
const cureList = [];
let noCureCount = 0;
for (const curPoke of pokemon.side.active) {
if (!curPoke?.status) {
continue;
}
if (curPoke.showCure) {
continue;
}
const species = curPoke.species;
if (!Object.values(species.abilities).includes("Natural Cure")) {
continue;
}
if (!species.abilities["1"] && !species.abilities["H"]) {
continue;
}
if (curPoke !== pokemon && !this.queue.willSwitch(curPoke)) {
continue;
}
if (curPoke.hasAbility("naturalcure")) {
cureList.push(curPoke);
} else {
noCureCount++;
}
}
if (!cureList.length || !noCureCount) {
for (const pkmn of cureList) {
pkmn.showCure = true;
}
} else {
this.add("-message", `(${cureList.length} of ${pokemon.side.name}'s pokemon ${cureList.length === 1 ? "was" : "were"} cured by Natural Cure.)`);
for (const pkmn of cureList) {
pkmn.showCure = false;
}
}
},
onSwitchOut(pokemon) {
if (!pokemon.status)
return;
if (pokemon.showCure === void 0)
pokemon.showCure = true;
if (pokemon.showCure)
this.add("-curestatus", pokemon, pokemon.status, "[from] ability: Natural Cure");
pokemon.clearStatus();
if (!pokemon.showCure)
pokemon.showCure = void 0;
},
flags: {},
name: "Natural Cure",
rating: 2.5,
num: 30
},
neuroforce: {
onModifyDamage(damage, source, target, move) {
if (move && target.getMoveHitData(move).typeMod > 0) {
return this.chainModify([5120, 4096]);
}
},
flags: {},
name: "Neuroforce",
rating: 2.5,
num: 233
},
neutralizinggas: {
// Ability suppression implemented in sim/pokemon.ts:Pokemon#ignoringAbility
onSwitchInPriority: 2,
onSwitchIn(pokemon) {
this.add("-ability", pokemon, "Neutralizing Gas");
pokemon.abilityState.ending = false;
const strongWeathers = ["desolateland", "primordialsea", "deltastream"];
for (const target of this.getAllActive()) {
if (target.hasItem("Ability Shield")) {
this.add("-block", target, "item: Ability Shield");
continue;
}
if (target.volatiles["commanding"]) {
continue;
}
if (target.illusion) {
this.singleEvent("End", this.dex.abilities.get("Illusion"), target.abilityState, target, pokemon, "neutralizinggas");
}
if (target.volatiles["slowstart"]) {
delete target.volatiles["slowstart"];
this.add("-end", target, "Slow Start", "[silent]");
}
if (strongWeathers.includes(target.getAbility().id)) {
this.singleEvent("End", this.dex.abilities.get(target.getAbility().id), target.abilityState, target, pokemon, "neutralizinggas");
}
}
},
onEnd(source) {
if (source.transformed)
return;
for (const pokemon of this.getAllActive()) {
if (pokemon !== source && pokemon.hasAbility("Neutralizing Gas")) {
return;
}
}
this.add("-end", source, "ability: Neutralizing Gas");
if (source.abilityState.ending)
return;
source.abilityState.ending = true;
const sortedActive = this.getAllActive();
this.speedSort(sortedActive);
for (const pokemon of sortedActive) {
if (pokemon !== source) {
if (pokemon.getAbility().flags["cantsuppress"])
continue;
if (pokemon.hasItem("abilityshield"))
continue;
this.singleEvent("Start", pokemon.getAbility(), pokemon.abilityState, pokemon);
if (pokemon.ability === "gluttony") {
pokemon.abilityState.gluttony = false;
}
}
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1 },
name: "Neutralizing Gas",
rating: 3.5,
num: 256
},
noguard: {
onAnyInvulnerabilityPriority: 1,
onAnyInvulnerability(target, source, move) {
if (move && (source === this.effectState.target || target === this.effectState.target))
return 0;
},
onAnyAccuracy(accuracy, target, source, move) {
if (move && (source === this.effectState.target || target === this.effectState.target)) {
return true;
}
return accuracy;
},
flags: {},
name: "No Guard",
rating: 4,
num: 99
},
normalize: {
onModifyTypePriority: 1,
onModifyType(move, pokemon) {
const noModifyType = [
"hiddenpower",
"judgment",
"multiattack",
"naturalgift",
"revelationdance",
"struggle",
"technoblast",
"terrainpulse",
"weatherball"
];
if (!(move.isZ && move.category !== "Status") && !noModifyType.includes(move.id) && // TODO: Figure out actual interaction
!(move.name === "Tera Blast" && pokemon.terastallized)) {
move.type = "Normal";
move.typeChangerBoosted = this.effect;
}
},
onBasePowerPriority: 23,
onBasePower(basePower, pokemon, target, move) {
if (move.typeChangerBoosted === this.effect)
return this.chainModify([4915, 4096]);
},
flags: {},
name: "Normalize",
rating: 0,
num: 96
},
oblivious: {
onUpdate(pokemon) {
if (pokemon.volatiles["attract"]) {
this.add("-activate", pokemon, "ability: Oblivious");
pokemon.removeVolatile("attract");
this.add("-end", pokemon, "move: Attract", "[from] ability: Oblivious");
}
if (pokemon.volatiles["taunt"]) {
this.add("-activate", pokemon, "ability: Oblivious");
pokemon.removeVolatile("taunt");
}
},
onImmunity(type, pokemon) {
if (type === "attract")
return false;
},
onTryHit(pokemon, target, move) {
if (move.id === "attract" || move.id === "captivate" || move.id === "taunt") {
this.add("-immune", pokemon, "[from] ability: Oblivious");
return null;
}
},
onTryBoost(boost, target, source, effect) {
if (effect.name === "Intimidate" && boost.atk) {
delete boost.atk;
this.add("-fail", target, "unboost", "Attack", "[from] ability: Oblivious", `[of] ${target}`);
}
},
flags: { breakable: 1 },
name: "Oblivious",
rating: 1.5,
num: 12
},
opportunist: {
onFoeAfterBoost(boost, target, source, effect) {
if (effect?.name === "Opportunist" || effect?.name === "Mirror Herb")
return;
if (!this.effectState.boosts)
this.effectState.boosts = {};
const boostPlus = this.effectState.boosts;
let i;
for (i in boost) {
if (boost[i] > 0) {
boostPlus[i] = (boostPlus[i] || 0) + boost[i];
}
}
},
onAnySwitchInPriority: -3,
onAnySwitchIn() {
if (!this.effectState.boosts)
return;
this.boost(this.effectState.boosts, this.effectState.target);
delete this.effectState.boosts;
},
onAnyAfterMove() {
if (!this.effectState.boosts)
return;
this.boost(this.effectState.boosts, this.effectState.target);
delete this.effectState.boosts;
},
onResidualOrder: 29,
onResidual(pokemon) {
if (!this.effectState.boosts)
return;
this.boost(this.effectState.boosts, this.effectState.target);
delete this.effectState.boosts;
},
onEnd() {
delete this.effectState.boosts;
},
flags: {},
name: "Opportunist",
rating: 3,
num: 290
},
orichalcumpulse: {
onStart(pokemon) {
if (this.field.setWeather("sunnyday")) {
this.add("-activate", pokemon, "Orichalcum Pulse", "[source]");
} else if (this.field.isWeather("sunnyday")) {
this.add("-activate", pokemon, "ability: Orichalcum Pulse");
}
},
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
if (["sunnyday", "desolateland"].includes(pokemon.effectiveWeather())) {
this.debug("Orichalcum boost");
return this.chainModify([5461, 4096]);
}
},
flags: {},
name: "Orichalcum Pulse",
rating: 4.5,
num: 288
},
overcoat: {
onImmunity(type, pokemon) {
if (type === "sandstorm" || type === "hail" || type === "powder")
return false;
},
onTryHitPriority: 1,
onTryHit(target, source, move) {
if (move.flags["powder"] && target !== source && this.dex.getImmunity("powder", target)) {
this.add("-immune", target, "[from] ability: Overcoat");
return null;
}
},
flags: { breakable: 1 },
name: "Overcoat",
rating: 2,
num: 142
},
overgrow: {
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender, move) {
if (move.type === "Grass" && attacker.hp <= attacker.maxhp / 3) {
this.debug("Overgrow boost");
return this.chainModify(1.5);
}
},
onModifySpAPriority: 5,
onModifySpA(atk, attacker, defender, move) {
if (move.type === "Grass" && attacker.hp <= attacker.maxhp / 3) {
this.debug("Overgrow boost");
return this.chainModify(1.5);
}
},
flags: {},
name: "Overgrow",
rating: 2,
num: 65
},
owntempo: {
onUpdate(pokemon) {
if (pokemon.volatiles["confusion"]) {
this.add("-activate", pokemon, "ability: Own Tempo");
pokemon.removeVolatile("confusion");
}
},
onTryAddVolatile(status, pokemon) {
if (status.id === "confusion")
return null;
},
onHit(target, source, move) {
if (move?.volatileStatus === "confusion") {
this.add("-immune", target, "confusion", "[from] ability: Own Tempo");
}
},
onTryBoost(boost, target, source, effect) {
if (effect.name === "Intimidate" && boost.atk) {
delete boost.atk;
this.add("-fail", target, "unboost", "Attack", "[from] ability: Own Tempo", `[of] ${target}`);
}
},
flags: { breakable: 1 },
name: "Own Tempo",
rating: 1.5,
num: 20
},
parentalbond: {
onPrepareHit(source, target, move) {
if (move.category === "Status" || move.multihit || move.flags["noparentalbond"] || move.flags["charge"] || move.flags["futuremove"] || move.spreadHit || move.isZ || move.isMax)
return;
move.multihit = 2;
move.multihitType = "parentalbond";
},
// Damage modifier implemented in BattleActions#modifyDamage()
onSourceModifySecondaries(secondaries, target, source, move) {
if (move.multihitType === "parentalbond" && move.id === "secretpower" && move.hit < 2) {
return secondaries.filter((effect) => effect.volatileStatus === "flinch");
}
},
flags: {},
name: "Parental Bond",
rating: 4.5,
num: 185
},
pastelveil: {
onStart(pokemon) {
for (const ally of pokemon.alliesAndSelf()) {
if (["psn", "tox"].includes(ally.status)) {
this.add("-activate", pokemon, "ability: Pastel Veil");
ally.cureStatus();
}
}
},
onUpdate(pokemon) {
if (["psn", "tox"].includes(pokemon.status)) {
this.add("-activate", pokemon, "ability: Pastel Veil");
pokemon.cureStatus();
}
},
onAnySwitchIn() {
this.effect.onStart.call(this, this.effectState.target);
},
onSetStatus(status, target, source, effect) {
if (!["psn", "tox"].includes(status.id))
return;
if (effect?.status) {
this.add("-immune", target, "[from] ability: Pastel Veil");
}
return false;
},
onAllySetStatus(status, target, source, effect) {
if (!["psn", "tox"].includes(status.id))
return;
if (effect?.status) {
const effectHolder = this.effectState.target;
this.add("-block", target, "ability: Pastel Veil", `[of] ${effectHolder}`);
}
return false;
},
flags: { breakable: 1 },
name: "Pastel Veil",
rating: 2,
num: 257
},
perishbody: {
onDamagingHit(damage, target, source, move) {
if (!this.checkMoveMakesContact(move, source, target) || source.volatiles["perishsong"])
return;
this.add("-ability", target, "Perish Body");
source.addVolatile("perishsong");
target.addVolatile("perishsong");
},
flags: {},
name: "Perish Body",
rating: 1,
num: 253
},
pickpocket: {
onAfterMoveSecondary(target, source, move) {
if (source && source !== target && move?.flags["contact"]) {
if (target.item || target.switchFlag || target.forceSwitchFlag || source.switchFlag === true) {
return;
}
const yourItem = source.takeItem(target);
if (!yourItem) {
return;
}
if (!target.setItem(yourItem)) {
source.item = yourItem.id;
return;
}
this.add("-enditem", source, yourItem, "[silent]", "[from] ability: Pickpocket", `[of] ${source}`);
this.add("-item", target, yourItem, "[from] ability: Pickpocket", `[of] ${source}`);
}
},
flags: {},
name: "Pickpocket",
rating: 1,
num: 124
},
pickup: {
onResidualOrder: 28,
onResidualSubOrder: 2,
onResidual(pokemon) {
if (pokemon.item)
return;
const pickupTargets = this.getAllActive().filter((target) => target.lastItem && target.usedItemThisTurn && pokemon.isAdjacent(target));
if (!pickupTargets.length)
return;
const randomTarget = this.sample(pickupTargets);
const item = randomTarget.lastItem;
randomTarget.lastItem = "";
this.add("-item", pokemon, this.dex.items.get(item), "[from] ability: Pickup");
pokemon.setItem(item);
},
flags: {},
name: "Pickup",
rating: 0.5,
num: 53
},
pixilate: {
onModifyTypePriority: -1,
onModifyType(move, pokemon) {
const noModifyType = [
"judgment",
"multiattack",
"naturalgift",
"revelationdance",
"technoblast",
"terrainpulse",
"weatherball"
];
if (move.type === "Normal" && !noModifyType.includes(move.id) && !(move.isZ && move.category !== "Status") && !(move.name === "Tera Blast" && pokemon.terastallized)) {
move.type = "Fairy";
move.typeChangerBoosted = this.effect;
}
},
onBasePowerPriority: 23,
onBasePower(basePower, pokemon, target, move) {
if (move.typeChangerBoosted === this.effect)
return this.chainModify([4915, 4096]);
},
flags: {},
name: "Pixilate",
rating: 4,
num: 182
},
plus: {
onModifySpAPriority: 5,
onModifySpA(spa, pokemon) {
for (const allyActive of pokemon.allies()) {
if (allyActive.hasAbility(["minus", "plus"])) {
return this.chainModify(1.5);
}
}
},
flags: {},
name: "Plus",
rating: 0,
num: 57
},
poisonheal: {
onDamagePriority: 1,
onDamage(damage, target, source, effect) {
if (effect.id === "psn" || effect.id === "tox") {
this.heal(target.baseMaxhp / 8);
return false;
}
},
flags: {},
name: "Poison Heal",
rating: 4,
num: 90
},
poisonpoint: {
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target)) {
if (this.randomChance(3, 10)) {
source.trySetStatus("psn", target);
}
}
},
flags: {},
name: "Poison Point",
rating: 1.5,
num: 38
},
poisonpuppeteer: {
onAnyAfterSetStatus(status, target, source, effect) {
if (source.baseSpecies.name !== "Pecharunt")
return;
if (source !== this.effectState.target || target === source || effect.effectType !== "Move")
return;
if (status.id === "psn" || status.id === "tox") {
target.addVolatile("confusion");
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1 },
name: "Poison Puppeteer",
rating: 3,
num: 310
},
poisontouch: {
onSourceDamagingHit(damage, target, source, move) {
if (target.hasAbility("shielddust") || target.hasItem("covertcloak"))
return;
if (this.checkMoveMakesContact(move, target, source)) {
if (this.randomChance(3, 10)) {
target.trySetStatus("psn", source);
}
}
},
flags: {},
name: "Poison Touch",
rating: 2,
num: 143
},
powerconstruct: {
onResidualOrder: 29,
onResidual(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== "Zygarde" || pokemon.transformed || !pokemon.hp)
return;
if (pokemon.species.id === "zygardecomplete" || pokemon.hp > pokemon.maxhp / 2)
return;
this.add("-activate", pokemon, "ability: Power Construct");
pokemon.formeChange("Zygarde-Complete", this.effect, true);
pokemon.baseMaxhp = Math.floor(Math.floor(
2 * pokemon.species.baseStats["hp"] + pokemon.set.ivs["hp"] + Math.floor(pokemon.set.evs["hp"] / 4) + 100
) * pokemon.level / 100 + 10);
const newMaxHP = pokemon.volatiles["dynamax"] ? 2 * pokemon.baseMaxhp : pokemon.baseMaxhp;
pokemon.hp = newMaxHP - (pokemon.maxhp - pokemon.hp);
pokemon.maxhp = newMaxHP;
this.add("-heal", pokemon, pokemon.getHealth, "[silent]");
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "Power Construct",
rating: 5,
num: 211
},
powerofalchemy: {
onAllyFaint(target) {
if (!this.effectState.target.hp)
return;
const ability = target.getAbility();
if (ability.flags["noreceiver"] || ability.id === "noability")
return;
if (this.effectState.target.setAbility(ability)) {
this.add("-ability", this.effectState.target, ability, "[from] ability: Power of Alchemy", `[of] ${target}`);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
name: "Power of Alchemy",
rating: 0,
num: 223
},
powerspot: {
onAllyBasePowerPriority: 22,
onAllyBasePower(basePower, attacker, defender, move) {
if (attacker !== this.effectState.target) {
this.debug("Power Spot boost");
return this.chainModify([5325, 4096]);
}
},
flags: {},
name: "Power Spot",
rating: 0,
num: 249
},
prankster: {
onModifyPriority(priority, pokemon, target, move) {
if (move?.category === "Status") {
move.pranksterBoosted = true;
return priority + 1;
}
},
flags: {},
name: "Prankster",
rating: 4,
num: 158
},
pressure: {
onStart(pokemon) {
this.add("-ability", pokemon, "Pressure");
},
onDeductPP(target, source) {
if (target.isAlly(source))
return;
return 1;
},
flags: {},
name: "Pressure",
rating: 2.5,
num: 46
},
primordialsea: {
onStart(source) {
this.field.setWeather("primordialsea");
},
onAnySetWeather(target, source, weather) {
const strongWeathers = ["desolateland", "primordialsea", "deltastream"];
if (this.field.getWeather().id === "primordialsea" && !strongWeathers.includes(weather.id))
return false;
},
onEnd(pokemon) {
if (this.field.weatherState.source !== pokemon)
return;
for (const target of this.getAllActive()) {
if (target === pokemon)
continue;
if (target.hasAbility("primordialsea")) {
this.field.weatherState.source = target;
return;
}
}
this.field.clearWeather();
},
flags: {},
name: "Primordial Sea",
rating: 4.5,
num: 189
},
prismarmor: {
onSourceModifyDamage(damage, source, target, move) {
if (target.getMoveHitData(move).typeMod > 0) {
this.debug("Prism Armor neutralize");
return this.chainModify(0.75);
}
},
flags: {},
name: "Prism Armor",
rating: 3,
num: 232
},
propellertail: {
onModifyMovePriority: 1,
onModifyMove(move) {
move.tracksTarget = move.target !== "scripted";
},
flags: {},
name: "Propeller Tail",
rating: 0,
num: 239
},
protean: {
onPrepareHit(source, target, move) {
if (this.effectState.protean === source.previouslySwitchedIn)
return;
if (move.hasBounced || move.flags["futuremove"] || move.sourceEffect === "snatch" || move.callsMove)
return;
const type = move.type;
if (type && type !== "???" && source.getTypes().join() !== type) {
if (!source.setType(type))
return;
this.effectState.protean = source.previouslySwitchedIn;
this.add("-start", source, "typechange", type, "[from] ability: Protean");
}
},
flags: {},
name: "Protean",
rating: 4,
num: 168
},
protosynthesis: {
onSwitchInPriority: -2,
onStart(pokemon) {
this.singleEvent("WeatherChange", this.effect, this.effectState, pokemon);
},
onWeatherChange(pokemon) {
if (this.field.isWeather("sunnyday")) {
pokemon.addVolatile("protosynthesis");
} else if (!pokemon.volatiles["protosynthesis"]?.fromBooster && !this.field.isWeather("sunnyday")) {
pokemon.removeVolatile("protosynthesis");
}
},
onEnd(pokemon) {
delete pokemon.volatiles["protosynthesis"];
this.add("-end", pokemon, "Protosynthesis", "[silent]");
},
condition: {
noCopy: true,
onStart(pokemon, source, effect) {
if (effect?.name === "Booster Energy") {
this.effectState.fromBooster = true;
this.add("-activate", pokemon, "ability: Protosynthesis", "[fromitem]");
} else {
this.add("-activate", pokemon, "ability: Protosynthesis");
}
this.effectState.bestStat = pokemon.getBestStat(false, true);
this.add("-start", pokemon, "protosynthesis" + this.effectState.bestStat);
},
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
if (this.effectState.bestStat !== "atk" || pokemon.ignoringAbility())
return;
this.debug("Protosynthesis atk boost");
return this.chainModify([5325, 4096]);
},
onModifyDefPriority: 6,
onModifyDef(def, pokemon) {
if (this.effectState.bestStat !== "def" || pokemon.ignoringAbility())
return;
this.debug("Protosynthesis def boost");
return this.chainModify([5325, 4096]);
},
onModifySpAPriority: 5,
onModifySpA(spa, pokemon) {
if (this.effectState.bestStat !== "spa" || pokemon.ignoringAbility())
return;
this.debug("Protosynthesis spa boost");
return this.chainModify([5325, 4096]);
},
onModifySpDPriority: 6,
onModifySpD(spd, pokemon) {
if (this.effectState.bestStat !== "spd" || pokemon.ignoringAbility())
return;
this.debug("Protosynthesis spd boost");
return this.chainModify([5325, 4096]);
},
onModifySpe(spe, pokemon) {
if (this.effectState.bestStat !== "spe" || pokemon.ignoringAbility())
return;
this.debug("Protosynthesis spe boost");
return this.chainModify(1.5);
},
onEnd(pokemon) {
this.add("-end", pokemon, "Protosynthesis");
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1 },
name: "Protosynthesis",
rating: 3,
num: 281
},
psychicsurge: {
onStart(source) {
this.field.setTerrain("psychicterrain");
},
flags: {},
name: "Psychic Surge",
rating: 4,
num: 227
},
punkrock: {
onBasePowerPriority: 7,
onBasePower(basePower, attacker, defender, move) {
if (move.flags["sound"]) {
this.debug("Punk Rock boost");
return this.chainModify([5325, 4096]);
}
},
onSourceModifyDamage(damage, source, target, move) {
if (move.flags["sound"]) {
this.debug("Punk Rock weaken");
return this.chainModify(0.5);
}
},
flags: { breakable: 1 },
name: "Punk Rock",
rating: 3.5,
num: 244
},
purepower: {
onModifyAtkPriority: 5,
onModifyAtk(atk) {
return this.chainModify(2);
},
flags: {},
name: "Pure Power",
rating: 5,
num: 74
},
purifyingsalt: {
onSetStatus(status, target, source, effect) {
if (effect?.status) {
this.add("-immune", target, "[from] ability: Purifying Salt");
}
return false;
},
onTryAddVolatile(status, target) {
if (status.id === "yawn") {
this.add("-immune", target, "[from] ability: Purifying Salt");
return null;
}
},
onSourceModifyAtkPriority: 6,
onSourceModifyAtk(atk, attacker, defender, move) {
if (move.type === "Ghost") {
this.debug("Purifying Salt weaken");
return this.chainModify(0.5);
}
},
onSourceModifySpAPriority: 5,
onSourceModifySpA(spa, attacker, defender, move) {
if (move.type === "Ghost") {
this.debug("Purifying Salt weaken");
return this.chainModify(0.5);
}
},
flags: { breakable: 1 },
name: "Purifying Salt",
rating: 4,
num: 272
},
quarkdrive: {
onSwitchInPriority: -2,
onStart(pokemon) {
this.singleEvent("TerrainChange", this.effect, this.effectState, pokemon);
},
onTerrainChange(pokemon) {
if (this.field.isTerrain("electricterrain")) {
pokemon.addVolatile("quarkdrive");
} else if (!pokemon.volatiles["quarkdrive"]?.fromBooster) {
pokemon.removeVolatile("quarkdrive");
}
},
onEnd(pokemon) {
delete pokemon.volatiles["quarkdrive"];
this.add("-end", pokemon, "Quark Drive", "[silent]");
},
condition: {
noCopy: true,
onStart(pokemon, source, effect) {
if (effect?.name === "Booster Energy") {
this.effectState.fromBooster = true;
this.add("-activate", pokemon, "ability: Quark Drive", "[fromitem]");
} else {
this.add("-activate", pokemon, "ability: Quark Drive");
}
this.effectState.bestStat = pokemon.getBestStat(false, true);
this.add("-start", pokemon, "quarkdrive" + this.effectState.bestStat);
},
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
if (this.effectState.bestStat !== "atk" || pokemon.ignoringAbility())
return;
this.debug("Quark Drive atk boost");
return this.chainModify([5325, 4096]);
},
onModifyDefPriority: 6,
onModifyDef(def, pokemon) {
if (this.effectState.bestStat !== "def" || pokemon.ignoringAbility())
return;
this.debug("Quark Drive def boost");
return this.chainModify([5325, 4096]);
},
onModifySpAPriority: 5,
onModifySpA(spa, pokemon) {
if (this.effectState.bestStat !== "spa" || pokemon.ignoringAbility())
return;
this.debug("Quark Drive spa boost");
return this.chainModify([5325, 4096]);
},
onModifySpDPriority: 6,
onModifySpD(spd, pokemon) {
if (this.effectState.bestStat !== "spd" || pokemon.ignoringAbility())
return;
this.debug("Quark Drive spd boost");
return this.chainModify([5325, 4096]);
},
onModifySpe(spe, pokemon) {
if (this.effectState.bestStat !== "spe" || pokemon.ignoringAbility())
return;
this.debug("Quark Drive spe boost");
return this.chainModify(1.5);
},
onEnd(pokemon) {
this.add("-end", pokemon, "Quark Drive");
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1 },
name: "Quark Drive",
rating: 3,
num: 282
},
queenlymajesty: {
onFoeTryMove(target, source, move) {
const targetAllExceptions = ["perishsong", "flowershield", "rototiller"];
if (move.target === "foeSide" || move.target === "all" && !targetAllExceptions.includes(move.id)) {
return;
}
const dazzlingHolder = this.effectState.target;
if ((source.isAlly(dazzlingHolder) || move.target === "all") && move.priority > 0.1) {
this.attrLastMove("[still]");
this.add("cant", dazzlingHolder, "ability: Queenly Majesty", move, `[of] ${target}`);
return false;
}
},
flags: { breakable: 1 },
name: "Queenly Majesty",
rating: 2.5,
num: 214
},
quickdraw: {
onFractionalPriorityPriority: -1,
onFractionalPriority(priority, pokemon, target, move) {
if (move.category !== "Status" && this.randomChance(3, 10)) {
this.add("-activate", pokemon, "ability: Quick Draw");
return 0.1;
}
},
flags: {},
name: "Quick Draw",
rating: 2.5,
num: 259
},
quickfeet: {
onModifySpe(spe, pokemon) {
if (pokemon.status) {
return this.chainModify(1.5);
}
},
flags: {},
name: "Quick Feet",
rating: 2.5,
num: 95
},
raindish: {
onWeather(target, source, effect) {
if (target.hasItem("utilityumbrella"))
return;
if (effect.id === "raindance" || effect.id === "primordialsea") {
this.heal(target.baseMaxhp / 16);
}
},
flags: {},
name: "Rain Dish",
rating: 1.5,
num: 44
},
rattled: {
onDamagingHit(damage, target, source, move) {
if (["Dark", "Bug", "Ghost"].includes(move.type)) {
this.boost({ spe: 1 });
}
},
onAfterBoost(boost, target, source, effect) {
if (effect?.name === "Intimidate" && boost.atk) {
this.boost({ spe: 1 });
}
},
flags: {},
name: "Rattled",
rating: 1,
num: 155
},
receiver: {
onAllyFaint(target) {
if (!this.effectState.target.hp)
return;
const ability = target.getAbility();
if (ability.flags["noreceiver"] || ability.id === "noability")
return;
if (this.effectState.target.setAbility(ability)) {
this.add("-ability", this.effectState.target, ability, "[from] ability: Receiver", `[of] ${target}`);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
name: "Receiver",
rating: 0,
num: 222
},
reckless: {
onBasePowerPriority: 23,
onBasePower(basePower, attacker, defender, move) {
if (move.recoil || move.hasCrashDamage) {
this.debug("Reckless boost");
return this.chainModify([4915, 4096]);
}
},
flags: {},
name: "Reckless",
rating: 3,
num: 120
},
refrigerate: {
onModifyTypePriority: -1,
onModifyType(move, pokemon) {
const noModifyType = [
"judgment",
"multiattack",
"naturalgift",
"revelationdance",
"technoblast",
"terrainpulse",
"weatherball"
];
if (move.type === "Normal" && !noModifyType.includes(move.id) && !(move.isZ && move.category !== "Status") && !(move.name === "Tera Blast" && pokemon.terastallized)) {
move.type = "Ice";
move.typeChangerBoosted = this.effect;
}
},
onBasePowerPriority: 23,
onBasePower(basePower, pokemon, target, move) {
if (move.typeChangerBoosted === this.effect)
return this.chainModify([4915, 4096]);
},
flags: {},
name: "Refrigerate",
rating: 4,
num: 174
},
regenerator: {
onSwitchOut(pokemon) {
pokemon.heal(pokemon.baseMaxhp / 3);
},
flags: {},
name: "Regenerator",
rating: 4.5,
num: 144
},
ripen: {
onTryHeal(damage, target, source, effect) {
if (!effect)
return;
if (effect.name === "Berry Juice" || effect.name === "Leftovers") {
this.add("-activate", target, "ability: Ripen");
}
if (effect.isBerry)
return this.chainModify(2);
},
onChangeBoost(boost, target, source, effect) {
if (effect && effect.isBerry) {
let b;
for (b in boost) {
boost[b] *= 2;
}
}
},
onSourceModifyDamagePriority: -1,
onSourceModifyDamage(damage, source, target, move) {
if (target.abilityState.berryWeaken) {
target.abilityState.berryWeaken = false;
return this.chainModify(0.5);
}
},
onTryEatItemPriority: -1,
onTryEatItem(item, pokemon) {
this.add("-activate", pokemon, "ability: Ripen");
},
onEatItem(item, pokemon) {
const weakenBerries = [
"Babiri Berry",
"Charti Berry",
"Chilan Berry",
"Chople Berry",
"Coba Berry",
"Colbur Berry",
"Haban Berry",
"Kasib Berry",
"Kebia Berry",
"Occa Berry",
"Passho Berry",
"Payapa Berry",
"Rindo Berry",
"Roseli Berry",
"Shuca Berry",
"Tanga Berry",
"Wacan Berry",
"Yache Berry"
];
pokemon.abilityState.berryWeaken = weakenBerries.includes(item.name);
},
flags: {},
name: "Ripen",
rating: 2,
num: 247
},
rivalry: {
onBasePowerPriority: 24,
onBasePower(basePower, attacker, defender, move) {
if (attacker.gender && defender.gender) {
if (attacker.gender === defender.gender) {
this.debug("Rivalry boost");
return this.chainModify(1.25);
} else {
this.debug("Rivalry weaken");
return this.chainModify(0.75);
}
}
},
flags: {},
name: "Rivalry",
rating: 0,
num: 79
},
rkssystem: {
// RKS System's type-changing itself is implemented in statuses.js
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "RKS System",
rating: 4,
num: 225
},
rockhead: {
onDamage(damage, target, source, effect) {
if (effect.id === "recoil") {
if (!this.activeMove)
throw new Error("Battle.activeMove is null");
if (this.activeMove.id !== "struggle")
return null;
}
},
flags: {},
name: "Rock Head",
rating: 3,
num: 69
},
rockypayload: {
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender, move) {
if (move.type === "Rock") {
this.debug("Rocky Payload boost");
return this.chainModify(1.5);
}
},
onModifySpAPriority: 5,
onModifySpA(atk, attacker, defender, move) {
if (move.type === "Rock") {
this.debug("Rocky Payload boost");
return this.chainModify(1.5);
}
},
flags: {},
name: "Rocky Payload",
rating: 3.5,
num: 276
},
roughskin: {
onDamagingHitOrder: 1,
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target, true)) {
this.damage(source.baseMaxhp / 8, source, target);
}
},
flags: {},
name: "Rough Skin",
rating: 2.5,
num: 24
},
runaway: {
flags: {},
name: "Run Away",
rating: 0,
num: 50
},
sandforce: {
onBasePowerPriority: 21,
onBasePower(basePower, attacker, defender, move) {
if (this.field.isWeather("sandstorm")) {
if (move.type === "Rock" || move.type === "Ground" || move.type === "Steel") {
this.debug("Sand Force boost");
return this.chainModify([5325, 4096]);
}
}
},
onImmunity(type, pokemon) {
if (type === "sandstorm")
return false;
},
flags: {},
name: "Sand Force",
rating: 2,
num: 159
},
sandrush: {
onModifySpe(spe, pokemon) {
if (this.field.isWeather("sandstorm")) {
return this.chainModify(2);
}
},
onImmunity(type, pokemon) {
if (type === "sandstorm")
return false;
},
flags: {},
name: "Sand Rush",
rating: 3,
num: 146
},
sandspit: {
onDamagingHit(damage, target, source, move) {
this.field.setWeather("sandstorm");
},
flags: {},
name: "Sand Spit",
rating: 1,
num: 245
},
sandstream: {
onStart(source) {
this.field.setWeather("sandstorm");
},
flags: {},
name: "Sand Stream",
rating: 4,
num: 45
},
sandveil: {
onImmunity(type, pokemon) {
if (type === "sandstorm")
return false;
},
onModifyAccuracyPriority: -1,
onModifyAccuracy(accuracy) {
if (typeof accuracy !== "number")
return;
if (this.field.isWeather("sandstorm")) {
this.debug("Sand Veil - decreasing accuracy");
return this.chainModify([3277, 4096]);
}
},
flags: { breakable: 1 },
name: "Sand Veil",
rating: 1.5,
num: 8
},
sapsipper: {
onTryHitPriority: 1,
onTryHit(target, source, move) {
if (target !== source && move.type === "Grass") {
if (!this.boost({ atk: 1 })) {
this.add("-immune", target, "[from] ability: Sap Sipper");
}
return null;
}
},
onAllyTryHitSide(target, source, move) {
if (source === this.effectState.target || !target.isAlly(source))
return;
if (move.type === "Grass") {
this.boost({ atk: 1 }, this.effectState.target);
}
},
flags: { breakable: 1 },
name: "Sap Sipper",
rating: 3,
num: 157
},
schooling: {
onSwitchInPriority: -1,
onStart(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== "Wishiwashi" || pokemon.level < 20 || pokemon.transformed)
return;
if (pokemon.hp > pokemon.maxhp / 4) {
if (pokemon.species.id === "wishiwashi") {
pokemon.formeChange("Wishiwashi-School");
}
} else {
if (pokemon.species.id === "wishiwashischool") {
pokemon.formeChange("Wishiwashi");
}
}
},
onResidualOrder: 29,
onResidual(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== "Wishiwashi" || pokemon.level < 20 || pokemon.transformed || !pokemon.hp)
return;
if (pokemon.hp > pokemon.maxhp / 4) {
if (pokemon.species.id === "wishiwashi") {
pokemon.formeChange("Wishiwashi-School");
}
} else {
if (pokemon.species.id === "wishiwashischool") {
pokemon.formeChange("Wishiwashi");
}
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "Schooling",
rating: 3,
num: 208
},
scrappy: {
onModifyMovePriority: -5,
onModifyMove(move) {
if (!move.ignoreImmunity)
move.ignoreImmunity = {};
if (move.ignoreImmunity !== true) {
move.ignoreImmunity["Fighting"] = true;
move.ignoreImmunity["Normal"] = true;
}
},
onTryBoost(boost, target, source, effect) {
if (effect.name === "Intimidate" && boost.atk) {
delete boost.atk;
this.add("-fail", target, "unboost", "Attack", "[from] ability: Scrappy", `[of] ${target}`);
}
},
flags: {},
name: "Scrappy",
rating: 3,
num: 113
},
screencleaner: {
onStart(pokemon) {
let activated = false;
for (const sideCondition of ["reflect", "lightscreen", "auroraveil"]) {
for (const side of [pokemon.side, ...pokemon.side.foeSidesWithConditions()]) {
if (side.getSideCondition(sideCondition)) {
if (!activated) {
this.add("-activate", pokemon, "ability: Screen Cleaner");
activated = true;
}
side.removeSideCondition(sideCondition);
}
}
}
},
flags: {},
name: "Screen Cleaner",
rating: 2,
num: 251
},
seedsower: {
onDamagingHit(damage, target, source, move) {
this.field.setTerrain("grassyterrain");
},
flags: {},
name: "Seed Sower",
rating: 2.5,
num: 269
},
serenegrace: {
onModifyMovePriority: -2,
onModifyMove(move) {
if (move.secondaries) {
this.debug("doubling secondary chance");
for (const secondary of move.secondaries) {
if (secondary.chance)
secondary.chance *= 2;
}
}
if (move.self?.chance)
move.self.chance *= 2;
},
flags: {},
name: "Serene Grace",
rating: 3.5,
num: 32
},
shadowshield: {
onSourceModifyDamage(damage, source, target, move) {
if (target.hp >= target.maxhp) {
this.debug("Shadow Shield weaken");
return this.chainModify(0.5);
}
},
flags: {},
name: "Shadow Shield",
rating: 3.5,
num: 231
},
shadowtag: {
onFoeTrapPokemon(pokemon) {
if (!pokemon.hasAbility("shadowtag") && pokemon.isAdjacent(this.effectState.target)) {
pokemon.tryTrap(true);
}
},
onFoeMaybeTrapPokemon(pokemon, source) {
if (!source)
source = this.effectState.target;
if (!source || !pokemon.isAdjacent(source))
return;
if (!pokemon.hasAbility("shadowtag")) {
pokemon.maybeTrapped = true;
}
},
flags: {},
name: "Shadow Tag",
rating: 5,
num: 23
},
sharpness: {
onBasePowerPriority: 19,
onBasePower(basePower, attacker, defender, move) {
if (move.flags["slicing"]) {
this.debug("Sharpness boost");
return this.chainModify(1.5);
}
},
flags: {},
name: "Sharpness",
rating: 3.5,
num: 292
},
shedskin: {
onResidualOrder: 5,
onResidualSubOrder: 3,
onResidual(pokemon) {
if (pokemon.hp && pokemon.status && this.randomChance(33, 100)) {
this.debug("shed skin");
this.add("-activate", pokemon, "ability: Shed Skin");
pokemon.cureStatus();
}
},
flags: {},
name: "Shed Skin",
rating: 3,
num: 61
},
sheerforce: {
onModifyMove(move, pokemon) {
if (move.secondaries) {
delete move.secondaries;
delete move.self;
if (move.id === "clangoroussoulblaze")
delete move.selfBoost;
move.hasSheerForce = true;
}
},
onBasePowerPriority: 21,
onBasePower(basePower, pokemon, target, move) {
if (move.hasSheerForce)
return this.chainModify([5325, 4096]);
},
flags: {},
name: "Sheer Force",
rating: 3.5,
num: 125
},
shellarmor: {
onCriticalHit: false,
flags: { breakable: 1 },
name: "Shell Armor",
rating: 1,
num: 75
},
shielddust: {
onModifySecondaries(secondaries) {
this.debug("Shield Dust prevent secondary");
return secondaries.filter((effect) => !!(effect.self || effect.dustproof));
},
flags: { breakable: 1 },
name: "Shield Dust",
rating: 2,
num: 19
},
shieldsdown: {
onSwitchInPriority: -1,
onStart(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== "Minior" || pokemon.transformed)
return;
if (pokemon.hp > pokemon.maxhp / 2) {
if (pokemon.species.forme !== "Meteor") {
pokemon.formeChange("Minior-Meteor");
}
} else {
if (pokemon.species.forme === "Meteor") {
pokemon.formeChange(pokemon.set.species);
}
}
},
onResidualOrder: 29,
onResidual(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== "Minior" || pokemon.transformed || !pokemon.hp)
return;
if (pokemon.hp > pokemon.maxhp / 2) {
if (pokemon.species.forme !== "Meteor") {
pokemon.formeChange("Minior-Meteor");
}
} else {
if (pokemon.species.forme === "Meteor") {
pokemon.formeChange(pokemon.set.species);
}
}
},
onSetStatus(status, target, source, effect) {
if (target.species.id !== "miniormeteor" || target.transformed)
return;
if (effect?.status) {
this.add("-immune", target, "[from] ability: Shields Down");
}
return false;
},
onTryAddVolatile(status, target) {
if (target.species.id !== "miniormeteor" || target.transformed)
return;
if (status.id !== "yawn")
return;
this.add("-immune", target, "[from] ability: Shields Down");
return null;
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "Shields Down",
rating: 3,
num: 197
},
simple: {
onChangeBoost(boost, target, source, effect) {
if (effect && effect.id === "zpower")
return;
let i;
for (i in boost) {
boost[i] *= 2;
}
},
flags: { breakable: 1 },
name: "Simple",
rating: 4,
num: 86
},
skilllink: {
onModifyMove(move) {
if (move.multihit && Array.isArray(move.multihit) && move.multihit.length) {
move.multihit = move.multihit[1];
}
if (move.multiaccuracy) {
delete move.multiaccuracy;
}
},
flags: {},
name: "Skill Link",
rating: 3,
num: 92
},
slowstart: {
onStart(pokemon) {
pokemon.addVolatile("slowstart");
},
onEnd(pokemon) {
delete pokemon.volatiles["slowstart"];
this.add("-end", pokemon, "Slow Start", "[silent]");
},
condition: {
duration: 5,
onResidualOrder: 28,
onResidualSubOrder: 2,
onStart(target) {
this.add("-start", target, "ability: Slow Start");
},
onResidual(pokemon) {
if (!pokemon.activeTurns) {
this.effectState.duration += 1;
}
},
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
return this.chainModify(0.5);
},
onModifySpe(spe, pokemon) {
return this.chainModify(0.5);
},
onEnd(target) {
this.add("-end", target, "Slow Start");
}
},
flags: {},
name: "Slow Start",
rating: -1,
num: 112
},
slushrush: {
onModifySpe(spe, pokemon) {
if (this.field.isWeather(["hail", "snowscape"])) {
return this.chainModify(2);
}
},
flags: {},
name: "Slush Rush",
rating: 3,
num: 202
},
sniper: {
onModifyDamage(damage, source, target, move) {
if (target.getMoveHitData(move).crit) {
this.debug("Sniper boost");
return this.chainModify(1.5);
}
},
flags: {},
name: "Sniper",
rating: 2,
num: 97
},
snowcloak: {
onImmunity(type, pokemon) {
if (type === "hail")
return false;
},
onModifyAccuracyPriority: -1,
onModifyAccuracy(accuracy) {
if (typeof accuracy !== "number")
return;
if (this.field.isWeather(["hail", "snowscape"])) {
this.debug("Snow Cloak - decreasing accuracy");
return this.chainModify([3277, 4096]);
}
},
flags: { breakable: 1 },
name: "Snow Cloak",
rating: 1.5,
num: 81
},
snowwarning: {
onStart(source) {
this.field.setWeather("snowscape");
},
flags: {},
name: "Snow Warning",
rating: 4,
num: 117
},
solarpower: {
onModifySpAPriority: 5,
onModifySpA(spa, pokemon) {
if (["sunnyday", "desolateland"].includes(pokemon.effectiveWeather())) {
return this.chainModify(1.5);
}
},
onWeather(target, source, effect) {
if (target.hasItem("utilityumbrella"))
return;
if (effect.id === "sunnyday" || effect.id === "desolateland") {
this.damage(target.baseMaxhp / 8, target, target);
}
},
flags: {},
name: "Solar Power",
rating: 2,
num: 94
},
solidrock: {
onSourceModifyDamage(damage, source, target, move) {
if (target.getMoveHitData(move).typeMod > 0) {
this.debug("Solid Rock neutralize");
return this.chainModify(0.75);
}
},
flags: { breakable: 1 },
name: "Solid Rock",
rating: 3,
num: 116
},
soulheart: {
onAnyFaintPriority: 1,
onAnyFaint() {
this.boost({ spa: 1 }, this.effectState.target);
},
flags: {},
name: "Soul-Heart",
rating: 3.5,
num: 220
},
soundproof: {
onTryHit(target, source, move) {
if (target !== source && move.flags["sound"]) {
this.add("-immune", target, "[from] ability: Soundproof");
return null;
}
},
onAllyTryHitSide(target, source, move) {
if (move.flags["sound"]) {
this.add("-immune", this.effectState.target, "[from] ability: Soundproof");
}
},
flags: { breakable: 1 },
name: "Soundproof",
rating: 2,
num: 43
},
speedboost: {
onResidualOrder: 28,
onResidualSubOrder: 2,
onResidual(pokemon) {
if (pokemon.activeTurns) {
this.boost({ spe: 1 });
}
},
flags: {},
name: "Speed Boost",
rating: 4.5,
num: 3
},
stakeout: {
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender) {
if (!defender.activeTurns) {
this.debug("Stakeout boost");
return this.chainModify(2);
}
},
onModifySpAPriority: 5,
onModifySpA(atk, attacker, defender) {
if (!defender.activeTurns) {
this.debug("Stakeout boost");
return this.chainModify(2);
}
},
flags: {},
name: "Stakeout",
rating: 4.5,
num: 198
},
stall: {
onFractionalPriority: -0.1,
flags: {},
name: "Stall",
rating: -1,
num: 100
},
stalwart: {
onModifyMovePriority: 1,
onModifyMove(move) {
move.tracksTarget = move.target !== "scripted";
},
flags: {},
name: "Stalwart",
rating: 0,
num: 242
},
stamina: {
onDamagingHit(damage, target, source, effect) {
this.boost({ def: 1 });
},
flags: {},
name: "Stamina",
rating: 4,
num: 192
},
stancechange: {
onModifyMovePriority: 1,
onModifyMove(move, attacker, defender) {
if (attacker.species.baseSpecies !== "Aegislash" || attacker.transformed)
return;
if (move.category === "Status" && move.id !== "kingsshield")
return;
const targetForme = move.id === "kingsshield" ? "Aegislash" : "Aegislash-Blade";
if (attacker.species.name !== targetForme)
attacker.formeChange(targetForme);
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "Stance Change",
rating: 4,
num: 176
},
static: {
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target)) {
if (this.randomChance(3, 10)) {
source.trySetStatus("par", target);
}
}
},
flags: {},
name: "Static",
rating: 2,
num: 9
},
steadfast: {
onFlinch(pokemon) {
this.boost({ spe: 1 });
},
flags: {},
name: "Steadfast",
rating: 1,
num: 80
},
steamengine: {
onDamagingHit(damage, target, source, move) {
if (["Water", "Fire"].includes(move.type)) {
this.boost({ spe: 6 });
}
},
flags: {},
name: "Steam Engine",
rating: 2,
num: 243
},
steelworker: {
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender, move) {
if (move.type === "Steel") {
this.debug("Steelworker boost");
return this.chainModify(1.5);
}
},
onModifySpAPriority: 5,
onModifySpA(atk, attacker, defender, move) {
if (move.type === "Steel") {
this.debug("Steelworker boost");
return this.chainModify(1.5);
}
},
flags: {},
name: "Steelworker",
rating: 3.5,
num: 200
},
steelyspirit: {
onAllyBasePowerPriority: 22,
onAllyBasePower(basePower, attacker, defender, move) {
if (move.type === "Steel") {
this.debug("Steely Spirit boost");
return this.chainModify(1.5);
}
},
flags: {},
name: "Steely Spirit",
rating: 3.5,
num: 252
},
stench: {
onModifyMovePriority: -1,
onModifyMove(move) {
if (move.category !== "Status") {
this.debug("Adding Stench flinch");
if (!move.secondaries)
move.secondaries = [];
for (const secondary of move.secondaries) {
if (secondary.volatileStatus === "flinch")
return;
}
move.secondaries.push({
chance: 10,
volatileStatus: "flinch"
});
}
},
flags: {},
name: "Stench",
rating: 0.5,
num: 1
},
stickyhold: {
onTakeItem(item, pokemon, source) {
if (!this.activeMove)
throw new Error("Battle.activeMove is null");
if (!pokemon.hp || pokemon.item === "stickybarb")
return;
if (source && source !== pokemon || this.activeMove.id === "knockoff") {
this.add("-activate", pokemon, "ability: Sticky Hold");
return false;
}
},
flags: { breakable: 1 },
name: "Sticky Hold",
rating: 1.5,
num: 60
},
stormdrain: {
onTryHit(target, source, move) {
if (target !== source && move.type === "Water") {
if (!this.boost({ spa: 1 })) {
this.add("-immune", target, "[from] ability: Storm Drain");
}
return null;
}
},
onAnyRedirectTarget(target, source, source2, move) {
if (move.type !== "Water" || move.flags["pledgecombo"])
return;
const redirectTarget = ["randomNormal", "adjacentFoe"].includes(move.target) ? "normal" : move.target;
if (this.validTarget(this.effectState.target, source, redirectTarget)) {
if (move.smartTarget)
move.smartTarget = false;
if (this.effectState.target !== target) {
this.add("-activate", this.effectState.target, "ability: Storm Drain");
}
return this.effectState.target;
}
},
flags: { breakable: 1 },
name: "Storm Drain",
rating: 3,
num: 114
},
strongjaw: {
onBasePowerPriority: 19,
onBasePower(basePower, attacker, defender, move) {
if (move.flags["bite"]) {
return this.chainModify(1.5);
}
},
flags: {},
name: "Strong Jaw",
rating: 3.5,
num: 173
},
sturdy: {
onTryHit(pokemon, target, move) {
if (move.ohko) {
this.add("-immune", pokemon, "[from] ability: Sturdy");
return null;
}
},
onDamagePriority: -30,
onDamage(damage, target, source, effect) {
if (target.hp === target.maxhp && damage >= target.hp && effect && effect.effectType === "Move") {
this.add("-ability", target, "Sturdy");
return target.hp - 1;
}
},
flags: { breakable: 1 },
name: "Sturdy",
rating: 3,
num: 5
},
suctioncups: {
onDragOutPriority: 1,
onDragOut(pokemon) {
this.add("-activate", pokemon, "ability: Suction Cups");
return null;
},
flags: { breakable: 1 },
name: "Suction Cups",
rating: 1,
num: 21
},
superluck: {
onModifyCritRatio(critRatio) {
return critRatio + 1;
},
flags: {},
name: "Super Luck",
rating: 1.5,
num: 105
},
supersweetsyrup: {
onStart(pokemon) {
if (pokemon.syrupTriggered)
return;
pokemon.syrupTriggered = true;
this.add("-ability", pokemon, "Supersweet Syrup");
for (const target of pokemon.adjacentFoes()) {
if (target.volatiles["substitute"]) {
this.add("-immune", target);
} else {
this.boost({ evasion: -1 }, target, pokemon, null, true);
}
}
},
flags: {},
name: "Supersweet Syrup",
rating: 1.5,
num: 306
},
supremeoverlord: {
onStart(pokemon) {
if (pokemon.side.totalFainted) {
this.add("-activate", pokemon, "ability: Supreme Overlord");
const fallen = Math.min(pokemon.side.totalFainted, 5);
this.add("-start", pokemon, `fallen${fallen}`, "[silent]");
this.effectState.fallen = fallen;
}
},
onEnd(pokemon) {
this.add("-end", pokemon, `fallen${this.effectState.fallen}`, "[silent]");
},
onBasePowerPriority: 21,
onBasePower(basePower, attacker, defender, move) {
if (this.effectState.fallen) {
const powMod = [4096, 4506, 4915, 5325, 5734, 6144];
this.debug(`Supreme Overlord boost: ${powMod[this.effectState.fallen]}/4096`);
return this.chainModify([powMod[this.effectState.fallen], 4096]);
}
},
flags: {},
name: "Supreme Overlord",
rating: 4,
num: 293
},
surgesurfer: {
onModifySpe(spe) {
if (this.field.isTerrain("electricterrain")) {
return this.chainModify(2);
}
},
flags: {},
name: "Surge Surfer",
rating: 3,
num: 207
},
swarm: {
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender, move) {
if (move.type === "Bug" && attacker.hp <= attacker.maxhp / 3) {
this.debug("Swarm boost");
return this.chainModify(1.5);
}
},
onModifySpAPriority: 5,
onModifySpA(atk, attacker, defender, move) {
if (move.type === "Bug" && attacker.hp <= attacker.maxhp / 3) {
this.debug("Swarm boost");
return this.chainModify(1.5);
}
},
flags: {},
name: "Swarm",
rating: 2,
num: 68
},
sweetveil: {
onAllySetStatus(status, target, source, effect) {
if (status.id === "slp") {
this.debug("Sweet Veil interrupts sleep");
const effectHolder = this.effectState.target;
this.add("-block", target, "ability: Sweet Veil", `[of] ${effectHolder}`);
return null;
}
},
onAllyTryAddVolatile(status, target) {
if (status.id === "yawn") {
this.debug("Sweet Veil blocking yawn");
const effectHolder = this.effectState.target;
this.add("-block", target, "ability: Sweet Veil", `[of] ${effectHolder}`);
return null;
}
},
flags: { breakable: 1 },
name: "Sweet Veil",
rating: 2,
num: 175
},
swiftswim: {
onModifySpe(spe, pokemon) {
if (["raindance", "primordialsea"].includes(pokemon.effectiveWeather())) {
return this.chainModify(2);
}
},
flags: {},
name: "Swift Swim",
rating: 3,
num: 33
},
symbiosis: {
onAllyAfterUseItem(item, pokemon) {
if (pokemon.switchFlag)
return;
const source = this.effectState.target;
const myItem = source.takeItem();
if (!myItem)
return;
if (!this.singleEvent("TakeItem", myItem, source.itemState, pokemon, source, this.effect, myItem) || !pokemon.setItem(myItem)) {
source.item = myItem.id;
return;
}
this.add("-activate", source, "ability: Symbiosis", myItem, `[of] ${pokemon}`);
},
flags: {},
name: "Symbiosis",
rating: 0,
num: 180
},
synchronize: {
onAfterSetStatus(status, target, source, effect) {
if (!source || source === target)
return;
if (effect && effect.id === "toxicspikes")
return;
if (status.id === "slp" || status.id === "frz")
return;
this.add("-activate", target, "ability: Synchronize");
source.trySetStatus(status, target, { status: status.id, id: "synchronize" });
},
flags: {},
name: "Synchronize",
rating: 2,
num: 28
},
swordofruin: {
onStart(pokemon) {
if (this.suppressingAbility(pokemon))
return;
this.add("-ability", pokemon, "Sword of Ruin");
},
onAnyModifyDef(def, target, source, move) {
const abilityHolder = this.effectState.target;
if (target.hasAbility("Sword of Ruin"))
return;
if (!move.ruinedDef?.hasAbility("Sword of Ruin"))
move.ruinedDef = abilityHolder;
if (move.ruinedDef !== abilityHolder)
return;
this.debug("Sword of Ruin Def drop");
return this.chainModify(0.75);
},
flags: {},
name: "Sword of Ruin",
rating: 4.5,
num: 285
},
tabletsofruin: {
onStart(pokemon) {
if (this.suppressingAbility(pokemon))
return;
this.add("-ability", pokemon, "Tablets of Ruin");
},
onAnyModifyAtk(atk, source, target, move) {
const abilityHolder = this.effectState.target;
if (source.hasAbility("Tablets of Ruin"))
return;
if (!move.ruinedAtk)
move.ruinedAtk = abilityHolder;
if (move.ruinedAtk !== abilityHolder)
return;
this.debug("Tablets of Ruin Atk drop");
return this.chainModify(0.75);
},
flags: {},
name: "Tablets of Ruin",
rating: 4.5,
num: 284
},
tangledfeet: {
onModifyAccuracyPriority: -1,
onModifyAccuracy(accuracy, target) {
if (typeof accuracy !== "number")
return;
if (target?.volatiles["confusion"]) {
this.debug("Tangled Feet - decreasing accuracy");
return this.chainModify(0.5);
}
},
flags: { breakable: 1 },
name: "Tangled Feet",
rating: 1,
num: 77
},
tanglinghair: {
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target, true)) {
this.add("-ability", target, "Tangling Hair");
this.boost({ spe: -1 }, source, target, null, true);
}
},
flags: {},
name: "Tangling Hair",
rating: 2,
num: 221
},
technician: {
onBasePowerPriority: 30,
onBasePower(basePower, attacker, defender, move) {
const basePowerAfterMultiplier = this.modify(basePower, this.event.modifier);
this.debug(`Base Power: ${basePowerAfterMultiplier}`);
if (basePowerAfterMultiplier <= 60) {
this.debug("Technician boost");
return this.chainModify(1.5);
}
},
flags: {},
name: "Technician",
rating: 3.5,
num: 101
},
telepathy: {
onTryHit(target, source, move) {
if (target !== source && target.isAlly(source) && move.category !== "Status") {
this.add("-activate", target, "ability: Telepathy");
return null;
}
},
flags: { breakable: 1 },
name: "Telepathy",
rating: 0,
num: 140
},
teraformzero: {
onAfterTerastallization(pokemon) {
if (pokemon.baseSpecies.name !== "Terapagos-Stellar")
return;
if (this.field.weather || this.field.terrain) {
this.add("-ability", pokemon, "Teraform Zero");
this.field.clearWeather();
this.field.clearTerrain();
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1 },
name: "Teraform Zero",
rating: 3,
num: 309
},
terashell: {
// effectiveness implemented in sim/pokemon.ts:Pokemon#runEffectiveness
// needs two checks to reset between regular moves and future attacks
onAnyBeforeMove() {
delete this.effectState.resisted;
},
onAnyAfterMove() {
delete this.effectState.resisted;
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, breakable: 1 },
name: "Tera Shell",
rating: 3.5,
num: 308
},
terashift: {
onSwitchInPriority: 2,
onSwitchIn(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== "Terapagos")
return;
if (pokemon.species.forme !== "Terastal") {
this.add("-activate", pokemon, "ability: Tera Shift");
pokemon.formeChange("Terapagos-Terastal", this.effect, true);
pokemon.regressionForme = false;
pokemon.baseMaxhp = Math.floor(Math.floor(
2 * pokemon.species.baseStats["hp"] + pokemon.set.ivs["hp"] + Math.floor(pokemon.set.evs["hp"] / 4) + 100
) * pokemon.level / 100 + 10);
const newMaxHP = pokemon.baseMaxhp;
pokemon.hp = newMaxHP - (pokemon.maxhp - pokemon.hp);
pokemon.maxhp = newMaxHP;
this.add("-heal", pokemon, pokemon.getHealth, "[silent]");
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1, notransform: 1 },
name: "Tera Shift",
rating: 3,
num: 307
},
teravolt: {
onStart(pokemon) {
this.add("-ability", pokemon, "Teravolt");
},
onModifyMove(move) {
move.ignoreAbility = true;
},
flags: {},
name: "Teravolt",
rating: 3,
num: 164
},
thermalexchange: {
onDamagingHit(damage, target, source, move) {
if (move.type === "Fire") {
this.boost({ atk: 1 });
}
},
onUpdate(pokemon) {
if (pokemon.status === "brn") {
this.add("-activate", pokemon, "ability: Thermal Exchange");
pokemon.cureStatus();
}
},
onSetStatus(status, target, source, effect) {
if (status.id !== "brn")
return;
if (effect?.status) {
this.add("-immune", target, "[from] ability: Thermal Exchange");
}
return false;
},
flags: { breakable: 1 },
name: "Thermal Exchange",
rating: 2.5,
num: 270
},
thickfat: {
onSourceModifyAtkPriority: 6,
onSourceModifyAtk(atk, attacker, defender, move) {
if (move.type === "Ice" || move.type === "Fire") {
this.debug("Thick Fat weaken");
return this.chainModify(0.5);
}
},
onSourceModifySpAPriority: 5,
onSourceModifySpA(atk, attacker, defender, move) {
if (move.type === "Ice" || move.type === "Fire") {
this.debug("Thick Fat weaken");
return this.chainModify(0.5);
}
},
flags: { breakable: 1 },
name: "Thick Fat",
rating: 3.5,
num: 47
},
tintedlens: {
onModifyDamage(damage, source, target, move) {
if (target.getMoveHitData(move).typeMod < 0) {
this.debug("Tinted Lens boost");
return this.chainModify(2);
}
},
flags: {},
name: "Tinted Lens",
rating: 4,
num: 110
},
torrent: {
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender, move) {
if (move.type === "Water" && attacker.hp <= attacker.maxhp / 3) {
this.debug("Torrent boost");
return this.chainModify(1.5);
}
},
onModifySpAPriority: 5,
onModifySpA(atk, attacker, defender, move) {
if (move.type === "Water" && attacker.hp <= attacker.maxhp / 3) {
this.debug("Torrent boost");
return this.chainModify(1.5);
}
},
flags: {},
name: "Torrent",
rating: 2,
num: 67
},
toughclaws: {
onBasePowerPriority: 21,
onBasePower(basePower, attacker, defender, move) {
if (move.flags["contact"]) {
return this.chainModify([5325, 4096]);
}
},
flags: {},
name: "Tough Claws",
rating: 3.5,
num: 181
},
toxicboost: {
onBasePowerPriority: 19,
onBasePower(basePower, attacker, defender, move) {
if ((attacker.status === "psn" || attacker.status === "tox") && move.category === "Physical") {
return this.chainModify(1.5);
}
},
flags: {},
name: "Toxic Boost",
rating: 3,
num: 137
},
toxicchain: {
onSourceDamagingHit(damage, target, source, move) {
if (target.hasAbility("shielddust") || target.hasItem("covertcloak"))
return;
if (this.randomChance(3, 10)) {
target.trySetStatus("tox", source);
}
},
flags: {},
name: "Toxic Chain",
rating: 4.5,
num: 305
},
toxicdebris: {
onDamagingHit(damage, target, source, move) {
const side = source.isAlly(target) ? source.side.foe : source.side;
const toxicSpikes = side.sideConditions["toxicspikes"];
if (move.category === "Physical" && (!toxicSpikes || toxicSpikes.layers < 2)) {
this.add("-activate", target, "ability: Toxic Debris");
side.addSideCondition("toxicspikes", target);
}
},
flags: {},
name: "Toxic Debris",
rating: 3.5,
num: 295
},
trace: {
onStart(pokemon) {
this.effectState.seek = true;
if (pokemon.adjacentFoes().some((foeActive) => foeActive.ability === "noability")) {
this.effectState.seek = false;
}
if (pokemon.hasItem("Ability Shield")) {
this.add("-block", pokemon, "item: Ability Shield");
this.effectState.seek = false;
}
if (this.effectState.seek) {
this.singleEvent("Update", this.effect, this.effectState, pokemon);
}
},
onUpdate(pokemon) {
if (!this.effectState.seek)
return;
const possibleTargets = pokemon.adjacentFoes().filter(
(target2) => !target2.getAbility().flags["notrace"] && target2.ability !== "noability"
);
if (!possibleTargets.length)
return;
const target = this.sample(possibleTargets);
const ability = target.getAbility();
if (pokemon.setAbility(ability)) {
this.add("-ability", pokemon, ability, "[from] ability: Trace", `[of] ${target}`);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
name: "Trace",
rating: 2.5,
num: 36
},
transistor: {
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender, move) {
if (move.type === "Electric") {
this.debug("Transistor boost");
return this.chainModify([5325, 4096]);
}
},
onModifySpAPriority: 5,
onModifySpA(atk, attacker, defender, move) {
if (move.type === "Electric") {
this.debug("Transistor boost");
return this.chainModify([5325, 4096]);
}
},
flags: {},
name: "Transistor",
rating: 3.5,
num: 262
},
triage: {
onModifyPriority(priority, pokemon, target, move) {
if (move?.flags["heal"])
return priority + 3;
},
flags: {},
name: "Triage",
rating: 3.5,
num: 205
},
truant: {
onStart(pokemon) {
pokemon.removeVolatile("truant");
if (pokemon.activeTurns && (pokemon.moveThisTurnResult !== void 0 || !this.queue.willMove(pokemon))) {
pokemon.addVolatile("truant");
}
},
onBeforeMovePriority: 9,
onBeforeMove(pokemon) {
if (pokemon.removeVolatile("truant")) {
this.add("cant", pokemon, "ability: Truant");
return false;
}
pokemon.addVolatile("truant");
},
condition: {},
flags: {},
name: "Truant",
rating: -1,
num: 54
},
turboblaze: {
onStart(pokemon) {
this.add("-ability", pokemon, "Turboblaze");
},
onModifyMove(move) {
move.ignoreAbility = true;
},
flags: {},
name: "Turboblaze",
rating: 3,
num: 163
},
unaware: {
onAnyModifyBoost(boosts, pokemon) {
const unawareUser = this.effectState.target;
if (unawareUser === pokemon)
return;
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
boosts["def"] = 0;
boosts["spd"] = 0;
boosts["evasion"] = 0;
}
if (pokemon === this.activePokemon && unawareUser === this.activeTarget) {
boosts["atk"] = 0;
boosts["def"] = 0;
boosts["spa"] = 0;
boosts["accuracy"] = 0;
}
},
flags: { breakable: 1 },
name: "Unaware",
rating: 4,
num: 109
},
unburden: {
onAfterUseItem(item, pokemon) {
if (pokemon !== this.effectState.target)
return;
pokemon.addVolatile("unburden");
},
onTakeItem(item, pokemon) {
pokemon.addVolatile("unburden");
},
onEnd(pokemon) {
pokemon.removeVolatile("unburden");
},
condition: {
onModifySpe(spe, pokemon) {
if (!pokemon.item && !pokemon.ignoringAbility()) {
return this.chainModify(2);
}
}
},
flags: {},
name: "Unburden",
rating: 3.5,
num: 84
},
unnerve: {
onSwitchInPriority: 1,
onStart(pokemon) {
if (this.effectState.unnerved)
return;
this.add("-ability", pokemon, "Unnerve");
this.effectState.unnerved = true;
},
onEnd() {
this.effectState.unnerved = false;
},
onFoeTryEatItem() {
return !this.effectState.unnerved;
},
flags: {},
name: "Unnerve",
rating: 1,
num: 127
},
unseenfist: {
onModifyMove(move) {
if (move.flags["contact"])
delete move.flags["protect"];
},
flags: {},
name: "Unseen Fist",
rating: 2,
num: 260
},
vesselofruin: {
onStart(pokemon) {
if (this.suppressingAbility(pokemon))
return;
this.add("-ability", pokemon, "Vessel of Ruin");
},
onAnyModifySpA(spa, source, target, move) {
const abilityHolder = this.effectState.target;
if (source.hasAbility("Vessel of Ruin"))
return;
if (!move.ruinedSpA)
move.ruinedSpA = abilityHolder;
if (move.ruinedSpA !== abilityHolder)
return;
this.debug("Vessel of Ruin SpA drop");
return this.chainModify(0.75);
},
flags: {},
name: "Vessel of Ruin",
rating: 4.5,
num: 284
},
victorystar: {
onAnyModifyAccuracyPriority: -1,
onAnyModifyAccuracy(accuracy, target, source) {
if (source.isAlly(this.effectState.target) && typeof accuracy === "number") {
return this.chainModify([4506, 4096]);
}
},
flags: {},
name: "Victory Star",
rating: 2,
num: 162
},
vitalspirit: {
onUpdate(pokemon) {
if (pokemon.status === "slp") {
this.add("-activate", pokemon, "ability: Vital Spirit");
pokemon.cureStatus();
}
},
onSetStatus(status, target, source, effect) {
if (status.id !== "slp")
return;
if (effect?.status) {
this.add("-immune", target, "[from] ability: Vital Spirit");
}
return false;
},
onTryAddVolatile(status, target) {
if (status.id === "yawn") {
this.add("-immune", target, "[from] ability: Vital Spirit");
return null;
}
},
flags: { breakable: 1 },
name: "Vital Spirit",
rating: 1.5,
num: 72
},
voltabsorb: {
onTryHit(target, source, move) {
if (target !== source && move.type === "Electric") {
if (!this.heal(target.baseMaxhp / 4)) {
this.add("-immune", target, "[from] ability: Volt Absorb");
}
return null;
}
},
flags: { breakable: 1 },
name: "Volt Absorb",
rating: 3.5,
num: 10
},
wanderingspirit: {
onDamagingHit(damage, target, source, move) {
if (source.getAbility().flags["failskillswap"] || target.volatiles["dynamax"])
return;
if (this.checkMoveMakesContact(move, source, target)) {
const targetCanBeSet = this.runEvent("SetAbility", target, source, this.effect, source.ability);
if (!targetCanBeSet)
return targetCanBeSet;
const sourceAbility = source.setAbility("wanderingspirit", target);
if (!sourceAbility)
return;
if (target.isAlly(source)) {
this.add("-activate", target, "Skill Swap", "", "", `[of] ${source}`);
} else {
this.add("-activate", target, "ability: Wandering Spirit", this.dex.abilities.get(sourceAbility).name, "Wandering Spirit", `[of] ${source}`);
}
target.setAbility(sourceAbility);
}
},
flags: {},
name: "Wandering Spirit",
rating: 2.5,
num: 254
},
waterabsorb: {
onTryHit(target, source, move) {
if (target !== source && move.type === "Water") {
if (!this.heal(target.baseMaxhp / 4)) {
this.add("-immune", target, "[from] ability: Water Absorb");
}
return null;
}
},
flags: { breakable: 1 },
name: "Water Absorb",
rating: 3.5,
num: 11
},
waterbubble: {
onSourceModifyAtkPriority: 5,
onSourceModifyAtk(atk, attacker, defender, move) {
if (move.type === "Fire") {
return this.chainModify(0.5);
}
},
onSourceModifySpAPriority: 5,
onSourceModifySpA(atk, attacker, defender, move) {
if (move.type === "Fire") {
return this.chainModify(0.5);
}
},
onModifyAtk(atk, attacker, defender, move) {
if (move.type === "Water") {
return this.chainModify(2);
}
},
onModifySpA(atk, attacker, defender, move) {
if (move.type === "Water") {
return this.chainModify(2);
}
},
onUpdate(pokemon) {
if (pokemon.status === "brn") {
this.add("-activate", pokemon, "ability: Water Bubble");
pokemon.cureStatus();
}
},
onSetStatus(status, target, source, effect) {
if (status.id !== "brn")
return;
if (effect?.status) {
this.add("-immune", target, "[from] ability: Water Bubble");
}
return false;
},
flags: { breakable: 1 },
name: "Water Bubble",
rating: 4.5,
num: 199
},
watercompaction: {
onDamagingHit(damage, target, source, move) {
if (move.type === "Water") {
this.boost({ def: 2 });
}
},
flags: {},
name: "Water Compaction",
rating: 1.5,
num: 195
},
waterveil: {
onUpdate(pokemon) {
if (pokemon.status === "brn") {
this.add("-activate", pokemon, "ability: Water Veil");
pokemon.cureStatus();
}
},
onSetStatus(status, target, source, effect) {
if (status.id !== "brn")
return;
if (effect?.status) {
this.add("-immune", target, "[from] ability: Water Veil");
}
return false;
},
flags: { breakable: 1 },
name: "Water Veil",
rating: 2,
num: 41
},
weakarmor: {
onDamagingHit(damage, target, source, move) {
if (move.category === "Physical") {
this.boost({ def: -1, spe: 2 }, target, target);
}
},
flags: {},
name: "Weak Armor",
rating: 1,
num: 133
},
wellbakedbody: {
onTryHit(target, source, move) {
if (target !== source && move.type === "Fire") {
if (!this.boost({ def: 2 })) {
this.add("-immune", target, "[from] ability: Well-Baked Body");
}
return null;
}
},
flags: { breakable: 1 },
name: "Well-Baked Body",
rating: 3.5,
num: 273
},
whitesmoke: {
onTryBoost(boost, target, source, effect) {
if (source && target === source)
return;
let showMsg = false;
let i;
for (i in boost) {
if (boost[i] < 0) {
delete boost[i];
showMsg = true;
}
}
if (showMsg && !effect.secondaries && effect.id !== "octolock") {
this.add("-fail", target, "unboost", "[from] ability: White Smoke", `[of] ${target}`);
}
},
flags: { breakable: 1 },
name: "White Smoke",
rating: 2,
num: 73
},
wimpout: {
onEmergencyExit(target) {
if (!this.canSwitch(target.side) || target.forceSwitchFlag || target.switchFlag)
return;
for (const side of this.sides) {
for (const active of side.active) {
active.switchFlag = false;
}
}
target.switchFlag = true;
this.add("-activate", target, "ability: Wimp Out");
},
flags: {},
name: "Wimp Out",
rating: 1,
num: 193
},
windpower: {
onDamagingHitOrder: 1,
onDamagingHit(damage, target, source, move) {
if (move.flags["wind"]) {
target.addVolatile("charge");
}
},
onAllySideConditionStart(target, source, sideCondition) {
const pokemon = this.effectState.target;
if (sideCondition.id === "tailwind") {
pokemon.addVolatile("charge");
}
},
flags: {},
name: "Wind Power",
rating: 1,
num: 277
},
windrider: {
onStart(pokemon) {
if (pokemon.side.sideConditions["tailwind"]) {
this.boost({ atk: 1 }, pokemon, pokemon);
}
},
onTryHit(target, source, move) {
if (target !== source && move.flags["wind"]) {
if (!this.boost({ atk: 1 }, target, target)) {
this.add("-immune", target, "[from] ability: Wind Rider");
}
return null;
}
},
onAllySideConditionStart(target, source, sideCondition) {
const pokemon = this.effectState.target;
if (sideCondition.id === "tailwind") {
this.boost({ atk: 1 }, pokemon, pokemon);
}
},
flags: { breakable: 1 },
name: "Wind Rider",
rating: 3.5,
// We do not want Brambleghast to get Infiltrator in Randbats
num: 274
},
wonderguard: {
onTryHit(target, source, move) {
if (target === source || move.category === "Status" || move.type === "???" || move.id === "struggle")
return;
if (move.id === "skydrop" && !source.volatiles["skydrop"])
return;
this.debug("Wonder Guard immunity: " + move.id);
if (target.runEffectiveness(move) <= 0) {
if (move.smartTarget) {
move.smartTarget = false;
} else {
this.add("-immune", target, "[from] ability: Wonder Guard");
}
return null;
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, failskillswap: 1, breakable: 1 },
name: "Wonder Guard",
rating: 5,
num: 25
},
wonderskin: {
onModifyAccuracyPriority: 10,
onModifyAccuracy(accuracy, target, source, move) {
if (move.category === "Status" && typeof accuracy === "number") {
this.debug("Wonder Skin - setting accuracy to 50");
return 50;
}
},
flags: { breakable: 1 },
name: "Wonder Skin",
rating: 2,
num: 147
},
zenmode: {
onResidualOrder: 29,
onResidual(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== "Darmanitan" || pokemon.transformed) {
return;
}
if (pokemon.hp <= pokemon.maxhp / 2 && !["Zen", "Galar-Zen"].includes(pokemon.species.forme)) {
pokemon.addVolatile("zenmode");
} else if (pokemon.hp > pokemon.maxhp / 2 && ["Zen", "Galar-Zen"].includes(pokemon.species.forme)) {
pokemon.addVolatile("zenmode");
pokemon.removeVolatile("zenmode");
}
},
onEnd(pokemon) {
if (!pokemon.volatiles["zenmode"] || !pokemon.hp)
return;
pokemon.transformed = false;
delete pokemon.volatiles["zenmode"];
if (pokemon.species.baseSpecies === "Darmanitan" && pokemon.species.battleOnly) {
pokemon.formeChange(pokemon.species.battleOnly, this.effect, false, "0", "[silent]");
}
},
condition: {
onStart(pokemon) {
if (!pokemon.species.name.includes("Galar")) {
if (pokemon.species.id !== "darmanitanzen")
pokemon.formeChange("Darmanitan-Zen");
} else {
if (pokemon.species.id !== "darmanitangalarzen")
pokemon.formeChange("Darmanitan-Galar-Zen");
}
},
onEnd(pokemon) {
if (["Zen", "Galar-Zen"].includes(pokemon.species.forme)) {
pokemon.formeChange(pokemon.species.battleOnly);
}
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "Zen Mode",
rating: 0,
num: 161
},
zerotohero: {
onSwitchOut(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== "Palafin")
return;
if (pokemon.species.forme !== "Hero") {
pokemon.formeChange("Palafin-Hero", this.effect, true);
pokemon.regressionForme = false;
}
},
onSwitchIn(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== "Palafin")
return;
if (!this.effectState.heroMessageDisplayed && pokemon.species.forme === "Hero") {
this.add("-activate", pokemon, "ability: Zero to Hero");
this.effectState.heroMessageDisplayed = true;
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1, notransform: 1 },
name: "Zero to Hero",
rating: 5,
num: 278
},
// CAP
mountaineer: {
onDamage(damage, target, source, effect) {
if (effect && effect.id === "stealthrock") {
return false;
}
},
onTryHit(target, source, move) {
if (move.type === "Rock" && !target.activeTurns) {
this.add("-immune", target, "[from] ability: Mountaineer");
return null;
}
},
isNonstandard: "CAP",
flags: { breakable: 1 },
name: "Mountaineer",
rating: 3,
num: -2
},
rebound: {
isNonstandard: "CAP",
onTryHitPriority: 1,
onTryHit(target, source, move) {
if (this.effectState.target.activeTurns)
return;
if (target === source || move.hasBounced || !move.flags["reflectable"]) {
return;
}
const newMove = this.dex.getActiveMove(move.id);
newMove.hasBounced = true;
this.actions.useMove(newMove, target, { target: source });
return null;
},
onAllyTryHitSide(target, source, move) {
if (this.effectState.target.activeTurns)
return;
if (target.isAlly(source) || move.hasBounced || !move.flags["reflectable"]) {
return;
}
const newMove = this.dex.getActiveMove(move.id);
newMove.hasBounced = true;
this.actions.useMove(newMove, this.effectState.target, { target: source });
return null;
},
condition: {
duration: 1
},
flags: { breakable: 1 },
name: "Rebound",
rating: 3,
num: -3
},
persistent: {
isNonstandard: "CAP",
// implemented in the corresponding move
flags: {},
name: "Persistent",
rating: 3,
num: -4
}
};
//# sourceMappingURL=abilities.js.map