Jofthomas's picture
Jofthomas HF staff
Upload 4781 files
5c2ed06 verified
"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 auction_exports = {};
__export(auction_exports, {
Auction: () => Auction,
commands: () => commands,
roomSettings: () => roomSettings
});
module.exports = __toCommonJS(auction_exports);
var import_lib = require("../../lib");
class Team {
constructor(name, auction) {
this.id = toID(name);
this.name = name;
this.players = [];
this.credits = auction.startingCredits;
this.suspended = false;
this.auction = auction;
}
getManagers() {
return [...this.auction.managers.values()].filter((m) => m.team === this).map((m) => Users.getExact(m.id)?.name || m.id);
}
addPlayer(player, price = 0) {
player.team?.removePlayer(player);
this.players.push(player);
this.credits -= price;
player.team = this;
player.price = price;
}
removePlayer(player) {
const pIndex = this.players.indexOf(player);
if (pIndex === -1)
return;
this.players.splice(pIndex, 1);
delete player.team;
player.price = 0;
}
isSuspended() {
return this.suspended || (this.auction.type === "snake" ? this.players.length >= this.auction.minPlayers : this.credits < this.auction.minBid || this.auction.maxPlayers && this.players.length >= this.auction.maxPlayers);
}
maxBid(credits = this.credits) {
return credits + this.auction.minBid * Math.min(0, this.players.length - this.auction.minPlayers + 1);
}
}
function parseCredits(amount) {
let credits = Number(amount.replace(",", "."));
if (Math.abs(credits) < 500)
credits *= 1e3;
if (!credits || credits % 500 !== 0) {
throw new Chat.ErrorMessage(`The amount of credits must be a multiple of 500.`);
}
return credits;
}
class Auction extends Rooms.SimpleRoomGame {
constructor(room, startingCredits = 1e5) {
super(room);
this.gameid = "auction";
this.owners = /* @__PURE__ */ new Set();
this.teams = /* @__PURE__ */ new Map();
this.managers = /* @__PURE__ */ new Map();
this.auctionPlayers = /* @__PURE__ */ new Map();
this.minBid = 3e3;
this.minPlayers = 10;
this.maxPlayers = 0;
this.type = "auction";
this.lastQueue = null;
this.queue = [];
this.nomTimer = null;
this.nomTimeLimit = 0;
this.nomTimeRemaining = 0;
this.bidTimer = null;
this.bidTimeLimit = 10;
this.bidTimeRemaining = 10;
this.nominatingTeam = null;
this.nominatedPlayer = null;
this.highestBidder = null;
this.highestBid = 0;
/** Used for blind mode */
this.bidsPlaced = /* @__PURE__ */ new Map();
this.state = "setup";
this.title = "Auction";
this.startingCredits = startingCredits;
}
sendMessage(message) {
this.room.add(`|c|~|${message}`).update();
}
sendHTMLBox(htmlContent) {
this.room.add(`|html|<div class="infobox">${htmlContent}</div>`).update();
}
checkOwner(user) {
if (!this.owners.has(user.id) && !Users.Auth.hasPermission(user, "declare", null, this.room)) {
throw new Chat.ErrorMessage(`You must be an auction owner to use this command.`);
}
}
addOwners(users) {
for (const name of users) {
const user = Users.getExact(name);
if (!user)
throw new Chat.ErrorMessage(`User "${name}" not found.`);
if (this.owners.has(user.id))
throw new Chat.ErrorMessage(`${user.name} is already an auction owner.`);
this.owners.add(user.id);
}
}
removeOwners(users) {
for (const name of users) {
const id = toID(name);
if (!this.owners.has(id))
throw new Chat.ErrorMessage(`User "${name}" is not an auction owner.`);
this.owners.delete(id);
}
}
generateUsernameList(players, max = players.length, clickable = false) {
let buf = `<span style="font-size: 85%">`;
buf += players.slice(0, max).map((p) => {
if (typeof p === "object") {
return `<username ${clickable ? ' class="username"' : ""}>${import_lib.Utils.escapeHTML(p.name)}</username>`;
}
return `<username${clickable ? ' class="username"' : ""}>${import_lib.Utils.escapeHTML(p)}</username>`;
}).join(", ");
if (players.length > max) {
buf += ` <span title="${players.slice(max).map((p) => import_lib.Utils.escapeHTML(typeof p === "object" ? p.name : p)).join(", ")}">(+${players.length - max})</span>`;
}
buf += `</span>`;
return buf;
}
generatePriceList() {
const players = import_lib.Utils.sortBy(this.getDraftedPlayers(), (p) => -p.price);
let buf = "";
let smogonExport = "";
for (const team of this.teams.values()) {
let table2 = `<table>`;
for (const player of players.filter((p) => p.team === team)) {
table2 += import_lib.Utils.html`<tr><td>${player.name}</td><td>${player.price}</td></tr>`;
}
table2 += `</table>`;
buf += `<details><summary>${import_lib.Utils.escapeHTML(team.name)}</summary>${table2}</details><br/>`;
if (this.ended)
smogonExport += `[SPOILER="${team.name}"]${table2.replace(/<(.*?)>/g, "[$1]")}[/SPOILER]`;
}
let table = `<table>`;
for (const player of players) {
table += import_lib.Utils.html`<tr><td>${player.name}</td><td>${player.price}</td><td>${player.team.name}</td></tr>`;
}
table += `</table>`;
buf += `<details><summary>All</summary>${table}</details><br/>`;
if (this.ended) {
smogonExport += `[SPOILER="All"]${table.replace(/<(.*?)>/g, "[$1]")}[/SPOILER]`;
buf += import_lib.Utils.html`<copytext value="${smogonExport}">Copy Smogon Export</copytext>`;
}
return buf;
}
generateAuctionTable() {
const queue = this.queue.filter((team) => !team.isSuspended());
let buf = `<div class="ladder pad"><table style="width: 100%"><tr>${!this.ended ? `<th colspan=2>Order</th>` : ""}<th>Team</th>${this.type !== "snake" ? `<th>Credits</th>` : ""}<th style="width: 100%">Players</th></tr>`;
for (const team of this.teams.values()) {
buf += `<tr>`;
if (!this.ended) {
let i1 = queue.indexOf(team) + 1;
let i2 = queue.lastIndexOf(team) + 1;
if (i1 > queue.length / 2) {
[i1, i2] = [i2, i1];
}
buf += `<td align="center" style="width: 15px">${i1 || "-"}</td><td align="center" style="width: 15px">${i2 || "-"}</td>`;
}
buf += `<td style="white-space: nowrap"><strong>${import_lib.Utils.escapeHTML(team.name)}</strong><br/>${this.generateUsernameList(team.getManagers(), 2, true)}</td>`;
if (this.type !== "snake") {
buf += `<td style="white-space: nowrap">${team.credits.toLocaleString()}${team.maxBid() >= this.minBid ? `<br/><span style="font-size: 90%">Max bid: ${team.maxBid().toLocaleString()}</span>` : ""}</td>`;
}
buf += `<td title="${team.players.map((p) => import_lib.Utils.escapeHTML(p.name)).join(", ")}"><div style="min-height: 32px${!this.ended ? `; height: 32px; overflow: hidden; resize: vertical` : ""}"><span style="float: right">${team.players.length}</span>${this.generateUsernameList(team.players)}</div></td>`;
buf += `</tr>`;
}
buf += `</table></div>`;
const players = import_lib.Utils.sortBy(this.getUndraftedPlayers(), (p) => p.name);
const tierArrays = /* @__PURE__ */ new Map();
for (const player of players) {
for (const tier of player.tiersPlayed) {
if (!tierArrays.has(tier))
tierArrays.set(tier, []);
tierArrays.get(tier).push(player);
}
}
const sortedTiers = [...tierArrays.keys()].sort();
if (sortedTiers.length) {
buf += `<details><summary>Remaining Players (${players.length})</summary>`;
buf += `<details><summary>All</summary>${this.generateUsernameList(players)}</details>`;
buf += `<details><summary>Tiers</summary><ul style="list-style-type: none">`;
for (const tier of sortedTiers) {
const tierPlayers = tierArrays.get(tier);
buf += `<li><details><summary>${import_lib.Utils.escapeHTML(tier)} (${tierPlayers.length})</summary>${this.generateUsernameList(tierPlayers)}</details></li>`;
}
buf += `</ul></details></details>`;
} else {
buf += `<details><summary>Remaining Players (${players.length})</summary>${this.generateUsernameList(players)}</details>`;
}
buf += `<details><summary>Auction Settings</summary>`;
buf += `- Minimum bid: <b>${this.minBid.toLocaleString()}</b><br/>`;
buf += `- Minimum players per team: <b>${this.minPlayers}</b><br/>`;
if (this.type !== "snake")
buf += `- Maximum players per team: <b>${this.maxPlayers || "N/A"}</b><br/>`;
buf += `- Nom timer: <b>${this.nomTimeLimit ? `${this.nomTimeLimit}s` : "Off"}</b><br/>`;
if (this.type !== "snake")
buf += `- Bid timer: <b>${this.bidTimeLimit}s</b><br/>`;
buf += `- Auction type: <b>${this.type}</b><br/>`;
buf += `</details>`;
return buf;
}
sendBidInfo() {
if (this.type === "blind")
return;
let buf = `<div class="infobox">`;
buf += import_lib.Utils.html`Player: <username>${this.nominatedPlayer.name}</username> `;
buf += `Top bid: <b>${this.highestBid}</b> `;
buf += import_lib.Utils.html`Top bidder: <b>${this.highestBidder.name}</b><br/>`;
buf += import_lib.Utils.html`Tiers Played: <b>${this.nominatedPlayer.tiersPlayed.length ? `${this.nominatedPlayer.tiersPlayed.join(", ")}` : "N/A"}</b><br/>`;
buf += import_lib.Utils.html`Tiers Not Played: <b>${this.nominatedPlayer.tiersNotPlayed.length ? `${this.nominatedPlayer.tiersNotPlayed.join(", ")}` : "N/A"}</b>`;
buf += `</div>`;
this.room.add(`|uhtml|bid-${this.nominatedPlayer.id}|${buf}`).update();
}
sendTimer(change = false, nom = false) {
let buf = `<div class="infobox message-error">`;
buf += `<i class="fa fa-hourglass-start"></i> ${Chat.toDurationString((nom ? this.nomTimeRemaining : this.bidTimeRemaining) * 1e3, { hhmmss: true }).slice(1)}`;
buf += `</div>`;
this.room.add(`|uhtml${change ? "change" : ""}|timer|${buf}`).update();
}
setMinBid(amount) {
if (this.state !== "setup") {
throw new Chat.ErrorMessage(`The minimum bid cannot be changed after the auction has started.`);
}
if (amount > 5e5)
throw new Chat.ErrorMessage(`The minimum bid must not exceed 500,000.`);
this.minBid = amount;
}
setMinPlayers(amount) {
if (this.state !== "setup") {
throw new Chat.ErrorMessage(`The minimum number of players cannot be changed after the auction has started.`);
}
if (!amount || amount > 30) {
throw new Chat.ErrorMessage(`The minimum number of players must be between 1 and 30.`);
}
this.minPlayers = amount;
}
setMaxPlayers(amount) {
if (this.type === "snake")
throw new Chat.ErrorMessage(`You only need to set minplayers for snake drafts.`);
if (this.state !== "setup") {
throw new Chat.ErrorMessage(`The maximum number of players cannot be changed after the auction has started.`);
}
this.maxPlayers = amount;
}
setNomTimeLimit(seconds) {
if (this.state !== "setup") {
throw new Chat.ErrorMessage(`The nomination time limit cannot be changed after the auction has started.`);
}
if (isNaN(seconds) || seconds && (seconds < 7 || seconds > 300)) {
throw new Chat.ErrorMessage(`The nomination time limit must be between 7 and 300 seconds.`);
}
this.nomTimeLimit = this.nomTimeRemaining = seconds;
}
setBidTimeLimit(seconds) {
if (this.state !== "setup") {
throw new Chat.ErrorMessage(`The bid time limit cannot be changed after the auction has started.`);
}
if (!seconds || seconds < 7 || seconds > 120) {
throw new Chat.ErrorMessage(`The bid time limit must be between 7 and 120 seconds.`);
}
this.bidTimeLimit = this.bidTimeRemaining = seconds;
}
setType(auctionType) {
if (this.state !== "setup") {
throw new Chat.ErrorMessage(`The auction type cannot be changed after the auction has started.`);
}
if (!["auction", "blind", "snake"].includes(toID(auctionType))) {
throw new Chat.ErrorMessage(`Invalid auction type "${auctionType}". Valid types are "auction", "blind", and "snake".`);
}
this.type = toID(auctionType);
this.nomTimeLimit = this.nomTimeRemaining = this.type === "snake" ? 60 : 0;
this.bidTimeLimit = this.bidTimeRemaining = this.type === "blind" ? 30 : 10;
}
getUndraftedPlayers() {
return [...this.auctionPlayers.values()].filter((p) => !p.team);
}
getDraftedPlayers() {
return [...this.auctionPlayers.values()].filter((p) => p.team);
}
importPlayers(data) {
if (this.state !== "setup") {
throw new Chat.ErrorMessage(`Player lists cannot be imported after the auction has started.`);
}
const rows = data.replace("\r", "").split("\n");
const tierNames = rows.shift().split(" ").slice(1);
if (tierNames.some((tier) => tier.length > 30)) {
throw new Chat.ErrorMessage(`Tier names must be 30 characters or less.`);
}
const playerList = /* @__PURE__ */ new Map();
for (const row of rows) {
const tiersPlayed = [];
const tiersNotPlayed = [];
const [name, ...tierData] = row.split(" ");
for (let i = 0; i < tierData.length; i++) {
switch (tierData[i].trim().toLowerCase()) {
case "y":
if (!tierNames[i])
throw new Chat.ErrorMessage(`Invalid tier data found in the pastebin.`);
tiersPlayed.push(tierNames[i]);
break;
case "n":
if (!tierNames[i])
throw new Chat.ErrorMessage(`Invalid tier data found in the pastebin.`);
tiersNotPlayed.push(tierNames[i]);
break;
}
}
if (name.length > 25)
throw new Chat.ErrorMessage(`Player names must be 25 characters or less.`);
const player = {
id: toID(name),
name: name.trim(),
price: 0,
tiersPlayed,
tiersNotPlayed
};
playerList.set(player.id, player);
}
this.auctionPlayers = playerList;
}
addAuctionPlayer(name, tiersPlayed, tiersNotPlayed) {
if (this.state === "bid")
throw new Chat.ErrorMessage(`Players cannot be added during a nomination.`);
if (name.length > 25)
throw new Chat.ErrorMessage(`Player names must be 25 characters or less.`);
if (tiersPlayed.some((tier) => tier.length > 30) || tiersNotPlayed.some((tier) => tier.length > 30)) {
throw new Chat.ErrorMessage(`Tier names must be 30 characters or less.`);
}
const player = {
id: toID(name),
name,
price: 0,
tiersPlayed,
tiersNotPlayed
};
this.auctionPlayers.set(player.id, player);
return player;
}
removeAuctionPlayer(name) {
if (this.state === "bid")
throw new Chat.ErrorMessage(`Players cannot be removed during a nomination.`);
const player = this.auctionPlayers.get(toID(name));
if (!player)
throw new Chat.ErrorMessage(`Player "${name}" not found.`);
player.team?.removePlayer(player);
this.auctionPlayers.delete(player.id);
if (this.state !== "setup" && !this.getUndraftedPlayers().length) {
this.end("The auction has ended because there are no players remaining in the draft pool.");
}
return player;
}
assignPlayer(name, teamName) {
if (this.state === "bid")
throw new Chat.ErrorMessage(`Players cannot be assigned during a nomination.`);
const player = this.auctionPlayers.get(toID(name));
if (!player)
throw new Chat.ErrorMessage(`Player "${name}" not found.`);
if (teamName) {
const team = this.teams.get(toID(teamName));
if (!team)
throw new Chat.ErrorMessage(`Team "${teamName}" not found.`);
team.addPlayer(player);
if (!this.getUndraftedPlayers().length) {
return this.end("The auction has ended because there are no players remaining in the draft pool.");
}
} else {
player.team?.removePlayer(player);
}
}
addTeam(name) {
if (this.state !== "setup")
throw new Chat.ErrorMessage(`Teams cannot be added after the auction has started.`);
if (name.length > 40)
throw new Chat.ErrorMessage(`Team names must be 40 characters or less.`);
const team = new Team(name, this);
this.teams.set(team.id, team);
const teams = [...this.teams.values()];
this.queue = teams.concat(teams.slice().reverse());
return team;
}
removeTeam(name) {
if (this.state !== "setup")
throw new Chat.ErrorMessage(`Teams cannot be removed after the auction has started.`);
const team = this.teams.get(toID(name));
if (!team)
throw new Chat.ErrorMessage(`Team "${name}" not found.`);
this.queue = this.queue.filter((t) => t !== team);
this.teams.delete(team.id);
return team;
}
suspendTeam(name) {
if (this.state === "bid")
throw new Chat.ErrorMessage(`Teams cannot be suspended during a nomination.`);
const team = this.teams.get(toID(name));
if (!team)
throw new Chat.ErrorMessage(`Team "${name}" not found.`);
if (team.suspended)
throw new Chat.ErrorMessage(`Team ${name} is already suspended.`);
if (this.nominatingTeam === team)
throw new Chat.ErrorMessage(`The nominating team cannot be suspended.`);
team.suspended = true;
return team;
}
unsuspendTeam(name) {
if (this.state === "bid")
throw new Chat.ErrorMessage(`Teams cannot be unsuspended during a nomination.`);
const team = this.teams.get(toID(name));
if (!team)
throw new Chat.ErrorMessage(`Team "${name}" not found.`);
if (!team.suspended)
throw new Chat.ErrorMessage(`Team ${name} is not suspended.`);
team.suspended = false;
return team;
}
addManagers(teamName, users) {
const team = this.teams.get(toID(teamName));
if (!team)
throw new Chat.ErrorMessage(`Team "${teamName}" not found.`);
const problemUsers = users.filter((user) => !toID(user) || toID(user).length > 18);
if (problemUsers.length) {
throw new Chat.ErrorMessage(`Invalid usernames: ${problemUsers.join(", ")}`);
}
for (const id of users.map(toID)) {
const manager = this.managers.get(id);
if (!manager) {
this.managers.set(id, { id, team });
} else {
manager.team = team;
}
}
return team;
}
removeManagers(users) {
const problemUsers = users.filter((user) => !this.managers.has(toID(user)));
if (problemUsers.length) {
throw new Chat.ErrorMessage(`Invalid managers: ${problemUsers.join(", ")}`);
}
for (const id of users.map(toID)) {
this.managers.delete(id);
}
}
addCreditsToTeam(teamName, amount) {
if (this.type === "snake")
throw new Chat.ErrorMessage(`Snake draft does not support credits.`);
if (this.state === "bid")
throw new Chat.ErrorMessage(`Credits cannot be changed during a nomination.`);
const team = this.teams.get(toID(teamName));
if (!team)
throw new Chat.ErrorMessage(`Team "${teamName}" not found.`);
const newCredits = team.credits + amount;
if (newCredits <= 0 || newCredits > 1e7) {
throw new Chat.ErrorMessage(`A team must have between 0 and 10,000,000 credits.`);
}
if (team.maxBid(newCredits) < this.minBid) {
throw new Chat.ErrorMessage(`A team must have enough credits to draft the minimum amount of players.`);
}
team.credits = newCredits;
return team;
}
start() {
if (this.state !== "setup")
throw new Chat.ErrorMessage(`The auction has already started.`);
if (this.teams.size < 2)
throw new Chat.ErrorMessage(`The auction needs at least 2 teams to start.`);
const problemTeams = [...this.teams.values()].filter((t) => t.maxBid() < this.minBid).map((t) => t.name);
if (problemTeams.length) {
throw new Chat.ErrorMessage(`The following teams do not have enough credits to draft the minimum amount of players: ${problemTeams.join(", ")}`);
}
this.next();
}
reset() {
const teams = [...this.teams.values()];
for (const team of teams) {
team.credits = this.startingCredits;
team.suspended = false;
for (const player of team.players) {
delete player.team;
player.price = 0;
}
team.players = [];
}
this.lastQueue = null;
this.queue = teams.concat(teams.slice().reverse());
this.clearNomTimer();
this.clearBidTimer();
this.state = "setup";
this.sendHTMLBox(this.generateAuctionTable());
}
next() {
this.state = "nom";
if (!this.queue.filter((team) => !team.isSuspended()).length) {
return this.end("The auction has ended because there are no teams remaining that can draft players.");
}
if (!this.getUndraftedPlayers().length) {
return this.end("The auction has ended because there are no players remaining in the draft pool.");
}
do {
this.nominatingTeam = this.queue.shift();
this.queue.push(this.nominatingTeam);
} while (this.nominatingTeam.isSuspended());
this.sendHTMLBox(this.generateAuctionTable());
this.sendMessage(`/html It is now <b>${import_lib.Utils.escapeHTML(this.nominatingTeam.name)}</b>'s turn to nominate a player. Managers: ${this.nominatingTeam.getManagers().map((m) => `<username class="username">${import_lib.Utils.escapeHTML(m)}</username>`).join(" ")}`);
this.startNomTimer();
}
nominate(user, target) {
if (this.state !== "nom")
throw new Chat.ErrorMessage(`You cannot nominate players right now.`);
const manager = this.managers.get(user.id);
if (!manager || manager.team !== this.nominatingTeam)
this.checkOwner(user);
this.lastQueue = this.queue.slice();
this.lastQueue.unshift(this.lastQueue.pop());
const player = this.auctionPlayers.get(toID(target));
if (!player)
throw new Chat.ErrorMessage(`${target} is not a valid player.`);
if (player.team)
throw new Chat.ErrorMessage(`${player.name} has already been drafted.`);
this.clearNomTimer();
this.nominatedPlayer = player;
if (this.type === "snake") {
this.sendMessage(import_lib.Utils.html`/html <b>${this.nominatingTeam.name}</b> drafted <username>${this.nominatedPlayer.name}</username>!`);
this.nominatingTeam.addPlayer(this.nominatedPlayer);
this.next();
} else {
this.state = "bid";
this.highestBid = this.minBid;
this.highestBidder = this.nominatingTeam;
this.sendMessage(import_lib.Utils.html`/html <username class="username">${user.name}</username> from team <b>${this.nominatingTeam.name}</b> has nominated <username>${player.name}</username> for auction!`);
const notifyMsg = import_lib.Utils.html`|notify|${this.room.title} Auction|${player.name} has been nominated!`;
for (const currManager of this.managers.values()) {
if (currManager.team === this.nominatingTeam)
continue;
const curUser = Users.getExact(currManager.id);
curUser?.sendTo(this.room, notifyMsg);
curUser?.sendTo(
this.room,
`|raw|Send a message with the amount you want to bid (e.g. <code>.5</code> or <code>5</code> will place a bid of <b>5000</b>)!`
);
}
this.sendBidInfo();
this.startBidTimer();
}
}
bid(user, bid) {
if (this.state !== "bid")
throw new Chat.ErrorMessage(`There are no players up for auction right now.`);
const team = this.managers.get(user.id)?.team;
if (!team)
throw new Chat.ErrorMessage(`Only managers can bid on players.`);
if (team.isSuspended())
throw new Chat.ErrorMessage(`Your team is suspended and cannot place bids.`);
if (bid > team.maxBid())
throw new Chat.ErrorMessage(`Your team cannot afford to bid that much.`);
if (this.type === "blind") {
if (this.bidsPlaced.has(team))
throw new Chat.ErrorMessage(`Your team has already placed a bid.`);
if (bid <= this.minBid)
throw new Chat.ErrorMessage(`Your bid must be higher than the minimum bid.`);
const msg = `|c:|${Math.floor(Date.now() / 1e3)}|&|/html Your team placed a bid of <b>${bid}</b> on <username>${import_lib.Utils.escapeHTML(this.nominatedPlayer.name)}</username>.`;
for (const manager of this.managers.values()) {
if (manager.team !== team)
continue;
Users.getExact(manager.id)?.sendTo(this.room, msg);
}
if (bid > this.highestBid) {
this.highestBid = bid;
this.highestBidder = team;
}
this.bidsPlaced.set(team, bid);
if (this.bidsPlaced.size === this.teams.size) {
this.finishCurrentNom();
}
} else {
if (bid <= this.highestBid)
throw new Chat.ErrorMessage(`Your bid must be higher than the current bid.`);
this.highestBid = bid;
this.highestBidder = team;
this.sendBidInfo();
this.startBidTimer();
}
}
onChatMessage(message, user) {
if (this.state !== "bid" || this.type !== "blind")
return;
if (message.startsWith("."))
message = message.slice(1);
if (Number(message.replace(",", "."))) {
this.bid(user, parseCredits(message));
return "";
}
}
onLogMessage(message, user) {
if (this.state !== "bid" || this.type === "blind")
return;
if (message.startsWith("."))
message = message.slice(1);
if (Number(message.replace(",", "."))) {
this.room.update();
try {
this.bid(user, parseCredits(message));
} catch (e) {
if (e instanceof Chat.ErrorMessage) {
user.sendTo(this.room, import_lib.Utils.html`|raw|<span class="message-error">${e.message}</span>`);
} else {
user.sendTo(this.room, `|raw|<span class="message-error">An unexpected error occurred while placing your bid.</span>`);
}
}
}
}
skipNom() {
if (this.state !== "nom")
throw new Chat.ErrorMessage(`Nominations cannot be skipped right now.`);
this.nominatedPlayer = null;
this.sendMessage(`**${this.nominatingTeam.name}**'s nomination turn has been skipped!`);
this.clearNomTimer();
this.next();
}
finishCurrentNom() {
if (this.type === "blind") {
let buf = `<div class="ladder pad"><table><tr><th>Team</th><th>Bid</th></tr>`;
if (!this.bidsPlaced.has(this.nominatingTeam)) {
buf += import_lib.Utils.html`<tr><td>${this.nominatingTeam.name}</td><td>${this.minBid}</td></tr>`;
}
for (const [team, bid] of this.bidsPlaced) {
buf += import_lib.Utils.html`<tr><td>${team.name}</td><td>${bid}</td></tr>`;
}
buf += `</table></div>`;
this.sendHTMLBox(buf);
this.bidsPlaced.clear();
}
this.sendMessage(import_lib.Utils.html`/html <b>${this.highestBidder.name}</b> bought <username>${this.nominatedPlayer.name}</username> for <b>${this.highestBid}</b> credits!`);
this.highestBidder.addPlayer(this.nominatedPlayer, this.highestBid);
this.clearBidTimer();
this.next();
}
undoLastNom() {
if (this.state !== "nom")
throw new Chat.ErrorMessage(`Nominations cannot be undone right now.`);
if (!this.lastQueue)
throw new Chat.ErrorMessage(`Only one nomination can be undone at a time.`);
this.queue = this.lastQueue;
this.lastQueue = null;
if (this.nominatedPlayer) {
this.highestBidder.removePlayer(this.nominatedPlayer);
this.highestBidder.credits += this.highestBid;
}
this.next();
}
clearNomTimer() {
clearInterval(this.nomTimer);
this.nomTimeRemaining = this.nomTimeLimit;
this.room.add("|uhtmlchange|timer|");
}
startNomTimer() {
if (!this.nomTimeLimit)
return;
this.clearNomTimer();
this.sendTimer(false, true);
this.nomTimer = setInterval(() => this.pokeNomTimer(), 1e3);
}
clearBidTimer() {
clearInterval(this.bidTimer);
this.bidTimeRemaining = this.bidTimeLimit;
this.room.add("|uhtmlchange|timer|");
}
startBidTimer() {
if (!this.bidTimeLimit)
return;
this.clearBidTimer();
this.sendTimer();
this.bidTimer = setInterval(() => this.pokeBidTimer(), 1e3);
}
pokeNomTimer() {
this.nomTimeRemaining--;
if (!this.nomTimeRemaining) {
this.skipNom();
} else {
this.sendTimer(true, true);
if (this.nomTimeRemaining % 30 === 0 || [20, 10, 5].includes(this.nomTimeRemaining)) {
this.sendMessage(`/html <span class="message-error">${this.nomTimeRemaining} seconds left!</span>`);
}
}
}
pokeBidTimer() {
this.bidTimeRemaining--;
if (!this.bidTimeRemaining) {
this.finishCurrentNom();
} else {
this.sendTimer(true);
if (this.bidTimeRemaining % 30 === 0 || [20, 10, 5].includes(this.bidTimeRemaining)) {
this.sendMessage(`/html <span class="message-error">${this.bidTimeRemaining} seconds left!</span>`);
}
}
}
end(message) {
this.setEnded();
this.sendHTMLBox(this.generateAuctionTable());
this.sendHTMLBox(this.generatePriceList());
if (message)
this.sendMessage(message);
this.destroy();
}
destroy() {
this.clearNomTimer();
this.clearBidTimer();
super.destroy();
}
}
const commands = {
auction: {
create(target, room, user) {
room = this.requireRoom();
this.checkCan("minigame", null, room);
if (room.game)
return this.errorReply(`There is already a game of ${room.game.title} in progress in this room.`);
if (room.settings.auctionDisabled)
return this.errorReply("Auctions are currently disabled in this room.");
let startingCredits;
if (target) {
startingCredits = parseCredits(target);
if (startingCredits < 1e4 || startingCredits > 1e7) {
return this.errorReply(`Starting credits must be between 10,000 and 10,000,000.`);
}
}
const auction = new Auction(room, startingCredits);
auction.addOwners([user.id]);
room.game = auction;
this.addModAction(`An auction was created by ${user.name}.`);
this.modlog(`AUCTION CREATE`);
},
createhelp: [
`/auction create [startingcredits] - Creates an auction. Requires: % @ # ~`
],
start(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
auction.start();
this.addModAction(`The auction was started by ${user.name}.`);
this.modlog(`AUCTION START`);
},
reset(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
auction.reset();
this.addModAction(`The auction was reset by ${user.name}.`);
this.modlog(`AUCTION RESET`);
},
delete: "end",
stop: "end",
end(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
auction.end();
this.addModAction(`The auction was ended by ${user.name}.`);
this.modlog("AUCTION END");
},
info: "display",
display(target, room, user) {
this.runBroadcast();
const auction = this.requireGame(Auction);
this.sendReplyBox(auction.generateAuctionTable());
},
pricelist(target, room, user) {
this.runBroadcast();
const auction = this.requireGame(Auction);
this.sendReplyBox(auction.generatePriceList());
},
minbid(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
if (!target)
return this.parse("/help auction minbid");
const amount = parseCredits(target);
auction.setMinBid(amount);
this.addModAction(`${user.name} set the minimum bid to ${amount}.`);
this.modlog("AUCTION MINBID", null, `${amount}`);
},
minbidhelp: [
`/auction minbid [amount] - Sets the minimum bid. Requires: # ~ auction owner`
],
minplayers(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
if (!target)
return this.parse("/help auction minplayers");
const amount = parseInt(target);
auction.setMinPlayers(amount);
this.addModAction(`${user.name} set the minimum number of players to ${amount}.`);
},
minplayershelp: [
`/auction minplayers [amount] - Sets the minimum number of players. Requires: # ~ auction owner`
],
maxplayers(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
if (!target)
return this.parse("/help auction maxplayers");
const amount = parseInt(target);
auction.setMaxPlayers(amount);
this.addModAction(`${user.name} set the maximum number of players to ${amount}.`);
},
maxplayershelp: [
`/auction maxplayers [amount] - Sets the maximum number of players. Requires: # ~ auction owner`
],
nomtimer(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
if (!target)
return this.parse("/help auction nomtimer");
const seconds = this.meansNo(target) ? 0 : parseInt(target);
auction.setNomTimeLimit(seconds);
this.addModAction(`${user.name} set the nomination timer to ${seconds} seconds.`);
},
nomtimerhelp: [
`/auction nomtimer [seconds/off] - Sets the nomination timer to [seconds] seconds or disables it. Requires: # ~ auction owner`
],
bidtimer(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
if (!target)
return this.parse("/help auction settimer");
const seconds = parseInt(target);
auction.setBidTimeLimit(seconds);
this.addModAction(`${user.name} set the bid timer to ${seconds} seconds.`);
},
bidtimerhelp: [
`/auction timer [seconds] - Sets the bid timer to [seconds] seconds. Requires: # ~ auction owner`
],
settype(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
if (!target)
return this.parse("/help auction settype");
auction.setType(target);
this.addModAction(`${user.name} set the auction type to ${toID(target)}.`);
},
settypehelp: [
`/auction settype [auction|blind|snake] - Sets the auction type. Requires: # ~ auction owner`,
`- auction: Standard auction with credits and bidding.`,
`- blind: Same as auction, but bids are hidden until the end of the nomination.`,
`- snake: Standard snake draft with no credits or bidding.`
],
addowner: "addowners",
addowners(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
const owners = target.split(",").map((x) => x.trim());
if (!owners.length)
return this.parse("/help auction addowners");
auction.addOwners(owners);
this.addModAction(`${user.name} added ${Chat.toListString(owners.map((o) => Users.getExact(o).name))} as auction owner${Chat.plural(owners.length)}.`);
},
addownershelp: [
`/auction addowners [user1], [user2], ... - Adds users as auction owners. Requires: # ~ auction owner`
],
removeowner: "removeowners",
removeowners(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
const owners = target.split(",").map((x) => x.trim());
if (!owners.length)
return this.parse("/help auction removeowners");
auction.removeOwners(owners);
this.addModAction(`${user.name} removed ${Chat.toListString(owners.map((o) => Users.getExact(o)?.name || o))} as auction owner${Chat.plural(owners.length)}.`);
},
removeownershelp: [
`/auction removeowners [user1], [user2], ... - Removes users as auction owners. Requires: # ~ auction owner`
],
async importplayers(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
if (!target)
return this.parse("/help auction importplayers");
if (!/^https?:\/\/pastebin\.com\/[a-zA-Z0-9]+$/.test(target)) {
return this.errorReply("Invalid pastebin URL.");
}
let data = "";
try {
data = await (0, import_lib.Net)(`https://pastebin.com/raw/${target.split("/").pop()}`).get();
} catch {
}
if (!data)
return this.errorReply("Error fetching data from pastebin.");
auction.importPlayers(data);
this.addModAction(`${user.name} imported the player list from ${target}.`);
},
importplayershelp: [
`/auction importplayers [pastebin url] - Imports a list of players from a pastebin. Requires: # ~ auction owner`,
`The pastebin should be a list of tab-separated values with the first row containing tier names and subsequent rows containing the player names and either a 'y' or an 'n' in the column corresponding to the tier they prefer or do not play respectively.`,
`See https://pastebin.com/jPTbJBva for an example.`
],
addplayer(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
const [playedPart, notPlayedPart] = target.split(";");
const tiersPlayed = playedPart.split(",").map((item) => item.trim());
const tiersNotPlayed = notPlayedPart ? notPlayedPart.split(",").map((item) => item.trim()) : [];
const name = tiersPlayed.shift();
if (!name)
return this.parse("/help auction addplayer");
const player = auction.addAuctionPlayer(name, tiersPlayed, tiersNotPlayed);
this.addModAction(`${user.name} added player ${player.name} to the auction.`);
},
addplayerhelp: [
`/auction addplayer [name], [tierPlayed1], [tierPlayed2], ... ; [tierNotPlayed1], [tierNotPlayed2], ... - Adds a player to the auction. Requires: # ~ auction owner`
],
removeplayer(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
if (!target)
return this.parse("/help auction removeplayer");
const player = auction.removeAuctionPlayer(target);
this.addModAction(`${user.name} removed player ${player.name} from the auction.`);
},
removeplayerhelp: [
`/auction removeplayer [name] - Removes a player from the auction. Requires: # ~ auction owner`
],
assignplayer(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
const [player, team] = target.split(",").map((x) => x.trim());
if (!player)
return this.parse("/help auction assignplayer");
if (team) {
auction.assignPlayer(player, team);
this.addModAction(`${user.name} assigned player ${player} to team ${team}.`);
} else {
auction.assignPlayer(player);
this.sendReply(`${user.name} returned player ${player} to the draft pool.`);
}
},
assignplayerhelp: [
`/auction assignplayer [player], [team] - Assigns a player to a team. If team is blank, returns player to draft pool. Requires: # ~ auction owner`
],
addteam(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
const [name, ...managerNames] = target.split(",").map((x) => x.trim());
if (!name)
return this.parse("/help auction addteam");
const team = auction.addTeam(name);
this.addModAction(`${user.name} added team ${team.name} to the auction.`);
auction.addManagers(team.name, managerNames);
},
addteamhelp: [
`/auction addteam [name], [manager1], [manager2], ... - Adds a team to the auction. Requires: # ~ auction owner`
],
removeteam(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
if (!target)
return this.parse("/help auction removeteam");
const team = auction.removeTeam(target);
this.addModAction(`${user.name} removed team ${team.name} from the auction.`);
},
removeteamhelp: [
`/auction removeteam [team] - Removes a team from the auction. Requires: # ~ auction owner`
],
suspendteam(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
if (!target)
return this.parse("/help auction suspendteam");
const team = auction.suspendTeam(target);
this.addModAction(`${user.name} suspended team ${team.name}.`);
},
suspendteamhelp: [
`/auction suspendteam [team] - Suspends a team from the auction. Requires: # ~ auction owner`,
`Suspended teams have their nomination turns skipped and are not allowed to place bids.`
],
unsuspendteam(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
if (!target)
return this.parse("/help auction unsuspendteam");
const team = auction.unsuspendTeam(target);
this.addModAction(`${user.name} unsuspended team ${team.name}.`);
},
unsuspendteamhelp: [
`/auction unsuspendteam [team] - Unsuspends a team from the auction. Requires: # ~ auction owner`
],
addmanager: "addmanagers",
addmanagers(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
const [teamName, ...managerNames] = target.split(",").map((x) => x.trim());
if (!teamName || !managerNames.length)
return this.parse("/help auction addmanagers");
const team = auction.addManagers(teamName, managerNames);
const managers = managerNames.map((m) => Users.getExact(m)?.name || toID(m));
this.addModAction(`${user.name} added ${Chat.toListString(managers)} as manager${Chat.plural(managers.length)} for team ${team.name}.`);
},
addmanagershelp: [
`/auction addmanagers [team], [user1], [user2], ... - Adds users as managers to a team. Requires: # ~ auction owner`
],
removemanager: "removemanagers",
removemanagers(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
if (!target)
return this.parse("/help auction removemanagers");
const managerNames = target.split(",").map((x) => x.trim());
auction.removeManagers(managerNames);
const managers = managerNames.map((m) => Users.getExact(m)?.name || toID(m));
this.addModAction(`${user.name} removed ${Chat.toListString(managers)} as manager${Chat.plural(managers.length)}.`);
},
removemanagershelp: [
`/auction removemanagers [user1], [user2], ... - Removes users as managers. Requires: # ~ auction owner`
],
addcredits(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
const [teamName, amount] = target.split(",").map((x) => x.trim());
if (!teamName || !amount)
return this.parse("/help auction addcredits");
const credits = parseCredits(amount);
const team = auction.addCreditsToTeam(teamName, credits);
this.addModAction(`${user.name} ${credits < 0 ? "removed" : "added"} ${Math.abs(credits)} credits ${credits < 0 ? "from" : "to"} team ${team.name}.`);
},
addcreditshelp: [
`/auction addcredits [team], [amount] - Adds credits to a team. Requires: # ~ auction owner`
],
nom: "nominate",
nominate(target, room, user) {
const auction = this.requireGame(Auction);
if (!target)
return this.parse("/help auction nominate");
auction.nominate(user, target);
},
nominatehelp: [
`/auction nominate OR /nom [player] - Nominates a player for auction.`
],
skip: "skipnom",
skipnom(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
auction.skipNom();
this.addModAction(`${user.name} skipped the previous nomination.`);
},
undo(target, room, user) {
const auction = this.requireGame(Auction);
auction.checkOwner(user);
auction.undoLastNom();
this.addModAction(`${user.name} undid the last nomination.`);
},
disable(target, room) {
room = this.requireRoom();
this.checkCan("gamemanagement", null, room);
if (room.settings.auctionDisabled) {
return this.errorReply("Auctions are already disabled.");
}
room.settings.auctionDisabled = true;
room.saveSettings();
this.sendReply("Auctions have been disabled for this room.");
},
enable(target, room) {
room = this.requireRoom();
this.checkCan("gamemanagement", null, room);
if (!room.settings.auctionDisabled) {
return this.errorReply("Auctions are already enabled.");
}
delete room.settings.auctionDisabled;
room.saveSettings();
this.sendReply("Auctions have been enabled for this room.");
},
ongoing: "running",
running() {
if (!this.runBroadcast())
return;
const runningAuctions = [...Rooms.rooms.values()].filter((r) => r.getGame(Auction)).map((r) => r.title);
this.sendReply(`Running auctions: ${runningAuctions.join(", ") || "None"}`);
},
"": "help",
help() {
this.parse("/help auction");
}
},
auctionhelp() {
if (!this.runBroadcast())
return;
this.sendReplyBox(
`Auction commands<br/>- create [startingcredits]: Creates an auction.<br/>- start: Starts the auction.<br/>- reset: Resets the auction.<br/>- end: Ends the auction.<br/>- running: Shows a list of rooms with running auctions.<br/>- display: Displays the current state of the auction.<br/>- pricelist: Displays the current prices of players by team.<br/>- nom [player]: Nominates a player for auction.<br/>You may use /nom directly without the /auction prefix.<br/>During the bidding phase, all numbers that are sent in the chat will be treated as bids.<br/><br/><details class="readmore"><summary>Configuration Commands</summary>- minbid [amount]: Sets the minimum bid.<br/>- minplayers [amount]: Sets the minimum number of players.<br/>- nomtimer [seconds]: Sets the nomination timer to [seconds] seconds.<br/>- bidtimer [seconds]: Sets the bid timer to [seconds] seconds.<br/>- settype [auction|blind|snake]: Sets the auction type.<br/>- addowners [user1], [user2], ...: Adds users as auction owners.<br/>- removeowners [user1], [user2], ...: Removes users as auction owners.<br/>- importplayers [pastebin url]: Imports a list of players from a pastebin.<br/>- addplayer [name], [tier1], [tier2], ...: Adds a player to the auction.<br/>- removeplayer [name]: Removes a player from the auction.<br/>- assignplayer [player], [team]: Assigns a player to a team. If team is blank, returns player to draft pool.<br/>- addteam [name], [manager1], [manager2], ...: Adds a team to the auction.<br/>- removeteam [name]: Removes the given team from the auction.<br/>- suspendteam [name]: Suspends the given team from the auction.<br/>- unsuspendteam [name]: Unsuspends the given team from the auction.<br/>- addmanagers [team], [user1], [user2], ...: Adds users as managers to a team.<br/>- removemanagers [user1], [user2], ...: Removes users as managers..<br/>- addcredits [team], [amount]: Adds credits to a team.<br/>- skipnom: Skips the current nomination.<br/>- undo: Undoes the last nomination.<br/>- [enable/disable]: Enables or disables auctions from being started in a room.<br/></details>`
);
},
nom(target) {
this.parse(`/auction nominate ${target}`);
},
bid() {
this.errorReply(`/bid is no longer supported. Send the amount by itself in the chat to place your bid.`);
},
overpay() {
this.requireGame(Auction);
this.checkChat();
return "/announce OVERPAY!";
}
};
const roomSettings = (room) => ({
label: "Auction",
permission: "editroom",
options: [
[`disabled`, room.settings.auctionDisabled || "auction disable"],
[`enabled`, !room.settings.auctionDisabled || "auction enable"]
]
});
//# sourceMappingURL=auction.js.map