Bots Home
|
Create an App
aerh
Author:
4science
Description
Source Code
Launch Bot
Current Users
Created by:
4science
/** Name: Dorothy's Ultra Fembot Author: chelsea2950 Created: 11/29/2018 See Change Log on bot description page for revision history This ultrabot is intended to provide more experienced cammers with a single tool to provide most common bot functions. I've borrowed some existing features from many places/bots including 18yearold, allinone and ultrabot for most, so credit to those who have gone before for all your hard work (britney and justin, alice and shaggy, lund, acrazyguy, and I'm sure many others). Special recognition to 4science for the Tip Menu and Token Polls (which were built off work by badbadbubba and NotThatFrank). This bot is also intended to be transparent and not automatically add people to your modlist and ticket show lists and give other special rights without permission. Main features from the Easy Fembot are: Messaging for mods and broadcasters Private Messages to other users Silence Level and Graphic Level Leaderboard Nice List Tip Count next to name Silence individual users Silence individual users without notification (ninja) Added features in this bot: Tip Menu Positions Tip Menu Token Poll VIP List External FanClub List Blocked word list Additional Notifiers (up to 5 rotating) User Group icons next to name (mods, CB fan club, external fan club, VIP list) Color control of most messaging Ticket prep function (disable regular tip menu, enable positions menu and token poll) Lush/Nora/Domi/Hush/Osci Menu Media Contact List Ticket show pre-sales Hidden Ticket Show Dice Game Gray Chat Time Lock Raffle Price Checker - ensure same price not used across features All time tippers Assign nicknames Note that I've made 3 copies of the bot, as I expect that people may want to create 2 or 3 versions that they can save for deifferent types of shows. For example, all of the tip menus and token polls may be different between a couples show, solo show, and shark week show, so by having three separate bots you can configure and save, you don't have to change the setup when you switch between shows, just swap out the bot. The primary bot is this one, secondary bots are "Dorothy's Ultra Fembot - Show 2" and "Dorothy's Ultra Fembot - Show 3". **/ // prototype functions { String.prototype.capitalize = function() { return this.charAt(0).toUpperCase() + this.slice(1); } String.prototype.repeat = function (number) { return new Array(number + 1).join(this); } String.prototype.equals = function (str) { var m = new RegExp(str); return this.match(m) != null; } String.prototype.equalsIgnoreCase = function (str) { var m = new RegExp(str, "i"); return this.match(m) != null; } } {cb.settings_choices = [ {name: 'dummy0', label: '******************* Introduction ******************** Latest Updt: 07/15/2019 (version 2.7) See Change Log. **************************************************** Welcome to Dorothy\'s Ultra Fembot, if this is your first time using the bot, you can accept all of the defaults and it will just turn on the minimum set of features such as messaging and tip tracking/leaderboard. Other features such as tip menu, token poll, notifiers, and more can be set up in future shows or turned on during the show by you or your moderator. Moderators are given significant privileges by this bot, so please make sure you assign moderators you can trust. I\'ve also setup a default tip menu, token poll, positions menu, and lush menu using prices that I find to be common, but please update these per your preference, the defaults are only suggestions! Also, you can see the full list of commands for the bot by typing "/fbhelp" in the chat (no quotes), and then also see more detailed help by section. Please enjoy using the ultrabot and feel free to say hello if you see me around, or DM me on twitter @thechelsea2950 if you have questions. Thank you! - chelsea', type: 'choice',required: false}, // *** Messages and Notifications {name: 'dummy1', label: '************ Notifications and Messages *************', type: 'choice',required: false}, {name: 'enableEntryMessage', label: 'Display notification to users when they enter?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'entryMessage', label: 'Enter the message to display', type: 'str',required: false, minLength: 1, maxLength: 1000, defaultValue: 'Welcome to my room! Please have a great time and treat your fellow chatters with kindness. Rude comments and demands will not be tolerated.'}, {name: 'enableNotifier', label: 'Would you like to periodically send a message to the room? Up to 5 messages can be displayed in rotation according to the interval specified below', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'notifierMessage1', label: 'Enter the first notification message you would like to display.',required: false, type: 'str', minLength: 1, maxLength: 1000, defaultValue: '[Update as needed] Welcome everyone to the show! Today we are doing goals with a tip menu, and the dice game is on as well!'}, {name: 'notifierMessage2', label: 'Notification Message #2', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage3', label: 'Notification Message #3', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage4', label: 'Notification Message #4', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage5', label: 'Notification Message #5', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierInterval', label: 'Notification display interval (minutes)', type: 'int', minValue: 1, maxValue: 60, defaultValue: 5}, {name: 'notifiersTextColor', label: 'Text color used for Notification Messages 1-5 and Chat Notices /cn, /cnh, /cnd, /cndh)', type: 'choice', choice1: "White/No Color",choice2: "Black",choice3: "Dark Grey",choice4: "Dark Red",choice5: "Dark Orange",choice6: "Dark Green",choice7: "Dark Aqua",choice8: "Dark Blue",choice9: "Dark Purple",choice10: "Dark Pink",choice11: "Custom",defaultValue: "Dark Aqua"}, {name: 'notifiersTextCustColor',type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix)",required: false}, {name: 'notifiersBgColor', label: 'Background highlight color used for Notification Messages 1-5 and Chat Notices (/cn, /cnh, /cnd, /cndh)', type: 'choice', choice1: "White/No Color",choice2: "Light Yellow",choice3: "Light Blue",choice4: "Light Pink",choice5: "Light Red",choice6: "Light Green",choice7: "Light Purple",choice8: "Light Orange",choice9: "Light Grey",choice10: "Light Aqua",choice11: "Custom",defaultValue: "Light Aqua"}, {name: 'notifiersBgCustColor', type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix)",required: false}, {name: 'enableTipResponse', label: 'Would you like to send an automatic response to users who tip a certain amount? Messages for up to 5 tip thresholds can be specified below', type: 'choice', choice1: 'No', choice2: 'Yes, send to tipper', choice3: 'Yes, send to all', defaultValue: 'No'}, {name: 'tipResponseAmount1',type: 'int',required: false,minValue: 1,maxValue: 1000,defaultValue: 25,label: 'Threshold 1'}, {name: 'tipResponseMessage1', label: 'Enter the Tip Response message you would like to display at the above threshold.',required: false, type: 'str', minLength: 1, maxLength: 100, defaultValue: 'Thank you for tipping!'}, {name: 'tipResponseAmount2',type: 'int',minValue: 1,maxValue: 1000,defaultValue: 100,required: false,label: 'Threshold 2'}, {name: 'tipResponseMessage2',required: false, label: 'Enter the Tip Response message you would like to display at the above threshold.', type: 'str', minLength: 1, maxLength: 100, defaultValue: 'Wow! Thank you very much for tipping!'}, {name: 'tipResponseAmount3',type: 'int',minValue: 1,maxValue: 1000,defaultValue: 250,required: false,label: 'Threshold 3'}, {name: 'tipResponseMessage3',required: false, label: 'Enter the Tip Response message you would like to display at the above threshold.', type: 'str', minLength: 1, maxLength: 100, defaultValue: 'Amazing Tip! Thank you so much for your generosity!'}, {name: 'tipResponseAmount4',type: 'int',minValue: 1,maxValue: 1000,defaultValue: 500,required: false,label: 'Threshold 4'}, {name: 'tipResponseMessage4',required: false, label: 'Enter the Tip Response message you would like to display at the above threshold.', type: 'str', minLength: 1, maxLength: 100, defaultValue: 'I am speechless! Thank you for your amazing kindness!'}, {name: 'tipResponseAmount5',type: 'int',minValue: 1,maxValue: 1000,defaultValue: 1000,required: false,label: 'Threshold 5'}, {name: 'tipResponseMessage5',required: false, label: 'Enter the Tip Response message you would like to display at the above threshold.', type: 'str', minLength: 1, maxLength: 100, defaultValue: 'OMG! All hail the king!'}, {name: 'defaultTimerDescription', label: 'Optional: Enter the description you would like to use for the general timer (/startclock function). The value will be displayed in the countdown text, and can be changed during the show with the command "/chgtimerdesc". Max length of 30 characters',required: false, type: 'str', minLength: 1, maxLength: 30}, // *** Tip Count and Leaderboard {name: 'dummy2', label: '*********** Tip Count and Leaderboard ***************', type: 'choice',required: false}, {name: 'enableSubjectChange', label: 'Allow moderators to change Room Subject. Note that if an app or bot is running that updates the room title, it will always override on next update', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'enableTipCount', label: 'Display user tip count as prefix in messages?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'enableTipLeaderIcons', label: 'Display icon for the top 3 tippers as prefix in messages? If yes, enter a value for positions 1-3 below.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'tipLeaderGif1', type: 'str',defaultValue: ':crowngold',required: false,label: 'Choose the icon to be displayed for the top tipper of the current session (optional). It can be a gif or a string of text/special characters (&!&). If using a gif, make sure to start it with the colon (:) as it would be typed in the chat'}, {name: 'tipLeaderGif2', type: 'str',defaultValue: ':mtlhfu2',required: false,label: 'Choose the icon to be displayed for the second highest tipper of the current session (optional).'}, {name: 'tipLeaderGif3', type: 'str',defaultValue: ':mtlhfu3 ',required: false,label: 'Choose the icon to be displayed for the third highest tipper of the current session (optional).'}, {name: 'enableLeaderboard', label: 'Display the leaderboard in the chat (top 5 tippers in current session)?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'leaderInterval', label: 'Leaderboard display interval (minutes)', type: 'int',required: false, minValue: 1, maxValue: 60, defaultValue: 5}, {name: 'leaderTextColor', label: 'Text color used for Leaderboard', type: 'choice', choice1: "White/No Color",choice2: "Black",choice3: "Dark Grey",choice4: "Dark Red",choice5: "Dark Orange",choice6: "Dark Green",choice7: "Dark Aqua",choice8: "Dark Blue",choice9: "Dark Purple",choice10: "Dark Pink",choice11: "Custom",defaultValue: "Dark Blue"}, {name: 'leaderTextCustColor',type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix)",required: false}, {name: 'leaderBgColor', label: 'Background color used for Leaderboard', type: 'choice', choice1: "White/No Color",choice2: "Light Yellow",choice3: "Light Blue",choice4: "Light Pink",choice5: "Light Red",choice6: "Light Green",choice7: "Light Purple",choice8: "Light Orange",choice9: "Light Grey",choice10: "Light Aqua",choice11: "Custom",defaultValue: "Light Blue"}, {name: 'leaderBgCustColor', type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom background highlight color in the previous setting, enter the hex color (6character hex color codes including the # prefix)",required: false}, {name: 'enableAllTime', label: 'Track the all time highest tippers? If tracking, please use the /alltime command before you end the bot to get the current list, and save the list, and paste it into the field below next time you start the bot. Values captured during the show cannnot be automatically saved, so the must be manually updated when the bot is stopped and started', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'allTimeInterval', label: 'All Time Tipper List display interval (minutes) if it is being tracked. Setting to "0" will disable the notice, but totals can still be tracked if enabled above, and can be displayed on demand using the command "/top10". If used, this notice is not typically displayed frquently, 30 minutes in the default.', type: 'int',required: false, minValue: 0, maxValue: 60, defaultValue: 30}, {name: 'allTimeTipperList', label: 'If tracking all time tippers, enter the list copied from the previous show. If typing in, separate the user name and total tip count with a colon (:), and put commas (,) between the entries, with no spaces. For example "name1:5000,name2:3500".', type: 'str', minLength: 1, maxLength: 3000, defaultValue: 'name1:10,name2:5', required: false}, // *** Chat Controls {name: 'dummy3', label: '*************** Chat Controls ***********************', type: 'choice',required: false}, {name: 'dummychat', label: 'For the below lists, User IDs should be separated by commas and without spaces (user1,user2,user3). The values will be saved each time you start, but please also store your lists in an external document in case the saved settings for this bot get erased or reset. Also note that users can be added in show for each, but those are not permanently saved and should be copied to this settings page to be saved for the next show.', type: 'choice',required: false}, {name: 'silenceList', label: 'Enter the names of any users you have had to repeatedly silence in the past and would like to ensure cannot chat in your room.', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'showSilencedMsgs', label: 'Show chat messages to mods and/or broadcaster for people who have been silenced using the Fembot?', type: 'choice', choice1: 'Do not show', choice2: 'Broadcaster only', choice3: 'Mods only', choice4: 'Broadcaster and Mods', defaultValue: 'Do not show'}, {name: 'ninjaList', label: 'Enter the names of any users you would like to ensure cannot chat in your room, but do not want them to be notified of being silenced. This for those users who may tip sometimes, but you really do not want to listen to their comments unles it is in a tip note.', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'showNinjadMsgs', label: 'Show chat messages to mods and/or broadcaster for people who have been ninja silenced using the Fembot?', type: 'choice', choice1: 'Do not show', choice2: 'Broadcaster only', choice3: 'Mods only', choice4: 'Broadcaster and Mods', defaultValue: 'Do not show'}, {name: 'niceList', label: 'Enter the names of any users you would like to grant voice and graphic usage privileges regardless of the silence and graphic levels (permanent nice list). These are typically gray users that do not make rude comments and demands.', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'enablePMs', label: 'Allow users to PM in chat', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'requireAnswerLevel', label: 'Require users in these categories to answer a question to chat - reduces spam. Each category accumulates the levels below it, so "Light Blue" requires both Light Blue and Gray, "Dark Blue" requires Dark Blue, Light Blue and Gray, etc.', type: 'choice', choice1: 'Not Used', choice2: 'Gray Users', choice3: 'Light Blue Users', choice4: 'Dark Blue Users', choice5: 'Light Purple Users', choice6: 'Dark Purple Users', defaultValue: 'Not Used'}, {name: 'lockGrayChat', label: 'Prevent gray chat for the first X minutes that they are in the room? If yes, set the time threshold with the next setting. This setting will usually prevent bots from posting to the chat as they do it immediately upon entering', required: false,type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'grayChatTime',type: 'int',minValue: 1,maxValue: 20,defaultValue: 5,required: false,label: 'If gray chat is locked upon entering, set the time threshold (in minutes) for when they can begin chatting.'}, {name: 'enablePMResponse', label: 'Enable PM Response: Enable or disable the automatic reponse if a non-broadcaster/mod/fan uses the word "PM" in a message. If yes, define the message in the next setting', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'pmResponseMessage',required: false, label: 'PM Response: Enter the Message you would like to display in the chat if PM response is enabled', type: 'str', minLength: 1, maxLength: 100, defaultValue: 'Broadcaster does not do PMs during the show / PMs are xx tokens, see tip menu'}, {name: 'initialSilenceLevel', type: 'int',minValue: 0,maxValue: 4,label: 'Set the initial Silence Level for the Chat to define who can chat (0=Everyone,1=Users with tokens,2=Users who have tipped,3=Users who have tipped the minimum configured tokens,4=Only Mods, Fans, VIPs)', defaultValue: 0}, {name: 'initialGraphicsLevel', type: 'int',minValue: 0,maxValue: 4,label: 'Set the initial Graphics Level for the Chat to define who can post gifs (0=Everyone,1=Users with tokens,2=Users who have tipped,3=Users who have tipped the minimum configured tokens,4=Only Mods, Fans, VIPs)', defaultValue: 1}, {name: 'botModList', label: 'Bot Mods: Enter the names of any users you would like to grant moderator privileges without assigning Chaturbate moderator status. Users in this group are granted the same permissions as the red-named moderators assigned through CB. They can be entered here or added during the show with the "/addmod" command', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'minTipToChat', type: 'int',minValue: 1,maxValue: 1000,label: 'For Silence Level and Graphic Level 3, set the minimum tip amount to allow chatting or graphics', defaultValue: 25}, // *** User Icons {name: 'dummy4', label: '*************** User Group Icons ********************', type: 'choice',required: false}, {name: 'enableGroupIcons', label: 'Enable group icons (gifs) to be displayed in front of a user name for the mod, Fanclub, external Fanclub, and VIP list groups', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'iconMods', type: 'str',defaultValue: ':heart2',required: false,label: 'Choose the personalized icon to be displayed for the moderator group of users assigned in CB with red names (optional). It can be a gif or a string of text/special characters (&!&). If using a gif, make sure to start it with the colon (:) as it would be typed in the chat'}, {name: 'iconBotMods', type: 'str',required: false,label: 'Choose the personalized icon to be displayed for the "botmod" moderator group of users that are assigned within the Fembot (optional). The group of user names can be pre-defined using the list in the previous section or added during the show with the "/addmod" command.'}, {name: 'iconFans', type: 'str',defaultValue: ':greenHeart',required: false,label: 'Choose the personalized icon to be displayed for the chaturbate fanclub group of users (optional)'}, {name: 'iconExtFans', type: 'str',defaultValue: ':fanclub-lana2',required: false,label: 'Choose the personalized icon to be displayed for the external fanclub group of users (optional)'}, {name: 'iconVIP', type: 'str',defaultValue: ':VIPCookie',required: false,label: 'Choose the personalized icon to be displayed for the VIP group of users (optional).'}, {name: 'iconNicknameList', label: 'Set the icons, nicknames, and chat text color for any users you would like to give these privileges to. Separate each of the four pieces of a user entry with a slash (/), and put commas (,) between the user entries, with no spaces. Even if no value is entered for the icon or nickname or color, use the slashes with empty values. For example "name1/:icon1/nickname1/#ff0033,name2/:icon2//,name3///#ff0033". In this example, user 1 has a personal icon, nickname and text color. User 2 has only an icon, and User 3 has only a text color. User icons should include the ":" prefix, and hex color codes should include the "#" prefix', type: 'str', minLength: 1, maxLength: 1000, defaultValue: 'name1/:icon1/nickname1/color1', required: false}, // *** VIP List {name: 'dummy5', label: '******************* VIP List ************************', type: 'choice',required: false}, {name: 'enableVIPList', label: 'Enable VIP List Privileges (PMs, Ticket Shows).', type: 'choice', choice1: 'PMs', choice2: 'Ticket Shows', choice3: 'PMs and Ticket Shows', choice4: 'None', defaultValue: 'None'}, {name: 'VIPList', label: 'Enter the names of any VIP users you would like to grant special privileges (ability to PM and free or discounted access to ticket shows). Users should be separated by a comma with no spaces', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'announceVIP', label: 'Display announcement when VIPs enter/leave the room?', type: 'choice', choice1: 'Enter Only', choice2: 'Leave Only', choice3: 'Enter or Leave', choice4: 'None', defaultValue: 'Enter Only'}, {name: 'announceVIPtext', label: 'Add any text you would like to show up as part of their entry announcement', type: 'str',defaultValue: 'Thanks for being a VIP!',required: false}, // *** External Fan Club List {name: 'dummy6', label: '*************** External Fan Club *******************', type: 'choice',required: false}, {name: 'enableExtFans', label: 'Enable External Fan Club Privileges (PMs, Ticket Shows).', type: 'choice', choice1: 'PMs', choice2: 'Ticket Shows', choice3: 'PMs and Ticket Shows', choice4: 'None', defaultValue: 'None'}, {name: 'extFanList', label: 'Enter the names of any External Fan Club members you would like to grant special privileges (ability to PM and free or discounted access to ticket shows). Users should be separated by a comma with no spaces', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'announceExtFans', label: 'Display announcement when external Fan Club members enter/leave the room?', type: 'choice', choice1: 'Enter Only', choice2: 'Leave Only', choice3: 'Enter or Leave', choice4: 'None', defaultValue: 'Enter Only'}, {name: 'announceExtFanstext', label: 'Add any text you would like to show up as part of their entry announcement', type: 'str',defaultValue: 'Thanks for being in our fanclub!',required: false}, // *** Blocked Word List {name: 'dummy7', label: '*************** Blocked Word List *******************', type: 'choice',required: false}, {name: 'enableWordList', label: 'Enable Blocked Word List.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'wordBlockList', label: 'Enter the words you would like to block in the chat. Words should be separated by a comma with no spaces.', type: 'str', minLength: 1, maxLength: 1000, defaultValue: 'cunt,bitch,slut,c2c,cumslut,chatur.,[http://sexmap.', required: false}, {name: 'showBlockedMsgs', label: 'Still show chat messages to only the broadcaster when a viewer uses blocked words?', type: 'choice', choice1: 'Do not display', choice2: 'Display to Broadcaster only', defaultValue: 'Do not display'}, {name: 'blockedLevel', label: 'Block words for which user groups?', type: 'choice', choice1: 'All Users Except Mods', choice2: 'All Users Except Mods/Fans/VIPs', choice3: 'Only Light Blue and Gray Users', choice4: 'Gray Users Only', defaultValue: 'All Users Except Mods/Fans/VIPs'}, // *** Tip Menu 1: 40 slots {name: 'dummy8', label: '****************** Tip Menu *************************', type: 'choice',required: false}, {name: 'enableTipMenu', label: 'Enable the Tip Menu at the start of the show? Note you can also turn the tip menu on and off during the show using the "/usemenu on" and "/usemenu off" commands.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'chatNotice',type: 'choice',choice1: 'Display the full menu',choice2: 'Only display the short notice',defaultValue: 'Display the full menu',label: "Do you want the notice to display the actual Tip Menu or only the short notice that users can view the menu using the command '/tipmenu'?"}, {name: 'menuDspInt',type: 'str',defaultValue: 3,required: false,label: 'Tip Menu display interval. Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.'}, {name: 'listSort',type: 'choice',choice1: 'Do not sort the list',choice2: 'Ascending',choice3: 'Descending',defaultValue: 'Ascending',label: "Sort the items in the tip menu by price?"}, {name: 'listSplit',type: 'choice',choice1: 'Do not split the list',choice2: 'Split the list in 2',defaultValue: 'Do not split the list',label: "Should the menu be split into two sections? (will only be valid if more than 8 entries)"}, {name: 'sepchar', type: 'choice',choice1: 'Vertical Bar',choice2: 'Hearts',choice3: 'Glitter',choice4: 'Flowers',choice5: 'Bow',choice6: 'Hearts2',choice7: 'Smiley',choice8: 'Text Heart',choice9: 'Text Diamond',choice10: 'Text Star',choice11: 'Custom',defaultValue: 'Vertical Bar',label: "Choose your separator character to appear between menu items. You can also use a specific gif by entering one in the next setting below, which will override this setting"}, {name: 'sepcharcustom',type: 'str',defaultValue: ':heart2',required: false,label: 'Choose your custom separator (optional). It can be a gif or a string of text/special characters (&!&). If using a gif, make sure to start it with the colon (:) as it would be typed in the chat'}, {name: 'menutxtcolor1',type: 'choice',label: 'Choose your text color for the single menu or part 1 of the split menu',required: false,choice1: "White/No Color",choice2: "Black",choice3: "Dark Grey",choice4: "Dark Red",choice5: "Dark Orange",choice6: "Dark Green",choice7: "Dark Aqua",choice8: "Dark Blue",choice9: "Dark Purple",choice10: "Dark Pink",choice11: "Custom",defaultValue: "Dark Orange"}, {name: 'menuCustTxtColor1',type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):",required: false}, {name: 'menubgcolor1',label: 'Choose the background color for the above',required: false,type: 'choice', choice1: "White/No Color",choice2: "Light Yellow",choice3: "Light Blue",choice4: "Light Pink",choice5: "Light Red",choice6: "Light Green",choice7: "Light Purple",choice8: "Light Orange",choice9: "Light Grey",choice10: "Light Aqua",choice11: "Custom",defaultValue: "White/No Color"}, {name: 'menuCustBgColor1',type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix)",required: false}, {name: 'menutxtcolor2',type: 'choice',label: 'Choose your text color for part 2 of the split menu',required: false,choice1: "White/No Color",choice2: "Black",choice3: "Dark Grey",choice4: "Dark Red",choice5: "Dark Orange",choice6: "Dark Green",choice7: "Dark Aqua",choice8: "Dark Blue",choice9: "Dark Purple",choice10: "Dark Pink",choice11: "Custom",defaultValue: "Dark Green"}, {name: 'menuCustTxtColor2',type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):",required: false}, {name: 'menubgcolor2',label: 'Choose the background color for the above',required: false,type: 'choice', choice1: "White/No Color",choice2: "Light Yellow",choice3: "Light Blue",choice4: "Light Pink",choice5: "Light Red",choice6: "Light Green",choice7: "Light Purple",choice8: "Light Orange",choice9: "Light Grey",choice10: "Light Aqua",choice11: "Custom",defaultValue: "White/No Color"}, {name: 'menuCustBgColor2',type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix)",required: false}, {name: 'menuitem1',type: 'str',required: false,defaultValue: 'If you like the show',label: 'Tip Menu Item 1'}, {name: 'menuitemprice1',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 3,required: false,label: 'Item 1 price'}, {name: 'menuitem2',type: 'str',required: false,defaultValue: 'Kiss',label: 'Tip Menu Item 2'}, {name: 'menuitemprice2',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 9,required: false,label: 'Item 2 price'}, {name: 'menuitem3',type: 'str',required: false,defaultValue: 'Makeout',label: 'Tip Menu Item 3'}, {name: 'menuitemprice3',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 21,required: false,label: 'Item 3 price'}, {name: 'menuitem4',type: 'str',required: false,defaultValue: 'Show Feet',label: 'Tip Menu Item 4'}, {name: 'menuitemprice4',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 23,required: false,label: 'Item 4 price'}, {name: 'menuitem5',type: 'str',required: false,defaultValue: '10 Jumping Jacks',label: 'Tip Menu Item 5'}, {name: 'menuitemprice5',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 27,required: false,label: 'Item 5 price'}, {name: 'menuitem6',type: 'str',required: false,defaultValue: '10 Squats',label: 'Tip Menu Item 6'}, {name: 'menuitemprice6',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 31,required: false,label: 'Item 6 price'}, {name: 'menuitem7',type: 'str',required: false,defaultValue: 'Flash Boobs',label: 'Tip Menu Item 7'}, {name: 'menuitemprice7',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 36,required: false,label: 'Item 7 price'}, {name: 'menuitem8',type: 'str',required: false,defaultValue: 'Flash Butt',label: 'Tip Menu Item 8'}, {name: 'menuitemprice8',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 38,required: false,label: 'Item 8 price'}, {name: 'menuitem9',type: 'str',required: false,defaultValue: '5 bare ass hand spanks',label: 'Tip Menu Item 9'}, {name: 'menuitemprice9',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 41,required: false,label: 'Item 9 price'}, {name: 'menuitem10',type: 'str',required: false,defaultValue: '5 paddle spanks',label: 'Tip Menu Item 10'}, {name: 'menuitemprice10',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 43,required: false,label: 'Item 10 price'}, {name: 'menuitem11',type: 'str',required: false,defaultValue: 'PM',label: 'Tip Menu Item 11'}, {name: 'menuitemprice11',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 47,required: false,label: 'Item 11 price'}, {name: 'menuitem12',type: 'str',required: false,defaultValue: 'Flash cock/pussy',label: 'Tip Menu Item 12'}, {name: 'menuitemprice12',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 56,required: false,label: 'Item 12 price'}, {name: 'menuitem13',type: 'str',required: false,defaultValue: 'Tickling',label: 'Tip Menu Item 13'}, {name: 'menuitemprice13',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 62,required: false,label: 'Item 13 price'}, {name: 'menuitem14',type: 'str',required: false,defaultValue: '1 Minute Handjob Tease',label: 'Tip Menu Item 14'}, {name: 'menuitemprice14',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 83,required: false,label: 'Item 14 price'}, {name: 'menuitem15',type: 'str',required: false,defaultValue: '1 Minute BJ Tease',label: 'Tip Menu Item 15'}, {name: 'menuitemprice15',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 85,required: false,label: 'Item 15 price'}, {name: 'menuitem16',type: 'str',required: false,defaultValue: '1 Minute Fingering Tease',label: 'Tip Menu Item 16'}, {name: 'menuitemprice16',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 87,required: false,label: 'Item 16 price'}, {name: 'menuitem17',type: 'str',required: false,defaultValue: 'Tip Menu Item 17',label: 'Tip Menu Item 17'}, {name: 'menuitemprice17',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 17 price'}, {name: 'menuitem18',type: 'str',required: false,label: 'Tip Menu Item 18'}, {name: 'menuitemprice18',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 18 price'}, {name: 'menuitem19',type: 'str',required: false,label: 'Tip Menu Item 19'}, {name: 'menuitemprice19',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 19 price'}, {name: 'menuitem20',type: 'str',required: false,label: 'Tip Menu Item 20'}, {name: 'menuitemprice20',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 20 price'}, {name: 'menuitem21',type: 'str',required: false,label: 'Tip Menu Item 21'}, {name: 'menuitemprice21',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 21 price'}, {name: 'menuitem22',type: 'str',required: false,label: 'Tip Menu Item 22'}, {name: 'menuitemprice22',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 22 price'}, {name: 'menuitem23',type: 'str',required: false,label: 'Tip Menu Item 23'}, {name: 'menuitemprice23',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 23 price'}, {name: 'menuitem24',type: 'str',required: false,label: 'Tip Menu Item 24'}, {name: 'menuitemprice24',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 24 price'}, {name: 'menuitem25',type: 'str',required: false,label: 'Tip Menu Item 25'}, {name: 'menuitemprice25',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 25 price'}, {name: 'menuitem26',type: 'str',required: false,label: 'Tip Menu Item 26'}, {name: 'menuitemprice26',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 26 price'}, {name: 'menuitem27',type: 'str',required: false,label: 'Tip Menu Item 27'}, {name: 'menuitemprice27',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 27 price'}, {name: 'menuitem28',type: 'str',required: false,label: 'Tip Menu Item 28'}, {name: 'menuitemprice28',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 28 price'}, {name: 'menuitem29',type: 'str',required: false,label: 'Tip Menu Item 29'}, {name: 'menuitemprice29',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 29 price'}, {name: 'menuitem30',type: 'str',required: false,label: 'Tip Menu Item 30'}, {name: 'menuitemprice30',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 30 price'}, {name: 'menuitem31',type: 'str',required: false,label: 'Tip Menu Item 31'}, {name: 'menuitemprice31',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 31 price'}, {name: 'menuitem32',type: 'str',required: false,label: 'Tip Menu Item 32'}, {name: 'menuitemprice32',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 32 price'}, {name: 'menuitem33',type: 'str',required: false,label: 'Tip Menu Item 33'}, {name: 'menuitemprice33',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 33 price'}, {name: 'menuitem34',type: 'str',required: false,label: 'Tip Menu Item 34'}, {name: 'menuitemprice34',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 34 price'}, {name: 'menuitem35',type: 'str',required: false,label: 'Tip Menu Item 35'}, {name: 'menuitemprice35',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 35 price'}, {name: 'menuitem36',type: 'str',required: false,label: 'Tip Menu Item 36'}, {name: 'menuitemprice36',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 36 price'}, {name: 'menuitem37',type: 'str',required: false,label: 'Tip Menu Item 37'}, {name: 'menuitemprice37',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 37 price'}, {name: 'menuitem38',type: 'str',required: false,label: 'Tip Menu Item 38'}, {name: 'menuitemprice38',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 38 price'}, {name: 'menuitem39',type: 'str',required: false,label: 'Tip Menu Item 39'}, {name: 'menuitemprice39',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 39 price'}, {name: 'menuitem40',type: 'str',required: false,label: 'Tip Menu Item 40'}, {name: 'menuitemprice40',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 40 price'}, // *** Tip Menu 2: 20 slots {name: 'dummymenu2', label: '***************** Tip Menu 2 ***********************', type: 'choice',required: false}, {name: 'enableTipMenu2', label: 'Enable Tip Menu #2 at the start of the show? Note you can also turn the tip menu on and off during the show using the "/usemenu2 on" and "/usemenu2 off" commands, or you can switch between menu 1 and menu 2 with the /swapmenu command. Menu 2 uses the same general settings defined above for Menu 1 (interval, color, separator), it is the menu options that are unique.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'menu2item1',type: 'str',required: false,label: 'Tip Menu 2 Item 1'}, {name: 'menu2itemprice1',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 1 price'}, {name: 'menu2item2',type: 'str',required: false,label: 'Tip Menu 2 Item 2'}, {name: 'menu2itemprice2',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 2 price'}, {name: 'menu2item3',type: 'str',required: false,label: 'Tip Menu 2 Item 3'}, {name: 'menu2itemprice3',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 3 price'}, {name: 'menu2item4',type: 'str',required: false,label: 'Tip Menu 2 Item 4'}, {name: 'menu2itemprice4',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 4 price'}, {name: 'menu2item5',type: 'str',required: false,label: 'Tip Menu 2 Item 5'}, {name: 'menu2itemprice5',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 5 price'}, {name: 'menu2item6',type: 'str',required: false,label: 'Tip Menu 2 Item 6'}, {name: 'menu2itemprice6',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 6 price'}, {name: 'menu2item7',type: 'str',required: false,label: 'Tip Menu 2 Item 7'}, {name: 'menu2itemprice7',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 7 price'}, {name: 'menu2item8',type: 'str',required: false,label: 'Tip Menu 2 Item 8'}, {name: 'menu2itemprice8',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 8 price'}, {name: 'menu2item9',type: 'str',required: false,label: 'Tip Menu 2 Item 9'}, {name: 'menu2itemprice9',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 9 price'}, {name: 'menu2item10',type: 'str',required: false,label: 'Tip Menu 2 Item 10'}, {name: 'menu2itemprice10',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 10 price'}, {name: 'menu2item11',type: 'str',required: false,label: 'Tip Menu 2 Item 11'}, {name: 'menu2itemprice11',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 11 price'}, {name: 'menu2item12',type: 'str',required: false,label: 'Tip Menu 2 Item 12'}, {name: 'menu2itemprice12',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 12 price'}, {name: 'menu2item13',type: 'str',required: false,label: 'Tip Menu 2 Item 13'}, {name: 'menu2itemprice13',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 13 price'}, {name: 'menu2item14',type: 'str',required: false,label: 'Tip Menu 2 Item 14'}, {name: 'menu2itemprice14',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 14 price'}, {name: 'menu2item15',type: 'str',required: false,label: 'Tip Menu 2 Item 15'}, {name: 'menu2itemprice15',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 15 price'}, {name: 'menu2item16',type: 'str',required: false,label: 'Tip Menu 2 Item 16'}, {name: 'menu2itemprice16',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 16 price'}, {name: 'menu2item17',type: 'str',required: false,label: 'Tip Menu 2 Item 17'}, {name: 'menu2itemprice17',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 17 price'}, {name: 'menu2item18',type: 'str',required: false,label: 'Tip Menu 2 Item 18'}, {name: 'menu2itemprice18',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 18 price'}, {name: 'menu2item19',type: 'str',required: false,label: 'Tip Menu 2 Item 19'}, {name: 'menu2itemprice19',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 19 price'}, {name: 'menu2item20',type: 'str',required: false,label: 'Tip Menu 2 Item 20'}, {name: 'menu2itemprice20',type: 'int',minValue: 0,maxValue: 99999,required: false,label: 'Item 20 price'}, // *** Positions Tip Menu {name: 'dummy9', label: '**************** Positions Menu *********************', type: 'choice',required: false}, {name: 'enablePosTipMenu', label: 'Enable the Positions Tip Menu at the start of the show? Note you can also turn the positions tip menu on and off during the show using the "/useposmenu on" and "/useposmenu off" commands.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'posMenuInterval',type: 'str',defaultValue: 3,required: false,label: 'Positions Tip Menu display interval. Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.'}, {name: 'posListSort',type: 'choice',choice1: 'Do not sort the list',choice2: 'Ascending',choice3: 'Descending',defaultValue: 'Ascending',label: "Sort the items in the positions menu by price?"}, {name: 'posSepChar', type: 'choice',choice1: 'Vertical Bar',choice2: 'Hearts',choice3: 'Glitter',choice4: 'Flowers',choice5: 'Bow',choice6: 'Hearts2',choice7: 'Smiley',choice8: 'Text Heart',choice9: 'Text Diamond',choice10: 'Text Star',choice11: 'Custom',defaultValue: 'Vertical Bar',label: "Choose your separator character to appear between menu items. You can also use a specific gif by entering one in the next setting below, which will override this setting."}, {name: 'posSepCharCustom',type: 'str',defaultValue: ':heart2',required: false,label: 'Choose your custom separator (optional). It can be a gif or a string of text/special characters (&!&). If using a gif, make sure to start it with the colon (:) as it would be typed in the chat'}, {name: 'posMenuTxtColor',type: 'choice',label: 'Choose your text color for the positions menu',required: false,choice1: "White/No Color",choice2: "Black",choice3: "Dark Grey",choice4: "Dark Red",choice5: "Dark Orange",choice6: "Dark Green",choice7: "Dark Aqua",choice8: "Dark Blue",choice9: "Dark Purple",choice10: "Dark Pink",choice11: "Custom",defaultValue: "Dark Pink"}, {name: 'posMenuCustTxtColor',type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):",required: false}, {name: 'posMenuBgColor',label: 'Choose your background color for the positions menu',required: false,type: 'choice', choice1: "White/No Color",choice2: "Light Yellow",choice3: "Light Blue",choice4: "Light Pink",choice5: "Light Red",choice6: "Light Green",choice7: "Light Purple",choice8: "Light Orange",choice9: "Light Grey",choice10: "Light Aqua",choice11: "Custom",defaultValue: "Light Pink"}, {name: 'posMenuCustBgColor',type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):",required: false}, {name: 'posMenuItem1',type: 'str',required: false,defaultValue: 'Missionary',label: "Positions Tip Menu Item 1 "}, {name: 'posMenuItemPrice1',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 101,required: false,label: 'Positions Item 1 price'}, {name: 'posMenuItem2',type: 'str',required: false,defaultValue: 'Doggy Style',label: 'Positions Tip Menu Item 2'}, {name: 'posMenuItemPrice2',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 107,required: false,label: 'Positions Item 2 price'}, {name: 'posMenuItem3',type: 'str',required: false,defaultValue: 'Doggy Style POV',label: 'Positions Tip Menu Item 3'}, {name: 'posMenuItemPrice3',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 109,required: false,label: 'Positions Item 3 price'}, {name: 'posMenuItem4',type: 'str',required: false,defaultValue: 'Cowgirl facing cam',label: 'Positions Tip Menu Item 4'}, {name: 'posMenuItemPrice4',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 112,required: false,label: 'Positions Item 4 price'}, {name: 'posMenuItem5',type: 'str',required: false,defaultValue: 'Cowgirl, back to cam',label: 'Positions Tip Menu Item 5'}, {name: 'posMenuItemPrice5',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 104,required: false,label: 'Positions Item 5 price'}, {name: 'posMenuItem6',type: 'str',required: false,defaultValue: 'Reverse cowgirl facing cam',label: 'Positions Tip Menu Item 6'}, {name: 'posMenuItemPrice6',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 115,required: false,label: 'Positions Item 6 price'}, {name: 'posMenuItem7',type: 'str',required: false,defaultValue: 'Spooning',label: 'Positions Tip Menu Item 7'}, {name: 'posMenuItemPrice7',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 106,required: false,label: 'Positions Item 7 price'}, {name: 'posMenuItem8',type: 'str',required: false,defaultValue: 'Prone Bone (face down from behind)',label: 'Positions Tip Menu Item 8'}, {name: 'posMenuItemPrice8',type: 'int',minValue: 0,maxValue: 99999,defaultValue: 108,required: false,label: 'Positions Item 8 price'}, // *** Token Poll {name: 'dummy10', label: '******************* Token Poll **********************', type: 'choice',required: false}, {name: 'enableTokenPoll', label: 'Enable the Token Poll at start of show? Note you can also turn the token poll on and off during the show using the "/usepoll on" and "/usepoll off" commands.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: "pollTitle",type: "str",required: false,minLength: 1,maxLength: 255,label: "Poll Title (what will people be voting for?)"}, {name: "pollInterval",type: "int",required: false,minValue: 1,maxValue: 15,defaultValue: 2,label: "Display Interval for Token Poll vote summary (in minutes)"}, {name: "pollMode",type: "choice",label: "Type of Poll - will it be ended manually by the mod or broadcaster (default), use a timer, or go until a certain number of total votes or votes for one choice?",choice1: 'Ends by Mod/Broadcaster command',choice2: 'Ends after X minutes',choice3: 'Ends after X votes',choice4: 'Ends when one option reaches X votes',defaultValue: 'Ends by Mod/Broadcaster command'}, {name: "pollCount",type: "int",required: false,minValue: 1,defaultValue: 1,label: "Per above choice for Poll Type, choose value for X (in minutes or votes) "}, {name: "pollMinimum",type: "int",minValue: 1,maxValue: 50,defaultValue: 1,required: false, label: "Minimum total votes required to make the poll valid? Set to '1' to not require a minimum"}, {name: "pollTxtColor",type: "choice",label: "Poll text color",choice1: "White/No Color",choice2: "Black",choice3: "Dark Grey",choice4: "Dark Red",choice5: "Dark Orange",choice6: "Dark Green",choice7: "Dark Aqua",choice8: "Dark Blue",choice9: "Dark Purple",choice10: "Dark Pink",choice11: "Custom",defaultValue: "Dark Green"}, {name: "pollCustTxtColor",type: "str",minLength: 1,maxLength: 7,label: "If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):",required: false}, {name: "pollBgColor",label: "Poll background color",type: 'choice', choice1: "White/No Color",choice2: "Light Yellow",choice3: "Light Blue",choice4: "Light Pink",choice5: "Light Red",choice6: "Light Green",choice7: "Light Purple",choice8: "Light Orange",choice9: "Light Grey",choice10: "Light Aqua",choice11: "Custom",defaultValue: "Light Green"}, {name: "pollCustBgColor",type: "str",minLength: 1,maxLength: 7,label: "If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):",required: false}, {name: "pollFanClubDouble",type: "choice",choice1: "Yes",choice2: "No",defaultValue: "No",label: "Fan club members vote counts double?"}, {name: "pollKeepalive",type: "choice",choice1: "Yes",choice2: "No",defaultValue: "No",label: "When using a Poll Timer, when the timer remaining drops below 30 seconds, keep the poll alive by adding 30 more seconds if people are tipping?"}, {name: "pollModAdd",type: "choice",choice1: "Yes",choice2: "No",defaultValue: "Yes",label: "Allow a moderator to add or remove votes?"}, {name: 'dummypoll', label: 'For Poll options below, you can configure up to 8 voting options below by setting the name of the choice and the associated price. Please ensure the price does not overlap with other menu options, ticket show prices, etc.', type: 'choice',required: false}, {name: "pollOptLabel1",type: "str",minLength: 1,maxLength: 50,defaultValue: 'On Boobs',label: "Option 1",required: false}, {name: "pollOptTokens1",type: "int",minValue: 1,defaultValue: 11,label: "Option 1 tokens",required: false}, {name: "pollOptLabel2",type: "str",minLength: 1,maxLength: 50,defaultValue: 'On Butt',label: "Option 2",required: false}, {name: "pollOptTokens2",type: "int",minValue: 1,defaultValue: 12,label: "Option 2 tokens",required: false}, {name: "pollOptLabel3",type: "str",minLength: 1,maxLength: 50,defaultValue: 'On Pussy',label: "Option 3",required: false}, {name: "pollOptTokens3",type: "int",minValue: 1,defaultValue: 13,label: "Option 3 tokens",required: false}, {name: "pollOptLabel4",type: "str",minLength: 1,maxLength: 50,defaultValue: 'Creampie',label: "Option 4",required: false}, {name: "pollOptTokens4",type: "int",minValue: 1,defaultValue: 14,label: "Option 4 tokens",required: false}, {name: "pollOptLabel5",type: "str",minLength: 1,maxLength: 50,defaultValue: 'Mouth/Swallow',label: "Option 5",required: false}, {name: "pollOptTokens5",type: "int",minValue: 1,defaultValue: 16,label: "Option 5 tokens",required: false}, {name: "pollOptLabel6",type: "str",minLength: 1,maxLength: 50,defaultValue: 'Facial',label: "Option 6",required: false}, {name: "pollOptTokens6",type: "int",minValue: 1,defaultValue: 17,label: "Option 6 tokens",required: false}, {name: "pollOptLabel7",type: "str",minLength: 1,maxLength: 50,label: "Option 7",required: false}, {name: "pollOptTokens7",type: "int",minValue: 1,label: "Option 7 tokens",required: false}, {name: "pollOptLabel8",type: "str",minLength: 1,maxLength: 50,label: "Option 8",required: false}, {name: "pollOptTokens8",type: "int",minValue: 1,label: "Option 8 tokens",required: false}, // *** General Ticket Show Settings {name: 'dummyticket', label: '******************* Ticket Shows ******************** This bot contains its own hidden ticket show feature, and also support certain interactions with separate ticekt apps such as Dorothy\'s UltraApp and Dorothy\'s Ticket Show. The "prepticket" and "ticket pre-sales" features can be used with either type of show. The backup ticket list feature is specific to using an external ticket App. While the ticket show feature is available in the Fembot, it is always recommended to use an App for ticket shows. IMPORTANT: Do not enable the ticket show both an external App and Fembot at the same time, it will cause issues with hidden cam access.', type: 'choice',required: false}, {name: 'ticketShowType', label: 'Which app/bot will you be using for the ticket show? While a ticket show feature is available here in the Fembot, Dorothy\'s UltraApp (which also has multiple types of goal shows), or Dorothy\'s Ticket App are recommended, since an app provides better functionality for tracking ticket sales progress. If using the Fembot ticket show, complete the next section ("Fembot Ticket Shows"); if using a separate ticket show app, complete this section below for some optional features that can be used alongside the Ticket App', type: 'choice', choice1: 'Fembot Ticket Show', choice2: 'Separate Ticket App', defaultValue: 'Separate Ticket App'}, {name: 'prepticketTipMenuOff', label: 'Enable the /prepticket command to turn off the Tip Menu if currently on?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'prepticketPosMenuOn', label: 'Enable the /prepticket command to turn on the Positions Tip Menu if currently off?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'prepticketStartPoll', label: 'Enable the /prepticket command to start the Token Poll if currently off?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'prepticketStopPresale', label: 'Enable the /prepticket command to turn off the Pre-sales feature if currently on?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'prepticketAddPresales', label: 'Enable the /prepticket command to automatically add Pre-Sale Ticket holders to the ticket show?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'prepticketAddVIP', label: 'Enable the /prepticket command to add VIP Members to the ticket show (if granted ticket show privileges)?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'prepticketAddExtFC', label: 'Enable the /prepticket command to add External Fan Club Members to the ticket show (if granted ticket show privileges)?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'startPollTimerWithShow', label: 'A common approach when using a poll in combination with a ticket show is to initially start the Poll under "Manual End" mode before the show and then once the show is started, also start a countdown for the poll. This setting controls whether the /startshow command will also switch the poll to Timer mode, and the next setting below defines the length of the timer.', type: 'choice', choice1: 'Yes, switch to timed poll at show start', choice2: 'No, do not change poll', defaultValue: 'No, do not change poll'}, {name: 'startPollMinAfterShow',type: 'int', minValue: 1, maxValue: 60,required: false, defaultValue: 10,label: 'If the above setting switches the Poll to "Timer" mode, define the number of minutes to use for the poll timer after /startshow'}, {name: 'endPosMenuWithShow', label: 'Turn off the Positions menu when the show is finished (either /showend or /stopshow will end it)', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'ticketModAdd', label: 'Allow moderators to use the commands to add top tippers to the Ticket Show.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'numberFromLB',type: 'int',minValue: 1,maxValue: 10,required: false, defaultValue: 3,label: 'Number of entries from the top of the leaderboard to add to a ticket show (Top 3, Top 5, etc). Defaults to Top 3 if not set. Set this number or the minimum tip amount to add.'}, {name: 'amountFromLB',type: 'str',minLength: 1,maxLength: 6,required: false, defaultValue: 1000,label: 'Minimum total tip amount to be used to grant a free ticket to a ticket show. Defaults to 1000 if not set. Set this number or the number of top tippers.'}, {name: 'enablePresales', label: 'Perform pre-sales in Fembot? If pre-sales are to be performed in Dorothy\'s UltraApp, set this to "No".', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'enablePresalesMode', label: 'Ticket show pre-sales mode to use at the start of the broadcast? Note you can also enable and disable presales during the broadcast using the "/usepresale on" and "/usepresale off" commands. You can also change the mode using the command "/chgpresalemode [mode]". Using pre-sales will automatically turn on the backup ticket list and use the pre-sale price as the backup price. There are three modes available, with further settings below for the automated modes. If the Hidden Show feature (above) is enabled, pre-sales will automatically be disabled regardless of this setting', type: 'choice', choice1: 'No Pre-sales', choice2: 'Yes, Mode 1: Increment Manually', choice3: 'Yes, Mode 2: Increment on X Tickets Sold',choice4: 'Yes, Mode 3: Increment on Automatic Timer',defaultValue: 'No Pre-sales'}, {name: 'presaleCountIncrement',type: 'int',minValue: 1,maxValue: 50,required: false,defaultValue: 10,label: 'Mode 2: If setting an automatic increment per number of tickets sold, indicate the number of tickets to be sold in each increment here. After this number are sold, price will increase by the amount specified in the later setting.'}, {name: 'presaleTimedIncrement',type: 'int',minValue: 1,maxValue: 50,required: false,defaultValue: 15,label: 'Mode 3: If setting an automatic timer increment, this is the number of minutes for the timer. Timer will recycle and continue incrementing until limit is reached, or next increment would exceed the planned ticket show price. After each cycle of the timer expires, the price will automatically increase by the amount specified in the below setting.'}, {name: 'presaleIncreasePerIncrement',type: 'int',minValue: 1,maxValue: 100,required: false,defaultValue: 10,label: 'If setting an automatic increment by timer or number of tickets sold, indicate the increment in ticket price for each occurrence. This means every [X] minutes (defined in previous setting), the price will go up by the number of tokens defined here, or if selling by count, once all tickets have been sold at the current price, the price will increment by this amount. Note that the price will never increment above the defined ticket price above.'}, {name: 'presaleMaxIncrements',type: 'int',minValue: 1,maxValue: 10,required: false,defaultValue: 3,label: 'When using mode 2 or mode 3 for an automatic increment, this is the maximum number of increments before the presale stops increments. Once it reaches this point (or next increment would exceed the planned ticket price), the price stops incrementing and pre-sales will continue at the same price until they are ended.'}, {name: 'initialPresalePrice',type: 'int',minValue: 1,maxValue: 1000,required: false,defaultValue: 45,label: 'If the ticket show pre-sales are performed in the Fembot, use this price as the initial pre-sale price. The pre-sale price can also be updated during show with the command "/presaleprice xx" where xx is the new price.'}, {name: 'presaleNoticeInterval',type: 'int',minValue: 1,maxValue: 15,required: false,defaultValue: 2,label: 'Display Interval for generic Ticket Show Pre-sales notice (in minutes). This notice just alerts the room that a pre-sale is active, regardless of mode'}, {name: 'ticketShowPrice',label: 'If the ticket show will be in the External App, such as Dorothy\'s UltraApp or Dorothy\'s Ticket Show, set the price here for the initial price to use for the backup list. All tips in excess of this amount will add someone to the Back-up ticket list in case you lose the ticket list in the App. The value will be updated automaticllay whenever the presales price or ticket price is update with a command, but will not update if there is an automatic presale price increment. The command "/backupprice xx" can be used for that purpose.',type: 'int',minValue: 1,maxValue: 1000,required: false, defaultValue: 69}, // *** Fembot Hidden Show {name: 'dummyhidden', label: '************** Fembot Ticket Shows *****************', type: 'choice',required: false}, {name: 'enableHiddenShow', label: 'Enable the Hidden Show feature at the beginning of the broadcast? The Hidden Show can be enabled later using the "/usehiddenshow on" command. Note that if the Ticket show type is set to "CrazyTicket", the Fembot Ticket Show feature will not start.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'hiddenShowDescription', label: 'Description of the show (optional)', type:'str',minLength: 1,maxLength: 100,required: false,defaultValue: 'Hidden Sex Show! Token Poll for cumshot!'}, {name: 'hiddenShowStartMode', label: 'Which mode is used for determining when to start the show? This setting works in combination with the next setting to define what will trigger the start of show, and whether it starts automatically', type: 'choice', choice1: 'Start Show Anytime', choice2: 'Start Show after Timer', choice3: 'Start Show after Ticket Goal', choice4: 'Start Show after Token Goal', defaultValue: 'Start Show Anytime'}, {name: 'hiddenShowStartAuto', label: 'If using a timer or goal to determine start of show, does the Broadcaster (or moderator) start the show manually with the /startshow command, or does the show start automatically when time runs out or goal is reached?', type: 'choice', choice1: 'Start from Command', choice2: 'Automated Start', defaultValue: 'Start from Command'}, {name: 'hiddenShowGoal', label: 'If using a goal for the total sales before starting the show of either total number of tickets or toals tips, set goal amount here (in terms of tickets or tokens based on type of goal)', type: 'int',minValue: 1,maxValue: 5000,defaultValue: 1000,required: false}, {name: 'hiddenShowStartTimer', label: 'If the start mode is set for using an automatic timer, define the number of minutes for the countdown to show start here. Timer will start immediately upon starting the broadcast, or when the Hidden Ticket Show feature is turned on later.', type: 'int',minValue: 1,maxValue: 120,defaultValue: 15,required: false}, {name: 'hiddenShowPrice', label: 'Price for a ticket to the show. The Hidden Show feature cannot be enabled without a price defined. Discounted prices for certain user groups are defined below', type: 'int',minValue: 1,maxValue: 300,defaultValue: 69,required: false}, {name: 'hiddenShowPriceFC', label: 'Price for a ticket to the show for CB Fan Club members. This is overridden if the later setting grants them a free ticket.', type: 'int',minValue: 1,maxValue: 300,defaultValue: 35,required: false}, {name: 'hiddenShowPriceEFC', label: 'Price for a ticket to the show for External Fan Club members. This is overridden if the previous setting in the External Fan Club section grants them a free ticket privileges.', type: 'int',minValue: 1,maxValue: 300,defaultValue: 35,required: false}, {name: 'hiddenShowPriceVIP', label: 'Price for a ticket to the show for VIP List members. This is overridden if the previous setting in the VIP List section grants them a free ticket privileges', type: 'int',minValue: 1,maxValue: 300,defaultValue: 35,required: false}, {name: 'hiddenShowFreeFC', label: 'Give a free ticket to CB Fanclub members?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'hiddenShowFreeMods', label: 'Give a free ticket to moderators?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'hiddenShowCumulative', label: 'Once ticket sales have started (including pre-sales if used), accumulate tips toward ticket price? -- Recommend set to "Yes" to avoid need for many manual adds. If set to "No", user can only tip the ticket amount or higher to be added.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'enableHiddenShowOT', label: 'Enable Outstanding Ticket feature so users can save their ticket for use in a later show. Note that the broadcaster must still record the user names and enter them in the OTS list below. Can also be used for granting free tickets to viewers for a future show in place of a refund if there was a problem with a show, or user bought at the last second and missed the show.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'hiddenShowOTList', label: 'If the Outstanding Ticket feature is enabled above, enter the names of any viewers you would like to grant a ticket to a future show. The user will be notified when they enter that they have a free ticket, and if they choose to use it, the broadcaster is notified so they can remove them from the list before next show', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'hiddenShowModsAdd', label: 'Allow moderators to use the /addticket command to add themselves and others to the show? Note this will allow them to add themselves even if the above setting for giving them a free ticket is set to "No"', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'hiddenShowModsChgPrice', label: 'Allow moderators to change the price of a ticket?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'ticketNoticeInterval',type: 'str',required: false,defaultValue: 3,label: 'Display interval for the notice that the Fembot Ticket show sales are active. Decimals are ok as long as they are greater than 1. The notice will include stats on the ticket sales and change between the two below messages once the broadcast is hidden.'}, {name: 'hiddenShowPreNotice', label: 'Message to display in the Notice during ticket sales', type:'str',minLength: 1,maxLength: 100,required: false,defaultValue: 'Hidden Sex Show starts soon! There will be a Token Poll for cumshot!'}, {name: 'hiddenShowNotice', label: 'Message to display in the Notice once the show has started', type:'str',minLength: 1,maxLength: 100,required: false,defaultValue: 'Hidden Sex Show in progress! Vote in the Token Poll for cumshot!'}, {name: 'afterShowNotice', label: 'Message to display in the Room Subject and Notice after the show has ended', type:'str',minLength: 1,maxLength: 100,required: false,defaultValue: 'After show hangout, please follow us on twitter @yourusername.'}, {name: 'hiddenShowReducePriceWarn', label: 'Reduce Ticket Price by this amount when the /showwarn command is used to indicate the show is nearly over. Set to 0 to not use this feature', type: 'int',minValue: 0,maxValue: 300,defaultValue: 0,required: false}, {name: 'hiddenShowAllowGift', label: 'Allow users to buy additional tickets they can use as gifts to other users', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, // *** Lush/Domi/Nora Tip Menu {name: 'dummy12', label: '********* Lush/Domi/Nora/Osci/Hush Tip Menu **********', type: 'choice',required: false}, {name: 'enableLushMenu', label: 'Enable the Toy Tip Menu at the start of the show? Note you can also turn the menu on and off during the show using the "/uselushmenu on" and "/uselushmenu off" commands. Also, this only displays the lush tipping options, it does not control the lush itself, that is done through the lush app. You can also use the chrome extension to publish the lush config directly to the chat in place of this menu.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'lushMenuInterval',type: 'str',required: false,defaultValue: 3,label: 'Toy Tip Menu display interval. Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.'}, {name: 'whichToy', label: 'Which toy is being used? The menu title is updated to reflect the toy', type: 'choice', choice1: 'Lush', choice2: 'Nora', choice3: 'Domi', choice4: 'Hush', choice5: 'Osci', defaultValue: 'Lush'}, {name: 'lushMenuTxtColor',type: 'choice',label: 'Choose your text color for the Toy menu',choice1: "White/No Color",choice2: "Black",choice3: "Dark Grey",choice4: "Dark Red",choice5: "Dark Orange",choice6: "Dark Green",choice7: "Dark Aqua",choice8: "Dark Blue",choice9: "Dark Purple",choice10: "Dark Pink",choice11: "Custom",defaultValue: "Dark Pink"}, {name: 'lushMenuCustTxtColor',type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):",required: false}, {name: 'lushMenuBgColor',label: 'Choose your background color for the Toy menu',type: 'choice', choice1: "White/No Color",choice2: "Light Yellow",choice3: "Light Blue",choice4: "Light Pink",choice5: "Light Red",choice6: "Light Green",choice7: "Light Purple",choice8: "Light Orange",choice9: "Light Grey",choice10: "Light Aqua",choice11: "Custom",defaultValue: "Light Pink"}, {name: 'lushMenuCustBgColor',type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):",required: false}, {name: 'dummy13', label: 'Lush Level Heading only: Use the default as a template and set the text in the options below to match the configuration in the lush control panel, leave an entry blank to skip display of a level', type: 'choice',required: false}, {name: 'lushMenuLevel1',type: 'str',label: "Level 1 Message",defaultValue: 'Level 1 (Tip 1-14) : 5 seconds on LOW vibrations',required: false}, {name: 'lushMenuLevel2',type: 'str',label: "Level 2 Message",defaultValue: 'Level 2 (Tip 15-30) : 5 seconds on MEDIUM vibrations',required: false}, {name: 'lushMenuLevel3',type: 'str',label: "Level 3 Message",defaultValue: 'Level 3 (Tip 31-49) : 10 seconds on MEDIUM vibrations',required: false}, {name: 'lushMenuLevel4',type: 'str',label: "Level 4 Message",defaultValue: 'Level 4 (Tip 50-74) : 15 seconds on MEDIUM vibrations',required: false}, {name: 'lushMenuLevel5',type: 'str',label: "Level 5 Message",defaultValue: 'Level 5 (Tip 75-99) : 30 seconds on HIGH vibrations',required: false}, {name: 'lushMenuLevel6',type: 'str',label: "Level 6 Message",defaultValue: 'Level 6 (Tip 100-249): 30 seconds on HIGH vibrations',required: false}, {name: 'lushMenuLevel7',type: 'str',label: "Level 7 Message",defaultValue: 'Level 7 (Tip 250-499): 1 Minute on HIGH vibrations',required: false}, {name: 'lushMenuLevel8',type: 'str',label: "Level 8 Message",defaultValue: 'Level 8 (Tip 500+) : 5 Minutes on HIGH vibrations',required: false}, {name: 'lushMenuLevel9',type: 'str',label: "Random Level Message",defaultValue: 'Random Level - Tip 70 to get a random level!',required: false}, {name: 'lushMenuLevel10',type: 'str',label: "Pattern Level 1 Message",defaultValue: 'Pattern 1 - Tip 115 for a wave pattern for 30 seconds',required: false}, {name: 'lushMenuLevel11',type: 'str',label: "Pattern Level 2 Message",defaultValue: 'Pattern 2 - Tip 116 for a block wave pattern for 30 seconds',required: false}, {name: 'lushMenuLevel12',type: 'str',label: "Pattern Level 3 Message",defaultValue: 'Pattern 3 - Tip 117 for a pulse pattern for 30 seconds',required: false}, {name: 'lushMenuLevel13',type: 'str',label: "Pattern Level 4 Message",defaultValue: 'Pattern 4 - Tip 118 for a constant high pattern for 30 seconds',required: false}, // *** Media Platforms {name: 'dummy14', label: '****************** Media List ************************', type: 'choice',required: false}, {name: 'enableMediaNotice',label: 'Enable the posting of your contact info and media platforms detailed below? Note you can also turn the notice on and off during the show using the "/usemedia on" and "/usemedia off" commands.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'mediaListInterval',type: 'int',minValue: 1,maxValue: 15,required: false, defaultValue: 5,label: 'Time interval for displaying the Media List'}, {name: 'mediaListIntro',type: 'str',minLength: 1,maxLength: 255,label: "Enter the Text you would like to show at the beginning of the media list to introduce the list to the user",required: false, defaultValue: 'Contact info is below for scheduling privates, shopping on amazon wishlist, and staying in touch through my various social media platforms:'}, {name: 'mediaListTxtColor',type: 'choice',label: 'Choose your text color for the Media List',choice1: "White/No Color",choice2: "Black",choice3: "Dark Grey",choice4: "Dark Red",choice5: "Dark Orange",choice6: "Dark Green",choice7: "Dark Aqua",choice8: "Dark Blue",choice9: "Dark Purple",choice10: "Dark Pink",choice11: "Custom",defaultValue: "Dark Pink"}, {name: 'mediaListCustTxtColor',type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):",required: false}, {name: 'mediaListBgColor',label: 'Choose your background color for the Media List',type: 'choice', choice1: "White/No Color",choice2: "Light Yellow",choice3: "Light Blue",choice4: "Light Pink",choice5: "Light Red",choice6: "Light Green",choice7: "Light Purple",choice8: "Light Orange",choice9: "Light Grey",choice10: "Light Aqua",choice11: "Custom",defaultValue: "Light Pink"}, {name: 'mediaListCustBgColor',type: 'str',minLength: 1,maxLength: 7,label: "If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):",required: false}, {name: 'dummymedia', label: 'Default values are provided as an example, feel free to use the default gifs (such as :twitter_30x30) or find or create your own. You can put the gif in the description or the value. Please blank out lines you are not planning to use.', type: 'choice',required: false}, {name: 'mediaListText1',type: 'str',label: "Text for Item 1",defaultValue: 'E-mail Address',required: false}, {name: 'mediaListItem1',type: 'str',label: "Item 1",defaultValue: 'abc@email.com',required: false}, {name: 'mediaListText2',type: 'str',label: "Text for Item 2",defaultValue: 'Personal Website',required: false}, {name: 'mediaListItem2',type: 'str',label: "Item 2",defaultValue: 'http://abc.web.com',required: false}, {name: 'mediaListText3',type: 'str',label: "Text for Item 3",defaultValue: 'Twitter ID',required: false}, {name: 'mediaListItem3',type: 'str',label: "Item 3",defaultValue: ':twitter_30x30 @Twitter',required: false}, {name: 'mediaListText4',type: 'str',label: "Text for Item 4",defaultValue: 'Instagram ID',required: false}, {name: 'mediaListItem4',type: 'str',label: "Item 4",defaultValue: ':inst_30x30 @Instagram',required: false}, {name: 'mediaListText5',type: 'str',label: "Text for Item 5",defaultValue: 'Public Snapchat ID',required: false}, {name: 'mediaListItem5',type: 'str',label: "Item 5",defaultValue: ':snapchat_30x30 @snapID',required: false}, {name: 'mediaListText6',type: 'str',label: "Text for Item 6",defaultValue: 'Amazon Wishlist',required: false}, {name: 'mediaListItem6',type: 'str',label: "Item 6",defaultValue: ':AmazonWLSml http://amazon.com/user',required: false}, {name: 'mediaListText7',type: 'str',label: "Text for Item 7",defaultValue: 'Video sales site',required: false}, {name: 'mediaListItem7',type: 'str',label: "Item 7",defaultValue: 'link to site',required: false}, {name: 'mediaListText8',type: 'str',label: "Text for Item 8",defaultValue: 'External Fan Club',required: false}, {name: 'mediaListItem8',type: 'str',label: "Item 8",defaultValue: 'fanclub_30x30 http://fancentro.com/user',required: false}, {name: 'mediaListText9',type: 'str',label: "Text for Item 9",defaultValue: 'Misc Link 1',required: false}, {name: 'mediaListItem9',type: 'str',label: "Item 9",defaultValue: 'Insert Link 1',required: false}, {name: 'mediaListText10',type: 'str',label: "Text for Item 10",defaultValue: 'Misc Link 2',required: false}, {name: 'mediaListItem10',type: 'str',label: "Item 10",defaultValue: 'Insert Link 2',required: false}, {name: 'mediaListText11',type: 'str',label: "Text for Item 11",defaultValue: 'Misc Link 3',required: false}, {name: 'mediaListItem11',type: 'str',label: "Item 11",defaultValue: 'Insert Link 3',required: false}, {name: 'mediaListText12',type: 'str',label: "Text for Item 12",defaultValue: 'Misc Link 4',required: false}, {name: 'mediaListItem12',type: 'str',label: "Item 12",defaultValue: 'Insert Link 4',required: false}, // *** Dice Game {name: 'dummy15', label: '****************** Dice Game *********************** This is a simple traditional dice roll game with possible rolls of 2-12, with a special rare roll of 13. Default price and prizes are only suggestions, please update with your choices. Text for all notices is black, but you can change the background highlight color for each type notice below', type: 'choice',required: false}, {name: 'enableDiceGame',required: false,label: 'Enable the Dice Game at the start of the show? Note you can also turn the game on and off during the show using the "/usedice on" and "/usedice off" commands.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'diceRollPrice',type: 'int',minValue: 1,maxValue: 1000,required: false, defaultValue: 48,label: 'How much do you want to charge per roll of the dice?'}, {name: 'diceRemoveWinner',required: false,label: 'Remove a winning roll from available choices until all possible rolls are used? This setting is generally not used as it gives the dice roller progressively worse and worse odds to get a winning roll', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'diceMultiRolls',required: false,type: 'int',minValue: 1,maxValue: 10,label: 'Enable multiple rolls with a single tip? Set the maximum number of rolls or set to 1 to only allow rolls for the specific amount above. For example: If this is set to 3 and you charge 30 tokens per roll, a user could tip exactly 60 for 2 rolls or exactly 90 for 3 rolls. Any tip amount that is not a multiple of the single roll will be ignored.', defaultValue: '1'}, {name: 'diceMinSpecial',required: false,label: 'Minimum rolls before the special roll of 13 is allowed. Note that even after the minimum, there is only a 20% chance of rolling a 7 with the first dice and normal odds of rolling a 6 with the second dice, so the odds of hitting 13 are about 1 in 30 after the minimum is satisfied', type: 'choice', choice1: '5', choice2: '10', choice3: '15', choice4: '20',choice5: '25', choice6: '30',choice7: '40', choice8: '50',defaultValue: '15'}, {name: 'diceNoticeInterval',required: false,type: 'int',minValue: 1,maxValue: 15,defaultValue: 5,label: 'Time interval for displaying the Dice Game notice in the chat'}, {name: 'diceNoticeBgColor',label: 'Choose your background color for the Dice Game recurring notices',required: false,type: 'choice', choice1: "White/No Color",choice2: "Light Yellow",choice3: "Light Blue",choice4: "Light Pink",choice5: "Light Red",choice6: "Light Green",choice7: "Light Purple",choice8: "Light Orange",choice9: "Light Grey",choice10: "Light Aqua",defaultValue: "Light Grey"}, {name: 'diceRollBgColor',label: 'Choose your background color for the Dice Roll results',required: false,type: 'choice', choice1: "White/No Color",choice2: "Light Yellow",choice3: "Light Blue",choice4: "Light Pink",choice5: "Light Red",choice6: "Light Green",choice7: "Light Purple",choice8: "Light Orange",choice9: "Light Grey",choice10: "Light Aqua",defaultValue: "Light Green"}, {name: 'diceRollBgColorSpecial',label: 'Choose your background color for the Special Dice Roll (13) results',required: false,type: 'choice', choice1: "White/No Color",choice2: "Light Yellow",choice3: "Light Blue",choice4: "Light Pink",choice5: "Light Red",choice6: "Light Green",choice7: "Light Purple",choice8: "Light Orange",choice9: "Light Grey",choice10: "Light Aqua",defaultValue: "Light Aqua"}, {name: 'dicePrize_2',required: false, type: 'str', label: 'Prize for dice roll of 2', defaultValue: 'Boob Flash'}, {name: 'dicePrize_3',required: false, type: 'str', label: 'Prize for dice roll of 3', defaultValue: 'Booty Flash'}, {name: 'dicePrize_4',required: false, type: 'str', label: 'Prize for dice roll of 4', defaultValue: 'Naked Jumping Jacks'}, {name: 'dicePrize_5',required: false, type: 'str', label: 'Prize for dice roll of 5', defaultValue: '3 Spanks'}, {name: 'dicePrize_6',required: false, type: 'str', label: 'Prize for dice roll of 6', defaultValue: 'Sexy Strip Tease'}, {name: 'dicePrize_7',required: false, type: 'str', label: 'Prize for dice roll of 7', defaultValue: 'Lap Dance'}, {name: 'dicePrize_8',required: false, type: 'str', label: 'Prize for dice roll of 8', defaultValue: 'Naked Squats'}, {name: 'dicePrize_9',required: false, type: 'str', label: 'Prize for dice roll of 9', defaultValue: '5 Spanks'}, {name: 'dicePrize_10',required: false, type: 'str', label: 'Prize for dice roll of 10', defaultValue: 'Naked Dancing'}, {name: 'dicePrize_11',required: false, type: 'str', label: 'Prize for dice roll of 11', defaultValue: 'Pussy or Cock Flash'}, {name: 'dicePrize_12',required: false, type: 'str', label: 'Prize for dice roll of 12', defaultValue: 'Oil and Massage Boobs'}, {name: 'dicePrize_13',required: false, type: 'str', label: 'Prize for dice roll of 13 (Rare special prize)', defaultValue: '5 Min BJ'}, // *** Raffle {name: 'dummy16', label: '******************** Raffle ************************ This raffle lets you sell tickets for multiple levels of prizes. You can have the drawing executed automatically at the end of a timed interval or when a certain number of tickets are sold, or you can do the drawing manually when you choose. There can be a single drawing or multiple drawings (a drawing every hour, etc). Each drawing can clear the ticket list or it can remain intact (cleared list is moved to a backup list each time). When performing the drawing, you can do all levels at once, or draw individual levels by setting a level value on the /raffledrawing command (see help for details). IMPORTANT!: If you would like to conduct the raffle over multiple shows, you will need to display the results at the end of each show (using /entries) and save that displayed string and paste it into the "Previous Show Results" field below when starting the next show to keep track of the tickets, as CB does not allow values captured by a bot during the show to be saved back to the launch page or between restarts of the bot.', type: 'choice',required: false}, {name: 'enableRaffle',required: false,label: 'Enable the Raffle at the start of the show? Note you can also turn the raffle sales on and off during the show using the "/useraffle on" and "/useraffle off" commands. Even when the raffle sales are turned off, the ticket list is still saved and available to display.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'raffleWhenDrawing', label: 'Which mode is used for when the drawing will take place? This setting works in combination with the next one to define what will trigger the end of the raffle, and who performs the drawing at the end (Broadcaster or Automated)', type: 'choice', choice1: 'Drawing at Broadcaster Discretion', choice2: 'Drawing after a Time Period', choice3: 'Drawing after a Ticket Goal', choice4: 'Drawing after a Token Goal', defaultValue: 'Drawing at Broadcaster Discretion'}, {name: 'raffleAutoDrawing', label: 'At the end of the raffle, if using a timer or goal, does the Broadcaster perform the drawing manually with the /raffledrawing command, or does the drawing occur automatically when time runs out or goal is reached?', type: 'choice', choice1: 'Broadcaster Performs Drawing', choice2: 'Automated Drawing', defaultValue: 'Broadcaster Performs Drawing'}, {name: 'raffleDrawingInterval',required: false,type: 'int',minValue: 1,maxValue: 120,defaultValue: 60,label: 'Time interval between drawings or until main drawing if there is only one. You can have the bot perform the drawing automatically at the end of the time period, or just have the timer run and perform the drawing manually using the command "/raffledrawing"'}, {name: 'raffleDrawingGoal',required: false,type: 'int',minValue: 1,maxValue: 10000,defaultValue: 500,label: 'Raffle goal in tickets or tokens per the above defined mode. As with the timer, you can have the bot perform the drawing automatically when goal is reached, or just track against the goal and perform the drawing manually using the command "/raffledrawing"'}, {name: 'raffleModDrawing', label: 'Allow a moderator to perform the ticket drawing for the broadcaster when in manual drawing mode?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'raffleTipMultiple', label: 'Allow a viewer to buy multiple raffle tickets with a single tip? Note that if this is turned on, and you use multiple levels of prizes, you should make sure that the prices for each level are not multiples of each other. The bot will use the first level it comes to that the tip is a multiple of. Also the tip multiples are not validated against the duplicate price checker', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'rafflePrice1',type: 'int',minValue: 0,maxValue: 1000,required: false, label: 'Raffle Level 1 Ticket Price. Set to "0" if not using this level'}, {name: 'rafflePrizes1',type: 'str',minLength: 1,maxLength: 2000,required: false,label: 'Raffle prizes available for Level 1. Can be a single prize or multiple prizes. For multiple prizes, the format must be a list separated by a commas (,). Spaces are allowed, but should not be used between prizes, else they will be shown as part of the prize name. For example, you could use a string like this: "free video,half priced private,polaroids in the mail,one month free fanclub,one month free snap". Note that if you are only intending to give out one prize from a list, DO NOT separate them with commas or they are treated as individual prizes. You can use the format "One of PRIZE 1/PRIZE 2/PRIZE 3 to have them treated as one prize"'}, {name: 'rafflePrice2',type: 'int',minValue: 0,maxValue: 1000,required: false, label: 'Raffle Level 2 Ticket Price. Set to "0" if not using this level'}, {name: 'rafflePrizes2',type: 'str',minLength: 1,maxLength: 2000,required: false,label: 'Raffle prizes available for Level 2. Use the same format shown above for Level 1. '}, {name: 'rafflePrice3',type: 'int',minValue: 0,maxValue: 1000,required: false, label: 'Raffle Level 3 Ticket Price. Set to "0" if not using this level'}, {name: 'rafflePrizes3',type: 'str',minLength: 1,maxLength: 2000,required: false,label: 'Raffle prizes available for Level 3. Use the same format shown above for Level 1. '}, {name: 'rafflePrice4',type: 'int',minValue: 0,maxValue: 1000,required: false, label: 'Raffle Level 4 Ticket Price. Set to "0" if not using this level'}, {name: 'rafflePrizes4',type: 'str',minLength: 1,maxLength: 2000,required: false,label: 'Raffle prizes available for Level 4. Use the same format shown above for Level 1. '}, {name: 'rafflePrice5',type: 'int',minValue: 0,maxValue: 1000,required: false, label: 'Raffle Level 5 Ticket Price. Set to "0" if not using this level'}, {name: 'rafflePrizes5',type: 'str',minLength: 1,maxLength: 2000,required: false,label: 'Raffle prizes available for Level 5. Use the same format shown above for Level 1. '}, {name: 'raffleNoticeInterval',required: false,type: 'int',minValue: 1,maxValue: 20,defaultValue: 2,label: 'Time interval between postings of the notice that a raffle is going on. The text below will be shown in each notice, followed by a listing of the raffle levels and prizes.'}, {name: 'raffleNoticeText',type: 'str',minLength: 1,maxLength: 255,label: 'Enter the Text you would like to display in the Raffle Notice',required: false, defaultValue: 'A raffle is running today. You can buy tickets for up to 5 levels of prizes, shown below. Drawings will be held every hour for a winner from each level.'}, {name: 'raffleContinuous',required: false,label: 'Will you perform multiple drawings and continuously renew the timer or goal? Or will you do a single drawing?', type: 'choice', choice1: 'Continuous', choice2: 'Single Drawing', defaultValue: 'Single Drawing'}, {name: 'raffleResetCycle',required: false,label: 'If performing multiple drawings, should all entries be cleared with each drawing? It is expected this would normally be "No", and tickets are retained until the end of the raffle or the ticket is drawn as a winner.', type: 'choice', choice1: 'No', choice2: 'Yes', defaultValue: 'No'}, {name: 'raffleTicketList',type: 'str',minLength: 1,maxLength: 2000,required: false,label: 'If running a show over multiple days or multiple sessions, paste the results from the previous session here. The formatting must be kept intact, where a user name and their ticket count is separated by a colon (:), and each pair is separated by a comma (,). For example, a string of user1:1:5,user2:1:1,user2:3:1 indicates user 1 has already bought 5 tickets at level 1, and user 2 has bought 1 ticket at level 1 and 1 ticket at level 3. The command "/entries" will display this list in the chat so you can copy and paste it into an external document to be saved for the next show'} ]; } { // *********************************** Variables and Arrays ************************************** var initialize = 0; /* Used to run initialization once */ var numPMs = 0; var timerStart = 0; /* captured time when the timer was started, used to calculate time left */ var clockStartTime = 0; var clockStopTime = 0; var timerDuration = 0; var clockTimeAdded = 0; var clockMinsRemain = 0; var clockSecsRemain = 0; var clockSkipMin = false; var clockSkipSec = false; var silenceLevel = cb.settings.initialSilenceLevel; var graphicLevel = cb.settings.initialGraphicsLevel; var showNinjadMsgs = cb.settings.showNinjadMsgs; var showSilencedMsgs = cb.settings.showSilencedMsgs; var notifierToggle = 0; var tipMenuToggle = 0; var tipMenu2Toggle = 0; var posTipMenuToggle = 0; var tokenPollToggle = 0; var lushMenuToggle = 0; var leaderboardToggle = 0; var tipCountToggle = 0; var groupIconsToggle = 0; var backupToggle = 0; var mediaToggle = 0; var tipLeaderIconsToggle = 0; var presalesToggle = 0; var tipResponseToggle = 0; var diceToggle = 0; var grayLockToggle = 0; var ticketShowToggle = 0; var ticketShowOtToggle = 0; var raffleToggle = 0; var allTimeToggle = 0; var requireAnswerToggle = 0; var numberOfTippers = 0; var firstlb = 0; var firstmedia = 0; var leaderTimer = 0; var num = 0; var minTipToChat = parseInt(cb.settings.minTipToChat); var whichToy = cb.settings.whichToy; var grayChatTime = cb.settings.grayChatTime; var requireAnswerLevel = 0; var requireAnswerLevelText = cb.settings.requireAnswerLevel; var timerDesc = cb.settings.defaultTimerDescription; var isPrivate = false; var presaleStartTime = 0; var presaleStopTime = 0; var presaleTimeAdded = 0; var presaleMinsRemain = 0; var presaleSecsRemain = 0; var presaleSkipMin = false; var presaleSkipSec = false; var presaleSkipNotice = false; var presalePrice = cb.settings.initialPresalePrice; var nextPresalePrice = 0; var countPresaleSold = 0; var presaleMode = ""; var presaleModeText = ""; var enablePresales = cb.settings.enablePresales; var ticketStartMode = ""; var ticketModeAuto = ""; var ticketShowTotalTips = 0; var ticketShowTotalTickets = 0; var ticketStartTime = 0; var ticketStopTime = 0; var ticketTimeAdded = 0; var ticketMinsRemain = 0; var ticketSecsRemain = 0; var ticketPriceVIP = cb.settings.hiddenShowPriceVIP; var ticketPriceEFC = cb.settings.hiddenShowPriceEFC; var ticketPriceFC = cb.settings.hiddenShowPriceFC; var ticketSubjectText = cb.settings.hiddenShowDescription; var ticketShowType = cb.settings.ticketShowType; var ticketPrice = cb.settings.hiddenShowPrice; var backupPrice = 0; var ticketShowEnded = false; var ticketSalesEnded = false; var raffleWhenDrawing = cb.settings.raffleWhenDrawing; var raffleAutoDrawing = cb.settings.raffleAutoDrawing; var raffleGoalTicketsSold = 0; var raffleTotalTicketsSold = 0; var raffleTotalTokens = 0; var raffleGoalTokens = 0; var raffleEndMode = ""; var newRaffleEndMode = ""; var raffleDrawingMode = ""; var newRaffleDrawingMode = ""; var raffleStartTime = 0; var raffleStopTime = 0; var raffleTimeAdded = 0; var raffleMinsRemain = 0; var raffleSecsRemain = 0; var previousRaffleLoaded = false; var raffleSkipMin = false; var raffleSkipSec = false; var raffleSkipNotice = false; var raffleTicketGoalAmt = cb.settings.raffleDrawingGoal; var raffleTipGoalAmt = cb.settings.raffleDrawingGoal; var notifierMessage1 = cb.settings.notifierMessage1; var notifierMessage2 = cb.settings.notifierMessage2; var notifierMessage3 = cb.settings.notifierMessage3; var notifierMessage4 = cb.settings.notifierMessage4; var notifierMessage5 = cb.settings.notifierMessage5; var tipResponseMessage1 = cb.settings.tipResponseMessage1; var tipResponseMessage2 = cb.settings.tipResponseMessage2; var tipResponseMessage3 = cb.settings.tipResponseMessage3; var tipResponseMessage4 = cb.settings.tipResponseMessage4; var tipResponseMessage5 = cb.settings.tipResponseMessage5; var tipResponseAmount1 = parseInt(cb.settings.tipResponseAmount1); var tipResponseAmount2 = parseInt(cb.settings.tipResponseAmount2); var tipResponseAmount3 = parseInt(cb.settings.tipResponseAmount3); var tipResponseAmount4 = parseInt(cb.settings.tipResponseAmount4); var tipResponseAmount5 = parseInt(cb.settings.tipResponseAmount5); var BC = cb.room_slug; var leaderInt = parseInt(cb.settings.leaderInterval) * 60000; var green = "#a2dfac"; // Used for general messaging from fembot var purple = "#e2a2ea"; var yellow = "#f4d599"; // Used for clock countdown var red = "#f4c1bc"; // Used for last 2 minutes of clock countdown var blue = "#0099ff"; var HLgreen = "#91c970"; // Green notice highlighting var HLpurple = "#e2a2ea"; // Purple notice highlighting var HLyellow = "#fcff9b"; // Yellow notice highlighting var HLred = "#ff6d69"; // Red notice highlighting var HLblue = "#81bcff"; // Blue notice highlighting var ticketHolderBgColor = '#e8fbe8' // Light green highlighting for ticket show buyers var ticketStatsBgColor = '#e0e0e0' // Light gray for ticket show stats background var dashLine60 = new Array(60).join("-"); var dashLine70 = new Array(70).join("-"); var dashLine80 = new Array(80).join("-"); var dashLine90 = new Array(90).join("-"); var mediaListItem1 = cb.settings.mediaListItem1; var mediaListItem2 = cb.settings.mediaListItem2; var mediaListItem3 = cb.settings.mediaListItem3; var mediaListItem4 = cb.settings.mediaListItem4; var mediaListItem5 = cb.settings.mediaListItem5; var mediaListItem6 = cb.settings.mediaListItem6; var mediaListItem7 = cb.settings.mediaListItem7; var mediaListItem8 = cb.settings.mediaListItem8; var mediaListItem9 = cb.settings.mediaListItem9; var mediaListItem10 = cb.settings.mediaListItem10; var mediaListItem11 = cb.settings.mediaListItem11; var mediaListItem12 = cb.settings.mediaListItem12; var mediaListText1 = cb.settings.mediaListText1; var mediaListText2 = cb.settings.mediaListText2; var mediaListText3 = cb.settings.mediaListText3; var mediaListText4 = cb.settings.mediaListText4; var mediaListText5 = cb.settings.mediaListText5; var mediaListText6 = cb.settings.mediaListText6; var mediaListText7 = cb.settings.mediaListText7; var mediaListText8 = cb.settings.mediaListText8; var mediaListText9 = cb.settings.mediaListText9; var mediaListText10 = cb.settings.mediaListText10; var mediaListText11 = cb.settings.mediaListText11; var mediaListText12 = cb.settings.mediaListText12; var mediaInt = parseInt(cb.settings.mediaListInterval) * 60000; var ticketModAdd = (cb.settings.ticketModAdd === "Yes"); var ticketShowGoal = parseInt(cb.settings.hiddenShowGoal); var suppressPrefix = false; // Arrays */ var niceListArray = []; var silenceListArray = []; var ninjaListArray = []; var VIPListArray = []; var extFanListArray = []; var wordListArray = []; var MessageArray = []; var pmArray = []; var backupListArray = []; var presaleArray = []; var grayLockList = []; var answerLockList = []; var answerLockStatus = []; var answerLockQuestion = [0]; var rafflePrizeList1 = []; var rafflePrizeList2 = []; var rafflePrizeList3 = []; var rafflePrizeList4 = []; var rafflePrizeList5 = []; var raffleDrawingArray = []; var fanClubList = []; var ticketShowViewerList = []; var ticketCumulative = {name: [], amount: []}; var moderatorList = {name: [], type: []}; var botModListArray = []; var tipCountArray = {name: [], amount: []}; var grayLockStatus = {canChat: [], entered: []}; var otChangesArray = {name: [], type: []}; var iconNicknamesArray = {name: [], icon: [], nickname: [], color: []}; var outstandingTicketArray = []; var priceCheckArray = {amount: [], name: []}; var rafflePrevTicketsArray = {name: [], level: []}; var raffleCurrentTicketsArray = {name: [], level: []}; var raffleTicketsSoldLvl = []; var rafflePrice = []; var allTimeArray = {name: [], totaltips: []}; var ticketShowExtraTickets = {name: [], count: []}; var lockQuestions = ['three + two = ____ (three,four,five)','the sky is _____ (yellow,green,blue)','dogs have _____ legs (four,six,eight)','a hexagon has _____ sides (six,eight,ten)','iphones are made by _____ (plum,orange,apple)','Tiger Woods plays _____ (basketball,golf,football)','Christmas is in _____ (january,march,december)','austin is the capital of _____ (oklahoma,texas,ohio)','spiders have _____ legs (six,seven,eight)','Paris is in _____ (france,spain,portugal)']; var lockAnswers = ['five','blue','four','six','apple','golf','december','texas','eight','france']; // **** Tip Menu Variables var TIPMENU = { menuDspIntTime: 0, sepChar: "| ", tipMenu: "", menuPart1: "", menuPart2: "", menuToken: 1, tipMenuPrice: [], tipMenuItem: [], initToken: true, txtColor1: "", bgColor1: "", txtColor2: "", bgColor2: "", menuLength: 0, requesters: [], request: [], }; var TIPMENU2 = { menuDspIntTime: 0, sepChar: "| ", tipMenu: "", menuPart1: "", menuPart2: "", menuToken: 1, tipMenuPrice: [], tipMenuItem: [], initToken: true, txtColor1: "", bgColor1: "", txtColor2: "", bgColor2: "", menuLength: 0, requesters: [], request: [], }; var POSTIPMENU = { posMenuDspIntTime: 0, posSepChar: "| ", posTipMenu: "", posTipMenuPrice: [], posTipMenuItem: [], posInitToken: true, posTxtColor: "", posBgColor: "", posMenuLength: 0, posRequesters: [], posRequest: [], }; var LUSHMENU = { lushMenuDspIntTime: 0, lushMenu: "", lushMenuLevel: [], lushInitToken: true, lushTxtColor: "", lushBgColor: "", lushMenuLength: 0, }; // ************ Variables for Token Poll var pollwarnLight = "#FF0000"; var pollwarnDark = "#FFFFFF"; var pollType; var fanDouble = (cb.settings.pollFanClubDouble === "Yes"); var pollModAdd = (cb.settings.pollModAdd === "Yes"); var pollStartTime; var pollStopTime; var pollMinsRemain = cb.settings.pollCount; var pollSecsRemain = 60; var votesRemain = cb.settings.pollCount; var pollRunning = false; var aliveWarned = false; var nline = 0; var pollOptLabel1 = cb.settings.pollOptLabel1; var pollOptLabel2 = cb.settings.pollOptLabel2; var pollOptLabel3 = cb.settings.pollOptLabel3; var pollOptLabel4 = cb.settings.pollOptLabel4; var pollOptLabel5 = cb.settings.pollOptLabel5; var pollOptLabel6 = cb.settings.pollOptLabel6; var pollOptLabel7 = cb.settings.pollOptLabel7; var pollOptLabel8 = cb.settings.pollOptLabel8; var pollOptTokens1 = cb.settings.pollOptTokens1; var pollOptTokens2 = cb.settings.pollOptTokens2; var pollOptTokens3 = cb.settings.pollOptTokens3; var pollOptTokens4 = cb.settings.pollOptTokens4; var pollOptTokens5 = cb.settings.pollOptTokens5; var pollOptTokens6 = cb.settings.pollOptTokens6; var pollOptTokens7 = cb.settings.pollOptTokens7; var pollOptTokens8 = cb.settings.pollOptTokens8; var pollArrayAmount = []; var pollArrayLabel = []; var pollArrayVotes = []; var pollSkipMin = false; var pollSkipSec = false; var pollMinimum = cb.settings.pollMinimum; var totalPollVotes = 0; var pollTitle = cb.settings.pollTitle; // ************ Variables for Dice Game var diceRollPrice = cb.settings.diceRollPrice; var dicePlural = (diceRollPrice > 1) ? 'tokens' : 'token'; var diceMultiRolls = cb.settings.diceMultiRolls; var diceLastRoller = '--'; var diceLastPrizeWon = '--'; var diceRollCounter = 0; var diceRollCounterSpecial = 0; var diceWinners = []; var dicePrizes = []; var diceMinSpecial = parseInt(cb.settings.diceMinSpecial); var diceGifPfx = ':reddie'; var diceRarePct = 20; var diceInt = parseInt(cb.settings.diceNoticeInterval) * 60000; var firstDice = 0; } { // *********************************** Functions ************************************** { // Generic functions to set the color or separator characters function checkTextColor(color) { switch (color) { case "White/No Color": return "#FFFFFF"; case "Black": return "#000000"; case "Dark Blue": return "#0629AC"; case "Dark Pink": return "#FF6680"; case "Dark Green": return "#006600"; case "Dark Red": return "#cc0000"; case "Dark Purple": return "#3d003d"; case "Dark Grey": return "#737373"; case "Dark Orange": return "#e77400"; case "Dark Aqua": return "#006767"; default: if (/^#[0-9A-F]{6}$/i.test(color)) { return color; } else if (/^[0-9A-F]{6}$/i.test(color)) { return ('#' + color); } else { return ("default"); } } } function checkBgColor(color) { switch (color) { case "White/No Color": return "#FFFFFF"; case "Light Aqua": return "#adeaea"; case "Light Pink": return "#FFE6EA"; case "Light Green": return "#94e594"; case "Light Red": return "#ff9a9a"; case "Light Purple": return "#f2cdff"; case "Light Orange": return "#ffd9b3"; case "Light Grey": return "#e6e6e6"; case "Light Blue": return "#d1eaee"; case "Light Yellow": return "#ffff94" case "Cream": return "#f9f6ed" default: if (/^#[0-9A-F]{6}$/i.test(color)) { return color; } else if (/^[0-9A-F]{6}$/i.test(color)) { return ('#' + color); } else { return ("default"); } } } function checkSepChar(char) { switch (char) { case "Hearts": return ':heart2'; case "Glitter": return ':pixelglitter'; case "Flowers": return ':tinyflower2'; case "Bow": return ':bluebow'; case "Hearts2": return ':Hearts2'; case "Smiley": return ':smile'; case "Text Heart": return '\u2665'; case "Text Diamond": return '\u2666'; case "Text Star": return '\u2605'; default: return ("|"); } } //********** Price Check Function ************** function priceChecker(mode, name, price, sendto) { if (price != 0 && price !=null) { if (mode === 'add') { if (cbjs.arrayContains(priceCheckArray.name,name)) { nameIndex = priceCheckArray.name.indexOf(name); priceCheckArray.name.splice(nameIndex,1); priceCheckArray.amount.splice(nameIndex,1); } if (cbjs.arrayContains(priceCheckArray.amount,price)) { priceIndex = priceCheckArray.amount.indexOf(price); cb.sendNotice('Warning! There is a duplicate price entry. When adding ' + name + ', the configured price of ' + price + ' was found already in use for ' + priceCheckArray.name[priceIndex] + '.',sendto,yellow); } if (price == 1 || price == 5 || price == 10 || price == 15 || price == 20 || price == 25 || price == 50 || price == 100) { cb.sendNotice('Warning! When adding ' + name + ', the configured price of ' + price + ' is a common tip amount (1,5,10,15,20,25,50,100) and not recommended for any specific feature price. It is recommended to use uncommon tip amounts for all prices.',sendto,yellow); } priceCheckArray.name.push(name); priceCheckArray.amount.push(price); } else if (mode === 'rmv') { if (cbjs.arrayContains(priceCheckArray.name,name)) { nameIndex = priceCheckArray.name.indexOf(name); priceCheckArray.name.splice(nameIndex,1); priceCheckArray.amount.splice(nameIndex,1); } } } } //********** Tip Count Functions ************** function populateTipCountArray(user,tip) { tipCountArray.name.push(user); tipCountArray.amount.push(tip); } function findTipper(user) { for (var i = 0; i < tipCountArray.name.length; i++) { if(tipCountArray.name[i] == user) { break; } } return i; } //********** Room Subject Function ************** function setRoomSubject(newSubject, user) { cb.changeRoomSubject(newSubject); cb.sendNotice(user + ' has updated the room title to "' + newSubject + '".', "", "", "", "bold"); } //********** Caps Suppression Toggle ************** function setCapsToggle(option, mod) { if(option == 'on') { if(suppressCapsToggle == 1) { cb.sendNotice('The Caps Lock Suppression is already turned on.',mod,green); } else { suppressCapsToggle = 1; cb.sendNotice('You have enabled the Caps Lock Suppression.',mod,green); } } else if(option == 'off') { if(suppressCapsToggle == 0) { cb.sendNotice('The Caps Lock Suppression is already turned off.',mod,green); } else { suppressCapsToggle = 0; cb.sendNotice('You have disabled the Caps Lock Suppression.',mod,green); } } } //********** Leaderboard Functions ************** function setLeaderToggle(option, mod) { if(option == 'on') { if(leaderboardToggle == 1) { cb.sendNotice('The Leaderboard display is already turned on.',mod,green); } else { leaderboardToggle = 1; sendLeaderboard(); cb.sendNotice('You have enabled the Leaderboard display.',mod,green); } } else if(option == 'off') { if(leaderboardToggle == 0) { cb.sendNotice('The Leaderboard display is already turned off.',mod,green); } else { leaderboardToggle = 0; cb.sendNotice('You have disabled the Leaderboard display. Tip leaders are stil tracked but the board is not displayed.',mod,green); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /useleaderboard.\nType /fbhelp useleaderboard to see how to use /useleaderboard.',mod,green); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /useleaderboard.\nType /fbhelp useleaderboard to see how to use /useleaderboard.',mod,green); } } function sendLeaderboard() { if(firstlb == 0) { leaderTimer = leaderInt - 30000; firstlb = 1 } else { leaderTimer = leaderInt; } cb.setTimeout(leaderboardTimer, leaderTimer); } function leaderboardTimer() { if(leaderboardToggle == 1) { sortTippers(); setLeaderBoardColors(); var outString = ""; for (var i = 1; i <= 5; i++) { if (tipCountArray.name[i - 1] == null) outString += " " + i + ". empty" + "\n"; else outString += " " + i + ". " + '"' + tipCountArray.name[i - 1] + '"' + ": " + tipCountArray.amount[i - 1] + "\n"; } cb.sendNotice("\u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 LEADERBOARD \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606\n" + outString + "\u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606", "", leaderBgColor, leaderTextColor, "bold"); sendLeaderboard(); } } function showLeaderBoard(from, group) { if(leaderboardToggle == 1) { sortTippers(); setLeaderBoardColors(); var outString = ""; for (var i = 1; i <= 5; i++) { if (tipCountArray.name[i - 1] == null) outString += " " + i + ". empty" + "\n"; else outString += " " + i + ". " + '"' + tipCountArray.name[i - 1] + '"' + ": " + tipCountArray.amount[i - 1] + "\n"; } cb.sendNotice("\u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 LEADERBOARD \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606\n" + outString + "\u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606 \u2606", from, leaderBgColor, leaderTextColor, "bold", group); } else { cb.sendNotice('The broadcaster has decided not to use the Leaderboard feature.',from,green); } } function setLeaderBoardColors() { if (cb.settings.leaderTextColor == "Custom") { leaderTextColor = checkTextColor(cb.settings.leaderTextCustColor); if (leaderTextColor == "default") { cb.sendNotice("Leaderboard - Error while setting the text color. It has to be in a HEX format. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); leaderTextColor = '#000000'; } } else { leaderTextColor = checkTextColor(cb.settings.leaderTextColor); } if (cb.settings.leaderBgColor == "Custom") { leaderBgColor = checkBgColor(cb.settings.leaderBgCustColor); if (leaderBgColor == "default") { cb.sendNotice("Leaderboard - Error while setting the background color. It has to be in a HEX format. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); leaderBgColor = '#FFFFFF'; } } else { leaderBgColor = checkBgColor(cb.settings.leaderBgColor); } } function sortTippers() { var swapped, temp1, temp2; do { swapped = false; for (var i = 0; i < tipCountArray.amount.length ; i++) { if (tipCountArray.amount[i] < tipCountArray.amount[i + 1]) { temp1 = tipCountArray.amount[i]; temp2 = tipCountArray.name[i]; tipCountArray.amount[i] = tipCountArray.amount[i + 1]; tipCountArray.amount[i + 1] = temp1; tipCountArray.name[i] = tipCountArray.name[i + 1]; tipCountArray.name[i + 1] = temp2; swapped = true; } } } while (swapped); } function showTippers(from,group,num) { sortTippers(); var outString = ""; for (var i = 1; i <= num; i++) { if (tipCountArray.name[i - 1] == null) outString += "\u25ba " + i + ". --" + "\n"; else outString += "\u25ba " + i + ". " + '"' + tipCountArray.name[i - 1] + '"' + ": " + tipCountArray.amount[i - 1] + "\n"; } cb.sendNotice(dashLine80 + "\n\u25ba \u25ba \u25ba ALL TIPPERS \u25c4 \u25c4 \u25c4\n" + outString + dashLine80, from, "", '#111111', "bold",group); } function populateModeratorArray(user,type,mode) { if (mode == 'a') { if (!cbjs.arrayContains(moderatorList.name,user)) { moderatorList.name.push(user); moderatorList.type.push(type); } else { return; } } else if (mode == 'r') { if (cbjs.arrayContains(moderatorList.name,user)) { nameIndex = moderatorList.name.indexOf(user); moderatorList.name.splice(nameIndex,1); moderatorList.type.splice(nameIndex,1); } else { return; } } else { return; } } function populateFanClubArray(user) { if (!cbjs.arrayContains(fanClubList,user)) { fanClubList.push(user); } else { return; } } //********** Chat Control Functions ************** function setSilenceLevel(s, mod) { if (parseInt(s) >= 0 && parseInt(s) <= 4) { silenceLevel = parseInt(s); cb.sendNotice('The silence level has been set to ' + s + '.', cb.room_slug, green); cb.sendNotice('The silence level has been set to ' + s + '.', '', green, '', '', 'red'); switch(parseInt(s)) { case 0: cb.sendNotice('All members can talk in chat.', cb.room_slug, green); cb.sendNotice('All members can talk in chat.', '', green, '', '', 'red'); break; case 1: cb.sendNotice('Only members with tokens can talk in chat.', cb.room_slug, green); cb.sendNotice('Only members with tokens can talk in chat.', '', green, '', '', 'red'); break; case 2: cb.sendNotice('Only members who have tipped can talk in chat.', cb.room_slug, green); cb.sendNotice('Only members who have tipped can talk in chat.', '', green, '', '', 'red'); break; case 3: cb.sendNotice('Only members who have tipped at least ' + minTipToChat + ' tokens can talk in chat.', cb.room_slug, green); cb.sendNotice('Only members who have tipped at least ' + minTipToChat + ' tokens can talk in chat.', '', green, '', '', 'red'); break; case 4: cb.sendNotice('Only Moderators, Fans, and VIPs can chat.', cb.room_slug, green); cb.sendNotice('Only Moderators, Fans, and VIPs can chat.', '', green, '', '', 'red'); break; } } else { cb.sendNotice(s + ' is not a valid setting, must be a number from 0 to 4 (0=Everyone,1=Users with tokens,2=Users who have tipped,3=Users who have tipped the minimum configured tokens,4=Only Mods, Fans, VIPs).',mod,green); } } function setGraphicLevel(s, mod) { if(parseInt(s) >= 0 && parseInt(s) <= 4) { graphicLevel = parseInt(s); cb.sendNotice('The graphic level has been set to ' + s + '.', cb.room_slug, green); cb.sendNotice('The graphic level has been set to ' + s + '.', '', green, '', '', 'red'); switch(parseInt(s)) { case 0: cb.sendNotice('All members can use graphics in chat.',cb.room_slug,green); cb.sendNotice('All members can use graphics in chat.', '', green, '', '', 'red'); break; case 1: cb.sendNotice('Only members with tokens can use graphics in chat.', cb.room_slug, green); cb.sendNotice('Only members with tokens can use graphics in chat.', '', green, '', '', 'red'); break; case 2: cb.sendNotice('Only members who have tipped can use graphics in chat.', cb.room_slug, green); cb.sendNotice('Only members who have tipped can use graphics in chat.', "", green, '', '', 'red'); break; case 3: cb.sendNotice('Only members who have tipped at least ' + minTipToChat + ' tokens can use graphics in chat.', cb.room_slug, green); cb.sendNotice('Only members who have tipped at least ' + minTipToChat + ' tokens can use graphics in chat.', '', green, '', '', 'red'); break; case 4: cb.sendNotice('Only Moderators, Fans, and VIPs can use graphics in chat.', cb.room_slug, green); cb.sendNotice('Only Moderators, Fans, and VIPs can use graphics in chat.', '', green, '', '', 'red'); break; } } else { cb.sendNotice(s + ' is not a valid setting, must be a number from 0 to 4 (0=Everyone,1=Users with tokens,2=Users who have tipped,3=Users who have tipped the minimum configured tokens,4=Only Mods, Fans, VIPs).', mod, green); } } //********** List Maintenance Functions ************** function addRmvNinja(user, mod, mode) { if (mode == 'a') { if(cbjs.arrayContains(ninjaListArray,user)) { cb.sendNotice(user + ' has already been added to the ninja list.', mod, green); } else if(cbjs.arrayContains(moderatorList.name,user)) { cb.sendNotice(user + ' is a moderator and cannot be ninja\'d.', mod, green); } else if(user == cb.room_slug) { cb.sendNotice(user + ' is the broadcaster and cannot be ninja\'d.', mod, green); } else { ninjaListArray.push(user); cb.sendNotice('You have added ' + user + ' to the ninja list.', mod, green); } } else if (mode == 'r') { if(cbjs.arrayContains(ninjaListArray,user)) { cbjs.arrayRemove(ninjaListArray,user); cb.sendNotice('You have removed ' + user + ' from the ninja list.', mod, green); } else { cb.sendNotice(user + ' is not on the ninja list.', mod, green); } } } function addRmvSilence(user, mod, mode) { if (mode == 'a') { if(cbjs.arrayContains(silenceListArray,user)) { cb.sendNotice(user + ' has already been silenced.', mod, green); } else if(cbjs.arrayContains(moderatorList.name,user)) { cb.sendNotice(user + ' is a moderator and cannot be silenced.', mod, green); } else if(user == cb.room_slug) { cb.sendNotice(user + ' is the broadcaster and cannot be silenced.', mod, green); } else { silenceListArray.push(user); cb.sendNotice('You have added ' + user + ' to the silence list. Note this is only applied during this session, permanent silence list changes must be made to list defined when starting the Fembot. This list should also be saved to a separate document.', mod, green); cb.sendNotice('You have been silenced due to rudeness, demands or otherwise inappropriate behavior. In the future, you can avoid this by being nice and not making demands.', user, green); } } else if (mode == 'r') { if(cbjs.arrayContains(silenceListArray,user)) { cbjs.arrayRemove(silenceListArray,user); cb.sendNotice('You have removed ' + user + ' from the silence list. Note this is only applied during this session, permanent silence list changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.', mod, green); cb.sendNotice('You have been unsilenced by ' + mod + '. Please be nice and don\'t make demands.', user, green); } else { cb.sendNotice(user + ' is not currently silenced.', mod, green); } } } function addRmvWord(word, mod, mode) { if (mode == 'a') { if(cbjs.arrayContains(wordListArray,word)) { cb.sendNotice(word + ' has already been added to the Blocked Word list.', mod, green); } else { wordListArray.push(word); cb.sendNotice('You have added "' + word + '" to the Blocked Word list. Note this is only applied during this session, permanent word list changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.', mod, green); } } else if (mode == 'r') { if(cbjs.arrayContains(wordListArray,word)) { cbjs.arrayRemove(wordListArray,word); cb.sendNotice('You have removed "' + word + '" from the Blocked Word list. Note this is only applied during this session, permanent word list changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.', mod, green); } else { cb.sendNotice(word + ' is not on the Blocked Word list.', mod, green); } } } function addRmvVIP(user, mod, mode) { if (mode == 'a') { if(cbjs.arrayContains(VIPListArray,user)) { cb.sendNotice(user + ' has already been added to the VIP list.', mod, green); } else { VIPListArray.push(user); cb.sendNotice('You have added ' + user + ' to the VIP list. Note this is only applied during this session, permanent VIP list changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.', mod, green); cb.sendNotice('Congratulations! You have been added to the VIP list!', user, green); } } else if (mode == 'r') { if(cbjs.arrayContains(VIPListArray,user)) { cbjs.arrayRemove(VIPListArray,user); cb.sendNotice('You have removed ' + user + ' from the VIP list. Note this is only applied during this session, permanent VIP list changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.', mod, green); } else { cb.sendNotice(user + ' is not on the VIP list.', mod, green); } } } function addRmvExtFan(user, mod, mode) { if(mode == 'a') { if(cbjs.arrayContains(extFanListArray,user)) { cb.sendNotice(user + ' has already been added to the External Fan Club list.', mod, green); } else { extFanListArray.push(user); cb.sendNotice('You have added ' + user + ' to the External Fan Club list. Note this is only applied during this session, permanent External Fan Club list changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.', mod, green); cb.sendNotice('Congratulations! You have been added to the External Fan Club list!', user, green); } } else if(mode == 'r') { if(cbjs.arrayContains(extFanListArray,user)) { cbjs.arrayRemove(extFanListArray,user); cb.sendNotice('You have removed ' + user + ' from the External Fan Club list. Note this is only applied during this session, permanent Fan Club list changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.', mod, green); } else { cb.sendNotice(user + ' is not on the External Fan Club list.', mod, green); } } } function addRmvNice(user, mod, mode) { if(mode == 'a') { if(!cbjs.arrayContains(niceListArray,user)) { niceListArray.push(user); cb.sendNotice('You have added ' + user + ' to the nice list. Note this is only applied during this session, permanent nice list changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.', mod, green); cb.sendNotice(mod + ' has added you to the nice list. You will be able to chat and use graphcs regardless of the global room settings. Thank you for being nice!',user,green); } else { cb.sendNotice(user + ' is already on the nice list.', mod, green); } } else if(mode == 'r') { if(cbjs.arrayContains(niceListArray,user)) { cbjs.arrayRemove(niceListArray,user); cb.sendNotice('You have removed ' + user + ' from the nice list. Note this is only applied during this session, permanent nice list changes must be made to the list defined when starting the ultrabot. This list should also be saved to a separate document.', mod, green); cb.sendNotice(mod + ' has removed you from the nice list.', user, green); } else { cb.sendNotice(user + ' is not on the nice list.', mod, green); } } } function populateNiceListArray(user) { if (!cbjs.arrayContains(niceListArray, user)) niceListArray.push(user); else return; } function populateWordListArray(word) { if (!cbjs.arrayContains(wordListArray, word)) wordListArray.push(word); else return; } function populateVIPListArray(user) { if (!cbjs.arrayContains(VIPListArray, user)) VIPListArray.push(user); else return; } function populateExtFanListArray(user) { if (!cbjs.arrayContains(extFanListArray, user)) extFanListArray.push(user); else return; } //********** Timer Functions ************** function clockTimerMin() { if (!clockStopping) { switch (clockMinsRemain) { case 120: case 90: case 60: case 45: case 30: case 25: case 20: case 15: case 10: case 5: case 4: case 3: case 2: cb.sendNotice('\u23f1 \u23f1 \u23f1 There are ' + clockMinsRemain + ' minutes left on the timer ' + (timerDesc != '' ? ('until ' + timerDesc) : '') + ' \u23f1 \u23f1 \u23f1', '', yellow, '', 'bold'); break; case 1: cb.sendNotice('\u23f1 \u23f1 \u23f1 There is 1 minute left on the timer ' + (timerDesc != '' ? ('until ' + timerDesc) : '') + '!! \u23f1 \u23f1 \u23f1', '', red, '', 'bold'); break; } clockMinsRemain--; if (clockMinsRemain > 0) { displaySeconds = false; } else { displaySeconds = true; } clockSecsRemain = 60; clockTimerSec(); } } function clockTimerSec() { if (!clockStopping) { if (displaySeconds) { switch (clockSecsRemain) { case 30: case 10: case 5: case 4: case 3: case 2: cb.sendNotice('\u23f1 \u23f1 \u23f1 There are ' + clockSecsRemain + ' seconds left on the timer ' + (timerDesc != '' ? ('until ' + timerDesc) : '') + ' \u23f1 \u23f1 \u23f1', '', red, '', 'bold'); break; case 1: cb.sendNotice('\u23f1 \u23f1 \u23f1 There is 1 second left on the timer ' + (timerDesc != '' ? ('until ' + timerDesc) : '') + ' \u23f1 \u23f1 \u23f1', '', red, '', 'bold'); break; } } if (clockSecsRemain < 1) { if (clockMinsRemain >= 1) { clockTimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Time is up! \u23f0 \u23f0 \u23f0', '', yellow, '', 'bold'); timerDesc = ''; } } else { clockSecsRemain--; cb.setTimeout(clockTimerSec, 1000); } } } function clockAddTime(clocktimetoadd, u) { clockStopTime = new Date(clockStopTime.getTime() + clocktimetoadd * 60000); cb.sendNotice(u + ' has added ' + clocktimetoadd + ' minute' + (clocktimetoadd === 1 || clocktimetoadd === -1 ? '' : 's') + ' to the timer.',cb.room_slug,'','', 'bold'); cb.sendNotice(clocktimetoadd + ' minute' + (clocktimetoadd === 1 || clocktimetoadd === -1 ? ' has' : 's have') + ' been added to the timer. ' + clockTimeLeft(),'',yellow,'', 'bold'); clockMinsRemain = clockMinsRemain + clocktimetoadd; if (clockMinsRemain > 0) { displaySeconds = false; } else { displaySeconds = true; } } function clockTimeCal() { clockStartTime = new Date(); return clockStopTime - clockStartTime.getTime(); } function stopClockTimer(mod) { clockStopTime = new Date(); clockStopping = true; clockMinsRemain = 0; clockSecsRemain = 0; if(mod != null) { cb.sendNotice(mod + ' has stopped the timer.','',yellow,'', 'bold'); } } function clockTimeLeft(user) { var clockTimeLeft = clockTimeCal(); var clockMS = clockTimeLeft % 1000; var clockSeconds = ((clockTimeLeft - clockMS) % 60000); var clockMinutes = ((clockTimeLeft - clockSeconds - clockMS) % 3600000); var clockHours = (clockTimeLeft - clockMinutes - clockSeconds - clockMS); clockSeconds = clockSeconds / 1000; clockMinutes = clockMinutes / 60000; clockHours = clockHours / 3600000; if (clockHours > 0) { return clockHours + ' hour' + (clockHours > 1 ? 's' : '') + ' and ' + clockMinutes + ' minute' + (clockMinutes > 1 ? 's' : '') + ' remaining on the timer.'; } else if (clockMinutes > 0 && clockSeconds === 0) { return clockMinutes + ' minute' + (clockMinutes > 1 ? 's' : '') + " remaining on the timer."; } else if (clockMinutes > 0) { return clockMinutes + ' minute' + (clockMinutes > 1 ? 's' : '') + ' and ' + clockSeconds + ' second' + (clockSeconds > 1 ? 's' : '') + ' remaining on the timer.'; } else { return clockSeconds + ' second' + (clockSeconds > 1 ? 's' : '') + ' remaining on the timer.'; } } //********** Chat Notice Functions ************** function sendPublicNotice (message, user, type) { if (message != null) { if (message != '' || message != ' ' || message != '\u00a0') { setNoticeColor(); switch (type) { case 'div': cb.sendNotice(dashLine80 + '\n\u25ba ' + message.capitalize() + '\n' + dashLine80, '', '', noticeTextColor, 'bold'); break; case 'divh': cb.sendNotice(dashLine80 + '\n\u25ba ' + message.capitalize() + '\n' + dashLine80, '', noticeBgColor, noticeTextColor, 'bold'); break; case 'h': cb.sendNotice('\u25ba ' + message.capitalize(), '', noticeBgColor, noticeTextColor, 'bold'); break; case '': cb.sendNotice('\u25ba ' + message.capitalize(), '', '', noticeTextColor, 'bold'); break; } } else { cb.sendNotice('You can\'t send a blank message. Type a message and try again.', user, green); } } else { cb.sendNotice('You can\'t send a blank message. Type a message and try again.', user, green); } } //********** PM Functions ************** var TMgreenB = "#d2f8d2"; /* Background Highlighting used for tm */ var TMgreenF = "#007e00"; /* Text Color used for tm */ var BCpurpleB = "#f3e0f1"; /* Background Highlighting used for bc */ var BCpurpleF = "#752d6e"; /* Text Color used for bc */ var TBMblueB = "#dff1f3"; /* Background Highlighting used for tbm */ var TBMblueF = "#1a1aff"; /* Text Color used for tbm */ var PMaquaB = "#f2ebd4"; /* Background Highlighting used for pm */ var PMaquaF = "#008181"; /* Text Color used for pm */ function sendPrivateNotice (message, user, type, dest) { if (message != null) { if (message != '' || message != ' ' || message != '\u00a0') { switch (type) { case 'tm': if (user == cb.room_slug) { cb.sendNotice('\u261b You to mods: ' + message, cb.room_slug, TMgreenB, TMgreenF, "bold"); cb.sendNotice('\u261b ' + cb.room_slug + ' to mods: ' + message, "", TMgreenB, TMgreenF, "bold", "red"); } else { cb.sendNotice('\u261b ' + user + ' to mods: ' + message, "", TMgreenB, TMgreenF, "bold", "red"); } break; case 'bc': cb.sendNotice('\u261b ' + user + ' to you: ' + message, cb.room_slug, BCpurpleB, BCpurpleF, "bold"); cb.sendNotice('\u261b ' + 'You to ' + cb.room_slug + ': ' + message, user, BCpurpleB, BCpurpleF, "bold"); break; case 'tbm': if (user == cb.room_slug) { cb.sendNotice('\u261b You to mods: ' + message, cb.room_slug, TBMblueB, TBMblueF, "bold"); cb.sendNotice('\u261b ' + cb.room_slug + ' to mods: ' + message, "", TBMblueB, TBMblueF, "bold", "red"); } else { cb.sendNotice('\u261b ' + user + ' to ' + cb.room_slug + ' and mods: ' + message, "", TBMblueB, TBMblueF, "bold", "red"); cb.sendNotice('\u261b ' + user + ' to you and mods: ' + message, cb.room_slug, TBMblueB, TBMblueF, "bold"); } break; case 'pm': if (dest != null && (dest != "" || dest != " " || dest != "\u00a0")) { cb.sendNotice('\u261b ' + user + ': ' + message, dest, PMaquaB, PMaquaF, "bold"); cb.sendNotice('\u261b ' + 'You to ' + dest + ': ' + message, user, PMaquaB, PMaquaF, "bold"); pmArray[findPM(dest)][1] = user; } else { cb.sendNotice("You didn't specify who should receive the message.\nPlease enter a username and try again."); } break; } } else { cb.sendNotice('You can\'t send a blank message. Type a message and try again.', user, green); } } else { cb.sendNotice('You can\'t send a blank message. Type a message and try again.', user, green); } } function findPM(user) { for(var i = 0; i < pmArray.length; i++) { if(pmArray[i][0] == user) { break; } } if(i == pmArray.length) { pmArray[numPMs] = new Array; pmArray[numPMs][0] = user; pmArray[numPMs][1] = ''; numPMs++; findPM(user); } return i; } function sendReply(message, from) { if(pmArray[findPM(from)][1] != '') { var fullmsg = from + ': '; var msg = ''; for(var i = 1; i < message.length; i++) { if(i == 1) { msg += message[i]; fullmsg += message[i]; } else { msg += ' ' + message[i]; fullmsg += ' ' + message[i]; } } replyTo = pmArray[findPM(from)][1] pmArray[findPM(replyTo)][1] = from; cb.sendNotice('\u261b ' + fullmsg, replyTo, PMaquaB, PMaquaF, "bold"); cb.sendNotice('\u261b You to ' + replyTo + ': ' + msg, from, PMaquaB, PMaquaF, "bold"); } else { cb.sendNotice("No one has PM'd you.", from, green); } } //********** Notifier Functions ************** function showNotifier() { cb.setTimeout(notifierTimer,cb.settings.notifierInterval*60000); } function setNoticeColor() { if (cb.settings.notifiersTextColor == "Custom") { noticeTextColor = checkTextColor(cb.settings.notifiersTextCustColor); if (noticeTextColor == "default") { cb.sendNotice("Notifiers - Error while setting the text color. It has to be in a HEX format. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); noticeTextColor = "#FFFFFF"; } } else { noticeTextColor = checkTextColor(cb.settings.notifiersTextColor); } if (cb.settings.notifiersBgColor == "Custom") { noticeBgColor = checkBgColor(cb.settings.notifiersBgCustColor); if (noticeBgColor == "default") { cb.sendNotice("Notifiers - Error while setting the background color. It has to be in a HEX format. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); noticeBgColor = "#FFFFFF"; } } else { noticeBgColor = checkBgColor(cb.settings.notifiersBgColor); } } function notifierTimer() { if(notifierToggle == 1) { setNoticeColor(); rotcnt++; if (rotcnt > 5) { rotcnt = 1; } switch (rotcnt) { case (1): { if(notifierMessage1 == '' || notifierMessage1 == null || rotcnt > 5) { rotcnt = 0; } else { cb.sendNotice("\u25ba " + notifierMessage1, '', noticeBgColor, noticeTextColor, "bold"); } } break; case (2): { if(notifierMessage2 == '' || notifierMessage2 == null || rotcnt > 5) { rotcnt = 0; } else { cb.sendNotice("\u25ba " + notifierMessage2, '', noticeBgColor, noticeTextColor, "bold"); } } break; case (3): { if(notifierMessage3 == '' || notifierMessage3 == null || rotcnt > 5) { rotcnt = 0; } else { cb.sendNotice("\u25ba " + notifierMessage3, '', noticeBgColor, noticeTextColor, "bold"); } } break; case (4): { if(notifierMessage4 == '' || notifierMessage4 == null || rotcnt > 5) { rotcnt = 0; } else { cb.sendNotice("\u25ba " + notifierMessage4, '', noticeBgColor, noticeTextColor, "bold"); } } break; case (5): { if(notifierMessage5 == '' || notifierMessage5 == null || rotcnt > 5) { rotcnt = 0; } else { cb.sendNotice("\u25ba " + notifierMessage5, '', noticeBgColor, noticeTextColor, "bold"); } } break; } showNotifier(); } } function setNotifierToggle(option, mod) { if(option == 'on') { if(notifierToggle == 1) { cb.sendNotice('The Notifier toggle is already turned on.',mod,green); } else { notifierToggle = 1; rotcnt = 0; notifierTimer(); cb.sendNotice('You have enabled the display of the rotating notifier messages.',mod,green); } } else if(option == 'off') { if(notifierToggle == 0) { cb.sendNotice('The Notifier toggle is already turned off.',mod,green); } else { notifierToggle = 0; cb.sendNotice('You have disabled the display of the rotating notifier messages.',mod,green); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usenotifier.\nType /fbhelp notifier to see how to use /usenotifier.',mod,green); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usenotifier.\nType /fbhelp notifier to see how to use /usenotifier.',mod,green); } } function setTipCountToggle(option, mod) { if(option == 'on') { if(tipCountToggle == 1) { cb.sendNotice('The Tip Count display is already turned on.',mod,green); } else { tipCountToggle = 1; cb.sendNotice('You have enabled the Tip Count display next to each user name in the chat.',mod,green); } } else if(option == 'off') { if(tipCountToggle == 0) { cb.sendNotice('The Tip Count display is already turned off.',mod,green); } else { tipCountToggle = 0; cb.sendNotice('You have disabled the Tip Count display.',mod,green); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usetipcount.\nType /fbhelp usetipcount to see how to use /usetipcount.',mod,green); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usetipcount.\nType /fbhelp usetipcount to see how to use /usetipcount.',mod,green); } } // *************************** Tip Menu Functions ************************ function setTipMenuToggle(option, mod) { if(option == 'on') { if(tipMenuToggle == 1) { cb.sendNotice('Tip Menu 1 is already turned on.',mod,green); } else { tipMenuToggle = 1; initMenu(mod); cb.sendNotice('You have enabled Tip Menu 1.',mod,green); cb.sendNotice(' ' + mod + ' has enabled Tip Menu 1. You control the action by tipping for selections from the menu!',"",green,"","bold"); } } else if(option == 'off') { if(tipMenuToggle == 0) { cb.sendNotice('Tip Menu 1 is already turned off.',mod,green); } else { tipMenuToggle = 0; TIPMENU.tipMenuPrice = []; TIPMENU.tipMenuItem = []; cb.sendNotice('You have disabled Tip Menu 1.',mod,green); cb.sendNotice(' ' + mod + ' has disabled Tip Menu 1. You can no longer tip for selections from Menu 1.',"",green,"","bold"); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usemenu.\nType /fbhelp tipmenu to see how to use /usemenu.',mod,green); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usemenu.\nType /fbhelp tipmenu to see how to use /usemenu.',mod,green); } } function setTipMenu2Toggle(option, mod) { if(option == 'on') { if(tipMenu2Toggle == 1) { cb.sendNotice('Tip Menu 2 is already turned on.',mod,green); } else { tipMenu2Toggle = 1; initMenu2(mod); cb.sendNotice('You have enabled Tip Menu 2.',mod,green); cb.sendNotice(' ' + mod + ' has enabled Tip Menu 2. You control the action by tipping for selections from the menu!',"",green,"","bold"); } } else if(option == 'off') { if(tipMenu2Toggle == 0) { cb.sendNotice('Tip Menu 2 is already turned off.',mod,green); } else { tipMenu2Toggle = 0; TIPMENU2.tipMenuPrice = []; TIPMENU2.tipMenuItem = []; cb.sendNotice('You have disabled Tip Menu 2.',mod,green); cb.sendNotice(' ' + mod + ' has disabled Tip Menu 2. You can no longer tip for selections from Menu 2.',"",green,"","bold"); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usemenu2.\nType /fbhelp tipmenu to see how to use /usemenu.',mod,green); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usemenu2.\nType /fbhelp tipmenu to see how to use /usemenu.',mod,green); } } function initMenu(mod) { if (cb.settings.menutxtcolor1 == "Custom") { TIPMENU.txtColor1 = checkTextColor(cb.settings.menuCustTxtColor1); if (TIPMENU.txtColor1 == "default") { cb.sendNotice("Tip Menu - Error while setting the text color, it has to be in a HEX format, such as #0629AC. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); TIPMENU.txtColor1 = '#0629AC'; } } else { TIPMENU.txtColor1 = checkTextColor(cb.settings.menutxtcolor1); } if (cb.settings.menubgcolor1 == "Custom") { TIPMENU.bgColor1 = checkBgColor(cb.settings.menuCustBgColor1); if (TIPMENU.bgColor1 == 'default') { cb.sendNotice("Tip Menu - Error while setting the background color. It has to be in a HEX format, such as #FFFFFF. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); TIPMENU.bgColor1 = '#FFFFFF'; } } else { TIPMENU.bgColor1 = checkBgColor(cb.settings.menubgcolor1); } if (cb.settings.listSplit == 'Split the list in 2') { if (cb.settings.menutxtcolor2 === "Custom") { TIPMENU.txtColor2 = checkTextColor(cb.settings.menuCustTxtColor2); if (TIPMENU.txtColor2 == "default") { cb.sendNotice("Tip Menu part 2 - Error while setting the text color for second half of menu, it has to be in a HEX format, such as #0629AC. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); TIPMENU.txtColor2 = '#0629AC'; } } else { TIPMENU.txtColor2 = checkTextColor(cb.settings.menutxtcolor2); } if (cb.settings.menubgcolor2 == "Custom") { TIPMENU.bgColor2 = checkBgColor(cb.settings.menuCustBgColor2); if (TIPMENU.bgColor2 == 'default') { cb.sendNotice("Tip Menu part 2 - Error while setting the background color for second half of menu, it has to be in a HEX format, such as #FFFFFF. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); TIPMENU.bgColor2 = '#FFFFFF'; } } else { TIPMENU.bgColor2 = checkBgColor(cb.settings.menubgcolor2); } } displayMenuTimer(); setSepChar(); let maxItems = 40; for (let j = 0; j <= maxItems; j++) { if (cb.settings['menuitem' + j] !== '' && cb.settings['menuitemprice' + j] > 0) { if (cbjs.arrayContains(TIPMENU.tipMenuPrice, cb.settings['menuitemprice' + j])) { cb.sendNotice("Tip Menu - " + cb.settings['menuitemprice' + j] + " is already on the menu. It is recommended to have different price for each item.", cb.room_slug, "#FFFFFF", "#FF0000"); } TIPMENU.tipMenuPrice.push(cb.settings['menuitemprice' + j]); TIPMENU.tipMenuItem.push(cb.settings['menuitem' + j]); priceChecker('add','Tip Menu Option: '+(cb.settings['menuitem' + j]), (cb.settings['menuitemprice' + j]), mod); } } menuSanitize(); displayMenu(); } function initMenu2(mod) { if (cb.settings.menutxtcolor1 == "Custom") { TIPMENU2.txtColor1 = checkTextColor(cb.settings.menuCustTxtColor1); if (TIPMENU2.txtColor1 == "default") { cb.sendNotice("Tip Menu 2 - Error while setting the text color, it has to be in a HEX format, such as #0629AC. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); TIPMENU2.txtColor1 = '#0629AC'; } } else { TIPMENU2.txtColor1 = checkTextColor(cb.settings.menutxtcolor1); } if (cb.settings.menubgcolor1 == "Custom") { TIPMENU2.bgColor1 = checkBgColor(cb.settings.menuCustBgColor1); if (TIPMENU2.bgColor1 == 'default') { cb.sendNotice("Tip Menu 2 - Error while setting the background color. It has to be in a HEX format, such as #FFFFFF. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); TIPMENU2.bgColor1 = '#FFFFFF'; } } else { TIPMENU2.bgColor1 = checkBgColor(cb.settings.menubgcolor1); } if (cb.settings.listSplit == 'Split the list in 2') { if (cb.settings.menutxtcolor2 === "Custom") { TIPMENU2.txtColor2 = checkTextColor(cb.settings.menuCustTxtColor2); if (TIPMENU2.txtColor2 == "default") { cb.sendNotice("Tip Menu part 2 - Error while setting the text color for second half of menu, it has to be in a HEX format, such as #0629AC. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); TIPMENU2.txtColor2 = '#0629AC'; } } else { TIPMENU2.txtColor2 = checkTextColor(cb.settings.menutxtcolor2); } if (cb.settings.menubgcolor2 == "Custom") { TIPMENU2.bgColor2 = checkBgColor(cb.settings.menuCustBgColor2); if (TIPMENU2.bgColor2 == 'default') { cb.sendNotice("Tip Menu part 2 - Error while setting the background color for second half of menu, it has to be in a HEX format, such as #FFFFFF. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); TIPMENU2.bgColor2 = '#FFFFFF'; } } else { TIPMENU2.bgColor2 = checkBgColor(cb.settings.menubgcolor2); } } displayMenuTimer2(); setSepChar2(); let maxItems = 20; for (let j = 0; j <= maxItems; j++) { if (cb.settings['menu2item' + j] !== '' && cb.settings['menu2itemprice' + j] > 0) { if (cbjs.arrayContains(TIPMENU2.tipMenuPrice, cb.settings['menu2itemprice' + j])) { cb.sendNotice("Tip Menu 2 - " + cb.settings['menu2itemprice' + j] + " is already on the menu. It is recommended to have different price for each item.", cb.room_slug, "#FFFFFF", "#FF0000"); } TIPMENU2.tipMenuPrice.push(cb.settings['menu2itemprice' + j]); TIPMENU2.tipMenuItem.push(cb.settings['menu2item' + j]); priceChecker('add','Tip Menu 2 Option: '+(cb.settings['menu2item' + j]), (cb.settings['menu2itemprice' + j]), mod); } } menuSanitize2(); displayMenu2(); } function displayMenu() { if(tipMenuToggle == 1) { if (cb.settings.chatNotice === 'Only display the short notice' && !TIPMENU.initToken) { cb.sendNotice('Tip menu is active. To see the full tip menu type: /tipmenu', '', TIPMENU.bgColor1, TIPMENU.txtColor1, "bold"); } else if (TIPMENU.menuPart1 !== 'Tip Menu 1 Part 1: \n' && !TIPMENU.initToken) { if (TIPMENU.menuToken === 1) { cb.sendNotice(TIPMENU.menuPart1, '', TIPMENU.bgColor1, TIPMENU.txtColor1, "bold"); TIPMENU.menuToken = 2; } else if (TIPMENU.menuToken === 2) { cb.sendNotice(TIPMENU.menuPart2, '', TIPMENU.bgColor2, TIPMENU.txtColor2, "bold"); TIPMENU.menuToken = 1; } } else if (TIPMENU.tipMenu !== 'Tip Menu 1: ') { cb.sendNotice(TIPMENU.tipMenu, '', TIPMENU.bgColor1, TIPMENU.txtColor1, "bold"); if (TIPMENU.initToken) { TIPMENU.initToken = false; } } else { cb.sendNotice("Something went wrong with the menu.", '', "#FFFFFF", "#FF0000", "bold"); } cb.setTimeout(displayMenu, TIPMENU.menuDspIntTime); } } function displayMenu2() { if(tipMenu2Toggle == 1) { if (cb.settings.chatNotice === 'Only display the short notice' && !TIPMENU2.initToken) { cb.sendNotice('Tip Menu 2 is active. To see the full tip menu type: /tipmenu', '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, "bold"); } else if (TIPMENU2.menuPart1 !== 'Tip Menu 2 Part 1: \n' && !TIPMENU2.initToken) { if (TIPMENU2.menuToken === 1) { cb.sendNotice(TIPMENU2.menuPart1, '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, "bold"); TIPMENU2.menuToken = 2; } else if (TIPMENU2.menuToken === 2) { cb.sendNotice(TIPMENU2.menuPart2, '', TIPMENU2.bgColor2, TIPMENU2.txtColor2, "bold"); TIPMENU2.menuToken = 1; } } else if (TIPMENU2.tipMenu !== 'Tip Menu 2: ') { cb.sendNotice(TIPMENU2.tipMenu, '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, "bold"); if (TIPMENU2.initToken) { TIPMENU2.initToken = false; } } else { cb.sendNotice("Something went wrong with menu 2.", '', "#FFFFFF", "#FF0000", "bold"); } cb.setTimeout(displayMenu2, TIPMENU2.menuDspIntTime); } } function displayMenuTimer() { let timer = parseFloat(cb.settings.menuDspInt); if (timer < 1) { cb.sendNotice("Tip Menu - Time lapse is too short. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); timer = 3; } timer *= 60000; timer = parseInt(timer); TIPMENU.menuDspIntTime = timer; } function displayMenuTimer2() { let timer = parseFloat(cb.settings.menuDspInt); if (timer < 1) { cb.sendNotice("Tip Menu 2 - Time lapse is too short. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); timer = 3; } timer *= 60000; timer = parseInt(timer); TIPMENU2.menuDspIntTime = timer; } function menuSanitize() { TIPMENU.tipMenu = 'Tip Menu: '; TIPMENU.menuPart1 = 'Tip Menu 1 Part 1: \n'; TIPMENU.menuPart2 = 'Tip Menu 1 Part 2: \n'; let menuArray = []; let menuArray1 = []; let menuArray2 = []; let sorted = []; let menuL = TIPMENU.tipMenuPrice.length; for (let i = 0; i < menuL; i++) { sorted.push({ "prices": TIPMENU.tipMenuPrice[i], "id": i }); } if (cb.settings.listSort !== 'Do not sort the list') { sorted.sort(function(a, b) { return a.prices - b.prices; }); if (cb.settings.listSort === 'Descending') { sorted.reverse(); } } for (let j = 0; j < sorted.length; j++) { if (TIPMENU.tipMenuPrice[sorted[j].id] !== 0) { menuArray.push(TIPMENU.tipMenuItem[sorted[j].id] + ' (' + TIPMENU.tipMenuPrice[sorted[j].id] + ') '); } } TIPMENU.tipMenu += menuArray.join(TIPMENU.sepChar); if (cb.settings.listSplit === 'Split the list in 2') { if (menuArray.length < 10) { cb.sendNotice("Tip Menu - Error - The menu has less than 10 items, it will not be split.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); } else { let msglength1 = 0; let msgHalf = (TIPMENU.tipMenu.length - 9) / 2; for (let k = 0; k < sorted.length; k++) { if (TIPMENU.tipMenuPrice[sorted[k].id] !== 0) { if (msglength1 < msgHalf) { menuArray1.push(TIPMENU.tipMenuItem[sorted[k].id] + ' (' + TIPMENU.tipMenuPrice[sorted[k].id] + ') '); msglength1 = menuArray1.join(TIPMENU.sepChar).length; } else { menuArray2.push(TIPMENU.tipMenuItem[sorted[k].id] + ' (' + TIPMENU.tipMenuPrice[sorted[k].id] + ') '); } } } TIPMENU.menuPart1 += menuArray1.join(TIPMENU.sepChar) + '\n To see the full menu type /tipmenu.'; TIPMENU.menuPart2 += menuArray2.join(TIPMENU.sepChar) + '\n To see the full menu type /tipmenu.'; } } TIPMENU.menuLength = TIPMENU.tipMenuPrice.length; if (TIPMENU.tipMenu === 'Tip Menu: ') { cb.sendNotice('Error - No menu items found', '', '', TIPMENU.txtColor1, "bold"); } } function menuSanitize2() { TIPMENU2.tipMenu = 'Tip Menu 2: '; TIPMENU2.menuPart1 = 'Tip Menu 2 Part 1: \n'; TIPMENU2.menuPart2 = 'Tip Menu 2 Part 2: \n'; let menu2Array = []; let menu2Array1 = []; let menu2Array2 = []; let sorted2 = []; let menuL = TIPMENU2.tipMenuPrice.length; for (let i = 0; i < menuL; i++) { sorted2.push({ "prices": TIPMENU2.tipMenuPrice[i], "id": i }); } if (cb.settings.listSort !== 'Do not sort the list') { sorted2.sort(function(a, b) { return a.prices - b.prices; }); if (cb.settings.listSort === 'Descending') { sorted2.reverse(); } } for (let j = 0; j < sorted2.length; j++) { if (TIPMENU2.tipMenuPrice[sorted2[j].id] !== 0) { menu2Array.push(TIPMENU2.tipMenuItem[sorted2[j].id] + ' (' + TIPMENU2.tipMenuPrice[sorted2[j].id] + ') '); } } TIPMENU2.tipMenu += menu2Array.join(TIPMENU2.sepChar); if (cb.settings.listSplit === 'Split the list in 2') { if (menu2Array.length < 10) { cb.sendNotice("Tip Menu - Error - The menu has less than 10 items, it will not be split.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); } else { let msglength1 = 0; let msgHalf = (TIPMENU2.tipMenu.length - 9) / 2; for (let k = 0; k < sorted2.length; k++) { if (TIPMENU2.tipMenuPrice[sorted2[k].id] !== 0) { if (msglength1 < msgHalf) { menu2Array1.push(TIPMENU2.tipMenuItem[sorted2[k].id] + ' (' + TIPMENU2.tipMenuPrice[sorted2[k].id] + ') '); msglength1 = menu2Array1.join(TIPMENU2.sepChar).length; } else { menu2Array2.push(TIPMENU2.tipMenuItem[sorted2[k].id] + ' (' + TIPMENU2.tipMenuPrice[sorted2[k].id] + ') '); } } } TIPMENU2.menuPart1 += menu2Array1.join(TIPMENU2.sepChar) + '\n To see the full menu type /tipmenu.'; TIPMENU2.menuPart2 += menu2Array2.join(TIPMENU2.sepChar) + '\n To see the full menu type /tipmenu.'; } } TIPMENU2.menuLength = TIPMENU2.tipMenuPrice.length; if (TIPMENU2.tipMenu === 'Tip Menu 2: ') { cb.sendNotice('Error - No menu items found', '', '', TIPMENU2.txtColor1, "bold"); } } function setSepChar() { if (cb.settings.sepchar == "Custom") { if (cb.settings.sepcharcustom) { TIPMENU.sepChar = cb.settings.sepcharcustom; } else { TIPMENU.sepChar = "|"; } } else { TIPMENU.sepChar = checkSepChar(cb.settings.sepchar) } TIPMENU.sepChar += " "; } function setSepChar2() { if (cb.settings.sepchar == "Custom") { if (cb.settings.sepcharcustom) { TIPMENU2.sepChar = cb.settings.sepcharcustom; } else { TIPMENU2.sepChar = "|"; } } else { TIPMENU2.sepChar = checkSepChar(cb.settings.sepchar) } TIPMENU2.sepChar += " "; } // *************************** Positions Tip Menu Functions ************************ function setPosTipMenuToggle(option, mod) { if(option == 'on') { if(posTipMenuToggle == 1) { cb.sendNotice('The Positions Tip Menu is already enabled.',mod,green); } else { posTipMenuToggle = 1; cb.sendNotice('You have enabled the Positions Tip Menu.',mod,green); cb.sendNotice(' ' + mod + ' has enabled the Positions Tip Menu. You control the action by tipping for your favorite position!',"",green,"","bold"); initPosMenu(); } } else if(option == 'off') { if(posTipMenuToggle == 0) { cb.sendNotice('The Positions Tip Menu is already disabled.',mod,green); } else { posTipMenuToggle = 0; POSTIPMENU.posTipMenuPrice = []; POSTIPMENU.posTipMenuItem = []; cb.sendNotice('You have disabled the Positions Tip Menu.',mod,green); cb.sendNotice(' ' + mod + ' has disabled the Positions Tip Menu. You can no longer tip for positions.',"",green,"","bold"); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /useposmenu.\nType /fbhelp positions to see how to use /usepostipmenu.',mod,green); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /useposmenu.\nType /fbhelp positions to see how to use /usepostipmenu.',mod,green); } } function initPosMenu(mod) { let maxItems = 8; if (cb.settings.posMenuTxtColor === "Custom") { POSTIPMENU.posTxtColor = checkTextColor(cb.settings.posMenuCustTxtColor); if (POSTIPMENU.posTxtColor === "default") { cb.sendNotice("Positions Menu - Error while setting the text color. It has to be in a HEX format. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); POSTIPMENU.posTxtColor = '#FFFFFF'; } } else { POSTIPMENU.posTxtColor = checkTextColor(cb.settings.posMenuTxtColor); } if (cb.settings.posMenuBgColor === "Custom") { POSTIPMENU.posBgColor = checkBgColor(cb.settings.posMenuCustBgColor); if (POSTIPMENU.posBgColor === 'default') { cb.sendNotice("Positions Menu - Error while setting the background color. It has to be in a HEX format. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); POSTIPMENU.posBgColor = '#0629AC'; } } else { POSTIPMENU.posBgColor = checkBgColor(cb.settings.posMenuBgColor); } displayPosMenuTimer(); setPosSepChar(); for (let j = 0; j <= maxItems; j++) { if (cb.settings['posMenuItem' + j] !== '' && cb.settings['posMenuItemPrice' + j] > 0) { if (cbjs.arrayContains(POSTIPMENU.posTipMenuPrice, cb.settings['posMenuItemPrice' + j])) { cb.sendNotice("Positions Tip Menu - " + cb.settings['posMenuItemPrice' + j] + " is already on the menu. It is recommended to have different price for each item.", cb.room_slug, "#FFFFFF", "#FF0000"); } POSTIPMENU.posTipMenuPrice.push(cb.settings['posMenuItemPrice' + j]); POSTIPMENU.posTipMenuItem.push(cb.settings['posMenuItem' + j]); priceChecker('add','Positions Menu Option: '+(cb.settings['posMenuItem' + j]), (cb.settings['posMenuItemPrice' + j]),mod); } } cb.sendNotice('Type /fbhelp tipmenu to see all the Tip menu commands.', "", "", "", "bold"); posMenuSanitize(); displayPosMenu(); } function displayPosMenu() { if(posTipMenuToggle == 1) { if (cb.settings.posChatNotice === 'Only display the short notice' && !POSTIPMENU.posInitToken) { cb.sendNotice('Positions Tip menu is active. To see the full tip menu type: /postipmenu', '', POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor, "bold"); } else if (POSTIPMENU.posTipMenu !== 'Positions Tip Menu: \n' && !POSTIPMENU.posInitToken) { cb.sendNotice(POSTIPMENU.posTipMenu, '', POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor, "bold"); } else if (POSTIPMENU.posTipMenu !== 'Positions Tip Menu: ') { cb.sendNotice(POSTIPMENU.posTipMenu, '', POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor, "bold"); if (POSTIPMENU.posInitToken) { POSTIPMENU.posInitToken = false; } } else { cb.sendNotice("Something went wrong with the positions menu.", '', "#FFFFFF", "#FF0000", "bold"); } cb.setTimeout(displayPosMenu, POSTIPMENU.posMenuDspIntTime); } } function displayPosMenuTimer() { let postimer = parseFloat(cb.settings.posMenuInterval); if (postimer < 1) { cb.sendNotice("Positions Tip Menu - Time interval is less than 1 minute. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); postimer = 3; } postimer *= 60000; postimer = parseInt(postimer); POSTIPMENU.posMenuDspIntTime = postimer; } function posMenuSanitize() { POSTIPMENU.posTipMenu = 'Positions Tip Menu: '; let posMenuArray = []; let posSorted = []; let posMenuL = POSTIPMENU.posTipMenuPrice.length; for (let i = 0; i < posMenuL; i++) { posSorted.push({ "posprices": POSTIPMENU.posTipMenuPrice[i], "posid": i }); } if (cb.settings.posListSort !== 'Do not sort the list') { posSorted.sort(function(a, b) { return a.posprices - b.posprices; }); if (cb.settings.posListSort === 'Descending') { posSorted.reverse(); } } for (let j = 0; j < posSorted.length; j++) { if (POSTIPMENU.posTipMenuPrice[posSorted[j].posid] !== 0) { posMenuArray.push(POSTIPMENU.posTipMenuItem[posSorted[j].posid] + ' (' + POSTIPMENU.posTipMenuPrice[posSorted[j].posid] + ') '); } } POSTIPMENU.posTipMenu += posMenuArray.join(POSTIPMENU.posSepChar); POSTIPMENU.posMenuLength = POSTIPMENU.posTipMenuPrice.length; if (POSTIPMENU.posTipMenu === 'Positions Tip Menu: ') { cb.sendNotice('Error - No positions menu items found', '', '', POSTIPMENU.posTxtColor, "bold"); } } function setPosSepChar() { if (cb.settings.posSepChar == "Custom") { if (cb.settings.posSepCharCustom) { POSTIPMENU.posSepChar = cb.settings.posSepCharCustom; } else { POSTIPMENU.posSepChar = "|"; } } else { POSTIPMENU.posSepChar = checkSepChar(cb.settings.posSepChar) } POSTIPMENU.posSepChar += " "; } // *************************** Lush Menu Functions ************************ function setLushMenuToggle(option, mod) { if(option == 'on') { if(lushMenuToggle == 1) { cb.sendNotice('The ' + whichToy + ' Menu is already enabled.',mod,green); } else { lushMenuToggle = 1; cb.sendNotice('You have enabled the Toy Menu.',mod,green); cb.sendNotice(' ' + mod + ' has enabled the ' + whichToy + ' Menu. Use the tip ranges on the menu to make the toy vibrate!',"",green,"","bold"); initLushMenu(); } } else if(option == 'off') { if(lushMenuToggle == 0) { cb.sendNotice('The ' + whichToy + ' Menu is already disabled.',mod,green); } else { lushMenuToggle = 0; LUSHMENU.lushMenuLevel = []; cb.sendNotice('You have disabled the ' + whichToy + ' Menu.',mod,green); cb.sendNotice(' ' + mod + ' has disabled the ' + whichToy + ' Menu.',"",green,"","bold"); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /uselushmenu.\nType /fbhelp tipmenu to see how to use /uselushmenu.',mod,green); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /uselushmenu.\nType /fbhelp tipmenu to see how to use /uselushmenu.',mod,green); } } function initLushMenu() { if (cb.settings.lushMenuTxtColor === "Custom") { LUSHMENU.lushTxtColor = checkTextColor(cb.settings.lushMenuCustTxtColor); if (LUSHMENU.lushTxtColor === "default") { cb.sendNotice(whichToy + ' Menu - Error while setting the text color. It has to be in a HEX format. Using default value.', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); LUSHMENU.lushTxtColor = '#FFFFFF'; } } else { LUSHMENU.lushTxtColor = checkTextColor(cb.settings.lushMenuTxtColor); } if (cb.settings.lushMenuBgColor === "Custom") { LUSHMENU.lushBgColor = checkBgColor(cb.settings.lushMenuCustBgColor); if (LUSHMENU.lushBgColor === 'default') { cb.sendNotice(whichToy + ' Menu - Error while setting the background color. It has to be in a HEX format. Using default value.', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); LUSHMENU.lushBgColor = '#0629AC'; } } else { LUSHMENU.lushBgColor = checkBgColor(cb.settings.lushMenuBgColor); } displayLushMenuTimer(); setLushMenu(); displayLushMenu(); } function setLushMenu() { LUSHMENU.lushMenuLevel = []; LUSHMENU.lushMenu = ""; for (let j = 0; j <= 13; j++) { if (cb.settings['lushMenuLevel' + j] !== '') { LUSHMENU.lushMenuLevel.push(cb.settings['lushMenuLevel' + j]); } } switch (whichToy) { case "Lush": { LUSHMENU.lushMenu = '-------- :lushsm \u2665 :lushsm \u2665 :lushsm LUSH MENU :lushsm \u2665 :lushsm \u2665 :lushsm --------'; } break; case "Domi": { LUSHMENU.lushMenu = '-------- :domism \u2665 :domism \u2665 :domism DOMI MENU :domism \u2665 :domism \u2665 :domism --------'; } break; case "Nora": { LUSHMENU.lushMenu = '-------- :norasm \u2665 :norasm \u2665 :norasm NORA MENU :norasm \u2665 :norasm \u2665 :norasm --------'; } break; case "Hush": { LUSHMENU.lushMenu = '-------- :hushsm \u2665 :hushsm \u2665 :hushsm HUSH MENU :hushsm \u2665 :hushsm \u2665 :hushsm --------'; } break; case "Osci": { LUSHMENU.lushMenu = '-------- :oscism \u2665 :oscism \u2665 :oscism OSCI MENU :oscism \u2665 :oscism \u2665 :oscism --------'; } break; } LUSHMENU.lushMenu += LUSHMENU.lushMenuLevel.join('\n'); } function displayLushMenu() { if(lushMenuToggle == 1) { cb.sendNotice(LUSHMENU.lushMenu, '', LUSHMENU.lushBgColor, LUSHMENU.lushTxtColor, "bold"); cb.setTimeout(displayLushMenu, LUSHMENU.lushMenuDspIntTime); } } function displayLushMenuTimer() { let lushtimer = parseFloat(cb.settings.lushMenuInterval); if (lushtimer < 1) { cb.sendNotice(whichToy + ' Menu - Time interval is less than 1 minute. Using default value.', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); lushtimer = 3; } lushtimer *= 60000; lushtimer = parseInt(lushtimer); LUSHMENU.lushMenuDspIntTime = lushtimer; } // *************************** Token Poll Functions ************************ function setTokenPollToggle(option, mod) { setPollColors(); if(option == 'on') { if(tokenPollToggle == 1) { cb.sendNotice('The Token Poll is already enabled.', mod, green); } else { tokenPollToggle = 1; initTokenPoll(mod); cb.sendNotice('You have enabled the Token Poll.', mod, green); pollmsg("a", "", mod + " has enabled the Token Poll feature. You can now vote in the poll."); } } else if(option == 'off') { if(tokenPollToggle == 0) { cb.sendNotice('The Token Poll is already disabled.', mod, green); } else { tokenPollToggle = 0; pollArrayAmount = []; pollArrayLabel = []; pollArrayVotes = []; cb.sendNotice('You have disabled the Token Poll.', mod, green); pollmsg("a", "", mod + " has disabled the Token Poll feature. Voting will no longer be tracked."); pollRunning = false; } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usepoll.\nType /fbhelp tokenpoll to see how to use /usepoll.', mod, green); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usepoll.\nType /fbhelp tokenpoll to see how to use /usepoll.', mod, green); } } function initTokenPoll(mod) { switch (cb.settings.pollMode) { case "Ends by Mod/Broadcaster command": pollType = "Never"; break; case "Ends after X minutes": pollType = "Timer"; break; case "Ends after X votes": pollType = "Vote"; break; case "Ends when one option reaches x votes": pollType = "Goal"; break; default: cb.sendNotice("Error in determining the poll type", "", pollbackground, pollforeground); } setPollColors(); pollRunning = true; buildPollBoard(mod); showBoard('timer'); initPollTimer(); cb.setTimeout(displayPoll, 30000); totalPollVotes = 0; } function setPollColors() { if (cb.settings.pollTxtColor === "Custom") { pollforeground = checkTextColor(cb.settings.pollCustTxtColor); if (pollforeground === "default") { cb.sendNotice("Token Poll - Error while setting the font color. It has to be in a HEX format. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); pollforeground = '#FFFFFF'; } } else { pollforeground = checkTextColor(cb.settings.pollTxtColor); } if (cb.settings.pollBgColor === "Custom") { pollbackground = checkBgColor(cb.settings.pollCustBgColor); if (pollbackground === 'default') { cb.sendNotice("Token Poll - Error while setting the background color. It has to be in a HEX format. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); pollbackground = '#0629AC'; } } else { pollbackground = checkBgColor(cb.settings.pollBgColor); } } function buildPollBoard(mod) { for (let i = 1; i <= 8; i++) { var oktoadd = 1; if(this["pollOptTokens"+i] != '' && this["pollOptTokens"+i] != null) { if(this["pollOptLabel"+i] != '' && this["pollOptLabel"+i] != null) { for (let j = 0; j < i-1; j++) { if (pollArrayAmount[j] === this["pollOptTokens"+i]) { pollmsg("bm", "", "Tip Price Amount for option " + i + " is not unique, it is not added to the board."); oktoadd = 0; break; } else if (pollArrayLabel[j] === this["pollOptLabel"+i]) { pollmsg("bm", "", "Label for option " + i + " is not unique, it is not added to the board."); oktoadd = 0; break; } } if(oktoadd == 1) { populatePollArray(this["pollOptLabel"+i],this["pollOptTokens"+i],0); priceChecker('add','Poll Option: '+this["pollOptLabel"+i], this["pollOptTokens"+i],mod); } } else { pollmsg("bm", "", "Label for option " + i + " is blank or null, not added to board."); } } } } function populatePollArray(label, amount, votes) { if (!cbjs.arrayContains(pollArrayAmount, amount) && !cbjs.arrayContains(pollArrayLabel, label)) { var pollindex = pollArrayAmount.length; pollArrayLabel[pollindex] = label; pollArrayAmount[pollindex] = amount; pollArrayVotes[pollindex] = votes; } else { pollmsg("bm", "", "Tip Price Amount or Label for option " + label + " is not unique, it is not added to the board."); return; } } function showBoard(reqby) { if (reqby === undefined) { reqby = 'timer'; } if (tokenPollToggle == 1) { if (reqby == 'bc' || reqby == 'timer' ) { var pollresponse1 = 'Sent to ALL:'; } else { var pollresponse1 = 'Sent to you:'; } if (pollRunning) { pollresponse1 += '\n \u25B7 \u25B7 \u25B7 \u25B7 \u25B7 \u25B7 Token Poll Board \u25C1 \u25C1 \u25C1 \u25C1 \u25C1 \u25C1'; } else { pollresponse1 += '\n \u25B7 \u25B7 \u25B7 \u25B7 \u25B7 \u25B7 Poll Results! \u25C1 \u25C1 \u25C1 \u25C1 \u25C1 \u25C1'; } var pollresponse2 = '\n \u25c7 \u25c7 \u25c7 \u25c7 \u25c7 \u25c7 ' + pollTitle + ' \u25c7 \u25c7 \u25c7 \u25c7 \u25c7 \u25c7'; let ids = []; for (let i = 0; i < pollArrayAmount.length; i++) { ids.push({ 'votes': pollArrayVotes[i], 'id': i }); } ids.sort(function(a, b) { return b.votes - a.votes; }); for (let j = 0; j < ids.length; j++) { if (0 != pollArrayAmount[ids[j].id]) { pollresponse2 += '\n \u23E9 ' + pollArrayLabel[ids[j].id] + ' (Price = ' + pollArrayAmount[ids[j].id] + ' tokens): ' + pollArrayVotes[ids[j].id] + ' vote' + (pollArrayVotes[ids[j].id] != 1 ? 's' : ''); } } let pollresponse3 = ''; if (pollRunning) { switch (pollType) { case 'Timer': break; case 'Vote': pollresponse3 = votesRemain + " vote" + (votesRemain > 1 ? "s" : "") + " remaining before poll closes\n"; break; case 'Goal': pollresponse3 = 'First option to ' + cb.settings.pollCount + ' votes wins!\n'; break; } pollresponse3 += 'Simply tip the shown token amounts to register your vote. Type /poll at any time to see the poll board.'; if (pollMinimum > 1) { if (totalPollVotes >= pollMinimum) { pollresponse3 += '\nThe minimum total number of votes has been met! The poll result is valid.'; } else { votesNeeded = pollMinimum - totalPollVotes; pollresponse3 += '\nThe minimum total number of votes to make the poll valid is ' + pollMinimum + ' and has not yet been met. ' + votesNeeded + ' more vote' + (votesNeeded != 1 ? 's' : '') + ' needed!'; } } } else { pollresponse3 += '\nThe poll has been closed, no more voting!'; } sendto = reqby; if (reqby == 'timer') { sendto = ''; if (pollRunning) { cb.setTimeout(showBoard, cb.settings.pollInterval * 60000); } } else if (reqby == 'bc') { sendto = ''; } cb.sendNotice(pollresponse1 + pollresponse2, sendto, pollbackground, pollforeground, 'bold'); cb.sendNotice(pollresponse3, sendto, pollbackground, pollforeground, 'bold'); } } function pollTip(tipAmount,voteAmount,tippedby) { for (let i = 0; i < pollArrayAmount.length; i++) { if (tipAmount == pollArrayAmount[i]) { pollArrayVotes[i] += voteAmount; totalPollVotes += voteAmount; if (voteAmount == 1) { cb.sendNotice(tippedby + ' voted for ' + pollArrayLabel[i], '', pollbackground, pollforeground, 'bold'); } else { cb.sendNotice(tippedby + ' voted ' + voteAmount + ' time' + (voteAmount == 1 ? '' : 's') + ' for ' + pollArrayLabel[i], '', pollbackground, pollforeground, 'bold'); } if (pollType == 'Vote') { votesRemain -= voteAmount; } if (pollType == 'Timer' && cb.settings.pollKeepalive == 'Yes' && pollSecsRemain < 30 && pollMinsRemain < 1) { pollStopTime = new Date(pollStopTime.getTime() + 30000); pollSecsRemain = pollSecsRemain + 30; cb.sendNotice('The token poll timer is set to keep alive with continued voting, 30 seconds have been added to the timer. Now ' + pollTimeLeft(), '', pollbackground, pollforeground, 'bold'); if (!aliveWarned) { aliveWarning(); } } if (pollType != 'Timer') { checkPollEnd(); } } } } function aliveWarning() { if (!pollRunning || pollType != 'Timer') { return; } pollmsg('b', '', 'Since you have enabled the setting to keep the poll alive if users are still voting, the poll might be kept alive indefinitely by tipping, however, you can use /endpoll to stop it.'); pollmsg('m', '', 'Since the broadcaster has enabled the setting to keep the poll alive if users are still voting, the poll might be kept alive indefinitely by tipping, however, you can use /endpoll to stop it.'); if (pollMinsRemain < 2 && pollRunning) { cb.setTimeout(aliveWarning, 60000); } aliveWarned = true; } function checkPollEnd() { if (pollType == 'Vote') { if (votesRemain < 1) { pollRunning = false; showWinner(''); } } else if (pollType == 'Goal') { for (let i = 0; i < pollArrayAmount.length; i++) { if (pollArrayVotes[i] >= cb.settings.pollCount) { pollRunning = false; showWinner(''); } } } } function showWinner(u) { let options = []; for (let i = 0; i < pollArrayAmount.length; i++) { options[i] = i; } options.sort(function(a, b) { return pollArrayVotes[b] - pollArrayVotes[a]; }); let win_count = 1; for (let j = 1; j < pollArrayAmount.length; j++) { if (pollArrayVotes[options[j]] != pollArrayVotes[options[0]]) { break; } if (0 != pollArrayAmount[options[j]]) { win_count++; } } let pollresponse1 = '\u23f0 \u23f0 \u23f0 Token Poll has ended! \u23f0 \u23f0 \u23f0 \n'; let pollresponse2 = 'Winner' + (win_count > 1 ? 's (' + win_count + '-way tie)' : '') + ':'; for (let k = 0; k < win_count; k++) { if (pollArrayAmount[options[k]] != 0) { pollresponse2 += "\n \u23E9 " + pollArrayLabel[options[k]] + ": " + pollArrayVotes[options[k]] + " votes"; } } cb.sendNotice(pollresponse1 + pollresponse2, u, pollbackground, pollforeground, "bold"); } function showLead() { let options = []; let leadOpt = []; for (let i = 0; i < pollArrayAmount.length; i++) { options[i] = i; } options.sort(function(a, b) { return pollArrayVotes[b] - pollArrayVotes[a]; }); if (pollArrayVotes[options[0] ] > 0 ){ leadOpt.push(pollArrayLabel[options[0]]); for (let j = 1; j < pollArrayAmount.length; j++) { if (pollArrayVotes[options[j]] != pollArrayVotes[options[0]]) { break; } if (0 != pollArrayAmount[options[j]]) { leadOpt.push(pollArrayLabel[options[j]]); } } } let pollresponse1; let leadCount = leadOpt.length; if (leadCount === 0){ pollresponse1 = "No votes yet, be sure to vote for your favorite! Type /poll at any time to see all the options."; } else if (leadCount === 1) { pollresponse1 = pollArrayLabel[options[0]] + " is in the lead by " + (pollArrayVotes[options[0]] - pollArrayVotes[options[1]]) + " vote" + ((pollArrayVotes[options[0]] - pollArrayVotes[options[1]]) === 1 ? "" : "s") + "."; } else{ pollresponse1 = "We have a " + leadCount + "-way tie between " + formatArray(leadOpt,"and") + "."; } return pollresponse1; } function formatArray(arr,andor){ let outStr = ""; if (arr.length === 1) { outStr = arr[0]; } else if (arr.length === 2) { outStr = arr.join(' '+andor+' '); } else if (arr.length > 2) { outStr = arr.slice(0, -1).join(', ') + ', '+andor+' ' + arr.slice(-1); } return outStr; } function timeCal() { pollStartTime = new Date(); return pollStopTime - pollStartTime.getTime(); } function pollTimeLeft() { var pollTimeLeft = timeCal(); var milliseconds = pollTimeLeft % 1000; var seconds = ((pollTimeLeft - milliseconds) % 60000); var minutes = ((pollTimeLeft - seconds - milliseconds) % 3600000); var hours = (pollTimeLeft - 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 initPollTimer() { if (!pollRunning || pollType !== "Timer") { return; } else { pollStartTime = new Date(); pollStopTime = new Date(pollStartTime.getTime() + cb.settings.pollCount * 60000); pollTimerMin(); } } function pollAddTime(timetoadd, u) { pollStopTime = new Date(pollStopTime.getTime() + timetoadd * 60000); pollmsg('bm', u, u + ' has added ' + timetoadd + ' minute' + (timetoadd === 1 || timetoadd === -1 ? '' : 's') + ' to the token poll timer.'); pollmsg('a', u, timetoadd + ' minute' + (timetoadd === 1 || timetoadd === -1 ? '' : 's') + ' have been added to the token poll timer. ' + pollTimeLeft()); pollMinsRemain = pollMinsRemain + timetoadd; if (pollMinsRemain > 0) { pollDisplaySeconds = false; } else { pollDisplaySeconds = true; } } function pollSwitchToTimer(timetoadd, u) { pollType = "Timer"; pollStartTime = new Date(); pollStopTime = new Date(pollStartTime.getTime() + timetoadd * 60000); pollmsg("bm", u, u + " set a token poll timer for " + timetoadd + " minute" + (timetoadd === 1 || timetoadd === -1 ? "" : "s")); cb.sendNotice("A token poll timer has been set for " + timetoadd + " minute" + (timetoadd === 1 || timetoadd === -1 ? "" : "s"), "", pollbackground, pollforeground, "bold"); pollMinsRemain = timetoadd; pollTimerStopping = false; pollTimerMin(); return; } function pollTimerMin() { if(!pollTimerStopping) { if (!pollRunning || pollType !== "Timer") { return; } switch (pollMinsRemain) { case 30: case 25: case 20: case 15: case 10: case 9: case 8: case 7: case 6: case 5: case 4: case 3: case 2: cb.sendNotice('\u231A \u231A \u231A ' + pollMinsRemain + ' minutes left to vote!!! \u231A \u231A \u231A', '', pollbackground, pollforeground, 'bold'); break; case 1: cb.sendNotice('\u231A \u231A \u231A There is 1 minute left to vote!!! \u231A \u231A \u231A', '', red, '', 'bold'); break; } pollMinsRemain--; if (pollMinsRemain > 0) { pollDisplaySeconds = false; } else { pollDisplaySeconds = true; } pollSecsRemain = 60; pollTimerSec(); } } function pollTimerSec() { if(!pollTimerStopping) { if (!pollRunning || pollType !== 'Timer') { return; } if (pollDisplaySeconds) { switch (pollSecsRemain) { case 30: case 10: case 5: case 4: case 3: case 2: cb.sendNotice('\u231A \u231A \u231A There are ' + pollSecsRemain + ' seconds left to vote!!! \u231A \u231A \u231A', '', red, '', 'bold'); break; case 1: cb.sendNotice('\u231A \u231A \u231A There is 1 second left to vote!!! \u231A \u231A \u231A', '', red, '', 'bold'); break; } } if (pollSecsRemain < 1) { if (pollMinsRemain >= 1) { pollTimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Time is up! No more Votes!!! \u23f0 \u23f0 \u23f0', '', yellow, '', 'bold'); showWinner(''); pollRunning = false; } } else { pollSecsRemain--; cb.setTimeout(pollTimerSec, 1000); } } } function pollStopTimer() { pollStopTime = new Date(); pollMinsRemain = 0; pollSecsRemain = 0; pollTimerStopping = true; } function displayPoll() { if (tokenPollToggle == 1 && pollRunning) { let pollNotice = ["a poll is currently running, type '/poll' to see the current votes and the amounts to tip for each choice."]; if (fanDouble) { pollNotice.push("Fan club members currently get two votes for the price of one!"); } pollNotice.push(showLead()); pollmsg("", "", pollNotice[nline]); nline += 1; if (nline >= pollNotice.length) { nline = 0; } cb.setTimeout(displayPoll, 90000); } } function pollmsg(to, u, m) { switch (to) { case "b": cb.sendNotice("Token Poll to Broadcaster - " + m, cb.room_slug, pollwarnDark, pollwarnLight, "bold"); break; case "m": cb.sendNotice("Token Poll to mods - " + m, "", pollbackground, pollforeground, "bold", "red"); break; case "bm": cb.sendNotice("Token Poll to Broadcaster - " + m, cb.room_slug, pollwarnDark, pollwarnLight, "bold"); cb.sendNotice("Token Poll to mods - " + m, "", pollbackground, pollforeground, "bold", "red"); break; case "a": cb.sendNotice("Token Poll - " + m, "", pollbackground, pollforeground, "bold"); break; case "nm": cb.sendNotice("Token Poll - This command only works for broadcasters and mods", u, pollwarnDark, pollwarnLight, "bold"); break; case "w": cb.sendNotice("Token Poll - " + m, u, pollwarnDark, pollwarnLight, "bold"); break; case "s": cb.sendNotice(m, u, "#e6e6e6", "#737373"); break; case "n": cb.sendNotice("Token Poll - " + m, u, pollbackground, pollforeground); break; default: cb.sendNotice("Token Poll - " + m, u, pollbackground, pollforeground, "bold"); break; } } // *********************************** Ticket Show Functions ************************************** function prepticketshow(mod) { // Start the token poll if(cb.settings.prepticketStartPoll == 'Yes' && tokenPollToggle == 0) { setTokenPollToggle("on",mod); } // Swap out the menus if(cb.settings.prepticketTipMenuOff == 'Yes' && tipMenuToggle == 1) { setTipMenuToggle("off",mod); } if(cb.settings.prepticketPosMenuOn == 'Yes' && posTipMenuToggle == 0) { setPosTipMenuToggle("on",mod); } // Turn on the backup ticket list if (backupToggle == 0 && ticketShowType != 'Fembot Ticket Show') { setBackupToggle('on',mod); if (ticketPrice <= 0) { cb.sendNotice('Note the ticket price value is not set, use "/ticketprice xx" to set the initial price, where xx is the amount in tokens. Users who buy a ticket at this amount will also be added to the backup ticket list.', mod, green); } } // Add presales for Fembot Ticket Show if (ticketShowType == 'Fembot Ticket Show' && cb.settings.prepticketAddPresales == 'Yes') { if (presaleArray.length > 0) { addPresaleList(mod); } else { cb.sendNotice('No pre-sale list ticket holders to add.', mod, green); } setPresalesToggle('off', mod); } } function addFromLeaderboard(mode, num, mod) { sortTippers(); addLBstring = ''; switch(mode) { case "num": { for (var LBi = 1; LBi <= num; LBi++) { if (tipCountArray.name[LBi - 1]) { if (!cb.limitCam_userHasAccess(tipCountArray.name[LBi - 1])) { if (ticketShowType == 'Fembot Ticket Show') { addRmvTicket('add',tipCountArray.name[LBi - 1],''); addLBstring += tipCountArray.name[LBi - 1]; } else { if (LBi > 1) { addLBstring += ', '; } addLBstring += tipCountArray.name[LBi - 1]; } } else { cb.sendNotice('User ' + tipCountArray.name[LBi - 1] + ' is already on the ticket list and was therefore skipped.', mod, green); } } else { return(addLBstring); } } break; } case "amt": { for (var LBi = 1; LBi <= 99; LBi++) { if (tipCountArray.name[LBi - 1] && tipCountArray.amount[LBi - 1] >= num) { if (!cb.limitCam_userHasAccess(tipCountArray.name[LBi - 1])) { if (ticketShowType == 'Fembot Ticket Show') { addRmvTicket('add',tipCountArray.name[LBi - 1],''); addLBstring += tipCountArray.name[LBi - 1]; } else { if (LBi > 1) { addLBstring += ', '; } addLBstring += tipCountArray.name[LBi - 1]; } } else { cb.sendNotice('User ' + tipCountArray.name[LBi - 1] + ' is already on the ticket list and was therefore skipped.', mod, green); } } else { return(addLBstring); } } break; } } } function addRmvTicketBackupList(mode,user,amount) { switch(mode) { case 'add': { if(!cbjs.arrayContains(backupListArray,user)) { backupListArray.push(user); } break; } case 'rmv': { if(cbjs.arrayContains(backupListArray,user)) { cbjs.arrayRemove(backupListArray,user); } break; } case 'addtip': { backupListArray.push(user); break; } } } function setTicketPrice(amount,sendto,announce) { ticketPrice = parseInt(amount); priceChecker('add','Fembot Ticket Price', amount,sendto); if (announce === 'yes') { ticketPriceChangeNotice(ticketPrice); } } function setBackupTicketPrice(amount,sendto) { priceChecker('rmv','Backup Ticket Price', backupPrice, sendto); backupPrice = amount; priceChecker('add','Backup Ticket Price', backupPrice, sendto); if (enablePresales != 'Yes') { cb.sendNotice('From Fembot: Backup ticket list price updated, all single tips of at least ' + amount + ' tokens will add a user to the Backup Ticket List. Note that cumulative tips do not get added to the backup list.', sendto, green); } } function setBackupToggle(option, mod) { if (option == 'on') { if (backupToggle == 1) { cb.sendNotice('The Backup Ticket List is already enabled.',mod,green); } else { backupToggle = 1; cb.sendNotice('You have enabled the Backup Ticket List.',mod,green); } } else if (option == 'off') { if (backupToggle == 0) { cb.sendNotice('The Backup Ticket List is already disabled.',mod,green); } else { backupToggle = 0; cb.sendNotice('You have disabled the Backup Ticket List.',mod,green); } } } // *********************************** Media Display Function ************************************** function setMediaToggle(option, mod) { if (option == 'on') { if(mediaToggle == 1) { cb.sendNotice('The Media List is already enabled.', mod, green); } else { mediaToggle = 1; setMediaColors(); sendMediaList(); cb.sendNotice('You have enabled the Media List.', mod, green); } } else if (option == 'off') { if (mediaToggle == 0) { cb.sendNotice('The Media List is already disabled.', mod, green); } else { mediaToggle = 0; cb.sendNotice('You have disabled the Media List.', mod, green); } } } function setMediaColors() { if (cb.settings.mediaListTxtColor === "Custom") { mediaforeground = checkTextColor(cb.settings.mediaListCustTxtColor); if (mediaforeground === "default") { cb.sendNotice("Media List - Error while setting the font color. It has to be in a HEX format. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); mediaforeground = '#FFFFFF'; } } else { mediaforeground = checkTextColor(cb.settings.mediaListTxtColor); } if (cb.settings.mediaListBgColor === "Custom") { mediabackground = checkBgColor(cb.settings.mediaListCustBgColor); if (mediabackground === 'default') { cb.sendNotice("Media List - Error while setting the background color. It has to be in a HEX format. Using default value.", cb.room_slug, "#FFFFFF", "#FF0000", "bold"); mediabackground = '#0629AC'; } } else { mediabackground = checkBgColor(cb.settings.mediaListBgColor); } } function sendMediaList() { if(firstmedia == 0) { mediaTimer = mediaInt - 10000; firstmedia = 1 } else { mediaTimer = mediaInt; } cb.setTimeout(mediaListTimer, mediaTimer); } function mediaListTimer() { if(mediaToggle == 1) { showMedia(""); sendMediaList(); } } function showMedia(sendto) { cb.sendNotice('Media Info : ' + cb.settings.mediaListIntro, sendto, mediabackground, mediaforeground, "bold"); for (let j = 1; j <= 12; j++) { if(this["mediaListItem"+j] != '' && this["mediaListItem"+j] != null) { cb.sendNotice(this["mediaListText"+j] + ' : ' + this["mediaListItem"+j], sendto, mediabackground, mediaforeground); } } } // *********************************** Require Answer Chat Lock Function ************************************** function setRequireAnswerToggle(mode,setby) { if (mode == 'on') { if (requireAnswerToggle == 1) { cb.sendNotice('The "Answer Required" Chat Lock is already enabled at the level of ' + requireAnswerLevelText + '.', setby, green); } else { requireAnswerToggle = 1; if (requireAnswerLevel > 0) { cb.sendNotice('You have enabled the "Answer Required" Chat Lock at the level of ' + requireAnswerLevelText + '.', setby, green); } else { requireAnswerLevel = 1; requireAnswerLevelText = 'Gray Users'; cb.sendNotice('You have enabled the "Answer Required" Chat Lock. Since a level was not previously defined, the level is defaulted to "' + requireAnswerLevelText + '". You can change the level using the command /setanswerlevel.', setby, green); } } } else if (mode == 'off') { if (requireAnswerToggle == 0) { cb.sendNotice('The "Answer Required" Chat Lock is already disabled.', setby, green); } else { requireAnswerLevel = 0; requireAnswerLevelText = 'Not Used'; requireAnswerToggle = 0; cb.sendNotice('You have disabled the "Answer Required" Chat Lock.', setby, green); } } } function requireAnswerLockCheck(user) { if (!cbjs.arrayContains(answerLockList,user)) { addToAnswerLockList(user); } var answeruserindex = answerLockList.indexOf(user); if (answerLockStatus[answeruserindex]) { return true; } else { return false; } } function addToAnswerLockList(user) { initCanChat = false; lockquestionindex = Math.floor(Math.random() * 10); answerLockList.push(user); answerLockStatus.push(initCanChat); answeruserindex = answerLockList.indexOf(user); answerLockQuestion[answeruserindex] = lockquestionindex; } function clearAnswerLock() { answerLockList = []; answerLockStatus = []; answerLockQuestion = [0]; } // *********************************** Gray Chat Lock Function ************************************** function setGrayLockToggle(option, mod) { if(option == 'on') { if(grayLockToggle == 1) { cb.sendNotice('The Gray Chat Lock is already enabled with threshold set to ' + grayChatTime + ' minutes.', mod, green); } else { grayLockToggle = 1; cb.sendNotice('You have enabled the Gray Chat Lock with the configured threshold set to ' + grayChatTime + ' minutes.', mod, green); } } else if(option == 'off') { if(grayLockToggle == 0) { cb.sendNotice('The Gray Chat Lock is already disabled.', mod, green); } else { grayLockToggle = 0; cb.sendNotice('You have disabled the Gray Chat Lock.', mod, green); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usegraylock, the option should be "on" or "off".', mod, green); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usegraylock, the option should be "on" or "off".', mod, green); } } function grayLockCheck(user,isBC,isMod,isFan,isGray) { if (!cbjs.arrayContains(grayLockList,user)) { addToLockList(user,isBC,isMod,isFan,isGray); } var grayIndex = grayLockList.indexOf(user); if (grayLockStatus.canChat[grayIndex]) { return true; } else if (grayExpired(grayLockStatus.entered[grayIndex])) { grayLockStatus.canChat[grayIndex] = true; return true; } else { return false; } } function grayExpired(enteredDateTime) { return grayTimeElapsed(enteredDateTime) >= grayChatTime; } function grayTimeElapsed(enteredDateTime) { var nowDateTime = Date.now(); var elapsedMinutes = Math.floor((nowDateTime - enteredDateTime) / (1000 * 60)); return elapsedMinutes; } function addToLockList(user,isBC,isMod,isFan,isGray) { if (isBC || !isGray || isFan || isMod || cbjs.arrayContains(VIPListArray,user) || cbjs.arrayContains(extFanListArray,user)) { initCanChat = true; } else { initCanChat = false; } grayLockList.push(user); grayLockStatus.entered.push(Date.now()); grayLockStatus.canChat.push(initCanChat); } function grayTimeLeft(user) { var ERR = -1; if (!cbjs.arrayContains(grayLockList,user)) { return ERR; } var entered = grayLockStatus.entered[grayLockList.indexOf(user)]; return grayChatTime - grayTimeElapsed(entered); } function addRmvGrayLock(mode,user,sendto) { if (mode == 'a') { if(grayLockStatus.canChat[grayLockList.indexOf(user)] === false) { cb.sendNotice(user + ' is already on chat restricted time lock.', sendto, green); } else { grayLockStatus.canChat[grayLockList.indexOf(user)] = false; grayLockStatus.entered[grayLockList.indexOf(user)] = Date.now(); cb.sendNotice('You have added ' + user + ' to the chat restricted time lock, and reset their timer to start now and last for ' + grayChatTime + ' minutes.', sendto, green); } } else if (mode == 'r') { if(grayLockStatus.canChat[grayLockList.indexOf(user)] === false) { grayLockStatus.canChat[grayLockList.indexOf(user)] = true; cb.sendNotice('You have removed ' + user + ' from the chat restricted time lock. They are now free to chat.', sendto, green); } else { cb.sendNotice(user + ' is not on chat restricted time lock.', sendto, green); } } } function clearGrayLock(sendto) { grayLockList = []; grayLockStatus.canChat = []; grayLockStatus.entered = []; cb.sendNotice('You have cleared the chat restricted time lock list. The list will be rebuilt as users chat or enter the room.', sendto, green); } // *********************************** Dice Game Functions ************************************** function setDiceToggle(option, mod) { if(option == 'on') { if(diceToggle == 1) { cb.sendNotice('The Dice Game is already enabled.', mod, green); } else { diceToggle = 1; setDiceColors(); diceSetPrizes(); diceNoticeTimer(); cb.sendNotice(mod + ' has enabled the dice game!', '', diceNoticeBg, diceTextColor, 'bold'); cb.sendNotice('You have enabled the Dice Game.', mod, green); priceChecker('add','Dice Roll Price', diceRollPrice,mod); } } else if(option == 'off') { if(diceToggle == 0) { cb.sendNotice('The Dice Game is already disabled.', mod, green); } else { diceToggle = 0; cb.sendNotice('You have disabled the Dice Game.', mod, green); cb.sendNotice(mod + ' has disabled the dice game, you can no longer tip to roll the dice.', '', diceNoticeBg, diceTextColor, 'bold'); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usedice, the option should be "on" or "off".', mod, green); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usedice, the option should be "on" or "off".', mod, green); } } function setDiceColors() { diceNoticeBg = checkBgColor(cb.settings.diceNoticeBgColor); diceRollBg = checkBgColor(cb.settings.diceRollBgColor); diceRollBgSpecial = checkBgColor(cb.settings.diceRollBgColorSpecial); diceTextColor = '#000000'; } function setDiceNoticeTimeout() { if(diceInt <= 0) { diceInt = 180000; } cb.setTimeout(diceNoticeTimer, diceInt); } function diceNoticeTimer() { if(diceToggle == 1) { diceShowNotice(""); setDiceNoticeTimeout(); } } function diceShowNotice(sendto) { if (diceMultiRolls <= 1) { var msg = ':diceroll1 \nDice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! You can use the command /prizes to see the prize list.'; } else if (diceMultiRolls == 2) { var msg = ':diceroll1 \nDice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! You can use the command /prizes to see the prize list.\nYou can tip up to 2 multiples of the dice roll price to roll multiple times (' + diceRollPrice + ' or ' + diceRollPrice*2 + ').'; } else if (diceMultiRolls == 3) { var msg = ':diceroll1 \nDice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! You can use the command /prizes to see the prize list.\nYou can tip up to 3 multiples of the dice roll price to roll multiple times (' + diceRollPrice + ', ' + diceRollPrice*2 + ', or ' + diceRollPrice*3 + ').'; } else if (diceMultiRolls > 3) { var msg = ':diceroll1 \nDice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! You can use the command /prizes to see the prize list.\nYou can tip up to ' + diceMultiRolls + ' multiples of the dice roll price to roll multiple times (' + diceRollPrice + ', ' + diceRollPrice*2 + ', ' + diceRollPrice*3 + ',...)'; } if (cb.settings.diceRemoveWinner == 'Yes') { msg += '\nEach prize that is won will be removed from the list until all prizes are won and the list resets.'; } else { msg += '\nEach prize remains on the list and can be won multiple times.'; } cb.sendNotice(msg, sendto, diceNoticeBg, diceTextColor, 'bold'); } function diceRoll(rolledby) { diceRollCounter++; diceRollCounterSpecial++; var firstDie = Math.floor(Math.random() * 6) + 1; var secondDie = Math.floor(Math.random() * 6) + 1; if (diceRollCounterSpecial > diceMinSpecial) { if (Math.random() <= (diceRarePct / 100)) { firstDie = 7; diceRollCounterSpecial = 0; } } var diceTotal = firstDie + secondDie; var winner = false; if (diceTotal >= 2 && diceTotal <= 13) { winner = true; var prize = cb.settings['dicePrize_' + diceTotal]; } else { winner = false; var prize = 'A Thank You!'; } var prizeIndex = dicePrizes.indexOf(prize); if (prizeIndex >= 0) { if (cb.settings.diceRemoveWinner == 'Yes') dicePrizes.splice(prizeIndex, 1); } else { prize = 'A Thank You!'; } if (dicePrizes.length === 1) { diceSetPrizes(); } var msg = diceGifPfx + firstDie + " " + diceGifPfx + secondDie + "\n"; msg += rolledby + " rolled a " + diceTotal + "! \n".toUpperCase(); msg += "Roll #" + diceRollCounter + " | Prize: " + prize; if (diceTotal == 13) { cb.sendNotice(msg, '', diceRollBgSpecial, diceTextColor, 'bold'); } else { cb.sendNotice(msg, '', diceRollBg, diceTextColor, 'bold'); } diceLastPrizeWon = prize; diceWinners.push("Roll #" + diceRollCounter + " (" + diceTotal + "): " + rolledby + " - " + prize); } function diceSetPrizes() { var rareText = ''; for (var i = 2; i <= 13; i++) { if (i == 13) rareText = " (RARE)"; dicePrizes.push(cb.settings['dicePrize_' + i] + rareText); } } function diceShowPrizes(sendto) { if (dicePrizes.length) { var rareText = ''; var msg = '\u22A1 \u22A1 \u22A1 \u22A1 DICE GAME PRIZES \u22A1 \u22A1 \u22A1 \u22A1'; cb.sendNotice(msg, sendto, diceNoticeBg, diceTextColor, 'bold'); var msg = '' for (var i = 2; i <= 13; i++) { if (i == 13) rareText = ' (RARE)'; if (dicePrizes.indexOf(cb.settings['dicePrize_' + i] + rareText) >= 0) msg += 'Roll ' + i + ' - ' + cb.settings['dicePrize_' + i] + rareText + '\n'; } } else { var msg = "SORRY! There are no prizes left in the list, but thank you for the tip. :thumbsup"; } cb.sendNotice(msg, sendto, '', '', 'bold'); } function diceShowRolls(sendto) { var msg = "\u22A1 \u22A1 \u22A1 \u22A1 LAST 20 DICE ROLLS \u22A1 \u22A1 \u22A1 \u22A1"; cb.sendNotice(msg, sendto, diceNoticeBg, diceTextColor, 'bold'); var msg = '' if (diceWinners.length === 0) { cb.sendNotice('No one has won anything yet. Roll the dice to win a prize!', sendto, '', '', 'bold'); } else { var diceRecentWinners = diceWinners.slice(-20); for (var i = 0; i < diceRecentWinners.length; i++) msg += "\n" + diceRecentWinners[i]; cb.sendNotice(msg, sendto, '', '', 'bold'); } } // *********************************** Tip Response Functions ************************************** function setTipResponseToggle(mode, mod) { if (mode == 'tipper' || mode == 'all' ) { if (mode == 'tipper' && tipResponseToggle == 1) { cb.sendNotice('The Tip Response is already set to "send to tipper".', mod, green); } else if (mode == 'all' && tipResponseToggle == 2) { cb.sendNotice('The Tip Response is already set to "send to all".', mod, green); } else { if (tipResponseAmount1 > 0 && (tipResponseAmount1 > tipResponseAmount2 || tipResponseAmount1 > tipResponseAmount3 || tipResponseAmount1 > tipResponseAmount4 || tipResponseAmount1 > tipResponseAmount5)) { cb.sendNotice('Unable to use Tip Response Notes, Tip Response threshold 1 is greater than a threshold in 2-5. Response notes disabled.', u, green); } else if (tipResponseAmount2 > 0 && (tipResponseAmount2 > tipResponseAmount3 || tipResponseAmount2 > tipResponseAmount4 || tipResponseAmount2 > tipResponseAmount5)) { cb.sendNotice('Unable to use Tip Response Notes, Tip Response threshold 2 is greater than a threshold in 3-5. Response notes disabled.', u, green); } else if (tipResponseAmount3 > 0 && (tipResponseAmount3 > tipResponseAmount4 || tipResponseAmount3 > tipResponseAmount5)) { cb.sendNotice('Unable to use Tip Response Notes, Tip Response threshold 3 is greater than a threshold in 4-5. Response notes disabled.', u, green); } else if (tipResponseAmount4 > 0 && (tipResponseAmount4 > tipResponseAmount5)) { cb.sendNotice('Unable to use Tip Response Notes, Tip Response threshold 4 is greater than threshold 5. Response notes disabled.', u, green); } else { tipresponsetextcolor = checkTextColor("Dark Red"); tipresponsebgcolor = checkBgColor("White"); if (mode == 'tipper') { tipResponseToggle = 1; } else { tipResponseToggle = 2; } cb.sendNotice('You have enabled the Tip Response. Users will now see a response message when they tip above each threshold.', mod, green); } } } else if (mode == 'off') { if (tipResponseToggle == 0) { cb.sendNotice('The Tip Response is already disabled.', mod, green); } else { tipResponseToggle = 0; cb.sendNotice('You have disabled the Tip Response.', mod, green); } } } // *********************************** Ticket Show Pre-sale Functions ************************************** function setPresalesToggle(option, sendto, price) { if(option == 'on') { if (presalesToggle == 1) { cb.sendNotice('The Pre-Sales Ticket feature is already enabled.',sendto,green); } else { priceChecker('add','Pre-sale Ticket Price', presalePrice,sendto); presalesToggle = 1; presalesTxtColor = checkTextColor("Dark Purple"); presalesBgColor = checkBgColor("Light Blue"); cb.sendNotice(sendto + ' has started the Ticket Show Pre-sales. You can now buy advance tickets to the show for ' + presalePrice + ' tokens. You will automatically be added to the ticket show when the Ticket Show app is started later.', "", presalesBgColor, presalesTxtColor, "bold"); cb.sendNotice('***Warning Regarding Presales***: Do not deactivate or restart the Ultra Fembot before exporting the pre-sale list to the ticket show or you will lose the pre-sale list. This can be done with the command "/expps" once the separate Ticket App is started (when you are done with presales and want to start the actual show). If it is necessary to restart, please save the pre-sale list first (use /presalelist to view and copy) and then add those users back to the presale (/addpresale) or the actual ticket show (/add).',cb.room_slug,green); presaleSkipMin = false; presaleSkipSec = false; presaleSkipNotice = false; setPresaleMode('init',sendto); countPresaleSold = 0; presaleIncrements = 0; stopIncrement = false; cb.setTimeout(presaleNoticeTimer, cb.settings.presaleNoticeInterval * 60000); } } else if(option == 'off') { if(presalesToggle == 0) { cb.sendNotice('The Pre-Sales Ticket feature is already disabled.',sendto,green); } else { presalesToggle = 0; stopPresaleTimer(sendto); presaleSkipNotice = true; cb.sendNotice('You have disabled the Pre-Sales Ticket feature. The pre-sales list is still intact, but no more tickets will be sold.',sendto,green); cb.sendNotice(sendto + ' has disabled the Ticket Show Pre-sales Feature. You can no longer buy Pre-sale tickets.', '', presalesBgColor, presalesTxtColor, 'bold'); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usepresale.\nType "/fbhelp presale" to see how to use pre-sales related commands.',sendto,green); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usepresale.\nType "/fbhelp presale" to see how to use pre-sales related commands.',sendto,green); } } function setPresaleMode(mode,sendto) { if (mode === 'init') { if (cb.settings.enablePresalesMode === 'Yes, Mode 1: Increment Manually') { newPresaleMode = 'manual'; } else if (cb.settings.enablePresalesMode === 'Yes, Mode 2: Increment on X Tickets Sold') { newPresaleMode = 'count'; } else if (cb.settings.enablePresalesMode === 'Yes, Mode 3: Increment on Automatic Timer') { newPresaleMode = 'timer'; } else { newPresaleMode = 'initmanual'; } } else { countPresaleSold = 0; presaleIncrements = 0; stopIncrement = false; newPresaleMode = mode; } if (presaleMode === 'timer' && newPresaleMode != 'timer') { stopPresaleTimer(sendto); } if (newPresaleMode === 'manual') { presaleMode = 'manual'; presaleIncAmt = cb.settings.presaleIncreasePerIncrement; cb.sendNotice('Pre-sales is set to manual mode. The broadcaster or moderator can change the presale price on demand using the command "/presaleprice [newprice]".', sendto, green); } else if (newPresaleMode === 'timer') { if (cb.settings.presaleIncreasePerIncrement >= 1 && cb.settings.presaleTimedIncrement >= 1) { presaleMode = 'timer'; presaleTimeAmt = cb.settings.presaleTimedIncrement; presaleIncAmt = cb.settings.presaleIncreasePerIncrement; presaleAutoTimer(presaleTimeAmt); cb.sendNotice('Pre-sales is set to Mode 3: Automatic timer mode. Timer cycle is set to ' + presaleTimeAmt + ' minutes, and price will increase ' + presaleIncAmt + ' tokens each time, with a maximum of ' + cb.settings.presaleMaxIncrements + ' increases.', sendto, green); } else { presaleMode = 'manual'; presaleIncAmt = cb.settings.presaleIncreasePerIncrement; cb.sendNotice('Pre-sales is set to manual mode. Mode was requested for automatic timer, but either the price increment or number of minutes per increment is not set. You can restart the bot and update the missing values, update the pre-sale price manually without a timer, or manually start a single increment timer.', sendto, green); } } else if (newPresaleMode === 'count') { if (cb.settings.presaleIncreasePerIncrement >= 1 && cb.settings.presaleCountIncrement >= 1) { presaleMode = 'count'; presaleCountAmt = cb.settings.presaleCountIncrement; presaleIncAmt = cb.settings.presaleIncreasePerIncrement; ticketsLeft = presaleCountAmt; cb.sendNotice('Pre-sales is set to Mode 2: Increment by tickets sold. Ticket count cycle is set to ' + presaleCountAmt + ' tickets sold, and price will increase ' + presaleIncAmt + ' tokens each time, with a maximum of ' + cb.settings.presaleMaxIncrements + ' increases.', sendto, green); cb.sendNotice('Pre-sale tickets are limited. The pre-sale price will increase from ' + presalePrice + ' to ' + (presalePrice + presaleIncAmt) + ' tokens once ' + presaleCountAmt + ' tickets are sold. Buy now before the price goes up!', "", presalesBgColor, presalesTxtColor, "bold"); } else { presaleMode = 'manual'; presaleIncAmt = cb.settings.presaleIncreasePerIncrement; cb.sendNotice('Pre-sales is set to manual mode. Mode was requested for increment by tickets sold, but either the price increment or number of tickets sold per increment is not set. You can restart the bot and update the missing values, update the pre-sale price manually with a count, or manually start a single increment timer.', sendto, green); } } else if (newPresaleMode === 'initmanual') { presaleMode = 'manual'; presaleIncAmt = cb.settings.presaleIncreasePerIncrement; cb.sendNotice('Pre-sales is set to manual mode since pre-sale was turned off on the start page. You can change the mode using the command "/chgpresalemode [mode]", where [mode] is "manual", "count", or "timer".', sendto, green); } } function presalePriceChange(price,mod) { cb.sendNotice('\u21D2 . . . . Ticket Show Pre-Sales Price Updated!!!. . . . . \u21D0 \n' + '\u21D2 . . . . . Pre-sale Tickets are now ' + price + ' tokens!!! . . . . . \u21D0', '', '#059abd', '#FFFFFF', "bold"); priceChecker('rmv','Pre-sale Ticket Price', presalePrice, mod); presalePrice = price; priceChecker('add','Pre-sale Ticket Price', presalePrice, mod); } function presaleNoticeTimer() { if(presalesToggle == 1) { if (presaleMode === 'manual') { cb.sendNotice('Ticket Show Pre-sales are active. You can now buy advance tickets to the show at a price of ' + presalePrice + ' tokens. You will automatically be added to the ticket show when the Ticket Show app is started later. Planned ticket price for the show is ' + ticketPrice + ' tokens.', "", presalesBgColor, presalesTxtColor, "bold"); } else if (presaleMode === 'timer') { if (stopIncrement === true || (presalePrice + presaleIncAmt) > ticketPrice || presaleIncrements > cb.settings.presaleMaxIncrements) { cb.sendNotice('Ticket Show Pre-sales are active. You can now buy advance tickets to the show at a price of ' + presalePrice + ' tokens. You will automatically be added to the ticket show when the Ticket Show app is started later. Planned ticket price for the show is ' + ticketPrice + ' tokens.', "", presalesBgColor, presalesTxtColor, "bold"); } else { cb.sendNotice('Ticket Show Pre-sales are active. You can now buy advance tickets to the show at a price of ' + presalePrice + ' tokens. You will automatically be added to the ticket show when the Ticket Show app is started later. Pre-sale tickets are being sold at this price for a limited period of time. The pre-sale price will increase from ' + presalePrice + ' to ' + (presalePrice + presaleIncAmt) + ' tokens once the timer runs out. Buy now before the price goes up!', "", presalesBgColor, presalesTxtColor, "bold"); } } else if (presaleMode === 'count') { if (stopIncrement === true || (presalePrice + presaleIncAmt) > ticketPrice || (presaleIncrements + 1) > cb.settings.presaleMaxIncrements) { cb.sendNotice('Ticket Show Pre-sales are active. You can now buy advance tickets to the show at a price of ' + presalePrice + ' tokens. You will automatically be added to the ticket show when the Ticket Show app is started later. Planned ticket price for the show is ' + ticketPrice + ' tokens.', "", presalesBgColor, presalesTxtColor, "bold"); } else { cb.sendNotice('Ticket Show Pre-sales are active. You can now buy advance tickets to the show at a price of ' + presalePrice + ' tokens. You will automatically be added to the ticket show when the Ticket Show app is started later. Pre-sale tickets are limited. The pre-sale price will increase from ' + presalePrice + ' to ' + (presalePrice + presaleIncAmt) + ' tokens once ' + ticketsLeft + ' more ticket' + (ticketsLeft > 1 ? "s are" : " is") + ' sold. Buy now before the price goes up!', "", presalesBgColor, presalesTxtColor, "bold"); } } if (!presaleSkipNotice) { cb.setTimeout(presaleNoticeTimer, cb.settings.presaleNoticeInterval * 60000); } else { presaleSkipNotice = false; } } } function presaleAutoTimer(addtime) { cb.sendNotice('An automatic timer was started, pre-sale ticket prices will increase from ' + presalePrice + ' to ' + (presalePrice + presaleIncAmt) + ' tokens in ' + presaleTimeAmt + ' minutes. Buy now before the price goes up! Ticket show price will be ' + ticketPrice + ' tokens.', "", presalesBgColor, presalesTxtColor, "bold"); presaleMinsRemain = addtime; presaleSecsRemain = 0; presaleStartTime = new Date(); presaleStopTime = new Date(presaleStartTime.getTime() + presaleMinsRemain * 60000); presaleTimerMin(); } function presaleTimerMin() { presaleSeconds = presaleCheckMin(); if (presaleSkipMin === false && presaleMode === 'timer' && (presaleSeconds >= 55 || presaleSeconds == 0)) { switch (presaleMinsRemain) { case 60: case 45: case 30: case 20: case 15: case 10: case 9: case 8: case 7: case 6: case 5: case 4: case 3: case 2: cb.sendNotice('\u23f1 \u23f1 \u23f1 There are ' + presaleMinsRemain + ' minutes left on the timer to buy a pre-sale ticket for ' + presalePrice + ' tokens! \u23f1 \u23f1 \u23f1', "", yellow, "", "bold"); } presaleMinsRemain--; if (presaleMinsRemain > 0) { cb.setTimeout(presaleTimerMin, 60000); } else { presaleSecsRemain = 60; cb.sendNotice('\u23f1 \u23f1 \u23f1 There is 1 minute left on the timer to buy a pre-sale ticket for ' + presalePrice + ' tokens!! \u23f1 \u23f1 \u23f1', "", red, "", "bold"); presaleTimerSec(); } } else { if (presaleSkipMin === true) { presaleSkipMin = false; } } } function presaleCheckMin() { var presaleTimeLeft = presaleTimeCal(); var presaleMS = presaleTimeLeft % 1000; var presaleSeconds = ((presaleTimeLeft - presaleMS) % 60000); presaleSeconds = presaleSeconds / 1000; return presaleSeconds; } function presaleTimerSec() { if (!presaleSkipSec && presaleMode === 'timer') { if (presaleMinsRemain > 0) { cb.setTimeout(presaleTimerMin, presaleSecsRemain*1000); } else { presaleSecsRemain--; if (presaleSecsRemain < 1) { cb.sendNotice("\u23f0 \u23f0 \u23f0 Time is up! Pre-sale Price is changing! \u23f0 \u23f0 \u23f0", "", yellow, "", "bold"); nextPresalePrice = presalePrice + presaleIncAmt; presalePriceChange(nextPresalePrice,cb.room_slug); presalePrice = nextPresalePrice; presaleIncrements ++; if (presalePrice + presaleIncAmt > ticketPrice) { stopIncrement = true; cb.sendNotice('The automated timer has ended. Pre-sale tickets will remain at ' + presalePrice + ' tokens until start of show unless manually updated by the broadcaster.',"", presalesBgColor, presalesTxtColor, "bold"); cb.sendNotice('No additional timer started, next increment would have exceeded planned ticket show price of ' + ticketPrice + '.',cb.room_slug, green); } else if ((presaleIncrements + 1) > cb.settings.presaleMaxIncrements) { stopIncrement = true; cb.sendNotice('The automated timer has ended. Pre-sale tickets will remain at ' + presalePrice + ' tokens until start of show unless manually updated by the broadcaster.',"", presalesBgColor, presalesTxtColor, "bold"); cb.sendNotice('No additional timer started, next increment would have exceeded max increments of ' + cb.settings.presaleMaxIncrements + '.',cb.room_slug, green); } else { presaleAutoTimer(presaleTimeAmt); } } else { switch (presaleSecsRemain) { case 30: case 10: case 5: case 4: case 3: case 2: case 1: cb.sendNotice('\u23f1 \u23f1 \u23f1 There are ' + presaleSecsRemain + ' second' + (presaleSecsRemain > 1 ? "s" : "") + ' left on the timer to buy a pre-sale ticket for ' + presalePrice + ' tokens! \u23f1 \u23f1 \u23f1', "", red, "", "bold"); } } if (presaleSecsRemain > 0) { cb.setTimeout(presaleTimerSec, 1000); } } } else { presaleSkipSec = false; } } function presaleAddTime(presaletimetoadd, u) { presaleStopTime = new Date(presaleStopTime.getTime() + presaletimetoadd * 60000); cb.sendNotice(u + " has added " + presaletimetoadd + " minute" + (presaletimetoadd === 1 || presaletimetoadd === -1 ? "" : "s") + " to the timer.",cb.room_slug,"","", "bold"); cb.sendNotice(presaletimetoadd + " minute" + (presaletimetoadd === 1 || presaletimetoadd === -1 ? "" : "s") + " have been added to the timer. Now " + presaleTimeLeft(),"",yellow,"", "bold"); presaleMinsRemain = presaleMinsRemain + presaletimetoadd; if (presaleMinsRemain < 1) { presaleSkipMin = true; presaleTimeLeft = presaleTimeCal(); presaleMS = presaleTimeLeft % 1000; presaleSeconds = ((presaleTimeLeft - presaleMS) % 60000) / 1000; presaleSecsRemain = presaleSeconds; presaleTimerSec(); } return; } function presaleTimeCal() { presaleStartTime = new Date(); return presaleStopTime - presaleStartTime.getTime(); } function stopPresaleTimer(mod) { presaleStopTime = new Date(); if (presaleMinsRemain > 0 || presaleSecsRemain > 0) { presaleMinsRemain = 0; presaleSecsRemain = 0; presaleSkipMin = true; presaleSkipSec = true; if(mod != null) { cb.sendNotice(mod + ' has stopped the ticket show pre-sales timer.',"",yellow,"", "bold"); } } } function presaleTimeLeft(user) { var presaleTimeLeft = presaleTimeCal(); var presaleMS = presaleTimeLeft % 1000; var presaleSeconds = ((presaleTimeLeft - presaleMS) % 60000); var presaleMinutes = ((presaleTimeLeft - presaleSeconds - presaleMS) % 3600000); var presaleHours = (presaleTimeLeft - presaleMinutes - presaleSeconds - presaleMS); presaleSeconds = presaleSeconds / 1000; presaleMinutes = presaleMinutes / 60000; presaleHours = presaleHours / 3600000; if (presaleHours > 0) { return presaleHours + " hour" + (presaleHours > 1 ? "s" : "") + " and " + presaleMinutes + " minute" + (presaleMinutes > 1 ? "s" : "") + " remaining to vote."; } else if (presaleMinutes > 0 && presaleSeconds === 0) { return presaleMinutes + " minute" + (presaleMinutes > 1 ? "s" : "") + " remaining on the timer."; } else if (presaleMinutes > 0) { return presaleMinutes + " minute" + (presaleMinutes > 1 ? "s" : "") + " and " + presaleSeconds + " second" + (presaleSeconds > 1 ? "s" : "") + " remaining on the timer."; } else { return presaleSeconds + " second" + (presaleSeconds > 1 ? "s" : "") + " remaining on the timer."; } } function addRmvPresale(mode,user,amount) { switch(mode) { case 'add': { if(!cbjs.arrayContains(presaleArray,user)) { presaleArray.push(user); cb.sendNotice(user + ' has been added to the pre-sale ticket list.', '', presalesBgColor, presalesTxtColor, 'bold'); countPresaleSold ++; if (presaleMode == 'count' && stopIncrement === false) { checkPresaleCount(); } } break; } case 'rmv': { if(cbjs.arrayContains(presaleArray,user)) { cbjs.arrayRemove(presaleArray,user); cb.sendNotice(user + ' has been removed from the pre-sale ticket list.', '', presalesBgColor, presalesTxtColor, 'bold'); } break; } case 'addtip': { if (amount >= presalePrice) { presaleArray.push(user); cb.sendNotice('Welcome ' + user + ', you have been added to the pre-sale ticket list.', '', presalesBgColor, presalesTxtColor, 'bold'); countPresaleSold ++; if (presaleMode == 'count' && stopIncrement === false) { checkPresaleCount(); } } break; } } } function checkPresaleCount() { ticketsLeft = (cb.settings.presaleCountIncrement - countPresaleSold) if (ticketsLeft > 0) { cb.sendNotice('There ' + (ticketsLeft > 1 ? "are " : "is ") + (ticketsLeft) + ' pre-sale ticket' + (ticketsLeft > 1 ? "s" : "") + ' remaining at a price of ' + presalePrice + ' tokens!',"", presalesBgColor, presalesTxtColor, "bold"); } else { if (presalePrice + presaleIncAmt > ticketPrice) { stopIncrement = true; cb.sendNotice('Pre-sale tickets will remain at ' + presalePrice + ' tokens until start of show',"", presalesBgColor, presalesTxtColor, "bold"); cb.sendNotice('No additional price changes made, next increment would have exceeded planned ticket show price of ' + ticketPrice + '.',cb.room_slug, green); } else if (presaleIncrements + 1 > cb.settings.presaleMaxIncrements) { stopIncrement = true; cb.sendNotice('Pre-sale tickets will remain at ' + presalePrice + ' tokens until start of show',"", presalesBgColor, presalesTxtColor, "bold"); cb.sendNotice('No additional price changes made, next increment would have exceeded max increments of ' + cb.settings.presaleMaxIncrements + '.',cb.room_slug, green); } else { cb.sendNotice('All pre-sale tickets at a price of ' + presalePrice + ' tokens have been sold!',"", presalesBgColor, presalesTxtColor, "bold"); presaleIncrements ++; nextPresalePrice = presalePrice + presaleIncAmt; presalePriceChange(nextPresalePrice,cb.room_slug); countPresaleSold = 0; ticketsLeft = cb.settings.presaleCountIncrement; } } } function addPresaleList(mod) { if (presaleArray.length > 1) { cb.sendNotice("Adding multiple users to the Fembot ticket show list.", mod, green); for (var i = 0; i < presaleArray.length; i++) { if (presaleArray[i] != '') { if (!cb.limitCam_userHasAccess(presaleArray[i])) { addRmvTicket('add', presaleArray[i]); cb.sendNotice('Added ' + presaleArray[i] + ' to the ticket show list.', mod); cb.sendNotice(mod + ' has added you to the ticket show list since you purchased a pre-sale ticket.', presaleArray[i], green); } else { cb.sendNotice(presaleArray[i] + ' is already on the ticket show list. Skipping.', mod); } } } cb.sendNotice('All users from the pre-sale list were added to the Fembot Ticket Show and notified.', mod, green); cb.sendNotice(mod + ' has added multiple users from the Pre-sale list to the Fembot Ticket Show list.\nUsers added: ' + cbjs.arrayJoin(presaleArray, ', '), '', green, '', 'normal', 'red'); } else { if (!cb.limitCam_userHasAccess(presaleArray[0])) { addRmvTicket('add', presaleArray[0]); cb.sendNotice('All users from the pre-sale list were added to the Fembot Ticket Show and notified.', mod, green); } else { cb.sendNotice('Note: User ' + presaleArray[0] + ' is already in the Fembot Ticket Show List. There are no additional users on the Pre-sale list.', mod, green); } } } // *********************************** Fembot Hidden Ticket Show Functions ************************************** function setTicketShowToggle(option, sendto, price) { if(option == 'on') { if(ticketShowToggle == 1) { cb.sendNotice('The Fembot Hidden Ticket Show feature is already enabled.',sendto,green); } else { initTicketShow(price,sendto); cb.sendNotice(dashLine90 + '\n* ' + sendto + ' has started ticket sales for the Fembot Hidden Ticket Show. Tickets are ' + ticketPrice + ' tokens.\n' + dashLine90, '', ticketBgColor, ticketTxtColor, 'bold'); cb.sendNotice('***Warning Regarding the Hidden Show***: Do not deactivate or restart the Ultra Fembot once ticket sales have started without saving the ticket show list or you will lose the list. If it is necessary to restart, please save the ticket list first (use /tickets to view and then copy) and then add those users back to the show once restarted (/addtickets).',cb.room_slug,green); cb.sendNotice('***Another Warning Regarding the Hidden Show***: The Fembot Ticket Show will update the room title at certain milestones during the show. Please ensure that no other apps are running that would affect the room title.',cb.room_slug,green); if (cb.settings.hiddenShowAllowGift === 'Yes') { cb.sendNotice(dashLine90 + '\n* The Broadcaster has enabled the the gifting of tickets. \n* You can buy extra tickets and gift them to others using the command "/giftticket user" \n* You can also give away your own ticket using the command "/givemyticketto user".\n' + dashLine90, '', ticketBgColor, ticketTxtColor, 'bold'); } } } else if(option == 'off') { if(ticketShowToggle == 0) { cb.sendNotice('The Fembot Hidden Ticket Show feature is already disabled.',sendto,green); } else if (cb.limitCam_isRunning()) { cb.sendNotice('The show is still hidden, please end the hidden show and return to a public broadcast using the command "/stopshow" before disabling the Hidden Show feature.',sendto,green); } else { ticketShowToggle = 0; if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { stopTicketTimer(); } ticketSkipNotice = true; cb.sendNotice('You have disabled the Fembot Hidden Ticket Show feature. The ticket list and outstanding ticket list are still intact.',sendto,green); } } } function initTicketShow(price,sendto) { ticketShowToggle = 1; ticketShowColors(); showStage = 'ticketsales'; setTicketPrice(price,sendto,'no'); ticketSkipMin = false; ticketSkipSec = false; setTicketMode('init',sendto); ticketSkipNotice = false; ticketShowEnded = false; ticketSalesEnded = false; countTicketsSold = 0; loadFreeTickets(); changeTicketShowSubject(); cb.setTimeout(ticketNoticeTimer, cb.settings.ticketNoticeInterval * 60000); } function ticketShowColors() { ticketTxtColor = checkTextColor("Black"); ticketBgColor = checkBgColor("Light Blue"); ticketNoticesTxtColor = checkTextColor("Dark Red"); ticketNoticesBgColor = checkBgColor("Cream"); ticketTxtColorFan = checkTextColor("Black"); ticketBgColorFan = checkBgColor("Light Green"); ticketTxtColorVIP = checkTextColor("Black"); ticketBgColorVIP = checkBgColor("Light Purple"); ticketTxtColorMod = checkTextColor("Black"); ticketBgColorMod = checkBgColor("Light Red"); } function setTicketShowOtToggle(option, sendto) { if(option == 'on') { if(ticketShowOtToggle == 1) { cb.sendNotice('The Outstanding Ticket feature is already enabled.',sendto,green); } else { ticketShowOtToggle = 1; cb.sendNotice(dashLine80 + '\n* ' + sendto + ' has started the Outstanding Ticket (OT) feature of the Hidden Ticket Show.\n* You can save your ticket if you have to leave before the show starts and use it at a later date using the command "/saveticket" (you will be removed from the current show list). \n* If you have an outstanding ticket from a previous show, you can redeem it using the command "/useticket".\n' + dashLine80, '', ticketBgColor, ticketTxtColor, 'bold'); cb.sendNotice('***Warning Regarding Outstanding Tickets***: The Outstanding tickets added and removed during the show must be made permanent by updating the list on the start page or saving the list externally and updating the Outstanding Ticket list before the next show. Changes made during the show are not saved beyond the current session.',cb.room_slug,green); } } else if(option == 'off') { if(ticketShowOtToggle == 0) { cb.sendNotice('The Outstanding Ticket feature is already disabled.',sendto,green); } else { ticketShowOtToggle = 0; cb.sendNotice('You have disabled the Outstanding Ticket (OT) feature. The outstanding ticket list is still intact, but no more tickets will be sold. The list can be viewed using the command "/otlist" or the changes for the current session can be seen using "/otchanges" to use for updating your master list.',sendto,green); } } } function loadFreeTickets() { if (cb.settings.hiddenShowFreeMods === 'Yes') { for (let i = 0; i < moderatorList.name.length; i++) { if (!cb.limitCam_userHasAccess(moderatorList.name[i]) && moderatorList.type[i] != 'broadcaster') { addRmvTicket('add',moderatorList.name[i],'mod'); } } } if (cb.settings.hiddenShowFreeFC === 'Yes') { for (let i = 0; i < fanClubList.length; i++) { if (!cb.limitCam_userHasAccess(fanClubList[i])) { addRmvTicket('add',fanClubList[i],'fan'); } } } if (cb.settings.hiddenShowFreeEFC === 'Yes') { for (let i = 0; i < extFanListArray.length; i++) { if (!cb.limitCam_userHasAccess(extFanListArray[i])) { addRmvTicket('add',extFanListArray[i],'fan'); } } } if (cb.settings.hiddenShowFreeVIP === 'Yes') { for (let i = 0; i < VIPListArray.length; i++) { if (!cb.limitCam_userHasAccess(VIPListArray[i])) { addRmvTicket('add',VIPListArray[i],'vip'); } } } } function setTicketMode(startmode,automode,sendto) { if (startmode === 'init') { if (cb.settings.hiddenShowStartMode === 'Start Show Anytime') { newTicketMode = 'manual'; } else if (cb.settings.hiddenShowStartMode === 'Start Show after Timer') { newTicketMode = 'timer'; } else if (cb.settings.hiddenShowStartMode === 'Start Show after Ticket Goal') { newTicketMode = 'ticketgoal'; } else if (cb.settings.hiddenShowStartMode === 'Start Show after Token Goal') { newTicketMode = 'tokengoal'; } if (cb.settings.hiddenShowStartAuto === 'Start from Command') { newTicketAuto = 'bc'; } else if (cb.settings.hiddenShowStartAuto === 'Automated Start') { newTicketAuto = 'auto'; } } else { if(startmode != '' && startmode != null) { newTicketMode = startmode; } else { newTicketMode = ticketStartMode; } if(automode != '' && automode != null) { newTicketAuto = automode; } else { newTicketAuto = ticketModeAuto; } } if (ticketStartMode === 'timer' && newTicketMode != 'timer') { if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { stopTicketTimer(sendto); } } if (newTicketMode === 'manual') { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; cb.sendNotice('Ticket Show start mode is set to "Manual", the show will be started by the broadcaster or moderator.','', ticketBgColor, ticketTxtColor, 'bold'); } else if (newTicketMode === 'timer') { if (cb.settings.hiddenShowStartTimer >= 1) { ticketStartMode = 'timer'; ticketTimeAmt = cb.settings.hiddenShowStartTimer; if (newTicketAuto === 'auto') { ticketAutoTimer(ticketTimeAmt); ticketModeAuto = 'auto'; cb.sendNotice('Ticket Show start mode is set to "Automatic timer" with a duration of ' + ticketTimeAmt + ' minutes. The Ticket Show will start automatically when the timer runs out.','', ticketBgColor, ticketTxtColor, 'bold'); } else { ticketModeAuto = 'bc'; cb.sendNotice('Ticket Show start mode is set to "Broadcaster managed timer". The broadcaster will set a timer and start the show when the timer runs out.','', ticketBgColor, ticketTxtColor, 'bold'); } } else { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; ticketIncAmt = cb.settings.ticketIncreasePerIncrement; cb.sendNotice('Ticket Show start is set to manual mode. Mode was requested for automatic timer, but the timer was not set on the start page. You can restart the bot and update the missing time, or continue and start the show manually at the end of a timer or at a time of your choosing.', sendto, green); } } else if (newTicketMode === 'tokengoal') { if (cb.settings.hiddenShowGoal >= 1) { ticketStartMode = 'tokengoal'; ticketShowGoalTokens = cb.settings.hiddenShowGoal; if (newTicketAuto === 'auto') { ticketModeAuto = 'auto'; cb.sendNotice('Ticket Show start mode is set to "Automatic at token goal." There will be a short 2 minute countdown started once the goal is met for total tip amount (' + ticketShowGoalTokens + ' tokens), and then the show will start automatically.','', ticketBgColor, ticketTxtColor, 'bold'); } else { ticketModeAuto = 'bc'; cb.sendNotice('Ticket Show start mode is set to "Broadcaster managed token goal". The broadcaster will start the show once the goal is met for the total tips (' + ticketShowGoalTokens + ' tokens).','', ticketBgColor, ticketTxtColor, 'bold'); } } else { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; ticketIncAmt = cb.settings.ticketIncreasePerIncrement; cb.sendNotice('Ticket Show start is set to manual mode. Mode was requested for automatic goal start, but the goal was not set on the start page. You can restart the bot and update the missing goal, update the goal using the command "/chgticketgoal [amt]" and then change the mode using "/chgticketmode goal", or continue and start the show manually at the end of a timer or at a time of your choosing.', sendto, green); } } else if (newTicketMode === 'ticketgoal') { if (cb.settings.hiddenShowGoal >= 1) { ticketStartMode = 'ticketgoal'; ticketShowGoalTickets = cb.settings.hiddenShowGoal; if (newTicketAuto === 'auto') { ticketModeAuto = 'auto'; cb.sendNotice('Ticket Show start mode is set to "Automatic at ticket goal." There will be a short 2 minute countdown started once the goal is met for tickets sold (' + ticketShowGoalTickets + ' tickets), and then the show will start automatically.','', ticketBgColor, ticketTxtColor, 'bold'); } else { ticketModeAuto = 'bc'; cb.sendNotice('Ticket Show start mode is set to "Broadcaster managed ticket goal". The broadcaster will start the show once the goal is met for tickets sold (' + ticketShowGoalTickets + ' tickets).','', ticketBgColor, ticketTxtColor, 'bold'); } } else { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; ticketIncAmt = cb.settings.ticketIncreasePerIncrement; cb.sendNotice('Ticket Show start is set to manual mode. Mode was requested for automatic goal start, but the goal was not set on the start page. You can restart the bot and update the missing goal, update the goal using the command "/chgticketgoal [amt]" and then change the mode using "/chgticketmode goal", or continue and start the show manually at the end of a timer or at a time of your choosing.', sendto, green); } } } function setTicketAuto(automode) { if (automode === 'bc') { ticketModeAuto = 'bc'; } else if (automode === 'auto') { ticketModeAuto = 'auto'; } } function ticketPriceChangeNotice(price) { cb.sendNotice(':ticket_red_small :ticket_red_small :ticket_red_small :ticket_red_small :ticket_red_small \n' + '\u21D2 . . . . Ticket Show Price Updated!!!. . . . . \u21D0 \n' + '\u21D2 . . . . Tickets are now ' + ticketPrice + ' tokens!!! . . . . . \u21D0 \n' + ':ticket_red_small :ticket_red_small :ticket_red_small :ticket_red_small :ticket_red_small' , "", ticketNoticesBgColor, ticketNoticesTxtColor, "bold"); } function ticketNoticeTimer() { if(ticketShowToggle == 1) { if (showStage === 'ticketsales') { cb.sendNotice(cb.settings.hiddenShowPreNotice, "", ticketBgColor, ticketTxtColor, "bold"); if (ticketStartMode === 'ticketgoal') { cb.sendNotice('Start Mode: Ticket Goal\n Progress: ' + ticketShowTotalTickets + ' / ' + ticketShowGoalTickets + ' tickets', "", ticketBgColor, ticketTxtColor, "bold"); } else if (ticketStartMode === 'tokengoal') { cb.sendNotice('Start Mode: Token Goal\n Progress: ' + ticketShowTotalTips + ' / ' + ticketShowGoalTokens + ' tokens', "", ticketBgColor, ticketTxtColor, "bold"); } else if (ticketStartMode === 'timer') { cb.sendNotice('Start Mode: Timer\n ' + ((ticketSecsRemain > 0 || ticketMinsRemain > 0) ? ticketTimeLeft() : "Timer not yet started"), "", ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice('Start Mode: Manual', "", ticketBgColor, ticketTxtColor, "bold"); } } else if (showStage === 'ticketshow') { cb.sendNotice(cb.settings.hiddenShowNotice, "", ticketBgColor, ticketTxtColor, "bold"); } else if (showStage === 'aftershow') { cb.sendNotice(cb.settings.afterShowNotice, "", ticketBgColor, ticketTxtColor, "bold"); } cb.sendNotice('Ticket Holders: ' + countTicketsSold + '\nViewers: ' + ticketShowViewerList.length + '\nTicket Price: ' + ticketPrice + ' tokens', "", ticketStatsBgColor); if (!ticketSkipNotice) { cb.setTimeout(ticketNoticeTimer, cb.settings.ticketNoticeInterval * 60000); } else { ticketSkipNotice = false; } } } function ticketAutoTimer(addtime) { if (ticketModeAuto === 'auto') { cb.sendNotice('An automatic timer was started, ticket show price will be ' + ticketPrice + ' tokens.', "", ticketBgColor, ticketTxtColor, "bold"); } else if (ticketModeAuto === 'bc') { cb.sendNotice('A timer was started to provide an countdown to approximate showtime. \n The broadcaster will start the show after the timer runs out.', "", ticketBgColor, ticketTxtColor, "bold"); } ticketMinsRemain = addtime; ticketSecsRemain = 0; ticketStartTime = new Date(); ticketStopTime = new Date(ticketStartTime.getTime() + ticketMinsRemain * 60000); ticketTimerMin(); } function ticketTimerMin() { ticketSeconds = ticketCheckMin(); if (ticketSkipMin === false && ticketStartMode === 'timer' && ticketShowToggle == 1 && (ticketSeconds >= 55 || ticketSeconds == 0)) { switch (ticketMinsRemain) { case 120: case 90: case 60: case 45: case 30: case 20: case 15: case 10: case 9: case 8: case 7: case 6: case 5: case 4: case 3: case 2: cb.sendNotice('\u23f1 \u23f1 \u23f1 There are ' + ticketMinsRemain + ' minutes left on the timer to buy a ticket for ' + ticketPrice + ' tokens before the show starts! \u23f1 \u23f1 \u23f1', "", yellow, "", "bold"); } ticketMinsRemain--; if (ticketMinsRemain > 0) { cb.setTimeout(ticketTimerMin, 60000); } else { ticketSecsRemain = 60; cb.sendNotice('\u23f1 \u23f1 \u23f1 There is 1 minute left on the timer to buy a ticket for ' + ticketPrice + ' tokens before the show starts!! \u23f1 \u23f1 \u23f1', "", red, "", "bold"); ticketTimerSec(); } } else { if (ticketSkipMin === true) { ticketSkipMin = false; } } } function ticketCheckMin() { var ticketTimeLeft = ticketTimeCal(); var ticketMS = ticketTimeLeft % 1000; var ticketSeconds = ((ticketTimeLeft - ticketMS) % 60000); ticketSeconds = ticketSeconds / 1000; return ticketSeconds; } function ticketTimerSec() { if (!ticketSkipSec && ticketStartMode === 'timer' && ticketShowToggle == 1 ) { if (ticketMinsRemain > 0) { cb.setTimeout(ticketTimerMin, ticketSecsRemain*1000); } else { ticketSecsRemain--; if (ticketSecsRemain < 1) { if (ticketStartMode = 'timer' && ticketModeAuto === 'auto') { cb.sendNotice("\u23f0 \u23f0 \u23f0 Time is up! Ticket Show is starting! \u23f0 \u23f0 \u23f0", "", ticketNoticesBgColor, ticketNoticesTxtColor, "bold"); startTicketShow(cb.room_slug); } else { cb.sendNotice("\u23f0 \u23f0 \u23f0 Time is up! Broadcaster will be starting the show! \u23f0 \u23f0 \u23f0", "", ticketNoticesBgColor, ticketNoticesTxtColor, "bold"); } } else { switch (ticketSecsRemain) { case 30: case 10: case 5: case 4: case 3: case 2: case 1: cb.sendNotice('\u23f1 \u23f1 \u23f1 There are ' + ticketSecsRemain + ' second' + (ticketSecsRemain > 1 ? "s" : "") + ' left! \u23f1 \u23f1 \u23f1', "", red, "", "bold"); } } if (ticketSecsRemain > 0) { cb.setTimeout(ticketTimerSec, 1000); } } } else { ticketSkipSec = false; } } function ticketAddTime(tickettimetoadd, u) { ticketStopTime = new Date(ticketStopTime.getTime() + tickettimetoadd * 60000); cb.sendNotice(u + " has added " + tickettimetoadd + " minute" + (tickettimetoadd === 1 || tickettimetoadd === -1 ? "" : "s") + " to the timer.",cb.room_slug,"","", "bold"); cb.sendNotice(tickettimetoadd + " minute" + (tickettimetoadd === 1 || tickettimetoadd === -1 ? "" : "s") + " have been added to the timer. Now " + ticketTimeLeft(),"",yellow,"", "bold"); ticketMinsRemain = ticketMinsRemain + tickettimetoadd; if (ticketMinsRemain < 1) { ticketSkipMin = true; ticketTimeLeft = ticketTimeCal(); ticketMS = ticketTimeLeft % 1000; ticketSeconds = ((ticketTimeLeft - ticketMS) % 60000) / 1000; ticketSecsRemain = ticketSeconds; ticketTimerSec(); } return; } function ticketTimeCal() { ticketStartTime = new Date(); return ticketStopTime - ticketStartTime.getTime(); } function stopTicketTimer(mod) { ticketStopTime = new Date(); if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { ticketSkipMin = true; ticketSkipSec = true; } ticketMinsRemain = 0; ticketSecsRemain = 0; if(mod != null && mod != '') { cb.sendNotice(mod + ' has stopped the ticket show timer.',"",yellow,"", "bold"); } } function ticketTimeLeft(user) { var ticketTimeLeft = ticketTimeCal(); var ticketMS = ticketTimeLeft % 1000; var ticketSeconds = ((ticketTimeLeft - ticketMS) % 60000); var ticketMinutes = ((ticketTimeLeft - ticketSeconds - ticketMS) % 3600000); var ticketHours = (ticketTimeLeft - ticketMinutes - ticketSeconds - ticketMS); ticketSeconds = ticketSeconds / 1000; ticketMinutes = ticketMinutes / 60000; ticketHours = ticketHours / 3600000; if (ticketHours > 0) { return ticketHours + " hour" + (ticketHours > 1 ? "s" : "") + " and " + ticketMinutes + " minute" + (ticketMinutes > 1 ? "s" : "") + " remaining on the ticket show timer."; } else if (ticketMinutes > 0 && ticketSeconds === 0) { return ticketMinutes + " minute" + (ticketMinutes > 1 ? "s" : "") + " remaining on the ticket show timer."; } else if (ticketMinutes > 0) { return ticketMinutes + " minute" + (ticketMinutes > 1 ? "s" : "") + " and " + ticketSeconds + " second" + (ticketSeconds > 1 ? "s" : "") + " remaining on the ticket show timer."; } else { return ticketSeconds + " second" + (ticketSeconds > 1 ? "s" : "") + " remaining on the ticket show timer."; } } function addRmvTicket(mode,user,usertype,tipamount) { switch(mode) { case 'add': { cb.limitCam_addUsers([user]); if (!cbjs.arrayContains(ticketShowViewerList,user)) { ticketShowViewerList.push(user); } if (usertype == 'fan') { cb.sendNotice('Fan Club member ' + user + ' has been added to the ticket show list.', "", ticketBgColorFan, ticketTxtColorFan, "bold"); } else if (usertype == 'vip') { cb.sendNotice('VIP List member ' + user + ' has been added to the ticket show list.', "", ticketBgColorVIP, ticketTxtColorVIP, "bold"); } else if (usertype == 'mod') { cb.sendNotice('Moderator ' + user + ' has been added to the ticket show list.', "", ticketBgColorMod, ticketTxtColorMod, "bold"); } else { cb.sendNotice(user + ' has been added to the ticket show list.', "", ticketBgColor, ticketTxtColor, "bold"); } countTicketsSold ++; break; } case 'rmv': { cb.limitCam_removeUsers([user]); if (cbjs.arrayContains(ticketShowViewerList,user)) { ticketShowViewerList.pop(user); } cb.sendNotice(user + ' has been removed from the ticket show list.', "", ticketBgColor, ticketTxtColor, "bold"); countTicketsSold --; break; } case 'addtip': { cb.limitCam_addUsers([user]); if (!cbjs.arrayContains(ticketShowViewerList,user)) { ticketShowViewerList.push(user); } if (usertype == 'fan') { cb.sendNotice('Welcome Fan Club member ' + user + ', you have been added to the ticket show list.', "", ticketBgColorFan, ticketTxtColorFan, "bold"); } else if (usertype == 'vip') { cb.sendNotice('Welcome VIP List member ' + user + ', you have been added to the ticket show list.', "", ticketBgColorVIP, ticketTxtColorVIP, "bold"); } else if (usertype == 'mod') { cb.sendNotice('Welcome ' + user + ', you have been added to the ticket show list.', "", ticketBgColorMod, ticketTxtColorMod, "bold"); } else { cb.sendNotice('Welcome ' + user + ', you have been added to the ticket show list.', "", ticketBgColor, ticketTxtColor, "bold"); } countTicketsSold ++; if (tipamount >= (2*ticketPrice)) { addRmvTicket('addextra', user, 'common', (tipamount - ticketPrice)); } break; } case 'addextra': { var numtickets = Math.floor(parseInt(tipamount / ticketPrice)); if (numtickets > 0) { if (!cbjs.arrayContains(ticketShowExtraTickets.name,user)) { ticketShowExtraTickets.name.push(user); ticketShowExtraTickets.count.push(numtickets); } else { index = ticketShowExtraTickets.name.indexOf(user); ticketShowExtraTickets.count[index] = ticketShowExtraTickets.count[index] + numtickets; } cb.sendNotice(user + ', you have purchased ' + numtickets + ' extra tickets to the show. You can gift these to other users with the command "/giftticket user". Each time you use the command uses up one of your extra tickets. Please make sure to spell the user name right, gifted tickets cannot be recovered if they are gifted incorrectly.', user, ticketBgColor, ticketTxtColor, "bold"); } break; } } } function checkCumulative(tipBy,tipAmount,cumTktPrice,usertype,saletype) { if (cb.settings.hiddenShowCumulative == 'Yes') { if (!cbjs.arrayContains(ticketCumulative.name, tipBy)) { ticketCumulative.name.push(tipBy); ticketCumulative.amount.push(tipAmount); } else { index = ticketCumulative.name.indexOf(tipBy); if (ticketCumulative.amount[index] + tipAmount >= cumTktPrice) { if (saletype == 'ticket') { addRmvTicket('addtip', tipBy, usertype, tipAmount); } else if (saletype == 'presale') { addRmvPresale('addtip', tipBy); } ticketCumulative.amount[index] = 0; } else { ticketCumulative.amount[index] += tipAmount; } } } } function giftTicket(fromuser,touser) { cb.limitCam_addUsers([touser]); if (!cbjs.arrayContains(ticketShowViewerList,touser)) { ticketShowViewerList.push(touser); } cb.sendNotice('Welcome ' + touser + ', ' + fromuser + ' has gifted you a ticket to the show!', '', ticketBgColor, ticketTxtColor, 'bold'); countTicketsSold ++; } function giveAwayTicket(fromuser,touser) { cb.limitCam_addUsers([touser]); cb.limitCam_removeUsers([fromuser]); if (!cbjs.arrayContains(ticketShowViewerList,touser)) { ticketShowViewerList.push(touser); } if (cbjs.arrayContains(ticketShowViewerList,fromuser)) { ticketShowViewerList.pop(fromuser); } cb.sendNotice('Welcome ' + touser + ', ' + fromuser + ' has gifted you a ticket to the show!', '', ticketBgColor, ticketTxtColor, 'bold'); } function addRmvOutstandingTicket(mode,user) { switch(mode) { case "add": { outstandingTicketArray.push(user); populateOtChangesArray(user,'add'); break; } case "rmv": { cbjs.arrayRemove(outstandingTicketArray,user); populateOtChangesArray(user,'rmv'); break; } } } function populateOtChangesArray(user,type) { if (cbjs.arrayContains(otChangesArray.name,user)) { index = otChangesArray.name.indexOf(user); if (otChangesArray.type[index] != type) { otChangesArray.name.push(user); otChangesArray.type.push(type); } else { return; } } else { otChangesArray.name.push(user); otChangesArray.type.push(type); } } function ticketShowGoalProgress(tipAmount) { ticketShowTotalTips = ticketShowTotalTips + tipAmount; ticketShowTotalTickets++; if (ticketStartMode === 'tokengoal' && ticketShowTotalTips >= ticketShowGoalTokens) { cb.sendNotice(dashLine80 + '\n :siren1 *** The ticket show Tip goal has been met!! *** :siren1 \n*** Starting a 2 minute timer for automatic start of show! ***\n' + dashLine80,"", ticketNoticesBgColor, ticketNoticesTxtColor, "bold"); ticketStartMode = 'timer'; ticketAutoTimer(2); } else if (ticketStartMode === 'ticketgoal' && ticketShowTotalTickets >= ticketShowGoalTickets) { cb.sendNotice(dashLine80 + '\n :siren1 ** The ticket show Ticket goal has been met!! ** :siren1 \n*** Starting a 2 minute timer for automatic start of show! ***\n' + dashLine80,"", ticketNoticesBgColor, ticketNoticesTxtColor, "bold"); ticketStartMode = 'timer'; ticketAutoTimer(2); } } function startTicketShow(startedby) { if (tokenPollToggle == 1 && cb.settings.startPollTimerWithShow == 'Yes, switch to timed poll at show start') { if(pollRunning && pollType == 'Timer' && (pollMinsRemain > 0 || pollSecsRemain > 0)) { cb.sendNotice('Note: Poll timer not started with /startshow as it is already running. You can adjust the time remaining with the "/polladdtime [X]" command.', startedby, green); } else { timetoadd = parseInt(cb.settings.startPollMinAfterShow) if (timetoadd <= 0) { timetoadd = 10; cb.sendNotice('No setting defined for token poll end timer, defaulting to 10 min.', startedby, green); } pollSwitchToTimer(timetoadd, startedby); } } else { cb.sendNotice('Note: Poll Timer not started with /startshow per configuration.', startedby, green); } var nowTime = new Date(); cb.sendNotice(dashLine60 + '\n :siren1 :siren1 :siren1 ' + startedby + ' has started the show! :siren1 :siren1 :siren1 \n' + dashLine60,'',ticketBgColor, ticketNoticesTxtColor, "bold"); cb.sendNotice('*** REMINDER: Please do not deactivate the Hidden Ticket Show feature until after you end your show with the "/stopshow" command.', cb.room_slug, ticketBgColor, ticketTxtColor, "bold"); cb.limitCam_start('Fembot Ticket Show\n\nHidden Cam show in progress \nCheck room notices for ticket price, and if tickets are still being sold'); showStage = 'ticketshow'; changeTicketShowSubject(); if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { stopTicketTimer(); } hiddenTime = Date.now(); } function restartTicketShow(startedby) { var nowTime = new Date(); cb.sendNotice(dashLine80 + '\n :siren1 \u25C8 \u25C8 \u25C8 ' + startedby + ' has restarted the ticket show! \u25C8 \u25C8 \u25C8 :siren1 \n \u25C8 \u25C8 \u25C8 All current ticket holders still have access. \u25C8 \u25C8 \u25C8 \n \u25C8 \u25C8 \u25C8 Ticket sales are open, price is ' + ticketPrice + ' tokens. \u25C8 \u25C8 \u25C8 \n' + dashLine80,'',ticketBgColor, ticketNoticesTxtColor, "bold"); cb.limitCam_start('Fembot Ticket Show\n\nHidden Cam show in progress. Tip ' + ticketPrice + ' tokens to unlock the screen!'); showStage = 'ticketshow'; changeTicketShowSubject(); ticketShowEnded = false; ticketSalesEnded = false; if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { stopTicketTimer(); } hiddenTime = Date.now(); } function warnShowEnding(by) { showStage = 'showwarn'; changeTicketShowSubject(); if (cb.settings.hiddenShowReducePriceWarn > 0) { ticketPrice = ticketPrice - cb.settings.hiddenShowReducePriceWarn; changeTicketShowSubject(); cb.sendNotice(dashLine90 + '\n :siren1 \u25C8 \u25C8 \u25C8 ' + by + ' has indicated the show is nearly finished. \u25C8 \u25C8 \u25C8 :siren1 \n \u25C8 \u25C8 It is not recommended to buy a ticket, but sales are still open. \u25C8 \u25C8 \n \u25B7 \u25B7 \u25B7 \u25B7 \u25B7 The Ticket Price has been reduced to ' + ticketPrice + ' tokens! \u25C1 \u25C1 \u25C1 \u25C1 \u25C1 \n' + dashLine90,'',ticketBgColor,ticketNoticesTxtColor,'bold'); } else { cb.sendNotice(dashLine90 + '\n :siren1 \u25C8 \u25C8 \u25C8 ' + by + ' has indicated the show is nearly finished. \u25C8 \u25C8 \u25C8 :siren1 \n \u25C8 \u25C8 It is not recommended to buy a ticket, but sales are still open. \u25C8 \u25C8 \n' + dashLine90,'',ticketBgColor,ticketNoticesTxtColor,'bold'); } } function stopTicketSales(stoppedby) { cb.sendNotice(dashLine70 + '\n :siren1 :alert1 :siren1 \u25B7 \u25B7 ' + stoppedby + ' has ended ticket sales. \u25C1 \u25C1 :siren1 :alert1 :siren1 \n' + dashLine70,'',ticketBgColor,ticketNoticesTxtColor,'bold'); showStage = 'showfinale'; changeTicketShowSubject(); ticketSkipNotice = true; ticketSalesEnded = true; } function stopTicketShow(stoppedby) { cb.sendNotice(dashLine60 + '\n :alert1 \u25C8 \u25C8 \u25C8 ' + stoppedby + ' has ended the show \u25C8 \u25C8 \u25C8 :alert1 \n \u25C8 \u25C8 \u25C8 \u25C8 \u25C8 Ticket Show length ' + ((Date.now() - hiddenTime)/60000).toFixed(2) + ' minutes. \u25C8 \u25C8 \u25C8 \u25C8 \u25C8 \n' + dashLine60,'',ticketBgColor,ticketNoticesTxtColor,'bold'); cb.limitCam_stop(); cb.sendNotice(dashLine70 + '\n :siren1 :siren1 :siren1 The broadcast is returning to Public Chat. :siren1 :siren1 :siren1 \n' + dashLine70, '',ticketBgColor,ticketNoticesTxtColor,'bold'); hiddenTime = 0; ticketSkipNotice = true; ticketShowEnded = true; ticketSalesEnded = true; showStage = 'aftershow'; ticketSubjectText = cb.settings.afterShowNotice; changeTicketShowSubject(); } function useTicket(user) { addRmvOutstandingTicket('rmv',user); cb.limitCam_addUsers([user]); if (!cbjs.arrayContains(ticketShowViewerList,user)) { ticketShowViewerList.push(user); } } function saveTicket(user) { addRmvOutstandingTicket('add',user); cb.limitCam_removeUsers([user]); if (cbjs.arrayContains(ticketShowViewerList,user)) { ticketShowViewerList.pop(user); } } function getShowTime(u) { cb.sendNotice('*** Hidden Cam show in progress for ' + ((Date.now() - hiddenTime)/60000).toFixed(2) + ' minutes. ***', u, ticketBgColor,ticketTxtColor,'bold'); } function changeTicketShowSubject() { if (showStage == 'ticketsales') { newsubject = 'TICKET SHOW SALES [' + ticketPrice + ' tokens]: ' + ticketSubjectText; } else if (showStage == 'ticketshow') { newsubject = 'TICKET SHOW -- IN PROGRESS [' + ticketPrice + ' tokens]: ' + ticketSubjectText; } else if (showStage == 'showwarn') { newsubject = 'TICKET SHOW -- ENDING SOON [' + ticketPrice + ' tokens]: ' + ticketSubjectText; } else if (showStage == 'showfinale') { newsubject = 'TICKET SHOW -- SALES ENDED: ' + ticketSubjectText; } else if (showStage == 'aftershow') { newsubject = 'TICKET SHOW HAS ENDED: ' + ticketSubjectText; } else { newsubject = 'TICKET SHOW'; } cb.changeRoomSubject(newsubject); } // *********************************** Raffle Functions ************************************** function setRaffleToggle(option, mod) { if(option == 'on') { if(raffleToggle == 1) { cb.sendNotice('The Tip Response is already enabled.', mod, green); } else { initRaffle(mod); cb.sendNotice('You have enabled the Raffle with a End Mode of ' + raffleWhenDrawing + ' and it will be ended by ' + raffleAutoDrawing + '. Available raffle commands can be seen by typing "/fbhelp raffle".', mod, green); } } else if(option == 'off') { if(raffleToggle == 0) { cb.sendNotice('The Raffle is already disabled.', mod, green); } else { raffleToggle = 0; raffleSkipNotice = true; cb.sendNotice('You have disabled the Raffle.', mod, green); cb.sendNotice(' ' + mod + ' has disabled the Raffle Feature. You can no longer tip for Raffle Tickets.',"",green,"","bold"); } } } function initRaffle(sendto) { raffleToggle = 1; raffleTextColor = checkTextColor("Dark Green"); raffleBgColor = checkBgColor("Cream"); raffleWinnerBgColor = checkBgColor("Light Yellow"); priceChecker('add','Raffle Price 1',rafflePrice[1]); priceChecker('add','Raffle Price 2',rafflePrice[2]); priceChecker('add','Raffle Price 3',rafflePrice[3]); priceChecker('add','Raffle Price 4',rafflePrice[4]); priceChecker('add','Raffle Price 5',rafflePrice[5]); setRaffleMode('init',sendto); raffleSkipMin = false; raffleSkipSec = false; raffleSkipNotice = false; cb.setTimeout(raffleNoticeTimer, cb.settings.raffleNoticeInterval * 60000); } function setRaffleMode(endmode,drawingmode,sendto) { if (endmode === 'init') { if (cb.settings.raffleWhenDrawing === 'Drawing at Broadcaster Discretion') { newRaffleEndMode = 'manual'; } else if (cb.settings.raffleWhenDrawing === 'Drawing after a Time Period') { newRaffleEndMode = 'timer'; } else if (cb.settings.raffleWhenDrawing === 'Drawing after a Ticket Goal') { newRaffleEndMode = 'ticketgoal'; } else if (cb.settings.raffleWhenDrawing === 'Drawing after a Token Goal') { newRaffleEndMode = 'tokengoal'; } if (cb.settings.raffleAutoDrawing === 'Broadcaster Performs Drawing') { newRaffleDrawingMode = 'bc'; } else if (cb.settings.raffleAutoDrawing === 'Automated Drawing') { newRaffleDrawingMode = 'auto'; } } else { if(endmode != '' && endmode != null) { newRaffleEndMode = endmode; } else { newRaffleEndMode = raffleEndMode; } if(drawingmode != '' && drawingmode != null) { newRaffleDrawingMode = drawingmode; } else { newRaffleDrawingMode = raffleDrawingMode; } } if (raffleEndMode === 'timer' && newRaffleEndMode != 'timer') { stopRaffleTimer(sendto); } if (newRaffleEndMode === 'manual') { raffleEndMode = 'manual'; raffleDrawingMode = 'bc'; cb.sendNotice('Raffle drawing mode is set to "Broadcaster Discretion", the raffle drawing will occur when the broadcaster chooses.','', raffleBgColor, raffleTextColor, 'bold'); } else if (newRaffleEndMode === 'timer') { if (cb.settings.raffleDrawingInterval >= 1) { raffleEndMode = 'timer'; raffleTimeAmt = cb.settings.raffleDrawingInterval; if (newRaffleDrawingMode === 'auto') { raffleAutoTimer(raffleTimeAmt); raffleDrawingMode = 'auto'; cb.sendNotice('Raffle drawing mode is set to "Automatic timer" with a duration of ' + raffleTimeAmt + ' minutes. The drawing will be performed automatically when the timer runs out.','', raffleBgColor, raffleTextColor, 'bold'); } else { raffleDrawingMode = 'bc'; cb.sendNotice('Raffle drawing mode is set to "Broadcaster managed timer". The broadcaster will set a timer and perform the drawing when the timer runs out.','', raffleBgColor, raffleTextColor, 'bold'); } } else { raffleEndMode = 'manual'; raffleDrawingMode = 'bc'; cb.sendNotice('Raffle drawing is set to manual mode/broadcaster discretion. Mode was requested for automatic timer, but the timer length was not set on the start page. You can restart the bot and update the missing time, or continue and start a manual timer. You can use the command /raffledrawing at the end of the timer, see help details on the how to use the command.', sendto, green); } } else if (newRaffleEndMode === 'ticketgoal') { if (cb.settings.raffleDrawingGoal >= 1) { raffleEndMode = 'ticketgoal'; raffleTicketGoalAmt = cb.settings.raffleDrawingGoal; if (newRaffleDrawingMode === 'auto') { raffleDrawingMode = 'auto'; cb.sendNotice('Raffle drawing mode is set to "Automatic at ticket goal". There will be a short 2 minute countdown started once the goal is met for number of tickets sold (' + raffleTicketGoalAmt + ' tickets), and then the drawing will be performed automatically.','', raffleBgColor, raffleTextColor, 'bold'); } else { raffleDrawingMode = 'bc'; cb.sendNotice('Raffle drawing mode is set to "Broadcaster managed ticket goal". The broadcaster will perform the drawing once the goal is met for number of tickets sold (' + raffleTicketGoalAmt + ' tickets).','', raffleBgColor, raffleTextColor, 'bold'); } } else { raffleEndMode = 'manual'; raffleDrawingMode = 'bc'; cb.sendNotice('Raffle drawing is set to manual mode. Mode was requested for automatic goal start, but the goal was not set on the start page. You can restart the bot and update the missing goal, update the ticket goal using the command "/chgrafflegoal [amt]" and then change the mode using "/chgrafflemode ticketgoal", or continue and start the show manually at the end of a timer or at a time of your choosing.', sendto, green); } } else if (newRaffleEndMode === 'tokengoal') { if (cb.settings.raffleDrawingGoal >= 1) { raffleEndMode = 'tokengoal'; raffleTipGoalAmt = cb.settings.raffleDrawingGoal; if (newRaffleDrawingMode === 'auto') { raffleDrawingMode = 'auto'; cb.sendNotice('Raffle drawing mode is set to "Automatic at token goal". There will be a short 2 minute countdown started once the goal is met for total tip amount (' + raffleTipGoalAmt + ' tokens), and then the drawing will be performed automatically.','', raffleBgColor, raffleTextColor, 'bold'); } else { raffleDrawingMode = 'bc'; cb.sendNotice('Raffle drawing mode is set to "Broadcaster managed token goal". The broadcaster will perform the drawing once the goal is met for total tip amount (' + raffleTipGoalAmt + ' tokens).','', raffleBgColor, raffleTextColor, 'bold'); } } else { raffleEndMode = 'manual'; raffleDrawingMode = 'bc'; cb.sendNotice('Raffle drawing is set to manual mode. Mode was requested for automatic goal start, but the goal was not set on the start page. You can restart the bot and update the missing goal, update the ticket goal using the command "/chgrafflegoal [amt]" and then change the mode using "/chgrafflemode tokengoal", or continue and start the show manually at the end of a timer or at a time of your choosing.', sendto, green); } } } function loadPrevRaffleResults(sendto) { if (cb.settings.raffleTicketList != '' && cb.settings.raffleTicketList != null) { var n = cb.settings.raffleTicketList; temprafflearray = n.split(','); if(temprafflearray.length > 0) { for (var i = 0; i < temprafflearray.length; i++) { raffleentries = temprafflearray[i].split(':'); if(raffleentries[0] == '' || raffleentries[0] == null || raffleentries[1] == '' || raffleentries[1] == null) { cb.sendNotice('Cannot load previous raffle ticket list entry ' + temprafflearray[i] + ', invalid formatting within entry.', sendto, green); } else { rafflePrevTicketsArray.name.push(raffleentries[0]); rafflePrevTicketsArray.level.push(raffleentries[1]); raffleCurrentTicketsArray.name.push(raffleentries[0]); raffleCurrentTicketsArray.level.push(raffleentries[1]); for (var j = 1; j <= 5; j++) { if (raffleentries[1] == j) { raffleTicketsSoldLvl[j]++; raffleGoalTicketsSold++; raffleTotalTicketsSold++; raffleTotalTokens += rafflePrice[j]; raffleGoalTokens += rafflePrice[j]; break; } } } } } else { cb.sendNotice('Cannot load previous raffle ticket list, invalid formatting of list: ' + temprafflearray, sendto, green); } } } function raffleNoticeTimer() { if(raffleToggle == 1) { if (!raffleSkipNotice) { cb.sendNotice(cb.settings.raffleNoticeText, "", ticketStatsBgColor,"","bold"); if (raffleEndMode === 'ticketgoal') { cb.sendNotice('Raffle End Mode: Ticket Goal\n Progress: ' + raffleGoalTicketsSold + ' / ' + raffleTicketGoalAmt + ' tickets', "", ticketStatsBgColor,"","bold"); } else if (raffleEndMode === 'tokengoal') { cb.sendNotice('Raffle End Mode: Token Goal\n Progress: ' + raffleGoalTokens + ' / ' + raffleTipGoalAmt + ' tokens', "", ticketStatsBgColor,"","bold"); } else if (raffleEndMode === 'timer') { if (raffleMinsRemain > 0 || raffleSecsRemain > 0) { cb.sendNotice('Raffle End Mode: Timer\n ' + raffleTimeLeft(), "", ticketStatsBgColor,"","bold"); } else { cb.sendNotice('Raffle End Mode: Timer (not running)', "", ticketStatsBgColor,"","bold"); } } else { cb.sendNotice('Raffle End Mode: Broadcaster Choice', "", ticketStatsBgColor,"","bold"); } if (rafflePrice[1] > 0 || rafflePrizeList1.length > 0) { cb.sendNotice('Raffle Level 1 - ', "", ticketStatsBgColor,"","bold"); cb.sendNotice('...Ticket Price: ' + rafflePrice[1] + ' tokens', "", ticketStatsBgColor); cb.sendNotice('...Tickets Sold: ' + raffleTicketsSoldLvl[1], "", ticketStatsBgColor); cb.sendNotice('...Prize' + (rafflePrizeList1.length > 1 ? 's' : '') + ': ' + cbjs.arrayJoin(rafflePrizeList1, ', '), "", ticketStatsBgColor); } if (rafflePrice[2] > 0 || rafflePrizeList2.length > 0) { cb.sendNotice('Raffle Level 2 - ', "", ticketStatsBgColor,"","bold"); cb.sendNotice('...Ticket Price: ' + rafflePrice[2] + ' tokens', "", ticketStatsBgColor); cb.sendNotice('...Tickets Sold: ' + raffleTicketsSoldLvl[2], "", ticketStatsBgColor); cb.sendNotice('...Prize' + (rafflePrizeList2.length > 1 ? 's' : '') + ': ' + cbjs.arrayJoin(rafflePrizeList2, ', '), "", ticketStatsBgColor); } if (rafflePrice[3] > 0 || rafflePrizeList3.length > 0) { cb.sendNotice('Raffle Level 3 - ', "", ticketStatsBgColor,"","bold"); cb.sendNotice('...Ticket Price: ' + rafflePrice[3] + ' tokens', "", ticketStatsBgColor); cb.sendNotice('...Tickets Sold: ' + raffleTicketsSoldLvl[3], "", ticketStatsBgColor); cb.sendNotice('...Prize' + (rafflePrizeList3.length > 1 ? 's' : '') + ': ' + cbjs.arrayJoin(rafflePrizeList3, ', '), "", ticketStatsBgColor); } if (rafflePrice[4] > 0 || rafflePrizeList4.length > 0) { cb.sendNotice('Raffle Level 4 - ', "", ticketStatsBgColor,"","bold"); cb.sendNotice('...Ticket Price: ' + rafflePrice[4] + ' tokens', "", ticketStatsBgColor); cb.sendNotice('...Tickets Sold: ' + raffleTicketsSoldLvl[4], "", ticketStatsBgColor); cb.sendNotice('...Prize' + (rafflePrizeList4.length > 1 ? 's' : '') + ': ' + cbjs.arrayJoin(rafflePrizeList4, ', '), "", ticketStatsBgColor); } if (rafflePrice[5] > 0 || rafflePrizeList5.length > 0) { cb.sendNotice('Raffle Level 5 - ', "", ticketStatsBgColor,"","bold"); cb.sendNotice('...Ticket Price: ' + rafflePrice[5] + ' tokens', "", ticketStatsBgColor); cb.sendNotice('...Tickets Sold: ' + raffleTicketsSoldLvl[5], "", ticketStatsBgColor); cb.sendNotice('...Prize' + (rafflePrizeList5.length > 1 ? 's' : '') + ': ' + cbjs.arrayJoin(rafflePrizeList5, ', '), "", ticketStatsBgColor); } cb.setTimeout(raffleNoticeTimer, cb.settings.raffleNoticeInterval * 60000); } else { raffleSkipNotice = false; } } } function raffleTicketPurchase(level,user,amount) { raffleCurrentTicketsArray.name.push(user); raffleCurrentTicketsArray.level.push(level); checkTipGoalStartRaffle(amount,level); checkTicketGoalStartRaffle(amount,level); } function checkTipGoalStartRaffle(amount,level) { raffleTotalTokens += amount; raffleGoalTokens += amount; if (raffleEndMode === 'tokengoal' && raffleGoalTokens == raffleTipGoalAmt) { if (raffleDrawingMode === 'auto') { cb.sendNotice(dashLine80 + '\n *The raffle goal has been met!! Starting a 2 minute timer for automatic drawing!\n' + dashLine80,"", raffleBgColor, raffleTextColor, 'bold'); raffleEndMode = 'timer'; raffleAutoTimer(2); } else if (raffleDrawingMode === 'bc') { cb.sendNotice(dashLine80 + '\n *The raffle goal has been met!! The broadcaster will now perform a drawing for the raffle prize(s)!\n' + dashLine80,"", raffleBgColor, raffleTextColor, 'bold'); } } } function checkTicketGoalStartRaffle(amount,level) { raffleGoalTicketsSold++; raffleTotalTicketsSold++; raffleTicketsSoldLvl[level]++; if (raffleEndMode === 'ticketgoal' && raffleGoalTicketsSold == raffleTicketGoalAmt) { if (raffleDrawingMode === 'auto') { cb.sendNotice(dashLine80 + '\n *The raffle goal has been met!! Starting a 2 minute timer for automatic drawing!\n' + dashLine80,"", raffleBgColor, raffleTextColor, 'bold'); raffleEndMode = 'timer'; raffleAutoTimer(2); } else if (raffleDrawingMode === 'bc') { cb.sendNotice(dashLine80 + '\n *The raffle goal has been met!! The broadcaster will now perform a drawing for the raffle prize(s)!\n' + dashLine80,"", raffleBgColor, raffleTextColor, 'bold'); } } } function raffleAutoTimer(addtime) { if (raffleDrawingMode === 'auto') { cb.sendNotice('An automatic timer was started for the raffle drawing.', "", raffleBgColor, raffleTextColor, "bold"); } else if (raffleDrawingMode === 'bc') { cb.sendNotice('A timer was started for the raffle drawing, the broadcaster will trigger the drawing after the timer runs out.', "", raffleBgColor, raffleTextColor, "bold"); } raffleMinsRemain = addtime; raffleSecsRemain = 0; raffleStartTime = new Date(); raffleStopTime = new Date(raffleStartTime.getTime() + raffleMinsRemain * 60000); raffleTimerMin(); } function raffleTimerMin() { raffleSeconds = raffleCheckMin(); if (raffleSkipMin === false && raffleEndMode === 'timer' && raffleToggle == 1 && (raffleSeconds >= 55 || raffleSeconds == 0)) { switch (raffleMinsRemain) { case 120: case 90: case 60: case 45: case 30: case 20: case 15: case 10: case 9: case 8: case 7: case 6: case 5: case 4: case 3: case 2: cb.sendNotice('\u23f1 \u23f1 \u23f1 There are ' + raffleMinsRemain + ' minutes left on the timer to buy a raffle ticket before the drawing takes place! \u23f1 \u23f1 \u23f1', "", yellow, "", "bold"); } raffleMinsRemain--; if (raffleMinsRemain > 0) { cb.setTimeout(raffleTimerMin, 60000); } else { raffleSecsRemain = 60; cb.sendNotice('\u23f1 \u23f1 \u23f1 There is 1 minute left on the timer to buy a raffle ticket before the drawing takes place!! \u23f1 \u23f1 \u23f1', "", red, "", "bold"); raffleTimerSec(); } } else { if (raffleSkipMin === true) { raffleSkipMin = false; } } } function raffleCheckMin() { var raffleTimeLeft = raffleTimeCal(); var raffleMS = raffleTimeLeft % 1000; var raffleSeconds = ((raffleTimeLeft - raffleMS) % 60000); raffleSeconds = raffleSeconds / 1000; return raffleSeconds; } function raffleTimerSec() { if (!raffleSkipSec && raffleEndMode === 'timer' && raffleToggle == 1) { if (raffleMinsRemain > 0) { cb.setTimeout(raffleTimerMin, raffleSecsRemain*1000); } else { raffleSecsRemain--; winner = false; if (raffleSecsRemain < 1) { cb.sendNotice("\u23f0 \u23f0 \u23f0 Time is up! Raffle Drawing now! \u23f0 \u23f0 \u23f0", "", raffleBgColor, raffleTextColor, "bold"); if (raffleEndMode === 'timer' && raffleDrawingMode === 'auto') { selectAllRaffleWinners('The Automatic Timer'); winner = true; } } else { switch (raffleSecsRemain) { case 30: case 10: case 5: case 4: case 3: case 2: case 1: cb.sendNotice('\u23f1 \u23f1 \u23f1 There ' + (raffleSecsRemain == 1 ? "is " : "are ") + raffleSecsRemain + ' second' + (raffleSecsRemain == 1 ? "" : "s") + ' left! \u23f1 \u23f1 \u23f1', "", red, "", "bold"); } } if (raffleSecsRemain > 0 && !winner) { cb.setTimeout(raffleTimerSec, 1000); } } } else { raffleSkipSec = false; } } function raffleAddTime(raffletimetoadd, u) { raffleStopTime = new Date(raffleStopTime.getTime() + raffletimetoadd * 60000); if (raffletimetoadd < 0) { cb.sendNotice(u + " has subtracted " + Math.abs(raffletimetoadd) + " minute" + (raffletimetoadd === 1 || raffletimetoadd === -1 ? "" : "s") + " from the raffle drawing timer.",cb.room_slug,"","", "bold"); cb.sendNotice(Math.abs(raffletimetoadd) + " minute" + (raffletimetoadd === 1 || raffletimetoadd === -1 ? " has" : "s have") + " been subtracted from the raffle drawing timer. Now " + raffleTimeLeft(),"",yellow,"", "bold"); } else { cb.sendNotice(u + " has added " + raffletimetoadd + " minute" + (raffletimetoadd === 1 || raffletimetoadd === -1 ? "" : "s") + " to the raffle drawing timer.",cb.room_slug,"","", "bold"); cb.sendNotice(raffletimetoadd + " minute" + (raffletimetoadd === 1 || raffletimetoadd === -1 ? " has" : "s have") + " been added to the raffle drawing timer. Now " + raffleTimeLeft(),"",yellow,"", "bold"); } raffleMinsRemain = raffleMinsRemain + raffletimetoadd; if (raffleMinsRemain < 1) { raffleSkipMin = true; raffleTimeLeft = raffleTimeCal(); raffleMS = raffleTimeLeft % 1000; raffleSeconds = ((raffleTimeLeft - raffleMS) % 60000) / 1000; raffleSecsRemain = raffleSeconds; raffleTimerSec(); } } function raffleTimeCal() { raffleStartTime = new Date(); return raffleStopTime - raffleStartTime.getTime(); } function stopRaffleTimer(mod) { raffleStopTime = new Date(); raffleSkipNotice = true; if (raffleMinsRemain > 0 || raffleSecsRemain > 0) { raffleSkipMin = true; raffleSkipSec = true; } raffleMinsRemain = 0; raffleSecsRemain = 0; if(mod != null) { cb.sendNotice(mod + ' has stopped the raffle drawing timer.',"",yellow,"", "bold"); } } function raffleTimeLeft(user) { var raffleTimeLeft = raffleTimeCal(); var raffleMS = raffleTimeLeft % 1000; var raffleSeconds = ((raffleTimeLeft - raffleMS) % 60000); var raffleMinutes = ((raffleTimeLeft - raffleSeconds - raffleMS) % 3600000); raffleSeconds = raffleSeconds / 1000; raffleMinutes = raffleMinutes / 60000; if (raffleMinutes > 0 && raffleSeconds == 0) { return raffleMinutes + " minute" + (raffleMinutes > 1 ? "s" : "") + " remaining on the raffle drawing timer."; } else if (raffleMinutes > 0) { return raffleMinutes + " minute" + (raffleMinutes > 1 ? "s" : "") + " and " + raffleSeconds + " second" + (raffleSeconds > 1 ? "s" : "") + " remaining on the raffle drawing timer."; } else { return raffleSeconds + " second" + (raffleSeconds > 1 ? "s" : "") + " remaining on the raffle drawing timer."; } } function selectAllRaffleWinners(drawingby) { if (rafflePrice[1] > 0 && rafflePrizeList1.length > 0) { selectSingleRaffleWinner(1,drawingby); } if (rafflePrice[2] > 0 && rafflePrizeList2.length > 0) { selectSingleRaffleWinner(2,drawingby); } if (rafflePrice[3] > 0 && rafflePrizeList3.length > 0) { selectSingleRaffleWinner(3,drawingby); } if (rafflePrice[4] > 0 && rafflePrizeList4.length > 0) { selectSingleRaffleWinner(4,drawingby); } if (rafflePrice[5] > 0 && rafflePrizeList5.length > 0) { selectSingleRaffleWinner(5,drawingby); } if (cb.settings.raffleContinuous === 'Continuous') { if (cb.settings.raffleResetCycle === 'Yes') { clearRaffleEntries('all',drawingby); } else { clearRaffleEntries('resume',drawingby); } resumeRaffle(drawingby); } else { cb.sendNotice('The Raffle Drawing has been performed and the Raffle is now Over!!! Thanks to everyone who bought a ticket!', '', raffleBgColor, raffleTextColor, 'bold'); stopRaffleTimer(); } } function resumeRaffle(drawingby) { setRaffleMode('init',drawingby); raffleSkipMin = false; raffleSkipSec = false; raffleSkipNotice = false; } function selectSingleRaffleWinner(level,drawingby) { raffleDrawingArray = []; buildRaffleDrawingArray(level); if (raffleDrawingArray.length > 0) { maxPrizes = raffleDrawingArray.length; if (level == 1) { if (rafflePrizeList1.length <= maxPrizes) { maxPrizes = rafflePrizeList1.length; } else { cb.sendNotice('There are fewer raffle tickets available (' + raffleDrawingArray.length + ') than prizes (' + rafflePrizeList1.length + ') for level ' + level + ', only rewarding prizes for the number of tickets sold.', '', raffleBgColor,raffleTextColor,'bold'); } for (var i = 0; i < maxPrizes; i++) { rafflePrize = rafflePrizeList1[i]; raffleAnnounceWinner(level,rafflePrize,drawingby); } } else if (level == 2) { if (rafflePrizeList2.length <= maxPrizes) { maxPrizes = rafflePrizeList2.length; } else { cb.sendNotice('There are fewer raffle tickets available (' + raffleDrawingArray.length + ') than prizes (' + rafflePrizeList2.length + ') for level ' + level + ', only rewarding prizes for the number of tickets sold.', '', raffleBgColor,raffleTextColor,'bold'); } for (var i = 0; i < maxPrizes; i++) { rafflePrize = rafflePrizeList2[i]; raffleAnnounceWinner(level,rafflePrize,drawingby); } } else if (level == 3) { if (rafflePrizeList3.length <= maxPrizes) { maxPrizes = rafflePrizeList3.length; } else { cb.sendNotice('There are fewer raffle tickets available (' + raffleDrawingArray.length + ') than prizes (' + rafflePrizeList3.length + ') for level ' + level + ', only rewarding prizes for the number of tickets sold.', '', raffleBgColor,raffleTextColor,'bold'); } for (var i = 0; i < maxPrizes; i++) { rafflePrize = rafflePrizeList3[i]; raffleAnnounceWinner(level,rafflePrize,drawingby); } } else if (level == 4) { if (rafflePrizeList4.length <= maxPrizes) { maxPrizes = rafflePrizeList4.length; } else { cb.sendNotice('There are fewer raffle tickets available (' + raffleDrawingArray.length + ') than prizes (' + rafflePrizeList4.length + ') for level ' + level + ', only rewarding prizes for the number of tickets sold.', '', raffleBgColor,raffleTextColor,'bold'); } for (var i = 0; i < maxPrizes; i++) { rafflePrize = rafflePrizeList4[i]; raffleAnnounceWinner(level,rafflePrize,drawingby); } } else if (level == 5) { if (rafflePrizeList5.length <= maxPrizes) { maxPrizes = rafflePrizeList5.length; } else { cb.sendNotice('There are fewer raffle tickets available (' + raffleDrawingArray.length + ') than prizes (' + rafflePrizeList5.length + ') for level ' + level + ', only rewarding prizes for the number of tickets sold.', '', raffleBgColor,raffleTextColor,'bold'); } for (var i = 0; i < maxPrizes; i++) { rafflePrize = rafflePrizeList5[i]; raffleAnnounceWinner(level,rafflePrize,drawingby); } } } else { cb.sendNotice('There are no raffle tickets purchased for Level ' + level, '', raffleBgColor,raffleTextColor,'bold'); } } function buildRaffleDrawingArray(level) { for (var j = 0; j < raffleCurrentTicketsArray.name.length; j++) { if (raffleCurrentTicketsArray.level[j] == level) { raffleDrawingArray.push(raffleCurrentTicketsArray.name[j]); } } } function raffleAnnounceWinner(level,rafflePrize,drawingby) { cb.sendNotice(drawingby + ' is drawing a winner for the prize of ' + rafflePrize + '...', '', raffleBgColor,raffleTextColor,'bold'); totalEntries = raffleDrawingArray.length; raffleWinnerIndex = Math.floor(Math.random() * totalEntries); if(raffleWinnerIndex > (raffleDrawingArray.length - 1)) { raffleWinnerIndex = (raffleDrawingArray.length - 1); } raffleWinner = raffleDrawingArray[raffleWinnerIndex]; cb.sendNotice(':raffleticket :WINNER', '', raffleBgColor,raffleTextColor,'bold'); cb.sendNotice('Congratulations!!! ' + raffleWinner + ' has won ' + rafflePrize + '!', '', raffleWinnerBgColor,raffleTextColor,'bold'); removeWinner(level,raffleWinner); } function removeWinner(level,raffleWinner) { drawingIndex = raffleDrawingArray.indexOf(raffleWinner); raffleDrawingArray.splice(drawingIndex,1); for (var j = 0; j < raffleCurrentTicketsArray.name.length; j++) { if (raffleCurrentTicketsArray.level[j] == level && raffleCurrentTicketsArray.name[j] == raffleWinner) { raffleCurrentTicketsArray.name.splice(j,1); raffleCurrentTicketsArray.level.splice(j,1); break; } } } function removeTicket(level,user) { for (var j = 0; j < raffleCurrentTicketsArray.name.length; j++) { if (raffleCurrentTicketsArray.level[j] == level && raffleCurrentTicketsArray.name[j] == user) { raffleCurrentTicketsArray.name.splice(j,1); raffleCurrentTicketsArray.level.splice(j,1); raffleGoalTicketsSold--; raffleTotalTicketsSold--; raffleTicketsSoldLvl[level]--; break; } } } function displayEntries(sendto) { cb.sendNotice('Listing of Raffle entries (Combines Previous Show Sales and Current Sales): ', sendto, green); var outString = "Copy this list and paste it into the field for previous ticket holders on the start page: "; for (var i = 0; i < raffleCurrentTicketsArray.name.length; i++) { if (raffleCurrentTicketsArray.name[i] == null) { break } else { outString += (i > 0 ? "," : "") + raffleCurrentTicketsArray.name[i] + ":" + raffleCurrentTicketsArray.level[i]; } } cb.sendNotice(outString, sendto); cb.sendNotice('End of List', sendto, green); } function clearRaffleEntries(mode,by) { if (mode === 'all') { displayEntries(cb.room_slug); cb.sendNotice('The raffle ticket list has been cleared. In case this was done in error, the current list is printed below, and can be added back if needed.', cb.room_slug, green); if (by != cb.room_slug) { cb.sendNotice('The raffle ticket list has been cleared, and a backup list has been displayed to the broadcaster.', by, green); } raffleCurrentTicketsArray.name.length = 0; raffleCurrentTicketsArray.level.length = 0; for (var j = 1; j <= 5; j++) { raffleTicketsSoldLvl[j] = 0; } } raffleGoalTicketsSold = 0; raffleGoalTokens = 0; } // *********************************** All Time Tipper Display Function ************************************** function setAllTimeToggle(option, mod) { if(option == 'on') { if(allTimeToggle == 1) { cb.sendNotice('The All-Time Tipper List is already enabled.', mod, green); } else { allTimeToggle = 1; allTimeTextColor = checkTextColor("Dark Blue"); allTimeBgColor = checkBgColor("Light Yellow"); if (cb.settings.allTimeInterval > 0) { allTimeListTimer(); } cb.sendNotice('You have enabled the All-Time Tipper List. Please remember to use the "/alltime" command before you end the bot to get the current list, save the list, and paste it into the start page all time list field next time you start the bot.', mod, green); } } else if(option == 'off') { if(allTimeToggle == 0) { cb.sendNotice('The All-Time Tipper List is already disabled.', mod, green); } else { allTimeToggle = 0; cb.sendNotice('You have disabled the All-Time Tipper List Notice.', mod, green); } } } function allTimeListTimer() { allTimeTimer = cb.settings.allTimeInterval * 60000; cb.setTimeout(allTimeNoticeDisplay, allTimeTimer); } function allTimeNoticeDisplay() { if(allTimeToggle == 1) { buildAllTimeArray(); displayAllTimeTop10(''); allTimeListTimer(); } } function buildAllTimeArray() { allTimeArray.name.length = 0; allTimeArray.totaltips.length = 0; if(cb.settings.allTimeTipperList != '' && cb.settings.allTimeTipperList != null) { var n = cb.settings.allTimeTipperList; tempalltimearray = n.split(','); if(tempalltimearray.length > 0) { for (var i = 0; i < tempalltimearray.length; i++) { namelink = tempalltimearray[i].split(':'); if(namelink[0] == '' || namelink[0] == null || namelink[1] == '' || namelink[1] == null) { cb.sendNotice('Cannot load all-time tipper list entry ' + tempalltimearray[i] + ', invalid formatting within pairing.', cb.room_slug, green); } else { allTimeArray.name.push(namelink[0]); allTimeArray.totaltips.push(parseInt(namelink[1])); } } } else { cb.sendNotice('Cannot load all-time tipper list, invalid formatting of list: ' + tempalltimearray, cb.room_slug, green); } for (var i = 0; i < tipCountArray.name.length; i++) { if(tipCountArray.amount[i] >= 25) { if (cbjs.arrayContains(allTimeArray.name,tipCountArray.name[i])) { index = allTimeArray.name.indexOf(tipCountArray.name[i]); allTimeArray.totaltips[index] = allTimeArray.totaltips[index] + tipCountArray.amount[i]; } else { allTimeArray.totaltips.push(tipCountArray.amount[i]); allTimeArray.name.push(tipCountArray.name[i]); } } } sortAllTimeTippers(); } } function displayAllTimeTop10(sendto) { cb.sendNotice(':crowngold :crownsilver :crowngold :crownsilver :crowngold', sendto, allTimeBgColor, allTimeTextColor, 'bold'); cb.sendNotice('Top 10 All Time Tippers: ', sendto, allTimeBgColor, allTimeTextColor, 'bold'); var outString = ''; for (var i = 0; i < 10; i++) { if (allTimeArray.name[i] == null) outString += ' ' + (i+1) + '. empty' + '\n'; else outString += ' ' + (i+1) + '. ' + allTimeArray.name[i] + ' : ' + allTimeArray.totaltips[i] + ' tokens\n'; } cb.sendNotice(outString,sendto, allTimeBgColor, allTimeTextColor, 'bold'); cb.sendNotice(':crowngold :crownsilver :crowngold :crownsilver :crowngold', sendto, allTimeBgColor, allTimeTextColor, 'bold'); } function displayAllTime(sendto) { cb.sendNotice('Listing of All-time top tippers (Combines Previous Show List and Current Show users who have tipped at least 25 tokens): ', sendto, green); var outString = "Copy this list and paste it into the field for all-time tippers on the launch page to use it as the starting point for your next show: \n"; for (var i = 0; i < allTimeArray.name.length; i++) { if (allTimeArray.name[i] == null) { break } else { outString += (i > 0 ? "," : "") + allTimeArray.name[i] + ":" + allTimeArray.totaltips[i]; } } cb.sendNotice(outString, sendto); cb.sendNotice('End of List', sendto, green); } function sortAllTimeTippers() { var swapped, temp1, temp2; do { swapped = false; for (var i = 0; i < allTimeArray.totaltips.length ; i++) { if (allTimeArray.totaltips[i] < allTimeArray.totaltips[i + 1]) { temp1 = allTimeArray.totaltips[i]; temp2 = allTimeArray.name[i]; allTimeArray.totaltips[i] = allTimeArray.totaltips[i + 1]; allTimeArray.totaltips[i + 1] = temp1; allTimeArray.name[i] = allTimeArray.name[i + 1]; allTimeArray.name[i + 1] = temp2; swapped = true; } } } while (swapped); } // ********************* Private On-demand ************************** function goPrivate(user) { cb.limitCam_addUsers([user]); ticketShowColors(); cb.sendNotice(dashLine80 + '\n *** The broadcaster has started a private show ***\n' + dashLine80,'',ticketBgColor, ticketNoticesTxtColor, "bold"); cb.sendNotice('*** You have started a hidden Private Show with ' + user + '. Please ensure the name is correct and matches their user name in the chat. You can use the "/stopprivate" command to end the hidden show (do this before logging off) ***.',cb.room_slug,ticketBgColor, ticketTxtColor, "bold"); cb.limitCam_start('Fembot Private Show\n\nPrivate Hidden Cam Show in Progress.'); cb.changeRoomSubject("PRIVATE SHOW IN PROGRESS. The cam will be hidden until the broadcaster finishes the private show."); isPrivate = true; } function stopPrivate() { cb.limitCam_removeAllUsers(); cb.sendNotice(dashLine80 + '\n *** The broadcaster has ended the private show ***\n' + dashLine80,'',ticketBgColor, ticketNoticesTxtColor, "bold"); cb.limitCam_stop(); cb.changeRoomSubject("Welcome to our room."); isPrivate = false; } // *********************************** Help Function ************************************** function helpCommon(option,from) { if(option == null){option = '';} cb.sendNotice('Dorothy\'s Fembot Help Menu', from, green); cb.sendNotice('',from,green); cb.sendNotice( '/reply [msg]: If a moderator or broadcaster PMs you in the chat, you can use the command /reply [msg] to send a message back to the last person that PMd you.' + '\n/tipmenu: Display the tip menu at any time in the chat, only to the user that requests it.' + '\n/posmenu: Display the positions tip menu at any time in the chat, only to the user that requests it.' + '\n/timeleft: Display the time left on a timed countdown clock.' + '\n/leaders: Display the tip leaderboard at any time in the chat, only to the user that requests it.' + '\n/poll: Display the current results of the token poll at any time in the chat, only to the user that requests it.' + '\n/wordlist: Display the blocked word list at any time in the chat, only to the user that requests it.' + '\n/lushmenu: Display the interactive toy tip menu at any time in the chat, only to the user that requests it.' + '\n/media: Display the broadcaster media list at any time in the chat, only to the user that requests it.' + '\n/top10 (or /alltimetop10, or /dsptop10): Display a listing of the top 10 all time tippers. Sent to the user that requested, unless requested by moderator or broadcaster, then sent to all. This list is presented in the same format as the notice, not in the format needed to paste into the previous show totals field on the launch page (use the "/alltime" command for that).' + '\n/prizes: Display the dice game prizes menu at any time in the chat, only to the user that requests it.' ,from); cb.sendNotice('',from,green); } function helpModBC(option,from) { var valid = 0; if(option == null){option = '';} switch(option) { case '': { valid = 1; cb.sendNotice('Dorothy\'s Fembot Help Menu for Broadcasters and Moderators', from, green); cb.sendNotice('Type /fbhelp [X], where [X] is one of the following choices, for more detailed information.\nEx: "/fbhelp messaging" to see the submenu for messaging related commands.', from); cb.sendNotice('',from,green); cb.sendNotice( '"messaging" : (/pm, /reply, /bc, /tm, /tbm)' + '\n"chatcontrol" : (/silencelevel, /graphiclevel, /ninja, /unninja, /ninjalist, /silence, /unsilence, /silencelist, /showninja, /showsilence)' + '\n"tipmenu" : (/tipmenu, /tipmenurequests, /tipmenuadd, /tipmenurmv, /usemenu)' + '\n"positions" : (/posmenu, /posmenurequests, /posmenuadd, /posmenurmv, /useposmenu)' + '\n"timer" : (/startclock, /addtoclock, /timeleft, /stopclock)' + '\n"notices" : (/cn, /cnh, /cnd, /cndh, /usenotifier, /chgmsg1.../chgmsg5, /dspmsg, /leaders, /useleaderboard, /usetipcount, /tippers)' + '\n"tokenpoll" : (/poll, /usepoll, /endpoll, /restartpoll, /addvote, /polloptadd, /polloptrmv, /pollstarttimer, /polladdtime, /pollstoptimer, /pollleader)' + '\n"nicelist" : (/addnice, /rmvnice, /nicelist)' + '\n"viplist" : (/addvip, /rmvvip, /viplist, /exportvip)' + '\n"fanlist" : (/addfan, /rmvfan, /fanlist, /exportfans)' + '\n"botmods" : (/addmod, /rmvmod, /modlist)' + '\n"wordlist" : (/addword, /rmvword, /wordlist)' + '\n"other" : (/newsubject, /settings, /checkcolor)' + '\n"ticketsupport" : (/prepticket, /dspbackup, /usebackup, /expbackup, /addlbtop, /addlbamt)' + '\n"ticketshow" : (see full command list in submenu)' + '\n"presales" : (/usepresale, /presalelist, /presaleprice, /presalepricetimer, /presalestarttimer, /presalestoptimer, /presaleaddtime, /exppresale, /addpresale, /rmvpresale, /chgpresalemode, /presaletimeleft)' + '\n"lush" : (/lushmenu, /uselushmenu, /chgtoy, /uselush, /usedomi, /usenora)' + '\n"media" : (/media, /usemedia)' + '\n"dice" : (/prizes, /usedice, /chgdiceprice, /dicerolls)' + '\n"raffle" : (see full command list in submenu)' + '\n"alltime" : (/usealltime, top10, /alltime)' + '\n"private" : (/startprivate, /stopprivate)' + '\n"about"' ,from); cb.sendNotice('',from,green); break; } case 'other': { valid = 1; cb.sendNotice('Fembot Command List',from,green); cb.sendNotice('',from,green); cb.sendNotice( 'Other Commands' + '\n/newsubject [X]: Update the room subject to a new value [X].' + '\n/checkcolor [BG],[FG]: Display a test message to check a color combination with the color names or color codes in the format of "background,foreground". For example, you could use the command "/checkcolor #cdcdff,#0000ff" using hex codes or "/checkcolor Light Pink,Dark Pink" using the colors defined in the bot.' + '\n/settings: Send a list of all of the Fembot settings defined when the current bot session was started to the chat... mainly for troubleshooting.' + '\n/pricechecklisy: Display a listing of all the current price check entries.' + '\n/nocaps [on/off]: Toggle the control for suppressing all CAPS words.' + '\n/nnlist: display a listing of the user specific icons, nick names, and text colors.' + '\n/setusericon [username] [:icon]: (mods/bc only) Updates the icon for an existing user icon/nickname/color entry, or adds a new entry with a icon specified (and a null nickname and color). The icon should have the ":" prefix included.' + '\n/setusernn [username] [nickname]: (mods/bc only) Updates the nickname for an existing user icon/nickname/color entry, or adds a new entry with a nickname specified (and a null icon and color). ' + '\n/setusercolor [username] [#000000]: (mods/bc only) Updates the hex color code for an existing user icon/nickname/color entry, or adds a new entry with a color specified (and a null nickname and icon). The hex color code should have the "#" prefix included. ' ,from); cb.sendNotice('',from,green); break; } case 'alltime': { valid = 1; cb.sendNotice('Fembot Command List',from,green); cb.sendNotice('',from,green); cb.sendNotice( 'All-time tipper Tracking - ' + '\n/usealltime [on/off]: (mods/bc only) Toggle the setting for whether the tracking of all-time tipper information is "on" or "off". Overrides the initial setting, and allows you to turn the tracking on or off during the show. Note that tip totals are only extracted when the "/alltime" command is used, so it can be enabled anytime during the show without losing any information. The toggle mainly controls if the commands are allowed to be executed.' + '\n/top10 (or /alltimetop10, or /dsptop10) : (all users) Display a listing of the top 10 all time tippers. Sent to the user that requested, unless requested by moderator or broadcaster, then sent to all. This list is presented in the same format as the notice, not in the format needed to paste into the previous show totals field on the launch page (use the "/alltime" command for that).' + '\n/alltime (or /listalltime, or /alltimelist) : (mods/bc only) Display the all-time tipper totals, including previous show totals and current totals, in a formatted list that can be copied and pasted into the previous show all time list on the launch page. As noted previously, this list should also be saved outside CB.' ,from); cb.sendNotice('',from,green); break; } case 'private': { valid = 1; cb.sendNotice('Fembot Command List',from,green); cb.sendNotice('',from,green); cb.sendNotice( 'On-demand private show - ' + '\n/startprivate (or /goprivate) [user]: (bc only) The broadcaster initiates the private, and only the user name entered will be able to see the show. The room will be immediately hidden in the same way as a ticket show. Make sure to enter the users name correctly!' + '\n/stopprivate (or /endprivate) : (bc only) End the private hidden cam show and immediately return to public chat.' ,from); cb.sendNotice('',from,green); break; } case 'ticketsupport': { valid = 1; cb.sendNotice('Fembot Command List',from,green); cb.sendNotice('',from,green); cb.sendNotice( 'Ticket Show Support Commands - These commands are used for working alongside the an External Ticket App (some are also used in the Fembot ticket show - see the "ticketshow" submenu).' + '\n/prepticket: Prepare for a ticket show by disabling the regular Tip Menu if running, enabling the Positions Menu, and enabling the Token Poll.' + '\nThis command will also add the VIP List and External Fan Club list to the ticket show if enabled.' + '\n/usebackup [on/off]: Toggle the setting for whether the Backup Ticket List tracking is "on" or "off". Overrides the initial setting to turn it on or off during the show.' + '\n/dspbackup (or /backuplist): Display the Backup Ticket list.' + '\n/backupprice: Update the price used to add ticket buyers to the backup list. Mainly used if doing pre-sales with an automatically changing ticket price.' + '\n/expbackup: Export the backup ticket list by creating the /add command to add all backup list members to the ticket app.' + '\n/addlbtop [X]: Add the top [X] tippers from the leaderboard to the ticket show. Available only to broadcasters, and if configured, moderators as well. Check the top tippers using /leaders or /tippers before using this command to ensure the appropriate users are being added.' + '\n/addlbamt [X]: Add the tippers from the leaderboard who have tipped at least [X] amount to the ticket show. Available only to broadcasters, and if configured, moderators as well. Check the top tippers using /leaders or /tippers before using this command to ensure the appropriate users are being added.' ,from); cb.sendNotice('',from,green); break; } case 'ticketshow': { valid = 1; cb.sendNotice('Fembot Command List',from,green); cb.sendNotice('',from,green); cb.sendNotice( 'Fembot Ticket Show Commands - they are used specifically for the Fembot Ticket show, not for the ticket apps (although some commands perform the same type of function)' + '\n/useshow (or /useticketshow) [on/off]: (mods/bc only) Toggle the setting for whether the Fembot Ticket Show feature is "on" or "off". Overrides the initial setting, and allows you to turn the Ticket Show feature on or off during the show. Note that turning the show off will suspend the display of the notice, and tips will no longer buy a ticket, however, the existing ticket purchases are kept until the fembot is restarted.' + '\n/tickets : (mods/bc only) Display the list of users that have bought a ticket. If the parameter of "alpha" is added, the list is displayed alphabetically. Note that viewers can be added back to the show using the /add or /addticket commands and pasting the list that is shown from the /tickets command. ' + '\n/chgticketshow : (mods/bc only) change whether the ticket show is controlled in the Fembot or an external ticket app, overrides the initial setting on the bot launch page. Ends the Fembot hidden show feature if the show had already started.' + '\n/useot [on/off]: (mods/bc only) Toggle the setting for whether the Outstanding Ticket feature of the Ticket Show is "on" or "off". Overrides the initial setting, and allows you to turn the Outstanding Ticket usage feature on or off during the show. .' + '\n/otlist : (all users) Display the list of outstanding ticket holders, can be used by anyone if the Outstanding Ticket feature is enabled.' + '\n/otchanges : (mods/bc only) ** IMPORTANT when using the OT feature ** Displays a list of tickets that have been saved or used during the current session so the permanent list can be updated.' + '\n/saveticket: (all ticket buyers) If the broadcaster has enabled Outstanding Tickets (and is tracking them) - If you have bought a ticket and will not be able to stay for the show, you can save it for a future show. You will no longer be able to see the current show. IMPORTANT: If in the same session, the ticket will be available automatically. However for future shows or if the broadcaster restarts the bot, the broadcaster must add the saved tickets to the outstanding ticket list to be able to use them with /useticket. ' + '\n/useticket: (all users with an outstanding ticket) If the broadcaster has enabled Outstanding Tickets (and is tracking them) - Redeem an outstanding ticket and use it for access to this show. You can use the command /otlist to view the list of outstanding ticket holders if the broadcaster has enabled this feature.' + '\n/addot : (mods, bc if granted privileges) If the outstanding ticket feature is in use, the broadcaster can manually give a user an outstanding ticket. Moderators can also add if they have authority. The addition still must be made permanent by updating the launch page outstanding ticket list.' + '\n/rmvot : (mods/bc only) Remove a user from the outstanding ticket list within the current show. The removal still must be made permanent by updating the launch page outstanding ticket list.' + '\n/addticket or (/add) [user]: (bc only, moderator when granted privileges) Manually add a user to the ticket show list. Can be a specific user or a list of users separated by a comma. ' + '\n/rmvticket (or /del or /delticket) [user]: (mods/bc only) Manually remove a specific user from the ticket show list, only used for one user at a time. ' + '\n/startshow: (mods/bc only) Start the ticket show when not set to automatic start. Once started, the show will only be visible to ticket holders. Hint: start the show when you are in a good position for the preview pic to be frozen that will attract more ticket buyers.' + '\n/showwarn (or /showover): (mods/bc only) Display a warning that the show will be ending soon and ticket purchases are allowed but not recommended. If configured, this can also end the positions menu, and reduce the ticket price.' + '\n/showend (or /stopsales): (mods/bc only) Suspend ticket sales, no more automatic ticket purchases can be made. Recommended to always do this once you are less than a few minutes from the end of the show so people do not buy at the last second and are disappointed by getting a short show. If configured, this can also end the positions menu, and reduce the ticket price. ' + '\n/stopshow: (mods/bc only) End the hidden show and return to a public broadcast.' + '\n/newticketshow: (mods/bc only) Completely refresh the ticket show to start a brand new show. This will remove all the ticket holders from the list, and re-initialize all settings using the configuration from the launch page.' + '\n/restartshow: (mods/bc only) Go back into hidden cam mode if the show was accidentally ended too soon, or the broadcaster wanted to go back to public to sell more tickets. The ticket holder list and all settings are kept intact.' + '\n/ticketprice (or /ctprice, or /chgticketprice) [newprice]: (mods/bc only) Update the ticket price to the [newprice]. ' + '\n/starttimer (or /ticketstarttimer, or /starttickettimer) [time]: (mods/bc only) Start a [time] minute timer for the raffle drawing when in "timer" mode with the drawing to be triggered by the /raffledrawing command. The timer will count down but not automatically perform the drawing (unless set to automatic mode but the auto-timer was ended, and this is a restart of that timer)' + '\n/addtime (or /ticketaddtime, or /addtickettime) [time]: (mods/bc only) Add [time] minutes to the timer for either automatic or manual drawing mode. The [time] value can be a negative number to subtract time, but cannot be greater than the remaining time.' + '\n/stoptimer (or /ticketstoptimer, or /stoptickettimer): (mods/bc only) Stop the raffle timer for either automatic or manual drawing mode.' + '\n/tickettimeleft : (mods/bc only) Display the time left on the ticket show countdown for either automatic or manual starting mode.' + '\n/showtime : (all users) Display a message showing how long the current show has been hidden.' + '\n/chgticketmode [manual/timer/ticketgoal/tokengoal]: (mods/bc only) Switch between the modes being used to determine when to start the ticket show. If switching from a timer show to a non-timer show, the timer will be ended. Ticket count and Tip Count are being tracked regardless of mode, so switching to a "goal" mode should not require starting progress at 0.' + '\n/chgticketmodeauto [auto/bc]: (mods/bc only) Switch between the modes being used to define if the show starts automatically when a goal is reached or timer expires, or if the broadcaster or mods still control the start of the show. ' + '\n/giftticket [user]: (all users, once you have extra tickets) If the "gifting" feature is enabled, when you tip enough to buy extra tickets, you can gift those tickets to other users using this command. Each time you gift, it removes one of your "extra" tickets. You can only gift extra tickets with this command, to give away your own ticket, you can use /givemyticketto as noted below. Be sure to type the user name correctly for the person you are gifting to, extra tickets cannot be recovered once they are gifted. This can be done before and during the show.' + '\n/givemyticketto [user]: (all ticket buyers) If you cannot stay for a show, and outstanding ticket feature is no used to allow saving your ticket, you can give your ticket to another user. This can only be done before the show starts, and you will be removed from the ticket show list!' + '\n/ticketsubject [newsubject]: (mods/bc only) Change the room description/subject/title to a new value. Note that this command is only used for the Fembot ticket show. The command for use with CrazyTicket is /ctsubject or /subject. ' + '\n/addlbtop [X]: (bc/mods) Add the top [X] number of tippers for the current session to the ticket show. Moderators may only use this if allowed per configuration. This can be used with the Fembot Ticket show or in support of the Ticket App. The /add command is executed, which will add them to the show if the user executing them has authority to the /add command' + '\n/addlbamt [X]: (bc/mods) Add tippers who have tipped at least [X] number of tokens for the current session to the ticket show. Moderators may only use this if allowed per configuration. This can be used with the Fembot Ticket show or in support of the Ticket App. The /add command is executed, which will add them to the show if the user executing them has authority to the /add command' ,from); cb.sendNotice('',from,green); break; } case 'presales': { valid = 1; cb.sendNotice('Ultra Fembot help for Ticket Show Pre-Sales Commands:',from,green); cb.sendNotice( '\n/presalelist: Display the list of pre-sale ticket holders in the chat, shown to the user that requests it.' + '\n/usepresale [on/off]: Toggle the setting for whether the Ticket Show Pre-sales are "on" or "off". Overrides the initial setting to turn the Pre-sales on or off during the show. The Presale mode defaults to the value from start page, and if that was set to no pre-sales, it defaults to manual mode.' + '\n/presaleprice [price]: Change the Pree-sale price to [price] tokens. This is the initial pre-sale price before autimated increases or can be manually updated at any time during the show. You will get an error if you try to increase the pre-sales price higher than the planned ticket show price, and a warning if lowering the price at any point.' + '\n/presalepricetimer [time] [price]: When in manual price change mode, set a timer to change the price in [time] minutes to a new value of [price] tokens. Note you are specifying the new price, not a price increase. ' + '\n/presalestarttimer [time]: When in manual price change mode, set a timer to increase the price in [time] minutes by the default price increase specified on the start page.' + '\n/presalestoptimer: Stop any pre-sales timer that is running, either the automatic timer, or a manually started timer.' + '\n/presaleaddtime [time]: Add [time] minutes to the pre-sale timer, either the automatic timer, or a manually started timer.' + '\n/presaletimeleft: Display the time left on the current timer, either the automatic timer, or a manually started timer.' + '\n/chgpresalemode [mode]: Change the presale mode that is currently running. The default value is set on the start page, and can be change on the fly during the show to "manual", "timer", or "count".' + '\nManual Mode: The broadcaster or moderator controls the price increases (or there are no price increases). Price can either be changed immediately using /presaleprice, or a timer can be started to change it by a specified amount (/presalepricetimer) or by the default increment amount (/presalestarttimer).' + '\nTimer Mode: The price is changed automatically on a recycling timer as defined on the start page. The broadcaster or a moderator can add or remove time from the timer as needed, or stop the timer. At the end of each cycle, the price will increase by the configured increment and a new timer will be kicked off as long as it does not exceed the maximum number of increments and would not exceed the ticket price with the next cycle.' + '\nCount Mode: The price is changed automatically on a recycling ticket count as defined on the start page. At the end of each cycle when the defined number of tickets is sold, the price will increase by the configured increment as long as it does not exceed the maximum number of increments and does not exceed the ticket price with the next cycle.' + '\n/exppresale: Issue the "/add" command to add all pre-sale ticket holders to the ticket show list. This assumes the Ticket App is started, and the current user has the authority to use the /add command. Note it does not clear the pre-sale list, so the action can be performed multiple times if needed.' + '\n/addpresale [user]: Add a single user name [user] to the pre-sale ticket list manually (normally they are added through ticket sales).' + '\n/rmvpresale [user]: Remove a single user name [user] from the pre-sale ticket list.' + '\n/fbpresale [on/off]: (bc/mods only) Enable or Disable the pre-sales feature. Overrides the initial setting on the launch page. Once enabled, the actual sales can be started or ended with "/usepresale on" or "/usepresale off". If doing presales in the UltraApp, which is preferred, do not do pre-sales in the Fembot.' ,from); cb.sendNotice('',from,green); break; } case 'raffle': { valid = 1; cb.sendNotice('Fembot Command List',from,green); cb.sendNotice('',from,green); cb.sendNotice( 'Raffle Ticket Sale -' + '\n/useraffle [on/off]: (mods/bc only) Toggle the setting for whether the Raffle Feature is "on" or "off". Overrides the initial setting, and allows you to turn the Raffle on or off during the show. Note that turning the raffle off will suspend the display of the notice, and tips will no longer buy a ticket, however, the ticket purchase history is kept until the fembot is restarted.' + '\n/entries (or /raffletickets, or /raffleentries): (mods/bc only) Display the list of raffle ticket entries in a format that can be pasted directly into the bot launch page "previous show" raffle list. As noted above, this must be done to track ticket purchases between shows, or restarts of the fembot.' + '\n/previousentries : (mods/bc only) Display the same list of previous ticket purchases that was specified when launching the bot, mainly for informational purposes if there is a question of what was bought in previous shows vs the current total list.' + '\n/resetraffle (or /clearraffle): (bc only) Delete all raffle ticket purchase history and start a new raffle with the existing settings. Obviously be careful using this command as you will lose all outstanding tickets. It will display a list of ticket holders in the chat for the broadcaster in case this is done by mistake, the list could be put back in.' + '\n/addraffle [level] [user]: (bc only) Manually add a user to the specified ticket purchase level. The synatx would be "/addraffle 2 john" to give user name john a ticket for the level 2 drawing.' + '\n/rmvraffle [level] [user]: (bc only) Manually remove a user from the specified ticket purchase level. The synatx would be "/rmvraffle 2 john" to remove the ticket for user name john for the level 2 drawing. Note that it will only remove the first occurrence of that user ticket for that level, the command must be executed multiple times if they have multiple tickets.' + '\n/raffleprizes: (all users) Display the available prizes in the Raffle, by level, only shown to the user that requests it.' + '\n/setraffleprice [level] [newprice]: (mods/bc only) Change the price of Level 2 raffle tickets, where [newprice] is the new price to use. ' + '\n/raffledrawing: (bc, mods when configured) Perform the raffle drawing when not set to Automatic Drawing mode. The winners from each level will be chosen and displayed in the chat. Note that the winner history is not tracked, so you must distribute the prizes or make note of the winners as they are shown in the chat. If continuous mode is selected, the goals are reset and the next cycle is started, which may clear the ticket pool if configured to do so in continuous mode.' + '\n/rafflestarttimer (or /startraffletimer) [time]: (mods/bc only) Start a [time] minute timer for the raffle drawing when in "timer" mode with the drawing to be triggered by the /raffledrawing command. The timer will count down but not automatically perform the drawing (unless set to automatic mode but the auto-timer was ended, and this is a restart of that timer)' + '\n/raffleaddtime (or /addraffletime) [time]: (mods/bc only) Add [time] minutes to the timer for either automatic or manual drawing mode. The [time] value can be a negative number to subtract time, but cannot be greater than the remaining time.' + '\n/rafflestoptimer (or /stopraffletimer): (mods/bc only) Stop the raffle timer for either automatic or manual drawing mode.' + '\n/raffletimeleft : (mods/bc only) Display the time left on the raffle timer for either automatic or manual drawing mode.' + '\n/chgrafflemode [manual/timer/ticketgoal/tokengoal]: (mods/bc only) Switch between the modes being used to determine when to perform the raffle drawing. If switching from a timer show to a non-timer show, the timer will be ended. Ticket count and Tip Count are being tracked regardless of mode, so switching to a "goal" mode should not require starting progress at 0.' + '\n/addraffleprize [level] [prize]: (mods/bc only) Add a raffle prize to the specified [level] (1-5) with a description of [prize].' + '\n/rmvraffleprize [level] [prize]: (mods/bc only) Remove the specified raffle [prize] from the specified [level] (1-5), the text must match the existing prize exactly (case and punctuation).' ,from); cb.sendNotice('',from,green); break; } case 'messaging': { valid = 1; cb.sendNotice('Ultra Fembot help for Messaging Commands:',from,green); cb.sendNotice( 'pm: This command is usable by moderators and broadcasters to send a PM to a specific user in the main chat window.' + '\nThe syntax for using PMs is "/pm [X] [Y]", where [X] is the username of the user you want to send the message to, and [Y] is the message you want to send.' + '\nA related command is /reply.' + '\n/reply: This command is usable by everyone once they have received a PM from a moderator or broadcaster.' + '\nThe syntax for replying to a PM is "/reply [X]", where [X] is message that you want to PM to the user who most recently sent a PM to you.' + '\nYou should be careful using this to ensure the last person that PM\'d you is the person you are intending to reply to.' + '\nAlternatvely, a new PM can be sent using the /pm command rather than reply if you are not sure who last PM\'d you.' + '\n/bc: This command is usable by moderators to send a PM specifically to the broadcaster.' + '\nThe syntax for using this type of PM is "/bc [X]", where [X] is the message you want to send.' + '\n/tm: This command that is usable by moderators and the broadcaster to send a PM to the moderator group as a whole.' + '\nThe syntax for using this type of PM is "/tm [X]", where [X] is the message you want to send.' + '\n/tbm: This command is usable by moderators and the broadcaster to send a PM to the moderator group plus the broadcaster.' + '\nThe syntax for using this type of PM is "/tbm [X]", where [X] is the message you want to send.' ,from); cb.sendNotice('',from,green); break; } case 'timer': { valid = 1; cb.sendNotice('Ultra Fembot help for Timer Commands:',from,green); cb.sendNotice( '/startclock [time] [description]: This command is usable by moderators and broadcasters to start a timer in the room for [time] minutes and an optional [description]. This timer is not tied to any specific function, just a countdown, although the [description] value can be used to show what happens at the end of the countdown.' + '\nThe syntax for using the command is "/startclock [T]", where [T] is the desired duration of the countdown timer in minutes. The function will accept whole numbers only.' + '\nThe timer will make announcements at 15, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 minutes and 30 seconds remaining. The function /addtoclock can be used to add time to a currently running timer.' + '\n/addtoclock: This command is usable by moderators and broadcasters to add time to (or subtract time from) an existing countdown.' + '\nThe syntax for using addtoclock is "/addtoclock [T]", where [T] is the amount of time you want to add in minutes. The command will accept positive or negative whole numbers only. Negative numbers can be used to subtract time from the clock.' + '\n/timeleft: This command will display the amount of time left in the countdown.' + '\/chgclockdesc [newtext]: change the text used in the timer description to the new value [newtext], overrides the initial value set on the launch page of the Fembot' + '\n/stopclock: This command will end the countdown timer.' ,from); cb.sendNotice('',from,green); break; } case 'notices': { valid = 1; cb.sendNotice('Ultra Fembot help for Chat Notice Commands:',from,green); cb.sendNotice( 'cn: This command is usable by moderators and the broadcaster to post a one-time notice in the chat.' + '\nThe syntax for using this type of notice is "/cn [X]", where [X] is the message you want to send.' + '\nThis is the plain notification without any separators or highlighting.' + '\n/cnd: This command is usable by moderators and the broadcaster to post a one-time notice in the chat.' + '\nThe syntax for using this type of notice is "/cnd [X]", where [X] is the message you want to send.' + '\nThis notification includes a dash separator before and after the message, but no highlighting.' + '\n/cnh: This command is usable by moderators and the broadcaster to post a one-time notice in the chat.' + '\nThe syntax for using this type of notice is "/cnh [X]", where [X] is the message you want to send.' + '\nThis notification includes highlighting, but no separators.' + '\n/cndh: This command is usable by moderators and the broadcaster to post a one-time notice in the chat.' + '\nThe syntax for using this type of notice is "/cndh [X]", where [X] is the message you want to send.' + '\nThis notification includes both separators and highlighting.' + '\n/usenotifier: This command is usable by moderators and broadcasters to toggle on or off the display of the periodic notification message defined by the broadcaster.' + '\nThe syntax for using notifier is /usenotifier [X], where [X] is either "on" or "off".' + '\n/chgmsg1: Change the text of the message slotted in Notifier 1. Notifications must be enabled for the message to display.' + '\nThe syntax for using command is /chgmsg1 [X], where [X] is the new message that should be displayed.' + '\n/chgmsg2: Change the text of the message slotted in Notifier 1. Notifications must be enabled for the message to display.' + '\nThe syntax for using command is /chgmsg2 [X], where [X] is the new message that should be displayed.' + '\n/chgmsg3: Change the text of the message slotted in Notifier 1. Notifications must be enabled for the message to display.' + '\nThe syntax for using command is /chgmsg3 [X], where [X] is the new message that should be displayed.' + '\n/chgmsg4: Change the text of the message slotted in Notifier 1. Notifications must be enabled for the message to display.' + '\nThe syntax for using command is /chgmsg4 [X], where [X] is the new message that should be displayed.' + '\n/chgmsg5: Change the text of the message slotted in Notifier 1. Notifications must be enabled for the message to display.' + '\nThe syntax for using command is /chgmsg5 [X], where [X] is the new message that should be displayed.' + '\n/dspmsg [X]: Display the message slotted in position [X], where [X] can be the integers 1-5 or "all".' + '\n/leaders: This command is usable by everyone with the default delivery of displaying the tip leader list only to the requesting user. The leaderboard can also be ' + 'sent to the general chat for all to see, or to the broadcaster or mods specifically.' + '\nThe syntax for using leaderboard is "/leaders" to send to yourself. Moderators and broadcasters can use "/leaders all", "/leaders mods" or "/leaders bc".' + '\nThis command triggers the display of the top 5 tippers of the current session, regardless of the setting for periodic display of the leaderboard.' + '\n/useleaderboard [X]: This command is usable by moderators and broadcasters to toggle the display of the leaderboard in the chat per the defined interval.' + '\nThe syntax for using the leaderboard toggle is /useleaderboard [X], where [X] is either "on" or "off".' + '\nThe interval for the display is still controlled by the configuration settings when enabling the bot.' + '\n/usetipcount [X]: This command is usable by moderators and broadcasters to toggle the display of the user\'s tip count at the beginning of their chat messages.' + '\nThe syntax for using the tip count toggle is /usetipcount [X], where [X] is either "on" or "off".' + '\nNote that enabling and disabling this will not control whether the token tip counts are tracked, only whether they are displayed.' + '\n/tippers: This command that is usable by moderators and broadcasters to trigger the display of the top 25 tippers of the current session with the default delivery displaying ' + 'the tip leader list only to the requesting user. The leaderboard can also be sent to the general chat for all to see, or to the broadcaster or mods specifically.' + '\nThe syntax for using leaderboard is "/tippers" to send to yourself. Moderators and broadcasters can use "/leaders all", "/leaders mods" or "/leaders bc".' ,from); cb.sendNotice('',from,green); break; } case 'chatcontrol': { valid = 1; cb.sendNotice('Ultra Fembot help for Chat Control Commands:',from,green); cb.sendNotice( '\n/silencelevel: This command is used by moderators and broadcasters to control who is able to chat in the room.' + '\nThe syntax for using silencelevel is "/silencelevel [X]", where [X] is a number from 0 to 3.' + '\nSetting the Silence Level to 0 will grant chat privileges to all users, ' + 'setting it to 1 will remove chat privileges from users without tokens, ' + 'setting it to 2 will remove chat privileges from users who have not tipped, ' + 'and setting it to 3 will remove chat privileges from users who have not tipped the minimum configured tokens.' + '\nThe default setting for /silencelevel is 0. The chat ability of broadcasters, moderators, and fan club members is unaffected by the Silence Level.' + '\n/graphiclevel: This command is used by moderators and broadcasters to control who is able to post graphics or gifs in the room.' + '\nThe syntax for using graphiclevel is "/graphiclevel [X]", where [X] is a number from 0 to 3.' + '\nSetting the Graphic Level to 0 will grant graphic usage privileges to all users, ' + 'setting it to 1 will revoke graphic usage privileges from users who do not have tokens, ' + 'setting it to 2 will revoke graphic usage privileges from users who have not tipped, ' + 'and setting it to 3 will revoke graphic usage privileges from users who have not tipped the minimum configured tokens.' + '\nThe default setting for /graphiclevel is 1. The graphiclevel does not affect the ability of broadcasters, moderators, and fan club members from posting graphics.' + '\n/ninja: This command is usable by moderators and broadcasters.' + '\nThe syntax for using silence is "/ninja [X]", where [X] is the user you want to silence without notification.' + '\nThe effect of the /ninja feature is similar the /silence feature except that the user is not notified.' + '\nThe effect of /ninja can be reversed by running the command /unninja.' + '\n/unninja: This command is usable by moderators and broadcasters.' + '\nThe syntax for using unninja is "/unninja [X]", where [X] is the username of the user you want to remove from the ninja list.' + '\nunninja grants chat privileges back to a user who was previously silenced by ninja.' + '\n/ninjalist: This command is usable by moderators and broadcasters.' + '\nUsing this command will display the list of users that has been silenced using the /ninja command.' + '\nUsers can be removed from this list by running the command /unninja.' + '\n/showninja [X]: Update the setting for whether ninja\'d user\'s messages are still displayed to mods and broadcasters (values for [X]: 0=Do not show,1=Broadcaster only,2=Mods only,3=Broadcaster and Mods).' + '\n/silence: The syntax for using silence is "/silence [X]", where [X] is the user you want to silence.' + '\nThe effect of the /silence feature is similar the Chaturbate silence feature when you click on a user\'s name and select silence for 6 hrs, ' + 'except that it lasts for the duration of the current session. Also, the user is notified of being silenced, differentiating it from the /ninja function.' + '\nThe effect of /silence can be reversed by running the command /unsilence.' + '\n/unsilence: This command is usable by moderators and broadcasters to grant chat privileges back to a user who was previously silenced.' + '\nThe syntax for using unsilence is "/unsilence [X]", where [X] is the username of the user you want to unsilence.' + '\nNOTE: /unsilence cannot undo the effect of Chaturbate\'s silence for 6 hours feature!' + '\n/silencelist: This is a command that is usable by moderators and broadcasters to display the list of users that has been silenced using the /silence command.' + '\n/showsilence [X]: Update the setting for whether silenced user\'s messages are still displayed to mods and broadcasters (values for [X]: 0=Do not show,1=Broadcaster only,2=Mods only,3=Broadcaster and Mods).' + '\n/useanswerlock [on/off]: Toggle the setting for whether the configured user group(s) must respond to a question before they are allowed to chat. Overrides the initial setting defined on the start page.' + '\n/setanswerlevel [X]: Change the user level that is required to respond to a question before they can chat. Overrides the initial setting defined on the start page. Values for [X]: 0=Not Used,1=Gray,2=Light Blue,3=Dark Blue,4=Light Purple,5=Dark Purple' + '\n/clearanswerlock: Clears all "required answer" restrictions and starts over. All affected user groups will have to respond to a question again.' + '\n/usegraylock [on/off]: Toggle the setting for whether the Gray Chat Time Lock feature is "on" or "off". Overrides the initial setting defined on the start page.' + '\n/chggraytime [X]: Change the gray lock time threshold to a new value [X] minutes. Valid values are from 1 to 20 minutes. Overrides the initial setting defined on the start page.' + '\n/cleargraylock: Clears all gray chat lock tracking and starts over. All gray users will be time restricted by the current time threshold setting.' + '\n/addgraylock [user]: Reinstates gray time lock on a specific user, they will not be able to chat until the gray chat lock time elapses.' + '\n/rmvgraylock [user]: Removes gray time lock on a specific user, they will be able to chat immediately, assuming not silenced by other means (ninja, silence, silencelevel).' ,from); cb.sendNotice('',from,green); break; } case 'tipmenu': { valid = 1; cb.sendNotice('Ultra Fembot help for Tip Menu Commands:',from,green); cb.sendNotice( '\n/tipmenu: Display the tip menu in the chat. Available to any user, menu only shown to the user that requests it.' + '\n/usemenu [on/off]: Toggle the setting for whether the Tip Menu is "on" or "off". Overrides the initial setting to turn the Tip Menu on or off during the show.' + '\n/useposmenu [on/off]: Toggle the setting for whether the Positions Tip Menu is "on" or "off". Overrides the initial setting to turn the Positions Tip Menu on or off during the show.' + '\n/tipmenurequests: Show recent tip menu requests, defaults to a maximum of the 10 most recent when no quantity is entered.' + '\n/tipmenurequests X: Show the last "X" requests.' + '\n/tipmenurequests all: Show all the requests, maximum of 50.' + '\n/tipmenuadd X Y: Add an item name "Y" with a price of "X" tokens to the menu.' + '\n/tipmenurmv X: Removes every item with a price of "X" tokens from the tip menu.' + '\n/tipmenurmv Y: Will remove any item labeled "Y" regardless of price from the tip menu.' ,from); cb.sendNotice('',from,green); break; } case 'positions': { valid = 1; cb.sendNotice('Ultra Fembot help for Tip Menu Commands:',from,green); cb.sendNotice( '\n/posmenu: Display the positions tip menu in the chat. Available to any user, menu only shown to the user that requests it.' + '\n/useposmenu [on/off]: Toggle the setting for whether the Positions Tip Menu is "on" or "off". Overrides the initial setting to turn the Positions Tip Menu on or off during the show.' + '\n/posmenurequests: Show recent positions menu requests, defaults to a maximum of the 10 most recent.' + '\n/posmenuadd X Y: Add an item name "Y" with a price of "X" tokens to the positions menu.' + '\n/posmenurmv X: Removes every item from the positions menu with a price of "X" tokens from the positions menu.' + '\n/posmenurmv Y: Will remove any item labeled "Y" regardless of price from the positions menu.' ,from); cb.sendNotice('',from,green); break; } case 'tokenpoll': { valid = 1; cb.sendNotice('Ultra Fembot help for Token Poll Commands:',from,green); cb.sendNotice( '/poll: (all users) Display the current poll results board in the chat for the requesting user. Displayed to all when requested by moderators.' + '\n/usepoll [on/off]: (mods/bc only) Toggle the setting for whether the Token Poll is "on" or "off". Overrides the initial setting to turn the Token Poll on or off during the show.' + '\n/endpoll: (mods/bc only) When running under manual control, end the poll and display the winner.' + '\n/restartpoll: (mods/bc only) If the poll is accidentally ended, or suspended, it can be restarted using this command.' + '\n/addvote X Y: (mods/bc only) Add or remove "Y" number of votes to the poll item with a price of "X". If "Y" is not specified, defaults to one vote added or removed. Number can be shown as negative (-2) to remove votes. Moderators have to be enabled to use this command.' + '\n/polloptadd X Y: (mods/bc only) Add an item named "Y" with a price of "X" tokens to the poll.' + '\n/polloptrmv X: (mods/bc only) Will remove any item with a price of "X" from the token poll.' + '\n/pollstarttimer X: (mods/bc only) Starts a timer for "X" minutes for the poll when run under timed mode. Poll will automatically end when time runs out.' + '\n/polladdtime X: (mods/bc only) Adds "X" minutes to the poll timer if a timer is running.' + '\n/pollstoptimer: (mods/bc only) Ends the timer if running under timed mode.' + '\n/pollleader: (all users) Post the poll leader message to the chat for the requesting user. Displayed to all when requested by moderators.' + '\n/pollchgtitle [new title]: (mods/bc only) Update the text of the token poll title to [new title].' ,from); cb.sendNotice('',from,green); break; } case 'nicelist': { valid = 1; cb.sendNotice('Ultra Fembot help for Timer Commands:',from,green); cb.sendNotice( '/addnice: This command is usable by moderators and broadcasters.' + '\nThe syntax for using addnice is "/addnice x", where x is the username of the user you want to add to the nice list.' + '\nAdding a user to the nice list guarantees that user voice and graphic usage privileges regardless of the silence and graphic level settings. ' + 'Using /silence will still silence a user on the nice list.' + '\nUsers can be removed from the nice list by using the command /rmvnice.' + '\nSee the help sections for silencelevel and graphiclevel for more information on the global settings or the help section for nicelist for more information on the nice list.' + '\n/rmvnice: This command is usable by moderators and broadcasters.' + '\nThe syntax for using this command is "/rmvnice x", where x is the username of the user you want to remove from the nice list.' + '\n/nicelist: Sometimes, there are nice or polite users you would like to allow to chat even when they don\'t have tokens or haven\'t tipped. ' + 'When the silence level is elevated, usually these users are no longer able to chat, but adding them to the nice list allows them to still chat despite the silence level.' + 'Users can be added to the nice list using the command /addnice [user] where [user] is the user name that should be added.' + 'Likewise users can be removed from the nice list using the command /rmvnice [user] where [user] is the user name that should be removed' + 'The list of users currently in the nice list can be displayed using the command /nicelist.' ,from); cb.sendNotice('',from,green); break; } case 'viplist': { valid = 1; cb.sendNotice('Ultra Fembot help for VIP List Commands:',from,green); cb.sendNotice( '/addvip: This command is usable by broadcasters only.' + '\nThe syntax for using the command is "/addvip [X]", where [X] is the user you want to add to the VIP list.' + '\nAdding a user to the VIP list gives them a badge icon in the chat, PM ability, and includes them in the export list sent to the ticket show. ' + '\nUsers can be removed from the VIP list by using the command /rmvvip.' + '\n/rmvvip: This command is usable by broadcasters only.' + '\nThe syntax for using this command is "/rmvvip [X]", where [X] is the user you want to remove from the VIP list.' + '\n/viplist: Displays the list of users currently in the VIP list.' + '\n/exportvip: Displays the list of users currently in the VIP list in a format that can easily be repasted in the chat to add users to a ticket show.' + '\nNote that this logic will also be executed using the /prepticket command.' ,from); cb.sendNotice('',from,green); break; } case 'fanlist': { valid = 1; cb.sendNotice('Ultra Fembot help for External Fan Club List Commands:',from,green); cb.sendNotice( '/addfan: This command is usable by broadcasters only.' + '\nThe syntax for using the command is "/addvip [username]", where [username] is the user you want to add to the External Fan Club list.' + '\nAdding a user to the External Fan Club list gives them a badge icon in the chat, PM ability, and includes them in the export list sent to the ticket show. ' + '\nUsers can be removed from the External Fan Club list by using the command /rmvfan [username].' + '\n/rmvfan: This command is usable by broadcasters only.' + '\nThe syntax for using this command is "/rmvfan [username]", where [username] is the user you want to remove from the External Fan Club list.' + '\n/fanlist: Displays the list of users currently in the External Fan Club list.' + '\n/exportfan: Displays the list of users currently in the External Fan Club list in a format that can easily be repasted in the chat to add users to a ticket show.' + '\nNote that this logic will also be executed using the /prepticket command.' ,from); cb.sendNotice('',from,green); break; } case 'botmods': { valid = 1; cb.sendNotice('Ultra Fembot help for Bot Moderators:',from,green); cb.sendNotice( '/addmod: This command is usable by broadcasters and moderators.' + '\nThe syntax for using the command is "/addmod [username]", where [username] is the user you want to add to the Fembot Moderator list.' + '\nAdding a user to the Fembot Moderator list gives them full moderator privileges for all functions WITHIN THIS BOT ONLY, and a badge icon in the chat (if configured). ' + '\nUsers can be removed from the Fembot Moderator list by using the command /rmvmod [username].' + '\n/rmvmod: This command is usable by broadcasters and moderators.' + '\nThe syntax for using this command is "/rmvmod [username]", where [username] is the user you want to remove from the Fembot Moderator list.' + '\n/modlist: Displays the list of users currently in the Fembot Moderator list (list will also include broadcaster and CB mods).' ,from); cb.sendNotice('',from,green); break; } case 'wordlist': { valid = 1; cb.sendNotice('Ultra Fembot help for Blocked Word List Commands:',from,green); cb.sendNotice( '/addword: This command is usable by broadcasters and moderators only.' + '\nThe syntax for using the command is "/addword [X]", where [X] is the word you want to add to the Blocked Word list.' + '\nAdding a word to the Blocked Word list will cause a message containing that word to be blocked and not posted to the chat.' + '\nWords can be removed from the Blocked Word list by using the command /rmvword.' + '\n/rmvword: This command is usable by broadcasters and moderators only.' + '\nThe syntax for using this command is "/rmvword [X]", where [X] is the word you want to remove from the Blocked Word list.' + '\n/wordlist: Displays the list of words currently in the Blocked Word list, available to all users.' ,from); cb.sendNotice('',from,green); break; } case 'lush': { valid = 1; cb.sendNotice('Ultra Fembot help for Toy Menu Commands:',from,green); cb.sendNotice( '\n/lushmenu: Display the Toy Menu in chat. Available to any user, only shown to the user that requests it.' + '\n/chgtoy [X]: Changes the name of the toy currently being used, where [X] is one of the toys "lush", "nora", "domi", "hush", or "osci". The new name will then be displayed in all chat messaging. Can also use a specific command of /uselush, /usenora, /usedomi, /usehush, or /useosci to set the toy.' + '\n/uselushmenu [on/off]: Toggle the setting for whether the Toy Menu is "on" or "off", and displays at the defined interval. Overrides the initial setting to turn the Toy Menu on or off during the show.' ,from); cb.sendNotice('',from,green); break; } case 'media': { valid = 1; cb.sendNotice('Ultra Fembot help for Media List Commands:',from,green); cb.sendNotice( '\n/media: Display the media list in chat. Available to any user, only shown to the user that requests it.' + '\n/usemedia [on/off]: Toggle the setting for whether the Media List is "on" or "off", and displays at the defined interval. Overrides the initial setting to turn the Media Menu on or off during the show.' ,from); cb.sendNotice('',from,green); break; } case 'dice': { valid = 1; cb.sendNotice('Ultra Fembot help for Dice Game Commands:',from,green); cb.sendNotice( '\n/prizes: Display the list of prizes in the dice game. Available to any user, only shown to the user that requests it, unless requested by moderator or broadcaster - then it is sent to everyone.' + '\n/usedice [on/off]: Toggle the setting for whether the Dice Game is "on" or "off". Overrides the initial setting to turn the Dice Game on or off during the show.' + '\n/chgdiceprice [amt]: Change the dice roll price to a new amount [amt]. Available only to broadcasters and moderators.' + '\n/dicerolls: Display the last (up to) 20 rolls of the dice, especially helpful if several rolls have been made in a short period of time.' ,from); cb.sendNotice('',from,green); break; } case 'about': { valid = 1; cb.sendNotice('About the Ultra Fembot',from,green); cb.sendNotice('Dorothy\'s Ultra Fembot was written by chelsea2950 mostly based on several existing bots with some tweaks and improvements.' + '\nComments, suggestions, requests, and bug reports can be made by either tweeting @thechelsea2950, or by posting comments on bot help page.' + '\nThe purpose of this Ultra Bot is to serve as one tool that experienced cammers can use for most of the common functions needed during a show. ' + '\nWhereas the "Easy Fembot" contains basic features such as Private Messaging, Leader Board, Silencing users, Silence Level, Graphic Level, Nice List and Notifier, ' + 'the "Ultra Fembot" also adds fancier features such as a Tip Menu, VIP list, Token Poll, icons by user group, blocked wordlist, and additional notifiers. ' + '\nSee the help details for each command for more information on these features.' ,from); cb.sendNotice('',from,green); break; } } if(valid == 0) { cb.sendNotice(option + ' is not a valid subsection of the help menu. Type "/fbhelp" to access the main help menu.',from,green); } } } } // ******************************* Upon user entry of a Message ************************************** { cb.onMessage(function (msg) { var message = msg['m'].split(' '); var cmd = 0; var symbolString = '~`!@#$%^&*()_-+={[}]|\\:;"\'<,>.?/'; var listRegExp = /[,\s]+/; var listRegExpSpc = /[,]+/; var m = msg.m; var u = msg.user; var isMod = msg.is_mod; var isCBMod = msg.is_mod; var isFan = msg.in_fanclub; var isDarkBlue = false; var isLightBlue = false; var isLightPurple = false; var isDarkPurple = false; var isGray = false; var isBC = (u === cb.room_slug); var BC = cb.room_slug; var isExtFan = cbjs.arrayContains(extFanListArray,u); var isVIP = cbjs.arrayContains(VIPListArray,u); var isNinjaSilenced = cbjs.arrayContains(ninjaListArray, u); var isNice = cbjs.arrayContains(niceListArray, u); var isSilenced = cbjs.arrayContains(silenceListArray, u); var messageArrayBuilt = false; if (msg.tipped_tons_recently) { isDarkPurple = true; } else if (msg.tipped_alot_recently) { isLightPurple = true; } else if (msg.tipped_recently) { isDarkBlue = true; } else if (msg.has_tokens) { isLightBlue = true; } else if (!msg.has_tokens) { isGray = true; } isBotMod = false; if (isMod) { populateModeratorArray(u, 'cbmod', 'a'); } else { if (cbjs.arrayContains(moderatorList.name,u)) { nameIndex = moderatorList.name.indexOf(u); if (moderatorList.type[nameIndex] == 'botmod') { isBotMod = true; isMod = true; } } } if(isFan) { populateFanClubArray(u); } var command = message[0] var commandVar1 = parseInt(message[1]); var commandVar2 = parseInt(message[2]); if (message[0].charAt(0) != '/') { if (requireAnswerToggle == 1 && !isBC && !isMod && !isFan && !isExtFan && !isVIP) { if (isGray && requireAnswerLevel >= 1 || isLightBlue && requireAnswerLevel >= 2 || isDarkBlue && requireAnswerLevel >= 3 || isLightPurple && requireAnswerLevel >= 4 || isDarkPurple && requireAnswerLevel >= 5) { if (requireAnswerLockCheck(u) === false) { lockanswer = msg['m'].toLowerCase(); questionindex = answerLockQuestion[answerLockList.indexOf(u)] correctanswer = lockAnswers[questionindex]; if (lockanswer == correctanswer) { answerLockStatus[answerLockList.indexOf(u)] = true; cb.sendNotice('Thank you, chat is unlocked for your user. Please be respectful of your fellow chatters and do not make demands. Sexy chat should be sent in tip notes.', u, '', '', 'bold'); msg['X-Spam'] = true; } else { cb.sendNotice('Sorry, the chat is locked for your user level until you correctly complete the following sentence: \n ' + lockQuestions[questionindex], u, '', '', 'bold'); msg['X-Spam'] = true; } } } } } if(message[0].charAt(0) == '/') { msg['X-Spam'] = true; var ntc = null; for (var i = 1; i < message.length; i++) { if (i == 1) ntc = message[i]; else ntc += " " + message[i]; } var ntc2 = null; for (var i = 2; i < message.length; i++) { if (i == 2) ntc2 = message[i]; else ntc2 += " " + message[i]; } var cmdval = null; for (var i = 1; i < message.length; i++) { if (i == 1) cmdval = message[i]; else cmdval += " " + message[i]; } switch(command) { //******** Chat Control Commands *********** case '/silencelevel': { cmd = 1; if(isMod || isBC) { setSilenceLevel(message[1], u); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/graphiclevel': { cmd = 1; if(isMod || isBC) { setGraphicLevel(message[1], u); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/chplay': { cmd = 1; if (isMod || isBC) { suppressPrefix = true; cb.sendNotice('Fembot: Message prefixes (icons, tip count, etc) have been disabled while playing charades. They are automatically enabled when you turn off the charades game "/charades off".', u, green); } break; } case '/charades': { cmd = 1; if (message[1] == 'off') { if (isMod || isBC) { suppressPrefix = false; cb.sendNotice('Fembot: Message prefixes (icons, tip count, etc) have been re-enabled.', u, green); } } break; } //******** Timer Commands *********** case '/startclock': { cmd = 1; if (isMod || isBC) { if (clockMinsRemain >= 1 || clockSecsRemain >= 1) { cb.sendNotice('A timer is already running, you can type /stopclock to end the current timer or /addtoclock X to add time, where X is the time to add in minutes.', u, green); } else if (isNaN (commandVar1) || commandVar1 < 1 || commandVar1 > 120) { cb.sendNotice('The first parameter is the time for the countdown in minutes, and must be a numeric value from 1 to 120. Example: use "/startclock 10" to start a 10 minute timer.', u, green); } else { if (message[2]) { for (let i = 2; i < message.length; i++) { if (i === 2) { label = message[i]; } else { label += " " + message[i]; } } timerDesc = label; } clockStartTime = new Date(); clockStopTime = new Date(clockStartTime.getTime() + commandVar1 * 60000); clockMinsRemain = commandVar1; clockTimeAdded = false; cb.sendNotice(u + " has started a timer for " + clockMinsRemain + " minute" + (clockMinsRemain > 1 ? "s" : ""), "", green, "", "bold"); clockStopping = false; clockTimerMin(); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.', u, green); } break; } case '/clockadd': case '/addtoclock': { cmd = 1; if (isMod || isBC) { if (!commandVar1) { cb.sendNotice('Invalid command, you need to specify the amount of time to add to the timer in minutes. Example: use "/addtoclock 3" to add 3 minutes to the timer.', u, green); } else if ((clockMinsRemain + 1) + commandVar1 <= 0) { cb.sendNotice('The time to subtract is greater than the amount of time left. You can use "/stopclock" to stop the timer.'); } else if ((clockMinsRemain + 1) + commandVar1 > 120) { cb.sendNotice('The added time will increase the timer to greater than 2 hours, please use a smaller value.'); } else { if (clockMinsRemain >= 1 || clockSecsRemain >= 1) { clockAddTime(commandVar1, u); break; } else { cb.sendNotice('A timer is not running.', u, green); } } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp timer" to see a full list of the timer related commands.', u,green); } break; } case '/timeleft': { cmd = 1; if (isMod || isBC) { if (clockMinsRemain >= 1 || clockSecsRemain >= 1) { cb.sendNotice(clockTimeLeft(), "", yellow, "", "bold"); } else { cb.sendNotice('A Fembot timer is not running, however this command may be in use with a separate Ticket App.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/stopclock': { cmd = 1; if (isMod || isBC) { if (clockMinsRemain >= 1 || clockSecsRemain >= 1) { stopClockTimer(u); } else { cb.sendNotice('A timer is not running.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/chgclockdesc': { cmd = 1; if (isMod || isBC) { if(message[1] != '' && message[1] != null) { timerDesc = msg['m'].substring(14).trim(); cb.sendNotice('The timer description has been updated to "' + timerDesc + '".', u, green); } else { cb.sendNotice('No value was specified for the new timer description.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //******** Ninja Commands *********** case '/ninja': { cmd = 1; if(isMod || isBC) { if (message[1] != null && message[1] != '' && message[1] != ' ') { addRmvNinja(message[1], u, 'a'); } else { cb.sendNotice('No value was specified for the user to ninja, please try again.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/unninja': { cmd = 1; if (isMod || isBC) { addRmvNinja(message[1], u, 'r'); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/ninjalist': { cmd = 1; if (isMod || isBC) { cb.sendNotice('Users currently on the Ninja List: ' + ninjaListArray.length, u, green); cb.sendNotice((ninjaListArray.length > 0 == true ? cbjs.arrayJoin(ninjaListArray, ', ') : 'No users.'), u); cb.sendNotice('End of List', u, green); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/showninja': { cmd = 1; if (isMod || isBC) { nummode = parseInt(message[1]); if (isNaN(nummode)) { cb.sendNotice('The parameter entered for the /showninja command is not numeric, please try again (0=Do not show,1=Broadcaster only,2=Mods only,3=Broadcaster and Mods).', u, green); } else if (nummode < 0 || nummode > 3) { cb.sendNotice('The parameter entered for the /showninja command is outside allowable values from 0 to 3, please try again (0=Do not show,1=Broadcaster only,2=Mods only,3=Broadcaster and Mods).', u, green); } else { if (nummode == 0) { showNinjadMsgs = 'Do not show'; cb.sendNotice('The setting for showing messages from ninja\'d users has been updated to "0=Do not show".', u, green); } else if (nummode == 1) { showNinjadMsgs = 'Broadcaster only'; cb.sendNotice('The setting for showing messages from ninja\'d users has been updated to "1=Broadcaster only".', u, green); } else if (nummode == 2) { showNinjadMsgs = 'Mods only'; cb.sendNotice('The setting for showing messages from ninja\'d users has been updated to "2=Mods only".', u, green); } else if (nummode == 3) { showNinjadMsgs = 'Broadcaster and Mods'; cb.sendNotice('The setting for showing messages from ninja\'d users has been updated to "3=Broadcaster and Mods".', u, green); } } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //******** Silence List Commands *********** case '/silence': { cmd = 1; if (isMod || isBC) { if (message[1] != null && message[1] != "" && message[1] != " ") { addRmvSilence(message[1], u, 'a'); } else { cb.sendNotice('No value was specified for the user to silence, please try again.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/unsilence': { cmd = 1; if (isMod || isBC) { addRmvSilence(message[1], u, 'r'); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/silencelist': { cmd = 1; if (isMod || isBC) { cb.sendNotice('Users currently on the Silence List: ' + silenceListArray.length, u, green); cb.sendNotice((silenceListArray.length > 0 == true ? cbjs.arrayJoin(silenceListArray, ', ') : 'No users.'), u); cb.sendNotice('End of List', u, green); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/showsilence': { cmd = 1; if (isMod || isBC) { nummode = parseInt(message[1]); if (isNaN(nummode)) { cb.sendNotice('The parameter entered for the /showsilence command is not numeric, please try again (0=Do not show,1=Broadcaster only,2=Mods only,3=Broadcaster and Mods).', u, green); } else if (nummode < 0 || nummode > 3) { cb.sendNotice('The parameter entered for the /showsilence command is outside allowable values from 0 to 3, please try again (0=Do not show,1=Broadcaster only,2=Mods only,3=Broadcaster and Mods).', u, green); } else { if (nummode == 0) { showSilencedMsgs = 'Do not show'; cb.sendNotice('The setting for showing messages from silenced users has been updated to "0=Do not show".', u, green); } else if (nummode == 1) { showSilencedMsgs = 'Broadcaster only'; cb.sendNotice('The setting for showing messages from silenced users has been updated to "1=Broadcaster only".', u, green); } else if (nummode == 2) { showSilencedMsgs = 'Mods only'; cb.sendNotice('The setting for showing messages from silenced users has been updated to "2=Mods only".', u, green); } else if (nummode == 3) { showSilencedMsgs = 'Broadcaster and Mods'; cb.sendNotice('The setting for showing messages from silenced users has been updated to "3=Broadcaster and Mods".', u, green); } } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //******** VIP Commands *********** case '/addvip': { cmd = 1; if (isBC) { if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice("Adding multiple users to the VIP list.", u, green); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != "") { if (!cbjs.arrayContains(VIPListArray, cmdvalsplit[i])) { populateVIPListArray(cmdvalsplit[i]); cb.sendNotice("Added " + cmdvalsplit[i] + " to the list.", u); cb.sendNotice(u + " has added you to the VIP list.", cmdvalsplit[i], "#efe"); } else { cb.sendNotice(cmdvalsplit[i] + " is already on the list. Skipping.", u); } } } cb.sendNotice("All users were added and notified.", u, green) cb.sendNotice(u + " has added multiple users to the VIP list.\n" + "Users added: " + cbjs.arrayJoin(cmdvalsplit, ", "), "", green, "", "normal", "red"); } else { var cmdvalsingle = message[1]; addRmvVIP(cmdvalsingle, u, 'a'); } } else { cb.sendNotice("You didn't specify what user(s) you want to add to the External Fan Club list.", u, green); } } else { cb.sendNotice('Only broadcasters are able to use that command.', u, green); } break; } case '/rmvvip': { cmd = 1; if(isBC) { addRmvVIP(message[1], u, 'r'); } else { cb.sendNotice('Only broadcasters are able to use that command.', u, green); } break; } case '/viplist': { cmd = 1; if (isMod || isBC) { cb.sendNotice('Users currently on the Fembot VIP List: ' + VIPListArray.length, u, green); cb.sendNotice((VIPListArray.length > 0 == true ? cbjs.arrayJoin(VIPListArray, ', ') : 'No users.'), u); cb.sendNotice('End of List', u, green); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/exportvip': { cmd = 1; if (VIPListArray.length > 0) { if (isMod || isBC) { msg['m'] = '/add ' + cbjs.arrayJoin(VIPListArray, ', '); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('Cannot export, there are no users in the VIP List.', u, green); } break; } //******** External Fan Club Commands *********** case '/addfan': { cmd = 1; if (isBC) { if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice("Adding multiple users to the External Fan Club list.", u, green); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != "") { if (!cbjs.arrayContains(extFanListArray, cmdvalsplit[i])) { populateExtFanListArray(cmdvalsplit[i]); cb.sendNotice("Added " + cmdvalsplit[i] + " to the list.", u); cb.sendNotice(u + " has added you to the External Fan Club list.", cmdvalsplit[i], "#efe"); } else { cb.sendNotice(cmdvalsplit[i] + " is already on the list. Skipping.", u); } } } cb.sendNotice("All users were added and notified.", u, green) cb.sendNotice(u + " has added multiple users to the External Fan Club list.\n" + "Users added: " + cbjs.arrayJoin(cmdvalsplit, ", "), "", green, "", "normal", "red"); } else { var cmdvalsingle = message[1]; addRmvExtFan(cmdvalsingle, u, 'a'); } } else { cb.sendNotice("You didn't specify what user(s) you want to add to the External Fan Club list.", u, green); } } else { cb.sendNotice('Only broadcasters are able to use that command.', u, green); } break; } case '/rmvfan': { cmd = 1; if(isBC) { addRmvExtFan(message[1], u, 'r'); } else { cb.sendNotice('Only broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.', u, green); } break; } case '/fanlist': { cmd = 1; if (isMod || isBC) { cb.sendNotice('Users currently in the Fembot External Fan Club: ' + extFanListArray.length, u, green); cb.sendNotice((extFanListArray.length > 0 == true ? cbjs.arrayJoin(extFanListArray, ', ') : 'No users.'), u); cb.sendNotice('End of List', u, green); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.', u, green); } break; } case '/exportfans': { cmd = 1; if (extFanListArray.length > 0 == true) { if (isMod || isBC) { msg['m'] = '/add ' + cbjs.arrayJoin(extFanListArray, ', '); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.', u, green); } } else { cb.sendNotice('Cannot export, there are no users in the External Fan Club List.', u, green); } break; } //******** Blocked Word List Commands *********** case '/addword': { cmd = 1; if (isMod || isBC ) { if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice("Adding multiple words to the Blocked Word list.", u, green); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != "") { if (!cbjs.arrayContains(wordListArray, cmdvalsplit[i])) { populateWordListArray(cmdvalsplit[i]); cb.sendNotice("Added " + cmdvalsplit[i] + " to the list.", u); } else { cb.sendNotice(cmdvalsplit[i] + " is already on the list. Skipping.", u); } } } cb.sendNotice("All words were added.", u, green) cb.sendNotice(u + " has added multiple words to the Blocked Word list.\n" + "Words added: " + cbjs.arrayJoin(cmdvalsplit, ", "), "", green, "", "normal", "red"); } else { var cmdvalsingle = message[1]; addRmvWord(cmdvalsingle, u, 'a'); } } else { cb.sendNotice("You didn't specify what word(s) you want to add to the Blocked Word list.", u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp" to see a full list of the available commands.', u, green); } break; } case '/rmvword': { cmd = 1; if(isMod || isBC) { addRmvWord(message[1], u, 'r'); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/wordlist': { cmd = 1; if (isBC) { cb.sendNotice('Words currently on the Blocked Word List: ' + wordListArray.length, u, green); cb.sendNotice((wordListArray.length > 0 == true ? cbjs.arrayJoin(wordListArray, ', ') : 'No users.'), u); cb.sendNotice('End of List', u, green); } else { cb.sendNotice('Only broadcasters are able to use that command.', u, green); } break; } //******** Nice List Commands *********** case '/addnice': { cmd = 1; if (isMod || isBC ) { if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice("Adding multiple users to the nice list.", u, green); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != "") { if (!cbjs.arrayContains(niceListArray, cmdvalsplit[i])) { populateNiceListArray(cmdvalsplit[i]); cb.sendNotice("Added " + cmdvalsplit[i] + " to the list.", u); cb.sendNotice(u + " has added you to the nice list.", cmdvalsplit[i], "#efe"); } else { cb.sendNotice(cmdvalsplit[i] + " is already on the list. Skipping.", u); } } } cb.sendNotice("All users were added and notified.", u, green) cb.sendNotice(u + " has added multiple users to the nice list.\n" + "Users added: " + cbjs.arrayJoin(cmdvalsplit, ", "), "", green, "", "normal", "red"); } else { var cmdvalsingle = message[1]; addRmvNice(cmdvalsingle, u, 'a'); } } else { cb.sendNotice('You didn\'t specify who you want to add to the nice list.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/rmvnice': { cmd = 1; if (isMod || isBC) { addRmvNice(message[1], u, 'r'); } break; } case '/nicelist': { cmd = 1; if (isMod || isBC) { cb.sendNotice('Users currently on the Nice List: ' + niceListArray.length, u, green); cb.sendNotice((niceListArray.length > 0 == true ? cbjs.arrayJoin(niceListArray, ', ') : 'No users.'), u); cb.sendNotice('End of List', u, green); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.', u, green); } break; } //******** Moderator List Commands *********** case '/addmod': { cmd = 1; if (isMod || isBC ) { if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice('Adding multiple users to the Fembot moderator list for this show.', u, green); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { if (!cbjs.arrayContains(moderatorList.name, cmdvalsplit[i])) { populateModeratorArray(cmdvalsplit[i],'botmod','a'); cb.sendNotice('You have added ' + cmdvalsplit[i] + ' to the Fembot moderator list.', u); if (u != cb.room_slug) { cb.sendNotice(u + ' added ' + cmdvalsplit[i] + ' to the Fembot moderator list.', cb.room_slug); } cb.sendNotice(u + ' has added you to the Fembot moderator list.', cmdvalsplit[i], green); } else { cb.sendNotice(cmdvalsplit[i] + ' is already on the Fembot moderator list. Skipping.', u); } } } cb.sendNotice('All users were added and notified.', u, green) cb.sendNotice(u + ' has added multiple users to the Fembot moderator list.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), '', green, '', 'normal', 'red'); } else { var cmdvalsingle = message[1]; populateModeratorArray(cmdvalsingle, 'botmod', 'a'); cb.sendNotice('You have added ' + cmdvalsingle + ' to the Fembot moderator list.', u, green); if (u != cb.room_slug) { cb.sendNotice(u + ' added ' + cmdvalsingle + ' to the Fembot moderator list.', cb.room_slug, green); } cb.sendNotice(u + ' has added you to the Fembot moderator list. You now have all moderator privileges, you can view the full command list with the "/fbhelp" command.', cmdvalsingle, green); } } else { cb.sendNotice('You didn\'t specify who you want to add to the Fembot moderator list.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/rmvmod': { cmd = 1; if (isMod || isBC) { if (message[1]) { if (cbjs.arrayContains(moderatorList.name, message[1])) { populateModeratorArray(message[1], 'botmod', 'r'); cb.sendNotice('You have removed ' + message[1] + ' from the Fembot moderator list.', u, green); if (u != cb.room_slug) { cb.sendNotice(u + ' removed ' + message[1] + ' from the Fembot moderator list.', cb.room_slug, green); } } else { cb.sendNotice(message[1] + ' is not in the moderator list.', u, green); } } else { cb.sendNotice('A parameter is required for this command to specify the user to remove from the moderator list, such as "/rmvmod username".', u, green); } } break; } case '/modlist': { cmd = 1; if (isMod || isBC) { message = ''; message += 'Users currently on the Moderator List: '; if (moderatorList.name.length > 0) { for (var i = 0; i < moderatorList.name.length; i++) { message += '\n' + (i+1) + '. ' + moderatorList.name[i] + ' (' + moderatorList.type[i] + ')'; } } else { message += '\nNo moderators currently assigned.'; } message += '\nEnd of List'; cb.sendNotice(message, u, green); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //******** Chat Notice Commands *********** case '/cn': { cmd = 1; if (isMod || isBC) { if (ntc != null && (ntc != "" || ntc != " " || ntc != "\u00a0")) { sendPublicNotice(ntc, u, ""); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/cn [message]".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.', u, green); } break; } case "/cnh": { cmd = 1; if (isMod || isBC) { if (ntc != null && (ntc != "" || ntc != " " || ntc != "\u00a0")) { sendPublicNotice(ntc, u, "h"); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/cnh [message]".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.', u, green); } break; } case "/cnd": { cmd = 1; if (isMod || isBC) { if (ntc != null && (ntc != "" || ntc != " " || ntc != "\u00a0")) { sendPublicNotice(ntc, u, "div"); } else { cb.sendNotice('You cannot send a blank message.\n The correct syntax for this command is "/cnd [message]".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case "/cndh": { cmd = 1; if (isMod || isBC) { if (ntc != null && (ntc != "" || ntc != " " || ntc != "\u00a0")) { sendPublicNotice(ntc, u, "divh"); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/cndh [message]".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/ctn': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (ntc != null && (ntc != "" || ntc != " " || ntc != "\u00a0")) { sendPublicNotice(ntc, u, ""); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/ctn [message]".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } break; } case "/ctnh": { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (ntc != null && (ntc != "" || ntc != " " || ntc != "\u00a0")) { sendPublicNotice(ntc, u, "h"); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/ctnh [message]".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } break; } case "/ctnd": { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (ntc != null && (ntc != "" || ntc != " " || ntc != "\u00a0")) { sendPublicNotice(ntc, u, "div"); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/ctnd [message]".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } break; } case "/ctndh": { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (ntc != null && (ntc != "" || ntc != " " || ntc != "\u00a0")) { sendPublicNotice(ntc, u, "divh"); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/ctndh [message]".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } break; } //******** Private Message Commands *********** case "/bc": { cmd = 1; if (isMod || (isVIP && (cb.settings.enableVIPList == 'PMs' || cb.settings.enableVIPList == 'PMs and Ticket Shows')) || (isExtFan && (cb.settings.enableExtFans == 'PMs' || cb.settings.enableExtFans == 'PMs and Ticket Shows'))) { if (ntc != null && (ntc != "" || ntc != " " || ntc != "\u00a0")) { sendPrivateNotice(ntc, u, "bc", "default"); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/bc [message]".', u, green); } } else { cb.sendNotice('Only moderators are able to use that command.', u, green); } break; } case "/tm": { cmd = 1; if (isMod || isBC) { if (ntc != null && (ntc != "" || ntc != " " || ntc != "\u00a0")) { sendPrivateNotice(ntc, u, "tm"); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/tm [message]".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case "/tbm": { cmd = 1; if (isMod || isBC) { if (ntc != null && (ntc != "" || ntc != " " || ntc != "\u00a0")) { sendPrivateNotice(ntc, u, "tbm", "default"); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/tbm [message]".', u, green); } } else { cb.sendNotice('Only moderators are able to use that command.', u, green); } break; } case '/pm': { cmd = 1; if (cb.settings.enablePMs == "Yes") { if (isMod || isBC || (isVIP && (cb.settings.enableVIPList == 'PMs' || cb.settings.enableVIPList == 'PMs and Ticket Shows')) || (isExtFan && (cb.settings.enableExtFans == 'PMs' || cb.settings.enableExtFans == 'PMs and Ticket Shows'))) { if (ntc2 != null && (ntc2 != "" || ntc2 != " " || ntc2 != "\u00a0")) { sendPrivateNotice(ntc2, u, "pm", message[1]); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/pm [user] [message]".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('That command has not been enabled by the broadcaster.', u, green); } break; } case '/reply': { cmd = 1; if (cb.settings.enablePMs == "Yes") { sendReply(message, u); break; } else { cb.sendNotice('That command has not been enabled by the broadcaster.', u, green); } } //******** Tip Leader Commands *********** case '/leaders': { cmd = 1; if (isMod || isBC) { switch (message[1]) { case "all": cb.sendNotice( "SENT TO ALL:", u, '#111111', '#d1eaee', "bold"); showLeaderBoard("", ""); break; case "tbm": cb.sendNotice( "SENT TO BROADCASTER and MODS:", u, '#111111', '#d1eaee', "bold"); showLeaderBoard("", "red");showLeaderBoard(BC,''); break; case "mods": cb.sendNotice( "SENT TO MODS:", u, '#111111', '#d1eaee', "bold"); showLeaderBoard("", "red"); break; case "bc": cb.sendNotice( "SENT TO YOU BY: "+u, BC, '#111111', '#d1eaee' , "bold"); cb.sendNotice( "SENT TO BROADCASTER:", u, '#111111', '#d1eaee', "bold"); showLeaderBoard(BC, ""); break; default: cb.sendNotice( "SENT TO ONLY YOU:", u, '#111111', '#d1eaee', "bold"); showLeaderBoard(u, ""); break; } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/tippers': { cmd = 1; if (isMod || isBC) { if (ntc2 != null && (ntc2 != "" || ntc2 != " " || ntc2 != "\u00a0")) { if (ntc2 > 100) { cb.sendNotice('List cannot exceed 100, defaulting to 100.', u, green); num = 100 } num = ntc2; } else { num = 20 } switch (ntc) { case "all": cb.sendNotice( "SENT TO ALL:", u, '#111111', '#d1eaee' , "bold"); showTippers("", "", num); break; case "tbm": cb.sendNotice( "SENT TO BROADCASTER and MODS:", u, '#111111', '#d1eaee' , "bold"); showTippers("", "red", num);showTippers(BC,''); break; case "mods": cb.sendNotice( "SENT TO MODS:", u, '#111111', '#d1eaee' , "bold"); showTippers("", "red", num); break; case "bc": cb.sendNotice( "SENT TO YOU BY: "+u, BC, '#111111', lbback , "bold"); cb.sendNotice( "SENT TO BROADCASTER:", u, '#111111', '#d1eaee' , "bold"); showTippers(BC, "", num); break; default: cb.sendNotice( "SENT TO ONLY YOU:", u, '#111111', '#d1eaee' , "bold"); showTippers(u, "", num); break; } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/useleaderboard': { cmd = 1; if (isMod || isBC) { setLeaderToggle(message[1],u) } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.',u,green); } break; } case '/usetipcount': { cmd = 1; if (isMod || isBC) { setTipCountToggle(message[1],u) } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.',u,green); } break; } //********* Notifier Commands case '/usenotifier': { cmd = 1; if (isMod || isBC) { setNotifierToggle(message[1],u) } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.',u,green); } break; } case '/chgmsg1': { cmd = 1; if (isMod || isBC) { if(message[1] == '' || message[1] == null) { cb.sendNotice('You must enter a new message for the notifier feature. If you want to disable the notifications, enter /usenotifier off.',u,green) } else { notifierMessage1 = msg['m'].substring(8).trim(); cb.sendNotice('You have set the Notifier 1 message to: ' + notifierMessage1,u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.',u,green); } break; } case '/chgmsg2': { cmd = 1; if (isMod || isBC) { if(message[1] == '' || message[1] == null) { cb.sendNotice('You must enter a new message for the notifier feature. If you want to disable the notifications, enter /usenotifier off.',u,green) } else { notifierMessage2 = msg['m'].substring(8).trim(); cb.sendNotice('You have set the Notifier 2 message to: ' + notifierMessage2,u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.',u,green); } break; } case '/chgmsg3': { cmd = 1; if (isMod || isBC) { if(message[1] == '' || message[1] == null) { cb.sendNotice('You must enter a new message for the notifier feature. If you want to disable the notifications, enter /usenotifier off.',u,green) } else { notifierMessage3 = msg['m'].substring(8).trim(); cb.sendNotice('You have set the Notifier 3 message to: ' + notifierMessage3,u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.',u,green); } break; } case '/chgmsg4': { cmd = 1; if (isMod || isBC) { if(message[1] == '' || message[1] == null) { cb.sendNotice('You must enter a new message for the notifier feature. If you want to disable the notifications, enter /usenotifier off.',u,green) } else { notifierMessage4 = msg['m'].substring(8).trim(); cb.sendNotice('You have set the Notifier 4 message to: ' + notifierMessage4,u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.',u,green); } break; } case '/chgmsg5': { cmd = 1; if (isMod || isBC) { if(message[1] == '' || message[1] == null) { cb.sendNotice('You must enter a new message for the notifier feature. If you want to disable the notifications, enter /usenotifier off.',u,green) } else { notifierMessage5 = msg['m'].substring(8).trim(); cb.sendNotice('You have set the Notifier 5 message to: ' + notifierMessage5,u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.',u,green); } break; } case '/dspmsg': { cmd = 1; if (isMod || isBC) { setNoticeColor(); switch(message[1]) { case('1'): { if(notifierMessage1 == '' || notifierMessage1 == null) { cb.sendNotice('Notifier 1 Message is blank.', u, green) } else { cb.sendNotice('\u25ba ' + notifierMessage1, "", noticeBgColor, noticeTextColor, "bold"); } break; } case('2'): { if(notifierMessage2 == '' || notifierMessage2 == null) { cb.sendNotice('Notifier 2 Message is blank.', u, green) } else { cb.sendNotice('\u25ba ' + notifierMessage2, "", noticeBgColor, noticeTextColor, "bold"); } break; } case('3'): { if(notifierMessage3 == '' || notifierMessage3 == null) { cb.sendNotice('Notifier 3 Message is blank.', u, green) } else { cb.sendNotice('\u25ba ' + notifierMessage3, "", noticeBgColor, noticeTextColor, "bold"); } break; } case('4'): { if(notifierMessage4 == '' || notifierMessage4 == null) { cb.sendNotice('Notifier 4 Message is blank.', u, green) } else { cb.sendNotice('\u25ba ' + notifierMessage4, "", noticeBgColor, noticeTextColor, "bold"); } break; } case('5'): { if(notifierMessage5 == '' || notifierMessage5 == null) { cb.sendNotice('Notifier 5 Message is blank.', u, green) } else { cb.sendNotice('\u25ba ' + notifierMessage5, '', noticeBgColor, noticeTextColor, 'bold'); } break; } case('all'): { for (let j = 1; j <= 5; j++) { if(this["notifierMessage"+j] != '' && this["notifierMessage"+j] != null) { cb.sendNotice(j + ". " + this["notifierMessage"+j], u, noticeBgColor, noticeTextColor, "bold"); } } break; } default: { cb.sendNotice('Invalid message slot, values must be 1-5 or "all".\nType "/fbhelp notices" to see a full list of the notice related commands.', u, green); break; } } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } break; } //********* Change Subject Command case '/chgsubject': case '/newsubject': { cmd = 1; if (isMod || isBC) { newSubject = msg['m'].substring(12).trim() setRoomSubject(newSubject,u); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } break; } case '/subject': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { newSubject = msg['m'].substring(9).trim() setRoomSubject(newSubject,u); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } } break; } //********* Ticket Show Support Commands case '/prepticket': { cmd = 1; if (isMod || isBC) { if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { prepticketshow(u); cb.sendNotice('Fembot Ticket show prep has been completed.', u, green); } else { cb.sendNotice('For the Fembot Ticket Show, the ticket show must be active before using the /prepticket command (can be started with "/useticketshow on").', u, green); } } else { prepticketshow(u); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } break; } case '/backuplist': case '/dspbackup': { cmd = 1; if (ticketShowType != 'Fembot Ticket Show') { if (backupToggle == 1) { if (isMod || isBC) { cb.sendNotice('Users currently on the Backup Ticket List: ' + backupListArray.length, u, green); cb.sendNotice((backupListArray.length > 0 == true ? cbjs.arrayJoin(backupListArray, ', ') : 'No users.'), u); cb.sendNotice('End of List', u, green); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('The Backup Ticket List is disabled.', u, green); } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup list is only used for separate Ticket Apps.', u, green); } break; } case '/backupfb': { cmd = 1; if (ticketShowType != 'Fembot Ticket Show') { if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice('Backing up external ticket list in the Fembot.', u, green); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { if (!cbjs.arrayContains(backupListArray, cmdvalsplit[i])) { backupListArray.push(cmdvalsplit[i]); cb.sendNotice('Added ' + cmdvalsplit[i] + ' to the backup ticket list.', u); } } } } else if (!cbjs.arrayContains(backupListArray, message[1])) { backupListArray.push(message[1]); } cb.sendNotice(u + ' has completed a backup of the current ticket list.', '', green, '', 'normal', 'red'); cb.sendNotice('All users were added.', u, green); } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup list is only used for separate Ticket Apps.', u, green); } break; } case '/expbackup': { cmd = 1; if (ticketShowType != 'Fembot Ticket Show') { if (backupToggle == 1) { if (isMod || isBC) { if (backupListArray.length > 0) { msg['m'] = '/add ' + cbjs.arrayJoin(backupListArray, ', '); cb.sendNotice('The command has been issued to restore the users from the backup ticket list to the ticket show, which requires the Ticket App is already running, and this user has authority to the /add command.', u, green); } else { cb.sendNotice('No Backup Ticket List to add.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.',u,green); } } else { cb.sendNotice('The Backup Ticket List is disabled.', u, green); } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup list is only used for separate Ticket Apps.', u, green); } break; } case '/addlbtop': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use the /add command while a private show is running.', u,green); } else { LBi = 0; addcmd = '/add '; if (isBC || (isMod && ticketModAdd)) { numLB = parseInt(message[1]) if(isNaN(numLB)) { cb.sendNotice('The value entered for the number of tippers from the leaderboard is not numeric, please try again.', u, green); break; } if (numLB <= 0) { numLB = parseInt(cb.settings.numberFromLB); } if (numLB <= 0) { numLB = 3; cb.sendNotice('No setting defined for number of entries to add, defaulting to top 3.', u, green); } if (ticketShowType != 'Fembot Ticket Show') { addFromLeaderboard('num', numLB); if (addLBstring != '') { msg['m'] = addcmd + addLBstring; cb.sendNotice('The top ' + numLB + ' tippers from the Leaderboard have been added to the ticket show (if the ticket App is already running, and this user has authority to the /add command).', u, green); } else { cb.sendNotice('No Leaderboard entries to add.', u, green); } } else { if (ticketShowToggle == 1) { addFromLeaderboard('num', numLB); if (addLBstring != '') { cb.sendNotice('The top ' + numLB + ' tippers from the Leaderboard have been added to the Fembot Ticket Show.', u, green); } else { cb.sendNotice('No Leaderboard entries to add.', u, green); } } else { cb.sendNotice('Before using the "Add Leaderboard" function, the ticket show feature must first be enabled when using the Fembot Ticket Show.', u, green); } } } else { cb.sendNotice('Only broadcasters and moderators (if configured) are able to use that command.\nType "/fbhelp tickets" to see a full list of the ticket show related commands.',u ,green); } } break; } case '/addlbamt': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use the /addlbamt command while a private show is running.', u,green); } else { LBi = 0; addcmd = '/add '; if (isBC || (isMod && ticketModAdd)) { amtLB = parseInt(message[1]) if (isNaN(amtLB)) { cb.sendNotice('The value entered for the tip amount is not numeric, please try again.', u, green); break; } if (amtLB <= 0) { amtLB = parseInt(cb.settings.amountFromLB); } if (amtLB <= 0) { amtLB = 1000; cb.sendNotice('No setting defined for minimum tip amount to add, defaulting to 1000 tokens.', u, green); } if (ticketShowType != 'Fembot Ticket Show') { addFromLeaderboard("amt", amtLB); if (addLBstring != '') { msg['m'] = addcmd + addLBstring; cb.sendNotice('Users who have tipped more than ' + amtLB + ' during this session have been added to the ticket show (assumes the Ticket App is already running, and this user has authority to the /add command).', u, green); } else { cb.sendNotice('No qualifying tippers to add.', u, green); } } else { if (ticketShowToggle == 1) { addFromLeaderboard("amt", amtLB); if (addLBstring != '') { cb.sendNotice('Users who have tipped more than ' + amtLB + ' during this session have been added to the Fembot Ticket Show.', u, green); } else { cb.sendNotice('No qualifying tippers to add.', u, green); } } else { cb.sendNotice('Before using the "Add Leaderboard" function, the ticket show feature must first be enabled when using the Fembot Ticket Show.', u, green); } } } else { cb.sendNotice('Only broadcasters and moderators (if configured) are able to use that command.\nType "/fbhelp tickets" to see a full list of the ticket show related commands.',u ,green); } } break; } case '/backupprice': case '/bup': { cmd = 1; if (isMod || isBC) { if (ticketShowType != 'Fembot Ticket Show') { numprice = parseInt(message[1]) if(isNaN(numprice)) { cb.sendNotice('The value entered for the backup ticket price is not numeric, please try again.', u, green); } else if (backupToggle != 1) { cb.sendNotice('The backup list is disabled, you can use the command "/usebackup on" to enable the backup.', u, green); } else { ticketPrice = numprice; cb.sendNotice('From Fembot: Backup List ticket price has been updated to ' + numprice + ' tokens.', u, green); } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup price is only used for separate Ticket Apps.', u, green); } } break; } case '/usebackup': { cmd = 1; if (ticketShowType != 'Fembot Ticket Show') { if (isMod || isBC) { if (message[1] != 'on' && message[1] != 'off') { cb.sendNotice(message[1] + ' is not a valid parameter option for /usebackup, the parameter should be "on" or "off".', mod, green); } else { setBackupToggle(message[1],u) } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup list is only used for separate Ticket Apps.', u, green); } break; } //********* Tip Menu Commands case '/tipmenu': { cmd = 1; if (tipMenuToggle == 1) { if (isMod || isBC) { u = ''; } cb.sendNotice(TIPMENU.tipMenu, u, TIPMENU.bgColor1, TIPMENU.txtColor1, "bold"); } else if (tipMenu2Toggle == 1) { if (isMod || isBC) { u = ''; } cb.sendNotice(TIPMENU2.tipMenu, u, TIPMENU2.bgColor1, TIPMENU2.txtColor1, "bold"); } else { cb.sendNotice('The Tip Menu has not been enabled.', u, green); } break; } case '/swapmenu': { cmd = 1; if (isMod || isBC) { if (tipMenuToggle == 1 && tipMenu2Toggle == 0) { setTipMenuToggle('off',u) setTipMenu2Toggle('on',u) } else if (tipMenu2Toggle == 1 && tipMenuToggle == 0) { setTipMenu2Toggle('off',u) setTipMenuToggle('on',u) } else if (tipMenu2Toggle == 0 && tipMenuToggle == 0) { cb.sendNotice('Both menus are currently disabled, they cannot be swapped. You can turn one of the menus on using either /usemenu on or /usemenu2 on', u, green); } else { cb.sendNotice('Invalid definition, both menus are already active.', u, green); } } break; } case '/usemenu': { cmd = 1; if (isMod || isBC) { if (tipMenu2Toggle == 1 && message[1] === 'on') { cb.sendNotice('Cannot enable Tip Menu 1 while Tip Menu 2 is active. You can use the "/swapmenu" command to switch between the two.', u, green); } else { setTipMenuToggle(message[1],u) } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.',u,green); } break; } case '/usemenu2': { cmd = 1; if (isMod || isBC) { if (tipMenuToggle == 1 && message[1] === 'on') { cb.sendNotice('Cannot enable Tip Menu 2 while Tip Menu 1 is active. You can use the "/swapmenu" command to switch between the two.', u, green); } else { setTipMenu2Toggle(message[1],u) } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.',u,green); } break; } case '/tipmenurequests': { cmd = 1; touser = u; if (isMod) { touser = ""; } if (tipMenuToggle == 1) { let rL = TIPMENU.request.length; if (rL === 0) { cb.sendNotice("There is no request at the moment.", u, TIPMENU.bgColor1, TIPMENU.txtColor1); } else { let cmdInt1 = parseInt(message['1']); if (cmdInt1 <= 0) { cb.sendNotice('There have been no requests.', u, TIPMENU.bgColor1, TIPMENU.txtColor1); } else { let noticeMsg; let rS = 0; if (message['1'] === "all" || message['1'] === "All") { cmdInt1 = rL; } else if (cmdInt1 === undefined || isNaN(cmdInt1)) { cmdInt1 = 10; rS = rL - 10; } if (rL <= cmdInt1) { noticeMsg = '**** Here is the list of all the requests! ****\n'; cmdInt1 = rL; rS = 0; } else if (rL > 50) { noticeMsg = '**** Here is are the last 50 requests! ****\n'; rS = rL - 50; } else { noticeMsg = '**** Here ' + (cmdInt1 === 1 ? "is the last" : "are the last " + cmdInt1) + ' request' + (cmdInt1 === 1 ? "" : "s") + '! **** \n'; rS = rL - cmdInt1; } for (let i = rS; i < rL; i++) { noticeMsg += 'Request #' + (i + 1) + ': ' + TIPMENU.requesters[i] + ' requested ' + TIPMENU.request[i] + '\n'; } noticeMsg += '**************************************'; cb.sendNotice(noticeMsg, touser, TIPMENU.bgColor1, TIPMENU.txtColor1); } } } else if (tipMenu2Toggle == 1) { let rL = TIPMENU2.request.length; if (rL === 0) { cb.sendNotice("There is no request at the moment.", u, TIPMENU2.bgColor1, TIPMENU2.txtColor1); } else { let cmdInt1 = parseInt(message['1']); if (cmdInt1 <= 0) { cb.sendNotice('There have been no requests.', u, TIPMENU2.bgColor1, TIPMENU2.txtColor1); } else { let noticeMsg; let rS = 0; if (message['1'] === "all" || message['1'] === "All") { cmdInt1 = rL; } else if (cmdInt1 === undefined || isNaN(cmdInt1)) { cmdInt1 = 10; rS = rL - 10; } if (rL <= cmdInt1) { noticeMsg = '**** Here is the list of all the requests! ****\n'; cmdInt1 = rL; rS = 0; } else if (rL > 50) { noticeMsg = '**** Here is are the last 50 requests! ****\n'; rS = rL - 50; } else { noticeMsg = '**** Here ' + (cmdInt1 === 1 ? "is the last" : "are the last " + cmdInt1) + ' request' + (cmdInt1 === 1 ? "" : "s") + '! **** \n'; rS = rL - cmdInt1; } for (let i = rS; i < rL; i++) { noticeMsg += 'Request #' + (i + 1) + ': ' + TIPMENU2.requesters[i] + ' requested ' + TIPMENU2.request[i] + '\n'; } noticeMsg += '**************************************'; cb.sendNotice(noticeMsg, touser, TIPMENU2.bgColor1, TIPMENU2.txtColor1); } } } break; } case '/tipmenuadd': { cmd = 1; if (!isMod && !isBC) { cb.sendNotice("Only mods and broadcasters can use this command.", u, "#FFFFFF", "#FF0000"); } else { let label; let newItemPrice = parseInt(message['1']); if (newItemPrice <= 0 || isNaN(newItemPrice)) { cb.sendNotice('The correct format is "/menuadd X item" where X has to be a number over 0. This is the amount the viewers will tip for it.', u, "#FFFFFF", "#FF0000"); return; } if (!message[2]) { cb.sendNotice("You need to include a label for that option.", u, "#FFFFFF", "#FF0000"); return; } for (let j = 2; j < message.length; j++) { if (j === 2) { label = message[j]; } else { label += " " + message[j]; } } if (tipMenuToggle == 1) { cb.sendNotice("Tip menu to Broadcaster - " + (u === cb.room_slug ? "You" : u) + ' added the option "' + label + '" for ' + newItemPrice + ' tokens to the menu.', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice("Tip menu to mods - " + u + ' added the option "' + label + '" for ' + newItemPrice + ' tokens the menu.', "", "#FFFFFF", "#FF0000", "bold", "red"); if (cbjs.arrayContains(TIPMENU.tipMenuPrice, newItemPrice)) { cb.sendNotice("Tip Menu - " + newItemPrice + " is already on the menu. It is recommended to have different price for each item.", u, "#FFFFFF", "#FF0000"); } TIPMENU.tipMenuPrice.push(newItemPrice); TIPMENU.tipMenuItem.push(label); priceChecker('add','Tip Menu Option: '+label, newItemPrice); menuSanitize(); } else if (tipMenu2Toggle == 1) { cb.sendNotice("Tip menu to Broadcaster - " + (u === cb.room_slug ? "You" : u) + ' added the option "' + label + '" for ' + newItemPrice + ' tokens to Menu 2.', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice("Tip menu to mods - " + u + ' added the option "' + label + '" for ' + newItemPrice + ' tokens to Menu 2.', "", "#FFFFFF", "#FF0000", "bold", "red"); if (cbjs.arrayContains(TIPMENU2.tipMenuPrice, newItemPrice)) { cb.sendNotice("Tip Menu - " + newItemPrice + " is already on Menu 2. It is recommended to have different price for each item.", u, "#FFFFFF", "#FF0000"); } TIPMENU2.tipMenuPrice.push(newItemPrice); TIPMENU2.tipMenuItem.push(label); priceChecker('add','Tip Menu 2 Option: '+label, newItemPrice); menuSanitize2(); } } break; } case '/tipmenurmv': { cmd = 1; if (!isMod && !isBC) { cb.sendNotice("Only mods and broadcasters can use this command.", u, "#FFFFFF", "#FF0000"); } else { let itemPrice = parseInt(message['1']); let label; let s = 2; if (isNaN(itemPrice)) { s = 1; } for (let i = s; i < message.length; i++) { if (i === s) { label = message[i]; } else { label += " " + message[i]; } } if (itemPrice <= 0) { cb.sendNotice("Error! Price must be greater than 0.", "", "#FFFFFF", "#FF0000", "bold"); return; } if (tipMenuToggle == 1) { if (itemPrice > 0) { if (cbjs.arrayContains(TIPMENU.tipMenuPrice, itemPrice)) { if (!message[2]) { cb.sendNotice('Tip menu - No item label was given with the command, so all menu items that match the price of "' + itemPrice + '" will be removed from the menu.', u, "#FFFFFF", "#FF0000", "bold"); for (let i = 0; i < TIPMENU.menuLength; i++) { if (itemPrice === TIPMENU.tipMenuPrice[i]) { priceChecker('rmv','Tip Menu Option: '+TIPMENU.tipMenuItem[i], TIPMENU.tipMenuPrice[i],u); TIPMENU.tipMenuPrice[i] = 0; cb.sendNotice("Tip menu to Broadcaster - " + (u === cb.room_slug ? "You" : u) + ' removed the option "' + TIPMENU.tipMenuItem[i] + '" from the menu.', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice("Tip menu to mods - " + u + ' removed the option "' + TIPMENU.tipMenuItem[i] + '" from the menu.', "", "#FFFFFF", "#FF0000", "bold", "red"); } } menuSanitize(); } else { let labelFound = false; for (let i = 0; i < TIPMENU.menuLength; i++) { if (itemPrice === TIPMENU.tipMenuPrice[i] && label === TIPMENU.tipMenuItem[i]) { labelFound = true; priceChecker('rmv','Tip Menu Option: '+TIPMENU.tipMenuItem[i], TIPMENU.tipMenuPrice[i],u); TIPMENU.tipMenuPrice[i] = 0; cb.sendNotice("Tip menu to Broadcaster - " + (u === cb.room_slug ? "You" : u) + ' removed the option "' + TIPMENU.tipMenuItem[i] + '" from the menu.', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice("Tip menu to mods - " + u + ' removed the option "' + TIPMENU.tipMenuItem[i] + '" from the menu.', "", "#FFFFFF", "#FF0000", "bold", "red"); menuSanitize(); } } if (!labelFound) { cb.sendNotice("Tip menu - Unable find item " + label + "(" + itemPrice + ") on the menu. Skipping.", u, "#FFFFFF", "#FF0000", "bold"); } } } else { cb.sendNotice("Tip menu - Unable find any item at " + itemPrice + " tokens on the menu.", u, "#FFFFFF", "#FF0000", "bold"); } } else { if (!label) { cb.sendNotice('Tip menu - Unable to process. Use "/tipmenurmv X Label". Where X is the amount of tokens and label is the name of the item.', u, "#FFFFFF", "#FF0000", "bold"); } else if (cbjs.arrayContains(TIPMENU.tipMenuItem, label)) { for (let i = 0; i < TIPMENU.menuLength; i++) { if (label === TIPMENU.tipMenuItem[i]) { priceChecker('rmv','Tip Menu Option: '+TIPMENU.tipMenuItem[i], TIPMENU.tipMenuPrice[i],u); TIPMENU.tipMenuPrice[i] = 0; cb.sendNotice("Tip menu to Broadcaster - " + (u === cb.room_slug ? "You" : u) + ' removed the option "' + TIPMENU.tipMenuItem[i] + '" from the menu.', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice("Tip menu to mods - " + u + ' removed the option "' + TIPMENU.tipMenuItem[i] + '" from the menu.', "", "#FFFFFF", "#FF0000", "bold", "red"); } } menuSanitize(); } else { cb.sendNotice("Tip menu - Unable find item " + label + " on the menu. Skipping.", u, "#FFFFFF", "#FF0000", "bold"); } } } else if (tipMenu2Toggle == 1) { if (itemPrice > 0) { if (cbjs.arrayContains(TIPMENU2.tipMenuPrice, itemPrice)) { if (!message[2]) { cb.sendNotice('Tip menu 2 - No label was found! Every options that match "' + itemPrice + '" will be removed from menu 2.', u, "#FFFFFF", "#FF0000", "bold"); for (let i = 0; i < TIPMENU2.menuLength; i++) { if (itemPrice === TIPMENU2.tipMenuPrice[i]) { priceChecker('rmv','Tip Menu 2 Option: '+TIPMENU2.tipMenuItem[i], TIPMENU2.tipMenuPrice[i],u); TIPMENU2.tipMenuPrice[i] = 0; cb.sendNotice("Tip menu 2 to Broadcaster - " + (u === cb.room_slug ? "You" : u) + ' removed the option "' + TIPMENU2.tipMenuItem[i] + '" from menu 2.', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice("Tip menu 2 to mods - " + u + ' removed the option "' + TIPMENU2.tipMenuItem[i] + '" from menu 2.', "", "#FFFFFF", "#FF0000", "bold", "red"); } } menuSanitize2(); } else { let labelFound = false; for (let i = 0; i < TIPMENU2.menuLength; i++) { if (itemPrice === TIPMENU2.tipMenuPrice[i] && label === TIPMENU2.tipMenuItem[i]) { labelFound = true; priceChecker('rmv','Tip Menu 2 Option: '+TIPMENU2.tipMenuItem[i], TIPMENU2.tipMenuPrice[i],u); TIPMENU2.tipMenuPrice[i] = 0; cb.sendNotice("Tip menu 2 to Broadcaster - " + (u === cb.room_slug ? "You" : u) + ' removed the option "' + TIPMENU2.tipMenuItem[i] + '" from menu 2.', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice("Tip menu 2 to mods - " + u + ' removed the option "' + TIPMENU2.tipMenuItem[i] + '" from menu 2.', "", "#FFFFFF", "#FF0000", "bold", "red"); menuSanitize2(); } } if (!labelFound) { cb.sendNotice("Tip menu 2 - Unable find item " + label + "(" + itemPrice + ") on menu 2. Skipping.", u, "#FFFFFF", "#FF0000", "bold"); } } } else { cb.sendNotice("Tip menu 2 - Unable find any item at " + itemPrice + " tokens on menu 2.", u, "#FFFFFF", "#FF0000", "bold"); } } else { if (!label) { cb.sendNotice('Tip menu - Unable to process. Use "/tipmenurmv X Label". Where X is the amount of tokens and label is the name of the item.', u, "#FFFFFF", "#FF0000", "bold"); } else if (cbjs.arrayContains(TIPMENU2.tipMenuItem, label)) { for (let i = 0; i < TIPMENU2.menuLength; i++) { if (label === TIPMENU2.tipMenuItem[i]) { priceChecker('rmv','Tip Menu 2 Option: '+TIPMENU2.tipMenuItem[i], TIPMENU2.tipMenuPrice[i],u); TIPMENU2.tipMenuPrice[i] = 0; cb.sendNotice("Tip menu 2 to Broadcaster - " + (u === cb.room_slug ? "You" : u) + ' removed the option "' + TIPMENU2.tipMenuItem[i] + '" from menu 2.', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice("Tip menu 2 to mods - " + u + ' removed the option "' + TIPMENU2.tipMenuItem[i] + '" from menu 2.', "", "#FFFFFF", "#FF0000", "bold", "red"); } } menuSanitize(); } else { cb.sendNotice("Tip menu 2 - Unable find item " + label + " on menu 2. Skipping.", u, "#FFFFFF", "#FF0000", "bold"); } } } } break; } //********* Positions Tip Menu Commands case '/posmenu': { cmd = 1; if (posTipMenuToggle == 1) { if (isMod) { u = ''; } cb.sendNotice(POSTIPMENU.posTipMenu, u, POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor, "bold"); } else { cb.sendNotice('The Positions Tip Menu has not been enabled.', u, green); } break; } case '/useposmenu': { cmd = 1; if (isMod || isBC) { setPosTipMenuToggle(message[1], u) } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u,green); } break; } case '/posmenurequests': { cmd = 1; m.background = '#d9d9d9'; if (isMod) { u = ''; } let posrL = POSTIPMENU.posRequest.length; if (posrL === 0) { cb.sendNotice("There is no request at the moment.", u, POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor); } else { let cmdInt1 = 10; let posNoticeMsg; let posrS = 0; if (posrL <= cmdInt1) { posNoticeMsg = '**** Here is the list of the requests! ****\n'; cmdInt1 = posrL; posrS = 0; } else if (posrL > 10) { posNoticeMsg = '**** Here is are the last 10 requests! ****\n'; posrS = posrL - 10; } for (let i = posrS; i < posrL; i++) { posNoticeMsg += 'Position Request #' + (i + 1) + ': ' + POSTIPMENU.posRequesters[i] + ' requested ' + POSTIPMENU.posRequest[i] + '\n'; } posNoticeMsg += '**************************************'; cb.sendNotice(posNoticeMsg, u, POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor); } break; } case '/posmenuadd': { cmd = 1; m.background = '#d9d9d9'; if (!isMod && !isBC) { cb.sendNotice("Only mods and broadcasters can use this command.", u, "#FFFFFF", "#FF0000"); } else { let poslabel; let newPosItemPrice = parseInt(message['1']); if (newPosItemPrice <= 0 || isNaN(newPosItemPrice)) { cb.sendNotice('No price was given. The correct format is "/postipmenuadd X Y" where X has to be a number greater than 0. This is the amount the viewers will tip for item.', u, "#FFFFFF", "#FF0000"); return; } if (!message[2]) { cb.sendNotice('No position was given. The correct format is "/postipmenuadd X Y" where Y has to be the name of the position being added.', u, "#FFFFFF", "#FF0000"); return; } for (let j = 2; j < message.length; j++) { if (j === 2) { poslabel = message[j]; } else { poslabel += " " + message[j]; } } cb.sendNotice('Position Tip menu notification - ' + (u === cb.room_slug ? "You" : u) + ' added the option "' + poslabel + '" for ' + newPosItemPrice + ' tokens to the positions menu.', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice('Position Tip menu notification - The option "' + poslabel + '" for ' + newPosItemPrice + ' tokens was added to the Positions Tip Menu.', "", "#FFFFFF", "#FF0000", "bold", "red"); if (cbjs.arrayContains(POSTIPMENU.posTipMenuPrice, newPosItemPrice)) { cb.sendNotice("Positions Tip Menu - " + newPosItemPrice + " is already on the positions menu. It is recommended to have different price for each item.", u, "#FFFFFF", "#FF0000"); } POSTIPMENU.posTipMenuPrice.push(newPosItemPrice); POSTIPMENU.posTipMenuItem.push(poslabel); priceChecker('add','Positions Menu Option: '+poslabel, newPosItemPrice,u); posMenuSanitize(); } break; } case '/posmenurmv': { cmd = 1; m.background = '#d9d9d9'; if (!isMod && !isBC) { cb.sendNotice("Only mods and broadcasters can use this command.", u, "#FFFFFF", "#FF0000"); } else { let posItemPrice = parseInt(message['1']); let poslabel; let s = 2; if (isNaN(posItemPrice)) { s = 1; } for (let i = s; i < message.length; i++) { if (i === s) { poslabel = message[i]; } else { poslabel += " " + message[i]; } } if (posItemPrice <= 0) { cb.sendNotice("Positions Tip menu - Error! Price to be removed must be greater than 0.", "", "#FFFFFF", "#FF0000", "bold"); } if (posItemPrice > 0) { if (cbjs.arrayContains(POSTIPMENU.posTipMenuPrice, posItemPrice)) { if (!message[2]) { cb.sendNotice('Positions Tip Menu - No position name was provided, all options that match the "' + posItemPrice + '" token price will be removed.', u, "#FFFFFF", "#FF0000", "bold"); for (let i = 0; i < POSTIPMENU.posMenuLength; i++) { if (posItemPrice === POSTIPMENU.posTipMenuPrice[i]) { priceChecker('rmv','Positions Menu Option: '+POSTIPMENU.posTipMenuItem[i], POSTIPMENU.posTipMenuPrice[i],u); POSTIPMENU.posTipMenuPrice[i] = 0; cb.sendNotice('Positions Tip Menu - ' + (u === cb.room_slug ? "You" : u) + ' removed the option "' + POSTIPMENU.posTipMenuItem[i] + '".', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice('Positions Tip Menu - The option "' + POSTIPMENU.posTipMenuItem[i] + '" was removed.', "", "#FFFFFF", "#FF0000", "bold", "red"); } } posMenuSanitize(); } else { let poslabelFound = false; for (let i = 0; i < POSTIPMENU.posMenuLength; i++) { if (posItemPrice === POSTIPMENU.posTipMenuPrice[i] && label === POSTIPMENU.posTipMenuItem[i]) { poslabelFound = true; priceChecker('rmv','Positions Menu Option: '+POSTIPMENU.posTipMenuItem[i], POSTIPMENU.posTipMenuPrice[i],u); POSTIPMENU.posTipMenuPrice[i] = 0; cb.sendNotice('Positions Tip Menu - ' + (u === cb.room_slug ? "You" : u) + ' removed the option "' + POSTIPMENU.posTipMenuItem[i] + '".', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice('Positions Tip Menu - The option "' + POSTIPMENU.posTipMenuItem[i] + '" was removed.', "", "#FFFFFF", "#FF0000", "bold", "red"); menuSanitize(); } } if (!poslabelFound) { cb.sendNotice('Positions Tip Menu - Unable find item ' + poslabel + '(' + posItemPrice + ') on the menu. Skipping.', u, "#FFFFFF", "#FF0000", "bold"); } } } else { cb.sendNotice('Positions Tip Menu - Unable find any item at ' + posItemPrice + ' tokens on the positions menu.', u, "#FFFFFF", "#FF0000", "bold"); } } else { if (!poslabel) { cb.sendNotice('Positions Tip Menu - Unable to process command. Use "/postipmenurmv X Y". Where X is the tip amount and Y is the name of the position.', u, "#FFFFFF", "#FF0000", "bold"); } else if (cbjs.arrayContains(POSTIPMENU.posTipMenuItem, poslabel)) { for (let i = 0; i < POSTIPMENU.posMenuLength; i++) { if (poslabel === POSTIPMENU.posTipMenuItem[i]) { priceChecker('rmv','Positions Menu Option: '+POSTIPMENU.posTipMenuItem[i], POSTIPMENU.posTipMenuPrice[i],u); POSTIPMENU.posTipMenuPrice[i] = 0; cb.sendNotice('Positions Tip Menu - ' + (u === cb.room_slug ? "You" : u) + ' removed the option "' + POSTIPMENU.posTipMenuItem[i] + '".', cb.room_slug, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice('Positions Tip Menu - The option "' + POSTIPMENU.posTipMenuItem[i] + '" was removed.', "", "#FFFFFF", "#FF0000", "bold", "red"); } } posMenuSanitize(); } else { cb.sendNotice('Positions Tip Menu - Unable find item ' + poslabel + ' on the positions menu. Skipping.', u, "#FFFFFF", "#FF0000", "bold"); } } } break; } //********* Token Poll Commands case '/usepoll': { cmd = 1; if (isMod || isBC) { setTokenPollToggle(message[1], u) } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.\nType "/fbhelp commands" to see a full list of the available commands.',u,green); } break; } case '/poll': { cmd = 1; if (tokenPollToggle == 1) { sendto = u; if (isMod || isBC) { sendto = 'bc'; } showBoard(sendto); } else { cb.sendNotice('The Token Poll is disabled.', u, green); } break; } case '/endpoll': { cmd = 1; if (tokenPollToggle == 1) { if (!isMod && !isBC) { pollmsg("nm", u, ""); break; } pollmsg("a", "", u + " has ended the poll. No more votes will be counted."); if (pollRunning) { pollRunning = false; } showWinner(""); } else { cb.sendNotice('The Token Poll is disabled.', u, green); } break; } case '/restartpoll': { cmd = 1; if (tokenPollToggle == 1) { if (!isMod && !isBC) { pollmsg("nm", u, ""); break; } pollmsg("a", "", u + " has restarted the poll, voting has resumed."); if (!pollRunning) { pollRunning = true; pollType = "Never"; } } else { cb.sendNotice('The Token Poll is disabled.', u, green); } break; } case '/addvote': { cmd = 1; if (tokenPollToggle == 1) { var amount; if (!isMod && !isBC) { pollmsg("nm", u, ""); break; } if (isMod && !pollModAdd) { pollmsg("", u, "The broadcaster has disabled this function for mods."); break; } if (isMod || isBC) { var voteFail = true; if (!pollRunning) { pollmsg("", u, "The poll is not running, no need to vote."); break; } if (commandVar1 === 0 || commandVar2 === 0) { pollmsg("", u, 'Invalid Entry - The tip price amount and added vote amount cannot be zero. \n ex: "/addvote 10 1" will add 1 vote for the poll option with a price of 10'); break; } if (!commandVar1) { pollmsg("", u, 'Invalid Entry - A tip price amount must be specified to add votes to. \n ex: "/addvote 10 1" will add 1 vote for the poll option with a price of 10'); break; } if (!commandVar2) { amount = 1; } else { amount = commandVar2; } for (let i = 0; i < pollArrayAmount.length; i++) { if (commandVar1 === pollArrayAmount[i]) { pollmsg("a", u, u + " has " + (amount > 0 ? "added" : "removed") + " " + (amount < 0 ? -amount : amount) + " vote" + (amount === 1 || amount === -1 ? "" : "s") + " for " + pollArrayLabel[i]); pollArrayVotes[i] += amount; totalPollVotes += amount; voteFail = false; if (pollType === "Vote") { votesRemain -= amount; } checkPollEnd(); break; } } if (voteFail) { pollmsg("w", u, 'Invalid Entry - That tip price amount is not currently in the poll. \n The first variable needs to match a tip amount on the poll, the second variable is the number of votes to add.\n ex: "/addvote 10 1" will add 1 vote for the poll option with a price of 10'); break; } } } else { cb.sendNotice('The Token Poll is disabled.', u, green); } break; } case '/polloptadd': { cmd = 1; if (tokenPollToggle == 1) { var label; var oktoadd = 1; if (!isMod && !isBC) { pollmsg("nm", u, ""); break; } if (isMod || isBC) { if (commandVar1 <= 0 || isNaN(commandVar1)) { pollmsg("w", u, "The first variable has be be a number greater than 0. This is the amount the viewers will tip to vote for this selection."); var oktoadd = 0; break; } if (!message[2]) { pollmsg("w", u, "You must include a label for this voting selection in the second variable."); var oktoadd = 0; break; } if (pollArrayAmount.length >= 8) { pollmsg("w", u, "There are already 8 entries in the poll, no more can be added."); var oktoadd = 0; break; } for (let j = 0; j < pollArrayAmount.length; j++) { if (pollArrayAmount[j] === commandVar1) { pollmsg("bm", "", "Tip Price Amount specified is already used in the poll, and will not be added to the board. Please try again with a unique tip amount."); var oktoadd = 0; break; } } for (let i = 2; i < message.length; i++) { if (i === 2) { label = message[i]; } else { label += " " + message[i]; } } for (let j = 0; j < pollArrayLabel.length; j++) { if (pollArrayLabel[j] === label) { pollmsg("bm", "", "The Poll Option Label specified is already used in the poll, and will not be added to the board. Please try again with a unique label value."); var oktoadd = 0; break; } } if(oktoadd == 1) { populatePollArray(label,commandVar1,0); priceChecker('add','Poll Option: '+label, commandVar1,u); pollmsg("bm", u, u + ' added the option "' + label + '" to the poll.'); } } } else { cb.sendNotice('The Token Poll is disabled.', u, green); } break; } case '/polloptrmv': { cmd = 1; if (tokenPollToggle == 1) { if (!isMod && !isBC) { pollmsg("nm", u, ""); break; } if (isMod || isBC) { if (commandVar1 <= 0 || isNaN(commandVar1)) { pollmsg("w", u, "The first variable has be be a number greater than 0. This value is used to select the poll item that will be removed based on the price."); break; } if (pollArrayAmount.length <= 2) { pollmsg("w", u, "There are only 2 entries in the poll, no more can be removed."); break; } for (let i = 0; i < pollArrayAmount.length; i++) { if (pollArrayAmount[i] === commandVar1) { pollmsg("bm", u, u + ' removed the option "' + pollArrayLabel[i] + '" from the poll.'); priceChecker('rmv','Poll Option: '+pollArrayLabel[i], pollArrayAmount[i],u); cbjs.arrayRemove(pollArrayAmount, pollArrayAmount[i]); cbjs.arrayRemove(pollArrayLabel, pollArrayLabel[i]); pollArrayVotes[i] = 'dummy'; cbjs.arrayRemove(pollArrayVotes, 'dummy'); } } } } else { cb.sendNotice('The Token Poll is disabled.', u, green); } break; } case '/pst': case '/pollstarttimer': { cmd = 1; if (tokenPollToggle == 1) { if (!isMod && !isBC) { pollmsg("nm", u, ""); break; } if (!pollRunning) { pollmsg("w", u, "The poll is not running, unable to start a timer."); break; } if (pollType === "Timer") { if (pollMinsRemain >= 1) { pollmsg("w", u, 'A timer is already running, please use "/polladdtime [X]" to add time to timer. \nThe poll will end in ' + pollMinsRemain + ' minute' + (pollMinsRemain > 1 ? 's' : '')); } else if (pollSecsRemain >= 1) { pollmsg("w", u, 'Timer is already running, use "/polladdtime [X]" to change the remaining time. \nThe poll will end in ' + pollSecsRemain + ' seconds' + (pollSecsRemain > 1 ? 's' : '')); } break; } if (!commandVar1) { pollmsg("w", u, 'Invalid command, you need to specify the starting point for the timer in minutes. Example: use "/pollstarttimer 10" to start a 10 minute timer'); break; } if (commandVar1 > 60) { pollmsg("w", u, 'The time specified is greater than 60 minutes, please use a smaller value.'); break; } commandVar1 = parseInt(commandVar1) if (isNaN (commandVar1)) { pollmsg("w", u, 'Invalid value, the time entered must be a numeric value in minutes. Example: use "/pollstarttimer 10" to start a 10 minute timer'); break; } if (pollType !== "Timer") { pollTimerStopping = false; pollSwitchToTimer(commandVar1, u); break; } } else { cb.sendNotice('The Token Poll is disabled.', u, green); } break; } case '/polltimeleft': { cmd = 1; if (tokenPollToggle == 1) { if (!pollRunning) { showWinner(u); break; } if (pollType === "Timer") { cb.sendNotice(pollTimeLeft(), u, pollbackground, pollforeground, "bold"); break; } else { if (isMod || isBC) { pollmsg("", u, 'Timer is not running. If you want to start a timer use "/pollstarttimer X"'); } else { pollmsg("", u, "Timer is not running."); } break; } } else { cb.sendNotice('The Token Poll is disabled.', u, green); } break; } case '/polladdtime': { cmd = 1; if (tokenPollToggle == 1) { if (!isMod && !isBC) { pollmsg("nm", u, ""); } else if (!pollRunning) { pollmsg("w", u, "The poll is not running, no need to add time."); } else if (!commandVar1) { pollmsg("w", u, 'Invalid command, you need to specify the amount of time to add to the timer in minutes. Example: use "/polladdtime 3" to add 3 minutes to the timer'); } else if (pollType !== "Timer") { pollmsg("w", u, 'The poll is currently configured for vote count or manual end, a timer is not valid in this mode.'); } else if (pollMinsRemain + commandVar1 <= 0) { pollmsg("w", u, 'The value is over the amount of time left. You can use "/endpoll" to stop the poll and pick the winner.'); } else if (pollMinsRemain + commandVar1 > 60) { pollmsg("w", u, 'The added time will increase the timer to greater than 60 minutes, please use a smaller value.'); } else { pollAddTime(commandVar1, u); break; } } else { cb.sendNotice('The Token Poll is disabled.', u, green); } break; } case '/pollleader': { cmd = 1; if (tokenPollToggle == 1) { if (!pollRunning) { showWinner(u); break; } if (!isMod) { pollmsg("n", u, showLead()); break; } if (isMod) { pollmsg("", "", showLead()); break; } } else { cb.sendNotice('The Token Poll is disabled.', u, green); } break; } case '/pollstoptimer': { cmd = 1; if (tokenPollToggle == 1) { if (!isMod && !isBC) { pollmsg("nm", u, ""); break; } if (!pollRunning) { pollmsg("w", u, "The poll is not running, there is no timer running."); break; } if (pollType !== "Timer") { pollmsg("w", u, "A timer is not for this poll mode. Ignoring command."); break; } else if (pollType === "Timer") { pollType = "Never"; pollStopTimer(); pollmsg("a", u, "The timer has been canceled, switching modes to manual end. The poll will go on until stopped by the broadcaster or moderator.", "", pollbackground, pollforeground); break; } } else { cb.sendNotice('The Token Poll is disabled.', u, green); } break; } case '/pollchgtitle': { cmd = 1; if (tokenPollToggle == 1) { if (!isMod && !isBC) { pollmsg("nm", u, ""); break; } else { newtitle = msg['m'].substring(14).trim() if (newtitle) { pollTitle = newtitle; cb.sendNotice('You have updated the poll title to "' + newtitle + '".', u, green); } else { cb.sendNotice('A new title was not specified, please try the command again in the format "/pollchgtitle [new title]".', u, green); } } } else { cb.sendNotice('The Token Poll is disabled.', u, green); } break; } //********* Lush Menu Commands case '/lushmenu': { cmd = 1; if (lushMenuToggle == 1) { if (isMod || isBC) { sendto = ''; } else { sendto = u; } cb.sendNotice(LUSHMENU.lushMenu, sendto, LUSHMENU.lushBgColor, LUSHMENU.lushTxtColor, "bold"); } else { cb.sendNotice('Cannot display, the ' + whichToy + ' Menu is disabled.', u, green); } break; } case '/useoscimenu': case '/usehushmenu': case '/usetoymenu': case '/usetoy': case '/usedomimenu': case '/usenoramenu': case '/uselushmenu': { cmd = 1; if (isMod || isBC) { setLushMenuToggle(message[1], u) } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } break; } case '/uselush': { cmd = 1; if (isMod || isBC) { if (whichToy == 'Lush') { cb.sendNotice('The toy type is already set to "lush", please enter a new toy type.',u,green); } else { whichToy = 'Lush'; setLushMenu(); cb.sendNotice('You have updated the toy to the "lush".',u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } break; } case '/usenora': { cmd = 1; if (isMod || isBC) { if (whichToy == 'Nora') { cb.sendNotice('The toy type is already set to "nora", please enter a new toy type.',u,green); } else { whichToy = 'Nora'; setLushMenu(); cb.sendNotice('You have updated the toy to the "nora".',u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } break; } case '/usedomi': { cmd = 1; if (isMod || isBC) { if (whichToy == 'Domi') { cb.sendNotice('The toy type is already set to "domi", please enter a new toy type.',u,green); } else { whichToy = 'Domi'; setLushMenu(); cb.sendNotice('You have updated the toy to the "domi".',u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } break; } case '/usehush': { cmd = 1; if (isMod || isBC) { if (whichToy == 'Hush') { cb.sendNotice('The toy type is already set to "hush", please enter a new toy type.',u,green); } else { whichToy = 'Hush'; setLushMenu(); cb.sendNotice('You have updated the toy to the "hush".',u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } break; } case '/useosci': { cmd = 1; if (isMod || isBC) { if (whichToy == 'Osci') { cb.sendNotice('The toy type is already set to "osci", please enter a new toy type.',u,green); } else { whichToy = 'Osci'; setLushMenu(); cb.sendNotice('You have updated the toy to the "osci".',u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } break; } case '/chgtoy': { cmd = 1; if (isMod || isBC) { if (message[1] == whichToy) { cb.sendNotice('The toy type is already set to ' + whichToy + ', please enter a new toy type.',u,green); } else if (message[1] == 'Lush' || message[1] == 'lush') { whichToy = 'Lush'; setLushMenu(); cb.sendNotice('You have updated the toy to the "lush".',u,green); } else if (message[1] == 'Domi' || message[1] == 'domi') { whichToy = 'Domi'; setLushMenu(); cb.sendNotice('You have updated the toy to the "domi".',u,green); } else if (message[1] == 'Nora' || message[1] == 'nora') { whichToy = 'Nora'; setLushMenu(); cb.sendNotice('You have updated the toy to the "nora".',u,green); } else if (message[1] == 'Hush' || message[1] == 'hush') { whichToy = 'Hush'; setLushMenu(); cb.sendNotice('You have updated the toy to the "hush".',u,green); } else if (message[1] == 'Osci' || message[1] == 'osci') { whichToy = 'Osci'; setLushMenu(); cb.sendNotice('You have updated the toy to the "osci".',u,green); } else { cb.sendNotice('Invalid toy name, valid names are "lush", "nora", "domi", "hush", and "osci". Therefore, syntax for command is /chgtoy lush, please try again.',u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } break; } //********* Media List commands case "/media": { cmd = 1; if (mediaToggle == 0) { setMediaColors(); } if (isMod || isBC) { sendto = ""; } else { sendto = u; } showMedia(sendto); break; } case '/usemedia': { cmd = 1; if (isMod || isBC) { if (message[1] != 'on' && message[1] != 'off') { cb.sendNotice(message[1] + ' is not a valid parameter option for /usemedia, the parameter should be "on" or "off".', mod, green); } else { setMediaToggle(message[1], u) } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //********* Tip Response Commands case '/usetr': case '/usetipresponse': { cmd = 1; if (isMod || isBC) { if (message[1] != 'tipper' && message[1] != 'all' && message[1] != 'off') { cb.sendNotice(message[1] + ' is not a valid parameter option for /usetipresponse, the parameter should be "tipper", "all", or "off".', mod, green); } else { setTipResponseToggle(message[1], u) } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //********* Pre-sales Commands case '/fbpresale': { cmd = 1; if (isMod || isBC) { if ((message[1] == 'on' || message[1] == 'ON' || message[1] == 'On') && enablePresales == 'Yes') { cb.sendNotice('Fembot pre-sales are already enabled.', u, green); } else if ((message[1] == 'off' || message[1] == 'OFF' || message[1] == 'Off') && enablePresales == 'No') { cb.sendNotice('Fembot pre-sales are already disabled.', u, green); } else if ((message[1] == 'on' || message[1] == 'ON' || message[1] == 'On') && enablePresales == 'No') { enablePresales = 'Yes'; cb.sendNotice('Fembot pre-sales have been enabled.', u, green); } else if ((message[1] == 'off' || message[1] == 'OFF' || message[1] == 'Off') && enablePresales == 'Yes') { enablePresales = 'No'; cb.sendNotice('Fembot pre-sales have been disabled.', u, green); } else { cb.sendNotice('Invalid parameter for this command, valid values are "on" or "off".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case "/pslist": case "/presalelist": { cmd = 1; if (presalesToggle == 1) { if (isMod || isBC) { cb.sendNotice('Fembot: Users currently on the Pre-sale Ticket List: ' + presaleArray.length, u, green); cb.sendNotice((presaleArray.length > 0 == true ? cbjs.arrayJoin(presaleArray, ', ') : 'No ticket buyers.'), u); cb.sendNotice('End of Pre-sale List', u, green); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('Fembot: The Pre-sales feature is disabled.', u, green); } break; } case '/useps': case '/usepresales': case '/usepresale': { cmd = 1; if (enablePresales == 'Yes') { if (isMod || isBC) { if (presalePrice > 0) { if (ticketPrice > 0) { setPresalesToggle(message[1], u); } else { cb.sendNotice('Fembot: Unable to start pre-sales, a ticket show price must be set first using the command "/ticketprice xx" where xx will be the the Ticket App show price.', u, green); } } else { cb.sendNotice('Fembot: Unable to start pre-sales, a pre-sale ticket price must be set first using the command "/presaleprice xx" where xx is in the initial price to start selling pre-sales tickets at.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('Fembot pre-sales not started/ended as they are disabled. This is expected if UltraApp pre-sales are used.', u, green); } break; } case '/psprice': case '/presaleprice': { cmd = 1; if (isMod || isBC) { if (enablePresales == 'Yes') { numprice = parseInt(message[1]) if (isNaN(numprice)) { cb.sendNotice('The value entered for the pre-sale ticket price is not numeric, please try again.', u, green); break; } else if (numprice < 1 || numprice > 1000) { cb.sendNotice('The value entered for the pre-sale ticket price is outside allowable values from 1 to 1000, please try again.', u, green); } else if (numprice > ticketPrice) { cb.sendNotice('The value entered for the pre-sale ticket price is higher than the actual ticket price of ' + ticketPrice + '. Please update the ticket price first using the command "/ticketprice [newprice]".', u, green); } else { if (numprice < presalePrice) { cb.sendNotice('Warning: Value is updated but this price is lower than the previous pre-sale price of ' + presalePrice + '. It is not advisiable to decrease the presale price once tickets have been sold.', u, green); } if (presalesToggle == 1) { presalePriceChange(numprice,u); cb.sendNotice('The Pre-sale Ticket Price has been updated to ' + numprice + ' tokens, all tips of at least this amount will add a user to the Pre-sale Ticket List. You can view the pre-sales list with the command /presalelist and if not added from /prepticket, the presales list can be added to the show with the command /exppresale after the ticket show app is started.', u, green); } else { presalePrice = numprice; cb.sendNotice('The Pre-sale Ticket Price has been set to ' + numprice + ' tokens, and the pre-sale can now be started with the command "/usepresale on". ', u, green); } } } if (ticketShowType != 'Fembot Ticket Show' && backupToggle == 1) { numprice = parseInt(message[1]) if (!isNaN(numprice)) { setBackupTicketPrice(numprice,u); } } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/pspt': case '/presalepricetimer': { cmd = 1; if (isMod || isBC) { if (presalesToggle == 1) { validtimer = 0; numtimer = parseInt(message[1]) if(isNaN(numtimer)) { cb.sendNotice('The timer value entered for the pre-sale price change is not numeric, please try again. The syntax for the command is "/presalepricetimer [t] [p]", where [t] is the number of minutes to use for the timer, and [p] is the new ticket price that will be used when the timer expires.', u, green); } else if (numtimer < 1 || numtimer > 60) { cb.sendNotice('The timer value entered for the pre-sale price change is outside allowable values from 1 to 60 minutes, please try again. The syntax for the command is "/presalepricetimer [t] [p]", where [t] is the number of minutes to use for the timer, and [p] is the new ticket price that will be used when the timer expires.', u, green); } else if (presaleMinsRemain > 0 || presaleSecsRemain > 0) { cb.sendNotice('A timer is already running for the next price change. You can add time to the timer with the command "/presaleaddtime [t]" where [t] is the number of minutes to add, and can be positive to add time or negative to subtract time.', u, green); } else if (presalesToggle == 0) { cb.sendNotice('The Pre-sales function has not been turned on, you can use the command "/usepresale on" to enable this function if an initial price has been set.', u, green); } else { validtimer = 1; } numprice = parseInt(message[2]) if(isNaN(numprice)) { cb.sendNotice('The new pre-sales price value entered for the price change timer is not numeric, please try again.', u, green); validtimer = 0; } else if(numprice < 1 || numprice > 1000) { cb.sendNotice('The new pre-sales price value entered for the price change timer is outside allowable values from 1 to 1000, please try again.', u, green); validtimer = 0; } else if(numprice > ticketPrice) { cb.sendNotice('The new pre-sales price value entered of ' + numprice + ' should not be greater than the ticket show price of ' + ticketPrice + ', please try again. If the ticket show price is incorrect or not set, it can be set using the command "/ticketprice pp", where pp is the planned ticket show price.', u, green); validtimer = 0; } else { if (validtimer = 1) { presaleMinsRemain = numtimer; nextPresalePrice = numprice; presaleAutoTimer(presaleMinsRemain); cb.sendNotice('The timer has been started to update the pre-sale price to ' + numprice + ' tokens in ' + numtimer + ' minutes.', u, green); } } } else { cb.sendNotice('The Ticket Show Pre-sales function has not been turned on, you can use the command "/usepresale on" to enable this function if an initial price has been set.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/psstarttimer': case '/presalestarttimer': { cmd = 1; if (presalesToggle == 1) { if (isMod || isBC) { numtimer = parseInt(message[1]) if(isNaN(numtimer)) { cb.sendNotice('The value entered for the minutes to use for the pre-sale timer is not numeric, please try again.', u, green); break; } else if(numtimer < 1 || numtimer > 60) { cb.sendNotice('The value entered for the minutes to use for the pre-sale timer is outside allowable values from 1 to 60, please try again.', u, green); } else { presaleMinsRemain = numtimer; presaleAutoTimer(presaleMinsRemain); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.\nType "/fbhelp tickets" to see a full list of the available commands related to ticket shows.', u, green); } break; } case '/psat': case '/presaleaddtime': { cmd = 1; if (presalesToggle == 1) { if (isMod || isBC) { numtimer = parseInt(message[1]) if(isNaN(numtimer)) { cb.sendNotice('The value entered for the minutes to add to the pre-sale timer is not numeric, please try again.', u, green); break; } else if(numtimer < 1 || numtimer > 60) { cb.sendNotice('The value entered for the minutes to add to the pre-sale timer is outside allowable values from 1 to 60, please try again.', u, green); } else { presaleAddTime(numtimer, u); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.\nType "/fbhelp tickets" to see a full list of the available commands related to ticket shows.', u, green); } break; } case '/psstoptime': case '/presalestoptime': case '/presalestoptimer': { cmd = 1; if (presalesToggle == 1) { if (isMod || isBC) { stopPresaleTimer(u); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.\nType "/fbhelp tickets" to see a full list of the available commands related to ticket shows.', u, green); } break; } case '/expps': case '/exppresale': { cmd = 1; if (enablePresales == 'Yes') { if (isPrivate) { cb.sendNotice('You are not able to use the /exppresale command while a private show is running.', u,green); } else { if (isMod || isBC) { if (presaleArray.length > 0) { if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { addPresaleList(); } else { cb.sendNotice('For the Fembot Ticket Show, the ticket show must be active before using the Export Presale command (can be started with "/useticketshow on").', u, green); } } else { msg['m'] = '/add ' + cbjs.arrayJoin(presaleArray, ', '); cb.sendNotice('The "/add" command has been issued, so users from the pre-sale ticket list have been added to the ' + ticketShowType + ', assuming that App is already running, and this user has authority to the "/add" command.', u, green); } } else { cb.sendNotice('No Pre-sale Ticket List to add.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } } } break; } case '/addps': case '/addpresale': { cmd = 1; if (isMod || isBC) { if (presalesToggle == 1) { if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice('Adding multiple users to the Pre-sale list.', u, green); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { if (!cbjs.arrayContains(presaleArray, cmdvalsplit[i])) { addRmvPresale('add', cmdvalsplit[i]); cb.sendNotice('Added ' + cmdvalsplit[i] + ' to the pre-sale list.', u); cb.sendNotice(u + ' has added you to the Pre-sale list.', cmdvalsplit[i], green); } else { cb.sendNotice(cmdvalsplit[i] + ' is already on the pre-sale list. Skipping.', u); } } } cb.sendNotice('All users were added and notified.', u, green) cb.sendNotice(u + ' has added multiple users to the pre-sale list.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), '', green, '', 'normal', 'red'); } else { if (!cbjs.arrayContains(presaleArray, message[1])) { addRmvPresale('add',message[1]); } else { cb.sendNotice(message[1] + ' is already on the pre-sale list.', u); } } } else { cb.sendNotice('You didn\'t specify what user(s) you want to add to the Pre-sale list.', u, green); } } else { cb.sendNotice('Fembot: User not added to pre-sale ticket list, the Fembot Ticket Pre-sales feature is disabled.',u,green); } } break; } case '/rmvps': case '/rmvpresale': { cmd = 1; if (isMod || isBC) { if (presalesToggle == 1) { if(message[1] != '' && message[1] != null) { if (cbjs.arrayContains(presaleArray,message[1])) { addRmvPresale("rmv", message[1]); cb.sendNotice('User ' + message[1] + ' has been removed from the Pre-Sale Ticket List.', u, green); } else { cb.sendNotice('Note: User is not in the Pre-Sale Ticket List.',u,green); } } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.',u,green); } } break; } case '/psmode': case '/chgpresalemode': { cmd = 1; if (isMod || isBC) { if (presalesToggle == 1) { newPresaleMode = message[1].toLowerCase(); if (newPresaleMode != 'manual' && newPresaleMode != 'timer' && newPresaleMode != 'count') { cb.sendNotice('The value entered for the new mode is not valid, please try again using a value of "manual", "timer", or "count".', u, green); } else { if (newPresaleMode === presaleMode) { cb.sendNotice('The value entered for the new mode is the same as the existing mode, command ignored.', u, green); } else { setPresaleMode(newPresaleMode,u); } } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.',u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/pstimeleft': case '/presaletimeleft': { cmd = 1; if (enablePresales == 'Yes') { if (isMod || isBC) { if (presaleMinsRemain >= 1 || presaleSecsRemain >= 1) { cb.sendNotice(presaleTimeLeft(), "", yellow, "", "bold"); } else { cb.sendNotice('A pre-sale timer is not running.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } break; } //********* Check Colors case '/checkcolor': { cmd = 1; if (isBC || isMod) { if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExpSpc); if (cmdvalsplit.length < 2 || cmdvalsplit.length > 2) { cb.sendNotice('Invalid number of parameters for the /checkcolor command, should be two colors specified with a comma separating, such as /checkcolor "Light Blue","Dark Blue" (include quotes) for the colors that are already defined for the bot, or /checkcolor #yyyyyy,#xxxxxx for custom colors using their hex codes', u, green); } else { if (cmdvalsplit[1] != "" && cmdvalsplit[1] != "") { if (cmdvalsplit[1].substring(0,1) == '#') { testTextColor = checkTextColor(cmdvalsplit[1]); if (testTextColor == "default") { cb.sendNotice("Error while setting a custom text color. It has to be in a HEX format. Using default value.", u, "#FFFFFF", "#FF0000", "bold"); testTextColor = "#FFFFFF"; } } else { testTextColor = checkTextColor(cmdvalsplit[1]); } if (cmdvalsplit[0].substring(0,1) == '#') { testBgColor = checkBgColor(cmdvalsplit[0]); if (testBgColor == "default") { cb.sendNotice("Error while setting a custom background color. It has to be in a HEX format. Using default value.", u, "#FFFFFF", "#FF0000", "bold"); testBgColor = "#FFFFFF"; } } else { testBgColor = checkBgColor(cmdvalsplit[0]); } cb.sendNotice("This is your test message for Color Check.", u, testBgColor, testTextColor, "bold") } } } else { cb.sendNotice("No Colors were specified.", u, green); } } else { cb.sendNotice('Only broadcasters and moderators are able to use that command.', u, green); } break; } //********* Dice Game commands case '/prizes': { cmd = 1; if (diceToggle == 1) { if (isMod || isBC) { sendto = ""; } else { sendto = u; } diceShowPrizes(sendto); } else { cb.sendNotice('The dice game is not enabled.', u, green); } break; } case '/usedice': { cmd = 1; if (isMod || isBC) { setDiceToggle(message[1], u); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/dicerolls': { cmd = 1; if (isMod) { diceShowRolls(cb.room_slug); } diceShowRolls(u); break; } case '/chgdiceprice': { cmd = 1; if (isMod || isBC) { if (diceToggle == 1) { numprice = parseInt(message[1]); if(isNaN(numprice)) { cb.sendNotice('The value entered for the new Dice Roll price is not numeric, please try again.', u, green); } else if(numprice < 1 || numprice > 1000) { cb.sendNotice('The value entered for the new Dice Roll price is outside allowable values from 1 to 1000, please try again.', u, green); } else { diceRollPrice = numprice; priceChecker('add','Dice Roll Price', diceRollPrice,u); cb.sendNotice(u + ' has updated the Dice Roll Price.', u, green); cb.sendNotice('The Dice Roll Price has been updated to ' + numprice + ' tokens.', '', diceNoticeBg, diceTextColor, 'bold'); } } else { cb.sendNotice('The Dice Game has not been turned on, you can use the command "/usedice on" to enable it.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //********* Time Locked Gray Chat commands case '/usegraylock': { cmd = 1; if (isMod || isBC) { setGrayLockToggle(message[1], u); } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/cleargraylock': { cmd = 1; if (isMod || isBC) { if (grayLockToggle == 1) { clearGrayLock(u); } else { cb.sendNotice('The Gray Chat Time Lock has not been turned on, you can use the command "/usegraylock on" to enable it. Note the current Gray Chat Time Threshold is ' + grayChatTime + ' minutes.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/rmvgraylock': { cmd = 1; if (isMod || isBC) { if (grayLockToggle == 1) { if (!cbjs.arrayContains(grayLockList,u)) { addToLockList(u,isBC,isMod,isFan,isGray); } addRmvGrayLock('r',message[1], u); } else { cb.sendNotice('The Gray Chat Time Lock has not been turned on, you can use the command "/usegraylock on" to enable it. Note the current Gray Chat Time Threshold is ' + grayChatTime + ' minutes.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/addgraylock': { cmd = 1; if (isMod || isBC) { if (grayLockToggle == 1) { if (!cbjs.arrayContains(grayLockList,u)) { addToLockList(u,isBC,isMod,isFan,isGray); } addRmvGrayLock('a',message[1], u); } else { cb.sendNotice('The Gray Chat Time Lock has not been turned on, you can use the command "/usegraylock on" to enable it. Note the current Gray Chat Time Threshold is ' + grayChatTime + ' minutes.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/chggraytime': { cmd = 1; if (isMod || isBC) { if (grayLockToggle == 1) { nummin = parseInt(message[1]); if (isNaN(nummin)) { cb.sendNotice('The value entered for the new Gray Chat Time Threshold is not numeric, please try again.', u, green); } else if (nummin < 1 || nummin > 20) { cb.sendNotice('The value entered for the new Gray Chat Time Threshold is outside allowable values from 1 to 20, please try again.', u, green); } else { grayChatTime = nummin; cb.sendNotice('You have updated the Gray Chat Time Threshold to ' + grayChatTime + ' minutes.', u, green); } } else { cb.sendNotice('The Gray Chat Time Lock has not been turned on, you can use the command "/usegraylock on" to enable it. Note the current Gray Chat Time Threshold is ' + grayChatTime + ' minutes.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //********* "Answer Required" Chat Lock commands case '/useanswerlock': { cmd = 1; if (isMod || isBC) { if (message[1] == 'on' || message[1] == 'off') { setRequireAnswerToggle(message[1], u); } else { cb.sendNotice('Invalid parameter for the /useanswerlock command, valid values are "on" and "off".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/clearanswerlock': { cmd = 1; if (isMod || isBC) { if (requireAnswerToggle == 1) { clearAnswerLock(); cb.sendNotice('You have cleared the "Answer Required" chat restriction list. The list will be rebuilt as users chat or enter the room.', u, green); } else { cb.sendNotice('The "Answer Required" Chat Lock has not been enabled, you can use the command "/useanswerlock on" to enable it. Note the current Answer Lock Level is ' + requireAnswerLevelText + '.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/setanswerlevel': { cmd = 1; if (isMod || isBC) { if (requireAnswerToggle == 1) { numlevel = parseInt(message[1]); if (isNaN(numlevel)) { cb.sendNotice('The value entered for the new "Answer Required" level is not numeric, please try again.', u, green); } else if (numlevel < 0 || numlevel > 5) { cb.sendNotice('The value entered for the new "Answer Required" level is outside allowable values from 0 to 5, please try again (0=Not Used,1=Gray,2=Light Blue,3=Dark Blue,4=Light Purple,5=Dark Purple).', u, green); } else { requireAnswerLevel = numlevel; if (requireAnswerLevel == 0) { setRequireAnswerToggle('off',u); } else if (requireAnswerLevel == 1) { requireAnswerLevelText = 'Gray Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 1=Gray Users.', u, green); } else if (requireAnswerLevel == 2) { requireAnswerLevelText = 'Light Blue Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 2=Light Blue Users.', u, green); } else if (requireAnswerLevel == 3) { requireAnswerLevelText = 'Dark Blue Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 3=Dark Blue Users.', u, green); } else if (requireAnswerLevel == 4) { requireAnswerLevelText = 'Light Purple Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 4=Light Purple Users.', u, green); } else if (requireAnswerLevel == 5) { requireAnswerLevelText = 'Dark Purple Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 5=Dark Purple Users.', u, green); } } } else { cb.sendNotice('The "Answer Required" Chat Lock has not been enabled, you can use the command "/useanswerlock on" to enable it. Note the current Answer Lock Level is ' + requireAnswerLevelText + '.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //********* Fembot Hidden Ticket Show Commands case '/tickets': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { var ticketlist = cb.limitCam_allUsersWithAccess(); if (ticketlist.length > 0) { if (message[1] === 'a' || message[1] === 'A' || message[1] === 'alpha') { ticketlist.sort(); cb.sendNotice('Alphabetic listing of users currently with access to the Hidden Ticket Show : \n' + cbjs.arrayJoin(ticketlist, ', ') + '\nEnd of List', u, green); } else { cb.sendNotice('Users currently with access to the Hidden Ticket Show, in order of when added (use the "alpha" qualifier for a sorted list): \n' + cbjs.arrayJoin(ticketlist, ', ') + '\nEnd of List', u, green); } } else { cb.sendNotice('No ticket buyers yet.', u, green); } } break; } case '/useshow': case '/useticketshow': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,green); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (ticketPrice > 0) { if(message[1] != null && message[1] != 'on' && message[1] != 'off') { cb.sendNotice('The value ' + message[1] + ' is not a valid option for /useticketshow, please try again.',u,green); } else if(message[1] == null) { cb.sendNotice('You did not enter a valid option for /useticketshow, please try again.',u,green); } else { setTicketShowToggle(message[1], u, ticketPrice); } } else { cb.sendNotice('Unable to start Fembot Ticket Show feature, a ticket show price must be set first using the command "/ticketprice [amt]" where [amt] is the price.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('This command is only valid when you have set the ticket show type in the Fembot to "Fembot Ticket Show". Since the show type is set to "Separate Ticket App", it is expected you are using an app like Dorothy\'s UltraApp or Dorothy\'s Ticket Show or CrazyTicket for the actual show.', u, green); } } break; } case '/chgticketshow': { cmd = 1; if (isMod || isBC) { if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,green); } else { if (message[1]) { if (ticketShowType == 'Fembot Ticket Show' && (message[1] == 'fembot' || message[1] == 'Fembot')) { cb.sendNotice('The ticket show type is already set to use the Fembot ticket feature, and not a separate ticket App.', u, green); } else if (ticketShowType == 'Separate Ticket App' && (message[1] == 'other' || message[1] == 'other')) { cb.sendNotice('The ticket show type is already set to use a separate ticket App, and not the Fembot.', u, green); } else { if (message[1] == 'fembot' || message[1] == 'Fembot') { ticketShowType = 'Fembot Ticket Show'; cb.sendNotice('The ticket show type has been updated to Fembot Ticket Show.', u, green); } else if (message[1] == 'other' || message[1] == 'Other') { ticketShowType = 'Separate Ticket App'; if (cb.limitCam_isRunning()) { cb.limitCam_stop(); cb.sendNotice('The Fembot Hidden Show has been disabled', u, green, '', 'bold'); hiddenTime = 0; ticketSkipNotice = true; ticketShowEnded = true; ticketSalesEnded = true; showStage = ''; } cb.sendNotice('The ticket show type has been updated to Separate Ticket App. Ticket Sales will no longer be made in the Fembot. If a hidden show was already underway, the Fembot control of the hidden show has ended.', u, green); } } } else { cb.sendNotice('A parameter is required for this command, either "fembot" or "other", to indicate which app or bot is managing the ticket show. If changing to use a separate ticket app, use "other", if changing to use the Fembot, use "fembot".', u, green); } } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/useot': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (isMod || isBC) { if(message[1] != null && message[1] != 'on' && message[1] != 'off') { cb.sendNotice('The value ' + message[1] + ' is not a valid option for /useot, please try again.',u,green); } else if(message[1] == null) { cb.sendNotice('You did not enter a valid option for /useot, please try again.',u,green); } else { setTicketShowOtToggle(message[1], u); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('The Ticket Show feature is disabled.', u, green); } } break; } case "/otlist": { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowOtToggle == 1) { cb.sendNotice('Users currently on the Outstanding Ticket List: ' + outstandingTicketArray.length, u, green); cb.sendNotice((outstandingTicketArray.length > 0 == true ? cbjs.arrayJoin(outstandingTicketArray, ', ') : 'No outstanding ticket holders.'), u); cb.sendNotice('End of List', u, green); } else { cb.sendNotice('The Ticket Show Outstanding Ticket feature is disabled.', u, green); } break; } } case "/otchanges": { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (isMod || isBC) { if (otChangesArray.name.length > 0) { cb.sendNotice('Listing of Changes to the Outstanding Ticket List : ', u, green); outString = ""; for (var i = 0; i < otChangesArray.name.length; i++) { if (otChangesArray.name[i] == null) { break } else { outString += (i > 0 ? "," : "") + otChangesArray.name[i] + "(" + otChangesArray.type[i] + ")"; } } cb.sendNotice(outString, u); cb.sendNotice('End of List', u, green); } else { cb.sendNotice('No entries have been added to the Outstanding Ticket Change list.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('The Ticket Show feature is disabled.', u, green); } } break; } case '/ctprice': case '/chgticketprice': case '/ticketprice': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { numprice = parseInt(message[1]) if (isNaN(numprice)) { cb.sendNotice('The value entered for the ticket price is not numeric, please try again.', u, green); break; } else if (numprice < 1 || numprice > 1000) { cb.sendNotice('The value entered for the ticket price is outside allowable values from 1 to 500, please try again.', u, green); } else { if (ticketShowToggle == 1) { setTicketPrice(numprice,u,'yes'); cb.sendNotice('The Fembot Ticket Show price has been updated to ' + numprice + ' tokens, all tips of at least this amount will add a user to the Ticket Show List. You can view the ticket list with the command "/tickets".', u, green); } else { ticketPrice = numprice; cb.sendNotice('The Ticket Price has been set to ' + numprice + ' tokens, and the ticket show feature can now be started with the command "/useticketshow on". ', u, green); } } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { if (isMod || isBC) { numprice = parseInt(message[1]) if (!isNaN(numprice) && backupToggle == 1) { setBackupTicketPrice(numprice,u); } } } break; } case '/starttickettimer': case '/ticketstarttimer': case '/starttimer': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (isMod || isBC) { numtimer = parseInt(message[1]) if(isNaN(numtimer)) { cb.sendNotice('The value entered for the minutes to use for the timer is not numeric, please try again.', u, green); break; } else if(numtimer < 1 || numtimer > 120) { cb.sendNotice('The value entered for the minutes to use for the ticket show timer is outside allowable values from 1 to 120 (up to 2 hrs), please try again.', u, green); } else { ticketMinsRemain = numtimer; ticketStartMode = 'timer'; ticketAutoTimer(ticketMinsRemain); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.', u, green); } } break; } case '/addtickettime': case '/ticketaddtime': case '/addtime': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (isMod || isBC) { numtimer = parseInt(message[1]) if(isNaN(numtimer)) { cb.sendNotice('The value entered for the minutes to add to the ticket show start timer is not numeric, please try again.', u, green); } else if(numtimer < -60 || numtimer > 60) { cb.sendNotice('The value entered for the minutes to add to the ticket show start timer is outside allowable values from -60 to 60, please try again. Negative numbers can be used to subtract time.', u, green); } else if(numtimer == 0) { cb.sendNotice('Cannot add zero time.', u, green); } else if(numtimer < 0 && Math.abs(numtimer) > ticketMinsRemain) { cb.sendNotice('The value entered for the minutes to subtract is greater than the remaining time on the timer, please try again. Negative numbers can be used to subtract time.', u, green); } else { ticketAddTime(numtimer, u); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.', u, green); } } break; } case '/ticketstoptime': case '/ticketstoptimer': case '/stoptimer': { cmd = 1; if (ticketShowToggle == 1) { if (isMod || isBC) { if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { stopTicketTimer(u); } else { cb.sendNotice('A ticket timer is not currently running.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.', u, green); } break; } case '/add': case '/addticket': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use the /add or /addticket commands while a private show is running.', u,green); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isBC || (isMod && cb.settings.hiddenShowModsAdd == 'Yes')) { if (ticketShowToggle == 1) { if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice('Adding multiple users to the ticket show list.', u, green); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { if (!cb.limitCam_userHasAccess(cmdvalsplit[i])) { addRmvTicket('add', cmdvalsplit[i]); cb.sendNotice('Added ' + cmdvalsplit[i] + ' to the ticket show list.', u); cb.sendNotice(u + ' has added you to the ticket show list.', cmdvalsplit[i], green); } else { cb.sendNotice(cmdvalsplit[i] + ' is already on the ticket show list. Skipping.', u); } } } cb.sendNotice('All users were added and notified.', u, green) cb.sendNotice(u + ' has added multiple users to the ticket show list.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), '', green, '', 'normal', 'red'); } else { if (!cb.limitCam_userHasAccess(message[1])) { addRmvTicket('add', message[1]); } else { cb.sendNotice('Note: User ' + message[1] + ' is already in the Ticket Show List.',u,green); } } } else { if (!cb.limitCam_userHasAccess(u)) { addRmvTicket('add', u); } else { cb.sendNotice('Note: User ' + u + ' is already in the Ticket Show List.',u,green); } } } else { cb.sendNotice('Note: User not added to ticket list, the Hidden Ticket Show feature is disabled.',u,green); } } else { cb.sendNotice('You do not have authority to use the /addticket command.',u,green); } } else { if (backupToggle == 1) { if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice('Adding multiple users to the Backup Ticket List.', u, green); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { if (!cbjs.arrayContains(niceListArray, cmdvalsplit[i])) { addRmvTicketBackupList('add',cmdvalsplit[i]); cb.sendNotice('User ' + cmdvalsplit[i] + ' has been added to the Backup Ticket List.', u, green); cb.sendNotice(u + ' has added you to the Backup Ticket List.', cmdvalsplit[i], green); } else { cb.sendNotice(cmdvalsplit[i] + ' is already on the Backup Ticket List. Skipping.', u); } } } cb.sendNotice('All users were added and notified.', u, green) cb.sendNotice(u + ' has added multiple users to the Backup Ticket List.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), '', green, '', 'normal', 'red'); } else { var cmdvalsingle = message[1]; addRmvTicketBackupList('add',cmdvalsingle); cb.sendNotice('User ' + cmdvalsingle + ' has been added to the Backup Ticket List.', u, green); } } else { addRmvTicketBackupList('add',u); cb.sendNotice('User ' + u + ' has been added to the Backup Ticket List.', u, green); } } else { cb.sendNotice('Note: User not added to backup ticket list, the Backup List is disabled.', u,green); } } } break; } case '/del': case '/delticket': case '/rmvticket': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isBC || isMod) { if (ticketShowToggle == 1) { if(message[1] != '' && message[1] != null) { if (cb.limitCam_userHasAccess(message[1])) { addRmvTicket('rmv', message[1]); cb.sendNotice('User ' + message[1] + ' has been removed from the Ticket Show List.', '', ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice('Note: User is not in the Ticket Show List.',u,green); } } else { cb.sendNotice('No user was specified for the /rmvticket command.',u,green); } } else { cb.sendNotice('The Hidden Ticket Show feature is disabled.',u,green); } } else { cb.sendNotice('You do not have authority to use the /rmvticket command.',u,green); } } else { if (isMod || isBC) { if (backupToggle == 1) { addRmvTicketBackupList('rmv', message[1]); cb.sendNotice('User ' + message[1] + ' has been removed from the Backup Ticket List.', u, green); } } } break; } case '/giftticket': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,green); } else { if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (cb.settings.hiddenShowAllowGift == 'Yes') { if (cbjs.arrayContains(ticketShowExtraTickets.name,u)) { index = ticketShowExtraTickets.name.indexOf(u); if (ticketShowExtraTickets.count[index] > 0) { giftTicket(u,message[1]); ticketShowExtraTickets.count[index]--; cb.sendNotice('You have gifted a ticket to ' + message[1] + '. Thank you for your generosity.',u,green,'','bold'); cb.sendNotice('Mods: ' + u + ' has gifted a ticket to ' + message[1] + '.','',green,'','','red'); cb.sendNotice('Broadcaster: ' + u + ' has gifted a ticket to ' + message[1] + '.',BC,green); } else { cb.sendNotice('Sorry, you do not have any extra tickets remaining.',u,green); } } else { cb.sendNotice('Sorry, you have not purchased any extra tickets.',u,green); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the use of gifting tickets for this show.',u,green); } } else { cb.sendNotice('The Hidden Ticket Show feature is not currently active.',u,green); } } } break; } case '/givemyticketto': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,green); } else { if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (cb.settings.hiddenShowAllowGift == 'Yes') { if (cb.limitCam_userHasAccess(u) && showStage == 'ticketsales') { giveAwayTicket(u,message[1]); cb.sendNotice('You have gifted your ticket to ' + message[1] + '. You will now be removed from the show. Thank you for your generosity.',u,green,'','bold'); cb.sendNotice('Mods/Broadcaster: ' + u + ' has gifted their own ticket to ' + message[1] + '.','',green,'','','red'); } else { cb.sendNotice('Sorry, you do not have a ticket purchased or the show has already started.',u,green); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the gifting of tickets for this show.',u,green); } } else { cb.sendNotice('The Hidden Ticket Show feature is not currently active.',u,green); } } } break; } case '/chgticketmode': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (ticketShowToggle == 1) { newTicketMode = message[1].toLowerCase(); if (newTicketMode != 'manual' && newTicketMode != 'timer' && newTicketMode != 'ticketgoal' && newTicketMode != 'tokengoal') { cb.sendNotice('The value entered for the new mode is not valid, please try again using a value of "manual", "timer", "ticketgoal", or "tokengoal".', u, green); } else { if (newTicketMode === ticketStartMode) { cb.sendNotice('The value entered for the new mode is the same as the existing mode, command ignored.', u, green); } else { setTicketMode(newTicketMode,u); } } } else { cb.sendNotice('The Hidden Ticket Show feature is disabled.',u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } break; } case '/chgtktauto': case '/chgticketmodeauto': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (ticketShowToggle == 1) { newTicketAuto = message[1].toLowerCase(); if (newTicketAuto != 'bc' && newTicketAuto != 'auto') { cb.sendNotice('The value entered for the new mode is not valid, please try again using a value of "bc" or "auto".', u, green); } else if (newTicketAuto === 'auto' && ticketStartMode === 'manual') { cb.sendNotice('The mode cannot be changed to "auto" unless there is a goal or timer being used to define when the show will start. Show is currently to be started at broadcaster discretion.', u, green); } else if (newTicketAuto === ticketModeAuto) { cb.sendNotice('The value entered for the new mode is the same as the existing mode, command ignored.', u, green); } else { setTicketAuto(newTicketAuto); if (newTicketAuto === 'bc') { cb.sendNotice('You have updated the ticket show starting mode from automatic to requiring command entry from the broadcaster or moderator.', u, green); } else if (newTicketAuto === 'bc') { cb.sendNotice('You have updated the ticket show starting mode to automatic, the show will start when the goal is met or the timer expires.', u, green); } } } else { cb.sendNotice('The Hidden Ticket Show feature is disabled.',u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } break; } case '/tickettimeleft': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (ticketMinsRemain >= 1 || ticketSecsRemain >= 1) { cb.sendNotice(ticketTimeLeft(), "", yellow, "", "bold"); } else { cb.sendNotice('A Hidden Ticket Show timer is not running.', u, green); } } else { cb.sendNotice('The Hidden Ticket Show feature is disabled.',u,green); } } break; } case '/showtime': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (cb.limitCam_isRunning()) { getShowTime(u); } else { cb.sendNotice('The ticket show is not running, it has not yet started or already finished.', u, green); } } else { cb.sendNotice('The Hidden Ticket Show feature is disabled.',u,green); } } break; } case '/useticket': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,green); } else { if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (cb.settings.enableHiddenShowOT == 'Yes') { if (!cb.limitCam_userHasAccess(u) && cbjs.arrayContains(outstandingTicketArray,u)) { useTicket(u); cb.sendNotice('Your outstanding ticket has been redeemed and you have been added to the ticket holders list for this show.',u,green,'','bold'); cb.sendNotice('Broadcaster: ' + u + ' has used their outstanding ticket. They should be removed from the permanent OT list on the bot start page.',BC,green); cb.sendNotice('Mods: ' + u + ' has used their outstanding ticket. The broadcaster has been notified to remove them from the permanent OT list on the bot start page.','',green,'','','red'); } else { cb.sendNotice('Sorry, you have no outstanding ticket available.',u,green); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the use of outstanding tickets for this show.',u,green); } } else { cb.sendNotice('The Hidden Ticket Show feature is not currently active.',u,green); } } } break; } case '/saveticket': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (cb.settings.enableHiddenShowOT == 'Yes') { if (cb.limitCam_userHasAccess(u) && showStage == 'ticketsales') { saveTicket(u); cb.sendNotice('Your ticket from this show has been saved and you have been removed from the ticket list for this show.',u,green,'','bold'); cb.sendNotice('Broadcaster: ' + u + ' has saved their ticket from this show to the outstanding ticket list. They should be added from the permanent OT list on the bot start page upon next restart.',BC,green); cb.sendNotice('Mods: ' + u + ' has saved their ticket from this show to the outstanding ticket list. The broadcaster has been notified to add them to the permanent OT list on the bot start page.','',green,'','','red'); } else { cb.sendNotice('Sorry, you have no ticket purchase to save, or the show has already started.',u,green); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the ability to save an outstanding tickets for this show.',u,green); } } else { cb.sendNotice('The Hidden Ticket Show feature is not currently active.',u,green); } } break; } case '/addot': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (cb.settings.enableHiddenShowOT == 'Yes') { if (isBC || (isMod && cb.settings.hiddenShowModsAdd === 'Yes')) { if (ticketShowToggle == 1) { if(message[1] != '' && message[1] != null) { if (!cbjs.arrayContains(outstandingTicketArray,message[1])) { addRmvOutstandingTicket("add", message[1]); cb.sendNotice('User ' + message[1] + ' has been added to the Outstanding Ticket List.', u, green); } else { cb.sendNotice('Cannot add, user is already in the Outstanding Ticket List.',u,green); } } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.',u,green); } } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the outstanding ticket show feature.',u,green); } } break; } case '/rmvot': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (ticketShowToggle == 1) { if(message[1] != '' && message[1] != null) { if (cbjs.arrayContains(outstandingTicketArray,message[1])) { addRmvOutstandingTicket("rmv", message[1]); cb.sendNotice('User ' + message[1] + ' has been removed from the Outstanding Ticket List.', u, green); } else { cb.sendNotice('Cannot remove, user is not in the Outstanding Ticket List.',u,green); } } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.',u,green); } } } break; } case '/startshow': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,green); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (ticketShowToggle == 1) { if (!cb.limitCam_isRunning() && ticketShowEnded === false) { startTicketShow(u); if (presalesToggle == 1) { setPresalesToggle('off',u); } } else if (!cb.limitCam_isRunning() && ticketShowEnded === true) { cb.sendNotice('A Hidden Cam show was already started and stopped, please use the command "/restartshow" to resume the hidden show.', u, green); } else { cb.sendNotice('A Hidden Cam show is already underway.', u, green); } } else { cb.sendNotice('The Fembot ticket show has not been enabled.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { if (isMod || isBC) { if (tokenPollToggle == 1 && cb.settings.startPollTimerWithShow == 'Yes, switch to timed poll at show start') { if (pollRunning && pollType == 'Timer' && (pollMinsRemain > 0 || pollSecsRemain > 0)) { cb.sendNotice('Note: Poll timer not started with /startshow as it is already running. You can adjust the time remaining with the "/polladdtime [X]" command.', u, green); } else { timetoadd = parseInt(cb.settings.startPollMinAfterShow) if (timetoadd <= 0) { timetoadd = 10; cb.sendNotice('No setting defined for token poll end timer, defaulting to 10 min.', u, green); } pollSwitchToTimer(timetoadd, u); } } else { cb.sendNotice('Note: Poll Timer not started with /startshow per configuration.', u,green); } if (presalesToggle == 1) { setPresalesToggle('off',u); } } } } break; } case '/showover': case '/showwarn': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,green); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (cb.limitCam_isRunning()) { if (showStage == 'ticketshow') { warnShowEnding(u); } else { cb.sendNotice('The /showwarn or /showover command is used for a first warning. The show has already progressed past the point this command should be used. To end the show and return to a public broadcast, use the /stopshow command.', u, green); } } else { cb.sendNotice('The Hidden Cam show has not been started or has already ended.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } } break; } case '/showend': case '/stopsales': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,green); } else { if (ticketShowType === 'Fembot Ticket Show') { if (isMod || isBC) { if (cb.limitCam_isRunning()) { if (cb.settings.endPosMenuWithShow == 'Yes' && posTipMenuToggle == 1) { setPosTipMenuToggle('off', u); } stopTicketSales(u); } else { cb.sendNotice('The Hidden Cam show has not been started or has already ended.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { if (isMod || isBC) { if (cb.settings.endPosMenuWithShow == 'Yes' && posTipMenuToggle == 1) { setPosTipMenuToggle('off', u); } } } } break; } case '/stopshow': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,green); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (cb.limitCam_isRunning()) { if (cb.settings.endPosMenuWithShow == 'Yes' && posTipMenuToggle == 1) { setPosTipMenuToggle('off', u); } stopTicketShow(u); } else { cb.sendNotice('The Hidden Cam show has not been started or has already ended.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { if (isMod || isBC) { if (cb.settings.endPosMenuWithShow == 'Yes' && posTipMenuToggle == 1) { setPosTipMenuToggle('off', u); } } } } break; } case '/ticketsubject': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { ticketSubjectText = msg['m'].substring(15).trim(); if(ticketSubjectText != '' && ticketSubjectText != null) { changeTicketShowSubject(); } else { cb.sendNotice('No value was specified for the new room description.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } break; } case '/ctsubject': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { ticketSubjectText = msg['m'].substring(11).trim(); if(ticketSubjectText != '' && ticketSubjectText != null) { changeTicketShowSubject(); } else { cb.sendNotice('No value was specified for the new room description.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } break; } case '/newticketshow': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,green); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (!cb.limitCam_isRunning()) { ticketlist = cb.limitCam_allUsersWithAccess(); if (ticketlist.length > 0) { cb.sendNotice('In case the ticket show was reset by mistake, the previous ticket list is displayed below so they can be added back to the show using the /addticket command : ', cb.room_slug, green); cb.sendNotice(cbjs.arrayJoin(ticketlist, ', '), cb.room_slug); cb.sendNotice('End of List', cb.room_slug, green); if (isMod) { cb.sendNotice('In case the ticket show was reset by mistake, the previous ticket list is displayed below so they can be added back to the show using the /addticket command : ', u, green); cb.sendNotice(cbjs.arrayJoin(ticketlist, ', '), u); cb.sendNotice('End of List', u, green); } } else { cb.sendNotice('No ticket buyers in the previous ticket list.', u, green); } initTicketShow(u,ticketPrice); cb.limitCam_removeAllUsers(); while (ticketShowViewerList.length > 0) viewerList.pop(); } else { cb.sendNotice('A Hidden Cam show is still running. The /newticketshow command can be used to start a brand new ticket show. The ticket list is cleared but the outstanding ticket list and changes list remains intact.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } } break; } case '/restartshow': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,green); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isMod || isBC) { if (!cb.limitCam_isRunning()) { restartTicketShow(u); } else { cb.sendNotice('A Hidden Cam show is already running. The /restartshow command can be used to resume a hidden show that was ended prematurely or accidentally. All settings remain the same and the ticket list stays intact.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } } break; } //********* Raffle commands case '/useraffle': { cmd = 1; if (isMod || isBC) { if(message[1] == null || message[1] == '') { cb.sendNotice('You did not enter a valid option for /useraffle, the option should be "on" or "off".', u, green); } else if (message[1] != 'on' && message[1] != 'off') { cb.sendNotice(message[1] + ' is not a valid option for /useraffle, the option should be "on" or "off".', u, green); } else { setRaffleToggle(message[1], u); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case "/resetraffle": case "/clearraffle": { cmd = 1; if (isBC) { if (raffleToggle == 1) { clearRaffleEntries('all',u); } else { cb.sendNotice('The Raffle feature has not been turned on, you can use the command "/useraffle on" to enable it.', u, green); } } else { cb.sendNotice('Only broadcasters are able to use that command.', u, green); } break; } case '/addraffletkt': { cmd = 1; if (isBC) { if (raffleToggle == 1) { level = parseInt(message[1]); adduser = message[2]; if (isNaN(level)) { cb.sendNotice('The value entered for the Level is not numeric, please try again. The syntax for this command is "/addraffletkt [level] [user]" and both level and user must be populated, and level must be from 1-5.', u, green); } else if (level < 1 || level > 500) { cb.sendNotice('The value entered for the Level is outside allowable values from 1 to 5, please try again. The syntax for this command is "/addraffletkt [level] [user]" and both level and user must be populated, and level must be from 1-5.', u, green); } else if (!message[2]) { cb.sendNotice('The value for user was not provided, please try again. The syntax for this command is "/addraffletkt [level] [user]" and both level and user must be populated, and level must be from 1-5.', u, green); } else { raffleTicketPurchase(level,adduser,0); cb.sendNotice('One level ' + level + ' raffle ticket added for ' + adduser + '.', u, green); } } else { cb.sendNotice('The raffle is not enabled, you can use the command "/useraffle on" to enable it.', u, green); } } else { cb.sendNotice('Only broadcasters are able to use that command.', u, green); } break; } case '/rmvraffletkt': { cmd = 1; if (isBC) { if (raffleToggle == 1) { level = parseInt(message[1]); rmvuser = message[2]; if (isNaN(level)) { cb.sendNotice('The value entered for the Level is not numeric, please try again. The syntax for this command is "/rmvraffletkt [level] [user]" and both level and user must be populated, and level must be from 1-5.', u, green); } else if (level < 1 || level > 500) { cb.sendNotice('The value entered for the Level is outside allowable values from 1 to 5, please try again. The syntax for this command is "/rmvraffletkt [level] [user]" and both level and user must be populated, and level must be from 1-5.', u, green); } else if (!message[2]) { cb.sendNotice('The value for user was not provided, please try again. The syntax for this command is "/rmvraffletkt [level] [user]" and both level and user must be populated, and level must be from 1-5.', u, green); } else { removeTicket(level,rmvuser); cb.sendNotice('One level ' + level + ' raffle ticket removed for ' + rmvuser + '.', u, green); } } else { cb.sendNotice('The raffle is not enabled, you can use the command "/useraffle on" to enable it.', u, green); } } else { cb.sendNotice('Only broadcasters are able to use that command.', u, green); } break; } case '/setraffleprice': { cmd = 1; if (isMod || isBC) { level = parseInt(message[1]); numtokens = parseInt(message[2]); if (isNaN(level) || level < 1 || level > 5) { cb.sendNotice('The first parameter is the level and must be a number between 1 and 5. For example, use "/setraffleprice 2 18" to change the price of raffle level 2 ticket to 18 tokens.', u, green); } else if (isNaN(numtokens) || numtokens < 1 || numtokens > 500) { cb.sendNotice('The value entered for the new Level ' + level + ' Raffle Ticket Price is outside allowable values from 1 to 500, please try again. For example, use "/setraffleprice 2 18" to change the price of raffle level 2 ticket to 18 tokens.', u, green); } else { rafflePrice[level] = numtokens; priceChecker('add','Raffle Price ' + level,rafflePrice[level]); cb.sendNotice('You have updated the Level ' + level + ' Raffle Ticket Price to ' + numtokens + ' tokens.', u, green); cb.sendNotice(u + ' updated the raffle price for Level ' + commandVar1 + ' to ' + numtokens + '.', '', green, '', '', 'red'); cb.sendNotice(u + ' updated the raffle price for Level ' + commandVar1 + ' to ' + numtokens + '.', cb.room_slug, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/addraffleprize': { cmd = 1; if (isMod || isBC) { if (isNaN(commandVar1) || commandVar1 < 1 || commandVar1 > 5) { cb.sendNotice('The first parameter is the level and must be a number between 1 and 5. For example, "/addraffleprize 2 Free Video" to add a level 2 raffle prize of a free video', u, green); } else if (!rafflePrice[commandVar1] > 0) { cb.sendNotice('The level ' + commandVar1 + ' raffle price has not yet been set, please set the price first using the command "/setraffleprice ' + commandVar1 + ' [amt]"', u, green); } else if (!message[2]) { cb.sendNotice('The second parameter is the description of prize being added (can be multiple words) and is required. For example, "/addraffleprize 2 Free Video" to add a level 2 raffle prize of a free video', u, green); } else { for (let i = 2; i < message.length; i++) { if (i === 2) { label = message[i]; } else { label += " " + message[i]; } } switch (commandVar1) { case 1: { rafflePrizeList1.push(label); break; } case 2: { rafflePrizeList2.push(label); break; } case 3: { rafflePrizeList3.push(label); break; } case 4: { rafflePrizeList4.push(label); break; } case 5: { rafflePrizeList5.push(label); break; } cb.sendNotice('Raffle Prize "' + label + '" was added to Raffle Level ' + commandVar1 + '.', u, green); cb.sendNotice(u + ' added Raffle Prize "' + label + '" to Raffle Level ' + commandVar1 + '.', '', green, '', '', 'red'); cb.sendNotice(u + ' added Raffle Prize "' + label + '" to Raffle Level ' + commandVar1 + '.', cb.room_slug, green); } } } else { cb.sendNotice('Only broadcasters and moderators are able to use that command.', u, green); } break; } case '/rmvraffleprize': { cmd = 1; if (isMod || isBC) { if (isNaN(commandVar1) || commandVar1 < 1 || commandVar1 > 5) { cb.sendNotice('The first parameter is the level and must be a number between 1 and 5. For example, use "/rmvraffleprize 2 Free Video" to remove an existing level 2 raffle prize named "Free Video"', u, green); } else if (!message[2]) { cb.sendNotice('The second parameter is the description of prize being remove (must match the text of the prize being removed exactly) and is required. For example, use "/rmvraffleprize 2 Free Video" to remove an existing level 2 raffle prize named "Free Video"', u, green); } else { for (let i = 2; i < message.length; i++) { if (i === 2) { label = message[i]; } else { label += " " + message[i]; } } switch (commandVar1) { case 1: { let labelFound = false; for (let i = 0; i < rafflePrizeList1.length; i++) { if (label === rafflePrizeList1[i]) { labelFound = true; while (label === rafflePrizeList1[i]) { rafflePrizeList1.splice(i,1); cb.sendNotice('Raffle prize "' + label + '" was removed from Raffle Level ' + commandVar1 + '.', u, green); cb.sendNotice(u + ' removed Raffle Prize "' + label + '" from Raffle Level ' + commandVar1 + '.', '', green, '', '', 'red'); cb.sendNotice(u + ' removed Raffle Prize "' + label + '" from Raffle Level ' + commandVar1 + '.', cb.room_slug, green); } } } if (!labelFound) { cb.sendNotice('Unable find item "' + label + '" in the raffle list for level ' + commandVar1 + '.', u, green); } break; } case 2: { let labelFound = false; for (let i = 0; i < rafflePrizeList2.length; i++) { if (label === rafflePrizeList2[i]) { labelFound = true; while (label === rafflePrizeList1[i]) { rafflePrizeList1.splice(i,1); cb.sendNotice('Raffle prize "' + label + '" was removed from Raffle Level ' + commandVar1 + '.', u, green); cb.sendNotice(u + ' removed Raffle Prize "' + label + '" from Raffle Level ' + commandVar1 + '.', '', green, '', '', 'red'); cb.sendNotice(u + ' removed Raffle Prize "' + label + '" from Raffle Level ' + commandVar1 + '.', cb.room_slug, green); } } } if (!labelFound) { cb.sendNotice('Unable find item "' + label + '" in the raffle list for level ' + commandVar1 + '.', u, green); } break; } case 3: { let labelFound = false; for (let i = 0; i < rafflePrizeList3.length; i++) { if (label === rafflePrizeList3[i]) { labelFound = true; while (label === rafflePrizeList1[i]) { rafflePrizeList1.splice(i,1); cb.sendNotice('Raffle prize "' + label + '" was removed from Raffle Level ' + commandVar1 + '.', u, green); cb.sendNotice(u + ' removed Raffle Prize "' + label + '" from Raffle Level ' + commandVar1 + '.', '', green, '', '', 'red'); cb.sendNotice(u + ' removed Raffle Prize "' + label + '" from Raffle Level ' + commandVar1 + '.', cb.room_slug, green); } } } if (!labelFound) { cb.sendNotice('Unable find item "' + label + '" in the raffle list for level ' + commandVar1 + '.', u, green); } break; } case 4: { let labelFound = false; for (let i = 0; i < rafflePrizeList4.length; i++) { if (label === rafflePrizeList4[i]) { labelFound = true; while (label === rafflePrizeList1[i]) { rafflePrizeList1.splice(i,1); cb.sendNotice('Raffle prize "' + label + '" was removed from Raffle Level ' + commandVar1 + '.', u, green); cb.sendNotice(u + ' removed Raffle Prize "' + label + '" from Raffle Level ' + commandVar1 + '.', '', green, '', '', 'red'); cb.sendNotice(u + ' removed Raffle Prize "' + label + '" from Raffle Level ' + commandVar1 + '.', cb.room_slug, green); } } } if (!labelFound) { cb.sendNotice('Unable find item "' + label + '" in the raffle list for level ' + commandVar1 + '.', u, green); } break; } case 5: { let labelFound = false; for (let i = 0; i < rafflePrizeList5.length; i++) { if (label === rafflePrizeList5[i]) { labelFound = true; while (label === rafflePrizeList1[i]) { rafflePrizeList1.splice(i,1); cb.sendNotice('Raffle prize "' + label + '" was removed from Raffle Level ' + commandVar1 + '.', u, green); cb.sendNotice(u + ' removed Raffle Prize "' + label + '" from Raffle Level ' + commandVar1 + '.', '', green, '', '', 'red'); cb.sendNotice(u + ' removed Raffle Prize "' + label + '" from Raffle Level ' + commandVar1 + '.', cb.room_slug, green); } } } if (!labelFound) { cb.sendNotice('Unable find item "' + label + '" in the raffle list for level ' + commandVar1 + '.', u, green); } break; } } } } else { cb.sendNotice('Only broadcasters and moderators are able to use that command.', u, green); } break; } case "/entries": case "/raffletickets": case "/raffleentries": { cmd = 1; if (isMod || isBC) { if (raffleCurrentTicketsArray.name.length > 0) { displayEntries(u); } else { cb.sendNotice('No entries in the raffle yet.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case "/previousentries": { cmd = 1; if (isMod || isBC) { if (rafflePrevTicketsArray.name.length > 0) { cb.sendNotice('Listing of Previous Show Raffle entries : ', u, green); outString = ""; for (var i = 0; i < rafflePrevTicketsArray.name.length; i++) { if (rafflePrevTicketsArray.name[i] == null) { break } else { outString += (i > 0 ? "," : "") + rafflePrevTicketsArray.name[i] + ":" + rafflePrevTicketsArray.level[i]; } } cb.sendNotice(outString, u); cb.sendNotice('End of List', u, green); } else { cb.sendNotice('No previous entries were imported in the raffle.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case "/raffleprizes": { cmd = 1; outString = 'Listing of Raffle Prizes by Level : '; if (rafflePrizeList1.length > 0) { outString += '\nLevel 1 (ticket price = ' + rafflePrice[1] + ' tokens) -- ' + cbjs.arrayJoin(rafflePrizeList1, ', '); } else { outString += '\nNo prize(s) set up for level 1.'; } if (rafflePrizeList2.length > 0) { outString += '\nLevel 2 (ticket price = ' + rafflePrice[2] + ' tokens) -- ' + cbjs.arrayJoin(rafflePrizeList2, ', '); } else { outString += '\nNo prize(s) set up for level 2.'; } if (rafflePrizeList3.length > 0) { outString += '\nLevel 3 (ticket price = ' + rafflePrice[3] + ' tokens) -- ' + cbjs.arrayJoin(rafflePrizeList3, ', '); } else { outString += '\nNo prize(s) set up for level 3.'; } if (rafflePrizeList4.length > 0) { outString += '\nLevel 4 (ticket price = ' + rafflePrice[4] + ' tokens) -- ' + cbjs.arrayJoin(rafflePrizeList4, ', '); } else { outString += '\nNo prize(s) set up for level 4.'; } if (rafflePrizeList5.length > 0) { outString += '\nLevel 5 (ticket price = ' + rafflePrice[5] + ' tokens) -- ' + cbjs.arrayJoin(rafflePrizeList5, ', '); } else { outString += '\nNo prize(s) set up for level 5.'; } cb.sendNotice(outString, u, green); break; } case "/raffledrawing": { cmd = 1; if (isBC || (isMod && cb.settings.raffleModDrawing == 'Yes')) { if (message[1] == 'all' || message[1] == 'All') { selectAllRaffleWinners(u); } else if (parseInt(message[1]) >= 1 && parseInt(message[1]) <= 5) { selectSingleRaffleWinner(parseInt(message[1]),u); } else { cb.sendNotice('Invalid value entered for drawing, the value should be "all" for all levels, or a specific level number. For example "/raffledrawing all" or "/raffledrawing 1".', u, green); } } else { cb.sendNotice('Only broadcasters and moderators with privileges are able to use that command.', u, green); } break; } case '/rafflestarttimer': case '/startraffletimer': { cmd = 1; if (raffleToggle == 1) { if (isMod || isBC) { if (raffleEndMode == 'timer') { numtimer = parseInt(message[1]) if(isNaN(numtimer)) { cb.sendNotice('The value entered for the minutes to use for the raffle drawing timer is not numeric, please try again.', u, green); } else if(numtimer < 1 || numtimer > 120) { cb.sendNotice('The value entered for the minutes to use for the raffle drawing timer is outside allowable values from 1 to 120 (up to 2 hrs), please try again.', u, green); } else if(raffleMinsRemain > 0 || raffleSecsRemain > 0) { cb.sendNotice('A raffle timer is already running.', u, green); } else { raffleMinsRemain = numtimer; raffleAutoTimer(raffleMinsRemain); } } else { cb.sendNotice('Cannot start a timer unelss the end mode is "timer".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('The raffle feature is disabled.', u, green); } break; } case '/addraffletime': case '/raffleaddtime': { cmd = 1; if (raffleToggle == 1) { if (isMod || isBC) { if (raffleEndMode == 'timer') { numtimer = parseInt(message[1]); if (isNaN(numtimer)) { cb.sendNotice('The value entered for the minutes to add to the raffle drawing timer is not numeric, please try again.', u, green); break; } else if (numtimer < -60 || numtimer > 60) { cb.sendNotice('The value entered for the minutes to add to the raffle drawing timer is outside allowable values from -60 to 60, please try again. Negative numbers can be used to subtract time.', u, green); } else if (numtimer == 0) { cb.sendNotice('Cannot add zero time.', u, green); } else if (numtimer < 0 && Math.abs(numtimer) > raffleMinsRemain) { cb.sendNotice('The value entered for the minutes to subtract is greater than the remaining timeon the timer, please try again. Negative numbers can be used to subtract time.', u, green); } else { raffleAddTime(numtimer, u); } } else { cb.sendNotice('Cannot perform timer functions when end mode is not "timer".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('The raffle feature is disabled.', u, green); } break; } case '/rafflestoptimer': case '/stopraffletimer': { cmd = 1; if (raffleToggle == 1) { if (isMod || isBC) { if (raffleEndMode == 'timer') { stopRaffleTimer(u); } else { cb.sendNotice('Cannot perform timer functions when end mode is not "timer".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } } else { cb.sendNotice('The raffle feature is disabled.', u, green); } break; } case '/chgrafflemode': { cmd = 1; if (isMod || isBC) { if (raffleToggle == 1) { newRaffleEndMode = message[1].toLowerCase(); if (newRaffleEndMode != 'manual' && newRaffleEndMode != 'timer' && newRaffleEndMode != 'ticketgoal' && newRaffleEndMode != 'tokengoal') { cb.sendNotice('The value entered for the new mode is not valid, please try again using a value of "manual", "timer", "ticketgoal", or "tokengoal".', u, green); } else { if (newRaffleEndMode === raffleEndMode) { cb.sendNotice('The value entered for the new mode is the same as the existing mode, command ignored.', u, green); } else { setRaffleMode(newRaffleEndMode,u); } } } else { cb.sendNotice('The raffle feature is disabled.',u,green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/raffletimeleft': { cmd = 1; if (raffleToggle == 1) { if (raffleMinsRemain >= 1 || raffleSecsRemain >= 1) { cb.sendNotice(raffleTimeLeft(), "", yellow, "", "bold"); } else { cb.sendNotice('A raffle drawing timer is not running.', u, green); } } else { cb.sendNotice('The raffle feature is disabled.',u,green); } break; } //********* Price Check List case "/pricechecklist": { cmd = 1; if (isMod || isBC) { if (priceCheckArray.name.length > 0) { cb.sendNotice('Alphabetic listing of Price Check Array entries : ', u, green); var outString = ""; for (var i = 0; i < priceCheckArray.name.length; i++) { if (priceCheckArray.name[i] == null) outString += " " + i + ". empty" + "\n"; else outString += " " + i + ". " + '"' + priceCheckArray.name[i] + '"' + ": " + priceCheckArray.amount[i] + "\n"; } cb.sendNotice(outString,u); cb.sendNotice('End of List', u, green); } else { cb.sendNotice('No entries yet.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //********* Icon / Nicknames List case '/nnlist': { cmd = 1; if (isMod || isBC) { if (iconNicknamesArray.name.length > 0) { cb.sendNotice('Listing of Nickname entries : ', u, green); var outString = ''; for (var i = 0; i < iconNicknamesArray.name.length; i++) { if (iconNicknamesArray.name[i] == null) outString += ' ' + (i+1) + '. empty' + '\n'; else outString += ' ' + (i+1) + '. ' + iconNicknamesArray.name[i] + ' / "' + iconNicknamesArray.icon[i] + '" / ' + iconNicknamesArray.nickname[i] + ' / ' + iconNicknamesArray.color[i] + '\n'; } cb.sendNotice(outString,u); cb.sendNotice('End of List', u, green); } else { cb.sendNotice('No entries yet.', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/setusericon': { cmd = 1; if (isMod || isBC) { if (!message[1]) { cb.sendNotice('Parameter for user is not specified. Command syntax is /setusericon username :iconname', u, green); } else if (!message[2]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setusericon username :iconname', u, green); } else if (message[2].substring(0,1) != ':' && message[2] != 'null') { cb.sendNotice('Parameter for icon does not start with a ":" and is not "null". Command syntax is /setusericon username :iconname. The value of "null" can be used to remove an existing setting.', u, green); } else { if (cbjs.arrayContains(iconNicknamesArray.name,message[1])) { iconindex = iconNicknamesArray.name.indexOf(message[1]); if (message[2] == 'null') { iconNicknamesArray.icon[iconindex] = null; } else { iconNicknamesArray.icon[iconindex] = message[2]; } cb.sendNotice('The icon for user ' + message[1] + ' has been updated to ' + message[2] + '.', u, green); } else { iconNicknamesArray.name.push(message[1]); iconNicknamesArray.icon.push(message[2]); iconNicknamesArray.nickname.push(null); iconNicknamesArray.color.push(null); cb.sendNotice('An entry has been added for user ' + message[1] + ' with an icon of ' + message[2] + '.', u, green); } } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/setusernn': { cmd = 1; if (isMod || isBC) { if (!message[1]) { cb.sendNotice('Parameter for user is not specified. Command syntax is /setusernn username nickname', u, green); } else if (!message[2]) { cb.sendNotice('Parameter for nickname is not specified. Command syntax is /setusernn username nickname. The value of "null" can be used to remove an existing setting.', u, green); } else { if (cbjs.arrayContains(iconNicknamesArray.name,message[1])) { nnindex = iconNicknamesArray.name.indexOf(message[1]); if (message[2] == 'null') { iconNicknamesArray.nickname[nnindex] = null; } else { iconNicknamesArray.nickname[nnindex] = message[2]; } cb.sendNotice('The nickname for user ' + message[1] + ' has been updated to ' + message[2] + '.', u, green); } else { iconNicknamesArray.name.push(message[1]); iconNicknamesArray.icon.push(null); iconNicknamesArray.nickname.push(message[2]); iconNicknamesArray.color.push(null); cb.sendNotice('An entry has been added for user ' + message[1] + ' with a nickname of ' + message[2] + '.', u, green); } } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/setusercolor': { cmd = 1; if (isMod || isBC) { if (!message[1]) { cb.sendNotice('Parameter for user is not specified. Command syntax is /setusercolor username #000000, where 000000 is a valid hex color', u, green); } else if (!message[2]) { cb.sendNotice('Parameter for color is not specified. Command syntax is /setusercolor username #000000, where 000000 is a valid hex color', u, green); } else if (message[2].substring(0,1) != '#' && message[2] != 'null') { cb.sendNotice('Parameter for color does not start with a "#" and is not "null". Command syntax is /setusercolor username #000000, where 000000 is a valid hex color. The value of "null" can be used to remove an existing setting.', u, green); } else { if (cbjs.arrayContains(iconNicknamesArray.name,message[1])) { colorindex = iconNicknamesArray.name.indexOf(message[1]); if (message[2] == 'null') { iconNicknamesArray.color[colorindex] = null; } else { iconNicknamesArray.color[colorindex] = message[2]; } cb.sendNotice('The color for user ' + message[1] + ' has been updated to ' + message[2] + '.', u, green); } else { iconNicknamesArray.name.push(message[1]); iconNicknamesArray.icon.push(null); iconNicknamesArray.nickname.push(null); iconNicknamesArray.color.push(message[2]); cb.sendNotice('An entry has been added for user ' + message[1] + ' with an color of ' + message[2] + '.', u, green); } } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //********* All Time Tipper List case '/usealltime': { cmd = 1; if (isMod || isBC) { if(message[1] == null || message[1] == '') { cb.sendNotice('You did not enter a valid option for /usealltime, the option should be "on" or "off".', u, green); } else if (message[1] != 'on' && message[1] != 'off') { cb.sendNotice(message[1] + ' is not a valid option for /usealltime, the option should be "on" or "off".', u, green); } else { setAllTimeToggle(message[1], u); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } case '/dsptop10': case '/alltimetop10': case '/top10': { cmd = 1; if (allTimeToggle == 1) { buildAllTimeArray(); sendto = u; if (allTimeArray.name.length > 0) { if (isMod || isBC) { sendto = ''; } displayAllTimeTop10(sendto); } else { cb.sendNotice('There are no entries in the all-time tipper list.', u, green); } } else { cb.sendNotice('All Time Tippers are not being tracked. roadcasters and Moderators can enable this feature using the command "/usealltime on".', u, green); } break; } case '/listalltime': case '/alltimelist': case '/alltime': { cmd = 1; if (isMod || isBC) { if (allTimeToggle == 1) { buildAllTimeArray(); if (allTimeArray.name.length > 0) { displayAllTime(u); } else { cb.sendNotice('There are no entries in the all-time list.', u, green); } } else { cb.sendNotice('All Time Tippers are not being tracked. You can enable this feature using the command "/usealltime on".', u, green); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //********* On-demand Privates case '/startprivate': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,green); } else { if (isBC) { if(message[1] != '' && message[1] != null) { goPrivate(message[1]); } else { cb.sendNotice('No value was specified for the user name to take private.', u, green); } } else { cb.sendNotice('Only broadcasters are able to use that command.', u, green); } } break; } case '/endprivate': case '/stopprivate': { cmd = 1; if (!isPrivate) { cb.sendNotice('You are not able to use this command unless a private show is running.', u,green); } else { if (isBC) { stopPrivate(); } else { cb.sendNotice('Only broadcasters are able to use that command.', u, green); } } break; } //********* Suppress Caps Toggle case '/nocaps': { cmd = 1; if (isMod || isBC) { if(message[1] == null || message[1] == '') { cb.sendNotice('You did not enter a valid option for /nocaps, the option should be "on" or "off".', u, green); } else if (message[1] != 'on' && message[1] != 'off') { cb.sendNotice(message[1] + ' is not a valid option for /nocaps, the option should be "on" or "off".', u, green); } else { setCapsToggle(message[1], u); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, green); } break; } //********* Help Menu case '/fbhelp': { cmd = 1; if (isMod || isBC) { helpModBC(message[1],u); } else { helpCommon(message[1],u); } break; } //********* Dump config settings case '/settings': { cmd = 1; if (isMod || isBC) { if(message[1] == null){message[1] = '';} switch(message[1]) { case '': { cb.sendNotice( 'A parameter is required for settings, such as "/settings notices", please use one of the following: notices, leaders, chat, groups, tipmenu1, tipmenu2, positions, poll, tickets, toys, media, dice, or raffle.',u,green); break; } case 'notices': { cb.sendNotice( 'Dump of all current settings for notices:' + '\n**************** Notices Controls ************************' + '\nenableEntryMessage : ' + cb.settings.enableEntryMessage + '\nentryMessage : ' + cb.settings.entryMessage + '\nenableNotifier : ' + cb.settings.enableNotifier + '\nnotifierMessage1 : ' + cb.settings.notifierMessage1 + '\nnotifierMessage2 : ' + cb.settings.notifierMessage2 + '\nnotifierMessage3 : ' + cb.settings.notifierMessage3 + '\nnotifierMessage4 : ' + cb.settings.notifierMessage4 + '\nnotifierMessage5 : ' + cb.settings.notifierMessage5 + '\nnotifierInterval : ' + cb.settings.notifierInterval + '\nnotifiersTextColor : ' + cb.settings.notifiersTextColor + '\nnotifiersTextCustColor : ' + cb.settings.notifiersTextCustColor + '\nnotifiersBgColor : ' + cb.settings.notifiersBgColor + '\nnotifiersBgCustColor : ' + cb.settings.notifiersBgCustColor + '\nenableTipResponse : ' + cb.settings.enableTipResponse + '\ntipResponseAmount1 : ' + cb.settings.tipResponseAmount1 + '\ntipResponseMessage1 : ' + cb.settings.tipResponseMessage1 + '\ntipResponseAmount2 : ' + cb.settings.tipResponseAmount2 + '\ntipResponseMessage2 : ' + cb.settings.tipResponseMessage2 + '\ntipResponseAmount3 : ' + cb.settings.tipResponseAmount3 + '\ntipResponseMessage3 : ' + cb.settings.tipResponseMessage3 + '\ntipResponseAmount4 : ' + cb.settings.tipResponseAmount4 + '\ntipResponseMessage4 : ' + cb.settings.tipResponseMessage4 + '\ntipResponseAmount5 : ' + cb.settings.tipResponseAmount5 + '\ntipResponseMessage5 : ' + cb.settings.tipResponseMessage5 + '\ndefaultTimerDescription : ' + cb.settings.defaultTimerDescription,u); break; } case 'leaders': { cb.sendNotice( 'Dump of all current settings for tip leaders and leaderboard:' + '\n**************** Tip Leaders Controls ************************' + '\nenableSubjectChange : ' + cb.settings.enableSubjectChange + '\nenableTipCount : ' + cb.settings.enableTipCount + '\nenableTipLeaderIcons : ' + cb.settings.enableTipLeaderIcons + '\ntipLeaderGif1 : ' + cb.settings.tipLeaderGif1 + '\ntipLeaderGif2 : ' + cb.settings.tipLeaderGif2 + '\ntipLeaderGif3 : ' + cb.settings.tipLeaderGif3 + '\nenableLeaderboard : ' + cb.settings.enableLeaderboard + '\nleaderInterval : ' + cb.settings.leaderInterval + '\nleaderTextColor : ' + cb.settings.leaderTextColor + '\nleaderTextCustColor : ' + cb.settings.leaderTextCustColor + '\nleaderBgColor : ' + cb.settings.leaderBgColor + '\nleaderBgCustColor : ' + cb.settings.leaderBgCustColor + '\nenableAllTime : ' + cb.settings.enableAllTime + '\nallTimeInterval : ' + cb.settings.allTimeInterval + '\nallTimeTipperList : ' + cb.settings.allTimeTipperList,u); break; } case 'chat': { cb.sendNotice( 'Dump of all current settings for chat controls:' + '\n**************** Chat Controls ************************' + '\nsilenceList : ' + cb.settings.silenceList + '\nninjaList : ' + cb.settings.ninjaList + '\nniceList : ' + cb.settings.niceList + '\nenablePMs : ' + cb.settings.enablePMs + '\nlockGrayChat : ' + cb.settings.lockGrayChat + '\ngrayChatTime : ' + cb.settings.grayChatTime + '\n**************** Blocked Word List ********************' + '\nenableWordList : ' + cb.settings.enableWordList + '\nwordBlockList : **intentionally hidden**',u); break; } case 'groups': { cb.sendNotice( 'Dump of all current settings for user groups such as fan club and VIP:' + '\n**************** User Group Icons *********************' + '\nenableGroupIcons : ' + cb.settings.enableGroupIcons + '\niconMods : ' + cb.settings.iconMods + '\niconFans : ' + cb.settings.iconFans + '\niconExtFans : ' + cb.settings.iconExtFans + '\niconVIP : ' + cb.settings.iconVIP + '\niconNicknameList : ' + cb.settings.iconNicknameList + '\n******************** VIP List *************************' + '\nenableVIPList : ' + cb.settings.enableVIPList + '\nVIPList : ' + cb.settings.VIPList + '\nannounceVIP : ' + cb.settings.announceVIP + '\nannounceVIPtext : ' + cb.settings.announceVIPtext + '\n**************** External Fan Club ********************' + '\nenableExtFans : ' + cb.settings.enableExtFans + '\nextFanList : ' + cb.settings.extFanList + '\nannounceExtFans : ' + cb.settings.announceExtFans + '\nannounceExtFanstext : ' + cb.settings.announceExtFanstext,u); break; } case 'tipmenu1': { cb.sendNotice( 'Dump of all current settings for Tip Menu 1:' + '\n******************* Tip Menu 1 **************************' + '\nenableTipMenu : ' + cb.settings.enableTipMenu + '\nchatNotice : ' + cb.settings.chatNotice + '\nmenuDspInt : ' + cb.settings.menuDspInt + '\nlistSort : ' + cb.settings.listSort + '\nlistSplit : ' + cb.settings.listSplit + '\nsepchar : ' + cb.settings.sepchar + '\nsepcharcustom : ' + cb.settings.sepcharcustom + '\nmenutxtcolor1 : ' + cb.settings.menutxtcolor1 + '\nmenuCustTxtColor1 : ' + cb.settings.menuCustTxtColor1 + '\nmenubgcolor1 : ' + cb.settings.menubgcolor1 + '\nmenuCustBgColor1 : ' + cb.settings.menuCustBgColor1 + '\nmenutxtcolor2 : ' + cb.settings.menutxtcolor2 + '\nmenuCustTxtColor2 : ' + cb.settings.menuCustTxtColor2 + '\nmenubgcolor2 : ' + cb.settings.menubgcolor2 + '\nmenuCustBgColor2 : ' + cb.settings.menuCustBgColor2 + '\nmenuitem1 : ' + cb.settings.menuitem1 + '\nmenuitemprice1 : ' + cb.settings.menuitemprice1 + '\nmenuitem2 : ' + cb.settings.menuitem2 + '\nmenuitemprice2 : ' + cb.settings.menuitemprice2 + '\nmenuitem3 : ' + cb.settings.menuitem3 + '\nmenuitemprice3 : ' + cb.settings.menuitemprice3 + '\nmenuitem4 : ' + cb.settings.menuitem4 + '\nmenuitemprice4 : ' + cb.settings.menuitemprice4 + '\nmenuitem5 : ' + cb.settings.menuitem5 + '\nmenuitemprice5 : ' + cb.settings.menuitemprice5 + '\nmenuitem6 : ' + cb.settings.menuitem6 + '\nmenuitemprice6 : ' + cb.settings.menuitemprice6 + '\nmenuitem7 : ' + cb.settings.menuitem7 + '\nmenuitemprice7 : ' + cb.settings.menuitemprice7 + '\nmenuitem8 : ' + cb.settings.menuitem8 + '\nmenuitemprice8 : ' + cb.settings.menuitemprice8 + '\nmenuitem9 : ' + cb.settings.menuitem9 + '\nmenuitemprice9 : ' + cb.settings.menuitemprice9 + '\nmenuitem10 : ' + cb.settings.menuitem10 + '\nmenuitemprice10 : ' + cb.settings.menuitemprice10 + '\nmenuitem11 : ' + cb.settings.menuitem11 + '\nmenuitemprice11 : ' + cb.settings.menuitemprice11 + '\nmenuitem12 : ' + cb.settings.menuitem12 + '\nmenuitemprice12 : ' + cb.settings.menuitemprice12 + '\nmenuitem13 : ' + cb.settings.menuitem13 + '\nmenuitemprice13 : ' + cb.settings.menuitemprice13 + '\nmenuitem14 : ' + cb.settings.menuitem14 + '\nmenuitemprice14 : ' + cb.settings.menuitemprice14 + '\nmenuitem15 : ' + cb.settings.menuitem15 + '\nmenuitemprice15 : ' + cb.settings.menuitemprice15 + '\nmenuitem16 : ' + cb.settings.menuitem16 + '\nmenuitemprice16 : ' + cb.settings.menuitemprice16 + '\nmenuitem17 : ' + cb.settings.menuitem17 + '\nmenuitemprice17 : ' + cb.settings.menuitemprice17 + '\nmenuitem18 : ' + cb.settings.menuitem18 + '\nmenuitemprice18 : ' + cb.settings.menuitemprice18 + '\nmenuitem19 : ' + cb.settings.menuitem19 + '\nmenuitemprice19 : ' + cb.settings.menuitemprice19 + '\nmenuitem20 : ' + cb.settings.menuitem20 + '\nmenuitemprice20 : ' + cb.settings.menuitemprice20 + '\nmenuitem21 : ' + cb.settings.menuitem21 + '\nmenuitemprice21 : ' + cb.settings.menuitemprice21 + '\nmenuitem22 : ' + cb.settings.menuitem22 + '\nmenuitemprice22 : ' + cb.settings.menuitemprice22 + '\nmenuitem23 : ' + cb.settings.menuitem23 + '\nmenuitemprice23 : ' + cb.settings.menuitemprice23 + '\nmenuitem24 : ' + cb.settings.menuitem24 + '\nmenuitemprice24 : ' + cb.settings.menuitemprice24 + '\nmenuitem25 : ' + cb.settings.menuitem25 + '\nmenuitemprice25 : ' + cb.settings.menuitemprice25 + '\nmenuitem26 : ' + cb.settings.menuitem26 + '\nmenuitemprice26 : ' + cb.settings.menuitemprice26 + '\nmenuitem27 : ' + cb.settings.menuitem27 + '\nmenuitemprice27 : ' + cb.settings.menuitemprice27 + '\nmenuitem28 : ' + cb.settings.menuitem28 + '\nmenuitemprice28 : ' + cb.settings.menuitemprice28 + '\nmenuitem29 : ' + cb.settings.menuitem29 + '\nmenuitemprice29 : ' + cb.settings.menuitemprice29 + '\nmenuitem30 : ' + cb.settings.menuitem30 + '\nmenuitemprice30 : ' + cb.settings.menuitemprice30 + '\nmenuitem31 : ' + cb.settings.menuitem31 + '\nmenuitemprice31 : ' + cb.settings.menuitemprice31 + '\nmenuitem32 : ' + cb.settings.menuitem32 + '\nmenuitemprice32 : ' + cb.settings.menuitemprice32 + '\nmenuitem33 : ' + cb.settings.menuitem33 + '\nmenuitemprice33 : ' + cb.settings.menuitemprice33 + '\nmenuitem34 : ' + cb.settings.menuitem34 + '\nmenuitemprice34 : ' + cb.settings.menuitemprice34 + '\nmenuitem35 : ' + cb.settings.menuitem35 + '\nmenuitemprice35 : ' + cb.settings.menuitemprice35 + '\nmenuitem36 : ' + cb.settings.menuitem36 + '\nmenuitemprice36 : ' + cb.settings.menuitemprice36 + '\nmenuitem37 : ' + cb.settings.menuitem37 + '\nmenuitemprice37 : ' + cb.settings.menuitemprice37 + '\nmenuitem38 : ' + cb.settings.menuitem38 + '\nmenuitemprice38 : ' + cb.settings.menuitemprice38 + '\nmenuitem39 : ' + cb.settings.menuitem39 + '\nmenuitemprice39 : ' + cb.settings.menuitemprice39 + '\nmenuitem40 : ' + cb.settings.menuitem40 + '\nmenuitemprice40 : ' + cb.settings.menuitemprice40,u); break; } case 'tipmenu2': { cb.sendNotice( 'Dump of all current settings for Tip Menu 2:' + '\n******************* Tip Menu 2 **************************' + '\nenableTipMenu2 : ' + cb.settings.enableTipMenu2 + '\nmenu2item1 : ' + cb.settings.menu2item1 + '\nmenu2itemprice1 : ' + cb.settings.menu2itemprice1 + '\nmenu2item2 : ' + cb.settings.menu2item2 + '\nmenu2itemprice2 : ' + cb.settings.menu2itemprice2 + '\nmenu2item3 : ' + cb.settings.menu2item3 + '\nmenu2itemprice3 : ' + cb.settings.menu2itemprice3 + '\nmenu2item4 : ' + cb.settings.menu2item4 + '\nmenu2itemprice4 : ' + cb.settings.menu2itemprice4 + '\nmenu2item5 : ' + cb.settings.menu2item5 + '\nmenu2itemprice5 : ' + cb.settings.menu2itemprice5 + '\nmenu2item6 : ' + cb.settings.menu2item6 + '\nmenu2itemprice6 : ' + cb.settings.menu2itemprice6 + '\nmenu2item7 : ' + cb.settings.menu2item7 + '\nmenu2itemprice7 : ' + cb.settings.menu2itemprice7 + '\nmenu2item8 : ' + cb.settings.menu2item8 + '\nmenu2itemprice8 : ' + cb.settings.menu2itemprice8 + '\nmenu2item9 : ' + cb.settings.menu2item9 + '\nmenu2itemprice9 : ' + cb.settings.menu2itemprice9 + '\nmenu2item10 : ' + cb.settings.menu2item10 + '\nmenu2itemprice10 : ' + cb.settings.menu2itemprice10 + '\nmenu2item11 : ' + cb.settings.menu2item11 + '\nmenu2itemprice11 : ' + cb.settings.menu2itemprice11 + '\nmenu2item12 : ' + cb.settings.menu2item12 + '\nmenu2itemprice12 : ' + cb.settings.menu2itemprice12 + '\nmenu2item13 : ' + cb.settings.menu2item13 + '\nmenu2itemprice13 : ' + cb.settings.menu2itemprice13 + '\nmenu2item14 : ' + cb.settings.menu2item14 + '\nmenu2itemprice14 : ' + cb.settings.menu2itemprice14 + '\nmenu2item15 : ' + cb.settings.menu2item15 + '\nmenu2itemprice15 : ' + cb.settings.menu2itemprice15 + '\nmenu2item16 : ' + cb.settings.menu2item16 + '\nmenu2itemprice16 : ' + cb.settings.menu2itemprice16 + '\nmenu2item17 : ' + cb.settings.menu2item17 + '\nmenu2itemprice17 : ' + cb.settings.menu2itemprice17 + '\nmenu2item18 : ' + cb.settings.menu2item18 + '\nmenu2itemprice18 : ' + cb.settings.menu2itemprice18 + '\nmenu2item19 : ' + cb.settings.menu2item19 + '\nmenu2itemprice19 : ' + cb.settings.menu2itemprice19 + '\nmenu2item20 : ' + cb.settings.menu2item20 + '\nmenu2itemprice20 : ' + cb.settings.menu2itemprice20,u); break; } case 'positions': { cb.sendNotice( 'Dump of all current settings for positions menu:' + '\n***************** Positions Menu **********************' + '\nenablePosTipMenu : ' + cb.settings.enablePosTipMenu + '\nposMenuInterval : ' + cb.settings.posMenuInterval + '\nposListSort : ' + cb.settings.posListSort + '\nposSepChar : ' + cb.settings.posSepChar + '\nposSepCharCustom : ' + cb.settings.posSepCharCustom + '\nposMenuTxtColor : ' + cb.settings.posMenuTxtColor + '\nposMenuCustTxtColor : ' + cb.settings.posMenuCustTxtColor + '\nposMenuBgColor : ' + cb.settings.posMenuBgColor + '\nposMenuCustBgColor : ' + cb.settings.posMenuCustBgColor + '\nposMenuItem1 : ' + cb.settings.posMenuItem1 + '\nposMenuItemPrice1 : ' + cb.settings.posMenuItemPrice1 + '\nposMenuItem2 : ' + cb.settings.posMenuItem2 + '\nposMenuItemPrice2 : ' + cb.settings.posMenuItemPrice2 + '\nposMenuItem3 : ' + cb.settings.posMenuItem3 + '\nposMenuItemPrice3 : ' + cb.settings.posMenuItemPrice3 + '\nposMenuItem4 : ' + cb.settings.posMenuItem4 + '\nposMenuItemPrice4 : ' + cb.settings.posMenuItemPrice4 + '\nposMenuItem5 : ' + cb.settings.posMenuItem5 + '\nposMenuItemPrice5 : ' + cb.settings.posMenuItemPrice5 + '\nposMenuItem6 : ' + cb.settings.posMenuItem6 + '\nposMenuItemPrice6 : ' + cb.settings.posMenuItemPrice6 + '\nposMenuItem7 : ' + cb.settings.posMenuItem7 + '\nposMenuItemPrice7 : ' + cb.settings.posMenuItemPrice7 + '\nposMenuItem8 : ' + cb.settings.posMenuItem8 + '\nposMenuItemPrice8 : ' + cb.settings.posMenuItemPrice8,u); break; } case 'poll': { cb.sendNotice( 'Dump of all current settings for token poll:' + '\n******************** Token Poll ***********************' + '\nenableTokenPoll : ' + cb.settings.enableTokenPoll + '\npollTitle : ' + cb.settings.pollTitle + '\npollInterval : ' + cb.settings.pollInterval + '\npollMode : ' + cb.settings.pollMode + '\npollCount : ' + cb.settings.pollCount + '\npollMinimum : ' + cb.settings.pollMinimum + '\npollTxtColor : ' + cb.settings.pollTxtColor + '\npollCustTxtColor : ' + cb.settings.pollCustTxtColor + '\npollBgColor : ' + cb.settings.pollBgColor + '\npollCustBgColor : ' + cb.settings.pollCustBgColor + '\npollFanClubDouble : ' + cb.settings.pollFanClubDouble + '\npollKeepalive : ' + cb.settings.pollKeepalive + '\npollModAdd : ' + cb.settings.pollModAdd + '\npollOptLabel1 : ' + cb.settings.pollOptLabel1 + '\npollOptTokens1 : ' + cb.settings.pollOptTokens1 + '\npollOptLabel2 : ' + cb.settings.pollOptLabel2 + '\npollOptTokens2 : ' + cb.settings.pollOptTokens2 + '\npollOptLabel3 : ' + cb.settings.pollOptLabel3 + '\npollOptTokens3 : ' + cb.settings.pollOptTokens3 + '\npollOptLabel4 : ' + cb.settings.pollOptLabel4 + '\npollOptTokens4 : ' + cb.settings.pollOptTokens4 + '\npollOptLabel5 : ' + cb.settings.pollOptLabel5 + '\npollOptTokens5 : ' + cb.settings.pollOptTokens5 + '\npollOptLabel6 : ' + cb.settings.pollOptLabel6 + '\npollOptTokens6 : ' + cb.settings.pollOptTokens6 + '\npollOptLabel7 : ' + cb.settings.pollOptLabel7 + '\npollOptTokens7 : ' + cb.settings.pollOptTokens7 + '\npollOptLabel8 : ' + cb.settings.pollOptLabel8 + '\npollOptTokens8 : ' + cb.settings.pollOptTokens8,u); break; } case 'tickets': { cb.sendNotice( 'Dump of all current settings for tickets:' + '\n****************** Ticket Shows ***********************' + '\nticketShowType : ' + cb.settings.ticketShowType + '\nprepticketTipMenuOff : ' + cb.settings.prepticketTipMenuOff + '\nprepticketPosMenuOn : ' + cb.settings.prepticketPosMenuOn + '\nprepticketStartPoll : ' + cb.settings.prepticketStartPoll + '\nprepticketStopPresale : ' + cb.settings.prepticketStopPresale + '\nprepticketAddPresales : ' + cb.settings.prepticketAddPresales + '\nprepticketAddVIP : ' + cb.settings.prepticketAddVIP + '\nprepticketAddExtFC : ' + cb.settings.prepticketAddExtFC + '\nstartPollTimerWithShow : ' + cb.settings.startPollTimerWithShow + '\nstartPollMinAfterShow : ' + cb.settings.startPollMinAfterShow + '\nendPosMenuWithShow : ' + cb.settings.endPosMenuWithShow + '\nticketModAdd : ' + cb.settings.ticketModAdd + '\nnumberFromLB : ' + cb.settings.numberFromLB + '\namountFromLB : ' + cb.settings.amountFromLB + '\nenablePresales : ' + cb.settings.enablePresales + '\nenablePresalesMode : ' + cb.settings.enablePresalesMode + '\npresaleCountIncrement : ' + cb.settings.presaleCountIncrement + '\npresaleTimedIncrement : ' + cb.settings.presaleTimedIncrement + '\npresaleIncreasePerIncrement : ' + cb.settings.presaleIncreasePerIncrement + '\npresaleMaxIncrements : ' + cb.settings.presaleMaxIncrements + '\ninitialPresalePrice : ' + cb.settings.initialPresalePrice + '\npresaleNoticeInterval : ' + cb.settings.presaleNoticeInterval + '\nticketShowPrice : ' + cb.settings.ticketShowPrice + '\n****************** Fembot Show ***********************' + '\nenableHiddenShow : ' + cb.settings.enableHiddenShow + '\nhiddenShowDescription : ' + cb.settings.hiddenShowDescription + '\nhiddenShowStartMode : ' + cb.settings.hiddenShowStartMode + '\nhiddenShowStartAuto : ' + cb.settings.hiddenShowStartAuto + '\nhiddenShowGoal : ' + cb.settings.hiddenShowGoal + '\nhiddenShowStartTimer : ' + cb.settings.hiddenShowStartTimer + '\nhiddenShowPrice : ' + cb.settings.hiddenShowPrice + '\nhiddenShowPriceFC : ' + cb.settings.hiddenShowPriceFC + '\nhiddenShowPriceEFC : ' + cb.settings.hiddenShowPriceEFC + '\nhiddenShowPriceVIP : ' + cb.settings.hiddenShowPriceVIP + '\nhiddenShowFreeFC : ' + cb.settings.hiddenShowFreeFC + '\nhiddenShowFreeMods : ' + cb.settings.hiddenShowFreeMods + '\nenableHiddenShowOT : ' + cb.settings.enableHiddenShowOT + '\nhiddenShowOTList : ' + cb.settings.hiddenShowOTList + '\nhiddenShowModsAdd : ' + cb.settings.hiddenShowModsAdd + '\nhiddenShowModsChgPrice : ' + cb.settings.hiddenShowModsChgPrice + '\nticketNoticeInterval : ' + cb.settings.ticketNoticeInterval + '\nhiddenShowPreNotice : ' + cb.settings.hiddenShowPreNotice + '\nhiddenShowNotice : ' + cb.settings.hiddenShowNotice + '\nafterShowNotice : ' + cb.settings.afterShowNotice + '\nhiddenShowReducePriceWarn : ' + cb.settings.hiddenShowReducePriceWarn + '\nhiddenShowAllowGift : ' + cb.settings.hiddenShowAllowGift,u); break; } case 'toys': { cb.sendNotice( 'Dump of all current settings for the toy menus:' + '\n***************** Lush Tip Menu ***********************' + '\nenableLushMenu : ' + cb.settings.enableLushMenu + '\nlushMenuInterval : ' + cb.settings.lushMenuInterval + '\nwhichToy : ' + cb.settings.whichToy + '\nlushMenuTxtColor : ' + cb.settings.lushMenuTxtColor + '\nlushMenuCustTxtColor : ' + cb.settings.lushMenuCustTxtColor + '\nlushMenuBgColor : ' + cb.settings.lushMenuBgColor + '\nlushMenuCustBgColor : ' + cb.settings.lushMenuCustBgColor + '\nlushMenuLevel1 : ' + cb.settings.lushMenuLevel1 + '\nlushMenuLevel2 : ' + cb.settings.lushMenuLevel2 + '\nlushMenuLevel3 : ' + cb.settings.lushMenuLevel3 + '\nlushMenuLevel4 : ' + cb.settings.lushMenuLevel4 + '\nlushMenuLevel5 : ' + cb.settings.lushMenuLevel5 + '\nlushMenuLevel6 : ' + cb.settings.lushMenuLevel6 + '\nlushMenuLevel7 : ' + cb.settings.lushMenuLevel7 + '\nlushMenuLevel8 : ' + cb.settings.lushMenuLevel8 + '\nlushMenuLevel9 : ' + cb.settings.lushMenuLevel9 + '\nlushMenuLevel10 : ' + cb.settings.lushMenuLevel10 + '\nlushMenuLevel11 : ' + cb.settings.lushMenuLevel11 + '\nlushMenuLevel12 : ' + cb.settings.lushMenuLevel12 + '\nlushMenuLevel13 : ' + cb.settings.lushMenuLevel13,u); break; } case 'media': { cb.sendNotice( 'Dump of all current settings for the media list:' + '\n******************* Media List *************************' + '\nenableMediaNotice : ' + cb.settings.enableMediaNotice + '\nmediaListInterval : ' + cb.settings.mediaListInterval + '\nmediaListIntro : ' + cb.settings.mediaListIntro + '\nmediaListTxtColor : ' + cb.settings.mediaListTxtColor + '\nmediaListCustTxtColor : ' + cb.settings.mediaListCustTxtColor + '\nmediaListBgColor : ' + cb.settings.mediaListBgColor + '\nmediaListCustBgColor : ' + cb.settings.mediaListCustBgColor + '\nmediaListText1 : ' + cb.settings.mediaListText1 + '\nmediaListItem1 : ' + cb.settings.mediaListItem1 + '\nmediaListText2 : ' + cb.settings.mediaListText2 + '\nmediaListItem2 : ' + cb.settings.mediaListItem2 + '\nmediaListText3 : ' + cb.settings.mediaListText3 + '\nmediaListItem3 : ' + cb.settings.mediaListItem3 + '\nmediaListText4 : ' + cb.settings.mediaListText4 + '\nmediaListItem4 : ' + cb.settings.mediaListItem4 + '\nmediaListText5 : ' + cb.settings.mediaListText5 + '\nmediaListItem5 : ' + cb.settings.mediaListItem5 + '\nmediaListText6 : ' + cb.settings.mediaListText6 + '\nmediaListItem6 : ' + cb.settings.mediaListItem6 + '\nmediaListText7 : ' + cb.settings.mediaListText7 + '\nmediaListItem7 : ' + cb.settings.mediaListItem7 + '\nmediaListText8 : ' + cb.settings.mediaListText8 + '\nmediaListItem8 : ' + cb.settings.mediaListItem8 + '\nmediaListText9 : ' + cb.settings.mediaListText9 + '\nmediaListItem9 : ' + cb.settings.mediaListItem9 + '\nmediaListText10 : ' + cb.settings.mediaListText10 + '\nmediaListItem10 : ' + cb.settings.mediaListItem10 + '\nmediaListText11 : ' + cb.settings.mediaListText11 + '\nmediaListItem11 : ' + cb.settings.mediaListItem11 + '\nmediaListText12 : ' + cb.settings.mediaListText12 + '\nmediaListItem12 : ' + cb.settings.mediaListItem12,u); break; } case 'dice': { cb.sendNotice( 'Dump of all current settings for the dice game:' + '\n******************* Dice Game *************************' + '\ndiceRollPrice : ' + cb.settings.diceRollPrice + '\ndiceRemoveWinner : ' + cb.settings.diceRemoveWinner + '\ndiceMultiRolls : ' + cb.settings.diceMultiRolls + '\ndiceMinSpecial : ' + cb.settings.diceMinSpecial + '\ndiceNoticeInterval : ' + cb.settings.diceNoticeInterval + '\ndiceNoticeBgColor : ' + cb.settings.diceNoticeBgColor + '\ndiceRollBgColor : ' + cb.settings.diceRollBgColor + '\ndiceRollBgColorSpecial : ' + cb.settings.diceRollBgColorSpecial + '\ndicePrize_2 : ' + cb.settings.dicePrize_2 + '\ndicePrize_3 : ' + cb.settings.dicePrize_3 + '\ndicePrize_4 : ' + cb.settings.dicePrize_4 + '\ndicePrize_5 : ' + cb.settings.dicePrize_5 + '\ndicePrize_6 : ' + cb.settings.dicePrize_6 + '\ndicePrize_7 : ' + cb.settings.dicePrize_7 + '\ndicePrize_8 : ' + cb.settings.dicePrize_8 + '\ndicePrize_9 : ' + cb.settings.dicePrize_9 + '\ndicePrize_10 : ' + cb.settings.dicePrize_10 + '\ndicePrize_11 : ' + cb.settings.dicePrize_11 + '\ndicePrize_12 : ' + cb.settings.dicePrize_12 + '\ndicePrize_13 : ' + cb.settings.dicePrize_13,u); break; } case 'raffle': { cb.sendNotice( 'Dump of all current settings for the raffle:' + '\n******************* Dice Game *************************' + '\nenableRaffle : ' + cb.settings.enableRaffle + '\nraffleWhenDrawing : ' + cb.settings.raffleWhenDrawing + '\nraffleAutoDrawing : ' + cb.settings.raffleAutoDrawing + '\nraffleDrawingInterval : ' + cb.settings.raffleDrawingInterval + '\nraffleDrawingGoal : ' + cb.settings.raffleDrawingGoal + '\nraffleModDrawing : ' + cb.settings.raffleModDrawing + '\nrafflePrice1 : ' + cb.settings.rafflePrice1 + '\nrafflePrizes1 : ' + cb.settings.rafflePrizes1 + '\nrafflePrice2 : ' + cb.settings.rafflePrice2 + '\nrafflePrizes2 : ' + cb.settings.rafflePrizes2 + '\nrafflePrice3 : ' + cb.settings.rafflePrice3 + '\nrafflePrizes3 : ' + cb.settings.rafflePrizes3 + '\nrafflePrice4 : ' + cb.settings.rafflePrice4 + '\nrafflePrizes4 : ' + cb.settings.rafflePrizes4 + '\nrafflePrice5 : ' + cb.settings.rafflePrice5 + '\nrafflePrizes5 : ' + cb.settings.rafflePrizes5 + '\nraffleNoticeInterval : ' + cb.settings.raffleNoticeInterval + '\nraffleNoticeText : ' + cb.settings.raffleNoticeText + '\nraffleContinuous : ' + cb.settings.raffleContinuous + '\nraffleResetCycle : ' + cb.settings.raffleResetCycle + '\nraffleTicketList : ' + cb.settings.raffleTicketList,u); break; } default: { cb.sendNotice('Invalid setting group, please use one of the following: notices, leaders, chat, groups, tipmenu1, tipmenu2, positions, poll, tickets, toys, media, dice, or raffle.',u,green); break; } } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.',u,green); } } } //********* End of Expected commands if (message[0] == '/chscoreboard' || message[0] == '/chs' || message[0] == '/chfixscore' || message[0] == '/chlength' || message[0] == '/chclearlist' || message[0] == '/chskip' || message[0] == '/chwin' || message[0] == '/chend' || message[0] == '/chstoptimer' || message[0] == '/chfree' || message[0] == '/chword' || message[0] == '/chprice' || message[0] == '/chplay' || message[0] == '/chh' || message[0] == '/chq' || message[0] == '/chlist' || message[0] == '/chi' || message[0] == '/charades' || message[0] == '/randomfree' || message[0] == '/random' || message[0] == '/ri' || message[0] == '/rw' || message[0] == '/badfree' || message[0] == '/badlibs' || message[0] == '/bi' || message[0] == '/bc' || message[0] == '/badprice' || message[0] == '/bw' || message[0] == '/addwho' || message[0] == '/addwhat' || message[0] == '/addwhere' || message[0] == '/addhowlong' || message[0] == '/uapresale' || message[0] == '/uapresales' || message[0] == '/backup' || message[0] == '/setracetext' || message[0] == '/setracepaneltext' || message[0] == '/restartrace' || message[0] == '/setrace1' || message[0] == '/setrace2' || message[0] == '/addrace1' || message[0] == '/addrace2' || message[0] == '/tipnoteon' || message[0] == '/tipnoteoff' || message[0] == '/ki' || message[0] == '/gbhelp' || message[0] == '/whs' || message[0] == '/rri' || message[0] == '/whi' || message[0] == '/di' || message[0] == '/pt' || message[0] == '/gbstats' || message[0] == '/wi' || message[0] == '/wf' || message[0] == '/warfree' || message[0] == '/pi' || message[0] == '/pf' || message[0] == '/pressfree' || message[0] == '/pw' || message[0] == '/presswinners' || message[0] == '/ww' || message[0] == '/warwinners' || message[0] == '/cpd' || message[0] == '/chgprizedesc' || message[0] == '/addprize' || message[0] == '/cpp' || message[0] == '/changeprizeprice' || message[0] == '/mpl' || message[0] == '/masterprizelist' || message[0] == '/ap' || message[0] == '/pl' || message[0] == '/presslist' || message[0] == '/stoppress' || message[0] == '/press' || message[0] == '/pp' || message[0] == '/pressprizes' || message[0] == '/war' || message[0] == '/waragain' || message[0] == '/stopwar' || message[0] == '/warprizes' || message[0] == '/wl' || message[0] == '/warlist' || message[0] == '/wd' || message[0] == '/wardraw' || message[0] == '/wp' || message[0] == '/kb' || message[0] == '/freekeno' || message[0] == '/wargame' || message[0] == '/keno' || message[0] == '/kp' || message[0] == '/kpbc' || message[0] == '/rrprice' || message[0] == '/chambers' || message[0] == '/rrp' || message[0] == '/rr' || message[0] == '/rrs' || message[0] == '/shooters' || message[0] == '/wheelspins' || message[0] == '/wheelprice' || message[0] == '/freespin' || message[0] == '/freeroll' || message[0] == '/wheel' || message[0] == '/wheelprizes' || message[0] == '/dice' || message[0] == '/diceprizes' || message[0] == '/diceprice' || message[0] == '/msaddfan' || message[0] == '/msrmvfan' || message[0] == '/msfanlist' || message[0] == '/mschgdft' || message[0] == '/mschguser' || message[0] == '/addefc' || message[0] == '/rmvefc' || message[0] == '/listefc' || message[0] == '/listvip' || message[0] == '/addvipuser' || message[0] == '/rmvvipuser' || message[0] == '/resetapp' || message[0] == '/chgpanelbg' || message[0] == '/chgpaneltext' || message[0] == '/check' || message[0] == '/pass' || message[0] == '/plist' || message[0] == '/plistw' || message[0] == '/email' || message[0] == '/newshow' || message[0] == '/chgapp' || message[0] == '/faster' || message[0] == '/slower' || message[0] == '/next' || message[0] == '/skip' || message[0] == '/listgoals' || message[0] == '/lg' || message[0].substring(0,8) == '/setgoal' || message[0].substring(0,9) == '/setcount' || message[0].substring(0,7) == '/setjar' || message[0].substring(0,7) == '/setseq' || message[0] == '/chgendseq' || message[0] == '/addtips' || message[0] == '/restartgoal' || message[0] == '/setgoaltext' || message[0] == '/chgcountgoal' || message[0] == '/setcounttext' || message[0] == '/usechatmsg' || message[0] == '/setseqtext' || message[0] == '/usegrouptips' || message[0] == '/setjartext' || message[0] == '/rmvgoal' || message[0] == '/rmvcount' || message[0] == '/rmvseq' || message[0] == '/rmvjar' || message[0] == '/skiplevel' || message[0] == '/stats' || message[0] == '/spanked' || message[0] == '/spanktotals' || message[0] == '/spanktips' || message[0] == '/spankmenu' || message[0] == '/setspanktext' || message[0] == '/rmvspankgoal' || message[0].substring(0,13) == '/setspankgoal' || message[0] == '/peeplength' || message[0] == '/peeptimer' || message[0] == '/peepaddtime' || message[0] == '/peepstoptimer' || message[0] == '/peepadduser' || message[0] == '/peeprmv' || message[0] == '/peeptimeleft' || message[0] == '/mytime' || message[0] == '/peepsubject' || message[0] == '/peeprestart' || message[0] == '/pp' || message[0] == '/peepprice' || message[0] == '/pv' || message[0] == '/peepviewers' || message[0] == '/pb' || message[0] == '/peepbuyers') { cmd = 1; } if (cmd == 0) { cb.sendNotice(message[0] + ' is not a recognized Fembot, UltraApp, or Gamebot command.\nType "/fbhelp" to see a full list of the available Fembot commands.', u, green); } } var silencedmsg = 0; //********* Suppress for Silence Level if (silenceLevel > 0 && !isMod && !isBC && !isNice && !isFan && !isVIP && !isExtFan) { switch (silenceLevel) { case 1: if (!msg['has_tokens']) { silencedmsg = 1; cb.sendNotice('Your message was not sent because the silence level has been set to only allow members with tokens to chat.',u,green); } break; case 2: if (!cbjs.arrayContains(tipCountArray.name,u)) { silencedmsg = 1; cb.sendNotice('Your message was not sent because the silence level has been set to only allow members who have tipped at least 1 token to chat.',u,green); } break; case 3: if (cbjs.arrayContains(tipCountArray.name,u)) { if (parseInt(tipCountArray.amount[findTipper(u)]) < minTipToChat) { silencedmsg = 1; cb.sendNotice('Your message was not sent because the silence level has been set to only allow members who have tipped at least ' + minTipToChat + ' tokens to chat.',u,green); } } else { silencedmsg = 1; cb.sendNotice('Your message was not sent because the silence level has been set to only allow members who have tipped at least ' + minTipToChat + ' tokens to chat.',u,green); } break; case 4: silencedmsg = 1; cb.sendNotice('Your message was not sent because the silence level has been set to only allow Fans and VIPs to chat. Join the Fan Club!',u,green); break; } } //********* Suppress for Gray Chat Time-Lock if (grayLockToggle == 1 && !isMod && !isBC && !isNice && !isFan && !isVIP && !isExtFan && isGray && silencedmsg == 0) { if (!grayLockCheck(u,isBC,isMod,isFan,isGray)) { var left = grayTimeLeft(u); silencedmsg = 1; cb.sendNotice('Your message was not sent because gray chat is time-locked and you have ' + left + ' minute' + (left === 1 ? '' : 's') + ' remaining.',u,green); } } //********* Suppress for Ninja'd or Silenced if (isNinjaSilenced && !isMod && !isBC && silencedmsg == 0) { silencedmsg = 1; if (showNinjadMsgs == 'Broadcaster only') { cb.sendNotice('Fembot - Chat message from ninja silenced user ' + u + ' : ' + msg['m'],BC,green); } else if (showNinjadMsgs == 'Mods only') { cb.sendNotice('Fembot - Chat message from ninja silenced user ' + u + ' : ' + msg['m'],'',green,'','','red'); } else if (showNinjadMsgs == 'Broadcaster and Mods') { cb.sendNotice('Fembot - Chat message from ninja silenced user ' + u + ' : ' + msg['m'],BC,green); cb.sendNotice('Fembot - Chat message from ninja silenced user ' + u + ' : ' + msg['m'],'',green,'','','red'); } } if (isSilenced && !isMod && !isBC && silencedmsg == 0) { silencedmsg = 1; cb.sendNotice('Your message was not sent because you have been silenced.',u,green); if (showSilencedMsgs == 'Broadcaster only') { cb.sendNotice('Fembot - Chat message from silenced user ' + u + ' : ' + msg['m'],BC,green); } else if (showSilencedMsgs == 'Mods only') { cb.sendNotice('Fembot - Chat message from silenced user ' + u + ' : ' + msg['m'],'',green,'','','red'); } else if (showSilencedMsgs == 'Broadcaster and Mods') { cb.sendNotice('Fembot - Chat message from silenced user ' + u + ' : ' + msg['m'],BC,green); cb.sendNotice('Fembot - Chat message from silenced user ' + u + ' : ' + msg['m'],'',green,'','','red'); } } //********* Graphic Level if (graphicLevel > 0 && !isMod && !isBC && !isNice && !isFan && !isVIP && !isExtFan && silencedmsg == 0) { switch(graphicLevel) { case 1: if(!msg['has_tokens']) { for(var i = 0; i < message.length; i++) { if(message[i].charAt(0) == ':' && message[i].charAt(1) != ')') { silencedmsg = 1; cb.sendNotice('Your message was not displayed because the graphic level has been set to only allow users with tokens to use graphics.',u,green); } } } break; case 2: if(!cbjs.arrayContains(tipCountArray.name,u)) { for(var i = 0; i < message.length; i++) { if(message[i].charAt(0) == ':' && message[i].charAt(1) != ')') { silencedmsg = 1; cb.sendNotice('Your message was not displayed because the graphic level has been set to only allow users who have tipped to use graphics.',u,green); } } } break; case 3: if(cbjs.arrayContains(tipCountArray.name,u)) { if(parseInt(tipCountArray.amount[findTipper(u)]) < minTipToChat) { for(var i = 0; i < message.length; i++) { if(message[i].charAt(0) == ':' && message[i].charAt(1) != ')') { silencedmsg = 1; cb.sendNotice('Your message was not displayed because the graphic level has been set to only allow members who have tipped at least ' + minTipToChat + ' tokens to use graphics.',u,green); } } } } else { for(var i = 0; i < message.length; i++) { if(message[i].charAt(0) == ':' && message[i].charAt(1) != ')') { silencedmsg = 1; cb.sendNotice('Your message was not displayed because the graphic level has been set to only allow members who have tipped at least ' + minTipToChat + ' tokens to use graphics.',u,green); } } } break; case 4: for(var i = 0; i < message.length; i++) { if (message[i].charAt(0) == ':' && message[i].charAt(1) != ')') { silencedmsg = 1; cb.sendNotice('Your message was not displayed because the graphic level has been set to only allow users who have tipped to use graphics.',u,green); } } break; } } // ********** Convert to lower case if (suppressCapsToggle == 1) { capscount = 0; var caps = /[A-Z][A-Z]+/; if (!isMod && !isBC) { var d = msg['m']; MessageArray = d.split(' '); for (var i = 0; i < MessageArray.length; i++) { if (caps.test(MessageArray[i])) { capscount++; } } if (capscount > 1) { m = m.toLowerCase(); msg['m'] = m; cb.sendNotice('Message converted to lower case, please do not type in all CAPS!',u,green); } } } // ********** Suppress messages containing blocked word if (cb.settings.enableWordList == 'Yes' && wordListArray.length > 0 && silencedmsg == 0) { if (cb.settings.blockedLevel == 'All Users Except Mods' && !isMod && !isBC) { checkblocklist = true; } else if (cb.settings.blockedLevel == 'All Users Except Mods/Fans/VIPs' && !isMod && !isBC && !isFan && !isVIP && !isExtFan) { checkblocklist = true; } else if (cb.settings.blockedLevel == 'Only Light Blue and Gray Users' && !isMod && !isBC && !isFan && !isVIP && !isExtFan && !isDarkBlue && !isDarkPurple && !isLightPurple) { checkblocklist = true; } else if (cb.settings.blockedLevel == 'Gray Users Only' && isGray) { checkblocklist = true; } else { checkblocklist = false; } if (checkblocklist) { var d = msg['m']; messageArrayBuilt = true; MessageArray = d.split(' '); for (var i = 0; i < MessageArray.length; i++) { if (cbjs.arrayContains(wordListArray, MessageArray[i])) { silencedmsg = 1; cb.sendNotice('Your message was not displayed because it contains words in the blocked word list. Please refrain from rude language. You can view blocked words with the command /wordlist.',u,green); if (cb.settings.showBlockedMsgs == 'Display to Broadcaster only') { cb.sendNotice('Fembot - Blocked word list message from user ' + u + ' : ' + msg['m'],BC,green); } } } } } // ********** PM Response if (!isMod && !isBC && !isFan && !isVIP && !isExtFan && silencedmsg == 0) { if (cb.settings.enablePMResponse == 'Yes' && cb.settings.pmResponseMessage != '') { if (messageArrayBuilt != true) { var d = msg['m']; MessageArray = d.split(' '); messageArrayBuilt = true; } for (var i = 0; i < MessageArray.length; i++) { if (MessageArray[i] == 'PM' || MessageArray[i] == 'pm' || MessageArray[i] == 'Pm' || MessageArray[i] == 'PM?' || MessageArray[i] == 'Pm?' || MessageArray[i] == 'pm?') { cb.sendNotice(cb.settings.pmResponseMessage, '', green, '', 'bold'); break; } } } } // ********** Add message prefix if needed if (!suppressPrefix) { if(cbjs.arrayContains(tipCountArray.name,u) || isMod || isFan || isVIP || isExtFan || cbjs.arrayContains(iconNicknamesArray.name,u)) { if(message[0].charAt(0) != '/' && message[0].charAt(0) != '!') { grp = null; posn = 0; tipcount = 0; if(tipCountToggle == 1 && cbjs.arrayContains(tipCountArray.name,u)) { tipcount = parseInt(tipCountArray.amount[findTipper(u)]); } if(groupIconsToggle == 1) { if (isBotMod) { grp = 'botmods'; } else if (isCBMod) { grp = 'cbmods'; } else if (isFan) { grp = 'fans'; } else if (cbjs.arrayContains(extFanListArray,u)) { grp = 'extfans'; } else if (cbjs.arrayContains(VIPListArray,u)) { grp = 'VIP'; } } if (tipLeaderIconsToggle == 1 && cbjs.arrayContains(tipCountArray.name,u)) { sortTippers(); for (var i = 1; i <= tipCountArray.name.length; i++) { if(tipCountArray.name[i-1] == u) { break; } } lbposn = i; if (lbposn >= 1 && lbposn <= 3) { posn = lbposn; } } if (tipcount > 0 || grp != null || posn > 0 || cbjs.arrayContains(iconNicknamesArray.name,u)) { pfxgrpicon = null; pfxcount = null; pfxtipleader = null; pfxnickname = null; switch (grp) { case 'botmods': pfxgrpicon = cb.settings.iconBotMods; break; case 'cbmods': pfxgrpicon = cb.settings.iconMods; break; case 'fans': pfxgrpicon = cb.settings.iconFans; break; case 'extfans': pfxgrpicon = cb.settings.iconExtFans; break; case 'VIP': pfxgrpicon = cb.settings.iconVIP; break; } if (cbjs.arrayContains(iconNicknamesArray.name,u)) { iconindex = iconNicknamesArray.name.indexOf(u); if (iconNicknamesArray.icon[iconindex] != '' && iconNicknamesArray.icon[iconindex] != null) { pfxgrpicon = iconNicknamesArray.icon[iconindex]; } } switch (posn) { case 1: pfxtipleader = cb.settings.tipLeaderGif1; break; case 2: pfxtipleader = cb.settings.tipLeaderGif2; break; case 3: pfxtipleader = cb.settings.tipLeaderGif3; break; } if (tipcount > 0) { pfxcount = '|' + tipCountArray.amount[findTipper(u)] + '| '; } if (cbjs.arrayContains(iconNicknamesArray.name,u)) { nicknameindex = iconNicknamesArray.name.indexOf(u); if (iconNicknamesArray.nickname[nicknameindex] != '' && iconNicknamesArray.nickname[nicknameindex] != null) { pfxnickname = '[' + iconNicknamesArray.nickname[nicknameindex] + '] '; } } msg.m = (pfxgrpicon != null ? pfxgrpicon + ' ' : '') + (pfxtipleader != null ? pfxtipleader + ' ' : '') + (pfxcount != null ? pfxcount + ' ' : '') + (pfxnickname != null ? pfxnickname + ' ' : '') + msg.m; } } } } // Highlight background for Ticket show users if (cb.limitCam_userHasAccess(u) && ticketShowToggle == 1) { msg['background'] = ticketHolderBgColor; } // Set message text color if defined if (cbjs.arrayContains(iconNicknamesArray.name,u)) { colorindex = iconNicknamesArray.name.indexOf(u); if (iconNicknamesArray.color[colorindex] != '' && iconNicknamesArray.color[colorindex] != null) { msgtextcolor = checkTextColor(iconNicknamesArray.color[colorindex]); if (msgtextcolor == 'default') { msgtextcolor = '#FFFFFF'; } msg.c = msgtextcolor; } } if(silencedmsg == 1) { msg['X-Spam'] = true; } return msg; }); } // *********************************** Actions on user entering ************************************** { cb.onEnter(function(user) { // Variables var u = user.user; var isMod = user.is_mod; var isCBMod = user.is_mod; var isBC = (u === cb.room_slug); var isFan = user.in_fanclub; var isGray = false; var isDarkBlue = false; var isLightBlue = false; var isLightPurple = false; var isDarkPurple = false; var isExtFan = cbjs.arrayContains(extFanListArray,u); var isVIP = cbjs.arrayContains(VIPListArray,u); if (user.tipped_tons_recently) { isDarkPurple = true; } else if (user.tipped_alot_recently) { isLightPurple = true; } else if (user.tipped_recently) { isDarkBlue = true; } else if (user.has_tokens) { isLightBlue = true; } else if (!user.has_tokens) { isGray = true; } isBotMod = false; if (isMod) { populateModeratorArray(u,'cbmod','a'); } else { if (cbjs.arrayContains(moderatorList.name,u)) { nameIndex = moderatorList.name.indexOf(u); if (moderatorList.type[nameIndex] == 'botmod') { isBotMod = true; isMod = true; } } } if (isFan) { populateFanClubArray(u); } if(cb.limitCam_userHasAccess(u)) { if (!cbjs.arrayContains(ticketShowViewerList,u)) { ticketShowViewerList.push(u); } } // **** General Entry Message if (cb.settings.enableEntryMessage == 'Yes') { var entryMessage = cb.settings.entryMessage; if (tipMenuToggle == 1 || tipMenu2Toggle == 1) { entryMessage += '\n \u21E8 A Tip Menu is available. The menu may display periodically if enabled by the broadcaster, or you can see the menu at anytime by typing "/tipmenu".'; } if (posTipMenuToggle == 1) { entryMessage += '\n \u21E8 The Positions Tip Menu is active. The menu may display periodically if enabled by the broadcaster, or you can see the menu at anytime by typing "/postipmenu".'; } if (lushMenuToggle == 1) { entryMessage += '\n \u21E8 The ' + whichToy + ' Menu is active, please use the ' + whichToy + ' Tip Menu Ranges to control the toy.'; } if (tokenPollToggle == 1) { entryMessage += '\n \u21E8 A Token Poll is running, you can tip to vote for your favorite in the poll. You can also type "/poll" to see the current poll choices and votes.'; if (isFan && fanDouble) { entryMessage += '\n \u21E8 Fan Club members get double votes in the poll today!'; } if (isMod) { entryMessage += '\n \u21E8 Moderators: Type "/fbhelp tokenpoll" to see all of the poll related commands.'; } } if (presalesToggle == 1) { entryMessage += '\n \u21E8 Ticket Show Pre-sales are active. You can now buy advance tickets to the show at a price of ' + presalePrice + ' tokens. You will automatically be added to the ticket show when the Ticket Show app is started later. Buy now before the price goes up! Ticket show price will be ' + ticketPrice + ' tokens.'; } if (raffleToggle == 1) { entryMessage += '\n \u21E8 A raffle is running today, the recurring notice will provide info on raffle ticket prices and the prize list, or you can use the command "/raffleprizes" to display the list at any time.'; } if (diceToggle == 1) { if (diceMultiRolls <= 1) { entryMessage += '\n \u21E8 The Dice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! You can use the command /prizes to see the prize list.'; } else if (diceMultiRolls == 2) { entryMessage += '\n \u21E8 The Dice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! You can use the command /prizes to see the prize list.You can tip up to 2 multiples of the dice roll price to roll multiple times (' + diceRollPrice + ' or ' + diceRollPrice*2 + ').'; } else if (diceMultiRolls == 3) { entryMessage += '\n \u21E8 The Dice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! You can use the command /prizes to see the prize list.You can tip up to 3 multiples of the dice roll price to roll multiple times (' + diceRollPrice + ', ' + diceRollPrice*2 + ', or ' + diceRollPrice*3 + ').'; } else if (diceMultiRolls > 3) { entryMessage += '\n \u21E8 The Dice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! You can use the command /prizes to see the prize list.You can tip up to ' + diceMultiRolls + ' multiples of the dice roll price to roll multiple times (' + diceRollPrice + ', ' + diceRollPrice*2 + ', ' + diceRollPrice*3 + ',...)'; } } temptextcolor = checkTextColor('Dark Green'); tempbgcolor = checkBgColor('Cream'); cb.sendNotice(entryMessage, u, tempbgcolor, temptextcolor, 'bold'); } // **** Announce VIPs if((cb.settings.announceVIP == 'Enter Only' || cb.settings.announceVIP == 'Enter or Leave') && cbjs.arrayContains(VIPListArray,u)) { temptextcolor = checkTextColor('Dark Blue'); tempbgcolor = checkBgColor('Light Blue'); if (cb.settings.announceVIPtext) { cb.sendNotice('Welcome ' + u + '! ' + cb.settings.announceVIPtext, '', tempbgcolor, temptextcolor, 'bold'); } else { cb.sendNotice('Welcome VIP member ' + u + ' to our room!', '', tempbgcolor, temptextcolor, 'bold'); } } // **** Announce External Fan Club members if((cb.settings.announceExtFans == 'Enter Only' || cb.settings.announceExtFans == 'Enter or Leave') && cbjs.arrayContains(extFanListArray,u)) { temptextcolor = checkTextColor('Dark Green'); tempbgcolor = checkBgColor('Light Green'); if (cb.settings.announceExtFanstext) { cb.sendNotice('Welcome ' + u + '! ' + cb.settings.announceExtFanstext, '', tempbgcolor, temptextcolor, 'bold'); } else { cb.sendNotice('Welcome Fan Club member ' + u + ' to our room!', '', tempbgcolor, temptextcolor, 'bold'); } } // **** Entry message if on the nice list if(cbjs.arrayContains(niceListArray,u)) { cb.sendNotice('Welcome ' + u + ', you are on the nice list, so you will still be able to chat when the silence level is elevated. Thank you for not making rude and demanding comments in your chat.',u,'','','bold'); } // **** Ticket Show functions and message if (ticketShowToggle == 1) { if (cb.limitCam_isRunning()) { getShowTime(u); if (!cb.limitCam_userHasAccess(u)) { if (showStage === 'ticketshow') { cb.sendNotice(dashLine80 + '\nTicket Show is in progress, broadcaster has not indicated Show Finale.\n' + dashLine80, u, ticketBgColor,ticketTxtColor,'bold'); if (ticketShowOtToggle == 1) { cb.sendNotice(dashLine80 + '\n* The Broadcaster has enabled the Outstanding Ticket Feature. \n* You can use the command "/otlist" to see if you have an outstanding ticket. \n* You can use a saved outstanding ticket with the command "/useticket". \n* You can also save your ticket for a future show using the command "/saveticket" if the show has not staretd yet.\n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } } else if (showStage === 'showwarn') { cb.sendNotice(dashLine80 + '\nTicket Show is in progress, however broadcaster has indicated show is nearly over. \nBuying a ticket now is not recommended, but you may still buy a ticket for ' + ticketPrice + ' tokens. Recommend checking with the broadcaster or moderators on show status before buying.\n' + dashLine80, u, ticketBgColor,ticketTxtColor,'bold'); } else if (showStage === 'showfinale') { cb.sendNotice(dashLine80 + '\nTicket Show is in progress, however broadcaster has indicated show is nearly over and suspended ticket sales. \nBroadcaster may be returning to public chat shortly.\n' + dashLine80, u, ticketBgColor,ticketTxtColor,'bold'); } } } else { if (showStage === 'ticketsales') { if (cb.limitCam_userHasAccess(u)) { cb.sendNotice(dashLine80 + '\nWelcome! You have a ticket to the show and the show has not yet started.\n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice(dashLine80 + '\nTicket Show sales are active and show has not yet started. \nThe ticket price is ' + ticketPrice + ' tokens.\n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } if (cb.settings.hiddenShowAllowGift === 'Yes') { cb.sendNotice(dashLine80 + '\n* The Broadcaster has enabled the the gifting of tickets. \n* If you purchase extra tickets, you can gift them to others using the command "/giftticket user" \n* You can also choose to give away your own ticket using the command "/givemyticketto user".\n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } if (ticketShowOtToggle == 1) { cb.sendNotice(dashLine80 + '\n* The Broadcaster has enabled the Outstanding Ticket Feature. \n* You can use the command "/otlist" to see if you have an outstanding ticket. \n* You can use a saved outstanding ticket with the command "/useticket". \n* You can also save your ticket for a future show using the command "/saveticket" if the show has not staretd yet.\n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } } else if (showStage === 'aftershow' || ticketShowEnded === true) { cb.sendNotice(dashLine60 + '\nThe Ticket Show is over.\n' + dashLine60, u, ticketBgColor, ticketTxtColor, "bold"); } } if (!cb.limitCam_userHasAccess(u)) { if (isMod) { if (cb.settings.hiddenShowFreeMods === 'Yes') { addRmvTicket('add',u,'mod'); cb.sendNotice(dashLine80 + '\n* You\'ve automatically been added to the ticket show because you\'re a moderator! \n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } cb.sendNotice(dashLine80 + '\n* Moderators: The Fembot Ticket Show feature is enabled. \nType "/fbhelp ticketshow" to see details on available commands for this feature. \n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } if (isFan) { if (cb.settings.hiddenShowFreeFC === 'Yes') { addRmvTicket('add',u,'fan'); cb.sendNotice(dashLine80 + '\n* You\'ve automatically been added to the ticket list because you\'re in the fan club! \n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice(dashLine80 + '\n* As a fan club member, you can buy a ticket to the show for ' + cb.settings.hiddenShowPriceFC + ' tokens. \n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } } if (isExtFan) { if (cb.settings.enableExtFans === 'Ticket Shows' || cb.settings.enableExtFans === 'PMs and Ticket Shows') { addRmvTicket('add',u,'fan'); cb.sendNotice(dashLine80 + '\n* You\'ve automatically been added to the ticket list because you\'re an external fan club member!\n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice(dashLine80 + '\n* As an External Fan Club member, you can buy a ticket to the show for ' + cb.settings.hiddenShowPriceEFC + ' tokens. \n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } } if (isVIP) { if (cb.settings.enableVIPList == 'Ticket Shows' || cb.settings.enableVIPList == 'PMs and Ticket Shows') { addRmvTicket('add',u,'vip'); cb.sendNotice(dashLine80 + '\n* You\'ve automatically been added to the ticket list because you\'re on the VIP list! \n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice(dashLine80 + '\n* As a VIP, you can buy a ticket to the show for ' + cb.settings.hiddenShowPriceVIP + ' tokens. \n' + dashLine80, u, ticketBgColor, ticketTxtColor, "bold"); } } } } // **** Track Grays for Time Lock if (grayLockToggle == 1) { if (!cbjs.arrayContains(grayLockList,u)) { addToLockList(u,isBC,isMod,isFan,isGray); } if (grayLockStatus.canChat[grayLockList.indexOf(u)] === false) { cb.sendNotice('Welcome, gray chat is locked for the first ' + grayChatTime + ' minutes in the room, once that time expires, you will be able to chat.', u, '', '', 'bold'); } } // **** Track Users for Answer Required Lock if (requireAnswerToggle == 1) { if (!isBC && !isMod && !isFan && !isExtFan && !isVIP) { if (isGray && requireAnswerLevel >= 1 || isLightBlue && requireAnswerLevel >= 2 || isDarkBlue && requireAnswerLevel >= 3 || isLightPurple && requireAnswerLevel >= 4 || isDarkPurple && requireAnswerLevel >= 5) { if (!cbjs.arrayContains(answerLockList,u)) { addToAnswerLockList(u); } if (answerLockStatus[answerLockList.indexOf(u)] === false) { lockquestionindex = answerLockQuestion[answerLockList.indexOf(u)]; cb.sendNotice('Welcome, ' + u + ' chat is locked for your user level until you correctly complete the following sentence: \n ' + lockQuestions[lockquestionindex], u, '', '', 'bold'); } } } } }); } // *********************************** Actions upon leaving ************************************** { cb.onLeave(function(user) { var u = user.user; // **** Remove from ticket show viewer list if (ticketShowToggle == 1) { if (cbjs.arrayContains(ticketShowViewerList,u)) { cbjs.arrayRemove(ticketShowViewerList,u); } } // **** Announce VIPs if ((cb.settings.announceVIP == 'Leave Only' || cb.settings.announceVIP == 'Enter or Leave') && cbjs.arrayContains(VIPListArray,u)) { temptextcolor = checkTextColor('Dark Blue'); tempbgcolor = checkBgColor('Light Blue'); cb.sendNotice('VIP member ' + u + ' has left the room', '', tempbgcolor, temptextcolor, 'bold'); } // **** Announce External Fan Club members if ((cb.settings.announceExtFans == 'Leave Only' || cb.settings.announceExtFans == 'Enter or Leave') && cbjs.arrayContains(extFanListArray,u)) { temptextcolor = checkTextColor('Dark Green'); tempbgcolor = checkBgColor('Light Green'); cb.sendNotice('Fan Club member ' + u + ' has left the room', '', tempbgcolor, temptextcolor, 'bold'); } }); } // *********************************** Actions upon tipping ************************************** { cb.onTip(function (tip) { var tipAmount = Number.parseInt(tip.amount, 10); var u = tip.from_user var isFan = tip.from_user_in_fanclub; var voteAmount = 1; var isExtFan = cbjs.arrayContains(extFanListArray,u); var isVIP = cbjs.arrayContains(VIPListArray,u); // ***** Tip Response Message if (tipResponseToggle == 1 || tipResponseToggle == 2) { if (tipResponseToggle == 1) { sendto = u; } else { sendto = ''; } if (tipResponseAmount5 > 0 && tipAmount >= tipResponseAmount5) { cb.sendNotice(tipResponseMessage5, sendto, tipresponsebgcolor, tipresponsetextcolor, 'bold'); } else if (tipResponseAmount4 > 0 && tipAmount >= tipResponseAmount4) { cb.sendNotice(tipResponseMessage4, sendto, tipresponsebgcolor, tipresponsetextcolor, 'bold'); } else if (tipResponseAmount3 > 0 && tipAmount >= tipResponseAmount3) { cb.sendNotice(tipResponseMessage3, sendto, tipresponsebgcolor, tipresponsetextcolor, 'bold'); } else if (tipResponseAmount2 > 0 && tipAmount >= tipResponseAmount2) { cb.sendNotice(tipResponseMessage2, sendto, tipresponsebgcolor, tipresponsetextcolor, 'bold'); } else if (tipResponseAmount1 > 0 && tipAmount >= tipResponseAmount1) { cb.sendNotice(tipResponseMessage1, sendto, tipresponsebgcolor, tipresponsetextcolor, 'bold'); } else { } } // ***** Tip Count Array if (!cbjs.arrayContains(tipCountArray.name, u)) { populateTipCountArray(u,tipAmount); } else { tipCountArray.amount[findTipper(u)] += tipAmount; } // ***** Tip Menu if (tipMenuToggle == 1) { for (let i = 0; i < TIPMENU.menuLength; i++) { if (tipAmount === TIPMENU.tipMenuPrice[i]) { TIPMENU.requesters.push(tip.from_user); TIPMENU.request.push(TIPMENU.tipMenuItem[i]); cb.sendNotice(u + ' tipped for ' + TIPMENU.tipMenuItem[i], '', TIPMENU.bgColor1, TIPMENU.txtColor1, "bold"); } } } if (tipMenu2Toggle == 1) { for (let i = 0; i < TIPMENU2.menuLength; i++) { if (tipAmount === TIPMENU2.tipMenuPrice[i]) { TIPMENU2.requesters.push(tip.from_user); TIPMENU2.request.push(TIPMENU2.tipMenuItem[i]); cb.sendNotice(u + ' tipped for ' + TIPMENU2.tipMenuItem[i], '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, "bold"); } } } if (posTipMenuToggle == 1) { for (let i = 0; i < POSTIPMENU.posMenuLength; i++) { if (tipAmount === POSTIPMENU.posTipMenuPrice[i]) { POSTIPMENU.posRequesters.push(tip.from_user); POSTIPMENU.posRequest.push(POSTIPMENU.posTipMenuItem[i]); cb.sendNotice(u + ' tipped for ' + POSTIPMENU.posTipMenuItem[i], '', POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor, "bold"); } } } // ***** Add to Ticket Show Backup List if (backupToggle == 1 && !cbjs.arrayContains(backupListArray,u)) { if (ticketShowType != 'Fembot Ticket Show' && tipAmount >= backupPrice) { addRmvTicketBackupList('addtip', u); } } // ***** Add to Pre-Sale Ticket List if (presalesToggle == 1 && !cbjs.arrayContains(presaleArray,u)) { if (tipAmount >= presalePrice) { addRmvPresale('addtip', u, tipAmount); } else { checkCumulative(u,tipAmount,presalePrice,'common','presale'); } } // ***** Add to Ticket Show if (ticketShowToggle == 1 && !ticketShowEnded && !ticketSalesEnded && !cb.limitCam_userHasAccess(u)) { if (isFan) { if (tipAmount >= ticketPriceFC) { addRmvTicket('addtip', u, 'fan', tipAmount); } else { checkCumulative(u,tipAmount,ticketPriceFC,'fan','ticket'); } } else if (isExtFan) { if (tipAmount >= ticketPriceEFC) { addRmvTicket('addtip', u, 'fan', tipAmount); } else { checkCumulative(u,tipAmount,ticketPriceEFC,'fan','ticket'); } } else if (isVIP) { if (tipAmount >= ticketPriceVIP) { addRmvTicket('addtip', u, 'vip', tipAmount); } else { checkCumulative(u,tipAmount,ticketPriceVIP,'vip','ticket'); } } else { if (tipAmount >= ticketPrice) { addRmvTicket('addtip', u, 'common', tipAmount); } else { checkCumulative(u,tipAmount,ticketPrice,'common','ticket'); } } } else if (ticketShowToggle == 1 && !ticketShowEnded && !ticketSalesEnded && cb.limitCam_userHasAccess(u) && cb.settings.hiddenShowAllowGift === 'Yes') { if (tipAmount >= ticketPrice) { addRmvTicket('addextra', u, 'common', tipAmount); } } // ***** Progress on Ticket Show Goal if (ticketShowToggle == 1) { ticketShowGoalProgress(tipAmount); } // ***** Perform Token Poll Tip Functions if(tokenPollToggle == 1 && pollRunning && cbjs.arrayContains(pollArrayAmount,tipAmount)) { if (isFan && fanDouble) { voteAmount = 2; pollmsg('', u, 'Since you are a member of the fan club, your votes will be doubled.'); } pollTip(tipAmount,voteAmount,u); } // ***** Perform Dice Roll Function if (diceToggle == 1 && tipAmount >= diceRollPrice && (tipAmount / diceRollPrice <= diceMultiRolls) && (tipAmount % diceRollPrice == 0)) { var numberOfRolls = Math.floor(parseInt(tip['amount']) / diceRollPrice); for (var i = 0; i < numberOfRolls; i++) { diceRoll(tip['from_user']); diceLastRoller = tip['from_user']; } } // ***** Perform Raffle Ticket Purchase if (raffleToggle == 1) { if (cb.settings.raffleTipMultiple == 'Yes') { for (var i = 1; i <= 5; i++) { if (tipAmount % rafflePrice[i] == 0) { var numberOfTickets = Math.floor(parseInt(tip['amount']) / rafflePrice[i]); for (var j = 0; j < numberOfTickets; j++) { raffleTicketPurchase(i,u,rafflePrice[i]) } cb.sendNotice(u + ' has bought ' + (numberOfTickets > 1 ? numberOfTickets : 'a') + ' Level ' + i + ' Raffle Ticket' + (numberOfTickets > 1 ? 's' : '') + '!', '', raffleBgColor, raffleTextColor, 'bold'); break; } } } else { for (var i = 1; i <= 5; i++) { if (rafflePrice[i] > 0 && tipAmount == rafflePrice[i]) { raffleTicketPurchase(i,u,tipAmount); cb.sendNotice(u + ' has bought a Level ' + i + ' Raffle Ticket!', '', raffleBgColor, raffleTextColor, 'bold'); break; } } } } }); } // *********************************** Initialize ************************************** { if (initialize == 0) { cb.sendNotice(' :DorothysUltraFembot v2.7'); cb.sendNotice('** Version 2.7 released on 07/15/2019, please see the change log at the bottom of the bot description page for a list of added features in the current release. You can type "/fbhelp" for the command list.', cb.room_slug, green); // *** Init Features using toggle functions suppressCapsToggle = 1; if (cb.settings.enableGroupIcons == 'Yes') { groupIconsToggle = 1; } if (cb.settings.enableTipLeaderIcons == 'Yes') { tipLeaderIconsToggle = 1; } if (cb.settings.enableLeaderboard == 'Yes') { setLeaderToggle('on',cb.room_slug); } if (cb.settings.enableNotifier == 'Yes') { setNotifierToggle('on',cb.room_slug); } if (cb.settings.enableTipCount == 'Yes') { setTipCountToggle('on',cb.room_slug); } if (cb.settings.enableTipMenu == 'Yes') { setTipMenuToggle('on',cb.room_slug); if(cb.settings.enableTipMenu2 == 'Yes') { cb.sendNotice('Unable to start Tip Menu 2, since Tip Menu 1 is already enabled. To switch to Tip Menu 2, use the command "/swapmenu".', cb.room_slug, green); } } if (cb.settings.enableTipMenu2 == 'Yes' && cb.settings.enableTipMenu == 'No') { setTipMenu2Toggle('on',cb.room_slug); } if (cb.settings.enablePosTipMenu == 'Yes') { setPosTipMenuToggle('on',cb.room_slug); } if (cb.settings.enableTokenPoll == 'Yes') { setTokenPollToggle('on',cb.room_slug); } if (cb.settings.enableLushMenu == 'Yes') { whichToy = cb.settings.whichToy; setLushMenuToggle('on',cb.room_slug); } if (cb.settings.enableMediaNotice == 'Yes') { setMediaToggle('on',cb.room_slug); } if (cb.settings.enableDiceGame == 'Yes') { setDiceToggle('on',cb.room_slug); } if (cb.settings.enableTipResponse == 'Yes, send to tipper') { setTipResponseToggle('tipper',cb.room_slug); } else if (cb.settings.enableTipResponse == 'Yes, send to all') { setTipResponseToggle('all',cb.room_slug); } else if (cb.settings.enableTipResponse == 'No') { setTipResponseToggle('off',cb.room_slug); } if (cb.settings.lockGrayChat == 'Yes') { setGrayLockToggle('on',cb.room_slug); } if (cb.settings.requireAnswerLevel != 'Not Used') { requireAnswerLevelText = cb.settings.requireAnswerLevel; if (cb.settings.requireAnswerLevel == 'Gray Users') { requireAnswerLevel = 1; } else if (cb.settings.requireAnswerLevel == 'Light Blue Users') { requireAnswerLevel = 2; } else if (cb.settings.requireAnswerLevel == 'Dark Blue Users') { requireAnswerLevel = 3; } else if (cb.settings.requireAnswerLevel == 'Light Purple Users') { requireAnswerLevel = 4; } else if (cb.settings.requireAnswerLevel == 'Dark Purple Users') { requireAnswerLevel = 5; } setRequireAnswerToggle('on',cb.room_slug); } if(cb.settings.enableAllTime == 'Yes') { setAllTimeToggle('on',cb.room_slug); } raffleTicketsSoldLvl[1] = 0; raffleTicketsSoldLvl[2] = 0; raffleTicketsSoldLvl[3] = 0; raffleTicketsSoldLvl[4] = 0; raffleTicketsSoldLvl[5] = 0; rafflePrice[1] = cb.settings.rafflePrice1; rafflePrice[2] = cb.settings.rafflePrice2; rafflePrice[3] = cb.settings.rafflePrice3; rafflePrice[4] = cb.settings.rafflePrice4; rafflePrice[5] = cb.settings.rafflePrice5; loadPrevRaffleResults(cb.room_slug); if(cb.settings.enableRaffle == 'Yes') { if(cb.settings.rafflePrizes1 != '' && cb.settings.rafflePrizes1 != null || cb.settings.rafflePrizes2 != '' && cb.settings.rafflePrizes2 != null || cb.settings.rafflePrizes3 != '' && cb.settings.rafflePrizes3 != null || cb.settings.rafflePrizes4 != '' && cb.settings.rafflePrizes4 != null || cb.settings.rafflePrizes5 != '' && cb.settings.rafflePrizes5 != null) { if(rafflePrice[1] > 0 || rafflePrice[2] > 0 || rafflePrice[3] > 0 || rafflePrice[4] > 0 || rafflePrice[5] > 0) { setRaffleToggle('on',cb.room_slug); } else { cb.sendNotice('Unable to start raffle, no prices have been defined. Raffle is turned off.',cb.room_slug,green); } } else { cb.sendNotice('Unable to start raffle, no prizes have been defined. Raffle is turned off.',cb.room_slug,green); } } // *** Init Lists if(cb.settings.niceList != '' && cb.settings.niceList != null) { var n = cb.settings.niceList; niceListArray = n.split(','); } if(cb.settings.silenceList != '' && cb.settings.silenceList != null) { var n = cb.settings.silenceList; silenceListArray = n.split(','); } if(cb.settings.ninjaList != '' && cb.settings.ninjaList != null) { var n = cb.settings.ninjaList; ninjaListArray = n.split(','); } if(cb.settings.wordBlockList != '' && cb.settings.wordBlockList != null) { var n = cb.settings.wordBlockList; wordListArray = n.split(','); } if(cb.settings.extFanList != '' && cb.settings.extFanList != null) { var n = cb.settings.extFanList; extFanListArray = n.split(','); } if(cb.settings.VIPList != '' && cb.settings.VIPList != null) { var n = cb.settings.VIPList; VIPListArray = n.split(','); } if(cb.settings.hiddenShowOTList != '' && cb.settings.hiddenShowOTList != null) { var n = cb.settings.hiddenShowOTList; outstandingTicketArray = n.split(','); } if(cb.settings.botModList != '' && cb.settings.botModList != null) { var n = cb.settings.botModList; botModListArray = n.split(','); for (var i = 0; i < botModListArray.length; i++) { populateModeratorArray(botModListArray[i], 'botmod', 'a'); } } if(cb.settings.iconNicknameList != '' && cb.settings.iconNicknameList != null) { var n = cb.settings.iconNicknameList; tempnicknamearray = n.split(','); if(tempnicknamearray.length > 0) { for (var i = 0; i < tempnicknamearray.length; i++) { namelink = tempnicknamearray[i].split('/'); if(namelink[0] == '' || namelink[0] == null) { cb.sendNotice('Cannot load icon / nickname list entry ' + tempnicknamearray[i] + ', no user name is provided.', cb.room_slug, green); } else { if (namelink[1] == '') { namelink[1] = null; } if (namelink[2] == '') { namelink[2] = null; } if (namelink[3] == '') { namelink[3] = null; } iconNicknamesArray.name.push(namelink[0]); iconNicknamesArray.icon.push(namelink[1]); iconNicknamesArray.nickname.push(namelink[2]); iconNicknamesArray.color.push(namelink[3]); } } } else { cb.sendNotice('Cannot load nickname list, invalid formatting of list: ' + tempnicknamearray, cb.room_slug, green); } } if(cb.settings.rafflePrizes1 != '' && cb.settings.rafflePrizes1 != null && rafflePrice[1] > 0) { var n = cb.settings.rafflePrizes1; rafflePrizeList1 = n.split(','); } if(cb.settings.rafflePrizes2 != '' && cb.settings.rafflePrizes2 != null && rafflePrice[2] > 0) { var n = cb.settings.rafflePrizes2; rafflePrizeList2 = n.split(','); } if(cb.settings.rafflePrizes3 != '' && cb.settings.rafflePrizes3 != null && rafflePrice[3] > 0) { var n = cb.settings.rafflePrizes3; rafflePrizeList3 = n.split(','); } if(cb.settings.rafflePrizes4 != '' && cb.settings.rafflePrizes4 != null && rafflePrice[4] > 0) { var n = cb.settings.rafflePrizes4; rafflePrizeList4 = n.split(','); } if(cb.settings.rafflePrizes5 != '' && cb.settings.rafflePrizes5 != null && rafflePrice[5] > 0) { var n = cb.settings.rafflePrizes5; rafflePrizeList5 = n.split(','); } //*** Init Ticket Show Features if (ticketShowType == 'Fembot Ticket Show') { if (cb.settings.enableHiddenShow == 'Yes') { if (ticketPrice > 0) { setTicketShowToggle('on', cb.room_slug,ticketPrice); if (cb.settings.enableHiddenShowOT == 'Yes') { setTicketShowOtToggle('on', cb.room_slug); } } else { cb.sendNotice('Unable to start the Fembot Hidden Show feature, a ticket price was not set on the start page. You can either set the price now using the command "/ticketprice [amt]" where [amt] is in the price in tokens, or restart the bot and set the price. The Hidden Show feature can then be started using the command "/useticketshow on". ', cb.room_slug, green); } } } else { if (cb.settings.ticketShowPrice > 0) { setBackupTicketPrice(cb.settings.ticketShowPrice,cb.room_slug) setBackupToggle('on', cb.room_slug); } else { cb.sendNotice('Unable to start the backup list for ticket sales, a planned ticket show price must be set first using the command "/presaleprice xx" or "/ticketprice xx" depending on how tickets are being sold, where xx is in the initial price. Backup list can then be started manually using the command "/usebackup on".', cb.room_slug, green); } } if (enablePresales == 'Yes' && cb.settings.enablePresalesMode != 'No Pre-sales') { if (ticketShowToggle == 0) { if (presalePrice > 0) { if (presalePrice > ticketPrice && ticketPrice > 0) { cb.sendNotice('Unable to start pre-sales, the pre-sales price (' + presalePrice + ' tokens) is greater than the planned ticket show price (' + cb.settings.ticketPrice + ' tokens).\n Use the command "/presaleprice xx" or "/ticketprice xx" to update one of them, where xx is in the price being set, to update and then start pre-sales with the command "/usepresale on".', u, green); } else if (ticketPrice <= 0) { cb.sendNotice('Unable to start pre-sales, the planned price for the Ticket Show is not yet defined. You can use the command "/ticketprice xx", to update the price, where xx is the planned price. The price can be changed later for either type of show but is required now for pre-sales.', u, green); } else { setPresalesToggle('on', cb.room_slug); } } else { cb.sendNotice('Unable to start pre-sales, a pre-sale ticket price must be set first using the command "/presaleprice xx" where xx is in the initial price. Pre-sales can then be started using the command "/usepresale on". ', cb.room_slug, green); } } else { cb.sendNotice('Unable to start pre-sales, the Fembot Ticket Show feature is already started.', cb.room_slug, green); } } populateModeratorArray(cb.room_slug, 'broadcaster', 'a'); cb.sendNotice('** The Fembot silence level is set to "' + silenceLevel + '". \n** The Fembot graphics level is set to "' + graphicLevel + '".', cb.room_slug, green); initialize = 1; } }
© Copyright Chaturbate 2011- 2024. All Rights Reserved.