"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var winrates_exports = {}; __export(winrates_exports, { commands: () => commands, getSpeciesName: () => getSpeciesName, handlers: () => handlers, pages: () => pages, saveStats: () => saveStats, stats: () => stats }); module.exports = __toCommonJS(winrates_exports); var import_lib = require("../../../lib"); const STATS_PATH = Monitor.logPath("randbats/{{MONTH}}-winrates.json").path; const stats = getDefaultStats(); try { const path = STATS_PATH.replace("{{MONTH}}", getMonth()); if (!Monitor.logPath("randbats/").existsSync()) { Monitor.logPath("randbats/").mkdirSync(); } const savedStats = JSON.parse((0, import_lib.FS)(path).readSync()); stats.elo = savedStats.elo; stats.month = savedStats.month; for (const k in stats.formats) { stats.formats[k] = savedStats.formats[k] || stats.formats[k]; } } catch { } function getDefaultStats() { return { elo: 1500, month: getMonth(), formats: { // all of these requested by rands staff. they don't anticipate it being changed much // so i'm not spending the time to add commands to toggle this gen9randombattle: { mons: {} }, gen9randomdoublesbattle: { mons: {} }, gen9babyrandombattle: { mons: {} }, gen9superstaffbrosultimate: { mons: {} }, gen8randombattle: { mons: {} }, gen7randombattle: { mons: {} }, gen6randombattle: { mons: {} }, gen5randombattle: { mons: {} }, gen4randombattle: { mons: {} }, gen3randombattle: { mons: {} }, gen2randombattle: { mons: {} }, gen1randombattle: { mons: {} } } }; } function saveStats(month = getMonth()) { const curStats = { ...stats }; (0, import_lib.FS)(STATS_PATH.replace("{{MONTH}}", month)).writeUpdate(() => JSON.stringify(curStats)); } function getMonth() { return Chat.toTimestamp(new Date()).split(" ")[0].slice(0, -3); } function getSpeciesName(set, format) { const species = set.species; const item = Dex.items.get(set.item); const moves = set.moves; const megaRayquazaPossible = ["gen6", "gen7"].includes(format.mod) && !format.ruleset.includes("Mega Rayquaza Clause"); if (species.startsWith("Pikachu-")) { return "Pikachu"; } else if (species.startsWith("Unown-")) { return "Unown"; } else if (species === "Gastrodon-East") { return "Gastrodon"; } else if (species === "Magearna-Original") { return "Magearna"; } else if (species === "Genesect-Douse") { return "Genesect"; } else if (species === "Dudunsparce-Three-Segment") { return "Dudunsparce"; } else if (species === "Maushold-Four") { return "Maushold"; } else if (species === "Greninja-Bond") { return "Greninja"; } else if (species === "Keldeo-Resolute") { return "Keldeo"; } else if (species === "Zarude-Dada") { return "Zarude"; } else if (species === "Polteageist-Antique") { return "Polteageist"; } else if (species === "Sinistcha-Masterpiece") { return "Sinistcha"; } else if (species === "Squawkabilly-Blue") { return "Squawkabilly"; } else if (species === "Squawkabilly-White") { return "Squawkabilly-Yellow"; } else if (species.startsWith("Basculin-")) { return "Basculin"; } else if (species.startsWith("Sawsbuck-")) { return "Sawsbuck"; } else if (species.startsWith("Vivillon-")) { return "Vivillon"; } else if (species.startsWith("Florges-")) { return "Florges"; } else if (species.startsWith("Furfrou-")) { return "Furfrou"; } else if (species.startsWith("Minior-")) { return "Minior"; } else if (species.startsWith("Toxtricity-")) { return "Toxtricity"; } else if (species.startsWith("Tatsugiri-")) { return "Tatsugiri"; } else if (species.startsWith("Alcremie-")) { return "Alcremie"; } else if (species === "Zacian" && item.name === "Rusted Sword") { return "Zacian-Crowned"; } else if (species === "Zamazenta" && item.name === "Rusted Shield") { return "Zamazenta-Crowned"; } else if (species === "Kyogre" && item.name === "Blue Orb") { return "Kyogre-Primal"; } else if (species === "Groudon" && item.name === "Red Orb") { return "Groudon-Primal"; } else if (item.megaStone) { return item.megaStone; } else if (species === "Rayquaza" && moves.includes("Dragon Ascent") && !item.zMove && megaRayquazaPossible) { return "Rayquaza-Mega"; } else if (species === "Poltchageist-Artisan") { return "Poltchageist"; } else if (species === "Shellos-East") { return "Shellos"; } else if (species === "Sinistea-Antique") { return "Sinistea"; } else if (species.startsWith("Deerling-")) { return "Deerling"; } else if (species.startsWith("Flabe\u0301be\u0301-")) { return "Flabe\u0301be\u0301"; } else { return species; } } function checkRollover() { if (stats.month !== getMonth()) { saveStats(stats.month); Object.assign(stats, getDefaultStats()); saveStats(); } } const getZScore = (data) => 2 * Math.sqrt(data.timesGenerated) * (data.numWins / data.timesGenerated - 0.5); const handlers = { onBattleEnd(battle, winner, players) { void collectStats(battle, winner, players); } }; async function collectStats(battle, winner, players) { const formatData = stats.formats[battle.format]; let eloFloor = stats.elo; const format = Dex.formats.get(battle.format); if (format.mod === "gen2" || format.team === "randomBaby") { eloFloor = 1150; } else if (format.mod !== `gen${Dex.gen}`) { eloFloor = 1300; } else if (format.gameType === "doubles") { eloFloor = 1400; } if (!formatData || format.mod !== "gen9ssb" && battle.rated < eloFloor || !winner) return; checkRollover(); for (const p of battle.players) { const team = await battle.getPlayerTeam(p); if (!team) return; const mons = team.map((f) => getSpeciesName(f, format)); for (const mon of mons) { if (!formatData.mons[mon]) formatData.mons[mon] = { timesGenerated: 0, numWins: 0 }; formatData.mons[mon].timesGenerated++; if (toID(winner) === toID(p.name)) { formatData.mons[mon].numWins++; } } } saveStats(); } const commands = { rwr: "randswinrates", randswinrates(target, room, user) { target = toID(target); if (/^(gen|)[0-9]+$/.test(target)) { if (target.startsWith("gen")) target = target.slice(3); target = `gen${target}randombattle`; } return this.parse(`/j view-winrates-${target ? Dex.formats.get(target).id : `gen${Dex.gen}randombattle`}`); }, randswinrateshelp: [ "/randswinrates OR /rwr [format] - Get a list of the win rates for all Pokemon in the given Random Battles format." ], async removewinrates(target, room, user) { this.checkCan("rangeban"); if (!/^[0-9]{4}-[0-9]{2}$/.test(target) || target === getMonth()) { return this.errorReply(`Invalid month: ${target}`); } const path = STATS_PATH.replace("{{MON}}", target); if (!await (0, import_lib.FS)(path).exists()) { return this.errorReply(`No stats for the month ${target}.`); } await (0, import_lib.FS)(path).unlinkIfExists(); this.globalModlog("REMOVEWINRATES", null, target); this.privateGlobalModAction(`${user.name} removed Random Battle winrates for the month of ${target}`); } }; const pages = { async winrates(query, user) { if (!user.named) return Rooms.RETRY_AFTER_LOGIN; query = query.join("-").split("--"); const format = toID(query.shift()); if (!format) return this.errorReply(`Specify a format to view winrates for.`); if (!stats.formats[format]) { return this.errorReply(`That format does not have winrates tracked.`); } checkRollover(); const sorter = toID(query.shift() || "zscore"); if (!["zscore", "raw"].includes(sorter)) { return this.errorReply(`Invalid sorting method. Must be either 'zscore' or 'raw'.`); } const month = query.shift() || getMonth(); if (!/^[0-9]{4}-[0-9]{2}$/.test(month)) { return this.errorReply(`Invalid month: ${month}`); } const isOldMonth = month !== getMonth(); if (isOldMonth && !await (0, import_lib.FS)(STATS_PATH.replace("{{MONTH}}", month)).exists()) { return this.errorReply(`There are no winrates for that month.`); } const formatTitle = Dex.formats.get(format).name; let buf = `
Pokemon | Win % | Z-Score | `; buf += `Raw wins | Times generated |
---|---|---|---|---|
${Dex.species.get(mon).name} | `; const { timesGenerated, numWins } = data; buf += `${(numWins / timesGenerated * 100).toFixed(2)}% | `; buf += `${getZScore(data).toFixed(3)} | `; buf += `${numWins} | ${timesGenerated} | `; buf += `