Advertisement
Guest User

Untitled

a guest
Jun 13th, 2015
295
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 30.75 KB | None | 0 0
  1. // ==UserScript==
  2. // @name Monster Minigame Auto-script w/ auto-click
  3. // @namespace https://github.com/SteamDatabase/steamSummerMinigame
  4. // @description A script that runs the Steam Monster Minigame for you.
  5. // @version 3.6.5
  6. // @match *://steamcommunity.com/minigame/towerattack*
  7. // @match *://steamcommunity.com//minigame/towerattack*
  8. // @grant none
  9. // @updateURL https://raw.githubusercontent.com/SteamDatabase/steamSummerMinigame/master/autoPlay.user.js
  10. // @downloadURL https://raw.githubusercontent.com/SteamDatabase/steamSummerMinigame/master/autoPlay.user.js
  11. // ==/UserScript==
  12.  
  13.  
  14. // IMPORTANT: Update the @version property above to a higher number such as 1.1 and 1.2 when you update the script! Otherwise, Tamper / Greasemonkey users will not update automatically.
  15.  
  16.  
  17. (function(w) {
  18. "use strict";
  19.  
  20.  
  21. var isAlreadyRunning = false;
  22. var clickRate = 1000;
  23. var logLevel = 1; // 5 is the most verbose, 0 disables all log
  24. var removeInterface = false; // get rid of a bunch of pointless DOM
  25.  
  26.  
  27. var optimizeGraphics = true; //set this to false if you don't want effects disabled (introduces memory leak.)
  28.  
  29.  
  30. var ABILITIES = {
  31. "MORALE_BOOSTER": 5,
  32. "GOOD_LUCK": 6,
  33. "MEDIC": 7,
  34. "METAL_DETECTOR": 8,
  35. "COOLDOWN": 9,
  36. "NUKE": 10,
  37. "CLUSTER_BOMB": 11,
  38. "NAPALM": 12
  39. };
  40.  
  41.  
  42. var ITEMS = {
  43. "REVIVE": 13,
  44. "CRIPPLE_SPAWNER": 14,
  45. "CRIPPLE_MONSTER": 15,
  46. "MAXIMIZE_ELEMENT": 16,
  47. "GOLD_RAIN": 17,
  48. "CRIT": 18,
  49. "PUMPED_UP": 19,
  50. "THROW_MONEY": 20,
  51. "GOD_MODE": 21,
  52. "TREASURE": 22,
  53. "STEAL_HEALTH": 23,
  54. "REFLECT_DAMAGE": 24
  55. };
  56.  
  57.  
  58. var ENEMY_TYPE = {
  59. "SPAWNER":0,
  60. "CREEP":1,
  61. "BOSS":2,
  62. "MINIBOSS":3,
  63. "TREASURE":4
  64. };
  65.  
  66.  
  67.  
  68.  
  69. function firstRun() {
  70. lockElements();
  71. // disable particle effects - this drastically reduces the game's memory leak
  72. if(!optimizeGraphics) {
  73. return;
  74. }
  75.  
  76.  
  77. if (g_Minigame !== undefined) {
  78. g_Minigame.CurrentScene().SpawnEmitter = function(emitter) {
  79. emitter.emit = false;
  80. return emitter;
  81. };
  82. }
  83.  
  84.  
  85. // disable enemy flinching animation when they get hit
  86. if (CEnemy !== undefined) {
  87. CEnemy.prototype.TakeDamage = function() {};
  88. CEnemySpawner.prototype.TakeDamage = function() {};
  89. CEnemyBoss.prototype.TakeDamage = function() {};
  90. }
  91.  
  92.  
  93. if ( removeInterface ) {
  94. var node = document.getElementById("global_header");
  95. if (node && node.parentNode) {
  96. node.parentNode.removeChild( node );
  97. }
  98. node = document.getElementById("footer");
  99. if (node && node.parentNode) {
  100. node.parentNode.removeChild( node );
  101. }
  102. node = document.getElementById("footer_spacer");
  103. if (node && node.parentNode) {
  104. node.parentNode.removeChild( node );
  105. }
  106. node = document.querySelector(".leave_game_helper");
  107. if (node && node.parentNode) {
  108. node.parentNode.removeChild( node );
  109. }
  110. node = document.querySelector(".pagecontent");
  111. if (node) {
  112. node.style = "padding-bottom: 0";
  113. }
  114. document.body.style.backgroundPosition = "0 0";
  115. }
  116.  
  117.  
  118. if (w.CSceneGame !== undefined) {
  119. w.CSceneGame.prototype.DoScreenShake = function() {};
  120. }
  121.  
  122.  
  123. enhanceTooltips();
  124. }
  125.  
  126.  
  127. function MainLoop() {
  128. if (!isAlreadyRunning) {
  129. isAlreadyRunning = true;
  130.  
  131.  
  132. goToLaneWithBestTarget();
  133. useGoodLuckCharmIfRelevant();
  134. useMedicsIfRelevant();
  135. useMoraleBoosterIfRelevant();
  136. useClusterBombIfRelevant();
  137. useNapalmIfRelevant();
  138. useTacticalNukeIfRelevant();
  139. useCrippleSpawnerIfRelevant();
  140. useGoldRainIfRelevant();
  141. useMetalDetectorIfRelevant();
  142. attemptRespawn();
  143. disableCooldownIfRelevant();
  144.  
  145.  
  146. g_Minigame.m_CurrentScene.m_nClicks = clickRate;
  147. g_msTickRate = 100000;
  148.  
  149.  
  150. var damagePerClick = g_Minigame.m_CurrentScene.CalculateDamage(
  151. g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_per_click,
  152. g_Minigame.m_CurrentScene.m_rgGameData.lanes[g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane].element
  153. );
  154.  
  155.  
  156. advLog("Ticked. Current clicks per second: " + clickRate + ". Current damage per second: " + (damagePerClick * clickRate), 4);
  157.  
  158.  
  159. isAlreadyRunning = false;
  160.  
  161.  
  162. var enemy = g_Minigame.m_CurrentScene.GetEnemy(
  163. g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane,
  164. g_Minigame.m_CurrentScene.m_rgPlayerData.target);
  165.  
  166.  
  167. if (enemy) {
  168. displayText(
  169. enemy.m_Sprite.position.x - (enemy.m_nLane * 440),
  170. enemy.m_Sprite.position.y - 52,
  171. "-" + FormatNumberForDisplay((damagePerClick * clickRate), 5),
  172. "#aaf"
  173. );
  174.  
  175.  
  176. if( g_Minigame.m_CurrentScene.m_rgStoredCrits.length > 0 )
  177. {
  178. var rgDamage = g_Minigame.m_CurrentScene.m_rgStoredCrits.splice(0,1);
  179.  
  180.  
  181. g_Minigame.m_CurrentScene.DoCritEffect( rgDamage[0], enemy.m_Sprite.position.x - (enemy.m_nLane * 440), enemy.m_Sprite.position.y - 52, 'Crit!' );
  182. }
  183.  
  184.  
  185. var goldPerClickPercentage = g_Minigame.m_CurrentScene.m_rgGameData.lanes[g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane].active_player_ability_gold_per_click;
  186. if (goldPerClickPercentage > 0 && enemy.m_data.hp > 0)
  187. {
  188. var goldPerSecond = enemy.m_data.gold * goldPerClickPercentage * clickRate;
  189. advLog(
  190. "Raining gold ability is active in current lane. Percentage per click: " + goldPerClickPercentage
  191. + "%. Approximately gold per second: " + goldPerSecond,
  192. 4
  193. );
  194. displayText(
  195. enemy.m_Sprite.position.x - (enemy.m_nLane * 440),
  196. enemy.m_Sprite.position.y - 17,
  197. "+" + FormatNumberForDisplay(goldPerSecond, 5),
  198. "#e1b21e"
  199. );
  200. }
  201. }
  202. }
  203. }
  204.  
  205.  
  206. function lockElements() {
  207. var elementMultipliers = [
  208. g_Minigame.CurrentScene().m_rgPlayerTechTree.damage_multiplier_fire,
  209. g_Minigame.CurrentScene().m_rgPlayerTechTree.damage_multiplier_water,
  210. g_Minigame.CurrentScene().m_rgPlayerTechTree.damage_multiplier_air,
  211. g_Minigame.CurrentScene().m_rgPlayerTechTree.damage_multiplier_earth
  212. ];
  213.  
  214.  
  215. var hashCode=function(str) {
  216. var t=0, i, char;
  217. if (0 === str.length) {
  218. return t;
  219. }
  220.  
  221.  
  222. for (i=0; i<str.length; i++) {
  223. char=str.charCodeAt(i);
  224. t=(t<<5)-t+char;
  225. t&=t;
  226. }
  227.  
  228.  
  229. return t;
  230. };
  231.  
  232.  
  233. var elem = Math.abs(hashCode(g_steamID)%4);
  234.  
  235.  
  236. // If more than two elements are leveled to 3 or higher, do not enable lock
  237. var leveled = 0;
  238. var lastLeveled = -1;
  239.  
  240.  
  241. for (var i=0; i < elementMultipliers.length; i++){
  242. advLog("Element " + i + " is at level " + (elementMultipliers[i]-1)/1.5, 3);
  243. if ((elementMultipliers[i]-1)/1.5 >= 3) {
  244. leveled++;
  245. // Only used if there is only one so overwriting it doesn't matter
  246. lastLeveled = i;
  247. }
  248. }
  249.  
  250.  
  251. if (leveled >= 2) {
  252. advLog("More than 2 elementals leveled to 3 or above, not locking.", 1);
  253. return;
  254. } else if (leveled == 1) {
  255. advLog("Found existing lock on " + lastLeveled + ", locking to it.", 1);
  256. lockToElement(lastLeveled);
  257. } else {
  258. advLog("Locking to element " + elem + " as chosen by SteamID", 1);
  259. lockToElement(elem);
  260. }
  261. }
  262.  
  263.  
  264. function lockToElement(element) {
  265. var fire = document.querySelector("a.link.element_upgrade_btn[data-type=\"3\"]");
  266. var water = document.querySelector("a.link.element_upgrade_btn[data-type=\"4\"]");
  267. var air = document.querySelector("a.link.element_upgrade_btn[data-type=\"5\"]");
  268. var earth = document.querySelector("a.link.element_upgrade_btn[data-type=\"6\"]");
  269.  
  270.  
  271. var elems = [fire, water, air, earth];
  272.  
  273.  
  274. for (var i=0; i < elems.length; i++) {
  275. if (i === element) {
  276. continue;
  277. }
  278. elems[i].style.visibility = "hidden";
  279. }
  280. }
  281.  
  282.  
  283. function displayText(x, y, strText, color) {
  284. var text = new PIXI.Text(strText, {font: "35px 'Press Start 2P'", fill: color, stroke: '#000', strokeThickness: 2 });
  285.  
  286.  
  287. text.x = x;
  288. text.y = y;
  289.  
  290.  
  291. g_Minigame.CurrentScene().m_containerUI.addChild( text );
  292. text.container = g_Minigame.CurrentScene().m_containerUI;
  293.  
  294.  
  295. var e = new CEasingSinOut( text.y, -200, 1000 );
  296. e.parent = text;
  297. text.m_easeY = e;
  298.  
  299.  
  300. e = new CEasingSinOut( 2, -2, 1000 );
  301. e.parent = text;
  302. text.m_easeAlpha = e;
  303.  
  304.  
  305. g_Minigame.CurrentScene().m_rgClickNumbers.push(text);
  306. }
  307.  
  308.  
  309. function goToLaneWithBestTarget() {
  310. // We can overlook spawners if all spawners are 40% hp or higher and a creep is under 10% hp
  311. var spawnerOKThreshold = 0.4;
  312. var creepSnagThreshold = 0.1;
  313.  
  314.  
  315. var targetFound = false;
  316. var lowHP = 0;
  317. var lowLane = 0;
  318. var lowTarget = 0;
  319. var lowPercentageHP = 0;
  320. var preferredLane = -1;
  321. var preferredTarget = -1;
  322.  
  323.  
  324. // determine which lane and enemy is the optimal target
  325. var enemyTypePriority = [
  326. ENEMY_TYPE.TREASURE,
  327. ENEMY_TYPE.BOSS,
  328. ENEMY_TYPE.MINIBOSS,
  329. ENEMY_TYPE.SPAWNER,
  330. ENEMY_TYPE.CREEP
  331. ];
  332.  
  333.  
  334. var i;
  335. var skippingSpawner = false;
  336. var skippedSpawnerLane = 0;
  337. var skippedSpawnerTarget = 0;
  338. var targetIsTreasureOrBoss = false;
  339.  
  340.  
  341. for (var k = 0; !targetFound && k < enemyTypePriority.length; k++) {
  342.  
  343.  
  344. if (enemyTypePriority[k] == ENEMY_TYPE.TREASURE || enemyTypePriority[k] == ENEMY_TYPE.BOSS){
  345. targetIsTreasureOrBoss = true;
  346. } else {
  347. targetIsTreasureOrBoss = false;
  348. }
  349.  
  350.  
  351. var enemies = [];
  352.  
  353.  
  354. // gather all the enemies of the specified type.
  355. for (i = 0; i < 3; i++) {
  356. for (var j = 0; j < 4; j++) {
  357. var enemy = g_Minigame.CurrentScene().GetEnemy(i, j);
  358. if (enemy && enemy.m_data.type == enemyTypePriority[k]) {
  359. enemies[enemies.length] = enemy;
  360. }
  361. }
  362. }
  363.  
  364.  
  365. //Prefer lane with raining gold, unless current enemy target is a treasure or boss.
  366. if(lowTarget != ENEMY_TYPE.TREASURE && lowTarget != ENEMY_TYPE.BOSS ){
  367. var potential = 0;
  368. // Loop through lanes by elemental preference
  369. var sortedLanes = sortLanesByElementals();
  370. for(var notI = 0; notI < sortedLanes.length; notI++){
  371. // Maximize compability with upstream
  372. i = sortedLanes[notI];
  373. // ignore if lane is empty
  374. if(g_Minigame.CurrentScene().m_rgGameData.lanes[i].dps === 0)
  375. continue;
  376. var stacks = 0;
  377. if(typeof g_Minigame.m_CurrentScene.m_rgLaneData[i].abilities[17] != 'undefined') {
  378. stacks = g_Minigame.m_CurrentScene.m_rgLaneData[i].abilities[17];
  379. advLog('stacks: ' + stacks, 3);
  380. }
  381. for(var m = 0; m < g_Minigame.m_CurrentScene.m_rgEnemies.length; m++) {
  382. var enemyGold = g_Minigame.m_CurrentScene.m_rgEnemies[m].m_data.gold;
  383. if (stacks * enemyGold > potential) {
  384. potential = stacks * enemyGold;
  385. preferredTarget = g_Minigame.m_CurrentScene.m_rgEnemies[m].m_nID;
  386. preferredLane = i;
  387. }
  388. }
  389. }
  390. }
  391.  
  392.  
  393. // target the enemy of the specified type with the lowest hp
  394. var mostHPDone = 0;
  395. for (i = 0; i < enemies.length; i++) {
  396. if (enemies[i] && !enemies[i].m_bIsDestroyed) {
  397. // Only select enemy and lane if the preferedLane matches the potential enemy lane
  398. if(lowHP < 1 || enemies[i].m_flDisplayedHP < lowHP) {
  399. var element = g_Minigame.CurrentScene().m_rgGameData.lanes[enemies[i].m_nLane].element;
  400.  
  401.  
  402. var dmg = g_Minigame.CurrentScene().CalculateDamage(
  403. g_Minigame.CurrentScene().m_rgPlayerTechTree.dps,
  404. element
  405. );
  406. if(mostHPDone < dmg)
  407. {
  408. mostHPDone = dmg;
  409. } else {
  410. continue;
  411. }
  412.  
  413.  
  414. targetFound = true;
  415. lowHP = enemies[i].m_flDisplayedHP;
  416. lowLane = enemies[i].m_nLane;
  417. lowTarget = enemies[i].m_nID;
  418. }
  419. var percentageHP = enemies[i].m_flDisplayedHP / enemies[i].m_data.max_hp;
  420. if (lowPercentageHP === 0 || percentageHP < lowPercentageHP) {
  421. lowPercentageHP = percentageHP;
  422. }
  423. }
  424. }
  425.  
  426.  
  427. if(preferredLane != -1 && preferredTarget != -1){
  428. lowLane = preferredLane;
  429. lowTarget = preferredTarget;
  430. advLog('Switching to a lane with best raining gold benefit', 2);
  431. }
  432.  
  433.  
  434. // If we just finished looking at spawners,
  435. // AND none of them were below our threshold,
  436. // remember them and look for low creeps (so don't quit now)
  437. // Don't skip spawner if lane has raining gold
  438. if ((enemyTypePriority[k] == ENEMY_TYPE.SPAWNER && lowPercentageHP > spawnerOKThreshold) && preferredLane == -1) {
  439. skippedSpawnerLane = lowLane;
  440. skippedSpawnerTarget = lowTarget;
  441. skippingSpawner = true;
  442. targetFound = false;
  443. }
  444.  
  445.  
  446. // If we skipped a spawner and just finished looking at creeps,
  447. // AND the lowest was above our snag threshold,
  448. // just go back to the spawner!
  449. if (skippingSpawner && enemyTypePriority[k] == ENEMY_TYPE.CREEP && lowPercentageHP > creepSnagThreshold ) {
  450. lowLane = skippedSpawnerLane;
  451. lowTarget = skippedSpawnerTarget;
  452. }
  453. }
  454.  
  455.  
  456.  
  457.  
  458. // go to the chosen lane
  459. if (targetFound) {
  460. if (g_Minigame.CurrentScene().m_nExpectedLane != lowLane) {
  461. advLog('Switching to lane' + lowLane, 3);
  462. g_Minigame.CurrentScene().TryChangeLane(lowLane);
  463. }
  464.  
  465.  
  466. // target the chosen enemy
  467. if (g_Minigame.CurrentScene().m_nTarget != lowTarget) {
  468. advLog('Switching targets', 3);
  469. g_Minigame.CurrentScene().TryChangeTarget(lowTarget);
  470. }
  471.  
  472.  
  473.  
  474.  
  475. // Prevent attack abilities and items if up against a boss or treasure minion
  476. if (targetIsTreasureOrBoss) {
  477. // Morale
  478. disableAbility(ABILITIES.MORALE_BOOSTER);
  479. // Luck
  480. disableAbility(ABILITIES.GOOD_LUCK);
  481. // Nuke
  482. disableAbility(ABILITIES.NUKE);
  483. // Clusterbomb
  484. disableAbility(ABILITIES.CLUSTER_BOMB);
  485. // Napalm
  486. disableAbility(ABILITIES.NAPALM);
  487. // Crit
  488. disableAbilityItem(ITEMS.CRIT);
  489. // Cripple Spawner
  490. disableAbilityItem(ITEMS.CRIPPLE_SPAWNER);
  491. // Cripple Monster
  492. disableAbilityItem(ITEMS.CRIPPLE_MONSTER);
  493. // Max Elemental Damage
  494. disableAbilityItem(ITEMS.MAXIMIZE_ELEMENT);
  495. // Reflect Damage
  496. disableAbilityItem(ITEMS.REFLECT_DAMAGE);
  497. // Throw Money at Screen
  498. disableAbilityItem(ITEMS.THROW_MONEY);
  499. } else {
  500. // Morale
  501. enableAbility(ABILITIES.MORALE_BOOSTER);
  502. // Luck
  503. enableAbility(ABILITIES.GOOD_LUCK);
  504. // Nuke
  505. enableAbility(ABILITIES.NUKE);
  506. // Clusterbomb
  507. enableAbility(ABILITIES.CLUSTER_BOMB);
  508. // Napalm
  509. enableAbility(ABILITIES.NAPALM);
  510. // Crit
  511. enableAbilityItem(ITEMS.CRIT);
  512. // Cripple Spawner
  513. enableAbilityItem(ITEMS.CRIPPLE_SPAWNER);
  514. // Cripple Monster
  515. enableAbilityItem(ITEMS.CRIPPLE_MONSTER);
  516. // Max Elemental Damage
  517. enableAbilityItem(ITEMS.MAXIMIZE_ELEMENT);
  518. // Reflect Damage
  519. enableAbilityItem(ITEMS.REFLECT_DAMAGE);
  520. // Throw Money at Screen
  521. enableAbilityItem(ITEMS.THROW_MONEY);
  522. }
  523. }
  524. }
  525.  
  526.  
  527. function disableCooldownIfRelevant() {
  528. if(getActiveAbilityNum(ABILITIES.COOLDOWN) > 0)
  529. {
  530. disableAbility(ABILITIES.COOLDOWN);
  531. return;
  532. }
  533.  
  534.  
  535. if(!isAbilityActive(ABILITIES.COOLDOWN))
  536. {
  537. enableAbility(ABILITIES.COOLDOWN);
  538. }
  539.  
  540.  
  541. }
  542.  
  543.  
  544. function useMedicsIfRelevant() {
  545. var myMaxHealth = g_Minigame.CurrentScene().m_rgPlayerTechTree.max_hp;
  546.  
  547.  
  548. // check if health is below 50%
  549. var hpPercent = g_Minigame.CurrentScene().m_rgPlayerData.hp / myMaxHealth;
  550. if (hpPercent > 0.5 || g_Minigame.CurrentScene().m_rgPlayerData.hp < 1) {
  551. return; // no need to heal - HP is above 50% or already dead
  552. }
  553.  
  554.  
  555. // check if Medics is purchased and cooled down
  556. if (hasPurchasedAbility(ABILITIES.MEDIC) && !isAbilityCoolingDown(ABILITIES.MEDIC)) {
  557.  
  558.  
  559. // Medics is purchased, cooled down, and needed. Trigger it.
  560. advLog('Medics is purchased, cooled down, and needed. Trigger it.', 2);
  561. triggerAbility(ABILITIES.MEDIC);
  562. } else if (hasItem(ITEMS.GOD_MODE) && !isAbilityCoolingDown(ITEMS.GOD_MODE)) {
  563.  
  564.  
  565. advLog('We have god mode, cooled down, and needed. Trigger it.', 2);
  566. triggerItem(ITEMS.GOD_MODE);
  567. }
  568. }
  569.  
  570.  
  571. // Use Good Luck Charm if doable
  572. function useGoodLuckCharmIfRelevant() {
  573.  
  574.  
  575. // check if Crits is purchased and cooled down
  576. if (hasOneUseAbility(18) && !isAbilityCoolingDown(18)){
  577. // Crits is purchased, cooled down, and needed. Trigger it.
  578. advLog('Crit chance is always good.', 3);
  579. triggerAbility(18);
  580. }
  581.  
  582.  
  583. // check if Good Luck Charms is purchased and cooled down
  584. if (hasPurchasedAbility(ABILITIES.GOOD_LUCK)) {
  585. if (isAbilityCoolingDown(ABILITIES.GOOD_LUCK)) {
  586. return;
  587. }
  588.  
  589.  
  590. if (! isAbilityEnabled(ABILITIES.GOOD_LUCK)) {
  591. return;
  592. }
  593.  
  594.  
  595. // Good Luck Charms is purchased, cooled down, and needed. Trigger it.
  596. advLog('Good Luck Charms is purchased, cooled down, and needed. Trigger it.', 2);
  597. triggerAbility(ABILITIES.GOOD_LUCK);
  598. }
  599. }
  600.  
  601.  
  602. function useClusterBombIfRelevant() {
  603. //Check if Cluster Bomb is purchased and cooled down
  604. if (hasPurchasedAbility(ABILITIES.CLUSTER_BOMB)) {
  605. if (isAbilityCoolingDown(ABILITIES.CLUSTER_BOMB)) {
  606. return;
  607. }
  608.  
  609.  
  610. //Check lane has monsters to explode
  611. var currentLane = g_Minigame.CurrentScene().m_nExpectedLane;
  612. var enemyCount = 0;
  613. var enemySpawnerExists = false;
  614. //Count each slot in lane
  615. for (var i = 0; i < 4; i++) {
  616. var enemy = g_Minigame.CurrentScene().GetEnemy(currentLane, i);
  617. if (enemy) {
  618. enemyCount++;
  619. if (enemy.m_data.type === 0) {
  620. enemySpawnerExists = true;
  621. }
  622. }
  623. }
  624. //Bombs away if spawner and 2+ other monsters
  625. if (enemySpawnerExists && enemyCount >= 3) {
  626. triggerAbility(ABILITIES.CLUSTER_BOMB);
  627. }
  628. }
  629. }
  630.  
  631.  
  632. function useNapalmIfRelevant() {
  633. //Check if Napalm is purchased and cooled down
  634. if (hasPurchasedAbility(ABILITIES.NAPALM)) {
  635. if (isAbilityCoolingDown(ABILITIES.NAPALM)) {
  636. return;
  637. }
  638.  
  639.  
  640. //Check lane has monsters to burn
  641. var currentLane = g_Minigame.CurrentScene().m_nExpectedLane;
  642. var enemyCount = 0;
  643. var enemySpawnerExists = false;
  644. //Count each slot in lane
  645. for (var i = 0; i < 4; i++) {
  646. var enemy = g_Minigame.CurrentScene().GetEnemy(currentLane, i);
  647. if (enemy) {
  648. enemyCount++;
  649. if (enemy.m_data.type === 0) {
  650. enemySpawnerExists = true;
  651. }
  652. }
  653. }
  654. //Burn them all if spawner and 2+ other monsters
  655. if (enemySpawnerExists && enemyCount >= 3) {
  656. triggerAbility(ABILITIES.NAPALM);
  657. }
  658. }
  659. }
  660.  
  661.  
  662. // Use Moral Booster if doable
  663. function useMoraleBoosterIfRelevant() {
  664. // check if Good Luck Charms is purchased and cooled down
  665. if (hasPurchasedAbility(ABILITIES.MORALE_BOOSTER)) {
  666. if (isAbilityCoolingDown(ABILITIES.MORALE_BOOSTER)) {
  667. return;
  668. }
  669. var numberOfWorthwhileEnemies = 0;
  670. for(var i = 0; i < g_Minigame.CurrentScene().m_rgGameData.lanes[g_Minigame.CurrentScene().m_nExpectedLane].enemies.length; i++){
  671. //Worthwhile enemy is when an enamy has a current hp value of at least 1,000,000
  672. if(g_Minigame.CurrentScene().m_rgGameData.lanes[g_Minigame.CurrentScene().m_nExpectedLane].enemies[i].hp > 1000000) {
  673. numberOfWorthwhileEnemies++;
  674. }
  675. }
  676. if(numberOfWorthwhileEnemies >= 2){
  677. // Moral Booster is purchased, cooled down, and needed. Trigger it.
  678. advLog('Moral Booster is purchased, cooled down, and needed. Trigger it.', 2);
  679. triggerAbility(ABILITIES.MORALE_BOOSTER);
  680. }
  681. }
  682. }
  683. function useTacticalNukeIfRelevant() {
  684. // Check if Tactical Nuke is purchased
  685. if(hasPurchasedAbility(ABILITIES.NUKE)) {
  686. if (isAbilityCoolingDown(ABILITIES.NUKE)) {
  687. return;
  688. }
  689.  
  690.  
  691. //Check that the lane has a spawner and record it's health percentage
  692. var currentLane = g_Minigame.CurrentScene().m_nExpectedLane;
  693. var enemySpawnerExists = false;
  694. var enemySpawnerHealthPercent = 0.0;
  695. //Count each slot in lane
  696. for (var i = 0; i < 4; i++) {
  697. var enemy = g_Minigame.CurrentScene().GetEnemy(currentLane, i);
  698. if (enemy) {
  699. if (enemy.m_data.type === 0) {
  700. enemySpawnerExists = true;
  701. enemySpawnerHealthPercent = enemy.m_flDisplayedHP / enemy.m_data.max_hp;
  702. }
  703. }
  704. }
  705.  
  706.  
  707. // If there is a spawner and it's health is between 60% and 30%, nuke it!
  708. if (enemySpawnerExists && enemySpawnerHealthPercent < 0.6 && enemySpawnerHealthPercent > 0.3) {
  709. advLog("Tactical Nuke is purchased, cooled down, and needed. Nuke 'em.", 2);
  710. triggerAbility(ABILITIES.NUKE);
  711. }
  712. }
  713. }
  714.  
  715.  
  716. function useCrippleSpawnerIfRelevant() {
  717. // Check if Cripple Spawner is available
  718. if(hasItem(ITEMS.CRIPPLE_SPAWNER)) {
  719. if (isAbilityCoolingDown(ITEMS.CRIPPLE_SPAWNER)) {
  720. return;
  721. }
  722.  
  723.  
  724. //Check that the lane has a spawner and record it's health percentage
  725. var currentLane = g_Minigame.CurrentScene().m_nExpectedLane;
  726. var enemySpawnerExists = false;
  727. var enemySpawnerHealthPercent = 0.0;
  728. //Count each slot in lane
  729. for (var i = 0; i < 4; i++) {
  730. var enemy = g_Minigame.CurrentScene().GetEnemy(currentLane, i);
  731. if (enemy) {
  732. if (enemy.m_data.type === 0) {
  733. enemySpawnerExists = true;
  734. enemySpawnerHealthPercent = enemy.m_flDisplayedHP / enemy.m_data.max_hp;
  735. }
  736. }
  737. }
  738.  
  739.  
  740. // If there is a spawner and it's health is above 95%, cripple it!
  741. if (enemySpawnerExists && enemySpawnerHealthPercent > 0.95) {
  742. advLog("Cripple Spawner available, and needed. Cripple 'em.", 2);
  743. triggerItem(ITEMS.CRIPPLE_SPAWNER);
  744. }
  745. }
  746. }
  747.  
  748.  
  749. function useGoldRainIfRelevant() {
  750. // Check if gold rain is purchased
  751. if (hasItem(ITEMS.GOLD_RAIN)) {
  752. if (isAbilityCoolingDown(ITEMS.GOLD_RAIN)) {
  753. return;
  754. }
  755.  
  756.  
  757. var enemy = g_Minigame.m_CurrentScene.GetEnemy(g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane, g_Minigame.m_CurrentScene.m_rgPlayerData.target);
  758. // check if current target is a boss, otherwise its not worth using the gold rain
  759. if (enemy && enemy.m_data.type == ENEMY_TYPE.BOSS) {
  760. var enemyBossHealthPercent = enemy.m_flDisplayedHP / enemy.m_data.max_hp;
  761.  
  762.  
  763. if (enemyBossHealthPercent >= 0.6) { // We want sufficient time for the gold rain to be applicable
  764. // Gold Rain is purchased, cooled down, and needed. Trigger it.
  765. advLog('Gold rain is purchased and cooled down, Triggering it on boss', 2);
  766. triggerItem(ITEMS.GOLD_RAIN);
  767. }
  768. }
  769. }
  770. }
  771.  
  772.  
  773. function useMetalDetectorIfRelevant() {
  774. // Check if metal detector is purchased
  775. if (hasPurchasedAbility(ABILITIES.METAL_DETECTOR)) {
  776. if (isAbilityCoolingDown(ABILITIES.METAL_DETECTOR) || isAbilityActive(ABILITIES.METAL_DETECTOR)) {
  777. return;
  778. }
  779.  
  780.  
  781. var enemy = g_Minigame.m_CurrentScene.GetEnemy(g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane, g_Minigame.m_CurrentScene.m_rgPlayerData.target);
  782. // check if current target is a boss, otherwise we won't use metal detector
  783. if (enemy && enemy.m_data.type == ENEMY_TYPE.BOSS) {
  784. var enemyBossHealthPercent = enemy.m_flDisplayedHP / enemy.m_data.max_hp;
  785.  
  786.  
  787. if (enemyBossHealthPercent >= 0.9) { // We want sufficient time for the metal detector to be applicable
  788. // Metal Detector is purchased, cooled down, and needed. Trigger it.
  789. advLog('Metal Detector is purchased and cooled down, Triggering it on boss', 2);
  790. triggerAbility(ABILITIES.METAL_DETECTOR);
  791. }
  792. }
  793. }
  794. }
  795.  
  796.  
  797. function attemptRespawn() {
  798. if ((g_Minigame.CurrentScene().m_bIsDead) &&
  799. ((g_Minigame.CurrentScene().m_rgPlayerData.time_died) + 5) < (g_Minigame.CurrentScene().m_nTime)) {
  800. RespawnPlayer();
  801. }
  802. }
  803.  
  804.  
  805. function isAbilityActive(abilityId) {
  806. return g_Minigame.CurrentScene().bIsAbilityActive(abilityId);
  807. }
  808.  
  809.  
  810. function hasItem(itemId) {
  811. for ( var i = 0; i < g_Minigame.CurrentScene().m_rgPlayerTechTree.ability_items.length; ++i ) {
  812. var abilityItem = g_Minigame.CurrentScene().m_rgPlayerTechTree.ability_items[i];
  813. if (abilityItem.ability == itemId) {
  814. return true;
  815. }
  816. }
  817. return false;
  818. }
  819.  
  820.  
  821. function isAbilityCoolingDown(abilityId) {
  822. return g_Minigame.CurrentScene().GetCooldownForAbility(abilityId) > 0;
  823. }
  824.  
  825.  
  826. function hasOneUseAbility(abilityId) {
  827. var elem = document.getElementById('abilityitem_' + abilityId);
  828. return elem !== null;
  829. }
  830.  
  831.  
  832. function hasPurchasedAbility(abilityId) {
  833. // each bit in unlocked_abilities_bitfield corresponds to an ability.
  834. // the above condition checks if the ability's bit is set or cleared. I.e. it checks if
  835. // the player has purchased the specified ability.
  836. return (1 << abilityId) & g_Minigame.CurrentScene().m_rgPlayerTechTree.unlocked_abilities_bitfield;
  837. }
  838.  
  839.  
  840. function triggerItem(itemId) {
  841. var elem = document.getElementById('abilityitem_' + itemId);
  842. if (elem && elem.childElements() && elem.childElements().length >= 1) {
  843. g_Minigame.CurrentScene().TryAbility(document.getElementById('abilityitem_' + itemId).childElements()[0]);
  844. }
  845. }
  846.  
  847.  
  848. function triggerAbility(abilityId) {
  849. g_Minigame.CurrentScene().m_rgAbilityQueue.push({'ability': abilityId});
  850. }
  851.  
  852.  
  853. function toggleAbilityVisibility(abilityId, show) {
  854. var vis = show === true ? "visible" : "hidden";
  855.  
  856.  
  857. var elem = document.getElementById('ability_' + abilityId);
  858. if (elem && elem.childElements() && elem.childElements().length >= 1) {
  859. elem.childElements()[0].style.visibility = vis;
  860. }
  861. }
  862.  
  863.  
  864. function disableAbility(abilityId) {
  865. toggleAbilityVisibility(abilityId, false);
  866. }
  867.  
  868.  
  869. function enableAbility(abilityId) {
  870. toggleAbilityVisibility(abilityId, true);
  871. }
  872.  
  873.  
  874. function isAbilityEnabled(abilityId) {
  875. var elem = document.getElementById('ability_' + abilityId);
  876. if (elem && elem.childElements() && elem.childElements().length >= 1) {
  877. return elem.childElements()[0].style.visibility == "visible";
  878. }
  879. return false;
  880. }
  881.  
  882.  
  883. function toggleAbilityItemVisibility(abilityId, show) {
  884. var elem = document.getElementById('abilityitem_' + abilityId);
  885. if (elem && elem.childElements() && elem.childElements().length >= 1) {
  886. elem.childElements()[0].style.visibility = show === true ? "visible" : "hidden";
  887. }
  888. }
  889.  
  890.  
  891. function disableAbilityItem(abilityId) {
  892. toggleAbilityItemVisibility(abilityId, false);
  893. }
  894.  
  895.  
  896. function enableAbilityItem(abilityId) {
  897. toggleAbilityItemVisibility(abilityId, true);
  898. }
  899.  
  900.  
  901. function isAbilityItemEnabled(abilityId) {
  902. var elem = document.getElementById('abilityitem_' + abilityId);
  903. if (elem && elem.childElements() && elem.childElements().length >= 1) {
  904. return elem.childElements()[0].style.visibility == "visible";
  905. }
  906. return false;
  907. }
  908.  
  909.  
  910. function getActiveAbilityNum(ability) {
  911. var abilities = g_Minigame.m_CurrentScene.m_rgGameData.lanes[g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane].active_player_abilities;
  912. var count = 0;
  913. for(var i = 0; i < abilities.length; i++)
  914. {
  915. if(abilities[i].ability != ability)
  916. {
  917. continue;
  918. }
  919. if(abilities[i].timestamp_done < Date.now())
  920. {
  921. continue;
  922. }
  923. count++;
  924. }
  925. return count;
  926. }
  927.  
  928.  
  929. function sortLanesByElementals() {
  930. var elementPriorities = [
  931. g_Minigame.CurrentScene().m_rgPlayerTechTree.damage_multiplier_fire,
  932. g_Minigame.CurrentScene().m_rgPlayerTechTree.damage_multiplier_water,
  933. g_Minigame.CurrentScene().m_rgPlayerTechTree.damage_multiplier_air,
  934. g_Minigame.CurrentScene().m_rgPlayerTechTree.damage_multiplier_earth
  935. ];
  936.  
  937.  
  938. var lanes = g_Minigame.CurrentScene().m_rgGameData.lanes;
  939. var lanePointers = [];
  940.  
  941.  
  942. for (var i = 0; i < lanes.length; i++) {
  943. lanePointers[i] = i;
  944. }
  945.  
  946.  
  947. lanePointers.sort(function(a, b) {
  948. return elementPriorities[lanes[b].element - 1] - elementPriorities[lanes[a].element - 1];
  949. });
  950.  
  951.  
  952. advLog("Lane IDs : " + lanePointers[0] + " " + lanePointers[1] + " " + lanePointers[2], 4);
  953. advLog("Elements : " + lanes[lanePointers[0]].element + " " + lanes[lanePointers[1]].element + " " + lanes[lanePointers[2]].element, 4);
  954.  
  955.  
  956. return lanePointers;
  957. }
  958.  
  959.  
  960. function advLog(msg, lvl) {
  961. if (lvl <= logLevel) {
  962. console.log(msg);
  963. }
  964. }
  965.  
  966.  
  967. if(w.SteamDB_Minigame_Timer) {
  968. w.clearInterval(w.SteamDB_Minigame_Timer);
  969. }
  970.  
  971.  
  972. w.SteamDB_Minigame_Timer = w.setInterval(function(){
  973. if (g_Minigame && g_Minigame.CurrentScene().m_bRunning && g_Minigame.CurrentScene().m_rgPlayerTechTree) {
  974. w.clearInterval(w.SteamDB_Minigame_Timer);
  975. firstRun();
  976. w.SteamDB_Minigame_Timer = w.setInterval(MainLoop, 1000);
  977. }
  978. }, 1000);
  979.  
  980.  
  981. // Append gameid to breadcrumbs
  982. var breadcrumbs = document.querySelector('.breadcrumbs');
  983.  
  984.  
  985. if(breadcrumbs) {
  986. var element = document.createElement('span');
  987. element.textContent = ' > ';
  988. breadcrumbs.appendChild(element);
  989.  
  990.  
  991. element = document.createElement('span');
  992. element.style.color = '#D4E157';
  993. element.style.textShadow = '1px 1px 0px rgba( 0, 0, 0, 0.3 )';
  994. element.textContent = 'Room ' + g_GameID;
  995. breadcrumbs.appendChild(element);
  996. }
  997.  
  998.  
  999. // Helpers to access player stats.
  1000. function getCritChance(){
  1001. return g_Minigame.m_CurrentScene.m_rgPlayerTechTree.crit_percentage * 100;
  1002. }
  1003.  
  1004.  
  1005. function getCritMultiplier(){
  1006. return g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_multiplier_crit;
  1007. }
  1008.  
  1009.  
  1010. function getDPS(){
  1011. return g_Minigame.m_CurrentScene.m_rgPlayerTechTree.dps;
  1012. }
  1013.  
  1014.  
  1015. function getClickDamage(){
  1016. return g_Minigame.m_CurrentScene.m_rgPlayerTechTree.damage_per_click;
  1017. }
  1018.  
  1019.  
  1020. function enhanceTooltips(){
  1021. var trt_oldTooltip = w.fnTooltipUpgradeDesc;
  1022. w.fnTooltipUpgradeDesc = function(context){
  1023. var $context = $J(context);
  1024. var desc = $context.data('desc');
  1025. var strOut = desc;
  1026. var multiplier = parseFloat( $context.data('multiplier') );
  1027. switch( $context.data('upgrade_type') )
  1028. {
  1029. case 7: // Lucky Shot's type.
  1030. var currentMultiplier = getCritMultiplier();
  1031. var newMultiplier = currentMultiplier + multiplier;
  1032. var dps = getDPS();
  1033. var clickDamage = getClickDamage();
  1034.  
  1035.  
  1036. strOut += '<br><br>You can have multiple crits in a second. The server combines them into one.';
  1037.  
  1038.  
  1039. strOut += '<br><br>Crit Percentage: ' + getCritChance().toFixed(1) + '%';
  1040.  
  1041.  
  1042. strOut += '<br><br>Current: ' + ( currentMultiplier ) + 'x';
  1043. strOut += '<br>Next Level: ' + ( newMultiplier ) + 'x';
  1044.  
  1045.  
  1046. strOut += '<br><br>Damage with one crit:';
  1047. strOut += '<br>DPS: ' + FormatNumberForDisplay( currentMultiplier * dps ) + ' => ' + FormatNumberForDisplay( newMultiplier * dps );
  1048. strOut += '<br>Click: ' + FormatNumberForDisplay( currentMultiplier * clickDamage ) + ' => ' + FormatNumberForDisplay( newMultiplier * clickDamage );
  1049. break;
  1050. default:
  1051. return trt_oldTooltip(context);
  1052. }
  1053.  
  1054.  
  1055. return strOut;
  1056. };
  1057. }
  1058.  
  1059.  
  1060. }(window));
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement