├── README.md ├── automator.user.js ├── elementsStatTracker.js ├── img ├── game_frame_tv.png ├── icons.png ├── settings.png └── stats.png ├── minified.js ├── notes.txt └── slaveWindows.js /README.md: -------------------------------------------------------------------------------- 1 | # SteamMonsterGameScript 2 | A Javascript automator for the 2015 Summer Steam Monster Minigame 3 | ###DISCLAIMER: I take no responsibility for the use of this program, or any negative effects that may result in using it!### 4 | 5 | ###ATTENTION: Before spamming me with "I don't see anything therefore it's not working wtf" messages, please read the [Notes](https://github.com/ensingm2/SteamMonsterGameScript#notes) and [Testing](https://github.com/ensingm2/SteamMonsterGameScript#testing) sections of the readme.### 6 | 7 | ##Links: 8 | - [Reddit Thread](https://www.reddit.com/r/SteamMonsterGame/comments/39lv9t/customizable_js_autoclicker_targetlanechanger_and/) 9 | - [/r/SteamMonsterGame/](https://www.reddit.com/r/SteamMonsterGame/) 10 | 11 | #How To Use: 12 | ###UserScript via Greasemonkey or Tampermonkey (Preferred Method, allows slave windows): 13 | 1. Download the relevent addon if you don't already have it 14 | - [Tampermonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo) for Chrome 15 | - [Greasemonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/) for Firefox 16 | 2. Install the script by visiting [this link](https://raw.githubusercontent.com/ensingm2/SteamMonsterGameScript/master/automator.user.js) and pressing 'Install' 17 | 3. The script will now automatically load whenever you visit http://steamcommunity.com/minigame/towerattack/ 18 | 4. Enjoy! 19 | 20 | ##Javascript Only Version (No slave window support) 21 | To load the script, copy/paste the code from either automator.user.js or minified.js or into your browser console or userscript plugin, and hit return to run it. 22 | 23 | ##Parts: 24 | Any of the additions can be started or stopped individually: 25 | - **autoClicker:** run "startAutoClicker()" or "stopAutoClicker()" in the console. 26 | - **autoRespawner:** run "startAutoRespawner()" or "stopAutoRespawner()" in the console. 27 | - **autoTargetSwapper:** run "startAutoTargetSwapper()" or "stopAutoTargetSwapper()" in the console. 28 | - **autoAbilityUser:** run "startAutoAbilityUser()" or "stopAutoAbilityUser()" in the console. 29 | - **autoItemUser:** run "startAutoItemUser()" or "stopAutoItemUser()" in the console. 30 | - **autoUpgradeManager:** run "startAutoUpgradeManager()" or "stopAutoUpgradeManager()" in the console. 31 | 32 | ###Slave Window Manager (created by [ags131](https://github.com/ags131/steamMinigameSlaveScript)): 33 | - Allows opening of multiple slave windows to work around the clicks per second limit 34 | - Disables rendering on slave windows in order to reduce memory/cpu use 35 | - In-UI management of slaves from master window 36 | - Automatic refresh of slave windows to avoid any memleaks 37 | - ***Known issue with Slave Window Manager & UserScript:*** 38 | - The Slave Window Manager code seems to get cached by the userscript. You can force a refresh by uninstalling and reinstalling the base userscript. NOTE: Issue being tracked [here](https://github.com/ensingm2/SteamMonsterGameScript/issues/59), if you have any ideas on how to fix it, I'd appreciate a comment. 39 | 40 | 41 | *There are buttons that get added to the bottom of the game page that toggle these functions for your convenience* 42 | 43 | ##Variables: 44 | Feel free to edit any variables to suit your needs 45 | ###Main 46 | - **debug (default: false):** if true, logs all actions to the console. 47 | - **clicksPerSecond (default: g_TuningData.abilities[1].max_num_clicks):** Number of clicks to be sent to the server each second. 48 | - **autoClickerVariance (default: 10% of clicksPerSecond):** amount that the clicks per second can be randomized by (range is clicksPersecond +/- autoClickerVariance) 49 | - **respawnCheckFreq (default: 5000ms):** Duration (in milliseconds) between checks to see if the player needs to be revived. 50 | - **targetSwapperFreq (default: 1000ms):** Duration (in milliseconds) between checks to see if the player needs to change targets. 51 | - **abilityUseCheckFreq (default: 2000ms):** Duration (in milliseconds) between checks to see if it is beneficial to use an active ability 52 | - **itemUseCheckFreq (default: 5000ms):** Duration (in milliseconds) between checks to see if it is beneficial to use a consumable item 53 | - **upgradeManagerFreq (default: 30000):** Duration (in milliseconds) between checks to see if it is beneficial to purchase an upgrade 54 | - **autoBuyAbilities (default: false):** if true, autoUpgrader will prioritize buying new abilities for use over upgrades. 55 | - **nukeBossesAfterLevel (default: 1000):** Including and Past this point, Nukes will be used on bosses, not spawners. 56 | - **farmGoldOnBossesLevelDiff (default: 200):** Farms gold on bosses every nth level. 57 | - **useNukeOnBossAbovePercent (default: 25):** If boss nuke is active, will use a nuke on any targetted boss with above this % health remaining. 58 | 59 | ###Item Use 60 | - **useMedicsAtPercent (default: 30):** % max hp at which to use the medics ability 61 | - **useMedicsAtLanePercent (default: 70):** If average lane health dips below this %, Medics will be used. 62 | - **useMedicsAtLanePercentAliveReq (default: 30):** % of lane allies that must be alive in order to use Medics selflessly 63 | - **useNukeOnSpawnerAbovePercent (default: 75):** Above this % percentage threshold, a nuke will be used on a targeted spawner 64 | - **useMetalDetectorOnBossBelowPercent (default: 30):** Below this % percentage threshold, a Metal Detector will be used on a targeted boss 65 | - **seekHealingPercent (default: 20)** Below this % percentage threshold, script will swap to any lane that has a Healing powerup active 66 | - **useStealHealthAtPercent (default: 15):** % max hp at which to use the Steal Health Item 67 | - **useRainingGoldAbovePercent (default: 75):** Above this % percentage threshold, Raining Gold will be used on a targeted boss 68 | - **useLikeNewAboveCooldown (default: 14220000):** If total non-item ability cooldown passes this threshold (in milliseconds) and one is available, a Like New will be used. 69 | - **useResurrectToSaveCount (default: 150):** Will use resurrect if over this number of players is dead in your lane. 70 | - **spamStatBoosters (default: true):** If set, will automatically use Crit and Pumped up whenever they become available. 71 | 72 | ###Slave Window Settings (NOT CURRENTLY ACCESSABLE) 73 | - **slaveWindowUICleanup (default: true):** Whether or not slave windows will have all graphics removed in order to reduce load. 74 | - **slaveWindowPeriodicRestart (default: true):** If enabled, slave windows will periodically close and reopen in an attempt to cut down on any memory leaks 75 | - **slaveWindowPeriodicRestartInterval (default: 300000 [5 minutes]):** Duration (in milliseconds) between slave window reloads, if slaveWindowPeriodicRestart is set 76 | 77 | ##Notes: 78 | This script does not output particles for clicks, so you will not see damage output from the autoclicker. This is intended, as it reduces lag and removes a fairly large memory leak in the base game. 79 | You will however see the output from the attacks made by any auto-fire cannons or your own manual clicks, as we haven't altered that code. 80 | See the [Testing](https://github.com/ensingm2/SteamMonsterGameScript#testing) section of this readme if you want to make sure things are working. 81 | 82 | ##Testing: 83 | If you would like to test the script, you have a few options 84 | - Use a browser add-on such as Firebug for Firefox and view the POST data being sent to the server. This is the best testing method as you can see exactly what's being sent to the server. 85 | - If you're running in chrome and just want to make sure the scripts are running, type "debug=true" into the console, and it will enable debug console logs as things happen. 86 | 87 | ##Using code from this in your own script?## 88 | Yeah, you're welcome to. It'd be nice of you to give some type of credit to whoever originally added that feature though. Don't worry about it if you're forking from this, in that case there's a trail leading back so people can see the original committers. 89 | 90 | ##TODO: 91 | - Finish automating use of abilities & items 92 | - Bug Fixes? 93 | 94 | ##Contributors: 95 | (Listed alphabetically) 96 | - [ags131](https://github.com/ags131) 97 | - [DannyDaemonic](https://github.com/DannyDaemonic) 98 | - [EnragedRabisu](https://github.com/joshho) 99 | - [ensingm2](https://github.com/ensingm2) 100 | - [iareHuuman](https://github.com/iareHuuman) 101 | - [iskandar](https://github.com/iskandar) 102 | - [joshho](https://github.com/joshho) 103 | - [jcugat](https://github.com/jcugat) 104 | - [leandroclem](https://github.com/leandroclem) 105 | - [meishuu](https://github.com/meishuu) 106 | - [waterfoul] (https://github.com/waterfoul) 107 | - [nbadal](https://github.com/nbadal) 108 | - [vanZeben](https://github.com/vanZeben) 109 | - [Zazcallabah](https://github.com/Zazcallabah) 110 | - [/u/kolodz](https://reddit.com/user/kolodz) 111 | - [/u/Landriff](https://reddit.com/user/Landriff) 112 | - [/u/lllillillilll](https://reddit.com/user/lllillillilll) 113 | - [/u/Meishuu](https://reddit.com/user/Meishuu) 114 | - [/u/minusra](https://reddit.com/user/minusra) 115 | - [/u/Scyntrus](https://reddit.com/user/Scyntrus) 116 | - [/u/TheDollarDes](https://reddit.com/user/TheDollarDes) 117 | -------------------------------------------------------------------------------- /automator.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name [ensingm2] Steam Monster Game Script 3 | // @namespace https://github.com/ensingm2/SteamMonsterGameScript 4 | // @description A Javascript automator for the 2015 Summer Steam Monster Minigame 5 | // @version 2.16 6 | // @match http://steamcommunity.com/minigame/towerattack* 7 | // @match http://steamcommunity.com//minigame/towerattack* 8 | // @updateURL https://raw.githubusercontent.com/ensingm2/SteamMonsterGameScript/master/automator.user.js 9 | // @downloadURL https://raw.githubusercontent.com/ensingm2/SteamMonsterGameScript/master/automator.user.js 10 | // @require https://raw.githubusercontent.com/ensingm2/SteamMonsterGameScript/master/slaveWindows.js?ver=2_06 11 | // @grant none 12 | // ==/UserScript== 13 | 14 | // Compiled and customized by https://github.com/ensingm2 15 | // See a (hopefully) full list of contributors over at https://github.com/ensingm2/SteamMonsterGameScript#contributors 16 | 17 | // Custom variables 18 | var debug = false; 19 | var clicksPerSecond = g_TuningData.abilities[1].max_num_clicks; 20 | var autoClickerVariance = Math.floor(clicksPerSecond / 10); 21 | clicksPerSecond -= Math.ceil(autoClickerVariance / 2); 22 | var respawnCheckFreq = 5000; 23 | var targetSwapperFreq = 1000; 24 | var abilityUseCheckFreq = 2000; 25 | var itemUseCheckFreq = 5000; 26 | var seekHealingPercent = 20; 27 | var upgradeManagerFreq = 5000; 28 | var slowRenderingFreq = 1000; 29 | var autoBuyAbilities = false; 30 | var refreshDelay = 3600000; //Page refresh every 60min 31 | var spamStatBoosters = true; 32 | 33 | // Boss Nuke Variables 34 | var useNukeOnBossAbovePercent = 40; 35 | 36 | //Controls to sync us up with other scripts 37 | var CONTROL = { 38 | speedThreshold: 2000, // use gold rain every boss round after here 39 | rainingRounds: 100, // use gold rain every x rounds 40 | disableGoldRainLevels: 200 // min level to use gold rain on 41 | }; 42 | 43 | //item use variables 44 | var useMedicsAtPercent = 40; 45 | var useMedicsAtLanePercent = 70; 46 | var useMedicsAtLanePercentAliveReq = 30; 47 | var useNukeOnSpawnerAbovePercent = 75; 48 | var useMetalDetectorOnBossBelowPercent = 30; 49 | 50 | var useStealHealthAtPercent = 15; 51 | var useRainingGoldAbovePercent = 50; 52 | var useLikeNewAboveCooldown = 14220000; // Need to save at least 14220s of cooldowns(60% of max) 53 | var useResurrectToSaveCount = 150; // Use revive to save 150 people 54 | var minutesBufferForConsumableDump = 10; 55 | var survivalTime = 10; // check how long we would survive on a level and prioritize armour if needed 56 | 57 | // You shouldn't need to ever change this, you only push to server every 1s anyway 58 | var autoClickerFreq = 1000; 59 | 60 | // Internal variables, you shouldn't need to touch these 61 | var autoRespawner, autoClicker, autoTargetSwapper, autoTargetSwapperElementUpdate, autoAbilityUser, autoUpgradeManager, fpsThrottle, spammer; 62 | var elementUpdateRate = 60000; 63 | var autoUseConsumables = true; 64 | var userElementMultipliers = [1, 1, 1, 1]; 65 | var userMaxElementMultiiplier = 1; 66 | var swapReason; 67 | var lastLootLevel = 0; 68 | var lastLootCache = []; 69 | 70 | var ABILITIES = { 71 | FIRE_WEAPON: 1, 72 | CHANGE_LANE: 2, 73 | RESPAWN: 3, 74 | CHANGE_TARGET: 4, 75 | MORALE_BOOSTER: 5, 76 | GOOD_LUCK_CHARMS: 6, 77 | MEDICS: 7, 78 | METAL_DETECTOR: 8, 79 | DECREASE_COOLDOWNS: 9, 80 | TACTICAL_NUKE: 10, 81 | CLUSTER_BOMB: 11, 82 | NAPALM: 12, 83 | RESURRECTION: 13, 84 | CRIPPLE_SPAWNER: 14, 85 | CRIPPLE_MONSTER: 15, 86 | MAX_ELEMENTAL_DAMAGE: 16, 87 | RAINING_GOLD: 17, 88 | CRIT: 18, 89 | PUMPED_UP: 19, 90 | THROW_MONEY_AT_SCREEN: 20, 91 | GOD_MODE: 21, 92 | TREASURE: 22, 93 | STEAL_HEALTH: 23, 94 | REFLECT_DAMAGE: 24, 95 | FEELING_LUCKY: 25, 96 | WORMHOLE: 26, 97 | LIKE_NEW: 27 98 | }; 99 | 100 | function startAllAutos() { 101 | startAutoRespawner(); 102 | 103 | 104 | startAutoClicker(); 105 | startAutoTargetSwapper(); 106 | startAutoAbilityUser(); 107 | startAutoItemUser(); 108 | startAutoUpgradeManager(); 109 | } 110 | 111 | function loadSettings() { 112 | if(WebStorage.GetLocal('autoClickerEnabled') === false) 113 | toggleAutoClicker(); 114 | if(WebStorage.GetLocal('autoTargetSwapperEnabled') === false) 115 | toggleAutoTargetSwapper(); 116 | if(WebStorage.GetLocal('autoAbilityUserEnabled') === false) 117 | toggleAutoAbilityUser(); 118 | if(WebStorage.GetLocal('autoConsumableUserEnabled') === false) 119 | toggleAutoItemUser(); 120 | if(WebStorage.GetLocal('autoUpgraderEnabled') === false) 121 | toggleAutoUpgradeManager(); 122 | 123 | 124 | if(WebStorage.GetLocal('particleSpamEnabled')){ 125 | spammer = setInterval(spamNoClick, 1000 / clicksPerSecond); 126 | updateToggle("particles", false); 127 | } 128 | 129 | if (WebStorage.GetLocal('fpsThrottleEnabled') === true) 130 | toggleFPS(); 131 | 132 | if(WebStorage.GetLocal('spamStatBoostersEnabled') === false) 133 | toggleSpamStatBoosters(); 134 | 135 | if(WebStorage.GetLocal('survivalTime') !== null) { 136 | survivalTime = WebStorage.GetLocal('survivalTime'); 137 | $J("#survival_time").html(survivalTime); 138 | } 139 | } 140 | 141 | function stopAllAutos() { 142 | stopAutoClicker(); 143 | stopAutoRespawner(); 144 | stopAutoTargetSwapper(); 145 | stopAutoAbilityUser(); 146 | stopAutoItemUser(); 147 | stopAutoUpgradeManager(); 148 | } 149 | 150 | //Keep trying to start every second till success 151 | var startAttempts = 0; 152 | var startAll = setInterval(function() { 153 | if (!gameRunning()) { 154 | //Don't refresh if we're waiting on game to start 155 | if (g_Minigame.m_CurrentScene.m_rgGameData.status != 1) { 156 | //Refresh if the game still isn't running after 15s 157 | if (startAttempts > 15) 158 | location.reload(); 159 | 160 | startAttempts++; 161 | } 162 | return; 163 | } 164 | 165 | clearInterval(startAll); 166 | 167 | startAllAutos(); 168 | initGUI(); 169 | loadSettings(); 170 | 171 | //Start leaderboard (if user is running userscript) 172 | if (typeof unsafeWindow != 'undefined') 173 | initLeaderboard(); 174 | 175 | if (typeof runMaster == 'function') { 176 | //Setup for slave windows 177 | if (location.search.match(/slave/)) 178 | runSlave(); 179 | else 180 | runMaster(); 181 | } 182 | 183 | //Keep Playing while minimized - http://www.reddit.com/r/SteamMonsterGame/comments/39yng9/keep_autoclicking_after_minimizingchanging_tabs/ 184 | setInterval(function(p) { 185 | return p.Tick = eval("(" + ("" + p.Tick).replace(/document\.(hidden|webkitHidden|mozHidden|msHidden)/g, !1) + ")"), 186 | function() { 187 | p = g_Minigame.m_CurrentScene, p && document.hidden && p.Tick(); 188 | }; 189 | }(CSceneGame.prototype), 1000); 190 | 191 | setTimeout(function() { 192 | //Try to reload every 15s 193 | var reloader = setInterval(function() { 194 | //No raining gold, treasure mob, boss, or miniboss 195 | var target = getTarget(); 196 | var reload = !currentLaneHasAbility(ABILITIES.RAINING_GOLD) && target.m_data.type != 4 && target.m_data.type != 2 && target.m_data.type != 3 && target.m_data.type !== false; 197 | if (reload) { 198 | clearInterval(reloader); 199 | location.reload(); 200 | } 201 | }, 15000); 202 | }, refreshDelay); 203 | }, 1000); 204 | 205 | //Expose functions if running in userscript 206 | if (typeof unsafeWindow != 'undefined') { 207 | // Variables 208 | unsafeWindow.debug = debug; 209 | unsafeWindow.clicksPerSecond = clicksPerSecond; 210 | unsafeWindow.autoClickerVariance = autoClickerVariance; 211 | unsafeWindow.respawnCheckFreq = respawnCheckFreq; 212 | unsafeWindow.targetSwapperFreq = targetSwapperFreq; 213 | unsafeWindow.abilityUseCheckFreq = abilityUseCheckFreq; 214 | unsafeWindow.itemUseCheckFreq = itemUseCheckFreq; 215 | unsafeWindow.seekHealingPercent = seekHealingPercent; 216 | unsafeWindow.upgradeManagerFreq = upgradeManagerFreq; 217 | unsafeWindow.autoBuyAbilities = autoBuyAbilities; 218 | unsafeWindow.fpsThrottle = fpsThrottle; 219 | 220 | //item use variables 221 | unsafeWindow.useMedicsAtPercent = useMedicsAtPercent; 222 | unsafeWindow.useMedicsAtLanePercent = useMedicsAtLanePercent; 223 | unsafeWindow.useMedicsAtLanePercentAliveReq = useMedicsAtLanePercentAliveReq; 224 | unsafeWindow.useNukeOnSpawnerAbovePercent = useNukeOnSpawnerAbovePercent; 225 | unsafeWindow.useMetalDetectorOnBossBelowPercent = useMetalDetectorOnBossBelowPercent; 226 | unsafeWindow.useStealHealthAtPercent = useStealHealthAtPercent; 227 | unsafeWindow.useRainingGoldAbovePercent = useRainingGoldAbovePercent; 228 | unsafeWindow.autoUseConsumables = autoUseConsumables; 229 | unsafeWindow.useResurrectToSaveCount = useResurrectToSaveCount; 230 | unsafeWindow.spamStatBoosters = spamStatBoosters; 231 | 232 | //Slave window variables 233 | unsafeWindow.slaveWindowUICleanup = slaveWindowUICleanup; 234 | unsafeWindow.slaveWindowPeriodicRestart = slaveWindowPeriodicRestart; 235 | unsafeWindow.slaveWindowPeriodicRestartInterval = slaveWindowPeriodicRestartInterval; 236 | 237 | //Boss nuke vars 238 | unsafeWindow.useNukeOnBossAbovePercent = useNukeOnBossAbovePercent; 239 | 240 | // Functions 241 | unsafeWindow.startAutoClicker = startAutoClicker; 242 | unsafeWindow.startAutoRespawner = startAutoRespawner; 243 | unsafeWindow.startAutoTargetSwapper = startAutoTargetSwapper; 244 | unsafeWindow.startAutoAbilityUser = startAutoAbilityUser; 245 | unsafeWindow.startAutoItemUser = startAutoItemUser; 246 | unsafeWindow.startAllAutos = startAllAutos; 247 | unsafeWindow.startAutoUpgradeManager = startAutoUpgradeManager; 248 | unsafeWindow.stopAutoClicker = stopAutoClicker; 249 | unsafeWindow.stopAutoRespawner = stopAutoRespawner; 250 | unsafeWindow.stopAutoTargetSwapper = stopAutoTargetSwapper; 251 | unsafeWindow.stopAutoAbilityUser = stopAutoAbilityUser; 252 | unsafeWindow.stopAutoItemUser = stopAutoItemUser; 253 | unsafeWindow.stopAutoUpgradeManager = stopAutoUpgradeManager; 254 | unsafeWindow.stopAllAutos = stopAllAutos; 255 | unsafeWindow.disableAutoNukes = disableAutoNukes; 256 | unsafeWindow.castAbility = castAbility; 257 | unsafeWindow.hasAbility = hasAbility; 258 | unsafeWindow.abilityIsUnlocked = abilityIsUnlocked; 259 | unsafeWindow.abilityCooldown = abilityCooldown; 260 | unsafeWindow.toggleAutoClicker = toggleAutoClicker; 261 | unsafeWindow.toggleAutoTargetSwapper = toggleAutoTargetSwapper; 262 | unsafeWindow.toggleAutoAbilityUser = toggleAutoAbilityUser; 263 | unsafeWindow.toggleAutoItemUser = toggleAutoItemUser; 264 | unsafeWindow.toggleAutoUpgradeManager = toggleAutoUpgradeManager; 265 | unsafeWindow.spamNoClick = spamNoClick; 266 | unsafeWindow.toggleSpammer = toggleSpammer; 267 | unsafeWindow.getTarget = getTarget; 268 | unsafeWindow.currentLaneHasAbility = currentLaneHasAbility; 269 | unsafeWindow.laneHasAbility = laneHasAbility; 270 | unsafeWindow.getMobTypePriority = getMobTypePriority; 271 | unsafeWindow.updateStats = updateStats; 272 | 273 | //Hacky way to let people change vars using userscript before I set up getter/setter fns tomorrow 274 | var varSetter = setInterval(function() { 275 | if (debug) 276 | console.log('updating options'); 277 | 278 | // Main vars 279 | debug = unsafeWindow.debug; 280 | clicksPerSecond = unsafeWindow.clicksPerSecond; 281 | autoClickerVariance = unsafeWindow.autoClickerVariance; 282 | respawnCheckFreq = unsafeWindow.respawnCheckFreq; 283 | targetSwapperFreq = unsafeWindow.targetSwapperFreq; 284 | abilityUseCheckFreq = unsafeWindow.abilityUseCheckFreq; 285 | itemUseCheckFreq = unsafeWindow.itemUseCheckFreq; 286 | seekHealingPercent = unsafeWindow.seekHealingPercent; 287 | upgradeManagerFreq = unsafeWindow.upgradeManagerFreq; 288 | autoBuyAbilities = unsafeWindow.autoBuyAbilities; 289 | fpsThrottle = unsafeWindow.fpsThrottle; 290 | 291 | //item use variables 292 | useMedicsAtPercent = unsafeWindow.useMedicsAtPercent; 293 | useMedicsAtLanePercent = unsafeWindow.useMedicsAtLanePercent; 294 | useMedicsAtLanePercentAliveReq = unsafeWindow.useMedicsAtLanePercentAliveReq; 295 | useNukeOnSpawnerAbovePercent = unsafeWindow.useNukeOnSpawnerAbovePercent; 296 | useMetalDetectorOnBossBelowPercent = unsafeWindow.useMetalDetectorOnBossBelowPercent; 297 | useStealHealthAtPercent = unsafeWindow.useStealHealthAtPercent; 298 | useRainingGoldAbovePercent = unsafeWindow.useRainingGoldAbovePercent; 299 | useResurrectToSaveCount = unsafeWindow.useResurrectToSaveCount; 300 | spamStatBoosters = unsafeWindow.spamStatBoosters; 301 | 302 | //Boss nuke vars 303 | useNukeOnBossAbovePercent = unsafeWindow.useNukeOnBossAbovePercent; 304 | 305 | }, 5000); 306 | 307 | //Add closure 'debug' getter and setter 308 | unsafeWindow.getDebug = function() { 309 | return debug; 310 | }; 311 | unsafeWindow.setDebug = function(state) { 312 | debug = state; 313 | }; 314 | } 315 | 316 | // ================ AUTO CLICKER ================ 317 | function startAutoClicker() { 318 | if (autoClicker) { 319 | console.log("Autoclicker is already running!"); 320 | return; 321 | } 322 | 323 | autoClicker = setInterval(function() { 324 | if (!gameRunning()) return; 325 | 326 | //Vary the number of clicks by up to the autoClickerVariance variable (plus or minus) 327 | var randomVariance = Math.floor(Math.random() * autoClickerVariance * 2) - (autoClickerVariance); 328 | var clicks = clicksPerSecond + randomVariance; 329 | 330 | // Set the variable to be sent to the server 331 | g_Minigame.m_CurrentScene.m_nClicks += clicks; 332 | 333 | // Anti-anti-clicker countermeasure 334 | g_msTickRate = 1100; 335 | 336 | // Update Gold Counter 337 | var nClickGoldPct = g_Minigame.m_CurrentScene.m_rgGameData.lanes[g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane].active_player_ability_gold_per_click; 338 | var enemy = getTarget(); 339 | if (enemy && nClickGoldPct > 0 && enemy.m_data.hp > 0) { 340 | var nClickGold = enemy.m_data.gold * nClickGoldPct * g_Minigame.m_CurrentScene.m_nClicks; 341 | g_Minigame.m_CurrentScene.ClientOverride('player_data', 'gold', g_Minigame.m_CurrentScene.m_rgPlayerData.gold + nClickGold); 342 | g_Minigame.m_CurrentScene.ApplyClientOverrides('player_data', true); 343 | } 344 | 345 | //Clear out the crits 346 | var numCrits = g_Minigame.m_CurrentScene.m_rgStoredCrits.length; 347 | g_Minigame.m_CurrentScene.m_rgStoredCrits = []; 348 | 349 | if (debug) { 350 | if (numCrits > 1) 351 | console.log('Clicking ' + g_Minigame.m_CurrentScene.m_nClicks + ' times this second. (' + numCrits + ' crits).'); 352 | if (numCrits == 1) 353 | console.log('Clicking ' + g_Minigame.m_CurrentScene.m_nClicks + ' times this second. (1 crit).'); 354 | else 355 | console.log('Clicking ' + g_Minigame.m_CurrentScene.m_nClicks + ' times this second.'); 356 | 357 | //Calculate Damage done 358 | var damage = g_Minigame.m_CurrentScene.CalculateDamage(g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_per_click * userMaxElementMultiiplier * g_Minigame.m_CurrentScene.m_nClicks); 359 | var damageStr = "(unknown)"; 360 | if (damage > 1000000000) 361 | damageStr = (damage / 1000000000) + "B"; 362 | else if (damage > 1000000) 363 | damageStr = (damage / 1000000) + "M"; 364 | else if (damage > 1000) 365 | damageStr = (damage / 1000) + "K"; 366 | console.log('We did roughly ' + damageStr + ' damage in the last second.'); 367 | } 368 | 369 | }, autoClickerFreq); 370 | 371 | console.log("autoClicker has been started."); 372 | } 373 | 374 | function stopAutoClicker() { 375 | if (autoClicker) { 376 | clearInterval(autoClicker); 377 | autoClicker = null; 378 | console.log("autoClicker has been stopped."); 379 | } else 380 | console.log("No autoClicker is running to stop."); 381 | } 382 | 383 | // ================ AUTO ABILITY ITEM USE ================ 384 | function startAutoAbilityUser() { 385 | if (autoAbilityUser) { 386 | console.log("autoAbilityUser is already running!"); 387 | return; 388 | } 389 | 390 | autoAbilityUser = setInterval(function() { 391 | 392 | if (debug) 393 | console.log("Checking if it's useful to use an ability."); 394 | 395 | var percentHPRemaining = g_Minigame.CurrentScene().m_rgPlayerData.hp / g_Minigame.CurrentScene().m_rgPlayerTechTree.max_hp * 100; 396 | var target = getTarget(); 397 | 398 | var currentLane = g_Minigame.m_CurrentScene.m_rgGameData.lanes[g_Minigame.CurrentScene().m_rgPlayerData.current_lane]; 399 | var lvl = getGameLevel(); 400 | 401 | // Use any consumables that you won't run out of before round end 402 | for (var key in ABILITIES) { 403 | if (ABILITIES.hasOwnProperty(key)) { 404 | var abilityID = ABILITIES[key]; 405 | //Only check consumables 406 | if (abilityID >= ABILITIES.RESURRECTION) { 407 | var ignoreBufferPeriod = (abilityID == ABILITIES.THROW_MONEY_AT_SCREEN); 408 | if(hasTimeLeftToUseConsumable(abilityID, ignoreBufferPeriod)) 409 | castAbility(abilityID); 410 | } 411 | } 412 | } 413 | 414 | // Wormholes -- use before wasting items on lanes 415 | if (hasAbility(ABILITIES.WORMHOLE) && autoUseConsumables) { 416 | if ((lvl % CONTROL.rainingRounds === 0 && lvl > CONTROL.speedThreshold) || hasTimeLeftToUseConsumable(ABILITIES.WORMHOLE, false)) { // Use wormhole as close to the end on every 100th level (causes a 10 level jump instead of a 1) 417 | if (debug) 418 | console.log("Casting Wormhole! Allons-y!!!"); 419 | castAbility(ABILITIES.WORMHOLE); 420 | } 421 | } 422 | 423 | // Spam permanent stat boosters if set 424 | if(spamStatBoosters){ 425 | // Crit 426 | if(getAbilityItemQuantity(18)) 427 | castAbility(18); 428 | 429 | // Pumped Up 430 | if(getAbilityItemQuantity(19)) 431 | castAbility(19); 432 | } 433 | 434 | // Abilities only used on targets 435 | if (target) { 436 | 437 | var targetPercentHPRemaining = target.m_data.hp / target.m_data.max_hp * 100; 438 | var laneDPS = g_Minigame.m_CurrentScene.m_rgLaneData[g_Minigame.CurrentScene().m_rgPlayerData.current_lane].friendly_dps; 439 | var timeToTargetDeath = target.m_data.hp / laneDPS; 440 | 441 | // First priority since it can use Decrease Cooldowns 442 | 443 | //Nuke bosses after the 1000th level and not every 200th level thereafter 444 | var nukeBosses = (g_Minigame.m_CurrentScene.m_nCurrentLevel + 1 >= CONTROL.speedThreshold) && ((g_Minigame.m_CurrentScene.m_nCurrentLevel + 1) % CONTROL.rainingRounds !== 0); 445 | 446 | var isBoss = (target.m_data.type == 2 || target.m_data.type === false); // Assume false is a boss 447 | 448 | 449 | //Use Decrease Cooldowns on bosses 450 | if(isBoss) 451 | if(targetPercentHPRemaining > 75 && !currentLaneHasAbility(9) && hasAbility(9)) 452 | castAbility(9); 453 | 454 | // Abilities only used when targeting Spawners (sub lvl 1000) or nuking bosses (above level 1k) 455 | if ((target.m_data.type === 0 && g_Minigame.m_CurrentScene.m_nCurrentLevel + 1 >= CONTROL.speedThreshold) || (isBoss && nukeBosses)) { 456 | // Morale Booster, Good Luck Charm, and Decrease Cooldowns 457 | var moraleBoosterReady = hasAbility(ABILITIES.MORALE_BOOSTER); 458 | var goodLuckCharmReady = hasAbility(ABILITIES.GOOD_LUCK_CHARMS); 459 | var critReady = (hasAbility(ABILITIES.CRIT) && autoUseConsumables); 460 | 461 | 462 | // Only use items on targets that are spawners and have nearly full health 463 | if (targetPercentHPRemaining >= 90 && autoUseConsumables && (hasAbility(ABILITIES.CRIPPLE_SPAWNER) || hasAbility(ABILITIES.CRIPPLE_MONSTER))) { 464 | // Check to see if Cripple Spawner and Cripple Monster items are ready to use 465 | if (hasAbility(ABILITIES.CRIPPLE_SPAWNER)) { 466 | castAbility(ABILITIES.CRIPPLE_SPAWNER); 467 | } else if (hasAbility(ABILITIES.CRIPPLE_MONSTER)) { 468 | castAbility(ABILITIES.CRIPPLE_MONSTER); 469 | } 470 | } else if (moraleBoosterReady || critReady || goodLuckCharmReady) { 471 | // If we have both we want to combo them 472 | var moraleBoosterUnlocked = abilityIsUnlocked(ABILITIES.MORALE_BOOSTER); 473 | var goodLuckCharmUnlocked = abilityIsUnlocked(ABILITIES.GOOD_LUCK_CHARMS); 474 | 475 | // "if Moral Booster isn't unlocked or Good Luck Charm isn't unlocked, or both are ready" 476 | if ((!moraleBoosterUnlocked && !critReady) || !goodLuckCharmUnlocked || ((moraleBoosterReady || critReady) && (goodLuckCharmReady || !goodLuckCharmUnlocked))) { 477 | var currentLaneHasCooldown = currentLaneHasAbility(ABILITIES.DECREASE_COOLDOWNS); 478 | // Only use on targets that are spawners and have nearly full health 479 | if (targetPercentHPRemaining >= 70 || (currentLaneHasCooldown && targetPercentHPRemaining >= 60)) { 480 | // Combo these with Decrease Cooldowns ability 481 | 482 | // If Decreased Cooldowns will be available soon, wait 483 | if ( 484 | currentLaneHasCooldown || // If current lane already has Decreased Cooldown, or 485 | hasAbility(ABILITIES.DECREASE_COOLDOWNS) || // If we have the ability ready 486 | !abilityIsUnlocked(ABILITIES.DECREASE_COOLDOWNS) || // if we haven't unlocked the ability yet, or 487 | (abilityCooldown(ABILITIES.DECREASE_COOLDOWNS) > 60) // if cooldown > 60 488 | ) { 489 | if (hasAbility(ABILITIES.DECREASE_COOLDOWNS) && !currentLaneHasAbility(ABILITIES.DECREASE_COOLDOWNS)) { 490 | // Other abilities won't benifit if used at the same time 491 | if (debug) 492 | console.log('Triggering Decrease Cooldown!'); 493 | castAbility(ABILITIES.DECREASE_COOLDOWNS); 494 | } else { 495 | // Use these abilities next pass 496 | 497 | //Use crit if one's available 498 | if (critReady) { 499 | if (debug) 500 | console.log("Using Crit!"); 501 | castAbility(ABILITIES.CRIT); 502 | } else if (moraleBoosterReady) { 503 | if (debug) 504 | console.log("Casting Morale Booster!"); 505 | castAbility(ABILITIES.MORALE_BOOSTER); 506 | } 507 | 508 | if (goodLuckCharmReady) { 509 | if (debug) 510 | console.log("Casting Good Luck Charm!"); 511 | castAbility(ABILITIES.GOOD_LUCK_CHARMS); 512 | } 513 | } 514 | } 515 | } 516 | } 517 | } 518 | 519 | // Tactical Nuke 520 | if (hasAbility(ABILITIES.TACTICAL_NUKE) && (targetPercentHPRemaining >= useNukeOnSpawnerAbovePercent || (target.m_data.type == 2 && targetPercentHPRemaining >= useNukeOnBossAbovePercent))) { 521 | if (debug) 522 | console.log('Nuclear launch detected.'); 523 | 524 | castAbility(ABILITIES.TACTICAL_NUKE); 525 | } 526 | 527 | // Napalm 528 | else if (target.m_data.type === 0 && hasAbility(ABILITIES.NAPALM) && targetPercentHPRemaining >= useNukeOnSpawnerAbovePercent && currentLane.enemies.length >= 4) { 529 | 530 | if (debug) 531 | console.log('Triggering napalm!'); 532 | 533 | castAbility(ABILITIES.NAPALM); 534 | } 535 | 536 | // Cluster Bomb 537 | else if (target.m_data.type === 0 && hasAbility(ABILITIES.CLUSTER_BOMB) && targetPercentHPRemaining >= useNukeOnSpawnerAbovePercent && currentLane.enemies.length >= 4) { 538 | 539 | if (debug) 540 | console.log('Triggering cluster bomb!'); 541 | 542 | castAbility(ABILITIES.CLUSTER_BOMB); 543 | } 544 | 545 | // Boss Nuke Rounds 546 | if (isBoss) { 547 | 548 | // Max Elemental Damage 549 | if (hasAbility(ABILITIES.MAX_ELEMENTAL_DAMAGE) && autoUseConsumables && targetPercentHPRemaining > useNukeOnBossAbovePercent) { 550 | if (debug) 551 | console.log('Using Max Elemental Damage on boss.'); 552 | 553 | castAbility(ABILITIES.MAX_ELEMENTAL_DAMAGE); 554 | } 555 | 556 | // Reflect Damage 557 | if (hasAbility(ABILITIES.REFLECT_DAMAGE) && autoUseConsumables && targetPercentHPRemaining > useNukeOnBossAbovePercent) { 558 | if (debug) 559 | console.log('Using Reflect Damage on boss.'); 560 | 561 | castAbility(ABILITIES.REFLECT_DAMAGE); 562 | } 563 | } 564 | } 565 | 566 | //Use cases for bosses 567 | else if (!nukeBosses && isBoss) { 568 | if(!nukeBosses) { 569 | //Raining Gold 570 | if (hasAbility(ABILITIES.RAINING_GOLD) && autoUseConsumables && targetPercentHPRemaining > useRainingGoldAbovePercent && timeToTargetDeath > 30 && lvl > CONTROL.disableGoldRainLevels && (lvl <= CONTROL.speedThreshold || lvl % CONTROL.rainingRounds === 0)) { 571 | if (debug) 572 | console.log('Using Raining Gold on boss.'); 573 | 574 | castAbility(ABILITIES.RAINING_GOLD); 575 | } 576 | } 577 | } 578 | 579 | // Metal Detector 580 | var treasureReady = hasAbility(ABILITIES.TREASURE) && autoUseConsumables; 581 | if ((isBoss || target.m_data.type == 4) && timeToTargetDeath < 10) { 582 | if (hasAbility(ABILITIES.METAL_DETECTOR) || treasureReady) { 583 | if (treasureReady) { 584 | if (debug) 585 | console.log('Using Metal Detector via Treasure.'); 586 | castAbility(ABILITIES.TREASURE); 587 | } else { 588 | if (debug) 589 | console.log('Using Metal Detector.'); 590 | castAbility(ABILITIES.METAL_DETECTOR); 591 | } 592 | } 593 | } 594 | } 595 | 596 | //Estimate average player HP Percent in lane 597 | var laneTotalPctHP = 0; 598 | var laneTotalCount = 0; 599 | for (var i = 1; i < 10; i++) { 600 | var HPGuess = ((i - 1) * 10 + 5); 601 | laneTotalPctHP += HPGuess * currentLane.player_hp_buckets[i]; 602 | laneTotalCount += currentLane.player_hp_buckets[i]; 603 | } 604 | var avgLanePercentHP = laneTotalPctHP / laneTotalCount; 605 | var percentAlive = laneTotalCount / (laneTotalCount + currentLane.player_hp_buckets[0]) * 100; 606 | 607 | // Medics 608 | if ((percentHPRemaining <= useMedicsAtPercent || (avgLanePercentHP <= useMedicsAtLanePercent && percentAlive > useMedicsAtLanePercentAliveReq)) && !g_Minigame.m_CurrentScene.m_bIsDead) { 609 | if (debug) { 610 | if (percentHPRemaining <= useMedicsAtPercent) 611 | console.log("Health below threshold. Need medics!"); 612 | if (avgLanePercentHP <= useMedicsAtLanePercent && percentAlive > useMedicsAtLanePercentAliveReq) 613 | console.log("Average lane below threshold. Need medics!"); 614 | } 615 | 616 | // Only use if there isn't already a Medics active? 617 | var pumpedUpReady = hasAbility(ABILITIES.PUMPED_UP) && autoUseConsumables; 618 | var stealHealthReady = hasAbility(ABILITIES.STEAL_HEALTH) && autoUseConsumables; 619 | if ((hasAbility(ABILITIES.MEDICS) || pumpedUpReady) && currentLaneHasAbility(ABILITIES.MEDICS) < 2) { 620 | 621 | if (pumpedUpReady) { 622 | if (debug) 623 | console.log("Using Medics via Pumped Up!"); 624 | castAbility(ABILITIES.PUMPED_UP); 625 | } else { 626 | if (debug) 627 | console.log("Using Medics!"); 628 | castAbility(ABILITIES.MEDICS); 629 | } 630 | } else if (stealHealthReady && percentHPRemaining <= useMedicsAtPercent) { 631 | if (debug) 632 | console.log("Using Steal Health in place of Medics!"); 633 | castAbility(ABILITIES.STEAL_HEALTH); 634 | } else if (debug) 635 | console.log("No medics to unleash!"); 636 | } 637 | 638 | // Resurrect 639 | if (hasAbility(ABILITIES.RESURRECTION) && autoUseConsumables) { 640 | if (currentLane.player_hp_buckets[0] >= useResurrectToSaveCount) { 641 | if (debug) 642 | console.log('Using resurrection to save ' + currentLane.player_hp_buckets[0] + ' lane allies.'); 643 | castAbility(ABILITIES.RESURRECTION); 644 | } 645 | } 646 | 647 | // Like New 648 | if (hasAbility(ABILITIES.LIKE_NEW) && autoUseConsumables) { 649 | var totalCD = 0; 650 | for (i = 5; i <= 12; i++) { 651 | if (abilityIsUnlocked(i)) 652 | totalCD += abilityCooldown(i); 653 | } 654 | 655 | if (totalCD * 1000 >= useLikeNewAboveCooldown) { 656 | if (debug) 657 | console.log('Using like new to save a total of ' + totalCD + ' seconds of cooldown.'); 658 | castAbility(ABILITIES.LIKE_NEW); 659 | } 660 | } 661 | 662 | }, abilityUseCheckFreq); 663 | 664 | console.log("autoAbilityUser has been started."); 665 | } 666 | 667 | function startAutoItemUser() { 668 | autoUseConsumables = true; 669 | console.log("Automatic use of consumables has been enabled."); 670 | } 671 | 672 | function stopAutoAbilityUser() { 673 | if (autoAbilityUser) { 674 | clearInterval(autoAbilityUser); 675 | autoAbilityUser = null; 676 | console.log("autoAbilityUser has been stopped."); 677 | } else 678 | console.log("No autoAbilityUser is running to stop."); 679 | } 680 | 681 | function stopAutoItemUser() { 682 | autoUseConsumables = false; 683 | console.log("Automatic use of consumables has been disabled."); 684 | } 685 | 686 | function disableAutoNukes() { 687 | useNukeOnSpawnerAbovePercent = 200; 688 | console.log('Automatic nukes have been disabled'); 689 | } 690 | 691 | // ================ AUTO RESPAWNER ================ 692 | function startAutoRespawner() { 693 | if (autoRespawner) { 694 | console.log("autoRespawner is already running!"); 695 | return; 696 | } 697 | 698 | autoRespawner = setInterval(function() { 699 | if (debug) 700 | console.log('Checking if the player is dead.'); 701 | 702 | // Credit to /u/kolodz for base code. http://www.reddit.com/r/SteamMonsterGame/comments/39joz2/javascript_auto_respawn/ 703 | if (g_Minigame.m_CurrentScene.m_bIsDead) { 704 | if (debug) 705 | console.log('Player is dead. Respawning.'); 706 | 707 | RespawnPlayer(); 708 | } 709 | }, respawnCheckFreq); 710 | 711 | console.log("autoRespawner has been started."); 712 | } 713 | 714 | function stopAutoRespawner() { 715 | if (autoRespawner) { 716 | clearInterval(autoRespawner); 717 | autoRespawner = null; 718 | console.log("autoRespawner has been stopped."); 719 | } else 720 | console.log("No autoRespawner is running to stop."); 721 | } 722 | 723 | // ================ AUTO TARGET SWAPPER ================ 724 | function startAutoTargetSwapper() { 725 | if (autoTargetSwapper) { 726 | console.log("autoTargetSwapper is already running!"); 727 | return; 728 | } 729 | 730 | updateUserElementMultipliers(); 731 | autoTargetSwapperElementUpdate = setInterval(updateUserElementMultipliers, elementUpdateRate); 732 | 733 | autoTargetSwapper = setInterval(function() { 734 | 735 | if (debug) 736 | console.log('Looking for a new target.'); 737 | 738 | var currentTarget = getTarget(); 739 | g_Minigame.m_CurrentScene.m_rgEnemies.each(function(potentialTarget) { 740 | if (compareMobPriority(potentialTarget, currentTarget)) 741 | currentTarget = potentialTarget; 742 | }); 743 | 744 | //Switch to that target 745 | var oldTarget = getTarget(); 746 | if (currentTarget.m_data && oldTarget.m_data && currentTarget.m_data.id != oldTarget.m_data.id) { 747 | if (debug && swapReason !== null) { 748 | console.log(swapReason); 749 | swapReason = null; 750 | } 751 | 752 | if (g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane != currentTarget.m_nLane) 753 | g_Minigame.m_CurrentScene.TryChangeLane(currentTarget.m_nLane); 754 | g_Minigame.m_CurrentScene.TryChangeTarget(currentTarget.m_nID); 755 | 756 | } 757 | //Move back to lane if still targetting 758 | else if (currentTarget.m_data && g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane != currentTarget.m_nLane) { 759 | g_Minigame.m_CurrentScene.TryChangeLane(currentTarget.m_nLane); 760 | } 761 | 762 | }, targetSwapperFreq); 763 | 764 | console.log("autoTargetSwapper has been started."); 765 | } 766 | 767 | function stopAutoTargetSwapper() { 768 | if (autoTargetSwapper) { 769 | clearInterval(autoTargetSwapper); 770 | autoTargetSwapper = null; 771 | console.log("autoTargetSwapper has been stopped."); 772 | } else 773 | console.log("No autoTargetSwapper is running to stop."); 774 | } 775 | 776 | // ================ AUTO UPGRADE MANAGER ================ 777 | var upgradeManagerPrefilter; 778 | if (!upgradeManagerPrefilter) { 779 | // add prefilter on first run 780 | $J.ajaxPrefilter(function() { 781 | // this will be defined by the end of the script 782 | if (upgradeManagerPrefilter !== undefined) { 783 | upgradeManagerPrefilter.apply(this, arguments); 784 | } 785 | }); 786 | } 787 | 788 | function startAutoUpgradeManager() { 789 | if (autoUpgradeManager) { 790 | console.log("UpgradeManager is already running!"); 791 | return; 792 | } 793 | 794 | /************ 795 | * SETTINGS * 796 | ************/ 797 | 798 | // Should we highlight the item we're going for next? 799 | var highlightNext = true; 800 | 801 | // Should we automatically by the next item? 802 | var autoBuyNext = true; 803 | 804 | // How many elements do you want to upgrade? If we decide to upgrade an 805 | // element, we'll try to always keep this many as close in levels as we 806 | // can, and ignore the rest. 807 | var elementalSpecializations = 1; 808 | 809 | // To estimate the overall boost in damage from upgrading an element, 810 | // we sort the elements from highest level to lowest, then multiply 811 | // each one's level by the number in the corresponding spot to get a 812 | // weighted average of their effects on your overall damage per click. 813 | // If you don't prioritize lanes that you're strongest against, this 814 | // will be [0.25, 0.25, 0.25, 0.25], giving each element an equal 815 | // scaling. However, this defaults to [0.4, 0.3, 0.2, 0.1] under the 816 | // assumption that you will spend much more time in lanes with your 817 | // strongest elements. 818 | var elementalCoefficients = [0.4, 0.3, 0.2, 0.1]; 819 | 820 | // To include passive DPS upgrades (Auto-fire, etc.) we have to scale 821 | // down their DPS boosts for an accurate comparison to clicking. This 822 | // is approximately how many clicks per second we should assume you are 823 | // consistently doing. If you have an autoclicker, this is easy to set. 824 | var clickFrequency = clicksPerSecond + Math.ceil(autoClickerVariance / 2); 825 | 826 | /*********** 827 | * GLOBALS * 828 | ***********/ 829 | var scene = g_Minigame.CurrentScene(); 830 | var waitingForUpdate = false; 831 | 832 | var next = { 833 | id: -1, 834 | cost: 0 835 | }; 836 | 837 | var necessary = [ 838 | { 839 | id: 0, 840 | level: 1 841 | }, // Light Armor 842 | { 843 | id: 11, 844 | level: 1 845 | }, // Medics 846 | { 847 | id: 2, 848 | level: 10 849 | }, // Armor Piercing Round 850 | { 851 | id: 1, 852 | level: 10 853 | }, // Auto-fire Cannon 854 | ]; 855 | 856 | var gAbilities = [ 857 | 11, // Medics 858 | 13, // Good Luck Charms 859 | 16, // Tactical Nuke 860 | 18, // Napalm 861 | 17, // Cluster Bomb 862 | 14, // Metal Detector 863 | 15, // Decrease Cooldowns 864 | 12, // Morale Booster 865 | ]; 866 | 867 | var gLuckyShot = 7; 868 | var gBossLoot = 19; 869 | var gElementalUpgrades = [3, 4, 5, 6]; // Fire, Water, Earth, Air 870 | 871 | var gHealthUpgrades = []; 872 | var gAutoUpgrades = []; 873 | var gDamageUpgrades = []; 874 | 875 | Object.keys(scene.m_rgTuningData.upgrades) 876 | .sort(function(a, b) { 877 | return a - b; 878 | }) // why is default sort string comparison 879 | .forEach(function(id) { 880 | var upgrade = scene.m_rgTuningData.upgrades[id]; 881 | switch (upgrade.type) { 882 | case 0: 883 | gHealthUpgrades.push(+id); 884 | break; 885 | case 1: 886 | gAutoUpgrades.push(+id); 887 | break; 888 | case 2: 889 | gDamageUpgrades.push(+id); 890 | break; 891 | } 892 | }); 893 | 894 | /*********** 895 | * HELPERS * 896 | ***********/ 897 | var getElementals = (function() { 898 | var cache = false; 899 | return function(refresh) { 900 | if (!cache || refresh) { 901 | cache = gElementalUpgrades 902 | .map(function(id) { 903 | return { 904 | id: id, 905 | level: scene.GetUpgradeLevel(id) 906 | }; 907 | }) 908 | .sort(function(a, b) { 909 | return b.level - a.level; 910 | }); 911 | } 912 | return cache; 913 | }; 914 | })(); 915 | 916 | var getElementalCoefficient = function(elementals) { 917 | elementals = elementals || getElementals(); 918 | return scene.m_rgTuningData.upgrades[4].multiplier * 919 | elementals.reduce(function(sum, elemental, i) { 920 | return sum + elemental.level * elementalCoefficients[i]; 921 | }, 0); 922 | }; 923 | 924 | var canUpgrade = function(id) { 925 | // do we even have the upgrade? 926 | if (!scene.bHaveUpgrade(id)) return false; 927 | 928 | // does it have a required upgrade? 929 | var data = scene.m_rgTuningData.upgrades[id]; 930 | var required = data.required_upgrade; 931 | if (required !== undefined) { 932 | // is it at the required level to unlock? 933 | var level = data.required_upgrade_level || 1; 934 | return (level <= scene.GetUpgradeLevel(required)); 935 | } 936 | 937 | // otherwise, we're good to go! 938 | return true; 939 | }; 940 | 941 | var calculateUpgradeTree = function(id, level) { 942 | var data = scene.m_rgTuningData.upgrades[id]; 943 | var boost = 0; 944 | var cost = 0; 945 | var parent; 946 | 947 | var cur_level = scene.GetUpgradeLevel(id); 948 | if (level === undefined) level = cur_level + 1; 949 | 950 | // for each missing level, add boost and cost 951 | for (var level_diff = level - cur_level; level_diff > 0; level_diff--) { 952 | boost += data.multiplier; 953 | cost += data.cost * Math.pow(data.cost_exponential_base, level - level_diff); 954 | } 955 | 956 | // recurse for required upgrades 957 | var required = data.required_upgrade; 958 | if (required !== undefined) { 959 | var parents = calculateUpgradeTree(required, data.required_upgrade_level || 1); 960 | if (parents.cost > 0) { 961 | boost += parents.boost; 962 | cost += parents.cost; 963 | parent = parents.required || required; 964 | } 965 | } 966 | 967 | return { 968 | boost: boost, 969 | cost: cost, 970 | required: parent 971 | }; 972 | }; 973 | 974 | var necessaryUpgrade = function() { 975 | var best = { 976 | id: -1, 977 | cost: 0 978 | }; 979 | var wanted, id; 980 | while (necessary.length > 0) { 981 | wanted = necessary[0]; 982 | id = wanted.id; 983 | if (scene.GetUpgradeLevel(id) < wanted.level) { 984 | best = { 985 | id: id, 986 | cost: scene.GetUpgradeCost(id) 987 | }; 988 | break; 989 | } 990 | necessary.shift(); 991 | } 992 | return best; 993 | }; 994 | 995 | var nextAbilityUpgrade = function() { 996 | var best = { 997 | id: -1, 998 | cost: 0 999 | }; 1000 | if (autoBuyAbilities) { 1001 | gAbilities.some(function(id) { 1002 | if (canUpgrade(id) && scene.GetUpgradeLevel(id) < 1) { 1003 | best = { 1004 | id: id, 1005 | cost: scene.GetUpgradeCost(id) 1006 | }; 1007 | return true; 1008 | } 1009 | }); 1010 | } 1011 | return best; 1012 | }; 1013 | 1014 | var bestHealthUpgrade = function() { 1015 | var best = { 1016 | id: -1, 1017 | cost: 0, 1018 | hpg: 0 1019 | }; 1020 | var result, hpg; 1021 | gHealthUpgrades.forEach(function(id) { 1022 | result = calculateUpgradeTree(id); 1023 | hpg = scene.m_rgTuningData.player.hp * result.boost / result.cost; 1024 | if (hpg >= best.hpg) { 1025 | if (result.required !== undefined) id = result.required; 1026 | cost = scene.GetUpgradeCost(id); 1027 | if (cost <= scene.m_rgPlayerData.gold || (best.cost === 0 || cost < best.cost)) { // TODO 1028 | best = { 1029 | id: id, 1030 | cost: cost, 1031 | hpg: hpg 1032 | }; 1033 | } 1034 | } 1035 | }); 1036 | return best; 1037 | }; 1038 | 1039 | var bestDamageUpgrade = function() { 1040 | var best = { 1041 | id: -1, 1042 | cost: 0, 1043 | dpg: 0 1044 | }; 1045 | var result, data, cost, dpg, boost; 1046 | 1047 | var dpc = scene.m_rgPlayerTechTree.damage_per_click; 1048 | var base_dpc = scene.m_rgTuningData.player.damage_per_click; 1049 | var critmult = scene.m_rgPlayerTechTree.damage_multiplier_crit; 1050 | var unusedCritChance = getAbilityItemQuantity(18) * 0.01; // Take unused Crit items into account, since they will probably be applied soon 1051 | var critrate = Math.min(scene.m_rgPlayerTechTree.crit_percentage + unusedCritChance, 1); 1052 | var elementals = getElementals(); 1053 | var elementalCoefficient = getElementalCoefficient(elementals); 1054 | 1055 | // check auto damage upgrades 1056 | gAutoUpgrades.forEach(function(id) { 1057 | result = calculateUpgradeTree(id); 1058 | dpg = (scene.m_rgPlayerTechTree.base_dps * result.boost / clickFrequency) / result.cost; 1059 | if (dpg >= best.dpg) { 1060 | if (result.required !== undefined) id = result.required; 1061 | best = { 1062 | id: id, 1063 | cost: scene.GetUpgradeCost(id), 1064 | dpg: dpg 1065 | }; 1066 | } 1067 | }); 1068 | 1069 | // check Lucky Shot 1070 | if (canUpgrade(gLuckyShot)) { // lazy check because prereq is necessary upgrade 1071 | data = scene.m_rgTuningData.upgrades[gLuckyShot]; 1072 | boost = dpc * critrate * data.multiplier; 1073 | cost = scene.GetUpgradeCost(gLuckyShot); 1074 | dpg = boost / cost; 1075 | if (dpg >= best.dpg) { 1076 | best = { 1077 | id: gLuckyShot, 1078 | cost: cost, 1079 | dpg: dpg 1080 | }; 1081 | } 1082 | } 1083 | 1084 | // check click damage upgrades 1085 | gDamageUpgrades.forEach(function(id) { 1086 | result = calculateUpgradeTree(id); 1087 | dpg = base_dpc * result.boost * (critrate * critmult + (1 - critrate) * elementalCoefficient) / result.cost; 1088 | if (dpg >= best.dpg) { 1089 | if (result.required !== undefined) id = result.required; 1090 | best = { 1091 | id: id, 1092 | cost: scene.GetUpgradeCost(id), 1093 | dpg: dpg 1094 | }; 1095 | } 1096 | }); 1097 | 1098 | // check elementals 1099 | data = scene.m_rgTuningData.upgrades[4]; 1100 | var elementalLevels = elementals.reduce(function(sum, elemental) { 1101 | return sum + elemental.level; 1102 | }, 1); 1103 | cost = data.cost * Math.pow(data.cost_exponential_base, elementalLevels); 1104 | 1105 | // - make new elementals array for testing 1106 | var testElementals = elementals.map(function(elemental) { 1107 | return { 1108 | level: elemental.level 1109 | }; 1110 | }); 1111 | var upgradeLevel = testElementals[elementalSpecializations - 1].level; 1112 | testElementals[elementalSpecializations - 1].level++; 1113 | if (elementalSpecializations > 1) { 1114 | // swap positions if upgraded elemental now has bigger level than (originally) next highest 1115 | var prevElem = testElementals[elementalSpecializations - 2].level; 1116 | if (prevElem <= upgradeLevel) { 1117 | testElementals[elementalSpecializations - 2].level = upgradeLevel + 1; 1118 | testElementals[elementalSpecializations - 1].level = prevElem; 1119 | } 1120 | } 1121 | 1122 | // - calculate stats 1123 | boost = dpc * (1 - critrate) * (getElementalCoefficient(testElementals) - elementalCoefficient); 1124 | dpg = boost / cost; 1125 | if (dpg > best.dpg) { // give base damage boosters priority 1126 | // find all elements at upgradeLevel and randomly pick one 1127 | var match = elementals.filter(function(elemental) { 1128 | return elemental.level == upgradeLevel; 1129 | }); 1130 | match = match[Math.floor(Math.random() * match.length)].id; 1131 | best = { 1132 | id: match, 1133 | cost: cost, 1134 | dpg: dpg 1135 | }; 1136 | } 1137 | 1138 | // Boss Loot Upgrade 1139 | var lootRate = g_Minigame.m_CurrentScene.m_rgPlayerTechTree.boss_loot_drop_percentage * 100; 1140 | var levelTime = (g_Minigame.m_CurrentScene.m_rgGameData.timestamp - g_Minigame.m_CurrentScene.m_rgGameData.timestamp_game_start) / g_Minigame.m_CurrentScene.m_rgGameData.level; 1141 | var lootCost = scene.GetUpgradeCost(gBossLoot); 1142 | var lootEfficient = false; 1143 | 1144 | // Case1: drop rate < 50%: if cost is <10% that of the 'best upgrade', and room isn't moving slowly. 1145 | // Case2: drop rate >=50%: if cost is <1% that of the 'best upgrade', and room isn't moving slowly. 1146 | if ( (lootRate < 50 && lootCost < best.cost * 0.1 && lootCost < best.cost * 10 / levelTime) || (lootRate < 100 && lootCost < best.cost * 0.01 && lootCost < best.cost / levelTime) ) { 1147 | lootEfficient = true; 1148 | } 1149 | 1150 | if (canUpgrade(gBossLoot) && lootEfficient) { 1151 | best = { 1152 | id: gBossLoot, 1153 | cost: lootCost, 1154 | dpg: gBossLoot.cost 1155 | }; 1156 | } 1157 | 1158 | return best; 1159 | }; 1160 | 1161 | var timeToDie = (function() { 1162 | var cache = false; 1163 | return function(refresh) { 1164 | if (cache === false || refresh) { 1165 | var maxHp = scene.m_rgPlayerTechTree.max_hp; 1166 | var enemyDps = scene.m_rgGameData.lanes.reduce(function(max, lane) { 1167 | return Math.max(max, lane.enemies.reduce(function(sum, enemy) { 1168 | return sum + enemy.dps; 1169 | }, 0)); 1170 | }, 0); 1171 | cache = maxHp / (enemyDps || scene.m_rgGameData.level * 4); 1172 | } 1173 | return cache; 1174 | }; 1175 | })(); 1176 | 1177 | var updateNext = function() { 1178 | next = necessaryUpgrade(); 1179 | if (next.id === -1) { 1180 | if (timeToDie() < survivalTime) { 1181 | next = bestHealthUpgrade(); 1182 | } else { 1183 | var damage = bestDamageUpgrade(); 1184 | var ability = nextAbilityUpgrade(); 1185 | next = (damage.cost < ability.cost || ability.id === -1) ? damage : ability; 1186 | } 1187 | } 1188 | if (next.id !== -1) { 1189 | if (highlightNext) { 1190 | $J('.next_upgrade').removeClass('next_upgrade'); 1191 | $J(document.getElementById('upgr_' + next.id)).addClass('next_upgrade'); 1192 | } 1193 | if (debug) { 1194 | console.log( 1195 | 'next buy:', 1196 | scene.m_rgTuningData.upgrades[next.id].name, 1197 | '(' + FormatNumberForDisplay(next.cost) + ')' 1198 | ); 1199 | } 1200 | } 1201 | }; 1202 | 1203 | var hook = function(base, method, func) { 1204 | var original = method + '_upgradeManager'; 1205 | if (!base.prototype[original]) base.prototype[original] = base.prototype[method]; 1206 | base.prototype[method] = function() { 1207 | this[original].apply(this, arguments); 1208 | func.apply(this, arguments); 1209 | }; 1210 | }; 1211 | 1212 | /******** 1213 | * MAIN * 1214 | ********/ 1215 | // ---------- JS hooks ---------- 1216 | hook(CSceneGame, 'TryUpgrade', function() { 1217 | // if it's a valid try, we should reevaluate after the update 1218 | if (this.m_bUpgradesBusy) { 1219 | if (highlightNext) $J(document.body).addClass('upgrade_waiting'); 1220 | next.id = -1; 1221 | } 1222 | }); 1223 | 1224 | hook(CSceneGame, 'ChangeLevel', function() { 1225 | // recalculate enemy DPS to see if we can survive this level 1226 | if (timeToDie(true) < survivalTime) updateNext(); 1227 | }); 1228 | 1229 | upgradeManagerPrefilter = function(opts, origOpts, xhr) { 1230 | if (/ChooseUpgrade/.test(opts.url)) { 1231 | xhr 1232 | .success(function() { 1233 | // wait as short a delay as possible 1234 | // then we re-run to figure out the next item to queue 1235 | window.setTimeout(upgradeManager, 0); 1236 | }) 1237 | .fail(function() { 1238 | // we're desynced. wait til data refresh 1239 | // m_bUpgradesBusy was not set to false 1240 | scene.m_bNeedTechTree = true; 1241 | waitingForUpdate = true; 1242 | }); 1243 | } else if (/GetPlayerData/.test(opts.url)) { 1244 | if (waitingForUpdate) { 1245 | xhr.success(function(result) { 1246 | var message = g_Server.m_protobuf_GetPlayerDataResponse.decode(result).toRaw(true, true); 1247 | if (message.tech_tree) { 1248 | // done waiting! no longer busy 1249 | waitingForUpdate = false; 1250 | scene.m_bUpgradesBusy = false; 1251 | window.setTimeout(upgradeManager, 0); 1252 | } 1253 | }); 1254 | } 1255 | } 1256 | }; 1257 | 1258 | // ---------- CSS ---------- 1259 | $J(document.body).removeClass('upgrade_waiting'); 1260 | $J('.next_upgrade').removeClass('next_upgrade'); 1261 | if (highlightNext) { 1262 | var cssPrefix = function(property, value) { 1263 | return '-webkit-' + property + ': ' + value + '; ' + property + ': ' + value + ';'; 1264 | }; 1265 | 1266 | var css = 1267 | '.next_upgrade { ' + cssPrefix('filter', 'brightness(1.5) contrast(2)') + ' }\n' + 1268 | '.next_upgrade.cantafford { ' + cssPrefix('filter', 'contrast(1.3)') + ' }\n' + 1269 | '.next_upgrade .info .name, .next_upgrade.element_upgrade .level { color: #e1b21e; }\n' + 1270 | '#upgrades .next_upgrade .link { ' + cssPrefix('filter', 'brightness(0.8) hue-rotate(120deg)') + ' }\n' + 1271 | '#elements .next_upgrade .link { ' + cssPrefix('filter', 'hue-rotate(120deg)') + ' }\n' + 1272 | '.next_upgrade .cost { ' + cssPrefix('filter', 'hue-rotate(-120deg)') + ' }\n' + 1273 | '.upgrade_waiting .next_upgrade { ' + cssPrefix('animation', 'blink 1s infinite alternate') + ' }\n' + 1274 | '@-webkit-keyframes blink { to { opacity: 0.5; } }\n' + 1275 | '@keyframes blink { to { opacity: 0.5; } }'; 1276 | 1277 | var style = document.getElementById('upgradeManagerStyles'); 1278 | if (!style) { 1279 | style = document.createElement('style'); 1280 | $J(style).attr('id', 'upgradeManagerStyles').appendTo('head'); 1281 | } 1282 | $J(style).html(css); 1283 | } 1284 | 1285 | // ---------- Timer ---------- 1286 | function upgradeManager() { 1287 | if (debug) 1288 | console.log('Checking for worthwhile upgrades'); 1289 | 1290 | scene = g_Minigame.CurrentScene(); 1291 | 1292 | // tried to buy upgrade and waiting for reply; don't do anything 1293 | if (scene.m_bUpgradesBusy) return; 1294 | 1295 | // no item queued; refresh stats and queue next item 1296 | if (next.id === -1) { 1297 | if (highlightNext) $J(document.body).removeClass('upgrade_waiting'); 1298 | getElementals(true); 1299 | timeToDie(true); 1300 | updateNext(); 1301 | } 1302 | 1303 | // item queued; buy if we can afford it 1304 | if (next.id !== -1 && autoBuyNext) { 1305 | if (next.cost <= scene.m_rgPlayerData.gold) { 1306 | var link = $J('.link', document.getElementById('upgr_' + next.id)).get(0); 1307 | if (link) { 1308 | scene.TryUpgrade(link); 1309 | } else { 1310 | console.error('failed to find upgrade'); 1311 | } 1312 | } 1313 | } 1314 | } 1315 | 1316 | autoUpgradeManager = setInterval(upgradeManager, upgradeManagerFreq); 1317 | 1318 | console.log("autoUpgradeManager has been started."); 1319 | } 1320 | 1321 | function stopAutoUpgradeManager() { 1322 | if (autoUpgradeManager) { 1323 | clearInterval(autoUpgradeManager); 1324 | autoUpgradeManager = null; 1325 | 1326 | //Remove hooks 1327 | function removeHook(base, method) { 1328 | base.prototype[method] = (base.prototype[method + '_upgradeManager'] || base.prototype[method]); 1329 | } 1330 | 1331 | removeHook(CSceneGame, 'TryUpgrade'); 1332 | removeHook(CSceneGame, 'ChangeLevel'); 1333 | 1334 | //Clear the visual 1335 | $J(document.body).removeClass('upgrade_waiting'); 1336 | $J('.next_upgrade').removeClass('next_upgrade'); 1337 | 1338 | console.log("autoUpgradeManager has been stopped."); 1339 | } else 1340 | console.log("No autoUpgradeManager is running to stop."); 1341 | } 1342 | 1343 | 1344 | // ================ SLOW RENDERING ================ 1345 | var gameOldRenderer = function() {}; 1346 | function startFPSThrottle(){ 1347 | if (fpsThrottle) { 1348 | console.log("fpsThrottling is already running!"); 1349 | return; 1350 | } 1351 | 1352 | gameOldRenderer = g_Minigame.Render; 1353 | var ticker = PIXI.ticker.shared; 1354 | ticker.autoStart = false; 1355 | ticker.stop(); 1356 | g_Minigame.Render = function() {}; 1357 | 1358 | // Visual Display for peoples 1359 | $J("#uicontainer").append('
Currently in slow FPS mode to maximize performance, toggle this off in the settings if you want full FPS
'); 1360 | $J("#slow_fps_dialog").css({ "position": "absolute", "top": "0", "left":"0", "right":"0", "height":"100%", "background-color": "rgba(0,0,0,0.6)", "color":"white", "text-align": "center", "font-size":"12px", "z-index":"9", "padding": "10px"}); 1361 | 1362 | 1363 | var fpsThrottleRender = function() { 1364 | if (!gameRunning()) return; 1365 | m_nLastTick = false; 1366 | g_Minigame.CurrentScene().Tick(); 1367 | requestAnimationFrame(function() { g_Minigame.Renderer.render(g_Minigame.CurrentScene().m_Container); }); 1368 | }; 1369 | 1370 | // Custom render cycle 1371 | fpsThrottle = setInterval(fpsThrottleRender, slowRenderingFreq); 1372 | console.log("fpsThrottle has been started."); 1373 | 1374 | } 1375 | 1376 | function stopFPSThrottle() { 1377 | if (fpsThrottle) { 1378 | clearInterval(fpsThrottle); 1379 | 1380 | var ticker = PIXI.ticker.shared; 1381 | ticker.autoStart = true; 1382 | ticker.start(); 1383 | 1384 | g_Minigame.Render = gameOldRenderer; 1385 | g_Minigame.Render(); 1386 | 1387 | $J("#slow_fps_dialog").remove(); 1388 | fpsThrottle = null; 1389 | 1390 | console.log("fpsThrottle has been stopped."); 1391 | } else 1392 | console.log("No fpsThrottle is running to stop."); 1393 | } 1394 | 1395 | 1396 | // ================ UI ELEMENTS ================ 1397 | function initGUI() { 1398 | updatePlayersInLane(); 1399 | updatePlayersInRoom(); 1400 | setInterval(function() { 1401 | updatePlayersInLane(); 1402 | updatePlayersInRoom(); 1403 | }, 10000); 1404 | addPointer(); 1405 | addExtraUI(); 1406 | 1407 | // Overwrite this function so it doesn't delete our sexy pointer 1408 | CSceneGame.prototype.ClearNewPlayer = function() { 1409 | if (this.m_spriteFinger) { 1410 | var bPlayedBefore = WebStorage.SetLocal('mg_how2click', 1); 1411 | $J('#newplayer').hide(); 1412 | } 1413 | }; 1414 | 1415 | // Overwrite this function so our loot notifications do not repeat until we actually have a new one 1416 | CUI.prototype.UpdateLootNotification = function() { 1417 | if (this.m_Game.m_rgPlayerData.loot && this.m_Game.m_rgPlayerData.loot.length !== 0 && this.m_Game.m_rgGameData.level >= lastLootLevel + 10 && (lastLootCache.length === 0 || lastLootCache.toString() !== this.m_Game.m_rgPlayerData.loot.toString())) { 1418 | $J("#loot_notification").show(); 1419 | var abilities = this.m_Game.m_rgTuningData.abilities; 1420 | var strLootNames = ""; 1421 | for (var i = 0; i < this.m_Game.m_rgPlayerData.loot.length; ++i) { 1422 | var loot = this.m_Game.m_rgPlayerData.loot[i]; 1423 | if (i !== 0) { 1424 | strLootNames += ", "; 1425 | } 1426 | strLootNames += abilities[loot.ability].name; 1427 | } 1428 | $J("#loot_name").text(strLootNames); 1429 | setTimeout(function() { 1430 | $J("#loot_notification").fadeOut(1000); 1431 | }, 5000); 1432 | lastLootLevel = this.m_Game.m_rgGameData.level; 1433 | lastLootCache = this.m_Game.m_rgPlayerData.loot; 1434 | this.m_Game.m_rgPlayerData.loot = []; 1435 | } 1436 | }; 1437 | } 1438 | 1439 | function addPointer() { 1440 | g_Minigame.m_CurrentScene.m_rgFingerTextures = []; 1441 | var w = 26; 1442 | var h = 49; 1443 | 1444 | for (var y = 0; y < 4; y++) { 1445 | for (var x = 0; x < 5; x++) { 1446 | g_Minigame.m_CurrentScene.m_rgFingerTextures.push(new PIXI.Texture(g_rgTextureCache.pointer.texture, { 1447 | x: x * w, 1448 | y: y * h, 1449 | width: w, 1450 | height: h 1451 | })); 1452 | } 1453 | } 1454 | 1455 | g_Minigame.m_CurrentScene.m_nFingerIndex = 0; 1456 | 1457 | g_Minigame.m_CurrentScene.m_spriteFinger = new PIXI.Sprite(g_Minigame.m_CurrentScene.m_rgFingerTextures[g_Minigame.m_CurrentScene.m_nFingerIndex]); 1458 | g_Minigame.m_CurrentScene.m_spriteFinger.scale.x = g_Minigame.m_CurrentScene.m_spriteFinger.scale.y = 2; 1459 | 1460 | g_Minigame.m_CurrentScene.m_containerParticles.addChild(g_Minigame.m_CurrentScene.m_spriteFinger); 1461 | } 1462 | 1463 | function updatePlayersInLane() { 1464 | // update players in lane 1465 | var players = "???"; 1466 | if (g_Minigame.m_CurrentScene.m_rgLaneData[g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane]) 1467 | players = g_Minigame.m_CurrentScene.m_rgLaneData[g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane].players; 1468 | 1469 | $J("#players_in_lane").html(players); 1470 | } 1471 | 1472 | function updatePlayersInRoom() { 1473 | //Update players in room 1474 | var players = "???"; 1475 | if (g_Minigame.m_CurrentScene.m_rgLaneData[0]) 1476 | players = (g_Minigame.m_CurrentScene.m_rgLaneData[0].players + g_Minigame.m_CurrentScene.m_rgLaneData[1].players + g_Minigame.m_CurrentScene.m_rgLaneData[2].players); 1477 | $J("#players_in_room").html(players); 1478 | } 1479 | 1480 | var endDate = initEndDate(); 1481 | 1482 | function initEndDate() { 1483 | var endDate = new Date(); 1484 | if (endDate.getUTCHours() >= 16) { 1485 | endDate.setUTCDate(endDate.getUTCDate() + 1); 1486 | } 1487 | endDate.setUTCHours(16, 0, 0, 0); 1488 | return endDate; 1489 | } 1490 | 1491 | function updateStats() { 1492 | var getFormattedRemainingTime = function() { 1493 | var secondsUntilEnd = getSecondsUntilEnd(); 1494 | var hrs = Math.floor(secondsUntilEnd / 3600); 1495 | var min = Math.floor((secondsUntilEnd - (hrs * 3600)) / 60); 1496 | var sec = secondsUntilEnd - (hrs * 3600) - (min * 60); 1497 | 1498 | var time = ''; 1499 | if (hrs > 0) { 1500 | if (hrs == 1) { 1501 | time += "an hour"; 1502 | } else { 1503 | time += hrs + " hours"; 1504 | } 1505 | if (min > 1) { 1506 | time += " and " + min + " minute" + (min == 1 ? '' : 's'); 1507 | } 1508 | } else if (min > 0) { 1509 | if (min == 1) { 1510 | time += "a minute"; 1511 | } else { 1512 | time += min + " minutes"; 1513 | } 1514 | if (sec > 1) { 1515 | time += " and " + sec + " second" + (sec == 1 ? '' : 's'); 1516 | } 1517 | } else { 1518 | if (sec <= 1) { 1519 | time += "about a second"; 1520 | } else { 1521 | time += "about " + sec + " seconds"; 1522 | } 1523 | } 1524 | return time; 1525 | }; 1526 | 1527 | $J('#avg_completion_rate').html(parseFloat(getSecondsPerLevel()).toFixed(2)); 1528 | $J("#estimated_end_level").html(Math.round(getSecondsUntilEnd() / getSecondsPerLevel() + g_Minigame.m_CurrentScene.m_rgGameData.level)); 1529 | $J("#remaining_time").html(getFormattedRemainingTime()); 1530 | } 1531 | 1532 | function addExtraUI() { 1533 | //Add in player count for current room 1534 | var old = $J(".title_activity").html(); 1535 | $J(".title_activity").html(old + ' [0 in room]'); 1536 | $J("#gamecontainer").append('
'); 1537 | $J('#settings').css({ 1538 | "position": "absolute", 1539 | "background": "url('" + getUploadedFilePath("master/img/settings.png?v2") + "')", 1540 | "background-repeat": "no-repeat", 1541 | "background-position": "0px 0px", 1542 | "height": "300px", 1543 | "width": "500px", 1544 | "margin-top": "2px", 1545 | "bottom": "-65px", 1546 | "right": "10px", 1547 | "padding-top": "15px", 1548 | "padding-left": "12px" 1549 | }); 1550 | 1551 | //Add replacement settings options 1552 | $J("#settings").append('
Music:
'); 1553 | $J("#settings").append('
SFX:
'); 1554 | $J("#settings").append('
Auto-Clicker:
'); 1555 | $J("#settings").append('
Target Swapper:
'); 1556 | $J("#settings").append('
Ability Use:
'); 1557 | $J("#settings").append('
Consumable Use:
'); 1558 | $J("#settings").append('
Auto Upgrader:
'); 1559 | $J("#settings").append('
Spam StatBoosts:
'); 1560 | $J("#settings").append('
FPS Limiter:
'); 1561 | $J("#settings").append('
Particles:
'); 1562 | $J("#settings").append('
Survival Time: ^ 30 seconds v
'); 1563 | $J("#sfx_toggle").click(function(e) { 1564 | e.stopPropagation(); 1565 | toggleSFX(true); 1566 | }); 1567 | $J("#music_toggle").click(function(e) { 1568 | e.stopPropagation(); 1569 | toggleMusic(true); 1570 | }); 1571 | $J("#autoclicker_toggle").click(function(e) { 1572 | e.stopPropagation(); 1573 | toggleAutoClicker(); 1574 | }); 1575 | $J("#autotargetswapper_toggle").click(function(e) { 1576 | e.stopPropagation(); 1577 | toggleAutoTargetSwapper(); 1578 | }); 1579 | $J("#autoabilityuse_toggle").click(function(e) { 1580 | e.stopPropagation(); 1581 | toggleAutoAbilityUser(); 1582 | }); 1583 | $J("#autoconsume_toggle").click(function(e) { 1584 | e.stopPropagation(); 1585 | toggleAutoItemUser(); 1586 | }); 1587 | $J("#autoupgrade_toggle").click(function(e) { 1588 | e.stopPropagation(); 1589 | toggleAutoUpgradeManager(); 1590 | }); 1591 | $J("#fps_toggle").click(function(e) { 1592 | e.stopPropagation(); 1593 | toggleFPS(); 1594 | }); 1595 | $J("#particles_toggle").click(function(e) { 1596 | e.stopPropagation(); 1597 | toggleSpammer(); 1598 | }); 1599 | 1600 | $J("#spamStatBoosters_toggle").click(function(e) { 1601 | e.stopPropagation(); 1602 | toggleSpamStatBoosters(); 1603 | }); 1604 | $J("#increase_survival").click(function(e) { 1605 | e.stopPropagation(); 1606 | survivalTime += 10; 1607 | WebStorage.SetLocal('survivalTime', survivalTime); 1608 | $J("#survival_time").html(survivalTime); 1609 | }); 1610 | $J("#decrease_survival").click(function(e) { 1611 | e.stopPropagation(); 1612 | if (survivalTime - 10 < 0) { return; } 1613 | survivalTime -= 10; 1614 | WebStorage.SetLocal('survivalTime', survivalTime); 1615 | $J("#survival_time").html(survivalTime); 1616 | }); 1617 | // We force update the icon once to sync with active settings 1618 | toggleSFX(false); 1619 | toggleMusic(false); 1620 | 1621 | // Slide the settings panel out on click 1622 | $J("#settings").click(function() { 1623 | var op = $J("#settings"); 1624 | op.animate({ 1625 | bottom: parseInt(op.css('bottom'), 10) == -65 ? -op.outerHeight() : -65 1626 | }); 1627 | }); 1628 | 1629 | //Statistics 1630 | $J("#gamecontainer").append('
'); 1631 | $J('#statistics').css({ 1632 | "position": "absolute", 1633 | "background": "url('" + getUploadedFilePath("master/img/stats.png") + "')", 1634 | "background-repeat": "no-repeat", 1635 | "background-position": "0px 0px", 1636 | "height": "250px", 1637 | "width": "500px", 1638 | "margin-top": "2px", 1639 | "bottom": "-65px", 1640 | "left": "10px", 1641 | "padding-top": "15px", 1642 | "padding-left": "25px" 1643 | }); 1644 | 1645 | //Add in stats 1646 | $J("#statistics").append('
Dmg Per Click: 0
'); 1647 | $J("#statistics").append('
Dmg Per Second: 0
'); 1648 | $J("#statistics").append('
Critical Chance: 0
'); 1649 | $J("#statistics").append('
Critical Dmg Multiplier: 0
'); 1650 | $J("#statistics").append('
Elemental Multiplier: 0
'); 1651 | $J("#statistics").append('
Elemental DPC: 0
'); 1652 | $J("#statistics").append('
Elemental DPS: 0
'); 1653 | $J("#statistics").append('
Boss Loot Chance: 0
'); 1654 | 1655 | $J("#footer_spacer").css({ 1656 | "height": "175px" 1657 | }); 1658 | $J("canvas").css({ 1659 | "position": "relative", 1660 | "z-index": "5" 1661 | }); 1662 | $J("#uicontainer").css({ 1663 | "z-index": "6" 1664 | }); 1665 | 1666 | //Add in IRC link 1667 | setTimeout(function() { 1668 | $J(".tv_ui").css({"background": "url('" + getUploadedFilePath("master/img/game_frame_tv.png") + "')"}); 1669 | $J("#info_block").append('
'); 1670 | $J("#irc_join").click(function(e) { 1671 | e.stopPropagation(); 1672 | window.open('http://chat.mibbit.com/?channel=%23SMG_'+g_GameID+'&server=irc.mibbit.net&nick='+getUserName(),'_blank'); // Cant seem to find a local storing in js of the players username, so lets just take it from the dropdown 1673 | }); 1674 | }, 1000); 1675 | 1676 | //Update stats 1677 | setInterval(function() { 1678 | function getElementalMul() { 1679 | return Math.max(g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_air, g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_earth, g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_fire, g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_water); 1680 | } 1681 | $J("#statistics #stat_player_dpc .value").html(FormatNumberForDisplay(g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_per_click, 5)); 1682 | $J("#statistics #stat_player_dps .value").html(FormatNumberForDisplay(g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_per_click * clicksPerSecond, 5)); 1683 | $J("#statistics #stat_player_crit .value").html(FormatNumberForDisplay(Math.round(g_Minigame.m_CurrentScene.m_rgPlayerTechTree.crit_percentage * 100), 5) + "%"); 1684 | $J("#statistics #stat_crit_mul .value").html(FormatNumberForDisplay(g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_crit, 5) + "x"); 1685 | $J("#statistics #stat_elemental_mul .value").html(FormatNumberForDisplay(getElementalMul()) + "x"); 1686 | $J("#statistics #stat_elemental_dpc .value").html(FormatNumberForDisplay(getElementalMul() * g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_per_click, 5)); 1687 | $J("#statistics #stat_elemental_dps .value").html(FormatNumberForDisplay(getElementalMul() * g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_per_click * clicksPerSecond, 5)); 1688 | $J("#statistics #stat_boss_loot .value").html(FormatNumberForDisplay(Math.round(g_Minigame.m_CurrentScene.m_rgPlayerTechTree.boss_loot_drop_percentage * 100, 5)) + "%"); 1689 | }, 1000); 1690 | 1691 | $J("#statistics").click(function() { 1692 | var op = $J("#statistics"); 1693 | op.animate({ 1694 | bottom: parseInt(op.css('bottom'), 10) == -65 ? -op.outerHeight() : -65 1695 | }); 1696 | }); 1697 | 1698 | //Other UI elements 1699 | customCSS(); 1700 | addCustomButtons(); 1701 | 1702 | // Put the page footer behind settings 1703 | $J("#footer").css('z-index', -1); 1704 | } 1705 | 1706 | function addCustomButtons() { 1707 | //Smack the TV Easter Egg 1708 | $J('


Smack TV
').insertBefore('#row_bottom'); 1709 | 1710 | //Remove unneeded options area 1711 | $J(".game_options").remove(); 1712 | 1713 | //Bring the close button back 1714 | $J('Close
Game
').insertAfter("#settings"); 1715 | $J(".leave_game_btn").css({ 1716 | "width": "120px", 1717 | "position": "absolute", 1718 | "bottom": "72px", 1719 | "z-index": "12", 1720 | "left": "340px", 1721 | "background": "url('http://steamcommunity-a.akamaihd.net/public/images/promo/towerattack/leave_game_btn.png')", 1722 | "background-repeat": "no-repeat", 1723 | "background-position": "-75px 0px", 1724 | "height": "56px", 1725 | "float": "right", 1726 | "margin-right": "7px", 1727 | "padding-top": "14px", 1728 | "cursor": "pointer", 1729 | }); 1730 | $J('
You can safely close the game or leave this screen at any time—you will continue collecting gold and damaging monsters even while away from your computer. Check back occasionally to see how you\'re doing and use in-game gold to purchase upgrades.
').insertAfter("#settings"); 1731 | $J(".leave_game_helper").css({ 1732 | "left": "150px", 1733 | "top": "initial", 1734 | "bottom": "-20px", 1735 | "z-index": "12" 1736 | }); 1737 | 1738 | //Hide the stupid "Leave game" tooltip 1739 | $J('.leave_game_btn').mouseover(function() { 1740 | $J('.leave_game_helper').show(); 1741 | }) 1742 | .mouseout(function() { 1743 | $J('.leave_game_helper').hide(); 1744 | }); 1745 | $J('.leave_game_helper').hide(); 1746 | 1747 | // Append gameid to breadcrumbs 1748 | var breadcrumbs = document.querySelector('.breadcrumbs'); 1749 | 1750 | if (breadcrumbs) { 1751 | var element = document.createElement('span'); 1752 | element.textContent = ' > '; 1753 | breadcrumbs.appendChild(element); 1754 | 1755 | element = document.createElement('span'); 1756 | element.style.color = '#D4E157'; 1757 | element.style.textShadow = '1px 1px 0px rgba( 0, 0, 0, 0.3 )'; 1758 | element.textContent = 'Room ' + g_GameID; 1759 | breadcrumbs.appendChild(element); 1760 | 1761 | element = document.createElement('span'); 1762 | element.textContent = ' > '; 1763 | breadcrumbs.appendChild(element); 1764 | 1765 | element = document.createElement('span'); 1766 | element.style.color = '#F089B2'; 1767 | element.style.textShadow = '1px 1px 0px rgba( 0, 0, 0, 0.3 )'; 1768 | element.innerHTML = 'Expected Level: 0, Seconds Per Level 0'; 1769 | breadcrumbs.appendChild(element); 1770 | 1771 | element = document.createElement('span'); 1772 | element.textContent = ' > '; 1773 | breadcrumbs.appendChild(element); 1774 | 1775 | element = document.createElement('span'); 1776 | element.style.color = '#ACA5F2'; 1777 | element.style.textShadow = '1px 1px 0px rgba( 0, 0, 0, 0.3 )'; 1778 | element.innerHTML = 'Remaining Time: 0 Seconds.'; 1779 | breadcrumbs.appendChild(element); 1780 | 1781 | updateStats(); 1782 | setInterval(function() { 1783 | updateStats(); 1784 | }, 10000); 1785 | 1786 | if (typeof GM_info != 'undefined') { 1787 | element = document.createElement('span'); 1788 | element.style.cssFloat = 'right'; 1789 | element.style.color = '#D4E157'; 1790 | element.style.textShadow = '1px 1px 0px rgba( 0, 0, 0, 0.3 )'; 1791 | element.innerHTML = '' + GM_info.script.name + ' v' + GM_info.script.version + ''; 1792 | breadcrumbs.appendChild(element); 1793 | } 1794 | } 1795 | 1796 | } 1797 | 1798 | function customCSS() { 1799 | var css = ""; 1800 | css += "#settings .toggle { position: relative; margin-top: 10px; width: 30%; height: 32px; z-index: 0; float: left; margin-left: 10px;} "; 1801 | css += "#settings span.title { position: relative; top: 10px; float: right; right:15px; text-align:right; width: 80%;} "; 1802 | css += "#settings span.value { position: relative; float: right; right:10px; display: inline-block; z-index:11; cursor: pointer;} "; 1803 | css += "#settings span.value.enabled { background: url('" + getUploadedFilePath("master/img/icons.png") + "'); background-repeat: no-repeat;background-position:0px 0px;width:30px;height:30px; } "; 1804 | css += "#settings span.value.enabled:hover { background: url('" + getUploadedFilePath("master/img/icons.png") + "'); background-repeat: no-repeat;background-position:-30px 0px;width:30px;height:30px; } "; 1805 | css += "#settings span.value.disabled { background: url('" + getUploadedFilePath("master/img/icons.png") + "'); background-repeat: no-repeat;background-position:0px -30px;width:30px;height:32px; } "; 1806 | css += "#settings span.value.disabled:hover { background: url('" + getUploadedFilePath("master/img/icons.png") + "'); background-repeat: no-repeat;background-position:-30px -30px;width:30px;height:32px; } "; 1807 | 1808 | css += "#statistics .stat { position: relative; margin-top: 5px; width: 40%; height: 32px; z-index: 0; margin-left: 25px; float:left;} "; 1809 | css += "#statistics span.value { position: relative; float: right; margin-right: 30px; text-align: right; width: 100%;} "; 1810 | css += "#statistics span.title { position: relative; width: 100%; font-weight: bold;} "; 1811 | 1812 | css += ".toggle_btn {background: #d6d6d6;-webkit-border-radius: 7; -moz-border-radius: 7; border-radius: 7px; color: #333; text-decoration: none; text-align: center;cursor: pointer;font-weight: bold;} "; 1813 | css += ".toggle_btn:hover { background: #85c8f2; text-decoration: none; color: #fff;cursor: pointer;font-weight: bold;} "; 1814 | css += "#activeinlanecontainer:hover {height:auto;background:rgba(50,50,50,0.9);padding-bottom:10px;position:absolute;z-index:1} #activeinlanecontainer:hover ~ #activitylog {margin-top:97px} #activitylog {margin-top: 29px} "; 1815 | css += "#leaderboard_wrapper {overflow: hidden; height: 360px; width: 261px; position: relative; margin: 50px 0px 0px 5px; padding: 5px;} #activeinlanecontainer:hover ~ #leaderboard_wrapper {margin-top: 118px}"; 1816 | css += "#info_hp { position:relative; top:28px; text-align: center;}"; 1817 | css += "#irc_join {position: relative; width: 175px; height: 30px; top: -50px; left: 30px; cursor: pointer;}"; 1818 | css += ".arrow {font-weight: bold; background-color: #bebebe; width: 20px; color: #434340; border-radius: 7px; float: right; text-align: center; margin-top: -2px; margin-left: 10px; }"; 1819 | $J('head').append(''); 1820 | } 1821 | 1822 | function updateToggle(id, enabled) { 1823 | if (enabled) { 1824 | $J("#" + id + "_toggle span.value").removeClass("enabled").addClass("disabled"); 1825 | } else { 1826 | $J("#" + id + "_toggle span.value").removeClass("disabled").addClass("enabled"); 1827 | } 1828 | } 1829 | 1830 | function toggleSFX(shouldToggle) { 1831 | var enabled = WebStorage.GetLocal('minigame_mute'); 1832 | if (shouldToggle) { 1833 | enabled = !enabled; 1834 | WebStorage.SetLocal('minigame_mute', enabled); 1835 | } 1836 | updateToggle("sfx", enabled); 1837 | } 1838 | 1839 | function toggleMusic(shouldToggle) { 1840 | if (shouldToggle) { 1841 | g_AudioManager.ToggleMusic(); 1842 | } 1843 | updateToggle("music", WebStorage.GetLocal('minigame_mutemusic')); 1844 | } 1845 | 1846 | function toggleAutoClicker() { 1847 | if (autoClicker) { 1848 | stopAutoClicker(); 1849 | } else { 1850 | startAutoClicker(); 1851 | } 1852 | WebStorage.SetLocal('autoClickerEnabled', (autoClicker !== null)); 1853 | updateToggle("autoclicker", !autoClicker); 1854 | } 1855 | 1856 | function toggleAutoTargetSwapper() { 1857 | if (autoTargetSwapper) { 1858 | stopAutoTargetSwapper(); 1859 | } else { 1860 | startAutoTargetSwapper(); 1861 | } 1862 | WebStorage.SetLocal('autoTargetSwapperEnabled', (autoTargetSwapper !== null)); 1863 | updateToggle("autotargetswapper", !autoTargetSwapper); 1864 | } 1865 | 1866 | function toggleAutoAbilityUser() { 1867 | if (autoAbilityUser) { 1868 | stopAutoAbilityUser(); 1869 | } else { 1870 | startAutoAbilityUser(); 1871 | } 1872 | WebStorage.SetLocal('autoAbilityUserEnabled', (autoAbilityUser !== null)); 1873 | updateToggle("autoabilityuse", !autoAbilityUser); 1874 | } 1875 | 1876 | function toggleAutoItemUser() { 1877 | if (autoUseConsumables) { 1878 | stopAutoItemUser(); 1879 | } else { 1880 | startAutoItemUser(); 1881 | } 1882 | WebStorage.SetLocal('autoConsumableUserEnabled', autoUseConsumables); 1883 | updateToggle("autoconsume", !autoUseConsumables); 1884 | } 1885 | 1886 | function toggleAutoUpgradeManager() { 1887 | if (autoUpgradeManager) { 1888 | stopAutoUpgradeManager(); 1889 | } else { 1890 | startAutoUpgradeManager(); 1891 | } 1892 | WebStorage.SetLocal('autoUpgraderEnabled', (autoClicker !== null)); 1893 | updateToggle("autoupgrade", !autoUpgradeManager); 1894 | } 1895 | 1896 | function toggleFPS() { 1897 | if (fpsThrottle) { 1898 | stopFPSThrottle(); 1899 | } else { 1900 | startFPSThrottle(); 1901 | } 1902 | WebStorage.SetLocal('fpsThrottleEnabled', (fpsThrottle !== null)); 1903 | updateToggle("fps", (fpsThrottle === null)); 1904 | } 1905 | 1906 | function toggleSpamStatBoosters() { 1907 | spamStatBoosters = !spamStatBoosters; 1908 | WebStorage.SetLocal('spamStatBoostersEnabled', spamStatBoosters); 1909 | updateToggle("spamStatBoosters", !spamStatBoosters); 1910 | } 1911 | 1912 | function spamNoClick() { 1913 | if(!autoClicker) 1914 | return; 1915 | 1916 | // Save the click count 1917 | var clickCount = g_Minigame.m_CurrentScene.m_nClicks; 1918 | 1919 | // Perform default click 1920 | g_Minigame.m_CurrentScene.DoClick({ 1921 | data: { 1922 | getLocalPosition: function() { 1923 | var enemy = getTarget(), 1924 | laneOffset = enemy.m_nLane * 440; 1925 | 1926 | return { 1927 | x: enemy.m_Sprite.position.x - laneOffset, 1928 | y: enemy.m_Sprite.position.y - 52 1929 | }; 1930 | } 1931 | } 1932 | }); 1933 | 1934 | // Restore the click count 1935 | g_Minigame.m_CurrentScene.m_nClicks = clickCount; 1936 | } 1937 | 1938 | function toggleSpammer() { 1939 | if (spammer) { 1940 | clearInterval(spammer); 1941 | 1942 | WebStorage.SetLocal('particleSpamEnabled', false); 1943 | spammer = null; 1944 | } else { 1945 | if (confirm("Are you SURE you want to do this? This leads to massive memory leaks fairly quickly.")) { 1946 | WebStorage.SetLocal('particleSpamEnabled', true); 1947 | spammer = setInterval(spamNoClick, 1000 / clicksPerSecond); 1948 | } 1949 | } 1950 | updateToggle("particles", (spammer === null)); 1951 | } 1952 | 1953 | // ================ LEADERBOARD ================ 1954 | //Pulled from https://github.com/hansskogvold/steamSummerMinigame/commit/f0f905188585e367f42b756a95d459205190b14f 1955 | function initLeaderboard() { 1956 | var container = document.createElement('div'); 1957 | container.id = 'leaderboard_wrapper'; 1958 | container.style.display = "none"; 1959 | 1960 | document.getElementById('col_right').appendChild(container); 1961 | 1962 | var leaderboard = document.createElement('table'); 1963 | leaderboard.id = 'leaderboard'; 1964 | 1965 | var th = document.createElement('tr'); 1966 | th.style.fontSize = '11px'; 1967 | th.style.color = '#ddd'; 1968 | 1969 | var thc = document.createElement('th'); 1970 | var thn = document.createElement('th'); 1971 | var thl = document.createElement('th'); 1972 | thc.appendChild(document.createTextNode('Rank')); 1973 | thn.appendChild(document.createTextNode('Name')); 1974 | thl.appendChild(document.createTextNode('Level')); 1975 | 1976 | th.appendChild(thc); 1977 | th.appendChild(thn); 1978 | th.appendChild(thl); 1979 | 1980 | leaderboard.appendChild(th); 1981 | 1982 | document.getElementById('leaderboard_wrapper').appendChild(leaderboard); 1983 | 1984 | var credit = document.createElement('div'); 1985 | credit.style.fontSize = "12px"; 1986 | credit.style.textAlign = "center"; 1987 | credit.innerHTML = 'Data by steamga.me'; 1988 | 1989 | document.getElementById('leaderboard_wrapper').appendChild(credit); 1990 | 1991 | var toggler = document.createElement('div'); 1992 | toggler.id = "leaderboard_toggler"; 1993 | toggler.onclick = function() { 1994 | toggleLeaderboard(); 1995 | }; 1996 | toggler.style.position = 'absolute'; 1997 | toggler.style.bottom = "-48px"; 1998 | toggler.style.color = "black"; 1999 | toggler.style.textAlign = "center"; 2000 | toggler.style.width = '261px'; 2001 | toggler.style.cursor = "pointer"; 2002 | toggler.appendChild(document.createTextNode("Show Leaderboards")); 2003 | 2004 | document.getElementById('col_right').appendChild(toggler); 2005 | 2006 | getLeaderboard(); 2007 | 2008 | setInterval(function() { 2009 | getLeaderboard(); 2010 | }, 1000 * 30); 2011 | } 2012 | 2013 | function drawLeaderboardRoom(room) { 2014 | var item = document.createElement('tr'); 2015 | item.className = 'leaderboard_item'; 2016 | item.style.height = '23px'; 2017 | item.style.fontSize = '10px'; 2018 | 2019 | var num = document.createElement('td'); 2020 | num.appendChild(document.createTextNode('#' + room.position)); 2021 | 2022 | var name = document.createElement('td'); 2023 | name.style.textAlign = 'center'; 2024 | name.appendChild(document.createTextNode(room.name)); 2025 | 2026 | var level = document.createElement('td'); 2027 | level.style.textAlign = 'right'; 2028 | level.appendChild(document.createTextNode(room.level)); 2029 | 2030 | if (room.id == g_GameID) { 2031 | item.style.color = '#d4e157'; 2032 | } 2033 | 2034 | item.appendChild(num); 2035 | item.appendChild(name); 2036 | item.appendChild(level); 2037 | 2038 | document.getElementById('leaderboard').appendChild(item); 2039 | } 2040 | 2041 | function getLeaderboard() { 2042 | GM_xmlhttpRequest({ 2043 | method: "GET", 2044 | url: "http://steamga.me/data/api/leaderboard.json", 2045 | onload: function(response) { 2046 | console.log('Downloading new leaderboard...'); 2047 | var elements = document.getElementsByClassName('leaderboard_item'); 2048 | while (elements.length > 0) { 2049 | elements[0].parentNode.removeChild(elements[0]); 2050 | } 2051 | var resp = JSON.parse(response.responseText); 2052 | var leaderboard = Object.keys(resp).map(function(key) { 2053 | return resp[key]; 2054 | }); 2055 | leaderboard.sort(function(a, b) { 2056 | return b.level - a.level; 2057 | }); 2058 | leaderboard.map(function(room) { 2059 | drawLeaderboardRoom(room); 2060 | }); 2061 | } 2062 | }); 2063 | } 2064 | 2065 | function toggleLeaderboard() { 2066 | var a = document.getElementById('leaderboard_wrapper'); 2067 | var b = document.getElementById('activitylog'); 2068 | var c = document.getElementById('leaderboard_toggler'); 2069 | if (a.style.display == 'block') { 2070 | a.style.display = 'none'; 2071 | b.style.display = 'block'; 2072 | c.innerHTML = "Show Leaderboards"; 2073 | } else { 2074 | a.style.display = 'block'; 2075 | b.style.display = 'none'; 2076 | c.innerHTML = "Show Activity"; 2077 | } 2078 | } 2079 | 2080 | // ================ UTILS================ 2081 | function getSecondsUntilEnd() { 2082 | return (endDate.getTime() / 1000) - g_Minigame.m_CurrentScene.m_nTime; 2083 | } 2084 | 2085 | function getSecondsPerLevel() { 2086 | return ((g_Minigame.m_CurrentScene.m_rgGameData.timestamp - g_Minigame.m_CurrentScene.m_rgGameData.timestamp_game_start) / g_Minigame.m_CurrentScene.m_rgGameData.level); 2087 | } 2088 | 2089 | function hasTimeLeftToUseConsumable(id, ignoreBuffer) { 2090 | // Use early if Raining Gold or Treasure 2091 | if(id == 17 || id == 22) 2092 | ignoreBuffer *= 6; 2093 | 2094 | if(ignoreBuffer) 2095 | return getSecondsUntilEnd() <= (getAbilityItemQuantity(id) * abilityCooldown(id)); 2096 | else 2097 | return getSecondsUntilEnd() <= ((getAbilityItemQuantity(id) * abilityCooldown(id)) + minutesBufferForConsumableDump * 60); 2098 | } 2099 | 2100 | function getEstimatedLevelsLeft() { 2101 | return getSecondsUntilEnd() / getSecondsPerLevel(); 2102 | } 2103 | function castAbility(abilityID) { 2104 | if (hasAbility(abilityID)) { 2105 | if (abilityID <= ABILITIES.NAPALM && document.getElementById('ability_' + abilityID) !== null) 2106 | g_Minigame.CurrentScene().TryAbility(document.getElementById('ability_' + abilityID).childElements()[0]); 2107 | else if (document.getElementById('abilityitem_' + abilityID) !== null) 2108 | g_Minigame.CurrentScene().TryAbility(document.getElementById('abilityitem_' + abilityID).childElements()[0]); 2109 | } 2110 | } 2111 | 2112 | function currentLaneHasAbility(abilityID) { 2113 | return laneHasAbility(g_Minigame.CurrentScene().m_rgPlayerData.current_lane, abilityID); 2114 | } 2115 | 2116 | function laneHasAbility(lane, abilityID) { 2117 | try { 2118 | if (g_Minigame.m_CurrentScene.m_rgLaneData[lane].abilities[abilityID]) 2119 | return g_Minigame.m_CurrentScene.m_rgLaneData[lane].abilities[abilityID]; 2120 | else 2121 | return 0; 2122 | } catch (e) { 2123 | return 0; 2124 | } 2125 | } 2126 | 2127 | function abilityIsUnlocked(abilityID) { 2128 | if (abilityID <= ABILITIES.NAPALM) 2129 | return ((1 << abilityID) & g_Minigame.CurrentScene().m_rgPlayerTechTree.unlocked_abilities_bitfield) > 0; 2130 | else 2131 | return getAbilityItemQuantity(abilityID) > 0; 2132 | } 2133 | 2134 | function getAbilityItemQuantity(abilityID) { 2135 | for (var i = 0; i < g_Minigame.CurrentScene().m_rgPlayerTechTree.ability_items.length; ++i) { 2136 | var abilityItem = g_Minigame.CurrentScene().m_rgPlayerTechTree.ability_items[i]; 2137 | 2138 | if (abilityItem.ability == abilityID) 2139 | return abilityItem.quantity; 2140 | } 2141 | 2142 | return 0; 2143 | } 2144 | 2145 | // Ability cooldown time remaining (in seconds) 2146 | function abilityCooldown(abilityID) { 2147 | return g_Minigame.CurrentScene().GetCooldownForAbility(abilityID); 2148 | } 2149 | 2150 | // thanks to /u/mouseasw for the base code: https://github.com/mouseas/steamSummerMinigame/blob/master/autoPlay.js 2151 | function hasAbility(abilityID) { 2152 | // each bit in unlocked_abilities_bitfield corresponds to an ability. 2153 | // the above condition checks if the ability's bit is set or cleared. I.e. it checks if 2154 | // the player has purchased the specified ability. 2155 | return abilityIsUnlocked(abilityID) && abilityCooldown(abilityID) <= 0; 2156 | } 2157 | 2158 | function updateUserElementMultipliers() { 2159 | if (!gameRunning() || !g_Minigame.m_CurrentScene.m_rgPlayerTechTree) return; 2160 | 2161 | userElementMultipliers[3] = g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_air; 2162 | userElementMultipliers[4] = g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_earth; 2163 | userElementMultipliers[1] = g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_fire; 2164 | userElementMultipliers[2] = g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_water; 2165 | 2166 | userMaxElementMultiiplier = Math.max.apply(null, userElementMultipliers); 2167 | } 2168 | 2169 | // Return a value to compare mobs' priority (lower value = less important) 2170 | // (treasure > boss > miniboss > spawner > creep) 2171 | function getMobTypePriority(potentialTarget) { 2172 | 2173 | if (!potentialTarget || !potentialTarget.m_data) 2174 | return -1; 2175 | 2176 | mobType = potentialTarget.m_data.type; 2177 | 2178 | switch (mobType) { 2179 | case 1: // Creep 2180 | return 0; 2181 | case 0: // Spawner 2182 | return 1; 2183 | case 3: // Miniboss 2184 | return 2; 2185 | case 2: // Boss 2186 | return 3; 2187 | case 4: // Treasure 2188 | return 4; 2189 | case false: // Let's just assume false is a flag for most important 2190 | return 4; 2191 | default: 2192 | return -1; 2193 | } 2194 | } 2195 | 2196 | // Compares two mobs' priority. Returns a negative number if A < B, 0 if equal, positive if A > B 2197 | function compareMobPriority(mobA, mobB) { 2198 | if (!mobA) 2199 | return false; 2200 | if (!mobB) { 2201 | swapReason = "Swapping off a non-existent mob."; 2202 | return true; 2203 | } 2204 | 2205 | var percentHPRemaining = g_Minigame.CurrentScene().m_rgPlayerData.hp / g_Minigame.CurrentScene().m_rgPlayerTechTree.max_hp * 100; 2206 | var aHasHealing = laneHasAbility(mobA.m_nLane, ABILITIES.MEDICS) || laneHasAbility(mobA.m_nLane, ABILITIES.STEAL_HEALTH); 2207 | var bHasHealing = laneHasAbility(mobB.m_nLane, ABILITIES.MEDICS) || laneHasAbility(mobB.m_nLane, ABILITIES.STEAL_HEALTH); 2208 | 2209 | var aIsGold = laneHasAbility(mobA.m_nLane, ABILITIES.RAINING_GOLD); 2210 | var bIsGold = laneHasAbility(mobB.m_nLane, ABILITIES.RAINING_GOLD); 2211 | 2212 | var aTypePriority = getMobTypePriority(mobA); 2213 | var bTypePriority = getMobTypePriority(mobB); 2214 | 2215 | var aElemMult = userElementMultipliers[g_Minigame.m_CurrentScene.m_rgGameData.lanes[mobA.m_nLane].element]; 2216 | var bElemMult = userElementMultipliers[g_Minigame.m_CurrentScene.m_rgGameData.lanes[mobB.m_nLane].element]; 2217 | 2218 | //check for Max Elemental Damage Ability 2219 | if (laneHasAbility(mobA.m_nLane, ABILITIES.MAX_ELEMENTAL_DAMAGE)) 2220 | aElemMult = userMaxElementMultiiplier; 2221 | if (laneHasAbility(mobB.m_nLane, ABILITIES.MAX_ELEMENTAL_DAMAGE)) 2222 | bElemMult = userMaxElementMultiiplier; 2223 | 2224 | var aHP = mobA.m_data.hp; 2225 | var bHP = mobB.m_data.hp; 2226 | 2227 | //First, make sure they're alive 2228 | if (mobA.m_bIsDestroyed || aHP <= 0) 2229 | return false; 2230 | else if (mobB.m_bIsDestroyed || bHP <= 0) { 2231 | swapReason = "Swapping off a destroyed mob."; 2232 | return true; 2233 | } 2234 | 2235 | //ignore in the weird case that mob priority isn't set to any type (usually set to 'false') (I've seen it sometimes) 2236 | /*if(aTypePriority !== -1) { 2237 | //if(debug) 2238 | // console.log('wtf, unknown mobType.', [mobA.m_nLane, mobA.m_nID, aTypePriority], [mobB.m_nLane, mobB.m_nID, bTypePriority]); 2239 | return false; 2240 | } 2241 | else if(bTypePriority !== -1) 2242 | return true; 2243 | */ 2244 | else if (aIsGold != bIsGold) { 2245 | if (aIsGold > bIsGold && (mobB.m_data.type == 3 || mobB.m_data.type == 1)) { 2246 | swapReason = "Switching to target with Raining Gold."; 2247 | return true; 2248 | } 2249 | } else if (aTypePriority != bTypePriority) { 2250 | if (aTypePriority > bTypePriority) { 2251 | swapReason = "Switching to higher priority target."; 2252 | return true; 2253 | } 2254 | } 2255 | 2256 | //Run to a medic lane if needed 2257 | else if (percentHPRemaining <= seekHealingPercent && !g_Minigame.m_CurrentScene.m_bIsDead) { 2258 | if (aHasHealing != bHasHealing) { 2259 | if (aHasHealing) { 2260 | swapReason = "Swapping to lane with active healing."; 2261 | return true; 2262 | } 2263 | } 2264 | } else if (aElemMult != bElemMult) { 2265 | if (aElemMult > bElemMult) { 2266 | swapReason = "Switching to elementally weaker target."; 2267 | return true; 2268 | } 2269 | } else if (aHP != bHP) { 2270 | if (aHP < bHP) { 2271 | swapReason = "Switching to lower HP target."; 2272 | return true; 2273 | } 2274 | } 2275 | return false; 2276 | } 2277 | 2278 | function getTarget() { 2279 | try { 2280 | var target = g_Minigame.m_CurrentScene.GetEnemy(g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane, g_Minigame.m_CurrentScene.m_rgPlayerData.target); 2281 | return target; 2282 | } catch (e) { 2283 | return null; 2284 | } 2285 | } 2286 | 2287 | function gameRunning() { 2288 | try { 2289 | return (typeof g_Minigame === "object" && g_Minigame.m_CurrentScene.m_rgGameData.status == 2); 2290 | } catch (e) { 2291 | return false; 2292 | } 2293 | } 2294 | 2295 | function getUploadedFilePath(fileName) { 2296 | if (typeof GM_info != 'undefined') { 2297 | return GM_info.script.namespace.replace("github", "raw.githubusercontent") + "/" + fileName; 2298 | } else return "https://raw.githubusercontent.com/ensingm2/SteamMonsterGameScript/"+fileName; 2299 | } 2300 | 2301 | function subLong(x, y) { 2302 | var addLong = function(x, y) { 2303 | var s = ''; 2304 | if (y.length > x.length) { 2305 | s = x; 2306 | x = y; 2307 | y = s; 2308 | } 2309 | s = (parseInt(x.slice(-9),10) + parseInt(y.slice(-9),10)).toString(); 2310 | x = x.slice(0,-9); 2311 | y = y.slice(0,-9); 2312 | if (s.length > 9) { 2313 | if (x === '') return s; 2314 | x = addLong(x, '1'); 2315 | s = s.slice(1); 2316 | } else if (x.length) { while (s.length < 9) { s = '0' + s; } } 2317 | if (y === '') return x + s; 2318 | return addLong(x, y) + s; 2319 | }; 2320 | 2321 | var s; 2322 | s = (parseInt('1'+x.slice(-9),10) - parseInt(y.slice(-9),10)).toString(); 2323 | x = x.slice(0,-9); 2324 | y = y.slice(0,-9); 2325 | if (s.length === 10 || x === '') { 2326 | s = s.slice(1); 2327 | } else { 2328 | if (y.length) { y = addLong(y, '1'); } 2329 | else { y = '1';} 2330 | if (x.length) { while (s.length < 9) { s = '0' + s; }} 2331 | } 2332 | if (y === '') { 2333 | s = (x + s).replace(/^0+/,''); 2334 | return s; 2335 | } 2336 | return subLong(x, y) + s; 2337 | } 2338 | 2339 | function getAccountId(id) { 2340 | return parseInt(subLong(''+id, '76561197960265728')); 2341 | } 2342 | 2343 | function getUserName() { 2344 | if (g_Minigame.m_CurrentScene.m_rgPlayerNameCache) { 2345 | return g_Minigame.m_CurrentScene.m_rgPlayerNameCache[getAccountId(g_steamID)]; 2346 | } 2347 | return "Unknown"; 2348 | } 2349 | 2350 | function getGameLevel() { 2351 | return g_Minigame.m_CurrentScene.m_rgGameData.level + 1; 2352 | } 2353 | -------------------------------------------------------------------------------- /elementsStatTracker.js: -------------------------------------------------------------------------------- 1 | // WIP: this doesn't work yet. 2 | 3 | //This just keeps track of the distribution of elements in lanes 4 | 5 | var elementStats; 6 | var levelNum = -1; 7 | 8 | var elementStatTracker = setInterval(function() { 9 | // Check for new level 10 | if(levelNum != g_Minigame.CurrentScene().m_nCurrentLevel) { 11 | levelNum = g_Minigame.CurrentScene().m_nCurrentLevel; 12 | elementStats[levelNum] = { 0 : g_Minigame.CurrentScene().m_rgLaneData[0], 13 | 1 : , 14 | 2 : , 15 | } 16 | } 17 | }, 5000) -------------------------------------------------------------------------------- /img/game_frame_tv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensingm2/SteamMonsterGameScript/fd9badab1f0218975e41b6f86f18e8f4f7fdb4b2/img/game_frame_tv.png -------------------------------------------------------------------------------- /img/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensingm2/SteamMonsterGameScript/fd9badab1f0218975e41b6f86f18e8f4f7fdb4b2/img/icons.png -------------------------------------------------------------------------------- /img/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensingm2/SteamMonsterGameScript/fd9badab1f0218975e41b6f86f18e8f4f7fdb4b2/img/settings.png -------------------------------------------------------------------------------- /img/stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensingm2/SteamMonsterGameScript/fd9badab1f0218975e41b6f86f18e8f4f7fdb4b2/img/stats.png -------------------------------------------------------------------------------- /minified.js: -------------------------------------------------------------------------------- 1 | function startAllAutos(){startAutoRespawner(),startAutoClicker(),startAutoTargetSwapper(),startAutoAbilityUser(),startAutoItemUser(),startAutoUpgradeManager()}function loadSettings(){WebStorage.GetLocal("autoClickerEnabled")===!1&&toggleAutoClicker(),WebStorage.GetLocal("autoTargetSwapperEnabled")===!1&&toggleAutoTargetSwapper(),WebStorage.GetLocal("autoAbilityUserEnabled")===!1&&toggleAutoAbilityUser(),WebStorage.GetLocal("autoConsumableUserEnabled")===!1&&toggleAutoItemUser(),WebStorage.GetLocal("autoUpgraderEnabled")===!1&&toggleAutoUpgradeManager(),WebStorage.GetLocal("particleSpamEnabled")&&(spammer=setInterval(spamNoClick,1e3/clicksPerSecond),updateToggle("particles",!1)),WebStorage.GetLocal("fpsThrottleEnabled")===!0&&toggleFPS(),WebStorage.GetLocal("spamStatBoostersEnabled")===!1&&toggleSpamStatBoosters(),null!==WebStorage.GetLocal("survivalTime")&&(survivalTime=WebStorage.GetLocal("survivalTime"),$J("#survival_time").html(survivalTime))}function stopAllAutos(){stopAutoClicker(),stopAutoRespawner(),stopAutoTargetSwapper(),stopAutoAbilityUser(),stopAutoItemUser(),stopAutoUpgradeManager()}function startAutoClicker(){return autoClicker?void console.log("Autoclicker is already running!"):(autoClicker=setInterval(function(){if(gameRunning()){var e=Math.floor(Math.random()*autoClickerVariance*2)-autoClickerVariance,t=clicksPerSecond+e;g_Minigame.m_CurrentScene.m_nClicks+=t,g_msTickRate=1100;var a=g_Minigame.m_CurrentScene.m_rgGameData.lanes[g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane].active_player_ability_gold_per_click,n=getTarget();if(n&&a>0&&n.m_data.hp>0){var r=n.m_data.gold*a*g_Minigame.m_CurrentScene.m_nClicks;g_Minigame.m_CurrentScene.ClientOverride("player_data","gold",g_Minigame.m_CurrentScene.m_rgPlayerData.gold+r),g_Minigame.m_CurrentScene.ApplyClientOverrides("player_data",!0)}var i=g_Minigame.m_CurrentScene.m_rgStoredCrits.length;if(g_Minigame.m_CurrentScene.m_rgStoredCrits=[],debug){i>1&&console.log("Clicking "+g_Minigame.m_CurrentScene.m_nClicks+" times this second. ("+i+" crits)."),console.log(1==i?"Clicking "+g_Minigame.m_CurrentScene.m_nClicks+" times this second. (1 crit).":"Clicking "+g_Minigame.m_CurrentScene.m_nClicks+" times this second.");var o=g_Minigame.m_CurrentScene.CalculateDamage(g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_per_click*userMaxElementMultiiplier*g_Minigame.m_CurrentScene.m_nClicks),s="(unknown)";o>1e9?s=o/1e9+"B":o>1e6?s=o/1e6+"M":o>1e3&&(s=o/1e3+"K"),console.log("We did roughly "+s+" damage in the last second.")}}},autoClickerFreq),void console.log("autoClicker has been started."))}function stopAutoClicker(){autoClicker?(clearInterval(autoClicker),autoClicker=null,console.log("autoClicker has been stopped.")):console.log("No autoClicker is running to stop.")}function startAutoAbilityUser(){return autoAbilityUser?void console.log("autoAbilityUser is already running!"):(autoAbilityUser=setInterval(function(){debug&&console.log("Checking if it's useful to use an ability.");var e=g_Minigame.CurrentScene().m_rgPlayerData.hp/g_Minigame.CurrentScene().m_rgPlayerTechTree.max_hp*100,t=getTarget(),a=g_Minigame.m_CurrentScene.m_rgGameData.lanes[g_Minigame.CurrentScene().m_rgPlayerData.current_lane],n=getGameLevel();for(var r in ABILITIES)if(ABILITIES.hasOwnProperty(r)){var i=ABILITIES[r];if(i>=ABILITIES.RESURRECTION){var o=i==ABILITIES.THROW_MONEY_AT_SCREEN;hasTimeLeftToUseConsumable(i,o)&&castAbility(i)}}if(hasAbility(ABILITIES.WORMHOLE)&&autoUseConsumables&&(n%CONTROL.rainingRounds===0&&n>CONTROL.speedThreshold||hasTimeLeftToUseConsumable(ABILITIES.WORMHOLE,!1))&&(debug&&console.log("Casting Wormhole! Allons-y!!!"),castAbility(ABILITIES.WORMHOLE)),spamStatBoosters&&(getAbilityItemQuantity(18)&&castAbility(18),getAbilityItemQuantity(19)&&castAbility(19)),t){var s=t.m_data.hp/t.m_data.max_hp*100,l=g_Minigame.m_CurrentScene.m_rgLaneData[g_Minigame.CurrentScene().m_rgPlayerData.current_lane].friendly_dps,u=t.m_data.hp/l,g=g_Minigame.m_CurrentScene.m_nCurrentLevel+1>=CONTROL.speedThreshold&&(g_Minigame.m_CurrentScene.m_nCurrentLevel+1)%CONTROL.rainingRounds!==0,c=2==t.m_data.type||t.m_data.type===!1;if(c&&s>75&&!currentLaneHasAbility(9)&&hasAbility(9)&&castAbility(9),0===t.m_data.type&&g_Minigame.m_CurrentScene.m_nCurrentLevel+1>=CONTROL.speedThreshold||c&&g){var d=hasAbility(ABILITIES.MORALE_BOOSTER),p=hasAbility(ABILITIES.GOOD_LUCK_CHARMS),m=hasAbility(ABILITIES.CRIT)&&autoUseConsumables;if(s>=90&&autoUseConsumables&&(hasAbility(ABILITIES.CRIPPLE_SPAWNER)||hasAbility(ABILITIES.CRIPPLE_MONSTER)))hasAbility(ABILITIES.CRIPPLE_SPAWNER)?castAbility(ABILITIES.CRIPPLE_SPAWNER):hasAbility(ABILITIES.CRIPPLE_MONSTER)&&castAbility(ABILITIES.CRIPPLE_MONSTER);else if(d||m||p){var _=abilityIsUnlocked(ABILITIES.MORALE_BOOSTER),b=abilityIsUnlocked(ABILITIES.GOOD_LUCK_CHARMS);if(!_&&!m||!b||(d||m)&&(p||!b)){var h=currentLaneHasAbility(ABILITIES.DECREASE_COOLDOWNS);(s>=70||h&&s>=60)&&(h||hasAbility(ABILITIES.DECREASE_COOLDOWNS)||!abilityIsUnlocked(ABILITIES.DECREASE_COOLDOWNS)||abilityCooldown(ABILITIES.DECREASE_COOLDOWNS)>60)&&(hasAbility(ABILITIES.DECREASE_COOLDOWNS)&&!currentLaneHasAbility(ABILITIES.DECREASE_COOLDOWNS)?(debug&&console.log("Triggering Decrease Cooldown!"),castAbility(ABILITIES.DECREASE_COOLDOWNS)):(m?(debug&&console.log("Using Crit!"),castAbility(ABILITIES.CRIT)):d&&(debug&&console.log("Casting Morale Booster!"),castAbility(ABILITIES.MORALE_BOOSTER)),p&&(debug&&console.log("Casting Good Luck Charm!"),castAbility(ABILITIES.GOOD_LUCK_CHARMS))))}}hasAbility(ABILITIES.TACTICAL_NUKE)&&(s>=useNukeOnSpawnerAbovePercent||2==t.m_data.type&&s>=useNukeOnBossAbovePercent)?(debug&&console.log("Nuclear launch detected."),castAbility(ABILITIES.TACTICAL_NUKE)):0===t.m_data.type&&hasAbility(ABILITIES.NAPALM)&&s>=useNukeOnSpawnerAbovePercent&&a.enemies.length>=4?(debug&&console.log("Triggering napalm!"),castAbility(ABILITIES.NAPALM)):0===t.m_data.type&&hasAbility(ABILITIES.CLUSTER_BOMB)&&s>=useNukeOnSpawnerAbovePercent&&a.enemies.length>=4&&(debug&&console.log("Triggering cluster bomb!"),castAbility(ABILITIES.CLUSTER_BOMB)),c&&(hasAbility(ABILITIES.MAX_ELEMENTAL_DAMAGE)&&autoUseConsumables&&s>useNukeOnBossAbovePercent&&(debug&&console.log("Using Max Elemental Damage on boss."),castAbility(ABILITIES.MAX_ELEMENTAL_DAMAGE)),hasAbility(ABILITIES.REFLECT_DAMAGE)&&autoUseConsumables&&s>useNukeOnBossAbovePercent&&(debug&&console.log("Using Reflect Damage on boss."),castAbility(ABILITIES.REFLECT_DAMAGE)))}else!g&&c&&(g||hasAbility(ABILITIES.RAINING_GOLD)&&autoUseConsumables&&s>useRainingGoldAbovePercent&&u>30&&n>CONTROL.disableGoldRainLevels&&(n<=CONTROL.speedThreshold||n%CONTROL.rainingRounds===0)&&(debug&&console.log("Using Raining Gold on boss."),castAbility(ABILITIES.RAINING_GOLD)));var A=hasAbility(ABILITIES.TREASURE)&&autoUseConsumables;(c||4==t.m_data.type)&&10>u&&(hasAbility(ABILITIES.METAL_DETECTOR)||A)&&(A?(debug&&console.log("Using Metal Detector via Treasure."),castAbility(ABILITIES.TREASURE)):(debug&&console.log("Using Metal Detector."),castAbility(ABILITIES.METAL_DETECTOR)))}for(var f=0,v=0,S=1;10>S;S++){var y=10*(S-1)+5;f+=y*a.player_hp_buckets[S],v+=a.player_hp_buckets[S]}var C=f/v,T=v/(v+a.player_hp_buckets[0])*100;if((useMedicsAtPercent>=e||useMedicsAtLanePercent>=C&&T>useMedicsAtLanePercentAliveReq)&&!g_Minigame.m_CurrentScene.m_bIsDead){debug&&(useMedicsAtPercent>=e&&console.log("Health below threshold. Need medics!"),useMedicsAtLanePercent>=C&&T>useMedicsAtLanePercentAliveReq&&console.log("Average lane below threshold. Need medics!"));var I=hasAbility(ABILITIES.PUMPED_UP)&&autoUseConsumables,E=hasAbility(ABILITIES.STEAL_HEALTH)&&autoUseConsumables;(hasAbility(ABILITIES.MEDICS)||I)&¤tLaneHasAbility(ABILITIES.MEDICS)<2?I?(debug&&console.log("Using Medics via Pumped Up!"),castAbility(ABILITIES.PUMPED_UP)):(debug&&console.log("Using Medics!"),castAbility(ABILITIES.MEDICS)):E&&useMedicsAtPercent>=e?(debug&&console.log("Using Steal Health in place of Medics!"),castAbility(ABILITIES.STEAL_HEALTH)):debug&&console.log("No medics to unleash!")}if(hasAbility(ABILITIES.RESURRECTION)&&autoUseConsumables&&a.player_hp_buckets[0]>=useResurrectToSaveCount&&(debug&&console.log("Using resurrection to save "+a.player_hp_buckets[0]+" lane allies."),castAbility(ABILITIES.RESURRECTION)),hasAbility(ABILITIES.LIKE_NEW)&&autoUseConsumables){var M=0;for(S=5;12>=S;S++)abilityIsUnlocked(S)&&(M+=abilityCooldown(S));1e3*M>=useLikeNewAboveCooldown&&(debug&&console.log("Using like new to save a total of "+M+" seconds of cooldown."),castAbility(ABILITIES.LIKE_NEW))}},abilityUseCheckFreq),void console.log("autoAbilityUser has been started."))}function startAutoItemUser(){autoUseConsumables=!0,console.log("Automatic use of consumables has been enabled.")}function stopAutoAbilityUser(){autoAbilityUser?(clearInterval(autoAbilityUser),autoAbilityUser=null,console.log("autoAbilityUser has been stopped.")):console.log("No autoAbilityUser is running to stop.")}function stopAutoItemUser(){autoUseConsumables=!1,console.log("Automatic use of consumables has been disabled.")}function disableAutoNukes(){useNukeOnSpawnerAbovePercent=200,console.log("Automatic nukes have been disabled")}function startAutoRespawner(){return autoRespawner?void console.log("autoRespawner is already running!"):(autoRespawner=setInterval(function(){debug&&console.log("Checking if the player is dead."),g_Minigame.m_CurrentScene.m_bIsDead&&(debug&&console.log("Player is dead. Respawning."),RespawnPlayer())},respawnCheckFreq),void console.log("autoRespawner has been started."))}function stopAutoRespawner(){autoRespawner?(clearInterval(autoRespawner),autoRespawner=null,console.log("autoRespawner has been stopped.")):console.log("No autoRespawner is running to stop.")}function startAutoTargetSwapper(){return autoTargetSwapper?void console.log("autoTargetSwapper is already running!"):(updateUserElementMultipliers(),autoTargetSwapperElementUpdate=setInterval(updateUserElementMultipliers,elementUpdateRate),autoTargetSwapper=setInterval(function(){debug&&console.log("Looking for a new target.");var e=getTarget();g_Minigame.m_CurrentScene.m_rgEnemies.each(function(t){compareMobPriority(t,e)&&(e=t)});var t=getTarget();e.m_data&&t.m_data&&e.m_data.id!=t.m_data.id?(debug&&null!==swapReason&&(console.log(swapReason),swapReason=null),g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane!=e.m_nLane&&g_Minigame.m_CurrentScene.TryChangeLane(e.m_nLane),g_Minigame.m_CurrentScene.TryChangeTarget(e.m_nID)):e.m_data&&g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane!=e.m_nLane&&g_Minigame.m_CurrentScene.TryChangeLane(e.m_nLane)},targetSwapperFreq),void console.log("autoTargetSwapper has been started."))}function stopAutoTargetSwapper(){autoTargetSwapper?(clearInterval(autoTargetSwapper),autoTargetSwapper=null,console.log("autoTargetSwapper has been stopped.")):console.log("No autoTargetSwapper is running to stop.")}function startAutoUpgradeManager(){function e(){if(debug&&console.log("Checking for worthwhile upgrades"),o=g_Minigame.CurrentScene(),!o.m_bUpgradesBusy&&(-1===l.id&&(t&&$J(document.body).removeClass("upgrade_waiting"),b(!0),T(!0),I()),-1!==l.id&&a&&l.cost<=o.m_rgPlayerData.gold)){var e=$J(".link",document.getElementById("upgr_"+l.id)).get(0);e?o.TryUpgrade(e):console.error("failed to find upgrade")}}if(autoUpgradeManager)return void console.log("UpgradeManager is already running!");var t=!0,a=!0,n=1,r=[.4,.3,.2,.1],i=clicksPerSecond+Math.ceil(autoClickerVariance/2),o=g_Minigame.CurrentScene(),s=!1,l={id:-1,cost:0},u=[{id:0,level:1},{id:11,level:1},{id:2,level:10},{id:1,level:10}],g=[11,13,16,18,17,14,15,12],c=7,d=[3,4,5,6],p=[],m=[],_=[];Object.keys(o.m_rgTuningData.upgrades).sort(function(e,t){return e-t}).forEach(function(e){var t=o.m_rgTuningData.upgrades[e];switch(t.type){case 0:p.push(+e);break;case 1:m.push(+e);break;case 2:_.push(+e)}});var b=function(){var e=!1;return function(t){return(!e||t)&&(e=d.map(function(e){return{id:e,level:o.GetUpgradeLevel(e)}}).sort(function(e,t){return t.level-e.level})),e}}(),h=function(e){return e=e||b(),o.m_rgTuningData.upgrades[4].multiplier*e.reduce(function(e,t,a){return e+t.level*r[a]},0)},A=function(e){if(!o.bHaveUpgrade(e))return!1;var t=o.m_rgTuningData.upgrades[e],a=t.required_upgrade;if(void 0!==a){var n=t.required_upgrade_level||1;return n<=o.GetUpgradeLevel(a)}return!0},f=function(e,t){var a,n=o.m_rgTuningData.upgrades[e],r=0,i=0,s=o.GetUpgradeLevel(e);void 0===t&&(t=s+1);for(var l=t-s;l>0;l--)r+=n.multiplier,i+=n.cost*Math.pow(n.cost_exponential_base,t-l);var u=n.required_upgrade;if(void 0!==u){var g=f(u,n.required_upgrade_level||1);g.cost>0&&(r+=g.boost,i+=g.cost,a=g.required||u)}return{boost:r,cost:i,required:a}},v=function(){for(var e,t,a={id:-1,cost:0};u.length>0;){if(e=u[0],t=e.id,o.GetUpgradeLevel(t)=a.hpg&&(void 0!==e.required&&(n=e.required),cost=o.GetUpgradeCost(n),(cost<=o.m_rgPlayerData.gold||0===a.cost||cost=l.dpg&&(void 0!==e.required&&(t=e.required),l={id:t,cost:o.GetUpgradeCost(t),dpg:r})}),A(c)&&(t=o.m_rgTuningData.upgrades[c],s=u*v*t.multiplier,a=o.GetUpgradeCost(c),r=s/a,r>=l.dpg&&(l={id:c,cost:a,dpg:r})),_.forEach(function(t){e=f(t),r=g*e.boost*(v*d+(1-v)*y)/e.cost,r>=l.dpg&&(void 0!==e.required&&(t=e.required),l={id:t,cost:o.GetUpgradeCost(t),dpg:r})}),t=o.m_rgTuningData.upgrades[4];var C=S.reduce(function(e,t){return e+t.level},1);a=t.cost*Math.pow(t.cost_exponential_base,C);var T=S.map(function(e){return{level:e.level}}),I=T[n-1].level;if(T[n-1].level++,n>1){var E=T[n-2].level;I>=E&&(T[n-2].level=I+1,T[n-1].level=E)}if(s=u*(1-v)*(h(T)-y),r=s/a,r>l.dpg){var M=S.filter(function(e){return e.level==I});M=M[Math.floor(Math.random()*M.length)].id,l={id:M,cost:a,dpg:r}}return l},T=function(){var e=!1;return function(t){if(e===!1||t){var a=o.m_rgPlayerTechTree.max_hp,n=o.m_rgGameData.lanes.reduce(function(e,t){return Math.max(e,t.enemies.reduce(function(e,t){return e+t.dps},0))},0);e=a/(n||4*o.m_rgGameData.level)}return e}}(),I=function(){if(l=v(),-1===l.id)if(T()
Currently in slow FPS mode to maximize performance, toggle this off in the settings if you want full FPS
'),$J("#slow_fps_dialog").css({position:"absolute",top:"0",left:"0",right:"0",height:"100%","background-color":"rgba(0,0,0,0.6)",color:"white","text-align":"center","font-size":"12px","z-index":"9",padding:"10px"});var t=function(){gameRunning()&&(m_nLastTick=!1,g_Minigame.CurrentScene().Tick(),requestAnimationFrame(function(){g_Minigame.Renderer.render(g_Minigame.CurrentScene().m_Container)}))};fpsThrottle=setInterval(t,slowRenderingFreq),console.log("fpsThrottle has been started.")}function stopFPSThrottle(){if(fpsThrottle){clearInterval(fpsThrottle);var e=PIXI.ticker.shared;e.autoStart=!0,e.start(),g_Minigame.Render=gameOldRenderer,g_Minigame.Render(),$J("#slow_fps_dialog").remove(),fpsThrottle=null,console.log("fpsThrottle has been stopped.")}else console.log("No fpsThrottle is running to stop.")}function initGUI(){updatePlayersInLane(),updatePlayersInRoom(),setInterval(function(){updatePlayersInLane(),updatePlayersInRoom()},1e4),addPointer(),addExtraUI(),CSceneGame.prototype.ClearNewPlayer=function(){if(this.m_spriteFinger){{WebStorage.SetLocal("mg_how2click",1)}$J("#newplayer").hide()}},CUI.prototype.UpdateLootNotification=function(){if(this.m_Game.m_rgPlayerData.loot&&0!==this.m_Game.m_rgPlayerData.loot.length&&this.m_Game.m_rgGameData.level>=lastLootLevel+10&&(0===lastLootCache.length||lastLootCache.toString()!==this.m_Game.m_rgPlayerData.loot.toString())){$J("#loot_notification").show();for(var e=this.m_Game.m_rgTuningData.abilities,t="",a=0;aa;a++)for(var n=0;5>n;n++)g_Minigame.m_CurrentScene.m_rgFingerTextures.push(new PIXI.Texture(g_rgTextureCache.pointer.texture,{x:n*e,y:a*t,width:e,height:t}));g_Minigame.m_CurrentScene.m_nFingerIndex=0,g_Minigame.m_CurrentScene.m_spriteFinger=new PIXI.Sprite(g_Minigame.m_CurrentScene.m_rgFingerTextures[g_Minigame.m_CurrentScene.m_nFingerIndex]),g_Minigame.m_CurrentScene.m_spriteFinger.scale.x=g_Minigame.m_CurrentScene.m_spriteFinger.scale.y=2,g_Minigame.m_CurrentScene.m_containerParticles.addChild(g_Minigame.m_CurrentScene.m_spriteFinger)}function updatePlayersInLane(){var e="???";g_Minigame.m_CurrentScene.m_rgLaneData[g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane]&&(e=g_Minigame.m_CurrentScene.m_rgLaneData[g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane].players),$J("#players_in_lane").html(e)}function updatePlayersInRoom(){var e="???";g_Minigame.m_CurrentScene.m_rgLaneData[0]&&(e=g_Minigame.m_CurrentScene.m_rgLaneData[0].players+g_Minigame.m_CurrentScene.m_rgLaneData[1].players+g_Minigame.m_CurrentScene.m_rgLaneData[2].players),$J("#players_in_room").html(e)}function initEndDate(){var e=new Date;return e.getUTCHours()>=16&&e.setUTCDate(e.getUTCDate()+1),e.setUTCHours(16,0,0,0),e}function updateStats(){var e=function(){var e=getSecondsUntilEnd(),t=Math.floor(e/3600),a=Math.floor((e-3600*t)/60),n=e-3600*t-60*a,r="";return t>0?(r+=1==t?"an hour":t+" hours",a>1&&(r+=" and "+a+" minute"+(1==a?"":"s"))):a>0?(r+=1==a?"a minute":a+" minutes",n>1&&(r+=" and "+n+" second"+(1==n?"":"s"))):r+=1>=n?"about a second":"about "+n+" seconds",r};$J("#avg_completion_rate").html(parseFloat(getSecondsPerLevel()).toFixed(2)),$J("#estimated_end_level").html(Math.round(getSecondsUntilEnd()/getSecondsPerLevel()+g_Minigame.m_CurrentScene.m_rgGameData.level)),$J("#remaining_time").html(e())}function addExtraUI(){var e=$J(".title_activity").html();$J(".title_activity").html(e+' [0 in room]'),$J("#gamecontainer").append('
'),$J("#settings").css({position:"absolute",background:"url('"+getUploadedFilePath("master/img/settings.png?v2")+"')","background-repeat":"no-repeat","background-position":"0px 0px",height:"300px",width:"500px","margin-top":"2px",bottom:"-65px",right:"10px","padding-top":"15px","padding-left":"12px"}),$J("#settings").append('
Music:
'),$J("#settings").append('
SFX:
'),$J("#settings").append('
Auto-Clicker:
'),$J("#settings").append('
Target Swapper:
'),$J("#settings").append('
Ability Use:
'),$J("#settings").append('
Consumable Use:
'),$J("#settings").append('
Auto Upgrader:
'),$J("#settings").append('
Spam StatBoosts:
'),$J("#settings").append('
FPS Limiter:
'),$J("#settings").append('
Particles:
'),$J("#settings").append('
Survival Time: ^ 30 seconds v
'),$J("#sfx_toggle").click(function(e){e.stopPropagation(),toggleSFX(!0)}),$J("#music_toggle").click(function(e){e.stopPropagation(),toggleMusic(!0)}),$J("#autoclicker_toggle").click(function(e){e.stopPropagation(),toggleAutoClicker()}),$J("#autotargetswapper_toggle").click(function(e){e.stopPropagation(),toggleAutoTargetSwapper()}),$J("#autoabilityuse_toggle").click(function(e){e.stopPropagation(),toggleAutoAbilityUser()}),$J("#autoconsume_toggle").click(function(e){e.stopPropagation(),toggleAutoItemUser()}),$J("#autoupgrade_toggle").click(function(e){e.stopPropagation(),toggleAutoUpgradeManager()}),$J("#fps_toggle").click(function(e){e.stopPropagation(),toggleFPS()}),$J("#particles_toggle").click(function(e){e.stopPropagation(),toggleSpammer()}),$J("#spamStatBoosters_toggle").click(function(e){e.stopPropagation(),toggleSpamStatBoosters()}),$J("#increase_survival").click(function(e){e.stopPropagation(),survivalTime+=10,WebStorage.SetLocal("survivalTime",survivalTime),$J("#survival_time").html(survivalTime)}),$J("#decrease_survival").click(function(e){e.stopPropagation(),0>survivalTime-10||(survivalTime-=10,WebStorage.SetLocal("survivalTime",survivalTime),$J("#survival_time").html(survivalTime))}),toggleSFX(!1),toggleMusic(!1),$J("#settings").click(function(){var e=$J("#settings");e.animate({bottom:-65==parseInt(e.css("bottom"),10)?-e.outerHeight():-65})}),$J("#gamecontainer").append('
'),$J("#statistics").css({position:"absolute",background:"url('"+getUploadedFilePath("master/img/stats.png")+"')","background-repeat":"no-repeat","background-position":"0px 0px",height:"250px",width:"500px","margin-top":"2px",bottom:"-65px",left:"10px","padding-top":"15px","padding-left":"25px"}),$J("#statistics").append('
Dmg Per Click: 0
'),$J("#statistics").append('
Dmg Per Second: 0
'),$J("#statistics").append('
Critical Chance: 0
'),$J("#statistics").append('
Critical Dmg Multiplier: 0
'),$J("#statistics").append('
Elemental Multiplier: 0
'),$J("#statistics").append('
Elemental DPC: 0
'),$J("#statistics").append('
Elemental DPS: 0
'),$J("#statistics").append('
Boss Loot Chance: 0
'),$J("#footer_spacer").css({height:"175px"}),$J("canvas").css({position:"relative","z-index":"5"}),$J("#uicontainer").css({"z-index":"6"}),setTimeout(function(){$J(".tv_ui").css({background:"url('"+getUploadedFilePath("master/img/game_frame_tv.png")+"')"}),$J("#info_block").append('
'),$J("#irc_join").click(function(e){e.stopPropagation(),window.open("http://chat.mibbit.com/?channel=%23SMG_"+g_GameID+"&server=irc.mibbit.net&nick="+getUserName(),"_blank")})},1e3),setInterval(function(){function e(){return Math.max(g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_air,g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_earth,g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_fire,g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_water)}$J("#statistics #stat_player_dpc .value").html(FormatNumberForDisplay(g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_per_click,5)),$J("#statistics #stat_player_dps .value").html(FormatNumberForDisplay(g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_per_click*clicksPerSecond,5)),$J("#statistics #stat_player_crit .value").html(FormatNumberForDisplay(Math.round(100*g_Minigame.m_CurrentScene.m_rgPlayerTechTree.crit_percentage),5)+"%"),$J("#statistics #stat_crit_mul .value").html(FormatNumberForDisplay(g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_crit,5)+"x"),$J("#statistics #stat_elemental_mul .value").html(FormatNumberForDisplay(e())+"x"),$J("#statistics #stat_elemental_dpc .value").html(FormatNumberForDisplay(e()*g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_per_click,5)),$J("#statistics #stat_elemental_dps .value").html(FormatNumberForDisplay(e()*g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_per_click*clicksPerSecond,5)),$J("#statistics #stat_boss_loot .value").html(FormatNumberForDisplay(Math.round(100*g_Minigame.m_CurrentScene.m_rgPlayerTechTree.boss_loot_drop_percentage,5))+"%")},1e3),$J("#statistics").click(function(){var e=$J("#statistics");e.animate({bottom:-65==parseInt(e.css("bottom"),10)?-e.outerHeight():-65})}),customCSS(),addCustomButtons(),$J("#footer").css("z-index",-1)}function addCustomButtons(){$J('


Smack TV
').insertBefore("#row_bottom"),$J(".game_options").remove(),$J('Close
Game
').insertAfter("#settings"),$J(".leave_game_btn").css({width:"120px",position:"absolute",bottom:"72px","z-index":"12",left:"340px",background:"url('http://steamcommunity-a.akamaihd.net/public/images/promo/towerattack/leave_game_btn.png')","background-repeat":"no-repeat","background-position":"-75px 0px",height:"56px","float":"right","margin-right":"7px","padding-top":"14px",cursor:"pointer"}),$J('
You can safely close the game or leave this screen at any time—you will continue collecting gold and damaging monsters even while away from your computer. Check back occasionally to see how you\'re doing and use in-game gold to purchase upgrades.
').insertAfter("#settings"),$J(".leave_game_helper").css({left:"150px",top:"initial",bottom:"-20px","z-index":"12"}),$J(".leave_game_btn").mouseover(function(){$J(".leave_game_helper").show()}).mouseout(function(){$J(".leave_game_helper").hide()}),$J(".leave_game_helper").hide();var e=document.querySelector(".breadcrumbs");if(e){var t=document.createElement("span");t.textContent=" > ",e.appendChild(t),t=document.createElement("span"),t.style.color="#D4E157",t.style.textShadow="1px 1px 0px rgba( 0, 0, 0, 0.3 )",t.textContent="Room "+g_GameID,e.appendChild(t),t=document.createElement("span"),t.textContent=" > ",e.appendChild(t),t=document.createElement("span"),t.style.color="#F089B2",t.style.textShadow="1px 1px 0px rgba( 0, 0, 0, 0.3 )",t.innerHTML='Expected Level: 0, Seconds Per Level 0',e.appendChild(t),t=document.createElement("span"),t.textContent=" > ",e.appendChild(t),t=document.createElement("span"),t.style.color="#ACA5F2",t.style.textShadow="1px 1px 0px rgba( 0, 0, 0, 0.3 )",t.innerHTML='Remaining Time: 0 Seconds.',e.appendChild(t),updateStats(),setInterval(function(){updateStats()},1e4),"undefined"!=typeof GM_info&&(t=document.createElement("span"),t.style.cssFloat="right",t.style.color="#D4E157",t.style.textShadow="1px 1px 0px rgba( 0, 0, 0, 0.3 )",t.innerHTML=''+GM_info.script.name+" v"+GM_info.script.version+"",e.appendChild(t))}}function customCSS(){var e="";e+="#settings .toggle { position: relative; margin-top: 10px; width: 30%; height: 32px; z-index: 0; float: left; margin-left: 10px;} ",e+="#settings span.title { position: relative; top: 10px; float: right; right:15px; text-align:right; width: 80%;} ",e+="#settings span.value { position: relative; float: right; right:10px; display: inline-block; z-index:11; cursor: pointer;} ",e+="#settings span.value.enabled { background: url('"+getUploadedFilePath("master/img/icons.png")+"'); background-repeat: no-repeat;background-position:0px 0px;width:30px;height:30px; } ",e+="#settings span.value.enabled:hover { background: url('"+getUploadedFilePath("master/img/icons.png")+"'); background-repeat: no-repeat;background-position:-30px 0px;width:30px;height:30px; } ",e+="#settings span.value.disabled { background: url('"+getUploadedFilePath("master/img/icons.png")+"'); background-repeat: no-repeat;background-position:0px -30px;width:30px;height:32px; } ",e+="#settings span.value.disabled:hover { background: url('"+getUploadedFilePath("master/img/icons.png")+"'); background-repeat: no-repeat;background-position:-30px -30px;width:30px;height:32px; } ",e+="#statistics .stat { position: relative; margin-top: 5px; width: 40%; height: 32px; z-index: 0; margin-left: 25px; float:left;} ",e+="#statistics span.value { position: relative; float: right; margin-right: 30px; text-align: right; width: 100%;} ",e+="#statistics span.title { position: relative; width: 100%; font-weight: bold;} ",e+=".toggle_btn {background: #d6d6d6;-webkit-border-radius: 7; -moz-border-radius: 7; border-radius: 7px; color: #333; text-decoration: none; text-align: center;cursor: pointer;font-weight: bold;} ",e+=".toggle_btn:hover { background: #85c8f2; text-decoration: none; color: #fff;cursor: pointer;font-weight: bold;} ",e+="#activeinlanecontainer:hover {height:auto;background:rgba(50,50,50,0.9);padding-bottom:10px;position:absolute;z-index:1} #activeinlanecontainer:hover ~ #activitylog {margin-top:97px} #activitylog {margin-top: 29px} ",e+="#leaderboard_wrapper {overflow: hidden; height: 360px; width: 261px; position: relative; margin: 50px 0px 0px 5px; padding: 5px;} #activeinlanecontainer:hover ~ #leaderboard_wrapper {margin-top: 118px}",e+="#info_hp { position:relative; top:28px; text-align: center;}",e+="#irc_join {position: relative; width: 175px; height: 30px; top: -50px; left: 30px; cursor: pointer;}",e+=".arrow {font-weight: bold; background-color: #bebebe; width: 20px; color: #434340; border-radius: 7px; float: right; text-align: center; margin-top: -2px; margin-left: 10px; }",$J("head").append("") 2 | }function updateToggle(e,t){t?$J("#"+e+"_toggle span.value").removeClass("enabled").addClass("disabled"):$J("#"+e+"_toggle span.value").removeClass("disabled").addClass("enabled")}function toggleSFX(e){var t=WebStorage.GetLocal("minigame_mute");e&&(t=!t,WebStorage.SetLocal("minigame_mute",t)),updateToggle("sfx",t)}function toggleMusic(e){e&&g_AudioManager.ToggleMusic(),updateToggle("music",WebStorage.GetLocal("minigame_mutemusic"))}function toggleAutoClicker(){autoClicker?stopAutoClicker():startAutoClicker(),WebStorage.SetLocal("autoClickerEnabled",null!==autoClicker),updateToggle("autoclicker",!autoClicker)}function toggleAutoTargetSwapper(){autoTargetSwapper?stopAutoTargetSwapper():startAutoTargetSwapper(),WebStorage.SetLocal("autoTargetSwapperEnabled",null!==autoTargetSwapper),updateToggle("autotargetswapper",!autoTargetSwapper)}function toggleAutoAbilityUser(){autoAbilityUser?stopAutoAbilityUser():startAutoAbilityUser(),WebStorage.SetLocal("autoAbilityUserEnabled",null!==autoAbilityUser),updateToggle("autoabilityuse",!autoAbilityUser)}function toggleAutoItemUser(){autoUseConsumables?stopAutoItemUser():startAutoItemUser(),WebStorage.SetLocal("autoConsumableUserEnabled",autoUseConsumables),updateToggle("autoconsume",!autoUseConsumables)}function toggleAutoUpgradeManager(){autoUpgradeManager?stopAutoUpgradeManager():startAutoUpgradeManager(),WebStorage.SetLocal("autoUpgraderEnabled",null!==autoClicker),updateToggle("autoupgrade",!autoUpgradeManager)}function toggleFPS(){fpsThrottle?stopFPSThrottle():startFPSThrottle(),WebStorage.SetLocal("fpsThrottleEnabled",null!==fpsThrottle),updateToggle("fps",null===fpsThrottle)}function toggleSpamStatBoosters(){spamStatBoosters=!spamStatBoosters,WebStorage.SetLocal("spamStatBoostersEnabled",spamStatBoosters),updateToggle("spamStatBoosters",!spamStatBoosters)}function spamNoClick(){if(autoClicker){var e=g_Minigame.m_CurrentScene.m_nClicks;g_Minigame.m_CurrentScene.DoClick({data:{getLocalPosition:function(){var e=getTarget(),t=440*e.m_nLane;return{x:e.m_Sprite.position.x-t,y:e.m_Sprite.position.y-52}}}}),g_Minigame.m_CurrentScene.m_nClicks=e}}function toggleSpammer(){spammer?(clearInterval(spammer),WebStorage.SetLocal("particleSpamEnabled",!1),spammer=null):confirm("Are you SURE you want to do this? This leads to massive memory leaks fairly quickly.")&&(WebStorage.SetLocal("particleSpamEnabled",!0),spammer=setInterval(spamNoClick,1e3/clicksPerSecond)),updateToggle("particles",null===spammer)}function initLeaderboard(){var e=document.createElement("div");e.id="leaderboard_wrapper",e.style.display="none",document.getElementById("col_right").appendChild(e);var t=document.createElement("table");t.id="leaderboard";var a=document.createElement("tr");a.style.fontSize="11px",a.style.color="#ddd";var n=document.createElement("th"),r=document.createElement("th"),i=document.createElement("th");n.appendChild(document.createTextNode("Rank")),r.appendChild(document.createTextNode("Name")),i.appendChild(document.createTextNode("Level")),a.appendChild(n),a.appendChild(r),a.appendChild(i),t.appendChild(a),document.getElementById("leaderboard_wrapper").appendChild(t);var o=document.createElement("div");o.style.fontSize="12px",o.style.textAlign="center",o.innerHTML='Data by steamga.me',document.getElementById("leaderboard_wrapper").appendChild(o);var s=document.createElement("div");s.id="leaderboard_toggler",s.onclick=function(){toggleLeaderboard()},s.style.position="absolute",s.style.bottom="-48px",s.style.color="black",s.style.textAlign="center",s.style.width="261px",s.style.cursor="pointer",s.appendChild(document.createTextNode("Show Leaderboards")),document.getElementById("col_right").appendChild(s),getLeaderboard(),setInterval(function(){getLeaderboard()},3e4)}function drawLeaderboardRoom(e){var t=document.createElement("tr");t.className="leaderboard_item",t.style.height="23px",t.style.fontSize="10px";var a=document.createElement("td");a.appendChild(document.createTextNode("#"+e.position));var n=document.createElement("td");n.style.textAlign="center",n.appendChild(document.createTextNode(e.name));var r=document.createElement("td");r.style.textAlign="right",r.appendChild(document.createTextNode(e.level)),e.id==g_GameID&&(t.style.color="#d4e157"),t.appendChild(a),t.appendChild(n),t.appendChild(r),document.getElementById("leaderboard").appendChild(t)}function getLeaderboard(){GM_xmlhttpRequest({method:"GET",url:"http://steamga.me/data/api/leaderboard.json",onload:function(e){console.log("Downloading new leaderboard...");for(var t=document.getElementsByClassName("leaderboard_item");t.length>0;)t[0].parentNode.removeChild(t[0]);var a=JSON.parse(e.responseText),n=Object.keys(a).map(function(e){return a[e]});n.sort(function(e,t){return t.level-e.level}),n.map(function(e){drawLeaderboardRoom(e)})}})}function toggleLeaderboard(){var e=document.getElementById("leaderboard_wrapper"),t=document.getElementById("activitylog"),a=document.getElementById("leaderboard_toggler");"block"==e.style.display?(e.style.display="none",t.style.display="block",a.innerHTML="Show Leaderboards"):(e.style.display="block",t.style.display="none",a.innerHTML="Show Activity")}function getSecondsUntilEnd(){return endDate.getTime()/1e3-g_Minigame.m_CurrentScene.m_nTime}function getSecondsPerLevel(){return(g_Minigame.m_CurrentScene.m_rgGameData.timestamp-g_Minigame.m_CurrentScene.m_rgGameData.timestamp_game_start)/g_Minigame.m_CurrentScene.m_rgGameData.level}function hasTimeLeftToUseConsumable(e,t){return(17==e||22==e)&&(t*=6),t?getSecondsUntilEnd()<=getAbilityItemQuantity(e)*abilityCooldown(e):getSecondsUntilEnd()<=getAbilityItemQuantity(e)*abilityCooldown(e)+60*minutesBufferForConsumableDump}function getEstimatedLevelsLeft(){return getSecondsUntilEnd()/getSecondsPerLevel()}function castAbility(e){hasAbility(e)&&(e<=ABILITIES.NAPALM&&null!==document.getElementById("ability_"+e)?g_Minigame.CurrentScene().TryAbility(document.getElementById("ability_"+e).childElements()[0]):null!==document.getElementById("abilityitem_"+e)&&g_Minigame.CurrentScene().TryAbility(document.getElementById("abilityitem_"+e).childElements()[0]))}function currentLaneHasAbility(e){return laneHasAbility(g_Minigame.CurrentScene().m_rgPlayerData.current_lane,e)}function laneHasAbility(e,t){try{return g_Minigame.m_CurrentScene.m_rgLaneData[e].abilities[t]?g_Minigame.m_CurrentScene.m_rgLaneData[e].abilities[t]:0}catch(a){return 0}}function abilityIsUnlocked(e){return e<=ABILITIES.NAPALM?(1<0:getAbilityItemQuantity(e)>0}function getAbilityItemQuantity(e){for(var t=0;t=c)return!1;if(t.m_bIsDestroyed||0>=d)return swapReason="Swapping off a destroyed mob.",!0;if(i!=o){if(i>o&&(3==t.m_data.type||1==t.m_data.type))return swapReason="Switching to target with Raining Gold.",!0}else if(s!=l){if(s>l)return swapReason="Switching to higher priority target.",!0}else if(seekHealingPercent>=a&&!g_Minigame.m_CurrentScene.m_bIsDead){if(n!=r&&n)return swapReason="Swapping to lane with active healing.",!0}else if(u!=g){if(u>g)return swapReason="Switching to elementally weaker target.",!0}else if(c!=d&&d>c)return swapReason="Switching to lower HP target.",!0;return!1}function getTarget(){try{var e=g_Minigame.m_CurrentScene.GetEnemy(g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane,g_Minigame.m_CurrentScene.m_rgPlayerData.target);return e}catch(t){return null}}function gameRunning(){try{return"object"==typeof g_Minigame&&2==g_Minigame.m_CurrentScene.m_rgGameData.status}catch(e){return!1}}function getUploadedFilePath(e){return"undefined"!=typeof GM_info?GM_info.script.namespace.replace("github","raw.githubusercontent")+"/"+e:"https://raw.githubusercontent.com/ensingm2/SteamMonsterGameScript/"+e}function subLong(e,t){var a,n=function(e,t){var a="";if(t.length>e.length&&(a=e,e=t,t=a),a=(parseInt(e.slice(-9),10)+parseInt(t.slice(-9),10)).toString(),e=e.slice(0,-9),t=t.slice(0,-9),a.length>9){if(""===e)return a;e=n(e,"1"),a=a.slice(1)}else if(e.length)for(;a.length<9;)a="0"+a;return""===t?e+a:n(e,t)+a};if(a=(parseInt("1"+e.slice(-9),10)-parseInt(t.slice(-9),10)).toString(),e=e.slice(0,-9),t=t.slice(0,-9),10===a.length||""===e)a=a.slice(1);else if(t=t.length?n(t,"1"):"1",e.length)for(;a.length<9;)a="0"+a;return""===t?a=(e+a).replace(/^0+/,""):subLong(e,t)+a}function getAccountId(e){return parseInt(subLong(""+e,"76561197960265728"))}function getUserName(){return g_Minigame.m_CurrentScene.m_rgPlayerNameCache?g_Minigame.m_CurrentScene.m_rgPlayerNameCache[getAccountId(g_steamID)]:"Unknown"}function getGameLevel(){return g_Minigame.m_CurrentScene.m_rgGameData.level+1}var debug=!1,clicksPerSecond=g_TuningData.abilities[1].max_num_clicks,autoClickerVariance=Math.floor(clicksPerSecond/10);clicksPerSecond-=Math.ceil(autoClickerVariance/2);var respawnCheckFreq=5e3,targetSwapperFreq=1e3,abilityUseCheckFreq=2e3,itemUseCheckFreq=5e3,seekHealingPercent=20,upgradeManagerFreq=5e3,slowRenderingFreq=1e3,autoBuyAbilities=!1,refreshDelay=36e5,spamStatBoosters=!0,useNukeOnBossAbovePercent=25,CONTROL={speedThreshold:2e3,rainingRounds:100,disableGoldRainLevels:200},useMedicsAtPercent=40,useMedicsAtLanePercent=70,useMedicsAtLanePercentAliveReq=30,useNukeOnSpawnerAbovePercent=75,useMetalDetectorOnBossBelowPercent=30,useStealHealthAtPercent=15,useRainingGoldAbovePercent=50,useLikeNewAboveCooldown=1422e4,useResurrectToSaveCount=150,minutesBufferForConsumableDump=10,survivalTime=10,autoClickerFreq=1e3,autoRespawner,autoClicker,autoTargetSwapper,autoTargetSwapperElementUpdate,autoAbilityUser,autoUpgradeManager,fpsThrottle,spammer,elementUpdateRate=6e4,autoUseConsumables=!0,userElementMultipliers=[1,1,1,1],userMaxElementMultiiplier=1,swapReason,lastLootLevel=0,lastLootCache=[],ABILITIES={FIRE_WEAPON:1,CHANGE_LANE:2,RESPAWN:3,CHANGE_TARGET:4,MORALE_BOOSTER:5,GOOD_LUCK_CHARMS:6,MEDICS:7,METAL_DETECTOR:8,DECREASE_COOLDOWNS:9,TACTICAL_NUKE:10,CLUSTER_BOMB:11,NAPALM:12,RESURRECTION:13,CRIPPLE_SPAWNER:14,CRIPPLE_MONSTER:15,MAX_ELEMENTAL_DAMAGE:16,RAINING_GOLD:17,CRIT:18,PUMPED_UP:19,THROW_MONEY_AT_SCREEN:20,GOD_MODE:21,TREASURE:22,STEAL_HEALTH:23,REFLECT_DAMAGE:24,FEELING_LUCKY:25,WORMHOLE:26,LIKE_NEW:27},startAttempts=0,startAll=setInterval(function(){return gameRunning()?(clearInterval(startAll),startAllAutos(),initGUI(),loadSettings(),"undefined"!=typeof unsafeWindow&&initLeaderboard(),"function"==typeof runMaster&&(location.search.match(/slave/)?runSlave():runMaster()),setInterval(function(p){return p.Tick=eval("("+(""+p.Tick).replace(/document\.(hidden|webkitHidden|mozHidden|msHidden)/g,!1)+")"),function(){p=g_Minigame.m_CurrentScene,p&&document.hidden&&p.Tick()}}(CSceneGame.prototype),1e3),void setTimeout(function(){var e=setInterval(function(){var t=getTarget(),a=!currentLaneHasAbility(ABILITIES.RAINING_GOLD)&&4!=t.m_data.type&&2!=t.m_data.type&&3!=t.m_data.type&&t.m_data.type!==!1;a&&(clearInterval(e),location.reload())},15e3)},refreshDelay)):void(1!=g_Minigame.m_CurrentScene.m_rgGameData.status&&(startAttempts>15&&location.reload(),startAttempts++))},1e3);if("undefined"!=typeof unsafeWindow){unsafeWindow.debug=debug,unsafeWindow.clicksPerSecond=clicksPerSecond,unsafeWindow.autoClickerVariance=autoClickerVariance,unsafeWindow.respawnCheckFreq=respawnCheckFreq,unsafeWindow.targetSwapperFreq=targetSwapperFreq,unsafeWindow.abilityUseCheckFreq=abilityUseCheckFreq,unsafeWindow.itemUseCheckFreq=itemUseCheckFreq,unsafeWindow.seekHealingPercent=seekHealingPercent,unsafeWindow.upgradeManagerFreq=upgradeManagerFreq,unsafeWindow.autoBuyAbilities=autoBuyAbilities,unsafeWindow.fpsThrottle=fpsThrottle,unsafeWindow.useMedicsAtPercent=useMedicsAtPercent,unsafeWindow.useMedicsAtLanePercent=useMedicsAtLanePercent,unsafeWindow.useMedicsAtLanePercentAliveReq=useMedicsAtLanePercentAliveReq,unsafeWindow.useNukeOnSpawnerAbovePercent=useNukeOnSpawnerAbovePercent,unsafeWindow.useMetalDetectorOnBossBelowPercent=useMetalDetectorOnBossBelowPercent,unsafeWindow.useStealHealthAtPercent=useStealHealthAtPercent,unsafeWindow.useRainingGoldAbovePercent=useRainingGoldAbovePercent,unsafeWindow.autoUseConsumables=autoUseConsumables,unsafeWindow.useResurrectToSaveCount=useResurrectToSaveCount,unsafeWindow.spamStatBoosters=spamStatBoosters,unsafeWindow.slaveWindowUICleanup=slaveWindowUICleanup,unsafeWindow.slaveWindowPeriodicRestart=slaveWindowPeriodicRestart,unsafeWindow.slaveWindowPeriodicRestartInterval=slaveWindowPeriodicRestartInterval,unsafeWindow.useNukeOnBossAbovePercent=useNukeOnBossAbovePercent,unsafeWindow.startAutoClicker=startAutoClicker,unsafeWindow.startAutoRespawner=startAutoRespawner,unsafeWindow.startAutoTargetSwapper=startAutoTargetSwapper,unsafeWindow.startAutoAbilityUser=startAutoAbilityUser,unsafeWindow.startAutoItemUser=startAutoItemUser,unsafeWindow.startAllAutos=startAllAutos,unsafeWindow.startAutoUpgradeManager=startAutoUpgradeManager,unsafeWindow.stopAutoClicker=stopAutoClicker,unsafeWindow.stopAutoRespawner=stopAutoRespawner,unsafeWindow.stopAutoTargetSwapper=stopAutoTargetSwapper,unsafeWindow.stopAutoAbilityUser=stopAutoAbilityUser,unsafeWindow.stopAutoItemUser=stopAutoItemUser,unsafeWindow.stopAutoUpgradeManager=stopAutoUpgradeManager,unsafeWindow.stopAllAutos=stopAllAutos,unsafeWindow.disableAutoNukes=disableAutoNukes,unsafeWindow.castAbility=castAbility,unsafeWindow.hasAbility=hasAbility,unsafeWindow.abilityIsUnlocked=abilityIsUnlocked,unsafeWindow.abilityCooldown=abilityCooldown,unsafeWindow.toggleAutoClicker=toggleAutoClicker,unsafeWindow.toggleAutoTargetSwapper=toggleAutoTargetSwapper,unsafeWindow.toggleAutoAbilityUser=toggleAutoAbilityUser,unsafeWindow.toggleAutoItemUser=toggleAutoItemUser,unsafeWindow.toggleAutoUpgradeManager=toggleAutoUpgradeManager,unsafeWindow.spamNoClick=spamNoClick,unsafeWindow.toggleSpammer=toggleSpammer,unsafeWindow.getTarget=getTarget,unsafeWindow.currentLaneHasAbility=currentLaneHasAbility,unsafeWindow.laneHasAbility=laneHasAbility,unsafeWindow.getMobTypePriority=getMobTypePriority,unsafeWindow.updateStats=updateStats;var varSetter=setInterval(function(){debug&&console.log("updating options"),debug=unsafeWindow.debug,clicksPerSecond=unsafeWindow.clicksPerSecond,autoClickerVariance=unsafeWindow.autoClickerVariance,respawnCheckFreq=unsafeWindow.respawnCheckFreq,targetSwapperFreq=unsafeWindow.targetSwapperFreq,abilityUseCheckFreq=unsafeWindow.abilityUseCheckFreq,itemUseCheckFreq=unsafeWindow.itemUseCheckFreq,seekHealingPercent=unsafeWindow.seekHealingPercent,upgradeManagerFreq=unsafeWindow.upgradeManagerFreq,autoBuyAbilities=unsafeWindow.autoBuyAbilities,fpsThrottle=unsafeWindow.fpsThrottle,useMedicsAtPercent=unsafeWindow.useMedicsAtPercent,useMedicsAtLanePercent=unsafeWindow.useMedicsAtLanePercent,useMedicsAtLanePercentAliveReq=unsafeWindow.useMedicsAtLanePercentAliveReq,useNukeOnSpawnerAbovePercent=unsafeWindow.useNukeOnSpawnerAbovePercent,useMetalDetectorOnBossBelowPercent=unsafeWindow.useMetalDetectorOnBossBelowPercent,useStealHealthAtPercent=unsafeWindow.useStealHealthAtPercent,useRainingGoldAbovePercent=unsafeWindow.useRainingGoldAbovePercent,useResurrectToSaveCount=unsafeWindow.useResurrectToSaveCount,spamStatBoosters=unsafeWindow.spamStatBoosters,useNukeOnBossAbovePercent=unsafeWindow.useNukeOnBossAbovePercent},5e3);unsafeWindow.getDebug=function(){return debug},unsafeWindow.setDebug=function(e){debug=e}}var upgradeManagerPrefilter;upgradeManagerPrefilter||$J.ajaxPrefilter(function(){void 0!==upgradeManagerPrefilter&&upgradeManagerPrefilter.apply(this,arguments)});var gameOldRenderer=function(){},endDate=initEndDate(); -------------------------------------------------------------------------------- /notes.txt: -------------------------------------------------------------------------------- 1 | Notes: 2 | 3 | Ability IDs (id - action - data added to requested_abilities array in POST data) 4 | 1 - Normal Click - {"ability":1,"num_clicks":n} (where 'n' is some int) 5 | 2 - Swap Lane - {"ability":2,"new_lane":n} (where 'n' is the lane number 0-2) 6 | 3 - 7 | 4 - Swap Target - {"ability":4,"new_target":n} (where 'n' is the target ID 0-3, not sure how the layout is set) 8 | 5 - Morale Booster - {"ability":5} 9 | 6 - Good Luck Charms - {"ability":6} 10 | 7 - Medics - {"ability":7} 11 | 8 - Metal Detector - {"ability":8} 12 | 9 - Decrease Cooldowns - {"ability":9} 13 | 10 - Nuke - {"ability":10} 14 | 11 - Cluster Bomb - {"ability":11} 15 | 12 - Napalm - {"ability":12} 16 | 13 - Resurrect - {"ability":13} 17 | 14 - Cripple Spawner - {"ability":14} 18 | 15 - Cripple Monster - {"ability":15} 19 | 16 - Max Elemental Damage - {"ability":16} 20 | 17 - Raining Gold - {"ability":17} 21 | 18 - Crit - {"ability":18} 22 | 19 - Pumped Up - {"ability":19} 23 | 20 - Throw Money at Screen - {"ability":20} 24 | 21 - God Mode - {"ability":21} 25 | 22 - Treasure - {"ability":22} 26 | 23 - Steal Health - {"ability":23} 27 | 24 - Reflect Damage - {"ability":24} 28 | 25 - Feeling Lucky 29 | 26 - Wormhole 30 | 27 - Like New -------------------------------------------------------------------------------- /slaveWindows.js: -------------------------------------------------------------------------------- 1 | //Slave Window Variables 2 | var slaveWindowUICleanup = true; // Hide all UI and disable rendering for slaves. This will help on CPU and possibly RAM usage 3 | var slaveWindowPeriodicRestart = true; // Periodically restarts slaves in attempts to free memory 4 | var slaveWindowPeriodicRestartInterval = 5 * 60 * 1000; // Period to restart slaves (In milliseconds) 5 | var slaveDelayBetweenSpawns = 1000; // Delay (in milliseconds) between when each slave will spawn. 6 | 7 | //================= Adding slave windows ============================= 8 | // See: https://github.com/ags131/steamMinigameSlaveScript 9 | 10 | function runMaster() 11 | { 12 | window.onbeforeunload = function(){ killAllSlaves(false); }; 13 | 14 | var slavesList = window.slaves = []; 15 | 16 | function spawnSlave(){ 17 | var num = slavesList.length; 18 | var slaveheight = screen.height / 10; 19 | var params = 'left=0, top='+(num*100)+', width=220, height=100'; 20 | var slave = window.open("http://steamcommunity.com/minigame/towerattack/?slave",'slave'+num, params); 21 | slavesList.push(slave); 22 | $J('.slaveWindowCount').text(slavesList.length); 23 | } 24 | 25 | function spawnSlaves(cnt){ 26 | if(typeof cnt == 'object') 27 | cnt = parseInt(prompt("How many slave windows would you like to open?\n(REMEMBER TO ALLOW POPUPS)", "2")); 28 | 29 | if(cnt === 0 || typeof cnt === 'object') 30 | return; 31 | 32 | console.log("spawning " + cnt + " slave windows."); 33 | 34 | //Mute Sounds 35 | WebStorage.SetLocal('minigame_mute', true); 36 | WebStorage.SetLocal('minigame_mutemusic', true); 37 | g_AudioManager.m_eleMusic.pause(); 38 | 39 | 40 | //Set the local variable (for restarts) 41 | WebStorage.SetLocal('minigame_slaveCount', cnt); 42 | 43 | for(var i=0;i').addClass('slaveManager'); 69 | 70 | 71 | var counterStyle = { 72 | 'position': 'relative', 73 | 'font-weight': 'bold', 74 | 'top': '15px', 75 | 'color': '#FF8585', 76 | "float": "right", 77 | "margin-right": "40px" 78 | }; 79 | 80 | $J("#settings").append('
Spawn Slaves
Kill Slaves
Slaves: 0
'); 81 | $J("#spawn_slaves").click(function(e) { e.stopPropagation(); spawnSlaves(e); }); 82 | $J("#kill_slaves").click(function(e) { e.stopPropagation(); killAllSlaves(); }); 83 | 84 | $J('#slaveCounter').css(counterStyle); 85 | 86 | var autoOpenSlaveCount = WebStorage.GetLocal('minigame_slaveCount'); 87 | if(autoOpenSlaveCount !== null && autoOpenSlaveCount !== 0) 88 | spawnSlaves(autoOpenSlaveCount); 89 | 90 | } 91 | function runSlave() 92 | { 93 | 94 | if(slaveWindowUICleanup){ 95 | var cleanupPageInter = setInterval(function(){ 96 | if(window.CUI || g_Minigame.m_CurrentScene.m_bRunning) 97 | { 98 | clearInterval(cleanupPageInter); 99 | $J('body > *').hide(); 100 | var cont = $J('body'); 101 | $J('
').css({ 102 | 'padding-top': '20px', 103 | 'font-family': '"Press Start 2P"', 104 | 'font-size': '32pt' 105 | }) 106 | .text('Slave') 107 | .appendTo(cont); 108 | g_Minigame.Renderer.render = function(){}; // Disable rendering. Completely. 109 | } 110 | },1000); 111 | } 112 | 113 | if(slaveWindowPeriodicRestart) { 114 | var resetInterval = setInterval(function () { 115 | // Only refresh if we're not on a boss / Treasure mob 116 | var target = getTarget(); 117 | if(target && target.m_data.type != 2 && target.m_data.type != 4 ){ 118 | clearInterval(resetInterval); // Shouldn't need this but meh. 119 | window.location.href = "./?slave"; 120 | } 121 | 122 | }, slaveWindowPeriodicRestartInterval); 123 | } 124 | 125 | //Don't allow slaves to purchase upgrades or use abilities/items 126 | stopAutoAbilityUser(); 127 | stopAutoItemUser(); 128 | stopAutoUpgradeManager(); 129 | } --------------------------------------------------------------------------------