Apps Home
|
Create an App
test000999
Author:
french_riv1era
Description
Source Code
Launch App
Current Users
Created by:
French_Riv1era
/** Name: Dorothy's Ticket Show Author: butter_my_toast Created 2/15/2019 **/ //** Enable for ESLINT syntax check, Disable for CB compile //var cb = ''; //var cbjs = ''; var dummycounter = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71' ]; var backgroundArray = { menu: ['Animated - Cube Wave', 'Hearts', 'Blue Floral', 'Animated - Aquarium', 'Animated - Snakeskin', 'Pastels', 'Animated - Clouds', 'Animated - Lava Lamp', 'Light Blue', 'Moon', 'Purple Haze', 'Blue Bars', 'Valentines Pink Bars', 'Valentines 2 Hearts', 'Green and Blue Bars', 'Pink and Blue Bars', 'Green and Green Bars', 'Green and Yellow Bars', 'Purple and Pink Bars', 'Aqua and Pink Bars', 'Light and Dark Pink Bars', 'Gold and Yellow Bars', 'Christmas - Silver snowflakes', 'Christmas Lights', 'Christmas - Green background', 'Christmas - Blue and Silver', 'Halloween - spooky pumpkins', 'Halloween - bouncing pumpkin', 'Halloween - Red sky lightning', 'Halloween - orange sky bats', 'Halloween - blue sky bats', 'Halloween - graveyard', 'Halloween - blue with ghosts', 'Halloween - red paper with webs', 'Christmas - BW Snowflakes', 'Christmas - Blue Snowflakes', 'Christmas - Snowflake border', 'Christmas - Red with snow', 'Christmas - Red Santa and snowman', 'Christmas - Wrapping Paper', 'Christmas - Classic', 'Pastel Aqua Stars', 'Black Leather Texture', 'St. Patricks Day 1', 'St. Patricks Day 2', 'St. Patricks Day 3', 'Flowers White', 'Flowers Blue', 'Flowers Cream and Rose', 'Lily Pads', 'Flowers Green and White', 'Green Leaves Pattern', 'Mauve Leaf Pattern', 'White Rose', 'Green Pattern', 'Dark Blue-Green Watercolor', 'Aqua Watercolor', 'Green Diamond Pattern', 'Green Circles Pattern', 'Water Droplets', 'Light Blue Splash', 'Pool Surface', 'Turquoise Tiles', 'Shifting Hexagons', 'Topography', 'Tropical Leaves', 'Animated Red Waves', 'Animated Rainbow Waves', 'Pink & Purple Pattern', 'Big Leaves', 'Animated Gray Liquid', 'Animated Light Streaks' ], command: ['cubewave', 'hearts', 'bluefloral', 'aquarium', 'snakeskin', 'pastels', 'clouds', 'lavalamp', 'lightblue', 'moon', 'purplehaze', 'bluegradient', 'valentines1', 'valentines2', 'greenblue', 'pinkblue', 'greengreen', 'greenyellow', 'purplepink', 'aquapink', 'pinkpink', 'yellowyellow', 'christmas1silversnowflakes', 'christmas2lights', 'christmas3green', 'christmas4blue', 'halloween1', 'halloween2', 'halloween3', 'halloween4', 'halloween5', 'halloween6', 'halloween7', 'halloween8', 'christmas4bw', 'christmas5bluesnowflakes', 'christmas6snowflakesborder', 'christmas7red1', 'christmas8red2', 'christmas9wrap', 'christmas10classic', 'pastelaqua', 'blackleather', 'stpatrick1', 'stpatrick2', 'stpatrick3', 'flowerswhite', 'flowersblue', 'flowerscreamrose', 'lilypads', 'flowersgreenwhite', 'greenleaf', 'mauveleaf', 'whiterose', 'greenpattern', 'bluegreenwatercolor', 'aquawatercolor', 'greendiamond', 'greencircles', 'waterdroplets', 'bluesplash', 'pool', 'turqoise_tiles', 'hexagons', 'topography', 'tropical_leaves', 'red_waves', 'Rainbow Waves', 'pp_pattern', 'big_leaves', 'gray_liquid', 'light_streaks' ], devfile: ['17606e52-2215-403d-b052-46a936ca9f92','add', '8b1ebdd0-1e73-4abe-b882-4239b6e55b0d', 'add', 'add', 'add', 'add', 'add', 'add', 'add', '4b465340-8967-48cc-9945-532f789f73e1', 'add', 'add', 'add', 'add', 'add', 'ca7b4f10-9623-4db8-8f84-70153dc60f61', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'cd1d941d-0a4d-4bc1-975c-32a7073f951b', 'add', '6967fc13-202c-49ff-8f15-6b92812c87ff', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add', 'add' ], livefile: ['5a1440ce-144f-471a-8e94-9ed1ba1303c5','f21bd2fc-ec02-42e9-b656-bfa791c36e5d', '226704d8-dddf-47fb-86ec-9b20f25fa9ac', 'e028e600-24fe-4db8-b9a0-ac0256e7f380', '75858206-0614-43ab-ac1f-ce8c394c6994', '3d335a10-9c34-4897-8085-39008cd172cc', 'e85b51a4-bf0c-4b01-8f5f-a6541b1d7095', '8284528c-2a13-4ce2-a1f9-0ab0abf0b064', '097633c4-f094-48df-b2f3-94f5a05d4167', 'd458cc82-9b76-4851-a913-83066895007d', '91270fd0-5837-4d05-9e89-020a5b3e491b', 'e460b54e-0c66-4998-9480-2543b06e0d24', '22c39588-c0ba-4864-8b77-89e702c3074f', 'c9cff59d-5b97-4e94-8f6c-3b12206540ef', 'fc3456c8-c2c3-4792-b3a1-ae17e8cef8e9', '768bf7a4-7be9-4664-ab90-fa51f9707552', 'c5f0d810-c7f9-4f5a-94cb-e6326879b459', 'c9006e13-265c-4e3c-8e7d-4bc0241afcea', '8c05f68b-84b0-4fb7-b095-5d7091624b17', 'd95d1e4e-9d25-438c-a220-7547acf919ca', 'eb30ef8b-8e71-4c4a-ab01-01396d6b8473', '58d18175-ad41-486f-ae1f-a5f135bef6ee', '082cba9b-f7de-4d84-8955-c91e60178985', 'b57b93ae-18c2-4188-95e8-bf98754ac0fc', 'ba373861-1082-41a2-9bfe-9185acf80614', '6c61664d-c983-416d-a69e-f8594b5e290b', '0dddbf84-b2f1-43a7-a2f3-251cf684a9b4', '54ff2913-ca6a-4b80-8f00-b5dae9c4ea86', '148686cd-bb91-448e-9a96-0406999a4a7a', 'c141e2a0-ad33-4e91-81ab-aae10412299d', 'b9ea1db5-a1ef-4f24-9ab0-660272ee85af', '9c6030d6-2614-476c-ba51-a0ba3faedd4f', 'a24fe9ce-5f3f-43fd-ac7f-dbab607e9a8b', '8d216a27-723d-4451-8675-47bbf077e229', '95d94aa3-7fd0-4a15-8c47-a7f32496d94c', 'cc06f8d6-faf2-48a9-bb23-4be4625bedf1', '7c91e7db-8fd4-4f82-89b0-2130c259ad60', 'b5a0da46-d304-4427-8198-47757004df3a', '1b2c6660-7d9c-4ffa-bdc7-55c9b97a6a9d', '2ee071d5-dbd1-4794-a059-a7e9f3f8eed0', 'aad10a11-9b39-4fab-96dd-cd7ed41c8405', '1da3dd2b-cad8-43b0-a1e6-c354b6ff8675', 'c83c2d94-d0d7-4abc-b23a-b0d37261da43', '1976fa1b-7b19-44a2-9002-ed813033c052', '5899c48d-4dad-48dc-8d62-a7355fdd298f', '75aa6096-a1d0-49d3-b2d8-50518b215e46', '00709180-24e2-4b74-a3f0-5987566a7de4', '98f792d8-6611-4386-8c5d-e07603235bef', 'a1cf9a3f-1e6b-4861-b66d-8d23e38dd1ff', '4b2f32ff-a13e-4965-859a-7942f8cb8113', 'd1781cb5-e5cc-4f7c-ba5c-08b14678dd5d', '20275e51-40b9-4c41-9551-c8c34492d64a', '3ea5bd36-3a34-4eaa-b1d2-5f58dfb3841c', '4f00abdc-5b6a-40a4-93f9-c56f93fe3786', 'c463ebe6-2780-44bb-ba8d-97a003fcce0d', '68d1b04f-aada-410d-bce5-6ef16d202f14', 'e98cbc2f-91a5-4a7f-8ea3-b004e8d81ee8', '09e346ba-4389-412e-81f0-9d9760cdcf96', 'cfa47ff4-351d-4b92-af82-4323442b0664', 'fb0600fc-c44d-4cb4-a66b-3d99b49c4f42', '7d65f794-12dc-44d7-8bcc-d833766a0c1b', '15576c58-b770-49f1-9cbe-f30078d6395e', 'e4305c67-8dc8-43d2-be67-a9d4ed5a0bbc', '3cea32ee-f0c0-4458-8f5a-22f5cffb1e94', '1b4740a4-a0cd-4a1b-a320-f47577bcc77b', '20275e51-40b9-4c41-9551-c8c34492d64a', '4b5d4f49-d7dd-4111-b24a-b123d5ead102', 'b63c5c51-8346-43cf-92e7-0d2ddf049850', '1fbf9b7d-3095-492a-85df-8a283fd4d031', 'd6a42a9b-bc46-42ef-9005-8ec0fba826d3', '6a8b4cf9-a6cf-4079-98bc-15a71ec2f02d', '77bca1c6-5dc6-4d8c-9216-a8fa58f2de7e' ] }; var botPanel = false; 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' ]}; var textColorArray = { dispname: ['White/No Color', 'Black', 'Dark Grey', 'Dark Red', 'Dark Orange', 'Dark Green', 'Dark Aqua', 'Dark Blue', 'Dark Purple', 'Dark Pink', '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', 'darkgold', 'darkteal', 'darkbrown', 'darkbronze', 'darkperiwinkle', 'darkfuschia', 'darklime', 'darkplum' ], colorID: ['#FFFFFF', '#000000', '#737373', '#cc0000', '#e77400', '#006600', '#006767', '#0629AC', '#3d003d', '#FF6680', '#998100', '#003f1f', '#582c00', '#a56728', '#155bd7', '#d6155c', '#6b790c', '#7f13bf' ]}; var bgColorArray = { dispname: ['White/No Color', 'Light Yellow', 'Light Blue', 'Light Pink', 'Light Red', 'Light Green', 'Light Purple', 'Light Orange', 'Light Grey', 'Light Aqua', 'Light Teal', 'Cream', 'Light Bronze', 'Light Periwinkle', 'Light Fuschia', 'Light Lime', 'Light Plum'], name: ['white', 'lightyellow', 'lightblue', 'lightpink', 'lightred', 'lightgreen', 'lightpurple', 'lightorange', 'lightgrey', 'lightaqua', 'lightteal', 'cream', 'lightbronze', 'lightperiwinkle', 'lightfuschia', 'lightlime', 'lightplum' ], colorID: ['#FFFFFF', '#ffff94', '#d1eaee', '#FFE6EA', '#ff9a9a', '#94e594', '#f2cdff', '#ffd9b3', '#e6e6e6', '#adeaea', '#d7fbee', '#f9f6ed', '#ebccad', '#d7e4fb', '#fbd7e4', '#ecf6a7', '#e3c0f9' ]}; cb.settings_choices = [ {name: 'intro', label: '------------------------------------------------------------------------------------ INTRODUCTION ------------------------------------------------------------------------------------ Latest Update: November 13, 2021 (version 3.0). Welcome ' + cb.room_slug + ' to Dorothy\'s Ticket Show App, if this is your first time using the App, the main settings to define are in "1A" through "1C" below, namely the show description, the ticket price, and the method of show start. All other settings are optional and define additional features. There is also a personalization section at the bottom for choosing colors and such. ****** Note that in the latest update there is a significant update to how ticket buyers are added the ticket show when the show is started to address and bypass the technical issues that CB has been having recently with ticket shows. Previously, users were granted show access as soon as they bought a ticket. The logic is now changed to not add users to the show until right after the room is locked, so that the isssues with locking the room when a large number of users are already present can be bypassed. It appears that there is sometimes still a need for users to refresh their browser to be given access if they buy a ticket after the show starts, will continue looking to improve that if possible.*****', type: 'choice',required: false}, // *** Hidden Ticket Show {name: 'ticketshow', label: '------------------------------------------------------------------------------- REQUIRED SETTINGS -------------------------------------------------------------------------------', type: 'choice',required: false}, {name: 'ticketRoomSubjectSfx', label: '1A. Title? -- Description of the show to appear as part of the room title (optional). You can include hashtags for keywords you want to be searchable', type:'str', minLength: 1,maxLength: 200, defaultValue: 'Hidden Ticket Show!'}, {name: 'ticketShowPrice', label: '1B. Ticket Show Price? -- This is the initial ticket show price for the general audience, and may remain the final ticket price if not changed later. Discounted prices for Fan Club, Mods and VIPs are defined later below.', type: 'int',minValue: 1,maxValue: 99999,defaultValue: 69}, {name: 'ticketShowStartMode', label: '1C. Start Mode? -- Which mode is used for determining when to start the show? This setting defines what will trigger the start of show, and whether it starts automatically. If starting a timer immediately, define setting "1G" below (default is 15 min). If defining a token or ticket goal, also define setting "1D" below', 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: 'ticketshow2', label: '------------------------------------------------------------------------------- OPTIONAL SETTINGS -------------------------------------------------------------------------------', type: 'choice',required: false}, {name: 'ticketShowGoal', label: '1D. Goal Amount? -- If setting "1C" above is configured for a ticket or token goal before starting the show, set goal amount here (in terms of tickets or tokens based on type of show start goal defined above).', type: 'int',minValue: 1,maxValue: 5000,defaultValue: 1000,required: false}, {name: 'ticketShowStartAuto', label: '1E. AutoStart? -- 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 timer runs out or goal is reached?', type: 'choice', choice1: 'Start from Command', choice2: 'Automated Start', defaultValue: 'Start from Command'}, {name: 'ticketShowStartPrice', label: '1F. New Price at Start of Hidden Show? -- You can choose to have the price increase once at the time the show starts from the original price above (in "1B") to a higher price. set to 0 if not used. Only valid if configured to a value greater than the ticket price above in "1B".', type: 'int',minValue: 0,maxValue: 99999,defaultValue: 0,required: false}, {name: 'ticketShowStartTimer', label: '1G. Default Timer -- If the start mode is set for using a timer that automatically starts when the app starts, define the number of minutes for the countdown from starting the app until the show will start (you can add and subtract time later with commands if needed). To start a timer later rather than as soon as you start the App, start the show in "Start Show Anytime" mode, turn off "Autostart", and use the command "/ticketstarttimer" to do a countdown when you are ready', type: 'int',minValue: 1,maxValue: 120,defaultValue: 15}, {name: 'ticketShowCumulative', label: '1H. Accumulate tips? -- Once ticket sales have started, 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: 'ticketShowFanAppreciation', label: '1J. Fan Appreciation Mode? When turned on, a special ticket show is used where only the members defined below for free shows are able to access. There will be no ticket sales available.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'ticketShowFreeFC', label: '1K1. Give a free ticket to CB Fanclub members?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'ticketShowFreeMods', label: '1K2. Give a free ticket to moderators?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'ticketShowFreeEFC', label: '1K3. Give a free ticket to External Fanclub 1 members? Even if the External FanClub 1 list has been setup in the Fembot, it must also be duplicated here (see Personalization section below) to enter the user list for ticket show privileges', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'ticketShowFreeEFC2', label: '1K4. Give a free ticket to External Fanclub 2 members? Even if the External FanClub 2 list has been setup in the Fembot, it must also be duplicated here (see Personalization section below) to enter the user list for ticket show privileges', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'ticketShowFreeVIP', label: '1K5. Give a free ticket to VIP List members? Even if the VIP list has been setup in the Fembot, it must also be duplicated here (see Personalization section below) to enter the user list for ticket show privileges', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'ticketShowPriceFC', label: '1L1. Discounted price for CB Fan Club members -- If no price is set, the Fan Club ticket price is the same as regular viewers. This value is not used if the above setting grants them a free ticket.', type: 'int',minValue: 1,maxValue: 300,defaultValue: 35,required: false}, {name: 'ticketShowPriceEFC', label: '1L2. Discounted price for External Fan Club 1 members -- If no price is set, the External Fan Club 1 ticket price is the same as regular viewers. This value is not used if the above setting grants them a free ticket.', type: 'int',minValue: 0,maxValue: 300,required: false}, {name: 'ticketShowPriceEFC2', label: '1L3. Discounted price for External Fan Club 2 members -- If no price is set, the External Fan Club 2 ticket price is the same as regular viewers. This value is not used if the above setting grants them a free ticket.', type: 'int',minValue: 0,maxValue: 300,required: false}, {name: 'ticketShowPriceVIP', label: '1L4. Discounted price for VIP List members -- If no price is set, the VIP List ticket price is the same as regular viewers. This value is not used if the above setting grants them a free ticket.', type: 'int',minValue: 0,maxValue: 300,required: false}, {name: 'ticketShowModsAdd', label: '1M1. Allow moderators to use the "add" and "remove" commands? Note that enabling this will allow them to add themselves to a show even if the above setting for giving them a free ticket is set to "No". This setting overrides the general setting for mod authority specifically for the ticket show "/add" functions.', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'ticketShowModsChgPrice', label: '1M2. Allow moderators to change the price of a ticket? This setting overrides the general setting for mod authority specifically for the ticket show price functions', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes'}, {name: 'ticketShowAfterNotice', label: '1N. 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: 'ticketShowReducePriceWarn', label: '1P. Late addition Ticket Show Sale? -- 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. Note this is the price reduction, not the actual new price, and it will apply to all ticket prices (including fans clubs and VIPs)', type: 'int',minValue: 0,maxValue: 300,defaultValue: 0,required: false}, {name: 'ticketShowEnableOT', label: '1Q1. Enable OT List? -- 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: 'No'}, {name: 'ticketShowOTList', label: '1Q2. OT List -- 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. The format should be a comma separated list (user1,user2,user3)', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'ticketShowAllowGift', label: '1R. Gifting Allowed? -- Allow users to buy additional tickets they can use as gifts to other users', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, {name: 'ticketShowPreviewLength', label: '1S1. Free Preview? -- If a free preview will be allowed for people joining the room after the show starts, define the length of the preview period. Set to "No Preview" to disable, or select a length from the list.',type: 'choice', choice1: 'No Preview', choice2: '10 seconds',choice3: '20 seconds', choice4: '30 seconds', choice5: '1 minute', choice6: '2 minutes', choice7: '3 minutes',choice8: '4 minutes',choice9: '5 minutes',defaultValue: 'No Preview'}, {name: 'ticketShowPreviewGrays', label: '1S2. Allow users without tokens to view the free preview?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No'}, // *** General Settings {name: 'general', label: '---------------------------------------------------------------------------------- PERSONALIZATION ---------------------------------------------------------------------------------- ', type: 'choice',required: false}, {name: 'modLevel', label: '2A. Moderator Trust Level -- This will control how much authority and access is granted to moderators, and 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 command usage abilities as a broadcaster (not CB functions like banning users).', type: 'choice', choice1: 'Basic', choice2: 'Standard', choice3: 'Advanced', defaultValue: 'Standard'}, {name: 'extFanList', label: '2B1. External FanClub 1 List -- Enter the names of any External Fan Club 1 members you would like to grant special privileges, such as free or reduced prices to ticket shows. User names should be separated by a comma with no spaces', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'EFCname', label: '2B2. External FanClub 1 Name -- Enter the Display Name of the External Fan Club 1 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: 'extFanList2', label: '2B3. External FanClub 2 List -- Enter the names of any External Fan Club 2 members you would like to grant special privileges, such as free or reduced prices to ticket shows. User names should be separated by a comma with no spaces', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'EFCname2', label: '2B4. External FanClub 2 Name -- Enter the Display Name of 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: 'VIPList', label: '2B5. VIP List -- Enter the names of any VIP List users you would like to grant special privileges, such as free or reduced prices to ticket shows. User names should be separated by a comma with no spaces', type: 'str', minLength: 1, maxLength: 1000, defaultValue: '', required: false}, {name: 'VIPname', label: '2B6. VIP List Name -- Enter the Display Name of the VIP List if you have a personalized one. Default is "VIP List" if you do not enter one.', type: 'str', minLength: 1, maxLength: 50, required: false}, {name: 'bctext', label: '2C. Broadcaster Display Name -- 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: 'panelBackground', label: '2D1. Background Panel Graphic -- Which background panel type would you like to display? Note you cannot use "My Custom Panel" background unless one has been created for your room, otherwise it will use the default if that is selected', type: 'choice', choice1: 'default - no image', choice2: backgroundArray.menu[0], choice3: backgroundArray.menu[1], choice4: backgroundArray.menu[2], choice5: backgroundArray.menu[3], choice6: backgroundArray.menu[4], choice7: backgroundArray.menu[5], choice8: backgroundArray.menu[6], choice9: backgroundArray.menu[7], choice10: backgroundArray.menu[8], choice11: backgroundArray.menu[9], choice12: backgroundArray.menu[10], choice13: backgroundArray.menu[11], choice14: backgroundArray.menu[12], choice15: backgroundArray.menu[13], choice16: backgroundArray.menu[14], choice17: backgroundArray.menu[15], choice18: backgroundArray.menu[16], choice19: backgroundArray.menu[17], choice20: backgroundArray.menu[18], choice21: backgroundArray.menu[19], choice22: backgroundArray.menu[20], choice23: backgroundArray.menu[21], choice24: backgroundArray.menu[22], choice25: backgroundArray.menu[23], choice26: backgroundArray.menu[24], choice27: backgroundArray.menu[25], choice28: backgroundArray.menu[26], choice29: backgroundArray.menu[27], choice30: backgroundArray.menu[28], choice31: backgroundArray.menu[29], choice32: backgroundArray.menu[30], choice33: backgroundArray.menu[31], choice34: backgroundArray.menu[32], choice35: backgroundArray.menu[33], choice36: backgroundArray.menu[34], choice37: backgroundArray.menu[35], choice38: backgroundArray.menu[36], choice39: backgroundArray.menu[37], choice40: backgroundArray.menu[38], choice41: backgroundArray.menu[39], choice42: backgroundArray.menu[40], choice43: backgroundArray.menu[41], choice44: backgroundArray.menu[42], choice45: backgroundArray.menu[43], choice46: backgroundArray.menu[44], choice47: backgroundArray.menu[45], choice48: backgroundArray.menu[46], choice49: backgroundArray.menu[47], choice50: backgroundArray.menu[48], choice51: backgroundArray.menu[49], choice52: backgroundArray.menu[50], choice53: backgroundArray.menu[51], choice54: backgroundArray.menu[52], choice55: backgroundArray.menu[53], choice56: backgroundArray.menu[54], choice57: backgroundArray.menu[55], choice58: backgroundArray.menu[56], choice59: backgroundArray.menu[57], choice60: backgroundArray.menu[58], choice61: backgroundArray.menu[59], choice62: backgroundArray.menu[60], choice63: backgroundArray.menu[61], choice64: backgroundArray.menu[62], choice65: backgroundArray.menu[63], choice66: backgroundArray.menu[64], defaultValue: 'default - no image'}, {name: 'panelTextColor', label: '2D2. Panel Text Color -- Choose from the menu or select "Custom" and input a color code below',type: 'choice',choice1: 'White/No Color',choice2: 'Black',choice3: 'Dark Grey',choice4: 'Dark Red',choice5: 'Dark Orange',choice6: 'Dark Green',choice7: 'Dark Aqua',choice8: 'Dark Blue',choice9: 'Dark Purple',choice10: 'Dark Pink',choice11: 'Dark Gold',choice12: 'Dark Teal',choice13: 'Dark Brown',choice14: 'Dark Bronze',choice15: 'Dark Periwinkle',choice16: 'Dark Fuschia',choice17: 'Dark Lime',choice18: 'Dark Plum',choice19: 'Custom',defaultValue: 'Black'}, {name: 'panelCustomTextColor', label: '2D3. Panel Text Custom Color -- If you picked a custom text color in the previous setting, enter the hex color (6 character hex color codes including the # prefix, such as #FFFFFF):', type: 'str', minLength: 1, maxLength: 7, required: false}, {name: 'colorTheme', label: '2E. Use a color theme for the recurring notice text background? -- You can set this to the same value as in other Dorothy Apps and Bots to make all the notices match. When choosing "custom", enter your chosen colors below in settings "2F1-4".', type: 'choice', choice1: 'None', choice2: 'Custom', choice3: themeArray.name[0], choice4: themeArray.name[1], choice5: themeArray.name[2], choice6: themeArray.name[3], choice7: themeArray.name[4], choice8: themeArray.name[5], choice9: themeArray.name[6], choice10: themeArray.name[7], choice11: themeArray.name[8], choice12: themeArray.name[9], choice13: themeArray.name[10], choice14: themeArray.name[11], choice15: themeArray.name[12], choice16: themeArray.name[13], defaultValue: themeArray.name[5]}, {name: 'colorThemeCustBg1', label: '2F1. Custom Color 1 - If you picked "custom" color theme above in setting 2E, 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: '2F2. Custom Color 2 - If you picked "custom" color theme above in setting 2E, 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: '2F3. Custom Color 3 - If you picked "custom" color theme above in setting 2E, enter the hex color code for background color 3 (optional)',type: 'str',minLength: 1,maxLength: 7,required: false}, {name: 'colorThemeCustText', label: '2F4. Custom Text Color - If you picked "custom" color theme above in setting 2E, 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: '2G. Use a color gradient (gradual fade from one color to another) in the recurring notice backgrounds? -- This will be used if you choose a "custom" theme. Note that the gradient setting only affects the shading pattern, the actual colors used are defined above. For the pre-configured color themes, the gradient direction is predefined, 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: 'ticketNoticeInterval', label: '2H. Time interval for displaying the Ticket Show Price Notice in the chat, in minutes. Decimals are ok as long as they are greater than 1. For example, 1.5 = "One minute and 30 second" intervals.',required: false,type: 'str',defaultValue: 1.2}, {name: 'textWrapLength', label: '2J. 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 where longer text could be used. Default value is 78 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: 78}, {name: 'boldText', label: '2K. Display ticket show chat notices in bold or plain text?', type: 'choice', choice1: 'Bold Text', choice2: 'Plain Text', defaultValue: 'Bold Text'} ]; // *********************************** Variables and Arrays ************************************** var initialize = 0; var chatMsgToggle = false; var BC = cb.room_slug; var ticketAppPanelText3 = ' '; var panelText3Updated = false; var fontSize = 12; var appStartTime = 0; var bcText = ''; var EFCname = ''; var EFCname2 = ''; var VIPname = ''; var currentAppTotalTicket = 0; var currentSessionTotal = 0; var fixShowDelay = 3000; var showStage = 'ticketsales' var fixAlreadyRun = false; var fixTicketsRunning = false; var fixTicketsDontAdd = false; var checkSpecial = /[!@#$%^&*()+\-=\[\]{};':"\\|,.<>\/?]+/; var wrapMaxLength = cb.settings.textWrapLength; var ticketEmoji = '\uD83C\uDF9F\uFE0F'; var botName = 'Ticket Show: '; var whichApp = 'ticket'; var modLevel = cb.settings.modLevel; var backgroundImage = ''; var currentPanel = ''; var colorTheme = cb.settings.colorTheme; var maxTipToGoal = cb.settings.maxTipToGoal; var boldTextLiteral = ''; var textColor = 'black'; var appNoticeColor = '#f4d599'; var appErrorColor = '#f4c1bc'; var ticketHolderBgColor = 'linear-gradient(to bottom, #ffffff 20%, #cdf2ff 100%)'; var freePreviewerBgColor = '#fff6e7' var panelPreviewOn = false; var savedPanelBackground = ''; var savedPanelFilename = ''; var savedBotPanel = false; var panelPreviewer = ''; var currentPanelCycleIndex = 0; var leftjust1 = 20; var leftjust2 = 20; var leftjust3 = 20; var topjust1 = 4; var topjust2 = 27; var topjust3 = 49; var borderTicketTop = ''; var borderTicketBottom = ''; var borderAllNotices = ''; var ticketSubjectText = cb.settings.ticketRoomSubjectSfx; var ticketNoticesTextColor = ''; var ticketNoticesBgColor = ''; var ticketTextColorFan = ''; var ticketBgColorFan = ''; var ticketTextColorVIP = ''; var ticketBgColorVIP = ''; var ticketTextColorMod = ''; var ticketBgColorMod = ''; var ticketTextColor = ''; var ticketBgColor = ''; var ticketStartMode = ''; var ticketModeAuto = ''; var ticketShowTotalTips = 0; var ticketShowTotalTicketsBought = 0; var ticketStartTime = 0; var ticketStopTime = 0; var ticketTimeAdded = 0; var ticketMinsRemain = 0; var ticketSecsRemain = 0; var ticketShowGoal = parseInt(cb.settings.ticketShowGoal); var ticketShowAllowGift = cb.settings.ticketShowAllowGift; var ticketShowOtToggle = false; var ticketPrice = cb.settings.ticketShowPrice; var ticketShowEnded = false; var ticketSalesEnded = false; var countTickets = 0; var countTicketsFromPreview = 0; var ticketTimeAmt = cb.settings.ticketShowStartTimer; var ticketShowGoalTokens = cb.settings.ticketShowGoal; var ticketModeMessage = ''; var hiddenTime = 0; var ticketNoticeInt = 0; var ticketShowGoalTickets = 0; var ticketTimerStopping = false; var ticketDisplaySeconds = false; var ticketShowStartPrice = 0; var freePreviewLength = 0; var savedTicketSubjectText = ''; var afterNoticeInt = 90000; var freePreviewLengthText = ''; var ticketCountdownRunning = false; var tktNoticeRunning = false; var ticketShowPriceFC = cb.settings.ticketShowPriceFC; var ticketShowPriceEFC = cb.settings.ticketShowPriceEFC; var ticketShowPriceEFC2 = cb.settings.ticketShowPriceEFC2; var ticketShowPriceVIP = cb.settings.ticketShowPriceVIP; 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 noticeOnlyBCMod3P = botName + 'Only broadcasters and moderators with configured "price change" authority are able to use that command.'; // Arrays */ var fanClubInShow = []; var VIPListArray = []; var VIPsInShow = []; var extFanListArray = []; var extFanList2Array = []; var extFansInShow = []; var extFansInShow2 = []; var moderatorList = {name: [], type: []}; var modsInShow = []; var ticketShowViewerList = []; var ticketShowPreViewerList = []; var ticketHolderList = []; var ticketCumulative = {name: [], amount: []}; var outstandingTicketArray = []; var otChangesArray = {name: [], type: []}; var ticketShowExtraTickets = {name: [], count: []}; var drawpanel = {panel: {}}; var freePreviewUserArray = []; var freePreviewTimeArray = [0]; var noticeIntervals = {name: [], time: [], fieldname: []}; var cbAccessList = []; String.prototype.capitalize = function() { return this.charAt(0).toUpperCase() + this.slice(1); } // *********************************** Initialize ************************************** if (initialize == 0) { let intromessage = '\u26D4 Dorothys Ticket Show v3.0 -- Version 3.0 was released on November 13, 2021 \u26D4'; intromessage += '\n \u2705 Dorothy\'s Ticket Show 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://www.freesexcam.ca/apps/app_details/dorothys-ultraapp/ '; intromessage += '\n \u2705 ' + wordWrap('Hopefully this version of the ticket show is only in use temporarily while CB fixes the issues that prevent ticket shows from staying private with large numbers of ticket buyers. It has been re-written to only give ticket buyers hidden show access immediately after "start show" has been entered or tiggered'); intromessage += '\n \u2705 ' + wordWrap('Reminder: You can type "/tickethelp" to display the ticket show command list'); cb.sendNotice(intromessage, BC, appErrorColor); if (cb.settings.bctext) { bcText = cb.settings.bctext; } else { bcText = 'The Broadcaster'; } // *** Initialize variables across all Apps once at beginning loadNoticeIntervals(); loadAllStaticColors(BC); if (colorTheme != 'None') { loadThemeColors(BC); } if (cb.settings.boldText == 'Bold Text') { boldTextLiteral = 'bold'; } borderTicketTop = new Array(37).join('-') + ' ' + ticketEmoji + ' TICKET SHOW ' + ticketEmoji + ' ' + new Array(38).join('-'); borderTicketBottom = '\n' + new Array(49).join('-') + ' \u25CF ' + new Array(49).join('-'); borderAllNotices = new Array(49).join('-') + ' \u25CF ' + new Array(49).join('-'); // *** Personalized names if (cb.settings.EFCname != '' && cb.settings.EFCname != null) { EFCname = cb.settings.EFCname; } else { EFCname = 'External Fan Club'; } if (cb.settings.EFCname2 != '' && cb.settings.EFCname2 != null) { EFCname2 = cb.settings.EFCname2; } else { EFCname2 = 'External Fan Club 2'; } if (cb.settings.VIPname != '' && cb.settings.VIPname != null) { VIPname = cb.settings.VIPname; } else { VIPname = 'VIP List'; } // *** Init Ticket Show Related Settings freePreviewLengthText = cb.settings.ticketShowPreviewLength; switch (freePreviewLengthText) { case 'No Preview': { freePreviewLength = 0; break; } case '10 seconds': { freePreviewLength = 10; break; } case '20 seconds': { freePreviewLength = 20; break; } case '30 seconds': { freePreviewLength = 30; break; } case '1 minute': { freePreviewLength = 60; break; } case '2 minutes': { freePreviewLength = 120; break; } case '3 minutes': { freePreviewLength = 180; break; } case '4 minutes': { freePreviewLength = 240; break; } case '5 minutes': { freePreviewLength = 300; break; } } //*** Initialize panel if (cb.settings.panelBackground != 'default - no image') { if (cbjs.arrayContains(backgroundArray.menu,cb.settings.panelBackground)) { let initbackground = backgroundArray.command[backgroundArray.menu.indexOf(cb.settings.panelBackground)]; customizePanelBackground(initbackground,BC,'init'); customizePanelText('',BC); } else { botPanel = false; cb.sendNotice('A panel background was chosen but it does not exist, using the default panel background.', BC, appNoticeColor); } } else { botPanel = false; } initTicketShow(BC); cb.drawPanel(); if (cb.settings.ticketShowFanAppreciation == 'Yes') { cb.sendNotice(borderTicketTop + '\nToday\'s Ticket Show is a Fan Club Appreciation Show!\nOnly configured Fan Club Members will be admitted to the show!\nPlease consider joining the Fan Club!' + borderTicketBottom, '', ticketBgColor, ticketTextColor, 'bold'); } else { cb.sendNotice(borderTicketTop + '\n' + bcText + ' has started selling tickets for the show for ' + ticketPrice + ' tokens.' + borderTicketBottom, '', ticketBgColor, ticketTextColor, 'bold'); } if (cb.settings.ticketShowStartPrice > 0) { if (cb.settings.ticketShowStartPrice > ticketPrice) { ticketShowStartPrice = cb.settings.ticketShowStartPrice; } else { cb.sendNotice('Unable to set new price for start of Ticket Show as it is not greater than the initial price. Ticket Show Start price change is disabled. You can use the command "/showstartprice xx" to update the price to a value greater than the initial price of ' + ticketPrice + '.', BC, appNoticeColor); ticketShowStartPrice = 0; } } else { ticketShowStartPrice = 0; } //*** Init OT List for Ticket Show if (cb.settings.ticketShowEnableOT == 'Yes' && cb.settings.ticketShowFanAppreciation != 'Yes') { setTicketShowOtToggle('on',BC) } if (cb.settings.ticketShowOTList) { let otn = cb.settings.ticketShowOTList.toLowerCase(); let tempotlarray = otn.split(','); let initotltoadd = ''; for (let otlidx = 0; otlidx < tempotlarray.length; otlidx++) { initotltoadd = tempotlarray[otlidx].trim(); if (validateUserID(initotltoadd,'Outstanding Ticket List')) { if (cbjs.arrayContains(outstandingTicketArray,initotltoadd)) { cb.sendNotice(botName + 'Skipping duplicate entry for user "' + initotltoadd + '" in the Outstanding Ticket List.', BC, appNoticeColor); } else { outstandingTicketArray.push(initotltoadd); } } } } //*** Init External Fan Club 1 List if (cb.settings.extFanList) { let efcn = cb.settings.extFanList.toLowerCase(); let tempefcarray = efcn.split(','); let initefctoadd = ''; for (let efcnidx = 0; efcnidx < tempefcarray.length; efcnidx++) { initefctoadd = tempefcarray[efcnidx].trim(); if (validateUserID(initefctoadd,'External Fan Club 1 List')) { if (cbjs.arrayContains(extFanListArray,initefctoadd)) { cb.sendNotice(botName + 'Skipping duplicate entry for user "' + initefctoadd + '" in the External Fanclub List.', BC, appNoticeColor); } else { extFanListArray.push(initefctoadd); } } } } //*** Init External Fan Club 2 List if (cb.settings.extFanList2) { let efc2n = cb.settings.extFanList2.toLowerCase(); let tempefc2array = efc2n.split(','); let initefc2toadd = ''; for (let efc2nidx = 0; efc2nidx < tempefc2array.length; efc2nidx++) { initefc2toadd = tempefc2array[efc2nidx].trim(); if (validateUserID(initefc2toadd,'External Fan Club 2 List')) { if (cbjs.arrayContains(extFanList2Array,initefc2toadd)) { cb.sendNotice(botName + 'Skipping duplicate entry for user "' + initefc2toadd + '" in the External Fanclub 2 List.', BC, appNoticeColor); } else { extFanList2Array.push(initefc2toadd); } } } } //*** Init VIP List if (cb.settings.VIPList) { let vipn = cb.settings.VIPList.toLowerCase(); let tempviparray = vipn.split(','); let initviptoadd = ''; for (let vipnidx = 0; vipnidx < tempviparray.length; vipnidx++) { initviptoadd = tempviparray[vipnidx].trim(); if (validateUserID(initviptoadd,'VIP List')) { if (cbjs.arrayContains(VIPListArray,initviptoadd)) { cb.sendNotice(botName + 'Skipping duplicate entry for user "' + initviptoadd + '" in the VIP List.', BC, appNoticeColor); } else { VIPListArray.push(initviptoadd); } } } } appStartTime = new Date(); initialize = 1; } // ** Functions ** //********** Check Next Line Function and Word Wrap ************** function checkNextLine(nlmessage) { var nlmessagearray = nlmessage.split(' '); var nllinearray = []; var templinearray = []; var lineidx = 0; var currlineidx = 0; var nlreplace = false; var nlsubfound = true; while (nlsubfound) { if (cbjs.arrayContains(nlmessagearray,'{n}')) { let nlmsgindex = nlmessagearray.indexOf('{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 (var 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) { var white = new RegExp(/^\s$/); return white.test(whitestring.charAt(0)); } //********** Check Username Function ************** function checkUsername(ckusermessage,chkuser) { var responsemessagearray = ckusermessage.split(' '); var userreplace = false; if (cbjs.arrayContains(responsemessagearray,'{username}')) { let msgindex = responsemessagearray.indexOf('{username}'); responsemessagearray[msgindex] = chkuser; userreplace = true; } else if (cbjs.arrayContains(responsemessagearray,'{username},')) { let msgindex = responsemessagearray.indexOf('{username},'); responsemessagearray[msgindex] = chkuser + ','; userreplace = true; } else if (cbjs.arrayContains(responsemessagearray,'{username}!')) { let msgindex = responsemessagearray.indexOf('{username}!'); responsemessagearray[msgindex] = chkuser + '!'; userreplace = true; } else if (cbjs.arrayContains(responsemessagearray,'{username}:')) { let msgindex = responsemessagearray.indexOf('{username}:'); responsemessagearray[msgindex] = chkuser + ':'; userreplace = true; } else if (cbjs.arrayContains(responsemessagearray,'{username}.')) { let msgindex = responsemessagearray.indexOf('{username}.'); responsemessagearray[msgindex] = chkuser + '.'; userreplace = true; } if (userreplace) { return cbjs.arrayJoin(responsemessagearray,' '); } else { return ckusermessage; } } // Generic functions to set the color or separator characters function loadThemeColors(loadthemeby) { ticketBgColor = setThemeBgColor(loadthemeby); ticketTextColor = setThemeTextColor(loadthemeby); } function loadAllStaticColors() { ticketNoticesTextColor = setTextColor('Dark Red'); ticketNoticesBgColor = setBgColor('Cream'); ticketTextColorFan = setTextColor('Black'); ticketBgColorFan = setBgColor('Light Green'); ticketTextColorVIP = setTextColor('Black'); ticketBgColorVIP = setBgColor('Light Purple'); ticketTextColorMod = setTextColor('Black'); ticketBgColorMod = setBgColor('Light Red'); } function setThemeTextColor(sttcsendto) { var selectedthemetextcolor = '#000000'; if (colorTheme == 'Custom') { var 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 { 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, appNoticeColor); } } else { if (cbjs.arrayContains(themeArray.name,colorTheme)) { let themeidx = themeArray.name.indexOf(colorTheme); return themeArray.textcolor[themeidx]; } else { cb.sendNotice(botName + ' Warning! Invalid theme setting of "' + colorTheme + '". \nDefaulting to no theme used.', sttcsendto, appNoticeColor); colorTheme = 'None'; } } return selectedthemetextcolor; } function setThemeBgColor(setthemeby) { var selectedthemebgcolor = '#FFFFFF'; if (colorTheme == 'Custom') { var 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'; } var themecustbg1 = ''; var themecustbg2 = ''; var 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 { 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, appNoticeColor); colorTheme = 'None'; } } else { cb.sendNotice(botName + ' Warning! Custom color theme selected but Background 1 is not configured. \nDefaulting to no theme used.', setthemeby, appNoticeColor); 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'; 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, appNoticeColor); } } else { themecustbg2 = '#FFFFFF'; 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, appNoticeColor); } var 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 { cb.sendNotice(botName + ' Warning! Invalid theme setting of "' + colorTheme + '". \nDefaulting to no theme used.', setthemeby, appNoticeColor); colorTheme = 'None'; } } return selectedthemebgcolor; } function setTextColor(inputtextcolor,inputtextcolortype,inputtextcolorsendto) { var selectedtextcolor = '#FFFFFF'; if (cbjs.arrayContains(textColorArray.dispname,inputtextcolor)) { var 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 { 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, appNoticeColor); } } return selectedtextcolor; } function setBgColor(inputbgcolor,inputbgcolortype,inputbgcolorsendto) { var selectedbgcolor = '#FFFFFF'; if (cbjs.arrayContains(bgColorArray.dispname,inputbgcolor)) { var 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 { 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, appNoticeColor); } } 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 leftJustify(textstring,line) { var textstringlength = textstring.length; if (fontSize == 11) { if (line == 1) { if (textstringlength < 4) { return 114; } else if (textstringlength < 6) { return 109; } else if (textstringlength < 8) { return 104; } else if (textstringlength < 10) { return 100; } else if (textstringlength < 12) { return 95; } else if (textstringlength < 14) { return 90; } else if (textstringlength < 16) { return 86; } else if (textstringlength < 18) { return 82; } else if (textstringlength < 20) { return 77; } else if (textstringlength < 22) { return 72; } else if (textstringlength < 24) { return 67; } else if (textstringlength < 26) { return 62; } else if (textstringlength < 28) { return 58; } else if (textstringlength < 30) { return 53; } else if (textstringlength < 32) { return 49; } else if (textstringlength < 34) { return 44; } else if (textstringlength < 37) { return 39; } else if (textstringlength < 40) { return 34; } else if (textstringlength < 42) { return 30; } else if (textstringlength < 44) { return 26; } else if (textstringlength < 47) { return 21; } else if (textstringlength < 49) { return 16; } else if (textstringlength < 51) { return 11; } else { return 7; } } else { if (textstringlength < 4) { return 114; } else if (textstringlength < 6) { return 110; } else if (textstringlength < 8) { return 105; } else if (textstringlength < 10) { return 100; } else if (textstringlength < 12) { return 97; } else if (textstringlength < 14) { return 93; } else if (textstringlength < 16) { return 88; } else if (textstringlength < 18) { return 83; } else if (textstringlength < 20) { return 79; } else if (textstringlength < 22) { return 74; } else if (textstringlength < 24) { return 71; } else if (textstringlength < 26) { return 66; } else if (textstringlength < 28) { return 61; } else if (textstringlength < 30) { return 57; } else if (textstringlength < 32) { return 53; } else if (textstringlength < 34) { return 48; } else if (textstringlength < 37) { return 44; } else if (textstringlength < 39) { return 39; } else if (textstringlength < 42) { return 34; } else if (textstringlength < 44) { return 29; } else if (textstringlength < 47) { return 24; } else if (textstringlength < 49) { return 19; } else if (textstringlength < 52) { return 14; } else { return 7; } } } else { if (line == 1) { if (textstringlength < 4) { return 113; } else if (textstringlength < 6) { return 108; } else if (textstringlength < 8) { return 103; } else if (textstringlength < 10) { return 99; } else if (textstringlength < 12) { return 94; } else if (textstringlength < 14) { return 89; } else if (textstringlength < 16) { return 84; } else if (textstringlength < 18) { return 80; } else if (textstringlength < 20) { return 75; } else if (textstringlength < 22) { return 70; } else if (textstringlength < 24) { return 65; } else if (textstringlength < 26) { return 60; } else if (textstringlength < 28) { return 55; } else if (textstringlength < 30) { return 50; } else if (textstringlength < 32) { return 46; } else if (textstringlength < 34) { return 41; } else if (textstringlength < 37) { return 36; } else if (textstringlength < 40) { return 31; } else if (textstringlength < 42) { return 26; } else if (textstringlength < 44) { return 22; } else if (textstringlength < 47) { return 17; } else if (textstringlength < 49) { return 12; } else if (textstringlength < 51) { return 7; } else { return 3; } } else { if (textstringlength < 4) { return 113; } else if (textstringlength < 6) { return 109; } else if (textstringlength < 8) { return 104; } else if (textstringlength < 10) { return 99; } else if (textstringlength < 12) { return 95; } else if (textstringlength < 14) { return 91; } else if (textstringlength < 16) { return 86; } else if (textstringlength < 18) { return 81; } else if (textstringlength < 20) { return 77; } else if (textstringlength < 22) { return 72; } else if (textstringlength < 24) { return 68; } else if (textstringlength < 26) { return 63; } else if (textstringlength < 28) { return 58; } else if (textstringlength < 30) { return 54; } else if (textstringlength < 32) { return 50; } else if (textstringlength < 34) { return 45; } else if (textstringlength < 37) { return 40; } else if (textstringlength < 39) { return 35; } else if (textstringlength < 42) { return 30; } else if (textstringlength < 44) { return 25; } else if (textstringlength < 47) { return 20; } else if (textstringlength < 49) { return 15; } else if (textstringlength < 52) { return 10; } else { return 3; } } } } //********** User ID list validations ************** function validateUserID(validateuser,validatetype) { if (validateuser.length < 3 || validateuser.includes(' ')) { cb.sendNotice('Cannot load ' + validatetype + ' entry "' + validateuser + '", it is improperly formatted (either contains a blank or is less than 3 characters).', BC, appNoticeColor); return false; } else if (checkSpecial.test(validateuser)) { cb.sendNotice('Cannot load ' + validatetype + ' entry "' + validateuser + '", it contains a special character.', BC, appNoticeColor); return false; } else { return true; } } //********** Build Moderator Array ************** function addRmvModsInShow(armisuser,armismode) { if (armismode == 'a') { if (cbjs.arrayContains(modsInShow,armisuser)) { return; } else { modsInShow.push(armisuser); } } else if (armismode == 'r') { if (cbjs.arrayContains(modsInShow,armisuser)) { cbjs.arrayRemove(modsInShow,armisuser); } else { return; } } } function addRmvFanClubInShow(arfcisuser,arfcismode) { if (arfcismode == 'a') { if (!cbjs.arrayContains(fanClubInShow,arfcisuser)) { fanClubInShow.push(arfcisuser); } else { return; } } else if (arfcismode == 'r') { if (cbjs.arrayContains(fanClubInShow,arfcisuser)) { cbjs.arrayRemove(fanClubInShow,arfcisuser); } else { return; } } } function addRmvVIP(arvuser,arvmode) { if (arvmode == 'a') { if (cbjs.arrayContains(VIPListArray,arvuser)) { return; } else { VIPListArray.push(arvuser); } } else if (arvmode == 'r') { if (cbjs.arrayContains(VIPListArray,arvuser)) { cbjs.arrayRemove(VIPListArray,arvuser); } else { return; } } } function addRmvVIPInShow(arvisuser,arvismode) { if (arvismode == 'a') { if (cbjs.arrayContains(VIPsInShow,arvisuser)) { return; } else { VIPsInShow.push(arvisuser); } } else if (arvismode == 'r') { if (cbjs.arrayContains(VIPsInShow,arvisuser)) { cbjs.arrayRemove(VIPsInShow,arvisuser); } else { return; } } } function addRmvExtFan(arefuser,arefmode) { if (arefmode == 'a') { if (cbjs.arrayContains(extFanListArray,arefuser)) { return; } else { extFanListArray.push(arefuser); } } else if (arefmode == 'r') { if (cbjs.arrayContains(extFanListArray,arefuser)) { cbjs.arrayRemove(extFanListArray,arefuser); } else { return; } } } function addRmvExtFan2(aref2user,aref2mode) { if (aref2mode == 'a') { if (cbjs.arrayContains(extFanList2Array,aref2user)) { return; } else { extFanList2Array.push(aref2user); } } else if (aref2mode == 'r') { if (cbjs.arrayContains(extFanList2Array,aref2user)) { cbjs.arrayRemove(extFanList2Array,aref2user); } else { return; } } } function addRmvExtFanInShow(arefisuser,arefismode) { if (arefismode == 'a') { if (cbjs.arrayContains(extFansInShow,arefisuser)) { return; } else { extFansInShow.push(arefisuser); } } else if (arefismode == 'r') { if (cbjs.arrayContains(extFansInShow,arefisuser)) { cbjs.arrayRemove(extFansInShow,arefisuser); } else { return; } } } function addRmvExtFanInShow2(aref2isuser,aref2ismode) { if (aref2ismode == 'a') { if (cbjs.arrayContains(extFansInShow2,aref2isuser)) { return; } else { extFansInShow2.push(aref2isuser); } } else if (aref2ismode == 'r') { if (cbjs.arrayContains(extFansInShow2,aref2isuser)) { cbjs.arrayRemove(extFansInShow2,aref2isuser); } else { return; } } } function loadNoticeIntervals() { noticeIntervals.name[5] = 'ticket'; noticeIntervals.fieldname[5] = 'ticketNoticeInt'; updateIntervalArray('ticket',cb.settings.ticketNoticeInterval,1.7); } function updateIntervalArray(updtinttype,updintint,updintdft) { if (!updintint) { updintint = updintdft; cb.sendNotice(botName + '"' + updtinttype + '" Chat Notice Interval is not configured. Using default value of ' + updintdft + ' minutes.', BC, appNoticeColor); } if (updintint > 0 && updintint < 1) { updintint = updintdft; cb.sendNotice(botName + '"' + updtinttype + '" Chat Notice Interval is too short, must be at least 1 minute. Using default value of ' + updintdft + ' minutes.', BC, appNoticeColor); } if (cbjs.arrayContains(noticeIntervals.name,updtinttype)) { let nameidx = noticeIntervals.name.indexOf(updtinttype); let actualint = parseInt(updintint*60000); this[noticeIntervals.fieldname[nameidx]] = actualint; noticeIntervals.time[nameidx] = actualint; } } //********** Set custom panel text and background ************** function customizePanelText(cptcolor,cptsendto) { if (!cptcolor && cb.settings.panelTextColor == 'Custom') { var textcolorchk = setTextColor(cb.settings.panelCustomTextColor,false); if (textcolorchk == 'default') { cb.sendNotice('Draw Panel Text Color - Error while setting the text color. It has to be in a HEX format.', cptsendto, appNoticeColor, ''); } else { textColor = textcolorchk; } } else if (cptcolor) { textcolorchk = setTextColor(cptcolor,false); if (textcolorchk == 'default') { cb.sendNotice('Draw Panel Text Color - Error while setting the text color. It has to be in a HEX format.', cptsendto, appNoticeColor, ''); } else { textColor = textcolorchk; } } else { textColor = setTextColor(cb.settings.panelTextColor,false); cb.drawPanel(); } } function customizePanelBackground(newbackground,sendto,custpanelmode) { botPanel = false; if (cbjs.arrayContains(backgroundArray.command,newbackground)) { var bgindex = backgroundArray.command.indexOf(newbackground); // dorothy is the testbed user if (BC == 'dorothy') { backgroundImage = backgroundArray.devfile[bgindex]; botPanel = true; currentPanel = newbackground; if (custpanelmode != 'init') { cb.sendNotice('You have updated the panel background to "' + newbackground + '".', sendto, appNoticeColor, ''); } } else { backgroundImage = backgroundArray.livefile[bgindex]; botPanel = true; currentPanel = newbackground; if (custpanelmode != 'init') { cb.sendNotice('You have updated the panel background to "' + newbackground + '".', sendto, appNoticeColor, ''); } } } else { cb.sendNotice('Invalid background name. The valid names are: \n' + cbjs.arrayJoin(backgroundArray.command, ', '), sendto, appNoticeColor, ''); } } function cyclePanels() { if (panelPreviewOn) { if (BC == 'dorothy') { backgroundImage = backgroundArray.devfile[currentPanelCycleIndex]; } else { backgroundImage = backgroundArray.livefile[currentPanelCycleIndex]; } currentPanel = backgroundArray.command[currentPanelCycleIndex]; if (currentPanel == 'custom') { cb.sendNotice('Skipping Panel #' + (currentPanelCycleIndex+1) + ': This is the placeholder for a customized room-specific panel.', panelPreviewer, appNoticeColor); } else { cb.drawPanel(); cb.sendNotice('Displaying Panel #' + (currentPanelCycleIndex+1) + ': panel ID is "' + currentPanel + '".', panelPreviewer, appNoticeColor); } botPanel = true; currentPanelCycleIndex ++; if (currentPanelCycleIndex >= backgroundArray.menu.length) { currentPanel = savedPanelBackground; backgroundImage = savedPanelFilename; botPanel = savedBotPanel; cb.drawPanel(); panelPreviewOn = false; cb.sendNotice('The panel background preview has finished, all panels displayed. It has now returned to the previously used panel.', panelPreviewer, appNoticeColor); } else { cb.setTimeout(cyclePanels, 10000); } } } // *********************************** Length of show ************************************** function clockTimeCal() { var timenow = new Date(); return timenow - appStartTime.getTime(); } function timeOnline() { var timeElapsed = clockTimeCal(); var clockMS = timeElapsed % 1000; var clockSeconds = ((timeElapsed - clockMS) % 60000); var clockMinutes = ((timeElapsed - clockSeconds - clockMS) % 3600000); var clockHours = (timeElapsed - clockMinutes - clockSeconds - clockMS); clockSeconds = clockSeconds / 1000; clockMinutes = clockMinutes / 60000; clockHours = clockHours / 3600000; if (clockHours > 0) { return clockHours + ' hour' + (clockHours > 1 ? 's' : '') + ' and ' + clockMinutes + ' minute' + (clockMinutes > 1 ? 's' : ''); } else if (clockMinutes > 0 && clockSeconds === 0) { return clockMinutes + ' minute' + (clockMinutes > 1 ? 's' : ''); } else if (clockMinutes > 0) { return clockMinutes + ' minute' + (clockMinutes > 1 ? 's' : '') + ' and ' + clockSeconds + ' second' + (clockSeconds > 1 ? 's' : ''); } else { return clockSeconds + ' second' + (clockSeconds > 1 ? 's' : ''); } } //******************** Goal Bar ************************** function goalBar(currentamt,totalamt) { var percentbar = 0; if (currentamt > 0 && totalamt > 0) { percentbar = Math.round(100*(currentamt/totalamt)); } var barstring = ''; var fullicon = '\u25C6'; var halficon = '\u25C8'; var emptyicon = '\u25C7'; var var1 = (percentbar - (percentbar % 10)) / 10; var var2 = (percentbar % 10) > 0 ? 1 : 0; var var3 = 10 - (var1 + var2); barstring += charRepeat(fullicon, var1); (var2 === 1 ? barstring += halficon : barstring += ''); barstring += charRepeat(emptyicon, var3) return barstring; } function charRepeat(repeatchar,repeatln) { var repeatstring = ''; for (var charindex = 1; charindex <= repeatln; charindex++) { repeatstring += repeatchar } return repeatstring; } //********** Record Tip and Track Goal Progress ************** function recordTip(tippedamount,tippedby,tippedisfan,tippedisextfan,tippedisextfan2,tippedisvip,tippedbydisp) { if (tippedby != 'bc') { currentAppTotalTicket += tippedamount; currentSessionTotal += tippedamount; } if (cb.settings.ticketShowFanAppreciation != 'Yes') { if (!ticketShowEnded && !ticketSalesEnded && !cbjs.arrayContains(ticketHolderList,tippedby)) { if (tippedisfan) { if (tippedamount >= ticketShowPriceFC) { addRmvTicket('addtip',tippedby,'fan',tippedamount,tippedbydisp); } else { checkCumulative(tippedby,tippedamount,ticketShowPriceFC,'fan','ticket',tippedbydisp); } } else if (tippedisextfan) { if (tippedamount >= ticketShowPriceEFC) { addRmvTicket('addtip',tippedby,'extfan',tippedamount,tippedbydisp); } else { checkCumulative(tippedby,tippedamount,ticketShowPriceEFC,'extfan','ticket',tippedbydisp); } } else if (tippedisextfan2) { if (tippedamount >= ticketShowPriceEFC2) { addRmvTicket('addtip',tippedby,'extfan2',tippedamount,tippedbydisp); } else { checkCumulative(tippedby,tippedamount,ticketShowPriceEFC2,'extfan2','ticket',tippedbydisp); } } else if (tippedisvip) { if (tippedamount >= ticketShowPriceVIP) { addRmvTicket('addtip',tippedby,'vip',tippedamount,tippedbydisp); } else { checkCumulative(tippedby,tippedamount,ticketShowPriceVIP,'vip','ticket',tippedbydisp); } } else { if (tippedamount >= ticketPrice) { addRmvTicket('addtip',tippedby,'common',tippedamount,tippedbydisp); } else { checkCumulative(tippedby,tippedamount,ticketPrice,'common','ticket',tippedbydisp); } } } else if (!ticketShowEnded && !ticketSalesEnded && cbjs.arrayContains(ticketHolderList,tippedby) && ticketShowAllowGift == 'Yes') { if (tippedamount >= ticketPrice) { addRmvTicket('addextra', tippedby, 'common', tippedamount,tippedbydisp); } } ticketShowGoalProgress(tippedamount); } cb.drawPanel(); } function checkCumulative(tippedbycum,tippedamountcum,cumTktPrice,usertype,saletype,tippedbycumdisp) { if (cb.settings.ticketShowCumulative == 'Yes') { if (!cbjs.arrayContains(ticketCumulative.name, tippedbycum)) { ticketCumulative.name.push(tippedbycum); ticketCumulative.amount.push(tippedamountcum); } else { var chkcumidx = ticketCumulative.name.indexOf(tippedbycum); if (ticketCumulative.amount[chkcumidx] + tippedamountcum >= cumTktPrice) { addRmvTicket('addtip',tippedbycum,usertype,tippedamountcum,tippedbycumdisp); ticketCumulative.amount[chkcumidx] = 0; } else { ticketCumulative.amount[chkcumidx] += tippedamountcum; } } } } function buildSubject(currenttext,addition) { if (currenttext != '') { return currenttext + ' -- ' + addition; } else { return addition; } } function changeRoomSubject() { let newsubject = ''; if (cb.settings.ticketShowFanAppreciation == 'Yes') { if (showStage == 'ticketsales') { newsubject += 'FANCLUB APPRECIATION SHOW STARTING SOON! JOIN FANCLUB TO SEE! '; } else if (showStage == 'ticketshow' || showStage == 'showwarn' || showStage == 'showfinale') { newsubject += 'FANCLUB APPRECIATION SHOW IN PROGRESS! JOIN FANCLUB TO SEE! '; } else if (showStage == 'aftershow') { newsubject += 'FANCLUB APPRECIATION SHOW HAS ENDED. THANK YOU FANS! '; } else { newsubject += 'FANCLUB APPRECIATION SHOW '; } } else { if (showStage == 'ticketsales') { newsubject += 'TICKET SHOW SALES [' + ticketPrice + ' tokens]: '; } else if (showStage == 'ticketshow') { newsubject += 'TICKET SHOW IN PROGRESS [' + ticketPrice + ' tokens]: '; } else if (showStage == 'showwarn') { newsubject += 'TICKET SHOW ENDING SOON [' + ticketPrice + ' tokens]: '; } else if (showStage == 'showfinale') { newsubject += 'TICKET SHOW SALES ENDED -- DO NOT BUY A TICKET!: '; } else if (showStage == 'aftershow') { newsubject += 'TICKET SHOW HAS ENDED: '; } else { newsubject += 'TICKET SHOW '; } } newsubject += ticketSubjectText; cb.changeRoomSubject(newsubject); } // *********************************** Ticket Show Functions ************************************** function initTicketShow(inittktsendto) { whichApp = 'ticket'; if (ticketHolderList.length > 0) { countTickets = ticketHolderList.length; } else { countTickets = 0; } countTicketsFromPreview = 0; showStage = 'ticketsales'; changeRoomSubject(); setTicketMode('init', inittktsendto); ticketShowEnded = false; ticketSalesEnded = false; loadFreeTickets(); if (!tktNoticeRunning) { cb.setTimeout(ticketNoticeDisplay,ticketNoticeInt); } cb.drawPanel(); } function ticketNoticeDisplay() { if (whichApp == 'ticket') { var tktmsg = ''; if (cb.settings.ticketShowFanAppreciation == 'Yes') { tktmsg += '\n**** Today\'s Ticket Show is a Fan Club Appreciation Show! ****'; tktmsg += '\nOnly configured Fan Club Members will be admitted to the show, please consider joining the Fan Club!'; } else { if (showStage == 'ticketsales') { tktmsg += '\n\u23E9 General Ticket Price: ' + ticketPrice + ' token' + (ticketPrice > 1 ? 's.' : '.'); tktmsg += '\n\u23E9 ' + wordWrap('Description: ' + ticketSubjectText); if (ticketStartMode == 'ticketgoal') { tktmsg += '\n\u23E9 Start Mode: Ticket Goal (Sold ' + ticketShowTotalTicketsBought + ' / ' + ticketShowGoalTickets + ' tickets)'; } else if (ticketStartMode == 'tokengoal') { tktmsg += '\n\u23E9 Start Mode: Token Goal (' + ticketShowTotalTips + ' / ' + ticketShowGoalTokens + ' tokens)'; } else if (ticketStartMode == 'timer') { tktmsg += '\n\u23E9 Start Mode: Timer (' + ((ticketSecsRemain > 0 || ticketMinsRemain > 0) ? ticketTimeLeft() : 'Timer not yet started') + ')'; } else { tktmsg += '\n\u23E9 Start Mode: Manual (Broadcaster or Moderator will start the show)'; } } else if (showStage == 'ticketshow') { tktmsg += '\n\u23E9 Ticket Price: ' + ticketPrice + ' token' + (ticketPrice > 1 ? 's.' : '.'); tktmsg += '\n\u23E9 Show has started, ticket sales still available'; tktmsg += '\n\u23E9 ' + wordWrap('Description: ' + ticketSubjectText); tktmsg += '\n\u23E9 Ticket show active for ' + ((Date.now() - hiddenTime)/60000).toFixed(1) + ' min'; if (freePreviewLength > 0) { if (cb.settings.ticketShowPreviewGrays == 'Yes') { tktmsg += '\n\u23E9 ' + wordWrap('Free preview is enabled (' + freePreviewLengthText + ')'); } else { tktmsg += '\n\u23E9 ' + wordWrap(' Free preview is enabled for users with tokens (' + freePreviewLengthText + ')'); } } } else if (showStage == 'showwarn') { tktmsg += '\n\u23E9 Ticket Price: ' + ticketPrice + ' token' + (ticketPrice > 1 ? 's.' : '.'); tktmsg += '\n\u23E9 Ticket Sales available, but show is ending soon!'; tktmsg += '\n\u23E9 ' + wordWrap('Description: ' + ticketSubjectText); } else if (showStage == 'showfinale') { tktmsg += '\n :siren1 :siren1 :siren1 Ticket Sales have ended, do not tip for a ticket! :siren1 :siren1 :siren1'; } else if (showStage == 'aftershow') { tktmsg += '\n\u23E9 ' + wordWrap('Show has ended! -- ' + cb.settings.ticketShowAfterNotice); } if (showStage != 'aftershow' && showStage != 'showfinale') { tktmsg += '\n\u23E9 Ticket Holders: ' + countTickets; if (ticketShowStartPrice > 0 && whichApp == 'ticket' && showStage == 'ticketsales') { tktmsg += '\n\u23E9 ' + wordWrap('Buy now! The ticket price will increase to ' + ticketShowStartPrice + ' tokens when the show is started.'); } if (ticketShowPriceFC > 1 && ticketShowPriceFC < ticketPrice && cb.settings.ticketShowFreeFC != 'Yes') { tktmsg += '\n\u23E9 Chaturbate Fanclub ticket price: ' + ticketShowPriceFC + ' token' + (ticketShowPriceFC > 1 ? 's.' : '.'); } else if (cb.settings.ticketShowFreeFC == 'Yes') { tktmsg += '\n\u23E9 Chaturbate Fanclub members get a free ticket!'; } if (extFanListArray.length > 0) { if (ticketShowPriceEFC > 1 && ticketShowPriceEFC < ticketPrice && cb.settings.ticketShowFreeEFC != 'Yes') { tktmsg += '\n\u23E9 ' + EFCname + ' ticket price: ' + ticketShowPriceEFC + ' token' + (ticketShowPriceEFC > 1 ? 's.' : '.'); } else if (cb.settings.ticketShowFreeEFC == 'Yes') { tktmsg += '\n\u23E9 ' + EFCname + ' members get a free ticket!'; } } if (extFanList2Array.length > 0) { if (ticketShowPriceEFC2 > 1 && ticketShowPriceEFC2 < ticketPrice && cb.settings.ticketShowFreeEFC2 != 'Yes') { tktmsg += '\n\u23E9 ' + EFCname2 + ' ticket price: ' + ticketShowPriceEFC2 + ' token' + (ticketShowPriceEFC2 > 1 ? 's.' : '.'); } else if (cb.settings.ticketShowFreeEFC2 == 'Yes') { tktmsg += '\n\u23E9 ' + EFCname2 + ' members get a free ticket!'; } } if (VIPListArray.length > 0) { if (ticketShowPriceVIP > 1 && ticketShowPriceVIP < ticketPrice && cb.settings.ticketShowFreeVIP != 'Yes') { tktmsg += '\n\u23E9 ' + VIPname + ' ticket price: ' + ticketShowPriceVIP + ' token' + (ticketShowPriceVIP > 1 ? 's.' : '.'); } else if (cb.settings.ticketShowFreeVIP == 'Yes') { tktmsg += '\n\u23E9 ' + VIPname + ' members get a free ticket!'; } } } } cb.sendNotice(borderTicketTop + tktmsg + borderTicketBottom, '', ticketBgColor, ticketTextColor, boldTextLiteral); tktNoticeRunning = true; cb.setTimeout(ticketNoticeDisplay,ticketNoticeInt); } } function setTicketShowOtToggle(mode,sendto) { if (mode == 'on') { if (ticketShowOtToggle) { cb.sendNotice('The Outstanding Ticket feature is already enabled.',sendto,appNoticeColor); } else { ticketShowOtToggle = true; let otlinitmessage = '\nThe Outstanding Ticket List feature is enabled for the Ticket Show.'; otlinitmessage += '\nTo save your ticket for later, type: /saveticket'; otlinitmessage += '\nThis will REMOVE you from the current show\'s ticket list.'; otlinitmessage += '\nTo redeem an outstanding ticket, type: /useticket'; otlinitmessage += '\nTo view the OT List, type: /otlist'; cb.sendNotice(borderTicketTop + otlinitmessage + borderTicketBottom, '', ticketBgColor, ticketTextColor, boldTextLiteral); cb.sendNotice('***Notice Regarding Outstanding Tickets***: \nThe Outstanding tickets added and removed during the show must be made permanent\nby updating the list on the App Launch page.\nThe list can be viewed by typing: /otlist.\nThe changes for the current session can be seen by typing: /otchanges.\nIt is recommended to save the list and update the OT list before the next show.\nChanges made during the show are not saved beyond the current session.', BC, appNoticeColor); } } else if (mode == 'off') { if (!ticketShowOtToggle) { cb.sendNotice('The Outstanding Ticket feature is already disabled.',sendto,appNoticeColor); } else { ticketShowOtToggle = false; cb.sendNotice('You have disabled the Outstanding Ticket (OT) feature.\nThe outstanding ticket list is still intact, but no more tickets will be sold.\nThe list can be viewed by typing: /otlist.\nThe changes for the current session can be seen by typing: /otchanges \nBe sure to update these entries into the OT List on the App Launch Page, they cannot be saved automatically.',sendto,appNoticeColor); } } } function setTicketPrice(amount,announce) { ticketPrice = parseInt(amount); if (announce == 'yes') { ticketPriceChangeNotice(ticketPrice); } } function ticketPriceChangeNotice(price) { cb.sendNotice(':ticket_red_small \u2749 \u2749 \u2749 :ticket_red_small \u2749 \u2749 \u2749 :ticket_red_small \n' + '\u21D2 . . . . Ticket Show Price Updated!!!. . . . . \u21D0 \n' + '\u21D2 . . . . Tickets are now ' + ticketPrice + ' tokens!!! . . . . . \u21D0 \n' + ':ticket_red_small \u2749 \u2749 \u2749 :ticket_red_small \u2749 \u2749 \u2749 :ticket_red_small' , "", ticketNoticesBgColor, ticketNoticesTextColor, "bold"); changeRoomSubject(); cb.drawPanel(); } function loadFreeTickets() { if (cb.settings.ticketShowFreeMods == 'Yes') { for (let i = 0; i < modsInShow.length; i++) { addRmvTicket('add',modsInShow[i],'mod',0,modsInShow[i]); } } if (cb.settings.ticketShowFreeFC == 'Yes') { for (let i = 0; i < fanClubInShow.length; i++) { addRmvTicket('add',fanClubInShow[i],'fan',0,fanClubInShow[i]); } } if (cb.settings.ticketShowFreeEFC == 'Yes') { for (let i = 0; i < extFansInShow.length; i++) { addRmvTicket('add',extFansInShow[i],'extfan',0,extFansInShow[i]); } } if (cb.settings.ticketShowFreeEFC2 == 'Yes') { for (let i = 0; i < extFansInShow2.length; i++) { addRmvTicket('add',extFansInShow2[i],'extfan2',0,extFansInShow2[i]); } } if (cb.settings.ticketShowFreeVIP == 'Yes') { for (let i = 0; i < VIPsInShow.length; i++) { addRmvTicket('add',VIPsInShow[i],'vip',0,VIPsInShow[i]); } } } function checkFreeTickets(checkfreeuser,checkfreemod,checkfreefan,checkfreeextfan,checkfreeextfan2,checkfreevip,checkmode) { if ((!cb.limitCam_userHasAccess(checkfreeuser) && !cbjs.arrayContains(ticketHolderList,checkfreeuser)) && showStage != 'aftershow') { if (checkfreemod) { if (cb.settings.ticketShowFreeMods == 'Yes') { addRmvTicket('add',checkfreeuser,'mod',0,checkfreeuser); cb.sendNotice(borderAllNotices + '\nYou\'ve been added to the show because you\'re a moderator! \n' + borderAllNotices, checkfreeuser, appNoticeColor, '', 'bold'); } else if (checkmode == 'enter') { cb.sendNotice(borderAllNotices + '\nThe Ticket Show has not been configured to give a free ticket to moderators. \n' + borderAllNotices, checkfreeuser, appNoticeColor, '', 'bold'); } } else if (checkfreefan) { if (cb.settings.ticketShowFreeFC == 'Yes') { addRmvTicket('add',checkfreeuser,'fan',0,checkfreeuser); cb.sendNotice(borderAllNotices + '\nYou\'ve automatically been added to the show because you\'re in the CB Fan Club! \n' + borderAllNotices, checkfreeuser, appNoticeColor, '', 'bold'); } else if (ticketShowPriceFC > 1 && checkmode == 'enter') { cb.sendNotice(borderAllNotices + '\nAs a CB Fan Club member, you can buy a ticket for ' + ticketShowPriceFC + ' tokens. \n' + borderAllNotices, checkfreeuser, appNoticeColor, '', 'bold'); } } else if (checkfreeextfan) { if (cb.settings.ticketShowFreeEFC == 'Yes') { addRmvTicket('add',checkfreeuser,'extfan',0,checkfreeuser); cb.sendNotice(borderAllNotices + '\nYou\'ve automatically been added to the show because you\'re in ' + EFCname + '! \n' + borderAllNotices, checkfreeuser, appNoticeColor, '', 'bold'); } else if (ticketShowPriceEFC > 1 && checkmode == 'enter') { cb.sendNotice(borderAllNotices + '\nAs a member of ' + EFCname + ', you can buy a ticket for ' + ticketShowPriceEFC + ' tokens. \n' + borderAllNotices, checkfreeuser, appNoticeColor, '', 'bold'); } } else if (checkfreeextfan2) { if (cb.settings.ticketShowFreeEFC2 == 'Yes') { addRmvTicket('add',checkfreeuser,'extfan2',0,checkfreeuser); cb.sendNotice(borderAllNotices + '\nYou\'ve automatically been added to the show because you\'re in ' + EFCname2 + '! \n' + borderAllNotices, checkfreeuser, appNoticeColor, '', 'bold'); } else if (ticketShowPriceEFC2 > 1 && checkmode == 'enter') { cb.sendNotice(borderAllNotices + '\nAs a member of ' + EFCname2 + ', you can buy a ticket for ' + ticketShowPriceEFC2 + ' tokens. \n' + borderAllNotices, checkfreeuser, appNoticeColor, '', 'bold'); } } else if (checkfreevip) { if (cb.settings.ticketShowFreeVIP == 'Yes') { addRmvTicket('add',checkfreeuser,'vip',0,checkfreeuser); cb.sendNotice(borderAllNotices + '\nYou\'ve automatically been added to the show because you\'re a ' + VIPname + ' member! \n' + borderAllNotices, checkfreeuser, appNoticeColor, '', 'bold'); } else if (ticketShowPriceVIP > 1 && checkmode == 'enter') { cb.sendNotice(borderAllNotices + '\nAs a ' + VIPname + ' member, you can buy a ticket for ' + ticketShowPriceVIP + ' tokens. \n' + borderAllNotices, checkfreeuser, appNoticeColor, '', 'bold'); } } } } function setTicketMode(settktmode,settktsendto) { var newticketmode = ''; var newticketauto = ''; if (settktmode === 'init') { if (cb.settings.ticketShowStartMode === 'Start Show Anytime') { newticketmode = 'manual'; } else if (cb.settings.ticketShowStartMode === 'Start Show after Timer') { newticketmode = 'timer'; } else if (cb.settings.ticketShowStartMode === 'Start Show after Ticket Goal') { newticketmode = 'ticketgoal'; } else if (cb.settings.ticketShowStartMode === 'Start Show after Token Goal') { newticketmode = 'tokengoal'; } if (cb.settings.ticketShowStartAuto === 'Start from Command') { newticketauto = 'bc'; } else if (cb.settings.ticketShowStartAuto === 'Automated Start') { newticketauto = 'auto'; } } else { newticketauto = ticketModeAuto; if (settktmode != '' && settktmode != null) { newticketmode = settktmode; } else { newticketmode = ticketStartMode; } } if (ticketStartMode === 'timer' && newticketmode != 'timer') { if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { stopTicketTimer(settktsendto); } } if (newticketmode == 'manual') { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; updtTicketModeMessage(); } else if (newticketmode == 'timer') { if (cb.settings.ticketShowStartTimer >= 1) { ticketStartMode = 'timer'; ticketTimeAmt = cb.settings.ticketShowStartTimer; if (newticketauto == 'auto') { ticketAutoTimer(ticketTimeAmt); ticketModeAuto = 'auto'; updtTicketModeMessage(); } else { ticketAutoTimer(ticketTimeAmt); ticketModeAuto = 'bc'; updtTicketModeMessage(); } } else { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; updtTicketModeMessage(); 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 (cb.settings.ticketShowGoal >= 1) { ticketStartMode = 'tokengoal'; ticketShowGoalTokens = cb.settings.ticketShowGoal; if (newticketauto == 'auto') { ticketModeAuto = 'auto'; updtTicketModeMessage(); } else { ticketModeAuto = 'bc'; updtTicketModeMessage(); } } else { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; updtTicketModeMessage(); 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 (cb.settings.ticketShowGoal >= 1) { ticketStartMode = 'ticketgoal'; ticketShowGoalTickets = cb.settings.ticketShowGoal; if (newticketauto == 'auto') { ticketModeAuto = 'auto'; updtTicketModeMessage(); } else { ticketModeAuto = 'bc'; updtTicketModeMessage(); } } else { ticketStartMode = 'manual'; ticketModeAuto = 'bc'; updtTicketModeMessage(); 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'; updtTicketModeMessage(); } else if (automode === 'auto') { ticketModeAuto = 'auto'; updtTicketModeMessage(); } } function updtTicketModeMessage() { if (ticketStartMode == 'manual') { ticketModeMessage = 'Ticket Show start mode is set to "Manual"\nThe show will be started by ' + bcText + ' or a moderator.'; } else if (ticketStartMode == 'timer') { if (ticketModeAuto == 'auto') { ticketModeMessage = 'Ticket Show start mode is set to "Automatic timer" with a duration of ' + ticketTimeAmt + ' minutes.\nThe Ticket Show will start automatically when the timer runs out.'; } else if (ticketModeAuto == 'bc') { ticketModeMessage = 'Ticket Show start mode is set to "Broadcaster managed timer". \n' + bcText + ' will set a timer and start the show when the timer runs out.'; } } else if (ticketStartMode == 'tokengoal') { if (ticketModeAuto == 'auto') { ticketModeMessage = 'Ticket Show start mode is set to "Automatic at token goal." \nThere 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.'; } else if (ticketModeAuto == 'bc') { ticketModeMessage = 'Ticket Show start mode is set to "Broadcaster managed token goal". \n' + bcText + ' will start the show once the goal is met for the total tips (' + ticketShowGoalTokens + ' tokens).'; } } else if (ticketStartMode == 'ticketgoal') { if (ticketModeAuto == 'auto') { ticketModeMessage = 'Ticket Show start mode is set to "Automatic at ticket goal." \nThere 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.'; } else if (ticketModeAuto == 'bc') { ticketModeMessage = 'Ticket Show start mode is set to "Broadcaster managed ticket goal". \n' + bcText + ' will start the show once the goal is met for tickets sold (' + ticketShowGoalTickets + ' tickets).'; } } } function startTicketShowTimer(startnumtimer) { ticketMinsRemain = startnumtimer; ticketStartMode = 'timer'; ticketAutoTimer(ticketMinsRemain); cb.drawPanel(); } function ticketAutoTimer(addtime) { if (ticketModeAuto == 'auto') { if (cb.settings.ticketShowFanAppreciation == 'Yes') { cb.sendNotice(borderTicketTop + '\nAn automatic timer was started for the countdown to the Fan Appreciation show.' + borderTicketBottom, '', ticketBgColor, ticketTextColor, 'bold'); } else { cb.sendNotice(borderTicketTop + '\nAn automatic timer was started, ticket show price will be ' + ticketPrice + ' tokens.' + borderTicketBottom, '', ticketBgColor, ticketTextColor, 'bold'); } } 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, ticketTextColor, 'bold'); } ticketMinsRemain = addtime; ticketSecsRemain = 0; ticketStartTime = new Date(); ticketStopTime = new Date(ticketStartTime.getTime() + ticketMinsRemain * 60000); ticketTimerStopping = false; ticketTimerMin(); } function ticketTimerMin() { if (!ticketTimerStopping && ticketStartMode == 'timer' && whichApp == 'ticket') { switch (ticketMinsRemain) { case 60: case 45: 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: if (cb.settings.ticketShowFanAppreciation == 'Yes') { cb.sendNotice('\u23f1 \u23f1 \u23f1 There are ' + ticketMinsRemain + ' minutes left until the Fan Appreciation Show! \u23f1 \u23f1 \u23f1', '', appNoticeColor, '', 'bold'); } else { cb.sendNotice('\u23f1 \u23f1 \u23f1 There are ' + ticketMinsRemain + ' minutes left to buy a ticket for ' + ticketPrice + ' tokens before the show starts! \u23f1 \u23f1 \u23f1', '', appNoticeColor, '', 'bold'); } break; case 1: if (cb.settings.ticketShowFanAppreciation == 'Yes') { cb.sendNotice('\u23f1 \u23f1 \u23f1 There is 1 minute left until the Fan Appreciation Show! \u23f1 \u23f1 \u23f1', '', appNoticeColor, '', "bold"); } else { cb.sendNotice('\u23f1 \u23f1 \u23f1 There is 1 minute left to buy a ticket for ' + ticketPrice + ' tokens before the show starts! \u23f1 \u23f1 \u23f1', '', appNoticeColor, '', 'bold'); } break; } cb.drawPanel(); ticketMinsRemain--; if (ticketMinsRemain > 0) { ticketDisplaySeconds = false; } else { ticketDisplaySeconds = true; } ticketSecsRemain = 60; ticketTimerSec(); } } function ticketTimerSec() { if (!ticketTimerStopping && ticketStartMode === 'timer' && whichApp === 'ticket') { if (ticketDisplaySeconds) { switch (ticketSecsRemain) { case 30: case 10: case 5: case 4: case 3: case 2: cb.sendNotice('\u23f1 \u23f1 \u23f1 There are ' + ticketSecsRemain + ' seconds left! \u23f1 \u23f1 \u23f1', '', appErrorColor, '', 'bold'); break; case 1: cb.sendNotice('\u23f1 \u23f1 \u23f1 There is 1 second left! \u23f1 \u23f1 \u23f1', '', appErrorColor, '', 'bold'); break; } cb.drawPanel(); } if (ticketSecsRemain < 1) { if (ticketMinsRemain >= 1) { ticketTimerMin(); } else { if (ticketStartMode = 'timer' && ticketModeAuto === 'auto') { cb.sendNotice('\u23f0 \u23f0 \u23f0 Time is up! Ticket Show is starting! \u23f0 \u23f0 \u23f0', '', ticketNoticesBgColor, ticketNoticesTextColor, 'bold'); startTicketShow(bcText); } else { cb.sendNotice('\u23f0 \u23f0 \u23f0 Time is up! ' + bcText + ' will be starting the show! \u23f0 \u23f0 \u23f0', '', ticketNoticesBgColor, ticketNoticesTextColor, 'bold'); } } } else { ticketSecsRemain--; cb.setTimeout(ticketTimerSec, 1000); } } } function ticketAddTime(tickettimetoadd, tatuser) { ticketStopTime = new Date(ticketStopTime.getTime() + tickettimetoadd * 60000); var timetoaddabs = Math.abs(tickettimetoadd); if (tickettimetoadd > 0) { cb.sendNotice(tatuser + ' has added ' + tickettimetoadd + ' minute' + (tickettimetoadd === 1 || tickettimetoadd === -1 ? '' : 's') + ' to the timer.',BC,'','', 'bold'); cb.sendNotice(tickettimetoadd + ' minute' + (tickettimetoadd === 1 || tickettimetoadd === -1 ? ' has' : 's have') + ' been added to the timer. Now ' + ticketTimeLeft(),'',appNoticeColor,'', 'bold'); } else { cb.sendNotice(tatuser + ' has subtracted ' + timetoaddabs + ' minute' + (timetoaddabs === 1 || timetoaddabs === -1 ? '' : 's') + ' from the timer.',BC,'','', 'bold'); cb.sendNotice(timetoaddabs + ' minute' + (timetoaddabs === 1 || timetoaddabs === -1 ? ' has' : 's have') + ' been subtracted from the timer. Now ' + ticketTimeLeft(),'',appNoticeColor,'', 'bold'); } ticketMinsRemain = ticketMinsRemain + tickettimetoadd; if (ticketMinsRemain > 0) { ticketDisplaySeconds = false; } else { ticketDisplaySeconds = true; } cb.drawPanel(); return; } function ticketTimeCal() { ticketStartTime = new Date(); return ticketStopTime - ticketStartTime.getTime(); } function stopTicketTimer(mod) { ticketStopTime = new Date(); ticketTimerStopping = true; ticketMinsRemain = 0; ticketSecsRemain = 0; if(mod != null && mod != '') { cb.sendNotice(mod + ' has stopped the ticket show timer.','',appNoticeColor,'', 'bold'); } cb.drawPanel(); } function ticketTimeLeft() { var ticketTimeLeft = ticketTimeCal(); var ticketMS = ticketTimeLeft % 1000; var ticketSeconds = ((ticketTimeLeft - ticketMS) % 60000); var ticketMinutes = ((ticketTimeLeft - ticketSeconds - ticketMS) % 3600000); var ticketHours = (ticketTimeLeft - ticketMinutes - ticketSeconds - ticketMS); ticketSeconds = ticketSeconds / 1000; ticketMinutes = ticketMinutes / 60000; ticketHours = ticketHours / 3600000; if (ticketHours > 0) { return ticketHours + ' hour' + (ticketHours > 1 ? 's' : '') + ' and ' + ticketMinutes + ' min' + (ticketMinutes > 1 ? 's' : '') + ' left on the show timer.'; } else if (ticketMinutes > 0 && ticketSeconds === 0) { return ticketMinutes + ' min' + (ticketMinutes > 1 ? 's' : '') + ' left on the show timer.'; } else if (ticketMinutes > 0) { return ticketMinutes + ' min' + (ticketMinutes > 1 ? 's' : '') + ' and ' + ticketSeconds + ' sec' + (ticketSeconds > 1 ? 's' : '') + ' left on the show timer.'; } else { return ticketSeconds + ' sec' + (ticketSeconds > 1 ? 's' : '') + ' left on the show timer.'; } } function ticketTimeLeftPanel() { var ticketTimeLeft = ticketTimeCal(); var ticketMS = ticketTimeLeft % 1000; var ticketSeconds = ((ticketTimeLeft - ticketMS) % 60000); var ticketMinutes = ((ticketTimeLeft - ticketSeconds - ticketMS) % 3600000); var ticketHours = (ticketTimeLeft - ticketMinutes - ticketSeconds - ticketMS); ticketSeconds = ticketSeconds / 1000; ticketMinutes = ticketMinutes / 60000; if (ticketMinutes > 0) { return 'Less than ' + (ticketMinutes+1) + ' min rem'; } else { return (ticketSeconds) + ' sec rem'; } } function addRmvTicket(addrmvtktmode,addrmvtktuser,addrmvtktusertype,addrmvtkttipamt,addrmvtktdispuser) { switch (addrmvtktmode) { case 'add': { if (cbjs.arrayContains(freePreviewUserArray,addrmvtktuser)) { removePreview(addrmvtktuser); } if (cb.limitCam_isRunning() && !fixTicketsDontAdd) { cb.limitCam_addUsers(addrmvtktuser); cb.sendNotice('You have been added to the show already in progress, you may need to refresh your browser to see the show.', addrmvtktuser, appNoticeColor, '', 'bold'); } addViewer(addrmvtktuser); addTicketHolder(addrmvtktuser); if (addrmvtktusertype == 'fan') { cb.sendNotice('CB Fan Club member ' + addrmvtktdispuser + ' has been added to the ticket show list.', '', ticketBgColorFan, ticketTextColorFan, 'bold'); } else if (addrmvtktusertype == 'extfan') { cb.sendNotice(EFCname + ' member ' + addrmvtktdispuser + ' has been added to the ticket show list.', '', ticketBgColorFan, ticketTextColorFan, 'bold'); } else if (addrmvtktusertype == 'extfan2') { cb.sendNotice(EFCname2 + ' member ' + addrmvtktdispuser + ' has been added to the ticket show list.', '', ticketBgColorFan, ticketTextColorFan, 'bold'); } else if (addrmvtktusertype == 'vip') { cb.sendNotice(VIPname + ' member ' + addrmvtktdispuser + ' has been added to the ticket show list.', '', ticketBgColorVIP, ticketTextColorVIP, 'bold'); } else if (addrmvtktusertype == 'mod') { cb.sendNotice('Moderator ' + addrmvtktdispuser + ' has been added to the ticket show list.', '', ticketBgColorMod, ticketTextColorMod, 'bold'); } else { cb.sendNotice(addrmvtktdispuser + ' has been added to the ticket show list.', '', ticketHolderBgColor, '', 'bold'); } cb.drawPanel(); break; } case 'rmv': { if (cb.limitCam_isRunning()) { cb.limitCam_removeUsers(addrmvtktuser); } removeTicketHolder(addrmvtktuser); removeViewer(addrmvtktuser); cb.sendNotice(addrmvtktdispuser + ' has been removed from the ticket show list.', '', ticketHolderBgColor, '', 'bold'); cb.drawPanel(); break; } case 'addtip': { if (cbjs.arrayContains(freePreviewUserArray,addrmvtktuser)) { removePreview(addrmvtktuser); countTicketsFromPreview++; } if (cb.limitCam_isRunning() && !fixTicketsDontAdd) { cb.limitCam_addUsers(addrmvtktuser); cb.sendNotice('You have been added to the show already in progress, you may need to refresh your browser to see the show.', addrmvtktuser, appNoticeColor, '', 'bold'); } addViewer(addrmvtktuser); addTicketHolder(addrmvtktuser); ticketShowTotalTicketsBought++; if (addrmvtktdispuser == 'Anonymous User') { cb.sendNotice(ticketEmoji + 'Welcome! You have bought a ticket to the show!', '', ticketHolderBgColor, '', 'bold'); } else { if (addrmvtktusertype == 'fan') { cb.sendNotice(ticketEmoji + ' Welcome CB Fan Club member ' + addrmvtktdispuser + ', you have bought a ticket to the show!', '', ticketBgColorFan, ticketTextColorFan, 'bold'); } else if (addrmvtktusertype == 'extfan') { cb.sendNotice(ticketEmoji + ' Welcome ' + EFCname + ' member ' + addrmvtktdispuser + ', you have bought a ticket to the show!', '', ticketBgColorFan, ticketTextColorFan, 'bold'); } else if (addrmvtktusertype == 'extfan2') { cb.sendNotice(ticketEmoji + ' Welcome ' + EFCname2 + ' member ' + addrmvtktdispuser + ', you have bought a ticket to the show!', '', ticketBgColorFan, ticketTextColorFan, 'bold'); } else if (addrmvtktusertype == 'vip') { cb.sendNotice(ticketEmoji + ' Welcome ' + VIPname + ' member ' + addrmvtktdispuser + ', you have bought a ticket to the show!', '', ticketBgColorVIP, ticketTextColorVIP, 'bold'); } else if (addrmvtktusertype == 'mod') { cb.sendNotice(ticketEmoji + ' Welcome ' + addrmvtktdispuser + ', you have bought a ticket to the show!', '', ticketHolderBgColor, '', 'bold'); } else { cb.sendNotice(ticketEmoji + ' Welcome ' + addrmvtktdispuser + ', you have bought a ticket to the show!', '', ticketHolderBgColor, '', 'bold'); } } if (ticketShowAllowGift == 'Yes' && addrmvtkttipamt >= (2*ticketPrice)) { addRmvTicket('addextra',addrmvtktuser,'common',(addrmvtkttipamt - ticketPrice),addrmvtktdispuser); } break; } case 'addextra': { var numtickets = Math.floor(parseInt(addrmvtkttipamt / ticketPrice)); if (numtickets > 0) { if (!cbjs.arrayContains(ticketShowExtraTickets.name,addrmvtktuser)) { ticketShowExtraTickets.name.push(addrmvtktuser); ticketShowExtraTickets.count.push(numtickets); } else { var addextraindex = ticketShowExtraTickets.name.indexOf(addrmvtktuser); ticketShowExtraTickets.count[addextraindex] = ticketShowExtraTickets.count[addextraindex] + numtickets; } cb.sendNotice(addrmvtktuser + ', you have purchased ' + numtickets + ' extra tickets to the show. You can gift these to other users with the command "/giftticket user". Each time you use the command uses up one of your extra tickets. Please make sure to spell the user name right, gifted tickets cannot be recovered if they are gifted incorrectly.', addrmvtktuser, ticketBgColor, ticketTextColor, "bold"); } cb.drawPanel(); break; } } } function fixTickets(fixedby) { cb.sendNotice(borderTicketTop + '\n' + fixedby + ' has initiated a reconstruction of the ticket list.\nThis utility will save the ticket list, temporarily unlock the show, clear the CB \n hidden show access list, and add all users back to the show.\nTicket holders may need to refresh AFTER the process is complete to see the \n hidden show again.\nPlease be patient while this process is completed...' + borderTicketBottom, '', ticketBgColor, ticketTextColor, 'bold'); fixTicketsDontAdd = true; if (fixAlreadyRun) { fixShowDelay = 10000; } else { fixShowDelay = 3000; } cb.setTimeout(fixTickets2, 1000); } function fixTickets2() { cb.sendNotice(borderTicketTop + '\nTicket List has been saved.\nUnlocking the hidden show...' + borderTicketBottom, '', ticketBgColor, ticketTextColor, 'bold'); cb.limitCam_stop(); cb.setTimeout(fixTickets3, fixShowDelay); } function fixTickets3() { cb.sendNotice(borderTicketTop + '\nShow has been unlocked.\nClearing the hidden show access list...' + borderTicketBottom, '', ticketBgColor, ticketTextColor, 'bold'); cb.limitCam_removeAllUsers(); cb.drawPanel(); cb.setTimeout(fixTickets4, fixShowDelay); } function fixTickets4() { cb.sendNotice(borderTicketTop + '\nList has been cleared.\nRe-locking the show (everyone will see the Hidden Show screen)...' + borderTicketBottom, '', ticketBgColor, ticketTextColor, 'bold'); if (cb.settings.ticketShowFanAppreciation == 'Yes') { cb.limitCam_start('Hidden Show\n\nFan Club Appreciation Show in progress. Join the Fanclub to unlock the screen!'); } else { cb.limitCam_start('Ticket Show\n\nHidden Cam show in progress with cumshot at the end \nTip 49 tokens to see the show'); } fixTicketsDontAdd = false; cb.setTimeout(fixTickets5, fixShowDelay); } function fixTickets5() { cb.sendNotice(borderTicketTop + '\nShow has been re-locked.\nAdding all ticket holders back into the show...' + borderTicketBottom, '', ticketBgColor, ticketTextColor, 'bold'); loadTicketHolders(); cb.drawPanel(); cb.setTimeout(fixTickets6, fixShowDelay); } function fixTickets6() { let cbfixlist = cb.limitCam_allUsersWithAccess(); let cbfixliststr = cbfixlist[0] + ''; let cbfixlistary = cbfixliststr.split(','); let cbcount = cbfixlistary.length; let appcount = ticketHolderList.length; let counttext = '\nAll Ticket Holders have been added back to the show. \nNumber of ticket holders in App: ' + appcount + '\nNumber of ticket holders in CB List: ' + cbcount; if (appcount == cbcount) { cb.sendNotice(borderTicketTop + counttext + '\nThe ticket list reconstruction has completed successfully.\nPlease refresh your browser if your screen has not unlocked (may require \n multiple refresh attempts).' + borderTicketBottom, '', ticketBgColor, ticketTextColor, 'bold'); } else { cb.sendNotice(borderTicketTop + counttext + '\nThe number of ticket holders in the App does not match the number of ticket \n holders CB has given access.\nThis maybe due to a server performance issue, or a very large ticket list.\nPlease resubmit the "/fixtickets" command and the utility will run with a longer \n delay.' + borderTicketBottom, '', ticketBgColor, ticketTextColor, 'bold'); } fixAlreadyRun = true; fixTicketsRunning = false; } function removePreview(rmvprvuser) { let rmvprvidx = freePreviewUserArray.indexOf(rmvprvuser); freePreviewUserArray.splice(rmvprvidx,1); freePreviewTimeArray.splice(rmvprvidx,1); removePreViewer(rmvprvuser); } function addViewer(addedviewer) { if (!cbjs.arrayContains(ticketShowViewerList,addedviewer)) { ticketShowViewerList.push(addedviewer); } } function removeViewer(removedviewer) { if (cbjs.arrayContains(ticketShowViewerList,removedviewer)) { var rmvvindex = ticketShowViewerList.indexOf(removedviewer); ticketShowViewerList.splice(rmvvindex,1); } } function addTicketHolder(addedtktholder) { if (!cbjs.arrayContains(ticketHolderList,addedtktholder)) { ticketHolderList.push(addedtktholder); countTickets ++; } } function removeTicketHolder(rmvtktholder) { if (cbjs.arrayContains(ticketHolderList,rmvtktholder)) { let rmvvindexh = ticketHolderList.indexOf(rmvtktholder); ticketHolderList.splice(rmvvindexh,1); if (countTickets > 0) { countTickets --; } } } function addPreViewer(addedprvwer) { if (!cbjs.arrayContains(ticketShowPreViewerList,addedprvwer)) { ticketShowPreViewerList.push(addedprvwer); } } function removePreViewer(rmvprvwr) { if (cbjs.arrayContains(ticketShowPreViewerList,rmvprvwr)) { let rmvpindex = ticketShowPreViewerList.indexOf(rmvprvwr); ticketShowPreViewerList.splice(rmvpindex,1); } } function addRmvPreview(addrmvprvmode,addrmvprvwr) { switch (addrmvprvmode) { case 'add': { cb.limitCam_addUsers(addrmvprvwr); addViewer(addrmvprvwr); addPreViewer(addrmvprvwr); let endtime = Date.now() + (freePreviewLength * 1000); freePreviewUserArray.push(addrmvprvwr); let addrmvpidx = freePreviewUserArray.indexOf(addrmvprvwr); freePreviewTimeArray[addrmvpidx] = endtime; break; } case 'rmv': { cb.limitCam_removeUsers([addrmvprvwr]); removeViewer(addrmvprvwr); removePreViewer(addrmvprvwr); break; } } } function previewMonitorTimer() { cb.setTimeout(previewMonitor, 5000); } function previewMonitor() { if (showStage == 'ticketshow' || showStage == 'showwarn' || showStage == 'showfinale') { previewCheckViewers(); previewMonitorTimer(); } cb.drawPanel(); } function previewCheckViewers() { var nowtime = Date.now(); for (var chk = 0; chk < freePreviewUserArray.length; chk++) { var prvuser = freePreviewUserArray[chk]; if (cb.limitCam_userHasAccess(prvuser)) { if (freePreviewTimeArray[chk] < nowtime) { addRmvPreview('rmv',prvuser); cb.sendNotice(borderTicketTop + '\n Your free preview period has ended. \nPlease buy a ticket for ' + ticketPrice + ' tokens to see the rest of the show.' + borderTicketBottom, prvuser, ticketBgColor, ticketTextColor, 'bold'); } } } } function giftTicket(fromuser,touser) { if (cb.limitCam_isRunning()) { cb.limitCam_addUsers(touser); } addViewer(touser); addTicketHolder(touser); cb.sendNotice('Welcome ' + touser + ', ' + fromuser + ' has gifted you a ticket to the show!', '', ticketBgColor, ticketTextColor, 'bold'); cb.drawPanel(); } function giveAwayTicket(fromuser,touser) { if (cb.limitCam_isRunning()) { cb.limitCam_addUsers(touser); } addViewer(touser); addTicketHolder(touser); if (cb.limitCam_isRunning()) { cb.limitCam_removeUsers([fromuser]); } removeViewer(fromuser); removeTicketHolder(fromuser); cb.sendNotice('Welcome ' + touser + ', ' + fromuser + ' has gifted you a ticket to the show!', '', ticketBgColor, ticketTextColor, 'bold'); cb.drawPanel(); } function addRmvOutstandingTicket(mode,user) { switch (mode) { case 'add': { if (!cbjs.arrayContains(outstandingTicketArray,user)) { outstandingTicketArray.push(user); } populateOtChangesArray(user,'add'); break; } case 'rmv': { if (cbjs.arrayContains(outstandingTicketArray,user)) { cbjs.arrayRemove(outstandingTicketArray,user); } populateOtChangesArray(user,'rmv'); break; } } } function populateOtChangesArray(user,type) { if (cbjs.arrayContains(otChangesArray.name,user)) { var otindex = otChangesArray.name.indexOf(user); if (otChangesArray.type[otindex] != type) { otChangesArray.name.push(user); otChangesArray.type.push(type); } else { return; } } else { otChangesArray.name.push(user); otChangesArray.type.push(type); } } function ticketShowGoalProgress(tippedamountprogress) { ticketShowTotalTips = ticketShowTotalTips + tippedamountprogress; if (ticketStartMode == 'tokengoal' && ticketShowTotalTips >= ticketShowGoalTokens) { cb.sendNotice(borderTicketTop + '\n :siren1 \u25C8 \u25C8 \u25C8 The ticket show Tip goal has been met!! \u25C8 \u25C8 \u25C8 :siren1 \n \u25C8 \u25C8 \u25C8 Starting a 2 minute timer for automatic start of show! \u25C8 \u25C8 \u25C8 ' + borderTicketBottom, '', ticketNoticesBgColor, ticketNoticesTextColor, 'bold'); ticketStartMode = 'timer'; ticketAutoTimer(2); } else if (ticketStartMode == 'ticketgoal' && ticketShowTotalTicketsBought >= ticketShowGoalTickets) { cb.sendNotice(borderTicketTop + '\n :siren1 \u25C8 \u25C8 The ticket show Ticket goal has been met!! \u25C8 \u25C8 :siren1 \n \u25C8 \u25C8 \u25C8 Starting a 2 minute timer for automatic start of show! \u25C8 \u25C8 \u25C8 ' + borderTicketBottom, '', ticketNoticesBgColor, ticketNoticesTextColor, 'bold'); ticketStartMode = 'timer'; ticketAutoTimer(2); } } function startTicketShow(startedby) { if (ticketShowStartPrice > 0) { ticketPrice = ticketShowStartPrice; ticketPriceChangeNotice(ticketShowStartPrice); } cb.sendNotice(borderTicketTop + '\n :siren1 :siren1 :siren1 ' + startedby + ' has started the hidden ticket show! :siren1 :siren1 :siren1' + borderTicketBottom,'',ticketBgColor, ticketNoticesTextColor, 'bold'); if (cb.settings.ticketShowFanAppreciation == 'Yes') { cb.limitCam_start('Hidden Show\n\nFan Club Appreciation Show in progress. Join the Fanclub to unlock the screen!'); } else { cb.limitCam_start('Ticket Show\n\nHidden Cam show in progress with cumshot at the end \nTip 49 tokens to see the show'); } loadTicketHolders(); showStage = 'ticketshow'; changeRoomSubject(); if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { stopTicketTimer(); } hiddenTime = Date.now(); if (freePreviewLength > 0) { previewMonitorTimer(); } cb.drawPanel(); } function loadTicketHolders() { cb.sendNotice('Adding all ticket holders to the show...', '', appNoticeColor, '', 'bold'); if (ticketHolderList.length > 0) { for (let buyeridx = 0; buyeridx < ticketHolderList.length; buyeridx++) { cb.limitCam_addUsers(ticketHolderList[buyeridx]); } cb.sendNotice('All ticket holders have been added to the show. \nYou may need to refresh your browser if you have a ticket and can\'t see the show.', '', appNoticeColor, '', 'bold'); } else { cb.sendNotice('There were no ticket holders to add to the show.', '', appNoticeColor, '', 'bold'); } } function restartTicketShow(startedby) { cb.sendNotice(borderTicketTop + '\n :siren1 \u25C8 \u25C8 \u25C8 ' + startedby + ' has restarted the ticket show! \u25C8 \u25C8 \u25C8 :siren1 \n \u25C8 \u25C8 \u25C8 All current ticket holders still have access. \u25C8 \u25C8 \u25C8 \n \u25C8 \u25C8 \u25C8 Ticket sales are open, price is ' + ticketPrice + ' tokens. \u25C8 \u25C8 \u25C8 ' + borderTicketBottom,'',ticketBgColor, ticketNoticesTextColor, 'bold'); if (cb.settings.ticketShowFanAppreciation == 'Yes') { cb.limitCam_start('Ticket Show\n\nFan Club Appreciation Show in progress. Join the Fanclub to unlock the screen!'); } else { cb.limitCam_start('Ticket Show\n\nHidden Cam show in progress with cumshot at the end \nTip 49 tokens to see the show'); } loadTicketHolders(); if (showStage == 'aftershow') { ticketSubjectText = savedTicketSubjectText; } showStage = 'ticketshow'; changeRoomSubject(); ticketShowEnded = false; ticketSalesEnded = false; if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { stopTicketTimer(); } hiddenTime = Date.now(); if (freePreviewLength > 0) { previewMonitorTimer(); } cb.drawPanel(); } function restartTicketSales(startedby) { if (showStage == 'aftershow') { cb.sendNotice(borderTicketTop + '\n :siren1 ' + startedby + ' has started selling tickets again! :siren1 \nAll current ticket holders still have access. \nTicket price is ' + ticketPrice + ' tokens. \n' + borderTicketBottom,'',ticketBgColor, ticketNoticesTextColor, 'bold'); showStage = 'ticketsales'; ticketSubjectText = savedTicketSubjectText; ticketShowEnded = false; } else if (showStage == 'showfinale') { cb.sendNotice(borderTicketTop + '\n :siren1 ' + startedby + ' has started selling tickets again! :siren1 \nTicket price is ' + ticketPrice + ' tokens. ' + borderTicketBottom,'',ticketBgColor, ticketNoticesTextColor, 'bold'); showStage = 'ticketshow'; } ticketSalesEnded = false; changeRoomSubject(); cb.drawPanel(); } function warnShowEnding(warnby) { showStage = 'showwarn'; let ticketwarnmsg = borderTicketTop; if (cb.settings.ticketShowFanAppreciation == 'Yes') { ticketwarnmsg += '\n \u26A0\uFE0F :siren1 ' + warnby + ' has indicated the Fan Appreciation Show is nearly finished :siren1 \u26A0\uFE0F '; } else { if (cb.settings.ticketShowReducePriceWarn > 0 && cb.settings.ticketShowReducePriceWarn < ticketPrice) { ticketPrice = ticketPrice - cb.settings.ticketShowReducePriceWarn; ticketwarnmsg += '\n :siren1 ' + warnby + ' has indicated the show is nearly finished. :siren1 \n \u26A0\uFE0F It is not recommended to buy a ticket, but sales are still open. \u26A0\uFE0F \n \u26A0\uFE0F The Ticket Price has been reduced to ' + ticketPrice + ' tokens! \u26A0\uFE0F '; if (ticketShowPriceFC > 1 && cb.settings.ticketShowReducePriceWarn < ticketShowPriceFC && cb.settings.ticketShowFreeFC != 'Yes') { ticketShowPriceFC = ticketShowPriceFC - cb.settings.ticketShowReducePriceWarn; if (ticketShowPriceFC <= ticketPrice) { ticketwarnmsg += '\n The CB Fanclub Ticket Price has been reduced to ' + ticketShowPriceFC + ' tokens'; } } if (ticketShowPriceEFC > 1 && cb.settings.ticketShowReducePriceWarn < ticketShowPriceEFC && cb.settings.ticketShowFreeEFC != 'Yes') { ticketShowPriceEFC = ticketShowPriceEFC - cb.settings.ticketShowReducePriceWarn; if (ticketShowPriceEFC <= ticketPrice) { ticketwarnmsg += '\n The ' + EFCname + ' Ticket Price has been reduced to ' + ticketShowPriceEFC + ' tokens'; } } if (ticketShowPriceEFC2 > 1 && cb.settings.ticketShowReducePriceWarn < ticketShowPriceEFC2 && cb.settings.ticketShowFreeEFC2 != 'Yes') { ticketShowPriceEFC2 = ticketShowPriceEFC2 - cb.settings.ticketShowReducePriceWarn; if (ticketShowPriceEFC2 <= ticketPrice) { ticketwarnmsg += '\n The ' + EFCname2 + ' Ticket Price has been reduced to ' + ticketShowPriceEFC2 + ' tokens'; } } if (ticketShowPriceVIP > 1 && cb.settings.ticketShowReducePriceWarn < ticketShowPriceVIP && cb.settings.ticketShowFreeVIP != 'Yes') { ticketShowPriceVIP = ticketShowPriceVIP - cb.settings.ticketShowReducePriceWarn; if (ticketShowPriceVIP <= ticketPrice) { ticketwarnmsg += '\n The ' + VIPname + ' Ticket Price has been reduced to ' + ticketShowPriceVIP + ' tokens'; } } } else { ticketwarnmsg += '\n :siren1 ' + warnby + ' has indicated the show is nearly finished. :siren1 \n \u26A0\uFE0F It is not recommended to buy a ticket, but sales are still open. \u26A0\uFE0F '; } } ticketwarnmsg += borderTicketBottom; cb.sendNotice(ticketwarnmsg,'',ticketBgColor,ticketNoticesTextColor,'bold'); changeRoomSubject(); cb.drawPanel(); } function stopTicketSales(salesstoppedby) { if (cb.settings.ticketShowFanAppreciation == 'Yes') { cb.sendNotice(borderTicketTop + '\n \u26A0\uFE0F :siren1 ' + salesstoppedby + ' has indicated the Fan Appreciation Show is nearly finished! :siren1 ' + borderTicketBottom,'',ticketBgColor,ticketNoticesTextColor,'bold'); } else { cb.sendNotice(borderTicketTop + '\n \u26A0\uFE0F :siren1 \u26A0\uFE0F ' + salesstoppedby + ' has ended ticket sales for the show! \u26A0\uFE0F :siren1 \u26A0\uFE0F ' + borderTicketBottom,'',ticketBgColor,ticketNoticesTextColor,'bold'); } showStage = 'showfinale'; changeRoomSubject(); ticketSalesEnded = true; cb.drawPanel(); } function stopTicketShow(stoppedby) { cb.sendNotice(borderTicketTop + '\n \u26A0\uFE0F :siren1 \u26A0\uFE0F ' + stoppedby + ' has ended the show! \u26A0\uFE0F :siren1 \u26A0\uFE0F \n Ticket Show length ' + ((Date.now() - hiddenTime)/60000).toFixed(2) + ' minutes.\nThe broadcast is returning to Public Chat.' + borderTicketBottom,'',ticketBgColor,ticketNoticesTextColor,'bold'); cb.limitCam_stop(); cb.limitCam_removeAllUsers(); hiddenTime = 0; ticketShowEnded = true; ticketSalesEnded = true; showStage = 'aftershow'; savedTicketSubjectText = ticketSubjectText; ticketSubjectText = cb.settings.ticketShowAfterNotice; changeRoomSubject(); cb.drawPanel(); if (ticketShowOtToggle) { if (otChangesArray.name.length > 0) { var outstringot = ''; for (var i = 0; i < otChangesArray.name.length; i++) { if (otChangesArray.name[i] == null) { break } else { outstringot += (i > 0 ? ',' : '') + otChangesArray.name[i] + '(' + otChangesArray.type[i] + ')'; } } cb.sendNotice('Listing of Changes to the Outstanding Ticket List from this show : \n' + outstringot + '\nEnd of List', BC, appNoticeColor); cb.sendNotice('Listing of Changes to the Outstanding Ticket List from this show : \n' + outstringot + '\nEnd of List', BC, appNoticeColor, '', '', 'red'); } else { cb.sendNotice('No entries have been added to the Outstanding Ticket Changes list from this show.', BC, appNoticeColor); cb.sendNotice('No entries have been added to the Outstanding Ticket Changes list from this show.', BC, appNoticeColor, '', '', 'red'); } } if (countTicketsFromPreview > 0) { cb.sendNotice('Good news! ' + countTicketsFromPreview + ' viewers bought tickets from watching the free preview period.', BC, appNoticeColor); cb.sendNotice('Good news! ' + countTicketsFromPreview + ' viewers bought tickets from watching the free preview period.', BC, appNoticeColor, '', '', 'red'); } } function saveTicket(savetktuser) { addRmvOutstandingTicket('add',savetktuser); cb.limitCam_removeUsers(savetktuser); removeTicketHolder(savetktuser); removeViewer(savetktuser); cb.drawPanel(); } function sendPublicNotice (pnmessage, user, type) { if (pnmessage != null) { if (pnmessage != '' || pnmessage != ' ' || pnmessage != '\u00a0') { switch (type) { case 'div': cb.sendNotice(borderAllNotices + '\n\u25ba ' + pnmessage.capitalize() + '\n' + borderAllNotices, '', '', ticketNoticesTextColor, 'bold'); break; case 'divh': cb.sendNotice(borderAllNotices + '\n\u25ba ' + pnmessage.capitalize() + '\n' + borderAllNotices, '', ticketBgColor,ticketNoticesTextColor, 'bold'); break; case 'h': cb.sendNotice("\u25ba " + pnmessage.capitalize(), '', ticketBgColor,ticketNoticesTextColor, 'bold'); break; case '': cb.sendNotice('\u25ba ' + pnmessage.capitalize(), '', '', ticketNoticesTextColor, 'bold'); break; } } else { cb.sendNotice('You cannot send a blank message. Type a message and try again.', user, appNoticeColor); } } else { cb.sendNotice('You cannot send a blank message. Type a message and try again.', user, appNoticeColor); } } // *********************************** About Function ************************************** function displayAbout(sendtoabout) { let aboutmessage = 'Dorothy\'s Ticket Show'; aboutmessage += '\n \u2705 About the App:'; aboutmessage += '\n \u2022 ' + wordWrap('Version 3.0 was released on August 21, 2021, 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 app 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 on bot help page.'); aboutmessage += '\n \u2022 ' + wordWrap('This ticket App was created as a temporoary fix for an technical issue that CB is having with ticket shows not staying private.'); aboutmessage += '\n \u2022 ' + wordWrap('You can type "/tickethelp" to display the command list summary'); // aboutmessage += '\n \u2022 ' + wordWrap('The app description page includes extensive details on App features, moderator trust levels, commands and recent release notes:'); // aboutmessage += '\n https://www.freesexcam.ca/apps/app_details/dorothys-ultraapp/ '; cb.sendNotice(aboutmessage, sendtoabout, appNoticeColor); } // *********************************** Help Function ************************************** function helpCommon(comhelpreqby) { let helptxtmsg = '\u23E9 Dorothys Ticket Show - Help Menu'; helptxtmsg += '\n \u2022 ' + wordWrap('/tickets: Display the list of users that have bought or been given 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" command and pasting the list that is shown from the "/tickets" command.'); helptxtmsg += '\n \u2022 ' + wordWrap('/previewers: Display the list of users that are currently viewing a free preview. If the parameter of "alpha" is added, the list is displayed alphabetically.'); helptxtmsg += '\n \u2022 ' + wordWrap('/otlist: Display the list of outstanding ticket holders, can be used by anyone if the Outstanding Ticket feature is enabled.'); helptxtmsg += '\n \u2022 ' + wordWrap('/saveticket: If ' + bcText + ' 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 ' + bcText + ' restarts the bot, they must add the saved tickets to the outstanding ticket list to be able to use them with /useticket.'); helptxtmsg += '\n \u2022 ' + wordWrap('/useticket: If ' + bcText + ' 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 ' + bcText + ' has enabled this feature.'); helptxtmsg += '\n \u2022 ' + wordWrap('/tickettimeleft: Display the time left on the ticket show countdown for either automatic or manual starting mode.'); helptxtmsg += '\n \u2022 ' + wordWrap('/showtime: Display a message showing how long the current show has been hidden.'); helptxtmsg += '\n \u2022 ' + wordWrap('/giftticket username: 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.'); cb.sendNotice(helptxtmsg, comhelpreqby, appNoticeColor); } function helpModBC(helpoption,helpreqby) { let validhelpcmd = false; if (helpoption == null || helpoption == '') { helpoption = 'ticket'; } switch (helpoption) { case 'about': { validhelpcmd = true; displayAbout(helpreqby); break; } case 'general': case 'gen': case 'all': { validhelpcmd = true; let helptxtmsg = '\u23E9 Dorothy\'s Ticket Show - General Commands'; helptxtmsg += '\n \u2022 ' + wordWrap('/stats : Display a listing of your time online (with the app running), total tips, and tips broken down by app.'); helptxtmsg += '\n \u2022 ' + wordWrap('/chgpanelbg [imagename]: Change the background of the drawpanel to one of the valid images. Images are updated regularly, so you can see the current list by entering this command with no parameter and the error message will show the current valid choices. Note that you can also see the images by going to the "Source Code" tab for the app and clicking the link for "App Images".'); helptxtmsg += '\n \u2022 ' + wordWrap('/paneltextcolor [newcolor]: Change the color of the text in the drawpanel to either a hex code (#0000ff) or the exact text of one of the color choices from the menu ("Dark Green", "Dark Red", etc). You can lookup hex codes for any color on a site such as Color-hexa: https://www.colorhexa.com/ '); helptxtmsg += '\n \u2022 ' + wordWrap('/paneltext1 [newtext] (also /paneltext2, /paneltext3): When there is no App running, change the text displayed in the draw panel, separate commands for lines 1-3, max of 50 characters each. If an app is running but completed, can change to no app running with "/chgapp none".'); helptxtmsg += '\n \u2022 ' + wordWrap('/seepanels: Rotate through a 10 second preview of each of the available panel backgrounds so you can find one you like. See the /stoppanel and /freezepanel commands that accompany this feature.'); helptxtmsg += '\n \u2022 ' + wordWrap('/stoppanels: Stop the panel background preview and reset the background to what it was before starting.'); helptxtmsg += '\n \u2022 ' + wordWrap('/freezepanels: Stop the panel background preview and keep it on the current preview panel being displayed.'); helptxtmsg += '\n \u2022 ' + wordWrap('/setmodlevel [1,2 or 3]: Update the mod trust level. 1=Basic, 2=Standard, 3=Advanced. See the "modlevels" help section for more detail.'); helptxtmsg += '\n \u2022 ' + wordWrap('/chgtheme [newcolortheme]: Change the color theme that is used for the background of the recurring notice. You can enter the command with no parameters to see the available choices.'); helptxtmsg += '\n \u2022 ' + wordWrap('/uachgtheme [newcolortheme]: Same command as /chgtheme above, but only updates for the UltraApp (the /chgtheme command will update the color theme across all Dorothy Apps currently running)'); helptxtmsg += '\n \u2022 ' + wordWrap('/uaseethemes: Display a sample listing of the available pre-defined color themes for the UltraApp'); helptxtmsg += '\n \u2022 ' + wordWrap('/uachgint [notice type] [new interval]: Change one of the recurring notice intervals. This command requires two parameters, to define the notice type, and to define the new interval (in minutes), in the format "/uachgint [notice type] [new interval]". You can enter the command with no parameters to see the valid notice types. The [new interval] is the new display interval in minutes. An example of a valid command would be "/uachgint goals 3.2" to update the Progressive Goals Notice interval to 3.2 minutes.'); helptxtmsg += '\n \u2022 ' + wordWrap('/emojis: Display a sample listing of emojis that can be used in the chat, in app and bot messaging, roomtitles, etc.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addfan [user]: (bc only) From within the show, adds a user to the External Fan Club list where [user] is the person you want to add. Normally these users are entered in the Fan Club List field on the launch page, but the command can be used if there is a new fan during the show.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rmvfan [user]: (bc only) Removes a user from the External Fan Club List where [user] is the person you want to remove.'); helptxtmsg += '\n \u2022 ' + wordWrap('/fanlist : (mods/bc only) Displays the list of users currently in the External Fan Club list.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addvip [user]: (bc only) From within the show, adds a user to the VIP list where [user] is the person you want to add. Normally these users are entered in the VIP List field on the launch page, but the command can be used if there is a new VIP during the show.'); helptxtmsg += '\n \u2022 ' + wordWrap('/rmvvip [user]: (bc only) Removes a user from the VIP List where [user] is the person you want to remove.'); helptxtmsg += '\n \u2022 ' + wordWrap('/viplist : (mods/bc only) Displays the list of users currently in the VIP list.'); cb.sendNotice(helptxtmsg, helpreqby, appNoticeColor); break; } case 'ticket': case 'ticketshow': { validhelpcmd = true; let helptxtmsg = '\u23E9 Dorothy\'s Ticket Show'; helptxtmsg += '\n \u2022 ' + wordWrap('This is the Ticket Show specific help menu. Type "/tickethelp general" to access the general app commands not specific to the ticket show (personalization, etc).'); helptxtmsg += '\n \u2705 KEY COMMANDS:'; helptxtmsg += '\n \u2022 ' + wordWrap('/tickets : (all users) Display the list of users that have bought or been given 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" command and pasting the list that is shown from the /tickets command.'); helptxtmsg += '\n \u2022 ' + wordWrap('/add or (/addticket) [user]: (bc only, moderator when granted privileges) Manually add a user to the ticket show list. Can be a specific user or a list of users separated by a comma.'); 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 are 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 show and return to a public broadcast.'); 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 X: (mods/bc only) Use a number in place of "X" to start a X minute timer for the ticket show when in "timer" mode with the start of the show to be triggered by the /startshow command. The timer will count down but not automatically start the show unless configured to do so.'); helptxtmsg += '\n\n \u2705 ADDITIONAL COMMANDS:'; helptxtmsg += '\n \u2022 ' + wordWrap('/rmv (or /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.'); helptxtmsg += '\n \u2022 ' + wordWrap('/previewers : (all users) Display the list of users that are currently viewing in their free preview period.'); helptxtmsg += '\n \u2022 ' + wordWrap('/addtime (or /ticketaddtime, or /addtickettime) [time]: (mods/bc only) Add [time] minutes to the timer for either automatic or manual drawing mode. The [time] value can be a negative number to subtract time, but cannot be greater than the remaining time.'); helptxtmsg += '\n \u2022 ' + wordWrap('/stoptimer (or /ticketstoptimer, or /stoptickettimer): (mods/bc only) Stop the ticket show timer for either automatic or manual drawing mode.'); helptxtmsg += '\n \u2022 ' + wordWrap('/usegift [on/off]: (mods/bc only) Toggle the setting for whether the ability to gift tickets is "on" or "off". Overrides the initial setting from the launch page, and allows you to turn the gifting of tickets on or off during the show.'); 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 (if displaying for copying to the app launch page, please use /otlistexp instead to get a better format to copy and paste). Command can be used by anyone if the Outstanding Ticket feature is enabled.'); helptxtmsg += '\n \u2022 ' + wordWrap('/otlistexp : (mods/bc only) Display the list of outstanding ticket holders in a format that can be copied and pasted into the bot lauch page for future shows.'); 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('/newticketshow: (mods/bc only) Completely refresh the ticket show to start a brand new show. This will remove all the ticket holders from the list, and re-initialize all settings using the configuration from the launch page.'); 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('/restartsales: (mods/bc only) Restart ticket sales either during the show (after /showend was used), or after you\'ve ended the show to go back to the ticket sales stage. The ticket holder list, ticket price and show description are kept intact.'); helptxtmsg += '\n \u2022 ' + wordWrap('/showstartprice [newprice]: (mods/bc only) Update the increased price that can be used at the start of the show to a new value of [newprice].'); helptxtmsg += '\n \u2022 ' + wordWrap('/tickettimeleft : (mods/bc only) Display the time left on the ticket show countdown for either automatic or manual starting mode.'); helptxtmsg += '\n \u2022 ' + wordWrap('/showtime : (all users) Display a message showing how long the current show has been hidden.'); helptxtmsg += '\n \u2022 ' + wordWrap('/chgticketmode (or /chgtktmode) [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('/chgticketauto (or /chgtktauto) [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 no used to allow saving your ticket, you can give your ticket to another user. This can only be done before the show starts, and you will be removed from the ticket show list!'); helptxtmsg += '\n \u2022 ' + wordWrap('/ticketsubject (or /ctsubject) [newsubject]: (mods/bc only) Change the room description/subject/title to a new value. This keeps the standard ticket show formatting and only changes the configurable part of the subject.'); helptxtmsg += '\n \u2022 ' + wordWrap('/previewlength [newlength]: (mods/bc only) Update the length of the free preview period. Note that setting it to zero ("0") will disable the free preview. Please make sure to use one of the following values as the parameter: "0", "10sec", "20sec", "30sec", "1min", "2min", "3min", "4min", or "5min"'); helptxtmsg += '\n \u2022 ' + wordWrap('/addlbtop [X]: (bc/mods - Fembot command) Add the top [X] number of tippers for the current session to the ticket show. Moderators may only use this if allowed per configuration. Note this command is actually being executed in the Fembot, so the Fembot must be running to make use of it. 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 - Fembot command) 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. Note this command is actually being executed in the Fembot, so the Fembot must be running to make use of it. 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('/cancelticket: (mods/bc only) Stop the automatic countdown to ticket sales that will start after the last goal if setting "1A2" is enabled.'); cb.sendNotice(helptxtmsg, helpreqby, appNoticeColor); break; } } if (!validhelpcmd) { cb.sendNotice(botName + helpoption + ' is not a valid subsection of the help menu. Valid subsections are "general", "ticket", and "about".',helpreqby,appNoticeColor); } } // ******************************* Upon user entry of a Message ************************************** cb.onMessage(function (msg) { let rawmsg = msg.m; let msgarray = rawmsg.split(' '); let msguser = msg.user; let msgismod = msg.is_mod; let msgisfan = msg.in_fanclub; let msgisextfan1 = cbjs.arrayContains(extFanListArray,msguser); let msgisextfan2 = cbjs.arrayContains(extFanList2Array,msguser); let msgisvip = cbjs.arrayContains(VIPListArray,msguser); let msgisbc = (msguser === BC); let command = msgarray[0]; let commandvar1 = parseInt(msgarray[1]); let commandvar2 = parseInt(msgarray[2]); let listregexp = /[,\s]+/; 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 (msgismod) { addRmvModsInShow(msguser,'a'); } if (msgisfan) { addRmvFanClubInShow(msguser,'a'); } if (msgisvip) { addRmvVIPInShow(msguser,'a'); } if (msgisextfan1) { addRmvExtFanInShow(msguser,'a'); } if (msgisextfan2) { addRmvExtFanInShow2(msguser,'a'); } if (msgismod || msgisfan || msgisextfan1 || msgisextfan2 || msgisvip) { checkFreeTickets(msguser,msgismod,msgisfan,msgisextfan1,msgisextfan2,msgisvip,'msg'); } if (msgarray[0].charAt(0) == '/') { var recognizedcmd = false; msg['X-Spam'] = true; var ntc = null; for (var n1 = 1; n1 < msgarray.length; n1++) { if (n1 == 1) ntc = msgarray[n1]; else ntc += ' ' + msgarray[n1]; } var ntc2 = null; for (var n2 = 2; n2 < msgarray.length; n2++) { if (n2 == 2) ntc2 = msgarray[n2]; else ntc2 += ' ' + msgarray[n2]; } var cmdval = null; for (var n3 = 1; n3 < msgarray.length; n3++) { if (n3 == 1) cmdval = msgarray[n3]; else cmdval += ' ' + msgarray[n3]; } switch (command) { //********* General App Commands case '/chgpanelbg': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (msgarray[1]) { var newbg = msgarray[1].toLowerCase(); customizePanelBackground(newbg,msguser,'cmd'); cb.drawPanel(); if (panelPreviewOn) { panelPreviewOn = false; cb.sendNotice('You have stopped the panel background preview.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'The /chgpanelbg command requires the entry of a parameter following the command, such as "/chgpanelbg lavalamp". The valid formats are: \n' + cbjs.arrayJoin(backgroundArray.command, ', '), msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/paneltextcolor': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { var pnltxtclr = rawmsg.substring(16).trim(); if (pnltxtclr) { customizePanelText(pnltxtclr,msguser); cb.drawPanel(); } else { cb.sendNotice(botName + 'The /paneltextcolor command requires the entry of a parameter following the command, which represents either the color name or the color hex code, such as "/paneltextcolor Blue" or "/paneltextcolor #0000ff".' , msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/chgtheme': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (msgarray[1]) { let newtheme = msgarray[1].toLowerCase(); if (newtheme == 'none') { colorTheme = 'None'; ticketTextColor = ''; ticketBgColor = ''; cb.sendNotice('You have updated the App to not use a color theme.', 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); 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 '/uaseetheme': case '/uaseethemes': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { // if (cb.settings.fembotRunning == 'No') { 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********************************************\n', msguser, tempseebgcolor, tempseetextcolor); } // } else { // cb.sendNotice(botName + 'Since setting "1N" indicates the Fembot is also running, the themes list is not displayed by this App, it is expected they will be shown by the Fembot using the same command.', msguser, appNoticeColor); // } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/showpanel': case '/showpanels': case '/seepanel': case '/seepanels': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (panelPreviewOn) { cb.sendNotice('A panel preview has already been started.', msguser, appNoticeColor); } else { cb.sendNotice('Beginning the Panel Background Preview\nEvery 10 seconds, the panel background will change.\nEach time it changes, you will receive a message with the name of the current panel.\nTo stop the preview, and return to your previous panel background, type: /stoppanel \nTo stop the preview, and stay on the currently previewed panel background, type: /freezepanel \nTo update the panel manually, use the /chgpanel command (a successful update will also stop the preview)', msguser, appNoticeColor); savedPanelBackground = currentPanel; savedPanelFilename = backgroundImage; savedBotPanel = botPanel; currentPanelCycleIndex = 0; panelPreviewOn = true; panelPreviewer = msguser; cyclePanels(); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/stoppanel': case '/stoppanels': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (panelPreviewOn) { currentPanel = savedPanelBackground; backgroundImage = savedPanelFilename; botPanel = savedBotPanel; cb.drawPanel(); panelPreviewOn = false; cb.sendNotice('You have stopped the panel background preview and returned to the previously used panel.\nPlease wait at least 10 seconds before using the /seepanels command again.', msguser, appNoticeColor); } else { cb.sendNotice('The panel preview is not currently active.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/freezepanel': case '/freezepanels': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (panelPreviewOn) { panelPreviewOn = false; botPanel = true; cb.sendNotice('You have stopped the panel background preview and kept the current preview panel.\nPlease wait at least 10 seconds before using the /seepanels command again.', msguser, appNoticeColor); } else { cb.sendNotice('The panel preview is not currently active.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/stats': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { cb.sendNotice('Current Session Stats:' + '\n \u21D2 Time Online................ ' + timeOnline() + '\n \u21D2 Total Tips................................. ' + currentSessionTotal + ' tokens ($' + Number(currentSessionTotal*.05).toFixed(2) + ' @ 5 cents per token)' + (currentAppTotalTicket > 0 ? '\n \u21D2 \u21D2 \u21D2 Ticket Show Total............. ' + currentAppTotalTicket + ' tokens' : '') + (countTickets > 0 ? '\n \u21D2 \u21D2 \u21D2 \u21D2 Total Tickets Sold.............. ' + countTickets + ' tickets' : '') + (countTicketsFromPreview > 0 ? '\n \u21D2 \u21D2 \u21D2 \u21D2 Tickets Sold From Preview.. ' + countTicketsFromPreview + ' tickets' : ''), msguser, appNoticeColor, '', boldTextLiteral); } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/setmodlevel': { recognizedcmd = true; if (msgisbc) { if (msgarray[1]) { if (msgarray[1] != '1' && msgarray[1] != '2' && msgarray[1] != '3') { cb.sendNotice(botName + 'Invalid parameter value, valid values are "1" for "Basic" level, "2" for "Standard" level, or "3" for "Advanced" level. See the "modlevels" help section for more detail (/uahelp modlevels)', msguser, appNoticeColor); } else { if (msgarray[1] == '1') { if (modLevel == 'Basic') { cb.sendNotice(botName + 'The Moderator Trust Level is already set to "Basic".', msguser, appNoticeColor); } else { modLevel = 'Basic'; cb.sendNotice(botName + 'The Moderator Trust Level has been updated to "Basic".', msguser, appNoticeColor); } } else if (msgarray[1] == '2') { if (modLevel == 'Standard') { cb.sendNotice(botName + 'The Moderator Trust Level is already set to "Standard".', msguser, appNoticeColor); } else { modLevel = 'Standard'; cb.sendNotice(botName + 'The Moderator Trust Level has been updated to "Standard".', msguser, appNoticeColor); } } else if (msgarray[1] == '3') { if (modLevel == 'Advanced') { cb.sendNotice(botName + 'The Moderator Trust Level is already set to "Advanced".', msguser, appNoticeColor); } else { modLevel = 'Advanced'; cb.sendNotice(botName + 'The Moderator Trust Level has been updated to "Advanced".', msguser, appNoticeColor); } } } } else { cb.sendNotice(botName + 'No parameter was specified for the new mod trust level, valid values are "1" for "Basic" level, "2" for "Standard" level, or "3" for "Advanced" level. See the "modlevels" help section for more detail (/uahelp modlevels)', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBC, msguser, appNoticeColor); } break; } case '/uachgint': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { let newtimer = 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 not a valid interval type. 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 "/uachgint [notice type] [new interval]", where [new interval] is the new display interval in minutes. An example of a valid command would be "/uachgint goals 3.2" to update the Goals Notice interval to 3.2 minutes.', msguser, appNoticeColor); } else if (isNaN(newtimer)) { cb.sendNotice(botName + 'The second parameter requires a numeric value to define the new interval (in minutes), in the format "/uachgint [notice type] [new interval]", where [new interval] is the new display interval in minutes. An example of a valid command would be "/uachgint goals 3.2" to update the Goals Notice interval to 3.2 minutes.', msguser, appNoticeColor); } else if (newtimer > 0 && newtimer < 1) { cb.sendNotice(botName + 'The new value for the timer interval must be "0" or a number greater than or equal to "1" (such as 1, 3, 4.5, etc). Setting to zero will disable the Notice.', msguser, appNoticeColor); } else { updateIntervalArray(intervaltochange,newtimer,0); cb.sendNotice(botName + 'The "' + intervaltochange + '" notice timer has been updated to a new interval of ' + newtimer + ' minutes. This will take effect after the next display of the notice.', 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 "/uachgint [notice type] [new interval]", where [notice type] is one of the values from this list: \n' + cbjs.arrayJoin(noticeIntervals.name, ', ') + '\nAn example of a valid command would be "/uachgint goals 3.2" to update the Goals Notice interval to 3.2 minutes.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/emoji': case '/emojis': { if (msgisbc || ismodlvlmsg1) { if (cb.settings.fembotRunning == 'No') { 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(botName + 'Since setting "3K" indicates the Fembot is also running, the emojis list is not displayed by this App.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/help': { recognizedcmd = true; let helpcmdtext = 'The Dorothy Apps and Bots each have their own help command, please use one of the following:'; helpcmdtext += '\n/tickethelp - Dorothy\'s Ticket show (currently running)'; cb.sendNotice(helpcmdtext, msguser, appNoticeColor); break; } //********* Ticket Show Commands case '/tickets': { recognizedcmd = true; if (ticketHolderList.length > 0) { let ticketholdercount = ticketHolderList.length; if (msgarray[1] == 'a' || msgarray[1] == 'A' || msgarray[1] == 'alpha') { let sortedticketlist = ticketHolderList.slice(); sortedticketlist.sort(); cb.sendNotice(botName + 'Alphabetic listing of users currently in the ticket holder list (' + ticketholdercount + ' ticket holders) :\n' + cbjs.arrayJoin(sortedticketlist, ', ') + '\nEnd of List', msguser, appNoticeColor); } else { cb.sendNotice(botName + 'Users currently in the ticket holder list, in order of when added (' + ticketholdercount + ' ticket holders). Use the "alpha" parameter for a sorted list : \n' + cbjs.arrayJoin(ticketHolderList, ', ') + '\nEnd of List', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'No ticket holders yet.', msguser, appNoticeColor); } break; } case '/cbtickets': case '/ticketscb': { recognizedcmd = true; if (cb.limitCam_allUsersWithAccess().length > 0) { // let cbaccesslist = []; // let cbaccessliststr = ''; let cbaccesslistary = []; cbaccesslistary = cb.limitCam_allUsersWithAccess(); // cbaccessliststr = cbaccesslist[0] + ''; // cbaccesslistary = cbaccessliststr.split(','); let numberwithaccess = cbaccesslistary.length; if (msgarray[1] == 'a' || msgarray[1] == 'A' || msgarray[1] == 'alpha') { cbaccesslistary.sort(); cb.sendNotice(botName + 'Alphabetic listing of users currently with access to the Hidden Ticket Show (' + numberwithaccess + ' users added) :\n' + cbjs.arrayJoin(cbaccesslistary, ', ') + '\nEnd of List', msguser, appNoticeColor); } else { cb.sendNotice(botName + 'Users currently with access to the Hidden Ticket Show, in order of when added (' + numberwithaccess + ' users added). Use the "alpha" parameter for a sorted list : \n' + cbjs.arrayJoin(cbaccesslistary, ', ') + '\nEnd of List', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'No users granted CB hidden show access yet.', msguser, appNoticeColor); } break; } case '/previewers': { recognizedcmd = true; if (whichApp == 'ticket') { if (freePreviewLength > 0) { if (ticketShowPreViewerList.length > 0) { if (msgarray[1] == 'a' || msgarray[1] == 'A' || msgarray[1] == 'alpha') { var sortedpvlist = ticketShowPreViewerList.slice(); sortedpvlist.sort(); cb.sendNotice(botName + 'Alphabetic listing of users currently seeing a free preview of the Ticket Show (' + sortedpvlist.length + ' previewers) : \n' + cbjs.arrayJoin(sortedpvlist, ', ') + '\nEnd of List', msguser, appNoticeColor); } else { cb.sendNotice(botName + 'Users currently seeing a free preview of the Ticket Show, in order of when added (' + ticketShowPreViewerList.length + ' previewers). Use the "alpha" parameter for a sorted list : \n' + cbjs.arrayJoin(ticketShowPreViewerList, ', ') + '\nEnd of List', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'No free preview viewers at this time.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'The Free Preview is disabled.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'The Ticket Show feature has not yet been started.', msguser, appNoticeColor); } break; } case '/backup': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (ticketHolderList.length > 0) { cb.sendNotice('Copy and paste the below command into the chat to backup the current ticket show list to the Fembot:\n/backupfb ' + cbjs.arrayJoin(ticketHolderList, ', ')); } else { cb.sendNotice('No ticket buyers yet.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/fixticket': case '/fixtickets': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { if (fixTicketsRunning) { cb.sendNotice('The "Fix Tickets" utility is already in progress. Please wait until the current run is complete.', msguser, appNoticeColor); } else { if (cb.limitCam_isRunning()) { fixTicketsRunning = true; fixTickets(msguser); } else { cb.sendNotice('This command can only be used once the ticket show is started. \nPrior to the show starting, the ticket list is only maintained in the app and can be viewed with the command /tickets', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/usegift': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (msgarray[1]) { if (msgarray[1].toLowerCase() != 'on' && msgarray[1].toLowerCase() != 'off') { cb.sendNotice('The value ' + msgarray[1] + ' is not a valid option for the "/usegift" command, please try again, valid values are "on" or "off".', msguser, appNoticeColor); } else if (cb.settings.ticketShowFanAppreciation == 'Yes' && msgarray[1].toLowerCase() == 'on') { cb.sendNotice('Gifting of Tickets is not enabled for a Fan Appreciation show.', msguser, appNoticeColor); } else { if (msgarray[1].toLowerCase() == 'on') { if (ticketShowAllowGift == 'Yes') { cb.sendNotice('The Gifting of Tickets is already enabled.', msguser, appNoticeColor); } else { ticketShowAllowGift = 'Yes'; cb.sendNotice('You have enabled the Gifting of Tickets.', msguser, appNoticeColor); if (msguser != BC) { cb.sendNotice(msguser + 'has enabled the Gifting of Tickets.', BC, appNoticeColor); } } } else if (msgarray[1].toLowerCase() == 'off') { if (ticketShowAllowGift == 'No') { cb.sendNotice('The Gifting of Tickets is already disabled.', msguser, appNoticeColor); } else { ticketShowAllowGift = 'No'; cb.sendNotice('You have disabled the Gifting of Tickets.', msguser, appNoticeColor); if (msguser != BC) { cb.sendNotice(msguser + 'has disabled the Gifting of Tickets.', BC, appNoticeColor); } } } } } else { cb.sendNotice('No parameter was specified for the "/usegift" command, valid values are "on" or "off".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/useot': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (msgarray[1]) { if (msgarray[1].toLowerCase() != 'on' && msgarray[1].toLowerCase() != 'off') { cb.sendNotice('The value ' + msgarray[1] + ' is not a valid option for the "/useot" command, please try again, valid values are "on" or "off".', msguser, appNoticeColor); } else if (cb.settings.ticketShowFanAppreciation == 'Yes' && msgarray[1].toLowerCase() == 'on') { cb.sendNotice('Outstanding Tickets are not enabled for a Fan Appreciation show.', msguser, appNoticeColor); } else { setTicketShowOtToggle(msgarray[1].toLowerCase(),msguser); } } else { cb.sendNotice('No parameter was specified for the "/usegift" command, valid values are "on" or "off".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/otlist': { recognizedcmd = true; var otlistcmdmsg = 'Outstanding Ticket List:'; var sortedotlist = outstandingTicketArray.slice(); sortedotlist.sort(); if (msgisbc || ismodlvlmsg1) { otlistcmdmsg += '\nIf displaying list to copy and paste into the app launch page, use command /otlistexp to get a better formatted list.'; } otlistcmdmsg += '\nUsers currently on the Outstanding Ticket List (sorted alphabetically): ' + sortedotlist.length; otlistcmdmsg += '\n' + (sortedotlist.length > 0 == true ? cbjs.arrayJoin(sortedotlist, ', ') : 'No outstanding ticket holders.'); otlistcmdmsg += '\nEnd of List'; cb.sendNotice(otlistcmdmsg, msguser, appNoticeColor); break; } case '/otlistexp': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { cb.sendNotice('Outstanding Ticket List (copy and paste into the app launch page, setting "6X": ' + 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(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/otchanges': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { if (otChangesArray.name.length > 0) { var outstringotc = ''; for (var oti = 0; oti < otChangesArray.name.length; oti++) { if (otChangesArray.name[oti] == null) { break } else { outstringotc += (oti > 0 ? ',' : '') + otChangesArray.name[oti] + '(' + otChangesArray.type[oti] + ')'; } } cb.sendNotice('Listing of Changes to the Outstanding Ticket List : \n' + outstringotc + '\nEnd 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); } break; } case '/ctprice': case '/chgticketprice': case '/ticketprice': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg2 && cb.settings.ticketShowModsChgPrice === 'Yes')) { if (msgarray[1]) { var numprice = parseInt(msgarray[1]) if (isNaN(numprice)) { cb.sendNotice(botName + 'The value entered for the ticket price is not numeric, please try again.', msguser, appNoticeColor); break; } else if (numprice < 1 || numprice > 99999) { cb.sendNotice(botName + 'The value entered for the ticket price is outside allowable values from 1 to 99999, please try again.', msguser, appNoticeColor); } else { var ticketannounce = 'no'; cb.sendNotice(botName + 'The Ticket Show price has been updated to ' + numprice + ' tokens. You can view the ticket list with the command "/tickets".', msguser, appNoticeColor); ticketannounce = 'yes'; setTicketPrice(numprice,ticketannounce); } } else { cb.sendNotice(botName + 'No parameter was specified for the new ticket price.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3P, msguser, appNoticeColor); } break; } case '/showstartprice': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg2 && cb.settings.ticketShowModsChgPrice === 'Yes')) { if (whichApp == 'ticket' && showStage != 'ticketsales') { cb.sendNotice(botName + 'The show start ticket price can only be updated while another app feature is running or prior to show start.', msguser, appNoticeColor); } else { if (msgarray[1]) { var numnewprice = parseInt(msgarray[1]) if (isNaN(numnewprice)) { cb.sendNotice(botName + 'The value entered for the ticket show start price is not numeric, please try again.', msguser, appNoticeColor); break; } else if (numnewprice < 1 || numnewprice > 99999) { cb.sendNotice(botName + 'The value entered for the ticket show start price is outside allowable values from 1 to 99999, please try again.', msguser, appNoticeColor); } else if (numnewprice <= ticketPrice) { cb.sendNotice(botName + 'The value entered for the ticket show start price is less than or equal to the current ticket price; it must be greater than the ticket price, please try again.', msguser, appNoticeColor); } else { ticketShowStartPrice = numnewprice; cb.sendNotice(botName + 'The Ticket Show Start price has been updated to ' + numnewprice + ' tokens. The ticket price will be updated to this amount when the show starts.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'No parameter was specified for the new ticket show start price.', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod3P, msguser, appNoticeColor); } break; } case '/previewlength': { recognizedcmd = true; if (whichApp == 'ticket' && showStage != 'ticketsales') { cb.sendNotice('The preview length can only be changed up until the show starts.', msguser, appNoticeColor); } else { if (msgisbc || ismodlvlmsg2) { if (msgarray[1]) { if (msgarray[1] != '0' && msgarray[1] != '10sec' && msgarray[1] != '20sec' && msgarray[1] != '30sec' && msgarray[1] != '1min' && msgarray[1] != '2min' && msgarray[1] != '3min' && msgarray[1] != '4min' && msgarray[1] != '5min') { cb.sendNotice(botName + 'The value entered for the new preview length is not valid, please make sure to use one of the following values: "0", "10sec", "20sec", "30sec", "1min", "2min", "3min", "4min", or "5min".', msguser, appNoticeColor); } else { switch (msgarray[1]) { case '0': { freePreviewLength = 0; freePreviewLengthText = 'No Preview'; break; } case '10sec': { freePreviewLength = 10; freePreviewLengthText = '10 seconds'; break; } case '20sec': { freePreviewLength = 20; freePreviewLengthText = '20 seconds'; break; } case '30sec': { freePreviewLength = 30; freePreviewLengthText = '30 seconds'; break; } case '1min': { freePreviewLength = 60; freePreviewLengthText = '1 minute'; break; } case '2min': { freePreviewLength = 120; freePreviewLengthText = '2 minutes'; break; } case '3min': { freePreviewLength = 180; freePreviewLengthText = '3 minutes'; break; } case '4min': { freePreviewLength = 240; freePreviewLengthText = '4 minutes'; break; } case '5min': { freePreviewLength = 300; freePreviewLengthText = '5 minutes'; break; } } cb.sendNotice(botName + 'The Ticket Show Free Preview length has been updated to "' + freePreviewLengthText + '".', msguser, appNoticeColor); if (msguser != BC) { cb.sendNotice(botName + 'The Ticket Show Free Preview length has been updated to "' + freePreviewLengthText + '".', BC, appNoticeColor); } } } else { cb.sendNotice(botName + 'No parameter was specified for the new preview length.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } } break; } case '/starttickettimer': case '/ticketstarttimer': case '/starttimer': { recognizedcmd = true; if (whichApp == 'ticket') { if (msgisbc || ismodlvlmsg1) { if (msgarray[1]) { var numtimer = parseInt(msgarray[1]) if(isNaN(numtimer)) { cb.sendNotice('The value entered for the minutes to use for the timer is not numeric, please try again.', msguser, appNoticeColor); break; } else if (numtimer < 1 || numtimer > 60) { cb.sendNotice('The value entered for the minutes to use for the ticket show timer is outside allowable values from 1 to 60 minutes, please try again.', msguser, appNoticeColor); } else { startTicketShowTimer(numtimer); } } else { cb.sendNotice('No parameter was specified for the number of minutes to use for the timer.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } else { cb.sendNotice('The Ticket Show feature is not running.', msguser, appNoticeColor); } break; } case '/addtickettime': case '/ticketaddtime': case '/addtime': { recognizedcmd = true; if (whichApp == 'ticket') { if (msgisbc || ismodlvlmsg1) { if (ticketMinsRemain > 0 || ticketSecsRemain > 0) { if (msgarray[1]) { var addnumtimer = parseInt(msgarray[1]); if (isNaN(addnumtimer)) { 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 (addnumtimer < -60 || addnumtimer > 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 (addnumtimer == 0) { cb.sendNotice('Cannot add zero time.', msguser, appNoticeColor); } else if (addnumtimer < 0 && Math.abs(addnumtimer) > 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 if (addnumtimer > 0 && (Math.abs(addnumtimer) + ticketMinsRemain) > 60) { cb.sendNotice('The value entered for the minutes to add would exceed the maximum countdown time of 60 minutes when added to the current time left.', msguser, appNoticeColor); } else { ticketAddTime(addnumtimer, msguser); } } else { cb.sendNotice('No parameter was specified for the number of minutes to add to the timer.', msguser, appNoticeColor); } } else { cb.sendNotice('A timer has not been started yet for the ticket show countdown.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } } else { cb.sendNotice('The Ticket Show feature is not running.', msguser, appNoticeColor); } break; } case '/ticketstoptime': case '/ticketstoptimer': case '/stoptimer': { recognizedcmd = true; if (whichApp == 'ticket') { if (msgisbc || ismodlvlmsg1) { 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 Ticket Show feature is not running.', msguser, appNoticeColor); } break; } case '/add': case '/addticket': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg2 && cb.settings.ticketShowModsAdd == 'Yes')) { if (cmdval) { var cmdvalsplit = cmdval.split(listregexp); if (cmdvalsplit.length > 1) { cb.sendNotice(botName + 'Adding multiple users to the ticket show list.', msguser, appNoticeColor); for (var i = 0; i < cmdvalsplit.length; i++) { if (cmdvalsplit[i]) { let nametoadd = cmdvalsplit[i].toLowerCase(); if (nametoadd.charAt(0) == '@') { nametoadd = nametoadd.substring(1); } if (!cb.limitCam_userHasAccess(nametoadd) || !cbjs.arrayContains(ticketHolderList,nametoadd)) { addRmvTicket('add',nametoadd,'',0,nametoadd); cb.sendNotice(msguser + ' has added you to the ticket show list.', nametoadd, appNoticeColor); } else { cb.sendNotice(nametoadd + ' is already on the ticket show list. Skipping.', msguser); } } else { cb.sendNotice('Skipping null entry.', 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(cmdvalsplit, ', '), '', appNoticeColor, '', 'normal', 'red'); } else { let nametoadd2 = msgarray[1].toLowerCase(); if (nametoadd2.charAt(0) == '@') { nametoadd2 = nametoadd2.substring(1); } if (cb.limitCam_userHasAccess(nametoadd2)) { if (cbjs.arrayContains(ticketHolderList,nametoadd2)) { cb.sendNotice(botName + 'Note: User ' + nametoadd2 + ' is already in the App ticket show list and also has access to the hidden show according to CB. They may need to try refreshing.', msguser, appNoticeColor); } else if (cbjs.arrayContains(freePreviewUserArray,nametoadd2)) { cb.sendNotice(botName + 'Note: Switching ' + nametoadd2 + ' from free preview to ticket show access.', msguser, appNoticeColor); addRmvTicket('add',nametoadd2,'',0,nametoadd2); } else { cb.sendNotice(botName + 'Note: User ' + nametoadd2 + ' already has access to the hidden show according to CB, but has not been added to the ticket list maintained within the Ticket Show App. \nAttempting to add them again.', msguser, appNoticeColor); addRmvTicket('add',nametoadd2,'',0,nametoadd2); } } else if (cbjs.arrayContains(ticketHolderList,nametoadd2)) { cb.sendNotice(botName + 'Note: User ' + nametoadd2 + ' is already in the Ticket Show List, but there is a problem with CB that has not given them access to the show. \nAttempting to add them again.\nIf unsuccessful, please try manually removing them with the /rmv command, and then adding back with the /add command.', msguser, appNoticeColor); addRmvTicket('add',nametoadd2,'',0,nametoadd2); } else { addRmvTicket('add',nametoadd2,'',0,nametoadd2); } } } else { if (cb.limitCam_userHasAccess(msguser)) { if (cbjs.arrayContains(ticketHolderList,msguser)) { cb.sendNotice(botName + 'Note: You are already in the ticket show list and have access to the hidden show according to CB. You may need to try refreshing.', msguser, appNoticeColor); } else if (cbjs.arrayContains(freePreviewUserArray,msguser)) { cb.sendNotice(botName + 'Note: Switching you from free preview to ticket show access.', msguser, appNoticeColor); addRmvTicket('add',msguser,'',0,msguser); } else { cb.sendNotice(botName + 'Note: You already have access to the hidden show according to CB, but have not been added to the ticket list maintained within the Ticket Show App. \nAttempting to add you again.', msguser, appNoticeColor); addRmvTicket('add',msguser,'',0,msguser); } } else if (cbjs.arrayContains(ticketHolderList,msguser)) { cb.sendNotice(botName + 'Note: You are already in the Ticket Show List, but there is a problem with CB that has not given you access to the show.\nAttempting to add you again.\nIf unsuccessful, please try manually removing yourself with the /rmv command, and then adding back with the /add command.', msguser, appNoticeColor); addRmvTicket('add',msguser,'',0,msguser); } else { addRmvTicket('add',msguser,'',0,msguser); } } } else { cb.sendNotice(noticeOnlyBCMod3A, msguser, appNoticeColor); } break; } case '/rmv': case '/del': case '/delticket': case '/rmvticket': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg2 && cb.settings.ticketShowModsAdd == 'Yes')) { if (msgarray[1]) { let nametormv = msgarray[1].toLowerCase(); if (nametormv.charAt(0) == '@') { nametormv = nametormv.substring(1); } if (cb.limitCam_userHasAccess(nametormv) || cbjs.arrayContains(ticketHolderList,nametormv)) { addRmvTicket('rmv',nametormv,'',0,nametormv); } else { cb.sendNotice(botName + 'User ' + nametormv + ' is not in the Ticket Show List and does not currently have access to the hidden show.', msguser, appNoticeColor); } } else { if (cb.limitCam_userHasAccess(msguser) || cbjs.arrayContains(ticketHolderList,msguser)) { addRmvTicket('rmv',msguser,'',0,msguser); } else { cb.sendNotice(botName + 'You are not in the Ticket Show List and do not currently have access to the hidden show.', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod3A, msguser, appNoticeColor); } break; } case '/giftticket': { recognizedcmd = true; if (cb.settings.ticketShowFanAppreciation != 'Yes') { if (ticketShowAllowGift == 'Yes') { if (cbjs.arrayContains(ticketShowExtraTickets.name,msguser)) { if (msgarray[1]) { let exttindex = ticketShowExtraTickets.name.indexOf(msguser); if (ticketShowExtraTickets.count[exttindex] > 0) { let nametogift = msgarray[1].toLowerCase(); if (nametogift.charAt(0) == '@') { nametogift = nametogift.substring(1); } giftTicket(msguser,nametogift); ticketShowExtraTickets.count[exttindex]--; cb.sendNotice('You have gifted a ticket to ' + nametogift + '. Thank you for your generosity.', msguser, appNoticeColor, '', 'bold'); cb.sendNotice('Moderators: ' + msguser + ' has gifted a ticket to ' + nametogift + '.', '', appNoticeColor, '', '', 'red'); cb.sendNotice('Broadcaster: ' + msguser + ' has gifted a ticket to ' + nametogift + '.', BC, appNoticeColor); } else { cb.sendNotice('Sorry, you do not have any extra tickets remaining.', msguser, appNoticeColor); } } else { cb.sendNotice('No parameter was specified for who to gift the ticket to, please specify the name of a user currently in the room.', msguser, appNoticeColor); } } else { cb.sendNotice('Sorry, you have not purchased any extra tickets.', msguser, appNoticeColor); } } else { cb.sendNotice('Sorry, ' + bcText + ' has not enabled the use of gifting tickets for this show.', msguser, appNoticeColor); } } else { cb.sendNotice('Tickets cannot be gifted for a Fan Appreciation show.', msguser, appNoticeColor); } break; } case '/givemyticketto': { recognizedcmd = true; if (cb.settings.ticketShowFanAppreciation != 'Yes') { if (ticketShowAllowGift == 'Yes') { if (msgarray[1]) { if (cb.limitCam_userHasAccess(msguser) && showStage == 'ticketsales' && !cbjs.arrayContains(ticketShowPreViewerList,msguser)) { let nametogive = msgarray[1].toLowerCase(); if (nametogive.charAt(0) == '@') { nametogive = nametogive.substring(1); } giveAwayTicket(msguser,nametogive); cb.sendNotice('You have gifted your ticket to ' + nametogive + '. You will now be removed from the show. Thank you for your generosity.',msguser,appNoticeColor,'','bold'); cb.sendNotice('Mods: ' + msguser + ' has gifted their own ticket to ' + nametogive + '.', '', appNoticeColor, '', '', 'red'); cb.sendNotice('Broadcaster: ' + msguser + ' has gifted their own ticket to ' + nametogive + '.', BC, appNoticeColor); } else { cb.sendNotice('Sorry, you do not have a ticket purchased or the show has already started.', msguser, appNoticeColor); } } else { cb.sendNotice('No parameter was specified for who to give the ticket to, please specify the name of a user currently in the room.', msguser, appNoticeColor); } } else { cb.sendNotice('Sorry, ' + bcText + ' has not enabled the gifting of tickets for this show.', msguser, appNoticeColor); } } else { cb.sendNotice('Tickets cannot be gifted for a Fan Appreciation show.', msguser, appNoticeColor); } break; } case '/chgtktmode': case '/chgticketmode': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (msgarray[1]) { var chgtktmode = msgarray[1].toLowerCase(); if (chgtktmode != 'manual' && chgtktmode != 'timer' && chgtktmode != 'ticketgoal' && chgtktmode != 'tokengoal') { cb.sendNotice('The value entered for the new mode is not valid, please try again using a value of "manual", "timer", "ticketgoal", or "tokengoal".', msguser, appNoticeColor); } else { if (chgtktmode == ticketStartMode) { cb.sendNotice('The value entered for the new mode is the same as the existing mode, command ignored.', msguser, appNoticeColor); } else { setTicketMode(chgtktmode,msguser); cb.sendNotice(ticketModeMessage,'', ticketBgColor,ticketTextColor,'bold'); cb.drawPanel(); } } } else { cb.sendNotice('No parameter was specified for the new ticket show start mode. Valid values are "manual", "timer", "ticketgoal", or "tokengoal".', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/chgtktauto': case '/chgticketauto': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (msgarray[1]) { var chgticketautovar = msgarray[1].toLowerCase(); if (chgticketautovar != 'bc' && chgticketautovar != 'auto') { cb.sendNotice('The value entered for the new mode is not valid, please try again using a value of "bc" or "auto".', msguser, appNoticeColor); } else if (chgticketautovar === 'auto' && ticketStartMode === 'manual') { cb.sendNotice('The mode cannot be changed to "auto" unless there is a goal or timer being used to define when the show will start. Show is currently to be started at broadcaster discretion.', msguser, appNoticeColor); } else if (chgticketautovar === ticketModeAuto) { cb.sendNotice('The value entered for the new mode is the same as the existing mode, command ignored.', msguser, appNoticeColor); } else { setTicketAuto(chgticketautovar); cb.sendNotice(ticketModeMessage, '', ticketBgColor, ticketTextColor, 'bold'); cb.drawPanel(); } } else { cb.sendNotice('No parameter was specified for the new autostart mode. Valid values are "bc" or "auto" (broadcaster command or automatic start).', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/tickettimeleft': { recognizedcmd = true; if (ticketMinsRemain >= 1 || ticketSecsRemain >= 1) { cb.sendNotice(ticketTimeLeft(), '', appNoticeColor, '', 'bold'); } else { cb.sendNotice('A Hidden Ticket Show timer is not running.', msguser, appNoticeColor); } break; } case '/showtime': { recognizedcmd = true; if (cb.limitCam_isRunning()) { cb.sendNotice(' \u25B7 \u25B7 \u25B7 Hidden Ticket Show in progress for ' + ((Date.now() - hiddenTime)/60000).toFixed(1) + ' minutes. \u25C1 \u25C1 \u25C1 ', msguser, ticketBgColor,ticketTextColor,'bold'); } else { cb.sendNotice('The ticket show is not running, it has not yet started or already finished.', msguser, appNoticeColor); } break; } case '/useticket': { recognizedcmd = true; if (cb.settings.ticketShowFanAppreciation != 'Yes') { if (ticketShowOtToggle) { if (cbjs.arrayContains(ticketHolderList,msguser)) { cb.sendNotice('You already have a ticket to the show.', msguser, appNoticeColor); } else { if (cbjs.arrayContains(outstandingTicketArray,msguser)) { addRmvOutstandingTicket('rmv',msguser); addRmvTicket('add',msguser,'',0,msguser); cb.sendNotice('Welcome ' + msguser + ', your Outstanding Ticket has been redeemed.', '', ticketHolderBgColor, '', 'bold'); cb.sendNotice('Broadcaster: ' + msguser + ' has used their Outstanding Ticket to join this show. \nThey should be removed from the permanent OT list on the bot start page.', BC, appNoticeColor); cb.sendNotice('Mods: ' + msguser + ' has used their Outstanding Ticket. \n' + bcText + ' has been notified to remove them from the permanent OT list on the bot start page.', BC, appNoticeColor, '', '', 'red'); } else { cb.sendNotice('Sorry, you do not have an outstanding ticket available.', msguser, appNoticeColor); } } } else { cb.sendNotice('Sorry, ' + bcText + ' has not enabled the use of outstanding tickets for this show.', msguser, appNoticeColor); } } else { cb.sendNotice('Outstanding Ticket features are not enabled for a Fan Appreciation Show.', msguser, appNoticeColor); } break; } case '/saveticket': { recognizedcmd = true; if (cb.settings.ticketShowFanAppreciation != 'Yes') { if (ticketShowOtToggle) { if (cbjs.arrayContains(ticketHolderList,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 to 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. ' + bcText + ' has been notified to add them to the permanent OT list on the bot start page.', '', appNoticeColor, '', '', 'red'); } else { cb.sendNotice('Sorry, you have no ticket purchase to save, or the show has already started.', msguser, appNoticeColor); } } else { cb.sendNotice('Sorry, ' + bcText + ' has not enabled the ability to save an outstanding tickets for this show.', msguser, appNoticeColor); } } else { cb.sendNotice('Outstanding Ticket features are not enabled for a Fan Appreciation Show.', msguser, appNoticeColor); } break; } case '/addot': { recognizedcmd = true; if (ticketShowOtToggle) { if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg2 && cb.settings.ticketShowModsAdd == 'Yes')) { if(msgarray[1]) { let addotname = msgarray[1].toLowerCase(); if (addotname.charAt(0) == '@') { addotname = addotname.substring(1); } if (!cbjs.arrayContains(outstandingTicketArray,addotname)) { addRmvOutstandingTicket('add',addotname); cb.sendNotice('User ' + addotname + ' has been added to the Outstanding Ticket List.', msguser, appNoticeColor); } else { cb.sendNotice('Cannot add, user is already in the Outstanding Ticket List.', msguser, appNoticeColor); } } } else { cb.sendNotice(noticeOnlyBCMod3A, msguser, appNoticeColor); } } else { cb.sendNotice('The Outstanding Ticket list feature is disabled. It can be enabled with the command "/useot on".', msguser, appNoticeColor); } break; } case '/rmvot': { recognizedcmd = true; if (ticketShowOtToggle) { if (msgisbc || ismodlvlmsg3 || (ismodlvlmsg2 && cb.settings.ticketShowModsAdd == 'Yes')) { if (msgarray[1]) { let rmvotname = msgarray[1].toLowerCase(); if (rmvotname.charAt(0) == '@') { rmvotname = rmvotname.substring(1); } if (cbjs.arrayContains(outstandingTicketArray,rmvotname)) { addRmvOutstandingTicket('rmv', msgarray[1]); cb.sendNotice('User ' + rmvotname + ' 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(noticeOnlyBCMod3A, msguser, appNoticeColor); } } else { cb.sendNotice('The Outstanding Ticket list feature is disabled. It can be enabled with the command "/useot on".', msguser, appNoticeColor); } break; } case '/startshow': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { var enteredby = msguser; if (msgisbc) { enteredby = bcText; } if (!cb.limitCam_isRunning() && ticketShowEnded == false) { startTicketShow(enteredby); } else if (!cb.limitCam_isRunning() && ticketShowEnded == true) { cb.sendNotice('The Hidden Cam show was already started and stopped, please use the command "/restartshow" to resume the hidden show.', msguser, appNoticeColor); } else { cb.sendNotice('The Hidden Cam show is already underway.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/showover': case '/showwarn': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { var soenteredby = msguser; if (msgisbc) { soenteredby = bcText; } if (cb.limitCam_isRunning()) { if (showStage == 'ticketshow') { warnShowEnding(soenteredby); } else if (showStage == 'showwarn') { cb.sendNotice('The /showwarn or /showover command has already been used. To suspend ticket sales, use the /showend command. To end the show and return to a public broadcast, use the /stopshow command.', msguser, appNoticeColor); } else if (showStage == 'showfinale') { cb.sendNotice('The show has already progressed past the point this command should be used, ticket sales have already been suspended. 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 (msgisbc || ismodlvlmsg2) { var seenteredby = msguser; if (msgisbc) { seenteredby = bcText; } if (cb.limitCam_isRunning()) { if (showStage == 'showfinale') { cb.sendNotice('Ticket Sales have already been suspended.', msguser, appNoticeColor); } else { stopTicketSales(seenteredby); } } 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 '/stopshow': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { var ssenteredby = msguser; if (msgisbc) { ssenteredby = bcText; } if (cb.limitCam_isRunning()) { stopTicketShow(ssenteredby); } 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 '/ticketsubject': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { ticketSubjectText = rawmsg.substring(15).trim(); if (ticketSubjectText != '' && ticketSubjectText != null) { changeRoomSubject(); } else { cb.sendNotice('No value was specified for the new room subject suffix.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/ctsubject': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { ticketSubjectText = rawmsg.substring(11).trim(); if (ticketSubjectText != '' && ticketSubjectText != null) { changeRoomSubject(); } else { cb.sendNotice('No value was specified for the new room subject suffix.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/newticketshow': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (!cb.limitCam_isRunning()) { if (ticketHolderList.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 "/add" command : ', BC, appNoticeColor); cb.sendNotice(cbjs.arrayJoin(ticketHolderList, ', '), 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 "/add" command : ', msguser, appNoticeColor); cb.sendNotice(cbjs.arrayJoin(ticketHolderList, ', '), 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(); ticketHolderList.length = 0; 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 (msgisbc || ismodlvlmsg2) { if (!cb.limitCam_isRunning()) { var rsstartedby = msguser; if (msgisbc) { rsstartedby = bcText; } restartTicketShow(rsstartedby); } 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; } case '/restartsales': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (ticketSalesEnded == true) { restartTicketSales(msguser); } else { cb.sendNotice('Ticket Sales are already enabled.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/chgticketshow': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (msgarray[1] == 'fembot' || msgarray[1] == 'Fembot') { cb.sendNotice('*** Warning *** You have enabled the ticket show in the Fembot while Dorothy\'s Ticket Show App is active. Only one app or bot should have the ticket show enabled. Running a ticket show in both will cause the user access to the ticket show to fail.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } case '/cancelticket': { recognizedcmd = true; if (msgisbc || ismodlvlmsg2) { if (ticketCountdownRunning) { ticketCountdownRunning = false; cb.sendNotice('The automatic start of ticket sales has been canceled.', '', appNoticeColor, '', 'bold'); } } else { cb.sendNotice(noticeOnlyBCMod2, msguser, appNoticeColor); } break; } //******** VIP Commands *********** case '/addvip': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { if (cmdval != null) { let vipcmdvalsplit = cmdval.split(listregexp); if (vipcmdvalsplit.length > 1) { let vipaddnotice = botName + 'Adding multiple users to the UltraApp ' + VIPname + '.'; vipaddnotice += '\nNote this is only applied during this session, permanent ' + VIPname + ' changes must be made to the list defined when starting the UltraApp. This list should also be saved to a separate document.'; for (let vipi = 0; vipi < vipcmdvalsplit.length; vipi++) { if (vipcmdvalsplit[vipi]) { let viptoadd = vipcmdvalsplit[vipi].toLowerCase(); if (viptoadd.charAt(0) == '@') { viptoadd = viptoadd.substring(1); } if (!cbjs.arrayContains(VIPListArray,viptoadd)) { addRmvVIP(viptoadd,'a'); vipaddnotice += '\nAdded ' + viptoadd + ' to the UltraApp ' + VIPname + '.'; cb.sendNotice(botName + msguser + ' has added you to the UltraApp ' + VIPname + '.', viptoadd, appNoticeColor); } else { vipaddnotice += '\n' + viptoadd + ' is already on the UltraApp ' + VIPname + '. Skipping.'; } } } vipaddnotice += '\nAll users were added and notified.'; cb.sendNotice(vipaddnotice, msguser, appNoticeColor); cb.sendNotice(msguser + ' has added multiple users to the UltraApp ' + VIPname + '.\n' + 'Users added: ' + cbjs.arrayJoin(vipcmdvalsplit, ', '), '', appNoticeColor, '', 'normal', 'red'); } else { let viptoadd2 = msgarray[1].toLowerCase(); if (viptoadd2.charAt(0) == '@') { viptoadd2 = viptoadd2.substring(1); } if (cbjs.arrayContains(VIPListArray,viptoadd2)) { cb.sendNotice(botName + viptoadd2 + ' is already on the ' + VIPname + '.', msguser, appNoticeColor); } else { addRmvVIP(viptoadd2,'a'); cb.sendNotice(botName + 'You have added ' + viptoadd2 + ' to the ' + VIPname + '.\nNote this is only applied during this session, permanent ' + VIPname + ' changes must be made to the list defined when starting the UltraApp. This list should also be saved to a separate document.', msguser, appNoticeColor); cb.sendNotice(botName + 'Congratulations! You have been added to the ' + VIPname + '!', viptoadd2, appNoticeColor); } } } else { cb.sendNotice(botName + 'You did not specify the username you want to add to the ' + VIPname + '.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/rmvvip': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { if (msgarray[1]) { let viptormv = msgarray[1].toLowerCase(); if (viptormv.charAt(0) == '@') { viptormv = viptormv.substring(1); } if (cbjs.arrayContains(VIPListArray,viptormv)) { addRmvVIP(viptormv,'r'); cb.sendNotice(botName + 'You have removed ' + viptormv + ' from the ' + VIPname + '.\nNote this is only applied during this session, permanent ' + VIPname + ' changes must be made to the list defined when starting the UltraApp. This list should also be saved to a separate document.', msguser, appNoticeColor); } else { cb.sendNotice(botName + viptormv + ' is not on the ' + VIPname + '.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'You did not specify the username you want to remove from the ' + VIPname + '.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/viplist': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { cb.sendNotice(botName + 'Users currently on the ' + VIPname + ': ' + VIPListArray.length + '\n' + (VIPListArray.length > 0 == true ? cbjs.arrayJoin(VIPListArray, ', ') : '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) { if (cmdval != null) { let fancmdvalsplit = cmdval.split(listregexp); if (fancmdvalsplit.length > 1) { let fanaddnotice = 'Adding multiple users to the UltraApp ' + EFCname + ' list.'; fanaddnotice += '\nNote this is only applied during this session, permanent ' + EFCname + ' list changes must be made to the list defined when starting the UltraApp. This list should also be saved to a separate document.'; for (let efci = 0; efci < fancmdvalsplit.length; efci++) { if (fancmdvalsplit[efci]) { let fantoadd = fancmdvalsplit[efci].toLowerCase(); if (fantoadd.charAt(0) == '@') { fantoadd = fantoadd.substring(1); } if (!cbjs.arrayContains(extFanListArray,fantoadd)) { addRmvExtFan(fantoadd,'a'); fanaddnotice += '\nAdded ' + fantoadd + ' to the UltraApp ' + EFCname + ' list.'; cb.sendNotice(msguser + ' has added you to the UltraApp ' + EFCname + ' list.', fantoadd, appNoticeColor); } else { fanaddnotice += '\n' + fantoadd + ' is already on the UltraApp ' + EFCname + ' list. Skipping.'; } } } fanaddnotice += '\nAll users were added and notified.'; cb.sendNotice(fanaddnotice, msguser, appNoticeColor); cb.sendNotice(msguser + ' has added multiple users to the UltraApp ' + EFCname + ' list.\n' + 'Users added: ' + cbjs.arrayJoin(fancmdvalsplit, ', '), '', appNoticeColor, '', 'normal', 'red'); } else { let fantoadd2 = msgarray[1].toLowerCase(); if (fantoadd2.charAt(0) == '@') { fantoadd2 = fantoadd2.substring(1); } if (cbjs.arrayContains(extFanListArray,fantoadd2)) { cb.sendNotice(botName + fantoadd2 + ' is already on the ' + EFCname + ' list.', msguser, appNoticeColor); } else { addRmvExtFan(fantoadd2,'a'); cb.sendNotice(botName + 'You have added ' + fantoadd2 + ' to the ' + EFCname + ' list.\nNote this is only applied during this session, permanent ' + EFCname + ' changes must be made to the list defined when starting the UltraApp. This list should also be saved to a separate document.', msguser, appNoticeColor); cb.sendNotice(botName + 'Congratulations! You have been added to the ' + EFCname + ' list!', fantoadd2, appNoticeColor); } } } else { cb.sendNotice(botName + 'You did not specify the username you want to add to the ' + EFCname + ' list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/addfan2': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { if (cmdval != null) { let fan2cmdvalsplit = cmdval.split(listregexp); if (fan2cmdvalsplit.length > 1) { let fan2addnotice = 'Adding multiple users to the UltraApp ' + EFCname2 + ' list.'; fan2addnotice += '\nNote this is only applied during this session, permanent ' + EFCname2 + ' list changes must be made to the list defined when starting the UltraApp. This list should also be saved to a separate document.'; for (let efcidx = 0; efcidx < fan2cmdvalsplit.length; efcidx++) { if (fan2cmdvalsplit[efcidx]) { let fan2toadd = fan2cmdvalsplit[efcidx].toLowerCase(); if (fan2toadd.charAt(0) == '@') { fan2toadd = fan2toadd.substring(1); } if (!cbjs.arrayContains(extFanList2Array, fan2toadd)) { addRmvExtFan2(fan2toadd,'a'); fan2addnotice += '\nAdded ' + fan2toadd + ' to the UltraApp ' + EFCname2 + ' list.'; cb.sendNotice(msguser + ' has added you to the UltraApp ' + EFCname2 + ' list.', fan2toadd, appNoticeColor); } else { fan2addnotice += '\n' + fan2toadd + ' is already on the UltraApp ' + EFCname2 + ' list. Skipping.'; } } } fan2addnotice += '\nAll users were added and notified.'; cb.sendNotice(fan2addnotice, msguser, appNoticeColor); cb.sendNotice(msguser + ' has added multiple users to the UltraApp ' + EFCname2 + ' list.\n' + 'Users added: ' + cbjs.arrayJoin(fan2cmdvalsplit, ', '), '', appNoticeColor, '', 'normal', 'red'); } else { let fan2toadd2 = msgarray[1].toLowerCase(); if (fan2toadd2.charAt(0) == '@') { fan2toadd2 = fan2toadd2.substring(1); } if (cbjs.arrayContains(extFanList2Array,fan2toadd2)) { cb.sendNotice(botName + fan2toadd2 + ' is already on the ' + EFCname2 + ' list.', msguser, appNoticeColor); } else { addRmvExtFan2(fan2toadd2,'a'); cb.sendNotice(botName + 'You have added ' + fan2toadd2 + ' to the ' + EFCname2 + ' list.\nNote this is only applied during this session, permanent ' + EFCname2 + ' changes must be made to the list defined when starting the UltraApp. This list should also be saved to a separate document.', msguser, appNoticeColor); cb.sendNotice(botName + 'Congratulations! You have been added to the ' + EFCname2 + ' list!', fan2toadd2, appNoticeColor); } } } else { cb.sendNotice(botName + 'You did not specify the username you want to add to the ' + EFCname2 + ' list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/rmvfan': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { if (msgarray[1]) { let fantormv = msgarray[1].toLowerCase(); if (fantormv.charAt(0) == '@') { fantormv = fantormv.substring(1); } if (cbjs.arrayContains(extFanListArray,fantormv)) { addRmvExtFan(fantormv,'r'); cb.sendNotice(botName + 'You have removed ' + fantormv + ' from the ' + EFCname + ' list.\nNote this is only applied during this session, permanent ' + EFCname + ' changes must be made to the list defined when starting the UltraApp. This list should also be saved to a separate document.', msguser, appNoticeColor); } else { cb.sendNotice(botName + fantormv + ' is not on the ' + EFCname + ' list.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'You did not specify the username you want to remove from the ' + EFCname + ' list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/rmvfan2': { recognizedcmd = true; if (msgisbc || ismodlvlmsg3) { if (msgarray[1]) { let fan2tormv = msgarray[1].toLowerCase(); if (fan2tormv.charAt(0) == '@') { fan2tormv = fan2tormv.substring(1); } if (cbjs.arrayContains(extFanList2Array,fan2tormv)) { addRmvExtFan2(fan2tormv,'r'); cb.sendNotice(botName + 'You have removed ' + fan2tormv + ' from the ' + EFCname2 + ' list.\nNote this is only applied during this session, permanent ' + EFCname2 + ' changes must be made to the list defined when starting the UltraApp. This list should also be saved to a separate document.', msguser, appNoticeColor); } else { cb.sendNotice(botName + fan2tormv + ' is not on the ' + EFCname2 + ' list.', msguser, appNoticeColor); } } else { cb.sendNotice(botName + 'You did not specify the username you want to remove from the ' + EFCname2 + ' list.', msguser, appNoticeColor); } } else { cb.sendNotice(noticeOnlyBCMod3, msguser, appNoticeColor); } break; } case '/fanlist': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { cb.sendNotice(botName + 'Users currently in the ' + EFCname + ' List: ' + extFanListArray.length + '\n' + (extFanListArray.length > 0 == true ? cbjs.arrayJoin(extFanListArray, ', ') : 'No users.') + '\nEnd of List', msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } case '/fanlist2': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { cb.sendNotice(botName + 'Users currently in the ' + EFCname2 + ' List: ' + extFanList2Array.length + '\n' + (extFanList2Array.length > 0 == true ? cbjs.arrayJoin(extFanList2Array, ', ') : 'No users.') + '\nEnd of List', msguser, appNoticeColor); } else { cb.sendNotice(noticeOnlyBCMod1, msguser, appNoticeColor); } break; } //********* Help Menu case '/tickethelp': { recognizedcmd = true; if (msgisbc || ismodlvlmsg1) { helpModBC(msgarray[1],msguser); } else { helpCommon(msguser); } break; } case '/about': { recognizedcmd = true; displayAbout(msguser); break; } //********* End of Expected commands } } // Highlight background for Ticket show users if (cbjs.arrayContains(ticketHolderList, msguser) && showStage != 'aftershow' && !cbjs.arrayContains(ticketShowPreViewerList, msguser)) { msg.background = ticketHolderBgColor; msg.m = ticketEmoji + ' ' + msg.m; } if (cbjs.arrayContains(ticketShowPreViewerList, msguser)) { msg.background = freePreviewerBgColor; } return msg; }); // **************************** Actions on user entering ***************************** cb.onEnter(function(user) { let enteruser = user.user; let enterismod = user.is_mod; let enterisbc = (enteruser === BC); let enterisfan = user.in_fanclub; let enterisextfan1 = cbjs.arrayContains(extFanListArray,enteruser); let enterisextfan2 = cbjs.arrayContains(extFanList2Array,enteruser); let enterisvip = cbjs.arrayContains(VIPListArray,enteruser); let enterisnotgray = user.has_tokens; if (enterismod) { addRmvModsInShow(enteruser,'a'); } if (enterisfan) { addRmvFanClubInShow(enteruser,'a'); } if (enterisvip) { addRmvVIPInShow(enteruser,'a'); } if (enterisextfan1) { addRmvExtFanInShow(enteruser,'a'); } if (enterisextfan2) { addRmvExtFanInShow2(enteruser,'a'); } if (cb.limitCam_userHasAccess(enteruser)) { addViewer(enteruser); if (cbjs.arrayContains(freePreviewUserArray,enteruser)) { addPreViewer(enteruser); } cb.drawPanel(); } // **** Ticket Show entry functions and messages if (!enterisbc) { if (enterismod || enterisfan || enterisextfan1 || enterisextfan2 || enterisvip) { checkFreeTickets(enteruser,enterismod,enterisfan,enterisextfan1,enterisextfan2,enterisvip,'enter'); } var enterticketmessage = ''; if (cb.limitCam_isRunning()) { if (!cb.limitCam_userHasAccess(enteruser)) { if (cb.settings.ticketShowFanAppreciation == 'Yes') { enterticketmessage += '\nToday\'s Ticket Show is a Fan Appreciation Show!'; enterticketmessage += '\nOnly configured Fan Club Members will be admitted to the show!'; enterticketmessage += '\nPlease consider joining the Fan Club!'; } else { if (freePreviewLength > 0 && (showStage == 'ticketshow' || showStage == 'showwarn')) { if (!cbjs.arrayContains(freePreviewUserArray,enteruser)) { if ((cb.settings.ticketShowPreviewGrays == 'No' && enterisnotgray) || cb.settings.ticketShowPreviewGrays == 'Yes') { addRmvPreview('add',enteruser); enterticketmessage += '\nThe Ticket Show has started!'; enterticketmessage += '\n' + bcText + ' has enabled a Free Preview period for users joining late.'; enterticketmessage += '\nYou will be able to see the show for ' + freePreviewLengthText + '.'; enterticketmessage += '\nAfter that you must buy a ticket to continue watching the show.'; } } } enterticketmessage += '\nHidden Ticket Show in progress for ' + ((Date.now() - hiddenTime)/60000).toFixed(1) + ' minutes.'; if (showStage == 'ticketshow') { enterticketmessage += '\nTicket sales still available, ticket price is ' + ticketPrice + ' tokens.'; } else if (showStage == 'showwarn') { enterticketmessage += '\n ' + bcText + ' has indicated the show is nearly over.'; enterticketmessage += '\nBuying a ticket is not recommended, but you may still buy one for ' + ticketPrice + ' tokens.'; } else if (showStage == 'showfinale') { enterticketmessage += '\n ' + bcText + ' has indicated the show is nearly over.'; enterticketmessage += '\nTicket Sales have been suspended, you can no longer buy a ticket.'; enterticketmessage += '\n' + bcText + ' may be returning to public chat shortly.'; } } } else { if (cbjs.arrayContains(ticketShowPreViewerList,enteruser)) { enterticketmessage += '\nYou are currently in your free preview period.'; enterticketmessage += '\nOnce it ends, you must buy a ticket to continue watching the show.'; } else { enterticketmessage += '\nWelcome, you already have a ticket, enjoy the show!'; } } cb.sendNotice(borderTicketTop + enterticketmessage + borderTicketBottom, enteruser, ticketBgColor, ticketTextColor, 'bold'); } else { if (showStage == 'ticketsales') { if (cb.settings.ticketShowFanAppreciation == 'Yes') { if (cbjs.arrayContains(ticketHolderList,enteruser)) { enterticketmessage += '\nWelcome! You have a ticket to the Fan Appreciation show and the show has not yet started.'; } else { enterticketmessage += '\nToday\'s Ticket Show is a Fan Appreciation Show!'; enterticketmessage += '\nOnly Fan Club Members will be admitted to the show!'; enterticketmessage += '\nPlease consider joining the Fan Club!'; } } else { if (cbjs.arrayContains(ticketHolderList,enteruser)) { enterticketmessage += '\nWelcome! You have a ticket, and the show has not yet started.'; } else { enterticketmessage += '\nTicket Show sales are active and the show has not yet started.'; enterticketmessage += '\nThe ticket price is ' + ticketPrice + ' tokens.'; if (ticketShowStartPrice > 0) { enterticketmessage += '\nThe ticket price will increase to ' + ticketShowStartPrice + ' tokens when the show is started.'; enterticketmessage += '\nGet your ticket before the price goes up!'; } } if (ticketShowAllowGift == 'Yes') { enterticketmessage += '\n' + bcText + ' has enabled the the gifting of tickets.'; enterticketmessage += '\nYou can buy extra tickets and gift them to others.'; enterticketmessage += '\nSee help text for info on gifting tickets using the "/uahelp" command.'; } } cb.sendNotice(borderTicketTop + enterticketmessage + borderTicketBottom, enteruser, ticketBgColor, ticketTextColor, 'bold'); } else if (showStage == 'aftershow' || ticketShowEnded == true) { enterticketmessage += '\nSorry, the Ticket Show is over.'; cb.sendNotice(borderTicketTop + enterticketmessage + borderTicketBottom, enteruser, ticketBgColor, ticketTextColor, 'bold'); } } if (ticketShowOtToggle && cbjs.arrayContains(outstandingTicketArray,enteruser)) { let otnotice = '\n' + bcText + ' has enabled the Outstanding Ticket feature'; otnotice += '\nYou have an outstanding ticket you can use to watch the show!'; otnotice += '\nTo use your outstanding ticket, type: /useticket'; cb.sendNotice(borderTicketTop + otnotice + borderTicketBottom, enteruser, ticketBgColor, ticketTextColor, 'bold'); } } }); // *********************************** Actions upon leaving ************************************** cb.onLeave(function(user) { let leaveuser = user.user; if (leaveuser != BC) { removeViewer(leaveuser); } }); // *********************************** Actions upon Draw Panel ************************************** cb.onDrawPanel(function (user) { var panel = {}; if (botPanel) { panel.template = 'image_template'; panel.row1_label = "row1_label"; panel.row1_value = "row1_value"; panel.row2_label = "row2_label"; panel.row2_value = "row2_value"; panel.row3_label = "row3_label"; panel.row3_value = "row3_value"; } else { panel.template = '3_rows_11_21_31'; } if (cb.settings.ticketShowFanAppreciation == 'Yes') { panel.row1_value = 'Fan Appreciation Ticket Show'; leftjust1 = leftJustify(panel.row1_value,1); panel.row2_value = 'Only Fan Club and ' + VIPname + ' Admitted'; leftjust2 = leftJustify(panel.row2_value,2); panel.row3_value = 'Join the Fanclub Today to See the Show!'; leftjust3 = leftJustify(panel.row3_value,3); } else if (showStage == 'ticketsales') { if (ticketStartMode == 'ticketgoal') { panel.row1_value = ticketEmoji + ' Ticket Price: ' + ticketPrice + ' tokens ' + ticketEmoji; leftjust1 = leftJustify(panel.row1_value+'..',1); panel.row2_value = 'Ticket Holders: ' + countTickets + ' \u25FE Viewers: ' + ticketShowViewerList.length; leftjust2 = leftJustify(panel.row2_value,2); panel.row3_value = 'Start Mode: Ticket Goal \u25FE ' + ticketShowTotalTicketsBought + ' / ' + ticketShowGoalTickets + ' tickets'; leftjust3 = leftJustify(panel.row3_value,3); } else if (ticketStartMode == 'tokengoal') { panel.row1_value = ticketEmoji + ' Ticket Price: ' + ticketPrice + ' tokens ' + ticketEmoji; leftjust1 = leftJustify(panel.row1_value+'...',1); panel.row2_value = 'Ticket Holders: ' + countTickets + ' \u25FE Viewers: ' + ticketShowViewerList.length; leftjust2 = leftJustify(panel.row2_value,2); panel.row3_value = 'Start Mode: Token Goal \u25FE ' + ticketShowTotalTips + ' / ' + ticketShowGoalTokens + ' tokens'; leftjust3 = leftJustify(panel.row3_value,3); } else if (ticketStartMode == 'timer') { panel.row1_value = ticketEmoji + ' Ticket Price: ' + ticketPrice + ' tokens ' + ticketEmoji; leftjust1 = leftJustify(panel.row1_value,1); panel.row2_value = 'Ticket Holders: ' + countTickets + ' \u25FE Viewers: ' + ticketShowViewerList.length; leftjust2 = leftJustify(panel.row2_value,2); panel.row3_value = 'Start Mode: Timer (' + ((ticketSecsRemain > 0 || ticketMinsRemain > 0) ? ticketTimeLeftPanel() : 'Timer not yet started') + ')'; leftjust3 = leftJustify(panel.row3_value,3); } else { panel.row1_value = ticketEmoji + ' Ticket Price: ' + ticketPrice + ' tokens ' + ticketEmoji; leftjust1 = leftJustify(panel.row1_value,1); panel.row2_value = 'Ticket Holders: ' + countTickets; leftjust2 = leftJustify(panel.row2_value,2); panel.row3_value = 'Start Mode: Manual ' + (cb.settings.showTotals == 'Yes' ? (' \u25FE Total Tips: ' + currentAppTotalTicket) : ''); leftjust3 = leftJustify(panel.row3_value,3); } } else if (showStage == 'showfinale') { panel.row1_value = 'Ticket Holders: ' + countTickets; leftjust1 = leftJustify(panel.row1_value,1); if (freePreviewLength > 0 && ticketShowPreViewerList.length > 0) { panel.row2_value = 'Viewers: ' + ticketShowViewerList.length + ' (' + ticketShowPreViewerList.length + ' previewer' + (ticketShowPreViewerList.length == 1 ? '' : 's') + ' included)'; } else { panel.row2_value = 'Viewers: ' + ticketShowViewerList.length; } leftjust2 = leftJustify(panel.row2_value,2); panel.row3_value = 'Show ending soon, no more ticket sales!'; leftjust3 = leftJustify(panel.row3_value,3); } else if (showStage == 'aftershow') { panel.row1_value = 'Ticket Show is Over!'; leftjust1 = leftJustify(panel.row1_value,1); panel.row2_value = 'Thank you so much everyone for joining!'; leftjust2 = leftJustify(panel.row2_value,2); panel.row3_value = ticketAppPanelText3; leftjust3 = leftJustify(panel.row3_value,3); } else { panel.row1_value = ticketEmoji + ' Ticket Price: ' + ticketPrice + ' tokens ' + ticketEmoji; leftjust1 = leftJustify(panel.row1_value,1); if (freePreviewLength > 0 && ticketShowPreViewerList.length > 0) { panel.row2_value = 'Viewers: ' + ticketShowViewerList.length + ' (' + ticketShowPreViewerList.length + ' previewer' + (ticketShowPreViewerList.length == 1 ? '' : 's') + ' included)'; } else { panel.row2_value = 'Viewers: ' + ticketShowViewerList.length; } leftjust2 = leftJustify(panel.row2_value,2); panel.row3_value = 'Ticket Holders: ' + countTickets; leftjust3 = leftJustify(panel.row3_value,3); } panel.layers = [ {'type': 'image', 'fileID': backgroundImage}, { 'type': 'text', 'text': panel.row1_value, 'top': topjust1, 'left': leftjust1, 'font-size': fontSize, 'font-weight': 'bold', 'color': textColor, }, { 'type': 'text', 'text': panel.row2_value, 'top': topjust2, 'left': leftjust2, 'font-size': fontSize, 'color': textColor, }, { 'type': 'text', 'text': panel.row3_value, 'top': topjust3, 'left': leftjust3, 'font-size': fontSize, 'color': textColor, }, ] return panel; }); // *********************************** Actions upon tipping ************************************** cb.onTip (function (tip) { let tipamount = Number.parseInt(tip.amount, 10); let tipfromuser = tip.from_user let tipisfan = tip.from_user_in_fanclub; let tipisextfan1 = cbjs.arrayContains(extFanListArray,tipfromuser); let tipisextfan2 = cbjs.arrayContains(extFanList2Array,tipfromuser); let tipisvip = cbjs.arrayContains(VIPListArray,tipfromuser); let tipisanon = tip.is_anon_tip; let tipfromdisplayuser = tipfromuser; if (tipisanon) { tipfromdisplayuser = 'Anonymous User'; } recordTip(tipamount,tipfromuser,tipisfan,tipisextfan1,tipisextfan2,tipisvip,tipfromdisplayuser); });
© Copyright Freesexcam 2011- 2024. All Rights Reserved.