Apps Home
|
Create an App
TMG_Test
Author:
mx2k6
Description
Source Code
Launch App
Current Users
Created by:
Mx2k6
/* Name: Tip Multi-Goal Author: mx2k6 Last Modified: 2017-01-03 23:45:00+13:00 For support enquiries, contact c9max69@gmail.com The moral right of "mx2k6" to be identified as the author of this work has been asserted. Version History ============================================================================================ v2.00 2017-01-03 Initial Release - see app source history for v1.x notes */ if (cb == null) { var cb = { changeRoomSubject: function (new_subject) { }, drawPanel: function () { }, log: function (message) { }, onDrawPanel: function (func) { }, onEnter: function (func) { }, onLeave: function (func) { }, onMessage: function (func) { }, onTip: function (func) { }, room_slug: '', sendNotice: function (message, to_user, background, foreground, weight, to_group) { }, setTimeout: function (func, msec) { }, settings_choices: [], settings: {}, tipOptions: function (func) { }, limitCam_start: function (message, allowed_users) { }, limitCam_stop: function () { }, limitCam_addUsers: function (allowed_users) { }, limitCam_removeUsers: function (removed_users) { }, limitCam_removeAllUsers: function () { }, limitCam_userHasAccess: function (user) { }, limitCam_allUsersWithAccess: function () { }, limitCam_isRunning: function () { }, }; } String.format = function () { var newString = String(arguments[0]); for (var idx = 1; idx < arguments.length; idx++) { newString = newString.replace(new RegExp("\\{" + (idx - 1) + "\\}", "g"), arguments[idx]); } return String(newString); }; String.prototype.format = function () { var newString = String(this); for (var idx = 0; idx < arguments.length; idx++) { newString = newString.replace(new RegExp("\\{" + (idx - 1) + "\\}", "g"), arguments[idx]); } return String(newString); }; String.Empty = ''; Math.isRoundNumber = function (x) { return (x * 10 == (Math.round(x) * 10)); } function isUndefined(test) { return (test == undefined || test == "" || test == 0); } function parseBool(val) { return ((typeof (val) === 'string' && val === 'Yes') || (typeof (val) === 'boolean' && val)); } var Application = { Title: "Tip Multi-Goal", // The name of the application Version: { // The current version of the application Major: 2, Minor: 0, Revision: 0 }, Hyperlink: 'http://chaturbate.com/apps/app_details/tip-multi-goal/', // The URL for more information Author: { // The author of this version. Don't change this unless you modified something! Name: 'mx2k6', Email: 'c9max69@gmail.com' }, Originator: { // The original author, I.E. me. If you change this, you're a cunt. It's not like it gets displayed anywhere Name: 'mx2k6', Email: 'c9max69@gmail.com' }, Debug: true, // Whether the application is in debug (verbose) mode. Don't change this in prod, or you're a retard StartupTime: 'never', // The time the application started up. Don't set this, it gets set at runtime ExpectedAppId: 445, // The ID of the application in the App List. DO NOT CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING Constants: { Language: 'en-GB', // The language to use Goals: 8, // The number of goals to permit configuration of in the startup settings window - add a UserConstant below to override per user DefaultColourScheme: 'Legacy', // The default colour scheme when something goes tips up and it doesn't parse, or when settings are nuked Shebang: '/' // The character to use to denote a command as opposed to random text }, UserConstants: { "mx2k6": { Goals: 3 } }, applyUserConstants: function (user) { if (this.UserConstants[user] != undefined) { this.Constants['UserConstants'] = this.UserConstants[user]; for (var property in this.UserConstants[user]) { this.Constants[property] = this.UserConstants[user][property]; } }; }, launchCheck: function () { if (Application.Debug && (Application.Author.Name !== Room.getOwner())) { Messaging.sendErrorMessage(Resources.getString('err_debug_in_production'), Room.getOwner(), null); return false; } if (typeof (cb.app_id) === 'string' || typeof (cb.app_id) === 'number') { if (parseInt(cb.app_id) !== Application.ExpectedAppId) { Messaging.sendErrorMessage(Resources.getString('err_unexpected_app_id')); return false; } } return true; }, wireup: function () { cb.onMessage(function (message) { if (message.m.startsWith(Application.Constants.Shebang)) { var command = message.m.split(' '); var user = User.parseFromMessage(message); if (CommandProcessor.processCommand(user, command[0].substring(1), command.splice(1))) { message['X-Spam'] = true; } } }); cb.onTip(function (tip) { var user = User.parseFromTip(tip); Tracker.processTip(user, tip.amount, false); }); cb.onEnter(function (entering) { Application.announce(entering.user); }); cb.onDrawPanel(function (user) { return Tracker.getPanel(); }); }, announce: function (user) { Messaging.sendGenericMessage(String.format(Resources.getString('app_announce'), this.Title, this.Version.toString(), Tracker.getCurrentGoal().getSubject(), Tracker.getCurrentGoal().getRemaining()), Colours.DarkSlateBlue, null, user, null); }, initialise: function () { Configuration.parseConfiguration(cb.settings); this.StartupTime = new Date(); this.announce(); return true; }, }; Application.Version.toString = function () { return String.format("{0}.{1}.{2}", this.Major, this.Minor, this.Revision); } var AccessLevels = { AlwaysDeveloper: 0, Developer: 1, AlwaysBroadcaster: 2, Broadcaster: 3, Moderator: 4, Tipper: 5, TokenHolder: 6, Everyone: 7 }; var Chronometer = { Timers: [], onElapsed: function () { var now = new Date(); now.setMilliseconds(0); for (var timerId in TimerManager.Timers) { if (!(TimerManager.Timers[timerId] instanceof Timer)) { delete TimerManager.Timers[timerId]; continue; } else { var timer = TimerManager.Timers[timerId]; if (now <= timer.getDeadline() && now >= timer.getDeadline()) { timer.onElapsed(); delete TimerManager.Timers[timerId]; break; } } } cb.setTimeout(TimerManager.onElapsed, 1000); }, addTimer: function (id, timer) { if (!(timer instanceof Timer)) return false; TimerManager.Timers[id] = timer; return true; }, removeTimer: function (id) { if (isUndefined(TimerManager.Timers[id])) return true; delete TimerManager.Timers[id]; if (isUndefined(TimerManager.Timers[id])) return true; return false }, initialise: function () { cb.setTimeout(TimerManager.onElapsed, 1000); }, }; function Timer(elapsed, seconds) { var now = new Date(); now.setSeconds(seconds); now.setMilliseconds(0); this.deadline = now; this.onElapsed = elapsed; } Timer.prototype.getDeadline = function () { return this.deadline; }; var Room = { _subject: '', getOwner: function () { return cb.room_slug; }, isOwner: function (user) { return cb.room_slug == user; }, setSubject: function (subject) { this._subject = subject; cb.changeRoomSubject(subject); }, getSubject: function () { return this._subject; }, // Only returns the subject if set with Room.setSubject, as there is no API to get room subject. Sucks yo checkAccessLevel: function (user, level) { switch (level) { case AccessLevels.AlwaysDeveloper: return (Application.Author.Name === user.getName() || Application.Originator.Name === user.getName()); break; case AccessLevels.Developer: return ((Application.Author.Name === user.getName() || Application.Originator.Name === user.getName()) && Configuration.SupportMode); break; case AccessLevels.AlwaysBroadcaster: return this.isOwner(user.getName()); break; case AccessLevels.Broadcaster: return (this.isOwner(user.getName() || (Configuration.AllowModSuperusers && user.getGroups().indexOf(Groups.Moderators) > -1))); break; case AccessLevels.Moderator: return (this.isOwner(user.getName() || user.getGroups().indexOf(Groups.Moderators) > -1)); break; case AccessLevels.Tipper: return ((this.isOwner(user.getName() || user.getGroups().indexOf(Groups.Moderators) > -1)) || Tracker.hasTippedMe(user.getName())); break; case AccessLevels.TokenHolder: return ((this.isOwner(user.getName() || user.getGroups().indexOf(Groups.Moderators) > -1)) || user.getGroups().indexOf(Groups.TokenHolders) > -1); break; case AccessLevels.Everyone: return true; break; } return false; }, getAccessLevel: function (user) { if ((Application.Author.Name === user.getName() || Application.Originator.Name === user.getName()) && Configuration.SupportMode) return AccessLevels.Developer; if (Application.Author.Name === user.getName() || Application.Originator.Name === user.getName()) return AccessLevels.AlwaysDeveloper; if (this.isOwner(user.getName())) return AccessLevels.AlwaysBroadcaster; if (Configuration.AllowModSuperusers && user.getGroups().indexOf(Groups.Moderators) > -1) return AccessLevels.Broadcaster; if (user.getGroups().indexOf(Groups.Moderators) > -1) return AccessLevels.Moderator; if (Tracker.hasTippedMe(user.getName())) return AccessLevels.Tipper; if (user.getGroups().indexOf(Groups.TokenHolders) > -1) return AccessLevels.TokenHolder; return AccessLevels.Everyone; }, }; var Colours = { AliceBlue: "#F0F8FF", AntiqueWhite: "#FAEBD7", Aqua: "#00FFFF", Aquamarine: "#7FFFD4", Azure: "#F0FFFF", Beige: "#F5F5DC", Bisque: "#FFE4C4", Black: "#000000", BlanchedAlmond: "#FFEBCD", Blue: "#0000FF", BlueViolet: "#8A2BE2", Brown: "#A52A2A", BurlyWood: "#DEB887", CadetBlue: "#5F9EA0", Chartreuse: "#7FFF00", Chocolate: "#D2691E", Coral: "#FF7F50", CornflowerBlue: "#6495ED", Cornsilk: "#FFF8DC", Crimson: "#DC143C", Cyan: "#00FFFF", DarkBlue: "#00008B", DarkCyan: "#008B8B", DarkGoldenRod: "#B8860B", DarkGrey: "#A9A9A9", DarkGreen: "#006400", DarkKhaki: "#BDB76B", DarkMagenta: "#8B008B", DarkOliveGreen: "#556B2F", DarkOrange: "#FF8C00", DarkOrchid: "#9932CC", DarkRed: "#8B0000", DarkSalmon: "#E9967A", DarkSeaGreen: "#8FBC8F", DarkSlateBlue: "#483D8B", DarkSlateGrey: "#2F4F4F", DarkTurquoise: "#00CED1", DarkViolet: "#9400D3", DeepPink: "#FF1493", DeepSkyBlue: "#00BFFF", DimGrey: "#696969", DodgerBlue: "#1E90FF", FireBrick: "#B22222", FloralWhite: "#FFFAF0", ForestGreen: "#228B22", Fuschia: "#FF00FF", Gainsboro: "#DCDCDC", GhostWhite: "#F8F8FF", Gold: "#FFD700", GoldenRod: "#DAA520", Grey: "#808080", Green: "#008000", GreenYellow: "#ADFF2F", HoneyDew: "#F0FFF0", HotPink: "#FF69B4", IndianRed: "#CD5C5C", Indigo: "#4B0082", Ivory: "#FFFFF0", Khaki: "#F0E68C", Lavender: "#E6E6FA", LavenderBlush: "#FFF0F5", LawnGreen: "#7CFC00", LemonChiffon: "#FFFACD", LightBlue: "#ADD8E6", LightCoral: "#F08080", LightCyan: "#E0FFFF", LightGoldenRodYellow: "#FAFAD2", LightGrey: "#D3D3D3", LightGreen: "#90EE90", LightPink: "#FFB6C1", LightSalmon: "#FFA07A", LightSeaGreen: "#20B2AA", LightSkyBlue: "#87CEFA", LightSlateGrey: "#778899", LightSteelBlue: "#B0C4DE", LightYellow: "#FFFFE0", Lime: "#00FF00", LimeGreen: "#32CD32", Linen: "#FAF0E6", Magenta: "#FF00FF", Maroon: "#800000", MediumAquaMarine: "#66CDAA", MediumBlue: "#0000CD", MediumOrchid: "#BA55D3", MediumPurple: "#9370DB", MediumSeaGreen: "#3CB371", MediumSlateBlue: "#7B68EE", MediumSpringGreen: "#00FA9A", MediumTurquoise: "#48D1CC", MediumVioletRed: "#C71585", MidnightBlue: "#191970", MintCream: "#F5FFFA", MistyRose: "#FFE4E1", Moccasin: "#FFE4B5", NavajoWhite: "#FFDEAD", Navy: "#000080", OldLace: "#FDF5E6", Olive: "#808000", OliveDrab: "#6B8E23", Orange: "#FFA500", OrangeRed: "#FF4500", Orchid: "#DA70D6", PaleGoldenRod: "#EEE8AA", PaleGreen: "#98FB98", PaleTurquoise: "#AFEEEE", PaleVioletRed: "#DB7093", PapayaWhip: "#FFEFD5", PeachPuff: "#FFDAB9", Peru: "#CD853F", Pink: "#FFC0CB", Plum: "#DDA0DD", PowderBlue: "#B0E0E6", Purple: "#800080", Red: "#FF0000", RosyBrown: "#BC8F8F", RoyalBlue: "#4169E1", SaddleBrown: "#8B4513", Salmon: "#FA8072", SandyBrown: "#F4A460", SeaGreen: "#2E8B57", SeaShell: "#FFF5EE", Sienna: "#A0522D", Silver: "#C0C0C0", SkyBlue: "#87CEEB", SlateBlue: "#6A5ACD", SlateGrey: "#708090", Snow: "#FFFAFA", SpringGreen: "#00FF7F", SteelBlue: "#4682B4", Tan: "#D2B48C", Teal: "#008080", Thistle: "#D8BFD8", Tomato: "#FF6347", Turquoise: "#40E0D0", Violet: "#EE82EE", Wheat: "#F5DEB3", White: "#FFFFFF", WhiteSmoke: "#F5F5F5", Yellow: "#FFFF00", YellowGreen: "#9ACD32" }; var Groups = { TokenHolders: 'lightblue', Tippers: 'darkblue', BigTippers: 'lightpurple', MassiveTippers: 'darkpurple', Fans: 'green', Moderators: 'red', }; var Resources = { Strings: { 'en-GB': { 'colour_scheme_none': 'None', 'colour_scheme_random': 'Rainbow', 'err_unexpected_app_id': 'The application running appears to be a clone of the original. Please deactivate and search "Tip Multi-Goal" to use this application', 'goal_action_loop': 'Loop last goal', 'goal_action_hidden': 'Start hidden show', 'goal_action_thanks': 'Show thanks message', 'announce_goal_met': 'Goal Met: {0}', 'subject_text': '{0} [{1} tokens left] {2}', 'command_unknown': 'Hey idiot, that command is unknown and you are in debug mode', 'err_access_denied': 'You do not have access to use the {0} command', 'bullet': unescape('%u25C6'), 'app_announce': '{0} v{1} is running! The current goal is {2} with {3} tokens to go', 'err_debug_in_production': 'This application is a DEVELOPMENT version and not intended to be used by the general public. Please use the release version!', 'stats_total': 'Total Tipped', 'heading_help': '{0} Help', 'heading_stats': 'Statistics', 'goal_timer_ended': 'Time is up! The goal was not met in time', 'panel_total_received': 'Total Received:', 'panel_highest': 'Highest Tip:', 'panel_most_recent': 'Last Tip:', 'panel_goal_received_no_total': 'Goal Received:', 'panel_goal_received': 'Goal Received (Total):', 'goal_timer_minsleft': '{0}m', 'noone': '--', }, }, getString: function (stringName) { return (this.Strings[Application.Constants.Language][stringName] != null ? this.Strings[Application.Constants.Language][stringName] : 'resource_string_missing'); }, }; var ColourSchemes = { _activeScheme: null, SchemeList: [ { Name: Resources.getString('colour_scheme_none') }, { Name: 'Legacy', BigSingleTipper: '#9F9', BigTotalTipper: '#CCF' }, { Name: 'Amethyst', BigSingleTipper: Colours.Orchid, BigTotalTipper: Colours.MediumSlateBlue }, { Name: 'Forest', BigSingleTipper: Colours.SpringGreen, BigTotalTipper: Colours.LimeGreen }, { Name: 'Sky', BigSingleTipper: Colours.LightSkyBlue, BigTotalTipper: Colours.SkyBlue }, { Name: 'Sunshine', BigSingleTipper: Colours.Yellow, BigTotalTipper: Colours.Gold }, { Name: Resources.getString('colour_scheme_random') } ], populateChoices: function (setting) { for (var i = 1; i <= this.SchemeList.length; i++) { if (this.SchemeList[i - 1] != null) { setting['choice' + i] = this.SchemeList[i - 1].Name; } } setting['defaultValue'] = Application.Constants.DefaultColourScheme; return setting; }, setActiveScheme: function (schemeName) { for (var scheme in this.SchemeList) { if (schemeName == scheme.Name) { this._activeScheme = scheme; } } }, getActiveScheme: function () { if (this._activeScheme.Name == Resources.getString('colour_scheme_random')) { // Select a random colour scheme return this.SchemeList[Math.floor(Math.random() * (this.SchemeList.length-2))]; } else if (this._activeScheme.Name == Resources.getString('colour_scheme_none')) { return null; } return this._activeScheme; }, }; var Messaging = { sendDebugMessage: function (message) { if (Application.Debug) { if (Room.getOwner() !== Application.Author.Name) this.sendGenericMessage(message, Colours.DarkGrey, null, Application.Author.Name); this.sendGenericMessage(message, Colours.DarkGrey, null, Room.getOwner()); cb.log(message); } }, sendModeratorNotice: function (str) { this.sendGenericMessage(str, Colours.Blue, null, Room.getOwner(), Groups.Moderators); }, sendErrorMessage: function (str, recipient, group) { this.sendGenericMessage(str, Colours.Red, null, recipient, group); }, sendWarningMessage: function (str, recipient, group) { this.sendGenericMessage(str, Colours.Orange, null, recipient, group); }, sendSuccessMessage: function (str, recipient, group) { this.sendGenericMessage(str, Colours.DarkGreen, null, recipient, group); }, sendInfoMessage: function (str, recipient, group) { this.sendGenericMessage(str, Colours.Black, null, recipient, group); }, sendGenericMessage: function (str, colour, background, recipient, group) { if (!isUndefined(recipient) && !isUndefined(group)) { cb.sendNotice(str, null, background, colour, 'bold', group); cb.sendNotice(str, recipient, background, colour, 'bold', null); } if (!isUndefined(recipient) && isUndefined(group)) cb.sendNotice(str, recipient, background, colour, 'bold', null); if (isUndefined(recipient) && !isUndefined(group)) cb.sendNotice(str, null, background, colour, 'bold', group); if (isUndefined(recipient) && isUndefined(group)) cb.sendNotice(str, null, background, colour, 'bold', null); }, }; var Configuration = { // Gets the configuration screen for rendering by the Django forms monstrosity, which is only slightly less monstrous than this app's code getSetupScreen: function () { var goalSettings = []; for (var gSetting = 1; gSetting <= Application.Constants.Goals; gSetting++) { goalSettings.push({ name: 'goal_' + gSetting + '_tokens', label: 'Goal ' + gSetting + ' Token Amount', type: 'int', minValue: 1, defaultValue: 200, required: (gSetting === 1) }); goalSettings.push({ name: 'goal_' + gSetting + '_description', label: 'Goal ' + gSetting + ' Description', type: 'str', minLength: (gSetting === 1 ? 1 : 0), maxLength: 255, required: (gSetting === 1) }); } var colourSchemeSetting = ColourSchemes.populateChoices({ name: 'tipper_colour_scheme', label: 'Tipper Highlight Colour Scheme', type: 'choice' }); var choices = [ { name: 'action_on_finality', label: 'After last goal', type: 'choice', choice1: Resources.getString('goal_action_thanks'), choice2: Resources.getString('goal_action_loop'), choice3: Resources.getString('goal_action_hidden'), defaultValue: Resources.getString('goal_action_thanks') }, { name: 'hidden_preshow_entry_fee', label: 'Tokens to enter hidden show before starting (if selected)', type: 'int', defaultValue: 1, required: true }, { name: 'hidden_show_entry_fee', label: 'Tokens to enter hidden show after starting (if selected)', type: 'int', defaultValue: 50, required: true }, { name: 'finality_message', label: 'Final Goal Met Subject', type: 'str', minLength: 1, maxLength: 255, defaultValue: 'Goal reached! Thanks to all tippers!' }, { name: 'auto_progress_goals', label: 'Automatically progress goals (if no, will require you to approve moving to next goal)', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'Yes' }, colourSchemeSetting, // This is prefilled with the available colour schemes, dynamically created by the ColourSchemes pseudo-class { name: 'mod_allow_broadcaster_cmd', label: 'Allow mods to use broadcaster commands?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No' }, { name: 'hide_token_haul', label: 'Hide your total token haul?', type: 'choice', choice1: 'Yes', choice2: 'No', defaultValue: 'No' }, { name: 'yellow_wall_threshold', label: 'Yellow wall threshold (this or lower is yellow wall and will not change subject - 0 to disable)', type: 'int', defaultValue: 0, required: true }, { name: 'subject_suffix', label: 'Hashtags (appended after the goal and token counter to the room subject)', type: 'str', required: false }, ]; return choices.concat(goalSettings); }, parseConfiguration: function (settings) { this.HiddenShow.EntryFee = parseInt(settings['hidden_show_entry_fee']); this.HiddenShow.PreorderFee = parseInt(settings['hidden_preshow_entry_fee']); this.ColourScheme = settings['tipper_colour_scheme']; this.HideTokensInSubject = parseBool(settings['hide_token_haul']); this.PinnacleMessage = settings['finality_message']; this.SubjectSuffix = settings['subject_suffix']; this.PinnacleAction = settings['action_on_finality']; this.ManualProgression = !parseBool(settings['auto_progress_goals']); this.AllowModSuperusers = parseBool(settings['mod_allow_broadcaster_cmd']); this.YellowWallThreshold = parseInt(settings['yellow_wall_threshold']); this.SupportMode = false; var last_goal = null; for (var goal_id = 1; goal_id <= Application.Constants.Goals; goal_id++) { if (settings['goal_' + goal_id + '_tokens'] != undefined) { // Goal exists in array, add it to the tracker var goal_tokens = parseInt(settings['goal_' + goal_id + '_tokens']); var goal_subject = settings['goal_' + goal_id + '_description']; if (goal_subject == '') continue; var this_goal = new Goal(goal_tokens, goal_subject, last_goal, null); if (last_goal != null) { last_goal.setNext(this_goal); } this_goal.onGoalMet = function (goal, remaining) { Tracker.onGoalMet(goal, remaining) }; this_goal.onGoalUnmet = function (goal, remaining) { Tracker.onGoalUnmet(goal, remaining) }; this_goal.onPinnacle = function () { Tracker.onPinnacle() }; Tracker.addGoal(this_goal); last_goal = this_goal; } }; }, HiddenShow: { Enabled: true, EntryFee: 0, PreorderFee: 0, }, ColourScheme: '', PinnacleAction: '', PinnacleMessage: '', ManualProgression: false, AllowModSuperusers: false, HideTokenTotal: false, HideTokensInSubject: false, YellowWallThreshold: 0, SubjectSuffix: '', SupportMode: false, }; function Goal(tokens, subject, previous, next) { this._tokens = tokens; this._consumed = 0; this._subject = subject; this._previous = previous; this._next = next; this.onGoalMet = function (goal, remaining) { }; this.onGoalUnmet = function (goal, remaining) { }; this.onPinnacle = function () { }; }; /* Property Accessors. Sigh, if only JavaScript had REAL getters and setters! */ Goal.prototype.getTokens = function () { return this._tokens; }; Goal.prototype.getConsumed = function () { return this._consumed; }; Goal.prototype.getSubject = function () { return this._subject; }; Goal.prototype.getPrevious = function () { return this._previous; }; Goal.prototype.getNext = function () { if (this._next == null && Configuration.PinnacleAction == Resources.getString('goal_action_loop')) { Messaging.sendDebugMessage(String.format("This goal is a loop! Creating a new vGoal for {0} tokens, with subject {1}", this.getTokens(), this.getSubject())); this._next = new Goal(this.getTokens(), this.getSubject(), this, null, true); this._next.onGoalMet = this.onGoalMet; this._next.onGoalUnmet = this.onGoalUnmet; this._next.onPinnacle = this.onPinnacle; } return this._next; }; Goal.prototype.setNext = function (next) { this._next = next; }; Goal.prototype.setPrevious = function (previous) { this._previous = previous; }; Goal.prototype.updateRoom = function () { var subject_text = (this._tokens == Infinity ? this._subject : String.format(Resources.getString("subject_text"), this.getSubject(), this.getRemaining(), Configuration.SubjectSuffix)); Room.setSubject(subject_text); }; Goal.prototype.getRemaining = function () { return this._tokens - this._consumed; }; Goal.prototype.reset = function () { this._consumed = 0; this.updateRoom(); }; Goal.prototype.consumeTip = function (tokens) { this._consumed += tokens; if (this._consumed >= this._tokens) { var remaining = this._consumed - this._tokens; this._consumed = this._tokens; return this.onGoalMet(this, remaining); } if (this._tokens !== Infinity) this.updateRoom(); }; Goal.prototype.regurgitateTip = function (tokens) { this._consumed -= tokens; if (this._consumed <= 0) { var remaining = this._consumed * -1; this._consumed = 0; return this.onGoalUnmet(this, remaining); } if (this._tokens !== Infinity) this.updateRoom(); }; Goal.prototype.toString = function () { return 'Goal [Tokens: ' + this._tokens + ' Consumed: ' + this._consumed + ' Subject: ' + this._subject + ' Loop: ' + this._loop + ' HasNext: ' + (this._next != null) + ' HasPrevious: ' + (this._previous != null) + ']'; }; function User(name, gender, is_mod, in_fanclub, has_tokens, tipped_recently, tipped_alot_recently, tipped_tons_recently) { this._name = name; this._tipped = 0; this._groups = []; if (is_mod) this._groups.push(Groups.Moderators); if (in_fanclub) this._groups.push(Groups.Fans); if (has_tokens && !tipped_recently && !tipped_alot_recently && !tipped_tons_recently) this._groups.push(Groups.TokenHolders); if (tipped_recently && !tipped_alot_recently && !tipped_tons_recently) this._groups.push(Groups.Tippers); if (tipped_alot_recently && !tipped_tons_recently) this._groups.push(Groups.BigTippers); if (tipped_tons_recently) this._groups.push(Groups.MassiveTippers); this._gender = gender; }; User.prototype.getName = function () { return this._name; }; User.prototype.getGender = function () { return this._gender; }; User.prototype.getGroups = function () { return this._groups; }; User.prototype.addTip = function (tokens) { this._tipped += tokens; }; User.parseFromMessage = function (message) { return new User(message.user, message.gender, message.is_mod, message.in_fanclub, message.has_tokens, message.tipped_recently, message.tipped_alot_recently, message.tipped_tons_recently); }; User.parseFromTip = function (tip) { return new User(tip.from_user, tip.from_user_gender, tip.from_user_is_mod, tip.from_user_in_fanclub, tip.from_user_has_tokens, tip.from_user_tipped_recently, tip.from_user_tipped_alot_recently, tip.from_user_tipped_tons_recently); } var Tracker = { Statistics: { HighestTipper: { Name: Resources.getString('noone'), Tokens: 0 }, HighestTotal: { Name: Resources.getString('noone'), Tokens: 0 }, LowestTipper: { Name: Resources.getString('noone'), Tokens: 0 }, MostRecentTipper: { Name: Resources.getString('noone'), Tokens: 0 }, TotalTipped: 0, VirtualTipped: 0, TotalTarget: 0, leaderboardUpdate: function (user, amount) { if (this.HighestTipper.Tokens < amount) { this.HighestTipper.Name = user.getName(); this.HighestTipper.Tokens = amount; } if (this.HighestTotal.Tokens < amount) { this.HighestTotal.Name = user.getName(); this.HighestTotal.Tokens = amount; } if (this.LowestTipper.Tokens > amount) { this.LowestTipper.Name = user.getName(); this.LowestTipper.Tokens = amount; } this.MostRecentTipper.Name = user.getName(); this.MostRecentTipper.Tokens = amount; }, }, _goals: [], _tippers: {}, _currentGoal: null, _panel: null, GoalTimer: { IsRunning: false, TimerId: null, Duration: 0, Elapsed: 0, startTimer: function (duration) { if (this.IsRunning) return false; this.TimerId = 'goal' + String(Math.floor(Math.random() * 100)) + String(Math.floor(Math.random() * 100)); Chronometer.addTimer(this.TimerId, new Timer(function () { Tracker.GoalTimer.onTimerHit() } , 1)); }, stopTimer: function (duration) { if (!this.IsRunning) return false; Chronometer.removeTimer(this.TimerId); }, onTimerHit: function () { this.Elapsed++; if (this.Elapsed >= this.Duration) { Chronometer.removeTimer(this.TimerId); this.onTimerComplete(); } }, onTimerComplete: function () { Messaging.sendWarningMessage(Resources.getString('goal_timer_ended')); }, }, buildPanel: function () { this._panel = { template: '3_rows_of_labels', row1_label: Resources.getString('panel_total_received'), row1_value: this.Statistics.VirtualTipped, row2_label: Resources.getString('panel_highest'), row2_value: String.format("{0} ({1})", this.Statistics.HighestTipper.Name, this.Statistics.HighestTipper.Tokens), row3_label: Resources.getString('panel_most_recent'), row3_value: String.format("{0} ({1})", this.Statistics.MostRecentTipper.Name, this.Statistics.MostRecentTipper.Tokens), }; if (Configuration.HideTokenTotal) { caches.panel.row1_label = String.Empty; caches.panel.row1_value = String.Empty; } this._panel = { template: '3_rows_of_labels', row1_label: Configuration.HideTokenTotal ? Resources.getString('panel_goal_received_no_total') : Resources.getString('panel_goal_received'), row1_value: String.format(Configuration.HideTokenTotal ? "{0} / {1}" : "{0} / {1} ({2})", Tracker.getCurrentGoal().getConsumed(), Tracker.getCurrentGoal().getTokens(), Tracker.Statistics.VirtualTipped), row2_label: Resources.getString('panel_highest'), row2_value: String.format("{0} ({1})", this.Statistics.HighestTipper.Name, this.Statistics.HighestTipper.Tokens), row3_label: Resources.getString('panel_most_recent'), row3_value: String.format("{0} ({1})", this.Statistics.MostRecentTipper.Name, this.Statistics.MostRecentTipper.Tokens), }; if (this.GoalTimer.IsRunning) { caches.panel.row3_label = Resources.getString('goal_timer_minsleft'); caches.panel.row3_value = (this.GoalTimer.Duration - this.GoalTimer.Elapsed)*60; } cb.drawPanel(); }, getPanel: function () { if (this._panel == null) { this.buildPanel(); } return this._panel; }, onGoalMet: function (goal, remaining) { Messaging.sendSuccessMessage(String.format(Resources.getString('announce_goal_met'), goal.getSubject())); if (goal.getNext() == null && Configuration.PinnacleAction == Resources.getString('goal_action_thanks')) { return this.onPinnacle(); } this._currentGoal = goal.getNext(); if (remaining > 0) { this._currentGoal.consumeTip(remaining); } else { this._currentGoal.updateRoom(); } this.buildPanel(); }, onGoalUnmet: function (goal, remaining) { if (this._currentGoal.getPrevious() == null) { return this._currentGoal.reset(); } this._currentGoal = this._currentGoal.getPrevious(); if (remaining > 0) { this._currentGoal.regurgitateTip(remaining); } else { this._currentGoal.updateRoom(); } this.buildPanel(); }, onPinnacle: function () { var pinnacle = new Goal(Infinity, Configuration.PinnacleMessage, this._currentGoal, null, false); this._currentGoal.setNext(pinnacle); this._currentGoal = pinnacle; pinnacle.updateRoom(); }, addGoal: function (goal) { if (this._goals.length == 0) { this._currentGoal = goal; goal.updateRoom(); } this.Statistics.TotalTarget += goal.getTokens(); this._goals.push(goal); }, getCurrentGoal: function () { return this._currentGoal; }, processTip: function (user, tokens, virtual) { if (!virtual) { if (!this._tippers.hasOwnProperty(user.getName())) { this._tippers[user.getName()] = user; } this._tippers[user.getName()].addTip(tokens); this.Statistics.TotalTipped += tokens; } else { this.Statistics.VirtualTipped += tokens; } this._currentGoal.consumeTip(tokens); this.Statistics.leaderboardUpdate(user, tokens); this.buildPanel(); }, processRollback: function (user, tokens, virtual) { this._currentGoal.regurgitateTip(tokens); this.buildPanel(); }, hasTippedMe: function (user) { return this._goals.hasOwnProperty(user); }, getStatistics: function () { var output = ""; output += String.format("{0}: {1}\n", Resources.getString('stats_total'), (this.Statistics.TotalTipped - this.Statistics.VirtualTipped)); output += "Total tipped so far: " + Tipping.VirtualTotal + "\n"; output += "Total goal remaining: " + (getSumTotalGoal() - Tipping.VirtualTotal) + "\n"; output += "Tokens/min: " + getTokensPerMinute() + "\n"; output += "Total actual tipped (disregarding resets): " + Tipping.ActualTotal + "\n"; output += "Dollars/min (assuming $0.05/token): $" + getDollarsPerMinute() + "\n"; output += "Total dollars (assuming $0.05/token): $" + getTotalDollars() + "\n"; output += "Disclaimer: per minute figures EXCLUDE private shows, group shows, and other non-tip token gains\n"; output += "=== Tip Stats ===\n"; output += "Highest total tips: " + Tipping.Leaderboard.Leaders.HighestTotal.Amount + " from " + Tipping.Leaderboard.Leaders.HighestTotal.Username + "\n"; output += "Awesomest tip: " + Tipping.Leaderboard.Leaders.Highest.Amount + " from " + Tipping.Leaderboard.Leaders.Highest.Username + "\n"; output += "Stingiest tip: " + Tipping.Leaderboard.Leaders.Lowest.Amount + " from " + Tipping.Leaderboard.Leaders.Lowest.Username + "\n"; output += "Most recent tip: " + Tipping.Leaderboard.Leaders.MostRecent.Amount + " from " + Tipping.Leaderboard.Leaders.MostRecent.Username + "\n"; output += "=== Leaderboard (Top 10) ===\n\n"; //output += getLeaderBoard(); return output; }, }; function Command(commandtext, help_text, param_names, access_level, callback) { this._commandtext = commandtext; this._helpText = help_text; this._paramNames = param_names; this._accessLevel = access_level; this._callback = callback; }; Command.prototype.process = function (user, command, args) { // Processes the specified command, and returns true if the command has been consumed if (command !== this._commandtext) return false; if (Room.getAccessLevel(user) > this._accessLevel) { CommandProcessor.sendAccessDeniedMessage(user, command); return true; } try { if (typeof (this._callback) === 'function') { this._callback(user, args); } } catch (e) { Messaging.sendDebugMessage(e.stack); } finally { return true; } } Command.prototype.getAccessLevel = function () { return this._accessLevel; } Command.prototype.getHelpText = function () { if (this._paramNames !== null && this._paramNames.length > 0) { var params = String.format("<{0}>", this._paramNames.join('> <')); return String.format("{0}{1} {2} -- {3}", Application.Constants.Shebang, this._commandtext.toLowerCase(), params, this._helpText); } else { return String.format("{0}{1} -- {2}", Application.Constants.Shebang, this._commandtext.toLowerCase(), this._helpText); } } var CommandProcessor = { commands: [], processCommand: function (sender, command, args) { command = command.toUpperCase(); for (var test in this.commands) { if (this.commands[test] && this.commands[test].process(sender, command, args)) return true; } return false; }, sendAccessDeniedMessage: function (sender, command) { Messaging.sendErrorMessage(String.format(Resources.getString('err_access_denied'), command), sender.getName()); }, addCommand: function (command) { this.commands.push(command); }, sendHelpMessage: function (user) { var help_text = String.format("{0}\n", String.format(Resources.getString('heading_help'), Application.Title)); for (var test in this.commands) { if (this.commands[test] && this.commands[test].getAccessLevel() >= Room.getAccessLevel(user)) help_text += String.format("\n{0}{1}", Resources.getString('bullet'), this.commands[test].getHelpText()); } Messaging.sendInfoMessage(help_text, user.getName()); } } // Setup commands CommandProcessor.addCommand(new Command("EVAL", "Evaluates the provided javascript code. Can result in ugly errors if you fuck it up", [], AccessLevels.AlwaysDeveloper, function (user, args) { eval(args.join(' ')); })); CommandProcessor.addCommand(new Command("STATS", "Displays statistics related to your show income, including totals and breakdowns", [], AccessLevels.Broadcaster, function (user, args) { Messaging.sendInfoMessage(Tracker.getStatistics(), user.getName()); })); CommandProcessor.addCommand(new Command("GOALS", "Sends the list of goals and their targets to you", [], AccessLevels.Broadcaster, function (user, args) { /* TODO Implement /goals */ })); CommandProcessor.addCommand(new Command("RESET", "Resets the application, returning your goals back to the start", [], AccessLevels.Broadcaster, function (user, args) { /* TODO Implement /reset */ })); CommandProcessor.addCommand(new Command("SKIP", "Immediately ends the current goal, and moves onto the next scheduled goal", [], AccessLevels.Broadcaster, function (user, args) { /* TODO Implement /skip */ })); CommandProcessor.addCommand(new Command("UPNEXT", "Announces to the room what the next goal will be", [], AccessLevels.Broadcaster, function (user, args) { /* TODO Implement /upnext */ })); CommandProcessor.addCommand(new Command("TIMER", "Manages timers. Provide a number to start a timer for the specified minutes, or 'stop' to stop running timers", ['minutes|stop'], AccessLevels.Broadcaster, function (user, args) { /* TODO Implement /timer */ })); CommandProcessor.addCommand(new Command("CONTINUE", "Continues onto the next goal, if progression is stopped due to manual progression being enabled", [], AccessLevels.Broadcaster, function (user, args) { /* TODO Implement /continue */ })); CommandProcessor.addCommand(new Command("SETCOLOURS", "Sets the colour scheme for high tipper highlighting", ['scheme'], AccessLevels.Broadcaster, function (user, args) { /* TODO Implement /setcolours */ })); CommandProcessor.addCommand(new Command("ADMIT", "Admits a user into your ticket show if one is or will be running", ['user'], AccessLevels.Broadcaster, function (user, args) { /* TODO Implement /admit */ })); CommandProcessor.addCommand(new Command("UNADMIT", "Removes a user from your ticket show if one is or will be running", ['user'], AccessLevels.Broadcaster, function (user, args) { /* TODO Implement /unadmit */ })); CommandProcessor.addCommand(new Command("TICKETS", "Displays a list of all users who have access to a ticket show started this session", [], AccessLevels.Broadcaster, function (user, args) { /* TODO Implement /tickets */ })); CommandProcessor.addCommand(new Command("ADDTOKENS", "Adds the specified number of 'virtual' tokens against the token goal", ['tokens'], AccessLevels.Broadcaster, function (user, args) { /* TODO Implement /addtokens */ })); CommandProcessor.addCommand(new Command("REMOVETOKENS", "Removes the specified number of 'virtual' tokens from the token goal", ['tokens'], AccessLevels.AlwaysBroadcaster, function (user, args) { /* TODO Implement /removetokens */ })); CommandProcessor.addCommand(new Command("SUPPORT", "Enables or disables Support Mode, enabling the developer to execute developer mode commands to assist you", [], AccessLevels.AlwaysBroadcaster, function (user, args) { Configuration.SupportMode = !Configuration.SupportMode; })); CommandProcessor.addCommand(new Command("HELP", "Outputs this help information", [], AccessLevels.Everyone, function (user, args) { CommandProcessor.sendHelpMessage(user); })); // Application initialisation Application.applyUserConstants(Room.getOwner()); cb.settings_choices = Configuration.getSetupScreen(); if (typeof (cb.settings) !== 'undefined' && typeof (cb.settings.action_on_finality) !== 'undefined') { if (Application.launchCheck()) { Application.initialise(); Application.wireup(); } };
© Copyright Chaturbate 2011- 2025. All Rights Reserved.