const LOTTERY_FILE = 'config/chat-plugins/lottery.json';
import {FS} from '../../lib/fs';
const lotteriesContents = FS(LOTTERY_FILE).readIfExistsSync();
const lotteries: {
[roomid: string]: {
maxWinners: number,
name: string,
markup: string,
participants: {[ip: string]: string},
winners: string[],
running: boolean,
},
} = lotteriesContents ? Object.assign(Object.create(null), JSON.parse(lotteriesContents)) : Object.create(null);
function createLottery(roomid: RoomID, maxWinners: number, name: string, markup: string) {
if (lotteries[roomid] && !lotteries[roomid].running) {
delete lotteries[roomid];
}
const lottery = lotteries[roomid];
lotteries[roomid] = {
maxWinners, name, markup, participants: (lottery && lottery.participants) || Object.create(null),
winners: (lottery && lottery.winners) || [], running: true,
};
writeLotteries();
}
function writeLotteries() {
for (const roomid of Object.keys(lotteries)) {
if (!Rooms.get(roomid)) {
delete lotteries[roomid];
}
}
FS(LOTTERY_FILE).writeUpdate(() => JSON.stringify(lotteries));
}
function destroyLottery(roomid: RoomID) {
delete lotteries[roomid];
writeLotteries();
}
function endLottery(roomid: RoomID, winners: string[]) {
const lottery = lotteries[roomid];
if (!lottery) return;
lottery.winners = winners;
lottery.running = false;
Object.freeze(lottery);
writeLotteries();
}
function addUserToLottery(roomid: RoomID, user: User) {
const lottery = lotteries[roomid];
if (!lottery) return;
const participants = lottery.participants;
const userSignedup = participants[user.latestIp] || Object.values(participants).map(toID).includes(user.id);
if (!userSignedup) {
participants[user.latestIp] = user.name;
writeLotteries();
return true;
}
return false;
}
function removeUserFromLottery(roomid: RoomID, user: User) {
const lottery = lotteries[roomid];
if (!lottery) return;
const participants = lottery.participants;
for (const [ip, participant] of Object.entries(participants)) {
if (toID(participant) === user.id || ip === user.latestIp) {
delete participants[ip];
writeLotteries();
return true;
}
}
return false;
}
function getWinnersInLottery(roomid: RoomID) {
const lottery = lotteries[roomid];
if (!lottery) return;
const winners = [];
const participants = Object.values(lottery.participants);
for (let i = 0; i < lottery.maxWinners; i++) {
const randomIdx = participants.length * Math.random() << 0;
const winner = participants[randomIdx];
winners.push(winner);
participants.splice(randomIdx, 1);
}
return winners;
}
export const commands: ChatCommands = {
lottery: {
''(target, room) {
const lottery = lotteries[room.roomid];
if (!lottery) {
return this.errorReply("This room doesn't have a lottery running.");
}
return this.parse(`/join view-lottery-${room.roomid}`);
},
edit: 'create',
create(target, room, user, connection, cmd) {
if (!this.can('declare', null, room)) return;
if (room.battle || !room.chatRoomData) {
return this.errorReply('This room does not support the creation of lotteries.');
}
const lottery = lotteries[room.roomid];
const edited = lottery && lottery.running;
if (cmd === 'edit' && !target && lottery) {
this.sendReply('Source:');
const markup = Chat.html`${lottery.markup}`.replace(/\n/g, '
');
return this.sendReplyBox(`/lottery edit ${lottery.maxWinners}, ${lottery.name}, ${markup}`);
}
const [maxWinners, name, markup] = Chat.splitFirst(target, ',', 2).map(val => val.trim());
if (!(maxWinners && name && markup.length)) {
return this.errorReply("You're missing a command parameter - see /help lottery for this command's syntax.");
}
const maxWinnersNum = parseInt(maxWinners);
if (!this.canHTML(markup)) return;
if (isNaN(maxWinnersNum)) {
return this.errorReply(`${maxWinners} is not a valid number.`);
}
if (maxWinnersNum < 1) {
return this.errorReply('The maximum winners should be at least 1.');
}
if (maxWinnersNum > Number.MAX_SAFE_INTEGER) {
return this.errorReply('The maximum winners number is too large, please pick a smaller number.');
}
if (name.length > 50) {
return this.errorReply('Name needs to be under 50 characters.');
}
createLottery(room.roomid, maxWinnersNum, name, markup);
this.sendReply(`The lottery was successfully ${edited ? 'edited' : 'created'}.`);
if (!edited) {
this.add(Chat.html`|raw|
${participants.join(', ')}
`; } else { buf += `${participants.length} participant(s) joined this lottery.`; } this.sendReplyBox(buf); }, help() { return this.parse('/help lottery'); }, }, lotteryhelp: [ `/lottery - opens the current lottery, if it exists.`, `/lottery create max winners, name, html - creates a new lottery with [name] as the header and [html] as body. Max winners is the amount of people that will win the lottery. Requires # & ~`, `/lottery delete - deletes the current lottery without declaring a winner. Requires # & ~`, `/lottery end - ends the current lottery, declaring a random participant as the winner. Requires # & ~`, `/lottery editmarkup html - edits the lottery markup with the provided HTML. Requires # & ~`, `/lottery join - joins the current lottery, if it exists, you need to be not currently punished in any public room, not locked and be autoconfirmed.`, `/lottery leave - leaves the current lottery, if it exists.`, `/lottery participants - shows the current participants in the lottery.`, ], }; export const pages: PageTable = { lottery(query, user) { this.extractRoom(); this.title = 'Lottery'; let buf = 'This lottery has already ended. The winners are:
'; buf += '