Bots Home
|
Create an App
iIH4T - Group - Token Poll
Author:
teacherspetsxxx
Description
Source Code
Launch Bot
Current Users
Created by:
Teacherspetsxxx
/****************************************************** ******************************************************* * Title: Token Poll - Hot For Teachers * Author: Jasper_Woodcock * Version: 1.0 (1/1/19) * * Based on: /* Token Poll - 4sci's fork v. 1.41- And There Was Light! This bot is based on Token poll by NotThatFrank but fixed some bugs and add some new features. It also uses the sorting function from LL-Token Poll. ************** * Bugs fixed * ************** - The poll will last the right amount of time. Token Poll always last 1 min more because of the way it was coded. - Fixed a typo that caused messages meant for the broadcaster to appear in the chat. - Added the slash (/) commands, it should prevent the commands from being block by all the version of ultrabot. **************** * New features * **************** - You can now pick your color from a drop down menu. You can also pick a color using hex color if that isn't enough choices. - You can start a timer to end the poll at any time. notice! It will end the poll, you can't add time once the timer is at 0. - You can add time on the timer while it is running. - You can stop the timer at anytime. Leaving the poll open until it is stopped manually. - Timer in seconds, useful for when the timer is about to end. - You can enable to keep the poll alive if people are still voting. If the timer is less than 1 min it will go back to 1 min left. - Broadcaster and mods can add vote by typing !vote X, where X is the token amount for that option. - Votes can also be added in batch. ex. !vote 11 10 will add 10 votes to the option 11. (mostly to fix a poll that was close or crashed) - You can enable that fan club member's vote count double. - Can show in chat by how much the leading option is winning. - You can add or remove option while the bot is running. ( fix typos, add suggestion from the tippers etc) You can send bug report, feature request, comments and insults to the4science@gmail.com or dm me on twitter @le4science. */ // bot options cb.settings_choices = [{ name: "poll_title", type: "str", minLength: 1, maxLength: 255, label: "Poll Title" }, { name: "board_interval", type: "int", minValue: 3, default: 5, label: "Board Display Interval (mins)" }, { name: "poll_mode", type: "choice", label: "Poll ends...", choice1: 'When I end it', choice2: 'After x minutes', choice3: 'After x votes', choice4: 'When one option reaches x votes', defaultValue: 'When I end it' }, { name: "poll_count", type: "int", minValue: 1, default: 15, label: "... Where x is ..." }, { name: "aggresiveTimer", type: "choice", label: "When the timer is about to end, how often do you want it to post in chat", choice1: 'At 1 min left', choice2: 'Every 15 seconds under 1 min', choice3: 'Every 15 and 5,4,3,2,1 seconds left', defaultValue: 'Every 15 and 5,4,3,2,1 seconds left' }, { name: "poll_fg_color", type: "choice", label: "Poll text color", choice1: "White", choice2: "Black", choice3: "Dark Grey", choice4: "Dark Blue", choice5: "Dark Pink", choice6: "Dark Red", choice7: "Dark Green", choice8: "Dark Purple", choice9: "Dark Orange", choice10: "Dark Grey", choice11: "Light Blue", choice12: "Light Pink", choice13: "Light Red", choice14: "Light Green", choice15: "Light Purple", choice16: "Light Orange", choice17: "Light Grey", choice18: "Indigo", choice19: "Custom", defaultValue: "White" }, { name: "cforeground", type: "str", minLength: 1, maxLength: 7, label: "If you picked custom text color. (Hex color codes start with #):", defaultValue: "#FFFFFF", required: false }, { name: "poll_bg_color", type: "choice", label: "Poll background color", choice1: "White", choice2: "Black", choice3: "Dark Grey", choice4: "Dark Blue", choice5: "Dark Pink", choice6: "Dark Red", choice7: "Dark Green", choice8: "Dark Purple", choice9: "Dark Orange", choice10: "Dark Grey", choice11: "Light Blue", choice12: "Light Pink", choice13: "Light Red", choice14: "Light Green", choice15: "Light Purple", choice16: "Light Orange", choice17: "Light Grey", choice18: "Indigo", choice19: "Custom", defaultValue: "Indigo" }, { name: "cbackground", type: "str", minLength: 1, maxLength: 7, label: "If you picked custom background color in the previous setting:", defaultValue: "#0629AC", required: false }, { name: "optFanClub", type: "choice", choice1: "Yes", choice2: "No", defaultValue: "No", label: "Fan club members vote counts double?" }, { name: "opt_keepalive", type: "choice", choice1: "Yes", choice2: "No", defaultValue: "No", label: "When on a timer, keep the poll alive if people are tipping?" }, { name: "opt_modadd", type: "choice", choice1: "Yes", choice2: "No", defaultValue: "Yes", label: "Allow mod to add or remove votes?" }, { name: "optTicketPrice", type: "int", minValue: 0, default: 0, label: "Price of the Crazy Ticket. Set to 0 if you are not selling ticket, otherwise it will remind people when they vote if they have not bought a ticket." }, { name: "opt1_label", type: "str", minLength: 1, maxLength: 255, label: "Option 1" }, { name: "opt1_tokens", type: "int", minValue: 1, default: 10, label: "Option 1 tokens" }, { name: "opt2_label", type: "str", minLength: 1, maxLength: 255, label: "Option 2" }, { name: "opt2_tokens", type: "int", minValue: 1, default: 11, label: "Option 2 tokens" }, { name: "opt3_label", type: "str", minLength: 1, maxLength: 255, label: "Option 3", required: false }, { name: "opt3_tokens", type: "int", minValue: 0, default: 0, label: "Option 3 tokens", required: false }, { name: "opt4_label", type: "str", minLength: 1, maxLength: 255, label: "Option 4", required: false }, { name: "opt4_tokens", type: "int", minValue: 0, default: 0, label: "Option 4 tokens", required: false }, { name: "opt5_label", type: "str", minLength: 1, maxLength: 255, label: "Option 5", required: false }, { name: "opt5_tokens", type: "int", minValue: 0, default: 0, label: "Option 5 tokens", required: false }, { name: "opt6_label", type: "str", minLength: 1, maxLength: 255, label: "Option 6", required: false }, { name: "opt6_tokens", type: "int", minValue: 0, default: 0, label: "Option 6 tokens", required: false }, { name: "opt7_label", type: "str", minLength: 1, maxLength: 255, label: "Option 7", required: false }, { name: "opt7_tokens", type: "int", minValue: 0, default: 0, label: "Option 7 tokens", required: false }, { name: "opt8_label", type: "str", minLength: 1, maxLength: 255, label: "Option 8", required: false }, { name: "opt8_tokens", type: "int", minValue: 0, default: 0, label: "Option 8 tokens", required: false }]; // For colours. var foreground; var background; var warnLight = "#FF0000"; var warnDark = "#FFFFFF"; // To pick what type of poll var pollType; // Option on the board var optVotes = [0, 0, 0, 0, 0, 0, 0, 0]; var optLabels = [cb.settings.opt1_label, cb.settings.opt2_label, cb.settings.opt3_label, cb.settings.opt4_label, cb.settings.opt5_label, cb.settings.opt6_label, cb.settings.opt7_label, cb.settings.opt8_label ]; var optTokens = [cb.settings.opt1_tokens, cb.settings.opt2_tokens, cb.settings .opt3_tokens, cb.settings.opt4_tokens, cb.settings.opt5_tokens, cb.settings.opt6_tokens, cb.settings.opt7_tokens, cb.settings.opt8_tokens ]; // Options about voting var fanDouble = (cb.settings.optFanClub === "Yes"); var modAdd = (cb.settings.opt_modadd === "Yes"); var tokensLength = optTokens.length; //Stuff about time var startTime; var stopTime; var minsRemain = cb.settings.poll_count; var secsRemain = 60; var votesRemain = cb.settings.poll_count; var pollRunning = true; var aliveWarned = false; var timeAddedB = false; var timeAddedT = false; var pollShow = false; var nline = 0; //For integration with ticket show var ticketPrice = cb.settings.optTicketPrice; var ticketBackup = []; function checkColor(c) { switch (c) { case "White": return "#FFFFFF"; case "Indigo": return "#3C6478"; case "Black": return "#000000"; case "Dark Blue": return "#0629AC"; case "Dark Pink": return "#FF6680"; case "Dark Green": return "#009900"; case "Dark Red": return "#cc0000"; case "Dark Purple": return "#3d003d"; case "Dark Grey": return "#737373"; case "Dark Orange": return "#ff9933"; case "Light Blue": return "#33cccc"; case "Light Pink": return "#FFE6EA"; case "Light Green": return "#99FF99"; case "Light Red": return "#ff4d4d"; case "Light Purple": return "#df80ff"; case "Light Orange": return "#ffcc99"; case "Light Grey": return "#e6e6e6"; default: if (/^#[0-9A-F]{6}$/i.test(c)) { return c; } else if (/^[0-9A-F]{6}$/i.test(c)) { return ('#' + c); } else { return ('default'); } } } function init() { switch (cb.settings.poll_mode) { case "When I end it": pollType = "Never"; break; case "After x minutes": pollType = "Timer"; break; case "After x votes": pollType = "Vote"; break; case "When one option reaches x votes": pollType = "Goal"; break; default: cb.sendNotice("Something when wrong with the poll type", "", background, foreground); } // Let's ajust the board color. if (cb.settings.poll_fg_color === "Custom") { foreground = checkColor(cb.settings.cforeground); if (foreground === "default") { cb.sendNotice("Poll - Error while setting the font color. It has to be in a HEX format. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", 'bold'); foreground = '#FFFFFF'; } } else { foreground = checkColor(cb.settings.poll_fg_color); } if (cb.settings.poll_bg_color === "Custom") { background = checkColor(cb.settings.bgcolor); if (background === 'default') { cb.sendNotice("Poll - Error while setting the background color. It has to be in a HEX format. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", 'bold'); background = '#0629AC'; } } else { background = checkColor(cb.settings.poll_bg_color); } sanitizeBoard(); showBoard(); initTimer(); cb.setTimeout(news, cb.settings.board_interval * 60 * 500); } function showBoard(u) { // To prevent the board from showing weird time left when triggered by timer if (timeAddedB && !pollShow) { cb.setTimeout(showBoard, timeCal() % 60000); timeAddedB = false; return; } if (pollShow) { pollShow = false; // flag if the poll was asked by a user. } let response1 = "---------- Token Poll board" + ("" === u ? " (sent to all)" : "") + ": ----------\n"; let response2 = cb.settings.poll_title; if (!pollRunning) { showWinner(u); return; } let ids = []; for (let i = 0; i < optVotes.length; i++) { ids.push({ "votes": optVotes[i], "id": i }); } ids.sort(function(a, b) { return b.votes - a.votes; }); for (let j = 0; j < ids.length; j++) { if (0 != optTokens[ids[j].id]) { response2 += "\n - " + optLabels[ids[j].id] + " [" + optVotes[ ids[j].id] + " vote" + (optVotes[ids[j].id] > 1 ? "s" : "")+"]: " + optTokens[ids[j].id] + " tokens"; } } let response3 = ""; switch (pollType) { case "Timer": response3 = timeLeft() + "\n"; break; case "Vote": response3 = votesRemain + " vote" + (votesRemain > 1 ? "s" : "") + " remaining before poll closes\n"; break; case "Goal": response3 = "First option to " + cb.settings.poll_count + " votes wins!\n"; break; } response3 += "Simply tip the shown token amounts to register your vote. Type /poll at any time to see the poll board."; if (u === undefined) { // we were triggered by a timeout u = ""; cb.setTimeout(showBoard, cb.settings.board_interval * 60 * 1000); } cb.sendNotice(response1 + response2, u, background, foreground, "bold"); cb.sendNotice(response3, u, background, foreground); } function sanitizeBoard() { for (let i = 1; i < tokensLength; i++) { // start at option 2 if (0 !== optTokens[i] && optLabels[i] === "") { // make sure no option labels are left blank msg("bm", "", "Label for option " + (i + 1) + " is blank -- removing from poll board!"); optTokens[i] = 0; continue; } for (let j = 0; j < i; j++) { // check all options before this one if (0 != optTokens[i] && optTokens[i] === optTokens[j]) { // make sure we don't have two options with the same token amounts msg("bm", "", "Token amount for option " + (i + 1) + " is not unique -- removing from poll board!"); optTokens[i] = 0; optLabels[i] = ""; break; } else if (0 !== optTokens[i] && optLabels[i] === optLabels[j]) { // make sure we don't have two options with the same label msg("bm", "", "Label for option " + (i + 1) + " is not unique -- removing from poll board!"); optTokens[i] = 0; optLabels[i] = ""; break; } } } } function showWinner(u) { let options = []; for (let i = 0; i < tokensLength; i++) { options[i] = i; } options.sort(function(a, b) { return optVotes[b] - optVotes[a]; }); let win_count = 1; for (let j = 1; j < tokensLength; j++) { if (optVotes[options[j]] != optVotes[options[0]]) { break; } if (0 != optTokens[options[j]]) { win_count++; } } let response1 = '---------- Token Poll has ended! ----------\n'; let response2 = 'Winner' + (win_count > 1 ? 's (' + win_count + '-way tie)' : '') + ':'; for (let k = 0; k < win_count; k++) { if (optTokens[options[k]] != 0) { response2 += "\n - " + optLabels[options[k]] + ": " + optVotes[options[k]] + " votes"; } } cb.sendNotice(response1 + response2, u, background, foreground, 'bold'); } function showLead() { let options = []; let leadOpt = []; for (let i = 0; i < tokensLength; i++) { options[i] = i; } options.sort(function(a, b) { return optVotes[b] - optVotes[a]; }); if (optVotes[options[0] ] > 0 ){ leadOpt.push(optLabels[options[0]]); for (let j = 1; j < tokensLength; j++) { if (optVotes[options[j]] != optVotes[options[0]]) { break; } if (0 != optTokens[options[j]]) { leadOpt.push(optLabels[options[j]]); } } } let response1; let leadCount = leadOpt.length; if (leadCount === 0){ response1 = "It's still anyone's game. Type /poll at any time to see all the options."; } else if (leadCount === 1) { response1 = optLabels[options[0]] + " is in the lead by " + (optVotes[options[0]] - optVotes[options[1]]) + " vote" + ((optVotes[options[0]] - optVotes[options[1]]) === 1 ? "" : "s") + "."; } else{ response1 = "We have a " + leadCount + "-way tie between " + formatArray(leadOpt,"and") + "."; } return response1; } function formatArray(arr,andor){ let outStr = ""; if (arr.length === 1) { outStr = arr[0]; } else if (arr.length === 2) { //joins all with "and" but no commas //example: "bob and sam" outStr = arr.join(' '+andor+' '); } else if (arr.length > 2) { //joins all with commas, but last one gets ", and" (oxford comma!) //example: "bob, joe, and sam" outStr = arr.slice(0, -1).join(', ') + ', '+andor+' ' + arr.slice(-1); } return outStr; } function topPick() { let options = []; for (let i = 0; i < tokensLength; i++) { options[i] = i; } options.sort(function(a, b) { return optVotes[b] - optVotes[a]; }); let leadCount = 1; for (let j = 1; j < tokensLength; j++) { if (optVotes[options[j]] != optVotes[options[0]]) { break; } if (0 != optTokens[options[j]]) { leadCount++; } } let response1; if (leadCount === 1) { response1 = "Token Poll - " + optLabels[options[0]] + " won this round by " + (optVotes[options[0]] - optVotes[options[1]]) + " vote" + ((optVotes[options[0]] - optVotes[options[1]]) === 1 ? "" : "s") + "."; optTokens[options[0]] = 0; optVotes[options[0]] = 0; } else { response1 = "We have a " + leadCount + "-way tie between " + optLabels[options[0]]; for (let k = 1; k < leadCount - 1; k++) { if (optTokens[options[k]] != 0) { response1 += ", " + optLabels[options[k]]; } } response1 += " and " + optLabels[options[leadCount - 1]] + "\nTry again later."; } cb.sendNotice(response1, "", background, foreground, "bold"); } function checkPollEnd() { var _pollRunning = pollRunning; switch (pollType) { case "Never": return; case "Timer": if (secsRemain < 1) { pollRunning = false; } break; case "Vote": if (votesRemain < 1) { pollRunning = false; } break; case "Goal": for (let i = 0; i < tokensLength; i++) { if (optVotes[i] >= cb.settings.poll_count) { pollRunning = false; } } break; } if (_pollRunning && !pollRunning) { showWinner(""); } } function timeCal() { startTime = new Date(); return stopTime - startTime.getTime(); } function timeLeft() { var timeLeft = timeCal(); // How many hours var milliseconds = timeLeft % 1000; var seconds = ((timeLeft - milliseconds) % 60000); var minutes = ((timeLeft - seconds - milliseconds) % 3600000); var hours = (timeLeft - minutes - seconds - milliseconds); seconds = seconds / 1000; minutes = minutes / 60000; hours = hours / 3600000; if (hours > 0) { return hours + " hour" + (hours > 1 ? "s" : "") + " and " + minutes + " minute" + (minutes > 1 ? "s" : "") + " remaining to vote."; } else if (minutes > 0 && seconds === 0) { return minutes + " minute" + (minutes > 1 ? "s" : "") + " remaining to vote!"; } else if (minutes > 0) { return minutes + " minute" + (minutes > 1 ? "s" : "") + " and " + seconds + " second" + (seconds > 1 ? "s" : "") + " remaining to vote!"; } else { return seconds + " second" + (seconds > 1 ? "s" : "") + " remaining to vote!!!"; } } function initTimer() { if (!pollRunning || pollType !== "Timer") { return; } else { startTime = new Date(); stopTime = new Date(startTime.getTime() + cb.settings.poll_count * 60000); tickTimer(); } } function tickTimer() { if (!pollRunning || pollType !== "Timer") { return; } if (timeAddedT) { var timeLeft = timeCal(); var msecsLeft = (timeLeft % 60000); minsRemain = (timeLeft - msecsLeft) % 3600000 / 60000; timeAddedT = false; cb.setTimeout(tickTimer, msecsLeft); } else { minsRemain--; if (minsRemain > 0) { cb.setTimeout(tickTimer, 60 * 1000); } else { secsRemain = 60; cb.sendNotice("1 minute remaining to vote!!!", "", background, foreground); tockTimer(); } } } function tockTimer() { if (!pollRunning || pollType !== "Timer") { return; } // If it is higher than 1, guess that someone added time. if (minsRemain > 0) { tickTimer(); } else { secsRemain--; checkPollEnd(); if (cb.settings.aggresiveTimer === "Every 15 seconds under 1 min") { switch (secsRemain) { case 45: case 30: case 15: cb.sendNotice(secsRemain + " second" + (secsRemain > 1 ? "s" : "") + " remaining to vote!!!", "", background, foreground); } } else if (cb.settings.aggresiveTimer === "Every 15 and 5,4,3,2,1 seconds left") { switch (secsRemain) { case 45: case 30: case 15: case 5: case 4: case 3: case 2: case 1: cb.sendNotice(secsRemain + " second" + (secsRemain > 1 ? "s" : "") + " remaining to vote!!!", "", background, foreground); } } else { // do nothing right? } if (secsRemain > 0) { cb.setTimeout(tockTimer, 1000); } } } function aliveWarning() { if (!pollRunning || pollType !== "Timer") { return; } msg("b", "", 'You enable to keep the poll alive if users are still voting. \n The poll might be kept alive indefinitely \n You can use "!endpoll" to end the poll if needed.'); msg("m", "", 'The broadcaster enabled to keep the poll alive if users are still voting. \n The poll might be kept alive indefinitely \n You can use "!endpoll" to end the poll if needed.'); if (minsRemain < 2 && pollRunning) { cb.setTimeout(aliveWarning, 60000); } aliveWarned = true; } function news() { if (!pollRunning) { showWinner(''); } else { let newsList = [ "Token Poll is on. Type /poll to see the options." ]; if (fanDouble) { newsList.push("Fan club members currently get two votes for the price of one!"); } newsList.push(showLead()); msg("", "", newsList[nline]); nline += 1; if (nline >= newsList.length) { nline = 0; } } cb.setTimeout(news, 120000); } function msg(t, u, m) { switch (t) { case "d": cb.sendNotice("Token Poll to Dev - " + m, "4science", foreground, background); break; case "b": cb.sendNotice("Token Poll to Broadcaster - " + m, cb.room_slug, warnDark, warnLight, "bold"); break; case "m": cb.sendNotice("Token Poll to mods - " + m, "", background, foreground, "bold", "red"); break; case "bm": cb.sendNotice("Token Poll to Broadcaster - " + m, cb.room_slug, warnDark, warnLight, "bold"); cb.sendNotice("Token Poll to mods - " + m, "", background, foreground, "bold", "red"); break; case "a": cb.sendNotice("Token Poll to Broadcaster - " + m, cb.room_slug, warnDark, warnLight, "bold"); cb.sendNotice("Token Poll to mods - " + m, "", warnDark, warnLight, "bold", "red"); cb.sendNotice("Token Poll - " + m, "", background, foreground); break; case "nm": cb.sendNotice("Token Poll - This command only works for broadcasters and mods", u, warnDark, warnLight, "bold"); break; case "w": cb.sendNotice("Token Poll - " + m, u, warnDark, warnLight, "bold"); break; case "s": cb.sendNotice(m, u, "#e6e6e6", "#737373"); break; case "n": cb.sendNotice("Token Poll - " + m, u, "#FFFFFF", "#0629AC"); break; default: cb.sendNotice("Token Poll - " + m, u, background, foreground); break; } } cb.onMessage(function(m) { if (m.m.charAt(0) === "/" || m.m.charAt(0) === "!" || m.m.charAt(0) === ":") { var u = m.user; var isMod = (cb.room_slug === u || m.is_mod || u === "4science"); var message = m.m.split(" "); //Trying to make the bot resistant to those gif bot if (m.m.charAt(0) === ":") { message = message.shift(); if (message[0].charAt(0) !== "/" || message[0].charAt(0) !== "!") { return m; } } var cmd = message[0].substr(1); var cmdVar1 = parseInt(message[1]); var cmdVar2 = parseInt(message[2]); switch (cmd) { case "poll": // other users don't need to see this message m['X-Spam'] = true; m.background = '#d9d9d9'; pollShow = true; if (isMod) { u = ""; } if (pollRunning) { showBoard(u); } else { showWinner(u); } return m; case "pollend": case "endpoll": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } msg("b", "", u + " has ended the poll"); if (pollRunning) { pollRunning = false; } showWinner(""); return m; case "startpoll": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } if (!pollRunning) { pollRunning = true; } return m; case "pollpicklead": case "ppl": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } msg("b", "", u + " has ended this round."); topPick(); return m; case "vote": var amount; m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } if (!modAdd && u !== cb.room_slug) { msg("", u, "The broadcaster has disabled this function for mods."); break; } if (isMod) { var voteFail = true; if (!pollRunning) { msg("", u, "The poll is not running, no need to vote."); break; } if (cmdVar1 === 0 || cmdVar2 === 0) { msg("", u, "Haha very funny, now make a decision."); break; } if (!cmdVar1) { msg("", u, "Not a valid choice\n !vote needs to have a value (the token amount for that option). ex: /vote 10"); break; } if (!cmdVar2) { amount = 1; } else { amount = cmdVar2; } for (let i = 0; i < tokensLength; i++) { if (cmdVar1 === optTokens[i]) { msg("a", u, u + " has " + (amount > 0 ? "added" : "removed") + " " + (amount < 0 ? -amount : amount) + " vote" + (amount === 1 || amount === -1 ? "" : "s") + " for " + optLabels[i]); optVotes[i] += amount; voteFail = false; if (pollType === "Vote") { votesRemain -= amount; } checkPollEnd(); break; } } if (voteFail) { msg("w", u, "Not a valid choice. \n X needs to match a tip amount on the poll."); break; } } return m; case "polladdopt": case "pao": var label; m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } if (isMod) { if (!pollRunning) { msg("w", u, "The poll is not running, no need to add option."); break; } if (cmdVar1 <= 0 || isNaN(cmdVar1)) { msg("w", u, "X has be be a number over 0. This is the amount the viewers will tip for it."); break; } if (!message[2]) { msg("w", u, "You need to include a label for that option"); break; } for (let i = 2; i < message.length; i++) { if (i === 2) { label = message[i]; } else { label += " " + message[i]; } } msg("bm", u, u + ' added the option "' + label + '" to the poll.'); optLabels.push(label); optTokens.push(cmdVar1); optVotes.push(0); tokensLength++; sanitizeBoard(); } return m; case "polldelopt": case "pdo": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } if (isMod) { if (!pollRunning) { msg("w", u, "The poll is not running, no need to delete option."); break; } if (cmdVar1 <= 0 || isNaN(cmdVar1)) { msg("w", u, "X has be be a number over 0. This is the amount the viewers will tip for it."); break; } for (let i = 1; i < tokensLength - 1; i++) { if (optTokens[i] === cmdVar1) { optTokens[i] = 0; msg("bm", u, u + ' removed the option "' + optLabels[i] + '" from the poll.'); } } } return m; case "pollstarttimer": case "pst": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } if (!pollRunning) { msg("w", u, "The poll is not running, no need to start a timer."); break; } if (pollType === "Timer") { if (minsRemain >= 1) { msg("w", u, "Timer is already running, use /polladdtime to change the remaining time. \nThe poll will end in " + minsRemain + " minute" + (minsRemain > 1 ? "s" : "")); } else if (secsRemain >= 1) { msg("w", u, "Timer is already running, use /polladdtime to change the remaining time. \nThe poll will end in " + secsRemain + " seconds" + (secsRemain > 1 ? "s" : "")); } break; } if (!cmdVar1) { msg("w", u, "Not a valid choice\n You need to specify an amount of time in min. ex:/pollstarttimer 10"); break; } if (pollType !== "Timer") { pollType = "Timer"; startTime = new Date(); stopTime = new Date(startTime.getTime() + cmdVar1 * 60000); minsRemain = cmdVar1; msg("bm", u, u + " " + (cmdVar1 > 0 ? "added " : "removed ") + cmdVar1 + " minute" + (cmdVar1 === 1 || cmdVar1 === -1 ? "" : "s") + " to the timer."); timeAddedB = true; timeAddedT = true; cb.sendNotice("The poll will end in " + minsRemain + " minute" + (minsRemain > 1 ? "s" : ""), "", background, foreground); tickTimer(); break; } return m; case "polltimer": case "polltimeleft": case "ptl": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!pollRunning) { showWinner(u); break; } if (pollType === "Timer") { cb.sendNotice(timeLeft(), u, background, foreground); break; } else { if (isMod) { msg("", u, "Timer is not running. If you want to start a timer use /pollstarttimer X"); } else { msg("", u, "Timer is not running."); } break; } return m; case "polladdtime": case "pat": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); } else if (!pollRunning) { msg("w", u, "The poll is not running, no need to add time."); } else if (!cmdVar1) { msg("w", u, "Not a valid choice\n You need to specify an amount of time in min. ex:/polltimer 10"); } else if (pollType !== "Timer") { msg("w", u, "Timer is not running, use /polltimer to set it up."); } else if (minsRemain + cmdVar1 <= 0) { msg("w", u, "The value is over the amount of time left. You can use !endpoll to stop the poll and pick the winner."); } else { stopTime = new Date(stopTime.getTime() + cmdVar1 * 60000); msg("bm", u, u + " " + (cmdVar1 > 0 ? "added " : "removed ") + (cmdVar1 > 0 ? cmdVar1 : -cmdVar1) + " minute" + (cmdVar1 === 1 || cmdVar1 === -1 ? "" : "s") + " to the timer."); timeAddedB = true; timeAddedT = true; } return m; case "polllead": case "pld": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!pollRunning) { showWinner(u); break; } if (!isMod) { msg("n", u, showLead()); break; } if (isMod) { msg("", "", showLead()); break; } return m; case "pollstoptimer": m['X-Spam'] = true; if (!isMod) { msg("nm", u, ""); break; } if (!pollRunning) { msg("w", u, "The poll is not running, no need to stop the timer."); break; } if (pollType !== "Timer") { msg("w", u, "The timer is not in use. Ignoring command."); break; } else if (pollType === "Timer") { pollType = "Never"; msg("a", u, "The timer was canceled. The poll will go on until stopped manually", "", background, foreground); break; } return m; case "polltxtcolor": case "ptc": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } if (!pollRunning) { msg("w", u, "The poll is not running, no need to change the text color."); break; } foreground = message[1]; return m; case "pollbgcolor": case "pbc": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } if (!pollRunning) { msg("w", u, "The poll is not running, no need to change the background color."); break; } background = message[1]; return m; case "polltprice": case "ptp": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } if (!pollRunning) { msg("w", u, "The poll is not running, no need to change the ticket price."); break; } if (isNaN(cmdVar1) || cmdVar1 < 0) { msg("w", u, "Not a valid choice\n You need to specify an amount for the ticket price."); break; } ticketPrice = cmdVar1; msg("bm", u, u + " has changed the ticket price to " + ticketPrice + " token" + (ticketPrice > 1 ? "" : "s")); return m; case "polladdt": case "pad": case "add": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } for (let i = 1; i < message.length; i++) { if (message[i].endsWith(",")) { message[i] = message[i].slice(0, -1); } if (cbjs.arrayContains(ticketBackup, message[i])) { cb.sendNotice("Token Poll - User " + message[i] + " is already on the list, skipping", u, "#FFFFFF", "#0629AC"); } else { ticketBackup.push(message[i]); cb.sendNotice("Token Poll - User " + message[i] + " has been added to the back up list.", u, "#FFFFFF", "#0629AC", "bold"); } } return m; case "polldelt": case "pdl": case "del": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } for (let i = 1; i < message.length; i++) { if (message[i].endsWith(",")) { message[i] = message[i].slice(0, -1); } if (cbjs.arrayContains(ticketBackup, message[i])) { cbjs.arrayRemove(ticketBackup, message[i]); cb.sendNotice("Token Poll - User " + message[i] + " has been removed from the list", u, "#FFFFFF", "#0629AC"); } else { cb.sendNotice("Token Poll - User " + message[i] + " is not on the back up list, skipping.", u, "#FFFFFF", "#0629AC", "bold"); } } return m; case "pollblist": case "pbl": case "backuplist": m['X-Spam'] = true; m.background = '#d9d9d9'; var tLenght = ticketBackup.length; var response1 = "Token Poll back up list: "; for (let i = 0; i < tLenght; i++) { response1 += ticketBackup[i] + (tLenght > 1 ? (i === tLenght - 1 ? "" : ", ") : ""); } msg("n", u, response1); return m; case "!ptarray": m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } msg("d", u, cb.limitCam_allUsersWithAccess()); return m; case "ctprice": // To match the crazy ticket price m['X-Spam'] = true; m.background = '#d9d9d9'; if (!isMod) { msg("nm", u, ""); break; } ticketPrice = cmdVar1; break; case "pollhelp": m['X-Spam'] = true; m.background = '#d9d9d9'; var helpUser = "Here are the commands available for Token Poll.\n" + "- /poll: Show the poll in chat.\n" + "- /polllead: Show the leader and by how much it leads.\n" + "- /polltimer: If the timer is running, it will show the time left in chat\n"; var helpMod = "****************\n" + "These commands are only available to mods and broadcasters.\n" + "- /endpoll: stop the poll and pick the winner\n" + "- /startpoll: will restart poll and restore the number of votes before it was stopped\n" + "- /pollpicklead: Will pick the current leader as a winner and the poll will continue without that option" + "- /vote X: add one vote for X token option\n" + "- /vote X Y: add Y votes for X token option\n" + "- /polltimer: If the timer is running, it will show the time left in chat\n" + "- /pollstarttimer X: start a timer to end the poll in X min if the timer isn't already running\n" + "- /polladdtime X: Add X min to the timer, negative value will decrease the timer\n" + '- /polladdopt X Y: Add an option on the poll for X amount of token, y is the label, can be multiple word. ex:"="Cut my hair"\n' + "- /polldelopt X: Will remove the option for X tokens from the poll\n" + "These commands can be use if the poll is running at the same time as a ticket show.\n" + "- /polltprice: Set the ticket price, the poll will keep a back up list of people who buy a ticket.\n" + "- /polladdt: add an user to the back up list for crazy ticket, has no effect on the real ticket list.\n" + "- /polldelt: delete a user from the back list for crazy ticket, has no effect on the real ticket list.\n" + "- /pollblist: show the back up list if the ticket price was set up.\n" + "- /addtlist: will add all the users on the back up list to the crazy ticket list without the need to copy paste.\n"; cb.sendNotice("---------------------------------\n" + helpUser + (isMod ? helpMod : "") + "---------------------------------", u, "#FFFFFF", "#0629AC", "bold"); return m; case "addtlist": case "addblist": m['X-Spam'] = true; m.background = '#d9d9d9'; if (isMod ) { m.m = '/add ' + cbjs.arrayJoin(ticketBackup, ', '); } return m; default: if (cmd > 4 && cmd.substring(0, 4) === "poll") { m['X-Spam'] = true; m.background = '#d9d9d9'; msg("n", u, "Looks like you tried to use a poll command but it did not work. \n Take a look a /pollhelp."); } return m; } } else { return m; } }); cb.onEnter(function(user) { // Variables var u = user.user; var isMod = (cb.room_slug === u || user.is_mod); var isFan = (user.in_fanclub || user.is_mod); // Mod is for testing, since you can't use fan club on the testbed. var msgOnEnter = "Hello " + u + ", the Token Poll bot is currently active in this room."; if (isMod) { msgOnEnter += "\nType /pollhelp to see all the commands."; } if (isFan && fanDouble) { msgOnEnter += "\nFan club members get double vote today!"; } cb.sendNotice(msgOnEnter, u, background, foreground); }); cb.onTip(function(tip) { // Variables var tipAmount = parseInt(tip.amount); var isFan = tip.from_user_in_fanclub; var u = tip.from_user; var voteAmount = 1; // If the poll isn't running, don't count votes if (!pollRunning) { return; } if (ticketPrice > 0 && tipAmount >= ticketPrice && !cbjs.arrayContains(ticketBackup, u)) { ticketBackup.push(u); } if (isFan && fanDouble) { voteAmount = 2; msg("", u, "Since you are a member of the fan club, your votes will be doubled."); } for (let i = 0; i < tokensLength; i++) { if (tipAmount === optTokens[i]) { optVotes[i] += voteAmount; if (voteAmount === 1) { cb.sendNotice(u + " voted for " + optLabels[i], "", background, foreground); } else { cb.sendNotice(u + " voted " + voteAmount + " time" + (voteAmount === 1 ? "" : "s") + " for " + optLabels[i], "", background, foreground); } if (pollType === "Vote") { votesRemain -= voteAmount; } if (pollType === "Timer" && cb.settings.opt_keepalive === "Yes" && minsRemain < 1) { minsRemain++; if (aliveWarned) { aliveWarning(); } } if (!cbjs.arrayContains(ticketBackup, u) && ticketPrice > 0) { msg("n", u, "Do not forget to buy a ticket to see the end of the show! \n Simply tip over " + ticketPrice + " token" + (ticketPrice > 1 ? "s" : "") + " to buy one."); } checkPollEnd(); } } }); init();
© Copyright Chaturbate 2011- 2026. All Rights Reserved.