Spaces:
Running
Running
; | |
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 room_game_exports = {}; | |
__export(room_game_exports, { | |
RoomGame: () => RoomGame, | |
RoomGamePlayer: () => RoomGamePlayer, | |
SimpleRoomGame: () => SimpleRoomGame | |
}); | |
module.exports = __toCommonJS(room_game_exports); | |
/** | |
* Room games | |
* Pokemon Showdown - http://pokemonshowdown.com/ | |
* | |
* Room games are an abstract representation of an activity that a room | |
* can be focused on, such as a battle, tournament, or chat game like | |
* Hangman. Rooms are limited to one roomgame at a time. | |
* | |
* Room games can keep track of designated players. If a user is a player, | |
* they will not be allowed to change name until their games are complete. | |
* | |
* The player system is optional: Some games, like Hangman, don't designate | |
* players and just allow any user in the room to play. | |
* | |
* @license MIT | |
*/ | |
class RoomGamePlayer { | |
constructor(user, game, num = 0) { | |
this.num = num; | |
if (!user) | |
user = num ? `Player ${num}` : `Player`; | |
this.game = game; | |
this.name = typeof user === "string" ? user : user.name; | |
if (typeof user === "string") | |
user = null; | |
this.id = user ? user.id : ""; | |
if (user && !this.game.isSubGame) { | |
user.games.add(this.game.roomid); | |
user.updateSearch(); | |
} | |
} | |
destroy() { | |
this.game = null; | |
} | |
toString() { | |
return this.id; | |
} | |
getUser() { | |
return this.id ? Users.getExact(this.id) : null; | |
} | |
send(data) { | |
this.getUser()?.send(data); | |
} | |
sendRoom(data) { | |
this.getUser()?.sendTo(this.game.roomid, data); | |
} | |
} | |
class RoomGame { | |
constructor(room, isSubGame = false) { | |
this.title = "Game"; | |
this.allowRenames = false; | |
/** | |
* userid:player table. | |
* | |
* Does not contain userless players: use this.players for the full list. | |
* | |
* Do not iterate. You usually want to iterate `game.players` instead. | |
* | |
* Do not modify directly. You usually want `game.addPlayer` or | |
* `game.removePlayer` instead. | |
* | |
* Not a source of truth. Should be kept in sync with | |
* `Object.fromEntries(this.players.filter(p => p.id).map(p => [p.id, p]))` | |
*/ | |
this.playerTable = /* @__PURE__ */ Object.create(null); | |
this.players = []; | |
this.playerCount = 0; | |
this.playerCap = 0; | |
/** should only be set by setEnded */ | |
this.ended = false; | |
/** Does `/guess` or `/choose` require the user to be able to talk? */ | |
this.checkChat = false; | |
this.roomid = room.roomid; | |
this.room = room; | |
this.isSubGame = isSubGame; | |
if (this.isSubGame) { | |
this.room.subGame = this; | |
} else { | |
this.room.game = this; | |
} | |
} | |
destroy() { | |
this.setEnded(); | |
if (this.isSubGame) { | |
this.room.subGame = null; | |
} else { | |
this.room.game = null; | |
} | |
this.room = null; | |
for (const player of this.players) { | |
player.destroy(); | |
} | |
this.players = null; | |
this.playerTable = null; | |
} | |
addPlayer(user = null, ...rest) { | |
if (typeof user !== "string" && user) { | |
if (user.id in this.playerTable) | |
return null; | |
} | |
if (this.playerCap > 0 && this.playerCount >= this.playerCap) | |
return null; | |
const player = this.makePlayer(user, ...rest); | |
if (!player) | |
return null; | |
if (typeof user === "string") | |
user = null; | |
this.players.push(player); | |
if (user) { | |
this.playerTable[user.id] = player; | |
this.playerCount++; | |
} | |
return player; | |
} | |
updatePlayer(player, userOrName) { | |
if (!this.allowRenames) | |
return; | |
this.setPlayerUser(player, userOrName); | |
} | |
setPlayerUser(player, userOrName) { | |
if (this.ended) | |
return; | |
if (player.id === toID(userOrName)) | |
return; | |
if (player.id) { | |
delete this.playerTable[player.id]; | |
const user = Users.getExact(player.id); | |
if (user) { | |
user.games.delete(this.roomid); | |
user.updateSearch(); | |
} | |
} | |
if (userOrName) { | |
const { name, id } = typeof userOrName === "string" ? { name: userOrName, id: toID(userOrName) } : userOrName; | |
player.id = id; | |
player.name = name; | |
this.playerTable[player.id] = player; | |
if (this.room.roomid.startsWith("battle-") || this.room.roomid.startsWith("game-")) { | |
this.room.auth.set(id, Users.PLAYER_SYMBOL); | |
} | |
const user = typeof userOrName === "string" ? Users.getExact(id) : userOrName; | |
if (user) { | |
user.games.add(this.roomid); | |
user.updateSearch(); | |
} | |
} else { | |
player.id = ""; | |
} | |
} | |
removePlayer(player) { | |
this.setPlayerUser(player, null); | |
const playerIndex = this.players.indexOf(player); | |
if (playerIndex < 0) | |
return false; | |
this.players.splice(playerIndex, 1); | |
player.destroy(); | |
this.playerCount--; | |
return true; | |
} | |
/** | |
* Like `setPlayerUser`, but bypasses some unnecessary game list updates if | |
* the user renamed directly from the old userid. | |
* | |
* `this.playerTable[oldUserid]` must exist or this will crash. | |
*/ | |
renamePlayer(user, oldUserid) { | |
if (user.id === oldUserid) { | |
this.playerTable[user.id].name = user.name; | |
} else { | |
this.playerTable[user.id] = this.playerTable[oldUserid]; | |
this.playerTable[user.id].id = user.id; | |
this.playerTable[user.id].name = user.name; | |
delete this.playerTable[oldUserid]; | |
} | |
} | |
/** | |
* This is purely for cleanup, suitable for calling from `destroy()`. | |
* You should make a different function, call it `end` or something, | |
* to end a game properly. See BestOfGame for an example of an `end` | |
* function. | |
*/ | |
setEnded() { | |
if (this.ended) | |
return; | |
this.ended = true; | |
if (this.isSubGame) | |
return; | |
for (const player of this.players) { | |
const user = player.getUser(); | |
if (user) { | |
user.games.delete(this.roomid); | |
user.updateSearch(); | |
} | |
} | |
} | |
renameRoom(roomid) { | |
for (const player of this.players) { | |
const user = player.getUser(); | |
user?.games.delete(this.roomid); | |
user?.games.add(roomid); | |
} | |
this.roomid = roomid; | |
} | |
// Events: | |
// Note: | |
// A user can have multiple connections. For instance, if you have | |
// two tabs open and connected to PS, those tabs represent two | |
// connections, but a single PS user. Each tab can be in separate | |
// rooms. | |
/** | |
* Called when a user joins a room. (i.e. when the user's first | |
* connection joins) | |
* | |
* While connection is passed, it should not usually be used: | |
* Any handling of connections should happen in onConnect. | |
*/ | |
onJoin(user, connection) { | |
} | |
/** | |
* Called when a user is banned from the room this game is taking | |
* place in. | |
*/ | |
removeBannedUser(user) { | |
this.forfeit?.(user, " lost by being banned."); | |
} | |
/** | |
* Called when a user in the game is renamed. `isJoining` is true | |
* if the user was previously a guest, but now has a username. | |
* Check `!user.named` for the case where a user previously had a | |
* username but is now a guest. By default, updates a player's | |
* name as long as allowRenames is set to true. | |
*/ | |
onRename(user, oldUserid, isJoining, isForceRenamed) { | |
if (!this.allowRenames || !user.named && !isForceRenamed) { | |
if (!(user.id in this.playerTable) && !this.isSubGame) { | |
user.games.delete(this.roomid); | |
user.updateSearch(); | |
} | |
return; | |
} | |
if (!(oldUserid in this.playerTable)) | |
return; | |
if (!user.named) { | |
return this.onLeave(user, oldUserid); | |
} | |
this.renamePlayer(user, oldUserid); | |
} | |
/** | |
* Called when a user leaves the room. (i.e. when the user's last | |
* connection leaves) | |
*/ | |
onLeave(user, oldUserid) { | |
} | |
/** | |
* Called each time a connection joins a room (after onJoin if | |
* applicable). By default, this is also called when connection | |
* is updated in some way (such as by changing user or renaming). | |
* If you don't want this behavior, override onUpdateConnection | |
* and/or onRename. | |
* | |
* This means that by default, it's called twice: once when | |
* connected to the server (as guest1763 or whatever), and once | |
* when logged in. | |
*/ | |
onConnect(user, connection) { | |
} | |
/** | |
* Called for each connection in a room that changes users by | |
* merging into a different user. By default, runs the onConnect | |
* handler. | |
* | |
* Player updates and an up-to-date report of what's going on in | |
* the game should be sent during `onConnect`. You should rarely | |
* need to handle the other events. | |
*/ | |
onUpdateConnection(user, connection) { | |
this.onConnect(user, connection); | |
} | |
/** | |
* Called for every message a user sends while this game is active. | |
* Return an error message to prevent the message from being sent, | |
* an empty string to prevent it with no error message, or | |
* `undefined` to let it through. | |
*/ | |
onChatMessage(message, user) { | |
} | |
/** | |
* Called for every message a user sends while this game is active. | |
* Unlike onChatMessage, this function runs after the message has been added to the room's log. | |
* Do not try to use this to block messages, use onChatMessage for that. | |
*/ | |
onLogMessage(message, user) { | |
} | |
/** | |
* Called when a game's timer needs to be started. Used mainly for tours. | |
*/ | |
startTimer() { | |
} | |
} | |
class SimpleRoomGame extends RoomGame { | |
makePlayer(user, ...rest) { | |
const num = this.players.length ? this.players[this.players.length - 1].num : 1; | |
return new RoomGamePlayer(user, this, num); | |
} | |
} | |
//# sourceMappingURL=room-game.js.map | |