Support per-pokemon Residual handlers in Side/Field conditions (#8222)

For side conditions, `onStart`/`onRestart`/`onResidual`/`onEnd`
have been renamed `onSideStart`/`onSideRestart`/`onSideResidual`/`onSideEnd`,
with the `onResidualOrder` properties renamed `onSideResidualOrder`.

For field conditions, `onStart`/`onRestart`/`onResidual`/`onEnd`
have been renamed `onFieldStart`/`onFieldRestart`/`onFieldResidual`/`onFieldEnd`,
with the `onResidualOrder` properties renamed `onFieldResidualOrder`.

(The `onField` and `onSide` part helps make it clear to the type system
that the first argument is a Field or Side, not a Pokemon.)

Side and field conditions can now use `onResidual` to tick separately
on each pokemon in Speed order. `onResidualOrder` (the per-pokemon
tick) can be timed separate from `onSideResidualOrder` (the
per-condition tick), allowing conditions to end at a different priority
than they tick per-pokemon.

Relatedly, `onTeamPreview` and `onStart` in formats now need to be
`onFieldTeamPreview` and `onFieldStart`.

Unrelatedly, `effectData` has been renamed `effectState`, and the
corresponding state containers (`pokemon.statusData`,
`pokemon.speciesData`, `pokemon.itemData`, `pokemon.abilityData`,
`field.weatherData`, `field.terrainData`) have been similarly renamed. I
renamed the types a while ago, but I was holding off renaming the fields
because it would be a breaking change. But this is a breaking change
anyway, so we might as well do it now.

Note: `onResidual` will tick even on `onSideEnd` turns, although
`onSideResidual` won't. When refactoring weather, remember to
check `this.state.duration` so you don't deal weather damage on the
ending turn.

Intended as a better fix for #8216
This commit is contained in:
Guangcong Luo
2021-04-25 10:55:54 -07:00
committed by GitHub
parent 66c547432b
commit f9fdc73133
59 changed files with 1338 additions and 1310 deletions

View File

@@ -1410,7 +1410,7 @@ export const Formats: FormatList = [
this.add('faint', pokemon);
pokemon.side.pokemonLeft--;
this.runEvent('Faint', pokemon, faintData.source, faintData.effect);
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityData, pokemon);
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityState, pokemon);
pokemon.clearVolatile(false);
pokemon.fainted = true;
pokemon.isActive = false;

View File

@@ -79,13 +79,13 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
airlock: {
onSwitchIn(pokemon) {
this.effectData.switchingIn = true;
this.effectState.switchingIn = true;
},
onStart(pokemon) {
// Air Lock does not activate when Skill Swapped or when Neutralizing Gas leaves the field
if (!this.effectData.switchingIn) return;
if (!this.effectState.switchingIn) return;
this.add('-ability', pokemon, 'Air Lock');
this.effectData.switchingIn = false;
this.effectState.switchingIn = false;
},
suppressWeather: true,
name: "Air Lock",
@@ -147,13 +147,13 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
arenatrap: {
onFoeTrapPokemon(pokemon) {
if (!pokemon.isAdjacent(this.effectData.target)) return;
if (!pokemon.isAdjacent(this.effectState.target)) return;
if (pokemon.isGrounded()) {
pokemon.tryTrap(true);
}
},
onFoeMaybeTrapPokemon(pokemon, source) {
if (!source) source = this.effectData.target;
if (!source) source = this.effectState.target;
if (!source || !pokemon.isAdjacent(source)) return;
if (pokemon.isGrounded(!pokemon.knownType)) { // Negate immunity if the type is unknown
pokemon.maybeTrapped = true;
@@ -167,7 +167,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onAllyTryAddVolatile(status, target, source, effect) {
if (['attract', 'disable', 'encore', 'healblock', 'taunt', 'torment'].includes(status.id)) {
if (effect.effectType === 'Move') {
const effectHolder = this.effectData.target;
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Aroma Veil', '[of] ' + effectHolder);
}
return null;
@@ -181,13 +181,13 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onPreStart(pokemon) {
this.add('-ability', pokemon, 'As One');
this.add('-ability', pokemon, 'Unnerve');
this.effectData.unnerved = true;
this.effectState.unnerved = true;
},
onEnd() {
this.effectData.unnerved = false;
this.effectState.unnerved = false;
},
onFoeTryEatItem() {
return !this.effectData.unnerved;
return !this.effectState.unnerved;
},
onSourceAfterFaint(length, target, source, effect) {
if (effect && effect.effectType === 'Move') {
@@ -203,13 +203,13 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onPreStart(pokemon) {
this.add('-ability', pokemon, 'As One');
this.add('-ability', pokemon, 'Unnerve');
this.effectData.unnerved = true;
this.effectState.unnerved = true;
},
onEnd() {
this.effectData.unnerved = false;
this.effectState.unnerved = false;
},
onFoeTryEatItem() {
return !this.effectData.unnerved;
return !this.effectState.unnerved;
},
onSourceAfterFaint(length, target, source, effect) {
if (effect && effect.effectType === 'Move') {
@@ -256,7 +256,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
battery: {
onAllyBasePowerPriority: 22,
onAllyBasePower(basePower, attacker, defender, move) {
if (attacker !== this.effectData.target && move.category === 'Special') {
if (attacker !== this.effectState.target && move.category === 'Special') {
this.debug('Battery boost');
return this.chainModify([5325, 4096]);
}
@@ -318,9 +318,9 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
!effect.multihit &&
(!effect.negateSecondary && !(effect.hasSheerForce && source.hasAbility('sheerforce')))
) {
target.abilityData.checkedBerserk = false;
target.abilityState.checkedBerserk = false;
} else {
target.abilityData.checkedBerserk = true;
target.abilityState.checkedBerserk = true;
}
},
onTryEatItem(item, pokemon) {
@@ -328,12 +328,12 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
'aguavberry', 'enigmaberry', 'figyberry', 'iapapaberry', 'magoberry', 'sitrusberry', 'wikiberry', 'oranberry', 'berryjuice',
];
if (healingItems.includes(item.id)) {
return pokemon.abilityData.checkedBerserk;
return pokemon.abilityState.checkedBerserk;
}
return true;
},
onAfterMoveSecondary(target, source, move) {
target.abilityData.checkedBerserk = true;
target.abilityState.checkedBerserk = true;
if (!source || source === target || !target.hp || !move.totalDamage) return;
const lastAttackedBy = target.getLastAttackedBy();
if (!lastAttackedBy) return;
@@ -439,13 +439,13 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
cloudnine: {
onSwitchIn(pokemon) {
this.effectData.switchingIn = true;
this.effectState.switchingIn = true;
},
onStart(pokemon) {
// Cloud Nine does not activate when Skill Swapped or when Neutralizing Gas leaves the field
if (!this.effectData.switchingIn) return;
if (!this.effectState.switchingIn) return;
this.add('-ability', pokemon, 'Cloud Nine');
this.effectData.switchingIn = false;
this.effectState.switchingIn = false;
},
suppressWeather: true,
name: "Cloud Nine",
@@ -578,7 +578,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
if (source.volatiles['disable']) return;
if (!move.isMax && !move.isFutureMove) {
if (this.randomChance(3, 10)) {
source.addVolatile('disable', this.effectData.target);
source.addVolatile('disable', this.effectState.target);
}
}
},
@@ -590,7 +590,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target)) {
if (this.randomChance(3, 10)) {
source.addVolatile('attract', this.effectData.target);
source.addVolatile('attract', this.effectState.target);
}
}
},
@@ -602,7 +602,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onAnyTryMove(target, source, effect) {
if (['explosion', 'mindblown', 'mistyexplosion', 'selfdestruct'].includes(effect.id)) {
this.attrLastMove('[still]');
this.add('cant', this.effectData.target, 'ability: Damp', effect, '[of] ' + target);
this.add('cant', this.effectState.target, 'ability: Damp', effect, '[of] ' + target);
return false;
}
},
@@ -628,8 +628,8 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onAnyBasePowerPriority: 20,
onAnyBasePower(basePower, source, target, move) {
if (target === source || move.category === 'Status' || move.type !== 'Dark') return;
if (!move.auraBooster) move.auraBooster = this.effectData.target;
if (move.auraBooster !== this.effectData.target) return;
if (!move.auraBooster) move.auraBooster = this.effectState.target;
if (move.auraBooster !== this.effectState.target) return;
return this.chainModify([move.hasAuraBreak ? 3072 : 5448, 4096]);
},
isUnbreakable: true,
@@ -652,7 +652,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
return;
}
const dazzlingHolder = this.effectData.target;
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);
@@ -713,11 +713,11 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
if (this.field.getWeather().id === 'deltastream' && !strongWeathers.includes(weather.id)) return false;
},
onEnd(pokemon) {
if (this.field.weatherData.source !== pokemon) return;
if (this.field.weatherState.source !== pokemon) return;
for (const target of this.getAllActive()) {
if (target === pokemon) continue;
if (target.hasAbility('deltastream')) {
this.field.weatherData.source = target;
this.field.weatherState.source = target;
return;
}
}
@@ -736,11 +736,11 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
if (this.field.getWeather().id === 'desolateland' && !strongWeathers.includes(weather.id)) return false;
},
onEnd(pokemon) {
if (this.field.weatherData.source !== pokemon) return;
if (this.field.weatherState.source !== pokemon) return;
for (const target of this.getAllActive()) {
if (target === pokemon) continue;
if (target.hasAbility('desolateland')) {
this.field.weatherData.source = target;
this.field.weatherState.source = target;
return;
}
}
@@ -758,7 +758,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
['mimikyu', 'mimikyutotem'].includes(target.species.id) && !target.transformed
) {
this.add('-activate', target, 'ability: Disguise');
this.effectData.busted = true;
this.effectState.busted = true;
return 0;
}
},
@@ -786,7 +786,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
return 0;
},
onUpdate(pokemon) {
if (['mimikyu', 'mimikyutotem'].includes(pokemon.species.id) && this.effectData.busted) {
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));
@@ -869,7 +869,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
onFoeBasePowerPriority: 17,
onFoeBasePower(basePower, attacker, defender, move) {
if (this.effectData.target !== defender) return;
if (this.effectState.target !== defender) return;
if (move.type === 'Fire') {
return this.chainModify(1.25);
}
@@ -939,8 +939,8 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onAnyBasePowerPriority: 20,
onAnyBasePower(basePower, source, target, move) {
if (target === source || move.category === 'Status' || move.type !== 'Fairy') return;
if (!move.auraBooster) move.auraBooster = this.effectData.target;
if (move.auraBooster !== this.effectData.target) return;
if (!move.auraBooster) move.auraBooster = this.effectState.target;
if (move.auraBooster !== this.effectState.target) return;
return this.chainModify([move.hasAuraBreak ? 3072 : 5448, 4096]);
},
isUnbreakable: true,
@@ -1024,7 +1024,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
flowergift: {
onStart(pokemon) {
delete this.effectData.forme;
delete this.effectState.forme;
},
onUpdate(pokemon) {
if (!pokemon.isActive || pokemon.baseSpecies.baseSpecies !== 'Cherrim' || pokemon.transformed) return;
@@ -1041,14 +1041,14 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
onAllyModifyAtkPriority: 3,
onAllyModifyAtk(atk, pokemon) {
if (this.effectData.target.baseSpecies.baseSpecies !== 'Cherrim') return;
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.effectData.target.baseSpecies.baseSpecies !== 'Cherrim') return;
if (this.effectState.target.baseSpecies.baseSpecies !== 'Cherrim') return;
if (['sunnyday', 'desolateland'].includes(pokemon.effectiveWeather())) {
return this.chainModify(1.5);
}
@@ -1069,7 +1069,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
}
}
if (showMsg && !(effect as ActiveMove).secondaries) {
const effectHolder = this.effectData.target;
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Flower Veil', '[of] ' + effectHolder);
}
},
@@ -1077,7 +1077,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
if (target.hasType('Grass') && source && target !== source && effect && effect.id !== 'yawn') {
this.debug('interrupting setStatus with Flower Veil');
if (effect.id === 'synchronize' || (effect.effectType === 'Move' && !effect.secondaries)) {
const effectHolder = this.effectData.target;
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Flower Veil', '[of] ' + effectHolder);
}
return null;
@@ -1086,7 +1086,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onAllyTryAddVolatile(status, target) {
if (target.hasType('Grass') && status.id === 'yawn') {
this.debug('Flower Veil blocking yawn');
const effectHolder = this.effectData.target;
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Flower Veil', '[of] ' + effectHolder);
return null;
}
@@ -1165,7 +1165,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
friendguard: {
name: "Friend Guard",
onAnyModifyDamage(damage, source, target, move) {
if (target !== this.effectData.target && target.isAlly(this.effectData.target)) {
if (target !== this.effectState.target && target.isAlly(this.effectState.target)) {
this.debug('Friend Guard weaken');
return this.chainModify(0.75);
}
@@ -1259,11 +1259,11 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
gorillatactics: {
onStart(pokemon) {
pokemon.abilityData.choiceLock = "";
pokemon.abilityState.choiceLock = "";
},
onBeforeMove(pokemon, target, move) {
if (move.isZOrMaxPowered || move.id === 'struggle') return;
if (pokemon.abilityData.choiceLock && pokemon.abilityData.choiceLock !== move.id) {
if (pokemon.abilityState.choiceLock && pokemon.abilityState.choiceLock !== move.id) {
// Fails unless ability is being ignored (these events will not run), no PP lost.
this.addMove('move', pokemon, move.name);
this.attrLastMove('[still]');
@@ -1273,8 +1273,8 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
}
},
onModifyMove(move, pokemon) {
if (pokemon.abilityData.choiceLock || move.isZOrMaxPowered || move.id === 'struggle') return;
pokemon.abilityData.choiceLock = move.id;
if (pokemon.abilityState.choiceLock || move.isZOrMaxPowered || move.id === 'struggle') return;
pokemon.abilityState.choiceLock = move.id;
},
onModifyAtkPriority: 1,
onModifyAtk(atk, pokemon) {
@@ -1284,16 +1284,16 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
return this.chainModify(1.5);
},
onDisableMove(pokemon) {
if (!pokemon.abilityData.choiceLock) return;
if (!pokemon.abilityState.choiceLock) return;
if (pokemon.volatiles['dynamax']) return;
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== pokemon.abilityData.choiceLock) {
pokemon.disableMove(moveSlot.id, false, this.effectData.sourceEffect);
if (moveSlot.id !== pokemon.abilityState.choiceLock) {
pokemon.disableMove(moveSlot.id, false, this.effectState.sourceEffect);
}
}
},
onEnd(pokemon) {
pokemon.abilityData.choiceLock = "";
pokemon.abilityState.choiceLock = "";
},
name: "Gorilla Tactics",
rating: 4.5,
@@ -1506,7 +1506,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onStart(pokemon) {
if (this.field.isWeather('hail') && pokemon.species.id === 'eiscuenoice' && !pokemon.transformed) {
this.add('-activate', pokemon, 'ability: Ice Face');
this.effectData.busted = false;
this.effectState.busted = false;
pokemon.formeChange('Eiscue', this.effect, true);
}
},
@@ -1517,7 +1517,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
target.species.id === 'eiscue' && !target.transformed
) {
this.add('-activate', target, 'ability: Ice Face');
this.effectData.busted = true;
this.effectState.busted = true;
return 0;
}
},
@@ -1539,16 +1539,16 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
return 0;
},
onUpdate(pokemon) {
if (pokemon.species.id === 'eiscue' && this.effectData.busted) {
if (pokemon.species.id === 'eiscue' && this.effectState.busted) {
pokemon.formeChange('Eiscue-Noice', this.effect, true);
}
},
onAnyWeatherStart() {
const pokemon = this.effectData.target;
const pokemon = this.effectState.target;
if (!pokemon.hp) return;
if (this.field.isWeather('hail') && pokemon.species.id === 'eiscuenoice' && !pokemon.transformed) {
this.add('-activate', pokemon, 'ability: Ice Face');
this.effectData.busted = false;
this.effectState.busted = false;
pokemon.formeChange('Eiscue', this.effect, true);
}
},
@@ -1586,7 +1586,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
onDamagingHit(damage, target, source, move) {
if (target.illusion) {
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityData, target, source, move);
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityState, target, source, move);
}
},
onEnd(pokemon) {
@@ -1627,18 +1627,18 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
imposter: {
onSwitchIn(pokemon) {
this.effectData.switchingIn = true;
this.effectState.switchingIn = true;
},
onStart(pokemon) {
// Imposter does not activate when Skill Swapped or when Neutralizing Gas leaves the field
if (!this.effectData.switchingIn) return;
if (!this.effectState.switchingIn) return;
// copies across in multibattle and diagonally in free-for-all
// fortunately, side.foe already takes care of all that
const target = pokemon.side.foe.active[pokemon.side.foe.active.length - 1 - pokemon.position];
if (target) {
pokemon.transformInto(target, this.dex.abilities.get('imposter'));
}
this.effectData.switchingIn = false;
this.effectState.switchingIn = false;
},
name: "Imposter",
rating: 5,
@@ -1836,12 +1836,12 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onAnyRedirectTarget(target, source, source2, move) {
if (move.type !== 'Electric' || ['firepledge', 'grasspledge', 'waterpledge'].includes(move.id)) return;
const redirectTarget = ['randomNormal', 'adjacentFoe'].includes(move.target) ? 'normal' : move.target;
if (this.validTarget(this.effectData.target, source, redirectTarget)) {
if (this.validTarget(this.effectState.target, source, redirectTarget)) {
if (move.smartTarget) move.smartTarget = false;
if (this.effectData.target !== target) {
this.add('-activate', this.effectData.target, 'ability: Lightning Rod');
if (this.effectState.target !== target) {
this.add('-activate', this.effectState.target, 'ability: Lightning Rod');
}
return this.effectData.target;
return this.effectState.target;
}
},
name: "Lightning Rod",
@@ -1918,7 +1918,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
const newMove = this.dex.getActiveMove(move.id);
newMove.hasBounced = true;
newMove.pranksterBoosted = false;
this.actions.useMove(newMove, this.effectData.target, source);
this.actions.useMove(newMove, this.effectState.target, source);
return null;
},
condition: {
@@ -1972,12 +1972,12 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
magnetpull: {
onFoeTrapPokemon(pokemon) {
if (pokemon.hasType('Steel') && pokemon.isAdjacent(this.effectData.target)) {
if (pokemon.hasType('Steel') && pokemon.isAdjacent(this.effectState.target)) {
pokemon.tryTrap(true);
}
},
onFoeMaybeTrapPokemon(pokemon, source) {
if (!source) source = this.effectData.target;
if (!source) source = this.effectState.target;
if (!source || !pokemon.isAdjacent(source)) return;
if (!pokemon.knownType || pokemon.hasType('Steel')) {
pokemon.maybeTrapped = true;
@@ -2029,7 +2029,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
}
},
onAnyTerrainStart() {
const pokemon = this.effectData.target;
const pokemon = this.effectState.target;
delete pokemon.volatiles['mimicry'];
pokemon.addVolatile('mimicry');
},
@@ -2309,10 +2309,10 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
// Ability suppression implemented in sim/pokemon.ts:Pokemon#ignoringAbility
onPreStart(pokemon) {
this.add('-ability', pokemon, 'Neutralizing Gas');
pokemon.abilityData.ending = false;
pokemon.abilityState.ending = false;
for (const target of this.getAllActive()) {
if (target.illusion) {
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityData, target, pokemon, 'neutralizinggas');
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityState, target, pokemon, 'neutralizinggas');
}
if (target.volatiles['slowstart']) {
delete target.volatiles['slowstart'];
@@ -2329,14 +2329,14 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
// (If you're tackling this, do note extreme weathers have the same issue)
// Mark this pokemon's ability as ending so Pokemon#ignoringAbility skips it
if (source.abilityData.ending) return;
source.abilityData.ending = true;
if (source.abilityState.ending) return;
source.abilityState.ending = true;
const sortedActive = this.getAllActive();
this.speedSort(sortedActive);
for (const pokemon of sortedActive) {
if (pokemon !== source) {
// Will be suppressed by Pokemon#ignoringAbility if needed
this.singleEvent('Start', pokemon.getAbility(), pokemon.abilityData, pokemon);
this.singleEvent('Start', pokemon.getAbility(), pokemon.abilityState, pokemon);
}
}
},
@@ -2347,10 +2347,10 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
noguard: {
onAnyInvulnerabilityPriority: 1,
onAnyInvulnerability(target, source, move) {
if (move && (source === this.effectData.target || target === this.effectData.target)) return 0;
if (move && (source === this.effectState.target || target === this.effectState.target)) return 0;
},
onAnyAccuracy(accuracy, target, source, move) {
if (move && (source === this.effectData.target || target === this.effectData.target)) {
if (move && (source === this.effectState.target || target === this.effectState.target)) {
return true;
}
return accuracy;
@@ -2506,7 +2506,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
onAllySwitchIn(pokemon) {
if (['psn', 'tox'].includes(pokemon.status)) {
this.add('-activate', this.effectData.target, 'ability: Pastel Veil');
this.add('-activate', this.effectState.target, 'ability: Pastel Veil');
pokemon.cureStatus();
}
},
@@ -2520,7 +2520,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onAllySetStatus(status, target, source, effect) {
if (!['psn', 'tox'].includes(status.id)) return;
if ((effect as Move)?.status) {
const effectHolder = this.effectData.target;
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Pastel Veil', '[of] ' + effectHolder);
}
return false;
@@ -2683,14 +2683,14 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
powerofalchemy: {
onAllyFaint(target) {
if (!this.effectData.target.hp) return;
if (!this.effectState.target.hp) return;
const ability = target.getAbility();
const additionalBannedAbilities = [
'noability', 'flowergift', 'forecast', 'hungerswitch', 'illusion', 'imposter', 'neutralizinggas', 'powerofalchemy', 'receiver', 'trace', 'wonderguard',
];
if (target.getAbility().isPermanent || additionalBannedAbilities.includes(target.ability)) return;
this.add('-ability', this.effectData.target, ability, '[from] ability: Power of Alchemy', '[of] ' + target);
this.effectData.target.setAbility(ability);
this.add('-ability', this.effectState.target, ability, '[from] ability: Power of Alchemy', '[of] ' + target);
this.effectState.target.setAbility(ability);
},
name: "Power of Alchemy",
rating: 0,
@@ -2699,7 +2699,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
powerspot: {
onAllyBasePowerPriority: 22,
onAllyBasePower(basePower, attacker, defender, move) {
if (attacker !== this.effectData.target) {
if (attacker !== this.effectState.target) {
this.debug('Power Spot boost');
return this.chainModify([5325, 4096]);
}
@@ -2740,11 +2740,11 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
if (this.field.getWeather().id === 'primordialsea' && !strongWeathers.includes(weather.id)) return false;
},
onEnd(pokemon) {
if (this.field.weatherData.source !== pokemon) return;
if (this.field.weatherState.source !== pokemon) return;
for (const target of this.getAllActive()) {
if (target === pokemon) continue;
if (target.hasAbility('primordialsea')) {
this.field.weatherData.source = target;
this.field.weatherState.source = target;
return;
}
}
@@ -2831,7 +2831,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
return;
}
const dazzlingHolder = this.effectData.target;
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);
@@ -2892,14 +2892,14 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
receiver: {
onAllyFaint(target) {
if (!this.effectData.target.hp) return;
if (!this.effectState.target.hp) return;
const ability = target.getAbility();
const additionalBannedAbilities = [
'noability', 'flowergift', 'forecast', 'hungerswitch', 'illusion', 'imposter', 'neutralizinggas', 'powerofalchemy', 'receiver', 'trace', 'wonderguard',
];
if (target.getAbility().isPermanent || additionalBannedAbilities.includes(target.ability)) return;
this.add('-ability', this.effectData.target, ability, '[from] ability: Receiver', '[of] ' + target);
this.effectData.target.setAbility(ability);
this.add('-ability', this.effectState.target, ability, '[from] ability: Receiver', '[of] ' + target);
this.effectState.target.setAbility(ability);
},
name: "Receiver",
rating: 0,
@@ -2962,7 +2962,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
onSourceModifyDamagePriority: -1,
onSourceModifyDamage(damage, source, target, move) {
if (target.abilityData.berryWeaken) {
if (target.abilityState.berryWeaken) {
return this.chainModify(0.5);
}
},
@@ -2975,7 +2975,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
'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',
];
// Record if the pokemon ate a berry to resist the attack
pokemon.abilityData.berryWeaken = weakenBerries.includes(item.name);
pokemon.abilityState.berryWeaken = weakenBerries.includes(item.name);
},
name: "Ripen",
rating: 2,
@@ -3107,9 +3107,9 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
}
},
onAllyTryHitSide(target, source, move) {
if (source === this.effectData.target || !target.isAlly(source)) return;
if (source === this.effectState.target || !target.isAlly(source)) return;
if (move.type === 'Grass') {
this.boost({atk: 1}, this.effectData.target);
this.boost({atk: 1}, this.effectState.target);
}
},
name: "Sap Sipper",
@@ -3217,12 +3217,12 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
shadowtag: {
onFoeTrapPokemon(pokemon) {
if (!pokemon.hasAbility('shadowtag') && pokemon.isAdjacent(this.effectData.target)) {
if (!pokemon.hasAbility('shadowtag') && pokemon.isAdjacent(this.effectState.target)) {
pokemon.tryTrap(true);
}
},
onFoeMaybeTrapPokemon(pokemon, source) {
if (!source) source = this.effectData.target;
if (!source) source = this.effectState.target;
if (!source || !pokemon.isAdjacent(source)) return;
if (!pokemon.hasAbility('shadowtag')) {
pokemon.maybeTrapped = true;
@@ -3454,7 +3454,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
soulheart: {
onAnyFaintPriority: 1,
onAnyFaint() {
this.boost({spa: 1}, this.effectData.target);
this.boost({spa: 1}, this.effectState.target);
},
name: "Soul-Heart",
rating: 3.5,
@@ -3469,7 +3469,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
onAllyTryHitSide(target, source, move) {
if (move.flags['sound']) {
this.add('-immune', this.effectData.target, '[from] ability: Soundproof');
this.add('-immune', this.effectState.target, '[from] ability: Soundproof');
}
},
name: "Soundproof",
@@ -3649,12 +3649,12 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onAnyRedirectTarget(target, source, source2, move) {
if (move.type !== 'Water' || ['firepledge', 'grasspledge', 'waterpledge'].includes(move.id)) return;
const redirectTarget = ['randomNormal', 'adjacentFoe'].includes(move.target) ? 'normal' : move.target;
if (this.validTarget(this.effectData.target, source, redirectTarget)) {
if (this.validTarget(this.effectState.target, source, redirectTarget)) {
if (move.smartTarget) move.smartTarget = false;
if (this.effectData.target !== target) {
this.add('-activate', this.effectData.target, 'ability: Storm Drain');
if (this.effectState.target !== target) {
this.add('-activate', this.effectState.target, 'ability: Storm Drain');
}
return this.effectData.target;
return this.effectState.target;
}
},
name: "Storm Drain",
@@ -3742,7 +3742,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onAllySetStatus(status, target, source, effect) {
if (status.id === 'slp') {
this.debug('Sweet Veil interrupts sleep');
const effectHolder = this.effectData.target;
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Sweet Veil', '[of] ' + effectHolder);
return null;
}
@@ -3750,7 +3750,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onAllyTryAddVolatile(status, target) {
if (status.id === 'yawn') {
this.debug('Sweet Veil blocking yawn');
const effectHolder = this.effectData.target;
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Sweet Veil', '[of] ' + effectHolder);
return null;
}
@@ -3771,11 +3771,11 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
symbiosis: {
onAllyAfterUseItem(item, pokemon) {
if (pokemon.switchFlag) return;
const source = this.effectData.target;
const source = this.effectState.target;
const myItem = source.takeItem();
if (!myItem) return;
if (
!this.singleEvent('TakeItem', myItem, source.itemData, pokemon, source, this.effect, myItem) ||
!this.singleEvent('TakeItem', myItem, source.itemState, pokemon, source, this.effect, myItem) ||
!pokemon.setItem(myItem)
) {
source.item = myItem.id;
@@ -3937,11 +3937,11 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
// n.b. only affects Hackmons
// interaction with No Ability is complicated: https://www.smogon.com/forums/threads/pokemon-sun-moon-battle-mechanics-research.3586701/page-76#post-7790209
if (pokemon.adjacentFoes().some(foeActive => foeActive.ability === 'noability')) {
this.effectData.gaveUp = true;
this.effectState.gaveUp = true;
}
},
onUpdate(pokemon) {
if (!pokemon.isStarted || this.effectData.gaveUp) return;
if (!pokemon.isStarted || this.effectState.gaveUp) return;
const additionalBannedAbilities = [
// Zen Mode included here for compatability with Gen 5-6
@@ -4022,7 +4022,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
unaware: {
name: "Unaware",
onAnyModifyBoost(boosts, pokemon) {
const unawareUser = this.effectData.target;
const unawareUser = this.effectState.target;
if (unawareUser === pokemon) return;
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
boosts['def'] = 0;
@@ -4041,7 +4041,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
unburden: {
onAfterUseItem(item, pokemon) {
if (pokemon !== this.effectData.target) return;
if (pokemon !== this.effectState.target) return;
pokemon.addVolatile('unburden');
},
onTakeItem(item, pokemon) {
@@ -4064,18 +4064,18 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
unnerve: {
onPreStart(pokemon) {
this.add('-ability', pokemon, 'Unnerve');
this.effectData.unnerved = true;
this.effectState.unnerved = true;
},
onStart(pokemon) {
if (this.effectData.unnerved) return;
if (this.effectState.unnerved) return;
this.add('-ability', pokemon, 'Unnerve');
this.effectData.unnerved = true;
this.effectState.unnerved = true;
},
onEnd() {
this.effectData.unnerved = false;
this.effectState.unnerved = false;
},
onFoeTryEatItem() {
return !this.effectData.unnerved;
return !this.effectState.unnerved;
},
name: "Unnerve",
rating: 1.5,
@@ -4092,7 +4092,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
victorystar: {
onAnyModifyAccuracyPriority: -1,
onAnyModifyAccuracy(accuracy, target, source) {
if (source.isAlly(this.effectData.target) && typeof accuracy === 'number') {
if (source.isAlly(this.effectState.target) && typeof accuracy === 'number') {
return this.chainModify([4506, 4096]);
}
},
@@ -4374,7 +4374,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
name: "Rebound",
onTryHitPriority: 1,
onTryHit(target, source, move) {
if (this.effectData.target.activeTurns) return;
if (this.effectState.target.activeTurns) return;
if (target === source || move.hasBounced || !move.flags['reflectable']) {
return;
@@ -4385,14 +4385,14 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
return null;
},
onAllyTryHitSide(target, source, move) {
if (this.effectData.target.activeTurns) return;
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.effectData.target, source);
this.actions.useMove(newMove, this.effectState.target, source);
return null;
},
condition: {

View File

@@ -52,16 +52,16 @@ export const Conditions: {[k: string]: ConditionData} = {
this.add('-status', target, 'slp');
}
// 1-3 turns
this.effectData.startTime = this.random(2, 5);
this.effectData.time = this.effectData.startTime;
this.effectState.startTime = this.random(2, 5);
this.effectState.time = this.effectState.startTime;
},
onBeforeMovePriority: 10,
onBeforeMove(pokemon, target, move) {
if (pokemon.hasAbility('earlybird')) {
pokemon.statusData.time--;
pokemon.statusState.time--;
}
pokemon.statusData.time--;
if (pokemon.statusData.time <= 0) {
pokemon.statusState.time--;
if (pokemon.statusState.time <= 0) {
pokemon.cureStatus();
return;
}
@@ -126,7 +126,7 @@ export const Conditions: {[k: string]: ConditionData} = {
name: 'tox',
effectType: 'Status',
onStart(target, source, sourceEffect) {
this.effectData.stage = 0;
this.effectState.stage = 0;
if (sourceEffect && sourceEffect.id === 'toxicorb') {
this.add('-status', target, 'tox', '[from] item: Toxic Orb');
} else if (sourceEffect && sourceEffect.effectType === 'Ability') {
@@ -136,14 +136,14 @@ export const Conditions: {[k: string]: ConditionData} = {
}
},
onSwitchIn() {
this.effectData.stage = 0;
this.effectState.stage = 0;
},
onResidualOrder: 9,
onResidual(pokemon) {
if (this.effectData.stage < 15) {
this.effectData.stage++;
if (this.effectState.stage < 15) {
this.effectState.stage++;
}
this.damage(this.clampIntRange(pokemon.baseMaxhp / 16, 1) * this.effectData.stage);
this.damage(this.clampIntRange(pokemon.baseMaxhp / 16, 1) * this.effectState.stage);
},
},
confusion: {
@@ -155,7 +155,7 @@ export const Conditions: {[k: string]: ConditionData} = {
} else {
this.add('-start', target, 'confusion');
}
this.effectData.time = this.random(2, 6);
this.effectState.time = this.random(2, 6);
},
onEnd(target) {
this.add('-end', target, 'confusion');
@@ -211,27 +211,27 @@ export const Conditions: {[k: string]: ConditionData} = {
return this.random(5, 7);
},
onStart(pokemon, source) {
this.add('-activate', pokemon, 'move: ' + this.effectData.sourceEffect, '[of] ' + source);
this.effectData.boundDivisor = source.hasItem('bindingband') ? 6 : 8;
this.add('-activate', pokemon, 'move: ' + this.effectState.sourceEffect, '[of] ' + source);
this.effectState.boundDivisor = source.hasItem('bindingband') ? 6 : 8;
},
onResidualOrder: 11,
onResidual(pokemon) {
const source = this.effectData.source;
const source = this.effectState.source;
// G-Max Centiferno and G-Max Sandblast continue even after the user leaves the field
const gmaxEffect = ['gmaxcentiferno', 'gmaxsandblast'].includes(this.effectData.sourceEffect.id);
const gmaxEffect = ['gmaxcentiferno', 'gmaxsandblast'].includes(this.effectState.sourceEffect.id);
if (source && (!source.isActive || source.hp <= 0 || !source.activeTurns) && !gmaxEffect) {
delete pokemon.volatiles['partiallytrapped'];
this.add('-end', pokemon, this.effectData.sourceEffect, '[partiallytrapped]', '[silent]');
this.add('-end', pokemon, this.effectState.sourceEffect, '[partiallytrapped]', '[silent]');
return;
}
this.damage(pokemon.baseMaxhp / this.effectData.boundDivisor);
this.damage(pokemon.baseMaxhp / this.effectState.boundDivisor);
},
onEnd(pokemon) {
this.add('-end', pokemon, this.effectData.sourceEffect, '[partiallytrapped]');
this.add('-end', pokemon, this.effectState.sourceEffect, '[partiallytrapped]');
},
onTrapPokemon(pokemon) {
const gmaxEffect = ['gmaxcentiferno', 'gmaxsandblast'].includes(this.effectData.sourceEffect.id);
if (this.effectData.source?.isActive || gmaxEffect) pokemon.tryTrap();
const gmaxEffect = ['gmaxcentiferno', 'gmaxsandblast'].includes(this.effectState.sourceEffect.id);
if (this.effectState.source?.isActive || gmaxEffect) pokemon.tryTrap();
},
},
lockedmove: {
@@ -243,24 +243,24 @@ export const Conditions: {[k: string]: ConditionData} = {
// don't lock, and bypass confusion for calming
delete target.volatiles['lockedmove'];
}
this.effectData.trueDuration--;
this.effectState.trueDuration--;
},
onStart(target, source, effect) {
this.effectData.trueDuration = this.random(2, 4);
this.effectData.move = effect.id;
this.effectState.trueDuration = this.random(2, 4);
this.effectState.move = effect.id;
},
onRestart() {
if (this.effectData.trueDuration >= 2) {
this.effectData.duration = 2;
if (this.effectState.trueDuration >= 2) {
this.effectState.duration = 2;
}
},
onEnd(target) {
if (this.effectData.trueDuration > 1) return;
if (this.effectState.trueDuration > 1) return;
target.addVolatile('confusion');
},
onLockMove(pokemon) {
if (pokemon.volatiles['dynamax']) return;
return this.effectData.move;
return this.effectState.move;
},
},
twoturnmove: {
@@ -268,7 +268,7 @@ export const Conditions: {[k: string]: ConditionData} = {
name: 'twoturnmove',
duration: 2,
onStart(target, source, effect) {
this.effectData.move = effect.id;
this.effectState.move = effect.id;
target.addVolatile(effect.id);
let moveTarget: Pokemon | null = source;
if (effect.sourceEffect && this.dex.moves.get(effect.id).target === 'normal') {
@@ -283,10 +283,10 @@ export const Conditions: {[k: string]: ConditionData} = {
this.runEvent('PrepareHit', target, source, effect);
},
onEnd(target) {
target.removeVolatile(this.effectData.move);
target.removeVolatile(this.effectState.move);
},
onLockMove() {
return this.effectData.move;
return this.effectState.move;
},
onMoveAborted(pokemon) {
pokemon.removeVolatile('twoturnmove');
@@ -298,7 +298,7 @@ export const Conditions: {[k: string]: ConditionData} = {
onStart(pokemon) {
if (!this.activeMove) throw new Error("Battle.activeMove is null");
if (!this.activeMove.id || this.activeMove.hasBounced || this.activeMove.sourceEffect === 'snatch') return false;
this.effectData.move = this.activeMove.id;
this.effectState.move = this.activeMove.id;
},
onBeforeMove(pokemon, target, move) {
if (!pokemon.getItem().isChoice) {
@@ -307,7 +307,7 @@ export const Conditions: {[k: string]: ConditionData} = {
}
if (
!pokemon.ignoringItem() && !pokemon.volatiles['dynamax'] &&
move.id !== this.effectData.move && move.id !== 'struggle'
move.id !== this.effectState.move && move.id !== 'struggle'
) {
// Fails unless the Choice item is being ignored, and no PP is lost
this.addMove('move', pokemon, move.name);
@@ -318,7 +318,7 @@ export const Conditions: {[k: string]: ConditionData} = {
}
},
onDisableMove(pokemon) {
if (!pokemon.getItem().isChoice || !pokemon.hasMove(this.effectData.move)) {
if (!pokemon.getItem().isChoice || !pokemon.hasMove(this.effectState.move)) {
pokemon.removeVolatile('choicelock');
return;
}
@@ -326,8 +326,8 @@ export const Conditions: {[k: string]: ConditionData} = {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectData.move) {
pokemon.disableMove(moveSlot.id, false, this.effectData.sourceEffect);
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id, false, this.effectState.sourceEffect);
}
}
},
@@ -353,7 +353,7 @@ export const Conditions: {[k: string]: ConditionData} = {
duration: 3,
onResidualOrder: 3,
onEnd(target) {
const data = this.effectData;
const data = this.effectState;
// time's up; time to hit! :D
const move = this.dex.moves.get(data.move);
if (target.fainted || target === data.source) {
@@ -382,15 +382,15 @@ export const Conditions: {[k: string]: ConditionData} = {
healreplacement: {
// this is a slot condition
name: 'healreplacement',
onStart(side, source, sourceEffect) {
this.effectData.sourceEffect = sourceEffect;
onStart(target, source, sourceEffect) {
this.effectState.sourceEffect = sourceEffect;
this.add('-activate', source, 'healreplacement');
},
onSwitchInPriority: 1,
onSwitchIn(target) {
if (!target.fainted) {
target.heal(target.maxhp);
this.add('-heal', target, target.getHealth, '[from] move: ' + this.effectData.sourceEffect, '[zeffect]');
this.add('-heal', target, target.getHealth, '[from] move: ' + this.effectState.sourceEffect, '[zeffect]');
target.side.removeSlotCondition(target, 'healreplacement');
}
},
@@ -401,22 +401,22 @@ export const Conditions: {[k: string]: ConditionData} = {
duration: 2,
counterMax: 729,
onStart() {
this.effectData.counter = 3;
this.effectState.counter = 3;
},
onStallMove(pokemon) {
// this.effectData.counter should never be undefined here.
// this.effectState.counter should never be undefined here.
// However, just in case, use 1 if it is undefined.
const counter = this.effectData.counter || 1;
const counter = this.effectState.counter || 1;
this.debug("Success chance: " + Math.round(100 / counter) + "%");
const success = this.randomChance(1, counter);
if (!success) delete pokemon.volatiles['stall'];
return success;
},
onRestart() {
if (this.effectData.counter < (this.effect as Condition).counterMax!) {
this.effectData.counter *= 3;
if (this.effectState.counter < (this.effect as Condition).counterMax!) {
this.effectState.counter *= 3;
}
this.effectData.duration = 2;
this.effectState.duration = 2;
},
},
gem: {
@@ -453,20 +453,20 @@ export const Conditions: {[k: string]: ConditionData} = {
return this.chainModify(0.5);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
if (this.gen <= 5) this.effectData.duration = 0;
if (this.gen <= 5) this.effectState.duration = 0;
this.add('-weather', 'RainDance', '[from] ability: ' + effect, '[of] ' + source);
} else {
this.add('-weather', 'RainDance');
}
},
onResidualOrder: 1,
onResidual() {
onFieldResidualOrder: 1,
onFieldResidual() {
this.add('-weather', 'RainDance', '[upkeep]');
this.eachEvent('Weather');
},
onEnd() {
onFieldEnd() {
this.add('-weather', 'none');
},
},
@@ -490,15 +490,15 @@ export const Conditions: {[k: string]: ConditionData} = {
return this.chainModify(1.5);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
this.add('-weather', 'PrimordialSea', '[from] ability: ' + effect, '[of] ' + source);
},
onResidualOrder: 1,
onResidual() {
onFieldResidualOrder: 1,
onFieldResidual() {
this.add('-weather', 'PrimordialSea', '[upkeep]');
this.eachEvent('Weather');
},
onEnd() {
onFieldEnd() {
this.add('-weather', 'none');
},
},
@@ -523,9 +523,9 @@ export const Conditions: {[k: string]: ConditionData} = {
return this.chainModify(0.5);
}
},
onStart(battle, source, effect) {
onFieldStart(battle, source, effect) {
if (effect?.effectType === 'Ability') {
if (this.gen <= 5) this.effectData.duration = 0;
if (this.gen <= 5) this.effectState.duration = 0;
this.add('-weather', 'SunnyDay', '[from] ability: ' + effect, '[of] ' + source);
} else {
this.add('-weather', 'SunnyDay');
@@ -535,12 +535,12 @@ export const Conditions: {[k: string]: ConditionData} = {
if (pokemon.hasItem('utilityumbrella')) return;
if (type === 'frz') return false;
},
onResidualOrder: 1,
onResidual() {
onFieldResidualOrder: 1,
onFieldResidual() {
this.add('-weather', 'SunnyDay', '[upkeep]');
this.eachEvent('Weather');
},
onEnd() {
onFieldEnd() {
this.add('-weather', 'none');
},
},
@@ -564,19 +564,19 @@ export const Conditions: {[k: string]: ConditionData} = {
return this.chainModify(1.5);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
this.add('-weather', 'DesolateLand', '[from] ability: ' + effect, '[of] ' + source);
},
onImmunity(type, pokemon) {
if (pokemon.hasItem('utilityumbrella')) return;
if (type === 'frz') return false;
},
onResidualOrder: 1,
onResidual() {
onFieldResidualOrder: 1,
onFieldResidual() {
this.add('-weather', 'DesolateLand', '[upkeep]');
this.eachEvent('Weather');
},
onEnd() {
onFieldEnd() {
this.add('-weather', 'none');
},
},
@@ -598,23 +598,23 @@ export const Conditions: {[k: string]: ConditionData} = {
return this.modify(spd, 1.5);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
if (this.gen <= 5) this.effectData.duration = 0;
if (this.gen <= 5) this.effectState.duration = 0;
this.add('-weather', 'Sandstorm', '[from] ability: ' + effect, '[of] ' + source);
} else {
this.add('-weather', 'Sandstorm');
}
},
onResidualOrder: 1,
onResidual() {
onFieldResidualOrder: 1,
onFieldResidual() {
this.add('-weather', 'Sandstorm', '[upkeep]');
if (this.field.isWeather('sandstorm')) this.eachEvent('Weather');
},
onWeather(target) {
this.damage(target.baseMaxhp / 16);
},
onEnd() {
onFieldEnd() {
this.add('-weather', 'none');
},
},
@@ -628,23 +628,23 @@ export const Conditions: {[k: string]: ConditionData} = {
}
return 5;
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
if (this.gen <= 5) this.effectData.duration = 0;
if (this.gen <= 5) this.effectState.duration = 0;
this.add('-weather', 'Hail', '[from] ability: ' + effect, '[of] ' + source);
} else {
this.add('-weather', 'Hail');
}
},
onResidualOrder: 1,
onResidual() {
onFieldResidualOrder: 1,
onFieldResidual() {
this.add('-weather', 'Hail', '[upkeep]');
if (this.field.isWeather('hail')) this.eachEvent('Weather');
},
onWeather(target) {
this.damage(target.baseMaxhp / 16);
},
onEnd() {
onFieldEnd() {
this.add('-weather', 'none');
},
},
@@ -659,15 +659,15 @@ export const Conditions: {[k: string]: ConditionData} = {
return 0;
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
this.add('-weather', 'DeltaStream', '[from] ability: ' + effect, '[of] ' + source);
},
onResidualOrder: 1,
onResidual() {
onFieldResidualOrder: 1,
onFieldResidual() {
this.add('-weather', 'DeltaStream', '[upkeep]');
this.eachEvent('Weather');
},
onEnd() {
onFieldEnd() {
this.add('-weather', 'none');
},
},

View File

@@ -145,7 +145,7 @@ export const Items: {[itemid: string]: ItemData} = {
onDamagingHit(damage, target, source, move) {
this.add('-enditem', target, 'Air Balloon');
target.item = '';
target.itemData = {id: '', target};
target.itemState = {id: '', target};
this.runEvent('AfterUseItem', target, null, null, this.dex.items.get('airballoon'));
},
onAfterSubDamage(damage, target, source, effect) {
@@ -153,7 +153,7 @@ export const Items: {[itemid: string]: ItemData} = {
if (effect.effectType === 'Move') {
this.add('-enditem', target, 'Air Balloon');
target.item = '';
target.itemData = {id: '', target};
target.itemState = {id: '', target};
this.runEvent('AfterUseItem', target, null, null, this.dex.items.get('airballoon'));
}
},
@@ -1490,7 +1490,7 @@ export const Items: {[itemid: string]: ItemData} = {
}
},
onAnyTerrainStart() {
const pokemon = this.effectData.target;
const pokemon = this.effectState.target;
if (this.field.isTerrain('electricterrain')) {
pokemon.useItem();
}
@@ -2160,7 +2160,7 @@ export const Items: {[itemid: string]: ItemData} = {
}
},
onAnyTerrainStart() {
const pokemon = this.effectData.target;
const pokemon = this.effectState.target;
if (this.field.isTerrain('grassyterrain')) {
pokemon.useItem();
}
@@ -3382,8 +3382,8 @@ export const Items: {[itemid: string]: ItemData} = {
},
condition: {
onStart(pokemon) {
this.effectData.lastMove = '';
this.effectData.numConsecutive = 0;
this.effectState.lastMove = '';
this.effectState.numConsecutive = 0;
},
onTryMovePriority: -2,
onTryMove(pokemon, target, move) {
@@ -3391,18 +3391,18 @@ export const Items: {[itemid: string]: ItemData} = {
pokemon.removeVolatile('metronome');
return;
}
if (this.effectData.lastMove === move.id && pokemon.moveLastTurnResult) {
this.effectData.numConsecutive++;
} else if (pokemon.volatiles['twoturnmove'] && this.effectData.lastMove !== move.id) {
this.effectData.numConsecutive = 1;
if (this.effectState.lastMove === move.id && pokemon.moveLastTurnResult) {
this.effectState.numConsecutive++;
} else if (pokemon.volatiles['twoturnmove'] && this.effectState.lastMove !== move.id) {
this.effectState.numConsecutive = 1;
} else {
this.effectData.numConsecutive = 0;
this.effectState.numConsecutive = 0;
}
this.effectData.lastMove = move.id;
this.effectState.lastMove = move.id;
},
onModifyDamage(damage, source, target, move) {
const dmgMod = [4096, 4915, 5734, 6553, 7372, 8192];
const numConsecutive = this.effectData.numConsecutive > 5 ? 5 : this.effectData.numConsecutive;
const numConsecutive = this.effectState.numConsecutive > 5 ? 5 : this.effectState.numConsecutive;
return this.chainModify([dmgMod[numConsecutive], 4096]);
},
},
@@ -3538,7 +3538,7 @@ export const Items: {[itemid: string]: ItemData} = {
}
},
onAnyTerrainStart() {
const pokemon = this.effectData.target;
const pokemon = this.effectState.target;
if (this.field.isTerrain('mistyterrain')) {
pokemon.useItem();
}
@@ -4231,7 +4231,7 @@ export const Items: {[itemid: string]: ItemData} = {
}
},
onAnyTerrainStart() {
const pokemon = this.effectData.target;
const pokemon = this.effectState.target;
if (this.field.isTerrain('psychicterrain')) {
pokemon.useItem();
}

View File

@@ -14,8 +14,8 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
},
onAnyDamage(damage, target, source, effect) {
if (effect?.id === 'aftermath') {
this.heal(this.effectData.target.baseMaxhp / 4);
this.add('-immune', this.effectData.target, '[from] ability: Porous');
this.heal(this.effectState.target.baseMaxhp / 4);
this.add('-immune', this.effectState.target, '[from] ability: Porous');
}
},
},
@@ -54,7 +54,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
return;
}
const dazzlingHolder = this.effectData.target;
const dazzlingHolder = this.effectState.target;
if ((source.side === dazzlingHolder.side || move.target === 'all') && move.priority > 0.1) {
this.attrLastMove('[still]');
this.add('cant', dazzlingHolder, "ability: King's Guard", move, '[of] ' + target);
@@ -80,7 +80,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
}
}
if (showMsg && !(effect as ActiveMove).secondaries) {
const effectHolder = this.effectData.target;
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Growth Veil', '[of] ' + effectHolder);
}
},
@@ -88,7 +88,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
if (target.hasType('Grass') && source && target !== source && effect && effect.id !== 'yawn') {
this.debug('interrupting setStatus with Growth Veil');
if (effect.id === 'synchronize' || (effect.effectType === 'Move' && !effect.secondaries)) {
const effectHolder = this.effectData.target;
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Growth Veil', '[of] ' + effectHolder);
}
return null;
@@ -97,7 +97,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
onAllyTryAddVolatile(status, target) {
if (target.hasType('Grass') && status.id === 'yawn') {
this.debug('Growth Veil blocking yawn');
const effectHolder = this.effectData.target;
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Growth Veil', '[of] ' + effectHolder);
return null;
}
@@ -168,7 +168,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
const newMove = this.dex.getActiveMove(move.id);
newMove.hasBounced = true;
newMove.pranksterBoosted = false;
this.actions.useMove(newMove, this.effectData.target, source);
this.actions.useMove(newMove, this.effectState.target, source);
return null;
},
condition: {
@@ -356,7 +356,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
name: "Concussion",
shortDesc: "Halves the effects of stat changes when taking or dealing damage.",
onAnyModifyBoost(boosts, pokemon) {
const unawareUser = this.effectData.target;
const unawareUser = this.effectState.target;
if (unawareUser === pokemon) return;
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
if (boosts['def']) boosts['def'] = Math.ceil(boosts['def'] / 2);
@@ -385,10 +385,10 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
},
onAnyInvulnerabilityPriority: 1,
onAnyInvulnerability(target, source, move) {
if (move && (source === this.effectData.target || target === this.effectData.target)) return 0;
if (move && (source === this.effectState.target || target === this.effectState.target)) return 0;
},
onAnyAccuracy(accuracy, target, source, move) {
if (move && (source === this.effectData.target || target === this.effectData.target)) {
if (move && (source === this.effectState.target || target === this.effectState.target)) {
return true;
}
return accuracy;
@@ -398,11 +398,11 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
name: "Fowl Behavior",
shortDesc: "This Pokemon's Sp. Atk is 1.5x, but it can only select the first move it executes.",
onStart(pokemon) {
pokemon.abilityData.choiceLock = "";
pokemon.abilityState.choiceLock = "";
},
onBeforeMove(pokemon, target, move) {
if (move.isZOrMaxPowered || move.id === 'struggle') return;
if (pokemon.abilityData.choiceLock && pokemon.abilityData.choiceLock !== move.id) {
if (pokemon.abilityState.choiceLock && pokemon.abilityState.choiceLock !== move.id) {
// Fails unless ability is being ignored (these events will not run), no PP lost.
this.addMove('move', pokemon, move.name);
this.attrLastMove('[still]');
@@ -412,8 +412,8 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
}
},
onModifyMove(move, pokemon) {
if (pokemon.abilityData.choiceLock || move.isZOrMaxPowered || move.id === 'struggle') return;
pokemon.abilityData.choiceLock = move.id;
if (pokemon.abilityState.choiceLock || move.isZOrMaxPowered || move.id === 'struggle') return;
pokemon.abilityState.choiceLock = move.id;
},
onModifySpAPriority: 5,
onModifySpA(atk, pokemon, t, move) {
@@ -433,16 +433,16 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
return this.chainModify(1.5);
},
onDisableMove(pokemon) {
if (!pokemon.abilityData.choiceLock) return;
if (!pokemon.abilityState.choiceLock) return;
if (pokemon.volatiles['dynamax']) return;
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== pokemon.abilityData.choiceLock) {
pokemon.disableMove(moveSlot.id, false, this.effectData.sourceEffect);
if (moveSlot.id !== pokemon.abilityState.choiceLock) {
pokemon.disableMove(moveSlot.id, false, this.effectState.sourceEffect);
}
}
},
onEnd(pokemon) {
pokemon.abilityData.choiceLock = "";
pokemon.abilityState.choiceLock = "";
},
},
pillage: {
@@ -451,11 +451,11 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
onStart(pokemon) {
if (pokemon.adjacentFoes().some(foeActive => foeActive.ability === 'noability') ||
pokemon.species.id !== 'yaciancrowned') {
this.effectData.gaveUp = true;
this.effectState.gaveUp = true;
}
},
onUpdate(pokemon) {
if (!pokemon.isStarted || this.effectData.gaveUp) return;
if (!pokemon.isStarted || this.effectState.gaveUp) return;
const possibleTargets = pokemon.adjacentFoes();
while (possibleTargets.length) {
let rand = 0;
@@ -670,10 +670,10 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
noguard: { // Edited for Sturdy Mold
onAnyInvulnerabilityPriority: 1,
onAnyInvulnerability(target, source, move) {
if (move && [source, target].includes(this.effectData.target) && !target.hasAbility('sturdymold')) return 0;
if (move && [source, target].includes(this.effectState.target) && !target.hasAbility('sturdymold')) return 0;
},
onAnyAccuracy(accuracy, target, source, move) {
if (move && [source, target].includes(this.effectData.target) && !target.hasAbility('sturdymold')) {
if (move && [source, target].includes(this.effectState.target) && !target.hasAbility('sturdymold')) {
return true;
}
return accuracy;
@@ -709,7 +709,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
this.boost({def: 1}, pokemon);
},
onAnyModifyDamage(damage, source, target, move) {
if (target !== this.effectData.target && target.side === this.effectData.target.side) {
if (target !== this.effectState.target && target.side === this.effectState.target.side) {
this.debug('Friend Shield weaken');
return this.chainModify(0.75);
}
@@ -872,7 +872,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
if (target.isSemiInvulnerable()) return;
if (target.ignoringItem()) return false;
const item = target.getItem();
if (!this.singleEvent('TakeItem', item, target.itemData, target, target, move, item)) return false;
if (!this.singleEvent('TakeItem', item, target.itemState, target, target, move, item)) return false;
if (item) {
target.addVolatile('fling');
this.damage(source.baseMaxhp / 4, source, target);

View File

@@ -89,7 +89,7 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
onStart(target, source, sourceEffect) {
if (sourceEffect?.effectType === 'Ability') {
this.add('-status', target, 'psn', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
this.effectData.sourceEffect = sourceEffect.id;
this.effectState.sourceEffect = sourceEffect.id;
} else {
this.add('-status', target, 'psn');
}
@@ -105,7 +105,7 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
name: 'tox',
effectType: 'Status',
onStart(target, source, sourceEffect) {
this.effectData.stage = 0;
this.effectState.stage = 0;
if (sourceEffect && sourceEffect.id === 'toxicorb') {
this.add('-status', target, 'tox', '[from] item: Toxic Orb');
target.m.orbItemStatus = true;
@@ -116,15 +116,15 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
}
},
onSwitchIn() {
this.effectData.stage = 0;
this.effectState.stage = 0;
},
onResidualOrder: 9,
onResidual(pokemon) {
if (this.effectData.stage < 15) {
this.effectData.stage++;
if (this.effectState.stage < 15) {
this.effectState.stage++;
}
if (!pokemon.hasAbility('therapeutic')) {
this.damage(this.clampIntRange(pokemon.baseMaxhp / 16, 1) * this.effectData.stage);
this.damage(this.clampIntRange(pokemon.baseMaxhp / 16, 1) * this.effectState.stage);
}
},
},

View File

@@ -11,7 +11,7 @@ export const Rulesets: {[k: string]: FormatData} = {
this.add('poke', pokemon.side.id, details, '');
}
},
onTeamPreview() {
onFieldTeamPreview() {
this.makeRequest('teampreview');
},
},

View File

@@ -66,20 +66,20 @@ export const Conditions: {[id: string]: ModdedConditionData} = {
this.add('-status', target, 'slp');
}
// 1-7 turns
this.effectData.startTime = this.random(1, 8);
this.effectData.time = this.effectData.startTime;
this.effectState.startTime = this.random(1, 8);
this.effectState.time = this.effectState.startTime;
},
onBeforeMovePriority: 10,
onBeforeMove(pokemon, target, move) {
pokemon.statusData.time--;
if (pokemon.statusData.time > 0) {
pokemon.statusState.time--;
if (pokemon.statusState.time > 0) {
this.add('cant', pokemon, 'slp');
}
pokemon.lastMove = null;
return false;
},
onAfterMoveSelf(pokemon) {
if (pokemon.statusData.time <= 0) pokemon.cureStatus();
if (pokemon.statusState.time <= 0) pokemon.cureStatus();
},
},
frz: {
@@ -131,7 +131,7 @@ export const Conditions: {[id: string]: ModdedConditionData} = {
} else {
this.add('-start', target, 'confusion');
}
this.effectData.time = this.random(2, 6);
this.effectState.time = this.random(2, 6);
},
onEnd(target) {
this.add('-end', target, 'confusion');
@@ -177,7 +177,7 @@ export const Conditions: {[id: string]: ModdedConditionData} = {
name: 'trapped',
noCopy: true,
onTrapPokemon(pokemon) {
if (!this.effectData.source?.isActive) {
if (!this.effectState.source?.isActive) {
delete pokemon.volatiles['trapped'];
return;
}
@@ -205,14 +205,14 @@ export const Conditions: {[id: string]: ModdedConditionData} = {
}
},
onStart(target, source, effect) {
this.effectData.move = effect.id;
this.effectState.move = effect.id;
},
onDisableMove(pokemon) {
if (!pokemon.hasMove(this.effectData.move)) {
if (!pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectData.move) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
@@ -241,12 +241,12 @@ export const Conditions: {[id: string]: ModdedConditionData} = {
duration: 2,
counterMax: 256,
onStart() {
this.effectData.counter = 2;
this.effectState.counter = 2;
},
onStallMove() {
// this.effectData.counter should never be undefined here.
// this.effectState.counter should never be undefined here.
// However, just in case, use 1 if it is undefined.
const counter = this.effectData.counter || 1;
const counter = this.effectState.counter || 1;
if (counter >= 256) {
// 2^32 - special-cased because Battle.random(n) can't handle n > 2^16 - 1
return (this.random() * 4294967296 < 1);
@@ -255,10 +255,10 @@ export const Conditions: {[id: string]: ModdedConditionData} = {
return this.randomChance(1, counter);
},
onRestart() {
if (this.effectData.counter < (this.effect as Condition).counterMax!) {
this.effectData.counter *= 2;
if (this.effectState.counter < (this.effect as Condition).counterMax!) {
this.effectState.counter *= 2;
}
this.effectData.duration = 2;
this.effectState.duration = 2;
},
},
};

View File

@@ -41,53 +41,53 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return this.random(3, 4);
},
onStart(pokemon) {
this.effectData.totalDamage = 0;
this.effectData.lastDamage = 0;
this.effectState.totalDamage = 0;
this.effectState.lastDamage = 0;
this.add('-start', pokemon, 'Bide');
},
onHit(target, source, move) {
if (source && source !== target && move.category !== 'Physical' && move.category !== 'Special') {
const damage = this.effectData.totalDamage;
this.effectData.totalDamage += damage;
this.effectData.lastDamage = damage;
this.effectData.sourceSlot = source.getSlot();
const damage = this.effectState.totalDamage;
this.effectState.totalDamage += damage;
this.effectState.lastDamage = damage;
this.effectState.sourceSlot = source.getSlot();
}
},
onDamage(damage, target, source, move) {
if (!source || source.isAlly(target)) return;
if (!move || move.effectType !== 'Move') return;
if (!damage && this.effectData.lastDamage > 0) {
damage = this.effectData.totalDamage;
if (!damage && this.effectState.lastDamage > 0) {
damage = this.effectState.totalDamage;
}
this.effectData.totalDamage += damage;
this.effectData.lastDamage = damage;
this.effectData.sourceSlot = source.getSlot();
this.effectState.totalDamage += damage;
this.effectState.lastDamage = damage;
this.effectState.sourceSlot = source.getSlot();
},
onAfterSetStatus(status, pokemon) {
// Sleep, freeze, and partial trap will just pause duration.
if (pokemon.volatiles['flinch']) {
this.effectData.duration++;
this.effectState.duration++;
} else if (pokemon.volatiles['partiallytrapped']) {
this.effectData.duration++;
this.effectState.duration++;
} else {
switch (status.id) {
case 'slp':
case 'frz':
this.effectData.duration++;
this.effectState.duration++;
break;
}
}
},
onBeforeMove(pokemon, t, move) {
if (this.effectData.duration === 1) {
if (this.effectState.duration === 1) {
this.add('-end', pokemon, 'Bide');
if (!this.effectData.totalDamage) {
if (!this.effectState.totalDamage) {
this.debug("Bide failed due to 0 damage taken");
this.add('-fail', pokemon);
return false;
}
const target = this.getAtSlot(this.effectData.sourceSlot);
this.actions.moveHit(target, pokemon, move, {damage: this.effectData.totalDamage * 2} as ActiveMove);
const target = this.getAtSlot(this.effectState.sourceSlot);
this.actions.moveHit(target, pokemon, move, {damage: this.effectState.totalDamage * 2} as ActiveMove);
pokemon.removeVolatile('bide');
return false;
}
@@ -279,12 +279,12 @@ export const Moves: {[k: string]: ModdedMoveData} = {
},
onStart(pokemon) {
if (!this.queue.willMove(pokemon)) {
this.effectData.duration++;
this.effectState.duration++;
}
const moves = pokemon.moves;
const move = this.dex.moves.get(this.sample(moves));
this.add('-start', pokemon, 'Disable', move.name);
this.effectData.move = move.id;
this.effectState.move = move.id;
return;
},
onResidualOrder: 14,
@@ -292,14 +292,14 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.add('-end', pokemon, 'Disable');
},
onBeforeMove(attacker, defender, move) {
if (move.id === this.effectData.move) {
if (move.id === this.effectState.move) {
this.add('cant', attacker, 'Disable', move);
return false;
}
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === this.effectData.move) {
if (moveSlot.id === this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
@@ -581,7 +581,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
// Rage lock
duration: 255,
onStart(target, source, effect) {
this.effectData.move = 'rage';
this.effectState.move = 'rage';
},
onLockMove: 'rage',
onTryHit(target, source, move) {
@@ -654,8 +654,8 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return false;
}
if (!target.setStatus('slp', source, move)) return false;
target.statusData.time = 2;
target.statusData.startTime = 2;
target.statusState.time = 2;
target.statusState.startTime = 2;
this.heal(target.maxhp); // Aesthetic only as the healing happens after you fall asleep in-game
},
},
@@ -764,7 +764,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectData.hp = Math.floor(target.maxhp / 4) + 1;
this.effectState.hp = Math.floor(target.maxhp / 4) + 1;
delete target.volatiles['partiallytrapped'];
},
onTryHitPriority: -1,

View File

@@ -55,7 +55,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectData.hp = Math.floor(target.maxhp / 4) + 1;
this.effectState.hp = Math.floor(target.maxhp / 4) + 1;
delete target.volatiles['partiallytrapped'];
},
onTryHitPriority: -1,

View File

@@ -45,18 +45,18 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
this.add('-status', target, 'slp');
}
// 1-3 turns
this.effectData.startTime = this.random(1, 4);
this.effectData.time = this.effectData.startTime;
this.effectState.startTime = this.random(1, 4);
this.effectState.time = this.effectState.startTime;
},
onBeforeMovePriority: 2,
onBeforeMove(pokemon, target, move) {
pokemon.statusData.time--;
pokemon.statusState.time--;
this.add('cant', pokemon, 'slp');
pokemon.lastMove = null;
return false;
},
onAfterMoveSelf(pokemon) {
if (pokemon.statusData.time <= 0) pokemon.cureStatus();
if (pokemon.statusState.time <= 0) pokemon.cureStatus();
},
},
frz: {
@@ -117,7 +117,7 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
this.add('-activate', target, 'move: ' + effect, '[of] ' + source);
},
onBeforeMove(pokemon) {
if (this.effectData.source && (!this.effectData.source.isActive || this.effectData.source.hp <= 0)) {
if (this.effectState.source && (!this.effectState.source.isActive || this.effectState.source.hp <= 0)) {
pokemon.removeVolatile('partiallytrapped');
return;
}
@@ -125,7 +125,7 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
return false;
},
onEnd(pokemon) {
this.add('-end', pokemon, this.effectData.sourceEffect, '[partiallytrapped]');
this.add('-end', pokemon, this.effectState.sourceEffect, '[partiallytrapped]');
},
},
};

View File

@@ -121,7 +121,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
// Rage lock
duration: 255,
onStart(target, source, effect) {
this.effectData.move = 'rage';
this.effectState.move = 'rage';
},
onLockMove: 'rage',
onTryHit(target, source, move) {
@@ -153,8 +153,8 @@ export const Moves: {[k: string]: ModdedMoveData} = {
// max HP and current HP is 0, 255, or 511
if (target.hp >= target.maxhp) return false;
if (!target.setStatus('slp', source, move)) return false;
target.statusData.time = 2;
target.statusData.startTime = 2;
target.statusState.time = 2;
target.statusState.startTime = 2;
target.recalculateStats!(); // Stadium Rest removes statdrops given by Major Status Conditions.
this.heal(target.maxhp); // Aesthetic only as the healing happens after you fall asleep in-game
},
@@ -175,7 +175,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectData.hp = Math.floor(target.maxhp / 4);
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryHitPriority: -1,

View File

@@ -34,12 +34,12 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
this.add('-status', target, 'slp');
}
// 1-6 turns
this.effectData.time = this.random(2, 8);
this.effectState.time = this.random(2, 8);
},
onBeforeMovePriority: 10,
onBeforeMove(pokemon, target, move) {
pokemon.statusData.time--;
if (pokemon.statusData.time <= 0) {
pokemon.statusState.time--;
if (pokemon.statusState.time <= 0) {
pokemon.cureStatus();
return;
}
@@ -117,9 +117,9 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
this.add('-start', target, 'confusion');
}
if (sourceEffect && sourceEffect.id === 'berserkgene') {
this.effectData.time = 256;
this.effectState.time = 256;
} else {
this.effectData.time = this.random(2, 6);
this.effectState.time = this.random(2, 6);
}
},
onBeforeMove(pokemon, target, move) {
@@ -168,7 +168,7 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
}
},
onStart(target, source, effect) {
this.effectData.move = effect.id;
this.effectState.move = effect.id;
},
onEnd(target) {
// Confusion begins even if already confused
@@ -176,13 +176,13 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
if (!target.side.getSideCondition('safeguard')) target.addVolatile('confusion');
},
onLockMove(pokemon) {
return this.effectData.move;
return this.effectState.move;
},
onMoveAborted(pokemon) {
delete pokemon.volatiles['lockedmove'];
},
onBeforeTurn(pokemon) {
const move = this.dex.moves.get(this.effectData.move);
const move = this.dex.moves.get(this.effectState.move);
if (move.id) {
this.debug('Forcing into ' + move.id);
this.queue.changeAction(pokemon, {choice: 'move', moveid: move.id});
@@ -199,16 +199,16 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
name: 'stall',
duration: 2,
onStart() {
this.effectData.counter = 127;
this.effectState.counter = 127;
},
onStallMove() {
const counter = Math.floor(this.effectData.counter) || 127;
const counter = Math.floor(this.effectState.counter) || 127;
this.debug("Success chance: " + Math.round(counter * 1000 / 255) / 10 + "% (" + counter + "/255)");
return this.randomChance(counter, 255);
},
onRestart() {
this.effectData.counter /= 2;
this.effectData.duration = 2;
this.effectState.counter /= 2;
this.effectState.duration = 2;
},
},
residualdmg: {

View File

@@ -57,23 +57,23 @@ export const Moves: {[k: string]: ModdedMoveData} = {
},
onLockMove: 'bide',
onStart(pokemon) {
this.effectData.totalDamage = 0;
this.effectState.totalDamage = 0;
this.add('-start', pokemon, 'move: Bide');
},
onDamagePriority: -101,
onDamage(damage, target, source, move) {
if (!move || move.effectType !== 'Move' || !source) return;
this.effectData.totalDamage += damage;
this.effectData.lastDamageSource = source;
this.effectState.totalDamage += damage;
this.effectState.lastDamageSource = source;
},
onBeforeMove(pokemon, target, move) {
if (this.effectData.duration === 1) {
if (this.effectState.duration === 1) {
this.add('-end', pokemon, 'move: Bide');
if (!this.effectData.totalDamage) {
if (!this.effectState.totalDamage) {
this.add('-fail', pokemon);
return false;
}
target = this.effectData.lastDamageSource;
target = this.effectState.lastDamageSource;
if (!target) {
this.add('-fail', pokemon);
return false;
@@ -90,7 +90,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
id: 'bide',
name: "Bide",
accuracy: 100,
damage: this.effectData.totalDamage * 2,
damage: this.effectState.totalDamage * 2,
category: "Physical",
priority: 0,
flags: {contact: 1, protect: 1},
@@ -202,18 +202,18 @@ export const Moves: {[k: string]: ModdedMoveData} = {
// it failed
return false;
}
this.effectData.move = lockedMove;
this.effectState.move = lockedMove;
this.add('-start', target, 'Encore');
if (!this.queue.willMove(target)) {
this.effectData.duration++;
this.effectState.duration++;
}
},
onOverrideAction(pokemon) {
return this.effectData.move;
return this.effectState.move;
},
onResidualOrder: 13,
onResidual(target) {
const lockedMoveIndex = target.moves.indexOf(this.effectData.move);
const lockedMoveIndex = target.moves.indexOf(this.effectState.move);
if (lockedMoveIndex >= 0 && target.moveSlots[lockedMoveIndex].pp <= 0) {
// early termination if you run out of PP
target.removeVolatile('encore');
@@ -223,11 +223,11 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectData.move || !pokemon.hasMove(this.effectData.move)) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectData.move) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
@@ -367,11 +367,11 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
duration: 5,
// Sp. Def boost applied directly in stat calculation
onStart(side) {
onSideStart(side) {
this.add('-sidestart', side, 'move: Light Screen');
},
onResidualOrder: 21,
onEnd(side) {
onSideResidualOrder: 21,
onSideEnd(side) {
this.add('-sideend', side, 'move: Light Screen');
},
},
@@ -385,7 +385,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
duration: 2,
onSourceAccuracy(accuracy, target, source, move) {
if (move && source === this.effectData.target && target === this.effectData.source) return true;
if (move && source === this.effectState.target && target === this.effectState.source) return true;
},
},
},
@@ -562,11 +562,11 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
duration: 5,
// Defense boost applied directly in stat calculation
onStart(side) {
onSideStart(side) {
this.add('-sidestart', side, 'Reflect');
},
onResidualOrder: 21,
onEnd(side) {
onSideResidualOrder: 21,
onSideEnd(side) {
this.add('-sideend', side, 'Reflect');
},
},
@@ -584,9 +584,9 @@ export const Moves: {[k: string]: ModdedMoveData} = {
} else {
this.add('-status', target, 'slp', '[from] move: Rest');
}
target.statusData.time = 3;
target.statusData.startTime = 3;
target.statusData.source = target;
target.statusState.time = 3;
target.statusState.startTime = 3;
target.statusState.source = target;
this.heal(target.maxhp);
},
secondary: null,
@@ -671,10 +671,10 @@ export const Moves: {[k: string]: ModdedMoveData} = {
inherit: true,
condition: {
// this is a side condition
onStart(side) {
if (!this.effectData.layers || this.effectData.layers === 0) {
onSideStart(side) {
if (!this.effectState.layers || this.effectState.layers === 0) {
this.add('-sidestart', side, 'Spikes');
this.effectData.layers = 1;
this.effectState.layers = 1;
} else {
return false;
}
@@ -682,7 +682,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
onSwitchIn(pokemon) {
if (!pokemon.runImmunity('Ground')) return;
const damageAmounts = [0, 3];
this.damage(damageAmounts[this.effectData.layers] * pokemon.maxhp / 24);
this.damage(damageAmounts[this.effectState.layers] * pokemon.maxhp / 24);
},
},
},
@@ -691,7 +691,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectData.hp = Math.floor(target.maxhp / 4);
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryPrimaryHitPriority: -1,

View File

@@ -51,12 +51,12 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
this.add('-status', target, 'slp');
}
// 1-4 turns, guaranteed 1 turn of sleep.
this.effectData.time = this.random(2, 5);
this.effectState.time = this.random(2, 5);
},
onBeforeMovePriority: 10,
onBeforeMove(pokemon, target, move) {
pokemon.statusData.time--;
if (pokemon.statusData.time <= 0) {
pokemon.statusState.time--;
if (pokemon.statusState.time <= 0) {
pokemon.cureStatus();
return;
}
@@ -76,7 +76,7 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
} else {
this.add('-start', target, 'confusion');
}
this.effectData.time = this.random(2, 6);
this.effectState.time = this.random(2, 6);
},
onBeforeMove(pokemon, target, move) {
pokemon.volatiles['confusion'].time--;

View File

@@ -515,7 +515,7 @@ export const Scripts: ModdedBattleScriptsData = {
this.add('faint', pokemon);
pokemon.side.pokemonLeft--;
this.runEvent('Faint', pokemon, faintData.source, faintData.effect);
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityData, pokemon);
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityState, pokemon);
pokemon.clearVolatile(false);
pokemon.fainted = true;
pokemon.isActive = false;

View File

@@ -80,8 +80,8 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
lightningrod: {
onFoeRedirectTarget(target, source, source2, move) {
if (move.type !== 'Electric') return;
if (this.validTarget(this.effectData.target, source, move.target)) {
return this.effectData.target;
if (this.validTarget(this.effectState.target, source, move.target)) {
return this.effectState.target;
}
},
name: "Lightning Rod",

View File

@@ -9,30 +9,30 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
this.add('-status', target, 'slp');
}
// 1-4 turns
this.effectData.time = this.random(2, 6);
this.effectState.time = this.random(2, 6);
// Turns spent using Sleep Talk/Snore immediately before switching out while asleep
this.effectData.skippedTime = 0;
this.effectState.skippedTime = 0;
},
onSwitchIn(target) {
this.effectData.time += this.effectData.skippedTime;
this.effectData.skippedTime = 0;
this.effectState.time += this.effectState.skippedTime;
this.effectState.skippedTime = 0;
},
onBeforeMovePriority: 10,
onBeforeMove(pokemon, target, move) {
if (pokemon.hasAbility('earlybird')) {
pokemon.statusData.time--;
pokemon.statusState.time--;
}
pokemon.statusData.time--;
if (pokemon.statusData.time <= 0) {
pokemon.statusState.time--;
if (pokemon.statusState.time <= 0) {
pokemon.cureStatus();
return;
}
this.add('cant', pokemon, 'slp');
if (move.sleepUsable) {
this.effectData.skippedTime++;
this.effectState.skippedTime++;
return;
}
this.effectData.skippedTime = 0;
this.effectState.skippedTime = 0;
return false;
},
},

View File

@@ -35,23 +35,23 @@ export const Moves: {[k: string]: ModdedMoveData} = {
duration: 3,
onLockMove: 'bide',
onStart(pokemon) {
this.effectData.totalDamage = 0;
this.effectState.totalDamage = 0;
this.add('-start', pokemon, 'move: Bide');
},
onDamagePriority: -101,
onDamage(damage, target, source, move) {
if (!move || move.effectType !== 'Move' || !source) return;
this.effectData.totalDamage += damage;
this.effectData.lastDamageSource = source;
this.effectState.totalDamage += damage;
this.effectState.lastDamageSource = source;
},
onBeforeMove(pokemon, target, move) {
if (this.effectData.duration === 1) {
if (this.effectState.duration === 1) {
this.add('-end', pokemon, 'move: Bide');
if (!this.effectData.totalDamage) {
if (!this.effectState.totalDamage) {
this.add('-fail', pokemon);
return false;
}
target = this.effectData.lastDamageSource;
target = this.effectState.lastDamageSource;
if (!target) {
this.add('-fail', pokemon);
return false;
@@ -68,7 +68,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
id: 'bide' as ID,
name: "Bide",
accuracy: 100,
damage: this.effectData.totalDamage * 2,
damage: this.effectState.totalDamage * 2,
category: "Physical",
priority: 0,
flags: {contact: 1, protect: 1},
@@ -127,19 +127,19 @@ export const Moves: {[k: string]: ModdedMoveData} = {
duration: 1,
noCopy: true,
onStart(target, source, move) {
this.effectData.slot = null;
this.effectData.damage = 0;
this.effectState.slot = null;
this.effectState.damage = 0;
},
onRedirectTargetPriority: -1,
onRedirectTarget(target, source, source2) {
if (source !== this.effectData.target || !this.effectData.slot) return;
return this.getAtSlot(this.effectData.slot);
if (source !== this.effectState.target || !this.effectState.slot) return;
return this.getAtSlot(this.effectState.slot);
},
onDamagePriority: -101,
onDamage(damage, target, source, effect) {
if (effect.effectType === 'Move' && !source.isAlly(target) && this.getCategory(effect.id) === 'Physical') {
this.effectData.slot = source.getSlot();
this.effectData.damage = 2 * damage;
this.effectState.slot = source.getSlot();
this.effectState.damage = 2 * damage;
}
},
},
@@ -173,7 +173,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
noCopy: true,
onStart(pokemon) {
if (!this.queue.willMove(pokemon)) {
this.effectData.duration++;
this.effectState.duration++;
}
if (!pokemon.lastMove) {
return false;
@@ -184,7 +184,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return false;
} else {
this.add('-start', pokemon, 'Disable', moveSlot.move);
this.effectData.move = pokemon.lastMove.id;
this.effectState.move = pokemon.lastMove.id;
return;
}
}
@@ -195,14 +195,14 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.add('-end', pokemon, 'move: Disable');
},
onBeforeMove(attacker, defender, move) {
if (move.id === this.effectData.move) {
if (move.id === this.effectState.move) {
this.add('cant', attacker, 'Disable', move);
return false;
}
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === this.effectData.move) {
if (moveSlot.id === this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
@@ -265,20 +265,20 @@ export const Moves: {[k: string]: ModdedMoveData} = {
// it failed
return false;
}
this.effectData.move = target.lastMove.id;
this.effectState.move = target.lastMove.id;
this.add('-start', target, 'Encore');
if (!this.queue.willMove(target)) {
this.effectData.duration++;
this.effectState.duration++;
}
},
onOverrideAction(pokemon) {
return this.effectData.move;
return this.effectState.move;
},
onResidualOrder: 13,
onResidual(target) {
if (
target.moves.includes(this.effectData.move) &&
target.moveSlots[target.moves.indexOf(this.effectData.move)].pp <= 0
target.moves.includes(this.effectState.move) &&
target.moveSlots[target.moves.indexOf(this.effectState.move)].pp <= 0
) {
// early termination if you run out of PP
target.removeVolatile('encore');
@@ -288,11 +288,11 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectData.move || !pokemon.hasMove(this.effectData.move)) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectData.move) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
@@ -403,19 +403,19 @@ export const Moves: {[k: string]: ModdedMoveData} = {
duration: 1,
noCopy: true,
onStart(target, source, move) {
this.effectData.slot = null;
this.effectData.damage = 0;
this.effectState.slot = null;
this.effectState.damage = 0;
},
onRedirectTargetPriority: -1,
onRedirectTarget(target, source, source2) {
if (source !== this.effectData.target || !this.effectData.slot) return;
return this.getAtSlot(this.effectData.slot);
if (source !== this.effectState.target || !this.effectState.slot) return;
return this.getAtSlot(this.effectState.slot);
},
onDamagePriority: -101,
onDamage(damage, target, source, effect) {
if (effect.effectType === 'Move' && !source.isAlly(target) && this.getCategory(effect.id) === 'Special') {
this.effectData.slot = source.getSlot();
this.effectData.damage = 2 * damage;
this.effectState.slot = source.getSlot();
this.effectState.damage = 2 * damage;
}
},
},
@@ -539,16 +539,16 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
noCopy: true,
onStart(target) {
this.effectData.layers = 1;
this.add('-start', target, 'stockpile' + this.effectData.layers);
this.effectState.layers = 1;
this.add('-start', target, 'stockpile' + this.effectState.layers);
},
onRestart(target) {
if (this.effectData.layers >= 3) return false;
this.effectData.layers++;
this.add('-start', target, 'stockpile' + this.effectData.layers);
if (this.effectState.layers >= 3) return false;
this.effectState.layers++;
this.add('-start', target, 'stockpile' + this.effectState.layers);
},
onEnd(target) {
this.effectData.layers = 0;
this.effectState.layers = 0;
this.add('-end', target, 'Stockpile');
},
},

View File

@@ -58,7 +58,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
onDamagingHit(damage, target, source, move) {
if (damage && move.flags['contact']) {
if (this.randomChance(3, 10)) {
source.addVolatile('attract', this.effectData.target);
source.addVolatile('attract', this.effectState.target);
}
}
},

View File

@@ -18,15 +18,15 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
this.add('-status', target, 'slp');
}
// 1-4 turns
this.effectData.time = this.random(2, 6);
this.effectState.time = this.random(2, 6);
},
onBeforeMovePriority: 10,
onBeforeMove(pokemon, target, move) {
if (pokemon.hasAbility('earlybird')) {
pokemon.statusData.time--;
pokemon.statusState.time--;
}
pokemon.statusData.time--;
if (pokemon.statusData.time <= 0) {
pokemon.statusState.time--;
if (pokemon.statusState.time <= 0) {
pokemon.cureStatus();
return;
}

View File

@@ -108,12 +108,12 @@ export const Items: {[k: string]: ModdedItemData} = {
duration: 1,
onDamage(damage, target, source, effect) {
if (effect && effect.effectType === 'Move' && damage >= target.hp) {
this.effectData.activated = true;
this.effectState.activated = true;
return target.hp - 1;
}
},
onAfterMoveSecondary(target) {
if (this.effectData.activated) target.useItem();
if (this.effectState.activated) target.useItem();
target.removeVolatile('focussash');
},
},
@@ -227,8 +227,8 @@ export const Items: {[k: string]: ModdedItemData} = {
inherit: true,
condition: {
onStart(pokemon) {
this.effectData.numConsecutive = 0;
this.effectData.lastMove = '';
this.effectState.numConsecutive = 0;
this.effectState.lastMove = '';
},
onTryMovePriority: -2,
onTryMove(pokemon, target, move) {
@@ -236,15 +236,15 @@ export const Items: {[k: string]: ModdedItemData} = {
pokemon.removeVolatile('metronome');
return;
}
if (this.effectData.lastMove === move.id && pokemon.moveLastTurnResult) {
this.effectData.numConsecutive++;
if (this.effectState.lastMove === move.id && pokemon.moveLastTurnResult) {
this.effectState.numConsecutive++;
} else {
this.effectData.numConsecutive = 0;
this.effectState.numConsecutive = 0;
}
this.effectData.lastMove = move.id;
this.effectState.lastMove = move.id;
},
onModifyDamagePhase2(damage, source, target, move) {
return damage * (1 + (this.effectData.numConsecutive / 10));
return damage * (1 + (this.effectState.numConsecutive / 10));
},
},
},

View File

@@ -94,14 +94,14 @@ export const Moves: {[k: string]: ModdedMoveData} = {
duration: 3,
onLockMove: 'bide',
onStart(pokemon) {
this.effectData.totalDamage = 0;
this.effectState.totalDamage = 0;
this.add('-start', pokemon, 'move: Bide');
},
onDamagePriority: -101,
onDamage(damage, target, source, move) {
if (!move || move.effectType !== 'Move' || !source) return;
this.effectData.totalDamage += damage;
this.effectData.lastDamageSource = source;
this.effectState.totalDamage += damage;
this.effectState.lastDamageSource = source;
},
onAfterSetStatus(status, pokemon) {
if (status.id === 'slp' || status.id === 'frz') {
@@ -109,13 +109,13 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
},
onBeforeMove(pokemon, target, move) {
if (this.effectData.duration === 1) {
if (this.effectState.duration === 1) {
this.add('-end', pokemon, 'move: Bide');
if (!this.effectData.totalDamage) {
if (!this.effectState.totalDamage) {
this.add('-fail', pokemon);
return false;
}
target = this.effectData.lastDamageSource;
target = this.effectState.lastDamageSource;
if (!target) {
this.add('-fail', pokemon);
return false;
@@ -132,7 +132,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
id: 'bide',
name: "Bide",
accuracy: true,
damage: this.effectData.totalDamage * 2,
damage: this.effectState.totalDamage * 2,
category: "Physical",
priority: 1,
flags: {contact: 1, protect: 1},
@@ -294,7 +294,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
noCopy: true,
onStart(pokemon) {
if (!this.queue.willMove(pokemon)) {
this.effectData.duration++;
this.effectState.duration++;
}
if (!pokemon.lastMove) {
return false;
@@ -305,7 +305,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return false;
} else {
this.add('-start', pokemon, 'Disable', moveSlot.move);
this.effectData.move = pokemon.lastMove.id;
this.effectState.move = pokemon.lastMove.id;
return;
}
}
@@ -317,14 +317,14 @@ export const Moves: {[k: string]: ModdedMoveData} = {
},
onBeforeMovePriority: 7,
onBeforeMove(attacker, defender, move) {
if (move.id === this.effectData.move) {
if (move.id === this.effectState.move) {
this.add('cant', attacker, 'Disable', move);
return false;
}
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === this.effectData.move) {
if (moveSlot.id === this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
@@ -409,20 +409,20 @@ export const Moves: {[k: string]: ModdedMoveData} = {
// it failed
return false;
}
this.effectData.move = target.lastMove.id;
this.effectState.move = target.lastMove.id;
this.add('-start', target, 'Encore');
if (!this.queue.willMove(target)) {
this.effectData.duration++;
this.effectState.duration++;
}
},
onOverrideAction(pokemon) {
return this.effectData.move;
return this.effectState.move;
},
onResidualOrder: 13,
onResidual(target) {
if (
target.moves.includes(this.effectData.move) &&
target.moveSlots[target.moves.indexOf(this.effectData.move)].pp <= 0
target.moves.includes(this.effectState.move) &&
target.moveSlots[target.moves.indexOf(this.effectState.move)].pp <= 0
) {
// early termination if you run out of PP
target.removeVolatile('encore');
@@ -432,11 +432,11 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectData.move || !pokemon.hasMove(this.effectData.move)) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectData.move) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
@@ -522,13 +522,13 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
duration: 2,
onStart() {
this.effectData.multiplier = 1;
this.effectState.multiplier = 1;
},
onRestart() {
if (this.effectData.multiplier < 16) {
this.effectData.multiplier <<= 1;
if (this.effectState.multiplier < 16) {
this.effectState.multiplier <<= 1;
}
this.effectData.duration = 2;
this.effectState.duration = 2;
},
},
},
@@ -717,7 +717,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return 5;
},
onAnyModifyDamagePhase1(damage, source, target, move) {
if (target !== source && this.effectData.target.hasAlly(target) && this.getCategory(move) === 'Special') {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Special') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) {
this.debug('Light Screen weaken');
if (target.alliesAndSelf().length > 1) return this.chainModify(2, 3);
@@ -725,11 +725,11 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
}
},
onStart(side) {
onSideStart(side) {
this.add('-sidestart', side, 'Light Screen');
},
onResidualOrder: 21,
onEnd(side) {
onSideResidualOrder: 21,
onSideEnd(side) {
this.add('-sideend', side, 'Light Screen');
},
},
@@ -740,10 +740,10 @@ export const Moves: {[k: string]: ModdedMoveData} = {
duration: 2,
onSourceInvulnerabilityPriority: 1,
onSourceInvulnerability(target, source, move) {
if (move && source === this.effectData.target && target === this.effectData.source) return 0;
if (move && source === this.effectState.target && target === this.effectState.source) return 0;
},
onSourceAccuracy(accuracy, target, source, move) {
if (move && source === this.effectData.target && target === this.effectData.source) return true;
if (move && source === this.effectState.target && target === this.effectState.source) return true;
},
},
},
@@ -759,12 +759,12 @@ export const Moves: {[k: string]: ModdedMoveData} = {
},
condition: {
duration: 1,
onStart(side) {
onSideStart(side) {
this.debug('Lunar Dance started on ' + side.name);
},
onSwitchInPriority: -1,
onSwitchIn(target) {
if (target.getSlot() !== this.effectData.sourceSlot) {
if (target.getSlot() !== this.effectState.sourceSlot) {
return;
}
if (target.hp > 0) {
@@ -1028,7 +1028,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return 5;
},
onAnyModifyDamagePhase1(damage, source, target, move) {
if (target !== source && this.effectData.target.hasAlly(target) && this.getCategory(move) === 'Physical') {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Physical') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) {
this.debug('Reflect weaken');
if (target.alliesAndSelf().length > 1) return this.chainModify(2, 3);
@@ -1036,11 +1036,11 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
}
},
onStart(side) {
onSideStart(side) {
this.add('-sidestart', side, 'Reflect');
},
onResidualOrder: 21,
onEnd(side) {
onSideResidualOrder: 21,
onSideEnd(side) {
this.add('-sideend', side, 'Reflect');
},
},
@@ -1166,7 +1166,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectData.hp = Math.floor(target.maxhp / 4);
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryPrimaryHitPriority: -1,
@@ -1255,15 +1255,15 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
return 3;
},
onStart(side) {
onSideStart(side) {
this.add('-sidestart', side, 'move: Tailwind');
},
onModifySpe(spe) {
return spe * 2;
},
onResidualOrder: 21,
onResidualSubOrder: 4,
onEnd(side) {
onSideResidualOrder: 21,
onSideResidualSubOrder: 4,
onSideEnd(side) {
this.add('-sideend', side, 'move: Tailwind');
},
},
@@ -1317,14 +1317,14 @@ export const Moves: {[k: string]: ModdedMoveData} = {
flags: {},
condition: {
// this is a side condition
onStart(side) {
onSideStart(side) {
this.add('-sidestart', side, 'move: Toxic Spikes');
this.effectData.layers = 1;
this.effectState.layers = 1;
},
onRestart(side) {
if (this.effectData.layers >= 2) return false;
onSideRestart(side) {
if (this.effectState.layers >= 2) return false;
this.add('-sidestart', side, 'move: Toxic Spikes');
this.effectData.layers++;
this.effectState.layers++;
},
onSwitchIn(pokemon) {
if (!pokemon.isGrounded()) return;
@@ -1333,7 +1333,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
pokemon.side.removeSideCondition('toxicspikes');
} else if (pokemon.volatiles['substitute'] || pokemon.hasType('Steel')) {
return;
} else if (this.effectData.layers >= 2) {
} else if (this.effectState.layers >= 2) {
pokemon.trySetStatus('tox', pokemon.side.foe.active[0]);
} else {
pokemon.trySetStatus('psn', pokemon.side.foe.active[0]);
@@ -1384,7 +1384,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
onResidualOrder: 0.5,
onEnd(target) {
if (!target.fainted) {
const source = this.effectData.source;
const source = this.effectState.source;
const damage = this.heal(target.baseMaxhp / 2, target, target);
if (damage) this.add('-heal', target, target.getHealth, '[from] move: Wish', '[wisher] ' + source.name);
}

View File

@@ -2,22 +2,22 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
slp: {
inherit: true,
onSwitchIn(target) {
this.effectData.time = this.effectData.startTime;
this.effectState.time = this.effectState.startTime;
},
},
partiallytrapped: {
inherit: true,
onStart(pokemon, source) {
this.add('-activate', pokemon, 'move: ' + this.effectData.sourceEffect, '[of] ' + source);
this.effectData.boundDivisor = source.hasItem('bindingband') ? 8 : 16;
this.add('-activate', pokemon, 'move: ' + this.effectState.sourceEffect, '[of] ' + source);
this.effectState.boundDivisor = source.hasItem('bindingband') ? 8 : 16;
},
onResidual(pokemon) {
const trapper = this.effectData.source;
const trapper = this.effectState.source;
if (trapper && (!trapper.isActive || trapper.hp <= 0 || !trapper.activeTurns)) {
delete pokemon.volatiles['partiallytrapped'];
return;
}
this.damage(pokemon.baseMaxhp / this.effectData.boundDivisor);
this.damage(pokemon.baseMaxhp / this.effectState.boundDivisor);
},
},
stall: {
@@ -25,12 +25,12 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
duration: 2,
counterMax: 256,
onStart() {
this.effectData.counter = 2;
this.effectState.counter = 2;
},
onStallMove() {
// this.effectData.counter should never be undefined here.
// this.effectState.counter should never be undefined here.
// However, just in case, use 1 if it is undefined.
const counter = this.effectData.counter || 1;
const counter = this.effectState.counter || 1;
if (counter >= 256) {
// 2^32 - special-cased because Battle.random(n) can't handle n > 2^16 - 1
return (this.random() * 4294967296 < 1);
@@ -39,10 +39,10 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
return this.randomChance(1, counter);
},
onRestart() {
if (this.effectData.counter < (this.effect as Condition).counterMax!) {
this.effectData.counter *= 2;
if (this.effectState.counter < (this.effect as Condition).counterMax!) {
this.effectState.counter *= 2;
}
this.effectData.duration = 2;
this.effectState.duration = 2;
},
},
gem: {

View File

@@ -65,20 +65,20 @@ export const Moves: {[k: string]: ModdedMoveData} = {
noCopy: true, // doesn't get copied by Baton Pass
onStart(pokemon) {
if (pokemon.species.weighthg > 1) {
this.effectData.multiplier = 1;
this.effectState.multiplier = 1;
this.add('-start', pokemon, 'Autotomize');
}
},
onRestart(pokemon) {
if (pokemon.species.weighthg - (this.effectData.multiplier * 1000) > 1) {
this.effectData.multiplier++;
if (pokemon.species.weighthg - (this.effectState.multiplier * 1000) > 1) {
this.effectState.multiplier++;
this.add('-start', pokemon, 'Autotomize');
}
},
onModifyWeightPriority: 2,
onModifyWeight(weighthg, pokemon) {
if (this.effectData.multiplier) {
weighthg -= this.effectData.multiplier * 1000;
if (this.effectState.multiplier) {
weighthg -= this.effectState.multiplier * 1000;
if (weighthg < 1) weighthg = 1;
return weighthg;
}
@@ -266,13 +266,13 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
duration: 2,
onStart() {
this.effectData.multiplier = 1;
this.effectState.multiplier = 1;
},
onRestart() {
if (this.effectData.multiplier < 8) {
this.effectData.multiplier <<= 1;
if (this.effectState.multiplier < 8) {
this.effectState.multiplier <<= 1;
}
this.effectData.duration = 2;
this.effectState.duration = 2;
},
},
},
@@ -499,7 +499,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return 5;
},
onAnyModifyDamage(damage, source, target, move) {
if (target !== source && this.effectData.target.hasAlly(target) && this.getCategory(move) === 'Special') {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Special') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) {
this.debug('Light Screen weaken');
if (this.activePerHalf > 1) return this.chainModify([2703, 4096]);
@@ -507,12 +507,12 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
}
},
onStart(side) {
onSideStart(side) {
this.add('-sidestart', side, 'move: Light Screen');
},
onResidualOrder: 21,
onResidualSubOrder: 1,
onEnd(side) {
onSideResidualOrder: 21,
onSideResidualSubOrder: 1,
onSideEnd(side) {
this.add('-sideend', side, 'move: Light Screen');
},
},
@@ -700,7 +700,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return 5;
},
onAnyModifyDamage(damage, source, target, move) {
if (target !== source && this.effectData.target.hasAlly(target) && this.getCategory(move) === 'Physical') {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Physical') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) {
this.debug('Reflect weaken');
if (this.activePerHalf > 1) return this.chainModify([2703, 4096]);
@@ -708,11 +708,11 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
}
},
onStart(side) {
onSideStart(side) {
this.add('-sidestart', side, 'Reflect');
},
onResidualOrder: 21,
onEnd(side) {
onSideResidualOrder: 21,
onSideEnd(side) {
this.add('-sideend', side, 'Reflect');
},
},
@@ -865,7 +865,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectData.hp = Math.floor(target.maxhp / 4);
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryPrimaryHitPriority: -1,

View File

@@ -97,11 +97,11 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
symbiosis: {
inherit: true,
onAllyAfterUseItem(item, pokemon) {
const source = this.effectData.target;
const source = this.effectState.target;
const myItem = source.takeItem();
if (!myItem) return;
if (
!this.singleEvent('TakeItem', myItem, source.itemData, pokemon, source, this.effect, myItem) ||
!this.singleEvent('TakeItem', myItem, source.itemState, pokemon, source, this.effect, myItem) ||
!pokemon.setItem(myItem)
) {
source.item = myItem.id;

View File

@@ -40,18 +40,18 @@ export const Moves: {[k: string]: ModdedMoveData} = {
// it failed
return false;
}
this.effectData.move = target.lastMove.id;
this.effectState.move = target.lastMove.id;
this.add('-start', target, 'Encore');
if (!this.queue.willMove(target)) {
this.effectData.duration++;
this.effectState.duration++;
}
},
onOverrideAction(pokemon, target, move) {
if (move.id !== this.effectData.move) return this.effectData.move;
if (move.id !== this.effectState.move) return this.effectState.move;
},
onResidualOrder: 13,
onResidual(target) {
const lockedMoveIndex = target.moves.indexOf(this.effectData.move);
const lockedMoveIndex = target.moves.indexOf(this.effectState.move);
if (lockedMoveIndex >= 0 && target.moveSlots[lockedMoveIndex].pp <= 0) {
// Encore ends early if you run out of PP
target.removeVolatile('encore');
@@ -61,11 +61,11 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectData.move || !pokemon.hasMove(this.effectData.move)) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectData.move) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
@@ -134,16 +134,16 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return this.chainModify(0.5);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Misty Terrain', '[from] ability: ' + effect, '[of] ' + source);
} else {
this.add('-fieldstart', 'move: Misty Terrain');
}
},
onResidualOrder: 21,
onResidualSubOrder: 2,
onEnd(side) {
onFieldResidualOrder: 21,
onFieldResidualSubOrder: 2,
onFieldEnd() {
this.add('-fieldend', 'Misty Terrain');
},
},
@@ -192,19 +192,19 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
noCopy: true,
onStart(target) {
this.effectData.layers = 1;
this.add('-start', target, 'stockpile' + this.effectData.layers);
this.effectState.layers = 1;
this.add('-start', target, 'stockpile' + this.effectState.layers);
this.boost({def: 1, spd: 1}, target, target);
},
onRestart(target) {
if (this.effectData.layers >= 3) return false;
this.effectData.layers++;
this.add('-start', target, 'stockpile' + this.effectData.layers);
if (this.effectState.layers >= 3) return false;
this.effectState.layers++;
this.add('-start', target, 'stockpile' + this.effectState.layers);
this.boost({def: 1, spd: 1}, target, target);
},
onEnd(target) {
const layers = this.effectData.layers * -1;
this.effectData.layers = 0;
const layers = this.effectState.layers * -1;
this.effectState.layers = 0;
this.boost({def: layers, spd: layers}, target, target);
this.add('-end', target, 'Stockpile');
},

View File

@@ -1111,9 +1111,9 @@ export class RandomGen6Teams extends RandomGen7Teams {
if (teamData.megaCount && teamData.megaCount > 0 && itemData.megaStone) continue; // reject 2+ mega stones
if (itemsMax[itemData.id] && teamData.has[itemData.id] >= itemsMax[itemData.id]) continue;
const abilityData = this.dex.abilities.get(curSet.ability);
if (weatherAbilitiesRequire[abilityData.id] && teamData.weather !== weatherAbilitiesRequire[abilityData.id]) continue;
if (teamData.weather && weatherAbilities.includes(abilityData.id)) continue; // reject 2+ weather setters
const abilityState = this.dex.abilities.get(curSet.ability);
if (weatherAbilitiesRequire[abilityState.id] && teamData.weather !== weatherAbilitiesRequire[abilityState.id]) continue;
if (teamData.weather && weatherAbilities.includes(abilityState.id)) continue; // reject 2+ weather setters
let reject = false;
let hasRequiredMove = false;
@@ -1253,9 +1253,9 @@ export class RandomGen6Teams extends RandomGen7Teams {
teamData.has[itemData.id] = 1;
}
const abilityData = this.dex.abilities.get(set.ability);
if (abilityData.id in weatherAbilitiesSet) {
teamData.weather = weatherAbilitiesSet[abilityData.id];
const abilityState = this.dex.abilities.get(set.ability);
if (abilityState.id in weatherAbilitiesSet) {
teamData.weather = weatherAbilitiesSet[abilityState.id];
}
for (const move of set.moves) {
@@ -1273,7 +1273,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
for (const typeName of this.dex.types.names()) {
// Cover any major weakness (3+) with at least one resistance
if (teamData.resistances[typeName] >= 1) continue;
if (resistanceAbilities[abilityData.id]?.includes(typeName) || !this.dex.getImmunity(typeName, types)) {
if (resistanceAbilities[abilityState.id]?.includes(typeName) || !this.dex.getImmunity(typeName, types)) {
// Heuristic: assume that Pokemon with these abilities don't have (too) negative typing.
teamData.resistances[typeName] = (teamData.resistances[typeName] || 0) + 1;
if (teamData.resistances[typeName] >= 1) teamData.weaknesses[typeName] = 0;

View File

@@ -2,7 +2,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
disguise: {
inherit: true,
onUpdate(pokemon) {
if (['mimikyu', 'mimikyutotem'].includes(pokemon.species.id) && this.effectData.busted) {
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);
}

View File

@@ -202,16 +202,16 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return this.chainModify(1.5);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Electric Terrain', '[from] ability: ' + effect, '[of] ' + source);
} else {
this.add('-fieldstart', 'move: Electric Terrain');
}
},
onResidualOrder: 21,
onResidualSubOrder: 2,
onEnd() {
onFieldResidualOrder: 21,
onFieldResidualSubOrder: 2,
onFieldEnd() {
this.add('-fieldend', 'move: Electric Terrain');
},
},
@@ -292,16 +292,16 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return this.chainModify(1.5);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Grassy Terrain', '[from] ability: ' + effect, '[of] ' + source);
} else {
this.add('-fieldstart', 'move: Grassy Terrain');
}
},
onResidualOrder: 5,
onResidualSubOrder: 3,
onResidual() {
onFieldResidualOrder: 5,
onFieldResidualSubOrder: 3,
onFieldResidual() {
this.eachEvent('Terrain');
},
onTerrainPriority: 1,
@@ -311,8 +311,8 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.heal(pokemon.baseMaxhp / 16, pokemon, pokemon);
}
},
onEnd() {
if (!this.effectData.duration) this.eachEvent('Terrain');
onFieldEnd() {
if (!this.effectState.duration) this.eachEvent('Terrain');
this.add('-fieldend', 'move: Grassy Terrain');
},
},
@@ -679,16 +679,16 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return this.chainModify(1.5);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Psychic Terrain', '[from] ability: ' + effect, '[of] ' + source);
} else {
this.add('-fieldstart', 'move: Psychic Terrain');
}
},
onResidualOrder: 21,
onResidualSubOrder: 2,
onEnd() {
onFieldResidualOrder: 21,
onFieldResidualSubOrder: 2,
onFieldEnd() {
this.add('-fieldend', 'move: Psychic Terrain');
},
},
@@ -896,8 +896,8 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return false;
}
if (
(myItem && !this.singleEvent('TakeItem', myItem, source.itemData, target, source, move, myItem)) ||
(yourItem && !this.singleEvent('TakeItem', yourItem, target.itemData, source, target, move, yourItem))
(myItem && !this.singleEvent('TakeItem', myItem, source.itemState, target, source, move, myItem)) ||
(yourItem && !this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem))
) {
if (yourItem) target.item = yourItem.id;
if (myItem) source.item = myItem.id;
@@ -950,10 +950,10 @@ export const Moves: {[k: string]: ModdedMoveData} = {
duration: 1,
onSourceInvulnerabilityPriority: 1,
onSourceInvulnerability(target, source, move) {
if (move && source === this.effectData.target) return 0;
if (move && source === this.effectState.target) return 0;
},
onSourceAccuracy(accuracy, target, source, move) {
if (move && source === this.effectData.target) return true;
if (move && source === this.effectState.target) return true;
},
},
},
@@ -972,8 +972,8 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return false;
}
if (
(myItem && !this.singleEvent('TakeItem', myItem, source.itemData, target, source, move, myItem)) ||
(yourItem && !this.singleEvent('TakeItem', yourItem, target.itemData, source, target, move, yourItem))
(myItem && !this.singleEvent('TakeItem', myItem, source.itemState, target, source, move, myItem)) ||
(yourItem && !this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem))
) {
if (yourItem) target.item = yourItem.id;
if (myItem) source.item = myItem.id;

View File

@@ -1764,9 +1764,9 @@ export class RandomGen7Teams extends RandomTeams {
teamData.has[itemData.id] = 1;
}
const abilityData = this.dex.abilities.get(set.ability);
if (abilityData.id in weatherAbilitiesSet) {
teamData.weather = weatherAbilitiesSet[abilityData.id];
const abilityState = this.dex.abilities.get(set.ability);
if (abilityState.id in weatherAbilitiesSet) {
teamData.weather = weatherAbilitiesSet[abilityState.id];
}
for (const move of set.moves) {
@@ -1784,7 +1784,7 @@ export class RandomGen7Teams extends RandomTeams {
for (const typeName of this.dex.types.names()) {
// Cover any major weakness (3+) with at least one resistance
if (teamData.resistances[typeName] >= 1) continue;
if (resistanceAbilities[abilityData.id]?.includes(typeName) || !this.dex.getImmunity(typeName, types)) {
if (resistanceAbilities[abilityState.id]?.includes(typeName) || !this.dex.getImmunity(typeName, types)) {
// Heuristic: assume that Pokémon with these abilities don't have (too) negative typing.
teamData.resistances[typeName] = (teamData.resistances[typeName] || 0) + 1;
if (teamData.resistances[typeName] >= 1) teamData.weaknesses[typeName] = 0;
@@ -1997,9 +1997,9 @@ export class RandomGen7Teams extends RandomTeams {
}
teamData.has[itemData.id] = 1;
const abilityData = this.dex.abilities.get(set.ability);
if (abilityData.id in weatherAbilitiesSet) {
teamData.weather = weatherAbilitiesSet[abilityData.id];
const abilityState = this.dex.abilities.get(set.ability);
if (abilityState.id in weatherAbilitiesSet) {
teamData.weather = weatherAbilitiesSet[abilityState.id];
}
for (const move of set.moves) {
@@ -2017,7 +2017,7 @@ export class RandomGen7Teams extends RandomTeams {
for (const typeName of this.dex.types.names()) {
// Cover any major weakness (3+) with at least one resistance
if (teamData.resistances[typeName] >= 1) continue;
if (resistanceAbilities[abilityData.id]?.includes(typeName) || !this.dex.getImmunity(typeName, types)) {
if (resistanceAbilities[abilityState.id]?.includes(typeName) || !this.dex.getImmunity(typeName, types)) {
// Heuristic: assume that Pokémon with these abilities don't have (too) negative typing.
teamData.resistances[typeName] = (teamData.resistances[typeName] || 0) + 1;
if (teamData.resistances[typeName] >= 1) teamData.weaknesses[typeName] = 0;

View File

@@ -43,7 +43,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
move.weather = '';
move.onHit = function (target, source) {
this.field.setWeather(weather, source, this.dex.abilities.get('forecast'));
this.field.weatherData.duration = 0;
this.field.weatherState.duration = 0;
};
move.target = 'self';
}
@@ -172,7 +172,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
move.weather = '';
move.onHit = function (target, source) {
this.field.setWeather(weather, source, this.dex.abilities.get('flowergift'));
this.field.weatherData.duration = 0;
this.field.weatherState.duration = 0;
};
move.target = 'self';
move.sideCondition = 'flowergift';
@@ -180,13 +180,13 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
},
onUpdate(pokemon) {
if (this.field.isWeather(['sunnyday', 'desolateland'])) {
if (pokemon.isActive && pokemon.species.id === 'cherrim' && this.effectData.forme !== 'Sunshine') {
this.effectData.forme = 'Sunshine';
if (pokemon.isActive && pokemon.species.id === 'cherrim' && this.effectState.forme !== 'Sunshine') {
this.effectState.forme = 'Sunshine';
this.add('-formechange', pokemon, 'Cherrim-Sunshine', '[msg]');
this.boost({spd: 1});
}
} else if (pokemon.isActive && pokemon.species.id === 'cherrim' && this.effectData.forme) {
delete this.effectData.forme;
} else if (pokemon.isActive && pokemon.species.id === 'cherrim' && this.effectState.forme) {
delete this.effectState.forme;
this.add('-formechange', pokemon, 'Cherrim', '[msg]');
}
},
@@ -577,13 +577,13 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
this.add('-start', target, 'move: Imprison');
},
onFoeDisableMove(pokemon) {
for (const moveSlot of this.effectData.target.moveSlots) {
for (const moveSlot of this.effectState.target.moveSlots) {
pokemon.disableMove(moveSlot.id, 'hidden');
}
pokemon.maybeDisabled = true;
},
onFoeBeforeMove(attacker, defender, move) {
if (move.id !== 'struggle' && this.effectData.target.hasMove(move.id) && !move.isZ) {
if (move.id !== 'struggle' && this.effectState.target.hasMove(move.id) && !move.isZ) {
this.add('cant', attacker, 'move: Imprison', move);
return false;
}
@@ -673,7 +673,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
pokemon.removeVolatile('shadowtag');
},
onFoeMaybeTrapPokemon(pokemon, source) {
if (!source) source = this.effectData.target;
if (!source) source = this.effectState.target;
if (!source || !pokemon.isAdjacent(source)) return;
if (pokemon.ability !== 'shadowtag' && !source.volatiles['shadowtag']) {
pokemon.maybeTrapped = true;

View File

@@ -56,7 +56,7 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
} else {
this.add('-start', target, 'confusion');
}
this.effectData.time = this.random(3, 4);
this.effectState.time = this.random(3, 4);
},
onEnd(target) {
this.add('-end', target, 'confusion');
@@ -341,7 +341,7 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
move.weather = '';
move.onHit = function (target, source) {
this.field.setWeather(weather, source, this.dex.abilities.get('snowwarning'));
this.field.weatherData.duration = 0;
this.field.weatherState.duration = 0;
};
move.target = 'self';
}
@@ -364,7 +364,7 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
move.weather = '';
move.onHit = function (target, source) {
this.field.setWeather(weather, source, this.dex.abilities.get('sandstream'));
this.field.weatherData.duration = 0;
this.field.weatherState.duration = 0;
};
move.target = 'self';
}
@@ -378,7 +378,7 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
move.weather = '';
move.onHit = function (target, source) {
this.field.setWeather(weather, source, this.dex.abilities.get('drizzle'));
this.field.weatherData.duration = 0;
this.field.weatherState.duration = 0;
};
move.target = 'self';
}

View File

@@ -141,7 +141,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectData.hp = Math.floor(target.maxhp / 4);
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onAccuracyPriority: -100,
@@ -630,7 +630,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
onStart(pokemon) {
if (pokemon.removeVolatile('bidestall') || pokemon.hp <= 1) return false;
pokemon.addVolatile('bidestall');
this.effectData.totalDamage = 0;
this.effectState.totalDamage = 0;
this.add('-start', pokemon, 'Bide');
},
onDamagePriority: -11,
@@ -640,8 +640,8 @@ export const Moves: {[k: string]: ModdedMoveData} = {
if (effect.effectType === 'Move' && damage >= target.hp) {
damage = target.hp - 1;
}
this.effectData.totalDamage += damage;
this.effectData.sourceSlot = source.getSlot();
this.effectState.totalDamage += damage;
this.effectState.sourceSlot = source.getSlot();
return damage;
},
onAfterSetStatus(status, pokemon) {
@@ -651,16 +651,16 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
},
onBeforeMove(pokemon, t, move) {
if (this.effectData.duration === 1) {
if (!this.effectData.totalDamage) {
if (this.effectState.duration === 1) {
if (!this.effectState.totalDamage) {
this.add('-end', pokemon, 'Bide');
this.add('-fail', pokemon);
return false;
}
this.add('-end', pokemon, 'Bide');
const target = this.getAtSlot(this.effectData.sourceSlot);
const target = this.getAtSlot(this.effectState.sourceSlot);
const moveData = {
damage: this.effectData.totalDamage * 2,
damage: this.effectState.totalDamage * 2,
} as unknown as ActiveMove;
this.actions.moveHit(target, pokemon, this.dex.getActiveMove('bide'), moveData);
return false;
@@ -822,7 +822,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
inherit: true,
condition: {
// this is a side condition
onStart(side) {
onSideStart(side) {
this.add('-sidestart', side, 'move: Stealth Rock');
},
onSwitchIn(pokemon) {

View File

@@ -13,7 +13,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
if (target.hasType('Grass') && source && target !== source && effect && effect.id !== 'yawn') {
this.debug('interrupting setStatus with Flower Veil');
if (effect.id.endsWith('synchronize') || (effect.effectType === 'Move' && !effect.secondaries)) {
const effectHolder = this.effectData.target;
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Flower Veil', '[of] ' + effectHolder);
}
return null;
@@ -85,7 +85,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
// Ability suppression implemented in sim/pokemon.ts:Pokemon#ignoringAbility
onPreStart(pokemon) {
this.add('-ability', pokemon, 'Neutralizing Gas');
pokemon.abilityData.ending = false;
pokemon.abilityState.ending = false;
// Remove setter's innates before the ability starts
if (pokemon.m.innates) {
for (const innate of pokemon.m.innates) {
@@ -95,7 +95,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
}
for (const target of this.getAllActive()) {
if (target.illusion) {
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityData, target, pokemon, 'neutralizinggas');
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityState, target, pokemon, 'neutralizinggas');
}
if (target.volatiles['slowstart']) {
delete target.volatiles['slowstart'];
@@ -118,14 +118,14 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
// (If you're tackling this, do note extreme weathers have the same issue)
// Mark this pokemon's ability as ending so Pokemon#ignoringAbility skips it
if (source.abilityData.ending) return;
source.abilityData.ending = true;
if (source.abilityState.ending) return;
source.abilityState.ending = true;
const sortedActive = this.getAllActive();
this.speedSort(sortedActive);
for (const pokemon of sortedActive) {
if (pokemon !== source) {
// Will be suppressed by Pokemon#ignoringAbility if needed
this.singleEvent('Start', pokemon.getAbility(), pokemon.abilityData, pokemon);
this.singleEvent('Start', pokemon.getAbility(), pokemon.abilityState, pokemon);
if (pokemon.m.innates) {
for (const innate of pokemon.m.innates) {
// permanent abilities
@@ -158,7 +158,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
powerofalchemy: {
inherit: true,
onAllyFaint(ally) {
const pokemon = this.effectData.target;
const pokemon = this.effectState.target;
if (!pokemon.hp) return;
const isAbility = pokemon.ability === 'powerofalchemy';
let possibleAbilities = [ally.ability];
@@ -190,7 +190,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
receiver: {
inherit: true,
onAllyFaint(ally) {
const pokemon = this.effectData.target;
const pokemon = this.effectState.target;
if (!pokemon.hp) return;
const isAbility = pokemon.ability === 'receiver';
let possibleAbilities = [ally.ability];
@@ -223,7 +223,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
trace: {
inherit: true,
onUpdate(pokemon) {
if (!pokemon.isStarted || this.effectData.gaveUp) return;
if (!pokemon.isStarted || this.effectState.gaveUp) return;
const isAbility = pokemon.ability === 'trace';
const possibleTargets: Pokemon[] = pokemon.adjacentFoes();
while (possibleTargets.length) {

View File

@@ -22,14 +22,14 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
},
onUpdate(pokemon) {
if (this.effectData.source && !this.effectData.source.isActive && pokemon.volatiles['attract']) {
if (this.effectState.source && !this.effectState.source.isActive && pokemon.volatiles['attract']) {
this.debug('Removing Attract volatile on ' + pokemon);
pokemon.removeVolatile('attract');
}
},
onBeforeMovePriority: 2,
onBeforeMove(pokemon, target, move) {
this.add('-activate', pokemon, 'move: Attract', '[of] ' + this.effectData.source);
this.add('-activate', pokemon, 'move: Attract', '[of] ' + this.effectState.source);
if (this.randomChance(1, 2)) {
this.add('cant', pokemon, 'Attract');
return false;
@@ -46,7 +46,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
// Ability suppression implemented in Pokemon.ignoringAbility() within sim/pokemon.js
onStart(pokemon) {
this.add('-endability', pokemon);
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityData, pokemon, pokemon, 'gastroacid');
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityState, pokemon, pokemon, 'gastroacid');
if (pokemon.m.innates) {
for (const innate of pokemon.m.innates) {
pokemon.removeVolatile("ability:" + innate);
@@ -86,12 +86,12 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return null;
}
},
onStart(side) {
onSideStart(side) {
this.add('-sidestart', side, 'Safeguard');
},
onResidualOrder: 21,
onResidualSubOrder: 2,
onEnd(side) {
onSideResidualOrder: 21,
onSideResidualSubOrder: 2,
onSideEnd(side) {
this.add('-sideend', side, 'Safeguard');
},
},

View File

@@ -20,7 +20,7 @@ export const Scripts: ModdedBattleScriptsData = {
// can't use hasAbility because it would lead to infinite recursion
if (
(pokemon.ability === ('neutralizinggas' as ID) || pokemon.m.innates?.some((k: string) => k === 'neutralizinggas')) &&
!pokemon.volatiles['gastroacid'] && !pokemon.abilityData.ending
!pokemon.volatiles['gastroacid'] && !pokemon.abilityState.ending
) {
neutralizinggas = true;
break;

View File

@@ -13,7 +13,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
if (target.hasType('Grass') && source && target !== source && effect && effect.id !== 'yawn') {
this.debug('interrupting setStatus with Flower Veil');
if (effect.id.endsWith('synchronize') || (effect.effectType === 'Move' && !effect.secondaries)) {
const effectHolder = this.effectData.target;
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Flower Veil', '[of] ' + effectHolder);
}
return null;
@@ -52,11 +52,11 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
// Ability suppression implemented in sim/pokemon.ts:Pokemon#ignoringAbility
onPreStart(pokemon) {
this.add('-ability', pokemon, 'Neutralizing Gas');
pokemon.abilityData.ending = false;
pokemon.abilityState.ending = false;
// Remove setter's innates before the ability starts
for (const target of this.getAllActive()) {
if (target.illusion) {
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityData, target, pokemon, 'neutralizinggas');
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityState, target, pokemon, 'neutralizinggas');
}
if (target.volatiles['slowstart']) {
delete target.volatiles['slowstart'];
@@ -79,14 +79,14 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
// (If you're tackling this, do note extreme weathers have the same issue)
// Mark this pokemon's ability as ending so Pokemon#ignoringAbility skips it
if (source.abilityData.ending) return;
source.abilityData.ending = true;
if (source.abilityState.ending) return;
source.abilityState.ending = true;
const sortedActive = this.getAllActive();
this.speedSort(sortedActive);
for (const pokemon of sortedActive) {
if (pokemon !== source) {
// Will be suppressed by Pokemon#ignoringAbility if needed
this.singleEvent('Start', pokemon.getAbility(), pokemon.abilityData, pokemon);
this.singleEvent('Start', pokemon.getAbility(), pokemon.abilityState, pokemon);
}
if (pokemon.m.abils?.length) {
for (const innate of pokemon.m.abils) {
@@ -136,7 +136,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
trace: {
inherit: true,
onUpdate(pokemon) {
if (!pokemon.isStarted || this.effectData.gaveUp) return;
if (!pokemon.isStarted || this.effectState.gaveUp) return;
const isAbility = pokemon.ability === 'trace';
const additionalBannedAbilities = [

View File

@@ -22,14 +22,14 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
},
onUpdate(pokemon) {
if (this.effectData.source && !this.effectData.source.isActive && pokemon.volatiles['attract']) {
if (this.effectState.source && !this.effectState.source.isActive && pokemon.volatiles['attract']) {
this.debug('Removing Attract volatile on ' + pokemon);
pokemon.removeVolatile('attract');
}
},
onBeforeMovePriority: 2,
onBeforeMove(pokemon, target, move) {
this.add('-activate', pokemon, 'move: Attract', '[of] ' + this.effectData.source);
this.add('-activate', pokemon, 'move: Attract', '[of] ' + this.effectState.source);
if (this.randomChance(1, 2)) {
this.add('cant', pokemon, 'Attract');
return false;
@@ -46,7 +46,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
// Ability suppression implemented in Pokemon.ignoringAbility() within sim/pokemon.js
onStart(pokemon) {
this.add('-endability', pokemon);
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityData, pokemon, pokemon, 'gastroacid');
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityState, pokemon, pokemon, 'gastroacid');
const keys = Object.keys(pokemon.volatiles).filter(x => x.startsWith("ability:"));
if (keys.length) {
for (const abil of keys) {
@@ -87,12 +87,12 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return null;
}
},
onStart(side) {
onSideStart(side) {
this.add('-sidestart', side, 'Safeguard');
},
onResidualOrder: 21,
onResidualSubOrder: 2,
onEnd(side) {
onSideResidualOrder: 21,
onSideResidualSubOrder: 2,
onSideEnd(side) {
this.add('-sideend', side, 'Safeguard');
},
},

View File

@@ -26,7 +26,7 @@ export const Scripts: ModdedBattleScriptsData = {
// can't use hasAbility because it would lead to infinite recursion
if (
(pokemon.ability === ('neutralizinggas' as ID) || pokemon.m.abils?.includes('ability:neutralizinggas')) &&
!pokemon.volatiles['gastroacid'] && !pokemon.abilityData.ending
!pokemon.volatiles['gastroacid'] && !pokemon.abilityState.ending
) {
neutralizinggas = true;
break;

View File

@@ -286,11 +286,11 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
if (this.field.getWeather().id === 'heavyhailstorm' && !STRONG_WEATHERS.includes(weather.id)) return false;
},
onEnd(pokemon) {
if (this.field.weatherData.source !== pokemon) return;
if (this.field.weatherState.source !== pokemon) return;
for (const target of this.getAllActive()) {
if (target === pokemon) continue;
if (target.hasAbility('iceage')) {
this.field.weatherData.source = target;
this.field.weatherState.source = target;
return;
}
}
@@ -316,7 +316,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
desc: "This Pokemon blocks certain status moves and instead uses the move against the original user. This Pokemon ignores other Pokemon's Attack, Special Attack, and accuracy stat stages when taking damage, and ignores other Pokemon's Defense, Special Defense, and evasiveness stat stages when dealing damage.",
shortDesc: "Magic Bounce + Unaware.",
onAnyModifyBoost(boosts, pokemon) {
const unawareUser = this.effectData.target;
const unawareUser = this.effectState.target;
if (unawareUser === pokemon) return;
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
boosts['def'] = 0;
@@ -351,7 +351,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
newMove.hasBounced = true;
newMove.pranksterBoosted = false;
this.add('-ability', target, 'Carefree');
this.actions.useMove(newMove, this.effectData.target, source);
this.actions.useMove(newMove, this.effectState.target, source);
return null;
},
condition: {
@@ -376,11 +376,11 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
indomitable: {
desc: "This Pokemon cures itself if it is confused or has a major status condition. Single use.",
onUpdate(pokemon) {
if ((pokemon.status || pokemon.volatiles['confusion']) && !this.effectData.indomitableActivated) {
if ((pokemon.status || pokemon.volatiles['confusion']) && !this.effectState.indomitableActivated) {
this.add('-activate', pokemon, 'ability: Indomitable');
pokemon.cureStatus();
pokemon.removeVolatile('confusion');
this.effectData.indomitableActivated = true;
this.effectState.indomitableActivated = true;
}
},
name: "Indomitable",
@@ -418,7 +418,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
newMove.hasBounced = true;
newMove.pranksterBoosted = false;
this.add('-ability', target, 'Magic Hat');
this.actions.useMove(newMove, this.effectData.target, source);
this.actions.useMove(newMove, this.effectState.target, source);
return null;
},
condition: {
@@ -477,11 +477,11 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
if (this.field.getWeather().id === 'turbulence' && !STRONG_WEATHERS.includes(weather.id)) return false;
},
onEnd(pokemon) {
if (this.field.weatherData.source !== pokemon) return;
if (this.field.weatherState.source !== pokemon) return;
for (const target of this.getAllActive()) {
if (target === pokemon) continue;
if (target.hasAbility('turbulence')) {
this.field.weatherData.source = target;
this.field.weatherState.source = target;
return;
}
}
@@ -547,7 +547,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
}
},
onAnyModifyBoost(boosts, pokemon) {
const unawareUser = this.effectData.target;
const unawareUser = this.effectState.target;
if (unawareUser === pokemon) return;
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
boosts['def'] = 0;
@@ -634,8 +634,8 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
shortDesc: "Once per battle, heals 50% when 25% or lower.",
name: "Dragon Heart",
onUpdate(pokemon) {
if (pokemon.hp > 0 && pokemon.hp < pokemon.maxhp / 4 && !this.effectData.dragonheart) {
this.effectData.dragonheart = true;
if (pokemon.hp > 0 && pokemon.hp < pokemon.maxhp / 4 && !this.effectState.dragonheart) {
this.effectState.dragonheart = true;
this.heal(pokemon.maxhp / 2);
}
},
@@ -907,7 +907,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
}
},
onAnyWeatherStart() {
const pokemon = this.effectData.target;
const pokemon = this.effectState.target;
if (this.field.isWeather(['raindance', 'primordialsea'])) {
this.boost({def: 1, spd: 1, spe: -1}, pokemon, pokemon);
this.add('-message', `${pokemon.name} is rusting...`);
@@ -972,12 +972,12 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
if (!['Water', 'Electric'].includes(move.type) ||
['firepledge', 'grasspledge', 'waterpledge'].includes(move.id)) return;
const redirectTarget = ['randomNormal', 'adjacentFoe'].includes(move.target) ? 'normal' : move.target;
if (this.validTarget(this.effectData.target, source, redirectTarget)) {
if (this.validTarget(this.effectState.target, source, redirectTarget)) {
if (move.smartTarget) move.smartTarget = false;
if (this.effectData.target !== target) {
this.add('-activate', this.effectData.target, 'ability: Hydrostatic');
if (this.effectState.target !== target) {
this.add('-activate', this.effectState.target, 'ability: Hydrostatic');
}
return this.effectData.target;
return this.effectState.target;
}
},
name: "Hydrostatic",
@@ -1007,11 +1007,11 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
shortDesc: "This Pokemon's Sp. Atk is 1.5x, but it can only select the first move it executes.",
name: "Pollo Diablo",
onStart(pokemon) {
pokemon.abilityData.choiceLock = "";
pokemon.abilityState.choiceLock = "";
},
onBeforeMove(pokemon, target, move) {
if (move.isZOrMaxPowered || move.id === 'struggle') return;
if (pokemon.abilityData.choiceLock && pokemon.abilityData.choiceLock !== move.id) {
if (pokemon.abilityState.choiceLock && pokemon.abilityState.choiceLock !== move.id) {
this.addMove('move', pokemon, move.name);
this.attrLastMove('[still]');
this.debug("Disabled by Pollo Diablo");
@@ -1020,8 +1020,8 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
}
},
onModifyMove(move, pokemon) {
if (pokemon.abilityData.choiceLock || move.isZOrMaxPowered || move.id === 'struggle') return;
pokemon.abilityData.choiceLock = move.id;
if (pokemon.abilityState.choiceLock || move.isZOrMaxPowered || move.id === 'struggle') return;
pokemon.abilityState.choiceLock = move.id;
},
onModifySpAPriority: 1,
onModifySpA(spa, pokemon) {
@@ -1030,16 +1030,16 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
return this.chainModify(1.5);
},
onDisableMove(pokemon) {
if (!pokemon.abilityData.choiceLock) return;
if (!pokemon.abilityState.choiceLock) return;
if (pokemon.volatiles['dynamax']) return;
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== pokemon.abilityData.choiceLock) {
pokemon.disableMove(moveSlot.id, false, this.effectData.sourceEffect);
if (moveSlot.id !== pokemon.abilityState.choiceLock) {
pokemon.disableMove(moveSlot.id, false, this.effectState.sourceEffect);
}
}
},
onEnd(pokemon) {
pokemon.abilityData.choiceLock = "";
pokemon.abilityState.choiceLock = "";
},
gen: 8,
},
@@ -1115,8 +1115,8 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
shortDesc: "Once per battle, heals 50% when 25% or lower.",
name: "Second Wind",
onUpdate(pokemon) {
if (pokemon.hp > 0 && pokemon.hp < pokemon.maxhp / 4 && !this.effectData.dragonheart) {
this.effectData.dragonheart = true;
if (pokemon.hp > 0 && pokemon.hp < pokemon.maxhp / 4 && !this.effectState.dragonheart) {
this.effectState.dragonheart = true;
this.heal(pokemon.maxhp / 2);
}
},
@@ -1160,7 +1160,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
},
onFoeBasePowerPriority: 17,
onFoeBasePower(basePower, attacker, defender, move) {
if (this.effectData.target !== defender) return;
if (this.effectState.target !== defender) return;
if (move.type === 'Fire') {
return this.chainModify(1.25);
}
@@ -1232,7 +1232,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
return 5;
},
onAnyInvulnerability(target, source, move) {
if (move && (source === this.effectData.target || target === this.effectData.target)) return 0;
if (move && (source === this.effectState.target || target === this.effectState.target)) return 0;
},
onSourceAccuracy(accuracy) {
return true;
@@ -1257,7 +1257,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
return;
}
const dazzlingHolder = this.effectData.target;
const dazzlingHolder = this.effectState.target;
if ((source.isAlly(dazzlingHolder) || move.target === 'all') && move.priority > 0.1) {
this.attrLastMove('[still]');
this.add('-ability', dazzlingHolder, 'Dark Royalty');
@@ -1302,7 +1302,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
}
},
onSwitchOut(pokemon) {
if (this.effectData.happened) delete this.effectData.happened;
if (this.effectState.happened) delete this.effectState.happened;
},
onFoeAfterBoost(boost, target, source, effect) {
const pokemon = target.side.foe.active[0];
@@ -1316,9 +1316,9 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
// Infinite Loop preventer
if (effect && ['stubbornness'].includes(effect.id)) return;
if (success) {
if (!this.effectData.happened) {
if (!this.effectState.happened) {
this.boost({atk: 1, def: 1, spd: 1}, pokemon);
this.effectData.happened = true;
this.effectState.happened = true;
} else {
this.boost({atk: 1}, pokemon);
}
@@ -1441,7 +1441,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
}
},
onAnyModifyBoost(boosts, pokemon) {
const unawareUser = this.effectData.target;
const unawareUser = this.effectState.target;
if (unawareUser === pokemon) return;
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
boosts['def'] = 0;
@@ -1510,7 +1510,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
shortDesc: "Unaware + Prankster. Dark-types still immune to Prankster moves.",
name: "Plausible Deniability",
onAnyModifyBoost(boosts, pokemon) {
const unawareUser = this.effectData.target;
const unawareUser = this.effectState.target;
if (unawareUser === pokemon) return;
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
boosts['def'] = 0;
@@ -1545,11 +1545,11 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
if (this.field.getWeather().id === 'winterhail' && !STRONG_WEATHERS.includes(weather.id)) return false;
},
onEnd(pokemon) {
if (this.field.weatherData.source !== pokemon) return;
if (this.field.weatherState.source !== pokemon) return;
for (const target of this.getAllActive()) {
if (target === pokemon) continue;
if (target.hasAbility('winterhail')) {
this.field.weatherData.source = target;
this.field.weatherState.source = target;
return;
}
}
@@ -1797,26 +1797,26 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
boost[randomStat] = 1;
this.boost(boost);
}
if (this.effectData.immunities) return;
if (this.effectState.immunities) return;
const typeList = this.dex.types.names();
const firstTypeIndex = this.random(typeList.length);
const secondType = this.sample(typeList.slice(0, firstTypeIndex).concat(typeList.slice(firstTypeIndex + 1)));
this.effectData.immunities = [typeList[firstTypeIndex], secondType];
this.add('-start', pokemon, `${this.effectData.immunities[0]} Immunity`, '[silent]');
this.add('-start', pokemon, `${this.effectData.immunities[1]} Immunity`, '[silent]');
this.add("-message", `${pokemon.name} is now immune to ${this.effectData.immunities[0]} and ${this.effectData.immunities[1]} type attacks!`);
this.effectState.immunities = [typeList[firstTypeIndex], secondType];
this.add('-start', pokemon, `${this.effectState.immunities[0]} Immunity`, '[silent]');
this.add('-start', pokemon, `${this.effectState.immunities[1]} Immunity`, '[silent]');
this.add("-message", `${pokemon.name} is now immune to ${this.effectState.immunities[0]} and ${this.effectState.immunities[1]} type attacks!`);
},
onTryHit(target, source, move) {
if (target !== source && this.effectData.immunities?.includes(move.type)) {
if (target !== source && this.effectState.immunities?.includes(move.type)) {
this.add('-immune', target, '[from] ability: Shady Deal');
return null;
}
},
onEnd(pokemon) {
if (!this.effectData.immunities) return;
this.add('-end', pokemon, `${this.effectData.immunities[0]} Immunity`, '[silent]');
this.add('-end', pokemon, `${this.effectData.immunities[1]} Immunity`, '[silent]');
delete this.effectData.immunities;
if (!this.effectState.immunities) return;
this.add('-end', pokemon, `${this.effectState.immunities[0]} Immunity`, '[silent]');
this.add('-end', pokemon, `${this.effectState.immunities[1]} Immunity`, '[silent]');
delete this.effectState.immunities;
},
name: "Shady Deal",
gen: 8,
@@ -1837,7 +1837,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
desc: "This Pokemon ignores other Pokemon's stat stages when taking or doing damage. This Pokemon can poison or badly poison Pokemon regardless of their typing.",
shortDesc: "Unaware + Corrosion.",
onAnyModifyBoost(boosts, pokemon) {
const unawareUser = this.effectData.target;
const unawareUser = this.effectState.target;
if (unawareUser === pokemon) return;
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
boosts['def'] = 0;
@@ -1921,7 +1921,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
}
},
onAnyModifyBoost(boosts, pokemon) {
const unawareUser = this.effectData.target;
const unawareUser = this.effectState.target;
if (unawareUser === pokemon) return;
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
boosts['def'] = 0;
@@ -1959,7 +1959,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
onDamagingHit(damage, target, source, move) {
if (source.volatiles['leechseed']) return;
if (!move.isFutureMove) {
source.addVolatile('leechseed', this.effectData.target);
source.addVolatile('leechseed', this.effectState.target);
}
},
name: "Trillionage Roots",
@@ -1972,7 +1972,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
shortDesc: "Soul Heart + Weak moves get +25 BP. Moves can't defrost. Defrost moves go thru frz.",
onAnyFaintPriority: 1,
onAnyFaint() {
this.boost({spa: 1}, this.effectData.target);
this.boost({spa: 1}, this.effectState.target);
},
onAnyModifyMove(move, pokemon) {
if (move.thawsTarget) {
@@ -2045,10 +2045,10 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
if (
effect?.effectType === 'Move' &&
cosplayFormes.includes(target.species.id) && !target.transformed &&
!this.effectData.busted
!this.effectState.busted
) {
this.add('-activate', target, 'ability: Combat Training');
this.effectData.busted = true;
this.effectState.busted = true;
return 0;
}
},
@@ -2178,16 +2178,16 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
if (this.field.isWeather(['heavyhailstorm', 'hail', 'winterhail']) &&
pokemon.species.id === 'eiscuenoice' && !pokemon.transformed) {
this.add('-activate', pokemon, 'ability: Ice Face');
this.effectData.busted = false;
this.effectState.busted = false;
pokemon.formeChange('Eiscue', this.effect, true);
}
},
onAnyWeatherStart() {
const pokemon = this.effectData.target;
const pokemon = this.effectState.target;
if (this.field.isWeather(['heavyhailstorm', 'hail', 'winterhail']) &&
pokemon.species.id === 'eiscuenoice' && !pokemon.transformed) {
this.add('-activate', pokemon, 'ability: Ice Face');
this.effectData.busted = false;
this.effectState.busted = false;
pokemon.formeChange('Eiscue', this.effect, true);
}
},
@@ -2232,7 +2232,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
unaware: {
inherit: true,
onAnyModifyBoost(boosts, pokemon) {
const unawareUser = this.effectData.target;
const unawareUser = this.effectState.target;
if (unawareUser === pokemon) return;
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
boosts['def'] = 0;

View File

@@ -281,7 +281,7 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
shortDesc: "This Pokemon ignores other Pokemon's stat stages when taking or doing damage.",
// Unaware innate
onAnyModifyBoost(boosts, pokemon) {
const unawareUser = this.effectData.target;
const unawareUser = this.effectState.target;
if (unawareUser.illusion) return;
if (unawareUser === pokemon) return;
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
@@ -668,7 +668,7 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
},
// Unburden Innate
onAfterUseItem(item, pokemon) {
if (pokemon !== this.effectData.target) return;
if (pokemon !== this.effectState.target) return;
pokemon.addVolatile('unburden');
},
onTakeItem(item, pokemon) {
@@ -1833,7 +1833,7 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
return this.chainModify(1.5);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
this.add('-weather', 'Hail', '[from] ability: ' + effect, '[of] ' + source);
this.add('-message', 'The hail became extremely chilling!');
},
@@ -1851,17 +1851,17 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
});
}
},
onResidualOrder: 1,
onResidual() {
onFieldResidualOrder: 1,
onFieldResidual() {
this.add('-weather', 'Hail', '[upkeep]');
if (this.field.isWeather('heavyhailstorm')) this.eachEvent('Weather');
},
onWeather(target, source, effect) {
if (target.isAlly(this.effectData.source)) return;
if (target.isAlly(this.effectState.source)) return;
// Hail is stronger from Heavy Hailstorm
if (!target.hasType('Ice')) this.damage(target.baseMaxhp / 8);
},
onEnd() {
onFieldEnd() {
this.add('-weather', 'none');
},
},
@@ -1870,15 +1870,15 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
name: 'Winter Hail',
effectType: 'Weather',
duration: 0,
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
this.add('-weather', 'Hail', '[from] ability: ' + effect, '[of] ' + source);
this.add('-message', 'It became winter!');
},
onModifySpe(spe, pokemon) {
if (!pokemon.hasType('Ice')) return this.chainModify(0.5);
},
onResidualOrder: 1,
onResidual() {
onFieldResidualOrder: 1,
onFieldResidual() {
this.add('-weather', 'Hail', '[upkeep]');
if (this.field.isWeather('winterhail')) this.eachEvent('Weather');
},
@@ -1886,7 +1886,7 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
if (target.hasType('Ice')) return;
this.damage(target.baseMaxhp / 8);
},
onEnd() {
onFieldEnd() {
this.add('-weather', 'none');
},
},
@@ -1894,35 +1894,35 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
name: 'Raindrop',
noCopy: true,
onStart(target) {
this.effectData.layers = 1;
this.effectData.def = 0;
this.effectData.spd = 0;
this.effectState.layers = 1;
this.effectState.def = 0;
this.effectState.spd = 0;
this.add('-start', target, 'Raindrop');
this.add('-message', `${target.name} has ${this.effectData.layers} raindrop(s)!`);
this.add('-message', `${target.name} has ${this.effectState.layers} raindrop(s)!`);
const [curDef, curSpD] = [target.boosts.def, target.boosts.spd];
this.boost({def: 1, spd: 1}, target, target);
if (curDef !== target.boosts.def) this.effectData.def--;
if (curSpD !== target.boosts.spd) this.effectData.spd--;
if (curDef !== target.boosts.def) this.effectState.def--;
if (curSpD !== target.boosts.spd) this.effectState.spd--;
},
onRestart(target) {
this.effectData.layers++;
this.effectState.layers++;
this.add('-start', target, 'Raindrop');
this.add('-message', `${target.name} has ${this.effectData.layers} raindrop(s)!`);
this.add('-message', `${target.name} has ${this.effectState.layers} raindrop(s)!`);
const curDef = target.boosts.def;
const curSpD = target.boosts.spd;
this.boost({def: 1, spd: 1}, target, target);
if (curDef !== target.boosts.def) this.effectData.def--;
if (curSpD !== target.boosts.spd) this.effectData.spd--;
if (curDef !== target.boosts.def) this.effectState.def--;
if (curSpD !== target.boosts.spd) this.effectState.spd--;
},
onEnd(target) {
if (this.effectData.def || this.effectData.spd) {
if (this.effectState.def || this.effectState.spd) {
const boosts: SparseBoostsTable = {};
if (this.effectData.def) boosts.def = this.effectData.def;
if (this.effectData.spd) boosts.spd = this.effectData.spd;
if (this.effectState.def) boosts.def = this.effectState.def;
if (this.effectState.spd) boosts.spd = this.effectState.spd;
this.boost(boosts, target, target);
}
this.add('-end', target, 'Raindrop');
if (this.effectData.def !== this.effectData.layers * -1 || this.effectData.spd !== this.effectData.layers * -1) {
if (this.effectState.def !== this.effectState.layers * -1 || this.effectState.spd !== this.effectState.layers * -1) {
this.hint("Raindrop keeps track of how many times it successfully altered each stat individually.");
}
},
@@ -1994,7 +1994,7 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
degeneratormod: {
onBeforeSwitchOut(pokemon) {
let alreadyAdded = false;
for (const source of this.effectData.sources) {
for (const source of this.effectState.sources) {
if (!source.hp || source.volatiles['gastroacid']) continue;
if (!alreadyAdded) {
const foe = pokemon.side.foe.active[0];
@@ -2092,7 +2092,7 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
}.bind(this);
return;
}
const dazzlingHolder = this.effectData.target;
const dazzlingHolder = this.effectState.target;
if (!dazzlingHolder.set.shiny) return;
if (dazzlingHolder.species.id !== 'minior') return;
const targetAllExceptions = ['perishsong', 'flowershield', 'rototiller'];
@@ -2147,11 +2147,11 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
name: 'Turbulence',
effectType: 'Weather',
duration: 0,
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
this.add('-weather', 'DeltaStream', '[from] ability: ' + effect, '[of] ' + source);
},
onResidualOrder: 1,
onResidual() {
onFieldResidualOrder: 1,
onFieldResidual() {
this.add('-weather', 'DeltaStream', '[upkeep]');
this.eachEvent('Weather');
},
@@ -2176,7 +2176,7 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
}
this.field.clearTerrain();
},
onEnd() {
onFieldEnd() {
this.add('-weather', 'none');
},
},
@@ -2211,20 +2211,20 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
return this.chainModify(0.5);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
if (this.gen <= 5) this.effectData.duration = 0;
if (this.gen <= 5) this.effectState.duration = 0;
this.add('-weather', 'RainDance', '[from] ability: ' + effect, '[of] ' + source);
} else {
this.add('-weather', 'RainDance');
}
},
onResidualOrder: 1,
onResidual() {
onFieldResidualOrder: 1,
onFieldResidual() {
this.add('-weather', 'RainDance', '[upkeep]');
this.eachEvent('Weather');
},
onEnd() {
onFieldEnd() {
this.add('-weather', 'none');
},
},
@@ -2239,7 +2239,7 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
return 5;
},
onAnyModifyDamage(damage, source, target, move) {
if (target !== source && this.effectData.target.hasAlly(target)) {
if (target !== source && this.effectState.target.hasAlly(target)) {
if ((target.side.getSideCondition('reflect') && this.getCategory(move) === 'Physical') ||
(target.side.getSideCondition('lightscreen') && this.getCategory(move) === 'Special')) {
return;
@@ -2251,16 +2251,16 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
}
}
},
onStart(side) {
onSideStart(side) {
if (this.field.isTerrain('waveterrain')) {
this.add('-message', `Wave Terrain prevented Aurora Veil from starting!`);
return null;
}
this.add('-sidestart', side, 'move: Aurora Veil');
},
onResidualOrder: 21,
onResidualSubOrder: 1,
onEnd(side) {
onSideResidualOrder: 21,
onSideResidualSubOrder: 1,
onSideEnd(side) {
this.add('-sideend', side, 'move: Aurora Veil');
},
},
@@ -2274,7 +2274,7 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
return 5;
},
onAnyModifyDamage(damage, source, target, move) {
if (target !== source && this.effectData.target.hasAlly(target) && this.getCategory(move) === 'Special') {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Special') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) {
this.debug('Light Screen weaken');
if (this.activePerHalf > 1) return this.chainModify([2732, 4096]);
@@ -2282,16 +2282,16 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
}
}
},
onStart(side) {
onSideStart(side) {
if (this.field.isTerrain('waveterrain')) {
this.add('-message', `Wave Terrain prevented Light Screen from starting!`);
return null;
}
this.add('-sidestart', side, 'move: Light Screen');
},
onResidualOrder: 21,
onResidualSubOrder: 1,
onEnd(side) {
onSideResidualOrder: 21,
onSideResidualSubOrder: 1,
onSideEnd(side) {
this.add('-sideend', side, 'move: Light Screen');
},
},
@@ -2314,16 +2314,16 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
}
}
},
onStart(side) {
onSideStart(side) {
if (this.field.isTerrain('waveterrain')) {
this.add('-message', `Wave Terrain prevented Mist from starting!`);
return null;
}
this.add('-sidestart', side, 'move: Mist');
},
onResidualOrder: 21,
onResidualSubOrder: 3,
onEnd(side) {
onSideResidualOrder: 21,
onSideResidualSubOrder: 3,
onSideEnd(side) {
this.add('-sideend', side, 'Mist');
},
},
@@ -2337,7 +2337,7 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
return 5;
},
onAnyModifyDamage(damage, source, target, move) {
if (target !== source && this.effectData.target.hasAlly(target) && this.getCategory(move) === 'Physical') {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Physical') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) {
this.debug('Reflect weaken');
if (this.activePerHalf > 1) return this.chainModify([2732, 4096]);
@@ -2345,15 +2345,15 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
}
}
},
onStart(side) {
onSideStart(side) {
if (this.field.isTerrain('waveterrain')) {
this.add('-message', `Wave Terrain prevented Reflect from starting!`);
return null;
}
this.add('-sidestart', side, 'Reflect');
},
onResidualOrder: 21,
onEnd(side) {
onSideResidualOrder: 21,
onSideEnd(side) {
this.add('-sideend', side, 'Reflect');
},
},
@@ -2386,21 +2386,21 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
return null;
}
},
onStart(side) {
onSideStart(side) {
if (this.field.isTerrain('waveterrain')) {
this.add('-message', `Wave Terrain prevented Safeguard from starting!`);
return null;
}
this.add('-sidestart', side, 'move: Safeguard');
},
onResidualOrder: 21,
onResidualSubOrder: 2,
onEnd(side) {
onSideResidualOrder: 21,
onSideResidualSubOrder: 2,
onSideEnd(side) {
this.add('-sideend', side, 'Safeguard');
},
},
gmaxsteelsurge: {
onStart(side) {
onSideStart(side) {
if (this.field.isTerrain('waveterrain')) {
this.add('-message', `Wave Terrain prevented Steel Spikes from starting!`);
return null;
@@ -2421,29 +2421,29 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
},
spikes: {
name: "Spikes",
onStart(side) {
onSideStart(side) {
if (this.field.isTerrain('waveterrain')) {
this.add('-message', `Wave Terrain prevented Spikes from starting!`);
return null;
}
this.effectData.layers = 1;
this.effectState.layers = 1;
this.add('-sidestart', side, 'move: Spikes');
},
onRestart(side) {
if (this.effectData.layers >= 3) return false;
onSideRestart(side) {
if (this.effectState.layers >= 3) return false;
this.add('-sidestart', side, 'Spikes');
this.effectData.layers++;
this.effectState.layers++;
},
onSwitchIn(pokemon) {
if (!pokemon.isGrounded()) return;
if (pokemon.hasItem('heavydutyboots')) return;
const damageAmounts = [0, 3, 4, 6]; // 1/8, 1/6, 1/4
this.damage(damageAmounts[this.effectData.layers] * pokemon.maxhp / 24);
this.damage(damageAmounts[this.effectState.layers] * pokemon.maxhp / 24);
},
},
stealthrock: {
name: "Stealth Rock",
onStart(side) {
onSideStart(side) {
if (this.field.isTerrain('waveterrain')) {
this.add('-message', `Wave Terrain prevented Stealth Rock from starting!`);
return null;
@@ -2458,7 +2458,7 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
},
stickyweb: {
name: "Sticky Web",
onStart(side) {
onSideStart(side) {
if (this.field.isTerrain('waveterrain')) {
this.add('-message', `Wave Terrain prevented Sticky Web from starting!`);
return null;
@@ -2474,18 +2474,18 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
},
toxicspikes: {
name: "Toxic Spikes",
onStart(side) {
onSideStart(side) {
if (this.field.isTerrain('waveterrain')) {
this.add('-message', `Wave Terrain prevented Toxic Spikes from starting!`);
return null;
}
this.add('-sidestart', side, 'move: Toxic Spikes');
this.effectData.layers = 1;
this.effectState.layers = 1;
},
onRestart(side) {
if (this.effectData.layers >= 2) return false;
onSideRestart(side) {
if (this.effectState.layers >= 2) return false;
this.add('-sidestart', side, 'move: Toxic Spikes');
this.effectData.layers++;
this.effectState.layers++;
},
onSwitchIn(pokemon) {
if (!pokemon.isGrounded()) return;
@@ -2494,7 +2494,7 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
pokemon.side.removeSideCondition('toxicspikes');
} else if (pokemon.hasType('Steel') || pokemon.hasItem('heavydutyboots')) {
return;
} else if (this.effectData.layers >= 2) {
} else if (this.effectState.layers >= 2) {
pokemon.trySetStatus('tox', pokemon.side.foe.active[0]);
} else {
pokemon.trySetStatus('psn', pokemon.side.foe.active[0]);
@@ -2546,13 +2546,13 @@ export const Conditions: {[k: string]: ModdedConditionData & {innateName?: strin
echoedvoiceclone: {
duration: 2,
onStart() {
this.effectData.multiplier = 1;
this.effectState.multiplier = 1;
},
onRestart() {
if (this.effectData.duration !== 2) {
this.effectData.duration = 2;
if (this.effectData.multiplier < 5) {
this.effectData.multiplier++;
if (this.effectState.duration !== 2) {
this.effectState.duration = 2;
if (this.effectState.multiplier < 5) {
this.effectState.multiplier++;
}
}
},

View File

@@ -593,7 +593,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return this.chainModify(1.2);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Wave Terrain', '[from] ability: ' + effect, '[of] ' + source);
} else {
@@ -619,13 +619,13 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
this.add('-message', `Hazards were removed by the terrain!`);
},
onResidualOrder: 5,
onResidualSubOrder: 3,
onResidual() {
onFieldResidualOrder: 5,
onFieldResidualSubOrder: 3,
onFieldResidual() {
this.eachEvent('Terrain');
},
onEnd() {
if (!this.effectData.duration) this.eachEvent('Terrain');
onFieldEnd() {
if (!this.effectState.duration) this.eachEvent('Terrain');
this.add('-fieldend', 'move: Wave Terrain');
},
},
@@ -958,7 +958,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return 5;
},
// Stat modifying in scripts.ts
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Bane Terrain', '[from] ability: ' + effect, '[of] ' + source);
} else {
@@ -966,13 +966,13 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
this.add('-message', 'The battlefield suddenly became grim!');
},
onResidualOrder: 5,
onResidualSubOrder: 3,
onResidual() {
onFieldResidualOrder: 5,
onFieldResidualSubOrder: 3,
onFieldResidual() {
this.eachEvent('Terrain');
},
onEnd() {
if (!this.effectData.duration) this.eachEvent('Terrain');
onFieldEnd() {
if (!this.effectState.duration) this.eachEvent('Terrain');
this.add('-fieldend', 'move: Bane Terrain');
},
},
@@ -1401,14 +1401,14 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.attrLastMove('[still]');
},
onPrepareHit(target, source) {
const moveAnim = (!source.abilityData.busted || source.side.pokemonLeft === 1) ? 'Swords Dance' : 'Teleport';
const moveAnim = (!source.abilityState.busted || source.side.pokemonLeft === 1) ? 'Swords Dance' : 'Teleport';
this.add('-anim', source, moveAnim, target);
},
onHit(target, source) {
if (!source.abilityData.busted || source.side.pokemonLeft === 1) {
if (!source.abilityState.busted || source.side.pokemonLeft === 1) {
this.boost({atk: 2}, target);
} else {
delete source.abilityData.busted;
delete source.abilityState.busted;
if (source.species.baseSpecies === 'Mimikyu') source.formeChange('Mimikyu', this.effect, true);
source.switchFlag = true;
}
@@ -1644,13 +1644,13 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
duration: 2,
onStart() {
this.effectData.multiplier = 1;
this.effectState.multiplier = 1;
},
onRestart() {
if (this.effectData.duration !== 2) {
this.effectData.duration = 2;
if (this.effectData.multiplier < 5) {
this.effectData.multiplier++;
if (this.effectState.duration !== 2) {
this.effectState.duration = 2;
if (this.effectState.multiplier < 5) {
this.effectState.multiplier++;
}
}
},
@@ -2208,7 +2208,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.debug('Thehuntison start');
let alreadyAdded = false;
pokemon.removeVolatile('destinybond');
for (const source of this.effectData.sources) {
for (const source of this.effectState.sources) {
if (!this.queue.cancelMove(source) || !source.hp) continue;
if (!alreadyAdded) {
this.add('-activate', pokemon, 'move: The Hunt is On!');
@@ -2321,7 +2321,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.add('-start', pokemon, 'Cozy Cuddle');
},
onTrapPokemon(pokemon) {
if (this.effectData.source?.isActive) pokemon.tryTrap();
if (this.effectState.source?.isActive) pokemon.tryTrap();
},
},
secondary: null,
@@ -2376,15 +2376,15 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
duration: 1,
onSwitchIn(pokemon) {
if (!this.effectData.count) this.effectData.count = 1;
if (this.effectData.count < 3) {
if (!this.effectState.count) this.effectState.count = 1;
if (this.effectState.count < 3) {
pokemon.forceSwitchFlag = true;
this.effectData.count++;
this.effectState.count++;
return;
}
pokemon.side.removeSideCondition('gaelstrom');
},
onStart(side, source) {
onSideStart(side, source) {
side.addSideCondition(['spikes', 'toxicspikes', 'stealthrock', 'stickyweb'][this.random(4)], source);
},
},
@@ -2477,21 +2477,21 @@ export const Moves: {[k: string]: ModdedMoveData} = {
sideCondition: 'leaveittotheteam',
condition: {
duration: 2,
onStart(side, source) {
onSideStart(side, source) {
this.debug('Leave it to the team! started on ' + side.name);
this.effectData.positions = [];
this.effectState.positions = [];
for (const i of side.active.keys()) {
this.effectData.positions[i] = false;
this.effectState.positions[i] = false;
}
this.effectData.positions[source.position] = true;
this.effectState.positions[source.position] = true;
},
onRestart(side, source) {
this.effectData.positions[source.position] = true;
onSideRestart(side, source) {
this.effectState.positions[source.position] = true;
},
onSwitchInPriority: 1,
onSwitchIn(target) {
const positions: boolean[] = this.effectData.positions;
if (target.getSlot() !== this.effectData.sourceSlot) {
const positions: boolean[] = this.effectState.positions;
if (target.getSlot() !== this.effectState.sourceSlot) {
return;
}
if (!target.fainted) {
@@ -2570,7 +2570,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
},
onDamagePriority: -10,
onDamage(damage, target, source, effect) {
if (this.effectData.gotHit) return damage;
if (this.effectState.gotHit) return damage;
if (effect?.effectType === 'Move' && damage >= target.hp) {
this.add('-activate', target, 'move: Kip Up');
return target.hp - 1;
@@ -2578,20 +2578,20 @@ export const Moves: {[k: string]: ModdedMoveData} = {
},
onHit(pokemon, source, move) {
if (!pokemon.hp) return;
if (this.effectData.gotHit) return;
if (this.effectState.gotHit) return;
if (!pokemon.isAlly(source) && move.category !== 'Status') {
this.effectData.gotHit = true;
this.effectState.gotHit = true;
this.add('-message', 'Gossifleur was prepared for the impact!');
const boosts: {[k: string]: number} = {def: 2, spd: 2};
if (pokemon.boosts.def >= 1) boosts.def--;
if (pokemon.boosts.spd >= 1) boosts.spd--;
this.boost(boosts, pokemon);
this.add('-message', "Gossifleur did a Kip Up and can jump right back into the action!");
this.effectData.duration++;
this.effectState.duration++;
}
},
onModifyPriority(priority, pokemon, target, move) {
if (!this.effectData.gotHit) return priority;
if (!this.effectState.gotHit) return priority;
return priority + 1;
},
},
@@ -2824,16 +2824,16 @@ export const Moves: {[k: string]: ModdedMoveData} = {
sideCondition: 'nexthunt',
condition: {
duration: 1,
onStart(side, source) {
onSideStart(side, source) {
this.debug('/nexthunt started on ' + side.name);
this.effectData.positions = [];
this.effectState.positions = [];
for (const i of side.active.keys()) {
this.effectData.positions[i] = false;
this.effectState.positions[i] = false;
}
this.effectData.positions[source.position] = true;
this.effectState.positions[source.position] = true;
},
onRestart(side, source) {
this.effectData.positions[source.position] = true;
onSideRestart(side, source) {
this.effectState.positions[source.position] = true;
},
onSwitchInPriority: 1,
onSwitchIn(target) {
@@ -3076,11 +3076,11 @@ export const Moves: {[k: string]: ModdedMoveData} = {
condition: {
duration: 2,
onStart() {
this.effectData.counter = 2;
this.effectState.counter = 2;
},
onRestart() {
this.effectData.counter *= 2;
this.effectData.duration = 2;
this.effectState.counter *= 2;
this.effectState.duration = 2;
},
},
secondary: null,
@@ -3476,7 +3476,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
},
condition: {
onAnyFaint(target) {
if (target === this.effectData.targetPokemon) this.effectData.source.faint();
if (target === this.effectState.targetPokemon) this.effectState.source.faint();
},
},
secondary: null,
@@ -3657,7 +3657,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return this.chainModify(0.5);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Swampy Terrain', '[from] ability: ' + effect, '[of] ' + source);
} else {
@@ -3665,9 +3665,9 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
this.add('-message', 'The battlefield became swamped!');
},
onResidualOrder: 5,
onResidualSubOrder: 3,
onResidual() {
onFieldResidualOrder: 5,
onFieldResidualSubOrder: 3,
onFieldResidual() {
this.eachEvent('Terrain');
},
onTerrain(pokemon) {
@@ -3678,8 +3678,8 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
}
},
onEnd() {
if (!this.effectData.duration) this.eachEvent('Terrain');
onFieldEnd() {
if (!this.effectState.duration) this.eachEvent('Terrain');
this.add('-fieldend', 'move: Swampy Terrain');
},
},
@@ -3718,8 +3718,8 @@ export const Moves: {[k: string]: ModdedMoveData} = {
},
condition: {
onStart(pokemon) {
this.effectData.numConsecutive = 0;
this.effectData.lastMove = 'triplethreat';
this.effectState.numConsecutive = 0;
this.effectState.lastMove = 'triplethreat';
},
onTryMovePriority: -2,
onTryMove(pokemon, target, move) {
@@ -3727,19 +3727,19 @@ export const Moves: {[k: string]: ModdedMoveData} = {
pokemon.removeVolatile('triplethreat');
return;
}
if (this.effectData.lastMove === move.id) {
this.effectData.numConsecutive++;
if (this.effectState.lastMove === move.id) {
this.effectState.numConsecutive++;
} else {
this.effectData.numConsecutive = 0;
this.effectState.numConsecutive = 0;
}
if (this.effectData.numConsecutive >= 3) this.effectData.numConsecutive = 0;
this.effectData.lastMove = move.id;
if (this.effectState.numConsecutive >= 3) this.effectState.numConsecutive = 0;
this.effectState.lastMove = move.id;
},
onModifyMove(move) {
if (move.secondaries && move.id === 'triplethreat') {
const bpModif = [40, 60, 100];
const secModif = [10, 25, 40];
const numConsecutive = this.effectData.numConsecutive > 2 ? 2 : this.effectData.numConsecutive;
const numConsecutive = this.effectState.numConsecutive > 2 ? 2 : this.effectState.numConsecutive;
move.basePower = bpModif[numConsecutive];
for (const secondary of move.secondaries) {
if (secondary.chance) secondary.chance = secModif[numConsecutive];
@@ -3882,7 +3882,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
if (move && !this.dex.getImmunity(move, type)) return 1;
return -typeMod;
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Inversion Terrain', '[from] ability: ' + effect, '[of] ' + source);
} else {
@@ -3890,13 +3890,13 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
this.add('-message', 'The battlefield became upside down!');
},
onResidualOrder: 5,
onResidualSubOrder: 3,
onResidual() {
onFieldResidualOrder: 5,
onFieldResidualSubOrder: 3,
onFieldResidual() {
this.eachEvent('Terrain');
},
onEnd() {
if (!this.effectData.duration) this.eachEvent('Terrain');
onFieldEnd() {
if (!this.effectState.duration) this.eachEvent('Terrain');
this.add('-fieldend', 'move: Inversion Terrain');
},
},
@@ -4060,7 +4060,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.add('-message', `${target.name} got a boost by the terrain!`);
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Pitch Black Terrain', '[from] ability: ' + effect, '[of] ' + source);
} else {
@@ -4072,9 +4072,9 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.add('-message', `${source.name} got a boost by the terrain!`);
}
},
onResidualOrder: 5,
onResidualSubOrder: 3,
onResidual() {
onFieldResidualOrder: 5,
onFieldResidualSubOrder: 3,
onFieldResidual() {
this.eachEvent('Terrain');
},
onTerrain(pokemon) {
@@ -4084,7 +4084,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.add('-message', `${pokemon.name} was hurt by the terrain!`);
}
},
onEnd() {
onFieldEnd() {
this.add('-fieldend', 'move: Pitch Black Terrain');
},
},
@@ -4396,7 +4396,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
return this.random(5, 7);
},
onStart(target) {
this.effectData.origTypes = target.getTypes(); // store original types
this.effectState.origTypes = target.getTypes(); // store original types
if (target.getTypes().length === 1) { // single type mons
if (!target.addType('Flying')) return false;
this.add('-start', target, 'typeadd', 'Flying', '[from] move: Updraft');
@@ -4407,8 +4407,8 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
},
onEnd(target) {
if (!target.setType(this.effectData.origTypes)) return false; // reset the types
this.add('-start', target, 'typechange', this.effectData.origTypes.join('/'), '[silent]');
if (!target.setType(this.effectState.origTypes)) return false; // reset the types
this.add('-start', target, 'typechange', this.effectState.origTypes.join('/'), '[silent]');
},
},
secondary: {
@@ -4442,9 +4442,9 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
return 5;
},
onResidualOrder: 5,
onResidualSubOrder: 3,
onResidual() {
onFieldResidualOrder: 5,
onFieldResidualSubOrder: 3,
onFieldResidual() {
this.eachEvent('Terrain');
},
onTerrain(pokemon) {
@@ -4458,7 +4458,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
}
},
onStart(battle, source, effect) {
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Tempest Terrain', '[from] ability: ' + effect, '[of] ' + source);
} else {
@@ -4466,7 +4466,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
this.add('-message', 'The battlefield became stormy!');
},
onEnd() {
onFieldEnd() {
this.add('-fieldend', 'move: Tempest Terrain');
},
},
@@ -4723,16 +4723,16 @@ export const Moves: {[k: string]: ModdedMoveData} = {
sideCondition: 'herocreation',
condition: {
duration: 1,
onStart(side, source) {
onSideStart(side, source) {
this.debug('Hero Creation started on ' + side.name);
this.effectData.positions = [];
this.effectState.positions = [];
for (const i of side.active.keys()) {
this.effectData.positions[i] = false;
this.effectState.positions[i] = false;
}
this.effectData.positions[source.position] = true;
this.effectState.positions[source.position] = true;
},
onRestart(side, source) {
this.effectData.positions[source.position] = true;
onSideRestart(side, source) {
this.effectState.positions[source.position] = true;
},
onSwitchInPriority: 1,
onSwitchIn(target) {
@@ -5372,7 +5372,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
}
},
onUpdate(pokemon) {
if (this.effectData.source && !this.effectData.source.isActive && pokemon.volatiles['attract']) {
if (this.effectState.source && !this.effectState.source.isActive && pokemon.volatiles['attract']) {
this.debug('Removing Attract volatile on ' + pokemon);
pokemon.removeVolatile('attract');
}
@@ -5387,7 +5387,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
},
onBeforeMovePriority: 2,
onBeforeMove(pokemon, target, move) {
this.add('-activate', pokemon, 'move: Attract', '[of] ' + this.effectData.source);
this.add('-activate', pokemon, 'move: Attract', '[of] ' + this.effectState.source);
if (this.randomChance(1, 2)) {
this.add('cant', pokemon, 'Attract');
return false;

View File

@@ -183,7 +183,7 @@ export const Scripts: ModdedBattleScriptsData = {
if (zMove) {
if (pokemon.illusion) {
this.battle.singleEvent('End', this.dex.abilities.get('Illusion'), pokemon.abilityData, pokemon);
this.battle.singleEvent('End', this.dex.abilities.get('Illusion'), pokemon.abilityState, pokemon);
}
this.battle.add('-zpower', pokemon);
// In SSB Z-Moves are limited to 1 per pokemon.
@@ -912,7 +912,7 @@ export const Scripts: ModdedBattleScriptsData = {
}
}
const prevStatus = this.status;
const prevStatusData = this.statusData;
const prevStatusState = this.statusState;
if (status.id) {
const result: boolean = this.battle.runEvent('SetStatus', this, source, sourceEffect, status);
if (!result) {
@@ -922,18 +922,18 @@ export const Scripts: ModdedBattleScriptsData = {
}
this.status = status.id;
this.statusData = {id: status.id, target: this};
if (source) this.statusData.source = source;
if (status.duration) this.statusData.duration = status.duration;
this.statusState = {id: status.id, target: this};
if (source) this.statusState.source = source;
if (status.duration) this.statusState.duration = status.duration;
if (status.durationCallback) {
this.statusData.duration = status.durationCallback.call(this.battle, this, source, sourceEffect);
this.statusState.duration = status.durationCallback.call(this.battle, this, source, sourceEffect);
}
if (status.id && !this.battle.singleEvent('Start', status, this.statusData, this, source, sourceEffect)) {
if (status.id && !this.battle.singleEvent('Start', status, this.statusState, this, source, sourceEffect)) {
this.battle.debug('status start [' + status.id + '] interrupted');
// cancel the setstatus
this.status = prevStatus;
this.statusData = prevStatusData;
this.statusState = prevStatusState;
return false;
}
if (status.id && !this.battle.runEvent('AfterSetStatus', this, source, sourceEffect, status)) {

File diff suppressed because it is too large Load Diff

View File

@@ -2361,9 +2361,9 @@ export class RandomTeams {
teamData.has[itemData.id] = 1;
const abilityData = this.dex.abilities.get(set.ability);
if (abilityData.id in weatherAbilitiesSet) {
teamData.weather = weatherAbilitiesSet[abilityData.id];
const abilityState = this.dex.abilities.get(set.ability);
if (abilityState.id in weatherAbilitiesSet) {
teamData.weather = weatherAbilitiesSet[abilityState.id];
}
for (const move of set.moves) {
@@ -2381,7 +2381,7 @@ export class RandomTeams {
for (const typeName of this.dex.types.names()) {
// Cover any major weakness (3+) with at least one resistance
if (teamData.resistances[typeName] >= 1) continue;
if (resistanceAbilities[abilityData.id]?.includes(typeName) || !this.dex.getImmunity(typeName, types)) {
if (resistanceAbilities[abilityState.id]?.includes(typeName) || !this.dex.getImmunity(typeName, types)) {
// Heuristic: assume that Pokémon with these abilities don't have (too) negative typing.
teamData.resistances[typeName] = (teamData.resistances[typeName] || 0) + 1;
if (teamData.resistances[typeName] >= 1) teamData.weaknesses[typeName] = 0;

View File

@@ -406,7 +406,7 @@ export const Rulesets: {[k: string]: FormatData} = {
this.add('poke', pokemon.side.id, details, '');
}
},
onTeamPreview() {
onFieldTeamPreview() {
this.makeRequest('teampreview');
},
},
@@ -419,7 +419,7 @@ export const Rulesets: {[k: string]: FormatData} = {
return [`One vs One is for singles formats.`, `(Use Two vs Two in doubles)`];
}
},
onStart() {
onFieldStart() {
if (this.format.gameType === 'singles') (this.format as any).teamLength = {battle: 1};
},
},
@@ -432,7 +432,7 @@ export const Rulesets: {[k: string]: FormatData} = {
return [`Two vs Two is for non-triples formats.`];
}
},
onStart() {
onFieldStart() {
if (this.format.gameType !== 'triples') (this.format as any).teamLength = {battle: 2};
},
},
@@ -857,7 +857,7 @@ export const Rulesets: {[k: string]: FormatData} = {
if (status.id === 'slp') {
for (const pokemon of target.side.pokemon) {
if (pokemon.hp && pokemon.status === 'slp') {
if (!pokemon.statusData.source || !pokemon.statusData.source.isAlly(pokemon)) {
if (!pokemon.statusState.source || !pokemon.statusState.source.isAlly(pokemon)) {
this.add('-message', 'Sleep Clause Mod activated.');
return false;
}
@@ -1247,7 +1247,7 @@ export const Rulesets: {[k: string]: FormatData} = {
this.add(`${buf}</span>`);
}
},
onTeamPreview() {
onFieldTeamPreview() {
this.makeRequest('teampreview');
},
},

View File

@@ -101,7 +101,7 @@ export class BattleActions {
// will definitely switch out at this point
oldActive.illusion = null;
this.battle.singleEvent('End', oldActive.getAbility(), oldActive.abilityData, oldActive);
this.battle.singleEvent('End', oldActive.getAbility(), oldActive.abilityState, oldActive);
// if a pokemon is forced out by Whirlwind/etc or Eject Button/Pack, it can't use its chosen move
this.battle.queue.cancelAction(oldActive);
@@ -141,7 +141,7 @@ export class BattleActions {
if (isDrag && this.battle.gen >= 5) {
// runSwitch happens immediately so that Mold Breaker can make hazards bypass Clear Body and Levitate
this.battle.singleEvent('PreStart', pokemon.getAbility(), pokemon.abilityData, pokemon);
this.battle.singleEvent('PreStart', pokemon.getAbility(), pokemon.abilityState, pokemon);
this.runSwitch(pokemon);
} else {
this.battle.queue.insertChoice({choice: 'runUnnerve', pokemon});
@@ -172,8 +172,8 @@ export class BattleActions {
if (!pokemon.hp) return false;
pokemon.isStarted = true;
if (!pokemon.fainted) {
this.battle.singleEvent('Start', pokemon.getAbility(), pokemon.abilityData, pokemon);
this.battle.singleEvent('Start', pokemon.getItem(), pokemon.itemData, pokemon);
this.battle.singleEvent('Start', pokemon.getAbility(), pokemon.abilityState, pokemon);
this.battle.singleEvent('Start', pokemon.getItem(), pokemon.itemState, pokemon);
}
if (this.battle.gen === 4) {
for (const foeActive of pokemon.foes()) {
@@ -276,7 +276,7 @@ export class BattleActions {
if (zMove) {
if (pokemon.illusion) {
this.battle.singleEvent('End', this.dex.abilities.get('Illusion'), pokemon.abilityData, pokemon);
this.battle.singleEvent('End', this.dex.abilities.get('Illusion'), pokemon.abilityState, pokemon);
}
this.battle.add('-zpower', pokemon);
pokemon.side.zMoveUsed = true;

View File

@@ -110,7 +110,7 @@ export class Battle {
winner?: string;
effect: Effect;
effectData: EffectState;
effectState: EffectState;
event: AnyObject;
events: AnyObject | null;
@@ -195,7 +195,7 @@ export class Battle {
this.ended = false;
this.effect = {id: ''} as Effect;
this.effectData = {id: ''};
this.effectState = {id: ''};
this.event = {id: ''};
this.events = null;
@@ -415,19 +415,21 @@ export class Battle {
/**
* Runs an event with no source on each effect on the field, in Speed order.
*
* Unlike `eachEvent`
* Unlike `eachEvent`, this contains a lot of other handling and is intended only for the residual step.
*/
residualEvent(eventid: string, relayVar?: any) {
const callbackName = `on${eventid}`;
let handlers = this.findBattleEventHandlers(callbackName, 'duration');
handlers = handlers.concat(this.findFieldEventHandlers(this.field, callbackName, 'duration'));
handlers = handlers.concat(this.findFieldEventHandlers(this.field, `onField${eventid}`, 'duration'));
for (const side of this.sides) {
if (side.n < 2 || !side.allySide) {
handlers = handlers.concat(this.findSideEventHandlers(side, callbackName, 'duration'));
handlers = handlers.concat(this.findSideEventHandlers(side, `onSide${eventid}`, 'duration'));
}
for (const active of side.active) {
if (!active) continue;
handlers = handlers.concat(this.findPokemonEventHandlers(active, callbackName, 'duration'));
handlers = handlers.concat(this.findSideEventHandlers(side, callbackName, undefined, active));
handlers = handlers.concat(this.findFieldEventHandlers(this.field, callbackName, undefined, active));
}
}
this.speedSort(handlers);
@@ -436,15 +438,22 @@ export class Battle {
handlers.shift();
const effect = handler.effect;
if ((handler.effectHolder as Pokemon).fainted) continue;
if (handler.state && handler.state.duration) {
if (handler.end && handler.state && handler.state.duration) {
handler.state.duration--;
if (!handler.state.duration) {
const endCallArgs = handler.endCallArgs || [handler.effectHolder, effect.id];
handler.end!.call(...endCallArgs as [any, ...any[]]);
handler.end.call(...endCallArgs as [any, ...any[]]);
continue;
}
}
this.singleEvent(eventid, effect, handler.state, handler.effectHolder, relayVar);
let handlerEventid = eventid;
if ((handler.effectHolder as Side).sideConditions) handlerEventid = `Side${eventid}`;
if ((handler.effectHolder as Field).pseudoWeather) handlerEventid = `Field${eventid}`;
if (handler.callback) {
this.singleEvent(handlerEventid, effect, handler.state, handler.effectHolder, null, null, relayVar, handler.callback);
}
this.faintMessages();
if (this.ended) return;
}
@@ -452,9 +461,9 @@ export class Battle {
/** The entire event system revolves around this function and runEvent. */
singleEvent(
eventid: string, effect: Effect, effectData: AnyObject | null,
eventid: string, effect: Effect, state: 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, customCallback?: unknown
) {
if (this.eventDepth >= 8) {
// oh fuck
@@ -491,22 +500,23 @@ export class Battle {
this.debug(eventid + ' handler suppressed by Gastro Acid');
return relayVar;
}
if (effect.effectType === 'Weather' && eventid !== 'Start' && eventid !== 'Residual' &&
eventid !== 'End' && this.field.suppressingWeather()) {
if (
effect.effectType === 'Weather' && eventid !== 'FieldStart' && eventid !== 'FieldResidual' &&
eventid !== 'FieldEnd' && this.field.suppressingWeather()
) {
this.debug(eventid + ' handler suppressed by Air Lock');
return relayVar;
}
// @ts-ignore - dynamic lookup
const callback = effect[`on${eventid}`];
const callback = customCallback || (effect as any)[`on${eventid}`];
if (callback === undefined) return relayVar;
const parentEffect = this.effect;
const parentEffectData = this.effectData;
const parentEffectState = this.effectState;
const parentEvent = this.event;
this.effect = effect;
this.effectData = effectData || {};
this.effectState = state || {};
this.event = {id: eventid, target, source, effect: sourceEffect};
this.eventDepth++;
@@ -522,7 +532,7 @@ export class Battle {
this.eventDepth--;
this.effect = parentEffect;
this.effectData = parentEffectData;
this.effectState = parentEffectState;
this.event = parentEvent;
return returnVal === undefined ? relayVar : returnVal;
@@ -619,10 +629,10 @@ export class Battle {
*
* this.effect:
* the Effect having the event handler
* this.effectData:
* this.effectState:
* the data store associated with the above Effect. This is a plain Object
* and you can use it to store data for later event handlers.
* this.effectData.target:
* this.effectState.target:
* the Pokemon, Side, or Battle that the event handler's effect was
* attached to.
* this.event.id:
@@ -764,15 +774,15 @@ export class Battle {
let returnVal;
if (typeof handler.callback === 'function') {
const parentEffect = this.effect;
const parentEffectData = this.effectData;
const parentEffectState = this.effectState;
this.effect = handler.effect;
this.effectData = handler.state || {};
this.effectData.target = effectHolder;
this.effectState = handler.state || {};
this.effectState.target = effectHolder;
returnVal = handler.callback.apply(this, args);
this.effect = parentEffect;
this.effectData = parentEffectData;
this.effectState = parentEffectState;
} else {
returnVal = handler.callback;
}
@@ -879,9 +889,9 @@ export class Battle {
const status = pokemon.getStatus();
// @ts-ignore - dynamic lookup
let callback = status[callbackName];
if (callback !== undefined || (getKey && pokemon.statusData[getKey])) {
if (callback !== undefined || (getKey && pokemon.statusState[getKey])) {
handlers.push(this.resolvePriority({
effect: status, callback, state: pokemon.statusData, end: pokemon.clearStatus, effectHolder: pokemon,
effect: status, callback, state: pokemon.statusState, end: pokemon.clearStatus, effectHolder: pokemon,
}, callbackName));
}
for (const id in pokemon.volatiles) {
@@ -898,17 +908,17 @@ export class Battle {
const ability = pokemon.getAbility();
// @ts-ignore - dynamic lookup
callback = ability[callbackName];
if (callback !== undefined || (getKey && pokemon.abilityData[getKey])) {
if (callback !== undefined || (getKey && pokemon.abilityState[getKey])) {
handlers.push(this.resolvePriority({
effect: ability, callback, state: pokemon.abilityData, end: pokemon.clearAbility, effectHolder: pokemon,
effect: ability, callback, state: pokemon.abilityState, end: pokemon.clearAbility, effectHolder: pokemon,
}, callbackName));
}
const item = pokemon.getItem();
// @ts-ignore - dynamic lookup
callback = item[callbackName];
if (callback !== undefined || (getKey && pokemon.itemData[getKey])) {
if (callback !== undefined || (getKey && pokemon.itemState[getKey])) {
handlers.push(this.resolvePriority({
effect: item, callback, state: pokemon.itemData, end: pokemon.clearItem, effectHolder: pokemon,
effect: item, callback, state: pokemon.itemState, end: pokemon.clearItem, effectHolder: pokemon,
}, callbackName));
}
const species = pokemon.baseSpecies;
@@ -916,20 +926,20 @@ export class Battle {
callback = species[callbackName];
if (callback !== undefined) {
handlers.push(this.resolvePriority({
effect: species, callback, state: pokemon.speciesData, end() {}, effectHolder: pokemon,
effect: species, callback, state: pokemon.speciesState, end() {}, effectHolder: pokemon,
}, callbackName));
}
const side = pokemon.side;
for (const conditionid in side.slotConditions[pokemon.position]) {
const slotConditionData = side.slotConditions[pokemon.position][conditionid];
const slotConditionState = side.slotConditions[pokemon.position][conditionid];
const slotCondition = this.dex.conditions.getByID(conditionid as ID);
// @ts-ignore - dynamic lookup
callback = slotCondition[callbackName];
if (callback !== undefined || (getKey && slotConditionData[getKey])) {
if (callback !== undefined || (getKey && slotConditionState[getKey])) {
handlers.push(this.resolvePriority({
effect: slotCondition,
callback,
state: slotConditionData,
state: slotConditionState,
end: side.removeSlotCondition,
endCallArgs: [side, pokemon, slotCondition.id],
effectHolder: side,
@@ -964,42 +974,45 @@ export class Battle {
return handlers;
}
findFieldEventHandlers(field: Field, callbackName: string, getKey?: 'duration') {
findFieldEventHandlers(field: Field, callbackName: string, getKey?: 'duration', customHolder?: Pokemon) {
const handlers: EventListener[] = [];
let callback;
for (const id in field.pseudoWeather) {
const pseudoWeatherData = field.pseudoWeather[id];
const pseudoWeatherState = field.pseudoWeather[id];
const pseudoWeather = this.dex.conditions.getByID(id as ID);
// @ts-ignore - dynamic lookup
callback = pseudoWeather[callbackName];
if (callback !== undefined || (getKey && pseudoWeatherData[getKey])) {
if (callback !== undefined || (getKey && pseudoWeatherState[getKey])) {
handlers.push(this.resolvePriority({
effect: pseudoWeather, callback, state: pseudoWeatherData, end: field.removePseudoWeather, effectHolder: field,
effect: pseudoWeather, callback, state: pseudoWeatherState,
end: customHolder ? null : field.removePseudoWeather, effectHolder: customHolder || field,
}, callbackName));
}
}
const weather = field.getWeather();
// @ts-ignore - dynamic lookup
callback = weather[callbackName];
if (callback !== undefined || (getKey && this.field.weatherData[getKey])) {
if (callback !== undefined || (getKey && this.field.weatherState[getKey])) {
handlers.push(this.resolvePriority({
effect: weather, callback, state: this.field.weatherData, end: field.clearWeather, effectHolder: field,
effect: weather, callback, state: this.field.weatherState,
end: customHolder ? null : field.clearWeather, effectHolder: customHolder || field,
}, callbackName));
}
const terrain = field.getTerrain();
// @ts-ignore - dynamic lookup
callback = terrain[callbackName];
if (callback !== undefined || (getKey && field.terrainData[getKey])) {
if (callback !== undefined || (getKey && field.terrainState[getKey])) {
handlers.push(this.resolvePriority({
effect: terrain, callback, state: field.terrainData, end: field.clearTerrain, effectHolder: field,
effect: terrain, callback, state: field.terrainState,
end: customHolder ? null : field.clearTerrain, effectHolder: customHolder || field,
}, callbackName));
}
return handlers;
}
findSideEventHandlers(side: Side, callbackName: string, getKey?: 'duration') {
findSideEventHandlers(side: Side, callbackName: string, getKey?: 'duration', customHolder?: Pokemon) {
const handlers: EventListener[] = [];
for (const id in side.sideConditions) {
@@ -1009,7 +1022,8 @@ export class Battle {
const callback = sideCondition[callbackName];
if (callback !== undefined || (getKey && sideConditionData[getKey])) {
handlers.push(this.resolvePriority({
effect: sideCondition, callback, state: sideConditionData, end: side.removeSideCondition, effectHolder: side,
effect: sideCondition, callback, state: sideConditionData,
end: customHolder ? null : side.removeSideCondition, effectHolder: customHolder || side,
}, callbackName));
}
}
@@ -1777,7 +1791,7 @@ export class Battle {
const name = effect.fullname === 'tox' ? 'psn' : effect.fullname;
switch (effect.id) {
case 'partiallytrapped':
this.add('-damage', target, target.getHealth, '[from] ' + this.effectData.sourceEffect.fullname, '[partiallytrapped]');
this.add('-damage', target, target.getHealth, '[from] ' + this.effectState.sourceEffect.fullname, '[partiallytrapped]');
break;
case 'powder':
this.add('-damage', target, target.getHealth, '[silent]');
@@ -2179,7 +2193,7 @@ export class Battle {
this.add('faint', pokemon);
if (pokemon.side.pokemonLeft) pokemon.side.pokemonLeft--;
this.runEvent('Faint', pokemon, faintData.source, faintData.effect);
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityData, pokemon);
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityState, pokemon);
pokemon.clearVolatile(false);
pokemon.fainted = true;
pokemon.illusion = null;
@@ -2305,7 +2319,7 @@ export class Battle {
}
}
for (const pokemon of this.getAllPokemon()) {
this.singleEvent('Start', this.dex.conditions.getByID(pokemon.species.id), pokemon.speciesData, pokemon);
this.singleEvent('Start', this.dex.conditions.getByID(pokemon.species.id), pokemon.speciesState, pokemon);
}
this.midTurn = true;
break;
@@ -2371,14 +2385,14 @@ export class Battle {
}
break;
case 'runUnnerve':
this.singleEvent('PreStart', action.pokemon.getAbility(), action.pokemon.abilityData, action.pokemon);
this.singleEvent('PreStart', action.pokemon.getAbility(), action.pokemon.abilityState, action.pokemon);
break;
case 'runSwitch':
this.actions.runSwitch(action.pokemon);
break;
case 'runPrimal':
if (!action.pokemon.transformed) {
this.singleEvent('Primal', action.pokemon.getItem(), action.pokemon.itemData, action.pokemon);
this.singleEvent('Primal', action.pokemon.getItem(), action.pokemon.itemState, action.pokemon);
}
break;
case 'shift':

View File

@@ -1,4 +1,4 @@
import {EventMethods} from './dex-conditions';
import {PokemonEventMethods} from './dex-conditions';
import {BasicEffect, toID} from './dex-data';
interface AbilityEventMethods {
@@ -8,7 +8,7 @@ interface AbilityEventMethods {
onStart?: (this: Battle, target: Pokemon) => void;
}
export interface AbilityData extends Partial<Ability>, AbilityEventMethods, EventMethods {
export interface AbilityData extends Partial<Ability>, AbilityEventMethods, PokemonEventMethods {
name: string;
}
@@ -20,7 +20,7 @@ export class Ability extends BasicEffect implements Readonly<BasicEffect> {
/** Rating from -1 Detrimental to +5 Essential; see `data/abilities.ts` for details. */
readonly rating: number;
readonly suppressWeather: boolean;
readonly condition?: Partial<ConditionData>;
readonly condition?: ConditionData;
readonly isPermanent?: boolean;
readonly isUnbreakable?: boolean;

View File

@@ -69,7 +69,7 @@ export interface EventMethods {
onRedirectTarget?: (
this: Battle, target: Pokemon, source: Pokemon, source2: Effect, move: ActiveMove
) => Pokemon | void;
onResidual?: (this: Battle, target: Pokemon & Side, source: Pokemon, effect: Effect) => void;
onResidual?: (this: Battle, target: Pokemon, source: Pokemon, effect: Effect) => void;
onSetAbility?: (this: Battle, ability: string, target: Pokemon, source: Pokemon, effect: Effect) => boolean | void;
onSetStatus?: (
this: Battle, status: Condition, target: Pokemon, source: Pokemon, effect: Effect
@@ -107,109 +107,6 @@ export interface EventMethods {
onWeatherModifyDamage?: CommonHandlers['ModifierSourceMove'];
onModifyDamagePhase1?: CommonHandlers['ModifierSourceMove'];
onModifyDamagePhase2?: CommonHandlers['ModifierSourceMove'];
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: Condition, target: Pokemon, source: Pokemon, effect: Effect) => void;
onAllyAfterSubDamage?: MoveEventMethods['onAfterSubDamage'];
onAllyAfterSwitchInSelf?: (this: Battle, pokemon: Pokemon) => void;
onAllyAfterUseItem?: (this: Battle, item: Item, pokemon: Pokemon) => void;
onAllyAfterBoost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source: Pokemon, effect: Effect) => void;
onAllyAfterFaint?: (this: Battle, length: number, target: Pokemon, source: Pokemon, effect: Effect) => void;
onAllyAfterMoveSecondarySelf?: MoveEventMethods['onAfterMoveSecondarySelf'];
onAllyAfterMoveSecondary?: MoveEventMethods['onAfterMoveSecondary'];
onAllyAfterMove?: MoveEventMethods['onAfterMove'];
onAllyAfterMoveSelf?: CommonHandlers['VoidSourceMove'];
onAllyAttract?: (this: Battle, target: Pokemon, source: Pokemon) => void;
onAllyAccuracy?: (
this: Battle, accuracy: number, target: Pokemon, source: Pokemon, move: ActiveMove
) => number | boolean | null | void;
onAllyBasePower?: CommonHandlers['ModifierSourceMove'];
onAllyBeforeFaint?: (this: Battle, pokemon: Pokemon, effect: Effect) => void;
onAllyBeforeMove?: CommonHandlers['VoidSourceMove'];
onAllyBeforeSwitchIn?: (this: Battle, pokemon: Pokemon) => void;
onAllyBeforeSwitchOut?: (this: Battle, pokemon: Pokemon) => void;
onAllyBeforeTurn?: (this: Battle, pokemon: Pokemon) => void;
onAllyBoost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source: Pokemon, effect: Effect) => void;
onAllyChargeMove?: CommonHandlers['VoidSourceMove'];
onAllyCriticalHit?: ((this: Battle, pokemon: Pokemon, source: null, move: ActiveMove) => boolean | void) | boolean;
onAllyDamage?: (
this: Battle, damage: number, target: Pokemon, source: Pokemon, effect: Effect
) => number | boolean | null | void;
onAllyDeductPP?: (this: Battle, target: Pokemon, source: Pokemon) => number | void;
onAllyDisableMove?: (this: Battle, pokemon: Pokemon) => void;
onAllyDragOut?: (this: Battle, pokemon: Pokemon, source?: Pokemon, move?: ActiveMove) => void;
onAllyEatItem?: (this: Battle, item: Item, pokemon: Pokemon) => void;
onAllyEffectiveness?: MoveEventMethods['onEffectiveness'];
onAllyFaint?: CommonHandlers['VoidEffect'];
onAllyFlinch?: ((this: Battle, pokemon: Pokemon) => boolean | void) | boolean;
onAllyHit?: MoveEventMethods['onHit'];
onAllyImmunity?: (this: Battle, type: string, pokemon: Pokemon) => void;
onAllyLockMove?: string | ((this: Battle, pokemon: Pokemon) => void | string);
onAllyMaybeTrapPokemon?: (this: Battle, pokemon: Pokemon) => void;
onAllyModifyAccuracy?: CommonHandlers['ModifierMove'];
onAllyModifyAtk?: CommonHandlers['ModifierSourceMove'];
onAllyModifyBoost?: (this: Battle, boosts: SparseBoostsTable, pokemon: Pokemon) => SparseBoostsTable | void;
onAllyModifyCritRatio?: CommonHandlers['ModifierSourceMove'];
onAllyModifyDamage?: CommonHandlers['ModifierSourceMove'];
onAllyModifyDef?: CommonHandlers['ModifierMove'];
onAllyModifyMove?: MoveEventMethods['onModifyMove'];
onAllyModifyPriority?: CommonHandlers['ModifierSourceMove'];
onAllyModifySecondaries?: (
this: Battle, secondaries: SecondaryEffect[], target: Pokemon, source: Pokemon, move: ActiveMove
) => void;
onAllyModifySpA?: CommonHandlers['ModifierSourceMove'];
onAllyModifySpD?: CommonHandlers['ModifierMove'];
onAllyModifySpe?: (this: Battle, spe: number, pokemon: Pokemon) => number | void;
onAllyModifyType?: MoveEventMethods['onModifyType'];
onAllyModifyTarget?: MoveEventMethods['onModifyTarget'];
onAllyModifyWeight?: (this: Battle, weighthg: number, pokemon: Pokemon) => number | void;
onAllyMoveAborted?: CommonHandlers['VoidMove'];
onAllyNegateImmunity?: ((this: Battle, pokemon: Pokemon, type: string) => boolean | void) | boolean;
onAllyOverrideAction?: (this: Battle, pokemon: Pokemon, target: Pokemon, move: ActiveMove) => string | void;
onAllyPrepareHit?: CommonHandlers['ResultSourceMove'];
onAllyRedirectTarget?: (
this: Battle, target: Pokemon, source: Pokemon, source2: Effect, move: ActiveMove
) => Pokemon | void;
onAllyResidual?: (this: Battle, target: Pokemon & Side, source: Pokemon, effect: Effect) => void;
onAllySetAbility?: (this: Battle, ability: string, target: Pokemon, source: Pokemon, effect: Effect) => boolean | void;
onAllySetStatus?: (
this: Battle, status: Condition, target: Pokemon, source: Pokemon, effect: Effect
) => boolean | null | void;
onAllySetWeather?: (this: Battle, target: Pokemon, source: Pokemon, weather: Condition) => boolean | void;
onAllyStallMove?: (this: Battle, pokemon: Pokemon) => boolean | void;
onAllySwitchIn?: (this: Battle, pokemon: Pokemon) => void;
onAllySwitchOut?: (this: Battle, pokemon: Pokemon) => void;
onAllyTakeItem?: (
(this: Battle, item: Item, pokemon: Pokemon, source: Pokemon, move?: ActiveMove) => boolean | void
) | boolean;
onAllyTerrain?: (this: Battle, pokemon: Pokemon) => void;
onAllyTerrainStart?: (this: Battle, target: Pokemon, source: Pokemon, terrain: Condition) => void;
onAllyWeatherStart?: (this: Battle, target: Pokemon, source: Pokemon, weather: Condition) => void;
onAllyTrapPokemon?: (this: Battle, pokemon: Pokemon) => void;
onAllyTryAddVolatile?: (
this: Battle, status: Condition, target: Pokemon, source: Pokemon, sourceEffect: Effect
) => boolean | null | void;
onAllyTryEatItem?: boolean | ((this: Battle, item: Item, pokemon: Pokemon) => boolean | void);
/* FIXME: onAllyTryHeal() is run with two different sets of arguments */
onAllyTryHeal?: (
((this: Battle, relayVar: number, target: Pokemon, source: Pokemon, effect: Effect) => number | boolean | void) |
((this: Battle, pokemon: Pokemon) => boolean | void) | boolean
);
onAllyTryHit?: MoveEventMethods['onTryHit'];
onAllyTryHitField?: MoveEventMethods['onTryHitField'];
onAllyTryHitSide?: CommonHandlers['ResultMove'];
onAllyInvulnerability?: CommonHandlers['ExtResultMove'];
onAllyTryMove?: MoveEventMethods['onTryMove'];
onAllyTryPrimaryHit?: (
this: Battle, target: Pokemon, source: Pokemon, move: ActiveMove
) => boolean | null | number | void;
onAllyType?: (this: Battle, types: string[], pokemon: Pokemon) => string[] | void;
onAllyUpdate?: (this: Battle, pokemon: Pokemon) => void;
onAllyWeather?: (this: Battle, target: Pokemon, source: null, effect: Condition) => void;
onAllyWeatherModifyDamage?: CommonHandlers['ModifierSourceMove'];
onAllyModifyDamagePhase1?: CommonHandlers['ModifierSourceMove'];
onAllyModifyDamagePhase2?: CommonHandlers['ModifierSourceMove'];
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'];
@@ -584,19 +481,149 @@ export interface EventMethods {
onTypePriority?: number;
}
export interface ConditionData extends Partial<Condition>, EventMethods {}
export interface PokemonEventMethods extends EventMethods {
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: Condition, target: Pokemon, source: Pokemon, effect: Effect) => void;
onAllyAfterSubDamage?: MoveEventMethods['onAfterSubDamage'];
onAllyAfterSwitchInSelf?: (this: Battle, pokemon: Pokemon) => void;
onAllyAfterUseItem?: (this: Battle, item: Item, pokemon: Pokemon) => void;
onAllyAfterBoost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source: Pokemon, effect: Effect) => void;
onAllyAfterFaint?: (this: Battle, length: number, target: Pokemon, source: Pokemon, effect: Effect) => void;
onAllyAfterMoveSecondarySelf?: MoveEventMethods['onAfterMoveSecondarySelf'];
onAllyAfterMoveSecondary?: MoveEventMethods['onAfterMoveSecondary'];
onAllyAfterMove?: MoveEventMethods['onAfterMove'];
onAllyAfterMoveSelf?: CommonHandlers['VoidSourceMove'];
onAllyAttract?: (this: Battle, target: Pokemon, source: Pokemon) => void;
onAllyAccuracy?: (
this: Battle, accuracy: number, target: Pokemon, source: Pokemon, move: ActiveMove
) => number | boolean | null | void;
onAllyBasePower?: CommonHandlers['ModifierSourceMove'];
onAllyBeforeFaint?: (this: Battle, pokemon: Pokemon, effect: Effect) => void;
onAllyBeforeMove?: CommonHandlers['VoidSourceMove'];
onAllyBeforeSwitchIn?: (this: Battle, pokemon: Pokemon) => void;
onAllyBeforeSwitchOut?: (this: Battle, pokemon: Pokemon) => void;
onAllyBeforeTurn?: (this: Battle, pokemon: Pokemon) => void;
onAllyBoost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source: Pokemon, effect: Effect) => void;
onAllyChargeMove?: CommonHandlers['VoidSourceMove'];
onAllyCriticalHit?: ((this: Battle, pokemon: Pokemon, source: null, move: ActiveMove) => boolean | void) | boolean;
onAllyDamage?: (
this: Battle, damage: number, target: Pokemon, source: Pokemon, effect: Effect
) => number | boolean | null | void;
onAllyDeductPP?: (this: Battle, target: Pokemon, source: Pokemon) => number | void;
onAllyDisableMove?: (this: Battle, pokemon: Pokemon) => void;
onAllyDragOut?: (this: Battle, pokemon: Pokemon, source?: Pokemon, move?: ActiveMove) => void;
onAllyEatItem?: (this: Battle, item: Item, pokemon: Pokemon) => void;
onAllyEffectiveness?: MoveEventMethods['onEffectiveness'];
onAllyFaint?: CommonHandlers['VoidEffect'];
onAllyFlinch?: ((this: Battle, pokemon: Pokemon) => boolean | void) | boolean;
onAllyHit?: MoveEventMethods['onHit'];
onAllyImmunity?: (this: Battle, type: string, pokemon: Pokemon) => void;
onAllyLockMove?: string | ((this: Battle, pokemon: Pokemon) => void | string);
onAllyMaybeTrapPokemon?: (this: Battle, pokemon: Pokemon) => void;
onAllyModifyAccuracy?: CommonHandlers['ModifierMove'];
onAllyModifyAtk?: CommonHandlers['ModifierSourceMove'];
onAllyModifyBoost?: (this: Battle, boosts: SparseBoostsTable, pokemon: Pokemon) => SparseBoostsTable | void;
onAllyModifyCritRatio?: CommonHandlers['ModifierSourceMove'];
onAllyModifyDamage?: CommonHandlers['ModifierSourceMove'];
onAllyModifyDef?: CommonHandlers['ModifierMove'];
onAllyModifyMove?: MoveEventMethods['onModifyMove'];
onAllyModifyPriority?: CommonHandlers['ModifierSourceMove'];
onAllyModifySecondaries?: (
this: Battle, secondaries: SecondaryEffect[], target: Pokemon, source: Pokemon, move: ActiveMove
) => void;
onAllyModifySpA?: CommonHandlers['ModifierSourceMove'];
onAllyModifySpD?: CommonHandlers['ModifierMove'];
onAllyModifySpe?: (this: Battle, spe: number, pokemon: Pokemon) => number | void;
onAllyModifyType?: MoveEventMethods['onModifyType'];
onAllyModifyTarget?: MoveEventMethods['onModifyTarget'];
onAllyModifyWeight?: (this: Battle, weighthg: number, pokemon: Pokemon) => number | void;
onAllyMoveAborted?: CommonHandlers['VoidMove'];
onAllyNegateImmunity?: ((this: Battle, pokemon: Pokemon, type: string) => boolean | void) | boolean;
onAllyOverrideAction?: (this: Battle, pokemon: Pokemon, target: Pokemon, move: ActiveMove) => string | void;
onAllyPrepareHit?: CommonHandlers['ResultSourceMove'];
onAllyRedirectTarget?: (
this: Battle, target: Pokemon, source: Pokemon, source2: Effect, move: ActiveMove
) => Pokemon | void;
onAllyResidual?: (this: Battle, target: Pokemon & Side, source: Pokemon, effect: Effect) => void;
onAllySetAbility?: (this: Battle, ability: string, target: Pokemon, source: Pokemon, effect: Effect) => boolean | void;
onAllySetStatus?: (
this: Battle, status: Condition, target: Pokemon, source: Pokemon, effect: Effect
) => boolean | null | void;
onAllySetWeather?: (this: Battle, target: Pokemon, source: Pokemon, weather: Condition) => boolean | void;
onAllyStallMove?: (this: Battle, pokemon: Pokemon) => boolean | void;
onAllySwitchIn?: (this: Battle, pokemon: Pokemon) => void;
onAllySwitchOut?: (this: Battle, pokemon: Pokemon) => void;
onAllyTakeItem?: (
(this: Battle, item: Item, pokemon: Pokemon, source: Pokemon, move?: ActiveMove) => boolean | void
) | boolean;
onAllyTerrain?: (this: Battle, pokemon: Pokemon) => void;
onAllyTerrainStart?: (this: Battle, target: Pokemon, source: Pokemon, terrain: Condition) => void;
onAllyWeatherStart?: (this: Battle, target: Pokemon, source: Pokemon, weather: Condition) => void;
onAllyTrapPokemon?: (this: Battle, pokemon: Pokemon) => void;
onAllyTryAddVolatile?: (
this: Battle, status: Condition, target: Pokemon, source: Pokemon, sourceEffect: Effect
) => boolean | null | void;
onAllyTryEatItem?: boolean | ((this: Battle, item: Item, pokemon: Pokemon) => boolean | void);
/* FIXME: onAllyTryHeal() is run with two different sets of arguments */
onAllyTryHeal?: (
((this: Battle, relayVar: number, target: Pokemon, source: Pokemon, effect: Effect) => number | boolean | void) |
((this: Battle, pokemon: Pokemon) => boolean | void) | boolean
);
onAllyTryHit?: MoveEventMethods['onTryHit'];
onAllyTryHitField?: MoveEventMethods['onTryHitField'];
onAllyTryHitSide?: CommonHandlers['ResultMove'];
onAllyInvulnerability?: CommonHandlers['ExtResultMove'];
onAllyTryMove?: MoveEventMethods['onTryMove'];
onAllyTryPrimaryHit?: (
this: Battle, target: Pokemon, source: Pokemon, move: ActiveMove
) => boolean | null | number | void;
onAllyType?: (this: Battle, types: string[], pokemon: Pokemon) => string[] | void;
onAllyUpdate?: (this: Battle, pokemon: Pokemon) => void;
onAllyWeather?: (this: Battle, target: Pokemon, source: null, effect: Condition) => void;
onAllyWeatherModifyDamage?: CommonHandlers['ModifierSourceMove'];
onAllyModifyDamagePhase1?: CommonHandlers['ModifierSourceMove'];
onAllyModifyDamagePhase2?: CommonHandlers['ModifierSourceMove'];
}
export interface SideEventMethods extends EventMethods {
onSideStart?: (this: Battle, target: Side, source: Pokemon, sourceEffect: Effect) => void;
onSideRestart?: (this: Battle, target: Side, source: Pokemon, sourceEffect: Effect) => void;
onSideResidual?: (this: Battle, target: Side, source: Pokemon, effect: Effect) => void;
onSideEnd?: (this: Battle, target: Side) => void;
onSideResidualOrder?: number;
onSideResidualPriority?: number;
onSideResidualSubOrder?: number;
}
export interface FieldEventMethods extends EventMethods {
onFieldStart?: (this: Battle, target: Field, source: Pokemon, sourceEffect: Effect) => void;
onFieldRestart?: (this: Battle, target: Field, source: Pokemon, sourceEffect: Effect) => void;
onFieldResidual?: (this: Battle, target: Field, source: Pokemon, effect: Effect) => void;
onFieldEnd?: (this: Battle, target: Field) => void;
onFieldResidualOrder?: number;
onFieldResidualPriority?: number;
onFieldResidualSubOrder?: number;
}
export interface PokemonConditionData extends Partial<Condition>, PokemonEventMethods {}
export interface SideConditionData extends
Partial<Omit<Condition, 'onStart' | 'onRestart' | 'onEnd'>>, SideEventMethods {}
export interface FieldConditionData extends
Partial<Omit<Condition, 'onStart' | 'onRestart' | 'onEnd'>>, FieldEventMethods {}
export type ModdedConditionData = ConditionData | Partial<ConditionData> & {inherit: true};
export type ConditionData = PokemonConditionData | SideConditionData | FieldConditionData;
export class Condition extends BasicEffect implements Readonly<BasicEffect & ConditionData> {
export type ModdedConditionData = ConditionData & {inherit?: true};
export class Condition extends BasicEffect implements
Readonly<BasicEffect & SideConditionData & FieldConditionData & PokemonConditionData> {
readonly effectType: 'Condition' | 'Weather' | 'Status';
readonly counterMax?: number;
readonly durationCallback?: (this: Battle, target: Pokemon, source: Pokemon, effect: Effect | null) => number;
readonly onCopy?: (this: Battle, pokemon: Pokemon) => void;
readonly onEnd?: (this: Battle, target: Pokemon & Side & Field) => void;
readonly onRestart?: (this: Battle, target: Pokemon & Side & Field, source: Pokemon, sourceEffect: Effect) => void;
readonly onStart?: (this: Battle, target: Pokemon & Side & Field, source: Pokemon, sourceEffect: Effect) => void;
readonly onEnd?: (this: Battle, target: Pokemon) => void;
readonly onRestart?: (this: Battle, target: Pokemon, source: Pokemon, sourceEffect: Effect) => void;
readonly onStart?: (this: Battle, target: Pokemon, source: Pokemon, sourceEffect: Effect) => void;
constructor(data: AnyObject) {
super(data);

View File

@@ -233,8 +233,8 @@ export class Format extends BasicEffect implements Readonly<BasicEffect> {
readonly onModifySpecies?: (
this: Battle, species: Species, target?: Pokemon, source?: Pokemon, effect?: Effect
) => Species | void;
readonly onStart?: (this: Battle) => void;
readonly onTeamPreview?: (this: Battle) => void;
readonly onFieldStart?: (this: Battle) => void;
readonly onFieldTeamPreview?: (this: Battle) => void;
readonly onValidateSet?: (
this: TeamValidator, set: PokemonSet, format: Format, setHas: AnyObject, teamHas: AnyObject
) => string[] | void;

View File

@@ -1,4 +1,4 @@
import {EventMethods} from './dex-conditions';
import {PokemonEventMethods} from './dex-conditions';
import {BasicEffect, toID} from './dex-data';
interface FlingData {
@@ -8,7 +8,7 @@ interface FlingData {
effect?: CommonHandlers['ResultMove'];
}
export interface ItemData extends Partial<Item>, EventMethods {
export interface ItemData extends Partial<Item>, PokemonEventMethods {
name: string;
}
@@ -89,7 +89,7 @@ export class Item extends BasicEffect implements Readonly<BasicEffect> {
/** Is this item a Pokeball? */
readonly isPokeball: boolean;
readonly condition?: Partial<ConditionData>;
readonly condition?: ConditionData;
readonly forcedForme?: string;
readonly isChoice?: boolean;
readonly naturalGift?: {basePower: number, type: string};

View File

@@ -131,7 +131,7 @@ export interface MoveData extends EffectData, MoveEventMethods, HitEffect {
name: string;
/** move index number, used for Metronome rolls */
num?: number;
condition?: Partial<ConditionData>;
condition?: ConditionData;
basePower: number;
accuracy: true | number;
pp: number;

View File

@@ -14,9 +14,9 @@ export class Field {
readonly id: ID;
weather: ID;
weatherData: EffectState;
weatherState: EffectState;
terrain: ID;
terrainData: EffectState;
terrainState: EffectState;
pseudoWeather: {[id: string]: EffectState};
constructor(battle: Battle) {
@@ -26,9 +26,9 @@ export class Field {
this.id = '';
this.weather = '';
this.weatherData = {id: ''};
this.weatherState = {id: ''};
this.terrain = '';
this.terrainData = {id: ''};
this.terrainState = {id: ''};
this.pseudoWeather = {};
}
@@ -44,7 +44,7 @@ export class Field {
if (this.weather === status.id) {
if (sourceEffect && sourceEffect.effectType === 'Ability') {
if (this.battle.gen > 5 || this.weatherData.duration === 0) {
if (this.battle.gen > 5 || this.weatherState.duration === 0) {
return false;
}
} else if (this.battle.gen > 2 || status.id === 'sandstorm') {
@@ -65,23 +65,23 @@ export class Field {
}
}
const prevWeather = this.weather;
const prevWeatherData = this.weatherData;
const prevWeatherState = this.weatherState;
this.weather = status.id;
this.weatherData = {id: status.id};
this.weatherState = {id: status.id};
if (source) {
this.weatherData.source = source;
this.weatherData.sourceSlot = source.getSlot();
this.weatherState.source = source;
this.weatherState.sourceSlot = source.getSlot();
}
if (status.duration) {
this.weatherData.duration = status.duration;
this.weatherState.duration = status.duration;
}
if (status.durationCallback) {
if (!source) throw new Error(`setting weather without a source`);
this.weatherData.duration = status.durationCallback.call(this.battle, source, source, sourceEffect);
this.weatherState.duration = status.durationCallback.call(this.battle, source, source, sourceEffect);
}
if (!this.battle.singleEvent('Start', status, this.weatherData, this, source, sourceEffect)) {
if (!this.battle.singleEvent('FieldStart', status, this.weatherState, this, source, sourceEffect)) {
this.weather = prevWeather;
this.weatherData = prevWeatherData;
this.weatherState = prevWeatherState;
return false;
}
this.battle.runEvent('WeatherStart', source, source, status);
@@ -91,9 +91,9 @@ export class Field {
clearWeather() {
if (!this.weather) return false;
const prevWeather = this.getWeather();
this.battle.singleEvent('End', prevWeather, this.weatherData, this);
this.battle.singleEvent('FieldEnd', prevWeather, this.weatherState, this);
this.weather = '';
this.weatherData = {id: ''};
this.weatherState = {id: ''};
return true;
}
@@ -134,20 +134,20 @@ export class Field {
if (this.terrain === status.id) return false;
const prevTerrain = this.terrain;
const prevTerrainData = this.terrainData;
const prevTerrainState = this.terrainState;
this.terrain = status.id;
this.terrainData = {
this.terrainState = {
id: status.id,
source,
sourceSlot: source.getSlot(),
duration: status.duration,
};
if (status.durationCallback) {
this.terrainData.duration = status.durationCallback.call(this.battle, source, source, sourceEffect);
this.terrainState.duration = status.durationCallback.call(this.battle, source, source, sourceEffect);
}
if (!this.battle.singleEvent('Start', status, this.terrainData, this, source, sourceEffect)) {
if (!this.battle.singleEvent('FieldStart', status, this.terrainState, this, source, sourceEffect)) {
this.terrain = prevTerrain;
this.terrainData = prevTerrainData;
this.terrainState = prevTerrainState;
return false;
}
this.battle.runEvent('TerrainStart', source, source, status);
@@ -157,9 +157,9 @@ export class Field {
clearTerrain() {
if (!this.terrain) return false;
const prevTerrain = this.getTerrain();
this.battle.singleEvent('End', prevTerrain, this.terrainData, this);
this.battle.singleEvent('FieldEnd', prevTerrain, this.terrainState, this);
this.terrain = '';
this.terrainData = {id: ''};
this.terrainState = {id: ''};
return true;
}
@@ -189,12 +189,12 @@ export class Field {
if (source === 'debug') source = this.battle.sides[0].active[0];
status = this.battle.dex.conditions.get(status);
let effectData = this.pseudoWeather[status.id];
if (effectData) {
if (!status.onRestart) return false;
return this.battle.singleEvent('Restart', status, effectData, this, source, sourceEffect);
let state = this.pseudoWeather[status.id];
if (state) {
if (!(status as any).onFieldRestart) return false;
return this.battle.singleEvent('FieldRestart', status, state, this, source, sourceEffect);
}
effectData = this.pseudoWeather[status.id] = {
state = this.pseudoWeather[status.id] = {
id: status.id,
source,
sourceSlot: source?.getSlot(),
@@ -202,9 +202,9 @@ export class Field {
};
if (status.durationCallback) {
if (!source) throw new Error(`setting fieldcond without a source`);
effectData.duration = status.durationCallback.call(this.battle, source, source, sourceEffect);
state.duration = status.durationCallback.call(this.battle, source, source, sourceEffect);
}
if (!this.battle.singleEvent('Start', status, effectData, this, source, sourceEffect)) {
if (!this.battle.singleEvent('FieldStart', status, state, this, source, sourceEffect)) {
delete this.pseudoWeather[status.id];
return false;
}
@@ -218,9 +218,9 @@ export class Field {
removePseudoWeather(status: string | Effect) {
status = this.battle.dex.conditions.get(status);
const effectData = this.pseudoWeather[status.id];
if (!effectData) return false;
this.battle.singleEvent('End', status, effectData, this);
const state = this.pseudoWeather[status.id];
if (!state) return false;
this.battle.singleEvent('FieldEnd', status, state, this);
delete this.pseudoWeather[status.id];
return true;
}

View File

@@ -75,10 +75,10 @@ export class Pokemon {
baseSpecies: Species;
species: Species;
speciesData: EffectState;
speciesState: EffectState;
status: ID;
statusData: EffectState;
statusState: EffectState;
volatiles: {[id: string]: EffectState};
showCure?: boolean;
@@ -107,10 +107,10 @@ export class Pokemon {
baseAbility: ID;
ability: ID;
abilityData: EffectState;
abilityState: EffectState;
item: ID;
itemData: EffectState;
itemState: EffectState;
lastItem: ID;
usedItemThisTurn: boolean;
ateBerry: boolean;
@@ -290,7 +290,7 @@ export class Pokemon {
if (set.name === set.species || !set.name) {
set.name = this.baseSpecies.baseSpecies;
}
this.speciesData = {id: this.species.id};
this.speciesState = {id: this.species.id};
this.name = set.name.substr(0, 20);
this.fullname = this.side.id + ': ' + this.name;
@@ -333,7 +333,7 @@ export class Pokemon {
(this.gender === '' ? '' : ', ' + this.gender) + (this.set.shiny ? ', shiny' : '');
this.status = '';
this.statusData = {};
this.statusState = {};
this.volatiles = {};
this.showCure = false;
@@ -376,10 +376,10 @@ export class Pokemon {
this.baseAbility = toID(set.ability);
this.ability = this.baseAbility;
this.abilityData = {id: this.ability};
this.abilityState = {id: this.ability};
this.item = toID(set.item);
this.itemData = {id: this.item};
this.itemState = {id: this.item};
this.lastItem = '';
this.usedItemThisTurn = false;
this.ateBerry = false;
@@ -768,7 +768,7 @@ export class Pokemon {
for (const pokemon of this.battle.getAllActive()) {
// can't use hasAbility because it would lead to infinite recursion
if (pokemon.ability === ('neutralizinggas' as ID) && !pokemon.volatiles['gastroacid'] &&
!pokemon.abilityData.ending) {
!pokemon.abilityState.ending) {
neutralizinggas = true;
break;
}
@@ -1521,7 +1521,7 @@ export class Pokemon {
}
}
const prevStatus = this.status;
const prevStatusData = this.statusData;
const prevStatusState = this.statusState;
if (status.id) {
const result: boolean = this.battle.runEvent('SetStatus', this, source, sourceEffect, status);
if (!result) {
@@ -1531,18 +1531,18 @@ export class Pokemon {
}
this.status = status.id;
this.statusData = {id: status.id, target: this};
if (source) this.statusData.source = source;
if (status.duration) this.statusData.duration = status.duration;
this.statusState = {id: status.id, target: this};
if (source) this.statusState.source = source;
if (status.duration) this.statusState.duration = status.duration;
if (status.durationCallback) {
this.statusData.duration = status.durationCallback.call(this.battle, this, source, sourceEffect);
this.statusState.duration = status.durationCallback.call(this.battle, this, source, sourceEffect);
}
if (status.id && !this.battle.singleEvent('Start', status, this.statusData, this, source, sourceEffect)) {
if (status.id && !this.battle.singleEvent('Start', status, this.statusState, this, source, sourceEffect)) {
this.battle.debug('status start [' + status.id + '] interrupted');
// cancel the setstatus
this.status = prevStatus;
this.statusData = prevStatusData;
this.statusState = prevStatusState;
return false;
}
if (status.id && !this.battle.runEvent('AfterSetStatus', this, source, sourceEffect, status)) {
@@ -1575,7 +1575,7 @@ export class Pokemon {
) {
this.battle.add('-enditem', this, item, '[eat]');
this.battle.singleEvent('Eat', item, this.itemData, this, source, sourceEffect);
this.battle.singleEvent('Eat', item, this.itemState, this, source, sourceEffect);
this.battle.runEvent('EatItem', this, null, null, item);
if (RESTORATIVE_BERRIES.has(item.id)) {
@@ -1592,7 +1592,7 @@ export class Pokemon {
this.lastItem = this.item;
this.item = '';
this.itemData = {id: '', target: this};
this.itemState = {id: '', target: this};
this.usedItemThisTurn = true;
this.ateBerry = true;
this.battle.runEvent('AfterUseItem', this, null, null, item);
@@ -1625,11 +1625,11 @@ export class Pokemon {
this.battle.boost(item.boosts, this, source, item);
}
this.battle.singleEvent('Use', item, this.itemData, this, source, sourceEffect);
this.battle.singleEvent('Use', item, this.itemState, this, source, sourceEffect);
this.lastItem = this.item;
this.item = '';
this.itemData = {id: '', target: this};
this.itemState = {id: '', target: this};
this.usedItemThisTurn = true;
this.battle.runEvent('AfterUseItem', this, null, null, item);
return true;
@@ -1648,7 +1648,7 @@ export class Pokemon {
const item = this.getItem();
if (this.battle.runEvent('TakeItem', this, source, null, item)) {
this.item = '';
this.itemData = {id: '', target: this};
this.itemState = {id: '', target: this};
this.pendingStaleness = undefined;
return item;
}
@@ -1668,9 +1668,9 @@ export class Pokemon {
this.pendingStaleness = undefined;
}
this.item = item.id;
this.itemData = {id: item.id, target: this};
this.itemState = {id: item.id, target: this};
if (item.id) {
this.battle.singleEvent('Start', item, this.itemData, this, source, effect);
this.battle.singleEvent('Start', item, this.itemState, this, source, effect);
}
return true;
}
@@ -1698,15 +1698,15 @@ export class Pokemon {
if (ability.isPermanent || this.getAbility().isPermanent) return false;
}
if (!this.battle.runEvent('SetAbility', this, source, this.battle.effect, ability)) return false;
this.battle.singleEvent('End', this.battle.dex.abilities.get(oldAbility), this.abilityData, this, source);
this.battle.singleEvent('End', this.battle.dex.abilities.get(oldAbility), this.abilityState, this, source);
if (this.battle.effect && this.battle.effect.effectType === 'Move' && !isFromFormeChange) {
this.battle.add('-endability', this, this.battle.dex.abilities.get(oldAbility), '[from] move: ' +
this.battle.dex.moves.get(this.battle.effect.id));
}
this.ability = ability.id;
this.abilityData = {id: ability.id, target: this};
this.abilityState = {id: ability.id, target: this};
if (ability.id && this.battle.gen > 3) {
this.battle.singleEvent('Start', ability, this.abilityData, this, source);
this.battle.singleEvent('Start', ability, this.abilityState, this, source);
}
this.abilityOrder = this.battle.abilityOrder++;
return oldAbility;

View File

@@ -275,8 +275,8 @@ export class Side {
status = this.battle.dex.conditions.get(status);
if (this.sideConditions[status.id]) {
if (!status.onRestart) return false;
return this.battle.singleEvent('Restart', status, this.sideConditions[status.id], this, source, sourceEffect);
if (!(status as any).onSideRestart) return false;
return this.battle.singleEvent('SideRestart', status, this.sideConditions[status.id], this, source, sourceEffect);
}
this.sideConditions[status.id] = {
id: status.id,
@@ -289,7 +289,7 @@ export class Side {
this.sideConditions[status.id].duration =
status.durationCallback.call(this.battle, this.active[0], source, sourceEffect);
}
if (!this.battle.singleEvent('Start', status, this.sideConditions[status.id], this, source, sourceEffect)) {
if (!this.battle.singleEvent('SideStart', status, this.sideConditions[status.id], this, source, sourceEffect)) {
delete this.sideConditions[status.id];
return false;
}
@@ -310,7 +310,7 @@ export class Side {
removeSideCondition(status: string | Effect): boolean {
status = this.battle.dex.conditions.get(status) as Effect;
if (!this.sideConditions[status.id]) return false;
this.battle.singleEvent('End', status, this.sideConditions[status.id], this);
this.battle.singleEvent('SideEnd', status, this.sideConditions[status.id], this);
delete this.sideConditions[status.id];
return true;
}

View File

@@ -28,7 +28,7 @@ describe('Disguise', function () {
battle.setPlayer('p1', {team: [{species: 'Mimikyu', ability: 'disguise', moves: ['splash']}]});
battle.setPlayer('p2', {team: [{species: 'Sableye', ability: 'prankster', moves: ['confuseray']}]});
assert.false.hurts(battle.p1.active[0], () => battle.makeChoices());
assert(battle.p1.active[0].abilityData.busted);
assert(battle.p1.active[0].abilityState.busted);
});
it('should not block damage from weather effects', function () {

View File

@@ -63,7 +63,7 @@ describe('G-Max Volcalith', function () {
assert.equal(battle.p2.active[0].hp, expectedHP);
});
it.skip(`should damage Pokemon in order of Speed`, function () {
it(`should damage Pokemon in order of Speed`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'Coalossal', moves: ['sleeptalk', 'rockthrow'], gigantamax: true},
{species: 'Wynaut', moves: ['sleeptalk']},
@@ -85,7 +85,7 @@ describe('G-Max Volcalith', function () {
assert(mewtwoDamagedTRIndex < wynautDamagedTRIndex, 'Wynaut should be damaged before Mewtwo in Trick Room.');
});
it.skip(`should deal damage before Black Sludge recovery/damage`, function () {
it(`should deal damage before Black Sludge recovery/damage`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'Coalossal', moves: ['sleeptalk', 'rockthrow'], gigantamax: true},
{species: 'Wynaut', moves: ['sleeptalk']},