Bots Home
|
Create an App
MJsRoomUpdateTest
Author:
mjsname
Description
Source Code
Launch Bot
Current Users
Created by:
Mjsname
/** * Manages and applies discounts */ var discount; /** * Manages and applies discounts */ (function (discount) { "use strict"; /** * Fanclub discount percentage * This should be within 0~1 */ discount.fanclub = 0; /** * Moderator discount percentage * This should be within 0~1 */ discount.moderator = 0; /** * Apply the appropriate discount to the specified item, returning the discounted cost * @param item Item to discount * @param user User information for calculating discount */ function apply(item, user) { // CB uses different property names for the same thing on different types; this is confusing // These two values are assigned from whatever is approriate, to make the actual code easier to read var in_fanclub = user.hasOwnProperty("from_user_in_fanclub") ? user.from_user_in_fanclub : user.in_fanclub; var is_mod = user.hasOwnProperty("from_user_is_mod") ? user.from_user_is_mod : user.is_mod; // If user has no applicable discount, don't bother calculating it if (!in_fanclub && !is_mod) return item.cost; // Calculate the user discount based on whatever discount is appropriate and higher if (discount.fanclub >= discount.moderator) { if (in_fanclub) return Math.floor(item.cost * (1 - discount.fanclub)); else if (is_mod) return Math.floor(item.cost * (1 - discount.moderator)); } else if (discount.moderator > discount.fanclub) { if (is_mod) return Math.floor(item.cost * (1 - discount.moderator)); else if (in_fanclub) return Math.floor(item.cost * (1 - discount.fanclub)); } return item.cost; } discount.apply = apply; })(discount || (discount = {})); /** * Provides aliases for emblem emotes */ var emblems; /** * Provides aliases for emblem emotes */ (function (emblems) { "use strict"; emblems.arrow = " :arrow16 "; emblems.ballot = " :ballot16 "; emblems.bb8 = " :miniBB-8 "; emblems.blank = " :blank16 "; emblems.bronzemedal = " :bronzemedal16c "; emblems.coppermedal = " :coppermedal16 "; emblems.crown = " :crown16 "; emblems.gavel = " :gavel16 "; emblems.goldmedal = " :goldmedal16 "; emblems.hitachi = " :hitachi16 "; emblems.notice = " :notice16 "; emblems.silvermedal = " :silvermedal16 "; emblems.song = " :song16 "; emblems.timer = " :timer16 "; emblems.tinmedal = " :tinmedal16 "; emblems.tipmenu = " :tipmenu16 "; emblems.token = " :token12 "; emblems.trusted = " :trusted16 "; emblems.whisper = " :whisper16 "; emblems.whispermod = " :whispermod16 "; })(emblems || (emblems = {})); /** * Manages the high tipper */ var hightip; /** * Manages the high tipper */ (function (hightip) { "use strict"; /** * The actual tipper */ var slot; /** * Compare the tip against the highest tip, replacing it if greater * This is single tip only, so no tipper lookup should ever occur * @param tip Tip to compare */ function compare(tip) { if (slot == null || tip.amount > slot.tipped) { slot = new tipper(tip.from_user, tip.amount); } } hightip.compare = compare; /** * Print the help menu for hightip * @param message Requesting message */ function help(message) { notice.add("/hightip --Get the highest single tipper"); notice.post(message.user); } hightip.help = help; /** * Load the state string * @param state State string */ function load(state) { var tipped = state.split(" ")[0]; var name = state.split(" ")[1]; slot = new tipper(name, Number(tipped)); } hightip.load = load; /** * Get the name of the high tipper */ function name() { return slot == null ? null : slot.name; } hightip.name = name; /** * Get the amount tipped during this show */ function tipped() { return slot == null ? null : slot.tipped; } hightip.tipped = tipped; /** * Try to parse a valid command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/hightip": notice.send(slot.tipped + " " + slot.name, message.user); return true; default: return false; } } hightip.tryParse = tryParse; })(hightip || (hightip = {})); /** * Handles the leaderboard */ var leaderboard; /** * Handles the leaderboard */ (function (leaderboard) { "use strict"; /** * Number, in minutes, between rotations */ leaderboard.lapse = 10; /** * Default size of the leaderboard */ leaderboard.size = 5; /** * Prints the help for the leaderboard * @param message Requesting message */ function help(message) { notice.add("/leaderboard --Print the leaderboard"); notice.post(message.user); message['X-Spam'] = true; } leaderboard.help = help; /** * Is the tipper in the leaderboard position? * This function technically will work beyond the leaderboard, but why would you bother? * @param pos Leaderboard position * @param tipper Tipper to check */ function isPos(pos, tipper) { return tippers.top(pos)[pos - 1] === tipper; } leaderboard.isPos = isPos; /** * Print the leaderboard to chat * @param slots Amount of slots to print * @param sendTo User to send to */ function print(slots, sendTo) { if (slots === void 0) { slots = leaderboard.size; } if (sendTo === void 0) { sendTo = ""; } var top = tippers.top(slots); if (top != null && top.length != 0) notice.add("===== Leaderboard ====="); if (top[0] != null && top[0].tipped != 0) notice.add(emblems.goldmedal + top[0].name + " " + top[0].tipped); if (top[1] != null && top[1].tipped != 0) notice.add(emblems.silvermedal + top[1].name + " " + top[1].tipped); if (top[2] != null && top[2].tipped != 0) notice.add(emblems.bronzemedal + top[2].name + " " + top[2].tipped); if (top[3] != null && top[3].tipped != 0) notice.add(emblems.tinmedal + top[3].name + " " + top[3].tipped); if (top[4] != null && top[4].tipped != 0) notice.add(emblems.coppermedal + top[4].name + " " + top[4].tipped); notice.post(sendTo); } /** * Rotate the leaderboard * @param slots Amount of slots to print */ function rotate(slots) { if (slots === void 0) { slots = leaderboard.size; } print(slots); cb.setTimeout(rotate, leaderboard.lapse * 60 * 1000); } leaderboard.rotate = rotate; /** * Try to parse a leaderboard command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/leaderboard": print(leaderboard.size, message.user); return true; default: return false; } } leaderboard.tryParse = tryParse; })(leaderboard || (leaderboard = {})); /** * Represents a tipmenu item */ var menuitem = (function () { /** * Create a new menu item * @param name Name of the item * @param cost Cost of the item * @param handler Handler function when this item is tipped for * @param params Parameters for the handler function */ function menuitem(name, cost, handler) { var params = []; for (var _i = 3; _i < arguments.length; _i++) { params[_i - 3] = arguments[_i]; } this.name = name; this.cost = cost; this.handler = handler; this.params = params; } /** * Handle the item, if it has a handler * This will not call the handler if one is not assigned */ menuitem.prototype.handle = function (tip) { if (this.handler != null) { this.handler(tip, this.params); } }; return menuitem; }()); /** * Represents a tipmenu section */ var menusection = (function () { function menusection(name) { var items = []; for (var _i = 1; _i < arguments.length; _i++) { items[_i - 1] = arguments[_i]; } /** * The actual items of the section */ this.items = []; this.name = name; this.items = items; } /** * Add the item to the section * @param name Name of the item * @param cost Cost of the item * @param handler Handler for when the item is tipped for */ menusection.prototype.add = function (name, cost, handler) { var params = []; for (var _i = 3; _i < arguments.length; _i++) { params[_i - 3] = arguments[_i]; } this.items[this.items.length] = new menuitem(name, cost, handler, params); }; /** * Clear the menu of all items */ menusection.prototype.clear = function () { this.items = []; }; /** * Delete the item from the section * @param name Name of the item */ menusection.prototype.del = function (name) { this.items = cbjs.arrayRemove(this.items, this.lookup(name)); }; /** * List all items in the section */ menusection.prototype.list = function () { return this.items; }; /** * Lookup the item * @param name Name of the item to get */ menusection.prototype.lookup = function (name) { for (var _i = 0, _a = this.items; _i < _a.length; _i++) { var item = _a[_i]; if (item.name.toLowerCase() === name.toLowerCase()) { return item; } } return null; }; /** * Print this section to chat */ menusection.prototype.print = function (user, limit, discounted) { if (discounted === void 0) { discounted = false; } notice.add("=====" + this.name + "====="); var price; for (var _i = 0, _a = this.items; _i < _a.length; _i++) { var item = _a[_i]; price = discounted ? discount.apply(item, user) : item.cost; if (limit != null && price >= limit) continue; notice.add(price + emblems.token + item.name); } notice.apply(emblems.tipmenu); notice.post(user.user); }; return menusection; }()); /** * Manages notices, especially buffering notices */ var notice; /** * Manages notices, especially buffering notices */ (function (notice_1) { "use strict"; /** * Color to use in notices, if none specified */ notice_1.color = "#000000"; /** * Buffer of notices that haven't been posted */ var buffer = []; /** * Add the notice to the buffer * @param notice Notice to add */ function add(notice) { buffer[buffer.length] = notice; } notice_1.add = add; /** * Add the notices to the buffer * @param notices Notices to add */ function adds() { var notices = []; for (var _i = 0; _i < arguments.length; _i++) { notices[_i] = arguments[_i]; } for (var _a = 0, notices_1 = notices; _a < notices_1.length; _a++) { var notice_2 = notices_1[_a]; add(notice_2); } } notice_1.adds = adds; /** * Apply the emblem to each notice in the buffer * @param emblem Emblem to apply */ function apply(emblem) { for (var _i = 0, buffer_1 = buffer; _i < buffer_1.length; _i++) { var notice_3 = buffer_1[_i]; notice_3 = emblem + notice_3; } } notice_1.apply = apply; /** * Clear the buffer */ function clear() { buffer = []; } notice_1.clear = clear; /** * Print the help menu for notices * @param message Requesting message */ function help(message) { if (permissions.isAtLeastModerator(message)) { add("/note,notice <Message> --Send a notice to chat"); post(message.user); } } notice_1.help = help; /** * Post all notices in the buffer * @param to User to send to * @param textcolor Color of the text * @param weight Weight of the font * @param autoclear Clear the buffer automatically */ function post(to, textcolor, weight, autoclear) { if (to === void 0) { to = ""; } if (textcolor === void 0) { textcolor = notice_1.color; } if (weight === void 0) { weight = "bold"; } if (autoclear === void 0) { autoclear = true; } var message = buffer.join("\n"); cb.sendNotice(message, to, "#FFFFFF", textcolor, weight); if (autoclear) clear(); } notice_1.post = post; /** * Post all notices in the buffer * @param to Group to send to * @param textcolor Color of the text * @param weight Weight of the font */ function postGroup(to, textcolor, weight, autoclear) { if (textcolor === void 0) { textcolor = notice_1.color; } if (weight === void 0) { weight = "bold"; } if (autoclear === void 0) { autoclear = true; } var message = buffer.join("\n"); cb.sendNotice(message, "", "#FFFFFF", textcolor, weight, to); if (autoclear) clear(); } notice_1.postGroup = postGroup; /** * Send a notice * @param message Message to send * @param to User to send to * @param textcolor Color of the text * @param weight Weight of the font */ function send(message, to, textcolor, weight) { if (to === void 0) { to = ""; } if (textcolor === void 0) { textcolor = notice_1.color; } if (weight === void 0) { weight = "bold"; } cb.sendNotice(message, to, "#FFFFFF", textcolor, weight); } notice_1.send = send; /** * Send a notice * @param message Message to send * @param to Group to send to * @param textcolor Color of the text * @param weight Weight of the font */ function sendGroup(message, to, textcolor, weight) { if (textcolor === void 0) { textcolor = notice_1.color; } if (weight === void 0) { weight = "bold"; } cb.sendNotice(message, "", "#FFFFFF", textcolor, weight, to); } notice_1.sendGroup = sendGroup; /** * Try to parse a valid notice command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { if (permissions.isAtLeastModerator(message)) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/note": case "/notice": send(emblems.notice + m.join(" ")); return true; default: return false; } } return false; } notice_1.tryParse = tryParse; })(notice || (notice = {})); /** * Provides permissions checking * A lot of these are provided by the object anyways, are are implemented for the sake of orthogonality * This is solely for permissions purposes, the levels are: * broadcaster > trusted user > moderator > fanclub > tipped tons > tipped alot > tipped > has tokens > gray */ var permissions; /** * Provides permissions checking * A lot of these are provided by the object anyways, are are implemented for the sake of orthogonality * This is solely for permissions purposes, the levels are: * broadcaster > trusted user > moderator > fanclub > tipped tons > tipped alot > tipped > has tokens > gray */ (function (permissions) { "use strict"; /** * List of trusted users; users with elevated permissions */ var trusted = []; /** * Trust the users * @param users Users to trust */ function entrust() { var users = []; for (var _i = 0; _i < arguments.length; _i++) { users[_i] = arguments[_i]; } for (var _a = 0, users_1 = users; _a < users_1.length; _a++) { var user_1 = users_1[_a]; trusted[trusted.length] = user_1; } } permissions.entrust = entrust; /** * Remove trust of the users * @param users Users to detrust */ function detrust() { var users = []; for (var _i = 0; _i < arguments.length; _i++) { users[_i] = arguments[_i]; } for (var _a = 0, users_2 = users; _a < users_2.length; _a++) { var user_2 = users_2[_a]; trusted = cbjs.arrayRemove(trusted, user_2); } } permissions.detrust = detrust; /** * Is the user the broadcaster? * @param user User to check */ function isBroadcaster(user) { return user.user === cb.room_slug; } permissions.isBroadcaster = isBroadcaster; /** * Is the user a trusted user? * @param user User to check */ function isTrusted(user) { return cbjs.arrayContains(trusted, user.user); } permissions.isTrusted = isTrusted; /** * Is the user at least a trusted user? * @param user User to check */ function isAtLeastTrusted(user) { return isBroadcaster(user) || isTrusted(user); } permissions.isAtLeastTrusted = isAtLeastTrusted; /** * Is the user a moderator? * @param user User to check */ function isModerator(user) { return user.is_mod; } permissions.isModerator = isModerator; /** * Is the user at least a moderator? * @param user User to check */ function isAtLeastModerator(user) { return isAtLeastTrusted(user) || isModerator(user); } permissions.isAtLeastModerator = isAtLeastModerator; /** * Is the user in the fanclub? * @param user User to check */ function isInFanclub(user) { return user.in_fanclub; } permissions.isInFanclub = isInFanclub; /** * Is the user at least in the fanclub? * @param user User to check */ function isAtLeastInFanclub(user) { return isAtLeastModerator(user) || isInFanclub(user); } permissions.isAtLeastInFanclub = isAtLeastInFanclub; /** * Has the user tipped tons recently? * @param user User to check */ function hasTippedTons(user) { return user.tipped_tons_recently; } permissions.hasTippedTons = hasTippedTons; /** * Has the user at least tipped tons recently? * @param user User to check */ function hasAtLeastTippedTons(user) { return isAtLeastInFanclub(user) || hasTippedTons(user); } permissions.hasAtLeastTippedTons = hasAtLeastTippedTons; /** * Has the user tipped alot recently? * @param user User to check */ function hasTippedAlot(user) { return user.tipped_alot_recently; } permissions.hasTippedAlot = hasTippedAlot; /** * Has the user at least tipped alot recently? * @param user User to check */ function hasAtLeastTippedAlot(user) { return hasAtLeastTippedTons(user) || hasTippedAlot(user); } permissions.hasAtLeastTippedAlot = hasAtLeastTippedAlot; /** * Has the user tipped recently? * @param user User to check */ function hasTipped(user) { return user.tipped_recently; } permissions.hasTipped = hasTipped; /** * Has the user at least tipped recently? * @param user User to check */ function hasAtLeastTipped(user) { return hasAtLeastTippedAlot(user) || hasTipped(user); } permissions.hasAtLeastTipped = hasAtLeastTipped; /** * Does the user have tokens? * @param user User to check */ function hasTokens(user) { return user.has_tokens; } permissions.hasTokens = hasTokens; /** * Does the user at least have tokens? * @param user User to check */ function hasAtLeastTokens(user) { return hasAtLeastTipped(user) || hasTokens(user); } permissions.hasAtLeastTokens = hasAtLeastTokens; /** * Prints the help for permissions * @param message Requesting message */ function help(message) { if (permissions.isAtLeastTrusted(message)) { notice.add("/trust,trusted"); } if (permissions.isBroadcaster(message)) { notice.add(emblems.blank + "add <User>+ --Entrust the users"); notice.add(emblems.blank + "del,delete,rem,remove <User>+ --Detrust the users"); } if (permissions.isAtLeastTrusted(message)) { notice.add(emblems.blank + "list --List all trusted users"); notice.post(message.user); } } permissions.help = help; /** * Try to parse a permissions command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { if (permissions.isBroadcaster(message)) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/detrust": for (var _i = 0, m_1 = m; _i < m_1.length; _i++) { var user_3 = m_1[_i]; detrust(user_3); } return true; case "/entrust": for (var _a = 0, m_2 = m; _a < m_2.length; _a++) { var user_4 = m_2[_a]; entrust(user_4); } return true; case "/trust": case "/trusted": if (m.length === 0) return false; var operation = m.shift().toLowerCase(); switch (operation) { case "add": for (var _b = 0, m_3 = m; _b < m_3.length; _b++) { var user_5 = m_3[_b]; entrust(user_5); } return true; case "del": case "delete": case "rem": case "remove": for (var _c = 0, m_4 = m; _c < m_4.length; _c++) { var user_6 = m_4[_c]; detrust(user_6); } return true; case "help": help(message); return true; case "list": notice.send(trusted.join(", "), message.user); return true; default: return false; } } } return false; } permissions.tryParse = tryParse; })(permissions || (permissions = {})); /** * Manages rotating notices */ var rotater; /** * Manages rotating notices */ (function (rotater) { "use strict"; /** * Number, in minutes, between notices */ rotater.lapse = 3; /** * Notices in rotation */ var pool = []; /** * Index of the notice pool; current position */ var n = 0; /** * Add a notice to rotation * @param notice Notice to add */ function add(message) { pool[pool.length] = message; notice.send(emblems.notice + "'" + message + "' has been added to rotation"); } rotater.add = add; /** * Delete a notice from rotation * @param notice Notice literal or position to delete */ function del(message) { if (typeof message === "string") { pool = cbjs.arrayRemove(pool, message); notice.send(emblems.notice + "'" + message + "' has been removed from rotation"); } else if (typeof message === "number") { notice.send(emblems.notice + "'" + pool[message - 1] + "' has been removed from rotation"); pool = cbjs.arrayRemove(pool, pool[message - 1]); } } rotater.del = del; /** * Print the help menu for rotating notices * @param message Requesting message */ function help(message) { notice.add("/rotater,rotating,rotation"); if (permissions.isAtLeastModerator(message)) { notice.add(emblems.blank + "add <Message> --Add the notice to rotation"); } if (permissions.isAtLeastTrusted(message)) { notice.add(emblems.blank + "del,delete (<Message> | <Position>) --Delete the notice from rotation"); } notice.add(emblems.blank + "list,print --List all notices in rotation"); notice.post(message.user); notice.clear(); } rotater.help = help; /** * List all notices in rotation */ function list() { return pool; } rotater.list = list; function print(user) { var i = 0; for (var _i = 0, pool_1 = pool; _i < pool_1.length; _i++) { var note = pool_1[_i]; notice.add(++i + ") " + note); } notice.post(user.user); notice.clear(); } rotater.print = print; /** * Rotate and post notice */ function rotate() { notice.send(emblems.notice + pool[n++]); n %= pool.length; cb.setTimeout(rotate, rotater.lapse * 60 * 1000); } /** * Start the rotater */ function start() { cb.setTimeout(rotate, rotater.lapse * 60 * 1000); } rotater.start = start; /** * Try to parse a rotater command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/rotater": case "/rotating": case "/rotation": // Command is valid, break out break; default: return false; } if (m.length === 0) return false; var operation = m.shift().toLowerCase(); switch (operation) { case "add": if (permissions.isAtLeastModerator(message)) { rotater.add(m.join(" ")); return true; } return false; case "del": case "delete": if (permissions.isAtLeastTrusted(message)) { var pos = m.shift(); if (isNaN(Number(pos))) { // pos isn't actually a position, so put it back m.unshift(pos); rotater.del(m.join(" ")); } else { rotater.del(Number(pos)); } return true; } return false; case "help": help(message); return true; case "list": case "print": print(message); return true; default: return false; } } rotater.tryParse = tryParse; })(rotater || (rotater = {})); var tipmenu; (function (tipmenu) { "use strict"; /** * The specials menu section */ tipmenu.specials = new menusection("Specials"); /** * Specials command handler */ var special; (function (special) { /** * Print the help messages for the special manager * @param message Requesting message */ function help(message) { if (permissions.isAtLeastTrusted(message)) { notice.add("/special,specials"); notice.add(emblems.blank + "add <Cost> <Name> --Add the special to the menu"); notice.add(emblems.blank + "clr,clear --Clear all specials"); notice.add(emblems.blank + "del,delete <Name> --Delete the special from the menu"); notice.post(message.user); } } special.help = help; /** * Try to parse a specials command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { if (!permissions.isAtLeastTrusted(message)) return false; var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/special": case "/specials": // Command is valid, break out break; default: return false; } if (m.length === 0) return false; var operation = m.shift().toLowerCase(); var name; // This is assigned while parsing operations switch (operation) { case "add": var cost = m.shift(); if (isNaN(Number(cost))) { // Cost wasn't at the beginning, try finding it at the end m.unshift(cost); cost = m.pop(); if (isNaN(Number(cost))) return false; // No cost found, not a valid command } // We've found the cost, the rest is the name name = m.join(" "); tipmenu.specials.add(name, Number(cost)); notice.send(emblems.tipmenu + "'" + name + "' added as a special for " + cost + emblems.token); return true; case "clr": case "clear": tipmenu.specials.clear(); notice.send(emblems.tipmenu + "All specials have been removed"); return true; case "del": case "delete": name = m.join(" "); tipmenu.specials.del(name); notice.send(emblems.tipmenu + "'" + name + "' has been removed from the specials"); return true; case "help": help(message); return true; default: return false; } } special.tryParse = tryParse; })(special = tipmenu.special || (tipmenu.special = {})); })(tipmenu || (tipmenu = {})); /** * Calculates various stats */ var stats; /** * Calculates various stats */ (function (stats) { "use strict"; function meanHalves(sendTo) { notice.add("Upper Mean: " + tippers.meanUpper()); notice.add("Lower Mean: " + tippers.meanLower()); notice.post(sendTo); } stats.meanHalves = meanHalves; function medianTip(sendTo) { notice.add("Median Tip: " + tippers.median()); notice.post(sendTo); } stats.medianTip = medianTip; function showDuration(sendTo) { var duration = timers.showDuration(); notice.add("Show Duration: " + duration[0] + ":" + duration[1] + ":" + duration[2]); notice.post(sendTo); } stats.showDuration = showDuration; function tippersTotal(sendTo) { notice.add("Tippers Total: " + tippers.count); notice.post(sendTo); } stats.tippersTotal = tippersTotal; function tokensPerHour(sendTo) { var duration = timers.showDuration(); var minutes = duration[0] * 60 + duration[1]; var rate = (tippers.tipped() / minutes) * 60; notice.add("Tokens Per Hour: " + rate); notice.post(sendTo); } stats.tokensPerHour = tokensPerHour; function tokensPerTipper(sendTo) { notice.add("Tokens Per Tipper: " + tippers.tipped() / tippers.count()); notice.post(sendTo); } stats.tokensPerTipper = tokensPerTipper; function tokensTotal(sendTo) { notice.add("Tokens Total: " + tippers.tipped()); notice.post(sendTo); } stats.tokensTotal = tokensTotal; })(stats || (stats = {})); /** * Tallies items within the various managers */ var tallier; /** * Tallies items within the various managers */ (function (tallier) { "use strict"; /** * The actual tallies */ var tallies = []; /** * Add to the tally * @param item Item to add * @param amount Amount to add */ function add(item, amount) { if (amount === void 0) { amount = 1; } var tally = lookup(item); if (tally == null) { tallies[tallies.length] = [item, amount]; } else { tally[1] += amount; } } tallier.add = add; /** * Clear the tallies */ function clear() { tallies = []; } tallier.clear = clear; /** * Calculate the highest tip */ function highest() { if (tallies == null || tallies === []) return null; var high = [null, 0]; for (var _i = 0, tallies_1 = tallies; _i < tallies_1.length; _i++) { var tally = tallies_1[_i]; if (tally[1] > high[1]) high = tally; } return high; } tallier.highest = highest; /** * Lookup the item, and return its tally, if any, null otherwise * @param item Item to look for */ function lookup(item) { for (var _i = 0, tallies_2 = tallies; _i < tallies_2.length; _i++) { var tally = tallies_2[_i]; if (tally[0] === item) return tally; } return null; } tallier.lookup = lookup; })(tallier || (tallier = {})); /** * Represents a teamate, a tipper belonging to a team */ var teamate = (function () { function teamate(tipper, points) { if (points === void 0) { points = 0; } this.tipper = tipper; this.points = points; } teamate.prototype.name = function () { return this.tipper.name; }; teamate.prototype.tipped = function () { return this.tipper.tipped; }; return teamate; }()); /** * Represents a team */ var team = (function () { function team(emblem) { /** Members of the team */ this.members = []; this.emblem = ""; this.emblem = emblem; } /** * Add a user to the team * Because of a lack of data persistance, this is only temporary * @param user User to add */ team.prototype.add = function (user, points) { if (points === void 0) { points = 0; } // See if the user is already a tipper var tipper = tippers.lookup(user); if (tipper === null) { // The user isn't a tipper, so create a dummy entry tippers.dummy(user); tipper = tippers.lookup(user); } // Add the tipper, and their points, to the team this.members[this.members.length] = new teamate(tipper, points); }; /** * Add the users to the team * Because of a lack of data persistance, this is only temporary * @param users Users to add */ team.prototype.adds = function (users) { if (typeof users[0] === "string") { for (var _i = 0, _a = users; _i < _a.length; _i++) { var user_7 = _a[_i]; this.add(user_7); } } else { for (var _b = 0, _c = users; _b < _c.length; _b++) { var user_8 = _c[_b]; this.add(user_8[0], user_8[1]); } } }; /** * Apply the team emblem to a message if a member * @param message Message to apply emblem */ team.prototype.apply = function (message) { if (this.isMember(message.user)) { return this.emblem + message.m; } else { return message.m; } }; /** * Delete the user from the team * @param user User to remove */ team.prototype.del = function (user) { cbjs.arrayRemove(this.members, this.lookup(user)); }; /** * Delete the users from the team * @param user Users to remove */ team.prototype.dels = function (users) { for (var _i = 0, users_3 = users; _i < users_3.length; _i++) { var user_9 = users_3[_i]; cbjs.arrayRemove(this.members, this.lookup(user_9)); } }; /** * Is the user a member of this team? * @param user User to check */ team.prototype.isMember = function (user) { for (var _i = 0, _a = this.members; _i < _a.length; _i++) { var member = _a[_i]; if (member.name() == user) return true; } return false; }; /** * The number of members in the team */ team.prototype.length = function () { return this.members.length; }; /** * List the users in this team */ team.prototype.list = function (withPoints) { if (withPoints === void 0) { withPoints = false; } this.sort(); var result = []; if (withPoints) { var points = void 0; for (var _i = 0, _a = this.members; _i < _a.length; _i++) { var member = _a[_i]; points = member.points + member.tipped(); result[result.length] = "[" + points + "] " + member.name(); } } else { for (var _b = 0, _c = this.members; _b < _c.length; _b++) { var member = _c[_b]; result[result.length] = member.name(); } } return result; }; /** * Load the state string into the team * This is used to implement a sort of data persistance, although it must be managed by the user * @param state State string of the team */ team.prototype.load = function (state) { var users = state.trim().split(","); var name; var points; for (var _i = 0, users_4 = users; _i < users_4.length; _i++) { var user_10 = users_4[_i]; name = user_10.trim().split(" ")[0]; points = Number(user_10.trim().split(" ")[1]); this.add(name, points); } }; /** * Lookup the specified user * @param name Name to lookup */ team.prototype.lookup = function (name) { for (var _i = 0, _a = this.members; _i < _a.length; _i++) { var member = _a[_i]; if (member.name() == name) { return member; } } return null; }; /** * Save the state string for the team * This is used to implement a sort of data persistance, although it must be managed by the user */ team.prototype.save = function () { this.sort(); var state = ""; for (var _i = 0, _a = this.members; _i < _a.length; _i++) { var member = _a[_i]; state += member.name() + " " + (member.points + member.tipped()) + ", "; } state = state.substring(0, state.length - 2); //Removes the trailing comma return state; }; /** * Sort the team by points, most first */ team.prototype.sort = function () { this.members = this.members.sort(function (a, b) { return (b.points + b.tipped()) - (a.points + a.tipped()); }); }; /** * Get the total points of this team */ team.prototype.points = function () { var result; for (var _i = 0, _a = this.members; _i < _a.length; _i++) { var member = _a[_i]; result += member.points; } return result; }; return team; }()); /** * Represents a timer */ var timer = (function () { /** * Create a new timer * @param name Name of the timer * @param duration Duration of the timer, in seconds * @param delay Delay before the timer starts, in seconds */ function timer(name, duration, delay, onStart, onStop, onTick) { if (delay === void 0) { delay = 0; } this.name = name; this.duration = duration; this.remaining = duration; this.delay = delay; this.onStart = onStart; this.onStop = onStop; this.onTick = onTick; } /** * Extend the timer * @param seconds Seconds to extend by */ timer.prototype.extend = function (seconds) { this.duration += seconds; this.remaining += seconds; notice.send(emblems.timer + "'" + this.name + "' extended with " + seconds + "sec"); }; /** * Is the timer active? * This is true whether the timer is delayed or running * A timer is only inactive when it has stopped */ timer.prototype.isActive = function () { return this.delay > 0 || this.remaining > 0; }; /** * Is the timer currently delayed? */ timer.prototype.isDelayed = function () { return this.delay > 0; }; /** * Is the timer currently running? */ timer.prototype.isRunning = function () { return this.remaining < this.duration && this.remaining > 0; }; /** * Perform one tick of the timer, and call any events necessary */ timer.prototype.tick = function () { // Check event conditions if (this.delay === 0 && this.remaining === this.duration) { notice.send(emblems.timer + "'" + this.name + "' started with " + this.duration / 60 + "min"); if (this.onStart != null) this.onStart(); } else if (this.delay === 0 && this.remaining === 0) { notice.send(emblems.timer + "'" + this.name + "' has expired"); if (this.onStop != null) this.onStop(); } else if (this.delay === 0 && this.remaining % 60 === 0) { notice.send(emblems.timer + "'" + this.name + "' has " + this.remaining / 60 + "min remaining"); } // Time down as necessary if (this.delay > 0) { this.delay--; } else if (this.remaining > 0) { if (this.onTick != null) this.onTick(); this.remaining--; } }; return timer; }()); /** * Manages timers */ var timers; /** * Manages timers */ (function (timers) { "use strict"; /** * Pool of running timers */ var pool = []; /** * Duration of the show, in seconds */ var showtime = 0; /** * Add the timer to the pool * @param name Name of the timer * @param duration Duration to run for, in seconds * @param delay Delay before start, in seconds * @param onStart Function to call on start * @param onStop function to call on stop */ function add(name, duration, delay, onStart, onStop, onTick) { if (delay === void 0) { delay = 0; } pool[pool.length] = new timer(name, duration, delay, onStart, onStop, onTick); if (delay > 0) { notice.send(emblems.timer + "'" + name + "' will start in " + delay + "s"); } } timers.add = add; /** * Clear the pool of all timers */ function clear() { pool = []; } timers.clear = clear; /** * Delete the specified timer without properly stopping it * @param name Timer name or position to delete */ function del(timer) { if (typeof timer === "number") { notice.send(emblems.timer + "'" + pool[timer].name + "' has been removed"); pool = cbjs.arrayRemove(pool, pool[timer]); } else if (typeof timer === "string") { if (cbjs.arrayContains(pool, lookup(timer))) { notice.send(emblems.timer + "'" + timer + "' has been removed"); pool = cbjs.arrayRemove(pool, lookup(timer)); } } } timers.del = del; /** * Extend the timer by duration * @param name Name of the timer * @param duration Duration, in seconds, to extend run for */ function extend(name, duration) { var timer = lookup(name); if (timer != null) { timer.extend(duration); } } timers.extend = extend; /** * Prints the help menu for timers * @param message Requesting message */ function help(message) { if (permissions.isAtLeastModerator(message)) { notice.add("/timer,timers"); notice.add(emblems.blank + "add,start <Duration> <Name> --Add and start the timer"); } if (permissions.isAtLeastTrusted(message)) { notice.add(emblems.blank + "clr,clear --Clear and stop all timers"); notice.add(emblems.blank + "del,delete (<Name> | <Position>) --Delete the timer without any stop events"); notice.add(emblems.blank + "ext,extend <Duration> <Name> --Extend the timer"); } notice.add(emblems.blank + "list,print --List all active timers"); if (permissions.isAtLeastTrusted(message)) { notice.add(emblems.blank + "stop (<Name | <Position>) --Stop the timer next tick"); } notice.post(message.user); } timers.help = help; /** * List all active timers */ function list() { return pool; } timers.list = list; /** * Lookup the timer in the pool, null if not found * @param name Name to lookup */ function lookup(name) { for (var _i = 0, pool_2 = pool; _i < pool_2.length; _i++) { var timer_1 = pool_2[_i]; if (timer_1.name.toLowerCase() == name.toLowerCase()) { return timer_1; } } return null; } timers.lookup = lookup; /** * Get the current duration of the show * This is formatted time: [hours, minutes, seconds] */ function showDuration() { var hours = 0; var minutes = 0; var seconds = showtime; while (seconds >= 3600) { seconds -= 3600; hours += 1; } while (seconds >= 60) { seconds -= 60; minutes += 1; } return [hours, minutes, seconds]; } timers.showDuration = showDuration; /** * Start the timers */ function start() { cb.setTimeout(tick, 1000); } timers.start = start; /** * Set the timer to stop next tick * @param timer Timer to stop */ function stop(timer) { if (typeof timer === "number") { if (pool[timer] != null) pool[timer].remaining = 0; } else if (typeof timer === "string") { var t = lookup(timer); if (t != null) { t.remaining = 0; } } } timers.stop = stop; /** * Count down one interval */ function tick() { var keep = []; showtime += 1; for (var _i = 0, pool_3 = pool; _i < pool_3.length; _i++) { var timer_2 = pool_3[_i]; if (timer_2.isActive()) keep[keep.length] = timer_2; timer_2.tick(); } if (pool !== keep) { pool = keep; } cb.setTimeout(tick, 1000); } /** * Try to parse a timer command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); cb.log("command: " + command); switch (command) { case "/timer": case "/timers": // Command is valid, break out break; default: return false; } if (m.length === 0) return false; var operation = m.shift().toLowerCase(); cb.log("operation: " + operation); var name; // This is assigned while parsing operations var duration; // This is assigned while parsing operations var pos; // This is assigned while parsing operations switch (operation) { case "add": case "start": duration = m.shift(); if (isNaN(Number(duration))) { // Duration wasn't at the beginning, try finding it at the end m.unshift(duration); duration = m.pop(); if (isNaN(Number(duration))) return false; // No duration found, not a valid command } // We've found the duration, the rest is the name name = m.join(" "); timers.add(name, Number(duration) * 60); return true; case "clr": case "clear": timers.clear(); return true; case "del": case "delete": pos = m.shift(); if (isNaN(Number(pos))) { // pos isn't actually a position, so put it back m.unshift(pos); timers.del(m.join(" ")); } else { timers.del(Number(pos) - 1); } return true; case "ext": case "extend": duration = m.shift(); if (isNaN(Number(duration))) { // Duration wasn't at the beginning, try finding it at the end m.unshift(duration); duration = m.pop(); if (isNaN(Number(duration))) return false; // No duration found, not a valid command } // We've found the duration, the rest is the name name = m.join(" "); timers.extend(name, Number(duration) * 60); return true; case "help": help(message); return true; case "list": case "print": var i = 0; for (var _i = 0, pool_4 = pool; _i < pool_4.length; _i++) { var timer_3 = pool_4[_i]; notice.add(++i + ") '" + timer_3.name + "' with " + timer_3.remaining + "s"); } notice.apply(emblems.timer); notice.post(message.user); return true; case "stop": pos = m.shift(); if (isNaN(Number(pos))) { // pos isn't actually a position, so put it back m.unshift(pos); timers.stop(m.join(" ")); } else { timers.stop(Number(pos) - 1); } return true; default: return false; } } timers.tryParse = tryParse; })(timers || (timers = {})); /** * Represents a tipper; a user who as tipped */ var tipper = (function () { function tipper(name, tipped) { this.name = name; this.tipped = tipped; } return tipper; }()); /** * Manages and records tippers */ var tippers; /** * Manages and records tippers */ (function (tippers) { "use strict"; /** * All the tippers this show */ var pool = []; /** * Add the tip, incrementing an existing tipper, or adding a new one * @param tip Tip to add */ function add(tip) { var candidate = lookup(tip.from_user); if (candidate == null) { pool[pool.length] = new tipper(tip.from_user, 0); candidate = pool[pool.length - 1]; } candidate.tipped += tip.amount; } tippers.add = add; /** * Get the total amount of tippers */ function count() { return pool.length; } tippers.count = count; /** * Adds a dummy tipper * This creates an entry in the tippers manager, with no tip amount, which is necessary for teams * This should never, ever, be called outside of initialization * @param name Name of the tipper */ function dummy(name) { pool[pool.length] = new tipper(name, 0); } tippers.dummy = dummy; /** * Lookup the user, null if not found * @param user User to look up */ function lookup(user) { for (var _i = 0, pool_5 = pool; _i < pool_5.length; _i++) { var tipper_1 = pool_5[_i]; if (tipper_1.name === user) return tipper_1; } return null; } tippers.lookup = lookup; /** * Return the mean of the lower half */ function meanLower() { sort(); var lower = pool.slice(0, pool.length); var total = 0; for (var _i = 0, lower_1 = lower; _i < lower_1.length; _i++) { var tipper_2 = lower_1[_i]; total += tipper_2.tipped; } return total / lower.length; } tippers.meanLower = meanLower; /** * Return the mean of the upper half */ function meanUpper() { sort(); var upper = pool.slice(pool.length / 2, pool.length); var total = 0; for (var _i = 0, upper_1 = upper; _i < upper_1.length; _i++) { var tipper_3 = upper_1[_i]; total += tipper_3.tipped; } return total / upper.length; } tippers.meanUpper = meanUpper; /** * Return the median tip */ function median() { sort(); if (pool[Math.floor(pool.length / 2)] == null) { return NaN; } else { return pool[Math.floor(pool.length / 2)].tipped; } } tippers.median = median; /** * Sort the tippers, highest first */ function sort() { pool = pool.sort(function (a, b) { return b.tipped - a.tipped; }); } tippers.sort = sort; /** * Return the specified amount of top tippers * This is used to fetch a leaderboard, although it has other uses * @param amount Amount of tippers from the top to get */ function top(amount) { sort(); return pool.slice(0, amount); } tippers.top = top; /** * Get the total amount tipped */ function tipped() { var total = 0; for (var _i = 0, pool_6 = pool; _i < pool_6.length; _i++) { var tipper_4 = pool_6[_i]; total += tipper_4.tipped; } return total; } tippers.tipped = tipped; })(tippers || (tippers = {})); /** * Tracks viewers for stats purposes * Don't take the gender stats too seriously: people lie. This is just a curiousity. */ var viewers; /** * Tracks viewers for stats purposes * Don't take the gender stats too seriously: people lie. This is just a curiousity. */ (function (viewers) { "use strict"; viewers.current = 0; viewers.withTokens = 0; viewers.inFanclub = 0; viewers.claimMale = 0; viewers.claimFemale = 0; viewers.claimTrans = 0; viewers.claimCouple = 0; function enter(user) { viewers.current += 1; if (user.has_tokens) viewers.withTokens += 1; if (user.in_fanclub) viewers.inFanclub += 1; if (user.gender == "m") viewers.claimMale += 1; if (user.gender == "f") viewers.claimFemale += 1; if (user.gender == "s") viewers.claimTrans += 1; if (user.gender == "c") viewers.claimTrans += 1; } viewers.enter = enter; function leave(user) { viewers.current -= 1; if (user.has_tokens) viewers.withTokens -= 1; if (user.in_fanclub) viewers.inFanclub -= 1; if (user.gender == "m") viewers.claimMale -= 1; if (user.gender == "f") viewers.claimFemale -= 1; if (user.gender == "s") viewers.claimTrans -= 1; if (user.gender == "c") viewers.claimTrans -= 1; } viewers.leave = leave; })(viewers || (viewers = {})); /** * Manages votes and ballots */ var votes; /** * Manages votes and ballots */ (function (votes) { "use strict"; /** * The cast votes */ var casts = []; /** * The current ballot */ var ballot = []; /** * Cast or change a vote, validating it in the process * @param username Username of the voter * @param choice Choice voting for */ function cast(username, choice) { for (var _i = 0, ballot_1 = ballot; _i < ballot_1.length; _i++) { var ch = ballot_1[_i]; if (ch.toLowerCase() === choice.toLowerCase()) { casts[casts.length] = [username, choice]; notice.send(emblems.ballot + "Vote cast"); return; } } notice.send(emblems.ballot + "Your vote for '" + choice + "' was not recognized among the valid options", username); } votes.cast = cast; /** * Clear the cast votes and ballot */ function clear() { casts = []; ballot = []; } votes.clear = clear; /** * Print the help messages for voting * @param message Requesting message */ function help(message) { if (permissions.hasAtLeastTokens(message)) { notice.add("/vote <Choice> --Cast a vote for the choice"); } if (permissions.isAtLeastModerator(message)) { notice.add(emblems.blank + "start,ballot <Choice>,+ --Start voting among the specified choices"); notice.add(emblems.blank + "stop,end,tally --Stop voting, tally results, and declare the winner"); } notice.post(message.user); } votes.help = help; /** * Lookup a vote cast by the user, null if not found * @param username Username to look for */ function lookup(username) { for (var _i = 0, casts_1 = casts; _i < casts_1.length; _i++) { var cast_1 = casts_1[_i]; if (cast_1[0] === username) return cast_1; } return null; } votes.lookup = lookup; /** * Start a ballot with the specified choices * @param choices Ballot choices */ function start(choices) { clear(); ballot = choices; notice.add("A ballot has started between the following:"); for (var _i = 0, choices_1 = choices; _i < choices_1.length; _i++) { var choice = choices_1[_i]; notice.add(choice); } notice.apply(emblems.ballot); notice.post(); notice.clear(); } votes.start = start; /** * Stop voting, count the votes, and report the winner */ function stop() { if (casts == null || casts === []) { notice.send(emblems.ballot + "No votes have been cast"); return; } for (var _i = 0, casts_2 = casts; _i < casts_2.length; _i++) { var cast_2 = casts_2[_i]; tallier.add(cast_2[1]); } var highest = tallier.highest(); notice.send(emblems.ballot + "Winner is: '" + highest[0] + "' with " + highest[1] + " votes"); clear(); tallier.clear(); } votes.stop = stop; /** * Try to parse a vote command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/vote": case "/voting": // Command is valid, break out break; default: return false; } if (m.length === 0) return false; var operation = m.shift().toLowerCase(); switch (operation) { case "help": help(message); return true; case "start": case "ballot": if (!permissions.isAtLeastModerator(message)) return false; var choices = m.join(" ").split(","); for (var _i = 0, choices_2 = choices; _i < choices_2.length; _i++) { var choice = choices_2[_i]; choice = choice.trim(); } start(choices); return true; case "stop": case "end": case "tally": if (!permissions.isAtLeastModerator(message)) return false; stop(); return true; default: if (!permissions.hasAtLeastTokens(message)) return false; m.unshift(operation); cast(message.user, m.join(" ")); return true; } } votes.tryParse = tryParse; })(votes || (votes = {})); /** * Implements whispers */ var whisper; /** * Implements whispers */ (function (whisper) { "use strict"; /** * Print the help messages for whispers * @param message Requesting message */ function help(message) { if (permissions.hasAtLeastTokens(message)) { notice.add("/w,whisper"); notice.add(emblems.blank + "model <Message> --Send a message to the model"); notice.add(emblems.blank + "mod,mods,moderator,moderators <Message> --Send a message to all moderators"); notice.add(emblems.blank + "<User> <Message> --Send a message to the user"); notice.post(message.user); notice.clear(); } } whisper.help = help; /** * Do model whisper specific stuff * @param message Requesting message * @param m Remaining message */ function model(message, m) { // While not the case elsewhere, this command uses the permissions level to color the whisper, not just permit it. if (permissions.isTrusted(message)) notice.send(emblems.whisper + message.user + ": " + m, cb.room_slug, "#802080", "bolder"); else if (permissions.isModerator(message)) notice.send(emblems.whisper + message.user + ": " + m, cb.room_slug, "#802020", "bolder"); else if (permissions.isInFanclub(message)) notice.send(emblems.whisper + message.user + ": " + m, cb.room_slug, "#208020"); else if (permissions.hasTokens(message)) notice.send(emblems.whisper + message.user + ": " + m, cb.room_slug, "#808080"); } /** * Do mod whisper specific stuff * @param message Requesting message * @param m Remaining message */ function mods(message, m) { notice.add(emblems.whispermod + message.user + ": " + m); notice.post(cb.room_slug, "#802020", "bolder", false); notice.postGroup("red", "#802020", "bolder", false); notice.clear(); } /** * Try to parse a specials command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/model": model(message, m.join(" ")); notice.send(emblems.whisper + "Sent to: " + cb.room_slug, message.user); return true; case "/mod": case "/mods": case "/moderator": case "/moderators": mods(message, m.join(" ")); notice.send(emblems.whispermod + "Sent to all moderators", message.user); return true; case "/w": case "/whisper": // Command is valid but needs further parsing, break out break; default: return false; } if (m.length === 0) return false; var target = m.shift().toLowerCase(); switch (target) { case "help": //Not actually a target, but an option, so print help and return help(message); return true; case "model": model(message, m.join(" ")); notice.send(emblems.whisper + "Sent to: " + cb.room_slug, message.user); return true; case "mod": case "mods": case "moderator": case "moderators": mods(message, m.join(" ")); notice.send(emblems.whispermod + "Sent to all moderators", message.user); return true; default: if (target.toLowerCase() === cb.room_slug) model(message, m.join(" ")); else notice.send(emblems.whisper + message.user + ": " + m.join(" "), target, "#808080", "normal"); notice.send(emblems.whisper + "Sent to: " + target, message.user); return true; } } whisper.tryParse = tryParse; })(whisper || (whisper = {})); /** * Misc. room stuff */ var room; /** * Misc. room stuff */ (function (room) { /** * Prints the full help menu * @param message Requesting message */ function help(message) { hightip.help(message); notice.help(message); permissions.help(message); rotater.help(message); tipmenu.special.help(message); stats.help(message); teams.help(message); timers.help(message); tipmenu.help(message); votes.help(message); whisper.help(message); } /** * Try to parse a room command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/room": if (m.length === 0) return false; var command_1 = m.shift().toLowerCase(); switch (command_1) { case "help": break; default: return false; } // This deliberately falls through case "/roomhelp": help(message); return true; } return false; } room.tryParse = tryParse; })(room || (room = {})); var stats; (function (stats) { "use strict"; /** * Prints the help for stats * @param message */ function help(message) { if (permissions.isAtLeastTrusted(message)) { notice.add("/stats,statistics --Get all calculated stats"); notice.post(message.user); message['X-Spam'] = true; } } stats.help = help; /** * Print all the stats * @param message Requesting message */ function print(message) { stats.showDuration(message.user); stats.tokensTotal(message.user); stats.tippersTotal(message.user); stats.tokensPerHour(message.user); stats.tokensPerTipper(message.user); stats.meanHalves(message.user); stats.medianTip(message.user); listViewers(message.user); listBans(message.user); } stats.print = print; function listBans(sendTo) { notice.add("Cum Ban: " + tipmenu.flags.cumban); notice.add("Pepsi Ban: " + tipmenu.flags.pepsiban); notice.post(sendTo); } stats.listBans = listBans; function listViewers(sendTo) { notice.add("Viewers (Signed In): " + viewers.current); notice.add("Viewers (With Tokens): " + viewers.withTokens); notice.post(sendTo); } stats.listViewers = listViewers; /** * Try to parse a stats command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { if (permissions.isAtLeastTrusted(message)) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/stats": case "/statistics": print(message); return true; default: return false; } } return false; } stats.tryParse = tryParse; })(stats || (stats = {})); var cb; (function (cb) { cb.settings_choices = [ { name: "anal", label: "Anal Items", type: "choice", choice1: "on", choice2: "off", defaultValue: "on", required: true, }, { name: "pussy", label: "Pussy Items", type: "choice", choice1: "on", choice2: "off", defaultValue: "on", required: true, }, { name: "spanks", label: "Spank Items", type: "choice", choice1: "on", choice2: "off", defaultValue: "on", required: true, }, { name: "workout", label: "Workout Items", type: "choice", choice1: "on", choice2: "off", defaultValue: "on", required: true, }, { name: "cumban", label: "Cumban Days", type: "int", defaultValue: 0, required: true, }, { name: "pepsiban", label: "Pepsiban Days", type: "int", defaultValue: 0, required: true, }, { name: "coke", label: "Coca-Cola", type: "int", defaultValue: 0, required: true, }, { name: "teamgood", label: "Team Good", type: "str", required: false, }, { name: "teamevil", label: "Team Evil", type: "str", required: false, }, { name: "teammj", label: "Team MJ", type: "str", required: false, }, { name: "teamamelia", label: "Team Amelia", type: "str", required: false, }, { name: "teamthrall", label: "Team Thrall", type: "str", required: false, }, { name: "hightip", label: "High Tip", type: "str", required: true, }, ]; })(cb || (cb = {})); var handlers; (function (handlers) { function ballgag() { var timer = timers.lookup("Ballgag"); if (timer != null) { timer.extend(4 * 60); } else { timers.add("Ballgag", 4 * 60, 60); } } handlers.ballgag = ballgag; function naked() { var timer = timers.lookup("Naked"); if (timer != null) { timer.extend(5 * 60); } else { timers.add("Naked", 5 * 60, 60); } } handlers.naked = naked; function coke(amount) { tipmenu.flags.coke += Number(amount); } handlers.coke = coke; function counterFapInterruption() { timers.stop("Fap Interruption"); } handlers.counterFapInterruption = counterFapInterruption; function counterSpankBan() { timers.stop("Spankban"); } handlers.counterSpankBan = counterSpankBan; function cumBan(amount) { tipmenu.flags.cumban += Number(amount); tipmenu.build(); } handlers.cumBan = cumBan; function fapInterruption() { var timer = timers.lookup("Fap Interruption"); if (timer != null) { timer.extend(30); } else { timers.add("Fap Interruption", 30, 0, function () { tipmenu.flags.fapinteruption = true; tipmenu.build(); }, function () { tipmenu.flags.fapinteruption = false; tipmenu.build(); }); } } handlers.fapInterruption = fapInterruption; function hitachi() { var timer = timers.lookup("Hitachi"); if (timer != null) { timer.extend(10 * 60); } else { timers.add("Hitachi", 10 * 60, 60); } } handlers.hitachi = hitachi; function joinGood() { } handlers.joinGood = joinGood; function joinEvil() { } handlers.joinEvil = joinEvil; function pepsiBan(amount) { tipmenu.flags.pepsiban += Number(amount); tipmenu.build(); } handlers.pepsiBan = pepsiBan; function plug() { tipmenu.flags.plugged = true; } handlers.plug = plug; function spankban() { var timer = timers.lookup("Spankban"); if (timer != null) { timer.extend(30); } else { timers.add("Spankban", 30 * 60, 0, function () { tipmenu.flags.spankban = true; tipmenu.build(); }, function () { tipmenu.flags.spankban = false; tipmenu.build(); }); } } handlers.spankban = spankban; function teamAmelia(tip) { if (teams.amelia.isMember(tip.from_user)) { return; } else { if (teams.mj.isMember(tip.from_user)) { teams.mj.del(tip.from_user); } else if (teams.thrall.isMember(tip.from_user)) { teams.thrall.del(tip.from_user); } teams.amelia.add(tip.from_user); } } handlers.teamAmelia = teamAmelia; function teamEvil(tip) { if (teams.evil.isMember(tip.from_user)) { return; } else { if (teams.good.isMember(tip.from_user)) { teams.evil.add(tip.from_user, teams.good.lookup(tip.from_user).points); teams.good.del(tip.from_user); } else { teams.evil.add(tip.from_user); } } } handlers.teamEvil = teamEvil; function teamGood(tip) { if (teams.good.isMember(tip.from_user)) { return; } else { if (teams.evil.isMember(tip.from_user)) { teams.good.add(tip.from_user, teams.evil.lookup(tip.from_user).points); teams.evil.del(tip.from_user); } else { teams.good.add(tip.from_user); } } } handlers.teamGood = teamGood; function teamMJ(tip) { if (teams.mj.isMember(tip.from_user)) { return; } else { if (teams.amelia.isMember(tip.from_user)) { teams.amelia.del(tip.from_user); } else if (teams.thrall.isMember(tip.from_user)) { teams.thrall.del(tip.from_user); } teams.mj.add(tip.from_user); } } handlers.teamMJ = teamMJ; function teamThrall(tip) { if (teams.thrall.isMember(tip.from_user)) { return; } else { if (teams.amelia.isMember(tip.from_user)) { teams.amelia.del(tip.from_user); } else if (teams.mj.isMember(tip.from_user)) { teams.mj.del(tip.from_user); } teams.thrall.add(tip.from_user); } } handlers.teamThrall = teamThrall; function unplug() { tipmenu.flags.plugged = false; } handlers.unplug = unplug; function vaginaTease() { var timer = timers.lookup("Vagina Tease"); if (timer != null) { timer.extend(60); } else { timers.add("Vagina Tease", 60, 30); } } handlers.vaginaTease = vaginaTease; })(handlers || (handlers = {})); var tipmenu; (function (tipmenu) { /** * Flags which control what is active in the tipmenu */ var flags; (function (flags) { flags.pepsiban = 0; flags.cumban = 0; flags.coke = 0; flags.fapinteruption = false; flags.plugged = false; flags.silenced = false; flags.spankban = false; flags.anal = false; flags.spanks = false; flags.pussy = false; flags.workout = false; })(flags = tipmenu.flags || (tipmenu.flags = {})); tipmenu.general = new menusection("General"); tipmenu.fanclub = new menusection("Fanclub"); tipmenu.good = new menusection("Good"); tipmenu.evil = new menusection("Evil"); tipmenu.teams = new menusection("Teams", new menuitem("Join Team Good (1mo)", 177, handlers.teamGood), new menuitem("Join Team Good (life)", 1177, handlers.teamGood), new menuitem("Join Team Evil (1mo)", 166, handlers.teamEvil), new menuitem("Join Team Evil (life)", 1166, handlers.teamEvil), new menuitem("Join Team Thrall", 497, handlers.teamThrall), new menuitem("Join Team MJ", 498, handlers.teamMJ), new menuitem("Join Team Amelia", 499, handlers.teamAmelia)); /** * Build the tipmenu with whatever is assigned in flags */ function build() { tipmenu.general.clear(); tipmenu.fanclub.clear(); tipmenu.good.clear(); tipmenu.evil.clear(); // Build General Section tipmenu.general.add("Foot Flash", 20); tipmenu.general.add("Booty Flash", 30); tipmenu.general.add("War", 44); tipmenu.general.add("Goody Box", 55); tipmenu.general.add("Boobie Flash", 65); if (flags.pussy) { tipmenu.general.add("Vagina/Doggy Flash", 66); } tipmenu.general.add("Suck a Toe", 99); if (flags.pussy) { tipmenu.general.add("Vagina Tease (1min)", 100, handlers.vaginaTease); } tipmenu.general.add("Lap Milk", 255); if (flags.pussy) { tipmenu.general.add("Naked (5min)", 366, handlers.naked); } if (flags.coke > 0) { tipmenu.general.add("Drink Coke", 400, handlers.coke, -1); tipmenu.general.add("Dump Fresh Coke", 401); tipmenu.general.add("Dump Current Coke", 644, handlers.coke, -1); } tipmenu.general.add("Ballgag (4min)", 444, handlers.ballgag); if (flags.anal && !flags.plugged) { tipmenu.general.add("Buttplug", 900, handlers.plug); } else if (flags.anal && flags.plugged) { tipmenu.general.add("Remove Buttplug", 900, handlers.unplug); } if (flags.pussy) { tipmenu.general.add("Hitachi (10 min)", 1000, handlers.hitachi); } // Build Fanclub Section tipmenu.fanclub.add("Imitate a GIF", 21); tipmenu.fanclub.add("Monkeyface", 35); tipmenu.fanclub.add("Stuff My Face", 105); if (flags.fapinteruption) { tipmenu.fanclub.add("Counter Fap Interruption", 130, handlers.counterFapInterruption); } else { tipmenu.fanclub.add("Fap Interruption (30s)", 129, handlers.fapInterruption); } tipmenu.fanclub.add("Sing to You", 349); tipmenu.fanclub.add("Force to Play Torture", 1010); tipmenu.fanclub.add("Log Off to Game", 6000); // Build Good Section tipmenu.good.add("Blow a Kiss", 7); tipmenu.good.add("Tip for Pet", 50); if (flags.workout) { tipmenu.good.add("Fitness Ginger", 175); } if (flags.spanks == true) { tipmenu.good.add("Spankban (30min)", 222, handlers.spankban); } tipmenu.good.add("Remove Clothing Added by Team Evil", 300); tipmenu.good.add("Remove Touchban", 567); if (flags.pepsiban > 0) { tipmenu.good.add("Remove Pepsiban (1d)", 733, handlers.pepsiBan, -1); tipmenu.good.add("Remove Pepsiban (1wk)", 3777, handlers.pepsiBan, -7); } if (flags.silenced) { tipmenu.good.add("Unsilence Me", 577); } if (flags.cumban > 0) { tipmenu.good.add("Remove Cumban (1d)", 2777, handlers.cumBan, -1); tipmenu.good.add("Remove Cumban (1wk)", 10777, handlers.cumBan, -7); } // Build Evil Section if (flags.spanks == true && flags.spankban == false) { tipmenu.evil.add("Hand Spank", 10); tipmenu.evil.add("Vagina Slap", 15); tipmenu.evil.add("Paddle Spank", 31); } tipmenu.evil.add("Flip you Off", 11); tipmenu.evil.add("Add Clothing (30min)", 250); if (flags.spanks == true && flags.spankban == true) { tipmenu.evil.add("Remove Spank Ban", 333, handlers.counterSpankBan); } tipmenu.evil.add("Touchban", 565); if (!flags.silenced) { tipmenu.evil.add("Silence (I Kill You)", 566); } tipmenu.evil.add("Pepsiban (1d)", 633, handlers.pepsiBan, 1); tipmenu.evil.add("Pepsiban (1wk)", 3333, handlers.pepsiBan, 7); tipmenu.evil.add("Cumban (1d)", 2666, handlers.cumBan, 1); tipmenu.evil.add("Cumban (1wk)", 9999, handlers.cumBan, 7); } tipmenu.build = build; /** * Print the help messages for tipmenu * @param message Requesting message */ function help(message) { notice.add("/menu -- Get the entire tipmenu"); notice.add(emblems.blank + "<Section>+ --Get only the specified sections"); notice.add(emblems.blank + "limit <Cost> --Get all items lesser or equal to the specified cost"); if (permissions.isAtLeastTrusted(message)) { notice.add(emblems.blank + "set (<Flag> <Level>)+ --Set each specified flag to level, and rebuild the tipmenu"); } notice.post(message.user); } tipmenu.help = help; /** * Attempt to match the tip to an item in the menu * @param tip Tip to match */ function match(tip) { for (var _i = 0, _a = tipmenu.specials.list(); _i < _a.length; _i++) { var item = _a[_i]; if (tip.amount === item.cost) return item; } for (var _b = 0, _c = tipmenu.general.list(); _b < _c.length; _b++) { var item = _c[_b]; if (tip.amount === item.cost) return item; } if (tip.from_user_in_fanclub) { for (var _d = 0, _e = tipmenu.fanclub.list(); _d < _e.length; _d++) { var item = _e[_d]; if (tip.amount === item.cost) return item; } } for (var _f = 0, _g = tipmenu.good.list(); _f < _g.length; _f++) { var item = _g[_f]; if (tip.amount === item.cost) return item; } for (var _h = 0, _j = tipmenu.evil.list(); _h < _j.length; _h++) { var item = _j[_h]; if (tip.amount === item.cost) return item; } return null; } tipmenu.match = match; /** * Print the tipmenu to chat * @param message Requesting message * @param flags Controls which sections are printed */ function print(message, limit, flags) { if (limit === void 0) { limit = null; } if (flags === void 0) { flags = [true, true, true, true, true, true]; } if (flags[0]) tipmenu.specials.print(message, limit); if (flags[1]) tipmenu.general.print(message, limit); if (flags[2]) tipmenu.fanclub.print(message, limit); if (flags[3]) tipmenu.good.print(message, limit); if (flags[4]) tipmenu.evil.print(message, limit); if (flags[5]) tipmenu.teams.print(message, limit); } tipmenu.print = print; /** * Try to parse a tipmenu command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/menu": case "/tipmenu": if (m.length === 0) { print(message); return true; } else { var sections = [false, false, false, false, false, false]; var setmode = false; var word = void 0; var level = void 0; while (m.length !== 0) { word = m.shift().toLowerCase(); switch (word) { case "limit": if (m.length === 0) return false; var limit = m.shift(); if (isNaN(Number(limit))) return false; print(message, Number(limit)); return true; case "anal": if (setmode) { if (m.length === 0) return false; level = m.shift().toLowerCase(); switch (level) { case "on": flags.anal = true; tipmenu.build(); notice.send(emblems.tipmenu + "Anal items are now active"); continue; case "off": flags.anal = false; tipmenu.build(); notice.send(emblems.tipmenu + "Anal items are no longer active"); continue; default: notice.send("For '" + word + "', found '" + level + "', but expected a level of (off | on)", message.user); return false; } } break; case "spanks": if (setmode) { if (m.length === 0) return false; level = m.shift().toLowerCase(); switch (level) { case "on": flags.spanks = true; tipmenu.build(); notice.send(emblems.tipmenu + "Spank items are now active"); continue; case "off": flags.spanks = false; tipmenu.build(); notice.send(emblems.tipmenu + "Spank items are no longer active"); continue; default: notice.send("For '" + word + "', found '" + level + "', but expected a level of (off | on)", message.user); return false; } } break; case "pussy": if (setmode) { if (m.length === 0) return false; level = m.shift().toLowerCase(); switch (level) { case "on": flags.pussy = true; tipmenu.build(); notice.send(emblems.tipmenu + "Pussy items are now active"); continue; case "off": flags.pussy = false; tipmenu.build(); notice.send(emblems.tipmenu + "Pussy items are no longer active"); continue; default: notice.send("For '" + word + "', found '" + level + "', but expected a level of (off | on)", message.user); return false; } } case "workout": case "fitness": if (setmode) { if (m.length === 0) return false; level = m.shift().toLowerCase(); switch (level) { case "on": flags.workout = true; tipmenu.build(); notice.send(emblems.tipmenu + "Fitness items are now active"); continue; case "off": flags.workout = false; tipmenu.build(); notice.send(emblems.tipmenu + "Fitness items are no longer active"); continue; default: notice.send("For '" + word + "', found '" + level + "', but expected a level of (off | on)", message.user); return false; } } default: break; } } print(message, null, sections); for (var _i = 0, sections_1 = sections; _i < sections_1.length; _i++) { var flag = sections_1[_i]; if (flag) return true; } return false; } default: return false; } } tipmenu.tryParse = tryParse; })(tipmenu || (tipmenu = {})); var teams; (function (teams) { teams.good = new team(" :goodminion24 "); teams.evil = new team(" :evilminion24g "); teams.mj = new team(""); teams.amelia = new team(""); teams.thrall = new team(""); /** * Print the help menu for teams * @param message Requesting message */ function help(message) { notice.add("/team,teams --List the teams"); notice.add(emblems.blank + "<Team> --List all users in the specified team"); if (permissions.isAtLeastTrusted(message)) { notice.add(emblems.blank + "<Team> add <Name>+ --Add the users to the specified team"); notice.add(emblems.blank + "<Team> delete <Name>+ --Delete the users from the specified team"); notice.add(emblems.blank + "<Team> points --Get the total points from the specified team"); notice.add(emblems.blank + "<Team> save,state,store --Get a state string for the specified team"); notice.post(message.user); } } teams.help = help; /** * Try to parse a teams command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/team": case "/teams": if (m.length === 0) { notice.send("Teams: good, evil", message.user); } else { var team_1 = m.shift().toLowerCase(); var operation = void 0; switch (team_1) { case "good": if (m.length === 0) { for (var _i = 0, _a = teams.good.list(true); _i < _a.length; _i++) { var user_11 = _a[_i]; notice.send(user_11, message.user); } return true; } else { if (!permissions.isAtLeastTrusted(message)) return false; operation = m.shift().toLowerCase(); switch (operation) { case "add": teams.good.adds(m); notice.send("Added users", message.user); return true; case "delete": teams.good.dels(m); notice.send("Deleted users", message.user); return true; case "point": case "points": notice.send("" + teams.good.points(), message.user); return true; case "save": case "state": case "store": notice.send(teams.good.save(), message.user); return true; default: return false; } } case "help": //Not actually a team, but an option, so print help then return help(message); return true; case "evil": if (m.length === 0) { for (var _b = 0, _c = teams.evil.list(true); _b < _c.length; _b++) { var user_12 = _c[_b]; notice.send(user_12, message.user); } return true; } else { if (!permissions.isAtLeastTrusted(message)) return false; operation = m.shift().toLowerCase(); switch (operation) { case "add": teams.evil.adds(m); notice.send("Added users", message.user); return true; case "delete": teams.evil.dels(m); notice.send("Deleted users", message.user); return true; case "point": case "points": notice.send("" + teams.evil.points(), message.user); return true; case "save": case "state": case "store": notice.send(teams.evil.save(), message.user); return true; default: return false; } } default: notice.send("For teams, found '" + team_1 + "', but expected one of: good, evil", message.user); return false; } } default: return false; } } teams.tryParse = tryParse; })(teams || (teams = {})); cb.onEnter(function (user) { notice.adds("Welcome to my room!", "To see available commands, enter /roomhelp in chat", "Check out the tip menu with /menu"); notice.apply(emblems.notice); notice.post(user.user); viewers.enter(user); }); cb.onLeave(function (user) { if (hightip.name() != null && hightip.name() === user.user) { notice.send(emblems.notice + "King " + hightip.name() + " has left... Quick, steal the" + emblems.crown); } viewers.leave(user); }); cb.onMessage(function (message) { // Mark a message as spam if a foreslash is found at the begining if (message.m.trim().charAt(0) === "/") message['X-Spam'] = true; /** Whether a valid command has been found while parsing */ var validCommand = false; // Attempt to parse a command // This is goal-directed parsing, essentially, JavaScript just doesn't have any good syntax for it // While a command has not been found, keep trying to parse commands // When a command has been found, mark it as spam, which in turn avoids further attempts at parsing if (!validCommand) { validCommand = hightip.tryParse(message); } if (!validCommand) { validCommand = leaderboard.tryParse(message); } if (!validCommand) { validCommand = notice.tryParse(message); } if (!validCommand) { validCommand = permissions.tryParse(message); } if (!validCommand) { validCommand = room.tryParse(message); } if (!validCommand) { validCommand = rotater.tryParse(message); } if (!validCommand) { validCommand = tipmenu.special.tryParse(message); } if (!validCommand) { validCommand = stats.tryParse(message); } if (!validCommand) { validCommand = teams.tryParse(message); } if (!validCommand) { validCommand = timers.tryParse(message); } if (!validCommand) { validCommand = tipmenu.tryParse(message); } if (!validCommand) { validCommand = votes.tryParse(message); } if (!validCommand) { validCommand = whisper.tryParse(message); } // A command was found, even if invalid, so return if (message['X-Spam'] || validCommand) return message; // Apply team emblems message.m = teams.good.apply(message); message.m = teams.evil.apply(message); // Apply background highlight if (teams.mj.isMember(message.user)) { message.background = "#FFBFBF"; } if (teams.amelia.isMember(message.user)) { message.background = "#FFEABF"; } if (teams.thrall.isMember(message.user)) { message.background = "#BFEAFF"; } // Apply tip amount var tipper = tippers.lookup(message.user); if (tipper !== null && tipper.tipped !== 0) { message.m = "[" + tipper.tipped + "] " + message.m; } // Return the message return message; }); cb.onTip(function (tip) { tippers.add(tip); var match = tipmenu.match(tip); if (match != null) { notice.send(emblems.tipmenu + tip.from_user + " has tipped for " + match.name); match.handle(tip); } }); /** * Initialization code */ { notice.color = "#00AAFF"; permissions.entrust("entomy", "mjsname", "jer4mj"); timers.start(); rotater.add("Follow me on Twitter: @Ginger_Soulz"); rotater.add("Check me out on ManyVids: GingerSouls.ManyVids.com"); rotater.add("Check out the tipmenu with: /menu"); rotater.start(); if (cb.settings.hightip !== undefined) { hightip.load(cb.settings.hightip); } if (cb.settings.cumban !== undefined) { tipmenu.flags.cumban = cb.settings.cumban; } if (cb.settings.pepsiban !== undefined) { tipmenu.flags.pepsiban = cb.settings.pepsiban; } if (cb.settings.coke !== undefined) { tipmenu.flags.coke = cb.settings.coke; } tipmenu.flags.anal = cb.settings.anal == "on"; tipmenu.flags.pussy = cb.settings.pussy == "on"; tipmenu.flags.spanks = cb.settings.spanks == "on"; tipmenu.flags.workout = cb.settings.workout == "on"; tipmenu.build(); teams.good.load(String(cb.settings.teamgood)); teams.evil.load(String(cb.settings.teamevil)); teams.mj.load(String(cb.settings.teammj)); teams.amelia.load(String(cb.settings.teamamelia)); teams.thrall.load(String(cb.settings.teamthrall)); }
© Copyright Chaturbate 2011- 2024. All Rights Reserved.