Apps Home
|
Create an App
Ultimate Tip Menu
Author:
test123908910
Description
Source Code
Launch App
Current Users
Created by:
Test123908910
/* * ============================================================ * Ultimate Tip Menu App v1.0 * A full-featured tip menu application for Chaturbate * * Features: * - Configurable tip menu with up to 5 items * - Color-themed notices (Pink, Blue, Green, Orange) * - Top tipper tracking and goal progress * - Auto-rotating menu reminders * - Tip option presets for quick tipping * - /menu, /tipmenu, /help chat commands * - Welcome messages on room enter * - Dynamic panel with live stats * * Mode: App (uses panel, subject, tipOptions) * ============================================================ */ // ── Settings ───────────────────────────────────────────────── cb.settings_choices = [ { name: 'subject_prefix', type: 'str', label: 'Room Subject Prefix', defaultValue: 'Tip Menu Active!', maxLength: 100 }, { name: 'notice_color', type: 'choice', label: 'Notice Theme', choice1: 'Pink', choice2: 'Blue', choice3: 'Green', choice4: 'Orange', defaultValue: 'Pink' }, { name: 'welcome_message', type: 'str', label: 'Welcome Message (use {user} for username)', defaultValue: 'Welcome {user}! Type /menu to see the tip menu!', maxLength: 200 }, { name: 'show_menu_on_enter', type: 'choice', label: 'Show Menu on Enter', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes' }, { name: 'reminder_interval', type: 'int', label: 'Menu Reminder Interval (seconds, 0=off)', minValue: 0, maxValue: 600, defaultValue: 120 }, { name: 'goal_amount', type: 'int', label: 'Tip Goal Amount (0=no goal)', minValue: 0, maxValue: 99999, defaultValue: 500 }, { name: 'goal_description', type: 'str', label: 'Goal Description', defaultValue: 'Special Show', maxLength: 100 }, { name: 'fanclub_emoji', type: 'str', label: 'Fan Club Message Prefix Emoji', defaultValue: ':heart2', maxLength: 20 } ]; // Dynamically generate 5 menu item settings for (var i = 1; i <= 5; i++) { cb.settings_choices.push( { name: 'item' + i + '_name', type: 'str', label: 'Menu Item ' + i + ' Name', defaultValue: (i === 1 ? 'Flash' : i === 2 ? 'Song Request' : i === 3 ? 'PM' : i === 4 ? 'Outfit Change' : 'Custom Show'), maxLength: 50, required: false }, { name: 'item' + i + '_amount', type: 'int', label: 'Menu Item ' + i + ' Amount', defaultValue: (i === 1 ? 25 : i === 2 ? 15 : i === 3 ? 50 : i === 4 ? 75 : 100), minValue: 1, maxValue: 9999, required: false } ); } // ── Color Themes ───────────────────────────────────────────── var THEMES = { 'Pink': { bg: '#FFD1DC', fg: '#8B0000' }, 'Blue': { bg: '#D1E7FF', fg: '#003366' }, 'Green': { bg: '#D1FFD1', fg: '#006600' }, 'Orange': { bg: '#FFE0CC', fg: '#CC4400' } }; // ── State Variables ────────────────────────────────────────── var totalTips = 0; var topTipper = ''; var topTipperAmount = 0; var menuItems = []; var reminderTimerId = null; var recentTippers = []; var knownUsers = []; // ── Helper Functions ───────────────────────────────────────── /** * Get the current color theme background and foreground. */ function getTheme() { var themeName = cb.settings.notice_color || 'Pink'; return THEMES[themeName] || THEMES['Pink']; } /** * Build the menu items array from settings. * Filters out items with empty names. */ function buildMenuItems() { var items = []; for (var i = 1; i <= 5; i++) { var name = cb.settings['item' + i + '_name'] || ''; var amount = parseInt(cb.settings['item' + i + '_amount']) || 0; if (name && amount > 0) { items.push({ name: name, amount: amount }); } } return items; } /** * Format the tip menu as a multi-line string for display. */ function formatMenu() { if (menuItems.length === 0) { return '--- No menu items configured ---'; } var lines = []; lines.push(':tipmenu Tip Menu :tipmenu'); lines.push('================================'); for (var i = 0; i < menuItems.length; i++) { var item = menuItems[i]; lines.push(item.name + ' ..... ' + item.amount + ' tokens'); } lines.push('================================'); lines.push('[cb:tip] Click amounts above or use the tip button!'); var goalAmount = parseInt(cb.settings.goal_amount) || 0; if (goalAmount > 0) { var remaining = goalAmount - totalTips; if (remaining > 0) { lines.push('Goal: ' + cb.settings.goal_description + ' (' + totalTips + '/' + goalAmount + ' tokens)'); } else { lines.push('Goal REACHED! ' + cb.settings.goal_description); } } return lines.join('\n'); } /** * Send a themed notice to the room or a specific user. * Uses all 6 positional parameters of cb.sendNotice. * * @param {string} message - notice text * @param {string} toUser - specific user or '' for all * @param {string} toGroup - group filter or '' for all * @param {string} weight - 'bold', 'normal', or '' */ function sendThemedNotice(message, toUser, toGroup, weight) { var theme = getTheme(); cb.sendNotice( message, toUser || '', theme.bg, theme.fg, weight || 'bold', toGroup || '' ); } /** * Find a menu item that matches a tip amount. * Returns the item object or null. */ function findMenuItemByAmount(amount) { for (var i = 0; i < menuItems.length; i++) { if (menuItems[i].amount === amount) { return menuItems[i]; } } return null; } /** * Update the room subject with goal progress. */ function updateSubject() { var prefix = cb.settings.subject_prefix || 'Tip Menu'; var subject = prefix; var goalAmount = parseInt(cb.settings.goal_amount) || 0; if (goalAmount > 0) { var remaining = goalAmount - totalTips; if (remaining > 0) { subject += ' | Goal: ' + cb.settings.goal_description + ' [' + totalTips + '/' + goalAmount + ']'; } else { subject += ' | GOAL REACHED: ' + cb.settings.goal_description + '!'; } } if (topTipper) { subject += ' | King: ' + topTipper + ' (' + topTipperAmount + ')'; } cb.changeRoomSubject(subject); } // ── Menu Reminder Timer ────────────────────────────────────── /** * Start (or restart) the rotating menu reminder timer. * Cancels any existing timer before setting a new one. */ function startReminderTimer() { // Cancel previous timer if it exists if (reminderTimerId !== null) { cb.cancelTimeout(reminderTimerId); reminderTimerId = null; cb.log('Cancelled previous reminder timer'); } var intervalSec = parseInt(cb.settings.reminder_interval) || 0; if (intervalSec <= 0) { cb.log('Menu reminders disabled (interval=0)'); return; } var intervalMs = intervalSec * 1000; function postReminder() { var theme = getTheme(); cb.sendNotice( formatMenu(), '', theme.bg, theme.fg, 'bold', '' ); cb.log('Posted periodic menu reminder'); // Schedule next reminder reminderTimerId = cb.setTimeout(postReminder, intervalMs); } // Schedule the first reminder reminderTimerId = cb.setTimeout(postReminder, intervalMs); cb.log('Menu reminder timer started: every ' + intervalSec + 's'); } // ── Event Handlers ─────────────────────────────────────────── /** * Handle incoming tips. * - Match against menu items * - Track top tipper * - Update panel and subject */ cb.onTip(function (tip) { var amount = parseInt(tip.amount); var tipper = tip.from_user; var isAnon = (tip.from_user === 'anonymous'); cb.log('Tip received: ' + amount + ' from ' + tipper); // Update running total totalTips += amount; // Track recent tippers using cbjs.arrayContains if (!cbjs.arrayContains(recentTippers, tipper)) { recentTippers.push(tipper); // Keep the list manageable — only last 50 if (recentTippers.length > 50) { recentTippers = recentTippers.slice(-50); } } // Update top tipper if (amount > topTipperAmount) { // If previous top tipper is being dethroned, remove from known list // (demonstrating cbjs.arrayRemove) if (topTipper && topTipper !== tipper) { knownUsers = cbjs.arrayRemove(knownUsers, topTipper); } topTipper = isAnon ? 'Anonymous' : tipper; topTipperAmount = amount; // Add new top tipper to known users if (!isAnon && !cbjs.arrayContains(knownUsers, tipper)) { knownUsers.push(tipper); } } // Check if the tip matches a menu item var matchedItem = findMenuItemByAmount(amount); if (matchedItem) { // Send a styled announcement for the matched menu item var theme = getTheme(); var announcement = ':party1 ' + tipper + ' tipped ' + amount + ' tokens for ' + matchedItem.name + '! :party1'; cb.sendNotice( announcement, '', theme.bg, theme.fg, 'bold', '' ); // Also send a private confirmation to the tipper cb.sendNotice( 'Thank you! Your "' + matchedItem.name + '" request has been received!', tipper, theme.bg, theme.fg, 'normal', '' ); } else { // Generic tip thank you var thankMsg = 'Thank you ' + tipper + ' for the ' + amount + ' token tip!'; sendThemedNotice(thankMsg, '', '', 'normal'); } // Update the room subject with goal progress updateSubject(); // Redraw the panel for all users cb.drawPanel(); }); /** * Handle chat messages. * - Process /menu, /tipmenu, /help commands * - Add emoji prefix for fan club members * - Return the (possibly modified) message object */ cb.onMessage(function (msg) { var text = msg.m || ''; var user = msg.user || ''; var isFC = msg.in_fanclub; var isBroadcaster = (msg.user === cb.room_slug); // Check for commands (commands start with /) var lowerText = text.toLowerCase().replace(/^\s+/, ''); if (lowerText === '/menu' || lowerText === '/tipmenu') { // Show the tip menu to the requesting user only var theme = getTheme(); cb.sendNotice( formatMenu(), user, theme.bg, theme.fg, 'bold', '' ); // Hide the command from chat msg['X-Spam'] = true; return msg; } if (lowerText === '/help') { var helpText = [ '--- Tip Menu Help ---', '/menu or /tipmenu - View the tip menu', '/help - Show this help message', '', 'Tip the exact amount listed next to a menu item to request it!', 'Your tips are tracked and the top tipper is displayed on the panel.' ].join('\n'); cb.sendNotice( helpText, user, '#EEEEEE', '#333333', 'normal', '' ); // Hide the command from chat msg['X-Spam'] = true; return msg; } // Add fan club emoji prefix to messages if (isFC && cb.settings.fanclub_emoji) { msg.m = cb.settings.fanclub_emoji + ' ' + msg.m; } return msg; }); /** * Handle user entering the room. * - Send a personalized welcome notice * - Optionally show the tip menu */ cb.onEnter(function (user) { var username = user.user || ''; cb.log('User entered: ' + username); // Build the welcome message, replacing {user} placeholder var welcomeMsg = cb.settings.welcome_message || 'Welcome {user}!'; welcomeMsg = welcomeMsg.replace(/\{user\}/g, username); // Send welcome notice to the entering user only var theme = getTheme(); cb.sendNotice( welcomeMsg, username, theme.bg, theme.fg, 'normal', '' ); // Optionally show the menu on enter if (cb.settings.show_menu_on_enter === 'Yes') { cb.sendNotice( formatMenu(), username, theme.bg, theme.fg, 'bold', '' ); } }); /** * Draw the app info panel. * Uses the 3_rows_of_labels template. * * Row 1: Top Tipper / name * Row 2: Total Tips / running total * Row 3: Menu Items / count */ cb.onDrawPanel(function (user) { var topDisplay = topTipper ? (topTipper + ' (' + topTipperAmount + ')') : '---'; var totalDisplay = '' + totalTips; var itemCountDisplay = '' + menuItems.length + ' items'; var goalAmount = parseInt(cb.settings.goal_amount) || 0; if (goalAmount > 0) { var pct = Math.min(100, Math.floor((totalTips / goalAmount) * 100)); totalDisplay += ' / ' + goalAmount + ' (' + pct + '%)'; } return { template: '3_rows_of_labels', row1_label: 'Top Tipper', row1_value: topDisplay, row2_label: 'Total Tips', row2_value: totalDisplay, row3_label: 'Menu Items', row3_value: itemCountDisplay }; }); /** * Provide tip option presets matching the menu items. * This populates the quick-tip dropdown/buttons. */ cb.tipOptions(function () { var options = []; for (var i = 0; i < menuItems.length; i++) { options.push({ label: menuItems[i].name + ' (' + menuItems[i].amount + ')', amount: menuItems[i].amount }); } return { options: options }; }); // ── Initialization ─────────────────────────────────────────── function init() { cb.log('Initializing Ultimate Tip Menu App v1.0'); cb.log('Theme: ' + (cb.settings.notice_color || 'Pink')); // Build menu items from settings menuItems = buildMenuItems(); cb.log('Menu items loaded: ' + menuItems.length); for (var i = 0; i < menuItems.length; i++) { cb.log(' ' + menuItems[i].name + ': ' + menuItems[i].amount + ' tokens'); } // Set the initial room subject updateSubject(); // Draw the initial panel cb.drawPanel(); // Start the reminder timer startReminderTimer(); // Send startup notice to the room sendThemedNotice( ':star2 Tip Menu is now active! Type /menu to see available items. :star2', '', '', 'bold' ); cb.log('Initialization complete'); } init();
© Copyright Chaturbate 2011- 2026. All Rights Reserved.