Fix bugs with secondary/ability order

Fixes #6346

The `AfterDamage` event has been replaced with `DamagingHit`, which
which happens for damaging moves after secondaries.

The `AfterHit` event has also been moved after `DamagingHit`, to make
sure Knock Off still procs after Rocky Helmet.

`AfterHit` is no longer a valid event on `secondary` and `self` blocks,
because it's meaningless in those blocks, anyway. All `self.onAfterHit`
and `secondary.onAfterHit` handlers have been moved to `onHit`, which
should have the same timing in practice.
This commit is contained in:
Guangcong Luo 2020-02-07 10:57:28 -08:00
parent 1f8b14cb6c
commit 55cbc52bba
17 changed files with 176 additions and 210 deletions

View File

@ -79,9 +79,9 @@ let BattleAbilities = {
shortDesc: "If this Pokemon is KOed with a contact move, that move's user loses 1/4 its max HP.",
id: "aftermath",
name: "Aftermath",
onAfterDamageOrder: 1,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.flags['contact'] && !target.hp) {
onDamagingHitOrder: 1,
onDamagingHit(damage, target, source, move) {
if (move.flags['contact'] && !target.hp) {
this.damage(source.baseMaxhp / 4, source, target);
}
},
@ -531,13 +531,11 @@ let BattleAbilities = {
"cottondown": {
desc: "When the Pokémon is hit by an attack, it scatters cotton fluff around and lowers the Speed stat of all Pokémon except itself.",
shortDesc: "Lowers Speed of all Pokémon except itself when hit by an attack.",
onAfterDamage(damage, target, source, effect) {
if (effect && effect.effectType === 'Move' && effect.id !== 'confused') {
this.add('-ability', target, 'Cotton Down');
for (let pokemon of this.getAllActive()) {
if (pokemon === target) continue;
this.boost({spe: -1}, pokemon, target, null, true);
}
onDamagingHit(damage, target, source, move) {
this.add('-ability', target, 'Cotton Down');
for (let pokemon of this.getAllActive()) {
if (pokemon === target) continue;
this.boost({spe: -1}, pokemon, target, null, true);
}
},
id: "cottondown",
@ -548,9 +546,9 @@ let BattleAbilities = {
"cursedbody": {
desc: "If this Pokemon is hit by an attack, there is a 30% chance that move gets disabled unless one of the attacker's moves is already disabled.",
shortDesc: "If this Pokemon is hit by an attack, there is a 30% chance that move gets disabled.",
onAfterDamage(damage, target, source, move) {
if (!source || source.volatiles['disable']) return;
if (source !== target && move && move.effectType === 'Move' && !move.isFutureMove) {
onDamagingHit(damage, target, source, move) {
if (source.volatiles['disable']) return;
if (!move.isFutureMove) {
if (this.randomChance(3, 10)) {
source.addVolatile('disable', this.effectData.target);
}
@ -564,8 +562,8 @@ let BattleAbilities = {
"cutecharm": {
desc: "There is a 30% chance a Pokemon making contact with this Pokemon will become infatuated if it is of the opposite gender.",
shortDesc: "30% chance of infatuating Pokemon of the opposite gender if they make contact.",
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
if (this.randomChance(3, 10)) {
source.addVolatile('attract', this.effectData.target);
}
@ -863,8 +861,8 @@ let BattleAbilities = {
"effectspore": {
desc: "30% chance a Pokemon making contact with this Pokemon will be poisoned, paralyzed, or fall asleep.",
shortDesc: "30% chance of poison/paralysis/sleep on others making contact with this Pokemon.",
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact'] && !source.status && source.runStatusImmunity('powder')) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact'] && !source.status && source.runStatusImmunity('powder')) {
let r = this.random(100);
if (r < 11) {
source.setStatus('slp', target);
@ -905,14 +903,6 @@ let BattleAbilities = {
this.add('-activate', target, 'ability: Emergency Exit');
}
},
onAfterDamage(damage, target, source, effect) {
if (!target.hp || effect.effectType === 'Move') return;
if (target.hp <= target.maxhp / 2 && target.hp + damage > target.maxhp / 2) {
if (!this.canSwitch(target.side) || target.forceSwitchFlag || target.switchFlag) return;
target.switchFlag = true;
this.add('-activate', target, 'ability: Emergency Exit');
}
},
id: "emergencyexit",
name: "Emergency Exit",
rating: 1,
@ -951,8 +941,8 @@ let BattleAbilities = {
},
"flamebody": {
shortDesc: "30% chance a Pokemon making contact with this Pokemon will be burned.",
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
if (this.randomChance(3, 10)) {
source.trySetStatus('brn', target);
}
@ -1275,8 +1265,8 @@ let BattleAbilities = {
},
"gooey": {
shortDesc: "Pokemon making contact with this Pokemon have their Speed lowered by 1 stage.",
onAfterDamage(damage, target, source, effect) {
if (effect && effect.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
this.add('-ability', target, 'Gooey');
this.boost({spe: -1}, source, target, null, true);
}
@ -1354,15 +1344,15 @@ let BattleAbilities = {
"gulpmissile": {
desc: "If this Pokemon is a Cramorant, it changes forme when it hits a target with Surf or uses the first turn of Dive successfully. It becomes Gulping Form with an Arrokuda in its mouth if it has more than 1/2 of its maximum HP remaining, or Gorging Form with a Pikachu in its mouth if it has 1/2 or less of its maximum HP remaining. If Cramorant gets hit in Gulping or Gorging Form, it spits the Arrokuda or Pikachu at its attacker, even if it has no HP remaining. The projectile deals damage equal to 1/4 of the target's maximum HP, rounded down; this damage is blocked by the Magic Guard Ability but not by a substitute. An Arrokuda also lowers the target's Defense by 1 stage, and a Pikachu paralyzes the target. Cramorant will return to normal if it spits out a projectile, switches out, or Dynamaxes.",
shortDesc: "When hit after Surf/Dive, attacker takes 1/4 max HP and -1 Defense or paralysis.",
onAfterDamage(damage, target, source, effect) {
if (effect && effect.effectType === 'Move' && effect.id !== 'confused' && ['cramorantgulping', 'cramorantgorging'].includes(target.template.speciesid) && !target.transformed && !target.isSemiInvulnerable()) {
onDamagingHit(damage, target, source, move) {
if (move.effectType === 'Move' && ['cramorantgulping', 'cramorantgorging'].includes(target.template.speciesid) && !target.transformed && !target.isSemiInvulnerable()) {
this.damage(source.baseMaxhp / 4, source, target);
if (target.template.speciesid === 'cramorantgulping') {
this.boost({def: -1}, source, target, null, true);
} else {
source.trySetStatus('par', target, effect);
source.trySetStatus('par', target, move);
}
target.formeChange('cramorant', effect);
target.formeChange('cramorant', move);
}
},
// The Dive part of this mechanic is implemented in Dive's `onTryMove` in moves.js
@ -1641,9 +1631,9 @@ let BattleAbilities = {
if (pokemon === pokemon.side.pokemon[i]) return;
pokemon.illusion = pokemon.side.pokemon[i];
},
onAfterDamage(damage, target, source, effect) {
if (target.illusion && effect && effect.effectType === 'Move' && effect.id !== 'confused') {
this.singleEvent('End', this.dex.getAbility('Illusion'), target.abilityData, target, source, effect);
onDamagingHit(damage, target, source, move) {
if (target.illusion) {
this.singleEvent('End', this.dex.getAbility('Illusion'), target.abilityData, target, source, move);
}
},
onEnd(pokemon) {
@ -1714,9 +1704,9 @@ let BattleAbilities = {
shortDesc: "If this Pokemon is KOed with a move, that move's user loses an equal amount of HP.",
id: "innardsout",
name: "Innards Out",
onAfterDamageOrder: 1,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.effectType === 'Move' && !target.hp) {
onDamagingHitOrder: 1,
onDamagingHit(damage, target, source, move) {
if (!target.hp) {
this.damage(target.getUndynamaxedHP(damage), source, target);
}
},
@ -1790,9 +1780,9 @@ let BattleAbilities = {
"ironbarbs": {
desc: "Pokemon making contact with this Pokemon lose 1/8 of their maximum HP, rounded down.",
shortDesc: "Pokemon making contact with this Pokemon lose 1/8 of their max HP.",
onAfterDamageOrder: 1,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.flags['contact']) {
onDamagingHitOrder: 1,
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
this.damage(source.baseMaxhp / 8, source, target);
}
},
@ -1818,8 +1808,8 @@ let BattleAbilities = {
},
"justified": {
shortDesc: "This Pokemon's Attack is raised by 1 stage after it is damaged by a Dark-type move.",
onAfterDamage(damage, target, source, effect) {
if (effect && effect.type === 'Dark') {
onDamagingHit(damage, target, source, move) {
if (move.type === 'Dark') {
this.boost({atk: 1});
}
},
@ -2352,8 +2342,8 @@ let BattleAbilities = {
shortDesc: "Pokemon making contact with this Pokemon have their Ability changed to Mummy.",
id: "mummy",
name: "Mummy",
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.flags['contact'] && source.ability !== 'mummy') {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact'] && source.ability !== 'mummy') {
let oldAbility = source.setAbility('mummy', target);
if (oldAbility) {
this.add('-activate', target, 'ability: Mummy', this.dex.getAbility(oldAbility).name, '[of] ' + source);
@ -2670,7 +2660,7 @@ let BattleAbilities = {
"perishbody": {
desc: "When hit by a move that makes direct contact, the Pokémon and the attacker will faint after three turns unless they switch out of battle.",
shortDesc: "When hit by a contact move, the Pokémon and the attacker faint in 3 turns.",
onAfterDamage(damage, target, source, move) {
onDamagingHit(damage, target, source, move) {
if (!move.flags['contact']) return;
let announced = false;
@ -2792,8 +2782,8 @@ let BattleAbilities = {
},
"poisonpoint": {
shortDesc: "30% chance a Pokemon making contact with this Pokemon will be poisoned.",
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
if (this.randomChance(3, 10)) {
source.trySetStatus('psn', target);
}
@ -3056,8 +3046,8 @@ let BattleAbilities = {
"rattled": {
desc: "This Pokemon's Speed is raised by 1 stage if hit by a Bug-, Dark-, or Ghost-type attack, or Intimidate.",
shortDesc: "Speed is raised 1 stage if hit by a Bug-, Dark-, or Ghost-type attack, or Intimidated.",
onAfterDamage(damage, target, source, effect) {
if (effect && (effect.type === 'Dark' || effect.type === 'Bug' || effect.type === 'Ghost')) {
onDamagingHit(damage, target, source, move) {
if (['Dark', 'Bug', 'Ghost'].includes(move.type)) {
this.boost({spe: 1});
}
},
@ -3215,9 +3205,9 @@ let BattleAbilities = {
"roughskin": {
desc: "Pokemon making contact with this Pokemon lose 1/8 of their maximum HP, rounded down.",
shortDesc: "Pokemon making contact with this Pokemon lose 1/8 of their max HP.",
onAfterDamageOrder: 1,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.flags['contact']) {
onDamagingHitOrder: 1,
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
this.damage(source.baseMaxhp / 8, source, target);
}
},
@ -3271,8 +3261,8 @@ let BattleAbilities = {
},
"sandspit": {
shortDesc: "The Pokémon creates a sandstorm when it's hit by an attack.",
onAfterDamage(damage, target, source, effect) {
if (effect && effect.effectType === 'Move' && effect.id !== 'confused' && this.field.getWeather().id !== 'sandstorm') {
onDamagingHit(damage, target, source, move) {
if (this.field.getWeather().id !== 'sandstorm') {
this.field.setWeather('sandstorm');
}
},
@ -3798,10 +3788,8 @@ let BattleAbilities = {
},
"stamina": {
shortDesc: "This Pokemon's Defense is raised by 1 stage after it is damaged by a move.",
onAfterDamage(damage, target, source, effect) {
if (effect && effect.effectType === 'Move' && effect.id !== 'confused') {
this.boost({def: 1});
}
onDamagingHit(damage, target, source, effect) {
this.boost({def: 1});
},
id: "stamina",
name: "Stamina",
@ -3825,8 +3813,8 @@ let BattleAbilities = {
},
"static": {
shortDesc: "30% chance a Pokemon making contact with this Pokemon will be paralyzed.",
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
if (this.randomChance(3, 10)) {
source.trySetStatus('par', target);
}
@ -3849,8 +3837,8 @@ let BattleAbilities = {
},
"steamengine": {
shortDesc: "This Pokemon's Speed is raised by 6 stages after it is damaged by Fire/Water moves.",
onAfterDamage(damage, target, source, effect) {
if (effect && ['Water', 'Fire'].includes(effect.type)) {
onDamagingHit(damage, target, source, move) {
if (['Water', 'Fire'].includes(move.type)) {
this.boost({spe: 6});
}
},
@ -4133,8 +4121,8 @@ let BattleAbilities = {
},
"tanglinghair": {
shortDesc: "Pokemon making contact with this Pokemon have their Speed lowered by 1 stage.",
onAfterDamage(damage, target, source, effect) {
if (effect && effect.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
this.add('-ability', target, 'Tangling Hair');
this.boost({spe: -1}, source, target, null, true);
}
@ -4455,10 +4443,10 @@ let BattleAbilities = {
"wanderingspirit": {
desc: "The Pokémon exchanges Abilities with a Pokémon that hits it with a move that makes direct contact.",
shortDesc: "Exchanges abilities when hit with a contact move.",
onAfterDamage(damage, target, source, effect) {
if (!source || source.ability === 'wanderingspirit') return;
onDamagingHit(damage, target, source, move) {
if (source.ability === 'wanderingspirit') return;
if (target.volatiles['dynamax'] || target.ability === 'illusion' || target.ability === 'wonderguard') return;
if (effect && effect.effectType === 'Move' && effect.flags['contact']) {
if (move.flags['contact']) {
let sourceAbility = source.setAbility('wanderingspirit', target);
if (!sourceAbility) return;
if (target.side === source.side) {
@ -4534,8 +4522,8 @@ let BattleAbilities = {
},
"watercompaction": {
shortDesc: "This Pokemon's Defense is raised 2 stages after it is damaged by a Water-type move.",
onAfterDamage(damage, target, source, effect) {
if (effect && effect.type === 'Water') {
onDamagingHit(damage, target, source, move) {
if (move.type === 'Water') {
this.boost({def: 2});
}
},
@ -4566,7 +4554,7 @@ let BattleAbilities = {
"weakarmor": {
desc: "If a physical attack hits this Pokemon, its Defense is lowered by 1 stage and its Speed is raised by 2 stages.",
shortDesc: "If a physical attack hits this Pokemon, Defense is lowered by 1, Speed is raised by 2.",
onAfterDamage(damage, target, source, move) {
onDamagingHit(damage, target, source, move) {
if (move.category === 'Physical') {
this.boost({def: -1, spe: 2}, target, target);
}
@ -4613,14 +4601,6 @@ let BattleAbilities = {
this.add('-activate', target, 'ability: Wimp Out');
}
},
onAfterDamage(damage, target, source, effect) {
if (!target.hp || effect.effectType === 'Move') return;
if (target.hp <= target.maxhp / 2 && target.hp + damage > target.maxhp / 2) {
if (!this.canSwitch(target.side) || target.forceSwitchFlag || target.switchFlag) return;
target.switchFlag = true;
this.add('-activate', target, 'ability: Wimp Out');
}
},
id: "wimpout",
name: "Wimp Out",
rating: 1,

View File

@ -41,7 +41,7 @@ let BattleItems = {
fling: {
basePower: 30,
},
onAfterDamage(damage, target, source, move) {
onDamagingHit(damage, target, source, move) {
if (move.type === 'Water') {
target.useItem();
}
@ -162,18 +162,15 @@ let BattleItems = {
}
},
// airborneness implemented in sim/pokemon.js:Pokemon#isGrounded
onAfterDamage(damage, target, source, effect) {
this.debug('effect: ' + effect.id);
if (effect.effectType === 'Move' && effect.id !== 'confused') {
this.add('-enditem', target, 'Air Balloon');
target.item = '';
target.itemData = {id: '', target};
this.runEvent('AfterUseItem', target, null, null, this.dex.getItem('airballoon'));
}
onDamagingHit(damage, target, source, move) {
this.add('-enditem', target, 'Air Balloon');
target.item = '';
target.itemData = {id: '', target};
this.runEvent('AfterUseItem', target, null, null, this.dex.getItem('airballoon'));
},
onAfterSubDamage(damage, target, source, effect) {
this.debug('effect: ' + effect.id);
if (effect.effectType === 'Move' && effect.id !== 'confused') {
if (effect.effectType === 'Move') {
this.add('-enditem', target, 'Air Balloon');
target.item = '';
target.itemData = {id: '', target};
@ -736,7 +733,7 @@ let BattleItems = {
fling: {
basePower: 30,
},
onAfterDamage(damage, target, source, move) {
onDamagingHit(damage, target, source, move) {
if (move.type === 'Electric') {
target.useItem();
}
@ -2900,8 +2897,8 @@ let BattleItems = {
basePower: 100,
type: "Dragon",
},
onAfterDamage(damage, target, source, move) {
if (source && source.hp && source !== target && move && move.category === 'Physical') {
onDamagingHit(damage, target, source, move) {
if (move.category === 'Physical') {
if (target.eatItem()) {
this.damage(source.baseMaxhp / 8, source, target);
}
@ -3404,7 +3401,7 @@ let BattleItems = {
fling: {
basePower: 30,
},
onAfterDamage(damage, target, source, move) {
onDamagingHit(damage, target, source, move) {
if (move.type === 'Water') {
target.useItem();
}
@ -5151,9 +5148,9 @@ let BattleItems = {
fling: {
basePower: 60,
},
onAfterDamageOrder: 2,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.flags['contact']) {
onDamagingHitOrder: 2,
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
this.damage(source.baseMaxhp / 6, source, target);
}
},
@ -5242,8 +5239,8 @@ let BattleItems = {
basePower: 100,
type: "Dark",
},
onAfterDamage(damage, target, source, move) {
if (source && source.hp && source !== target && move && move.category === 'Special') {
onDamagingHit(damage, target, source, move) {
if (move.category === 'Special') {
if (target.eatItem()) {
this.damage(source.baseMaxhp / 8, source, target);
}
@ -5711,7 +5708,7 @@ let BattleItems = {
fling: {
basePower: 30,
},
onAfterDamage(damage, target, source, move) {
onDamagingHit(damage, target, source, move) {
if (move.type === 'Ice') {
target.useItem();
}

View File

@ -956,7 +956,7 @@ let BattleMovedex = {
onAfterHit() {},
secondary: {
chance: 100,
onAfterHit(target, source) {
onHit(target, source) {
if (source.item || source.volatiles['gem']) {
return;
}

View File

@ -6,8 +6,8 @@ let BattleAbilities = {
inherit: true,
desc: "There is a 1/3 chance a Pokemon making contact with this Pokemon will become infatuated if it is of the opposite gender.",
shortDesc: "1/3 chance of infatuating Pokemon of the opposite gender if they make contact.",
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
if (this.randomChance(1, 3)) {
source.addVolatile('attract', target);
}
@ -18,8 +18,8 @@ let BattleAbilities = {
inherit: true,
desc: "10% chance a Pokemon making contact with this Pokemon will be poisoned, paralyzed, or fall asleep.",
shortDesc: "10% chance of poison/paralysis/sleep on others making contact with this Pokemon.",
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact'] && !source.status) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact'] && !source.status) {
let r = this.random(300);
if (r < 10) {
source.setStatus('slp', target);
@ -34,8 +34,8 @@ let BattleAbilities = {
"flamebody": {
inherit: true,
shortDesc: "1/3 chance a Pokemon making contact with this Pokemon will be burned.",
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
if (this.randomChance(1, 3)) {
source.trySetStatus('brn', target);
}
@ -129,8 +129,8 @@ let BattleAbilities = {
"poisonpoint": {
inherit: true,
shortDesc: "1/3 chance a Pokemon making contact with this Pokemon will be poisoned.",
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
if (this.randomChance(1, 3)) {
source.trySetStatus('psn', target);
}
@ -147,8 +147,8 @@ let BattleAbilities = {
inherit: true,
desc: "Pokemon making contact with this Pokemon lose 1/16 of their maximum HP, rounded down.",
shortDesc: "Pokemon making contact with this Pokemon lose 1/16 of their max HP.",
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
this.damage(source.baseMaxhp / 16, source, target);
}
},
@ -164,8 +164,8 @@ let BattleAbilities = {
"static": {
inherit: true,
shortDesc: "1/3 chance a Pokemon making contact with this Pokemon will be paralyzed.",
onAfterDamage(damage, target, source, effect) {
if (effect && effect.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
if (this.randomChance(1, 3)) {
source.trySetStatus('par', target);
}

View File

@ -33,10 +33,10 @@ let BattleAbilities = {
"colorchange": {
inherit: true,
desc: "This Pokemon's type changes to match the type of the last move that hit it, unless that type is already one of its types. This effect applies after each hit from a multi-hit move.",
onAfterDamage(damage, target, source, move) {
onDamagingHit(damage, target, source, move) {
if (!target.hp) return;
let type = move.type;
if (target.isActive && move.effectType === 'Move' && move.category !== 'Status' && type !== '???' && !target.hasType(type)) {
if (target.isActive && move.category !== 'Status' && type !== '???' && !target.hasType(type)) {
if (!target.setType(type)) return false;
this.add('-start', target, 'typechange', type, '[from] ability: Color Change');
}
@ -45,8 +45,8 @@ let BattleAbilities = {
},
"effectspore": {
inherit: true,
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact'] && !source.status) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact'] && !source.status) {
let r = this.random(100);
if (r < 10) {
source.setStatus('slp', target);

View File

@ -125,17 +125,6 @@ let BattleItems = {
onEffectiveness() {},
desc: "Holder's Speed is halved and it becomes grounded.",
},
"jabocaberry": {
inherit: true,
onAfterDamage() {},
onAfterMoveSecondary(target, source, move) {
if (source && source !== target && move && move.category === 'Physical') {
if (target.eatItem()) {
this.damage(source.baseMaxhp / 8, source, target, null, true);
}
}
},
},
"kingsrock": {
inherit: true,
onModifyMove(move) {
@ -258,17 +247,6 @@ let BattleItems = {
}
},
},
"rowapberry": {
inherit: true,
onAfterDamage() {},
onAfterMoveSecondary(target, source, move) {
if (source && source !== target && move && move.category === 'Special') {
if (target.eatItem()) {
this.damage(source.baseMaxhp / 8, source, target, null, true);
}
}
},
},
"stick": {
inherit: true,
onModifyCritRatio(critRatio, user) {

View File

@ -13,8 +13,8 @@ let BattleAbilities = {
},
"aftermath": {
inherit: true,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.flags['contact'] && !target.hp) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact'] && !target.hp) {
this.damage(source.baseMaxhp / 4, source, target, null, true);
}
},
@ -47,8 +47,8 @@ let BattleAbilities = {
},
"ironbarbs": {
inherit: true,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
this.damage(source.baseMaxhp / 8, source, target, null, true);
}
},
@ -124,8 +124,8 @@ let BattleAbilities = {
},
"roughskin": {
inherit: true,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
this.damage(source.baseMaxhp / 8, source, target, null, true);
}
},
@ -142,7 +142,7 @@ let BattleAbilities = {
inherit: true,
desc: "If a physical attack hits this Pokemon, its Defense is lowered by 1 stage and its Speed is raised by 1 stage.",
shortDesc: "If a physical attack hits this Pokemon, Defense is lowered by 1, Speed is raised by 1.",
onAfterDamage(damage, target, source, move) {
onDamagingHit(damage, target, source, move) {
if (move.category === 'Physical') {
this.boost({def: -1, spe: 1}, target, target);
}

View File

@ -76,8 +76,8 @@ let BattleItems = {
},
jabocaberry: {
inherit: true,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.category === 'Physical') {
onDamagingHit(damage, target, source, move) {
if (move.category === 'Physical') {
if (target.eatItem()) {
this.damage(source.baseMaxhp / 8, source, target, null, true);
}
@ -145,16 +145,16 @@ let BattleItems = {
},
rockyhelmet: {
inherit: true,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
this.damage(source.baseMaxhp / 6, source, target, null, true);
}
},
},
rowapberry: {
inherit: true,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.category === 'Special') {
onDamagingHit(damage, target, source, move) {
if (move.category === 'Special') {
if (target.eatItem()) {
this.damage(source.baseMaxhp / 8, source, target, null, true);
}

View File

@ -110,8 +110,8 @@ let BattleAbilities = {
"rattled": {
desc: "This Pokemon's Speed is raised by 1 stage if hit by a Bug-, Dark-, or Ghost-type attack.",
shortDesc: "This Pokemon's Speed is raised 1 stage if hit by a Bug-, Dark-, or Ghost-type attack.",
onAfterDamage(damage, target, source, effect) {
if (effect && (effect.type === 'Dark' || effect.type === 'Bug' || effect.type === 'Ghost')) {
onDamagingHit(damage, target, source, move) {
if (['Dark', 'Bug', 'Ghost'].includes(move.type)) {
this.boost({spe: 1});
}
},

View File

@ -123,8 +123,8 @@ let BattleAbilities = {
onResidual(target, source, effect) {
this.heal(target.baseMaxhp / 16);
},
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact'] && this.field.isWeather('hail')) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact'] && this.field.isWeather('hail')) {
if (this.randomChance(3, 10)) {
source.trySetStatus('frz', target);
}
@ -141,8 +141,8 @@ let BattleAbilities = {
},
"static": {
inherit: true,
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
source.trySetStatus('par', target);
}
},
@ -150,8 +150,8 @@ let BattleAbilities = {
},
"cutecharm": {
inherit: true,
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
source.addVolatile('Attract', target);
}
},
@ -160,8 +160,8 @@ let BattleAbilities = {
},
"poisonpoint": {
inherit: true,
onAfterDamage(damage, target, source, move) {
if (move && move.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
source.trySetStatus('psn', target);
}
},
@ -416,7 +416,7 @@ let BattleAbilities = {
return damage;
}
},
onAfterDamage() {},
onDamagingHit() {},
desc: "This ability reduces incoming move damage by 1/10 of the user's max HP and increases the user's Speed for the first hit after switch-in (and does not activate again until the next switch-in).",
shortDesc: "Reduces incoming move damage by 1/10 of the user's max HP and increases the user's Spe for the 1st hit after switch-in (doesn't activate until next switch-in).",
},
@ -482,8 +482,8 @@ let BattleAbilities = {
},
"aftermath": {
inherit: true,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && !target.hp) {
onDamagingHit(damage, target, source, move) {
if (!target.hp) {
this.damage(source.baseMaxhp / 3, source, target, null, true);
}
},

View File

@ -278,9 +278,8 @@ let BattleAbilities = {
if ((target === source || move.category === 'Status') && target.template.speciesid !== 'shayminsky' && target.transformed) return;
target.formeChange('Shaymin', this.effect);
},
onAfterDamage(damage, target, source, effect) {
if (source === target) return;
if (target && target.template.speciesid === 'shaymin') {
onDamagingHit(damage, target, source, move) {
if (target.template.speciesid === 'shaymin') {
target.formeChange('Shaymin-Sky', this.effect);
}
},
@ -333,9 +332,9 @@ let BattleAbilities = {
pokemon.maybeTrapped = true;
}
},
onAfterDamageOrder: 1,
onAfterDamage(damage, target, source, move) {
if (source && source !== target && move && move.effectType === 'Move' && !target.hp) {
onDamagingHitOrder: 1,
onDamagingHit(damage, target, source, move) {
if (!target.hp) {
this.damage(damage, source, target);
}
},
@ -407,8 +406,8 @@ let BattleAbilities = {
giblovepls: {
desc: "After being damaged by a contact move, this Pokemon is healed by 20% of its maximum HP and has its Defense raised by one stage.",
shortDesc: "Defense +1 and heal 20% after hit by contact move.",
onAfterDamage(damage, target, source, effect) {
if (effect && effect.flags['contact']) {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
this.boost({def: 1}, target);
this.heal(target.baseMaxhp / 5, target);
}
@ -452,10 +451,10 @@ let BattleAbilities = {
if (pokemon === pokemon.side.pokemon[i]) return;
pokemon.illusion = pokemon.side.pokemon[i];
},
onAfterDamage(damage, target, source, effect) {
onDamagingHit(damage, target, source, move) {
// Illusion that only breaks when hit with a move that is super effective VS dark
if (target.illusion && effect && effect.effectType === 'Move' && effect.id !== 'confused' && this.dex.getEffectiveness(effect.type, target.getTypes()) > 0) {
this.singleEvent('End', this.dex.getAbility('Illusion'), target.abilityData, target, source, effect);
if (target.illusion && this.dex.getEffectiveness(move.type, target.getTypes()) > 0) {
this.singleEvent('End', this.dex.getAbility('Illusion'), target.abilityData, target, source, move);
}
},
onEnd(pokemon) {
@ -632,8 +631,8 @@ let BattleAbilities = {
return this.chainModify([0x1333, 0x1000]);
}
},
onAfterDamage(damage, target, source, effect) {
if (effect && effect.effectType === 'Move' && effect.flags.contact && effect.id !== 'confused') {
onDamagingHit(damage, target, source, move) {
if (move.flags['contact']) {
this.boost({spe: 1});
}
},
@ -917,7 +916,7 @@ let BattleAbilities = {
return false;
}
},
onAfterDamage(damage, target, source, move) {
onDamagingHit(damage, target, source, move) {
if (target.getMoveHitData(move).typeMod > 0) {
if (target.m.heavilydamaged && !target.m.quoteplayed) {
this.add(`c|@Ransei|Yo really? Why do you keep hitting me with super effective moves?`);

View File

@ -1404,7 +1404,7 @@ let BattleStatuses = {
// Prevent Snaquaza from fainting while using a fake claim to prevent visual bug
if (pokemon.hp - damage <= 0) return (pokemon.hp - 1);
},
onAfterDamage(damage, pokemon) {
onDamagingHit(damage, pokemon) {
// Hack for Snaquaza's Z move
if (!pokemon.m.claimHP || pokemon.hp > 1) return;
// Now we handle the fake claim "fainting"

View File

@ -2974,8 +2974,8 @@ let BattleMovedex = {
if (source !== this.effectData.target) return;
return source.side.foe.active[this.effectData.position];
},
onAfterDamage(damage, target, source, effect) {
if (effect && effect.effectType === 'Move' && source.side !== target.side && this.getCategory(effect) === 'Physical') {
onDamagingHit(damage, target, source, move) {
if (source.side !== target.side && this.getCategory(move) === 'Physical') {
this.effectData.position = source.position;
this.effectData.damage = 2 * damage;
}
@ -6941,7 +6941,7 @@ let BattleMovedex = {
flags: {},
isMax: "Duraludon",
self: {
onAfterHit(source) {
onHit(source) {
for (let pokemon of source.side.foe.active) {
const move = pokemon.lastMove;
if (move && !move.isZ && !move.isMax) {
@ -6975,7 +6975,7 @@ let BattleMovedex = {
flags: {},
isMax: "Alcremie",
self: {
onAfterHit(target, source, move) {
onHit(target, source, move) {
for (let pokemon of source.side.active) {
this.heal(pokemon.maxhp / 6, pokemon, source, move);
}
@ -11944,8 +11944,8 @@ let BattleMovedex = {
if (source !== this.effectData.target) return;
return source.side.foe.active[this.effectData.position];
},
onAfterDamage(damage, target, source, effect) {
if (effect && effect.effectType === 'Move' && source.side !== target.side) {
onDamagingHit(damage, target, source, effect) {
if (source.side !== target.side) {
this.effectData.position = source.position;
this.effectData.damage = 1.5 * damage;
}
@ -12301,8 +12301,8 @@ let BattleMovedex = {
if (source !== this.effectData.target) return;
return source.side.foe.active[this.effectData.position];
},
onAfterDamage(damage, target, source, effect) {
if (effect && effect.effectType === 'Move' && source.side !== target.side && this.getCategory(effect) === 'Special') {
onDamagingHit(damage, target, source, move) {
if (source.side !== target.side && this.getCategory(move) === 'Special') {
this.effectData.position = source.position;
this.effectData.damage = 2 * damage;
}

View File

@ -291,6 +291,7 @@ let BattleScripts = {
return true;
},
/** NOTE: includes single-target moves */
trySpreadMoveHit(targets, pokemon, move) {
if (targets.length > 1) move.spreadHit = true;
@ -549,6 +550,7 @@ let BattleScripts = {
}
return undefined;
},
/** NOTE: used only for moves that target sides/fields rather than pokemon */
tryMoveHit(target, pokemon, move) {
this.setActiveMove(move, pokemon, target);
@ -790,6 +792,24 @@ let BattleScripts = {
if (!damage[j] && damage[j] !== 0) targets[j] = false;
}
/** @type {Pokemon[]} */
let damagedTargets = [];
let damagedDamage = [];
for (let i = 0; i < targets.length; i++) {
if (typeof damage[i] === 'number') {
damagedTargets.push(/** @type {Pokemon} */ (targets[i]));
damagedDamage.push(damage[i]);
}
}
if (damagedDamage.length) {
this.runEvent('DamagingHit', damagedTargets, pokemon, move, damagedDamage);
if (moveData.onAfterHit) {
for (const target of damagedTargets) {
this.singleEvent('AfterHit', moveData, {}, target, pokemon, move);
}
}
}
return [damage, targets];
},
tryPrimaryHitEvent(damage, targets, pokemon, move, moveData, isSecondary) {
@ -941,10 +961,6 @@ let BattleScripts = {
if (!isSelf && !isSecondary) {
this.runEvent('Hit', target, pokemon, move);
}
if (moveData.onAfterHit) {
hitResult = this.singleEvent('AfterHit', moveData, {}, target, pokemon, move);
didSomething = this.combineResults(didSomething, hitResult);
}
}
}
if (moveData.selfSwitch) {

View File

@ -416,7 +416,8 @@ export class Battle {
singleEvent(
eventid: string, effect: Effect, effectData: AnyObject | null,
target: string | Pokemon | Side | Field | Battle | null, source?: string | Pokemon | Effect | false | null,
sourceEffect?: Effect | string | null, relayVar?: any) {
sourceEffect?: Effect | string | null, relayVar?: any
) {
if (this.eventDepth >= 8) {
// oh fuck
this.add('message', 'STACK LIMIT EXCEEDED');
@ -588,7 +589,8 @@ export class Battle {
*/
runEvent(
eventid: string, target?: Pokemon | Pokemon[] | Side | Battle | null, source?: string | Pokemon | false | null,
effect?: Effect | null, relayVar?: any, onEffect?: boolean, fastExit?: boolean) {
effect?: Effect | null, relayVar?: any, onEffect?: boolean, fastExit?: boolean
) {
// if (Battle.eventCounter) {
// if (!Battle.eventCounter[eventid]) Battle.eventCounter[eventid] = 0;
// Battle.eventCounter[eventid]++;
@ -605,7 +607,7 @@ export class Battle {
let effectSource = null;
if (source instanceof Pokemon) effectSource = source;
const handlers = this.findEventHandlers(target, eventid, effectSource);
if (eventid === 'Invulnerability' || eventid === 'TryHit' || eventid === 'AfterDamage') {
if (eventid === 'Invulnerability' || eventid === 'TryHit' || eventid === 'DamagingHit') {
handlers.sort(Battle.compareLeftToRightOrder);
} else if (fastExit) {
handlers.sort(Battle.compareRedirectOrder);
@ -650,7 +652,7 @@ export class Battle {
if (handler.index !== undefined) {
// TODO: find a better way to do this
if (!targetRelayVars[handler.index] && !(targetRelayVars[handler.index] === 0 &&
eventid === 'AfterDamage')) continue;
eventid === 'DamagingHit')) continue;
if (handler.target) {
args[hasRelayVar] = handler.target;
this.event.target = handler.target;
@ -763,7 +765,8 @@ export class Battle {
*/
priorityEvent(
eventid: string, target: Pokemon | Side | Battle, source?: Pokemon | null,
effect?: Effect, relayVar?: any, onEffect?: boolean): any {
effect?: Effect, relayVar?: any, onEffect?: boolean
): any {
return this.runEvent(eventid, target, source, effect, relayVar, onEffect, true);
}
@ -1750,8 +1753,6 @@ export class Battle {
}
}
// @ts-ignore - FIXME AfterDamage passes an Effect, not an ActiveMove
if (!effect.flags) effect.flags = {};
if (instafaint) {
for (const [i, target] of targetArray.entries()) {
if (!retVals[i] || !target) continue;
@ -1766,7 +1767,6 @@ export class Battle {
}
}
}
retVals = this.runEvent('AfterDamage', (targetArray.filter(val => !!val)) as Pokemon[], source, effect, retVals);
return retVals;
}

View File

@ -109,7 +109,6 @@ interface SelfEffect {
terrain?: string
volatileStatus?: string
weather?: string
onAfterHit?: MoveEventMethods['onAfterHit']
onHit?: MoveEventMethods['onHit']
}
@ -122,7 +121,6 @@ interface SecondaryEffect {
self?: SelfEffect
status?: string
volatileStatus?: string
onAfterHit?: MoveEventMethods['onAfterHit']
onHit?: MoveEventMethods['onHit']
}
@ -196,7 +194,7 @@ interface PureEffectEventMethods {
}
interface EventMethods {
onAfterDamage?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void
onDamagingHit?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void
onAfterEachBoost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source: Pokemon) => void
onAfterHit?: MoveEventMethods['onAfterHit']
onAfterSetStatus?: (this: Battle, status: PureEffect, target: Pokemon, source: Pokemon, effect: Effect) => void
@ -283,7 +281,7 @@ interface EventMethods {
onWeatherModifyDamage?: CommonHandlers['ModifierSourceMove']
onModifyDamagePhase1?: CommonHandlers['ModifierSourceMove']
onModifyDamagePhase2?: CommonHandlers['ModifierSourceMove']
onAllyAfterDamage?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void
onAllyDamagingHit?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void
onAllyAfterEachBoost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source: Pokemon) => void
onAllyAfterHit?: MoveEventMethods['onAfterHit']
onAllyAfterSetStatus?: (this: Battle, status: PureEffect, target: Pokemon, source: Pokemon, effect: Effect) => void
@ -368,7 +366,7 @@ interface EventMethods {
onAllyWeatherModifyDamage?: CommonHandlers['ModifierSourceMove']
onAllyModifyDamagePhase1?: CommonHandlers['ModifierSourceMove']
onAllyModifyDamagePhase2?: CommonHandlers['ModifierSourceMove']
onFoeAfterDamage?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void
onFoeDamagingHit?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void
onFoeAfterEachBoost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source: Pokemon) => void
onFoeAfterHit?: MoveEventMethods['onAfterHit']
onFoeAfterSetStatus?: (this: Battle, status: PureEffect, target: Pokemon, source: Pokemon, effect: Effect) => void
@ -453,7 +451,7 @@ interface EventMethods {
onFoeWeatherModifyDamage?: CommonHandlers['ModifierSourceMove']
onFoeModifyDamagePhase1?: CommonHandlers['ModifierSourceMove']
onFoeModifyDamagePhase2?: CommonHandlers['ModifierSourceMove']
onSourceAfterDamage?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void
onSourceDamagingHit?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void
onSourceAfterEachBoost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source: Pokemon) => void
onSourceAfterHit?: MoveEventMethods['onAfterHit']
onSourceAfterSetStatus?: (this: Battle, status: PureEffect, target: Pokemon, source: Pokemon, effect: Effect) => void
@ -538,7 +536,7 @@ interface EventMethods {
onSourceWeatherModifyDamage?: CommonHandlers['ModifierSourceMove']
onSourceModifyDamagePhase1?: CommonHandlers['ModifierSourceMove']
onSourceModifyDamagePhase2?: CommonHandlers['ModifierSourceMove']
onAnyAfterDamage?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void
onAnyDamagingHit?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void
onAnyAfterEachBoost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source: Pokemon) => void
onAnyAfterHit?: MoveEventMethods['onAfterHit']
onAnyAfterSetStatus?: (this: Battle, status: PureEffect, target: Pokemon, source: Pokemon, effect: Effect) => void
@ -626,7 +624,7 @@ interface EventMethods {
// Priorities (incomplete list)
onAccuracyPriority?: number
onAfterDamageOrder?: number
onDamagingHitOrder?: number
onAfterMoveSecondaryPriority?: number
onAfterMoveSecondarySelfPriority?: number
onAfterMoveSelfPriority?: number

View File

@ -82,13 +82,11 @@ runAction() - runs runSwitch, runAfterSwitch, and runMove in priority order, the
[Damage] (A,U)
-> false => exit damage()
damage
[AfterDamage] (U)
}
heal() {
[Heal] (A)
-> false => exit heal()
heal
[AfterHeal]
}
status() (U) {
[Status] (A)