Bots Home
|
Create an App
AAZ
Author:
ho_2229
Description
Source Code
Launch Bot
Current Users
Created by:
Ho_2229
/** 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 broadcasters and moderators with a single tool to provide most common bot functions, primarily around chat control and personalization. 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, 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 or ticket shoPMw lists or give other special rights without permission. **/ // prototype functions { String.prototype.capitalize = function() {return this.charAt(0).toUpperCase() + this.slice(1);} } { var theme001brightrainbow = 'linear-gradient(to right, #ff6767, #ffdb9a, #ffff9d, #5fd85f, #9f9fff, #ff9bff)'; var theme001pastelrainbow = 'linear-gradient(to right, #ff9a9a, #ffe4b4, #ffffb4, #bfd9bf, #add8e6, #e0d6f4)'; var theme002valentines = 'linear-gradient(to right bottom, #ff7373, #ffe1f1)'; var theme003christmas = 'linear-gradient(to right bottom, #6bdb6b, #ff9a9a)'; var theme004halloween = 'linear-gradient(to right bottom, #ffba67, #ffffb4)'; var theme005blue = 'linear-gradient(to right bottom, #a9c4f5, #d4ebf2)'; var theme006green = 'linear-gradient(to right bottom, #9fc69f, #cfe3cf)'; var theme007pink = 'linear-gradient(to right bottom, #ffb6da, #ffe9ec)'; var theme008purple = 'linear-gradient(to right bottom, #c1adea, #dfd5f5)'; var theme009blackgray = 'linear-gradient(to right bottom, #c6c6c6, #ececec)'; var theme010sunset = 'linear-gradient(to right, #9489c2, #c600fb, #ffa200, #c600fb, #9489c2)'; var theme011abv = 'linear-gradient(to right bottom, #00e0ff, #c600fb, #9489c2)'; var theme012rwb = 'linear-gradient(to right bottom, #ff0000, #ffffff, #0027c1)'; var theme013stpat = 'linear-gradient(to right bottom, #0e7312, #c0e6c3, #0e7312)'; var themeArray = { name: ['Bright Rainbow', 'Pastel Rainbow', 'Valentines', 'Christmas', 'Halloween', 'Shades of Blue', 'Shades of Green', 'Shades of Pink', 'Shades of Purple', 'Black and Gray', 'Sunset', 'Aqua/Blue/Violet', 'Red/White/Blue', 'St Patrick\'s Day' ], colorID: [theme001brightrainbow, theme001pastelrainbow, theme002valentines, theme003christmas, theme004halloween, theme005blue, theme006green, theme007pink, theme008purple, theme009blackgray, theme010sunset, theme011abv, theme012rwb, theme013stpat ], textcolor: ['#00008b', '#00008b', '#c7006b', '#ffffff', '#000000', '#00008b', '#006400', '#d00068', '#663399', '#000000', '#000000', '#d4ebf2', '#000000', '#024604' ]}; // 1 2 3 4 5 6 7 var themeIconArray = { name: ['Rainbow', 'Valentines', 'Christmas', 'Halloween', 'Flowers', '420', 'St Patrick\'s Day' ], db: [':rainbowheart_small', ':coeuryn_icon_heart_blue', ':christmas9_hs', ':sagejackolantern', ':tinydaisy', ':icon_weed', ':fb_stpat_clover' ], lp: [':rainbowtig', ':heart7', ':christmas1_hs', ':ghostautumn', ':tinyflower2', ':bong', ':fb_stpat_hat' ], dp: [':rainbowcrown', ':abbie_heart', ':christmas11_hs', ':blackbat_small', ':tinyflower1', ':mushroom8', ':fb_stpat_gold' ]}; // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var separatorArray = { dispname: ['Vertical Bar', 'Hearts', 'Glitter', 'Flowers', 'Bow', 'Hearts2', 'Smiley', 'Text Heart', 'Text Diamond', 'Text Star', 'Custom', 'Boobs', 'Pot leaf', 'Mushroom', 'Dragon', 'Spinning curly shape', 'Handcuffs' ], charID: ['|', ':heart2', ':pixelglitter',':tinyflower2', ':bluebow', ':Hearts2', ':smile', '\u2665', '\u2666', '\u2605', 'None', ':pixel_boobie', ':icon_weed', ':mushroom8', ':firedragonellie', ':curley_small', ':handcuffs30' ]}; } {cb.settings_choices = [ {name: 'dummy0', label: '---------------------------------------------------------------------------------------------------- Latest Updt: March 22, 2021 (version 4.2) See Change Log for details ----------------------------------------------------------------------------------------------------', type: 'choice',required: false}, {name: 'dummy00', label: 'Welcome ' + cb.room_slug + '!. You can see the full list of commands for the Ultra Fembot by typing "/fbhelp" in the chat (no quotes), and then also see more detailed help by section. The full command list is also on the bot description page. 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! 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 & butter_my_toast', type: 'choice',required: false}, {name: 'emojibar', label: ' \u2B50 ', type: 'choice',required: false}, // *** TOC {name: 'dummytoc1', label: '******************* TABLE OF CONTENTS ***********************', type: 'choice',required: false}, {name: 'dummytoc1a', label: 'Section_0.......General Settings & Bot Personalization---------------------', type: 'choice',required: false}, {name: 'dummytoc2', label: 'Section_1.......Notifications and Messages--------------------------------------', type: 'choice',required: false}, {name: 'dummytoc3', label: 'Section_2.......Tip Count Tracking and Leaderboard-------------------------', type: 'choice',required: false}, {name: 'dummytoc4', label: 'Section_3.......King Tipper Settings------------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc5', label: 'Section_4.......Chat Control and Spam Blocking-------------------------------', type: 'choice',required: false}, {name: 'dummytoc6', label: 'Section_5.......Automated Responses---------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc7', label: 'Section_6.......Viewer Notes----------------------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc8', label: 'Section_7.......Icons and User Group Personalization------------------------', type: 'choice',required: false}, {name: 'dummytoc9', label: 'Section_8.......VIP List-------------------------------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc10', label: 'Section_9.......External Fan Clubs 1 and 2---------------------------------------', type: 'choice',required: false}, {name: 'dummytoc11', label: 'Section_10......Blocked Word List---------------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc12', label: 'Section_11......Tip Menus 1 and 2---------------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc13', label: 'Section_12......Positions Tip Menu-------------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc14', label: 'Section_13......Token Poll--------------------------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc15', label: 'Section_14......Ticket Show Support-----------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc16', label: 'Section_15......Fembot Ticket Show Setup--------------------------------------', type: 'choice',required: false}, {name: 'dummytoc17', label: 'Section_16......Toy Menu---------------------------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc18', label: 'Section_17......Media List--------------------------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc19', label: 'Section_18......Dice Game-------------------------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc20', label: 'Section_19......Room Rules-----------------------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc21', label: 'Section_20......Followers--------------------------------------------------------------', type: 'choice',required: false}, {name: 'dummytoc22', label: 'Section_21......Text Poll----------------------------------------------------------------', type: 'choice',required: false}, // *** General Settings {name: 'dummy01', label: '---------------------------------------------------------------------------------------------------- SECTION 0 - GENERAL SETTINGS & BOT PERSONALIZATION', type: 'choice',required: false}, {name: 'dummy01a', label: 'This section is new and will be expanded in the future with additional themes and colors to further personalize how the bot looks for your room. Please send us your feedback and ideas! (twitter ID above).', type: 'choice',required: false}, {name: 'bctext', label: '0A. Broadcaster Display Name -- This value will replace the general term "broadcaster" and in some cases the room name with the name of your choosing (the name you would like to be called, couples name, etc) wherever it appears in chat notices. Leave blank to just use "The Broadcaster".', type: 'str',required: false, minLength: 1, maxLength: 50}, {name: 'colorTheme', label: '0B. Use a color theme in all recurring notice text backgrounds? -- This will trigger all background highlighting in the different recurring notices and menus (rotating notifier, tip menu, token poll, room rules, etc) to follow the same color theme. If choosing "none" (default), the colors defined in each individual bot feature section are used. If choosing one of the existing themes or a custom theme, the individual color settings will be overridden and the theme colors will be used for all recurring notices (does not include user chat or bot responses and warnings). When choosing "custom", enter your chosen colors below in settings 0C1-0C4. Note that if a specific theme is used, it will always show a diagonal gradient, and setting "0D" below is ignored. More color themes will be added, send me your requests!', type: 'choice', choice1: 'None', choice2: 'Custom Linear', choice3: 'Placeholder - do not use', choice4: themeArray.name[0], choice5: themeArray.name[1], choice6: themeArray.name[2], choice7: themeArray.name[3], choice8: themeArray.name[4], choice9: themeArray.name[5], choice10: themeArray.name[6], choice11: themeArray.name[7], choice12: themeArray.name[8], choice13: themeArray.name[9], choice14: themeArray.name[10], choice15: themeArray.name[11], choice16: themeArray.name[12], choice17: themeArray.name[13], defaultValue: 'None'}, {name: 'colorThemeCustBg1', label: '0C1. Custom Color 1 - If you picked "custom" color theme above in setting 0B, enter the hex color code for background color 1 ("#" prefix plus the 6 character hex color codes, such #ffffff)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'colorThemeCustBg2', label: '0C2. Custom Color 2 - If you picked "custom" color theme above in setting 0B, enter the hex color code for background color 2, it will default to white (#ffffff) if none is chosen as two colors are required',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'colorThemeCustBg3', label: '0C3. Custom Color 3 - If you picked "custom" color theme above in setting 0B, enter the hex color code for background color 3 (optional)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'colorThemeCustText', label: '0C4. Custom Text Color - If you picked "custom" color theme above in setting 0B, enter the hex color code for text - it will default to white if none is chosen', type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'colorsGradientDirection', label: '0D. Use a color gradient (gradual fade from one color to another) in all recurring notice backgrounds? -- This will trigger all background highlighting in the different recurring notices to follow a similar gradient pattern. If choosing "Linear" for the gradual color change (from the defined color to white), you can also choose the direction of the fade - left right, top to bottom, or diagonal. A placeholder is also in the list for possibly have a "circular" gradient but as of now CB does not support that. Note that the gradient setting only affects the shading pattern, the actual colors used are defined either in the individual bot feature sections or overriden above in setting "0B" or "0C1-3". Also note that if a pre-configured color theme is used above, the gradient direction is unique to the theme and this gradient setting will be ignored', type: 'choice', choice1: 'No', choice2: 'Linear, left to right', choice3: 'Linear, top to bottom', choice4: 'Linear, diagonally', defaultValue: 'No'}, {name: 'exemptCommandList', label: '0E. Exempt Command List -- Enter any commands that you want the Fembot to skip when checking for invalid commands that start with "/" (to prevent Fembot error messages for commands used in other bots). Enter the list separated by commas, including the "/" for each entry (example list would be "/botcmd1, /appcmd1, appcmd2" but with no quotes)', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'modLevel', label: '0F. Moderator Trust Level -- This will control how much authority and access is granted to moderators. This applies to CB mods and bot mods, and the same moderator level is applied to all moderators (not user specific). There are 3 levels - Basic, Standard, and Advanced. "Standard" covers most of what mods are normally able to do and will be the default. Basic gives less access which is ideal when you are newer and may not have trusted mods yet. "Advanced" gives them mostly the same abilities as a broadcaster, with the exception of editing or viewing the Private Blocked Word List, and seeing User Notes. See the bot description page for a full listing of the Access for each mod level.', type: 'choice', choice1: 'Basic', choice2: 'Standard', choice3: 'Advanced', defaultValue: 'Standard'}, {name: 'botModList', label: '0G. Bot Mods List -- 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: 'noticeSepStyle', label: '0H1. Notice Border Style -- This control how the top and bottom border of several of the recurring notices is displayed. You can choose from the defined options here, or use the below setting for "0H2" to define your own emoji or other character. Depending on the type you choose, the spacing of the border will be different, so be sure to select the matching type here for the emoji or character you set below.', type: 'choice', choice1: 'No Border', choice2: 'Light Dashed Line', choice3: 'Heavy Dashed Line', choice4: 'Custom Emoji Below', choice5: 'Custom Unicode Character Below', defaultValue: 'Light Dashed Line'}, {name: 'separatorEmoji', label: '0H2. Notice Border emoji or text/unicode character -- For an emoji or unicode character, paste the actual emoji/image here, not the code (not \u2580 for example). Note that most unicode characters have the benfit of being the same color as your text. The borders are currently used for leaderboard, media info, room rules, dice game, and icon tip notices. Do NOT use a CB icon here, if you do, it will default to "Heavy Dashed Line". You can use the command /setemjsep to update the emoji separator during your show and play around with them to find one that has the color and spacing you are looking for.', type: 'str',minLength: 0,maxLength: 2,required: false}, // *** Messages and Notifications {name: 'dummy1', label: '---------------------------------------------------------------------------------------------------- SECTION 1 - NOTIFICATIONS AND MESSAGING', type: 'choice',required: false}, {name: 'enableEntryMessage', label: '1B. Enable "Welcome" message? -- Message will use same colors as defined in 1H-1L, even if notifiers not enabled.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'entryMessage', label: '1C. "Welcome" message -- Note that you can include the substitution identifier {username} within your welcome text to have the username of the person joining the room show in the welcome message. Just make sure there is a space on either side of {username} so that it is recognized (a comma immediately following is ok). The substitution identifier {n} can also be inserted into the message to force a break to a new line (must also be separated from other text and punctuation by a space)', type: 'str',required: false, minLength: 1, maxLength: 1000, defaultValue: 'Welcome {username} to my room! Please have a great time and treat your fellow chatters with kindness. {n} Rude comments and demands will not be tolerated.'}, {name: 'minMessagesForNotice', label: '1D. Limit Notice Displays for Slow Chat -- Minimum number of messages required to display the next of each type of notice. This helps reduce the frequency with which certain recurring notices are posted (such as tip menu, room rules, lush menu, dice announcement, etc) if there are not a lot of messages in the chat so that the chat is not flooded only by notices. Set to 0 to not impose a minimum number of messages. Values of 10-25 are commonly used but may be set lower if the chat is really slow, or higher if the chat is busy, although if the chat is busy, the normal time interval is usually fine and will not be restricted by this setting.', type: 'int',minValue: 0,maxValue: 1000,defaultValue: 0}, // {name: 'minTimeForNotice', label: '1D2. Limit Notice Display Frequency -- Minimum time required between individual notices, in seconds. This helps prevent multiple notices that may be on the same interval schedule from being displayed at the same time and waching away the chat. Set to 0 to diasble.', type: 'choice', choice1: 0,choice2: 5,choice3: 10,choice4: 15,choice5: 20,choice6: 25,choice7: 30,defaultValue: 10}, {name: 'enableNotifier', label: '1E. Enable Rotating Notifier? -- Up to 9 messages can be displayed in rotation according to the interval specified below', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'notifierMessage1', label: '1F. Notification Message #1 -- The text {n} can be inserted into each notifier to force a break to a new line (must be separated from other text and punctuation by a space)',required: false, type: 'str', minLength: 1, maxLength: 1000, defaultValue: 'Welcome everyone to the show!'}, {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: 'notifierMessage6', label: 'Notification Message #6', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage7', label: 'Notification Message #7', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage8', label: 'Notification Message #8', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage9', label: 'Notification Message #9', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierInterval', label: '1G. Rotating Notifier display interval -- Defined in minutes. Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.',type: 'str',defaultValue: 3.1,required: false}, {name: 'notifiersTextColor', label: '1H. Notice Text color -- Used for Notifier Messages above and Chat Notices triggered from commands (/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', label: '1J. Notice Custom Text color -- If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'notifiersBgColor', label: '1K. Notice 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 Aqua'}, {name: 'notifiersBgCustColor', label: '1L. Notice Custom Background Color -- Enter the hex color (6 character hex color codes plus the # prefix)', type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'enableTipResponse', label: '1M. Enable Automatic Tip Response? -- Messages for up to 5 tip thresholds can be specified below to automatically respond to the tipper. Note that you can include the identifier {username} to have the username of the person show in the message (including brackets). Just make sure there is a space on either side of {username} so that it is recognized.', type: 'choice', choice1: 'No', choice2: 'Yes, send to tipper', choice3: 'Yes, send to all', defaultValue: 'No'}, {name: 'tipResponseAmount1', label: '1N1. Tip Threshold 1',type: 'int',required: false,minValue: 1,maxValue: 99999,defaultValue: 25}, {name: 'tipResponseMessage1', label: '1N2. Tip Response Message 1 -- Displayed for tips greater than Threshold 1 and less than Threshold 2',required: false, type: 'str', minLength: 1, maxLength: 100, defaultValue: 'Thank you for tipping!'}, {name: 'tipResponseAmount2', label: '1N3. Tip Threshold 2',type: 'int',minValue: 1,maxValue: 99999,defaultValue: 100,required: false}, {name: 'tipResponseMessage2', label: '1N4. Tip Response Message 2 -- Displayed for tips greater than Threshold 2 and less than Threshold 3',required: false, type: 'str', minLength: 1, maxLength: 100, defaultValue: 'Wow! Thank you very much for tipping!'}, {name: 'tipResponseAmount3', label: '1N5. Tip Threshold 3',type: 'int',minValue: 1,maxValue: 99999,defaultValue: 250,required: false}, {name: 'tipResponseMessage3', label: '1N6. Tip Response Message 3 -- Displayed for tips greater than Threshold 3 and less than Threshold 4',required: false, type: 'str', minLength: 1, maxLength: 100, defaultValue: 'Amazing Tip! Thank you so much for your generosity!'}, {name: 'tipResponseAmount4', label: '1N7. Tip Threshold 4',type: 'int',minValue: 1,maxValue: 99999,defaultValue: 500,required: false}, {name: 'tipResponseMessage4', label: '1N8. Tip Response Message 4 -- Displayed for tips greater than Threshold 4 and less than Threshold 5',required: false, type: 'str', minLength: 1, maxLength: 100, defaultValue: 'I am speechless! Thank you for your amazing kindness!'}, {name: 'tipResponseAmount5', label: '1N9. Tip Threshold 5',type: 'int',minValue: 1,maxValue: 99999,defaultValue: 1000,required: false}, {name: 'tipResponseMessage5', label: '1N10. Tip Response Message 5 -- Displayed for tips greater than Threshold 5',required: false, type: 'str', minLength: 1, maxLength: 100, defaultValue: 'OMG! All hail the king!'}, {name: 'defaultTimerDesc', label: '1Q. Optional Timer Description -- 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 "/chgclockdesc". Max length of 30 characters',required: false, type: 'str', minLength: 1, maxLength: 30}, {name: 'defaultTimerDesc2', label: '1R. Optional Timer #2 Description -- Enter the description you would like to use for the general timer #2 (/startclock2 function). The value will be displayed in the countdown text, and can be changed during the show with the command "/chgclock2desc". Max length of 30 characters',required: false, type: 'str', minLength: 1, maxLength: 30}, // *** Tip Count and Leaderboard {name: 'dummy2', label: '---------------------------------------------------------------------------------------------------- SECTION 2 - TIP COUNT AND LEADERBOARD', type: 'choice',required: false}, {name: 'enableSubjectChange', label: '2A. 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: '2B. Display user tip count as prefix in messages?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'enableTipLeaderIcons', label: '2C. 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', label: '2D1. Choose the icon to be displayed for the top tipper of the current session (optional). Note this will be overridden by a King Tipper icon if enabled in setting 3L and defined in 3N. 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', type: 'str',defaultValue: ':crowngold',required: false}, {name: 'tipLeaderGif2', label: '2D2. Choose the icon to be displayed for the second highest tipper of the current session (optional).', type: 'str',defaultValue: ':mtlhfu2',required: false}, {name: 'tipLeaderGif3', label: '2D3. Choose the icon to be displayed for the third highest tipper of the current session (optional).', type: 'str',defaultValue: ':mtlhfu3 ',required: false}, {name: 'enableLeaderboard', label: '2G. Display the leaderboard in the chat (top X tippers in current session, length defined below)?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'leaderBoardSize', label: '2H. Leaderboard length - Number of top tipper positions to show on the leaderboard (from 3 to 10)', type: 'int',required: false, minValue: 3, maxValue: 10, defaultValue: 5}, {name: 'leaderInterval', label: '2J. Leaderboard display interval in minutes. Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.', type: 'str',defaultValue: 3.4,required: false}, {name: 'leaderTextColor', label: '2K. 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', label: '2L. If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'leaderBgColor', label: '2M. 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', label: '2N. If you picked a custom background highlight color in the previous setting, enter the hex color (6character hex color codes including the # prefix)', type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'enableAllTime', label: '2P. 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: '2Q. All Time Tipper List display interval (in minutes). 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 frequently, so 30 minutes is a typical default. Decimals are ok as long as they are greater than 1.', type: 'str',defaultValue: 0,required: false}, {name: 'allTimeTipperList', label: '2R. 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}, {name: 'allTimeAmount1', label: '2S1. All-time Token Threshold 1 - All-time tipper levels above this threshold (and below the next threshold) are awarded the Level 1 icon',type: 'int',minValue: 0,maxValue: 99999,required: false}, {name: 'allTimeIcon1', label: '2S2. Level 1 Icon - Make sure to include the colon (:) as it would be typed in the chat',type: 'str',minLength: 0,maxLength: 50,required: false}, {name: 'allTimeAmount2', label: '2S3. All-time Token Threshold 2',type: 'int',minValue: 0,maxValue: 99999,required: false}, {name: 'allTimeIcon2', label: '2S4. Level 2 Icon',type: 'str',minLength: 0,maxLength: 50,required: false}, {name: 'allTimeAmount3', label: '2S5. All-time Token Threshold 3',type: 'int',minValue: 0,maxValue: 99999,required: false}, {name: 'allTimeIcon3', label: '2S6. Level 3 Icon',type: 'str',minLength: 0,maxLength: 50,required: false}, {name: 'allTimeAmount4', label: '2S7. All-time Token Threshold 4',type: 'int',minValue: 0,maxValue: 99999,required: false}, {name: 'allTimeIcon4', label: '2S8. Level 4 Icon',type: 'str',minLength: 0,maxLength: 50,required: false}, {name: 'allTimeAmount5', label: '2S9. All-time Token Threshold 5',type: 'int',minValue: 0,maxValue: 99999,required: false}, {name: 'allTimeIcon5', label: '2S10. Level 5 Icon',type: 'str',minLength: 0,maxLength: 50,required: false}, {name: 'allTimeAmount6', label: '2S11. All-time Token Threshold 6',type: 'int',minValue: 0,maxValue: 99999,required: false}, {name: 'allTimeIcon6', label: '2S12. Level 6 Icon',type: 'str',minLength: 0,maxLength: 50,required: false}, {name: 'allTimeAmount7', label: '2S13. All-time Token Threshold 7',type: 'int',minValue: 0,maxValue: 99999,required: false}, {name: 'allTimeIcon7', label: '2S14. Level 7 Icon',type: 'str',minLength: 0,maxLength: 50,required: false}, {name: 'allTimeAmount8', label: '2S15. All-time Token Threshold 8',type: 'int',minValue: 0,maxValue: 99999,required: false}, {name: 'allTimeIcon8', label: '2S16. Level 8 Icon',type: 'str',minLength: 0,maxLength: 50,required: false}, // *** King Tipper {name: 'dummyking', label: '---------------------------------------------------------------------------------------------------- SECTION 3 - KING TIPPER SETTINGS', type: 'choice',required: false}, {name: 'dummyking0', label: 'The settings in 3A-3J deal with All-time King Tippers, the settings in 3L-3P deal with the Current Session King Tipper.', type: 'choice',required: false}, {name: 'dummyking1', label: '----- ALL-TIME KING TIPPER SETTINGS -----', type: 'choice',required: false}, {name: 'kingEnable', label: '3A. Enable All-Time King Tipper -- Should the All-time King Tipper Feature be used? And if so, should the king tipper be pulled from the All-time Tipper list (that must be enabled and entered in the above section) or specified below. For either case, the icon, nickname, announcement text, and welcome message can still be used. They are not all required, whatever is configured will be used', type: 'choice', choice1: 'No', choice2: 'Yes, define user below', choice3: 'Yes, use All Time list', defaultValue: 'No'}, {name: 'kingTipperName', label: '3B. All-time King Tipper Name -- If setting 3A is "Yes, define user below", set the user name here.', required: false,type: 'str', minLength: 1, maxLength: 100}, {name: 'kingTipperAmount', label: '3C. All-time King Tipper Amount -- If setting 3A is "Yes, define user below", set the total tip amount for the King Tipper', type: 'int',minValue: 0,maxValue: 9999999,defaultValue: 0,required: false}, {name: 'kingTipperIcon', label: '3D. All-time King Tipper Icon -- (Optional) For either choice above, define the icon to be shown in front of the King Tipper\'s username. 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. Note this will replace any other icons they may otherwise be granted by he nickname/icon list, or their group, or current session top 3 tip leader.' , type: 'str',defaultValue: ':crown10',required: false}, {name: 'kingTipperNickname', label: '3E. All-time King Tipper Nickname -- (Optional) For either choice above, define the nickname to be shown in front of the King Tipper\'s username of their chat messages. Note this will replace any nicknames previously assigned through the nickname list or by command.', type: 'str',defaultValue: 'The KING!',required: false}, {name: 'kingTipperTitle', label: '3F. All-time King Tipper Title -- (Optional) For either choice above, define their title to be used in the recurring King Tipper Notice.', type: 'str',defaultValue: 'KING!',required: false}, {name: 'kingTipperWelcome', label: '3G. All-time King Tipper Welcome Message -- (Optional) If you would like a welcome message to be sent to the chat when the All Time King Tipper joins the room, it can be entered here. The text {username} can be imbedded in the message to show the user', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'kingTipperHighlight', label: '3H1. Highlight the All-time King Tipper\'s Chat Messages? If enabling, choose color below in settings 3H2-3H3', type: 'choice', choice1: 'No', choice2: 'Yes', defaultValue: 'No'}, {name: 'kingTipperBgColor', label: '3H2. Background color used for King Tipper Chat and Announcement', 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 Purple'}, {name: 'kingTipperBgCustColor', label: '3H3. If you picked a custom highlight color in the previous setting, enter the hex color (6character hex color codes including the # prefix)', type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'kingTipperNotice', label: '3J1. All-time King Tipper Recurring Notice -- (Optional) Text notice. By default it will show "[Username] is the [Title]!" (the token count to take over high tipper is also shown if defined above or from the All Time list). If you would like any text to appear after this message, it can be entered here', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'kingTipperInterval', label: '3J2. All-time King Tipper Recurring Notice (minutes). Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.', type: 'str',defaultValue: 6.5,required: false}, {name: 'kingTipperTextColor', label: '3J3. Text color used for King Tipper Recurring Notice', 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: 'Black'}, {name: 'kingTipperTextCustColor', label: '3J4. If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'kingTipperNoticeColor', label: '3J5. Background color used for King Tipper Recurring Notice', 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 Purple'}, {name: 'kingTipperNoticeCustColor', label: '3J6. If you picked a custom notice highlight color in the previous setting, enter the hex color (6character hex color codes including the # prefix)', type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'dummyking2', label: '----- CURRENT SESSION KING TIPPER SETTINGS -----', type: 'choice',required: false}, {name: 'kingSessionEnable', label: '3L. Enable Current Session King Tipper -- Once any viewer reaches the minimum amount below, display a notice each time a new user takes over the tip lead? Note that the "new king" notification will not occur if a user tips anonymously', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'kingSessionMinAmount', label: '3M. Current Session King Tipper Minimum Amount -- Set the minimum tip tip total for a user that must be reached before the bot starts tracking the current session king tipper', type: 'int',minValue: 0,maxValue: 999999,defaultValue: 100,required: false}, {name: 'kingSessionIcon', label: '3N. Choose the icon to be displayed next to the username for the current session King Tipper. The icon defined here will override anything defined in setting 2D for the tip leader when tip leader icons are used. It can be a CB 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', type: 'str',required: false, defaultValue: ':crowngif282'}, {name: 'kingSessionInterval', label: '3P1. Current Session King Tipper Recurring Notice (minutes). Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals. Set to zero to disable. If enabled, will display a notice for users to tip at least X tokens to become the new King Tipper for this show', type: 'str',defaultValue: 5.7,required: false}, {name: 'kingSessionTextColor', label: '3P2. Text color used for Current Session King Tipper Recurring Notice', 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: 'Black'}, {name: 'kingSessionTextCustColor', label: '3P3. If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'kingSessionNoticeColor', label: '3P4. Background color used for Current Session King Tipper Recurring Notice', 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 Purple'}, {name: 'kingSessionNoticeCustColor',label: '3P5. If you picked a custom notice highlight color in the previous setting, enter the hex color (6character hex color codes including the # prefix)', type: 'str',minLength: 1,maxLength: 7,required: false}, // *** Chat Controls {name: 'dummy3', label: '---------------------------------------------------------------------------------------------------- SECTION 4 - CHAT CONTROLS ', type: 'choice',required: false}, {name: 'dummy3a', 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: '4B. Permanent Silence List -- 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: '4C. 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: '4E. Permanent Ninja List -- 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: '4F. 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: '4G. Nice List -- 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: '4H. Allow VIPs, CB Fanclub and External Fanclub members to PM you and other viewers in the chat using the /pm and /bc commands. Note this does not impact the ability for CB Supporter subscribers or CB Fanclub members to PM you or other users through the PM tab', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'requireAnswerLevel', label: '4J. Answer Lock / Captcha -- 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: '4K. Time Lock -- 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', label: '4L. If gray chat is locked upon entering, set the time threshold (in minutes) for when they can begin chatting.',type: 'int',minValue: 1,maxValue: 20,defaultValue: 5,required: false}, {name: 'initialSilenceLevel', label: '4N. Initial Silence Level -- Define who can chat, can be changed during the show with the /sl command (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)', type: 'int',minValue: 0,maxValue: 4, defaultValue: 0}, {name: 'initialGraphicsLevel', label: '4P. Initial Graphics Level -- Define who can post gifs, can be changed during show with the /gl command (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)', type: 'int',minValue: 0,maxValue: 4, defaultValue: 1}, {name: 'minTipToChat', label: '4Q. For Silence Level and Graphic Level 3, set the minimum tip amount to allow chatting or graphics', type: 'int',minValue: 1,maxValue: 1000, defaultValue: 25}, {name: 'restrictEnglishChar', label: '4R. Restrict gray and light blue chat to English (Latin) Keyboard characters? This can help prevent chat from spam bots that use special characters other than standard ASCII (standard English letters and punctuation) to get around word block filters. Note this will also block the use of emojis (true emojis, not CB gifs) for gray and light blue users', type: 'choice', choice1: 'No', choice2: 'Yes', defaultValue: 'No'}, {name: 'autoUpdateSLGL', label: '4S. Auto-update silence and graphic level as the room size increases. If enabled, as the room size crosses the thresholds in the below settings 4S2 and 4S3, the silence level will be increased to make the chat manageable. Can be configured to also decrease the silence level as the room size falls. Note that it will not include anonymous users in the count for comparison, only the total number of registered users who are able to chat. You can use both settings or only one or the other', type: 'choice', choice1: 'No', choice2: 'Yes, during Increase Only', choice3: 'Yes, during Increase and Decrease', defaultValue: 'No'}, {name: 'silenceGraysThreshold', label: '4T. Room Size to suppress chat and graphics from gray users automatically. Set to 0 if not used.', type: 'int',minValue: 0,maxValue: 99999, defaultValue: 0}, {name: 'silenceNonTipThreshold', label: '4U. Room Size to suppress chat and graphics from non-tippers automatically. Set to 0 if not used.', type: 'int',minValue: 0,maxValue: 99999, defaultValue: 0}, // *** Auto Responses {name: 'dummyresponse', label: '---------------------------------------------------------------------------------------------------- SECTION 5 - AUTOMATED RESPONSES', type: 'choice',required: false}, {name: 'enablePMResponse', label: '5A. Automated PM Response? -- Enable or disable the automatic reponse if a non-broadcaster/mod/fan uses a word like "PM" in a message. If yes, define the response message in the next setting. The text {n} can be inserted into the message to force a break to a new line (must be separated from other text and punctuation by a space)', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'pmResponseMessage', label: '5B. PM Response Message -- Enter the Message you would like to display in the chat if PM response is enabled. Be sure to update the default text if you enable the response',required: false, type: 'str', minLength: 1, maxLength: 100, defaultValue: 'Broadcaster does not do PMs during the show / PMs are xx tokens, see tip menu'}, {name: 'enablePrvResponse', label: '5C. Automated Privates Response? -- Enable or disable the automatic reponse if a non-broadcaster/mod/fan uses a word like "private?" in a message. If yes, define the response message in the next setting', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'prvResponseMessage', label: '5D. Privates Response Message -- Enter the Message you would like to display in the chat in response to people asking about privates. Can also be displayed on demand using the /prv command. The text {n} can be inserted into the message to force a break to a new line (must be separated from other text and punctuation by a space)',required: false, type: 'str', minLength: 1, maxLength: 150, defaultValue: 'We do not do privates during the broadcast, please email/tweet to xxxx@xxxx to discuss a private show.'}, {name: 'commandResponse1', label: '5E1. Command Response 1 -- Enter a Message you would like to display when you use the shortcut command /rsp1. The text {n} can be inserted into the message to force a break to a new line (must be separated from other text and punctuation by a space). This will most often be used to respond to a commonly asked question, so you don\'t have to type it out everytime, such as "What is your bra size?" or "What is your twitter ID?"',required: false, type: 'str', minLength: 0, maxLength: 150}, {name: 'commandResponse2', label: '5E2. Command Response 2 -- Enter a Message you would like to display when you use the shortcut command /rsp2.',required: false, type: 'str', minLength: 0, maxLength: 150}, {name: 'commandResponse3', label: '5E3. Command Response 3 -- Enter a Message you would like to display when you use the shortcut command /rsp3.',required: false, type: 'str', minLength: 0, maxLength: 150}, {name: 'commandResponse4', label: '5E4. Command Response 4 -- Enter a Message you would like to display when you use the shortcut command /rsp4.',required: false, type: 'str', minLength: 0, maxLength: 150}, {name: 'commandResponse5', label: '5E5. Command Response 5 -- Enter a Message you would like to display when you use the shortcut command /rsp5.',required: false, type: 'str', minLength: 0, maxLength: 150}, {name: 'enableAutoResponse', label: '5H. Automated keyword response checking? Enabling only for users with tokens can help keep the performance optimal by not checking every message in the chat, if it not necessary to check messages from gray users.', type: 'choice', choice1: 'No Automated Responses', choice2: 'Respond to Users with Tokens', choice3: 'Respond to All Users', defaultValue: 'No Automated Responses'}, {name: 'autoResponseWord1', label: '5J1. Automatic Response Keyword 1 -- Enter the word or phrase you would like to check for. The length is limited to 15 characters so as to ensure the checking of messages does not hamper performance. Be sure to use a specific word or phrase that will not commonly be used in the chat except for in the targeted manner',required: false, type: 'str', minLength: 0, maxLength: 15}, {name: 'autoResponse1', label: '5J2. Automatic Response 1 -- Enter a Message you would like to display when someone enters the above defined keyword or phrase. The text {n} can be inserted into the message to force a break to a new line (must be separated from other text and punctuation by a space).',required: false, type: 'str', minLength: 0, maxLength: 150}, {name: 'autoResponseWord2', label: '5J3. Automatic Response Keyword 2 -- Enter a second word or phrase you would like to check for.',required: false, type: 'str', minLength: 0, maxLength: 15}, {name: 'autoResponse2', label: '5J4. Automatic Response 2 -- Enter a Message you would like to display when someone enters the above defined keyword or phrase.',required: false, type: 'str', minLength: 0, maxLength: 150}, {name: 'autoResponseWord3', label: '5J5. Automatic Response Keyword 3 -- Enter a third word or phrase you would like to check for.',required: false, type: 'str', minLength: 0, maxLength: 15}, {name: 'autoResponse3', label: '5J6. Automatic Response 3 -- Enter a Message you would like to display when someone enters the above defined keyword or phrase.',required: false, type: 'str', minLength: 0, maxLength: 150}, {name: 'tipNoteForwardID', label: '5Q. Tip note forwarding -- A single user ID that can be configured to receive forwarded tip notes. This may be used if the broadcaster is logging in with an alternate ID to view the room or if doing a collaborative broadcast so the tip notes to one user are seen by the other. *** NOTE: If the mod trust level (setting "0D") is set to "Advanced", this value can be set to "*ALLMODS" (no quotes) to forward the tip notes to the full CB mod list (not bot mods). *** WARNING: It is generally not a good idea for tip notes to be seen by someone other than the broadcaster. The alternate ID will only be allowed to see the messages if they are a broadcaster, moderator or bot moderator', type: 'str',minLength: 0,maxLength: 25,required: false}, // *** Viewer Notes {name: 'dummynotes', label: '---------------------------------------------------------------------------------------------------- SECTION 6 - VIEWER NOTES', type: 'choice',required: false}, {name: 'dummynotes2', label: 'Configure a private list of notes for yourself to remember the nicknames and other personal details (good or bad) of the people you would like to see reminders for in the chat. ', type: 'choice',required: false}, {name: 'viewerNotesList', label: '6A. Viewer Notes - Separate the username and note for each of the entries with a slash (/), and put carets (^) between the user entries. Make sure not to use "/" or "^" in your descriptions. For example (no quotes) "username1/nickname1 - he has a cat named Fred^username2/nickname2^username3/John is an artist who likes nipple play". You can also use this as a private notification when certain people are in the room.', type: 'str', minLength: 0, maxLength: 99999, defaultValue: 'username1/reminder1^username2/reminder2', required: false}, {name: 'viewerNotesWhen', label: '6B. If using Viewer Notes, define when you would like to see the note - the first time they enter the room during a show, each time the enter the room, or the first time they chat during a show', type: 'choice', choice1: 'Do not Show', choice2: 'First Entry', choice3: 'Every Entry', choice4: 'First Chat', defaultValue: 'Do not Show'}, {name: 'viewerNotesWho', label: '6C. If using Viewer Notes, define who you would like to send the notes to. Warning! if you set this to show to moderators also, and you enter notes about the moderator, they will see the notes!', type: 'choice', choice1: 'Display to Broadcaster only', choice2: 'Display to Broadcaster and Moderators', defaultValue: 'Display to Broadcaster only'}, // *** Personalization {name: 'dummy4', label: '---------------------------------------------------------------------------------------------------- SECTION 7 - ICONS AND GROUP PERSONALIZATION', type: 'choice',required: false}, {name: 'enableGroupIcons', label: '7A. Enable group icons (gifs) to be displayed in front of a user name for the moderators and CB Fanclub. The settings for external Fanclub 1 & 2 and VIP list are further below in those sections.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'iconMods', label: '7B. 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', type: 'str',required: false}, {name: 'iconBotMods', label: '7D. 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.', type: 'str',required: false}, {name: 'moderatorHighlight', label: '7E. Highlight Moderator Chat? (light red)', type: 'choice', choice1: 'No', choice2: 'Yes', defaultValue: 'No'}, {name: 'iconFans', label: '7F. Choose the personalized icon to be displayed for the chaturbate fanclub group of users (optional)', type: 'str',required: false}, {name: 'fanclubHighlight', label: '7G. Highlight CB Fanclub Chat? (light green)', type: 'choice', choice1: 'No', choice2: 'Yes', defaultValue: 'No'}, {name: 'iconNicknameList', label: '7H. 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: 99999, defaultValue: 'name1/:icon1/nickname1/color1', required: false}, {name: 'dummy4a', label: '*** Tip for Icons -- Set the tip amount that people can tip to be rewarded with the corresponding icon by their name for the rest of the current show (specific tip amount or cumulative amount per the below setting). Then enter the icon (gif) ID to be used for people who tip the amount for that group. Be sure to use small/short gifs that do not take up a significant amount of space. Make sure to include the ":" in the name of the gif ID. You can also use unicode characters instead of gifs. Be sure to set the groups in ascending order by tip amount', type: 'choice',required: false}, {name: 'tipForIconType', label: '7J. Tip Amount Type -- Will the amounts below for groups 1-5 be defined as single tip amounts, or cumulative amounts?.', type: 'choice', choice1: 'Specific Tip Amount', choice2: 'Cumulative Tip Amount', defaultValue: 'Specific Tip Amount'}, {name: 'iconTipAmount1', label: '7K1. Group 1 Amount -- Set the exact tip amount that people can tip to be rewarded with the below Group 1 icon by their name.',type: 'int',required: false,minValue: 1,maxValue: 99999}, {name: 'iconTipIcon1', label: '7K2. Group 1 icon -- Choose the gif to be used for people who tip the exact amount above for this group. Be sure to use small/short gifs that do not take up a significant amount of space. Make sure to include the ":" in the name of the tag. You can also use unicode characters instead of gifs', type: 'str',required: false}, {name: 'iconTipAmount2', label: '7K3. Group 2 Amount',type: 'int',required: false,minValue: 1,maxValue: 99999}, {name: 'iconTipIcon2', label: '7K4. Group 2 icon', type: 'str',required: false}, {name: 'iconTipAmount3', label: '7K5. Group 3 Amount',type: 'int',required: false,minValue: 1,maxValue: 99999}, {name: 'iconTipIcon3', label: '7K6. Group 3 icon', type: 'str',required: false}, {name: 'iconTipAmount4', label: '7K7. Group 4 Amount',type: 'int',required: false,minValue: 1,maxValue: 99999}, {name: 'iconTipIcon4', label: '7K8. Group 4 icon', type: 'str',required: false}, {name: 'iconTipAmount5', label: '7K9. Group 5 Amount',type: 'int',required: false,minValue: 1,maxValue: 99999}, {name: 'iconTipIcon5', label: '7K10. Group 5 icon', type: 'str',required: false}, {name: 'iconTipNoticeInt', label: '7L. If you would like a notice to be displayed in the chat showing the above tip amounts to buy an icon for this show, define the notice interval here, else leave it at zero. Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.', type: 'str',defaultValue: 5.5,required: false,}, {name: 'iconTheme', label: '7M. Icon and Emoji Themes? -- If enabled, this will give the dark blue, light purple and dark purple users an icon or an emoji next to their name (fans, mods and VIPs can be given icons in previous sections). If you choose "Custom", you can identify the icon to use for each of these groups below in settings 7N1-7N3, otherwise the provided themes have pre-defined icons. If entering a CB gif name, include the ":" as part of the name. You can also use emojis. Individual personalization settings from setting 7H or external fan club and VIP icons are higher priority and will override the general blue and purple group settings defined here. More icon themes will be added, send me your requests!', type: 'choice', choice1: 'None', choice2: 'Custom', choice3: themeIconArray.name[0], choice4: themeIconArray.name[1], choice4: themeIconArray.name[2], choice5: themeIconArray.name[3], choice6: themeIconArray.name[4], choice6: themeIconArray.name[5], choice7: themeIconArray.name[6], defaultValue: 'None'}, {name: 'iconThemeDarkBlue', label: '7N1. Custom icon for dark blue users -- Leave blank if you do not want a custom icon for this group',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'iconThemeLightPurple', label: '7N2. Custom icon for light purple users -- Leave blank if you do not want a custom icon for this group',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'iconThemeDarkPurple', label: '7N3. Custom icon for dark purple users -- Leave blank if you do not want a custom icon for this group', type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'dummy4b', label: '*** The below settings 7P-7W can be optionally used to change the color of in-chat PMs. Enter the hex color (6 character hex color codes plus the # prefix). Leave these blank to use the defaults', type: 'choice',required: false}, {name: 'bcCustomTextColor', label: '7P. Custom Text Color for PMs to Broadcaster (using /bc command) -- Default is dark purple',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'bcCustomBgColor', label: '7Q. Custom Background/Highlight Color for PMs to Broadcaster -- Default is light purple', type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'tmCustomTextColor', label: '7R. Custom Text Color for PMs to Moderator Group (using /tm command) -- Default is dark green',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'tmCustomBgColor', label: '7S. Custom Background/Highlight Color for PMs to Moderator Group -- Default is light green', type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'tbmCustomTextColor', label: '7T. Custom Text Color for PMs to Broadcaster and Moderator Group (using /tbm command) -- Default is dark blue',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'tbmCustomBgColor', label: '7U. Custom Background/Highlight Color for PMs to Broadcaster and Moderator Group -- Default is light blue', type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'pmCustomTextColor', label: '7V. Custom Text Color for PMs to a user (using /pm command) -- Default is dark aqua',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'pmCustomBgColor', label: '7W. Custom Background/Highlight Color for PMs to a user -- Default is cream', type: 'str',minLength: 1,maxLength: 7,required: false}, // *** VIP List {name: 'dummy5', label: '---------------------------------------------------------------------------------------------------- SECTION 8 - VIP LIST', type: 'choice',required: false}, {name: 'enableVIPList', label: '8A. **No longer used** PM privileges controlled by setting 4H and Fembot ticket show access by setting 15M2.', type: 'choice',required: false}, {name: 'VIPList', label: '8B. 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: 3, maxLength: 99999, defaultValue: '', required: false}, {name: 'VIPname', label: '8C. Enter the name to be displayed for the VIP List if you have a personalized one. Default is "VIP List" if you do not enter one.', type: 'str', minLength: 1, maxLength: 50, required: false}, {name: 'announceVIP', label: '8D. 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: '8E. Add any text you would like to show up as part of their entry announcement. "Next line" feature enabled with {n}', type: 'str',defaultValue: 'Thanks for being a VIP!',required: false}, {name: 'joinVIPSingleTip', label: '8F. Single Tip for VIP -- If you would like have people automatically added to the VIP list if they tip a specific amount during the show, define a Single Tip amount here, otherwise leave this as zero. Also suggest adding it to the Tip Menu for visiblity. This setting can be used in combination with the cumulative tip amount defined below, whichever one occurs first will add them to the VIP list. Remember that the list is not permanently saved, you must add them to the permanent VIP list on the launch page if you want them to be VIPs in future shows.', type: 'int',minValue: 0,maxValue: 99999, defaultValue: 0}, {name: 'joinVIPCumulativeShow', label: '8G. Cumulative Tips for VIP -- If you would like have people automatically added to the VIP list if their cumulative tips within a show are above a certain threshold, define the threshold here, otherwise leave this as zero. It is suggested to add a notifier about the abilty to tip to become a VIP. Remember that the list is not permanently saved, you must add them to the permanent VIP list on the launch page if you want them to be VIPs in future shows.', type: 'int',minValue: 0,maxValue: 99999, defaultValue: 0}, {name: 'joinVIPCumulativeAllTime', label: '8H. All-time Tips for VIP -- If you would like have people automatically added to the VIP list if their All-time tip amount is above a certain threshold when the bot is launched or the all-time list displayed, define the threshold here. When the bot loads the All-Time Tipper list (from the Tip Count and Leaderboard section above), any users above this amount will automatically be added to the VIP List at the beginning of the show. If not used, leave this as zero. ', type: 'int',minValue: 0,maxValue: 99999, defaultValue: 0}, {name: 'iconVIP', label: '8J. Choose the per sonalized icon to be displayed for the VIP group of users (optional).', type: 'str',required: false}, {name: 'VIPHighlight', label: '8K. Highlight VIP Chat? (default is light blue)', type: 'choice', choice1: 'No', choice2: 'Yes', defaultValue: 'No'}, {name: 'VIPBgCustColor', label: '8L. VIP List Chat Highlight Custom Color - The default is light blue highlighting, however you can define a custom color here. Leave blank to use the default or enter the custom hex color value (the # prefix plus the 6 character hex color code)',type: 'str',minLength: 1,maxLength: 7,required: false}, // *** External Fan Clubs {name: 'dummy6', label: '---------------------------------------------------------------------------------------------------- SECTION 9 - EXTERNAL FAN CLUBS 1 and 2', type: 'choice',required: false}, {name: 'dummy6a', label: 'You can define a fan club list for up to 2 External (non-CB) Fan Clubs below, along with the fan club name, announcement, colors, etc for each.', type: 'choice',required: false}, {name: 'dummyfans1', label: '***************** Fan Club 1 ***********************', type: 'choice',required: false}, {name: 'enableExtFans', label: '9A. **No longer used** PM privileges controlled by setting 4H and Fembot ticket show access by setting 15M3.', type: 'choice',required: false}, {name: 'extFanList', label: '9B. Enter the names of any External Fan Club members you would like to grant special privileges. Users should be separated by a comma with no spaces', type: 'str', minLength: 3, maxLength: 99999, defaultValue: '', required: false}, {name: 'EFCname', label: '9C. Enter the name to be displayed for the External Fan Club if you have a personalized one. Default is "External Fan Club" if you do not enter one.', type: 'str', minLength: 1, maxLength: 50, required: false}, {name: 'announceExtFans', label: '9D. 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: '9E. Add any text you would like to show up as part of their entry announcement. "Next line" feature enabled with {n}', type: 'str',defaultValue: 'Thanks for being in our fanclub!',required: false}, {name: 'iconExtFans', label: '9F. Choose the personalized icon to be displayed for the External Fanclub group of users (optional)', type: 'str',required: false}, {name: 'efcHighlight', label: '9G. Highlight External Fan Club Chat? (default is light green)', type: 'choice', choice1: 'No', choice2: 'Yes', defaultValue: 'No'}, {name: 'efcBgCustColor', label: '9H. External Fan Club Chat Highlight Custom Color - The default is light green highlighting the same as CB Fanclub, however you can define a custom color here. Leave blank to use the default or enter the custom hex color value (the # prefix plus the 6 character hex color code)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'dummyfans2', label: '***************** Fan Club 2 ***********************', type: 'choice',required: false}, {name: 'enableExtFans2', label: '9J. **No longer used** PM privileges controlled by setting 4H and Fembot ticket show access by setting 15M4.', type: 'choice',required: false}, {name: 'extFanList2', label: '9K. Enter the names of any External Fan Club 2 members you would like to grant special privileges. Users should be separated by a comma with no spaces', type: 'str', minLength: 3, maxLength: 99999, defaultValue: '', required: false}, {name: 'EFCname2', label: '9L. Enter the name to be displayed for the External Fan Club 2 if you have a personalized one. Default is "External Fan Club 2" if you do not enter one.', type: 'str', minLength: 1, maxLength: 50, required: false}, {name: 'announceExtFans2', label: '9M. Display announcement when external Fan Club 2 members enter/leave the room?', type: 'choice', choice1: 'Enter Only', choice2: 'Leave Only', choice3: 'Enter or Leave', choice4: 'None', defaultValue: 'Enter Only'}, {name: 'announceExtFanstext2', label: '9N. Add any text you would like to show up as part of their entry announcement. "Next line" feature enabled with {n}', type: 'str',defaultValue: 'Thanks for being in our fanclub!',required: false}, {name: 'iconExtFans2', label: '9P. Choose the personalized icon to be displayed for the External Fanclub 2 group of users (optional)', type: 'str',required: false}, {name: 'efcHighlight2', label: '9Q. Highlight External Fan Club 2 Chat? (default is light green)', type: 'choice', choice1: 'No', choice2: 'Yes', defaultValue: 'No'}, {name: 'efcBgCustColor2', label: '9R. External Fan Club 2 Chat Highlight Custom Color - The default is light green highlighting the same as CB Fanclub, however you can define a custom color here. Leave blank to use the default or enter the custom hex color value (the # prefix plus the 6 character hex color code)',type: 'str',minLength: 1,maxLength: 7,required: false}, // *** Blocked Word List {name: 'dummy7', label: '---------------------------------------------------------------------------------------------------- SECTION 10 - BLOCKED WORD LIST', type: 'choice',required: false}, {name: 'enableWordList', label: '10A. Enable Blocked Word Lists - determines if both the Private and Public lists defined below are checked. Note that words added by command within the show are added to the public list.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'wordBlockList', label: '10B. Private Blocked Word List - Enter the words you would like to block in the chat. This private word list is not viewable by anyone other than the broadcaster, even moderators. If a word from this list is used, the broadcaster receives a notification, but the person who entered the message does not. Words should be separated by a comma with no spaces.', type: 'str', minLength: 1, maxLength: 1000, required: false}, {name: 'showBlockedMsgs', label: '10C. Private Blocked Word List - Show chat messages to the broadcaster when a viewer uses blocked words?', type: 'choice', choice1: 'Do not display', choice2: 'Display to Broadcaster only', defaultValue: 'Display to Broadcaster only'}, {name: 'blockedLevelPriv', label: '10D. Private Blocked Word List - Block words for which user groups?', type: 'choice', choice1: 'All Users', choice2: 'All Users Except Mods', choice3: 'All Users Except Mods/Fans/VIPs', choice4: 'Only Light Blue and Gray Users', choice5: 'Gray Users Only', defaultValue: 'All Users'}, {name: 'wordBlockListPub', label: '10E. Public Blocked Word List - Enter additional words you would like to block in the chat, but for which the person typing will receive a notification. Words should be separated by a comma with no spaces. This private word list is not viewable by anyone other than the broadcaster, even moderators. If a word from this list is used, the broadcaster receives a notification, but the person who entered the message does not. Words should be separated by a comma with no spaces.', type: 'str', minLength: 1, maxLength: 1000, defaultValue: 'cunt,bitch,slut,c2c,cumslut,whore,chatur.,[http://sexmap.', required: false}, {name: 'showBlockedMsgsPub', label: '10F. Public Blocked Word List - Show chat messages to certain groups when a viewer uses blocked words?', type: 'choice', choice1: 'Do not display', choice2: 'Display to Broadcaster only', choice3: 'Display to Broadcaster and Moderators', defaultValue: 'Display to Broadcaster and Moderators'}, {name: 'blockedLevelPub', label: '10G. Public Blocked Word List - Block words for which user groups?', type: 'choice', choice1: 'All Users', choice2: 'All Users Except Mods', choice3: 'All Users Except Mods/Fans/VIPs', choice4: 'Only Light Blue and Gray Users', choice5: 'Gray Users Only', defaultValue: 'All Users Except Mods/Fans/VIPs'}, // *** Tip Menu 1: 40 slots {name: 'dummy8', label: '---------------------------------------------------------------------------------------------------- SECTION 11 - TIP MENU 1 AND 2', type: 'choice',required: false}, {name: 'dummy8a', label: 'You can configure and save 2 different menus for different types of shows, and swap between either at startup or with the /swapmenu command during the show, but only Menu 1 or Menu 2 can be active at one time. The initial settings below apply to both menus, and then there are additional settings that are specific to each menu.', type: 'choice',required: false}, {name: 'tipMenuNoticeType', label: '11A. Menu Notice Format -- What format should be used for displaying the tip menu in the chat? Paragraph form is recommended as it uses the fewest lines, and it is recommended if you use more than 15-20 tip menu items to also split the menu into two halves that are displayed on a rotating basis. There must be at least 8 tip menu items for the split to occur. A list format is also available, where each tip menu item is on one line, for a cleaner look, and that format can also be split into smaller chunks so it does not clear the entire screen each time the menu displays.',type: 'choice',choice1: 'Full Menu - Paragraph Form',choice2: 'Split Menu - Paragraph Form',choice3: 'Full Menu - List Form',choice4: 'Notice only',choice5: 'Split Menu - List Form',defaultValue: 'Full Menu - Paragraph Form'}, {name: 'menuDspInt', label: '11B. Tip Menu display interval. Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.',type: 'str',defaultValue: 4.9,required: false}, {name: 'alertBCWhenReq', label: '11C. Alert the broadcaster and/or moderators when a user requests the tip menu?', type: 'choice', choice1: 'No Alert', choice2: 'Broadcaster Only', choice3: 'Moderators Only', choice4: 'Broadcaster and Moderators', defaultValue: 'No Alert'}, {name: 'listSort', label: '11D. Sort the items in the tip menu by price?',type: 'choice',choice1: 'Do not sort the list',choice2: 'Ascending',choice3: 'Descending',defaultValue: 'Ascending'}, {name: 'sepchar', label: '11E1. Choose your separator character to appear between menu items. You can also use a specific gif or emoji by choosing "Custom" and entering one in setting 11E2 below, which will override this setting', type: 'choice',choice1: separatorArray.dispname[0], choice2: separatorArray.dispname[1], choice3: separatorArray.dispname[2], choice4: separatorArray.dispname[3], choice5: separatorArray.dispname[4], choice6: separatorArray.dispname[5], choice7: separatorArray.dispname[6], choice8: separatorArray.dispname[7], choice9: separatorArray.dispname[8], choice10: separatorArray.dispname[9], choice11: separatorArray.dispname[10], choice12: separatorArray.dispname[11], choice13: separatorArray.dispname[12], choice14: separatorArray.dispname[13], choice15: separatorArray.dispname[14], choice16: separatorArray.dispname[15], choice17: separatorArray.dispname[16], defaultValue: separatorArray.dispname[3]}, {name: 'sepcharcustom', label: '11E2. Custom Separator (optional) - If you chose "Custom" above in setting 11E1, input your custom separator. It can be a gif, emoji 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. When using an emoji, paste the actual emoji image here',type: 'str',defaultValue: ':heart2',required: false}, {name: 'sepInResponse', label: '11E3. Add the separator character at the beginning and end of the tip response notice to make them stand out from other messaging in the chat?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'includeDiceRollPrice', label: '11F. If the Dice Game is enabled, include the dice roll price in the tip menu?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'menutxtcolor1', label: '11G. Choose your text color for the single menu or part 1 of the split menu. Note that even if a color theme is used for the recurring menu notice, this setting will still be used for the tip request message text color',type: 'choice',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 Red'}, {name: 'menuCustTxtColor1', label: '11H. If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'menubgcolor1', label: '11J. Choose the background color for the above. Note that even if a color theme is used for the recurring menu notice, this setting will still be used for the tip request message background color',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: 'menuCustBgColor1', label: '11K. If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'menutxtcolor2', label: '11L. Choose your text color for part 2 of the split menu',type: 'choice',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', label: '11M. If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'menubgcolor2', label: '11N. 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', label: '11P. If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'dummymenu1', label: '***************** Tip Menu 1 *********************** Use a negative sign (-) in front of the price to temporarily disable it, but leave the price intact to use later.', type: 'choice',required: false}, {name: 'enableTipMenu', label: '11Q. Enable Tip Menu 1 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: 'Yes'}, {name: 'dummyDiscounts', label: '11R. *** Tip Menu Discounts *** Discounts are optional and only apply to Tip Menu 1. You can define discount percentages for different user groups. There can be a general discount for everyone, and a different percentage for certain user groups (mods, CB fans, external fans, VIPs) can also be set with their individual percentages. Note that only the general tip menu price for the room (general discount), if any, will be reflected in the prices in the recurring notice. Users in the special discount groups will have to use the /tipmenu command to display the menu for their user group, and only they will see a reminder about this after the recurring message. There are also separate commands for a mod or broadcaster to view the group specific menus (/tipmenumod, /tipmenuvip, etc) Note that additional tip menu items for the Fan Club user groups can also be defined below after Tip Menu 2 under section 11U, however the percentages here will only apply to the menu items in Tip Menu 1. For each group, define the percentage off of normal prices here. For example, if a menu item is normally 90 tokens, putting a value of 10 here (for 10%) would make the price 81 tokens (90 minus 9). Leave the value as zero to use regular prices (leaving a zero for special groups will default to the normal price or the general room discount price). Note that using a sale may make some menu item amounts duplicated with other tip prices used elsewhere, or duplicated within the menu if items are close in price, so make sure to check the resulting amounts.', type: 'choice',required: false}, {name: 'tipMenuSalePct', label: '11R1. Tip Menu 1 Discount percentage for everyone (general viewers)? Set to 0 if not used',type: 'int',defaultValue: 0, minValue: 0,maxValue: 99}, {name: 'tipMenuModSalePct', label: '11R2. Tip Menu 1 Discount percentage for moderators? Set to 0 if not used',type: 'int',defaultValue: 0, minValue: 0,maxValue: 99}, {name: 'tipMenuCBFCSalePct', label: '11R3. Tip Menu 1 Discount percentage for CB Fanclub? Set to 0 if not used',type: 'int',defaultValue: 0, minValue: 0,maxValue: 99}, {name: 'tipMenuEFC1SalePct', label: '11R4. Tip Menu 1 Discount percentage for External FanClub 1? Set to 0 if not used',type: 'int',defaultValue: 0, minValue: 0,maxValue: 99}, {name: 'tipMenuEFC2SalePct', label: '11R5. Tip Menu 1 Discount percentage for External FanClub 2? Set to 0 if not used',type: 'int',defaultValue: 0, minValue: 0,maxValue: 99}, {name: 'tipMenuVIPSalePct', label: '11R6. Tip Menu 1 Discount percentage for VIPs? Set to 0 if not used',type: 'int',defaultValue: 0, minValue: 0,maxValue: 99}, {name: 'menuitem1', type: 'str',required: false,defaultValue: 'PM',label: 'Tip Menu Item 1'}, {name: 'menuitemprice1', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 5,required: false,label: 'Item 1 price'}, {name: 'menuitem2', type: 'str',required: false,defaultValue: 'blow kiss',label: 'Tip Menu Item 2'}, {name: 'menuitemprice2', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 6,required: false,label: 'Item 2 price'}, {name: 'menuitem3', type: 'str',required: false,defaultValue: 'YOU LIKE ME',label: 'Tip Menu Item 3'}, {name: 'menuitemprice3', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 7,required: false,label: 'Item 3 price'}, {name: 'menuitem4', type: 'str',required: false,defaultValue: 'stand up',label: 'Tip Menu Item 4'}, {name: 'menuitemprice4', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 10,required: false,label: 'Item 4 price'}, {name: 'menuitem5', type: 'str',required: false,defaultValue: 'feet/heels',label: 'Tip Menu Item 5'}, {name: 'menuitemprice5', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 21,required: false,label: 'Item 5 price'}, {name: 'menuitem6', type: 'str',required: false,defaultValue: 'stockings on/off',label: 'Tip Menu Item 6'}, {name: 'menuitemprice6', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 22,required: false,label: 'Item 6 price'}, {name: 'menuitem7', type: 'str',required: false,defaultValue: 'moan your name',label: 'Tip Menu Item 7'}, {name: 'menuitemprice7', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 23,required: false,label: 'Item 7 price'}, {name: 'menuitem8', type: 'str',required: false,defaultValue: 'suck finger',label: 'Tip Menu Item 8'}, {name: 'menuitemprice8', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 24,required: false,label: 'Item 8 price'}, {name: 'menuitem9', type: 'str',required: false,defaultValue: 'spin the wheel',label: 'Tip Menu Item 9'}, {name: 'menuitemprice9', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 25,required: false,label: 'Item 9 price'}, {name: 'menuitem10', type: 'str',required: false,defaultValue: '5 Jumping Jacks',label: 'Tip Menu Item 10'}, {name: 'menuitemprice10', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 28,required: false,label: 'Item 10 price'}, {name: 'menuitem11', type: 'str',required: false,defaultValue: 'Squats',label: 'Tip Menu Item 11'}, {name: 'menuitemprice11', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 29,required: false,label: 'Item 11 price'}, {name: 'menuitem12', type: 'str',required: false,defaultValue: 'Roll the Dice',label: 'Tip Menu Item 12'}, {name: 'menuitemprice12', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 33,required: false,label: 'Item 12 price'}, {name: 'menuitem13', type: 'str',required: false,defaultValue: 'spank butt',label: 'Tip Menu Item 13'}, {name: 'menuitemprice13', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 37,required: false,label: 'Item 13 price'}, {name: 'menuitem14', type: 'str',required: false,defaultValue: '5x spank butt both hands',label: 'Tip Menu Item 14'}, {name: 'menuitemprice14', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 43,required: false,label: 'Item 14 price'}, {name: 'menuitem15', type: 'str',required: false,defaultValue: 'doggy style',label: 'Tip Menu Item 15'}, {name: 'menuitemprice15', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 44,required: false,label: 'Item 15 price'}, {name: 'menuitem16', type: 'str',required: false,defaultValue: 'twerk',label: 'Tip Menu Item 16'}, {name: 'menuitemprice16', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 48,required: false,label: 'Item 16 price'}, {name: 'menuitem17', type: 'str',required: false,defaultValue: 'flash panties',label: 'Tip Menu Item 17'}, {name: 'menuitemprice17', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 52,required: false,label: 'Item 17 price'}, {name: 'menuitem18', type: 'str',required: false,defaultValue: 'flash bra',label: 'Tip Menu Item 18'}, {name: 'menuitemprice18', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 58,required: false,label: 'Item 18 price'}, {name: 'menuitem19', type: 'str',required: false,defaultValue: 'shake tits',label: 'Tip Menu Item 19'}, {name: 'menuitemprice19', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 54,required: false,label: 'Item 19 price'}, {name: 'menuitem20', type: 'str',required: false,defaultValue: 'squeeze tits',label: 'Tip Menu Item 20'}, {name: 'menuitemprice20', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 56,required: false,label: 'Item 20 price'}, {name: 'menuitem21', type: 'str',required: false,defaultValue: 'funny dance',label: 'Tip Menu Item 21'}, {name: 'menuitemprice21', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 61,required: false,label: 'Item 21 price'}, {name: 'menuitem22', type: 'str',required: false,defaultValue: 'hot strip & dance',label: 'Tip Menu Item 22'}, {name: 'menuitemprice22', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 69,required: false,label: 'Item 22 price'}, {name: 'menuitem23', type: 'str',required: false,defaultValue: 'HandBra',label: 'Tip Menu Item 23'}, {name: 'menuitemprice23', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 79,required: false,label: 'Item 23 price'}, {name: 'menuitem24', type: 'str',required: false,defaultValue: 'get naked out of the screen',label: 'Tip Menu Item 24'}, {name: 'menuitemprice24', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 99,required: false,label: 'Item 24 price'}, {name: 'menuitem25', type: 'str',required: false,defaultValue: 'rub my pussy 1 min',label: 'Tip Menu Item 25'}, {name: 'menuitemprice25', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 149,required: false,label: 'Item 25 price'}, {name: 'menuitem26', type: 'str',required: false,defaultValue: 'simulate sex on a chair 5min',label: 'Tip Menu Item 26'}, {name: 'menuitemprice26', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 249,required: false,label: 'Item 26 price'}, {name: 'menuitem27', type: 'str',required: false,defaultValue: 'Anal Plug(panty on)',label: 'Tip Menu Item 27'}, {name: 'menuitemprice27', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 696,required: false,label: 'Item 27 price'}, {name: 'menuitem28', type: 'str',required: false,defaultValue: 'make my day',label: 'Tip Menu Item 28'}, {name: 'menuitemprice28', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 500,required: false,label: 'Item 28 price'}, {name: 'menuitem29', type: 'str',required: false,defaultValue: 'you are mine',label: 'Tip Menu Item 29'}, {name: 'menuitemprice29', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 1000,required: false,label: 'Item 29 price'}, {name: 'menuitem30', type: 'str',required: false,defaultValue: 'ride a horse in underwear',label: 'Tip Menu Item 30'}, {name: 'menuitemprice30', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 30 price'}, {name: 'menuitem31', type: 'str',required: false,defaultValue: 'IF YOU REALLY LOVE ME!! I LOVE U HONEY !!! U MAKE ME VERY HAPPYYYY)',label: 'Tip Menu Item 31'}, {name: 'menuitemprice31', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 31 price'}, {name: 'menuitem32', type: 'str',required: false,defaultValue: 'Give me day off !!!',label: 'Tip Menu Item 32'}, {name: 'menuitemprice32', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 32 price'}, {name: 'menuitem33', type: 'str',required: false,defaultValue: 'PassShow: Only You and Me all day long',label: 'Tip Menu Item 33'}, {name: 'menuitemprice33', type: 'int',minValue: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,maxValue: 99999,defaultValue: 0,required: false,label: 'Item 40 price'}, // *** Tip Menu 2: 25 slots {name: 'dummymenu2', label: '***************** Tip Menu 2 *********************** Use a negative sign (-) in front of the price to temporarily disable it, but leave the price intact to use later.', type: 'choice',required: false}, {name: 'enableTipMenu2', label: '11S. 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: 'tipMenu2SalePct', label: '11T. Tip Menu #2 Discount Percentage? - If you would like to run a sale on your normal tip menu 2 prices, define the percentage off of normal prices here. For example, put a value of 10 here for 10% off normal prices. Leave the value as zero to use regular prices. Note that Tip Menu 2 does not provide User Group specific discounts, that is only available in Tip Menu 1 at this time', type: 'int',minValue: 0,maxValue: 99,defaultValue: 0}, {name: 'menu2item1', type: 'str',required: false,label: 'Tip Menu 2 Item 1'}, {name: 'menu2itemprice1', type: 'int',minValue: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,maxValue: 99999,required: false,label: 'Item 20 price'}, {name: 'menu2item21', type: 'str',required: false,label: 'Tip Menu 2 Item 21'}, {name: 'menu2itemprice21', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 21 price'}, {name: 'menu2item22', type: 'str',required: false,label: 'Tip Menu 2 Item 22'}, {name: 'menu2itemprice22', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 22 price'}, {name: 'menu2item23', type: 'str',required: false,label: 'Tip Menu 2 Item 23'}, {name: 'menu2itemprice23', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 23 price'}, {name: 'menu2item24', type: 'str',required: false,label: 'Tip Menu 2 Item 24'}, {name: 'menu2itemprice24', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 24 price'}, {name: 'menu2item25', type: 'str',required: false,label: 'Tip Menu 2 Item 25'}, {name: 'menu2itemprice25', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 25 price'}, // *** Fan Club Menus {name: 'dummymenufchdr', label: '11U. *** Fan Club Menus *** The below menu items for each type of Fan Club will be available on a custom Tip Menu that only club members will have access to through the normal /tipmenu command (they are not publicly displayed). If the fan club group has also been given a discount in settings 11R2-11R6 above, the custom menu will show the discounted prices for the regular Tip Menu 1 items in the custom menu first, followed by the items below. Otherwise, if there is no discount for the group, the custom menu will only show the below items. The discount percentage used for Tip Menu 1 will not be applied to these, so enter the actual price that you want them to tip for each item. Use a negative sign (-) in front of the price to temporarily disable it, but leave the price intact to use later.', type: 'choice',required: false}, // *** CB Fan Club: 10 slots {name: 'dummymenucbfc', label: '***************** CB Fan Club Menu Items ********************', type: 'choice',required: false}, {name: 'fanmenuitem1', type: 'str',required: false,label: 'CB Fan Club Menu Item 1'}, {name: 'fanmenuitemprice1', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 1 price'}, {name: 'fanmenuitem2', type: 'str',required: false,label: 'CB Fan Club Menu Item 2'}, {name: 'fanmenuitemprice2', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 2 price'}, {name: 'fanmenuitem3', type: 'str',required: false,label: 'CB Fan Club Menu Item 3'}, {name: 'fanmenuitemprice3', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 3 price'}, {name: 'fanmenuitem4', type: 'str',required: false,label: 'CB Fan Club Menu Item 4'}, {name: 'fanmenuitemprice4', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 4 price'}, {name: 'fanmenuitem5', type: 'str',required: false,label: 'CB Fan Club Menu Item 5'}, {name: 'fanmenuitemprice5', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 5 price'}, {name: 'fanmenuitem6', type: 'str',required: false,label: 'CB Fan Club Menu Item 6'}, {name: 'fanmenuitemprice6', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 6 price'}, {name: 'fanmenuitem7', type: 'str',required: false,label: 'CB Fan Club Menu Item 7'}, {name: 'fanmenuitemprice7', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 7 price'}, {name: 'fanmenuitem8', type: 'str',required: false,label: 'CB Fan Club Menu Item 8'}, {name: 'fanmenuitemprice8', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 8 price'}, {name: 'fanmenuitem9', type: 'str',required: false,label: 'CB Fan Club Menu Item 9'}, {name: 'fanmenuitemprice9', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 9 price'}, {name: 'fanmenuitem10', type: 'str',required: false,label: 'CB Fan Club Menu Item 10'}, {name: 'fanmenuitemprice10', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 10 price'}, // *** External Fan Club 1: 10 slots {name: 'dummymenuefc1', label: '************** Ext Fan Club 1 Menu Items *****************', type: 'choice',required: false}, {name: 'efc1menuitem1', type: 'str',required: false,label: 'Ext Fan Club 1 Menu Item 1'}, {name: 'efc1menuitemprice1', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 1 price'}, {name: 'efc1menuitem2', type: 'str',required: false,label: 'Ext Fan Club 1 Menu Item 2'}, {name: 'efc1menuitemprice2', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 2 price'}, {name: 'efc1menuitem3', type: 'str',required: false,label: 'Ext Fan Club 1 Menu Item 3'}, {name: 'efc1menuitemprice3', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 3 price'}, {name: 'efc1menuitem4', type: 'str',required: false,label: 'Ext Fan Club 1 Menu Item 4'}, {name: 'efc1menuitemprice4', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 4 price'}, {name: 'efc1menuitem5', type: 'str',required: false,label: 'Ext Fan Club 1 Menu Item 5'}, {name: 'efc1menuitemprice5', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 5 price'}, {name: 'efc1menuitem6', type: 'str',required: false,label: 'Ext Fan Club 1 Menu Item 6'}, {name: 'efc1menuitemprice6', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 6 price'}, {name: 'efc1menuitem7', type: 'str',required: false,label: 'Ext Fan Club 1 Menu Item 7'}, {name: 'efc1menuitemprice7', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 7 price'}, {name: 'efc1menuitem8', type: 'str',required: false,label: 'Ext Fan Club 1 Menu Item 8'}, {name: 'efc1menuitemprice8', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 8 price'}, {name: 'efc1menuitem9', type: 'str',required: false,label: 'Ext Fan Club 1 Menu Item 9'}, {name: 'efc1menuitemprice9', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 9 price'}, {name: 'efc1menuitem10', type: 'str',required: false,label: 'Ext Fan Club 1 Menu Item 10'}, {name: 'efc1menuitemprice10', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 10 price'}, // *** External Fan Club 2: 10 slots {name: 'dummymenuefc2', label: '************** Ext Fan Club 2 Menu Items *****************', type: 'choice',required: false}, {name: 'efc2menuitem1', type: 'str',required: false,label: 'Ext Fan Club 2 Menu Item 1'}, {name: 'efc2menuitemprice1', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 1 price'}, {name: 'efc2menuitem2', type: 'str',required: false,label: 'Ext Fan Club 2 Menu Item 2'}, {name: 'efc2menuitemprice2', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 2 price'}, {name: 'efc2menuitem3', type: 'str',required: false,label: 'Ext Fan Club 2 Menu Item 3'}, {name: 'efc2menuitemprice3', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 3 price'}, {name: 'efc2menuitem4', type: 'str',required: false,label: 'Ext Fan Club 2 Menu Item 4'}, {name: 'efc2menuitemprice4', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 4 price'}, {name: 'efc2menuitem5', type: 'str',required: false,label: 'Ext Fan Club 2 Menu Item 5'}, {name: 'efc2menuitemprice5', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 5 price'}, {name: 'efc2menuitem6', type: 'str',required: false,label: 'Ext Fan Club 2 Menu Item 6'}, {name: 'efc2menuitemprice6', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 6 price'}, {name: 'efc2menuitem7', type: 'str',required: false,label: 'Ext Fan Club 2 Menu Item 7'}, {name: 'efc2menuitemprice7', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 7 price'}, {name: 'efc2menuitem8', type: 'str',required: false,label: 'Ext Fan Club 2 Menu Item 8'}, {name: 'efc2menuitemprice8', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 8 price'}, {name: 'efc2menuitem9', type: 'str',required: false,label: 'Ext Fan Club 2 Menu Item 9'}, {name: 'efc2menuitemprice9', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 9 price'}, {name: 'efc2menuitem10', type: 'str',required: false,label: 'Ext Fan Club 2 Menu Item 10'}, {name: 'efc2menuitemprice10', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 10 price'}, // *** Positions Tip Menu {name: 'dummy9', label: '---------------------------------------------------------------------------------------------------- SECTION 12 - POSITIONS MENU', type: 'choice',required: false}, {name: 'dummy9a', label: '*** You can use a negative sign (-) in front of the price to temporarily disable it, but leave the price intact to use later.', type: 'choice',required: false}, {name: 'enablePosTipMenu', label: '12A. 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', label: '12B. 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.', type: 'str',defaultValue: 2.3,required: false}, {name: 'posListSort', label: '12C. Sort the items in the positions menu by price?', type: 'choice',choice1: 'Do not sort the list',choice2: 'Ascending',choice3: 'Descending',defaultValue: 'Ascending'}, {name: 'posSepChar', label: '12D1. Choose your separator character to appear between menu items. You can also use a specific gif or emoji by choosing "Custom" and entering one in setting 12D2 below', type: 'choice',choice1: separatorArray.dispname[0], choice2: separatorArray.dispname[1], choice3: separatorArray.dispname[2], choice4: separatorArray.dispname[3], choice5: separatorArray.dispname[4], choice6: separatorArray.dispname[5], choice7: separatorArray.dispname[6], choice8: separatorArray.dispname[7], choice9: separatorArray.dispname[8], choice10: separatorArray.dispname[9], choice11: separatorArray.dispname[10], choice12: separatorArray.dispname[11], choice13: separatorArray.dispname[12], choice14: separatorArray.dispname[13], choice15: separatorArray.dispname[14], choice16: separatorArray.dispname[15], choice17: separatorArray.dispname[16], defaultValue: separatorArray.dispname[0]}, {name: 'posSepCharCustom', label: '12D2. Custom Separator (optional) - If you chose "Custom" above in setting 12D1, input your custom separator. It can be a gif, emoji 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. When using an emoji, paste the actual emoji image here',type: 'str',defaultValue: ':heart2',required: false}, {name: 'posSepInResponse', label: '12D3. Add the separator character at the beginning and end of the tip response notice to make them stand out from other messaging in the chat?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'posMenuTxtColor', label: '12F. Choose your text color for the positions menu',type: 'choice',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', label: '12G. If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'posMenuBgColor', label: '12H. 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: '12J. 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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,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: -99999,maxValue: 99999,defaultValue: 108,required: false,label: 'Positions Item 8 price'}, // *** Token Poll {name: 'dummy10', label: '---------------------------------------------------------------------------------------------------- SECTION 13 - TOKEN POLL', type: 'choice',required: false}, {name: 'enableTokenPoll', label: '13A. 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', label: '13B. Poll Title (what will people be voting for?)',type: 'str',required: false,minLength: 1,maxLength: 255}, {name: 'pollInterval', label: '13C. Display Interval for Token Poll vote summary (in minutes). Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.', type: 'str',defaultValue: 2.0,required: false}, {name: 'pollMode', label: '13D. 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',type: 'choice',defaultValue: 'Ends by Mod/Broadcaster command'}, {name: 'pollCount', label: '13E. Per above choice for Poll Type, choose value for X (in minutes or votes) ',type: 'int',required: false,minValue: 1,defaultValue: 1}, {name: 'pollMinimum', label: '13F. Minimum total votes required to make the poll valid? Set to "1" to not require a minimum',type: 'int',minValue: 1,maxValue: 50,defaultValue: 1,required: false}, {name: 'pollTxtColor', label: '13G. Poll text color',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 Green'}, {name: 'pollCustTxtColor', label: '13H. If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'pollBgColor', label: '13J. 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', label: '13K. If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'pollFanClubDouble', label: '13L. Fan club members vote counts double?',type: 'choice',choice1: 'Yes',choice2: 'No',defaultValue: 'No'}, {name: 'pollKeepalive', label: '13M. 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?',type: 'choice',choice1: 'Yes',choice2: 'No',defaultValue: 'No'}, {name: 'pollModAdd', label: '13N. Allow a moderator to add or remove votes?',type: 'choice',choice1: 'Yes',choice2: 'No',defaultValue: 'Yes'}, {name: 'stealPollAmount', label: '13P. If you want to allow people to "hijack" the poll by tipping a very large amount in a single tip, set the amount here, otherwise set it to zero. Note that this has the potential to anger people who have been voting, but use it at your own discretion.',type: 'int',required: false,minValue: 0,maxValue: 99999,defaultValue: 0}, {name: 'dummypoll', label: '13Q. 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. To temporarily disable a Token Poll item, you can put a minus sign (-) in front of the price, and then it will not be used in the poll, but you can keep the item available for a future show and not have to delete it.', type: 'choice',required: false}, {name: 'pollOptLabel1', label: 'Option 1',type: 'str',minLength: 1,maxLength: 50,defaultValue: 'On Boobs',required: false}, {name: 'pollOptTokens1', label: 'Option 1 tokens',type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 11,required: false}, {name: 'pollOptLabel2', label: 'Option 2',type: 'str',minLength: 1,maxLength: 50,defaultValue: 'Facial',required: false}, {name: 'pollOptTokens2', label: 'Option 2 tokens',type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 12,required: false}, {name: 'pollOptLabel3', label: 'Option 3',type: 'str',minLength: 1,maxLength: 50,required: false}, {name: 'pollOptTokens3', label: 'Option 3 tokens',type: 'int',minValue: -99999,maxValue: 99999,required: false}, {name: 'pollOptLabel4', label: 'Option 4',type: 'str',minLength: 1,maxLength: 50,required: false}, {name: 'pollOptTokens4', label: 'Option 4 tokens',type: 'int',minValue: -99999,maxValue: 99999,required: false}, {name: 'pollOptLabel5', label: 'Option 5',type: 'str',minLength: 1,maxLength: 50,required: false}, {name: 'pollOptTokens5', label: 'Option 5 tokens',type: 'int',minValue: -99999,maxValue: 99999,required: false}, {name: 'pollOptLabel6', label: 'Option 6',type: 'str',minLength: 1,maxLength: 50,required: false}, {name: 'pollOptTokens6', label: 'Option 6 tokens',type: 'int',minValue: -99999,maxValue: 99999,required: false}, {name: 'pollOptLabel7', label: 'Option 7',type: 'str',minLength: 1,maxLength: 50,required: false}, {name: 'pollOptTokens7', label: 'Option 7 tokens',type: 'int',minValue: -99999,maxValue: 99999,required: false}, {name: 'pollOptLabel8', label: 'Option 8',type: 'str',minLength: 1,maxLength: 50,required: false}, {name: 'pollOptTokens8', label: 'Option 8 tokens',type: 'int',minValue: -99999,maxValue: 99999,required: false}, {name: 'pollSepBot', label: '13R. Running the Dorothy\'s Token Poll bot instead of the poll feature here in the Fembot? When set to "Yes", the Fembot will ignore the commands used for the separate bot since they are the same',type: 'choice',choice1: 'Yes',choice2: 'No',defaultValue: 'No'}, // *** General Ticket Show Settings {name: 'dummyticket', label: '---------------------------------------------------------------------------------------------------- SECTION 14 - TICKET SHOW SUPPORT ', type: 'choice',required: false}, {name: 'dummyticket2', label: 'This bot contains its own hidden ticket show feature, and also support certain interactions with separate ticket 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: '14A. 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: '14B. Enable the /prepticket command to turn off the Tip Menu if currently on?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'prepticketPosMenuOn', label: '14C. 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: '14D. Enable the /prepticket command to start the Token Poll if currently off?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'startPollTimerWithShow', label: '14J. 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', label: '14K. If the above setting switches the Poll to "Timer" mode, define the number of minutes to use for the poll timer after /startshow',type: 'int', minValue: 1, maxValue: 60,required: false, defaultValue: 10}, {name: 'endPosMenuWithShow', label: '14L. 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: 'numberFromLB', label: '14N. 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.',type: 'int',minValue: 1,maxValue: 10,required: false, defaultValue: 3}, {name: 'amountFromLB', label: '14P. 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.',type: 'str',minLength: 1,maxLength: 6,required: false, defaultValue: 1000}, {name: 'enablePresales', label: '14Q. 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: '14R. 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', label: '14S. 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.',type: 'int',minValue: 1,maxValue: 50,required: false,defaultValue: 10}, {name: 'presaleTimedIncrement', label: '14T. 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.',type: 'int',minValue: 1,maxValue: 50,required: false,defaultValue: 15}, {name: 'presaleIncreasePerIncrement', label: '14U. 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.',type: 'int',minValue: 1,maxValue: 100,required: false,defaultValue: 10}, {name: 'presaleMaxIncrements', label: '14V. 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.',type: 'int',minValue: 1,maxValue: 10,required: false,defaultValue: 3}, {name: 'initialPresalePrice', label: '14W. 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.',type: 'int',minValue: 1,maxValue: 1000,required: false,defaultValue: 45}, {name: 'presaleNoticeInterval', label: '14X. Display Interval for Ticket Show Pre-sales notice (in minutes). This notice alerts the room that a pre-sale is active, regardless of mode. Decimals are ok as long as they are greater than 1.',type: 'str',required: false,defaultValue: 3.3}, {name: 'ticketShowPrice', label: '14Y. 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: '---------------------------------------------------------------------------------------------------- SECTION 15 - FEMBOT TICKET SHOWS', type: 'choice',required: false}, {name: 'enableHiddenShow', label: '15A. Enable the Hidden Show feature at the beginning of the broadcast? The Hidden Show can be enabled later using the "/useticketshow on" command. Note that if the Ticket show type is set to Separate Ticket App, the Fembot Ticket Show feature will not start.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'hiddenShowDescription', label: '15B. Description of the show (optional)', type:'str',minLength: 1,maxLength: 100,required: false,defaultValue: 'Hidden Sex Show! Token Poll for cumshot!'}, {name: 'hiddenShowStartMode', label: '15C. 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: '15D. 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: '15E. 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: '15F. 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: '15G. 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: 99999,defaultValue: 69,required: false}, {name: 'hiddenShowPriceFC', label: '15H. 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: 99999,required: false}, {name: 'hiddenShowPriceEFC', label: '15I. Price for a ticket to the show for External Fan Club 1 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: 99999,required: false}, {name: 'hiddenShowPriceEFC2', label: '15J. Price for a ticket to the show for External Fan Club 2 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: 99999,required: false}, {name: 'hiddenShowPriceVIP', label: '15K. 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: 99999,required: false}, {name: 'hiddenShowFreeFC', label: '15L. Give a free ticket to CB Fanclub members?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'hiddenShowFreeMods', label: '15M1. Give a free ticket to moderators?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'hiddenShowFreeVIP', label: '15M2. Give a free ticket to members of the VIP List?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'hiddenShowFreeEFC', label: '15M3. Give a free ticket to External Fan Club Members?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'hiddenShowFreeEFC2', label: '15M4. Give a free ticket to External Fan Club 2 Members?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'hiddenShowCumulative', label: '15N. 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: '15P. 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: '15Q. 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: '15R. Allow moderators to use the "add" commands to add viewers to the show or the pre-sales list, including use of the commands to add an outstanding ticket, and add the top tippers. 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: 'No'}, {name: 'hiddenShowModsChgPrice', label: '15S. Allow moderators to change the price of a ticket?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'ticketNoticeInterval', label: '15T. 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.',type: 'str',required: false,defaultValue: 2.1}, {name: 'hiddenShowPreNotice', label: '15U. 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: '15V. 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: '15W. 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: '15X. 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: '15Y. Allow users to buy additional tickets they can use as gifts to other users', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'showTicketsAdded', label: '15Z. Show Ticket Purchased message to everyone, or just the purchaser (and mods, broadcaster)', type: 'choice', choice1: 'Everyone', choice2: 'Ticket Buyer', defaultValue: 'Everyone'}, // *** Lovense Toy Tip Menu {name: 'dummy12', label: '---------------------------------------------------------------------------------------------------- SECTION 16 - LOVENSE TOY TIP MENU', type: 'choice',required: false}, {name: 'enableLushMenu', label: '16A. 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 "/usetoy on" and "/usetoy 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', label: '16B. 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.',type: 'str',required: false,defaultValue: 2.7}, {name: 'whichToy', label: '16C. 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', choice6: 'Ferri', defaultValue: 'Lush'}, {name: 'lushMenuTxtColor', label: '16D. Choose your text color for the Toy menu',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 Pink'}, {name: 'lushMenuCustTxtColor', label: '16E. If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'lushMenuBgColor', label: '16F. 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', label: '16G. If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'dummy13', label: '16H. Toy 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', label: 'Level 1 Message',type: 'str',defaultValue: 'Level 1 (Tip 1-14) : 5 seconds on LOW vibrations',required: false}, {name: 'lushMenuLevel2', label: 'Level 2 Message',type: 'str',defaultValue: 'Level 2 (Tip 15-30) : 5 seconds on MEDIUM vibrations',required: false}, {name: 'lushMenuLevel3', label: 'Level 3 Message',type: 'str',defaultValue: 'Level 3 (Tip 31-49) : 10 seconds on MEDIUM vibrations',required: false}, {name: 'lushMenuLevel4', label: 'Level 4 Message',type: 'str',defaultValue: 'Level 4 (Tip 50-74) : 15 seconds on MEDIUM vibrations',required: false}, {name: 'lushMenuLevel5', label: 'Level 5 Message',type: 'str',defaultValue: 'Level 5 (Tip 75-99) : 30 seconds on HIGH vibrations',required: false}, {name: 'lushMenuLevel6', label: 'Level 6 Message',type: 'str',defaultValue: 'Level 6 (Tip 100-249): 30 seconds on HIGH vibrations',required: false}, {name: 'lushMenuLevel7', label: 'Level 7 Message',type: 'str',defaultValue: 'Level 7 (Tip 250-499): 1 Minute on HIGH vibrations',required: false}, {name: 'lushMenuLevel8', label: 'Level 8 Message',type: 'str',defaultValue: 'Level 8 (Tip 500+) : 5 Minutes on HIGH vibrations',required: false}, {name: 'lushMenuLevel9', label: 'Random Level Message',type: 'str',defaultValue: 'Random Level - Tip 70 to get a random level!',required: false}, {name: 'lushMenuLevel10', label: 'Pattern Level 1 Message',type: 'str',defaultValue: 'Pattern 1 - Tip 115 for a wave pattern for 30 seconds',required: false}, {name: 'lushMenuLevel11', label: 'Pattern Level 2 Message',type: 'str',defaultValue: 'Pattern 2 - Tip 116 for a block wave pattern for 30 seconds',required: false}, {name: 'lushMenuLevel12', label: 'Pattern Level 3 Message',type: 'str',defaultValue: 'Pattern 3 - Tip 117 for a pulse pattern for 30 seconds',required: false}, {name: 'lushMenuLevel13', label: 'Pattern Level 4 Message',type: 'str',defaultValue: 'Pattern 4 - Tip 118 for a constant high pattern for 30 seconds',required: false}, // *** Media Platforms {name: 'dummy14', label: '---------------------------------------------------------------------------------------------------- SECTION 17 - MEDIA LIST', type: 'choice',required: false}, {name: 'enableMediaNotice', label: '17A. 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', label: '17B. Media List Notice display interval in minutes. Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.', type: 'str',defaultValue: 5.7,required: false}, {name: 'mediaListIntro', label: '17C. Enter the Text you would like to show at the beginning of the media list to introduce the list to the user. "Next line" feature enabled with {n}.',required: false, defaultValue: 'Contact info is below for scheduling privates, shopping on amazon wishlist, and staying in touch through my various social media platforms:',type: 'str',minLength: 1,maxLength: 255}, {name: 'mediaSameLine', label: '17D. Print the media type text and actual link or ID on the same line or separate lines?', type: 'choice', choice1: 'Same Line', choice2: 'Separate Lines', defaultValue: 'Same Line'}, {name: 'mediaListTxtColor', label: '17E. Choose your text color for the Media List',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 Pink'}, {name: 'mediaListCustTxtColor', label: '17F. If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'mediaListBgColor', label: '17G. 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', label: '17H. If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'dummymedia', label: '17J. 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', label: 'Text for Item 1',type: 'str',defaultValue: 'E-mail Address',required: false}, {name: 'mediaListItem1', label: 'Item 1',type: 'str',defaultValue: 'abc@email.com',required: false}, {name: 'mediaListText2', label: 'Text for Item 2',type: 'str',defaultValue: 'Personal Website',required: false}, {name: 'mediaListItem2', label: 'Item 2',type: 'str',defaultValue: 'http://abc.web.com',required: false}, {name: 'mediaListText3', label: 'Text for Item 3',type: 'str',defaultValue: 'Twitter ID',required: false}, {name: 'mediaListItem3', label: 'Item 3',type: 'str',defaultValue: ':twitter_30x30 @Twitter',required: false}, {name: 'mediaListText4', label: 'Text for Item 4',type: 'str',defaultValue: 'Instagram ID',required: false}, {name: 'mediaListItem4', label: 'Item 4',type: 'str',defaultValue: ':inst_30x30 @Instagram',required: false}, {name: 'mediaListText5', label: 'Text for Item 5',type: 'str',defaultValue: 'Public Snapchat ID',required: false}, {name: 'mediaListItem5', label: 'Item 5',type: 'str',defaultValue: ':snapchat_30x30 @snapID',required: false}, {name: 'mediaListText6', label: 'Text for Item 6',type: 'str',defaultValue: 'Amazon Wishlist',required: false}, {name: 'mediaListItem6', label: 'Item 6',type: 'str',defaultValue: ':AmazonWLSml http://amazon.com/user',required: false}, {name: 'mediaListText7', label: 'Text for Item 7',type: 'str',defaultValue: 'Video sales site',required: false}, {name: 'mediaListItem7', label: 'Item 7',type: 'str',defaultValue: 'link to site',required: false}, {name: 'mediaListText8', label: 'Text for Item 8',type: 'str',defaultValue: 'External Fan Club',required: false}, {name: 'mediaListItem8', label: 'Item 8',type: 'str',defaultValue: 'fanclub_30x30 http://onlyfans.com/userID',required: false}, {name: 'mediaListText9', label: 'Text for Item 9',type: 'str',defaultValue: 'Misc Link 1',required: false}, {name: 'mediaListItem9', label: 'Item 9',type: 'str',defaultValue: 'Insert Link 1',required: false}, {name: 'mediaListText10', label: 'Text for Item 10',type: 'str',defaultValue: 'Misc Link 2',required: false}, {name: 'mediaListItem10', label: 'Item 10',type: 'str',defaultValue: 'Insert Link 2',required: false}, {name: 'mediaListText11', label: 'Text for Item 11',type: 'str',defaultValue: 'Misc Link 3',required: false}, {name: 'mediaListItem11', label: 'Item 11',type: 'str',defaultValue: 'Insert Link 3',required: false}, {name: 'mediaListText12', label: 'Text for Item 12',type: 'str',defaultValue: 'Misc Link 4',required: false}, {name: 'mediaListItem12', label: 'Item 12',type: 'str',defaultValue: 'Insert Link 4',required: false}, // *** Dice Game {name: 'dummy15', label: '---------------------------------------------------------------------------------------------------- SECTION 18 - DICE GAME', type: 'choice',required: false}, {name: 'dummy15a', label: 'This is a dice roll game with possible rolls of 2-12, plus 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', label: '18A. Enabled dice on Start? -- You can also turn the game on and off during the show using the "/usedice on" and "/usedice off" commands.',required: false, type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'diceRollPrice', label: '18B. Dice Roll Price',type: 'int',minValue: 1,maxValue: 1000,required: false, defaultValue: 48}, {name: 'diceRemoveWinner', label: '18C. Use prize once? -- Removes 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',required: false, type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'diceMultiRolls', label: '18D. Multiple rolls allowed? -- Set the maximum number of rolls from one tip 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.',required: false,type: 'int',minValue: 1,maxValue: 10, defaultValue: '1'}, {name: 'diceMinSpecial', label: '18E. Minimum for Rare Roll -- Set a minimum number of 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',required: false, type: 'choice', choice1: '5', choice2: '10', choice3: '15', choice4: '20',choice5: '25', choice6: '30',choice7: '40', choice8: '50',defaultValue: '15'}, {name: 'diceNoticeInterval', label: '18F. Dice Notice Interval -- Defined in minutes. Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.',type: 'str',defaultValue: 3.9,required: false}, {name: 'diceNoticeBgColor', label: '18G. Dice Game Notice Background Color',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: '18H. Dice Game Roll Results Background Color',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: '18J. Dice Game Special Dice Roll (13) Results Background Color',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', label: '18K1. Prize for dice roll of 2',required: false,type: 'str',defaultValue: 'Boob Flash'}, {name: 'dicePrize_3', label: '18K2. Prize for dice roll of 3',required: false,type: 'str',defaultValue: 'Booty Flash'}, {name: 'dicePrize_4', label: '18K3. Prize for dice roll of 4',required: false,type: 'str',defaultValue: 'Naked Jumping Jacks'}, {name: 'dicePrize_5', label: '18K4. Prize for dice roll of 5',required: false,type: 'str',defaultValue: '3 Spanks'}, {name: 'dicePrize_6', label: '18K5. Prize for dice roll of 6',required: false,type: 'str',defaultValue: 'Sexy Strip Tease'}, {name: 'dicePrize_7', label: '18K6. Prize for dice roll of 7',required: false,type: 'str',defaultValue: 'Lap Dance'}, {name: 'dicePrize_8', label: '18K7. Prize for dice roll of 8',required: false, type: 'str', defaultValue: 'Naked Squats'}, {name: 'dicePrize_9', label: '18K8. Prize for dice roll of 9',required: false, type: 'str', defaultValue: '5 Spanks'}, {name: 'dicePrize_10', label: '18K9. Prize for dice roll of 10',required: false, type: 'str', defaultValue: 'Naked Dancing'}, {name: 'dicePrize_11', label: '18K10. Prize for dice roll of 11',required: false, type: 'str', defaultValue: 'Pussy or Cock Flash'}, {name: 'dicePrize_12', label: '18K11. Prize for dice roll of 12',required: false, type: 'str', defaultValue: 'Oil and Massage Boobs'}, {name: 'dicePrize_13', label: '18K12. Prize for dice roll of 13 (Rare special prize)',required: false, type: 'str', defaultValue: '5 Min BJ'}, // *** Room Rules {name: 'dummy17', label: '---------------------------------------------------------------------------------------------------- SECTION 19 - ROOM RULES', type: 'choice',required: false}, {name: 'dummy17a', label: 'Define up to 8 rules that will be displayed to user. If enabled, the rules will be shown to every user when they enter the room, and can also be displayed on the chat on a recurring basis if you define a timer. Note that the "Next line" feature can be triggered with "{n}"', type: 'choice',required: false}, {name: 'enableRoomRules', label: '19A. Display on User Entry?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'roomRule1', label: '19B1. Rule #1', required: false,type: 'str', minLength: 0, maxLength: 200, defaultValue: 'Rule #1: No Demanding! Please put all sexy talk and requests in a tip note.'}, {name: 'roomRule2', label: '19B2. Rule #2', required: false,type: 'str', minLength: 0, maxLength: 200}, {name: 'roomRule3', label: '19B3. Rule #3', required: false,type: 'str', minLength: 0, maxLength: 200}, {name: 'roomRule4', label: '19B4. Rule #4', required: false,type: 'str', minLength: 0, maxLength: 200}, {name: 'roomRule5', label: '19B5. Rule #5', required: false,type: 'str', minLength: 0, maxLength: 200}, {name: 'roomRule6', label: '19B6. Rule #6', required: false,type: 'str', minLength: 0, maxLength: 200}, {name: 'roomRule7', label: '19B7. Rule #7', required: false,type: 'str', minLength: 0, maxLength: 200}, {name: 'roomRule8', label: '19B8. Rule #8', required: false,type: 'str', minLength: 0, maxLength: 200}, {name: 'roomRulesInterval', label: '19C. Room Rules display interval -- Defined in minutes, leave at zero to disable the recurring message (will still be shown when they enter based on "enable" setting above). Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.',type: 'str',defaultValue: 0,required: false}, {name: 'roomRulesTextColor', label: '19D. Room Rules Text Color', 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 Orange'}, {name: 'roomRulesTextCustColor', label: '19E. Room Rules Custom Text Color -- Enter the hex color (6 character hex color codes plus the # prefix)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'roomRulesBgColor', label: '19F. Room Rules 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 Orange'}, {name: 'roomRulesBgCustColor', label: '19G. Room Rules Custom Background Color -- Enter the hex color (6 character hex color codes plus the # prefix)', type: 'str',minLength: 1,maxLength: 7,required: false}, // *** Followers {name: 'dummy20', label: '---------------------------------------------------------------------------------------------------- SECTION 20 - FOLLOWERS', type: 'choice',required: false}, {name: 'dummy20a', label: 'CB has enabled Apps and Bots to receive notification when you get a new follower. This section defines some of the settings around how the Fembot tracks this information and potentially displays messges each time someone joins, as well as a recurring message to the broadcaster with summary stats, and a recurring reminder to the chat to follow your room. Settings 20A-20C define the behavior each time a new follower joins, and settings 20D-20G define the recurring notice behavior. The same color scheme is used for both sets.', type: 'choice',required: false}, {name: 'followerNotify', label: '20A. Display a message when you get a new follower? You can send a message to the Broadcaster, the new follower, or both, or to everyone in the room, or neither. If sending a message to the new follower, the message text can be customized below in setting 20C', type: 'choice', choice1: 'No', choice2: 'Yes, only to follower', choice3: 'Yes, only to broadcaster', choice4: 'Yes, to both', choice5: 'Yes, to everyone', defaultValue: 'No'}, {name: 'followerNotifyColor', label: '20B. If sending to broadcaster, send for only certain color users?', type: 'choice', choice1: 'Show All', choice2: 'Not For Gray Users', choice3: 'Not For Gray and Light Blue Users', defaultValue: 'Not For Gray Users'}, {name: 'followerMessage', label: '20C. If enabled in 20A, define the message to send to new followers or the public chat. Note that you can include the identifier {username} to have the username of the person show within the message (including brackets). Just make sure there is a space on either side of {username} so that it is recognized. You can also include icons and emojis and change the color using settings 20H-20L', required: false,type: 'str', minLength: 0, maxLength: 200, defaultValue: 'Thank you {username} for following my room!'}, {name: 'followerStatsEnable', label: '20D. Send summary follower stats to broadcaster? If enabled, it will be sent to the broadcaster only, at the same time as the follow reminder (same interval is used for both, even if only one is enabled)', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'followerReminderEnable', label: '20E. Send "follow" reminder message to general chat? If enabled, it will be sent at the same time as the summary stats to the broadcaster (same interval is used for both, even if only one is enabled), and text can be customized below in setting 20F', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'followReminder', label: '20F. If enabled in 20E, enter the Reminder Message to display', required: false,type: 'str', minLength: 0, maxLength: 200, defaultValue: 'Please make sure to hit the :follow2a button to be notified of the next show!'}, {name: 'followNoticeInterval', label: '20G. Reminder and Stats Summary display interval (whichever are enabled in 20D and 20E will be displayed) -- Defined in minutes, decimals are ok as long as the value is greater than 1. For example, 1.5 = one minute 30 second interval.',type: 'str',defaultValue: 4.8,required: false}, {name: 'followTextColor', label: '20H. Follower Response Message Text Color', 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: 'followCustomTextColor', label: '20J. Follower Response Messaging Custom Text Color -- Enter the hex color (6 character hex color codes plus the # prefix)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'followBgColor', label: '20K. Follower Response Messaging 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: 'followCustomBgColor', label: '20L. Follower Response Messaging Custom Background Color -- Enter the hex color (6 character hex color codes plus the # prefix)', type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'followNoticeTextColor', label: '20M. Follower Reminder Notice Text Color', 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: 'followNoticeCustomTextColor',label: '20N. Follower Reminder Notice Custom Text Color -- Enter the hex color (6 character hex color codes plus the # prefix)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'followNoticeBgColor', label: '20P. Follower Reminder Notice 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: 'followNoticeCustomBgColor', label: '20Q. Follower Reminder Notice Custom Background Color -- Enter the hex color (6 character hex color codes plus the # prefix)', type: 'str',minLength: 1,maxLength: 7,required: false}, // *** Text Poll {name: 'dummy21', label: '---------------------------------------------------------------------------------------------------- SECTION 21 - TEXT POLL', type: 'choice',required: false}, {name: 'dummy21a', label: 'You can conduct a text poll by monitoring what people type to count as votes rather than by monitoring tips. You can either define the poll options below at the start of the show, or you can define them at any time within the show using commands. Users will vote by typing the option ID (1-5) of their choice, and they can only vote 1 time. Moderators can add votes using commands if Mod Trust level is Standard or Advanced. You can choose to end the poll based on a timer, winning number of votes, total number of votes, or at your discretion', type: 'choice',required: false}, {name: 'textPollEnable', label: '21A. Enable at start of show? -- Note you can also turn the token poll on and off during the show using the "/usetextpoll on" and "/usetextpoll off" commands.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'textPollTitle', label: '21B. Poll Title (optional)',type: 'str',required: false, minLength: 1, maxLength: 50}, {name: 'textPollMode', label: '21C. End Poll Mode - Will it be ended manually by the mod or broadcaster (default), use a timer, or go until there are 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 total votes',choice4: 'Ends when one option reaches X votes',type: 'choice',defaultValue: 'Ends by Mod/Broadcaster command'}, {name: 'textPollCount', label: '21D. End Poll Amount - Per the above choice for Poll Type, choose value for X (in minutes or votes) ',type: 'int',required: false,minValue: 1,defaultValue: 1}, {name: 'textPollFanClubDouble', label: '21E. Fan club vote counts double?',type: 'choice',choice1: 'Yes',choice2: 'No',defaultValue: 'No'}, {name: 'textPollInterval', label: '21G. Display Interval -- Time interval for displaying the Text Poll vote summary (in minutes). Decimals are ok as long as they are greater than 1. For example, 1.5 = one minute 30 second intervals.', type: 'str',defaultValue: 2.0,required: false}, {name: 'textPollOpt1', label: '21H1. Option 1',type: 'str',minLength: 1,maxLength: 50,defaultValue: 'Yes',required: false}, {name: 'textPollOpt2', label: '21H2. Option 2',type: 'str',minLength: 1,maxLength: 50,defaultValue: 'No',required: false}, {name: 'textPollOpt3', label: '21H3. Option 3',type: 'str',minLength: 1,maxLength: 50,required: false}, {name: 'textPollOpt4', label: '21H4. Option 4',type: 'str',minLength: 1,maxLength: 50,required: false}, {name: 'textPollOpt5', label: '21H5. Option 5',type: 'str',minLength: 1,maxLength: 50,required: false}, {name: 'textPollTextColor', label: '21J. Text Poll Notice text color',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 Green'}, {name: 'textPollCustTextColor', label: '21K. If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'textPollBgColor', label: '21L. Text Poll Notice 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: 'textPollCustBgColor', label: '21M. If you picked a custom background highlight color in the previous setting, enter the hex color (6 character hex color codes plus the # prefix):',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'textPollSepBot', label: '21N. Running the Dorothy\'s Text Poll bot instead of the poll feature here in the Fembot? When set to "Yes", the Fembot will ignore the commands used for the separate bot since they are the same',type: 'choice',choice1: 'Yes',choice2: 'No',defaultValue: 'No'} ]; } { // *********************************** Variables and Arrays ************************************** var initialize = 0; var numPMs = 0; var BC = cb.room_slug; var currentSessionTotal = 0; var clockStartTime = 0; var clockStopTime = 0; var clockTimeAdded = 0; var clockMinsRemain = 0; var clockSecsRemain = 0; var clock2StartTime = 0; var clock2StopTime = 0; var clock2TimeAdded = 0; var clock2MinsRemain = 0; var clock2SecsRemain = 0; var clock3StartTime = 0; var clock3StopTime = 0; var clock3TimeAdded = 0; var clock3MinsRemain = 0; var clock3SecsRemain = 0; var clock4StartTime = 0; var clock4StopTime = 0; var clock4TimeAdded = 0; var clock4MinsRemain = 0; var clock4SecsRemain = 0; var timerDesc = cb.settings.defaultTimerDesc; var timer2Desc = cb.settings.defaultTimerDesc2; var timer3Desc = ''; var timer4Desc = ''; var freqPrev = 0; var freqCurrent = 0; var silenceLevel = cb.settings.initialSilenceLevel; var graphicLevel = cb.settings.initialGraphicsLevel; var showNinjadMsgs = cb.settings.showNinjadMsgs; var showSilencedMsgs = cb.settings.showSilencedMsgs; var iconMods = cb.settings.iconMods; var iconFans = cb.settings.iconFans; var iconExtFans = cb.settings.iconExtFans; var iconExtFans2 = cb.settings.iconExtFans2; var iconVIP = cb.settings.iconVIP; var iconBotMods = cb.settings.iconBotMods; var caps = /[A-Z][A-Z]+/; var minMessagesForNotice = cb.settings.minMessagesForNotice; var borderChar = ''; var borderCharSpacing = ''; var suppressCapsToggle = true; var tipnoteWarned = false; //var minTimeForNotice = cb.settings.minTimeForNotice; var minTimeForNotice = 0; var msgCounterTipMenu = 0; var msgCounterPosMenu = 0; var msgCounterLushMenu = 0; var msgCounterDice = 0; var msgCounterNotifier = 0; var msgCounterTokenPoll = 0; var msgCounterLeaderboard = 0; var msgCounterRules = 0; var msgCounterPresales = 0; var msgCounterMedia = 0; var msgCounterIconNotice = 0; var msgCounterKing = 0; var msgCounterKingSession = 0; var msgCounterFollow = 0; var msgCounterTextPoll = 0; 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 allTimeToggle = 0; var requireAnswerToggle = 0; var roomRuleToggle = 0; var textPollToggle = false; //Colors var textPollBgColor = ''; var textPollTextColor = ''; var numberOfTippers = 0; var firstlb = 0; var firstmedia = 0; var leaderTimer = 0; var num = 0; var minTipToChat = parseInt(cb.settings.minTipToChat); var leaderSize = parseInt(cb.settings.leaderBoardSize); var whichToy = cb.settings.whichToy; var currentKingTipperAmount = 0; var currentKingTipper = ''; var kingTipperColorSet = false; var currentKingTipper = ''; var kingTipperName = ''; var followerNotifyFlag = 0; var firstFollowMsg = true; var numNewFollowersGray = 0; var numNewFollowersLBlue = 0; var numNewFollowersDBlue = 0; var numNewFollowersLPurple = 0; var numNewFollowersDPurple = 0; var numNewFollowersTotal = 0; var grayChatTime = cb.settings.grayChatTime; var requireAnswerLevel = 0; var requireAnswerLevelText = cb.settings.requireAnswerLevel; 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 backupPrice = 0; var ticketShowEnded = false; var ticketSalesEnded = false; 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 iconTipAmount1 = cb.settings.iconTipAmount1; var iconTipAmount2 = cb.settings.iconTipAmount2; var iconTipAmount3 = cb.settings.iconTipAmount3; var iconTipAmount4 = cb.settings.iconTipAmount4; var iconTipAmount5 = cb.settings.iconTipAmount5; var iconTipIcon1 = cb.settings.iconTipIcon1; var iconTipIcon2 = cb.settings.iconTipIcon2; var iconTipIcon3 = cb.settings.iconTipIcon3; var iconTipIcon4 = cb.settings.iconTipIcon4; var iconTipIcon5 = cb.settings.iconTipIcon5; var tipForIconType = cb.settings.tipForIconType; var appNoticeColor = '#a2dfac'; // Used for general messaging from fembot (green) var appWarningColor = '#f4d599'; // Used for general messaging from fembot (yellow) var appAlertColor = '#f4c1bc'; // Used for general messaging from fembot (red) 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 lightblue = '#add8e6'; var lightmagenta = '#ffa6ff'; 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 = '#e9f9ff'; // Light blue highlighting for ticket show buyers var ticketStatsBgColor = '#e0e0e0'; // Light gray for ticket show stats background var kingTipperBgColor = '#efe9ff'; // Light purple highlighting for king tipper var moderatorBgColor = '#ffe7e7'; // Light red highlighting for moderators var fanclubBgColor = '#e6f9e6'; // Light green highlighting for CB Fanclub var tipnoteyellow = '#ffff00'; // Forwarded Tip notes var dashLine60 = new Array(60).join('-'); var dashLine70 = new Array(70).join('-'); var dashLine80 = new Array(80).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 hiddenShowModsAdd = (cb.settings.hiddenShowModsAdd === 'Yes'); var ticketShowGoal = parseInt(cb.settings.hiddenShowGoal); var suppressPrefix = false; var roomRule1 = cb.settings.roomRule1; var roomRule2 = cb.settings.roomRule2; var roomRule3 = cb.settings.roomRule3; var roomRule4 = cb.settings.roomRule4; var roomRule5 = cb.settings.roomRule5; var roomRule6 = cb.settings.roomRule6; var roomRule7 = cb.settings.roomRule7; var roomRule8 = cb.settings.roomRule8; var allTimeAmount1 = cb.settings.allTimeAmount1; var allTimeAmount2 = cb.settings.allTimeAmount2; var allTimeAmount3 = cb.settings.allTimeAmount3; var allTimeAmount4 = cb.settings.allTimeAmount4; var allTimeAmount5 = cb.settings.allTimeAmount5; var allTimeAmount6 = cb.settings.allTimeAmount6; var allTimeAmount7 = cb.settings.allTimeAmount7; var allTimeAmount8 = cb.settings.allTimeAmount8; var allTimeIcon1 = cb.settings.allTimeIcon1; var allTimeIcon2 = cb.settings.allTimeIcon2; var allTimeIcon3 = cb.settings.allTimeIcon3; var allTimeIcon4 = cb.settings.allTimeIcon4; var allTimeIcon5 = cb.settings.allTimeIcon5; var allTimeIcon6 = cb.settings.allTimeIcon6; var allTimeIcon7 = cb.settings.allTimeIcon7; var allTimeIcon8 = cb.settings.allTimeIcon8; var enableAutoResponse = cb.settings.enableAutoResponse; var autoResponseWord1 = cb.settings.autoResponseWord1; var autoResponse1 = cb.settings.autoResponse1; var autoResponseWord2 = cb.settings.autoResponseWord2; var autoResponse2 = cb.settings.autoResponse2; var autoResponseWord3 = cb.settings.autoResponseWord3; var autoResponse3 = cb.settings.autoResponse3; var viewerNotesWhen = cb.settings.viewerNotesWhen; var viewerNotesWho = cb.settings.viewerNotesWho; var modSpecificMenuItems = false; var cbfcSpecificMenuItems = false; var efc1SpecificMenuItems = false; var efc2SpecificMenuItems = false; var vipSpecificMenuItems = false; var menuListSplit = true; var noticeOnlyBC = 'Fembot: Only broadcasters are able to use that command.'; var noticeOnlyBCMod1 = 'Fembot: Only broadcasters and moderators are able to use that command.'; var noticeOnlyBCMod2 = 'Fembot: Only broadcasters and "Standard/Advanced" moderator levels are able to use that command.'; var noticeOnlyBCMod3 = 'Fembot: Only broadcasters and the "Advanced" moderator level are able to use that command.'; var noticeOnlyBCMod3A = 'Fembot: Only broadcasters and moderators with configured "add" and "remove" authority are able to use that command.'; var tipNoteForwardID = ''; var themeWarning = false; var themeWarning2 = false; var themeWarning3 = false; var themeWarning4 = false; var themeWarning5 = false; // Arrays */ var niceListArray = []; var silenceListArray = []; var ninjaListArray = []; var VIPListArray = []; var VIPInShowArray = []; var extFanListArray = []; var extFanInShowArray = []; var extFanList2Array = []; var extFanInShow2Array = []; var notifierArray = []; var wordListArray = []; var wordListArrayTemp = []; var wordListArrayPub = []; var wordListArrayPubTemp = []; var MessageArray = []; var capsMessageArray = []; var pmArray = []; var backupListArray = []; var presaleArray = []; var grayLockList = []; var answerLockList = []; var answerLockStatus = []; var answerLockQuestion = [0]; var fanClubList = []; var ticketShowViewerList = []; var ticketCumulative = {name: [], amount: []}; var alltimeIconArray = {amount: [], icon: []}; var moderatorList = {name: [], type: []}; var botModListArray = []; var exemptCmdList = []; 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 allTimeArray = {name: [], totaltips: []}; var ticketShowExtraTickets = {name: [], count: []}; var lockQuestions = ['three + four = ____ (three, five, or seven)','the grass is _____ (yellow, green, or blue)','spiders have _____ legs (four, six, or eight)','an octogon has _____ sides (six, eight, or ten)','an apple is a _____ (meat, vegetable, or fruit)','Lebron James plays _____ (basketball, golf, or football)','Christmas is in _____ (january,march,december)','Tallahassee is the capital of _____ (oklahoma, florida, or ohio)','there are _____ minutes in an hour (twelve, sixty, or ninety)','Berlin is in _____ (germany, spain, or portugal)']; var lockAnswers = ['seven','green','eight','eight','fruit','basketball','december','florida','sixty','germany']; var roomRulesArray = []; var iconTipAmountArray = []; var iconTipIconArray = []; var tipForIconArray = {name: [], icon: []}; var viewerNotesArray = {username: [], notes: [], displayed: [], addinshow: []}; var tipMenuRequests = {name: [], amt: [], desc: []}; var tipMenuRequestTime = []; var textPollArray = {dispname: [], voteID: [], votes: []}; var followerThresholdArray = [1000,2000,3000,4000,5000,6000,7000,8000,9000,10000,15000,20000,25000,30000,40000,50000,60000,70000,75000,80000,90000,100000,125000,150000,175000,200000,250000,300000,400000,500000,1000000,5000000,10000000,100000000]; // **** Tip Menu Variables var TIPMENU = { menuDspIntTime: 0, sepChar: '| ', tipMenu: '', menuPartArray: [], menuToken: 1, tipMenuPrice: [], tipMenuItem: [], txtColor1: '', bgColor1: '', txtColor2: '', bgColor2: '', txtColorTip: '', bgColorTip: '', menuLength: 0, }; var TIPMENU2 = { menuDspIntTime: 0, sepChar: '| ', tipMenu: '', menuPartArray: [], menuToken: 1, tipMenuPrice: [], tipMenuItem: [], txtColor1: '', bgColor1: '', txtColor2: '', bgColor2: '', txtColorTip: '', bgColorTip: '', menuLength: 0, }; var TIPMENUMOD = { menuDspIntTime: 0, sepChar: '| ', tipMenu: '', menuPart1: '', menuPart2: '', menuToken: 1, tipMenuPrice: [], tipMenuItem: [], menuLength: 0, }; var TIPMENUCBFC = { menuDspIntTime: 0, sepChar: '| ', tipMenu: '', menuPart1: '', menuPart2: '', menuToken: 1, tipMenuPrice: [], tipMenuItem: [], menuLength: 0, }; var TIPMENUEFC1 = { menuDspIntTime: 0, sepChar: '| ', tipMenu: '', menuPart1: '', menuPart2: '', menuToken: 1, tipMenuPrice: [], tipMenuItem: [], menuLength: 0, }; var TIPMENUEFC2 = { menuDspIntTime: 0, sepChar: '| ', tipMenu: '', menuPart1: '', menuPart2: '', menuToken: 1, tipMenuPrice: [], tipMenuItem: [], menuLength: 0, }; var TIPMENUVIP = { menuDspIntTime: 0, sepChar: '| ', tipMenu: '', menuPart1: '', menuPart2: '', menuToken: 1, tipMenuPrice: [], tipMenuItem: [], menuLength: 0, }; var POSTIPMENU = { posMenuDspIntTime: 0, posSepChar: '| ', posTipMenu: '', posTipMenuPrice: [], posTipMenuItem: [], posTxtColor: '', posBgColor: '', posMenuLength: 0, posRequesters: [], posRequest: [], posRequestTime: [0], }; var LUSHMENU = { lushMenuDspIntTime: 0, lushMenu: '', lushMenuLevel: [], lushTxtColor: '', lushBgColor: '', lushMenuLength: 0, }; // ************ Variables for Token Poll 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 stealPollAmount = cb.settings.stealPollAmount; 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 pollNoticeInt = 0; var pollMinimum = cb.settings.pollMinimum; var totalPollVotes = 0; var pollTitle = cb.settings.pollTitle; // ************ Variables for On-demand Token Poll var odpollType; var odpollModAdd = 'Yes'; var odpollMinsRemain = 0; var odpollSecsRemain = 0; var ODpollNoticeInt = 0; var onDemandPollRunning = false; var onDemandPollEnabled = false; var odpollTitle = 'Poll Topic'; var tempODPollLabels = []; var tempODPollAmounts = []; var odpollArrayAmount = []; var odpollArrayLabel = []; var odpollArrayVotes = []; var nlineOD = 0; // ************ Variables for Text Poll var textPollType; var textPollFanDouble = (cb.settings.textPollFanClubDouble == 'Yes'); var textPollStartTime; var textPollStopTime; var textPollMinsRemain = cb.settings.textPollCount; var textPollSecsRemain = 60; var textPollVotesRemain = 0; var textPollRunning = false; var ntxtline = 0; var textPollOpt1 = cb.settings.textPollOpt1; var textPollOpt2 = cb.settings.textPollOpt2; var textPollOpt3 = cb.settings.textPollOpt3; var textPollOpt4 = cb.settings.textPollOpt4; var textPollOpt5 = cb.settings.textPollOpt5; var textPollNoticeInt = 0; var textPollTotalVotes = 0; var textPollTitle = cb.settings.textPollTitle; // ************ 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 = ':gbdie'; var diceRarePct = 20; var firstDice = 0; } { // *********************************** Functions ************************************** { // Generic functions to set the color or separator characters function checkTextColor(inputcolortxt,usethemetxt) { tempthemetxt = cb.settings.colorTheme; if (!usethemetxt) { tempthemetxt = 'None'; } if (tempthemetxt == 'Placeholder - do not use') { tempthemetxt = 'None'; if (!themeWarning) { cb.sendNotice('Warning! Invalid theme setting of "' + cb.settings.colorTheme + '". Defaulting to no theme used.',cb.room_slug,appWarningColor); themeWarning = true; } } if (tempthemetxt == 'Custom Linear') { temptextcolor = cb.settings.colorThemeCustText; if (/^#[0-9A-F]{6}$/i.test(temptextcolor)) { return temptextcolor; } else if (/^[0-9A-F]{6}$/i.test(temptextcolor)) { return ('#' + temptextcolor); } else { return 'default'; } } else if (tempthemetxt != 'None') { if (cbjs.arrayContains(themeArray.name,tempthemetxt)) { themeidx = themeArray.name.indexOf(tempthemetxt); return themeArray.textcolor[themeidx]; } else { cb.sendNotice('Warning! Invalid theme setting of "' + cb.settings.colorTheme + '". \nDefaulting to no theme used.',cb.room_slug,appWarningColor); tempthemetxt = 'None'; } } if (tempthemetxt == 'None') { switch (inputcolortxt) { 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'; case 'Dark Gold': return '#998100'; case 'Dark Teal': return '#003f1f'; case 'Dark Brown': return '#582c00'; case 'Dark Bronze': return '#a56728'; case 'Dark Periwinkle': return '#155bd7'; case 'Dark Fuschia': return '#d6155c'; case 'Dark Lime': return '#6b790c'; case 'Dark Plum': return '#7f13bf'; default: if (/^#[0-9A-F]{6}$/i.test(inputcolortxt)) { return inputcolortxt; } else if (/^[0-9A-F]{6}$/i.test(inputcolortxt)) { return ('#' + inputcolortxt); } else { return 'default'; } } } } function checkBgColor(inputcolor,usetheme) { selectedcolor = 'default'; temptheme = cb.settings.colorTheme; if (!usetheme) { temptheme = 'None'; } if (temptheme == 'Placeholder - do not use') { temptheme = 'None'; if (!themeWarning) { cb.sendNotice('Warning! Invalid theme setting of "' + cb.settings.colorTheme + '". \nDefaulting to no theme used.',cb.room_slug,appWarningColor); themeWarning = true; } } if (cb.settings.colorsGradientDirection == 'Linear, left to right') { graddir = 'to right'; } else if (cb.settings.colorsGradientDirection == 'Linear, top to bottom') { graddir = 'to bottom'; } else if (cb.settings.colorsGradientDirection == 'Linear, diagonally') { graddir = 'to right bottom'; } else if (cb.settings.colorsGradientDirection == 'No') { graddir = 'to right bottom'; } if (temptheme == 'Custom Linear') { if (cb.settings.colorThemeCustBg1) { if (/^#[0-9A-F]{6}$/i.test(cb.settings.colorThemeCustBg1)) { themeCustBg1 = cb.settings.colorThemeCustBg1; } else if (/^[0-9A-F]{6}$/i.test(cb.settings.colorThemeCustBg1)) { themeCustBg1 = '#' + cb.settings.colorThemeCustBg1; } else { if (!themeWarning2) { cb.sendNotice('Warning! Custom color theme selected but Background 1 is not in the correct hex color code format. \nDefaulting to no theme used.',cb.room_slug,appWarningColor); themeWarning2 = true; } temptheme = 'None'; } } else { if (!themeWarning3) { cb.sendNotice('Warning! Custom color theme selected but Background 1 is not configured. \nDefaulting to no theme used.',cb.room_slug,appWarningColor); themeWarning3 = true; } temptheme = 'None'; } if (cb.settings.colorThemeCustBg2) { if (/^#[0-9A-F]{6}$/i.test(cb.settings.colorThemeCustBg2)) { themeCustBg2 = cb.settings.colorThemeCustBg2; } else if (/^[0-9A-F]{6}$/i.test(cb.settings.colorThemeCustBg2)) { themeCustBg2 = '#' + cb.settings.colorThemeCustBg2; } else { themeCustBg2 = '#ffffff'; if (!themeWarning4) { cb.sendNotice('Warning! Custom color theme selected but Background 2 is not configured with a proper hex color code. \nDefaulting second color to white.',cb.room_slug,appWarningColor); themeWarning4 = true; } } } else { themeCustBg2 = '#ffffff'; if (!themeWarning5) { cb.sendNotice('Warning! Custom color theme selected but Background 2 is not configured. \nAt least two colors are required, defaulting second color to white.',cb.room_slug,appWarningColor); themeWarning5 = true; } } if (cb.settings.colorThemeCustBg3) { numbercustcolors = 3; if (/^#[0-9A-F]{6}$/i.test(cb.settings.colorThemeCustBg3)) { themeCustBg3 = cb.settings.colorThemeCustBg3; } else if (/^[0-9A-F]{6}$/i.test(cb.settings.colorThemeCustBg3)) { themeCustBg3 = '#' + cb.settings.colorThemeCustBg3; } else { themeCustBg3 = '#ffffff'; } } else { numbercustcolors = 2; } if (temptheme != 'None') { if (numbercustcolors == 2) { return 'linear-gradient(' + graddir + ', ' + themeCustBg1 + ', ' + themeCustBg2 + ')'; } else { return 'linear-gradient(' + graddir + ', ' + themeCustBg1 + ', ' + themeCustBg2 + ', ' + themeCustBg3 + ')'; } } // else if (temptheme == 'Custom Radial') { // return 'radial-gradient(circle, ' + cb.settings.colorThemeCustBg1 + ', ' + cb.settings.colorThemeCustBg2 + ')'; } else if (temptheme != 'None') { if (cbjs.arrayContains(themeArray.name,temptheme)) { themeidx = themeArray.name.indexOf(temptheme); return themeArray.colorID[themeidx]; } else { cb.sendNotice('Warning! Invalid theme setting of "' + cb.settings.colorTheme + '". \nDefaulting to no theme used.',cb.room_slug,appWarningColor); temptheme = 'None'; } } if (temptheme == 'None') { switch (inputcolor) { case 'White/No Color': selectedcolor = '#FFFFFF'; break; case 'Light Aqua': selectedcolor = '#adeaea'; break; case 'Light Pink': selectedcolor = '#FFE6EA'; break; case 'Light Green': selectedcolor = '#94e594'; break; case 'Light Red': selectedcolor = '#ff9a9a'; break; case 'Light Purple': selectedcolor = '#f2cdff'; break; case 'Light Orange': selectedcolor = '#ffd9b3'; break; case 'Light Grey': selectedcolor = '#e6e6e6'; break; case 'Light Blue': selectedcolor = '#d1eaee'; break; case 'Light Yellow': selectedcolor = '#ffff94' break; case 'Cream': selectedcolor = '#f9f6ed' break; case 'Light Bronze': selectedcolor = '#ebccad'; break; case 'Light Periwinkle': selectedcolor = '#d7e4fb'; break; case 'Light Teal': selectedcolor = '#d7fbee'; break; case 'Light Fuschia': selectedcolor = '#fbd7e4'; break; case 'Light Lime': selectedcolor = '#ecf6a7'; break; case 'Light Plum': selectedcolor = '#e3c0f9'; break; default: if (/^#[0-9A-F]{6}$/i.test(inputcolor)) { selectedcolor = inputcolor; } else if (/^[0-9A-F]{6}$/i.test(inputcolor)) { selectedcolor = '#' + inputcolor; } else { return 'default'; } } if (cb.settings.colorsGradientDirection == 'Linear, left to right') { return 'linear-gradient(to right, ' + selectedcolor + ', #ffffff)'; } else if (cb.settings.colorsGradientDirection == 'Linear, top to bottom') { return 'linear-gradient(to bottom, ' + selectedcolor + ', #ffffff)'; } else if (cb.settings.colorsGradientDirection == 'Linear, diagonally') { return 'linear-gradient(to right bottom, ' + selectedcolor + ', #ffffff)'; // } else if (cb.settings.colorsGradientDirection == 'Circular') { // return 'radial-gradient(circle, ' + selectedcolor + ', #ffffff)'; } else if (cb.settings.colorsGradientDirection == 'No') { return selectedcolor; } else { return 'default'; } } } function checkPMColor(inputcolorpm) { if (/^#[0-9A-F]{6}$/i.test(inputcolorpm)) { return inputcolorpm; } else if (/^[0-9A-F]{6}$/i.test(inputcolorpm)) { return ('#' + inputcolorpm); } else { return 'default'; } } function checkSepChar(inputchar) { if (cbjs.arrayContains(separatorArray.dispname,inputchar)) { var charidx = separatorArray.dispname.indexOf(inputchar); return separatorArray.charID[charidx]; } else { 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,appWarningColor); } 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,etc) and not recommended for any specific feature price. \nIt is recommended to use uncommon tip amounts for all prices.',sendto,appWarningColor); } 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); } } } } //********** Room Stats Functions ************** function displayRoomStats(statsendto) { cb.getRoomOwnerData(ownerData => { if (ownerData['success']) { cb.sendNotice('Room Stats:' + '\n \u21D2 Fembot Time Online: ' + timeOnline() + '\n \u21D2 Total Tips this session: ' + currentSessionTotal + ' tokens ($' + Number(currentSessionTotal*.05).toFixed(2) + ' @ 5 cents per token)' + '\n \u21D2 Total Followers: ' + ownerData['data']['followers'] , statsendto, lightmagenta); if (ownerData['data']['chat_allowed_by'] == 'public' ) { cb.sendNotice('Room Status: Public (you are broadcasting to everyone in the room).', statsendto, appNoticeColor); } else if (ownerData['data']['chat_allowed_by'] == 'all' ) { chatAllowedBy = 'All users'; } else if (ownerData['data']['chat_allowed_by'] == 'tip_recent' ) { chatAllowedBy = 'Users who have tipped me recently'; } else if (ownerData['data']['chat_allowed_by'] == 'tip_anytime' ) { chatAllowedBy = 'Users who have tipped me'; } else if (ownerData['data']['chat_allowed_by'] == 'tokens' ) { chatAllowedBy = 'Users with tokens'; } else { chatAllowedBy = 'Unexpected Setting'; } cb.sendNotice('Current Room Settings:' + '\n \u21D2 Cam available to genders (m=male,f=female,c=couple,t=trans): ' + ownerData['data']['show_cam_to_genders'] + '\n \u21D2 Fan Club cost: ' + ownerData['data']['fanclub_cost'] + ' tokens / month' + '\n \u21D2 Setting for Allow Private Shows: ' + ownerData['data']['allow_private_shows'] + '\n \u21D2 Setting for Allow Private Show Recordings: ' + ownerData['data']['allow_private_show_recordings'] + '\n \u21D2 Private show cost: ' + ownerData['data']['private_show_tokens_per_minute'] + ' tokens / minute' + '\n \u21D2 Private show minimum duration: ' + ownerData['data']['private_show_minimum_minutes'] + ' minutes' + '\n \u21D2 Spy on Private show cost: ' + ownerData['data']['spy_on_private_show_tokens_per_minute'] + ' tokens / minute' + '\n \u21D2 Token balance required to request private: ' + ownerData['data']['token_balance_to_request_private_show'] + ' tokens' + '\n \u21D2 Chat allowed for certain users?: ' + chatAllowedBy , statsendto, lightblue); if (ownerData['data']['room_status'] == 'public' ) { cb.sendNotice('Room Status: \n \u21D2 Public (you are broadcasting to everyone in the room).', statsendto, appNoticeColor); } else if (ownerData['data']['room_status'] == 'private' ) { cb.sendNotice('Room Status: \n \u21D2 ' + ownerData['data']['room_status'] + '. \nWarning! Your room is currently hidden for a private show.', statsendto, appWarningColor); } else if (ownerData['data']['room_status'] == 'group' ) { cb.sendNotice('Room Status: \n \u21D2 ' + ownerData['data']['room_status'] + '. \nWarning! Your room is currently hidden for a group show.', statsendto, appWarningColor); } else if (ownerData['data']['room_status'] == 'hidden' ) { cb.sendNotice('Room Status: \n \u21D2 ' + ownerData['data']['room_status'] + '. \nWarning! Your room is currently hidden for a ticket show (or other restricted access show).', statsendto, appWarningColor); } else if (ownerData['data']['room_status'] == 'password protected' ) { cb.sendNotice('Room Status: \n \u21D2 ' + ownerData['data']['room_status'] + '. \nWarning! Your room is currently hidden for a password show. \nYou can remove the password under the "Settings & Privacy" tab to go back to public broadcast.', statsendto, appWarningColor); } } else { cb.sendNotice('Error retrieving Room Statistics from CB.', statsendto, appWarningColor); } }); } function checkPasswordLock() { cb.getRoomOwnerData(ownerData => { if (ownerData['success']) { if (ownerData['data']['room_status'] == 'password protected' ) { cb.sendNotice('Reminder -- Your room is currently hidden for a password show. \nYou can remove the password under the "Settings & Privacy" tab and then click "Update Settings" when you are ready to go back to a public broadcast.', cb.room_slug, appWarningColor, '','bold'); } } }); cb.setTimeout(checkPasswordLock, 300000); } function initFollowerThreshold() { ftaIndex = 0; nextFollowerThreshold = 0; cb.getRoomOwnerData(ownerData => { if (ownerData['success']) { for (var checkindex = 0; checkindex < followerThresholdArray.length; checkindex++) { if (ownerData['data']['followers'] >= followerThresholdArray[checkindex]) { if (ownerData['data']['followers'] < followerThresholdArray[checkindex+1] ) { ftaIndex = checkindex + 1; break; } } } nextFollowerThreshold = followerThresholdArray[ftaIndex]; cb.sendNotice('Welcome back ' + cb.room_slug + '. \nYou have ' + ownerData['data']['followers'] + ' follower' + (ownerData['data']['followers'] == 1 ? '' : 's') + '. You are ' + (nextFollowerThreshold - ownerData['data']['followers']) + ' away from ' + nextFollowerThreshold + ' followers!', cb.room_slug, followBgColor, followTextColor, 'bold'); if (nextFollowerThreshold > 0) { cb.setTimeout(checkFollowerCount, 60000); } } }); } function checkFollowerCount() { cb.getRoomOwnerData(ownerData => { if (ownerData['success']) { if (ownerData['data']['followers'] >= nextFollowerThreshold ) { if (nextFollowerThreshold < 5000) { followerthresholdicon = ':celebration7'; } else if (nextFollowerThreshold < 10000) { followerthresholdicon = ':partyface'; } else if (nextFollowerThreshold == 10000) { followerthresholdicon = ':10000followers'; } else if (nextFollowerThreshold < 25000) { followerthresholdicon = ':celebrate-js'; } else if (nextFollowerThreshold < 50000) { followerthresholdicon = ':celebrationminion'; } else if (nextFollowerThreshold < 100000) { followerthresholdicon = ':congratsddddd'; } else if (nextFollowerThreshold < 250000) { followerthresholdicon = ':PARTY'; } else if (nextFollowerThreshold < 500000) { followerthresholdicon = ':wow7'; } else if (nextFollowerThreshold < 9999999) { followerthresholdicon = ':amazingtg'; } else { followerthresholdicon = ':celebration7'; } cb.sendNotice(followerthresholdicon + ' Congratulations ' + cb.room_slug + ' on reaching ' + nextFollowerThreshold + ' followers!!! ' + followerthresholdicon, '', lightblue, '', 'bold'); ftaIndex++; nextFollowerThreshold = followerThresholdArray[ftaIndex]; } } }); cb.setTimeout(checkFollowerCount, 60000); } function displayUserStats(ustatsendto) { cb.getRoomUsersData(usersData => { if (usersData['success']) { numberMods = usersData['data']['moderator'].length; numberFans = usersData['data']['fanclub'].length; numberDarkPurple = usersData['data']['dark_purple'].length; numberLightPurple = usersData['data']['light_purple'].length; numberDarkBlue = usersData['data']['dark_blue'].length; numberLightBlue = usersData['data']['light_blue'].length; numberGrey = usersData['data']['grey'].length; numberExtFans1 = extFanListArray.length; numberExtFansInShow1 = extFanInShowArray.length; numberExtFans2 = extFanList2Array.length; numberExtFansInShow2 = extFanInShow2Array.length; numberVIPs = VIPListArray.length; numberVIPsInShow = VIPInShowArray.length; cb.sendNotice('Statistics for CB User Groups (currently in the room): ' + '\n \u21D2 Number of Moderators: ' + numberMods + '\n \u21D2 Number of CB Fans: ' + numberFans + '\n \u21D2 Number of Dark Purple Users: ' + numberDarkPurple + '\n \u21D2 Number of Light Purple Users: ' + numberLightPurple + '\n \u21D2 Number of Dark Blue Users: ' + numberDarkBlue + '\n \u21D2 Number of Light Blue Users: ' + numberLightBlue + '\n \u21D2 Number of Grey Users: ' + numberGrey , ustatsendto, appNoticeColor); cb.sendNotice('Statistics for Fembot User Groups: ' + '\n \u21D2 Number of Users in External Fan Club 1: ' + numberExtFans1 + '\n \u21D2 Number of External Fan Club 1 members in current show: ' + numberExtFansInShow1 + '\n \u21D2 Number of Users in External Fan Club 2: ' + numberExtFansInShow2 + '\n \u21D2 Number of External Fan Club 2 members in current show: ' + numberExtFans2 + '\n \u21D2 Number of Users in VIP List: ' + numberVIPs + '\n \u21D2 Number of VIPs in current show: ' + numberVIPsInShow , ustatsendto, lightblue); } else { cb.sendNotice('Error retrieving User Statistics from CB.', ustatsendto, appWarningColor); } }); } function roomSizeMonitor() { cb.getRoomUsersData(usersData => { if (usersData['success']) { numberMods = usersData['data']['moderator'].length; numberFans = usersData['data']['fanclub'].length; numberDarkPurple = usersData['data']['dark_purple'].length; numberLightPurple = usersData['data']['light_purple'].length; numberDarkBlue = usersData['data']['dark_blue'].length; numberLightBlue = usersData['data']['light_blue'].length; numberGrey = usersData['data']['grey'].length; totalNumberInRoom = numberMods + numberFans + numberDarkPurple + numberLightPurple + numberDarkBlue + numberLightBlue + numberGrey; if (totalNumberInRoom > 0 && totalNumberInRoom > roomSizePrevTotal) { if (cb.settings.silenceGraysThreshold > 0 && totalNumberInRoom > cb.settings.silenceGraysThreshold) { if (silenceLevel < 1) { silenceLevel = 1; cb.sendNotice('Current number of registered viewers has exceeeded the threshold for silencing gray users (' + cb.settings.silenceGraysThreshold + '). \n Silence Level is being increased to "1" (only users with tokens can chat). \nYou can use the /sl command to manually update the silence level if needed.', cb.room_slug, appWarningColor); cb.sendNotice('Current number of registered viewers has exceeeded the threshold for silencing gray users (' + cb.settings.silenceGraysThreshold + '). \n Silence Level is being increased to "1" (only users with tokens can chat). \nYou can use the /sl command to manually update the silence level if needed.', cb.room_slug, appWarningColor, '', '', 'red'); } if (graphicLevel < 1) { graphicLevel = 1; cb.sendNotice('Current number of registered viewers has exceeeded the threshold for preventing gray users from posting graphics (' + cb.settings.silenceGraysThreshold + '). \n Graphics Level is being increased to "1" (only users with tokens can use graphics). \nYou can use the /gl command to manually update the graphic level if needed.', cb.room_slug, appWarningColor); cb.sendNotice('Current number of registered viewers has exceeeded the threshold for preventing gray users from posting graphics (' + cb.settings.silenceGraysThreshold + '). \n Graphics Level is being increased to "1" (only users with tokens can use graphics). \nYou can use the /gl command to manually update the graphic level if needed.', cb.room_slug, appWarningColor, '', '', 'red'); } } else if (cb.settings.silenceNonTipThreshold > 0 && totalNumberInRoom > cb.settings.silenceNonTipThreshold) { if (silenceLevel < 2) { silenceLevel = 2; cb.sendNotice('Current number of registered viewers has exceeeded the configured threshold for silencing non-tippers (' + cb.settings.silenceNonTipThreshold + '). \n Silence Level is being increased to "2" (only tippers can chat). \nYou can use the /sl command to manually update the silence level if needed.', cb.room_slug, appWarningColor); cb.sendNotice('Current number of registered viewers has exceeeded the configured threshold for silencing non-tippers (' + cb.settings.silenceNonTipThreshold + '). \n Silence Level is being increased to "2" (only tippers can chat). \nYou can use the /sl command to manually update the silence level if needed.', cb.room_slug, appWarningColor, '', '', 'red'); } if (graphicLevel < 2) { graphicLevel = 2; cb.sendNotice('Current number of registered viewers has exceeeded the threshold for preventing non-tippers from posting graphics (' + cb.settings.silenceNonTipThreshold + '). \n Graphics Level is being increased to "2" (only tippers can use graphics). \nYou can use the /gl command to manually update the graphic level if needed.', cb.room_slug, appWarningColor); cb.sendNotice('Current number of registered viewers has exceeeded the threshold for preventing non-tippers from posting graphics (' + cb.settings.silenceNonTipThreshold + '). \n Graphics Level is being increased to "2" (only tippers can use graphics). \nYou can use the /gl command to manually update the graphic level if needed.', cb.room_slug, appWarningColor, '', '', 'red'); } } } if (cb.settings.autoUpdateSLGL == 'Yes, during Increase and Decrease') { if (totalNumberInRoom < roomSizePrevTotal) { if (cb.settings.silenceGraysThreshold > 0 && totalNumberInRoom < cb.settings.silenceGraysThreshold) { if (silenceLevel > 0) { silenceLevel = 0; cb.sendNotice('Current number of registered viewers has dropped below the threshold for silencing gray users (' + cb.settings.silenceGraysThreshold + '). \n Silence Level is being decreased to "0" (all users can chat). \nYou can use the /sl command to manually update the silence level if needed.', cb.room_slug, appWarningColor); cb.sendNotice('Current number of registered viewers has dropped below the threshold for silencing gray users (' + cb.settings.silenceGraysThreshold + '). \n Silence Level is being decreased to "0" (all users can chat). \nYou can use the /sl command to manually update the silence level if needed.', cb.room_slug, appWarningColor, '', '', 'red'); } if (graphicLevel > 0) { graphicLevel = 0; cb.sendNotice('Current number of registered viewers has dropped below the threshold for preventing gray users from posting graphics (' + cb.settings.silenceGraysThreshold + '). \n Graphics Level is being decreased to "0" (all users can use graphics). \nYou can use the /gl command to manually update the graphic level if needed.', cb.room_slug, appWarningColor); cb.sendNotice('Current number of registered viewers has dropped below the threshold for preventing gray users from posting graphics (' + cb.settings.silenceGraysThreshold + '). \n Graphics Level is being decreased to "0" (all users can use graphics). \nYou can use the /gl command to manually update the graphic level if needed.', cb.room_slug, appWarningColor, '', '', 'red'); } } else if (cb.settings.silenceNonTipThreshold > 0 && totalNumberInRoom < cb.settings.silenceNonTipThreshold) { if (silenceLevel > 1) { silenceLevel = 1; cb.sendNotice('Current number of registered viewers has dropped below the configured threshold for silencing non-tippers (' + cb.settings.silenceNonTipThreshold + '). \n Silence Level is being decreased to "1" (only users with tokens can chat). \nYou can use the /sl command to manually update the silence level if needed.', cb.room_slug, appWarningColor); cb.sendNotice('Current number of registered viewers has dropped below the configured threshold for silencing non-tippers (' + cb.settings.silenceNonTipThreshold + '). \n Silence Level is being decreased to "1" (only users with tokens can chat). \nYou can use the /sl command to manually update the silence level if needed.', cb.room_slug, appWarningColor, '', '', 'red'); } if (graphicLevel > 1) { graphicLevel = 1; cb.sendNotice('Current number of registered viewers has dropped below the threshold for preventing non-tippers from posting graphics (' + cb.settings.silenceNonTipThreshold + '). \n Graphics Level is being decreased to "1" (only users with tokens can use graphics). \nYou can use the /gl command to manually update the graphic level if needed.', cb.room_slug, appWarningColor); cb.sendNotice('Current number of registered viewers has dropped below the threshold for preventing non-tippers from posting graphics (' + cb.settings.silenceNonTipThreshold + '). \n Graphics Level is being decreased to "1" (only users with tokens can use graphics). \nYou can use the /gl command to manually update the graphic level if needed.', cb.room_slug, appWarningColor, '', '', 'red'); } } } } roomSizePrevTotal = totalNumberInRoom; } else { cb.sendNotice('Error retrieving User Statistics from CB.', cb.room_slug, appWarningColor); } }); cb.setTimeout(roomSizeMonitor, 60000); } // *********************************** Length of show ************************************** function timeOnline() { var timeOnlineElapsed = onlineclockTimeCal(); var onlineclockMS = timeOnlineElapsed % 1000; var onlineclockSeconds = ((timeOnlineElapsed - onlineclockMS) % 60000); var onlineclockMinutes = ((timeOnlineElapsed - onlineclockSeconds - onlineclockMS) % 3600000); var onlineclockHours = (timeOnlineElapsed - onlineclockMinutes - onlineclockSeconds - onlineclockMS); onlineclockSeconds = onlineclockSeconds / 1000; onlineclockMinutes = onlineclockMinutes / 60000; onlineclockHours = onlineclockHours / 3600000; if (onlineclockHours > 0) { return onlineclockHours + ' hour' + (onlineclockHours > 1 ? 's' : '') + ' and ' + onlineclockMinutes + ' minute' + (onlineclockMinutes > 1 ? 's' : ''); } else if (onlineclockMinutes > 0 && onlineclockSeconds === 0) { return onlineclockMinutes + ' minute' + (onlineclockMinutes > 1 ? 's' : ''); } else if (onlineclockMinutes > 0) { return onlineclockMinutes + ' minute' + (onlineclockMinutes > 1 ? 's' : '') + ' and ' + onlineclockSeconds + ' second' + (onlineclockSeconds > 1 ? 's' : ''); } else { return onlineclockSeconds + ' second' + (onlineclockSeconds > 1 ? 's' : ''); } } function onlineclockTimeCal() { timeNow = new Date(); return timeNow - fembotStartTime.getTime(); } //********** 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; } //********** Check Username Function ************** function checkUsername(message,user) { responseMessageArray = message.split(' '); replace = false; if (cbjs.arrayContains(responseMessageArray,'{username}')) { msgindex = responseMessageArray.indexOf('{username}'); responseMessageArray[msgindex] = user; replace = true; } else if (cbjs.arrayContains(responseMessageArray,'{username},')) { msgindex = responseMessageArray.indexOf('{username},'); responseMessageArray[msgindex] = user + ','; replace = true; } else if (cbjs.arrayContains(responseMessageArray,'{username}!')) { msgindex = responseMessageArray.indexOf('{username}!'); responseMessageArray[msgindex] = user + '!'; replace = true; } else if (cbjs.arrayContains(responseMessageArray,'{username}:')) { msgindex = responseMessageArray.indexOf('{username}:'); responseMessageArray[msgindex] = user + ':'; replace = true; } else if (cbjs.arrayContains(responseMessageArray,'{username}.')) { msgindex = responseMessageArray.indexOf('{username}.'); responseMessageArray[msgindex] = user + '.'; replace = true; } if (replace) { return cbjs.arrayJoin(responseMessageArray,' '); } else { return message; } } //********** Check Next Line Function ************** function checkNextLine(nlmessage,user) { nextLineMessageArray = nlmessage.split(' '); replace = false; subfound = true; while (subfound) { if (cbjs.arrayContains(nextLineMessageArray,'{n}')) { msgindex = nextLineMessageArray.indexOf('{n}'); nextLineMessageArray[msgindex] = '\n'; replace = true; } else { subfound = false; } } if (replace) { return cbjs.arrayJoin(nextLineMessageArray,' '); } else { return nlmessage; } } //********** Build Repeating Char Lines ************** function noticeBorder(bordertopbtm,bordertype,bordertext) { var outcharstring = ''; var halfcharstring = ''; var midchar = '\u2666'; var dispspace = false; var dispnumber = 0; if (borderCharSpacing == 'none') { if (bordertopbtm == 'top') { outcharstring = bordertext; } } else { if (bordertopbtm == 'top') { if (borderCharSpacing == 'emoji') { dispspace = true; if (bordertype == 'short') { dispnumber = 3; } else if (bordertype == 'long') { dispnumber = 8; } else if (bordertype == 'ticket') { dispnumber = 8; } } else if (borderCharSpacing == 'unicode') { if (bordertype == 'short') { dispnumber = 5; } else if (bordertype == 'long') { dispnumber = 15; } else if (bordertype == 'ticket') { dispnumber = 15; } } else if (borderCharSpacing == 'light') { if (bordertype == 'short') { dispnumber = 15; } else if (bordertype == 'long') { dispnumber = 36; } else if (bordertype == 'ticket') { dispnumber = 35; } } for (var charidx = 1; charidx <= dispnumber; charidx++) { if (dispspace) { halfcharstring += borderChar + ' '; } else { halfcharstring += borderChar; } } outcharstring = halfcharstring + ' ' + bordertext + ' ' + halfcharstring; } else if (bordertopbtm == 'bottom') { if (borderCharSpacing == 'emoji') { dispspace = true; if (bordertype == 'short') { dispnumber = 6; } else if (bordertype == 'long') { dispnumber = 10; } else if (bordertype == 'ticket') { dispnumber = 12; } } else if (borderCharSpacing == 'unicode') { if (bordertype == 'short') { dispnumber = 11; } else if (bordertype == 'long') { dispnumber = 18; } else if (bordertype == 'ticket') { dispnumber = 22; } } else if (borderCharSpacing == 'light') { if (bordertype == 'short') { dispnumber = 28; } else if (bordertype == 'long') { dispnumber = 43; } else if (bordertype == 'ticket') { dispnumber = 50; } } for (var charidx = 1; charidx <= dispnumber; charidx++) { if (dispspace) { halfcharstring += borderChar + ' '; } else { halfcharstring += borderChar; } } if (dispspace == true) { outcharstring = '\n' + halfcharstring + halfcharstring; } else { outcharstring = '\n' + halfcharstring + ' ' + midchar + ' ' + halfcharstring; } } } return outcharstring; } //********** Check Message Frequency Function ************** /* function checkNoticeFrequency(frqmessage,frqto,frqbg,frqtext,frqbold,frqgroup) { if (freqPrev == 0) { freqPrev = new Date(); cb.sendNotice(frqmessage, frqto, frqbg, frqtext, frqbold, frqgroup); return; } mindifference = minTimeForNotice * 1000; freqCurrent = new Date(); timedifference = freqCurrent.getTime() - freqPrev.getTime(); freqPrev = new Date(); if (timedifference < mindifference) { cb.setTimeout(checkNoticeFrequency, mindifference); } else { cb.sendNotice(frqmessage, frqto, frqbg, frqtext, frqbold, frqgroup); } } */ //********** 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 == true) { cb.sendNotice('The Caps Lock Suppression is already turned on.',mod,appNoticeColor); } else { suppressCapsToggle = true; cb.sendNotice('You have enabled the Caps Lock Suppression.',mod,appNoticeColor); } } else if (option == 'off') { if (suppressCapsToggle == false) { cb.sendNotice('The Caps Lock Suppression is already turned off.',mod,appNoticeColor); } else { suppressCapsToggle = false; cb.sendNotice('You have disabled the Caps Lock Suppression.',mod,appNoticeColor); } } } //********** Auto Response messages on delay ************** function sendPMResponseDelay() { cb.sendNotice(checkNextLine(cb.settings.pmResponseMessage), '', appNoticeColor, '', 'bold'); } function sendPrivateResponseDelay() { cb.sendNotice(checkNextLine(cb.settings.prvResponseMessage), '', appNoticeColor, '', 'bold'); } function sendAutoResponse1Delay() { cb.sendNotice(checkNextLine(autoResponse1), '', appNoticeColor, '', 'bold'); } function sendAutoResponse2Delay() { cb.sendNotice(checkNextLine(autoResponse2), '', appNoticeColor, '', 'bold'); } function sendAutoResponse3Delay() { cb.sendNotice(checkNextLine(autoResponse3), '', appNoticeColor, '', 'bold'); } //********** Leaderboard Functions ************** function setLeaderToggle(option,mod,bycmd) { if (option == 'on') { if (leaderboardToggle == 1) { cb.sendNotice('The Leaderboard display is already turned on.', mod, appNoticeColor); } else { leaderboardToggle = 1; setLeaderBoardColors(); initLeaderboardTimer(); if (bycmd) { cb.sendNotice('You have enabled the Leaderboard display.', mod, appNoticeColor); } } } else if (option == 'off') { if (leaderboardToggle == 0) { cb.sendNotice('The Leaderboard display is already turned off.', mod, appNoticeColor); } else { leaderboardToggle = 0; cb.sendNotice('You have disabled the Leaderboard display. Tip leaders are still tracked but the board is not displayed.', mod, appNoticeColor); } } else if (option != null) { cb.sendNotice(option + ' is not a valid option for /useleaderboard.', mod, appNoticeColor); } else if (option == null) { cb.sendNotice('You did not enter a valid option for /useleaderboard.', mod, appNoticeColor); } } function setLeaderBoardColors() { if (cb.settings.leaderTextColor == 'Custom') { leaderTextColor = checkTextColor(cb.settings.leaderTextCustColor,true); 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,true); } if (cb.settings.leaderBgColor == 'Custom') { leaderBgColor = checkBgColor(cb.settings.leaderBgCustColor,true); 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,true); } } function initLeaderboardTimer() { if (isNaN(parseFloat(cb.settings.leaderInterval))) { cb.sendNotice('Fembot: Leaderboard notice interval is not set with a valid number so the leaderboard notice is not enabled.', cb.room_slug, appWarningColor); leaderInt = 0; } else { leaderInt = parseFloat(cb.settings.leaderInterval); } if (leaderInt != 0) { if (leaderInt < 1) { cb.sendNotice('Fembot: Leaderboard notice interval is too short, must be at least 1 minute. Using default value of 3.5 minutes.', cb.room_slug, appWarningColor); leaderInt = 3.5; } leaderInt = parseInt(leaderInt * 60000); cb.setTimeout(leaderboardTimer, leaderInt); } } function leaderboardTimer() { if (leaderboardToggle == 1) { if (minMessagesForNotice > 0 && msgCounterLeaderboard < minMessagesForNotice) { cb.setTimeout(leaderboardTimer, 30000); } else { if (tipCountArray.name.length > 0) { msgCounterLeaderboard = 0; showLeaderBoard('timer',''); } cb.setTimeout(leaderboardTimer, leaderInt); } } } function showLeaderBoard(showleadmode,showleadto) { var leaderboardstring = ''; if (showleadmode == 'me') { leaderboardstring += 'Sent to YOU:\n'; } else if (showleadmode == 'all') { leaderboardstring += 'Sent to ALL:\n'; } leaderboardstring += noticeBorder('top','short','TIPPER LEADERBOARD'); if (tipCountArray.name.length > 0) { var maxlbdisp = leaderSize; if (tipCountArray.name.length < maxlbdisp) { maxlbdisp = tipCountArray.name.length; } sortTippers(); for (var lbidx = 1; lbidx <= maxlbdisp; lbidx++) { if (tipCountArray.name[lbidx-1] != null) { leaderboardstring += '\n' + lbidx + '. ' + tipCountArray.name[lbidx-1] + ' : ' + tipCountArray.amount[lbidx-1]; } } } else { leaderboardstring += '\nNo tippers yet'; } leaderboardstring += noticeBorder('bottom','short',''); cb.sendNotice(leaderboardstring, showleadto, leaderBgColor, leaderTextColor, 'bold'); } 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(sentfrom,group,numtippers,sendto,sendtoname) { switch (sendto) { case 'all': var outString = 'SENT TO ALL:\n'; break; case 'mods': var outString = 'SENT TO MODS BY: ' + sentfrom + '\n'; break; case 'tbm': var outString = 'SENT TO MODS AND BROADCASTER BY: ' + sentfrom + '\n'; break; case 'bc': var outString = 'SENT TO YOU BY: ' + sentfrom + '\n'; break; default: var outString = 'SENT TO YOU:\n'; break; } outString += dashLine60 + '\n\u25ba \u25ba \u25ba TOP ' + numtippers + ' TIPPER LIST \u25c4 \u25c4 \u25c4\n' + dashLine60 + '\n'; if (tipCountArray.name.length > 0) { if (tipCountArray.name.length < numtippers) { numtippersindex = tipCountArray.name.length; } else { numtippersindex = numtippers; } for (var i = 1; i <= numtippersindex; i++) { if (tipCountArray.name[i - 1] == null) outString += '\u25ba ' + i + '. --' + '\n'; else outString += '\u25ba ' + i + '. ' + '"' + tipCountArray.name[i - 1] + '"' + ': ' + tipCountArray.amount[i - 1] + '\n'; } } else { outString += '\u25ba No Tippers Yet.'; } cb.sendNotice(outString, sendtoname, '', '', 'bold', group); } function populateModeratorArray(popuser,poptype,popmode) { if (popmode == 'a') { if (poptype == 'cbmod' && cbjs.arrayContains(moderatorList.name,popuser)) { nameindex = moderatorList.name.indexOf(popuser); if (moderatorList.type[nameindex] == 'botmod') { moderatorList.name.splice(nameindex,1); moderatorList.type.splice(nameindex,1); } } if (!cbjs.arrayContains(moderatorList.name,popuser)) { moderatorList.name.push(popuser); moderatorList.type.push(poptype); } else { return; } } else if (popmode == 'r') { if (poptype == 'botmod' && cbjs.arrayContains(moderatorList.name,popuser)) { nameindex = moderatorList.name.indexOf(popuser); if (moderatorList.type[nameindex] == 'botmod') { moderatorList.name.splice(nameindex,1); moderatorList.type.splice(nameindex,1); } } else if (poptype == 'cbmod' && cbjs.arrayContains(moderatorList.name,popuser)) { nameindex = moderatorList.name.indexOf(popuser); if (moderatorList.type[nameindex] == 'cbmod') { 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(level, mod) { silenceLevel = level; cb.sendNotice('The silence level has been set to ' + level + '.', cb.room_slug, appNoticeColor); cb.sendNotice('The silence level has been set to ' + level + '.', '', appNoticeColor, '', '', 'red'); switch (level) { case 0: cb.sendNotice('All members can talk in chat.', cb.room_slug, appNoticeColor); cb.sendNotice('All members can talk in chat.', '', appNoticeColor, '', '', 'red'); break; case 1: cb.sendNotice('Only members with tokens can talk in chat.', cb.room_slug, appNoticeColor); cb.sendNotice('Only members with tokens can talk in chat.', '', appNoticeColor, '', '', 'red'); break; case 2: cb.sendNotice('Only members who have tipped can talk in chat.', cb.room_slug, appNoticeColor); cb.sendNotice('Only members who have tipped can talk in chat.', '', appNoticeColor, '', '', 'red'); break; case 3: cb.sendNotice('Only members who have tipped at least ' + minTipToChat + ' tokens can talk in chat.', cb.room_slug, appNoticeColor); cb.sendNotice('Only members who have tipped at least ' + minTipToChat + ' tokens can talk in chat.', '', appNoticeColor, '', '', 'red'); break; case 4: cb.sendNotice('Only Moderators, Fans, and VIPs can chat.', cb.room_slug, appNoticeColor); cb.sendNotice('Only Moderators, Fans, and VIPs can chat.', '', appNoticeColor, '', '', 'red'); break; } } function setGraphicLevel(level, mod) { graphicLevel = level; cb.sendNotice('The graphic level has been set to ' + level + '.', cb.room_slug, appNoticeColor); cb.sendNotice('The graphic level has been set to ' + level + '.', '', appNoticeColor, '', '', 'red'); switch (level) { case 0: cb.sendNotice('All members can use graphics in chat.',cb.room_slug,appNoticeColor); cb.sendNotice('All members can use graphics in chat.', '', appNoticeColor, '', '', 'red'); break; case 1: cb.sendNotice('Only members with tokens can use graphics in chat.', cb.room_slug, appNoticeColor); cb.sendNotice('Only members with tokens can use graphics in chat.', '', appNoticeColor, '', '', 'red'); break; case 2: cb.sendNotice('Only members who have tipped can use graphics in chat.', cb.room_slug, appNoticeColor); cb.sendNotice('Only members who have tipped can use graphics in chat.', "", appNoticeColor, '', '', 'red'); break; case 3: cb.sendNotice('Only members who have tipped at least ' + minTipToChat + ' tokens can use graphics in chat.', cb.room_slug, appNoticeColor); cb.sendNotice('Only members who have tipped at least ' + minTipToChat + ' tokens can use graphics in chat.', '', appNoticeColor, '', '', 'red'); break; case 4: cb.sendNotice('Only Moderators, Fans, and VIPs can use graphics in chat.', cb.room_slug, appNoticeColor); cb.sendNotice('Only Moderators, Fans, and VIPs can use graphics in chat.', '', appNoticeColor, '', '', 'red'); break; } } //********** 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, appNoticeColor); } else if(cbjs.arrayContains(moderatorList.name,user)) { cb.sendNotice(user + ' is a moderator and cannot be ninja\'d.', mod, appNoticeColor); } else if(user == cb.room_slug) { cb.sendNotice(user + ' is the broadcaster and cannot be ninja\'d.', mod, appNoticeColor); } else { ninjaListArray.push(user); cb.sendNotice('You have added ' + user + ' to the ninja list.', mod, appNoticeColor); } } else if (mode == 'r') { if(cbjs.arrayContains(ninjaListArray,user)) { cbjs.arrayRemove(ninjaListArray,user); cb.sendNotice('You have removed ' + user + ' from the ninja list.', mod, appNoticeColor); } else { cb.sendNotice(user + ' is not on the ninja list.', mod, appNoticeColor); } } } function addRmvSilence(user, mod, mode) { if (mode == 'a') { if(cbjs.arrayContains(silenceListArray,user)) { cb.sendNotice(user + ' has already been silenced.', mod, appNoticeColor); } else if(cbjs.arrayContains(moderatorList.name,user)) { cb.sendNotice(user + ' is a moderator and cannot be silenced.', mod, appNoticeColor); } else if(user == cb.room_slug) { cb.sendNotice(user + ' is the broadcaster and cannot be silenced.', mod, appNoticeColor); } 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, appNoticeColor); 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, appNoticeColor); } } 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, appNoticeColor); cb.sendNotice('You have been unsilenced by ' + mod + '. Please be nice and don\'t make demands.', user, appNoticeColor); } else { cb.sendNotice(user + ' is not currently silenced.', mod, appNoticeColor); } } } function addRmvWord(word, mod, mode) { if (mode == 'a') { if (cbjs.arrayContains(wordListArrayPub,word)) { cb.sendNotice(word + ' has already been added to the Public Blocked Word list.', mod, appNoticeColor); } else { wordListArrayPub.push(word); cb.sendNotice('You have added "' + word + '" to the Public 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, appNoticeColor); } } else if (mode == 'r') { if (cbjs.arrayContains(wordListArrayPub,word)) { cbjs.arrayRemove(wordListArrayPub,word); cb.sendNotice('You have removed "' + word + '" from the Public 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, appNoticeColor); } else { cb.sendNotice('"' + word + '" is not on the Public Blocked Word list.', mod, appNoticeColor); } if (mod == cb.room_slug) { if (cbjs.arrayContains(wordListArray,word)) { cbjs.arrayRemove(wordListArray,word); cb.sendNotice('You have removed "' + word + '" from the Private 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, appNoticeColor); } else { cb.sendNotice('"' + word + '" is not on the Private Blocked Word list.', mod, appNoticeColor); } } } } function addRmvVIP(user, mode) { if (mode == 'a') { if (cbjs.arrayContains(VIPListArray,user)) { return; } else { VIPListArray.push(user); } } else if (mode == 'r') { if (cbjs.arrayContains(VIPListArray,user)) { cbjs.arrayRemove(VIPListArray,user); if (cbjs.arrayContains(VIPInShowArray,user)) { cbjs.arrayRemove(VIPInShowArray,user); } } else { return; } } } function addRmvExtFan(user, mode) { if (mode == 'a') { if (cbjs.arrayContains(extFanListArray,user)) { return; } else { extFanListArray.push(user); } } else if (mode == 'r') { if (cbjs.arrayContains(extFanListArray,user)) { cbjs.arrayRemove(extFanListArray,user); if (cbjs.arrayContains(extFanInShowArray,user)) { cbjs.arrayRemove(extFanInShowArray,user); } } else { return; } } } function addRmvExtFan2(user, mode) { if (mode == 'a') { if (cbjs.arrayContains(extFanList2Array,user)) { return; } else { extFanList2Array.push(user); } } else if (mode == 'r') { if (cbjs.arrayContains(extFanList2Array,user)) { cbjs.arrayRemove(extFanList2Array,user); if (cbjs.arrayContains(extFanInShow2Array,user)) { cbjs.arrayRemove(extFanInShow2Array,user); } } else { return; } } } function addRmvNice(user, mod, mode) { if(mode == 'a') { if(!cbjs.arrayContains(niceListArray,user)) { niceListArray.push(user); cb.sendNotice('You have added ' + user + ' to the Fembot 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, appNoticeColor); cb.sendNotice(mod + ' has added you to the Fembot nice list. You will be able to chat and use graphcs regardless of the global room settings. Thank you for being nice!',user,appNoticeColor); } else { cb.sendNotice(user + ' is already on the Fembot nice list.', mod, appNoticeColor); } } else if(mode == 'r') { if(cbjs.arrayContains(niceListArray,user)) { cbjs.arrayRemove(niceListArray,user); cb.sendNotice('You have removed ' + user + ' from the Fembot 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, appNoticeColor); cb.sendNotice(mod + ' has removed you from the Fembot nice list.', user, appNoticeColor); } else { cb.sendNotice(user + ' is not on the Fembot Nice List.', mod, appNoticeColor); } } } function populateNiceListArray(user) { if (!cbjs.arrayContains(niceListArray, user)) niceListArray.push(user); else return; } function addUserIcon(addedby,addfor,gifname) { if (cbjs.arrayContains(iconNicknamesArray.name,addfor)) { iconindex = iconNicknamesArray.name.indexOf(addfor); if (gifname == 'null') { iconNicknamesArray.icon[iconindex] = null; cb.sendNotice('The icon for user ' + addfor + ' has been cleared.', addedby, appNoticeColor); } else { iconNicknamesArray.icon[iconindex] = gifname; cb.sendNotice('The icon for user ' + addfor + ' has been updated to ' + gifname + '.', addedby, appNoticeColor); } } else { iconNicknamesArray.name.push(addfor); iconNicknamesArray.nickname.push(null); iconNicknamesArray.color.push(null); if (gifname == 'null') { iconNicknamesArray.icon.push(null); cb.sendNotice('An entry has been added for user ' + addfor + ' with no icon.', addedby, appNoticeColor); } else { iconNicknamesArray.icon.push(gifname); cb.sendNotice('An entry has been added for user ' + addfor + ' with an icon of ' + gifname + '.', addedby, appNoticeColor); } } } function addTipForIcon(addfor,gifname) { if (cbjs.arrayContains(tipForIconArray.name,addfor)) { tipiconindex = tipForIconArray.name.indexOf(addfor); tipForIconArray.icon[tipiconindex] = gifname; } else { tipForIconArray.name.push(addfor); tipForIconArray.icon.push(gifname); } } //********** 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 Timer #1 ' + (timerDesc != '' ? ('until ' + timerDesc) : '') + ' \u23f1 \u23f1 \u23f1', '', appWarningColor, '', 'bold'); break; case 1: cb.sendNotice('\u23f1 \u23f1 \u23f1 There is 1 minute left on Timer #1 ' + (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 Timer #1 ' + (timerDesc != '' ? ('until ' + timerDesc) : '') + ' \u23f1 \u23f1 \u23f1', '', red, '', 'bold'); break; case 1: cb.sendNotice('\u23f1 \u23f1 \u23f1 There is 1 second left on Timer #1 ' + (timerDesc != '' ? ('until ' + timerDesc) : '') + ' \u23f1 \u23f1 \u23f1', '', red, '', 'bold'); break; } } if (clockSecsRemain < 1) { if (clockMinsRemain >= 1) { clockTimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Timer #1: Time is up! \u23f0 \u23f0 \u23f0', '', appWarningColor, '', 'bold'); timerDesc = ''; } } else { clockSecsRemain--; cb.setTimeout(clockTimerSec, 1000); } } } function clockAddTime(clocktimetoadd, u) { clockStopTime = new Date(clockStopTime.getTime() + clocktimetoadd * 60000); timetoaddabs = Math.abs(clocktimetoadd); if (clocktimetoadd > 0) { cb.sendNotice(clocktimetoadd + ' minute' + (clocktimetoadd == 1 || clocktimetoadd == -1 ? ' has' : 's have') + ' been added to Timer #1. Now ' + clockTimeLeft(), '', appWarningColor,'', 'bold'); } else { cb.sendNotice(timetoaddabs + ' minute' + (timetoaddabs == 1 || timetoaddabs == -1 ? ' has' : 's have') + ' been subtracted from Timer #1. Now ' + clockTimeLeft(), '', appWarningColor,'', '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 Timer #1.','',appWarningColor,'', 'bold'); } } function clockTimeLeft() { 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 Timer #1.'; } else if (clockMinutes > 0 && clockSeconds === 0) { return clockMinutes + ' minute' + (clockMinutes > 1 ? 's' : '') + ' remaining on Timer #1.'; } else if (clockMinutes > 0) { return clockMinutes + ' minute' + (clockMinutes > 1 ? 's' : '') + ' and ' + clockSeconds + ' second' + (clockSeconds > 1 ? 's' : '') + ' remaining on Timer #1.'; } else { return clockSeconds + ' second' + (clockSeconds > 1 ? 's' : '') + ' remaining on Timer #1.'; } } //********** Timer #2 Functions ************** function clock2TimerMin() { if (!clock2Stopping) { switch (clock2MinsRemain) { 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('\u2777 \u231A \u2777 There are ' + clock2MinsRemain + ' minutes left on Timer #2 ' + (timer2Desc != '' ? ('until ' + timer2Desc) : '') + ' \u2777 \u231A \u2777', '', lightblue, '', 'bold'); break; case 1: cb.sendNotice('\u2777 \u231A \u2777 There is 1 minute left on Timer #2 ' + (timer2Desc != '' ? ('until ' + timer2Desc) : '') + '!! \u2777 \u231A \u2777', '', lightmagenta, '', 'bold'); break; } clock2MinsRemain--; if (clock2MinsRemain > 0) { displaySeconds2 = false; } else { displaySeconds2 = true; } clock2SecsRemain = 60; clock2TimerSec(); } } function clock2TimerSec() { if (!clock2Stopping) { if (displaySeconds2) { switch (clock2SecsRemain) { case 30: case 10: case 5: case 4: case 3: case 2: cb.sendNotice('\u2777 \u231A \u2777 There are ' + clock2SecsRemain + ' seconds left on Timer #2 ' + (timer2Desc != '' ? ('until ' + timer2Desc) : '') + ' \u2777 \u231A \u2777', '', lightmagenta, '', 'bold'); break; case 1: cb.sendNotice('\u2777 \u231A \u2777 There is 1 second left on Timer #2 ' + (timer2Desc != '' ? ('until ' + timer2Desc) : '') + ' \u2777 \u231A \u2777', '', lightmagenta, '', 'bold'); break; } } if (clock2SecsRemain < 1) { if (clock2MinsRemain >= 1) { clock2TimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Timer #2: Time is up! \u23f0 \u23f0 \u23f0', '', lightblue, '', 'bold'); timer2Desc = ''; } } else { clock2SecsRemain--; cb.setTimeout(clock2TimerSec, 1000); } } } function clock2AddTime(clock2timetoadd, u) { clock2StopTime = new Date(clock2StopTime.getTime() + clock2timetoadd * 60000); timetoaddabs2 = Math.abs(clock2timetoadd); if (clock2timetoadd > 0) { cb.sendNotice(clock2timetoadd + ' minute' + (clock2timetoadd == 1 || clock2timetoadd == -1 ? ' has' : 's have') + ' been added to Timer #2. Now ' + clock2TimeLeft(), '', lightblue,'', 'bold'); } else { cb.sendNotice(timetoaddabs2 + ' minute' + (timetoaddabs2 == 1 || timetoaddabs2 == -1 ? ' has' : 's have') + ' been subtracted from Timer #2. Now ' + clock2TimeLeft(), '', lightblue,'', 'bold'); } clock2MinsRemain = clock2MinsRemain + clock2timetoadd; if (clock2MinsRemain > 0) { displaySeconds2 = false; } else { displaySeconds2 = true; } } function clock2TimeCal() { clock2StartTime = new Date(); return clock2StopTime - clock2StartTime.getTime(); } function stopClockTimer2(mod) { clock2StopTime = new Date(); clock2Stopping = true; clock2MinsRemain = 0; clock2SecsRemain = 0; if(mod != null) { cb.sendNotice(mod + ' has stopped Timer #2.', '', lightblue, '', 'bold'); } } function clock2TimeLeft() { var clock2TimeLeft = clock2TimeCal(); var clock2MS = clock2TimeLeft % 1000; var clock2Seconds = ((clock2TimeLeft - clock2MS) % 60000); var clock2Minutes = ((clock2TimeLeft - clock2Seconds - clock2MS) % 3600000); var clock2Hours = (clock2TimeLeft - clock2Minutes - clock2Seconds - clock2MS); clock2Seconds = clock2Seconds / 1000; clock2Minutes = clock2Minutes / 60000; clock2Hours = clock2Hours / 3600000; if (clock2Hours > 0) { return clock2Hours + ' hour' + (clock2Hours > 1 ? 's' : '') + ' and ' + clock2Minutes + ' minute' + (clock2Minutes > 1 ? 's' : '') + ' remaining on Timer #2.'; } else if (clock2Minutes > 0 && clock2Seconds === 0) { return clock2Minutes + ' minute' + (clock2Minutes > 1 ? 's' : '') + ' remaining on Timer #2.'; } else if (clock2Minutes > 0) { return clock2Minutes + ' minute' + (clock2Minutes > 1 ? 's' : '') + ' and ' + clock2Seconds + ' second' + (clock2Seconds > 1 ? 's' : '') + ' remaining on Timer #2.'; } else { return clock2Seconds + ' second' + (clock2Seconds > 1 ? 's' : '') + ' remaining on Timer #2.'; } } //********** Timer #3 Functions ************** function clock3TimerMin() { if (!clock3Stopping) { switch (clock3MinsRemain) { 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('\u2778 \u231A \u2778 There are ' + clock3MinsRemain + ' minutes left on Timer #3 ' + (timer3Desc != '' ? ('until ' + timer3Desc) : '') + ' \u2778 \u231A \u2778', '', lightblue, '', 'bold'); break; case 1: cb.sendNotice('\u2778 \u231A \u2778 There is 1 minute left on Timer #3 ' + (timer3Desc != '' ? ('until ' + timer3Desc) : '') + '!! \u2778 \u231A \u2778', '', lightmagenta, '', 'bold'); break; } clock3MinsRemain--; if (clock3MinsRemain > 0) { displaySeconds3 = false; } else { displaySeconds3 = true; } clock3SecsRemain = 60; clock3TimerSec(); } } function clock3TimerSec() { if (!clock3Stopping) { if (displaySeconds3) { switch (clock3SecsRemain) { case 30: case 10: case 5: case 4: case 3: case 2: cb.sendNotice('\u2778 \u231A \u2778 There are ' + clock3SecsRemain + ' seconds left on Timer #3 ' + (timer3Desc != '' ? ('until ' + timer3Desc) : '') + ' \u2778 \u231A \u2778', '', lightmagenta, '', 'bold'); break; case 1: cb.sendNotice('\u2778 \u231A \u2778 There is 1 second left on Timer #3 ' + (timer3Desc != '' ? ('until ' + timer3Desc) : '') + ' \u2778 \u231A \u2778', '', lightmagenta, '', 'bold'); break; } } if (clock3SecsRemain < 1) { if (clock3MinsRemain >= 1) { clock3TimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Timer #3: Time is up! \u23f0 \u23f0 \u23f0', '', lightblue, '', 'bold'); timer3Desc = ''; } } else { clock3SecsRemain--; cb.setTimeout(clock3TimerSec, 1000); } } } function clock3AddTime(clock3timetoadd, u) { clock3StopTime = new Date(clock3StopTime.getTime() + clock3timetoadd * 60000); timetoaddabs3 = Math.abs(clock3timetoadd); if (clock3timetoadd > 0) { cb.sendNotice(clock3timetoadd + ' minute' + (clock3timetoadd == 1 || clock3timetoadd == -1 ? ' has' : 's have') + ' been added to Timer #3. Now ' + clock3TimeLeft(), '', lightblue,'', 'bold'); } else { cb.sendNotice(timetoaddabs3 + ' minute' + (timetoaddabs3 == 1 || timetoaddabs3 == -1 ? ' has' : 's have') + ' been subtracted from Timer #3. Now ' + clock3TimeLeft(), '', lightblue,'', 'bold'); } clock3MinsRemain = clock3MinsRemain + clock3timetoadd; if (clock3MinsRemain > 0) { displaySeconds3 = false; } else { displaySeconds3 = true; } } function clock3TimeCal() { clock3StartTime = new Date(); return clock3StopTime - clock3StartTime.getTime(); } function stopClockTimer3(mod) { clock3StopTime = new Date(); clock3Stopping = true; clock3MinsRemain = 0; clock3SecsRemain = 0; if(mod != null) { cb.sendNotice(mod + ' has stopped Timer #3.', '', lightblue, '', 'bold'); } } function clock3TimeLeft() { var clock3TimeLeft = clock3TimeCal(); var clock3MS = clock3TimeLeft % 1000; var clock3Seconds = ((clock3TimeLeft - clock3MS) % 60000); var clock3Minutes = ((clock3TimeLeft - clock3Seconds - clock3MS) % 3600000); var clock3Hours = (clock3TimeLeft - clock3Minutes - clock3Seconds - clock3MS); clock3Seconds = clock3Seconds / 1000; clock3Minutes = clock3Minutes / 60000; clock3Hours = clock3Hours / 3600000; if (clock3Hours > 0) { return clock3Hours + ' hour' + (clock3Hours > 1 ? 's' : '') + ' and ' + clock3Minutes + ' minute' + (clock3Minutes > 1 ? 's' : '') + ' remaining on Timer #3.'; } else if (clock3Minutes > 0 && clock3Seconds === 0) { return clock3Minutes + ' minute' + (clock3Minutes > 1 ? 's' : '') + ' remaining on Timer #3.'; } else if (clock3Minutes > 0) { return clock3Minutes + ' minute' + (clock3Minutes > 1 ? 's' : '') + ' and ' + clock3Seconds + ' second' + (clock3Seconds > 1 ? 's' : '') + ' remaining on Timer #3.'; } else { return clock3Seconds + ' second' + (clock3Seconds > 1 ? 's' : '') + ' remaining on Timer #3.'; } } //********** Timer #4 Functions ************** function clock4TimerMin() { if (!clock4Stopping) { switch (clock4MinsRemain) { 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('\u2779 \u231A \u2779 There are ' + clock4MinsRemain + ' minutes left on Timer #4 ' + (timer4Desc != '' ? ('until ' + timer4Desc) : '') + ' \u2779 \u231A \u2779', '', lightblue, '', 'bold'); break; case 1: cb.sendNotice('\u2779 \u231A \u2779 There is 1 minute left on Timer #4 ' + (timer4Desc != '' ? ('until ' + timer4Desc) : '') + '!! \u2779 \u231A \u2779', '', lightmagenta, '', 'bold'); break; } clock4MinsRemain--; if (clock4MinsRemain > 0) { displaySeconds4 = false; } else { displaySeconds4 = true; } clock4SecsRemain = 60; clock4TimerSec(); } } function clock4TimerSec() { if (!clock4Stopping) { if (displaySeconds4) { switch (clock4SecsRemain) { case 30: case 10: case 5: case 4: case 3: case 2: cb.sendNotice('\u2779 \u231A \u2779 There are ' + clock4SecsRemain + ' seconds left on Timer #4 ' + (timer4Desc != '' ? ('until ' + timer4Desc) : '') + ' \u23f1 \u231A \u23f1', '', lightmagenta, '', 'bold'); break; case 1: cb.sendNotice('\u2779 \u231A \u2779 There is 1 second left on Timer #4 ' + (timer4Desc != '' ? ('until ' + timer4Desc) : '') + ' \u2779 \u231A \u2779', '', lightmagenta, '', 'bold'); break; } } if (clock4SecsRemain < 1) { if (clock4MinsRemain >= 1) { clock4TimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Timer #4: Time is up! \u23f0 \u23f0 \u23f0', '', lightblue, '', 'bold'); timer4Desc = ''; } } else { clock4SecsRemain--; cb.setTimeout(clock4TimerSec, 1000); } } } function clock4AddTime(clock4timetoadd, u) { clock4StopTime = new Date(clock4StopTime.getTime() + clock4timetoadd * 60000); timetoaddabs4 = Math.abs(clock4timetoadd); if (clock4timetoadd > 0) { cb.sendNotice(clock4timetoadd + ' minute' + (clock4timetoadd == 1 || clock4timetoadd == -1 ? ' has' : 's have') + ' been added to Timer #4. Now ' + clock4TimeLeft(), '', lightblue,'', 'bold'); } else { cb.sendNotice(timetoaddabs4 + ' minute' + (timetoaddabs4 == 1 || timetoaddabs4 == -1 ? ' has' : 's have') + ' been subtracted from Timer #4. Now ' + clock4TimeLeft(), '', lightblue,'', 'bold'); } clock4MinsRemain = clock4MinsRemain + clock4timetoadd; if (clock4MinsRemain > 0) { displaySeconds4 = false; } else { displaySeconds4 = true; } } function clock4TimeCal() { clock4StartTime = new Date(); return clock4StopTime - clock4StartTime.getTime(); } function stopClockTimer4(mod) { clock4StopTime = new Date(); clock4Stopping = true; clock4MinsRemain = 0; clock4SecsRemain = 0; if(mod != null) { cb.sendNotice(mod + ' has stopped Timer #4.', '', lightblue, '', 'bold'); } } function clock4TimeLeft() { var clock4TimeLeft = clock4TimeCal(); var clock4MS = clock4TimeLeft % 1000; var clock4Seconds = ((clock4TimeLeft - clock4MS) % 60000); var clock4Minutes = ((clock4TimeLeft - clock4Seconds - clock4MS) % 3600000); var clock4Hours = (clock4TimeLeft - clock4Minutes - clock4Seconds - clock4MS); clock4Seconds = clock4Seconds / 1000; clock4Minutes = clock4Minutes / 60000; clock4Hours = clock4Hours / 3600000; if (clock4Hours > 0) { return clock4Hours + ' hour' + (clock4Hours > 1 ? 's' : '') + ' and ' + clock4Minutes + ' minute' + (clock4Minutes > 1 ? 's' : '') + ' remaining on Timer #4.'; } else if (clock4Minutes > 0 && clock4Seconds === 0) { return clock4Minutes + ' minute' + (clock4Minutes > 1 ? 's' : '') + ' remaining on Timer #4.'; } else if (clock4Minutes > 0) { return clock4Minutes + ' minute' + (clock4Minutes > 1 ? 's' : '') + ' and ' + clock4Seconds + ' second' + (clock4Seconds > 1 ? 's' : '') + ' remaining on Timer #4.'; } else { return clock4Seconds + ' second' + (clock4Seconds > 1 ? 's' : '') + ' remaining on Timer #4.'; } } //********** 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, appNoticeColor); } } else { cb.sendNotice('You can\'t send a blank message. Type a message and try again.', user, appNoticeColor); } } //********** PM Functions ************** 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 PM - You to mods: ' + message, cb.room_slug, TMgreenB, TMgreenF, 'bold'); cb.sendNotice('\u261b PM - ' + cb.room_slug + ' to mods: ' + message, '', TMgreenB, TMgreenF, 'bold', 'red'); for (let modindex = 0; modindex < moderatorList.name.length; modindex++) { if (moderatorList.type[modindex] == 'botmod') { sendtotm = moderatorList.name[modindex].trim(); cb.sendNotice('\u261b PM - ' + cb.room_slug + ' to mods: ' + message, sendtotm, TMgreenB, TMgreenF, 'bold'); } } } else { cb.sendNotice('\u261b PM - ' + user + ' to mods: ' + message, '', TMgreenB, TMgreenF, 'bold', 'red'); for (let modindex = 0; modindex < moderatorList.name.length; modindex++) { if (moderatorList.type[modindex] == 'botmod') { sendtotm = moderatorList.name[modindex].trim(); cb.sendNotice('\u261b PM - ' + user + ' to mods: ' + message, sendtotm, TMgreenB, TMgreenF, 'bold'); } } } break; case 'bc': cb.sendNotice('\u261b PM - ' + user + ' to you: ' + message, cb.room_slug, BCpurpleB, BCpurpleF, 'bold'); cb.sendNotice('\u261b PM - ' + 'You to ' + cb.room_slug + ': ' + message, user, BCpurpleB, BCpurpleF, 'bold'); break; case 'tbm': if (user == cb.room_slug) { cb.sendNotice('\u261b PM - You to mods: ' + message, cb.room_slug, TBMblueB, TBMblueF, 'bold'); cb.sendNotice('\u261b PM - ' + cb.room_slug + ' to mods: ' + message, '', TBMblueB, TBMblueF, 'bold', 'red'); for (let modindex = 0; modindex < moderatorList.name.length; modindex++) { if (moderatorList.type[modindex] == 'botmod') { sendtotbm = moderatorList.name[modindex].trim(); cb.sendNotice('\u261b PM - ' + cb.room_slug + ' to mods: ' + message, sendtotbm, TBMblueB, TBMblueF, 'bold'); } } } else { cb.sendNotice('\u261b PM - ' + user + ' to ' + cb.room_slug + ' and mods: ' + message, '', TBMblueB, TBMblueF, 'bold', 'red'); cb.sendNotice('\u261b PM - ' + user + ' to you and mods: ' + message, cb.room_slug, TBMblueB, TBMblueF, 'bold'); for (let modindex = 0; modindex < moderatorList.name.length; modindex++) { if (moderatorList.type[modindex] == 'botmod') { sendtotbm = moderatorList.name[modindex].trim(); cb.sendNotice('\u261b PM - ' + user + ' to ' + cb.room_slug + ' and mods: ' + message, sendtotbm, TBMblueB, TBMblueF, 'bold'); } } } break; case 'pm': if (dest != null && (dest != '' || dest != ' ' || dest != '\u00a0')) { cb.sendNotice('\u261b PM - ' + user + ': ' + message, dest, PMaquaB, PMaquaF, 'bold'); cb.sendNotice('\u261b PM - ' + '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, appNoticeColor); } } else { cb.sendNotice('You can\'t send a blank message. Type a message and try again.', user, appNoticeColor); } } 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, appNoticeColor); } } //********** Notifier Functions ************** function setNotifierToggle(mode,mod,bycmd) { if (mode == 'on') { if (notifierToggle == 1) { cb.sendNotice('The Notifier toggle is already turned on.', mod, appNoticeColor); } else { notifierToggle = 1; setNoticeColor(); rotcnt = 0; totcnt = 0; initNotifierTimer(); cb.setTimeout(displayNotifiers,notifierInt); if (bycmd) { cb.sendNotice('You have enabled the display of the rotating notifier messages.', mod, appNoticeColor); } } } else if (mode == 'off') { if (notifierToggle == 0) { cb.sendNotice('The Notifier toggle is already turned off.', mod, appNoticeColor); } else { notifierToggle = 0; cb.sendNotice('You have disabled the display of the rotating notifier messages.', mod, appNoticeColor); } } } function setNoticeColor() { if (cb.settings.notifiersTextColor == 'Custom') { noticeTextColor = checkTextColor(cb.settings.notifiersTextCustColor,true); 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,true); } if (cb.settings.notifiersBgColor == 'Custom') { noticeBgColor = checkBgColor(cb.settings.notifiersBgCustColor,true); 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,true); } } function initNotifierTimer() { let notifiertimer = parseFloat(cb.settings.notifierInterval); if (notifiertimer < 1) { cb.sendNotice('Fembot: Notifier interval is too short, must be at least 1. Using a value of 1 minute.', cb.room_slug, appNoticeColor); notifiertimer = 1; } notifiertimer *= 60000; notifierInt = parseInt(notifiertimer); } function displayNotifiers() { if (notifierToggle == 1) { if (minMessagesForNotice > 0 && msgCounterNotifier < minMessagesForNotice) { cb.setTimeout(displayNotifiers, 30000); } else { msgCounterNotifier = 0; notifierfound = false; if (rotcnt > 8) { rotcnt = 0; } if (notifierArray[rotcnt]) { notifiermessage = checkNextLine(notifierArray[rotcnt]); if (minTimeForNotice > 0) { // checkNoticeFrequency('\u25ba ' + notifiermessage, '', , noticeTextColor, 'bold', ''); } else { cb.sendNotice('\u25ba ' + notifiermessage, '', noticeBgColor, noticeTextColor, 'bold'); } notifierfound = true; } rotcnt++; totcnt++; if (notifierfound) { totcnt = 0; cb.setTimeout(displayNotifiers,notifierInt); } else { if (totcnt > 8) { cb.sendNotice('Fembot: Warning! Notifier enabled, but no notifications configured, disabling the notifier. You can use the command "/chgmsg1" (or 2 thru 9) to configure notifiers and then turn on notifications again with "/usenotifier on", or you can restart the bot and configure at least one notifier.', cb.room_slug, appNoticeColor); notifierToggle = 0; } else { displayNotifiers(); } } } } } //********** Room Rules Functions ************** function setRoomRulesToggle(mode, mod, bycmd) { if (mode == 'on') { if (roomRuleToggle == 1) { cb.sendNotice('The Room Rules toggle is already turned on.', mod, appNoticeColor); } else { roomRuleToggle = 1; setRoomRulesColor(); initRoomRulesTimer(); if (bycmd) { cb.sendNotice('You have enabled the display of the Room Rules messages.', mod, appNoticeColor); } } } else if (mode == 'off') { if (roomRuleToggle == 0) { cb.sendNotice('The Room Rules toggle is already turned off.', mod, appNoticeColor); } else { roomRuleToggle = 0; cb.sendNotice('You have disabled the display of the Room Rules messages.', mod, appNoticeColor); } } } function setRoomRulesColor() { if (cb.settings.roomRulesTextColor == 'Custom') { roomRulesTextColor = checkTextColor(cb.settings.roomRulesTextCustColor,true); if (roomRulesTextColor == 'default') { cb.sendNotice('Fembot Room Rules - Error while setting the text color. It has to be in a HEX format. Using default value.', cb.room_slug, '#FFFFFF', '#FF0000', 'bold'); roomRulesTextColor = '#FFFFFF'; } } else { roomRulesTextColor = checkTextColor(cb.settings.roomRulesTextColor,true); } if (cb.settings.roomRulesBgColor == 'Custom') { roomRulesBgColor = checkBgColor(cb.settings.roomRulesBgCustColor,true); if (roomRulesBgColor == 'default') { cb.sendNotice('Fembot Room Rules - Error while setting the background color. It has to be in a HEX format. Using default value.', cb.room_slug, '#FFFFFF', '#FF0000', 'bold'); roomRulesBgColor = '#FFFFFF'; } } else { roomRulesBgColor = checkBgColor(cb.settings.roomRulesBgColor,true); } } function initRoomRulesTimer() { if (isNaN(parseFloat(cb.settings.roomRulesInterval))) { rulestimer = 0; } else { rulestimer = parseFloat(cb.settings.roomRulesInterval); } if (rulestimer != 0) { if (rulestimer < 1) { cb.sendNotice('Fembot: Room Rules notice interval is too short, must be at least 1. Using a value of 5.5 minutes.', cb.room_slug, appWarningColor); rulestimer = 5.5; } roomRulesInt = parseInt(rulestimer * 60000); cb.setTimeout(roomRulesTimer,roomRulesInt); } } function roomRulesTimer() { if (roomRuleToggle == 1 && roomRulesArray.length > 0) { if (minMessagesForNotice > 0 && msgCounterRules < minMessagesForNotice) { cb.setTimeout(roomRulesTimer, 30000); } else { msgCounterRules = 0; displayRules(''); cb.setTimeout(roomRulesTimer,roomRulesInt); } } } function displayRules(sendto) { var rulemessage = noticeBorder('top','long','ROOM RULES'); for (let ruleindex = 0; ruleindex < roomRulesArray.length; ruleindex++) { if (roomRulesArray[ruleindex]) { rulemessage += '\n' + checkNextLine(roomRulesArray[ruleindex]); } } rulemessage += noticeBorder('bottom','long',''); cb.sendNotice(rulemessage, sendto, roomRulesBgColor, roomRulesTextColor, 'bold'); } //********** Followers Functions ************** function initFollowers() { followerNotifyFlag = 0; if (cb.settings.followerNotify == 'Yes, only to follower') { followerNotifyFlag = 1; } else if (cb.settings.followerNotify == 'Yes, only to broadcaster') { followerNotifyFlag = 2; } else if (cb.settings.followerNotify == 'Yes, to both') { followerNotifyFlag = 3; } else if (cb.settings.followerNotify == 'Yes, to everyone') { followerNotifyFlag = 4; } initFollowerTimer(); } function setFollowerColor() { if (cb.settings.followTextColor == 'Custom') { followTextColor = checkTextColor(cb.settings.followCustomTextColor,false); if (followTextColor == 'default') { cb.sendNotice('Fembot: Follower Response Message - error while setting the text color. It has to be in a HEX format. Using default value.', cb.room_slug, appWarningColor); followTextColor = '#000000'; } } else { followTextColor = checkTextColor(cb.settings.followTextColor,false); } if (cb.settings.followNoticeTextColor == 'Custom') { followNoticeTextColor = checkTextColor(cb.settings.followNoticeCustomTextColor,true); if (followNoticeTextColor == 'default') { cb.sendNotice('Fembot: Follower Notice - error while setting the text color. It has to be in a HEX format. Using default value.', cb.room_slug, appWarningColor); followNoticeTextColor = '#000000'; } } else { followNoticeTextColor = checkTextColor(cb.settings.followNoticeTextColor,true); } if (cb.settings.followBgColor == 'Custom') { followBgColor = checkBgColor(cb.settings.followCustomBgColor,false); if (followBgColor == 'default') { cb.sendNotice('Fembot: Follower Response Message - error while setting the background color. It has to be in a HEX format. Using default value.', cb.room_slug, appWarningColor); followBgColor = '#ffffff'; } } else { followBgColor = checkBgColor(cb.settings.followBgColor,false); } if (cb.settings.followNoticeBgColor == 'Custom') { followNoticeBgColor = checkBgColor(cb.settings.followNoticeCustomBgColor,true); if (followNoticeBgColor == 'default') { cb.sendNotice('Fembot: Follower Notice - error while setting the background color. It has to be in a HEX format. Using default value.', cb.room_slug, appWarningColor); followNoticeBgColor = '#ffffff'; } } else { followNoticeBgColor = checkBgColor(cb.settings.followNoticeBgColor,true); } } function initFollowerTimer() { if (isNaN(parseFloat(cb.settings.followNoticeInterval))) { cb.sendNotice('Fembot: Follower notice interval is not valid. Recurring notice and Follower stats summary are disabled.', cb.room_slug, appWarningColor); followtimer = 0; } else { followtimer = parseFloat(cb.settings.followNoticeInterval); } if (followtimer > 0) { if (followtimer < 1) { cb.sendNotice('Fembot: Follower notice interval is too short, must be at least 1 minute. Using a default value of 4.8 minutes.', cb.room_slug, appWarningColor); followtimer = 4.8; } followerInt = parseInt(followtimer * 60000); cb.setTimeout(followerTimer,followerInt); } } function followerTimer() { if ((cb.settings.followerReminderEnable == 'Yes' && cb.settings.followReminder) || cb.settings.followerStatsEnable == 'Yes') { if (minMessagesForNotice > 0 && msgCounterFollow < minMessagesForNotice) { cb.setTimeout(followerTimer, 30000); } else { msgCounterFollow = 0; if (cb.settings.followerReminderEnable == 'Yes' && cb.settings.followReminder) { cb.sendNotice(cb.settings.followReminder, '', followNoticeBgColor, followNoticeTextColor, 'bold'); } if (cb.settings.followerStatsEnable == 'Yes') { displayFollowerStats(cb.room_slug); } cb.setTimeout(followerTimer,followerInt); } } } function displayFollowerStats(statsendto) { cb.getRoomOwnerData(ownerData => { if (ownerData['success']) { var totalFollowers = ownerData['data']['followers']; var followersmsg = 'Sent only to YOU:\n'; followersmsg += noticeBorder('top','short','FOLLOWER SUMMARY'); if (numNewFollowersTotal > 0) { followersmsg += '\nNew followers this session (' + numNewFollowersTotal + ' total):'; if (numNewFollowersDPurple > 0) { followersmsg += '\n' + numNewFollowersDPurple + ' dark purple user' + (numNewFollowersDPurple != 1 ? 's' : ''); } if (numNewFollowersLPurple > 0) { followersmsg += '\n' + numNewFollowersLPurple + ' light purple user' + (numNewFollowersLPurple != 1 ? 's' : ''); } if (numNewFollowersDBlue > 0) { followersmsg += '\n' + numNewFollowersDBlue + ' dark blue user' + (numNewFollowersDBlue != 1 ? 's' : ''); } if (numNewFollowersLBlue > 0) { followersmsg += '\n' + numNewFollowersLBlue + ' light blue user' + (numNewFollowersLBlue != 1 ? 's' : ''); } if (numNewFollowersGray > 0) { followersmsg += '\n' + numNewFollowersGray + ' gray user' + (numNewFollowersGray != 1 ? 's' : ''); } } else { followersmsg += '\nNo new followers yet this session'; } if (totalFollowers > 0) { followersmsg += '\nTotal All-time Followers: ' + totalFollowers; } followersmsg += noticeBorder('bottom','short',''); cb.sendNotice(followersmsg, statsendto, followBgColor, followTextColor, 'bold'); } }); } function displayFollowerTotal(followsendto) { cb.getRoomOwnerData(ownerData => { if (ownerData['success']) { cb.sendNotice('Total Followers: ' + ownerData['data']['followers'], followsendto, appNoticeColor); } else { cb.sendNotice('Error retrieving Chaturbate Room data', followsendto, appNoticeColor); } }); } //********** Icon Tip Notice Functions ************** function setIconTipNoticeToggle(mode, mod, bycmd) { if (mode == 'on') { if (iconTipNoticeToggle == 1) { cb.sendNotice('The Icon Tip Notice toggle is already turned on.', mod, appNoticeColor); } else { iconTipNoticeToggle = 1; setIconTipNoticeColor(); initIconTipNoticeTimer(); if (bycmd) { cb.sendNotice('You have enabled the Icon Tip Notice.', mod, appNoticeColor); } } } else if (mode == 'off') { if (iconTipNoticeToggle == 0) { cb.sendNotice('The Icon Tip Notice toggle is already turned off.', mod, appNoticeColor); } else { iconTipNoticeToggle = 0; cb.sendNotice('You have disabled the Icon Tip Notice.', mod, appNoticeColor); } } } function setIconTipNoticeColor() { iconTipNoticeTextColor = checkTextColor('Black',true); iconTipNoticeBgColor = checkBgColor('Light Red',true); } function initIconTipNoticeTimer() { if (isNaN(parseFloat(cb.settings.iconTipNoticeInt))) { iconnoticetimer = 0; } else { iconnoticetimer = parseFloat(cb.settings.iconTipNoticeInt); } if (iconnoticetimer != 0) { if (iconnoticetimer < 1) { cb.sendNotice('Fembot: Tip for Icon notice interval is too short, must be at least 1. Using a value of 3.8 minutes.', cb.room_slug, appNoticeColor); iconnoticetimer = 3.8; } iconNoticeInt = parseInt(iconnoticetimer * 60000); cb.setTimeout(iconNoticeTimer,iconNoticeInt); } } function iconNoticeTimer() { if (iconTipNoticeToggle == 1) { if (minMessagesForNotice > 0 && msgCounterIconNotice < minMessagesForNotice) { cb.setTimeout(iconNoticeTimer, 30000); } else { msgCounterIconNotice = 0; if (iconTipAmountArray.length > 0) { displayIconTipNotice(); cb.setTimeout(iconNoticeTimer,iconNoticeInt); } } } } function displayIconTipNotice() { var iconmessage = noticeBorder('top','long','TIP FOR ICONS'); if (tipForIconType == 'Specific Tip Amount') { iconmessage += '\nYou can tip one of the below exact token amounts to be rewarded \nwith the associated icon next to your name in the chat:'; } else if (tipForIconType == 'Cumulative Tip Amount') { iconmessage += '\nOnce your total tips during this show exceed one of the amounts, \nyou will be rewarded with the associated icon by your name:'; } for (let noticeindex = 0; noticeindex < iconTipAmountArray.length; noticeindex++) { if (iconTipAmountArray[noticeindex]) { iconmessage += '\n' + iconTipAmountArray[noticeindex] + ' tokens: ' + iconTipIconArray[noticeindex]; } } if (minTimeForNotice > 0) { // checkNoticeFrequency(iconmessage, '', iconTipNoticeBgColor, iconTipNoticeTextColor, 'bold', ''); } else { iconmessage += noticeBorder('bottom','long',''); cb.sendNotice(iconmessage, '', iconTipNoticeBgColor, iconTipNoticeTextColor, 'bold'); } } //********** King Tipper Functions ************** function setKingTipperToggle(mode,sendto,bycmd) { if (mode == '1') { if (kingTipperToggle == 1) { cb.sendNotice('The King Tipper toggle is already turned on (user defined name).', sendto, appNoticeColor); } else { prevkingtippertoggle = kingTipperToggle; kingTipperToggle = 1; if (prevkingtippertoggle != 2) { setKingTipperColor(); initKingTipperTimer(); } if (bycmd) { cb.sendNotice('You have enabled the King Tipper feature for chat notices and user identification, using the pre-defined king tipper name.', sendto, appNoticeColor); } } } else if (mode == '2') { if (kingTipperToggle == 2) { cb.sendNotice('The King Tipper toggle is already turned on (All time list).', sendto, appNoticeColor); } else { prevkingtippertoggle = kingTipperToggle; kingTipperToggle = 2; buildAllTimeArray(); if (prevkingtippertoggle != 1) { setKingTipperColor(); initKingTipperTimer(); } cb.sendNotice('You have enabled the King Tipper feature for chat notices and user identification, using the all time list for king tipper tracking.', sendto, appNoticeColor); } } else if (mode == '0') { if (kingTipperToggle == 0) { cb.sendNotice('The King Tipper toggle is already turned off.', sendto, appNoticeColor); } else { kingTipperToggle = 0; cb.sendNotice('You have disabled the King Tipper feature.', sendto, appNoticeColor); } } } function setKingSessionToggle(mode,sendto,bycmd) { if (mode == '1') { if (kingSessionToggle == 1) { cb.sendNotice('The Current Session King Tipper toggle is already turned on.', sendto, appNoticeColor); } else { kingSessionToggle = 1; setKingSessionColor(); initKingSessionTimer(); if (bycmd) { cb.sendNotice('You have enabled the Current Session King Tipper feature.', sendto, appNoticeColor); } } } else if (mode == '0') { if (kingSessionToggle == 0) { cb.sendNotice('The Current Session King Tipper toggle is already turned off.', sendto, appNoticeColor); } else { kingSessionToggle = 0; cb.sendNotice('You have disabled the Current Session King Tipper feature.', sendto, appNoticeColor); } } } function setKingTipperColor() { kingTipperColorSet = true; if (cb.settings.kingTipperTextColor == 'Custom') { kingTipperTextColor = checkTextColor(cb.settings.kingTipperTextCustColor,true); if (kingTipperTextColor == 'default') { cb.sendNotice('Fembot King Tipper - Error while setting the text color. It has to be in a HEX format. Using default value.', cb.room_slug, '#FFFFFF', '#FF0000', 'bold'); kingTipperTextColor = ''; } } else { kingTipperTextColor = checkTextColor(cb.settings.kingTipperTextColor,true); } if (cb.settings.kingTipperBgColor == 'Custom') { kingTipperBgColor = checkBgColor(cb.settings.kingTipperBgCustColor,false); if (kingTipperBgColor == 'default') { cb.sendNotice('Fembot King Tipper - Error while setting the chat and announcement background color. It has to be in a HEX format. Using default value.', cb.room_slug, '#FFFFFF', '#FF0000', 'bold'); kingTipperBgColor = '#efe9ff'; } } else { kingTipperBgColor = checkBgColor(cb.settings.kingTipperBgColor,false); } if (cb.settings.kingTipperNoticeColor == 'Custom') { kingTipperBgNoticeColor = checkBgColor(cb.settings.kingTipperNoticeCustColor,true); if (kingTipperBgNoticeColor == 'default') { cb.sendNotice('Fembot King Tipper - Error while setting the notice background color. It has to be in a HEX format. Using default value.', cb.room_slug, '#FFFFFF', '#FF0000', 'bold'); kingTipperBgNoticeColor = '#efe9ff'; } } else { kingTipperBgNoticeColor = checkBgColor(cb.settings.kingTipperNoticeColor,true); } } function initKingTipperTimer() { if (isNaN(parseFloat(cb.settings.kingTipperInterval))) { kttimer = 0; } else { kttimer = parseFloat(cb.settings.kingTipperInterval); } if (kttimer != 0) { if (kttimer < 1) { cb.sendNotice('Fembot: King Tipper notice interval is too short, must be at least 1 minute. Using default value of 6.5 minutes.', cb.room_slug, appNoticeColor); kttimer = 6.5; } kingTipperInt = parseInt(kttimer * 60000); cb.setTimeout(kingTipperTimer, kingTipperInt); } } function kingTipperTimer() { if (kingTipperToggle == 1) { if (minMessagesForNotice > 0 && msgCounterKing < minMessagesForNotice) { cb.setTimeout(kingTipperTimer, 30000); } else { msgCounterKing = 0; displayKingTipperNotice(''); cb.setTimeout(kingTipperTimer,kingTipperInt); } } } function displayKingTipperNotice(sendto) { if (kingTipperName) { var kingTipperNotice = ''; if (cb.settings.kingTipperTitle) { kingTipperNotice += kingTipperName + ' is the ' + cb.settings.kingTipperTitle + '!'; } else { kingTipperNotice += kingTipperName + ' is the All-time tip leader for this room.'; } if (kingTipperAmount > 0) { kingTipperNotice += '\nYou can tip ' + (kingTipperAmount + 1) + ' to become the new all-time king!'; } if (cb.settings.kingTipperNotice) { kingTipperNotice += '\n' + cb.settings.kingTipperNotice; } if (minTimeForNotice > 0) { // checkNoticeFrequency(kingTipperNotice, sendto, kingTipperBgColor, kingTipperTextColor, 'bold', ''); } else { cb.sendNotice(kingTipperNotice, sendto, kingTipperBgNoticeColor, kingTipperTextColor, 'bold'); } } else { cb.sendNotice('The King Tipper Name was not successfully assigned, disabling the King Tipper feature.', sendto, appWarningColor); setKingTipperToggle('0',cb.room_slug,false); } } function setKingSessionColor() { kingSessionColorSet = true; if (cb.settings.kingSessionTextColor == 'Custom') { kingSessionTextColor = checkTextColor(cb.settings.kingSessionTextCustColor,true); if (kingSessionTextColor == 'default') { cb.sendNotice('Fembot King Session Tipper - Error while setting the text color. It has to be in a HEX format. Using default value.', cb.room_slug, '#FFFFFF', '#FF0000', 'bold'); kingSessionTextColor = ''; } } else { kingSessionTextColor = checkTextColor(cb.settings.kingSessionTextColor,true); } if (cb.settings.kingSessionNoticeColor == 'Custom') { kingSessionNoticeColor = checkBgColor(cb.settings.kingSessionNoticeCustColor,true); if (kingSessionNoticeColor == 'default') { cb.sendNotice('Fembot King Session Tipper - Error while setting the notice background color. It has to be in a HEX format. Using default value.', cb.room_slug, '#FFFFFF', '#FF0000', 'bold'); kingSessionNoticeColor = '#efe9ff'; } } else { kingSessionNoticeColor = checkBgColor(cb.settings.kingSessionNoticeColor,true); } } function initKingSessionTimer() { var sesktint = 0; if (isNaN(parseFloat(cb.settings.kingSessionInterval))) { sesktint = 0; } else { sesktint = parseFloat(cb.settings.kingSessionInterval); } if (sesktint != 0) { if (sesktint < 1) { cb.sendNotice('Fembot: King Tipper notice interval is too short, must be at least 1 minute. Using default value of 5.7 minutes.', cb.room_slug, appNoticeColor); sesktint = 5.7; } kingSessionInt = parseInt(sesktint * 60000); cb.setTimeout(kingSessionTimer, kingSessionInt); } } function kingSessionTimer() { if (kingSessionToggle == 1) { if (minMessagesForNotice > 0 && msgCounterKingSession < minMessagesForNotice) { cb.setTimeout(kingSessionTimer, 30000); } else { msgCounterKingSession = 0; displayKingSessionNotice(''); cb.setTimeout(kingSessionTimer,kingSessionInt); } } } function displayKingSessionNotice(kingsessionsendto) { if (cb.settings.kingSessionEnable == 'Yes' && cb.settings.kingSessionMinAmount > 0) { var kingsessionnotice = ''; if (currentKingTipper) { kingsessionnotice += cb.settings.kingSessionIcon + ' ' + currentKingTipper + ' is the king tipper for this show. ' + cb.settings.kingSessionIcon + '\nTip at least ' + (currentKingTipperAmount + 1) + ' tokens to become the new king!'; } else { kingsessionnotice += cb.settings.kingSessionIcon + ' You can tip at least ' + cb.settings.kingSessionMinAmount + ' tokens to become the new king of this show! ' + cb.settings.kingSessionIcon; } if (minTimeForNotice > 0) { // checkNoticeFrequency(kingsessionnotice, kingsessionsendto, kingSessionNoticeColor, kingSessionTextColor, 'bold', ''); } else { cb.sendNotice(kingsessionnotice, kingsessionsendto, kingSessionNoticeColor, kingSessionTextColor, 'bold'); } } } // *************************** Tip Count Functions ************************ function setTipCountToggle(mode,mod,bycmd) { if (mode == 'on') { if(tipCountToggle == 1) { cb.sendNotice('The Tip Count display is already turned on.',mod,appNoticeColor); } else { tipCountToggle = 1; if (bycmd) { cb.sendNotice('You have enabled the Tip Count display next to each user name in the chat.',mod,appNoticeColor); } } } else if (mode == 'off') { if (tipCountToggle == 0) { cb.sendNotice('The Tip Count display is already turned off.',mod,appNoticeColor); } else { tipCountToggle = 0; cb.sendNotice('You have disabled the Tip Count display.',mod,appNoticeColor); } } else if (mode != null) { cb.sendNotice(mode + ' is not a valid option for /usetipcount.',mod,appNoticeColor); } else if (mode == null) { cb.sendNotice('You did not enter a valid option for /usetipcount.',mod,appNoticeColor); } } // *************************** Tip Menu Functions ************************ function setTipMenuToggle(option, mod) { if(option == 'on') { if(tipMenuToggle == 1) { cb.sendNotice('Tip Menu 1 is already turned on.',mod,appNoticeColor); } else { tipMenuToggle = 1; initMenu(mod); cb.sendNotice(' ' + mod + ' has enabled Tip Menu 1.\nYou control the action by tipping for selections from the menu!\nTo see the menu, type: /tipmenu', '', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } } else if(option == 'off') { if(tipMenuToggle == 0) { cb.sendNotice('Tip Menu 1 is already turned off.',mod,appNoticeColor); } else { tipMenuToggle = 0; for (let i = 0; i < TIPMENU.tipMenuPrice.length; i++) { priceChecker('rmv','Tip Menu Option: '+TIPMENU.tipMenuItem[i],TIPMENU.tipMenuPrice[i],mod); } TIPMENU.tipMenuPrice = []; TIPMENU.tipMenuItem = []; cb.sendNotice(' ' + mod + ' has disabled Tip Menu 1.\nYou can no longer tip for selections from Menu 1.', '', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold') } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usemenu.',mod,appNoticeColor); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usemenu.',mod,appNoticeColor); } } function setTipMenu2Toggle(option, mod) { if(option == 'on') { if(tipMenu2Toggle == 1) { cb.sendNotice('Tip Menu 2 is already turned on.',mod,appNoticeColor); } else { tipMenu2Toggle = 1; initMenu2(mod); cb.sendNotice(' ' + mod + ' has enabled Tip Menu 2.\nYou control the action by tipping for selections from the menu!\nTo see the menu, type: /tipmenu', '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); } } else if(option == 'off') { if(tipMenu2Toggle == 0) { cb.sendNotice('Tip Menu 2 is already turned off.',mod,appNoticeColor); } else { tipMenu2Toggle = 0; for (let i = 0; i < TIPMENU2.tipMenuPrice.length; i++) { priceChecker('rmv','Tip Menu 2 Option: '+TIPMENU2.tipMenuItem[i],TIPMENU2.tipMenuPrice[i],mod); } TIPMENU2.tipMenuPrice = []; TIPMENU2.tipMenuItem = []; cb.sendNotice(' ' + mod + ' has disabled Tip Menu 2.\nYou can no longer tip for selections from Menu 2.', '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usemenu2.',mod,appNoticeColor); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usemenu2.',mod,appNoticeColor); } } function initMenu(mod) { if (cb.settings.menutxtcolor1 == 'Custom') { TIPMENU.txtColor1 = checkTextColor(cb.settings.menuCustTxtColor1,true); TIPMENU.txtColorTip = checkTextColor(cb.settings.menuCustTxtColor1,false); 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'; TIPMENU.txtColorTip = '#0629AC'; } } else { TIPMENU.txtColor1 = checkTextColor(cb.settings.menutxtcolor1,true); TIPMENU.txtColorTip = checkTextColor(cb.settings.menutxtcolor1,false); } if (cb.settings.menubgcolor1 == 'Custom') { TIPMENU.bgColor1 = checkBgColor(cb.settings.menuCustBgColor1,true); TIPMENU.bgColorTip = checkBgColor(cb.settings.menuCustBgColor1,false); 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'; TIPMENU.bgColorTip = '#FFFFFF'; } } else { TIPMENU.bgColor1 = checkBgColor(cb.settings.menubgcolor1,true); TIPMENU.bgColorTip = checkBgColor(cb.settings.menubgcolor1,false); } if (cb.settings.tipMenuNoticeType == 'Split Menu - Paragraph Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { if (cb.settings.menutxtcolor2 == 'Custom') { TIPMENU.txtColor2 = checkTextColor(cb.settings.menuCustTxtColor2,true); 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,true); } if (cb.settings.menubgcolor2 == 'Custom') { TIPMENU.bgColor2 = checkBgColor(cb.settings.menuCustBgColor2,true); 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,true); } } displayMenuTimer(); setSepChar(); let maxItems = 40; if (cb.settings.includeDiceRollPrice == 'Yes' && diceToggle == 1 && diceRollPrice > 0) { TIPMENU.tipMenuPrice.push(diceRollPrice); TIPMENU.tipMenuItem.push('Dice Roll'); if (cb.settings.tipMenuModSalePct > 0) { TIPMENUMOD.tipMenuPrice.push(diceRollPrice); TIPMENUMOD.tipMenuItem.push('Dice Roll'); } if (cb.settings.tipMenuCBFCSalePct > 0) { TIPMENUCBFC.tipMenuPrice.push(diceRollPrice); TIPMENUCBFC.tipMenuItem.push('Dice Roll'); } if (cb.settings.tipMenuEFC1SalePct > 0) { TIPMENUEFC1.tipMenuPrice.push(diceRollPrice); TIPMENUEFC1.tipMenuItem.push('Dice Roll'); } if (cb.settings.tipMenuEFC2SalePct > 0) { TIPMENUEFC2.tipMenuPrice.push(diceRollPrice); TIPMENUEFC2.tipMenuItem.push('Dice Roll'); } if (cb.settings.tipMenuVIPSalePct > 0) { TIPMENUVIP.tipMenuPrice.push(diceRollPrice); TIPMENUVIP.tipMenuItem.push('Dice Roll'); } } for (let j = 0; j <= maxItems; j++) { if (cb.settings['menuitem' + j] !== '' && cb.settings['menuitemprice' + j] > 0) { if (cb.settings.tipMenuSalePct > 0) { regularprice = cb.settings['menuitemprice' + j]; saleprice = Math.round(regularprice - (cb.settings.tipMenuSalePct/100*regularprice)); if (saleprice <= 0) { saleprice = 1; } TIPMENU.tipMenuPrice.push(saleprice.toString()); priceused = saleprice.toString(); } else { TIPMENU.tipMenuPrice.push(cb.settings['menuitemprice' + j]); priceused = cb.settings['menuitemprice' + j]; } TIPMENU.tipMenuItem.push(cb.settings['menuitem' + j]); priceChecker('add','Tip Menu Option: '+(cb.settings['menuitem' + j]), priceused, mod); if (cb.settings.tipMenuModSalePct > 0) { regularprice = cb.settings['menuitemprice' + j]; modsaleprice = Math.round(regularprice - (cb.settings.tipMenuModSalePct/100*regularprice)); if (modsaleprice <= 0) { modsaleprice = 1; } TIPMENUMOD.tipMenuItem.push(cb.settings['menuitem' + j]); TIPMENUMOD.tipMenuPrice.push(modsaleprice.toString()); } if (cb.settings.tipMenuCBFCSalePct > 0) { regularprice = cb.settings['menuitemprice' + j]; fansaleprice = Math.round(regularprice - (cb.settings.tipMenuCBFCSalePct/100*regularprice)); if (fansaleprice <= 0) { fansaleprice = 1; } TIPMENUCBFC.tipMenuItem.push(cb.settings['menuitem' + j]); TIPMENUCBFC.tipMenuPrice.push(fansaleprice.toString()); } if (cb.settings.tipMenuEFC1SalePct > 0) { regularprice = cb.settings['menuitemprice' + j]; extfan1saleprice = Math.round(regularprice - (cb.settings.tipMenuEFC1SalePct/100*regularprice)); if (extfan1saleprice <= 0) { extfan1saleprice = 1; } TIPMENUEFC1.tipMenuItem.push(cb.settings['menuitem' + j]); TIPMENUEFC1.tipMenuPrice.push(extfan1saleprice.toString()); } if (cb.settings.tipMenuEFC2SalePct > 0) { regularprice = cb.settings['menuitemprice' + j]; extfan2saleprice = Math.round(regularprice - (cb.settings.tipMenuEFC2SalePct/100*regularprice)); if (extfan2saleprice <= 0) { extfan2saleprice = 1; } TIPMENUEFC2.tipMenuItem.push(cb.settings['menuitem' + j]); TIPMENUEFC2.tipMenuPrice.push(extfan2saleprice.toString()); } if (cb.settings.tipMenuVIPSalePct > 0) { regularprice = cb.settings['menuitemprice' + j]; vipsaleprice = Math.round(regularprice - (cb.settings.tipMenuVIPSalePct/100*regularprice)); if (vipsaleprice <= 0) { vipsaleprice = 1; } TIPMENUVIP.tipMenuItem.push(cb.settings['menuitem' + j]); TIPMENUVIP.tipMenuPrice.push(vipsaleprice.toString()); } } } for (let fanloadidx = 0; fanloadidx <= 10; fanloadidx++) { if (cb.settings['fanmenuitem' + fanloadidx] !== '' && cb.settings['fanmenuitemprice' + fanloadidx] > 0) { if (cbjs.arrayContains(TIPMENUCBFC.tipMenuPrice, cb.settings['fanmenuitemprice' + fanloadidx])) { cb.sendNotice('Tip Menu - ' + cb.settings['fanmenuitemprice' + fanloadidx] + ' is already on the CB Fan Club-specific menu. \nIt is recommended to have a different price for each item.', cb.room_slug, '#FFFFFF', '#FF0000'); } TIPMENUCBFC.tipMenuPrice.push(cb.settings['fanmenuitemprice' + fanloadidx]); TIPMENUCBFC.tipMenuItem.push(cb.settings['fanmenuitem' + fanloadidx]); fanpriceused = cb.settings['fanmenuitemprice' + fanloadidx]; priceChecker('add','CB Fanclub Tip Menu Option: '+(cb.settings['menuitem' + fanloadidx]), fanpriceused, mod); } } for (let efc1loadidx = 0; efc1loadidx <= 10; efc1loadidx++) { if (cb.settings['efc1menuitem' + efc1loadidx] !== '' && cb.settings['efc1menuitemprice' + efc1loadidx] > 0) { if (cbjs.arrayContains(TIPMENUCBFC.tipMenuPrice, cb.settings['efc1menuitemprice' + efc1loadidx])) { cb.sendNotice('Tip Menu - ' + cb.settings['efc1menuitemprice' + efc1loadidx] + ' is already on the External Fan Club 1-specific menu. \nIt is recommended to have a different price for each item.', cb.room_slug, '#FFFFFF', '#FF0000'); } TIPMENUEFC1.tipMenuPrice.push(cb.settings['efc1menuitemprice' + efc1loadidx]); TIPMENUEFC1.tipMenuItem.push(cb.settings['efc1menuitem' + efc1loadidx]); efc1priceused = cb.settings['efc1menuitemprice' + efc1loadidx]; priceChecker('add','External Fanclub 1 Tip Menu Option: '+(cb.settings['menuitem' + efc1loadidx]), efc1priceused, mod); } } for (let efc2loadidx = 0; efc2loadidx <= 10; efc2loadidx++) { if (cb.settings['efc2menuitem' + efc2loadidx] !== '' && cb.settings['efc2menuitemprice' + efc2loadidx] > 0) { if (cbjs.arrayContains(TIPMENUCBFC.tipMenuPrice, cb.settings['efc2menuitemprice' + efc2loadidx])) { cb.sendNotice('Tip Menu - ' + cb.settings['efc2menuitemprice' + efc2loadidx] + ' is already on the External Fan Club 2-specific menu. It is recommended to have a different price for each item.', cb.room_slug, '#FFFFFF', '#FF0000'); } TIPMENUEFC1.tipMenuPrice.push(cb.settings['efc2menuitemprice' + efc2loadidx]); TIPMENUEFC1.tipMenuItem.push(cb.settings['efc2menuitem' + efc2loadidx]); efc2priceused = cb.settings['efc2menuitemprice' + efc2loadidx]; priceChecker('add','External Fanclub 2 Tip Menu Option: '+(cb.settings['menuitem' + efc2loadidx]), efc2priceused, mod); } } buildMenu(); cb.setTimeout(displayMenu, TIPMENU.menuDspIntTime); } function displayMenuTimer() { if (isNaN(parseFloat(cb.settings.menuDspInt))) { cb.sendNotice('Fembot: Tip Menu notice interval is not set with a valid number so the Tip Menu notice is not enabled.', cb.room_slug, appWarningColor); tipmenutimer = 0; } else { tipmenutimer = parseFloat(cb.settings.menuDspInt); } if (tipmenutimer != 0) { if (tipmenutimer < 1) { cb.sendNotice('Fembot: Tip Menu notice interval is too short. Using default value of 2.9 minutes.', cb.room_slug, '#FFFFFF', '#FF0000', 'bold'); tipmenutimer = 2.9; } tipmenutimer = parseInt(tipmenutimer * 60000); TIPMENU.menuDspIntTime = tipmenutimer; } } function initMenu2(mod) { if (cb.settings.menutxtcolor1 == 'Custom') { TIPMENU2.txtColor1 = checkTextColor(cb.settings.menuCustTxtColor1,true); TIPMENU2.txtColorTip = checkTextColor(cb.settings.menuCustTxtColor1,false); 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'; TIPMENU2.txtColorTip = '#0629AC'; } } else { TIPMENU2.txtColor1 = checkTextColor(cb.settings.menutxtcolor1,true); TIPMENU2.txtColorTip = checkTextColor(cb.settings.menutxtcolor1,false); } if (cb.settings.menubgcolor1 == 'Custom') { TIPMENU2.bgColor1 = checkBgColor(cb.settings.menuCustBgColor1,true); TIPMENU2.bgColorTip = checkBgColor(cb.settings.menuCustBgColor1,true); 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'; TIPMENU2.bgColorTip = '#FFFFFF'; } } else { TIPMENU2.bgColor1 = checkBgColor(cb.settings.menubgcolor1,true); TIPMENU2.bgColorTip = checkBgColor(cb.settings.menubgcolor1,false); } if (cb.settings.tipMenuNoticeType == 'Split Menu - Paragraph Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { if (cb.settings.menutxtcolor2 == 'Custom') { TIPMENU2.txtColor2 = checkTextColor(cb.settings.menuCustTxtColor2,true); if (TIPMENU2.txtColor2 == 'default') { cb.sendNotice('Tip Menu part 2 - Error while setting the text color for second menu color, 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,true); } if (cb.settings.menubgcolor2 == 'Custom') { TIPMENU2.bgColor2 = checkBgColor(cb.settings.menuCustBgColor2,true); if (TIPMENU2.bgColor2 == 'default') { cb.sendNotice('Tip Menu part 2 - Error while setting the background color for second menu color, 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,true); } } displayMenuTimer2(); setSepChar2(); let maxItems = 25; for (let j = 0; j <= maxItems; j++) { if (cb.settings['menu2item' + j] !== '' && cb.settings['menu2itemprice' + j] > 0) { if (cb.settings.tipMenu2SalePct > 0) { regularprice = cb.settings['menu2itemprice' + j]; saleprice = Math.round(regularprice - (cb.settings.tipMenu2SalePct/100*regularprice)); if (saleprice <= 0) { saleprice = 1; } TIPMENU2.tipMenuPrice.push(saleprice.toString()); priceused = saleprice.toString(); } else { TIPMENU2.tipMenuPrice.push(cb.settings['menu2itemprice' + j]); priceused = cb.settings['menu2itemprice' + j]; } TIPMENU2.tipMenuItem.push(cb.settings['menu2item' + j]); priceChecker('add','Tip Menu 2 Option: '+(cb.settings['menu2item' + j]), priceused, mod); } } if (cb.settings.includeDiceRollPrice == 'Yes' && TIPMENU2.tipMenuPrice.length < maxItems && diceToggle == 1 && diceRollPrice > 0) { TIPMENU2.tipMenuPrice.push(diceRollPrice); TIPMENU2.tipMenuItem.push('Dice Roll'); } buildMenu2(); cb.setTimeout(displayMenu2, TIPMENU2.menuDspIntTime); } function buildMenu() { TIPMENU.tipMenu = bctext + '\'s Tip Menu:'; 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(); } } if (cb.settings.tipMenuNoticeType == 'Full Menu - List Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { if (cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { menuListSplit = true; if (sorted.length <= 8) { menuListSplit = false; cb.sendNotice('Tip Menu - Warning - Menu format is "Split Menu - List Form" but the menu has 8 items or less, it will not be split.', cb.room_slug, appWarningColor, '', 'bold'); } else { TIPMENU.menuPartArray[0] = bctext + '\'s Tip Menu Part 1:'; TIPMENU.menuPartArray[1] = bctext + '\'s Tip Menu Part 2:'; TIPMENU.menuPartArray[2] = bctext + '\'s Tip Menu Part 3:'; TIPMENU.menuPartArray[3] = bctext + '\'s Tip Menu Part 4:'; TIPMENU.menuPartArray[4] = bctext + '\'s Tip Menu Part 5:'; if (sorted.length <= 16) { menuNumberChunks = 2; menuChunkLength = Math.ceil(sorted.length / menuNumberChunks); } else if (sorted.length <= 24) { menuNumberChunks = 3; menuChunkLength = Math.ceil(sorted.length / menuNumberChunks); } else if (sorted.length <= 32) { menuNumberChunks = 4; menuChunkLength = Math.ceil(sorted.length / menuNumberChunks); } else if (sorted.length <= 40) { menuNumberChunks = 5; menuChunkLength = Math.ceil(sorted.length / menuNumberChunks); } currentChunk = 1; currentChunkItem = 1; } } for (let sortmenuidx = 0; sortmenuidx < sorted.length; sortmenuidx++) { if (TIPMENU.tipMenuPrice[sorted[sortmenuidx].id] !== 0) { TIPMENU.tipMenu += '\n' + TIPMENU.sepChar + ' ' + TIPMENU.tipMenuPrice[sorted[sortmenuidx].id] + ' - ' + TIPMENU.tipMenuItem[sorted[sortmenuidx].id] if (cb.settings.tipMenuNoticeType == 'Split Menu - List Form' && menuListSplit) { TIPMENU.menuPartArray[currentChunk-1] += '\n' + TIPMENU.sepChar + ' ' + TIPMENU.tipMenuPrice[sorted[sortmenuidx].id] + ' - ' + TIPMENU.tipMenuItem[sorted[sortmenuidx].id]; currentChunkItem++; if (currentChunkItem > menuChunkLength) { TIPMENU.menuPartArray[currentChunk-1] += '\nThe menu has been split. To see the full menu type: /tipmenu'; currentChunk ++; currentChunkItem = 1; } } } } } else { for (let sortmenuidx2 = 0; sortmenuidx2 < sorted.length; sortmenuidx2++) { if (TIPMENU.tipMenuPrice[sorted[sortmenuidx2].id] !== 0) { menuArray.push(TIPMENU.tipMenuItem[sorted[sortmenuidx2].id] + ' (' + TIPMENU.tipMenuPrice[sorted[sortmenuidx2].id] + ') '); } } TIPMENU.tipMenu += '\n' + menuArray.join(TIPMENU.sepChar); if (cb.settings.tipMenuNoticeType == 'Split Menu - Paragraph Form') { 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 { TIPMENU.menuPartArray[0] = bctext + '\'s Tip Menu Part 1:'; TIPMENU.menuPartArray[1] = bctext + '\'s Tip Menu Part 2:'; let msglength1 = 0; let msgHalf = (TIPMENU.tipMenu.length - 9) / 2; for (let sortmenuidx3 = 0; sortmenuidx3 < sorted.length; sortmenuidx3++) { if (TIPMENU.tipMenuPrice[sorted[sortmenuidx3].id] !== 0) { if (msglength1 < msgHalf) { menuArray1.push(TIPMENU.tipMenuItem[sorted[sortmenuidx3].id] + ' (' + TIPMENU.tipMenuPrice[sorted[sortmenuidx3].id] + ') '); msglength1 = menuArray1.join(TIPMENU.sepChar).length; } else { menuArray2.push(TIPMENU.tipMenuItem[sorted[sortmenuidx3].id] + ' (' + TIPMENU.tipMenuPrice[sorted[sortmenuidx3].id] + ') '); } } } TIPMENU.menuPartArray[0] += '\n' + menuArray1.join(TIPMENU.sepChar) + '\n The menu has been split. To see the full menu type: /tipmenu'; TIPMENU.menuPartArray[1] += '\n' + menuArray2.join(TIPMENU.sepChar) + '\n The menu has been split. To see the full menu type: /tipmenu'; } } } TIPMENU.menuLength = TIPMENU.tipMenuPrice.length; if (TIPMENU.menuLength <= 0) { cb.sendNotice('Error - No menu items found', '', '', TIPMENU.txtColor1, 'bold'); } if (TIPMENUMOD.tipMenuItem.length > 0) { modSpecificMenuItems = true; buildMenuMod(); } if (TIPMENUCBFC.tipMenuItem.length > 0) { cbfcSpecificMenuItems = true; buildMenuFan(); } if (TIPMENUEFC1.tipMenuItem.length > 0) { efc1SpecificMenuItems = true; buildMenuEFC1(); } if (TIPMENUEFC2.tipMenuItem.length > 0) { efc2SpecificMenuItems = true; buildMenuEFC2(); } if (TIPMENUVIP.tipMenuItem.length > 0) { vipSpecificMenuItems = true; buildMenuVIP(); } } function buildMenuMod() { TIPMENUMOD.tipMenu = bctext + '\'s Moderator Tip Menu'; let menuArray = []; let sorted = []; let menuL = TIPMENUMOD.tipMenuPrice.length; for (let i = 0; i < menuL; i++) { sorted.push({ 'prices': TIPMENUMOD.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(); } } if (cb.settings.tipMenuNoticeType == 'Full Menu - List Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { for (let j = 0; j < sorted.length; j++) { if (TIPMENUMOD.tipMenuPrice[sorted[j].id] !== 0) { menuArray.push(TIPMENUMOD.tipMenuPrice[sorted[j].id] + ' - ' + TIPMENUMOD.tipMenuItem[sorted[j].id]); } } tempsepchar = '\n' + TIPMENUMOD.sepChar; TIPMENUMOD.tipMenu += tempsepchar; TIPMENUMOD.tipMenu += menuArray.join(tempsepchar); } else { for (let j = 0; j < sorted.length; j++) { if (TIPMENUMOD.tipMenuPrice[sorted[j].id] !== 0) { menuArray.push(TIPMENUMOD.tipMenuItem[sorted[j].id] + ' (' + TIPMENUMOD.tipMenuPrice[sorted[j].id] + ') '); } } TIPMENUMOD.tipMenu += '\n' + menuArray.join(TIPMENUMOD.sepChar); } TIPMENUMOD.menuLength = TIPMENUMOD.tipMenuPrice.length; if (TIPMENU.menuLength <= 0) { cb.sendNotice('Error - No Moderator Specific menu items found', '', '', TIPMENU.txtColor1, 'bold'); } } function buildMenuFan() { TIPMENUCBFC.tipMenu = bctext + '\'s CB Fan Club Tip Menu:'; let menuArray = []; let sorted = []; let menuL = TIPMENUCBFC.tipMenuPrice.length; for (let i = 0; i < menuL; i++) { sorted.push({ 'prices': TIPMENUCBFC.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(); } } if (cb.settings.tipMenuNoticeType == 'Full Menu - List Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { for (let j = 0; j < sorted.length; j++) { if (TIPMENUCBFC.tipMenuPrice[sorted[j].id] !== 0) { menuArray.push(TIPMENUCBFC.tipMenuPrice[sorted[j].id] + ' - ' + TIPMENUCBFC.tipMenuItem[sorted[j].id]); } } tempsepchar = '\n' + TIPMENUCBFC.sepChar; TIPMENUCBFC.tipMenu += tempsepchar; TIPMENUCBFC.tipMenu += menuArray.join(tempsepchar); } else { for (let j = 0; j < sorted.length; j++) { if (TIPMENUCBFC.tipMenuPrice[sorted[j].id] !== 0) { menuArray.push(TIPMENUCBFC.tipMenuItem[sorted[j].id] + ' (' + TIPMENUCBFC.tipMenuPrice[sorted[j].id] + ') '); } } TIPMENUCBFC.tipMenu += '\n' + menuArray.join(TIPMENUCBFC.sepChar); } TIPMENUCBFC.menuLength = TIPMENUCBFC.tipMenuPrice.length; if (TIPMENU.menuLength <= 0) { cb.sendNotice('Error - No CB Fan Club Specific menu items found', '', '', TIPMENU.txtColor1, 'bold'); } } function buildMenuEFC1() { TIPMENUEFC1.tipMenu = EFCname + ' Tip Menu:'; let menuArray = []; let sorted = []; let menuL = TIPMENUEFC1.tipMenuPrice.length; for (let i = 0; i < menuL; i++) { sorted.push({ 'prices': TIPMENUEFC1.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(); } } if (cb.settings.tipMenuNoticeType == 'Full Menu - List Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { for (let j = 0; j < sorted.length; j++) { if (TIPMENUEFC1.tipMenuPrice[sorted[j].id] !== 0) { menuArray.push(TIPMENUEFC1.tipMenuPrice[sorted[j].id] + ' - ' + TIPMENUEFC1.tipMenuItem[sorted[j].id]); } } tempsepchar = '\n' + TIPMENUEFC1.sepChar; TIPMENUEFC1.tipMenu += tempsepchar; TIPMENUEFC1.tipMenu += menuArray.join(tempsepchar); } else { for (let j = 0; j < sorted.length; j++) { if (TIPMENUEFC1.tipMenuPrice[sorted[j].id] !== 0) { menuArray.push(TIPMENUEFC1.tipMenuItem[sorted[j].id] + ' (' + TIPMENUEFC1.tipMenuPrice[sorted[j].id] + ') '); } } TIPMENUEFC1.tipMenu += '\n' + menuArray.join(TIPMENUEFC1.sepChar); } TIPMENUEFC1.menuLength = TIPMENUEFC1.tipMenuPrice.length; if (TIPMENU.menuLength <= 0) { cb.sendNotice('Error - No Ext Fan Club 1 Specific menu items found', '', '', TIPMENU.txtColor1, 'bold'); } } function buildMenuEFC2() { TIPMENUEFC2.tipMenu = EFCname2 + ' Tip Menu:'; let menuArray = []; let sorted = []; let menuL = TIPMENUEFC2.tipMenuPrice.length; for (let i = 0; i < menuL; i++) { sorted.push({ 'prices': TIPMENUEFC2.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(); } } if (cb.settings.tipMenuNoticeType == 'Full Menu - List Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { for (let j = 0; j < sorted.length; j++) { if (TIPMENUEFC2.tipMenuPrice[sorted[j].id] !== 0) { menuArray.push(TIPMENUEFC2.tipMenuPrice[sorted[j].id] + ' - ' + TIPMENUEFC2.tipMenuItem[sorted[j].id]); } } tempsepchar = '\n' + TIPMENUEFC2.sepChar; TIPMENUEFC2.tipMenu += tempsepchar; TIPMENUEFC2.tipMenu += menuArray.join(tempsepchar); } else { for (let j = 0; j < sorted.length; j++) { if (TIPMENUEFC2.tipMenuPrice[sorted[j].id] !== 0) { menuArray.push(TIPMENUEFC2.tipMenuItem[sorted[j].id] + ' (' + TIPMENUEFC2.tipMenuPrice[sorted[j].id] + ') '); } } TIPMENUEFC2.tipMenu += '\n' + menuArray.join(TIPMENUEFC2.sepChar); } TIPMENUEFC2.menuLength = TIPMENUEFC2.tipMenuPrice.length; if (TIPMENU.menuLength <= 0) { cb.sendNotice('Error - No Ext Fan Club 2 Specific menu items found', '', '', TIPMENU.txtColor1, 'bold'); } } function buildMenuVIP() { TIPMENUVIP.tipMenu = bctext + '\'s VIP Tip Menu:'; let menuArray = []; let sorted = []; let menuL = TIPMENUVIP.tipMenuPrice.length; for (let i = 0; i < menuL; i++) { sorted.push({ 'prices': TIPMENUVIP.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(); } } if (cb.settings.tipMenuNoticeType == 'Full Menu - List Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { for (let j = 0; j < sorted.length; j++) { if (TIPMENUVIP.tipMenuPrice[sorted[j].id] !== 0) { menuArray.push(TIPMENUVIP.tipMenuPrice[sorted[j].id] + ' - ' + TIPMENUVIP.tipMenuItem[sorted[j].id]); } } tempsepchar = '\n' + TIPMENUVIP.sepChar; TIPMENUVIP.tipMenu += tempsepchar; TIPMENUVIP.tipMenu += menuArray.join(tempsepchar); } else { for (let j = 0; j < sorted.length; j++) { if (TIPMENUVIP.tipMenuPrice[sorted[j].id] !== 0) { menuArray.push(TIPMENUVIP.tipMenuItem[sorted[j].id] + ' (' + TIPMENUVIP.tipMenuPrice[sorted[j].id] + ') '); } } TIPMENUVIP.tipMenu += '\n' + menuArray.join(TIPMENUVIP.sepChar); } TIPMENUVIP.menuLength = TIPMENUVIP.tipMenuPrice.length; if (TIPMENU.menuLength <= 0) { cb.sendNotice('Error - No VIP Specific menu items found', '', '', TIPMENU.txtColor1, 'bold'); } } function buildMenu2() { TIPMENU2.tipMenu = bctext + '\'s Tip Menu #2:'; 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(); } } if (cb.settings.tipMenuNoticeType == 'Full Menu - List Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { if (cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { menu2ListSplit = true; if (sorted2.length <= 8) { menu2ListSplit = false; cb.sendNotice('Tip Menu 2 - Warning - Menu format is "Split Menu - List Form" but menu 2 has 8 items or less, it will not be split.', cb.room_slug, appWarningColor, '', 'bold'); } else { TIPMENU2.menuPartArray[0] = bctext + '\'s Tip Menu 2 Part 1:'; TIPMENU2.menuPartArray[1] = bctext + '\'s Tip Menu 2 Part 2:'; TIPMENU2.menuPartArray[2] = bctext + '\'s Tip Menu 2 Part 3:'; if (sorted2.length <= 16) { menuNumberChunks = 2; menuChunkLength = Math.ceil(sorted2.length / menuNumberChunks); } else if (sorted2.length <= 25) { menuNumberChunks = 3; menuChunkLength = Math.ceil(sorted2.length / menuNumberChunks); } currentChunk = 1; currentChunkItem = 1; } } for (let sortmenuidx = 0; sortmenuidx < sorted2.length; sortmenuidx++) { if (TIPMENU2.tipMenuPrice[sorted2[sortmenuidx].id] !== 0) { TIPMENU2.tipMenu += '\n' + TIPMENU2.sepChar + ' ' + TIPMENU2.tipMenuPrice[sorted2[sortmenuidx].id] + ' - ' + TIPMENU2.tipMenuItem[sorted2[sortmenuidx].id] if (cb.settings.tipMenuNoticeType == 'Split Menu - List Form' && menu2ListSplit) { TIPMENU2.menuPartArray[currentChunk-1] += '\n' + TIPMENU2.sepChar + ' ' + TIPMENU2.tipMenuPrice[sorted2[sortmenuidx].id] + ' - ' + TIPMENU2.tipMenuItem[sorted2[sortmenuidx].id]; currentChunkItem++; if (currentChunkItem > menuChunkLength) { TIPMENU2.menuPartArray[currentChunk-1] += '\nThe menu has been split. To see the full menu type: /tipmenu'; currentChunk ++; currentChunkItem = 1; } } } } } else { for (let sortmenuidx2 = 0; sortmenuidx2 < sorted2.length; sortmenuidx2++) { if (TIPMENU2.tipMenuPrice[sorted2[sortmenuidx2].id] !== 0) { menu2Array.push(TIPMENU2.tipMenuItem[sorted2[sortmenuidx2].id] + ' (' + TIPMENU2.tipMenuPrice[sorted2[sortmenuidx2].id] + ') '); } } TIPMENU2.tipMenu += '\n' + menu2Array.join(TIPMENU2.sepChar); if (cb.settings.tipMenuNoticeType == 'Split Menu - Paragraph Form') { if (menu2Array.length < 10) { cb.sendNotice('Tip Menu 2 - Error - The menu has less than 10 items, it will not be split.', cb.room_slug, '#FFFFFF', '#FF0000', 'bold'); } else { TIPMENU2.menuPartArray[0] = bctext + '\'s Tip Menu Part 1:'; TIPMENU2.menuPartArray[1] = bctext + '\'s Tip Menu Part 2:'; let msglength1 = 0; let msgHalf = (TIPMENU2.tipMenu.length - 9) / 2; for (let sortmenuidx3 = 0; sortmenuidx3 < sorted2.length; sortmenuidx3++) { if (TIPMENU2.tipMenuPrice[sorted2[sortmenuidx3].id] !== 0) { if (msglength1 < msgHalf) { menu2Array1.push(TIPMENU2.tipMenuItem[sorted2[sortmenuidx3].id] + ' (' + TIPMENU2.tipMenuPrice[sorted2[sortmenuidx3].id] + ') '); msglength1 = menu2Array1.join(TIPMENU2.sepChar).length; } else { menu2Array2.push(TIPMENU2.tipMenuItem[sorted2[sortmenuidx3].id] + ' (' + TIPMENU2.tipMenuPrice[sorted2[sortmenuidx3].id] + ') '); } } } TIPMENU2.menuPartArray[0] += '\n' + menu2Array1.join(TIPMENU2.sepChar) + '\n To see the full menu, type: /tipmenu.'; TIPMENU2.menuPartArray[1] += '\n' + menu2Array2.join(TIPMENU2.sepChar) + '\n To see the full menu, type: /tipmenu.'; } } } TIPMENU2.menuLength = TIPMENU2.tipMenuPrice.length; if (TIPMENU2.menuLength <= 0) { cb.sendNotice('Error - No menu items found', '', '', TIPMENU2.txtColor1, 'bold'); } } function displayMenu() { if (tipMenuToggle == 1) { if (minMessagesForNotice > 0 && msgCounterTipMenu < minMessagesForNotice) { cb.setTimeout(displayMenu, 30000); } else { msgCounterTipMenu = 0; if (cb.settings.tipMenuNoticeType == 'Notice only') { cb.sendNotice(bctext + '\'s Tip Menu is active, but is not automatically posted to the chat.\n To see the full tip menu, type: /tipmenu', '', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); if (cb.settings.tipMenuSalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenuSalePct + '% off normal prices!', '', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } cb.setTimeout(checkUserGroupMenuNotice, 500); } else if (TIPMENU.menuLength > 0 && cb.settings.tipMenuNoticeType == 'Split Menu - Paragraph Form') { if (TIPMENU.menuToken == 1) { cb.sendNotice(TIPMENU.menuPartArray[0],'', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); if (cb.settings.tipMenuSalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenuSalePct + '% off normal prices!', '', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } TIPMENU.menuToken = 2; cb.setTimeout(checkUserGroupMenuNotice, 500); } else if (TIPMENU.menuToken == 2) { cb.sendNotice(TIPMENU.menuPartArray[1],'', TIPMENU.bgColor2, TIPMENU.txtColor2, 'bold'); if (cb.settings.tipMenuSalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenuSalePct + '% off normal prices!', '', TIPMENU.bgColor2, TIPMENU.txtColor2, 'bold'); } TIPMENU.menuToken = 1; cb.setTimeout(checkUserGroupMenuNotice, 500); } } else if (TIPMENU.menuLength > 0 && cb.settings.tipMenuNoticeType == 'Split Menu - List Form' && menuListSplit) { if (TIPMENU.menuToken == 1) { cb.sendNotice(TIPMENU.menuPartArray[0],'', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); if (cb.settings.tipMenuSalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenuSalePct + '% off normal prices!', '', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } TIPMENU.menuToken = 2; cb.setTimeout(checkUserGroupMenuNotice, 500); } else if (TIPMENU.menuToken == 2) { cb.sendNotice(TIPMENU.menuPartArray[1],'', TIPMENU.bgColor2, TIPMENU.txtColor2, 'bold'); if (cb.settings.tipMenuSalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenuSalePct + '% off normal prices!', '', TIPMENU.bgColor2, TIPMENU.txtColor2, 'bold'); } if (TIPMENU.menuLength > 16) { TIPMENU.menuToken = 3; } else { TIPMENU.menuToken = 1; } cb.setTimeout(checkUserGroupMenuNotice, 500); } else if (TIPMENU.menuToken == 3) { cb.sendNotice(TIPMENU.menuPartArray[2],'', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); if (cb.settings.tipMenuSalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenuSalePct + '% off normal prices!', '', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } if (TIPMENU.menuLength > 24) { TIPMENU.menuToken = 4; } else { TIPMENU.menuToken = 1; } cb.setTimeout(checkUserGroupMenuNotice, 500); } else if (TIPMENU.menuToken == 4) { cb.sendNotice(TIPMENU.menuPartArray[3],'', TIPMENU.bgColor2, TIPMENU.txtColor2, 'bold'); if (cb.settings.tipMenuSalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenuSalePct + '% off normal prices!', '', TIPMENU.bgColor2, TIPMENU.txtColor2, 'bold'); } if (TIPMENU.menuLength > 32) { TIPMENU.menuToken = 5; } else { TIPMENU.menuToken = 1; } cb.setTimeout(checkUserGroupMenuNotice, 500); } else if (TIPMENU.menuToken == 5) { cb.sendNotice(TIPMENU.menuPartArray[4],'', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); if (cb.settings.tipMenuSalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenuSalePct + '% off normal prices!', '', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } TIPMENU.menuToken = 1; cb.setTimeout(checkUserGroupMenuNotice, 500); } } else if (TIPMENU.menuLength > 0) { cb.sendNotice(TIPMENU.tipMenu,'', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); if (cb.settings.tipMenuSalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenuSalePct + '% off normal prices!', '', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } cb.setTimeout(checkUserGroupMenuNotice, 500); } else { cb.sendNotice('Tip Menu setup error - there are no entries in the menu.', '', '#FFFFFF', '#FF0000', 'bold'); } cb.setTimeout(displayMenu, TIPMENU.menuDspIntTime); } } } function checkUserGroupMenuNotice() { messageReceiptArray = []; if (TIPMENUMOD.tipMenuItem.length > 0) { for (let menuidx = 0; menuidx < moderatorList.name.length; menuidx++) { sendtomod = moderatorList.name[menuidx].trim(); if (sendtomod != cb.room_slug) { cb.sendNotice(sendtomod + ', as a Moderator, you get a discount off the general tip menu! \nTo see the Moderator specific discounted prices, type /tipmenu', sendtomod, appWarningColor, '', 'bold'); } messageReceiptArray.push(sendtomod); } } if (TIPMENUCBFC.tipMenuItem.length > 0) { for (let menuidx = 0; menuidx < fanClubList.length; menuidx++) { sendtocbfan = fanClubList[menuidx].trim(); if (!cbjs.arrayContains(messageReceiptArray,sendtocbfan)) { if (cb.settings.tipMenuCBFCSalePct > 0 && cbfcSpecificMenuItems) { cb.sendNotice(sendtocbfan + ', as a Fan Club Member, you get a discount off the general tip menu AND access to special menu items! \nTo see the Fan Club specific Tip Menu and discounted prices, type /tipmenu', sendtocbfan, appWarningColor, '', 'bold'); } else if (cb.settings.tipMenuCBFCSalePct > 0) { cb.sendNotice(sendtocbfan + ', as a Fan Club Member, you get a discount off the general tip menu! \nTo see the Fan Club specific discounted prices, type /tipmenu', sendtocbfan, appWarningColor, '', 'bold'); } else if (cbfcSpecificMenuItems) { cb.sendNotice(sendtocbfan + ', as a Fan Club Member, you have access to special menu items in addition to the general menu! \nTo see the Fan Club specific Tip Menu, type /tipmenu', sendtocbfan, appWarningColor, '', 'bold'); } messageReceiptArray.push(sendtocbfan); } } } if (TIPMENUEFC1.tipMenuItem.length > 0) { for (let menuidx = 0; menuidx < extFanInShowArray.length; menuidx++) { sendtoextfan1 = extFanInShowArray[menuidx].trim(); if (!cbjs.arrayContains(messageReceiptArray,sendtoextfan1)) { if (cb.settings.tipMenuEFC1SalePct > 0 && efc1SpecificMenuItems) { cb.sendNotice(sendtoextfan1 + ', as a member of ' + EFCname + ', you get a discount off the general tip menu AND access to special menu items! \nTo see your Tip Menu and discounted prices, type /tipmenu', sendtoextfan1, appWarningColor, '', 'bold'); } else if (cb.settings.tipMenuEFC1SalePct > 0) { cb.sendNotice(sendtoextfan1 + ', as a member of ' + EFCname + ', you get a discount off the general tip menu! \nTo see the your discounted prices, type /tipmenu', sendtoextfan1, appWarningColor, '', 'bold'); } else if (efc1SpecificMenuItems) { cb.sendNotice(sendtoextfan1 + ', as a member of ' + EFCname + ', you have access to special menu items in addition to the general menu! \nTo see your Tip Menu, type /tipmenu', sendtoextfan1, appWarningColor, '', 'bold'); } messageReceiptArray.push(sendtoextfan1); } } } if (TIPMENUEFC2.tipMenuItem.length > 0) { for (let menuidx = 0; menuidx < extFanInShow2Array.length; menuidx++) { sendtoextfan2 = extFanInShow2Array[menuidx].trim(); if (!cbjs.arrayContains(messageReceiptArray,sendtoextfan2)) { if (cb.settings.tipMenuEFC2SalePct > 0 && efc2SpecificMenuItems) { cb.sendNotice(sendtoextfan2 + ', as a member of ' + EFCname2 + ', you get a discount off the general tip menu AND access to special menu items! \nTo see your Tip Menu and discounted prices, type /tipmenu', sendtoextfan2, appWarningColor, '', 'bold'); } else if (cb.settings.tipMenuEFC2SalePct > 0) { cb.sendNotice(sendtoextfan2 + ', as a member of ' + EFCname2 + ', you get a discount off the general tip menu! \nTo see the your discounted prices, type /tipmenu', sendtoextfan2, appWarningColor, '', 'bold'); } else if (efc2SpecificMenuItems) { cb.sendNotice(sendtoextfan2 + ', as a member of ' + EFCname2 + ', you have access to special menu items in addition to the general menu! \nTo see your Tip Menu, type /tipmenu', sendtoextfan2, appWarningColor, '', 'bold'); } messageReceiptArray.push(sendtoextfan2); } } } if (TIPMENUVIP.tipMenuItem.length > 0) { for (let menuidx = 0; menuidx < VIPInShowArray.length; menuidx++) { sendtovip = VIPInShowArray[menuidx].trim(); if (!cbjs.arrayContains(messageReceiptArray,sendtovip)) { cb.sendNotice(sendtovip + ', as a VIP you get a discount off the general tip menu! \nTo see the VIP specific discounted prices, type /tipmenu', sendtovip, appWarningColor, '', 'bold'); } } } } function displayMenu2() { if (tipMenu2Toggle == 1) { if (minMessagesForNotice > 0 && msgCounterTipMenu < minMessagesForNotice) { cb.setTimeout(displayMenu2, 30000); } else { msgCounterTipMenu = 0; if (cb.settings.tipMenuNoticeType == 'Notice only') { cb.sendNotice(bctext + '\'s Tip Menu is active, but is not automatically posted to the chat.\n To see the full tip menu type: /tipmenu', '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); if (cb.settings.tipMenu2SalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenu2SalePct + '% off normal prices!', '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); } } else if (TIPMENU2.menuLength > 0 && cb.settings.tipMenuNoticeType == 'Split Menu - Paragraph Form') { if (TIPMENU2.menuToken == 1) { cb.sendNotice(TIPMENU2.menuPart1, '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); if (cb.settings.tipMenu2SalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenu2SalePct + '% off normal prices!', '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); } TIPMENU2.menuToken = 2; } else if (TIPMENU2.menuToken == 2) { cb.sendNotice(TIPMENU2.menuPart2, '', TIPMENU2.bgColor2, TIPMENU2.txtColor2, 'bold'); if (cb.settings.tipMenu2SalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenu2SalePct + '% off normal prices!', '', TIPMENU2.bgColor2, TIPMENU2.txtColor2, 'bold'); } TIPMENU2.menuToken = 1; } } else if (TIPMENU2.menuLength > 0 && cb.settings.tipMenuNoticeType == 'Split Menu - List Form' && menu2ListSplit) { if (TIPMENU2.menuToken == 1) { cb.sendNotice(TIPMENU2.menuPartArray[0],'', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); if (cb.settings.tipMenu2SalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenu2SalePct + '% off normal prices!', '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); } TIPMENU2.menuToken = 2; } else if (TIPMENU2.menuToken == 2) { cb.sendNotice(TIPMENU2.menuPartArray[1],'', TIPMENU2.bgColor2, TIPMENU2.txtColor2, 'bold'); if (cb.settings.tipMenu2SalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenu2SalePct + '% off normal prices!', '', TIPMENU2.bgColor2, TIPMENU2.txtColor2, 'bold'); } if (TIPMENU2.menuLength > 16) { TIPMENU2.menuToken = 3; } else { TIPMENU2.menuToken = 1; } } else if (TIPMENU2.menuToken == 3) { cb.sendNotice(TIPMENU2.menuPartArray[2],'', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); if (cb.settings.tipMenu2SalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenu2SalePct + '% off normal prices!', '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); } TIPMENU2.menuToken = 1; } } else if (TIPMENU2.menuLength > 0) { cb.sendNotice(TIPMENU2.tipMenu,'', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); if (cb.settings.tipMenu2SalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! \nTip Menu prices have been discounted ' + cb.settings.tipMenu2SalePct + '% off normal prices!', '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); } } else { cb.sendNotice('Tip Menu #2 setup error - there are no entries in the menu.', '', '#FFFFFF', '#FF0000', 'bold'); } cb.setTimeout(displayMenu2, TIPMENU2.menuDspIntTime); } } } function displayMenuTimer2() { if (isNaN(parseFloat(cb.settings.menuDspInt))) { cb.sendNotice('Fembot: Tip Menu 2 notice interval is not set with a valid number so the Tip Menu notice is not enabled.', cb.room_slug, appWarningColor); tipmenu2timer = 0; } else { tipmenu2timer = parseFloat(cb.settings.menuDspInt); } if (tipmenu2timer != 0) { if (tipmenu2timer < 1) { cb.sendNotice('Fembot: Tip Menu 2 notice interval is too short. Using default value of 2.9 minutes.', cb.room_slug, '#FFFFFF', '#FF0000', 'bold'); tipmenu2timer = 2.9; } tipmenu2timer = parseInt(tipmenu2timer * 60000); TIPMENU2.menuDspIntTime = tipmenu2timer; } } 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 += ' '; TIPMENUMOD.sepChar = TIPMENU.sepChar; TIPMENUCBFC.sepChar = TIPMENU.sepChar; TIPMENUEFC1.sepChar = TIPMENU.sepChar; TIPMENUEFC2.sepChar = TIPMENU.sepChar; TIPMENUVIP.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,appNoticeColor); } else { posTipMenuToggle = 1; initPosMenu(); cb.sendNotice(' ' + mod + ' has enabled the Positions Tip Menu. \nYou control the action by tipping for your favorite position!\nTo display the positions menu, type: /posmenu','',POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor,'bold'); } } else if(option == 'off') { if(posTipMenuToggle == 0) { cb.sendNotice('The Positions Tip Menu is already disabled.',mod,appNoticeColor); } else { posTipMenuToggle = 0; POSTIPMENU.posTipMenuPrice = []; POSTIPMENU.posTipMenuItem = []; cb.sendNotice(' ' + mod + ' has disabled the Positions Tip Menu. \nYou can no longer tip for positions.','',POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor,'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,appNoticeColor); } 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,appNoticeColor); } } function initPosMenu(mod) { let maxItems = 8; if (cb.settings.posMenuTxtColor === "Custom") { POSTIPMENU.posTxtColor = checkTextColor(cb.settings.posMenuCustTxtColor,true); 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,true); } if (cb.settings.posMenuBgColor === "Custom") { POSTIPMENU.posBgColor = checkBgColor(cb.settings.posMenuCustBgColor,true); 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,true); } displayPosMenuTimer(); setPosSepChar(); for (let j = 0; j <= maxItems; j++) { if (cb.settings['posMenuItem' + j] !== '' && cb.settings['posMenuItemPrice' + j] > 0) { 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); } } buildPosMenu(); cb.setTimeout(displayPosMenu, POSTIPMENU.posMenuDspIntTime); } function displayPosMenuTimer() { if (isNaN(parseFloat(cb.settings.posMenuInterval))) { cb.sendNotice('Fembot: Positions Menu notice interval is not set with a valid number so the Positions Menu notice is not enabled.', cb.room_slug, appWarningColor); posmenutimer = 0; } else { posmenutimer = parseFloat(cb.settings.posMenuInterval); } if (posmenutimer != 0) { if (posmenutimer < 1) { cb.sendNotice('Fembot: Positions Menu notice interval is too short. Using default value of 1.9 minutes.', cb.room_slug, appWarningColor); posmenutimer = 1.9; } posmenutimer = parseInt(posmenutimer * 60000); POSTIPMENU.posMenuDspIntTime = posmenutimer; } } function buildPosMenu() { POSTIPMENU.posTipMenu = bctext + '\'s Positions Tip Menu: \n'; 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.posMenuLength <= 0) { cb.sendNotice('Error - No positions menu items found', '', '', POSTIPMENU.posTxtColor, "bold"); } } function displayPosMenu() { if(posTipMenuToggle == 1) { if (minMessagesForNotice > 0 && msgCounterPosMenu < minMessagesForNotice) { cb.setTimeout(displayPosMenu, 30000); } else { msgCounterPosMenu = 0; if (cb.settings.posChatNotice === 'Only display the short notice') { 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') { if (minTimeForNotice > 0) { // checkNoticeFrequency(POSTIPMENU.posTipMenu, '', POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor, 'bold', ''); } else { cb.sendNotice(POSTIPMENU.posTipMenu, '', POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor, 'bold'); } } else if (POSTIPMENU.posTipMenu !== 'Positions Tip Menu: ') { if (minTimeForNotice > 0) { // checkNoticeFrequency(POSTIPMENU.posTipMenu, '', POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor, 'bold', ''); } else { cb.sendNotice(POSTIPMENU.posTipMenu, '', POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor, 'bold'); } } else { cb.sendNotice("Something went wrong with the positions menu.", '', "#FFFFFF", "#FF0000", "bold"); } cb.setTimeout(displayPosMenu, POSTIPMENU.posMenuDspIntTime); } } } 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,appNoticeColor); } else { lushMenuToggle = 1; initLushMenu(); cb.sendNotice(' ' + mod + ' has enabled the ' + whichToy + ' Menu. Use the tip ranges on the menu to make the toy vibrate!','',LUSHMENU.lushBgColor, LUSHMENU.lushTxtColor,'bold'); } } else if(option == 'off') { if(lushMenuToggle == 0) { cb.sendNotice('The ' + whichToy + ' Menu is already disabled.',mod,appNoticeColor); } else { lushMenuToggle = 0; LUSHMENU.lushMenuLevel = []; cb.sendNotice(' ' + mod + ' has disabled the ' + whichToy + ' Menu.','',LUSHMENU.lushBgColor, LUSHMENU.lushTxtColor,'bold'); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usetoy.',mod,appNoticeColor); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usetoy.',mod,appNoticeColor); } } function initLushMenu() { if (cb.settings.lushMenuTxtColor === 'Custom') { LUSHMENU.lushTxtColor = checkTextColor(cb.settings.lushMenuCustTxtColor,true); 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,true); } if (cb.settings.lushMenuBgColor === 'Custom') { LUSHMENU.lushBgColor = checkBgColor(cb.settings.lushMenuCustBgColor,true); 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,true); } displayLushMenuTimer(); setLushMenu(); cb.setTimeout(displayLushMenu, LUSHMENU.lushMenuDspIntTime); } 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]); } } LUSHMENU.lushMenu = '-------- ' + whichToyIcon + ' \u2665 ' + whichToyIcon + ' \u2665 ' + whichToyIcon + ' \u2665 ' + bctext + '\'s "' + whichToy + '" Toy Menu \u2665 ' + whichToyIcon + ' \u2665 ' + whichToyIcon + ' \u2665 ' + whichToyIcon + ' --------'; LUSHMENU.lushMenu += LUSHMENU.lushMenuLevel.join('\n'); } function displayLushMenu() { if (lushMenuToggle == 1) { if (minMessagesForNotice > 0 && msgCounterLushMenu < minMessagesForNotice) { cb.setTimeout(displayLushMenu, 30000); } else { msgCounterLushMenu = 0; if (minTimeForNotice > 0) { // checkNoticeFrequency(LUSHMENU.lushMenu, '', LUSHMENU.lushBgColor, LUSHMENU.lushTxtColor, 'bold', ''); } else { cb.sendNotice(LUSHMENU.lushMenu, '', LUSHMENU.lushBgColor, LUSHMENU.lushTxtColor, 'bold'); } cb.setTimeout(displayLushMenu, LUSHMENU.lushMenuDspIntTime); } } } function displayLushMenuTimer() { if (isNaN(parseFloat(cb.settings.lushMenuInterval))) { cb.sendNotice('Fembot: Toy Menu notice interval is not set with a valid number so the notice is not enabled.', cb.room_slug, appWarningColor); lushtimer = 0; } else { lushtimer = parseFloat(cb.settings.lushMenuInterval); } if (lushtimer != 0) { if (lushtimer < 1) { cb.sendNotice('Fembot: Toy Menu notice interval is less than 1 minute. Using default value of 2.2 minutes.', cb.room_slug, '#FFFFFF', '#FF0000', 'bold'); lushtimer = 2.2; } lushtimer = parseInt(lushtimer * 60000); LUSHMENU.lushMenuDspIntTime = lushtimer; } } // *************************** Token Poll Functions ************************ function setTokenPollToggle(mode, calledby) { setPollColors(); if (mode == 'on') { if(tokenPollToggle == 1) { cb.sendNotice('The Token Poll is already enabled.', calledby, appNoticeColor); } else { tokenPollToggle = 1; initTokenPoll(calledby); cb.sendNotice(calledby + ' has enabled the Token Poll feature, you can now vote in the poll. \nTo see the current voting options and totals, type: /poll', '', tokenPollBgColor, tokenPollTextColor, 'bold'); } } else if (mode == 'off') { if(tokenPollToggle == 0) { cb.sendNotice('The Token Poll is already disabled.', calledby, appNoticeColor); } else { for (let i = 0; i < pollArrayAmount.length; i++) { priceChecker('rmv','Poll Option: '+pollArrayLabel[i],pollArrayAmount[i],calledby); } tokenPollToggle = 0; cb.sendNotice(calledby + ' has disabled the Token Poll feature, voting will no longer be tracked.', '', tokenPollBgColor, tokenPollTextColor, 'bold'); pollRunning = false; } } else if (mode != null) { cb.sendNotice(mode + ' is not a valid option for /usepoll, valid values are "on" or "off".', calledby, appNoticeColor); } else if (mode == null) { cb.sendNotice('You did not enter a valid option for /usepoll, valid values are "on" or "off".', calledby, appNoticeColor); } } function initTokenPoll(calledby) { 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', calledby, appNoticeColor); } pollRunning = true; pollTimerStopping = false; nline = 0; buildPollBoard(calledby); initPollBoardTimer(); cb.setTimeout(showBoard, 30000); initPollTimer(); cb.setTimeout(displayPoll, 60000); totalPollVotes = 0; } function initPollBoardTimer() { if (isNaN(parseFloat(cb.settings.pollInterval))) { pollNoticeInt = 1.5; cb.sendNotice('Fembot: Token Poll Board notice interval is not set with a valid number so the Token Poll Board interval is set to the default of 1.5 minutes.', cb.room_slug, appWarningColor); } else { pollNoticeInt = parseFloat(cb.settings.pollInterval); } if (pollNoticeInt <= 0) { pollNoticeInt = 1.5; cb.sendNotice('Fembot: Token Poll Board notice interval is not set with a valid number so the Token Poll Board interval is set to the default of 1.5 minutes.', cb.room_slug, appWarningColor); } else if (pollNoticeInt < 1) { pollNoticeInt = 1.5; cb.sendNotice('Fembot: Token Poll Board notice interval is too short, must be at least 1 minute. Using default setting of 1.5 minutes.', cb.room_slug, appWarningColor); } pollNoticeInt = parseInt(pollNoticeInt * 60000); } function setPollColors() { if (cb.settings.pollTxtColor == 'Custom') { tokenPollTextColor = checkTextColor(cb.settings.pollCustTxtColor,true); if (tokenPollTextColor === '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'); tokenPollTextColor = '#FFFFFF'; } } else { tokenPollTextColor = checkTextColor(cb.settings.pollTxtColor,true); } if (cb.settings.pollBgColor == 'Custom') { tokenPollBgColor = checkBgColor(cb.settings.pollCustBgColor,true); if (tokenPollBgColor === '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'); tokenPollBgColor = '#0629AC'; } } else { tokenPollBgColor = checkBgColor(cb.settings.pollBgColor,true); } } function buildPollBoard(calledby) { for (let i = 1; i <= 8; i++) { var oktoadd = 1; if (this['pollOptTokens'+i] != '' && this['pollOptTokens'+i] != null && this['pollOptTokens'+i] > 0) { if (this['pollOptLabel'+i] != '' && this['pollOptLabel'+i] != null) { for (let j = 0; j < i-1; j++) { if (pollArrayAmount[j] === this['pollOptTokens'+i]) { cb.sendNotice('Tip Price Amount for option ' + i + ' is not unique, it is not added to the board.', calledby, appNoticeColor); oktoadd = 0; break; } else if (pollArrayLabel[j] === this['pollOptLabel'+i]) { cb.sendNotice('Label for option ' + i + ' is not unique, it is not added to the board.', calledby, appNoticeColor); oktoadd = 0; break; } } if(oktoadd == 1) { populatePollArray(this['pollOptLabel'+i],this['pollOptTokens'+i],0,calledby); priceChecker('add','Poll Option: '+this['pollOptLabel'+i], this['pollOptTokens'+i],calledby); } } else { cb.sendNotice('Label for option ' + i + ' is blank or null, not added to board.', calledby, appNoticeColor); } } } } function displayPoll() { if (tokenPollToggle == 1 && pollRunning) { if (minMessagesForNotice > 0 && msgCounterTokenPoll < minMessagesForNotice) { cb.setTimeout(displayPoll, 30000); } else { msgCounterTokenPoll = 0; let pollNotice = ['A poll is currently running. \nTo see the current voting options and totals, type: /poll']; if (fanDouble) { pollNotice.push('Fan club members currently get two votes for the price of one!'); } pollNotice.push(showLead()); cb.sendNotice(pollNotice[nline], '', tokenPollBgColor, tokenPollTextColor, 'bold'); nline += 1; if (nline >= pollNotice.length) { nline = 0; } cb.setTimeout(displayPoll, 90000); } } } function populatePollArray(label, amount, votes, calledby) { if (!cbjs.arrayContains(pollArrayAmount, amount) && !cbjs.arrayContains(pollArrayLabel, label)) { var pollindex = pollArrayAmount.length; pollArrayLabel[pollindex] = label; pollArrayAmount[pollindex] = amount; pollArrayVotes[pollindex] = votes; } else { cb.sendNotice('Tip Price Amount or Label for option ' + label + ' is not unique, it is not added to the board.', calledby, appNoticeColor); return; } } function showBoard(reqby) { if (reqby === undefined) { reqby = 'timer'; } if (tokenPollToggle == 1) { var pollboard1 = ''; var pollboard2 = ''; if (reqby == 'bc' || reqby == 'timer' ) { pollboard1 += 'Sent to ALL:\n'; } else { pollboard1 += 'Sent to you:\n'; } if (pollRunning) { pollboard1 += noticeBorder('top','long','TOKEN POLL'); } else { pollboard1 += noticeBorder('top','long','POLL RESULTS'); } pollboard1 += '\n \u2753 \u2754 \u2753 \u2754 \u2753 ' + pollTitle + ' \u2753 \u2754 \u2753 \u2754 \u2753'; 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]) { pollboard1 += '\n \u23E9 ' + pollArrayLabel[ids[j].id] + ' (Price = ' + pollArrayAmount[ids[j].id] + ' tokens): ' + pollArrayVotes[ids[j].id] + ' vote' + (pollArrayVotes[ids[j].id] != 1 ? 's' : ''); } } if (stealPollAmount > 0) { pollboard1 += '\n *** ' + bctext + ' has enabled hijacking of the poll. \nIf a user tips ' + stealPollAmount + ' tokens in a single tip, they will "hijack" the poll \n and be able to choose the poll winner regardless of current voting.'; } if (pollRunning) { switch (pollType) { case 'Timer': break; case 'Vote': pollboard2 += votesRemain + ' vote' + (votesRemain == 1 ? '' : 's') + ' remaining before poll closes\n'; break; case 'Goal': pollboard2 += 'First option to ' + cb.settings.pollCount + ' votes wins!\n'; break; } pollboard2 += 'Simply tip the shown token amounts to vote for your choice. \nTo see the current voting options and totals, type: /poll.'; if (pollMinimum > 1) { if (totalPollVotes >= pollMinimum) { pollboard2 += '\nThe minimum total number of votes has been met! The poll result is valid.'; } else { votesNeeded = pollMinimum - totalPollVotes; pollboard2 += '\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 { pollboard2 += 'The poll has been closed, no more voting!'; } sendto = reqby; if (reqby == 'timer') { sendto = ''; if (pollRunning) { cb.setTimeout(showBoard, pollNoticeInt); } } else if (reqby == 'bc') { sendto = ''; } pollboard1 += noticeBorder('bottom','long',''); cb.sendNotice(pollboard1, sendto, tokenPollBgColor, tokenPollTextColor, 'bold'); cb.sendNotice(pollboard2, sendto, tokenPollBgColor, tokenPollTextColor, '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], '', tokenPollBgColor, tokenPollTextColor, 'bold'); } else { cb.sendNotice(tippedby + ' voted ' + voteAmount + ' time' + (voteAmount == 1 ? '' : 's') + ' for ' + pollArrayLabel[i], '', tokenPollBgColor, tokenPollTextColor, '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(), '', tokenPollBgColor, tokenPollTextColor, 'bold'); if (!aliveWarned) { aliveWarning(); } } if (pollType != 'Timer') { checkPollEnd(); } } } } function stealPoll(tippedby) { if (tokenPollToggle == 1) { cb.sendNotice(' :siren1 ' + tippedby + ' has HIJACKED the poll and will get to choose the winner! :siren1 \nVoting is ended, and no more votes will be counted.', '', tokenPollBgColor, tokenPollTextColor, 'bold'); if (pollRunning) { pollRunning = false; } } } function aliveWarning() { if (!pollRunning || pollType != 'Timer') { return; } cb.sendNotice('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.', cb.room_slug, appNoticeColor); cb.sendNotice('Since ' + bctext + ' 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.', '', appNoticeColor,'','','red'); 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(showwinneruser) { 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 pollwinner1 = '\u23f0 \u23f0 \u23f0 Token Poll has ended! \u23f0 \u23f0 \u23f0 \n'; let pollwinner2 = 'Winner' + (win_count > 1 ? 's (' + win_count + '-way tie)' : '') + ':'; for (let k = 0; k < win_count; k++) { if (pollArrayAmount[options[k]] != 0) { pollwinner2 += '\n \u23E9 ' + pollArrayLabel[options[k]] + ': ' + pollArrayVotes[options[k]] + ' votes'; } } cb.sendNotice(pollwinner1 + pollwinner2, showwinneruser, tokenPollBgColor, tokenPollTextColor, '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 polllead; let leadCount = leadOpt.length; if (leadCount === 0){ polllead = 'Token Poll: No votes yet, be sure to vote for your favorite! \nTo see the current voting options and totals, type: /poll'; } else if (leadCount === 1) { polllead = 'Token Poll: ' +pollArrayLabel[options[0]] + ' is in the lead by ' + (pollArrayVotes[options[0]] - pollArrayVotes[options[1]]) + ' vote' + ((pollArrayVotes[options[0]] - pollArrayVotes[options[1]]) === 1 ? '' : 's') + '.'; } else { polllead = 'Token Poll: We have a ' + leadCount + '-way tie between ' + formatArray(leadOpt,'and') + '.'; } return polllead; } 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(polltimetoadd, u) { pollStopTime = new Date(pollStopTime.getTime() + polltimetoadd * 60000); timetoaddabs = Math.abs(polltimetoadd); if (polltimetoadd > 0) { cb.sendNotice(polltimetoadd + ' minute' + (polltimetoadd == 1 || polltimetoadd == -1 ? ' has' : 's have') + ' been added to the timer. Now ' + pollTimeLeft(), '', tokenPollBgColor, tokenPollTextColor, 'bold'); } else { cb.sendNotice(timetoaddabs + ' minute' + (timetoaddabs == 1 || timetoaddabs == -1 ? ' has' : 's have') + ' been subtracted from the timer. Now ' + pollTimeLeft(), '', tokenPollBgColor, tokenPollTextColor, 'bold'); } pollMinsRemain = pollMinsRemain + polltimetoadd; if (pollMinsRemain > 0) { pollDisplaySeconds = false; } else { pollDisplaySeconds = true; } } function pollSwitchToTimer(timetoadd, u) { pollType = 'Timer'; pollStartTime = new Date(); pollStopTime = new Date(pollStartTime.getTime() + timetoadd * 60000); cb.sendNotice('A token poll timer has been set for ' + timetoadd + ' minute' + (timetoadd === 1 || timetoadd === -1 ? '' : 's'), '', tokenPollBgColor, tokenPollTextColor, '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', '', tokenPollBgColor, tokenPollTextColor, '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', '', appWarningColor, '', 'bold'); showWinner(''); pollRunning = false; } } else { pollSecsRemain--; cb.setTimeout(pollTimerSec, 1000); } } } function pollStopTimer() { pollStopTime = new Date(); pollMinsRemain = 0; pollSecsRemain = 0; pollTimerStopping = true; } // *************************** On-demand Poll Functions ************************ function createOnDemandPoll(startedby) { odtokenPollTextColor = checkTextColor('Dark Purple',true); odtokenPollBgColor = checkBgColor('Light Pink',true); onDemandPollEnabled = true; onDemandPollRunning = false; odpollTimerStopping = false; odpollArrayAmount = []; odpollArrayLabel = []; odpollArrayVotes = []; tempODPollLabels = []; tempODPollAmounts = []; nlineOD = 0; odpollType = 'Never'; cb.sendNotice('You have enabled the On-demand Token Poll. \nUp to 8 poll options can be added using the /makepoll command. \nYou can change the Poll Topic text in the header with the command /pollchgtitle.', startedby, appNoticeColor); cb.sendNotice(startedby + ' has enabled the On-demand Token Poll feature. \nOnce the Poll is completely built, it will be displayed and you will be able to vote in the poll.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); } function disableOnDemandPoll(endedby) { if (onDemandPollRunning) { if (endedby != 'hijack') { cb.sendNotice(endedby + ' has disabled the On-demand Token Poll feature. \nNo more voting will be counted.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); } for (let i = 0; i < odpollArrayAmount.length; i++) { priceChecker('rmv','On-demand Poll Option: '+odpollArrayLabel[i],odpollArrayAmount[i],endedby); } onDemandPollRunning = false; odpollArrayAmount = []; odpollArrayLabel = []; odpollArrayVotes = []; } else { for (let i = 0; i < tempODPollAmounts.length; i++) { priceChecker('rmv','On-demand Poll Option: '+tempODPollLabels[i],tempODPollAmounts[i],endedby); } } tempODPollLabels = []; tempODPollAmounts = []; onDemandPollEnabled = false; if (odpollMinsRemain >= 0 || odpollSecsRemain >= 0) { odpollStopTimer(); } if (endedby != 'hijack') { cb.sendNotice('You have disabled the On-demand Token Poll.', endedby, appNoticeColor); } } function addODTempOption(odlabel,odamount,addedby) { oktoadd = true; for (let i = 0; i <= tempODPollAmounts.length; i++) { if (odamount == tempODPollAmounts[i]) { cb.sendNotice('Option tip price amount for the new entry is not unique, it is not added to the poll board.',addedby, appNoticeColor); oktoadd = false; break; } else if (odlabel == tempODPollLabels[i]) { cb.sendNotice('Option name for the new entry is not unique, it is not added to the poll board.',addedby, appNoticeColor); oktoadd = false; break; } } if (oktoadd) { tempODPollAmounts.push(odamount); tempODPollLabels.push(odlabel); } } function startOnDemandPoll(startedby) { buildODPollBoard(startedby); onDemandPollRunning = true; initODPollBoardTimer(); initODPollTimer(); showODBoard('timer'); cb.setTimeout(displayODPollNotice, 30000); cb.sendNotice('You have started the On-demand Token Poll, voting can begin! \nYou can still add or remove options in the poll with the command /polloptadd or /polloptrmv.', startedby, appNoticeColor); cb.sendNotice(startedby + ' has started the On-demand Token Poll, you can now vote in the poll.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); } function initODPollBoardTimer() { if (isNaN(parseFloat(cb.settings.pollInterval))) { cb.sendNotice('Fembot: Token Poll Board notice interval is not set to a valid number so the On-demand Token Poll Board default is set to 1.5 minutes.', cb.room_slug, appWarningColor); ODpollNoticeInt = 1.5; } else { ODpollNoticeInt = parseFloat(cb.settings.pollInterval); } if (ODpollNoticeInt <= 0) { ODpollNoticeInt = 1.5; cb.sendNotice('Fembot: Token Poll Board notice interval is not set to a valid number so the On-demand Token Poll Board default is set to 1.5 minutes.', cb.room_slug, appWarningColor); } else if (ODpollNoticeInt < 1) { cb.sendNotice('Fembot: Token Poll Board notice interval is too short, must be at least 1 minute. Using default setting of 1.5 minutes.', cb.room_slug, appWarningColor); ODpollNoticeInt = 1.5; } ODpollNoticeInt = parseInt(ODpollNoticeInt * 60000); } function displayODPollNotice() { if (onDemandPollRunning) { if (minMessagesForNotice > 0 && msgCounterTokenPoll < minMessagesForNotice) { cb.setTimeout(displayODPollNotice, 30000); } else { msgCounterTokenPoll = 0; let odpollNotice = ['On-Demand Poll - a poll is currently running. \nTo see the current voting options and totals, type: /poll']; if (fanDouble) { odpollNotice.push('Fan club members currently get two votes for the price of one!'); } odpollNotice.push(odshowLead()); cb.sendNotice(odpollNotice[nlineOD], '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); nlineOD += 1; if (nlineOD >= odpollNotice.length) { nlineOD = 0; } cb.setTimeout(displayODPollNotice, ODpollNoticeInt); } } } function odshowLead() { let odoptions = []; let odleadOpt = []; for (let i = 0; i < odpollArrayAmount.length; i++) { odoptions[i] = i; } odoptions.sort(function(a, b) { return odpollArrayVotes[b] - odpollArrayVotes[a]; }); if (odpollArrayVotes[odoptions[0] ] > 0 ){ odleadOpt.push(odpollArrayLabel[odoptions[0]]); for (let j = 1; j < odpollArrayAmount.length; j++) { if (odpollArrayVotes[odoptions[j]] != odpollArrayVotes[odoptions[0]]) { break; } if (0 != odpollArrayAmount[odoptions[j]]) { odleadOpt.push(odpollArrayLabel[odoptions[j]]); } } } let odleadCount = odleadOpt.length; if (odleadCount == 0) { odpolllead = 'No votes yet, be sure to vote for your favorite! \nTo see the current voting options and totals, type: /poll'; } else if (odleadCount == 1) { odpolllead = odpollArrayLabel[odoptions[0]] + ' is in the lead by ' + (odpollArrayVotes[odoptions[0]] - odpollArrayVotes[odoptions[1]]) + ' vote' + ((odpollArrayVotes[odoptions[0]] - odpollArrayVotes[odoptions[1]]) === 1 ? '' : 's') + '.'; } else { odpolllead = 'We have a ' + odleadCount + '-way tie between ' + odformatArray(odleadOpt,'and') + '.'; } return odpolllead; } function buildODPollBoard(odboardstartedby) { for (let i = 0; i < tempODPollLabels.length; i++) { populateODPollArray(tempODPollLabels[i],tempODPollAmounts[i],0,odboardstartedby); } } function populateODPollArray(odlabel,odamount,odvotes,odstartby) { if (!cbjs.arrayContains(odpollArrayAmount,odamount) && !cbjs.arrayContains(odpollArrayLabel,odlabel)) { odpollArrayLabel.push(odlabel); odpollArrayAmount.push(odamount); odpollArrayVotes.push(odvotes); } else { cb.sendNotice('Option tip price or option name for combo (' + odlabel + ',' + odamount + ') is not unique, it is not added to the poll board.',odstartby, appNoticeColor); return; } } function showODBoard(odreqby) { if (odreqby === undefined) { odreqby = 'timer'; } var odpollboard1 = ''; var odpollboard2 = ''; if (odreqby == 'bc' || odreqby == 'timer' ) { odpollboard1 += 'Sent to ALL:\n'; } else { odpollboard1 += 'Sent to you:\n'; } if (onDemandPollRunning) { odpollboard1 += noticeBorder('top','long','ON-DEMAND POLL'); } else { odpollboard1 += noticeBorder('top','long','POLL RESULTS'); } odpollboard1 += '\n \u25c7 \u25c7 \u25c7 \u25c7 \u25c7 \u25c7 ' + odpollTitle + ' \u25c7 \u25c7 \u25c7 \u25c7 \u25c7 \u25c7'; let odSortedPollVotes = []; for (let i = 0; i < odpollArrayAmount.length; i++) { odSortedPollVotes.push({ 'odvotes': odpollArrayVotes[i], 'odid': i }); } odSortedPollVotes.sort(function(a, b) { return b.odvotes - a.odvotes; }); for (let j = 0; j < odSortedPollVotes.length; j++) { if (0 != odpollArrayAmount[odSortedPollVotes[j].odid]) { odpollboard1 += '\n \u23E9 ' + odpollArrayLabel[odSortedPollVotes[j].odid] + ' (Price = ' + odpollArrayAmount[odSortedPollVotes[j].odid] + ' tokens): ' + odpollArrayVotes[odSortedPollVotes[j].odid] + ' vote' + (odpollArrayVotes[odSortedPollVotes[j].odid] != 1 ? 's' : ''); } } if (stealPollAmount > 0) { odpollboard1 += '\n *** ' + bctext + ' has enabled hijacking of the poll. \nIf a user tips ' + stealPollAmount + ' tokens in a single tip, they will "hijack" the poll \nand be able to choose the poll winner regardless of current voting.'; } if (onDemandPollRunning) { odpollboard2 += 'Simply tip the shown token amounts to register your vote. \nTo see the current voting options and totals, type: /poll'; } else { odpollboard2 += 'The poll has been closed, no more voting!'; } odsendto = odreqby; if (odreqby == 'timer') { odsendto = ''; if (onDemandPollRunning) { cb.setTimeout(showODBoard, ODpollNoticeInt); } } else if (odreqby == 'bc') { odsendto = ''; } odpollboard1 += noticeBorder('bottom','long',''); cb.sendNotice(odpollboard1, odsendto, odtokenPollBgColor, odtokenPollTextColor, 'bold'); cb.sendNotice(odpollboard2, odsendto, odtokenPollBgColor, odtokenPollTextColor, 'bold'); } function odpollTip(tipAmount,voteAmount,tippedby) { pollindex = odpollArrayAmount.indexOf(tipAmount); odpollArrayVotes[pollindex] += voteAmount; votedfor = odpollArrayLabel[pollindex]; if (voteAmount == 1) { cb.sendNotice(tippedby + ' voted for ' + votedfor + '.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); } else { cb.sendNotice('Fanclub member ' + tippedby + ' voted twice for ' + votedfor + '.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); } } function odshowWinner(odshowwinneruser) { let odoptions = []; for (let i = 0; i < odpollArrayAmount.length; i++) { odoptions[i] = i; } odoptions.sort(function(a, b) { return odpollArrayVotes[b] - odpollArrayVotes[a]; }); let win_count = 1; for (let j = 1; j < odpollArrayAmount.length; j++) { if (odpollArrayVotes[odoptions[j]] != odpollArrayVotes[odoptions[0]]) { break; } if (0 != odpollArrayAmount[odoptions[j]]) { win_count++; } } let odpollwinner1 = '\u23f0 \u23f0 \u23f0 Token Poll has ended! \u23f0 \u23f0 \u23f0 \n'; let odpollwinner2 = 'Winner' + (win_count > 1 ? 's (' + win_count + '-way tie)' : '') + ':'; for (let k = 0; k < win_count; k++) { if (odpollArrayAmount[odoptions[k]] != 0) { odpollwinner2 += '\n \u23E9 ' + odpollArrayLabel[odoptions[k]] + ': ' + odpollArrayVotes[odoptions[k]] + ' votes'; } } cb.sendNotice(odpollwinner1 + odpollwinner2, odshowwinneruser, odtokenPollBgColor, odtokenPollTextColor, 'bold'); } function stealODPoll(tippedby) { if (onDemandPollRunning) { cb.sendNotice(' :siren1 ' + tippedby + ' has HIJACKED the poll and will get to choose the winner! :siren1 \nVoting is ended, and no more votes will be counted.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); disableOnDemandPoll('hijack'); } } function odformatArray(arr,andor){ let odoutStr = ''; if (arr.length === 1) { odoutStr = arr[0]; } else if (arr.length === 2) { odoutStr = arr.join(' '+andor+' '); } else if (arr.length > 2) { odoutStr = arr.slice(0, -1).join(', ') + ', '+andor+' ' + arr.slice(-1); } return odoutStr; } function odtimeCal() { odpollStartTime = new Date(); return odpollStopTime - odpollStartTime.getTime(); } function odpollTimeLeft() { var odpollTimeLeft = odtimeCal(); var milliseconds = odpollTimeLeft % 1000; var seconds = ((odpollTimeLeft - milliseconds) % 60000); var minutes = ((odpollTimeLeft - seconds - milliseconds) % 3600000); var hours = (odpollTimeLeft - 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 initODPollTimer() { odpollStartTime = new Date(); odpollStopTime = new Date(odpollStartTime.getTime() + cb.settings.pollCount * 60000); odpollTimerMin(); } function odpollAddTime(polltimetoadd, u) { odpollStopTime = new Date(odpollStopTime.getTime() + polltimetoadd * 60000); timetoaddabs = Math.abs(polltimetoadd); if (polltimetoadd > 0) { cb.sendNotice(polltimetoadd + ' minute' + (polltimetoadd == 1 || polltimetoadd == -1 ? ' has' : 's have') + ' been added to the timer. Now ' + odpollTimeLeft(), '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); } else { cb.sendNotice(timetoaddabs + ' minute' + (timetoaddabs == 1 || timetoaddabs == -1 ? ' has' : 's have') + ' been subtracted from the timer. Now ' + odpollTimeLeft(), '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); } odpollMinsRemain = odpollMinsRemain + polltimetoadd; if (odpollMinsRemain > 0) { odpollDisplaySeconds = false; } else { odpollDisplaySeconds = true; } } function odpollSwitchToTimer(timetoadd, u) { odpollType = 'Timer'; odpollStartTime = new Date(); odpollStopTime = new Date(odpollStartTime.getTime() + timetoadd * 60000); cb.sendNotice('A token poll timer has been set for ' + timetoadd + ' minute' + (timetoadd === 1 || timetoadd === -1 ? '' : 's'), '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); odpollMinsRemain = timetoadd; odpollTimerStopping = false; odpollTimerMin(); return; } function odpollTimerMin() { if(!odpollTimerStopping) { if (!onDemandPollRunning || odpollType !== 'Timer') { return; } switch (odpollMinsRemain) { 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 ' + odpollMinsRemain + ' minutes left to vote!!! \u231A \u231A \u231A', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); break; case 1: cb.sendNotice('\u231A \u231A \u231A There is 1 minute left to vote!!! \u231A \u231A \u231A', '', red, '', 'bold'); break; } odpollMinsRemain--; if (odpollMinsRemain > 0) { odpollDisplaySeconds = false; } else { odpollDisplaySeconds = true; } odpollSecsRemain = 60; odpollTimerSec(); } } function odpollTimerSec() { if(!odpollTimerStopping) { if (!onDemandPollRunning || odpollType !== 'Timer') { return; } if (odpollDisplaySeconds) { switch (odpollSecsRemain) { case 30: case 10: case 5: case 4: case 3: case 2: cb.sendNotice('\u231A \u231A \u231A There are ' + odpollSecsRemain + ' 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 (odpollSecsRemain < 1) { if (odpollMinsRemain >= 1) { odpollTimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Time is up! No more Votes!!! \u23f0 \u23f0 \u23f0', '', appWarningColor, '', 'bold'); odshowWinner(''); onDemandPollRunning = false; } } else { odpollSecsRemain--; cb.setTimeout(odpollTimerSec, 1000); } } } function odpollStopTimer() { odpollStopTime = new Date(); odpollMinsRemain = 0; odpollSecsRemain = 0; odpollTimerStopping = true; } // *************************** Text Poll Functions ************************ function setTextPollToggle(txtpollinitmode,txtpollcalledby) { setTextPollColors(); if (txtpollinitmode == 'on') { textPollToggle = true; initTextPoll(txtpollcalledby); cb.sendNotice(txtpollcalledby + ' has enabled the Text Poll feature, you can now vote in the poll. \nTo see the current voting options and totals, type: /textpoll', '', textPollBgColor, textPollTextColor, 'bold'); } else if (txtpollinitmode == 'off') { textPollToggle = false; cb.sendNotice(':siren1 ' + txtpollcalledby + ' has disabled the Text Poll feature, voting will no longer be tracked :siren1', '', textPollBgColor, textPollTextColor, 'bold'); cb.sendNotice('The poll has been disabled, but the poll options and votes are not cleared, you can resume the poll later by turning the poll back on. You can clear the vote counts with the command /resetpoll. You can edit the poll options using commands.', BC, appWarningColor); if (txtpollcalledby != BC) { cb.sendNotice('The poll has been disabled, but the poll options and votes are not cleared, you can resume the poll later by turning the poll back on. You can clear the vote counts with the command /resetpoll. You can edit the poll options using commands.', BC, appWarningColor); } textPollRunning = false; } } function initTextPoll(inittextcalledby) { switch (cb.settings.textPollMode) { case 'Ends by Mod/Broadcaster command': textPollType = 'Never'; break; case 'Ends after X minutes': textPollType = 'Timer'; break; case 'Ends after X total votes': textPollType = 'Vote'; break; case 'Ends when one option reaches X votes': textPollType = 'Goal'; break; default: cb.sendNotice('Error in determining the text poll end type, defaulting to no limit.', inittextcalledby, appNoticeColor); textPollType = 'Never'; } initTextPollValues(); buildTextPollBoard(inittextcalledby); initTextPollBoardTimer(); cb.setTimeout(showTextPollBoard, 30000); initTextPollTimer(); cb.setTimeout(displayTextPoll, 60000); } function initTextPollValues() { textPollRunning = true; textPollTimerStopping = false; textPollUsersVoted = []; ntxtline = 0; textPollVotesRemain = cb.settings.textPollCount; textPollTotalVotes = 0; } function initTextPollBoardTimer() { if (isNaN(parseFloat(cb.settings.textPollInterval))) { textPollNoticeInt = 1.5; cb.sendNotice('Fembot: Text Poll notice interval is not defined with a valid number so it is set to the default of 1.5 minutes.', BC, appWarningColor); } else { textPollNoticeInt = parseFloat(cb.settings.textPollInterval); } if (textPollNoticeInt <= 0) { textPollNoticeInt = 1.5; cb.sendNotice('Fembot: Text Poll notice interval is not defined with a valid number so it is set to the default of 1.5 minutes.', BC, appWarningColor); } else if (textPollNoticeInt < 1) { textPollNoticeInt = 1.5; cb.sendNotice('Fembot: Text Poll notice interval is too short, must be at least 1 minute. Using default setting of 1.5 minutes.', BC, appWarningColor); } textPollNoticeInt = parseInt(textPollNoticeInt * 60000); } function setTextPollColors() { if (cb.settings.textPollTextColor == 'Custom') { textPollTextColor = checkTextColor(cb.settings.textPollCustTextColor,true); if (textPollTextColor == 'default') { cb.sendNotice('Text Poll - Error while setting the font color. It has to be in a HEX format. Using default value.', BC, '#FFFFFF', '#FF0000', 'bold'); textPollTextColor = '#FFFFFF'; } } else { textPollTextColor = checkTextColor(cb.settings.textPollTextColor,true); } if (cb.settings.textPollBgColor == 'Custom') { textPollBgColor = checkBgColor(cb.settings.textPollCustBgColor,true); if (textPollBgColor == 'default') { cb.sendNotice('Text Poll - Error while setting the background color. It has to be in a HEX format. Using default value.', BC, '#FFFFFF', '#FF0000', 'bold'); textPollBgColor = '#0629AC'; } } else { textPollBgColor = checkBgColor(cb.settings.textPollBgColor,true); } } function buildTextPollBoard(buildtextcalledby) { for (let i = 1; i <= 5; i++) { var textoktoadd = true; if (this['textPollOpt'+i]) { for (let j = 0; j < i-1; j++) { if (textPollArray.dispname[j] == this['textPollOpt'+i]) { cb.sendNotice('Label for text poll option ' + i + ' is not unique, it is not added to the board.', buildtextcalledby, appNoticeColor); textoktoadd = false; break; } } if (textoktoadd) { textPollArray.dispname.push(this['textPollOpt'+i]); textPollArray.voteID.push(textPollArray.dispname.length); textPollArray.votes.push(0); } } } } function displayTextPoll() { if (textPollToggle && textPollRunning) { if (minMessagesForNotice > 0 && msgCounterTextPoll < minMessagesForNotice) { cb.setTimeout(displayPoll, 30000); } else { msgCounterTextPoll = 0; let textPollNotice = ['A textPoll is currently running. \nTo see the current voting options and totals, type: /textPoll']; if (fanDouble) { textPollNotice.push('Fan club members currently get two votes for the price of one!'); } textPollNotice.push(showLead()); cb.sendNotice(textPollNotice[ntxtline], '', textPollBgColor, textPollTextColor, 'bold'); ntxtline += 1; if (ntxtline >= textPollNotice.length) { ntxtline = 0; } cb.setTimeout(displayTextPoll, 90000); } } } function showTextPollBoard(showpollreqby) { if (showpollreqby === undefined) { showpollreqby = 'timer'; } if (textPollToggle) { var textpollboard1 = ''; var textpollboard2 = ''; if (showpollreqby == 'bc' || showpollreqby == 'timer' ) { textpollboard1 += 'Sent to ALL:\n'; } else { textpollboard1 += 'Sent to you:\n'; } if (textPollRunning) { textpollboard1 += noticeBorder('top','long','TEXT POLL'); } else { textpollboard1 += noticeBorder('top','long','POLL RESULTS'); } textpollboard1 += '\n \u2753 \u2754 \u2753 \u2754 \u2753 ' + textPollTitle + ' \u2753 \u2754 \u2753 \u2754 \u2753'; let tparraysort = []; for (let tparraysortidx = 0; tparraysortidx < textPollArray.votes.length; tparraysortidx++) { tparraysort.push({ 'votes': textPollArray.votes[tparraysortidx], 'id': tparraysortidx }); } tparraysort.sort(function(a, b) { return b.votes - a.votes; }); for (let tparraysortidx2 = 0; tparraysortidx2 < tparraysort.length; tparraysortidx2++) { if (0 != textPollArray.voteID[tparraysort[tparraysortidx2].id]) { textpollboard1 += '\n \u23E9 ' + textPollArray.dispname[tparraysort[tparraysortidx2].id] + ' (Choice #' + textPollArray.voteID[tparraysort[tparraysortidx2].id] + '): ' + textPollArray.votes[tparraysort[tparraysortidx2].id] + ' vote' + (textPollArray.votes[tparraysort[tparraysortidx2].id] != 1 ? 's' : ''); } } if (textPollRunning) { switch (textPollType) { case 'Timer': break; case 'Vote': textpollboard2 += textPollVotesRemain + ' vote' + (textPollVotesRemain == 1 ? '' : 's') + ' remaining before poll closes\n'; break; case 'Goal': textpollboard2 += 'First option to ' + cb.settings.textPollCount + ' votes wins!\n'; break; } if (textPollArray.dispname.length > 2) { textpollboard2 += 'To vote in the text poll, type the choice number (1-' + textPollArray.dispname.length + ') in the chat. \nNote you can only vote one time. \nTo see the current voting options and totals, type: /textpoll'; } else { textpollboard2 += 'To vote in the text poll, type the choice number (1 or 2) in the chat. \nNote you can only vote one time. \nTo see the current voting options and totals, type: /textpoll'; } } else { textpollboard2 += 'The text poll has been closed, no more voting!'; } showpollsendto = showpollreqby; if (showpollreqby == 'timer') { showpollsendto = ''; if (textPollRunning) { cb.setTimeout(showTextPollBoard, textPollNoticeInt); } } else if (showpollreqby == 'bc') { showpollsendto = ''; } textpollboard1 += noticeBorder('bottom','long',''); cb.sendNotice(textpollboard1, showpollsendto, textPollBgColor, textPollTextColor, 'bold'); cb.sendNotice(textpollboard2, showpollsendto, textPollBgColor, textPollTextColor, 'bold'); } } function textPollVote(votedID,votedamount,votedby) { var voteoptionidx = votedID - 1; textPollArray.votes[voteoptionidx] += votedamount; textPollTotalVotes += votedamount; textPollUsersVoted.push(votedby); if (votedamount == 1) { cb.sendNotice(votedby + ' voted for " ' + textPollArray.dispname[voteoptionidx] + ' "', '', textPollBgColor, textPollTextColor, 'bold'); } else { cb.sendNotice(votedby + ' voted ' + votedamount + ' time' + (votedamount == 1 ? '' : 's') + ' for " ' + textPollArray.dispname[voteoptionidx] + ' "', '', textPollBgColor, textPollTextColor, 'bold'); } if (textPollType == 'Vote') { textPollVotesRemain -= votedamount; } textPollCheckEnd(); } function textPollCheckEnd() { if (textPollType != 'Timer') { if (textPollType == 'Vote') { if (textPollVotesRemain < 1) { textPollRunning = false; showTextPollWinner(''); } } else if (textPollType == 'Goal') { for (let tpridx = 0; tpridx < textPollArray.votes.length; tpridx++) { if (textPollArray.votes[tpridx] >= cb.settings.textPollCount) { textPollRunning = false; showTextPollWinner(''); break; } } } } } function showTextPollWinner(showwinneruser) { let tpoptions = []; for (let i = 0; i < textPollArray.votes.length; i++) { tpoptions[i] = i; } tpoptions.sort(function(a, b) { return textPollArray.votes[b] - textPollArray.votes[a]; }); let win_count = 1; for (let j = 1; j < textPollArray.votes.length; j++) { if (textPollArray.votes[tpoptions[j]] != textPollArray.votes[tpoptions[0]]) { break; } if (0 != textPollArray.votes[tpoptions[j]]) { win_count++; } } let textPollwinner1 = '\u23f0 \u23f0 \u23f0 Text Poll has ended! \u23f0 \u23f0 \u23f0 \n'; let textPollwinner2 = 'Winner' + (win_count > 1 ? 's (' + win_count + '-way tie)' : '') + ':'; for (let k = 0; k < win_count; k++) { if (textPollArray.votes[tpoptions[k]] != 0) { textPollwinner2 += '\n \u23E9 ' + textPollArray.dispname[tpoptions[k]] + ': ' + textPollArray.votes[tpoptions[k]] + ' votes'; } } cb.sendNotice(textPollwinner1 + textPollwinner2, showwinneruser, textPollBgColor, textPollTextColor, 'bold'); } function showTextPollLead() { let tploptions = []; let tpleadopt = []; for (let i = 0; i < textPollArray.dispname.length; i++) { tploptions[i] = i; } tploptions.sort(function(a, b) { return textPollArray.votes[b] - textPollArray.votes[a]; }); if (textPollArray.votes[tploptions[0] ] > 0 ){ tpleadopt.push(textPollArray.dispname[tploptions[0]]); for (let j = 1; j < textPollArray.dispname.length; j++) { if (textPollArray.votes[tploptions[j]] != textPollArray.votes[tploptions[0]]) { break; } if (0 != textPollArray.voteID[tploptions[j]]) { tpleadopt.push(textPollArray.dispname[tploptions[j]]); } } } let tplead; let leadCount = tpleadopt.length; if (leadCount == 0){ tplead = 'Text Poll: No votes yet, be sure to vote for your favorite! \nTo see the current voting options and totals, type: /textpoll'; } else if (leadCount == 1) { tplead = 'Text Poll: ' + textPollArray.dispname[tploptions[0]] + ' is in the lead by ' + (textPollArray.votes[options[0]] - textPollArray.votes[options[1]]) + ' vote' + ((textPollArray.votes[options[0]] - textPollArray.votes[options[1]]) === 1 ? '' : 's') + '.'; } else { tplead = 'Text Poll: We have a ' + leadCount + '-way tie between ' + formatTextArray(tpleadopt,'and') + '.'; } return tplead; } function formatTextArray(arr,andor){ var textoutstr = ''; if (arr.length == 1) { textoutstr = arr[0]; } else if (arr.length == 2) { textoutstr = arr.join(' '+andor+' '); } else if (arr.length > 2) { textoutstr = arr.slice(0, -1).join(', ') + ', '+andor+' ' + arr.slice(-1); } return textoutstr; } function textPollTimeCal() { textPollStartTime = new Date(); return textPollStopTime - textPollStartTime.getTime(); } function textPollTimeLeft() { var textpolltimeleft = textPollTimeCal(); var txtmilliseconds = textpolltimeleft % 1000; var txtseconds = ((textpolltimeleft - txtmilliseconds) % 60000); var txtminutes = ((textpolltimeleft - txtseconds - txtmilliseconds) % 3600000); var txthours = (textpolltimeleft - txtminutes - txtseconds - txtmilliseconds); txtseconds = txtseconds / 1000; txtminutes = txtminutes / 60000; txthours = txthours / 3600000; if (txthours > 0) { return txthours + ' hour' + (txthours > 1 ? 's' : '') + ' and ' + txtminutes + ' minute' + (txtminutes > 1 ? 's' : '') + ' left to vote.'; } else if (txtminutes > 0 && txtseconds === 0) { return txtminutes + ' minute' + (txtminutes > 1 ? 's' : '') + ' left to vote!'; } else if (txtminutes > 0) { return txtminutes + ' minute' + (txtminutes > 1 ? 's' : '') + ' and ' + txtseconds + ' second' + (txtseconds > 1 ? 's' : '') + ' left to vote!'; } else { return txtseconds + ' second' + (txtseconds > 1 ? 's' : '') + ' left to vote!!!'; } } function initTextPollTimer() { if (!textPollRunning || textPollType != 'Timer') { return; } else { textPollStartTime = new Date(); textPollStopTime = new Date(textPollStartTime.getTime() + cb.settings.textPollCount * 60000); textPollTimerMin(); } } function textPollAddTime(textpolltimetoadd, u) { textPollStopTime = new Date(textPollStopTime.getTime() + textpolltimetoadd * 60000); texttimetoaddabs = Math.abs(textpolltimetoadd); if (textpolltimetoadd > 0) { cb.sendNotice(textpolltimetoadd + ' minute' + (textpolltimetoadd == 1 || textpolltimetoadd == -1 ? ' has' : 's have') + ' been added to the timer. Now ' + textPollTimeLeft(), '', appWarningColor, '', 'bold'); } else { cb.sendNotice(texttimetoaddabs + ' minute' + (texttimetoaddabs == 1 || texttimetoaddabs == -1 ? ' has' : 's have') + ' been subtracted from the timer. Now ' + textPollTimeLeft(), '', appWarningColor, '', 'bold'); } textPollMinsRemain = textPollMinsRemain + textpolltimetoadd; if (textPollMinsRemain > 0) { textPollDisplaySeconds = false; } else { textPollDisplaySeconds = true; } } function textPollSwitchToTimer(tptimetoadd, u) { textPollType = 'Timer'; textPollStartTime = new Date(); textPollStopTime = new Date(textPollStartTime.getTime() + tptimetoadd * 60000); cb.sendNotice('A text poll timer has been set for ' + tptimetoadd + ' minute' + (tptimetoadd === 1 || tptimetoadd === -1 ? '' : 's'), '', appWarningColor, '', 'bold'); textPollMinsRemain = tptimetoadd; textPollTimerStopping = false; textPollTimerMin(); return; } function textPollTimerMin() { if(!textPollTimerStopping) { if (!textPollRunning || textPollType != 'Timer') { return; } switch (textPollMinsRemain) { 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 ' + textPollMinsRemain + ' minutes left to vote in the text poll!!! \u231A \u231A \u231A', '', appWarningColor, '', 'bold'); break; case 1: cb.sendNotice('\u231A \u231A \u231A There is 1 minute left to vote in the text poll!!! \u231A \u231A \u231A', '', red, '', 'bold'); break; } textPollMinsRemain--; if (textPollMinsRemain > 0) { textPollDisplaySeconds = false; } else { textPollDisplaySeconds = true; } textPollSecsRemain = 60; textPollTimerSec(); } } function textPollTimerSec() { if(!textPollTimerStopping) { if (!textPollRunning || textPollType != 'Timer') { return; } if (textPollDisplaySeconds) { switch (textPollSecsRemain) { case 30: case 10: case 5: case 4: case 3: case 2: cb.sendNotice('\u231A \u231A \u231A There are ' + textPollSecsRemain + ' 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 (textPollSecsRemain < 1) { if (textPollMinsRemain >= 1) { textPollTimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Time is up! No more Votes!!! \u23f0 \u23f0 \u23f0', '', appWarningColor, '', 'bold'); showTextPollWinner(''); textPollRunning = false; } } else { textPollSecsRemain--; cb.setTimeout(textPollTimerSec, 1000); } } } function textPollStopTimer() { textPollStopTime = new Date(); textPollMinsRemain = 0; textPollSecsRemain = 0; textPollTimerStopping = true; } // *********************************** Ticket Show Functions ************************************** function prepticketshow(mod) { if (cb.settings.prepticketStartPoll == 'Yes' && tokenPollToggle == 0) { setTokenPollToggle('on',mod); } if (cb.settings.prepticketTipMenuOff == 'Yes' && tipMenuToggle == 1) { setTipMenuToggle('off',mod); } if (cb.settings.prepticketPosMenuOn == 'Yes' && posTipMenuToggle == 0) { setPosTipMenuToggle('on',mod); } if (backupToggle == 0 && ticketShowType != 'Fembot Ticket Show') { setBackupToggle('on',mod,true); 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, appNoticeColor); } } } 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],'',0,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, appNoticeColor); } } 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],'',0,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, appNoticeColor); } } else { return(addLBstring); } } break; } } } function addRmvTicketBackupList(mode,user) { 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); changeTicketShowSubject(ticketPrice); if (announce === 'yes') { 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' , '', ticketBgColor, ticketTxtColor, 'bold'); } } 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, appNoticeColor); } } function setBackupToggle(mode,mod,bycmd) { if (mode == 'on') { if (backupToggle == 1) { cb.sendNotice('The Backup Ticket List is already enabled.',mod,appNoticeColor); } else { backupToggle = 1; if (bycmd) { cb.sendNotice('You have enabled the Backup Ticket List.',mod,appNoticeColor); } } } else if (mode == 'off') { if (backupToggle == 0) { cb.sendNotice('The Backup Ticket List is already disabled.',mod,appNoticeColor); } else { backupToggle = 0; cb.sendNotice('You have disabled the Backup Ticket List.',mod,appNoticeColor); } } } // *********************************** Media Display Function ************************************** function setMediaToggle(mode,mod,bycmd) { if (mode == 'on') { if (mediaToggle == 1) { cb.sendNotice('The Media List is already enabled.', mod, appNoticeColor); } else { mediaToggle = 1; setMediaColors(); initMediaListTimer(); if (bycmd) { cb.sendNotice('You have enabled the Media List.', mod, appNoticeColor); } } } else if (mode == 'off') { if (mediaToggle == 0) { cb.sendNotice('The Media List is already disabled.', mod, appNoticeColor); } else { mediaToggle = 0; cb.sendNotice('You have disabled the Media List.', mod, appNoticeColor); } } } function setMediaColors() { if (cb.settings.mediaListTxtColor === "Custom") { mediaforeground = checkTextColor(cb.settings.mediaListCustTxtColor,true); 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,true); } if (cb.settings.mediaListBgColor === "Custom") { mediabackground = checkBgColor(cb.settings.mediaListCustBgColor,true); 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,true); } } function initMediaListTimer() { if (isNaN(parseFloat(cb.settings.mediaListInterval))) { cb.sendNotice('Fembot: Media List notice interval is not set with a valid number so the Media List notice is not enabled.', cb.room_slug, appWarningColor); mediaTimerInt = 0; } else { mediaTimerInt = parseFloat(cb.settings.mediaListInterval); } if (mediaTimerInt != 0) { if (mediaTimerInt < 1) { cb.sendNotice('Fembot: Media List notice interval is too short, must be at least 1 minute. Using default value of 5.7 minutes.', cb.room_slug, appWarningColor); mediaTimerInt = 5.7; } mediaTimerInt = parseInt(mediaTimerInt * 60000); cb.setTimeout(mediaListTimer, mediaTimerInt); } } function mediaListTimer() { if (mediaToggle == 1) { if (minMessagesForNotice > 0 && msgCounterMedia < minMessagesForNotice) { cb.setTimeout(mediaListTimer, 30000); } else { msgCounterMedia = 0; showMedia(''); cb.setTimeout(mediaListTimer, mediaTimerInt); } } } function showMedia(sendto) { var mediamessage = noticeBorder('top','long','MEDIA INFO'); mediamessage += '\n' + checkNextLine(cb.settings.mediaListIntro); for (let j = 1; j <= 12; j++) { if (this['mediaListItem'+j] != '' && this['mediaListItem'+j] != null) { if (cb.settings.mediaSameLine == 'Same Line') { mediamessage += '\n' + this['mediaListText'+j] + ' : ' + this['mediaListItem'+j]; } else { mediamessage += '\n' + this['mediaListText'+j] + '\n' + this['mediaListItem'+j]; } } } mediamessage += noticeBorder('bottom','long',''); cb.sendNotice(mediamessage, sendto, mediabackground, mediaforeground, 'bold'); } // *********************************** Require Answer Chat Lock Function ************************************** function setRequireAnswerToggle(mode,setby,bycmd) { if (mode == 'on') { if (requireAnswerToggle == 1) { cb.sendNotice('The "Answer Required" Chat Lock is already enabled at the level of ' + requireAnswerLevelText + '.', setby, appNoticeColor); } else { requireAnswerToggle = 1; if (requireAnswerLevel > 0) { if (bycmd) { cb.sendNotice('You have enabled the "Answer Required" Chat Lock at the level of ' + requireAnswerLevelText + '.', setby, appNoticeColor); } } else { requireAnswerLevel = 1; requireAnswerLevelText = 'Gray Users'; if (bycmd) { 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, appNoticeColor); } } } } else if (mode == 'off') { if (requireAnswerToggle == 0) { cb.sendNotice('The "Answer Required" Chat Lock is already disabled.', setby, appNoticeColor); } else { requireAnswerLevel = 0; requireAnswerLevelText = 'Not Used'; requireAnswerToggle = 0; cb.sendNotice('You have disabled the "Answer Required" Chat Lock.', setby, appNoticeColor); } } } function requireAnswerLockCheck(checklockuser) { if (!cbjs.arrayContains(answerLockList,checklockuser)) { addToAnswerLockList(checklockuser); } var answeruserindex = answerLockList.indexOf(checklockuser); if (answerLockStatus[answeruserindex]) { return true; } else { return false; } } function addToAnswerLockList(addlockuser) { initCanChat = false; lockquestionindex = Math.floor(Math.random() * 10); answerLockList.push(addlockuser); answerLockStatus.push(initCanChat); answeruserindex = answerLockList.indexOf(addlockuser); 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, appNoticeColor); } else { grayLockToggle = 1; cb.sendNotice('You have enabled the Gray Chat Lock with the configured threshold set to ' + grayChatTime + ' minutes.', mod, appNoticeColor); } } else if(option == 'off') { if(grayLockToggle == 0) { cb.sendNotice('The Gray Chat Lock is already disabled.', mod, appNoticeColor); } else { grayLockToggle = 0; cb.sendNotice('You have disabled the Gray Chat Lock.', mod, appNoticeColor); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usegraylock, the option should be "on" or "off".', mod, appNoticeColor); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usegraylock, the option should be "on" or "off".', mod, appNoticeColor); } } function grayLockCheck(userlock,isbclock,ismodlock,isfanlock,isgraylock) { if (!cbjs.arrayContains(grayLockList,userlock)) { addToLockList(userlock,isbclock,ismodlock,isfanlock,isgraylock); } var grayIndex = grayLockList.indexOf(userlock); 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(userlkadd,isbclkadd,ismodlkadd,isfanlkadd,isgraylkadd) { if (isbclkadd || !isgraylkadd || isfanlkadd || ismodlkadd || cbjs.arrayContains(VIPListArray,userlkadd) || cbjs.arrayContains(extFanListArray,userlkadd) || cbjs.arrayContains(extFanList2Array,userlkadd)) { initCanChat = true; } else { initCanChat = false; } grayLockList.push(userlkadd); 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, appNoticeColor); } 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, appNoticeColor); } } 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, appNoticeColor); } else { cb.sendNotice(user + ' is not on chat restricted time lock.', sendto, appNoticeColor); } } } 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, appNoticeColor); } // *********************************** Dice Game Functions ************************************** function setDiceToggle(option, mod) { if(option == 'on') { if(diceToggle == 1) { cb.sendNotice('The Dice Game is already enabled.', mod, appNoticeColor); } else { diceToggle = 1; setDiceColors(); diceSetPrizes(); initDiceTimer(); cb.sendNotice(mod + ' has enabled the dice game!', '', diceNoticeBg, diceNoticeTextColor, 'bold'); priceChecker('add','Dice Roll Price', diceRollPrice,mod); } } else if(option == 'off') { if(diceToggle == 0) { cb.sendNotice('The Dice Game is already disabled.', mod, appNoticeColor); } else { diceToggle = 0; cb.sendNotice(mod + ' has disabled the dice game, you can no longer tip to roll the dice.', '', diceNoticeBg, diceNoticeTextColor, 'bold'); } } else if(option != null) { cb.sendNotice(option + ' is not a valid option for /usedice, the option should be "on" or "off".', mod, appNoticeColor); } else if(option == null) { cb.sendNotice('You did not enter a valid option for /usedice, the option should be "on" or "off".', mod, appNoticeColor); } } function setDiceColors() { diceNoticeBg = checkBgColor(cb.settings.diceNoticeBgColor,true); diceRollBg = checkBgColor(cb.settings.diceRollBgColor,false); diceRollBgSpecial = checkBgColor(cb.settings.diceRollBgColorSpecial,false); diceTextColor = checkTextColor('#000000',false); diceNoticeTextColor = checkTextColor('#000000',true); } function initDiceTimer() { if (isNaN(parseFloat(cb.settings.diceNoticeInterval))) { cb.sendNotice('Fembot: Dice notice interval is not set, dice notice will not be displayed.', cb.room_slug, appWarningColor); diceInt = 0; } else { diceInt = parseFloat(cb.settings.diceNoticeInterval); } if (diceInt != 0) { if (diceInt < 1) { cb.sendNotice('Fembot: Dice notice interval is too short, must be at least 1 minute. Using default value of 3.3 minutes.', cb.room_slug, appWarningColor); diceInt = 3.3; } diceInt = parseInt(diceInt * 60000); cb.setTimeout(diceNoticeTimer, diceInt); } } function diceNoticeTimer() { if (diceToggle == 1) { if (minMessagesForNotice > 0 && msgCounterDice < minMessagesForNotice) { cb.setTimeout(diceNoticeTimer, 30000); } else { msgCounterDice = 0; diceShowNotice(''); cb.setTimeout(diceNoticeTimer, diceInt); } } } function diceShowNotice(sendto) { var dicegamemsg = noticeBorder('top','long','DICE GAME'); if (diceMultiRolls <= 1) { dicegamemsg += '\n :diceroll1 \nTip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! \nTo see the Prize list, type: /prizes'; } else if (diceMultiRolls == 2) { dicegamemsg += '\n :diceroll1 Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! \nYou can tip up to 2 multiples of the dice roll price (' + diceRollPrice + ' or ' + diceRollPrice*2 + ') \nTo see the Prize list, type: /prizes'; } else if (diceMultiRolls == 3) { dicegamemsg += '\n :diceroll1 Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! \nYou can tip up to 3 multiples of the dice roll price (' + diceRollPrice + ', ' + diceRollPrice*2 + ', or ' + diceRollPrice*3 + ') \nTo see the Prize list, type: /prizes'; } else if (diceMultiRolls > 3) { dicegamemsg += '\n :diceroll1 Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! \nYou can tip up to ' + diceMultiRolls + ' multiples of the dice roll price (' + diceRollPrice + ', ' + diceRollPrice*2 + ', ' + diceRollPrice*3 + ',...) \nTo see the Prize list, type: /prizes'; } dicegamemsg += noticeBorder('bottom','long',''); if (minTimeForNotice > 0) { // checkNoticeFrequency(dicegamemsg, sendto, diceNoticeBg, diceTextColor, 'bold', ''); } else { cb.sendNotice(dicegamemsg, sendto, diceNoticeBg, diceNoticeTextColor, '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; } } diceTotal = firstDie + secondDie; winner = false; if (diceTotal >= 2 && diceTotal <= 13) { winner = true; prizeIndex = diceTotal - 2; prize = dicePrizes[prizeIndex]; if (cb.settings.diceRemoveWinner == 'Yes') { dicePrizes.splice(prizeIndex, 1); } } else { winner = false; prize = 'A Thank You!'; } if (dicePrizes.length === 1) { diceSetPrizes(); } var msg = 'Roll #' + diceRollCounter + '...'; msg += '\n' + diceGifPfx + firstDie + " " + diceGifPfx + secondDie; msg += '\n' + rolledby + ' rolled a ' + diceTotal + '!'; if (diceTotal == 13) { msg += ' \nPrize: :siren1 ' + prize + ' :siren1'; cb.sendNotice(msg, '', diceRollBgSpecial, diceTextColor, 'bold'); } else { msg += ' \nPrize: ' + prize; 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'; for (var i = 2; i <= 13; i++) { if (i == 13) rareText = ' (RARE)'; if (dicePrizes.indexOf(cb.settings['dicePrize_' + i] + rareText) >= 0) msg += '\nRoll ' + i + ' - ' + cb.settings['dicePrize_' + i] + rareText; } } else { var msg = "SORRY! There are no prizes left in the list, but thank you for the tip. :thumbsup"; } cb.sendNotice(msg, sendto, diceNoticeBg, diceTextColor, '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,bycmd) { if (mode == 'tipper' || mode == 'all' ) { if (mode == 'tipper' && tipResponseToggle == 1) { cb.sendNotice('The Tip Response is already set to "send to tipper".', mod, appNoticeColor); } else if (mode == 'all' && tipResponseToggle == 2) { cb.sendNotice('The Tip Response is already set to "send to all".', mod, appNoticeColor); } 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.', mod, appNoticeColor); } 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.', mod, appNoticeColor); } 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.', mod, appNoticeColor); } 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.', mod, appNoticeColor); } else { tipresponsetextcolor = checkTextColor('Dark Red',false); tipresponsebgcolor = checkBgColor('White',false); if (mode == 'tipper') { tipResponseToggle = 1; } else { tipResponseToggle = 2; } if (bycmd) { cb.sendNotice('You have enabled the Tip Response. Users will now see a response message when they tip above each threshold.', mod, appNoticeColor); } } } } else if (mode == 'off') { if (tipResponseToggle == 0) { cb.sendNotice('The Tip Response is already disabled.', mod, appNoticeColor); } else { tipResponseToggle = 0; cb.sendNotice('You have disabled the Tip Response.', mod, appNoticeColor); } } } // *********************************** 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,appNoticeColor); } else { priceChecker('add','Pre-sale Ticket Price', presalePrice,sendto); presalesToggle = 1; presalesTxtColor = checkTextColor('Dark Purple',true); presalesBgColor = checkBgColor('Light Blue',true); 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,appNoticeColor); presaleSkipMin = false; presaleSkipSec = false; presaleSkipNotice = false; setPresaleMode('init',sendto); countPresaleSold = 0; presaleIncrements = 0; stopIncrement = false; initPresaleNoticeTimer(); } } else if(option == 'off') { if(presalesToggle == 0) { cb.sendNotice('The Pre-Sales Ticket feature is already disabled.',sendto,appNoticeColor); } 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,appNoticeColor); 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,appNoticeColor); } 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,appNoticeColor); } } function initPresaleNoticeTimer() { if (isNaN(parseFloat(cb.settings.presaleNoticeInterval))) { cb.sendNotice('Fembot: The Pre-Sales notice interval is not set with a valid number so the Pre-Sales notice is not enabled.', cb.room_slug, appWarningColor); presaleNoticeInt = 0; } else { presaleNoticeInt = parseFloat(cb.settings.presaleNoticeInterval); } if (presaleNoticeInt != 0) { if (presaleNoticeInt < 1) { cb.sendNotice('Fembot: Pre-Sales notice interval is too short, must be at least 1 minute. Using default value of 4.1 minutes.', cb.room_slug, appWarningColor); presaleNoticeInt = 4.1; } presaleNoticeInt = parseInt(presaleNoticeInt * 60000); cb.setTimeout(presaleNoticeTimer, presaleNoticeInt); } } 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. ' + bctext + ' or a moderator can change the presale price on demand using the command "/presaleprice [newprice]".', sendto, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } } 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, appNoticeColor); 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, appNoticeColor); } } 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, appNoticeColor); } } 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 && ticketShowToggle != 1) { if (minMessagesForNotice > 0 && msgCounterPresales < minMessagesForNotice) { cb.setTimeout(presaleNoticeTimer, 30000); } else { msgCounterPresales = 0; 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, presaleNoticeInt); } 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', "", appWarningColor, "", "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", "", appWarningColor, "", "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.',"", presalesBgColor, presalesTxtColor, "bold"); cb.sendNotice('No additional timer started, next increment would have exceeded planned ticket show price of ' + ticketPrice + '.',cb.room_slug, appNoticeColor); } 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.',"", presalesBgColor, presalesTxtColor, "bold"); cb.sendNotice('No additional timer started, next increment would have exceeded max increments of ' + cb.settings.presaleMaxIncrements + '.',cb.room_slug, appNoticeColor); } 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(),'',appWarningColor,'', '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.','',appWarningColor,'', '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(addpremode,addpreuser,addpreamount,addpreanon) { switch(addpremode) { case 'add': { if(!cbjs.arrayContains(presaleArray,addpreuser)) { presaleArray.push(addpreuser); cb.sendNotice(addpreanon + ' 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,addpreuser)) { cbjs.arrayRemove(presaleArray,addpreuser); cb.sendNotice(addpreanon + ' has been removed from the pre-sale ticket list.', '', presalesBgColor, presalesTxtColor, 'bold'); } break; } case 'addtip': { if (addpreamount >= presalePrice) { presaleArray.push(addpreuser); cb.sendNotice('Welcome ' + addpreanon + ', 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); for (var i = 0; i < presaleArray.length; i++) { if (presaleArray[i] != '') { if (!cb.limitCam_userHasAccess(presaleArray[i])) { addRmvTicket('add',presaleArray[i],'',0,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], appNoticeColor); } 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, appNoticeColor); cb.sendNotice(mod + ' has added multiple users from the Pre-sale list to the Fembot Ticket Show list.\nUsers added: ' + cbjs.arrayJoin(presaleArray, ', '), '', appNoticeColor, '', 'normal', 'red'); } else { if (!cb.limitCam_userHasAccess(presaleArray[0])) { addRmvTicket('add',presaleArray[0],'',0,presaleArray[0]); cb.sendNotice('All users from the pre-sale list were added to the Fembot Ticket Show and notified.', mod, appNoticeColor); } 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, appNoticeColor); } } } // *********************************** 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,appNoticeColor); } else { initTicketShow(price,sendto); cb.sendNotice(dashLineTicket1 + '\n* ' + sendto + ' has started ticket sales for the Fembot Hidden Ticket Show.\n* Tickets are ' + ticketPrice + ' tokens.' + dashLineTicket2, '', ticketBgColor, ticketTxtColor, 'bold'); if (cb.settings.hiddenShowAllowGift === 'Yes') { cb.sendNotice(dashLineTicket1 + '\n* ' + bctext + ' has enabled the the gifting of tickets. \n* You can buy extra tickets and gift them using the command /giftticket' + dashLineTicket2, '', ticketBgColor, ticketTxtColor, 'bold'); } } } else if(option == 'off') { if (ticketShowToggle == 0) { cb.sendNotice('The Fembot Hidden Ticket Show feature is already disabled.',sendto,appNoticeColor); } 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,appNoticeColor); } 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,appNoticeColor); } } } 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(); if (cb.settings.ticketNoticeInterval >= 1) { ticketNoticeInt = parseInt(cb.settings.ticketNoticeInterval * 60000); } else { ticketNoticeInt = parseInt(2.1 * 60000); } if (ticketShowType == 'Fembot Ticket Show') { if (presaleArray.length > 0) { addPresaleList(sendto); } else { cb.sendNotice('No pre-sale list ticket holders to add.', sendto, appNoticeColor); } } if (presalesToggle == 1) { setPresalesToggle('off', sendto); } cb.setTimeout(ticketNoticeTimer, ticketNoticeInt); } function ticketShowColors() { ticketTxtColor = checkTextColor('Black',false); ticketBgColor = checkBgColor('Light Blue',false); ticketNoticesTxtColor = checkTextColor('Dark Red',true); ticketNoticesBgColor = checkBgColor('Cream',true); ticketTxtColorFan = checkTextColor('Black',false); ticketBgColorFan = checkBgColor('Light Green',false); ticketTxtColorVIP = checkTextColor('Black',false); ticketBgColorVIP = checkBgColor('Light Purple',false); ticketTxtColorMod = checkTextColor('Black',false); ticketBgColorMod = checkBgColor('Light Red',false); ticketStatsBgColor = checkBgColor(ticketStatsBgColor,false); } function setTicketShowOtToggle(option, sendto) { if(option == 'on') { if(ticketShowOtToggle == 1) { cb.sendNotice('The Outstanding Ticket feature is already enabled.',sendto,appNoticeColor); } else { ticketShowOtToggle = 1; cb.sendNotice(dashLineTicket1 + '\n* ' + sendto + ' has started the Outstanding Ticket (OT) feature.\n* To save your ticket if you have to leave, type: /saveticket \n(you will be removed from the current show list). \n* To use an outstanding ticket from a previous show, type: /useticket' + dashLineTicket2, '', 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,appNoticeColor); } } else if(option == 'off') { if(ticketShowOtToggle == 0) { cb.sendNotice('The Outstanding Ticket feature is already disabled.',sendto,appNoticeColor); } 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,appNoticeColor); } } } 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',0,moderatorList.name[i]); } } } if (cb.settings.hiddenShowFreeFC == 'Yes') { for (let i = 0; i < fanClubList.length; i++) { if (!cb.limitCam_userHasAccess(fanClubList[i])) { addRmvTicket('add',fanClubList[i],'fan',0,fanClubList[i]); } } } if (cb.settings.hiddenShowFreeEFC == 'Yes') { for (let i = 0; i < extFanInShowArray.length; i++) { if (!cb.limitCam_userHasAccess(extFanInShowArray[i])) { addRmvTicket('add',extFanInShowArray[i],'fan',0,extFanInShowArray[i]); } } } if (cb.settings.hiddenShowFreeEFC2 == 'Yes') { for (let i = 0; i < extFanInShow2Array.length; i++) { if (!cb.limitCam_userHasAccess(extFanInShow2Array[i])) { addRmvTicket('add',extFanInShow2Array[i],'fan',0,extFanInShow2Array[i]); } } } if (cb.settings.hiddenShowFreeVIP == 'Yes') { for (let i = 0; i < VIPInShowArray.length; i++) { if (!cb.limitCam_userHasAccess(VIPInShowArray[i])) { addRmvTicket('add',VIPInShowArray[i],'vip',0,VIPInShowArray[i]); } } } } function setTicketMode(startmode,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) { newTicketMode = startmode; } else { newTicketMode = ticketStartMode; } newTicketAuto = ticketModeAuto; } if (ticketStartMode === 'timer' && newTicketMode != 'timer') { if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { stopTicketTimer(sendto); } } if (newTicketMode === 'manual') { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; if (startmode != 'init') { cb.sendNotice('Ticket Show start mode is set to "Manual", the show will be started via command when ready.','', 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". ' + bctext + ' 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, appNoticeColor); } } 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". ' + bctext + ' 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, appNoticeColor); } } 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". ' + bctext + ' 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, appNoticeColor); } } } function setTicketAuto(automode) { if (automode === 'bc') { ticketModeAuto = 'bc'; } else if (automode === 'auto') { ticketModeAuto = 'auto'; } } function ticketNoticeTimer() { if (ticketShowToggle == 1) { var ticketnotice = dashLineTicket1; if (showStage == 'ticketsales') { ticketnotice += '\n\u23E9 Ticket Price: ' + ticketPrice + ' tokens'; ticketnotice += '\n\u23E9 Description: ' + cb.settings.hiddenShowPreNotice; if (ticketStartMode == 'ticketgoal') { ticketnotice += '\n\u23E9 Start Mode: Ticket Goal (Sold ' + ticketShowTotalTickets + ' / ' + ticketShowGoalTickets + ' tickets)'; } else if (ticketStartMode == 'tokengoal') { ticketnotice += '\n\u23E9 Start Mode: Token Goal (' + ticketShowTotalTips + ' / ' + ticketShowGoalTokens + ' tokens)'; } else if (ticketStartMode == 'timer') { ticketnotice += '\n\u23E9 Start Mode: Timer (' + ((ticketSecsRemain > 0 || ticketMinsRemain > 0) ? ticketTimeLeft() : 'Timer not yet started') + ')'; } else { ticketnotice += '\n\u23E9 Start Mode: Manual (Broadcaster or Moderator will start the show)'; } } else if (showStage == 'ticketshow') { ticketnotice += '\n\u23E9 Ticket Price: ' + ticketPrice + ' tokens'; ticketnotice += '\n\u23E9 Ticket Sales: Ticket sales available'; ticketnotice += '\n\u23E9 Description: ' + cb.settings.hiddenShowNotice; } else if (showStage == 'showwarn') { ticketnotice += '\n\u23E9 Ticket Price: ' + ticketPrice + ' tokens'; ticketnotice += '\n\u23E9 Ticket Sales: Ticket sales available, show ending soon!'; ticketnotice += '\n\u23E9 Description: ' + cb.settings.hiddenShowNotice; } else if (showStage == 'showfinale') { ticketnotice += '\n\u23E9 Description: ' + cb.settings.hiddenShowNotice; ticketnotice += '\n\u23E9 Ticket Sales: Ticket sales ended, do not buy a ticket!'; } else if (showStage == 'aftershow') { ticketnotice += '\n\u23E9 Show has ended! -- ' + cb.settings.afterShowNotice; } if (showStage != 'aftershow') { ticketnotice += '\n\u23E9 Ticket Holders: ' + countTicketsSold; ticketnotice += '\n\u23E9 Viewers: ' + ticketShowViewerList.length; } ticketnotice += dashLineTicket2; cb.sendNotice(ticketnotice, '', ticketNoticesBgColor, ticketNoticesTxtColor, 'bold'); if (!ticketSkipNotice) { cb.setTimeout(ticketNoticeTimer, ticketNoticeInt); } else { ticketSkipNotice = false; } } } function ticketAutoTimer(addtime) { if (ticketModeAuto === 'auto') { cb.sendNotice(dashLineTicket1 + '\nAn automatic timer was started, ticket show price will be ' + ticketPrice + ' tokens.' + dashLineTicket2, '', ticketBgColor, ticketTxtColor, 'bold'); } else if (ticketModeAuto === 'bc') { cb.sendNotice(dashLineTicket1 + '\nA timer was started to provide an countdown to approximate showtime. \n ' + bctext + ' will start the show after the timer runs out.' + dashLineTicket2, '', 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', "", appWarningColor, "", "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', '', ticketBgColor, ticketTxtColor, 'bold'); startTicketShow(cb.room_slug); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Time is up! ' + bctext + ' will be starting the show! \u23f0 \u23f0 \u23f0', '', ticketBgColor, ticketTxtColor, '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(), '', appWarningColor, '', '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.', '', appWarningColor, '', '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' : '') + ' left on the ticket show timer'; } else if (ticketMinutes > 0 && ticketSeconds === 0) { return ticketMinutes + ' minute' + (ticketMinutes > 1 ? 's' : '') + ' left on the ticket show timer'; } else if (ticketMinutes > 0) { return ticketMinutes + ' minute' + (ticketMinutes > 1 ? 's' : '') + ' and ' + ticketSeconds + ' second' + (ticketSeconds > 1 ? 's' : '') + ' left on the ticket show timer'; } else { return ticketSeconds + ' second' + (ticketSeconds > 1 ? 's' : '') + ' left on the ticket show timer'; } } function addRmvTicket(mode,addtktuser,usertype,tipamount,anontipper) { switch(mode) { case 'add': { cb.limitCam_addUsers([addtktuser]); if (!cbjs.arrayContains(ticketShowViewerList,addtktuser)) { ticketShowViewerList.push(addtktuser); } if (cb.settings.showTicketsAdded == 'Everyone') { if (usertype == 'fan') { cb.sendNotice('Fan Club member ' + anontipper + ' has been added to the ticket show list.', '', ticketBgColorFan, ticketTxtColorFan, 'bold'); } else if (usertype == 'vip') { cb.sendNotice('VIP List member ' + anontipper + ' has been added to the ticket show list.', '', ticketBgColorVIP, ticketTxtColorVIP, 'bold'); } else if (usertype == 'mod') { cb.sendNotice('Moderator ' + anontipper + ' has been added to the ticket show list.', '', ticketBgColorMod, ticketTxtColorMod, 'bold'); } else { cb.sendNotice(anontipper + ' has been added to the ticket show list.', '', ticketBgColor, ticketTxtColor, 'bold'); } } else if (cb.settings.showTicketsAdded == 'Ticket Buyer') { if (usertype == 'fan') { cb.sendNotice('Welcome! As a Fan Club member, you have been added to the ticket show list.', addtktuser, ticketBgColorFan, ticketTxtColorFan, 'bold'); cb.sendNotice('Fan Club member ' + addtktuser + ' has been added to the ticket show list.', cb.room_slug, ticketBgColorFan, ticketTxtColorFan, 'bold'); cb.sendNotice('Fan Club member ' + anontipper + ' has been added to the ticket show list.', '', ticketBgColorFan, ticketTxtColorFan, 'bold', 'red'); } else if (usertype == 'vip') { cb.sendNotice('Welcome! As a VIP List member, you have been added to the ticket show list.', addtktuser, ticketBgColorVIP, ticketTxtColorVIP, 'bold'); cb.sendNotice('VIP List member ' + addtktuser + ' has been added to the ticket show list.', cb.room_slug, ticketBgColorVIP, ticketTxtColorVIP, 'bold'); cb.sendNotice('VIP List member ' + anontipper + ' has been added to the ticket show list.', '', ticketBgColorVIP, ticketTxtColorVIP, 'bold', 'red'); } else if (usertype == 'mod') { cb.sendNotice('Welcome! As a moderator, you have been added to the ticket show list.', addtktuser, ticketBgColorMod, ticketTxtColorMod, 'bold'); cb.sendNotice('Moderator ' + addtktuser + ' has been added to the ticket show list.', cb.room_slug, ticketBgColorMod, ticketTxtColorMod, 'bold'); cb.sendNotice('Moderator ' + anontipper + ' has been added to the ticket show list.', '', ticketBgColorMod, ticketTxtColorMod, 'bold', 'red'); } else { cb.sendNotice('Welcome! You have been added to the ticket show list.', addtktuser, ticketBgColor, ticketTxtColor, 'bold'); cb.sendNotice(addtktuser + ' has been added to the ticket show list.', cb.room_slug, ticketBgColor, ticketTxtColor, 'bold'); cb.sendNotice(anontipper + ' has been added to the ticket show list.', '', ticketBgColor, ticketTxtColor, 'bold', 'red'); } } countTicketsSold ++; break; } case 'rmv': { cb.limitCam_removeUsers([addtktuser]); if (cbjs.arrayContains(ticketShowViewerList,addtktuser)) { ticketShowViewerList.pop(addtktuser); } cb.sendNotice(anontipper + ' has been removed from the ticket show list.', '', ticketBgColor, ticketTxtColor, 'bold'); countTicketsSold --; break; } case 'addtip': { cb.limitCam_addUsers([addtktuser]); if (!cbjs.arrayContains(ticketShowViewerList,addtktuser)) { ticketShowViewerList.push(addtktuser); } if (cb.settings.showTicketsAdded == 'Everyone') { if (usertype == 'fan') { cb.sendNotice('Welcome Fan Club member ' + anontipper + ', you have been added to the ticket show list.', '', ticketBgColorFan, ticketTxtColorFan, 'bold'); } else if (usertype == 'vip') { cb.sendNotice('Welcome VIP List member ' + anontipper + ', you have been added to the ticket show list.', '', ticketBgColorVIP, ticketTxtColorVIP, 'bold'); } else if (usertype == 'mod') { cb.sendNotice('Welcome ' + anontipper + ', you have been added to the ticket show list.', '', ticketBgColorMod, ticketTxtColorMod, 'bold'); } else { cb.sendNotice('Welcome ' + anontipper + ', you have been added to the ticket show list.', '', ticketBgColor, ticketTxtColor, 'bold'); } } else if (cb.settings.showTicketsAdded == 'Ticket Buyer') { if (usertype == 'fan') { cb.sendNotice('Welcome! Thank you for buying a ticket, you have been added to the ticket show list.', addtktuser, ticketBgColorFan, ticketTxtColorFan, 'bold'); cb.sendNotice('Fan Club member ' + anontipper + ' has bought a ticket to the show.', cb.room_slug, ticketBgColorFan, ticketTxtColorFan, 'bold'); cb.sendNotice('Fan Club member ' + anontipper + ' has bought a ticket to the show.', '', ticketBgColorFan, ticketTxtColorFan, 'bold', 'red'); } else if (usertype == 'vip') { cb.sendNotice('Welcome! Thank you for buying a ticket, you have been added to the ticket show list.', addtktuser, ticketBgColorVIP, ticketTxtColorVIP, 'bold'); cb.sendNotice('VIP List member ' + anontipper + ' has bought a ticket to the show.', cb.room_slug, ticketBgColorFan, ticketTxtColorFan, 'bold'); cb.sendNotice('VIP List member ' + anontipper + ' has bought a ticket to the show.', '', ticketBgColorFan, ticketTxtColorFan, 'bold', 'red'); } else if (usertype == 'mod') { cb.sendNotice('Welcome! Thank you for buying a ticket, you have been added to the ticket show list.', addtktuser, ticketBgColorMod, ticketTxtColorMod, 'bold'); cb.sendNotice('Moderator ' + anontipper + ' has bought a ticket to the show.', cb.room_slug, ticketBgColorFan, ticketTxtColorFan, 'bold'); cb.sendNotice('Moderator ' + anontipper + ' has bought a ticket to the show.', '', ticketBgColorFan, ticketTxtColorFan, 'bold', 'red'); } else { cb.sendNotice('Welcome! Thank you for buying a ticket, you have been added to the ticket show list.', addtktuser, ticketBgColor, ticketTxtColor, 'bold'); cb.sendNotice(anontipper + ' has bought a ticket to the show.', cb.room_slug, ticketBgColorFan, ticketTxtColorFan, 'bold'); cb.sendNotice(anontipper + ' has bought a ticket to the show.', '', ticketBgColorFan, ticketTxtColorFan, 'bold', 'red'); } } countTicketsSold ++; if (tipamount >= (2*ticketPrice)) { addRmvTicket('addextra', addtktuser, 'common', (tipamount - ticketPrice), addtktuser); } break; } case 'addextra': { var numtickets = Math.floor(parseInt(tipamount / ticketPrice)); if (numtickets > 0) { if (!cbjs.arrayContains(ticketShowExtraTickets.name,addtktuser)) { ticketShowExtraTickets.name.push(addtktuser); ticketShowExtraTickets.count.push(numtickets); } else { index = ticketShowExtraTickets.name.indexOf(addtktuser); ticketShowExtraTickets.count[index] = ticketShowExtraTickets.count[index] + numtickets; } cb.sendNotice(addtktuser + ', you have purchased ' + numtickets + ' extra ticket(s) to the show. \nYou can gift a ticket to another user with the command /giftticket. \nEach time you use the command will use up one of your extra tickets. \nPlease make sure to spell the user name right, \ngifted tickets cannot be recovered if they are gifted incorrectly.', addtktuser, ticketBgColor, ticketTxtColor, "bold"); } break; } } } function checkCumulative(cumuser,cumamount,cumprice,usertype,saletype,anontipper) { if (cb.settings.hiddenShowCumulative == 'Yes') { if (!cbjs.arrayContains(ticketCumulative.name, cumuser)) { ticketCumulative.name.push(cumuser); ticketCumulative.amount.push(cumamount); } else { index = ticketCumulative.name.indexOf(cumuser); if (ticketCumulative.amount[index] + cumamount >= cumprice) { if (saletype == 'ticket') { addRmvTicket('addtip',cumuser,usertype,cumamount,anontipper); } else if (saletype == 'presale') { addRmvPresale('addtip',cumuser,0,anontipper); } ticketCumulative.amount[index] = 0; } else { ticketCumulative.amount[index] += cumamount; } } } } 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(dashLineTicket1 + '\n :siren1 *** The ticket show Tip goal has been met!! *** :siren1 \n*** Starting a 2 minute timer for automatic start of show! ***' + dashLineTicket2,"", ticketBgColor, ticketTxtColor, "bold"); ticketStartMode = 'timer'; ticketAutoTimer(2); } else if (ticketStartMode === 'ticketgoal' && ticketShowTotalTickets >= ticketShowGoalTickets) { cb.sendNotice(dashLineTicket1 + '\n :siren1 ** The ticket show Ticket goal has been met!! ** :siren1 \n*** Starting a 2 minute timer for automatic start of show! ***' + dashLineTicket2,"", ticketBgColor, ticketTxtColor, "bold"); ticketStartMode = 'timer'; ticketAutoTimer(2); } } function startTicketShow(startedby) { if (tokenPollToggle == 1) { if (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. \nYou can adjust the time remaining with the "/polladdtime [X]" command.', startedby, appNoticeColor); } 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, appNoticeColor); } pollSwitchToTimer(timetoadd, startedby); } } else { cb.sendNotice('Note: Poll Timer not started with /startshow per configuration.', startedby, appNoticeColor); } } var nowTime = new Date(); cb.sendNotice(dashLineTicket1 + '\n :siren1 :alert1 :siren1 ' + startedby + ' has started the hidden ticket show! :siren1 :alert1 :siren1 ' + dashLineTicket2, '', 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(dashLineTicket1 + '\n :siren1 :alert1 :siren1 ' + startedby + ' has restarted the hidden ticket show! :siren1 :alert1 :siren1 \n All current ticket holders still have access. \n Ticket sales are open, price is ' + ticketPrice + ' tokens.' + dashLineTicket2, '', ticketBgColor, ticketTxtColor, "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(dashLineTicket1 + '\n :siren1 :alert1 :siren1 ' + by + ' has indicated the show is nearly finished. :siren1 :alert1 :siren1 \n It is not recommended to buy a ticket, but sales are still open. \n The Ticket Price has been reduced to ' + ticketPrice + ' tokens! ' + dashLineTicket2, '', ticketBgColor, ticketTxtColor, 'bold'); } else { cb.sendNotice(dashLineTicket1 + '\n :siren1 :alert1 :siren1 ' + by + ' has indicated the show is nearly finished. :siren1 :alert1 :siren1 \n It is not recommended to buy a ticket, but sales are still open. ' + dashLineTicket2, '', ticketBgColor, ticketTxtColor, 'bold'); } } function stopTicketSales(stoppedby) { cb.sendNotice(dashLineTicket1 + '\n :siren1 :alert1 :siren1 \u25B7 \u25B7 ' + stoppedby + ' has ended the ticket show sales. \u25C1 \u25C1 :siren1 :alert1 :siren1 ' + dashLineTicket2, '', ticketBgColor, ticketTxtColor, 'bold'); showStage = 'showfinale'; changeTicketShowSubject(); ticketSalesEnded = true; } function stopTicketShow(stoppedby) { cb.sendNotice(dashLineTicket1 + '\n :siren1 :alert1 :siren1 ' + stoppedby + ' has ended the hidden ticket show :siren1 :alert1 :siren1 \n Ticket Show length ' + ((Date.now() - hiddenTime)/60000).toFixed(2) + ' minutes. \n The broadcast is returning to Public Chat.' + dashLineTicket2, '', ticketBgColor, ticketTxtColor, 'bold'); cb.limitCam_stop(); 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(gettimeuser) { cb.sendNotice('*** Hidden Cam show in progress for ' + ((Date.now() - hiddenTime)/60000).toFixed(2) + ' minutes. ***', gettimeuser, 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); } // *********************************** 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, appNoticeColor); } else { allTimeToggle = 1; allTimeTextColor = checkTextColor('Dark Blue',true); allTimeBgColor = checkBgColor('Light Yellow',true); initAllTimeNotice(); 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, appNoticeColor); } } else if(option == 'off') { if(allTimeToggle == 0) { cb.sendNotice('The All-Time Tipper List is already disabled.', mod, appNoticeColor); } else { allTimeToggle = 0; cb.sendNotice('You have disabled the All-Time Tipper List Notice.', mod, appNoticeColor); } } } function initAllTimeNotice() { if (isNaN(parseFloat(cb.settings.allTimeInterval))) { cb.sendNotice('Fembot: All-time Leaderboard notice interval is not set with a valid number so the All-time Leaderboard notice is not enabled.', cb.room_slug, appWarningColor); allTimeTimer = 0; } else { allTimeTimer = parseFloat(cb.settings.allTimeInterval); } if (allTimeTimer != 0) { if (allTimeTimer < 1) { cb.sendNotice('Fembot: All-time Leaderboard notice interval is too short, must be at least 1 minute. Using default value of 30.2 minutes.', cb.room_slug, appWarningColor); allTimeTimer = 30.2; } allTimeTimer = parseInt(allTimeTimer * 60000); cb.setTimeout(allTimeNoticeDisplay, allTimeTimer); } } function allTimeNoticeDisplay() { if (allTimeToggle == 1) { buildAllTimeArray(); displayAllTimeLeaders(''); cb.setTimeout(allTimeNoticeDisplay, allTimeTimer); } } 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, appNoticeColor); } 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, appNoticeColor); } 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]); allTimetotaltips = allTimeArray.totaltips[index] + tipCountArray.amount[i]; allTimeArray.totaltips[index] = allTimeArray.totaltips[index] + tipCountArray.amount[i]; } else { allTimeArray.totaltips.push(tipCountArray.amount[i]); allTimeArray.name.push(tipCountArray.name[i]); allTimetotaltips = tipCountArray.amount[i]; } if (cb.settings.joinVIPCumulativeAllTime > 0) { if (allTimetotaltips >= cb.settings.joinVIPCumulativeAllTime && !cbjs.arrayContains(VIPListArray, tipCountArray.name[i])) { addRmvVIP(tipCountArray.name[i],'a'); cb.sendNotice(tipCountArray.name[i] + ' has been added to the VIP list based on all-time tipping surpassing the configured amount (' + cb.settings.joinVIPCumulativeAllTime + ').', cb.room_slug, appNoticeColor); temptextcolor = checkTextColor('Dark Blue',true); tempbgcolor = checkBgColor('Light Blue',true); cb.sendNotice('Welcome ' + tipCountArray.name[i] + ' to the VIP list!', '', tempbgcolor, temptextcolor, 'bold'); } } } } sortAllTimeTippers(); if (kingTipperToggle == 2 && kingTipperName != allTimeArray.name[0]) { kingTipperName = allTimeArray.name[0]; kingTipperAmount = allTimeArray.totaltips[0]; } } } function displayAllTimeLeaders(sendto) { if (allTimeArray.name.length > 0) { var alltimeleadersize = allTimeArray.name.length; if (alltimeleadersize > 10) { alltimeleadersize = 10; } var alltimemsg = ':crowngold :crownsilver Top All-time Tippers :crownsilver :crowngold' for (var datidx = 0; datidx < alltimeleadersize; datidx++) { if (allTimeArray.name[datidx]) { alltimemsg += '\n' + (datidx+1) + '. ' + allTimeArray.name[datidx] + ' : ' + allTimeArray.totaltips[datidx] + ' tokens'; } } alltimemsg += '\n:crowngold :crownsilver :crowngold :crownsilver :crowngold :crownsilver :crowngold :crownsilver '; if (minTimeForNotice > 0) { // checkNoticeFrequency(alltimemsg, sendto, allTimeBgColor, allTimeTextColor, 'bold', ''); } else { cb.sendNotice(alltimemsg, 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, appNoticeColor); 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, appNoticeColor); } 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 *** ' + bctext + ' has started a private show ***\n' + dashLine80, '', ticketBgColor, ticketTxtColor, '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 *** ' + bctext + ' has ended the private show ***\n' + dashLine80, '', ticketBgColor, ticketTxtColor, 'bold'); cb.limitCam_stop(); cb.changeRoomSubject("Welcome to our room."); isPrivate = false; } // *********************************** Help Function ************************************** function displayAbout(sendtoabout) { var aboutmessage = '\u26D4 Version 4.2 was released on March 22, 2021 \u26D4'; aboutmessage += '\n \u2705 Dorothy\'s Ultra Fembot was written by CB users chelsea2950 and butter_my_toast'; aboutmessage += '\n \u2705 Comments, suggestions, requests, and bug reports can be made by either tweeting @thechelsea2950, or by posting comments on bot help page.'; aboutmessage += '\n \u2705 The purpose of this Ultra/All in one Bot is to serve as a single tool that experienced cammers can use for most of the common functions needed during a show.'; aboutmessage += '\n \u2705 You can type "/fbhelp" to display the command list summary, and use one of the group qualifiers to see more details within a group, such as "/fbhelp tokenpoll"'; aboutmessage += '\n \u2705 The bot description page includes extensive details on bot features, icon and emoji usage, moderator trust levels, commands and recent release notes:'; aboutmessage += '\n https://chaturbate.com/apps/app_details/dorothys-ultra-fembot/ '; aboutmessage += '\n \u2705 Highlights of fixes and improvements in the version are below. To review notes on previous releases, please see the Release Notes section at the bottom of the bot description page, linked above:'; aboutmessage += '\n Version 4.2 (current version):'; aboutmessage += '\n - Reformatted the Fembot ticket show recurring notice, corrected color themes used on Fembot ticket show notices and other messaging'; aboutmessage += '\n - *** New Feature - Added option to make the border for recurring notices configurable. You can now specify no border, light dash line, heavy dash line, custom emoji, custom unicode character (setting "0H1"). Existing emoji value from previous version becomes setting "0H2" and is triggered by the "custom" settings in "0H1".'; aboutmessage += '\n - Added several more pre-defined tip menu separator icons (for tip menu in setting "11E1" and positions menu in "12D"). Emphasized that emojis can be used for these. '; aboutmessage += '\n - Added version and release note information in the "/fbhelp about" or "/about" commands to display app version currently running, with latest release notes.'; aboutmessage += '\n - *** New Feature - Added section 21 for Text Polls. Use this to conduct a poll without requiring tipping (more people in the room can/will participate). Define the poll options on bot launch or later with commands.'; aboutmessage += '\n - Don\'t clear the poll options when the poll is turned on and off, only when resetting the poll by command. Poll can be turned on and off without losing voting options and progress (suspended). '; aboutmessage += '\n - Added setting "12D3" for including the separator character from the positions tip menu also in the positions tip menu response notice to make it stand out. Defaults to No, must be enabled.'; cb.sendNotice(aboutmessage, sendtoabout, appWarningColor); } function helpCommon(option,from) { if(option == null){option = '';} cb.sendNotice('Dorothy\'s Fembot Help Menu', from, appNoticeColor); cb.sendNotice('',from,appNoticeColor); 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.' + '\n/posmenu: Display the positions tip menu at any time in the chat.' + '\n/timeleft: Display the time left on a timed countdown clock.' + '\n/leaders: Display the tip leaderboard at any time in the chat.' + '\n/poll: Display the current results of the token poll at any time in the chat.' + '\n/toymenu: Display the interactive toy tip menu at any time in the chat.' + '\n/media: Display the broadcaster media list at any time in the chat.' + '\n/top10 (or /alltimetop10, or /dsptop10): Display a listing of the top 10 all-time tippers.' + '\n/prizes: Display the dice game prizes menu at any time in the chat.' ,from); cb.sendNotice('',from,appNoticeColor); } 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, appNoticeColor); 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( '"messaging" : (/pm, /reply, /bc, /tm, /tbm)' + '\n"chatcontrol" : (/silencelevel, /graphiclevel, /ninja, /unninja, /ninjalist, /silence, /unsilence, /silencelist, /showninja, /showsilence)' + '\n"tipmenu" : (/tipmenu, /tipmenurequests or /tmr, /tipmenuadd, /tipmenurmv, /usemenu, /swapmenu)' + '\n"positions" : (/posmenu, /posmenurequests, /posmenuadd, /posmenurmv, /useposmenu)' + '\n"timer" : (/startclock, /addtoclock, /timeleft, /stopclock)' + '\n"notices" : (/cn, /cnh, /cnd, /cndh, /usenotifier, /chgmsg1.../chgmsg8, /dspmsg1.../dspmsg8, dspallmsg, /leaders, /useleaderboard, /usetipcount, /tippers, /userules, /rsp1, /rsp2, /rsp3, /rsp4, /rsp5, /dsprsp)' + '\n"viewernotes" : (/addnote, /notelist, /shownote)' + '\n"tokenpoll" : (/poll, /usepoll, /endpoll, /restartpoll, /resetpoll, /addvote, /polloptadd, /polloptrmv, /pollstarttimer, /polladdtime, /pollstoptimer, /polllead, /makepoll, /odstart, /odoff, /hijackprice, /polltimeleft)' + '\n"textpoll" : (/textpoll, /usetextpoll, /endtextpoll, /restarttextpoll, /resettextpoll, /addtextvote, /textoptadd, /textoptrmv, /textstarttimer, /textaddtime, /textstoptimer, /textlead, /textchgtitle, /texttimeleft)' + '\n"nicelist" : (/addnice, /rmvnice, /nicelist)' + '\n"viplist" : (/addvip, /rmvvip, /viplist, /setvipicon)' + '\n"fans" : (/addfan, /rmvfan, /fanlist, /addfan2, /rmvfan2, /fanlist2, /setfanicon, /setextfanicon, /setextfan2icon)' + '\n"botmods" : (/addmod, /rmvmod, /modlist, /setmodicon, /setbotmodicon)' + '\n"wordlist" : (/addword, /rmvword, /wordlist, /wordlistprv)' + '\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" : (/toymenu, /chgtoy, /usetoy, /uselush, /usedomi, /usenora, useferri, /useosci)' + '\n"media" : (/media, /usemedia)' + '\n"dice" : (/prizes, /usedice, /chgdiceprice, /dicerolls)' + '\n"alltime" : (/usealltime, top10, /alltime, /useking, /king)' + '\n"private" : (/startprivate, /stopprivate)' + '\n"followers" : (/followers, /fmt, /fc)' + '\n"other" : (/newsubject, /settings, /checkcolor, /prv, /pricechecklist, /nocaps, /nnlist, /setusericon, /setusernn, /setusercolor, /icontips, /chgint, /setemjsep)' + '\n"about"' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'other': { valid = 1; cb.sendNotice('Fembot Command List',from,appNoticeColor); 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 current user... mainly for troubleshooting.' + '\n/pricechecklist: Display a listing of all current price check entries.' + '\n/nocaps [on/off]: Toggle the control for suppressing all CAPS words.' + '\n/prv: Display the "Private Request Response" message that is configured on the launch page.' + '\n/nnlist: display a listing of the user specific icons, nick names, and text colors.' + '\n/icontips: on-demand display of the table of icon tip amounts and associated icons to the general chat.' + '\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.' + '\n/setemjsep [emoji]: (mods/bc only) Updates the emoji used for the border of the recurring notices for token poll, dice game, leaderboard, media list, and room rules. if you do not want to use an emoji, you can type in two caracters of text like "--" or "**" (no quotes)' + '\n/chgint [notice type] [new interval]: This command requires two parameters, to define the notice type, and to define the new interval (in minutes), in the format "/chgint [notice type] [new interval]". The [notice type] is one of the values of "notifier", "tipmenu", "posmenu", "poll", "leaders", "alltime", "ticket", "presale", "rules", "media", "toy", "icon", "king", or "dice". The [new interval] is the new display interval in minutes. An example of a valid command would be "/chgint tipmenu 3.2" to update the tip menu interval to 3.2 minutes.' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'alltime': { valid = 1; cb.sendNotice('Fembot Command List',from,appNoticeColor); cb.sendNotice('All-time Highest Tippers - ' + '\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 launch page 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/useking [0/1/2]: (mods/bc only) Toggle the setting for whether the All-Time King Tipper features are off (parameter="0"), pulled from the configured name or name updated via command (parameter="1"), or pulled from the all-time list (parameter="2"). Overrides the initial setting, and allows you to turn the feature on or off during the show. Note that it cannot be enabled if a King Tipper is not already identified, either from the setting in the bot, or the All Time list. The below command can be used to define the King Tipper during the show.' + '\n/king [amt] [name]: (mods/bc only) Update the king tipper user name and amount, overriding the settings from the launch page. A parameter is required for both the amount and the user, but the amount can be zero if you would not like to show the amount.' + '\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,appNoticeColor); break; } case 'notes': case 'viewernotes': { valid = 1; cb.sendNotice('Fembot Command List',from,appNoticeColor); cb.sendNotice('Viewer Notes - ' + '\n/addnote username text: (bc only) The command is entered where "username" is the CB user ID, and "text" is the free form text note you would like to add. If there is already an entry for the username, the new text will be appended to the end. Note this entry is not saved beyond the current show, so make sure to use the "/notelist" command at the end of the show and copy your notes so they can be entered on the launch page for next start (setting 6A).' + '\n/shownote username: (bc only) Display the notes that you have recorded for one specific viewer.' + '\n/notelist: (bc only) Display a list of all of the notes that you have recorded for viewers. In addition to the username and corresponding note, it will also show whether the note was added/updated in the current show so you know to copy it to the launch page for next time, and whether it has been displayed already during this session.' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'private': { valid = 1; cb.sendNotice('Fembot Command List',from,appNoticeColor); 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,appNoticeColor); break; } case 'followers': { valid = 1; cb.sendNotice('Fembot Command List',from,appNoticeColor); cb.sendNotice('Follower Tracking - ' + '\n/followers: (bc and mods) Display the follower stats for the current show on-demand' + '\n/fc: (all users) Display the total number of followers to the requesting user' + '\n/fmt [newtype]: (bc and mods) Update the flag for which type of messaging is used for each follow: Valid values are "0" for no message, "1" for message to follower only, "2" for message to broadcaster only, and "3" for message to both.' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'ticketsupport': { valid = 1; cb.sendNotice('Fembot Command List',from,appNoticeColor); 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.' + '\n- This 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,appNoticeColor); break; } case 'ticketshow': { valid = 1; cb.sendNotice('Fembot Command List',from,appNoticeColor); cb.sendNotice('Fembot Ticket Show Commands - these are used specifically for the Fembot Ticket show, not for the external 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 commas. ' + '\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 get 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 Ticket 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 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 ticket show start when in "timer" mode.' + '\n/addtime (or /ticketaddtime, or /addtickettime) [time]: (mods/bc only) Add [time] minutes to the ticket show start timer. 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 ticket timer.' + '\n/tickettimeleft : (mods/bc only) Display the time left on the ticket show countdown.' + '\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 not 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. ' + '\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,appNoticeColor); break; } case 'presales': { valid = 1; cb.sendNotice('Fembot Command List',from,appNoticeColor); cb.sendNotice('Ticket Show Pre-sales commands - ' + '\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 Pre-sale price to [price] tokens. This is the initial pre-sale price before automated 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, for either the automatic timer, or a manually started timer.' + '\n/presaleaddtime [time]: Add [time] minutes to the pre-sale timer, for either the automatic timer, or a manually started timer.' + '\n/presaletimeleft: Display the time left on the current timer, for 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 changed during the show to "manual", "timer", or "count".' + '\n- Manual 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).' + '\n- Timer 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.' + '\n- Count 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,appNoticeColor); break; } case 'messaging': { valid = 1; cb.sendNotice('Fembot Command List',from,appNoticeColor); cb.sendNotice('Private Messaging commands - ' + '\n/pm: This command is usable by moderators and broadcasters to send an in-chat PM (Private Message) to a specific user (rather than having to use a separate tab).' + '\n- The 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.' + '\n- A related command is /reply.' + '\n/reply: This command is usable by everyone once they have received a PM from a moderator or broadcaster.' + '\n- The 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.' + '\n- You should be careful using this to ensure the last person that PMd you is the person you are intending to reply to.' + '\n- Alternatvely, a new PM can be sent using the /pm command rather than reply if you are not sure who last PMd you.' + '\n/bc: This command is usable by moderators to send a PM specifically to the broadcaster.' + '\n- The 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.' + '\n- The 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.' + '\n- The syntax for using this type of PM is "/tbm [X]", where [X] is the message you want to send.' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'timer': { valid = 1; cb.sendNotice('Fembot Command List',from,appNoticeColor); cb.sendNotice('Timer / Clock commands - ' + '\n/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.' + '\n/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.' + '\nTimer #2: ' + '\n/startclock2 [time] [description]: This command is usable by moderators and broadcasters to start Timer #2 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.' + '\n/addtoclock2: This command is usable by moderators and broadcasters to add time to (or subtract time from) an existing Timer #2 countdown.' + '\n/timeleft2: This command will display the amount of time left in the Timer #2 countdown.' + '\n/chgclock2desc [newtext]: change the text used in the Timer #2 description to the new value [newtext], overrides the initial value set on the launch page.' + '\n/stopclock2: This command will end the Timer #2 countdown.' + '\nTimer #3: ' + '\n/startclock3 [time] [description]: This command is usable by moderators and broadcasters to start Timer #3 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.' + '\n/addtoclock3: This command is usable by moderators and broadcasters to add time to (or subtract time from) an existing Timer #3 countdown.' + '\n/timeleft3: This command will display the amount of time left in the Timer #3 countdown.' + '\n/chgclock3desc [newtext]: change the text used in the Timer #3 description to the new value [newtext], overrides the initial value set on the launch page.' + '\n/stopclock3: This command will end the Timer #3 countdown.' + '\nTimer #4: ' + '\n/startclock4 [time] [description]: This command is usable by moderators and broadcasters to start Timer #4 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.' + '\n/addtoclock4: This command is usable by moderators and broadcasters to add time to (or subtract time from) an existing Timer #4 countdown.' + '\n/timeleft4: This command will display the amount of time left in the Timer #4 countdown.' + '\n/chgclock4desc [newtext]: change the text used in the Timer #4 description to the new value [newtext], overrides the initial value set on the launch page.' + '\n/stopclock4: This command will end the Timer #4 countdown.' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'notices': { valid = 1; cb.sendNotice('Fembot Command List',from,appNoticeColor); cb.sendNotice('Notices - ' + '\n/cn: This command is usable by moderators and the broadcaster to post a plain notification without any separators or highlighting.' + '\n- The syntax for using this type of notice is "/cn [X]", where [X] is the message you want to send.' + '\n/cnd: This command is usable by moderators and the broadcaster to post a notification that includes a dash separator above and below the message, but no highlighting.' + '\n- The syntax for using this type of notice is "/cnd [X]", where [X] is the message you want to send.' + '\n/cnh: This command is usable by moderators and the broadcaster to post a notice that includes highlighting, but no separators.' + '\n- The syntax for using this type of notice is "/cnh [X]", where [X] is the message you want to send.' + '\n/cndh: This command is usable by moderators and the broadcaster to post a notice that includes both separators and highlighting.' + '\nThe syntax for using this type of notice is "/cndh [X]", where [X] is the message you want to send.' + '\n/userules: This command is usable by moderators and broadcasters to toggle "on" or "off" the display of the Room Rules, both as an entry message and as a recurring notice.' + '\n/usenotifier: This command is usable by moderators and broadcasters to toggle "on" or "off" the display of the periodic notification messages defined on the launch page or with the below commands.' + '\n/chgmsg1 [msg] (also /chgmsg2 - /chgmsg8): update the notifier message in Slot 1-8 to a new value of [msg].' + '\n/dspmsg1 (also /dspmsg2 - /dspmsg8): display the notifier message in Slot 1-8; If the "all" parameter is specified after the command, the requested message is sent to the general chat and formatted like a standard Chat Notifier message. If "all" is not specified, it is only sent to the requester, and formatted as a bot notice.' + '\n/dspallmsg: Display the current value for all of the messages in notifiers 1-8.' + '\n/rsp1: Display the response message 1 in the chat, viewable by all.' + '\n/rsp2: Display the response message 2 in the chat, viewable by all.' + '\n/rsp3: Display the response message 3 in the chat, viewable by all.' + '\n/rsp4: Display the response message 4 in the chat, viewable by all.' + '\n/rsp5: Display the response message 5 in the chat, viewable by all.' + '\n/dsprsp: Display all 5 of the available command triggered responses (for /rsp1, /rsp2, /rsp3, /rsp4, /rsp5) and the 5 automated keyword responses. Summary is only sent to the user requesting them, used as a reminder of the current settings.' + '\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.' + '\n- The syntax for using leaderboard is "/leaders" to send to yourself. Moderators and broadcasters can use "/leaders all", "/leaders mods" or "/leaders bc".' + '\n- This 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 "on" or "off" the display of the leaderboard in the chat per the defined interval. The 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 "on" or "off" the display of the user\'s tip count at the beginning of their chat messages. Note 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 X tippers of the current session with the default delivery displaying the top 20.' + '\n- The command format should be /tippers [number] [sendto], where [number] is the number of entries to display, and [sendto] is the value for who to send it to, and can be "mods" for the moderator group, "bc" for only the broadcaster, "tbm" for the moderators and the broadcaster, "all" for the whole room, and blank for only yourself.' + '\n- Using the command with no paramters would result in the top 20 entries being sent only to the requesting user.' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'chat': case 'chatcontrol': { valid = 1; cb.sendNotice('Ultra Fembot help for Chat Control Commands:',from,appNoticeColor); cb.sendNotice( '/silencelevel (also /sl): 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 4.' + '\n0 = chat privileges to all users' + '\n1 = remove chat privileges from users without tokens' + '\n2 = remove chat privileges from users who have not tipped' + '\n3 = remove chat privileges from users who have not tipped the minimum configured tokens.' + '\n4 = allow only mods, fans, and VIPs to chat.' + '\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 (also (/gl): 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 4.' + '\n0 = grant graphic usage privileges to all users, ' + '\n1 = revoke graphic usage privileges from users who do not have tokens, ' + '\n2 = revoke graphic usage privileges from users who have not tipped, ' + '\n3 = revoke graphic usage privileges from users who have not tipped the minimum configured tokens.' + '\n4 = revoke graphic usage privileges from all users other than mods, fans, and VIPs.' + '\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,appNoticeColor); break; } case 'tipmenu': { valid = 1; cb.sendNotice('Ultra Fembot help for Tip Menu Commands:',from,appNoticeColor); cb.sendNotice( '/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 (or /tmr): Show recent tip menu requests, defaults to a maximum of the 10 most recent when no quantity is entered. When requested by a moderator it is sent to all users, otherwise just the requester' + '\n/tipmenurequests X: Show the last "X" requests.' + '\n/tipmenurequests all: Show all the requests (maximum of 100).' + '\n/tipmenuprice X Y: Updates a menu item with description of "Y" to "X" tokens. Description entered for "Y" must be an exact match of the text in the menu.' + '\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.' + '\n/tipmenumod: The broadcaster can use this command to see the same tip menu that the mod group sees if there is a moderator discount percentage (Moderators will just use the /tipmenu command).'+ '\n/tipmenufan: Moderators and the broadcaster can use this command to see the same tip menu that the CB Fanclub group sees if there is a CB Fanclub discount percentage or group specific menu items (CB Fanclub will just use the /tipmenu command).'+ '\n/tipmenufc1: Moderators and the broadcaster can use this command to see the same tip menu that the Ext Fanclub 1 group sees if there is a Ext Fanclub 1 discount percentage or group specific menu items (Ext Fanclub 1 members will just use the /tipmenu command).'+ '\n/tipmenufc2: Moderators and the broadcaster can use this command to see the same tip menu that the Ext Fanclub 2 group sees if there is a Ext Fanclub 2 discount percentage or group specific menu items (Ext Fanclub 2 members will just use the /tipmenu command).'+ '\n/tipmenuvip: Moderators and the broadcaster can use this command to see the same tip menu that the VIP group sees if there is a VIP discount percentage (VIPs will just use the /tipmenu command).' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'positions': { valid = 1; cb.sendNotice('Ultra Fembot help for Tip Menu Commands:',from,appNoticeColor); cb.sendNotice( '/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,appNoticeColor); break; } case 'tokenpoll': { valid = 1; cb.sendNotice('Ultra Fembot help for Token Poll Commands:',from,appNoticeColor); 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/resetpoll: (mods/bc only) This will reset the poll to the beginning and start the voting at 0 for the same poll options.' + '\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/pollchgtitle [new title]: (mods/bc only) Update the text of the token poll title to [new title].' + '\n/polllead (or /pl): (all users) Display only the notice for the current leader of the poll. When requested by mods or broadcaster, the notice is sent to all.' + '\n/hijackprice [newprice]: (mods/bc only) Update the price for hijacking the poll. Note that updating it to 0 will disable the hijack feature.' + '\nON DEMAND POLL:' + '\n/makepoll X Y: (mods/bc only) Adds a new option to the on-demand poll with a price of X and decription/name of Y. Note that the options are not part of the actual poll (viewers cannot see them, they do not show up with the "/poll" command) until you use the command /odstart to start the poll.' + '\n/odstart: (mods/bc only) Start the on-demand poll, viewers can now see the optionsand vote.' + '\n/odoff: (mods/bc only) Disables the on-demand poll so that the pre-configured poll can be used (or a new on-demand poll can be started).' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'textpoll': { valid = 1; cb.sendNotice('Ultra Fembot help for Text Poll Commands:',from,appNoticeColor); cb.sendNotice( '/textpoll: (all users) Display the current text poll results board in the chat for the requesting user. Displayed to all when requested by moderators.' + '\n/usetextpoll [on/off]: (mods/bc only) Toggle the setting for whether the Text Poll is "on" or "off". Overrides the initial setting to turn the Text Poll on or off during the show.' + '\n/endtextpoll: (mods/bc only) When running under manual control, end the text poll and display the winner.' + '\n/restarttextpoll: (mods/bc only) If the text poll is accidentally ended, or suspended, it can be restarted using this command. This does not reset the votes.' + '\n/resettextpoll: (mods/bc only) This will reset the poll to the beginning and start the voting at 0 for the same poll options.' + '\n/addtextvote X Y: (mods/bc only) Add or remove "Y" number of votes to the poll item with a choice ID 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/textoptadd X Y: (mods/bc only) Add an item named "Y" with a chice ID of "X" tokens to the poll.' + '\n/textoptrmv X: (mods/bc only) Will remove any item with a choice ID of "X" from the text poll. Note this will renumber the choice IDs after the indicated one is removed.' + '\n/textstarttimer X: (mods/bc only) Starts a timer for "X" minutes for the text poll when run under timed mode. Poll will automatically end when time runs out.' + '\n/textaddtime X: (mods/bc only) Adds "X" minutes to the text poll timer if a timer is running.' + '\n/textstoptimer: (mods/bc only) Ends the text poll timer if running under timed mode.' + '\n/textchgtitle [new title]: (mods/bc only) Update the text of the text poll title to [new title].' + '\n/textlead (or /pl): (all users) Display only the notice for the current leader of the poll. When requested by mods or broadcaster, the notice is sent to all.' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'nicelist': { valid = 1; cb.sendNotice('Ultra Fembot help for Timer Commands:',from,appNoticeColor); 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,appNoticeColor); break; } case 'viplist': { valid = 1; cb.sendNotice('Ultra Fembot help for VIP List Commands:',from,appNoticeColor); 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/setvipicon: Update the group icon used for VIPs to a new value. A value of "null" can be used to clear the existing setting. ' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'fans': { valid = 1; cb.sendNotice('Ultra Fembot help for External Fan Club List Commands:',from,appNoticeColor); 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/addfan2: Same as /addfan above but for External Fan Club 2.' + '\n/rmvfan2: Same as /rmvfan above but for External Fan Club 2.' + '\n/fanlist2: Display the list of users in External Fan Club 2.' + '\n/setfanicon: Update the group icon used for CB Fanclub to a new value. A value of "null" can be used to clear the existing setting. ' + '\n/setextfanicon: Update the group icon used for External Fan Club to a new value. A value of "null" can be used to clear the existing setting. ' + '\n/setextfan2icon: Update the group icon used for External Fan Club to a new value. A value of "null" can be used to clear the existing setting. ' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'botmods': { valid = 1; cb.sendNotice('Ultra Fembot help for Bot Moderators:',from,appNoticeColor); 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).' + '\n/setmodicon: Update the group icon used for CB Moderators to a new value. A value of "null" can be used to clear the existing setting. ' + '\n/setbotmodicon: Update the group icon used for Bot Moderators to a new value. A value of "null" can be used to clear the existing setting. ' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'wordlist': { valid = 1; cb.sendNotice('Ultra Fembot help for Blocked Word List Commands:',from,appNoticeColor); cb.sendNotice( '/addword: This command is usable by broadcasters and moderators only. Note that words can only be added to the Public Blocked word list during a show. Words must be added to the Private blocked word list on the launch page.' + '\nThe syntax for using the command is "/addword [X]", where [X] is the word you want to add to the Public Blocked Word list.' + '\nAdding a word to the Public Blocked Word list will cause any chat message containing that word to be blocked and not posted to the chat, and the user will receive a notice.' + '\nWords can be removed from the Public Blocked Word list by using the command /rmvword.' + '\n/rmvword: This command is usable by broadcasters and moderators only. When used by a moderator, it will remove words from the Public word list. When used by a broadcaster, it will remove words from both the Public and Private lists.' + '\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 Public Blocked Word list, available to mods and broadcasters.' + '\n/wordlistprv: Displays the list of words currently in the Private Blocked Word list, available only to broadcasters.' ,from); cb.sendNotice('',from,appNoticeColor); break; } case 'lush': { valid = 1; cb.sendNotice('Ultra Fembot help for Toy Menu Commands:',from,appNoticeColor); cb.sendNotice( '/toymenu: 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", "ferri", or "osci". The new name will then be displayed in all chat messaging. Can also use a specific command of /uselush, /usenora, /usedomi, /usehush, /useferri, or /useosci to set the toy.' + '\n/usetoy [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,appNoticeColor); break; } case 'media': { valid = 1; cb.sendNotice('Ultra Fembot help for Media List Commands:',from,appNoticeColor); cb.sendNotice( '/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,appNoticeColor); break; } case 'dice': { valid = 1; cb.sendNotice('Ultra Fembot help for Dice Game Commands:',from,appNoticeColor); cb.sendNotice( '/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,appNoticeColor); break; } case 'about': { valid = 1; displayAbout(from); 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,appNoticeColor); } } } } // ******************************* Upon user entry of a Message ************************************** { cb.onMessage(function (msg) { var message = msg['m'].split(' '); var cmd = 0; var listRegExp = /[,\s]+/; var listRegExpSpc = /[,]+/; var m = msg.m; var u = msg.user; var isMod = msg.is_mod; var isCBMod = msg.is_mod; var isModLvlMsg1 = false; var isModLvlMsg2 = false; var isModLvlMsg3 = false; 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 isFanMsg = msg.in_fanclub; var isExtFanMsg = cbjs.arrayContains(extFanListArray,u); var isExtFanMsg2 = cbjs.arrayContains(extFanList2Array,u); var isVIPMsg = cbjs.arrayContains(VIPListArray,u); var isNice = cbjs.arrayContains(niceListArray, u); var messageArrayBuilt = false; if (msg['X-Spam'] != true && minMessagesForNotice > 0) { msgCounterTipMenu++; msgCounterPosMenu++; msgCounterLushMenu++; msgCounterDice++; msgCounterNotifier++; msgCounterTokenPoll++; msgCounterLeaderboard++; msgCounterRules++; msgCounterMedia++; msgCounterPresales++; msgCounterIconNotice++; msgCounterKing++; msgCounterKingSession++; } 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; } else if (moderatorList.type[nameIndex] == 'cbmod') { populateModeratorArray(u,'cbmod','r'); } } } if (isMod) { isModLvlMsg1 = true; if (cb.settings.modLevel == 'Standard') { isModLvlMsg2 = true; } else if (cb.settings.modLevel == 'Advanced') { isModLvlMsg2 = true; isModLvlMsg3 = true; } } if (isVIPMsg && !cbjs.arrayContains(VIPInShowArray,u)) { VIPInShowArray.push(u); } if (isExtFanMsg && !cbjs.arrayContains(extFanInShowArray,u)) { extFanInShowArray.push(u); } if (isExtFanMsg2 && !cbjs.arrayContains(extFanInShow2Array,u)) { extFanInShow2Array.push(u); } if (isFanMsg) { populateFanClubArray(u); } if (viewerNotesWhen == 'First Chat' && cbjs.arrayContains(viewerNotesArray.username,u)) { noteIndex = viewerNotesArray.username.indexOf(u); if (!viewerNotesArray.displayed[noteIndex]) { cb.sendNotice('Fembot Viewer Notes for ' + viewerNotesArray.username[noteIndex] + ': ' + viewerNotesArray.notes[noteIndex], BC, '', '', 'bold'); viewerNotesArray.displayed[noteIndex] = true; if (viewerNotesWho == 'Display to Broadcaster and Moderators') { cb.sendNotice('Fembot Viewer Notes for ' + viewerNotesArray.username[noteIndex] + ': ' + viewerNotesArray.notes[noteIndex], '', '', '', 'bold', 'red'); } } } var command = message[0] var commandVar1 = parseInt(message[1]); var commandVar2 = parseInt(message[2]); if (message[0].charAt(0) != '/') { if (requireAnswerToggle == 1 && !isBC && !isModLvlMsg1 && !isFanMsg && !isExtFanMsg && !isExtFanMsg2 && !isVIPMsg) { 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, appNoticeColor, '', '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, appWarningColor, '', 'bold'); msg['X-Spam'] = true; } } } } } if (textPollToggle) { var tpfirstbyte = message[0].charAt(0); if (tpfirstbyte >= '1' && tpfirstbyte <= '5') { var tpfirstbyteN = parseInt(tpfirstbyte); if (cbjs.arrayContains(textPollArray.voteID,tpfirstbyteN)) { if (cbjs.arrayContains(textPollUsersVoted,u)) { cb.sendNotice('Fembot: You have already voted in the poll, you cannot vote again.', u, textPollBgColor, textPollTextColor, 'bold'); } else { var textpollamt = 1; if (isFanMsg && textPollFanDouble) { textpollamt = 2; cb.sendNotice('Since you are a member of the fan club, your vote is doubled!', u, textPollBgColor, textPollTextColor, 'bold'); } textPollVote(tpfirstbyteN,textpollamt,u); } } } } if (message[0].charAt(0) == '/') { msg['X-Spam'] = true; //******** Chat Control Commands *********** switch(command) { case '/sl': case '/silencelevel': { cmd = 1; if (isModLvlMsg2 || isBC) { if (message[1]) { numlevel = parseInt(message[1]); if (isNaN(numlevel)) { cb.sendNotice('The parameter entered for the /silencelevel command is not numeric, please try again (0=All users can chat,1=Users with tokens can chat,2=Users who have tipped can chat,3=Users who have tipped the minimum can chat,4=Mods, Fans and VIPs can chat).', u, appNoticeColor); } else if (numlevel < 0 || numlevel > 4) { cb.sendNotice('The parameter entered for the /silencelevel command is outside allowable values from 0 to 4, please try again (0=All users can chat,1=Users with tokens can chat,2=Users who have tipped can chat,3=Users who have tipped the minimum can chat,4=Mods, Fans and VIPs can chat).', u, appNoticeColor); } else if (numlevel == silenceLevel) { cb.sendNotice('The current silence level is already set to ' + silenceLevel + '.', u, appNoticeColor); } else { setSilenceLevel(numlevel, u); } } else { cb.sendNotice('Fembot: The parameter was not entered for the /silencelevel command, please try again (0=All users can chat,1=Users with tokens can chat,2=Users who have tipped can chat,3=Users who have tipped the minimum can chat,4=Mods, Fans and VIPs can chat).', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/gl': case '/graphicslevel': case '/graphiclevel': { cmd = 1; if (isModLvlMsg2 || isBC) { if (message[1]) { numlevel = parseInt(message[1]); if (isNaN(numlevel)) { cb.sendNotice('The parameter entered for the /graphiclevel command is not numeric, please try again (0=All users can post graphics,1=Users with tokens can post graphics,2=Users who have tipped can post graphics,3=Users who have tipped the minimum can post graphics,4=Mods, Fans and VIPs can post graphics).', u, appNoticeColor); } else if (numlevel < 0 || numlevel > 4) { cb.sendNotice('The parameter entered for the /graphiclevel command is outside allowable values from 0 to 4, please try again (0=All users can post graphics,1=Users with tokens can post graphics,2=Users who have tipped can post graphics,3=Users who have tipped the minimum can post graphics,4=Mods, Fans and VIPs can post graphics).', u, appNoticeColor); } else if (numlevel == graphicLevel) { cb.sendNotice('The current graphics level is already set to ' + graphicLevel + '.', u, appNoticeColor); } else { setGraphicLevel(numlevel, u); } } else { cb.sendNotice('Fembot: The parameter was not entered for the /graphiclevel command, please try again (0=All users can post graphics,1=Users with tokens can post graphics,2=Users who have tipped can post graphics,3=Users who have tipped the minimum can post graphics,4=Mods, Fans and VIPs can post graphics).', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/chplay': { cmd = 1; if (isModLvlMsg1 || 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, appNoticeColor); } break; } case '/charades': { cmd = 1; if (message[1] == 'off') { if (isModLvlMsg1 || isBC) { suppressPrefix = false; cb.sendNotice('Fembot: Message prefixes (icons, tip count, etc) have been re-enabled.', u, appNoticeColor); } } break; } case '/minmsg': { cmd = 1; if (isModLvlMsg2 || isBC) { nummsg = parseInt(message[1]); if (isNaN(nummsg)) { cb.sendNotice('The parameter entered for the /minmsg command is not numeric, please try again. Setting the value to 0 will disabled the minimum message count check. A value of 25 is commonly used but may be set lower if the chat is slow, or higher if the chat is busy.', u, appNoticeColor); } else { minMessagesForNotice = nummsg; cb.sendNotice('The minimum number of chat messages required before a recurring notice is displayed has been updated to ' + nummsg + '.', u, appNoticeColor); if (u != BC) { cb.sendNotice('The minimum number of chat messages required before a recurring notice is displayed has been updated to ' + nummsg + ' by ' + u + '.', BC, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/chgint': { cmd = 1; if (isBC || isModLvlMsg1) { newtimer = parseFloat(message[2]); if (message[1]) { intervaltochange = message[1].toLowerCase(); if (intervaltochange != 'notifier' && intervaltochange != 'tipmenu' && intervaltochange != 'posmenu' && intervaltochange != 'poll' && intervaltochange != 'leaders' && intervaltochange != 'alltime' && intervaltochange != 'ticket' && intervaltochange != 'presale' && intervaltochange != 'rules' && intervaltochange != 'media' && intervaltochange != 'toy' && intervaltochange != 'dice' && intervaltochange != 'icon' && intervaltochange != 'follower' && intervaltochange != 'king') { cb.sendNotice('The value entered for the notice type to change is invalid, please try again using one of these values of "notifier", "tipmenu", "posmenu", "poll", "leaders", "alltime", "ticket", "presale", "rules", "media", "toy", "icon", "king", "follower", or "dice".', u, appNoticeColor); } else if (!message[2]) { cb.sendNotice('This command requires a parameter to define the new interval (in minutes), in the format "/chgint [notice type] [new interval]", where [new interval] is the new display interval in minutes. An example of a valid command would be "/chgint tipmenu 3.2" to update the tip menu interval to 3.2 minutes.', u, appNoticeColor); } else if (isNaN(newtimer)) { cb.sendNotice('The second parameter requires a numeric value to define the new interval (in minutes), in the format "/chgint [notice type] [new interval]", where [new interval] is the new display interval in minutes. An example of a valid command would be "/chgint tipmenu 3.2" to update the tip menu interval to 3.2 minutes.', u, appNoticeColor); } else if (newtimer <= 1) { cb.sendNotice('The new value for the timer interval must be at least "1" for 1 minute (such as 1, 3, 4.5, etc).', u, appNoticeColor); } else { newtimerint = newtimer * 60000; newtimerint = parseInt(newtimerint); switch (intervaltochange) { case 'notifier': { notifierInt = newtimerint; break; } case 'leaders': { leaderInt = newtimerint; break; } case 'alltime': { allTimeTimer = newtimerint; break; } case 'king': { kingTipperInt = newtimerint; break; } case 'icon': { iconNoticeInt = newtimerint; break; } case 'toy': { LUSHMENU.lushMenuDspIntTime = newtimerint; break; } case 'tipmenu': { TIPMENU.menuDspIntTime = newtimerint; TIPMENU2.menuDspIntTime = newtimerint; break; } case 'posmenu': { POSTIPMENU.posMenuDspIntTime = newtimerint; break; } case 'poll': { pollNoticeInt = newtimerint; ODpollNoticeInt = newtimerint; break; } case 'media': { mediaTimerInt = newtimerint; break; } case 'rules': { roomRulesInt = newtimerint; break; } case 'dice': { diceInt = newtimerint; break; } case 'ticket': { ticketNoticeInt = newtimerint; break; } case 'presale': { presaleNoticeInt = newtimerint; break; } case 'follower': { followerInt = newtimerint; break; } } cb.sendNotice('The "' + intervaltochange + '" notice timer has been updated to a new interval of ' + newtimer + ' minutes. This will take effect after the next display of the notice.', u, appNoticeColor); } } else { cb.sendNotice('This command requires a parameter to define to notice timer that is to be used, in the format "/chgint [notice type] [new interval]", where [notice type] is one of the defined values of "notifier", "tipmenu", "posmenu", "poll", "leaders", "alltime", "ticket", "presale", "rules", "media", "toy", "icon", "king", or "dice", and [new interval] is the new interval in minutes. An example of a valid command would be "/chgint tipmenu 3.2" to update the tip menu interval to 3.2 minutes.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/setemjsep': { cmd = 1; if (isModLvlMsg2 || isBC) { if (!message[1]) { cb.sendNotice('Parameter for new emoji is not specified.', u, appNoticeColor); } else { borderChar = message[1]; cb.sendNotice('Separator Emoji has been updated to ' + borderChar, u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/about': { cmd = 1; displayAbout(u); break; } //******** Timer Commands *********** case '/startclock': { cmd = 1; if (isModLvlMsg1 || isBC) { if (clockMinsRemain >= 1 || clockSecsRemain >= 1) { cb.sendNotice('Timer #1 is already running, you can type /stopclock to end Timer #1 or /addtoclock X to add time, where X is the time to add in minutes.', u, appNoticeColor); } 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, appNoticeColor); } else { if (message[2]) { for (let i = 2; i < message.length; i++) { if (i === 2) { label = message[i]; } else { label += ' ' + message[i]; } } timerDesc = label; } else if (cb.settings.defaultTimerDesc) { timerDesc = cb.settings.defaultTimerDesc; } clockStartTime = new Date(); clockStopTime = new Date(clockStartTime.getTime() + commandVar1 * 60000); clockMinsRemain = commandVar1; clockTimeAdded = false; cb.sendNotice(u + ' has started Timer #1 for ' + clockMinsRemain + ' minute' + (clockMinsRemain > 1 ? 's' : ''), '', appNoticeColor, '', 'bold'); clockStopping = false; clockTimerMin(); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/clockaddtime': case '/clockadd': case '/addtoclock': { cmd = 1; if (isModLvlMsg1 || isBC) { if (!commandVar1) { cb.sendNotice('Invalid command, you need to specify the amount of time to add to Timer #1 in minutes. Example: use "/addtoclock 3" to add 3 minutes to the timer.', u, appNoticeColor); } else if ((clockMinsRemain + 1) + commandVar1 <= 0) { cb.sendNotice('The time to subtract is greater than the amount of time left on Timer #1. You can use "/stopclock" to stop the timer.'); } else if ((clockMinsRemain + 1) + commandVar1 > 120) { cb.sendNotice('The added time will increase Timer #1 to greater than 2 hours, please use a smaller value.'); } else { if (clockMinsRemain >= 1 || clockSecsRemain >= 1) { clockAddTime(commandVar1, u); break; } else { cb.sendNotice('Timer #1 is not running.', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod1, u,appNoticeColor); } break; } case '/timeleft': { cmd = 1; if (isModLvlMsg1 || isBC) { if (clockMinsRemain >= 1 || clockSecsRemain >= 1) { cb.sendNotice(clockTimeLeft(), "", appWarningColor, "", "bold"); } else { cb.sendNotice('Timer #1 is not running, however this command may be in use with a separate Ticket App.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/stopclock': { cmd = 1; if (isModLvlMsg1 || isBC) { if (clockMinsRemain >= 1 || clockSecsRemain >= 1) { stopClockTimer(u); } else { cb.sendNotice('Timer #1 is not running.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/chgclockdesc': { cmd = 1; if (isModLvlMsg1 || isBC) { if(message[1] != '' && message[1] != null) { timerDesc = msg['m'].substring(14).trim(); cb.sendNotice('The Timer #1 description has been updated to "' + timerDesc + '".', u, appNoticeColor); } else { cb.sendNotice('No value was specified for the new Timer #1 description.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } //******** Timer #2 Commands *********** case '/startclock2': { cmd = 1; if (isModLvlMsg1 || isBC) { if (clock2MinsRemain >= 1 || clock2SecsRemain >= 1) { cb.sendNotice('Timer #2 is already running, you can type /stopclock2 to end Timer #2 or /addtoclock2 X to add time, where X is the time to add in minutes.', u, appNoticeColor); } 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 "/startclock2 10" to start a 10 minute timer.', u, appNoticeColor); } else { if (message[2]) { for (let i = 2; i < message.length; i++) { if (i === 2) { label = message[i]; } else { label += ' ' + message[i]; } } timer2Desc = label; } else if (cb.settings.defaultTimerDesc2) { timer2Desc = cb.settings.defaultTimerDesc2; } clock2StartTime = new Date(); clock2StopTime = new Date(clock2StartTime.getTime() + commandVar1 * 60000); clock2MinsRemain = commandVar1; clock2TimeAdded = false; cb.sendNotice(u + ' has started Timer #2 for ' + clock2MinsRemain + ' minute' + (clock2MinsRemain > 1 ? 's' : ''), '', appNoticeColor, '', 'bold'); clock2Stopping = false; clock2TimerMin(); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/clock2addtime': case '/clock2add': case '/addtoclock2': { cmd = 1; if (isModLvlMsg1 || isBC) { if (!commandVar1) { cb.sendNotice('Invalid command, you need to specify the amount of time to add to Timer #2 in minutes. Example: use "/addtoclock2 3" to add 3 minutes to the timer.', u, appNoticeColor); } else if ((clock2MinsRemain + 1) + commandVar1 <= 0) { cb.sendNotice('The time to subtract is greater than the amount of time left on Timer #2. You can use "/stopclock2" to stop Timer #2.'); } else if ((clock2MinsRemain + 1) + commandVar1 > 120) { cb.sendNotice('The added time will increase Timer #2 to greater than 2 hours, please use a smaller value.'); } else { if (clock2MinsRemain >= 1 || clock2SecsRemain >= 1) { clock2AddTime(commandVar1, u); break; } else { cb.sendNotice('Timer #2 is not running.', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod1, u,appNoticeColor); } break; } case '/timeleft2': { cmd = 1; if (isModLvlMsg1 || isBC) { if (clock2MinsRemain >= 1 || clock2SecsRemain >= 1) { cb.sendNotice(clock2TimeLeft(), '', appWarningColor, '', 'bold'); } else { cb.sendNotice('Timer #2 is not running.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/stopclock2': { cmd = 1; if (isModLvlMsg1 || isBC) { if (clock2MinsRemain >= 1 || clock2SecsRemain >= 1) { stopClockTimer2(u); } else { cb.sendNotice('Timer #2 is not running.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/chgclock2desc': { cmd = 1; if (isModLvlMsg1 || isBC) { if(message[1] != '' && message[1] != null) { timer2Desc = msg['m'].substring(14).trim(); cb.sendNotice('The Timer #2 description has been updated to "' + timer2Desc + '".', u, appNoticeColor); } else { cb.sendNotice('No value was specified for the new Timer #2 description.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } //******** Timer #3 Commands *********** case '/startclock3': { cmd = 1; if (isModLvlMsg1 || isBC) { if (clock3MinsRemain >= 1 || clock3SecsRemain >= 1) { cb.sendNotice('Timer #3 is already running, you can type /stopclock3 to end Timer #3 or /addtoclock3 X to add time, where X is the time to add in minutes.', u, appNoticeColor); } 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 "/startclock3 10" to start a 10 minute timer.', u, appNoticeColor); } else { if (message[2]) { for (let i = 2; i < message.length; i++) { if (i === 2) { label = message[i]; } else { label += ' ' + message[i]; } } timer3Desc = label; } clock3StartTime = new Date(); clock3StopTime = new Date(clock3StartTime.getTime() + commandVar1 * 60000); clock3MinsRemain = commandVar1; clock3TimeAdded = false; cb.sendNotice(u + ' has started Timer #3 for ' + clock3MinsRemain + ' minute' + (clock3MinsRemain > 1 ? 's' : ''), '', appNoticeColor, '', 'bold'); clock3Stopping = false; clock3TimerMin(); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/clock3addtime': case '/clock3add': case '/addtoclock3': { cmd = 1; if (isModLvlMsg1 || isBC) { if (!commandVar1) { cb.sendNotice('Invalid command, you need to specify the amount of time to add to Timer #3 in minutes. Example: use "/addtoclock3 2" to add 2 minutes to the timer.', u, appNoticeColor); } else if ((clock3MinsRemain + 1) + commandVar1 <= 0) { cb.sendNotice('The time to subtract is greater than the amount of time left on Timer #3. You can use "/stopclock3" to stop Timer #3.'); } else if ((clock3MinsRemain + 1) + commandVar1 > 120) { cb.sendNotice('The added time will increase Timer #3 to greater than 2 hours, please use a smaller value.'); } else { if (clock3MinsRemain >= 1 || clock3SecsRemain >= 1) { clock3AddTime(commandVar1, u); break; } else { cb.sendNotice('Timer #3 is not running.', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod1, u,appNoticeColor); } break; } case '/timeleft3': { cmd = 1; if (isModLvlMsg1 || isBC) { if (clock3MinsRemain >= 1 || clock3SecsRemain >= 1) { cb.sendNotice(clock3TimeLeft(), '', appWarningColor, '', 'bold'); } else { cb.sendNotice('Timer #3 is not running.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/stopclock3': { cmd = 1; if (isModLvlMsg1 || isBC) { if (clock3MinsRemain >= 1 || clock3SecsRemain >= 1) { stopClockTimer3(u); } else { cb.sendNotice('Timer #3 is not running.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/chgclock3desc': { cmd = 1; if (isModLvlMsg1 || isBC) { if(message[1] != '' && message[1] != null) { timer3Desc = msg['m'].substring(14).trim(); cb.sendNotice('The Timer #3 description has been updated to "' + timer3Desc + '".', u, appNoticeColor); } else { cb.sendNotice('No value was specified for the new Timer #3 description.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } //******** Timer #4 Commands *********** case '/startclock4': { cmd = 1; if (isModLvlMsg1 || isBC) { if (clock4MinsRemain >= 1 || clock4SecsRemain >= 1) { cb.sendNotice('Timer #4 is already running, you can type /stopclock4 to end Timer #4 or /addtoclock4 X to add time, where X is the time to add in minutes.', u, appNoticeColor); } 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 "/startclock4 10" to start a 10 minute timer.', u, appNoticeColor); } else { if (message[2]) { for (let i = 2; i < message.length; i++) { if (i === 2) { label = message[i]; } else { label += ' ' + message[i]; } } timer4Desc = label; } clock4StartTime = new Date(); clock4StopTime = new Date(clock4StartTime.getTime() + commandVar1 * 60000); clock4MinsRemain = commandVar1; clock4TimeAdded = false; cb.sendNotice(u + ' has started Timer #4 for ' + clock4MinsRemain + ' minute' + (clock4MinsRemain > 1 ? 's' : ''), '', appNoticeColor, '', 'bold'); clock4Stopping = false; clock4TimerMin(); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/clock4addtime': case '/clock4add': case '/addtoclock4': { cmd = 1; if (isModLvlMsg1 || isBC) { if (!commandVar1) { cb.sendNotice('Invalid command, you need to specify the amount of time to add to Timer #4 in minutes. Example: use "/addtoclock4 3" to add 3 minutes to the timer.', u, appNoticeColor); } else if ((clock4MinsRemain + 1) + commandVar1 <= 0) { cb.sendNotice('The time to subtract is greater than the amount of time left on Timer #4. You can use "/stopclock4" to stop Timer #4.'); } else if ((clock4MinsRemain + 1) + commandVar1 > 120) { cb.sendNotice('The added time will increase Timer #4 to greater than 2 hours, please use a smaller value.'); } else { if (clock4MinsRemain >= 1 || clock4SecsRemain >= 1) { clock4AddTime(commandVar1, u); break; } else { cb.sendNotice('Timer #4 is not running.', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod1, u,appNoticeColor); } break; } case '/timeleft4': { cmd = 1; if (isModLvlMsg1 || isBC) { if (clock4MinsRemain >= 1 || clock4SecsRemain >= 1) { cb.sendNotice(clock4TimeLeft(), '', appWarningColor, '', 'bold'); } else { cb.sendNotice('Timer #4 is not running.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/stopclock4': { cmd = 1; if (isModLvlMsg1 || isBC) { if (clock4MinsRemain >= 1 || clock4SecsRemain >= 1) { stopClockTimer4(u); } else { cb.sendNotice('Timer #4 is not running.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/chgclock4desc': { cmd = 1; if (isModLvlMsg1 || isBC) { if(message[1] != '' && message[1] != null) { timer4Desc = msg['m'].substring(14).trim(); cb.sendNotice('The Timer #4 description has been updated to "' + timer4Desc + '".', u, appNoticeColor); } else { cb.sendNotice('No value was specified for the new Timer #4 description.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } //******** Ninja Commands *********** case '/ninja': { cmd = 1; if(isModLvlMsg2 || 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/unninja': { cmd = 1; if (isModLvlMsg2 || isBC) { addRmvNinja(message[1], u, 'r'); } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/ninjalist': { cmd = 1; if (isModLvlMsg2 || isBC) { cb.sendNotice('Users currently on the Ninja List: ' + ninjaListArray.length, u, appNoticeColor); cb.sendNotice((ninjaListArray.length > 0 == true ? cbjs.arrayJoin(ninjaListArray, ', ') : 'No users.'), u); cb.sendNotice('End of List', u, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/showninja': { cmd = 1; if (isModLvlMsg2 || 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, appNoticeColor); } 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, appNoticeColor); } else if (nummode == 0 && showNinjadMsgs == 'Do not show') { cb.sendNotice('The current setting for showing messages from ninja\'d users is already set to "Do not show".', u, appNoticeColor); } else if (nummode == 1 && showNinjadMsgs == 'Broadcaster only') { cb.sendNotice('The current setting for showing messages from ninja\'d users is already set to "Broadcaster only".', u, appNoticeColor); } else if (nummode == 2 && showNinjadMsgs == 'Mods only') { cb.sendNotice('The current setting for showing messages from ninja\'d users is already set to "Mods only".', u, appNoticeColor); } else if (nummode == 3 && showNinjadMsgs == 'Broadcaster and Mods') { cb.sendNotice('The current setting for showing messages from ninja\'d users is already set to "Broadcaster and Mods".', u, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } //******** Silence List Commands *********** case '/silence': { cmd = 1; if (isModLvlMsg2 || 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/unsilence': { cmd = 1; if (isModLvlMsg2 || isBC) { addRmvSilence(message[1], u, 'r'); } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/silencelist': { cmd = 1; if (isModLvlMsg2 || isBC) { cb.sendNotice('Users currently on the Silence List: ' + silenceListArray.length, u, appNoticeColor); cb.sendNotice((silenceListArray.length > 0 == true ? cbjs.arrayJoin(silenceListArray, ', ') : 'No users.'), u); cb.sendNotice('End of List', u, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/showsilence': { cmd = 1; if (isModLvlMsg2 || 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, appNoticeColor); } 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, appNoticeColor); } else if (nummode == 0 && showSilencedMsgs == 'Do not show') { cb.sendNotice('The current setting for showing messages from bot silenced users is already set to "Do not show".', u, appNoticeColor); } else if (nummode == 1 && showSilencedMsgs == 'Broadcaster only') { cb.sendNotice('The current setting for showing messages from bot silenced users is already set to "Broadcaster only".', u, appNoticeColor); } else if (nummode == 2 && showSilencedMsgs == 'Mods only') { cb.sendNotice('The current setting for showing messages from bot silenced users is already set to "Mods only".', u, appNoticeColor); } else if (nummode == 3 && showSilencedMsgs == 'Broadcaster and Mods') { cb.sendNotice('The current setting for showing messages from bot silenced users is already set to "Broadcaster and Mods".', u, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } //******** VIP Commands *********** case '/addvip': { cmd = 1; if (isBC || isModLvlMsg3) { cmdval = msg['m'].substring(8).trim(); if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { addnotice = 'Adding multiple users to the Fembot VIP list.'; addnotice += '\nNote 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.'; for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { nametoadd = cmdvalsplit[i].toLowerCase(); if (!cbjs.arrayContains(VIPListArray, nametoadd)) { addRmvVIP(nametoadd,'a'); addnotice += '\nAdded ' + nametoadd + ' to the Fembot VIP list.'; cb.sendNotice(u + ' has added you to the Fembot VIP list.', nametoadd, '#efe'); } else { addnotice += '\n' + nametoadd + ' is already on the Fembot VIP list. Skipping.'; } } } addnotice += '\nAll users were added and notified.'; if (u == BC) { cb.sendNotice(addnotice, u, appNoticeColor); cb.sendNotice(u + ' has added multiple users to the Fembot VIP list.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), BC, appNoticeColor, '', 'normal', 'red'); } else { cb.sendNotice(addnotice, BC, appNoticeColor); } } else { nametoadd = message[1].toLowerCase(); if (cbjs.arrayContains(VIPListArray,nametoadd)) { cb.sendNotice('Fembot: ' + nametoadd + ' is already on the VIP list.', u, appNoticeColor); } else { addRmvVIP(nametoadd,'a'); if (u == BC) { cb.sendNotice('Fembot: You have added ' + nametoadd + ' to the VIP list.\nNote this is only applied during this session, permanent VIP list changes must be made to the list defined when starting the Fembot. \nThis list should also be saved to a separate document.', u, appNoticeColor); } else { cb.sendNotice('Fembot: ' + u + ' has added ' + nametoadd + ' to the VIP list.\nNote this is only applied during this session, permanent VIP list changes must be made to the list defined when starting the Fembot. \nThis list should also be saved to a separate document.', BC, appNoticeColor); } cb.sendNotice('Fembot: Congratulations! You have been added to the VIP list!', nametoadd, appNoticeColor); } } } else { cb.sendNotice('Fembot: You did not specify the username you want to add to the Fembot VIP list.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, u, appNoticeColor); } break; } case '/rmvvip': { cmd = 1; if (isBC || isModLvlMsg3) { if (message[1]) { nametormv = message[1].toLowerCase(); if (cbjs.arrayContains(VIPListArray,nametormv)) { addRmvVIP(nametormv,'r'); if (u == BC) { cb.sendNotice('Fembot: You have removed ' + nametormv + ' from the VIP list.\nNote this is only applied during this session, permanent VIP list changes must be made to the list defined when starting the Fembot. \nThis list should also be saved to a separate document.', u, appNoticeColor); } else { cb.sendNotice('Fembot ' + u + ' has removed ' + nametormv + ' from the VIP list.\nNote this is only applied during this session, permanent VIP list changes must be made to the list defined when starting the Fembot. \nThis list should also be saved to a separate document.', BC, appNoticeColor); } } else { cb.sendNotice('Fembot: ' + nametormv + ' is not on the VIP list.', u, appNoticeColor); } } else { cb.sendNotice('Fembot: You did not specify what username you want to remove from the VIP list.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, u, appNoticeColor); } break; } case '/viplist': { cmd = 1; if (isModLvlMsg1 || isBC) { cb.sendNotice('Users currently on the Fembot VIP List: ' + VIPListArray.length + '\n' + (VIPListArray.length > 0 == true ? cbjs.arrayJoin(VIPListArray, ',') : 'No users.') + '\nEnd of List', u, appNoticeColor); cb.sendNotice('VIP List Members in the current show: ' + VIPInShowArray.length + '\n' + (VIPInShowArray.length > 0 == true ? cbjs.arrayJoin(VIPInShowArray, ',') : 'No users.') + '\nEnd of List', u, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } //******** External Fan Club Commands *********** case '/addfan': { cmd = 1; if (isBC || isModLvlMsg3) { cmdval = msg['m'].substring(8).trim(); if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { addnotice = 'Adding multiple users to ' + EFCname + '.'; addnotice += '\nNote this is only applied during this session, permanent External Fan Club 1 list changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.'; for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { nametoadd = cmdvalsplit[i].toLowerCase(); if (!cbjs.arrayContains(extFanListArray, nametoadd)) { addRmvExtFan(nametoadd,'a'); addnotice += '\nAdded ' + nametoadd + ' to ' + EFCname + '.'; cb.sendNotice(u + ' has added you to ' + EFCname + '.', nametoadd, appNoticeColor); } else { cb.sendNotice(nametoadd + ' is already on the list. Skipping.', u); } } } addnotice += '\nAll users were added and notified.'; if (u == BC) { cb.sendNotice(addnotice, u, appNoticeColor); cb.sendNotice(u + ' has added multiple users to ' + EFCname + '.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), BC, appNoticeColor, '', 'normal', 'red'); } else { cb.sendNotice(addnotice, BC, appNoticeColor); } } else { nametoadd = message[1].toLowerCase(); if (cbjs.arrayContains(extFanListArray,nametoadd)) { cb.sendNotice('Fembot: ' + nametoadd + ' is already in ' + EFCname + '.', u, appNoticeColor); } else { addRmvExtFan(nametoadd,'a'); if (u == BC) { cb.sendNotice('Fembot: You have added ' + nametoadd + ' to ' + EFCname + '.\nNote this is only applied during this session, permanent External Fan Club 1 list changes must be made to the list defined when starting the Fembot. \nThis list should also be saved to a separate document.', u, appNoticeColor); } else { cb.sendNotice('Fembot: ' + u + ' has added ' + nametoadd + ' to ' + EFCname + '.\nNote this is only applied during this session, permanent External Fan Club 1 list changes must be made to the list defined when starting the Fembot. \nThis list should also be saved to a separate document.', BC, appNoticeColor); } cb.sendNotice('Fembot: Congratulations! You have been added to the ' + EFCname, nametoadd, appNoticeColor); } } } else { cb.sendNotice('Fembot: You did not specify the username you want to add to ' + EFCname + '.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, u, appNoticeColor); } break; } case '/addfan2': { cmd = 1; if (isBC || isModLvlMsg3) { cmdval = msg['m'].substring(9).trim(); if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { addnotice = 'Adding multiple users to ' + EFCname2 + '.'; addnotice += '\nNote this is only applied during this session, permanent ' + EFCname2 + ' changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.'; for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { nametoadd = cmdvalsplit[i].toLowerCase(); if (!cbjs.arrayContains(extFanList2Array, nametoadd)) { addRmvExtFan2(nametoadd,'a'); addnotice += '\nAdded ' + nametoadd + ' to ' + EFCname2 + '.'; cb.sendNotice(u + ' has added you to ' + EFCname2 + '.', nametoadd, appNoticeColor); } else { cb.sendNotice(nametoadd + ' is already on the list. Skipping.', u); } } } addnotice += '\nAll users were added and notified.'; cb.sendNotice(addnotice, u, appNoticeColor); cb.sendNotice(u + ' has added multiple users to ' + EFCname2 + '.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), '', appNoticeColor, '', 'normal', 'red'); } else { nametoadd = message[1].toLowerCase(); if (cbjs.arrayContains(extFanList2Array,nametoadd)) { cb.sendNotice('Fembot: ' + nametoadd + ' is already in ' + EFCname2 + '.', u, appNoticeColor); } else { addRmvExtFan2(nametoadd,'a'); cb.sendNotice('Fembot: You have added ' + nametoadd + ' to ' + EFCname2 + '.\nNote 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.', u, appNoticeColor); cb.sendNotice('Fembot: Congratulations! You have been added to ' + EFCname2 + '!', nametoadd, appNoticeColor); } } } else { cb.sendNotice('Fembot: You did not specify the username you want to add to the External Fan Club 2 list.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, u, appNoticeColor); } break; } case '/rmvfan': { cmd = 1; if (isBC || isModLvlMsg3) { if (message[1]) { nametormv = message[1].toLowerCase(); if (cbjs.arrayContains(extFanListArray,nametormv)) { addRmvExtFan(nametormv,'r'); cb.sendNotice('Fembot: You have removed ' + nametormv + ' from the External Fan Club 1 list.\nNote 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.', u, appNoticeColor); } else { cb.sendNotice('Fembot: ' + nametormv + ' is not on the External Fan Club 1 list.', u, appNoticeColor); } } else { cb.sendNotice('You did not specify what username you want to remove from the Fembot External Fan Club 1 list.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, u, appNoticeColor); } break; } case '/rmvfan2': { cmd = 1; if (isBC || isModLvlMsg3) { if (message[1]) { nametormv = message[1].toLowerCase(); if (cbjs.arrayContains(extFanList2Array,nametormv)) { addRmvExtFan2(nametormv,'r'); cb.sendNotice('Fembot: You have removed ' + nametormv + ' from the External Fan Club 2 list.\nNote 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.', u, appNoticeColor); } else { cb.sendNotice('Fembot: ' + nametormv + ' is not on the External Fan Club 2 list.', u, appNoticeColor); } } else { cb.sendNotice('You did not specify what username you want to remove from the Fembot External Fan Club 2 list.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, u, appNoticeColor); } break; } case '/fanlist': { cmd = 1; if (isModLvlMsg1 || isBC) { cb.sendNotice('Users currently in the Fembot External Fan Club 1 List: ' + extFanListArray.length + '\n' + (extFanListArray.length > 0 == true ? cbjs.arrayJoin(extFanListArray, ',') : 'No users.') + '\nEnd of List', u, appNoticeColor); cb.sendNotice('External Fan Club 1 members in the current show: ' + extFanInShowArray.length + '\n' + (extFanInShowArray.length > 0 == true ? cbjs.arrayJoin(extFanInShowArray, ',') : 'No users.') + '\nEnd of List', u, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/fanlist2': { cmd = 1; if (isModLvlMsg1 || isBC) { cb.sendNotice('Users currently in the Fembot External Fan Club 2 List: ' + extFanList2Array.length + '\n' + (extFanList2Array.length > 0 == true ? cbjs.arrayJoin(extFanList2Array, ',') : 'No users.') + '\nEnd of List', u, appNoticeColor); cb.sendNotice('External Fan Club 2 members in the current show: ' + extFanInShow2Array.length + '\n' + (extFanInShow2Array.length > 0 == true ? cbjs.arrayJoin(extFanInShow2Array, ',') : 'No users.') + '\nEnd of List', u, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } //******** Moderator List Commands *********** case '/addmod': { cmd = 1; if (isBC || isModLvlMsg3) { cmdval = msg['m'].substring(8).trim(); if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { addnotice = 'Adding multiple users to the Fembot Moderator list.'; addnotice += '\nNote this is only applied during this session, permanent Moderator list changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.'; for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { nametoadd = cmdvalsplit[i].toLowerCase(); if (!cbjs.arrayContains(moderatorList.name, nametoadd)) { populateModeratorArray(nametoadd,'botmod','a'); addnotice += '\nAdded ' + nametoadd + ' to the Fembot Moderator list.'; cb.sendNotice(u + ' has added you to the Fembot moderator list.', nametoadd, appNoticeColor); } else { addnotice += '\n' + nametoadd + ' is already on the Fembot moderator list. Skipping.'; } } } addnotice += '\nAll users were added and notified.'; cb.sendNotice(addnotice, u, appNoticeColor); cb.sendNotice(u + ' has added multiple users to the Fembot moderator list.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), '', appNoticeColor, '', 'normal', 'red'); } else { nametoadd = message[1].toLowerCase(); if (!cbjs.arrayContains(moderatorList.name,nametoadd)) { populateModeratorArray(nametoadd,'botmod','a'); cb.sendNotice('You have added ' + nametoadd + ' to the Fembot moderator list.', u, appNoticeColor); cb.sendNotice('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.', u, appNoticeColor); 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.', nametoadd, appNoticeColor); } else { cb.sendNotice(nametoadd + ' is already on the Fembot moderator list.', u, appNoticeColor); } } } else { cb.sendNotice('Fembot: You did not specify the username you want to add to the Fembot moderator list.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, u, appNoticeColor); } break; } case '/rmvmod': { cmd = 1; if (isBC || isModLvlMsg3) { if (message[1]) { nametormv = message[1].toLowerCase(); if (cbjs.arrayContains(moderatorList.name,nametormv)) { nameIndex = moderatorList.name.indexOf(nametormv); if (moderatorList.type[nameIndex] == 'botmod') { populateModeratorArray(nametormv,'botmod','r'); cb.sendNotice('You have removed ' + nametormv + ' as a Bot Mod from the Fembot Moderator list.', u, appNoticeColor); } else if (moderatorList.type[nameIndex] == 'cbmod') { populateModeratorArray(nametormv,'cbmod','r'); cb.sendNotice('You have removed ' + nametormv + ' as a CB Mod from the Fembot Moderator list. If they are still a red name, they will be added back the next time they enter the room or chat. You must revoked their CB moderator status to prevent them from being added back.', u, appNoticeColor); } else { cb.sendNotice('You cannot remove ' + nametormv + ' from the Fembot Moderator list, they are the broadcaster or an unknown mod type.', u, appNoticeColor); } } else { cb.sendNotice(nametormv + ' is not in the Fembot moderator list.', u, appNoticeColor); } } else { cb.sendNotice('Fembot: A parameter is required for this command to specify the user to remove from the Fembot Moderator list, such as "/rmvmod username".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, u, appNoticeColor); } break; } case '/modlist': { cmd = 1; if (isModLvlMsg1 || isBC) { message = ''; message += 'Users currently on the Fembot 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, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } //******** Blocked Word List Commands *********** case '/addword': { cmd = 1; if (isModLvlMsg2 || isBC ) { cmdval = msg['m'].substring(9).trim(); if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice('Adding multiple words to the Public Blocked Word list.', u, appNoticeColor); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != "") { if (!cbjs.arrayContains(wordListArrayPub, cmdvalsplit[i])) { wordListArrayPub.push(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, appNoticeColor) cb.sendNotice(u + ' has added multiple words to the Blocked Word list.\n' + 'Words added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), '', appNoticeColor, '', 'normal', 'red'); } else { var cmdvalsingle = message[1].toLowerCase(); addRmvWord(cmdvalsingle, u, 'a'); } } else { cb.sendNotice('Fembot: You did not specify what word(s) you want to add to the Public Blocked Word list.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/rmvword': { cmd = 1; if (isModLvlMsg2 || isBC) { addRmvWord(message[1], u, 'r'); } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/wordlist': { cmd = 1; if (isModLvlMsg1 || isBC) { cb.sendNotice('Words currently on the Public Blocked Word List: ' + wordListArrayPub.length, u, appNoticeColor); cb.sendNotice((wordListArrayPub.length > 0 == true ? cbjs.arrayJoin(wordListArrayPub, ', ') : 'No words.'), u); cb.sendNotice('End of List', u, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/wordlistprv': { cmd = 1; if (isBC) { cb.sendNotice('Words currently on the Private Blocked Word List: ' + wordListArray.length, u, appNoticeColor); cb.sendNotice((wordListArray.length > 0 == true ? cbjs.arrayJoin(wordListArray, ', ') : 'No words.'), u); cb.sendNotice('End of List', u, appNoticeColor); } else { cb.sendNotice(noticeOnlyBC, u, appNoticeColor); } break; } //******** Nice List Commands *********** case '/addnice': { cmd = 1; if (isModLvlMsg1 || isBC ) { cmdval = msg['m'].substring(9).trim(); if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice('Adding multiple users to the nice list.', u, appNoticeColor); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { nametoadd = cmdvalsplit[i].toLowerCase(); if (!cbjs.arrayContains(niceListArray, nametoadd)) { populateNiceListArray(nametoadd); cb.sendNotice('Added ' + nametoadd + ' to the list.', u); cb.sendNotice(u + ' has added you to the nice list.', nametoadd, appNoticeColor); } else { cb.sendNotice(nametoadd + ' is already on the list. Skipping.', u); } } } cb.sendNotice('All users were added and notified.', u, appNoticeColor) cb.sendNotice(u + ' has added multiple users to the nice list.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), '', appNoticeColor, '', 'normal', 'red'); } else { addRmvNice(message[1].toLowerCase(), u, 'a'); } } else { cb.sendNotice('Fembot: You did not specify the username you want to add to the nice list.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/rmvnice': { cmd = 1; if (isModLvlMsg1 || isBC) { addRmvNice(message[1].toLowerCase(), u, 'r'); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/nicelist': { cmd = 1; if (isModLvlMsg1 || isBC) { cb.sendNotice('Users currently in the Fembot Nice List: ' + niceListArray.length + '\n' + (niceListArray.length > 0 == true ? cbjs.arrayJoin(niceListArray, ', ') : 'No users.') + '\nEnd of List', u, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } //******** Chat Notice Commands *********** case '/cn': { cmd = 1; if (isModLvlMsg1 || isBC) { noticemsg = msg['m'].substring(4).trim(); if (noticemsg != null && (noticemsg != '' || noticemsg != ' ' || noticemsg != '\u00a0')) { sendPublicNotice(noticemsg, u, ''); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/cn [message]".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/cnh': { cmd = 1; if (isModLvlMsg1 || isBC) { noticemsg = msg['m'].substring(5).trim(); if (noticemsg != null && (noticemsg != '' || noticemsg != ' ' || noticemsg != '\u00a0')) { sendPublicNotice(noticemsg, u, 'h'); } else { cb.sendNotice('You cannot send a blank message. The correct syntax for this command is "/cnh [message]".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/cnd': { cmd = 1; if (isModLvlMsg1 || isBC) { noticemsg = msg['m'].substring(5).trim(); if (noticemsg != null && (noticemsg != '' || noticemsg != ' ' || noticemsg != '\u00a0')) { sendPublicNotice(noticemsg, u, 'div'); } else { cb.sendNotice('Fembot: You cannot send a blank message.\n The correct syntax for this command is "/cnd [message]".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/cndh': { cmd = 1; if (isModLvlMsg1 || isBC) { noticemsg = msg['m'].substring(6).trim(); if (noticemsg != null && (noticemsg != '' || noticemsg != ' ' || noticemsg != '\u00a0')) { sendPublicNotice(noticemsg, u, 'divh'); } else { cb.sendNotice('Fembot: You cannot send a blank message. The correct syntax for this command is "/cndh [message]".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/ctn': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg1 || isBC) { noticemsg = msg['m'].substring(5).trim(); if (noticemsg != null && (noticemsg != '' || noticemsg != ' ' || noticemsg != '\u00a0')) { sendPublicNotice(noticemsg, u, ""); } else { cb.sendNotice('Fembot: You cannot send a blank message. The correct syntax for this command is "/ctn [message]".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/ctnh': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg1 || isBC) { noticemsg = msg['m'].substring(6).trim(); if (noticemsg != null && (noticemsg != '' || noticemsg != ' ' || noticemsg != '\u00a0')) { sendPublicNotice(noticemsg, u, 'h'); } else { cb.sendNotice('Fembot: You cannot send a blank message. The correct syntax for this command is "/ctnh [message]".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/ctnd': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg1 || isBC) { noticemsg = msg['m'].substring(6).trim(); if (noticemsg != null && (noticemsg != '' || noticemsg != ' ' || noticemsg != '\u00a0')) { sendPublicNotice(noticemsg, u, "div"); } else { cb.sendNotice('Fembot: You cannot send a blank message. The correct syntax for this command is "/ctnd [message]".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/ctndh': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg1 || isBC) { noticemsg = msg['m'].substring(7).trim(); if (noticemsg != null && (noticemsg != '' || noticemsg != ' ' || noticemsg != '\u00a0')) { sendPublicNotice(noticemsg, u, "divh"); } else { cb.sendNotice('Fembot: You cannot send a blank message. The correct syntax for this command is "/ctndh [message]".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } //******** Private Message Commands *********** case '/bc': { cmd = 1; if (isBC) { cb.sendNotice('Fembot: Broadcasters cannot send messages to themselves.', u, appNoticeColor); } else { if (isModLvlMsg1 || ((isFanMsg || isVIPMsg || isExtFanMsg || isExtFanMsg2) && (cb.settings.enablePMs == 'Yes'))) { privatemsg = msg['m'].substring(4).trim(); if (privatemsg != null && (privatemsg != '' || privatemsg != ' ' || privatemsg != '\u00a0')) { sendPrivateNotice(privatemsg, u, 'bc', 'default'); } else { cb.sendNotice('Fembot: You cannot send a blank message. The correct syntax for this command is "/bc [message]".', u, appNoticeColor); } } else { cb.sendNotice('Fembot: That command has not been enabled by the broadcaster for your user group (setting 4H).', u, appNoticeColor); } } break; } case '/tm': { cmd = 1; if (isModLvlMsg1 || isBC) { privatemsg = msg['m'].substring(4).trim(); if (privatemsg != null && (privatemsg != '' || privatemsg != ' ' || privatemsg != '\u00a0')) { sendPrivateNotice(privatemsg, u, 'tm'); } else { cb.sendNotice('Fembot: You cannot send a blank message. The correct syntax for this command is "/tm [message]".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/tbm': { cmd = 1; if (isModLvlMsg1 || isBC) { privatemsg = msg['m'].substring(5).trim(); if (privatemsg != null && (privatemsg != '' || privatemsg != ' ' || privatemsg != '\u00a0')) { sendPrivateNotice(privatemsg, u, 'tbm', 'default'); } else { cb.sendNotice('Fembot: You cannot send a blank message. The correct syntax for this command is "/tbm [message]".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/pm': { cmd = 1; if (isModLvlMsg1 || isBC || ((isFanMsg || isVIPMsg || isExtFanMsg || isExtFanMsg2) && (cb.settings.enablePMs == 'Yes'))) { var checkSpecial = /[!@#$%^&*()+\-=\[\]{};':"\\|,.<>\/?]+/; if (message[1].length < 3) { cb.sendNotice('Fembot: Username (first parameter) in PM command is too short (CB usernames must be 3 characters or more), message not sent.', u, appNoticeColor); } else if (checkSpecial.test(message[1])) { cb.sendNotice('Fembot: Username (first parameter) in PM command is invalid, it uses special characters other than "_", message not sent.', u, appNoticeColor); } else { ntc2 = null; for (var msgi = 2; msgi < message.length; msgi++) { if (msgi == 2) ntc2 = message[msgi]; else ntc2 += ' ' + message[msgi]; } if (ntc2 != null && (ntc2 != '' || ntc2 != ' ' || ntc2 != '\u00a0')) { sendPrivateNotice(ntc2, u, 'pm', message[1]); } else { cb.sendNotice('Fembot: You cannot send a blank message. The correct syntax for this command is "/pm [user] [message]".', u, appNoticeColor); } } } else { cb.sendNotice('Fembot: That command has not been enabled by the broadcaster for your user group (setting 4H).', u, appNoticeColor); } break; } case '/reply': { cmd = 1; if (cb.settings.enablePMs == 'Yes') { sendReply(message, u); } else { cb.sendNotice('Fembot: That command has not been enabled by the broadcaster.', u, appNoticeColor); } break; } //******** Tip Leader Commands *********** case '/leaders': { cmd = 1; if (leaderboardToggle == 1) { if (message[1]) { var lbparm = message[1].toLowerCase(); if (lbparm == 'all') { if (isModLvlMsg1 || isBC) { showLeaderBoard('all',''); } else { cb.sendNotice('Fembot: The "all" parameter can only be used by the broadcaster or moderators.', u, appNoticeColor); } } else { cb.sendNotice('Fembot: The parameter for the /leaders command is not valid. \nYou can select a parameter of "all" to send the leaderboard to everyone, or do not use a parameter to send it to yourself. \nDefaulting to send to YOU', u, appNoticeColor); showLeaderBoard('me',u); } } else { showLeaderBoard('me',u); } } else { cb.sendNotice('Fembot: The leaderboard is not enabled.', u, appNoticeColor); } break; } case '/tippers': { cmd = 1; if (isModLvlMsg1 || isBC) { numtippers = parseInt(message[1]) if (isNaN(numtippers)) { cb.sendNotice('The value entered for the number of tippers from the leaderboard is not numeric, defaulting to 20.', u, appNoticeColor); numtippers = 20; } else if (numtippers > 100) { cb.sendNotice('Fembot: The value entered for the number of tippers from the leaderboard cannot exceed 100, defaulting to 100.', u, appNoticeColor); numtippers = 100; } else if (numtippers <= 0) { cb.sendNotice('Fembot: The value entered for the number of tippers from the leaderboard must be greater than zero, defaulting to 20.', u, appNoticeColor); numtippers = 20; } if (message[2] == 'all' || message[2] == 'tbm' || message[2] == 'mods' || message[2] == 'bc' || message[2] == '' || message[2] == null) { sortTippers(); switch (message[2]) { case 'all': showTippers(u,'',numtippers,'all',''); break; case 'tbm': showTippers(u,'',numtippers,'tbm',BC); showTippers(u,'red',numtippers,'tbm',''); break; case 'mods': showTippers(u,'red',numtippers,'mods',''); if (u == BC) { showTippers(u,'',numtippers,'mods',u); } break; case 'bc': if (u != BC) { showTippers(u,'',numtippers,'bc',BC); } showTippers(u,'',numtippers,'me',u); break; default: showTippers(u,'',numtippers,'me',u); break; } } else { cb.sendNotice('Fembot: Invalid parameter supplied for who to send the list of tippers to. The command format should be /tippers [number] [sendto], where [number] is the number of entries to display, and [sendto] is the value for who to send it to, and can be "mods" for the moderator group, "bc" for only the broadcaster, "tbm" for the moderators and the broadcaster, "all" for the whole room, and blank for only yourself.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/useleaderboard': { cmd = 1; if (isModLvlMsg1 || isBC) { setLeaderToggle(message[1],u,true); } else { cb.sendNotice(noticeOnlyBCMod1,u,appNoticeColor); } break; } case '/usetipcount': { cmd = 1; if (isModLvlMsg1 || isBC) { setTipCountToggle(message[1],u,true); } else { cb.sendNotice(noticeOnlyBCMod1,u,appNoticeColor); } break; } //********* Room Rules Commands case '/userules': { cmd = 1; if (isModLvlMsg2 || isBC) { if (message[1].toLowerCase() == 'on' || message[1].toLowerCase() == 'off') { setRoomRulesToggle(message[1],u,true); } else { cb.sendNotice('Fembot: You did not enter a valid parameter for /userules, valid options are "on" or "off".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } //********* Notifier Commands case '/usenotifier': { cmd = 1; if (isModLvlMsg2 || isBC) { if (message[1].toLowerCase() == 'on' || message[1].toLowerCase() == 'off') { setNotifierToggle(message[1],u,true); } else { cb.sendNotice('Fembot: You did not enter a valid parameter for /usenotifier, valid options are "on" or "off".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } case '/chgmsg1': case '/chgmsg2': case '/chgmsg3': case '/chgmsg4': case '/chgmsg5': case '/chgmsg6': case '/chgmsg7': case '/chgmsg8': case '/chgmsg9': { cmd = 1; if (isModLvlMsg2 || isBC) { msgnum = parseInt(msg['m'].substring(7,8)); msgindex = msgnum - 1; if (!message[1]) { cb.sendNotice('Fembot: You must enter a new message for the selected notifier, for example "/chgmsg3 New Notice!". If you want to disable the notifications, enter /usenotifier off.',u,appNoticeColor) } else { notifierArray[msgindex] = msg['m'].substring(9).trim(); cb.sendNotice('Fembot: You have updated the message for Notifier entry ' + msgnum + ' to "' + notifierArray[msgindex] + '".', u, appNoticeColor); if (u != BC) { cb.sendNotice('Fembot: ' + u + ' has updated the message for Notifier entry ' + msgnum + ' to "' + notifierArray[msgindex] + '".', BC, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } case '/dspmsg1': case '/dspmsg2': case '/dspmsg3': case '/dspmsg4': case '/dspmsg5': case '/dspmsg6': case '/dspmsg7': case '/dspmsg8': case '/dspmsg9': { cmd = 1; if (isModLvlMsg1 || isBC) { msgnum = parseInt(msg['m'].substring(7,8)); msgindex = msgnum - 1; if (message[1] == 'all') { setNoticeColor(); if (!notifierArray[msgindex]) { cb.sendNotice('Notifier ' + msgnum + ' Message is blank.', u, appNoticeColor); } else { cb.sendNotice('\u25ba ' + notifierArray[msgindex], '', noticeBgColor, noticeTextColor, 'bold'); } } else { if (!notifierArray[msgindex]) { cb.sendNotice('Notifier ' + msgnum + ' Message is blank.', u, appNoticeColor); } else { cb.sendNotice('Notifier ' + msgnum + ': ' + notifierArray[msgindex], u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/dspallmsg': { cmd = 1; if (isModLvlMsg1 || isBC) { displaymessage = ''; for (var msgindex = 0; msgindex < 9; msgindex++) { if (!notifierArray[msgindex]) { displaymessage += 'Notifier ' + (msgindex+1) + ': Message is blank.\n'; } else { displaymessage += 'Notifier ' + (msgindex+1) + ': ' + notifierArray[msgindex] + '\n'; } } cb.sendNotice(displaymessage, u, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1,u,appNoticeColor); } break; } //********* Viewer Notes Commands case '/noteslist': case '/notelist': { cmd = 1; if (isBC) { displaymessage = 'Viewer Notes: \n'; for (var notelistindex = 0; notelistindex < viewerNotesArray.username.length; notelistindex++) { displaymessage += (notelistindex+1) + '. ' + viewerNotesArray.username[notelistindex] + ': ' + (viewerNotesArray.displayed[notelistindex] ? 'Already Shown' : 'Not yet Shown') + ' : ' + (viewerNotesArray.addinshow[notelistindex] ? 'New' : 'Existing') + ' : ' + viewerNotesArray.notes[notelistindex] + '\n'; } cb.sendNotice(displaymessage, u, appNoticeColor); } else { cb.sendNotice(noticeOnlyBC, u, appNoticeColor); } break; } case '/shownote': { cmd = 1; if (isBC) { if (message[1]) { noteuser = message[1].toLowerCase(); if (cbjs.arrayContains(viewerNotesArray.username, noteuser)) { noteindex = viewerNotesArray.username.indexOf(noteuser); cb.sendNotice('Viewer Notes for ' + noteuser + ' :\n' + viewerNotesArray.notes[noteindex], u, appNoticeColor); } else { cb.sendNotice('Fembot: There is no entry for ' + noteuser + ' in the Notes list. You can add one with the command /addnote, or view the full list with the command /notelist.',u,appNoticeColor); } } else { cb.sendNotice('Fembot: No username was specified to display notes for. Command should be /shownote username.',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBC, u, appNoticeColor); } break; } case '/addnote': { cmd = 1; if (isBC) { if (!message[1]) { cb.sendNotice('Fembot: The first parameter for username is missing. The correct command format is "/addnote username notes" where "username" is the CB user ID, and "notes" is the free form text note you would like to add. If there is already an entry for the username, the new text will be appended to the end. Note this entry is not saved beyond the current show, so make sure to use the "/notelist" command at the end of the show and copy your notes so they can be entered on the launch page for next start (setting 6A).', u, appNoticeColor); return; } if (!message[2]) { cb.sendNotice('Fembot: The text notes are missing. The correct command format is "/addnote username notes" where "username" is the CB user ID, and "notes" is the free form text note you would like to add. If there is already an entry for the username, the new text will be appended to the end. Note this entry is not saved beyond the current show, so make sure to use the "/notelist" command at the end of the show and copy your notes so they can be entered on the launch page for next start (setting 6A).', u, appNoticeColor); return; } let label; for (let j = 2; j < message.length; j++) { if (j === 2) { label = message[j]; } else { label += ' ' + message[j]; } } adduser = message[1].toLowerCase(); if (cbjs.arrayContains(viewerNotesArray.username, adduser)) { addnoteindex = viewerNotesArray.username.indexOf(adduser); viewerNotesArray.notes[addnoteindex] += ' ' + label; viewerNotesArray.displayed[addnoteindex] = false; viewerNotesArray.addinshow[addnoteindex] = true; cb.sendNotice('Fembot: Your note was added to the existing entry for user "' + adduser + '". Even if shown once previously, the note will be displayed upon "' + viewerNotesWhen + '" per current settings so you can verify correct info. This update cannot be permanently saved, so make sure to use the "/notelist" command at the end of the show so you can copy this entry to add to the launch page later.', u, appNoticeColor); } else { viewerNotesArray.username.push(adduser); viewerNotesArray.notes.push(label); viewerNotesArray.displayed.push(false); viewerNotesArray.addinshow.push(true); cb.sendNotice('Fembot: Your note was added as a new entry for user "' + adduser + '". The note will be displayed upon "' + viewerNotesWhen + '" per current settings so you can verify correct info. You can append more text to the existing entry using the "/addnote" command again for the same user. This update cannot be permanently saved, so make sure to use the "/notelist" command at the end of the show so you can copy this entry to add to the launch page later.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBC, u, appNoticeColor); } break; } //********* Change Subject Command case '/chgsubject': case '/newsubject': { cmd = 1; if (isModLvlMsg1 || isBC) { newSubject = msg['m'].substring(12).trim() setRoomSubject(newSubject,u); } else { cb.sendNotice(noticeOnlyBCMod1,u,appNoticeColor); } break; } case '/subject': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg1 || isBC) { newSubject = msg['m'].substring(9).trim() setRoomSubject(newSubject,u); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } //********* Ticket Show Support Commands case '/prepticket': { cmd = 1; if (isModLvlMsg2 || isBC) { if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { prepticketshow(u); cb.sendNotice('Fembot Ticket show prep has been completed.', u, appNoticeColor); } 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, appNoticeColor); } } else { prepticketshow(u); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/backuplist': case '/dspbackup': { cmd = 1; if (ticketShowType != 'Fembot Ticket Show') { if (isModLvlMsg2 || isBC) { if (backupListArray.length > 0) { lengthcheckstring = cbjs.arrayJoin(backupListArray, ', '); if (lengthcheckstring.length < 1020) { backupmsg = 'Users currently on the Backup Ticket List -'; backupmsg += '\nThe /add command is included so you can copy and paste to restore tickets.'; backupmsg += '\nThere are ' + backupListArray.length + ' users in the list:'; backupmsg += '\n' + cbjs.arrayJoin(backupListArray, ', '); backupmsg += '\nEnd of List'; } else { backupmsg = 'Users currently on the Backup Ticket List -'; backupmsg += '\nThe /add command is included so you can copy and paste to restore tickets.'; backupmsg += '\nNote that there are more users than can be added in a single command (' + backupListArray.length + ' users).'; backupmsg += '\nTherefore the list is displayed in multiple chunks.'; currentlength = 5; chunknumber = 1; backupmsg += '\nChunk #1 \n/add '; for (var listindex = 0; listindex < backupListArray.length; listindex++) { if (currentlength + backupListArray[listindex].length < 1020) { if (listindex == 0) { backupmsg += backupListArray[listindex]; } else { backupmsg += ', ' + backupListArray[listindex]; currentlength += 2; } currentlength += backupListArray[listindex].length; } else { currentlength = 5; chunknumber++; backupmsg += '\nChunk #' + chunknumber + '\n/add '; backupmsg += backupListArray[listindex]; currentlength += backupListArray[listindex].length; } } } cb.sendNotice(backupmsg, u, appNoticeColor); } else { cb.sendNotice('There are no users in the backup list.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup list is only used for separate Ticket Apps.', u, appNoticeColor); } break; } case '/backupfb': { cmd = 1; if (ticketShowType != 'Fembot Ticket Show') { if (isModLvlMsg2 || isBC) { cmdval = msg['m'].substring(10).trim(); if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice('Backing up external ticket list in the Fembot.', u, appNoticeColor); 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.', '', appNoticeColor, '', 'normal', 'red'); cb.sendNotice('All users were added.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } else { cb.sendNotice('Fembot: Command is not valid for the Fembot Hidden Ticket Show, backup list is only used for separate Ticket Apps.', u, appNoticeColor); } break; } case '/expbackup': { cmd = 1; if (ticketShowType != 'Fembot Ticket Show') { if (backupToggle == 1) { if (isModLvlMsg2 || isBC) { if (backupListArray.length > 0) { lengthcheckstring = cbjs.arrayJoin(backupListArray, ', '); if (lengthcheckstring.length > 1020) { cb.sendNotice('Fembot: The length of the command string to all ticket list users is longer than the max allowed by Chaturbate (1025 characters). Please use the /backuplist command to view the list in multiple chunks and add back each chunk.', u, appNoticeColor); } else { msg['m'] = '/add ' + cbjs.arrayJoin(backupListArray, ', '); cb.sendNotice('Fembot: 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, appNoticeColor); } } else { cb.sendNotice('Fembot: No Backup Ticket List to add.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } } else { cb.sendNotice('Fembot: The Backup Ticket List is disabled.', u, appNoticeColor); } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup list is only used for separate Ticket Apps.', u, appNoticeColor); } 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,appNoticeColor); } else { LBi = 0; addcmd = '/add '; if (isBC || isModLvlMsg3 || (isModLvlMsg1 && hiddenShowModsAdd)) { 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, appNoticeColor); 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, appNoticeColor); } if (ticketShowType != 'Fembot Ticket Show') { addFromLeaderboard('num', numLB, u); 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, appNoticeColor); } else { cb.sendNotice('No Leaderboard entries to add.', u, appNoticeColor); } } else { if (ticketShowToggle == 1) { addFromLeaderboard('num', numLB, u); if (addLBstring != '') { cb.sendNotice('The top ' + numLB + ' tippers from the Leaderboard have been added to the Fembot Ticket Show.', u, appNoticeColor); } else { cb.sendNotice('No Leaderboard entries to add.', u, appNoticeColor); } } else { cb.sendNotice('Before using the "Add Leaderboard" function, the ticket show feature must first be enabled when using the Fembot Ticket Show.', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod3A, u,appNoticeColor); } } 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,appNoticeColor); } else { LBi = 0; addcmd = '/add '; if (isBC || isModLvlMsg3 || (isModLvlMsg1 && hiddenShowModsAdd)) { amtLB = parseInt(message[1]) if (isNaN(amtLB)) { cb.sendNotice('The value entered for the tip amount is not numeric, please try again.', u, appNoticeColor); 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, appNoticeColor); } if (ticketShowType != 'Fembot Ticket Show') { addFromLeaderboard('amt', amtLB, u); 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, appNoticeColor); } else { cb.sendNotice('No qualifying tippers to add.', u, appNoticeColor); } } else { if (ticketShowToggle == 1) { addFromLeaderboard('amt', amtLB, u); if (addLBstring != '') { cb.sendNotice('Users who have tipped more than ' + amtLB + ' during this session have been added to the Fembot Ticket Show.', u, appNoticeColor); } else { cb.sendNotice('No qualifying tippers to add.', u, appNoticeColor); } } else { cb.sendNotice('Before using the "Add Leaderboard" function, the ticket show feature must first be enabled when using the Fembot Ticket Show.', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod3A, u, appNoticeColor); } } break; } case '/backupprice': case '/bup': { cmd = 1; if (isModLvlMsg2 || 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, appNoticeColor); } else if (backupToggle != 1) { cb.sendNotice('The backup list is disabled, you can use the command "/usebackup on" to enable the backup.', u, appNoticeColor); } else { ticketPrice = numprice; cb.sendNotice('From Fembot: Backup List ticket price has been updated to ' + numprice + ' tokens.', u, appNoticeColor); } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup price is only used for separate Ticket Apps.', u, appNoticeColor); } } break; } case '/usebackup': { cmd = 1; if (ticketShowType != 'Fembot Ticket Show') { if (isModLvlMsg2 || 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".', u, appNoticeColor); } else { setBackupToggle(message[1],u,true) } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup list is only used for separate Ticket Apps.', u, appNoticeColor); } break; } //********* Tip Menu Commands case '/tipmenu': { cmd = 1; sendnotice = false; if (tipMenuToggle == 1) { sendto = u; if (isModLvlMsg1 && modSpecificMenuItems) { var mainsndmodmsg = 'Sent to YOU:'; if (cb.settings.tipMenuModSalePct > 0) { mainsndmodmsg += '\nAs a moderator, your Tip Menu is discounted ' + cb.settings.tipMenuModSalePct + '%'; } mainsndmodmsg += '\n' + TIPMENUMOD.tipMenu; cb.sendNotice(mainsndmodmsg, sendto, TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } else if (isFanMsg && cbfcSpecificMenuItems) { var mainsndfanmsg = 'Sent to YOU:'; if (cb.settings.tipMenuCBFCSalePct > 0) { mainsndfanmsg += '\nAs a Fan Club member, your Tip Menu is discounted ' + cb.settings.tipMenuCBFCSalePct + '%'; } else { mainsndfanmsg += '\n** Displaying general menu first:'; mainsndfanmsg += '\n' + TIPMENU.tipMenu; mainsndfanmsg += '\n** Displaying your Fan Club specific menu items:'; } mainsndfanmsg += '\n' + TIPMENUCBFC.tipMenu; cb.sendNotice(mainsndfanmsg, sendto, TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } else if (isExtFanMsg && efc1SpecificMenuItems) { var mainsndefc1msg = 'Sent to YOU:'; if (cb.settings.tipMenuEFC1SalePct > 0) { mainsndefc1msg += '\nAs a ' + EFCname + ' member, your Tip Menu is discounted ' + cb.settings.tipMenuEFC1SalePct + '%'; } else { mainsndefc1msg += '\nDisplaying general menu first:'; mainsndefc1msg += '\n' + TIPMENU.tipMenu; mainsndefc1msg += '\nDisplaying your ' + EFCname + ' menu items:'; } mainsndefc1msg += '\n' + TIPMENUEFC1.tipMenu; cb.sendNotice(mainsndefc1msg, sendto, TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } else if (isExtFanMsg2 && efc2SpecificMenuItems) { var mainsndefc2msg = 'Sent to YOU:'; if (cb.settings.tipMenuEFC2SalePct > 0) { mainsndefc2msg += '\nAs a ' + EFCname2 + ' member, your Tip Menu is discounted ' + cb.settings.tipMenuEFC2SalePct + '%'; } else { mainsndefc2msg += '\nDisplaying general menu first:'; mainsndefc2msg += '\n' + TIPMENU.tipMenu; mainsndefc2msg += '\nDisplaying ' + EFCname2 + ' menu items:'; } mainsndefc2msg += '\n' + TIPMENUEFC2.tipMenu; cb.sendNotice(mainsndefc2msg, sendto, TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } else if (isVIPMsg && vipSpecificMenuItems) { var mainsndvipmsg = 'Sent to YOU:'; if (cb.settings.tipMenuVIPSalePct > 0) { mainsndvipmsg += '\nAs a VIP, your Tip Menu is discounted ' + cb.settings.tipMenuVIPSalePct + '%'; } mainsndvipmsg += '\n' + TIPMENUVIP.tipMenu; cb.sendNotice(mainsndvipmsg, sendto, TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } else { if (isModLvlMsg1 || isBC) { sendto = ''; cb.sendNotice('Sent to ALL:\n' + TIPMENU.tipMenu, sendto, TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } else { sendto = u; cb.sendNotice('Sent to YOU:\n' + TIPMENU.tipMenu, sendto, TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } if (cb.settings.tipMenuSalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! Tip Menu prices have been discounted ' + cb.settings.tipMenuSalePct + '% off normal prices!', '', TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } } sendnotice = true; } else if (tipMenu2Toggle == 1) { if (isModLvlMsg1 || isBC) { sendto = ''; cb.sendNotice('Sent to ALL:\n' + TIPMENU2.tipMenu, sendto, TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); } else { sendto = u; cb.sendNotice('Sent to YOU:\n' + TIPMENU2.tipMenu, sendto, TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); } if (cb.settings.tipMenu2SalePct > 0) { cb.sendNotice('There is a Tip Menu sale today! Tip Menu prices have been discounted ' + cb.settings.tipMenu2SalePct + '% off normal prices!', '', TIPMENU2.bgColor1, TIPMENU2.txtColor1, 'bold'); } sendnotice = true; } else { cb.sendNotice('Fembot: The Tip Menu has not been enabled.', u, appNoticeColor); } if (sendnotice && !isBC && !isModLvlMsg1) { if (cb.settings.alertBCWhenReq == 'Broadcaster Only' || cb.settings.alertBCWhenReq == 'Broadcaster and Moderators') { cb.sendNotice('Fembot: The Tip menu was requested by ' + u + '.', BC, appNoticeColor, ''); } if (cb.settings.alertBCWhenReq == 'Moderators Only' || cb.settings.alertBCWhenReq == 'Broadcaster and Moderators') { cb.sendNotice('Fembot: The Tip menu was requested by ' + u + '.', '', appNoticeColor, '', '', 'red'); } } break; } case '/tipmenumod': { cmd = 1; if (isModLvlMsg1 || isBC) { if (tipMenuToggle == 1) { if (modSpecificMenuItems) { var sndmodmsg = 'Sent to YOU:'; if (cb.settings.tipMenuModSalePct > 0) { sndmodmsg += '\n(Menu is discounted ' + cb.settings.tipMenuModSalePct + '%)'; } sndmodmsg += '\n' + TIPMENUMOD.tipMenu; cb.sendNotice(sndmodmsg, u, TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } else { cb.sendNotice('There is not a moderator discount available.', u, appNoticeColor); } } else { cb.sendNotice('The moderator specific menu is only valid for Tip Menu 1.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1,u,appNoticeColor); } break; } case '/tipmenuvip': { cmd = 1; if (isModLvlMsg1 || isBC || isVIPMsg) { if (tipMenuToggle == 1) { if (vipSpecificMenuItems) { var sndvipmsg = 'Sent to YOU:'; if (cb.settings.tipMenuVIPSalePct > 0) { sndvipmsg += '\n(Menu is discounted ' + cb.settings.tipMenuVIPSalePct + '%)'; } sndvipmsg += '\n' + TIPMENUVIP.tipMenu; cb.sendNotice(sndvipmsg, u, TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } else { cb.sendNotice('There is not a VIP discount available.', u, appNoticeColor); } } else { cb.sendNotice('The VIP specific menu is only valid for Tip Menu 1.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1,u,appNoticeColor); } break; } case '/tipmenufan': { cmd = 1; if (isModLvlMsg1 || isBC || isFanMsg) { if (tipMenuToggle == 1) { if (cbfcSpecificMenuItems) { var sndfanmsg = 'Sent to YOU:'; if (cb.settings.tipMenuCBFCSalePct > 0) { sndfanmsg += '\n(Menu is discounted ' + cb.settings.tipMenuCBFCSalePct + '%)'; } else { sndfanmsg += '\nDisplaying general menu first:'; sndfanmsg += '\n' + TIPMENU.tipMenu; sndfanmsg += '\nDisplaying fan club specific menu items:'; } sndfanmsg += '\n' + TIPMENUCBFC.tipMenu; cb.sendNotice(sndfanmsg, u, TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } else { cb.sendNotice('There is not a CB Fanclub menu or discount available.', u, appNoticeColor); } } else { cb.sendNotice('The CB Fanclub specific menu is only valid for Tip Menu 1.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1,u,appNoticeColor); } break; } case '/tipmenufc1': { cmd = 1; if (isModLvlMsg1 || isBC || isExtFanMsg) { if (tipMenuToggle == 1) { if (efc1SpecificMenuItems) { var sndefc1msg = 'Sent to YOU:'; if (cb.settings.tipMenuEFC1SalePct > 0) { sndefc1msg += '\n(Menu is discounted ' + cb.settings.tipMenuEFC1SalePct + '%)'; } else { sndefc1msg += '\nDisplaying general menu first:'; sndefc1msg += '\n' + TIPMENU.tipMenu; sndefc1msg += '\nDisplaying ' + EFCname + ' menu items:'; } sndefc1msg += '\n' + TIPMENUEFC1.tipMenu; cb.sendNotice(sndefc1msg, u, TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } else { cb.sendNotice('There is not a ' + EFCname + ' menu or discount available.', u, appNoticeColor); } } else { cb.sendNotice('The ' + EFCname + ' specific menu is only valid for Tip Menu 1.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1,u,appNoticeColor); } break; } case '/tipmenufc2': { cmd = 1; if (isModLvlMsg1 || isBC || isExtFanMsg2) { if (tipMenuToggle == 1) { if (efc2SpecificMenuItems) { var sndefc2msg = 'Sent to YOU:'; if (cb.settings.tipMenuEFC2SalePct > 0) { sndefc2msg += '\n(Menu is discounted ' + cb.settings.tipMenuEFC2SalePct + '%)'; } else { sndefc2msg += '\nDisplaying general menu first:'; sndefc2msg += '\n' + TIPMENU.tipMenu; sndefc2msg += '\nDisplaying ' + EFCname2 + ' menu items:'; } sndefc2msg += '\n' + TIPMENUEFC2.tipMenu; cb.sendNotice(sndefc2msg, u, TIPMENU.bgColor1, TIPMENU.txtColor1, 'bold'); } else { cb.sendNotice('There is not a ' + EFCname2 + ' menu or discount available.', u, appNoticeColor); } } else { cb.sendNotice('The ' + EFCname2 + ' specific menu is only valid for Tip Menu 1.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1,u,appNoticeColor); } break; } case '/swapmenu': { cmd = 1; if (isModLvlMsg2 || 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('Fembot: Both menus are currently disabled, they cannot be swapped. You can turn one of the menus on using either /usemenu on or /usemenu2 on. Ignore this message if the command was for Dorothy\'s Tip Menu Pro.', u, appNoticeColor); } else { cb.sendNotice('Fembot: Invalid definition, both menus are already active.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } case '/usemenu': { cmd = 1; if (isModLvlMsg2 || isBC) { if (tipMenu2Toggle == 1 && message[1] === 'on') { cb.sendNotice('Fembot: Cannot enable Tip Menu 1 while Tip Menu 2 is active. You can use the "/swapmenu" command to switch between the two.', u, appNoticeColor); } else { setTipMenuToggle(message[1],u) } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } case '/usemenu2': { cmd = 1; if (isModLvlMsg2 || isBC) { if (tipMenuToggle == 1 && message[1] === 'on') { cb.sendNotice('Fembot: Cannot enable Tip Menu 2 while Tip Menu 1 is active. You can use the "/swapmenu" command to switch between the two.', u, appNoticeColor); } else { setTipMenu2Toggle(message[1],u) } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } case '/tmr': case '/tmrb': case '/tipmenurequests': { cmd = 1; if (isModLvlMsg1 && command == '/tmrb') { sendto = BC; cb.sendNotice('Fembot: You have sent the list of Tip Menu Requests to the broadcaster.', u, appNoticeColor); } else { sendto = u; } let requestLines = tipMenuRequests.name.length; let linesToShow = 0; if (requestLines <= 0) { cb.sendNotice('Fembot: There have been no Tip Menu requests.', u, appNoticeColor); } else if (message[1] && message[1] != 'all' && message[1] != 'All' && message[1] != 'ALL' && (isNaN(message[1]) || message[1] <= 0)) { cb.sendNotice('Fembot: Invalid parameter for number of requests to display, must be a number greater than zero, "all", or blanks (blanks defaults to last 10).', u, appNoticeColor); } else { let noticeMsg; let startIndex = 0; if (message[1] === 'all' || message[1] === 'All' || message[1] === 'ALL') { linesToShow = requestLines; } else if (message[1]) { linesToShow = parseInt(message[1]); } else { linesToShow = 10; } if (linesToShow > requestLines) { if (message[1]) { cb.sendNotice('Fembot: Requested more entries than available, showing entire list.', u, appNoticeColor); } linesToShow = requestLines; } else if (linesToShow > 100) { cb.sendNotice('Fembot: Maximum list size is 100 entries, defaulting to 100.', u, appNoticeColor); linesToShow = 100; } noticeMsg = '**** Here ' + (linesToShow === 1 ? 'is the last' : 'are the last ' + linesToShow) + ' tip menu request' + (linesToShow === 1 ? '' : 's') + '! **** \n'; startIndex = requestLines - linesToShow; for (let tmridx = startIndex; tmridx < requestLines; tmridx++) { currenttimecalc = new Date(); howlongago = (currenttimecalc.getTime() - tipMenuRequestTime[tmridx]); howlongagoMS = howlongago % 1000; howlongagoSec = ((howlongago - howlongagoMS) % 60000); howlongagoMin = ((howlongago - howlongagoSec - howlongagoMS) % 3600000); howlongagoSec = howlongagoSec / 1000; howlongagoMin = howlongagoMin / 60000; if (howlongagoMin < 1) { howlongagoDisp = howlongagoSec + ' sec ago'; } else { howlongagoDisp = howlongagoMin + ' min ago'; } if (tipMenuRequests.desc[tmridx] == 'TMR') { noticeMsg += 'Seq #' + (tmridx + 1) + ': >>> ' + tipMenuRequests.name[tmridx] + ' viewed the tip request summary (' + howlongagoDisp + ') <<<\n'; } else { noticeMsg += 'Seq #' + (tmridx + 1) + ': ' + tipMenuRequests.name[tmridx] + ' tipped ' + tipMenuRequests.amt[tmridx] + ' for ' + tipMenuRequests.desc[tmridx] + ' (' + howlongagoDisp + ')\n'; } } noticeMsg += '**************************************'; tipMenuRequests.name.push(u); tipMenuRequests.desc.push('TMR'); tipMenuRequests.amt.push(0); currenttimereq = new Date(); tipMenuRequestTime.push(currenttimereq.getTime()); cb.sendNotice(noticeMsg, sendto, appWarningColor); } break; } case '/tipmenuprice': { cmd = 1; if (!isModLvlMsg2 && !isBC) { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } else { let label; let newItemPrice = parseInt(message[1]); if (newItemPrice <= 0 || isNaN(newItemPrice)) { cb.sendNotice('Fembot: The correct command format is "/tipmenuprice X Y" where "X" is the new price and must be a number over 0, and "Y" is the exact match of the current description of the item.', u, appNoticeColor); return; } if (!message[2]) { cb.sendNotice('Fembot: The second parameter for menu item description is missing. The correct command format is "/tipmenuprice X Y" where "X" is the new price and must be a number over 0, and "Y" is the exact match of the current description of the item.', u, appNoticeColor); return; } for (let j = 2; j < message.length; j++) { if (j === 2) { label = message[j]; } else { label += ' ' + message[j]; } } if (tipMenuToggle == 1) { if (!cbjs.arrayContains(TIPMENU.tipMenuItem, label)) { cb.sendNotice('Fembot: Tip Menu item with description "' + label + '" was not found. Make sure you are entering an exact match of the menu item description, including upper and lower case.', u, appNoticeColor); } else { menuitemindex = TIPMENU.tipMenuItem.indexOf(label); priceChecker('rmv','Tip Menu Option: '+label, TIPMENU.tipMenuPrice[menuitemindex]); TIPMENU.tipMenuPrice[menuitemindex] = newItemPrice; priceChecker('add','Tip Menu Option: '+label, newItemPrice); cb.sendNotice('Tip menu to ' + bctext + ' - ' + (u === cb.room_slug ? 'You' : u) + ' updated the price of "' + label + '" to ' + newItemPrice + ' tokens.', cb.room_slug, appNoticeColor); cb.sendNotice('Tip menu to mods - ' + u + ' updated the price of "' + label + '" to ' + newItemPrice + ' tokens.', '', appNoticeColor, '', '', 'red'); buildMenu(); } } else if (tipMenu2Toggle == 1) { if (!cbjs.arrayContains(TIPMENU2.tipMenuItem, label)) { cb.sendNotice('Fembot: Tip Menu item with description "' + label + '" was not found. Make sure you are entering an exact match of the menu item description, including upper and lower case.', u, appNoticeColor); } else { menuitemindex = TIPMENU2.tipMenuItem.indexOf(label); priceChecker('rmv','Tip Menu 2 Option: '+label, TIPMENU2.tipMenuPrice[menuitemindex]); TIPMENU2.tipMenuPrice[menuitemindex] = newItemPrice; priceChecker('add','Tip Menu 2 Option: '+label, newItemPrice); cb.sendNotice('Tip menu to ' + bctext + ' - ' + (u === cb.room_slug ? 'You' : u) + ' updated the price of "' + label + '" to ' + newItemPrice + ' tokens.', cb.room_slug, appNoticeColor); cb.sendNotice('Tip menu to mods - ' + u + ' updated the price of "' + label + '" to ' + newItemPrice + ' tokens.', '', appNoticeColor, '', '', 'red'); buildMenu2(); } } } break; } case '/tipmenuadd': { cmd = 1; if (!isModLvlMsg2 && !isBC) { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } else { let label; let newItemPrice = parseInt(message['1']); if (newItemPrice <= 0 || isNaN(newItemPrice)) { cb.sendNotice('Fembot: The correct format is "/tipmenuadd X item" where X has to be a number over 0. This is the amount the viewers will tip for it.', u, appNoticeColor); return; } if (!message[2]) { cb.sendNotice('Fembot: You need to include a label for that option.', u, appNoticeColor); 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 ' + bctext + ' - ' + (u === cb.room_slug ? 'You' : u) + ' added the option "' + label + '" for ' + newItemPrice + ' tokens to the menu.', cb.room_slug, appNoticeColor); cb.sendNotice('Tip menu to mods - ' + u + ' added the option "' + label + '" for ' + newItemPrice + ' tokens the menu.', '', appNoticeColor, '', '', 'red'); TIPMENU.tipMenuPrice.push(newItemPrice); TIPMENU.tipMenuItem.push(label); priceChecker('add','Tip Menu Option: '+label, newItemPrice); buildMenu(); } else if (tipMenu2Toggle == 1) { cb.sendNotice('Tip menu to ' + bctext + ' - ' + (u === cb.room_slug ? 'You' : u) + ' added the option "' + label + '" for ' + newItemPrice + ' tokens to Menu 2.', cb.room_slug, appNoticeColor); cb.sendNotice('Tip menu to mods - ' + u + ' added the option "' + label + '" for ' + newItemPrice + ' tokens to Menu 2.', '', appNoticeColor, '', '', '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, appNoticeColor); } TIPMENU2.tipMenuPrice.push(newItemPrice); TIPMENU2.tipMenuItem.push(label); priceChecker('add','Tip Menu 2 Option: '+label, newItemPrice); buildMenu2(); } } break; } case '/tipmenurmv': { cmd = 1; if (!isModLvlMsg2 && !isBC) { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } 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('Fembot: Error! Price must be greater than 0.', '', appNoticeColor); return; } if (tipMenuToggle == 1) { if (itemPrice > 0) { if (cbjs.arrayContains(TIPMENU.tipMenuPrice, itemPrice)) { if (!message[2]) { cb.sendNotice('Fembot: 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, appNoticeColor); 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('Fembot: Tip menu to ' + bctext + ' - ' + (u === cb.room_slug ? 'You' : u) + ' removed the option "' + TIPMENU.tipMenuItem[i] + '" from the menu.', cb.room_slug, appNoticeColor); cb.sendNotice('Fembot: Tip menu to mods - ' + u + ' removed the option "' + TIPMENU.tipMenuItem[i] + '" from the menu.', '', appNoticeColor, '', '', 'red'); } } buildMenu(); } 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('Fembot: Tip menu to ' + bctext + ' - ' + (u === cb.room_slug ? 'You' : u) + ' removed the option "' + TIPMENU.tipMenuItem[i] + '" from the menu.', cb.room_slug, appNoticeColor); cb.sendNotice('Fembot: Tip menu to mods - ' + u + ' removed the option "' + TIPMENU.tipMenuItem[i] + '" from the menu.', '', appNoticeColor, '', '', 'red'); buildMenu(); } } if (!labelFound) { cb.sendNotice('Fembot: Tip menu - Unable find item ' + label + '(' + itemPrice + ') on the menu. Skipping.', u, appNoticeColor); } } } else { cb.sendNotice('Fembot: Tip menu - Unable find any item at ' + itemPrice + ' tokens on the menu.', u, appNoticeColor); } } 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, appNoticeColor); } 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('Fembot: Tip menu to ' + bctext + ' - ' + (u === cb.room_slug ? 'You' : u) + ' removed the option "' + TIPMENU.tipMenuItem[i] + '" from the menu.', cb.room_slug, appNoticeColor); cb.sendNotice('Fembot: Tip menu to mods - ' + u + ' removed the option "' + TIPMENU.tipMenuItem[i] + '" from the menu.', '', appNoticeColor, '', '', 'red'); } } buildMenu(); } else { cb.sendNotice('Fembot: Tip menu - Unable find item ' + label + ' on the menu. Skipping.', u, appNoticeColor); } } } else if (tipMenu2Toggle == 1) { if (itemPrice > 0) { if (cbjs.arrayContains(TIPMENU2.tipMenuPrice, itemPrice)) { if (!message[2]) { cb.sendNotice('Fembot: Tip menu 2 - No label was found! Every options that match "' + itemPrice + '" will be removed from menu 2.', u, appNoticeColor); 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('Fembot: Tip menu 2 to ' + bctext + ' - ' + (u === cb.room_slug ? 'You' : u) + ' removed the option "' + TIPMENU2.tipMenuItem[i] + '" from menu 2.', cb.room_slug, appNoticeColor); cb.sendNotice('Fembot: Tip menu 2 to mods - ' + u + ' removed the option "' + TIPMENU2.tipMenuItem[i] + '" from menu 2.', '', appNoticeColor, '', '', 'red'); } } buildMenu2(); } 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('Fembot: Tip menu 2 to ' + bctext + ' - ' + (u === cb.room_slug ? 'You' : u) + ' removed the option "' + TIPMENU2.tipMenuItem[i] + '" from menu 2.', cb.room_slug, appNoticeColor); cb.sendNotice('Fembot: Tip menu 2 to mods - ' + u + ' removed the option "' + TIPMENU2.tipMenuItem[i] + '" from menu 2.', '', appNoticeColor, '', '', 'red'); buildMenu2(); } } if (!labelFound) { cb.sendNotice('Fembot: Tip menu 2 - Unable find item ' + label + '(' + itemPrice + ') on menu 2. Skipping.', u, appNoticeColor); } } } else { cb.sendNotice('Fembot: Tip menu 2 - Unable find any item at ' + itemPrice + ' tokens on menu 2.', u, appNoticeColor); } } else { if (!label) { cb.sendNotice('Fembot: 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, appNoticeColor); } 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('Fembot: Tip menu 2 to ' + bctext + ' - ' + (u === cb.room_slug ? 'You' : u) + ' removed the option "' + TIPMENU2.tipMenuItem[i] + '" from menu 2.', cb.room_slug, appNoticeColor); cb.sendNotice('Fembot: Tip menu 2 to mods - ' + u + ' removed the option "' + TIPMENU2.tipMenuItem[i] + '" from menu 2.', '', appNoticeColor, '', '', 'red'); } } buildMenu(); } else { cb.sendNotice('Fembot: Tip menu 2 - Unable find item ' + label + ' on menu 2. Skipping.', u, appNoticeColor); } } } } break; } //********* Positions Tip Menu Commands case '/posmenu': { cmd = 1; if (posTipMenuToggle == 1) { if (isModLvlMsg1) { u = ''; } cb.sendNotice('Sent to YOU:\n' + POSTIPMENU.posTipMenu, u, POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor, "bold"); } else { cb.sendNotice('The Positions Tip Menu has not been enabled.', u, appNoticeColor); } break; } case '/useposmenu': { cmd = 1; if (isModLvlMsg2 || isBC) { setPosTipMenuToggle(message[1], u) } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/posmenurequests': { cmd = 1; m.background = '#d9d9d9'; if (isModLvlMsg1) { 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 (!isModLvlMsg2 && !isBC) { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } 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); buildPosMenu(); } break; } case '/posmenurmv': { cmd = 1; m.background = '#d9d9d9'; if (!isModLvlMsg2 && !isBC) { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } 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"); } } buildPosMenu(); } 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"); buildPosMenu(); } } 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"); } } buildPosMenu(); } 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 (cb.settings.pollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (onDemandPollEnabled) { cb.sendNotice('The On-Demand Token Poll is enabled, the Pre-configured Fembot Token Poll cannot be started at the same time.', u, appNoticeColor); } else { setTokenPollToggle(message[1], u) } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } } else { cb.sendNotice('This command is only valid when using the Token Poll in the Fembot, please check setting "13R" if you are not using an external bot for the poll. To start the poll in Dorothy\'s Token Poll, use the command /startpoll.',u,appNoticeColor); } break; } case '/poll': { cmd = 1; if (cb.settings.pollSepBot == 'No') { sendto = u; if (isModLvlMsg1 || isBC) { sendto = 'bc'; } if (tokenPollToggle == 1) { showBoard(sendto); } else if (onDemandPollRunning) { showODBoard(sendto); } else { cb.sendNotice('The Token Poll is disabled.', u, appNoticeColor); } } break; } case '/endpoll': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (tokenPollToggle == 1) { cb.sendNotice(u + ' has ended the poll. No more votes will be counted.', '', tokenPollBgColor, tokenPollTextColor, 'bold'); if (pollRunning) { pollRunning = false; } showWinner(''); } else if (onDemandPollRunning) { cb.sendNotice(u + ' has ended the poll. No more votes will be counted.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); onDemandPollRunning = false; odshowWinner(''); } else { cb.sendNotice('The Token Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } } break; } case '/restartpoll': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (tokenPollToggle == 1) { cb.sendNotice(u + ' has restarted the poll, voting has resumed.', '', tokenPollBgColor, tokenPollTextColor, 'bold'); if (!pollRunning) { pollRunning = true; pollType = 'Never'; } } else if (onDemandPollEnabled) { cb.sendNotice(u + ' has restarted the poll, voting has resumed.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); if (!onDemandPollRunning) { onDemandPollRunning = true; } } else { cb.sendNotice('The Token Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } } break; } case '/resetpoll': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (tokenPollToggle == 1) { pollArrayVotes.fill(0); totalPollVotes = 0; cb.sendNotice(u + ' has reset the poll vote counts, voting is now starting over.', '', tokenPollBgColor, tokenPollTextColor, 'bold'); if (!pollRunning) { pollRunning = true; pollType = 'Never'; } } else if (onDemandPollEnabled) { if (onDemandPollRunning) { odpollArrayVotes.fill(0); cb.sendNotice(u + ' has reset the On-demand poll vote counts, voting is now starting over.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); } else { cb.sendNotice('The The current On-demand Poll is in the process of being defined and has not yet been started. Use the /odstart command to begin using the current poll options.', u, appNoticeColor); } } else { cb.sendNotice('The Token Poll is disabled, there is no poll currently running to reset. You can use the command "/usepoll on" to start using the pre-configured poll.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } } break; } case '/addvote': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isBC || isModLvlMsg3 || (isModLvlMsg1 && pollModAdd)) { if (tokenPollToggle == 1) { var amount; var voteFail = true; if (commandVar1 === 0 || commandVar2 === 0) { cb.sendNotice('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', u, appNoticeColor); break; } if (!commandVar1) { cb.sendNotice('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', u, appNoticeColor); break; } if (!commandVar2) { amount = 1; } else { amount = commandVar2; } for (let i = 0; i < pollArrayAmount.length; i++) { if (commandVar1 === pollArrayAmount[i]) { cb.sendNotice(u + ' has ' + (amount > 0 ? 'added' : 'removed') + ' ' + (amount < 0 ? -amount : amount) + ' vote' + (amount === 1 || amount === -1 ? '' : 's') + ' for poll option "' + pollArrayLabel[i] + '".', '', tokenPollBgColor, tokenPollTextColor, 'bold'); pollArrayVotes[i] += amount; totalPollVotes += amount; voteFail = false; if (pollType === 'Vote') { votesRemain -= amount; } checkPollEnd(); break; } } if (voteFail) { cb.sendNotice('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', u, appNoticeColor); break; } } else if (onDemandPollRunning) { var voteFail = true; if (commandVar1 === 0 || commandVar2 === 0) { cb.sendNotice('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', u, appNoticeColor); break; } if (!commandVar1) { cb.sendNotice('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', u, appNoticeColor); break; } if (!commandVar2) { amount = 1; } else { amount = commandVar2; } for (let i = 0; i < odpollArrayAmount.length; i++) { if (commandVar1 == odpollArrayAmount[i]) { cb.sendNotice(u + ' has ' + (amount > 0 ? 'added' : 'removed') + ' ' + (amount < 0 ? -amount : amount) + ' vote' + (amount === 1 || amount === -1 ? '' : 's') + ' for poll option "' + odpollArrayLabel[i] + '".', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); odpollArrayVotes[i] += amount; voteFail = false; break; } } if (voteFail) { cb.sendNotice('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', u, appNoticeColor); break; } } else { cb.sendNotice('The Token Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3A,u,appNoticeColor); } } break; } case '/polloptadd': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (tokenPollToggle == 1) { var label; var oktoadd = 1; if (commandVar1 <= 0 || isNaN(commandVar1)) { cb.sendNotice('The first variable has be be a number greater than 0. This is the amount the viewers will tip to vote for this selection.', u, appNoticeColor); var oktoadd = 0; break; } if (!message[2]) { cb.sendNotice('You must include a label for this voting selection in the second variable.', u, appNoticeColor); var oktoadd = 0; break; } if (pollArrayAmount.length >= 8) { cb.sendNotice('There are already 8 entries in the poll, no more can be added.', u, appNoticeColor); var oktoadd = 0; break; } for (let j = 0; j < pollArrayAmount.length; j++) { if (pollArrayAmount[j] === commandVar1) { cb.sendNotice('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.', u, appNoticeColor); 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) { cb.sendNotice('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.', u, appNoticeColor); var oktoadd = 0; break; } } if(oktoadd == 1) { populatePollArray(label,commandVar1,0,u); priceChecker('add','Poll Option: '+label, commandVar1,u); cb.sendNotice(u + ' added the option "' + label + '" to the poll.', '', tokenPollBgColor, tokenPollTextColor, 'bold'); } } else if (onDemandPollEnabled && !onDemandPollRunning) { cb.sendNotice('The On-demand Token Poll is still being built, please use the /makepoll command.', u, appNoticeColor); } else if (onDemandPollRunning) { var label; var oktoadd = 1; if (commandVar1 <= 0 || isNaN(commandVar1)) { cb.sendNotice('The first variable has be be a number greater than 0. This is the amount the viewers will tip to vote for this selection.', u, appNoticeColor); var oktoadd = 0; break; } if (!message[2]) { cb.sendNotice('You must include a label for this voting selection in the second variable.', u, appNoticeColor); var oktoadd = 0; break; } if (odpollArrayAmount.length >= 8) { cb.sendNotice('There are already 8 entries in the poll, no more can be added.', u, appNoticeColor); var oktoadd = 0; break; } for (let j = 0; j < odpollArrayAmount.length; j++) { if (odpollArrayAmount[j] == commandVar1) { cb.sendNotice('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.', u, appNoticeColor); 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 < odpollArrayLabel.length; j++) { if (odpollArrayLabel[j] == label) { cb.sendNotice('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.', u, appNoticeColor); var oktoadd = 0; break; } } if (oktoadd == 1) { populateODPollArray(label,commandVar1,0,u); priceChecker('add','On-demand Poll Option: '+label,commandVar1,u); cb.sendNotice(u + ' added the option "' + label + '" to the poll.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); } } else { cb.sendNotice('The Token Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } break; } case '/polloptrmv': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (tokenPollToggle == 1) { if (commandVar1 <= 0 || isNaN(commandVar1)) { cb.sendNotice('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.', u, appNoticeColor); break; } if (pollArrayAmount.length <= 2) { cb.sendNotice('There are only 2 entries in the poll, no more can be removed.', u, appNoticeColor); break; } if (cbjs.arrayContains(pollArrayAmount,commandVar1)) { pollindex = pollArrayAmount.indexOf(commandVar1); priceChecker('rmv','Poll Option: '+pollArrayLabel[pollindex], pollArrayAmount[pollindex],u); cb.sendNotice(u + ' removed the option "' + pollArrayLabel[pollindex] + '" from the poll.', '', tokenPollBgColor, tokenPollTextColor, 'bold'); pollArrayAmount.splice(pollindex,1); pollArrayLabel.splice(pollindex,1); pollArrayVotes.splice(pollindex,1); } else { cb.sendNotice('The specified poll option amount is not in the poll, please try again.', u, appNoticeColor); } } else if (onDemandPollEnabled && !onDemandPollRunning) { cb.sendNotice('The On-demand Token Poll is still being built, please finish the poll using the /makepoll command and /odstart command, and then options can be removed.', u, appNoticeColor); } else if (onDemandPollRunning) { if (commandVar1 <= 0 || isNaN(commandVar1)) { cb.sendNotice('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.', u, appNoticeColor); break; } if (odpollArrayAmount.length <= 2) { cb.sendNotice('There are only 2 entries in the poll, no more can be removed.', u, appNoticeColor); break; } if (cbjs.arrayContains(odpollArrayAmount,commandVar1)) { pollindex = odpollArrayAmount.indexOf(commandVar1); priceChecker('rmv','Poll Option: '+odpollArrayLabel[pollindex], odpollArrayAmount[pollindex],u); cb.sendNotice(u + ' removed the option "' + odpollArrayLabel[pollindex] + '" from the poll.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); odpollArrayAmount.splice(pollindex,1); odpollArrayLabel.splice(pollindex,1); odpollArrayVotes.splice(pollindex,1); } else { cb.sendNotice('The specified poll option amount is not in the poll, please try again.', u, appNoticeColor); } } else { cb.sendNotice('The Token Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } break; } case '/pst': case '/pollstarttimer': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg1 || isBC) { if (tokenPollToggle == 1) { if (!pollRunning) { cb.sendNotice('The poll is not running, cannot to start a timer.', u, appNoticeColor); break; } if (pollType == 'Timer' && (pollMinsRemain >= 1 || pollSecsRemain >= 1)) { cb.sendNotice('A timer is already running, please use "/polladdtime [X]" to add time to timer.', u, appNoticeColor); break; } if (!commandVar1) { cb.sendNotice('Invalid command, you need to specify the starting point for the timer in minutes. Example: use "/pollstarttimer 10" to start a 10 minute timer.', u, appNoticeColor); break; } if (commandVar1 > 60) { cb.sendNotice('The time specified is greater than 60 minutes, please use a smaller value.', u, appNoticeColor); break; } commandVar1 = parseInt(commandVar1) if (isNaN (commandVar1)) { cb.sendNotice('Invalid value, the time entered must be a numeric value in minutes. Example: use "/pollstarttimer 10" to start a 10 minute timer.', u, appNoticeColor); break; } if (pollType !== 'Timer') { pollTimerStopping = false; pollSwitchToTimer(commandVar1, u); break; } } else if (onDemandPollEnabled && !onDemandPollRunning) { cb.sendNotice('An on-demand poll has been created but not started. You can add more poll options or use the command /odstart when ready to start the poll', u, appNoticeColor); } else if (onDemandPollRunning) { if (odpollType == 'Timer' && (odpollMinsRemain >= 1 || odpollSecsRemain >= 1)) { cb.sendNotice('A timer is already running, please use "/polladdtime [X]" to add time to timer.', u, appNoticeColor); break; } if (!commandVar1) { cb.sendNotice('Invalid command, you must specify the time to use for the countdown in minutes. Example: use "/pollstarttimer 10" to start a 10 minute timer.', u, appNoticeColor); break; } if (commandVar1 > 60) { cb.sendNotice('The time specified is greater than 60 minutes, please use a smaller value.', u, appNoticeColor); break; } commandVar1 = parseInt(commandVar1) if (isNaN (commandVar1)) { cb.sendNotice('Invalid value, the time entered must be a numeric value in minutes. Example: use "/pollstarttimer 10" to start a 10 minute timer', u, appNoticeColor); break; } if (odpollType !== 'Timer') { odpollTimerStopping = false; odpollSwitchToTimer(commandVar1, u); break; } } else { cb.sendNotice('The Token Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/polltimeleft': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (tokenPollToggle == 1) { if (pollType == 'Timer') { cb.sendNotice(pollTimeLeft(), u, tokenPollBgColor, tokenPollTextColor, 'bold'); break; } else { cb.sendNotice('Timer is not running.', u, appNoticeColor); } } else if (onDemandPollRunning) { if (odpollType == 'Timer') { cb.sendNotice(odpollTimeLeft(), u, odtokenPollBgColor, odtokenPollTextColor, 'bold'); } else { cb.sendNotice('Timer is not running.', u, appNoticeColor); } } else { cb.sendNotice('A Token Poll is not running.', u, appNoticeColor); } } break; } case '/polladdtime': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg1 || isBC) { if (tokenPollToggle == 1) { if (!pollRunning) { cb.sendNotice('The poll is not running, no need to add time.', u, appNoticeColor); } else if (!commandVar1) { cb.sendNotice('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', u, appNoticeColor); } else if (pollType !== 'Timer') { cb.sendNotice('The poll is currently configured for vote count or manual end, a timer is not valid in this mode.', u, appNoticeColor); } else if (pollMinsRemain + commandVar1 <= 0) { cb.sendNotice('The value is over the amount of time left. You can use "/endpoll" to stop the poll and pick the winner.', u, appNoticeColor); } else if (pollMinsRemain + commandVar1 > 60) { cb.sendNotice('The added time will increase the timer to greater than 60 minutes, please use a smaller value.', u, appNoticeColor); } else { pollAddTime(commandVar1, u); } } else if (onDemandPollRunning) { if (!commandVar1) { cb.sendNotice('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', u, appNoticeColor); } else if (odpollType !== 'Timer') { cb.sendNotice('The poll is currently configured for vote count or manual end, a timer is not valid in this mode.', u, appNoticeColor); } else if (odpollMinsRemain + commandVar1 <= 0) { cb.sendNotice('The value is over the amount of time left. You can use "/endpoll" to stop the poll and pick the winner.', u, appNoticeColor); } else if (odpollMinsRemain + commandVar1 > 60) { cb.sendNotice('The added time will increase the timer to greater than 60 minutes, please use a smaller value.', u, appNoticeColor); } else { odpollAddTime(commandVar1, u); } } else { cb.sendNotice('The Token Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/pollstoptimer': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg1 || isBC) { if (tokenPollToggle == 1) { if (!pollRunning) { cb.sendNotice('The poll is not running.', u, appNoticeColor); } else if (pollType != 'Timer' || pollMinsRemain <= 0 || pollSecsRemain <= 0) { cb.sendNotice('A timer is not in use, ignoring command.', u, appNoticeColor); } else if (pollType == 'Timer') { pollType = 'Never'; pollStopTimer(); cb.sendNotice('The timer has been canceled, switching modes to manual end. The poll will go on until stopped by the ' + bctext + ' or a moderator.', '', appWarningColor, '', 'bold'); } } else if (onDemandPollRunning) { if (odpollType != 'Timer' || odpollMinsRemain <= 0 || odpollSecsRemain <= 0) { cb.sendNotice('A timer is not in use, ignoring command.', u, appNoticeColor); } else if (odpollMinsRemain >= 0 || odpollSecsRemain >= 0) { odpollType = 'Never'; odpollStopTimer(); cb.sendNotice('The timer has been canceled, switching modes to manual end. The poll will go on until stopped by the ' + bctext + ' or a moderator.', '', appWarningColor, '', 'bold'); } } else { cb.sendNotice('The Token Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/pollchgtitle': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg1 || isBC) { if (tokenPollToggle == 1) { newtitle = msg['m'].substring(14).trim() if (newtitle) { pollTitle = newtitle; cb.sendNotice('You have updated the poll title to "' + newtitle + '".', u, appNoticeColor); } else { cb.sendNotice('A new title was not specified, please try the command again in the format "/pollchgtitle [new title]".', u, appNoticeColor); } } else if (onDemandPollEnabled) { newtitle = msg['m'].substring(14).trim() if (newtitle) { odpollTitle = newtitle; cb.sendNotice('You have updated the poll title to "' + newtitle + '".', u, appNoticeColor); } else { cb.sendNotice('A new title was not specified, please try the command again in the format "/pollchgtitle [new title]".', u, appNoticeColor); } } else { cb.sendNotice('The Token Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/pl': case '/polllead': { cmd = 1; if (cb.settings.pollSepBot == 'No') { sendto = u; if (isModLvlMsg1 || isBC) { sendto = ''; } if (tokenPollToggle == 1) { cb.sendNotice((sendto == '' ? 'Sent to ALL: ' : 'Sent to YOU: ') + showLead(), sendto, tokenPollBgColor, tokenPollTextColor, 'bold'); } else if (onDemandPollRunning) { cb.sendNotice((sendto == '' ? 'Sent to ALL: ' : 'Sent to YOU: ') + odshowLead(), sendto, odtokenPollBgColor, odtokenPollTextColor, 'bold'); } else { cb.sendNotice('The Token Poll is disabled.', u, appNoticeColor); } } break; } case '/hijackprice': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg3 || isBC) { if (tokenPollToggle == 1 || onDemandPollRunning) { numprice = parseInt(message[1]) if (isNaN(numprice)) { cb.sendNotice('The value entered for the new "hijack" price is not numeric, please try again.', u, appNoticeColor); break; } else if (numprice < 0 || numprice > 99999) { cb.sendNotice('The value entered for new "hijack" price is outside allowable values from 0 to 99999, please try again. Note that a value of 0 will disable the hijack feature.', u, appNoticeColor); } else { stealPollAmount = numprice; if (stealPollAmount == 0) { if (tokenPollToggle == 1) { cb.sendNotice('The "hijacking" of the poll has been disabled.', u, tokenPollBgColor, tokenPollTextColor, 'bold'); } else if (onDemandPollRunning) { cb.sendNotice('The "hijacking" of the poll has been disabled.', u, odtokenPollBgColor, odtokenPollTextColor, 'bold'); } } else { if (tokenPollToggle == 1) { cb.sendNotice('The price to "hijack" the poll has been set to ' + numprice + ' tokens.', u, tokenPollBgColor, tokenPollTextColor, 'bold'); } else if (onDemandPollRunning) { cb.sendNotice('The price to "hijack" the poll has been set to ' + numprice + ' tokens.', u, odtokenPollBgColor, odtokenPollTextColor, 'bold'); } } } } else { cb.sendNotice('The Token Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, u, appNoticeColor); } } break; } //********* On-demand Poll Commands case '/makepoll': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (tokenPollToggle == 1) { cb.sendNotice('The Pre-configured Token Poll is enabled, an on-demand poll cannot be started at the same time. You can disable the pre-configured Fembot poll with the command "/usepoll off".', u, appNoticeColor); } else if (onDemandPollRunning) { cb.sendNotice('The on-demand poll is already running, please use the "/polloptadd" command to add another item to the poll.', u, appNoticeColor); } else { oktoadd = true; if (commandVar1 <= 0 || isNaN(commandVar1)) { cb.sendNotice('The first variable is the poll option price and must be a number greater than 0. This is the amount the viewers will tip to vote for this selection. Sample command format: "/makepoll 13 Take off shirt" to add this option for 13 tokens.', u, appNoticeColor); oktoadd = false; break; } if (!message[2]) { cb.sendNotice('The second parameter is the tip option name and must be entered. It can be a word or phrase, spaces are ok. Sample command format: "/makepoll 13 Take off shirt" to add this option for 13 tokens.', u, appNoticeColor); oktoadd = false; break; } if (tempODPollAmounts.length >= 8) { cb.sendNotice('There are already 8 entries in the poll, no more can be added.', u, appNoticeColor); oktoadd = false; break; } for (let j = 0; j < tempODPollAmounts.length; j++) { if (tempODPollAmounts[j] == commandVar1) { cb.sendNotice('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.', u, appNoticeColor); oktoadd = false; break; } } for (let i = 2; i < message.length; i++) { if (i == 2) { label = message[i]; } else { label += ' ' + message[i]; } } for (let j = 0; j < tempODPollLabels.length; j++) { if (tempODPollLabels[j] == label) { cb.sendNotice('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.', u, appNoticeColor); oktoadd = false; break; } } if (oktoadd) { if (!onDemandPollEnabled) { createOnDemandPoll(u); } addODTempOption(label,commandVar1,u); priceChecker('add','On-demand Poll Option: '+label,commandVar1,u); cb.sendNotice('You have added the option "' + label + '" to the poll. You can add more poll options or use the command "/odstart" when ready to start running the poll.', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } break; } case '/odpollstart': case '/odstart': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (tokenPollToggle == 1) { cb.sendNotice('Fembot: The Pre-configured Token Poll is enabled, an on-demand poll cannot be started at the same time.', u, appNoticeColor); } else if (!onDemandPollEnabled) { cb.sendNotice('Fembot: An on-demand poll has not been created, you can use the command "/makepoll" to add each option, then start the poll.', u, appNoticeColor); } else if (onDemandPollRunning) { cb.sendNotice('Fembot: The on-demand poll is already running.', u, appNoticeColor); } else if (tempODPollLabels.length < 2) { cb.sendNotice('Fembot: At least two options are required in the poll, you can use the command "/makepoll" to add each option, then start the poll.', u, appNoticeColor); } else { startOnDemandPoll(u); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } break; } case '/odoff': { cmd = 1; if (cb.settings.pollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (!onDemandPollEnabled) { cb.sendNotice('Fembot: An on-demand poll has not been created or started.', u, appNoticeColor); } else { disableOnDemandPoll(u) } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } break; } //********* Text Poll Commands case '/usetextpoll': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (message[1]) { var textpollenable = message[1].toLowerCase(); if (textpollenable == 'on' && textPollToggle) { cb.sendNotice('Fembot: The text poll is alreasy enabled.', u, appNoticeColor); } else if (textpollenable == 'off' && !textPollToggle) { cb.sendNotice('Fembot: The text poll is alreasy disabled.', u, appNoticeColor); } else if (textpollenable != 'on' && textpollenable != 'off') { cb.sendNotice('Fembot: An invalid parameter was specified for the /usetextpoll command, allowed values are "on" or "off".', u, appNoticeColor); } else { setTextPollToggle(textpollenable, u) } } else { cb.sendNotice('Fembot: No parameter was specified for the /usetextpoll command, allowed values are "on" or "off".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } } else { cb.sendNotice('Fembot: This command is only valid when using the Text Poll in the Fembot, please check setting "21N" if you are not using an external bot for the poll. To start the poll in Dorothy\'s Text Poll during the show, use the command /starttextpoll.',u,appNoticeColor); } break; } case '/textpoll': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { var tpsendto = u; if (isModLvlMsg1 || isBC) { tpsendto = 'bc'; } if (textPollToggle) { showTextPollBoard(tpsendto); } else { cb.sendNotice('Fembot: The Text Poll is disabled.', u, appNoticeColor); } } break; } case '/endtextpoll': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (textPollToggle) { cb.sendNotice('Fembot: ' + u + ' has ended the text poll. No more votes will be counted.', '', textPollBgColor, textPollTextColor, 'bold'); if (textPollRunning) { textPollRunning = false; } showTextPollWinner(''); } else { cb.sendNotice('Fembot: The Text Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } } break; } case '/restarttextpoll': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (textPollToggle) { cb.sendNotice(u + ' has restarted the text poll, voting has resumed.', '', textPollBgColor, textPollTextColor, 'bold'); if (!textPollRunning) { textPollRunning = true; textPollType = 'Never'; } } else { cb.sendNotice('Fembot: The Text Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } } break; } case '/resettextpoll': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (textPollToggle) { initTextPollValues(); textPollArray.votes.fill(0); cb.sendNotice('Fembot: ' + u + ' has reset the text poll vote counts, voting is now starting over.', '', textPollBgColor, textPollTextColor, 'bold'); if (!textPollRunning) { textPollRunning = true; textPollType = 'Never'; } } else { cb.sendNotice('Fembot: The Text Poll is disabled, there is no poll currently running to reset. You can use the command "/usepoll on" to start using the pre-configured poll.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } } break; } case '/addtextvote': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { if (isBC || isModLvlMsg2) { if (textPollToggle) { var atvamount; var atvfail = true; if (commandVar1 == 0 || commandVar2 == 0) { cb.sendNotice('Fembot: Invalid Entry - The text poll ID number and added vote amount cannot be zero. \n ex: "/addtextvote 3 1" will add 1 vote for the poll option with an ID of 3', u, appNoticeColor); break; } if (!commandVar1) { cb.sendNotice('Fembot: Invalid Entry - The text poll ID number must be specified to add votes to. \n ex: "/addtextvote 3 1" will add 1 vote for the poll option with an ID of 3', u, appNoticeColor); break; } if (!commandVar2) { atvamount = 1; } else { atvamount = commandVar2; } for (let i = 0; i < textPollArray.dispname.length; i++) { if (commandVar1 == textPollArray.voteID[i]) { cb.sendNotice(u + ' has ' + (atvamount > 0 ? 'added' : 'removed') + ' ' + (atvamount < 0 ? -atvamount : atvamount) + ' vote' + (atvamount === 1 || atvamount === -1 ? '' : 's') + ' for poll option "' + pollArrayLabel[i] + '".', '', textPollBgColor, textPollTextColor, 'bold'); textPollArray.votes[i] += atvamount; textPollTotalVotes += atvamount; atvfail = false; if (textPollType === 'Vote') { textPollVotesRemain -= atvamount; } textPollCheckEnd(); break; } } if (atvfail) { cb.sendNotice('Fembot: Invalid Entry - That poll ID number is not currently in the poll. \n The first variable needs to match a poll option ID, the second variable is the number of votes to add.\n ex: "/addtextvote 3 1" will add 1 vote for the poll option with an ID of 3', u, appNoticeColor); break; } } else { cb.sendNotice('Fembot: The Text Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3A,u,appNoticeColor); } } break; } case '/textoptadd': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (textPollToggle) { var toalabel; var toaoktoadd = 1; if (commandVar1 <= 0 || isNaN(commandVar1)) { cb.sendNotice('Fembot: The first variable has be be a number from 1 to 5. This is the poll ID the viewers will enter vote for this selection, and cannot already be used.', u, appNoticeColor); var toaoktoadd = 0; break; } if (!message[2]) { cb.sendNotice('Fembot: You must include a label for this voting selection in the second variable.', u, appNoticeColor); var toaoktoadd = 0; break; } if (pollArrayAmount.length >= 5) { cb.sendNotice('Fembot: There are already 5 entries in the poll, no more can be added.', u, appNoticeColor); var toaoktoadd = 0; break; } for (let j = 0; j < textPollArray.dispname.length; j++) { if (textPollArray.voteID[j] === commandVar1) { cb.sendNotice('Fembot: Poll option ID specified is already used in the poll, and will not be added to the board. Please try again with a unique poll option ID.', u, appNoticeColor); var toaoktoadd = 0; break; } } for (let i = 2; i < message.length; i++) { if (i === 2) { toalabel = message[i]; } else { toalabel += ' ' + message[i]; } } for (let j = 0; j < textPollArray.dispname.length; j++) { if (textPollArray.dispname[j] == toalabel) { cb.sendNotice('Fembot: The Text Poll Option name specified is already used in the poll, and will not be added to the board. Please try again with a unique option name value.', u, appNoticeColor); var toaoktoadd = 0; break; } } if (toaoktoadd == 1) { textPollArray.dispname.push(toalabel); textPollArray.voteID.push(textPollArray.dispname.length); textPollArray.votes.push(0); cb.sendNotice('Fembot: ' + u + ' added the option "' + toalabel + '" to the poll.', '', textPollBgColor, textPollTextColor, 'bold'); } } else { cb.sendNotice('Fembot: The Text Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } break; } case '/textoptrmv': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { if (isModLvlMsg2 || isBC) { if (textPollToggle) { if (commandVar1 <= 0 || isNaN(commandVar1)) { cb.sendNotice('Fembot: The first variable has be be a number greater than 0. This value is the option ID that will be removed.', u, appNoticeColor); break; } if (textPollArray.dispname.length <= 2) { cb.sendNotice('Fembot: There are only 2 entries in the poll, no more can be removed.', u, appNoticeColor); break; } if (cbjs.arrayContains(textPollArray.voteID,commandVar1)) { var tporidx = textPollArray.voteID.indexOf(commandVar1); cb.sendNotice('Fembot: ' + u + ' removed the option "' + textPollArray.dispname[tporidx] + '" from the poll.', '', textPollBgColor, textPollTextColor, 'bold'); textPollArray.voteID.splice(tporidx,1); textPollArray.dispname.splice(tporidx,1); textPollArray.votes.splice(tporidx,1); for (let j = 0; j < textPollArray.dispname.length; j++) { textPollArray.voteID[j] = (j+1); } } else { cb.sendNotice('Fembot: The specified poll option amount is not in the poll, please try again.', u, appNoticeColor); } } else { cb.sendNotice('Fembot: The Text Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } break; } case '/textstarttimer': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { if (isModLvlMsg1 || isBC) { if (textPollToggle) { if (!textPollRunning) { cb.sendNotice('Fembot: The text poll is not running, cannot to start a timer.', u, appNoticeColor); break; } if (textPollType == 'Timer' && (textPollMinsRemain >= 1 || textPollSecsRemain >= 1)) { cb.sendNotice('Fembot: A timer is already running, please use the command /textpolladdtime to add time to timer.', u, appNoticeColor); break; } if (!commandVar1) { cb.sendNotice('Fembot: Invalid command, you need to specify the parameter as number of minutes to put on the timer. Example: use "/textpollstarttimer 10" to start a 10 minute timer.', u, appNoticeColor); break; } if (commandVar1 > 60) { cb.sendNotice('Fembot: The time specified is greater than 60 minutes, please use a smaller value.', u, appNoticeColor); break; } commandVar1 = parseInt(commandVar1) if (isNaN (commandVar1)) { cb.sendNotice('Fembot: Invalid value, the time entered must be a numeric value in minutes from 1 to 60. Example: use "/textpollstarttimer 10" to start a 10 minute timer.', u, appNoticeColor); break; } if (textPollType !== 'Timer') { textPollTimerStopping = false; textPollSwitchToTimer(commandVar1, u); break; } } else { cb.sendNotice('Fembot: The Text Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/texttimeleft': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { if (textPollToggle) { if (textPollType == 'Timer') { cb.sendNotice(textPollTimeLeft(), u, textPollBgColor, textPollTextColor, 'bold'); break; } else { cb.sendNotice('Fembot: Text Poll Timer is not running.', u, appNoticeColor); } } else { cb.sendNotice('Fembot: The Text Poll is disabled.', u, appNoticeColor); } } break; } case '/textaddtime': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { if (isModLvlMsg1 || isBC) { if (textPollToggle) { if (!textPollRunning) { cb.sendNotice('Fembot: The text poll is not running, no need to add time.', u, appNoticeColor); } else if (!commandVar1) { cb.sendNotice('Fembot: Invalid command, you need to specify the amount of time to add to the timer in minutes, from 1 to 60. Example: use "/textpolladdtime 3" to add 3 minutes to the timer', u, appNoticeColor); } else if (textPollType !== 'Timer') { cb.sendNotice('Fembot: The poll is currently configured for vote count or manual end, a timer is not valid in this mode.', u, appNoticeColor); } else if (textPollMinsRemain + commandVar1 <= 0) { cb.sendNotice('Fembot: The value is over the amount of time left. You can use "/endtextpoll" to stop the poll and pick the winner.', u, appNoticeColor); } else if (textPollMinsRemain + commandVar1 > 60) { cb.sendNotice('Fembot: The added time will increase the timer to greater than 60 minutes, please use a smaller value.', u, appNoticeColor); } else { textPollAddTime(commandVar1, u); } } else { cb.sendNotice('Fembot: The Text Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/textstoptimer': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { if (isModLvlMsg1 || isBC) { if (textPollToggle) { if (!textPollRunning) { cb.sendNotice('Fembot: The Text Poll is not running.', u, appNoticeColor); } else if (textPollType != 'Timer' || pollMinsRemain <= 0 || pollSecsRemain <= 0) { cb.sendNotice('Fembot: A timer is not in use, ignoring command.', u, appNoticeColor); } else if (textPollType == 'Timer') { textPollType = 'Never'; textPollStopTimer(); cb.sendNotice('Fembot: The timer has been canceled, switching modes to manual end. The poll will go on until stopped by the ' + bctext + ' or a moderator.', '', appWarningColor, '', 'bold'); } } else { cb.sendNotice('Fembot: The Text Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/textchgtitle': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { if (isModLvlMsg1 || isBC) { if (textPollToggle) { var newtexttitle = msg['m'].substring(14).trim() if (newtexttitle) { textPollTitle = newtexttitle; cb.sendNotice('Fembot: You have updated the text poll title to "' + newtexttitle + '".', u, appNoticeColor); } else { cb.sendNotice('Fembot: A new title was not specified, please try the command again in the format "/textpollchgtitle [new title]".', u, appNoticeColor); } } else { cb.sendNotice('Fembot: The Text Poll is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/textlead': { cmd = 1; if (cb.settings.textPollSepBot == 'No') { var tplsendto = u; if (isModLvlMsg1 || isBC) { tplsendto = ''; } if (textPollToggle) { cb.sendNotice((tplsendto == '' ? 'Sent to ALL: ' : 'Sent to YOU: ') + showTextPollLead(), tplsendto, textPollBgColor, textPollTextColor, 'bold'); } else { cb.sendNotice('Fembot: The Text Poll is disabled.', u, appNoticeColor); } } break; } //********* Lush Menu Commands case '/toymenu': case '/lushmenu': { cmd = 1; if (lushMenuToggle == 1) { if (isModLvlMsg1 || 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, appNoticeColor); } break; } case '/useoscimenu': case '/usehushmenu': case '/useferrimenu': case '/usetoymenu': case '/usetoy': case '/usedomimenu': case '/usenoramenu': case '/uselushmenu': { cmd = 1; if (isModLvlMsg2 || isBC) { whichToyIcon = ':' + whichToy.toLowerCase() + 'sm'; setLushMenuToggle(message[1], u) } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } case '/uselush': { cmd = 1; if (isModLvlMsg2 || isBC) { if (whichToy == 'Lush') { cb.sendNotice('The toy type is already set to "lush", please enter a new toy type.',u,appNoticeColor); } else { whichToy = 'Lush'; whichToyIcon = ':lushsm'; setLushMenu(); cb.sendNotice('You have updated the toy to the "lush".',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } case '/usenora': { cmd = 1; if (isModLvlMsg2 || isBC) { if (whichToy == 'Nora') { cb.sendNotice('The toy type is already set to "nora", please enter a new toy type.',u,appNoticeColor); } else { whichToy = 'Nora'; whichToyIcon = ':norasm'; setLushMenu(); cb.sendNotice('You have updated the toy to the "nora".',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } case '/usedomi': { cmd = 1; if (isModLvlMsg2 || isBC) { if (whichToy == 'Domi') { cb.sendNotice('The toy type is already set to "domi", please enter a new toy type.',u,appNoticeColor); } else { whichToy = 'Domi'; whichToyIcon = ':domism'; setLushMenu(); cb.sendNotice('You have updated the toy to the "domi".',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } case '/usehush': { cmd = 1; if (isModLvlMsg2 || isBC) { if (whichToy == 'Hush') { cb.sendNotice('The toy type is already set to "hush", please enter a new toy type.',u,appNoticeColor); } else { whichToy = 'Hush'; whichToyIcon = ':hushsm'; setLushMenu(); cb.sendNotice('You have updated the toy to the "hush".',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } case '/useosci': { cmd = 1; if (isModLvlMsg2 || isBC) { if (whichToy == 'Osci') { cb.sendNotice('The toy type is already set to "osci", please enter a new toy type.',u,appNoticeColor); } else { whichToy = 'Osci'; whichToyIcon = ':oscism'; setLushMenu(); cb.sendNotice('You have updated the toy to the "osci".',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } case '/useferri': { cmd = 1; if (isModLvlMsg2 || isBC) { if (whichToy == 'Ferri') { cb.sendNotice('The toy type is already set to "ferri", please enter a new toy type.',u,appNoticeColor); } else { whichToy = 'Ferri'; whichToyIcon = ':ferrism'; setLushMenu(); cb.sendNotice('You have updated the toy to the "ferri".',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } case '/chgtoy': { cmd = 1; if (isModLvlMsg2 || isBC) { if (message[1].toLowerCase() == whichToy.toLowerCase()) { cb.sendNotice('The toy type is already set to ' + whichToy + ', please enter a new toy type.',u,appNoticeColor); } else if (message[1].toLowerCase() == 'lush') { whichToy = 'Lush'; whichToyIcon = ':lushsm'; setLushMenu(); cb.sendNotice('You have updated the toy to the "lush".',u,appNoticeColor); } else if (message[1].toLowerCase() == 'domi') { whichToy = 'Domi'; whichToyIcon = ':domism'; setLushMenu(); cb.sendNotice('You have updated the toy to the "domi".',u,appNoticeColor); } else if (message[1].toLowerCase() == 'nora') { whichToy = 'Nora'; whichToyIcon = ':norasm'; setLushMenu(); cb.sendNotice('You have updated the toy to the "nora".',u,appNoticeColor); } else if (message[1].toLowerCase() == 'hush') { whichToy = 'Hush'; whichToyIcon = ':hushsm'; setLushMenu(); cb.sendNotice('You have updated the toy to the "hush".',u,appNoticeColor); } else if (message[1].toLowerCase() == 'osci') { whichToy = 'Osci'; whichToyIcon = ':oscism'; setLushMenu(); cb.sendNotice('You have updated the toy to the "osci".',u,appNoticeColor); } else if (message[1].toLowerCase() == 'ferri') { whichToy = 'Ferri'; whichToyIcon = ':ferrism'; setLushMenu(); cb.sendNotice('You have updated the toy to the "ferri".',u,appNoticeColor); } else { cb.sendNotice('Invalid toy name, valid names are "lush", "nora", "domi", "hush", "ferri", and "osci". Therefore, syntax for command is /chgtoy lush, please try again.',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } break; } //********* Media List commands case "/media": { cmd = 1; if (mediaToggle == 0) { setMediaColors(); } if (isModLvlMsg1 || isBC) { sendto = ""; } else { sendto = u; } showMedia(sendto); break; } case '/usemedia': { cmd = 1; if (isModLvlMsg2 || 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".', u, appNoticeColor); } else { setMediaToggle(message[1],u,true) } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } //********* Tip Response Commands case '/usetr': case '/usetipresponse': { cmd = 1; if (isModLvlMsg2 || 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".', u, appNoticeColor); } else { setTipResponseToggle(message[1],u,true) } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } //********* Pre-sales Commands case '/fbpresale': { cmd = 1; if (isModLvlMsg2 || isBC) { if ((message[1] == 'on' || message[1] == 'ON' || message[1] == 'On') && enablePresales == 'Yes') { cb.sendNotice('Fembot pre-sales are already enabled.', u, appNoticeColor); } else if ((message[1] == 'off' || message[1] == 'OFF' || message[1] == 'Off') && enablePresales == 'No') { cb.sendNotice('Fembot pre-sales are already disabled.', u, appNoticeColor); } else if ((message[1] == 'on' || message[1] == 'ON' || message[1] == 'On') && enablePresales == 'No') { enablePresales = 'Yes'; cb.sendNotice('Fembot pre-sales have been enabled.', u, appNoticeColor); } else if ((message[1] == 'off' || message[1] == 'OFF' || message[1] == 'Off') && enablePresales == 'Yes') { enablePresales = 'No'; cb.sendNotice('Fembot pre-sales have been disabled.', u, appNoticeColor); } else { cb.sendNotice('Invalid parameter for this command, valid values are "on" or "off".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case "/pslist": case "/presalelist": { cmd = 1; if (isModLvlMsg1 || isBC) { cb.sendNotice('Fembot: Users currently on the Pre-sale Ticket List: ' + presaleArray.length, u, appNoticeColor); cb.sendNotice((presaleArray.length > 0 == true ? cbjs.arrayJoin(presaleArray, ', ') : 'No ticket buyers.'), u); cb.sendNotice('End of Pre-sale List', u, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/useps': case '/usepresales': case '/usepresale': { cmd = 1; if (enablePresales == 'Yes') { if (isModLvlMsg2 || 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, appNoticeColor); } } 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } else { cb.sendNotice('Fembot pre-sales not started/ended as they are disabled. This is expected if UltraApp pre-sales are used.', u, appNoticeColor); } break; } case '/psprice': case '/presaleprice': { cmd = 1; if (isModLvlMsg3 || 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, appNoticeColor); 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } } } if (ticketShowType != 'Fembot Ticket Show' && backupToggle == 1) { numprice = parseInt(message[1]) if (!isNaN(numprice)) { setBackupTicketPrice(numprice,u); } } } else { cb.sendNotice(noticeOnlyBCMod3, u, appNoticeColor); } break; } case '/pspt': case '/presalepricetimer': { cmd = 1; if (isModLvlMsg1 || 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); 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, appNoticeColor); 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, appNoticeColor); 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, appNoticeColor); } } } 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/psstarttimer': case '/presalestarttimer': { cmd = 1; if (presalesToggle == 1) { if (isModLvlMsg1 || 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, appNoticeColor); 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, appNoticeColor); } else { presaleMinsRemain = numtimer; presaleAutoTimer(presaleMinsRemain); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.', u, appNoticeColor); } break; } case '/psat': case '/presaleaddtime': { cmd = 1; if (presalesToggle == 1) { if (isModLvlMsg1 || 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, appNoticeColor); 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, appNoticeColor); } else { presaleAddTime(numtimer, u); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.', u, appNoticeColor); } break; } case '/psstoptime': case '/presalestoptime': case '/presalestoptimer': { cmd = 1; if (presalesToggle == 1) { if (isModLvlMsg1 || isBC) { stopPresaleTimer(u); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.', u, appNoticeColor); } 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,appNoticeColor); } else { if (isModLvlMsg2 || 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, appNoticeColor); } } 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, appNoticeColor); } } else { cb.sendNotice('No Pre-sale Ticket List to add.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } } } break; } case '/addps': case '/addpresale': { cmd = 1; if (isBC || isModLvlMsg3 || (isModLvlMsg1 && hiddenShowModsAdd)) { if (presalesToggle == 1) { if (command == '/addps') { cmdval = msg['m'].substring(7).trim(); } else if (command == '/addpresale') { cmdval = msg['m'].substring(12).trim(); } if (cmdval != null) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice('Adding multiple users to the Pre-sale list.', u, appNoticeColor); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { if (!cbjs.arrayContains(presaleArray, cmdvalsplit[i])) { addRmvPresale('add',cmdvalsplit[i],0,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], appNoticeColor); } else { cb.sendNotice(cmdvalsplit[i] + ' is already on the pre-sale list. Skipping.', u); } } } cb.sendNotice('All users were added and notified.', u, appNoticeColor) cb.sendNotice(u + ' has added multiple users to the pre-sale list.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), '', appNoticeColor, '', 'normal', 'red'); } else { if (!cbjs.arrayContains(presaleArray, message[1])) { addRmvPresale('add',message[1],0,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, appNoticeColor); } } else { cb.sendNotice('Fembot: User not added to pre-sale ticket list, the Fembot Ticket Pre-sales feature is disabled.',u,appNoticeColor); } } break; } case '/rmvps': case '/rmvpresale': { cmd = 1; if (isBC || isModLvlMsg3 || (isModLvlMsg1 && hiddenShowModsAdd)) { if (presalesToggle == 1) { if(message[1] != '' && message[1] != null) { if (cbjs.arrayContains(presaleArray,message[1])) { addRmvPresale('rmv',message[1],0,message[1]); cb.sendNotice('User ' + message[1] + ' has been removed from the Pre-Sale Ticket List.', u, appNoticeColor); } else { cb.sendNotice('Note: User is not in the Pre-Sale Ticket List.',u,appNoticeColor); } } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.',u,appNoticeColor); } } break; } case '/psmode': case '/chgpresalemode': { cmd = 1; if (isModLvlMsg2 || 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, appNoticeColor); } else { if (newPresaleMode === presaleMode) { cb.sendNotice('The value entered for the new mode is the same as the existing mode, command ignored.', u, appNoticeColor); } else { setPresaleMode(newPresaleMode,u); } } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/pstimeleft': case '/presaletimeleft': { cmd = 1; if (enablePresales == 'Yes') { if (isModLvlMsg1 || isBC) { if (presaleMinsRemain >= 1 || presaleSecsRemain >= 1) { cb.sendNotice(presaleTimeLeft(), "", appWarningColor, "", "bold"); } else { cb.sendNotice('A pre-sale timer is not running.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } //********* Check Colors case '/checkcolor': { cmd = 1; if (isBC || isModLvlMsg1) { cmdval = msg['m'].substring(12).trim(); 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, appNoticeColor); } else { if (cmdvalsplit[1] != "" && cmdvalsplit[1] != "") { if (cmdvalsplit[1].substring(0,1) == '#') { testTextColor = checkTextColor(cmdvalsplit[1],false); 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],false); } if (cmdvalsplit[0].substring(0,1) == '#') { testBgColor = checkBgColor(cmdvalsplit[0],false); 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],false); } cb.sendNotice("This is your test message for Color Check.", u, testBgColor, testTextColor, "bold") } } } else { cb.sendNotice("No Colors were specified.", u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } //********* Dice Game commands case '/prizes': { cmd = 1; if (diceToggle == 1) { if (isModLvlMsg1 || isBC) { sendto = ''; } else { sendto = u; } diceShowPrizes(sendto); } else { cb.sendNotice('The dice game is not enabled.', u, appNoticeColor); } break; } case '/usedice': { cmd = 1; if (isModLvlMsg2 || isBC) { setDiceToggle(message[1], u); } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/dicerolls': { cmd = 1; if (isModLvlMsg1 || isBC) { diceShowRolls(cb.room_slug); } diceShowRolls(u); break; } case '/chgdiceprice': { cmd = 1; if (isModLvlMsg2 || 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, appNoticeColor); } 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, appNoticeColor); } else { diceRollPrice = numprice; priceChecker('add','Dice Roll Price', diceRollPrice,u); cb.sendNotice(u + ' has updated the Dice Roll Price.', u, appNoticeColor); 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } //********* Time Locked Gray Chat commands case '/usegraylock': { cmd = 1; if (isModLvlMsg2 || isBC) { setGrayLockToggle(message[1], u); } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/cleargraylock': { cmd = 1; if (isModLvlMsg2 || 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/rmvgraylock': { cmd = 1; if (isModLvlMsg2 || isBC) { if (grayLockToggle == 1) { if (!cbjs.arrayContains(grayLockList,u)) { addToLockList(u,isBC,isModLvlMsg2,isFanMsg,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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/addgraylock': { cmd = 1; if (isModLvlMsg2 || isBC) { if (grayLockToggle == 1) { if (!cbjs.arrayContains(grayLockList,u)) { addToLockList(u,isBC,isModLvlMsg2,isFanMsg,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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/chggraytime': { cmd = 1; if (isModLvlMsg2 || 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, appNoticeColor); } 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, appNoticeColor); } else { grayChatTime = nummin; cb.sendNotice('You have updated the Gray Chat Time Threshold to ' + grayChatTime + ' minutes.', u, appNoticeColor); } } 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } //********* "Answer Required" Chat Lock commands case '/useanswerlock': { cmd = 1; if (isModLvlMsg2 || isBC) { if (message[1] == 'on' || message[1] == 'off') { setRequireAnswerToggle(message[1],u,true); } else { cb.sendNotice('Invalid parameter for the /useanswerlock command, valid values are "on" and "off".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/clearanswerlock': { cmd = 1; if (isModLvlMsg2 || 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, appNoticeColor); } 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/setanswerlevel': { cmd = 1; if (isModLvlMsg2 || 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, appNoticeColor); } 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, appNoticeColor); } else { requireAnswerLevel = numlevel; if (requireAnswerLevel == 0) { setRequireAnswerToggle('off',u,true); } else if (requireAnswerLevel == 1) { requireAnswerLevelText = 'Gray Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 1=Gray Users.', u, appNoticeColor); } else if (requireAnswerLevel == 2) { requireAnswerLevelText = 'Light Blue Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 2=Light Blue Users.', u, appNoticeColor); } else if (requireAnswerLevel == 3) { requireAnswerLevelText = 'Dark Blue Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 3=Dark Blue Users.', u, appNoticeColor); } else if (requireAnswerLevel == 4) { requireAnswerLevelText = 'Light Purple Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 4=Light Purple Users.', u, appNoticeColor); } else if (requireAnswerLevel == 5) { requireAnswerLevelText = 'Dark Purple Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 5=Dark Purple Users.', u, appNoticeColor); } } } 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } } else { cb.sendNotice('No ticket buyers yet.', u, appNoticeColor); } } break; } case '/useticketshow': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg2 || 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,appNoticeColor); } else if(message[1] == null) { cb.sendNotice('You did not enter a valid option for /useticketshow, please try again.',u,appNoticeColor); } 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } 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 other Ticket App for the actual show.', u, appNoticeColor); } } break; } case '/chgticketshow': { cmd = 1; if (isModLvlMsg2 || isBC) { if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor, '', '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, appNoticeColor); } } } 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, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/useot': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (isModLvlMsg2 || 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,appNoticeColor); } else if(message[1] == null) { cb.sendNotice('You did not enter a valid option for /useot, please try again.',u,appNoticeColor); } else { setTicketShowOtToggle(message[1], u); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } else { cb.sendNotice('The Ticket Show feature is disabled.', u, appNoticeColor); } } 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, appNoticeColor); cb.sendNotice((outstandingTicketArray.length > 0 == true ? cbjs.arrayJoin(outstandingTicketArray, ', ') : 'No outstanding ticket holders.'), u); cb.sendNotice('End of List', u, appNoticeColor); } else { cb.sendNotice('The Ticket Show Outstanding Ticket feature is disabled.', u, appNoticeColor); } } break; } case "/otchanges": { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (isModLvlMsg1 || isBC) { if (otChangesArray.name.length > 0) { cb.sendNotice('Listing of Changes to the Outstanding Ticket List : ', u, appNoticeColor); 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, appNoticeColor); } else { cb.sendNotice('No entries have been added to the Outstanding Ticket Change list.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } else { cb.sendNotice('The Ticket Show feature is disabled.', u, appNoticeColor); } } break; } case '/ctprice': case '/chgticketprice': case '/ticketprice': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg3 || isBC) { numprice = parseInt(message[1]) if (isNaN(numprice)) { cb.sendNotice('The value entered for the ticket price is not numeric, please try again.', u, appNoticeColor); 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod3, u, appNoticeColor); } } else { if (isModLvlMsg1 || 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 (isModLvlMsg1 || 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, appNoticeColor); 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, appNoticeColor); } else { ticketMinsRemain = numtimer; ticketStartMode = 'timer'; ticketAutoTimer(ticketMinsRemain); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.', u, appNoticeColor); } } break; } case '/addtickettime': case '/ticketaddtime': case '/addtime': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (isModLvlMsg1 || 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, appNoticeColor); } 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, appNoticeColor); } else if(numtimer == 0) { cb.sendNotice('Cannot add zero time.', u, appNoticeColor); } 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, appNoticeColor); } else { ticketAddTime(numtimer, u); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.', u, appNoticeColor); } } break; } case '/ticketstoptime': case '/ticketstoptimer': case '/stoptimer': { cmd = 1; if (ticketShowToggle == 1) { if (isModLvlMsg1 || isBC) { if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { stopTicketTimer(u); } else { cb.sendNotice('A ticket timer is not currently running.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.', u, appNoticeColor); } 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,appNoticeColor); } else { if (command == '/add') { cmdval = msg['m'].substring(5).trim(); } else if (command == '/addticket') { cmdval = msg['m'].substring(11).trim(); } if (ticketShowType == 'Fembot Ticket Show') { if (isBC || isModLvlMsg3 || (isModLvlMsg1 && hiddenShowModsAdd)) { 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, appNoticeColor); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { if (!cb.limitCam_userHasAccess(cmdvalsplit[i])) { addRmvTicket('add', cmdvalsplit[i],'',0,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], appNoticeColor); } else { cb.sendNotice(cmdvalsplit[i] + ' is already on the ticket show list. Skipping.', u); } } } cb.sendNotice('All users were added and notified.', u, appNoticeColor) cb.sendNotice(u + ' has added multiple users to the ticket show list.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), '', appNoticeColor, '', 'normal', 'red'); } else { if (!cb.limitCam_userHasAccess(message[1])) { addRmvTicket('add',message[1],'',0,message[1]); } else { cb.sendNotice('Note: User ' + message[1] + ' is already in the Ticket Show List.',u,appNoticeColor); } } } else { if (!cb.limitCam_userHasAccess(u)) { addRmvTicket('add',u,'',0,u); } else { cb.sendNotice('Note: User ' + u + ' is already in the Ticket Show List.',u,appNoticeColor); } } } else { cb.sendNotice('Note: User not added to ticket list, the Hidden Ticket Show feature is disabled.',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3A, u, appNoticeColor); } } 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, appNoticeColor); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i] != '') { if (!cbjs.arrayContains(backupListArray, cmdvalsplit[i])) { addRmvTicketBackupList('add',cmdvalsplit[i]); cb.sendNotice('User ' + cmdvalsplit[i] + ' has been added to the Backup Ticket List.', u, appNoticeColor); cb.sendNotice(u + ' has added you to the Backup Ticket List.', cmdvalsplit[i], appNoticeColor); } else { cb.sendNotice(cmdvalsplit[i] + ' is already on the Backup Ticket List. Skipping.', u); } } } cb.sendNotice('All users were added and notified.', u, appNoticeColor) cb.sendNotice(u + ' has added multiple users to the Backup Ticket List.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalsplit, ', '), '', appNoticeColor, '', 'normal', 'red'); } else { var cmdvalsingle = message[1].trim(); addRmvTicketBackupList('add',cmdvalsingle); cb.sendNotice('User ' + cmdvalsingle + ' has been added to the Backup Ticket List.', u, appNoticeColor); } } else { addRmvTicketBackupList('add',u); cb.sendNotice('User ' + u + ' has been added to the Backup Ticket List.', u, appNoticeColor); } } else { cb.sendNotice('Note: User not added to backup ticket list, the Backup List is disabled.', u,appNoticeColor); } } } break; } case '/del': case '/delticket': case '/rmvticket': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isBC || isModLvlMsg3 || (isModLvlMsg1 && hiddenShowModsAdd)) { if (ticketShowToggle == 1) { if(message[1] != '' && message[1] != null) { if (cb.limitCam_userHasAccess(message[1])) { addRmvTicket('rmv',message[1],'',0,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,appNoticeColor); } } else { cb.sendNotice('No user was specified for the /rmvticket command.',u,appNoticeColor); } } else { cb.sendNotice('The Hidden Ticket Show feature is disabled.',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3A,u,appNoticeColor); } } else { if (isModLvlMsg1 || isBC) { if (backupToggle == 1) { addRmvTicketBackupList('rmv', message[1]); cb.sendNotice('User ' + message[1] + ' has been removed from the Backup Ticket List.', u, appNoticeColor); } } } break; } case '/giftticket': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,appNoticeColor); } 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,appNoticeColor,'','bold'); cb.sendNotice('Mods: ' + u + ' has gifted a ticket to ' + message[1] + '.','',appNoticeColor,'','','red'); cb.sendNotice('Broadcaster: ' + u + ' has gifted a ticket to ' + message[1] + '.',BC,appNoticeColor); } else { cb.sendNotice('Sorry, you do not have any extra tickets remaining.',u,appNoticeColor); } } else { cb.sendNotice('Sorry, you have not purchased any extra tickets.',u,appNoticeColor); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the use of gifting tickets for this show.',u,appNoticeColor); } } else { cb.sendNotice('The Hidden Ticket Show feature is not currently active.',u,appNoticeColor); } } } break; } case '/givemyticketto': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,appNoticeColor); } 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,appNoticeColor,'','bold'); cb.sendNotice('Mods/Broadcaster: ' + u + ' has gifted their own ticket to ' + message[1] + '.','',appNoticeColor,'','','red'); } else { cb.sendNotice('Sorry, you do not have a ticket purchased or the show has already started.',u,appNoticeColor); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the gifting of tickets for this show.',u,appNoticeColor); } } else { cb.sendNotice('The Hidden Ticket Show feature is not currently active.',u,appNoticeColor); } } } break; } case '/chgticketmode': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg2 || 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, appNoticeColor); } else { if (newTicketMode === ticketStartMode) { cb.sendNotice('The value entered for the new mode is the same as the existing mode, command ignored.', u, appNoticeColor); } else { setTicketMode(newTicketMode,u); } } } else { cb.sendNotice('The Hidden Ticket Show feature is disabled.',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } break; } case '/chgtktauto': case '/chgticketmodeauto': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg2 || 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, appNoticeColor); } 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, appNoticeColor); } else if (newTicketAuto === ticketModeAuto) { cb.sendNotice('The value entered for the new mode is the same as the existing mode, command ignored.', u, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } } } else { cb.sendNotice('The Hidden Ticket Show feature is disabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } break; } case '/tickettimeleft': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle == 1) { if (ticketMinsRemain >= 1 || ticketSecsRemain >= 1) { cb.sendNotice(ticketTimeLeft(), '', appWarningColor, '', 'bold'); } else { cb.sendNotice('A Hidden Ticket Show timer is not running.', u, appNoticeColor); } } else { cb.sendNotice('The Hidden Ticket Show feature is disabled.', u, appNoticeColor); } } 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, appNoticeColor); } } else { cb.sendNotice('The Hidden Ticket Show feature is disabled.', u, appNoticeColor); } } break; } case '/useticket': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,appNoticeColor); } 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,appNoticeColor,'','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,appNoticeColor); 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.','',appNoticeColor,'','','red'); } else { cb.sendNotice('Sorry, you have no outstanding ticket available.',u,appNoticeColor); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the use of outstanding tickets for this show.',u,appNoticeColor); } } else { cb.sendNotice('The Hidden Ticket Show feature is not currently active.',u,appNoticeColor); } } } 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,appNoticeColor,'','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,appNoticeColor); 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.','',appNoticeColor,'','','red'); } else { cb.sendNotice('Sorry, you have no ticket purchase to save, or the show has already started.',u,appNoticeColor); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the ability to save an outstanding tickets for this show.',u,appNoticeColor); } } else { cb.sendNotice('The Hidden Ticket Show feature is not currently active.',u,appNoticeColor); } } break; } case '/addot': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (cb.settings.enableHiddenShowOT == 'Yes') { if (isBC || isModLvlMsg3 || (isModLvlMsg1 && hiddenShowModsAdd)) { 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, appNoticeColor); } else { cb.sendNotice('Cannot add, user is already in the Outstanding Ticket List.',u,appNoticeColor); } } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3A, u,appNoticeColor); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the outstanding ticket show feature.',u,appNoticeColor); } } break; } case '/rmvot': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isBC || isModLvlMsg3 || (isModLvlMsg1 && hiddenShowModsAdd)) { 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, appNoticeColor); } else { cb.sendNotice('Cannot remove, user is not in the Outstanding Ticket List.',u,appNoticeColor); } } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.',u,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3A, u,appNoticeColor); } } break; } case '/startshow': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg2 || 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, appNoticeColor); } else { cb.sendNotice('A Hidden Cam show is already underway.', u, appNoticeColor); } } else { cb.sendNotice('The Fembot ticket show has not been enabled.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } else { if (isModLvlMsg2 || 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, appNoticeColor); } 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, appNoticeColor); } pollSwitchToTimer(timetoadd, u); } } else { cb.sendNotice('Note: Poll Timer not started with /startshow per configuration.', u,appNoticeColor); } 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,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg2 || 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, appNoticeColor); } } else { cb.sendNotice('The Hidden Cam show has not been started or has already ended.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } } 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,appNoticeColor); } else { if (ticketShowType === 'Fembot Ticket Show') { if (isModLvlMsg2 || 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } else { if (isModLvlMsg2 || 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,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg2 || 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } else { if (isModLvlMsg1 || isBC) { if (cb.settings.endPosMenuWithShow == 'Yes' && posTipMenuToggle == 1) { setPosTipMenuToggle('off', u); } } } } break; } case '/ticketsubject': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg1 || 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/ctsubject': { cmd = 1; if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg1 || 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } break; } case '/newticketshow': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg2 || 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, appNoticeColor); cb.sendNotice(cbjs.arrayJoin(ticketlist, ', '), cb.room_slug); cb.sendNotice('End of List', cb.room_slug, appNoticeColor); if (isModLvlMsg2) { 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, appNoticeColor); cb.sendNotice(cbjs.arrayJoin(ticketlist, ', '), u); cb.sendNotice('End of List', u, appNoticeColor); } } else { cb.sendNotice('No ticket buyers in the previous ticket list.', u, appNoticeColor); } initTicketShow(u,ticketPrice); cb.limitCam_removeAllUsers(); while (ticketShowViewerList.length > 0) ticketShowViewerList.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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } } break; } case '/restartshow': { cmd = 1; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', u,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (isModLvlMsg2 || 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } } } break; } //********* Price Check List case '/pricechecklist': { cmd = 1; if (isModLvlMsg1 || isBC) { if (priceCheckArray.name.length > 0) { cb.sendNotice('Alphabetic listing of Price Check Array entries : ', u, appNoticeColor); var outString = ''; for (var i = 0; i < priceCheckArray.name.length; i++) { if (priceCheckArray.name[i] == null) outString += ' ' + i + '. empty' + '\n'; else outString += ' ' + (i+1) + '. ' + '"' + priceCheckArray.name[i] + '"' + ': ' + priceCheckArray.amount[i] + '\n'; } cb.sendNotice(outString,u); cb.sendNotice('End of List', u, appNoticeColor); } else { cb.sendNotice('No entries yet.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } //********* Icon / Nicknames List case '/nnlist': { cmd = 1; if (isModLvlMsg1 || isBC) { if (iconNicknamesArray.name.length > 0) { cb.sendNotice('Listing of Nickname entries : ', u, appNoticeColor); 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, appNoticeColor); } else { cb.sendNotice('No entries yet.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/setusericon': { cmd = 1; if (isModLvlMsg2 || isBC) { if (!message[1]) { cb.sendNotice('Parameter for user is not specified. Command syntax is /setusericon username :iconname', u, appNoticeColor); } else if (!message[2]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setusericon username :iconname', u, appNoticeColor); } 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, appNoticeColor); } else { addUserIcon(u,message[1].toLowerCase(),message[2]); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/setusernn': { cmd = 1; if (isModLvlMsg2 || isBC) { if (!message[1]) { cb.sendNotice('Parameter for user is not specified. Command syntax is /setusernn username nickname', u, appNoticeColor); } 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, appNoticeColor); } else { nnlabel = ''; for (let i = 2; i < message.length; i++) { if (i == 2) { nnlabel = message[i]; } else { nnlabel += ' ' + message[i]; } } if (cbjs.arrayContains(iconNicknamesArray.name,message[1])) { nnindex = iconNicknamesArray.name.indexOf(message[1]); if (nnlabel == 'null') { iconNicknamesArray.nickname[nnindex] = null; cb.sendNotice('The nickname for user ' + message[1] + ' has been cleared.', u, appNoticeColor); } else { iconNicknamesArray.nickname[nnindex] = nnlabel; cb.sendNotice('The nickname for user ' + message[1] + ' has been updated to "' + nnlabel + '".', u, appNoticeColor); } } else { iconNicknamesArray.name.push(message[1]); iconNicknamesArray.icon.push(null); iconNicknamesArray.color.push(null); if (nnlabel == 'null') { iconNicknamesArray.nickname.push(null); cb.sendNotice('An entry has been added for user ' + message[1] + ' with no nickname.', u, appNoticeColor); } else { iconNicknamesArray.nickname.push(nnlabel); cb.sendNotice('An entry has been added for user ' + message[1] + ' with a nickname of "' + nnlabel + '".', u, appNoticeColor); } } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/setusercolor': { cmd = 1; if (isModLvlMsg2 || 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, appNoticeColor); } 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, appNoticeColor); } 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, appNoticeColor); } else { if (cbjs.arrayContains(iconNicknamesArray.name,message[1])) { colorindex = iconNicknamesArray.name.indexOf(message[1]); if (message[2] == 'null') { iconNicknamesArray.color[colorindex] = null; cb.sendNotice('The color for user ' + message[1] + ' has been cleared.', u, appNoticeColor); } else { iconNicknamesArray.color[colorindex] = message[2]; cb.sendNotice('The color for user ' + message[1] + ' has been updated to ' + message[2] + '.', u, appNoticeColor); } } else { iconNicknamesArray.name.push(message[1]); iconNicknamesArray.icon.push(null); iconNicknamesArray.nickname.push(null); if (message[2] == 'null') { iconNicknamesArray.color.push(null); cb.sendNotice('An entry has been added for user ' + message[1] + ' with no color.', u, appNoticeColor); } else { iconNicknamesArray.color.push(message[2]); cb.sendNotice('An entry has been added for user ' + message[1] + ' with a color of ' + message[2] + '.', u, appNoticeColor); } } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/icontips': { cmd = 1; if (iconTipAmountArray.length > 0) { if (isModLvlMsg1 || isBC) { displayIconTipNotice(); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } } else { cb.sendNotice('There are no Tip Amount icons configured.', u, appNoticeColor); } break; } case '/setmodicon': { cmd = 1; if (isModLvlMsg2 || isBC) { if (!message[1]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setmodicon :iconname', u, appNoticeColor); } else if (message[1].substring(0,1) != ':' && message[1] != 'null') { cb.sendNotice('Parameter for icon does not start with a ":" and is not "null". Command syntax is /setmodicon :iconname. The value of "null" can be used to remove an existing setting.', u, appNoticeColor); } else { if (message[1] == 'null') { iconMods = null; cb.sendNotice('You have cleared the CB Moderator group icon.', u, appNoticeColor); } else { iconMods = message[1]; cb.sendNotice('You have updated the CB Moderator group icon to "' + iconMods + '".', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/setbotmodicon': { cmd = 1; if (isModLvlMsg2 || isBC) { if (!message[1]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setbotmodicon :iconname', u, appNoticeColor); } else if (message[1].substring(0,1) != ':' && message[1] != 'null') { cb.sendNotice('Parameter for icon does not start with a ":" and is not "null". Command syntax is /setbotmodicon :iconname. The value of "null" can be used to remove an existing setting.', u, appNoticeColor); } else { if (message[1] == 'null') { iconBotMods = null; cb.sendNotice('You have cleared the Bot Mod group icon.', u, appNoticeColor); } else { iconBotMods = message[1]; cb.sendNotice('You have updated the Bot Mod group icon to "' + iconBotMods + '".', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/setfanicon': { cmd = 1; if (isModLvlMsg2 || isBC) { if (!message[1]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setfanicon :iconname', u, appNoticeColor); } else if (message[1].substring(0,1) != ':' && message[1] != 'null') { cb.sendNotice('Parameter for icon does not start with a ":" and is not "null". Command syntax is /setfanicon :iconname. The value of "null" can be used to remove an existing setting.', u, appNoticeColor); } else { if (message[1] == 'null') { iconFans = null; cb.sendNotice('You have cleared the CB Fan Club group icon.', u, appNoticeColor); } else { iconFans = message[1]; cb.sendNotice('You have updated the CB Fan Club group icon to "' + iconFans + '".', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/setextfanicon': { cmd = 1; if (isModLvlMsg2 || isBC) { if (!message[1]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setextfanicon :iconname', u, appNoticeColor); } else if (message[1].substring(0,1) != ':' && message[1] != 'null') { cb.sendNotice('Parameter for icon does not start with a ":" and is not "null". Command syntax is /setextfanicon :iconname. The value of "null" can be used to remove an existing setting.', u, appNoticeColor); } else { if (message[1] == 'null') { iconExtFans = null; cb.sendNotice('You have cleared the External Fan Club 1 group icon.', u, appNoticeColor); } else { iconExtFans = message[1]; cb.sendNotice('You have updated the External Fan Club 1 group icon to "' + iconExtFans + '".', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/setextfan2icon': { cmd = 1; if (isModLvlMsg2 || isBC) { if (!message[1]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setextfan2icon :iconname', u, appNoticeColor); } else if (message[1].substring(0,1) != ':' && message[1] != 'null') { cb.sendNotice('Parameter for icon does not start with a ":" and is not "null". Command syntax is /setextfan2icon :iconname. The value of "null" can be used to remove an existing setting.', u, appNoticeColor); } else { if (message[1] == 'null') { iconExtFans2 = null; cb.sendNotice('You have cleared the External Fan Club 2 group icon.', u, appNoticeColor); } else { iconExtFans2 = message[1]; cb.sendNotice('You have updated the External Fan Club 2 group icon to "' + iconExtFans2 + '".', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/setvipicon': { cmd = 1; if (isModLvlMsg2 || isBC) { if (!message[1]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setvipicon :iconname', u, appNoticeColor); } else if (message[1].substring(0,1) != ':' && message[1] != 'null') { cb.sendNotice('Parameter for icon does not start with a ":" and is not "null". Command syntax is /setvipicon :iconname. The value of "null" can be used to remove an existing setting.', u, appNoticeColor); } else { if (message[1] == 'null') { iconVIP = null; cb.sendNotice('You have cleared the VIP group icon.', u, appNoticeColor); } else { iconVIP = message[1]; cb.sendNotice('You have updated the VIP group icon to "' + iconVIP + '".', u, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } //********* All Time Tipper List case '/usealltime': { cmd = 1; if (isModLvlMsg2 || 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, appNoticeColor); } 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, appNoticeColor); } else { setAllTimeToggle(message[1], u); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, appNoticeColor); } break; } case '/useking': { cmd = 1; if (isModLvlMsg2 || isBC) { if (message[1] != '0' && message[1] != '1' && message[1] != '2') { cb.sendNotice('You did not enter a valid option for /useking, the parameter should be 0, 1, or 2. \nA value of "0" means off.\nA value of "1" means use the configured name or name updated via command. \nA value of "2" means use the All-Time Tip Leader (all time tracking must be enabled). \nNote that King Tipper cannot be enabled if a King Tipper is not already identified. \nThe command "/king" can be used to define the King Tipper during the show (temporary assignment until bot restart).', u, appNoticeColor); } else if (message[1] == '0') { setKingTipperToggle('0',u,true); } else if (message[1] == '1') { if (!kingTipperName) { if (cb.settings.kingTipperName != null && cb.settings.kingTipperName != ' ') { kingTipperName = cb.settings.kingTipperName; if (cb.settings.kingTipperAmount > 0) { kingTipperAmount = cb.settings.kingTipperAmount; } setKingTipperToggle('1',u,true); } else { cb.sendNotice('The King Tipper cannot be enabled with setting "1" if no King Tipper is configured. The command "/king" can be used to define the King Tipper during the show (temporary assignment until bot restart).', u, appNoticeColor); } } else { setKingTipperToggle('1',u,true); } } else if (message[1] == '2') { if (!allTimeToggle) { cb.sendNotice('The King Tipper cannot be enabled with setting "2" if the All Time Tipper tracking is disabled.', u, appNoticeColor); } else { buildAllTimeArray(); kingTipperName = allTimeArray.name[0]; kingTipperAmount = allTimeArray.totaltips[0]; setKingTipperToggle('2',u,true); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/king': { cmd = 1; if (isModLvlMsg2 || isBC) { kingamount = parseInt(message[1]); if (isNaN(kingamount)) { cb.sendNotice('The first parameter is the King Tipper all time tip amount and is required and must be a number. Use a value of "0" to not display an amount.An example of command format whould be "/king 1000 fonzy" to assign username fonzy as the king tipper with a tip amount of 1000.', u, appNoticeColor); } else if (!message[2]) { cb.sendNotice('The second parameter is the username and is required. An example of command format whould be "/king 1000 fonzy" to assign username fonzy as the king tipper with a tip amount of 1000.', u, appNoticeColor); } else { kingTipperName = message[2].toLowerCase(); kingTipperAmount = kingamount; cb.sendNotice('You have updated the All Time King Tipper as ' + kingTipperName + ' with an amount of ' + kingTipperAmount + ' tokens.', u, appNoticeColor); if (u != cb.room_slug) { cb.sendNotice(u + ' updated the All Time King Tipper as ' + kingTipperName + ' with an amount of ' + kingTipperAmount + ' tokens.', cb.room_slug, appNoticeColor); } if (kingTipperToggle == 2) { cb.sendNotice('Note that the King Tipper feature is currently configured under mode "2" to be pulled from the All Time tipper list. In order to use the value that was entered here, please also change the King Tipper mode to "1" using the command "/useking 1".', cb.room_slug, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/dsptop10': case '/alltimetop10': case '/top10': { cmd = 1; if (allTimeToggle == 1) { buildAllTimeArray(); var alltimesendto = u; if (allTimeArray.name.length > 0) { if (isModLvlMsg1 || isBC) { alltimesendto = ''; } displayAllTimeLeaders(alltimesendto); } else { cb.sendNotice('There are no entries in the all-time tipper list.', u, appNoticeColor); } } else { cb.sendNotice('All Time Tippers are not being tracked. Broadcasters and Moderators can enable this feature using the command "/usealltime on".', u, appNoticeColor); } break; } case '/listalltime': case '/alltimelist': case '/alltime': { cmd = 1; if (isModLvlMsg1 || 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, appNoticeColor); } } else { cb.sendNotice('All Time Tippers are not being tracked. You can enable this feature using the command "/usealltime on".', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } //********* Privates Response Message case '/prv': { cmd = 1; if (isModLvlMsg1 || isBC) { cb.sendNotice(checkNextLine(cb.settings.prvResponseMessage), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } //********* Command Response Messages case '/rsp1': { cmd = 1; if (isModLvlMsg1 || isBC) { cb.sendNotice(checkNextLine(cb.settings.commandResponse1), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/rsp2': { cmd = 1; if (isModLvlMsg1 || isBC) { cb.sendNotice(checkNextLine(cb.settings.commandResponse2), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/rsp3': { cmd = 1; if (isModLvlMsg1 || isBC) { cb.sendNotice(checkNextLine(cb.settings.commandResponse3), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/rsp4': { cmd = 1; if (isModLvlMsg1 || isBC) { cb.sendNotice(checkNextLine(cb.settings.commandResponse4), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/rsp5': { cmd = 1; if (isModLvlMsg1 || isBC) { cb.sendNotice(checkNextLine(cb.settings.commandResponse5), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } break; } case '/dsprsp': { cmd = 1; if (isModLvlMsg1 || isBC) { displaymessage = ''; if (!cb.settings.commandResponse1) { displaymessage += 'Command Response 1 (/rsp1): Message is blank.\n'; } else { displaymessage += 'Command Response 1 (/rsp1): ' + cb.settings.commandResponse1 + '\n'; } if (!cb.settings.commandResponse2) { displaymessage += 'Command Response 2 (/rsp2): Message is blank.\n'; } else { displaymessage += 'Command Response 2 (/rsp2): ' + cb.settings.commandResponse2 + '\n'; } if (!cb.settings.commandResponse3) { displaymessage += 'Command Response 3 (/rsp3): Message is blank.\n'; } else { displaymessage += 'Command Response 3 (/rsp3): ' + cb.settings.commandResponse3 + '\n'; } if (!cb.settings.commandResponse4) { displaymessage += 'Command Response 4 (/rsp4): Message is blank.\n'; } else { displaymessage += 'Command Response 4 (/rsp4): ' + cb.settings.commandResponse4 + '\n'; } if (!cb.settings.commandResponse5) { displaymessage += 'Command Response 5 (/rsp5): Message is blank.\n'; } else { displaymessage += 'Command Response 5 (/rsp5): ' + cb.settings.commandResponse5 + '\n'; } if (!autoResponseWord1) { displaymessage += 'Automated Response Word 1: Word is blank.\n'; } else { displaymessage += 'Automated Response Word 1: ' + autoResponseWord1 + '\n'; displaymessage += 'Automated Response 1: ' + autoResponse1 + '\n'; } if (!autoResponseWord2) { displaymessage += 'Automated Response Word 2: Word is blank.\n'; } else { displaymessage += 'Automated Response Word 2: ' + autoResponseWord2 + '\n'; displaymessage += 'Automated Response 2: ' + autoResponse2 + '\n'; } if (!autoResponseWord3) { displaymessage += 'Automated Response Word 3: Word is blank.\n'; } else { displaymessage += 'Automated Response Word 3: ' + autoResponseWord3 + '\n'; displaymessage += 'Automated Response 3: ' + autoResponse3 + '\n'; } if (!cb.settings.prvResponseMessage) { displaymessage += 'Private Response (/prv): Message is blank.\n'; } else { displaymessage += 'Private Response (/prv): ' + cb.settings.prvResponseMessage + '\n'; } if (!cb.settings.pmResponseMessage) { displaymessage += 'PM Response: Message is blank.\n'; } else { displaymessage += 'PM Response: ' + cb.settings.pmResponseMessage + '\n'; } cb.sendNotice(displaymessage, u, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, u, appNoticeColor); } 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,appNoticeColor); } 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, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBC, u, appNoticeColor); } } 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,appNoticeColor); } else { if (isBC) { stopPrivate(); } else { cb.sendNotice(noticeOnlyBC, u, appNoticeColor); } } break; } //********* Suppress Caps Toggle case '/nocaps': { cmd = 1; if (isModLvlMsg1 || 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, appNoticeColor); } 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, appNoticeColor); } else { setCapsToggle(message[1], u); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', u, appNoticeColor); } break; } //********* Followers case '/followers': { cmd = 1; if (isModLvlMsg2 || isBC) { displayFollowerStats(u); } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/fmt': { cmd = 1; if (isModLvlMsg2 || isBC) { newflag = parseInt(message[1]); if (isNaN(newflag)) { cb.sendNotice('A parameter is required and must be numeric. Valid values are 0=No message, 1=Message to follower only, 2=Message to broadcaster only, 3=Message to both follower and broadcaster, 4=Message to everyone. For example, use "/fmt 1" (without quotes) to disable broadcaster notifications, and only send messages to individual followers.', u, appNoticeColor); } else if (newflag < 0 || newflag > 3) { cb.sendNotice('You did not enter a valid option for the new follower message type. Valid values are "0" for no message, "1" for message to follower only, "2" for message to broadcaster only, "3" for message to both follower and broadcaster, or "4" for message to everyone in the room.', u, appNoticeColor); } else if (followerNotifyFlag == newflag) { cb.sendNotice('The follower message type is already set to "' + followerNotifyFlag + '".', u, appNoticeColor); } else { followerNotifyFlag = newflag; cb.sendNotice('The follower message type has been updated to "' + followerNotifyFlag + '". Setting values are 0=no message, 1=Message to follower only, 2=Message to broadcaster only, 3=Message to both follower and broadcaster, 4=Message to everyone.', u, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/fc': { cmd = 1; displayFollowerTotal(u); break; } //********* Room Stats & User Stats case '/roomstats': { cmd = 1; if (isModLvlMsg2 || isBC) { displayRoomStats(u); } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } case '/userstats': { cmd = 1; if (isModLvlMsg2 || isBC) { displayUserStats(u); } else { cb.sendNotice(noticeOnlyBCMod2, u, appNoticeColor); } break; } //********* Help Menu case '/fbhelp': { cmd = 1; if (isModLvlMsg1 || isBC) { helpModBC(message[1],u); } else { helpCommon(message[1],u); } break; } //********* Dump config settings case '/settings': { cmd = 1; if (isModLvlMsg2 || 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: general, notices, leaders, king, chat, responses, notes, icons, vip, extfans, blocked, tipmenu1, tipmenu2, positions, poll, tickets, toys, media, dice or rules.',u,appNoticeColor); break; } case 'general': { cb.sendNotice( 'Dump of all launch and current settings for General Settings and Personalization:' + '\n0A. bctext : ' + cb.settings.bctext + '\n0B. colorTheme : ' + cb.settings.colorTheme + '\n0C1. colorThemeCustBg1 : ' + cb.settings.colorThemeCustBg1 + '\n0C2. colorThemeCustBg2 : ' + cb.settings.colorThemeCustBg2 + '\n0C3. colorThemeCustBg2 : ' + cb.settings.colorThemeCustBg3 + '\n0C4. colorThemeCustText : ' + cb.settings.colorThemeCustText + '\n0D. colorsGradientDirection : ' + cb.settings.colorsGradientDirection + '\n0E. exemptCommandList : ' + cb.settings.exemptCommandList + '\n0F. modLevel : initial : ' + cb.settings.modLevel + ' : current : ' + modLevel + '\n0G. botModList : ' + cb.settings.botModList + '\n0H. separatoremoji : ' + cb.settings.separatorEmoji ,u); break; } case 'notices': { cb.sendNotice( 'Dump of all settings for Notices:' + '\n1B. enableEntryMessage : ' + cb.settings.enableEntryMessage + '\n1C. entryMessage : ' + cb.settings.entryMessage + '\n1D. minMessagesForNotice : ' + cb.settings.nminMessagesForNotice + '\n1E. enableNotifier : ' + cb.settings.enableNotifier + '\n1F1. notifierMessage1 : ' + cb.settings.notifierMessage1 + '\n1F2. notifierMessage2 : ' + cb.settings.notifierMessage2 + '\n1F3. notifierMessage3 : ' + cb.settings.notifierMessage3 + '\n1F4. notifierMessage4 : ' + cb.settings.notifierMessage4 + '\n1F5. notifierMessage5 : ' + cb.settings.notifierMessage5 + '\n1F6. notifierMessage6 : ' + cb.settings.notifierMessage6 + '\n1F7. notifierMessage7 : ' + cb.settings.notifierMessage7 + '\n1F8. notifierMessage8 : ' + cb.settings.notifierMessage8 + '\n1F9. notifierMessage9 : ' + cb.settings.notifierMessage9 + '\n1G. notifierInterval : ' + cb.settings.notifierInterval + '\n1H. notifiersTextColor : ' + cb.settings.notifiersTextColor + '\n1J. notifiersTextCustColor : ' + cb.settings.notifiersTextCustColor + '\n1K. notifiersBgColor : ' + cb.settings.notifiersBgColor + '\n1L. notifiersBgCustColor : ' + cb.settings.notifiersBgCustColor + '\n1M. enableTipResponse : ' + cb.settings.enableTipResponse + '\n1N1. tipResponseAmount1 : ' + cb.settings.tipResponseAmount1 + '\n1N2. tipResponseMessage1 : ' + cb.settings.tipResponseMessage1 + '\n1N3. tipResponseAmount2 : ' + cb.settings.tipResponseAmount2 + '\n1N4. tipResponseMessage2 : ' + cb.settings.tipResponseMessage2 + '\n1N5. tipResponseAmount3 : ' + cb.settings.tipResponseAmount3 + '\n1N6. tipResponseMessage3 : ' + cb.settings.tipResponseMessage3 + '\n1N7. tipResponseAmount4 : ' + cb.settings.tipResponseAmount4 + '\n1N8. tipResponseMessage4 : ' + cb.settings.tipResponseMessage4 + '\n1N9. tipResponseAmount5 : ' + cb.settings.tipResponseAmount5 + '\n1N10. tipResponseMessage5 : ' + cb.settings.tipResponseMessage5 + '\n1Q. defaultTimerDesc : ' + cb.settings.defaultTimerDesc + '\n1R. defaultTimerDesc2 : ' + cb.settings.defaultTimerDesc2 ,u); break; } case 'leaders': { cb.sendNotice( 'Dump of all current settings for tip leaders and leaderboard:' + '\n2A. enableSubjectChange : ' + cb.settings.enableSubjectChange + '\n2B. enableTipCount : ' + cb.settings.enableTipCount + '\n2C. enableTipLeaderIcons : ' + cb.settings.enableTipLeaderIcons + '\n2D1. tipLeaderGif1 : ' + cb.settings.tipLeaderGif1 + '\n2D2. tipLeaderGif2 : ' + cb.settings.tipLeaderGif2 + '\n2D3. tipLeaderGif3 : ' + cb.settings.tipLeaderGif3 + '\n2G. enableLeaderboard : ' + cb.settings.enableLeaderboard + '\n2H. leaderBoardSize : ' + cb.settings.leaderBoardSize + '\n2J. leaderInterval : ' + cb.settings.leaderInterval + '\n2K. leaderTextColor : ' + cb.settings.leaderTextColor + '\n2L. leaderTextCustColor : ' + cb.settings.leaderTextCustColor + '\n2M. leaderBgColor : ' + cb.settings.leaderBgColor + '\n2N. leaderBgCustColor : ' + cb.settings.leaderBgCustColor + '\n2P. enableAllTime : ' + cb.settings.enableAllTime + '\n2Q. allTimeInterval : ' + cb.settings.allTimeInterval + '\n2R. allTimeTipperList : ' + cb.settings.allTimeTipperList + '\n2S1. allTimeAmount1 : ' + cb.settings.allTimeAmount1 + '\n2S2. allTimeIcon1 : "' + cb.settings.allTimeIcon1 + '"' + '\n2S3. allTimeAmount2 : ' + cb.settings.allTimeAmount2 + '\n2S4. allTimeIcon2 : "' + cb.settings.allTimeIcon2 + '"' + '\n2S5. allTimeAmount3 : ' + cb.settings.allTimeAmount3 + '\n2S6. allTimeIcon3 : "' + cb.settings.allTimeIcon3 + '"' + '\n2S7. allTimeAmount4 : ' + cb.settings.allTimeAmount4 + '\n2S8. allTimeIcon4 : "' + cb.settings.allTimeIcon4 + '"' + '\n2S9. allTimeAmount5 : ' + cb.settings.allTimeAmount5 + '\n2S10. allTimeIcon5 : "' + cb.settings.allTimeIcon5 + '"' + '\n2S11. allTimeAmount6 : ' + cb.settings.allTimeAmount6 + '\n2S12. allTimeIcon6 : "' + cb.settings.allTimeIcon6 + '"' + '\n2S13. allTimeAmount7 : ' + cb.settings.allTimeAmount7 + '\n2S14. allTimeIcon7 : "' + cb.settings.allTimeIcon7 + '"' + '\n2S15. allTimeAmount8 : ' + cb.settings.allTimeAmount8 + '\n2S16. allTimeIcon8 : "' + cb.settings.allTimeIcon8 + '"' ,u); break; } case 'king': { cb.sendNotice( 'Dump of all current settings for King Tipper:' + '\n3A. kingEnable : ' + cb.settings.kingEnable + '\n3B. kingTipperName : ' + cb.settings.kingTipperName + '\n3C. kingTipperAmount : ' + cb.settings.kingTipperAmount + '\n3D. kingTipperIcon : ' + cb.settings.kingTipperIcon + '\n3E. kingTipperNickname : ' + cb.settings.kingTipperNickname + '\n3F. kingTipperTitle : ' + cb.settings.kingTipperTitle + '\n3G. kingTipperWelcome : ' + cb.settings.kingTipperWelcome + '\n3H. kingTipperHighlight : ' + cb.settings.kingTipperHighlight + '\n3J. kingTipperNotice : ' + cb.settings.kingTipperNotice + '\n3K. kingTipperInterval : ' + cb.settings.kingTipperInterval + '\n3L. kingSessionEnable : ' + cb.settings.kingSessionEnable + '\n3M. kingSessionMinAmount : ' + cb.settings.kingSessionMinAmount + '\n3N. kingSessionIcon : ' + cb.settings.kingSessionIcon + '\n3P. kingTipperTextColor : ' + cb.settings.kingTipperTextColor + '\n3Q. kingTipperTextCustColor : ' + cb.settings.kingTipperTextCustColor + '\n3R. kingTipperBgColor : ' + cb.settings.kingTipperBgColor + '\n3S. kingTipperBgCustColor : ' + cb.settings.kingTipperBgCustColor + '\n3R. kingTipperNoticeColor : ' + cb.settings.kingTipperBgColor + '\n3S. kingTipperNoticeCustColor: ' + cb.settings.kingTipperNoticeCustColor ,u); break; } case 'chat': { cb.sendNotice( 'Dump of all current settings for chat controls:' + '\n4B. silenceList : ' + cb.settings.silenceList + '\n4C. showSilencedMsgs : ' + cb.settings.showSilencedMsgs + '\n4E. ninjaList : ' + cb.settings.ninjaList + '\n4F. showNinjadMsgs : ' + cb.settings.showNinjadMsgs + '\n4G. niceList : ' + cb.settings.niceList + '\n4H. enablePMs : ' + cb.settings.enablePMs + '\n4J. requireAnswerLevel : ' + cb.settings.requireAnswerLevel + '\n4K. lockGrayChat : ' + cb.settings.lockGrayChat + '\n4L. grayChatTime : ' + cb.settings.grayChatTime + '\n4N. initialSilenceLevel : ' + cb.settings.initialSilenceLevel + '\n4P. initialGraphicsLevel : ' + cb.settings.initialGraphicsLevel + '\n4Q. minTipToChat : ' + cb.settings.minTipToChat + '\n4R. restrictEnglishChar : ' + cb.settings.restrictEnglishChar + '\n4S. autoUpdateSLGL : ' + cb.settings.autoUpdateSLGL + '\n4T. silenceGraysThreshold : ' + cb.settings.minTipToChat + '\n4U. silenceNonTipThreshold : ' + cb.settings.minTipToChat ,u); break; } case 'responses': { cb.sendNotice( 'Dump of all current settings for Automated Responses:' + '\n5A. enablePMResponse : ' + cb.settings.enablePMResponse + '\n5B. pmResponseMessage : ' + cb.settings.pmResponseMessage + '\n5C. enablePrvResponse : ' + cb.settings.enablePrvResponse + '\n5D. prvResponseMessage : ' + cb.settings.prvResponseMessage + '\n5E1. commandResponse1 : ' + cb.settings.commandResponse1 + '\n5E2. commandResponse2 : ' + cb.settings.commandResponse2 + '\n5E3. commandResponse3 : ' + cb.settings.commandResponse3 + '\n5E4. commandResponse4 : ' + cb.settings.commandResponse4 + '\n5E5. commandResponse5 : ' + cb.settings.commandResponse5 + '\n5H. enableAutoResponse : ' + cb.settings.enableAutoResponse + '\n5J1. autoResponseWord1 : ' + cb.settings.autoResponseWord1 + '\n5J2. autoResponse1 : ' + cb.settings.autoResponse1 + '\n5J3. autoResponseWord2 : ' + cb.settings.autoResponseWord2 + '\n5J4. autoResponse2 : ' + cb.settings.autoResponse2 + '\n5J5. autoResponseWord3 : ' + cb.settings.autoResponseWord3 + '\n5J6. autoResponse3 : ' + cb.settings.autoResponse3 + '\n5Q. tipNoteForwardID : ' + cb.settings.tipNoteForwardID ,u); break; } case 'notes': { cb.sendNotice( 'Dump of all current settings for Viewer Notes:' + '\n6A. viewerNotesList : ** Viewer Notes Intentionally Hidden **' + '\n6B. viewerNotesWhen : ' + cb.settings.viewerNotesWhen + '\n6C. viewerNotesWho : ' + cb.settings.viewerNotesWho ,u); break; } case 'icons': { cb.sendNotice( 'Dump of all current settings for User Group Icons:' + '\n7A. enableGroupIcons : ' + cb.settings.enableGroupIcons + '\n7B. iconMods : ' + cb.settings.iconMods + '\n7D. iconBotMods : "' + cb.settings.iconBotMods + '"' + '\n7E. moderatorHighlight : ' + cb.settings.moderatorHighlight + '\n7F. iconFans : "' + cb.settings.iconFans + '"' + '\n7G. fanclubHighlight : ' + cb.settings.fanclubHighlight + '\n7H. iconNicknameList : ' + cb.settings.iconNicknameList + '\n7J. tipForIconType : ' + cb.settings.tipForIconType + '\n7K1. iconTipAmount1 : ' + cb.settings.iconTipAmount1 + '\n7K2. iconTipIcon1 : "' + cb.settings.iconTipIcon1 + '"' + '\n7K3. iconTipAmount2 : ' + cb.settings.iconTipAmount2 + '\n7K4. iconTipIcon2 : "' + cb.settings.iconTipIcon2 + '"' + '\n7K5. iconTipAmount3 : ' + cb.settings.iconTipAmount3 + '\n7K6. iconTipIcon3 : "' + cb.settings.iconTipIcon3 + '"' + '\n7K7. iconTipAmount4 : ' + cb.settings.iconTipAmount4 + '\n7K8. iconTipIcon4 : "' + cb.settings.iconTipIcon4 + '"' + '\n7K9. iconTipAmount5 : ' + cb.settings.iconTipAmount5 + '\n7K10. iconTipIcon5 : "' + cb.settings.iconTipIcon5 + '"' + '\n7L. iconTipNoticeInt : ' + cb.settings.iconTipNoticeInt + '\n7M. iconTheme : ' + cb.settings.iconTheme + '\n7N1. iconThemeDarkBlue : "' + cb.settings.iconThemeDarkBlue + '"' + '\n7N2. iconThemeLightPurple : "' + cb.settings.iconThemeLightPurple + '"' + '\n7N3. iconThemeDarkPurple : "' + cb.settings.iconThemeDarkPurple + '"' + '\n7P. bcCustomTextColor : ' + cb.settings.bcCustomTextColor + '\n7Q. bcCustomBgColor : ' + cb.settings.bcCustomBgColor + '\n7R. tmCustomTextColor : ' + cb.settings.tmCustomTextColor + '\n7S. tmCustomBgColor : ' + cb.settings.tmCustomBgColor + '\n7T. tbmCustomTextColor : ' + cb.settings.tbmCustomTextColor + '\n7U. tbmCustomBgColor : ' + cb.settings.tbmCustomBgColor + '\n7V. pmCustomTextColor : ' + cb.settings.pmCustomTextColor + '\n7W. pmCustomBgColor : ' + cb.settings.pmCustomBgColor ,u); break; } case 'vip': { cb.sendNotice( 'Dump of all current settings for VIP list:' + '\nVIPList : ' + cb.settings.VIPList + '\nVIPname : ' + cb.settings.VIPname + '\nannounceVIP : ' + cb.settings.announceVIP + '\nannounceVIPtext : ' + cb.settings.announceVIPtext + '\njoinVIPSingleTip : ' + cb.settings.joinVIPSingleTip + '\njoinVIPCumulativeShow : ' + cb.settings.joinVIPCumulativeShow + '\njoinVIPCumulativeAllTime : ' + cb.settings.joinVIPCumulativeAllTime + '\niconVIP : "' + cb.settings.iconVIP + '"' + '\nVIPHighlight : ' + cb.settings.VIPHighlight + '\nVIPBgCustColor : ' + cb.settings.VIPBgCustColor ,u); break; } case 'extfans': { cb.sendNotice( 'Dump of all current settings for External Fan Clubs 1 and 2:' + '\n******************* Fan Club 1 **************************' + '\nextFanList : ' + cb.settings.extFanList + '\nEFCname : ' + cb.settings.EFCname + '\nannounceExtFans : ' + cb.settings.announceExtFans + '\nannounceExtFanstext : ' + cb.settings.announceExtFanstext + '\niconExtFans : "' + cb.settings.iconExtFans + '"' + '\nefcHighlight : ' + cb.settings.efcHighlight + '\nefcBgCustColor : ' + cb.settings.efcBgCustColor + '\n******************* Fan Club 2 **************************' + '\nextFanList2 : ' + cb.settings.extFanList2 + '\nEFCname2 : ' + cb.settings.EFCname2 + '\nannounceExtFans2 : ' + cb.settings.announceExtFans2 + '\nannounceExtFanstext2 : ' + cb.settings.announceExtFanstext2 + '\niconExtFans2 : "' + cb.settings.iconExtFans2 + '"' + '\nefcHighlight2 : ' + cb.settings.efcHighlight2 + '\nefcBgCustColor2 : ' + cb.settings.efcBgCustColor2 ,u); break; } case 'blocked': { cb.sendNotice( 'Dump of all current settings for chat controls:' + '\nenableWordList : ' + cb.settings.enableWordList + '\nwordBlockList : ** Private Blocked Word List intentionally hidden **' + '\nshowBlockedMsgs : ' + cb.settings.showBlockedMsgs + '\nblockedLevelPriv : ' + cb.settings.blockedLevelPriv + '\nwordBlockListPub : ' + cb.settings.wordBlockListPub + '\nshowBlockedMsgsPub : ' + cb.settings.showBlockedMsgsPub + '\nblockedLevelPub : ' + cb.settings.blockedLevelPub ,u); break; } case 'tipmenu1': { cb.sendNotice( 'Dump of all current settings for the Tip Menu:' + '\ntipMenuNoticeType : ' + cb.settings.tipMenuNoticeType + '\nmenuDspInt : ' + cb.settings.menuDspInt + '\nalertBCWhenReq : ' + cb.settings.alertBCWhenReq + '\nlistSort : ' + cb.settings.listSort + '\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 + '\nenableTipMenu : ' + cb.settings.enableTipMenu + '\ntipMenuSalePct : ' + cb.settings.tipMenuSalePct + '\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:' + '\nenableTipMenu2 : ' + cb.settings.enableTipMenu2 + '\ntipMenu2SalePct : ' + cb.settings.tipMenu2SalePct + '\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 + '\nmenu2item21 : ' + cb.settings.menu2item21 + '\nmenu2itemprice21 : ' + cb.settings.menu2itemprice21 + '\nmenu2item22 : ' + cb.settings.menu2item22 + '\nmenu2itemprice22 : ' + cb.settings.menu2itemprice22 + '\nmenu2item23 : ' + cb.settings.menu2item23 + '\nmenu2itemprice23 : ' + cb.settings.menu2itemprice23 + '\nmenu2item24 : ' + cb.settings.menu2item24 + '\nmenu2itemprice24 : ' + cb.settings.menu2itemprice24 + '\nmenu2item25 : ' + cb.settings.menu2item25 + '\nmenu2itemprice25 : ' + cb.settings.menu2itemprice25 ,u); break; } case 'positions': { cb.sendNotice( 'Dump of all current settings for 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:' + '\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 + '\nstealPollAmount : ' + cb.settings.stealPollAmount + '\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 + '\npollSepBot : ' + cb.settings.pollSepBot ,u); break; } case 'tickets': { cb.sendNotice( 'Dump of all current settings for tickets:' + '\nticketShowType : ' + cb.settings.ticketShowType + '\nprepticketTipMenuOff : ' + cb.settings.prepticketTipMenuOff + '\nprepticketPosMenuOn : ' + cb.settings.prepticketPosMenuOn + '\nprepticketStartPoll : ' + cb.settings.prepticketStartPoll + '\nstartPollTimerWithShow : ' + cb.settings.startPollTimerWithShow + '\nstartPollMinAfterShow : ' + cb.settings.startPollMinAfterShow + '\nendPosMenuWithShow : ' + cb.settings.endPosMenuWithShow + '\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 + '\nhiddenShowPriceEFC2 : ' + cb.settings.hiddenShowPriceEFC2 + '\nhiddenShowPriceVIP : ' + cb.settings.hiddenShowPriceVIP + '\nhiddenShowFreeFC : ' + cb.settings.hiddenShowFreeFC + '\nhiddenShowFreeMods : ' + cb.settings.hiddenShowFreeMods + '\nhiddenShowFreeEFC : ' + cb.settings.hiddenShowFreeEFC + '\nhiddenShowFreeEFC2 : ' + cb.settings.hiddenShowFreeEFC2 + '\nhiddenShowFreeVIP : ' + cb.settings.hiddenShowFreeVIP + '\nhiddenShowCumulative : ' + cb.settings.hiddenShowCumulative + '\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 'rules': { cb.sendNotice( 'Dump of all current settings for the dice game:' + '\nenableRoomRules : ' + cb.settings.enableRoomRules + '\nroomRule1 : ' + cb.settings.roomRule1 + '\nroomRule2 : ' + cb.settings.roomRule2 + '\nroomRule3 : ' + cb.settings.roomRule3 + '\nroomRule4 : ' + cb.settings.roomRule4 + '\nroomRule5 : ' + cb.settings.roomRule5 + '\nroomRule6 : ' + cb.settings.roomRule6 + '\nroomRule7 : ' + cb.settings.roomRule7 + '\nroomRule8 : ' + cb.settings.roomRule8 + '\nroomRulesInterval : ' + cb.settings.roomRulesInterval + '\nroomRulesTextColor : ' + cb.settings.roomRulesTextColor + '\nroomRulesTextCustColor : ' + cb.settings.roomRulesTextCustColor + '\nroomRulesBgColor : ' + cb.settings.roomRulesBgColor + '\nroomRulesBgCustColor : ' + cb.settings.roomRulesBgCustColor ,u); break; } case 'followers': { cb.sendNotice( 'Dump of all current settings for Followers section:' + '\nfollowerNotify : ' + cb.settings.followerNotify + '\nfollowerNotifyColor : ' + cb.settings.followerNotifyColor + '\nfollowerMessage : ' + cb.settings.followerMessage + '\nfollowerStatsEnable : ' + cb.settings.followerStatsEnable + '\nfollowerReminderEnable : ' + cb.settings.followerReminderEnable + '\nfollowReminder : ' + cb.settings.followReminder + '\nfollowNoticeInterval : ' + cb.settings.followNoticeInterval + '\nfollowTextColor : ' + cb.settings.followTextColor + '\nfollowCustomTextColor : ' + cb.settings.followCustomTextColor + '\nfollowBgColor : ' + cb.settings.followBgColor + '\nfollowCustomBgColor : ' + cb.settings.followCustomBgColor + '\nfollowNoticeTextColor : ' + cb.settings.followNoticeTextColor + '\nfollowNoticeCustomTextColor : ' + cb.settings.followNoticeCustomTextColor + '\nfollowNoticeBgColor : ' + cb.settings.followNoticeBgColor + '\nfollowNoticeCustomBgColor : ' + cb.settings.followNoticeCustomBgColor ,u); break; } case 'textpoll': { cb.sendNotice( 'Dump of all current settings for Text Poll section:' + '\n21A. textPollEnable : ' + cb.settings.textPollEnable + '\n21B. textPollTitle : ' + cb.settings.textPollTitle + '\n21C. textPollMode : ' + cb.settings.textPollMode + '\n21D. textPollCount : ' + cb.settings.textPollCount + '\n21E. textPollFanClubDouble : ' + cb.settings.textPollFanClubDouble + '\n21F. textPollInterval : ' + cb.settings.textPollInterval + '\n21G1. textPollOpt1 : ' + cb.settings.textPollOpt1 + '\n21G2. textPollOpt2 : ' + cb.settings.textPollOpt2 + '\n21G3. textPollOpt3 : ' + cb.settings.textPollOpt3 + '\n21G4. textPollOpt4 : ' + cb.settings.textPollOpt4 + '\n21G5. textPollOpt5 : ' + cb.settings.textPollOpt5 + '\n21H. textPollTextColor : ' + cb.settings.textPollTextColor + '\n21J. textPollCustTextColor : ' + cb.settings.textPollCustTextColor + '\n21K. textPollBgColor : ' + cb.settings.textPollBgColor + '\n21L. textPollCustBgColor : ' + cb.settings.textPollCustBgColor + '\n21M. textPollSepBot : ' + cb.settings.textPollSepBot ,u); break; } default: { cb.sendNotice('Invalid setting group, please use one of the following: notices, leaders, king, chat, responses, notes, icons, vip, extfans, blocked, tipmenu1, tipmenu2, positions, poll, tickets, toys, media, dice or rules.',u,appNoticeColor); break; } } } else { cb.sendNotice(noticeOnlyBCMod2,u,appNoticeColor); } } } //********* End of Expected commands if ( message[0] == '/paneltext1' || message[0] == '/paneltext2' || message[0] == '/paneltext3' || 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] == '/chrmv' || message[0] == '/chsave' || message[0] == '/chprice' || message[0] == '/chplay' || message[0] == '/chh' || message[0] == '/chq' || message[0] == '/chlist' || message[0] == '/chi' || message[0] == '/charades' || message[0] == '/tq' || message[0] == '/tqi' || message[0] == '/tqh' || message[0] == '/tqa' || message[0] == '/tword' || message[0] == '/tprize' || message[0] == '/twenty' || message[0] == '/twentyprice' || message[0] == '/twentywin' || message[0] == '/twentyend' || message[0] == '/twentymode' || message[0] == '/twentyquestions' || message[0] == '/randomfree' || message[0] == '/random' || message[0] == '/ri' || message[0] == '/rw' || message[0] == '/badfree' || message[0] == '/badlibs' || message[0] == '/bli' || message[0] == '/blc' || message[0] == '/badprice' || message[0] == '/blw' || 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] == '/pq' || message[0] == '/pressq' || message[0] == '/pressqueue' || 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] == '/kpa' || message[0] == '/kpw' || message[0] == '/kpwa' || 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] == '/resetapp' || message[0] == '/chgpanelbg' || message[0] == '/paneltextcolor' || 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] == '/listremgoals' || message[0] == '/lrg' || 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] == '/spankall' || 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] == '/peepstarttimer' || 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' || message[0] == '/startpresale' || message[0] == '/stoppresale' || message[0] == '/startmenu' || message[0] == '/stopmenu' || message[0] == '/startmenu2' || message[0] == '/stopmenu2' || message[0] == '/menu' || message[0] == '/menurequests' || message[0] == '/menuadd' || message[0] == '/menurmv' || message[0] == '/startposmenu' || message[0] == '/stopposmenu' || message[0] == '/setautogoal' || message[0] == '/setautofinal' || message[0] == '/setautotext' || message[0] == '/uahelp' || message[0] == '/tickethelp' || message[0] == '/menuhelp' || message[0] == '/setgentext' || message[0] == '/gentextposn' || message[0] == '/pause' || message[0] == '/resume' || message[0] == '/ninjatip' || message[0] == '/ninjatipon' || message[0] == '/ninjatipoff' || message[0] == '/raffle' || message[0] == '/entries' || message[0] == '/previousentries' || message[0] == '/resetraffle' || message[0] == '/addraffletkt1' || message[0] == '/addraffletkt2' || message[0] == '/addraffletkt3' || message[0] == '/addraffletkt4' || message[0] == '/addraffletkt5' || message[0] == '/rmvraffletkt' || message[0] == '/raffleprizes' || message[0] == '/setraffleprice' || message[0] == '/raffledrawing' || message[0] == '/rafflestarttimer' || message[0] == '/raffleaddtime' || message[0] == '/rafflestoptimer' || message[0] == '/raffletimeleft' || message[0] == '/chgrafflemode' || message[0] == '/addraffleprize' || message[0] == '/rmvraffleprize' || message[0] == '/startpoll' || message[0] == '/newpass' || message[0] == '/mypass' || message[0] == '/seepass' || message[0] == '/pwsettings' || message[0] == '/passlist' || message[0] == '/passnow' || message[0] == '/passhelp' || message[0] == '/passto' || message[0] == '/bjfree' || message[0] == '/bjgame' || message[0] == '/blackjack' || message[0] == '/bji' || message[0] == '/hit' || message[0] == '/stay' || message[0] == '/bjg' || message[0] == '/goal' || message[0].substring(0,11) == '/setspank1p' || message[0].substring(0,11) == '/setspank2p' || message[0].substring(0,11) == '/setspank3p' || message[0].substring(0,11) == '/setspank4p' || message[0].substring(0,11) == '/setspank5p' || message[0].substring(0,13) == '/setspanktype' || message[0] == '/previewers') { cmd = 1; } if (cbjs.arrayContains(exemptCmdList,message[0].toLowerCase())) { 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, appNoticeColor); } } var silencedmsg = 0; // ********** Suppress messages containing Private blocked word if (silencedmsg == 0 && cb.settings.enableWordList == 'Yes' && wordListArray.length > 0) { if (cb.settings.blockedLevelPriv == 'All Users' && !isBC) { checkblocklist = true; } else if (cb.settings.blockedLevelPriv == 'All Users Except Mods' && !isModLvlMsg1 && !isBC) { checkblocklist = true; } else if (cb.settings.blockedLevelPriv == 'All Users Except Mods/Fans/VIPs' && !isModLvlMsg1 && !isBC && !isFanMsg && !isVIPMsg && !isExtFanMsg && !isExtFanMsg2) { checkblocklist = true; } else if (cb.settings.blockedLevelPriv == 'Only Light Blue and Gray Users' && !isModLvlMsg1 && !isBC && !isFanMsg && !isVIPMsg && !isExtFanMsg && !isExtFanMsg2 && !isDarkBlue && !isDarkPurple && !isLightPurple) { checkblocklist = true; } else if (cb.settings.blockedLevelPriv == 'Gray Users Only' && isGray) { checkblocklist = true; } else { checkblocklist = false; } if (checkblocklist) { chkblockmsg = msg['m'].toLowerCase(); MessageArray = chkblockmsg.split(' '); for (var blockindex = 0; blockindex < MessageArray.length; blockindex++) { if (cbjs.arrayContains(wordListArray, MessageArray[blockindex])) { silencedmsg = 1; if (cb.settings.showBlockedMsgs == 'Display to Broadcaster only') { cb.sendNotice('Fembot: Blocked Private Word List message from user ' + u + ' : ' + msg['m'],BC,red); } } } } } // ********** Suppress messages containing Public blocked words if (silencedmsg == 0 && cb.settings.enableWordList == 'Yes' && wordListArrayPub.length > 0) { if (cb.settings.blockedLevelPub == 'All Users' && !isBC) { checkpubblocklist = true; } else if (cb.settings.blockedLevelPub == 'All Users Except Mods' && !isModLvlMsg1 && !isBC) { checkpubblocklist = true; } else if (cb.settings.blockedLevelPub == 'All Users Except Mods/Fans/VIPs' && !isModLvlMsg1 && !isBC && !isFanMsg && !isVIPMsg && !isExtFanMsg && !isExtFanMsg2) { checkpubblocklist = true; } else if (cb.settings.blockedLevelPub == 'Only Light Blue and Gray Users' && !isModLvlMsg1 && !isBC && !isFanMsg && !isVIPMsg && !isExtFanMsg && !isExtFanMsg2 && !isDarkBlue && !isDarkPurple && !isLightPurple) { checkpubblocklist = true; } else if (cb.settings.blockedLevelPub == 'Gray Users Only' && isGray) { checkpubblocklist = true; } else { checkpubblocklist = false; } if (checkpubblocklist) { chkpubblockmsg = msg['m'].toLowerCase(); pubMessageArray = chkpubblockmsg.split(' '); for (var pblockindex = 0; pblockindex < pubMessageArray.length; pblockindex++) { if (cbjs.arrayContains(wordListArrayPub, pubMessageArray[pblockindex])) { silencedmsg = 1; cb.sendNotice('Fembot: Your message was not displayed because it contains words in the blocked word list. Please refrain from rude or demanding language.', u, appNoticeColor); if (cb.settings.showBlockedMsgsPub == 'Display to Broadcaster only') { cb.sendNotice('Fembot: Blocked word list message from user ' + u + ' : ' + msg['m'],BC,appNoticeColor); } else if (cb.settings.showBlockedMsgsPub == 'Display to Broadcaster and Moderators') { cb.sendNotice('Fembot: Blocked word list message from user ' + u + ' : ' + msg['m'],BC,appNoticeColor); cb.sendNotice('Fembot: Blocked word list message from user ' + u + ' : ' + msg['m'],BC,appNoticeColor,'','','red'); } } } } } //********* Suppress for Silence Level if (silencedmsg == 0 && silenceLevel > 0 && !isModLvlMsg1 && !isBC && !isNice && !isFanMsg && !isVIPMsg && !isExtFanMsg && !isExtFanMsg2) { 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,appNoticeColor); } 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,appNoticeColor); } 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,appNoticeColor); } } 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,appNoticeColor); } 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,appNoticeColor); break; } } //********* Suppress for Gray Chat Time-Lock if (silencedmsg == 0 && grayLockToggle == 1 && !isModLvlMsg1 && !isBC && !isNice && !isFanMsg && !isVIPMsg && !isExtFanMsg && !isExtFanMsg2 && isGray) { if (!grayLockCheck(u,isBC,isModLvlMsg1,isFanMsg,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,appNoticeColor); } } //********* Suppress for Answer locked users if (silencedmsg == 0 && requireAnswerToggle == 1) { if (!isBC && !isModLvlMsg1 && !isFanMsg && !isExtFanMsg && !isExtFanMsg2 && !isVIPMsg) { if (cbjs.arrayContains(answerLockList,u)) { if (answerLockStatus[answerLockList.indexOf(u)] === false) { silencedmsg = 1; } } } } //********* Suppress for Ninja'd or Silenced if (silencedmsg == 0 && cbjs.arrayContains(ninjaListArray,u) && !isModLvlMsg1 && !isBC) { silencedmsg = 1; if (showNinjadMsgs == 'Broadcaster only') { cb.sendNotice('Fembot - Chat message from ninja silenced user ' + u + ' : ' + msg['m'],BC,appNoticeColor); } else if (showNinjadMsgs == 'Mods only') { cb.sendNotice('Fembot - Chat message from ninja silenced user ' + u + ' : ' + msg['m'],BC,appNoticeColor,'','','red'); } else if (showNinjadMsgs == 'Broadcaster and Mods') { cb.sendNotice('Fembot - Chat message from ninja silenced user ' + u + ' : ' + msg['m'],BC,appNoticeColor); cb.sendNotice('Fembot - Chat message from ninja silenced user ' + u + ' : ' + msg['m'],BC,appNoticeColor,'','','red'); } } if (silencedmsg == 0 && cbjs.arrayContains(silenceListArray,u) && !isModLvlMsg1 && !isBC) { silencedmsg = 1; cb.sendNotice('Your message was not sent because you have been silenced.',u,appNoticeColor); if (showSilencedMsgs == 'Broadcaster only') { cb.sendNotice('Fembot - Chat message from silenced user ' + u + ' : ' + msg['m'],BC,appNoticeColor); } else if (showSilencedMsgs == 'Mods only') { cb.sendNotice('Fembot - Chat message from silenced user ' + u + ' : ' + msg['m'],BC,appNoticeColor,'','','red'); } else if (showSilencedMsgs == 'Broadcaster and Mods') { cb.sendNotice('Fembot - Chat message from silenced user ' + u + ' : ' + msg['m'],BC,appNoticeColor); cb.sendNotice('Fembot - Chat message from silenced user ' + u + ' : ' + msg['m'],BC,appNoticeColor,'','','red'); } } //********* Graphic Level if (silencedmsg == 0 && graphicLevel > 0 && !isModLvlMsg1 && !isBC && !isNice && !isFanMsg && !isVIPMsg && !isExtFanMsg && !isExtFanMsg2) { switch(graphicLevel) { case 1: if (!msg['has_tokens']) { for (var i = 0; i < message.length; i++) { if (message[i].charAt(0) == ':' && message[i].length > 3) { 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,appNoticeColor); } } } break; case 2: if(!cbjs.arrayContains(tipCountArray.name,u)) { for (var i = 0; i < message.length; i++) { if (message[i].charAt(0) == ':' && message[i].length > 3) { 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,appNoticeColor); } } } 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].length > 3) { 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,appNoticeColor); } } } } else { for (var i = 0; i < message.length; i++) { if (message[i].charAt(0) == ':' && message[i].length > 3) { 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,appNoticeColor); } } } break; case 4: for (var i = 0; i < message.length; i++) { if (message[i].charAt(0) == ':' && message[i].length > 3) { silencedmsg = 1; cb.sendNotice('Your message was not displayed because the graphic level has been set to only allow mods, fans, and VIPS to use graphics.',u,appNoticeColor); } } break; } } // ********** Suppress non-English/ASCII characters if (silencedmsg == 0 && cb.settings.restrictEnglishChar == 'Yes' && (isGray || isLightBlue)) { var checkASCII = /[\u0000-\u007F]+/; if (!checkASCII.test(msg['m'])) { cb.sendNotice('Your Message was not sent. The broadcaster has disabled non-English keyboard character entry.', u, appWarningColor); silencedmsg = 1; } } // ********** Auto-responses for configured words if (silencedmsg == 0 && (enableAutoResponse == 'Respond to All Users' || (enableAutoResponse == 'Respond to Users with Tokens' && !isGray))) { tempautomessage = msg['m'].toLowerCase(); if (autoResponse1) { if (tempautomessage.includes(autoResponseWord1.toLowerCase())) { cb.setTimeout(sendAutoResponse1Delay, 500); } } if (autoResponse2) { if (tempautomessage.includes(autoResponseWord2.toLowerCase())) { cb.setTimeout(sendAutoResponse2Delay, 500); } } if (autoResponse3) { if (tempautomessage.includes(autoResponseWord3.toLowerCase())) { cb.setTimeout(sendAutoResponse3Delay, 500); } } } // ********** PM and Private Request Auto Response, Convert to lower case if (silencedmsg == 0 && !isModLvlMsg1 && !isBC && !isFanMsg && !isVIPMsg && !isExtFanMsg && !isExtFanMsg2) { tempmessage = msg['m'].toLowerCase(); if (sendPMResponse) { if (tempmessage.includes('pm') && !tempmessage.includes('tipmenu')) { cb.setTimeout(sendPMResponseDelay, 500); } } if (sendPvtResponse && !isGray) { if (tempmessage.includes('private') || tempmessage.includes('pvt')) { cb.setTimeout(sendPrivateResponseDelay, 500); } } if (suppressCapsToggle) { capscount = 0; currentmessage = msg['m']; capsMessageArray = currentmessage.split(' '); for (var chkindex = 0; chkindex < capsMessageArray.length; chkindex++) { if (caps.test(capsMessageArray[chkindex])) { capscount++; } } if (capscount > 1) { msg['m'] = m.toLowerCase(); cb.sendNotice('Message converted to lower case, please do not type in all CAPS!', u, appNoticeColor); } } } // ********** Add nickname if needed if (!suppressPrefix && silencedmsg == 0) { if (cbjs.arrayContains(iconNicknamesArray.name,u) || u == kingTipperName) { if (message[0].charAt(0) != '/' && message[0].charAt(0) != '!') { pfxnickname = null; if (cbjs.arrayContains(iconNicknamesArray.name,u)) { nicknameindex = iconNicknamesArray.name.indexOf(u); if (iconNicknamesArray.nickname[nicknameindex] != '' && iconNicknamesArray.nickname[nicknameindex] != null) { pfxnickname = '[' + iconNicknamesArray.nickname[nicknameindex] + '] '; } } if (u == kingTipperName) { if (cb.settings.kingTipperNickname) { pfxnickname = '[' + cb.settings.kingTipperNickname + '] '; } } msg.m = (pfxnickname != null ? pfxnickname + ' ' : '') + msg.m; } } } // ********** Add tip count prefix if needed if (!suppressPrefix && silencedmsg == 0) { if (cbjs.arrayContains(tipCountArray.name,u)) { if (message[0].charAt(0) != '/' && message[0].charAt(0) != '!') { tipcount = 0; pfxcount = null; if (tipCountToggle == 1 && cbjs.arrayContains(tipCountArray.name,u)) { tipcount = parseInt(tipCountArray.amount[findTipper(u)]); if (tipcount > 0) { pfxcount = '\u2507' + tipCountArray.amount[findTipper(u)] + '\u2507 '; } } if (pfxcount != null) { msg.m = pfxcount + ' ' + msg.m; } } } } // ********** Add tip based icon if needed if (!suppressPrefix && silencedmsg == 0) { if (cbjs.arrayContains(tipCountArray.name,u) || u == kingTipperName || cbjs.arrayContains(allTimeArray.name,u)) { if (message[0].charAt(0) != '/' && message[0].charAt(0) != '!') { pfxtipleader = null; 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) { switch (lbposn) { case 1: pfxtipleader = cb.settings.tipLeaderGif1; break; case 2: pfxtipleader = cb.settings.tipLeaderGif2; break; case 3: pfxtipleader = cb.settings.tipLeaderGif3; break; } } } if (cbjs.arrayContains(allTimeArray.name,u) && alltimeIconArray.amount.length > 0) { useralltimelevel = 0; amtindex = allTimeArray.name.indexOf(u); useralltimetips = allTimeArray.totaltips[amtindex]; for (var levelindex = 0; levelindex < alltimeIconArray.amount.length; levelindex++) { if (useralltimetips < alltimeIconArray.amount[levelindex]) { break; } else { useralltimelevel++; } } if (useralltimelevel > 0) { pfxtipleader = alltimeIconArray.icon[useralltimelevel - 1]; } } if (u == kingTipperName) { if (cb.settings.kingTipperIcon) { pfxtipleader = cb.settings.kingTipperIcon; } } else if (u == currentKingTipper) { if (cb.settings.kingSessionIcon) { pfxtipleader = cb.settings.kingSessionIcon; } } if (pfxtipleader != null) { msg.m = pfxtipleader + ' ' + msg.m; } } } } // ********** Add group icon prefix if needed if (!suppressPrefix && silencedmsg == 0) { if (isModLvlMsg1 || isFanMsg || isVIPMsg || isExtFanMsg || isExtFanMsg2 || cbjs.arrayContains(iconNicknamesArray.name,u) || cbjs.arrayContains(tipForIconArray.name,u) || (themeIconsToggle == 1 && (isDarkBlue || isLightPurple || isDarkPurple)) ) { if (message[0].charAt(0) != '/' && message[0].charAt(0) != '!') { pfxgrpicon = null; if (groupIconsToggle == 1 || themeIconsToggle == 1) { if (isBotMod && iconBotMods) { pfxgrpicon = iconBotMods; } else if (isCBMod && iconMods) { pfxgrpicon = iconMods; } else if (isFanMsg && iconFans) { pfxgrpicon = iconFans; } else if (cbjs.arrayContains(extFanListArray,u) && iconExtFans) { pfxgrpicon = iconExtFans; } else if (cbjs.arrayContains(extFanList2Array,u) && iconExtFans2) { pfxgrpicon = iconExtFans2; } else if (cbjs.arrayContains(VIPListArray,u) && iconVIP) { pfxgrpicon = iconVIP; } else if (isDarkPurple && iconDarkPurple) { pfxgrpicon = iconDarkPurple; } else if (isLightPurple && iconLightPurple) { pfxgrpicon = iconLightPurple; pfxgrpicon = iconLightPurple; } else if (isDarkBlue && iconDarkBlue) { pfxgrpicon = iconDarkBlue; } } if (cbjs.arrayContains(iconNicknamesArray.name,u)) { iconindex = iconNicknamesArray.name.indexOf(u); if (iconNicknamesArray.icon[iconindex] != '' && iconNicknamesArray.icon[iconindex] != null) { pfxgrpicon = iconNicknamesArray.icon[iconindex]; } } else if (cbjs.arrayContains(tipForIconArray.name,u)) { iconindex = tipForIconArray.name.indexOf(u); if (tipForIconArray.icon[iconindex] != '' && tipForIconArray.icon[iconindex] != null) { pfxgrpicon = tipForIconArray.icon[iconindex]; } } if (pfxgrpicon != null) { msg.m = pfxgrpicon + ' ' + msg.m; } } } } // Highlight background for Ticket show users, mods, and King Tipper if (cb.settings.kingTipperHighlight == 'Yes' && u == kingTipperName) { msg['background'] = kingTipperBgColor; } else if (cb.settings.moderatorHighlight == 'Yes' && isModLvlMsg1) { msg['background'] = moderatorBgColor; } else if (cb.settings.fanclubHighlight == 'Yes' && isFanMsg) { msg['background'] = fanclubBgColor; } else if (cb.settings.efcHighlight == 'Yes' && isExtFanMsg) { msg['background'] = extfanclubBgColor; } else if (cb.settings.efcHighlight2 == 'Yes' && isExtFanMsg2) { msg['background'] = extfanclubBgColor2; } else if (cb.settings.VIPHighlight == 'Yes' && isVIPMsg) { msg['background'] = vipBgColor; } else 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],false); 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 userEnter = user.user; var isModEnter = user.is_mod; var isBCEnter = (userEnter === cb.room_slug); var isFanEnter = user.in_fanclub; var isGray = false; var isDarkBlue = false; var isLightBlue = false; var isLightPurple = false; var isDarkPurple = false; var isExtFanEnter = cbjs.arrayContains(extFanListArray,userEnter); var isExtFanEnter2 = cbjs.arrayContains(extFanList2Array,userEnter); var isVIPEnter = cbjs.arrayContains(VIPListArray,userEnter); 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; } isBotModEnter = false; if (isModEnter) { populateModeratorArray(userEnter,'cbmod','a'); } else { if (cbjs.arrayContains(moderatorList.name,userEnter)) { nameIndex = moderatorList.name.indexOf(userEnter); if (moderatorList.type[nameIndex] == 'botmod') { isBotModEnter = true; isModEnter = true; } else if (moderatorList.type[nameIndex] == 'cbmod') { populateModeratorArray(userEnter,'cbmod','r'); } } } if (isVIPEnter && !cbjs.arrayContains(VIPInShowArray,userEnter)) { VIPInShowArray.push(userEnter); } if (isExtFanEnter && !cbjs.arrayContains(extFanInShowArray,userEnter)) { extFanInShowArray.push(userEnter); } if (isExtFanEnter2 && !cbjs.arrayContains(extFanInShow2Array,userEnter)) { extFanInShow2Array.push(userEnter); } if (isFanEnter) { populateFanClubArray(userEnter); } if(cb.limitCam_userHasAccess(userEnter)) { if (!cbjs.arrayContains(ticketShowViewerList,userEnter)) { ticketShowViewerList.push(userEnter); } } if ((viewerNotesWhen == 'First Entry' || viewerNotesWhen == 'Every Entry') && cbjs.arrayContains(viewerNotesArray.username,userEnter)) { noteIndex = viewerNotesArray.username.indexOf(userEnter); if (viewerNotesWhen == 'Every Entry' || !viewerNotesArray.displayed[noteIndex]) { cb.sendNotice('Fembot Viewer Notes for ' + viewerNotesArray.username[noteIndex] + ': ' + viewerNotesArray.notes[noteIndex], BC, '', '', 'bold'); viewerNotesArray.displayed[noteIndex] = true; if (viewerNotesWho == 'Display to Broadcaster and Moderators') { cb.sendNotice('Fembot Viewer Notes for ' + viewerNotesArray.username[noteIndex] + ': ' + viewerNotesArray.notes[noteIndex], '', '', '', 'bold', 'red'); } } } // **** General Entry Message if (cb.settings.enableEntryMessage == 'Yes' && !isGray) { entryMessage = checkNextLine(cb.settings.entryMessage); entryMessage = checkUsername(entryMessage,userEnter); if (tipMenuToggle == 1 || tipMenu2Toggle == 1) { entryMessage += '\n \u21E8 A Tip Menu is available. The menu may display periodically if enabled by the broadcaster, or to see the menu at anytime, type: /tipmenu'; if (tipMenuToggle == 1) { if (TIPMENUMOD.tipMenuItem.length > 0 && isModEnter) { cb.sendNotice(userEnter + ', as a Moderator, you get a discount off the general tip menu! \nTo see the Moderator specific discounted prices, type: /tipmenu', userEnter, appWarningColor, '', 'bold'); } else if (TIPMENUCBFC.tipMenuItem.length > 0 && isFanEnter) { if (cb.settings.tipMenuCBFCSalePct > 0 && cbfcSpecificMenuItems) { cb.sendNotice(userEnter + ', as a Fan Club Member, you get a discount off the general tip menu AND access to special menu items! \nTo see the Fan Club specific Tip Menu and discounted prices, type: /tipmenu', userEnter, appWarningColor, '', 'bold'); } else if (cb.settings.tipMenuCBFCSalePct > 0) { cb.sendNotice(userEnter + ', as a Fan Club Member, you get a discount off the general tip menu! \nTo see the Fan Club specific discounted prices, type: /tipmenu', userEnter, appWarningColor, '', 'bold'); } else if (cbfcSpecificMenuItems) { cb.sendNotice(userEnter + ', as a Fan Club Member, you have access to special menu items in addition to the general menu! \nTo see the Fan Club specific Tip Menu, type: /tipmenu', userEnter, appWarningColor, '', 'bold'); } } else if (TIPMENUEFC1.tipMenuItem.length > 0 && isExtFanEnter) { if (cb.settings.tipMenuEFC1SalePct > 0 && efc1SpecificMenuItems) { cb.sendNotice(userEnter + ', as a member of ' + EFCname + ', you get a discount off the general tip menu AND access to special menu items! \nTo see your Tip Menu and discounted prices, type: /tipmenu', userEnter, appWarningColor, '', 'bold'); } else if (cb.settings.tipMenuEFC1SalePct > 0) { cb.sendNotice(userEnter + ', as a member of ' + EFCname + ', you get a discount off the general tip menu! \nTo see the your discounted prices, type: /tipmenu', userEnter, appWarningColor, '', 'bold'); } else if (efc1SpecificMenuItems) { cb.sendNotice(userEnter + ', as a member of ' + EFCname + ', you have access to special menu items in addition to the general menu! \nTo see your Tip Menu, type: /tipmenu', userEnter, appWarningColor, '', 'bold'); } } else if (TIPMENUEFC2.tipMenuItem.length > 0 && isExtFanEnter2) { if (cb.settings.tipMenuEFC2SalePct > 0 && efc2SpecificMenuItems) { cb.sendNotice(userEnter + ', as a member of ' + EFCname2 + ', you get a discount off the general tip menu AND access to special menu items! \nTo see your Tip Menu and discounted prices, type: /tipmenu', userEnter, appWarningColor, '', 'bold'); } else if (cb.settings.tipMenuEFC2SalePct > 0) { cb.sendNotice(userEnter + ', as a member of ' + EFCname2 + ', you get a discount off the general tip menu! \nTo see the your discounted prices, type: /tipmenu', userEnter, appWarningColor, '', 'bold'); } else if (efc2SpecificMenuItems) { cb.sendNotice(userEnter + ', as a member of ' + EFCname2 + ', you have access to special menu items in addition to the general menu! \nTo see your Tip Menu, type: /tipmenu', userEnter, appWarningColor, '', 'bold'); } } else if (TIPMENUVIP.tipMenuItem.length > 0 && isVIPEnter) { cb.sendNotice(userEnter + ', as a VIP you get a discount off the general tip menu! \nTo see the VIP specific discounted prices, type: /tipmenu', userEnter, appWarningColor, '', 'bold'); } } } 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. To see the current poll choices and votes, type /poll'; if (isFanEnter && fanDouble) { entryMessage += '\n \u21E8 Fan Club members get double votes in the poll today!'; } if (isModEnter) { 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 (diceToggle == 1) { if (diceMultiRolls <= 1) { entryMessage += '\n \u21E8 The Dice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! \nTo see the prize list, type: /prizes'; } else if (diceMultiRolls == 2) { entryMessage += '\n \u21E8 The Dice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! \nTo see the prize list, type: /prizes \nYou can tip up to 2 multiples of the dice roll price (' + diceRollPrice + ' or ' + diceRollPrice*2 + ').'; } else if (diceMultiRolls == 3) { entryMessage += '\n \u21E8 The Dice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! \nTo see the prize list, type: /prizes \nYou can tip up to 3 multiples of the dice roll price (' + 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! \nTo see the prize list, type: /prizes \nYou can tip up to ' + diceMultiRolls + ' multiples of the dice roll price (' + diceRollPrice + ', ' + diceRollPrice*2 + ', ' + diceRollPrice*3 + ',...)'; } } if (notifierToggle == 0) { setNoticeColor(); } cb.sendNotice(entryMessage, userEnter, noticeBgColor, noticeTextColor, 'bold'); } // **** Room Rules if (roomRuleToggle == 1 && !isBCEnter) { if (roomRulesArray.length > 0) { displayRules(userEnter); } } // **** Announce VIPs if ((cb.settings.announceVIP == 'Enter Only' || cb.settings.announceVIP == 'Enter or Leave') && cbjs.arrayContains(VIPListArray,userEnter)) { temptextcolor = checkTextColor('Dark Blue',false); tempbgcolor = checkBgColor('Light Blue',false); if (cb.settings.announceVIPtext) { cb.sendNotice('Welcome ' + userEnter + '! ' + checkNextLine(cb.settings.announceVIPtext), '', tempbgcolor, temptextcolor, 'bold'); } else { cb.sendNotice('Welcome ' + VIPname + ' member ' + userEnter + ' 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,userEnter)) { temptextcolor = checkTextColor('Dark Green',false); tempbgcolor = checkBgColor('Light Green',false); if (cb.settings.announceExtFanstext) { cb.sendNotice('Welcome ' + userEnter + '! ' + checkNextLine(cb.settings.announceExtFanstext), '', tempbgcolor, temptextcolor, 'bold'); } else { cb.sendNotice('Welcome ' + EFCname + ' member ' + userEnter + ' to our room!', '', tempbgcolor, temptextcolor, 'bold'); } } if ((cb.settings.announceExtFans2 == 'Enter Only' || cb.settings.announceExtFans2 == 'Enter or Leave') && cbjs.arrayContains(extFanList2Array,userEnter)) { temptextcolor2 = checkTextColor('Dark Green',false); tempbgcolor2 = checkBgColor('Light Green',false); if (cb.settings.announceExtFanstext2) { cb.sendNotice('Welcome ' + userEnter + '! ' + checkNextLine(cb.settings.announceExtFanstext2), '', tempbgcolor2, temptextcolor2, 'bold'); } else { cb.sendNotice('Welcome ' + EFCname2 + ' member ' + userEnter + ' to our room!', '', tempbgcolor2, temptextcolor2, 'bold'); } } // **** Entry message if on the nice list if (cbjs.arrayContains(niceListArray,userEnter)) { cb.sendNotice('Welcome ' + userEnter + ', 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.',userEnter,'','','bold'); } // **** Ticket Show functions and message if (ticketShowToggle == 1) { if (cb.limitCam_isRunning()) { if (!cb.limitCam_userHasAccess(userEnter) && !isGray) { if (showStage === 'ticketshow') { cb.sendNotice(dashLineTicket1 + '\nTicket Show is in progress!\n' + getShowTime(userEnter) + dashLineTicket2, userEnter, ticketBgColor,ticketTxtColor,'bold'); if (ticketShowOtToggle == 1) { cb.sendNotice(dashLineTicket1 + '\n* ' + bctext + ' has enabled the Outstanding Ticket Feature. \n* To view the list of outstanding tickets, type: /otlist \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 started yet.' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } } else if (showStage === 'showwarn') { cb.sendNotice(dashLineTicket1 + '\nTicket Show is in progress, however ' + bctext + ' has indicated show is nearly over. \nBuying a ticket now is not recommended, but you may still buy a ticket for ' + ticketPrice + ' tokens. \n* Recommend checking with the broadcaster or moderators on show status before buying.\n' + getShowTime(userEnter) + dashLineTicket2, userEnter, ticketBgColor,ticketTxtColor,'bold'); } else if (showStage === 'showfinale') { cb.sendNotice(dashLineTicket1 + '\nTicket Show is in progress, however ' + bctext + ' has indicated show is nearly over and suspended ticket sales. \nBroadcaster may be returning to public chat shortly.\n' + getShowTime(userEnter) + dashLineTicket2, userEnter, ticketBgColor,ticketTxtColor,'bold'); } } } else { if (showStage === 'ticketsales') { if (cb.limitCam_userHasAccess(userEnter)) { cb.sendNotice(dashLineTicket1 + '\nWelcome! You have a ticket to the show and the show has not yet started.' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } else if (!isGray) { cb.sendNotice(dashLineTicket1 + '\nTicket Show sales are active and show has not yet started. \nThe ticket price is ' + ticketPrice + ' tokens.' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } if (cb.settings.hiddenShowAllowGift === 'Yes' && !isGray) { cb.sendNotice(dashLineTicket1 + '\n* ' + bctext + ' has enabled the the gifting of tickets. \n* If you purchase extra tickets, you can gift them to others using the command /giftticket' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } if (ticketShowOtToggle == 1) { cb.sendNotice(dashLineTicket1 + '\n* ' + bctext + ' has enabled the Outstanding Ticket Feature. \n* To view the list of outstanding tickets, type: /otlist \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 started yet.' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, 'bold'); } } else if (showStage === 'aftershow' || ticketShowEnded === true) { cb.sendNotice(dashLineTicket1 + '\nThe Ticket Show is over.' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, 'bold'); } } if (!cb.limitCam_userHasAccess(userEnter)) { if (isModEnter) { if (cb.settings.hiddenShowFreeMods === 'Yes') { addRmvTicket('add',userEnter,'mod',0,userEnter); cb.sendNotice(dashLineTicket1 + '\n* You\'ve automatically been added to the ticket show because you\'re a moderator!' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } cb.sendNotice(dashLineTicket1 + '\n* Moderators: The Fembot Ticket Show feature is enabled. \nType "/fbhelp ticketshow" to see details on available commands for this feature.' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } if (isFanEnter) { if (cb.settings.hiddenShowFreeFC === 'Yes') { addRmvTicket('add',userEnter,'fan',0,userEnter); cb.sendNotice(dashLineTicket1 + '\n* You\'ve automatically been added to the ticket list because you\'re in the Chaturbate Fan Club!' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice(dashLineTicket1 + '\n* As a Chaturbate Fan Club member, you can buy a ticket to the show for ' + cb.settings.hiddenShowPriceFC + ' tokens.' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } } if (isExtFanEnter) { if (cb.settings.hiddenShowFreeEFC == 'Yes') { addRmvTicket('add',userEnter,'fan',0,userEnter); cb.sendNotice(dashLineTicket1 + '\n* You\'ve automatically been added to the ticket list because you\'re a ' + EFCname + ' member!' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice(dashLineTicket1 + '\n* As a ' + EFCname + ' member, you can buy a ticket to the show for ' + cb.settings.hiddenShowPriceEFC + ' tokens.' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } } if (isExtFanEnter2) { if (cb.settings.hiddenShowFreeEFC2 == 'Yes') { addRmvTicket('add',userEnter,'fan',0,userEnter); cb.sendNotice(dashLineTicket1 + '\n* You\'ve automatically been added to the ticket list because you\'re a ' + EFCname2 + ' member!' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice(dashLineTicket1 + '\n* As a ' + EFCname2 + ' member, you can buy a ticket to the show for ' + cb.settings.hiddenShowPriceEFC2 + ' tokens.' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } } if (isVIPEnter) { if (cb.settings.hiddenShowFreeVIP == 'Yes') { addRmvTicket('add',userEnter,'vip',0,userEnter); cb.sendNotice(dashLineTicket1 + '\n* You\'ve automatically been added to the ticket list because you\'re a ' + VIPname + ' member!' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice(dashLineTicket1 + '\n* As a ' + VIPname + ' member, you can buy a ticket to the show for ' + cb.settings.hiddenShowPriceVIP + ' tokens.' + dashLineTicket2, userEnter, ticketBgColor, ticketTxtColor, "bold"); } } } } // **** Track Users for Answer Required Lock answerlocked = false; if (requireAnswerToggle == 1) { if (!isBCEnter && !isModEnter && !isFanEnter && !isExtFanEnter && !isExtFanEnter2 && !isVIPEnter) { if (isGray && requireAnswerLevel >= 1 || isLightBlue && requireAnswerLevel >= 2 || isDarkBlue && requireAnswerLevel >= 3 || isLightPurple && requireAnswerLevel >= 4 || isDarkPurple && requireAnswerLevel >= 5) { if (!cbjs.arrayContains(answerLockList,userEnter)) { addToAnswerLockList(userEnter); } if (answerLockStatus[answerLockList.indexOf(userEnter)] === false) { lockquestionindex = answerLockQuestion[answerLockList.indexOf(userEnter)]; cb.sendNotice('Welcome, ' + userEnter + ' chat is locked for your user level until you correctly complete the following sentence: \n ' + lockQuestions[lockquestionindex], userEnter, appWarningColor, '', 'bold'); answerlocked = true; } } } } // **** Track Grays for Time Lock if (grayLockToggle == 1) { if (!cbjs.arrayContains(grayLockList,userEnter)) { addToLockList(userEnter,isBCEnter,isModEnter,isFanEnter,isGray); } if (!answerlocked) { if (grayLockStatus.canChat[grayLockList.indexOf(userEnter)] === 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.', userEnter, appWarningColor, '', 'bold'); } } } // **** King tipper welcome if (kingTipperToggle == 1) { if (userEnter == kingTipperName && cb.settings.kingTipperWelcome) { kingTipperWelcome = checkUsername(cb.settings.kingTipperWelcome,userEnter); cb.sendNotice(kingTipperWelcome, '', kingTipperBgColor, '', 'bold'); } } }); } // *********************************** Actions upon leaving ************************************** { cb.onLeave(function(user) { var userLeave = user.user; // **** Remove from ticket show viewer list if (ticketShowToggle == 1) { if (cbjs.arrayContains(ticketShowViewerList,userLeave)) { cbjs.arrayRemove(ticketShowViewerList,userLeave); } } // **** Announce VIPs if ((cb.settings.announceVIP == 'Leave Only' || cb.settings.announceVIP == 'Enter or Leave') && cbjs.arrayContains(VIPListArray,userLeave)) { temptextcolor = checkTextColor('Dark Blue',false); tempbgcolor = checkBgColor('Light Blue',false); cb.sendNotice(VIPname + ' member ' + userLeave + ' 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,userLeave)) { temptextcolor = checkTextColor('Dark Green',false); tempbgcolor = checkBgColor('Light Green',false); cb.sendNotice(EFCname + ' member ' + userLeave + ' has left the room', '', tempbgcolor, temptextcolor, 'bold'); } if ((cb.settings.announceExtFans2 == 'Leave Only' || cb.settings.announceExtFans2 == 'Enter or Leave') && cbjs.arrayContains(extFanList2Array,userLeave)) { temptextcolor2 = checkTextColor('Dark Green',false); tempbgcolor2 = checkBgColor('Light Green',false); cb.sendNotice(EFCname2 + ' member ' + userLeave + ' has left the room', '', tempbgcolor2, temptextcolor2, 'bold'); } }); } // ******************************* Actions upon following ************************************** { cb.onFollow(function(user) { var followUser = user.user; var followBC = cb.room_slug; var followerColor = ''; numNewFollowersTotal++; if (user.tipped_tons_recently) { followerColor = 'Dark Purple'; numNewFollowersDPurple++; } else if (user.tipped_alot_recently) { followerColor = 'Light Purple'; numNewFollowersLPurple++; } else if (user.tipped_recently) { followerColor = 'Dark Blue'; numNewFollowersDBlue++; } else if (user.has_tokens) { followerColor = 'Light Blue'; numNewFollowersLBlue++; } else if (!user.has_tokens) { followerColor = 'Gray'; numNewFollowersGray++; } if (cb.settings.followerMessage && (followerNotifyFlag == 1 || followerNotifyFlag == 3)) { sendmsg = checkUsername(cb.settings.followerMessage,followUser); cb.sendNotice(sendmsg, followUser, followBgColor, followTextColor, 'bold'); } if (followerNotifyFlag == 2 || followerNotifyFlag == 3) { if (cb.settings.followerNotifyColor == 'Show All' || (cb.settings.followerNotifyColor == 'Not For Gray Users' && followerColor !== 'Gray') || (cb.settings.followerNotifyColor == 'Not For Gray and Light Blue Users' && followerColor !== 'Gray' && followerColor !== 'Light Blue')) { cb.sendNotice('You have a new follower: ' + followUser + ' (' + followerColor + ').', followBC, followBgColor, followTextColor, 'bold'); if (firstFollowMsg) { firstFollowMsg = false; cb.sendNotice('NOTE: You can change your follower notification settings using the /fmt command.', followBC, followBgColor, followTextColor, 'bold'); } } } if (cb.settings.followerMessage && followerNotifyFlag == 4) { sendmsg = checkUsername(cb.settings.followerMessage,followUser); cb.sendNotice(sendmsg, '', followBgColor, followTextColor, 'bold'); } }); } // *********************************** Actions upon tipping ************************************** { cb.onTip(function (tip) { var tipAmount = Number.parseInt(tip.amount, 10); var tipUser = tip.from_user; var realTipper = tip.from_user; var isFanTip = tip.from_user_in_fanclub; var isExtFanTip = cbjs.arrayContains(extFanListArray,realTipper); var isExtFan2Tip = cbjs.arrayContains(extFanList2Array,realTipper); var isVIPTip = cbjs.arrayContains(VIPListArray,realTipper); var isModTip = cbjs.arrayContains(moderatorList.name,realTipper); var tipNote = tip.message; var isAnon = tip.is_anon_tip; var userTotalTipsThisShow = 0; currentSessionTotal = currentSessionTotal + tipAmount; if (isAnon) { tipUser = 'Anonymous'; } if (isVIPTip && !cbjs.arrayContains(VIPInShowArray,realTipper)) { VIPInShowArray.push(realTipper); } if (isExtFanTip && !cbjs.arrayContains(extFanInShowArray,realTipper)) { extFanInShowArray.push(realTipper); } if (isExtFan2Tip && !cbjs.arrayContains(extFanInShow2Array,realTipper)) { extFanInShow2Array.push(realTipper); } // ***** Tip Count Array if (!isAnon) { if (!cbjs.arrayContains(tipCountArray.name, tipUser)) { populateTipCountArray(tipUser,tipAmount); userTotalTipsThisShow = tipAmount; } else { tipindex = findTipper(tipUser); tipCountArray.amount[tipindex] += tipAmount; userTotalTipsThisShow = tipCountArray.amount[tipindex]; } } // ***** New King Tipper? if (!isAnon) { if (cb.settings.kingSessionEnable == 'Yes') { if (currentKingTipper) { kingtipindex = findTipper(currentKingTipper); currentKingTipperAmount = tipCountArray.amount[kingtipindex]; } if (userTotalTipsThisShow >= cb.settings.kingSessionMinAmount && userTotalTipsThisShow > currentKingTipperAmount && realTipper != currentKingTipper) { currentKingTipperAmount = userTotalTipsThisShow; currentKingTipper = realTipper; if (!kingTipperColorSet) { setKingTipperColor(); } cb.sendNotice(cb.settings.kingSessionIcon + ' Congratulations ' + realTipper + ' on becoming the new King Tipper for the current show! ' + cb.settings.kingSessionIcon, '', kingTipperBgColor, '', 'bold'); } } } // ***** Auto-add VIP if (!isAnon) { if (!cbjs.arrayContains(VIPListArray, tipUser)) { if (cb.settings.joinVIPSingleTip > 0 && tipAmount == cb.settings.joinVIPSingleTip) { temptextcolor = checkTextColor('Dark Blue',false); tempbgcolor = checkBgColor('Light Blue',false); addRmvVIP(tipUser,'a'); cb.sendNotice('Fembot: ' + tipUser + ' has tipped to join ' + VIPname + ' !\nNote that this addition is only made in the Fembot, if you are also using Dorothy\'s UltraApp or Dorothy\'s Gamebot and would like this user added for those apps, you can use the /addvip command to manually add them to one or both at the same time.\nAlso note this is only applied during this session, permanent ' + VIPname + ' changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.', cb.room_slug, appNoticeColor); cb.sendNotice('Welcome ' + tipUser + ' to ' + VIPname + '!', '', tempbgcolor, temptextcolor, 'bold'); } else if (cb.settings.joinVIPCumulativeShow > 0 && userTotalTipsThisShow >= cb.settings.joinVIPCumulativeShow) { temptextcolor = checkTextColor('Dark Blue',false); tempbgcolor = checkBgColor('Light Blue',false); addRmvVIP(tipUser,'a'); cb.sendNotice('Fembot: ' + tipUser + ' has tipped beyond the cumulative threshold for this show (' + cb.settings.joinVIPCumulativeShow + ') to join ' + VIPname + '!\nNote that this addition is only made in the Fembot, if you are also using Dorothy\'s UltraApp or Dorothy\'s Gamebot and would like this user added for those apps, you can use the /addvip command to manually add them to one or both at the same time.\nAlso note this is only applied during this session, permanent ' + VIPname + ' changes must be made to the list defined when starting the Fembot. This list should also be saved to a separate document.', cb.room_slug, appNoticeColor); cb.sendNotice('Welcome ' + tipUser + ' to ' + VIPname + '!', '', tempbgcolor, temptextcolor, 'bold'); } } } // ***** Tip Response Message if (!isAnon) { if (tipResponseToggle == 1 || tipResponseToggle == 2) { if (tipResponseToggle == 1) { sendto = tipUser; } else { sendto = ''; } sendresponse = false; if (tipResponseAmount5 > 0 && tipAmount >= tipResponseAmount5 && cb.settings.tipResponseMessage5) { tipResponseMessage = checkUsername(cb.settings.tipResponseMessage5,tipUser); sendresponse = true; } else if (tipResponseAmount4 > 0 && tipAmount >= tipResponseAmount4 && cb.settings.tipResponseMessage4) { tipResponseMessage = checkUsername(cb.settings.tipResponseMessage4,tipUser); sendresponse = true; } else if (tipResponseAmount3 > 0 && tipAmount >= tipResponseAmount3 && cb.settings.tipResponseMessage3) { tipResponseMessage = checkUsername(cb.settings.tipResponseMessage3,tipUser); sendresponse = true; } else if (tipResponseAmount2 > 0 && tipAmount >= tipResponseAmount2 && cb.settings.tipResponseMessage2) { tipResponseMessage = checkUsername(cb.settings.tipResponseMessage2,tipUser); sendresponse = true; } else if (tipResponseAmount1 > 0 && tipAmount >= tipResponseAmount1 && cb.settings.tipResponseMessage1) { tipResponseMessage = checkUsername(cb.settings.tipResponseMessage1,tipUser); sendresponse = true; } if (sendresponse) { cb.sendNotice(tipResponseMessage, sendto, tipresponsebgcolor, tipresponsetextcolor, 'bold'); } } } // ***** Tip Menu if (tipMenuToggle == 1) { groupSpecificTipFound = false; if (isModTip && modSpecificMenuItems) { for (let tipidx = 0; tipidx < TIPMENUMOD.menuLength; tipidx++) { if (tipAmount == TIPMENUMOD.tipMenuPrice[tipidx]) { groupSpecificTipFound = true; tipMenuRequests.name.push(tipUser); tipMenuRequests.desc.push('"' + TIPMENUMOD.tipMenuItem[tipidx] + '" from the Moderator Menu.'); tipMenuRequests.amt.push(tipAmount); currenttime = new Date(); tipMenuRequestTime.push(currenttime.getTime()); if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(TIPMENUMOD.sepChar + ' ' + tipUser + ' tipped for " ' + TIPMENUMOD.tipMenuItem[tipidx] + ' " from the Moderator Tip Menu ' + TIPMENUMOD.sepChar, '', TIPMENU.bgColorTip, TIPMENU.txtColorTip, 'bold'); } else { cb.sendNotice(tipUser + ' tipped for " ' + TIPMENUMOD.tipMenuItem[tipidx] + ' " from the Moderator Tip Menu.', '', TIPMENU.bgColorTip, TIPMENU.txtColorTip, 'bold'); } } } } else if (isFanTip && cbfcSpecificMenuItems) { for (let tipidx = 0; tipidx < TIPMENUCBFC.menuLength; tipidx++) { if (tipAmount == TIPMENUCBFC.tipMenuPrice[tipidx]) { groupSpecificTipFound = true; tipMenuRequests.name.push(tipUser); tipMenuRequests.desc.push('"' + TIPMENUCBFC.tipMenuItem[tipidx] + '" from the CB Fanclub Menu.'); tipMenuRequests.amt.push(tipAmount); currenttime = new Date(); tipMenuRequestTime.push(currenttime.getTime()); if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(TIPMENUCBFC.sepChar + ' ' + tipUser + ' tipped for " ' + TIPMENUCBFC.tipMenuItem[tipidx] + ' " from the Fanclub Tip Menu ' + TIPMENUCBFC.sepChar, '', TIPMENU.bgColorTip, TIPMENU.txtColorTip, 'bold'); } else { cb.sendNotice(tipUser + ' tipped for " ' + TIPMENUCBFC.tipMenuItem[tipidx] + ' " from the Fanclub Tip Menu.', '', TIPMENU.bgColorTip, TIPMENU.txtColorTip, 'bold'); } } } } else if (isExtFanTip && efc1SpecificMenuItems) { for (let tipidx = 0; tipidx < TIPMENUEFC1.menuLength; tipidx++) { if (tipAmount == TIPMENUEFC1.tipMenuPrice[tipidx]) { groupSpecificTipFound = true; tipMenuRequests.name.push(tipUser); tipMenuRequests.desc.push('"' + TIPMENUEFC1.tipMenuItem[tipidx] + '" from the ' + EFCname + ' Menu.'); tipMenuRequests.amt.push(tipAmount); currenttime = new Date(); tipMenuRequestTime.push(currenttime.getTime()); if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(TIPMENUEFC1.sepChar + ' ' + tipUser + ' tipped for " ' + TIPMENUEFC1.tipMenuItem[tipidx] + ' " from the ' + EFCname + ' Tip Menu ' + TIPMENUEFC1.sepChar, '', TIPMENU.bgColorTip, TIPMENU.txtColorTip, 'bold'); } else { cb.sendNotice(tipUser + ' tipped for " ' + TIPMENUEFC1.tipMenuItem[tipidx] + ' " from the ' + EFCname + ' Tip Menu.', '', TIPMENU.bgColorTip, TIPMENU.txtColorTip, 'bold'); } } } } else if (isExtFan2Tip && efc2SpecificMenuItems) { for (let tipidx = 0; tipidx < TIPMENUEFC2.menuLength; tipidx++) { if (tipAmount == TIPMENUEFC2.tipMenuPrice[tipidx]) { groupSpecificTipFound = true; tipMenuRequests.name.push(tipUser); tipMenuRequests.desc.push('"' + TIPMENUEFC2.tipMenuItem[tipidx] + '" from the ' + EFCname2 + ' Menu.'); tipMenuRequests.amt.push(tipAmount); currenttime = new Date(); tipMenuRequestTime.push(currenttime.getTime()); if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(TIPMENUEFC2.sepChar + ' ' + tipUser + ' tipped for " ' + TIPMENUEFC2.tipMenuItem[tipidx] + ' " from the ' + EFCname2 + ' Tip Menu ' + TIPMENUEFC2.sepChar, '', TIPMENU.bgColorTip, TIPMENU.txtColorTip, 'bold'); } else { cb.sendNotice(tipUser + ' tipped for " ' + TIPMENUEFC2.tipMenuItem[tipidx] + ' " from the ' + EFCname2 + ' Tip Menu.', '', TIPMENU.bgColorTip, TIPMENU.txtColorTip, 'bold'); } } } } else if (isVIPTip && vipSpecificMenuItems) { for (let tipidx = 0; tipidx < TIPMENUVIP.menuLength; tipidx++) { if (tipAmount == TIPMENUVIP.tipMenuPrice[tipidx]) { currenttime = new Date(); groupSpecificTipFound = true; tipMenuRequests.name.push(tipUser); tipMenuRequests.desc.push('"' + TIPMENUVIP.tipMenuItem[tipidx] + '" from the VIP Menu.'); tipMenuRequests.amt.push(tipAmount); currenttime = new Date(); tipMenuRequestTime.push(currenttime.getTime()); if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(TIPMENUVIP.sepChar + ' ' + tipUser + ' tipped for " ' + TIPMENUVIP.tipMenuItem[tipidx] + ' " from the VIP Tip Menu ' + TIPMENUVIP.sepChar, '', TIPMENU.bgColorTip, TIPMENU.txtColorTip, 'bold'); } else { cb.sendNotice(tipUser + ' tipped for " ' + TIPMENUVIP.tipMenuItem[tipidx] + ' " from the VIP Tip Menu.', '', TIPMENU.bgColorTip, TIPMENU.txtColorTip, 'bold'); } } } } if (!groupSpecificTipFound) { for (let tipidx = 0; tipidx < TIPMENU.menuLength; tipidx++) { if (tipAmount == TIPMENU.tipMenuPrice[tipidx]) { tipMenuRequests.name.push(tipUser); tipMenuRequests.desc.push('"' + TIPMENU.tipMenuItem[tipidx] + '" from Tip Menu 1.'); tipMenuRequests.amt.push(tipAmount); currenttime = new Date(); tipMenuRequestTime.push(currenttime.getTime()); if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(TIPMENU.sepChar + ' ' + tipUser + ' tipped for " ' + TIPMENU.tipMenuItem[tipidx] + ' " ' + TIPMENU.sepChar, '', TIPMENU.bgColorTip, TIPMENU.txtColorTip, 'bold'); } else { cb.sendNotice(tipUser + ' tipped for " ' + TIPMENU.tipMenuItem[tipidx] + ' ".', '', TIPMENU.bgColorTip, TIPMENU.txtColorTip, 'bold'); } } } } } if (tipMenu2Toggle == 1) { for (let i = 0; i < TIPMENU2.menuLength; i++) { if (tipAmount == TIPMENU2.tipMenuPrice[i]) { tipMenuRequests.name.push(tipUser); tipMenuRequests.desc.push('"' + TIPMENU2.tipMenuItem[i] + '" from Tip Menu 2.'); tipMenuRequests.amt.push(tipAmount); currenttime = new Date(); tipMenuRequestTime.push(currenttime.getTime()); if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(TIPMENU2.sepChar + ' ' + tipUser + ' tipped for " ' + TIPMENU2.tipMenuItem[i] + ' " ' + TIPMENU2.sepChar, '', TIPMENU2.bgColorTip, TIPMENU2.txtColorTip, 'bold'); } else { cb.sendNotice(tipUser + ' tipped for " ' + TIPMENU2.tipMenuItem[i] + ' ".', '', TIPMENU2.bgColorTip, TIPMENU2.txtColorTip, 'bold'); } } } } if (posTipMenuToggle == 1) { for (let i = 0; i < POSTIPMENU.posMenuLength; i++) { if (tipAmount == POSTIPMENU.posTipMenuPrice[i]) { POSTIPMENU.posRequesters.push(tipUser); POSTIPMENU.posRequest.push(POSTIPMENU.posTipMenuItem[i]); currenttime = new Date(); POSTIPMENU.posRequestTime.push(currenttime.getTime()); if (cb.settings.posSepInResponse == 'Yes') { cb.sendNotice(POSTIPMENU.posSepChar + ' ' + tipUser + ' tipped for " ' + POSTIPMENU.tipMenuItem[tipidx] + ' " ' + POSTIPMENU.posSepChar, '', POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor, 'bold'); } else { cb.sendNotice(tipUser + ' tipped for " ' + POSTIPMENU.posTipMenuItem[i] + ' ".', '', POSTIPMENU.posBgColor, POSTIPMENU.posTxtColor, 'bold'); } } } } // ***** Add to Ticket Show Backup List if (backupToggle == 1 && !cbjs.arrayContains(backupListArray,realTipper)) { if (ticketShowType != 'Fembot Ticket Show' && tipAmount >= backupPrice) { addRmvTicketBackupList('addtip',realTipper); } } // ***** Add to Pre-Sale Ticket List if (presalesToggle == 1 && !cbjs.arrayContains(presaleArray,realTipper)) { if (tipAmount >= presalePrice) { addRmvPresale('addtip',realTipper,tipAmount,tipUser); } else { checkCumulative(realTipper,tipAmount,presalePrice,'common','presale',tipUser); } } // ***** Add to Ticket Show if (ticketShowToggle == 1 && !ticketShowEnded && !ticketSalesEnded && !cb.limitCam_userHasAccess(realTipper)) { if (isFanTip) { if (tipAmount >= ticketPriceFC) { addRmvTicket('addtip', realTipper, 'fan', tipAmount, tipUser); } else { checkCumulative(realTipper,tipAmount,ticketPriceFC,'fan','ticket', tipUser); } } else if (isExtFanTip) { if (tipAmount >= ticketPriceEFC) { addRmvTicket('addtip', realTipper, 'fan', tipAmount, tipUser); } else { checkCumulative(realTipper,tipAmount,ticketPriceEFC,'fan','ticket', tipUser); } } else if (isExtFan2Tip) { if (tipAmount >= ticketPriceEFC2) { addRmvTicket('addtip', realTipper, 'fan', tipAmount, tipUser); } else { checkCumulative(realTipper,tipAmount,ticketPriceEFC2,'fan','ticket', tipUser); } } else if (isVIPTip) { if (tipAmount >= ticketPriceVIP) { addRmvTicket('addtip', realTipper, 'vip', tipAmount, tipUser); } else { checkCumulative(realTipper,tipAmount,ticketPriceVIP,'vip','ticket', tipUser); } } else { if (tipAmount >= ticketPrice) { addRmvTicket('addtip', realTipper, 'common', tipAmount, tipUser); } else { checkCumulative(realTipper,tipAmount,ticketPrice,'common','ticket', tipUser); } } } else if (ticketShowToggle == 1 && !ticketShowEnded && !ticketSalesEnded && cb.limitCam_userHasAccess(realTipper) && cb.settings.hiddenShowAllowGift === 'Yes') { if (tipAmount >= ticketPrice) { addRmvTicket('addextra', realTipper, 'common', tipAmount, tipUser); } } // ***** Progress on Ticket Show Goal if (ticketShowToggle == 1) { ticketShowGoalProgress(tipAmount); } // ***** Perform Token Poll Tip Functions if (tokenPollToggle == 1 && pollRunning) { if (tipAmount == stealPollAmount) { stealPoll(tipUser); } else if (cbjs.arrayContains(pollArrayAmount,tipAmount)) { voteAmount = 1; if (isFanTip && fanDouble) { voteAmount = 2; cb.sendNotice('Since you are a member of the fan club, your vote is doubled!', tipUser, tokenPollBgColor, tokenPollTextColor, 'bold'); } pollTip(tipAmount,voteAmount,tipUser); } } else if (onDemandPollRunning) { if (tipAmount == stealPollAmount) { stealODPoll(tipUser); } else if (cbjs.arrayContains(odpollArrayAmount,tipAmount)) { voteAmount = 1; if (isFanTip && fanDouble) { voteAmount = 2; cb.sendNotice('Since you are a member of the fan club, your vote is doubled!', tipUser, odtokenPollBgColor, odtokenPollTextColor, 'bold'); } odpollTip(tipAmount,voteAmount,tipUser); } } // ***** Perform Dice Roll Function if (diceToggle == 1 && tipAmount >= diceRollPrice && (tipAmount / diceRollPrice <= diceMultiRolls) && (tipAmount % diceRollPrice == 0)) { var numberOfRolls = Math.floor(parseInt(tipAmount) / diceRollPrice); for (var i = 0; i < numberOfRolls; i++) { diceRoll(tipUser); diceLastRoller = tipUser; } } // ***** Buy an Icon/Gif for your username if (!isAnon) { if (iconTipAmountArray.length > 0) { if (tipForIconType == 'Specific Tip Amount') { if (cbjs.arrayContains(iconTipAmountArray,tipAmount)) { newiconindex = iconTipAmountArray.indexOf(tipAmount); alreadythisicon = false; if (cbjs.arrayContains(tipForIconArray.name,realTipper)) { iconindex = tipForIconArray.name.indexOf(realTipper); if (tipForIconArray.icon[iconindex] == iconTipIconArray[newiconindex]) { alreadythisicon = true; } } if (!alreadythisicon) { addTipForIcon(realTipper,iconTipIconArray[newiconindex]); cb.sendNotice('Congratulations, you have tipped to change your user icon!', realTipper, appNoticeColor); } } } else if (tipForIconType == 'Cumulative Tip Amount' && userTotalTipsThisShow >= iconTipAmountArray[0]) { for (var i = (iconTipAmountArray.length-1); i >= 0; i--) { if (userTotalTipsThisShow >= iconTipAmountArray[i]) { alreadythisicon = false; if (cbjs.arrayContains(tipForIconArray.name,realTipper)) { iconindex = tipForIconArray.name.indexOf(realTipper); if (tipForIconArray.icon[iconindex] == iconTipIconArray[i]) { alreadythisicon = true; } } if (!alreadythisicon) { addTipForIcon(realTipper,iconTipIconArray[i]); cb.sendNotice('Congratulations, you have tipped to change your user icon!', realTipper, appNoticeColor); } break; } } } } } // ***** Forward Tip Note if (tipNote) { if (tipNoteForwardID == '*ALLMODS' && cb.settings.modLevel == 'Advanced') { cb.sendNotice('Forwarded Tip Note from ' + tipUser + ': ' + tipNote, BC, tipnoteyellow, '', 'bold', 'red'); } else if (tipNoteForwardID == '*ALLMODS') { cb.sendNotice('WARNING: You have configured "*ALLMODS" for Tip Note forwarding, but the mod level is not set to "Advanced". Therefore, forwarding is disabled.', BC, appWarningColor); } else if (tipNoteForwardID && tipNoteForwardID != realTipper) { if (cbjs.arrayContains(moderatorList.name,tipNoteForwardID)) { cb.sendNotice('Forwarded Tip Note from ' + tipUser + ': ' + tipNote, tipNoteForwardID, tipnoteyellow, '', 'bold'); } else { if (!tipnoteWarned) { cb.sendNotice('WARNING: You have configured a single user ID for Tip Note forwarding, but ' + tipNoteForwardID + ' is not a broadcaster or moderator. Therefore, forwarding is disabled.', BC, appWarningColor); tipnoteWarned = true; } } } } }); } // *********************************** Initialize ************************************** { if (initialize == 0) { cb.sendNotice(':DorothysUltraFembot v4.2'); var intromessage = '\u26D4 Version 4.2 was released on March 22, 2021 \u26D4'; intromessage += '\n \u2705 Please use the command "/about" to see the highlights for the current version and recent previous releases, or you can read the full list on the bot description page:'; intromessage += '\n \u2705 https://chaturbate.com/apps/app_details/dorothys-ultra-fembot/ '; intromessage += '\n \u2705 Be sure to check out the fan club menus, color themes, gradient color patterns, and Split List tip menu formats introduced in version 4.0. They are a great way to further personalize your room!'; intromessage += '\n \u2705 Reminder: You can type "/fbhelp" to display the full command list, or use one of the group qualifiers to see more details within a group, such as "/fbhelp tokenpoll"'; cb.sendNotice(intromessage, BC, red); // *** Init Features using toggle functions // *** Border style borderChar = cb.settings.separatorEmoji; if (cb.settings.noticeSepStyle == 'Custom Emoji Below') { borderCharSpacing = 'emoji'; if (borderChar) { if (borderChar.includes(':') || borderChar.includes('\\')) { cb.sendNotice('Fembot: You have configured configured the notice border style as "Custom Emoji" but the value contains ":" or "\\" (CB gifs are not allowed). Defaulting to an emoji of Heavy Dashed Line " \u2796 ".', BC, appWarningColor); borderChar = '\u2796'; } } else { borderChar = '\u2796'; cb.sendNotice('Fembot: You have configured configured the notice border style as "Custom Emoji" but an emoji is not defined. Defaulting to an emoji of Heavy Dashed Line " \u2796 ".', BC, appWarningColor); } } else if (cb.settings.noticeSepStyle == 'Custom Unicode Character Below') { borderCharSpacing = 'unicode'; if (borderChar) { if (borderChar.includes(':')) { cb.sendNotice('Fembot: You have configured configured the notice border style as "Custom Unicode Character" but the value contains ":" (CB gifs are not allowed). Defaulting to a character of Heavy Dashed Line " \u268A ".', BC, appWarningColor); borderChar = '\u268A'; } } else { borderChar = '\u268A'; cb.sendNotice('Fembot: You have configured configured the notice border style as "Custom Unicode Character" but a character is not defined. Defaulting to a character of Heavy Dashed Line " \u268A ".', BC, appWarningColor); } } else if (cb.settings.noticeSepStyle == 'Heavy Dashed Line') { borderCharSpacing = 'unicode'; borderChar = '\u268A'; } else if (cb.settings.noticeSepStyle == 'Light Dashed Line') { borderCharSpacing = 'light'; borderChar = '-'; } else { borderCharSpacing = 'none'; } var dashLineTicket1 = noticeBorder('top','ticket',' :uaticketsmall TICKET SHOW :uaticketsmall ') ; var dashLineTicket2 = noticeBorder('bottom','ticket',' :uaticketsmall TICKET SHOW :uaticketsmall '); setFollowerColor(); if (cb.settings.tipNoteForwardID) { if (cb.settings.tipNoteForwardID == '*ALLMODS') { if (cb.settings.modLevel != 'Advanced') { cb.sendNotice('WARNING: You have configured "*ALLMODS" for Tip Note forwarding, but the mod level is not set to "Advanced". Therefore, forwarding is disabled.', BC, appWarningColor); } tipNoteForwardID = '*ALLMODS'; } else { tipNoteForwardID = cb.settings.tipNoteForwardID.toLowerCase(); } } if (cb.settings.EFCname != '' && cb.settings.EFCname != null) { EFCname = cb.settings.EFCname; } else { EFCname = 'External Fan Club'; } if (cb.settings.EFCname2 != '' && cb.settings.EFCname2 != null) { EFCname2 = cb.settings.EFCname2; } else { EFCname2 = 'External Fan Club 2'; } if (cb.settings.efcBgCustColor != '' && cb.settings.efcBgCustColor != null) { efcBgCustColor = checkBgColor(cb.settings.efcBgCustColor,false); if (efcBgCustColor == 'default') { cb.sendNotice('External Fan Club 1 Highlight Color Error, it must be in a HEX format, such as "#e6f9e6". Using default light green highlight color.', BC, appWarningColor); extfanclubBgColor = '#e6f9e6'; } else { extfanclubBgColor = efcBgCustColor; } } else { extfanclubBgColor = '#e6f9e6'; } if (cb.settings.efcBgCustColor2 != '' && cb.settings.efcBgCustColor2 != null) { efcBgCustColor2 = checkBgColor(cb.settings.efcBgCustColor2,false); if (efcBgCustColor2 == 'default') { cb.sendNotice('External Fan Club 2 Highlight Color Error, it must be in a HEX format, such as "#e6f9e6". Using default light green highlight color.', BC, appWarningColor); extfanclubBgColor2 = '#e6f9e6'; } else { extfanclubBgColor2 = efcBgCustColor2; } } else { extfanclubBgColor2 = '#e6f9e6'; } if (cb.settings.VIPBgCustColor != '' && cb.settings.VIPBgCustColor != null) { VIPBgCustColor = checkBgColor(cb.settings.VIPBgCustColor,false); if (VIPBgCustColor == 'default') { cb.sendNotice('VIP List Highlight Color Error, it must be in a HEX format, such as "#faebf7". Using default light purple highlight color.', BC, appWarningColor); vipBgColor = '#faebf7'; } else { vipBgColor = VIPBgCustColor; } } else { vipBgColor = '#faebf7'; } if (cb.settings.VIPname != '' && cb.settings.VIPname != null) { VIPname = cb.settings.VIPname; } else { VIPname = 'VIP List'; } if (cb.settings.bctext != '' && cb.settings.bctext != null) { bctext = cb.settings.bctext; } else { bctext = 'The Broadcaster'; } if (cb.settings.enableGroupIcons == 'Yes') { groupIconsToggle = 1; } if (cb.settings.enableTipLeaderIcons == 'Yes') { tipLeaderIconsToggle = 1; } if (cb.settings.enableLeaderboard == 'Yes') { setLeaderToggle('on',BC,false); } notifierArray[0] = cb.settings.notifierMessage1; notifierArray[1] = cb.settings.notifierMessage2; notifierArray[2] = cb.settings.notifierMessage3; notifierArray[3] = cb.settings.notifierMessage4; notifierArray[4] = cb.settings.notifierMessage5; notifierArray[5] = cb.settings.notifierMessage6; notifierArray[6] = cb.settings.notifierMessage7; notifierArray[7] = cb.settings.notifierMessage8; notifierArray[8] = cb.settings.notifierMessage9; if (cb.settings.enableNotifier == 'Yes') { setNotifierToggle('on',BC,false); } if (cb.settings.enableTipCount == 'Yes') { setTipCountToggle('on',BC,false); } if (cb.settings.enableDiceGame == 'Yes') { setDiceToggle('on',BC); } if (cb.settings.enableTipMenu == 'Yes') { setTipMenuToggle('on',BC); 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".', BC, appWarningColor); } } if (cb.settings.enableTipMenu2 == 'Yes' && cb.settings.enableTipMenu == 'No') { setTipMenu2Toggle('on',BC); } if (cb.settings.enablePosTipMenu == 'Yes') { setPosTipMenuToggle('on',BC); } if (cb.settings.enableTokenPoll == 'Yes') { setTokenPollToggle('on',BC); } if (cb.settings.textPollEnable == 'Yes') { setTextPollToggle('on',BC); } if (cb.settings.enableLushMenu == 'Yes') { whichToy = cb.settings.whichToy; whichToyIcon = ':' + whichToy.toLowerCase() + 'sm'; setLushMenuToggle('on',BC); } if (cb.settings.enableMediaNotice == 'Yes') { setMediaToggle('on',BC,false); } if (cb.settings.enableTipResponse == 'Yes, send to tipper') { setTipResponseToggle('tipper',BC,false); } else if (cb.settings.enableTipResponse == 'Yes, send to all') { setTipResponseToggle('all',BC,false); } if (cb.settings.lockGrayChat == 'Yes') { setGrayLockToggle('on',BC); } 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',BC,false); } for (let i = 0; i < 8; i++) { if (this['roomRule'+(i+1)]) { roomRulesArray.push(this['roomRule'+(i+1)]); } } if (cb.settings.enableRoomRules == 'Yes') { setRoomRulesToggle('on',BC,false); } initFollowers(); iconTipNoticeToggle = 0; for (let i = 0; i < 5; i++) { if (this['iconTipAmount'+(i+1)] && this['iconTipIcon'+(i+1)]) { iconTipAmountArray.push(this['iconTipAmount'+(i+1)]); iconTipIconArray.push(this['iconTipIcon'+(i+1)]); priceused = 'iconTipAmount'+(i+1); priceChecker('add','Tip for Icon #' + (i+1),priceused,BC); } } if (cb.settings.iconTipNoticeInt && iconTipAmountArray.length > 0) { setIconTipNoticeToggle('on',BC, false); } // *** Init Lists if (cb.settings.niceList != '' && cb.settings.niceList != null) { var n = cb.settings.niceList.toLowerCase(); niceListArray = n.split(','); for (var i = 0; i < niceListArray.length; i++) { niceListArray[i] = niceListArray[i].trim(); } } if (cb.settings.silenceList != '' && cb.settings.silenceList != null) { var n = cb.settings.silenceList.toLowerCase(); silenceListArray = n.split(','); for (var i = 0; i < silenceListArray.length; i++) { silenceListArray[i] = silenceListArray[i].trim(); } } if (cb.settings.ninjaList != '' && cb.settings.ninjaList != null) { var n = cb.settings.ninjaList.toLowerCase(); ninjaListArray = n.split(','); for (var i = 0; i < ninjaListArray.length; i++) { ninjaListArray[i] = ninjaListArray[i].trim(); } } if (cb.settings.wordBlockList != '' && cb.settings.wordBlockList != null) { var n = cb.settings.wordBlockList.toLowerCase(); wordListArrayTemp = n.split(','); for (var i = 0; i < wordListArrayTemp.length; i++) { wordtoadd = wordListArrayTemp[i].trim(); if (wordtoadd.length < 2) { cb.sendNotice('Cannot load private word list entry ' + wordtoadd + ', it is less than 2 characters).', BC, appWarningColor); } else { wordListArray.push(wordtoadd); } } } if (cb.settings.wordBlockListPub != '' && cb.settings.wordBlockListPub != null) { var n = cb.settings.wordBlockListPub.toLowerCase(); wordListArrayPubTemp = n.split(','); for (var i = 0; i < wordListArrayPubTemp.length; i++) { wordtoadd = wordListArrayPubTemp[i].trim(); if (wordtoadd.length < 2) { cb.sendNotice('Cannot load public word list entry ' + wordtoadd + ', it is less than 2 characters).', BC, appWarningColor); } else { wordListArrayPub.push(wordtoadd); } } } if (cb.settings.extFanList != '' && cb.settings.extFanList != null) { var n = cb.settings.extFanList.toLowerCase(); extFanListArray = n.split(','); for (var i = 0; i < extFanListArray.length; i++) { extFanListArray[i] = extFanListArray[i].trim(); } } if (cb.settings.extFanList2 != '' && cb.settings.extFanList2 != null) { var n = cb.settings.extFanList2.toLowerCase(); extFanList2Array = n.split(','); for (var i = 0; i < extFanList2Array.length; i++) { extFanList2Array[i] = extFanList2Array[i].trim(); } } if (cb.settings.VIPList != '' && cb.settings.VIPList != null) { var n = cb.settings.VIPList.toLowerCase(); VIPListArray = n.split(','); for (var i = 0; i < VIPListArray.length; i++) { VIPListArray[i] = VIPListArray[i].trim(); } } if (cb.settings.hiddenShowOTList != '' && cb.settings.hiddenShowOTList != null) { var n = cb.settings.hiddenShowOTList.toLowerCase(); outstandingTicketArray = n.split(','); for (var i = 0; i < outstandingTicketArray.length; i++) { outstandingTicketArray[i] = outstandingTicketArray[i].trim(); } } if (cb.settings.botModList != '' && cb.settings.botModList != null) { var n = cb.settings.botModList.toLowerCase(); botModListArray = n.split(','); for (var i = 0; i < botModListArray.length; i++) { usertoadd = botModListArray[i].trim(); var checkSpecial = /[!@#$%^&*()+\-=\[\]{};':"\\|,.<>\/?]+/; if (usertoadd.length < 3 || usertoadd.includes(' ')) { cb.sendNotice('Cannot load bot moderator list entry ' + usertoadd + ', it is improperly formatted (either contains a blank or is less than 3 characters).', BC, appWarningColor); } else if (checkSpecial.test(usertoadd)) { cb.sendNotice('Cannot load bot moderator list entry ' + usertoadd + ', it contains a special character.', BC, appWarningColor); } else { populateModeratorArray(usertoadd,'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.', BC, appWarningColor); } else { if (namelink[1] == '') { namelink[1] = null; } if (namelink[2] == '') { namelink[2] = null; } if (namelink[3] == '') { namelink[3] = null; } iconNicknamesArray.name.push(namelink[0].toLowerCase()); 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, BC, appWarningColor); } } if (cb.settings.viewerNotesList != '' && cb.settings.viewerNotesList != null) { var n = cb.settings.viewerNotesList; tempnotesarray = n.split('^'); if (tempnotesarray.length > 0) { for (var i = 0; i < tempnotesarray.length; i++) { namelink = tempnotesarray[i].split('/'); if (namelink[0] == '' || namelink[0] == null) { cb.sendNotice('Cannot load viewer notes list entry ' + tempnotesarray[i] + ', no user name is provided.', BC, appWarningColor); } else { if (namelink[1] == '') { namelink[1] = null; } viewerNotesArray.username.push(namelink[0].toLowerCase()); viewerNotesArray.notes.push(namelink[1]); viewerNotesArray.displayed.push(false); viewerNotesArray.addinshow.push(false); } } } else { cb.sendNotice('Cannot load viewer notes list, invalid formatting of list: ' + tempnotesarray, BC, appWarningColor); } } if (cb.settings.enableAllTime == 'Yes') { setAllTimeToggle('on',BC); if (cb.settings.joinVIPCumulativeAllTime > 0 && allTimeArray.name.length > 0) { numadded = 0; for (var i = 0; i < allTimeArray.name.length; i++) { if (allTimeArray.totaltips[i] >= cb.settings.joinVIPCumulativeAllTime && !cbjs.arrayContains(VIPListArray, allTimeArray.name[i])) { addRmvVIP(allTimeArray.name[i],'a'); cb.sendNotice(allTimeArray.name[i] + ' has been added to the VIP list.', BC, appNoticeColor); numadded++; } } if (numadded > 0) { cb.sendNotice(numadded + ' users have been added to the VIP list based on All-time Tipper totals.\nNote that the additions are only made in the Fembot, if you are also using Dorothy\'s UltraApp or Dorothy\'s Gamebot and would like this user added to the VIP list for those apps, you can use the /addvip command to manually add them to one or both at the same time, or include them in the laucnh page lists for those apps.', BC, appNoticeColor); } } } if (cb.settings.exemptCommandList != '' && cb.settings.exemptCommandList != null) { var n = cb.settings.exemptCommandList.toLowerCase(); exemptCmdList = n.split(','); for (var i = 0; i < exemptCmdList.length; i++) { exemptCmdList[i] = exemptCmdList[i].trim(); } } //*** Init Ticket Show Features var ticketPrice = cb.settings.hiddenShowPrice; if (ticketShowType == 'Fembot Ticket Show') { if (cb.settings.enableHiddenShow == 'Yes') { if (ticketPrice > 0) { setTicketShowToggle('on', BC,ticketPrice); if (cb.settings.enableHiddenShowOT == 'Yes') { setTicketShowOtToggle('on', BC); } } 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". ', BC, appWarningColor); } } } else { if (cb.settings.ticketShowPrice > 0) { setBackupTicketPrice(cb.settings.ticketShowPrice,BC) setBackupToggle('on', BC,false); } 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".', BC, appWarningColor); } } 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 (' + 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".', BC, appWarningColor); } 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.', BC, appWarningColor); } else { setPresalesToggle('on', BC); } } 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". ', BC, appWarningColor); } } else { cb.sendNotice('Unable to start pre-sales, the Fembot Ticket Show feature is already started.', BC, appWarningColor); } } if (cb.settings.enablePMResponse == 'Yes' && cb.settings.pmResponseMessage != '') { sendPMResponse = true; } else { sendPMResponse = false; } if (cb.settings.enablePrvResponse == 'Yes' && cb.settings.prvResponseMessage != '') { sendPvtResponse = true; } else { sendPvtResponse = false; } //*** Init King Tipper var kingTipperToggle = 0; kingTipperName = ''; kingTipperAmount = 0; if (cb.settings.kingEnable == 'Yes, define user below') { if (cb.settings.kingTipperName != null && cb.settings.kingTipperName != ' ') { kingTipperName = cb.settings.kingTipperName; if (cb.settings.kingTipperAmount > 0) { kingTipperAmount = cb.settings.kingTipperAmount; } setKingTipperToggle('1',BC,false); } else { cb.sendNotice('Unable to use the King Tipper feature, it has been configured for King Tipper name entry, but no name is entered. King Tipper not started.', BC, appWarningColor); } } else if (cb.settings.kingEnable == 'Yes, use All Time list') { if (cb.settings.enableAllTime == 'Yes') { setKingTipperToggle('2',BC,false); } else { cb.sendNotice('Unable to use All Time tip leader as the King Tipper because the Fembot setting to track All Time tipping is disabled. King Tipper not started.', BC, appWarningColor); } } //*** Init King Session Tipper var kingSessionToggle = 0; if (cb.settings.kingSessionEnable == 'Yes') { setKingSessionToggle('1',BC,false); } // *** Load Array for All Time Icons for (let loadindex = 1; loadindex <= 8; loadindex++) { alltimeamount = this["allTimeAmount"+loadindex]; alltimeicon = this["allTimeIcon"+loadindex]; if (alltimeamount != '' && alltimeamount != null && alltimeicon != '' && alltimeicon != null) { alltimeIconArray.amount.push(alltimeamount); alltimeIconArray.icon.push(alltimeicon); } } // *** Load Theme Icons var iconDarkBlue = ''; var iconLightPurple = ''; var iconDarkPurple = ''; if (cb.settings.iconTheme == 'None') { themeIconsToggle = 0; } else { themeIconsToggle = 1; if (cb.settings.iconTheme == 'Custom') { iconDarkBlue = cb.settings.iconThemeDarkBlue; iconLightPurple = cb.settings.iconThemeLightPurple; iconDarkPurple = cb.settings.iconThemeDarkPurple; } else { if (cbjs.arrayContains(themeIconArray.name,cb.settings.iconTheme)) { themeidx = themeIconArray.name.indexOf(cb.settings.iconTheme); iconDarkBlue = themeIconArray.db[themeidx]; iconLightPurple = themeIconArray.lp[themeidx]; iconDarkPurple = themeIconArray.dp[themeidx]; } else { cb.sendNotice('Warning! Invalid Icon Theme setting of ' + cb.settings.iconTheme + '. Defaulting to no icon theme used.', BC, appWarningColor); } } } // *** Load PM Colors if (cb.settings.bcCustomTextColor) { BCpurpleF = checkPMColor(cb.settings.bcCustomTextColor); if (BCpurpleF == 'default') { cb.sendNotice('Error while setting the custom Broadcaster PM text color (setting 21D2). It has to be in a HEX format. Using default value.', BC, appWarningColor); BCpurpleF = '#752d6e'; } } else { BCpurpleF = '#752d6e'; } if (cb.settings.bcCustomBgColor) { BCpurpleB = checkPMColor(cb.settings.bcCustomBgColor); if (BCpurpleB == 'default') { cb.sendNotice('Error while setting the custom Broadcaster PM background color (setting 21D3). It has to be in a HEX format. Using default value.', BC, appWarningColor); BCpurpleB = '#f3e0f1'; } } else { BCpurpleB = '#f3e0f1'; } if (cb.settings.tmCustomTextColor) { TMgreenF = checkPMColor(cb.settings.tmCustomTextColor); if (TMgreenF == 'default') { cb.sendNotice('Error while setting the custom Mod Group PM text color (setting 21D4). It has to be in a HEX format. Using default value.', BC, appWarningColor); TMgreenF = '#007e00'; } } else { TMgreenF = '#007e00'; } if (cb.settings.tmCustomBgColor) { TMgreenB = checkPMColor(cb.settings.tmCustomBgColor); if (TMgreenB == 'default') { cb.sendNotice('Error while setting the custom Mod Group PM background color (setting 21D5). It has to be in a HEX format. Using default value.', BC, appWarningColor); TMgreenB = '#d2f8d2'; } } else { TMgreenB = '#d2f8d2'; } if (cb.settings.tbmCustomTextColor) { TBMblueF = checkPMColor(cb.settings.tbmCustomTextColor); if (TBMblueF == 'default') { cb.sendNotice('Error while setting the custom BC and Mod Group PM text color (setting 21D6). It has to be in a HEX format. Using default value.', BC, appWarningColor); TBMblueF = '#1a1aff'; } } else { TBMblueF = '#1a1aff'; } if (cb.settings.tbmCustomBgColor) { TBMblueB = checkPMColor(cb.settings.tbmCustomBgColor); if (TBMblueB == 'default') { cb.sendNotice('Error while setting the custom BC and Mod Group PM background color (setting 21D7). It has to be in a HEX format. Using default value.', BC, appWarningColor); TBMblueB = '#dff1f3'; } } else { TBMblueB = '#dff1f3'; } if (cb.settings.pmCustomTextColor) { PMaquaF = checkPMColor(cb.settings.pmCustomTextColor); if (PMaquaF == 'default') { cb.sendNotice('Error while setting the custom PM text color (setting 21D8). It has to be in a HEX format. Using default value.', BC, appWarningColor); PMaquaF = '#008181'; } } else { PMaquaF = '#008181'; } if (cb.settings.pmCustomBgColor) { PMaquaB = checkPMColor(cb.settings.pmCustomBgColor); if (PMaquaB == 'default') { cb.sendNotice('Error while setting the custom PM background color (setting 21D9). It has to be in a HEX format. Using default value.', BC, appWarningColor); PMaquaB = '#f2ebd4'; } } else { PMaquaB = '#f2ebd4'; } // *** Miscellaneous fembotStartTime = new Date(); cb.setTimeout(checkPasswordLock, 30000); cb.setTimeout(initFollowerThreshold, 20000); if (cb.settings.autoUpdateSLGL != 'No') { roomSizePrevTotal = 0; cb.setTimeout(roomSizeMonitor, 60000); } populateModeratorArray(BC,'broadcaster','a'); switch (silenceLevel) { case 0: cb.sendNotice('** The Fembot Silence Level is set to "0", all viewers can chat.', BC, appNoticeColor); break; case 1: cb.sendNotice('** The Fembot Silence Level is set to "1", all members with tokens can chat.', BC, appNoticeColor); break; case 2: cb.sendNotice('** The Fembot Silence Level is set to "2", only members who have tipped can chat.', BC, appNoticeColor); break; case 3: minTipToChat = parseInt(cb.settings.minTipToChat); cb.sendNotice('** The Fembot Silence Level is set to "3", only members who have tipped at least ' + minTipToChat + ' tokens can chat.', BC, appNoticeColor); break; case 4: cb.sendNotice('** The Fembot Silence Level is set to "4", only Moderators, Fans, and VIPs can chat.', BC, appNoticeColor); break; } switch (graphicLevel) { case 0: cb.sendNotice('** The Fembot Graphics Level is set to "0", all viewers can post gifs in the chat.', BC, appNoticeColor); break; case 1: cb.sendNotice('** The Fembot Graphics Level is set to "1", all members with tokens can post gifs in the chat.', BC, appNoticeColor); break; case 2: cb.sendNotice('** The Fembot Graphics Level is set to "2", only members who have tipped can post gifs in the chat.', BC, appNoticeColor); break; case 3: minTipToChat = parseInt(cb.settings.minTipToChat); cb.sendNotice('** The Fembot Graphics Level is set to "3", only members who have tipped at least ' + minTipToChat + ' tokens can post gifs in the chat.', BC, appNoticeColor); break; case 4: cb.sendNotice('** The Fembot Graphics Level is set to "4", only Moderators, Fans, and VIPs can post gifs in the chat.', BC, appNoticeColor); break; } initialize = 1; } }
© Copyright Chaturbate 2011- 2024. All Rights Reserved.