├── 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 | }
--------------------------------------------------------------------------------