/** * 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}`); } } } }); } });