Skip to content

Commit

Permalink
Update Dex API (#8181)
Browse files Browse the repository at this point in the history
This is the change that renames:

- `Dex.getMove` -> `Dex.moves.get`
- `Dex.getAbility` -> `Dex.abilities.get`
- `Dex.getItem` -> `Dex.items.get`
- `Dex.getSpecies` -> `Dex.species.get`
- `Dex.getEffect` -> `Dex.conditions.get`
- `Dex.getNature` -> `Dex.natures.get`
- `Dex.getType` -> `Dex.types.get`
- `Dex.getFormat` -> `Dex.formats.get`

In addition, some other APIs have been updated:

- `getByID` methods have also been added to every other table.
- `Dex.moves.all()` now gets an array of all moves
  - Plus equivalent methods for `abilities`, `items`, `species`, `formats`, `natures`, `types`
  - Note: there's no `Dex.conditions.all()`
- new API: `Dex.stats` for naming/iterating stats
- `Dex.getEffectByID` -> `Dex.conditions.getByID`
- `Dex.getType` -> `Dex.types.get`
- `Dex.data.Formats` -> `Dex.data.Rulesets`
- `Dex.formats` -> now an array `Dex.formats.all()`
- `Dex.getRuleTable` -> `Dex.formats.getRuleTable`
- `Dex.validateFormat` -> `Dex.formats.validate`

Team functions have been split off into a new `sim/teams` package:

- `Dex.packTeam` -> `Teams.pack`
- `Dex.fastUnpackTeam` -> `Teams.unpack`
- `Dex.generateTeam` -> `Teams.generate`
- `Dex.stringifyTeam` -> `Teams.export`

`Teams.export` has also been rewritten to better match how it works in client.

This implements #8178
  • Loading branch information
Zarel committed Apr 8, 2021
1 parent 697cd71 commit 13189fd
Show file tree
Hide file tree
Showing 136 changed files with 2,918 additions and 2,529 deletions.
3 changes: 1 addition & 2 deletions PROTOCOL.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,8 +488,7 @@ To cancel searching, send:
### Team format

Pokémon Showdown's main way of representing teams is in packed format. This
format is implemented in `Dex.packTeam` and `Dex.fastUnpackTeam` in
`sim/dex.js`.
format is implemented in `Teams.pack` and `Teams.unpack` in `sim/teams.ts`.

If you're not using JavaScript and don't want to reimplement these conversions,
[Pokémon Showdown's command-line client][command-line] can convert between packed teams and
Expand Down
131 changes: 65 additions & 66 deletions config/formats.ts

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions data/FORMES.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Cosmetic formes are not listed in the `otherFormes` array, only in the `cosmetic

`{name: "Gastrodon", baseForme: "West", cosmeticFormes: ["gastodoneast"]}`

You will still be able to get a data entry for a cosmetic forme with `getSpecies` as normal, though:
You will still be able to get a data entry for a cosmetic forme with `species.get` as normal, though:

`{name: "Gastodon-East", forme: "East", baseSpecies: "Gastrodon"}`

Expand Down Expand Up @@ -192,6 +192,6 @@ Dynamax and Gigantamax are not considered formes by the games themselves. PS imp
`pokedex.js`
------------

All the data shown here is information available from `Dex.getSpecies`. Data in `pokedex.js` will not necessarily contain the same information.
All the data shown here is information available from `Dex.species.get`. Data in `pokedex.js` will not necessarily contain the same information.

Most importantly, note that cosmetic formes are not listed in `pokedex.js`, but generated automatically from their base forme entry.
56 changes: 28 additions & 28 deletions data/abilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onStart(pokemon) {
for (const target of pokemon.foes()) {
for (const moveSlot of target.moveSlots) {
const move = this.dex.getMove(moveSlot.move);
const move = this.dex.moves.get(moveSlot.move);
if (move.category === 'Status') continue;
const moveType = move.id === 'hiddenpower' ? target.hpType : move.type;
if (
Expand Down Expand Up @@ -191,7 +191,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
onSourceAfterFaint(length, target, source, effect) {
if (effect && effect.effectType === 'Move') {
this.boost({atk: length}, source, source, this.dex.getAbility('chillingneigh'));
this.boost({atk: length}, source, source, this.dex.abilities.get('chillingneigh'));
}
},
isPermanent: true,
Expand All @@ -213,7 +213,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
onSourceAfterFaint(length, target, source, effect) {
if (effect && effect.effectType === 'Move') {
this.boost({spa: length}, source, source, this.dex.getAbility('grimneigh'));
this.boost({spa: length}, source, source, this.dex.abilities.get('grimneigh'));
}
},
isPermanent: true,
Expand Down Expand Up @@ -297,7 +297,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
if (effect && effect.effectType === 'Move') {
let statName = 'atk';
let bestStat = 0;
let s: StatNameExceptHP;
let s: StatIDExceptHP;
for (s in source.storedStats) {
if (source.storedStats[s] > bestStat) {
statName = s;
Expand Down Expand Up @@ -422,7 +422,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onBoost(boost, target, source, effect) {
if (source && target === source) return;
let showMsg = false;
let i: BoostName;
let i: BoostID;
for (i in boost) {
if (boost[i]! < 0) {
delete boost[i];
Expand Down Expand Up @@ -502,7 +502,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
return;
}
let statsLowered = false;
let i: BoostName;
let i: BoostID;
for (i in boost) {
if (boost[i]! < 0) {
statsLowered = true;
Expand Down Expand Up @@ -531,7 +531,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
contrary: {
onBoost(boost, target, source, effect) {
if (effect && effect.id === 'zpower') return;
let i: BoostName;
let i: BoostID;
for (i in boost) {
boost[i]! *= -1;
}
Expand Down Expand Up @@ -689,7 +689,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
return;
}
let statsLowered = false;
let i: BoostName;
let i: BoostID;
for (i in boost) {
if (boost[i]! < 0) {
statsLowered = true;
Expand Down Expand Up @@ -789,7 +789,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
if (['mimikyu', 'mimikyutotem'].includes(pokemon.species.id) && this.effectData.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.getSpecies(speciesid));
this.damage(pokemon.baseMaxhp / 8, pokemon, pokemon, this.dex.species.get(speciesid));
}
},
isPermanent: true,
Expand Down Expand Up @@ -1061,7 +1061,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onAllyBoost(boost, target, source, effect) {
if ((source && target === source) || !target.hasType('Grass')) return;
let showMsg = false;
let i: BoostName;
let i: BoostID;
for (i in boost) {
if (boost[i]! < 0) {
delete boost[i];
Expand Down Expand Up @@ -1140,7 +1140,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
let warnBp = 1;
for (const target of pokemon.foes()) {
for (const moveSlot of target.moveSlots) {
const move = this.dex.getMove(moveSlot.move);
const move = this.dex.moves.get(moveSlot.move);
let bp = move.basePower;
if (move.ohko) bp = 150;
if (move.id === 'counter' || move.id === 'metalburst' || move.id === 'mirrorcoat') bp = 120;
Expand Down Expand Up @@ -1189,7 +1189,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onBoost(boost, target, source, effect) {
if (source && target === source) return;
let showMsg = false;
let i: BoostName;
let i: BoostID;
for (i in boost) {
if (boost[i]! < 0) {
delete boost[i];
Expand Down Expand Up @@ -1371,7 +1371,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onResidualSubOrder: 1,
onResidual(pokemon) {
if (this.field.isWeather(['sunnyday', 'desolateland']) || this.randomChance(1, 2)) {
if (pokemon.hp && !pokemon.item && this.dex.getItem(pokemon.lastItem).isBerry) {
if (pokemon.hp && !pokemon.item && this.dex.items.get(pokemon.lastItem).isBerry) {
pokemon.setItem(pokemon.lastItem);
pokemon.lastItem = '';
this.add('-item', pokemon, pokemon.getItem(), '[from] ability: Harvest');
Expand Down Expand Up @@ -1586,7 +1586,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
onDamagingHit(damage, target, source, move) {
if (target.illusion) {
this.singleEvent('End', this.dex.getAbility('Illusion'), target.abilityData, target, source, move);
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityData, target, source, move);
}
},
onEnd(pokemon) {
Expand Down Expand Up @@ -1636,7 +1636,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
// 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.getAbility('imposter'));
pokemon.transformInto(target, this.dex.abilities.get('imposter'));
}
this.effectData.switchingIn = false;
},
Expand Down Expand Up @@ -2087,7 +2087,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onBoost(boost, target, source, effect) {
// Don't bounce self stat changes, or boosts that have already bounced
if (target === source || !boost || effect.id === 'mirrorarmor') return;
let b: BoostName;
let b: BoostID;
for (b in boost) {
if (boost[b]! < 0) {
if (target.boosts[b] === -6) continue;
Expand Down Expand Up @@ -2126,20 +2126,20 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onResidualOrder: 26,
onResidualSubOrder: 1,
onResidual(pokemon) {
let stats: BoostName[] = [];
let stats: BoostID[] = [];
const boost: SparseBoostsTable = {};
let statPlus: BoostName;
let statPlus: BoostID;
for (statPlus in pokemon.boosts) {
if (statPlus === 'accuracy' || statPlus === 'evasion') continue;
if (pokemon.boosts[statPlus] < 6) {
stats.push(statPlus);
}
}
let randomStat: BoostName | undefined = stats.length ? this.sample(stats) : undefined;
let randomStat: BoostID | undefined = stats.length ? this.sample(stats) : undefined;
if (randomStat) boost[randomStat] = 2;

stats = [];
let statMinus: BoostName;
let statMinus: BoostID;
for (statMinus in pokemon.boosts) {
if (statMinus === 'accuracy' || statMinus === 'evasion') continue;
if (pokemon.boosts[statMinus] > -6 && statMinus !== randomStat) {
Expand Down Expand Up @@ -2206,7 +2206,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
if (move.flags['contact']) {
const oldAbility = source.setAbility('mummy', target);
if (oldAbility) {
this.add('-activate', target, 'ability: Mummy', this.dex.getAbility(oldAbility).name, '[of] ' + source);
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, '[of] ' + source);
}
}
},
Expand Down Expand Up @@ -2315,7 +2315,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
pokemon.abilityData.ending = false;
for (const target of this.getAllActive()) {
if (target.illusion) {
this.singleEvent('End', this.dex.getAbility('Illusion'), target.abilityData, target, pokemon, 'neutralizinggas');
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityData, target, pokemon, 'neutralizinggas');
}
if (target.volatiles['slowstart']) {
delete target.volatiles['slowstart'];
Expand Down Expand Up @@ -2587,7 +2587,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
const randomTarget = this.sample(pickupTargets);
const item = randomTarget.lastItem;
randomTarget.lastItem = '';
this.add('-item', pokemon, this.dex.getItem(item), '[from] ability: Pickup');
this.add('-item', pokemon, this.dex.items.get(item), '[from] ability: Pickup');
pokemon.setItem(item);
},
name: "Pickup",
Expand Down Expand Up @@ -2660,7 +2660,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
move.secondaries.push({
chance: 30,
status: 'psn',
ability: this.dex.getAbility('poisontouch'),
ability: this.dex.abilities.get('poisontouch'),
});
},
name: "Poison Touch",
Expand Down Expand Up @@ -2960,7 +2960,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
onBoost(boost, target, source, effect) {
if (effect && (effect as Item).isBerry) {
let b: BoostName;
let b: BoostID;
for (b in boost) {
boost[b]! *= 2;
}
Expand Down Expand Up @@ -3334,7 +3334,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
simple: {
onBoost(boost, target, source, effect) {
if (effect && effect.id === 'zpower') return;
let i: BoostName;
let i: BoostID;
for (i in boost) {
boost[i]! *= 2;
}
Expand Down Expand Up @@ -4152,7 +4152,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
if (target.isAlly(source)) {
this.add('-activate', target, 'Skill Swap', '', '', '[of] ' + source);
} else {
this.add('-activate', target, 'ability: Wandering Spirit', this.dex.getAbility(sourceAbility).name, 'Wandering Spirit', '[of] ' + source);
this.add('-activate', target, 'ability: Wandering Spirit', this.dex.abilities.get(sourceAbility).name, 'Wandering Spirit', '[of] ' + source);
}
target.setAbility(sourceAbility);
}
Expand Down Expand Up @@ -4256,7 +4256,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onBoost(boost, target, source, effect) {
if (source && target === source) return;
let showMsg = false;
let i: BoostName;
let i: BoostID;
for (i in boost) {
if (boost[i]! < 0) {
delete boost[i];
Expand Down
4 changes: 2 additions & 2 deletions data/conditions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ export const Conditions: {[k: string]: ConditionData} = {
this.effectData.move = effect.id;
target.addVolatile(effect.id);
let moveTarget: Pokemon | null = source;
if (effect.sourceEffect && this.dex.getMove(effect.id).target === 'normal') {
if (effect.sourceEffect && this.dex.moves.get(effect.id).target === 'normal') {
// this move was called by another move such as metronome and needs a random target to be determined now
// won't randomly choose an empty slot if there's at least one valid target
moveTarget = this.getRandomTarget(target, effect.id);
Expand Down Expand Up @@ -355,7 +355,7 @@ export const Conditions: {[k: string]: ConditionData} = {
onEnd(target) {
const data = this.effectData;
// time's up; time to hit! :D
const move = this.dex.getMove(data.move);
const move = this.dex.moves.get(data.move);
if (target.fainted || target === data.source) {
this.hint(`${move.name} did not hit because the target is ${(target.fainted ? 'fainted' : 'the user')}.`);
return;
Expand Down
18 changes: 9 additions & 9 deletions data/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,15 @@ export const Items: {[itemid: string]: ItemData} = {
this.add('-enditem', target, 'Air Balloon');
target.item = '';
target.itemData = {id: '', target};
this.runEvent('AfterUseItem', target, null, null, this.dex.getItem('airballoon'));
this.runEvent('AfterUseItem', target, null, null, this.dex.items.get('airballoon'));
},
onAfterSubDamage(damage, target, source, effect) {
this.debug('effect: ' + effect.id);
if (effect.effectType === 'Move') {
this.add('-enditem', target, 'Air Balloon');
target.item = '';
target.itemData = {id: '', target};
this.runEvent('AfterUseItem', target, null, null, this.dex.getItem('airballoon'));
this.runEvent('AfterUseItem', target, null, null, this.dex.items.get('airballoon'));
}
},
num: 541,
Expand Down Expand Up @@ -275,7 +275,7 @@ export const Items: {[itemid: string]: ItemData} = {
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (this.dex.getMove(moveSlot.move).category === 'Status') {
if (this.dex.moves.get(moveSlot.move).category === 'Status') {
pokemon.disableMove(moveSlot.id);
}
}
Expand Down Expand Up @@ -1420,7 +1420,7 @@ export const Items: {[itemid: string]: ItemData} = {
onAfterBoost(boost, target, source, effect) {
if (this.activeMove?.id === 'partingshot') return;
let eject = false;
let i: BoostName;
let i: BoostID;
for (i in boost) {
if (boost[i]! < 0) {
eject = true;
Expand Down Expand Up @@ -2910,7 +2910,7 @@ export const Items: {[itemid: string]: ItemData} = {
},
onAfterMoveSecondarySelf(source, target, move) {
if (source && source !== target && move && move.category !== 'Status') {
this.damage(source.baseMaxhp / 10, source, source, this.dex.getItem('lifeorb'));
this.damage(source.baseMaxhp / 10, source, source, this.dex.items.get('lifeorb'));
}
},
num: 270,
Expand Down Expand Up @@ -5243,8 +5243,8 @@ export const Items: {[itemid: string]: ItemData} = {
}
},
onEat(pokemon) {
const stats: BoostName[] = [];
let stat: BoostName;
const stats: BoostID[] = [];
let stat: BoostID;
for (stat in pokemon.boosts) {
if (stat !== 'accuracy' && stat !== 'evasion' && pokemon.boosts[stat] < 6) {
stats.push(stat);
Expand Down Expand Up @@ -6704,7 +6704,7 @@ export const Items: {[itemid: string]: ItemData} = {
effect(pokemon) {
let activate = false;
const boosts: SparseBoostsTable = {};
let i: BoostName;
let i: BoostID;
for (i in pokemon.boosts) {
if (pokemon.boosts[i] < 0) {
activate = true;
Expand All @@ -6720,7 +6720,7 @@ export const Items: {[itemid: string]: ItemData} = {
onUpdate(pokemon) {
let activate = false;
const boosts: SparseBoostsTable = {};
let i: BoostName;
let i: BoostID;
for (i in pokemon.boosts) {
if (pokemon.boosts[i] < 0) {
activate = true;
Expand Down
8 changes: 4 additions & 4 deletions data/mods/gen1/moves.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,11 @@ export const Moves: {[k: string]: ModdedMoveData} = {
// - (Counter will thus desync if the target's last used move is not as counterable as the target's last selected move)
// - if Counter succeeds it will deal twice the last move damage dealt in battle (even if it's from a different pokemon because of a switch)

const lastMove = target.side.lastMove && this.dex.getMove(target.side.lastMove.id);
const lastMove = target.side.lastMove && this.dex.moves.get(target.side.lastMove.id);
const lastMoveIsCounterable = lastMove && lastMove.basePower > 0 &&
['Normal', 'Fighting'].includes(lastMove.type) && lastMove.id !== 'counter';

const lastSelectedMove = target.side.lastSelectedMove && this.dex.getMove(target.side.lastSelectedMove);
const lastSelectedMove = target.side.lastSelectedMove && this.dex.moves.get(target.side.lastSelectedMove);
const lastSelectedMoveIsCounterable = lastSelectedMove && lastSelectedMove.basePower > 0 &&
['Normal', 'Fighting'].includes(lastSelectedMove.type) && lastSelectedMove.id !== 'counter';

Expand Down Expand Up @@ -296,7 +296,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.effectData.duration++;
}
const moves = pokemon.moves;
const move = this.dex.getMove(this.sample(moves));
const move = this.dex.moves.get(this.sample(moves));
this.add('-start', pokemon, 'Disable', move.name);
this.effectData.move = move.id;
return;
Expand Down Expand Up @@ -558,7 +558,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
const moves = target.moves;
const moveid = this.sample(moves);
if (!moveid) return false;
const move = this.dex.getMove(moveid);
const move = this.dex.moves.get(moveid);
source.moveSlots[moveslot] = {
move: move.name,
id: move.id,
Expand Down

0 comments on commit 13189fd

Please sign in to comment.