mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-05-17 10:46:53 -05:00
164 lines
6.9 KiB
JavaScript
164 lines
6.9 KiB
JavaScript
/**
|
|
* Miscellaneous Random Battle-related tests not associated with a particular generation.
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const assert = require('../assert');
|
|
const {Utils} = require('../../lib');
|
|
const {testTeam, assertSetValidity, validateLearnset} = require('./tools');
|
|
const {default: Dex} = require('../../sim/dex');
|
|
|
|
describe('value rule support', () => {
|
|
it('should generate teams of the proper length for the format (i.e. support Max Team Size)', () => {
|
|
testTeam({format: 'gen8randombattle', rounds: 100}, team => assert.equal(team.length, 6));
|
|
testTeam({format: 'gen8challengecup1v1', rounds: 100}, team => assert.equal(team.length, 6));
|
|
testTeam({format: 'gen8hackmonscup', rounds: 100}, team => assert.equal(team.length, 6));
|
|
|
|
testTeam({format: 'gen8multirandombattle', rounds: 100}, team => assert.equal(team.length, 3));
|
|
testTeam({format: 'gen8cap1v1', rounds: 100}, team => assert.equal(team.length, 3));
|
|
});
|
|
|
|
for (let gen = 1; gen <= 8; gen++) {
|
|
const formatID = `gen${gen}randombattle`;
|
|
const dex = Dex.forFormat(formatID);
|
|
for (const count of [1, 3, 24]) {
|
|
// This is tough to test in Gen 1 because we don't know how many moves a Pokémon ought to have,
|
|
// so we only test 'Max Move Count = 1' in Gen 1.
|
|
if (gen === 1 && count !== 1) continue;
|
|
const format = Dex.formats.get(`${formatID}@@@Max Move Count = ${count}`);
|
|
|
|
it(`${format.name} should support Max Move Count = ${count}`, () => {
|
|
testTeam({format, rounds: 50}, team => {
|
|
for (const set of team) {
|
|
let species = set.species;
|
|
// Formes make this test code really complicated, so we skip them
|
|
// (This is because info about formes isn't passed through)
|
|
if (dex.species.get(species).otherFormes?.length || dex.species.get(species).forme) continue;
|
|
if (set.gigantamax && !set.species.endsWith('max')) species += '-Gmax';
|
|
|
|
// If the Pokémon has less than the max in its movepool, we should
|
|
// just see all those moves
|
|
let totalMoves = 0;
|
|
let seenHP = false;
|
|
for (const move of dex.species.get(species).randomBattleMoves) {
|
|
if (move.startsWith('hiddenpower')) {
|
|
if (seenHP) continue;
|
|
seenHP = true;
|
|
}
|
|
totalMoves++;
|
|
}
|
|
|
|
const expected = Math.min(totalMoves, count);
|
|
assert.equal(set.moves.length, expected, `${species} should have ${expected} moves (moves=${set.moves})`);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
for (const format of Dex.formats.all()) {
|
|
if (!format.team) continue;
|
|
if (Dex.formats.getRuleTable(format).has('adjustleveldown')) continue; // already adjusts level
|
|
|
|
for (const level of [1, 99999]) {
|
|
it(`${format.name} should support Adjust Level = ${level}`, () => {
|
|
testTeam({format: `${format.id}@@@Adjust Level = ${level}`, rounds: 50}, team => {
|
|
for (const set of team) {
|
|
assert.equal(set.level, level);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
describe(`randomly generated teams should be valid (slow)`, () => {
|
|
for (const format of Dex.formats.all()) {
|
|
if (!format.team) continue; // format doesn't use randomly generated teams
|
|
|
|
it(`should generate valid ${format} teams`, function () {
|
|
this.timeout(0);
|
|
|
|
const targetTeamSize = Dex.formats.getRuleTable(format).maxTeamSize;
|
|
testTeam({format: format.id}, team => {
|
|
assert.equal(team.length, targetTeamSize, `Team of incorrect size (should have ${targetTeamSize} Pokémon but actually has ${team.length} Pokémon): ${JSON.stringify(team)}`);
|
|
|
|
for (const set of team) {
|
|
assertSetValidity(format, set);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
describe('Battle Factory and BSS Factory data should be valid (slow)', () => {
|
|
for (const filename of ['bss-factory-sets', 'mods/gen7/bss-factory-sets', 'mods/gen7/factory-sets', 'mods/gen6/factory-sets']) {
|
|
it(`${filename}.json should contain valid sets (slow)`, function () {
|
|
this.timeout(0);
|
|
const setsJSON = require(`../../data/${filename}.json`);
|
|
const mod = filename.split('/')[1] || 'gen' + Dex.gen;
|
|
const genNum = isNaN(mod[3]) ? Dex.gen : mod[3];
|
|
|
|
for (const type in setsJSON) {
|
|
const typeTable = filename.includes('bss-factory-sets') ? setsJSON : setsJSON[type];
|
|
const vType = filename === 'bss-factory-sets' ? `battle${genNum === 8 ? 'stadium' : 'spot'}singles` :
|
|
type === 'Mono' ? 'monotype' : type.toLowerCase();
|
|
for (const species in typeTable) {
|
|
const speciesData = typeTable[species];
|
|
for (const set of speciesData.sets) {
|
|
const species = Dex.species.get(set.species);
|
|
assert(species.exists, `invalid species "${set.species}" of ${species}`);
|
|
assert.equal(species.name, set.species, `miscapitalized species "${set.species}" of ${species}`);
|
|
|
|
// currently failing due to a Piloswine labeled as a Mamoswine set
|
|
assert(species.id.startsWith(toID(species.baseSpecies)), `non-matching species "${set.species}" of ${species}`);
|
|
|
|
assert(!species.battleOnly, `invalid battle-only forme "${set.species}" of ${species}`);
|
|
|
|
for (const itemName of [].concat(set.item)) {
|
|
if (!itemName && [].concat(...set.moves).includes("Acrobatics")) continue;
|
|
const item = Dex.items.get(itemName);
|
|
assert(item.exists, `invalid item "${itemName}" of ${species}`);
|
|
assert.equal(item.name, itemName, `miscapitalized item "${itemName}" of ${species}`);
|
|
}
|
|
|
|
for (const abilityName of [].concat(set.ability)) {
|
|
const ability = Dex.abilities.get(abilityName);
|
|
assert(ability.exists, `invalid ability "${abilityName}" of ${species}`);
|
|
assert.equal(ability.name, abilityName, `miscapitalized ability "${abilityName}" of ${species}`);
|
|
}
|
|
|
|
for (const natureName of [].concat(set.nature)) {
|
|
const nature = Dex.natures.get(natureName);
|
|
assert(nature.exists, `invalid nature "${natureName}" of ${species}`);
|
|
assert.equal(nature.name, natureName, `miscapitalized nature "${natureName}" of ${species}`);
|
|
}
|
|
|
|
for (const moveSpec of set.moves) {
|
|
for (const moveName of [].concat(moveSpec)) {
|
|
const move = Dex.moves.get(moveName);
|
|
assert(move.exists, `invalid move "${moveName}" of ${species}`);
|
|
assert.equal(move.name, moveName, `miscapitalized move "${moveName}" ≠ "${move.name}" of ${species}`);
|
|
assert(validateLearnset(move, set, vType, mod), `illegal move "${moveName}" of ${species}`);
|
|
}
|
|
}
|
|
|
|
assert(!!set.evs, `Set of ${species} has no EVs specified`);
|
|
const keys = Object.keys(set.evs);
|
|
let totalEVs = 0;
|
|
for (const ev of keys) {
|
|
assert(Dex.stats.ids().includes(ev), `Invalid EV key (${ev}) on set of ${species}`);
|
|
totalEVs += set.evs[ev];
|
|
assert.equal(set.evs[ev] % 4, 0, `EVs of ${ev} not divisible by 4 on ${species}`);
|
|
}
|
|
const sortedKeys = Utils.sortBy([...keys], ev => Dex.stats.ids().indexOf(ev));
|
|
assert.deepEqual(keys, sortedKeys, `EVs out of order on set of ${species}, possibly because one of them is for the wrong stat`);
|
|
assert(totalEVs <= 510, `more than 510 EVs on set of ${species}`);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|