Bots Home
|
Create an App
Rock-Paper-Scissors
Author:
noiett
Description
Source Code
Launch Bot
Current Users
Created by:
Noiett
/* * Title: Rock Paper Scissors * Author: noiett * Email: noiett.cb@gmail.com * Twitter: @biosandapps * Version: 1.3 Aug 1, 2018 * Description: Rock Paper Scissors game * * */ // Some useful characters var HEART = '\u2665'; // ♥ BDIAMOND = '\u2666'; // ♦ BSTAR = '\u2605'; // ★ SSTAR = '\u22c6'; // ⋆ WSTAR = '\u2606'; // ☆ POINT = '\u00B7'; // · ARROW = '\u2192'; // → SBSQR = '\u25AA'; // ▪ SARROW = '\u10148'; // ➤ /* -------------------------------------------- * Constants for different uses * -------------------------------------------- */ // CONSTANTS var COLORS = [ {name: 'Amaranth', code: '#c92572', bgcode: '#f9eaf1'}, {name: 'Black', code: '#000000', bgcode: '#e8e8e8'}, {name: 'Blue', code: '#016ea6', bgcode: '#e3eff6'}, {name: 'LightBlue', code: '#4682b4', bgcode: '#e5f0f9'}, {name: 'SteelBlue', code: '#4159b5', bgcode: '#e7ebfb'}, {name: 'DarkBlue', code: '#364785', bgcode: '#e4e9f9'}, {name: 'BrownRed', code: '#b31313', bgcode: '#fbe9e9'}, {name: 'DarkViolet', code: '#9c3dc4', bgcode: '#efdff4'}, {name: 'SeanceViolet', code: '#ba21bf', bgcode: '#ffdffe'}, {name: 'Green', code: '#327939', bgcode: '#e1f9e3'}, {name: 'DarkGreen', code: '#436446', bgcode: '#d0e8d3'}, {name: 'Pink', code: '#FF00BA', bgcode: '#ffe6f8'}, {name: 'Purple', code: '#800080', bgcode: '#f1e4f1'}, {name: 'Red', code: '#ff3232', bgcode: '#ffe5e5'}, {name: 'SlateGray', code: '#708090', bgcode: '#eaeff3'}, ]; /* ------------------------------------------------ * Global variables * ------------------------------------------------ */ var botName = 'Rock Paper Scissors'; var botTextColor = '#FF00BA'; var botBgColor = '#ffe6f8'; var botTextWeight = 'normal'; var modelName = cb.room_slug; var botVersion = "1.3"; var botDate = "Aug 1, 2018"; var botWarnColor = '#ff0000'; var botNoticeDelay = 500; var silencedTimeout = 0; var silencedTimeoutFreq = 0.5; var gameCurrent = ''; var gameRPSPlayer1 = ''; var gameRPSPlayer2 = ''; var gameRPSHand1 = ''; var gameRPSHand2 = ''; var rpsBoardType = 0; var rpsSilenceLoser = false; var rpsSilenceTime = 5; var rpsCrownIcon = ''; var silencedList = []; var playersList = []; var botCommand = '/'; var theHeader = ':mtlstar ' + botName + ' v' + botVersion + ' :mtlstar'; var loadText = 'Built by noiett (' + botDate + ')\n' + 'Type /rpshelp to see all bot commands.'; var publicHelp = ''; /* -------------------------------------------- * Bot settings * -------------------------------------------- */ cb.settings_choices = [ { name: 'rps_colors', type:'choice', label:'Color scheme', choice1: 'Amaranth', choice2: 'Black', choice3: 'Blue', choice4: 'LightBlue', choice5: 'SteelBlue', choice6: 'DarkBlue', choice7: 'BrownRed', choice8: 'DarkViolet', choice9: 'SeanceViolet', choice10: 'Green', choice11: 'DarkGreen', choice12: 'Pink', choice13: 'Purple', choice14: 'Red', choice15: 'SlateGray', defaultValue: 'SteelBlue' }, { name: 'rps_board_type', type: 'choice', choice1: 'Difference wins vs losses', choice2: 'Total wins and draws', defaultValue: 'Total wins and draws', label: 'Sort the leaderboard by' }, { name: 'rps_crown', type: 'str', defaultValue: ':icon_crown', label: 'Icon for the leader' }, { name: 'rps_silence', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No (Skip next section)', label: 'Silence the losers?' }, { name: 'rps_silence_time', type: 'choice', choice1: 1, choice2: 2, choice3: 3, choice4: 4, choice5: 5, choice6: 6, choice7: 8, choice8: 10, choice9: 12, choice10: 15, choice11: 20, choice11: 30, defaultValue: 2, label: 'Duration of the silence (mins)' }, ]; /* * Handle new message */ cb.onMessage(function (msg) { // Some variables var name = msg['user']; var isModel = (name == cb.room_slug); var isMod = msg['is_mod']; var isFan = msg['in_fanclub']; var isCreator = (name == 'noiett'); var hasTokens = msg['has_tokens']; var hasTipped = (msg['tipped_recently'] || msg['tipped_alot_recently'] || msg['tipped_tons_recently']); var isGrey = !(hasTokens || isMod || isModel || isFan); var userMsg = ''; var roomInfoNotice = ''; var roomNotice = ''; var botPrefix = ''; // Save MVP first and add crown if needed var playerMVP = ''; if (playersList.length) { playerMVP = playersList[0].name; } // Check whether user is allowed to chat var silencedUser = getSilencedUser( name ); if ( silencedUser ) { msg['X-Spam'] = true; msg['m'] = '[ Message blocked ' + SBSQR + ' You are currently silenced in the room ]'; if ( silencedUser.time ) { userMsg = 'You will be released from silence in ' + getSilenceReleaseTime( name ) + '.'; delayedNotice( userMsg, name, '', botWarnColor, 'bold', 200 ); } return msg; } // If command then process if (msg.m.indexOf('/') == 0 || msg.m.indexOf('!') == 0) { // Handling commands var message = msg['m'].substr(1); var userParam = getParam(message,0); var userParam2 = getParam(message,1); var userParam3 = getParam(message,2); var botPrefix = botCommand; switch (userParam) { case 'rpshelp': msg['m'] = msg['m'] + " (help sent to " + msg['user'] + ")"; sendCommand(name, 'help'); break; case 'board': msg['m'] = msg['m'] + " (leaderboard sent to " + msg['user'] + ")"; sendCommand(name, 'board'); break; case 'rock': case 'paper': case 'scissors': if (gameCurrent == 'Rock-Paper-Scissors') { msg['X-Spam'] = true; if (!gameRPSPlayer1 && !gameRPSPlayer2) { // Save first player hand gameRPSPlayer1 = name; gameRPSHand1 = userParam; roomNotice = name + ' is ready to play.\nType /rock, /paper or /scissors to become the second player and beat ' + name + '!'; } else { if (!gameRPSPlayer2) { if (name != gameRPSPlayer1) { // Last spot available. Save and play! gameRPSPlayer2 = name; gameRPSHand2 = userParam; // Play hand // A. Draw case if (gameRPSHand1 == gameRPSHand2) { roomInfoNotice = ':mtlstar The game ends in a draw!! :mtlstar'; roomNotice = gameRPSPlayer1 + ' plays ' + gameRPSHand1 + ' and ' + gameRPSPlayer2 + ' replies with ' + gameRPSHand2 + ' too.' + '\nType /rock, /paper or /scissors to play again or /board to see the rankings!'; // Handle leaderboard addDrawUser(gameRPSPlayer2); addDrawUser(gameRPSPlayer1); } else { // B. Not a draw var theWinner = ''; var theLoser = ''; switch (gameRPSHand1) { case 'rock': switch (gameRPSHand2) { case 'paper': roomNotice = gameRPSPlayer1 + ' plays rock confidently but ' + gameRPSPlayer2 + ' wraps that rock with a paper hand.' + '\nType /rock, /paper or /scissors to play again or /board to see the rankings!'; theLoser = gameRPSPlayer1; theWinner = gameRPSPlayer2; break; case 'scissors': roomNotice = gameRPSPlayer1 + ' stunts ' + gameRPSPlayer2 + '\'s scissors with a powerful rock.' + '\nType /rock, /paper or /scissors to play again or /board to see the rankings!'; theLoser = gameRPSPlayer2; theWinner = gameRPSPlayer1; break; } break; case 'paper': switch (gameRPSHand2) { case 'rock': roomNotice = gameRPSPlayer2 + ' plays rock confidently but ' + gameRPSPlayer1 + ' eats that rock with a paper hand.' + '\nType /rock, /paper or /scissors to play again or /board to see the rankings!'; theLoser = gameRPSPlayer2; theWinner = gameRPSPlayer1; break; case 'scissors': roomNotice = gameRPSPlayer1 + ' tries to wrap the opponent with a paper hand but ' + gameRPSPlayer2 + ' plays scissors and cuts the paper.' + '\nType /rock, /paper or /scissors to play again or /board to see the rankings!'; theLoser = gameRPSPlayer1; theWinner = gameRPSPlayer2; break; } break; case 'scissors': switch (gameRPSHand2) { case 'rock': roomNotice = gameRPSPlayer1 + ' plays scissors confidently but ' + gameRPSPlayer2 + ' stunts the scissors with a powerful rock.' + '\nType /rock, /paper or /scissors to play again or /board to see the rankings!'; theLoser = gameRPSPlayer1; theWinner = gameRPSPlayer2; break; case 'paper': roomNotice = gameRPSPlayer2 + ' tries to wrap the opponent with a paper hand but ' + gameRPSPlayer1 + ' plays scissors and cuts the paper.' + '\nType /rock, /paper or /scissors to play again or /board to see the rankings!'; theLoser = gameRPSPlayer2; theWinner = gameRPSPlayer1; break; } break; default: roomNotice = 'Sorry, something wrong happened and the game could not be finished.'; break; } // Handle leaderboard and room info notice roomInfoNotice = ':mtlstar ' + theWinner + ' is the winner!! :mtlstar'; addWinUser(theWinner); addLossUser(theLoser); // Silence loser if (theLoser && rpsSilenceLoser) { silencedList.push({ name: theLoser, time: rpsSilenceTime, startTime: new Date() }); if (!silencedTimeout) { // Launch timer to release silenced users silencedTimeout = cb.setTimeout(releaseSilencedUsers, silencedTimeoutFreq * 60000); } roomNotice += '\nUser ' + theLoser + ' will be silenced for ' + rpsSilenceTime + ' ' + ((rpsSilenceTime > 1) ? 'minutes' : 'minute') + ' after losing the game.'; } } sortPlayers(); if (playersList[0].name != playerMVP) { if (gameRPSHand1 == gameRPSHand2) { roomInfoNotice = ':mtlstar The game ends in a draw and ' + playersList[0].name + ' is the new leader!! :mtlstar'; } else { roomInfoNotice = ':mtlstar ' + theWinner + ' is the winner and the new leader!! :mtlstar'; } } // Reset variables gameRPSPlayer1 = ''; gameRPSPlayer2 = ''; gameRPSHand1 = ''; gameRPSHand2 = ''; } else { userMsg = 'You already sent your hand! Wait for your opponent to join.'; } } else { // Sorry, no spots left to play userMsg = 'We have 2 players already. Wait for another round!'; } } } else { userMsg = 'You can\'t play Rock-Paper-Scissors until someone starts the game.'; } break; // Mod and Admin commands case 'rpsstart': if (isCreator || isModel) { msg['X-Spam'] = true; gameCurrent = 'Rock-Paper-Scissors'; roomInfoNotice = ':mtlstar ' + name + ' has started a ' + gameCurrent + ' game! :mtlstar'; roomNotice = 'Type /rock, /paper or /scissors to join and play this round.'; } break; // Mod and Admin commands case 'rpsstop': if (isCreator || isModel) { // Stop the current game msg['X-Spam'] = true; gameCurrent = ''; roomInfoNotice = ':mtlstar ' + name + ' has stopped the ' + gameCurrent + ' game :mtlstar'; gameRPSPlayer1 = ''; gameRPSPlayer2 = ''; gameRPSHand1 = ''; gameRPSHand2 = ''; } break; } } // Sending output messages // Workaround for CB bug: delayed notices prevent messages from being broken by command message // Room info notice (dark background) if (roomInfoNotice) delayedNotice(roomInfoNotice,'',botTextColor,"#FFFFFF",'bolder', botNoticeDelay); if (roomNotice) delayedNotice(roomNotice, '', botBgColor, botTextColor, botTextWeight, botNoticeDelay + 200); if (userMsg) delayedNotice(userMsg, name, '', botTextColor, botTextWeight, botNoticeDelay); // MVP crown if (playersList.length) { if (name == playerMVP) { msg['m'] = rpsCrownIcon + ' ' + msg['m']; } } return msg; }); /* ------------------------------------------------ * Functions for different uses * ------------------------------------------------ */ function playerPosition(name) { for (var i=0; i<playersList.length; i++) { if (playersList[i].name == name) return i; } return -1; } /* * Adds a win to a user in the playersList Array * */ function addWinUser(name) { var pos = playerPosition(name); if (pos != -1) { playersList[pos].win ++; } else { playersList.push({ name: name, win: 1, draw: 0, loss: 0 }) } } /* * Adds a draw to a user in the playersList Array * */ function addDrawUser(name) { var pos = playerPosition(name); if (pos != -1) { playersList[pos].draw ++; } else { playersList.push({ name: name, win: 0, draw: 1, loss: 0 }) } } /* * Adds a win to a user in the playersList Array * */ function addLossUser(name) { var pos = playerPosition(name); if (pos != -1) { playersList[pos].loss ++; } else { playersList.push({ name: name, win: 0, draw: 0, loss: 1 }) } } function sortPlayers() { if (rpsBoardType == 0) { // Sort by total wins, if equal sort by draws and less losses playersList.sort(function (x, y) { var n = y.win - x.win; if (n !== 0) { return n; } else { n = y.draw - x.draw; if (n !== 0) { return n; } else { return x.loss - y.loss; } } }); } else { // Sort by points, if equal sort by most wins playersList.sort(function (x, y) { n = (y.win - y.loss) - (x.win - x.loss); if (n !== 0) { return n; } return y.win - x.win; }); } } /* * Returns the time in a Date object in string format: 1h 2mins 45secs */ function dateToString(date) { var out = ''; if (date.getHours()) out += date.getHours() + 'h'; if (date.getMinutes()) { out += ' ' + date.getMinutes(); out += (date.getMinutes() > 1) ? 'mins' : 'min'; } if (date.getSeconds()) { out += ' ' + date.getSeconds(); out += (date.getSeconds() > 1) ? 'secs' : 'sec'; } return out; } /* * Returns a Date (time) object equivalent to the number of seconds in @secs */ function secondsToDate(secs) { var dateTime = new Date(); dateTime.setHours(Math.floor(secs / 3600)); dateTime.setMinutes(Math.floor((secs - dateTime.getHours() * 3600) / 60)); dateTime.setSeconds(Math.floor((secs - dateTime.getHours() * 3600 - dateTime.getMinutes() * 60))); return dateTime; } /* * Returns the number of seconds of a Date object */ function dateToSeconds( date ) { return ( date.getTime() / 1000 ); } /* * Returns the user object from the silenced list matching the name */ function getSilencedUser(name) { for (var i=0; i<silencedList.length; i++) { if (silencedList[i].name == name) { return silencedList[i]; } } return 0; } /* * Returns the time left (string format) before a silence release */ function getSilenceReleaseTime( name ) { var silencedUser = getSilencedUser( name ); // Check if exists if ( silencedUser ) { // Check if it's a temporary silence if ( silencedUser.time ) { // Calculate time left var currentTime = new Date(); var releaseSeconds = dateToSeconds( silencedUser.startTime ) + ( silencedUser.time * 60 ); var secondsLeft = releaseSeconds - dateToSeconds( currentTime ); var out = ''; if ( secondsLeft < 10 ) { out = 'a few seconds'; } else { out = dateToString( secondsToDate( secondsLeft ) ); } return out; } } return 0; } /* * This function checks times for all silenced users * and stops the silencedTimout if no temporary silences are found. */ function updateSilencedTimeout() { var found = false; // Make sure there's an active timeout if (silencedTimeout) { // Check if there are pending users for (var i=0; i<silencedList.length; i++) { if (silencedList[i].time) { found = true; break; } } if (!found) { // Kill the timeout as it has nothing left to do cb.cancelTimeout(silencedTimeout); silencedTimeout = 0; } } } /* * This function is called by a timeout enabled with command /silence [user] [time] * and triggered regularly to remove expired silences until there are no more pending ones. */ function releaseSilencedUsers() { var pending = false; var currentTime = new Date(); var elapsedTime = 0; var elapsedSeconds = 0; var roomNotice = ''; var removeList = []; // Search al silenced users for (var i=0; i<silencedList.length; i++) { // Check if silenced user has timer if (silencedList[i].time) { // Check if timer has expired elapsedSeconds = currentTime.getHours() * 3600 + currentTime.getMinutes() * 60 + currentTime.getSeconds() - silencedList[i].startTime.getHours() * 3600 - silencedList[i].startTime.getMinutes() * 60 - silencedList[i].startTime.getSeconds(); elapsedTime = secondsToDate(elapsedSeconds); //cb.log('User ' + silencedList[i].name + ' has been banned for + ' + dateToString(elapsedTime) + ' and timer was ' + silencedList[i].time + '.'); if (elapsedTime.getMinutes() >= silencedList[i].time) { // Time expired: add user to remove list removeList.push(silencedList[i]); } else { // Time not expired: silence is pending pending = true; } } } // Remove all picked users (if any) for (i=0; i<removeList.length; i++) { cbjs.arrayRemove(silencedList, removeList[i]); roomNotice = 'User ' + removeList[i].name + ' has ' + ' been granted permission to chat again!'; cb.sendNotice(roomNotice, '', botBgColor, botTextColor, botTextWeight); } if (!pending) { // No temporary silences left: stop the timeout cb.cancelTimeout(silencedTimeout); silencedTimeout = 0; } else { // Launch timeout again silencedTimeout = cb.setTimeout(releaseSilencedUsers, silencedTimeoutFreq * 60000); } } /* * Returns the code of a requested color name */ function getColorCode(name) { for (var i=0; i<COLORS.length; i++) { if (COLORS[i].name == name) { return COLORS[i].code; } } return "#FFFFFF"; cb.log('Error: Could not find the code for this color: ' + name); } /* * Returns the code of a requested color background */ function getBgColorCode(name) { for (var i=0; i<COLORS.length; i++) { if (COLORS[i].name == name) { return COLORS[i].bgcode; } } return "#FFFFFF"; cb.log('Error: Could not find the bgcode for this color: ' + name); } /* * Return parameter in a certain position in a string */ function getParam(msg, position) { var tmp = msg.split(' '); return tmp[position]; } /* * Validates if number is Integer type * */ function isInteger(value) { return !isNaN(value) && parseInt(Number(value)) == value && !isNaN(parseInt(value, 10)); } /* * Send delayed notice * @msg: message to send * @target: send the notice to this target * @delay: delay time in miliseconds * @type: Type of notice: 0=Default, 1=White BG, 2=Highlighted, 3=Warning * */ function delayedNotice(msg, target, bgcolor, fgcolor, weight, delay) { if (msg && isInteger(delay) && delay > 0) { // Send Notice setTimeout(function(){ cb.sendNotice(msg,target,bgcolor,fgcolor,weight); }, delay); return true; } else { return false; } } /* * Sends info from this commands to the user or the room: * /help * @name: name of the user, '' = send to the room */ function sendCommand(target, command, param) { var head = ''; var outMsg = ''; var msgBgColor = botBgColor; var msgWeigth = botTextWeight; switch (command) { case 'help': head = ':mtlstar ' + botName + ' Help :mtlstar'; outMsg = publicHelp; break; case 'board': if (playersList.length) { head = ':mtlstar RPS Leaderboard :mtlstar'; for (var i=0; i<playersList.length; i++) { if (outMsg) outMsg += '\n'; outMsg += (i+1) + '. ' + playersList[i].name + ' ' + ARROW + ' '; var rating = playersList[i].win - playersList[i].loss; if (rpsBoardType) outMsg += '(' + (rating > 0 ? '+' : '') + (rating) + ') '; outMsg += playersList[i].win + 'W ' + playersList[i].draw + 'D ' + playersList[i].loss + 'L '; } } else { outMsg = 'No players yet. Play now and become the first leader!'; } break; } // Workaround for CB bug: this delayed notice prevents message from being broken or shown in wrong order // Send Command response to user if (head) delayedNotice(head,target,botTextColor,'#FFFFFF','bold',300); delayedNotice(outMsg,target,botBgColor,botTextColor,msgWeigth,600); } /* * Builds user vars and arrays based on settings */ function parseSettings() { // General bot settings botTextColor = getColorCode(cb.settings.rps_colors); botBgColor = getBgColorCode(cb.settings.rps_colors); rpsBoardType = (cb.settings.rps_board_type == 'Difference wins vs losses' ? 1 : 0); if (cb.settings.rps_crown) rpsCrownIcon = cb.settings.rps_crown; rpsSilenceLoser = (cb.settings.rps_silence == 'Yes') ? 1 : 0; rpsSilenceTime = cb.settings.rps_silence_time; // Users and admin help var prefix = botCommand; publicHelp = '/rpshelp ' + ARROW + ' Show a list with all commands\n' + prefix + 'rpsstart ' + ARROW + ' Start a new Rock-Paper-Scissors game\n' + prefix + 'rpsstop ' + ARROW + ' Stop the game\n' + prefix + 'board ' + ARROW + ' Show the leaderboard\n' + prefix + 'rock ' + ARROW + ' Play rock when the game is running\n' + prefix + 'paper ' + ARROW + ' Play paper when the game is running\n' + prefix + 'scissors ' + ARROW + ' Play scissors when the game is running'; } /* * Setting up the bot at start */ function init() { //Load user's settings values into global variables parseSettings(); // Bot loaded message delayedNotice(theHeader,'',botTextColor,"#FFFFFF",'bold',botNoticeDelay); delayedNotice(loadText,'','',botTextColor,'normal',botNoticeDelay+300); } init();
© Copyright Chaturbate 2011- 2026. All Rights Reserved.