Bots Home
|
Create an App
dory bot
Author:
dre
Description
Source Code
Launch Bot
Current Users
Created by:
Dre
/** Name: Dorothy's Ultra Fembot Author: chelsea2950 Created: 11/29/2018 See Change Log on bot description page for revision history **/ //** Enable for ESLINT syntax check, Disable for CB compile //var cb = ''; //var cbjs = ''; var t01brightrainbow = 'linear-gradient(to right, #ff6767, #ffdb9a, #ffff9d, #5fd85f, #9f9fff, #ff9bff)'; var t02pastelrainbow = 'linear-gradient(to right, #ff9a9a, #ffe4b4, #ffffb4, #bfd9bf, #add8e6, #e0d6f4)'; var t03valentines = 'linear-gradient(to right bottom, #ff7373, #ffe1f1)'; var t04christmas = 'linear-gradient(to right bottom, #6bdb6b, #ff9a9a)'; var t05halloween = 'linear-gradient(to right bottom, #ffba67, #ffffb4)'; var t06blue = 'linear-gradient(to right bottom, #a9c4f5, #d4ebf2)'; var t07green = 'linear-gradient(to right bottom, #9fc69f, #cfe3cf)'; var t08pink = 'linear-gradient(to right bottom, #ffb6da, #ffe9ec)'; var t09purple = 'linear-gradient(to right bottom, #c1adea, #dfd5f5)'; var t10blackgray = 'linear-gradient(to right bottom, #c6c6c6, #ececec)'; var t11sunset = 'linear-gradient(to right, #9489c2, #c600fb, #ffa200, #c600fb, #9489c2)'; var t12abv = 'linear-gradient(to right bottom, #00e0ff, #c600fb, #9489c2)'; var t13rwb = 'linear-gradient(to right bottom, #ff0000, #ffffff, #0027c1)'; var t14stpat = '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' ], shortcut: ['brightrainbow', 'pastelrainbow', 'valentines', 'christmas', 'halloween', 'shadesblue', 'shadesgreen', 'shadespink', 'shadespurple', 'blackgray', 'sunset', 'aquablue', 'redwhiteblue', 'stpat' ], colorID: [t01brightrainbow, t02pastelrainbow, t03valentines, t04christmas, t05halloween, t06blue, t07green, t08pink, t09purple, t10blackgray, t11sunset, t12abv, t13rwb, t14stpat ], 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', ':handcuffs_small' ]}; // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var textColorArray = { dispname: ['White/No Color', 'Black', 'Dark Grey', 'Dark Red', 'Dark Orange', 'Dark Green', 'Dark Aqua', 'Dark Blue', 'Dark Purple', 'Dark Pink', 'Custom', 'Dark Gold', 'Dark Teal', 'Dark Brown', 'Dark Bronze', 'Dark Periwinkle', 'Dark Fuschia', 'Dark Lime', 'Dark Plum' ], name: ['white', 'black', 'darkgrey', 'darkred', 'darkorange', 'darkgreen', 'darkaqua', 'darkblue', 'darkpurple', 'darkpink', 'custom', 'darkgold', 'darkteal', 'darkbrown', 'darkbronze', 'darkperiwinkle', 'darkfuschia', 'darklime', 'darkplum' ], colorID: ['#FFFFFF', '#000000', '#737373', '#cc0000', '#e77400', '#006600', '#006767', '#0629AC', '#3d003d', '#ff6680', '#ffffff', '#998100', '#003f1f', '#582c00', '#a56728', '#155bd7', '#d6155c', '#6b790c', '#7f13bf' ]}; // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var bgColorArray = { dispname: ['White/No Color', 'Light Yellow', 'Light Blue', 'Light Pink', 'Light Red', 'Light Green', 'Light Purple', 'Light Orange', 'Light Grey', 'Light Aqua', 'Custom', 'Light Teal', 'Cream', 'Light Bronze', 'Light Periwinkle', 'Light Fuschia', 'Light Lime', 'Light Plum'], name: ['white', 'lightyellow', 'lightblue', 'lightpink', 'lightred', 'lightgreen', 'lightpurple', 'lightorange', 'lightgrey', 'lightaqua', 'custom', 'lightteal', 'cream', 'lightbronze', 'lightperiwinkle', 'lightfuschia', 'lightlime', 'lightplum' ], colorID: ['#FFFFFF', '#ffff94', '#d1eaee', '#FFE6EA', '#ff9a9a', '#94e594', '#f2cdff', '#ffd9b3', '#e6e6e6', '#adeaea', '#000000', '#d7fbee', '#f9f6ed', '#ebccad', '#d7e4fb', '#fbd7e4', '#ecf6a7', '#e3c0f9' ]}; // 1 2 3 4 5 6 7 8 9 10 var diceIconArray = { dispname: ['White on Red', 'Green', 'Blue', 'Gray', 'Green on Blue', 'Blue on Pink', 'Yellow on Red', 'Rainbow', 'Halloween', 'Red White and Blue' ], shortcut: ['whitered', 'green', 'blue', 'gray', 'greenblue', 'bluepink', 'yellowred', 'rainbow', 'halloween', 'redwhiteblue' ], iconabb: ['redwh_', 'green_', 'blue_', 'gray_', 'bluegr_', 'pinkblue_', 'redyel_', 'rnbw_', 'hlwn_', 'redwhbl_' ]}; cb.settings_choices = [ {name: 'dummy0', label: '---------------------------------------------------------------------------------------------------- Latest Updt: Feb 6, 2022 (version 4.6) 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. Please enjoy using the ultrabot and feel free to say hello if you see us around (chelsea2950 or butter_my_toast), or DM us on twitter @thechelsea2950 if you have questions. Thank you! - chelsea & butter', 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......Additional 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}, {name: 'dummytoc23', label: 'Section_22......Guest Broadcasters-------------------------------------------------', type: 'choice',required: false}, // *** General Settings {name: 'dummy01', label: '---------------------------------------------------------------------------------------------------- SECTION 0 - GENERAL SETTINGS & BOT PERSONALIZATION', 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. Color Theme -- 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', 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: themeArray.name[5]}, {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. 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: 'Linear, diagonally'}, {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 controls how the top and bottom border of several of the recurring notices are 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', choice6: 'Custom Emoji Below - Extra Space', 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 /setbrdsep 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}, {name: 'textWrapLength', label: '0J. Set the number of characters at which to wrap a long line of text to the next line. The same setting is used in several places such as the welcome message, notifier, room rules, and media list intro. Default is 80 as that typically fits the width of the border for recurring notices, and must be at least 25 or set to zero to disable automatic line wrapping. Values from 1-24 will default to 25', type: 'int',minValue: 0,maxValue: 120,defaultValue: 76}, {name: 'iconBC', label: '0K. Icon or Emoji to be displayed next to your username in the chat (optional).', type: 'str',required: false}, {name: 'boldText', label: '0L. Display all notices in bold or plain text?', type: 'choice', choice1: 'Bold Text', choice2: 'Plain Text', defaultValue: 'Bold Text'}, // *** 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. Also displays the "Tip Options" notice if enabled here. Note if you are also using Dorothys UltraApp, you should probably only set a welcome message in one of them.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'entryMessage', label: '1C. "Welcome" message -- Note if you are also using Dorothys UltraApp, only set a welcome message in one of them, otherwise users get two messages. 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: 'enableNotifier', label: '1E. Enable Rotating Notifier? -- Up to 10 messages can be displayed in rotation according to the interval specified below. The substitution text {n} can be inserted into a notifier message to force a break to a new line. The {n} must be separated from other text and punctuation by a space.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'notifierMessage1', label: '1F1. Notification Message #1',required: false, type: 'str', minLength: 1, maxLength: 1000, defaultValue: 'Welcome everyone to the show!'}, {name: 'notifierMessage2', label: '1F2. Notification Message #2', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage3', label: '1F3. Notification Message #3', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage4', label: '1F4. Notification Message #4', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage5', label: '1F5. Notification Message #5', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage6', label: '1F6. Notification Message #6', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage7', label: '1F7. Notification Message #7', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage8', label: '1F8. Notification Message #8', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage9', label: '1F9. Notification Message #9', required: false,type: 'str', minLength: 1, maxLength: 1000}, {name: 'notifierMessage10', label: '1F10. Notification Message #10', 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 (such as 1.5 for 1 min 30 sec)',type: 'str',defaultValue: 3.1,required: false}, {name: 'notifiersTextColor', label: '1H. Text color for Rotating Notifier Messages above in 1F1-10, and Chat Notices triggered from commands (/cn, /cnh, /cnd, /cndh)', type: 'choice',choice1: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[6]}, {name: 'notifiersTextCustColor', label: '1J. 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. Background Color for Rotating Notifier Messages above in 1F1-10, and Chat Notices', type: 'choice', choice1: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[9]}, {name: 'notifiersBgCustColor', label: '1L. 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}, {name: 'enableShowSummary', label: '1S1. Enable Recurring Notice of Current Tip Options Summary? -- If enabled, a recurring notice will be shown to the room using the below interval to summarize what tip options are available to participate in the current show (tipmenu, dice, token poll, etc). It will also be displayed to a non-gray user entering the room as well. Note that the room welcome must be enabled in "1B" to display the show summary message on user entry, but the recurring notice is not dependent on the room welcome.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'showSummaryInterval', label: '1S2. Show Summary display interval -- Defined in minutes. Decimals are ok as long as they are greater than 1 (such as 1.5 for 1 min 30 sec)',type: 'str',defaultValue: 4.1,required: false}, // *** 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: 'leaderUniqueTippers', label: '2H2. Display number of unique tippers in the leaderboard?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'leaderInterval', label: '2J. Leaderboard display interval in minutes. Decimals are ok as long as they are greater than 1 (such as 1.5 for 1 min 30 sec)', type: 'str',defaultValue: 3.4,required: false}, {name: 'leaderTextColor', label: '2K. Text color used for Leaderboard', type: 'choice',choice1: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[7]}, {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: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[2]}, {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. Display a recurring notice for the All-Time Tipper leaderboard? Even if not displaying the notice, you can use the /alltime command before you end the bot for each show to display the current all-time list (previous results plus current show totals), save the list, and then paste it into the field below in setting "2R" next time you start the bot. You can also display the All-Time Top 10 leaderboard in the chat on-demand using the command "/top10"', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'allTimeInterval', label: '2Q. All Time Tipper List display interval (in minutes). Decimals are ok as long as they are greater than 1 (such as 1.5 for 1min 30 sec)', type: 'str',defaultValue: 23.2 ,required: false}, {name: 'allTimeTipperList', label: '2R. If tracking all time tippers, enter the list copied from the previous show here (the results from the /alltime command). If typing the results in manually, separate the user name and total tip count with a colon (:), and put commas (,) between the entries. For example "name1:5000, name2:3500, name3:1600".', type: 'str', minLength: 1, maxLength: 99999, 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}, {name: 'allTimeMinThreshold', label: '2T. All-time Minimum Threshold - Only include users who have tipped this minimum amount within a show in the all-time list. Default is 25, but you may want to increase this over time if your list gets too long',type: 'int',minValue: 1,maxValue: 99999,defaultValue: 25}, // *** King Tipper {name: 'dummyking', label: '---------------------------------------------------------------------------------------------------- SECTION 3 - KING TIPPER SETTINGS', type: 'choice',required: false}, {name: 'dummyking0', label: 'The settings in 3A-3K deal with All-time King Tippers (king for total tips and highest single tip can be displayed), the settings in 3L-3P deal with the Current Session King Tipper and highest single tip', 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 (Total Tips) -- 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 in setting "2P" above and list maintainer in "2R" above) 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: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[6]}, {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 (such as 1.5 for 1 min 30 sec)', type: 'str',defaultValue: 6.5,required: false}, {name: 'kingTipperTextColor', label: '3J3. Text color used for King Tipper Recurring Notice', type: 'choice',choice1: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[1]}, {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: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[6]}, {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: 'kingSingleEnable', label: '3K1. Include All-Time Highest Single Tip in Recurring Notice?', type: 'choice', choice1: 'No', choice2: 'Yes, defined below', defaultValue: 'No'}, {name: 'kingSingleTipperName', label: '3K2. All-Time Highest Single Tipper Name -- If setting 3K1 is "Yes, defined below", set the user name here', required: false,type: 'str', minLength: 1, maxLength: 50}, {name: 'kingSingleTipperAmount', label: '3K3. All-Time Highest Single Tip Amount -- If setting 3K1 is "Yes, defined below", set the high tip amount here', type: 'int',minValue: 0,maxValue: 9999999,defaultValue: 0,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: 'kingSessionEnableSingle', label: '3L2. Enable Current Session Highest Single Tip -- Once any viewer tips at least 25, include a line in the recurring notice for Current Show Highest Tip', 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 (such as 1.5 for 1 min 30 sec). Notice will display a reminder 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: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[1]}, {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: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[6]}, {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: 'Gray Users'}, {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: 'restrictChar', label: '4R. Chat character restrictions? -- For users not in the mods, fans, or VIP groups, restrict chat to a subset of available keyboard/unicode/emoji 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. Restricting to the English keyboard only is the most restrictive and will not allow symbols or emojis either.', type: 'choice', choice1: 'No restriction', choice2: 'Allow English keyboard only', choice3: 'Allow English keyboard plus emojis', defaultValue: 'No restriction'}, {name: 'autoUpdateSLGL', label: '4S1. 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: '4S2. 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: '4S3. 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'}, {name: 'letMeKnowList', label: '6D. "Let Me Know" List -- Enter the names of any users for whom you would like to receive a notice when the enter the room. This could be friends you just want to know when they arrive, or users you\'ve had problems with. It is a simple notification when they enter. You can choose in the next setting below who receives the notifications.', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'letMeKnowSendTo', label: '6E. Send "Let Me Know" Notifications to', type: 'choice', choice1: 'Broadcaster Only', choice2: 'Broadcaster and Moderators', choice3: 'Moderators Only', defaultValue: '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, CB Fanclub, external Fanclub 1 & 2 and VIP list. This is the high level control that must be enabled to display any group icons. See settings "7B", "7D", "7F", "8J", "9F", and "9P" to define the icons for each group. 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: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'iconMods', label: '7B. (optional) Icon or Emoji to be displayed for the moderator group of users assigned in CB with red names.', type: 'str',required: false}, {name: 'iconBotMods', label: '7D. (optional) Icon or Emoji to be displayed for the "botmod" moderator group of users that are assigned within the Fembot', type: 'str',required: false}, {name: 'moderatorHighlight', label: '7E. Highlight Moderator Chat? (light red backgroun)', type: 'choice', choice1: 'No', choice2: 'Yes', defaultValue: 'No'}, {name: 'iconFans', label: '7F. (optional) Icon or Emoji to be displayed for the Chaturbate Fanclub group of users with green names', type: 'str',required: false}, {name: 'fanclubHighlight', label: '7G. Highlight CB Fanclub Chat? (light green background)', type: 'choice', choice1: 'No', choice2: 'Yes', defaultValue: 'No'}, {name: 'iconNicknameList', label: '7H. (optional) Create a list for any individal users that you would like to grant special icons, nicknames, or chat text color (will override a user\'s group icon). In the list, 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? You can set to "Do not use" to temporarily disable the ability to "Tip for Icons" without deleting the choices', type: 'choice', choice1: 'Specific Tip Amount', choice2: 'Cumulative Tip Amount', choice3: 'Do not use', defaultValue: 'Do not use'}, {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: 'iconTipNotice', label: '7L1. Display "Tip for Icon" recurring notice? -- Even if notice is disabled, tipping for icons will still work as long as setting "7J" above is enabled.', type: 'choice', choice1: 'No', choice2: 'Yes', defaultValue: 'Yes'}, {name: 'iconTipNoticeInt', label: '7L2. "Tip for Icon" Recurring notice Interval -- Decimals are ok as long as they are greater than 1 (such as 1.5 for 1 min 30 sec)', type: 'str',defaultValue: 4.5,required: false,}, {name: 'dummy4b', label: '*** Icon and Emoji Themes by user tipping level -- 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). ', type: 'choice',required: false}, {name: 'iconTheme', label: '7M. Icon and Emoji Themes -- Select from the existing themes or choose "Custom" to make your own. 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 below, 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',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'iconThemeLightPurple', label: '7N2. Custom icon for light purple users',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'iconThemeDarkPurple', label: '7N3. Custom icon for dark purple users', type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'dummy4c', 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: 'VIPList', label: '8B. VIP List -- Enter the names of any users you would like to grant special VIP privileges (icons, ability to PM and free or discounted ticket shows, etc). List entries are separated by a comma', type: 'str', minLength: 3, maxLength: 99999, defaultValue: '', required: false}, {name: 'VIPname', label: '8C. VIP List Name -- Enter the alternate text to be displayed instead of "VIP List" if you have a personalized one', type: 'str', minLength: 1, maxLength: 50, required: false}, {name: 'announceVIP', label: '8D1. Announce 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: '8D2. Entry announcement text -- The "Next line" feature is enabled with substitution text of {n}', type: 'str',defaultValue: 'Thanks for being a VIP!',required: false}, {name: 'announceVIPTo', label: '8D3. Display enter/exit announcements to', type: 'choice', choice1: 'Everyone', choice2: 'Broadcaster Only', choice3: 'Moderators Only', choice4: 'Moderators and Broadcaster Only', choice5: 'Entering User Only', choice6: 'Mods, Broadcaster, and Entering User Only', defaultValue: 'Moderators and Broadcaster Only'}, {name: 'announceVIPOnce', label: '8D4. Display the enter/exit announcements every time or only the first time?', type: 'choice', choice1: 'Every Time', choice2: 'First Time Only', defaultValue: 'First Time Only'}, {name: 'joinVIPSingleTip', label: '8F. Single Tip for VIP -- Automatically add users to the in-show VIP list if they tip a specific amount during the show. Leave as 0 if not using. You can also add this as an entry in the Tip Menu for visiblity. In-show additions are not permanently added to the VIP list', type: 'int',minValue: 0,maxValue: 99999, defaultValue: 0}, {name: 'joinVIPCumulativeShow', label: '8G. Cumulative Tips for VIP -- Automatically add users to the in-show VIP list if their cumulative tips within the show are above the threshold. Leave as 0 if not using. In-show additions are not permanently added to the VIP list', type: 'int',minValue: 0,maxValue: 99999, defaultValue: 0}, {name: 'joinVIPCumulativeAllTime', label: '8H. All-time Tips for VIP -- If you use the All-time tip tracking (list entered in "2R"), and a user tip total is above this threshold when the bot is launched or the all-time list displayed, they will automatically be added to the VIP List. If not used, leave this as zero.', type: 'int',minValue: 0,maxValue: 99999, defaultValue: 0}, {name: 'iconVIP', label: '8J. Icon or Emoji to be displayed for the VIP group of users', type: 'str',required: false}, {name: 'VIPHighlight', label: '8K. Highlight VIP Chat? -- Default is light blue, can be personalized below', type: 'choice', choice1: 'No', choice2: 'Yes', defaultValue: 'No'}, {name: 'VIPBgCustColor', label: '8L. VIP List Chat Highlight Custom Color -- Define a custom color here using a 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: '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: '9D1. 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: '9D2. Enter 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: 'announceExtFansTo', label: '9D3. Display announcement to?', type: 'choice', choice1: 'Everyone', choice2: 'Broadcaster Only', choice3: 'Moderators Only', choice4: 'Moderators and Broadcaster Only', choice5: 'Entering User Only', choice6: 'Mods, Broadcaster, and Entering User Only', defaultValue: 'Moderators and Broadcaster Only'}, {name: 'announceExtFansOnce', label: '9D4. Display the enter/exit announcements every time or only the first time?', type: 'choice', choice1: 'Every Time', choice2: 'First Time Only', defaultValue: 'First Time Only'}, {name: 'iconExtFans', label: '9F. Choose the personalized Icon or Emoji 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: '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: '9M1. 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: '9M2. 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: 'announceExtFans2To', label: '9M3. Display announcement to?', type: 'choice', choice1: 'Everyone', choice2: 'Broadcaster Only', choice3: 'Moderators Only', choice4: 'Moderators and Broadcaster Only', choice5: 'Entering User Only', choice6: 'Mods, Broadcaster, and Entering User Only', defaultValue: 'Moderators and Broadcaster Only'}, {name: 'announceExtFans2Once', label: '9M4. Display the enter/exit announcements every time or only the first time?', type: 'choice', choice1: 'Every Time', choice2: 'First Time Only', defaultValue: 'First Time Only'}, {name: 'iconExtFans2', label: '9P. Choose the personalized Icon or Emoji 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: 'dummy7a', label: 'There are three types of blocked word lists: Public, Private and Bot blocked. You can create your own Public and Private lists, and the Fembot has it\'s own internal Bot blocked word list to capture non-gray spam bots. It is recommended to use the captcha feature in setting "4J" above to prevent gray spambots rather than a word list. There are settings for each to have the Fembot Auto-silence or Quarantine users for chat messages containing blocked words. Auto-silence gives the same result as the /silence command (and can be reversed with /unsilence). Quarantine adds them to a list that you can review and choose to move to silenced or release, and they can still chat in the meantime. Note that words added to the Public and Private word lists will be converted to all lowercase and checked against the chat messages also converted to lowercase, EXCEPT for words that contain non-ASCII characters, which will not be altered, so they can be checked for an exact match', 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: 'blockedLevelPriv', label: '10C. Private List Blocked 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: 'autoSilencePriv', label: '10D. Private List: Notification, Auto-silence, or Quarantine. For messages containing a blocked word from the private list, the message will be hidden in the general chat for all of these settings', type: 'choice', choice1: 'Notification Only', choice2: 'Auto-silence', choice3: 'Quarantine', defaultValue: 'Notification Only'}, {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 word list is viewable by moderators with appropriate authority. If a word from this list is used, the broadcaster receives a notification, as well as the person who entered the message. Words should be separated by a comma with no spaces. Note: To view the common spambot words in the internal hardcoded list (maintained in the bot, you do not have to add these), type "/botblock" in the chat (no quotes)', type: 'str', minLength: 1, maxLength: 1000, required: false, defaultValue: 'cunt, bitch, slut, c2c, cumslut, whore'}, {name: 'showBlockedMsgsPub', label: '10F. Public List Notification To - Show chat messages to certain groups when a viewer uses blocked words? If you configure for "Swap Word" fill in the setting below with the word to swap, otherwise it will default to behavior for "Display to Broadcaster only"', type: 'choice', choice1: 'Do not display', choice2: 'Display to Broadcaster only', choice3: 'Display to Broadcaster and Moderators', choice4: 'Swap Word', defaultValue: 'Display to Broadcaster and Moderators'}, {name: 'blockedPubSwapWord', label: '10F2. Public List Word Swap - Word to swap with a blocked word?', type: 'str', minLength: 1, maxLength: 25, required: false}, {name: 'blockedLevelPub', label: '10G. Public List Blocked 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'}, {name: 'autoSilencePub', label: '10H. Public List: Notification, Auto-silence, or Quarantin. Note that Quarantine will still show chat messages in general chat, Notification and Auto-silence will hide the message', type: 'choice', choice1: 'Notification Only', choice2: 'Auto-silence', choice3: 'Quarantine', defaultValue: 'Notification Only'}, {name: 'autoSilenceBots', label: '10J. Bot Block List (for Spam Bots): Notification, Auto-silence, or Quarantine. Note that Quarantine will still show chat messages in general chat, Notification and Auto-silence will hide the message', type: 'choice', choice1: 'Notification Only', choice2: 'Auto-silence', choice3: 'Quarantine', defaultValue: 'Auto-silence'}, // *** 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 (such as 1.5 for 1 min 30 sec)',type: 'str',defaultValue: 2.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 gif or emoji of your choosing by selecting "Custom" from the list and entering one in setting 11E2 below, which will override this setting. It is recommended to use emojis rather than gifs to reduce the size of the menu as much as possible', 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: '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',choice1: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[4]}, {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',type: 'choice', choice1: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[0]}, {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',choice1: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[5]}, {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',type: 'choice', choice1: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[0]}, {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: 'No'}, {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: 'If you like the show',label: 'Tip Menu Item 1'}, {name: 'menuitemprice1', type: 'int',minValue: -99999,maxValue: 99999,defaultValue: 3,required: false,label: 'Item 1 price'}, {name: 'menuitem2', type: 'str',required: false,label: 'Tip Menu Item 2'}, {name: 'menuitemprice2', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 2 price'}, {name: 'menuitem3', type: 'str',required: false,label: 'Tip Menu Item 3'}, {name: 'menuitemprice3', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 3 price'}, {name: 'menuitem4', type: 'str',required: false,label: 'Tip Menu Item 4'}, {name: 'menuitemprice4', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 4 price'}, {name: 'menuitem5', type: 'str',required: false,label: 'Tip Menu Item 5'}, {name: 'menuitemprice5', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 5 price'}, {name: 'menuitem6', type: 'str',required: false,label: 'Tip Menu Item 6'}, {name: 'menuitemprice6', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 6 price'}, {name: 'menuitem7', type: 'str',required: false,label: 'Tip Menu Item 7'}, {name: 'menuitemprice7', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 7 price'}, {name: 'menuitem8', type: 'str',required: false,label: 'Tip Menu Item 8'}, {name: 'menuitemprice8', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 8 price'}, {name: 'menuitem9', type: 'str',required: false,label: 'Tip Menu Item 9'}, {name: 'menuitemprice9', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 9 price'}, {name: 'menuitem10', type: 'str',required: false,label: 'Tip Menu Item 10'}, {name: 'menuitemprice10', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 10 price'}, {name: 'menuitem11', type: 'str',required: false,label: 'Tip Menu Item 11'}, {name: 'menuitemprice11', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 11 price'}, {name: 'menuitem12', type: 'str',required: false,label: 'Tip Menu Item 12'}, {name: 'menuitemprice12', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 12 price'}, {name: 'menuitem13', type: 'str',required: false,label: 'Tip Menu Item 13'}, {name: 'menuitemprice13', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 13 price'}, {name: 'menuitem14', type: 'str',required: false,label: 'Tip Menu Item 14'}, {name: 'menuitemprice14', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 14 price'}, {name: 'menuitem15', type: 'str',required: false,label: 'Tip Menu Item 15'}, {name: 'menuitemprice15', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 15 price'}, {name: 'menuitem16', type: 'str',required: false,label: 'Tip Menu Item 16'}, {name: 'menuitemprice16', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 16 price'}, {name: 'menuitem17', type: 'str',required: false,label: 'Tip Menu Item 17'}, {name: 'menuitemprice17', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 17 price'}, {name: 'menuitem18', type: 'str',required: false,label: 'Tip Menu Item 18'}, {name: 'menuitemprice18', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 18 price'}, {name: 'menuitem19', type: 'str',required: false,label: 'Tip Menu Item 19'}, {name: 'menuitemprice19', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 19 price'}, {name: 'menuitem20', type: 'str',required: false,label: 'Tip Menu Item 20'}, {name: 'menuitemprice20', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 20 price'}, {name: 'menuitem21', type: 'str',required: false,label: 'Tip Menu Item 21'}, {name: 'menuitemprice21', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 21 price'}, {name: 'menuitem22', type: 'str',required: false,label: 'Tip Menu Item 22'}, {name: 'menuitemprice22', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 22 price'}, {name: 'menuitem23', type: 'str',required: false,label: 'Tip Menu Item 23'}, {name: 'menuitemprice23', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 23 price'}, {name: 'menuitem24', type: 'str',required: false,label: 'Tip Menu Item 24'}, {name: 'menuitemprice24', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 24 price'}, {name: 'menuitem25', type: 'str',required: false,label: 'Tip Menu Item 25'}, {name: 'menuitemprice25', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 25 price'}, {name: 'menuitem26', type: 'str',required: false,label: 'Tip Menu Item 26'}, {name: 'menuitemprice26', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 26 price'}, {name: 'menuitem27', type: 'str',required: false,label: 'Tip Menu Item 27'}, {name: 'menuitemprice27', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 27 price'}, {name: 'menuitem28', type: 'str',required: false,label: 'Tip Menu Item 28'}, {name: 'menuitemprice28', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 28 price'}, {name: 'menuitem29', type: 'str',required: false,label: 'Tip Menu Item 29'}, {name: 'menuitemprice29', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 29 price'}, {name: 'menuitem30', type: 'str',required: false,label: 'Tip Menu Item 30'}, {name: 'menuitemprice30', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 30 price'}, {name: 'menuitem31', type: 'str',required: false,label: 'Tip Menu Item 31'}, {name: 'menuitemprice31', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 31 price'}, {name: 'menuitem32', type: 'str',required: false,label: 'Tip Menu Item 32'}, {name: 'menuitemprice32', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 32 price'}, {name: 'menuitem33', type: 'str',required: false,label: 'Tip Menu Item 33'}, {name: 'menuitemprice33', type: 'int',minValue: -99999,maxValue: 99999,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,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,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,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,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,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,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,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 - ADDITIONAL (POSITIONS) MENU', type: 'choice',required: false}, {name: 'dummy9a', label: '*** Whereas only one of either Tip Menu 1 or 2 can be displayed at a time, this is an additional menu that can be displayed along with either menu 1 or 2, or by itself. This menu by default is named the "Postions" tip menu as that is a common usage, but the description can be changed to use it for other purposes in setting "12A2". As with the other menus, you can use a negative sign (-) in front of the price to temporarily disable an item on the menu, but leave the description and price value intact to use later.', type: 'choice',required: false}, {name: 'enablePosTipMenu', label: '12A. Enable the Menu at the start of the show? Note you can also turn the menu on and off during the show using the "/useposmenu on" and "/useposmenu off" commands.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'posMenuLiteralDesc', label: '12A2. Menu Description -- Default is "Postions" menu, but can be updated to serve other purposes.', type: 'str',defaultValue: 'Positions',required: false,minLength: 1,maxLength: 25}, {name: 'posMenuInterval', label: '12B. Positions Tip Menu display interval. Decimals are ok as long as they are greater than 1 (such as 1.5 for 1 min 30 sec)', 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 gif or emoji of your choosing by selecting "Custom" from the list and entering one in setting 12D2 below. It is recommended to use emojis to reduce the size of the menu as much as possible', 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',choice1: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[9]}, {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',type: 'choice', choice1: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[3]}, {name: 'posMenuCustBgColor', 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):',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'posMenuItem1', type: 'str',required: false,label: 'Menu Item 1 '}, {name: 'posMenuItemPrice1', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 1 price'}, {name: 'posMenuItem2', type: 'str',required: false,label: 'Menu Item 2'}, {name: 'posMenuItemPrice2', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 2 price'}, {name: 'posMenuItem3', type: 'str',required: false,label: 'Menu Item 3'}, {name: 'posMenuItemPrice3', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 3 price'}, {name: 'posMenuItem4', type: 'str',required: false,label: 'Menu Item 4'}, {name: 'posMenuItemPrice4', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 4 price'}, {name: 'posMenuItem5', type: 'str',required: false,label: 'Menu Item 5'}, {name: 'posMenuItemPrice5', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 5 price'}, {name: 'posMenuItem6', type: 'str',required: false,label: 'Menu Item 6'}, {name: 'posMenuItemPrice6', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 6 price'}, {name: 'posMenuItem7', type: 'str',required: false,label: 'Menu Item 7'}, {name: 'posMenuItemPrice7', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: 'Item 7 price'}, {name: 'posMenuItem8', type: 'str',required: false,label: 'Menu Item 8'}, {name: 'posMenuItemPrice8', type: 'int',minValue: -99999,maxValue: 99999,required: false,label: '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 (such as 1.5 for 1 min 30 sec)', 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: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[5]}, {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: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[5]}, {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: '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: 'Poll option 1',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: 'Poll option 2',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 (or /chgapp ticket) command to turn off the Tip Menu if currently on?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'prepticketDiceOff', label: '14B2. Enable the /prepticket (or /chgapp ticket) command to turn off the Dice Game if currently on?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'prepticketPosMenuOn', label: '14C. Enable the /prepticket (or /chgapp ticket) 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 (or /chgapp ticket) 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 (such as 1.5 for 1 min 30 sec)',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: 'hiddenShowFreeEFC', label: '15M2. Give a free ticket to External Fan Club Members?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'hiddenShowFreeEFC2', label: '15M3. Give a free ticket to External Fan Club 2 Members?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'hiddenShowFreeVIP', label: '15M4. Give a free ticket to members of the VIP List?', 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 (such as 1.5 for 1 min 30 sec). 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: 'lushMenuDispType', label: '16A2. Notice Display Type -- Display the full Lush Menu in the chat at each interval, or only display a single line reminder with the command for users to display it to only themselves. Chat is less cluttered with single line reminder.', type: 'choice', choice1: 'Full Notice', choice2: 'Reminder Only', defaultValue: 'Full Notice'}, {name: 'lushMenuInterval', label: '16B. Toy Tip Menu display interval. Decimals are ok as long as they are greater than 1 (such as 1.5 for 1 min 30 sec)',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', choice7: 'Edge', choice8: 'Quake', defaultValue: 'Lush'}, {name: 'lushMenuTxtColor', label: '16D. Choose your text color for the Toy menu',type: 'choice',choice1: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[9]}, {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: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[3]}, {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: 'mediaListDispType', label: '17A2. Notice Display Type -- Display the full Media List in the chat at each interval, or only display a single line reminder with the command for users to display it to themselves. Chat is less cluttered with single line reminder.', type: 'choice', choice1: 'Full Notice', choice2: 'Reminder Only', defaultValue: 'Full Notice'}, {name: 'mediaListInterval', label: '17B. Media List Notice display interval in minutes. Decimals are ok as long as they are greater than 1 (such as 1.5 for 1 min 30 sec)', 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: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[5]}, {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: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[5]}, {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: 'diceColor', label: '18B2. Dice Colors -- Select the coloring of the dice', type: 'choice', choice1: diceIconArray.dispname[0], choice2: diceIconArray.dispname[1], choice3: diceIconArray.dispname[2], choice4: diceIconArray.dispname[3], choice5: diceIconArray.dispname[4], choice6: diceIconArray.dispname[5], choice7: diceIconArray.dispname[6], choice8: diceIconArray.dispname[7], choice9: diceIconArray.dispname[8], choice10: diceIconArray.dispname[9], defaultValue: diceIconArray.dispname[0]}, {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 Game Notice Interval -- Defined in minutes. Decimals are ok as long as they are greater than 1 (such as 1.5 for 1 min 30 sec)',type: 'str',defaultValue: 3.9,required: false}, {name: 'diceNoticeBgColor', label: '18G. Dice Game Notice Background Color',type: 'choice', choice1: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[8]}, {name: 'diceNoticeBgCustColor', label: '18G2. If you picked a custom background 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: 'diceRollBgColor', label: '18H. Dice Game Roll Results Background Color',type: 'choice', choice1: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[5]}, {name: 'diceRollBgCustColor', label: '18H2. If you picked a custom background 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: 'diceRollBgColorSpecial', label: '18J. Dice Game Special Dice Roll (13) Results Background Color',type: 'choice', choice1: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[9]}, {name: 'diceRollBgCustColorSpecial',label: '18J2. If you picked a custom background 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: '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. The two settings below define if the rules will be shown to every user when they enter the room and/or be displayed in the general chat on a recurring basis. Note that the "Next line" feature can be triggered within a message using the substitution text "{n}"', type: 'choice',required: false}, {name: 'enableRoomRules', label: '19A1. Display Rules at User Entry?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'enableRoomRulesInt', label: '19A2. Display Rules in Recurring Notice?', 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 -- Used if setting "19A2" for recurring notice is enabled. Defined in minutes, decimals are ok as long as they are greater than 1 (such as 1.5 for 1 min 30 sec)',type: 'str',defaultValue: 5.5,required: false}, {name: 'roomRulesTextColor', label: '19D. Room Rules Text Color', type: 'choice',choice1: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[4]}, {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: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[7]}, {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. You can include the text substitution {n} to force a line break in the displayed message', 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 they are greater than 1 (such as 1.5 for 1 min 30 sec)',type: 'str',defaultValue: 4.8,required: false}, {name: 'followTextColor', label: '20H. Follower Response Message Text Color', type: 'choice',choice1: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[7]}, {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: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[5]}, {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: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[7]}, {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: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[5]}, {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 (such as 1.5 for 1 min 30 sec)', 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: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[5]}, {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: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[5]}, {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'}, // *** Guest Info {name: 'dummy22', label: '---------------------------------------------------------------------------------------------------- SECTION 22 - GUEST INFO', type: 'choice',required: false}, {name: 'dummy22a', label: 'This section will allow you to provide info for up to 3 guests in your show. You can specify a comment and up to 3 links for each guest, such as to provide their CB room name, onlyf@ns link, twitter ID, etc. Each user can be enabled and disabled so you can save info for multiple users. Multiple guests can be enabled in each show. When enabled, they will be included in a notice that is posted periodically according to the configured interval. If entering a CB user for the guest, use the "@" prefix so they are tagged in the chat and people can click on the link to go to their page.', type: 'choice',required: false}, {name: 'guestListIntro', label: '22A. Intro -- Enter the text you would like to show as an intro to the guest list (Optional)',required: false, defaultValue: 'We have a guest on the show today!',type: 'str',minLength: 1,maxLength: 255}, {name: 'guestListDispType', label: '22B. Display Type -- Display the full Notice in the chat at each interval, or only display a single line reminder with the command for users to display it to themselves', type: 'choice', choice1: 'Full Notice', choice2: 'Reminder Only', defaultValue: 'Reminder Only'}, {name: 'guestListInterval', label: '22C. Guest Notice interval -- Notice/Reminder recurrence in minutes. Decimals are ok as long as they are greater than 1 (such as 1.5 for 1 min 30 sec)', type: 'str',defaultValue: 1.7,required: false}, {name: 'guestListUsername1', label: '22D1. Guest Name 1',type: 'str',required: false}, {name: 'guestListEnable1', label: '22D2. Enable Guest 1 Notice for this show?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'guestListComment1', label: '22D3. General Comment or Intro for Guest 1',type: 'str',minLength: 0,maxLength: 200,required: false}, {name: 'guestListLink1_1', label: '22D4. Guest 1 Link or ID #1',type: 'str',minLength: 0,maxLength: 200,defaultValue: 'Twitter: @twitterID',required: false}, {name: 'guestListLink2_1', label: '22D5. Guest 1 Link or ID #2',type: 'str',minLength: 0,maxLength: 200,required: false}, {name: 'guestListLink3_1', label: '22D6. Guest 1 Link or ID #3',type: 'str',minLength: 0,maxLength: 200,required: false}, {name: 'guestListUsername2', label: '22E1. Guest Name 2',type: 'str',required: false}, {name: 'guestListEnable2', label: '22E2. Enable Guest 2 Notice for this show?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'guestListComment2', label: '22E3. General Comment or Intro for Guest 2',type: 'str',minLength: 0,maxLength: 200,required: false}, {name: 'guestListLink1_2', label: '22E4. Guest 2 Link or ID #1',type: 'str',minLength: 0,maxLength: 200,required: false}, {name: 'guestListLink2_2', label: '22E5. Guest 2 Link or ID #2',type: 'str',minLength: 0,maxLength: 200,required: false}, {name: 'guestListLink3_2', label: '22E6. Guest 2 Link or ID #3',type: 'str',minLength: 0,maxLength: 200,required: false}, {name: 'guestListUsername3', label: '22F1. Guest Name 3',type: 'str',required: false}, {name: 'guestListEnable3', label: '22F2. Enable Guest 3 Notice for this show?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'guestListComment3', label: '22F3. General Comment or Intro for Guest 3',type: 'str',minLength: 0,maxLength: 200,required: false}, {name: 'guestListLink1_3', label: '22F4. Guest 3 Link or ID #1',type: 'str',minLength: 0,maxLength: 200,required: false}, {name: 'guestListLink2_3', label: '22F5. Guest 3 Link or ID #2',type: 'str',minLength: 0,maxLength: 200,required: false}, {name: 'guestListLink3_3', label: '22F6. Guest 3 Link or ID #3',type: 'str',minLength: 0,maxLength: 200,required: false}, {name: 'guestListTextColor', label: '22G. Choose your text color for the Guest List',type: 'choice',choice1: textColorArray.dispname[0],choice2: textColorArray.dispname[1],choice3: textColorArray.dispname[2],choice4: textColorArray.dispname[3],choice5: textColorArray.dispname[4],choice6: textColorArray.dispname[5],choice7: textColorArray.dispname[6],choice8: textColorArray.dispname[7],choice9: textColorArray.dispname[8],choice10: textColorArray.dispname[9],choice11: textColorArray.dispname[10],choice12: textColorArray.dispname[11],choice13: textColorArray.dispname[12],choice14: textColorArray.dispname[13],choice15: textColorArray.dispname[14],choice16: textColorArray.dispname[15],choice17: textColorArray.dispname[16],choice18: textColorArray.dispname[17],choice19: textColorArray.dispname[18],defaultValue: textColorArray.dispname[5]}, {name: 'guestListCustTextColor', label: '22H. 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: 'guestListBgColor', label: '22J. Choose your background color for the Guest List',type: 'choice', choice1: bgColorArray.dispname[0],choice2: bgColorArray.dispname[1],choice3: bgColorArray.dispname[2],choice4: bgColorArray.dispname[3],choice5: bgColorArray.dispname[4],choice6: bgColorArray.dispname[5],choice7: bgColorArray.dispname[6],choice8: bgColorArray.dispname[7],choice9: bgColorArray.dispname[8],choice10: bgColorArray.dispname[9],choice11: bgColorArray.dispname[10],choice12: bgColorArray.dispname[11],choice13: bgColorArray.dispname[12],choice14: bgColorArray.dispname[13],choice15: bgColorArray.dispname[14],choice16: bgColorArray.dispname[15],choice17: bgColorArray.dispname[16],choice18: bgColorArray.dispname[17],defaultValue: bgColorArray.dispname[5]}, {name: 'guestListCustBgColor', label: '22K. 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} ]; // *********************************** Variables and Arrays ************************************** var initialize = 0; var numPMs = 0; var BC = cb.room_slug; var currentSessionTotal = 0; var wrapMaxLength = cb.settings.textWrapLength; var caps = /[A-Z][A-Z]+/; var checkSpecial = /[!@#$%^&*()+\-=\[\]{};':"\\|,.<>\/?]+/; var checkASCIIChar = /[\u0000-\u007F]+/; var checkEmojiChar = /(\u00a9|\u00ae|[\u2190-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/gi; var ticketEmoji = '\uD83C\uDF9F\uFE0F'; var botName = 'Fembot: '; var borderCharSpacing = ''; var borderChar = cb.settings.separatorEmoji; var modLevel = cb.settings.modLevel; var colorTheme = cb.settings.colorTheme; var silenceLevel = cb.settings.initialSilenceLevel; var graphicLevel = cb.settings.initialGraphicsLevel; var manualSilenceLvlUpd = false; var manualGraphicLvlUpd = false; var showNinjadMsgs = cb.settings.showNinjadMsgs; var showSilencedMsgs = cb.settings.showSilencedMsgs; var minMessagesForNotice = cb.settings.minMessagesForNotice; var suppressCapsToggle = true; var tipnoteWarned = false; var boldTextLiteral = ''; var iconMods = cb.settings.iconMods; var iconBC = cb.settings.iconBC; 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 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 msgCounterTipMenu = 0; var msgCounterPosMenu = 0; var msgCounterLushMenu = 0; var msgCounterDice = 0; var msgCounterNotifier = 0; var msgCounterSummary = 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 msgCounterAllTime = 0; var msgCounterGuest = 0; var notifierToggle = false; var showSummaryToggle = false; var tipMenuToggle = false; var tipMenu2Toggle = false; var posTipMenuToggle = false; var tokenPollToggle = false; var lushMenuToggle = false; var leaderboardToggle = false; var tipCountToggle = false; var groupIconsToggle = false; var backupToggle = false; var mediaToggle = false; var tipLeaderIconsToggle = false; var presalesToggle = false; var diceToggle = false; var grayLockToggle = false; var ticketShowToggle = false; var ticketShowOtToggle = false; var allTimeNoticeToggle = false; var requireAnswerToggle = false; var roomRuleEnterToggle = false; var roomRuleNoticeToggle = false; var textPollToggle = false; var kingSessionToggle = false; var guestToggle = false; var tipResponseFlag = 0; var kingTipperFlag = 0; var leaderBgColor = ''; var leaderTextColor = ''; var noticeBgColor = ''; var noticeTextColor = ''; var roomRulesBgColor = ''; var roomRulesTextColor = ''; var followNoticeBgColor = ''; var followNoticeTextColor = ''; var iconTipNoticeBgColor = ''; var iconTipNoticeTextColor = ''; var kingTipperBgNoticeColor = ''; var kingTipperTextColor = ''; var kingSessionNoticeColor = ''; var kingSessionTextColor = ''; var tokenPollBgColor = ''; var tokenPollTextColor = ''; var odtokenPollBgColor = ''; var odtokenPollTextColor = ''; var textPollBgColor = ''; var textPollTextColor = ''; var mediabackground = ''; var mediaforeground = ''; var diceNoticeBgColor = ''; var diceNoticeTextColor = ''; var diceRollTextColor = ''; var diceRollBgColor = ''; var diceRollBgSpecial = ''; var presalesBgColor = ''; var presalesTxtColor = ''; var ticketNoticesBgColor = ''; var ticketNoticesTxtColor = ''; var ticketBgColor = ''; var ticketTxtColor = ''; var ticketTxtColorFan = ''; var ticketBgColorFan = ''; var ticketTxtColorVIP = ''; var ticketBgColorVIP = ''; var ticketTxtColorMod = ''; var ticketBgColorMod = ''; var allTimeBgColor = ''; var allTimeTextColor = ''; var followTextColor = ''; var followBgColor = ''; var kingTipperBgColor = ''; var tipRespTextColor = ''; var tipRespBgColor = ''; var BCpurpleF = ''; var BCpurpleB = ''; var TMgreenF = ''; var TMgreenB = ''; var TBMblueF = ''; var TBMblueB = ''; var PMaquaF = ''; var PMaquaB = ''; var guestListBgColor = ''; var guestListTextColor = ''; var borderLeaderboardTop = ''; var borderLeaderboardBottom = ''; var borderTipForIconTop = ''; var borderPollTop = ''; var borderPollResultsTop = ''; var borderOdPollTop = ''; var borderTextPollTop = ''; var borderDiceTop = ''; var borderMediaTop = ''; var borderRoomRulesTop = ''; var borderAllTimeTop = ''; var borderToyMenuTop = ''; var borderTmrTop = ''; var borderDiceHistTop = ''; var borderFollowerTop = ''; var borderWelcomeTop = ''; var borderSummaryTop = ''; var borderAllNoticesTop = ''; var borderCurrentKingTop = ''; var borderGuestTop = ''; var borderUniversalBottom = ''; var diceInt = 3.3; var followerInt = 4.8; var iconNoticeInt = 4.5; var kingSessionInt = 5.7; var kingTipperInt = 6.6; var leaderInt = 3.5; var mediaTimerInt = 5.7; var notifierInt = 1.7; var ODpollNoticeInt = 1.5; var pollNoticeInt = 1.5; var presaleNoticeInt = 4.1; var roomRulesInt = 5.5; var textPollNoticeInt = 1.5; var toyMenuDispInt = 2.7; var posMenuDispInt = 3.4; var tipMenu2DispInt = 2.9; var tipMenuDispInt = 2.9; var ticketNoticeInt = 2.1; var showSummaryInt = 4.2; var allTimeInt = 23.2; var guestListInt = 1.7; 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 ftaIndex = 0; var nextFollowerThreshold = 0; var displaySeconds = false; var displaySeconds2 = false; var displaySeconds3 = false; var displaySeconds4 = false; var pollDisplaySeconds = false; var odpollDisplaySeconds = false; var textPollDisplaySeconds = false; var clockStopping = false; var clock2Stopping = false; var clock3Stopping = false; var clock4Stopping = false; var pollTimerStopping = false; var odpollTimerStopping = false; var textPollTimerStopping = false; var whichToy = cb.settings.whichToy; var whichToyIcon = ''; var currentKingTipperAmount = 0; var currentKingTipper = ''; var currentKingTipperAmountSingle = 0; var currentKingTipperSingle = ''; var kingTipperName = ''; var kingTipperAmount = 0; var kingSingleTipperAmount = cb.settings.kingSingleTipperAmount; var kingSingleTipperName = cb.settings.kingSingleTipperName; 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 presaleIncrements = 0; var stopIncrement = false; var presaleTimeAmt = cb.settings.presaleTimedIncrement; var presaleIncAmt = cb.settings.presaleIncreasePerIncrement; var presaleCountAmt = cb.settings.presaleCountIncrement; var presaleTicketsLeft = 0; var presaleSeconds = 0; 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 ticketPriceEFC2 = cb.settings.hiddenShowPriceEFC2; 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 ticketSkipNotice = false; var ticketSkipMin = false; var ticketSkipSec = false; var showStage = ''; var countTicketsSold = 0; var ticketTimeAmt = cb.settings.hiddenShowStartTimer; var ticketShowGoalTokens = cb.settings.hiddenShowGoal; var ticketShowGoalTickets = cb.settings.hiddenShowGoal; var hiddenShowModsAdd = (cb.settings.hiddenShowModsAdd === 'Yes'); var ticketSeconds = 0; var hiddenTime = 0; var notifierMessage1 = cb.settings.notifierMessage1; var notifierMessage2 = cb.settings.notifierMessage2; var notifierMessage3 = cb.settings.notifierMessage3; var notifierMessage4 = cb.settings.notifierMessage4; var notifierMessage5 = cb.settings.notifierMessage5; var notifierMessage6 = cb.settings.notifierMessage6; var notifierMessage7 = cb.settings.notifierMessage7; var notifierMessage8 = cb.settings.notifierMessage8; var notifierMessage9 = cb.settings.notifierMessage9; var notifierMessage10 = cb.settings.notifierMessage10; var notifierRotateCount = 0; var notifierTotalCount = 0; 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 appErrorColor = '#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 = 'linear-gradient(to bottom, #ffffff 20%, #cdf2ff 100%)'; var moderatorBgColor = '#ffe7e7'; // Light red highlighting for moderators var fanclubBgColor = '#e6f9e6'; // Light green highlighting for CB Fanclub var tipnoteyellow = '#ffff00'; // Forwarded Tip notes var commandBgColor = 'linear-gradient(to left, #ffffff 20%, #cfcfcf 100%)'; 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 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 allTimeMinThreshold = cb.settings.allTimeMinThreshold; 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 pmRequestTime = 0; var prvRequestTime = 0; var auto1RequestTime = 0; var auto2RequestTime = 0; var auto3RequestTime = 0; 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 menu2ListSplit = true; var noticeOnlyBC = botName + ' Only broadcasters are able to use that command.'; var noticeOnlyBCMod1 = botName + ' Only broadcasters and moderators are able to use that command.'; var noticeOnlyBCMod2 = botName + ' Only broadcasters and "Standard/Advanced" moderator levels are able to use that command.'; var noticeOnlyBCMod3 = botName + ' Only broadcasters and the "Advanced" moderator level are able to use that command.'; var noticeOnlyBCMod3A = botName + ' 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; var tipMenuSepChar = '| '; var tipMenuDisplayText = ''; var tipMenuToken = 1; var tipMenuTextColor1 = ''; var tipMenuBgColor1 = ''; var tipMenuTextColor2 = ''; var tipMenuBgColor2 = ''; var tipMenuTextColorTip = ''; var tipMenuBgColorTip = ''; var tipMenuLength = 0; var tipMenu2SepChar = '| '; var tipMenu2DisplayText = ''; var tipMenu2Token = 1; var tipMenu2TextColor1 = ''; var tipMenu2BgColor1 = ''; var tipMenu2TextColor2 = ''; var tipMenu2BgColor2 = ''; var tipMenu2TextColorTip = ''; var tipMenu2BgColorTip = ''; var tipMenu2Length = 0; var tipMenuModDisplayText = ''; var tipMenuModLength = 0; var tipMenuCBFCDisplayText = ''; var tipMenuCBFCLength = 0; var tipMenuEFC1DisplayText = ''; var tipMenuEFC1Length = 0; var tipMenuEFC2DisplayText = ''; var tipMenuEFC2Length = 0; var tipMenuVIPDisplayText = ''; var tipMenuVIPLength = 0; var posMenuSepChar = '| '; var posMenuDisplayText = ''; var posMenuToken = 1; var posMenuTextColor = ''; var posMenuBgColor = ''; var posMenuLength = 0; var toyMenuDisplayText = ''; var toyMenuTextColor = ''; var toyMenuBgColor = ''; var sendPMResponse = false; var sendPvtResponse = false; 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 pollMinimum = cb.settings.pollMinimum; var totalPollVotes = 0; var pollTitle = cb.settings.pollTitle; var odpollType; var odpollModAdd = 'Yes'; var odpollMinsRemain = 0; var odpollSecsRemain = 0; var onDemandPollRunning = false; var onDemandPollEnabled = false; var odpollTitle = 'Poll Topic'; var tempODPollLabels = []; var tempODPollAmounts = []; var odpollArrayAmount = []; var odpollArrayLabel = []; var odpollArrayVotes = []; var nlineOD = 0; var odpollStartTime; var odpollStopTime; 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 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 textPollTotalVotes = 0; var textPollTitle = cb.settings.textPollTitle; var textPollReminderToken = 0; var diceRollPrice = cb.settings.diceRollPrice; var dicePlural = (diceRollPrice > 1) ? 'tokens' : 'token'; var diceMultiRolls = cb.settings.diceMultiRolls; var diceRollCounter = 0; var diceRollCounterSpecial = 0; var diceWinners = []; var dicePrizes = []; var diceMinSpecial = parseInt(cb.settings.diceMinSpecial); var diceGifPfx = ':dorothydice_'; var diceColorShortcut = 'redwh_'; var diceRarePct = 20; var showBlockedMsgsPub = cb.settings.showBlockedMsgsPub; var guestListUsername1 = cb.settings.guestListUsername1; var guestListEnable1 = cb.settings.guestListEnable1; var guestListComment1 = cb.settings.guestListComment1; var guestListLink1_1 = cb.settings.guestListLink1_1; var guestListLink2_1 = cb.settings.guestListLink2_1; var guestListLink3_1 = cb.settings.guestListLink3_1; var guestListUsername2 = cb.settings.guestListUsername2; var guestListEnable2 = cb.settings.guestListEnable2; var guestListComment2 = cb.settings.guestListComment2; var guestListLink1_2 = cb.settings.guestListLink1_2; var guestListLink2_2 = cb.settings.guestListLink2_2; var guestListLink3_2 = cb.settings.guestListLink3_2; var guestListUsername3 = cb.settings.guestListUsername3; var guestListEnable3 = cb.settings.guestListEnable3; var guestListComment3 = cb.settings.guestListComment3; var guestListLink1_3 = cb.settings.guestListLink1_3; var guestListLink2_3 = cb.settings.guestListLink2_3; var guestListLink3_3 = cb.settings.guestListLink3_3; // ***************************Arrays var niceListArray = []; var silenceListArray = []; var quarantineArray = []; var silencePrefixList = []; var ninjaListArray = []; var VIPListArray = []; var VIPInShowArray = []; var extFanListArray = []; var extFanInShowArray = []; var extFanList2Array = []; var extFanInShow2Array = []; var notifierArray = []; var wordListArray = []; var wordListArrayPub = []; var pmArray = []; var backupListArray = []; var presaleArray = []; var grayLockList = []; var answerLockList = []; var answerLockStatus = []; var answerLockQuestion = []; var answerLockAnswer = []; 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 allTimeArrayLoad = {name: [], totaltips: []}; var ticketShowExtraTickets = {name: [], count: []}; var roomRulesArray = []; var iconTipAmountArray = []; var iconTipIconArray = []; var tipForIconArray = {name: [], icon: []}; var viewerNotesArray = {username: [], notes: [], displayed: [], addinshow: []}; var tipMenuRequests = {name: [], amt: [], desc: []}; var tipMenuRequestTime = []; var tmrInquiries = {name: [], time: []}; var textPollArray = {dispname: [], voteID: [], votes: []}; var textPollUsersVoted = []; 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,350000,400000,450000,500000,550000,600000,650000,700000,750000,800000,850000,900000,950000,1000000,5000000,10000000,100000000]; var letMeKnowListArray = []; var noticeIntervals = {name: [], fieldname: [], interval: [], settingID: []}; var newFollowers = []; var tipMenuPriceArray = []; var tipMenuItemArray = []; var tipMenuPartArray = []; var tipMenu2PriceArray = []; var tipMenu2ItemArray = []; var tipMenu2PartArray = []; var tipMenuModPriceArray = []; var tipMenuModItemArray = []; var tipMenuCBFCPriceArray = []; var tipMenuCBFCItemArray = []; var tipMenuEFC1PriceArray = []; var tipMenuEFC1ItemArray = []; var tipMenuEFC2PriceArray = []; var tipMenuEFC2ItemArray = []; var tipMenuVIPPriceArray = []; var tipMenuVIPItemArray = []; var posMenuPriceArray = []; var posMenuItemArray = []; var posMenuPartArray = []; var posMenuRequestersArray = []; var posMenuRequestsArray = []; var posMenuRequestsArrayTime = []; var toyMenuLevelArray = []; var textPollNotice = []; var botLoadErrors = []; var messageReceiptArray = []; var announcedEnterV = []; var announcedExitV = []; var announcedEnterE1 = []; var announcedExitE1 = []; var announcedEnterE2 = []; var announcedExitE2 = []; var botBlockList = ['tokencb.com', 'nearsluts.com', 'https://tokencb.com/', 'cb-tokens.com', 'sex24x.com', 'tokensxxx.com', 'camsero.com', 'sex18xx.com', 'cams18x.com', 'bonustk.com', 'cams24x.com', '18tokens.com', 'tokens20.com']; var botGrayBlockList = ['\uD835\uDDA4\uD835\uDDB2\uD835\uDDA2\uD835\uDDAE\uD835\uDDB1\uD835\uDDB3', 'cumsho\uD835\uDE38.m\uD835\uDE26', 'c2cse\uD835\uDC65.live', 'sn\u0430\u0440\u0441h\u0430t:', 'c2cse\uD835\uDC65.live', 'assplay.\uD835\uDC5Cnlin\uD835\uDC52', 'dadd\uD835\uDEA2ssgirl.c\uD835\uDE30m', '\uD835\uDE39t\uD835\uDE26as\uD835\uDE26.cam', 'sla\uD835\uDE9F\uD835\uDC52.chat', 'pvt.\uD835\uDC64atch', 'asspla\uD835\uDDD2.online', 'prvt.\uD835\uDC60how', 'daddysgi\uD835\uDC5F\uD835\uDDC5.\uD835\uDDC5ive']; var exemptDorothyCmdList = ['/paneltext1', '/paneltext2', '/paneltext3', '/chscoreboard', '/chs', '/chfixscore', '/chlength', '/chclearlist', '/chskip', '/chwin', '/chend', '/chstoptimer', '/chfree', '/chword', '/chrmv', '/chsave', '/chprice', '/chplay', '/chh', '/chq', '/chlist', '/chi', '/charades', '/tq', '/tqi', '/tqh', '/tqa', '/tword', '/tprize', '/twenty', '/twentyprice', '/twentywin', '/twentyend', '/twentymode', '/twentyquestions', '/randomfree', '/random', '/ri', '/rw', '/badfree', '/badlibs', '/bli', '/blc', '/badprice', '/blw', '/addwho', '/addwhat', '/addwhere', '/addhowlong', '/uapresale', '/uapresales', '/backup', '/setracetext', '/setracepaneltext', '/restartrace', '/setrace1', '/setrace2', '/addrace1', '/addrace2', '/tipnoteon', '/tipnoteoff', '/ki', '/gbhelp', '/whs', '/rri', '/whi', '/di', '/pt', '/gbstats', '/wi', '/wf', '/warfree', '/pi', '/pf', '/pressfree', '/pw', '/presswinners', '/ww', '/warwinners', '/cpd', '/chgprizedesc', '/addprize', '/cpp', '/changeprizeprice', '/mpl', '/masterprizelist', '/ap', '/pq', '/pressq', '/pressqueue', '/stoppress', '/press', '/pp', '/pressprizes', '/war', '/waragain', '/stopwar', '/warprizes', '/wl', '/warlist', '/wd', '/wardraw', '/wp', '/kb', '/freekeno', '/wargame', '/keno', '/kp', '/kpa', '/kpw', '/kpwa', '/kpbc', '/rrprice', '/chambers', '/rrp', '/rr', '/rrs', '/shooters', '/wheelspins', '/wheelprice', '/freespin', '/freeroll', '/wheel', '/wheelprizes', '/dice', '/diceprizes', '/diceprice', '/msaddfan', '/msrmvfan', '/msfanlist', '/mschgdft', '/mschguser', '/resetapp', '/chgpanelbg', '/paneltextcolor', '/check', '/pass', '/plist', '/plistw', '/email', '/newshow', '/faster', '/slower', '/next', '/skip', '/listgoals', '/lg', '/listremgoals', '/lrg', '/chgendseq', '/addtips', '/restartgoal', '/setgoaltext', '/chgcountgoal', '/setcounttext', '/usechatmsg', '/setseqtext', '/usegrouptips', '/setjartext', '/rmvgoal', '/rmvcount', '/rmvseq', '/rmvjar', '/skiplevel', '/stats', '/spanked', '/spankall', '/spanktotals', '/spanktips', '/spankmenu', '/setspanktext', '/rmvspankgoal', '/peeplength', '/peepstarttimer', '/peeptimer', '/peepaddtime', '/peepstoptimer', '/peepadduser', '/peeprmv', '/peeptimeleft', '/mytime', '/peepsubject', '/peeprestart', '/pp', '/peepprice', '/pv', '/peepviewers', '/pb', '/peepbuyers', '/startpresale', '/stoppresale', '/startmenu', '/stopmenu', '/startmenu2', '/stopmenu2', '/menu', '/menurequests', '/menuadd', '/menurmv', '/startposmenu', '/stopposmenu', '/setautogoal', '/setautofinal', '/setautotext', '/uahelp', '/tickethelp', '/menuhelp', '/setgentext', '/gentextposn', '/pause', '/resume', '/ninjatip', '/ninjatipon', '/ninjatipoff', '/raffle', '/entries', '/previousentries', '/resetraffle', '/addraffletkt1', '/addraffletkt2', '/addraffletkt3', '/addraffletkt4', '/addraffletkt5', '/rmvraffletkt', '/raffleprizes', '/setraffleprice', '/raffledrawing', '/rafflestarttimer', '/raffleaddtime', '/rafflestoptimer', '/raffletimeleft', '/chgrafflemode', '/addraffleprize', '/rmvraffleprize', '/startpoll', '/newpass', '/mypass', '/seepass', '/pwsettings', '/passlist', '/passnow', '/passhelp', '/passto', '/bjfree', '/bjgame', '/blackjack', '/bji', '/hit', '/stay', '/bjg', '/goal', '/previewers', '/ffj1', 'ffj2', '/ffjoin1', '/ffjoin2', '/ffplay', '/ffq', '/ffa1', '/ffa2', '/ffa3', '/ffa4', '/ffa5', '/ffa6', '/ffa7', '/ffa8'] // ****************** Prototypes String.prototype.capitalize = function() {return this.charAt(0).toUpperCase() + this.slice(1);} // *********************************** Initialize ************************************** if (initialize == 0) { cb.sendNotice(':DorothysUltraFembot v4.6'); let intromessage = '\u26D4 Version 4.6 was released on Feb 6, 2022 \u26D4'; intromessage += '\n \u2705 Dorothy\'s Ultra Fembot was written by CB users chelsea2950 and butter_my_toast.'; intromessage += '\n \u2705 ' + wordWrap('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 ' + wordWrap('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 ' + wordWrap('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, appErrorColor); loadNoticeIntervals(); loadAllStaticColors(BC); if (colorTheme == 'None') { loadAllFeatureColors(BC,true); } else { loadThemeColors(BC,true); } if (cb.settings.boldText == 'Bold Text') { boldTextLiteral = 'bold'; } var maxNotifierMsgLength = 0; for (let i = 0; i < 10; i++) { if (this['notifierMessage'+(i+1)]) { notifierArray.push(this['notifierMessage'+(i+1)]); let thismsgl = this['notifierMessage'+(i+1)].length; if (thismsgl > maxNotifierMsgLength) { maxNotifierMsgLength = thismsgl; } } } noticeBorderChar(); var borderTicketTop = new Array(37).join('-') + ' ' + ticketEmoji + ' TICKET SHOW ' + ticketEmoji + ' ' + new Array(38).join('-'); var borderTicketBottom = '\n' + new Array(49).join('-') + ' \u25CF ' + new Array(49).join('-'); var borderPresaleTop = new Array(40).join('-') + ' ' + ticketEmoji + ' PRE-SALES ' + ticketEmoji + ' ' + new Array(40).join('-'); var borderPresaleBottom = '\n' + new Array(49).join('-') + ' \u25CF ' + new Array(49).join('-'); var borderTicketTopShort = new Array(26).join('-') + ' ' + ticketEmoji + ' TICKET SHOW ' + ticketEmoji + ' ' + new Array(26).join('-'); var borderTicketBottomShort = '\n' + new Array(49).join('-') + ' \u25CF ' + new Array(49).join('-'); // *** Tip Note Forwarding if (cb.settings.tipNoteForwardID) { if (cb.settings.tipNoteForwardID == '*ALLMODS') { if (modLevel != 'Advanced') { botLoadErrors.push('WARNING: You have configured "*ALLMODS" for Tip Note forwarding, but the mod level is not set to "Advanced". Therefore, forwarding is disabled.'); } tipNoteForwardID = '*ALLMODS'; } else { tipNoteForwardID = cb.settings.tipNoteForwardID.toLowerCase(); } } var EFCname = 'External Fan Club'; if (cb.settings.EFCname) { EFCname = cb.settings.EFCname; } var EFCname2 = 'External Fan Club 2'; if (cb.settings.EFCname2) { EFCname2 = cb.settings.EFCname2; } var VIPname = 'VIP List'; if (cb.settings.VIPname) { VIPname = cb.settings.VIPname; } var bcText = 'The Broadcaster'; if (cb.settings.bctext) { bcText = cb.settings.bctext; } var efcBgColor = '#e6f9e6'; if (cb.settings.efcBgCustColor) { let tempefcbgcust = setBgColor(cb.settings.efcBgCustColor,'Default External Fan Club Background',BC,true); if (tempefcbgcust == 'default') { botLoadErrors.push('External Fan Club 1 Highlight Color Error, it must be in a HEX format, such as "#e6f9e6". Using default light green highlight color.'); } else { efcBgColor = tempefcbgcust; } } var efcBgColor2 = '#e6f9e6'; if (cb.settings.efcBgCustColor2) { let tempefc2bgcust = setBgColor(cb.settings.efcBgCustColor2,'Default External Fan Club 2 Background',BC,true); if (tempefc2bgcust == 'default') { botLoadErrors.push('External Fan Club 2 Highlight Color Error, it must be in a HEX format, such as "#e6f9e6". Using default light green highlight color.'); } else { efcBgColor2 = tempefc2bgcust; } } var vipBgColor = '#faebf7'; if (cb.settings.VIPBgCustColor) { let tempvipbgcust = setBgColor(cb.settings.VIPBgCustColor,'Default VIP Background',BC,true); if (tempvipbgcust == 'default') { botLoadErrors.push('VIP List Highlight Color Error, it must be in a HEX format, such as "#faebf7". Using default light purple highlight color.'); } else { vipBgColor = tempvipbgcust; } } // *** Init Features using toggle functions if (cb.settings.enableGroupIcons == 'Yes') { groupIconsToggle = true; } if (cb.settings.enableTipLeaderIcons == 'Yes') { tipLeaderIconsToggle = true; } if (cb.settings.enableLeaderboard == 'Yes') { setLeaderToggle('on',BC,false); } if (cb.settings.enableNotifier == 'Yes') { setNotifierToggle('on',BC,false); } if (cb.settings.enableShowSummary == 'Yes') { setShowSummaryToggle('on',BC,false); } if (cb.settings.enableTipCount == 'Yes') { setTipCountToggle('on',BC,false); } if (cb.settings.enableDiceGame == 'Yes') { setDiceToggle('on','init'); } if (cb.settings.enableTipMenu == 'Yes') { setTipMenuToggle('on','init'); if (cb.settings.enableTipMenu2 == 'Yes') { botLoadErrors.push('Unable to start Tip Menu 2, since Tip Menu 1 is already enabled. To switch to Tip Menu 2, use the command "/swapmenu".'); } } if (cb.settings.enableTipMenu2 == 'Yes' && cb.settings.enableTipMenu == 'No') { setTipMenu2Toggle('on','init'); } var posMenuLiteralDesc = cb.settings.posMenuLiteralDesc; if (!posMenuLiteralDesc) { posMenuLiteralDesc = 'Positions'; } if (cb.settings.enablePosTipMenu == 'Yes') { setPosTipMenuToggle('on','init'); } buildPollBoard(BC); if (cb.settings.enableTokenPoll == 'Yes') { setTokenPollToggle('on','init'); } if (cb.settings.textPollEnable == 'Yes') { setTextPollToggle('on',BC); } if (cb.settings.enableLushMenu == 'Yes') { whichToy = cb.settings.whichToy; whichToyIcon = ':' + whichToy.toLowerCase() + 'sm'; if (whichToy == 'Domi') { whichToyIcon = ':domi-small-transparent'; } setToyMenuToggle('on',BC); } if (cb.settings.enableMediaNotice == 'Yes') { setMediaToggle('on',BC,false); } if (cb.settings.guestListEnable1 == 'Yes' || cb.settings.guestListEnable2 == 'Yes' || cb.settings.guestListEnable3 == 'Yes') { setGuestToggle('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 (roomRulesArray.length > 0) { if (cb.settings.enableRoomRulesInt == 'Yes') { setRoomRulesNoticeToggle('on',BC,false); } if (cb.settings.enableRoomRules == 'Yes') { setRoomRulesEnterToggle('on',BC,false); } } if (showBlockedMsgsPub == 'Swap Word' && !cb.settings.blockedPubSwapWord) { showBlockedMsgsPub = 'Display to Broadcaster only'; botLoadErrors.push('Configured for "Swap Word" on Public Blocked Word List, but no Word specified in setting "10F2". Defaulting to Notify Broadcaster Only.'); } initFollowers(); for (let itnidx = 0; itnidx < 5; itnidx++) { if (this['iconTipAmount'+(itnidx+1)] && this['iconTipIcon'+(itnidx+1)]) { iconTipAmountArray.push(this['iconTipAmount'+(itnidx+1)]); iconTipIconArray.push(this['iconTipIcon'+(itnidx+1)]); let itnpriceused = 'iconTipAmount'+(itnidx+1); priceChecker('add','Tip for Icon #' + (itnidx+1),itnpriceused,'init'); } } var iconTipNoticeToggle = false; if (iconTipAmountArray.length > 0 && tipForIconType != 'Do not use' && cb.settings.iconTipNotice == 'Yes') { setIconTipNoticeToggle('on',BC); } // *** Init User Lists if (cb.settings.niceList) { let niceary = cb.settings.niceList.toLowerCase(); let tempnicearray = niceary.split(','); let initnicetoadd = ''; for (let niceloadidx = 0; niceloadidx < tempnicearray.length; niceloadidx++) { initnicetoadd = tempnicearray[niceloadidx].trim(); if (validateUserID(initnicetoadd,'Nice List',BC,true)) { if (cbjs.arrayContains(niceListArray, initnicetoadd)) { botLoadErrors.push('Skipping duplicate entry for user "' + initnicetoadd + '" in the Nice List.'); } else { niceListArray.push(initnicetoadd); } } } } if (cb.settings.silenceList) { let silenceary = cb.settings.silenceList.toLowerCase(); let tempsilencearray = silenceary.split(','); let initsiltoadd = ''; for (let silloadidx = 0; silloadidx < tempsilencearray.length; silloadidx++) { initsiltoadd = tempsilencearray[silloadidx].trim(); if (validateUserID(initsiltoadd,'Silence List',BC,true)) { if (cbjs.arrayContains(silenceListArray, initsiltoadd)) { botLoadErrors.push('Skipping duplicate entry for user "' + initsiltoadd + '" in the Silence List.'); } else { silenceListArray.push(initsiltoadd); } } } } if (cb.settings.letMeKnowList) { let lmkary = cb.settings.letMeKnowList.toLowerCase(); let templmkarray = lmkary.split(','); let initlmktoadd = ''; for (let lmkloadidx = 0; lmkloadidx < templmkarray.length; lmkloadidx++) { initlmktoadd = templmkarray[lmkloadidx].trim(); if (validateUserID(initlmktoadd,'"Let Me Know" List',BC,true)) { if (cbjs.arrayContains(letMeKnowListArray, initlmktoadd)) { botLoadErrors.push('Skipping duplicate entry for user "' + initlmktoadd + '" in the "Let me Know" List.'); } else { letMeKnowListArray.push(initlmktoadd); } } } } if (cb.settings.ninjaList) { let ninjaary = cb.settings.ninjaList.toLowerCase(); let tempninjaarray = ninjaary.split(','); let initninjatoadd = ''; for (let ninjaloadidx = 0; ninjaloadidx < tempninjaarray.length; ninjaloadidx++) { initninjatoadd = tempninjaarray[ninjaloadidx].trim(); if (validateUserID(initninjatoadd,'Ninja List',BC,true)) { if (cbjs.arrayContains(ninjaListArray, initninjatoadd)) { botLoadErrors.push('Skipping duplicate entry for user "' + initninjatoadd + '" in the Ninja List.'); } else { ninjaListArray.push(initninjatoadd); } } } } if (cb.settings.extFanList) { let efc1ary = cb.settings.extFanList.toLowerCase(); let tempefc1array = efc1ary.split(','); let initefc1toadd = ''; for (let efc1loadidx = 0; efc1loadidx < tempefc1array.length; efc1loadidx++) { initefc1toadd = tempefc1array[efc1loadidx].trim(); if (validateUserID(initefc1toadd,'External Fan Club 1 List',BC,true)) { if (cbjs.arrayContains(extFanListArray, initefc1toadd)) { botLoadErrors.push('Skipping duplicate entry for user "' + initefc1toadd + '" in the External Fan Club 1 List.'); } else { extFanListArray.push(initefc1toadd); } } } } if (cb.settings.extFanList2) { let efc2ary = cb.settings.extFanList2.toLowerCase(); let tempefc2array = efc2ary.split(','); let initefc2toadd = ''; for (let efc2loadidx = 0; efc2loadidx < tempefc2array.length; efc2loadidx++) { initefc2toadd = tempefc2array[efc2loadidx].trim(); if (validateUserID(initefc2toadd,'External Fan Club 2 List',BC,true)) { if (cbjs.arrayContains(extFanList2Array, initefc2toadd)) { botLoadErrors.push('Skipping duplicate entry for user "' + initefc2toadd + '" in the External Fan Club 2 List.'); } else { extFanList2Array.push(initefc2toadd); } } } } if (cb.settings.VIPList) { let vipary = cb.settings.VIPList.toLowerCase(); let tempviparray = vipary.split(','); let initviptoadd = ''; for (let viploadidx = 0; viploadidx < tempviparray.length; viploadidx++) { initviptoadd = tempviparray[viploadidx].trim(); if (validateUserID(initviptoadd,'VIP List',BC,true)) { if (cbjs.arrayContains(VIPListArray, initviptoadd)) { botLoadErrors.push('Skipping duplicate entry for user "' + initviptoadd + '" in the VIP List.'); } else { VIPListArray.push(initviptoadd); } } } } if (cb.settings.hiddenShowOTList) { let otary = cb.settings.hiddenShowOTList.toLowerCase(); let tempotarray = otary.split(','); let initottoadd = ''; for (let otloadidx = 0; otloadidx < tempotarray.length; otloadidx++) { initottoadd = tempotarray[otloadidx].trim(); if (validateUserID(initottoadd,'Outstanding Ticket List',BC,true)) { if (cbjs.arrayContains(outstandingTicketArray, initottoadd)) { botLoadErrors.push('Skipping duplicate entry for user "' + initottoadd + '" in the Outstanding Ticket List.'); } else { outstandingTicketArray.push(initottoadd); } } } } if (cb.settings.botModList) { let modlistary = cb.settings.botModList.toLowerCase(); let tempbotmodarray = modlistary.split(','); let initmodtoadd = ''; for (let modloadidx = 0; modloadidx < tempbotmodarray.length; modloadidx++) { initmodtoadd = tempbotmodarray[modloadidx].trim(); if (validateUserID(initmodtoadd,'Bot Moderator',BC,true)) { if (cbjs.arrayContains(moderatorList.name, initmodtoadd)) { botLoadErrors.push('Skipping duplicate entry for user "' + initmodtoadd + '" in the Bot Mod List.'); } else { populateModeratorArray(initmodtoadd,'botmod','a'); } } } } if (cb.settings.allTimeTipperList) { let tempalltimelist = cb.settings.allTimeTipperList; let tempalltimearray = tempalltimelist.split(','); if (tempalltimearray.length > 0) { for (let ataidx = 0; ataidx < tempalltimearray.length; ataidx++) { let nameamtary = tempalltimearray[ataidx].trim().split(':'); if (!nameamtary[0]) { botLoadErrors.push('Cannot load all-time tipper list entry "' + tempalltimearray[ataidx] + '", name is missing.'); } else if (nameamtary[0].length < 3 || nameamtary[0].includes(' ')) { botLoadErrors.push('Cannot load all-time tipper list entry "' + tempalltimearray[ataidx] + '", name contains a blank or is less than 3 characters.'); } else if (checkSpecial.test(nameamtary[0])) { botLoadErrors.push('Cannot load all-time tipper list entry "' + tempalltimearray[ataidx] + '", name contains special characters.'); } else if (!nameamtary[1]) { botLoadErrors.push('Cannot load all-time tipper list entry "' + tempalltimearray[ataidx] + '", amount is missing.'); } else { let tempamountnum = parseInt(nameamtary[1]); if (isNaN(tempamountnum)) { botLoadErrors.push('Cannot load all-time tipper list entry "' + tempalltimearray[ataidx] + '", the tip amount is not numeric.'); } else { allTimeArrayLoad.name.push(nameamtary[0].trim()); allTimeArrayLoad.totaltips.push(parseInt(nameamtary[1])); } } } } else { botLoadErrors.push('Cannot load all-time tipper list, invalid formatting of list: ' + tempalltimearray); } } // Init word block lists if (cb.settings.wordBlockList != '' && cb.settings.wordBlockList != null) { let tempprivlistarray = cb.settings.wordBlockList.split(','); for (let pvtlistidx = 0; pvtlistidx < tempprivlistarray.length; pvtlistidx++) { let wordtoadd = tempprivlistarray[pvtlistidx].trim(); if (checkASCII(wordtoadd)) { wordtoadd = wordtoadd.toLowerCase(); } if (wordtoadd.length < 2) { botLoadErrors.push('Cannot load Private word list entry "' + wordtoadd + '", it is less than 2 characters.'); } else { if (cbjs.arrayContains(wordListArray,wordtoadd)) { botLoadErrors.push('Skipping duplicate entry for word "' + wordtoadd + '" in the Private Blocked Word List.'); } else { wordListArray.push(wordtoadd); } } } } if (cb.settings.wordBlockListPub != '' && cb.settings.wordBlockListPub != null) { let temppublistarray = cb.settings.wordBlockListPub.split(','); for (let publistidx = 0; publistidx < temppublistarray.length; publistidx++) { let pubwordtoadd = temppublistarray[publistidx].trim(); if (checkASCII(pubwordtoadd)) { pubwordtoadd = pubwordtoadd.toLowerCase(); } if (pubwordtoadd.length < 2) { botLoadErrors.push('Cannot load public word list entry "' + pubwordtoadd + '", must be at least 2 characters long.'); } else { if (cbjs.arrayContains(wordListArrayPub,pubwordtoadd)) { botLoadErrors.push('Skipping duplicate entry for word "' + pubwordtoadd + '" in the Public Blocked Word List.'); } else { wordListArrayPub.push(pubwordtoadd); } } } } //*** Icons, nickname, colors if (cb.settings.iconNicknameList != '' && cb.settings.iconNicknameList != null) { let tempiconlist = cb.settings.iconNicknameList; let tempnicknamearray = tempiconlist.split(','); if (tempnicknamearray.length > 0) { for (let nnidx = 0; nnidx < tempnicknamearray.length; nnidx++) { let iconnnentry = tempnicknamearray[nnidx].split('/'); if (!iconnnentry[0]) { botLoadErrors.push('Cannot load icon / nickname list entry ' + tempnicknamearray[nnidx] + ', no user name is provided.'); } else { if (iconnnentry[1] == '') { iconnnentry[1] = null; } if (iconnnentry[2] == '') { iconnnentry[2] = null; } if (iconnnentry[3] == '') { iconnnentry[3] = null; } iconNicknamesArray.name.push(iconnnentry[0].toLowerCase()); iconNicknamesArray.icon.push(iconnnentry[1]); iconNicknamesArray.nickname.push(iconnnentry[2]); iconNicknamesArray.color.push(iconnnentry[3]); } } } else { botLoadErrors.push('Cannot load nickname list, invalid formatting of list: ' + tempnicknamearray); } } //*** Viewer Notes list if (cb.settings.viewerNotesList != '' && cb.settings.viewerNotesList != null) { let vnlist = cb.settings.viewerNotesList; let tempnotesarray = vnlist.split('^'); if (tempnotesarray.length > 0) { for (let vnidx = 0; vnidx < tempnotesarray.length; vnidx++) { let vnentry = tempnotesarray[vnidx].split('/'); if (!vnentry[0]) { botLoadErrors.push('Cannot load viewer notes list entry ' + tempnotesarray[vnidx] + ', no user name is provided.'); } else { if (vnentry[1] == '') { vnentry[1] = null; } viewerNotesArray.username.push(vnentry[0].toLowerCase()); viewerNotesArray.notes.push(vnentry[1]); viewerNotesArray.displayed.push(false); viewerNotesArray.addinshow.push(false); } } } else { botLoadErrors.push('Cannot load viewer notes list, invalid formatting of list: ' + tempnotesarray); } } //*** Init Exempt command list if (cb.settings.exemptCommandList) { let tempexemptcmdlist = cb.settings.exemptCommandList.toLowerCase(); exemptCmdList = tempexemptcmdlist.split(','); for (let excmdidx = 0; excmdidx < exemptCmdList.length; excmdidx++) { exemptCmdList[excmdidx] = exemptCmdList[excmdidx].trim(); } } //*** All Time Tippers if (cb.settings.enableAllTime == 'Yes') { setAllTimeToggle('on','init'); if (cb.settings.joinVIPCumulativeAllTime > 0 && allTimeArray.name.length > 0) { let atnumadded = 0; for (let alltimeidx = 0; alltimeidx < allTimeArray.name.length; alltimeidx++) { if (allTimeArray.totaltips[alltimeidx] >= cb.settings.joinVIPCumulativeAllTime && !cbjs.arrayContains(VIPListArray, allTimeArray.name[alltimeidx])) { addRmvVIP(allTimeArray.name[alltimeidx],'a'); botLoadErrors.push(allTimeArray.name[alltimeidx] + ' has been added to the VIP list.'); atnumadded++; } } if (atnumadded > 0) { botLoadErrors.push(atnumadded + ' 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.'); } } } //*** Init Ticket Show Features var ticketPrice = cb.settings.hiddenShowPrice; if (ticketShowType == 'Fembot Ticket Show') { if (cb.settings.enableHiddenShow == 'Yes') { if (ticketPrice > 0) { setTicketShowToggle('on','init',ticketPrice); if (cb.settings.enableHiddenShowOT == 'Yes') { setTicketShowOtToggle('on', BC); } } else { botLoadErrors.push('Unable to start the Fembot Ticket 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".'); } } } else { if (cb.settings.ticketShowPrice > 0) { setBackupTicketPrice(cb.settings.ticketShowPrice,'init') setBackupToggle('on', BC,false); } else { botLoadErrors.push('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. \nBackup list can then be started manually using the command "/usebackup on".'); } } if (enablePresales == 'Yes' && cb.settings.enablePresalesMode != 'No Pre-sales') { if (!ticketShowToggle) { if (presalePrice > 0) { if (presalePrice > ticketPrice && ticketPrice > 0) { botLoadErrors.push('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".'); } else if (ticketPrice <= 0) { botLoadErrors.push('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.'); } else { setPresalesToggle('on', 'init'); } } else { botLoadErrors.push('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". '); } } else { botLoadErrors.push('Unable to start pre-sales, the Fembot Ticket Show feature is already started.'); } } if (cb.settings.enablePMResponse == 'Yes' && cb.settings.pmResponseMessage != '') { sendPMResponse = true; } if (cb.settings.enablePrvResponse == 'Yes' && cb.settings.prvResponseMessage != '') { sendPvtResponse = true; } //*** Init King Tipper 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; } setKingTipperFlag('1',BC,false); } else { botLoadErrors.push('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.'); } } else if (cb.settings.kingEnable == 'Yes, use All Time list') { if (cb.settings.enableAllTime == 'Yes') { setKingTipperFlag('2',BC,false); } else { botLoadErrors.push('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.'); } } //*** Init King Session Tipper if (cb.settings.kingSessionEnable == 'Yes' || cb.settings.kingSessionEnableSingle == 'Yes') { setKingSessionToggle('1',BC,false); } // *** Load Array for All Time Icons for (let loadindex = 1; loadindex <= 8; loadindex++) { let alltimeamount = this["allTimeAmount"+loadindex]; let alltimeicon = this["allTimeIcon"+loadindex]; if (alltimeamount && alltimeicon) { alltimeIconArray.amount.push(alltimeamount); alltimeIconArray.icon.push(alltimeicon); } } // *** Load Theme Icons var iconDarkBlue = ''; var iconLightPurple = ''; var iconDarkPurple = ''; var themeIconsToggle = false; if (cb.settings.iconTheme != 'None') { themeIconsToggle = true; 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)) { let themeidx = themeIconArray.name.indexOf(cb.settings.iconTheme); iconDarkBlue = themeIconArray.db[themeidx]; iconLightPurple = themeIconArray.lp[themeidx]; iconDarkPurple = themeIconArray.dp[themeidx]; } else { botLoadErrors.push('Warning! Invalid Icon Theme setting of ' + cb.settings.iconTheme + '. Defaulting to no icon theme used.'); } } } // *** Load PM Colors if (cb.settings.bcCustomTextColor) { BCpurpleF = setTextColor(cb.settings.bcCustomTextColor,'PM To Broadcaster',BC,true); } else { BCpurpleF = setTextColor('#752d6e','PM To Broadcaster',BC,true); } if (cb.settings.bcCustomBgColor) { BCpurpleB = setBgColor(cb.settings.bcCustomBgColor,'PM To Broadcaster',BC,true); } else { BCpurpleB = setBgColor('#f3e0f1','PM To Broadcaster',BC,true); } if (cb.settings.tmCustomTextColor) { TMgreenF = setTextColor(cb.settings.tmCustomTextColor,'PM To Mods',BC,true); } else { TMgreenF = setTextColor('#007e00','PM To Mods',BC,true); } if (cb.settings.tmCustomBgColor) { TMgreenB = setBgColor(cb.settings.tmCustomBgColor,'PM To Mods',BC,true); } else { TMgreenB = setBgColor('#d2f8d2','PM To Mods',BC,true); } if (cb.settings.tbmCustomTextColor) { TBMblueF = setTextColor(cb.settings.tbmCustomTextColor,'PM To Broadcaster and Mods',BC,true); } else { TBMblueF = setTextColor('#1a1aff','PM To Broadcaster and Mods',BC,true); } if (cb.settings.tbmCustomBgColor) { TBMblueB = setBgColor(cb.settings.tbmCustomBgColor,'PM To Broadcaster and Mods',BC,true); } else { TBMblueB = setBgColor('#dff1f3','PM To Broadcaster and Mods',BC,true); } if (cb.settings.pmCustomTextColor) { PMaquaF = setTextColor(cb.settings.pmCustomTextColor,'PM To Any User',BC,true); } else { PMaquaF = setTextColor('#008181','PM To Any User',BC,true); } if (cb.settings.pmCustomBgColor) { PMaquaB = setBgColor(cb.settings.pmCustomBgColor,'PM To Any User',BC,true); } else { PMaquaB = setBgColor('#f2ebd4','PM To Any User',BC,true); } // *** Miscellaneous var fembotStartTime = new Date(); cb.setTimeout(checkPasswordLock, 30000); var roomSizePrevTotal = 0; cb.setTimeout(initFollowerThreshold, 20000); if (cb.settings.autoUpdateSLGL != 'No') { cb.setTimeout(roomSizeMonitor, 60000); } populateModeratorArray(BC,'broadcaster','a'); switch (silenceLevel) { case 0: botLoadErrors.push('The Fembot Silence Level is set to "0", all viewers can chat.'); break; case 1: botLoadErrors.push('The Fembot Silence Level is set to "1", all members with tokens can chat.'); break; case 2: botLoadErrors.push('The Fembot Silence Level is set to "2", only members who have tipped can chat.'); break; case 3: minTipToChat = parseInt(cb.settings.minTipToChat); botLoadErrors.push('The Fembot Silence Level is set to "3", only members who have tipped at least ' + minTipToChat + ' tokens can chat.'); break; case 4: botLoadErrors.push('The Fembot Silence Level is set to "4", only Moderators, Fans, and VIPs can chat.'); break; } switch (graphicLevel) { case 0: botLoadErrors.push('The Fembot Graphics Level is set to "0", all viewers can post gifs in the chat.'); break; case 1: botLoadErrors.push('The Fembot Graphics Level is set to "1", all members with tokens can post gifs in the chat.'); break; case 2: botLoadErrors.push('The Fembot Graphics Level is set to "2", only members who have tipped can post gifs in the chat.'); break; case 3: minTipToChat = parseInt(cb.settings.minTipToChat); botLoadErrors.push('The Fembot Graphics Level is set to "3", only members who have tipped at least ' + minTipToChat + ' tokens can post gifs in the chat.'); break; case 4: botLoadErrors.push('The Fembot Graphics Level is set to "4", only Moderators, Fans, and VIPs can post gifs in the chat.'); break; } cb.setTimeout(displayBotLoadErrors, 3000); initialize = 1; } // *********************************** Functions ************************************** function displayBotLoadErrors() { let blemessage = 'Fembot Startup Notices and Warnings:' if (botLoadErrors.length > 0) { for (let bleidx = 0; bleidx < botLoadErrors.length; bleidx++) { blemessage += '\n \u26D4 ' + wordWrap(botLoadErrors[bleidx]); } } else { blemessage += '\n \u2022 No notices.'; } cb.sendNotice(blemessage, BC, appWarningColor); } function loadAllFeatureColors(loadfeatby,ldstartupflag) { setLeaderBoardColors(loadfeatby,ldstartupflag); setNoticeColor(loadfeatby,ldstartupflag); setRoomRulesColor(loadfeatby,ldstartupflag); setFollowerNoticeColor(loadfeatby,ldstartupflag); setIconTipNoticeColor(loadfeatby,ldstartupflag); setKingTipperColor(loadfeatby,ldstartupflag); setKingSessionColor(loadfeatby,ldstartupflag); setTipMenuColors(loadfeatby,ldstartupflag); setPosMenuColors(loadfeatby,ldstartupflag); setToyMenuColors(loadfeatby,ldstartupflag); setPollColors(loadfeatby,ldstartupflag); setODPollColors(loadfeatby,ldstartupflag); setTextPollColors(loadfeatby,ldstartupflag); setMediaColors(loadfeatby,ldstartupflag); setDiceNoticeColors(loadfeatby,ldstartupflag); setPresalesNoticeColors(loadfeatby,ldstartupflag); ticketShowColors(loadfeatby,ldstartupflag); setAllTimeListColors(loadfeatby,ldstartupflag); setGuestColors(loadfeatby,ldstartupflag); } function loadThemeColors(loadthemeby,startupflag) { let tempthemebgcolor = setThemeBgColor(loadthemeby,startupflag); let tempthemetextcolor = setThemeTextColor(loadthemeby,startupflag); leaderBgColor = tempthemebgcolor; leaderTextColor = tempthemetextcolor; noticeBgColor = tempthemebgcolor; noticeTextColor = tempthemetextcolor; roomRulesBgColor = tempthemebgcolor; roomRulesTextColor = tempthemetextcolor; followNoticeBgColor = tempthemebgcolor; followNoticeTextColor = tempthemetextcolor; iconTipNoticeBgColor = tempthemebgcolor; iconTipNoticeTextColor = tempthemetextcolor; kingTipperBgNoticeColor = tempthemebgcolor; kingTipperTextColor = tempthemetextcolor; kingSessionNoticeColor = tempthemebgcolor; kingSessionTextColor = tempthemetextcolor; tipMenuBgColor1 = tempthemebgcolor; tipMenuTextColor1 = tempthemetextcolor; tipMenuBgColor2 = tempthemebgcolor; tipMenuTextColor2 = tempthemetextcolor; tipMenu2BgColor1 = tempthemebgcolor; tipMenu2TextColor1 = tempthemetextcolor; tipMenu2BgColor2 = tempthemebgcolor; tipMenu2TextColor2 = tempthemetextcolor; posMenuBgColor = tempthemebgcolor; posMenuTextColor = tempthemetextcolor; toyMenuBgColor = tempthemebgcolor; toyMenuTextColor = tempthemetextcolor; tokenPollBgColor = tempthemebgcolor; tokenPollTextColor = tempthemetextcolor; odtokenPollBgColor = tempthemebgcolor; odtokenPollTextColor = tempthemetextcolor; textPollBgColor = tempthemebgcolor; textPollTextColor = tempthemetextcolor; mediabackground = tempthemebgcolor; mediaforeground = tempthemetextcolor; diceNoticeBgColor = tempthemebgcolor; diceNoticeTextColor = tempthemetextcolor; presalesBgColor = tempthemebgcolor; presalesTxtColor = tempthemetextcolor; ticketNoticesBgColor = tempthemebgcolor; ticketNoticesTxtColor = tempthemetextcolor; allTimeBgColor = tempthemebgcolor; allTimeTextColor = tempthemetextcolor; guestListBgColor = tempthemebgcolor; guestListTextColor = tempthemetextcolor; } function loadAllStaticColors(loadstaticby) { setFollowerColor(loadstaticby,true); setKingTipperChatColor(loadstaticby,true); setTipMenuRespColors(loadstaticby,true); setDiceColors(loadstaticby,true); setTipResponseColors(loadstaticby,true); ticketShowNoticeColors(loadstaticby,true); } function setThemeTextColor(sttcsendto,ststartupflag) { let selectedthemetextcolor = '#000000'; if (colorTheme == 'Custom') { let temptextcolor = cb.settings.colorThemeCustText; if (/^#[0-9A-F]{6}$/i.test(temptextcolor)) { selectedthemetextcolor = temptextcolor; } else if (/^[0-9A-F]{6}$/i.test(temptextcolor)) { selectedthemetextcolor = '#' + temptextcolor; } else { if (ststartupflag) { botLoadErrors.push(temptextcolor + ' - Error while setting the text color. It must be in a HEX code format. Using default value of black text.'); } else { cb.sendNotice(botName + ' ' + temptextcolor + ' - Error while setting the text color. It must be in a HEX code format. Using default value of black text.', sttcsendto, appWarningColor); } } } else { if (cbjs.arrayContains(themeArray.name,colorTheme)) { let themeidx = themeArray.name.indexOf(colorTheme); return themeArray.textcolor[themeidx]; } else { if (ststartupflag) { botLoadErrors.push('Warning! Invalid theme setting of "' + colorTheme + '". Defaulting to no theme used.'); } else { cb.sendNotice(botName + ' Warning! Invalid theme setting of "' + colorTheme + '". \nDefaulting to no theme used.', sttcsendto, appWarningColor); } colorTheme = 'None'; } } return selectedthemetextcolor; } function setThemeBgColor(setthemeby,stbgstartupflag) { let selectedthemebgcolor = '#FFFFFF'; if (colorTheme == 'Custom') { let graddir = ''; 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'; } let themecustbg1 = ''; let themecustbg2 = ''; let themecustbg3 = ''; 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 (stbgstartupflag) { botLoadErrors.push('Warning! Custom color theme selected but Background 1 is not in the correct hex color code format. Defaulting to no theme used.'); } else { cb.sendNotice(botName + ' Warning! Custom color theme selected but Background 1 is not in the correct hex color code format. \nDefaulting to no theme used.', setthemeby, appWarningColor); } colorTheme = 'None'; } } else { if (stbgstartupflag) { botLoadErrors.push('Warning! Custom color theme selected but Background 1 is not configured. Defaulting to no theme used.'); } else { cb.sendNotice(botName + ' Warning! Custom color theme selected but Background 1 is not configured. \nDefaulting to no theme used.', setthemeby, appWarningColor); } colorTheme = '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 (stbgstartupflag) { botLoadErrors.push('Warning! Custom color theme selected but Background 2 is not configured with a proper hex color code. Defaulting second color to white.'); } else { cb.sendNotice(botName + ' Warning! Custom color theme selected but Background 2 is not configured with a proper hex color code. \nDefaulting second color to white.', setthemeby, appWarningColor); } } } else { themecustbg2 = '#FFFFFF'; if (stbgstartupflag) { botLoadErrors.push('Warning! Custom color theme selected but Background 2 is not configured. At least two colors are required, defaulting second color to white.'); } else { cb.sendNotice(botName + ' Warning! Custom color theme selected but Background 2 is not configured. \nAt least two colors are required, defaulting second color to white.', setthemeby, appWarningColor); } } let numbercustcolors = 2; 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'; } } if (colorTheme != 'None') { if (numbercustcolors == 2) { selectedthemebgcolor = 'linear-gradient(' + graddir + ', ' + themecustbg1 + ', ' + themecustbg2 + ')'; } else { selectedthemebgcolor = 'linear-gradient(' + graddir + ', ' + themecustbg1 + ', ' + themecustbg2 + ', ' + themecustbg3 + ')'; } } } else { if (cbjs.arrayContains(themeArray.name,colorTheme)) { let themeidx = themeArray.name.indexOf(colorTheme); selectedthemebgcolor = themeArray.colorID[themeidx]; } else { if (stbgstartupflag) { botLoadErrors.push('Warning! Invalid theme setting of "' + colorTheme + '". Defaulting to no theme used.'); } else { cb.sendNotice(botName + ' Warning! Invalid theme setting of "' + colorTheme + '". \nDefaulting to no theme used.', setthemeby, appWarningColor); } colorTheme = 'None'; } } return selectedthemebgcolor; } function setTextColor(inputtextcolor,inputtextcolortype,inputtextcolorsendto,txtstartupflag) { let selectedtextcolor = '#FFFFFF'; if (cbjs.arrayContains(textColorArray.dispname,inputtextcolor)) { let txtclridx = textColorArray.dispname.indexOf(inputtextcolor); selectedtextcolor = textColorArray.colorID[txtclridx]; } else { if (/^#[0-9A-F]{6}$/i.test(inputtextcolor)) { selectedtextcolor = inputtextcolor; } else if (/^[0-9A-F]{6}$/i.test(inputtextcolor)) { selectedtextcolor = '#' + inputtextcolor; } else { if (txtstartupflag) { botLoadErrors.push(inputtextcolortype + ' - Error while setting the text color. It must be in a HEX code format. Using default value of black text.'); } else { cb.sendNotice(botName + ' ' + inputtextcolortype + ' - Error while setting the text color. It must be in a HEX code format. Using default value of black text.', inputtextcolorsendto, appWarningColor); } } } return selectedtextcolor; } function setBgColor(inputbgcolor,inputbgcolortype,inputbgcolorsendto,bgstartupflag) { let selectedbgcolor = '#FFFFFF'; if (cbjs.arrayContains(bgColorArray.dispname,inputbgcolor)) { let clridx = bgColorArray.dispname.indexOf(inputbgcolor); selectedbgcolor = bgColorArray.colorID[clridx]; } else { if (/^#[0-9A-F]{6}$/i.test(inputbgcolor)) { selectedbgcolor = inputbgcolor; } else if (/^[0-9A-F]{6}$/i.test(inputbgcolor)) { selectedbgcolor = '#' + inputbgcolor; } else { if (bgstartupflag) { botLoadErrors.push(inputbgcolortype + ' - Error while setting the background color. It must be in a HEX code format. Using default value of white/no background.'); } else { cb.sendNotice(botName + ' ' + inputbgcolortype + ' - Error while setting the background color. It must be in a HEX code format. Using default value of white/no background.', inputbgcolorsendto, appWarningColor); } } } if (selectedbgcolor != '#FFFFFF') { if (cb.settings.colorsGradientDirection == 'Linear, left to right') { selectedbgcolor = 'linear-gradient(to right, ' + selectedbgcolor + ', #FFFFFF)'; } else if (cb.settings.colorsGradientDirection == 'Linear, top to bottom') { selectedbgcolor = 'linear-gradient(to bottom, ' + selectedbgcolor + ', #FFFFFF)'; } else if (cb.settings.colorsGradientDirection == 'Linear, diagonally') { selectedbgcolor = 'linear-gradient(to right bottom, ' + selectedbgcolor + ', #FFFFFF)'; } } return selectedbgcolor; } function checkSepChar(inputchar) { if (cbjs.arrayContains(separatorArray.dispname,inputchar)) { let charidx = separatorArray.dispname.indexOf(inputchar); return separatorArray.charID[charidx]; } else { return '|'; } } //********** Build Repeating Char Lines ************** function noticeBorderChar() { let emojispace = ''; if (cb.settings.noticeSepStyle == 'Custom Emoji Below' || cb.settings.noticeSepStyle == 'Custom Emoji Below - Extra Space') { borderCharSpacing = 'emoji'; if (borderChar) { if (borderChar.includes(':') || borderChar.includes('\\')) { cb.sendNotice(botName + ' 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(botName + ' 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); } if (cb.settings.noticeSepStyle == 'Custom Emoji Below - Extra Space') { emojispace = '\n'; } } else if (cb.settings.noticeSepStyle == 'Custom Unicode Character Below') { borderCharSpacing = 'unicode'; if (borderChar) { if (borderChar.includes(':')) { cb.sendNotice(botName + ' 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(botName + ' 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'; } switch (borderCharSpacing) { case 'emoji': borderLeaderboardTop = noticeBorder('top','LEADERBOARD',4,false,true) + emojispace; borderLeaderboardBottom = '\n' + noticeBorder('bottom','',7,false,true); borderTipForIconTop = noticeBorder('top','TIP FOR ICONS',9,true,true) + emojispace; borderPollTop = noticeBorder('top','TOKEN POLL',10,false,true) + emojispace; borderPollResultsTop = noticeBorder('top','POLL RESULTS',9,false,true) + emojispace; borderOdPollTop = noticeBorder('top','ON-DEMAND POLL',8,false,true) + emojispace; borderTextPollTop = noticeBorder('top','TEXT POLL',10,false,true) + emojispace; borderDiceTop = noticeBorder('top','DICE GAME',10,false,true) + emojispace; borderMediaTop = noticeBorder('top','MEDIA INFO',10,false,true) + emojispace; borderRoomRulesTop = noticeBorder('top','ROOM RULES',10,false,true) + emojispace; borderAllTimeTop = noticeBorder('top','ALL-TIME TIP LEADERS',8,false,true) + emojispace; borderToyMenuTop = noticeBorder('top','TOY MENU',10,true,true) + emojispace; borderTmrTop = noticeBorder('top','TIP REQUEST HISTORY',7,false,true) + emojispace; borderDiceHistTop = noticeBorder('top','DICE ROLL HISTORY',7,false,true) + emojispace; borderFollowerTop = noticeBorder('top','FOLLOWERS',10,false,true) + emojispace; borderWelcomeTop = noticeBorder('top','WELCOME',10,false,true) + emojispace; borderSummaryTop = noticeBorder('top','TIP OPTIONS',10,false,true) + emojispace; borderCurrentKingTop = noticeBorder('top','CURRENT SHOW',9,false,true) + emojispace; borderGuestTop = noticeBorder('top','GUEST INFO',10,false,true) + emojispace; borderAllNoticesTop = noticeBorder('bottom','',12,false,true) + emojispace + '\n'; borderUniversalBottom = '\n' + emojispace + noticeBorder('bottom','',12,false,true); break; case 'unicode': borderLeaderboardTop = noticeBorder('top','LEADERBOARD',9,false,false); borderLeaderboardBottom = '\n' + noticeBorder('bottom','',13,false,false); borderTipForIconTop = noticeBorder('top','TIP FOR ICONS',18,false,false); borderPollTop = noticeBorder('top','TOKEN POLL',18,true,false); borderPollResultsTop = noticeBorder('top','POLL RESULTS',18,false,false); borderOdPollTop = noticeBorder('top','ON-DEMAND POLL',17,false,false); borderTextPollTop = noticeBorder('top','TEXT POLL',19,false,false); borderDiceTop = noticeBorder('top','DICE GAME',19,false,false); borderMediaTop = noticeBorder('top','MEDIA INFO',19,false,false); borderRoomRulesTop = noticeBorder('top','ROOM RULES',18,true,false); borderAllTimeTop = noticeBorder('top','ALL-TIME TIP LEADERS',15,true,false); borderToyMenuTop = noticeBorder('top','TOY MENU',18,false,false); borderTmrTop = noticeBorder('top','TIP REQUEST HISTORY',16,false,false); borderDiceHistTop = noticeBorder('top','DICE ROLL HISTORY',16,false,false); borderFollowerTop = noticeBorder('top','FOLLOWERS',18,false,false); borderWelcomeTop = noticeBorder('top','WELCOME',19,true,false); borderSummaryTop = noticeBorder('top','TIP OPTIONS',18,true,false); borderCurrentKingTop = noticeBorder('top','CURRENT SHOW',18,false,false); borderGuestTop = noticeBorder('top','GUEST INFO',19,false,false); borderAllNoticesTop = noticeBorder('bottom','',22,false,false) + '\n'; borderUniversalBottom = '\n' + noticeBorder('bottom','',22,false,false); break; case 'light': borderLeaderboardTop = noticeBorder('top','LEADERBOARD',20,true,false); borderLeaderboardBottom = '\n' + noticeBorder('bottom','',29,false,false); borderTipForIconTop = noticeBorder('top','TIP FOR ICONS',39,true,false); borderPollTop = noticeBorder('top','TOKEN POLL',41,false,false); borderPollResultsTop = noticeBorder('top','POLL RESULTS',39,false,false); borderOdPollTop = noticeBorder('top','ON-DEMAND POLL',38,false,false); borderTextPollTop = noticeBorder('top','TEXT POLL',42,false,false); borderDiceTop = noticeBorder('top','DICE GAME',42,false,false); borderMediaTop = noticeBorder('top','MEDIA INFO',41,false,false); borderRoomRulesTop = noticeBorder('top','ROOM RULES',40,true,false); borderAllTimeTop = noticeBorder('top','ALL-TIME TIP LEADERS',35,false,false); borderToyMenuTop = noticeBorder('top','TOY MENU',42,true,false); borderTmrTop = noticeBorder('top','TIP REQUEST HISTORY',37,false,false); borderDiceHistTop = noticeBorder('top','DICE ROLL HISTORY',36,false,false); borderFollowerTop = noticeBorder('top','FOLLOWERS',41,false,false); borderWelcomeTop = noticeBorder('top','WELCOME',42,true,false); borderSummaryTop = noticeBorder('top','TIP OPTIONS',41,false,false); borderCurrentKingTop = noticeBorder('top','CURRENT SHOW',39,false,false); borderGuestTop = noticeBorder('top','GUEST INFO',41,false,false); borderAllNoticesTop = noticeBorder('bottom','',48,false,false) + '\n'; borderUniversalBottom = '\n' + noticeBorder('bottom','',48,false,false); break; case 'none': borderLeaderboardTop = noticeBorder('top','LEADERBOARD',0,false,false); borderLeaderboardBottom = ''; borderTipForIconTop = noticeBorder('top','TIP FOR ICONS',0,false,false); borderPollTop = noticeBorder('top','TOKEN POLL',0,false,false); borderPollResultsTop = noticeBorder('top','POLL RESULTS',0,false,false); borderOdPollTop = noticeBorder('top','ON-DEMAND POLL',0,false,false); borderTextPollTop = noticeBorder('top','TEXT POLL',0,false,false); borderDiceTop = noticeBorder('top','DICE GAME',0,false,false); borderMediaTop = noticeBorder('top','MEDIA INFO',0,false,false); borderRoomRulesTop = noticeBorder('top','ROOM RULES',0,false,false); borderAllTimeTop = noticeBorder('top','ALL-TIME TIP LEADERS',0,false,false); borderToyMenuTop = noticeBorder('top','TOY MENU',0,false,false); borderTmrTop = noticeBorder('top','TIP REQUEST HISTORY',0,false,false); borderDiceHistTop = noticeBorder('top','DICE ROLL HISTORY',0,false,false); borderFollowerTop = noticeBorder('top','FOLLOWERS',0,false,false); borderWelcomeTop = noticeBorder('top','WELCOME',0,false,false); borderSummaryTop = noticeBorder('top','TIP OPTIONS',0,false,false); borderCurrentKingTop = noticeBorder('top','CURRENT SHOW',0,false,false); borderGuestTop = noticeBorder('top','GUEST INFO',0,false,false); borderAllNoticesTop = ''; borderUniversalBottom = ''; break; } } function noticeBorder(bordertopbtm,bordertext,bordernumchar,bordernumaddone,borderdispspace) { let outcharstring = ''; let halfcharstring = ''; let midchar = '\u25CF'; let dispnumber = 0; if (borderCharSpacing == 'none') { if (bordertopbtm == 'top') { outcharstring = bordertext; } } else { for (let charidx = 1; charidx <= bordernumchar; charidx++) { if (borderdispspace) { halfcharstring += borderChar + ' '; } else { halfcharstring += borderChar; } } if (bordertopbtm == 'top') { outcharstring += halfcharstring + ' ' + bordertext + ' ' + halfcharstring; if (bordernumaddone) { outcharstring += borderChar; } } else if (bordertopbtm == 'bottom') { if (borderdispspace) { outcharstring += halfcharstring + halfcharstring; } else { outcharstring += halfcharstring + ' ' + midchar + ' ' + halfcharstring; } } } return outcharstring; } function checkEmoji(inputchar) { return checkEmojiChar.test(inputchar); } function checkASCII(inputchar) { return checkASCIIChar.test(inputchar); } function loadNoticeIntervals() { noticeIntervals.name[0] = 'dice'; noticeIntervals.fieldname[0] = 'diceInt'; noticeIntervals.settingID[0] = '18F'; updateIntervalArray(noticeIntervals.name[0],cb.settings.diceNoticeInterval,3.3,noticeIntervals.settingID[0]); noticeIntervals.name[1] = 'toymenu'; noticeIntervals.fieldname[1] = 'toyMenuDispInt'; noticeIntervals.settingID[1] = '16B'; updateIntervalArray(noticeIntervals.name[1],cb.settings.lushMenuInterval,2.7,noticeIntervals.settingID[1]); noticeIntervals.name[2] = 'tipmenu1'; noticeIntervals.fieldname[2] = 'tipMenuDispInt'; noticeIntervals.settingID[2] = '11B'; updateIntervalArray(noticeIntervals.name[2],cb.settings.menuDspInt,2.9,noticeIntervals.settingID[2]); noticeIntervals.name[3] = 'tipmenu2'; noticeIntervals.fieldname[3] = 'tipMenu2DispInt'; noticeIntervals.settingID[3] = '11B'; updateIntervalArray(noticeIntervals.name[3],cb.settings.menuDspInt,2.9,noticeIntervals.settingID[3]); noticeIntervals.name[4] = 'posmenu'; noticeIntervals.fieldname[4] = 'posMenuDispInt'; noticeIntervals.settingID[4] = '12B'; updateIntervalArray(noticeIntervals.name[4],cb.settings.posMenuInterval,3.4,noticeIntervals.settingID[4]); noticeIntervals.name[5] = 'follow'; noticeIntervals.fieldname[5] = 'followerInt'; noticeIntervals.settingID[5] = '20G'; updateIntervalArray(noticeIntervals.name[5],cb.settings.followNoticeInterval,4.8,noticeIntervals.settingID[5]); noticeIntervals.name[6] = 'tipforicon'; noticeIntervals.fieldname[6] = 'iconNoticeInt'; noticeIntervals.settingID[6] = '7L2'; updateIntervalArray(noticeIntervals.name[6],cb.settings.iconTipNoticeInt,4.5,noticeIntervals.settingID[6]); noticeIntervals.name[7] = 'kingsession'; noticeIntervals.fieldname[7] = 'kingSessionInt'; noticeIntervals.settingID[7] = '3P1'; updateIntervalArray(noticeIntervals.name[7],cb.settings.kingSessionInterval,5.7,noticeIntervals.settingID[7]); noticeIntervals.name[8] = 'kingalltime'; noticeIntervals.fieldname[8] = 'kingTipperInt'; noticeIntervals.settingID[8] = '3J2'; updateIntervalArray(noticeIntervals.name[8],cb.settings.kingTipperInterval,6.6,noticeIntervals.settingID[8]); noticeIntervals.name[9] = 'leaderboard'; noticeIntervals.fieldname[9] = 'leaderInt'; noticeIntervals.settingID[9] = '2J'; updateIntervalArray(noticeIntervals.name[9],cb.settings.leaderInterval,3.5,noticeIntervals.settingID[9]); noticeIntervals.name[10] = 'media'; noticeIntervals.fieldname[10] = 'mediaTimerInt'; noticeIntervals.settingID[10] = '17B'; updateIntervalArray(noticeIntervals.name[10],cb.settings.mediaListInterval,5.7,noticeIntervals.settingID[10]); noticeIntervals.name[11] = 'notifier'; noticeIntervals.fieldname[11] = 'notifierInt'; noticeIntervals.settingID[11] = '1G'; updateIntervalArray(noticeIntervals.name[11],cb.settings.notifierInterval,1.7,noticeIntervals.settingID[11]); noticeIntervals.name[12] = 'ondemandpoll'; noticeIntervals.fieldname[12] = 'ODpollNoticeInt'; noticeIntervals.settingID[12] = '13C'; updateIntervalArray(noticeIntervals.name[12],cb.settings.pollInterval,1.5,noticeIntervals.settingID[12]); noticeIntervals.name[13] = 'tokenpoll'; noticeIntervals.fieldname[13] = 'pollNoticeInt'; noticeIntervals.settingID[13] = '13C'; updateIntervalArray(noticeIntervals.name[13],cb.settings.pollInterval,1.5,noticeIntervals.settingID[13]); noticeIntervals.name[14] = 'presales'; noticeIntervals.fieldname[14] = 'presaleNoticeInt'; noticeIntervals.settingID[14] = '14X'; updateIntervalArray(noticeIntervals.name[14],cb.settings.presaleNoticeInterval,4.1,noticeIntervals.settingID[14]); noticeIntervals.name[15] = 'roomrules'; noticeIntervals.fieldname[15] = 'roomRulesInt'; noticeIntervals.settingID[15] = '19C'; updateIntervalArray(noticeIntervals.name[15],cb.settings.roomRulesInterval,5.5,noticeIntervals.settingID[15]); noticeIntervals.name[16] = 'textpoll'; noticeIntervals.fieldname[16] = 'textPollNoticeInt'; noticeIntervals.settingID[16] = '21G'; updateIntervalArray(noticeIntervals.name[16],cb.settings.textPollInterval,1.5,noticeIntervals.settingID[16]); noticeIntervals.name[17] = 'ticket'; noticeIntervals.fieldname[17] = 'ticketNoticeInt'; noticeIntervals.settingID[17] = '15T'; updateIntervalArray(noticeIntervals.name[17],cb.settings.ticketNoticeInterval,2.1,noticeIntervals.settingID[17]); noticeIntervals.name[18] = 'showsummary'; noticeIntervals.fieldname[18] = 'showSummaryInt'; noticeIntervals.settingID[18] = '1S2'; updateIntervalArray(noticeIntervals.name[18],cb.settings.showSummaryInterval,4.2,noticeIntervals.settingID[18]); noticeIntervals.name[19] = 'alltime'; noticeIntervals.fieldname[19] = 'allTimeInt'; noticeIntervals.settingID[19] = '2Q'; updateIntervalArray(noticeIntervals.name[19],cb.settings.allTimeInterval,23.2,noticeIntervals.settingID[19]); noticeIntervals.name[20] = 'guest'; noticeIntervals.fieldname[20] = 'guestListInt'; noticeIntervals.settingID[20] = '22B'; updateIntervalArray(noticeIntervals.name[20],cb.settings.guestListInterval,1.7,noticeIntervals.settingID[20]); } function updateIntervalArray(updtinttype,updintint,updintdft,updintsetting) { if (!updintint) { updintint = updintdft; } else { let timersetting = parseFloat(updintint); if (isNaN(timersetting)) { updintint = updintdft; botLoadErrors.push('The "' + updtinttype + '" Chat Notice Interval is configured (setting "' + updintsetting + '"), but is not numeric, it must be a numeric value of at least one (decimals allowed). Using default value of ' + updintdft + ' minutes.'); } else if (updintint < 1) { updintint = updintdft; botLoadErrors.push('The "' + updtinttype + '" Chat Notice Interval is configured (setting "' + updintsetting + '"), but is too short, it must be at least 1 minute. Using default value of ' + updintdft + ' minutes.'); } } updateIntervalValues(updtinttype,updintint); } function updateIntervalValues(updvaltype,updvalint) { let intnameidx = noticeIntervals.name.indexOf(updvaltype); let actualint = parseInt(updvalint*60000); this[noticeIntervals.fieldname[intnameidx]] = actualint; } //********** Price Check Function ************** function priceChecker(pcmode,pcname,pcprice,pcsendto) { let pricechksndto = pcsendto; if (pcsendto == 'init') { pricechksndto = BC; } if (pcprice) { if (pcmode == 'add') { if (cbjs.arrayContains(priceCheckArray.name,pcname)) { let pcnameidx = priceCheckArray.name.indexOf(pcname); priceCheckArray.name.splice(pcnameidx,1); priceCheckArray.amount.splice(pcnameidx,1); } if (cbjs.arrayContains(priceCheckArray.amount,pcprice)) { let pcpriceidx = priceCheckArray.amount.indexOf(pcprice); if (pcsendto == 'init') { botLoadErrors.push('Warning! There is a duplicate price entry. When adding "' + pcname + '", the configured price of ' + pcprice + ' was found already in use for ' + priceCheckArray.name[pcpriceidx] + '.'); } else { cb.sendNotice(botName + 'Warning! There is a duplicate price entry. When adding "' + pcname + '", the configured price of ' + pcprice + ' was found already in use for ' + priceCheckArray.name[pcpriceidx] + '.',pricechksndto,appWarningColor); } } if (pcprice == 1 || pcprice == 5 || pcprice == 10 || pcprice == 15 || pcprice == 20 || pcprice == 25 || pcprice == 50 || pcprice == 100) { if (pcsendto == 'init') { botLoadErrors.push('Warning! When adding "' + pcname + '", the configured price of ' + pcprice + ' is a common tip amount (1,5,10,15,20,25,50,100) and not recommended for any specific feature price. It is recommended to use uncommon tip amounts for all prices.'); } else { cb.sendNotice(botName + 'Warning! When adding "' + pcname + '", the configured price of ' + pcprice + ' is a common tip amount (1,5,10,15,20,25,50,100) and not recommended for any specific feature price. \nIt is recommended to use uncommon tip amounts for all prices.',pricechksndto,appWarningColor); } } priceCheckArray.name.push(pcname); priceCheckArray.amount.push(pcprice); } else if (pcmode == 'rmv') { if (cbjs.arrayContains(priceCheckArray.name,pcname)) { let pcnameidxr = priceCheckArray.name.indexOf(pcname); priceCheckArray.name.splice(pcnameidxr,1); priceCheckArray.amount.splice(pcnameidxr,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); let chatallowedby = 'Unexpected Setting'; 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'; } 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.', BC, appWarningColor, '','bold'); } } }); cb.setTimeout(checkPasswordLock, 300000); } function initFollowerThreshold() { cb.getRoomOwnerData(ownerData => { if (ownerData.success) { for (let 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(borderAllNoticesTop + 'Welcome back ' + BC + '. \nYou have ' + ownerData.data.followers + ' follower' + (ownerData.data.followers == 1 ? '' : 's') + '. You are ' + (nextFollowerThreshold - ownerData.data.followers) + ' away from ' + nextFollowerThreshold + ' followers!' + borderUniversalBottom, BC, followBgColor, followTextColor, 'bold'); if (nextFollowerThreshold > 0) { cb.setTimeout(checkFollowerCount, 60000); } } }); } function checkFollowerCount() { cb.getRoomOwnerData(ownerData => { if (ownerData.success) { if (ownerData.data.followers >= nextFollowerThreshold ) { let followerthresholdicon = ''; 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 ' + BC + ' on reaching ' + nextFollowerThreshold + ' followers!!! ' + followerthresholdicon, '', lightblue, '', 'bold'); ftaIndex++; nextFollowerThreshold = followerThresholdArray[ftaIndex]; } } }); cb.setTimeout(checkFollowerCount, 60000); } function displayUserStats(ustatsendto) { cb.getRoomUsersData(usersData => { if (usersData.success) { let numbermods = usersData.data.moderator.length; let numberfans = usersData.data.fanclub.length; let numberdarkpurple = usersData.data.dark_purple.length; let numberlightpurple = usersData.data.light_purple.length; let numberdarkblue = usersData.data.dark_blue.length; let numberlightblue = usersData.data.light_blue.length; let numbergrey = usersData.data.grey.length; let numberextfans1 = extFanListArray.length; let numberextfansinshow1 = extFanInShowArray.length; let numberextfans2 = extFanList2Array.length; let numberextfansinshow2 = extFanInShow2Array.length; let numbervips = VIPListArray.length; let 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: ' + numberextfans2 + '\n \u21D2 Number of External Fan Club 2 members in current show: ' + numberextfansinshow2 + '\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) { let totalnumberinroom = usersData.data.moderator.length + usersData.data.fanclub.length + usersData.data.dark_purple.length + usersData.data.light_purple.length + usersData.data.dark_blue.length + usersData.data.light_blue.length + usersData.data.grey.length; if (totalnumberinroom > 0 && totalnumberinroom > roomSizePrevTotal) { if (cb.settings.silenceGraysThreshold > 0 && totalnumberinroom > cb.settings.silenceGraysThreshold) { if (silenceLevel < 1 && !manualSilenceLvlUpd) { 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.', BC, 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.', BC, appWarningColor, '', '', 'red'); } if (graphicLevel < 1 && !manualGraphicLvlUpd) { 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.', BC, 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.', BC, appWarningColor, '', '', 'red'); } } else if (cb.settings.silenceNonTipThreshold > 0 && totalnumberinroom > cb.settings.silenceNonTipThreshold) { if (silenceLevel < 2 && !manualSilenceLvlUpd) { 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.', BC, 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.', BC, appWarningColor, '', '', 'red'); } if (graphicLevel < 2 && !manualGraphicLvlUpd) { 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.', BC, 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.', BC, 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 && !manualSilenceLvlUpd) { 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.', BC, 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.', BC, appWarningColor, '', '', 'red'); } if (graphicLevel > 0 && !manualGraphicLvlUpd) { 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.', BC, 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.', BC, appWarningColor, '', '', 'red'); } } else if (cb.settings.silenceNonTipThreshold > 0 && totalnumberinroom < cb.settings.silenceNonTipThreshold) { if (silenceLevel > 1 && !manualSilenceLvlUpd) { 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.', BC, 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.', BC, appWarningColor, '', '', 'red'); } if (graphicLevel > 1 && !manualGraphicLvlUpd) { 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.', BC, 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.', BC, appWarningColor, '', '', 'red'); } } } } roomSizePrevTotal = totalnumberinroom; } else { cb.sendNotice('Error retrieving User Statistics from CB.', BC, appWarningColor); } }); cb.setTimeout(roomSizeMonitor, 60000); } // *********************************** Length of show ************************************** function timeOnline() { let timeonlineelapsed = onlineclockTimeCal(); let onlineclockMS = timeonlineelapsed % 1000; let onlineclockSeconds = ((timeonlineelapsed - onlineclockMS) % 60000); let onlineclockMinutes = ((timeonlineelapsed - onlineclockSeconds - onlineclockMS) % 3600000); let 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() { let timenow = new Date(); return (timenow - fembotStartTime.getTime()); } function howLongAgoCalc(inputtime) { let currenttimecalc = new Date(); let howlongago = (currenttimecalc.getTime() - inputtime); let howlongagoMS = howlongago % 1000; let howlongagoSec = Math.floor(((howlongago - howlongagoMS) % 60000)/1000); let howlongagoMin = Math.floor(((howlongago - howlongagoSec - howlongagoMS) % 3600000)/ 60000); let howlongagoHr = Math.floor(((howlongago - howlongagoMin - howlongagoSec - howlongagoMS) % 216000000)/ 3600000); let timeliteral = ''; if (howlongagoHr < 1 && howlongagoMin < 1) { timeliteral = howlongagoSec + ' sec ago'; } else if (howlongagoHr < 1) { if (howlongagoSec < 1) { timeliteral = howlongagoMin + ' min ago'; } else { timeliteral = howlongagoMin + ' min ' + howlongagoSec + ' sec ago'; } } else { if (howlongagoMin < 1) { timeliteral = howlongagoHr + ' hr ago'; } else { timeliteral = howlongagoHr + ' hr ' + howlongagoMin + ' min ago'; } } return timeliteral; } //********** Tip Count Functions ************** function populateTipCountArray(user,tip) { tipCountArray.name.push(user); tipCountArray.amount.push(tip); } function findTipper(user) { for (var ftidx = 0; ftidx < tipCountArray.name.length; ftidx++) { if (tipCountArray.name[ftidx] == user) { break; } } return ftidx; } //********** Check Username Function ************** function checkUsername(ckusermessage,chkuser) { let responsemessagearray = ckusermessage.split(' '); let userreplace = false; if (cbjs.arrayContains(responsemessagearray,'{username}')) { let cumsgindex = responsemessagearray.indexOf('{username}'); responsemessagearray[cumsgindex] = chkuser; userreplace = true; } else if (cbjs.arrayContains(responsemessagearray,'{username},')) { let cumsgindex2 = responsemessagearray.indexOf('{username},'); responsemessagearray[cumsgindex2] = chkuser + ','; userreplace = true; } else if (cbjs.arrayContains(responsemessagearray,'{username}!')) { let cumsgindex3 = responsemessagearray.indexOf('{username}!'); responsemessagearray[cumsgindex3] = chkuser + '!'; userreplace = true; } else if (cbjs.arrayContains(responsemessagearray,'{username}:')) { let cumsgindex4 = responsemessagearray.indexOf('{username}:'); responsemessagearray[cumsgindex4] = chkuser + ':'; userreplace = true; } else if (cbjs.arrayContains(responsemessagearray,'{username}.')) { let cumsgindex5 = responsemessagearray.indexOf('{username}.'); responsemessagearray[cumsgindex5] = chkuser + '.'; userreplace = true; } if (userreplace) { return cbjs.arrayJoin(responsemessagearray,' '); } else { return ckusermessage; } } //********** Check for Recent Auto-response ************** function checkRecentAutoResponse(autotype) { let chkrecenttimecalc = new Date(); let howlongago = 0; if (autotype == 'PM') { if (pmRequestTime == 0) { pmRequestTime = chkrecenttimecalc.getTime(); return false; } else { howlongago = (chkrecenttimecalc.getTime() - pmRequestTime); if (howlongago < 30000) { return true; } else { pmRequestTime = chkrecenttimecalc.getTime(); return false; } } } else if (autotype == 'private') { if (prvRequestTime == 0) { prvRequestTime = chkrecenttimecalc.getTime(); return false; } else { howlongago = (chkrecenttimecalc.getTime() - prvRequestTime); if (howlongago < 30000) { return true; } else { prvRequestTime = chkrecenttimecalc.getTime(); return false; } } } else if (autotype == 'auto1') { if (auto1RequestTime == 0) { auto1RequestTime = chkrecenttimecalc.getTime(); return false; } else { howlongago = (chkrecenttimecalc.getTime() - auto1RequestTime); if (howlongago < 30000) { return true; } else { auto1RequestTime = chkrecenttimecalc.getTime(); return false; } } } else if (autotype == 'auto2') { if (auto2RequestTime == 0) { auto2RequestTime = chkrecenttimecalc.getTime(); return false; } else { howlongago = (chkrecenttimecalc.getTime() - auto2RequestTime); if (howlongago < 30000) { return true; } else { auto2RequestTime = chkrecenttimecalc.getTime(); return false; } } } else if (autotype == 'auto3') { if (auto3RequestTime == 0) { auto3RequestTime = chkrecenttimecalc.getTime(); return false; } else { howlongago = (chkrecenttimecalc.getTime() - auto3RequestTime); if (howlongago < 30000) { return true; } else { auto3RequestTime = chkrecenttimecalc.getTime(); return false; } } } } //********** Check Next Line Function ************** function checkNextLine(nlmessage) { let nlmessagearray = nlmessage.split(' '); let nllinearray = []; let templinearray = []; let lineidx = 0; let currlineidx = 0; let nlreplace = false; let nlsubfound = true; while (nlsubfound) { if (cbjs.arrayContains(nlmessagearray,'{n}')) { let nlmsgindex = nlmessagearray.indexOf('{n}'); nlmessagearray[nlmsgindex] = '\n'; templinearray = nlmessagearray.slice(currlineidx,nlmsgindex); nllinearray[lineidx] = wordWrap(cbjs.arrayJoin(templinearray,' ')); templinearray = nlmessagearray.slice(nlmsgindex+1); nllinearray[lineidx+1] = wordWrap(cbjs.arrayJoin(templinearray,' ')); lineidx++; currlineidx = nlmsgindex+1; nlreplace = true; } else { nlsubfound = false; } } if (nlreplace) { return cbjs.arrayJoin(nllinearray,'\n'); } else { return wordWrap(nlmessage); } } function wordWrap(wrapstring) { if (wrapMaxLength > 0) { let newlinechar = '\n'; let splitstring = ''; while (wrapstring.length > wrapMaxLength) { let spacefound = false; for (let wwidx = wrapMaxLength - 1; wwidx >= 0; wwidx--) { if (testWhite(wrapstring.charAt(wwidx))) { splitstring = splitstring + [wrapstring.slice(0, wwidx), newlinechar].join(''); wrapstring = wrapstring.slice(wwidx + 1); spacefound = true; break; } } if (!spacefound) { splitstring += [wrapstring.slice(0, wrapMaxLength), newlinechar].join(''); wrapstring = wrapstring.slice(wrapMaxLength); } } return splitstring + wrapstring; } else { return wrapstring; } } function testWhite(whitestring) { let white = new RegExp(/^\s$/); return white.test(whitestring.charAt(0)); } //********** 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(setcapopt, setcapby) { if (setcapopt == 'on') { if (suppressCapsToggle == true) { cb.sendNotice('The Caps Lock Suppression is already turned on.',setcapby,appNoticeColor); } else { suppressCapsToggle = true; cb.sendNotice('You have enabled the Caps Lock Suppression.',setcapby,appNoticeColor); } } else if (setcapopt == 'off') { if (suppressCapsToggle == false) { cb.sendNotice('The Caps Lock Suppression is already turned off.',setcapby,appNoticeColor); } else { suppressCapsToggle = false; cb.sendNotice('You have disabled the Caps Lock Suppression.',setcapby,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(setlbmode,setlbby,setlbbycmd) { if (setlbmode == 'on') { if (leaderboardToggle) { cb.sendNotice('The Leaderboard display is already turned on.', setlbby, appNoticeColor); } else { leaderboardToggle = true; cb.setTimeout(leaderboardTimer,leaderInt); if (setlbbycmd) { cb.sendNotice('You have enabled the Leaderboard display.', setlbby, appNoticeColor); } } } else if (setlbmode == 'off') { if (!leaderboardToggle) { cb.sendNotice('The Leaderboard display is already turned off.', setlbby, appNoticeColor); } else { leaderboardToggle = false; cb.sendNotice('You have disabled the Leaderboard display. Tip leaders are still tracked but the board is not displayed.', setlbby, appNoticeColor); } } else if (setlbmode != null) { cb.sendNotice(setlbmode + ' is not a valid option for /useleaderboard.', setlbby, appNoticeColor); } else if (setlbmode == null) { cb.sendNotice('You did not enter a valid option for /useleaderboard.', setlbby, appNoticeColor); } } function setLeaderBoardColors(lbcolorsby,stupflag) { if (cb.settings.leaderTextColor == 'Custom') { leaderTextColor = setTextColor(cb.settings.leaderTextCustColor,'Leaderboard',lbcolorsby,stupflag); } else { leaderTextColor = setTextColor(cb.settings.leaderTextColor,'Leaderboard',lbcolorsby,stupflag); } if (cb.settings.leaderBgColor == 'Custom') { leaderBgColor = setBgColor(cb.settings.leaderBgCustColor,'Leaderboard',lbcolorsby,stupflag); } else { leaderBgColor = setBgColor(cb.settings.leaderBgColor,'Leaderboard',lbcolorsby,stupflag); } } function leaderboardTimer() { if (leaderboardToggle) { 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) { let leaderboardstring = borderLeaderboardTop; if (showleadmode == 'me') { leaderboardstring += '\nSent to YOU:'; } else if (showleadmode == 'all') { leaderboardstring += '\nSent to ALL:'; } if (tipCountArray.name.length > 0) { var maxlbdisp = leaderSize; var numberunique = 0; if (cb.settings.leaderUniqueTippers == 'Yes') { numberunique = tipCountArray.name.length; } 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'; } if (numberunique > 0) { leaderboardstring += '\nNumber of Unique Tippers: ' + numberunique; } leaderboardstring += borderLeaderboardBottom; cb.sendNotice(leaderboardstring, showleadto, leaderBgColor, leaderTextColor, boldTextLiteral); } 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(stsentfrom,stgroup,stnumtippers,stsendto,stsendtoname) { let tipperliststring = ''; switch (stsendto) { case 'all': tipperliststring = 'SENT TO ALL:\n'; break; case 'mods': tipperliststring = 'SENT TO MODS BY: ' + stsentfrom + '\n'; break; case 'tbm': tipperliststring = 'SENT TO MODS AND BROADCASTER BY: ' + stsentfrom + '\n'; break; case 'bc': tipperliststring = 'SENT TO YOU BY: ' + stsentfrom + '\n'; break; default: tipperliststring = 'SENT TO YOU:\n'; break; } tipperliststring += dashLine60 + '\n\u25ba \u25ba \u25ba TOP ' + stnumtippers + ' TIPPER LIST \u25c4 \u25c4 \u25c4\n' + dashLine60 + '\n'; if (tipCountArray.name.length > 0) { let numtippersindex = stnumtippers; if (tipCountArray.name.length < stnumtippers) { numtippersindex = tipCountArray.name.length; } for (let tlistidx = 1; tlistidx <= numtippersindex; tlistidx++) { if (tipCountArray.name[tlistidx - 1] == null) { tipperliststring += '\u25ba ' + tlistidx + '. --\n'; } else { tipperliststring += '\u25ba ' + tlistidx + '. "' + tipCountArray.name[tlistidx - 1] + '" : ' + tipCountArray.amount[tlistidx - 1] + '\n'; } } } else { tipperliststring += '\u25ba No Tippers Yet.'; } cb.sendNotice(tipperliststring, stsendtoname, '', '', boldTextLiteral, stgroup); } function populateModeratorArray(popuser,poptype,popmode) { if (popmode == 'a') { if (poptype == 'cbmod' && cbjs.arrayContains(moderatorList.name,popuser)) { let popmodidx = moderatorList.name.indexOf(popuser); if (moderatorList.type[popmodidx] == 'botmod') { moderatorList.name.splice(popmodidx,1); moderatorList.type.splice(popmodidx,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)) { let popmodidx2 = moderatorList.name.indexOf(popuser); if (moderatorList.type[popmodidx2] == 'botmod') { moderatorList.name.splice(popmodidx2,1); moderatorList.type.splice(popmodidx2,1); } } else if (poptype == 'cbmod' && cbjs.arrayContains(moderatorList.name,popuser)) { let popmodidx3 = moderatorList.name.indexOf(popuser); if (moderatorList.type[popmodidx3] == 'cbmod') { moderatorList.name.splice(popmodidx3,1); moderatorList.type.splice(popmodidx3,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 + '.', BC, appNoticeColor); cb.sendNotice('The silence level has been set to ' + level + '.', BC, appNoticeColor, '', '', 'red'); manualSilenceLvlUpd = true; if (cb.settings.autoUpdateSLGL != 'No') { cb.sendNotice('Since the silence level has been manually updated, the room size monitor will no longer update it automatically.', BC, appNoticeColor); cb.sendNotice('Since the silence level has been manually updated, the room size monitor will no longer update it automatically.', BC, appNoticeColor, '', '', 'red'); } switch (level) { case 0: cb.sendNotice('All members can talk in chat.', BC, appNoticeColor); cb.sendNotice('All members can talk in chat.', BC, appNoticeColor, '', '', 'red'); break; case 1: cb.sendNotice('Only members with tokens can talk in chat.', BC, appNoticeColor); cb.sendNotice('Only members with tokens can talk in chat.', BC, appNoticeColor, '', '', 'red'); break; case 2: cb.sendNotice('Only members who have tipped can talk in chat.', BC, appNoticeColor); cb.sendNotice('Only members who have tipped can talk in chat.', BC, appNoticeColor, '', '', 'red'); break; case 3: cb.sendNotice('Only members who have tipped at least ' + minTipToChat + ' tokens can talk in chat.', BC, appNoticeColor); cb.sendNotice('Only members who have tipped at least ' + minTipToChat + ' tokens can talk in chat.', BC, appNoticeColor, '', '', 'red'); break; case 4: cb.sendNotice('Only Moderators, Fans, and VIPs can chat.', BC, appNoticeColor); cb.sendNotice('Only Moderators, Fans, and VIPs can chat.', BC, appNoticeColor, '', '', 'red'); break; } } function setGraphicLevel(level, mod) { graphicLevel = level; cb.sendNotice('The graphic level has been set to ' + level + '.', BC, appNoticeColor); cb.sendNotice('The graphic level has been set to ' + level + '.', BC, appNoticeColor, '', '', 'red'); manualGraphicLvlUpd = true; if (cb.settings.autoUpdateSLGL != 'No') { cb.sendNotice('Since the graphics level has been manually updated, the room size monitor will no longer update it automatically.', BC, appNoticeColor); cb.sendNotice('Since the graphics level has been manually updated, the room size monitor will no longer update it automatically.', BC, appNoticeColor, '', '', 'red'); } switch (level) { case 0: cb.sendNotice('All members can use graphics in chat.', BC,appNoticeColor); cb.sendNotice('All members can use graphics in chat.', BC, appNoticeColor, '', '', 'red'); break; case 1: cb.sendNotice('Only members with tokens can use graphics in chat.', BC, appNoticeColor); cb.sendNotice('Only members with tokens can use graphics in chat.', BC, appNoticeColor, '', '', 'red'); break; case 2: cb.sendNotice('Only members who have tipped can use graphics in chat.', BC, appNoticeColor); cb.sendNotice('Only members who have tipped can use graphics in chat.', BC, appNoticeColor, '', '', 'red'); break; case 3: cb.sendNotice('Only members who have tipped at least ' + minTipToChat + ' tokens can use graphics in chat.', BC, appNoticeColor); cb.sendNotice('Only members who have tipped at least ' + minTipToChat + ' tokens can use graphics in chat.', BC, appNoticeColor, '', '', 'red'); break; case 4: cb.sendNotice('Only Moderators, Fans, and VIPs can use graphics in chat.', BC, appNoticeColor); cb.sendNotice('Only Moderators, Fans, and VIPs can use graphics in chat.', BC, appNoticeColor, '', '', 'red'); break; } } //********** List Maintenance Functions ************** function validateUserID(validateuser,validatetype,validateby,validatestartup) { if (validateuser.length < 3 || validateuser.includes(' ')) { if (validatestartup) { botLoadErrors.push('Cannot load ' + validatetype + ' entry "' + validateuser + '", it is improperly formatted (either contains a blank or is less than 3 characters).'); } else { cb.sendNotice(botName + 'Cannot load ' + validatetype + ' entry "' + validateuser + '", it is improperly formatted (either contains a blank or is less than 3 characters).', validateby, appWarningColor); } return false; } else if (checkSpecial.test(validateuser)) { if (validatestartup) { botLoadErrors.push('Cannot load ' + validatetype + ' entry "' + validateuser + '", it contains a special character.'); } else { cb.sendNotice(botName + 'Cannot load ' + validatetype + ' entry "' + validateuser + '", it contains a special character.', validateby, appWarningColor); } return false; } else { return true; } } 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 == BC) { 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 == BC) { 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(blockwordadd,mod,mode) { if (mode == 'a') { if (cbjs.arrayContains(wordListArrayPub,blockwordadd)) { cb.sendNotice(blockwordadd + ' has already been added to the Public Blocked Word list.', mod, appNoticeColor); } else { wordListArrayPub.push(blockwordadd); cb.sendNotice('You have added "' + blockwordadd + '" 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,blockwordadd)) { cbjs.arrayRemove(wordListArrayPub,blockwordadd); cb.sendNotice('You have removed "' + blockwordadd + '" 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('"' + blockwordadd + '" is not on the Public Blocked Word list.', mod, appNoticeColor); } if (mod == BC) { if (cbjs.arrayContains(wordListArray,blockwordadd)) { cbjs.arrayRemove(wordListArray,blockwordadd); cb.sendNotice('You have removed "' + blockwordadd + '" 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('"' + blockwordadd + '" 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)) { let 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)) { let 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, '', boldTextLiteral); break; case 1: cb.sendNotice('\u23f1 \u23f1 \u23f1 There is 1 minute left on Timer #1 ' + (timerDesc != '' ? ('until ' + timerDesc) : '') + '!! \u23f1 \u23f1 \u23f1', '', red, '', boldTextLiteral); 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, '', boldTextLiteral); break; case 1: cb.sendNotice('\u23f1 \u23f1 \u23f1 There is 1 second left on Timer #1 ' + (timerDesc != '' ? ('until ' + timerDesc) : '') + ' \u23f1 \u23f1 \u23f1', '', red, '', boldTextLiteral); break; } } if (clockSecsRemain < 1) { if (clockMinsRemain >= 1) { clockTimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Timer #1: Time is up! \u23f0 \u23f0 \u23f0', '', appWarningColor, '', boldTextLiteral); timerDesc = ''; } } else { clockSecsRemain--; cb.setTimeout(clockTimerSec, 1000); } } } function clockAddTime(clocktimetoadd) { clockStopTime = new Date(clockStopTime.getTime() + parseInt(clocktimetoadd*60000)); let timetoaddabs = Math.abs(clocktimetoadd); let minstoaddabs = parseInt(timetoaddabs); let minstoadd = parseInt(clocktimetoadd); let secstoaddabs = parseInt((timetoaddabs-minstoaddabs)*60); clockMinsRemain = clockMinsRemain + minstoadd; if (clocktimetoadd > 0) { if ((clockSecsRemain+secstoaddabs) >=60) { clockMinsRemain++; clockSecsRemain = ((clockSecsRemain+secstoaddabs)-60); } else { clockSecsRemain = clockSecsRemain+secstoaddabs; } } else { if (secstoaddabs >= clockSecsRemain) { clockMinsRemain--; clockSecsRemain = (60-(secstoaddabs-clockSecsRemain)); } else { clockSecsRemain = clockSecsRemain-secstoaddabs; } } if (secstoaddabs == 0) { cb.sendNotice(minstoaddabs + ' minute' + (minstoaddabs == 1 ? ' has' : 's have') + ' been ' + (clocktimetoadd > 0 ? 'added to' : 'subtracted from') + ' Timer #1. \nNow ' + clockTimeLeft(), '', appWarningColor,'', boldTextLiteral); } else { if (minstoaddabs > 0) { cb.sendNotice(minstoaddabs + ' minute' + (minstoaddabs == 1 ? ' and ' : 's and ') + secstoaddabs + ' second' + (secstoaddabs == 1 ? '' : 's') + ' have been ' + (clocktimetoadd > 0 ? 'added to' : 'subtracted from') + ' Timer #1. \nNow ' + clockTimeLeft(), '', appWarningColor,'', boldTextLiteral); } else { cb.sendNotice(secstoaddabs + ' second' + (secstoaddabs == 1 ? ' has' : 's have') + ' been ' + (clocktimetoadd > 0 ? 'added to' : 'subtracted from') + ' Timer #1. \nNow ' + clockTimeLeft(), '', appWarningColor,'', boldTextLiteral); } } 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,'', boldTextLiteral); } } function clockTimeLeft() { let temptimeleft = clockTimeCal(); let temptimems = temptimeleft % 1000; let temptimesec = ((temptimeleft - temptimems) % 60000); let temptimemin = ((temptimeleft - temptimesec - temptimems) % 3600000); let temptimehr = (temptimeleft - temptimemin - temptimesec - temptimems); temptimesec = temptimesec / 1000; temptimemin = temptimemin / 60000; temptimehr = temptimehr / 3600000; if (temptimehr > 0) { return temptimehr + ' hour' + (temptimehr > 1 ? 's' : '') + ' and ' + temptimemin + ' minute' + (temptimemin > 1 ? 's' : '') + ' remaining on Timer #1.'; } else if (temptimemin > 0 && temptimesec === 0) { return temptimemin + ' minute' + (temptimemin > 1 ? 's' : '') + ' remaining on Timer #1.'; } else if (temptimemin > 0) { return temptimemin + ' minute' + (temptimemin > 1 ? 's' : '') + ' and ' + temptimesec + ' second' + (temptimesec > 1 ? 's' : '') + ' remaining on Timer #1.'; } else { return temptimesec + ' second' + (temptimesec > 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, '', boldTextLiteral); break; case 1: cb.sendNotice('\u2777 \u231A \u2777 There is 1 minute left on Timer #2 ' + (timer2Desc != '' ? ('until ' + timer2Desc) : '') + '!! \u2777 \u231A \u2777', '', lightmagenta, '', boldTextLiteral); 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, '', boldTextLiteral); break; case 1: cb.sendNotice('\u2777 \u231A \u2777 There is 1 second left on Timer #2 ' + (timer2Desc != '' ? ('until ' + timer2Desc) : '') + ' \u2777 \u231A \u2777', '', lightmagenta, '', boldTextLiteral); break; } } if (clock2SecsRemain < 1) { if (clock2MinsRemain >= 1) { clock2TimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Timer #2: Time is up! \u23f0 \u23f0 \u23f0', '', lightblue, '', boldTextLiteral); timer2Desc = ''; } } else { clock2SecsRemain--; cb.setTimeout(clock2TimerSec, 1000); } } } function clock2AddTime(clock2timetoadd) { clock2StopTime = new Date(clock2StopTime.getTime() + clock2timetoadd * 60000); let 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,'', boldTextLiteral); } else { cb.sendNotice(timetoaddabs2 + ' minute' + (timetoaddabs2 == 1 || timetoaddabs2 == -1 ? ' has' : 's have') + ' been subtracted from Timer #2. Now ' + clock2TimeLeft(), '', lightblue,'', boldTextLiteral); } 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, '', boldTextLiteral); } } function clock2TimeLeft() { let temptimeleft2 = clock2TimeCal(); let temptimems2 = temptimeleft2 % 1000; let temptimesec2 = ((temptimeleft2 - temptimems2) % 60000); let temptimemin2 = ((temptimeleft2 - temptimesec2 - temptimems2) % 3600000); let temptimehr2 = (temptimeleft2 - temptimemin2 - temptimesec2 - temptimems2); temptimesec2 = temptimesec2 / 1000; temptimemin2 = temptimemin2 / 60000; temptimehr2 = temptimehr2 / 3600000; if (temptimehr2 > 0) { return temptimehr2 + ' hour' + (temptimehr2 > 1 ? 's' : '') + ' and ' + temptimemin2 + ' minute' + (temptimemin2 > 1 ? 's' : '') + ' remaining on Timer #2.'; } else if (temptimemin2 > 0 && temptimesec2 === 0) { return temptimemin2 + ' minute' + (temptimemin2 > 1 ? 's' : '') + ' remaining on Timer #2.'; } else if (temptimemin2 > 0) { return temptimemin2 + ' minute' + (temptimemin2 > 1 ? 's' : '') + ' and ' + temptimesec2 + ' second' + (temptimesec2 > 1 ? 's' : '') + ' remaining on Timer #2.'; } else { return temptimesec2 + ' second' + (temptimesec2 > 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, '', boldTextLiteral); break; case 1: cb.sendNotice('\u2778 \u231A \u2778 There is 1 minute left on Timer #3 ' + (timer3Desc != '' ? ('until ' + timer3Desc) : '') + '!! \u2778 \u231A \u2778', '', lightmagenta, '', boldTextLiteral); 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, '', boldTextLiteral); break; case 1: cb.sendNotice('\u2778 \u231A \u2778 There is 1 second left on Timer #3 ' + (timer3Desc != '' ? ('until ' + timer3Desc) : '') + ' \u2778 \u231A \u2778', '', lightmagenta, '', boldTextLiteral); break; } } if (clock3SecsRemain < 1) { if (clock3MinsRemain >= 1) { clock3TimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Timer #3: Time is up! \u23f0 \u23f0 \u23f0', '', lightblue, '', boldTextLiteral); timer3Desc = ''; } } else { clock3SecsRemain--; cb.setTimeout(clock3TimerSec, 1000); } } } function clock3AddTime(clock3timetoadd) { clock3StopTime = new Date(clock3StopTime.getTime() + clock3timetoadd * 60000); let 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,'', boldTextLiteral); } else { cb.sendNotice(timetoaddabs3 + ' minute' + (timetoaddabs3 == 1 || timetoaddabs3 == -1 ? ' has' : 's have') + ' been subtracted from Timer #3. Now ' + clock3TimeLeft(), '', lightblue,'', boldTextLiteral); } 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, '', boldTextLiteral); } } function clock3TimeLeft() { let temptimeleft3 = clock3TimeCal(); let temptimems3 = temptimeleft3 % 1000; let temptimesec3 = ((temptimeleft3 - temptimems3) % 60000); let temptimemin3 = ((temptimeleft3 - temptimesec3 - temptimems3) % 3600000); let temptimehr3 = (temptimeleft3 - temptimemin3 - temptimesec3 - temptimems3); temptimesec3 = temptimesec3 / 1000; temptimemin3 = temptimemin3 / 60000; temptimehr3 = temptimehr3 / 3600000; if (temptimehr3 > 0) { return temptimehr3 + ' hour' + (temptimehr3 > 1 ? 's' : '') + ' and ' + temptimemin3 + ' minute' + (temptimemin3 > 1 ? 's' : '') + ' remaining on Timer #3.'; } else if (temptimemin3 > 0 && temptimesec3 === 0) { return temptimemin3 + ' minute' + (temptimemin3 > 1 ? 's' : '') + ' remaining on Timer #3.'; } else if (temptimemin3 > 0) { return temptimemin3 + ' minute' + (temptimemin3 > 1 ? 's' : '') + ' and ' + temptimesec3 + ' second' + (temptimesec3 > 1 ? 's' : '') + ' remaining on Timer #3.'; } else { return temptimesec3 + ' second' + (temptimesec3 > 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, '', boldTextLiteral); break; case 1: cb.sendNotice('\u2779 \u231A \u2779 There is 1 minute left on Timer #4 ' + (timer4Desc != '' ? ('until ' + timer4Desc) : '') + '!! \u2779 \u231A \u2779', '', lightmagenta, '', boldTextLiteral); 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, '', boldTextLiteral); break; case 1: cb.sendNotice('\u2779 \u231A \u2779 There is 1 second left on Timer #4 ' + (timer4Desc != '' ? ('until ' + timer4Desc) : '') + ' \u2779 \u231A \u2779', '', lightmagenta, '', boldTextLiteral); break; } } if (clock4SecsRemain < 1) { if (clock4MinsRemain >= 1) { clock4TimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Timer #4: Time is up! \u23f0 \u23f0 \u23f0', '', lightblue, '', boldTextLiteral); timer4Desc = ''; } } else { clock4SecsRemain--; cb.setTimeout(clock4TimerSec, 1000); } } } function clock4AddTime(clock4timetoadd) { clock4StopTime = new Date(clock4StopTime.getTime() + clock4timetoadd * 60000); let 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,'', boldTextLiteral); } else { cb.sendNotice(timetoaddabs4 + ' minute' + (timetoaddabs4 == 1 || timetoaddabs4 == -1 ? ' has' : 's have') + ' been subtracted from Timer #4. Now ' + clock4TimeLeft(), '', lightblue,'', boldTextLiteral); } 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, '', boldTextLiteral); } } function clock4TimeLeft() { let temptimeleft4 = clock4TimeCal(); let temptimems4 = temptimeleft4 % 1000; let temptimesec4 = ((temptimeleft4 - temptimems4) % 60000); let temptimemin4 = ((temptimeleft4 - temptimesec4 - temptimems4) % 3600000); let temptimehr4 = (temptimeleft4 - temptimemin4 - temptimesec4 - temptimems4); temptimesec4 = temptimesec4 / 1000; temptimemin4 = temptimemin4 / 60000; temptimehr4 = temptimehr4 / 3600000; if (temptimehr4 > 0) { return temptimehr4 + ' hour' + (temptimehr4 > 1 ? 's' : '') + ' and ' + temptimemin4 + ' minute' + (temptimemin4 > 1 ? 's' : '') + ' remaining on Timer #4.'; } else if (temptimemin4 > 0 && temptimesec4 === 0) { return temptimemin4 + ' minute' + (temptimemin4 > 1 ? 's' : '') + ' remaining on Timer #4.'; } else if (temptimemin4 > 0) { return temptimemin4 + ' minute' + (temptimemin4 > 1 ? 's' : '') + ' and ' + temptimesec4 + ' second' + (temptimesec4 > 1 ? 's' : '') + ' remaining on Timer #4.'; } else { return temptimesec4 + ' second' + (temptimesec4 > 1 ? 's' : '') + ' remaining on Timer #4.'; } } //********** Chat Notice Functions ************** function sendPublicNotice (spnmessage, spnuser, spntype) { if (spnmessage) { switch (spntype) { case 'div': cb.sendNotice(dashLine80 + '\n\u25ba ' + spnmessage.capitalize() + '\n' + dashLine80, '', '', noticeTextColor, 'bold'); break; case 'divh': cb.sendNotice(dashLine80 + '\n\u25ba ' + spnmessage.capitalize() + '\n' + dashLine80, '', noticeBgColor, noticeTextColor, 'bold'); break; case 'h': cb.sendNotice('\u25ba ' + spnmessage.capitalize(), '', noticeBgColor, noticeTextColor, 'bold'); break; case '': cb.sendNotice('\u25ba ' + spnmessage.capitalize(), '', '', noticeTextColor, 'bold'); break; } } else { cb.sendNotice('You can\'t send a blank message. Type a message and try again.', spnuser, appNoticeColor); } } //********** PM Functions ************** function sendPrivateNotice(pvtmessage, pvtuser, pvttype, pvtdest) { if (pvtmessage) { switch (pvttype) { case 'tm': if (pvtuser == BC) { cb.sendNotice('\u261b PM - You to mods: ' + pvtmessage, BC, TMgreenB, TMgreenF, 'bold'); cb.sendNotice('\u261b PM - ' + BC + ' to mods: ' + pvtmessage, BC, TMgreenB, TMgreenF, 'bold', 'red'); for (let modindex = 0; modindex < moderatorList.name.length; modindex++) { if (moderatorList.type[modindex] == 'botmod') { let sendtotm = moderatorList.name[modindex].trim(); cb.sendNotice('\u261b PM - ' + BC + ' to mods: ' + pvtmessage, sendtotm, TMgreenB, TMgreenF, 'bold'); } } } else { cb.sendNotice('\u261b PM - ' + pvtuser + ' to mods: ' + pvtmessage, BC, TMgreenB, TMgreenF, 'bold', 'red'); for (let modindex = 0; modindex < moderatorList.name.length; modindex++) { if (moderatorList.type[modindex] == 'botmod') { let sendtotm2 = moderatorList.name[modindex].trim(); cb.sendNotice('\u261b PM - ' + pvtuser + ' to mods: ' + pvtmessage, sendtotm2, TMgreenB, TMgreenF, 'bold'); } } } break; case 'bc': cb.sendNotice('\u261b PM - ' + pvtuser + ' to you: ' + pvtmessage, BC, BCpurpleB, BCpurpleF, 'bold'); cb.sendNotice('\u261b PM - You to ' + BC + ': ' + pvtmessage, pvtuser, BCpurpleB, BCpurpleF, 'bold'); break; case 'tbm': if (pvtuser == BC) { cb.sendNotice('\u261b PM - You to mods: ' + pvtmessage, BC, TBMblueB, TBMblueF, 'bold'); cb.sendNotice('\u261b PM - ' + BC + ' to mods: ' + pvtmessage, BC, TBMblueB, TBMblueF, 'bold', 'red'); for (let modindex = 0; modindex < moderatorList.name.length; modindex++) { if (moderatorList.type[modindex] == 'botmod') { let sendtotbm = moderatorList.name[modindex].trim(); cb.sendNotice('\u261b PM - ' + BC + ' to mods: ' + pvtmessage, sendtotbm, TBMblueB, TBMblueF, 'bold'); } } } else { cb.sendNotice('\u261b PM - ' + pvtuser + ' to ' + BC + ' and mods: ' + pvtmessage, BC, TBMblueB, TBMblueF, 'bold', 'red'); cb.sendNotice('\u261b PM - ' + pvtuser + ' to you and mods: ' + pvtmessage, BC, TBMblueB, TBMblueF, 'bold'); for (let modindex = 0; modindex < moderatorList.name.length; modindex++) { if (moderatorList.type[modindex] == 'botmod') { let sendtotbm2 = moderatorList.name[modindex].trim(); cb.sendNotice('\u261b PM - ' + pvtuser + ' to ' + BC + ' and mods: ' + pvtmessage, sendtotbm2, TBMblueB, TBMblueF, 'bold'); } } } break; case 'pm': if (pvtdest) { cb.sendNotice('\u261b PM - ' + pvtuser + ': ' + pvtmessage, pvtdest, PMaquaB, PMaquaF, 'bold'); cb.sendNotice('\u261b PM - You to ' + pvtdest + ': ' + pvtmessage, pvtuser, PMaquaB, PMaquaF, 'bold'); pmArray[findPM(pvtdest)][1] = pvtuser; } 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.', pvtuser, appNoticeColor); } } function findPM(fpmuser) { for(var i = 0; i < pmArray.length; i++) { if(pmArray[i][0] == fpmuser) { break; } } if(i == pmArray.length) { pmArray[numPMs] = new Array; pmArray[numPMs][0] = fpmuser; pmArray[numPMs][1] = ''; numPMs++; findPM(fpmuser); } return i; } function sendReply(replymessage, replyfrom) { if (pmArray[findPM(replyfrom)][1] != '') { let srfullmsg = replyfrom + ': '; let srmsg = ''; for (let sndrepidx = 1; sndrepidx < replymessage.length; sndrepidx++) { if (sndrepidx == 1) { srmsg += replymessage[sndrepidx]; srfullmsg += replymessage[sndrepidx]; } else { srmsg += ' ' + replymessage[sndrepidx]; srfullmsg += ' ' + replymessage[sndrepidx]; } } let replyto = pmArray[findPM(replyfrom)][1] pmArray[findPM(replyto)][1] = replyfrom; cb.sendNotice('\u261b ' + srfullmsg, replyto, PMaquaB, PMaquaF, 'bold'); cb.sendNotice('\u261b You to ' + replyto + ': ' + srmsg, replyfrom, PMaquaB, PMaquaF, 'bold'); } else { cb.sendNotice('No one has PM\'d you.', replyfrom, appNoticeColor); } } //********** Notifier Functions ************** function setNotifierToggle(snmode,snsetby,snbycmd) { if (snmode == 'on') { if (notifierToggle) { cb.sendNotice('The Notifier toggle is already turned on.', snsetby, appNoticeColor); } else { notifierToggle = true; notifierRotateCount = 0; notifierTotalCount = 0; cb.setTimeout(displayNotifiers,notifierInt); if (snbycmd) { cb.sendNotice('You have enabled the display of the rotating notifier messages.', snsetby, appNoticeColor); } } } else if (snmode == 'off') { if (!notifierToggle) { cb.sendNotice('The Notifier toggle is already turned off.', snsetby, appNoticeColor); } else { notifierToggle = false; cb.sendNotice('You have disabled the display of the rotating notifier messages.', snsetby, appNoticeColor); } } } function setNoticeColor(notifiercolorby,stupflag) { if (cb.settings.notifiersTextColor == 'Custom') { noticeTextColor = setTextColor(cb.settings.notifiersTextCustColor,'Notifiers',notifiercolorby,stupflag); } else { noticeTextColor = setTextColor(cb.settings.notifiersTextColor,'Notifiers',notifiercolorby,stupflag); } if (cb.settings.notifiersBgColor == 'Custom') { noticeBgColor = setBgColor(cb.settings.notifiersBgCustColor,'Notifiers',notifiercolorby,stupflag); } else { noticeBgColor = setBgColor(cb.settings.notifiersBgColor,'Notifiers',notifiercolorby,stupflag); } } function displayNotifiers() { if (notifierToggle) { if (minMessagesForNotice > 0 && msgCounterNotifier < minMessagesForNotice) { cb.setTimeout(displayNotifiers, 30000); } else { msgCounterNotifier = 0; var notifierfound = false; if (notifierRotateCount > 10) { notifierRotateCount = 1; } if (notifierArray[notifierRotateCount-1]) { displayOneNotifier(notifierRotateCount-1); notifierfound = true; } notifierRotateCount++; notifierTotalCount++; if (notifierfound) { notifierTotalCount = 1; cb.setTimeout(displayNotifiers,notifierInt); } else { if (notifierTotalCount > 10) { cb.sendNotice(botName + ' Warning! Notifier enabled, but no notifications configured, disabling the notifier. You can use the command "/chgmsg" to configure notifiers and then turn on notifications again with "/notifier on", or you can restart the bot and configure at least one notifier.', BC, appNoticeColor); notifierToggle = false; } else { displayNotifiers(); } } } } } function displayOneNotifier(notenum) { let notifiermsg = ''; if (cb.settings.noticeSepStyle != 'No Border') { notifiermsg += borderAllNoticesTop; } notifiermsg += checkNextLine(notifierArray[notenum]); if (cb.settings.noticeSepStyle != 'No Border') { notifiermsg += borderUniversalBottom; } cb.sendNotice(notifiermsg, '', noticeBgColor, noticeTextColor, boldTextLiteral); } //********** Show Summary Functions ************** function setShowSummaryToggle(ssmode,sssetby,ssbycmd) { if (ssmode == 'on') { if (showSummaryToggle) { cb.sendNotice('The Show Summary toggle is already turned on.', sssetby, appNoticeColor); } else { showSummaryToggle = true; cb.setTimeout(displayShowSummaryTimer,showSummaryInt); if (ssbycmd) { cb.sendNotice('You have enabled the display of the Show Summary message.', sssetby, appNoticeColor); } } } else if (ssmode == 'off') { if (!showSummaryToggle) { cb.sendNotice('The Show Summary toggle is already turned off.', sssetby, appNoticeColor); } else { showSummaryToggle = false; cb.sendNotice('You have disabled the display of the Show Summary messages.', sssetby, appNoticeColor); } } } function displayShowSummaryTimer() { if (showSummaryToggle) { if (minMessagesForNotice > 0 && msgCounterSummary < minMessagesForNotice) { cb.setTimeout(displayShowSummaryTimer, 30000); } else { msgCounterSummary = 0; displayShowSummary(''); cb.setTimeout(displayShowSummaryTimer,showSummaryInt); } } } function displayShowSummary(sssendto) { let summarymsg = borderSummaryTop; summarymsg += '\n' + wordWrap('Welcome! You can participate in the show by making use of the following features that are currently active:'); let summaryflag = false; if (tipMenuToggle || tipMenu2Toggle) { summaryflag = true; summarymsg += '\n \u23E9 ' + wordWrap('A Tip Menu is available. The menu may display periodically if enabled by the broadcaster, or to see the menu at any time, type: /tipmenu'); } if (posTipMenuToggle) { summaryflag = true; summarymsg += '\n \u23E9 ' + wordWrap('The Positions Tip Menu is active. The menu may display periodically if enabled by the broadcaster, or to see the menu at anytime, type: /postipmenu'); } if (lushMenuToggle) { summaryflag = true; summarymsg += '\n \u23E9 ' + wordWrap('The ' + whichToy + ' Menu is active, please use the ' + whichToy + ' Tip Menu Ranges to control the toy with your tips!'); } if (tokenPollToggle && pollRunning) { summaryflag = true; summarymsg += '\n \u23E9 ' + wordWrap('A Token Poll is running, you can tip to vote for your favorite choice in the poll. To see the current poll choices and votes, type: /poll'); } if (iconTipAmountArray.length > 0 && tipForIconType != 'Do not use') { summaryflag = true; summarymsg += '\n \u23E9 ' + wordWrap('You can tip to add or change the icon next to your username in the chat, see the recurring chat notice for available icons and tip amounts.'); } if (presalesToggle) { summaryflag = true; summarymsg += '\n \u23E9 ' + wordWrap('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) { summaryflag = true; if (diceMultiRolls <= 1) { summarymsg += '\n \u23E9 ' + wordWrap('The Dice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! To see the prize list, type: /prizes'); } else if (diceMultiRolls == 2) { summarymsg += '\n \u23E9 ' + wordWrap('The Dice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! You can tip up to 2 multiples of the dice roll price (' + diceRollPrice + ' or ' + diceRollPrice*2 + '). To see the prize list, type: /prizes'); } else if (diceMultiRolls == 3) { summarymsg += '\n \u23E9 ' + wordWrap('The Dice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! You can tip up to 3 multiples of the dice roll price (' + diceRollPrice + ', ' + diceRollPrice*2 + ', or ' + diceRollPrice*3 + '). To see the prize list, type: /prizes'); } else if (diceMultiRolls > 3) { summarymsg += '\n \u23E9 ' + wordWrap('The Dice Game is active! Tip ' + diceRollPrice + ' ' + dicePlural + ' to roll the dice! You can tip up to ' + diceMultiRolls + ' multiples of the dice roll price (' + diceRollPrice + ', ' + diceRollPrice*2 + ', ' + diceRollPrice*3 + ',...). To see the prize list, type: /prizes'); } } summarymsg += borderUniversalBottom; if (summaryflag) { cb.sendNotice(summarymsg, sssendto, noticeBgColor, noticeTextColor, boldTextLiteral); } } //********** Room Rules Functions ************** function setRoomRulesNoticeToggle(rrnmode,rrnsendto,rrnbycmd) { if (rrnmode == 'on') { if (roomRuleNoticeToggle) { cb.sendNotice('The Room Rules Recurring Notice is already turned on.', rrnsendto, appNoticeColor); } else { roomRuleNoticeToggle = true; cb.setTimeout(roomRulesTimer,roomRulesInt); if (rrnbycmd) { cb.sendNotice('You have enabled the display of the Room Rules Recurring Notice.', rrnsendto, appNoticeColor); } } } else if (rrnmode == 'off') { if (!roomRuleNoticeToggle) { cb.sendNotice('The Room Rules Recurring Notice is already turned off.', rrnsendto, appNoticeColor); } else { roomRuleNoticeToggle = false; cb.sendNotice('You have disabled the display of the Room Rules Recurring Notice.', rrnsendto, appNoticeColor); } } } function setRoomRulesEnterToggle(rrmode,rrsendto,rrbycmd) { if (rrmode == 'on') { if (roomRuleEnterToggle) { cb.sendNotice('The Room Rules Entry Notice is already turned on.', rrsendto, appNoticeColor); } else { roomRuleEnterToggle = true; if (rrbycmd) { cb.sendNotice('You have enabled the display of the Room Rules Entry Notice.', rrsendto, appNoticeColor); } } } else if (rrmode == 'off') { if (!roomRuleEnterToggle) { cb.sendNotice('The Room Rules Entry Notice is already turned off.', rrsendto, appNoticeColor); } else { roomRuleEnterToggle = false; cb.sendNotice('You have disabled the display of the Room Rules Entry Notice.', rrsendto, appNoticeColor); } } } function setRoomRulesColor(setrrby,stupflag) { if (cb.settings.roomRulesTextColor == 'Custom') { roomRulesTextColor = setTextColor(cb.settings.roomRulesTextCustColor,'Room Rules',setrrby,stupflag); } else { roomRulesTextColor = setTextColor(cb.settings.roomRulesTextColor,'Room Rules',setrrby,stupflag); } if (cb.settings.roomRulesBgColor == 'Custom') { roomRulesBgColor = setBgColor(cb.settings.roomRulesBgCustColor,'Room Rules',setrrby,stupflag); } else { roomRulesBgColor = setBgColor(cb.settings.roomRulesBgColor,'Room Rules',setrrby,stupflag); } } function roomRulesTimer() { if (roomRuleNoticeToggle && 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 = borderRoomRulesTop for (let ruleindex = 0; ruleindex < roomRulesArray.length; ruleindex++) { if (roomRulesArray[ruleindex]) { rulemessage += '\n' + checkNextLine(roomRulesArray[ruleindex]); } } rulemessage += borderUniversalBottom; cb.sendNotice(rulemessage, sendto, roomRulesBgColor, roomRulesTextColor, boldTextLiteral); } //********** 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; } cb.setTimeout(followerTimer,followerInt); } function setFollowerColor(setfollby,stupflag) { if (cb.settings.followTextColor == 'Custom') { followTextColor = setTextColor(cb.settings.followCustomTextColor,'Followers',setfollby,stupflag); } else { followTextColor = setTextColor(cb.settings.followTextColor,'Followers',setfollby,stupflag); } if (cb.settings.followBgColor == 'Custom') { followBgColor = setBgColor(cb.settings.followCustomBgColor,'Followers',setfollby,stupflag); } else { followBgColor = setBgColor(cb.settings.followBgColor,'Followers',setfollby,stupflag); } } function setFollowerNoticeColor(setfollnotby,stupflag) { if (cb.settings.followNoticeTextColor == 'Custom') { followNoticeTextColor = setTextColor(cb.settings.followNoticeCustomTextColor,'Followers Notice',setfollnotby,stupflag); } else { followNoticeTextColor = setTextColor(cb.settings.followNoticeTextColor,'Followers Notice',setfollnotby,stupflag); } if (cb.settings.followNoticeBgColor == 'Custom') { followNoticeBgColor = setBgColor(cb.settings.followNoticeCustomBgColor,'Followers Notice',setfollnotby,stupflag); } else { followNoticeBgColor = setBgColor(cb.settings.followNoticeBgColor,'Followers Notice',setfollnotby,stupflag); } } 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(borderAllNoticesTop + checkNextLine(cb.settings.followReminder) + borderUniversalBottom, '', followNoticeBgColor, followNoticeTextColor, boldTextLiteral); } if (cb.settings.followerStatsEnable == 'Yes') { displayFollowerStats(BC); } cb.setTimeout(followerTimer,followerInt); } } } function displayFollowerStats(statsendto) { cb.getRoomOwnerData(ownerData => { if (ownerData.success) { var totalFollowers = ownerData.data.followers; let followersmsg = borderFollowerTop + '\nSent only to YOU:'; 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 += borderUniversalBottom; cb.sendNotice(followersmsg, statsendto, followBgColor, followTextColor, boldTextLiteral); } }); } 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(seticontipopt, seticontipby) { if (seticontipopt == 'on') { if (iconTipNoticeToggle) { cb.sendNotice('The Icon Tip Notice toggle is already turned on.', seticontipby, appNoticeColor); } else { iconTipNoticeToggle = true; cb.setTimeout(iconNoticeTimer,iconNoticeInt); } } else if (seticontipopt == 'off') { if (!iconTipNoticeToggle) { cb.sendNotice('The Icon Tip Notice toggle is already turned off.', seticontipby, appNoticeColor); } else { iconTipNoticeToggle = false; cb.sendNotice('You have disabled the Icon Tip Notice.', seticontipby, appNoticeColor); } } } function setIconTipNoticeColor(iconnotby,stupflag) { iconTipNoticeTextColor = setTextColor('Black','Icon Tip Notice',iconnotby,stupflag); iconTipNoticeBgColor = setBgColor('Light Red','Icon Tip Notice',iconnotby,stupflag); } function iconNoticeTimer() { if (iconTipNoticeToggle) { if (minMessagesForNotice > 0 && msgCounterIconNotice < minMessagesForNotice) { cb.setTimeout(iconNoticeTimer, 30000); } else { msgCounterIconNotice = 0; displayIconTipNotice(); cb.setTimeout(iconNoticeTimer,iconNoticeInt); } } } function displayIconTipNotice() { var iconmessage = borderTipForIconTop; if (tipForIconType == 'Specific Tip Amount') { if (iconTipAmountArray.length == 1) { iconmessage += wordWrap('\nYou can tip the below exact token amount to be rewarded with the associated icon next to your name in the chat:'); } else { iconmessage += wordWrap('\nYou can tip one of the below exact token amounts to be rewarded with the associated icon next to your name in the chat:'); } } else if (tipForIconType == 'Cumulative Tip Amount') { if (iconTipAmountArray.length == 1) { iconmessage += wordWrap('\nOnce your total tips during this show exceed the below amount, you will be rewarded with the associated icon by your name:'); } else { iconmessage += wordWrap('\nOnce your total tips during this show exceed one of the amounts, you 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]; } } iconmessage += borderUniversalBottom; cb.sendNotice(iconmessage, '', iconTipNoticeBgColor, iconTipNoticeTextColor, boldTextLiteral); } //********** King Tipper Functions ************** function setKingTipperFlag(mode,sendto,bycmd) { if (mode == '1') { if (kingTipperFlag == 1) { cb.sendNotice('The King Tipper toggle is already turned on (user defined name).', sendto, appNoticeColor); } else { let prevkingtippertoggle = kingTipperFlag; kingTipperFlag = 1; if (prevkingtippertoggle != 2) { cb.setTimeout(kingTipperTimer,kingTipperInt); } 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 (kingTipperFlag == 2) { cb.sendNotice('The King Tipper toggle is already turned on (All time list).', sendto, appNoticeColor); } else { let prevkingtippertoggle2 = kingTipperFlag; kingTipperFlag = 2; buildAllTimeArray(); if (prevkingtippertoggle2 != 1) { cb.setTimeout(kingTipperTimer,kingTipperInt); } if (bycmd) { 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 (kingTipperFlag == 0) { cb.sendNotice('The King Tipper toggle is already turned off.', sendto, appNoticeColor); } else { kingTipperFlag = 0; cb.sendNotice('You have disabled the King Tipper feature.', sendto, appNoticeColor); } } } function setKingSessionToggle(mode,sendto,bycmd) { if (mode == '1') { if (kingSessionToggle) { cb.sendNotice('The Current Session King Tipper toggle is already turned on.', sendto, appNoticeColor); } else { kingSessionToggle = true; cb.setTimeout(kingSessionTimer,kingSessionInt); if (bycmd) { cb.sendNotice('You have enabled the Current Session King Tipper feature.', sendto, appNoticeColor); } } } else if (mode == '0') { if (!kingSessionToggle) { cb.sendNotice('The Current Session King Tipper toggle is already turned off.', sendto, appNoticeColor); } else { kingSessionToggle = false; cb.sendNotice('You have disabled the Current Session King Tipper feature.', sendto, appNoticeColor); } } } function setKingTipperColor(setktnoteby,stupflag) { if (cb.settings.kingTipperTextColor == 'Custom') { kingTipperTextColor = setTextColor(cb.settings.kingTipperTextCustColor,'King Tipper Notice',setktnoteby,stupflag); } else { kingTipperTextColor = setTextColor(cb.settings.kingTipperTextColor,'King Tipper Notice',setktnoteby,stupflag); } if (cb.settings.kingTipperNoticeColor == 'Custom') { kingTipperBgNoticeColor = setBgColor(cb.settings.kingTipperNoticeCustColor,'King Tipper Notice',setktnoteby,stupflag); } else { kingTipperBgNoticeColor = setBgColor(cb.settings.kingTipperNoticeColor,'King Tipper Notice',setktnoteby,stupflag); } } function setKingTipperChatColor(setktchatby,stupflag) { if (cb.settings.kingTipperBgColor == 'Custom') { kingTipperBgColor = setBgColor(cb.settings.kingTipperBgCustColor,'King Tipper Chat',setktchatby,stupflag); } else { kingTipperBgColor = setBgColor(cb.settings.kingTipperBgColor,'King Tipper Chat',setktchatby,stupflag); } } function kingTipperTimer() { if (kingTipperFlag == 1 || kingTipperFlag == 2) { if (minMessagesForNotice > 0 && msgCounterKing < minMessagesForNotice) { cb.setTimeout(kingTipperTimer, 30000); } else { if (kingTipperName) { msgCounterKing = 0; displayKingTipperNotice(''); cb.setTimeout(kingTipperTimer,kingTipperInt); } else { cb.sendNotice('The King Tipper Name was not successfully assigned, disabling the King Tipper feature.', BC, appWarningColor); setKingTipperFlag('0',BC,false); } } } } function displayKingTipperNotice(sendto) { let kingTipperNotice = borderAllNoticesTop; 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 (cb.settings.kingSingleEnable == 'Yes, defined below' && kingSingleTipperName && kingSingleTipperAmount > 0) { kingTipperNotice += '\n' + kingSingleTipperName + ' has the all-time highest single tip of ' + kingSingleTipperAmount + ' tokens!'; } kingTipperNotice += borderUniversalBottom; cb.sendNotice(kingTipperNotice, sendto, kingTipperBgNoticeColor, kingTipperTextColor, boldTextLiteral); } function setKingSessionColor(setkingsessby,stupflag) { if (cb.settings.kingSessionTextColor == 'Custom') { kingSessionTextColor = setTextColor(cb.settings.kingSessionTextCustColor,'King Tipper Session',setkingsessby,stupflag); } else { kingSessionTextColor = setTextColor(cb.settings.kingSessionTextColor,'King Tipper Session',setkingsessby,stupflag); } if (cb.settings.kingSessionNoticeColor == 'Custom') { kingSessionNoticeColor = setBgColor(cb.settings.kingSessionNoticeCustColor,'King Tipper Session',setkingsessby,stupflag); } else { kingSessionNoticeColor = setBgColor(cb.settings.kingSessionNoticeColor,'King Tipper Session',setkingsessby,stupflag); } } function kingSessionTimer() { if (kingSessionToggle) { 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) || (cb.settings.kingSessionEnableSingle == 'Yes' && currentKingTipperSingle)) { let kingsessionnotice = borderCurrentKingTop + '\n'; 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 + ' Tip at least ' + cb.settings.kingSessionMinAmount + ' tokens to become the new king of this show! ' + cb.settings.kingSessionIcon; } if (currentKingTipperSingle) { kingsessionnotice += '\n' + currentKingTipperSingle + ' has the highest single tip for this show (' + currentKingTipperAmountSingle + ' tokens)'; } kingsessionnotice += borderUniversalBottom; cb.sendNotice(kingsessionnotice, kingsessionsendto, kingSessionNoticeColor, kingSessionTextColor, boldTextLiteral); } } // *************************** Tip Count Functions ************************ function setTipCountToggle(settcopt,settcby,settcbycmd) { if (settcopt == 'on') { if(tipCountToggle) { cb.sendNotice('The Tip Count display is already turned on.',settcby,appNoticeColor); } else { tipCountToggle = true; if (settcbycmd) { cb.sendNotice('You have enabled the Tip Count display next to each user name in the chat.',settcby,appNoticeColor); } } } else if (settcopt == 'off') { if (!tipCountToggle) { cb.sendNotice('The Tip Count display is already turned off.',settcby,appNoticeColor); } else { tipCountToggle = false; cb.sendNotice('You have disabled the Tip Count display.',settcby,appNoticeColor); } } else if (settcopt != null) { cb.sendNotice(settcopt + ' is not a valid option for /usetipcount.',settcby,appNoticeColor); } else if (settcopt == null) { cb.sendNotice('You did not enter a valid option for /usetipcount.',settcby,appNoticeColor); } } // *************************** Tip Menu Functions ************************ function setTipMenuToggle(setmenuopt,setmenuby) { let settipmenusendto = setmenuby; if (setmenuby == 'init') { settipmenusendto = BC; } if (setmenuopt == 'on') { if (tipMenuToggle) { cb.sendNotice('Tip Menu 1 is already turned on.',settipmenusendto,appNoticeColor); } else { tipMenuToggle = true; initMenu(setmenuby); cb.sendNotice(' ' + settipmenusendto + ' has enabled Tip Menu 1.\nYou control the action by tipping for selections from the menu!\nTo see the menu, type: /tipmenu', '', tipMenuBgColor1, tipMenuTextColor1, 'bold'); } } else if (setmenuopt == 'off') { if (!tipMenuToggle) { cb.sendNotice('Tip Menu 1 is already turned off.',settipmenusendto,appNoticeColor); } else { tipMenuToggle = false; for (let i = 0; i < tipMenuPriceArray.length; i++) { priceChecker('rmv','Tip Menu Option: '+tipMenuItemArray[i],tipMenuPriceArray[i],setmenuby); } tipMenuPriceArray = []; tipMenuItemArray = []; cb.sendNotice(' ' + settipmenusendto + ' has disabled Tip Menu 1.\nYou can no longer tip for selections from Menu 1.', '', tipMenuBgColor1, tipMenuTextColor1, 'bold') } } else if (setmenuopt != null) { cb.sendNotice(setmenuopt + ' is not a valid option for /usemenu.',settipmenusendto,appNoticeColor); } else if (setmenuopt == null) { cb.sendNotice('You did not enter a valid option for /usemenu.',settipmenusendto,appNoticeColor); } } function setTipMenu2Toggle(setmenu2opt,setmenu2by) { let settipmenu2sendto = setmenu2by; if (setmenu2by == 'init') { settipmenu2sendto = BC; } if (setmenu2opt == 'on') { if (tipMenu2Toggle) { cb.sendNotice('Tip Menu 2 is already turned on.',settipmenu2sendto,appNoticeColor); } else { tipMenu2Toggle = true; initMenu2(settipmenu2sendto); cb.sendNotice(' ' + settipmenu2sendto + ' has enabled Tip Menu 2.\nYou control the action by tipping for selections from the menu!\nTo see the menu, type: /tipmenu', '', tipMenu2BgColor1, tipMenu2TextColor1, 'bold'); } } else if (setmenu2opt == 'off') { if (!tipMenu2Toggle) { cb.sendNotice('Tip Menu 2 is already turned off.',settipmenu2sendto,appNoticeColor); } else { tipMenu2Toggle = false; for (let i = 0; i <tipMenu2PriceArray.length; i++) { priceChecker('rmv','Tip Menu 2 Option: '+tipMenu2ItemArray[i],tipMenu2PriceArray[i],setmenu2by); } tipMenu2PriceArray = []; tipMenu2ItemArray = []; cb.sendNotice(' ' + settipmenu2sendto + ' has disabled Tip Menu 2.\nYou can no longer tip for selections from Menu 2.', '', tipMenu2BgColor1, tipMenu2TextColor1, 'bold'); } } else if (setmenu2opt) { cb.sendNotice(setmenu2opt + ' is not a valid option for /usemenu2.',settipmenu2sendto,appNoticeColor); } else if (!setmenu2opt) { cb.sendNotice('You did not enter a valid option for /usemenu2.',settipmenu2sendto,appNoticeColor); } } function setTipMenuColors(stmby,stupflag) { if (cb.settings.menutxtcolor1 == 'Custom') { tipMenuTextColor1 = setTextColor(cb.settings.menuCustTxtColor1,'Tip Menu, Part 1',stmby,stupflag); tipMenu2TextColor1 = tipMenuTextColor1; } else { tipMenuTextColor1 = setTextColor(cb.settings.menutxtcolor1,'Tip Menu, Part 1',stmby,stupflag); tipMenu2TextColor1 = tipMenuTextColor1; } if (cb.settings.menubgcolor1 == 'Custom') { tipMenuBgColor1 = setBgColor(cb.settings.menuCustBgColor1,'Tip Menu, Part 1',stmby,stupflag); tipMenu2BgColor1 = tipMenuBgColor1; } else { tipMenuBgColor1 = setBgColor(cb.settings.menubgcolor1,'Tip Menu, Part 1',stmby,stupflag); tipMenu2BgColor1 = tipMenuBgColor1; } if (cb.settings.menutxtcolor2 == 'Custom') { tipMenuTextColor2 = setTextColor(cb.settings.menuCustTxtColor2,'Tip Menu, Part 2',stmby,stupflag); tipMenu2TextColor2 = tipMenuTextColor2; } else { tipMenuTextColor2 = setTextColor(cb.settings.menutxtcolor2,'Tip Menu, Part 2',stmby,stupflag); tipMenu2TextColor2 = tipMenuTextColor2; } if (cb.settings.menubgcolor2 == 'Custom') { tipMenuBgColor2 = setBgColor(cb.settings.menuCustBgColor2,'Tip Menu, Part 2',stmby,stupflag); tipMenu2BgColor2 = tipMenuBgColor2; } else { tipMenuBgColor2 = setBgColor(cb.settings.menubgcolor2,'Tip Menu, Part 2',stmby,stupflag); tipMenu2BgColor2 = tipMenuBgColor2; } } function setTipMenuRespColors(stmrby,stupflag) { if (cb.settings.menutxtcolor1 == 'Custom') { tipMenuTextColorTip = setTextColor(cb.settings.menuCustTxtColor1,'Tip Menu Responses',stmrby,stupflag); } else { tipMenuTextColorTip = setTextColor(cb.settings.menutxtcolor1,'Tip Menu Responses',stmrby,stupflag); } if (cb.settings.menubgcolor1 == 'Custom') { tipMenuBgColorTip = setBgColor(cb.settings.menuCustBgColor1,'Tip Menu Responses',stmrby,stupflag); } else { tipMenuBgColorTip = setBgColor(cb.settings.menubgcolor1,'Tip Menu Responses',stmrby,stupflag); } } function initMenu(initmenuuser) { setSepChar(); let maxItems = 40; if (cb.settings.includeDiceRollPrice == 'Yes' && diceToggle && diceRollPrice > 0) { tipMenuPriceArray.push(diceRollPrice); tipMenuItemArray.push('Dice Roll'); if (cb.settings.tipMenuModSalePct > 0) { tipMenuModPriceArray.push(diceRollPrice); tipMenuModItemArray.push('Dice Roll'); } if (cb.settings.tipMenuCBFCSalePct > 0) { tipMenuCBFCPriceArray.push(diceRollPrice); tipMenuCBFCItemArray.push('Dice Roll'); } if (cb.settings.tipMenuEFC1SalePct > 0) { tipMenuEFC1PriceArray.push(diceRollPrice); tipMenuEFC1ItemArray.push('Dice Roll'); } if (cb.settings.tipMenuEFC2SalePct > 0) { tipMenuEFC2PriceArray.push(diceRollPrice); tipMenuEFC2ItemArray.push('Dice Roll'); } if (cb.settings.tipMenuVIPSalePct > 0) { tipMenuVIPPriceArray.push(diceRollPrice); tipMenuVIPItemArray.push('Dice Roll'); } } for (let j = 0; j <= maxItems; j++) { if (cb.settings['menuitem' + j] !== '' && cb.settings['menuitemprice' + j] > 0) { let regularprice = cb.settings['menuitemprice' + j]; let saleprice = 0; let priceused = regularprice; if (cb.settings.tipMenuSalePct > 0) { saleprice = Math.round(regularprice - (cb.settings.tipMenuSalePct/100*regularprice)); if (saleprice <= 0) { saleprice = 1; } tipMenuPriceArray.push(saleprice.toString()); priceused = saleprice.toString(); } else { tipMenuPriceArray.push(regularprice); } tipMenuItemArray.push(cb.settings['menuitem' + j]); priceChecker('add','Tip Menu Option: '+(cb.settings['menuitem' + j]), priceused, initmenuuser); if (cb.settings.tipMenuModSalePct > 0) { let modsaleprice = Math.round(regularprice - (cb.settings.tipMenuModSalePct/100*regularprice)); if (modsaleprice <= 0) { modsaleprice = 1; } tipMenuModItemArray.push(cb.settings['menuitem' + j]); tipMenuModPriceArray.push(modsaleprice.toString()); } if (cb.settings.tipMenuCBFCSalePct > 0) { let fansaleprice = Math.round(regularprice - (cb.settings.tipMenuCBFCSalePct/100*regularprice)); if (fansaleprice <= 0) { fansaleprice = 1; } tipMenuCBFCItemArray.push(cb.settings['menuitem' + j]); tipMenuCBFCPriceArray.push(fansaleprice.toString()); } if (cb.settings.tipMenuEFC1SalePct > 0) { let extfan1saleprice = Math.round(regularprice - (cb.settings.tipMenuEFC1SalePct/100*regularprice)); if (extfan1saleprice <= 0) { extfan1saleprice = 1; } tipMenuEFC1ItemArray.push(cb.settings['menuitem' + j]); tipMenuEFC1PriceArray.push(extfan1saleprice.toString()); } if (cb.settings.tipMenuEFC2SalePct > 0) { let extfan2saleprice = Math.round(regularprice - (cb.settings.tipMenuEFC2SalePct/100*regularprice)); if (extfan2saleprice <= 0) { extfan2saleprice = 1; } tipMenuEFC2ItemArray.push(cb.settings['menuitem' + j]); tipMenuEFC2PriceArray.push(extfan2saleprice.toString()); } if (cb.settings.tipMenuVIPSalePct > 0) { let vipsaleprice = Math.round(regularprice - (cb.settings.tipMenuVIPSalePct/100*regularprice)); if (vipsaleprice <= 0) { vipsaleprice = 1; } tipMenuVIPItemArray.push(cb.settings['menuitem' + j]); tipMenuVIPPriceArray.push(vipsaleprice.toString()); } } } for (let fanloadidx = 0; fanloadidx <= 10; fanloadidx++) { if (cb.settings['fanmenuitem' + fanloadidx] !== '' && cb.settings['fanmenuitemprice' + fanloadidx] > 0) { if (cbjs.arrayContains(tipMenuCBFCPriceArray, 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.', BC, '#FFFFFF', '#FF0000'); } tipMenuCBFCPriceArray.push(cb.settings['fanmenuitemprice' + fanloadidx]); tipMenuCBFCItemArray.push(cb.settings['fanmenuitem' + fanloadidx]); let fanpriceused = cb.settings['fanmenuitemprice' + fanloadidx]; priceChecker('add','CB Fanclub Tip Menu Option: '+(cb.settings['menuitem' + fanloadidx]), fanpriceused, initmenuuser); } } for (let efc1loadidx = 0; efc1loadidx <= 10; efc1loadidx++) { if (cb.settings['efc1menuitem' + efc1loadidx] !== '' && cb.settings['efc1menuitemprice' + efc1loadidx] > 0) { if (cbjs.arrayContains(tipMenuEFC1PriceArray, 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.', BC, '#FFFFFF', '#FF0000'); } tipMenuEFC1PriceArray.push(cb.settings['efc1menuitemprice' + efc1loadidx]); tipMenuEFC1ItemArray.push(cb.settings['efc1menuitem' + efc1loadidx]); let efc1priceused = cb.settings['efc1menuitemprice' + efc1loadidx]; priceChecker('add','External Fanclub 1 Tip Menu Option: '+(cb.settings['menuitem' + efc1loadidx]), efc1priceused, initmenuuser); } } for (let efc2loadidx = 0; efc2loadidx <= 10; efc2loadidx++) { if (cb.settings['efc2menuitem' + efc2loadidx] !== '' && cb.settings['efc2menuitemprice' + efc2loadidx] > 0) { if (cbjs.arrayContains(tipMenuEFC2PriceArray, 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.', BC, '#FFFFFF', '#FF0000'); } tipMenuEFC2PriceArray.push(cb.settings['efc2menuitemprice' + efc2loadidx]); tipMenuEFC2ItemArray.push(cb.settings['efc2menuitem' + efc2loadidx]); let efc2priceused = cb.settings['efc2menuitemprice' + efc2loadidx]; priceChecker('add','External Fanclub 2 Tip Menu Option: '+(cb.settings['menuitem' + efc2loadidx]), efc2priceused, initmenuuser); } } buildMenu(); cb.setTimeout(displayMenu,tipMenuDispInt); } function initMenu2(initmenu2user) { setSepChar2(); let maxItems = 25; for (let j = 0; j <= maxItems; j++) { if (cb.settings['menu2item' + j] !== '' && cb.settings['menu2itemprice' + j] > 0) { let regularprice2 = cb.settings['menu2itemprice' + j]; let priceused2 = regularprice2; if (cb.settings.tipMenu2SalePct > 0) { let saleprice2 = Math.round(regularprice2 - (cb.settings.tipMenu2SalePct/100*regularprice2)); if (saleprice2 <= 0) { saleprice2 = 1; } tipMenu2PriceArray.push(saleprice2.toString()); priceused2 = saleprice2.toString(); } else { tipMenu2PriceArray.push(regularprice2); } tipMenu2ItemArray.push(cb.settings['menu2item' + j]); priceChecker('add','Tip Menu 2 Option: '+(cb.settings['menu2item' + j]), priceused2, initmenu2user); } } if (cb.settings.includeDiceRollPrice == 'Yes' &&tipMenu2PriceArray.length < maxItems && diceToggle && diceRollPrice > 0) { tipMenu2PriceArray.push(diceRollPrice); tipMenu2ItemArray.push('Dice Roll'); } buildMenu2(); cb.setTimeout(displayMenu2,tipMenu2DispInt); } function buildMenu() { tipMenuDisplayText = bcText + '\'s Tip Menu:'; let menuarray = []; let menuarray1 = []; let menuarray2 = []; let sorted = []; for (let bmenuidx = 0; bmenuidx < tipMenuPriceArray.length; bmenuidx++) { sorted.push({ 'prices': tipMenuPriceArray[bmenuidx], 'id': bmenuidx }); } 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') { let numbermenuchunks = 1; let menuchunklength = sorted.length; let currentchunk = 1; let currentchunkitem = 1; 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.', BC, appWarningColor, '', 'bold'); } else { tipMenuPartArray[0] = bcText + '\'s Tip Menu Part 1:'; tipMenuPartArray[1] = bcText + '\'s Tip Menu Part 2:'; tipMenuPartArray[2] = bcText + '\'s Tip Menu Part 3:'; tipMenuPartArray[3] = bcText + '\'s Tip Menu Part 4:'; tipMenuPartArray[4] = bcText + '\'s Tip Menu Part 5:'; if (sorted.length <= 16) { numbermenuchunks = 2; menuchunklength = Math.ceil(sorted.length / numbermenuchunks); } else if (sorted.length <= 24) { numbermenuchunks = 3; menuchunklength = Math.ceil(sorted.length / numbermenuchunks); } else if (sorted.length <= 32) { numbermenuchunks = 4; menuchunklength = Math.ceil(sorted.length / numbermenuchunks); } else if (sorted.length <= 40) { numbermenuchunks = 5; menuchunklength = Math.ceil(sorted.length / numbermenuchunks); } } } for (let sortmenuidx = 0; sortmenuidx < sorted.length; sortmenuidx++) { if (tipMenuPriceArray[sorted[sortmenuidx].id] !== 0) { tipMenuDisplayText += '\n' + tipMenuSepChar + ' ' + tipMenuPriceArray[sorted[sortmenuidx].id] + ' - ' + tipMenuItemArray[sorted[sortmenuidx].id] if (cb.settings.tipMenuNoticeType == 'Split Menu - List Form' && menuListSplit) { tipMenuPartArray[currentchunk-1] += '\n' + tipMenuSepChar + ' ' + tipMenuPriceArray[sorted[sortmenuidx].id] + ' - ' + tipMenuItemArray[sorted[sortmenuidx].id]; currentchunkitem++; if (currentchunkitem > menuchunklength) { tipMenuPartArray[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 (tipMenuPriceArray[sorted[sortmenuidx2].id] !== 0) { menuarray.push(tipMenuItemArray[sorted[sortmenuidx2].id] + ' (' + tipMenuPriceArray[sorted[sortmenuidx2].id] + ') '); } } tipMenuDisplayText += '\n' + menuarray.join(tipMenuSepChar); 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.', BC, '#FFFFFF', '#FF0000', 'bold'); } else { tipMenuPartArray[0] = bcText + '\'s Tip Menu Part 1:'; tipMenuPartArray[1] = bcText + '\'s Tip Menu Part 2:'; let msglength1 = 0; let msgHalf = (tipMenuDisplayText.length - 9) / 2; for (let sortmenuidx3 = 0; sortmenuidx3 < sorted.length; sortmenuidx3++) { if (tipMenuPriceArray[sorted[sortmenuidx3].id] !== 0) { if (msglength1 < msgHalf) { menuarray1.push(tipMenuItemArray[sorted[sortmenuidx3].id] + ' (' + tipMenuPriceArray[sorted[sortmenuidx3].id] + ') '); msglength1 = menuarray1.join(tipMenuSepChar).length; } else { menuarray2.push(tipMenuItemArray[sorted[sortmenuidx3].id] + ' (' + tipMenuPriceArray[sorted[sortmenuidx3].id] + ') '); } } } tipMenuPartArray[0] += '\n' + menuarray1.join(tipMenuSepChar) + '\n The menu has been split. To see the full menu type: /tipmenu'; tipMenuPartArray[1] += '\n' + menuarray2.join(tipMenuSepChar) + '\n The menu has been split. To see the full menu type: /tipmenu'; } } } tipMenuLength = tipMenuPriceArray.length; if (tipMenuLength <= 0) { cb.sendNotice('Error - No menu items found', '', '', tipMenuTextColor1, 'bold'); } if (tipMenuModItemArray.length > 0) { modSpecificMenuItems = true; buildMenuMod(); } if (tipMenuCBFCItemArray.length > 0) { cbfcSpecificMenuItems = true; buildMenuFan(); } if (tipMenuEFC1ItemArray.length > 0) { efc1SpecificMenuItems = true; buildMenuEFC1(); } if (tipMenuEFC2ItemArray.length > 0) { efc2SpecificMenuItems = true; buildMenuEFC2(); } if (tipMenuVIPItemArray.length > 0) { vipSpecificMenuItems = true; buildMenuVIP(); } } function buildMenuMod() { tipMenuModDisplayText = bcText + '\'s Moderator Tip Menu'; let menuarraymod = []; let sortedmod = []; for (let bmmodidx = 0; bmmodidx < tipMenuModPriceArray.length; bmmodidx++) { sortedmod.push({ 'prices': tipMenuModPriceArray[bmmodidx], 'id': bmmodidx }); } if (cb.settings.listSort !== 'Do not sort the list') { sortedmod.sort(function(a, b) { return a.prices - b.prices; }); if (cb.settings.listSort === 'Descending') { sortedmod.reverse(); } } if (cb.settings.tipMenuNoticeType == 'Full Menu - List Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { for (let j = 0; j < sortedmod.length; j++) { if (tipMenuModPriceArray[sortedmod[j].id] !== 0) { menuarraymod.push(tipMenuModPriceArray[sortedmod[j].id] + ' - ' + tipMenuModItemArray[sortedmod[j].id]); } } let tempsepcharmod = '\n' + tipMenuSepChar; tipMenuModDisplayText += tempsepcharmod; tipMenuModDisplayText += menuarraymod.join(tempsepcharmod); } else { for (let j = 0; j < sortedmod.length; j++) { if (tipMenuModPriceArray[sortedmod[j].id] !== 0) { menuarraymod.push(tipMenuModItemArray[sortedmod[j].id] + ' (' + tipMenuModPriceArray[sortedmod[j].id] + ') '); } } tipMenuModDisplayText += '\n' + menuarraymod.join(tipMenuSepChar); } tipMenuModLength = tipMenuModPriceArray.length; if (tipMenuLength <= 0) { cb.sendNotice('Error - No Moderator Specific menu items found', '', '', tipMenuTextColor1, 'bold'); } } function buildMenuFan() { tipMenuCBFCDisplayText = bcText + '\'s CB Fan Club Tip Menu:'; let menuarrayfan = []; let sortedfan = []; for (let bmfanidx = 0; bmfanidx < tipMenuCBFCPriceArray.length; bmfanidx++) { sortedfan.push({ 'prices': tipMenuCBFCPriceArray[bmfanidx], 'id': bmfanidx }); } if (cb.settings.listSort !== 'Do not sort the list') { sortedfan.sort(function(a, b) { return a.prices - b.prices; }); if (cb.settings.listSort === 'Descending') { sortedfan.reverse(); } } if (cb.settings.tipMenuNoticeType == 'Full Menu - List Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { for (let j = 0; j < sortedfan.length; j++) { if (tipMenuCBFCPriceArray[sortedfan[j].id] !== 0) { menuarrayfan.push(tipMenuCBFCPriceArray[sortedfan[j].id] + ' - ' + tipMenuCBFCItemArray[sortedfan[j].id]); } } let tempsepcharfc = '\n' + tipMenuSepChar; tipMenuCBFCDisplayText += tempsepcharfc; tipMenuCBFCDisplayText += menuarrayfan.join(tempsepcharfc); } else { for (let j = 0; j < sortedfan.length; j++) { if (tipMenuCBFCPriceArray[sortedfan[j].id] !== 0) { menuarrayfan.push(tipMenuCBFCItemArray[sortedfan[j].id] + ' (' + tipMenuCBFCPriceArray[sortedfan[j].id] + ') '); } } tipMenuCBFCDisplayText += '\n' + menuarrayfan.join(tipMenuSepChar); } tipMenuCBFCLength = tipMenuCBFCPriceArray.length; if (tipMenuLength <= 0) { cb.sendNotice('Error - No CB Fan Club Specific menu items found', '', '', tipMenuTextColor1, 'bold'); } } function buildMenuEFC1() { tipMenuEFC1DisplayText = EFCname + ' Tip Menu:'; let menuarrayefc1 = []; let sortedefc1 = []; for (let bmef1idx = 0; bmef1idx < tipMenuEFC1PriceArray.length; bmef1idx++) { sortedefc1.push({ 'prices': tipMenuEFC1PriceArray[bmef1idx], 'id': bmef1idx }); } if (cb.settings.listSort !== 'Do not sort the list') { sortedefc1.sort(function(fc1a, fc1b) { return fc1a.prices - fc1b.prices; }); if (cb.settings.listSort === 'Descending') { sortedefc1.reverse(); } } if (cb.settings.tipMenuNoticeType == 'Full Menu - List Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { for (let j = 0; j < sortedefc1.length; j++) { if (tipMenuEFC1PriceArray[sortedefc1[j].id] !== 0) { menuarrayefc1.push(tipMenuEFC1PriceArray[sortedefc1[j].id] + ' - ' + tipMenuEFC1ItemArray[sortedefc1[j].id]); } } let tempsepcharefc1 = '\n' + tipMenuSepChar; tipMenuEFC1DisplayText += tempsepcharefc1; tipMenuEFC1DisplayText += menuarrayefc1.join(tempsepcharefc1); } else { for (let j = 0; j < sortedefc1.length; j++) { if (tipMenuEFC1PriceArray[sortedefc1[j].id] !== 0) { menuarrayefc1.push(tipMenuEFC1ItemArray[sortedefc1[j].id] + ' (' + tipMenuEFC1PriceArray[sortedefc1[j].id] + ') '); } } tipMenuEFC1DisplayText += '\n' + menuarrayefc1.join(tipMenuSepChar); } tipMenuEFC1Length = tipMenuEFC1PriceArray.length; if (tipMenuLength <= 0) { cb.sendNotice('Error - No Ext Fan Club 1 Specific menu items found', '', '', tipMenuTextColor1, 'bold'); } } function buildMenuEFC2() { tipMenuEFC2DisplayText = EFCname2 + ' Tip Menu:'; let menuarrayefc2 = []; let sortedefc2 = []; for (let bmef2idx = 0; bmef2idx < tipMenuEFC2PriceArray.length; bmef2idx++) { sortedefc2.push({ 'prices': tipMenuEFC2PriceArray[bmef2idx], 'id': bmef2idx }); } if (cb.settings.listSort !== 'Do not sort the list') { sortedefc2.sort(function(fc2a, fc2b) { return fc2a.prices - fc2b.prices; }); if (cb.settings.listSort === 'Descending') { sortedefc2.reverse(); } } if (cb.settings.tipMenuNoticeType == 'Full Menu - List Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { for (let j = 0; j < sortedefc2.length; j++) { if (tipMenuEFC2PriceArray[sortedefc2[j].id] !== 0) { menuarrayefc2.push(tipMenuEFC2PriceArray[sortedefc2[j].id] + ' - ' + tipMenuEFC2ItemArray[sortedefc2[j].id]); } } let tempsepcharefc2 = '\n' + tipMenuSepChar; tipMenuEFC2DisplayText += tempsepcharefc2; tipMenuEFC2DisplayText += menuarrayefc2.join(tempsepcharefc2); } else { for (let j = 0; j < sortedefc2.length; j++) { if (tipMenuEFC2PriceArray[sortedefc2[j].id] !== 0) { menuarrayefc2.push(tipMenuEFC2ItemArray[sortedefc2[j].id] + ' (' + tipMenuEFC2PriceArray[sortedefc2[j].id] + ') '); } } tipMenuEFC2DisplayText += '\n' + menuarrayefc2.join(tipMenuSepChar); } tipMenuEFC2Length = tipMenuEFC2PriceArray.length; if (tipMenuLength <= 0) { cb.sendNotice('Error - No Ext Fan Club 2 Specific menu items found', '', '', tipMenuTextColor1, 'bold'); } } function buildMenuVIP() { tipMenuVIPDisplayText = bcText + '\'s VIP Tip Menu:'; let menuarrayvip = []; let sortedvip = []; for (let bmvipidx = 0; bmvipidx < tipMenuVIPPriceArray.length; bmvipidx++) { sortedvip.push({ 'prices': tipMenuVIPPriceArray[bmvipidx], 'id': bmvipidx }); } if (cb.settings.listSort !== 'Do not sort the list') { sortedvip.sort(function(a, b) { return a.prices - b.prices; }); if (cb.settings.listSort === 'Descending') { sortedvip.reverse(); } } if (cb.settings.tipMenuNoticeType == 'Full Menu - List Form' || cb.settings.tipMenuNoticeType == 'Split Menu - List Form') { for (let j = 0; j < sortedvip.length; j++) { if (tipMenuVIPPriceArray[sortedvip[j].id] !== 0) { menuarrayvip.push(tipMenuVIPPriceArray[sortedvip[j].id] + ' - ' + tipMenuVIPItemArray[sortedvip[j].id]); } } let tempsepcharvip = '\n' + tipMenuSepChar; tipMenuVIPDisplayText += tempsepcharvip; tipMenuVIPDisplayText += menuarrayvip.join(tempsepcharvip); } else { for (let j = 0; j < sortedvip.length; j++) { if (tipMenuVIPPriceArray[sortedvip[j].id] !== 0) { menuarrayvip.push(tipMenuVIPItemArray[sortedvip[j].id] + ' (' + tipMenuVIPPriceArray[sortedvip[j].id] + ') '); } } tipMenuVIPDisplayText += '\n' + menuarrayvip.join(tipMenuSepChar); } tipMenuVIPLength = tipMenuVIPPriceArray.length; if (tipMenuLength <= 0) { cb.sendNotice('Error - No VIP Specific menu items found', '', '', tipMenuTextColor1, 'bold'); } } function buildMenu2() { tipMenu2DisplayText = bcText + '\'s Tip Menu #2:'; let menu2Array = []; let menu2Array1 = []; let menu2Array2 = []; let sorted2 = []; let menuL = tipMenu2PriceArray.length; for (let bm2idx = 0; bm2idx < menuL; bm2idx++) { sorted2.push({ 'prices':tipMenu2PriceArray[bm2idx], 'id': bm2idx }); } 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') { let currentchunk2 = 1; let currentchunkitem2 = 1; let numbermenuchunks2 = 1; let menuchunklength2 = sorted2.length; 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.', BC, appWarningColor, '', 'bold'); } else { tipMenu2PartArray[0] = bcText + '\'s Tip Menu 2 Part 1:'; tipMenu2PartArray[1] = bcText + '\'s Tip Menu 2 Part 2:'; tipMenu2PartArray[2] = bcText + '\'s Tip Menu 2 Part 3:'; if (sorted2.length <= 16) { numbermenuchunks2 = 2; menuchunklength2 = Math.ceil(sorted2.length / numbermenuchunks2); } else if (sorted2.length <= 25) { numbermenuchunks2 = 3; menuchunklength2 = Math.ceil(sorted2.length / numbermenuchunks2); } } } for (let sortmenuidx = 0; sortmenuidx < sorted2.length; sortmenuidx++) { if (tipMenu2PriceArray[sorted2[sortmenuidx].id] !== 0) { tipMenu2DisplayText += '\n' + tipMenu2SepChar + ' ' +tipMenu2PriceArray[sorted2[sortmenuidx].id] + ' - ' +tipMenu2ItemArray[sorted2[sortmenuidx].id] if (cb.settings.tipMenuNoticeType == 'Split Menu - List Form' && menu2ListSplit) { tipMenu2PartArray[currentchunk2-1] += '\n' + tipMenu2SepChar + ' ' +tipMenu2PriceArray[sorted2[sortmenuidx].id] + ' - ' +tipMenu2ItemArray[sorted2[sortmenuidx].id]; currentchunkitem2++; if (currentchunkitem2 > menuchunklength2) { tipMenu2PartArray[currentchunk2-1] += '\nThe menu has been split. To see the full menu type: /tipmenu'; currentchunk2 ++; currentchunkitem2 = 1; } } } } } else { for (let sortmenuidx2 = 0; sortmenuidx2 < sorted2.length; sortmenuidx2++) { if (tipMenu2PriceArray[sorted2[sortmenuidx2].id] !== 0) { menu2Array.push(tipMenu2ItemArray[sorted2[sortmenuidx2].id] + ' (' +tipMenu2PriceArray[sorted2[sortmenuidx2].id] + ') '); } } tipMenu2DisplayText += '\n' + menu2Array.join(tipMenu2SepChar); 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.', BC, '#FFFFFF', '#FF0000', 'bold'); } else { tipMenu2PartArray[0] = bcText + '\'s Tip Menu 2 Part 1:'; tipMenu2PartArray[1] = bcText + '\'s Tip Menu 2 Part 2:'; let msglength1 = 0; let msgHalf = (tipMenu2DisplayText.length - 9) / 2; for (let sortmenuidx3 = 0; sortmenuidx3 < sorted2.length; sortmenuidx3++) { if (tipMenu2PriceArray[sorted2[sortmenuidx3].id] !== 0) { if (msglength1 < msgHalf) { menu2Array1.push(tipMenu2ItemArray[sorted2[sortmenuidx3].id] + ' (' +tipMenu2PriceArray[sorted2[sortmenuidx3].id] + ') '); msglength1 = menu2Array1.join(tipMenu2SepChar).length; } else { menu2Array2.push(tipMenu2ItemArray[sorted2[sortmenuidx3].id] + ' (' +tipMenu2PriceArray[sorted2[sortmenuidx3].id] + ') '); } } } tipMenu2PartArray[0] += '\n' + menu2Array1.join(tipMenu2SepChar) + '\n To see the full menu, type: /tipmenu.'; tipMenu2PartArray[1] += '\n' + menu2Array2.join(tipMenu2SepChar) + '\n To see the full menu, type: /tipmenu.'; } } } tipMenu2Length =tipMenu2PriceArray.length; if (tipMenu2Length <= 0) { cb.sendNotice('Error - No menu items found', '', '', tipMenu2TextColor1, 'bold'); } } function displayMenu() { if (tipMenuToggle) { 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', '', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); 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!', '', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } cb.setTimeout(checkUserGroupMenuNotice, 500); } else if (tipMenuLength > 0 && cb.settings.tipMenuNoticeType == 'Split Menu - Paragraph Form') { if (tipMenuToken == 1) { cb.sendNotice(tipMenuPartArray[0],'', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); 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!', '', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } tipMenuToken = 2; cb.setTimeout(checkUserGroupMenuNotice, 500); } else if (tipMenuToken == 2) { cb.sendNotice(tipMenuPartArray[1],'', tipMenuBgColor2, tipMenuTextColor2, boldTextLiteral); 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!', '', tipMenuBgColor2, tipMenuTextColor2, boldTextLiteral); } tipMenuToken = 1; cb.setTimeout(checkUserGroupMenuNotice, 500); } } else if (tipMenuLength > 0 && cb.settings.tipMenuNoticeType == 'Split Menu - List Form' && menuListSplit) { if (tipMenuToken == 1) { cb.sendNotice(tipMenuPartArray[0],'', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); 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!', '', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } tipMenuToken = 2; cb.setTimeout(checkUserGroupMenuNotice, 500); } else if (tipMenuToken == 2) { cb.sendNotice(tipMenuPartArray[1],'', tipMenuBgColor2, tipMenuTextColor2, boldTextLiteral); 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!', '', tipMenuBgColor2, tipMenuTextColor2, boldTextLiteral); } if (tipMenuLength > 16) { tipMenuToken = 3; } else { tipMenuToken = 1; } cb.setTimeout(checkUserGroupMenuNotice, 500); } else if (tipMenuToken == 3) { cb.sendNotice(tipMenuPartArray[2],'', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); 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!', '', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } if (tipMenuLength > 24) { tipMenuToken = 4; } else { tipMenuToken = 1; } cb.setTimeout(checkUserGroupMenuNotice, 500); } else if (tipMenuToken == 4) { cb.sendNotice(tipMenuPartArray[3],'', tipMenuBgColor2, tipMenuTextColor2, boldTextLiteral); 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!', '', tipMenuBgColor2, tipMenuTextColor2, boldTextLiteral); } if (tipMenuLength > 32) { tipMenuToken = 5; } else { tipMenuToken = 1; } cb.setTimeout(checkUserGroupMenuNotice, 500); } else if (tipMenuToken == 5) { cb.sendNotice(tipMenuPartArray[4],'', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); 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!', '', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } tipMenuToken = 1; cb.setTimeout(checkUserGroupMenuNotice, 500); } } else if (tipMenuLength > 0) { cb.sendNotice(tipMenuDisplayText,'', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); 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!', '', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } cb.setTimeout(checkUserGroupMenuNotice, 500); } else { cb.sendNotice('Tip Menu setup error - there are no entries in the menu.', '', '#FFFFFF', '#FF0000', 'bold'); } cb.setTimeout(displayMenu,tipMenuDispInt); } } } function checkUserGroupMenuNotice() { messageReceiptArray = []; if (tipMenuModItemArray.length > 0) { for (let menuidx = 0; menuidx < moderatorList.name.length; menuidx++) { let sendtomod = moderatorList.name[menuidx].trim(); if (sendtomod != BC) { 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, '', boldTextLiteral); } messageReceiptArray.push(sendtomod); } } if (tipMenuCBFCItemArray.length > 0) { for (let menuidx = 0; menuidx < fanClubList.length; menuidx++) { let 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, '', boldTextLiteral); } 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, '', boldTextLiteral); } 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, '', boldTextLiteral); } messageReceiptArray.push(sendtocbfan); } } } if (tipMenuEFC1ItemArray.length > 0) { for (let menuidx = 0; menuidx < extFanInShowArray.length; menuidx++) { let 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, '', boldTextLiteral); } 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, '', boldTextLiteral); } 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, '', boldTextLiteral); } messageReceiptArray.push(sendtoextfan1); } } } if (tipMenuEFC2ItemArray.length > 0) { for (let menuidx = 0; menuidx < extFanInShow2Array.length; menuidx++) { let 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, '', boldTextLiteral); } 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, '', boldTextLiteral); } 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, '', boldTextLiteral); } messageReceiptArray.push(sendtoextfan2); } } } if (tipMenuVIPItemArray.length > 0) { for (let menuidx = 0; menuidx < VIPInShowArray.length; menuidx++) { let 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, '', boldTextLiteral); } } } } function displayMenu2() { if (tipMenu2Toggle) { 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', '', tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); 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!', '', tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); } } else if (tipMenu2Length > 0 && cb.settings.tipMenuNoticeType == 'Split Menu - Paragraph Form') { if (tipMenu2Token == 1) { cb.sendNotice(tipMenu2PartArray[0], '', tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); 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!', '', tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); } tipMenu2Token = 2; } else if (tipMenu2Token == 2) { cb.sendNotice(tipMenu2PartArray[1], '', tipMenu2BgColor2, tipMenu2TextColor2, boldTextLiteral); 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!', '', tipMenu2BgColor2, tipMenu2TextColor2, boldTextLiteral); } tipMenu2Token = 1; } } else if (tipMenu2Length > 0 && cb.settings.tipMenuNoticeType == 'Split Menu - List Form' && menu2ListSplit) { if (tipMenu2Token == 1) { cb.sendNotice(tipMenu2PartArray[0],'', tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); 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!', '', tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); } tipMenu2Token = 2; } else if (tipMenu2Token == 2) { cb.sendNotice(tipMenu2PartArray[1],'', tipMenu2BgColor2, tipMenu2TextColor2, boldTextLiteral); 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!', '', tipMenu2BgColor2, tipMenu2TextColor2, boldTextLiteral); } if (tipMenu2Length > 16) { tipMenu2Token = 3; } else { tipMenu2Token = 1; } } else if (tipMenu2Token == 3) { cb.sendNotice(tipMenu2PartArray[2],'', tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); 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!', '', tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); } tipMenu2Token = 1; } } else if (tipMenu2Length > 0) { cb.sendNotice(tipMenu2DisplayText,'', tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); 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!', '', tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); } } else { cb.sendNotice('Tip Menu #2 setup error - there are no entries in the menu.', '', '#FFFFFF', '#FF0000', 'bold'); } cb.setTimeout(displayMenu2,tipMenu2DispInt); } } } function setSepChar() { if (cb.settings.sepchar == 'Custom') { if (cb.settings.sepcharcustom) { tipMenuSepChar = cb.settings.sepcharcustom; } else { tipMenuSepChar = '|'; } } else { tipMenuSepChar = checkSepChar(cb.settings.sepchar); } tipMenuSepChar += ' '; } function setSepChar2() { if (cb.settings.sepchar == 'Custom') { if (cb.settings.sepcharcustom) { tipMenu2SepChar = cb.settings.sepcharcustom; } else { tipMenu2SepChar = '|'; } } else { tipMenu2SepChar = checkSepChar(cb.settings.sepchar); } tipMenu2SepChar += ' '; } // *************************** Positions Tip Menu Functions ************************ function setPosTipMenuToggle(setposopt,setposby) { let setposmenusendto = setposby; if (setposby == 'init') { setposmenusendto = BC; } if (setposopt == 'on') { if (posTipMenuToggle) { cb.sendNotice('The Positions Tip Menu is already enabled.',setposmenusendto,appNoticeColor); } else { posTipMenuToggle = true; initPosMenu(setposby); cb.sendNotice(' ' + setposmenusendto + ' has enabled the Positions Tip Menu. \nYou control the action by tipping for your favorite position!\nTo display the positions menu, type: /posmenu','',posMenuBgColor, posMenuTextColor,'bold'); } } else if (setposopt == 'off') { if (!posTipMenuToggle) { cb.sendNotice('The Positions Tip Menu is already disabled.',setposmenusendto,appNoticeColor); } else { posTipMenuToggle = false; posMenuPriceArray = []; posMenuItemArray = []; cb.sendNotice(' ' + setposmenusendto + ' has disabled the Positions Tip Menu. \nYou can no longer tip for positions.','',posMenuBgColor, posMenuTextColor,'bold'); } } else if (setposopt) { cb.sendNotice(setposopt + ' is not a valid option for /useposmenu.\nType /fbhelp positions to see how to use /usepostipmenu.',setposmenusendto,appNoticeColor); } else if (!setposopt) { cb.sendNotice('You did not enter a valid option for /useposmenu.\nType /fbhelp positions to see how to use /usepostipmenu.',setposmenusendto,appNoticeColor); } } function setPosMenuColors(spmby,stupflag) { if (cb.settings.posMenuTxtColor == 'Custom') { posMenuTextColor = setTextColor(cb.settings.posMenuCustTxtColor,'Positions Menu',spmby,stupflag); } else { posMenuTextColor = setTextColor(cb.settings.posMenuTxtColor,'Positions Menu',spmby,stupflag); } if (cb.settings.posMenuBgColor == 'Custom') { posMenuBgColor = setBgColor(cb.settings.posMenuCustBgColor,'Positions Menu',spmby,stupflag); } else { posMenuBgColor = setBgColor(cb.settings.posMenuBgColor,'Positions Menu',spmby,stupflag); } } function initPosMenu(initposmenuuser) { let maxItems = 8; setPosSepChar(); for (let j = 0; j <= maxItems; j++) { if (cb.settings['posMenuItem' + j] && cb.settings['posMenuItemPrice' + j] > 0) { posMenuPriceArray.push(cb.settings['posMenuItemPrice' + j]); posMenuItemArray.push(cb.settings['posMenuItem' + j]); priceChecker('add','Positions Menu Option: '+(cb.settings['posMenuItem' + j]), (cb.settings['posMenuItemPrice' + j]),initposmenuuser); } } posMenuLength = posMenuPriceArray.length; if (posMenuLength > 0) { buildPosMenuText(); cb.setTimeout(displayPosMenu,posMenuDispInt); } else { cb.sendNotice('Error - No positions menu items found, menu has been disabled.', '', '', posMenuTextColor, 'bold'); posTipMenuToggle = false; } } function buildPosMenuText() { posMenuDisplayText = bcText + '\'s ' + posMenuLiteralDesc + ' Tip Menu: \n'; let tempposmenuary = []; let tempposmenuarysort = []; for (let i = 0; i < posMenuLength; i++) { tempposmenuarysort.push({ "posprices": posMenuPriceArray[i], "posid": i }); } if (cb.settings.posListSort !== 'Do not sort the list') { tempposmenuarysort.sort(function(a, b) { return a.posprices - b.posprices; }); if (cb.settings.posListSort === 'Descending') { tempposmenuarysort.reverse(); } } for (let j = 0; j < tempposmenuarysort.length; j++) { if (posMenuPriceArray[tempposmenuarysort[j].posid] !== 0) { tempposmenuary.push(posMenuItemArray[tempposmenuarysort[j].posid] + ' (' + posMenuPriceArray[tempposmenuarysort[j].posid] + ') '); } } posMenuDisplayText += tempposmenuary.join(posMenuSepChar); } function displayPosMenu() { if (posTipMenuToggle) { if (minMessagesForNotice > 0 && msgCounterPosMenu < minMessagesForNotice) { cb.setTimeout(displayPosMenu, 30000); } else { msgCounterPosMenu = 0; if (posMenuLength > 0) { cb.sendNotice(posMenuDisplayText, '', posMenuBgColor, posMenuTextColor, boldTextLiteral); } else { cb.sendNotice('No options were added to the ' + posMenuLiteralDesc + ' Tip Menu', '', appNoticeColor); } cb.setTimeout(displayPosMenu,posMenuDispInt); } } } function setPosSepChar() { if (cb.settings.posSepChar == 'Custom') { if (cb.settings.posSepCharCustom) { posMenuSepChar = cb.settings.posSepCharCustom; } else { posMenuSepChar = '|'; } } else { posMenuSepChar = checkSepChar(cb.settings.posSepChar); } posMenuSepChar += ' '; } // *************************** Lush Menu Functions ************************ function setToyMenuToggle(slmtoption,slmtby) { if (slmtoption == 'on') { if(lushMenuToggle) { cb.sendNotice('The ' + whichToy + ' Menu is already enabled.',slmtby,appNoticeColor); } else { lushMenuToggle = true; buildToyMenu(); cb.setTimeout(toyMenuTimer,toyMenuDispInt); cb.sendNotice(' ' + slmtby + ' has enabled the ' + whichToy + ' Menu. Use the tip ranges on the menu to make the toy vibrate!','',toyMenuBgColor, toyMenuTextColor,'bold'); } } else if (slmtoption == 'off') { if (!lushMenuToggle) { cb.sendNotice('The ' + whichToy + ' Menu is already disabled.',slmtby,appNoticeColor); } else { lushMenuToggle = false; toyMenuLevelArray = []; cb.sendNotice(' ' + slmtby + ' has disabled the ' + whichToy + ' Menu.','',toyMenuBgColor, toyMenuTextColor,'bold'); } } else if (slmtoption) { cb.sendNotice(slmtoption + ' is not a valid option for /usetoy.',slmtby,appNoticeColor); } else if (!slmtoption) { cb.sendNotice('You did not enter a valid option for /usetoy.',slmtby,appNoticeColor); } } function setToyMenuColors(slmcby,stupflag) { if (cb.settings.lushMenuTxtColor == 'Custom') { toyMenuTextColor = setTextColor(cb.settings.lushMenuCustTxtColor,'Toy Menu',slmcby,stupflag); } else { toyMenuTextColor = setTextColor(cb.settings.lushMenuTxtColor,'Toy Menu',slmcby,stupflag); } if (cb.settings.lushMenuBgColor == 'Custom') { toyMenuBgColor = setBgColor(cb.settings.lushMenuCustBgColor,'Toy Menu',slmcby,stupflag); } else { toyMenuBgColor = setBgColor(cb.settings.lushMenuBgColor,'Toy Menu',slmcby,stupflag); } } function buildToyMenu() { toyMenuLevelArray = []; toyMenuDisplayText = ''; for (let j = 0; j <= 13; j++) { if (cb.settings['lushMenuLevel' + j] !== '') { toyMenuLevelArray.push(cb.settings['lushMenuLevel' + j]); } } toyMenuDisplayText = ' \u2665 ' + whichToyIcon + ' \u2665 ' + whichToyIcon + ' \u2665 ' + whichToyIcon + ' \u2665 ' + bcText + '\'s "' + whichToy + '" Toy Menu \u2665 ' + whichToyIcon + ' \u2665 ' + whichToyIcon + ' \u2665 ' + whichToyIcon + ' \u2665 '; toyMenuDisplayText += toyMenuLevelArray.join('\n'); } function toyMenuTimer() { if (lushMenuToggle) { if (minMessagesForNotice > 0 && msgCounterLushMenu < minMessagesForNotice) { cb.setTimeout(toyMenuTimer, 30000); } else { msgCounterLushMenu = 0; displayToyMenu('timer',''); cb.setTimeout(toyMenuTimer, toyMenuDispInt); } } } function displayToyMenu(toymenureqmode,toymenusendto) { let toymenumsg = ''; if (cb.settings.lushMenuDispType == 'Full Notice' || toymenureqmode == 'cmd') { toymenumsg = borderToyMenuTop; if (toymenureqmode == 'cmd') { if (toymenusendto == '') { toymenumsg += '\nSent to ALL:' } else { toymenumsg += '\nSent to YOU:' } } toymenumsg += '\n' + toyMenuDisplayText + borderUniversalBottom; } else { toymenumsg = 'To see the broadcaster\'s Tip Menu for the ' + whichToy + ', type: /toymenu'; } cb.sendNotice(toymenumsg, toymenusendto, toyMenuBgColor, toyMenuTextColor, boldTextLiteral); } // *************************** Token Poll Functions ************************ function setTokenPollToggle(setpollopt, setpollby) { let settokpollsendto = setpollby; if (setpollby == 'init') { settokpollsendto = BC; } if (setpollopt == 'on') { if(tokenPollToggle) { cb.sendNotice('The Token Poll is already enabled.', settokpollsendto, appNoticeColor); } else { tokenPollToggle = true; initTokenPoll(setpollby); cb.sendNotice(settokpollsendto + ' 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 (setpollopt == 'off') { if (!tokenPollToggle) { cb.sendNotice('The Token Poll is already disabled.', settokpollsendto, appNoticeColor); } else { for (let i = 0; i < pollArrayAmount.length; i++) { priceChecker('rmv','Poll Option: '+pollArrayLabel[i],pollArrayAmount[i],setpollby); } tokenPollToggle = false; cb.sendNotice(settokpollsendto + ' has disabled the Token Poll feature, voting will no longer be tracked.', '', tokenPollBgColor, tokenPollTextColor, 'bold'); pollRunning = false; } } else if (setpollopt) { cb.sendNotice(setpollopt + ' is not a valid option for /usepoll, valid values are "on" or "off".', settokpollsendto, appNoticeColor); } else if (!setpollopt) { cb.sendNotice('You did not enter a valid option for /usepoll, valid values are "on" or "off".', settokpollsendto, appNoticeColor); } } function initTokenPoll(initpollby) { 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; } pollRunning = true; pollTimerStopping = false; nline = 0; cb.setTimeout(pollBoardTimer, 30000); initPollTimer(); cb.setTimeout(displayPollReminder, 60000); totalPollVotes = 0; } function setPollColors(stpcby,stupflag) { if (cb.settings.pollTxtColor == 'Custom') { tokenPollTextColor = setTextColor(cb.settings.pollCustTxtColor,'Token Poll',stpcby,stupflag); } else { tokenPollTextColor = setTextColor(cb.settings.pollTxtColor,'Token Poll',stpcby,stupflag); } if (cb.settings.pollBgColor == 'Custom') { tokenPollBgColor = setBgColor(cb.settings.pollCustBgColor,'Token Poll',stpcby,stupflag); } else { tokenPollBgColor = setBgColor(cb.settings.pollBgColor,'Token Poll',stpcby,stupflag); } } function buildPollBoard(buildpollcalledby) { for (let i = 1; i <= 8; i++) { let 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]) { botLoadErrors.push('Warning! Tip Price Amount for Token Poll option ' + i + ' is not unique, it is not added to the board.'); oktoadd = 0; break; } else if (pollArrayLabel[j] === this['pollOptLabel'+i]) { botLoadErrors.push('Warning! Label/Description for Tip Menu option ' + i + ' is not unique, it is not added to the board.'); oktoadd = 0; break; } } if (oktoadd == 1) { populatePollArray(this['pollOptLabel'+i],this['pollOptTokens'+i],0,buildpollcalledby); priceChecker('add','Poll Option: '+this['pollOptLabel'+i], this['pollOptTokens'+i],'init'); } } else { botLoadErrors.push('Warning! Label/Description for Tip Menu option ' + i + ' is blank or null, not added to board.'); } } } } function displayPollReminder() { if (tokenPollToggle && pollRunning) { if (minMessagesForNotice > 0 && msgCounterTokenPoll < minMessagesForNotice) { cb.setTimeout(displayPollReminder, 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('Token Poll: Fan club members currently get two votes for the price of one!'); } pollNotice.push(showLead()); cb.sendNotice(pollNotice[nline], '', tokenPollBgColor, tokenPollTextColor, boldTextLiteral); nline += 1; if (nline >= pollNotice.length) { nline = 0; } cb.setTimeout(displayPollReminder,pollNoticeInt); } } } function populatePollArray(label,amount,votes,calledby) { if (!cbjs.arrayContains(pollArrayAmount, amount) && !cbjs.arrayContains(pollArrayLabel, label)) { let 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 pollBoardTimer(showpollreqby) { if (tokenPollToggle && pollRunning) { if (minMessagesForNotice > 0 && msgCounterTokenPoll < minMessagesForNotice) { cb.setTimeout(pollBoardTimer,30000); } else { msgCounterTokenPoll = 0; showBoard('timer','',false); cb.setTimeout(pollBoardTimer,pollNoticeInt); } } } function showBoard(showboardmode,showboardsendto,showboardpreview) { let pollboard = ''; if (pollRunning || showboardpreview) { pollboard += borderPollTop; } else { pollboard += borderPollResultsTop; } if (showboardmode == 'cmd') { if (showboardsendto == '') { pollboard += '\nSent to ALL:'; } else if (!showboardpreview) { pollboard += '\nSent to YOU:'; } else if (showboardpreview) { pollboard += '\nPoll Preview Sent to YOU:'; } } pollboard += '\n \u2753 \u2754 \u2753 \u2754 \u2753 ' + pollTitle + ' \u2753 \u2754 \u2753 \u2754 \u2753'; let pollarraysort = []; for (let pollbdidx = 0; pollbdidx < pollArrayAmount.length; pollbdidx++) { pollarraysort.push({ 'votes': pollArrayVotes[pollbdidx], 'id': pollbdidx }); } pollarraysort.sort(function(a, b) { return b.votes - a.votes; }); for (let pollbdidx2 = 0; pollbdidx2 < pollarraysort.length; pollbdidx2++) { if (0 != pollArrayAmount[pollarraysort[pollbdidx2].id]) { pollboard += '\n \u23E9 ' + pollArrayLabel[pollarraysort[pollbdidx2].id] + ' (Price = ' + pollArrayAmount[pollarraysort[pollbdidx2].id] + ' tokens): ' + pollArrayVotes[pollarraysort[pollbdidx2].id] + ' vote' + (pollArrayVotes[pollarraysort[pollbdidx2].id] != 1 ? 's' : ''); } } if (stealPollAmount > 0) { pollboard += '\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': pollboard += '\n' + votesRemain + ' vote' + (votesRemain == 1 ? '' : 's') + ' remaining before poll closes'; break; case 'Goal': pollboard += '\nFirst option to ' + cb.settings.pollCount + ' votes wins!'; break; } pollboard += '\nTip the token amount next to your choice to vote. \nTo see the current voting options and totals, type: /poll.'; if (pollMinimum > 1) { if (totalPollVotes >= pollMinimum) { pollboard += '\n' + wordWrap('The minimum total number of votes has been met! The poll result is valid.'); } else { let votesneeded = pollMinimum - totalPollVotes; pollboard += '\n' + wordWrap('The 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 if (showboardpreview) { } else { pollboard += '\nThe poll has been closed, no more voting!'; } pollboard += borderUniversalBottom; cb.sendNotice(pollboard, showboardsendto, tokenPollBgColor, tokenPollTextColor, boldTextLiteral); } function pollTip(polltipamount,voteAmount,tippedby) { for (let i = 0; i < pollArrayAmount.length; i++) { if (polltipamount == pollArrayAmount[i]) { pollArrayVotes[i] += voteAmount; totalPollVotes += voteAmount; if (voteAmount == 1) { cb.sendNotice(tippedby + ' voted for ' + pollArrayLabel[i], '', tokenPollBgColor, tokenPollTextColor, boldTextLiteral); } else { cb.sendNotice(tippedby + ' voted ' + voteAmount + ' time' + (voteAmount == 1 ? '' : 's') + ' for ' + pollArrayLabel[i], '', tokenPollBgColor, tokenPollTextColor, boldTextLiteral); } 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, boldTextLiteral); if (!aliveWarned) { aliveWarning(); } } if (pollType != 'Timer') { checkPollEnd(); } } } } function stealPoll(tippedby) { if (tokenPollToggle) { 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, boldTextLiteral); 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.', BC, 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.', BC, 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, boldTextLiteral); } 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() { let ptltime = timeCal(); let ptlms = ptltime % 1000; let ptlsec = ((ptltime - ptlms) % 60000); let ptlmin = ((ptltime - ptlsec - ptlms) % 3600000); let ptlhr = (ptltime - ptlmin - ptlsec - ptlms); ptlsec = ptlsec / 1000; ptlmin = ptlmin / 60000; ptlhr = ptlhr / 3600000; if (ptlhr > 0) { return ptlhr + ' hour' + (ptlhr > 1 ? 's' : '') + ' and ' + ptlmin + ' minute' + (ptlmin > 1 ? 's' : '') + ' remaining to vote.'; } else if (ptlmin > 0 && ptlsec === 0) { return ptlmin + ' minute' + (ptlmin > 1 ? 's' : '') + ' remaining to vote!'; } else if (ptlmin > 0) { return ptlmin + ' minute' + (ptlmin > 1 ? 's' : '') + ' and ' + ptlsec + ' second' + (ptlsec > 1 ? 's' : '') + ' remaining to vote!'; } else { return ptlsec + ' second' + (ptlsec > 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) { pollStopTime = new Date(pollStopTime.getTime() + polltimetoadd * 60000); let polltimetoaddabs = 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, boldTextLiteral); } else { cb.sendNotice(polltimetoaddabs + ' minute' + (polltimetoaddabs == 1 || polltimetoaddabs == -1 ? ' has' : 's have') + ' been subtracted from the timer. Now ' + pollTimeLeft(), '', tokenPollBgColor, tokenPollTextColor, boldTextLiteral); } pollMinsRemain = pollMinsRemain + polltimetoadd; if (pollMinsRemain > 0) { pollDisplaySeconds = false; } else { pollDisplaySeconds = true; } } function pollSwitchToTimer(timetoadd) { 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, boldTextLiteral); 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, boldTextLiteral); break; case 1: cb.sendNotice('\u231A \u231A \u231A There is 1 minute left to vote!!! \u231A \u231A \u231A', '', red, '', boldTextLiteral); 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, '', boldTextLiteral); break; case 1: cb.sendNotice('\u231A \u231A \u231A There is 1 second left to vote!!! \u231A \u231A \u231A', '', red, '', boldTextLiteral); break; } } if (pollSecsRemain < 1) { if (pollMinsRemain >= 1) { pollTimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Time is up! No more Votes!!! \u23f0 \u23f0 \u23f0', '', appWarningColor, '', boldTextLiteral); 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) { 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 setODPollColors(sodpcby,stupflag) { odtokenPollTextColor = setTextColor('Dark Purple','On-Demand Token Poll',sodpcby,stupflag); odtokenPollBgColor = setBgColor('Light Pink','On-Demand Token Poll',sodpcby,stupflag); } 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) { let 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; initODPollTimer(); odpollBoardTimer(); 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 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('On Demand Poll: Fan club members currently get two votes for the price of one!'); } odpollNotice.push(odshowLead()); cb.sendNotice(odpollNotice[nlineOD], '', odtokenPollBgColor, odtokenPollTextColor, boldTextLiteral); 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; let odpolllead = ''; 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 odpollBoardTimer() { if (onDemandPollRunning) { if (minMessagesForNotice > 0 && msgCounterTokenPoll < minMessagesForNotice) { cb.setTimeout(odpollBoardTimer,30000); } else { msgCounterTokenPoll = 0; showODBoard('timer',''); cb.setTimeout(odpollBoardTimer,ODpollNoticeInt); } } } function showODBoard(odpollmode,odpollsendto) { let odpollboard = ''; if (onDemandPollRunning) { odpollboard += borderOdPollTop; } else { odpollboard += borderPollResultsTop; } if (odpollmode == 'cmd') { if (odpollsendto == '') { odpollboard += '\nSent to ALL:'; } else { odpollboard += '\nSent to YOU:'; } } odpollboard += '\n \u25c7 \u25c7 \u25c7 \u25c7 \u25c7 \u25c7 ' + odpollTitle + ' \u25c7 \u25c7 \u25c7 \u25c7 \u25c7 \u25c7'; let odsortedvotes = []; for (let odpbidx = 0; odpbidx < odpollArrayAmount.length; odpbidx++) { odsortedvotes.push({ 'odvotes': odpollArrayVotes[odpbidx], 'odid': odpbidx }); } odsortedvotes.sort(function(a, b) { return b.odvotes - a.odvotes; }); for (let odpbidx2 = 0; odpbidx2 < odsortedvotes.length; odpbidx2++) { if (0 != odpollArrayAmount[odsortedvotes[odpbidx2].odid]) { odpollboard += '\n \u23E9 ' + odpollArrayLabel[odsortedvotes[odpbidx2].odid] + ' (Price = ' + odpollArrayAmount[odsortedvotes[odpbidx2].odid] + ' tokens): ' + odpollArrayVotes[odsortedvotes[odpbidx2].odid] + ' vote' + (odpollArrayVotes[odsortedvotes[odpbidx2].odid] != 1 ? 's' : ''); } } if (stealPollAmount > 0) { odpollboard += '\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) { odpollboard += '\nSimply tip the shown token amounts to register your vote. \nTo see the current voting options and totals, type: /poll'; } else { odpollboard += '\nThe poll has been closed, no more voting!'; } odpollboard += borderUniversalBottom; cb.sendNotice(odpollboard, odpollsendto, odtokenPollBgColor, odtokenPollTextColor, boldTextLiteral); } function odpollTip(odpolltipamount,voteAmount,tippedby) { let odpollindex = odpollArrayAmount.indexOf(odpolltipamount); odpollArrayVotes[odpollindex] += voteAmount; let votedfor = odpollArrayLabel[odpollindex]; if (voteAmount == 1) { cb.sendNotice(tippedby + ' voted for ' + votedfor + '.', '', odtokenPollBgColor, odtokenPollTextColor, boldTextLiteral); } else { cb.sendNotice('Fanclub member ' + tippedby + ' voted twice for ' + votedfor + '.', '', odtokenPollBgColor, odtokenPollTextColor, boldTextLiteral); } } 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, boldTextLiteral); } 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() { let odptltime = odtimeCal(); let odptlms = odptltime % 1000; let odptlsec = ((odptltime - odptlms) % 60000); let odptlmin = ((odptltime - odptlsec - odptlms) % 3600000); let odptlhr = (odptltime - odptlmin - odptlsec - odptlms); odptlsec = odptlsec / 1000; odptlmin = odptlmin / 60000; odptlhr = odptlhr / 3600000; if (odptlhr > 0) { return odptlhr + ' hour' + (odptlhr > 1 ? 's' : '') + ' and ' + odptlmin + ' minute' + (odptlmin > 1 ? 's' : '') + ' remaining to vote.'; } else if (odptlmin > 0 && odptlsec === 0) { return odptlmin + ' minute' + (odptlmin > 1 ? 's' : '') + ' remaining to vote!'; } else if (odptlmin > 0) { return odptlmin + ' minute' + (odptlmin > 1 ? 's' : '') + ' and ' + odptlsec + ' second' + (odptlsec > 1 ? 's' : '') + ' remaining to vote!'; } else { return odptlsec + ' second' + (odptlsec > 1 ? 's' : '') + ' remaining to vote!!!'; } } function initODPollTimer() { odpollStartTime = new Date(); odpollStopTime = new Date(odpollStartTime.getTime() + cb.settings.pollCount * 60000); odpollTimerMin(); } function odpollAddTime(odpolltimetoadd) { odpollStopTime = new Date(odpollStopTime.getTime() + odpolltimetoadd * 60000); let odtimetoaddabs = Math.abs(odpolltimetoadd); if (odpolltimetoadd > 0) { cb.sendNotice(odpolltimetoadd + ' minute' + (odpolltimetoadd == 1 || odpolltimetoadd == -1 ? ' has' : 's have') + ' been added to the timer. Now ' + odpollTimeLeft(), '', odtokenPollBgColor, odtokenPollTextColor, boldTextLiteral); } else { cb.sendNotice(odtimetoaddabs + ' minute' + (odtimetoaddabs == 1 || odtimetoaddabs == -1 ? ' has' : 's have') + ' been subtracted from the timer. Now ' + odpollTimeLeft(), '', odtokenPollBgColor, odtokenPollTextColor, boldTextLiteral); } odpollMinsRemain = odpollMinsRemain + odpolltimetoadd; if (odpollMinsRemain > 0) { odpollDisplaySeconds = false; } else { odpollDisplaySeconds = true; } } function odpollSwitchToTimer(timetoadd) { 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, boldTextLiteral); 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, boldTextLiteral); break; case 1: cb.sendNotice('\u231A \u231A \u231A There is 1 minute left to vote!!! \u231A \u231A \u231A', '', red, '', boldTextLiteral); 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, '', boldTextLiteral); break; case 1: cb.sendNotice('\u231A \u231A \u231A There is 1 second left to vote!!! \u231A \u231A \u231A', '', red, '', boldTextLiteral); break; } } if (odpollSecsRemain < 1) { if (odpollMinsRemain >= 1) { odpollTimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Time is up! No more Votes!!! \u23f0 \u23f0 \u23f0', '', appWarningColor, '', boldTextLiteral); 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) { 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); cb.setTimeout(textPollBoardTimer, 30000); initTextPollTimer(); loadTextPollReminder(); cb.setTimeout(displayTextPollReminder, 60000); } function initTextPollValues() { textPollRunning = true; textPollTimerStopping = false; textPollUsersVoted = []; textPollVotesRemain = cb.settings.textPollCount; textPollTotalVotes = 0; } function setTextPollColors(stxtpcby,stupflag) { if (cb.settings.textPollTextColor == 'Custom') { textPollTextColor = setTextColor(cb.settings.textPollCustTextColor,'Text Poll',stxtpcby,stupflag); } else { textPollTextColor = setTextColor(cb.settings.textPollTextColor,'Text Poll',stxtpcby,stupflag); } if (cb.settings.textPollBgColor == 'Custom') { textPollBgColor = setBgColor(cb.settings.textPollCustBgColor,'Text Poll',stxtpcby,stupflag); } else { textPollBgColor = setBgColor(cb.settings.textPollBgColor,'Text Poll',stxtpcby,stupflag); } } function buildTextPollBoard(buildtextcalledby) { for (let i = 1; i <= 5; i++) { let 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 loadTextPollReminder() { textPollNotice.push('A Text Poll is currently running. \nTo see the current voting options and totals, type: /textpoll'); if (fanDouble) { textPollNotice.push('Text Poll: Fan club members currently get two votes for the price of one!'); } textPollNotice.push(showTextPollLead()); } function displayTextPollReminder() { if (textPollToggle && textPollRunning) { if (minMessagesForNotice > 0 && msgCounterTextPoll < minMessagesForNotice) { cb.setTimeout(displayTextPollReminder, 30000); } else { msgCounterTextPoll = 0; cb.sendNotice(textPollNotice[textPollReminderToken], '', textPollBgColor, textPollTextColor, boldTextLiteral); textPollReminderToken++; if (textPollReminderToken >= textPollNotice.length) { textPollReminderToken = 0; } cb.setTimeout(displayTextPollReminder, 90000); } } } function textPollBoardTimer() { if (textPollToggle && textPollRunning) { if (minMessagesForNotice > 0 && msgCounterTextPoll < minMessagesForNotice) { cb.setTimeout(textPollBoardTimer,30000); } else { msgCounterTextPoll = 0; showTextPollBoard('timer',''); cb.setTimeout(textPollBoardTimer,textPollNoticeInt); } } } function showTextPollBoard(textpollmode,textpollsendto) { if (textPollToggle) { let textpollboard = ''; if (textPollRunning) { textpollboard += borderTextPollTop; } else { textpollboard += borderPollResultsTop; } if (textpollmode == 'cmd') { if (textpollsendto == '') { textpollboard += '\nSent to ALL:'; } else { textpollboard += '\nSent to YOU:'; } } textpollboard += '\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({ 'textvotes': textPollArray.votes[tparraysortidx], 'textid': tparraysortidx }); } tparraysort.sort(function(a, b) { return b.textvotes - a.textvotes; }); for (let tparraysortidx2 = 0; tparraysortidx2 < tparraysort.length; tparraysortidx2++) { if (0 != textPollArray.voteID[tparraysort[tparraysortidx2].textid]) { textpollboard += '\n \u23E9 ' + textPollArray.dispname[tparraysort[tparraysortidx2].textid] + ' (Choice #' + textPollArray.voteID[tparraysort[tparraysortidx2].textid] + '): ' + textPollArray.votes[tparraysort[tparraysortidx2].textid] + ' vote' + (textPollArray.votes[tparraysort[tparraysortidx2].textid] != 1 ? 's' : ''); } } if (textPollRunning) { switch (textPollType) { case 'Timer': break; case 'Vote': textpollboard += '\n' + textPollVotesRemain + ' vote' + (textPollVotesRemain == 1 ? '' : 's') + ' remaining before poll closes'; break; case 'Goal': textpollboard += '\nFirst option to ' + cb.settings.textPollCount + ' votes wins!'; break; } if (textPollArray.dispname.length > 2) { textpollboard += '\nTo 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 { textpollboard += '\nTo 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 { textpollboard += '\nThe text poll has been closed, no more voting!'; } textpollboard += borderUniversalBottom; cb.sendNotice(textpollboard, textpollsendto, textPollBgColor, textPollTextColor, boldTextLiteral); } } function textPollVote(votedID,votedamount,votedby) { let 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, boldTextLiteral); } else { cb.sendNotice(votedby + ' voted ' + votedamount + ' time' + (votedamount == 1 ? '' : 's') + ' for " ' + textPollArray.dispname[voteoptionidx] + ' "', '', textPollBgColor, textPollTextColor, boldTextLiteral); } 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, boldTextLiteral); } 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[tploptions[0]] - textPollArray.votes[tploptions[1]]) + ' vote' + ((textPollArray.votes[tploptions[0]] - textPollArray.votes[tploptions[1]]) === 1 ? '' : 's') + '.'; } else { tplead = 'Text Poll: We have a ' + leadCount + '-way tie between ' + formatTextArray(tpleadopt,'and') + '.'; } return tplead; } function formatTextArray(arr,andor){ let 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() { let textpolltimeleft = textPollTimeCal(); let txtmilliseconds = textpolltimeleft % 1000; let txtseconds = ((textpolltimeleft - txtmilliseconds) % 60000); let txtminutes = ((textpolltimeleft - txtseconds - txtmilliseconds) % 3600000); let 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) { textPollStopTime = new Date(textPollStopTime.getTime() + textpolltimetoadd * 60000); let 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, '', boldTextLiteral); } else { cb.sendNotice(texttimetoaddabs + ' minute' + (texttimetoaddabs == 1 || texttimetoaddabs == -1 ? ' has' : 's have') + ' been subtracted from the timer. Now ' + textPollTimeLeft(), '', appWarningColor, '', boldTextLiteral); } textPollMinsRemain = textPollMinsRemain + textpolltimetoadd; if (textPollMinsRemain > 0) { textPollDisplaySeconds = false; } else { textPollDisplaySeconds = true; } } function textPollSwitchToTimer(tptimetoadd) { 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, '', boldTextLiteral); 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, '', boldTextLiteral); break; case 1: cb.sendNotice('\u231A \u231A \u231A There is 1 minute left to vote in the text poll!!! \u231A \u231A \u231A', '', red, '', boldTextLiteral); 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, '', boldTextLiteral); break; case 1: cb.sendNotice('\u231A \u231A \u231A There is 1 second left to vote!!! \u231A \u231A \u231A', '', red, '', boldTextLiteral); break; } } if (textPollSecsRemain < 1) { if (textPollMinsRemain >= 1) { textPollTimerMin(); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Time is up! No more Votes!!! \u23f0 \u23f0 \u23f0', '', appWarningColor, '', boldTextLiteral); 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(prepuser) { if (cb.settings.prepticketStartPoll == 'Yes' && !tokenPollToggle) { setTokenPollToggle('on',prepuser); } if (cb.settings.prepticketTipMenuOff == 'Yes' && tipMenuToggle) { setTipMenuToggle('off',prepuser); } if (cb.settings.prepticketDiceOff == 'Yes' && diceToggle) { setDiceToggle('off',prepuser); } if (cb.settings.prepticketPosMenuOn == 'Yes' && posMenuItemArray.length > 0 && !posTipMenuToggle) { setPosTipMenuToggle('on',prepuser); } if (!backupToggle && ticketShowType != 'Fembot Ticket Show') { if (ticketPrice > 0) { setBackupToggle('on',prepuser,true); } else { cb.sendNotice('Note: Fembot Backup Ticket List feature could not be started, the ticket price value is not set.\nIf you would like to use the optional backup list, first set the price to use with the command "/bup xx", where xx is the amount in tokens.\nUsers who buy a ticket by tipping this amount or higher will then also be added to the backup ticket list.', prepuser, appNoticeColor); } } } function addFromLeaderboard(addfrlbmode,addfrlbnum,addfrlbsendto) { sortTippers(); let addlbstring = ''; switch (addfrlbmode) { case 'num': { for (let addfrlbidx = 1; addfrlbidx <= addfrlbnum; addfrlbidx++) { let addlbtipper = tipCountArray.name[addfrlbidx-1]; if (addlbtipper) { if (!cb.limitCam_userHasAccess(addlbtipper)) { if (ticketShowType == 'Fembot Ticket Show') { addRmvTicket('add',addlbtipper,'',0,addlbtipper); addlbstring += addlbtipper; } else { if (addfrlbidx > 1) { addlbstring += ', '; } addlbstring += addlbtipper; } } else { cb.sendNotice('User ' + addlbtipper + ' already has access to the show and was therefore skipped.', addfrlbsendto, appNoticeColor); } } } return (addlbstring); break; } case 'amt': { for (let addfrlbidx2 = 1; addfrlbidx2 <= 99; addfrlbidx2++) { let addlbtipper2 = tipCountArray.name[addfrlbidx2-1]; if (addlbtipper2 && tipCountArray.amount[addfrlbidx2-1] >= addfrlbnum) { if (!cb.limitCam_userHasAccess(addlbtipper2)) { if (ticketShowType == 'Fembot Ticket Show') { addRmvTicket('add',addlbtipper2,'',0,addlbtipper2); addlbstring += addlbtipper2; } else { if (addfrlbidx2 > 1) { addlbstring += ', '; } addlbstring += addlbtipper2; } } else { cb.sendNotice('User ' + addlbtipper2 + ' already has access to the show and was therefore skipped.', addfrlbsendto, appNoticeColor); } } } break; } } return (addlbstring); } function addRmvTicketBackupList(addrmvtktbumode,addrmvtktbuuser) { switch (addrmvtktbumode) { case 'add': { if(!cbjs.arrayContains(backupListArray,addrmvtktbuuser)) { backupListArray.push(addrmvtktbuuser); } break; } case 'rmv': { if(cbjs.arrayContains(backupListArray,addrmvtktbuuser)) { cbjs.arrayRemove(backupListArray,addrmvtktbuuser); } break; } case 'addtip': { backupListArray.push(addrmvtktbuuser); 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) { let setbutktsendto = sendto; if (sendto == 'init') { setbutktsendto = BC; } priceChecker('rmv','Backup Ticket Price', backupPrice, sendto); backupPrice = amount; priceChecker('add','Backup Ticket Price', backupPrice, sendto); if (enablePresales != 'Yes') { if (sendto == 'init') { botLoadErrors.push('Price updated for Backup Ticket List, all single tips of at least ' + amount + ' tokens will add a user to the Backup Ticket List, which can be used to recover your ticketholder list if ticket app fails or is closed accidentally.'); } else { cb.sendNotice(botName + 'Backup ticket list price updated, all single tips of at least ' + amount + ' tokens will add a user to the Backup Ticket List, which can be used to recover your ticketholder list if ticket app fails or is closed accidentally.', setbutktsendto, appNoticeColor); } } } function setBackupToggle(mode,mod,bycmd) { if (mode == 'on') { if (backupToggle) { cb.sendNotice('The Backup Ticket List is already enabled.',mod,appNoticeColor); } else { backupToggle = true; if (bycmd) { cb.sendNotice('You have enabled the Backup Ticket List.',mod,appNoticeColor); } } } else if (mode == 'off') { if (!backupToggle) { cb.sendNotice('The Backup Ticket List is already disabled.',mod,appNoticeColor); } else { backupToggle = false; cb.sendNotice('You have disabled the Backup Ticket List.',mod,appNoticeColor); } } } // *********************************** Media Display Function ************************************** function setMediaToggle(mode,mod,bycmd) { if (mode == 'on') { if (mediaToggle) { cb.sendNotice('The Media List is already enabled.', mod, appNoticeColor); } else { mediaToggle = true; cb.setTimeout(mediaListTimer,mediaTimerInt); if (bycmd) { cb.sendNotice('You have enabled the Media List.', mod, appNoticeColor); } } } else if (mode == 'off') { if (!mediaToggle) { cb.sendNotice('The Media List is already disabled.', mod, appNoticeColor); } else { mediaToggle = false; cb.sendNotice('You have disabled the Media List.', mod, appNoticeColor); } } } function setMediaColors(smedcby,stupflag) { if (cb.settings.mediaListTxtColor == 'Custom') { mediaforeground = setTextColor(cb.settings.mediaListCustTxtColor,'Media List',smedcby,stupflag); } else { mediaforeground = setTextColor(cb.settings.mediaListTxtColor,'Media List',smedcby,stupflag); } if (cb.settings.mediaListBgColor == 'Custom') { mediabackground = setBgColor(cb.settings.mediaListCustBgColor,'Media List',smedcby,stupflag); } else { mediabackground = setBgColor(cb.settings.mediaListBgColor,'Media List',smedcby,stupflag); } } function mediaListTimer() { if (mediaToggle) { if (minMessagesForNotice > 0 && msgCounterMedia < minMessagesForNotice) { cb.setTimeout(mediaListTimer, 30000); } else { msgCounterMedia = 0; showMedia('','timer'); cb.setTimeout(mediaListTimer,mediaTimerInt); } } } function showMedia(smsendto,smreqby) { let mediamessage = ''; if (cb.settings.mediaListDispType == 'Full Notice' || smreqby == 'cmd') { mediamessage = borderMediaTop; if (smreqby == 'cmd') { if (smsendto == '') { mediamessage += '\nSent to ALL:' } else { mediamessage += '\nSent to YOU:' } } 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 += borderUniversalBottom; } else { mediamessage = 'To see the broadcaster\'s media links and contact info, type: /media'; } cb.sendNotice(mediamessage, smsendto, mediabackground, mediaforeground, boldTextLiteral); } // *********************************** Guest List Display Function ************************************** function setGuestToggle(sgtmode,sgtsendto,sgtbycmd) { if (sgtmode == 'on') { if (guestToggle) { cb.sendNotice('The Guest List Notice is already enabled.', sgtsendto, appNoticeColor); } else { guestToggle = true; cb.setTimeout(guestListTimer,guestListInt); if (sgtbycmd) { cb.sendNotice('You have enabled the Guest List Notice.', sgtsendto, appNoticeColor); } } } else if (sgtmode == 'off') { if (!guestToggle) { cb.sendNotice('The Guest List Notice is already disabled.', sgtsendto, appNoticeColor); } else { guestToggle = false; cb.sendNotice('You have disabled the Guest List Notice.', sgtsendto, appNoticeColor); } } } function setGuestColors(sgcby,sgcstupflag) { if (cb.settings.guestListTextColor == 'Custom') { guestListTextColor = setTextColor(cb.settings.guestListCustTextColor,'Guest List Notice',sgcby,sgcstupflag); } else { guestListTextColor = setTextColor(cb.settings.guestListTextColor,'Guest List Notice',sgcby,sgcstupflag); } if (cb.settings.guestListBgColor == 'Custom') { guestListBgColor = setBgColor(cb.settings.guestListCustBgColor,'Guest List Notice',sgcby,sgcstupflag); } else { guestListBgColor = setBgColor(cb.settings.guestListBgColor,'Guest List Notice',sgcby,sgcstupflag); } } function guestListTimer() { if (guestToggle) { if (minMessagesForNotice > 0 && msgCounterGuest < minMessagesForNotice) { cb.setTimeout(guestListTimer, 30000); } else { msgCounterGuest = 0; showGuests('','timer'); cb.setTimeout(guestListTimer,guestListInt); } } } function showGuests(sgsendto,sgreqfrom) { let guestmessage = ''; if (cb.settings.guestListDispType == 'Full Notice' || sgreqfrom == 'cmd') { guestmessage = borderGuestTop; if (cb.settings.guestListIntro) { guestmessage += '\n' + wordWrap(cb.settings.guestListIntro); } for (let j = 1; j <= 3; j++) { if (this['guestListEnable'+j] == 'Yes') { guestmessage += '\n \uD83D\uDD39 \uD83D\uDD39 \uD83D\uDD39 \uD83D\uDD39 \uD83D\uDD39 \uD83D\uDD39 \uD83D\uDD39 \uD83D\uDD39 \uD83D\uDD39 \uD83D\uDD39'; if (this['guestListUsername'+j]) { guestmessage += '\nGuest Name: ' + this['guestListUsername'+j]; } if (this['guestListComment'+j]) { guestmessage += wordWrap('\nIntro: ' + this['guestListComment'+j]); } let notecounter = 1; for (let k = 1; k <= 3; k++) { if (this['guestListLink'+k+'_'+j]) { guestmessage += '\nNote/Link ' + notecounter + ': ' + this['guestListLink'+k+'_'+j]; notecounter++; } } } } guestmessage += borderUniversalBottom; } else { guestmessage = 'To see the contact and media info for today\'s guests, type: /guests'; } cb.sendNotice(guestmessage, sgsendto, guestListBgColor, guestListTextColor, boldTextLiteral); } // *********************************** Require Answer Chat Lock Function ************************************** function setRequireAnswerToggle(mode,setby,bycmd) { if (mode == 'on') { if (requireAnswerToggle) { cb.sendNotice('The "Answer Required" Chat Lock is already enabled at the level of ' + requireAnswerLevelText + '.', setby, appNoticeColor); } else { requireAnswerToggle = true; 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) { cb.sendNotice('The "Answer Required" Chat Lock is already disabled.', setby, appNoticeColor); } else { requireAnswerLevel = 0; requireAnswerLevelText = 'Not Used'; requireAnswerToggle = false; cb.sendNotice('You have disabled the "Answer Required" Chat Lock.', setby, appNoticeColor); } } } function requireAnswerLockCheck(checklockuser) { if (!cbjs.arrayContains(answerLockList,checklockuser)) { addToAnswerLockList(checklockuser); } let answeruserindex = answerLockList.indexOf(checklockuser); if (answerLockStatus[answeruserindex]) { return true; } else { return false; } } function addToAnswerLockList(addlockuser) { let initcanchat = false; let answeraddnum1 = Math.floor(Math.random() * 100) + 1; let answeraddnum2 = Math.floor(Math.random() * 100) + 1; answerLockList.push(addlockuser); answerLockStatus.push(initcanchat); answerLockQuestion.push('What is the sum of ' + answeraddnum1 + ' plus ' + answeraddnum2 + '?'); answerLockAnswer.push(answeraddnum1 + answeraddnum2); } function clearAnswerLock() { answerLockList = []; answerLockStatus = []; answerLockQuestion = []; answerLockAnswer = []; } // *********************************** Gray Chat Lock Function ************************************** function setGrayLockToggle(setlockopt, setlockby) { if (setlockopt == 'on') { if (grayLockToggle) { cb.sendNotice('The Gray Chat Lock is already enabled with threshold set to ' + grayChatTime + ' minutes.', setlockby, appNoticeColor); } else { grayLockToggle = true; cb.sendNotice('You have enabled the Gray Chat Lock with the configured threshold set to ' + grayChatTime + ' minutes.', setlockby, appNoticeColor); } } else if(setlockopt == 'off') { if(!grayLockToggle) { cb.sendNotice('The Gray Chat Lock is already disabled.', setlockby, appNoticeColor); } else { grayLockToggle = false; cb.sendNotice('You have disabled the Gray Chat Lock.', setlockby, appNoticeColor); } } else if (setlockopt) { cb.sendNotice(setlockopt + ' is not a valid option for /usegraylock, the option should be "on" or "off".', setlockby, appNoticeColor); } else if (!setlockopt) { cb.sendNotice('You did not enter a valid option for /usegraylock, the option should be "on" or "off".', setlockby, appNoticeColor); } } function grayLockCheck(userlock,isbclock,ismodlock,isfanlock,isgraylock) { if (!cbjs.arrayContains(grayLockList,userlock)) { addToLockList(userlock,isbclock,ismodlock,isfanlock,isgraylock); } let grayidx = grayLockList.indexOf(userlock); if (grayLockStatus.canChat[grayidx]) { return true; } else if (grayExpired(grayLockStatus.entered[grayidx])) { grayLockStatus.canChat[grayidx] = true; return true; } else { return false; } } function grayExpired(enteredDateTime) { return grayTimeElapsed(enteredDateTime) >= grayChatTime; } function grayTimeElapsed(enteredDateTime) { let graynowdate = Date.now(); let grayelapsedmin = Math.floor((graynowdate - enteredDateTime) / (1000 * 60)); return grayelapsedmin; } function addToLockList(userlkadd,isbclkadd,ismodlkadd,isfanlkadd,isgraylkadd) { let initcanchat = false; if (isbclkadd || !isgraylkadd || isfanlkadd || ismodlkadd || cbjs.arrayContains(VIPListArray,userlkadd) || cbjs.arrayContains(extFanListArray,userlkadd) || cbjs.arrayContains(extFanList2Array,userlkadd)) { initcanchat = true; } grayLockList.push(userlkadd); grayLockStatus.entered.push(Date.now()); grayLockStatus.canChat.push(initcanchat); } function grayTimeLeft(gtluser) { var ERR = -1; if (!cbjs.arrayContains(grayLockList,gtluser)) { return ERR; } let graytimeentered = grayLockStatus.entered[grayLockList.indexOf(gtluser)]; return grayChatTime - grayTimeElapsed(graytimeentered); } function addRmvGrayLock(argraymode,argrayuser,argraysendto) { if (argraymode == 'a') { if (grayLockStatus.canChat[grayLockList.indexOf(argrayuser)] == false) { cb.sendNotice(argrayuser + ' is already on chat restricted time lock.', argraysendto, appNoticeColor); } else { grayLockStatus.canChat[grayLockList.indexOf(argrayuser)] = false; grayLockStatus.entered[grayLockList.indexOf(argrayuser)] = Date.now(); cb.sendNotice('You have added ' + argrayuser + ' to the chat restricted time lock, and reset their timer to start now and last for ' + grayChatTime + ' minutes.', argraysendto, appNoticeColor); } } else if (argraymode == 'r') { if (grayLockStatus.canChat[grayLockList.indexOf(argrayuser)] == false) { grayLockStatus.canChat[grayLockList.indexOf(argrayuser)] = true; cb.sendNotice('You have removed ' + argrayuser + ' from the chat restricted time lock. They are now free to chat.', argraysendto, appNoticeColor); } else { cb.sendNotice(argrayuser + ' is not on chat restricted time lock.', argraysendto, 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(setdiceoption,setdiceby) { let setdicesendto = setdiceby; if (setdiceby == 'init') { setdicesendto = BC; } if (setdiceoption == 'on') { if (diceToggle) { cb.sendNotice('The Dice Game is already enabled.', setdicesendto, appNoticeColor); } else { diceToggle = true; setDiceIconColor(); diceSetPrizes(); cb.setTimeout(diceNoticeTimer, diceInt); cb.sendNotice(setdicesendto + ' has enabled the dice game!', '', diceNoticeBgColor, diceNoticeTextColor, 'bold'); priceChecker('add','Dice Roll Price', diceRollPrice,setdiceby); } } else if (setdiceoption == 'off') { if (!diceToggle) { cb.sendNotice('The Dice Game is already disabled.', setdicesendto, appNoticeColor); } else { diceToggle = false; cb.sendNotice(setdicesendto + ' has disabled the dice game.\nYou can no longer tip to roll the dice.', '', diceNoticeBgColor, diceNoticeTextColor, 'bold'); } } else if (setdiceoption) { cb.sendNotice(setdiceoption + ' is not a valid parameter for the /usedice command. \nThe parameter should be "on" or "off".', setdicesendto, appNoticeColor); } else if (!setdiceoption) { cb.sendNotice('You did not enter a valid parameter for the /usedice command. \nThe parameter should be "on" or "off".', setdicesendto, appNoticeColor); } } function setDiceNoticeColors(sdncby,stupflag) { diceNoticeTextColor = setTextColor('#000000','Dice Notice',sdncby,stupflag); if (cb.settings.diceNoticeBgColor == 'Custom') { diceNoticeBgColor = setBgColor(cb.settings.diceNoticeBgCustColor,'Dice Notice',sdncby,stupflag); } else { diceNoticeBgColor = setBgColor(cb.settings.diceNoticeBgColor,'Dice Notice',sdncby,stupflag); } } function setDiceColors(sdcby,stupflag) { diceRollTextColor = setTextColor('#000000','Dice Game',sdcby,stupflag); if (cb.settings.diceRollBgColor == 'Custom') { diceRollBgColor = setBgColor(cb.settings.diceRollBgCustColor,'Dice Roll',sdcby,stupflag); } else { diceRollBgColor = setBgColor(cb.settings.diceRollBgColor,'Dice Roll',sdcby,stupflag); } if (cb.settings.diceRollBgColorSpecial == 'Custom') { diceRollBgSpecial = setBgColor(cb.settings.diceRollBgCustColorSpecial,'Dice Roll Special',sdcby,stupflag); } else { diceRollBgSpecial = setBgColor(cb.settings.diceRollBgColorSpecial,'Dice Roll Special',sdcby,stupflag); } } function setDiceIconColor() { if (cbjs.arrayContains(diceIconArray.dispname,cb.settings.diceColor)) { let diceiconidx = diceIconArray.dispname.indexOf(cb.settings.diceColor); diceColorShortcut = diceIconArray.iconabb[diceiconidx]; } else { botLoadErrors.push('Error loading the dice color name, "' + cb.settings.diceColor + '" does not exist in the program array. Defaulting to Red and White.'); diceColorShortcut = 'redwh_'; } } function diceNoticeTimer() { if (diceToggle) { if (minMessagesForNotice > 0 && msgCounterDice < minMessagesForNotice) { cb.setTimeout(diceNoticeTimer, 30000); } else { msgCounterDice = 0; diceShowNotice(''); cb.setTimeout(diceNoticeTimer,diceInt); } } } function diceShowNotice(sendto) { let dicegamemsg = borderDiceTop; 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 += borderUniversalBottom; cb.sendNotice(dicegamemsg, sendto, diceNoticeBgColor, diceNoticeTextColor, boldTextLiteral); } function diceRoll(rolledby) { diceRollCounter++; diceRollCounterSpecial++; let firstdie = Math.floor(Math.random() * 6) + 1; let seconddie = Math.floor(Math.random() * 6) + 1; if (diceRollCounterSpecial > diceMinSpecial) { if (Math.random() <= (diceRarePct / 100)) { firstdie = 7; diceRollCounterSpecial = 0; } } let dicetotal = firstdie + seconddie; let dicewinner = false; let diceprize = ''; if (dicetotal >= 2 && dicetotal <= 13) { dicewinner = true; diceprize = dicePrizes[dicetotal-2]; } else { dicewinner = false; diceprize = 'A Thank You!'; } let dicerollmsg = 'Roll #' + diceRollCounter + '...'; if (firstdie == 7) { dicerollmsg += '\n' + diceGifPfx + diceColorShortcut + '6 ' + diceGifPfx + diceColorShortcut + '1 ' + diceGifPfx + diceColorShortcut + seconddie; } else { dicerollmsg += '\n' + diceGifPfx + diceColorShortcut + firstdie + ' ' + diceGifPfx + diceColorShortcut + seconddie; } dicerollmsg += '\n' + rolledby + ' rolled a ' + dicetotal + '!'; if (dicetotal == 13) { dicerollmsg += ' \nPrize: :siren1 ' + diceprize + ' :siren1'; cb.sendNotice(dicerollmsg, '', diceRollBgSpecial, diceRollTextColor, 'bold'); } else { dicerollmsg += ' \nPrize: ' + diceprize; cb.sendNotice(dicerollmsg, '', diceRollBgColor, diceRollTextColor, 'bold'); } diceWinners.push('Roll #' + diceRollCounter + ' (' + dicetotal + '): ' + rolledby + ' - ' + diceprize); tipMenuRequests.name.push(rolledby); tipMenuRequests.desc.push('"' + diceprize + '" from rolling the dice.'); tipMenuRequests.amt.push(diceRollPrice); let currenttimedr = new Date(); tipMenuRequestTime.push(currenttimedr.getTime()); } function diceSetPrizes() { for (let dicesetidx = 2; dicesetidx <= 13; dicesetidx++) { if (dicesetidx == 13) { dicePrizes.push(cb.settings['dicePrize_' + dicesetidx] + ' (RARE)'); } else { dicePrizes.push(cb.settings['dicePrize_' + dicesetidx]); } } } function diceShowPrizes(diceprizessendto) { let diceprizelist = '\u22A1 \u22A1 \u22A1 \u22A1 DICE GAME PRIZES \u22A1 \u22A1 \u22A1 \u22A1'; if (dicePrizes.length > 0) { for (let diceprzidx = 2; diceprzidx <= 13; diceprzidx++) { diceprizelist += '\nRoll of ' + diceprzidx + ' - ' + dicePrizes[diceprzidx-2]; } } else { diceprizelist = '\nThere are no prizes in the list.'; } cb.sendNotice(diceprizelist, diceprizessendto, diceNoticeBgColor, diceRollTextColor, boldTextLiteral); } function diceShowRolls(dicerollssendto) { let dicerollsmsg = '\u22A1 \u22A1 \u22A1 \u22A1 LAST 20 DICE ROLLS \u22A1 \u22A1 \u22A1 \u22A1'; if (diceWinners.length == 0) { dicerollsmsg += '\nNo dice rolls completed yet.'; } else { let dicewinnersarr = diceWinners.slice(-20); for (let dicewinidx = 0; dicewinidx < dicewinnersarr.length; dicewinidx++) { dicerollsmsg += '\n' + dicewinnersarr[dicewinidx]; } } cb.sendNotice(dicerollsmsg, dicerollssendto, diceNoticeBgColor, diceRollTextColor, boldTextLiteral); } // *********************************** Tip Response Functions ************************************** function setTipResponseToggle(tiprspmode,tiprspsndto,tiprspbycmd) { if (tiprspmode == 'tipper' || tiprspmode == 'all' ) { if (tiprspmode == 'tipper' && tipResponseFlag == 1) { cb.sendNotice('The Tip Response is already set to "send to tipper".', tiprspsndto, appNoticeColor); } else if (tiprspmode == 'all' && tipResponseFlag == 2) { cb.sendNotice('The Tip Response is already set to "send to all".', tiprspsndto, 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.', tiprspsndto, 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.', tiprspsndto, 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.', tiprspsndto, 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.', tiprspsndto, appNoticeColor); } else { if (tiprspmode == 'tipper') { tipResponseFlag = 1; } else { tipResponseFlag = 2; } if (tiprspbycmd) { cb.sendNotice('You have enabled the Tip Response. Users will now see a response message when they tip above each threshold.', tiprspsndto, appNoticeColor); } } } } else if (tiprspmode == 'off') { if (tipResponseFlag == 0) { cb.sendNotice('The Tip Response is already disabled.', tiprspsndto, appNoticeColor); } else { tipResponseFlag = 0; cb.sendNotice('You have disabled the Tip Response.', tiprspsndto, appNoticeColor); } } } function setTipResponseColors(strespcby,stupflag) { tipRespTextColor = setTextColor('Dark Red','Tip Responses',strespcby,stupflag); tipRespBgColor = setBgColor('White/No Color','Tip Responses',strespcby,stupflag); } // *********************************** Ticket Show Pre-sale Functions ************************************** function setPresalesToggle(setpresoption,setpresby) { let setpresalesendto = setpresby; if (setpresby == 'init') { setpresalesendto = BC; } if (setpresoption == 'on') { if (presalesToggle) { cb.sendNotice('The Pre-Sales Ticket feature is already enabled.',setpresalesendto,appNoticeColor); } else { priceChecker('add','Pre-sale Ticket Price', presalePrice,setpresby); presalesToggle = true; cb.sendNotice(setpresalesendto + ' 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).',BC,appNoticeColor); presaleSkipMin = false; presaleSkipSec = false; presaleSkipNotice = false; setPresaleMode('init',setpresalesendto); countPresaleSold = 0; presaleIncrements = 0; stopIncrement = false; cb.setTimeout(presaleNoticeTimer,presaleNoticeInt); } } else if (setpresoption == 'off') { if (!presalesToggle) { cb.sendNotice('The Pre-Sales Ticket feature is already disabled.',setpresalesendto,appNoticeColor); } else { presalesToggle = false; stopPresaleTimer(setpresalesendto); 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.',setpresalesendto,appNoticeColor); cb.sendNotice(setpresalesendto + ' has disabled the Ticket Show Pre-sales Feature. You can no longer buy Pre-sale tickets.', '', presalesBgColor, presalesTxtColor, 'bold'); } } else if (setpresoption) { cb.sendNotice(setpresoption + ' is not a valid option for /usepresale.\nType "/fbhelp presale" to see how to use pre-sales related commands.',setpresalesendto,appNoticeColor); } else if (!setpresoption) { cb.sendNotice('You did not enter a valid option for /usepresale.\nType "/fbhelp presale" to see how to use pre-sales related commands.',setpresalesendto,appNoticeColor); } } function setPresalesNoticeColors(spresnotcby,stupflag) { presalesTxtColor = setTextColor('Dark Purple','Pre-sales Notice',spresnotcby,stupflag); presalesBgColor = setBgColor('Light Blue','Pre-sales Notice',spresnotcby,stupflag); } function setPresaleMode(setprsmode,sendto) { let newpresalemode = setprsmode; if (setprsmode == '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; } if (presaleMode == 'timer' && newpresalemode != 'timer') { stopPresaleTimer(sendto); } if (newpresalemode == 'manual') { presaleMode = 'manual'; 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 (presaleIncAmt >= 1 && cb.settings.presaleTimedIncrement >= 1) { presaleMode = 'timer'; 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'; 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 (presaleIncAmt >= 1 && cb.settings.presaleCountIncrement >= 1) { presaleMode = 'count'; presaleTicketsLeft = 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'; 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'; 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 && !ticketShowToggle) { 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 ' + presaleTicketsLeft + ' more ticket' + (presaleTicketsLeft > 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() { let presaletimerem = presaleTimeCal(); let presalems = presaletimerem % 1000; let presalesec = ((presaletimerem - presalems) % 60000); presalesec = presalesec / 1000; return presalesec; } 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,BC); 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 + '.',BC, 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 + '.',BC, 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, presaletimetoaddu) { presaleStopTime = new Date(presaleStopTime.getTime() + presaletimetoadd * 60000); cb.sendNotice(presaletimetoaddu + ' has added ' + presaletimetoadd + ' minute' + (presaletimetoadd === 1 || presaletimetoadd === -1 ? '' : 's') + ' to the timer.',BC,'','', boldTextLiteral); cb.sendNotice(presaletimetoadd + ' minute' + (presaletimetoadd === 1 || presaletimetoadd === -1 ? '' : 's') + ' have been added to the timer. Now ' + presaleTimeLeft(),'',appWarningColor,'', boldTextLiteral); presaleMinsRemain = presaleMinsRemain + presaletimetoadd; if (presaleMinsRemain < 1) { presaleSkipMin = true; let presaletimerem = presaleTimeCal(); let presalems = presaletimerem % 1000; let presalesec = ((presaletimerem - presalems) % 60000) / 1000; presaleSecsRemain = presalesec; presaleTimerSec(); } return; } function presaleTimeCal() { presaleStartTime = new Date(); return presaleStopTime - presaleStartTime.getTime(); } function stopPresaleTimer(stoppstuser) { presaleStopTime = new Date(); if (presaleMinsRemain > 0 || presaleSecsRemain > 0) { presaleMinsRemain = 0; presaleSecsRemain = 0; presaleSkipMin = true; presaleSkipSec = true; if (stoppstuser) { cb.sendNotice(stoppstuser + ' has stopped the ticket show pre-sales timer.','',appWarningColor,'', boldTextLiteral); } } } function presaleTimeLeft() { let presaletimerem = presaleTimeCal(); let presalems = presaletimerem % 1000; let presalesec = ((presaletimerem - presalems) % 60000); let presalemin = ((presaletimerem - presalesec - presalems) % 3600000); let presalehr = (presaletimerem - presalemin - presalesec - presalems); presalesec = presalesec / 1000; presalemin = presalemin / 60000; presalehr = presalehr / 3600000; if (presalehr > 0) { return presalehr + ' hour' + (presalehr > 1 ? 's' : '') + ' and ' + presalemin + ' minute' + (presalemin > 1 ? 's' : '') + ' remaining to vote.'; } else if (presalemin > 0 && presalesec === 0) { return presalemin + ' minute' + (presalemin > 1 ? 's' : '') + ' remaining on the timer.'; } else if (presalemin > 0) { return presalemin + ' minute' + (presalemin > 1 ? 's' : '') + ' and ' + presalesec + ' second' + (presalesec > 1 ? 's' : '') + ' remaining on the timer.'; } else { return presalesec + ' second' + (presalesec > 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() { presaleTicketsLeft = (presaleCountAmt - countPresaleSold) if (presaleTicketsLeft > 0) { cb.sendNotice('There ' + (presaleTicketsLeft > 1 ? 'are ' : 'is ') + (presaleTicketsLeft) + ' pre-sale ticket' + (presaleTicketsLeft > 1 ? 's' : '') + ' remaining at a price of ' + presalePrice + ' tokens!','', presalesBgColor, presalesTxtColor, boldTextLiteral); } else { if (presalePrice + presaleIncAmt > ticketPrice) { stopIncrement = true; cb.sendNotice('Pre-sale tickets will remain at ' + presalePrice + ' tokens until start of show','', presalesBgColor, presalesTxtColor, boldTextLiteral); cb.sendNotice('No additional price changes made, next increment would have exceeded planned ticket show price of ' + ticketPrice + '.',BC, 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, boldTextLiteral); cb.sendNotice('No additional price changes made, next increment would have exceeded max increments of ' + cb.settings.presaleMaxIncrements + '.',BC, appNoticeColor); } else { cb.sendNotice('All pre-sale tickets at a price of ' + presalePrice + ' tokens have been sold!','', presalesBgColor, presalesTxtColor, boldTextLiteral); presaleIncrements++; nextPresalePrice = presalePrice + presaleIncAmt; presalePriceChange(nextPresalePrice,BC); countPresaleSold = 0; presaleTicketsLeft = presaleCountAmt; } } } function addPresaleList(addprsby) { if (presaleArray.length > 1) { cb.sendNotice('Adding multiple users to the Fembot ticket show list.', addprsby, appNoticeColor); for (let addprsidx = 0; addprsidx < presaleArray.length; addprsidx++) { if (presaleArray[addprsidx] != '') { if (!cb.limitCam_userHasAccess(presaleArray[addprsidx])) { addRmvTicket('add',presaleArray[addprsidx],'',0,presaleArray[addprsidx]); cb.sendNotice('Added ' + presaleArray[addprsidx] + ' to the ticket show list.', addprsby); cb.sendNotice(addprsby + ' has added you to the ticket show list since you purchased a pre-sale ticket.', presaleArray[addprsidx], appNoticeColor); } else { cb.sendNotice(presaleArray[addprsidx] + ' is already on the ticket show list. Skipping.', addprsby); } } } cb.sendNotice('All users from the pre-sale list were added to the Fembot Ticket Show and notified.', addprsby, appNoticeColor); cb.sendNotice(addprsby + ' has added multiple users from the Pre-sale list to the Fembot Ticket Show list.\nUsers added: ' + cbjs.arrayJoin(presaleArray, ', '), BC, 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.', addprsby, 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.', addprsby, appNoticeColor); } } } // *********************************** Fembot Hidden Ticket Show Functions ************************************** function setTicketShowToggle(settktopt,settktby,settktprice) { let settktsendto = settktby; if (settktby == 'init') { settktsendto = BC; } if (settktopt == 'on') { if (ticketShowToggle) { cb.sendNotice('The Fembot Hidden Ticket Show feature is already enabled.',settktsendto,appNoticeColor); } else { initTicketShow(settktprice,settktby); cb.sendNotice(borderTicketTop + '\n* ' + settktsendto + ' has started ticket sales for the Fembot Hidden Ticket Show.\n* Tickets are ' + ticketPrice + ' tokens.' + borderTicketBottom, '', ticketBgColor, ticketTxtColor, 'bold'); if (cb.settings.hiddenShowAllowGift === 'Yes') { cb.sendNotice(borderTicketTop + '\n* ' + bcText + ' has enabled the the gifting of tickets. \n* You can buy extra tickets and gift them using the command /giftticket' + borderTicketBottom, '', ticketBgColor, ticketTxtColor, 'bold'); } } } else if (settktopt == 'off') { if (!ticketShowToggle) { cb.sendNotice('The Fembot Hidden Ticket Show feature is already disabled.',settktsendto,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.',settktsendto,appNoticeColor); } else { ticketShowToggle = false; 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.',settktsendto,appNoticeColor); } } } function initTicketShow(inittktprice,inittktby) { let inittktsendto = inittktby; if (inittktby == 'init') { inittktsendto = BC; } ticketShowToggle = true; showStage = 'ticketsales'; setTicketPrice(inittktprice,inittktby,'no'); ticketSkipMin = false; ticketSkipSec = false; setTicketMode('init',inittktsendto); ticketSkipNotice = false; ticketShowEnded = false; ticketSalesEnded = false; countTicketsSold = 0; loadFreeTickets(); if (ticketShowType == 'Fembot Ticket Show') { if (presaleArray.length > 0) { addPresaleList(inittktsendto); } else { cb.sendNotice('No pre-sale list ticket holders to add.', inittktsendto, appNoticeColor); } } if (presalesToggle) { setPresalesToggle('off', inittktsendto); } cb.setTimeout(ticketNoticeTimer,ticketNoticeInt); } function ticketShowNoticeColors(tsncolby,stupflag) { ticketTxtColor = setTextColor('Dark Red','Ticket Show Notice',tsncolby,stupflag); ticketBgColor= setBgColor('Cream','Ticket Show Notice',tsncolby,stupflag); } function ticketShowColors(tscolby,stupflag) { ticketNoticesTxtColor = setTextColor('Black','Ticket Show',tscolby,stupflag); ticketNoticesBgColor = setBgColor('Light Blue','Ticket Show',tscolby,stupflag); ticketTxtColorFan = setTextColor('Black','Ticket Show Fan',tscolby,stupflag); ticketBgColorFan = setBgColor('Light Green','Ticket Show Fan',tscolby,stupflag); ticketTxtColorVIP = setTextColor('Black','Ticket Show VIP',tscolby,stupflag); ticketBgColorVIP = setBgColor('Light Purple','Ticket Show VIP',tscolby,stupflag); ticketTxtColorMod = setTextColor('Black','Ticket Show Mod',tscolby,stupflag); ticketBgColorMod = setBgColor('Light Red','Ticket Show Mod',tscolby,stupflag); } function setTicketShowOtToggle(settktotopt, settktotby) { if (settktotopt == 'on') { if (ticketShowOtToggle) { cb.sendNotice('The Outstanding Ticket feature is already enabled.',settktotby,appNoticeColor); } else { ticketShowOtToggle = true; cb.sendNotice(borderTicketTop + '\n* ' + settktotby + ' 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' + borderTicketBottom, '', ticketBgColor, ticketTxtColor, boldTextLiteral); 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.',BC,appNoticeColor); } } else if (settktotopt == 'off') { if (!ticketShowOtToggle) { cb.sendNotice('The Outstanding Ticket feature is already disabled.',settktotby,appNoticeColor); } else { ticketShowOtToggle = false; 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.',settktotby,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(settktstartmode,settktsendto) { let newticketmode = ''; let newticketauto = ''; if (settktstartmode == '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 (settktstartmode) { newticketmode = settktstartmode; } else { newticketmode = ticketStartMode; } newticketauto = ticketModeAuto; } if (ticketStartMode == 'timer' && newticketmode != 'timer') { if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { stopTicketTimer(settktsendto); } } if (newticketmode == 'manual') { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; if (settktstartmode != 'init') { cb.sendNotice('Ticket Show start mode is set to "Manual", the show will be started via command when ready.','', ticketBgColor, ticketTxtColor, boldTextLiteral); } } else if (newticketmode == 'timer') { if (cb.settings.hiddenShowStartTimer >= 1) { ticketStartMode = 'timer'; 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, boldTextLiteral); } 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, boldTextLiteral); } } else { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; 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.', settktsendto, appNoticeColor); } } else if (newticketmode == 'tokengoal') { if (ticketShowGoalTokens >= 1) { ticketStartMode = 'tokengoal'; 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, boldTextLiteral); } 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, boldTextLiteral); } } else { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; 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.', settktsendto, appNoticeColor); } } else if (newticketmode == 'ticketgoal') { if (ticketShowGoalTickets >= 1) { ticketStartMode = 'ticketgoal'; 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, boldTextLiteral); } 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, boldTextLiteral); } } else { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; 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.', settktsendto, appNoticeColor); } } } function setTicketAuto(automode) { if (automode === 'bc') { ticketModeAuto = 'bc'; } else if (automode === 'auto') { ticketModeAuto = 'auto'; } } function ticketNoticeTimer() { if (ticketShowToggle) { let ticketnotice = borderTicketTop; if (showStage == 'ticketsales') { ticketnotice += '\n\u23E9 Ticket Price: ' + ticketPrice + ' tokens'; ticketnotice += '\n\u23E9 ' + wordWrap('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: Show has started, still selling tickets!'; ticketnotice += '\n\u23E9 Description: ' + cb.settings.hiddenShowNotice; } else if (showStage == 'showwarn') { ticketnotice += '\n\u23E9 Ticket Price: ' + ticketPrice + ' tokens'; ticketnotice += '\n\u23E9 Ticket Sales: Show will finish soon, but still selling tickets'; 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' && showStage != 'showfinale') { ticketnotice += '\n\u23E9 Ticket Holders: ' + countTicketsSold; if (ticketPriceFC > 1 && cb.settings.hiddenShowFreeFC != 'Yes') { ticketnotice += '\n\u23E9 Chaturbate Fanclub Ticket Price: ' + ticketPriceFC + ' token' + (ticketPriceFC > 1 ? 's.' : '.'); } else if (cb.settings.hiddenShowFreeFC == 'Yes') { ticketnotice += '\n\u23E9 Chaturbate Fanclub members get a free ticket!'; } if (extFanListArray.length > 0) { if (ticketPriceEFC > 1 && cb.settings.hiddenShowFreeEFC != 'Yes') { ticketnotice += '\n\u23E9 ' + EFCname + ' Ticket Price: ' + ticketPriceEFC + ' token' + (ticketPriceEFC > 1 ? 's.' : '.'); } else if (cb.settings.hiddenShowFreeEFC == 'Yes') { ticketnotice += '\n\u23E9 ' + EFCname + ' members get a free ticket!'; } } if (extFanList2Array.length > 0) { if (ticketPriceEFC2 > 1 && cb.settings.hiddenShowFreeEFC2 != 'Yes') { ticketnotice += '\n\u23E9 ' + EFCname2 + ' Ticket Price: ' + ticketPriceEFC2 + ' token' + (ticketPriceEFC2 > 1 ? 's.' : '.'); } else if (cb.settings.hiddenShowFreeEFC2 == 'Yes') { ticketnotice += '\n\u23E9 ' + EFCname2 + ' members get a free ticket!'; } } if (VIPListArray.length > 0) { if (ticketPriceVIP > 1 && cb.settings.hiddenShowFreeVIP != 'Yes') { ticketnotice += '\n\u23E9 ' + VIPname + ' Ticket Price: ' + ticketPriceVIP + ' token' + (ticketPriceVIP > 1 ? 's.' : '.'); } else if (cb.settings.hiddenShowFreeVIP == 'Yes') { ticketnotice += '\n\u23E9 ' + VIPname + ' members get a free ticket!'; } } } ticketnotice += borderTicketBottom; cb.sendNotice(ticketnotice, '', ticketNoticesBgColor, ticketNoticesTxtColor, boldTextLiteral); if (!ticketSkipNotice) { cb.setTimeout(ticketNoticeTimer,ticketNoticeInt); } else { ticketSkipNotice = false; } } } function ticketAutoTimer(addtime) { if (ticketModeAuto == 'auto') { cb.sendNotice(borderTicketTop + '\nAn automatic timer was started, ticket show price will be ' + ticketPrice + ' tokens.' + borderTicketBottom, '', ticketBgColor, ticketTxtColor, boldTextLiteral); } else if (ticketModeAuto == 'bc') { cb.sendNotice(borderTicketTop + '\nA timer was started to provide an countdown to approximate showtime. \n ' + bcText + ' will start the show after the timer runs out.' + borderTicketBottom, '', ticketBgColor, ticketTxtColor, boldTextLiteral); } 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 && (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() { let ticketchkmintime = ticketTimeCal(); let ticketms = ticketchkmintime % 1000; let ticketsec = ((ticketchkmintime - ticketms) % 60000); ticketsec = ticketsec / 1000; return ticketsec; } function ticketTimerSec() { if (!ticketSkipSec && ticketStartMode === 'timer' && ticketShowToggle) { 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, boldTextLiteral); startTicketShow(BC); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Time is up! ' + bcText + ' will be starting the show! \u23f0 \u23f0 \u23f0', '', ticketBgColor, ticketTxtColor, boldTextLiteral); } } 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, tickettimetoaddu) { ticketStopTime = new Date(ticketStopTime.getTime() + tickettimetoadd * 60000); cb.sendNotice(tickettimetoaddu + ' has added ' + tickettimetoadd + ' minute' + (tickettimetoadd === 1 || tickettimetoadd === -1 ? '' : 's') + ' to the timer.', BC, '', '', boldTextLiteral); cb.sendNotice(tickettimetoadd + ' minute' + (tickettimetoadd === 1 || tickettimetoadd === -1 ? '' : 's') + ' have been added to the timer. Now ' + ticketTimeLeft(), '', appWarningColor, '', boldTextLiteral); ticketMinsRemain = ticketMinsRemain + tickettimetoadd; if (ticketMinsRemain < 1) { ticketSkipMin = true; let ticketaddtimeleft = ticketTimeCal(); let ticketaddtimems = ticketaddtimeleft % 1000; ticketSecsRemain = ((ticketaddtimeleft - ticketaddtimems) % 60000) / 1000; 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, '', boldTextLiteral); } } function ticketTimeLeft() { let tickettimeleftraw = ticketTimeCal(); let tickettimeleftms = tickettimeleftraw % 1000; let tickettimeleftsec = ((tickettimeleftraw - tickettimeleftms) % 60000); let tickettimeleftmin = ((tickettimeleftraw - tickettimeleftsec - tickettimeleftms) % 3600000); let tickettimelefthr = (tickettimeleftraw - tickettimeleftmin - tickettimeleftsec - tickettimeleftms); tickettimeleftsec = tickettimeleftsec / 1000; tickettimeleftmin = tickettimeleftmin / 60000; tickettimelefthr = tickettimelefthr / 3600000; if (tickettimelefthr > 0) { return tickettimelefthr + ' hour' + (tickettimelefthr > 1 ? 's' : '') + ' and ' + tickettimeleftmin + ' minute' + (tickettimeleftmin > 1 ? 's' : '') + ' left on the ticket show timer'; } else if (tickettimeleftmin > 0 && tickettimeleftsec === 0) { return tickettimeleftmin + ' minute' + (tickettimeleftmin > 1 ? 's' : '') + ' left on the ticket show timer'; } else if (tickettimeleftmin > 0) { return tickettimeleftmin + ' minute' + (tickettimeleftmin > 1 ? 's' : '') + ' and ' + tickettimeleftsec + ' second' + (tickettimeleftsec > 1 ? 's' : '') + ' left on the ticket show timer'; } else { return tickettimeleftsec + ' second' + (tickettimeleftsec > 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.', BC, ticketBgColorFan, ticketTxtColorFan, 'bold'); cb.sendNotice('Fan Club member ' + anontipper + ' has been added to the ticket show list.', BC, 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.', BC, ticketBgColorVIP, ticketTxtColorVIP, 'bold'); cb.sendNotice('VIP List member ' + anontipper + ' has been added to the ticket show list.', BC, 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.', BC, ticketBgColorMod, ticketTxtColorMod, 'bold'); cb.sendNotice('Moderator ' + anontipper + ' has been added to the ticket show list.', BC, 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.', BC, ticketBgColor, ticketTxtColor, 'bold'); cb.sendNotice(anontipper + ' has been added to the ticket show list.', BC, 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.', BC, ticketBgColorFan, ticketTxtColorFan, 'bold'); cb.sendNotice('Fan Club member ' + anontipper + ' has bought a ticket to the show.', BC, 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.', BC, ticketBgColorFan, ticketTxtColorFan, 'bold'); cb.sendNotice('VIP List member ' + anontipper + ' has bought a ticket to the show.', BC, 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.', BC, ticketBgColorFan, ticketTxtColorFan, 'bold'); cb.sendNotice('Moderator ' + anontipper + ' has bought a ticket to the show.', BC, 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.', BC, ticketBgColorFan, ticketTxtColorFan, 'bold'); cb.sendNotice(anontipper + ' has bought a ticket to the show.', BC, ticketBgColorFan, ticketTxtColorFan, 'bold', 'red'); } } countTicketsSold ++; if (tipamount >= (2*ticketPrice)) { addRmvTicket('addextra', addtktuser, 'common', (tipamount - ticketPrice), addtktuser); } break; } case 'addextra': { let numtickets = Math.floor(parseInt(tipamount / ticketPrice)); if (numtickets > 0) { if (!cbjs.arrayContains(ticketShowExtraTickets.name,addtktuser)) { ticketShowExtraTickets.name.push(addtktuser); ticketShowExtraTickets.count.push(numtickets); } else { let exttktindex = ticketShowExtraTickets.name.indexOf(addtktuser); ticketShowExtraTickets.count[exttktindex] = ticketShowExtraTickets.count[exttktindex] + 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 { let cumtktindex = ticketCumulative.name.indexOf(cumuser); if (ticketCumulative.amount[cumtktindex] + cumamount >= cumprice) { if (saletype == 'ticket') { addRmvTicket('addtip',cumuser,usertype,cumamount,anontipper); } else if (saletype == 'presale') { addRmvPresale('addtip',cumuser,0,anontipper); } ticketCumulative.amount[cumtktindex] = 0; } else { ticketCumulative.amount[cumtktindex] += cumamount; } } } } function giftTicket(giftfromuser,gifttouser) { cb.limitCam_addUsers([gifttouser]); if (!cbjs.arrayContains(ticketShowViewerList,gifttouser)) { ticketShowViewerList.push(gifttouser); } cb.sendNotice('Welcome ' + gifttouser + ', ' + giftfromuser + ' has gifted you a ticket to the show!', '', ticketBgColor, ticketTxtColor, 'bold'); countTicketsSold ++; } function giveAwayTicket(givefromuser,givetouser) { cb.limitCam_addUsers([givetouser]); cb.limitCam_removeUsers([givefromuser]); if (!cbjs.arrayContains(ticketShowViewerList,givetouser)) { ticketShowViewerList.push(givetouser); } if (cbjs.arrayContains(ticketShowViewerList,givefromuser)) { ticketShowViewerList.pop(givefromuser); } cb.sendNotice('Welcome ' + givetouser + ', ' + givefromuser + ' has gifted you a ticket to the show!', '', ticketBgColor, ticketTxtColor, 'bold'); } function addRmvOutstandingTicket(arotmode,arotuser) { switch (arotmode) { case 'add': { outstandingTicketArray.push(arotuser); populateOtChangesArray(arotuser,'add'); break; } case 'rmv': { cbjs.arrayRemove(outstandingTicketArray,arotuser); populateOtChangesArray(arotuser,'rmv'); break; } } } function populateOtChangesArray(popotuser,popottype) { if (cbjs.arrayContains(otChangesArray.name,popotuser)) { let popotindex = otChangesArray.name.indexOf(popotuser); if (otChangesArray.type[popotindex] != popottype) { otChangesArray.name.push(popotuser); otChangesArray.type.push(popottype); } else { return; } } else { otChangesArray.name.push(popotuser); otChangesArray.type.push(popottype); } } function ticketShowGoalProgress(tickettipamount) { ticketShowTotalTips = ticketShowTotalTips + tickettipamount; ticketShowTotalTickets++; if (ticketStartMode == 'tokengoal' && ticketShowTotalTips >= ticketShowGoalTokens) { cb.sendNotice(borderTicketTop + '\n :siren1 *** The ticket show Tip goal has been met!! *** :siren1 \n*** Starting a 2 minute timer for automatic start of show! ***' + borderTicketBottom,"", ticketBgColor, ticketTxtColor, "bold"); ticketStartMode = 'timer'; ticketAutoTimer(2); } else if (ticketStartMode == 'ticketgoal' && ticketShowTotalTickets >= ticketShowGoalTickets) { cb.sendNotice(borderTicketTop + '\n :siren1 ** The ticket show Ticket goal has been met!! ** :siren1 \n*** Starting a 2 minute timer for automatic start of show! ***' + borderTicketBottom,"", ticketBgColor, ticketTxtColor, "bold"); ticketStartMode = 'timer'; ticketAutoTimer(2); } } function startTicketShow(startedby) { if (tokenPollToggle) { 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 { let starttimetoadd = parseInt(cb.settings.startPollMinAfterShow) if (starttimetoadd <= 0) { starttimetoadd = 10; cb.sendNotice('No setting defined for token poll end timer, defaulting to 10 min.', startedby, appNoticeColor); } pollSwitchToTimer(starttimetoadd); } } else { cb.sendNotice('Note: Poll Timer not started with /startshow per configuration.', startedby, appNoticeColor); } } cb.sendNotice(borderTicketTop + '\n :siren1 :alert1 :siren1 ' + startedby + ' has started the hidden ticket show! :siren1 :alert1 :siren1 ' + borderTicketBottom, '', 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) { cb.sendNotice(borderTicketTop + '\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.' + borderTicketBottom, '', 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(borderTicketTop + '\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! ' + borderTicketBottom, '', ticketBgColor, ticketTxtColor, 'bold'); } else { cb.sendNotice(borderTicketTop + '\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. ' + borderTicketBottom, '', ticketBgColor, ticketTxtColor, 'bold'); } } function stopTicketSales(stoppedby) { cb.sendNotice(borderTicketTop + '\n :siren1 :alert1 :siren1 \u25B7 \u25B7 ' + stoppedby + ' has ended the ticket show sales. \u25C1 \u25C1 :siren1 :alert1 :siren1 ' + borderTicketBottom, '', ticketBgColor, ticketTxtColor, 'bold'); showStage = 'showfinale'; changeTicketShowSubject(); ticketSalesEnded = true; } function stopTicketShow(stoppedby) { cb.sendNotice(borderTicketTop + '\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.' + borderTicketBottom, '', 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 displayShowTime(gettimeuser) { cb.sendNotice('*** Hidden Cam show in progress for ' + ((Date.now() - hiddenTime)/60000).toFixed(2) + ' minutes. ***', gettimeuser, ticketBgColor,ticketTxtColor,'bold'); } function returnShowTime() { return 'Elapsed show time: ' + ((Date.now() - hiddenTime)/60000).toFixed(2) + ' minutes.'; } function changeTicketShowSubject() { let chgtktsubject = ''; if (showStage == 'ticketsales') { chgtktsubject = 'TICKET SHOW SALES [' + ticketPrice + ' tokens]: ' + ticketSubjectText; } else if (showStage == 'ticketshow') { chgtktsubject = 'TICKET SHOW -- IN PROGRESS [' + ticketPrice + ' tokens]: ' + ticketSubjectText; } else if (showStage == 'showwarn') { chgtktsubject = 'TICKET SHOW -- ENDING SOON [' + ticketPrice + ' tokens]: ' + ticketSubjectText; } else if (showStage == 'showfinale') { chgtktsubject = 'TICKET SHOW -- SALES ENDED: ' + ticketSubjectText; } else if (showStage == 'aftershow') { chgtktsubject = 'TICKET SHOW HAS ENDED: ' + ticketSubjectText; } else { chgtktsubject = 'TICKET SHOW'; } cb.changeRoomSubject(chgtktsubject); } // *********************************** All Time Tipper Display Function ************************************** function setAllTimeToggle(setattoption,setattby) { let setatsendto = setattby; if (setattby == 'init') { setatsendto = 'BC'; } if (setattoption == 'on') { if (allTimeNoticeToggle) { cb.sendNotice('The All-Time Top 10 Tipper List Notice is already enabled.', setatsendto, appNoticeColor); } else { allTimeNoticeToggle = true; cb.setTimeout(allTimeNoticeDisplay,allTimeInt); if (setattby == 'init') { botLoadErrors.push('You have enabled the All-Time Top 10 Tipper List Notice. If tracking all time tippers, please remember to use the "/alltime" command before you end the bot to get the current list at the end of the show, save the list, and paste it into the start page all time list setting "2R" next time you start the bot.'); } else { cb.sendNotice('You have enabled the All-Time Top 10 Tipper List Notice. If tracking all time tippers, please remember to use the "/alltime" command before you end the bot to get the current list at the end of the show, save the list, and paste it into the start page all time list setting "2R" next time you start the bot.', setatsendto, appNoticeColor); } } } else if (setattoption == 'off') { if (!allTimeNoticeToggle) { cb.sendNotice('The All-Time Top 10 Tipper List Notice is already disabled.', setatsendto, appNoticeColor); } else { allTimeNoticeToggle = false; cb.sendNotice('You have disabled the All-Time Top 10 Tipper List Notice.', setatsendto, appNoticeColor); } } } function setAllTimeListColors(setatlby,stupflag) { allTimeTextColor = setTextColor('Dark Blue','All-time List',setatlby,stupflag); allTimeBgColor = setBgColor('Light Yellow','All-time List',setatlby,stupflag); } function allTimeNoticeDisplay() { if (allTimeNoticeToggle) { if (minMessagesForNotice > 0 && msgCounterAllTime < minMessagesForNotice) { cb.setTimeout(allTimeNoticeDisplay, 30000); } else { msgCounterAllTime = 0; buildAllTimeArray(); displayAllTimeLeaders(''); cb.setTimeout(allTimeNoticeDisplay,allTimeInt); } } } function buildAllTimeArray() { allTimeArray.name.length = 0; allTimeArray.totaltips.length = 0; allTimeArray.name = allTimeArrayLoad.name.slice(); allTimeArray.totaltips = allTimeArrayLoad.totaltips.slice(); for (let bataidx = 0; bataidx < tipCountArray.name.length; bataidx++) { let alltimeusertoadd = tipCountArray.name[bataidx]; let alltimeusertoaddamt = tipCountArray.amount[bataidx]; if (alltimeusertoaddamt >= allTimeMinThreshold) { let useralltimetotal = 0; if (cbjs.arrayContains(allTimeArray.name,alltimeusertoadd)) { let batidx = allTimeArray.name.indexOf(alltimeusertoadd); useralltimetotal = allTimeArray.totaltips[batidx] + alltimeusertoaddamt; allTimeArray.totaltips[batidx] = allTimeArray.totaltips[batidx] + alltimeusertoaddamt; } else { allTimeArray.totaltips.push(alltimeusertoaddamt); allTimeArray.name.push(alltimeusertoadd); useralltimetotal = alltimeusertoaddamt; } if (cb.settings.joinVIPCumulativeAllTime > 0) { if (useralltimetotal >= cb.settings.joinVIPCumulativeAllTime && !cbjs.arrayContains(VIPListArray,alltimeusertoadd)) { addRmvVIP(alltimeusertoadd,'a'); cb.sendNotice(alltimeusertoadd + ' has been added to the VIP list based on all-time tipping surpassing the configured amount (' + cb.settings.joinVIPCumulativeAllTime + ').', BC, appNoticeColor); let temptextcolor = setTextColor('Dark Blue','VIP List Addition',BC,false); let tempbgcolor = setBgColor('Light Blue','VIP List Addition',BC,false); cb.sendNotice('Welcome ' + alltimeusertoadd + ' to the VIP list!', '', tempbgcolor, temptextcolor, 'bold'); } } } } sortAllTimeTippers(); if (kingTipperFlag == 2 && kingTipperName != allTimeArray.name[0]) { kingTipperName = allTimeArray.name[0]; kingTipperAmount = allTimeArray.totaltips[0]; } } function displayAllTimeLeaders(sendto) { if (allTimeArray.name.length > 0) { let alltimeleadersize = allTimeArray.name.length; if (alltimeleadersize > 10) { alltimeleadersize = 10; } let alltimemsg = borderAllTimeTop; for (let datidx = 0; datidx < alltimeleadersize; datidx++) { if (allTimeArray.name[datidx]) { let positionicon = ''; if (datidx == 0) { positionicon = ':crown-gold'; } else if (datidx == 1) { positionicon = ':crown-silver'; } else if (datidx == 2) { positionicon = ':crown-bronze'; } alltimemsg += '\n' + (datidx+1) + '. ' + positionicon + ' ' + allTimeArray.name[datidx] + ' : ' + allTimeArray.totaltips[datidx] + ' tokens'; } } alltimemsg += borderUniversalBottom; cb.sendNotice(alltimemsg, sendto, allTimeBgColor, allTimeTextColor, boldTextLiteral); } } function displayAllTime(sendto) { let alltimecopymsg = wordWrap('Listing of All-time top tippers (Combines Previous Show List and Current Show users who have tipped at least ' + allTimeMinThreshold + ' tokens). Copy this list starting *after* the arrow icon 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 (setting "2R"):') ; for (let dspatidx = 0; dspatidx < allTimeArray.name.length; dspatidx++) { if (allTimeArray.name[dspatidx] == null) { break; } else { alltimecopymsg += (dspatidx > 0 ? ', ' : '\n\u23E9 ') + allTimeArray.name[dspatidx] + ':' + allTimeArray.totaltips[dspatidx]; } } alltimecopymsg += '\nEnd of List'; cb.sendNotice(alltimecopymsg, sendto, appNoticeColor); } function sortAllTimeTippers() { var swapped, temp1, temp2; do { swapped = false; for (let sortatidx = 0; sortatidx < allTimeArray.totaltips.length ; sortatidx++) { if (allTimeArray.totaltips[sortatidx] < allTimeArray.totaltips[sortatidx + 1]) { temp1 = allTimeArray.totaltips[sortatidx]; temp2 = allTimeArray.name[sortatidx]; allTimeArray.totaltips[sortatidx] = allTimeArray.totaltips[sortatidx + 1]; allTimeArray.totaltips[sortatidx + 1] = temp1; allTimeArray.name[sortatidx] = allTimeArray.name[sortatidx + 1]; allTimeArray.name[sortatidx + 1] = temp2; swapped = true; } } } while (swapped); } // ********************* Private On-demand ************************** function goPrivate(user) { cb.limitCam_addUsers([user]); 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) ***.',BC,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 = 'Dorothy\'s Ultra Fembot'; aboutmessage += '\n \u2705 About the Bot:'; aboutmessage += '\n \u2022 ' + wordWrap('Version 4.6 was released on February 6, 2022 and was written by CB users chelsea2950 and butter_my_toast.'); aboutmessage += '\n \u2022 ' + wordWrap('We like to visit rooms to check on people using the bot so feel free to say hello if you see us!'); aboutmessage += '\n \u2022 ' + wordWrap('Comments, suggestions, requests, and bug reports can be made by either tweeting @thechelsea2950, or by posting comments in the forum at the bottom of the bot description page.'); aboutmessage += '\n \u2022 ' + wordWrap('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 \u2022 ' + wordWrap('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 \u2022 ' + wordWrap('The bot description page includes extensive details on bot features, icon and emoji usage, moderator trust levels, and commands.'); aboutmessage += '\n \u2022 ' + wordWrap('The description page also includes notes on previous releases, please see the Release Notes section at the bottom of the bot description page:'); aboutmessage += '\n https://chaturbate.com/apps/app_details/dorothys-ultra-fembot/ '; aboutmessage += '\n\n \u2705 Highlights of fixes and improvements for version 4.6:'; aboutmessage += '\n \u2022 ' + wordWrap('Fixed issue with Public blocked word messages still showing under "Notification" setting'); cb.sendNotice(aboutmessage, sendtoabout, appWarningColor); } function helpCommon(helpcomsendto) { let helptxtmsg = '\u23E9 Dorothy\'s Fembot = Help Menu'; helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/tipmenu: Display the tip menu at any time in the chat.'); helptxtmsg += '\n \u2022 ' + wordWrap('/posmenu: Display the positions tip menu at any time in the chat.'); helptxtmsg += '\n \u2022 ' + wordWrap('/timeleft: Display the time left on a timed countdown clock.'); helptxtmsg += '\n \u2022 ' + wordWrap('/leaders: Display the tip leaderboard at any time in the chat.'); helptxtmsg += '\n \u2022 ' + wordWrap('/poll: Display the current results of the token poll at any time in the chat.'); helptxtmsg += '\n \u2022 ' + wordWrap('/toymenu: Display the interactive toy tip menu at any time in the chat.'); helptxtmsg += '\n \u2022 ' + wordWrap('/media: Display the broadcaster media list at any time in the chat.'); helptxtmsg += '\n \u2022 ' + wordWrap('/guests: Display the guest info list at any time in the chat.'); helptxtmsg += '\n \u2022 ' + wordWrap('/top10 (or /alltimetop10, or /dsptop10): Display a listing of the top 10 all-time tippers.'); helptxtmsg += '\n \u2022 ' + wordWrap('/prizes: Display the dice game prizes menu at any time in the chat.'); cb.sendNotice(helptxtmsg,helpcomsendto,appNoticeColor); } function helpModBC(helpoption,helpsendto) { let validhelpcmd = false; if (helpoption == null) { helpoption = ''; } switch (helpoption) { case '': { validhelpcmd = true; let helptxtmsg = '\u23E9 Dorothy\'s Ultra Fembot - Help Menu for Broadcasters and Moderators:'; helptxtmsg += '\n' + wordWrap('Below is a summary of all of the Fembot commands by category. For a more detailed submenu and explanation of each command, type "/fbhelp [category]", where [category] is one of the following choices (do not type the brackets or quotes). For example, to see the submenu for messaging related commands, type: /fbhelp messaging'); helptxtmsg += '\n \u2705 "messaging" :: /pm, /reply, /bc, /tm, /tbm'; helptxtmsg += '\n \u2705 ' + wordWrap('"chatcontrol" :: /silencelevel, /graphiclevel, /ninja, /unninja, /ninjalist, /silence, /unsilence, /silencelist, /showninja, /showsilence'); helptxtmsg += '\n \u2705 ' + wordWrap('"tipmenu" :: /tipmenu, /tipmenurequests or /tmr, /tipmenuadd, /tipmenurmv, /usemenu, /swapmenu'); helptxtmsg += '\n \u2705 ' + wordWrap('"positions" :: /posmenu, /posmenurequests, /posmenuadd, /posmenurmv, /useposmenu'); helptxtmsg += '\n \u2705 ' + wordWrap('"timer" :: /startclock, /addtoclock, /timeleft, /stopclock'); helptxtmsg += '\n \u2705 ' + wordWrap('"notices" :: /cn, /cnh, /cnd, /cndh, /usenotifier, /chgmsg1.../chgmsg10, /dspmsg1.../dspmsg10, dspallmsg, /leaders, /useleaderboard, /usetipcount, /tippers, /userules, /userulesenter, /rsp1, /rsp2, /rsp3, /rsp4, /rsp5, /dsprsp'); helptxtmsg += '\n \u2705 ' + wordWrap('"viewernotes" :: /addnote, /notelist, /shownote'); helptxtmsg += '\n \u2705 ' + wordWrap('"tokenpoll" :: /poll, /usepoll, /endpoll, /restartpoll, /resetpoll, /addvote, /polloptadd, /polloptrmv, /pollstarttimer, /polladdtime, /pollstoptimer, /polllead, /makepoll, /odstart, /odoff, /hijackprice, /polltimeleft'); helptxtmsg += '\n \u2705 ' + wordWrap('"textpoll" :: /textpoll, /usetextpoll, /endtextpoll, /restarttextpoll, /resettextpoll, /addtextvote, /textoptadd, /textoptrmv, /textstarttimer, /textaddtime, /textstoptimer, /textlead, /textchgtitle, /texttimeleft'); helptxtmsg += '\n \u2705 "nicelist" :: /addnice, /rmvnice, /nicelist)'; helptxtmsg += '\n \u2705 ' + wordWrap('"viplist" :: /addvip, /rmvvip, /viplist, /setvipicon'); helptxtmsg += '\n \u2705 ' + wordWrap('"fans" :: /addfan, /rmvfan, /fanlist, /addfan2, /rmvfan2, /fanlist2, /setfanicon, /setextfanicon, /setextfan2icon'); helptxtmsg += '\n \u2705 ' + wordWrap('"botmods" :: /addmod, /rmvmod, /modlist, /setmodicon, /setbotmodicon'); helptxtmsg += '\n \u2705 ' + wordWrap('"wordlist" :: /addword, /rmvword, /wordlist, /wordlistprv, /botblock, /qrel, /qsil, /qlist'); helptxtmsg += '\n \u2705 ' + wordWrap('"ticketsupport" :: (/prepticket, /dspbackup, /usebackup, /expbackup, /addlbtop, /addlbamt'); helptxtmsg += '\n \u2705 "ticketshow" :: see full command list in submenu'; helptxtmsg += '\n \u2705 ' + wordWrap('"presales" :: /usepresale, /presalelist, /presaleprice, /presalepricetimer, /presalestarttimer, /presalestoptimer, /presaleaddtime, /exppresale, /addpresale, /rmvpresale, /chgpresalemode, /presaletimeleft'); helptxtmsg += '\n \u2705 ' + wordWrap('"toy" :: /toymenu, /chgtoy, /usetoy, /uselush, /usedomi, /usenora, useferri, /useosci, /usequake, /useedge'); helptxtmsg += '\n \u2705 "media" :: /media, /usemedia)'; helptxtmsg += '\n \u2705 "dice" :: /prizes, /usedice, /chgdiceprice, /dicerolls'; helptxtmsg += '\n \u2705 "alltime" :: /usealltime, top10, /alltime, /useking, /king'; helptxtmsg += '\n \u2705 "private" :: /startprivate, /stopprivate'; helptxtmsg += '\n \u2705 "followers" :: /followers, /fmt, /fc'; helptxtmsg += '\n \u2705 "guests" :: /guests, /useguest)'; helptxtmsg += '\n \u2705 ' + wordWrap('"other" :: /newsubject, /settings, /checkcolor, /prv, /pricechecklist, /nocaps, /nnlist, /setusericon, /setusernn, /setusercolor, /icontips, /chgint, /dspint, /setbrdsep, /clear'); helptxtmsg += '\n \u2705 "about"'; cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'other': { validhelpcmd = true; let helptxtmsg = '\u23E9 Other Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/newsubject [X]: Update the room subject to a new value [X].'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/pricechecklist: Display a listing of all current price check entries.'); helptxtmsg += '\n \u2022 ' + wordWrap('/nocaps [on/off]: Toggle the control for suppressing all CAPS words.'); helptxtmsg += '\n \u2022 ' + wordWrap('/prv: Display the "Private Request Response" message that is configured on the launch page.'); helptxtmsg += '\n \u2022 ' + wordWrap('/nnlist: display a listing of the user specific icons, nick names, and text colors.'); helptxtmsg += '\n \u2022 ' + wordWrap('/icontips: on-demand display of the table of icon tip amounts and associated icons to the general chat.'); helptxtmsg += '\n \u2022 ' + wordWrap('/setusericon [username] [:icon]: Updates the icon/emoji 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 or be a recognized emoji character.'); helptxtmsg += '\n \u2022 ' + wordWrap('/setusernn [username] [nickname]: 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).'); helptxtmsg += '\n \u2022 ' + wordWrap('/setusercolor [username] [#000000]: 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/setbrdsep [emoji]: (mods/bc only) Updates the emoji or text character 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 a characters of text like "-" or "*" (no quotes). It is not recommended to change from emoji to text or text to emoji during the show as the spacing has already been defined by the separator type'); helptxtmsg += '\n \u2022 ' + wordWrap('/fbsetbrdsep [emoji]: (mods/bc only) Same command as /setbrdsep above, but only updates for the Fembot (the /setbrdsep command will update across all Dorothy Apps currently running)'); helptxtmsg += '\n \u2022 ' + wordWrap('/clear: Fills the chat with 25 lines of blank text to clear obnoxious gifs or chat.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/dspint: Display all of the current interval settings so you can see them in one place and make changes to any that are too close together.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'alltime': { validhelpcmd = true; let helptxtmsg = '\u23E9 All-time Highest Tippers:'; helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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).'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'notes': case 'viewernotes': { validhelpcmd = true; let helptxtmsg = '\u23E9 Viewer Notes:'; helptxtmsg += '\n \u2022 ' + wordWrap('/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).'); helptxtmsg += '\n \u2022 ' + wordWrap('/shownote [username]: (bc only) Display the notes that you have recorded for one specific viewer.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'private': { validhelpcmd = true; let helptxtmsg = '\u23E9 On-demand private show:'; helptxtmsg += '\n \u2022 ' + wordWrap('/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!'); helptxtmsg += '\n \u2022 ' + wordWrap('/stopprivate (or /endprivate) : (bc only) End the private hidden cam show and immediately return to public chat.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'followers': { validhelpcmd = true; let helptxtmsg = '\u23E9 Follower Tracking:'; helptxtmsg += '\n \u2022 ' + wordWrap('/followers: (bc and mods) Display the follower stats for the current show on-demand'); helptxtmsg += '\n \u2022 ' + wordWrap('/fc: (all users) Display the total number of followers to the requesting user'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'ticketsupport': { validhelpcmd = true; let helptxtmsg = '\u23E9 Ticket Show Support Commands:'; helptxtmsg += '\n' + wordWrap('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).'); helptxtmsg += '\n \u2022 ' + wordWrap('/prepticket: Prepare for a ticket show by disabling the regular Tip Menu if running, enabling the Positions Menu, and enabling the Token Poll.'); helptxtmsg += '\n \u2022 ' + wordWrap('- This command will also add the VIP List and External Fan Club list to the ticket show if enabled.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/dspbackup (or /backuplist): Display the Backup Ticket list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/expbackup: Export the backup ticket list by creating the /add command to add all backup list members to the ticket app.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'ticket': case 'ticketshow': { validhelpcmd = true; let helptxtmsg = '\u23E9 Fembot Ticket Show Commands:'; helptxtmsg += '\n' + wordWrap('These are used specifically for the Fembot Ticket show, not for the external Ticket Apps (although some commands perform the same type of function)'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/otlist : (all users) Display the list of outstanding ticket holders, can be used by anyone if the Outstanding Ticket feature is enabled.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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. "@" username tagging is allowed'); helptxtmsg += '\n \u2022 ' + wordWrap('/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. "@" username tagging is allowed'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/stopshow: (mods/bc only) End the hidden Ticket Show and return to a public broadcast.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/ticketprice (or /ctprice, or /chgticketprice) [newprice]: (mods/bc only) Update the ticket price to the [newprice].'); helptxtmsg += '\n \u2022 ' + wordWrap('/starttimer (or /ticketstarttimer, or /starttickettimer) [time]: (mods/bc only) Start a [time] minute timer for the ticket show start when in "timer" mode.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/stoptimer (or /ticketstoptimer, or /stoptickettimer): (mods/bc only) Stop the ticket timer.'); helptxtmsg += '\n \u2022 ' + wordWrap('/tickettimeleft : (mods/bc only) Display the time left on the ticket show countdown.'); helptxtmsg += '\n \u2022 ' + wordWrap('/showtime : (all users) Display a message showing how long the current show has been hidden.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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!'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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'); helptxtmsg += '\n \u2022 ' + wordWrap('/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'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'presales': { validhelpcmd = true; let helptxtmsg = '\u23E9 Ticket Show Pre-sales:'; helptxtmsg += '\n \u2022 ' + wordWrap('/presalelist: Display the list of pre-sale ticket holders in the chat, shown to the user that requests it.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/presalestoptimer: Stop any pre-sales timer that is running, for either the automatic timer, or a manually started timer.'); helptxtmsg += '\n \u2022 ' + wordWrap('/presaleaddtime [time]: Add [time] minutes to the pre-sale timer, for either the automatic timer, or a manually started timer.'); helptxtmsg += '\n \u2022 ' + wordWrap('/presaletimeleft: Display the time left on the current timer, for either the automatic timer, or a manually started timer.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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".'); helptxtmsg += '\n ' + wordWrap('--- 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).'); helptxtmsg += '\n ' + wordWrap('--- 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.'); helptxtmsg += '\n ' + wordWrap('--- 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addpresale [user]: Add a single user name [user] to the pre-sale ticket list manually (normally they are added through ticket sales).'); helptxtmsg += '\n \u2022 ' + wordWrap('/rmvpresale [user]: Remove a single user name [user] from the pre-sale ticket list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'messaging': { validhelpcmd = true; let helptxtmsg = '\u23E9 Private Messaging:'; helptxtmsg += '\n \u2022 ' + wordWrap('/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).'); helptxtmsg += '\n ' + wordWrap('--- - 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.'); helptxtmsg += '\n ' + wordWrap('--- - A related command is /reply.'); helptxtmsg += '\n \u2022 ' + wordWrap('/reply: This command is usable by everyone once they have received a PM from a moderator or broadcaster.'); helptxtmsg += '\n ' + wordWrap('--- - 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.'); helptxtmsg += '\n ' + wordWrap('--- - You should be careful using this to ensure the last person that PMd you is the person you are intending to reply to.'); helptxtmsg += '\n ' + wordWrap('--- - Alternatvely, a new PM can be sent using the /pm command rather than reply if you are not sure who last PMd you.'); helptxtmsg += '\n \u2022 ' + wordWrap('/bc: This command is usable by moderators to send a PM specifically to the broadcaster.'); helptxtmsg += '\n ' + wordWrap('--- - The syntax for using this type of PM is "/bc [X]", where [X] is the message you want to send.'); helptxtmsg += '\n \u2022 ' + wordWrap('/tm: This command that is usable by moderators and the broadcaster to send a PM to the moderator group as a whole.'); helptxtmsg += '\n ' + wordWrap('--- - The syntax for using this type of PM is "/tm [X]", where [X] is the message you want to send.'); helptxtmsg += '\n \u2022 ' + wordWrap('/tbm: This command is usable by moderators and the broadcaster to send a PM to the moderator group plus the broadcaster.'); helptxtmsg += '\n ' + wordWrap('--- - The syntax for using this type of PM is "/tbm [X]", where [X] is the message you want to send.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'timer': { validhelpcmd = true; let helptxtmsg = '\u23E9 Countdown Timers / Clocks:'; helptxtmsg += '\n \u2705 Primary Timer:'; helptxtmsg += '\n \u2022 ' + wordWrap('/startclock [time] [description] (also /sc or /st): 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.'); helptxtmsg += '\n ' + wordWrap('--- The 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.'); helptxtmsg += '\n ' + wordWrap('--- The 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addtoclock: This command is usable by moderators and broadcasters to add time to (or subtract time from) an existing countdown.'); helptxtmsg += '\n ' + wordWrap('--- The 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/timeleft: This command will display the amount of time left in the countdown.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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'); helptxtmsg += '\n \u2022 ' + wordWrap('/stopclock: This command will end the countdown timer.'); helptxtmsg += '\n\n \u2705 Timer #2:'; helptxtmsg += '\n \u2022 ' + wordWrap('/startclock2 [time] [description] (also /sc2 or /st2): 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addtoclock2: This command is usable by moderators and broadcasters to add time to (or subtract time from) an existing Timer #2 countdown.'); helptxtmsg += '\n \u2022 ' + wordWrap('/timeleft2: This command will display the amount of time left in the Timer #2 countdown.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/stopclock2: This command will end the Timer #2 countdown.'); helptxtmsg += '\n\n \u2705 Timer #3:'; helptxtmsg += '\n \u2022 ' + wordWrap('/startclock3 [time] [description] (also /sc3 or /st3): 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addtoclock3: This command is usable by moderators and broadcasters to add time to (or subtract time from) an existing Timer #3 countdown.'); helptxtmsg += '\n \u2022 ' + wordWrap('/timeleft3: This command will display the amount of time left in the Timer #3 countdown.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/stopclock3: This command will end the Timer #3 countdown.'); helptxtmsg += '\n\n \u2705 Timer #4:'; helptxtmsg += '\n \u2022 ' + wordWrap('/startclock4 [time] [description] (also /sc4 or /st4): 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addtoclock4: This command is usable by moderators and broadcasters to add time to (or subtract time from) an existing Timer #4 countdown.'); helptxtmsg += '\n \u2022 ' + wordWrap('/timeleft4: This command will display the amount of time left in the Timer #4 countdown.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/stopclock4: This command will end the Timer #4 countdown.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'notices': { validhelpcmd = true; let helptxtmsg = '\u23E9 Rotating Notifier:'; helptxtmsg += '\n \u2022 ' + wordWrap('/cn: This command is usable by moderators and the broadcaster to post a plain notification without any separators or highlighting.'); helptxtmsg += '\n ' + wordWrap('--- - The syntax for using this type of notice is "/cn [X]", where [X] is the message you want to send.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n ' + wordWrap('--- - The syntax for using this type of notice is "/cnd [X]", where [X] is the message you want to send.'); helptxtmsg += '\n \u2022 ' + wordWrap('/cnh: This command is usable by moderators and the broadcaster to post a notice that includes highlighting, but no separators.'); helptxtmsg += '\n ' + wordWrap('--- - The syntax for using this type of notice is "/cnh [X]", where [X] is the message you want to send.'); helptxtmsg += '\n \u2022 ' + wordWrap('/cndh: This command is usable by moderators and the broadcaster to post a notice that includes both separators and highlighting.'); helptxtmsg += '\n ' + wordWrap('--- The syntax for using this type of notice is "/cndh [X]", where [X] is the message you want to send.'); helptxtmsg += '\n \u2022 ' + wordWrap('/userules: This command is used to toggle "on" or "off" the display of the Room Rules as a recurring notice.'); helptxtmsg += '\n \u2022 ' + wordWrap('/userulesenter: This command is used to toggle "on" or "off" the display of the Room Rules as an entry message.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/chgmsg1 [msg] (also /chgmsg2 - /chgmsg8): update the notifier message in Slot 1-8 to a new value of [msg].'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/dspallmsg: Display the current value for all of the messages in notifiers 1-8.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rsp1: Display the response message 1 in the chat, viewable by all.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rsp2: Display the response message 2 in the chat, viewable by all.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rsp3: Display the response message 3 in the chat, viewable by all.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rsp4: Display the response message 4 in the chat, viewable by all.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rsp5: Display the response message 5 in the chat, viewable by all.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n ' + wordWrap('--- - The syntax for using leaderboard is "/leaders" to send to yourself. Moderators and broadcasters can use "/leaders all", "/leaders mods" or "/leaders bc".'); helptxtmsg += '\n ' + wordWrap('--- - This command triggers the display of the top 5 tippers of the current session, regardless of the setting for periodic display of the leaderboard.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n ' + wordWrap('--- - 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.'); helptxtmsg += '\n ' + wordWrap('--- - Using the command with no paramters would result in the top 20 entries being sent only to the requesting user.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'chat': case 'chatcontrol': { validhelpcmd = true; let helptxtmsg = '\u23E9 Ultra Fembot help for Chat Control Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/silencelevel (also /sl): This command is used by moderators and broadcasters to control who is able to chat in the room.'); helptxtmsg += '\n ' + wordWrap('--- The syntax for using silencelevel is "/silencelevel [X]", where [X] is a number from 0 to 4.'); helptxtmsg += '\n ' + wordWrap('--- 0 = chat privileges to all users'); helptxtmsg += '\n ' + wordWrap('--- 1 = remove chat privileges from users without tokens'); helptxtmsg += '\n ' + wordWrap('--- 2 = remove chat privileges from users who have not tipped'); helptxtmsg += '\n ' + wordWrap('--- 3 = remove chat privileges from users who have not tipped the minimum configured tokens.'); helptxtmsg += '\n ' + wordWrap('--- 4 = allow only mods, fans, and VIPs to chat.'); helptxtmsg += '\n ' + wordWrap('--- The default setting for /silencelevel is 0. The chat ability of broadcasters, moderators, and fan club members is unaffected by the Silence Level.'); helptxtmsg += '\n \u2022 ' + wordWrap('/graphiclevel (also (/gl): This command is used by moderators and broadcasters to control who is able to post graphics or gifs in the room.'); helptxtmsg += '\n ' + wordWrap('--- The syntax for using graphiclevel is "/graphiclevel [X]", where [X] is a number from 0 to 4.'); helptxtmsg += '\n ' + wordWrap('--- 0 = grant graphic usage privileges to all users'); helptxtmsg += '\n ' + wordWrap('--- 1 = revoke graphic usage privileges from users who do not have tokens'); helptxtmsg += '\n ' + wordWrap('--- 2 = revoke graphic usage privileges from users who have not tipped'); helptxtmsg += '\n ' + wordWrap('--- 3 = revoke graphic usage privileges from users who have not tipped the minimum configured tokens.'); helptxtmsg += '\n ' + wordWrap('--- 4 = revoke graphic usage privileges from all users other than mods, fans, and VIPs.'); helptxtmsg += '\n ' + wordWrap('--- The default setting for /graphiclevel is 1. The graphiclevel does not affect the ability of broadcasters, moderators, and fan club members from posting graphics.'); helptxtmsg += '\n \u2022 ' + wordWrap('/ninja: This command is usable by moderators and broadcasters.'); helptxtmsg += '\n ' + wordWrap('--- The syntax for using silence is "/ninja [X]", where [X] is the user you want to silence without notification.'); helptxtmsg += '\n ' + wordWrap('--- The effect of the /ninja feature is similar the /silence feature except that the user is not notified.'); helptxtmsg += '\n ' + wordWrap('--- The effect of /ninja can be reversed by running the command /unninja.'); helptxtmsg += '\n ' + wordWrap('--- "@" username tagging is allowed.'); helptxtmsg += '\n \u2022 ' + wordWrap('/unninja: This command is usable by moderators and broadcasters.'); helptxtmsg += '\n ' + wordWrap('--- The syntax for using unninja is "/unninja [X]", where [X] is the username of the user you want to remove from the ninja list.'); helptxtmsg += '\n ' + wordWrap('--- unninja grants chat privileges back to a user who was previously silenced by ninja.'); helptxtmsg += '\n ' + wordWrap('--- "@" username tagging is allowed.'); helptxtmsg += '\n \u2022 ' + wordWrap('/ninjalist: This command is usable by moderators and broadcasters.'); helptxtmsg += '\n ' + wordWrap('--- Using this command will display the list of users that has been silenced using the /ninja command.'); helptxtmsg += '\n ' + wordWrap('--- Users can be removed from this list by running the command /unninja.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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).'); helptxtmsg += '\n \u2022 ' + wordWrap('/silence: The syntax for using silence is "/silence [X]", where [X] is the user you want to silence.'); helptxtmsg += '\n ' + wordWrap('--- The 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.'); helptxtmsg += '\n ' + wordWrap('--- The effect of /silence can be reversed by running the command /unsilence.'); helptxtmsg += '\n ' + wordWrap('--- "@" username tagging is allowed.'); helptxtmsg += '\n \u2022 ' + wordWrap('/unsilence: This command is usable by moderators and broadcasters to grant chat privileges back to a user who was previously silenced.'); helptxtmsg += '\n ' + wordWrap('--- The syntax for using unsilence is "/unsilence [X]", where [X] is the username of the user you want to unsilence.'); helptxtmsg += '\n ' + wordWrap('--- NOTE: /unsilence cannot undo the effect of Chaturbate\'s silence for 6 hours feature!'); helptxtmsg += '\n ' + wordWrap('--- "@" username tagging is allowed.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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).'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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'); helptxtmsg += '\n \u2022 ' + wordWrap('/clearanswerlock: Clears all "required answer" restrictions and starts over. All affected user groups will have to respond to a question again.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/cleargraylock: Clears all gray chat lock tracking and starts over. All gray users will be time restricted by the current time threshold setting.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addgraylock [user]: Reinstates gray time lock on a specific user, they will not be able to chat until the gray chat lock time elapses.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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).'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'tipmenu': { validhelpcmd = true; let helptxtmsg = '\u23E9 Tip Menu Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/tipmenu: Display the tip menu in the chat. Available to any user, menu only shown to the user that requests it.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/tipmenurequests (or /tmr): Show recent tip menu requests, defaults to the 10 most recent when no quantity is entered. When requested by a moderator it is sent to all users, otherwise just the requester. Note that this has been merged together with the /dicerolls and /positionmenurequests functions to show all 3 types of requests in one list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/tipmenurequests X: Show the last "X" requests.'); helptxtmsg += '\n \u2022 ' + wordWrap('/tipmenurequests all: Show all the requests (maximum of 100).'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/tipmenuadd X Y: Add an item name "Y" with a price of "X" tokens to the menu.'); helptxtmsg += '\n \u2022 ' + wordWrap('/tipmenurmv X: Removes every item with a price of "X" tokens from the tip menu.'); helptxtmsg += '\n \u2022 ' + wordWrap('/tipmenurmv Y: Will remove any item labeled "Y" regardless of price from the tip menu.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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).'); helptxtmsg += '\n \u2022 ' + wordWrap('/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).'); helptxtmsg += '\n \u2022 ' + wordWrap('/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).'); helptxtmsg += '\n \u2022 ' + wordWrap('/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).'); helptxtmsg += '\n \u2022 ' + wordWrap('/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).'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'positions': { validhelpcmd = true; let helptxtmsg = '\u23E9 ' + posMenuLiteralDesc + ' Menu Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/posmenu: Display the ' + posMenuLiteralDesc + ' tip menu in the chat. Available to any user, menu only shown to the user that requests it.'); helptxtmsg += '\n \u2022 ' + wordWrap('/useposmenu [on/off]: Toggle the setting for whether the ' + posMenuLiteralDesc + ' Tip Menu is "on" or "off". Overrides the initial setting to turn the ' + posMenuLiteralDesc + ' Tip Menu on or off during the show.'); helptxtmsg += '\n \u2022 ' + wordWrap('/posmenurequests: Show recent ' + posMenuLiteralDesc + ' menu requests, defaults to a maximum of the 10 most recent. Note that this has been merged together with the /dicerolls and regular /tmr functions to show all 3 types of requests in one list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/posmenuadd X Y: Add an item name "Y" with a price of "X" tokens to the ' + posMenuLiteralDesc + ' menu.'); helptxtmsg += '\n \u2022 ' + wordWrap('/posmenurmv X: Removes every item from the ' + posMenuLiteralDesc + ' menu with a price of "X" tokens from the ' + posMenuLiteralDesc + ' menu.'); helptxtmsg += '\n \u2022 ' + wordWrap('/posmenurmv Y: Will remove any item labeled "Y" regardless of price from the ' + posMenuLiteralDesc + ' menu.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'tokenpoll': { validhelpcmd = true; let helptxtmsg = '\u23E9 Token Poll Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/poll: (all users) Display the current poll results board in the chat for the requesting user. Displayed to all when requested by moderators.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/endpoll: (mods/bc only) When running under manual control, end the poll and display the winner.'); helptxtmsg += '\n \u2022 ' + wordWrap('/restartpoll: (mods/bc only) If the poll is accidentally ended, or suspended, it can be restarted using this command.'); helptxtmsg += '\n \u2022 ' + wordWrap('/resetpoll: (mods/bc only) This will reset the poll to the beginning and start the voting at 0 for the same poll options.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/polloptadd X Y: (mods/bc only) Add an item named "Y" with a price of "X" tokens to the poll.'); helptxtmsg += '\n \u2022 ' + wordWrap('/polloptrmv X: (mods/bc only) Will remove any item with a price of "X" from the token poll.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/polladdtime X: (mods/bc only) Adds "X" minutes to the poll timer if a timer is running.'); helptxtmsg += '\n \u2022 ' + wordWrap('/pollstoptimer: (mods/bc only) Ends the timer if running under timed mode.'); helptxtmsg += '\n \u2022 ' + wordWrap('/pollchgtitle [new title]: (mods/bc only) Update the text of the token poll title to [new title].'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/hijackprice [newprice]: (mods/bc only) Update the price for hijacking the poll. Note that updating it to 0 will disable the hijack feature.'); helptxtmsg += '\n\n \u2705 ON DEMAND POLL:'; helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/odstart: (mods/bc only) Start the on-demand poll, viewers can now see the optionsand vote.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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).'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'textpoll': { validhelpcmd = true; let helptxtmsg = '\u23E9 Ultra Fembot help for Text Poll Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/textpoll: (all users) Display the current text poll results board in the chat for the requesting user. Displayed to all when requested by moderators.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/endtextpoll: (mods/bc only) When running under manual control, end the text poll and display the winner.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/resettextpoll: (mods/bc only) This will reset the poll to the beginning and start the voting at 0 for the same poll options.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/textoptadd X Y: (mods/bc only) Add an item named "Y" with a chice ID of "X" tokens to the poll.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/textaddtime X: (mods/bc only) Adds "X" minutes to the text poll timer if a timer is running.'); helptxtmsg += '\n \u2022 ' + wordWrap('/textstoptimer: (mods/bc only) Ends the text poll timer if running under timed mode.'); helptxtmsg += '\n \u2022 ' + wordWrap('/textchgtitle [new title]: (mods/bc only) Update the text of the text poll title to [new title].'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'nicelist': { validhelpcmd = true; let helptxtmsg = '\u23E9 Nicelist Commands:'; helptxtmsg += '\n' + wordWrap('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. Using /silence will still silence a user on the nice list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addnice [username]: The syntax for using this command is "/addnice [username]", where [username] is the user you want to add to the nice list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rmvnice [username]: The syntax for using this command is "/rmvnice [username]", where [username] is the user you want to remove from the nice list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/nicelist: Display the list of users currently in the nice list.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'viplist': { validhelpcmd = true; let helptxtmsg = '\u23E9 VIP List Commands:'; helptxtmsg += '\n' + wordWrap('Adding a user to the VIP list gives them a badge icon in the chat, PM ability, and may give them other discounts or free tickets to shows, depending on configuration.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addvip [username]: Adds [username] to the VIP list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rmvvip [username]: Removes [username] from the VIP list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/viplist: Displays the list of users currently in the VIP list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/setvipicon [:iconname]: Update the group icon used for VIPs to a new value. A value of "null" can be used to clear the existing setting.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'fans': { validhelpcmd = true; let helptxtmsg = '\u23E9 External Fan Club List Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/addfan [username]: Adds [username] to the External Fanclub 1 list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rmvfan [username]: Removes [username] from the External Fanclub 1 list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/fanlist: Displays the list of users currently in the External Fan Club 1 list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addfan2: Same as /addfan above but for External Fan Club 2.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rmvfan2: Same as /rmvfan above but for External Fan Club 2.'); helptxtmsg += '\n \u2022 ' + wordWrap('/fanlist2: Display the list of users in External Fan Club 2.'); helptxtmsg += '\n \u2022 ' + wordWrap('/setextfanicon [:iconname]: 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/setextfan2icon [:iconname]: 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/setfanicon [:iconname]: Update the group icon used for CB Fanclub to a new value. A value of "null" can be used to clear the existing setting.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'botmods': { validhelpcmd = true; let helptxtmsg = '\u23E9 Bot Moderator List Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/addmod [username]: Adds [username] to the Bot Moderator list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rmvmod [username]: Removes [username] from the Bot Moderator list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/modlist: Displays the list of users currently in the Fembot Moderator list (list will also include broadcaster and CB mods).'); helptxtmsg += '\n \u2022 ' + wordWrap('/setmodicon [:iconname]: Update the group icon used for CB Moderators to a new value. A value of "null" can be used to clear the existing setting.'); helptxtmsg += '\n \u2022 ' + wordWrap('/setbotmodicon [:iconname]: Update the group icon used for Bot Moderators to a new value. A value of "null" can be used to clear the existing setting.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'wordlist': { validhelpcmd = true; let helptxtmsg = '\u23E9 Blocked Word List Commands:'; helptxtmsg += '\n' + wordWrap('Adding 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addword [word]: 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rmvword [word]: The value for [word] must exactly match the value from the list. 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/wordlist: Displays the list of words currently in the Public Blocked Word list, available to both mods and broadcasters.'); helptxtmsg += '\n \u2022 ' + wordWrap('/wordlistprv: Displays the list of words currently in the Private Blocked Word list, available only to broadcasters.'); helptxtmsg += '\n \u2022 ' + wordWrap('/botblock: Displays the list of words automatically added to the Public word list by the Fembot. You do not need to include these in your list on the launch page.'); helptxtmsg += '\n \u2022 ' + wordWrap('/qrel [username]: Releases [username] from the quarantine list, "@" username tagging is allowed.'); helptxtmsg += '\n \u2022 ' + wordWrap('/qsil [username]: Moves [username] from the quarantine list to the silence list. If a user is specified, only that user is moved. If no username is specified, all quarantine users are moved. "@" username tagging is allowed'); helptxtmsg += '\n \u2022 ' + wordWrap('/qlist: Displays the list of users currently in quarantine.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'quar': { validhelpcmd = true; let helptxtmsg = '\u23E9 Quarantine User Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/qrel [username]: Releases [username] from the quarantine list, "@" username tagging is allowed.'); helptxtmsg += '\n \u2022 ' + wordWrap('/qsil [username]: Moves [username] from the quarantine list to the silence list. If a user is specified, only that user is moved. If no username is specified, all quarantine users are moved. "@" username tagging is allowed'); helptxtmsg += '\n \u2022 ' + wordWrap('/qlist: Displays the list of users currently in quarantine.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'lush': case 'toy': { validhelpcmd = true; let helptxtmsg = '\u23E9 Toy Menu Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/toymenu: Display the Toy Menu in chat. Available to any user, only shown to the user that requests it.'); helptxtmsg += '\n \u2022 ' + wordWrap('/chgtoy [toyname]: Changes the name of the toy currently being used, where [toyname] 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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'media': { validhelpcmd = true; let helptxtmsg = '\u23E9 Media List Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/media: Display the media list in chat. Available to any user, only shown to the user that requests it.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'dice': { validhelpcmd = true; let helptxtmsg = '\u23E9 Dice Game Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/chgdiceprice [amt]: Change the dice roll price to a new amount [amt]. Available only to broadcasters and moderators.'); helptxtmsg += '\n \u2022 ' + wordWrap('/dicerolls: Display the last (up to) 10 rolls of the dice, especially helpful if several rolls have been made in a short period of time. Note that this has been merged together with the /posmenurequests and regular /tmr (/tipmenurequests) functions to show all 3 types of requests in one list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/freeroll: Broadcasters or moderators can perform a free roll of the dice - no tips required.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'guests': { validhelpcmd = true; let helptxtmsg = '\u23E9 Guest List Notice Commands:'; helptxtmsg += '\n \u2022 ' + wordWrap('/guests: Display the Guest Info Notice in chat. Available to any user, only shown to the user that requests it.'); helptxtmsg += '\n \u2022 ' + wordWrap('/useguest [on/off]: Toggle the setting for whether the Guest Info Notice is "on" or "off", and displays at the defined interval. Overrides the initial setting to turn the Guest Info Notice on or off during the show.'); cb.sendNotice(helptxtmsg,helpsendto,appNoticeColor); break; } case 'about': { validhelpcmd = true; displayAbout(helpsendto); break; } } if (!validhelpcmd) { cb.sendNotice(helpoption + ' is not a valid subsection of the help menu. Type "/fbhelp" to access the main help menu.',helpsendto,appNoticeColor); } } // ******************************* Upon user entry of a Message ************************************** cb.onMessage(function (msg) { let rawmsg = msg.m; let trimmedmsg = msg.m.trim(); let msgarray = trimmedmsg.split(' '); let msgcommand = msgarray[0].toLowerCase(); let msguser = msg.user; let msgismod = msg.is_mod; let msgisbotmod = false; let msgiscbmod = msg.is_mod; let msgisdarkblue = false; let msgislightblue = false; let msgislightpurple = false; let msgisdarkpurple = false; let msgisgray = false; let msgishidden = false; let msgisbc = (msguser === BC); let msgisfan = msg.in_fanclub; let msgisextfan1 = cbjs.arrayContains(extFanListArray,msguser); let msgisextfan2 = cbjs.arrayContains(extFanList2Array,msguser); let msgisvip = cbjs.arrayContains(VIPListArray,msguser); let msgisnice = cbjs.arrayContains(niceListArray,msguser); let messageArrayBuilt = false; let listRegExp = /[,\s]+/; let listRegExpSpc = /[,]+/; if (msg['X-Spam'] != true && minMessagesForNotice > 0) { msgCounterTipMenu++; msgCounterPosMenu++; msgCounterLushMenu++; msgCounterDice++; msgCounterNotifier++; msgCounterSummary++; msgCounterTokenPoll++; msgCounterLeaderboard++; msgCounterRules++; msgCounterMedia++; msgCounterPresales++; msgCounterIconNotice++; msgCounterKing++; msgCounterKingSession++; msgCounterAllTime++; msgCounterFollow++; msgCounterTextPoll++; } if (msg.tipped_tons_recently) { msgisdarkpurple = true; } else if (msg.tipped_alot_recently) { msgislightpurple = true; } else if (msg.tipped_recently) { msgisdarkblue = true; } else if (msg.has_tokens) { msgislightblue = true; } else if (!msg.has_tokens) { msgisgray = true; } if (msgismod) { populateModeratorArray(msguser,'cbmod','a'); } else { if (cbjs.arrayContains(moderatorList.name,msguser)) { let modlistidx = moderatorList.name.indexOf(msguser); if (moderatorList.type[modlistidx] == 'botmod') { msgisbotmod = true; msgismod = true; } else if (moderatorList.type[modlistidx] == 'cbmod') { populateModeratorArray(msguser,'cbmod','r'); } } } let ismodlvlmsg1 = false; let ismodlvlmsg2 = false; let ismodlvlmsg3 = false; if (msgismod) { ismodlvlmsg1 = true; if (modLevel == 'Standard') { ismodlvlmsg2 = true; } else if (modLevel == 'Advanced') { ismodlvlmsg2 = true; ismodlvlmsg3 = true; } } if (msgisvip && !cbjs.arrayContains(VIPInShowArray,msguser)) { VIPInShowArray.push(msguser); } if (msgisextfan1 && !cbjs.arrayContains(extFanInShowArray,msguser)) { extFanInShowArray.push(msguser); } if (msgisextfan2 && !cbjs.arrayContains(extFanInShow2Array,msguser)) { extFanInShow2Array.push(msguser); } if (msgisfan) { populateFanClubArray(msguser); } if (viewerNotesWhen == 'First Chat' && cbjs.arrayContains(viewerNotesArray.username,msguser)) { let vnoteidx = viewerNotesArray.username.indexOf(msguser); if (!viewerNotesArray.displayed[vnoteidx]) { cb.sendNotice('Fembot Viewer Notes for @' + viewerNotesArray.username[vnoteidx] + ': ' + viewerNotesArray.notes[vnoteidx], BC, '', '', boldTextLiteral); viewerNotesArray.displayed[vnoteidx] = true; if (viewerNotesWho == 'Display to Broadcaster and Moderators') { cb.sendNotice('Fembot Viewer Notes for @' + viewerNotesArray.username[vnoteidx] + ': ' + viewerNotesArray.notes[vnoteidx], BC, '', '', boldTextLiteral, 'red'); } } } if (msgcommand.charAt(0) != '/') { if (requireAnswerToggle && !msgisbc && !ismodlvlmsg1 && !msgisfan && !msgisextfan1 && !msgisextfan2 && !msgisvip) { if (msgisgray && requireAnswerLevel >= 1 || msgislightblue && requireAnswerLevel >= 2 || msgisdarkblue && requireAnswerLevel >= 3 || msgislightpurple && requireAnswerLevel >= 4 || msgisdarkpurple && requireAnswerLevel >= 5) { if (requireAnswerLockCheck(msguser) === false) { let lockanswer = msgcommand; let lockuserindex = answerLockList.indexOf(msguser); let lockquestion = answerLockQuestion[lockuserindex]; let correctanswer = answerLockAnswer[lockuserindex]; if (lockanswer == correctanswer) { answerLockStatus[lockuserindex] = 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.', msguser, appNoticeColor, '', boldTextLiteral); msg['X-Spam'] = true; } else { cb.sendNotice('Sorry, the chat is locked for your user level until you correctly solve the following math problem: \n ' + lockquestion + '\nType your answer in the chat.', msguser, appWarningColor, '', boldTextLiteral); msg['X-Spam'] = true; } } } } } if (textPollToggle) { var tpfirstbyte = msgcommand.charAt(0); if (tpfirstbyte >= '1' && tpfirstbyte <= '5') { var tpfirstbyteN = parseInt(tpfirstbyte); if (cbjs.arrayContains(textPollArray.voteID,tpfirstbyteN)) { if (cbjs.arrayContains(textPollUsersVoted,msguser)) { cb.sendNotice(botName + ' You have already voted in the poll, you cannot vote again.', msguser, textPollBgColor, textPollTextColor, boldTextLiteral); } else { var textpollamt = 1; if (msgisfan && textPollFanDouble) { textpollamt = 2; cb.sendNotice('Since you are a member of the fan club, your vote is doubled!', msguser, textPollBgColor, textPollTextColor, boldTextLiteral); } textPollVote(tpfirstbyteN,textpollamt,msguser); } } } } if (msgcommand.charAt(0) == '/') { msg['X-Spam'] = true; msgishidden = true; let recognizedcmd = false; let commandVar1 = parseInt(msgarray[1]); let commandVar2 = parseInt(msgarray[2]); let commandVar1dec = parseFloat(msgarray[1]); //******** Chat Control Commands *********** switch (msgcommand) { case '/sl': case '/silencelevel': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { let numlevel = parseInt(msgarray[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).', msguser, 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).', msguser, appNoticeColor); } else if (numlevel == silenceLevel) { cb.sendNotice('The current silence level is already set to ' + silenceLevel + '.', msguser, appNoticeColor); } else { setSilenceLevel(numlevel, msguser); } } else { cb.sendNotice(botName + ' 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).', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/gl': case '/graphicslevel': case '/graphiclevel': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { let numgrlevel = parseInt(msgarray[1]); if (isNaN(numgrlevel)) { 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).', msguser, appNoticeColor); } else if (numgrlevel < 0 || numgrlevel > 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).', msguser, appNoticeColor); } else if (numgrlevel == graphicLevel) { cb.sendNotice('The current graphics level is already set to ' + graphicLevel + '.', msguser, appNoticeColor); } else { setGraphicLevel(numgrlevel, msguser); } } else { cb.sendNotice(botName + ' 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).', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/chplay': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { suppressPrefix = true; cb.sendNotice(botName + ' 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".', msguser, appNoticeColor); } break; } case '/charades': { recognizedcmd = true; if (msgarray[1] == 'off') { if (ismodlvlmsg1 || msgisbc) { suppressPrefix = false; cb.sendNotice(botName + ' Message prefixes (icons, tip count, etc) have been re-enabled.', msguser, appNoticeColor); } } break; } case '/minmsg': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { let nummsg = parseInt(msgarray[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.', msguser, appNoticeColor); } else { minMessagesForNotice = nummsg; cb.sendNotice('The minimum number of chat messages required before a recurring notice is displayed has been updated to ' + nummsg + '.', msguser, appNoticeColor); if (msguser != BC) { cb.sendNotice('The minimum number of chat messages required before a recurring notice is displayed has been updated to ' + nummsg + ' by ' + msguser + '.', BC, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/chgint': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { let newtimervalue = parseFloat(msgarray[2]); if (msgarray[1]) { let intervaltochange = msgarray[1].toLowerCase(); if (!cbjs.arrayContains(noticeIntervals.name,intervaltochange)) { cb.sendNotice(botName + 'The value entered for the notice type to change is invalid, please try again. The valid types are: \n' + cbjs.arrayJoin(noticeIntervals.name, ', '), msguser, appNoticeColor); } else if (!msgarray[2]) { cb.sendNotice(botName + 'This command requires a parameter to define the new interval (in minutes), in the format "/chgint X Y", where Y is the new display interval in minutes. An example of a valid command would be "/chgint dice 3.2" to update the Dice Notice interval to 3.2 minutes.', msguser, appNoticeColor); } else if (isNaN(newtimervalue)) { cb.sendNotice(botName + 'The second parameter requires a numeric value to define the new interval (in minutes), in the format "/chgint X Y", where Y is the new display interval in minutes. An example of a valid command would be "/chgint dice 3.2" to update the Dice Notice interval to 3.2 minutes.', msguser, appNoticeColor); } else if (newtimervalue < 1) { cb.sendNotice(botName + 'The new value for the timer interval must be a number greater than or equal to "1" (such as 1, 3, 4.5, etc).', msguser, appNoticeColor); } else { updateIntervalValues(intervaltochange,newtimervalue); cb.sendNotice(botName + 'The "' + intervaltochange + '" notice timer has been updated to a new interval of ' + newtimervalue + ' minutes. This will take effect after the next display of the notice.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'This command requires a parameter to define the notice timer that is to be updated.\n The command format is "/chgint X Y", where X is one of the interval types from the below list and Y is the new interval in minutes. Valid types: \n' + cbjs.arrayJoin(noticeIntervals.name, ', ') + '\nAn example of a valid command would be "/chgint dice 3.2" to update the Dice Notice interval to 3.2 minutes.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/dspint': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let dspintstr = ''; if (noticeIntervals.name.length > 0) { dspintstr = '***** Listing of Current Notice Intervals (and setting IDs) *****'; for (let dspintidx = 0; dspintidx < noticeIntervals.name.length; dspintidx++) { dspintstr += '\n' + (dspintidx+1) + '. ' + noticeIntervals.name[dspintidx] + ' (' + noticeIntervals.settingID[dspintidx] + '): ' + Math.round((this[noticeIntervals.fieldname[dspintidx]]/60000)*100)/100 + ' min'; } } else { dspintstr = 'No notice intervals have been defined.'; } cb.sendNotice(dspintstr, msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1,msguser,appNoticeColor); } break; } case '/emoji': case '/emojis': { if (msgisbc || ismodlvlmsg1) { let emojimsg = wordWrap('The following is a sample listing of some emojis and unicode characters that can be copied and pasted into the App launch page values for emoji borders or used in other text strings such as a welcome message, goal name, or room title. Note that the room title will not allow some of the more complex emojis so those are separated out in the list.'); emojimsg += '\nRandom 1: \uD83D\uDC45 \uD83D\uDC44 \uD83D\uDC41\uFE0F \uD83D\uDCAA \uD83D\uDC59 \uD83D\uDC60 \uD83D\uDC5C \uD83D\uDCA5 \uD83D\uDCA6 \uD83D\uDECF\uFE0F \uD83E\uDDFB \uD83D\uDEBD \uD83D\uDCFD\uFE0F \uD83D\uDCA1 \uD83D\uDCFA \uD83D\uDD12 \uD83C\uDF0E \u2705 \u274C \u2796 \u2755 \u2754 \u260E\uFE0F'; emojimsg += '\nRandom 2: \uD83D\uDC51 \uD83D\uDD0B \uD83D\uDDA5\uFE0F \uD83C\uDF7D\uFE0F \uD83C\uDF7A \uD83C\uDF78 \uD83E\uDDCA \u2615 \uD83D\uDD95 \uD83D\uDC4F \uD83D\uDE4F \uD83D\uDCEA \uD83D\uDCE7 \u2709\uFE0F \uD83D\uDCB2 \uD83D\uDCB0 \uD83C\uDFB5 \uD83E\uDD41 \uD83C\uDFB8 \uD83C\uDF34 \uD83C\uDF35'; emojimsg += '\nRandom 3: \u2601\uFE0F \uD83D\uDD25 \u26A1 \uD83C\uDF29\uFE0F \uD83C\uDF19 \u2600\uFE0F \u2744\uFE0F \u2B50 \u23F0 \u231B \u231A \uD83D\uDD5B \uD83D\uDEE1\uFE0F \u2694\uFE0F \uD83D\uDDE1\uFE0F \uD83C\uDFF9 \uD83D\uDEA7 \uD83D\uDED1 \u2693'; emojimsg += '\nAnimal Faces: \uD83D\uDE38 \uD83D\uDC3B \uD83D\uDC2E \uD83D\uDC36 \uD83E\uDD81 \uD83D\uDC35 \uD83D\uDC3C \uD83D\uDC37 \uD83E\uDD8A'; emojimsg += '\nAnimals: \uD83D\uDC12 \uD83D\uDC18 \uD83D\uDC04 \uD83E\uDD84 \uD83E\uDD98 \uD83D\uDC1F \uD83D\uDC19 \uD83D\uDC09 \uD83D\uDC22 \uD83E\uDD9E \uD83E\uDD8B \uD83D\uDD77\uFE0F \uD83D\uDD78\uFE0F \uD83D\uDC1E'; emojimsg += '\nFlowers: \uD83C\uDF3C \uD83C\uDF38 \uD83C\uDFF5\uFE0F \uD83C\uDF37 \uD83C\uDF3B'; emojimsg += '\nFood: \uD83C\uDF69 \uD83C\uDF4C \uD83C\uDF52 \uD83C\uDF51 \uD83C\uDF49 \uD83C\uDF53 \uD83E\uDD68 \uD83C\uDF54 \uD83C\uDF2D \uD83C\uDF55 \uD83C\uDF2E \uD83E\uDDC1 \uD83E\uDD55 \uD83C\uDF46 \uD83C\uDF44'; emojimsg += '\nFaces: \uD83D\uDE32 \uD83D\uDE22 \uD83E\uDD21 \uD83D\uDC7D \uD83E\uDD16 \uD83D\uDCA9 \uD83D\uDE0D \uD83D\uDC7F \uD83D\uDC80 \uD83D\uDE44 \uD83D\uDE10 \uD83D\uDE42 \uD83D\uDE07 \uD83D\uDE43'; emojimsg += '\nHearts: \u2764\uFE0F \uD83E\uDDE1 \uD83D\uDC9B \uD83D\uDC9A \uD83D\uDC99 \uD83D\uDC9C \uD83E\uDD0D \uD83D\uDDA4 \uD83D\uDC94'; emojimsg += '\nAwards: \uD83E\uDD47 \uD83E\uDD48 \uD83E\uDD49 \uD83C\uDFC6'; emojimsg += '\nSymbols: \u25AA\uFE0F \u25FE \u25AB\uFE0F \u25FD \uD83D\uDD39 \uD83D\uDD38 \u26D4 \u2622\uFE0F \uD83D\uDEAB \u26A0\uFE0F'; emojimsg += '\nNumbers: 1\uFE0F\u20E3 2\uFE0F\u20E3 3\uFE0F\u20E3 4\uFE0F\u20E3 5\uFE0F\u20E3 6\uFE0F\u20E3 7\uFE0F\u20E3 8\uFE0F\u20E3 9\uFE0F\u20E3 \uD83D\uDD1F'; emojimsg += '\nSports and Gaming: \u265F\uFE0F \u2663\uFE0F \u2665\uFE0F \u2660\uFE0F \uD83C\uDFB0 \uD83C\uDFB1 \uD83D\uDD79\uFE0F \uD83C\uDFAE \u26BE \uD83C\uDFC8 \u26BD'; emojimsg += '\nSeasonal: \u2601\uFE0F \uD83C\uDF84 \u26C4 \uD83C\uDF81 \uD83C\uDF80 \uD83C\uDF85 \uD83C\uDF83 \uD83E\uDD87 \u2618\uFE0F \uD83C\uDF40'; emojimsg += '\nUnicode characters and the following emojis can be used in your room title:'; emojimsg += '\nSample unicode characters: \u2103 \u2109 \u21D0 \u21D1 \u21D2 \u21D3 \u21D4 \u2655 \u265A \u2776 \u2777 \u2778 \u2764 \u2756 \u2749 \u272D \u2740 \u27A4 \uA5BB \uA564 \uA66C \uFFFD'; emojimsg += '\nRoom Title Set 1: \u231B \u2744\uFE0F \u2B50 \u2600\uFE0F \u2764\uFE0F \u26F5 \u26EA \u26A1 \u231A \u26D4 \u2694\uFE0F \u26A0\uFE0F \u26C4 \u2693 \u2618\uFE0F'; emojimsg += '\nRoom Title Set 2: \u2663\uFE0F \u2665\uFE0F \u2660\uFE0F \u25AA\uFE0F \u25FE \u25AB\uFE0F \u25FD \u2615 \u2709\uFE0F 1\uFE0F\u20E3 2\uFE0F\u20E3 3\uFE0F\u20E3 4\uFE0F\u20E3 5\uFE0F\u20E3 6\uFE0F\u20E3 7\uFE0F\u20E3 8\uFE0F\u20E3 9\uFE0F\u20E3'; cb.sendNotice(emojimsg, msguser); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/chgtheme': case '/fbchgtheme': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (msgarray[1]) { let newtheme = msgarray[1].toLowerCase(); if (newtheme == 'none') { colorTheme = 'None'; loadAllFeatureColors(msguser,false); cb.sendNotice('You have updated the App to not use a color theme. The notice coloring will now default to the individual App features settings.', msguser, appNoticeColor, ''); } else if (newtheme == 'custom') { cb.sendNotice('A "custom" theme cannot be updated during the show, only the pre-defined themes, or "none".', msguser, appNoticeColor, ''); } else if (cbjs.arrayContains(themeArray.shortcut,newtheme)) { let themeindex = themeArray.shortcut.indexOf(newtheme); colorTheme = themeArray.name[themeindex]; loadThemeColors(msguser,false); cb.sendNotice('You have updated the color theme to "' + colorTheme + '".', msguser, appNoticeColor, ''); } else { cb.sendNotice('Invalid color theme name. The valid names are: \nnone, ' + cbjs.arrayJoin(themeArray.shortcut, ', '), msguser, appNoticeColor, ''); } } else { cb.sendNotice(botName + 'The /chgtheme command requires the entry of a parameter following the command, such as "/chgtheme pastelrainbow". The valid formats are: \nnone, ' + cbjs.arrayJoin(themeArray.shortcut, ', '), msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/seetheme': case '/seethemes': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { for (let stidx = 0; stidx < themeArray.name.length; stidx++) { let tempseebgcolor = themeArray.colorID[stidx]; let tempseetextcolor = themeArray.textcolor[stidx]; cb.sendNotice('********************************************\nTheme "' + themeArray.name[stidx] + '" (shortcut = "' + themeArray.shortcut[stidx] + '")\n********************************************', msguser, tempseebgcolor, tempseetextcolor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/fbsetbrdsep': case '/setbrdsep': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (cb.settings.noticeSepStyle == 'Heavy Dashed Line' || cb.settings.noticeSepStyle == 'Light Dashed Line' || cb.settings.noticeSepStyle == 'No Border') { cb.sendNotice(botName + ' The notice border character can only be updated if the bot is configured for a custom emoji or custom unicode character.', msguser, appNoticeColor); } else if (!msgarray[1]) { cb.sendNotice(botName + ' The parameter for new border separator was not specified.', msguser, appNoticeColor); } else { borderChar = msgarray[1]; noticeBorderChar(); cb.sendNotice(botName + ' Separator has been updated to " ' + borderChar + ' ".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/about': { recognizedcmd = true; displayAbout(msguser); break; } case '/clear': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { for (let i = 1; i <= 25; i++) { cb.sendNotice('clear'); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } //******** Timer Commands *********** case '/sc': case '/st': case '/startclock': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { 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.', msguser, appNoticeColor); } else if (isNaN (commandVar1dec) || commandVar1dec < .017 || commandVar1dec > 120) { cb.sendNotice('The first parameter is the time for the countdown in minutes, and must be a numeric value from 1 second up to 2 hrs, always entered in minutes (from 0.017 to 120). Decimal values are ok, such as 0.5 for a 30 second timer. As an example, to start a 10 minute timer, type: /startclock 10', msguser, appNoticeColor); } else { if (msgarray[2]) { let timerlabel = ''; for (let i = 2; i < msgarray.length; i++) { if (i === 2) { timerlabel = msgarray[i]; } else { timerlabel += ' ' + msgarray[i]; } } timerDesc = timerlabel; } else if (cb.settings.defaultTimerDesc) { timerDesc = cb.settings.defaultTimerDesc; } if (isNaN (commandVar1)) { commandVar1 = 0; } clockStartTime = new Date(); clockStopTime = new Date(clockStartTime.getTime() + commandVar1dec * 60000); clockMinsRemain = commandVar1; clockSecsRemain = parseInt((commandVar1dec-commandVar1)*60); clockTimeAdded = false; clockStopping = false; if (clockSecsRemain == 0) { cb.sendNotice(msguser + ' has started Timer #1 for ' + clockMinsRemain + ' minute' + (clockMinsRemain != 1 ? 's' : ''), '', appNoticeColor, '', boldTextLiteral); clockTimerMin(); } else { if (clockMinsRemain > 0) { displaySeconds = false; cb.sendNotice(msguser + ' has started Timer #1 for ' + clockMinsRemain + ' minute' + (clockMinsRemain != 1 ? 's' : '') + ' and ' + clockSecsRemain + ' second' + (clockSecsRemain != 1 ? 's' : ''), '', appNoticeColor, '', boldTextLiteral); } else { displaySeconds = true; cb.sendNotice(msguser + ' has started Timer #1 for ' + clockSecsRemain + ' second' + (clockSecsRemain != 1 ? 's' : ''), '', appNoticeColor, '', boldTextLiteral); } clockTimerSec(); } } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/clockadd': case '/addclock': case '/addtoclock': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let timeleftdec = clockMinsRemain + (clockSecsRemain/60); if (!commandVar1dec) { cb.sendNotice('Invalid command, you need to specify the amount of time to add to Timer #1 in minutes. Decimal values are ok, such as 0.5 to add 30 seconds to the timer. As an example, to add 3 minutes to the timer, type: /addtoclock 3', msguser, appNoticeColor); } else if (timeleftdec + commandVar1dec <= 0.017) { 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 (timeleftdec + commandVar1dec > 120) { cb.sendNotice('The added time will increase Timer #1 to greater than 2 hours, please use a smaller value.'); } else if (clockMinsRemain <= 0 && clockSecsRemain <= 0) { cb.sendNotice('Timer #1 is not running.', msguser, appNoticeColor); } else { clockAddTime(commandVar1dec); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser,appNoticeColor); } break; } case '/timeleft': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/stopclock': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if (clockMinsRemain >= 1 || clockSecsRemain >= 1) { stopClockTimer(msguser); } else { cb.sendNotice('Timer #1 is not running.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/chgclockdesc': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if(msgarray[1] != '' && msgarray[1] != null) { timerDesc = rawmsg.substring(14).trim(); cb.sendNotice('The Timer #1 description has been updated to "' + timerDesc + '".', msguser, appNoticeColor); } else { cb.sendNotice('No value was specified for the new Timer #1 description.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //******** Timer #2 Commands *********** case '/sc2': case '/st2': case '/startclock2': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { 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.', msguser, appNoticeColor); } else if (isNaN (commandVar1dec) || commandVar1dec < .017 || commandVar1dec > 120) { cb.sendNotice('The first parameter is the time for the countdown in minutes, and must be a numeric value from 1 second up to 2 hrs, always entered in minutes (from 0.017 to 120). Decimal values are ok, such as 0.5 for a 30 second timer. As an example, to start a 10 minute timer, type: /startclock2 10', msguser, appNoticeColor); } else { if (msgarray[2]) { let timer2lbl = ''; for (let i = 2; i < msgarray.length; i++) { if (i === 2) { timer2lbl = msgarray[i]; } else { timer2lbl += ' ' + msgarray[i]; } } timer2Desc = timer2lbl; } else if (cb.settings.defaultTimerDesc2) { timer2Desc = cb.settings.defaultTimerDesc2; } if (isNaN (commandVar1)) { commandVar1 = 0; } clock2StartTime = new Date(); clock2StopTime = new Date(clock2StartTime.getTime() + commandVar1dec * 60000); clock2MinsRemain = commandVar1; clock2SecsRemain = parseInt((commandVar1dec-commandVar1)*60); clock2TimeAdded = false; clock2Stopping = false; if (clock2SecsRemain == 0) { cb.sendNotice(msguser + ' has started Timer #2 for ' + clock2MinsRemain + ' minute' + (clock2MinsRemain != 1 ? 's' : ''), '', appNoticeColor, '', boldTextLiteral); clock2TimerMin(); } else { if (clock2MinsRemain > 0) { displaySeconds2 = false; cb.sendNotice(msguser + ' has started Timer #2 for ' + clock2MinsRemain + ' minute' + (clock2MinsRemain != 1 ? 's' : '') + ' and ' + clock2SecsRemain + ' second' + (clock2SecsRemain != 1 ? 's' : ''), '', appNoticeColor, '', boldTextLiteral); } else { displaySeconds2 = true; cb.sendNotice(msguser + ' has started Timer #2 for ' + clock2SecsRemain + ' second' + (clock2SecsRemain != 1 ? 's' : ''), '', appNoticeColor, '', boldTextLiteral); } clock2TimerSec(); } } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/clock2addtime': case '/clock2add': case '/addtoclock2': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { 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.', msguser, 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); break; } else { cb.sendNotice('Timer #2 is not running.', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod1, msguser,appNoticeColor); } break; } case '/timeleft2': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if (clock2MinsRemain >= 1 || clock2SecsRemain >= 1) { cb.sendNotice(clock2TimeLeft(), '', appWarningColor, '', boldTextLiteral); } else { cb.sendNotice('Timer #2 is not running.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/stopclock2': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if (clock2MinsRemain >= 1 || clock2SecsRemain >= 1) { stopClockTimer2(msguser); } else { cb.sendNotice('Timer #2 is not running.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/chgclock2desc': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if(msgarray[1] != '' && msgarray[1] != null) { timer2Desc = rawmsg.substring(14).trim(); cb.sendNotice('The Timer #2 description has been updated to "' + timer2Desc + '".', msguser, appNoticeColor); } else { cb.sendNotice('No value was specified for the new Timer #2 description.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //******** Timer #3 Commands *********** case '/sc3': case '/st3': case '/startclock3': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { 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.', msguser, appNoticeColor); } else if (isNaN (commandVar1dec) || commandVar1dec < .017 || commandVar1dec > 120) { cb.sendNotice('The first parameter is the time for the countdown in minutes, and must be a numeric value from 1 second up to 2 hrs, always entered in minutes (from 0.017 to 120). Decimal values are ok, such as 0.5 for a 30 second timer. As an example, to start a 10 minute timer, type: /startclock3 10', msguser, appNoticeColor); } else { if (msgarray[2]) { let timer3lbl = ''; for (let i = 2; i < msgarray.length; i++) { if (i === 2) { timer3lbl = msgarray[i]; } else { timer3lbl += ' ' + msgarray[i]; } } timer3Desc = timer3lbl; } clock3StartTime = new Date(); clock3StopTime = new Date(clock3StartTime.getTime() + commandVar1dec * 60000); clock3MinsRemain = commandVar1; clock3SecsRemain = parseInt((commandVar1dec-commandVar1)*60); clock3TimeAdded = false; clock3Stopping = false; if (clock3SecsRemain == 0) { cb.sendNotice(msguser + ' has started Timer #3 for ' + clock3MinsRemain + ' minute' + (clock3MinsRemain != 1 ? 's' : ''), '', appNoticeColor, '', boldTextLiteral); clock3TimerMin(); } else { if (clock3MinsRemain > 0) { displaySeconds3 = false; cb.sendNotice(msguser + ' has started Timer #3 for ' + clock3MinsRemain + ' minute' + (clock3MinsRemain != 1 ? 's' : '') + ' and ' + clock3SecsRemain + ' second' + (clock3SecsRemain != 1 ? 's' : ''), '', appNoticeColor, '', boldTextLiteral); } else { displaySeconds3 = true; cb.sendNotice(msguser + ' has started Timer #3 for ' + clock3SecsRemain + ' second' + (clock3SecsRemain != 1 ? 's' : ''), '', appNoticeColor, '', boldTextLiteral); } clock3TimerSec(); } } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/clock3addtime': case '/clock3add': case '/addtoclock3': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { 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.', msguser, 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); break; } else { cb.sendNotice('Timer #3 is not running.', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod1, msguser,appNoticeColor); } break; } case '/timeleft3': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if (clock3MinsRemain >= 1 || clock3SecsRemain >= 1) { cb.sendNotice(clock3TimeLeft(), '', appWarningColor, '', boldTextLiteral); } else { cb.sendNotice('Timer #3 is not running.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/stopclock3': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if (clock3MinsRemain >= 1 || clock3SecsRemain >= 1) { stopClockTimer3(msguser); } else { cb.sendNotice('Timer #3 is not running.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/chgclock3desc': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if(msgarray[1] != '' && msgarray[1] != null) { timer3Desc = rawmsg.substring(14).trim(); cb.sendNotice('The Timer #3 description has been updated to "' + timer3Desc + '".', msguser, appNoticeColor); } else { cb.sendNotice('No value was specified for the new Timer #3 description.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //******** Timer #4 Commands *********** case '/sc4': case '/st4': case '/startclock4': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { 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.', msguser, appNoticeColor); } else if (isNaN (commandVar1dec) || commandVar1dec < .017 || commandVar1dec > 120) { cb.sendNotice('The first parameter is the time for the countdown in minutes, and must be a numeric value from 1 second up to 2 hrs, always entered in minutes (from 0.017 to 120). Decimal values are ok, such as 0.5 for a 30 second timer. As an example, to start a 10 minute timer, type: /startclock4 10', msguser, appNoticeColor); } else { if (msgarray[2]) { let timer4lbl = ''; for (let i = 2; i < msgarray.length; i++) { if (i === 2) { timer4lbl = msgarray[i]; } else { timer4lbl += ' ' + msgarray[i]; } } timer4Desc = timer4lbl; } clock4StartTime = new Date(); clock4StopTime = new Date(clock4StartTime.getTime() + commandVar1dec * 60000); clock4MinsRemain = commandVar1; clock4SecsRemain = parseInt((commandVar1dec-commandVar1)*60); clock4TimeAdded = false; clock4Stopping = false; if (clock4SecsRemain == 0) { cb.sendNotice(msguser + ' has started Timer #4 for ' + clock4MinsRemain + ' minute' + (clock4MinsRemain != 1 ? 's' : ''), '', appNoticeColor, '', boldTextLiteral); clock4TimerMin(); } else { if (clock4MinsRemain > 0) { displaySeconds4 = false; cb.sendNotice(msguser + ' has started Timer #4 for ' + clock4MinsRemain + ' minute' + (clock4MinsRemain != 1 ? 's' : '') + ' and ' + clock4SecsRemain + ' second' + (clock4SecsRemain != 1 ? 's' : ''), '', appNoticeColor, '', boldTextLiteral); } else { displaySeconds4 = true; cb.sendNotice(msguser + ' has started Timer #4 for ' + clock4SecsRemain + ' second' + (clock4SecsRemain != 1 ? 's' : ''), '', appNoticeColor, '', boldTextLiteral); } clock4TimerSec(); } } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/clock4addtime': case '/clock4add': case '/addtoclock4': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { 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.', msguser, 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); break; } else { cb.sendNotice('Timer #4 is not running.', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod1, msguser,appNoticeColor); } break; } case '/timeleft4': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if (clock4MinsRemain >= 1 || clock4SecsRemain >= 1) { cb.sendNotice(clock4TimeLeft(), '', appWarningColor, '', boldTextLiteral); } else { cb.sendNotice('Timer #4 is not running.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/stopclock4': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if (clock4MinsRemain >= 1 || clock4SecsRemain >= 1) { stopClockTimer4(msguser); } else { cb.sendNotice('Timer #4 is not running.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/chgclock4desc': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if(msgarray[1] != '' && msgarray[1] != null) { timer4Desc = rawmsg.substring(14).trim(); cb.sendNotice('The Timer #4 description has been updated to "' + timer4Desc + '".', msguser, appNoticeColor); } else { cb.sendNotice('No value was specified for the new Timer #4 description.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //******** Ninja Commands *********** case '/ninja': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc ) { let cmdval = rawmsg.substring(7).trim(); if (cmdval) { var cmdvalsplit = cmdval.split(listRegExp); if (cmdvalsplit.length > 1) { cb.sendNotice('Adding multiple users to the ninja list.', msguser, appNoticeColor); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i]) { let ninjaentrytoadd = cmdvalsplit[i].toLowerCase(); if (ninjaentrytoadd.charAt(0) == '@') { ninjaentrytoadd = ninjaentrytoadd.substring(1); } if (validateUserID(ninjaentrytoadd,'Ninja List',msguser,false)) { addRmvNinja(ninjaentrytoadd,msguser,'a'); } } } cb.sendNotice('All users were added.', msguser, appNoticeColor); } else { let ninjalisttoadd = msgarray[1].toLowerCase(); if (ninjalisttoadd.charAt(0) == '@') { ninjalisttoadd = ninjalisttoadd.substring(1); } if (validateUserID(ninjalisttoadd,'Ninja List',msguser,false)) { addRmvNinja(ninjalisttoadd,msguser,'a'); } } } else { cb.sendNotice(botName + ' You did not specify the username or list of usernames you want to add to the nice list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/unninja': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { let ninjalisttormv = msgarray[1].toLowerCase(); if (ninjalisttormv.charAt(0) == '@') { ninjalisttormv = ninjalisttormv.substring(1); } addRmvNinja(ninjalisttormv,msguser,'r'); } else { cb.sendNotice('You must enter a username as the parameter for the unninja command. Only single usernames can be entered.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/ninjalist': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { cb.sendNotice('Users currently on the Ninja List: ' + ninjaListArray.length, msguser, appNoticeColor); cb.sendNotice((ninjaListArray.length > 0 == true ? '@' + cbjs.arrayJoin(ninjaListArray, ', @') : 'No users on ninja list.'), msguser); cb.sendNotice('End of List', msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/showninja': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { let numsnmode = parseInt(msgarray[1]); if (isNaN(numsnmode)) { 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).', msguser, appNoticeColor); } else if (numsnmode < 0 || numsnmode > 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).', msguser, appNoticeColor); } else if (numsnmode == 0 && showNinjadMsgs == 'Do not show') { cb.sendNotice('The current setting for showing messages from ninja\'d users is already set to "Do not show".', msguser, appNoticeColor); } else if (numsnmode == 1 && showNinjadMsgs == 'Broadcaster only') { cb.sendNotice('The current setting for showing messages from ninja\'d users is already set to "Broadcaster only".', msguser, appNoticeColor); } else if (numsnmode == 2 && showNinjadMsgs == 'Mods only') { cb.sendNotice('The current setting for showing messages from ninja\'d users is already set to "Mods only".', msguser, appNoticeColor); } else if (numsnmode == 3 && showNinjadMsgs == 'Broadcaster and Mods') { cb.sendNotice('The current setting for showing messages from ninja\'d users is already set to "Broadcaster and Mods".', msguser, appNoticeColor); } else { if (numsnmode == 0) { showNinjadMsgs = 'Do not show'; cb.sendNotice('The setting for showing messages from ninja\'d users has been updated to "0=Do not show".', msguser, appNoticeColor); } else if (numsnmode == 1) { showNinjadMsgs = 'Broadcaster only'; cb.sendNotice('The setting for showing messages from ninja\'d users has been updated to "1=Broadcaster only".', msguser, appNoticeColor); } else if (numsnmode == 2) { showNinjadMsgs = 'Mods only'; cb.sendNotice('The setting for showing messages from ninja\'d users has been updated to "2=Mods only".', msguser, appNoticeColor); } else if (numsnmode == 3) { showNinjadMsgs = 'Broadcaster and Mods'; cb.sendNotice('The setting for showing messages from ninja\'d users has been updated to "3=Broadcaster and Mods".', msguser, appNoticeColor); } } } else { cb.sendNotice('You must enter a parameter for the new ninja message mode: 0=Do not show,1=Broadcaster only,2=Mods only,3=Broadcaster and Mods. Current setting is "' + showNinjadMsgs + '".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } //******** Silence List Commands *********** case '/silence': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { let silenceuseradd = msgarray[1].toLowerCase(); if (silenceuseradd.charAt(0) == '@') { silenceuseradd = silenceuseradd.substring(1); } addRmvSilence(silenceuseradd,msguser,'a'); } else { cb.sendNotice('No value was specified for the user to silence, please try again.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/unsilence': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { let silenceuserrmv = msgarray[1].toLowerCase(); if (silenceuserrmv.charAt(0) == '@') { silenceuserrmv = silenceuserrmv.substring(1); } addRmvSilence(silenceuserrmv,msguser,'r'); } else { cb.sendNotice('No value was specified for the user to unsilence, please try again.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/silencelist': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { cb.sendNotice('Users currently on the Silence List: ' + silenceListArray.length, msguser, appNoticeColor); cb.sendNotice((silenceListArray.length > 0 == true ? '@' + cbjs.arrayJoin(silenceListArray, ', @') : 'No users.'), msguser); cb.sendNotice('End of List', msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/showsilence': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { let numssmode = parseInt(msgarray[1]); if (isNaN(numssmode)) { 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).', msguser, appNoticeColor); } else if (numssmode < 0 || numssmode > 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).', msguser, appNoticeColor); } else if (numssmode == 0 && showSilencedMsgs == 'Do not show') { cb.sendNotice('The current setting for showing messages from bot silenced users is already set to "Do not show".', msguser, appNoticeColor); } else if (numssmode == 1 && showSilencedMsgs == 'Broadcaster only') { cb.sendNotice('The current setting for showing messages from bot silenced users is already set to "Broadcaster only".', msguser, appNoticeColor); } else if (numssmode == 2 && showSilencedMsgs == 'Mods only') { cb.sendNotice('The current setting for showing messages from bot silenced users is already set to "Mods only".', msguser, appNoticeColor); } else if (numssmode == 3 && showSilencedMsgs == 'Broadcaster and Mods') { cb.sendNotice('The current setting for showing messages from bot silenced users is already set to "Broadcaster and Mods".', msguser, appNoticeColor); } else { if (numssmode == 0) { showSilencedMsgs = 'Do not show'; cb.sendNotice('The setting for showing messages from silenced users has been updated to "0=Do not show".', msguser, appNoticeColor); } else if (numssmode == 1) { showSilencedMsgs = 'Broadcaster only'; cb.sendNotice('The setting for showing messages from silenced users has been updated to "1=Broadcaster only".', msguser, appNoticeColor); } else if (numssmode == 2) { showSilencedMsgs = 'Mods only'; cb.sendNotice('The setting for showing messages from silenced users has been updated to "2=Mods only".', msguser, appNoticeColor); } else if (numssmode == 3) { showSilencedMsgs = 'Broadcaster and Mods'; cb.sendNotice('The setting for showing messages from silenced users has been updated to "3=Broadcaster and Mods".', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/silencepfx': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { let silencepfxadd = msgarray[1].toLowerCase(); silencePrefixList.push(silencepfxadd); cb.sendNotice('You have added the prefix "' + silencepfxadd + '" to the Silence Prefix list for this show. \nMessages from all user IDs that start with this prefix will be suppressed.', msguser, appNoticeColor); } else { cb.sendNotice('No value was specified for the user to silence, please try again.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } //******** VIP Commands *********** case '/addvip': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { let cmdvipval = rawmsg.substring(8).trim(); if (cmdvipval != null) { let cmdvalvipsplit = cmdvipval.split(listRegExp); if (cmdvalvipsplit.length > 1) { let addvipnotice = 'Adding multiple users to the Fembot VIP list.'; addvipnotice += '\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 (let addvipidx = 0; addvipidx < cmdvalvipsplit.length; addvipidx++) { if (cmdvalvipsplit[addvipidx]) { let vipnametoadd = cmdvalvipsplit[addvipidx].toLowerCase(); if (vipnametoadd.charAt(0) == '@') { vipnametoadd = vipnametoadd.substring(1); } if (!cbjs.arrayContains(VIPListArray, vipnametoadd)) { addRmvVIP(vipnametoadd,'a'); addvipnotice += '\nAdded ' + vipnametoadd + ' to the Fembot VIP list.'; cb.sendNotice(msguser + ' has added you to the Fembot VIP list.', vipnametoadd, appNoticeColor); } else { addvipnotice += '\n' + vipnametoadd + ' is already on the Fembot VIP list. Skipping.'; } } } addvipnotice += '\nAll users were added and notified.'; if (msguser == BC) { cb.sendNotice(addvipnotice, msguser, appNoticeColor); cb.sendNotice(msguser + ' has added multiple users to the Fembot VIP list.\n' + 'Users added: ' + cbjs.arrayJoin(cmdvalvipsplit, ', '), BC, appNoticeColor, '', 'normal', 'red'); } else { cb.sendNotice(addvipnotice, BC, appNoticeColor); } } else { let vipnametoadd2 = msgarray[1].toLowerCase(); if (vipnametoadd2.charAt(0) == '@') { vipnametoadd2 = vipnametoadd2.substring(1); } if (cbjs.arrayContains(VIPListArray,vipnametoadd2)) { cb.sendNotice(botName + vipnametoadd2 + ' is already on the VIP list.', msguser, appNoticeColor); } else { addRmvVIP(vipnametoadd2,'a'); if (msguser == BC) { cb.sendNotice(botName + ' You have added ' + vipnametoadd2 + ' 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.', msguser, appNoticeColor); } else { cb.sendNotice(botName + msguser + ' has added ' + vipnametoadd2 + ' 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(botName + ' Congratulations! You have been added to the VIP list!', vipnametoadd2, appNoticeColor); } } } else { cb.sendNotice(botName + ' You did not specify the username you want to add to the Fembot VIP list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/rmvvip': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { if (msgarray[1]) { let vipnametormv = msgarray[1].toLowerCase(); if (vipnametormv.charAt(0) == '@') { vipnametormv = vipnametormv.substring(1); } if (cbjs.arrayContains(VIPListArray,vipnametormv)) { addRmvVIP(vipnametormv,'r'); if (msguser == BC) { cb.sendNotice(botName + ' You have removed ' + vipnametormv + ' 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.', msguser, appNoticeColor); } else { cb.sendNotice('Fembot ' + msguser + ' has removed ' + vipnametormv + ' 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(botName + vipnametormv + ' is not on the VIP list.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + ' You did not specify what username you want to remove from the VIP list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/viplist': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { cb.sendNotice('Users currently on the Fembot VIP List: ' + VIPListArray.length + '\n' + (VIPListArray.length > 0 == true ? cbjs.arrayJoin(VIPListArray, ', ') : 'No users.') + '\nEnd of List', msguser, 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', msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //******** External Fan Club Commands *********** case '/addfan': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { let addfancmdval = rawmsg.substring(8).trim(); if (addfancmdval != null) { let addfancmdvalsplit = addfancmdval.split(listRegExp); if (addfancmdvalsplit.length > 1) { let addfannotice = 'Adding multiple users to ' + EFCname + '.'; addfannotice += '\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 (let addfanidx = 0; addfanidx < addfancmdvalsplit.length; addfanidx++) { if (addfancmdvalsplit[addfanidx] != '') { let addfannametoadd = addfancmdvalsplit[addfanidx].toLowerCase(); if (addfannametoadd.charAt(0) == '@') { addfannametoadd = addfannametoadd.substring(1); } if (!cbjs.arrayContains(extFanListArray, addfannametoadd)) { addRmvExtFan(addfannametoadd,'a'); addfannotice += '\nAdded ' + addfannametoadd + ' to ' + EFCname + '.'; cb.sendNotice(msguser + ' has added you to ' + EFCname + '.', addfannametoadd, appNoticeColor); } else { cb.sendNotice(addfannametoadd + ' is already on the list. Skipping.', msguser); } } } addfannotice += '\nAll users were added and notified.'; if (msguser == BC) { cb.sendNotice(addfannotice, msguser, appNoticeColor); cb.sendNotice(msguser + ' has added multiple users to ' + EFCname + '.\n' + 'Users added: ' + cbjs.arrayJoin(addfancmdvalsplit, ', '), BC, appNoticeColor, '', 'normal', 'red'); } else { cb.sendNotice(addfannotice, BC, appNoticeColor); } } else { let addfannametoadd2 = msgarray[1].toLowerCase(); if (addfannametoadd2.charAt(0) == '@') { addfannametoadd2 = addfannametoadd2.substring(1); } if (cbjs.arrayContains(extFanListArray,addfannametoadd2)) { cb.sendNotice(botName + addfannametoadd2 + ' is already in ' + EFCname + '.', msguser, appNoticeColor); } else { addRmvExtFan(addfannametoadd2,'a'); if (msguser == BC) { cb.sendNotice(botName + ' You have added ' + addfannametoadd2 + ' 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.', msguser, appNoticeColor); } else { cb.sendNotice(botName + msguser + ' has added ' + addfannametoadd2 + ' 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(botName + ' Congratulations! You have been added to the ' + EFCname, addfannametoadd2, appNoticeColor); } } } else { cb.sendNotice(botName + ' You did not specify the username you want to add to ' + EFCname + '.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/addfan2': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { let af2cmdval = rawmsg.substring(9).trim(); if (af2cmdval != null) { let af2cmdvalsplit = af2cmdval.split(listRegExp); if (af2cmdvalsplit.length > 1) { let af2addnotice = 'Adding multiple users to ' + EFCname2 + '.'; af2addnotice += '\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 (let af2idx = 0; af2idx < af2cmdvalsplit.length; af2idx++) { if (af2cmdvalsplit[af2idx] != '') { let af2nametoadd = af2cmdvalsplit[af2idx].toLowerCase(); if (af2nametoadd.charAt(0) == '@') { af2nametoadd = af2nametoadd.substring(1); } if (!cbjs.arrayContains(extFanList2Array,af2nametoadd)) { addRmvExtFan2(af2nametoadd,'a'); af2addnotice += '\nAdded ' + af2nametoadd + ' to ' + EFCname2 + '.'; cb.sendNotice(msguser + ' has added you to ' + EFCname2 + '.', af2nametoadd, appNoticeColor); } else { cb.sendNotice(af2nametoadd + ' is already on the list. Skipping.', msguser); } } } af2addnotice += '\nAll users were added and notified.'; cb.sendNotice(af2addnotice, msguser, appNoticeColor); cb.sendNotice(msguser + ' has added multiple users to ' + EFCname2 + '.\n' + 'Users added: ' + cbjs.arrayJoin(af2cmdvalsplit, ', '), BC, appNoticeColor, '', 'normal', 'red'); } else { let af2nametoadd2 = msgarray[1].toLowerCase(); if (af2nametoadd2.charAt(0) == '@') { af2nametoadd2 = af2nametoadd2.substring(1); } if (cbjs.arrayContains(extFanList2Array,af2nametoadd2)) { cb.sendNotice(botName + af2nametoadd2 + ' is already in ' + EFCname2 + '.', msguser, appNoticeColor); } else { addRmvExtFan2(af2nametoadd2,'a'); cb.sendNotice(botName + ' You have added ' + af2nametoadd2 + ' 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.', msguser, appNoticeColor); cb.sendNotice(botName + ' Congratulations! You have been added to ' + EFCname2 + '!', af2nametoadd2, appNoticeColor); } } } else { cb.sendNotice(botName + ' You did not specify the username you want to add to the External Fan Club 2 list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/rmvfan': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { if (msgarray[1]) { let fannametormv = msgarray[1].toLowerCase(); if (fannametormv.charAt(0) == '@') { fannametormv = fannametormv.substring(1); } if (cbjs.arrayContains(extFanListArray,fannametormv)) { addRmvExtFan(fannametormv,'r'); cb.sendNotice(botName + ' You have removed ' + fannametormv + ' 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.', msguser, appNoticeColor); } else { cb.sendNotice(botName + fannametormv + ' is not on the External Fan Club 1 list.', msguser, appNoticeColor); } } else { cb.sendNotice('You did not specify what username you want to remove from the Fembot External Fan Club 1 list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/rmvfan2': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { if (msgarray[1]) { let fannametormv2 = msgarray[1].toLowerCase(); if (fannametormv2.charAt(0) == '@') { fannametormv2 = fannametormv2.substring(1); } if (cbjs.arrayContains(extFanList2Array,fannametormv2)) { addRmvExtFan2(fannametormv2,'r'); cb.sendNotice(botName + ' You have removed ' + fannametormv2 + ' 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.', msguser, appNoticeColor); } else { cb.sendNotice(botName + fannametormv2 + ' is not on the External Fan Club 2 list.', msguser, appNoticeColor); } } else { cb.sendNotice('You did not specify what username you want to remove from the Fembot External Fan Club 2 list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/fanlist': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { 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', msguser, 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', msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/fanlist2': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { 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', msguser, 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', msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //******** Moderator List Commands *********** case '/addmod': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { let addmodcmdval = rawmsg.substring(8).trim(); if (addmodcmdval != null) { let addmodcmdvalsplit = addmodcmdval.split(listRegExp); if (addmodcmdvalsplit.length > 1) { let addmodnotice = 'Adding multiple users to the Fembot Moderator list.'; addmodnotice += '\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 (let addmodidx = 0; addmodidx < addmodcmdvalsplit.length; addmodidx++) { if (addmodcmdvalsplit[addmodidx] != '') { let addmodnametoadd = addmodcmdvalsplit[addmodidx].toLowerCase(); if (addmodnametoadd.charAt(0) == '@') { addmodnametoadd = addmodnametoadd.substring(1); } if (!cbjs.arrayContains(moderatorList.name, addmodnametoadd)) { populateModeratorArray(addmodnametoadd,'botmod','a'); addmodnotice += '\nAdded ' + addmodnametoadd + ' to the Fembot Moderator list.'; cb.sendNotice(botName + msguser + ' has added you to the Fembot moderator list.', addmodnametoadd, appNoticeColor); } else { addmodnotice += '\n' + addmodnametoadd + ' is already on the Fembot moderator list. Skipping.'; } } } addmodnotice += '\nAll users were added and notified.'; cb.sendNotice(addmodnotice, msguser, appNoticeColor); cb.sendNotice(botName + msguser + ' has added multiple users to the Fembot moderator list.\n' + 'Users added: ' + cbjs.arrayJoin(addmodcmdvalsplit, ', '), BC, appNoticeColor, '', 'normal', 'red'); } else { let addmodnametoadd2 = msgarray[1].toLowerCase(); if (addmodnametoadd2.charAt(0) == '@') { addmodnametoadd2 = addmodnametoadd2.substring(1); } if (!cbjs.arrayContains(moderatorList.name,addmodnametoadd2)) { populateModeratorArray(addmodnametoadd2,'botmod','a'); cb.sendNotice(botName + 'You have added ' + addmodnametoadd2 + ' to the Fembot moderator list.', msguser, appNoticeColor); cb.sendNotice(botName + '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.', msguser, appNoticeColor); cb.sendNotice(botName + msguser + ' 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.', addmodnametoadd2, appNoticeColor); } else { cb.sendNotice(botName + addmodnametoadd2 + ' is already on the Fembot moderator list.', msguser, appNoticeColor); } } } else { cb.sendNotice(botName + ' You did not specify the username you want to add to the Fembot moderator list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/rmvmod': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { if (msgarray[1]) { let modnametormv = msgarray[1].toLowerCase(); if (modnametormv.charAt(0) == '@') { modnametormv = modnametormv.substring(1); } if (cbjs.arrayContains(moderatorList.name,modnametormv)) { let rmvmodidx = moderatorList.name.indexOf(modnametormv); if (moderatorList.type[rmvmodidx] == 'botmod') { populateModeratorArray(modnametormv,'botmod','r'); cb.sendNotice(botName + 'You have removed ' + modnametormv + ' as a Bot Mod from the Fembot Moderator list.', msguser, appNoticeColor); } else if (moderatorList.type[rmvmodidx] == 'cbmod') { populateModeratorArray(modnametormv,'cbmod','r'); cb.sendNotice(botName + 'You have removed ' + modnametormv + ' 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.', msguser, appNoticeColor); } else { cb.sendNotice(botName + 'You cannot remove ' + modnametormv + ' from the Fembot Moderator list, they are the broadcaster or an unknown mod type.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + modnametormv + ' is not in the Fembot moderator list.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'A parameter is required for this command to specify the user to remove from the Fembot Moderator list, such as "/rmvmod username".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/modlist': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let mlmessage = 'Users currently on the Fembot Moderator List: '; if (moderatorList.name.length > 0) { for (let mlstidx = 0; mlstidx < moderatorList.name.length; mlstidx++) { mlmessage += '\n' + (mlstidx+1) + '. ' + moderatorList.name[mlstidx] + ' (' + moderatorList.type[mlstidx] + ')'; } } else { mlmessage += '\nNo moderators currently assigned.'; } mlmessage += '\nEnd of List'; cb.sendNotice(mlmessage, msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //******** Blocked Word List Commands *********** case '/addword': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc ) { let addwordcmdval = rawmsg.substring(9).trim(); if (addwordcmdval != null) { let addwcmdvalsplit = addwordcmdval.split(listRegExp); if (addwcmdvalsplit.length > 1) { cb.sendNotice('Adding multiple words to the Public Blocked Word list.', msguser, appNoticeColor); for (let addwidx = 0; addwidx < addwcmdvalsplit.length; addwidx++) { if (addwcmdvalsplit[addwidx]) { let addwcmdvalmult = addwcmdvalsplit[addwidx]; if (checkASCII(addwcmdvalmult)) { addwcmdvalmult = addwcmdvalmult.toLowerCase(); } if (!cbjs.arrayContains(wordListArrayPub,addwcmdvalmult)) { wordListArrayPub.push(addwcmdvalmult); cb.sendNotice('Added ' + addwcmdvalmult + ' to the list.', msguser); } else { cb.sendNotice(addwcmdvalmult + ' is already on the list. Skipping.', msguser); } } } cb.sendNotice('All words were added.', msguser, appNoticeColor) cb.sendNotice(msguser + ' has added multiple words to the Blocked Word list.\n' + 'Words added: ' + cbjs.arrayJoin(addwcmdvalsplit, ', '), BC, appNoticeColor, '', 'normal', 'red'); } else { let addwcmdvalsingle = msgarray[1]; if (checkASCII(addwcmdvalsingle)) { addwcmdvalsingle = addwcmdvalsingle.toLowerCase(); } addRmvWord(addwcmdvalsingle, msguser, 'a'); } } else { cb.sendNotice(botName + ' You did not specify what word(s) you want to add to the Public Blocked Word list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/rmvword': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { let rmvwordval = msgarray[1]; if (checkASCII(rmvwordval)) { rmvwordval = rmvwordval.toLowerCase(); } addRmvWord(rmvwordval,msguser,'r'); } else { cb.sendNotice(botName + ' You did not specify what word you want to remove from the Public Blocked Word list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/wordlist': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let wordlistmsg = 'Words currently on the Public Blocked Word List:\n'; wordlistmsg += 'Note that words may appear in lower case even if entered in upper case, all words that contain only ASCII characters are converted for comparison.\n'; wordlistmsg += (wordListArrayPub.length > 0 == true ? cbjs.arrayJoin(wordListArrayPub, ', ') : 'No words entered in Public Blocked Word list.'); cb.sendNotice(wordlistmsg, msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/botblock': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let botwordlistmsg = 'Words automatically added to the Public word list by the Fembot (you do not have to include these in your list):\n'; botwordlistmsg += 'Note that words/phrases/links may appear in lower case even if entered in upper case, all words that contain only ASCII characters are converted for comparison.\n'; botwordlistmsg += cbjs.arrayJoin(botBlockList, ', '); cb.sendNotice(botwordlistmsg, msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/wordlistprv': { recognizedcmd = true; if (msgisbc) { let prvwordlistmsg = 'Words currently on the Private Blocked Word List:\n'; prvwordlistmsg += 'Note that words/phrases/links may appear in lower case even if entered in upper case, all words that contain only ASCII characters are converted for comparison.\n'; prvwordlistmsg += (wordListArray.length > 0 == true ? cbjs.arrayJoin(wordListArray, ', ') : 'No words entered in Private Blocked Word list.'); cb.sendNotice(prvwordlistmsg, msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBC, msguser, appNoticeColor); } break; } case '/qrel': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { let qreluser = msgarray[1].toLowerCase(); if (qreluser.charAt(0) == '@') { qreluser = qreluser.substring(1); } if (cbjs.arrayContains(quarantineArray,qreluser)) { cbjs.arrayRemove(quarantineArray,qreluser); cb.sendNotice(botName + 'User ' + qreluser + ' removed from the quarantine list.', msguser, appNoticeColor); cb.sendNotice(botName + 'You have been released from the quarantine list.', qreluser, appNoticeColor); } else { cb.sendNotice(botName + 'User ' + qreluser + ' is not in the quarantine list.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'No parameter specified for the user to release from quarantine.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/qsil': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { let qsiluser = msgarray[1].toLowerCase(); if (qsiluser.charAt(0) == '@') { qsiluser = qsiluser.substring(1); } if (cbjs.arrayContains(quarantineArray,qsiluser)) { cbjs.arrayRemove(quarantineArray,qsiluser); if (!cbjs.arrayContains(silenceListArray,qsiluser)) { silenceListArray.push(qsiluser); cb.sendNotice(botName + 'User ' + qsiluser + ' moved from the quarantine list to the silence list.', msguser, appNoticeColor); } else { cb.sendNotice(botName + 'User ' + qsiluser + ' already in the silence list, and has been removed from the quarantine list.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'User ' + qsiluser + ' is not in the quarantine list.', msguser, appNoticeColor); } } else { if (quarantineArray.length > 0) { for (let qsilidx = (quarantineArray.length-1); qsilidx >= 0; qsilidx--) { let quserrmv = quarantineArray[qsilidx]; if (!cbjs.arrayContains(silenceListArray,quserrmv)) { silenceListArray.push(quserrmv); } cbjs.arrayRemove(quarantineArray,quarantineArray[qsilidx]); } cb.sendNotice(botName + 'All quarantined users have been moved to the Silence List.', msguser, appNoticeColor); } else { cb.sendNotice(botName + 'There are no users in the quarantine list.', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/qlist': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let qlistmsg = 'Users currently on the Quarantine List:\n'; qlistmsg += (quarantineArray.length > 0 == true ? '@' + cbjs.arrayJoin(quarantineArray, ', @') : 'No users currently in the quarantine list.'); qlistmsg += '\nTo remove a user from the list, use the command /qrel'; qlistmsg += '\nTo move a user from the quarantine list to the silence list, use the command /qsil. If you do not specify a user, all users will be moved.'; cb.sendNotice(qlistmsg, msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //******** Nice List Commands *********** case '/addnice': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc ) { let addncmdval = rawmsg.substring(9).trim(); if (addncmdval != null) { let addncmdvalsplit = addncmdval.split(listRegExp); if (addncmdvalsplit.length > 1) { cb.sendNotice('Adding multiple users to the nice list.', msguser, appNoticeColor); for (let addnidx = 0; addnidx < addncmdvalsplit.length; addnidx++) { if (addncmdvalsplit[addnidx]) { let niceentrytoadd = addncmdvalsplit[addnidx].toLowerCase(); if (niceentrytoadd.charAt(0) == '@') { niceentrytoadd = niceentrytoadd.substring(1); } if (validateUserID(niceentrytoadd,'Nice List',msguser,false)) { if (!cbjs.arrayContains(niceListArray, niceentrytoadd)) { populateNiceListArray(niceentrytoadd); cb.sendNotice('Added ' + niceentrytoadd + ' to the list.', msguser); cb.sendNotice(msguser + ' has added you to the nice list.', niceentrytoadd, appNoticeColor); } else { cb.sendNotice(niceentrytoadd + ' is already on the list. Skipping.', msguser); } } } } cb.sendNotice('All users were added and notified.', msguser, appNoticeColor); cb.sendNotice(msguser + ' has added multiple users to the nice list.\n' + 'Users added: ' + cbjs.arrayJoin(addncmdvalsplit, ', '), BC, appNoticeColor, '', 'normal', 'red'); } else { let nicelisttoadd = msgarray[1].toLowerCase(); if (nicelisttoadd.charAt(0) == '@') { nicelisttoadd = nicelisttoadd.substring(1); } if (validateUserID(nicelisttoadd,'Nice List',msguser,false)) { addRmvNice(nicelisttoadd,msguser,'a'); } } } else { cb.sendNotice(botName + ' You did not specify the username you want to add to the nice list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/rmvnice': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if (msgarray[1]) { let nicelisttormv = msgarray[1].toLowerCase(); if (nicelisttormv.charAt(0) == '@') { nicelisttormv = nicelisttormv.substring(1); } addRmvNice(nicelisttormv,msguser,'r'); } else { cb.sendNotice(botName + ' You did not specify the username you want to remove from the nice list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/nicelist': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { cb.sendNotice('Users currently in the Fembot Nice List: ' + niceListArray.length + '\n' + (niceListArray.length > 0 == true ? cbjs.arrayJoin(niceListArray, ', ') : 'No users.') + '\nEnd of List', msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //******** Chat Notice Commands *********** case '/cn': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let cnnoticemsg = rawmsg.substring(4).trim(); if (cnnoticemsg) { sendPublicNotice(cnnoticemsg, msguser, ''); } else { cb.sendNotice(botName + 'You cannot send a blank message. The correct syntax for this command is "/cn message text".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/cnh': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let cnhnoticemsg = rawmsg.substring(5).trim(); if (cnhnoticemsg) { sendPublicNotice(cnhnoticemsg, msguser, 'h'); } else { cb.sendNotice(botName + 'You cannot send a blank message. The correct syntax for this command is "/cnh message text".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/cnd': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let cndnoticemsg = rawmsg.substring(5).trim(); if (cndnoticemsg) { sendPublicNotice(cndnoticemsg, msguser, 'div'); } else { cb.sendNotice(botName + 'You cannot send a blank message.\n The correct syntax for this command is "/cnd message text".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/cndh': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let cndhnoticemsg = rawmsg.substring(6).trim(); if (cndhnoticemsg) { sendPublicNotice(cndhnoticemsg, msguser, 'divh'); } else { cb.sendNotice(botName + 'You cannot send a blank message. The correct syntax for this command is "/cndh message text".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/ctn': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg1 || msgisbc) { let ctnnoticemsg = rawmsg.substring(5).trim(); if (ctnnoticemsg) { sendPublicNotice(ctnnoticemsg, msguser, ''); } else { cb.sendNotice(botName + 'You cannot send a blank message. The correct syntax for this command is "/ctn message text".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/ctnh': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg1 || msgisbc) { let ctnhnoticemsg = rawmsg.substring(6).trim(); if (ctnhnoticemsg) { sendPublicNotice(ctnhnoticemsg, msguser, 'h'); } else { cb.sendNotice(botName + 'You cannot send a blank message. The correct syntax for this command is "/ctnh message text".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/ctnd': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg1 || msgisbc) { let ctndnoticemsg = rawmsg.substring(6).trim(); if (ctndnoticemsg) { sendPublicNotice(ctndnoticemsg, msguser, 'div'); } else { cb.sendNotice(botName + 'You cannot send a blank message. The correct syntax for this command is "/ctnd message text".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/ctndh': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg1 || msgisbc) { let ctndhnoticemsg = rawmsg.substring(7).trim(); if (ctndhnoticemsg) { sendPublicNotice(ctndhnoticemsg, msguser, "divh"); } else { cb.sendNotice(botName + 'You cannot send a blank message. The correct syntax for this command is "/ctndh message text".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } //******** Private Message Commands *********** case '/bc': { recognizedcmd = true; if (msgisbc) { cb.sendNotice(botName + ' Broadcasters cannot send messages to themselves.', msguser, appNoticeColor); } else { if (ismodlvlmsg1 || ((msgisfan || msgisvip || msgisextfan1 || msgisextfan2) && (cb.settings.enablePMs == 'Yes'))) { let bcprivatemsg = rawmsg.substring(4).trim(); if (bcprivatemsg) { sendPrivateNotice(bcprivatemsg, msguser, 'bc', 'default'); } else { cb.sendNotice(botName + ' You cannot send a blank message. The correct syntax for this command is "/bc message text".', msguser, appNoticeColor); } } else { cb.sendNotice(botName + ' That command has not been enabled by the broadcaster for your user group (setting 4H).', msguser, appNoticeColor); } } break; } case '/tm': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let tmprivatemsg = rawmsg.substring(4).trim(); if (tmprivatemsg) { sendPrivateNotice(tmprivatemsg, msguser, 'tm'); } else { cb.sendNotice(botName + ' You cannot send a blank message. The correct syntax for this command is "/tm message text".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/tbm': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let tbmprivatemsg = rawmsg.substring(5).trim(); if (tbmprivatemsg) { sendPrivateNotice(tbmprivatemsg, msguser, 'tbm', 'default'); } else { cb.sendNotice(botName + ' You cannot send a blank message. The correct syntax for this command is "/tbm message text".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/pm': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc || ((msgisfan || msgisvip || msgisextfan1 || msgisextfan2) && (cb.settings.enablePMs == 'Yes'))) { if (msgarray[1]) { let sendpmtouser = msgarray[1].toLowerCase(); if (sendpmtouser.charAt(0) == '@') { sendpmtouser = sendpmtouser.substring(1); } var checkSpecial = /[!@#$%^&*()+\-=\[\]{};':"\\|,.<>\/?]+/; if (sendpmtouser.length < 3) { cb.sendNotice(botName + ' Username (first parameter) in PM command is too short (CB usernames must be 3 characters or more), message not sent.', msguser, appNoticeColor); } else if (checkSpecial.test(sendpmtouser)) { cb.sendNotice(botName + ' Username (first parameter) in PM command is invalid, it uses special characters other than "_", message not sent.', msguser, appNoticeColor); } else { let pmstring = ''; for (let pmidx = 2; pmidx < msgarray.length; pmidx++) { if (pmidx == 2) { pmstring = msgarray[pmidx]; } else { pmstring += ' ' + msgarray[pmidx]; } } if (pmstring) { sendPrivateNotice(pmstring,msguser,'pm',sendpmtouser); } else { cb.sendNotice(botName + 'You cannot send a blank message. The correct syntax for this command is "/pm username message text".', msguser, appNoticeColor); } } } else { cb.sendNotice(botName + 'A username must be entered as the first parameter of the PM message.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'That command has not been enabled by the broadcaster for your user group (setting 4H).', msguser, appNoticeColor); } break; } case '/reply': { recognizedcmd = true; if (cb.settings.enablePMs == 'Yes') { sendReply(msgarray, msguser); } else { cb.sendNotice(botName + 'That command has not been enabled by the broadcaster.', msguser, appNoticeColor); } break; } //******** Tip Leader Commands *********** case '/leaders': { recognizedcmd = true; if (leaderboardToggle) { if (msgarray[1]) { var lbparm = msgarray[1].toLowerCase(); if (lbparm == 'all') { if (ismodlvlmsg1 || msgisbc) { showLeaderBoard('all',''); } else { cb.sendNotice(botName + ' The "all" parameter can only be used by the broadcaster or moderators.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + ' 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', msguser, appNoticeColor); showLeaderBoard('me',msguser); } } else { showLeaderBoard('me',msguser); } } else { cb.sendNotice(botName + ' The leaderboard is not enabled.', msguser, appNoticeColor); } break; } case '/tippers': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let numtippers = parseInt(msgarray[1]) if (isNaN(numtippers)) { cb.sendNotice('The value entered for the number of tippers from the leaderboard is not numeric, defaulting to 20.', msguser, appNoticeColor); numtippers = 20; } else if (numtippers > 100) { cb.sendNotice(botName + ' The value entered for the number of tippers from the leaderboard cannot exceed 100, defaulting to 100.', msguser, appNoticeColor); numtippers = 100; } else if (numtippers <= 0) { cb.sendNotice(botName + ' The value entered for the number of tippers from the leaderboard must be greater than zero, defaulting to 20.', msguser, appNoticeColor); numtippers = 20; } if (msgarray[2] == 'all' || msgarray[2] == 'tbm' || msgarray[2] == 'mods' || msgarray[2] == 'bc' || msgarray[2] == '' || msgarray[2] == null) { sortTippers(); switch (msgarray[2]) { case 'all': showTippers(msguser,'',numtippers,'all',''); break; case 'tbm': showTippers(msguser,'',numtippers,'tbm',BC); showTippers(msguser,'red',numtippers,'tbm',''); break; case 'mods': showTippers(msguser,'red',numtippers,'mods',''); if (msguser == BC) { showTippers(msguser,'',numtippers,'mods',msguser); } break; case 'bc': if (msguser != BC) { showTippers(msguser,'',numtippers,'bc',BC); } showTippers(msguser,'',numtippers,'me',msguser); break; default: showTippers(msguser,'',numtippers,'me',msguser); break; } } else { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/useleaderboard': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { setLeaderToggle(msgarray[1],msguser,true); } else { cb.sendNotice(noticeOnlyBCMod1,msguser,appNoticeColor); } break; } case '/usetipcount': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { setTipCountToggle(msgarray[1],msguser,true); } else { cb.sendNotice(noticeOnlyBCMod1,msguser,appNoticeColor); } break; } //********* Room Rules Commands case '/userules': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { let useruleparmnot = msgarray[1].toLowerCase(); if (useruleparmnot == 'on' || useruleparmnot == 'off') { setRoomRulesNoticeToggle(useruleparmnot,msguser,true); } else { cb.sendNotice(botName + ' You did not enter a valid parameter for /userules, valid options are "on" or "off".', msguser, appNoticeColor); } } else { cb.sendNotice(botName + ' You did not enter a parameter for /userules, valid options are "on" or "off".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/userulesenter': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { let useruleparm = msgarray[1].toLowerCase(); if (useruleparm == 'on' || useruleparm == 'off') { setRoomRulesEnterToggle(useruleparm,msguser,true); } else { cb.sendNotice(botName + ' You did not enter a valid parameter for /userulesenter, valid options are "on" or "off".', msguser, appNoticeColor); } } else { cb.sendNotice(botName + ' You did not enter a parameter for /userulesenter, valid options are "on" or "off".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } //********* Notifier Commands case '/usenotifier': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1].toLowerCase() == 'on' || msgarray[1].toLowerCase() == 'off') { setNotifierToggle(msgarray[1],msguser,true); } else { cb.sendNotice(botName + ' You did not enter a valid parameter for /usenotifier, valid options are "on" or "off".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/chgmsg1': case '/chgmsg2': case '/chgmsg3': case '/chgmsg4': case '/chgmsg5': case '/chgmsg6': case '/chgmsg7': case '/chgmsg8': case '/chgmsg9': case '/chgmsg10': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { let chgmsgnum = parseInt(rawmsg.substring(7,9)); let chgmsgidx = chgmsgnum-1; if (!msgarray[1]) { cb.sendNotice(botName + ' 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.',msguser,appNoticeColor) } else { notifierArray[chgmsgidx] = rawmsg.substring(9).trim(); cb.sendNotice(botName + ' You have updated the message for Notifier entry ' + chgmsgnum + ' to "' + notifierArray[chgmsgidx] + '".', msguser, appNoticeColor); if (msguser != BC) { cb.sendNotice(botName + msguser + ' has updated the message for Notifier entry ' + chgmsgnum + ' to "' + notifierArray[chgmsgidx] + '".', BC, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/dspmsg1': case '/dspmsg2': case '/dspmsg3': case '/dspmsg4': case '/dspmsg5': case '/dspmsg6': case '/dspmsg7': case '/dspmsg8': case '/dspmsg9': case '/dspmsg10': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let dspmsgnum = parseInt(rawmsg.substring(7,9)); let dspmsgindex = dspmsgnum-1; if (msgarray[1] == 'all') { if (!notifierArray[dspmsgindex]) { cb.sendNotice('Notifier ' + dspmsgnum + ' Message is blank.', msguser, appNoticeColor); } else { cb.sendNotice('\u25ba ' + notifierArray[dspmsgindex], '', noticeBgColor, noticeTextColor, boldTextLiteral); } } else { if (!notifierArray[dspmsgindex]) { cb.sendNotice('Notifier ' + dspmsgnum + ' Message is blank.', msguser, appNoticeColor); } else { cb.sendNotice('Notifier ' + dspmsgnum + ': ' + notifierArray[dspmsgindex], msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/dspallmsg': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let dspallmsgstr = ''; if (notifierArray.length > 0) { dspallmsgstr = '***** Notifier Message Listing *****'; for (let dspallmsgidx = 0; dspallmsgidx < 10; dspallmsgidx++) { if (notifierArray[dspallmsgidx]) { dspallmsgstr += '\nNotifier ' + (dspallmsgidx+1) + ': ' + notifierArray[dspallmsgidx]; } else { dspallmsgstr += '\nNotifier ' + (dspallmsgidx+1) + ': Message is blank.'; } } } else { dspallmsgstr = 'No notifiers have been configured or added with command'; } cb.sendNotice(dspallmsgstr, msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1,msguser,appNoticeColor); } break; } //********* Viewer Notes Commands case '/noteslist': case '/notelist': { recognizedcmd = true; if (msgisbc) { let displaymessage = 'Viewer Notes: \n'; for (let 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, msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBC, msguser, appNoticeColor); } break; } case '/shownote': { recognizedcmd = true; if (msgisbc) { if (msgarray[1]) { let shownoteuser = msgarray[1].toLowerCase(); if (cbjs.arrayContains(viewerNotesArray.username,shownoteuser)) { let shownoteindex = viewerNotesArray.username.indexOf(shownoteuser); cb.sendNotice('Viewer Notes for ' + shownoteuser + ' :\n' + viewerNotesArray.notes[shownoteindex], msguser, appNoticeColor); } else { cb.sendNotice(botName + ' There is no entry for ' + shownoteuser + ' in the Notes list. You can add one with the command /addnote, or view the full list with the command /notelist.',msguser,appNoticeColor); } } else { cb.sendNotice(botName + ' No username was specified to display notes for. Command should be /shownote username.',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBC, msguser, appNoticeColor); } break; } case '/addnote': { recognizedcmd = true; if (msgisbc) { if (!msgarray[1]) { cb.sendNotice(botName + ' 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).', msguser, appNoticeColor); return; } if (!msgarray[2]) { cb.sendNotice(botName + ' 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).', msguser, appNoticeColor); return; } let label; for (let j = 2; j < msgarray.length; j++) { if (j == 2) { label = msgarray[j]; } else { label += ' ' + msgarray[j]; } } let addnoteuser = msgarray[1].toLowerCase(); if (addnoteuser.charAt(0) == '@') { addnoteuser = addnoteuser.substring(1); } if (cbjs.arrayContains(viewerNotesArray.username, addnoteuser)) { let addnoteindex = viewerNotesArray.username.indexOf(addnoteuser); viewerNotesArray.notes[addnoteindex] += ' ' + label; viewerNotesArray.displayed[addnoteindex] = false; viewerNotesArray.addinshow[addnoteindex] = true; cb.sendNotice(botName + ' Your note was added to the existing entry for user "' + addnoteuser + '". 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.', msguser, appNoticeColor); } else { viewerNotesArray.username.push(addnoteuser); viewerNotesArray.notes.push(label); viewerNotesArray.displayed.push(false); viewerNotesArray.addinshow.push(true); cb.sendNotice(botName + ' Your note was added as a new entry for user "' + addnoteuser + '". 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBC, msguser, appNoticeColor); } break; } //********* Change Subject Command case '/chgsubject': case '/newsubject': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let chgsubjectcmd = rawmsg.substring(12).trim() setRoomSubject(chgsubjectcmd,msguser); } else { cb.sendNotice(noticeOnlyBCMod1,msguser,appNoticeColor); } break; } case '/subject': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg1 || msgisbc) { let chgsubjectcmd2 = rawmsg.substring(9).trim() setRoomSubject(chgsubjectcmd2,msguser); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } //********* Ticket Show Support Commands case '/prepticket': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { prepTicketShow(msguser); cb.sendNotice('Fembot: Ticket show prep has been completed according to settings in section 14 (if enabled).', msguser, 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").', msguser, appNoticeColor); } } else { prepTicketShow(msguser); cb.sendNotice('Fembot Ticket show prep for the UltraApp has been completed.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/chgapp': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { if (ticketShowType == 'Separate Ticket App' && msgarray[1].toLowerCase() == 'ticket') { prepTicketShow(msguser); cb.sendNotice('Fembot: Ticket show prep for the UltraApp Ticket Show has been completed according to settings in 14B-14D of the Fembot (if enabled).', msguser, appNoticeColor); } } } break; } case '/backuplist': case '/dspbackup': { recognizedcmd = true; if (ticketShowType != 'Fembot Ticket Show') { if (ismodlvlmsg2 || msgisbc) { if (backupListArray.length > 0) { let lengthcheckstring = cbjs.arrayJoin(backupListArray, ', '); let backupmsg = ''; 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.'; let bucurrentlength = 5; let buchunknumber = 1; backupmsg += '\nChunk #1 \n/add '; for (let bulistindex = 0; bulistindex < backupListArray.length; bulistindex++) { if (bucurrentlength + backupListArray[bulistindex].length < 1020) { if (bulistindex == 0) { backupmsg += backupListArray[bulistindex]; } else { backupmsg += ', ' + backupListArray[bulistindex]; bucurrentlength += 2; } bucurrentlength += backupListArray[bulistindex].length; } else { bucurrentlength = 5; buchunknumber++; backupmsg += '\nChunk #' + buchunknumber + '\n/add '; backupmsg += backupListArray[bulistindex]; bucurrentlength += backupListArray[bulistindex].length; } } } cb.sendNotice(backupmsg, msguser, appNoticeColor); } else { cb.sendNotice('There are no users in the backup list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup list is only used for separate Ticket Apps.', msguser, appNoticeColor); } break; } case '/backupfb': { recognizedcmd = true; if (ticketShowType != 'Fembot Ticket Show') { if (ismodlvlmsg2 || msgisbc) { let bu2cmdval = rawmsg.substring(10).trim(); if (bu2cmdval != null) { let bu2cmdvalsplit = bu2cmdval.split(listRegExp); if (bu2cmdvalsplit.length > 1) { cb.sendNotice('Backing up external ticket list in the Fembot.', msguser, appNoticeColor); for (let bufbidx = 0; bufbidx < bu2cmdvalsplit.length; bufbidx++) { if (bu2cmdvalsplit[bufbidx] != '') { if (!cbjs.arrayContains(backupListArray, bu2cmdvalsplit[bufbidx])) { backupListArray.push(bu2cmdvalsplit[bufbidx]); cb.sendNotice('Added ' + bu2cmdvalsplit[bufbidx] + ' to the backup ticket list.', msguser); } } } } else if (!cbjs.arrayContains(backupListArray, msgarray[1])) { backupListArray.push(msgarray[1]); } cb.sendNotice(msguser + ' has completed a backup of the current ticket list.', BC, appNoticeColor, '', 'normal', 'red'); cb.sendNotice('All users were added.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } else { cb.sendNotice(botName + ' Command is not valid for the Fembot Hidden Ticket Show, backup list is only used for separate Ticket Apps.', msguser, appNoticeColor); } break; } case '/expbackup': { recognizedcmd = true; if (ticketShowType != 'Fembot Ticket Show') { if (backupToggle) { if (ismodlvlmsg2 || msgisbc) { if (backupListArray.length > 0) { let lengthcheckstring = cbjs.arrayJoin(backupListArray, ', '); if (lengthcheckstring.length > 1020) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); } else { rawmsg = '/add ' + cbjs.arrayJoin(backupListArray, ', '); cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + ' No Backup Ticket List to add.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } } else { cb.sendNotice(botName + ' The Backup Ticket List is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup list is only used for separate Ticket Apps.', msguser, appNoticeColor); } break; } case '/addlbtop': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use the /add command while a private show is running.', msguser,appNoticeColor); } else { if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg1 && hiddenShowModsAdd)) { let numaddlb = parseInt(msgarray[1]); if (isNaN(numaddlb)) { cb.sendNotice('The value entered for the number of tippers from the leaderboard is not numeric, please try again.', msguser, appNoticeColor); break; } if (numaddlb <= 0) { numaddlb = parseInt(cb.settings.numberFromLB); } if (numaddlb <= 0) { numaddlb = 3; cb.sendNotice('No setting defined for number of entries to add, defaulting to top 3.', msguser, appNoticeColor); } let addfrlbstring = ''; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { addfrlbstring = addFromLeaderboard('num',numaddlb,msguser); if (addfrlbstring) { cb.sendNotice('The top ' + numaddlb + ' tippers from the Leaderboard have been added to the Fembot Ticket Show.', msguser, appNoticeColor); } else { cb.sendNotice('No Leaderboard entries to add.', msguser, appNoticeColor); } } else { cb.sendNotice('Before using the "Add Leaderboard" function, the ticket show feature must first be enabled when using the Fembot Ticket Show.', msguser, appNoticeColor); } } else { addfrlbstring = addFromLeaderboard('num',numaddlb,msguser); if (addfrlbstring) { msg.m = '/add ' + addfrlbstring; cb.sendNotice('The top ' + numaddlb + ' 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).', msguser, appNoticeColor); } else { cb.sendNotice('No Leaderboard entries to add.', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod3A, msguser,appNoticeColor); } } break; } case '/addlbamt': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use the /addlbamt command while a private show is running.', msguser,appNoticeColor); } else { if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg1 && hiddenShowModsAdd)) { let numaddlbamt = parseInt(msgarray[1]); if (isNaN(numaddlbamt)) { cb.sendNotice('The value entered for the tip amount is not numeric, please try again.', msguser, appNoticeColor); break; } if (numaddlbamt <= 0) { numaddlbamt = parseInt(cb.settings.amountFromLB); } if (numaddlbamt <= 0) { numaddlbamt = 1000; cb.sendNotice('No setting defined for minimum tip amount to add, defaulting to 1000 tokens.', msguser, appNoticeColor); } let addfrlbstringamt = ''; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { addfrlbstringamt = addFromLeaderboard('amt',numaddlbamt,msguser); if (addfrlbstringamt) { cb.sendNotice('Users who have tipped more than ' + numaddlbamt + ' during this session have been added to the Fembot Ticket Show.', msguser, appNoticeColor); } else { cb.sendNotice('No qualifying tippers to add.', msguser, appNoticeColor); } } else { cb.sendNotice('Before using the "Add Leaderboard" function, the ticket show feature must first be enabled when using the Fembot Ticket Show.', msguser, appNoticeColor); } } else { addfrlbstringamt = addFromLeaderboard('amt',numaddlbamt,msguser); if (addfrlbstringamt) { msg.m = '/add ' + addfrlbstringamt; cb.sendNotice('Users who have tipped more than ' + numaddlbamt + ' 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).', msguser, appNoticeColor); } else { cb.sendNotice('No qualifying tippers to add.', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod3A, msguser, appNoticeColor); } } break; } case '/backupprice': case '/bup': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (ticketShowType != 'Fembot Ticket Show') { let bupnumprice = parseInt(msgarray[1]); if (isNaN(bupnumprice)) { cb.sendNotice(botName + 'The value entered for the backup ticket price is not numeric, please try again.', msguser, appNoticeColor); } else { setBackupTicketPrice(bupnumprice,msguser); if (!backupToggle) { setBackupToggle('on',msguser); cb.sendNotice(botName + 'The backup list was disabled, it has been automatically enabled by setting the backup price.', msguser, appNoticeColor); } } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup price is only used for separate Ticket Apps.', msguser, appNoticeColor); } } break; } case '/usebackup': { recognizedcmd = true; if (ticketShowType != 'Fembot Ticket Show') { if (ismodlvlmsg2 || msgisbc) { if (msgarray[1] != 'on' && msgarray[1] != 'off') { cb.sendNotice(botName + msgarray[1] + ' is not a valid parameter option for /usebackup, the parameter should be "on" or "off".', msguser, appNoticeColor); } else { setBackupToggle(msgarray[1],msguser,true) } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } } else { cb.sendNotice('Command is not valid for the Fembot Hidden Ticket Show, backup list is only used for separate Ticket Apps.', msguser, appNoticeColor); } break; } //********* Tip Menu Commands case '/tipmenu': { recognizedcmd = true; let sendmenunotice = false; let tipmenucmdsendto = ''; if (tipMenuToggle) { tipmenucmdsendto = msguser; 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' + tipMenuModDisplayText; cb.sendNotice(mainsndmodmsg, tipmenucmdsendto, tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } else if (msgisfan && 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' + tipMenuDisplayText; mainsndfanmsg += '\n** Displaying your Fan Club specific menu items:'; } mainsndfanmsg += '\n' + tipMenuCBFCDisplayText; cb.sendNotice(mainsndfanmsg, tipmenucmdsendto, tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } else if (msgisextfan1 && 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' + tipMenuDisplayText; mainsndefc1msg += '\nDisplaying your ' + EFCname + ' menu items:'; } mainsndefc1msg += '\n' + tipMenuEFC1DisplayText; cb.sendNotice(mainsndefc1msg, tipmenucmdsendto, tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } else if (msgisextfan2 && 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' + tipMenuDisplayText; mainsndefc2msg += '\nDisplaying ' + EFCname2 + ' menu items:'; } mainsndefc2msg += '\n' + tipMenuEFC2DisplayText; cb.sendNotice(mainsndefc2msg, tipmenucmdsendto, tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } else if (msgisvip && 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' + tipMenuVIPDisplayText; cb.sendNotice(mainsndvipmsg, tipmenucmdsendto, tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } else { if (ismodlvlmsg1 || msgisbc) { cb.sendNotice('Sent to ALL:\n' + tipMenuDisplayText, '', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } else { cb.sendNotice('Sent to YOU:\n' + tipMenuDisplayText, msguser, tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } 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!', '', tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } } sendmenunotice = true; } else if (tipMenu2Toggle) { if (ismodlvlmsg1 || msgisbc) { cb.sendNotice('Sent to ALL:\n' + tipMenu2DisplayText, tipmenucmdsendto, tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); } else { cb.sendNotice('Sent to YOU:\n' + tipMenu2DisplayText, msguser, tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); } 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!', '', tipMenu2BgColor1, tipMenu2TextColor1, boldTextLiteral); } sendmenunotice = true; } else { cb.sendNotice(botName + ' The Tip Menu has not been enabled.', msguser, appNoticeColor); } if (sendmenunotice && !msgisbc && !ismodlvlmsg1) { if (cb.settings.alertBCWhenReq == 'Broadcaster Only' || cb.settings.alertBCWhenReq == 'Broadcaster and Moderators') { cb.sendNotice(botName + ' The Tip menu was requested by ' + msguser + '.', BC, appNoticeColor, ''); } if (cb.settings.alertBCWhenReq == 'Moderators Only' || cb.settings.alertBCWhenReq == 'Broadcaster and Moderators') { cb.sendNotice(botName + ' The Tip menu was requested by ' + msguser + '.', BC, appNoticeColor, '', '', 'red'); } } break; } case '/tipmenumod': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if (tipMenuToggle) { if (modSpecificMenuItems) { var sndmodmsg = 'Sent to YOU:'; if (cb.settings.tipMenuModSalePct > 0) { sndmodmsg += '\n(Menu is discounted ' + cb.settings.tipMenuModSalePct + '%)'; } sndmodmsg += '\n' + tipMenuModDisplayText; cb.sendNotice(sndmodmsg, msguser, tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } else { cb.sendNotice('There is not a moderator discount available.', msguser, appNoticeColor); } } else { cb.sendNotice('The moderator specific menu is only valid for Tip Menu 1.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1,msguser,appNoticeColor); } break; } case '/tipmenuvip': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc || msgisvip) { if (tipMenuToggle) { if (vipSpecificMenuItems) { var sndvipmsg = 'Sent to YOU:'; if (cb.settings.tipMenuVIPSalePct > 0) { sndvipmsg += '\n(Menu is discounted ' + cb.settings.tipMenuVIPSalePct + '%)'; } sndvipmsg += '\n' + tipMenuVIPDisplayText; cb.sendNotice(sndvipmsg, msguser, tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } else { cb.sendNotice('There is not a VIP discount available.', msguser, appNoticeColor); } } else { cb.sendNotice('The VIP specific menu is only valid for Tip Menu 1.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1,msguser,appNoticeColor); } break; } case '/tipmenufan': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc || msgisfan) { if (tipMenuToggle) { 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' + tipMenuDisplayText; sndfanmsg += '\nDisplaying fan club specific menu items:'; } sndfanmsg += '\n' + tipMenuCBFCDisplayText; cb.sendNotice(sndfanmsg, msguser, tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } else { cb.sendNotice('There is not a CB Fanclub menu or discount available.', msguser, appNoticeColor); } } else { cb.sendNotice('The CB Fanclub specific menu is only valid for Tip Menu 1.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1,msguser,appNoticeColor); } break; } case '/tipmenufc1': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc || msgisextfan1) { if (tipMenuToggle) { 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' + tipMenuDisplayText; sndefc1msg += '\nDisplaying ' + EFCname + ' menu items:'; } sndefc1msg += '\n' + tipMenuEFC1DisplayText; cb.sendNotice(sndefc1msg, msguser, tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } else { cb.sendNotice('There is not a ' + EFCname + ' menu or discount available.', msguser, appNoticeColor); } } else { cb.sendNotice('The ' + EFCname + ' specific menu is only valid for Tip Menu 1.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1,msguser,appNoticeColor); } break; } case '/tipmenufc2': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc || msgisextfan2) { if (tipMenuToggle) { 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' + tipMenuDisplayText; sndefc2msg += '\nDisplaying ' + EFCname2 + ' menu items:'; } sndefc2msg += '\n' + tipMenuEFC2DisplayText; cb.sendNotice(sndefc2msg, msguser, tipMenuBgColor1, tipMenuTextColor1, boldTextLiteral); } else { cb.sendNotice('There is not a ' + EFCname2 + ' menu or discount available.', msguser, appNoticeColor); } } else { cb.sendNotice('The ' + EFCname2 + ' specific menu is only valid for Tip Menu 1.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1,msguser,appNoticeColor); } break; } case '/swapmenu': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (tipMenuToggle && !tipMenu2Toggle) { setTipMenuToggle('off',msguser) setTipMenu2Toggle('on',msguser) } else if (tipMenu2Toggle && !tipMenuToggle) { setTipMenu2Toggle('off',msguser) setTipMenuToggle('on',msguser) } else if (!tipMenu2Toggle && !tipMenuToggle) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); } else { cb.sendNotice(botName + ' Invalid definition, both menus are already active.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/usemenu': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (tipMenu2Toggle && msgarray[1] === 'on') { cb.sendNotice(botName + ' Cannot enable Tip Menu 1 while Tip Menu 2 is active. You can use the "/swapmenu" command to switch between the two.', msguser, appNoticeColor); } else { setTipMenuToggle(msgarray[1],msguser) } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/usemenu2': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (tipMenuToggle && msgarray[1] === 'on') { cb.sendNotice(botName + ' Cannot enable Tip Menu 2 while Tip Menu 1 is active. You can use the "/swapmenu" command to switch between the two.', msguser, appNoticeColor); } else { setTipMenu2Toggle(msgarray[1],msguser) } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/dicerolls': case '/posmenurequests': case '/allrequests': case '/tmr': case '/tmrb': case '/tipmenurequests': { recognizedcmd = true; let tmrsendto = msguser; if (ismodlvlmsg1 && msgcommand == '/tmrb') { tmrsendto = BC; cb.sendNotice(botName + ' You have sent the list of Tip Menu Requests and Dice Rolls to the broadcaster.', msguser, appNoticeColor); } let tmrreqlines = tipMenuRequests.name.length; let tmrlinestoshow = 0; if (tmrreqlines <= 0) { cb.sendNotice(botName + ' There have been no Tip Menu requests or Dice Rolls.', msguser, appNoticeColor); } else if (msgarray[1] && msgarray[1] != 'all' && msgarray[1] != 'All' && msgarray[1] != 'ALL' && (isNaN(msgarray[1]) || msgarray[1] <= 0)) { cb.sendNotice(botName + ' Invalid parameter for number of requests to display, must be a number greater than zero, "all", or blanks (blanks defaults to last 10).', msguser, appNoticeColor); } else { let noticeMsg = borderTmrTop; let tmrstartidx = 0; if (msgarray[1] == 'all' || msgarray[1] == 'All' || msgarray[1] == 'ALL') { tmrlinestoshow = tmrreqlines; } else if (msgarray[1]) { tmrlinestoshow = parseInt(msgarray[1]); } else { tmrlinestoshow = 10; } if (tmrlinestoshow > tmrreqlines) { if (msgarray[1]) { cb.sendNotice(botName + ' Requested more entries than available, showing entire list.', msguser, appNoticeColor); } tmrlinestoshow = tmrreqlines; } else if (tmrlinestoshow > 100) { cb.sendNotice(botName + ' Maximum list size is 100 entries, defaulting to 100.', msguser, appNoticeColor); tmrlinestoshow = 100; } noticeMsg += '\n**** Here ' + (tmrlinestoshow == 1 ? 'is the last' : 'are the last ' + tmrlinestoshow) + ' request' + (tmrlinestoshow == 1 ? '' : 's') + ' from the Tip Menu, Dice Game, and ' + posMenuLiteralDesc + ' Menu! **** \n'; tmrstartidx = tmrreqlines - tmrlinestoshow; for (let tmridx = tmrstartidx; tmridx < tmrreqlines; tmridx++) { let howlongagodsp = howLongAgoCalc(tipMenuRequestTime[tmridx]); noticeMsg += '\nSeq #' + (tmridx+1) + ': ' + tipMenuRequests.name[tmridx] + ' tipped ' + tipMenuRequests.amt[tmridx] + ' for ' + tipMenuRequests.desc[tmridx] + ' (' + howlongagodsp + ')'; if (cbjs.arrayContains(tmrInquiries.name,tmrsendto)) { let tmrlastidx = tmrInquiries.name.indexOf(tmrsendto); if (tmrInquiries.time[tmrlastidx] > tipMenuRequestTime[tmridx] && (tmrInquiries.time[tmrlastidx] < tipMenuRequestTime[tmridx+1] || tmridx == (tmrreqlines - 1))) { let howlongagoinq = howLongAgoCalc(tmrInquiries.time[tmrlastidx]); if (tmrsendto == BC) { noticeMsg += '\n>>> You were last sent or last viewed the tip request summary (' + howlongagoinq + ') <<<'; } else { noticeMsg += '\n>>> You last viewed the tip request summary (' + howlongagoinq + ') <<<'; } } } } noticeMsg += borderUniversalBottom; let currenttimereq = new Date(); if (cbjs.arrayContains(tmrInquiries.name,tmrsendto)) { let tmrlastidx = tmrInquiries.name.indexOf(tmrsendto); tmrInquiries.time[tmrlastidx] = currenttimereq.getTime(); } else { tmrInquiries.name.push(tmrsendto); tmrInquiries.time.push(currenttimereq.getTime()); } cb.sendNotice(noticeMsg, tmrsendto, appWarningColor); } break; } case '/tipmenuprice': { recognizedcmd = true; if (!ismodlvlmsg2 && !msgisbc) { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } else { let label; let newItemPrice = parseInt(msgarray[1]); if (newItemPrice <= 0 || isNaN(newItemPrice)) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); return; } if (!msgarray[2]) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); return; } for (let j = 2; j < msgarray.length; j++) { if (j === 2) { label = msgarray[j]; } else { label += ' ' + msgarray[j]; } } if (tipMenuToggle) { if (!cbjs.arrayContains(tipMenuItemArray, label)) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); } else { let menuitemindex = tipMenuItemArray.indexOf(label); priceChecker('rmv','Tip Menu Option: '+label,tipMenuPriceArray[menuitemindex],msguser); tipMenuPriceArray[menuitemindex] = newItemPrice; priceChecker('add','Tip Menu Option: '+label,newItemPrice,msguser); cb.sendNotice('Tip menu to ' + bcText + ' - ' + (msguser === BC ? 'You' : msguser) + ' updated the price of "' + label + '" to ' + newItemPrice + ' tokens.', BC, appNoticeColor); cb.sendNotice('Tip menu to mods - ' + msguser + ' updated the price of "' + label + '" to ' + newItemPrice + ' tokens.', BC, appNoticeColor, '', '', 'red'); buildMenu(); } } else if (tipMenu2Toggle) { if (!cbjs.arrayContains(tipMenu2ItemArray, label)) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); } else { let menuitemindex2 = tipMenu2ItemArray.indexOf(label); priceChecker('rmv','Tip Menu 2 Option: '+label,tipMenu2PriceArray[menuitemindex2],msguser); tipMenu2PriceArray[menuitemindex2] = newItemPrice; priceChecker('add','Tip Menu 2 Option: '+label,newItemPrice,msguser); cb.sendNotice('Tip menu to ' + bcText + ' - ' + (msguser === BC ? 'You' : msguser) + ' updated the price of "' + label + '" to ' + newItemPrice + ' tokens.', BC, appNoticeColor); cb.sendNotice('Tip menu to mods - ' + msguser + ' updated the price of "' + label + '" to ' + newItemPrice + ' tokens.', BC, appNoticeColor, '', '', 'red'); buildMenu2(); } } } break; } case '/tipmenuadd': { recognizedcmd = true; if (!ismodlvlmsg2 && !msgisbc) { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } else { let label; let newItemPrice = parseInt(msgarray['1']); if (newItemPrice <= 0 || isNaN(newItemPrice)) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); return; } if (!msgarray[2]) { cb.sendNotice(botName + ' You need to include a label for that option.', msguser, appNoticeColor); return; } for (let j = 2; j < msgarray.length; j++) { if (j === 2) { label = msgarray[j]; } else { label += ' ' + msgarray[j]; } } if (tipMenuToggle) { cb.sendNotice('Tip menu to ' + bcText + ' - ' + (msguser === BC ? 'You' : msguser) + ' added the option "' + label + '" for ' + newItemPrice + ' tokens to the menu.', BC, appNoticeColor); cb.sendNotice('Tip menu to mods - ' + msguser + ' added the option "' + label + '" for ' + newItemPrice + ' tokens the menu.', BC, appNoticeColor, '', '', 'red'); tipMenuPriceArray.push(newItemPrice); tipMenuItemArray.push(label); priceChecker('add','Tip Menu Option: '+label,newItemPrice,msguser); buildMenu(); } else if (tipMenu2Toggle) { cb.sendNotice('Tip menu to ' + bcText + ' - ' + (msguser === BC ? 'You' : msguser) + ' added the option "' + label + '" for ' + newItemPrice + ' tokens to Menu 2.', BC, appNoticeColor); cb.sendNotice('Tip menu to mods - ' + msguser + ' added the option "' + label + '" for ' + newItemPrice + ' tokens to Menu 2.', BC, appNoticeColor, '', '', 'red'); if (cbjs.arrayContains(tipMenu2PriceArray, newItemPrice)) { cb.sendNotice('Tip Menu - ' + newItemPrice + ' is already on Menu 2. It is recommended to have different price for each item.', msguser, appNoticeColor); } tipMenu2PriceArray.push(newItemPrice); tipMenu2ItemArray.push(label); priceChecker('add','Tip Menu 2 Option: '+label,newItemPrice,msguser); buildMenu2(); } } break; } case '/tipmenurmv': { recognizedcmd = true; if (!ismodlvlmsg2 && !msgisbc) { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } else { let itemPrice = parseInt(msgarray[1]); let label; let s = 2; if (isNaN(itemPrice)) { s = 1; } for (let i = s; i < msgarray.length; i++) { if (i === s) { label = msgarray[i]; } else { label += ' ' + msgarray[i]; } } if (itemPrice <= 0) { cb.sendNotice(botName + ' Error! Price must be greater than 0.', '', appNoticeColor); return; } if (tipMenuToggle) { if (itemPrice > 0) { if (cbjs.arrayContains(tipMenuPriceArray, itemPrice)) { if (!msgarray[2]) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); for (let i = 0; i < tipMenuLength; i++) { if (itemPrice === tipMenuPriceArray[i]) { priceChecker('rmv','Tip Menu Option: '+tipMenuItemArray[i], tipMenuPriceArray[i],msguser); tipMenuPriceArray[i] = 0; cb.sendNotice(botName + ' Tip menu to ' + bcText + ' - ' + (msguser === BC ? 'You' : msguser) + ' removed the option "' + tipMenuItemArray[i] + '" from the menu.', BC, appNoticeColor); cb.sendNotice(botName + ' Tip menu to mods - ' + msguser + ' removed the option "' + tipMenuItemArray[i] + '" from the menu.', BC, appNoticeColor, '', '', 'red'); } } buildMenu(); } else { let labelFound = false; for (let i = 0; i < tipMenuLength; i++) { if (itemPrice === tipMenuPriceArray[i] && label === tipMenuItemArray[i]) { labelFound = true; priceChecker('rmv','Tip Menu Option: '+tipMenuItemArray[i], tipMenuPriceArray[i],msguser); tipMenuPriceArray[i] = 0; cb.sendNotice(botName + ' Tip menu to ' + bcText + ' - ' + (msguser === BC ? 'You' : msguser) + ' removed the option "' + tipMenuItemArray[i] + '" from the menu.', BC, appNoticeColor); cb.sendNotice(botName + ' Tip menu to mods - ' + msguser + ' removed the option "' + tipMenuItemArray[i] + '" from the menu.', BC, appNoticeColor, '', '', 'red'); buildMenu(); } } if (!labelFound) { cb.sendNotice(botName + ' Tip menu - Unable find item ' + label + '(' + itemPrice + ') on the menu. Skipping.', msguser, appNoticeColor); } } } else { cb.sendNotice(botName + ' Tip menu - Unable find any item at ' + itemPrice + ' tokens on the menu.', msguser, 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.', msguser, appNoticeColor); } else if (cbjs.arrayContains(tipMenuItemArray, label)) { for (let i = 0; i < tipMenuLength; i++) { if (label === tipMenuItemArray[i]) { priceChecker('rmv','Tip Menu Option: '+tipMenuItemArray[i], tipMenuPriceArray[i],msguser); tipMenuPriceArray[i] = 0; cb.sendNotice(botName + ' Tip menu to ' + bcText + ' - ' + (msguser === BC ? 'You' : msguser) + ' removed the option "' + tipMenuItemArray[i] + '" from the menu.', BC, appNoticeColor); cb.sendNotice(botName + ' Tip menu to mods - ' + msguser + ' removed the option "' + tipMenuItemArray[i] + '" from the menu.', BC, appNoticeColor, '', '', 'red'); } } buildMenu(); } else { cb.sendNotice(botName + ' Tip menu - Unable find item ' + label + ' on the menu. Skipping.', msguser, appNoticeColor); } } } else if (tipMenu2Toggle) { if (itemPrice > 0) { if (cbjs.arrayContains(tipMenu2PriceArray, itemPrice)) { if (!msgarray[2]) { cb.sendNotice(botName + ' Tip menu 2 - No label was found! Every options that match "' + itemPrice + '" will be removed from menu 2.', msguser, appNoticeColor); for (let i = 0; i < tipMenu2Length; i++) { if (itemPrice ===tipMenu2PriceArray[i]) { priceChecker('rmv','Tip Menu 2 Option: '+tipMenu2ItemArray[i],tipMenu2PriceArray[i],msguser); tipMenu2PriceArray[i] = 0; cb.sendNotice(botName + ' Tip menu 2 to ' + bcText + ' - ' + (msguser === BC ? 'You' : msguser) + ' removed the option "' +tipMenu2ItemArray[i] + '" from menu 2.', BC, appNoticeColor); cb.sendNotice(botName + ' Tip menu 2 to mods - ' + msguser + ' removed the option "' +tipMenu2ItemArray[i] + '" from menu 2.', BC, appNoticeColor, '', '', 'red'); } } buildMenu2(); } else { let labelFound = false; for (let i = 0; i < tipMenu2Length; i++) { if (itemPrice ===tipMenu2PriceArray[i] && label ===tipMenu2ItemArray[i]) { labelFound = true; priceChecker('rmv','Tip Menu 2 Option: '+tipMenu2ItemArray[i],tipMenu2PriceArray[i],msguser); tipMenu2PriceArray[i] = 0; cb.sendNotice(botName + ' Tip menu 2 to ' + bcText + ' - ' + (msguser === BC ? 'You' : msguser) + ' removed the option "' +tipMenu2ItemArray[i] + '" from menu 2.', BC, appNoticeColor); cb.sendNotice(botName + ' Tip menu 2 to mods - ' + msguser + ' removed the option "' +tipMenu2ItemArray[i] + '" from menu 2.', BC, appNoticeColor, '', '', 'red'); buildMenu2(); } } if (!labelFound) { cb.sendNotice(botName + ' Tip menu 2 - Unable find item ' + label + '(' + itemPrice + ') on menu 2. Skipping.', msguser, appNoticeColor); } } } else { cb.sendNotice(botName + ' Tip menu 2 - Unable find any item at ' + itemPrice + ' tokens on menu 2.', msguser, appNoticeColor); } } else { if (!label) { cb.sendNotice(botName + ' Tip menu - Unable to process. Use "/tipmenurmv X Label". Where X is the amount of tokens and label is the name of the item.', msguser, appNoticeColor); } else if (cbjs.arrayContains(tipMenu2ItemArray, label)) { for (let i = 0; i < tipMenu2Length; i++) { if (label ===tipMenu2ItemArray[i]) { priceChecker('rmv','Tip Menu 2 Option: '+tipMenu2ItemArray[i],tipMenu2PriceArray[i],msguser); tipMenu2PriceArray[i] = 0; cb.sendNotice(botName + ' Tip menu 2 to ' + bcText + ' - ' + (msguser === BC ? 'You' : msguser) + ' removed the option "' +tipMenu2ItemArray[i] + '" from menu 2.', BC, appNoticeColor); cb.sendNotice(botName + ' Tip menu 2 to mods - ' + msguser + ' removed the option "' +tipMenu2ItemArray[i] + '" from menu 2.', BC, appNoticeColor, '', '', 'red'); } } buildMenu(); } else { cb.sendNotice(botName + ' Tip menu 2 - Unable find item ' + label + ' on menu 2. Skipping.', msguser, appNoticeColor); } } } } break; } //********* Positions Tip Menu Commands case '/posmenu': { recognizedcmd = true; if (posTipMenuToggle) { if (ismodlvlmsg1) { msguser = ''; } cb.sendNotice('Sent to YOU:\n' + posMenuDisplayText, msguser, posMenuBgColor, posMenuTextColor, "bold"); } else { cb.sendNotice('The ' + posMenuLiteralDesc + ' Tip Menu has not been enabled.', msguser, appNoticeColor); } break; } case '/useposmenu': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { setPosTipMenuToggle(msgarray[1],msguser) } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/posmenurequestsold': { recognizedcmd = true; if (ismodlvlmsg1) { msguser = ''; } let posrL = posMenuRequestsArray.length; if (posrL === 0) { cb.sendNotice("There is no request at the moment.", msguser, posMenuBgColor, posMenuTextColor); } 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) + ': ' + posMenuRequestersArray[i] + ' requested ' + posMenuRequestsArray[i] + '\n'; } posNoticeMsg += '**************************************'; cb.sendNotice(posNoticeMsg, msguser, posMenuBgColor, posMenuTextColor); } break; } case '/posmenuadd': { recognizedcmd = true; if (!ismodlvlmsg2 && !msgisbc) { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } else { let poslabel; let newPosItemPrice = parseInt(msgarray['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.', msguser, "#FFFFFF", "#FF0000"); return; } if (!msgarray[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.', msguser, "#FFFFFF", "#FF0000"); return; } for (let j = 2; j < msgarray.length; j++) { if (j === 2) { poslabel = msgarray[j]; } else { poslabel += " " + msgarray[j]; } } cb.sendNotice('Position Tip menu notification - ' + (msguser === BC ? "You" : msguser) + ' added the option "' + poslabel + '" for ' + newPosItemPrice + ' tokens to the positions menu.', BC, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice('Position Tip menu notification - The option "' + poslabel + '" for ' + newPosItemPrice + ' tokens was added to the ' + posMenuLiteralDesc + ' Tip Menu.', "", "#FFFFFF", "#FF0000", "bold", "red"); if (cbjs.arrayContains(posMenuPriceArray, newPosItemPrice)) { cb.sendNotice("Positions Tip Menu - " + newPosItemPrice + " is already on the menu. It is recommended to have different price for each item.", msguser, "#FFFFFF", "#FF0000"); } posMenuPriceArray.push(newPosItemPrice); posMenuItemArray.push(poslabel); priceChecker('add','Positions Menu Option: '+poslabel,newPosItemPrice,msguser); posMenuLength = posMenuPriceArray.length; buildPosMenuText(); } break; } case '/posmenurmv': { recognizedcmd = true; if (!ismodlvlmsg2 && !msgisbc) { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } else { let posItemPrice = parseInt(msgarray['1']); let poslabel; let s = 2; if (isNaN(posItemPrice)) { s = 1; } for (let i = s; i < msgarray.length; i++) { if (i === s) { poslabel = msgarray[i]; } else { poslabel += " " + msgarray[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(posMenuPriceArray, posItemPrice)) { if (!msgarray[2]) { cb.sendNotice('Positions Tip Menu - No position name was provided, all options that match the "' + posItemPrice + '" token price will be removed.', msguser, "#FFFFFF", "#FF0000", "bold"); for (let i = 0; i < posMenuLength; i++) { if (posItemPrice === posMenuPriceArray[i]) { priceChecker('rmv','Positions Menu Option: '+posMenuItemArray[i],posMenuPriceArray[i],msguser); posMenuPriceArray[i] = 0; cb.sendNotice('Positions Tip Menu - ' + (msguser === BC ? "You" : msguser) + ' removed the option "' + posMenuItemArray[i] + '".', BC, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice('Positions Tip Menu - The option "' + posMenuItemArray[i] + '" was removed.', "", "#FFFFFF", "#FF0000", "bold", "red"); } } buildPosMenuText(); } else { let poslabelFound = false; for (let i = 0; i < posMenuLength; i++) { if (posItemPrice == posMenuPriceArray[i] && poslabel == posMenuItemArray[i]) { poslabelFound = true; priceChecker('rmv','Positions Menu Option: '+posMenuItemArray[i],posMenuPriceArray[i],msguser); posMenuPriceArray[i] = 0; cb.sendNotice('Positions Tip Menu - ' + (msguser === BC ? "You" : msguser) + ' removed the option "' + posMenuItemArray[i] + '".', BC, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice('Positions Tip Menu - The option "' + posMenuItemArray[i] + '" was removed.', "", "#FFFFFF", "#FF0000", "bold", "red"); buildPosMenuText(); } } if (!poslabelFound) { cb.sendNotice('Positions Tip Menu - Unable find item ' + poslabel + '(' + posItemPrice + ') on the menu. Skipping.', msguser, "#FFFFFF", "#FF0000", "bold"); } } } else { cb.sendNotice('Positions Tip Menu - Unable find any item at ' + posItemPrice + ' tokens on the menu.', msguser, "#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.', msguser, "#FFFFFF", "#FF0000", "bold"); } else if (cbjs.arrayContains(posMenuItemArray, poslabel)) { for (let i = 0; i < posMenuLength; i++) { if (poslabel === posMenuItemArray[i]) { priceChecker('rmv','Positions Menu Option: '+posMenuItemArray[i],posMenuPriceArray[i],msguser); posMenuPriceArray[i] = 0; cb.sendNotice('Positions Tip Menu - ' + (msguser === BC ? "You" : msguser) + ' removed the option "' + posMenuItemArray[i] + '".', BC, "#FFFFFF", "#FF0000", "bold"); cb.sendNotice('Positions Tip Menu - The option "' + posMenuItemArray[i] + '" was removed.', "", "#FFFFFF", "#FF0000", "bold", "red"); } } buildPosMenuText(); } else { cb.sendNotice('Positions Tip Menu - Unable find item ' + poslabel + ' on the positions menu. Skipping.', msguser, "#FFFFFF", "#FF0000", "bold"); } } } break; } //********* Token Poll Commands case '/usepoll': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (onDemandPollEnabled) { cb.sendNotice('The On-Demand Token Poll is enabled, the Pre-configured Fembot Token Poll cannot be started at the same time.', msguser, appNoticeColor); } else { setTokenPollToggle(msgarray[1], msguser) } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,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.',msguser,appNoticeColor); } break; } case '/poll': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { let pollsendto = msguser; if (ismodlvlmsg1 || msgisbc) { pollsendto = ''; } if (tokenPollToggle) { showBoard('cmd',pollsendto,false); } else if (onDemandPollRunning) { showODBoard('cmd',pollsendto); } else if (ismodlvlmsg1 || msgisbc) { showBoard('cmd',msguser,true); } else { cb.sendNotice('The Token Poll is disabled.', msguser, appNoticeColor); } } break; } case '/endpoll': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (tokenPollToggle) { cb.sendNotice(msguser + ' has ended the poll. No more votes will be counted.', '', tokenPollBgColor, tokenPollTextColor, 'bold'); if (pollRunning) { pollRunning = false; } showWinner(''); } else if (onDemandPollRunning) { cb.sendNotice(msguser + ' has ended the poll. No more votes will be counted.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); onDemandPollRunning = false; odshowWinner(''); } else { cb.sendNotice('The Token Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } } break; } case '/restartpoll': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (tokenPollToggle) { cb.sendNotice(msguser + ' has restarted the poll, voting has resumed.', '', tokenPollBgColor, tokenPollTextColor, 'bold'); if (!pollRunning) { pollRunning = true; pollType = 'Never'; } } else if (onDemandPollEnabled) { cb.sendNotice(msguser + ' has restarted the poll, voting has resumed.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); if (!onDemandPollRunning) { onDemandPollRunning = true; } } else { cb.sendNotice('The Token Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } } break; } case '/resetpoll': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (tokenPollToggle) { pollArrayVotes.fill(0); totalPollVotes = 0; cb.sendNotice(msguser + ' 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(msguser + ' 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.', msguser, 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } } break; } case '/addvote': case '/addvotes': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg1 && pollModAdd)) { if (tokenPollToggle) { let addvoteamount = 0; let addvotefail = 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', msguser, 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', msguser, appNoticeColor); break; } if (!commandVar2) { addvoteamount = 1; } else { addvoteamount = commandVar2; } for (let i = 0; i < pollArrayAmount.length; i++) { if (commandVar1 === pollArrayAmount[i]) { cb.sendNotice(msguser + ' has ' + (addvoteamount > 0 ? 'added' : 'removed') + ' ' + (addvoteamount < 0 ? -addvoteamount : addvoteamount) + ' vote' + (addvoteamount === 1 || addvoteamount === -1 ? '' : 's') + ' for poll option "' + pollArrayLabel[i] + '".', '', tokenPollBgColor, tokenPollTextColor, 'bold'); pollArrayVotes[i] += addvoteamount; totalPollVotes += addvoteamount; addvotefail = false; if (pollType === 'Vote') { votesRemain -= addvoteamount; } checkPollEnd(); break; } } if (addvotefail) { 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', msguser, appNoticeColor); break; } } else if (onDemandPollRunning) { let odaddvotefail = true; let odaddvoteamount = 0; 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', msguser, 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', msguser, appNoticeColor); break; } if (!commandVar2) { odaddvoteamount = 1; } else { odaddvoteamount = commandVar2; } for (let i = 0; i < odpollArrayAmount.length; i++) { if (commandVar1 == odpollArrayAmount[i]) { cb.sendNotice(msguser + ' has ' + (odaddvoteamount > 0 ? 'added' : 'removed') + ' ' + (odaddvoteamount < 0 ? -odaddvoteamount : odaddvoteamount) + ' vote' + (odaddvoteamount === 1 || odaddvoteamount === -1 ? '' : 's') + ' for poll option "' + odpollArrayLabel[i] + '".', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); odpollArrayVotes[i] += odaddvoteamount; odaddvotefail = false; break; } } if (odaddvotefail) { 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', msguser, appNoticeColor); break; } } else { cb.sendNotice('The Token Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3A,msguser,appNoticeColor); } } break; } case '/polloptadd': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (!onDemandPollEnabled) { let polloptlabel = ''; let oktoadd = true; 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.', msguser, appNoticeColor); oktoadd = false; break; } if (!msgarray[2]) { cb.sendNotice('You must include a label for this voting selection in the second variable.', msguser, appNoticeColor); oktoadd = false; break; } if (pollArrayAmount.length >= 8) { cb.sendNotice('There are already 8 entries in the poll, no more can be added.', msguser, appNoticeColor); oktoadd = false; 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.', msguser, appNoticeColor); oktoadd = false; break; } } for (let i = 2; i < msgarray.length; i++) { if (i == 2) { polloptlabel = msgarray[i]; } else { polloptlabel += ' ' + msgarray[i]; } } for (let j = 0; j < pollArrayLabel.length; j++) { if (pollArrayLabel[j] == polloptlabel) { 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.', msguser, appNoticeColor); oktoadd = false; break; } } if (oktoadd) { populatePollArray(polloptlabel,commandVar1,0,msguser); priceChecker('add','Poll Option: '+ polloptlabel,commandVar1,msguser); cb.sendNotice(msguser + ' added the option "' + polloptlabel + '" 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.', msguser, appNoticeColor); } else if (onDemandPollEnabled && onDemandPollRunning) { let odpolloptlabel = ''; let odoktoadd = true; 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.', msguser, appNoticeColor); odoktoadd = false; break; } if (!msgarray[2]) { cb.sendNotice('You must include a label for this voting selection in the second variable.', msguser, appNoticeColor); odoktoadd = false; break; } if (odpollArrayAmount.length >= 8) { cb.sendNotice('There are already 8 entries in the poll, no more can be added.', msguser, appNoticeColor); odoktoadd = false; 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.', msguser, appNoticeColor); odoktoadd = false; break; } } for (let i = 2; i < msgarray.length; i++) { if (i == 2) { odpolloptlabel = msgarray[i]; } else { odpolloptlabel += ' ' + msgarray[i]; } } for (let j = 0; j < odpollArrayLabel.length; j++) { if (odpollArrayLabel[j] == odpolloptlabel) { 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.', msguser, appNoticeColor); odoktoadd = false; break; } } if (odoktoadd) { populateODPollArray(odpolloptlabel,commandVar1,0,msguser); priceChecker('add','On-demand Poll Option: '+ odpolloptlabel,commandVar1,msguser); cb.sendNotice(msguser + ' added the option "' + odpolloptlabel + '" to the poll.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); } } else { cb.sendNotice('The Token Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } break; } case '/polloptrmv': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (!onDemandPollEnabled) { 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.', msguser, appNoticeColor); break; } if (pollArrayAmount.length <= 2) { cb.sendNotice('There are only 2 entries in the poll, no more can be removed.', msguser, appNoticeColor); break; } if (cbjs.arrayContains(pollArrayAmount,commandVar1)) { let pollrmvidx = pollArrayAmount.indexOf(commandVar1); priceChecker('rmv','Poll Option: '+pollArrayLabel[pollrmvidx],pollArrayAmount[pollrmvidx],msguser); cb.sendNotice(msguser + ' removed the option "' + pollArrayLabel[pollrmvidx] + '" from the poll.', '', tokenPollBgColor, tokenPollTextColor, 'bold'); pollArrayAmount.splice(pollrmvidx,1); pollArrayLabel.splice(pollrmvidx,1); pollArrayVotes.splice(pollrmvidx,1); } else { cb.sendNotice('The specified poll option amount is not in the poll, please try again.', msguser, 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.', msguser, appNoticeColor); } else if (onDemandPollEnabled && 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.', msguser, appNoticeColor); break; } if (odpollArrayAmount.length <= 2) { cb.sendNotice('There are only 2 entries in the poll, no more can be removed.', msguser, appNoticeColor); break; } if (cbjs.arrayContains(odpollArrayAmount,commandVar1)) { let odpollrmvidx = odpollArrayAmount.indexOf(commandVar1); priceChecker('rmv','Poll Option: '+odpollArrayLabel[odpollrmvidx],odpollArrayAmount[odpollrmvidx],msguser); cb.sendNotice(msguser + ' removed the option "' + odpollArrayLabel[odpollrmvidx] + '" from the poll.', '', odtokenPollBgColor, odtokenPollTextColor, 'bold'); odpollArrayAmount.splice(odpollrmvidx,1); odpollArrayLabel.splice(odpollrmvidx,1); odpollArrayVotes.splice(odpollrmvidx,1); } else { cb.sendNotice('The specified poll option amount is not in the poll, please try again.', msguser, appNoticeColor); } } else { cb.sendNotice('The Token Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } break; } case '/pst': case '/pollstarttimer': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg1 || msgisbc) { if (tokenPollToggle) { if (!pollRunning) { cb.sendNotice('The poll is not running, cannot to start a timer.', msguser, 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.', msguser, 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.', msguser, appNoticeColor); break; } if (commandVar1 > 60) { cb.sendNotice('The time specified is greater than 60 minutes, please use a smaller value.', msguser, 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.', msguser, appNoticeColor); break; } if (pollType !== 'Timer') { pollTimerStopping = false; pollSwitchToTimer(commandVar1); 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', msguser, 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.', msguser, 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.', msguser, appNoticeColor); break; } if (commandVar1 > 60) { cb.sendNotice('The time specified is greater than 60 minutes, please use a smaller value.', msguser, 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', msguser, appNoticeColor); break; } if (odpollType !== 'Timer') { odpollTimerStopping = false; odpollSwitchToTimer(commandVar1); break; } } else { cb.sendNotice('The Token Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/polltimeleft': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (tokenPollToggle) { if (pollType == 'Timer') { cb.sendNotice(pollTimeLeft(), msguser, tokenPollBgColor, tokenPollTextColor, boldTextLiteral); break; } else { cb.sendNotice('Timer is not running.', msguser, appNoticeColor); } } else if (onDemandPollRunning) { if (odpollType == 'Timer') { cb.sendNotice(odpollTimeLeft(), msguser, odtokenPollBgColor, odtokenPollTextColor, boldTextLiteral); } else { cb.sendNotice('Timer is not running.', msguser, appNoticeColor); } } else { cb.sendNotice('A Token Poll is not running.', msguser, appNoticeColor); } } break; } case '/polladdtime': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg1 || msgisbc) { if (tokenPollToggle) { if (!pollRunning) { cb.sendNotice('The poll is not running, no need to add time.', msguser, 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', msguser, 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.', msguser, 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.', msguser, 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.', msguser, appNoticeColor); } else { pollAddTime(commandVar1); } } 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', msguser, 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.', msguser, 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.', msguser, 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.', msguser, appNoticeColor); } else { odpollAddTime(commandVar1); } } else { cb.sendNotice('The Token Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/pollstoptimer': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg1 || msgisbc) { if (tokenPollToggle) { if (!pollRunning) { cb.sendNotice('The poll is not running.', msguser, appNoticeColor); } else if (pollType != 'Timer' || pollMinsRemain <= 0 || pollSecsRemain <= 0) { cb.sendNotice('A timer is not in use, ignoring command.', msguser, 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, '', boldTextLiteral); } } else if (onDemandPollRunning) { if (odpollType != 'Timer' || odpollMinsRemain <= 0 || odpollSecsRemain <= 0) { cb.sendNotice('A timer is not in use, ignoring command.', msguser, 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, '', boldTextLiteral); } } else { cb.sendNotice('The Token Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/pollchgtitle': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg1 || msgisbc) { if (tokenPollToggle) { let newtitle = rawmsg.substring(14).trim() if (newtitle) { pollTitle = newtitle; cb.sendNotice('You have updated the poll title to "' + newtitle + '".', msguser, appNoticeColor); } else { cb.sendNotice('A new title was not specified, please try the command again in the format "/pollchgtitle [new title]".', msguser, appNoticeColor); } } else if (onDemandPollEnabled) { let odnewtitle = rawmsg.substring(14).trim() if (odnewtitle) { odpollTitle = odnewtitle; cb.sendNotice('You have updated the poll title to "' + odnewtitle + '".', msguser, appNoticeColor); } else { cb.sendNotice('A new title was not specified, please try the command again in the format "/pollchgtitle [new title]".', msguser, appNoticeColor); } } else { cb.sendNotice('The Token Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/pl': case '/polllead': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { let polleadsendto = msguser; if (ismodlvlmsg1 || msgisbc) { polleadsendto = ''; } if (tokenPollToggle) { cb.sendNotice((polleadsendto == '' ? 'Sent to ALL: ' : 'Sent to YOU: ') + showLead(), polleadsendto, tokenPollBgColor, tokenPollTextColor, boldTextLiteral); } else if (onDemandPollRunning) { cb.sendNotice((polleadsendto == '' ? 'Sent to ALL: ' : 'Sent to YOU: ') + odshowLead(), polleadsendto, odtokenPollBgColor, odtokenPollTextColor, boldTextLiteral); } else { cb.sendNotice('The Token Poll is disabled.', msguser, appNoticeColor); } } break; } case '/hijackprice': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg3 || msgisbc) { if (tokenPollToggle || onDemandPollRunning) { let hjnumprice = parseInt(msgarray[1]) if (isNaN(hjnumprice)) { cb.sendNotice('The value entered for the new "hijack" price is not numeric, please try again.', msguser, appNoticeColor); break; } else if (hjnumprice < 0 || hjnumprice > 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.', msguser, appNoticeColor); } else { stealPollAmount = hjnumprice; if (stealPollAmount == 0) { if (tokenPollToggle) { cb.sendNotice('The "hijacking" of the poll has been disabled.', msguser, tokenPollBgColor, tokenPollTextColor, boldTextLiteral); } else if (onDemandPollRunning) { cb.sendNotice('The "hijacking" of the poll has been disabled.', msguser, odtokenPollBgColor, odtokenPollTextColor, boldTextLiteral); } } else { if (tokenPollToggle) { cb.sendNotice('The price to "hijack" the poll has been set to ' + hjnumprice + ' tokens.', msguser, tokenPollBgColor, tokenPollTextColor, boldTextLiteral); } else if (onDemandPollRunning) { cb.sendNotice('The price to "hijack" the poll has been set to ' + hjnumprice + ' tokens.', msguser, odtokenPollBgColor, odtokenPollTextColor, boldTextLiteral); } } } } else { cb.sendNotice('The Token Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } } break; } //********* On-demand Poll Commands case '/makepoll': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (tokenPollToggle) { 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".', msguser, 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.', msguser, appNoticeColor); } else { let mpoktoadd = 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.', msguser, appNoticeColor); mpoktoadd = false; break; } if (!msgarray[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.', msguser, appNoticeColor); mpoktoadd = false; break; } if (tempODPollAmounts.length >= 8) { cb.sendNotice('There are already 8 entries in the poll, no more can be added.', msguser, appNoticeColor); mpoktoadd = 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.', msguser, appNoticeColor); mpoktoadd = false; break; } } let mplabel = ''; for (let i = 2; i < msgarray.length; i++) { if (i == 2) { mplabel = msgarray[i]; } else { mplabel += ' ' + msgarray[i]; } } for (let j = 0; j < tempODPollLabels.length; j++) { if (tempODPollLabels[j] == mplabel) { 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.', msguser, appNoticeColor); mpoktoadd = false; break; } } if (mpoktoadd) { if (!onDemandPollEnabled) { createOnDemandPoll(msguser); } addODTempOption(mplabel,commandVar1,msguser); priceChecker('add','On-demand Poll Option: '+ mplabel,commandVar1,msguser); cb.sendNotice('You have added the option "' + mplabel + '" to the poll. You can add more poll options or use the command "/odstart" when ready to start running the poll.', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } break; } case '/odpollstart': case '/odstart': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (tokenPollToggle) { cb.sendNotice(botName + ' The Pre-configured Token Poll is enabled, an on-demand poll cannot be started at the same time.', msguser, appNoticeColor); } else if (!onDemandPollEnabled) { cb.sendNotice(botName + ' An on-demand poll has not been created, you can use the command "/makepoll" to add each option, then start the poll.', msguser, appNoticeColor); } else if (onDemandPollRunning) { cb.sendNotice(botName + ' The on-demand poll is already running.', msguser, appNoticeColor); } else if (tempODPollLabels.length < 2) { cb.sendNotice(botName + ' At least two options are required in the poll, you can use the command "/makepoll" to add each option, then start the poll.', msguser, appNoticeColor); } else { startOnDemandPoll(msguser); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } break; } case '/odoff': { recognizedcmd = true; if (cb.settings.pollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (!onDemandPollEnabled) { cb.sendNotice(botName + ' An on-demand poll has not been created or started.', msguser, appNoticeColor); } else { disableOnDemandPoll(msguser) } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } break; } //********* Text Poll Commands case '/usetextpoll': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (msgarray[1]) { var textpollenable = msgarray[1].toLowerCase(); if (textpollenable == 'on' && textPollToggle) { cb.sendNotice(botName + ' The text poll is alreasy enabled.', msguser, appNoticeColor); } else if (textpollenable == 'off' && !textPollToggle) { cb.sendNotice(botName + ' The text poll is alreasy disabled.', msguser, appNoticeColor); } else if (textpollenable != 'on' && textpollenable != 'off') { cb.sendNotice(botName + ' An invalid parameter was specified for the /usetextpoll command, allowed values are "on" or "off".', msguser, appNoticeColor); } else { setTextPollToggle(textpollenable, msguser) } } else { cb.sendNotice(botName + ' No parameter was specified for the /usetextpoll command, allowed values are "on" or "off".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } } else { cb.sendNotice(botName + ' 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.',msguser,appNoticeColor); } break; } case '/textpoll': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { let tpsendto = msguser; if (ismodlvlmsg1 || msgisbc) { tpsendto = ''; } if (textPollToggle) { showTextPollBoard('cmd',tpsendto); } else { cb.sendNotice(botName + ' The Text Poll is disabled.', msguser, appNoticeColor); } } break; } case '/endtextpoll': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (textPollToggle) { cb.sendNotice(botName + msguser + ' has ended the text poll. No more votes will be counted.', '', textPollBgColor, textPollTextColor, 'bold'); if (textPollRunning) { textPollRunning = false; } showTextPollWinner(''); } else { cb.sendNotice(botName + ' The Text Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } } break; } case '/restarttextpoll': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (textPollToggle) { cb.sendNotice(msguser + ' has restarted the text poll, voting has resumed.', '', textPollBgColor, textPollTextColor, 'bold'); if (!textPollRunning) { textPollRunning = true; textPollType = 'Never'; } } else { cb.sendNotice(botName + ' The Text Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } } break; } case '/resettextpoll': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (textPollToggle) { initTextPollValues(); textPollArray.votes.fill(0); cb.sendNotice(botName + msguser + ' has reset the text poll vote counts, voting is now starting over.', '', textPollBgColor, textPollTextColor, 'bold'); if (!textPollRunning) { textPollRunning = true; textPollType = 'Never'; } } else { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } } break; } case '/addtextvote': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { if (msgisbc || ismodlvlmsg2) { if (textPollToggle) { var atvamount; var atvfail = true; if (commandVar1 == 0 || commandVar2 == 0) { cb.sendNotice(botName + ' 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', msguser, appNoticeColor); break; } if (!commandVar1) { cb.sendNotice(botName + ' 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', msguser, 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(msguser + ' 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(botName + ' 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', msguser, appNoticeColor); break; } } else { cb.sendNotice(botName + ' The Text Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3A,msguser,appNoticeColor); } } break; } case '/textoptadd': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (textPollToggle) { let toalabel = ''; let toaoktoadd = true; if (commandVar1 <= 0 || isNaN(commandVar1)) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); toaoktoadd = false; break; } if (!msgarray[2]) { cb.sendNotice(botName + ' You must include a label for this voting selection in the second variable.', msguser, appNoticeColor); toaoktoadd = false; break; } if (pollArrayAmount.length >= 5) { cb.sendNotice(botName + ' There are already 5 entries in the poll, no more can be added.', msguser, appNoticeColor); toaoktoadd = false; break; } for (let j = 0; j < textPollArray.dispname.length; j++) { if (textPollArray.voteID[j] === commandVar1) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); toaoktoadd = false; break; } } for (let i = 2; i < msgarray.length; i++) { if (i == 2) { toalabel = msgarray[i]; } else { toalabel += ' ' + msgarray[i]; } } for (let j = 0; j < textPollArray.dispname.length; j++) { if (textPollArray.dispname[j] == toalabel) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); toaoktoadd = false; break; } } if (toaoktoadd) { textPollArray.dispname.push(toalabel); textPollArray.voteID.push(textPollArray.dispname.length); textPollArray.votes.push(0); cb.sendNotice(botName + msguser + ' added the option "' + toalabel + '" to the poll.', '', textPollBgColor, textPollTextColor, 'bold'); } } else { cb.sendNotice(botName + ' The Text Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } break; } case '/textoptrmv': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { if (ismodlvlmsg2 || msgisbc) { if (textPollToggle) { if (commandVar1 <= 0 || isNaN(commandVar1)) { cb.sendNotice(botName + ' The first variable has be be a number greater than 0. This value is the option ID that will be removed.', msguser, appNoticeColor); break; } if (textPollArray.dispname.length <= 2) { cb.sendNotice(botName + ' There are only 2 entries in the poll, no more can be removed.', msguser, appNoticeColor); break; } if (cbjs.arrayContains(textPollArray.voteID,commandVar1)) { var tporidx = textPollArray.voteID.indexOf(commandVar1); cb.sendNotice(botName + msguser + ' 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(botName + ' The specified poll option amount is not in the poll, please try again.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + ' The Text Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } break; } case '/textstarttimer': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { if (ismodlvlmsg1 || msgisbc) { if (textPollToggle) { if (!textPollRunning) { cb.sendNotice(botName + ' The text poll is not running, cannot to start a timer.', msguser, appNoticeColor); break; } if (textPollType == 'Timer' && (textPollMinsRemain >= 1 || textPollSecsRemain >= 1)) { cb.sendNotice(botName + ' A timer is already running, please use the command /textpolladdtime to add time to timer.', msguser, appNoticeColor); break; } if (!commandVar1) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); break; } if (commandVar1 > 60) { cb.sendNotice(botName + ' The time specified is greater than 60 minutes, please use a smaller value.', msguser, appNoticeColor); break; } commandVar1 = parseInt(commandVar1) if (isNaN (commandVar1)) { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); break; } if (textPollType !== 'Timer') { textPollTimerStopping = false; textPollSwitchToTimer(commandVar1); break; } } else { cb.sendNotice(botName + ' The Text Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/texttimeleft': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { if (textPollToggle) { if (textPollType == 'Timer') { cb.sendNotice(textPollTimeLeft(), msguser, textPollBgColor, textPollTextColor, 'bold'); break; } else { cb.sendNotice(botName + ' Text Poll Timer is not running.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + ' The Text Poll is disabled.', msguser, appNoticeColor); } } break; } case '/textaddtime': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { if (ismodlvlmsg1 || msgisbc) { if (textPollToggle) { if (!textPollRunning) { cb.sendNotice(botName + ' The text poll is not running, no need to add time.', msguser, appNoticeColor); } else if (!commandVar1) { cb.sendNotice(botName + ' 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', msguser, appNoticeColor); } else if (textPollType !== 'Timer') { cb.sendNotice(botName + ' The poll is currently configured for vote count or manual end, a timer is not valid in this mode.', msguser, appNoticeColor); } else if (textPollMinsRemain + commandVar1 <= 0) { cb.sendNotice(botName + ' The value is over the amount of time left. You can use "/endtextpoll" to stop the poll and pick the winner.', msguser, appNoticeColor); } else if (textPollMinsRemain + commandVar1 > 60) { cb.sendNotice(botName + ' The added time will increase the timer to greater than 60 minutes, please use a smaller value.', msguser, appNoticeColor); } else { textPollAddTime(commandVar1); } } else { cb.sendNotice(botName + ' The Text Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/textstoptimer': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { if (ismodlvlmsg1 || msgisbc) { if (textPollToggle) { if (!textPollRunning) { cb.sendNotice(botName + ' The Text Poll is not running.', msguser, appNoticeColor); } else if (textPollType != 'Timer' || pollMinsRemain <= 0 || pollSecsRemain <= 0) { cb.sendNotice(botName + ' A timer is not in use, ignoring command.', msguser, appNoticeColor); } else if (textPollType == 'Timer') { textPollType = 'Never'; textPollStopTimer(); cb.sendNotice(botName + ' 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(botName + ' The Text Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/textchgtitle': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { if (ismodlvlmsg1 || msgisbc) { if (textPollToggle) { var newtexttitle = rawmsg.substring(14).trim() if (newtexttitle) { textPollTitle = newtexttitle; cb.sendNotice(botName + ' You have updated the text poll title to "' + newtexttitle + '".', msguser, appNoticeColor); } else { cb.sendNotice(botName + ' A new title was not specified, please try the command again in the format "/textpollchgtitle [new title]".', msguser, appNoticeColor); } } else { cb.sendNotice(botName + ' The Text Poll is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/textlead': { recognizedcmd = true; if (cb.settings.textPollSepBot == 'No') { var tplsendto = msguser; if (ismodlvlmsg1 || msgisbc) { tplsendto = ''; } if (textPollToggle) { cb.sendNotice((tplsendto == '' ? 'Sent to ALL: ' : 'Sent to YOU: ') + showTextPollLead(), tplsendto, textPollBgColor, textPollTextColor, boldTextLiteral); } else { cb.sendNotice(botName + ' The Text Poll is disabled.', msguser, appNoticeColor); } } break; } //********* Lush Menu Commands case '/toymenu': { recognizedcmd = true; if (lushMenuToggle) { let toymenureqby = msguser; if (ismodlvlmsg1 || msgisbc) { toymenureqby = ''; } displayToyMenu('cmd',toymenureqby); } else { cb.sendNotice('Cannot display, the ' + whichToy + ' Menu is disabled.', msguser, appNoticeColor); } break; } case '/usetoymenu': case '/usetoy': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { whichToyIcon = ':' + whichToy.toLowerCase() + 'sm'; setToyMenuToggle(msgarray[1], msguser) } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/uselush': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (whichToy == 'Lush') { cb.sendNotice('The toy type is already set to "lush", please enter a new toy type.',msguser,appNoticeColor); } else { whichToy = 'Lush'; whichToyIcon = ':lushsm'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "lush".',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/usenora': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (whichToy == 'Nora') { cb.sendNotice('The toy type is already set to "nora", please enter a new toy type.',msguser,appNoticeColor); } else { whichToy = 'Nora'; whichToyIcon = ':norasm'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "nora".',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/usedomi': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (whichToy == 'Domi') { cb.sendNotice('The toy type is already set to "domi", please enter a new toy type.',msguser,appNoticeColor); } else { whichToy = 'Domi'; whichToyIcon = ':domi-small-transparent'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "domi".',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/usehush': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (whichToy == 'Hush') { cb.sendNotice('The toy type is already set to "hush", please enter a new toy type.',msguser,appNoticeColor); } else { whichToy = 'Hush'; whichToyIcon = ':hushsm'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "hush".',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/useosci': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (whichToy == 'Osci') { cb.sendNotice('The toy type is already set to "osci", please enter a new toy type.',msguser,appNoticeColor); } else { whichToy = 'Osci'; whichToyIcon = ':oscism'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "osci".',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/useferri': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (whichToy == 'Ferri') { cb.sendNotice('The toy type is already set to "ferri", please enter a new toy type.',msguser,appNoticeColor); } else { whichToy = 'Ferri'; whichToyIcon = ':ferrism'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "ferri".',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/useedge': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (whichToy == 'Edge') { cb.sendNotice('The toy type is already set to "edge", please enter a new toy type.',msguser,appNoticeColor); } else { whichToy = 'Edge'; whichToyIcon = ':edgesm'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "edge".',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/usequake': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (whichToy == 'Quake') { cb.sendNotice('The toy type is already set to "quake", please enter a new toy type.',msguser,appNoticeColor); } else { whichToy = 'Quake'; whichToyIcon = ':quakesm'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "quake".',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/chgtoy': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1].toLowerCase() == whichToy.toLowerCase()) { cb.sendNotice('The toy type is already set to ' + whichToy + ', please enter a new toy type.',msguser,appNoticeColor); } else if (msgarray[1].toLowerCase() == 'lush') { whichToy = 'Lush'; whichToyIcon = ':lushsm'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "lush".',msguser,appNoticeColor); } else if (msgarray[1].toLowerCase() == 'domi') { whichToy = 'Domi'; whichToyIcon = ':domi-small-transparent'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "domi".',msguser,appNoticeColor); } else if (msgarray[1].toLowerCase() == 'nora') { whichToy = 'Nora'; whichToyIcon = ':norasm'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "nora".',msguser,appNoticeColor); } else if (msgarray[1].toLowerCase() == 'hush') { whichToy = 'Hush'; whichToyIcon = ':hushsm'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "hush".',msguser,appNoticeColor); } else if (msgarray[1].toLowerCase() == 'osci') { whichToy = 'Osci'; whichToyIcon = ':oscism'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "osci".',msguser,appNoticeColor); } else if (msgarray[1].toLowerCase() == 'ferri') { whichToy = 'Ferri'; whichToyIcon = ':ferrism'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "ferri".',msguser,appNoticeColor); } else if (msgarray[1].toLowerCase() == 'edge') { whichToy = 'Edge'; whichToyIcon = ':edgesm'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "edge".',msguser,appNoticeColor); } else if (msgarray[1].toLowerCase() == 'quake') { whichToy = 'Quake'; whichToyIcon = ':quakesm'; buildToyMenu(); cb.sendNotice('You have updated the toy to the "quake".',msguser,appNoticeColor); } else { cb.sendNotice('Invalid toy name, valid names are "lush", "nora", "domi", "hush", "ferri", "edge", "quake", and "osci". Therefore, syntax for command is "/chgtoy lush" (no quotes), please try again.',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } //********* Media List commands case '/media': { recognizedcmd = true; let mediasendto = msguser; if (ismodlvlmsg1 || msgisbc) { mediasendto = ''; } showMedia(mediasendto,'cmd'); break; } case '/usemedia': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1] != 'on' && msgarray[1] != 'off') { cb.sendNotice(msgarray[1] + ' is not a valid parameter option for /usemedia, the parameter should be "on" or "off".', msguser, appNoticeColor); } else { setMediaToggle(msgarray[1],msguser,true) } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } //********* Guest List commands case '/guest': case '/guests': { recognizedcmd = true; let guestsendto = msguser; if (ismodlvlmsg1 || msgisbc) { guestsendto = ''; } showGuests(guestsendto,'cmd'); break; } case '/useguest': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1] != 'on' && msgarray[1] != 'off') { cb.sendNotice(msgarray[1] + ' is not a valid parameter option for /useguest, the parameter should be "on" or "off".', msguser, appNoticeColor); } else if (msgarray[1] == 'on' && cb.settings.guestListEnable1 != 'Yes' && cb.settings.guestListEnable2 != 'Yes' && cb.settings.guestListEnable3 != 'Yes') { cb.sendNotice('Guest Info Notice cannot be turned on when no current guests are enabled.', msguser, appNoticeColor); } else { setGuestToggle(msgarray[1],msguser,true) } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } //********* Tip Response Commands case '/usetr': case '/usetipresponse': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1] != 'tipper' && msgarray[1] != 'all' && msgarray[1] != 'off') { cb.sendNotice(msgarray[1] + ' is not a valid parameter option for /usetipresponse, the parameter should be "tipper", "all", or "off".', msguser, appNoticeColor); } else { setTipResponseToggle(msgarray[1],msguser,true) } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } //********* Pre-sales Commands case '/fbpresale': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if ((msgarray[1] == 'on' || msgarray[1] == 'ON' || msgarray[1] == 'On') && enablePresales == 'Yes') { cb.sendNotice('Fembot pre-sales are already enabled.', msguser, appNoticeColor); } else if ((msgarray[1] == 'off' || msgarray[1] == 'OFF' || msgarray[1] == 'Off') && enablePresales == 'No') { cb.sendNotice('Fembot pre-sales are already disabled.', msguser, appNoticeColor); } else if ((msgarray[1] == 'on' || msgarray[1] == 'ON' || msgarray[1] == 'On') && enablePresales == 'No') { enablePresales = 'Yes'; cb.sendNotice('Fembot pre-sales have been enabled.', msguser, appNoticeColor); } else if ((msgarray[1] == 'off' || msgarray[1] == 'OFF' || msgarray[1] == 'Off') && enablePresales == 'Yes') { enablePresales = 'No'; cb.sendNotice('Fembot pre-sales have been disabled.', msguser, appNoticeColor); } else { cb.sendNotice('Invalid parameter for this command, valid values are "on" or "off".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case "/pslist": case "/presalelist": { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { cb.sendNotice(botName + ' Users currently on the Pre-sale Ticket List: ' + presaleArray.length, msguser, appNoticeColor); cb.sendNotice((presaleArray.length > 0 == true ? cbjs.arrayJoin(presaleArray, ', ') : 'No ticket buyers.'), msguser); cb.sendNotice('End of Pre-sale List', msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/useps': case '/usepresales': case '/usepresale': { recognizedcmd = true; if (enablePresales == 'Yes') { if (ismodlvlmsg2 || msgisbc) { if (presalePrice > 0) { if (ticketPrice > 0) { setPresalesToggle(msgarray[1], msguser); } else { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + ' 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } else { cb.sendNotice('Fembot pre-sales not started/ended as they are disabled. This is expected if UltraApp pre-sales are used.', msguser, appNoticeColor); } break; } case '/psprice': case '/presaleprice': { recognizedcmd = true; if (ismodlvlmsg3 || msgisbc) { if (enablePresales == 'Yes') { let presalenumprice = parseInt(msgarray[1]) if (isNaN(presalenumprice)) { cb.sendNotice('The value entered for the pre-sale ticket price is not numeric, please try again.', msguser, appNoticeColor); break; } else if (presalenumprice < 1 || presalenumprice > 1000) { cb.sendNotice('The value entered for the pre-sale ticket price is outside allowable values from 1 to 1000, please try again.', msguser, appNoticeColor); } else if (presalenumprice > 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]".', msguser, appNoticeColor); } else { if (presalenumprice < 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.', msguser, appNoticeColor); } if (presalesToggle) { presalePriceChange(presalenumprice,msguser); cb.sendNotice('The Pre-sale Ticket Price has been updated to ' + presalenumprice + ' 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.', msguser, appNoticeColor); } else { presalePrice = presalenumprice; cb.sendNotice('The Pre-sale Ticket Price has been set to ' + presalenumprice + ' tokens, and the pre-sale can now be started with the command "/usepresale on". ', msguser, appNoticeColor); } } } if (ticketShowType != 'Fembot Ticket Show' && backupToggle) { let presalenumprice2 = parseInt(msgarray[1]) if (!isNaN(presalenumprice2)) { setBackupTicketPrice(presalenumprice2,msguser); } } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/pspt': case '/presalepricetimer': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if (presalesToggle) { let validtimer = false; let pspnumtimer = parseInt(msgarray[1]) if (isNaN(pspnumtimer)) { 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.', msguser, appNoticeColor); } else if (pspnumtimer < 1 || pspnumtimer > 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.', msguser, 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.', msguser, appNoticeColor); } else { validtimer = true; } let pspnumprice = parseInt(msgarray[2]) if (isNaN(pspnumprice)) { cb.sendNotice('The new pre-sales price value entered for the price change timer is not numeric, please try again.', msguser, appNoticeColor); validtimer = false; } else if (pspnumprice < 1 || pspnumprice > 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.', msguser, appNoticeColor); validtimer = false; } else if (pspnumprice > ticketPrice) { cb.sendNotice('The new pre-sales price value entered of ' + pspnumprice + ' 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.', msguser, appNoticeColor); validtimer = false; } else { if (validtimer) { presaleMinsRemain = pspnumtimer; nextPresalePrice = pspnumprice; presaleAutoTimer(presaleMinsRemain); cb.sendNotice('The timer has been started to update the pre-sale price to ' + pspnumprice + ' tokens in ' + pspnumtimer + ' minutes.', msguser, 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/psstarttimer': case '/presalestarttimer': { recognizedcmd = true; if (presalesToggle) { if (ismodlvlmsg1 || msgisbc) { let psstnumtimer = parseInt(msgarray[1]) if (isNaN(psstnumtimer)) { cb.sendNotice('The value entered for the minutes to use for the pre-sale timer is not numeric, please try again.', msguser, appNoticeColor); break; } else if(psstnumtimer < 1 || psstnumtimer > 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.', msguser, appNoticeColor); } else { presaleMinsRemain = psstnumtimer; presaleAutoTimer(presaleMinsRemain); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.', msguser, appNoticeColor); } break; } case '/psat': case '/presaleaddtime': { recognizedcmd = true; if (presalesToggle) { if (ismodlvlmsg1 || msgisbc) { let psatnumtimer = parseInt(msgarray[1]) if (isNaN(psatnumtimer)) { cb.sendNotice('The value entered for the minutes to add to the pre-sale timer is not numeric, please try again.', msguser, appNoticeColor); break; } else if (psatnumtimer < 1 || psatnumtimer > 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.', msguser, appNoticeColor); } else { presaleAddTime(psatnumtimer, msguser); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.', msguser, appNoticeColor); } break; } case '/psstoptime': case '/presalestoptime': case '/presalestoptimer': { recognizedcmd = true; if (presalesToggle) { if (ismodlvlmsg1 || msgisbc) { stopPresaleTimer(msguser); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.', msguser, appNoticeColor); } break; } case '/expps': case '/exppresale': { recognizedcmd = true; if (enablePresales == 'Yes') { if (isPrivate) { cb.sendNotice('You are not able to use the /exppresale command while a private show is running.', msguser,appNoticeColor); } else { if (ismodlvlmsg2 || msgisbc) { if (presaleArray.length > 0) { if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { 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").', msguser, 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.', msguser, appNoticeColor); } } else { cb.sendNotice('No Pre-sale Ticket List to add.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } } } break; } case '/addps': case '/addpresale': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg1 && hiddenShowModsAdd)) { if (presalesToggle) { let addpscmdval = ''; if (msgcommand == '/addps') { addpscmdval = rawmsg.substring(7).trim(); } else if (msgcommand == '/addpresale') { addpscmdval = rawmsg.substring(12).trim(); } if (addpscmdval) { let addpscmdvalsplit = addpscmdval.split(listRegExp); if (addpscmdvalsplit.length > 1) { cb.sendNotice('Adding multiple users to the Pre-sale list.', msguser, appNoticeColor); for (let addpsidx = 0; addpsidx < addpscmdvalsplit.length; addpsidx++) { if (addpscmdvalsplit[addpsidx]) { let addpresalemultiuser = addpscmdvalsplit[addpsidx].toLowerCase(); if (addpresalemultiuser.charAt(0) == '@') { addpresalemultiuser = addpresalemultiuser.substring(1); } if (!cbjs.arrayContains(presaleArray,addpresalemultiuser)) { addRmvPresale('add',addpresalemultiuser,0,addpresalemultiuser); cb.sendNotice('Added ' + addpresalemultiuser + ' to the Pre-sale list.',msguser); cb.sendNotice(msguser + ' has added you to the Pre-sale list.',addpresalemultiuser,appNoticeColor); } else { cb.sendNotice(addpresalemultiuser + ' is already on the pre-sale list. Skipping.',msguser); } } } cb.sendNotice('All users were added and notified.', msguser, appNoticeColor) cb.sendNotice(msguser + ' has added multiple users to the pre-sale list.\n' + 'Users added: ' + cbjs.arrayJoin(addpscmdvalsplit, ', '), BC, appNoticeColor, '', 'normal', 'red'); } else { let addpresaleuser = msgarray[1].toLowerCase(); if (addpresaleuser.charAt(0) == '@') { addpresaleuser = addpresaleuser.substring(1); } if (!cbjs.arrayContains(presaleArray,addpresaleuser)) { addRmvPresale('add',addpresaleuser,0,addpresaleuser); } else { cb.sendNotice(addpresaleuser + ' is already on the pre-sale list.', msguser); } } } else { cb.sendNotice('You didn\'t specify what user(s) you want to add to the Pre-sale list.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + ' User not added to pre-sale ticket list, the Fembot Ticket Pre-sales feature is disabled.',msguser,appNoticeColor); } } break; } case '/rmvps': case '/rmvpresale': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg1 && hiddenShowModsAdd)) { if (presalesToggle) { if (msgarray[1]) { let rmvpresaleuser = msgarray[1].toLowerCase(); if (rmvpresaleuser.charAt(0) == '@') { rmvpresaleuser = rmvpresaleuser.substring(1); } if (cbjs.arrayContains(presaleArray,rmvpresaleuser)) { addRmvPresale('rmv',rmvpresaleuser,0,rmvpresaleuser); cb.sendNotice('User ' + rmvpresaleuser + ' has been removed from the Pre-Sale Ticket List.', msguser, appNoticeColor); } else { cb.sendNotice('Note: User is not in the Pre-Sale Ticket List.',msguser,appNoticeColor); } } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.',msguser,appNoticeColor); } } break; } case '/psmode': case '/chgpresalemode': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (presalesToggle) { let newpsmode = msgarray[1].toLowerCase(); if (newpsmode != 'manual' && newpsmode != 'timer' && newpsmode != 'count') { cb.sendNotice('The value entered for the new mode is not valid, please try again using a value of "manual", "timer", or "count".', msguser, appNoticeColor); } else { if (newpsmode == presaleMode) { cb.sendNotice('The value entered for the new mode is the same as the existing mode, command ignored.', msguser, appNoticeColor); } else { setPresaleMode(newpsmode,msguser); } } } else { cb.sendNotice('The Ticket Pre-sales feature is disabled.',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/pstimeleft': case '/presaletimeleft': { recognizedcmd = true; if (enablePresales == 'Yes') { if (ismodlvlmsg1 || msgisbc) { if (presaleMinsRemain >= 1 || presaleSecsRemain >= 1) { cb.sendNotice(presaleTimeLeft(), '', appWarningColor, '', boldTextLiteral); } else { cb.sendNotice('A pre-sale timer is not running.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } //********* Check Colors case '/checkcolor': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { let chkcolcmdval = rawmsg.substring(12).trim(); if (chkcolcmdval) { let chkcolcmdvalsplit = chkcolcmdval.split(listRegExpSpc); if (chkcolcmdvalsplit.length < 2 || chkcolcmdvalsplit.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', msguser, appNoticeColor); } else { if (chkcolcmdvalsplit[1]) { let temptesttextcolor = setTextColor(chkcolcmdvalsplit[1],'Color Test',msguser,false); let temptestbgcolor = setBgColor(chkcolcmdvalsplit[0],'Color Test',msguser,false); cb.sendNotice('This is your test message for Color Check.', msguser, temptestbgcolor, temptesttextcolor, boldTextLiteral) } } } else { cb.sendNotice('No Colors were specified.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //********* Dice Game commands case '/prizes': { recognizedcmd = true; if (diceToggle) { let dcpsendto = msguser; if (ismodlvlmsg1 || msgisbc) { dcpsendto = ''; } diceShowPrizes(dcpsendto); } else { cb.sendNotice('The dice game is not enabled.', msguser, appNoticeColor); } break; } case '/usedice': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { setDiceToggle(msgarray[1], msguser); } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/dicerollsold': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { diceShowRolls(BC); } diceShowRolls(msguser); break; } case '/chgdiceprice': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (diceToggle) { let chgdcnumprice = parseInt(msgarray[1]); if (isNaN(chgdcnumprice)) { cb.sendNotice('The value entered for the new Dice Roll price is not numeric, please try again.', msguser, appNoticeColor); } else if (chgdcnumprice < 1 || chgdcnumprice > 1000) { cb.sendNotice('The value entered for the new Dice Roll price is outside allowable values from 1 to 1000, please try again.', msguser, appNoticeColor); } else { diceRollPrice = chgdcnumprice; priceChecker('add','Dice Roll Price',diceRollPrice,msguser); cb.sendNotice(msguser + ' has updated the Dice Roll Price.', msguser, appNoticeColor); cb.sendNotice('The Dice Roll Price has been updated to ' + chgdcnumprice + ' tokens.', '', diceNoticeBgColor, diceRollTextColor, 'bold'); } } else { cb.sendNotice('The Dice Game has not been turned on, you can use the command "/usedice on" to enable it.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/freeroll': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (diceToggle) { cb.sendNotice(botName + msguser + ' has triggered a free roll for the dice game.', msguser, appNoticeColor); diceRoll(msguser); } else { cb.sendNotice(botName + 'The dice game is not enabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } //********* Time Locked Gray Chat commands case '/usegraylock': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { setGrayLockToggle(msgarray[1], msguser); } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/cleargraylock': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (grayLockToggle) { clearGrayLock(msguser); } 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/rmvgraylock': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (grayLockToggle) { if (!cbjs.arrayContains(grayLockList,msguser)) { addToLockList(msguser,msgisbc,ismodlvlmsg2,msgisfan,msgisgray); } addRmvGrayLock('r',msgarray[1],msguser); } 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/addgraylock': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (grayLockToggle) { if (!cbjs.arrayContains(grayLockList,msguser)) { addToLockList(msguser,msgisbc,ismodlvlmsg2,msgisfan,msgisgray); } addRmvGrayLock('a',msgarray[1],msguser); } 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/chggraytime': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (grayLockToggle) { let chggraynummin = parseInt(msgarray[1]); if (isNaN(chggraynummin)) { cb.sendNotice('The value entered for the new Gray Chat Time Threshold is not numeric, please try again.', msguser, appNoticeColor); } else if (chggraynummin < 1 || chggraynummin > 20) { cb.sendNotice('The value entered for the new Gray Chat Time Threshold is outside allowable values from 1 to 20, please try again.', msguser, appNoticeColor); } else { grayChatTime = chggraynummin; cb.sendNotice('You have updated the Gray Chat Time Threshold to ' + grayChatTime + ' minutes.', msguser, 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } //********* "Answer Required" Chat Lock commands case '/useanswerlock': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1] == 'on' || msgarray[1] == 'off') { setRequireAnswerToggle(msgarray[1],msguser,true); } else { cb.sendNotice('Invalid parameter for the /useanswerlock command, valid values are "on" and "off".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/clearanswerlock': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (requireAnswerToggle) { clearAnswerLock(); cb.sendNotice('You have cleared the "Answer Required" chat restriction list. The list will be rebuilt as users chat or enter the room.', msguser, 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 + '.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/setanswerlevel': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (requireAnswerToggle) { let setansnumlevel = parseInt(msgarray[1]); if (isNaN(setansnumlevel)) { cb.sendNotice('The value entered for the new "Answer Required" level is not numeric, please try again.', msguser, appNoticeColor); } else if (setansnumlevel < 0 || setansnumlevel > 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).', msguser, appNoticeColor); } else { requireAnswerLevel = setansnumlevel; if (requireAnswerLevel == 0) { setRequireAnswerToggle('off',msguser,true); } else if (requireAnswerLevel == 1) { requireAnswerLevelText = 'Gray Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 1=Gray Users.', msguser, appNoticeColor); } else if (requireAnswerLevel == 2) { requireAnswerLevelText = 'Light Blue Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 2=Light Blue Users.', msguser, appNoticeColor); } else if (requireAnswerLevel == 3) { requireAnswerLevelText = 'Dark Blue Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 3=Dark Blue Users.', msguser, appNoticeColor); } else if (requireAnswerLevel == 4) { requireAnswerLevelText = 'Light Purple Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 4=Light Purple Users.', msguser, appNoticeColor); } else if (requireAnswerLevel == 5) { requireAnswerLevelText = 'Dark Purple Users'; cb.sendNotice('You have updated the "Answer Required" lock level to 5=Dark Purple Users.', msguser, 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 + '.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } //********* Fembot Hidden Ticket Show Commands case '/tickets': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { var ticketlist = cb.limitCam_allUsersWithAccess(); if (ticketlist.length > 0) { if (msgarray[1] === 'a' || msgarray[1] === 'A' || msgarray[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', msguser, 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', msguser, appNoticeColor); } } else { cb.sendNotice('No ticket buyers yet.', msguser, appNoticeColor); } } break; } case '/useticketshow': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', msguser,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg2 || msgisbc) { if (ticketPrice > 0) { if(msgarray[1] != null && msgarray[1] != 'on' && msgarray[1] != 'off') { cb.sendNotice('The value ' + msgarray[1] + ' is not a valid option for /useticketshow, please try again.',msguser,appNoticeColor); } else if(msgarray[1] == null) { cb.sendNotice('You did not enter a valid option for /useticketshow, please try again.',msguser,appNoticeColor); } else { setTicketShowToggle(msgarray[1], msguser, 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, 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.', msguser, appNoticeColor); } } break; } case '/chgticketshow': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', msguser,appNoticeColor); } else { if (msgarray[1]) { if (ticketShowType == 'Fembot Ticket Show' && (msgarray[1] == 'fembot' || msgarray[1] == 'Fembot')) { cb.sendNotice('The ticket show type is already set to use the Fembot ticket feature, and not a separate ticket App.', msguser, appNoticeColor); } else if (ticketShowType == 'Separate Ticket App' && (msgarray[1] == 'other' || msgarray[1] == 'other')) { cb.sendNotice('The ticket show type is already set to use a separate ticket App, and not the Fembot.', msguser, appNoticeColor); } else { if (msgarray[1] == 'fembot' || msgarray[1] == 'Fembot') { ticketShowType = 'Fembot Ticket Show'; cb.sendNotice('The ticket show type has been updated to Fembot Ticket Show.', msguser, appNoticeColor); } else if (msgarray[1] == 'other' || msgarray[1] == 'Other') { ticketShowType = 'Separate Ticket App'; if (cb.limitCam_isRunning()) { cb.limitCam_stop(); cb.sendNotice('The Fembot Hidden Show has been disabled', msguser, 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.', msguser, 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".', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/useot': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { if (ismodlvlmsg2 || msgisbc) { if(msgarray[1] != null && msgarray[1] != 'on' && msgarray[1] != 'off') { cb.sendNotice('The value ' + msgarray[1] + ' is not a valid option for /useot, please try again.',msguser,appNoticeColor); } else if(msgarray[1] == null) { cb.sendNotice('You did not enter a valid option for /useot, please try again.',msguser,appNoticeColor); } else { setTicketShowOtToggle(msgarray[1], msguser); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } else { cb.sendNotice('The Ticket Show feature is disabled.', msguser, appNoticeColor); } } break; } case "/otlist": { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowOtToggle) { cb.sendNotice('Users currently on the Outstanding Ticket List: ' + outstandingTicketArray.length, msguser, appNoticeColor); cb.sendNotice((outstandingTicketArray.length > 0 == true ? cbjs.arrayJoin(outstandingTicketArray, ', ') : 'No outstanding ticket holders.'), msguser); cb.sendNotice('End of List', msguser, appNoticeColor); } else { cb.sendNotice('The Ticket Show Outstanding Ticket feature is disabled.', msguser, appNoticeColor); } } break; } case "/otchanges": { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { if (ismodlvlmsg1 || msgisbc) { if (otChangesArray.name.length > 0) { cb.sendNotice('Listing of Changes to the Outstanding Ticket List : ', msguser, appNoticeColor); let otcstring = ''; for (let otcidx = 0; otcidx < otChangesArray.name.length; otcidx++) { if (otChangesArray.name[otcidx] == null) { break } else { otcstring += (otcidx > 0 ? ',' : '') + otChangesArray.name[otcidx] + '(' + otChangesArray.type[otcidx] + ')'; } } cb.sendNotice(otcstring, msguser); cb.sendNotice('End of List', msguser, appNoticeColor); } else { cb.sendNotice('No entries have been added to the Outstanding Ticket Change list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } else { cb.sendNotice('The Ticket Show feature is disabled.', msguser, appNoticeColor); } } break; } case '/ctprice': case '/chgticketprice': case '/ticketprice': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg3 || msgisbc) { let ctpnumprice = parseInt(msgarray[1]) if (isNaN(ctpnumprice)) { cb.sendNotice('The value entered for the ticket price is not numeric, please try again.', msguser, appNoticeColor); break; } else if (ctpnumprice < 1 || ctpnumprice > 1000) { cb.sendNotice('The value entered for the ticket price is outside allowable values from 1 to 500, please try again.', msguser, appNoticeColor); } else { if (ticketShowToggle) { setTicketPrice(ctpnumprice,msguser,'yes'); cb.sendNotice('The Fembot Ticket Show price has been updated to ' + ctpnumprice + ' 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".', msguser, appNoticeColor); } else { ticketPrice = ctpnumprice; cb.sendNotice('The Ticket Price has been set to ' + ctpnumprice + ' tokens, and the ticket show feature can now be started with the command "/useticketshow on". ', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } } else { if (ismodlvlmsg1 || msgisbc) { let ctpnumprice2 = parseInt(msgarray[1]) if (!isNaN(ctpnumprice2) && backupToggle) { setBackupTicketPrice(ctpnumprice2,msguser); } } } break; } case '/starttickettimer': case '/ticketstarttimer': case '/starttimer': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { if (ismodlvlmsg1 || msgisbc) { let sttnumtimer = parseInt(msgarray[1]) if (isNaN(sttnumtimer)) { cb.sendNotice('The value entered for the minutes to use for the timer is not numeric, please try again.', msguser, appNoticeColor); break; } else if (sttnumtimer < 1 || sttnumtimer > 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.', msguser, appNoticeColor); } else { ticketMinsRemain = sttnumtimer; ticketStartMode = 'timer'; ticketAutoTimer(ticketMinsRemain); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.', msguser, appNoticeColor); } } break; } case '/addtickettime': case '/ticketaddtime': case '/addtime': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { if (ismodlvlmsg1 || msgisbc) { let attnumtimer = parseInt(msgarray[1]) if (isNaN(attnumtimer)) { cb.sendNotice('The value entered for the minutes to add to the ticket show start timer is not numeric, please try again.', msguser, appNoticeColor); } else if (attnumtimer < -60 || attnumtimer > 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.', msguser, appNoticeColor); } else if (attnumtimer == 0) { cb.sendNotice('Cannot add zero time.', msguser, appNoticeColor); } else if (attnumtimer < 0 && Math.abs(attnumtimer) > 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.', msguser, appNoticeColor); } else { ticketAddTime(attnumtimer, msguser); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.', msguser, appNoticeColor); } } break; } case '/ticketstoptime': case '/ticketstoptimer': case '/stoptimer': { recognizedcmd = true; if (ticketShowToggle) { if (ismodlvlmsg1 || msgisbc) { if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { stopTicketTimer(msguser); } else { cb.sendNotice('A ticket timer is not currently running.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.', msguser, appNoticeColor); } break; } case '/add': case '/addticket': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use the /add or /addticket commands while a private show is running.', msguser,appNoticeColor); } else { let addtktcmdval = ''; if (msgcommand == '/add') { addtktcmdval = rawmsg.substring(5).trim(); } else if (msgcommand == '/addticket') { addtktcmdval = rawmsg.substring(11).trim(); } if (ticketShowType == 'Fembot Ticket Show') { if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg1 && hiddenShowModsAdd)) { if (ticketShowToggle) { if (addtktcmdval) { let addtktcmdvalsplit = addtktcmdval.split(listRegExp); if (addtktcmdvalsplit.length > 1) { cb.sendNotice('Adding multiple users to the ticket show list.', msguser, appNoticeColor); for (let addtktidx = 0; addtktidx < addtktcmdvalsplit.length; addtktidx++) { if (addtktcmdvalsplit[addtktidx]) { let addticketmultiuser = addtktcmdvalsplit[addtktidx].toLowerCase(); if (addticketmultiuser.charAt(0) == '@') { addticketmultiuser = addticketmultiuser.substring(1); } if (!cb.limitCam_userHasAccess(addticketmultiuser)) { addRmvTicket('add', addticketmultiuser,'',0,addticketmultiuser); cb.sendNotice('Added ' + addticketmultiuser + ' to the ticket show list.', msguser); cb.sendNotice(msguser + ' has added you to the ticket show list.', addticketmultiuser, appNoticeColor); } else { cb.sendNotice(addticketmultiuser + ' is already on the ticket show list. Skipping.', msguser); } } } cb.sendNotice('All users were added and notified.', msguser, appNoticeColor) cb.sendNotice(msguser + ' has added multiple users to the ticket show list.\n' + 'Users added: ' + cbjs.arrayJoin(addtktcmdvalsplit, ', '), BC, appNoticeColor, '', 'normal', 'red'); } else { let addticketuser = msgarray[1].toLowerCase(); if (addticketuser.charAt(0) == '@') { addticketuser = addticketuser.substring(1); } if (!cb.limitCam_userHasAccess(addticketuser)) { addRmvTicket('add',addticketuser,'',0,addticketuser); } else { cb.sendNotice('Note: User ' + addticketuser + ' is already in the Ticket Show List.',msguser,appNoticeColor); } } } else { if (!cb.limitCam_userHasAccess(msguser)) { addRmvTicket('add',msguser,'',0,msguser); } else { cb.sendNotice('Note: User ' + msguser + ' is already in the Ticket Show List.',msguser,appNoticeColor); } } } else { cb.sendNotice('Note: User not added to ticket list, the Hidden Ticket Show feature is disabled.',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3A, msguser, appNoticeColor); } } else { if (backupToggle) { if (addtktcmdval) { let addtktcmdvalsplit2 = addtktcmdval.split(listRegExp); if (addtktcmdvalsplit2.length > 1) { cb.sendNotice('Adding multiple users to the Backup Ticket List.', msguser, appNoticeColor); for (let addtktbuidx = 0; addtktbuidx < addtktcmdvalsplit2.length; addtktbuidx++) { if (addtktcmdvalsplit2[addtktbuidx]) { let cmdvalmultibu = addtktcmdvalsplit2[addtktbuidx].toLowerCase(); if (cmdvalmultibu.charAt(0) == '@') { cmdvalmultibu = cmdvalmultibu.substring(1); } if (!cbjs.arrayContains(backupListArray, cmdvalmultibu)) { addRmvTicketBackupList('add',cmdvalmultibu); cb.sendNotice('User ' + cmdvalmultibu + ' has been added to the Backup Ticket List.', msguser, appNoticeColor); cb.sendNotice(msguser + ' has added you to the Backup Ticket List.', cmdvalmultibu, appNoticeColor); } else { cb.sendNotice(cmdvalmultibu + ' is already on the Backup Ticket List. Skipping.', msguser); } } } cb.sendNotice('All users were added and notified.', msguser, appNoticeColor) cb.sendNotice(msguser + ' has added multiple users to the Backup Ticket List.\n' + 'Users added: ' + cbjs.arrayJoin(addtktcmdvalsplit2, ', '), BC, appNoticeColor, '', 'normal', 'red'); } else { let cmdvalsinglebu = msgarray[1].toLowerCase(); if (cmdvalsinglebu.charAt(0) == '@') { cmdvalsinglebu = cmdvalsinglebu.substring(1); } addRmvTicketBackupList('add',cmdvalsinglebu); cb.sendNotice('User ' + cmdvalsinglebu + ' has been added to the Backup Ticket List.', msguser, appNoticeColor); } } else { addRmvTicketBackupList('add',msguser); cb.sendNotice('User ' + msguser + ' has been added to the Backup Ticket List.', msguser, appNoticeColor); } } else { cb.sendNotice('Note: User not added to backup ticket list, the Backup List is disabled.', msguser,appNoticeColor); } } } break; } case '/del': case '/delticket': case '/rmvticket': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg1 && hiddenShowModsAdd)) { if (ticketShowToggle) { if (msgarray[1]) { let rmvticketuser = msgarray[1].toLowerCase(); if (rmvticketuser.charAt(0) == '@') { rmvticketuser = rmvticketuser.substring(1); } if (cb.limitCam_userHasAccess(rmvticketuser)) { addRmvTicket('rmv',rmvticketuser,'',0,rmvticketuser); cb.sendNotice('User ' + rmvticketuser + ' has been removed from the Ticket Show List.', '', ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice('Note: User is not in the Ticket Show List.',msguser,appNoticeColor); } } else { cb.sendNotice('No user was specified for the /rmvticket command.',msguser,appNoticeColor); } } else { cb.sendNotice('The Hidden Ticket Show feature is disabled.',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3A,msguser,appNoticeColor); } } else { if (ismodlvlmsg1 || msgisbc) { if (backupToggle) { if (msgarray[1]) { let rmvticketuserbu = msgarray[1].toLowerCase(); if (rmvticketuserbu.charAt(0) == '@') { rmvticketuserbu = rmvticketuserbu.substring(1); } addRmvTicketBackupList('rmv',rmvticketuserbu); cb.sendNotice('User ' + rmvticketuserbu + ' has been removed from the Backup Ticket List.', msguser, appNoticeColor); } else { cb.sendNotice('No user was specified for the /rmvticket command.',msguser,appNoticeColor); } } } } break; } case '/giftticket': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', msguser,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { if (cb.settings.hiddenShowAllowGift == 'Yes') { if (cbjs.arrayContains(ticketShowExtraTickets.name,msguser)) { let giftidx = ticketShowExtraTickets.name.indexOf(msguser); if (ticketShowExtraTickets.count[giftidx] > 0) { if (msgarray[1]) { let gifttickettouser = msgarray[1].toLowerCase(); if (gifttickettouser.charAt(0) == '@') { gifttickettouser = gifttickettouser.substring(1); } giftTicket(msguser,gifttickettouser); ticketShowExtraTickets.count[giftidx]--; cb.sendNotice('You have gifted a ticket to ' + gifttickettouser + '. Thank you for your generosity.',msguser,appNoticeColor,'','bold'); cb.sendNotice('Mods: ' + msguser + ' has gifted a ticket to ' + gifttickettouser + '.',BC,appNoticeColor,'','','red'); cb.sendNotice('Broadcaster: ' + msguser + ' has gifted a ticket to ' + gifttickettouser + '.',BC,appNoticeColor); } else { cb.sendNotice('No user was specified for the /giftticket command.',msguser,appNoticeColor); } } else { cb.sendNotice('Sorry, you do not have any extra tickets remaining.',msguser,appNoticeColor); } } else { cb.sendNotice('Sorry, you have not purchased any extra tickets.',msguser,appNoticeColor); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the use of gifting tickets for this show.',msguser,appNoticeColor); } } else { cb.sendNotice('The Hidden Ticket Show feature is not currently active.',msguser,appNoticeColor); } } } break; } case '/givemyticketto': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', msguser,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { if (cb.settings.hiddenShowAllowGift == 'Yes') { if (cb.limitCam_userHasAccess(msguser) && showStage == 'ticketsales') { if (msgarray[1]) { let givetickettouser = msgarray[1].toLowerCase(); if (givetickettouser.charAt(0) == '@') { givetickettouser = givetickettouser.substring(1); } giveAwayTicket(msguser,givetickettouser); cb.sendNotice('You have gifted your ticket to ' + givetickettouser + '. You will now be removed from the show. Thank you for your generosity.',msguser,appNoticeColor,'','bold'); cb.sendNotice('Mods/Broadcaster: ' + msguser + ' has gifted their own ticket to ' + givetickettouser + '.',BC,appNoticeColor,'','','red'); } else { cb.sendNotice('No user was specified for the /givemyticketto command.',msguser,appNoticeColor); } } else { cb.sendNotice('Sorry, you do not have a ticket purchased or the show has already started.',msguser,appNoticeColor); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the gifting of tickets for this show.',msguser,appNoticeColor); } } else { cb.sendNotice('The Hidden Ticket Show feature is not currently active.',msguser,appNoticeColor); } } } break; } case '/chgticketmode': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg2 || msgisbc) { if (ticketShowToggle) { let chgtktnewmode = msgarray[1].toLowerCase(); if (chgtktnewmode != 'manual' && chgtktnewmode != 'timer' && chgtktnewmode != 'ticketgoal' && chgtktnewmode != 'tokengoal') { cb.sendNotice(botName + 'The value entered for the new mode is not valid, please try again using a value of "manual", "timer", "ticketgoal", or "tokengoal".', msguser, appNoticeColor); } else { if (chgtktnewmode == ticketStartMode) { cb.sendNotice(botName + 'The value entered for the new mode is the same as the existing mode, command ignored.', msguser, appNoticeColor); } else { setTicketMode(chgtktnewmode,msguser); } } } else { cb.sendNotice(botName + 'The Ticket Show feature is disabled.',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } break; } case '/chgtktauto': case '/chgticketmodeauto': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg2 || msgisbc) { if (ticketShowToggle) { let chgtktnewauto = msgarray[1].toLowerCase(); if (chgtktnewauto != 'bc' && chgtktnewauto != 'auto') { cb.sendNotice(botName + 'The value entered for the new mode is not valid, please try again using a value of "bc" or "auto".', msguser, appNoticeColor); } else if (chgtktnewauto == 'auto' && ticketStartMode == 'manual') { cb.sendNotice(botName + '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.', msguser, appNoticeColor); } else if (chgtktnewauto == ticketModeAuto) { cb.sendNotice(botName + 'The value entered for the new mode is the same as the existing mode, command ignored.', msguser, appNoticeColor); } else { setTicketAuto(chgtktnewauto); if (chgtktnewauto == 'bc') { cb.sendNotice(botName + 'You have updated the ticket show starting mode from "automatic" to now requiring the /startshow command entry from the broadcaster or moderator.', msguser, appNoticeColor); } else if (chgtktnewauto == 'auto') { cb.sendNotice(botName + 'You have updated the ticket show starting mode to automatic, the show will start when the goal is met or the timer expires.', msguser, appNoticeColor); } } } else { cb.sendNotice(botName + 'The Ticket Show feature is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } break; } case '/tickettimeleft': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { if (ticketMinsRemain >= 1 || ticketSecsRemain >= 1) { cb.sendNotice(ticketTimeLeft(), '', appWarningColor, '', boldTextLiteral); } else { cb.sendNotice(botName + 'A Ticket Show timer is not running.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'The Ticket Show feature is disabled.', msguser, appNoticeColor); } } break; } case '/showtime': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { if (cb.limitCam_isRunning()) { displayShowTime(msguser); } else { cb.sendNotice(botName + 'The ticket show is not running, it has not yet started or already finished.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'The Ticket Show feature is disabled.', msguser, appNoticeColor); } } break; } case '/useticket': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', msguser,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { if (cb.settings.enableHiddenShowOT == 'Yes') { if (!cb.limitCam_userHasAccess(msguser) && cbjs.arrayContains(outstandingTicketArray,msguser)) { useTicket(msguser); cb.sendNotice('Your outstanding ticket has been redeemed and you have been added to the ticket holders list for this show.',msguser,appNoticeColor,'','bold'); cb.sendNotice('Broadcaster: ' + msguser + ' has used their outstanding ticket. They should be removed from the permanent OT list on the bot start page.',BC,appNoticeColor); cb.sendNotice('Mods: ' + msguser + ' has used their outstanding ticket. The broadcaster has been notified to remove them from the permanent OT list on the bot start page.',BC,appNoticeColor,'','','red'); } else { cb.sendNotice('Sorry, you have no outstanding ticket available.',msguser,appNoticeColor); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the use of outstanding tickets for this show.',msguser,appNoticeColor); } } else { cb.sendNotice('The Hidden Ticket Show feature is not currently active.',msguser,appNoticeColor); } } } break; } case '/saveticket': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ticketShowToggle) { if (cb.settings.enableHiddenShowOT == 'Yes') { if (cb.limitCam_userHasAccess(msguser) && showStage == 'ticketsales') { saveTicket(msguser); cb.sendNotice('Your ticket from this show has been saved and you have been removed from the ticket list for this show.',msguser,appNoticeColor,'','bold'); cb.sendNotice('Broadcaster: ' + msguser + ' 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: ' + msguser + ' 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.',BC,appNoticeColor,'','','red'); } else { cb.sendNotice('Sorry, you have no ticket purchase to save, or the show has already started.',msguser,appNoticeColor); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the ability to save an outstanding tickets for this show.',msguser,appNoticeColor); } } else { cb.sendNotice('The Hidden Ticket Show feature is not currently active.',msguser,appNoticeColor); } } break; } case '/addot': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (cb.settings.enableHiddenShowOT == 'Yes') { if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg1 && hiddenShowModsAdd)) { if (ticketShowToggle) { if (msgarray[1]) { let addotuser = msgarray[1].toLowerCase(); if (addotuser.charAt(0) == '@') { addotuser = addotuser.substring(1); } if (!cbjs.arrayContains(outstandingTicketArray,addotuser)) { addRmvOutstandingTicket('add',addotuser); cb.sendNotice('User ' + addotuser + ' has been added to the Outstanding Ticket List.', msguser, appNoticeColor); } else { cb.sendNotice('Cannot add ' + addotuser + ', user is already in the Outstanding Ticket List.',msguser,appNoticeColor); } } else { cb.sendNotice('No user was specified for the /addot command.',msguser,appNoticeColor); } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3A, msguser,appNoticeColor); } } else { cb.sendNotice('Sorry, the broadcaster has not enabled the outstanding ticket show feature.',msguser,appNoticeColor); } } break; } case '/rmvot': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg1 && hiddenShowModsAdd)) { if (ticketShowToggle) { if (msgarray[1]) { let rmvotuser = msgarray[1].toLowerCase(); if (rmvotuser.charAt(0) == '@') { rmvotuser = rmvotuser.substring(1); } if (cbjs.arrayContains(outstandingTicketArray,rmvotuser)) { addRmvOutstandingTicket('rmv',rmvotuser); cb.sendNotice('User ' + rmvotuser + ' has been removed from the Outstanding Ticket List.', msguser, appNoticeColor); } else { cb.sendNotice('Cannot remove, user is not in the Outstanding Ticket List.',msguser,appNoticeColor); } } } else { cb.sendNotice('The Fembot Ticket Show feature is disabled.',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3A, msguser,appNoticeColor); } } break; } case '/startshow': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', msguser,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg2 || msgisbc) { if (ticketShowToggle) { if (!cb.limitCam_isRunning() && ticketShowEnded === false) { startTicketShow(msguser); if (presalesToggle) { setPresalesToggle('off',msguser); } } 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.', msguser, appNoticeColor); } else { cb.sendNotice('A Hidden Cam show is already underway.', msguser, appNoticeColor); } } else { cb.sendNotice('The Fembot ticket show has not been enabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } else { if (ismodlvlmsg2 || msgisbc) { if (tokenPollToggle && 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.', msguser, appNoticeColor); } else { let stshowtimetoadd = parseInt(cb.settings.startPollMinAfterShow) if (stshowtimetoadd <= 0) { stshowtimetoadd = 10; cb.sendNotice('No setting defined for token poll end timer, defaulting to 10 min.', msguser, appNoticeColor); } pollSwitchToTimer(stshowtimetoadd); } } else { cb.sendNotice('Note: Poll Timer not started with /startshow per configuration.', msguser,appNoticeColor); } if (presalesToggle) { setPresalesToggle('off',msguser); } } } } break; } case '/showover': case '/showwarn': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', msguser,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg2 || msgisbc) { if (cb.limitCam_isRunning()) { if (showStage == 'ticketshow') { warnShowEnding(msguser); } 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.', msguser, appNoticeColor); } } else { cb.sendNotice('The Hidden Cam show has not been started or has already ended.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } } break; } case '/showend': case '/stopsales': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', msguser,appNoticeColor); } else { if (ticketShowType === 'Fembot Ticket Show') { if (ismodlvlmsg2 || msgisbc) { if (cb.limitCam_isRunning()) { if (cb.settings.endPosMenuWithShow == 'Yes' && posTipMenuToggle) { setPosTipMenuToggle('off',msguser); } stopTicketSales(msguser); } else { cb.sendNotice('The Hidden Cam show has not been started or has already ended.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } else { if (ismodlvlmsg2 || msgisbc) { if (cb.settings.endPosMenuWithShow == 'Yes' && posTipMenuToggle) { setPosTipMenuToggle('off',msguser); } } } } break; } case '/stopshow': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', msguser,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg2 || msgisbc) { if (cb.limitCam_isRunning()) { if (cb.settings.endPosMenuWithShow == 'Yes' && posTipMenuToggle) { setPosTipMenuToggle('off',msguser); } stopTicketShow(msguser); } else { cb.sendNotice('The Hidden Cam show has not been started or has already ended.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } else { if (ismodlvlmsg1 || msgisbc) { if (cb.settings.endPosMenuWithShow == 'Yes' && posTipMenuToggle) { setPosTipMenuToggle('off',msguser); } } } } break; } case '/ticketsubject': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg1 || msgisbc) { ticketSubjectText = rawmsg.substring(15).trim(); if(ticketSubjectText != '' && ticketSubjectText != null) { changeTicketShowSubject(); } else { cb.sendNotice('No value was specified for the new room description.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/ctsubject': { recognizedcmd = true; if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg1 || msgisbc) { ticketSubjectText = rawmsg.substring(11).trim(); if(ticketSubjectText != '' && ticketSubjectText != null) { changeTicketShowSubject(); } else { cb.sendNotice('No value was specified for the new room description.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } break; } case '/newticketshow': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', msguser,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg2 || msgisbc) { 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 : ', BC, appNoticeColor); cb.sendNotice(cbjs.arrayJoin(ticketlist, ', '), BC); cb.sendNotice('End of List', BC, 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 : ', msguser, appNoticeColor); cb.sendNotice(cbjs.arrayJoin(ticketlist, ', '), msguser); cb.sendNotice('End of List', msguser, appNoticeColor); } } else { cb.sendNotice('No ticket buyers in the previous ticket list.', msguser, appNoticeColor); } initTicketShow(msguser,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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } } break; } case '/restartshow': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', msguser,appNoticeColor); } else { if (ticketShowType == 'Fembot Ticket Show') { if (ismodlvlmsg2 || msgisbc) { if (!cb.limitCam_isRunning()) { restartTicketShow(msguser); } 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } } break; } //********* Price Check List case '/pricechecklist': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if (priceCheckArray.name.length > 0) { cb.sendNotice('Alphabetic listing of Price Check Array entries : ', msguser, appNoticeColor); let pcchkstr = ''; for (let pcchkidx = 0; pcchkidx < priceCheckArray.name.length; pcchkidx++) { if (priceCheckArray.name[pcchkidx] == null) { pcchkstr += ' ' + pcchkidx + '. empty\n'; } else { pcchkstr += ' ' + (pcchkidx+1) + '. "' + priceCheckArray.name[pcchkidx] + '": ' + priceCheckArray.amount[pcchkidx] + '\n'; } } cb.sendNotice(pcchkstr,msguser); cb.sendNotice('End of List', msguser, appNoticeColor); } else { cb.sendNotice('No entries yet.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //********* Icon / Nicknames List case '/nnlist': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if (iconNicknamesArray.name.length > 0) { cb.sendNotice('Listing of Nickname entries : ', msguser, appNoticeColor); let nnstring = ''; for (let nnidx = 0; nnidx < iconNicknamesArray.name.length; nnidx++) { if (iconNicknamesArray.name[nnidx] == null) { nnstring += ' ' + (nnidx+1) + '. empty\n'; } else { nnstring += ' ' + (nnidx+1) + '. ' + iconNicknamesArray.name[nnidx] + ' / "' + iconNicknamesArray.icon[nnidx] + '" / ' + iconNicknamesArray.nickname[nnidx] + ' / ' + iconNicknamesArray.color[nnidx] + '\n'; } } cb.sendNotice(nnstring,msguser); cb.sendNotice('End of List',msguser,appNoticeColor); } else { cb.sendNotice('No entries yet.',msguser,appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1,msguser,appNoticeColor); } break; } case '/setusericon': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { let enteredisemoji = false; if (msgarray[2]) { enteredisemoji = checkEmoji(msgarray[2]); } if (!msgarray[1]) { cb.sendNotice('Parameter for user is not specified. \nCommand syntax is /setusericon username :iconname', msguser, appNoticeColor); } else if (!msgarray[2]) { cb.sendNotice('Parameter for icon/emoji is not specified. \nCommand syntax is /setusericon username :iconname', msguser, appNoticeColor); } else if (msgarray[2].substring(0,1) != ':' && !enteredisemoji && msgarray[2] != 'null') { cb.sendNotice('Parameter for icon/emoji does not start with a ":" and is not a browser recognized emoji character. \nCommand syntax is /setusericon username :iconname. \nThe value of "null" (lowercase, no quotes) can be used to remove an existing setting.', msguser, appNoticeColor); } else { let seticonuser = msgarray[1].toLowerCase(); if (seticonuser.charAt(0) == '@') { seticonuser = seticonuser.substring(1); } addUserIcon(msguser,seticonuser,msgarray[2]); } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } break; } case '/setusernn': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (!msgarray[1]) { cb.sendNotice('Parameter for user is not specified. \nCommand syntax is /setusernn username nickname', msguser, appNoticeColor); } else if (!msgarray[2]) { cb.sendNotice('Parameter for nickname is not specified. \nCommand syntax is /setusernn username nickname. \nThe value of "null" can be used to remove an existing setting.', msguser, appNoticeColor); } else { let nnlabel = ''; for (let nnlblidx = 2; nnlblidx < msgarray.length; nnlblidx++) { if (nnlblidx == 2) { nnlabel = msgarray[nnlblidx]; } else { nnlabel += ' ' + msgarray[nnlblidx]; } } let setnnuser = msgarray[1].toLowerCase(); if (setnnuser.charAt(0) == '@') { setnnuser = setnnuser.substring(1); } if (cbjs.arrayContains(iconNicknamesArray.name,setnnuser)) { let setnnidx = iconNicknamesArray.name.indexOf(setnnuser); if (nnlabel == 'null') { iconNicknamesArray.nickname[setnnidx] = null; cb.sendNotice('The nickname for user ' + setnnuser + ' has been cleared.', msguser, appNoticeColor); } else { iconNicknamesArray.nickname[setnnidx] = nnlabel; cb.sendNotice('The nickname for user ' + setnnuser + ' has been updated to "' + nnlabel + '".', msguser, appNoticeColor); } } else { iconNicknamesArray.name.push(setnnuser); iconNicknamesArray.icon.push(null); iconNicknamesArray.color.push(null); if (nnlabel == 'null') { iconNicknamesArray.nickname.push(null); cb.sendNotice('An entry has been added for user ' + setnnuser + ' with no nickname.', msguser, appNoticeColor); } else { iconNicknamesArray.nickname.push(nnlabel); cb.sendNotice('An entry has been added for user ' + setnnuser + ' with a nickname of "' + nnlabel + '".', msguser, appNoticeColor); } } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/setusercolor': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (!msgarray[1]) { cb.sendNotice('Parameter for user is not specified. \nCommand syntax is /setusercolor username #000000, where 000000 is a valid hex color', msguser, appNoticeColor); } else if (!msgarray[2]) { cb.sendNotice('Parameter for color is not specified. \nCommand syntax is /setusercolor username #000000, where 000000 is a valid hex color', msguser, appNoticeColor); } else if (msgarray[2].substring(0,1) != '#' && msgarray[2] != 'null') { cb.sendNotice('Parameter for color does not start with a "#" and is not "null". \nCommand syntax is /setusercolor username #000000, where 000000 is a valid hex color. \nThe value of "null" can be used to remove an existing setting.', msguser, appNoticeColor); } else { let setcoloruser = msgarray[1].toLowerCase(); if (setcoloruser.charAt(0) == '@') { setcoloruser = setcoloruser.substring(1); } if (cbjs.arrayContains(iconNicknamesArray.name,setcoloruser)) { let setclridx = iconNicknamesArray.name.indexOf(setcoloruser); if (msgarray[2] == 'null') { iconNicknamesArray.color[setclridx] = null; cb.sendNotice('The color for user ' + setcoloruser + ' has been cleared.', msguser, appNoticeColor); } else { iconNicknamesArray.color[setclridx] = msgarray[2]; cb.sendNotice('The color for user ' + setcoloruser + ' has been updated to ' + msgarray[2] + '.', msguser, appNoticeColor); } } else { iconNicknamesArray.name.push(setcoloruser); iconNicknamesArray.icon.push(null); iconNicknamesArray.nickname.push(null); if (msgarray[2] == 'null') { iconNicknamesArray.color.push(null); cb.sendNotice('An entry has been added for user ' + setcoloruser + ' with no color.', msguser, appNoticeColor); } else { iconNicknamesArray.color.push(msgarray[2]); cb.sendNotice('An entry has been added for user ' + setcoloruser + ' with a color of ' + msgarray[2] + '.', msguser, appNoticeColor); } } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/icontips': { recognizedcmd = true; if (iconTipAmountArray.length > 0) { if (ismodlvlmsg1 || msgisbc) { displayIconTipNotice(); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } else { cb.sendNotice('There are no Tip Amount icons configured.', msguser, appNoticeColor); } break; } case '/setmodicon': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (!msgarray[1]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setmodicon :iconname', msguser, appNoticeColor); } else if (msgarray[1].substring(0,1) != ':' && msgarray[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.', msguser, appNoticeColor); } else { if (msgarray[1] == 'null') { iconMods = null; cb.sendNotice('You have cleared the CB Moderator group icon.', msguser, appNoticeColor); } else { iconMods = msgarray[1]; cb.sendNotice('You have updated the CB Moderator group icon to "' + iconMods + '".', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/setbotmodicon': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (!msgarray[1]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setbotmodicon :iconname', msguser, appNoticeColor); } else if (msgarray[1].substring(0,1) != ':' && msgarray[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.', msguser, appNoticeColor); } else { if (msgarray[1] == 'null') { iconBotMods = null; cb.sendNotice('You have cleared the Bot Mod group icon.', msguser, appNoticeColor); } else { iconBotMods = msgarray[1]; cb.sendNotice('You have updated the Bot Mod group icon to "' + iconBotMods + '".', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/setfanicon': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (!msgarray[1]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setfanicon :iconname', msguser, appNoticeColor); } else if (msgarray[1].substring(0,1) != ':' && msgarray[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.', msguser, appNoticeColor); } else { if (msgarray[1] == 'null') { iconFans = null; cb.sendNotice('You have cleared the CB Fan Club group icon.', msguser, appNoticeColor); } else { iconFans = msgarray[1]; cb.sendNotice('You have updated the CB Fan Club group icon to "' + iconFans + '".', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/setextfanicon': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (!msgarray[1]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setextfanicon :iconname', msguser, appNoticeColor); } else if (msgarray[1].substring(0,1) != ':' && msgarray[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.', msguser, appNoticeColor); } else { if (msgarray[1] == 'null') { iconExtFans = null; cb.sendNotice('You have cleared the External Fan Club 1 group icon.', msguser, appNoticeColor); } else { iconExtFans = msgarray[1]; cb.sendNotice('You have updated the External Fan Club 1 group icon to "' + iconExtFans + '".', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/setextfan2icon': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (!msgarray[1]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setextfan2icon :iconname', msguser, appNoticeColor); } else if (msgarray[1].substring(0,1) != ':' && msgarray[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.', msguser, appNoticeColor); } else { if (msgarray[1] == 'null') { iconExtFans2 = null; cb.sendNotice('You have cleared the External Fan Club 2 group icon.', msguser, appNoticeColor); } else { iconExtFans2 = msgarray[1]; cb.sendNotice('You have updated the External Fan Club 2 group icon to "' + iconExtFans2 + '".', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/setvipicon': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (!msgarray[1]) { cb.sendNotice('Parameter for icon is not specified. Command syntax is /setvipicon :iconname', msguser, appNoticeColor); } else if (msgarray[1].substring(0,1) != ':' && msgarray[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.', msguser, appNoticeColor); } else { if (msgarray[1] == 'null') { iconVIP = null; cb.sendNotice('You have cleared the VIP group icon.', msguser, appNoticeColor); } else { iconVIP = msgarray[1]; cb.sendNotice('You have updated the VIP group icon to "' + iconVIP + '".', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } //********* All Time Tipper List case '/usealltime': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1] == null || msgarray[1] == '') { cb.sendNotice('You did not enter a valid option for /usealltime, the option should be "on" or "off".', msguser, appNoticeColor); } else if (msgarray[1] != 'on' && msgarray[1] != 'off') { cb.sendNotice(msgarray[1] + ' is not a valid option for /usealltime, the option should be "on" or "off".', msguser, appNoticeColor); } else { setAllTimeToggle(msgarray[1],msguser); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', msguser, appNoticeColor); } break; } case '/useking': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1] != '0' && msgarray[1] != '1' && msgarray[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).', msguser, appNoticeColor); } else if (msgarray[1] == '0') { setKingTipperFlag('0',msguser,true); } else if (msgarray[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; } setKingTipperFlag('1',msguser,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).', msguser, appNoticeColor); } } else { setKingTipperFlag('1',msguser,true); } } else if (msgarray[1] == '2') { if (allTimeArray.name.length > 0) { setKingTipperFlag('2',msguser,true); } else { cb.sendNotice('The King Tipper cannot be enabled with a setting of "2" if the All Time Tipper list is empty.', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/king': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { let kingamount = parseInt(msgarray[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.', msguser, appNoticeColor); } else if (!msgarray[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.', msguser, appNoticeColor); } else { kingTipperName = msgarray[2].toLowerCase(); if (kingTipperName.charAt(0) == '@') { kingTipperName = kingTipperName.substring(1); } kingTipperAmount = kingamount; cb.sendNotice('You have updated the All Time King Tipper as ' + kingTipperName + ' with an amount of ' + kingTipperAmount + ' tokens.', msguser, appNoticeColor); if (msguser != BC) { cb.sendNotice(msguser + ' updated the All Time King Tipper as ' + kingTipperName + ' with an amount of ' + kingTipperAmount + ' tokens.', BC, appNoticeColor); } if (kingTipperFlag == 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".', BC, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/dsptop10': case '/top10': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { buildAllTimeArray(); var alltimesendto = msguser; if (allTimeArray.name.length > 0) { if (ismodlvlmsg1 || msgisbc) { alltimesendto = ''; } displayAllTimeLeaders(alltimesendto); } else { cb.sendNotice('There are no entries in the all-time tipper list, and no one has tipped at least ' + allTimeMinThreshold + ' tokens in the current show.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/listalltime': case '/alltimelist': case '/alltime': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { buildAllTimeArray(); if (allTimeArray.name.length > 0) { displayAllTime(msguser); } else { cb.sendNotice('There are no entries in the all-time tipper list, and no one has tipped at least ' + allTimeMinThreshold + ' tokens in the current show.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //********* Privates Response Message case '/prv': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { cb.sendNotice(checkNextLine(cb.settings.prvResponseMessage), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //********* Command Response Messages case '/rsp1': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { cb.sendNotice(checkNextLine(cb.settings.commandResponse1), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/rsp2': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { cb.sendNotice(checkNextLine(cb.settings.commandResponse2), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/rsp3': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { cb.sendNotice(checkNextLine(cb.settings.commandResponse3), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/rsp4': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { cb.sendNotice(checkNextLine(cb.settings.commandResponse4), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/rsp5': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { cb.sendNotice(checkNextLine(cb.settings.commandResponse5), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/dsprsp': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { let 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, msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //********* On-demand Privates case '/startprivate': { recognizedcmd = true; if (isPrivate) { cb.sendNotice('You are not able to use this command while a private show is running.', msguser,appNoticeColor); } else { if (msgisbc) { if(msgarray[1] != '' && msgarray[1] != null) { goPrivate(msgarray[1]); } else { cb.sendNotice('No value was specified for the user name to take private.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBC, msguser, appNoticeColor); } } break; } case '/endprivate': case '/stopprivate': { recognizedcmd = true; if (!isPrivate) { cb.sendNotice('You are not able to use this command unless a private show is running.', msguser,appNoticeColor); } else { if (msgisbc) { stopPrivate(); } else { cb.sendNotice(noticeOnlyBC, msguser, appNoticeColor); } } break; } //********* Suppress Caps Toggle case '/nocaps': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { if(msgarray[1] == null || msgarray[1] == '') { cb.sendNotice('You did not enter a valid option for /nocaps, the option should be "on" or "off".', msguser, appNoticeColor); } else if (msgarray[1] != 'on' && msgarray[1] != 'off') { cb.sendNotice(msgarray[1] + ' is not a valid option for /nocaps, the option should be "on" or "off".', msguser, appNoticeColor); } else { setCapsToggle(msgarray[1], msguser); } } else { cb.sendNotice('Only moderators and broadcasters are able to use that command.', msguser, appNoticeColor); } break; } //********* Followers case '/followers': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { displayFollowerStats(msguser); } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/fmt': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { let newflwnotflg = parseInt(msgarray[1]); if (isNaN(newflwnotflg)) { 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.', msguser, appNoticeColor); } else if (newflwnotflg < 0 || newflwnotflg > 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.', msguser, appNoticeColor); } else if (followerNotifyFlag == newflwnotflg) { cb.sendNotice('The follower message type is already set to "' + followerNotifyFlag + '".', msguser, appNoticeColor); } else { followerNotifyFlag = newflwnotflg; 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.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/fc': { recognizedcmd = true; displayFollowerTotal(msguser); break; } //********* Room Stats & User Stats case '/roomstats': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { displayRoomStats(msguser); } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/userstats': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { displayUserStats(msguser); } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } //********* Help Menu case '/fbhelp': { recognizedcmd = true; if (ismodlvlmsg1 || msgisbc) { helpModBC(msgarray[1],msguser); } else { helpCommon(msguser); } break; } case '/help': { recognizedcmd = true; let helpcmdtext = 'The Dorothy Apps and Bots each have their own help command, please use a specific one:'; helpcmdtext += '\n/fbhelp - Dorothy\'s Ultra Fembot'; cb.sendNotice(helpcmdtext, msguser, appNoticeColor); break; } //********* Dump config settings case '/settings': { recognizedcmd = true; if (ismodlvlmsg2 || msgisbc) { if (msgarray[1] == null){msgarray[1] = '';} switch(msgarray[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.',msguser,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 : ' + cb.settings.modLevel + '\n0G. botModList : ' + cb.settings.botModList + '\n0H1. noticeSepStyle : ' + cb.settings.noticeSepStyle + '\n0H2. separatorEmoji : initial : ' + cb.settings.separatorEmoji + ' : current : ' + borderChar ,msguser); 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 ,msguser); 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 + '"' ,msguser); 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 + '\n3H1. kingTipperHighlight : ' + cb.settings.kingTipperHighlight + '\n3H2. kingTipperBgColor : ' + cb.settings.kingTipperBgColor + '\n3H3. kingTipperBgCustColor : ' + cb.settings.kingTipperBgCustColor + '\n3J1. kingTipperNotice : ' + cb.settings.kingTipperNotice + '\n3J2. kingTipperInterval : ' + cb.settings.kingTipperInterval + '\n3J3. kingTipperTextColor : ' + cb.settings.kingTipperTextColor + '\n3J4. kingTipperTextCustColor : ' + cb.settings.kingTipperTextCustColor + '\n3J5. kingTipperNoticeColor : ' + cb.settings.kingTipperNoticeColor + '\n3J6. kingTipperNoticeCustColor : ' + cb.settings.kingTipperNoticeCustColor + '\n3L. kingSessionEnable : ' + cb.settings.kingSessionEnable + '\n3M. kingSessionMinAmount : ' + cb.settings.kingSessionMinAmount + '\n3N. kingSessionIcon : ' + cb.settings.kingSessionIcon + '\n3P1. kingSessionInterval : ' + cb.settings.kingSessionInterval + '\n3P2. kingSessionTextColor : ' + cb.settings.kingSessionTextColor + '\n3P3. kingSessionTextCustColor : ' + cb.settings.kingSessionTextCustColor + '\n3P4. kingSessionNoticeColor : ' + cb.settings.kingSessionNoticeColor + '\n3P5. kingSessionNoticeCustColor : ' + cb.settings.kingSessionNoticeCustColor ,msguser); 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 ,msguser); 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 ,msguser); 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 ,msguser); 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 + '"' + '\n7L1. iconTipNotice : ' + cb.settings.iconTipNotice + '\n7L2. 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 ,msguser); break; } case 'vip': { cb.sendNotice( 'Dump of all current settings for VIP list:' + '\n8B. VIPList : ' + cb.settings.VIPList + '\n8C. VIPname : ' + cb.settings.VIPname + '\n8D1. announceVIP : ' + cb.settings.announceVIP + '\n8D2. announceVIPtext : ' + cb.settings.announceVIPtext + '\n8D3. announceVIPTo : ' + cb.settings.announceVIPTo + '\n8F. joinVIPSingleTip : ' + cb.settings.joinVIPSingleTip + '\n8G. joinVIPCumulativeShow : ' + cb.settings.joinVIPCumulativeShow + '\n8H. joinVIPCumulativeAllTime : ' + cb.settings.joinVIPCumulativeAllTime + '\n8J. iconVIP : "' + cb.settings.iconVIP + '"' + '\n8K. VIPHighlight : ' + cb.settings.VIPHighlight + '\n8L. VIPBgCustColor : ' + cb.settings.VIPBgCustColor ,msguser); break; } case 'extfans': { cb.sendNotice( 'Dump of all current settings for External Fan Clubs 1 and 2:' + '\n******************* Fan Club 1 **************************' + '\n9B. extFanList : ' + cb.settings.extFanList + '\n9C. EFCname : ' + cb.settings.EFCname + '\n9D1.announceExtFans : ' + cb.settings.announceExtFans + '\n9D2.announceExtFanstext : ' + cb.settings.announceExtFanstext + '\n9D3. announceExtFansTo : ' + cb.settings.announceExtFansTo + '\n9F. iconExtFans : "' + cb.settings.iconExtFans + '"' + '\n9G. efcHighlight : ' + cb.settings.efcHighlight + '\n9H. efcBgCustColor : ' + cb.settings.efcBgCustColor + '\n******************* Fan Club 2 **************************' + '\n9K. extFanList2 : ' + cb.settings.extFanList2 + '\n9L. EFCname2 : ' + cb.settings.EFCname2 + '\n9M1. announceExtFans2 : ' + cb.settings.announceExtFans2 + '\n9M2. announceExtFanstext2 : ' + cb.settings.announceExtFanstext2 + '\n9M3. announceExtFansTo : ' + cb.settings.announceExtFansTo + '\n9P. iconExtFans2 : "' + cb.settings.iconExtFans2 + '"' + '\n9Q. efcHighlight2 : ' + cb.settings.efcHighlight2 + '\n9R. efcBgCustColor2 : ' + cb.settings.efcBgCustColor2 ,msguser); break; } case 'blocked': { cb.sendNotice( 'Dump of all current settings for chat controls:' + '\n10A. enableWordList : ' + cb.settings.enableWordList + '\n10B. wordBlockList : ** Private Blocked Word List intentionally hidden **' + '\n10D. blockedLevelPriv : ' + cb.settings.blockedLevelPriv + '\n10E. wordBlockListPub : ' + cb.settings.wordBlockListPub + '\n10F. showBlockedMsgsPub : ' + cb.settings.showBlockedMsgsPub + '\n10G. blockedLevelPub : ' + cb.settings.blockedLevelPub ,msguser); break; } case 'tipmenu1': { cb.sendNotice( 'Dump of all current settings for the Tip Menu:' + '\n11A. tipMenuNoticeType : ' + cb.settings.tipMenuNoticeType + '\n11B. menuDspInt : ' + cb.settings.menuDspInt + '\n11C. alertBCWhenReq : ' + cb.settings.alertBCWhenReq + '\n11D. listSort : ' + cb.settings.listSort + '\n11E1. sepchar : ' + cb.settings.sepchar + '\n11E2. sepcharcustom : ' + cb.settings.sepcharcustom + '\n11E3. sepInResponse : ' + cb.settings.menutxtcolor1 + '\n11F. includeDiceRollPrice : ' + cb.settings.menutxtcolor1 + '\n11G. menutxtcolor1 : ' + cb.settings.menutxtcolor1 + '\n11H. menuCustTxtColor1 : ' + cb.settings.menuCustTxtColor1 + '\n11J. menubgcolor1 : ' + cb.settings.menubgcolor1 + '\n11K. menuCustBgColor1 : ' + cb.settings.menuCustBgColor1 + '\n11L. menutxtcolor2 : ' + cb.settings.menutxtcolor2 + '\n11M. menuCustTxtColor2 : ' + cb.settings.menuCustTxtColor2 + '\n11N. menubgcolor2 : ' + cb.settings.menubgcolor2 + '\n11P. menuCustBgColor2 : ' + cb.settings.menuCustBgColor2 + '\n11Q. enableTipMenu : ' + cb.settings.enableTipMenu + '\n11R1. tipMenuSalePct : ' + cb.settings.tipMenuSalePct + '\n11R2. tipMenuModSalePct : ' + cb.settings.tipMenuModSalePct + '\n11R3. tipMenuCBFCSalePct : ' + cb.settings.tipMenuCBFCSalePct + '\n11R4. tipMenuEFC1SalePct : ' + cb.settings.tipMenuEFC1SalePct + '\n11R5. tipMenuEFC2SalePct : ' + cb.settings.tipMenuEFC2SalePct + '\n11R6. tipMenuVIPSalePct : ' + cb.settings.tipMenuVIPSalePct + '\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 ,msguser); break; } case 'tipmenu2': { cb.sendNotice( 'Dump of all current settings for Tip Menu 2:' + '\n11S. enableTipMenu2 : ' + cb.settings.enableTipMenu2 + '\n11T. tipMenu2SalePct : ' + 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 ,msguser); break; } case 'positions': { cb.sendNotice( 'Dump of all current settings for positions menu:' + '\n12A. enablePosTipMenu : ' + cb.settings.enablePosTipMenu + '\n12B. posMenuInterval : ' + cb.settings.posMenuInterval + '\n12C. posListSort : ' + cb.settings.posListSort + '\n12D1. posSepChar : ' + cb.settings.posSepChar + '\n12D2. posSepCharCustom : ' + cb.settings.posSepCharCustom + '\n12D3. posSepInResponse : ' + cb.settings.posSepInResponse + '\n12F. posMenuTxtColor : ' + cb.settings.posMenuTxtColor + '\n12G. posMenuCustTxtColor : ' + cb.settings.posMenuCustTxtColor + '\n12H. posMenuBgColor : ' + cb.settings.posMenuBgColor + '\n12J. posMenuCustBgColor : ' + 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 ,msguser); break; } case 'poll': { cb.sendNotice( 'Dump of all current settings for token poll:' + '\n13A. enableTokenPoll : ' + cb.settings.enableTokenPoll + '\n13B. pollTitle : ' + cb.settings.pollTitle + '\n13C. pollInterval : ' + cb.settings.pollInterval + '\n13D. pollMode : ' + cb.settings.pollMode + '\n13E. pollCount : ' + cb.settings.pollCount + '\n13F. pollMinimum : ' + cb.settings.pollMinimum + '\n13G. pollTxtColor : ' + cb.settings.pollTxtColor + '\n13H. pollCustTxtColor : ' + cb.settings.pollCustTxtColor + '\n13J. pollBgColor : ' + cb.settings.pollBgColor + '\n13K. pollCustBgColor : ' + cb.settings.pollCustBgColor + '\n13L. pollFanClubDouble : ' + cb.settings.pollFanClubDouble + '\n13M. pollKeepalive : ' + cb.settings.pollKeepalive + '\n13N. pollModAdd : ' + cb.settings.pollModAdd + '\n13P. stealPollAmount : ' + 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 + '\n13R. pollSepBot : ' + cb.settings.pollSepBot ,msguser); 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 ,msguser); 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 ,msguser); 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 ,msguser); break; } case 'dice': { cb.sendNotice( 'Dump of all current settings for the dice game:' + '\n******************* Dice Game *************************' + '\ndiceRollPrice : ' + cb.settings.diceRollPrice + '\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 ,msguser); 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 ,msguser); 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 ,msguser); 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 ,msguser); 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.',msguser,appNoticeColor); break; } } } else { cb.sendNotice(noticeOnlyBCMod2,msguser,appNoticeColor); } } } //********* End of Expected commands if (cbjs.arrayContains(exemptDorothyCmdList,msgcommand)) { recognizedcmd = true; } else if (msgcommand.substring(0,8) == '/setgoal' || msgcommand.substring(0,9) == '/setcount' || msgcommand.substring(0,7) == '/setjar' || msgcommand.substring(0,7) == '/setseq' || msgcommand.substring(0,13) == '/setspankgoal' || msgcommand.substring(0,11) == '/setspank1p' || msgcommand.substring(0,11) == '/setspank2p' || msgcommand.substring(0,11) == '/setspank3p' || msgcommand.substring(0,11) == '/setspank4p' || msgcommand.substring(0,11) == '/setspank5p' || msgcommand.substring(0,13) == '/setspanktype' || msgcommand == '/previewers') { recognizedcmd = true; } else if (cbjs.arrayContains(exemptCmdList,msgcommand)) { recognizedcmd = true; } if (!recognizedcmd) { cb.sendNotice(msgcommand + ' is not a recognized Fembot, UltraApp, or Gamebot command.\nType "/fbhelp" to see a full list of the available Fembot commands.', msguser, appNoticeColor); } } var silencedmsg = 0; // ********** Suppress messages containing Private blocked word - this check is first so the broadcaster always knows if someone uses a private blocked word if (silencedmsg == 0 && cb.settings.enableWordList == 'Yes' && wordListArray.length > 0) { let checkblocklist = false; if (cb.settings.blockedLevelPriv == 'All Users' && !msgisbc) { checkblocklist = true; } else if (cb.settings.blockedLevelPriv == 'All Users Except Mods' && !ismodlvlmsg1 && !msgisbc) { checkblocklist = true; } else if (cb.settings.blockedLevelPriv == 'All Users Except Mods/Fans/VIPs' && !ismodlvlmsg1 && !msgisbc && !msgisfan && !msgisvip && !msgisextfan1 && !msgisextfan2) { checkblocklist = true; } else if (cb.settings.blockedLevelPriv == 'Only Light Blue and Gray Users' && !ismodlvlmsg1 && !msgisbc && !msgisfan && !msgisvip && !msgisextfan1 && !msgisextfan2 && !msgisdarkblue && !msgisdarkpurple && !msgislightpurple) { checkblocklist = true; } else if (cb.settings.blockedLevelPriv == 'Gray Users Only' && msgisgray) { checkblocklist = true; } if (checkblocklist) { let privmsgary = rawmsg.split(' '); for (var blockindex = 0; blockindex < privmsgary.length; blockindex++) { let messagearywordprv = privmsgary[blockindex]; if (checkASCII(messagearywordprv)) { messagearywordprv = messagearywordprv.toLowerCase(); } if (cbjs.arrayContains(wordListArray,messagearywordprv)) { silencedmsg = 1; if (cb.settings.autoSilencePriv == 'Auto-silence') { if (cbjs.arrayContains(silenceListArray,msguser)) { cb.sendNotice(botName + '@' + msguser + ' has used a word from the Private Blocked list, but they are already silenced.',BC,appNoticeColor); } else { silenceListArray.push(msguser); cb.sendNotice(botName + '@' + msguser + ' has been added to the silence list for using a word from the Private Blocked word list, per setting "10D".\nThey have not been notified, but they will told that they are silenced when they attempt to chat again.\nMessage: ' + rawmsg + '\nYou can allow them to chat again with the command: /unsilence @' + msguser,BC,appNoticeColor); } } else if (cb.settings.autoSilencePriv == 'Quarantine') { if (cbjs.arrayContains(quarantineArray,msguser)) { cb.sendNotice(botName + '@' + msguser + ' has used a word from the Private Blocked list, but they are already quarantined.', BC, appNoticeColor); } else { quarantineArray.push(msguser); cb.sendNotice(botName + '@' + msguser + ' has been added to the quarantine list for using a word from the Private Blocked word list, per setting "10D".\nMessage: ' + rawmsg + '\nThey have not been notified, and they can still currently chat. \nYou can move the quarantine list to the silence list with the command: /qsil. \nTo see all quarantine commands, type: /fbhelp quar',BC,appNoticeColor); } } else { cb.sendNotice(botName + ' Blocked Private Word List message from user ("10D" set to Notification Only): @' + msguser + ' : ' + rawmsg,BC,red); } } } } } //********* Suppress for Gray Chat Time-Lock if (silencedmsg == 0 && grayLockToggle && !ismodlvlmsg1 && !msgisbc && !msgisnice && !msgisfan && !msgisvip && !msgisextfan1 && !msgisextfan2 && msgisgray) { if (!grayLockCheck(msguser,msgisbc,ismodlvlmsg1,msgisfan,msgisgray)) { var left = grayTimeLeft(msguser); silencedmsg = 1; cb.sendNotice('Your message was not sent because gray chat is time-locked and you have ' + left + ' minute' + (left === 1 ? '' : 's') + ' remaining.',msguser,appNoticeColor); } } //********* Suppress for Answer locked users if (silencedmsg == 0 && requireAnswerToggle) { if (!msgisbc && !ismodlvlmsg1 && !msgisfan && !msgisextfan1 && !msgisextfan2 && !msgisvip) { if (cbjs.arrayContains(answerLockList,msguser)) { if (answerLockStatus[answerLockList.indexOf(msguser)] === false) { silencedmsg = 1; } } } } // ********** Suppress non-English/ASCII characters if (silencedmsg == 0 && cb.settings.restrictChar == 'Allow English keyboard only' && !ismodlvlmsg1 && !msgisbc && !msgisfan && !msgisvip && !msgisextfan1 && !msgisextfan2) { if (!checkASCII(rawmsg)) { cb.sendNotice('Your Message was not sent. The broadcaster has disabled non-English keyboard characters and emojis.', msguser, appWarningColor); silencedmsg = 1; } } if (silencedmsg == 0 && cb.settings.restrictChar == 'Allow English keyboard plus emojis' && !ismodlvlmsg1 && !msgisbc && !msgisfan && !msgisvip && !msgisextfan1 && !msgisextfan2) { if (!checkASCII(rawmsg) && !checkEmoji(rawmsg)) { cb.sendNotice('Your Message was not sent. The broadcaster has disabled non-English keyboard characters.', msguser, appWarningColor); silencedmsg = 1; } } //********* Suppress for Silence Level if (silencedmsg == 0 && silenceLevel > 0 && !ismodlvlmsg1 && !msgisbc && !msgisnice && !msgisfan && !msgisvip && !msgisextfan1 && !msgisextfan2) { switch (silenceLevel) { case 1: if (msgisgray) { silencedmsg = 1; cb.sendNotice('Your message was not sent because the silence level has been set to only allow members with tokens to chat.',msguser,appNoticeColor); } break; case 2: if (!cbjs.arrayContains(tipCountArray.name,msguser)) { 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.',msguser,appNoticeColor); } break; case 3: if (cbjs.arrayContains(tipCountArray.name,msguser)) { if (parseInt(tipCountArray.amount[findTipper(msguser)]) < 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.',msguser,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.',msguser,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!',msguser,appNoticeColor); break; } } //********* Suppress for already being Ninja'd or Silenced if (silencedmsg == 0 && cbjs.arrayContains(ninjaListArray,msguser) && !ismodlvlmsg1 && !msgisbc) { silencedmsg = 1; if (showNinjadMsgs == 'Broadcaster only') { cb.sendNotice(botName + 'Chat message from ninja silenced user @' + msguser + ' : ' + rawmsg,BC,appNoticeColor); } else if (showNinjadMsgs == 'Mods only') { cb.sendNotice(botName + 'Chat message from ninja silenced user @' + msguser + ' : ' + rawmsg,BC,appNoticeColor,'','','red'); } else if (showNinjadMsgs == 'Broadcaster and Mods') { cb.sendNotice(botName + 'Chat message from ninja silenced user @' + msguser + ' : ' + rawmsg,BC,appNoticeColor); cb.sendNotice(botName + 'Chat message from ninja silenced user @' + msguser + ' : ' + rawmsg,BC,appNoticeColor,'','','red'); } } if (silencedmsg == 0 && cbjs.arrayContains(silenceListArray,msguser) && !ismodlvlmsg1 && !msgisbc) { silencedmsg = 1; cb.sendNotice('Your message was not sent because you have been silenced.',msguser,appNoticeColor); if (showSilencedMsgs == 'Broadcaster only') { cb.sendNotice(botName + 'Chat message from silenced user @' + msguser + ' : ' + rawmsg,BC,appNoticeColor); } else if (showSilencedMsgs == 'Mods only') { cb.sendNotice(botName + 'Chat message from silenced user @' + msguser + ' : ' + rawmsg,BC,appNoticeColor,'','','red'); } else if (showSilencedMsgs == 'Broadcaster and Mods') { cb.sendNotice(botName + 'Chat message from silenced user @' + msguser + ' : ' + rawmsg,BC,appNoticeColor); cb.sendNotice(botName + 'Chat message from silenced user @' + msguser + ' : ' + rawmsg,BC,appNoticeColor,'','','red'); } } if (silencedmsg == 0 && silencePrefixList.length > 0 && !ismodlvlmsg1 && !msgisbc && !msgisnice && !msgisfan && !msgisvip && !msgisextfan1 && !msgisextfan2) { for (let spfxidx = 0; spfxidx < silencePrefixList.length; spfxidx++) { let pfxmatchlength = silencePrefixList[spfxidx].length; if (msguser.substring(0,(pfxmatchlength)) == silencePrefixList[spfxidx]) { addRmvSilence(msguser,'add'); silencedmsg = 1; } } } // ********** Suppress messages containing Bot blocked words and silence or quarantine user if (silencedmsg == 0 && !ismodlvlmsg1 && !msgisbc && !msgisnice && !msgisfan && !msgisvip && !msgisextfan1 && !msgisextfan2) { let botblockarray = rawmsg.split(' '); for (let bblkidx = 0; bblkidx < botblockarray.length; bblkidx++) { let botblockword = botblockarray[bblkidx]; if (checkASCII(botblockword)) { botblockword = botblockword.toLowerCase(); } if (cbjs.arrayContains(botBlockList,botblockword)) { if (cb.settings.autoSilenceBots == 'Auto-silence') { silencedmsg = 1; if (cbjs.arrayContains(silenceListArray,msguser)) { cb.sendNotice(botName + 'Likely spam bot @' + msguser + ' has already been silenced.',BC,appNoticeColor); cb.sendNotice(botName + 'Likely spam bot @' + msguser + ' has already been silenced.',BC,appNoticeColor,'','','red'); } else { silenceListArray.push(msguser); cb.sendNotice(botName + 'Likely spam bot added to silence list: @' + msguser + '\nMessage: ' + rawmsg + '\nIf this is a mistake, you can allow them to chat again with the command: /unsilence @' + msguser,BC,appNoticeColor); cb.sendNotice(botName + 'Likely spam bot added to silence list: @' + msguser + '\nMessage: ' + rawmsg + '\nIf this is a mistake, you can allow them to chat again with the command: /unsilence @' + msguser,BC,appNoticeColor,'','','red'); } } else if (cb.settings.autoSilenceBots == 'Quarantine') { if (cbjs.arrayContains(quarantineArray,msguser)) { cb.sendNotice(botName + 'Likely spam bot @' + msguser + ' has already been quarantined. \nYou can move all quarantined users to the silenced List with the command: /qsil', BC, appNoticeColor); cb.sendNotice(botName + 'Likely spam bot @' + msguser + ' has already been quarantined. \nYou can move all quarantined users to the silenced List with the command: /qsil', BC, appNoticeColor,'','','red'); } else if (cbjs.arrayContains(silenceListArray,msguser)) { cb.sendNotice(botName + 'Likely spam bot @' + msguser + ' has already been silenced: /qsil', BC, appNoticeColor); cb.sendNotice(botName + 'Likely spam bot @' + msguser + ' has already been silenced: /qsil', BC, appNoticeColor,'','','red'); } else { quarantineArray.push(msguser); cb.sendNotice(botName + 'Likely spam bot added to quarantine list: @' + msguser + '\nMessage: ' + rawmsg + '\nThey can still currently chat. To see quarantine commands, type: /fbhelp quar',BC,appNoticeColor); cb.sendNotice(botName + 'Likely spam bot added to quarantine list: @' + msguser + '\nMessage: ' + rawmsg + '\nThey can still currently chat. To see quarantine commands, type: /fbhelp quar',BC,appNoticeColor,'','','red'); cb.sendNotice(botName + 'You have been quarantined until the broadcaster or a moderator determines if you should be silenced or released.', msguser, appNoticeColor); } } else { silencedmsg = 1; cb.sendNotice(botName + 'Likely spam bot ("10J" set to Notification Only): @' + msguser + '\nMessage: ' + rawmsg,BC,appNoticeColor); cb.sendNotice(botName + 'Likely spam bot ("10J" set to Notification Only): @' + msguser + '\nMessage: ' + rawmsg,BC,appNoticeColor,'','','red'); } } } } // ********** Suppress messages containing Public blocked words if (silencedmsg == 0 && cb.settings.enableWordList == 'Yes' && wordListArrayPub.length > 0) { let checkpubblocklist = false; if (cb.settings.blockedLevelPub == 'All Users' && !msgisbc) { checkpubblocklist = true; } else if (cb.settings.blockedLevelPub == 'All Users Except Mods' && !ismodlvlmsg1 && !msgisbc) { checkpubblocklist = true; } else if (cb.settings.blockedLevelPub == 'All Users Except Mods/Fans/VIPs' && !ismodlvlmsg1 && !msgisbc && !msgisfan && !msgisvip && !msgisextfan1 && !msgisextfan2) { checkpubblocklist = true; } else if (cb.settings.blockedLevelPub == 'Only Light Blue and Gray Users' && !ismodlvlmsg1 && !msgisbc && !msgisfan && !msgisvip && !msgisextfan1 && !msgisextfan2 && !msgisdarkblue && !msgisdarkpurple && !msgislightpurple) { checkpubblocklist = true; } else if (cb.settings.blockedLevelPub == 'Gray Users Only' && msgisgray) { checkpubblocklist = true; } if (checkpubblocklist) { let pubmsgary = rawmsg.split(' '); let pubmsgaryorig = rawmsg.split(' '); for (let pblockindex = 0; pblockindex < pubmsgary.length; pblockindex++) { let messagearyword = pubmsgary[pblockindex]; if (checkASCII(messagearyword)) { messagearyword = messagearyword.toLowerCase(); } if (cbjs.arrayContains(wordListArrayPub,messagearyword)) { if (showBlockedMsgsPub == 'Swap Word') { pubmsgaryorig[pblockindex] = cb.settings.blockedPubSwapWord; msg.m = cbjs.arrayJoin(pubmsgaryorig,' '); } else { if (cb.settings.autoSilencePub == 'Auto-silence') { silencedmsg = 1; cb.sendNotice(botName + ' Your message was not displayed because it contains words in the blocked word list.', msguser, appNoticeColor); if (cbjs.arrayContains(silenceListArray,msguser)) { if (showBlockedMsgsPub == 'Display to Broadcaster only') { cb.sendNotice(botName + '@' + msguser + ' has used a word from the Public Blocked Word list, but they are already silenced.',BC,appNoticeColor); } else if (showBlockedMsgsPub == 'Display to Broadcaster and Moderators') { cb.sendNotice(botName + '@' + msguser + ' has used a word from the Public Blocked Word list, but they are already silenced.',BC,appNoticeColor); cb.sendNotice(botName + '@' + msguser + ' has used a word from the Public Blocked Word list, but they are already silenced.',BC,appNoticeColor,'','','red'); } } else { silenceListArray.push(msguser); if (showBlockedMsgsPub == 'Display to Broadcaster only') { cb.sendNotice(botName + '@' + msguser + ' has been added to the silence list for using a word from the Public Blocked Word list.\nMessage: ' + rawmsg + '\nYou can allow them to chat again with the command: /unsilence @'+ msguser,BC,appNoticeColor); } else if (showBlockedMsgsPub == 'Display to Broadcaster and Moderators') { cb.sendNotice(botName + '@' + msguser + ' has been added to the silence list for using a word from the Public Blocked Word list.\nMessage: ' + rawmsg + '\nYou can allow them to chat again with the command: /unsilence @'+ msguser,BC,appNoticeColor); cb.sendNotice(botName + '@' + msguser + ' has been added to the silence list for using a word from the Public Blocked Word list.\nMessage: ' + rawmsg + '\nYou can allow them to chat again with the command: /unsilence @'+ msguser,BC,appNoticeColor,'','','red'); } } } else if (cb.settings.autoSilencePub == 'Quarantine') { if (cbjs.arrayContains(quarantineArray,msguser)) { if (showBlockedMsgsPub == 'Display to Broadcaster only') { cb.sendNotice(botName + '@' + msguser + ' has used a word from the Public Blocked Word list, but they are already quarantined.',BC,appNoticeColor); } else if (showBlockedMsgsPub == 'Display to Broadcaster and Moderators') { cb.sendNotice(botName + '@' + msguser + ' has used a word from the Public Blocked Word list, but they are already quarantined.',BC,appNoticeColor); cb.sendNotice(botName + '@' + msguser + ' has used a word from the Public Blocked Word list, but they are already quarantined.',BC,appNoticeColor,'','','red'); } } else { quarantineArray.push(msguser); if (showBlockedMsgsPub == 'Display to Broadcaster only') { cb.sendNotice(botName + '@' + msguser + ' has been added to the quarantine list for using a word from the Public Blocked Word list.\nMessage: ' + rawmsg + '\nThey can still currently chat. To see quarantine commands, type: /fbhelp quar',BC,appNoticeColor); } else if (showBlockedMsgsPub == 'Display to Broadcaster and Moderators') { cb.sendNotice(botName + '@' + msguser + ' has been added to the quarantine list for using a word from the Public Blocked Word list.\nMessage: ' + rawmsg + '\nThey can still currently chat. To see quarantine commands, type: /fbhelp quar',BC,appNoticeColor); cb.sendNotice(botName + '@' + msguser + ' has been added to the quarantine list for using a word from the Public Blocked Word list.\nMessage: ' + rawmsg + '\nThey can still currently chat. To see quarantine commands, type: /fbhelp quar',BC,appNoticeColor,'','','red'); } } } else { silencedmsg = 1; if (showBlockedMsgsPub == 'Display to Broadcaster only') { cb.sendNotice(botName + ' Blocked Public Word List message ("10H" set to Notification Only) from user: @' + msguser + '\nMessage: ' + rawmsg,BC,appNoticeColor); } else if (showBlockedMsgsPub == 'Display to Broadcaster and Moderators') { cb.sendNotice(botName + ' Blocked Public Word List message ("10H" set to Notification Only) from user: @' + msguser + '\nMessage: ' + rawmsg,BC,appNoticeColor); cb.sendNotice(botName + ' Blocked Public Word List message ("10H" set to Notification Only) from user: @' + msguser + '\nMessage: ' + rawmsg,BC,appNoticeColor,'','','red'); } } } } } } } //********* Graphic Level if (silencedmsg == 0 && graphicLevel > 0 && !ismodlvlmsg1 && !msgisbc && !msgisnice && !msgisfan && !msgisvip && !msgisextfan1 && !msgisextfan2) { switch(graphicLevel) { case 1: if (msgisgray) { for (let glchkidx1 = 0; glchkidx1 < msgarray.length; glchkidx1++) { if (msgarray[glchkidx1].charAt(0) == ':' && msgarray[glchkidx1].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.',msguser,appNoticeColor); } } } break; case 2: if (!cbjs.arrayContains(tipCountArray.name,msguser)) { for (let glchkidx2 = 0; glchkidx2 < msgarray.length; glchkidx2++) { if (msgarray[glchkidx2].charAt(0) == ':' && msgarray[glchkidx2].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.',msguser,appNoticeColor); } } } break; case 3: if (cbjs.arrayContains(tipCountArray.name,msguser)) { if (parseInt(tipCountArray.amount[findTipper(msguser)]) < minTipToChat) { for (let glchkidx3a = 0; glchkidx3a < msgarray.length; glchkidx3a++) { if (msgarray[glchkidx3a].charAt(0) == ':' && msgarray[glchkidx3a].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.',msguser,appNoticeColor); } } } } else { for (let glchkidx3b = 0; glchkidx3b < msgarray.length; glchkidx3b++) { if (msgarray[glchkidx3b].charAt(0) == ':' && msgarray[glchkidx3b].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.',msguser,appNoticeColor); } } } break; case 4: for (let glchkidx4 = 0; glchkidx4 < msgarray.length; glchkidx4++) { if (msgarray[glchkidx4].charAt(0) == ':' && msgarray[glchkidx4].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.',msguser,appNoticeColor); } } break; } } // ********** Auto-responses for configured words if (silencedmsg == 0 && (enableAutoResponse == 'Respond to All Users' || (enableAutoResponse == 'Respond to Users with Tokens' && !msgisgray))) { let tempautomessage = rawmsg.toLowerCase(); if (autoResponse1) { if (tempautomessage.includes(autoResponseWord1.toLowerCase())) { if (!checkRecentAutoResponse('auto1')) { cb.setTimeout(sendAutoResponse1Delay, 500); } } } if (autoResponse2) { if (tempautomessage.includes(autoResponseWord2.toLowerCase())) { if (!checkRecentAutoResponse('auto2')) { cb.setTimeout(sendAutoResponse2Delay, 500); } } } if (autoResponse3) { if (tempautomessage.includes(autoResponseWord3.toLowerCase())) { if (!checkRecentAutoResponse('auto3')) { cb.setTimeout(sendAutoResponse3Delay, 500); } } } } // ********** PM and Private Request Auto Response, Convert to lower case if (silencedmsg == 0 && !ismodlvlmsg1 && !msgisbc && !msgisfan && !msgisvip && !msgisextfan1 && !msgisextfan2) { let temprawmessage = rawmsg.toLowerCase(); if (sendPMResponse) { if (temprawmessage.includes('pm')) { if (!temprawmessage.includes('tipmenu') && !temprawmessage.includes('equipment')) { if (!checkRecentAutoResponse('PM')) { cb.setTimeout(sendPMResponseDelay, 500); } } } } if (sendPvtResponse && !msgisgray) { if (temprawmessage.includes('private') || temprawmessage.includes('pvt') || temprawmessage.includes('prv')) { if (!checkRecentAutoResponse('private')) { cb.setTimeout(sendPrivateResponseDelay, 500); } } } if (suppressCapsToggle) { let capscount = 0; let capsmsgary = []; capsmsgary = rawmsg.split(' '); for (let capschkindex = 0; capschkindex < capsmsgary.length; capschkindex++) { let capswordtest = capsmsgary[capschkindex]; if (caps.test(capswordtest) && capswordtest.substring(0,1) != ':') { capscount++; } } if (capsmsgary.length > 0) { let capspercent = capscount/capsmsgary.length; if (capspercent > 0.5) { msg.m = rawmsg.toLowerCase(); cb.sendNotice('Message converted to lower case, please do not type in all or mostly CAPS!', msguser, appNoticeColor); } } } } // ********** Add nickname if needed if (!suppressPrefix && silencedmsg == 0) { if (cbjs.arrayContains(iconNicknamesArray.name,msguser) || msguser == kingTipperName) { if (msgcommand.charAt(0) != '/' && msgcommand.charAt(0) != '!') { let pfxnickname = null; if (cbjs.arrayContains(iconNicknamesArray.name,msguser)) { let nicknameindex = iconNicknamesArray.name.indexOf(msguser); if (iconNicknamesArray.nickname[nicknameindex] != '' && iconNicknamesArray.nickname[nicknameindex] != null) { pfxnickname = '[' + iconNicknamesArray.nickname[nicknameindex] + '] '; } } if (msguser == 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,msguser)) { if (msgcommand.charAt(0) != '/' && msgcommand.charAt(0) != '!') { let tiparycount = 0; let pfxcount = null; if (tipCountToggle && cbjs.arrayContains(tipCountArray.name,msguser)) { tiparycount = parseInt(tipCountArray.amount[findTipper(msguser)]); if (tiparycount > 0) { pfxcount = '\u2507' + tipCountArray.amount[findTipper(msguser)] + '\u2507 '; } } if (pfxcount != null) { msg.m = pfxcount + ' ' + msg.m; } } } } // ********** Add quarantine prefix if needed if (silencedmsg == 0) { if (cbjs.arrayContains(quarantineArray,msguser)) { if (msgcommand.charAt(0) != '/' && msgcommand.charAt(0) != '!') { msg.m = ' --Quarantined User-- ' + msg.m; } } } // ********** Add tip based icon if needed if (!suppressPrefix && silencedmsg == 0) { if (cbjs.arrayContains(tipCountArray.name,msguser) || msguser == kingTipperName || cbjs.arrayContains(allTimeArray.name,msguser)) { if (msgcommand.charAt(0) != '/' && msgcommand.charAt(0) != '!') { let pfxtipleader = null; if (tipLeaderIconsToggle && cbjs.arrayContains(tipCountArray.name,msguser)) { sortTippers(); for (var tipIconIdx = 1; tipIconIdx <= tipCountArray.name.length; tipIconIdx++) { if (tipCountArray.name[tipIconIdx-1] == msguser) { break; } } let userlbposn = tipIconIdx; if (userlbposn >= 1 && userlbposn <= 3) { switch (userlbposn) { 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,msguser) && alltimeIconArray.amount.length > 0) { let useralltimelevel = 0; let amtindex = allTimeArray.name.indexOf(msguser); let useralltimetips = allTimeArray.totaltips[amtindex]; for (let levelindex = 0; levelindex < alltimeIconArray.amount.length; levelindex++) { if (useralltimetips < alltimeIconArray.amount[levelindex]) { break; } else { useralltimelevel++; } } if (useralltimelevel > 0) { pfxtipleader = alltimeIconArray.icon[useralltimelevel - 1]; } } if (msguser == kingTipperName) { if (cb.settings.kingTipperIcon) { pfxtipleader = cb.settings.kingTipperIcon; } } else if (msguser == 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 (msgisbc || ismodlvlmsg1 || msgisfan || msgisvip || msgisextfan1 || msgisextfan2 || cbjs.arrayContains(iconNicknamesArray.name,msguser) || cbjs.arrayContains(tipForIconArray.name,msguser) || (themeIconsToggle == 1 && (msgisdarkblue || msgislightpurple || msgisdarkpurple)) ) { if (msgcommand.charAt(0) != '/' && msgcommand.charAt(0) != '!') { let pfxgrpicon = null; if (groupIconsToggle || themeIconsToggle == 1) { if (msgisbotmod && iconBotMods) { pfxgrpicon = iconBotMods; } else if (msgiscbmod && iconMods) { pfxgrpicon = iconMods; } else if (msgisbc && iconBC) { pfxgrpicon = iconBC; } else if (msgisfan && iconFans) { pfxgrpicon = iconFans; } else if (cbjs.arrayContains(extFanListArray,msguser) && iconExtFans) { pfxgrpicon = iconExtFans; } else if (cbjs.arrayContains(extFanList2Array,msguser) && iconExtFans2) { pfxgrpicon = iconExtFans2; } else if (cbjs.arrayContains(VIPListArray,msguser) && iconVIP) { pfxgrpicon = iconVIP; } else if (msgisdarkpurple && iconDarkPurple) { pfxgrpicon = iconDarkPurple; } else if (msgislightpurple && iconLightPurple) { pfxgrpicon = iconLightPurple; } else if (msgisdarkblue && iconDarkBlue) { pfxgrpicon = iconDarkBlue; } } let iconindex = 0; if (cbjs.arrayContains(iconNicknamesArray.name,msguser)) { iconindex = iconNicknamesArray.name.indexOf(msguser); if (iconNicknamesArray.icon[iconindex]) { pfxgrpicon = iconNicknamesArray.icon[iconindex]; } } else if (cbjs.arrayContains(tipForIconArray.name,msguser)) { iconindex = tipForIconArray.name.indexOf(msguser); if (tipForIconArray.icon[iconindex]) { pfxgrpicon = tipForIconArray.icon[iconindex]; } } if (pfxgrpicon != null) { msg.m = pfxgrpicon + ' ' + msg.m; } } } } // Highlight background for Ticket show users, mods, and King Tipper if (msgishidden) { msg.background = commandBgColor; } else if (cb.settings.kingTipperHighlight == 'Yes' && msguser == kingTipperName) { msg.background = kingTipperBgColor; } else if (cb.settings.moderatorHighlight == 'Yes' && ismodlvlmsg1) { msg.background = moderatorBgColor; } else if (cb.settings.fanclubHighlight == 'Yes' && msgisfan) { msg.background = fanclubBgColor; } else if (cb.settings.efcHighlight == 'Yes' && msgisextfan1) { msg.background = efcBgColor; } else if (cb.settings.efcHighlight2 == 'Yes' && msgisextfan2) { msg.background = efcBgColor2; } else if (cb.settings.VIPHighlight == 'Yes' && msgisvip) { msg.background = vipBgColor; } else if (cb.limitCam_userHasAccess(msguser) && ticketShowToggle) { msg.background = ticketHolderBgColor; } // Set message text color if defined if (cbjs.arrayContains(iconNicknamesArray.name,msguser)) { let textcolorindex = iconNicknamesArray.name.indexOf(msguser); if (iconNicknamesArray.color[textcolorindex] != '' && iconNicknamesArray.color[textcolorindex] != null) { let msgtextcolor = setTextColor(iconNicknamesArray.color[textcolorindex],'User Chat Text Color',BC); msg.c = msgtextcolor; } } if(silencedmsg == 1) { msg['X-Spam'] = true; } return msg; }); // *********************************** Actions on user entering ************************************** cb.onEnter(function(user) { // Variables let enteruser = user.user; let enterismod = user.is_mod; let enterisbotmod = false; let enterisbc = (enteruser === BC); let enterisfan = user.in_fanclub; let enterisgray = false; let enterisdarkblue = false; let enterislightblue = false; let enterislightpurple = false; let enterisdarkpurple = false; let enterisextfan1 = cbjs.arrayContains(extFanListArray,enteruser); let enterisextfan2 = cbjs.arrayContains(extFanList2Array,enteruser); let enterisvip = cbjs.arrayContains(VIPListArray,enteruser); if (user.tipped_tons_recently) { enterisdarkpurple = true; } else if (user.tipped_alot_recently) { enterislightpurple = true; } else if (user.tipped_recently) { enterisdarkblue = true; } else if (user.has_tokens) { enterislightblue = true; } else if (!user.has_tokens) { enterisgray = true; } if (enterismod) { populateModeratorArray(enteruser,'cbmod','a'); } else { if (cbjs.arrayContains(moderatorList.name,enteruser)) { let modnameidx = moderatorList.name.indexOf(enteruser); if (moderatorList.type[modnameidx] == 'botmod') { enterisbotmod = true; enterismod = true; } else if (moderatorList.type[modnameidx] == 'cbmod') { populateModeratorArray(enteruser,'cbmod','r'); } } } if (enterisvip && !cbjs.arrayContains(VIPInShowArray,enteruser)) { VIPInShowArray.push(enteruser); } if (enterisextfan1 && !cbjs.arrayContains(extFanInShowArray,enteruser)) { extFanInShowArray.push(enteruser); } if (enterisextfan2 && !cbjs.arrayContains(extFanInShow2Array,enteruser)) { extFanInShow2Array.push(enteruser); } if (enterisfan) { populateFanClubArray(enteruser); } if(cb.limitCam_userHasAccess(enteruser)) { if (!cbjs.arrayContains(ticketShowViewerList,enteruser)) { ticketShowViewerList.push(enteruser); } } if ((viewerNotesWhen == 'First Entry' || viewerNotesWhen == 'Every Entry') && cbjs.arrayContains(viewerNotesArray.username,enteruser)) { let vnoteidx = viewerNotesArray.username.indexOf(enteruser); if (viewerNotesWhen == 'Every Entry' || !viewerNotesArray.displayed[vnoteidx]) { cb.sendNotice('Fembot Viewer Notes for @' + viewerNotesArray.username[vnoteidx] + ': ' + viewerNotesArray.notes[vnoteidx], BC, '', '', boldTextLiteral); viewerNotesArray.displayed[vnoteidx] = true; if (viewerNotesWho == 'Display to Broadcaster and Moderators') { cb.sendNotice('Fembot Viewer Notes for @' + viewerNotesArray.username[vnoteidx] + ': ' + viewerNotesArray.notes[vnoteidx], BC, '', '', boldTextLiteral, 'red'); } } } if (letMeKnowListArray.length > 0) { if (cbjs.arrayContains(letMeKnowListArray,enteruser)) { if (cb.settings.letMeKnowSendTo == 'Broadcaster Only' || cb.settings.letMeKnowSendTo == 'Broadcaster and Moderators') { cb.sendNotice(botName + 'Letting you know that @' + enteruser + ' has entered the room', BC, '', '', boldTextLiteral); } if (cb.settings.letMeKnowSendTo == 'Moderators Only' || cb.settings.letMeKnowSendTo == 'Broadcaster and Moderators') { cb.sendNotice(botName + 'Letting you know that @' + enteruser + ' has entered the room', BC, '', '', boldTextLiteral, 'red'); } } } // **** General Entry Message if (cb.settings.enableEntryMessage == 'Yes' && cb.settings.entryMessage && !enterisgray) { let welcomemsg = borderWelcomeTop; welcomemsg += '\n' + checkUsername(checkNextLine(cb.settings.entryMessage),enteruser); welcomemsg += borderUniversalBottom; cb.sendNotice(welcomemsg, enteruser, noticeBgColor, noticeTextColor, boldTextLiteral); displayShowSummary(enteruser); } // **** Custom tip menu notice if (tipMenuToggle) { if (tipMenuModItemArray.length > 0 && enterismod) { cb.sendNotice('@' + enteruser + ' as a Moderator, you get a discount off the general tip menu! \nTo see the Moderator specific discounted prices, type: /tipmenu', enteruser, appWarningColor, '', boldTextLiteral); } else if (tipMenuCBFCItemArray.length > 0 && enterisfan) { if (cb.settings.tipMenuCBFCSalePct > 0 && cbfcSpecificMenuItems) { cb.sendNotice('@' + enteruser + ' 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', enteruser, appWarningColor, '', boldTextLiteral); } else if (cb.settings.tipMenuCBFCSalePct > 0) { cb.sendNotice('@' + enteruser + ' as a Fan Club Member, you get a discount off the general tip menu! \nTo see the Fan Club specific discounted prices, type: /tipmenu', enteruser, appWarningColor, '', boldTextLiteral); } else if (cbfcSpecificMenuItems) { cb.sendNotice('@' + enteruser + ' 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', enteruser, appWarningColor, '', boldTextLiteral); } } else if (tipMenuEFC1ItemArray.length > 0 && enterisextfan1) { if (cb.settings.tipMenuEFC1SalePct > 0 && efc1SpecificMenuItems) { cb.sendNotice('@' + enteruser + ' 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', enteruser, appWarningColor, '', boldTextLiteral); } else if (cb.settings.tipMenuEFC1SalePct > 0) { cb.sendNotice('@' + enteruser + ' as a member of ' + EFCname + ', you get a discount off the general tip menu! \nTo see the your discounted prices, type: /tipmenu', enteruser, appWarningColor, '', boldTextLiteral); } else if (efc1SpecificMenuItems) { cb.sendNotice('@' + enteruser + ' 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', enteruser, appWarningColor, '', boldTextLiteral); } } else if (tipMenuEFC2ItemArray.length > 0 && enterisextfan2) { if (cb.settings.tipMenuEFC2SalePct > 0 && efc2SpecificMenuItems) { cb.sendNotice('@' + enteruser + ' 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', enteruser, appWarningColor, '', boldTextLiteral); } else if (cb.settings.tipMenuEFC2SalePct > 0) { cb.sendNotice('@' + enteruser + ' as a member of ' + EFCname2 + ', you get a discount off the general tip menu! \nTo see the your discounted prices, type: /tipmenu', enteruser, appWarningColor, '', boldTextLiteral); } else if (efc2SpecificMenuItems) { cb.sendNotice('@' + enteruser + ' 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', enteruser, appWarningColor, '', boldTextLiteral); } } else if (tipMenuVIPItemArray.length > 0 && enterisvip) { cb.sendNotice('@' + enteruser + ' as a VIP you get a discount off the general tip menu! \nTo see the VIP specific discounted prices, type: /tipmenu', enteruser, appWarningColor, '', boldTextLiteral); } } // **** Room Rules if (roomRuleEnterToggle && !enterisbc && roomRulesArray.length > 0) { displayRules(enteruser); } // **** Announce VIPs if ((cb.settings.announceVIP == 'Enter Only' || cb.settings.announceVIP == 'Enter or Leave') && cbjs.arrayContains(VIPListArray,enteruser)) { if (cb.settings.announceVIPOnce == 'Every Time' || (cb.settings.announceVIPOnce == 'First Time Only' && !cbjs.arrayContains(announcedEnterV,enteruser))) { if (!cbjs.arrayContains(announcedEnterV,enteruser)) { announcedEnterV.push(enteruser); } let temptextcolorvip = setTextColor('Dark Blue','Announce VIP',BC,false); let tempbgcolorvip = setBgColor('Light Blue','Announce VIP',BC,false); var vipentermessage = ''; if (cb.settings.announceVIPtext) { vipentermessage = 'Welcome ' + enteruser + '! ' + checkNextLine(cb.settings.announceVIPtext); } else { vipentermessage = 'Welcome ' + VIPname + ' member ' + enteruser + ' to our room!'; } if (cb.settings.announceVIPTo == 'Everyone') { cb.sendNotice(vipentermessage, '', tempbgcolorvip, temptextcolorvip, 'bold'); } else { if (cb.settings.announceVIPTo == 'Broadcaster Only' || cb.settings.announceVIPTo == 'Moderators and Broadcaster Only' || cb.settings.announceVIPTo == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(vipentermessage, BC, tempbgcolorvip, temptextcolorvip, 'bold'); } if (cb.settings.announceVIPTo == 'Moderators Only' || cb.settings.announceVIPTo == 'Moderators and Broadcaster Only' || cb.settings.announceVIPTo == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(vipentermessage, BC, tempbgcolorvip, temptextcolorvip, 'bold', 'red'); } if (cb.settings.announceVIPTo == 'Entering User Only' || cb.settings.announceVIPTo == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(vipentermessage, enteruser, tempbgcolorvip, temptextcolorvip, 'bold'); } } } } // **** Announce External Fan Club members if ((cb.settings.announceExtFans == 'Enter Only' || cb.settings.announceExtFans == 'Enter or Leave') && cbjs.arrayContains(extFanListArray,enteruser)) { if (cb.settings.announceExtFansOnce == 'Every Time' || (cb.settings.announceExtFansOnce == 'First Time Only' && !cbjs.arrayContains(announcedEnterE1,enteruser))) { if (!cbjs.arrayContains(announcedEnterE1,enteruser)) { announcedEnterE1.push(enteruser); } let temptextcolorefc1 = setTextColor('Dark Green','Announce Ext Fan 1',BC,false); let tempbgcolorefc1 = setBgColor('Light Green','Announce Ext Fan 1',BC,false); let efc1entermessage = ''; if (cb.settings.announceExtFanstext) { efc1entermessage = 'Welcome ' + enteruser + '! ' + checkNextLine(cb.settings.announceExtFanstext); } else { efc1entermessage = 'Welcome ' + EFCname + ' member ' + enteruser + ' to our room!'; } if (cb.settings.announceExtFansTo == 'Everyone') { cb.sendNotice(efc1entermessage, '', tempbgcolorefc1, temptextcolorefc1, 'bold'); } else { if (cb.settings.announceExtFansTo == 'Broadcaster Only' || cb.settings.announceExtFansTo == 'Moderators and Broadcaster Only' || cb.settings.announceExtFansTo == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(efc1entermessage, BC, tempbgcolorefc1, temptextcolorefc1, 'bold'); } if (cb.settings.announceExtFansTo == 'Moderators Only' || cb.settings.announceExtFansTo == 'Moderators and Broadcaster Only' || cb.settings.announceExtFansTo == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(efc1entermessage, BC, tempbgcolorefc1, temptextcolorefc1, 'bold', 'red'); } if (cb.settings.announceExtFansTo == 'Entering User Only' || cb.settings.announceExtFansTo == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(efc1entermessage, enteruser, tempbgcolorefc1, temptextcolorefc1, 'bold'); } } } } if ((cb.settings.announceExtFans2 == 'Enter Only' || cb.settings.announceExtFans2 == 'Enter or Leave') && cbjs.arrayContains(extFanList2Array,enteruser)) { if (cb.settings.announceExtFans2Once == 'Every Time' || (cb.settings.announceExtFans2Once == 'First Time Only' && !cbjs.arrayContains(announcedEnterE2,enteruser))) { if (!cbjs.arrayContains(announcedEnterE2,enteruser)) { announcedEnterE2.push(enteruser); } let temptextcolorefc2 = setTextColor('Dark Green','Announce Ext Fan 2',BC,false); let tempbgcolorefc2 = setBgColor('Light Green','Announce Ext Fan 2',BC,false); let efc2entermessage = ''; if (cb.settings.announceExtFanstext2) { efc2entermessage = 'Welcome ' + enteruser + '! ' + checkNextLine(cb.settings.announceExtFanstext2); } else { efc2entermessage = 'Welcome ' + EFCname2 + ' member ' + enteruser + ' to our room!'; } if (cb.settings.announceExtFans2To == 'Everyone') { cb.sendNotice(efc2entermessage, '', tempbgcolorefc2, temptextcolorefc2, 'bold'); } else { if (cb.settings.announceExtFans2To == 'Broadcaster Only' || cb.settings.announceExtFans2To == 'Moderators and Broadcaster Only' || cb.settings.announceExtFans2To == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(efc2entermessage, BC, tempbgcolorefc2, temptextcolorefc2, 'bold'); } if (cb.settings.announceExtFans2To == 'Moderators Only' || cb.settings.announceExtFans2To == 'Moderators and Broadcaster Only' || cb.settings.announceExtFans2To == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(efc2entermessage, BC, tempbgcolorefc2, temptextcolorefc2, 'bold', 'red'); } if (cb.settings.announceExtFans2To == 'Entering User Only' || cb.settings.announceExtFans2To == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(efc2entermessage, enteruser, tempbgcolorefc2, temptextcolorefc2, 'bold'); } } } } // **** Entry message if on the nice list if (cbjs.arrayContains(niceListArray,enteruser)) { cb.sendNotice('Welcome @' + enteruser + ', 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.',enteruser,'','',boldTextLiteral); } // **** Ticket Show functions and message if (ticketShowToggle) { if (cb.limitCam_isRunning()) { if (!cb.limitCam_userHasAccess(enteruser) && !enterisgray) { if (showStage === 'ticketshow') { cb.sendNotice(borderTicketTop + '\nTicket Show is in progress!\n' + returnShowTime() + borderTicketBottom, enteruser, ticketBgColor,ticketTxtColor,boldTextLiteral); if (ticketShowOtToggle) { cb.sendNotice(borderTicketTop + '\n* ' + bcText + ' has enabled the Outstanding Ticket Feature. \n* To view the list of outstanding tickets, type: /otlist \n* To use a saved outstanding ticket, type: /useticket \n* To save your ticket for a future show, type: /saveticket' + borderTicketBottom,enteruser,ticketBgColor,ticketTxtColor,boldTextLiteral); } } else if (showStage === 'showwarn') { cb.sendNotice(borderTicketTop + '\nTicket Show in progress, ' + 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' + returnShowTime() + borderTicketBottom, enteruser, ticketBgColor,ticketTxtColor,boldTextLiteral); } else if (showStage === 'showfinale') { cb.sendNotice(borderTicketTop + '\nTicket Show in progress, ' + bcText + ' has indicated show is nearly over \n and suspended ticket sales.\n' + returnShowTime() + borderTicketBottom,enteruser,ticketBgColor,ticketTxtColor,boldTextLiteral); } } } else { if (showStage === 'ticketsales') { if (cb.limitCam_userHasAccess(enteruser)) { cb.sendNotice(borderTicketTop + '\nWelcome! You have a ticket to the show and the show has not yet started.' + borderTicketBottom, enteruser, ticketBgColor, ticketTxtColor,boldTextLiteral); } else if (!enterisgray) { cb.sendNotice(borderTicketTop + '\nTicket Show sales are active and show has not yet started. \nThe ticket price is ' + ticketPrice + ' tokens.' + borderTicketBottom, enteruser,ticketBgColor,ticketTxtColor,boldTextLiteral); } if (cb.settings.hiddenShowAllowGift === 'Yes' && !enterisgray) { cb.sendNotice(borderTicketTop + '\n* ' + bcText + ' has enabled the the gifting of tickets. \n* You can purchase extra tickets and gift them using the command: /giftticket' + borderTicketBottom,enteruser,ticketBgColor,ticketTxtColor,boldTextLiteral); } if (ticketShowOtToggle) { cb.sendNotice(borderTicketTop + '\n* ' + bcText + ' has enabled the Outstanding Ticket Feature. \n* To view the list of outstanding tickets, type: /otlist \n* To use a saved outstanding ticket, type: /useticket \n* To save your ticket for a future show, type: /saveticket' + borderTicketBottom,enteruser,ticketBgColor,ticketTxtColor,boldTextLiteral); } } else if (showStage === 'aftershow' || ticketShowEnded === true) { cb.sendNotice(borderTicketTop + '\nThe Ticket Show is over.' + borderTicketBottom, enteruser, ticketBgColor, ticketTxtColor, boldTextLiteral); } } if (!cb.limitCam_userHasAccess(enteruser)) { if (enterismod) { if (cb.settings.hiddenShowFreeMods === 'Yes') { addRmvTicket('add',enteruser,'mod',0,enteruser); cb.sendNotice(borderTicketTop + '\n* You\'ve automatically been added to the ticket show because you\'re a moderator!' + borderTicketBottom, enteruser, ticketBgColor, ticketTxtColor, "bold"); } cb.sendNotice(borderTicketTop + '\n* Moderators: The Fembot Ticket Show feature is enabled. \n To see details on available commands for this feature, type: /fbhelp ticketshow' + borderTicketBottom, enteruser, ticketBgColor, ticketTxtColor, "bold"); } if (enterisfan) { if (cb.settings.hiddenShowFreeFC === 'Yes') { addRmvTicket('add',enteruser,'fan',0,enteruser); cb.sendNotice(borderTicketTop + '\n* You\'ve automatically been added to the ticket list because you\'re in the Chaturbate Fan Club!' + borderTicketBottom, enteruser, ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice(borderTicketTop + '\n* As a Chaturbate Fan Club member, you can buy a ticket to the show for ' + ticketPriceFC + ' tokens.' + borderTicketBottom, enteruser, ticketBgColor, ticketTxtColor, "bold"); } } if (enterisextfan1) { if (cb.settings.hiddenShowFreeEFC == 'Yes') { addRmvTicket('add',enteruser,'fan',0,enteruser); cb.sendNotice(borderTicketTop + '\n* You\'ve automatically been added to the ticket list because you\'re a ' + EFCname + ' member!' + borderTicketBottom, enteruser, ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice(borderTicketTop + '\n* As a ' + EFCname + ' member, you can buy a ticket to the show for ' + ticketPriceEFC + ' tokens.' + borderTicketBottom, enteruser, ticketBgColor, ticketTxtColor, "bold"); } } if (enterisextfan2) { if (cb.settings.hiddenShowFreeEFC2 == 'Yes') { addRmvTicket('add',enteruser,'fan',0,enteruser); cb.sendNotice(borderTicketTop + '\n* You\'ve automatically been added to the ticket list because you\'re a ' + EFCname2 + ' member!' + borderTicketBottom, enteruser, ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice(borderTicketTop + '\n* As a ' + EFCname2 + ' member, you can buy a ticket to the show for ' + ticketPriceEFC2 + ' tokens.' + borderTicketBottom, enteruser, ticketBgColor, ticketTxtColor, "bold"); } } if (enterisvip) { if (cb.settings.hiddenShowFreeVIP == 'Yes') { addRmvTicket('add',enteruser,'vip',0,enteruser); cb.sendNotice(borderTicketTop + '\n* You\'ve automatically been added to the ticket list because you\'re a ' + VIPname + ' member!' + borderTicketBottom, enteruser, ticketBgColor, ticketTxtColor, "bold"); } else { cb.sendNotice(borderTicketTop + '\n* As a ' + VIPname + ' member, you can buy a ticket to the show for ' + ticketPriceVIP + ' tokens.' + borderTicketBottom, enteruser, ticketBgColor, ticketTxtColor, "bold"); } } } } // **** Track Users for Answer Required Lock let answerlocked = false; if (requireAnswerToggle) { if (!enterisbc && !enterismod && !enterisfan && !enterisextfan1 && !enterisextfan2 && !enterisvip) { if (enterisgray && requireAnswerLevel >= 1 || enterislightblue && requireAnswerLevel >= 2 || enterisdarkblue && requireAnswerLevel >= 3 || enterislightpurple && requireAnswerLevel >= 4 || enterisdarkpurple && requireAnswerLevel >= 5) { if (!cbjs.arrayContains(answerLockList,enteruser)) { addToAnswerLockList(enteruser); } let trklockuserindex = answerLockList.indexOf(enteruser); if (answerLockStatus[trklockuserindex] == false) { let trklockquestion = answerLockQuestion[trklockuserindex]; cb.sendNotice('Welcome, ' + enteruser + ' chat is locked for your user level until you correctly solve the following math problem: \n ' + trklockquestion + '\nType your answer in the chat.', enteruser, appWarningColor, '', boldTextLiteral); answerlocked = true; } } } } if (grayLockToggle) { if (!cbjs.arrayContains(grayLockList,enteruser)) { addToLockList(enteruser,enterisbc,enterismod,enterisfan,enterisgray); } if (!answerlocked) { if (grayLockStatus.canChat[grayLockList.indexOf(enteruser)] == 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.', enteruser, appWarningColor, '', boldTextLiteral); } } } // **** King tipper welcome if (kingTipperFlag == 1) { if (enteruser == kingTipperName && cb.settings.kingTipperWelcome) { cb.sendNotice(checkUsername(cb.settings.kingTipperWelcome,enteruser),'', kingTipperBgColor,'','bold'); } } }); // *********************************** Actions upon leaving ************************************** cb.onLeave(function(user) { let leaveuser = user.user; // **** Remove from ticket show viewer list if (ticketShowToggle) { if (cbjs.arrayContains(ticketShowViewerList,leaveuser)) { cbjs.arrayRemove(ticketShowViewerList,leaveuser); } } if ((cb.settings.announceVIP == 'Leave Only' || cb.settings.announceVIP == 'Enter or Leave') && cbjs.arrayContains(VIPListArray,leaveuser)) { if (cb.settings.announceVIPOnce == 'Every Time' || (cb.settings.announceVIPOnce == 'First Time Only' && !cbjs.arrayContains(announcedExitV,leaveuser))) { if (!cbjs.arrayContains(announcedExitV,leaveuser)) { announcedExitV.push(leaveuser); } let temptextcolorvip = setTextColor('Dark Blue','Announce VIP',BC,false); let tempbgcolorvip = setBgColor('Light Blue','Announce VIP',BC,false); let vipleavemessage = VIPname + ' member ' + leaveuser + ' has left the room'; if (cb.settings.announceVIPTo == 'Everyone') { cb.sendNotice(vipleavemessage, '', tempbgcolorvip, temptextcolorvip, 'bold'); } else { if (cb.settings.announceVIPTo == 'Broadcaster Only' || cb.settings.announceVIPTo == 'Moderators and Broadcaster Only' || cb.settings.announceVIPTo == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(vipleavemessage, BC, tempbgcolorvip, temptextcolorvip, 'bold'); } if (cb.settings.announceVIPTo == 'Moderators Only' || cb.settings.announceVIPTo == 'Moderators and Broadcaster Only' || cb.settings.announceVIPTo == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(vipleavemessage, BC, tempbgcolorvip, temptextcolorvip, 'bold', 'red'); } } } } if ((cb.settings.announceExtFans == 'Leave Only' || cb.settings.announceExtFans == 'Enter or Leave') && cbjs.arrayContains(extFanListArray,leaveuser)) { if (cb.settings.announceExtFansOnce == 'Every Time' || (cb.settings.announceExtFansOnce == 'First Time Only' && !cbjs.arrayContains(announcedExitE1,leaveuser))) { if (!cbjs.arrayContains(announcedExitE1,leaveuser)) { announcedExitE1.push(leaveuser); } let temptextcolorefc1 = setTextColor('Dark Green','Announce Ext Fan 1',BC,false); let tempbgcolorefc1 = setBgColor('Light Green','Announce Ext Fan 1',BC,false); let efc1leavemessage = EFCname + ' member ' + leaveuser + ' has left the room'; if (cb.settings.announceExtFansTo == 'Everyone') { cb.sendNotice(efc1leavemessage, '', tempbgcolorefc1, temptextcolorefc1, 'bold'); } else { if (cb.settings.announceExtFansTo == 'Broadcaster Only' || cb.settings.announceExtFansTo == 'Moderators and Broadcaster Only' || cb.settings.announceExtFansTo == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(efc1leavemessage, BC, tempbgcolorefc1, temptextcolorefc1, 'bold'); } if (cb.settings.announceExtFansTo == 'Moderators Only' || cb.settings.announceExtFansTo == 'Moderators and Broadcaster Only' || cb.settings.announceExtFansTo == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(efc1leavemessage, BC, tempbgcolorefc1, temptextcolorefc1, 'bold', 'red'); } } } } if ((cb.settings.announceExtFans2 == 'Leave Only' || cb.settings.announceExtFans2 == 'Enter or Leave') && cbjs.arrayContains(extFanList2Array,leaveuser)) { if (cb.settings.announceExtFans2Once == 'Every Time' || (cb.settings.announceExtFans2Once == 'First Time Only' && !cbjs.arrayContains(announcedExitE2,leaveuser))) { if (!cbjs.arrayContains(announcedExitE2,leaveuser)) { announcedExitE2.push(leaveuser); } let temptextcolorefc2 = setTextColor('Dark Green','Announce Ext Fan 2',BC,false); let tempbgcolorefc2 = setBgColor('Light Green','Announce Ext Fan 2',BC,false); let efc2leavemessage = EFCname2 + ' member ' + leaveuser + ' has left the room'; if (cb.settings.announceExtFans2To == 'Everyone') { cb.sendNotice(efc2leavemessage, '', tempbgcolorefc2, temptextcolorefc2, 'bold'); } else { if (cb.settings.announceExtFans2To == 'Broadcaster Only' || cb.settings.announceExtFans2To == 'Moderators and Broadcaster Only' || cb.settings.announceExtFans2To == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(efc2leavemessage, BC, tempbgcolorefc2, temptextcolorefc2, 'bold'); } if (cb.settings.announceExtFans2To == 'Moderators Only' || cb.settings.announceExtFans2To == 'Moderators and Broadcaster Only' || cb.settings.announceExtFans2To == 'Mods, Broadcaster, and Entering User Only') { cb.sendNotice(efc2leavemessage, BC, tempbgcolorefc2, temptextcolorefc2, 'bold', 'red'); } } } } }); // ******************************* Actions upon following ************************************** cb.onFollow(function(user) { let followuser = user.user; let followbc = BC; let followercolor = ''; if (!cbjs.arrayContains(newFollowers, followuser)) { newFollowers.push(followuser); 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)) { cb.sendNotice(checkUsername(cb.settings.followerMessage,followuser),followuser,followBgColor,followTextColor,boldTextLiteral); } 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, boldTextLiteral); if (firstFollowMsg) { firstFollowMsg = false; cb.sendNotice('NOTE: You can change your follower notification settings using the /fmt command.', followbc, followBgColor, followTextColor, boldTextLiteral); } } } if (cb.settings.followerMessage && followerNotifyFlag == 4) { cb.sendNotice(checkUsername(cb.settings.followerMessage,followuser),'', followBgColor,followTextColor,boldTextLiteral); } } }); // *********************************** Actions upon tipping ************************************** cb.onTip(function (tip) { let tipamount = Number.parseInt(tip.amount, 10); let tipuser = tip.from_user; let tiprealuser = tip.from_user; let tipisfan = tip.from_user_in_fanclub; let tipisextfan1 = cbjs.arrayContains(extFanListArray,tiprealuser); let tipisextfan2 = cbjs.arrayContains(extFanList2Array,tiprealuser); let tipisvip = cbjs.arrayContains(VIPListArray,tiprealuser); let tipismod = cbjs.arrayContains(moderatorList.name,tiprealuser); let tipnotemessage = tip.message; let tipisanon = tip.is_anon_tip; let usertotaltipsthisshow = 0; currentSessionTotal = currentSessionTotal + tipamount; if (tipisanon) { tipuser = 'Anonymous'; } if (tipisvip && !cbjs.arrayContains(VIPInShowArray,tiprealuser)) { VIPInShowArray.push(tiprealuser); } if (tipisextfan1 && !cbjs.arrayContains(extFanInShowArray,tiprealuser)) { extFanInShowArray.push(tiprealuser); } if (tipisextfan2 && !cbjs.arrayContains(extFanInShow2Array,tiprealuser)) { extFanInShow2Array.push(tiprealuser); } // ***** Tip Count Array if (!tipisanon) { if (!cbjs.arrayContains(tipCountArray.name, tipuser)) { populateTipCountArray(tipuser,tipamount); usertotaltipsthisshow = tipamount; } else { let tiparyidx = findTipper(tipuser); tipCountArray.amount[tiparyidx] += tipamount; usertotaltipsthisshow = tipCountArray.amount[tiparyidx]; } } // ***** New King Tipper? if (!tipisanon) { if (cb.settings.kingSessionEnable == 'Yes') { if (currentKingTipper) { let kingtipindex = findTipper(currentKingTipper); currentKingTipperAmount = tipCountArray.amount[kingtipindex]; } if (usertotaltipsthisshow >= cb.settings.kingSessionMinAmount && usertotaltipsthisshow > currentKingTipperAmount) { currentKingTipperAmount = usertotaltipsthisshow; if (tiprealuser != currentKingTipper) { currentKingTipper = tiprealuser; cb.sendNotice(cb.settings.kingSessionIcon + ' Congratulations ' + tiprealuser + ' on becoming the new King Tipper for the current show! ' + cb.settings.kingSessionIcon, '', kingTipperBgColor, '', 'bold'); } } } if (cb.settings.kingSessionEnableSingle == 'Yes') { if (tipamount >= 25 && tipamount > currentKingTipperAmountSingle) { currentKingTipperAmountSingle = tipamount; currentKingTipperSingle = tiprealuser; cb.sendNotice(cb.settings.kingSessionIcon + ' Congratulations ' + tiprealuser + ' on having the highest single tip for the current show! ' + cb.settings.kingSessionIcon, '', kingTipperBgColor, '', 'bold'); } } if (cb.settings.kingSingleEnable == 'Yes, defined below') { if (tipamount > kingSingleTipperAmount && tiprealuser != kingSingleTipperName) { kingSingleTipperAmount = tipamount; kingSingleTipperName = tiprealuser; cb.sendNotice(':fireworks4 Congratulations ' + tiprealuser + ' on breaking the record for All-Time highest single tip in my room! :fireworks4', '', kingTipperBgColor, '', 'bold'); } } } // ***** Auto-add VIP if (!tipisanon) { if (!cbjs.arrayContains(VIPListArray, tipuser)) { if (cb.settings.joinVIPSingleTip > 0 && tipamount == cb.settings.joinVIPSingleTip) { let temptextcolorvip = setTextColor('Dark Blue','VIP List Addition',BC,false); let tempbgcolorvip = setBgColor('Light Blue','VIP List Addition',BC,false); addRmvVIP(tipuser,'a'); cb.sendNotice(botName + 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.', BC, appNoticeColor); cb.sendNotice('Welcome ' + tipuser + ' to ' + VIPname + '!', '', tempbgcolorvip, temptextcolorvip, 'bold'); } else if (cb.settings.joinVIPCumulativeShow > 0 && usertotaltipsthisshow >= cb.settings.joinVIPCumulativeShow) { let temptextcolorvip = setTextColor('Dark Blue','VIP List Addition',BC,false); let tempbgcolorvip = setBgColor('Light Blue','VIP List Addition',BC,false); addRmvVIP(tipuser,'a'); cb.sendNotice(botName + 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.', BC, appNoticeColor); cb.sendNotice('Welcome ' + tipuser + ' to ' + VIPname + '!', '', tempbgcolorvip, temptextcolorvip, 'bold'); } } } // ***** Tip Response Message if (!tipisanon) { if (tipResponseFlag == 1 || tipResponseFlag == 2) { let tiprespsendto = ''; if (tipResponseFlag == 1) { tiprespsendto = tipuser; } let sendresponse = false; let tipresponsemessage = ''; 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, tiprespsendto, tipRespBgColor, tipRespTextColor, 'bold'); } } } // ***** Perform Dice Roll Function let isdicerolltip = false; if (diceToggle && tipamount >= diceRollPrice && (tipamount / diceRollPrice <= diceMultiRolls) && (tipamount % diceRollPrice == 0)) { var numberOfRolls = Math.floor(parseInt(tipamount) / diceRollPrice); for (var i = 0; i < numberOfRolls; i++) { diceRoll(tipuser); } isdicerolltip = true; } // ***** Tip Menu if (tipMenuToggle) { let groupspectipfnd = false; if (tipismod && modSpecificMenuItems) { for (let tipmodidx = 0; tipmodidx < tipMenuModLength; tipmodidx++) { if (tipamount == tipMenuModPriceArray[tipmodidx]) { groupspectipfnd = true; if (!isdicerolltip) { tipMenuRequests.name.push(tipuser); tipMenuRequests.desc.push('"' + tipMenuModItemArray[tipmodidx] + '" from the Moderator Menu.'); tipMenuRequests.amt.push(tipamount); let currenttimetm = new Date(); tipMenuRequestTime.push(currenttimetm.getTime()); } if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(tipuser + ' tipped for: ' + tipMenuSepChar + ' ' + tipMenuModItemArray[tipmodidx] + ' ' + tipMenuSepChar + ' from the Moderator Tip Menu', '', tipMenuBgColorTip, tipMenuTextColorTip, 'bold'); } else { cb.sendNotice(tipuser + ' tipped for >> ' + tipMenuModItemArray[tipmodidx] + ' << from the Moderator Tip Menu.', '', tipMenuBgColorTip, tipMenuTextColorTip, 'bold'); } } } } else if (tipisfan && cbfcSpecificMenuItems) { for (let tipfanidx = 0; tipfanidx < tipMenuCBFCLength; tipfanidx++) { if (tipamount == tipMenuCBFCPriceArray[tipfanidx]) { groupspectipfnd = true; if (!isdicerolltip) { tipMenuRequests.name.push(tipuser); tipMenuRequests.desc.push('"' + tipMenuCBFCItemArray[tipfanidx] + '" from the CB Fanclub Menu.'); tipMenuRequests.amt.push(tipamount); let currenttimetf = new Date(); tipMenuRequestTime.push(currenttimetf.getTime()); } if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(tipuser + ' tipped for: ' + tipMenuSepChar + ' ' + tipMenuCBFCItemArray[tipfanidx] + ' ' + tipMenuSepChar + ' from the Fanclub Tip Menu', '', tipMenuBgColorTip, tipMenuTextColorTip, 'bold'); } else { cb.sendNotice(tipuser + ' tipped for >> ' + tipMenuCBFCItemArray[tipfanidx] + ' << from the Fanclub Tip Menu.', '', tipMenuBgColorTip, tipMenuTextColorTip, 'bold'); } } } } else if (tipisextfan1 && efc1SpecificMenuItems) { for (let tipef1idx = 0; tipef1idx < tipMenuEFC1Length; tipef1idx++) { if (tipamount == tipMenuEFC1PriceArray[tipef1idx]) { groupspectipfnd = true; if (!isdicerolltip) { tipMenuRequests.name.push(tipuser); tipMenuRequests.desc.push('"' + tipMenuEFC1ItemArray[tipef1idx] + '" from the ' + EFCname + ' Menu.'); tipMenuRequests.amt.push(tipamount); let currenttimetef1 = new Date(); tipMenuRequestTime.push(currenttimetef1.getTime()); } if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(tipuser + ' tipped for: ' + tipMenuSepChar + ' ' + tipMenuEFC1ItemArray[tipef1idx] + ' ' + tipMenuSepChar + ' from the ' + EFCname + ' Tip Menu', '', tipMenuBgColorTip, tipMenuTextColorTip, 'bold'); } else { cb.sendNotice(tipuser + ' tipped for >> ' + tipMenuEFC1ItemArray[tipef1idx] + ' << from the ' + EFCname + ' Tip Menu.', '', tipMenuBgColorTip, tipMenuTextColorTip, 'bold'); } } } } else if (tipisextfan2 && efc2SpecificMenuItems) { for (let tipef2idx = 0; tipef2idx < tipMenuEFC2Length; tipef2idx++) { if (tipamount == tipMenuEFC2PriceArray[tipef2idx]) { groupspectipfnd = true; if (!isdicerolltip) { tipMenuRequests.name.push(tipuser); tipMenuRequests.desc.push('"' + tipMenuEFC2ItemArray[tipef2idx] + '" from the ' + EFCname2 + ' Menu.'); tipMenuRequests.amt.push(tipamount); let currenttimetef2 = new Date(); tipMenuRequestTime.push(currenttimetef2.getTime()); } if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(tipuser + ' tipped for: ' + tipMenuSepChar + ' ' + tipMenuEFC2ItemArray[tipef2idx] + ' ' + tipMenuSepChar + ' from the ' + EFCname2 + ' Tip Menu', '', tipMenuBgColorTip, tipMenuTextColorTip, 'bold'); } else { cb.sendNotice(tipuser + ' tipped for >> ' + tipMenuEFC2ItemArray[tipef2idx] + ' << from the ' + EFCname2 + ' Tip Menu.', '', tipMenuBgColorTip, tipMenuTextColorTip, 'bold'); } } } } else if (tipisvip && vipSpecificMenuItems) { for (let tipvipidx = 0; tipvipidx < tipMenuVIPLength; tipvipidx++) { if (tipamount == tipMenuVIPPriceArray[tipvipidx]) { groupspectipfnd = true; if (!isdicerolltip) { tipMenuRequests.name.push(tipuser); tipMenuRequests.desc.push('"' + tipMenuVIPItemArray[tipvipidx] + '" from the VIP Menu.'); tipMenuRequests.amt.push(tipamount); let currenttimetv = new Date(); tipMenuRequestTime.push(currenttimetv.getTime()); } if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(tipuser + ' tipped for: ' + tipMenuSepChar + ' ' + tipMenuVIPItemArray[tipvipidx] + ' ' + tipMenuSepChar + ' from the VIP Tip Menu', '', tipMenuBgColorTip, tipMenuTextColorTip, 'bold'); } else { cb.sendNotice(tipuser + ' tipped for >> ' + tipMenuVIPItemArray[tipvipidx] + ' << from the VIP Tip Menu.', '', tipMenuBgColorTip, tipMenuTextColorTip, 'bold'); } } } } if (!groupspectipfnd) { for (let tipidx = 0; tipidx < tipMenuLength; tipidx++) { if (tipamount == tipMenuPriceArray[tipidx]) { if (!isdicerolltip) { tipMenuRequests.name.push(tipuser); tipMenuRequests.desc.push('"' + tipMenuItemArray[tipidx] + '" from Tip Menu 1.'); tipMenuRequests.amt.push(tipamount); let currenttimeng = new Date(); tipMenuRequestTime.push(currenttimeng.getTime()); } if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(tipuser + ' tipped for: ' + tipMenuSepChar + ' ' + tipMenuItemArray[tipidx] + ' ' + tipMenuSepChar, '', tipMenuBgColorTip, tipMenuTextColorTip, 'bold'); } else { cb.sendNotice(tipuser + ' tipped for >> ' + tipMenuItemArray[tipidx] + ' <<', '', tipMenuBgColorTip, tipMenuTextColorTip, 'bold'); } } } } } if (tipMenu2Toggle) { for (let tm2idx = 0; tm2idx < tipMenu2Length; tm2idx++) { if (tipamount ==tipMenu2PriceArray[tm2idx]) { if (!isdicerolltip) { tipMenuRequests.name.push(tipuser); tipMenuRequests.desc.push('"' +tipMenu2ItemArray[tm2idx] + '" from Tip Menu 2.'); tipMenuRequests.amt.push(tipamount); let currenttimetm2 = new Date(); tipMenuRequestTime.push(currenttimetm2.getTime()); } if (cb.settings.sepInResponse == 'Yes') { cb.sendNotice(tipuser + ' tipped for: ' + tipMenu2SepChar + ' ' + tipMenu2ItemArray[tm2idx] + ' ' + tipMenu2SepChar, '', tipMenu2BgColorTip, tipMenu2TextColorTip, 'bold'); } else { cb.sendNotice(tipuser + ' tipped for >> ' + tipMenu2ItemArray[tm2idx] + ' <<', '', tipMenu2BgColorTip, tipMenu2TextColorTip, 'bold'); } } } } if (posTipMenuToggle) { for (let ptmidx = 0; ptmidx < posMenuLength; ptmidx++) { if (tipamount == posMenuPriceArray[ptmidx]) { if (!isdicerolltip) { posMenuRequestersArray.push(tipuser); posMenuRequestsArray.push(posMenuItemArray[ptmidx]); tipMenuRequests.name.push(tipuser); tipMenuRequests.desc.push('"' + posMenuItemArray[ptmidx] + '" from the ' + posMenuLiteralDesc + ' Menu.'); tipMenuRequests.amt.push(tipamount); let currenttimepm = new Date(); posMenuRequestsArrayTime.push(currenttimepm.getTime()); tipMenuRequestTime.push(currenttimepm.getTime()); } if (cb.settings.posSepInResponse == 'Yes') { cb.sendNotice(tipuser + ' tipped for: ' + posMenuSepChar + ' ' + posMenuItemArray[ptmidx] + ' ' + posMenuSepChar, '', posMenuBgColor, posMenuTextColor, 'bold'); } else { cb.sendNotice(tipuser + ' tipped for >> ' + posMenuItemArray[ptmidx] + ' <<', '', posMenuBgColor, posMenuTextColor, 'bold'); } } } } // ***** Add to Ticket Show Backup List if (backupToggle && backupPrice > 0 && ticketShowType != 'Fembot Ticket Show' && tipamount >= backupPrice && !cbjs.arrayContains(backupListArray,tiprealuser)) { addRmvTicketBackupList('addtip',tiprealuser); } // ***** Add to Pre-Sale Ticket List if (presalesToggle && !cbjs.arrayContains(presaleArray,tiprealuser)) { if (tipamount >= presalePrice) { addRmvPresale('addtip',tiprealuser,tipamount,tipuser); } else { checkCumulative(tiprealuser,tipamount,presalePrice,'common','presale',tipuser); } } // ***** Add to Ticket Show if (ticketShowToggle && !ticketShowEnded && !ticketSalesEnded && !cb.limitCam_userHasAccess(tiprealuser)) { if (tipisfan) { if (tipamount >= ticketPriceFC) { addRmvTicket('addtip', tiprealuser, 'fan', tipamount, tipuser); } else { checkCumulative(tiprealuser,tipamount,ticketPriceFC,'fan','ticket', tipuser); } } else if (tipisextfan1) { if (tipamount >= ticketPriceEFC) { addRmvTicket('addtip', tiprealuser, 'fan', tipamount, tipuser); } else { checkCumulative(tiprealuser,tipamount,ticketPriceEFC,'fan','ticket', tipuser); } } else if (tipisextfan2) { if (tipamount >= ticketPriceEFC2) { addRmvTicket('addtip', tiprealuser, 'fan', tipamount, tipuser); } else { checkCumulative(tiprealuser,tipamount,ticketPriceEFC2,'fan','ticket', tipuser); } } else if (tipisvip) { if (tipamount >= ticketPriceVIP) { addRmvTicket('addtip', tiprealuser, 'vip', tipamount, tipuser); } else { checkCumulative(tiprealuser,tipamount,ticketPriceVIP,'vip','ticket', tipuser); } } else { if (tipamount >= ticketPrice) { addRmvTicket('addtip', tiprealuser, 'common', tipamount, tipuser); } else { checkCumulative(tiprealuser,tipamount,ticketPrice,'common','ticket', tipuser); } } } else if (ticketShowToggle && !ticketShowEnded && !ticketSalesEnded && cb.limitCam_userHasAccess(tiprealuser) && cb.settings.hiddenShowAllowGift === 'Yes') { if (tipamount >= ticketPrice) { addRmvTicket('addextra', tiprealuser, 'common', tipamount, tipuser); } } // ***** Progress on Ticket Show Goal if (ticketShowToggle) { ticketShowGoalProgress(tipamount); } // ***** Perform Token Poll Tip Functions if (tokenPollToggle && pollRunning) { if (tipamount == stealPollAmount) { stealPoll(tipuser); } else if (cbjs.arrayContains(pollArrayAmount,tipamount)) { let pollvoteamt = 1; if (tipisfan && fanDouble) { pollvoteamt = 2; cb.sendNotice('Since you are a member of the fan club, your vote is doubled!', tipuser, tokenPollBgColor, tokenPollTextColor, 'bold'); } pollTip(tipamount,pollvoteamt,tipuser); } } else if (onDemandPollRunning) { if (tipamount == stealPollAmount) { stealODPoll(tipuser); } else if (cbjs.arrayContains(odpollArrayAmount,tipamount)) { let odpollvoteamt = 1; if (tipisfan && fanDouble) { odpollvoteamt = 2; cb.sendNotice('Since you are a member of the fan club, your vote is doubled!', tipuser, odtokenPollBgColor, odtokenPollTextColor, 'bold'); } odpollTip(tipamount,odpollvoteamt,tipuser); } } // ***** Buy an Icon/Gif for your username if (!tipisanon) { if (iconTipAmountArray.length > 0) { if (tipForIconType == 'Specific Tip Amount') { if (cbjs.arrayContains(iconTipAmountArray,tipamount)) { let newiconindex = iconTipAmountArray.indexOf(tipamount); let alreadythisicon = false; if (cbjs.arrayContains(tipForIconArray.name,tiprealuser)) { let iconindex = tipForIconArray.name.indexOf(tiprealuser); if (tipForIconArray.icon[iconindex] == iconTipIconArray[newiconindex]) { alreadythisicon = true; } } if (!alreadythisicon) { addTipForIcon(tiprealuser,iconTipIconArray[newiconindex]); cb.sendNotice('Congratulations, you have tipped to change your user icon!', tiprealuser, appNoticeColor); } } } else if (tipForIconType == 'Cumulative Tip Amount' && usertotaltipsthisshow >= iconTipAmountArray[0]) { for (var buyiconidx = (iconTipAmountArray.length-1); buyiconidx >= 0; buyiconidx--) { if (usertotaltipsthisshow >= iconTipAmountArray[buyiconidx]) { let alreadythisicon2 = false; if (cbjs.arrayContains(tipForIconArray.name,tiprealuser)) { let iconindex2 = tipForIconArray.name.indexOf(tiprealuser); if (tipForIconArray.icon[iconindex2] == iconTipIconArray[buyiconidx]) { alreadythisicon2 = true; } } if (!alreadythisicon2) { addTipForIcon(tiprealuser,iconTipIconArray[buyiconidx]); cb.sendNotice('Congratulations, you have tipped to change your user icon!', tiprealuser, appNoticeColor); } break; } } } } } // ***** Forward Tip Note if (tipnotemessage) { if (tipNoteForwardID == '*ALLMODS' && modLevel == 'Advanced') { cb.sendNotice('Forwarded Tip Note from ' + tipuser + ': ' + tipnotemessage, 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 != tiprealuser) { if (cbjs.arrayContains(moderatorList.name,tipNoteForwardID)) { cb.sendNotice('Forwarded Tip Note from ' + tipuser + ': ' + tipnotemessage, 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; } } } } });
© Copyright Chaturbate 2011- 2024. All Rights Reserved.