/** * Wi-Fi chat-plugin. Only works in a room with id 'wifi' * Handles giveaways in the formats: question, lottery * Credits: Codelegend, SilverTactic, DanielCranham **/ // checks whether any alt of the user is present in list. function checkAllAlts(user, list) { for (var prevName in user.prevNames) { if (prevName === user.userid) continue; if (prevName in list) return 'previous name ' + prevName; } var ip = user.latestIp; for (var id in list) { var matchUser = Users.get(id); if (matchUser.latestIp === ip && matchUser.userid !== user.userid) return 'alt ' + matchUser.name; } return false; } var giveaways = {}; var wifiRoom = Rooms.get('wifi'); // import giveaways if stored in room if (wifiRoom) { if (wifiRoom.giveaways) { giveaways = wifiRoom.giveaways; } else { wifiRoom.giveaways = giveaways; } } var QuestionGiveAway = (function () { function QuestionGiveAway(host, giver, room, options) { this.host = host; this.giver = giver; this.room = room; this.phase = 'pending'; this.prize = options.prize; this.question = options.question; this.answers = options.answers; this.answered = {}; // userid: number of guesses this.room.addRaw("
It's giveaway time!
" + "Question Giveaway started by " + Tools.escapeHTML(host.name) + "

" + "" + Tools.escapeHTML(giver.name) + " will be giving away a " + Tools.escapeHTML(this.prize) + "!
" + "The question will be displayed in one minute!"); this.room.update(); this.startTimer = setTimeout(this.start.bind(this), 1000 * 60); this.excluded = {}; this.excluded[host.userid] = 1; this.excluded[giver.userid] = 1; } QuestionGiveAway.prototype.type = 'question'; QuestionGiveAway.prototype.guessAnswer = function (user, guess, output) { if (this.phase !== 'started') return output.sendReply("The giveaway has not started yet."); var joinError = checkAllAlts(user, this.answered); if (joinError) return output.sendReply("You have already joined the giveaway under the " + joinError + ". Use that alt/account to continue."); joinError = checkAllAlts(user, this.excluded) || (user.userid in this.excluded); if (joinError) return output.sendReply("You are the host/giver of the giveaway, and cannot guess."); var userid = user.userid; if (!this.answered[userid]) this.answered[userid] = 0; if (this.answered[userid] >= 3) return output.sendReply("You have already guessed three times. You cannot guess anymore in this giveaway."); if (toId(guess) in this.answers) { this.winner = user; return this.onEnd(); } this.answered[userid]++; if (this.answered[userid] >= 3) { output.sendReply("Your guess '" + guess + "' is wrong. You have used up all of your guesses. Better luck next time!"); } else { output.sendReply("Your guess '" + guess + "' is wrong. Try again!"); } }; QuestionGiveAway.prototype.change = function (key, value, user, output) { if (user.userid !== this.host.userid) return this.sendReply("Only the host can edit the giveaway."); if (this.phase !== 'pending') return output.sendReply("You cannot change the question or answer once the giveaway has started."); if (key === 'question') { this.question = value; output.sendReply("The question has been changed to " + value + "."); } else { var ans = this.sanitizeAnswers(value); var len = Object.keys(ans).length; if (!len) return output.sendReply("You must specify at least one answer and it must not contain any special characters."); this.answers = ans; output.sendReply("The answer" + (len > 1 ? "s have" : " has") + " been changed to " + value + "."); } }; QuestionGiveAway.prototype.start = function () { this.phase = 'started'; this.room.addRaw("
Giveaway Question: " + this.question + "
" + "use /ga to guess."); this.room.update(); this.endTimer = setTimeout(this.onEnd.bind(this), 1000 * 60 * 10); }; QuestionGiveAway.prototype.onEnd = function (force) { if (force) { if (this.phase === 'ended') return; clearTimeout(this.startTimer); clearTimeout(this.endTimer); this.room.addRaw("The giveaway was forcibly ended."); } else { this.phase = 'ended'; clearTimeout(this.endTimer); if (!this.winner) { this.room.addRaw("The giveaway has been forcibly ended as no one has answered the question."); } else { var ans = []; for (var i in this.answers) { ans.push(this.answers[i]); } this.room.addRaw("
" + Tools.escapeHTML(this.winner.name) + " guessed the correct answer. Congratulations!
" + "Correct answer(s): " + ans.join(',')); if (this.winner.connected) this.winner.popup('You have won the giveaway. PM **' + Tools.escapeHTML(this.giver.name) + '** to claim your prize!'); } } this.room.update(); delete giveaways[this.room.id]; }; QuestionGiveAway.sanitizeAnswers = function (target) { var ret = {}; target.split("/").forEach(function (ans) { ans = ans.replace(/[^a-z0-9 ]+/ig, "").trim(); if (!toId(ans)) return; ret[toId(ans)] = ans.toLowerCase(); }); return ret; }; return QuestionGiveAway; })(); var LotteryGiveAway = (function () { function LotteryGiveAway(host, giver, room, options) { this.host = host; this.giver = giver; this.room = room; this.phase = 'joining'; this.prize = options.prize; this.maxwinners = options.maxwinners; this.joined = {}; // userid: 1 this.reminder = '
It\'s giveaway time!
' + 'Giveaway started by ' + Tools.escapeHTML(host.name) + '

' + '' + Tools.escapeHTML(giver.name) + ' will be giving away: ' + Tools.escapeHTML(this.prize) + '!
' + 'The lottery drawing will occur in 2 minutes, and with ' + this.maxwinners + ' winner' + (this.maxwinners > 1 ? 's' : '') + '!
' + '
' + 'Note: Please do not join if you don\'t have a 3DS and a copy of Pokémon XY or ORAS'; this.room.addRaw(this.reminder); this.room.update(); this.drawTimer = setTimeout(this.drawLottery.bind(this), 1000 * 60 * 2); this.excluded = {}; this.excluded[host.userid] = 1; this.excluded[giver.userid] = 1; } LotteryGiveAway.prototype.type = 'lottery'; LotteryGiveAway.prototype.addUser = function (user, output) { if (this.phase !== 'joining') return output.sendReply("The join phase of the lottery giveaway has ended."); if (!user.named) return output.sendReply("You need to choose a name before joining a lottery giveaway."); var joinError = checkAllAlts(user, this.joined); if (joinError) return output.sendReply("You have already joined the giveaway under the " + joinError + ". Use that alt/account to continue."); joinError = checkAllAlts(user, this.excluded) || (user.userid in this.excluded); if (joinError) return output.sendReply("You are the host/giver of the giveaway, and cannot join."); this.joined[user.userid] = 1; output.sendReply("You have successfully joined the lottery giveaway."); }; LotteryGiveAway.prototype.removeUser = function (user, output) { if (this.phase !== 'joining') return output.sendReply("The join phase of the lottery giveaway has ended."); if (!(user.userid in this.joined)) return output.sendReply("You have not joined the lottery giveaway."); delete this.joined[user.userid]; output.sendReply("You have left the lottery giveaway."); }; LotteryGiveAway.prototype.drawLottery = function () { this.phase = 'drawing'; clearTimeout(this.drawTimer); var userlist = Object.keys(this.joined); this.totalusers = userlist.length; if (this.totalusers < this.maxwinners) return this.onEnd(true); this.winners = {}; while (this.maxwinners) { var index = Math.floor(Math.random() * this.totalusers); if (!(userlist[index] in this.winners)) { this.winners[userlist[index]] = Users.get(userlist[index]); this.maxwinners--; } } this.onEnd(); }; LotteryGiveAway.prototype.onEnd = function (force) { if (force) { if (this.phase === 'ended') return; clearTimeout(this.drawTimer); this.room.addRaw("The giveaway was forcibly ended as not enough users participated."); this.room.update(); } else { this.phase = 'ended'; var finallist = []; for (var id in this.winners) { finallist.push(this.winners[id].name); } var multiWin = finallist.length > 1; finallist = finallist.join(', '); this.room.addRaw("
Lottery Draw: " + this.totalusers + " users have joined the lottery.
" + "Our lucky winner" + (multiWin ? "s" : "") + ": " + Tools.escapeHTML(finallist) + "! Congratulations!"); this.room.update(); for (var id in this.winners) { var targetUser = this.winners[id]; if (targetUser.connected) targetUser.popup("You have won the lottery giveaway! PM **" + this.giver.name + "** to claim your prize!"); } if (this.giver.connected) this.giver.popup("The following users have won your lottery giveaway:\n" + finallist); } delete giveaways[this.room.id]; }; return LotteryGiveAway; })(); function spawnGiveaway(type, host, giver, room, options) { if (type === 'question') { giveaways[room.id] = new QuestionGiveAway(host, giver, room, options); } else { giveaways[room.id] = new LotteryGiveAway(host, giver, room, options); } } var commands = { // question giveaway. quiz: 'question', qg: 'question', question: function (target, room, user) { if (room.id !== 'wifi' || !this.can('warn', null, room) || !target) return false; if (giveaways[room.id]) return this.sendReply("There is already a giveaway going on!"); target = this.splitTarget(target); var targetUser = this.targetUser; if (!targetUser || !targetUser.connected) return this.sendReply("User '" + this.targetUsername + "' is not online."); target = target.split(',').map(function (val) { return val.trim(); }); if (target.length !== 3) return this.sendReply("Invalid arguments specified - /question giver, prize, question, answer(s)"); var options = { prize: target[0], question: target[1], answers: QuestionGiveAway.sanitizeAnswers(target[2]) }; if (!Object.keys(options.answers).length) return this.sendReply("You must specify at least one answer and it cannot contain any special characters."); spawnGiveaway('question', user, targetUser, room, options); this.privateModCommand("(" + user.name + " started a question giveaway for " + this.targetUsername + ")"); }, changeanswer: 'changequestion', changequestion: function (target, room, user, conn, cmd) { if (room.id !== 'wifi') return false; if (!giveaways[room.id]) return this.sendReply("There is no giveaway going on at the moment."); if (giveaways[room.id].type !== 'question') return this.sendReply("This is not a question giveaway."); target = target.trim(); if (!target) return this.sendReply("You must include a question or an answer."); giveaways[room.id].change(cmd.substr(6), target, user, this); }, showanswer: 'viewanswer', viewanswer: function (target, room, user) { if (room.id !== 'wifi') return false; var giveaway = giveaways[room.id]; if (!giveaway) return this.sendReply("There is no giveaway going on at the moment."); if (giveaway.type !== 'question') return this.sendReply("This is not a question giveaway."); if (user.userid !== giveaway.host.userid && user.userid !== giveaway.giver.userid) return; var answers = []; for (var i in giveaway.answers) { answers.push(giveaway.answers[i]); } var anstext = (answers.length === 1) ? 'answer is ' : 'answers are '; this.sendReply("The giveaway question is " + giveaway.question + ".\n" + "The " + anstext + answers.join('/') + "."); }, guessanswer: 'guess', guess: function (target, room, user) { if (room.id !== 'wifi') return this.sendReply("This command can only be used in the Wi-Fi room."); if (!giveaways[room.id]) return this.sendReply("There is no giveaway going on at the moment."); if (giveaways[room.id].type !== 'question') return this.sendReply("This is not a question giveaway."); giveaways[room.id].guessAnswer(user, target, this); }, // lottery giveaway. lg: 'lottery', lotto: 'lottery', lottery: function (target, room, user) { if (room.id !== 'wifi' || !this.can('warn', null, room) || !target) return false; if (giveaways[room.id]) return this.sendReply("There is already a giveaway going on!"); target = this.splitTarget(target); var targetUser = this.targetUser; if (!targetUser || !targetUser.connected) return this.sendReply("User '" + this.targetUsername + "' is not online."); target = target.split(',').map(function (val) { return val.trim(); }); if (target.length !== 2) return this.sendReply("Invalid arguments specified - /lottery giver, prize, max winners"); var options = { prize: target[0], maxwinners: parseInt(target[1]) }; if (options.maxwinners > 10 || options.maxwinners < 1 || isNaN(options.maxwinners)) return this.sendReply("The lottery giveaway can have a minimum of 1 and a maximum of 10 winners."); spawnGiveaway('lottery', user, targetUser, room, options); this.privateModCommand("(" + user.name + " started a lottery giveaway for " + this.targetUsername + ")"); }, leavelotto: 'join', leavelottery: 'join', leave: 'join', joinlotto: 'join', joinlottery: 'join', join: function (target, room, user, conn, cmd) { if (room.id !== 'wifi') return this.sendReply("This command can only be used in the Wi-Fi room."); var giveaway = giveaways[room.id]; if (!giveaway) return this.sendReply("There is no giveaway going on at the moment."); if (giveaway.type !== 'lottery') return this.sendReply("This is not a lottery giveaway."); switch (cmd) { case 'joinlottery': case 'join': case 'joinlotto': giveaway.addUser(user, this); break; case 'leavelottery': case 'leave': case 'leavelotto': giveaway.removeUser(user, this); break; } }, // general. stop: 'end', end: function (target, room, user) { if (room.id !== 'wifi') return this.sendReply("This command can only be used in the Wi-Fi room."); if (!giveaways[room.id]) return this.sendReply("There is no giveaway going on at the moment."); if (!this.can('warn', null, room) && user.userid !== giveaways[room.id].host.userid) return false; giveaways[room.id].onEnd(true); }, rm: 'remind', remind: function (target, room, user) { if (room.id !== 'wifi') return this.sendReply("This command can only be used in the Wi-Fi room."); var giveaway = giveaways[room.id]; if (!giveaway) return this.sendReply("There is no giveaway going on at the moment."); if (!this.canBroadcast()) return; if (giveaway.type === 'question') { if (giveaway.phase !== 'started') return this.sendReply("The giveaway has not started yet."); this.sendReply("|html|
Question Giveaway started by " + Tools.escapeHTML(giveaway.host.name) + "
" + "" + Tools.escapeHTML(giveaway.giver.name) + " will be giving away a " + Tools.escapeHTML(giveaway.prize) + "!
" + "Question: " + Tools.escapeHTML(giveaway.question) + ""); } else { this.sendReply('|raw|' + giveaway.reminder); } }, '': 'help', help: function (target, room, user) { if (room.id !== 'wifi') return this.sendReply("This command can only be used in the Wi-Fi room."); var reply = ''; switch (target) { case 'staff': if (!this.can('warn', null, room)) return; reply = 'Staff commands:
' + '- question or qg User, Prize, Question, Answer - Start a new question giveaway (Requires: % @ # & ~)
' + '- lottery or lg User, Prize[, Number of Winners] - Starts a lottery giveaway (Requires: % @ # & ~)
' + '- changequestion - Changes the question of a question giveaway (Requires: giveaway host)
' + '- changeanswer - Changes the answer of a question giveaway (Requires: giveaway host)
' + '- viewanswer - Shows the answer in a question giveaway (only to giveaway host/giver)
' + '- end - Forcibly ends the current giveaway (Requires: % @ # & ~)
'; break; case 'game': case 'giveaway': case 'user': if (!this.canBroadcast()) return; reply = 'Giveaway participation commands: (start with /giveaway, except for /ga)
' + '- guess or /ga answer - Guesses the answer for a question giveaway
' + '- viewanswer - Shows the answer in a question giveaway (only to host/giver)
' + '- remind - Shows the details of the current giveaway (can be broadcast)
' + '- join or joinlottery - Joins a lottery giveaway
' + '- leave or leavelottery - Leaves a lottery giveaway
'; break; default: if (!this.canBroadcast()) return; reply = 'Wi-Fi room Giveaway help and info
' + '- help user - shows list of participation commands
' + '- help staff - shows giveaway staff commands (Requires: % @ # & ~)'; } this.sendReplyBox(reply); } }; exports.commands = { 'giveaway': commands, 'ga': commands.guess, 'gh': commands.help };