{ "version": 3, "sources": ["../../server/room-battle.ts"], "sourcesContent": ["/**\n * Room Battle\n * Pokemon Showdown - http://pokemonshowdown.com/\n *\n * This file wraps the simulator in an implementation of the RoomGame\n * interface. It also abstracts away the multi-process nature of the\n * simulator.\n *\n * For the actual battle simulation, see sim/\n *\n * @license MIT\n */\n\nimport { execSync } from \"child_process\";\nimport { Repl, ProcessManager, type Streams } from '../lib';\nimport { BattleStream } from \"../sim/battle-stream\";\nimport { RoomGamePlayer, RoomGame } from \"./room-game\";\nimport type { Tournament } from './tournaments/index';\nimport type { RoomSettings } from './rooms';\nimport type { BestOfGame } from './room-battle-bestof';\nimport type { GameTimerSettings } from '../sim/dex-formats';\n\ntype ChannelIndex = 0 | 1 | 2 | 3 | 4;\nexport type PlayerIndex = 1 | 2 | 3 | 4;\nexport type ChallengeType = 'rated' | 'unrated' | 'challenge' | 'tour';\n\ninterface BattleRequestTracker {\n\trqid: number;\n\trequest: string;\n\t/**\n\t * - true = user has decided,\n\t * - false = user has yet to decide,\n\t * - 'cantUndo' = waiting on other user (U-turn, faint-switch) or uncancellable (trapping ability)\n\t */\n\tisWait: 'cantUndo' | true | false;\n\tchoice: string;\n}\n\n/** 5 seconds */\nconst TICK_TIME = 5;\nconst SECONDS = 1000;\n\n// Timer constants: In seconds, should be multiple of TICK_TIME\nconst STARTING_TIME = 150;\nconst MAX_TURN_TIME = 150;\nconst STARTING_TIME_CHALLENGE = 300;\nconst STARTING_GRACE_TIME = 60;\nconst MAX_TURN_TIME_CHALLENGE = 300;\n\nconst DISCONNECTION_TIME = 60;\nconst DISCONNECTION_BANK_TIME = 300;\n\n// time after a player disabling the timer before they can re-enable it\nconst TIMER_COOLDOWN = 20 * SECONDS;\nconst LOCKDOWN_PERIOD = 30 * 60 * 1000; // 30 minutes\n\nexport class RoomBattlePlayer extends RoomGamePlayer {\n\treadonly slot: SideID;\n\treadonly channelIndex: ChannelIndex;\n\trequest: BattleRequestTracker;\n\twantsTie: boolean;\n\twantsOpenTeamSheets: boolean | null;\n\teliminated: boolean;\n\t/**\n\t * Total timer.\n\t *\n\t * Starts at 210 per player in a ladder battle. Goes down by 5\n\t * every tick. Goes up by 10 every turn (with some complications -\n\t * see `nextRequest`), capped at starting time. The player loses if\n\t * this reaches 0.\n\t *\n\t * The equivalent of \"Your Time\" in VGC.\n\t *\n\t */\n\tsecondsLeft: number;\n\t/**\n\t * Current turn timer.\n\t *\n\t * Set equal to the player's overall timer, but capped at 150\n\t * seconds in a ladder battle. Goes down by 5 every tick.\n\t * Tracked separately from the overall timer, and the player also\n\t * loses if this reaches 0 (except in VGC where the default choice\n\t * is chosen if it reaches 0).\n\t */\n\tturnSecondsLeft: number;\n\t/**\n\t * Disconnect timer.\n\t *\n\t * Starts at 60 seconds. While the player is disconnected, this\n\t * will go down by 5 every tick. Tracked separately from the\n\t * overall timer, and the player also loses if this reaches 0.\n\t *\n\t * Mostly exists so impatient players don't have to wait the full\n\t * 150 seconds against a disconnected opponent.\n \t*/\n\tdcSecondsLeft: number;\n\t/**\n\t * Is the user actually in the room?\n\t */\n\tactive: boolean;\n\t/**\n\t * Used to track a user's last known connection status, and display\n\t * the proper message when it changes.\n\t *\n\t * `.active` is set right when the user joins/leaves, but `.knownActive`\n\t * is only set after the timer knows about it.\n\t */\n\tknownActive: boolean;\n\tinvite: ID;\n\t/**\n\t * Has the simulator received this player's team yet?\n\t * Basically always yes except when creating a 4-player battle,\n\t * in which case players will need to bring their own team.\n\t */\n\thasTeam: boolean;\n\tconstructor(user: User | string | null, game: RoomBattle, num: PlayerIndex) {\n\t\tsuper(user, game, num);\n\t\tif (typeof user === 'string') user = null;\n\n\t\tthis.slot = `p${num}` as SideID;\n\t\tthis.channelIndex = (game.gameType === 'multi' && num > 2 ? num - 2 : num) as ChannelIndex;\n\n\t\tthis.request = { rqid: 0, request: '', isWait: 'cantUndo', choice: '' };\n\t\tthis.wantsTie = false;\n\t\tthis.wantsOpenTeamSheets = null;\n\t\tthis.active = !!user?.connected;\n\t\tthis.eliminated = false;\n\n\t\tthis.secondsLeft = 1;\n\t\tthis.turnSecondsLeft = 1;\n\t\tthis.dcSecondsLeft = 1;\n\n\t\tthis.knownActive = true;\n\t\tthis.invite = '';\n\t\tthis.hasTeam = false;\n\n\t\tif (user) {\n\t\t\tuser.games.add(this.game.roomid);\n\t\t\tuser.updateSearch();\n\t\t\tfor (const connection of user.connections) {\n\t\t\t\tif (connection.inRooms.has(game.roomid)) {\n\t\t\t\t\tSockets.channelMove(connection.worker, this.game.roomid, this.channelIndex, connection.socketid);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\toverride destroy() {\n\t\tconst user = this.getUser();\n\t\tif (user) {\n\t\t\tthis.updateChannel(user, 0);\n\t\t}\n\t\tthis.knownActive = false;\n\t\tthis.active = false;\n\t}\n\tupdateChannel(user: User | Connection, channel = this.channelIndex) {\n\t\tfor (const connection of (user.connections || [user])) {\n\t\t\tSockets.channelMove(connection.worker, this.game.roomid, channel, connection.socketid);\n\t\t}\n\t}\n}\n\nexport class RoomBattleTimer {\n\treadonly battle: RoomBattle;\n\treadonly timerRequesters: Set;\n\ttimer: NodeJS.Timeout | null;\n\tisFirstTurn: boolean;\n\t/**\n\t * Last tick, as milliseconds since UNIX epoch.\n\t * Represents the last time a tick happened.\n\t */\n\tlastTick: number;\n\t/** Debug mode; true to output detailed timer info every tick */\n\tdebug: boolean;\n\tlastDisabledTime: number;\n\tlastDisabledByUser: null | ID;\n\tsettings: GameTimerSettings;\n\tconstructor(battle: RoomBattle) {\n\t\tthis.battle = battle;\n\n\t\tthis.timer = null;\n\t\tthis.timerRequesters = new Set();\n\t\tthis.isFirstTurn = true;\n\n\t\tthis.lastTick = 0;\n\n\t\tthis.debug = false;\n\n\t\tthis.lastDisabledTime = 0;\n\t\tthis.lastDisabledByUser = null;\n\n\t\tconst format = Dex.formats.get(battle.format, true);\n\t\tconst hasLongTurns = format.gameType !== 'singles';\n\t\tconst isChallenge = (battle.challengeType === 'challenge');\n\t\tconst timerEntry = Dex.formats.getRuleTable(format).timer;\n\t\tconst timerSettings = timerEntry?.[0];\n\n\t\t// so that Object.assign doesn't overwrite anything with `undefined`\n\t\tfor (const k in timerSettings) {\n\t\t\t// @ts-expect-error prop access\n\t\t\tif (timerSettings[k] === undefined) delete timerSettings[k];\n\t\t}\n\n\t\tthis.settings = {\n\t\t\tdcTimer: !isChallenge,\n\t\t\tdcTimerBank: isChallenge,\n\t\t\tstarting: isChallenge ? STARTING_TIME_CHALLENGE : STARTING_TIME,\n\t\t\tgrace: STARTING_GRACE_TIME,\n\t\t\taddPerTurn: hasLongTurns ? 25 : 10,\n\t\t\tmaxPerTurn: isChallenge ? MAX_TURN_TIME_CHALLENGE : MAX_TURN_TIME,\n\t\t\tmaxFirstTurn: isChallenge ? MAX_TURN_TIME_CHALLENGE : MAX_TURN_TIME,\n\t\t\ttimeoutAutoChoose: false,\n\t\t\taccelerate: !timerSettings && !isChallenge,\n\t\t\t...timerSettings,\n\t\t};\n\t\tif (this.settings.maxPerTurn <= 0) this.settings.maxPerTurn = Infinity;\n\n\t\tfor (const player of this.battle.players) {\n\t\t\tplayer.secondsLeft = this.settings.starting + this.settings.grace;\n\t\t\tplayer.turnSecondsLeft = -1;\n\t\t\tplayer.dcSecondsLeft = this.settings.dcTimerBank ? DISCONNECTION_BANK_TIME : DISCONNECTION_TIME;\n\t\t}\n\t}\n\tstart(requester?: User) {\n\t\tconst userid = requester ? requester.id : 'staff' as ID;\n\t\tif (this.timerRequesters.has(userid)) return false;\n\t\tif (this.battle.ended) {\n\t\t\trequester?.sendTo(this.battle.roomid, `|inactiveoff|The timer can't be enabled after a battle has ended.`);\n\t\t\treturn false;\n\t\t}\n\t\tif (this.timer) {\n\t\t\tthis.battle.room.add(`|inactive|${requester ? requester.name : userid} also wants the timer to be on.`).update();\n\t\t\tthis.timerRequesters.add(userid);\n\t\t\treturn false;\n\t\t}\n\t\tif (requester && this.battle.playerTable[requester.id] && this.lastDisabledByUser === requester.id) {\n\t\t\tconst remainingCooldownMs = (this.lastDisabledTime || 0) + TIMER_COOLDOWN - Date.now();\n\t\t\tif (remainingCooldownMs > 0) {\n\t\t\t\tthis.battle.playerTable[requester.id].sendRoom(\n\t\t\t\t\t`|inactiveoff|The timer can't be re-enabled so soon after disabling it (${Math.ceil(remainingCooldownMs / SECONDS)} seconds remaining).`\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\tthis.timerRequesters.add(userid);\n\t\tconst requestedBy = requester ? ` (requested by ${requester.name})` : ``;\n\t\tthis.battle.room.add(`|inactive|Battle timer is ON: inactive players will automatically lose when time's up.${requestedBy}`).update();\n\n\t\tthis.checkActivity();\n\t\tthis.nextRequest();\n\t\treturn true;\n\t}\n\tstop(requester?: User) {\n\t\tif (requester) {\n\t\t\tif (!this.timerRequesters.has(requester.id)) return false;\n\t\t\tthis.timerRequesters.delete(requester.id);\n\t\t\tthis.lastDisabledByUser = requester.id;\n\t\t\tthis.lastDisabledTime = Date.now();\n\t\t} else {\n\t\t\tthis.timerRequesters.clear();\n\t\t}\n\t\tif (this.timerRequesters.size) {\n\t\t\tthis.battle.room.add(`|inactive|${requester!.name} no longer wants the timer on, but the timer is staying on because ${[...this.timerRequesters].join(', ')} still does.`).update();\n\t\t\treturn false;\n\t\t}\n\t\tif (this.end()) {\n\t\t\tthis.battle.room.add(`|inactiveoff|Battle timer is now OFF.`).update();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\tend() {\n\t\tthis.timerRequesters.clear();\n\t\tif (!this.timer) return false;\n\t\tclearTimeout(this.timer);\n\t\tthis.timer = null;\n\t\treturn true;\n\t}\n\tnextRequest() {\n\t\tif (this.timer) {\n\t\t\tclearTimeout(this.timer);\n\t\t\tthis.timer = null;\n\t\t}\n\t\tif (!this.timerRequesters.size) return;\n\t\tconst players = this.battle.players;\n\t\tif (players.some(player => player.secondsLeft <= 0)) return;\n\n\t\t/** false = U-turn or single faint, true = \"new turn\" */\n\t\tlet isFull = true;\n\t\tlet isEmpty = true;\n\t\tfor (const player of players) {\n\t\t\tif (player.request.isWait) isFull = false;\n\t\t\tif (player.request.isWait !== 'cantUndo') isEmpty = false;\n\t\t}\n\t\tif (isEmpty) {\n\t\t\t// there are no active requests\n\t\t\treturn;\n\t\t}\n\t\tconst isFirst = this.isFirstTurn;\n\t\tthis.isFirstTurn = false;\n\n\t\tconst maxTurnTime = (isFirst ? this.settings.maxFirstTurn : 0) || this.settings.maxPerTurn;\n\n\t\tlet addPerTurn = isFirst ? 0 : this.settings.addPerTurn;\n\t\tif (this.settings.accelerate && addPerTurn) {\n\t\t\t// after turn 100ish: 15s/turn -> 10s/turn\n\t\t\tif (this.battle.requestCount > 200 && addPerTurn > TICK_TIME) {\n\t\t\t\taddPerTurn -= TICK_TIME;\n\t\t\t}\n\t\t\t// after turn 200ish: 10s/turn -> 7s/turn\n\t\t\tif (this.battle.requestCount > 400 && Math.floor(this.battle.requestCount / 2) % 2) {\n\t\t\t\taddPerTurn = 0;\n\t\t\t}\n\t\t}\n\n\t\tif (!isFull && addPerTurn > TICK_TIME) {\n\t\t\taddPerTurn = TICK_TIME;\n\t\t}\n\n\t\tconst room = this.battle.room;\n\t\tfor (const player of players) {\n\t\t\tif (!isFirst) {\n\t\t\t\tplayer.secondsLeft = Math.min(player.secondsLeft + addPerTurn, this.settings.starting);\n\t\t\t}\n\t\t\tplayer.turnSecondsLeft = Math.min(player.secondsLeft, maxTurnTime);\n\n\t\t\tconst secondsLeft = player.turnSecondsLeft;\n\t\t\tlet grace = player.secondsLeft - this.settings.starting;\n\t\t\tif (grace < 0) grace = 0;\n\t\t\tplayer.sendRoom(`|inactive|Time left: ${secondsLeft} sec this turn | ${player.secondsLeft - grace} sec total` + (grace ? ` | ${grace} sec grace` : ``));\n\t\t\tif (secondsLeft <= 30 && secondsLeft < this.settings.starting) {\n\t\t\t\troom.add(`|inactive|${player.name} has ${secondsLeft} seconds left this turn.`);\n\t\t\t}\n\t\t\tif (this.debug) {\n\t\t\t\troom.add(`||${player.name} | Time left: ${secondsLeft} sec this turn | ${player.secondsLeft} sec total | +${addPerTurn} seconds`);\n\t\t\t}\n\t\t}\n\t\troom.update();\n\t\tthis.lastTick = Date.now();\n\t\tthis.timer = setTimeout(() => this.nextTick(), TICK_TIME * SECONDS);\n\t}\n\tnextTick() {\n\t\tif (this.timer) clearTimeout(this.timer);\n\t\tif (this.battle.ended) return;\n\t\tconst room = this.battle.room;\n\t\tfor (const player of this.battle.players) {\n\t\t\tif (player.request.isWait) continue;\n\t\t\tif (player.knownActive) {\n\t\t\t\tplayer.secondsLeft -= TICK_TIME;\n\t\t\t\tplayer.turnSecondsLeft -= TICK_TIME;\n\t\t\t} else {\n\t\t\t\tplayer.dcSecondsLeft -= TICK_TIME;\n\t\t\t\tif (!this.settings.dcTimerBank) {\n\t\t\t\t\tplayer.secondsLeft -= TICK_TIME;\n\t\t\t\t\tplayer.turnSecondsLeft -= TICK_TIME;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst dcSecondsLeft = player.dcSecondsLeft;\n\t\t\tif (dcSecondsLeft <= 0) {\n\t\t\t\tplayer.turnSecondsLeft = 0;\n\t\t\t}\n\t\t\tconst secondsLeft = player.turnSecondsLeft;\n\t\t\tif (!secondsLeft) continue;\n\n\t\t\tif (!player.knownActive && (dcSecondsLeft <= secondsLeft || this.settings.dcTimerBank)) {\n\t\t\t\t// dc timer is shown only if it's lower than turn timer or you're in timer bank mode\n\t\t\t\tif (dcSecondsLeft % 30 === 0 || dcSecondsLeft <= 20) {\n\t\t\t\t\troom.add(`|inactive|${player.name} has ${dcSecondsLeft} seconds to reconnect!`);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// regular turn timer shown\n\t\t\t\tif (secondsLeft % 30 === 0 || secondsLeft <= 20) {\n\t\t\t\t\troom.add(`|inactive|${player.name} has ${secondsLeft} seconds left.`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.debug) {\n\t\t\t\troom.add(`||[${player.name} has ${player.turnSecondsLeft}s this turn / ${player.secondsLeft}s total]`);\n\t\t\t}\n\t\t}\n\t\troom.update();\n\t\tif (!this.checkTimeout()) {\n\t\t\tthis.timer = setTimeout(() => this.nextTick(), TICK_TIME * 1000);\n\t\t}\n\t}\n\tcheckActivity() {\n\t\tif (this.battle.ended) return;\n\t\tfor (const player of this.battle.players) {\n\t\t\tconst isActive = !!player.active;\n\n\t\t\tif (isActive === player.knownActive) continue;\n\n\t\t\tif (!isActive) {\n\t\t\t\t// player has disconnected\n\t\t\t\tplayer.knownActive = false;\n\t\t\t\tif (!this.settings.dcTimerBank) {\n\t\t\t\t\t// don't wait longer than 6 ticks (1 minute)\n\t\t\t\t\tif (this.settings.dcTimer) {\n\t\t\t\t\t\tplayer.dcSecondsLeft = DISCONNECTION_TIME;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// arbitrary large number\n\t\t\t\t\t\tplayer.dcSecondsLeft = DISCONNECTION_TIME * 10;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (this.timerRequesters.size) {\n\t\t\t\t\tlet msg = `!`;\n\n\t\t\t\t\tif (this.settings.dcTimer) {\n\t\t\t\t\t\tmsg = ` and has a minute to reconnect!`;\n\t\t\t\t\t}\n\t\t\t\t\tif (this.settings.dcTimerBank) {\n\t\t\t\t\t\tif (player.dcSecondsLeft > 0) {\n\t\t\t\t\t\t\tmsg = ` and has ${player.dcSecondsLeft} seconds to reconnect!`;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmsg = ` and has no disconnection time left!`;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis.battle.room.add(`|inactive|${player.name} disconnected${msg}`).update();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// player has reconnected\n\t\t\t\tplayer.knownActive = true;\n\t\t\t\tif (this.timerRequesters.size) {\n\t\t\t\t\tlet timeLeft = ``;\n\t\t\t\t\tif (!player.request.isWait) {\n\t\t\t\t\t\ttimeLeft = ` and has ${player.turnSecondsLeft} seconds left`;\n\t\t\t\t\t}\n\t\t\t\t\tthis.battle.room.add(`|inactive|${player.name} reconnected${timeLeft}.`).update();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tcheckTimeout() {\n\t\tconst players = this.battle.players;\n\t\tif (players.every(player => player.turnSecondsLeft <= 0)) {\n\t\t\tif (!this.settings.timeoutAutoChoose || players.every(player => player.secondsLeft <= 0)) {\n\t\t\t\tthis.battle.room.add(`|-message|All players are inactive.`).update();\n\t\t\t\tthis.battle.tie();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tlet didSomething = false;\n\t\tfor (const player of players) {\n\t\t\tif (!player.id) continue; // already eliminated, relevant for FFA gamesif it\n\t\t\t// https://play.pokemonshowdown.com/battle-gen9unratedrandombattle-2255606027-5a6bcd9zlb93e6id5pp7juvhcg5w41spw\n\t\t\t// why is this line here?\n\t\t\tif (player.turnSecondsLeft > 0) continue;\n\t\t\tif (this.settings.timeoutAutoChoose && player.secondsLeft > 0 && player.knownActive) {\n\t\t\t\tvoid this.battle.stream.write(`>${player.slot} default`);\n\t\t\t\tdidSomething = true;\n\t\t\t} else {\n\t\t\t\tthis.battle.forfeitPlayer(player, ' lost due to inactivity.');\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn didSomething;\n\t}\n}\n\nexport interface RoomBattlePlayerOptions {\n\tuser: User;\n\t/** should be '' for random teams */\n\tteam?: string;\n\trating?: number;\n\tinviteOnly?: boolean;\n\thidden?: boolean;\n}\n\nexport interface RoomBattleOptions {\n\tformat: string;\n\t/**\n\t * length should be equal to the format's playerCount, except in two\n\t * special cases:\n\t * - `/importinputlog`, where it's empty (players have to be invited/restored)\n\t * - challenge ffa/multi, where it's 2 (the rest have to be invited)\n\t * - restoring saved battles after a restart (players should be manually restored)\n\t * In all special cases, either `delayedStart` or `inputLog` must be set\n\t */\n\tplayers: RoomBattlePlayerOptions[];\n\tdelayedStart?: boolean | 'multi';\n\tchallengeType?: ChallengeType;\n\tallowRenames?: boolean;\n\trated?: number | boolean | null;\n\ttour?: Tournament | null;\n\tinputLog?: string;\n\tratedMessage?: string;\n\tseed?: PRNGSeed;\n\troomid?: RoomID;\n\t/** For battles restored after a restart */\n\tdelayedTimer?: boolean;\n\t/**\n\t * If false and the format is a best-of format, creates a best-of game\n\t * rather than a battle.\n\t */\n\tisBestOfSubBattle?: boolean;\n}\n\nexport class RoomBattle extends RoomGame {\n\toverride readonly gameid = 'battle' as ID;\n\toverride readonly room!: GameRoom;\n\toverride readonly title: string;\n\toverride readonly allowRenames: boolean;\n\treadonly format: string;\n\t/** Will exist even if the game is unrated, in case it's later forced to be rated */\n\treadonly ladder: string;\n\treadonly gameType: string | undefined;\n\treadonly challengeType: ChallengeType;\n\t/**\n\t * The lower player's rating, for searching purposes.\n\t * 0 for unrated battles. 1 for unknown ratings.\n\t */\n\treadonly rated: number;\n\t/**\n\t * userid that requested extraction -> playerids that accepted the extraction\n\t */\n\treadonly allowExtraction: { [k: string]: Set } = {};\n\treadonly stream: Streams.ObjectReadWriteStream;\n\toverride readonly timer: RoomBattleTimer;\n\tstarted = false;\n\tactive = false;\n\treplaySaved: boolean | 'auto' = false;\n\tforcedSettings: { modchat?: string | null, privacy?: string | null } = {};\n\tp1: RoomBattlePlayer = null!;\n\tp2: RoomBattlePlayer = null!;\n\tp3: RoomBattlePlayer = null!;\n\tp4: RoomBattlePlayer = null!;\n\tinviteOnlySetter: ID | null = null;\n\tlogData: AnyObject | null = null;\n\tendType: 'forfeit' | 'forced' | 'normal' = 'normal';\n\t/**\n\t * If the battle is ended: an array of the number of Pokemon left for each side.\n\t */\n\tscore: number[] | null = null;\n\tinputLog: string[] | null = null;\n\tturn = 0;\n\trqid = 1;\n\trequestCount = 0;\n\toptions: RoomBattleOptions;\n\tfrozen?: boolean;\n\tdataResolvers?: [((args: string[]) => void), ((error: Error) => void)][];\n\tconstructor(room: GameRoom, options: RoomBattleOptions) {\n\t\tsuper(room);\n\t\tconst format = Dex.formats.get(options.format, true);\n\t\tthis.title = format.name;\n\t\tthis.options = options;\n\t\tif (!this.title.endsWith(\" Battle\")) this.title += \" Battle\";\n\t\tthis.allowRenames = options.allowRenames !== undefined ? !!options.allowRenames : (!options.rated && !options.tour);\n\n\t\tthis.format = options.format;\n\t\tthis.gameType = format.gameType;\n\t\tthis.challengeType = options.challengeType || 'challenge';\n\t\tthis.rated = options.rated === true ? 1 : options.rated || 0;\n\t\tthis.ladder = typeof format.rated === 'string' ? toID(format.rated) : options.format;\n\t\tthis.playerCap = format.playerCount;\n\n\t\tthis.stream = PM.createStream();\n\n\t\tlet ratedMessage = options.ratedMessage || '';\n\t\tif (this.rated) {\n\t\t\tratedMessage = 'Rated battle';\n\t\t} else if (this.room.tour) {\n\t\t\tratedMessage = 'Tournament battle';\n\t\t}\n\n\t\tthis.room.battle = this;\n\n\t\tconst battleOptions = {\n\t\t\tformatid: this.format,\n\t\t\troomid: this.roomid,\n\t\t\trated: ratedMessage,\n\t\t\tseed: options.seed,\n\t\t};\n\t\tif (options.inputLog) {\n\t\t\tvoid this.stream.write(options.inputLog);\n\t\t} else {\n\t\t\tvoid this.stream.write(`>start ` + JSON.stringify(battleOptions));\n\t\t}\n\n\t\tvoid this.listen();\n\n\t\tif (options.players.length > this.playerCap) {\n\t\t\tthrow new Error(`${options.players.length} players passed to battle ${room.roomid} but ${this.playerCap} players expected`);\n\t\t}\n\t\tfor (let i = 0; i < this.playerCap; i++) {\n\t\t\tconst p = options.players[i];\n\t\t\tconst player = this.addPlayer(p?.user || null, p || null);\n\t\t\tif (!player) throw new Error(`failed to create player ${i + 1} in ${room.roomid}`);\n\t\t}\n\t\tif (options.inputLog) {\n\t\t\tlet scanIndex = 0;\n\t\t\tfor (const player of this.players) {\n\t\t\t\tconst nameIndex1 = options.inputLog.indexOf(`\"name\":\"`, scanIndex);\n\t\t\t\tconst nameIndex2 = options.inputLog.indexOf(`\"`, nameIndex1 + 8);\n\t\t\t\tif (nameIndex1 < 0 || nameIndex2 < 0) break; // shouldn't happen. incomplete inputlog?\n\t\t\t\tscanIndex = nameIndex2 + 1;\n\t\t\t\tconst name = options.inputLog.slice(nameIndex1 + 8, nameIndex2);\n\t\t\t\tplayer.name = name;\n\t\t\t\tplayer.hasTeam = true;\n\t\t\t}\n\t\t}\n\t\tthis.timer = new RoomBattleTimer(this);\n\t\tif (Config.forcetimer || this.format.includes('blitz')) this.timer.start();\n\t\tthis.start();\n\t}\n\n\tcheckActive() {\n\t\tconst active = (this.started && !this.ended && this.players.every(p => p.active));\n\t\tRooms.global.battleCount += (active ? 1 : 0) - (this.active ? 1 : 0);\n\t\tthis.room.active = active;\n\t\tthis.active = active;\n\t\tif (Rooms.global.battleCount === 0) Rooms.global.automaticKillRequest();\n\t}\n\toverride choose(user: User, data: string) {\n\t\tif (this.frozen) {\n\t\t\tuser.popup(`Your battle is currently paused, so you cannot move right now.`);\n\t\t\treturn;\n\t\t}\n\t\tconst player = this.playerTable[user.id];\n\t\tconst [choice, rqid] = data.split('|', 2);\n\t\tif (!player) return;\n\t\tconst request = player.request;\n\t\tif (request.isWait !== false && request.isWait !== true) {\n\t\t\tplayer.sendRoom(`|error|[Invalid choice] There's nothing to choose`);\n\t\t\treturn;\n\t\t}\n\t\tconst allPlayersWait = this.players.every(p => !!p.request.isWait);\n\t\tif (allPlayersWait || // too late\n\t\t\t(rqid && rqid !== `${request.rqid}`)) { // WAY too late\n\t\t\tplayer.sendRoom(`|error|[Invalid choice] Sorry, too late to make a different move; the next turn has already started`);\n\t\t\treturn;\n\t\t}\n\t\trequest.isWait = true;\n\t\trequest.choice = choice;\n\n\t\tvoid this.stream.write(`>${player.slot} ${choice}`);\n\t}\n\toverride undo(user: User, data: string) {\n\t\tconst player = this.playerTable[user.id];\n\t\tconst [, rqid] = data.split('|', 2);\n\t\tif (!player) return;\n\t\tconst request = player.request;\n\t\tif (request.isWait !== true) {\n\t\t\tplayer.sendRoom(`|error|[Invalid choice] There's nothing to cancel`);\n\t\t\treturn;\n\t\t}\n\t\tconst allPlayersWait = this.players.every(p => !!p.request.isWait);\n\t\tif (allPlayersWait || // too late\n\t\t\t(rqid && rqid !== `${request.rqid}`)) { // WAY too late\n\t\t\tplayer.sendRoom(`|error|[Invalid choice] Sorry, too late to cancel; the next turn has already started`);\n\t\t\treturn;\n\t\t}\n\t\trequest.isWait = false;\n\n\t\tvoid this.stream.write(`>${player.slot} undo`);\n\t}\n\toverride joinGame(user: User, slot?: SideID, playerOpts?: { team?: string }) {\n\t\tif (user.id in this.playerTable) {\n\t\t\tuser.popup(`You have already joined this battle.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tconst validSlots = this.players.filter(player => !player.id).map(player => player.slot);\n\n\t\tif (slot && !validSlots.includes(slot)) {\n\t\t\tuser.popup(`This battle already has a user in slot ${slot}.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!validSlots.length) {\n\t\t\tuser.popup(`This battle already has ${this.playerCap} players.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tslot ??= this.players.find(player => player.invite === user.id)?.slot;\n\t\tif (!slot && validSlots.length > 1) {\n\t\t\tuser.popup(`Which slot would you like to join into? Use something like \\`/joingame ${validSlots[0]}\\``);\n\t\t\treturn false;\n\t\t}\n\t\tslot ??= validSlots[0];\n\n\t\tif (this[slot].invite === user.id) {\n\t\t\tthis.room.auth.set(user.id, Users.PLAYER_SYMBOL);\n\t\t} else if (!user.can('joinbattle', null, this.room)) {\n\t\t\tuser.popup(`You must be set as a player to join a battle you didn't start. Ask a player to use /addplayer on you to join this battle.`);\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.setPlayerUser(this[slot], user, playerOpts);\n\t\tif (validSlots.length - 1 <= 0) {\n\t\t\t// all players have joined, start the battle\n\t\t\t// onCreateBattleRoom crashes if some users are unavailable at start of battle\n\t\t\t// what do we do??? no clue but I guess just exclude them from the array for now\n\t\t\tconst users = this.players.map(player => player.getUser()).filter(Boolean) as User[];\n\t\t\tRooms.global.onCreateBattleRoom(users, this.room, { rated: this.rated });\n\t\t\tthis.started = true;\n\t\t\tthis.room.add(`|uhtmlchange|invites|`);\n\t\t} else if (!this.started && this.invitesFull()) {\n\t\t\tthis.sendInviteForm(true);\n\t\t}\n\t\tif (user.inRooms.has(this.roomid)) this.onConnect(user);\n\t\tthis.room.update();\n\t\treturn true;\n\t}\n\toverride leaveGame(user: User) {\n\t\tif (!user) return false; // ...\n\t\tif (this.room.rated || this.room.tour) {\n\t\t\tuser.popup(`Players can't be swapped out in a ${this.room.tour ? \"tournament\" : \"rated\"} battle.`);\n\t\t\treturn false;\n\t\t}\n\t\tconst player = this.playerTable[user.id];\n\t\tif (!player) {\n\t\t\tuser.popup(`Failed to leave battle - you're not a player.`);\n\t\t\treturn false;\n\t\t}\n\t\tChat.runHandlers('onBattleLeave', user, this.room);\n\n\t\tthis.updatePlayer(player, null);\n\t\tthis.room.update();\n\t\treturn true;\n\t}\n\n\toverride startTimer() {\n\t\tthis.timer.start();\n\t}\n\n\tasync listen() {\n\t\tlet disconnected = false;\n\t\ttry {\n\t\t\tfor await (const next of this.stream) {\n\t\t\t\tif (!this.room) return; // room deleted in the middle of simulation\n\t\t\t\tthis.receive(next.split('\\n'));\n\t\t\t}\n\t\t} catch (err: any) {\n\t\t\t// Disconnected processes are already crashlogged when they happen;\n\t\t\t// also logging every battle room would overwhelm the crashlogger\n\t\t\tif (err.message.includes('Process disconnected')) {\n\t\t\t\tdisconnected = true;\n\t\t\t} else {\n\t\t\t\tMonitor.crashlog(err, 'A sim stream');\n\t\t\t}\n\t\t}\n\t\tif (!this.ended) {\n\t\t\tthis.room.add(`|bigerror|The simulator process crashed. We've been notified and will fix this ASAP.`);\n\t\t\tif (!disconnected) Monitor.crashlog(new Error(`Sim stream interrupted`), `A sim stream`);\n\t\t\tthis.started = true;\n\t\t\tthis.setEnded();\n\t\t\tthis.checkActive();\n\t\t}\n\t}\n\treceive(lines: string[]) {\n\t\tfor (const player of this.players) player.wantsTie = false;\n\n\t\tswitch (lines[0]) {\n\t\tcase 'requesteddata':\n\t\t\tlines = lines.slice(1);\n\t\t\tconst [resolver] = this.dataResolvers!.shift()!;\n\t\t\tresolver(lines);\n\t\t\tbreak;\n\n\t\tcase 'update':\n\t\t\tfor (const line of lines.slice(1)) {\n\t\t\t\tif (line.startsWith('|turn|')) {\n\t\t\t\t\tthis.turn = parseInt(line.slice(6));\n\t\t\t\t}\n\t\t\t\tthis.room.add(line);\n\t\t\t\tif (line.startsWith(`|bigerror|You will auto-tie if `) && Config.allowrequestingties && !this.room.tour) {\n\t\t\t\t\tthis.room.add(`|-hint|If you want to tie earlier, consider using \\`/offertie\\`.`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.room.update();\n\t\t\tif (!this.ended) this.timer.nextRequest();\n\t\t\tthis.checkActive();\n\t\t\tbreak;\n\n\t\tcase 'sideupdate': {\n\t\t\tconst slot = lines[1] as SideID;\n\t\t\tconst player = this[slot];\n\t\t\tif (lines[2].startsWith(`|error|[Invalid choice] Can't do anything`)) {\n\t\t\t\t// ... should not happen\n\t\t\t} else if (lines[2].startsWith(`|error|[Invalid choice]`)) {\n\t\t\t\tconst undoFailed = lines[2].includes(`Can't undo`);\n\t\t\t\tconst request = this[slot].request;\n\t\t\t\trequest.isWait = undoFailed ? 'cantUndo' : false;\n\t\t\t\trequest.choice = '';\n\t\t\t} else if (lines[2].startsWith(`|request|`)) {\n\t\t\t\tthis.rqid++;\n\t\t\t\tconst request = JSON.parse(lines[2].slice(9));\n\t\t\t\trequest.rqid = this.rqid;\n\t\t\t\tconst requestJSON = JSON.stringify(request);\n\t\t\t\tthis[slot].request = {\n\t\t\t\t\trqid: this.rqid,\n\t\t\t\t\trequest: requestJSON,\n\t\t\t\t\tisWait: request.wait ? 'cantUndo' : false,\n\t\t\t\t\tchoice: '',\n\t\t\t\t};\n\t\t\t\tthis.requestCount++;\n\t\t\t\tplayer?.sendRoom(`|request|${requestJSON}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tplayer?.sendRoom(lines[2]);\n\t\t\tbreak;\n\t\t}\n\n\t\tcase 'error': {\n\t\t\tif (process.uptime() * 1000 < LOCKDOWN_PERIOD) {\n\t\t\t\tconst error = new Error();\n\t\t\t\terror.stack = lines.slice(1).join('\\n');\n\t\t\t\t// lock down the server\n\t\t\t\tRooms.global.startLockdown(error);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase 'end':\n\t\t\tthis.logData = JSON.parse(lines[1]);\n\t\t\tthis.score = this.logData!.score;\n\t\t\tthis.inputLog = this.logData!.inputLog;\n\t\t\tthis.started = true;\n\t\t\tvoid this.end(this.logData!.winner);\n\t\t\tbreak;\n\t\t}\n\t}\n\tend(winnerName: unknown) {\n\t\tif (this.ended) return;\n\t\tthis.setEnded();\n\t\tthis.checkActive();\n\t\tthis.timer.end();\n\t\t// Declare variables here in case we need them for non-rated battles logging.\n\t\tlet p1score = 0.5;\n\t\tconst winnerid = toID(winnerName);\n\n\t\t// Check if the battle was rated to update the ladder, return its response, and log the battle.\n\t\tif (winnerid === this.p1.id) {\n\t\t\tp1score = 1;\n\t\t} else if (winnerid === this.p2.id) {\n\t\t\tp1score = 0;\n\t\t}\n\t\tChat.runHandlers('onBattleEnd', this, winnerid, this.players.map(p => p.id));\n\t\tif (this.room.rated && !this.options.isBestOfSubBattle) {\n\t\t\tvoid this.updateLadder(p1score, winnerid);\n\t\t} else if (Config.logchallenges) {\n\t\t\tvoid this.logBattle(p1score);\n\t\t} else if (!this.options.isBestOfSubBattle) {\n\t\t\tthis.logData = null;\n\t\t}\n\t\tthis.room.parent?.game?.onBattleWin?.(this.room, winnerid);\n\t\t// If the room's replay was hidden, don't let users join after the game is over\n\t\tif (this.room.hideReplay) {\n\t\t\tthis.room.settings.modjoin = '%';\n\t\t\tthis.room.setPrivate('hidden');\n\t\t}\n\t\tthis.room.update();\n\n\t\t// so it stops showing up in the users' games list\n\t\tfor (const player of this.players) {\n\t\t\tplayer.getUser()?.games.delete(this.roomid);\n\t\t}\n\n\t\t// If a replay was saved at any point or we were configured to autosavereplays,\n\t\t// reupload when the battle is over to overwrite the partial data (and potentially\n\t\t// reflect any changes that may have been made to the replay's hidden status).\n\t\tif (this.replaySaved || Config.autosavereplays) {\n\t\t\tconst options = Config.autosavereplays === 'private' ? undefined : 'silent';\n\t\t\treturn this.room.uploadReplay(undefined, undefined, options);\n\t\t}\n\t}\n\tasync updateLadder(p1score: number, winnerid: ID) {\n\t\tthis.room.rated = 0;\n\t\tconst winner = Users.get(winnerid);\n\t\tif (winner && !winner.registered) {\n\t\t\tthis.room.sendUser(winner, '|askreg|' + winner.id);\n\t\t}\n\t\tconst [score, p1rating, p2rating] = await Ladders(this.ladder).updateRating(\n\t\t\tthis.p1.name, this.p2.name, p1score, this.room\n\t\t);\n\t\tvoid this.logBattle(score, p1rating, p2rating);\n\t\tChat.runHandlers('onBattleRanked', this, winnerid, [p1rating, p2rating], [this.p1.id, this.p2.id]);\n\t}\n\tasync logBattle(\n\t\tp1score: number, p1rating: AnyObject | null = null, p2rating: AnyObject | null = null,\n\t\tp3rating: AnyObject | null = null, p4rating: AnyObject | null = null\n\t) {\n\t\tif (Dex.formats.get(this.format, true).noLog) return;\n\t\tconst logData = this.logData;\n\t\tif (!logData) return;\n\t\tthis.logData = null; // deallocate to save space\n\t\tlogData.log = this.room.getLog(-1).split('\\n'); // replay log (exact damage)\n\n\t\t// delete some redundant data\n\t\tfor (const rating of [p1rating, p2rating, p3rating, p4rating]) {\n\t\t\tif (rating) {\n\t\t\t\tdelete rating.formatid;\n\t\t\t\tdelete rating.username;\n\t\t\t\tdelete rating.rpsigma;\n\t\t\t\tdelete rating.sigma;\n\t\t\t}\n\t\t}\n\n\t\tlogData.p1rating = p1rating;\n\t\tif (this.replaySaved) logData.replaySaved = this.replaySaved;\n\t\tlogData.p2rating = p2rating;\n\t\tif (this.playerCap > 2) {\n\t\t\tlogData.p3rating = p3rating;\n\t\t\tlogData.p4rating = p4rating;\n\t\t}\n\t\tlogData.endType = this.endType;\n\t\tif (!p1rating) logData.ladderError = true;\n\t\tconst date = new Date();\n\t\tlogData.timestamp = `${date}`;\n\t\tlogData.roomid = this.room.roomid;\n\t\tlogData.format = this.room.format;\n\n\t\tconst logsubfolder = Chat.toTimestamp(date).split(' ')[0];\n\t\tconst logfolder = logsubfolder.split('-', 2).join('-');\n\t\tconst tier = Dex.formats.get(this.room.format).id;\n\t\tconst logpath = `${logfolder}/${tier}/${logsubfolder}/`;\n\n\t\tawait Monitor.logPath(logpath).mkdirp();\n\t\tawait Monitor.logPath(`${logpath}${this.room.getReplayData().id}.log.json`).write(JSON.stringify(logData));\n\t\t// console.log(JSON.stringify(logData));\n\t}\n\toverride onConnect(user: User, connection: Connection | null = null) {\n\t\tif (this.ended && this.room.parent?.game?.constructor.name === 'BestOfGame') {\n\t\t\tconst parentGame = this.room.parent.game as BestOfGame;\n\t\t\tparentGame.playerTable[user.id]?.updateReadyButton();\n\t\t}\n\t\t// this handles joining a battle in which a user is a participant,\n\t\t// where the user has already identified before attempting to join\n\t\t// the battle\n\t\tconst player = this.playerTable[user.id];\n\t\tif (!player) return;\n\t\tplayer.updateChannel(connection || user);\n\t\tconst request = player.request;\n\t\tif (request) {\n\t\t\tlet data = `|request|${request.request}`;\n\t\t\tif (request.choice) data += `\\n|sentchoice|${request.choice}`;\n\t\t\t(connection || user).sendTo(this.roomid, data);\n\t\t}\n\t\tif (!this.started) {\n\t\t\tthis.sendInviteForm(connection || user);\n\t\t}\n\t\tif (!player.active) this.onJoin(user);\n\t}\n\toverride onRename(user: User, oldUserid: ID, isJoining: boolean, isForceRenamed: boolean) {\n\t\tif (user.id === oldUserid) return;\n\t\tif (!this.playerTable) {\n\t\t\t// !! should never happen but somehow still does\n\t\t\tuser.games.delete(this.roomid);\n\t\t\treturn;\n\t\t}\n\t\tif (!(oldUserid in this.playerTable)) {\n\t\t\tif (user.id in this.playerTable) {\n\t\t\t\t// this handles a user renaming themselves into a user in the\n\t\t\t\t// battle (e.g. by using /nick)\n\t\t\t\tthis.onConnect(user);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (!this.allowRenames) {\n\t\t\tconst player = this.playerTable[oldUserid];\n\t\t\tif (player) {\n\t\t\t\tconst message = isForceRenamed ? \" lost by having an inappropriate name.\" : \" forfeited by changing their name.\";\n\t\t\t\tthis.forfeitPlayer(player, message);\n\t\t\t}\n\t\t\tif (!(user.id in this.playerTable)) {\n\t\t\t\tuser.games.delete(this.roomid);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (!user.named) {\n\t\t\tthis.onLeave(user, oldUserid);\n\t\t\treturn;\n\t\t}\n\t\tif (user.id in this.playerTable) return;\n\t\tconst player = this.playerTable[oldUserid];\n\t\tif (player) {\n\t\t\tthis.updatePlayer(player, user);\n\t\t}\n\t\tconst options = {\n\t\t\tname: user.name,\n\t\t\tavatar: user.avatar,\n\t\t};\n\t\tvoid this.stream.write(`>player ${player.slot} ` + JSON.stringify(options));\n\t}\n\toverride onJoin(user: User) {\n\t\tconst player = this.playerTable[user.id];\n\t\tif (player && !player.active) {\n\t\t\tplayer.active = true;\n\t\t\tthis.timer.checkActivity();\n\t\t\tthis.room.add(`|player|${player.slot}|${user.name}|${user.avatar}|`);\n\t\t\tChat.runHandlers('onBattleJoin', player.slot, user, this);\n\t\t}\n\t}\n\toverride onLeave(user: User, oldUserid?: ID) {\n\t\tconst player = this.playerTable[oldUserid || user.id];\n\t\tif (player?.active) {\n\t\t\tplayer.sendRoom(`|request|null`);\n\t\t\tplayer.active = false;\n\t\t\tthis.timer.checkActivity();\n\t\t\tthis.room.add(`|player|${player.slot}|`);\n\t\t}\n\t}\n\n\twin(user: User) {\n\t\tif (!user) {\n\t\t\tthis.tie();\n\t\t\treturn true;\n\t\t}\n\t\tconst player = this.playerTable[user.id];\n\t\tif (!player) return false;\n\t\tvoid this.stream.write(`>forcewin ${player.slot}`);\n\t}\n\ttie() {\n\t\tvoid this.stream.write(`>forcetie`);\n\t}\n\ttiebreak() {\n\t\tvoid this.stream.write(`>tiebreak`);\n\t}\n\toverride forfeit(user: User | string, message = '') {\n\t\tif (typeof user !== 'string') user = user.id;\n\t\telse user = toID(user);\n\n\t\tif (!(user in this.playerTable)) return false;\n\t\treturn this.forfeitPlayer(this.playerTable[user], message);\n\t}\n\n\tforfeitPlayer(player: RoomBattlePlayer, message = '') {\n\t\tif (this.ended || !this.started || player.eliminated) return false;\n\n\t\tplayer.eliminated = true;\n\t\tthis.room.add(`|-message|${player.name}${message || ' forfeited.'}`);\n\t\tthis.endType = 'forfeit';\n\t\tif (this.playerCap > 2) {\n\t\t\tplayer.sendRoom(`|request|null`);\n\t\t\tthis.setPlayerUser(player, null);\n\t\t}\n\t\tvoid this.stream.write(`>forcelose ${player.slot}`);\n\t\treturn true;\n\t}\n\n\t/**\n\t * playerOpts should be empty only if importing an inputlog\n\t * (so the player isn't recreated)\n\t */\n\toverride addPlayer(user: User | string | null, playerOpts?: RoomBattlePlayerOptions | null) {\n\t\tconst player = super.addPlayer(user);\n\t\tif (typeof user === 'string') user = null;\n\t\tif (!player) return null;\n\t\tconst slot = player.slot;\n\t\tthis[slot] = player;\n\n\t\tif (playerOpts) {\n\t\t\tconst options = {\n\t\t\t\tname: player.name,\n\t\t\t\tavatar: user ? `${user.avatar}` : '',\n\t\t\t\tteam: playerOpts.team || undefined,\n\t\t\t\trating: Math.round(playerOpts.rating || 0),\n\t\t\t};\n\t\t\tvoid this.stream.write(`>player ${slot} ${JSON.stringify(options)}`);\n\t\t\tplayer.hasTeam = true;\n\t\t}\n\n\t\tif (user) {\n\t\t\tthis.room.auth.set(player.id, Users.PLAYER_SYMBOL);\n\t\t}\n\t\tif (user?.inRooms.has(this.roomid)) this.onConnect(user);\n\t\treturn player;\n\t}\n\n\tcheckPrivacySettings(options: RoomBattleOptions & Partial) {\n\t\tlet inviteOnly = false;\n\t\tconst privacySetter = new Set([]);\n\t\tfor (const p of options.players) {\n\t\t\tif (p.user) {\n\t\t\t\tif (p.inviteOnly) {\n\t\t\t\t\tinviteOnly = true;\n\t\t\t\t\tprivacySetter.add(p.user.id);\n\t\t\t\t} else if (p.hidden) {\n\t\t\t\t\tprivacySetter.add(p.user.id);\n\t\t\t\t}\n\t\t\t\tthis.checkForcedUserSettings(p.user);\n\t\t\t}\n\t\t}\n\n\t\tif (privacySetter.size) {\n\t\t\tconst room = this.room;\n\t\t\tif (this.forcedSettings.privacy) {\n\t\t\t\troom.setPrivate(false);\n\t\t\t\troom.settings.modjoin = null;\n\t\t\t\troom.add(`|raw|
This battle is required to be public due to a player having a name starting with '${this.forcedSettings.privacy}'.
`);\n\t\t\t} else if (!options.tour || (room.tour?.allowModjoin)) {\n\t\t\t\troom.setPrivate('hidden');\n\t\t\t\tif (inviteOnly) room.settings.modjoin = '%';\n\t\t\t\troom.privacySetter = privacySetter;\n\t\t\t\tif (inviteOnly) {\n\t\t\t\t\troom.settings.modjoin = '%';\n\t\t\t\t\troom.add(`|raw|
This battle is invite-only!
Users must be invited with /invite (or be staff) to join
`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tcheckForcedUserSettings(user: User) {\n\t\tthis.forcedSettings = {\n\t\t\tmodchat: this.forcedSettings.modchat || RoomBattle.battleForcedSetting(user, 'modchat'),\n\t\t\tprivacy: !!this.options.rated && (this.forcedSettings.privacy || RoomBattle.battleForcedSetting(user, 'privacy')),\n\t\t};\n\t\tif (\n\t\t\tthis.players.some(p => p.getUser()?.battleSettings.special) ||\n\t\t\t(this.rated && this.forcedSettings.modchat)\n\t\t) {\n\t\t\tthis.room.settings.modchat = '\\u2606';\n\t\t}\n\t}\n\n\tstatic battleForcedSetting(user: User, key: 'modchat' | 'privacy') {\n\t\tif (Config.forcedpublicprefixes) {\n\t\t\tfor (const prefix of Config.forcedpublicprefixes) {\n\t\t\t\tChat.plugins['username-prefixes']?.prefixManager.addPrefix(prefix, 'privacy');\n\t\t\t}\n\t\t\tdelete Config.forcedpublicprefixes;\n\t\t}\n\t\tif (!Config.forcedprefixes) return null;\n\t\tfor (const { type, prefix } of Config.forcedprefixes) {\n\t\t\tif (user.id.startsWith(toID(prefix)) && type === key) return prefix;\n\t\t}\n\t\treturn null;\n\t}\n\n\tmakePlayer(user: User) {\n\t\tconst num = (this.players.length + 1) as PlayerIndex;\n\t\treturn new RoomBattlePlayer(user, this, num);\n\t}\n\n\toverride setPlayerUser(player: RoomBattlePlayer, user: User | null, playerOpts?: { team?: string }) {\n\t\tif (user === null && this.room.auth.get(player.id) === Users.PLAYER_SYMBOL) {\n\t\t\tthis.room.auth.set(player.id, '+');\n\t\t}\n\t\tsuper.setPlayerUser(player, user);\n\n\t\tplayer.invite = '';\n\t\tconst slot = player.slot;\n\t\tif (user) {\n\t\t\tplayer.active = user.inRooms.has(this.roomid);\n\t\t\tplayer.knownActive = true;\n\t\t\tconst options = {\n\t\t\t\tname: player.name,\n\t\t\t\tavatar: user.avatar,\n\t\t\t\tteam: playerOpts?.team,\n\t\t\t};\n\t\t\tvoid this.stream.write(`>player ${slot} ` + JSON.stringify(options));\n\t\t\tif (playerOpts) player.hasTeam = true;\n\n\t\t\tthis.room.add(`|player|${slot}|${player.name}|${user.avatar}|`);\n\t\t\tChat.runHandlers('onBattleJoin', slot as string, user, this);\n\t\t} else {\n\t\t\tplayer.active = false;\n\t\t\tplayer.knownActive = false;\n\t\t\tconst options = {\n\t\t\t\tname: '',\n\t\t\t};\n\t\t\tvoid this.stream.write(`>player ${slot} ` + JSON.stringify(options));\n\n\t\t\tthis.room.add(`|player|${slot}|`);\n\t\t}\n\t}\n\n\tstart() {\n\t\tif (this.gameType === 'multi') {\n\t\t\tthis.room.title = `Team ${this.p1.name} vs. Team ${this.p2.name}`;\n\t\t} else if (this.gameType === 'freeforall') {\n\t\t\t// p1 vs. p2 vs. p3 vs. p4 is too long of a title\n\t\t\tthis.room.title = `${this.p1.name} and friends`;\n\t\t} else {\n\t\t\tthis.room.title = `${this.p1.name} vs. ${this.p2.name}`;\n\t\t}\n\t\tthis.room.send(`|title|${this.room.title}`);\n\t\tconst suspectTest = Chat.plugins['suspect-tests']?.suspectTests[this.format] ||\n\t\t\tChat.plugins['suspect-tests']?.suspectTests.suspects[this.format];\n\t\tif (suspectTest) {\n\t\t\tconst format = Dex.formats.get(this.format);\n\t\t\tthis.room.add(\n\t\t\t\t`|html|
${format.name} is currently suspecting ${suspectTest.suspect}! ` +\n\t\t\t\t`For information on how to participate check out the suspect thread.
`\n\t\t\t).update();\n\t\t}\n\n\t\t// run onCreateBattleRoom handlers\n\n\t\tif (this.options.inputLog && this.players.every(player => player.hasTeam)) {\n\t\t\t// already started\n\t\t\tthis.started = true;\n\t\t}\n\t\tconst delayStart = this.options.delayedStart || !!this.options.inputLog;\n\t\tconst users = this.players.map(player => {\n\t\t\tconst user = player.getUser();\n\t\t\tif (!user && !delayStart) {\n\t\t\t\tthrow new Error(`User ${player.id} not found on ${this.roomid} battle creation`);\n\t\t\t}\n\t\t\treturn user;\n\t\t});\n\t\tif (!delayStart) {\n\t\t\tRooms.global.onCreateBattleRoom(users as User[], this.room, { rated: this.rated });\n\t\t\tthis.started = true;\n\t\t} else if (delayStart === 'multi') {\n\t\t\tthis.room.add(`|uhtml|invites|
This is a 4-player challenge battle
The players will need to add more players before the battle can start.
`);\n\t\t}\n\t}\n\n\tinvitesFull() {\n\t\treturn this.players.every(player => player.id || player.invite);\n\t}\n\t/** true = send to every player; falsy = send to no one */\n\tsendInviteForm(connection: Connection | User | null | boolean) {\n\t\tif (connection === true) {\n\t\t\tfor (const player of this.players) this.sendInviteForm(player.getUser());\n\t\t\treturn;\n\t\t}\n\t\tif (!connection) return;\n\n\t\tconst playerForms = this.players.map(player => (\n\t\t\tplayer.id ? (\n\t\t\t\t`
`\n\t\t\t) : player.invite ? (\n\t\t\t\t`
`\n\t\t\t) : (\n\t\t\t\t`
`\n\t\t\t)\n\t\t));\n\t\tif (this.gameType === 'multi') {\n\t\t\t[playerForms[1], playerForms[2]] = [playerForms[2], playerForms[1]];\n\t\t\tplayerForms.splice(2, 0, '— vs —');\n\t\t}\n\t\tconnection.sendTo(\n\t\t\tthis.room,\n\t\t\t`|uhtmlchange|invites|
This battle needs more players to start

${playerForms.join(``)}
`\n\t\t);\n\t}\n\n\toverride destroy() {\n\t\tif (!this.ended) {\n\t\t\tthis.setEnded();\n\t\t\tthis.room.parent?.game?.onBattleWin?.(this.room, '');\n\t\t}\n\t\tfor (const player of this.players) {\n\t\t\tplayer.destroy();\n\t\t}\n\t\tthis.playerTable = {};\n\t\tthis.players = [];\n\t\tthis.p1 = null!;\n\t\tthis.p2 = null!;\n\t\tthis.p3 = null!;\n\t\tthis.p4 = null!;\n\n\t\tvoid this.stream.destroy();\n\t\tif (this.active) {\n\t\t\tRooms.global.battleCount += -1;\n\t\t\tthis.active = false;\n\t\t}\n\n\t\t(this as any).room = null;\n\t\tif (this.dataResolvers) {\n\t\t\tfor (const [, reject] of this.dataResolvers) {\n\t\t\t\t// reject the promise, make whatever function called it return undefined\n\t\t\t\treject(new Error('Battle was destroyed.'));\n\t\t\t}\n\t\t}\n\t}\n\tasync getTeam(user: User | string) {\n\t\t// toID extracts user.id\n\t\tconst id = toID(user);\n\t\tconst player = this.playerTable[id];\n\t\tif (!player) return;\n\t\treturn this.getPlayerTeam(player);\n\t}\n\tasync getPlayerTeam(player: RoomBattlePlayer) {\n\t\tvoid this.stream.write(`>requestteam ${player.slot}`);\n\t\tconst teamDataPromise = new Promise((resolve, reject) => {\n\t\t\tif (!this.dataResolvers) this.dataResolvers = [];\n\t\t\tthis.dataResolvers.push([resolve, reject]);\n\t\t});\n\t\tconst resultStrings = await teamDataPromise;\n\t\tif (!resultStrings) return;\n\t\tconst result = Teams.unpack(resultStrings[0]);\n\t\treturn result;\n\t}\n\toverride onChatMessage(message: string, user: User) {\n\t\tconst parts = message.split('\\n');\n\t\tfor (const line of parts) {\n\t\t\tvoid this.stream.write(`>chat-inputlogonly ${user.getIdentity(this.room)}|${line}`);\n\t\t}\n\t}\n\tasync getLog(): Promise {\n\t\tif (!this.logData) this.logData = {};\n\t\tvoid this.stream.write('>requestlog');\n\t\tconst logPromise = new Promise((resolve, reject) => {\n\t\t\tif (!this.dataResolvers) this.dataResolvers = [];\n\t\t\tthis.dataResolvers.push([resolve, reject]);\n\t\t});\n\t\tconst result = await logPromise;\n\t\treturn result;\n\t}\n}\n\nexport class RoomBattleStream extends BattleStream {\n\toverride readonly battle: Battle;\n\tconstructor() {\n\t\tsuper({ keepAlive: true });\n\t\tthis.battle = null!;\n\t}\n\n\toverride _write(chunk: string) {\n\t\tconst startTime = Date.now();\n\t\tif (this.battle && Config.debugsimprocesses && process.send) {\n\t\t\tprocess.send('DEBUG\\n' + this.battle.inputLog.join('\\n') + '\\n' + chunk);\n\t\t}\n\t\ttry {\n\t\t\tthis._writeLines(chunk);\n\t\t} catch (err: any) {\n\t\t\tconst battle = this.battle;\n\t\t\tMonitor.crashlog(err, 'A battle', {\n\t\t\t\tchunk,\n\t\t\t\tinputLog: battle ? '\\n' + battle.inputLog.join('\\n') : '',\n\t\t\t\tlog: battle ? '\\n' + battle.getDebugLog() : '',\n\t\t\t});\n\n\t\t\tthis.push(`update\\n|html|
The battle crashed
Don't worry, we're working on fixing it.
`);\n\t\t\tif (battle) {\n\t\t\t\tfor (const side of battle.sides) {\n\t\t\t\t\tif (side?.requestState) {\n\t\t\t\t\t\tthis.push(`sideupdate\\n${side.id}\\n|error|[Invalid choice] The battle crashed`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// public crashlogs only have the stack anyways\n\t\t\tthis.push(`error\\n${err.stack}`);\n\t\t}\n\t\tif (this.battle) this.battle.sendUpdates();\n\t\tconst deltaTime = Date.now() - startTime;\n\t\tif (deltaTime > 1000) {\n\t\t\tMonitor.slow(`[slow battle] ${deltaTime}ms - ${chunk.replace(/\\n/ig, ' | ')}`);\n\t\t}\n\t}\n}\n\n/*********************************************************\n * Process manager\n *********************************************************/\n\nexport const PM = new ProcessManager.StreamProcessManager(module, () => new RoomBattleStream(), message => {\n\tif (message.startsWith(`SLOW\\n`)) {\n\t\tMonitor.slow(message.slice(5));\n\t}\n});\n\nif (!PM.isParentProcess) {\n\t// This is a child process!\n\trequire('source-map-support').install();\n\tglobal.Config = require('./config-loader').Config;\n\tglobal.Dex = require('../sim/dex').Dex;\n\tglobal.Monitor = {\n\t\tcrashlog(error: Error, source = 'A simulator process', details: AnyObject | null = null) {\n\t\t\tconst repr = JSON.stringify([error.name, error.message, source, details]);\n\t\t\tprocess.send!(`THROW\\n@!!@${repr}\\n${error.stack}`);\n\t\t},\n\t\tslow(text: string) {\n\t\t\tprocess.send!(`CALLBACK\\nSLOW\\n${text}`);\n\t\t},\n\t};\n\tglobal.__version = { head: '' };\n\ttry {\n\t\tconst head = execSync('git rev-parse HEAD', {\n\t\t\tstdio: ['ignore', 'pipe', 'ignore'],\n\t\t});\n\t\tconst merge = execSync('git merge-base origin/master HEAD', {\n\t\t\tstdio: ['ignore', 'pipe', 'ignore'],\n\t\t});\n\t\tglobal.__version.head = `${head}`.trim();\n\t\tconst origin = `${merge}`.trim();\n\t\tif (origin !== global.__version.head) global.__version.origin = origin;\n\t} catch {}\n\n\tif (Config.crashguard) {\n\t\t// graceful crash - allow current battles to finish before restarting\n\t\tprocess.on('uncaughtException', err => {\n\t\t\tMonitor.crashlog(err, 'A simulator process');\n\t\t});\n\t\tprocess.on('unhandledRejection', err => {\n\t\t\tMonitor.crashlog(err as any || {}, 'A simulator process Promise');\n\t\t});\n\t}\n\n\t// eslint-disable-next-line no-eval\n\tRepl.start(`sim-${process.pid}`, cmd => eval(cmd));\n} else {\n\tPM.spawn(global.Config ? Config.simulatorprocesses : 1);\n}\n"], "mappings": "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", "names": ["player"] }