Spaces:
Running
Running
; | |
const path = require('path'); | |
const fs = require('fs'); | |
const assert = require('./assert'); | |
const Sim = require('./../dist/sim'); | |
const Dex = Sim.Dex; | |
const cache = new Map(); | |
const formatsCache = new Map(); | |
function capitalize(word) { | |
return word.charAt(0).toUpperCase() + word.slice(1); | |
} | |
/** | |
* The default random number generator seed used if one is not given. | |
*/ | |
const DEFAULT_SEED = 'gen5,99176924e1c86af0'; | |
class TestTools { | |
constructor(mod = 'base') { | |
this.currentMod = mod; | |
this.dex = Dex.mod(mod); | |
this.modPrefix = this.dex.isBase ? `[gen9] ` : `[${mod}] `; | |
} | |
mod(mod) { | |
if (cache.has(mod)) return cache.get(mod); | |
if (typeof mod !== 'string') throw new Error("This only supports strings"); | |
if (!Dex.dexes[mod]) throw new Error(`Mod ${mod} does not exist`); | |
const moddedTestTools = new TestTools(mod); | |
cache.set(mod, moddedTestTools); | |
return moddedTestTools; | |
} | |
gen(genNum) { | |
return this.mod('gen' + genNum); | |
} | |
getFormat(options) { | |
if (options.formatid) { | |
const format = Dex.formats.get(options.formatid); | |
if (format.effectType !== 'Format') throw new Error(`Unidentified format: ${options.formatid}`); | |
return format; | |
} | |
const gameType = Dex.toID(options.gameType || 'singles'); | |
const customRules = [ | |
options.pokemon && '-Nonexistent', | |
options.legality && 'Obtainable', | |
!options.preview && '!Team Preview', | |
options.sleepClause && 'Sleep Clause Mod', | |
!options.cancel && '!Cancel Mod', | |
options.endlessBattleClause && 'Endless Battle Clause', | |
options.inverseMod && 'Inverse Mod', | |
options.overflowStatMod && 'Overflow Stat Mod', | |
].filter(Boolean); | |
const customRulesID = customRules.length ? `@@@${customRules.join(',')}` : ``; | |
let basicFormat = this.currentMod === 'base' && gameType === 'singles' ? 'Anything Goes' : 'Custom Game'; | |
let modPrefix = this.modPrefix; | |
if (this.currentMod === 'gen1stadium') basicFormat = 'OU'; | |
if (gameType === 'multi') { | |
basicFormat = 'randombattle'; | |
modPrefix = `[gen8] `; // Remove when multis support Gen 9 | |
} | |
// Re-integrate to the above if statement when gen 9 ffa randbats is added | |
if (gameType === 'freeforall') basicFormat = ''; | |
const gameTypePrefix = gameType === 'singles' ? '' : capitalize(gameType) + ' '; | |
const formatName = `${modPrefix}${gameTypePrefix}${basicFormat}${customRulesID}`; | |
let format = formatsCache.get(formatName); | |
if (format) return format; | |
format = Dex.formats.get(formatName); | |
if (format.effectType !== 'Format') throw new Error(`Unidentified format: ${formatName}`); | |
formatsCache.set(formatName, format); | |
return format; | |
} | |
/** | |
* Creates a new Battle and returns it. | |
* | |
* @param {Object} [options] | |
* @param {Team[]} [teams] | |
* @returns {Sim.Battle} A battle. | |
*/ | |
createBattle(options, teams) { | |
if (Array.isArray(options)) { | |
teams = options; | |
options = {}; | |
} | |
if (!options) options = {}; | |
const format = this.getFormat(options); | |
const battleOptions = { | |
debug: true, | |
forceRandomChance: options.forceRandomChance, | |
format, | |
// If a seed for the pseudo-random number generator is not provided, | |
// a default seed (guaranteed to be the same across test executions) | |
// will be used. | |
seed: options.seed === undefined ? DEFAULT_SEED : (options.seed || undefined), | |
strictChoices: options.strictChoices !== false, | |
}; | |
if (!teams) return new Sim.Battle(battleOptions); | |
for (let i = 0; i < teams.length; i++) { | |
assert(Array.isArray(teams[i]), `Team provided is not an array`); | |
const playerSlot = `p${i + 1}`; | |
battleOptions[playerSlot] = { team: teams[i] }; | |
} | |
return new Sim.Battle(battleOptions); | |
} | |
/** | |
* Saves the log of the given battle as a bare-bones replay file in the `test\replays` directory | |
* You can view the replay by opening the file in any browser or by dragging and dropping the | |
* file into a PS! client window. | |
* | |
* @param {Sim.Battle} battle | |
* @param {string} [fileName] | |
*/ | |
saveReplay(battle, fileName) { | |
const battleLog = battle.getDebugLog(); | |
if (!fileName) fileName = 'test-replay'; | |
const filePath = path.resolve(__dirname, `./replays/${fileName}-${Date.now()}.html`); | |
const out = fs.createWriteStream(filePath, { flags: 'a' }); | |
out.on('open', () => { | |
out.write( | |
`<!DOCTYPE html>\n` + | |
`<script type="text/plain" class="battle-log-data">${battleLog}</script>\n` + | |
`<script src="https://play.pokemonshowdown.com/js/replay-embed.js"></script>\n` | |
); | |
out.end(); | |
}); | |
} | |
hasModule(mod) { | |
try { | |
require(mod); | |
return true; | |
} catch { | |
return false; | |
} | |
} | |
} | |
const common = exports = module.exports = new TestTools(); | |
cache.set('base', common); | |
cache.set('gen9', common); | |