diff --git a/config/formats.js b/config/formats.js
index 08b92d8740698..9aae232c50477 100644
--- a/config/formats.js
+++ b/config/formats.js
@@ -520,6 +520,35 @@ let Formats = [
section: "OM of the Month",
column: 2,
},
+ {
+ name: "[Gen 7] Pokebilities",
+ desc: `Pokémon have all of their released Abilities simultaneously.`,
+ threads: [
+ `• Pokébilities`,
+ ],
+
+ mod: 'pokebilities',
+ ruleset: ['[Gen 7] OU'],
+ banlist: ['Diglett', 'Dugtrio', 'Excadrill', 'Gothita', 'Gothitelle', 'Gothorita', 'Trapinch', 'Wobbuffet', 'Wynaut'],
+ onBegin: function () {
+ let allPokemon = this.p1.pokemon.concat(this.p2.pokemon);
+ for (let pokemon of allPokemon) {
+ if (pokemon.ability === pokemon.template.abilities['S']) {
+ continue;
+ }
+ // @ts-ignore
+ pokemon.innates = Object.keys(pokemon.template.abilities).filter(key => key !== 'S' && (key !== 'H' || !pokemon.template.unreleasedHidden)).map(key => toId(pokemon.template.abilities[key])).filter(ability => ability !== pokemon.ability);
+ }
+ },
+ onSwitchInPriority: 2,
+ onSwitchIn: function (pokemon) {
+ if (pokemon.innates) pokemon.innates.forEach(innate => pokemon.addVolatile("ability" + innate, pokemon));
+ },
+ onAfterMega: function (pokemon) {
+ Object.keys(pokemon.volatiles).filter(innate => innate.startsWith('ability')).forEach(innate => pokemon.removeVolatile(innate));
+ pokemon.innates = undefined;
+ },
+ },
{
name: "[Gen 7] Hidden Type",
desc: `Pokémon have an added type determined by their IVs. Same as the Hidden Power type.`,
@@ -530,7 +559,7 @@ let Formats = [
mod: 'gen7',
ruleset: ['[Gen 7] OU'],
onModifyTemplate: function (template, pokemon) {
- if (template.types.includes(pokemon.hpType)) return;
+ if (!pokemon || template.types.includes(pokemon.hpType)) return;
let dex = this && this.deepClone ? this : Dex;
let newTemplate = dex.deepClone(template);
newTemplate.addedType = pokemon.hpType;
diff --git a/dev-tools/globals.ts b/dev-tools/globals.ts
index 37cd31bb7cc0f..98eb7b23874d4 100644
--- a/dev-tools/globals.ts
+++ b/dev-tools/globals.ts
@@ -755,12 +755,15 @@ interface ModdedBattlePokemon {
boostBy?: (this: Pokemon, boost: SparseBoostsTable) => boolean
calculateStat?: (this: Pokemon, statName: string, boost: number, modifier?: number) => number
getActionSpeed?: (this: Pokemon) => number
+ getRequestData?: (this: Pokemon) => {moves: {move: string, id: string, target?: string, disabled?: boolean}[], maybeDisabled?: boolean, trapped?: boolean, maybeTrapped?: boolean, canMegaEvo?: boolean, canUltraBurst?: boolean, canZMove?: AnyObject | null}
getStat?: (this: Pokemon, statName: string, unboosted?: boolean, unmodified?: boolean) => number
getWeight?: (this: Pokemon) => number
+ hasAbility?: (this: Pokemon, ability: string | string[]) => boolean
isGrounded?: (this: Pokemon, negateImmunity: boolean | undefined) => boolean | null
modifyStat?: (this: Pokemon, statName: string, modifier: number) => void
moveUsed?: (this: Pokemon, move: Move, targetLoc?: number) => void
recalculateStats?: (this: Pokemon) => void
+ setAbility?: (this: Pokemon, ability: string | Ability, source: Pokemon | null, isFromFormeChange: boolean) => string | false
transformInto?: (this: Pokemon, pokemon: Pokemon, effect: Effect | null) => boolean
}
@@ -772,11 +775,13 @@ interface ModdedBattleScriptsData extends Partial {
boost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source?: Pokemon | null, effect?: Effect | string | null, isSecondary?: boolean, isSelf?: boolean) => boolean | null | 0
debug?: (this: Battle, activity: string) => void
getDamage?: (this: Battle, pokemon: Pokemon, target: Pokemon, move: string | number | ActiveMove, suppressMessages: boolean) => number
+ getEffect?: (this: Battle, name: string | Effect | null) => Effect
init?: (this: Battle) => void
modifyDamage?: (this: Battle, baseDamage: number, pokemon: Pokemon, target: Pokemon, move: ActiveMove, suppressMessages?: boolean) => void
natureModify?: (this: Battle, stats: StatsTable, set: PokemonSet) => StatsTable
setTerrain?: (this: Battle, status: string | Effect, source: Pokemon | null | 'debug', sourceEffect: Effect | null) => boolean
spreadModify?: (this: Battle, baseStats: StatsTable, set: PokemonSet) => StatsTable
+ suppressingWeather?: (this: Battle) => boolean
// oms
doGetMixedTemplate?: (this: Battle, template: Template, deltas: AnyObject) => Template
diff --git a/mods/pic/moves.js b/mods/pic/moves.js
index 27d0411bb04e6..8657727232935 100644
--- a/mods/pic/moves.js
+++ b/mods/pic/moves.js
@@ -1,5 +1,6 @@
'use strict';
+/**@type {{[k: string]: ModdedMoveData}} */
exports.BattleMovedex = {
"skillswap": {
inherit: true,
@@ -26,8 +27,8 @@ exports.BattleMovedex = {
if (targetAbility.id !== sourceAbility.id) {
source.ability = targetAbility.id;
target.ability = sourceAbility.id;
- source.abilityData = {id: source.ability.id, target: source};
- target.abilityData = {id: target.ability.id, target: target};
+ source.abilityData = {id: source.ability, target: source};
+ target.abilityData = {id: target.ability, target: target};
}
if (sourceAlly && sourceAlly.ability !== source.ability) {
let volatile = sourceAlly.innate = 'ability' + source.ability;
diff --git a/mods/pic/scripts.js b/mods/pic/scripts.js
index 2aed4151e8246..fac3a58f38b7f 100644
--- a/mods/pic/scripts.js
+++ b/mods/pic/scripts.js
@@ -1,7 +1,8 @@
'use strict';
+/**@type {ModdedBattleScriptsData} */
exports.BattleScripts = {
- getEffect: function (name) {
+ getEffect(name) {
if (name && typeof name !== 'string') {
return name;
}
@@ -10,7 +11,7 @@ exports.BattleScripts = {
return Object.getPrototypeOf(this).getEffect.call(this, name);
},
pokemon: {
- setAbility: function (ability, source, isFromFormechange) {
+ setAbility(ability, source, isFromFormechange) {
if (!this.hp) return false;
ability = this.battle.getAbility(ability);
let oldAbility = this.ability;
@@ -36,7 +37,7 @@ exports.BattleScripts = {
this.abilityOrder = this.battle.abilityOrder++;
return oldAbility;
},
- hasAbility: function (ability) {
+ hasAbility(ability) {
if (!this.ignoringAbility()) {
if (Array.isArray(ability) ? ability.map(toId).includes(this.ability) : toId(ability) === this.ability) {
return true;
@@ -47,7 +48,7 @@ exports.BattleScripts = {
if (Array.isArray(ability)) return ability.map(toId).includes(ally.ability);
return toId(ability) === ally.ability;
},
- getRequestData: function () {
+ getRequestData() {
let ally = this.side.active.find(ally => ally && ally !== this && !ally.fainted);
this.moveSlots = this.baseMoveSlots.concat(ally ? ally.baseMoveSlots : []);
for (const moveSlot of this.moveSlots) {
diff --git a/mods/pokebilities/abilities.js b/mods/pokebilities/abilities.js
index 5cc2b8f84117b..e7f3e663f9974 100644
--- a/mods/pokebilities/abilities.js
+++ b/mods/pokebilities/abilities.js
@@ -1,16 +1,18 @@
'use strict';
+/**@type {{[k: string]: ModdedAbilityData}} */
exports.BattleAbilities = {
trace: {
inherit: true,
onUpdate: function (pokemon) {
if (!pokemon.isStarted) return;
let isAbility = this.effect.effectType === "Ability";
+ /**@type {string[]} */
let possibleInnates = [];
+ /**@type {Pokemon[]} */
let possibleTargets = [];
- for (let i = 0; i < pokemon.side.foe.active.length; i++) {
- let target = pokemon.side.foe.active[i];
- if (target && !target.fainted) {
+ for (let target of pokemon.side.foe.active) {
+ if (target && !target.fainted && target.innates) {
possibleInnates = possibleInnates.concat(target.innates);
possibleTargets = possibleTargets.concat(target.innates.map(innate => target));
}
@@ -30,7 +32,7 @@ exports.BattleAbilities = {
if (isAbility) {
pokemon.setAbility(ability);
} else {
- pokemon.removeVolatile("abilitytrace", pokemon);
+ pokemon.removeVolatile("abilitytrace");
pokemon.addVolatile("ability" + innate, pokemon);
}
return;
diff --git a/mods/pokebilities/scripts.js b/mods/pokebilities/scripts.js
index eaabf78e97056..6400fcb96d10f 100644
--- a/mods/pokebilities/scripts.js
+++ b/mods/pokebilities/scripts.js
@@ -1,7 +1,8 @@
'use strict';
+/**@type {ModdedBattleScriptsData} */
exports.BattleScripts = {
- getEffect: function (name) {
+ getEffect(name) {
if (name && typeof name !== 'string') {
return name;
}
@@ -22,13 +23,13 @@ exports.BattleScripts = {
return false;
},
pokemon: {
- hasAbility: function (ability) {
+ hasAbility(ability) {
if (this.ignoringAbility()) return false;
if (Array.isArray(ability)) return ability.some(ability => this.hasAbility(ability));
ability = toId(ability);
return this.ability === ability || !!this.volatiles['ability' + ability];
},
- transformInto: function (pokemon, effect) {
+ transformInto(pokemon, effect) {
let template = pokemon.template;
if (pokemon.fainted || pokemon.illusion || (pokemon.volatiles['substitute'] && this.battle.gen >= 5)) {
return false;
@@ -70,6 +71,7 @@ exports.BattleScripts = {
});
}
for (let j in pokemon.boosts) {
+ // @ts-ignore
this.boosts[j] = pokemon.boosts[j];
}
if (effect) {
@@ -77,9 +79,17 @@ exports.BattleScripts = {
} else {
this.battle.add('-transform', this, pokemon);
}
- this.setAbility(pokemon.ability, this, {id: 'transform'});
- this.innates.forEach(innate => this.removeVolatile('ability' + innate, this));
- pokemon.innates.forEach(innate => this.addVolatile('ability' + innate, this));
+ this.setAbility(pokemon.ability, this, true);
+ if (this.innates) {
+ for (let innate of this.innates) {
+ this.removeVolatile('ability' + innate);
+ }
+ }
+ if (pokemon.innates) {
+ for (let innate of pokemon.innates) {
+ this.addVolatile('ability' + innate, this);
+ }
+ }
return true;
},
},
diff --git a/tsconfig.json b/tsconfig.json
index 0af4d324a3aa1..2c9697497b663 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -11,9 +11,7 @@
},
"types": ["node"],
"exclude": [
- "./mods/gen1/pokedex.js",
- "./mods/pic/*.js",
- "./mods/pokebilities/*.js"
+ "./mods/gen1/pokedex.js"
],
"include": [
"./config/formats.js",