Bots Home
|
Create an App
cleopazzauto
Author:
osumba
Description
Source Code
Launch Bot
Current Users
Created by:
Osumba
/************************************************************* ** ** Title: Cleopatra House Renovation Bot (v3.6.0 - Auto KV Storage) ** Description: House renovation tiers, custom colors/GIFs per tier, ** automatic persistent KV storage, level-up announcements, host commands. ** *************************************************************/ var botVersion = "3.6.0"; var modelName = cb.room_slug; var botTrigger = "/cleobot"; var NOTICE_BG = '#7BD88F'; // one color for ALL bot notices var botMsgBg = NOTICE_BG; var botNoteBg = NOTICE_BG; var UNLOCK_MIN = 555; // single tip needed to join the crew var LEVEL2_AT = 1332; var LEVEL3_AT = 2331; var LEVEL4_AT = 3330; var LEVEL5_AT = 4329; // Architect level 1 var STEP = 999; // every 999 tokens after that = next Architect level var TIER_NAMES = { 1: "Laborer", 2: "Bricklayer", 3: "Finisher", 4: "Technician", 5: "Architect" }; var DEFAULT_COLORS = { 1: "#7BD88F", 2: "#73B5EB", 3: "#CD73EB", 4: "#FFA64D", 5: "#FCED79" }; // Colored marker shown next to the tier name in chat (used when no custom GIF/emote is set) var TIER_EMOJI = { 1: "🟩", 2: "🟦", 3: "🟪", 4: "🟧", 5: "🟨" }; var NOTICE_INTERVALS = [2, 5, 8, 10, 12, 15, 20, 25, 30, 45, 60]; /* * Settings */ function buildSettings() { var s = [ { name: 'genderEmotes', type: 'choice', label: 'Show gender of users in chat?', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes' }, { name: 'userGreets', type: 'choice', label: 'Announce crew members when they enter?', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes' }, { name: 'useBackground', type: 'choice', label: 'Color the WHOLE message row with the tier color?', choice1: 'Yes', choice2: 'No', defaultValue: 'No' } ]; var defaults = [10, 15, 20]; for (var n = 1; n <= 3; n++) { s.push({ name: 'autoNotice' + n, label: 'Promotional Notice ' + n + ' text (leave empty to disable)', type: 'str', minLength: 0, maxLength: 512, required: false, defaultValue: '' }); var iv = { name: 'autoNotice' + n + 'Interval', label: 'Show Notice ' + n + ' every x minutes', type: 'choice', defaultValue: defaults[n - 1] }; for (var c = 0; c < NOTICE_INTERVALS.length; c++) { iv['choice' + (c + 1)] = NOTICE_INTERVALS[c]; } s.push(iv); } s.push({ name: 'menuNoticeInterval', label: 'Show Tip Menu every x minutes (0 to disable)', type: 'choice', choice1: 0, choice2: 10, choice3: 15, choice4: 20, choice5: 30, choice6: 45, choice7: 60, defaultValue: 30 }); s.push({ name: 'statusNoticeInterval', label: 'Show member count notice every x minutes (0 to disable)', type: 'choice', choice1: 0, choice2: 4, choice3: 5, choice4: 7, choice5: 10, choice6: 15, choice7: 20, choice8: 30, defaultValue: 7 }); s.push({ name: 'backupInterval', label: 'Send automatic backup string to the host every x minutes (0 to disable)', type: 'choice', choice1: 0, choice2: 15, choice3: 30, choice6: 60, defaultValue: 30 }); s.push({ name: 'tiersDescription', label: 'Description of Tiers and Rewards', type: 'str', minLength: 0, maxLength: 1024, required: false, defaultValue: 'Level 1 (Laborer): 555 tokens. Level 2 (Bricklayer): 1,332 tokens. Level 3 (Finisher): 2,331 tokens. Level 4 (Technician): 3,330 tokens. Level 5 (Architect): 4,329 tokens, then a new Architect level every 999 tokens.' }); s.push({ name: 'savedUsersInput', label: 'Saved users backup string (format: username:tokens,username:tokens)', type: 'str', minLength: 0, maxLength: 10240, required: false, defaultValue: '' }); for (var t = 1; t <= 5; t++) { s.push({ name: 'tier' + t + 'Gif', label: 'Tier ' + t + ' (' + TIER_NAMES[t] + ') GIF tag (e.g. :mygif)', type: 'str', minLength: 0, maxLength: 50, required: false, defaultValue: '' }); s.push({ name: 'tier' + t + 'Color', label: 'Tier ' + t + ' (' + TIER_NAMES[t] + ') hex color (e.g. #73EBEB)', type: 'str', minLength: 0, maxLength: 10, required: false, defaultValue: DEFAULT_COLORS[t] }); } for (var tt = 1; tt <= 5; tt++) { for (var i = 1; i <= 5; i++) { s.push({ name: 'reward' + tt + '_' + i, label: 'Tier ' + tt + ' (' + TIER_NAMES[tt] + ') - Reward ' + i, type: 'str', minLength: 0, maxLength: 100, required: false, defaultValue: '' }); } } return s; } cb.settings_choices = buildSettings(); var genderEmotes = (cb.settings.genderEmotes !== 'No'); var userGreets = (cb.settings.userGreets !== 'No'); /* * Data & Persistent KV Storage Management */ var userHouseData = {}; var greetedThisSession = {}; var KV_KEY = "cleopatra_house_users_v1"; function calculateTier(points) { if (points < UNLOCK_MIN) return 0; if (points < LEVEL2_AT) return 1; if (points < LEVEL3_AT) return 2; if (points < LEVEL4_AT) return 3; if (points < LEVEL5_AT) return 4; return 5 + Math.floor((points - LEVEL5_AT) / STEP); } // Persist data automatically using Chaturbate KV storage system function savePersistentData() { var rawString = ""; for (var u in userHouseData) { if (userHouseData.hasOwnProperty(u) && userHouseData[u].currentTier > 0) { rawString += u + ":" + userHouseData[u].totalPoints + ","; } } if (typeof cb.kvStore === 'function') { cb.kvStore(KV_KEY, rawString); } else if (cb.settings && typeof cb.settings.set === 'function') { cb.settings.set(KV_KEY, rawString); } } function loadSavedData() { // 1. First try loading from native persistent KV storage var storedData = null; if (typeof cb.kvGet === 'function') { storedData = cb.kvGet(KV_KEY); } else if (cb.settings && typeof cb.settings.get === 'function') { storedData = cb.settings.get(KV_KEY); } // 2. Fallback to manual settings input if KV is empty if (!storedData || storedData.trim().length === 0) { storedData = cb.settings.savedUsersInput; } if (!storedData || storedData.trim().length === 0) return; var raw = storedData.trim().split(','); for (var i = 0; i < raw.length; i++) { var parts = raw[i].split(':'); if (parts.length === 2) { var uName = parts[0].trim().toLowerCase(); var uPoints = parseInt(parts[1].trim(), 10); if (uName.length > 0 && !isNaN(uPoints) && uPoints > 0) { userHouseData[uName] = { totalPoints: uPoints, currentTier: calculateTier(uPoints) }; } } } } loadSavedData(); function safeColor(value, fallback) { return (value && /^#[0-9a-fA-F]{6}$/.test(value.trim())) ? value.trim() : fallback; } function getTierInfo(tier) { if (tier <= 0) return { title: "None", tag: "", color: "" }; var base = Math.min(tier, 5); var gif = cb.settings['tier' + base + 'Gif'] || ""; var color = safeColor(cb.settings['tier' + base + 'Color'], DEFAULT_COLORS[base]); var prefix = (gif ? gif : TIER_EMOJI[base]) + " "; if (tier <= 4) { return { title: TIER_NAMES[tier], tag: prefix + "(" + TIER_NAMES[tier] + ")", color: color }; } var lvl = tier - 4; return { title: "Architect Level " + lvl, tag: prefix + "(Architect Level " + lvl + ")", color: color }; } function nextTarget(tier) { if (tier === 0) return UNLOCK_MIN; if (tier === 1) return LEVEL2_AT; if (tier === 2) return LEVEL3_AT; if (tier === 3) return LEVEL4_AT; if (tier === 4) return LEVEL5_AT; return LEVEL5_AT + (tier - 4) * STEP; } function isDoubleOrTriple(amount) { var s = amount.toString(); if (s.length === 2 || s.length === 3) { for (var i = 1; i < s.length; i++) { if (s.charAt(i) !== s.charAt(0)) return false; } return true; } return false; } /* * Backup export utility */ function buildExportChunks() { var chunks = []; var cur = ""; for (var u in userHouseData) { if (userHouseData.hasOwnProperty(u) && userHouseData[u].currentTier > 0) { var piece = u + ":" + userHouseData[u].totalPoints + ","; if (cur.length + piece.length > 400) { chunks.push(cur); cur = ""; } cur += piece; } } if (cur.length > 0) chunks.push(cur); return chunks; } function sendBackupToHost() { var chunks = buildExportChunks(); if (chunks.length === 0) { cb.chatNotice("BACKUP: no crew members yet.", cb.room_slug, botNoteBg, '', 'bold'); return; } cb.chatNotice("BACKUP (" + chunks.length + " part(s)) - automatic persistent storage is active, but you can save this string as extra backup:", cb.room_slug, botNoteBg, '', 'bold'); for (var i = 0; i < chunks.length; i++) { cb.chatNotice(chunks[i], cb.room_slug, botNoteBg, '', 'bold'); } } /* * Tip menu & notices */ function getFullTipMenuTextForUser(userTier) { var maxTier = (userTier >= 5 || userTier === 0) ? 5 : userTier; var text = "╔══════════════════════════════════╗\n" + "║ RENOVATION REWARD MENU ║\n" + "╚══════════════════════════════════╝\n"; var any = false; for (var t = 1; t <= maxTier; t++) { text += "► Tier " + t + " (" + TIER_NAMES[t] + "):\n"; var has = false; for (var i = 1; i <= 5; i++) { var item = cb.settings['reward' + t + '_' + i]; if (item && item.trim().length > 0) { text += " • " + item.trim() + "\n"; has = true; any = true; } } if (!has) text += " (No rewards configured)\n"; } return any ? text : "The reward tip menu is currently empty."; } function scheduleNotice(n) { var text = cb.settings['autoNotice' + n]; if (!text || text.trim().length === 0) return; var minutes = parseInt(cb.settings['autoNotice' + n + 'Interval'], 10) || 10; cb.setTimeout(function () { cb.chatNotice(text.trim(), '', botNoteBg, '', 'bold'); scheduleNotice(n); }, minutes * 60000); } function displayPeriodicTipMenu() { var minutes = parseInt(cb.settings.menuNoticeInterval, 10) || 0; if (minutes <= 0) return; cb.setTimeout(function () { cb.chatNotice(getFullTipMenuTextForUser(5), '', botMsgBg, '', 'bold'); displayPeriodicTipMenu(); }, minutes * 60000); } function scheduleBackup() { var minutes = parseInt(cb.settings.backupInterval, 10) || 0; if (minutes <= 0) return; cb.setTimeout(function () { sendBackupToHost(); scheduleBackup(); }, minutes * 60000); } function displayDynamicStatusNotice() { var counts = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 }; for (var u in userHouseData) { if (userHouseData.hasOwnProperty(u)) { var t = userHouseData[u].currentTier; if (t >= 1) counts[Math.min(t, 5)]++; } } var msg = "Help renovate Cleopatra's house! Tip " + UNLOCK_MIN + "+ tokens in a single tip to join the Renovation Crew. Currently there are " + counts[1] + " laborers, " + counts[2] + " bricklayers, " + counts[3] + " finishers, " + counts[4] + " technicians, and " + counts[5] + " architects!"; cb.chatNotice(msg, '', botNoteBg, '', 'bold'); scheduleStatusNotice(); } function scheduleStatusNotice() { var minutes = parseInt(cb.settings.statusNoticeInterval, 10); if (isNaN(minutes)) minutes = 7; if (minutes <= 0) return; cb.setTimeout(displayDynamicStatusNotice, minutes * 60000); } /* * Tips */ cb.onTip(function (tip) { if (tip['is_anon_tip']) return; var tipAmount = parseInt(tip['amount'], 10); var displayName = tip['from_user']; var name = displayName.toLowerCase(); var msg = ""; var userData = userHouseData[name]; var oldTier = userData ? userData.currentTier : 0; if (!userData || oldTier === 0) { if (tipAmount >= UNLOCK_MIN) { userHouseData[name] = { totalPoints: tipAmount, currentTier: calculateTier(tipAmount) }; savePersistentData(); // Auto save to KV var info = getTierInfo(userHouseData[name].currentTier); msg = '🎉 ' + displayName + ' tipped ' + tipAmount + ' tokens and officially joined the House Renovation Crew as ' + info.title + '!'; cb.chatNotice(msg, '', botMsgBg, '', 'bold'); } else { cb.chatNotice('Thank you ' + displayName + ' for your tip of ' + tipAmount + ' tokens! Tip ' + UNLOCK_MIN + ' or more in a single tip to join the Renovation Crew.', '', botMsgBg, '', 'bold'); } return; } if (isDoubleOrTriple(tipAmount)) { userData.totalPoints += tipAmount; userData.currentTier = calculateTier(userData.totalPoints); savePersistentData(); // Auto save to KV var tInfo = getTierInfo(userData.currentTier); if (userData.currentTier > oldTier) { msg = '🏗️ LEVEL UP! ' + displayName + ' is now ' + tInfo.title + '! Total: ' + userData.totalPoints + ' tokens. Thank you for helping renovate the house!'; cb.chatNotice(msg, '', botMsgBg, '', 'bold'); } else { msg = '⭐ ' + displayName + ' added ' + tipAmount + ' tokens to the renovation! Total: ' + userData.totalPoints + ' | Next level at ' + nextTarget(userData.currentTier); cb.chatNotice(msg, '', botMsgBg, '', 'bold'); } } else { cb.chatNotice('Thank you ' + displayName + ' for your tip of ' + tipAmount + ' tokens! (Only double/triple digit tips count towards your renovation progress.)', displayName, botMsgBg, '', 'bold'); } }); /* * Chat */ function genderEmote(g) { switch (g) { case 'm': return ':avatar_gen_male'; case 'f': return ':avatar_gen_female'; case 's': return ':avatar_gen_trans'; case 'c': return ':avatar_gen_couple'; default: return ':avatar_gen_unknown'; } } cb.onMessage(function (message) { var rawMsg = message['m'].trim(); var msg = rawMsg.toLowerCase(); var displayName = message['user']; var name = displayName.toLowerCase(); var isModel = (name === modelName.toLowerCase()); var member = userHouseData[name]; var tier = member ? member.currentTier : 0; var isCommand = (msg === '/tipmenu' || msg.indexOf(botTrigger) === 0); if (isCommand) message['X-Spam'] = true; if (!isCommand) { var prefix = genderEmotes ? genderEmote(message['gender']) + ' ' : ''; if (tier > 0) { var info = getTierInfo(tier); if (cb.settings.useBackground === 'Yes') message['background'] = info.color; message['m'] = prefix + info.tag + ' ' + rawMsg; } else if (prefix) { message['m'] = prefix + rawMsg; } return message; } if (msg === '/tipmenu') { cb.chatNotice(getFullTipMenuTextForUser(tier), displayName, botMsgBg, '', 'bold'); return message; } var parts = rawMsg.split(/\s+/); var cmd = parts[1] ? parts[1].toLowerCase() : 'help'; if (cmd === 'help') { var help = "--- Renovation Bot Commands ---\n" + "/tipmenu -> Show rewards menu\n" + botTrigger + " tiers -> Tiers description\n" + botTrigger + " status -> Your points and level"; if (isModel) { help += "\n" + botTrigger + " export -> Backup string of all members" + "\n" + botTrigger + " top -> Top 10 renovators" + "\n" + botTrigger + " add <user> <tokens> -> Add tokens (manual fix)" + "\n" + botTrigger + " set <user> <tokens> -> Set total tokens" + "\n" + botTrigger + " remove <user> -> Remove a member"; } cb.chatNotice(help, displayName, botMsgBg, '', 'bold'); } else if (cmd === 'tiers') { var desc = cb.settings.tiersDescription ? cb.settings.tiersDescription : "No tiers description provided."; cb.chatNotice("--- House Renovation Tiers & Rewards ---\n" + desc, displayName, botMsgBg, '', 'bold'); } else if (cmd === 'status') { var points = member ? member.totalPoints : 0; var sInfo = getTierInfo(tier); var line = "Your Stats -> Points: " + points + " | Rank: " + sInfo.title; if (tier > 0) line += " | Next level at: " + nextTarget(tier); else line += " | Tip " + UNLOCK_MIN + "+ in a single tip to join!"; cb.chatNotice(line, displayName, botMsgBg, '', 'bold'); } else if (isModel && cmd === 'export') { sendBackupToHost(); } else if (isModel && cmd === 'top') { var arr = []; for (var u in userHouseData) { if (userHouseData.hasOwnProperty(u) && userHouseData[u].currentTier > 0) arr.push({ n: u, p: userHouseData[u].totalPoints, t: userHouseData[u].currentTier }); } arr.sort(function (a, b) { return b.p - a.p; }); var out = "--- Top Renovators ---\n"; for (var k = 0; k < Math.min(10, arr.length); k++) { out += (k + 1) + ". " + arr[k].n + " - " + arr[k].p + " (" + getTierInfo(arr[k].t).title + ")\n"; } if (arr.length === 0) out = "No crew members yet."; cb.chatNotice(out, displayName, botMsgBg, '', 'bold'); } else if (isModel && (cmd === 'add' || cmd === 'set') && parts.length >= 4) { var target = parts[2].toLowerCase(); var amount = parseInt(parts[3], 10); if (isNaN(amount) || amount < 0) { cb.chatNotice("Invalid amount.", displayName, botMsgBg, '', 'bold'); } else { if (!userHouseData[target]) userHouseData[target] = { totalPoints: 0, currentTier: 0 }; userHouseData[target].totalPoints = (cmd === 'add') ? userHouseData[target].totalPoints + amount : amount; userHouseData[target].currentTier = calculateTier(userHouseData[target].totalPoints); savePersistentData(); // Auto save to KV cb.chatNotice(target + " is now at " + userHouseData[target].totalPoints + " tokens (" + getTierInfo(userHouseData[target].currentTier).title + ").", displayName, botNoteBg, '', 'bold'); } } else if (isModel && cmd === 'remove' && parts.length >= 3) { var rem = parts[2].toLowerCase(); if (userHouseData[rem]) { delete userHouseData[rem]; savePersistentData(); // Auto save to KV cb.chatNotice(rem + " removed.", displayName, botNoteBg, '', 'bold'); } else { cb.chatNotice("User not found.", displayName, botMsgBg, '', 'bold'); } } return message; }); /* * Enter */ cb.onEnter(function (user) { var displayName = user['user']; var name = displayName.toLowerCase(); if (greetedThisSession[name]) return; greetedThisSession[name] = true; var member = userHouseData[name]; if (userGreets && member && member.currentTier > 0) { var info = getTierInfo(member.currentTier); cb.chatNotice('Welcome back to the room, ' + info.title + ' ' + displayName + '!', '', botMsgBg, '', 'bold'); } cb.chatNotice('\nWelcome to the room! Type /tipmenu to see the rewards menu or ' + botTrigger + ' help for commands. Tip at least ' + UNLOCK_MIN + ' tokens in a single tip to join the House Renovation Crew!\n', displayName, botMsgBg, '', 'bold'); }); /* * Start timers */ scheduleNotice(1); scheduleNotice(2); scheduleNotice(3); displayPeriodicTipMenu(); scheduleBackup(); scheduleStatusNotice(); cb.chatNotice('House Renovation Bot v' + botVersion + ' started with auto KV storage enabled.', '', botMsgBg, '', 'bold');
© Copyright Chaturbate 2011- 2026. All Rights Reserved.