pokemon-showdown/mods/gennext/abilities.js
Kevin Lau 17724c59f0 Un-hardcode Rock Head in favor of an onDamage handler
Instead of having a hardcode in scripts.js that people needed to
reference, it seemed more intuitive to take advantage of the Damage
event instead, and have Rock Head negate damage within the event.

Fixed a bug in Gen-NEXT Rock Head exhibiting the same behavior that
was causing the original Rock Head + Mummy glitch.
2015-05-21 13:52:02 -07:00

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;
},
onAccuracy: function () {}
},
"sandveil": {
inherit: true,
onImmunity: function (type, pokemon) {
if (type === 'sandstorm') return false;
},
onSourceBasePower: function (basePower) {
if (this.isWeather('sandstorm')) {
return basePower * 4 / 5;
}
},
onAccuracy: 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.",
onSourceAccuracy: 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;
}
}
}
};