Advertisement
Guest User

Untitled

a guest
Feb 14th, 2016
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 33.49 KB | None | 0 0
  1. /**
  2. * @filename Attack.js
  3. * @author kolton
  4. * @desc handle player attacks
  5. */
  6.  
  7. var Attack = {
  8. classes: ["Amazon", "Sorceress", "Necromancer", "Paladin", "Barbarian", "Druid", "Assassin"],
  9. infinity: false,
  10.  
  11. // Initialize attacks
  12. init: function () {
  13. if (Config.Wereform) {
  14. include("common/Attacks/wereform.js");
  15. } else {
  16. include("common/Attacks/" + this.classes[me.classid] + ".js");
  17. }
  18.  
  19. if (Config.AttackSkill[1] < 0 || Config.AttackSkill[3] < 0) {
  20. showConsole();
  21. print("ÿc1Bad attack config. Don't expect your bot to attack.");
  22. }
  23.  
  24. if (me.gametype === 1) {
  25. this.checkInfinity();
  26. this.getCharges();
  27. }
  28. },
  29.  
  30. getCustomAttack: function (unit) {
  31. var i;
  32.  
  33. // Check if unit got invalidated
  34. if (!unit || !unit.name || !copyUnit(unit).x) {
  35. return false;
  36. }
  37.  
  38. for (i in Config.CustomAttack) {
  39. if (Config.CustomAttack.hasOwnProperty(i) && unit.name.toLowerCase() === i.toLowerCase()) {
  40. return Config.CustomAttack[i];
  41. }
  42. }
  43.  
  44. return false;
  45. },
  46.  
  47. // Get items with charges
  48. getCharges: function () {
  49. if (!Skill.charges) {
  50. Skill.charges = [];
  51. }
  52.  
  53. var i, stats,
  54. item = me.getItem(-1, 1);
  55.  
  56. if (item) {
  57. do {
  58. stats = item.getStat(-2);
  59.  
  60. if (stats.hasOwnProperty(204)) {
  61. if (stats[204] instanceof Array) {
  62. for (i = 0; i < stats[204].length; i += 1) {
  63. if (stats[204][i] !== undefined) {
  64. Skill.charges.push({
  65. unit: copyUnit(item),
  66. gid: item.gid,
  67. skill: stats[204][i].skill,
  68. level: stats[204][i].level,
  69. charges: stats[204][i].charges,
  70. maxcharges: stats[204][i].maxcharges
  71. });
  72. }
  73. }
  74. } else {
  75. Skill.charges.push({
  76. unit: copyUnit(item),
  77. gid: item.gid,
  78. skill: stats[204].skill,
  79. level: stats[204].level,
  80. charges: stats[204].charges,
  81. maxcharges: stats[204].maxcharges
  82. });
  83. }
  84. }
  85. } while (item.getNext());
  86. }
  87.  
  88. return true;
  89. },
  90.  
  91. // Check if player or his merc are using Infinity, and adjust resistance checks based on that
  92. checkInfinity: function () {
  93. var i, merc, item;
  94.  
  95. for (i = 0; i < 3; i += 1) {
  96. merc = me.getMerc();
  97.  
  98. if (merc) {
  99. break;
  100. }
  101.  
  102. delay(50);
  103. }
  104.  
  105. // Check merc infinity
  106. if (merc) {
  107. item = merc.getItem();
  108.  
  109. if (item) {
  110. do {
  111. if (item.getPrefix(20566)) {
  112. this.infinity = true;
  113.  
  114. return true;
  115. }
  116. } while (item.getNext());
  117. }
  118. }
  119.  
  120. // Check player infinity
  121. item = me.getItem(-1, 1);
  122.  
  123. if (item) {
  124. do {
  125. if (item.getPrefix(20566)) {
  126. this.infinity = true;
  127.  
  128. return true;
  129. }
  130. } while (item.getNext());
  131. }
  132.  
  133. return false;
  134. },
  135.  
  136. // Kill a monster based on its classId, can pass a unit as well
  137. kill: function (classId) {
  138. if (Config.AttackSkill[1] < 0) {
  139. return false;
  140. }
  141.  
  142. var i, target, gid,
  143. errorInfo = "",
  144. attackCount = 0;
  145.  
  146. if (typeof classId === "object") {
  147. target = classId;
  148. }
  149.  
  150. for (i = 0; !target && i < 5; i += 1) {
  151. target = getUnit(1, classId);
  152.  
  153. delay(200);
  154. }
  155.  
  156. if (!target) {
  157. //throw new Error("");
  158. }
  159.  
  160. gid = target.gid;
  161.  
  162. if (Config.MFLeader) {
  163. Pather.makePortal();
  164. say("kill " + classId);
  165. }
  166.  
  167. while (attackCount < 300 && this.checkMonster(target) && this.skipCheck(target)) {
  168. Misc.townCheck();
  169.  
  170. if (!target || !copyUnit(target).x) { // Check if unit got invalidated, happens if necro raises a skeleton from the boss's corpse.
  171. target = getUnit(1, -1, -1, gid);
  172.  
  173. if (!target) {
  174. break;
  175. }
  176. }
  177.  
  178. if (Config.Dodge && me.hp * 100 / me.hpmax <= Config.DodgeHP) {
  179. this.deploy(target, Config.DodgeRange, 5, 9);
  180. }
  181.  
  182. if (Config.MFSwitchPercent && target.hp / 128 * 100 < Config.MFSwitchPercent) {
  183. Precast.weaponSwitch(Math.abs(Config.MFSwitch));
  184. }
  185.  
  186. if (attackCount > 0 && attackCount % 15 === 0 && Skill.getRange(Config.AttackSkill[1]) < 4) {
  187. Packet.flash(me.gid);
  188. }
  189.  
  190. if (!ClassAttack.doAttack(target, attackCount % 15 === 0)) {
  191. errorInfo = " (doAttack failed)";
  192.  
  193. break;
  194. }
  195.  
  196. attackCount += 1;
  197. }
  198.  
  199. if (attackCount === 300) {
  200. errorInfo = " (attackCount exceeded)";
  201. }
  202.  
  203. if (Config.MFSwitchPercent) {
  204. Precast.weaponSwitch(Math.abs(Config.MFSwitch - 1));
  205. }
  206.  
  207. ClassAttack.afterAttack();
  208.  
  209. if (!target || !copyUnit(target).x) {
  210. return true;
  211. }
  212.  
  213. if (target.hp > 0 && target.mode !== 0 && target.mode !== 12) {
  214. //throw new Error("Failed to kill " + target.name + errorInfo);
  215. }
  216.  
  217. return true;
  218. },
  219.  
  220. hurt: function (classId, percent) {
  221. var i, target,
  222. attackCount = 0;
  223.  
  224. for (i = 0; i < 5; i += 1) {
  225. target = getUnit(1, classId);
  226.  
  227. if (target) {
  228. break;
  229. }
  230.  
  231. delay(200);
  232. }
  233.  
  234. while (attackCount < 300 && Attack.checkMonster(target) && Attack.skipCheck(target)) {
  235. if (!ClassAttack.doAttack(target, attackCount % 15 === 0)) {
  236. break;
  237. }
  238.  
  239. if (!copyUnit(target).x) {
  240. return true;
  241. }
  242.  
  243. attackCount += 1;
  244.  
  245. if (target.hp * 100 / 128 <= percent) {
  246. break;
  247. }
  248. }
  249.  
  250. return true;
  251. },
  252.  
  253. getScarinessLevel: function (unit) {
  254. var scariness = 0, ids = [58, 59, 60, 61, 62, 101, 102, 103, 104, 105, 278, 279, 280, 281, 282, 298, 299, 300, 645, 646, 647, 662, 663, 664, 667, 668, 669, 670, 675, 676];
  255.  
  256. // Only handling monsters for now
  257. if (unit.type !== 1) {
  258. return undefined;
  259. }
  260.  
  261. // Minion
  262. if (unit.spectype & 0x08) {
  263. scariness += 1;
  264. }
  265.  
  266. // Champion
  267. if (unit.spectype & 0x02) {
  268. scariness += 2;
  269. }
  270.  
  271. // Boss
  272. if (unit.spectype & 0x04) {
  273. scariness += 4;
  274. }
  275.  
  276. // Summoner or the like
  277. if (ids.indexOf(unit.classid) > -1) {
  278. scariness += 8;
  279. }
  280.  
  281. return scariness;
  282. },
  283.  
  284. // Clear monsters in a section based on range and spectype or clear monsters around a boss monster
  285. clear: function (range, spectype, bossId, sortfunc, pickit) { // probably going to change to passing an object
  286. while (!me.gameReady) {
  287. delay(40);
  288. }
  289.  
  290. if (Config.MFLeader && !!bossId) {
  291. Pather.makePortal();
  292. say("clear " + bossId);
  293. }
  294.  
  295. if (range === undefined) {
  296. range = 25;
  297. }
  298.  
  299. if (spectype === undefined) {
  300. spectype = 0;
  301. }
  302.  
  303. if (bossId === undefined) {
  304. bossId = false;
  305. }
  306.  
  307. if (sortfunc === undefined) {
  308. sortfunc = false;
  309. }
  310.  
  311. if (pickit === undefined) {
  312. pickit = true;
  313. }
  314.  
  315. if (typeof (range) !== "number") {
  316. //throw new Error("Attack.clear: range must be a number.");
  317. }
  318.  
  319. var i, boss, orgx, orgy, target, result, monsterList, start,
  320. gidAttack = [],
  321. attackCount = 0;
  322.  
  323. if (Config.AttackSkill[1] < 0 || Config.AttackSkill[3] < 0) {
  324. return false;
  325. }
  326.  
  327. if (!sortfunc) {
  328. sortfunc = this.sortMonsters;
  329. }
  330.  
  331. if (bossId) {
  332. for (i = 0; !boss && i < 5; i += 1) {
  333. boss = bossId > 999 ? getUnit(1, -1, -1, bossId) : getUnit(1, bossId);
  334.  
  335. delay(200);
  336. }
  337.  
  338. if (!boss) {
  339. //throw new Error("Attack.clear: " + bossId + " not found");
  340. }
  341.  
  342. orgx = boss.x;
  343. orgy = boss.y;
  344. } else {
  345. orgx = me.x;
  346. orgy = me.y;
  347. }
  348.  
  349. monsterList = [];
  350. target = getUnit(1);
  351.  
  352. if (target) {
  353. do {
  354. if ((!spectype || (target.spectype & spectype)) && this.checkMonster(target) && this.skipCheck(target)) {
  355. // Speed optimization - don't go through monster list until there's at least one within clear range
  356. if (!start && getDistance(target, orgx, orgy) <= range &&
  357. (me.getSkill(54, 1) || !Scripts.Follower || !checkCollision(me, target, 0x1))) {
  358. start = true;
  359. }
  360.  
  361. monsterList.push(copyUnit(target));
  362. }
  363. } while (target.getNext());
  364. }
  365.  
  366. while (start && monsterList.length > 0 && attackCount < 300) {
  367. if (boss) {
  368. orgx = boss.x;
  369. orgy = boss.y;
  370. }
  371.  
  372. if (me.dead) {
  373. return false;
  374. }
  375.  
  376. //monsterList.sort(Sort.units);
  377. monsterList.sort(sortfunc);
  378.  
  379. target = copyUnit(monsterList[0]);
  380.  
  381. if (target.x !== undefined && (getDistance(target, orgx, orgy) <= range || (this.getScarinessLevel(target) > 7 && getDistance(me, target) <= range)) && this.checkMonster(target)) {
  382. if (Config.Dodge && me.hp * 100 / me.hpmax <= Config.DodgeHP) {
  383. this.deploy(target, Config.DodgeRange, 5, 9);
  384. }
  385.  
  386. Misc.townCheck(true);
  387. //me.overhead("attacking " + target.name + " spectype " + target.spectype + " id " + target.classid);
  388.  
  389. result = ClassAttack.doAttack(target, attackCount % 15 === 0);
  390.  
  391. if (result) {
  392. for (i = 0; i < gidAttack.length; i += 1) {
  393. if (gidAttack[i].gid === target.gid) {
  394. break;
  395. }
  396. }
  397.  
  398. if (i === gidAttack.length) {
  399. gidAttack.push({gid: target.gid, attacks: 0, name: target.name});
  400. }
  401.  
  402. gidAttack[i].attacks += 1;
  403. attackCount += 1;
  404.  
  405. // Desync/bad position handler
  406. switch (Config.AttackSkill[(target.spectype & 0x7) ? 1 : 3]) {
  407. case 112:
  408. //print(gidAttack[i].name + " " + gidAttack[i].attacks);
  409.  
  410. // Tele in random direction with Blessed Hammer
  411. if (gidAttack[i].attacks > 0 && gidAttack[i].attacks % ((target.spectype & 0x7) ? 8 : 3) === 0) {
  412. //print("random move m8");
  413. Pather.moveTo(me.x + rand(-1, 1) * 5, me.y + rand(-1, 1) * 5);
  414. }
  415.  
  416. break;
  417. default:
  418. // Flash with melee skills
  419. if (gidAttack[i].attacks > 0 && gidAttack[i].attacks % ((target.spectype & 0x7) ? 15 : 5) === 0 && Skill.getRange(Config.AttackSkill[(target.spectype & 0x7) ? 1 : 3]) < 4) {
  420. Packet.flash(me.gid);
  421. }
  422.  
  423. break;
  424. }
  425.  
  426. // Skip non-unique monsters after 15 attacks, except in Throne of Destruction
  427. if (me.area !== 131 && !(target.spectype & 0x7) && gidAttack[i].attacks > 15) {
  428. print("ÿc1Skipping " + target.name + " " + target.gid + " " + gidAttack[i].attacks);
  429. monsterList.shift();
  430. }
  431.  
  432. if (target.mode === 0 || target.mode === 12 || Config.FastPick === 2) {
  433. Pickit.fastPick();
  434. }
  435. } else {
  436. monsterList.shift();
  437. }
  438. } else {
  439. monsterList.shift();
  440. }
  441. }
  442.  
  443. ClassAttack.afterAttack(pickit);
  444. this.openChests(range, orgx, orgy);
  445.  
  446. if (attackCount > 0 && pickit) {
  447. Pickit.pickItems();
  448. }
  449.  
  450. return true;
  451. },
  452.  
  453. // Filter monsters based on classId, spectype and range
  454. getMob: function (classid, spectype, range, center) {
  455. var monsterList = [],
  456. monster = getUnit(1);
  457.  
  458. if (range === undefined) {
  459. range = 25;
  460. }
  461.  
  462. if (!center) {
  463. center = me;
  464. }
  465.  
  466. switch (typeof classid) {
  467. case "number":
  468. case "string":
  469. monster = getUnit(1, classid);
  470.  
  471. if (monster) {
  472. do {
  473. if (getDistance(center.x, center.y, monster.x, monster.y) <= range && (!spectype || (monster.spectype & spectype)) && this.checkMonster(monster)) {
  474. monsterList.push(copyUnit(monster));
  475. }
  476. } while (monster.getNext());
  477. }
  478.  
  479. break;
  480. case "object":
  481. monster = getUnit(1);
  482.  
  483. if (monster) {
  484. do {
  485. if (classid.indexOf(monster.classid) > -1 && getDistance(center.x, center.y, monster.x, monster.y) <= range && (!spectype || (monster.spectype & spectype)) && this.checkMonster(monster)) {
  486. monsterList.push(copyUnit(monster));
  487. }
  488. } while (monster.getNext());
  489. }
  490.  
  491. break;
  492. }
  493.  
  494. if (!monsterList.length) {
  495. return false;
  496. }
  497.  
  498. return monsterList;
  499. },
  500.  
  501. // Clear an already formed array of monstas
  502. clearList: function (mainArg, sortFunc, refresh) {
  503. var i, target, result, monsterList,
  504. gidAttack = [],
  505. attackCount = 0;
  506.  
  507. switch (typeof mainArg) {
  508. case "function":
  509. monsterList = mainArg.call();
  510.  
  511. break;
  512. case "object":
  513. monsterList = mainArg.slice(0);
  514.  
  515. break;
  516. case "boolean": // false from Attack.getMob()
  517. return false;
  518. default:
  519. throw new Error("clearList: Invalid argument");
  520. }
  521.  
  522. if (!sortFunc) {
  523. sortFunc = this.sortMonsters;
  524. }
  525.  
  526. while (monsterList.length > 0 && attackCount < 300) {
  527. if (refresh && attackCount > 0 && attackCount % refresh === 0) {
  528. monsterList = mainArg.call();
  529. }
  530.  
  531. if (me.dead) {
  532. return false;
  533. }
  534.  
  535. monsterList.sort(sortFunc);
  536.  
  537. target = copyUnit(monsterList[0]);
  538.  
  539. if (target.x !== undefined && this.checkMonster(target)) {
  540. if (Config.Dodge && me.hp * 100 / me.hpmax <= Config.DodgeHP) {
  541. this.deploy(target, Config.DodgeRange, 5, 9);
  542. }
  543.  
  544. Misc.townCheck(true);
  545. //me.overhead("attacking " + target.name + " spectype " + target.spectype + " id " + target.classid);
  546.  
  547. result = ClassAttack.doAttack(target, attackCount % 15 === 0);
  548.  
  549. if (result) {
  550. for (i = 0; i < gidAttack.length; i += 1) {
  551. if (gidAttack[i].gid === target.gid) {
  552. break;
  553. }
  554. }
  555.  
  556. if (i === gidAttack.length) {
  557. gidAttack.push({gid: target.gid, attacks: 0});
  558. }
  559.  
  560. gidAttack[i].attacks += 1;
  561.  
  562. // Desync/bad position handler
  563. switch (Config.AttackSkill[(target.spectype & 0x7) ? 1 : 3]) {
  564. case 112:
  565. // Tele in random direction with Blessed Hammer
  566. if (gidAttack[i].attacks > 0 && gidAttack[i].attacks % ((target.spectype & 0x7) ? 5 : 15) === 0) {
  567. Pather.moveTo(me.x + rand(-1, 1) * 4, me.y + rand(-1, 1) * 4);
  568. }
  569.  
  570. break;
  571. default:
  572. // Flash with melee skills
  573. if (gidAttack[i].attacks > 0 && gidAttack[i].attacks % ((target.spectype & 0x7) ? 5 : 15) === 0 && Skill.getRange(Config.AttackSkill[(target.spectype & 0x7) ? 1 : 3]) < 4) {
  574. Packet.flash(me.gid);
  575. }
  576.  
  577. break;
  578. }
  579.  
  580. // Skip non-unique monsters after 15 attacks, except in Throne of Destruction
  581. if (me.area !== 131 && !(target.spectype & 0x7) && gidAttack[i].attacks > 15) {
  582. print("ÿc1Skipping " + target.name + " " + target.gid + " " + gidAttack[i].attacks);
  583. monsterList.shift();
  584. }
  585.  
  586. attackCount += 1;
  587.  
  588. if (target.mode === 0 || target.mode === 12 || Config.FastPick === 2) {
  589. Pickit.fastPick();
  590. }
  591. } else {
  592. monsterList.shift();
  593. }
  594. } else {
  595. monsterList.shift();
  596. }
  597. }
  598.  
  599. ClassAttack.afterAttack(true);
  600. this.openChests(30);
  601.  
  602. if (attackCount > 0) {
  603. Pickit.pickItems();
  604. }
  605.  
  606. return true;
  607. },
  608.  
  609. securePosition: function (x, y, range, timer, skipBlocked, special) {
  610. /*if (arguments.length < 4) {
  611. throw new Error("securePosition needs 4 arguments");
  612. }*/
  613.  
  614. var monster, monList, tick;
  615.  
  616. if (skipBlocked === true) {
  617. skipBlocked = 0x4;
  618. }
  619.  
  620. while (true) {
  621. if (getDistance(me, x, y) > 5) {
  622. Pather.moveTo(x, y);
  623. }
  624.  
  625. monster = getUnit(1);
  626. monList = [];
  627.  
  628. if (monster) {
  629. do {
  630. if (getDistance(monster, x, y) <= range && this.checkMonster(monster) && this.canAttack(monster) &&
  631. (!skipBlocked || !checkCollision(me, monster, skipBlocked)) &&
  632. ((me.classid === 1 && me.getSkill(54, 1)) || me.getStat(97, 54) || !checkCollision(me, monster, 0x1))) {
  633. monList.push(copyUnit(monster));
  634. }
  635. } while (monster.getNext());
  636. }
  637.  
  638. if (!monList.length) {
  639. if (!tick) {
  640. tick = getTickCount();
  641. }
  642.  
  643. // only return if it's been safe long enough
  644. if (getTickCount() - tick >= timer) {
  645. return true;
  646. }
  647. } else {
  648. this.clearList(monList);
  649.  
  650. // reset the timer when there's monsters in range
  651. if (tick) {
  652. tick = false;
  653. }
  654. }
  655.  
  656. if (special) {
  657. switch (me.classid) {
  658. case 3: // Paladin Redemption addon
  659. if (me.getSkill(124, 1)) {
  660. Skill.setSkill(124, 0);
  661. delay(1000);
  662. }
  663.  
  664. break;
  665. }
  666. }
  667.  
  668. delay(100);
  669. }
  670.  
  671. return true;
  672. },
  673.  
  674. // Draw lines around a room on minimap
  675. markRoom: function (room, color) {
  676. var arr = [];
  677.  
  678. arr.push(new Line(room.x * 5, room.y * 5, room.x * 5, room.y * 5 + room.ysize, color, true));
  679. arr.push(new Line(room.x * 5, room.y * 5, room.x * 5 + room.xsize, room.y * 5, color, true));
  680. arr.push(new Line(room.x * 5 + room.xsize, room.y * 5, room.x * 5 + room.xsize, room.y * 5 + room.ysize, color, true));
  681. arr.push(new Line(room.x * 5, room.y * 5 + room.ysize, room.x * 5 + room.xsize, room.y * 5 + room.ysize, color, true));
  682. },
  683.  
  684. countUniques: function () {
  685. if (!this.uniques) {
  686. this.uniques = 0;
  687. }
  688.  
  689. if (!this.ignoredGids) {
  690. this.ignoredGids = [];
  691. }
  692.  
  693. var monster = getUnit(1);
  694.  
  695. if (monster) {
  696. do {
  697. if ((monster.spectype & 0x5) && this.ignoredGids.indexOf(monster.gid) === -1) {
  698. this.uniques += 1;
  699. this.ignoredGids.push(monster.gid);
  700. }
  701. } while (monster.getNext());
  702. }
  703. },
  704.  
  705. storeStatistics: function (area) {
  706. var obj;
  707.  
  708. if (!FileTools.exists("statistics.json")) {
  709. Misc.fileAction("statistics.json", 1, "{}");
  710. }
  711.  
  712. obj = JSON.parse(Misc.fileAction("statistics.json", 0));
  713.  
  714. if (obj) {
  715. if (obj[area] === undefined) {
  716. obj[area] = {
  717. runs: 0,
  718. averageUniques: 0
  719. };
  720. }
  721.  
  722. obj[area].averageUniques = ((obj[area].averageUniques * obj[area].runs + this.uniques) / (obj[area].runs + 1)).toFixed(4);
  723. obj[area].runs += 1;
  724.  
  725. Misc.fileAction("statistics.json", 1, JSON.stringify(obj));
  726. }
  727.  
  728. this.uniques = 0;
  729. this.ignoredGids = [];
  730. },
  731.  
  732. // Clear an entire area based on monster spectype
  733. clearLevel: function (spectype) {
  734. if (Config.MFLeader) {
  735. Pather.makePortal();
  736. say("clearlevel " + getArea().name);
  737. }
  738.  
  739. var room, result, rooms, myRoom;
  740.  
  741. function RoomSort(a, b) {
  742. return getDistance(myRoom[0], myRoom[1], a[0], a[1]) - getDistance(myRoom[0], myRoom[1], b[0], b[1]);
  743. }
  744.  
  745. room = getRoom();
  746.  
  747. if (!room) {
  748. return false;
  749. }
  750.  
  751. if (spectype === undefined) {
  752. spectype = 0;
  753. }
  754.  
  755. rooms = [];
  756.  
  757. do {
  758. rooms.push([room.x * 5 + room.xsize / 2, room.y * 5 + room.ysize / 2]);
  759. } while (room.getNext());
  760.  
  761. while (rooms.length > 0) {
  762. // get the first room + initialize myRoom var
  763. if (!myRoom) {
  764. room = getRoom(me.x, me.y);
  765. }
  766.  
  767. if (room) {
  768. if (room instanceof Array) { // use previous room to calculate distance
  769. myRoom = [room[0], room[1]];
  770. } else { // create a new room to calculate distance (first room, done only once)
  771. myRoom = [room.x * 5 + room.xsize / 2, room.y * 5 + room.ysize / 2];
  772. }
  773. }
  774.  
  775. rooms.sort(RoomSort);
  776. room = rooms.shift();
  777.  
  778. result = Pather.getNearestWalkable(room[0], room[1], 18, 3);
  779.  
  780. if (result) {
  781. Pather.moveTo(result[0], result[1], 3, spectype);
  782. //this.countUniques();
  783.  
  784. if (!this.clear(40, spectype)) {
  785. break;
  786. }
  787. }
  788. }
  789.  
  790. //this.storeStatistics(Pather.getAreaName(me.area));
  791.  
  792. return true;
  793. },
  794.  
  795. // Sort monsters based on distance, spectype and classId (summoners are attacked first)
  796. sortMonsters: function (unitA, unitB) {
  797. // No special sorting for were-form
  798. if (Config.Wereform) {
  799. return getDistance(me, unitA) - getDistance(me, unitB);
  800. }
  801.  
  802. // Barb optimization
  803. if (me.classid === 4) {
  804. if (!Attack.checkResist(unitA, Attack.getSkillElement(Config.AttackSkill[(unitA.spectype & 0x7) ? 1 : 3]))) {
  805. return 1;
  806. }
  807.  
  808. if (!Attack.checkResist(unitB, Attack.getSkillElement(Config.AttackSkill[(unitB.spectype & 0x7) ? 1 : 3]))) {
  809. return -1;
  810. }
  811. }
  812.  
  813. var ids = [58, 59, 60, 61, 62, 101, 102, 103, 104, 105, 278, 279, 280, 281, 282, 298, 299, 300, 645, 646, 647, 662, 663, 664, 667, 668, 669, 670, 675, 676];
  814.  
  815. if (me.area !== 61 && ids.indexOf(unitA.classid) > -1 && ids.indexOf(unitB.classid) > -1) {
  816. // Kill "scary" uniques first (like Bishibosh)
  817. if ((unitA.spectype & 0x04) && (unitB.spectype & 0x04)) {
  818. return getDistance(me, unitA) - getDistance(me, unitB);
  819. }
  820.  
  821. if (unitA.spectype & 0x04) {
  822. return -1;
  823. }
  824.  
  825. if (unitB.spectype & 0x04) {
  826. return 1;
  827. }
  828.  
  829. return getDistance(me, unitA) - getDistance(me, unitB);
  830. }
  831.  
  832. if (ids.indexOf(unitA.classid) > -1) {
  833. return -1;
  834. }
  835.  
  836. if (ids.indexOf(unitB.classid) > -1) {
  837. return 1;
  838. }
  839.  
  840. if (Config.BossPriority) {
  841. if ((unitA.spectype & 0x5) && (unitB.spectype & 0x5)) {
  842. return getDistance(me, unitA) - getDistance(me, unitB);
  843. }
  844.  
  845. if (unitA.spectype & 0x5) {
  846. return -1;
  847. }
  848.  
  849. if (unitB.spectype & 0x5) {
  850. return 1;
  851. }
  852. }
  853.  
  854. return getDistance(me, unitA) - getDistance(me, unitB);
  855. },
  856.  
  857. // Check if a set of coords is valid/accessable
  858. validSpot: function (x, y) {
  859. var result;
  860.  
  861. if (!me.area || !x || !y) { // Just in case
  862. return false;
  863. }
  864.  
  865. try { // Treat thrown errors as invalid spot
  866. result = getCollision(me.area, x, y);
  867. } catch (e) {
  868. return false;
  869. }
  870.  
  871. // Avoid non-walkable spots, objects
  872. if (result === undefined || (result & 0x1) || (result & 0x400)) {
  873. return false;
  874. }
  875.  
  876. return true;
  877. },
  878.  
  879. // Open chests when clearing
  880. openChests: function (range, x, y) {
  881. if (!Config.OpenChests) {
  882. return false;
  883. }
  884.  
  885. if (x === undefined || y === undefined) {
  886. x = me.x;
  887. y = me.y;
  888. }
  889.  
  890. var i, unit,
  891. list = [],
  892. ids = ["chest", "chest3", "weaponrack", "armorstand"];
  893.  
  894. unit = getUnit(2);
  895.  
  896. if (unit) {
  897. do {
  898. if (unit.name && getDistance(unit, x, y) <= range && ids.indexOf(unit.name.toLowerCase()) > -1) {
  899. list.push(copyUnit(unit));
  900. }
  901. } while (unit.getNext());
  902. }
  903.  
  904. while (list.length) {
  905. list.sort(Sort.units);
  906.  
  907. if (Misc.openChest(list.shift())) {
  908. Pickit.pickItems();
  909. }
  910. }
  911.  
  912. return true;
  913. },
  914.  
  915. buildMonsterList: function () {
  916. var monster,
  917. monList = [];
  918.  
  919. monster = getUnit(1);
  920.  
  921. if (monster) {
  922. do {
  923. if (this.checkMonster(monster)) {
  924. monList.push(copyUnit(monster));
  925. }
  926. } while (monster.getNext());
  927. }
  928.  
  929. return monList;
  930. },
  931.  
  932. deploy: function (unit, distance, spread, range) {
  933. if (arguments.length < 4) {
  934. throw new Error("deploy: Not enough arguments supplied");
  935. }
  936.  
  937. var i, grid, index, currCount,
  938. tick = getTickCount(),
  939. monList = [],
  940. count = 999,
  941. idealPos = {
  942. x: Math.round(Math.cos(Math.atan2(me.y - unit.y, me.x - unit.x)) * Config.DodgeRange + unit.x),
  943. y: Math.round(Math.sin(Math.atan2(me.y - unit.y, me.x - unit.x)) * Config.DodgeRange + unit.y)
  944. };
  945.  
  946. monList = this.buildMonsterList();
  947.  
  948. monList.sort(Sort.units);
  949.  
  950. if (this.getMonsterCount(me.x, me.y, 15, monList) === 0) {
  951. return true;
  952. }
  953.  
  954. CollMap.getNearbyRooms(unit.x, unit.y);
  955.  
  956. grid = this.buildGrid(unit.x - distance, unit.x + distance, unit.y - distance, unit.y + distance, spread);
  957.  
  958. //print("Grid build time: " + (getTickCount() - tick));
  959.  
  960. if (!grid.length) {
  961. return false;
  962. }
  963.  
  964. function sortGrid(a, b) {
  965. //return getDistance(a.x, a.y, idealPos.x, idealPos.y) - getDistance(b.x, b.y, idealPos.x, idealPos.y);
  966. return getDistance(b.x, b.y, unit.x, unit.y) - getDistance(a.x, a.y, unit.x, unit.y);
  967. }
  968.  
  969. grid.sort(sortGrid);
  970.  
  971. for (i = 0; i < grid.length; i += 1) {
  972. if (!(CollMap.getColl(grid[i].x, grid[i].y, true) & 0x1) && !CollMap.checkColl(unit, {x: grid[i].x, y: grid[i].y}, 0x4)) {
  973. currCount = this.getMonsterCount(grid[i].x, grid[i].y, range, monList);
  974.  
  975. if (currCount < count) {
  976. index = i;
  977. count = currCount;
  978. }
  979.  
  980. if (currCount === 0) {
  981. break;
  982. }
  983. }
  984. }
  985.  
  986. //print("Safest spot with " + count + " monsters.");
  987.  
  988. if (typeof index === "number") {
  989. //print("Dodge build time: " + (getTickCount() - tick));
  990.  
  991. return Pather.moveTo(grid[index].x, grid[index].y, 0);
  992. }
  993.  
  994. return false;
  995. },
  996.  
  997. getMonsterCount: function (x, y, range, list) {
  998. var i,
  999. fire,
  1000. count = 0,
  1001. ignored = [243];
  1002.  
  1003. for (i = 0; i < list.length; i += 1) {
  1004. if (ignored.indexOf(list[i].classid) === -1 && this.checkMonster(list[i]) && getDistance(x, y, list[i].x, list[i].y) <= range) {
  1005. count += 1;
  1006. }
  1007. }
  1008.  
  1009. fire = getUnit(2, "fire");
  1010.  
  1011. if (fire) {
  1012. do {
  1013. if (getDistance(x, y, fire.x, fire.y) <= 4) {
  1014. count += 100;
  1015. }
  1016. } while (fire.getNext());
  1017. }
  1018.  
  1019. return count;
  1020. },
  1021.  
  1022. buildGrid: function (xmin, xmax, ymin, ymax, spread) {
  1023. if (xmin >= xmax || ymin >= ymax || spread < 1) {
  1024. throw new Error("buildGrid: Bad parameters");
  1025. }
  1026.  
  1027. var i, j, coll,
  1028. grid = [];
  1029.  
  1030. for (i = xmin; i <= xmax; i += spread) {
  1031. for (j = ymin; j <= ymax; j += spread) {
  1032. coll = CollMap.getColl(i, j, true);
  1033.  
  1034. if (typeof coll === "number") {
  1035. grid.push({x: i, y: j, coll: coll});
  1036. }
  1037. }
  1038. }
  1039.  
  1040. return grid;
  1041. },
  1042.  
  1043. // Check if a monster is attackable
  1044. checkMonster: function (unit) {
  1045. if (!unit || !copyUnit(unit).x) {
  1046. return false;
  1047. }
  1048.  
  1049. if (unit.area !== me.area) {
  1050. return false;
  1051. }
  1052.  
  1053. if (unit.type === 0 && unit.mode !== 17) { // Player
  1054. return true;
  1055. }
  1056.  
  1057. if (unit.hp === 0 || unit.mode === 0 || unit.mode === 12) { // Dead monster
  1058. return false;
  1059. }
  1060.  
  1061. if (unit.getStat(172) === 2) { // Friendly monster/NPC
  1062. return false;
  1063. }
  1064.  
  1065. if (getBaseStat("monstats", unit.classid, "neverCount")) { // neverCount base stat - hydras, traps etc.
  1066. return false;
  1067. }
  1068.  
  1069. switch (unit.classid) {
  1070. case 179: // An evil force - cow (lol)
  1071. return false;
  1072. case 543: // Baal in Throne
  1073. if (me.area === 131) {
  1074. return false;
  1075. }
  1076.  
  1077. break;
  1078. case 110: // Vultures
  1079. case 111:
  1080. case 112:
  1081. case 113:
  1082. case 114:
  1083. case 608:
  1084. if (unit.mode === 8) { // Flying
  1085. return false;
  1086. }
  1087.  
  1088. break;
  1089. case 68: // Sand Maggots
  1090. case 69:
  1091. case 70:
  1092. case 71:
  1093. case 72:
  1094. case 679:
  1095. case 258: // Water Watchers
  1096. case 259:
  1097. case 260:
  1098. case 261:
  1099. case 262:
  1100. case 263:
  1101. if (unit.mode === 14) { // Submerged/Burrowed
  1102. return false;
  1103. }
  1104.  
  1105. break;
  1106. }
  1107.  
  1108. return true;
  1109. },
  1110.  
  1111. skipCheck: function (unit) {
  1112. if (me.area === 131) {
  1113. return true;
  1114. }
  1115.  
  1116. var i, j, rval,
  1117. tempArray = [];
  1118.  
  1119. EnchantLoop: // Skip enchanted monsters
  1120. for (i = 0; i < Config.SkipEnchant.length; i += 1) {
  1121. tempArray = Config.SkipEnchant[i].toLowerCase().split(" and ");
  1122.  
  1123. for (j = 0; j < tempArray.length; j += 1) {
  1124. switch (tempArray[j]) {
  1125. case "extra strong":
  1126. tempArray[j] = 5;
  1127.  
  1128. break;
  1129. case "extra fast":
  1130. tempArray[j] = 6;
  1131.  
  1132. break;
  1133. case "cursed":
  1134. tempArray[j] = 7;
  1135.  
  1136. break;
  1137. case "magic resistant":
  1138. tempArray[j] = 8;
  1139.  
  1140. break;
  1141. case "fire enchanted":
  1142. tempArray[j] = 9;
  1143.  
  1144. break;
  1145. case "lightning enchanted":
  1146. tempArray[j] = 17;
  1147.  
  1148. break;
  1149. case "cold enchanted":
  1150. tempArray[j] = 18;
  1151.  
  1152. break;
  1153. case "mana burn":
  1154. tempArray[j] = 25;
  1155.  
  1156. break;
  1157. case "teleportation":
  1158. tempArray[j] = 26;
  1159.  
  1160. break;
  1161. case "spectral hit":
  1162. tempArray[j] = 27;
  1163.  
  1164. break;
  1165. case "stone skin":
  1166. tempArray[j] = 28;
  1167.  
  1168. break;
  1169. case "multiple shots":
  1170. tempArray[j] = 29;
  1171.  
  1172. break;
  1173. }
  1174. }
  1175.  
  1176. for (j = 0; j < tempArray.length; j += 1) {
  1177. if (!unit.getEnchant(tempArray[j])) {
  1178. break;
  1179. }
  1180. }
  1181.  
  1182. if (j === tempArray.length) {
  1183. //print("Skip Enchanted: " + unit.name);
  1184.  
  1185. return false;
  1186. }
  1187. }
  1188.  
  1189. ImmuneLoop: // Skip immune monsters
  1190. for (i = 0; i < Config.SkipImmune.length; i += 1) {
  1191. tempArray = Config.SkipImmune[i].toLowerCase().split(" and ");
  1192.  
  1193. for (j = 0; j < tempArray.length; j += 1) {
  1194. if (this.checkResist(unit, tempArray[j])) { // Infinity calculations are built-in
  1195. break;
  1196. }
  1197. }
  1198.  
  1199. if (j === tempArray.length) {
  1200. return false;
  1201. }
  1202. }
  1203.  
  1204. AuraLoop: // Skip monsters with auras
  1205. for (i = 0; i < Config.SkipAura.length; i += 1) {
  1206. rval = true;
  1207.  
  1208. switch (Config.SkipAura[i].toLowerCase()) {
  1209. case "fanaticism":
  1210. if (unit.getState(49)) {
  1211. rval = false;
  1212. }
  1213.  
  1214. break;
  1215. case "might":
  1216. if (unit.getState(33)) {
  1217. rval = false;
  1218. }
  1219.  
  1220. break;
  1221. case "holy fire":
  1222. if (unit.getState(35)) {
  1223. rval = false;
  1224. }
  1225.  
  1226. break;
  1227. case "blessed aim":
  1228. if (unit.getState(40)) {
  1229. rval = false;
  1230. }
  1231.  
  1232. break;
  1233. case "conviction":
  1234. if (unit.getState(28)) {
  1235. rval = false;
  1236. }
  1237.  
  1238. break;
  1239. case "holy freeze":
  1240. if (unit.getState(43)) {
  1241. rval = false;
  1242. }
  1243.  
  1244. break;
  1245. case "holy shock":
  1246. if (unit.getState(46)) {
  1247. rval = false;
  1248. }
  1249.  
  1250. break;
  1251. }
  1252.  
  1253. if (!rval) {
  1254. return false;
  1255. }
  1256. }
  1257.  
  1258. return true;
  1259. },
  1260.  
  1261. // Get element by skill number
  1262. getSkillElement: function (skillId) {
  1263. this.elements = ["physical", "fire", "lightning", "magic", "cold", "poison", "none"];
  1264.  
  1265. switch (skillId) {
  1266. case 74: // Corpse Explosion
  1267. case 144: // Concentrate
  1268. case 147: // Frenzy
  1269. case 273: // Minge Blast
  1270. case 500: // Summoner
  1271. return "physical";
  1272. case 101: // Holy Bolt
  1273. return "holybolt"; // no need to use this.elements array because it returns before going over the array
  1274. }
  1275.  
  1276. var eType = getBaseStat("skills", skillId, "etype");
  1277.  
  1278. if (typeof (eType) === "number") {
  1279. return this.elements[eType];
  1280. }
  1281.  
  1282. return false;
  1283. },
  1284.  
  1285. // Get a monster's resistance to specified element
  1286. getResist: function (unit, type) {
  1287. if (unit.type === 0) { // player
  1288. return 0;
  1289. }
  1290.  
  1291. switch (type) {
  1292. case "physical":
  1293. return unit.getStat(36);
  1294. case "fire":
  1295. return unit.getStat(39);
  1296. case "lightning":
  1297. return unit.getStat(41);
  1298. case "magic":
  1299. return unit.getStat(37);
  1300. case "cold":
  1301. return unit.getStat(43);
  1302. case "poison":
  1303. return unit.getStat(45);
  1304. case "none":
  1305. return 0;
  1306. case "holybolt": // check if a monster is undead
  1307. if (getBaseStat("monstats", unit.classid, "lUndead") || getBaseStat("monstats", unit.classid, "hUndead")) {
  1308. return 0;
  1309. }
  1310.  
  1311. return 100;
  1312. }
  1313.  
  1314. return 100;
  1315. },
  1316.  
  1317. // Check if a monster is immune to specified attack type
  1318. checkResist: function (unit, val, maxres) {
  1319. // Ignore player resistances
  1320. if (unit.type === 0) {
  1321. return true;
  1322. }
  1323.  
  1324. var damageType = typeof val === "number" ? this.getSkillElement(val) : val;
  1325.  
  1326. if (maxres === undefined) {
  1327. maxres = 100;
  1328. }
  1329.  
  1330. // Static handler
  1331. if (val === 42 && this.getResist(unit, damageType) < 100) {
  1332. return (unit.hp * 100 / 128) > Config.CastStatic;
  1333. }
  1334.  
  1335. if (this.infinity && ["fire", "lightning", "cold"].indexOf(damageType) > -1) {
  1336. if (!unit.getState(28)) {
  1337. return this.getResist(unit, damageType) < 117;
  1338. }
  1339.  
  1340. return this.getResist(unit, damageType) < maxres;
  1341. }
  1342.  
  1343. return this.getResist(unit, damageType) < maxres;
  1344. },
  1345.  
  1346. // Check if we have valid skills to attack a monster
  1347. canAttack: function (unit) {
  1348. if (unit.type === 1) {
  1349. if (unit.spectype & 0x7) { // Unique/Champion
  1350. if (Attack.checkResist(unit, this.getSkillElement(Config.AttackSkill[1])) || Attack.checkResist(unit, this.getSkillElement(Config.AttackSkill[2]))) {
  1351. return true;
  1352. }
  1353. } else {
  1354. if (Attack.checkResist(unit, this.getSkillElement(Config.AttackSkill[3])) || Attack.checkResist(unit, this.getSkillElement(Config.AttackSkill[4]))) {
  1355. return true;
  1356. }
  1357. }
  1358.  
  1359. if (Config.AttackSkill.length === 7) {
  1360. return Attack.checkResist(unit, this.getSkillElement(Config.AttackSkill[5])) || Attack.checkResist(unit, this.getSkillElement(Config.AttackSkill[6]));
  1361. }
  1362. }
  1363.  
  1364. return false;
  1365. },
  1366.  
  1367. // Detect use of bows/crossbows
  1368. usingBow: function () {
  1369. var item;
  1370.  
  1371. item = me.getItem(-1, 1);
  1372.  
  1373. if (item) {
  1374. do {
  1375. if (item.bodylocation === 4 || item.bodylocation === 5) {
  1376. switch (item.itemType) {
  1377. case 27: // Bows
  1378. case 85: // Amazon Bows
  1379. return "bow";
  1380. case 35: // Crossbows
  1381. return "crossbow";
  1382. }
  1383. }
  1384. } while (item.getNext());
  1385. }
  1386.  
  1387. return false;
  1388. },
  1389.  
  1390. // Find an optimal attack position and move or walk to it
  1391. getIntoPosition: function (unit, distance, coll, walk) {
  1392. if (!unit || !unit.x || !unit.y) {
  1393. return false;
  1394. }
  1395.  
  1396. if (walk === true) {
  1397. walk = 1;
  1398. }
  1399.  
  1400. if (distance < 4 && (!unit.hasOwnProperty("mode") || (unit.mode !== 0 && unit.mode !== 12))) {
  1401. //me.overhead("Short range");
  1402.  
  1403. if (walk) {
  1404. if (getDistance(me, unit) > 8 || checkCollision(me, unit, coll)) {
  1405. Pather.walkTo(unit.x, unit.y, 3);
  1406. }
  1407. } else {
  1408. Pather.moveTo(unit.x, unit.y, 0);
  1409. }
  1410.  
  1411. return !CollMap.checkColl(me, unit, coll);
  1412. }
  1413.  
  1414. var n, i, cx, cy, t,
  1415. coords = [],
  1416. fullDistance = distance,
  1417. name = unit.hasOwnProperty("name") ? unit.name : "",
  1418. angle = Math.round(Math.atan2(me.y - unit.y, me.x - unit.x) * 180 / Math.PI),
  1419. angles = [0, 15, -15, 30, -30, 45, -45, 60, -60, 75, -75, 90, -90, 135, -135, 180];
  1420.  
  1421. t = getTickCount();
  1422.  
  1423. for (n = 0; n < 3; n += 1) {
  1424. if (n > 0) {
  1425. distance -= Math.floor(fullDistance / 3 - 1);
  1426. }
  1427.  
  1428. for (i = 0; i < angles.length; i += 1) {
  1429. cx = Math.round((Math.cos((angle + angles[i]) * Math.PI / 180)) * distance + unit.x);
  1430. cy = Math.round((Math.sin((angle + angles[i]) * Math.PI / 180)) * distance + unit.y);
  1431.  
  1432. if (Pather.checkSpot(cx, cy, 0x1, false)) {
  1433. coords.push({x: cx, y: cy});
  1434. }
  1435. }
  1436.  
  1437. //print("ÿc9potential spots: ÿc2" + coords.length);
  1438.  
  1439. if (coords.length > 0) {
  1440. coords.sort(Sort.units);
  1441.  
  1442. for (i = 0; i < coords.length; i += 1) {
  1443. // Valid position found
  1444. if (!CollMap.checkColl({x: coords[i].x, y: coords[i].y}, unit, coll, 1)) {
  1445. //print("ÿc9optimal pos build time: ÿc2" + (getTickCount() - t)); // + " ÿc9distance from target: ÿc2" + getDistance(cx, cy, unit.x, unit.y));
  1446.  
  1447. switch (walk) {
  1448. case 1:
  1449. Pather.walkTo(coords[i].x, coords[i].y, 2);
  1450.  
  1451. break;
  1452. case 2:
  1453. if (getDistance(me, coords[i]) < 6 && !CollMap.checkColl(me, coords[i], 0x5)) {
  1454. Pather.walkTo(coords[i].x, coords[i].y, 2);
  1455. } else {
  1456. Pather.moveTo(coords[i].x, coords[i].y, 1);
  1457. }
  1458.  
  1459. break;
  1460. default:
  1461. Pather.moveTo(coords[i].x, coords[i].y, 1);
  1462.  
  1463. break;
  1464. }
  1465.  
  1466. return true;
  1467. }
  1468. }
  1469. }
  1470. }
  1471.  
  1472. if (name) {
  1473. print("Couldn't get to " + name);
  1474. }
  1475.  
  1476. return false;
  1477. }
  1478. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement