mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-05-23 00:06:15 -05:00
Add a new event ModifyAccuracy that affects all moves other than OHKO moves and switched many event handlers that originally used the Accuracy event to ModifyAccuracy instead.
617 lines
16 KiB
JavaScript
617 lines
16 KiB
JavaScript
exports.BattleAbilities = {
|
|
"drizzle": {
|
|
inherit: true,
|
|
onStart: function (source) {
|
|
this.setWeather('raindance', source, null);
|
|
}
|
|
},
|
|
"swiftswim": {
|
|
inherit: true,
|
|
onModifySpe: function (speMod, pokemon) {
|
|
if (this.isWeather(['raindance', 'primordialsea'])) {
|
|
return this.chain(speMod, 1.5);
|
|
}
|
|
}
|
|
},
|
|
"drought": {
|
|
inherit: true,
|
|
onStart: function (source) {
|
|
this.setWeather('sunnyday', source, null);
|
|
}
|
|
},
|
|
"chlorophyll": {
|
|
inherit: true,
|
|
onModifySpe: function (speMod) {
|
|
if (this.isWeather(['sunnyday', 'desolateland'])) {
|
|
return this.chain(speMod, 1.5);
|
|
}
|
|
}
|
|
},
|
|
"snowwarning": {
|
|
inherit: true,
|
|
onStart: function (source) {
|
|
this.setWeather('hail', source, null);
|
|
}
|
|
},
|
|
"sandstream": {
|
|
inherit: true,
|
|
onStart: function (source) {
|
|
this.setWeather('sandstorm', source, null);
|
|
}
|
|
},
|
|
"sandrush": {
|
|
inherit: true,
|
|
onModifySpe: function (speMod, pokemon) {
|
|
if (this.isWeather('sandstorm')) {
|
|
return this.chain(speMod, 1.5);
|
|
}
|
|
}
|
|
},
|
|
"forecast": {
|
|
inherit: true,
|
|
onModifyMove: function (move) {
|
|
if (move.weather) {
|
|
var weather = move.weather;
|
|
move.weather = null;
|
|
move.onHit = function (target, source) {
|
|
this.setWeather(weather, source, this.getAbility('forecast'));
|
|
this.weatherData.duration = 0;
|
|
};
|
|
move.target = 'self';
|
|
}
|
|
}
|
|
},
|
|
"thickfat": {
|
|
inherit: true,
|
|
onImmunity: function (type, pokemon) {
|
|
if (type === 'hail') return false;
|
|
},
|
|
onSourceModifyAtk: function (atk, attacker, defender, move) {
|
|
if (move.type === 'Ice' || move.type === 'Fire' || move.type === 'Fighting') {
|
|
this.add('-message', "The attack was weakened by Thick Fat!");
|
|
return this.chainModify(0.5);
|
|
}
|
|
},
|
|
onSourceModifySpA: function (atk, attacker, defender, move) {
|
|
if (move.type === 'Ice' || move.type === 'Fire' || move.type === 'Fighting') {
|
|
this.add('-message', "The attack was weakened by Thick Fat!");
|
|
return this.chainModify(0.5);
|
|
}
|
|
}
|
|
},
|
|
"marvelscale": {
|
|
inherit: true,
|
|
onImmunity: function (type, pokemon) {
|
|
if (type === 'hail') return false;
|
|
}
|
|
},
|
|
"snowcloak": {
|
|
inherit: true,
|
|
onImmunity: function (type, pokemon) {
|
|
if (type === 'hail') return false;
|
|
},
|
|
onSourceBasePower: function (basePower) {
|
|
if (this.isWeather('hail')) {
|
|
return basePower * 3 / 4;
|
|
}
|
|
return basePower * 7 / 8;
|
|
},
|
|
onModifyAccuracy: function () {}
|
|
},
|
|
"sandveil": {
|
|
inherit: true,
|
|
onImmunity: function (type, pokemon) {
|
|
if (type === 'sandstorm') return false;
|
|
},
|
|
onSourceBasePower: function (basePower) {
|
|
if (this.isWeather('sandstorm')) {
|
|
return basePower * 4 / 5;
|
|
}
|
|
},
|
|
onModifyAccuracy: function () {}
|
|
},
|
|
"waterveil": {
|
|
inherit: true,
|
|
onSourceBasePower: function (basePower) {
|
|
if (this.isWeather(['raindance', 'primordialsea'])) {
|
|
return basePower * 3 / 4;
|
|
}
|
|
return basePower * 7 / 8;
|
|
}
|
|
},
|
|
"icebody": {
|
|
inherit: true,
|
|
onImmunity: function (type, pokemon) {
|
|
if (type === 'hail') return false;
|
|
},
|
|
onResidual: function (target, source, effect) {
|
|
this.heal(target.maxhp / 16);
|
|
},
|
|
onAfterDamage: function (damage, target, source, move) {
|
|
if (move && move.flags['contact'] && this.isWeather('hail')) {
|
|
if (this.random(10) < 3) {
|
|
source.trySetStatus('frz', target, move);
|
|
}
|
|
}
|
|
},
|
|
onWeather: function () {}
|
|
},
|
|
"flamebody": {
|
|
inherit: true,
|
|
onImmunity: function (type, pokemon) {
|
|
if (type === 'hail') return false;
|
|
}
|
|
},
|
|
"static": {
|
|
inherit: true,
|
|
onAfterDamage: function (damage, target, source, move) {
|
|
if (move && move.flags['contact']) {
|
|
source.trySetStatus('par', target, move);
|
|
}
|
|
}
|
|
},
|
|
"cutecharm": {
|
|
inherit: true,
|
|
onAfterDamage: function (damage, target, source, move) {
|
|
if (move && move.flags['contact']) {
|
|
source.addVolatile('Attract', target);
|
|
}
|
|
}
|
|
},
|
|
"poisonpoint": {
|
|
inherit: true,
|
|
onAfterDamage: function (damage, target, source, move) {
|
|
if (move && move.flags['contact']) {
|
|
source.trySetStatus('psn', target, move);
|
|
}
|
|
}
|
|
},
|
|
"flowergift": {
|
|
inherit: true,
|
|
onModifyMove: function (move) {
|
|
if (move.id === 'sunnyday') {
|
|
var weather = move.weather;
|
|
move.weather = null;
|
|
move.onHit = function (target, source) {
|
|
this.setWeather(weather, source, this.getAbility('flowergift'));
|
|
this.weatherData.duration = 0;
|
|
};
|
|
move.target = 'self';
|
|
move.sideCondition = 'flowergift';
|
|
}
|
|
},
|
|
onUpdate: function (pokemon) {
|
|
if (this.isWeather(['sunnyday', 'desolateland'])) {
|
|
if (pokemon.isActive && pokemon.speciesid === 'cherrim' && this.effectData.forme !== 'Sunshine') {
|
|
this.effectData.forme = 'Sunshine';
|
|
this.add('-formechange', pokemon, 'Cherrim-Sunshine', '[msg]');
|
|
this.boost({spd:1});
|
|
}
|
|
} else if (pokemon.isActive && pokemon.speciesid === 'cherrim' && this.effectData.forme) {
|
|
delete this.effectData.forme;
|
|
this.add('-formechange', pokemon, 'Cherrim', '[msg]');
|
|
}
|
|
},
|
|
effect: {
|
|
onSwitchInPriority: 1,
|
|
onSwitchIn: function (target) {
|
|
if (!target.fainted) {
|
|
this.boost({spd:1}, target, target, this.getAbility('flowergift'));
|
|
}
|
|
target.side.removeSideCondition('flowergift');
|
|
}
|
|
}
|
|
},
|
|
"slowstart": {
|
|
inherit: true,
|
|
effect: {
|
|
duration: 3,
|
|
onStart: function (target) {
|
|
this.add('-start', target, 'Slow Start');
|
|
},
|
|
onModifyAtk: function (atk, pokemon) {
|
|
if (pokemon.ability !== 'slowstart') {
|
|
pokemon.removeVolatile('slowstart');
|
|
return;
|
|
}
|
|
return atk / 2;
|
|
},
|
|
onModifySpe: function (spe, pokemon) {
|
|
if (pokemon.ability !== 'slowstart') {
|
|
pokemon.removeVolatile('slowstart');
|
|
return;
|
|
}
|
|
return spe / 2;
|
|
},
|
|
onEnd: function (target) {
|
|
this.add('-end', target, 'Slow Start');
|
|
}
|
|
}
|
|
},
|
|
"compoundeyes": {
|
|
desc: "The accuracy of this Pokemon's moves receives a 60% increase; for example, a 50% accurate move becomes 80% accurate.",
|
|
shortDesc: "This Pokemon's moves have their Accuracy boosted to 1.6x.",
|
|
onSourceModifyAccuracy: function (accuracy) {
|
|
if (typeof accuracy !== 'number') return;
|
|
this.debug('compoundeyes - enhancing accuracy');
|
|
return accuracy * 1.6;
|
|
},
|
|
id: "compoundeyes",
|
|
name: "Compound Eyes",
|
|
rating: 3.5,
|
|
num: 14
|
|
},
|
|
"keeneye": {
|
|
desc: "The accuracy of this Pokemon's moves receives a 60% increase; for example, a 50% accurate move becomes 80% accurate.",
|
|
shortDesc: "This Pokemon's moves have their Accuracy boosted to 1.6x.",
|
|
onModifyMove: function (move) {
|
|
if (typeof move.accuracy !== 'number') return;
|
|
this.debug('keeneye - enhancing accuracy');
|
|
move.accuracy *= 1.6;
|
|
},
|
|
id: "keeneye",
|
|
name: "Keen Eye",
|
|
rating: 3.5,
|
|
num: 51
|
|
},
|
|
"solidrock": {
|
|
inherit: true,
|
|
onSourceModifyDamage: function (damage, attacker, defender, move) {
|
|
if (move.typeMod > 0) {
|
|
this.add('-message', "The attack was weakened by Solid Rock!");
|
|
return this.chainModify(0.5);
|
|
}
|
|
}
|
|
},
|
|
"filter": {
|
|
inherit: true,
|
|
onSourceModifyDamage: function (damage, attacker, defender, move) {
|
|
if (move.typeMod > 0) {
|
|
this.add('-message', "The attack was weakened by Filter!");
|
|
return this.chainModify(0.5);
|
|
}
|
|
}
|
|
},
|
|
"heatproof": {
|
|
inherit: true,
|
|
onSourceBasePower: function (basePower, attacker, defender, move) {
|
|
if (move.type === 'Fire') {
|
|
this.add('-message', "The attack was weakened by Heatproof!");
|
|
return basePower / 2;
|
|
}
|
|
}
|
|
},
|
|
"reckless": {
|
|
inherit: true,
|
|
onBasePower: function (basePower, attacker, defender, move) {
|
|
if (move.recoil || move.hasCustomRecoil || attacker.item === 'lifeorb') {
|
|
this.debug('Reckless boost');
|
|
return basePower * 12 / 10;
|
|
}
|
|
}
|
|
},
|
|
"clearbody": {
|
|
inherit: true,
|
|
onBoost: function (boost, target, source) {
|
|
for (var i in boost) {
|
|
if (boost[i] < 0) {
|
|
delete boost[i];
|
|
this.add("-message", target.name + "'s stats were not lowered! (placeholder)");
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"whitesmoke": {
|
|
inherit: true,
|
|
onBoost: function (boost, target, source) {
|
|
for (var i in boost) {
|
|
if (boost[i] < 0) {
|
|
delete boost[i];
|
|
this.add("-message", target.name + "'s stats were not lowered! (placeholder)");
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"rockhead": {
|
|
inherit: true,
|
|
onDamage: function (damage, target, source, effect) {
|
|
if (effect && effect.id in {lifeorb: 1, recoil: 1}) return false;
|
|
}
|
|
},
|
|
"download": {
|
|
inherit: true,
|
|
onStart: function (pokemon) {
|
|
if (pokemon.template.baseSpecies === 'Genesect') {
|
|
if (!pokemon.getItem().onDrive) return;
|
|
}
|
|
var foeactive = pokemon.side.foe.active;
|
|
var totaldef = 0;
|
|
var totalspd = 0;
|
|
for (var i = 0; i < foeactive.length; i++) {
|
|
if (!foeactive[i] || foeactive[i].fainted) continue;
|
|
totaldef += foeactive[i].stats.def;
|
|
totalspd += foeactive[i].stats.spd;
|
|
}
|
|
if (totaldef && totaldef >= totalspd) {
|
|
this.boost({spa:1});
|
|
} else if (totalspd) {
|
|
this.boost({atk:1});
|
|
}
|
|
}
|
|
},
|
|
"victorystar": {
|
|
inherit: true,
|
|
onAllyModifyMove: function (move) {
|
|
if (typeof move.accuracy === 'number') {
|
|
move.accuracy *= 1.5;
|
|
}
|
|
}
|
|
},
|
|
"shellarmor": {
|
|
inherit: true,
|
|
onDamage: function (damage, target, source, effect) {
|
|
if (effect && effect.effectType === 'Move') {
|
|
this.add('-message', "Its damage was reduced by Shell Armor!");
|
|
damage -= target.maxhp / 10;
|
|
if (damage < 0) damage = 0;
|
|
return damage;
|
|
}
|
|
},
|
|
onHit: function (target, source, move) {
|
|
if (move.id === 'shellsmash') {
|
|
target.setAbility('');
|
|
}
|
|
}
|
|
},
|
|
"battlearmor": {
|
|
inherit: true,
|
|
onDamage: function (damage, target, source, effect) {
|
|
if (effect && effect.effectType === 'Move') {
|
|
this.add('-message', "Its damage was reduced by Battle Armor!");
|
|
damage -= target.maxhp / 10;
|
|
if (damage < 0) damage = 0;
|
|
return damage;
|
|
}
|
|
}
|
|
},
|
|
"weakarmor": {
|
|
onDamage: function (damage, target, source, effect) {
|
|
if (effect && effect.effectType === 'Move') {
|
|
this.add('-message', "Its damage was reduced by Weak Armor!");
|
|
damage -= target.maxhp / 10;
|
|
if (damage < 0) damage = 0;
|
|
target.setAbility('');
|
|
this.boost({spe: 1});
|
|
return damage;
|
|
}
|
|
},
|
|
onAfterDamage: function () {}
|
|
},
|
|
"magmaarmor": {
|
|
inherit: true,
|
|
onImmunity: function (type, pokemon) {
|
|
if (type === 'hail') return false;
|
|
if (type === 'frz') return false;
|
|
},
|
|
onDamage: function (damage, target, source, effect) {
|
|
if (effect && effect.effectType === 'Move') {
|
|
damage -= target.maxhp / 10;
|
|
if (damage < 0) damage = 0;
|
|
if (effect.type === 'Ice' || effect.type === 'Water') {
|
|
this.add('-activate', target, 'ability: Magma Armor');
|
|
target.setAbility('battlearmor');
|
|
damage = 0;
|
|
} else {
|
|
this.add('-message', "Its damage was reduced by Magma Armor!");
|
|
}
|
|
return damage;
|
|
}
|
|
}
|
|
},
|
|
"multiscale": {
|
|
inherit: true,
|
|
onSourceModifyDamage: function (damage, source, target, move) {
|
|
if (target.hp >= target.maxhp) {
|
|
this.add('-message', "The attack was slightly weakened by Multiscale!");
|
|
return this.chainModify(2 / 3);
|
|
}
|
|
}
|
|
},
|
|
"ironfist": {
|
|
inherit: true,
|
|
onBasePower: function (basePower, attacker, defender, move) {
|
|
if (move.flags['punch']) {
|
|
return basePower * 1.33;
|
|
}
|
|
}
|
|
},
|
|
"stench": {
|
|
inherit: true,
|
|
onModifyMove: function (move) {
|
|
if (move.category !== "Status") {
|
|
this.debug('Adding Stench flinch');
|
|
if (!move.secondaries) move.secondaries = [];
|
|
for (var i = 0; i < move.secondaries.length; i++) {
|
|
if (move.secondaries[i].volatileStatus === 'flinch') return;
|
|
}
|
|
move.secondaries.push({
|
|
chance: 40,
|
|
volatileStatus: 'flinch'
|
|
});
|
|
}
|
|
}
|
|
},
|
|
"aftermath": {
|
|
inherit: true,
|
|
onAfterDamage: function (damage, target, source, move) {
|
|
if (source && source !== target && move && !target.hp) {
|
|
this.damage(source.maxhp / 3, source, target, null, true);
|
|
}
|
|
}
|
|
},
|
|
"cursedbody": {
|
|
desc: "When this Pokemon faints, attacker is Cursed.",
|
|
shortDesc: "When this Pokemon faints, attacker is Cursed.",
|
|
onFaint: function (target, source, effect) {
|
|
if (effect && effect.effectType === 'Move' && source) {
|
|
source.addVolatile('curse');
|
|
}
|
|
},
|
|
id: "cursedbody",
|
|
name: "Cursed Body",
|
|
rating: 3,
|
|
num: 130
|
|
},
|
|
"gluttony": {
|
|
inherit: true,
|
|
onResidualOrder: 26,
|
|
onResidualSubOrder: 1,
|
|
onResidual: function (pokemon) {
|
|
if (!pokemon.gluttonyFlag && !pokemon.item && this.getItem(pokemon.lastItem).isBerry) {
|
|
pokemon.gluttonyFlag = true;
|
|
pokemon.setItem(pokemon.lastItem);
|
|
this.add("-item", pokemon, pokemon.item, '[from] ability: Gluttony');
|
|
}
|
|
}
|
|
},
|
|
"guts": {
|
|
inherit: true,
|
|
onDamage: function (damage, attacker, defender, effect) {
|
|
if (effect && (effect.id === 'brn' || effect.id === 'psn' || effect.id === 'tox')) {
|
|
return damage / 2;
|
|
}
|
|
}
|
|
},
|
|
"quickfeet": {
|
|
inherit: true,
|
|
onDamage: function (damage, attacker, defender, effect) {
|
|
if (effect && (effect.id === 'brn' || effect.id === 'psn' || effect.id === 'tox')) {
|
|
return damage / 2;
|
|
}
|
|
}
|
|
},
|
|
"toxicboost": {
|
|
inherit: true,
|
|
onDamage: function (damage, attacker, defender, effect) {
|
|
if (effect && (effect.id === 'psn' || effect.id === 'tox')) {
|
|
return damage / 2;
|
|
}
|
|
}
|
|
},
|
|
"truant": {
|
|
onModifyMove: function (move, pokemon) {
|
|
if (!move.self) move.self = {};
|
|
if (!move.self.volatileStatus) move.self.volatileStatus = 'truant';
|
|
},
|
|
effect: {
|
|
duration: 2,
|
|
onStart: function (pokemon) {
|
|
this.add('-start', pokemon, 'Truant');
|
|
},
|
|
onBeforeMovePriority: 99,
|
|
onBeforeMove: function (pokemon, target, move) {
|
|
if (pokemon.removeVolatile('truant')) {
|
|
this.add('cant', pokemon, 'ability: Truant');
|
|
this.heal(pokemon.maxhp / 3);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"flareboost": {
|
|
inherit: true,
|
|
onDamage: function (damage, defender, attacker, effect) {
|
|
if (effect && (effect.id === 'brn')) {
|
|
return damage / 2;
|
|
}
|
|
}
|
|
},
|
|
"telepathy": {
|
|
inherit: true,
|
|
onStart: function (target) {
|
|
this.add('-start', target, 'move: Imprison');
|
|
},
|
|
onFoeDisableMove: function (pokemon) {
|
|
var foeMoves = this.effectData.target.moveset;
|
|
for (var f = 0; f < foeMoves.length; f++) {
|
|
pokemon.disableMove(foeMoves[f].id, true);
|
|
}
|
|
pokemon.maybeDisabled = true;
|
|
},
|
|
onFoeBeforeMove: function (attacker, defender, move) {
|
|
if (attacker.disabledMoves[move.id]) {
|
|
this.add('cant', attacker, 'move: Imprison', move);
|
|
return false;
|
|
}
|
|
}
|
|
},
|
|
"speedboost": {
|
|
inherit: true,
|
|
onResidualPriority: -1,
|
|
onResidual: function (pokemon) {
|
|
if (pokemon.activeTurns && !pokemon.volatiles.stall) {
|
|
this.boost({spe:1});
|
|
}
|
|
}
|
|
},
|
|
"parentalbond": {
|
|
inherit: true,
|
|
onModifyMove: function (move, pokemon, target) {
|
|
if (move.category !== 'Status' && !move.selfdestruct && !move.multihit && ((target.side && target.side.active.length < 2) || move.target in {any:1, normal:1, randomNormal:1})) {
|
|
move.multihit = 2;
|
|
move.accuracy = true;
|
|
pokemon.addVolatile('parentalbond');
|
|
}
|
|
},
|
|
effect: {
|
|
duration: 1,
|
|
onBasePowerPriority: 8,
|
|
onBasePower: function (basePower) {
|
|
return this.chainModify(0.5);
|
|
}
|
|
}
|
|
},
|
|
"adaptability": {
|
|
inherit: true,
|
|
onModifyMove: function (move) {},
|
|
onBasePower: function (power, attacker, defender, move) {
|
|
if (!attacker.hasType(move.type)) {
|
|
return this.chainModify(1.33);
|
|
}
|
|
}
|
|
},
|
|
"shadowtag": {
|
|
onStart: function (pokemon) {
|
|
pokemon.addVolatile('shadowtag');
|
|
},
|
|
effect: {
|
|
duration: 2,
|
|
onFoeModifyPokemon: function (pokemon) {
|
|
if (pokemon.ability !== 'shadowtag') {
|
|
pokemon.tryTrap(true);
|
|
}
|
|
}
|
|
},
|
|
onBeforeMovePriority: 15,
|
|
onBeforeMove: function (pokemon) {
|
|
pokemon.removeVolatile('shadowtag');
|
|
},
|
|
onFoeMaybeTrapPokemon: function (pokemon, source) {
|
|
if (!source) source = this.effectData.target;
|
|
if (pokemon.ability !== 'shadowtag' && !source.volatiles.shadowtag) {
|
|
pokemon.maybeTrapped = true;
|
|
}
|
|
}
|
|
},
|
|
"justified": {
|
|
inherit: true,
|
|
onBasePowerPriority: 100,
|
|
onBasePower: function (power, attacker, defender) {
|
|
if (power > 100 && !defender.hasType('Dark')) {
|
|
this.debug('capping base power at 100');
|
|
return 100;
|
|
}
|
|
}
|
|
}
|
|
};
|