Bots Home
|
Create an App
jfb03
Author:
cbrocks101
Description
Source Code
Launch Bot
Current Users
Created by:
Cbrocks101
/* ################################################################################################################# # Custom bot for jfowler275 # # Modules included are: Help,Notices,spamKill,tipGoal,mobilePM,thankYou,tipMenu,sB # # Author: alanstuart_ # Version: 20210719.1821 ################################################################################################################# */ /* ############################## # Main (version 20210514.1445) ############################## */ var botname='jfowbot',roomname='jfowler275'; /* ##################################################### # Declare Global variables and initalization function ##################################################### */ var modules={},thismod={},botmods={}; modules.names=[]; var model=cb.room_slug var debug=0; cb.settings_choices=[]; function init() { modnames=modules.names.join(); sendNotice(`:blankx Running ${botname} with the following functions enabled:\n:blankx :blankx ${modnames}\n:blankx Type /help for more info\n:blankx ${botname} was created by alanstuart_`,"","#900000"); for (const m of modsHandling("onInit")) {modules[m].funct("onInit","",m);} botInit(); } /* ############################# # Process Messages ############################# */ cb.onMessage(function (msg) { let c=parseMsg(msg); if (debug) {sendNotice("Debug: user="+c.user+",iscmd="+c.iscmd+",ismod="+c.ismod+",ismodel="+c.ismodel+",isgrey="+c.isgrey+",isfan="+c.isfan+",model="+model+",msg="+c.msg.m,c.user,"#ffffff","#000090","bold");} /* ####################################### # Process chat messages (non-commands) ####################################### */ if (!c.iscmd) { for (const m of modsHandling("onMessage")) { if (modules[m].funct("onMessage",c,m)) {return msg;} } return msg; } /* ####################################### # Process command messages ####################################### */ if (c.iscmd) { if (debug) {sendNotice("Debug: cmd="+c.cmd+",cpct="+c.cmdparmct+",c0="+c.cmd0+",c1="+c.cmd1+",c2="+c.cmd2+",cp1="+c.cmdparms[1],c.user,"#ffffff","#000090","bold");} for (const m of modsHandling("onCommand")) { if (modules[m].funct("onCommand",c,m)) {msg['X-Spam']=true;return msg;} } } // If it was a recognized command but not processed above, it must be syntax or permission error, // Otherwise pass through the command message unaltered (it may be used by another bot) if (c.cmd in c.cmds) {return badCommand('Syntax or Authorization error in command, type "/help" for more info',c);} else {return msg;} }); /* ############################# # Process User Entering Room ############################# */ cb.onEnter(function(user) { if (debug) {sendNotice("Debug: user "+user.user+" entered room","","#ffffff","#000090","bold");} for (const m of modsHandling("onEnter")) {modules[m].funct("onEnter",user,m);} }); /* ############################# # Process User Leaving Room ############################# */ cb.onLeave(function(user) { if (debug) {sendNotice("Debug: user "+user.user+" left room","","#ffffff","#000090","bold");} for (const m of modsHandling("onLeave")) {modules[m].funct("onLeave",user,m);} }); /* ############################# # Process User Following ############################# */ cb.onFollow(function(user) { if (debug) {sendNotice("Debug: user "+user.user+" followed","","#ffffff","#000090","bold");} for (const m of modsHandling("onFollow")) {modules[m].funct("onFollow",user,m);} }); /* ############################# # Process User unFollowing ############################# */ cb.onUnFollow(function(user) { if (debug) {sendNotice("Debug: user "+user.user+" unfollowed","","#ffffff","#000090","bold");} for (const m of modsHandling("onUnFollow")) {modules[m].funct("onUnFollow",user,m);} }); /* ############## # Process Tip ############## */ cb.onTip(function(tip) { if (debug) {sendNotice(`Debug: amt=${tip.smount},msg=${tip.message},from=${tip.from_user}`,"","#ffffff","#000090","bold");} for (const m of modsHandling("onTip")) {modules[m].funct("onTip",tip,m);} }); /* ################## # CORE FUNCTIONS # ################## /* ####################################################################### # Get the list of mods that have a handler for the event ####################################################################### */ function modsHandling(event) { let modlist=[]; modules.names.forEach(m=>{if (modules[m].events.includes(event)) {modlist.push(m)}}) return modlist; } /* ####################################################################### # Parse command parameters and user info into variables ####################################################################### */ function parseMsg(msg) { let c={}; c.msg=msg; c.origmsg=msg.m; c.user=msg.user; if (msg.is_mod||botmods[c.user]) {c.ismod=1;} else {c.ismod=0;} if (msg.has_tokens) {c.isgrey=0;} else {c.isgrey=1;} if (msg.in_fanclub) {c.isfan=1;} else {c.isfan=0;} if (c.user==model) {c.ismodel=1; c.ismod=1;} else {c.ismodel=0;} if (msg.m.substr(0,1)!=='/') {c.iscmd=0; return c;} else {c.iscmd=1} c.cmdparms=[]; c.cmdparms = notBlank(msg.m.substr(1).split(" ")); c.cmd = c.cmdparms[0]; c.cmdparmct = c.cmdparms.length-1; c.cmd0=c.cmd1=c.cmd2=c.cmd1p=c.cms2p=""; if (c.cmdparmct==0) {c.cmd0=c.cmd;} if (c.cmdparmct==1) {c.cmd1=c.cmd; c.cmd1p=c.cmd+" "+c.cmdparms[1];} if (c.cmdparmct==2) {c.cmd2=c.cmd; c.cmd2p=c.cmd+" "+c.cmdparms[1]+" "+c.cmdparms[2];} c.cmds=[]; return c; } /* ########################################################################### # Sends an error message notice in response to an invalid command message ########################################################################### */ function badCommand(badmsg,c) { cb.sendNotice('Error in command "'+c.msg.m+'"'+"\n"+badmsg,c.user,"#900000","#ffffff"); c.msg['X-Spam'] = true; return c.msg; } /* ########################################################################### # Function to facilitate splitting command message parms ########################################################################### */ function notBlank(array) { return array.filter(function(item){ return item != ""; }); } /* ##################################################################################### # Notice management # (if your bot uses this function, add "checkNotices()" into the init section) ##################################################################################### */ var notices={},notice={},lastsend=0;notice.timer=0; // function checkNotices() { const now=new Date().getTime(); if (notice.timer==0) {notice.last=now;} Object.keys(notices).forEach(n=>{ if (notices[n].interval>0) { notices[n].timeleft-=now-notice.last; if (notices[n].timeleft<=0) { showNotice(n); notices[n].timeleft+=notices[n].interval; } } }); notice.last=now; notice.timer=cb.setTimeout(checkNotices,1000); } // function addNotice(n,msg,user,interval,delay=0,fgcolor="#000090",bgcolor="#ffffff",weight="bold") { if (n in notices) {delete notices[n];} if (delay==-1) {delay=Math.floor(Math.random()*interval);} notices[n]={"message":msg,"user":user,"interval":interval*1000,"fgcolor":fgcolor,"bgcolor":bgcolor,"weight":weight,"timeleft":delay*1000}; if ((interval!==0)&&(delay!==0)) showNotice(n); } // function delNotice(n) {if (n in notices) {notices[n].interval=0;}} // function listNotices(user) { if (Object.keys(notices).length==0) {sendNotice("There are currently no Notices",user); return;} sendNotice("# List of notices",user); Object.keys(notices).forEach(n=>{ let u=notices[n].user; if (Array.isArray(u)) {u=u.join();} let m=notices[n].message; if (typeof(m)=='function') {m=m.name+"()";} sendNotice("# name="+n+", user="+u+", interval="+notices[n].interval/1000+" sec, nextnotice="+notices[n].timeleft/1000+"sec, message= "+m,user); }); } // function processUserList(ul) { let ul1=((ul.split(" ")).join("")).split(","); if (ul1.length==0) {return [`#Invalid user list: "${ul}"`]} let ul2=[]; for (u of ul1) { if (validateUserName(u)) {ul2.push(u)} else {return [`#Invalid user name: "${u}"`]} } if (ul2.includes("*")) {return ["*"];} return ul2; } // function validateUserName(n) { if (n.length>32) {return 0;} if ((n=="*")||(n=="*m")||(n=="*b")) {return 1;} if (!/^[a-zA-X0-9_]+$/.test(n)) {return 0;} return 1; } // function showNotice(n) { let m=""; if (typeof(notices[n].message)=='function') {m=notices[n].message();} else {m=notices[n].message;} let users=notices[n].user; if (!Array.isArray(users)) {users=[users];} for (u of users) { if (u=="*m") {sendNotice(m,"",notices[n].fgcolor,notices[n].bgcolor,notices[n].weight,"red");} else { if (u=="*b") {u=model;} else if (u=="*") {u="";} sendNotice(m,u,notices[n].fgcolor,notices[n].bgcolor,notices[n].weight); } } } // function sendNotice(notice,touser="",fgcolor="#000090",bgcolor="#ffffff",weight="bold",togroup="") { var now = new Date().getTime(); var wait = Math.max(lastsend+200-now,0); setTimeout(function(){cb.sendNotice(notice,touser,bgcolor,fgcolor,weight,togroup);},wait); lastsend=now+wait; } /* ##################################################################################### # Read settings for a module into modules[mod].data ##################################################################################### */ function readCBSettings(mod) { const m = modules[mod]; Object.keys(cb.settings).forEach(s=>{ let val = cb.settings[s]; let sp = s.split('_'); if (sp[0].toLowerCase()==mod.toLowerCase()) { if (typeof(val)=="string") { if ((val.toLowerCase()=="-yes-")||(val.toLowerCase()=="-true-")) {val=1;} else if ((val.toLowerCase()=="-no-")||(val.toLowerCase()=="-false-")) {val=0;} } sp.splice(0,1); if (sp[0]) { const ind=Number(sp[0]); if (Number.isInteger(ind)) { sp.splice(0,1); const vn=sp.join('_'); if (!m.data[vn]) {m.data[vn]=[];} m.data[vn][ind]=val; } else { const vn=sp.join('_'); m.data[vn]=val; } } else {m.data[s]=val;} } }) } /* ##################################################################################### # Override cb.setting_choices parameters setup in modules ##################################################################################### */ function deleteSC(scn) { cb.settings_choices.forEach((sc,i)=>{ if (sc.name.toLowerCase()==scn.toLowerCase()) {cb.settings_choices.splice(i,1); return;} }); } /* ######################################################################################### # Stub function to be run on bot initialization -- to be overridden with custom bot code ######################################################################################### */ function botInit() {} /* #################### # MODULES #################### */ /* ##################################################################################### # Module: Help (version 20210719.1821) ##################################################################################### */ modules['Help']={};thismod=modules['Help'];thismod.data={};modules.names.push('Help');thismod.name='Help'; thismod.data.fgcol="#000000";thismod.data.bgcol="#00ee00"; thismod.cmd="help"; thismod.events=["onCommand"]; thismod.funct = function(mode,c,m) { mod=modules[m]; if (mode=="onCommand") { if ((c.cmd==mod.cmd)||(c.cmd=="h")||(c.cmd=="?")) { c.cmds[c.cmd]=1; if (c.cmdparmct==0) { let h=`:blankx Help for Bot ${botname}`; if (bothelp&&(typeof(bothelp)=="string")) {bothelp.split("\n").forEach(l=>{h+=`\n :blankx ${l}`})}; if (modules.names.length>0) { h+="\n :blankx This Bot includes the following functions: \n"; for (const m of modules.names) { h+=` :blankx > "${m}"`; if (m.summary) {h+=` - ${m.summary}`;} h+=` \n`; } h+=" :blankx For help on one of these functions, type \"/help [function]\""; } sendNotice(h,c.user,mod.data.fgcol,mod.data.bgcol,"normal"); return 1; } else if (c.cmdparmct==1) { let cm = c.cmdparms[1]; if (cm!=='*') { let mfound=0; for (const m of modules.names) { if ((m==cm)||(m.toLowerCase()==cm)) {mfound=1;cm=m;} else if (modules[m].cmd) {if (modules[m].cmd.toLowerCase()==cm) {mfound=1;cm=m;}} } if (!mfound) {badCommand(`Function "${cm}" not found. Type "/help" for the list of functions in this Bot`,c); return 1;} let h1=` :blankx Help for function "${cm}"`; let cmod=modules[cm]; if (cmod.summary) {h1+=` (${cmod.summary})`;} let h2=""; if (cmod.desc) {cmod.desc.split("\n").forEach(l=>{h2+=` :blankx ${l}\n`});} if (cmod.commands && Object.keys(cmod.commands).length) { h2+=" :blankx Commands: \n"; Object.keys(cmod.commands).forEach(c=>{h2+=` :blankx > "${c}" - ${cmod.commands[c]}\n`}); } if (h2=="") {sendNotice("No help found for function "+m,c.user,mod.data.fgcol,mod.data.bgcol,"normal");} else {sendNotice(`${h1}\n${h2}`,c.user,mod.data.fgcol,mod.data.bgcol,"normal");} return 1; } else { let h=`Custom bot for <a href="https://chaturbate.com/${roomname}" style="color:#8888ff;text-decoration:underline;">`+ `${roomname}</a>'s room. Current modules included are: ${modnames}<br>`; for (const m of modules.names) { let mod=modules[m]; let mdesc=""; if (mod.summary) {mdesc=" - "+mod.summary;} h+=`<br><span style="font-style:italic;font-weight:bold;text-decoration:underline;color:#0000ff;">${m}</span><b>${mdesc}</b><br>`; if (mod.desc) {mod.desc.split("\n").forEach(l=>{h+=`${l}<br>`});} if (mod.commands && Object.keys(mod.commands).length) { h+=`<span style="text-decoration:underline;font-style:italic;font-weight:bold;color:#000000;">Commands</span><br>`; Object.keys(mod.commands).forEach(c=>{ h+=` > <span style="font-style:italic;color:#000000;font-weight:bold;">${c}</span>`+ ` ${modules[m].commands[c]}<br>`; }); } } sendNotice(`Copy this code to the bot description: ${h}`,c.user,"","","normal"); } } } } return 0; } thismod.summary = "get help on Bot functions and commands", thismod.desc = "Get help by typing /help, /h, or /?", thismod.commands = {'/h': "Get help on the Bot, and a list of all functions in the bot", '/h [function]': 'Get help on one of the functions in the bot, including it\'s commands', '/h *': "Display an auto-genertaed html description of the bot, that can be cut and paste into the Bot's description screen" }; /* ##################################################################################### # Module: Notices (version 20210719.1821) ##################################################################################### */ modules['Notices']={};thismod=modules['Notices'];thismod.data={};modules.names.push('Notices');thismod.name='Notices'; thismod.cmd='n'; for (i=1;i<=5;i++) { cb.settings_choices.push( // {name:`notices_${i}_name`,type:'str',defaultValue:'',label:`Notice #${i} name`,required:false,maxLength:16}, {name:`notices_${i}_msg`,type:'str',defaultValue:``,label:`Notice #${i} message (blank to disable)`,required:false,maxLength:255}, // {name:`notices_${i}_ul`,type:'str',defaultValue:'*',label:`Comma separated list of Users to display Notice #${i} to\n(*=all,*m=mods,*b=broadcaster)`,required:true,maxLength:255}, {name:`notices_${i}_colors`,type:'str',defaultValue:'#0000ff,#ffffff',label:`Notice #${i} Colors (foreground,background)`,required:true,maxLength:15}, {name:`notices_${i}_timer`,type:'int',defaultValue:0,minValue:0,label:`Notice #${i} repeat timer (in seconds).\nEnter 0 to only show Notice #${i} when /n command is used`,required:false} ); } cb.settings_choices.push({name:'notices_modcmd',type:'choice',choice1:"-No-",choice2:"-Yes-",defaultValue:'-Yes-',label:'Allow Mods to run Notice commands?',required:true}); thismod.events=["onInit","onCommand"]; thismod.funct = function(mode,c,m) { mod=modules[m]; if (mode=="onCommand") { if (c.cmd==mod.cmd) { c.cmds[mod.cmd]=1; if (!c.ismodel && !(mod.data.modcmd&&c.ismod)) {badCommand(`You are not authorized to run the /${mod.cmd} command`,c); return 1;} if (c.cmdparmct==0) { listNotices(c.user); return 1; } else if (c.cmdparmct==1) { if (c.cmdparms[1] in notices) { showNotice(c.cmdparms[1]); sendNotice("Notice "+c.cmdparms[1]+" has been sent",c.user); return 1; } else {badCommand("A notice named '"+c.cmdparms[1]+"' was not found",c); return 1;} } else if (c.cmdparmct==2) { if (c.cmdparms[1]=="off") { if (c.cmdparms[2]=='*') { Object.keys(notices).forEach(n=>delNotice(n)); sendNotice("All notices have been turned off",c.user); return 1; } else if (c.cmdparms[2] in notices) { delNotice(c.cmdparms[2]); sendNotice("Notice "+c.cmdparms[2]+" has been turned off",c.user); return 1; } else {badCommand("A notice named "+c.cmdparms[2]+" was not found",c); return 1;} } } else { if (c.cmdparms[1]=="add") { if (c.cmdparmct<5) {badCommand("Not enough parms specified for /n add",c); return 1;} const timer=Number(c.cmdparms[3]); if (!Number.isInteger(timer)) {badCommand("The timer value ("+c.cmdparms[3]+") is not an integer",c); return 1;} let ul=processUserList(c.cmdparms[4]); if (ul[0].substr(0,1)=="#") {badCommand("/n add error: "+ul[0].substr(1),c); return 1;} let msgwords=c.cmdparms.slice(5); let msg=msgwords.join(" "); if (msg=="") {badCommand("A message must be specified for the new notice",c); return 1;} addNotice(c.cmdparms[2],msg,ul,timer,-1); sendNotice("Notice "+c.cmdparms[2]+" has been added",c.user); return 1; } } } return 0; } else if (mode=="onInit") { mod.data.msg=[]; readCBSettings(m); for (i=1;i<mod.data["msg"].length;i++) {mod.loadParmNotice(mod.data,i)} checkNotices(); } return 0; } thismod['loadParmNotice'] = function(d,i) { // if (!d.name[i]) return; if (d.msg[i]=="") return; d.msg[i]=d.msg[i].replace("\\n","\n"); const tmr = Number(d.timer[i]); if (!Number.isInteger(tmr)) {sendNotice("For notice "+d.name[i]+" in launchparms, the timer value ("+d.timer[i]+") is not an integer. Notice not created",model,"#ff0000"); return;} // if (d.msg[i]=="") {sendNotice("For notice "+d.name[i]+" in launchparms, the message value is blank, Notice not created".model,"#ff0000"); return;} // let ul=processUserList(d.ul[i]); // if (ul[0].substr(0,1)=="#") {sendNotice("For notice "+d.name[i]+" in launchparms, the user list \""+d.ul[i]+"\" was invalid: "+ul[0].substr(1)+", Notice not created",model,"#ff0000"); return;} let cl = d.colors[i].match(/^(#?[\dA-Fa-f]{6})(,#?[\dA-Fa-f]{6})?$/); let fc='#fcfcfc'; let bc='#bcbcbc'; if (cl) {fc=cl[1]; if (cl[2]) {bc=cl[2].substr(1);}} if (fc.length==6) {fc='#'+fc;}; if (bc.length==6) {bc='#'+bc;} addNotice(`notice${i}`,d.msg[i],'*',tmr,-1,fc,bc); } thismod.summary = "create and manage recurring notices", thismod.desc = "Allows recurring notices to be setup and managed. Notices can be setup when the bot starts or via commands.\n"+ "For each notice you must specify the name, a message (i.e. the notice text that will be displayed), the \n"+ "time interval (in seconds) at which it will repeat (use time interval \"0\" to display message manually only),\n"+ "and the [userlist] it will be displayed to (a comma separated list that may include user names, \"*\" for all users,\n"+ "\"*m\" for all mods, or \"*b\" for the broadcaster). An example [userlist] is \"*m,user1\".\n"+ "After a notice is setup, it can be turned off, or displayed one time manually using the \"/n\" command"; thismod.commands = {'/n': "List all of the Notices that have been setup", '/n add [name] [timer] [userlist] [msg]': 'Create a new notice named [name], with message [msg], that will be displayed every [timer] seconds (see descript of [userlist] above ', '/n [name]': "Manually display notice [name] immediately (this will not effect the regularly scheduled display of the notice)", '/n off [name]': "Turn off the recurring notice named [name] -- it can still be displayed manually (specify [name] as \"*\' to turn off all notices)" }; /* ##################################################################################### # Module: spamKill (version 20210719.1821) ##################################################################################### */ modules['spamKill']={};thismod=modules['spamKill'];thismod.data={};modules.names.push('spamKill');thismod.name='spamKill'; thismod.cmd='sk'; thismod.data.fgcol="#ffffff";thismod.data.bgcol="#008800"; thismod.data.verify=[]; thismod.data.skstat="enabled"; thismod.events=["onMessage","onCommand"]; thismod.funct = function(mode,c,m) { mod=modules[m]; if (mode=="onCommand") { if (c.cmd==mod.cmd) { c.cmds[c.cmd]=1; if (c.ismod||c.ismodel) { if (c.cmdparmct==0) {sendNotice(`SpamKill is ${mod.data.skstat}`,c.user,mod.data.fgcol,mod.data.bgcol);return 1;} else if (c.cmdparmct==1&&(c.cmdparms[1]=="on"||c.cmdparms[1]=="off")) { if (c.cmdparms[1]=="on") {mod.data.skstat="enabled";} else {mod.data.skstat="disabled";} sendNotice(`SpamKill has been ${mod.data.skstat}`,c.user); return 1; } } else {badCommand("You are not authorized to run spamKill commands",c); return 1;} } } else if (mode=="onMessage") { if (mod.data.skstat=="enabled") { if (!c.isgrey) {return 0;} if (c.isfan) {return 0;} if (c.ismod) {return 0;} else if (!mod.data.verify[c.user]) { mod.data.verify[c.user]=[]; mod.data.verify[c.user]["1stmsg"]=c.msg.m; } else if (mod.data.verify[c.user]["status"]=="confirmed") {return 0;} else if (mod.data.verify[c.user]["status"]=="asked") { if (c.msg.m==mod.data.verify[c.user]["number"]) { mod.data.verify[c.user]["status"]="confirmed"; sendNotice(`You have been verified, thanks for helping us battle spam!`,c.user,"#008800"); c.msg.m=mod.data.verify[c.user]["1stmsg"]+"\n"; return 0; } else {sendNotice(`Incorrect response`,c.user,"#ff0000");} } mod.data.verify[c.user]["number"]= Math.floor(Math.random()*100); c.msg.m=`Please enter the number "${mod.data.verify[c.user]["number"]}" to send your message. You will only need to do this once.`; c.msg.c="#0000ff"; c.msg['X-Spam'] = true; mod.data.verify[c.user]["status"]="asked"; return 1; } } return 0; } thismod.summary = "user-friendly module for blocking spambots"; thismod.desc = "The goal of spamKill is to block spam while still being friendly to legitimate users.\n"+ "It does not use word filters that cause unnecessary blocks, and does not require users to solve\n"+ "capcha problems or retype messages that were intercepted. While this bot will not prevent all spam\n"+ "spam, it will block the most common spam messages generated by chatroom bots. It works as follows:\n"+ "When a grey user types a message in chat for the first time, they are greeted with the following message:\n"+ "> Please enter the number \"NN\" to send your message. You only need to do this once, thanks for helping battle spam!\n"+ "If the user enters the requested number, their message is sent, and they will the be able to chat freely without\n"+ "future prompts. If the requested number is not entered (and most bots will not), the message will not be sent and\n"+ "the user will continue to be prompted each time they enter an new message"; thismod.commands = {'/sk': "Display spamKill status (enabled or disabled)", '/sk on': 'Enable spamKill (spamKill is enabled by default at startup)', '/sk off': 'Disable spamKill' }; /* ##################################################################################### # Module: tipGoal (version 20210719.1821) ##################################################################################### */ modules['tipGoal']={};thismod=modules['tipGoal'];thismod.data={};modules.names.push('tipGoal');thismod.name='tipGoal'; thismod.cmd='g'; thismod.data.fgcol="#ffffff";thismod.data.bgcol="#880000"; thismod.data.goal={}; cb.settings_choices.push( {name:`${thismod.name}_amt`,type:'int',defaultValue:0,minValue:0,label:"Tip Goal Amount (enter 0 for no tip goal)",required:false}, {name:`${thismod.name}_desc`,type:'str',defaultValue:'',label:'Tip Goal Description',required:false,maxLength:128}, {name:`${thismod.name}_start`,type:'int',defaultValue:0,minValue:0,label:"Tip Goal Amount Collected (enter 0 unless continuing a prior goal)",required:false}, {name:`${thismod.name}_timer`,type:'int',defaultValue:180,minValue:0,label:"How often to Display the Goal Counter in the room (seconds)",required:false}, {name:`${thismod.name}_modcmd`,type:'choice',choice1:"-No-",choice2:"-Yes-",defaultValue:'-Yes-',label:'Allow Mods to run tipGoal commands?',required:true} ); thismod.events=["onInit","onCommand","onTip"]; thismod.funct = function(mode,c,m) { mod=modules[m]; if (mode=="onCommand") { if (c.cmd==mod.cmd) { c.cmds[c.cmd]=1; if (c.cmdparmct==0) { let tmsg=`:blankx Tip Goal: ${mod.data.goal.amt} (${mod.data.goal.curramt} Collected, ${mod.data.goal.amt-mod.data.goal.curramt} Remaining)`; if (c.ismodel||(mod.data.modcmd&&c.ismod)) { let gstat="Inactive"; if (mod.data.goal.active) {gstat="Active";} tmsg+=` Timer=${mod.data.goal.timer} Status=${gstat} :blankx\n :blankx ${mod.data.goal.desc} :blankx`; } else { if (!mod.data.goal.active) {tmsg=":blankx Tip Goal is not Active :blankx";} else {tmsg+=` :blankx\n :blankx ${mod.data.goal.desc} :blankx`;} } sendNotice(tmsg,c.user,mod.data.fgcol,mod.data.bgcol); return 1; } else if (!c.ismodel && !(mod.data.modcmd&&c.ismod)) {badCommand(`You are not authorized to run the ${mod.cmd} command`,c); return 1;} else if (c.cmdparmct==1) { if (c.cmdparms[1]=="show") {sendNotice(mod.tipProgress(),"",mod.data.fgcol,mod.data.bgcol); return 1;} else if (c.cmdparms[1]=="stop") { if (!mod.data.goal.active) {badCommand("Tip goal.is not active, it cannot be stoped",c); return 1;} mod.data.goal.active=0; delNotice("tipGoal"); sendNotice("Tip goal.turned off",c.user); return 1; } else if (c.cmdparms[1]=="restart") { if (mod.data.goal.desc==""||mod.data.goal.timer==0||mod.data.goal.amt==0) {badCommand("The tip goal.description, timer, or amount is not set, cannot restart goal",c); return 1;} sendNotice("Tip Goal restarted",c.user); mod.data.goal.active=1; mod.data.goal.curramt=0; addNotice('tipGoal',mod.tipProgress,'*',mod.data.goal.timer,-1,mod.data.fgcol,mod.data.bgcol); return 1; } else { if (!Number.isInteger(Number(c.cmdparms[1]))) {badCommand("The goal.amount specified ("+c.cmdparms[1]+") is not an integer",c); return 1;} if (Number(c.cmdparms[1])<=0) {badCommand("The goal.amount specified ("+c.cmdparms[1]+") must be greater than zero",c); return 1;} if (mod.data.goal.desc==""||mod.data.goal.timer==0) {badCommand("The goal.description or timer is not set, cannot change the amount",c); return 1;} mod.data.goal.amt=Number(c.cmdparms[1]); sendNotice("Tip Goal target changed to "+mod.data.goal.amt+" tokens",c.user); mod.processGoalChange(0,mod.data.goal.curramt); return 1; } } else if (c.cmdparmct==2) { if (c.cmdparms[1]=="sofar") { if (!Number.isInteger(Number(c.cmdparms[2]))) {badCommand("The amount collected specified ("+c.cmdparms[2]+") is not an integer",c); return 1;} if (Number(c.cmdparms[2])<=0) {badCommand("The amount collected specified ("+c.cmdparms[2]+") must be greater than zero",c); return 1;} mod.data.goal.curramt=Number(c.cmdparms[2]); sendNotice("Tip Goal current amount collected changed to "+mod.data.goal.curramt+" tokens",c.user); mod.processGoalChange(0,mod.data.goal.curramt); return 1; } } else { if (!Number.isInteger(Number(c.cmdparms[1]))) {badCommand("The goal.amount specified ("+c.cmdparms[1]+") is not an integer",c); return 1;} if (Number(c.cmdparms[1])<=0) {badCommand("The goal.amount specified ("+c.cmdparms[1]+") must be greater than zero",c); return 1;} if (!Number.isInteger(Number(c.cmdparms[2]))) {badCommand("The goal.noticication timer specified ("+c.cmdparms[2]+") is not an integer",c); return 1;} if (Number(c.cmdparms[2])<=0) {badCommand("The goal.notification timer specified ("+c.cmdparms[2]+") must be greater than zero",c); return 1;} mod.data.goal.amt=Number(c.cmdparms[1]); mod.data.goal.timer=Number(c.cmdparms[2]); let descwords=c.cmdparms.slice(3); mod.data.goal.desc=descwords.join(" "); mod.data.goal.curramt=0; mod.data.goal.active=1; addNotice('tipGoal',mod.tipProgress,'*',mod.data.goal.timer,-1,mod.data.fgcol,mod.data.bgcol); return 1; } } return 0; } else if (mode=="onTip") { let t=c; if (mod.data.goal.active) { mod.data.goal.curramt+=t.amount; mod.processGoalChange(mod.data.goal.curramt-t.amount,mod.data.goal.curramt); } } else if (mode=="onInit") { sendNotice("Module tipGoal is running, Type /g to view Current Goal","",mod.data.bgcol); readCBSettings(m); mod.loadParmsTG(mod.data.amt,mod.data.desc,mod.data.start,mod.data.timer); if (mod.data.goal.active) {addNotice('tipGoal',mod.tipProgress,'*',mod.data.goal.timer,-1,mod.data.fgcol,mod.data.bgcol);} checkNotices(); } return 0; } thismod['loadParmsTG'] = function(a,d,s,t) { const mod=modules["tipGoal"]; mod.data.goal.active=0;mod.data.goal.desc="";mod.data.goal.amt=0;mod.data.goal.curramt=0;mod.data.goal.timer=0; if (a==0) {sendNotice("Goal amount specified in launch parms is 0, tipGoal not activated",model,"#900000"); return;} if (s>=a) {sendNotice("Goal amount specified in launch parms is less than starting amount, tipGoal not activated",model,"#900000"); return;} if (!d) {sendNotice("Goal description specified in launch parms is blank, tipGoal not activated".model,"#900000"); return;} if (t==0) {sendNotice("Goal timer specified in launch parms is 0, tipGoal not activated",model,"#900000"); return;} mod.data.goal.amt=Number(a); mod.data.goal.desc=d; mod.data.goal.timer=t; mod.data.goal.curramt=Number(s);mod.data.goal.active=1; } thismod['tipProgress'] = function() { const mod=modules["tipGoal"]; if (!mod.data.goal.active) {return `Tip Goal is not active`;} if (mod.data.goal.curramt<mod.data.goal.amt) {return `:blankx ##### TIP GOAL (${mod.data.goal.amt}tk) #####\n`+ `:blankx :4rightarrows ${mod.data.goal.desc } :4leftarrows :blankx\n`+ `:blankx :danteyellowdot ONLY ${mod.data.goal.amt-mod.data.goal.curramt} TOKENS TO GO! :danteyellowdot :blankx`;} else {return `Tip Goal of ${mod.data.goal.amt} tokens Reached! ${mod.data.goal.desc}`;} } thismod['processGoalChange'] = function(pa,ca) { const mod=modules["tipGoal"]; if (mod.data.goal.active) { if ((pa<mod.data.goal.amt)&&(ca>=mod.data.goal.amt)) { sendNotice(":goalreached666"); sendNotice(":blankx ### GOAL HAS BEEN REACHED ### :blankx\n"+ ":blankx ### GOAL HAS BEEN REACHED ### :blankx\n"+ ":blankx ### GOAL HAS BEEN REACHED ### :blankx\n"+ ":blankx ### GOAL HAS BEEN REACHED ### :blankx\n"+ ":blankx ### GOAL HAS BEEN REACHED ### :blankx\n", model,"#ffffff","#ff0000"); mod.data.goal.active=0; delNotice("tipGoal"); } else {showNotice('tipGoal');} } } thismod.summary = "set and manage Tip Goals"; thismod.desc = "Establishes a tip goal. tracks how much has been collected against the goal.and displays it\n"+ "as a room notice, and notifies you when the goal.is met. Commands allow you to check the goal.status,\n"+ "stop/restart the goal. replace the goal. and change the goal.target or amount collected."; thismod.commands = {'/g': 'Show the goal and amount collected to the user typing the command. For mods/broadcaster, shows timer as well', '/g [amt] [timer] [desc]': 'Set the goal.to [amt] with description [desc], with notice displayed timer [timer] minutes', '/g [amt]': 'Change the goal.target amount to [amt], keeping the same description, timer, and amount collected', '/g stop': 'Disable the tip goal.', '/g restart': 'Restart the the tip goal. using previously set amount, description, and timer, Amount collected gets reset to 0', '/g sofar [amt]': 'Change the amount collected against the goal.to [amt]', '/g show': 'Display the goal.and its status as a room notice now' }; /* ##################################################################################### # Module: mobilePM (version 20210719.1821) ##################################################################################### */ modules['mobilePM']={};thismod=modules['mobilePM'];thismod.data={};modules.names.push('mobilePM');thismod.name='mobilePM'; thismod.cmd='pm'; thismod.data.fgcol="#ffffff";thismod.data.bgcol="#f211df"; cb.settings_choices.push({name:`mobilepm_tipamt`,type:'int',defaultValue:0,label:`Tip Amount that allows users to PM (0 to disable)`,required:true,minValue:0}) cb.settings_choices.push({name:`mobilepm_nfreq`,type:'int',defaultValue:180,label:`How often to display Tip for PM message (in seconds)`,required:true,minValue:10}) thismod.events=["onCommand","onTip","onInit"]; thismod.funct = function(mode,c,m) { mod=modules[m]; if (mode=="onCommand") { if ((c.cmd=="pmhelp")&&(c.cmdparmct==0)) { if (!mod.data.tipamt) {sendNotice("Tipping for PM's is not currently available",c.user,mod.data.bgcol,mod.data.fgcol);} else { sendNotice(`:blankx Tip ${mod.data.tipamt} tokens to be able to send PMs to ${model}\n`+ `:blankx You will be able to PM for the entire performance\n`+ `:blankx Once you have tipped, type "/pm [message]" to send a PM (e.g. /pm Hi ${model}!!)\n`+ `:blankx Note: ${model} can not PM you back, but can respond verbally on the stream`, c.user,mod.data.bgcol,mod.data.fgcol); } return 1; } if (c.cmd==mod.cmd) { c.cmds[c.cmd]=1; if (!c.ismodel && !c.ismod && !mod.data.pmlist[c.user]) {badCommand(`You are not authorized to run the ${mod.cmd} command`,c); return 1;} if (c.cmdparmct==0) {return 0;} else if ((c.cmdparmct==1)&&(c.cmdparms[1]=="list")) { if (!c.ismodel && !c.ismod) {badCommand(`You are not authorized to run this command`,c); return 1;} if (!Object.keys(mod.data.pmlist)) {sendNotice(`No users are currently setup to PM`,c.user,mod.data.bgcol,mod.data.fgcol);} else {sendNotice(`The following users can PM: ${Object.keys(mod.data.pmlist).join()}`,c.user,mod.data.bgcol,mod.data.fgcol);} return 1; } else if ((c.cmdparmct==2)&&(c.cmdparms[1]=="add")) { if (!c.ismodel && !c.ismod) {badCommand(`You are not authorized to run this command`,c); return 1;} mod.data.pmlist[c.cmdparms[2]]=1; sendNotice(`User ${c.cmdparms[2]} can now PM`,c.user,mod.data.bgcol,mod.data.fgcol); return 1; } else if ((c.cmdparmct==2)&&(c.cmdparms[1]=="del")) { if (!c.ismodel && !c.ismod) {badCommand(`You are not authorized to run this command`,c); return 1;} if (mod.data.pmlist[c.cmdparms[2]]) { delete mod.data.pmlist[c.cmdparms[2]]; sendNotice(`User ${c.cmdparms[2]} can no longer PM`,c.user,mod.data.bgcol,mod.data.fgcol); return 1; } else {sendNotice(`User ${c.cmdparms[2]} was not able to PM, not deleted`,c.user,mod.data.bgcol,mod.data.fgcol); return 1;} } else if ((c.cmdparmct==2)&&(c.cmdparms[1]=="tip")) { if (!c.ismodel && !c.ismod) {badCommand(`You are not authorized to run this command`,c); return 1;} const amt=Number(c.cmdparms[2]); if (!Number.isInteger(amt)) {badCommand("The tip amount ("+amt+") is not an integer",c); return 1;} if (amt<0) {badCommand("The tip amount ("+amt+") must be 0 or greater",c); return 1;} mod.data.tipamt=amt; mod.setupPMs(); sendNotice(`Tip amount for PMs changed to ${amt}`,c.user,mod.data.bgcol,mod.data.fgcol); return 1; } else { sendNotice(":blankx Private Message from "+c.user+" :blankx\n:blankx :4rightarrows "+c.msg.m.substr(4)+" :blankx",model,mod.data.fgcol,mod.data.bgcol); sendNotice("PM sent to "+model,c.user); return 1; } } } else if (mode=="onInit") { mod.data.pmlist={}; readCBSettings(m); mod.setupPMs(); checkNotices(); } else if (mode=="onTip") { if ((mod.data.tipamt==c.amount) && (!mod.data.pmlist[c.from_user])) { mod.data.pmlist[c.from_user]=1; sendNotice(`Thanks for your tip! You can now PM ${model}, type "/pmhelp" for more info`,c.from_user,mod.data.fgcol,mod.data.bgcol); sendNotice(`User ${c.from_user} tipped ${c.amount}tk, and can now PM you`,model,mod.data.fgcol,mod.data.bgcol); } } return 0; } thismod['setupPMs'] = function() { const mod=modules['mobilePM']; if (mod.data.tipamt) { addNotice(mod.name,`:blankx Tip ${mod.data.tipamt} tokens to allow sending PM's to ${model} :blankx\n:blankx Type /pmhelp for more information`,"",mod.data.nfreq,-1,mod.data.fgcol,mod.data.bgcol); } else {delNotice(mod.name)} } thismod.summary = "allows mods to PM the broadcaster"; thismod.desc = "This module is meant to supplement the mobile broadcastng app by allowing mods and users who tip a designated amount to PM the broadcaster\n"+ "The PMs show up as notices that are displayed only to the brioadcaster"; thismod.commands = {'/pm [message]': 'The [message] text is displayed as a private notice seen only by the broadcaster', '/pm list': 'List users that are allowed to PM', '/pm add [user]': 'Allow [user] to send PMs', '/pm del [user]': 'Allow [user] to send PMs', '/pm tip [amt]': 'Change the tip amount that allows users to PM to [amt]', '/pmhelp':'Display a message to the user explaining how to use these PMs' }; /* ##################################################################################### # Module: thankYou (version 20210719.1821) ##################################################################################### */ modules['thankYou']={};thismod=modules['thankYou'];thismod.data={};modules.names.push('thankYou');thismod.name='thankYou'; thismod.data.fgcol="#990000";thismod.data.bgcol="#eeee00"; thismod.events=["onFollow","onTip"]; thismod.funct = function(mode,c,m) { mod=modules[m]; if (mode=="onTip") { sendNotice(`:thanks9 \n:blankx FOR THE TIP, ${c.from_user.toUpperCase()} !! :blankx`,"",mod.data.fgcol,mod.data.bgcol); } else if (mode=="onFollow") { sendNotice(`:thanks9 \n:blankx FOR FOLLOWING, ${c.user.toUpperCase()} !! :blankx`,"",mod.data.fgcol,mod.data.bgcol); } return 0; } thismod.summary = "displays thank you notices for tips and follows"; thismod.desc = "Displays a notice to the room thanking a user who tips, or a user that follows"; /* ##################################################################################### # Module: tipMenu (version 20210719.1821) ##################################################################################### */ modules['tipMenu']={};thismod=modules['tipMenu'];thismod.data={};modules.names.push('tipMenu');thismod.name='tipMenu'; thismod.cmd='m'; thismod.data.fgcol="#ffffff";thismod.data.bgcol="#000090"; thismod.data.menu={}; cb.settings_choices.push({name:`tipmenu_hdr`,type:'choice',choice1:"*** ADD TIP MENU ITEMS BELOW ***",label:'THE AMOUNT FOR EACH TIP MENU ITEM MUST BE DIFFERENT',required:true}); for (i=1;i<=10;i++) { cb.settings_choices.push( {name:`tipmenu_${i}_amt`,type:'int',defaultValue:"",label:`Amount for Tip Menu item #${i}`,required:false,minValue:1}, {name:`tipmenu_${i}_item`,type:'str',defaultValue:"",label:`Desctiption of Tip Menu item #${i}`,required:false,maxLength:32} ); } cb.settings_choices.push( {name:'tipmenu_timer',type:'int',defaultValue:90,label:'How often to display Tip Menu (in seconds)',required:true,minvalue:1}, {name:'tipmenu_modcmd',type:'choice',choice1:"-No-",choice2:"-Yes-",defaultValue:'-Yes-',label:'Allow Mods to run tipMenu commands?',required:true} ); thismod.events=["onInit","onCommand","onTip"]; thismod.funct = function(mode,c,m) { mod=modules[m]; if (mode=="onCommand") { if (c.cmd==mod.cmd) { c.cmds[mod.cmd]=1; if (c.cmdparmct==0) { if (Object.keys(mod.data.menu).length==0) {sendNotice("There are no items on the tip menu",c.user,mod.data.bgcol);} else {sendNotice(mod.menuContent(),c.user,mod.data.fgcol,mod.data.bgcol);} return 1; } if (!c.ismodel && !(mod.data.modcmd&&c.ismod)) {badCommand(`You are not authorized to run the /${mod.cmd} command`,c); return 1;} else if (c.cmdparmct==2) { if (c.cmdparms[1]=="timer") { const timer=Number(c.cmdparms[2]); if (!Number.isInteger(timer)) {badCommand("The timer value ("+c.cmdparms[2]+") is not an integer",c); return 1;} if (timer<0) {badCommand("The timer value ("+c.cmdparms[2]+") must be 0 or greater",c); return 1;} mod.data.timer=timer; if (timer==0) {delNotice(m); sendNotice("Tip Menu has been turned off",c.user);} else { addNotice(m,mod.menuContent,"",mod.data.timer,-1,mod.data.fgcol,mod.data.bgcol); sendNotice("Tip Menu timer updated to "+timer,c.user); } return 1; } else if (c.cmdparms[1]=="del") { const amt=Number(c.cmdparms[2]); if (!Number.isInteger(amt)) {badCommand("The tip amount ("+c.cmdparms[2]+") is not an integer",c); return 1;} if (amt<1) {badCommand("The tip amount ("+amt+") must be greater than 0",c); return 1;} if (!mod.data.menu[amt]) {badCommand("A menu item for tip amount "+amt+" does not exist",c); return 1;} sendNotice(`Tip Menu item "${amt}tk - ${mod.data.menu[amt]}" has been deleted`,c.user); delete mod.data.menu[amt]; return 1; } } else if ((c.cmdparmct>2)&&(c.cmdparms[1]=="add")) { const amt=Number(c.cmdparms[2]); if (!Number.isInteger(amt)) {badCommand("The tip amount ("+c.cmdparms[2]+") is not an integer",c); return 1;} if (amt<1) {badCommand("The tip amount ("+amt+") must be greater than 0",c); return 1;} if (mod.data.menu[amt]) {badCommand("A menu item for tip amount "+amt+" already exists, delete it first",c); return 1;} let itemwords=c.cmdparms.slice(3); let item=itemwords.join(" "); mod.data.menu[amt]=item; sendNotice(`Tip Menu item "${amt}tk - ${item}" has been added`,c.user); return 1; } } return 0; } else if (mode=="onInit") { mod.data.amt=[];mod.data.item=[];mod.data.banner=""; readCBSettings(m); mod.loadMenu(); checkNotices(); } else if (mode=="onTip") { let itm="(No Matching Tip Menu Item)"; if (mod.data.menu[c.amount]) {itm=`for ${mod.data.menu[c.amount]}`;} sendNotice(`User ${c.from_user} tipped ${c.amount} ${itm}`,model,mod.data.fgcol,mod.data.bgcol); } return 0; } thismod['loadMenu'] = function() { const mod=modules['tipMenu']; for (i=1;i<=10;i++) { const amt=mod.data["amt"][i],item=mod.data["item"][i]; if (amt) { if (item=="") {sendNotice(`Menu item for amount ${amt} is blank, skipped`,model,"#ff0000");} else if (mod.data.menu[amt]) {sendNotice(`***\n*** Tip menu item already exists with amount ${amt}, item ${item} was not added to the tip menu\n***`,model,"#ff0000");} else {mod.data.menu[amt]=item;} } } if (Object.keys(mod.data.menu).length>0) { sendNotice("Module tipMenu is running, Type /m to view the tip menu","","#900000"); addNotice(mod.name,mod.menuContent,"",mod.data.timer,-1,mod.data.fgcol,mod.data.bgcol); } } thismod['menuContent'] = function() { const mod=modules['tipMenu']; if (mod.data.banner=="tipifyou") {mod.data.banner="showlove_ch";} else{mod.data.banner="tipifyou";} let m=` :blankx :${mod.data.banner}\n :blankx ########## TIP MENU ##########\n`; for (const amt of Object.keys(mod.data.menu).sort((a,b)=>a-b)) { m+=` :blankx :reddotblink2 ${amt}tk - ${mod.data.menu[amt]} :reddotblink2 :blankx\n`; } m+=" :blankx ###########################"; return m; } thismod.summary = "tip menu"; thismod.desc = "Creates a tip menu that is displayed as a repeating notice.\n"+ "When a tip matching a menu item amount is made, a notice is sent to the broadcaster indicating the item that was tipped for\n"+ "Menu items can be created at script startup and added/deleted via commands. Each tip menu item must have a unique cost"; "Menu items are created at script startup. Each tip menu item must have a unique cost"; thismod.commands = {'/m': "Display the tip menu", '/m add [cost] [description]': 'Create a new tip menu item with the [cost] and [description] provided (no other item can have the same cost)', '/m del [cost]': 'Deletes the tip menu item with the [cost] indicated', '/m timer [interval] ': 'Changes the interval that the tip notice is displayed to [interval] seconds (specify 0 to turn off notices)' }; /* ##################################################################################### # Module: sB (version 20210719.1821) ##################################################################################### */ modules['sB']={};thismod=modules['sB'];thismod.data={};modules.names.push('sB');thismod.name='sB'; thismod.cmd='sb'; thismod.data.fgcol="#ffffff";thismod.data.bgcol="#ff0000"; thismod.data.blist=[]; thismod.events=["onMessage","onCommand"]; thismod.funct = function(mode,c,m) { mod=modules[m]; if (mode=="onMessage") { if (mod.data.blist[c.user.toLowerCase()]) { c.msg['X-Spam']=true; sendNotice(`Blocked ${c.user}: ${c.msg.m}`,"",mod.data.fgcol,mod.data.bgcol,"","red"); return 1; } } else if (mode=="onCommand") { if (c.cmd==mod.cmd) { if (!c.ismodel && !c.ismod) {badCommand(`You are not authorized to run the ${mod.cmd} command`,c); return 1;} c.cmds[c.cmd]=1; if (c.cmdparmct==0) { let ul="There are no users on the sB list"; if (Object.keys(mod.data.blist).length>0) { ul=":blankx sB List: :blankx\n"; Object.keys(mod.data.blist).forEach(u=>ul+=`:blankx - ${u} :blankx\n`); } sendNotice(ul,c.user,mod.data.fgcol,mod.data.bgcol); return 1; } else if (c.cmdparmct==1) { c.cmdparms[1]=c.cmdparms[1].toLowerCase(); if (c.cmdparms[1]=='del') {return 0;} mod.data.blist[c.cmdparms[1]]=1; mod.sN(`User ${c.cmdparms[1]} has been added to the sB list`,c); return 1; } else if (c.cmdparmct==2) { c.cmdparms[1]=c.cmdparms[1].toLowerCase();c.cmdparms[2]=c.cmdparms[2].toLowerCase(); if (c.cmdparms[1]!=="del") {return 0;} if (c.cmdparms[2]=="*") {mod.data.blist=[]; mod.sN(`All users removed from sB list`,c);} else if (mod.data.blist[c.cmdparms[2]]) {delete mod.data.blist[c.cmdparms[2]]; mod.sN(`User ${c.cmdparms[2]} removed from sB list`,c);} else {sendNotice(`User ${c.cmdparms[2]} is not on the sB list`,c.user,mod.data.fgcol,mod.data.bgcol);} return 1; } } } return 0; } thismod['sN'] = function(n,c) {sendNotice(n,c.user,mod.data.fgcol,mod.data.bgcol);sendNotice(n,model,mod.data.fgcol,mod.data.bgcol);} thismod.summary = ""; thismod.desc = ""; thismod.commands = {'/sb': 'Show list', '/sb [u]': 'Add to list', '/sb del u|*': 'Remove from list (*=all)' }; /* ############ # BOT CODE ############ */ for (i=1;i<=5;i++) {deleteSC(`notices_${i}_msg`);deleteSC(`notices_${i}_colors`);deleteSC(`notices_${i}_timer`);} cb.settings_choices.push( {name:`notices_1_msg`,type:'str',defaultValue:`:blankx www.onlyfans.com/jfowler275 :blankx \n :blankx New Guy on Guy clips and Cumshot Videos :blankx`,label:`Notice #1 message (blank to disable)`,required:false,maxLength:255}, {name:`notices_1_colors`,type:'str',defaultValue:'#ffffff,#880000',label:`Notice #1 Colors`,required:true,maxLength:255}, {name:`notices_1_timer`,type:'int',defaultValue:120,minValue:0,label:`Notice #1 repeat timer (in seconds).Enter 0 to only show Notice #2 when /n command is used`,required:false}, {name:`notices_2_msg`,type:'str',defaultValue:`:blankx If you are into Sexy/Thick Girls, check out my best friend/roomate Megalonyx :blankx `+ `:blankx Free 1 hour+ Guy on Guy video with subs to both my and her OnlyFans :blankx \n`+ `:blankx www.onlyfans.com/megalonyx, www.onlyfans.com/jfowler275 :blankx`,label:`Notice #2 message (blank to disable)`,required:false,maxLength:255}, {name:`notices_2_colors`,type:'str',defaultValue:'#ffffff,#880000',label:`Notice #2 Colors`,required:true,maxLength:255}, {name:`notices_2_timer`,type:'int',defaultValue:120,minValue:0,label:`Notice #2 repeat timer (in seconds).Enter 0 to only show Notice #2 when /n command is used`,required:false}, {name:`notices_3_msg`,type:'str',defaultValue:`:blankx I also can be found on fetlife at https://fetlife.com/users/11561017 :blankx`,label:`Notice #3 message (blank to disable)`,required:false,maxLength:255}, {name:`notices_3_colors`,type:'str',defaultValue:'#ffffff,#880000',label:`Notice #3 Colors`,required:true,maxLength:255}, {name:`notices_3_timer`,type:'int',defaultValue:120,minValue:0,label:`Notice #3 repeat timer (in seconds).Enter 0 to only show Notice #3 when /n command is used`,required:false}, {name:`notices_4_msg`,type:'str',defaultValue:`:blankx :followclick`,label:`Notice #4 message (blank to disable)`,required:false,maxLength:255}, {name:`notices_4_colors`,type:'str',defaultValue:'#ffffff,#ffffff',label:`Notice #4 Colors`,required:true,maxLength:255}, {name:`notices_4_timer`,type:'int',defaultValue:120,minValue:0,label:`Notice #4 repeat timer (in seconds).Enter 0 to only show Notice #4 when /n command is used`,required:false} ); for (i=5;i<=5;i++) { cb.settings_choices.push( {name:`notices_${i}_msg`,type:'str',defaultValue:``,label:`Notice #${i} message {blank to disable)`,required:false,maxLength:255}, {name:`notices_${i}_colors`,type:'str',defaultValue:'#0000ff,#ffffff',label:`Notice #${i} Colors (foreground,background)`,required:true,maxLength:15}, {name:`notices_${i}_timer`,type:'int',defaultValue:0,minValue:0,label:`Notice #${i} repeat timer (in seconds).\nEnter 0 to only show Notice #${i} when /n command is used`,required:false} ) }; deleteSC(`tipMenu_hdr`); function botInit() { botmods['alanstuart_']=1; } bothelp="jfowlerbot was created by alanstuart_"; /* ################################################ # AFTER MODULES HAVE BEEN PROCESSED, RUN INIT # ################################################ */ init();
© Copyright Chaturbate 2011- 2024. All Rights Reserved.