Apps Home
|
Create an App
Xmas Tip Jar
Author:
garterxxx
Description
Source Code
Launch App
Current Users
Created by:
Garterxxx
// Title: Santa's Naughty Tip Jar // Author: Glow XXX // Version: 1.0-Christmas // Description: Festive tip jar with optional draining + simple Christmas commands ππππ₯π¦ // Commands (broadcaster & mods): // /reset // /setjar <amount> // /drainrate <tokens_per_sec> (0 disables) // /startat <amount> (begin draining once jar >= amount) // /topic <text> // /notice <text> var jar = 0; // current tokens in jar (float for fractional drain) var last_user = null; var last_tip = 0; var drainRate = 0.0; // tokens per second var startThreshold = 0; // start draining when jar >= this var draining = false; // drain loop flag var lastTickMs = Date.now(); // last tick timestamp (ms) // ---- Settings UI ---- cb.settings_choices = [ { name: 'tokens', type: 'int', minValue: 1, default: 500, label: 'Christmas Goal (tokens)' }, { name: 'goal_description', type: 'str', minLength: 1, maxLength: 255, label: 'Goal Description', defaultValue: 'Santaβs Naughty List' }, { name: 'drain_rate', type: 'str', minLength: 1, maxLength: 16, label: 'Drain rate tokens/sec (e.g. 0 or 0.5)', defaultValue: '0' }, { name: 'start_at', type: 'int', minValue: 0, default: 0, label: 'Start draining at (tokens in jar)' } ]; // ---- Tip handling ---- cb.onTip(function (tip) { var amt = tip.amount | 0; jar += amt; last_user = tip.from_user || null; last_tip = amt; updateSubject(); ensureTimer(); cb.drawPanel(); // Festive tip notice cb.sendNotice(`ππ ${last_user} sent ${last_tip} tokens to Santaβs Naughty Jar! Keep the elves busy! ππ¦`); }); // ---- Panel (3 rows) ---- cb.onDrawPanel(function () { var goal = cb.settings.tokens | 0; var jarDisplay = Math.max(0, Math.floor(jar)); var drainTxt = (drainRate > 0) ? ('draining ' + drainRate + '/s' + (startThreshold > 0 ? ' (starts at ' + startThreshold + ')' : '')) : 'off'; return { template: '3_rows_of_labels', row1_label: 'π Jar / Goal:', row1_value: (jarDisplay + ' / ' + goal), row2_label: 'βοΈ Drain:', row2_value: drainTxt, row3_label: 'π Latest Tip:', row3_value: ((shortUser(last_user)) + ' (' + last_tip + ' π)') }; }); // ---- Commands (mods & broadcaster) ---- cb.onMessage(function (msg) { var txt = (msg.m || '').trim(); if (!txt || txt[0] !== '/') return msg; var user = msg.user || ''; var isBroadcaster = (user === cb.room_slug); var isMod = !!msg.is_mod; if (!(isBroadcaster || isMod)) { msg['X-Spam'] = true; return msg; } msg['X-Spam'] = true; // consume in chat var parts = txt.substring(1).split(/\s+/); var cmd = parts.shift().toLowerCase(); var arg = parts.join(' '); switch (cmd) { case 'reset': jar = 0; last_user = null; last_tip = 0; cb.sendNotice('π Santaβs Naughty Jar reset. Letβs fill it again! ππ¦', user); break; case 'setjar': { var v = parseFloat(parts[0]); if (isFinite(v) && v >= 0) { jar = v; cb.sendNotice('π Jar set to ' + Math.floor(jar) + ' tokens!', user); } else cb.sendNotice('Usage: /setjar <amount>', user); break; } case 'drainrate': { var r = parseFloat(parts[0]); if (isFinite(r) && r >= 0) { drainRate = r; cb.sendNotice('βοΈ Drain rate ' + drainRate + ' tokens/sec.', user); ensureTimer(); } else cb.sendNotice('Usage: /drainrate <tokens_per_sec> (0 disables)', user); break; } case 'startat': { var s = parseFloat(parts[0]); if (isFinite(s) && s >= 0) { startThreshold = Math.floor(s); cb.sendNotice('π Start draining at ' + startThreshold + ' tokens.', user); ensureTimer(); } else cb.sendNotice('Usage: /startat <amount>', user); break; } case 'topic': if (arg.length) cb.changeRoomSubject(arg); else cb.sendNotice('Usage: /topic <text>', user); break; case 'notice': if (arg.length) cb.sendNotice(arg); else cb.sendNotice('Usage: /notice <text>', user); break; default: cb.sendNotice('Unknown command: /' + cmd, user); } updateSubject(); cb.drawPanel(); return msg; }); // ---- Drain loop ---- function ensureTimer() { var shouldDrain = (drainRate > 0) && (jar > 0) && (jar >= startThreshold); if (shouldDrain && !draining) { draining = true; lastTickMs = Date.now(); tick(); } else if (!shouldDrain && draining) { draining = false; } } function tick() { if (!draining) return; var now = Date.now(); var dt = Math.max(0, (now - lastTickMs) / 1000); // seconds lastTickMs = now; jar -= drainRate * dt; if (jar < 0) jar = 0; if (jar === 0 || jar < startThreshold || drainRate <= 0) draining = false; updateSubject(); cb.drawPanel(); if (draining) cb.setTimeout(tick, 1000); } // ---- Subject line ---- function updateSubject() { var remaining = Math.max(0, (cb.settings.tokens | 0) - Math.floor(jar)); cb.changeRoomSubject(`π ${cb.settings.goal_description} [${remaining} tokens remaining] ππ¦`); } // ---- Utils ---- function shortUser(u) { return u ? String(u).substring(0, 12) : '--'; } // ---- Init ---- (function init() { drainRate = parseFloat(cb.settings.drain_rate || '0') || 0; startThreshold = Math.max(0, (cb.settings.start_at | 0)); updateSubject(); ensureTimer(); cb.drawPanel(); })();
© Copyright Chaturbate 2011- 2026. All Rights Reserved.