HeroWarsHelper

Automation of actions for the game Hero Wars

  1. // ==UserScript==
  2. // @name HeroWarsHelper
  3. // @name:en HeroWarsHelper
  4. // @name:ru HeroWarsHelper
  5. // @namespace HeroWarsHelper
  6. // @version 2.352
  7. // @description Automation of actions for the game Hero Wars
  8. // @description:en Automation of actions for the game Hero Wars
  9. // @description:ru Автоматизация действий для игры Хроники Хаоса
  10. // @author ZingerY
  11. // @license Copyright ZingerY
  12. // @homepage https://zingery.ru/scripts/HeroWarsHelper.user.js
  13. // @icon https://zingery.ru/scripts/VaultBoyIco16.ico
  14. // @icon64 https://zingery.ru/scripts/VaultBoyIco64.png
  15. // @match https://www.hero-wars.com/*
  16. // @match https://apps-1701433570146040.apps.fbsbx.com/*
  17. // @run-at document-start
  18. // ==/UserScript==
  19.  
  20. (function() {
  21. /**
  22. * Start script
  23. *
  24. * Стартуем скрипт
  25. */
  26. console.log('%cStart ' + GM_info.script.name + ', v' + GM_info.script.version + ' by ' + GM_info.script.author, 'color: red');
  27. /**
  28. * Script info
  29. *
  30. * Информация о скрипте
  31. */
  32. this.scriptInfo = (({name, version, author, homepage, lastModified}, updateUrl) =>
  33. ({name, version, author, homepage, lastModified, updateUrl}))
  34. (GM_info.script, GM_info.scriptUpdateURL);
  35. this.GM_info = GM_info;
  36. /**
  37. * Information for completing daily quests
  38. *
  39. * Информация для выполнения ежендевных квестов
  40. */
  41. const questsInfo = {};
  42. /**
  43. * Is the game data loaded
  44. *
  45. * Загружены ли данные игры
  46. */
  47. let isLoadGame = false;
  48. /**
  49. * Headers of the last request
  50. *
  51. * Заголовки последнего запроса
  52. */
  53. let lastHeaders = {};
  54. /**
  55. * Information about sent gifts
  56. *
  57. * Информация об отправленных подарках
  58. */
  59. let freebieCheckInfo = null;
  60. /**
  61. * missionTimer
  62. *
  63. * missionTimer
  64. */
  65. let missionBattle = null;
  66. /**
  67. * User data
  68. *
  69. * Данные пользователя
  70. */
  71. let userInfo;
  72. this.isTimeBetweenNewDays = function () {
  73. if (userInfo.timeZone <= 3) {
  74. return false;
  75. }
  76. const nextDayTs = new Date(userInfo.nextDayTs * 1e3);
  77. const nextServerDayTs = new Date(userInfo.nextServerDayTs * 1e3);
  78. if (nextDayTs > nextServerDayTs) {
  79. nextDayTs.setDate(nextDayTs.getDate() - 1);
  80. }
  81. const now = Date.now();
  82. if (now > nextDayTs && now < nextServerDayTs) {
  83. return true;
  84. }
  85. return false;
  86. };
  87.  
  88. function getUserInfo() {
  89. return userInfo;
  90. }
  91. /**
  92. * Original methods for working with AJAX
  93. *
  94. * Оригинальные методы для работы с AJAX
  95. */
  96. const original = {
  97. open: XMLHttpRequest.prototype.open,
  98. send: XMLHttpRequest.prototype.send,
  99. setRequestHeader: XMLHttpRequest.prototype.setRequestHeader,
  100. SendWebSocket: WebSocket.prototype.send,
  101. fetch: fetch,
  102. };
  103.  
  104. // Sentry blocking
  105. // Блокировка наблюдателя
  106. this.fetch = function (url, options) {
  107. /**
  108. * Checking URL for blocking
  109. * Проверяем URL на блокировку
  110. */
  111. if (url.includes('sentry.io')) {
  112. console.log('%cFetch blocked', 'color: red');
  113. console.log(url, options);
  114. const body = {
  115. id: md5(Date.now()),
  116. };
  117. let info = {};
  118. try {
  119. info = JSON.parse(options.body);
  120. } catch (e) {}
  121. if (info.event_id) {
  122. body.id = info.event_id;
  123. }
  124. /**
  125. * Mock response for blocked URL
  126. *
  127. * Мокаем ответ для заблокированного URL
  128. */
  129. const mockResponse = new Response('Custom blocked response', {
  130. status: 200,
  131. headers: { 'Content-Type': 'application/json' },
  132. body,
  133. });
  134. return Promise.resolve(mockResponse);
  135. } else {
  136. /**
  137. * Call the original fetch function for all other URLs
  138. * Вызываем оригинальную функцию fetch для всех других URL
  139. */
  140. return original.fetch.apply(this, arguments);
  141. }
  142. };
  143.  
  144. /**
  145. * Decoder for converting byte data to JSON string
  146. *
  147. * Декодер для перобразования байтовых данных в JSON строку
  148. */
  149. const decoder = new TextDecoder("utf-8");
  150. /**
  151. * Stores a history of requests
  152. *
  153. * Хранит историю запросов
  154. */
  155. let requestHistory = {};
  156. /**
  157. * URL for API requests
  158. *
  159. * URL для запросов к API
  160. */
  161. let apiUrl = '';
  162.  
  163. /**
  164. * Connecting to the game code
  165. *
  166. * Подключение к коду игры
  167. */
  168. this.cheats = new hackGame();
  169. /**
  170. * The function of calculating the results of the battle
  171. *
  172. * Функция расчета результатов боя
  173. */
  174. this.BattleCalc = cheats.BattleCalc;
  175. /**
  176. * Sending a request available through the console
  177. *
  178. * Отправка запроса доступная через консоль
  179. */
  180. this.SendRequest = send;
  181. /**
  182. * Simple combat calculation available through the console
  183. *
  184. * Простой расчет боя доступный через консоль
  185. */
  186. this.Calc = function (data) {
  187. const type = getBattleType(data?.type);
  188. return new Promise((resolve, reject) => {
  189. try {
  190. BattleCalc(data, type, resolve);
  191. } catch (e) {
  192. reject(e);
  193. }
  194. })
  195. }
  196. /**
  197. * Short asynchronous request
  198. * Usage example (returns information about a character):
  199. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  200. *
  201. * Короткий асинхронный запрос
  202. * Пример использования (возвращает информацию о персонаже):
  203. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  204. */
  205. this.Send = function (json, pr) {
  206. return new Promise((resolve, reject) => {
  207. try {
  208. send(json, resolve, pr);
  209. } catch (e) {
  210. reject(e);
  211. }
  212. })
  213. }
  214.  
  215. this.xyz = (({ name, version, author }) => ({ name, version, author }))(GM_info.script);
  216. const i18nLangData = {
  217. /* English translation by BaBa */
  218. en: {
  219. /* Checkboxes */
  220. SKIP_FIGHTS: 'Skip battle',
  221. SKIP_FIGHTS_TITLE: 'Skip battle in Outland and the arena of the titans, auto-pass in the tower and campaign',
  222. ENDLESS_CARDS: 'Infinite cards',
  223. ENDLESS_CARDS_TITLE: 'Disable Divination Cards wasting',
  224. AUTO_EXPEDITION: 'Auto Expedition',
  225. AUTO_EXPEDITION_TITLE: 'Auto-sending expeditions',
  226. CANCEL_FIGHT: 'Cancel battle',
  227. CANCEL_FIGHT_TITLE: 'Ability to cancel manual combat on GW, CoW and Asgard',
  228. GIFTS: 'Gifts',
  229. GIFTS_TITLE: 'Collect gifts automatically',
  230. BATTLE_RECALCULATION: 'Battle recalculation',
  231. BATTLE_RECALCULATION_TITLE: 'Preliminary calculation of the battle',
  232. QUANTITY_CONTROL: 'Quantity control',
  233. QUANTITY_CONTROL_TITLE: 'Ability to specify the number of opened "lootboxes"',
  234. REPEAT_CAMPAIGN: 'Repeat missions',
  235. REPEAT_CAMPAIGN_TITLE: 'Auto-repeat battles in the campaign',
  236. DISABLE_DONAT: 'Disable donation',
  237. DISABLE_DONAT_TITLE: 'Removes all donation offers',
  238. DAILY_QUESTS: 'Quests',
  239. DAILY_QUESTS_TITLE: 'Complete daily quests',
  240. AUTO_QUIZ: 'AutoQuiz',
  241. AUTO_QUIZ_TITLE: 'Automatically receive correct answers to quiz questions',
  242. SECRET_WEALTH_CHECKBOX: 'Automatic purchase in the store "Secret Wealth" when entering the game',
  243. HIDE_SERVERS: 'Collapse servers',
  244. HIDE_SERVERS_TITLE: 'Hide unused servers',
  245. /* Input fields */
  246. HOW_MUCH_TITANITE: 'How much titanite to farm',
  247. COMBAT_SPEED: 'Combat Speed Multiplier',
  248. NUMBER_OF_TEST: 'Number of test fights',
  249. NUMBER_OF_AUTO_BATTLE: 'Number of auto-battle attempts',
  250. /* Buttons */
  251. RUN_SCRIPT: 'Run the',
  252. TO_DO_EVERYTHING: 'Do All',
  253. TO_DO_EVERYTHING_TITLE: 'Perform multiple actions of your choice',
  254. OUTLAND: 'Outland',
  255. OUTLAND_TITLE: 'Collect Outland',
  256. TITAN_ARENA: 'ToE',
  257. TITAN_ARENA_TITLE: 'Complete the titan arena',
  258. DUNGEON: 'Dungeon',
  259. DUNGEON_TITLE: 'Go through the dungeon',
  260. SEER: 'Seer',
  261. SEER_TITLE: 'Roll the Seer',
  262. TOWER: 'Tower',
  263. TOWER_TITLE: 'Pass the tower',
  264. EXPEDITIONS: 'Expeditions',
  265. EXPEDITIONS_TITLE: 'Sending and collecting expeditions',
  266. SYNC: 'Sync',
  267. SYNC_TITLE: 'Partial synchronization of game data without reloading the page',
  268. ARCHDEMON: 'Archdemon',
  269. FURNACE_OF_SOULS: 'Furnace of souls',
  270. ARCHDEMON_TITLE: 'Hitting kills and collecting rewards',
  271. ESTER_EGGS: 'Easter eggs',
  272. ESTER_EGGS_TITLE: 'Collect all Easter eggs or rewards',
  273. REWARDS: 'Rewards',
  274. REWARDS_TITLE: 'Collect all quest rewards',
  275. MAIL: 'Mail',
  276. MAIL_TITLE: 'Collect all mail, except letters with energy and charges of the portal',
  277. MINIONS: 'Minions',
  278. MINIONS_TITLE: 'Attack minions with saved packs',
  279. ADVENTURE: 'Adv.',
  280. ADVENTURE_TITLE: 'Passes the adventure along the specified route',
  281. STORM: 'Storm',
  282. STORM_TITLE: 'Passes the Storm along the specified route',
  283. SANCTUARY: 'Sanctuary',
  284. SANCTUARY_TITLE: 'Fast travel to Sanctuary',
  285. GUILD_WAR: 'Guild War',
  286. GUILD_WAR_TITLE: 'Fast travel to Guild War',
  287. SECRET_WEALTH: 'Secret Wealth',
  288. SECRET_WEALTH_TITLE: 'Buy something in the store "Secret Wealth"',
  289. /* Misc */
  290. BOTTOM_URLS:
  291. '<a href="https://t.me/+0oMwICyV1aQ1MDAy" target="_blank" title="Telegram"><svg width="20" height="20" style="margin:2px" viewBox="0 0 1e3 1e3" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="a" x1="50%" x2="50%" y2="99.258%"><stop stop-color="#2AABEE" offset="0"/><stop stop-color="#229ED9" offset="1"/></linearGradient></defs><g fill-rule="evenodd"><circle cx="500" cy="500" r="500" fill="url(#a)"/><path d="m226.33 494.72c145.76-63.505 242.96-105.37 291.59-125.6 138.86-57.755 167.71-67.787 186.51-68.119 4.1362-0.072862 13.384 0.95221 19.375 5.8132 5.0584 4.1045 6.4501 9.6491 7.1161 13.541 0.666 3.8915 1.4953 12.756 0.83608 19.683-7.5246 79.062-40.084 270.92-56.648 359.47-7.0089 37.469-20.81 50.032-34.17 51.262-29.036 2.6719-51.085-19.189-79.207-37.624-44.007-28.847-68.867-46.804-111.58-74.953-49.366-32.531-17.364-50.411 10.769-79.631 7.3626-7.6471 135.3-124.01 137.77-134.57 0.30968-1.3202 0.59708-6.2414-2.3265-8.8399s-7.2385-1.7099-10.352-1.0032c-4.4137 1.0017-74.715 47.468-210.9 139.4-19.955 13.702-38.029 20.379-54.223 20.029-17.853-0.3857-52.194-10.094-77.723-18.393-31.313-10.178-56.199-15.56-54.032-32.846 1.1287-9.0037 13.528-18.212 37.197-27.624z" fill="#fff"/></g></svg></a><a href="https://www.patreon.com/HeroWarsUserScripts" target="_blank" title="Patreon"><svg width="20" height="20" viewBox="0 0 1080 1080" xmlns="http://www.w3.org/2000/svg"><g fill="#FFF" stroke="None"><path d="m1033 324.45c-0.19-137.9-107.59-250.92-233.6-291.7-156.48-50.64-362.86-43.3-512.28 27.2-181.1 85.46-237.99 272.66-240.11 459.36-1.74 153.5 13.58 557.79 241.62 560.67 169.44 2.15 194.67-216.18 273.07-321.33 55.78-74.81 127.6-95.94 216.01-117.82 151.95-37.61 255.51-157.53 255.29-316.38z"/></g></svg></a>',
  292. GIFTS_SENT: 'Gifts sent!',
  293. DO_YOU_WANT: 'Do you really want to do this?',
  294. BTN_RUN: 'Run',
  295. BTN_CANCEL: 'Cancel',
  296. BTN_ACCEPT: 'Accept',
  297. BTN_OK: 'OK',
  298. MSG_HAVE_BEEN_DEFEATED: 'You have been defeated!',
  299. BTN_AUTO: 'Auto',
  300. MSG_YOU_APPLIED: 'You applied',
  301. MSG_DAMAGE: 'damage',
  302. MSG_CANCEL_AND_STAT: 'Auto (F5) and show statistic',
  303. MSG_REPEAT_MISSION: 'Repeat the mission?',
  304. BTN_REPEAT: 'Repeat',
  305. BTN_NO: 'No',
  306. MSG_SPECIFY_QUANT: 'Specify Quantity:',
  307. BTN_OPEN: 'Open',
  308. QUESTION_COPY: 'Question copied to clipboard',
  309. ANSWER_KNOWN: 'The answer is known',
  310. ANSWER_NOT_KNOWN: 'ATTENTION THE ANSWER IS NOT KNOWN',
  311. BEING_RECALC: 'The battle is being recalculated',
  312. THIS_TIME: 'This time',
  313. VICTORY: '<span style="color:green;">VICTORY</span>',
  314. DEFEAT: '<span style="color:red;">DEFEAT</span>',
  315. CHANCE_TO_WIN: 'Chance to win <span style="color: red;">based on pre-calculation</span>',
  316. OPEN_DOLLS: 'nesting dolls recursively',
  317. SENT_QUESTION: 'Question sent',
  318. SETTINGS: 'Settings',
  319. MSG_BAN_ATTENTION: '<p style="color:red;">Using this feature may result in a ban.</p> Continue?',
  320. BTN_YES_I_AGREE: 'Yes, I understand the risks!',
  321. BTN_NO_I_AM_AGAINST: 'No, I refuse it!',
  322. VALUES: 'Values',
  323. EXPEDITIONS_SENT: 'Expeditions:<br>Collected: {countGet}<br>Sent: {countSend}',
  324. EXPEDITIONS_NOTHING: 'Nothing to collect/send',
  325. EXPEDITIONS_NOTTIME: 'It is not time for expeditions',
  326. TITANIT: 'Titanit',
  327. COMPLETED: 'completed',
  328. FLOOR: 'Floor',
  329. LEVEL: 'Level',
  330. BATTLES: 'battles',
  331. EVENT: 'Event',
  332. NOT_AVAILABLE: 'not available',
  333. NO_HEROES: 'No heroes',
  334. DAMAGE_AMOUNT: 'Damage amount',
  335. NOTHING_TO_COLLECT: 'Nothing to collect',
  336. COLLECTED: 'Collected',
  337. REWARD: 'rewards',
  338. REMAINING_ATTEMPTS: 'Remaining attempts',
  339. BATTLES_CANCELED: 'Battles canceled',
  340. MINION_RAID: 'Minion Raid',
  341. STOPPED: 'Stopped',
  342. REPETITIONS: 'Repetitions',
  343. MISSIONS_PASSED: 'Missions passed',
  344. STOP: 'stop',
  345. TOTAL_OPEN: 'Total open',
  346. OPEN: 'Open',
  347. ROUND_STAT: 'Damage statistics for ',
  348. BATTLE: 'battles',
  349. MINIMUM: 'Minimum',
  350. MAXIMUM: 'Maximum',
  351. AVERAGE: 'Average',
  352. NOT_THIS_TIME: 'Not this time',
  353. RETRY_LIMIT_EXCEEDED: 'Retry limit exceeded',
  354. SUCCESS: 'Success',
  355. RECEIVED: 'Received',
  356. LETTERS: 'letters',
  357. PORTALS: 'portals',
  358. ATTEMPTS: 'attempts',
  359. /* Quests */
  360. QUEST_10001: 'Upgrade the skills of heroes 3 times',
  361. QUEST_10002: 'Complete 10 missions',
  362. QUEST_10003: 'Complete 3 heroic missions',
  363. QUEST_10004: 'Fight 3 times in the Arena or Grand Arena',
  364. QUEST_10006: 'Use the exchange of emeralds 1 time',
  365. QUEST_10007: 'Perform 1 summon in the Soul Atrium',
  366. QUEST_10016: 'Send gifts to guildmates',
  367. QUEST_10018: 'Use an experience potion',
  368. QUEST_10019: 'Open 1 chest in the Tower',
  369. QUEST_10020: 'Open 3 chests in Outland',
  370. QUEST_10021: 'Collect 75 Titanite in the Guild Dungeon',
  371. QUEST_10021: 'Collect 150 Titanite in the Guild Dungeon',
  372. QUEST_10023: 'Upgrade Gift of the Elements by 1 level',
  373. QUEST_10024: 'Level up any artifact once',
  374. QUEST_10025: 'Start Expedition 1',
  375. QUEST_10026: 'Start 4 Expeditions',
  376. QUEST_10027: 'Win 1 battle of the Tournament of Elements',
  377. QUEST_10028: 'Level up any titan artifact',
  378. QUEST_10029: 'Unlock the Orb of Titan Artifacts',
  379. QUEST_10030: 'Upgrade any Skin of any hero 1 time',
  380. QUEST_10031: 'Win 6 battles of the Tournament of Elements',
  381. QUEST_10043: 'Start or Join an Adventure',
  382. QUEST_10044: 'Use Summon Pets 1 time',
  383. QUEST_10046: 'Open 3 chests in Adventure',
  384. QUEST_10047: 'Get 150 Guild Activity Points',
  385. NOTHING_TO_DO: 'Nothing to do',
  386. YOU_CAN_COMPLETE: 'You can complete quests',
  387. BTN_DO_IT: 'Do it',
  388. NOT_QUEST_COMPLETED: 'Not a single quest completed',
  389. COMPLETED_QUESTS: 'Completed quests',
  390. /* everything button */
  391. ASSEMBLE_OUTLAND: 'Assemble Outland',
  392. PASS_THE_TOWER: 'Pass the tower',
  393. CHECK_EXPEDITIONS: 'Check Expeditions',
  394. COMPLETE_TOE: 'Complete ToE',
  395. COMPLETE_DUNGEON: 'Complete the dungeon',
  396. COLLECT_MAIL: 'Collect mail',
  397. COLLECT_MISC: 'Collect some bullshit',
  398. COLLECT_MISC_TITLE: 'Collect Easter Eggs, Skin Gems, Keys, Arena Coins and Soul Crystal',
  399. COLLECT_QUEST_REWARDS: 'Collect quest rewards',
  400. MAKE_A_SYNC: 'Make a sync',
  401.  
  402. RUN_FUNCTION: 'Run the following functions?',
  403. BTN_GO: 'Go!',
  404. PERFORMED: 'Performed',
  405. DONE: 'Done',
  406. ERRORS_OCCURRES: 'Errors occurred while executing',
  407. COPY_ERROR: 'Copy error information to clipboard',
  408. BTN_YES: 'Yes',
  409. ALL_TASK_COMPLETED: 'All tasks completed',
  410.  
  411. UNKNOWN: 'unknown',
  412. ENTER_THE_PATH: 'Enter the path of adventure using commas or dashes',
  413. START_ADVENTURE: 'Start your adventure along this path!',
  414. INCORRECT_WAY: 'Incorrect path in adventure: {from} -> {to}',
  415. BTN_CANCELED: 'Canceled',
  416. MUST_TWO_POINTS: 'The path must contain at least 2 points.',
  417. MUST_ONLY_NUMBERS: 'The path must contain only numbers and commas',
  418. NOT_ON_AN_ADVENTURE: 'You are not on an adventure',
  419. YOU_IN_NOT_ON_THE_WAY: 'Your location is not on the way',
  420. ATTEMPTS_NOT_ENOUGH: 'Your attempts are not enough to complete the path, continue?',
  421. YES_CONTINUE: 'Yes, continue!',
  422. NOT_ENOUGH_AP: 'Not enough action points',
  423. ATTEMPTS_ARE_OVER: 'The attempts are over',
  424. MOVES: 'Moves',
  425. BUFF_GET_ERROR: 'Buff getting error',
  426. BATTLE_END_ERROR: 'Battle end error',
  427. AUTOBOT: 'Autobot',
  428. FAILED_TO_WIN_AUTO: 'Failed to win the auto battle',
  429. ERROR_OF_THE_BATTLE_COPY: 'An error occurred during the passage of the battle<br>Copy the error to the clipboard?',
  430. ERROR_DURING_THE_BATTLE: 'Error during the battle',
  431. NO_CHANCE_WIN: 'No chance of winning this fight: 0/',
  432. LOST_HEROES: 'You have won, but you have lost one or several heroes',
  433. VICTORY_IMPOSSIBLE: 'Is victory impossible, should we focus on the result?',
  434. FIND_COEFF: 'Find the coefficient greater than',
  435. BTN_PASS: 'PASS',
  436. BRAWLS: 'Brawls',
  437. BRAWLS_TITLE: 'Activates the ability to auto-brawl',
  438. START_AUTO_BRAWLS: 'Start Auto Brawls?',
  439. LOSSES: 'Losses',
  440. WINS: 'Wins',
  441. FIGHTS: 'Fights',
  442. STAGE: 'Stage',
  443. DONT_HAVE_LIVES: "You don't have lives",
  444. LIVES: 'Lives',
  445. SECRET_WEALTH_ALREADY: 'Item for Pet Potions already purchased',
  446. SECRET_WEALTH_NOT_ENOUGH: 'Not Enough Pet Potion, You Have {available}, Need {need}',
  447. SECRET_WEALTH_UPGRADE_NEW_PET: 'After purchasing the Pet Potion, it will not be enough to upgrade a new pet',
  448. SECRET_WEALTH_PURCHASED: 'Purchased {count} {name}',
  449. SECRET_WEALTH_CANCELED: 'Secret Wealth: Purchase Canceled',
  450. SECRET_WEALTH_BUY: 'You have {available} Pet Potion.<br>Do you want to buy {countBuy} {name} for {price} Pet Potion?',
  451. DAILY_BONUS: 'Daily bonus',
  452. DO_DAILY_QUESTS: 'Do daily quests',
  453. ACTIONS: 'Actions',
  454. ACTIONS_TITLE: 'Dialog box with various actions',
  455. OTHERS: 'Others',
  456. OTHERS_TITLE: 'Others',
  457. CHOOSE_ACTION: 'Choose an action',
  458. OPEN_LOOTBOX: 'You have {lootBox} boxes, should we open them?',
  459. STAMINA: 'Energy',
  460. BOXES_OVER: 'The boxes are over',
  461. NO_BOXES: 'No boxes',
  462. NO_MORE_ACTIVITY: 'No more activity for items today',
  463. EXCHANGE_ITEMS: 'Exchange items for activity points (max {maxActive})?',
  464. GET_ACTIVITY: 'Get Activity',
  465. NOT_ENOUGH_ITEMS: 'Not enough items',
  466. ACTIVITY_RECEIVED: 'Activity received',
  467. NO_PURCHASABLE_HERO_SOULS: 'No purchasable Hero Souls',
  468. PURCHASED_HERO_SOULS: 'Purchased {countHeroSouls} Hero Souls',
  469. NOT_ENOUGH_EMERALDS_540: 'Not enough emeralds, you need {imgEmerald}540 you have {imgEmerald}{currentStarMoney}',
  470. BUY_OUTLAND_BTN: 'Buy {count} chests {imgEmerald}{countEmerald}',
  471. CHESTS_NOT_AVAILABLE: 'Chests not available',
  472. OUTLAND_CHESTS_RECEIVED: 'Outland chests received',
  473. RAID_NOT_AVAILABLE: 'The raid is not available or there are no spheres',
  474. RAID_ADVENTURE: 'Raid {adventureId} adventure!',
  475. SOMETHING_WENT_WRONG: 'Something went wrong',
  476. ADVENTURE_COMPLETED: 'Adventure {adventureId} completed {times} times',
  477. CLAN_STAT_COPY: 'Clan statistics copied to clipboard',
  478. GET_ENERGY: 'Get Energy',
  479. GET_ENERGY_TITLE: 'Opens platinum boxes one at a time until you get 250 energy',
  480. ITEM_EXCHANGE: 'Item Exchange',
  481. ITEM_EXCHANGE_TITLE: 'Exchanges items for the specified amount of activity',
  482. BUY_SOULS: 'Buy souls',
  483. BUY_SOULS_TITLE: 'Buy hero souls from all available shops',
  484. BUY_OUTLAND: 'Buy Outland',
  485. BUY_OUTLAND_TITLE: 'Buy 9 chests in Outland for 540 emeralds',
  486. RAID: 'Raid',
  487. AUTO_RAID_ADVENTURE: 'Raid',
  488. AUTO_RAID_ADVENTURE_TITLE: 'Raid adventure set number of times',
  489. CLAN_STAT: 'Clan statistics',
  490. CLAN_STAT_TITLE: 'Copies clan statistics to the clipboard',
  491. BTN_AUTO_F5: 'Auto (F5)',
  492. BOSS_DAMAGE: 'Boss Damage: ',
  493. NOTHING_BUY: 'Nothing to buy',
  494. LOTS_BOUGHT: '{countBuy} lots bought for gold',
  495. BUY_FOR_GOLD: 'Buy for gold',
  496. BUY_FOR_GOLD_TITLE: 'Buy items for gold in the Town Shop and in the Pet Soul Stone Shop',
  497. REWARDS_AND_MAIL: 'Rewards and Mail',
  498. REWARDS_AND_MAIL_TITLE: 'Collects rewards and mail',
  499. COLLECT_REWARDS_AND_MAIL: 'Collected {countQuests} rewards and {countMail} letters',
  500. TIMER_ALREADY: 'Timer already started {time}',
  501. NO_ATTEMPTS_TIMER_START: 'No attempts, timer started {time}',
  502. EPIC_BRAWL_RESULT: 'Wins: {wins}/{attempts}, Coins: {coins}, Streak: {progress}/{nextStage} [Close]{end}',
  503. ATTEMPT_ENDED: '<br>Attempts ended, timer started {time}',
  504. EPIC_BRAWL: 'Cosmic Battle',
  505. EPIC_BRAWL_TITLE: 'Spends attempts in the Cosmic Battle',
  506. RELOAD_GAME: 'Reload game',
  507. TIMER: 'Timer:',
  508. SHOW_ERRORS: 'Show errors',
  509. SHOW_ERRORS_TITLE: 'Show server request errors',
  510. ERROR_MSG: 'Error: {name}<br>{description}',
  511. EVENT_AUTO_BOSS:
  512. 'Maximum number of battles for calculation:</br>{length} ∗ {countTestBattle} = {maxCalcBattle}</br>If you have a weak computer, it may take a long time for this, click on the cross to cancel.</br>Should I search for the best pack from all or the first suitable one?',
  513. BEST_SLOW: 'Best (slower)',
  514. FIRST_FAST: 'First (faster)',
  515. FREEZE_INTERFACE: 'Calculating... <br>The interface may freeze.',
  516. ERROR_F12: 'Error, details in the console (F12)',
  517. FAILED_FIND_WIN_PACK: 'Failed to find a winning pack',
  518. BEST_PACK: 'Best pack:',
  519. BOSS_HAS_BEEN_DEF: 'Boss {bossLvl} has been defeated.',
  520. NOT_ENOUGH_ATTEMPTS_BOSS: 'Not enough attempts to defeat boss {bossLvl}, retry?',
  521. BOSS_VICTORY_IMPOSSIBLE:
  522. 'Based on the recalculation of {battles} battles, victory has not been achieved. Would you like to continue the search for a winning battle in real battles?',
  523. BOSS_HAS_BEEN_DEF_TEXT:
  524. 'Boss {bossLvl} defeated in<br>{countBattle}/{countMaxBattle} attempts{winTimer}<br>(Please synchronize or restart the game to update the data)',
  525. MAP: 'Map: ',
  526. PLAYER_POS: 'Player positions:',
  527. NY_GIFTS: 'Gifts',
  528. NY_GIFTS_TITLE: "Open all New Year's gifts",
  529. NY_NO_GIFTS: 'No gifts not received',
  530. NY_GIFTS_COLLECTED: '{count} gifts collected',
  531. CHANGE_MAP: 'Island map',
  532. CHANGE_MAP_TITLE: 'Change island map',
  533. SELECT_ISLAND_MAP: 'Select an island map:',
  534. MAP_NUM: 'Map {num}',
  535. SECRET_WEALTH_SHOP: 'Secret Wealth {name}: ',
  536. SHOPS: 'Shops',
  537. SHOPS_DEFAULT: 'Default',
  538. SHOPS_DEFAULT_TITLE: 'Default stores',
  539. SHOPS_LIST: 'Shops {number}',
  540. SHOPS_LIST_TITLE: 'List of shops {number}',
  541. SHOPS_WARNING:
  542. 'Stores<br><span style="color:red">If you buy brawl store coins for emeralds, you must use them immediately, otherwise they will disappear after restarting the game!</span>',
  543. MINIONS_WARNING: 'The hero packs for attacking minions are incomplete, should I continue?',
  544. FAST_SEASON: 'Fast season',
  545. FAST_SEASON_TITLE: 'Skip the map selection screen in a season',
  546. SET_NUMBER_LEVELS: 'Specify the number of levels:',
  547. POSSIBLE_IMPROVE_LEVELS: 'It is possible to improve only {count} levels.<br>Improving?',
  548. NOT_ENOUGH_RESOURECES: 'Not enough resources',
  549. IMPROVED_LEVELS: 'Improved levels: {count}',
  550. ARTIFACTS_UPGRADE: 'Artifacts Upgrade',
  551. ARTIFACTS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero artifacts',
  552. SKINS_UPGRADE: 'Skins Upgrade',
  553. SKINS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero skins',
  554. HINT: '<br>Hint: ',
  555. PICTURE: '<br>Picture: ',
  556. ANSWER: '<br>Answer: ',
  557. NO_HEROES_PACK: 'Fight at least one battle to save the attacking team',
  558. BRAWL_AUTO_PACK: 'Automatic selection of packs',
  559. BRAWL_AUTO_PACK_NOT_CUR_HERO: 'Automatic pack selection is not suitable for the current hero',
  560. BRAWL_DAILY_TASK_COMPLETED: 'Daily task completed, continue attacking?',
  561. CALC_STAT: 'Calculate statistics',
  562. ELEMENT_TOURNAMENT_REWARD: 'Unclaimed bonus for Elemental Tournament',
  563. BTN_TRY_FIX_IT: 'Fix it',
  564. BTN_TRY_FIX_IT_TITLE: 'Enable auto attack combat correction',
  565. DAMAGE_FIXED: 'Damage fixed from {lastDamage} to {maxDamage}!',
  566. DAMAGE_NO_FIXED: 'Failed to fix damage: {lastDamage}',
  567. LETS_FIX: "Let's fix",
  568. COUNT_FIXED: 'For {count} attempts',
  569. DEFEAT_TURN_TIMER: 'Defeat! Turn on the timer to complete the mission?',
  570. SEASON_REWARD: 'Season Rewards',
  571. SEASON_REWARD_TITLE: 'Collects available free rewards from all current seasons',
  572. SEASON_REWARD_COLLECTED: 'Collected {count} season rewards',
  573. SELL_HERO_SOULS: 'Sell ​​souls',
  574. SELL_HERO_SOULS_TITLE: 'Exchanges all absolute star hero souls for gold',
  575. GOLD_RECEIVED: 'Gold received: {gold}',
  576. OPEN_ALL_EQUIP_BOXES: 'Open all Equipment Fragment Box?',
  577. SERVER_NOT_ACCEPT: 'The server did not accept the result',
  578. INVASION_BOSS_BUFF: 'For {bossLvl} boss need buff {needBuff} you have {haveBuff}}',
  579. HERO_POWER: 'Hero Power',
  580. HERO_POWER_TITLE: 'Displays the current and maximum power of heroes',
  581. MAX_POWER_REACHED: 'Maximum power reached: {power}',
  582. CURRENT_POWER: 'Current power: {power}',
  583. POWER_TO_MAX: 'Power left to reach maximum: <span style="color:{color};">{power}</span><br>',
  584. BEST_RESULT: 'Best result: {value}%',
  585. GUILD_ISLAND_TITLE: 'Fast travel to Guild Island',
  586. TITAN_VALLEY_TITLE: 'Fast travel to Titan Valley',
  587. },
  588. ru: {
  589. /* Чекбоксы */
  590. SKIP_FIGHTS: 'Пропуск боев',
  591. SKIP_FIGHTS_TITLE: 'Пропуск боев в запределье и арене титанов, автопропуск в башне и кампании',
  592. ENDLESS_CARDS: 'Бесконечные карты',
  593. ENDLESS_CARDS_TITLE: 'Отключить трату карт предсказаний',
  594. AUTO_EXPEDITION: 'АвтоЭкспедиции',
  595. AUTO_EXPEDITION_TITLE: 'Автоотправка экспедиций',
  596. CANCEL_FIGHT: 'Отмена боя',
  597. CANCEL_FIGHT_TITLE: 'Возможность отмены ручного боя на ВГ, СМ и в Асгарде',
  598. GIFTS: 'Подарки',
  599. GIFTS_TITLE: 'Собирать подарки автоматически',
  600. BATTLE_RECALCULATION: 'Прерасчет боя',
  601. BATTLE_RECALCULATION_TITLE: 'Предварительный расчет боя',
  602. QUANTITY_CONTROL: 'Контроль кол-ва',
  603. QUANTITY_CONTROL_TITLE: 'Возможность указывать количество открываемых "лутбоксов"',
  604. REPEAT_CAMPAIGN: 'Повтор в кампании',
  605. REPEAT_CAMPAIGN_TITLE: 'Автоповтор боев в кампании',
  606. DISABLE_DONAT: 'Отключить донат',
  607. DISABLE_DONAT_TITLE: 'Убирает все предложения доната',
  608. DAILY_QUESTS: 'Квесты',
  609. DAILY_QUESTS_TITLE: 'Выполнять ежедневные квесты',
  610. AUTO_QUIZ: 'АвтоВикторина',
  611. AUTO_QUIZ_TITLE: 'Автоматическое получение правильных ответов на вопросы викторины',
  612. SECRET_WEALTH_CHECKBOX: 'Автоматическая покупка в магазине "Тайное Богатство" при заходе в игру',
  613. HIDE_SERVERS: 'Свернуть сервера',
  614. HIDE_SERVERS_TITLE: 'Скрывать неиспользуемые сервера',
  615. /* Поля ввода */
  616. HOW_MUCH_TITANITE: 'Сколько фармим титанита',
  617. COMBAT_SPEED: 'Множитель ускорения боя',
  618. NUMBER_OF_TEST: 'Количество тестовых боев',
  619. NUMBER_OF_AUTO_BATTLE: 'Количество попыток автобоев',
  620. /* Кнопки */
  621. RUN_SCRIPT: 'Запустить скрипт',
  622. TO_DO_EVERYTHING: 'Сделать все',
  623. TO_DO_EVERYTHING_TITLE: 'Выполнить несколько действий',
  624. OUTLAND: 'Запределье',
  625. OUTLAND_TITLE: 'Собрать Запределье',
  626. TITAN_ARENA: 'Турн.Стихий',
  627. TITAN_ARENA_TITLE: 'Автопрохождение Турнира Стихий',
  628. DUNGEON: 'Подземелье',
  629. DUNGEON_TITLE: 'Автопрохождение подземелья',
  630. SEER: 'Провидец',
  631. SEER_TITLE: 'Покрутить Провидца',
  632. TOWER: 'Башня',
  633. TOWER_TITLE: 'Автопрохождение башни',
  634. EXPEDITIONS: 'Экспедиции',
  635. EXPEDITIONS_TITLE: 'Отправка и сбор экспедиций',
  636. SYNC: 'Синхронизация',
  637. SYNC_TITLE: 'Частичная синхронизация данных игры без перезагрузки сатраницы',
  638. ARCHDEMON: 'Архидемон',
  639. FURNACE_OF_SOULS: 'Горнило душ',
  640. ARCHDEMON_TITLE: 'Набивает килы и собирает награду',
  641. ESTER_EGGS: 'Пасхалки',
  642. ESTER_EGGS_TITLE: 'Собрать все пасхалки или награды',
  643. REWARDS: 'Награды',
  644. REWARDS_TITLE: 'Собрать все награды за задания',
  645. MAIL: 'Почта',
  646. MAIL_TITLE: 'Собрать всю почту, кроме писем с энергией и зарядами портала',
  647. MINIONS: 'Прислужники',
  648. MINIONS_TITLE: 'Атакует прислужников сохраннеными пачками',
  649. ADVENTURE: 'Прикл',
  650. ADVENTURE_TITLE: 'Проходит приключение по указанному маршруту',
  651. STORM: 'Буря',
  652. STORM_TITLE: 'Проходит бурю по указанному маршруту',
  653. SANCTUARY: 'Святилище',
  654. SANCTUARY_TITLE: 'Быстрый переход к Святилищу',
  655. GUILD_WAR: 'Война гильдий',
  656. GUILD_WAR_TITLE: 'Быстрый переход к Войне гильдий',
  657. SECRET_WEALTH: 'Тайное богатство',
  658. SECRET_WEALTH_TITLE: 'Купить что-то в магазине "Тайное богатство"',
  659. /* Разное */
  660. BOTTOM_URLS:
  661. '<a href="https://t.me/+q6gAGCRpwyFkNTYy" target="_blank" title="Telegram"><svg width="20" height="20" style="margin:2px" viewBox="0 0 1e3 1e3" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="a" x1="50%" x2="50%" y2="99.258%"><stop stop-color="#2AABEE" offset="0"/><stop stop-color="#229ED9" offset="1"/></linearGradient></defs><g fill-rule="evenodd"><circle cx="500" cy="500" r="500" fill="url(#a)"/><path d="m226.33 494.72c145.76-63.505 242.96-105.37 291.59-125.6 138.86-57.755 167.71-67.787 186.51-68.119 4.1362-0.072862 13.384 0.95221 19.375 5.8132 5.0584 4.1045 6.4501 9.6491 7.1161 13.541 0.666 3.8915 1.4953 12.756 0.83608 19.683-7.5246 79.062-40.084 270.92-56.648 359.47-7.0089 37.469-20.81 50.032-34.17 51.262-29.036 2.6719-51.085-19.189-79.207-37.624-44.007-28.847-68.867-46.804-111.58-74.953-49.366-32.531-17.364-50.411 10.769-79.631 7.3626-7.6471 135.3-124.01 137.77-134.57 0.30968-1.3202 0.59708-6.2414-2.3265-8.8399s-7.2385-1.7099-10.352-1.0032c-4.4137 1.0017-74.715 47.468-210.9 139.4-19.955 13.702-38.029 20.379-54.223 20.029-17.853-0.3857-52.194-10.094-77.723-18.393-31.313-10.178-56.199-15.56-54.032-32.846 1.1287-9.0037 13.528-18.212 37.197-27.624z" fill="#fff"/></g></svg></a><a href="https://vk.com/invite/YNPxKGX" target="_blank" title="Вконтакте"><svg width="20" height="20" style="margin:2px" viewBox="0 0 101 100" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><path d="M0.5 48C0.5 25.3726 0.5 14.0589 7.52944 7.02944C14.5589 0 25.8726 0 48.5 0H52.5C75.1274 0 86.4411 0 93.4706 7.02944C100.5 14.0589 100.5 25.3726 100.5 48V52C100.5 74.6274 100.5 85.9411 93.4706 92.9706C86.4411 100 75.1274 100 52.5 100H48.5C25.8726 100 14.5589 100 7.52944 92.9706C0.5 85.9411 0.5 74.6274 0.5 52V48Z" fill="#07f"/><path d="m53.708 72.042c-22.792 0-35.792-15.625-36.333-41.625h11.417c0.375 19.083 8.7915 27.167 15.458 28.833v-28.833h10.75v16.458c6.5833-0.7083 13.499-8.2082 15.832-16.458h10.75c-1.7917 10.167-9.2917 17.667-14.625 20.75 5.3333 2.5 13.875 9.0417 17.125 20.875h-11.834c-2.5417-7.9167-8.8745-14.042-17.25-14.875v14.875h-1.2919z" fill="#fff"/></g><defs><clipPath id="a"><rect transform="translate(.5)" width="100" height="100" fill="#fff"/></clipPath></defs></svg></a>',
  662. GIFTS_SENT: 'Подарки отправлены!',
  663. DO_YOU_WANT: 'Вы действительно хотите это сделать?',
  664. BTN_RUN: 'Запускай',
  665. BTN_CANCEL: 'Отмена',
  666. BTN_ACCEPT: 'Принять',
  667. BTN_OK: 'Ок',
  668. MSG_HAVE_BEEN_DEFEATED: 'Вы потерпели поражение!',
  669. BTN_AUTO: 'Авто',
  670. MSG_YOU_APPLIED: 'Вы нанесли',
  671. MSG_DAMAGE: 'урона',
  672. MSG_CANCEL_AND_STAT: 'Авто (F5) и показать Статистику',
  673. MSG_REPEAT_MISSION: 'Повторить миссию?',
  674. BTN_REPEAT: 'Повторить',
  675. BTN_NO: 'Нет',
  676. MSG_SPECIFY_QUANT: 'Указать количество:',
  677. BTN_OPEN: 'Открыть',
  678. QUESTION_COPY: 'Вопрос скопирован в буфер обмена',
  679. ANSWER_KNOWN: 'Ответ известен',
  680. ANSWER_NOT_KNOWN: 'ВНИМАНИЕ ОТВЕТ НЕ ИЗВЕСТЕН',
  681. BEING_RECALC: 'Идет прерасчет боя',
  682. THIS_TIME: 'На этот раз',
  683. VICTORY: '<span style="color:green;">ПОБЕДА</span>',
  684. DEFEAT: '<span style="color:red;">ПОРАЖЕНИЕ</span>',
  685. CHANCE_TO_WIN: 'Шансы на победу <span style="color:red;">на основе прерасчета</span>',
  686. OPEN_DOLLS: 'матрешек рекурсивно',
  687. SENT_QUESTION: 'Вопрос отправлен',
  688. SETTINGS: 'Настройки',
  689. MSG_BAN_ATTENTION: '<p style="color:red;">Использование этой функции может привести к бану.</p> Продолжить?',
  690. BTN_YES_I_AGREE: 'Да, я беру на себя все риски!',
  691. BTN_NO_I_AM_AGAINST: 'Нет, я отказываюсь от этого!',
  692. VALUES: 'Значения',
  693. EXPEDITIONS_SENT: 'Экспедиции:<br>Собрано: {countGet}<br>Отправлено: {countSend}',
  694. EXPEDITIONS_NOTHING: 'Нечего собирать/отправлять',
  695. EXPEDITIONS_NOTTIME: 'Не время для экспедиций',
  696. TITANIT: 'Титанит',
  697. COMPLETED: 'завершено',
  698. FLOOR: 'Этаж',
  699. LEVEL: 'Уровень',
  700. BATTLES: 'бои',
  701. EVENT: 'Эвент',
  702. NOT_AVAILABLE: 'недоступен',
  703. NO_HEROES: 'Нет героев',
  704. DAMAGE_AMOUNT: 'Количество урона',
  705. NOTHING_TO_COLLECT: 'Нечего собирать',
  706. COLLECTED: 'Собрано',
  707. REWARD: 'наград',
  708. REMAINING_ATTEMPTS: 'Осталось попыток',
  709. BATTLES_CANCELED: 'Битв отменено',
  710. MINION_RAID: 'Рейд прислужников',
  711. STOPPED: 'Остановлено',
  712. REPETITIONS: 'Повторений',
  713. MISSIONS_PASSED: 'Миссий пройдено',
  714. STOP: 'остановить',
  715. TOTAL_OPEN: 'Всего открыто',
  716. OPEN: 'Открыто',
  717. ROUND_STAT: 'Статистика урона за',
  718. BATTLE: 'боев',
  719. MINIMUM: 'Минимальный',
  720. MAXIMUM: 'Максимальный',
  721. AVERAGE: 'Средний',
  722. NOT_THIS_TIME: 'Не в этот раз',
  723. RETRY_LIMIT_EXCEEDED: 'Превышен лимит попыток',
  724. SUCCESS: 'Успех',
  725. RECEIVED: 'Получено',
  726. LETTERS: 'писем',
  727. PORTALS: 'порталов',
  728. ATTEMPTS: 'попыток',
  729. QUEST_10001: 'Улучши умения героев 3 раза',
  730. QUEST_10002: 'Пройди 10 миссий',
  731. QUEST_10003: 'Пройди 3 героические миссии',
  732. QUEST_10004: 'Сразись 3 раза на Арене или Гранд Арене',
  733. QUEST_10006: 'Используй обмен изумрудов 1 раз',
  734. QUEST_10007: 'Соверши 1 призыв в Атриуме Душ',
  735. QUEST_10016: 'Отправь подарки согильдийцам',
  736. QUEST_10018: 'Используй зелье опыта',
  737. QUEST_10019: 'Открой 1 сундук в Башне',
  738. QUEST_10020: 'Открой 3 сундука в Запределье',
  739. QUEST_10021: 'Собери 75 Титанита в Подземелье Гильдии',
  740. QUEST_10021: 'Собери 150 Титанита в Подземелье Гильдии',
  741. QUEST_10023: 'Прокачай Дар Стихий на 1 уровень',
  742. QUEST_10024: 'Повысь уровень любого артефакта один раз',
  743. QUEST_10025: 'Начни 1 Экспедицию',
  744. QUEST_10026: 'Начни 4 Экспедиции',
  745. QUEST_10027: 'Победи в 1 бою Турнира Стихий',
  746. QUEST_10028: 'Повысь уровень любого артефакта титанов',
  747. QUEST_10029: 'Открой сферу артефактов титанов',
  748. QUEST_10030: 'Улучши облик любого героя 1 раз',
  749. QUEST_10031: 'Победи в 6 боях Турнира Стихий',
  750. QUEST_10043: 'Начни или присоеденись к Приключению',
  751. QUEST_10044: 'Воспользуйся призывом питомцев 1 раз',
  752. QUEST_10046: 'Открой 3 сундука в Приключениях',
  753. QUEST_10047: 'Набери 150 очков активности в Гильдии',
  754. NOTHING_TO_DO: 'Нечего выполнять',
  755. YOU_CAN_COMPLETE: 'Можно выполнить квесты',
  756. BTN_DO_IT: 'Выполняй',
  757. NOT_QUEST_COMPLETED: 'Ни одного квеста не выполенно',
  758. COMPLETED_QUESTS: 'Выполнено квестов',
  759. /* everything button */
  760. ASSEMBLE_OUTLAND: 'Собрать Запределье',
  761. PASS_THE_TOWER: 'Пройти башню',
  762. CHECK_EXPEDITIONS: 'Проверить экспедиции',
  763. COMPLETE_TOE: 'Пройти Турнир Стихий',
  764. COMPLETE_DUNGEON: 'Пройти подземелье',
  765. COLLECT_MAIL: 'Собрать почту',
  766. COLLECT_MISC: 'Собрать всякую херню',
  767. COLLECT_MISC_TITLE: 'Собрать пасхалки, камни облика, ключи, монеты арены и Хрусталь души',
  768. COLLECT_QUEST_REWARDS: 'Собрать награды за квесты',
  769. MAKE_A_SYNC: 'Сделать синхронизацию',
  770.  
  771. RUN_FUNCTION: 'Выполнить следующие функции?',
  772. BTN_GO: 'Погнали!',
  773. PERFORMED: 'Выполняется',
  774. DONE: 'Выполнено',
  775. ERRORS_OCCURRES: 'Призошли ошибки при выполнении',
  776. COPY_ERROR: 'Скопировать в буфер информацию об ошибке',
  777. BTN_YES: 'Да',
  778. ALL_TASK_COMPLETED: 'Все задачи выполнены',
  779.  
  780. UNKNOWN: 'Неизвестно',
  781. ENTER_THE_PATH: 'Введите путь приключения через запятые или дефисы',
  782. START_ADVENTURE: 'Начать приключение по этому пути!',
  783. INCORRECT_WAY: 'Неверный путь в приключении: {from} -> {to}',
  784. BTN_CANCELED: 'Отменено',
  785. MUST_TWO_POINTS: 'Путь должен состоять минимум из 2х точек',
  786. MUST_ONLY_NUMBERS: 'Путь должен содержать только цифры и запятые',
  787. NOT_ON_AN_ADVENTURE: 'Вы не в приключении',
  788. YOU_IN_NOT_ON_THE_WAY: 'Указанный путь должен включать точку вашего положения',
  789. ATTEMPTS_NOT_ENOUGH: 'Ваших попыток не достаточно для завершения пути, продолжить?',
  790. YES_CONTINUE: 'Да, продолжай!',
  791. NOT_ENOUGH_AP: 'Попыток не достаточно',
  792. ATTEMPTS_ARE_OVER: 'Попытки закончились',
  793. MOVES: 'Ходы',
  794. BUFF_GET_ERROR: 'Ошибка при получении бафа',
  795. BATTLE_END_ERROR: 'Ошибка завершения боя',
  796. AUTOBOT: 'АвтоБой',
  797. FAILED_TO_WIN_AUTO: 'Не удалось победить в автобою',
  798. ERROR_OF_THE_BATTLE_COPY: 'Призошли ошибка в процессе прохождения боя<br>Скопировать ошибку в буфер обмена?',
  799. ERROR_DURING_THE_BATTLE: 'Ошибка в процессе прохождения боя',
  800. NO_CHANCE_WIN: 'Нет шансов победить в этом бою: 0/',
  801. LOST_HEROES: 'Вы победили, но потеряли одного или несколько героев!',
  802. VICTORY_IMPOSSIBLE: 'Победа не возможна, бъем на результат?',
  803. FIND_COEFF: 'Поиск коэффициента больше чем',
  804. BTN_PASS: 'ПРОПУСК',
  805. BRAWLS: 'Потасовки',
  806. BRAWLS_TITLE: 'Включает возможность автопотасовок',
  807. START_AUTO_BRAWLS: 'Запустить Автопотасовки?',
  808. LOSSES: 'Поражений',
  809. WINS: 'Побед',
  810. FIGHTS: 'Боев',
  811. STAGE: 'Стадия',
  812. DONT_HAVE_LIVES: 'У Вас нет жизней',
  813. LIVES: 'Жизни',
  814. SECRET_WEALTH_ALREADY: 'товар за Зелья питомцев уже куплен',
  815. SECRET_WEALTH_NOT_ENOUGH: 'Не достаточно Зелье Питомца, у Вас {available}, нужно {need}',
  816. SECRET_WEALTH_UPGRADE_NEW_PET: 'После покупки Зелье Питомца будет не достаточно для прокачки нового питомца',
  817. SECRET_WEALTH_PURCHASED: 'Куплено {count} {name}',
  818. SECRET_WEALTH_CANCELED: 'Тайное богатство: покупка отменена',
  819. SECRET_WEALTH_BUY: 'У вас {available} Зелье Питомца.<br>Вы хотите купить {countBuy} {name} за {price} Зелье Питомца?',
  820. DAILY_BONUS: 'Ежедневная награда',
  821. DO_DAILY_QUESTS: 'Сделать ежедневные квесты',
  822. ACTIONS: 'Действия',
  823. ACTIONS_TITLE: 'Диалоговое окно с различными действиями',
  824. OTHERS: 'Разное',
  825. OTHERS_TITLE: 'Диалоговое окно с дополнительными различными действиями',
  826. CHOOSE_ACTION: 'Выберите действие',
  827. OPEN_LOOTBOX: 'У Вас {lootBox} ящиков, откываем?',
  828. STAMINA: 'Энергия',
  829. BOXES_OVER: 'Ящики закончились',
  830. NO_BOXES: 'Нет ящиков',
  831. NO_MORE_ACTIVITY: 'Больше активности за предметы сегодня не получить',
  832. EXCHANGE_ITEMS: 'Обменять предметы на очки активности (не более {maxActive})?',
  833. GET_ACTIVITY: 'Получить активность',
  834. NOT_ENOUGH_ITEMS: 'Предметов недостаточно',
  835. ACTIVITY_RECEIVED: 'Получено активности',
  836. NO_PURCHASABLE_HERO_SOULS: 'Нет доступных для покупки душ героев',
  837. PURCHASED_HERO_SOULS: 'Куплено {countHeroSouls} душ героев',
  838. NOT_ENOUGH_EMERALDS_540: 'Недостаточно изюма, нужно {imgEmerald}540 у Вас {imgEmerald}{currentStarMoney}',
  839. BUY_OUTLAND_BTN: 'Купить {count} сундуков {imgEmerald}{countEmerald}',
  840. CHESTS_NOT_AVAILABLE: 'Сундуки не доступны',
  841. OUTLAND_CHESTS_RECEIVED: 'Получено сундуков Запределья',
  842. RAID_NOT_AVAILABLE: 'Рейд не доступен или сфер нет',
  843. RAID_ADVENTURE: 'Рейд {adventureId} приключения!',
  844. SOMETHING_WENT_WRONG: 'Что-то пошло не так',
  845. ADVENTURE_COMPLETED: 'Приключение {adventureId} пройдено {times} раз',
  846. CLAN_STAT_COPY: 'Клановая статистика скопирована в буфер обмена',
  847. GET_ENERGY: 'Получить энергию',
  848. GET_ENERGY_TITLE: 'Открывает платиновые шкатулки по одной до получения 250 энергии',
  849. ITEM_EXCHANGE: 'Обмен предметов',
  850. ITEM_EXCHANGE_TITLE: 'Обменивает предметы на указанное количество активности',
  851. BUY_SOULS: 'Купить души',
  852. BUY_SOULS_TITLE: 'Купить души героев из всех доступных магазинов',
  853. BUY_OUTLAND: 'Купить Запределье',
  854. BUY_OUTLAND_TITLE: 'Купить 9 сундуков в Запределье за 540 изумрудов',
  855. RAID: 'Рейд',
  856. AUTO_RAID_ADVENTURE: 'Рейд',
  857. AUTO_RAID_ADVENTURE_TITLE: 'Рейд приключения заданное количество раз',
  858. CLAN_STAT: 'Клановая статистика',
  859. CLAN_STAT_TITLE: 'Копирует клановую статистику в буфер обмена',
  860. BTN_AUTO_F5: 'Авто (F5)',
  861. BOSS_DAMAGE: 'Урон по боссу: ',
  862. NOTHING_BUY: 'Нечего покупать',
  863. LOTS_BOUGHT: 'За золото куплено {countBuy} лотов',
  864. BUY_FOR_GOLD: 'Скупить за золото',
  865. BUY_FOR_GOLD_TITLE: 'Скупить предметы за золото в Городской лавке и в магазине Камней Душ Питомцев',
  866. REWARDS_AND_MAIL: 'Награды и почта',
  867. REWARDS_AND_MAIL_TITLE: 'Собирает награды и почту',
  868. COLLECT_REWARDS_AND_MAIL: 'Собрано {countQuests} наград и {countMail} писем',
  869. TIMER_ALREADY: 'Таймер уже запущен {time}',
  870. NO_ATTEMPTS_TIMER_START: 'Попыток нет, запущен таймер {time}',
  871. EPIC_BRAWL_RESULT: '{i} Победы: {wins}/{attempts}, Монеты: {coins}, Серия: {progress}/{nextStage} [Закрыть]{end}',
  872. ATTEMPT_ENDED: '<br>Попытки закончились, запущен таймер {time}',
  873. EPIC_BRAWL: 'Вселенская битва',
  874. EPIC_BRAWL_TITLE: 'Тратит попытки во Вселенской битве',
  875. RELOAD_GAME: 'Перезагрузить игру',
  876. TIMER: 'Таймер:',
  877. SHOW_ERRORS: 'Отображать ошибки',
  878. SHOW_ERRORS_TITLE: 'Отображать ошибки запросов к серверу',
  879. ERROR_MSG: 'Ошибка: {name}<br>{description}',
  880. EVENT_AUTO_BOSS:
  881. 'Максимальное количество боев для расчета:</br>{length} * {countTestBattle} = {maxCalcBattle}</br>Если у Вас слабый компьютер на это может потребоваться много времени, нажмите крестик для отмены.</br>Искать лучший пак из всех или первый подходящий?',
  882. BEST_SLOW: 'Лучший (медленее)',
  883. FIRST_FAST: 'Первый (быстрее)',
  884. FREEZE_INTERFACE: 'Идет расчет... <br> Интерфейс может зависнуть.',
  885. ERROR_F12: 'Ошибка, подробности в консоли (F12)',
  886. FAILED_FIND_WIN_PACK: 'Победный пак найти не удалось',
  887. BEST_PACK: 'Наилучший пак: ',
  888. BOSS_HAS_BEEN_DEF: 'Босс {bossLvl} побежден',
  889. NOT_ENOUGH_ATTEMPTS_BOSS: 'Для победы босса ${bossLvl} не хватило попыток, повторить?',
  890. BOSS_VICTORY_IMPOSSIBLE:
  891. 'По результатам прерасчета {battles} боев победу получить не удалось. Вы хотите продолжить поиск победного боя на реальных боях?',
  892. BOSS_HAS_BEEN_DEF_TEXT:
  893. 'Босс {bossLvl} побежден за<br>{countBattle}/{countMaxBattle} попыток{winTimer}<br>(Сделайте синхронизацию или перезагрузите игру для обновления данных)',
  894. MAP: 'Карта: ',
  895. PLAYER_POS: 'Позиции игроков:',
  896. NY_GIFTS: 'Подарки',
  897. NY_GIFTS_TITLE: 'Открыть все новогодние подарки',
  898. NY_NO_GIFTS: 'Нет не полученных подарков',
  899. NY_GIFTS_COLLECTED: 'Собрано {count} подарков',
  900. CHANGE_MAP: 'Карта острова',
  901. CHANGE_MAP_TITLE: 'Сменить карту острова',
  902. SELECT_ISLAND_MAP: 'Выберите карту острова:',
  903. MAP_NUM: 'Карта {num}',
  904. SECRET_WEALTH_SHOP: 'Тайное богатство {name}: ',
  905. SHOPS: 'Магазины',
  906. SHOPS_DEFAULT: 'Стандартные',
  907. SHOPS_DEFAULT_TITLE: 'Стандартные магазины',
  908. SHOPS_LIST: 'Магазины {number}',
  909. SHOPS_LIST_TITLE: 'Список магазинов {number}',
  910. SHOPS_WARNING:
  911. 'Магазины<br><span style="color:red">Если Вы купите монеты магазинов потасовок за изумруды, то их надо использовать сразу, иначе после перезагрузки игры они пропадут!</span>',
  912. MINIONS_WARNING: 'Пачки героев для атаки приспешников неполные, продолжить?',
  913. FAST_SEASON: 'Быстрый сезон',
  914. FAST_SEASON_TITLE: 'Пропуск экрана с выбором карты в сезоне',
  915. SET_NUMBER_LEVELS: 'Указать колличество уровней:',
  916. POSSIBLE_IMPROVE_LEVELS: 'Возможно улучшить только {count} уровней.<br>Улучшаем?',
  917. NOT_ENOUGH_RESOURECES: 'Не хватает ресурсов',
  918. IMPROVED_LEVELS: 'Улучшено уровней: {count}',
  919. ARTIFACTS_UPGRADE: 'Улучшение артефактов',
  920. ARTIFACTS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых артефактов героев',
  921. SKINS_UPGRADE: 'Улучшение обликов',
  922. SKINS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых обликов героев',
  923. HINT: '<br>Подсказка: ',
  924. PICTURE: '<br>На картинке: ',
  925. ANSWER: '<br>Ответ: ',
  926. NO_HEROES_PACK: 'Проведите хотя бы один бой для сохранения атакующей команды',
  927. BRAWL_AUTO_PACK: 'Автоподбор пачки',
  928. BRAWL_AUTO_PACK_NOT_CUR_HERO: 'Автоматический подбор пачки не подходит для текущего героя',
  929. BRAWL_DAILY_TASK_COMPLETED: 'Ежедневное задание выполнено, продолжить атаку?',
  930. CALC_STAT: 'Посчитать статистику',
  931. ELEMENT_TOURNAMENT_REWARD: 'Несобранная награда за Турнир Стихий',
  932. BTN_TRY_FIX_IT: 'Исправить',
  933. BTN_TRY_FIX_IT_TITLE: 'Включить исправление боев при автоатаке',
  934. DAMAGE_FIXED: 'Урон исправлен с {lastDamage} до {maxDamage}!',
  935. DAMAGE_NO_FIXED: 'Не удалось исправить урон: {lastDamage}',
  936. LETS_FIX: 'Исправляем',
  937. COUNT_FIXED: 'За {count} попыток',
  938. DEFEAT_TURN_TIMER: 'Поражение! Включить таймер для завершения миссии?',
  939. SEASON_REWARD: 'Награды сезонов',
  940. SEASON_REWARD_TITLE: 'Собирает доступные бесплатные награды со всех текущих сезонов',
  941. SEASON_REWARD_COLLECTED: 'Собрано {count} наград сезонов',
  942. SELL_HERO_SOULS: 'Продать души',
  943. SELL_HERO_SOULS_TITLE: 'Обменивает все души героев с абсолютной звездой на золото',
  944. GOLD_RECEIVED: 'Получено золота: {gold}',
  945. OPEN_ALL_EQUIP_BOXES: 'Открыть все ящики фрагментов экипировки?',
  946. SERVER_NOT_ACCEPT: 'Сервер не принял результат',
  947. INVASION_BOSS_BUFF: 'Для {bossLvl} босса нужен баф {needBuff} у вас {haveBuff}',
  948. HERO_POWER: 'Сила героев',
  949. HERO_POWER_TITLE: 'Отображает текущую и максимальную силу героев',
  950. MAX_POWER_REACHED: 'Максимальная достигнутая мощь: {power}',
  951. CURRENT_POWER: 'Текущая мощь: {power}',
  952. POWER_TO_MAX: 'До максимума мощи осталось: <span style="color:{color};">{power}</span><br>',
  953. BEST_RESULT: 'Лучший результат: {value}%',
  954. GUILD_ISLAND_TITLE: 'Перейти к Острову гильдии',
  955. TITAN_VALLEY_TITLE: 'Перейти к Долине титанов',
  956. },
  957. };
  958.  
  959. function getLang() {
  960. let lang = '';
  961. if (typeof NXFlashVars !== 'undefined') {
  962. lang = NXFlashVars.interface_lang
  963. }
  964. if (!lang) {
  965. lang = (navigator.language || navigator.userLanguage).substr(0, 2);
  966. }
  967. const { i18nLangData } = HWHData;
  968. if (i18nLangData[lang]) {
  969. return lang;
  970. }
  971. return 'en';
  972. }
  973.  
  974. this.I18N = function (constant, replace) {
  975. const { i18nLangData } = HWHData;
  976. const selectLang = getLang();
  977. if (constant && constant in i18nLangData[selectLang]) {
  978. const result = i18nLangData[selectLang][constant];
  979. if (replace) {
  980. return result.sprintf(replace);
  981. }
  982. return result;
  983. }
  984. console.warn('Language constant not found', {constant, replace});
  985. if (i18nLangData['en'][constant]) {
  986. const result = i18nLangData[selectLang][constant];
  987. if (replace) {
  988. return result.sprintf(replace);
  989. }
  990. return result;
  991. }
  992. return `% ${constant} %`;
  993. };
  994.  
  995. String.prototype.sprintf = String.prototype.sprintf ||
  996. function () {
  997. "use strict";
  998. var str = this.toString();
  999. if (arguments.length) {
  1000. var t = typeof arguments[0];
  1001. var key;
  1002. var args = ("string" === t || "number" === t) ?
  1003. Array.prototype.slice.call(arguments)
  1004. : arguments[0];
  1005.  
  1006. for (key in args) {
  1007. str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
  1008. }
  1009. }
  1010.  
  1011. return str;
  1012. };
  1013.  
  1014. /**
  1015. * Checkboxes
  1016. *
  1017. * Чекбоксы
  1018. */
  1019. const checkboxes = {
  1020. passBattle: {
  1021. get label() { return I18N('SKIP_FIGHTS'); },
  1022. cbox: null,
  1023. get title() { return I18N('SKIP_FIGHTS_TITLE'); },
  1024. default: false,
  1025. },
  1026. sendExpedition: {
  1027. get label() { return I18N('AUTO_EXPEDITION'); },
  1028. cbox: null,
  1029. get title() { return I18N('AUTO_EXPEDITION_TITLE'); },
  1030. default: false,
  1031. },
  1032. cancelBattle: {
  1033. get label() { return I18N('CANCEL_FIGHT'); },
  1034. cbox: null,
  1035. get title() { return I18N('CANCEL_FIGHT_TITLE'); },
  1036. default: false,
  1037. },
  1038. preCalcBattle: {
  1039. get label() { return I18N('BATTLE_RECALCULATION'); },
  1040. cbox: null,
  1041. get title() { return I18N('BATTLE_RECALCULATION_TITLE'); },
  1042. default: false,
  1043. },
  1044. countControl: {
  1045. get label() { return I18N('QUANTITY_CONTROL'); },
  1046. cbox: null,
  1047. get title() { return I18N('QUANTITY_CONTROL_TITLE'); },
  1048. default: true,
  1049. },
  1050. repeatMission: {
  1051. get label() { return I18N('REPEAT_CAMPAIGN'); },
  1052. cbox: null,
  1053. get title() { return I18N('REPEAT_CAMPAIGN_TITLE'); },
  1054. default: false,
  1055. },
  1056. noOfferDonat: {
  1057. get label() { return I18N('DISABLE_DONAT'); },
  1058. cbox: null,
  1059. get title() { return I18N('DISABLE_DONAT_TITLE'); },
  1060. /**
  1061. * A crutch to get the field before getting the character id
  1062. *
  1063. * Костыль чтоб получать поле до получения id персонажа
  1064. */
  1065. default: (() => {
  1066. $result = false;
  1067. try {
  1068. $result = JSON.parse(localStorage[GM_info.script.name + ':noOfferDonat']);
  1069. } catch (e) {
  1070. $result = false;
  1071. }
  1072. return $result || false;
  1073. })(),
  1074. },
  1075. dailyQuests: {
  1076. get label() { return I18N('DAILY_QUESTS'); },
  1077. cbox: null,
  1078. get title() { return I18N('DAILY_QUESTS_TITLE'); },
  1079. default: false,
  1080. },
  1081. // Потасовки
  1082. autoBrawls: {
  1083. get label() { return I18N('BRAWLS'); },
  1084. cbox: null,
  1085. get title() { return I18N('BRAWLS_TITLE'); },
  1086. default: (() => {
  1087. $result = false;
  1088. try {
  1089. $result = JSON.parse(localStorage[GM_info.script.name + ':autoBrawls']);
  1090. } catch (e) {
  1091. $result = false;
  1092. }
  1093. return $result || false;
  1094. })(),
  1095. hide: false,
  1096. },
  1097. getAnswer: {
  1098. get label() { return I18N('AUTO_QUIZ'); },
  1099. cbox: null,
  1100. get title() { return I18N('AUTO_QUIZ_TITLE'); },
  1101. default: false,
  1102. hide: false,
  1103. },
  1104. tryFixIt_v2: {
  1105. get label() { return I18N('BTN_TRY_FIX_IT'); },
  1106. cbox: null,
  1107. get title() { return I18N('BTN_TRY_FIX_IT_TITLE'); },
  1108. default: false,
  1109. hide: false,
  1110. },
  1111. showErrors: {
  1112. get label() { return I18N('SHOW_ERRORS'); },
  1113. cbox: null,
  1114. get title() { return I18N('SHOW_ERRORS_TITLE'); },
  1115. default: true,
  1116. },
  1117. buyForGold: {
  1118. get label() { return I18N('BUY_FOR_GOLD'); },
  1119. cbox: null,
  1120. get title() { return I18N('BUY_FOR_GOLD_TITLE'); },
  1121. default: false,
  1122. },
  1123. hideServers: {
  1124. get label() { return I18N('HIDE_SERVERS'); },
  1125. cbox: null,
  1126. get title() { return I18N('HIDE_SERVERS_TITLE'); },
  1127. default: false,
  1128. },
  1129. fastSeason: {
  1130. get label() { return I18N('FAST_SEASON'); },
  1131. cbox: null,
  1132. get title() { return I18N('FAST_SEASON_TITLE'); },
  1133. default: false,
  1134. },
  1135. };
  1136. /**
  1137. * Get checkbox state
  1138. *
  1139. * Получить состояние чекбокса
  1140. */
  1141. function isChecked(checkBox) {
  1142. const { checkboxes } = HWHData;
  1143. if (!(checkBox in checkboxes)) {
  1144. return false;
  1145. }
  1146. return checkboxes[checkBox].cbox?.checked;
  1147. }
  1148. /**
  1149. * Input fields
  1150. *
  1151. * Поля ввода
  1152. */
  1153. const inputs = {
  1154. countTitanit: {
  1155. input: null,
  1156. get title() { return I18N('HOW_MUCH_TITANITE'); },
  1157. default: 150,
  1158. },
  1159. speedBattle: {
  1160. input: null,
  1161. get title() { return I18N('COMBAT_SPEED'); },
  1162. default: 5,
  1163. },
  1164. countTestBattle: {
  1165. input: null,
  1166. get title() { return I18N('NUMBER_OF_TEST'); },
  1167. default: 10,
  1168. },
  1169. countAutoBattle: {
  1170. input: null,
  1171. get title() { return I18N('NUMBER_OF_AUTO_BATTLE'); },
  1172. default: 10,
  1173. },
  1174. FPS: {
  1175. input: null,
  1176. title: 'FPS',
  1177. default: 60,
  1178. }
  1179. }
  1180. /**
  1181. * Checks the checkbox
  1182. *
  1183. * Поплучить данные поля ввода
  1184. */
  1185. function getInput(inputName) {
  1186. const { inputs } = HWHData;
  1187. return inputs[inputName]?.input?.value;
  1188. }
  1189.  
  1190. /**
  1191. * Control FPS
  1192. *
  1193. * Контроль FPS
  1194. */
  1195. let nextAnimationFrame = Date.now();
  1196. const oldRequestAnimationFrame = this.requestAnimationFrame;
  1197. this.requestAnimationFrame = async function (e) {
  1198. const FPS = Number(getInput('FPS')) || -1;
  1199. const now = Date.now();
  1200. const delay = nextAnimationFrame - now;
  1201. nextAnimationFrame = Math.max(now, nextAnimationFrame) + Math.min(1e3 / FPS, 1e3);
  1202. if (delay > 0) {
  1203. await new Promise((e) => setTimeout(e, delay));
  1204. }
  1205. oldRequestAnimationFrame(e);
  1206. };
  1207. /**
  1208. * Button List
  1209. *
  1210. * Список кнопочек
  1211. */
  1212. const buttons = {
  1213. getOutland: {
  1214. get name() { return I18N('TO_DO_EVERYTHING'); },
  1215. get title() { return I18N('TO_DO_EVERYTHING_TITLE'); },
  1216. onClick: testDoYourBest,
  1217. },
  1218. doActions: {
  1219. get name() { return I18N('ACTIONS'); },
  1220. get title() { return I18N('ACTIONS_TITLE'); },
  1221. onClick: async function () {
  1222. const popupButtons = [
  1223. {
  1224. msg: I18N('OUTLAND'),
  1225. result: function () {
  1226. confShow(`${I18N('RUN_SCRIPT')} ${I18N('OUTLAND')}?`, getOutland);
  1227. },
  1228. get title() { return I18N('OUTLAND_TITLE'); },
  1229. },
  1230. {
  1231. msg: I18N('TOWER'),
  1232. result: function () {
  1233. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TOWER')}?`, testTower);
  1234. },
  1235. get title() { return I18N('TOWER_TITLE'); },
  1236. },
  1237. {
  1238. msg: I18N('EXPEDITIONS'),
  1239. result: function () {
  1240. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EXPEDITIONS')}?`, checkExpedition);
  1241. },
  1242. get title() { return I18N('EXPEDITIONS_TITLE'); },
  1243. },
  1244. {
  1245. msg: I18N('MINIONS'),
  1246. result: function () {
  1247. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MINIONS')}?`, testRaidNodes);
  1248. },
  1249. get title() { return I18N('MINIONS_TITLE'); },
  1250. },
  1251. {
  1252. msg: I18N('ESTER_EGGS'),
  1253. result: function () {
  1254. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ESTER_EGGS')}?`, offerFarmAllReward);
  1255. },
  1256. get title() { return I18N('ESTER_EGGS_TITLE'); },
  1257. },
  1258. {
  1259. msg: I18N('STORM'),
  1260. result: function () {
  1261. testAdventure('solo');
  1262. },
  1263. get title() { return I18N('STORM_TITLE'); },
  1264. },
  1265. {
  1266. msg: I18N('REWARDS'),
  1267. result: function () {
  1268. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS')}?`, questAllFarm);
  1269. },
  1270. get title() { return I18N('REWARDS_TITLE'); },
  1271. },
  1272. {
  1273. msg: I18N('MAIL'),
  1274. result: function () {
  1275. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MAIL')}?`, mailGetAll);
  1276. },
  1277. get title() { return I18N('MAIL_TITLE'); },
  1278. },
  1279. {
  1280. msg: I18N('SEER'),
  1281. result: function () {
  1282. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SEER')}?`, rollAscension);
  1283. },
  1284. get title() { return I18N('SEER_TITLE'); },
  1285. },
  1286. /*
  1287. {
  1288. msg: I18N('NY_GIFTS'),
  1289. result: getGiftNewYear,
  1290. get title() { return I18N('NY_GIFTS_TITLE'); },
  1291. },
  1292. */
  1293. ];
  1294. popupButtons.push({ result: false, isClose: true });
  1295. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1296. if (typeof answer === 'function') {
  1297. answer();
  1298. }
  1299. },
  1300. },
  1301. doOthers: {
  1302. get name() { return I18N('OTHERS'); },
  1303. get title() { return I18N('OTHERS_TITLE'); },
  1304. onClick: async function () {
  1305. const popupButtons = [
  1306. {
  1307. msg: I18N('GET_ENERGY'),
  1308. result: farmStamina,
  1309. get title() { return I18N('GET_ENERGY_TITLE'); },
  1310. },
  1311. {
  1312. msg: I18N('ITEM_EXCHANGE'),
  1313. result: fillActive,
  1314. get title() { return I18N('ITEM_EXCHANGE_TITLE'); },
  1315. },
  1316. {
  1317. msg: I18N('BUY_SOULS'),
  1318. result: function () {
  1319. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_SOULS')}?`, buyHeroFragments);
  1320. },
  1321. get title() { return I18N('BUY_SOULS_TITLE'); },
  1322. },
  1323. {
  1324. msg: I18N('BUY_FOR_GOLD'),
  1325. result: function () {
  1326. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_FOR_GOLD')}?`, buyInStoreForGold);
  1327. },
  1328. get title() { return I18N('BUY_FOR_GOLD_TITLE'); },
  1329. },
  1330. {
  1331. msg: I18N('BUY_OUTLAND'),
  1332. result: bossOpenChestPay,
  1333. get title() { return I18N('BUY_OUTLAND_TITLE'); },
  1334. },
  1335. {
  1336. msg: I18N('CLAN_STAT'),
  1337. result: clanStatistic,
  1338. get title() { return I18N('CLAN_STAT_TITLE'); },
  1339. },
  1340. {
  1341. msg: I18N('EPIC_BRAWL'),
  1342. result: async function () {
  1343. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EPIC_BRAWL')}?`, () => {
  1344. const brawl = new epicBrawl();
  1345. brawl.start();
  1346. });
  1347. },
  1348. get title() { return I18N('EPIC_BRAWL_TITLE'); },
  1349. },
  1350. {
  1351. msg: I18N('ARTIFACTS_UPGRADE'),
  1352. result: updateArtifacts,
  1353. get title() { return I18N('ARTIFACTS_UPGRADE_TITLE'); },
  1354. },
  1355. {
  1356. msg: I18N('SKINS_UPGRADE'),
  1357. result: updateSkins,
  1358. get title() { return I18N('SKINS_UPGRADE_TITLE'); },
  1359. },
  1360. {
  1361. msg: I18N('SEASON_REWARD'),
  1362. result: farmBattlePass,
  1363. get title() { return I18N('SEASON_REWARD_TITLE'); },
  1364. },
  1365. {
  1366. msg: I18N('SELL_HERO_SOULS'),
  1367. result: sellHeroSoulsForGold,
  1368. get title() { return I18N('SELL_HERO_SOULS_TITLE'); },
  1369. },
  1370. {
  1371. msg: I18N('CHANGE_MAP'),
  1372. result: async function () {
  1373. const maps = Object.values(lib.data.seasonAdventure.list)
  1374. .filter((e) => e.map.cells.length > 2)
  1375. .map((i) => ({
  1376. msg: I18N('MAP_NUM', { num: i.id }),
  1377. result: i.id,
  1378. }));
  1379.  
  1380. const result = await popup.confirm(I18N('SELECT_ISLAND_MAP'), [...maps, { result: false, isClose: true }]);
  1381. if (result) {
  1382. cheats.changeIslandMap(result);
  1383. }
  1384. },
  1385. get title() { return I18N('CHANGE_MAP_TITLE'); },
  1386. },
  1387. {
  1388. msg: I18N('HERO_POWER'),
  1389. result: async () => {
  1390. const calls = ['userGetInfo', 'heroGetAll'].map((name) => ({
  1391. name,
  1392. args: {},
  1393. ident: name,
  1394. }));
  1395. const [maxHeroSumPower, heroSumPower] = await Send({ calls }).then((e) => [
  1396. e.results[0].result.response.maxSumPower.heroes,
  1397. Object.values(e.results[1].result.response).reduce((a, e) => a + e.power, 0),
  1398. ]);
  1399. const power = maxHeroSumPower - heroSumPower;
  1400. let msg =
  1401. I18N('MAX_POWER_REACHED', { power: maxHeroSumPower.toLocaleString() }) +
  1402. '<br>' +
  1403. I18N('CURRENT_POWER', { power: heroSumPower.toLocaleString() }) +
  1404. '<br>' +
  1405. I18N('POWER_TO_MAX', { power: power.toLocaleString(), color: power >= 4000 ? 'green' : 'red' });
  1406. await popup.confirm(msg, [{ msg: I18N('BTN_OK'), result: 0 }]);
  1407. },
  1408. get title() { return I18N('HERO_POWER_TITLE'); },
  1409. },
  1410. ];
  1411. popupButtons.push({ result: false, isClose: true });
  1412. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1413. if (typeof answer === 'function') {
  1414. answer();
  1415. }
  1416. },
  1417. },
  1418. testTitanArena: {
  1419. isCombine: true,
  1420. combineList: [
  1421. {
  1422. get name() { return I18N('TITAN_ARENA'); },
  1423. get title() { return I18N('TITAN_ARENA_TITLE'); },
  1424. onClick: function () {
  1425. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TITAN_ARENA')}?`, testTitanArena);
  1426. },
  1427. },
  1428. {
  1429. name: '>>',
  1430. onClick: cheats.goTitanValley,
  1431. get title() { return I18N('TITAN_VALLEY_TITLE'); },
  1432. color: 'green',
  1433. },
  1434. ],
  1435. },
  1436. testDungeon: {
  1437. isCombine: true,
  1438. combineList: [
  1439. {
  1440. get name() { return I18N('DUNGEON'); },
  1441. onClick: function () {
  1442. confShow(`${I18N('RUN_SCRIPT')} ${I18N('DUNGEON')}?`, testDungeon);
  1443. },
  1444. get title() { return I18N('DUNGEON_TITLE'); },
  1445. },
  1446. {
  1447. name: '>>',
  1448. onClick: cheats.goClanIsland,
  1449. get title() { return I18N('GUILD_ISLAND_TITLE'); },
  1450. color: 'green',
  1451. },
  1452. ],
  1453. },
  1454. testAdventure: {
  1455. isCombine: true,
  1456. combineList: [
  1457. {
  1458. get name() { return I18N('ADVENTURE'); },
  1459. onClick: () => {
  1460. testAdventure();
  1461. },
  1462. get title() { return I18N('ADVENTURE_TITLE'); },
  1463. },
  1464. {
  1465. get name() { return I18N('AUTO_RAID_ADVENTURE'); },
  1466. onClick: autoRaidAdventure,
  1467. get title() { return I18N('AUTO_RAID_ADVENTURE_TITLE'); },
  1468. },
  1469. {
  1470. name: '>>',
  1471. onClick: cheats.goSanctuary,
  1472. get title() { return I18N('SANCTUARY_TITLE'); },
  1473. color: 'green',
  1474. },
  1475. ],
  1476. },
  1477. rewardsAndMailFarm: {
  1478. get name() { return I18N('REWARDS_AND_MAIL'); },
  1479. get title() { return I18N('REWARDS_AND_MAIL_TITLE'); },
  1480. onClick: function () {
  1481. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS_AND_MAIL')}?`, rewardsAndMailFarm);
  1482. },
  1483. },
  1484. goToClanWar: {
  1485. get name() { return I18N('GUILD_WAR'); },
  1486. get title() { return I18N('GUILD_WAR_TITLE'); },
  1487. onClick: cheats.goClanWar,
  1488. dot: true,
  1489. },
  1490. dailyQuests: {
  1491. get name() { return I18N('DAILY_QUESTS'); },
  1492. get title() { return I18N('DAILY_QUESTS_TITLE'); },
  1493. onClick: async function () {
  1494. const quests = new dailyQuests(
  1495. () => {},
  1496. () => {}
  1497. );
  1498. await quests.autoInit();
  1499. quests.start();
  1500. },
  1501. },
  1502. newDay: {
  1503. get name() { return I18N('SYNC'); },
  1504. get title() { return I18N('SYNC_TITLE'); },
  1505. onClick: function () {
  1506. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SYNC')}?`, cheats.refreshGame);
  1507. },
  1508. },
  1509. // Архидемон
  1510. bossRatingEventDemon: {
  1511. get name() { return I18N('ARCHDEMON'); },
  1512. get title() { return I18N('ARCHDEMON_TITLE'); },
  1513. onClick: function () {
  1514. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ARCHDEMON')}?`, bossRatingEvent);
  1515. },
  1516. hide: true,
  1517. color: 'red',
  1518. },
  1519. // Горнило душ
  1520. bossRatingEventSouls: {
  1521. get name() { return I18N('FURNACE_OF_SOULS'); },
  1522. get title() { return I18N('ARCHDEMON_TITLE'); },
  1523. onClick: function () {
  1524. confShow(`${I18N('RUN_SCRIPT')} ${I18N('FURNACE_OF_SOULS')}?`, bossRatingEventSouls);
  1525. },
  1526. hide: true,
  1527. color: 'red',
  1528. },
  1529. };
  1530. /**
  1531. * Display buttons
  1532. *
  1533. * Вывести кнопочки
  1534. */
  1535. function addControlButtons() {
  1536. const { ScriptMenu } = HWHClasses;
  1537. const scriptMenu = ScriptMenu.getInst();
  1538. const { buttons } = HWHData;
  1539. for (let name in buttons) {
  1540. button = buttons[name];
  1541. if (button.hide) {
  1542. continue;
  1543. }
  1544. if (button.isCombine) {
  1545. button['button'] = scriptMenu.addCombinedButton(button.combineList);
  1546. continue;
  1547. }
  1548. button['button'] = scriptMenu.addButton(button);
  1549. }
  1550. }
  1551. /**
  1552. * Adds links
  1553. *
  1554. * Добавляет ссылки
  1555. */
  1556. function addBottomUrls() {
  1557. const { ScriptMenu } = HWHClasses;
  1558. const scriptMenu = ScriptMenu.getInst();
  1559. scriptMenu.addHeader(I18N('BOTTOM_URLS'));
  1560. }
  1561. /**
  1562. * Stop repetition of the mission
  1563. *
  1564. * Остановить повтор миссии
  1565. */
  1566. let isStopSendMission = false;
  1567. /**
  1568. * There is a repetition of the mission
  1569. *
  1570. * Идет повтор миссии
  1571. */
  1572. let isSendsMission = false;
  1573. /**
  1574. * Data on the past mission
  1575. *
  1576. * Данные о прошедшей мисии
  1577. */
  1578. let lastMissionStart = {}
  1579. /**
  1580. * Start time of the last battle in the company
  1581. *
  1582. * Время начала последнего боя в кампании
  1583. */
  1584. let lastMissionBattleStart = 0;
  1585. /**
  1586. * Data for calculating the last battle with the boss
  1587. *
  1588. * Данные для расчете последнего боя с боссом
  1589. */
  1590. let lastBossBattle = null;
  1591. /**
  1592. * Information about the last battle
  1593. *
  1594. * Данные о прошедшей битве
  1595. */
  1596. let lastBattleArg = {}
  1597. let lastBossBattleStart = null;
  1598. this.addBattleTimer = 4;
  1599. this.invasionTimer = 2500;
  1600. const invasionInfo = {
  1601. id: 225,
  1602. buff: 0,
  1603. bossLvl: 130,
  1604. };
  1605. const invasionDataPacks = {
  1606. 130: { buff: 0, pet: 6005, heroes: [9, 62, 10, 1, 66], favor: { 9: 6006 } },
  1607. 140: { buff: 0, pet: 6005, heroes: [9, 62, 10, 1, 66], favor: {} },
  1608. 150: { buff: 0, pet: 6005, heroes: [9, 62, 10, 1, 66], favor: {} },
  1609. 160: { buff: 0, pet: 6005, heroes: [64, 66, 13, 9, 4], favor: { 4: 6006, 9: 6004, 13: 6003, 64: 6005, 66: 6002 } },
  1610. 170: { buff: 0, pet: 6005, heroes: [9, 62, 10, 1, 66], favor: { 1: 6006, 9: 6005, 10: 6008, 62: 6003, 66: 6002 } },
  1611. 180: { buff: 0, pet: 6006, heroes: [62, 10, 2, 4, 66], favor: { 2: 6005, 4: 6001, 10: 6006, 62: 6003 } },
  1612. 190: { buff: 40, pet: 6005, heroes: [9, 2, 43, 45, 66], favor: { 9: 6005, 45: 6002, 66: 6006 } },
  1613. 200: { buff: 20, pet: 6005, heroes: [9, 62, 1, 48, 66], favor: { 9: 6007, 62: 6003 } },
  1614. 210: { buff: 10, pet: 6008, heroes: [9, 10, 4, 32, 66], favor: { 9: 6005, 10: 6003, 32: 6007, 66: 6006 } },
  1615. 220: { buff: 20, pet: 6004, heroes: [9, 1, 48, 43, 66], favor: { 9: 6005, 43: 6006, 48: 6000, 66: 6002 } },
  1616. 230: { buff: 45, pet: 6001, heroes: [9, 7, 40, 43, 66], favor: { 7: 6006, 9: 6005, 40: 6004, 43: 6006, 66: 6006 } },
  1617. 240: { buff: 50, pet: 6009, heroes: [9, 40, 43, 51, 66], favor: { 9: 6005, 40: 6004, 43: 6002, 66: 6007 } },
  1618. 250: { buff: 70, pet: 6005, heroes: [9, 10, 13, 43, 66], favor: { 9: 6005, 10: 6002, 13: 6002, 43: 6006, 66: 6006 } },
  1619. 260: { buff: 80, pet: 6008, heroes: [9, 40, 43, 4, 66], favor: { 4: 6001, 9: 6006, 43: 6006 } },
  1620. 270: { buff: 115, pet: 6001, heroes: [9, 13, 43, 51, 66], favor: { 9: 6006, 43: 6006, 51: 6001 } },
  1621. 280: { buff: 80, pet: 6008, heroes: [9, 13, 43, 56, 66], favor: { 9: 6004, 13: 6006, 43: 6006, 66: 6006 } },
  1622. 290: { buff: 60, pet: 6005, heroes: [9, 10, 43, 56, 66], favor: { 9: 6005, 10: 6002, 43: 6006 } },
  1623. 300: { buff: 75, pet: 6006, heroes: [9, 62, 1, 45, 66], favor: { 1: 6006, 9: 6005, 45: 6002, 66: 6007 } },
  1624. };
  1625. /**
  1626. * The name of the function of the beginning of the battle
  1627. *
  1628. * Имя функции начала боя
  1629. */
  1630. let nameFuncStartBattle = '';
  1631. /**
  1632. * The name of the function of the end of the battle
  1633. *
  1634. * Имя функции конца боя
  1635. */
  1636. let nameFuncEndBattle = '';
  1637. /**
  1638. * Data for calculating the last battle
  1639. *
  1640. * Данные для расчета последнего боя
  1641. */
  1642. let lastBattleInfo = null;
  1643. /**
  1644. * The ability to cancel the battle
  1645. *
  1646. * Возможность отменить бой
  1647. */
  1648. let isCancalBattle = true;
  1649.  
  1650. function setIsCancalBattle(value) {
  1651. isCancalBattle = value;
  1652. }
  1653.  
  1654. /**
  1655. * Certificator of the last open nesting doll
  1656. *
  1657. * Идетификатор последней открытой матрешки
  1658. */
  1659. let lastRussianDollId = null;
  1660. /**
  1661. * Cancel the training guide
  1662. *
  1663. * Отменить обучающее руководство
  1664. */
  1665. this.isCanceledTutorial = false;
  1666.  
  1667. /**
  1668. * Data from the last question of the quiz
  1669. *
  1670. * Данные последнего вопроса викторины
  1671. */
  1672. let lastQuestion = null;
  1673. /**
  1674. * Answer to the last question of the quiz
  1675. *
  1676. * Ответ на последний вопрос викторины
  1677. */
  1678. let lastAnswer = null;
  1679. /**
  1680. * Flag for opening keys or titan artifact spheres
  1681. *
  1682. * Флаг открытия ключей или сфер артефактов титанов
  1683. */
  1684. let artifactChestOpen = false;
  1685. /**
  1686. * The name of the function to open keys or orbs of titan artifacts
  1687. *
  1688. * Имя функции открытия ключей или сфер артефактов титанов
  1689. */
  1690. let artifactChestOpenCallName = '';
  1691. let correctShowOpenArtifact = 0;
  1692. /**
  1693. * Data for the last battle in the dungeon
  1694. * (Fix endless cards)
  1695. *
  1696. * Данные для последнего боя в подземке
  1697. * (Исправление бесконечных карт)
  1698. */
  1699. let lastDungeonBattleData = null;
  1700. /**
  1701. * Start time of the last battle in the dungeon
  1702. *
  1703. * Время начала последнего боя в подземелье
  1704. */
  1705. let lastDungeonBattleStart = 0;
  1706. /**
  1707. * Subscription end time
  1708. *
  1709. * Время окончания подписки
  1710. */
  1711. let subEndTime = 0;
  1712. /**
  1713. * Number of prediction cards
  1714. *
  1715. * Количество карт предсказаний
  1716. */
  1717. const countPredictionCard = 0;
  1718.  
  1719. /**
  1720. * Brawl pack
  1721. *
  1722. * Пачка для потасовок
  1723. */
  1724. let brawlsPack = null;
  1725. /**
  1726. * Autobrawl started
  1727. *
  1728. * Автопотасовка запущена
  1729. */
  1730. let isBrawlsAutoStart = false;
  1731. let clanDominationGetInfo = null;
  1732. /**
  1733. * Copies the text to the clipboard
  1734. *
  1735. * Копирует тест в буфер обмена
  1736. * @param {*} text copied text // копируемый текст
  1737. */
  1738. function copyText(text) {
  1739. let copyTextarea = document.createElement("textarea");
  1740. copyTextarea.style.opacity = "0";
  1741. copyTextarea.textContent = text;
  1742. document.body.appendChild(copyTextarea);
  1743. copyTextarea.select();
  1744. document.execCommand("copy");
  1745. document.body.removeChild(copyTextarea);
  1746. delete copyTextarea;
  1747. }
  1748. /**
  1749. * Returns the history of requests
  1750. *
  1751. * Возвращает историю запросов
  1752. */
  1753. this.getRequestHistory = function() {
  1754. return requestHistory;
  1755. }
  1756. /**
  1757. * Generates a random integer from min to max
  1758. *
  1759. * Гененирует случайное целое число от min до max
  1760. */
  1761. const random = function (min, max) {
  1762. return Math.floor(Math.random() * (max - min + 1) + min);
  1763. }
  1764. const randf = function (min, max) {
  1765. return Math.random() * (max - min + 1) + min;
  1766. };
  1767. /**
  1768. * Clearing the request history
  1769. *
  1770. * Очистка истоии запросов
  1771. */
  1772. setInterval(function () {
  1773. let now = Date.now();
  1774. for (let i in requestHistory) {
  1775. const time = +i.split('_')[0];
  1776. if (now - time > 300000) {
  1777. delete requestHistory[i];
  1778. }
  1779. }
  1780. }, 300000);
  1781. /**
  1782. * Displays the dialog box
  1783. *
  1784. * Отображает диалоговое окно
  1785. */
  1786. function confShow(message, yesCallback, noCallback) {
  1787. let buts = [];
  1788. message = message || I18N('DO_YOU_WANT');
  1789. noCallback = noCallback || (() => {});
  1790. if (yesCallback) {
  1791. buts = [
  1792. { msg: I18N('BTN_RUN'), result: true},
  1793. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true},
  1794. ]
  1795. } else {
  1796. yesCallback = () => {};
  1797. buts = [
  1798. { msg: I18N('BTN_OK'), result: true},
  1799. ];
  1800. }
  1801. popup.confirm(message, buts).then((e) => {
  1802. // dialogPromice = null;
  1803. if (e) {
  1804. yesCallback();
  1805. } else {
  1806. noCallback();
  1807. }
  1808. });
  1809. }
  1810. /**
  1811. * Override/proxy the method for creating a WS package send
  1812. *
  1813. * Переопределяем/проксируем метод создания отправки WS пакета
  1814. */
  1815. WebSocket.prototype.send = function (data) {
  1816. if (!this.isSetOnMessage) {
  1817. const oldOnmessage = this.onmessage;
  1818. this.onmessage = function (event) {
  1819. try {
  1820. const data = JSON.parse(event.data);
  1821. if (!this.isWebSocketLogin && data.result.type == "iframeEvent.login") {
  1822. this.isWebSocketLogin = true;
  1823. } else if (data.result.type == "iframeEvent.login") {
  1824. return;
  1825. }
  1826. } catch (e) { }
  1827. return oldOnmessage.apply(this, arguments);
  1828. }
  1829. this.isSetOnMessage = true;
  1830. }
  1831. original.SendWebSocket.call(this, data);
  1832. }
  1833. /**
  1834. * Overriding/Proxying the Ajax Request Creation Method
  1835. *
  1836. * Переопределяем/проксируем метод создания Ajax запроса
  1837. */
  1838. XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
  1839. this.uniqid = Date.now() + '_' + random(1000000, 10000000);
  1840. this.errorRequest = false;
  1841. if (method == 'POST' && url.includes('.nextersglobal.com/api/') && /api\/$/.test(url)) {
  1842. if (!apiUrl) {
  1843. apiUrl = url;
  1844. const socialInfo = /heroes-(.+?)\./.exec(apiUrl);
  1845. console.log(socialInfo);
  1846. }
  1847. requestHistory[this.uniqid] = {
  1848. method,
  1849. url,
  1850. error: [],
  1851. headers: {},
  1852. request: null,
  1853. response: null,
  1854. signature: [],
  1855. calls: {},
  1856. };
  1857. } else if (method == 'POST' && url.includes('error.nextersglobal.com/client/')) {
  1858. this.errorRequest = true;
  1859. }
  1860. return original.open.call(this, method, url, async, user, password);
  1861. };
  1862. /**
  1863. * Overriding/Proxying the header setting method for the AJAX request
  1864. *
  1865. * Переопределяем/проксируем метод установки заголовков для AJAX запроса
  1866. */
  1867. XMLHttpRequest.prototype.setRequestHeader = function (name, value, check) {
  1868. if (this.uniqid in requestHistory) {
  1869. requestHistory[this.uniqid].headers[name] = value;
  1870. if (name == 'X-Auth-Signature') {
  1871. requestHistory[this.uniqid].signature.push(value);
  1872. if (!check) {
  1873. return;
  1874. }
  1875. }
  1876. } else {
  1877. check = true;
  1878. }
  1879. return original.setRequestHeader.call(this, name, value);
  1880. };
  1881. /**
  1882. * Overriding/Proxying the AJAX Request Sending Method
  1883. *
  1884. * Переопределяем/проксируем метод отправки AJAX запроса
  1885. */
  1886. XMLHttpRequest.prototype.send = async function (sourceData) {
  1887. if (this.uniqid in requestHistory) {
  1888. let tempData = null;
  1889. if (getClass(sourceData) == "ArrayBuffer") {
  1890. tempData = decoder.decode(sourceData);
  1891. } else {
  1892. tempData = sourceData;
  1893. }
  1894. requestHistory[this.uniqid].request = tempData;
  1895. let headers = requestHistory[this.uniqid].headers;
  1896. lastHeaders = Object.assign({}, headers);
  1897. /**
  1898. * Game loading event
  1899. *
  1900. * Событие загрузки игры
  1901. */
  1902. if (headers["X-Request-Id"] > 2 && !isLoadGame) {
  1903. isLoadGame = true;
  1904. if (cheats.libGame) {
  1905. lib.setData(cheats.libGame);
  1906. } else {
  1907. lib.setData(await cheats.LibLoad());
  1908. }
  1909. addControls();
  1910. addControlButtons();
  1911. addBottomUrls();
  1912.  
  1913. if (isChecked('sendExpedition')) {
  1914. const isTimeBetweenDays = isTimeBetweenNewDays();
  1915. if (!isTimeBetweenDays) {
  1916. checkExpedition();
  1917. } else {
  1918. setProgress(I18N('EXPEDITIONS_NOTTIME'), true);
  1919. }
  1920. }
  1921.  
  1922. getAutoGifts();
  1923.  
  1924. cheats.activateHacks();
  1925. justInfo();
  1926. if (isChecked('dailyQuests')) {
  1927. testDailyQuests();
  1928. }
  1929.  
  1930. if (isChecked('buyForGold')) {
  1931. buyInStoreForGold();
  1932. }
  1933. }
  1934. /**
  1935. * Outgoing request data processing
  1936. *
  1937. * Обработка данных исходящего запроса
  1938. */
  1939. sourceData = await checkChangeSend.call(this, sourceData, tempData);
  1940. /**
  1941. * Handling incoming request data
  1942. *
  1943. * Обработка данных входящего запроса
  1944. */
  1945. const oldReady = this.onreadystatechange;
  1946. this.onreadystatechange = async function (e) {
  1947. if (this.errorRequest) {
  1948. return oldReady.apply(this, arguments);
  1949. }
  1950. if(this.readyState == 4 && this.status == 200) {
  1951. isTextResponse = this.responseType === "text" || this.responseType === "";
  1952. let response = isTextResponse ? this.responseText : this.response;
  1953. requestHistory[this.uniqid].response = response;
  1954. /**
  1955. * Replacing incoming request data
  1956. *
  1957. * Заменна данных входящего запроса
  1958. */
  1959. if (isTextResponse) {
  1960. await checkChangeResponse.call(this, response);
  1961. }
  1962. /**
  1963. * A function to run after the request is executed
  1964. *
  1965. * Функция запускаемая после выполения запроса
  1966. */
  1967. if (typeof this.onReadySuccess == 'function') {
  1968. setTimeout(this.onReadySuccess, 500);
  1969. }
  1970. /** Удаляем из истории запросов битвы с боссом */
  1971. if ('invasion_bossStart' in requestHistory[this.uniqid].calls) delete requestHistory[this.uniqid];
  1972. }
  1973. if (oldReady) {
  1974. try {
  1975. return oldReady.apply(this, arguments);
  1976. } catch(e) {
  1977. console.log(oldReady);
  1978. console.error('Error in oldReady:', e);
  1979. }
  1980.  
  1981. }
  1982. }
  1983. }
  1984. if (this.errorRequest) {
  1985. const oldReady = this.onreadystatechange;
  1986. this.onreadystatechange = function () {
  1987. Object.defineProperty(this, 'status', {
  1988. writable: true
  1989. });
  1990. this.status = 200;
  1991. Object.defineProperty(this, 'readyState', {
  1992. writable: true
  1993. });
  1994. this.readyState = 4;
  1995. Object.defineProperty(this, 'responseText', {
  1996. writable: true
  1997. });
  1998. this.responseText = JSON.stringify({
  1999. "result": true
  2000. });
  2001. if (typeof this.onReadySuccess == 'function') {
  2002. setTimeout(this.onReadySuccess, 200);
  2003. }
  2004. return oldReady.apply(this, arguments);
  2005. }
  2006. this.onreadystatechange();
  2007. } else {
  2008. try {
  2009. return original.send.call(this, sourceData);
  2010. } catch(e) {
  2011. debugger;
  2012. }
  2013. }
  2014. };
  2015. /**
  2016. * Processing and substitution of outgoing data
  2017. *
  2018. * Обработка и подмена исходящих данных
  2019. */
  2020. async function checkChangeSend(sourceData, tempData) {
  2021. try {
  2022. /**
  2023. * A function that replaces battle data with incorrect ones to cancel combatя
  2024. *
  2025. * Функция заменяющая данные боя на неверные для отмены боя
  2026. */
  2027. const fixBattle = function (heroes) {
  2028. for (const ids in heroes) {
  2029. hero = heroes[ids];
  2030. hero.energy = random(1, 999);
  2031. if (hero.hp > 0) {
  2032. hero.hp = random(1, hero.hp);
  2033. }
  2034. }
  2035. }
  2036. /**
  2037. * Dialog window 2
  2038. *
  2039. * Диалоговое окно 2
  2040. */
  2041. const showMsg = async function (msg, ansF, ansS) {
  2042. if (typeof popup == 'object') {
  2043. return await popup.confirm(msg, [
  2044. {msg: ansF, result: false},
  2045. {msg: ansS, result: true},
  2046. ]);
  2047. } else {
  2048. return !confirm(`${msg}\n ${ansF} (${I18N('BTN_OK')})\n ${ansS} (${I18N('BTN_CANCEL')})`);
  2049. }
  2050. }
  2051. /**
  2052. * Dialog window 3
  2053. *
  2054. * Диалоговое окно 3
  2055. */
  2056. const showMsgs = async function (msg, ansF, ansS, ansT) {
  2057. return await popup.confirm(msg, [
  2058. {msg: ansF, result: 0},
  2059. {msg: ansS, result: 1},
  2060. {msg: ansT, result: 2},
  2061. ]);
  2062. }
  2063.  
  2064. let changeRequest = false;
  2065. const testData = JSON.parse(tempData);
  2066. for (const call of testData.calls) {
  2067. if (!artifactChestOpen) {
  2068. requestHistory[this.uniqid].calls[call.name] = call.ident;
  2069. }
  2070. /**
  2071. * Cancellation of the battle in adventures, on VG and with minions of Asgard
  2072. * Отмена боя в приключениях, на ВГ и с прислужниками Асгарда
  2073. */
  2074. if ((call.name == 'adventure_endBattle' ||
  2075. call.name == 'adventureSolo_endBattle' ||
  2076. call.name == 'clanWarEndBattle' &&
  2077. isChecked('cancelBattle') ||
  2078. call.name == 'crossClanWar_endBattle' &&
  2079. isChecked('cancelBattle') ||
  2080. call.name == 'brawl_endBattle' ||
  2081. call.name == 'towerEndBattle' ||
  2082. call.name == 'invasion_bossEnd' ||
  2083. call.name == 'titanArenaEndBattle' ||
  2084. call.name == 'bossEndBattle' ||
  2085. call.name == 'clanRaid_endNodeBattle') &&
  2086. isCancalBattle) {
  2087. nameFuncEndBattle = call.name;
  2088.  
  2089. if (isChecked('tryFixIt_v2') &&
  2090. !call.args.result.win &&
  2091. (call.name == 'brawl_endBattle' ||
  2092. //call.name == 'crossClanWar_endBattle' ||
  2093. call.name == 'epicBrawl_endBattle' ||
  2094. //call.name == 'clanWarEndBattle' ||
  2095. call.name == 'adventure_endBattle' ||
  2096. call.name == 'titanArenaEndBattle' ||
  2097. call.name == 'bossEndBattle' ||
  2098. call.name == 'adventureSolo_endBattle') &&
  2099. lastBattleInfo) {
  2100. const noFixWin = call.name == 'clanWarEndBattle' || call.name == 'crossClanWar_endBattle';
  2101. const cloneBattle = structuredClone(lastBattleInfo);
  2102. lastBattleInfo = null;
  2103. try {
  2104. const { BestOrWinFixBattle } = HWHClasses;
  2105. const bFix = new BestOrWinFixBattle(cloneBattle);
  2106. bFix.setNoMakeWin(noFixWin);
  2107. let endTime = Date.now() + 3e4;
  2108. if (endTime < cloneBattle.endTime) {
  2109. endTime = cloneBattle.endTime;
  2110. }
  2111. const result = await bFix.start(cloneBattle.endTime, 500);
  2112.  
  2113. if (result.result?.win) {
  2114. call.args.result = result.result;
  2115. call.args.progress = result.progress;
  2116. changeRequest = true;
  2117. } else if (result.value > 0) {
  2118. if (
  2119. await popup.confirm(I18N('DEFEAT') + '<br>' + I18N('BEST_RESULT', { value: result.value }), [
  2120. { msg: I18N('BTN_CANCEL'), result: 0 },
  2121. { msg: I18N('BTN_ACCEPT'), result: 1 },
  2122. ])
  2123. ) {
  2124. call.args.result = result.result;
  2125. call.args.progress = result.progress;
  2126. changeRequest = true;
  2127. }
  2128. }
  2129. } catch (error) {
  2130. console.error(error);
  2131. }
  2132. }
  2133.  
  2134. if (isChecked('tryFixIt_v2') && !call.args.result.win && call.name == 'invasion_bossEnd' && lastBattleInfo) {
  2135. setProgress(I18N('LETS_FIX'), false);
  2136. const cloneBattle = structuredClone(lastBattleInfo);
  2137. const bFix = new WinFixBattle(cloneBattle);
  2138. const result = await bFix.start(cloneBattle.endTime, 500);
  2139. console.log(result);
  2140. let msgResult = I18N('DEFEAT');
  2141. if (result.result?.win) {
  2142. call.args.result = result.result;
  2143. call.args.progress = result.progress;
  2144. msgResult = I18N('VICTORY');
  2145. changeRequest = true;
  2146. }
  2147. setProgress(msgResult, false, hideProgress);
  2148. if (lastBattleInfo.seed === 8008) {
  2149. let timer = result.battleTimer;
  2150. const period = Math.ceil((Date.now() - lastBossBattleStart) / 1000);
  2151. console.log(timer, period);
  2152. if (period < timer) {
  2153. timer = timer - period;
  2154. await countdownTimer(timer);
  2155. lastBattleInfo.timer = true;
  2156. }
  2157. }
  2158. }
  2159.  
  2160. if (!call.args.result.win) {
  2161. let resultPopup = false;
  2162. if (call.name == 'adventure_endBattle' ||
  2163. //call.name == 'invasion_bossEnd' ||
  2164. call.name == 'bossEndBattle' ||
  2165. call.name == 'adventureSolo_endBattle') {
  2166. resultPopup = await showMsgs(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  2167. } else if (call.name == 'clanWarEndBattle' ||
  2168. call.name == 'crossClanWar_endBattle') {
  2169. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_AUTO_F5'));
  2170. } else if (call.name !== 'epicBrawl_endBattle' && call.name !== 'titanArenaEndBattle') {
  2171. resultPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'));
  2172. }
  2173. if (resultPopup) {
  2174. if (call.name == 'invasion_bossEnd') {
  2175. this.errorRequest = true;
  2176. }
  2177. fixBattle(call.args.progress[0].attackers.heroes);
  2178. fixBattle(call.args.progress[0].defenders.heroes);
  2179. changeRequest = true;
  2180. if (resultPopup > 1) {
  2181. this.onReadySuccess = testAutoBattle;
  2182. // setTimeout(bossBattle, 1000);
  2183. }
  2184. }
  2185. } else if (call.args.result.stars < 3 && call.name == 'towerEndBattle') {
  2186. resultPopup = await showMsg(I18N('LOST_HEROES'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  2187. if (resultPopup) {
  2188. fixBattle(call.args.progress[0].attackers.heroes);
  2189. fixBattle(call.args.progress[0].defenders.heroes);
  2190. changeRequest = true;
  2191. if (resultPopup > 1) {
  2192. this.onReadySuccess = testAutoBattle;
  2193. }
  2194. }
  2195. }
  2196. // Потасовки
  2197. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_endBattle') {}
  2198. }
  2199. /**
  2200. * Save pack for Brawls
  2201. *
  2202. * Сохраняем пачку для потасовок
  2203. */
  2204. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_startBattle') {
  2205. console.log(JSON.stringify(call.args));
  2206. brawlsPack = call.args;
  2207. if (
  2208. await popup.confirm(
  2209. I18N('START_AUTO_BRAWLS'),
  2210. [
  2211. { msg: I18N('BTN_NO'), result: false },
  2212. { msg: I18N('BTN_YES'), result: true },
  2213. ],
  2214. [
  2215. {
  2216. name: 'isAuto',
  2217. get label() { return I18N('BRAWL_AUTO_PACK'); },
  2218. checked: false,
  2219. },
  2220. ]
  2221. )
  2222. ) {
  2223. isBrawlsAutoStart = true;
  2224. const isAuto = popup.getCheckBoxes().find((e) => e.name === 'isAuto');
  2225. this.errorRequest = true;
  2226. testBrawls(isAuto.checked);
  2227. }
  2228. }
  2229. /**
  2230. * Canceled fight in Asgard
  2231. * Отмена боя в Асгарде
  2232. */
  2233. if (call.name == 'clanRaid_endBossBattle' && isChecked('cancelBattle')) {
  2234. const bossDamage = call.args.progress[0].defenders.heroes[1].extra;
  2235. let maxDamage = bossDamage.damageTaken + bossDamage.damageTakenNextLevel;
  2236. const lastDamage = maxDamage;
  2237.  
  2238. const testFunc = [];
  2239.  
  2240. if (testFuntions.masterFix) {
  2241. testFunc.push({ msg: 'masterFix', isInput: true, default: 100 });
  2242. }
  2243.  
  2244. const resultPopup = await popup.confirm(
  2245. `${I18N('MSG_YOU_APPLIED')} ${lastDamage.toLocaleString()} ${I18N('MSG_DAMAGE')}.`,
  2246. [
  2247. { msg: I18N('BTN_OK'), result: false },
  2248. { msg: I18N('BTN_AUTO_F5'), result: 1 },
  2249. { msg: I18N('BTN_TRY_FIX_IT'), result: 2 },
  2250. ...testFunc,
  2251. ],
  2252. [
  2253. {
  2254. name: 'isStat',
  2255. get label() { return I18N('CALC_STAT'); },
  2256. checked: false,
  2257. },
  2258. ]
  2259. );
  2260. if (resultPopup) {
  2261. if (resultPopup == 2) {
  2262. setProgress(I18N('LETS_FIX'), false);
  2263. await new Promise((e) => setTimeout(e, 0));
  2264. const cloneBattle = structuredClone(lastBossBattle);
  2265. const endTime = cloneBattle.endTime - 15e3;
  2266. console.log('fixBossBattleStart');
  2267.  
  2268. const { BossFixBattle } = HWHClasses;
  2269. const bFix = new BossFixBattle(cloneBattle);
  2270. const result = await bFix.start(endTime, 500);
  2271. console.log(result);
  2272.  
  2273. let msgResult = I18N('DAMAGE_NO_FIXED', {
  2274. lastDamage: lastDamage.toLocaleString()
  2275. });
  2276. if (result.value > lastDamage) {
  2277. call.args.result = result.result;
  2278. call.args.progress = result.progress;
  2279. msgResult = I18N('DAMAGE_FIXED', {
  2280. lastDamage: lastDamage.toLocaleString(),
  2281. maxDamage: result.value.toLocaleString(),
  2282. });
  2283. }
  2284. console.log(lastDamage, '>', result.value);
  2285. setProgress(
  2286. msgResult +
  2287. '<br/>' +
  2288. I18N('COUNT_FIXED', {
  2289. count: result.maxCount,
  2290. }),
  2291. false,
  2292. hideProgress
  2293. );
  2294. } else if (resultPopup > 3) {
  2295. const cloneBattle = structuredClone(lastBossBattle);
  2296. const { masterFixBattle } = HWHClasses;
  2297. const mFix = new masterFixBattle(cloneBattle);
  2298. const result = await mFix.start(cloneBattle.endTime, resultPopup);
  2299. console.log(result);
  2300. let msgResult = I18N('DAMAGE_NO_FIXED', {
  2301. lastDamage: lastDamage.toLocaleString(),
  2302. });
  2303. if (result.value > lastDamage) {
  2304. maxDamage = result.value;
  2305. call.args.result = result.result;
  2306. call.args.progress = result.progress;
  2307. msgResult = I18N('DAMAGE_FIXED', {
  2308. lastDamage: lastDamage.toLocaleString(),
  2309. maxDamage: maxDamage.toLocaleString(),
  2310. });
  2311. }
  2312. console.log('Урон:', lastDamage, maxDamage);
  2313. setProgress(msgResult, false, hideProgress);
  2314. } else {
  2315. fixBattle(call.args.progress[0].attackers.heroes);
  2316. fixBattle(call.args.progress[0].defenders.heroes);
  2317. }
  2318. changeRequest = true;
  2319. }
  2320. const isStat = popup.getCheckBoxes().find((e) => e.name === 'isStat');
  2321. if (isStat.checked) {
  2322. this.onReadySuccess = testBossBattle;
  2323. }
  2324. }
  2325. /**
  2326. * Save the Asgard Boss Attack Pack
  2327. * Сохраняем пачку для атаки босса Асгарда
  2328. */
  2329. if (call.name == 'clanRaid_startBossBattle') {
  2330. console.log(JSON.stringify(call.args));
  2331. }
  2332. /**
  2333. * Saving the request to start the last battle
  2334. * Сохранение запроса начала последнего боя
  2335. */
  2336. if (
  2337. call.name == 'clanWarAttack' ||
  2338. call.name == 'crossClanWar_startBattle' ||
  2339. call.name == 'adventure_turnStartBattle' ||
  2340. call.name == 'adventureSolo_turnStartBattle' ||
  2341. call.name == 'bossAttack' ||
  2342. call.name == 'invasion_bossStart' ||
  2343. call.name == 'towerStartBattle'
  2344. ) {
  2345. nameFuncStartBattle = call.name;
  2346. lastBattleArg = call.args;
  2347.  
  2348. if (call.name == 'invasion_bossStart') {
  2349. const timePassed = Date.now() - lastBossBattleStart;
  2350. if (timePassed < invasionTimer) {
  2351. await new Promise((e) => setTimeout(e, invasionTimer - timePassed));
  2352. }
  2353. invasionTimer -= 1;
  2354. }
  2355. lastBossBattleStart = Date.now();
  2356. }
  2357. if (call.name == 'invasion_bossEnd') {
  2358. const lastBattle = lastBattleInfo;
  2359. if (lastBattle && call.args.result.win) {
  2360. if (lastBattle.seed === 8008) {
  2361. lastBattle.progress = call.args.progress;
  2362. const result = await Calc(lastBattle);
  2363. let timer = getTimer(result.battleTime, 1) + addBattleTimer;
  2364. const period = Math.ceil((Date.now() - lastBossBattleStart) / 1000);
  2365. console.log(timer, period);
  2366. if (period < timer) {
  2367. timer = timer - period;
  2368. await countdownTimer(timer);
  2369. }
  2370. }
  2371. }
  2372. }
  2373. /**
  2374. * Disable spending divination cards
  2375. * Отключить трату карт предсказаний
  2376. */
  2377. if (call.name == 'dungeonEndBattle') {
  2378. if (call.args.isRaid) {
  2379. if (HWHData.countPredictionCard <= 0) {
  2380. delete call.args.isRaid;
  2381. changeRequest = true;
  2382. } else if (HWHData.countPredictionCard > 0) {
  2383. HWHData.countPredictionCard--;
  2384. }
  2385. }
  2386. console.log(`Cards: ${HWHData.countPredictionCard}`);
  2387. /**
  2388. * Fix endless cards
  2389. * Исправление бесконечных карт
  2390. */
  2391. const lastBattle = lastDungeonBattleData;
  2392. if (lastBattle && !call.args.isRaid) {
  2393. if (changeRequest) {
  2394. lastBattle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  2395. } else {
  2396. lastBattle.progress = call.args.progress;
  2397. }
  2398. const result = await Calc(lastBattle);
  2399.  
  2400. if (changeRequest) {
  2401. call.args.progress = result.progress;
  2402. call.args.result = result.result;
  2403. }
  2404. let timer = result.battleTimer + addBattleTimer;
  2405. const period = Math.ceil((Date.now() - lastDungeonBattleStart) / 1000);
  2406. console.log(timer, period);
  2407. if (period < timer) {
  2408. timer = timer - period;
  2409. await countdownTimer(timer);
  2410. }
  2411. }
  2412. }
  2413. /**
  2414. * Quiz Answer
  2415. * Ответ на викторину
  2416. */
  2417. if (call.name == 'quiz_answer') {
  2418. /**
  2419. * Automatically changes the answer to the correct one if there is one.
  2420. * Автоматически меняет ответ на правильный если он есть
  2421. */
  2422. if (lastAnswer && isChecked('getAnswer')) {
  2423. call.args.answerId = lastAnswer;
  2424. lastAnswer = null;
  2425. changeRequest = true;
  2426. }
  2427. }
  2428. /**
  2429. * Present
  2430. * Подарки
  2431. */
  2432. if (call.name == 'freebieCheck') {
  2433. freebieCheckInfo = call;
  2434. }
  2435. /** missionTimer */
  2436. if (call.name == 'missionEnd' && missionBattle) {
  2437. let startTimer = false;
  2438. if (!call.args.result.win) {
  2439. startTimer = await popup.confirm(I18N('DEFEAT_TURN_TIMER'), [
  2440. { msg: I18N('BTN_NO'), result: false },
  2441. { msg: I18N('BTN_YES'), result: true },
  2442. ]);
  2443. }
  2444.  
  2445. if (call.args.result.win || startTimer) {
  2446. missionBattle.progress = call.args.progress;
  2447. missionBattle.result = call.args.result;
  2448. const result = await Calc(missionBattle);
  2449.  
  2450. let timer = result.battleTimer + addBattleTimer;
  2451. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  2452. if (period < timer) {
  2453. timer = timer - period;
  2454. await countdownTimer(timer);
  2455. }
  2456. missionBattle = null;
  2457. } else {
  2458. this.errorRequest = true;
  2459. }
  2460. }
  2461. /**
  2462. * Getting mission data for auto-repeat
  2463. * Получение данных миссии для автоповтора
  2464. */
  2465. if (isChecked('repeatMission') &&
  2466. call.name == 'missionEnd') {
  2467. let missionInfo = {
  2468. id: call.args.id,
  2469. result: call.args.result,
  2470. heroes: call.args.progress[0].attackers.heroes,
  2471. count: 0,
  2472. }
  2473. setTimeout(async () => {
  2474. if (!isSendsMission && await popup.confirm(I18N('MSG_REPEAT_MISSION'), [
  2475. { msg: I18N('BTN_REPEAT'), result: true},
  2476. { msg: I18N('BTN_NO'), result: false},
  2477. ])) {
  2478. isStopSendMission = false;
  2479. isSendsMission = true;
  2480. sendsMission(missionInfo);
  2481. }
  2482. }, 0);
  2483. }
  2484. /**
  2485. * Getting mission data
  2486. * Получение данных миссии
  2487. * missionTimer
  2488. */
  2489. if (call.name == 'missionStart') {
  2490. lastMissionStart = call.args;
  2491. lastMissionBattleStart = Date.now();
  2492. }
  2493. /**
  2494. * Specify the quantity for Titan Orbs and Pet Eggs
  2495. * Указать количество для сфер титанов и яиц петов
  2496. */
  2497. if (isChecked('countControl') &&
  2498. (call.name == 'pet_chestOpen' ||
  2499. call.name == 'titanUseSummonCircle') &&
  2500. call.args.amount > 1) {
  2501. const startAmount = call.args.amount;
  2502. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2503. { msg: I18N('BTN_OPEN'), isInput: true, default: 1},
  2504. ]);
  2505. if (result) {
  2506. const item = call.name == 'pet_chestOpen' ? { id: 90, type: 'consumable' } : { id: 13, type: 'coin' };
  2507. cheats.updateInventory({
  2508. [item.type]: {
  2509. [item.id]: -(result - startAmount),
  2510. },
  2511. });
  2512. call.args.amount = result;
  2513. changeRequest = true;
  2514. }
  2515. }
  2516. /**
  2517. * Specify the amount for keys and spheres of titan artifacts
  2518. * Указать колличество для ключей и сфер артефактов титанов
  2519. */
  2520. if (isChecked('countControl') &&
  2521. (call.name == 'artifactChestOpen' ||
  2522. call.name == 'titanArtifactChestOpen') &&
  2523. call.args.amount > 1 &&
  2524. call.args.free &&
  2525. !changeRequest) {
  2526. artifactChestOpenCallName = call.name;
  2527. const startAmount = call.args.amount;
  2528. let result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2529. { msg: I18N('BTN_OPEN'), isInput: true, default: 1 },
  2530. ]);
  2531. if (result) {
  2532. const openChests = result;
  2533. let sphere = result < 10 ? 1 : 10;
  2534. call.args.amount = sphere;
  2535. for (let count = openChests - sphere; count > 0; count -= sphere) {
  2536. if (count < 10) sphere = 1;
  2537. const ident = artifactChestOpenCallName + "_" + count;
  2538. testData.calls.push({
  2539. name: artifactChestOpenCallName,
  2540. args: {
  2541. amount: sphere,
  2542. free: true,
  2543. },
  2544. ident: ident
  2545. });
  2546. if (!Array.isArray(requestHistory[this.uniqid].calls[call.name])) {
  2547. requestHistory[this.uniqid].calls[call.name] = [requestHistory[this.uniqid].calls[call.name]];
  2548. }
  2549. requestHistory[this.uniqid].calls[call.name].push(ident);
  2550. }
  2551.  
  2552. const consumableId = call.name == 'artifactChestOpen' ? 45 : 55;
  2553. cheats.updateInventory({
  2554. consumable: {
  2555. [consumableId]: -(openChests - startAmount),
  2556. },
  2557. });
  2558. artifactChestOpen = true;
  2559. changeRequest = true;
  2560. }
  2561. }
  2562. if (call.name == 'consumableUseLootBox') {
  2563. lastRussianDollId = call.args.libId;
  2564. /**
  2565. * Specify quantity for gold caskets
  2566. * Указать количество для золотых шкатулок
  2567. */
  2568. if (isChecked('countControl') &&
  2569. call.args.libId == 148 &&
  2570. call.args.amount > 1) {
  2571. const result = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2572. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2573. ]);
  2574. call.args.amount = result;
  2575. changeRequest = true;
  2576. }
  2577. if (isChecked('countControl') && call.args.libId >= 362 && call.args.libId <= 389) {
  2578. this.massOpen = call.args.libId;
  2579. }
  2580. }
  2581. if (call.name == 'invasion_bossStart' && isChecked('tryFixIt_v2')) {
  2582. const { invasionInfo, invasionDataPacks } = HWHData;
  2583. if (call.args.id == invasionInfo.id) {
  2584. const pack = invasionDataPacks[invasionInfo.bossLvl];
  2585. if (pack) {
  2586. if (pack.buff != invasionInfo.buff) {
  2587. setProgress(
  2588. I18N('INVASION_BOSS_BUFF', {
  2589. bossLvl: invasionInfo.bossLvl,
  2590. needBuff: pack.buff,
  2591. haveBuff: invasionInfo.buff,
  2592. }),
  2593. false
  2594. );
  2595. } else {
  2596. call.args.pet = pack.pet;
  2597. call.args.heroes = pack.heroes;
  2598. call.args.favor = pack.favor;
  2599. changeRequest = true;
  2600. }
  2601. }
  2602. }
  2603. }
  2604. if (call.name == 'workshopBuff_create') {
  2605. const { invasionInfo, invasionDataPacks } = HWHData;
  2606. const pack = invasionDataPacks[invasionInfo.bossLvl];
  2607. if (pack) {
  2608. const addBuff = call.args.amount * 5;
  2609. if (pack.buff < addBuff + invasionInfo.buff) {
  2610. this.errorRequest = true;
  2611. }
  2612. setProgress(
  2613. I18N('INVASION_BOSS_BUFF', {
  2614. bossLvl: invasionInfo.bossLvl,
  2615. needBuff: pack.buff,
  2616. haveBuff: invasionInfo.buff,
  2617. }),
  2618. false
  2619. );
  2620. }
  2621. }
  2622. if (call.name == 'saleShowcase_rewardInfo') {
  2623. this[call.name] = {
  2624. offerId: call.args.offerId,
  2625. };
  2626. }
  2627. /**
  2628. * Changing the maximum number of raids in the campaign
  2629. * Изменение максимального количества рейдов в кампании
  2630. */
  2631. // if (call.name == 'missionRaid') {
  2632. // if (isChecked('countControl') && call.args.times > 1) {
  2633. // const result = +(await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2634. // { msg: I18N('BTN_RUN'), isInput: true, default: call.args.times },
  2635. // ]));
  2636. // call.args.times = result > call.args.times ? call.args.times : result;
  2637. // changeRequest = true;
  2638. // }
  2639. // }
  2640. }
  2641.  
  2642. let headers = requestHistory[this.uniqid].headers;
  2643. if (changeRequest) {
  2644. sourceData = JSON.stringify(testData);
  2645. headers['X-Auth-Signature'] = getSignature(headers, sourceData);
  2646. }
  2647.  
  2648. let signature = headers['X-Auth-Signature'];
  2649. if (signature) {
  2650. original.setRequestHeader.call(this, 'X-Auth-Signature', signature);
  2651. }
  2652. } catch (err) {
  2653. console.log("Request(send, " + this.uniqid + "):\n", sourceData, "Error:\n", err);
  2654. }
  2655. return sourceData;
  2656. }
  2657. /**
  2658. * Processing and substitution of incoming data
  2659. *
  2660. * Обработка и подмена входящих данных
  2661. */
  2662. async function checkChangeResponse(response) {
  2663. try {
  2664. isChange = false;
  2665. let nowTime = Math.round(Date.now() / 1000);
  2666. callsIdent = requestHistory[this.uniqid].calls;
  2667. respond = JSON.parse(response);
  2668. /**
  2669. * If the request returned an error removes the error (removes synchronization errors)
  2670. * Если запрос вернул ошибку удаляет ошибку (убирает ошибки синхронизации)
  2671. */
  2672. if (respond.error) {
  2673. isChange = true;
  2674. console.error(respond.error);
  2675. if (isChecked('showErrors')) {
  2676. popup.confirm(I18N('ERROR_MSG', {
  2677. name: respond.error.name,
  2678. description: respond.error.description,
  2679. }));
  2680. }
  2681. if (respond.error.name != 'AccountBan') {
  2682. delete respond.error;
  2683. respond.results = [];
  2684. }
  2685. }
  2686. let mainReward = null;
  2687. const allReward = {};
  2688. let countTypeReward = 0;
  2689. let readQuestInfo = false;
  2690. for (const call of respond.results) {
  2691. /**
  2692. * Obtaining initial data for completing quests
  2693. * Получение исходных данных для выполнения квестов
  2694. */
  2695. if (readQuestInfo) {
  2696. questsInfo[call.ident] = call.result.response;
  2697. }
  2698. /**
  2699. * Getting a user ID
  2700. * Получение идетификатора пользователя
  2701. */
  2702. if (call.ident == callsIdent['registration']) {
  2703. userId = call.result.response.userId;
  2704. if (localStorage['userId'] != userId) {
  2705. localStorage['newGiftSendIds'] = '';
  2706. localStorage['userId'] = userId;
  2707. }
  2708. await openOrMigrateDatabase(userId);
  2709. readQuestInfo = true;
  2710. }
  2711. /**
  2712. * Hiding donation offers 1
  2713. * Скрываем предложения доната 1
  2714. */
  2715. if (call.ident == callsIdent['billingGetAll'] && getSaveVal('noOfferDonat')) {
  2716. const billings = call.result.response?.billings;
  2717. const bundle = call.result.response?.bundle;
  2718. if (billings && bundle) {
  2719. call.result.response.billings = call.result.response.billings.filter((e) => ['repeatableOffer'].includes(e.type));
  2720. call.result.response.bundle = [];
  2721. isChange = true;
  2722. }
  2723. }
  2724. /**
  2725. * Hiding donation offers 2
  2726. * Скрываем предложения доната 2
  2727. */
  2728. if (getSaveVal('noOfferDonat') &&
  2729. (call.ident == callsIdent['offerGetAll'] ||
  2730. call.ident == callsIdent['specialOffer_getAll'])) {
  2731. let offers = call.result.response;
  2732. if (offers) {
  2733. call.result.response = offers.filter(
  2734. (e) => !['addBilling', 'bundleCarousel'].includes(e.type) || ['idleResource', 'stagesOffer'].includes(e.offerType)
  2735. );
  2736. isChange = true;
  2737. }
  2738. }
  2739. /**
  2740. * Hiding donation offers 3
  2741. * Скрываем предложения доната 3
  2742. */
  2743. if (getSaveVal('noOfferDonat') && call.result?.bundleUpdate) {
  2744. delete call.result.bundleUpdate;
  2745. isChange = true;
  2746. }
  2747. /**
  2748. * Hiding donation offers 4
  2749. * Скрываем предложения доната 4
  2750. */
  2751. if (call.result?.specialOffers) {
  2752. const offers = call.result.specialOffers;
  2753. call.result.specialOffers = offers.filter(
  2754. (e) => !['addBilling', 'bundleCarousel'].includes(e.type) || ['idleResource', 'stagesOffer'].includes(e.offerType)
  2755. );
  2756. isChange = true;
  2757. }
  2758. /**
  2759. * Copies a quiz question to the clipboard
  2760. * Копирует вопрос викторины в буфер обмена и получает на него ответ если есть
  2761. */
  2762. if (call.ident == callsIdent['quiz_getNewQuestion']) {
  2763. let quest = call.result.response;
  2764. console.log(quest.question);
  2765. copyText(quest.question);
  2766. setProgress(I18N('QUESTION_COPY'), true);
  2767. quest.lang = null;
  2768. if (typeof NXFlashVars !== 'undefined') {
  2769. quest.lang = NXFlashVars.interface_lang;
  2770. }
  2771. lastQuestion = quest;
  2772. if (isChecked('getAnswer')) {
  2773. const answer = await getAnswer(lastQuestion);
  2774. let showText = '';
  2775. if (answer) {
  2776. lastAnswer = answer;
  2777. console.log(answer);
  2778. showText = `${I18N('ANSWER_KNOWN')}: ${answer}`;
  2779. } else {
  2780. showText = I18N('ANSWER_NOT_KNOWN');
  2781. }
  2782.  
  2783. try {
  2784. const hint = hintQuest(quest);
  2785. if (hint) {
  2786. showText += I18N('HINT') + hint;
  2787. }
  2788. } catch (e) {}
  2789.  
  2790. setProgress(showText, true);
  2791. }
  2792. }
  2793. /**
  2794. * Submits a question with an answer to the database
  2795. * Отправляет вопрос с ответом в базу данных
  2796. */
  2797. if (call.ident == callsIdent['quiz_answer']) {
  2798. const answer = call.result.response;
  2799. if (lastQuestion) {
  2800. const answerInfo = {
  2801. answer,
  2802. question: lastQuestion,
  2803. lang: null,
  2804. };
  2805. if (typeof NXFlashVars !== 'undefined') {
  2806. answerInfo.lang = NXFlashVars.interface_lang;
  2807. }
  2808. lastQuestion = null;
  2809. setTimeout(sendAnswerInfo, 0, answerInfo);
  2810. }
  2811. }
  2812. /**
  2813. * Get user data
  2814. * Получить даныне пользователя
  2815. */
  2816. if (call.ident == callsIdent['userGetInfo']) {
  2817. let user = call.result.response;
  2818. document.title = user.name;
  2819. userInfo = Object.assign({}, user);
  2820. delete userInfo.refillable;
  2821. if (!questsInfo['userGetInfo']) {
  2822. questsInfo['userGetInfo'] = user;
  2823. }
  2824. }
  2825. /**
  2826. * Start of the battle for recalculation
  2827. * Начало боя для прерасчета
  2828. */
  2829. if (call.ident == callsIdent['clanWarAttack'] ||
  2830. call.ident == callsIdent['crossClanWar_startBattle'] ||
  2831. call.ident == callsIdent['bossAttack'] ||
  2832. call.ident == callsIdent['battleGetReplay'] ||
  2833. call.ident == callsIdent['brawl_startBattle'] ||
  2834. call.ident == callsIdent['adventureSolo_turnStartBattle'] ||
  2835. call.ident == callsIdent['invasion_bossStart'] ||
  2836. call.ident == callsIdent['titanArenaStartBattle'] ||
  2837. call.ident == callsIdent['towerStartBattle'] ||
  2838. call.ident == callsIdent['epicBrawl_startBattle'] ||
  2839. call.ident == callsIdent['adventure_turnStartBattle']) {
  2840. let battle = call.result.response.battle || call.result.response.replay;
  2841. if (call.ident == callsIdent['brawl_startBattle'] ||
  2842. call.ident == callsIdent['bossAttack'] ||
  2843. call.ident == callsIdent['towerStartBattle'] ||
  2844. call.ident == callsIdent['invasion_bossStart']) {
  2845. battle = call.result.response;
  2846. }
  2847. lastBattleInfo = battle;
  2848. if (call.ident == callsIdent['battleGetReplay'] && call.result.response.replay.type === "clan_raid") {
  2849. if (call?.result?.response?.replay?.result?.damage) {
  2850. const damages = Object.values(call.result.response.replay.result.damage);
  2851. const bossDamage = damages.reduce((a, v) => a + v, 0);
  2852. setProgress(I18N('BOSS_DAMAGE') + bossDamage.toLocaleString(), false, hideProgress);
  2853. continue;
  2854. }
  2855. }
  2856. if (!isChecked('preCalcBattle')) {
  2857. continue;
  2858. }
  2859. const preCalcBattle = structuredClone(battle);
  2860. setProgress(I18N('BEING_RECALC'));
  2861. let battleDuration = 120;
  2862. try {
  2863. const typeBattle = getBattleType(preCalcBattle.type);
  2864. battleDuration = +lib.data.battleConfig[typeBattle.split('_')[1]].config.battleDuration;
  2865. } catch (e) { }
  2866. //console.log(battle.type);
  2867. function getBattleInfo(battle, isRandSeed) {
  2868. return new Promise(function (resolve) {
  2869. if (isRandSeed) {
  2870. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  2871. }
  2872. BattleCalc(battle, getBattleType(battle.type), e => resolve(e));
  2873. });
  2874. }
  2875. let actions = [getBattleInfo(preCalcBattle, false)];
  2876. let countTestBattle = getInput('countTestBattle');
  2877. if (call.ident == callsIdent['invasion_bossStart'] && preCalcBattle.seed === 8008) {
  2878. countTestBattle = 0;
  2879. }
  2880. if (call.ident == callsIdent['battleGetReplay']) {
  2881. preCalcBattle.progress = [{ attackers: { input: ['auto', 0, 0, 'auto', 0, 0] } }];
  2882. }
  2883. for (let i = 0; i < countTestBattle; i++) {
  2884. actions.push(getBattleInfo(preCalcBattle, true));
  2885. }
  2886. Promise.all(actions)
  2887. .then(e => {
  2888. e = e.map(n => ({win: n.result.win, time: n.battleTime}));
  2889. let firstBattle = e.shift();
  2890. const timer = Math.floor(battleDuration - firstBattle.time);
  2891. const min = ('00' + Math.floor(timer / 60)).slice(-2);
  2892. const sec = ('00' + Math.floor(timer - min * 60)).slice(-2);
  2893. let msg = `${I18N('THIS_TIME')} ${firstBattle.win ? I18N('VICTORY') : I18N('DEFEAT')}`;
  2894. if (e.length) {
  2895. const countWin = e.reduce((w, s) => w + s.win, 0);
  2896. msg += ` ${I18N('CHANCE_TO_WIN')}: ${Math.floor((countWin / e.length) * 100)}% (${e.length})`;
  2897. }
  2898. msg += `, ${min}:${sec}`
  2899. setProgress(msg, false, hideProgress)
  2900. });
  2901. }
  2902. /**
  2903. * Start of the Asgard boss fight
  2904. * Начало боя с боссом Асгарда
  2905. */
  2906. if (call.ident == callsIdent['clanRaid_startBossBattle']) {
  2907. lastBossBattle = call.result.response.battle;
  2908. lastBossBattle.endTime = Date.now() + 160 * 1000;
  2909. if (isChecked('preCalcBattle')) {
  2910. const result = await Calc(lastBossBattle).then(e => e.progress[0].defenders.heroes[1].extra);
  2911. const bossDamage = result.damageTaken + result.damageTakenNextLevel;
  2912. setProgress(I18N('BOSS_DAMAGE') + bossDamage.toLocaleString(), false, hideProgress);
  2913. }
  2914. }
  2915. /**
  2916. * Cancel tutorial
  2917. * Отмена туториала
  2918. */
  2919. if (isCanceledTutorial && call.ident == callsIdent['tutorialGetInfo']) {
  2920. let chains = call.result.response.chains;
  2921. for (let n in chains) {
  2922. chains[n] = 9999;
  2923. }
  2924. isChange = true;
  2925. }
  2926. /**
  2927. * Opening keys and spheres of titan artifacts
  2928. * Открытие ключей и сфер артефактов титанов
  2929. */
  2930. if (artifactChestOpen &&
  2931. (call.ident == callsIdent[artifactChestOpenCallName] ||
  2932. (callsIdent[artifactChestOpenCallName] && callsIdent[artifactChestOpenCallName].includes(call.ident)))) {
  2933. let reward = call.result.response[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'];
  2934.  
  2935. reward.forEach(e => {
  2936. for (let f in e) {
  2937. if (!allReward[f]) {
  2938. allReward[f] = {};
  2939. }
  2940. for (let o in e[f]) {
  2941. if (!allReward[f][o]) {
  2942. allReward[f][o] = e[f][o];
  2943. countTypeReward++;
  2944. } else {
  2945. allReward[f][o] += e[f][o];
  2946. }
  2947. }
  2948. }
  2949. });
  2950.  
  2951. if (!call.ident.includes(artifactChestOpenCallName)) {
  2952. mainReward = call.result.response;
  2953. }
  2954. }
  2955.  
  2956. if (countTypeReward > 20) {
  2957. correctShowOpenArtifact = 3;
  2958. } else {
  2959. correctShowOpenArtifact = 0;
  2960. }
  2961. /**
  2962. * Sum the result of opening Pet Eggs
  2963. * Суммирование результата открытия яиц питомцев
  2964. */
  2965. if (isChecked('countControl') && call.ident == callsIdent['pet_chestOpen']) {
  2966. const rewards = call.result.response.rewards;
  2967. if (rewards.length > 10) {
  2968. /**
  2969. * Removing pet cards
  2970. * Убираем карточки петов
  2971. */
  2972. for (const reward of rewards) {
  2973. if (reward.petCard) {
  2974. delete reward.petCard;
  2975. }
  2976. }
  2977. }
  2978. rewards.forEach(e => {
  2979. for (let f in e) {
  2980. if (!allReward[f]) {
  2981. allReward[f] = {};
  2982. }
  2983. for (let o in e[f]) {
  2984. if (!allReward[f][o]) {
  2985. allReward[f][o] = e[f][o];
  2986. } else {
  2987. allReward[f][o] += e[f][o];
  2988. }
  2989. }
  2990. }
  2991. });
  2992. call.result.response.rewards = [allReward];
  2993. isChange = true;
  2994. }
  2995. /**
  2996. * Removing titan cards
  2997. * Убираем карточки титанов
  2998. */
  2999. if (call.ident == callsIdent['titanUseSummonCircle']) {
  3000. if (call.result.response.rewards.length > 10) {
  3001. for (const reward of call.result.response.rewards) {
  3002. if (reward.titanCard) {
  3003. delete reward.titanCard;
  3004. }
  3005. }
  3006. isChange = true;
  3007. }
  3008. }
  3009. /**
  3010. * Auto-repeat opening matryoshkas
  3011. * АвтоПовтор открытия матрешек
  3012. */
  3013. if (isChecked('countControl') && call.ident == callsIdent['consumableUseLootBox']) {
  3014. let [countLootBox, lootBox] = Object.entries(call.result.response).pop();
  3015. countLootBox = +countLootBox;
  3016. let newCount = 0;
  3017. if (lootBox?.consumable && lootBox.consumable[lastRussianDollId]) {
  3018. newCount += lootBox.consumable[lastRussianDollId];
  3019. delete lootBox.consumable[lastRussianDollId];
  3020. }
  3021. if (
  3022. newCount &&
  3023. (await popup.confirm(`${I18N('BTN_OPEN')} ${newCount} ${I18N('OPEN_DOLLS')}?`, [
  3024. { msg: I18N('BTN_OPEN'), result: true },
  3025. { msg: I18N('BTN_NO'), result: false, isClose: true },
  3026. ]))
  3027. ) {
  3028. const [count, recursionResult] = await openRussianDolls(lastRussianDollId, newCount);
  3029. countLootBox += +count;
  3030. mergeItemsObj(lootBox, recursionResult);
  3031. isChange = true;
  3032. }
  3033.  
  3034. if (this.massOpen) {
  3035. if (
  3036. await popup.confirm(I18N('OPEN_ALL_EQUIP_BOXES'), [
  3037. { msg: I18N('BTN_OPEN'), result: true },
  3038. { msg: I18N('BTN_NO'), result: false, isClose: true },
  3039. ])
  3040. ) {
  3041. const consumable = await Send({ calls: [{ name: 'inventoryGet', args: {}, ident: 'inventoryGet' }] }).then((e) =>
  3042. Object.entries(e.results[0].result.response.consumable)
  3043. );
  3044. const calls = [];
  3045. const deleteItems = {};
  3046. for (const [libId, amount] of consumable) {
  3047. if (libId != this.massOpen && libId >= 362 && libId <= 389) {
  3048. calls.push({
  3049. name: 'consumableUseLootBox',
  3050. args: { libId, amount },
  3051. ident: 'consumableUseLootBox_' + libId,
  3052. });
  3053. deleteItems[libId] = -amount;
  3054. }
  3055. }
  3056. const responses = await Send({ calls }).then((e) => e.results.map((r) => r.result.response).flat());
  3057.  
  3058. for (const loot of responses) {
  3059. const [count, result] = Object.entries(loot).pop();
  3060. countLootBox += +count;
  3061.  
  3062. mergeItemsObj(lootBox, result);
  3063. }
  3064. isChange = true;
  3065.  
  3066. this.onReadySuccess = () => {
  3067. cheats.updateInventory({ consumable: deleteItems });
  3068. cheats.refreshInventory();
  3069. };
  3070. }
  3071. }
  3072.  
  3073. if (isChange) {
  3074. call.result.response = {
  3075. [countLootBox]: lootBox,
  3076. };
  3077. }
  3078. }
  3079. /**
  3080. * Dungeon recalculation (fix endless cards)
  3081. * Прерасчет подземки (исправление бесконечных карт)
  3082. */
  3083. if (call.ident == callsIdent['dungeonStartBattle']) {
  3084. lastDungeonBattleData = call.result.response;
  3085. lastDungeonBattleStart = Date.now();
  3086. }
  3087. /**
  3088. * Getting the number of prediction cards
  3089. * Получение количества карт предсказаний
  3090. */
  3091. if (call.ident == callsIdent['inventoryGet']) {
  3092. HWHData.countPredictionCard = call.result.response.consumable[81] || 0;
  3093. }
  3094. /**
  3095. * Getting subscription status
  3096. * Получение состояния подписки
  3097. */
  3098. if (call.ident == callsIdent['subscriptionGetInfo']) {
  3099. const subscription = call.result.response.subscription;
  3100. if (subscription) {
  3101. subEndTime = subscription.endTime * 1000;
  3102. }
  3103. }
  3104. /**
  3105. * Getting prediction cards
  3106. * Получение карт предсказаний
  3107. */
  3108. if (call.ident == callsIdent['questFarm']) {
  3109. const consumable = call.result.response?.consumable;
  3110. if (consumable && consumable[81]) {
  3111. HWHData.countPredictionCard += consumable[81];
  3112. console.log(`Cards: ${HWHData.countPredictionCard}`);
  3113. }
  3114. }
  3115. /**
  3116. * Hiding extra servers
  3117. * Скрытие лишних серверов
  3118. */
  3119. if (call.ident == callsIdent['serverGetAll'] && isChecked('hideServers')) {
  3120. let servers = call.result.response.users.map(s => s.serverId)
  3121. call.result.response.servers = call.result.response.servers.filter(s => servers.includes(s.id));
  3122. isChange = true;
  3123. }
  3124. /**
  3125. * Displays player positions in the adventure
  3126. * Отображает позиции игроков в приключении
  3127. */
  3128. if (call.ident == callsIdent['adventure_getLobbyInfo']) {
  3129. const users = Object.values(call.result.response.users);
  3130. const mapIdent = call.result.response.mapIdent;
  3131. const adventureId = call.result.response.adventureId;
  3132. const maps = {
  3133. adv_strongford_3pl_hell: 9,
  3134. adv_valley_3pl_hell: 10,
  3135. adv_ghirwil_3pl_hell: 11,
  3136. adv_angels_3pl_hell: 12,
  3137. }
  3138. let msg = I18N('MAP') + (mapIdent in maps ? maps[mapIdent] : adventureId);
  3139. msg += '<br>' + I18N('PLAYER_POS');
  3140. for (const user of users) {
  3141. msg += `<br>${user.user.name} - ${user.currentNode}`;
  3142. }
  3143. setProgress(msg, false, hideProgress);
  3144. }
  3145. /**
  3146. * Automatic launch of a raid at the end of the adventure
  3147. * Автоматический запуск рейда при окончании приключения
  3148. */
  3149. if (call.ident == callsIdent['adventure_end']) {
  3150. autoRaidAdventure()
  3151. }
  3152. /** Удаление лавки редкостей */
  3153. if (call.ident == callsIdent['missionRaid']) {
  3154. if (call.result?.heroesMerchant) {
  3155. delete call.result.heroesMerchant;
  3156. isChange = true;
  3157. }
  3158. }
  3159. /** missionTimer */
  3160. if (call.ident == callsIdent['missionStart']) {
  3161. missionBattle = call.result.response;
  3162. }
  3163. /** Награды турнира стихий */
  3164. if (call.ident == callsIdent['hallOfFameGetTrophies']) {
  3165. const trophys = call.result.response;
  3166. const calls = [];
  3167. for (const week in trophys) {
  3168. const trophy = trophys[week];
  3169. if (!trophy.championRewardFarmed) {
  3170. calls.push({
  3171. name: 'hallOfFameFarmTrophyReward',
  3172. args: { trophyId: week, rewardType: 'champion' },
  3173. ident: 'body_champion_' + week,
  3174. });
  3175. }
  3176. if (Object.keys(trophy.clanReward).length && !trophy.clanRewardFarmed) {
  3177. calls.push({
  3178. name: 'hallOfFameFarmTrophyReward',
  3179. args: { trophyId: week, rewardType: 'clan' },
  3180. ident: 'body_clan_' + week,
  3181. });
  3182. }
  3183. }
  3184. if (calls.length) {
  3185. Send({ calls })
  3186. .then((e) => e.results.map((e) => e.result.response))
  3187. .then(async results => {
  3188. let coin18 = 0,
  3189. coin19 = 0,
  3190. gold = 0,
  3191. starmoney = 0;
  3192. for (const r of results) {
  3193. coin18 += r?.coin ? +r.coin[18] : 0;
  3194. coin19 += r?.coin ? +r.coin[19] : 0;
  3195. gold += r?.gold ? +r.gold : 0;
  3196. starmoney += r?.starmoney ? +r.starmoney : 0;
  3197. }
  3198.  
  3199. let msg = I18N('ELEMENT_TOURNAMENT_REWARD') + '<br>';
  3200. if (coin18) {
  3201. msg += cheats.translate('LIB_COIN_NAME_18') + `: ${coin18}<br>`;
  3202. }
  3203. if (coin19) {
  3204. msg += cheats.translate('LIB_COIN_NAME_19') + `: ${coin19}<br>`;
  3205. }
  3206. if (gold) {
  3207. msg += cheats.translate('LIB_PSEUDO_COIN') + `: ${gold}<br>`;
  3208. }
  3209. if (starmoney) {
  3210. msg += cheats.translate('LIB_PSEUDO_STARMONEY') + `: ${starmoney}<br>`;
  3211. }
  3212.  
  3213. await popup.confirm(msg, [{ msg: I18N('BTN_OK'), result: 0 }]);
  3214. });
  3215. }
  3216. }
  3217. if (call.ident == callsIdent['clanDomination_getInfo']) {
  3218. clanDominationGetInfo = call.result.response;
  3219. }
  3220. if (call.ident == callsIdent['clanRaid_endBossBattle']) {
  3221. console.log(call.result.response);
  3222. const damage = Object.values(call.result.response.damage).reduce((a, e) => a + e);
  3223. if (call.result.response.result.afterInvalid) {
  3224. addProgress('<br>' + I18N('SERVER_NOT_ACCEPT'));
  3225. }
  3226. addProgress('<br>Server > ' + I18N('BOSS_DAMAGE') + damage.toLocaleString());
  3227. }
  3228. if (call.ident == callsIdent['invasion_getInfo']) {
  3229. /*
  3230. const r = call.result.response;
  3231. if (r?.actions?.length) {
  3232. const { invasionInfo, invasionDataPacks } = HWHData;
  3233. const boss = r.actions.find((e) => e.payload.id === invasionInfo.id);
  3234. if (boss) {
  3235. invasionInfo.buff = r.buffAmount;
  3236. invasionInfo.bossLvl = boss.payload.level;
  3237. if (isChecked('tryFixIt_v2')) {
  3238. const pack = invasionDataPacks[invasionInfo.bossLvl];
  3239. if (pack) {
  3240. setProgress(
  3241. I18N('INVASION_BOSS_BUFF', {
  3242. bossLvl: invasionInfo.bossLvl,
  3243. needBuff: pack.buff,
  3244. haveBuff: invasionInfo.buff,
  3245. }),
  3246. false
  3247. );
  3248. }
  3249. }
  3250. }
  3251. }
  3252. */
  3253. }
  3254. if (call.ident == callsIdent['workshopBuff_create']) {
  3255. const r = call.result.response;
  3256. if (r.id == 1) {
  3257. const { invasionInfo, invasionDataPacks } = HWHData;
  3258. invasionInfo.buff = r.amount;
  3259. if (isChecked('tryFixIt_v2')) {
  3260. const pack = invasionDataPacks[invasionInfo.bossLvl];
  3261. if (pack) {
  3262. setProgress(
  3263. I18N('INVASION_BOSS_BUFF', {
  3264. bossLvl: invasionInfo.bossLvl,
  3265. needBuff: pack.buff,
  3266. haveBuff: invasionInfo.buff,
  3267. }),
  3268. false
  3269. );
  3270. }
  3271. }
  3272. }
  3273. }
  3274. if (call.ident == callsIdent['mailFarm']) {
  3275. const letters = Object.values(call.result.response);
  3276. for (const letter of letters) {
  3277. if (letter.consumable?.[81]) {
  3278. console.log('Карты предсказаний', letter.consumable[81]);
  3279. HWHData.countPredictionCard += letter.consumable[81];
  3280. }
  3281. if (letter.refillable?.[45]) {
  3282. console.log('Сферы портала', letter.refillable[45]);
  3283. setPortals(+letter.refillable[45], true);
  3284. }
  3285. }
  3286. }
  3287. if (call.ident == callsIdent['quest_questsFarm']) {
  3288. const rewards = call.result.response;
  3289. for (const reward of rewards) {
  3290. if (reward.consumable?.[81]) {
  3291. console.log('Карты предсказаний', reward.consumable[81]);
  3292. HWHData.countPredictionCard += reward.consumable[81];
  3293. }
  3294. if (reward.refillable?.[45]) {
  3295. console.log('Сферы портала', reward.refillable[45]);
  3296. setPortals(+reward.refillable[45], true);
  3297. }
  3298. }
  3299. }
  3300. if (call.ident == callsIdent['adventure_start']) {
  3301. setPortals(-1, true);
  3302. }
  3303. if (call.ident == callsIdent['clanWarEndBattle']) {
  3304. setWarTries(-1, true);
  3305. }
  3306. if (call.ident == callsIdent['saleShowcase_rewardInfo']) {
  3307. if (new Date(call.result.response.nextRefill * 1000) < Date.now()) {
  3308. const offerId = this?.['saleShowcase_rewardInfo']?.offerId;
  3309. if (offerId) {
  3310. try {
  3311. void Caller.send({ name: 'saleShowcase_farmReward', args: { offerId } });
  3312. } catch (e) {
  3313. console.error(e);
  3314. }
  3315. }
  3316. }
  3317. }
  3318. /*
  3319. if (call.ident == callsIdent['chatGetAll'] && call.args.chatType == 'clanDomination' && !callsIdent['clanDomination_mapState']) {
  3320. this.onReadySuccess = async function () {
  3321. const result = await Send({
  3322. calls: [
  3323. {
  3324. name: 'clanDomination_mapState',
  3325. args: {},
  3326. ident: 'clanDomination_mapState',
  3327. },
  3328. ],
  3329. }).then((e) => e.results[0].result.response);
  3330. let townPositions = result.townPositions;
  3331. let positions = {};
  3332. for (let pos in townPositions) {
  3333. let townPosition = townPositions[pos];
  3334. positions[townPosition.position] = townPosition;
  3335. }
  3336. Object.assign(clanDominationGetInfo, {
  3337. townPositions: positions,
  3338. });
  3339. let userPositions = result.userPositions;
  3340. for (let pos in clanDominationGetInfo.townPositions) {
  3341. let townPosition = clanDominationGetInfo.townPositions[pos];
  3342. if (townPosition.status) {
  3343. userPositions[townPosition.userId] = +pos;
  3344. }
  3345. }
  3346. cheats.updateMap(result);
  3347. };
  3348. }
  3349. if (call.ident == callsIdent['clanDomination_mapState']) {
  3350. const townPositions = call.result.response.townPositions;
  3351. const userPositions = call.result.response.userPositions;
  3352. for (let pos in townPositions) {
  3353. let townPos = townPositions[pos];
  3354. if (townPos.status) {
  3355. userPositions[townPos.userId] = townPos.position;
  3356. }
  3357. }
  3358. isChange = true;
  3359. }
  3360. */
  3361. }
  3362.  
  3363. if (mainReward && artifactChestOpen) {
  3364. console.log(allReward);
  3365. mainReward[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'] = [allReward];
  3366. artifactChestOpen = false;
  3367. artifactChestOpenCallName = '';
  3368. isChange = true;
  3369. }
  3370. } catch(err) {
  3371. console.log("Request(response, " + this.uniqid + "):\n", "Error:\n", response, err);
  3372. }
  3373.  
  3374. if (isChange) {
  3375. Object.defineProperty(this, 'responseText', {
  3376. writable: true
  3377. });
  3378. this.responseText = JSON.stringify(respond);
  3379. }
  3380. }
  3381.  
  3382. /**
  3383. * Request an answer to a question
  3384. *
  3385. * Запрос ответа на вопрос
  3386. */
  3387. async function getAnswer(question) {
  3388. // c29tZSBzdHJhbmdlIHN5bWJvbHM=
  3389. const quizAPI = new ZingerYWebsiteAPI('getAnswer.php', arguments, { question });
  3390. return new Promise((resolve, reject) => {
  3391. quizAPI.request().then((data) => {
  3392. if (data.result) {
  3393. resolve(data.result);
  3394. } else {
  3395. resolve(false);
  3396. }
  3397. }).catch((error) => {
  3398. console.error(error);
  3399. resolve(false);
  3400. });
  3401. })
  3402. }
  3403.  
  3404. /**
  3405. * Submitting a question and answer to a database
  3406. *
  3407. * Отправка вопроса и ответа в базу данных
  3408. */
  3409. function sendAnswerInfo(answerInfo) {
  3410. // c29tZSBub25zZW5zZQ==
  3411. const quizAPI = new ZingerYWebsiteAPI('setAnswer.php', arguments, { answerInfo });
  3412. quizAPI.request().then((data) => {
  3413. if (data.result) {
  3414. console.log(I18N('SENT_QUESTION'));
  3415. }
  3416. });
  3417. }
  3418.  
  3419. /**
  3420. * Returns the battle type by preset type
  3421. *
  3422. * Возвращает тип боя по типу пресета
  3423. */
  3424. function getBattleType(strBattleType) {
  3425. if (!strBattleType) {
  3426. return null;
  3427. }
  3428. switch (strBattleType) {
  3429. case 'titan_pvp':
  3430. return 'get_titanPvp';
  3431. case 'titan_pvp_manual':
  3432. case 'titan_clan_pvp':
  3433. case 'clan_pvp_titan':
  3434. case 'clan_global_pvp_titan':
  3435. case 'brawl_titan':
  3436. case 'challenge_titan':
  3437. case 'titan_mission':
  3438. return 'get_titanPvpManual';
  3439. case 'clan_raid': // Asgard Boss // Босс асгарда
  3440. case 'adventure': // Adventures // Приключения
  3441. case 'clan_global_pvp':
  3442. case 'epic_brawl':
  3443. case 'clan_pvp':
  3444. return 'get_clanPvp';
  3445. case 'dungeon_titan':
  3446. case 'titan_tower':
  3447. return 'get_titan';
  3448. case 'tower':
  3449. case 'clan_dungeon':
  3450. return 'get_tower';
  3451. case 'pve':
  3452. case 'mission':
  3453. return 'get_pve';
  3454. case 'mission_boss':
  3455. return 'get_missionBoss';
  3456. case 'challenge':
  3457. case 'pvp_manual':
  3458. return 'get_pvpManual';
  3459. case 'grand':
  3460. case 'arena':
  3461. case 'pvp':
  3462. case 'clan_domination':
  3463. return 'get_pvp';
  3464. case 'core':
  3465. return 'get_core';
  3466. default: {
  3467. if (strBattleType.includes('invasion')) {
  3468. return 'get_invasion';
  3469. }
  3470. if (strBattleType.includes('boss')) {
  3471. return 'get_boss';
  3472. }
  3473. if (strBattleType.includes('titan_arena')) {
  3474. return 'get_titanPvpManual';
  3475. }
  3476. return 'get_clanPvp';
  3477. }
  3478. }
  3479. }
  3480. /**
  3481. * Returns the class name of the passed object
  3482. *
  3483. * Возвращает название класса переданного объекта
  3484. */
  3485. function getClass(obj) {
  3486. return {}.toString.call(obj).slice(8, -1);
  3487. }
  3488. /**
  3489. * Calculates the request signature
  3490. *
  3491. * Расчитывает сигнатуру запроса
  3492. */
  3493. this.getSignature = function(headers, data) {
  3494. const sign = {
  3495. signature: '',
  3496. length: 0,
  3497. add: function (text) {
  3498. this.signature += text;
  3499. if (this.length < this.signature.length) {
  3500. this.length = 3 * (this.signature.length + 1) >> 1;
  3501. }
  3502. },
  3503. }
  3504. sign.add(headers["X-Request-Id"]);
  3505. sign.add(':');
  3506. sign.add(headers["X-Auth-Token"]);
  3507. sign.add(':');
  3508. sign.add(headers["X-Auth-Session-Id"]);
  3509. sign.add(':');
  3510. sign.add(data);
  3511. sign.add(':');
  3512. sign.add('LIBRARY-VERSION=1');
  3513. sign.add('UNIQUE-SESSION-ID=' + headers["X-Env-Unique-Session-Id"]);
  3514.  
  3515. return md5(sign.signature);
  3516. }
  3517.  
  3518. class HotkeyManager {
  3519. constructor() {
  3520. if (HotkeyManager.instance) {
  3521. return HotkeyManager.instance;
  3522. }
  3523. this.hotkeys = [];
  3524. document.addEventListener('keydown', this.handleKeyDown.bind(this));
  3525. HotkeyManager.instance = this;
  3526. }
  3527.  
  3528. handleKeyDown(event) {
  3529. const key = event.key.toLowerCase();
  3530. const mods = {
  3531. ctrl: event.ctrlKey,
  3532. alt: event.altKey,
  3533. shift: event.shiftKey,
  3534. };
  3535.  
  3536. this.hotkeys.forEach((hotkey) => {
  3537. if (hotkey.key === key && hotkey.ctrl === mods.ctrl && hotkey.alt === mods.alt && hotkey.shift === mods.shift) {
  3538. hotkey.callback(hotkey);
  3539. }
  3540. });
  3541. }
  3542.  
  3543. add(key, opt = {}, callback) {
  3544. this.hotkeys.push({
  3545. key: key.toLowerCase(),
  3546. callback,
  3547. ctrl: opt.ctrl || false,
  3548. alt: opt.alt || false,
  3549. shift: opt.shift || false,
  3550. });
  3551. }
  3552.  
  3553. remove(key, opt = {}) {
  3554. this.hotkeys = this.hotkeys.filter((hotkey) => {
  3555. return !(
  3556. hotkey.key === key.toLowerCase() &&
  3557. hotkey.ctrl === (opt.ctrl || false) &&
  3558. hotkey.alt === (opt.alt || false) &&
  3559. hotkey.shift === (opt.shift || false)
  3560. );
  3561. });
  3562. }
  3563.  
  3564. static getInst() {
  3565. if (!HotkeyManager.instance) {
  3566. new HotkeyManager();
  3567. }
  3568. return HotkeyManager.instance;
  3569. }
  3570. }
  3571.  
  3572. class MouseClicker {
  3573. constructor(element) {
  3574. if (MouseClicker.instance) {
  3575. return MouseClicker.instance;
  3576. }
  3577. this.element = element;
  3578. this.mouse = {
  3579. bubbles: true,
  3580. cancelable: true,
  3581. clientX: 0,
  3582. clientY: 0,
  3583. };
  3584. this.element.addEventListener('mousemove', this.handleMouseMove.bind(this));
  3585. this.clickInfo = {};
  3586. this.nextTimeoutId = 1;
  3587. MouseClicker.instance = this;
  3588. }
  3589.  
  3590. handleMouseMove(event) {
  3591. this.mouse.clientX = event.clientX;
  3592. this.mouse.clientY = event.clientY;
  3593. }
  3594.  
  3595. click(options) {
  3596. options = options || this.mouse;
  3597. this.element.dispatchEvent(new MouseEvent('mousedown', options));
  3598. this.element.dispatchEvent(new MouseEvent('mouseup', options));
  3599. }
  3600.  
  3601. start(interval = 1000, clickCount = Infinity) {
  3602. const currentMouse = { ...this.mouse };
  3603. const timeoutId = this.nextTimeoutId++;
  3604. let count = 0;
  3605.  
  3606. const clickTimeout = () => {
  3607. this.click(currentMouse);
  3608. count++;
  3609. if (count < clickCount) {
  3610. this.clickInfo[timeoutId].timeout = setTimeout(clickTimeout, interval);
  3611. } else {
  3612. delete this.clickInfo[timeoutId];
  3613. }
  3614. };
  3615.  
  3616. this.clickInfo[timeoutId] = {
  3617. timeout: setTimeout(clickTimeout, interval),
  3618. count: clickCount,
  3619. };
  3620. return timeoutId;
  3621. }
  3622.  
  3623. stop(timeoutId) {
  3624. if (this.clickInfo[timeoutId]) {
  3625. clearTimeout(this.clickInfo[timeoutId].timeout);
  3626. delete this.clickInfo[timeoutId];
  3627. }
  3628. }
  3629.  
  3630. stopAll() {
  3631. for (const timeoutId in this.clickInfo) {
  3632. clearTimeout(this.clickInfo[timeoutId].timeout);
  3633. }
  3634. this.clickInfo = {};
  3635. }
  3636.  
  3637. static getInst(element) {
  3638. if (!MouseClicker.instance) {
  3639. new MouseClicker(element);
  3640. }
  3641. return MouseClicker.instance;
  3642. }
  3643. }
  3644.  
  3645. let extintionsList = [];
  3646. /**
  3647. * Creates an interface
  3648. *
  3649. * Создает интерфейс
  3650. */
  3651. function createInterface() {
  3652. popup.init();
  3653. const { ScriptMenu } = HWHClasses;
  3654. const scriptMenu = ScriptMenu.getInst();
  3655. scriptMenu.init();
  3656. scriptMenu.addHeader(GM_info.script.name, justInfo);
  3657. const versionHeader = scriptMenu.addHeader('v' + GM_info.script.version);
  3658. if (extintionsList.length) {
  3659. versionHeader.title = '';
  3660. versionHeader.style.color = 'red';
  3661. for (const extintion of extintionsList) {
  3662. const { name, ver, author } = extintion;
  3663. versionHeader.title += name + ', v' + ver + ' by ' + author + '\n';
  3664. }
  3665. }
  3666. // AutoClicker
  3667. const hkm = new HotkeyManager();
  3668. const fc = document.getElementById('flash-content') || document.getElementById('game');
  3669. const mc = new MouseClicker(fc);
  3670. function toggleClicker(self, timeout) {
  3671. if (self.onClick) {
  3672. console.log('Останавливаем клики');
  3673. mc.stop(self.onClick);
  3674. self.onClick = false;
  3675. } else {
  3676. console.log('Стартуем клики');
  3677. self.onClick = mc.start(timeout);
  3678. }
  3679. }
  3680. hkm.add('C', { ctrl: true, alt: true }, (self) => {
  3681. console.log('"Ctrl + Alt + C"');
  3682. toggleClicker(self, 20);
  3683. });
  3684. hkm.add('V', { ctrl: true, alt: true }, (self) => {
  3685. console.log('"Ctrl + Alt + V"');
  3686. toggleClicker(self, 100);
  3687. });
  3688. }
  3689.  
  3690. function addExtentionName(name, ver, author) {
  3691. extintionsList.push({
  3692. name,
  3693. ver,
  3694. author,
  3695. });
  3696. }
  3697.  
  3698. function addControls() {
  3699. createInterface();
  3700. const { ScriptMenu } = HWHClasses;
  3701. const scriptMenu = ScriptMenu.getInst();
  3702. const checkboxDetails = scriptMenu.addDetails(I18N('SETTINGS'), 'settings');
  3703. const { checkboxes } = HWHData;
  3704. for (let name in checkboxes) {
  3705. if (checkboxes[name].hide) {
  3706. continue;
  3707. }
  3708. checkboxes[name].cbox = scriptMenu.addCheckbox(checkboxes[name].label, checkboxes[name].title, checkboxDetails);
  3709. /**
  3710. * Getting the state of checkboxes from storage
  3711. * Получаем состояние чекбоксов из storage
  3712. */
  3713. let val = storage.get(name, null);
  3714. if (val != null) {
  3715. checkboxes[name].cbox.checked = val;
  3716. } else {
  3717. storage.set(name, checkboxes[name].default);
  3718. checkboxes[name].cbox.checked = checkboxes[name].default;
  3719. }
  3720. /**
  3721. * Tracing the change event of the checkbox for writing to storage
  3722. * Отсеживание события изменения чекбокса для записи в storage
  3723. */
  3724. checkboxes[name].cbox.dataset['name'] = name;
  3725. checkboxes[name].cbox.addEventListener('change', async function (event) {
  3726. const nameCheckbox = this.dataset['name'];
  3727. /*
  3728. if (this.checked && nameCheckbox == 'cancelBattle') {
  3729. this.checked = false;
  3730. if (await popup.confirm(I18N('MSG_BAN_ATTENTION'), [
  3731. { msg: I18N('BTN_NO_I_AM_AGAINST'), result: true },
  3732. { msg: I18N('BTN_YES_I_AGREE'), result: false },
  3733. ])) {
  3734. return;
  3735. }
  3736. this.checked = true;
  3737. }
  3738. */
  3739. storage.set(nameCheckbox, this.checked);
  3740. })
  3741. }
  3742.  
  3743. const inputDetails = scriptMenu.addDetails(I18N('VALUES'), 'values');
  3744. const { inputs } = HWHData;
  3745. for (let name in inputs) {
  3746. inputs[name].input = scriptMenu.addInputText(inputs[name].title, false, inputDetails);
  3747. /**
  3748. * Get inputText state from storage
  3749. * Получаем состояние inputText из storage
  3750. */
  3751. let val = storage.get(name, null);
  3752. if (val != null) {
  3753. inputs[name].input.value = val;
  3754. } else {
  3755. storage.set(name, inputs[name].default);
  3756. inputs[name].input.value = inputs[name].default;
  3757. }
  3758. /**
  3759. * Tracing a field change event for a record in storage
  3760. * Отсеживание события изменения поля для записи в storage
  3761. */
  3762. inputs[name].input.dataset['name'] = name;
  3763. inputs[name].input.addEventListener('input', function () {
  3764. const inputName = this.dataset['name'];
  3765. let value = +this.value;
  3766. if (!value || Number.isNaN(value)) {
  3767. value = storage.get(inputName, inputs[inputName].default);
  3768. inputs[name].input.value = value;
  3769. }
  3770. storage.set(inputName, value);
  3771. })
  3772. }
  3773. }
  3774.  
  3775. /**
  3776. * Sending a request
  3777. *
  3778. * Отправка запроса
  3779. */
  3780. function send(json, callback, pr) {
  3781. if (typeof json == 'string') {
  3782. json = JSON.parse(json);
  3783. }
  3784. for (const call of json.calls) {
  3785. if (!call?.context?.actionTs) {
  3786. call.context = {
  3787. actionTs: Math.floor(performance.now())
  3788. }
  3789. }
  3790. }
  3791. json = JSON.stringify(json);
  3792. /**
  3793. * We get the headlines of the previous intercepted request
  3794. * Получаем заголовки предыдущего перехваченого запроса
  3795. */
  3796. let headers = lastHeaders;
  3797. /**
  3798. * We increase the header of the query Certifier by 1
  3799. * Увеличиваем заголовок идетификатора запроса на 1
  3800. */
  3801. headers["X-Request-Id"]++;
  3802. /**
  3803. * We calculate the title with the signature
  3804. * Расчитываем заголовок с сигнатурой
  3805. */
  3806. headers["X-Auth-Signature"] = getSignature(headers, json);
  3807. /**
  3808. * Create a new ajax request
  3809. * Создаем новый AJAX запрос
  3810. */
  3811. let xhr = new XMLHttpRequest;
  3812. /**
  3813. * Indicate the previously saved URL for API queries
  3814. * Указываем ранее сохраненный URL для API запросов
  3815. */
  3816. xhr.open('POST', apiUrl, true);
  3817. /**
  3818. * Add the function to the event change event
  3819. * Добавляем функцию к событию смены статуса запроса
  3820. */
  3821. xhr.onreadystatechange = function() {
  3822. /**
  3823. * If the result of the request is obtained, we call the flask function
  3824. * Если результат запроса получен вызываем колбек функцию
  3825. */
  3826. if(xhr.readyState == 4) {
  3827. callback(xhr.response, pr);
  3828. }
  3829. };
  3830. /**
  3831. * Indicate the type of request
  3832. * Указываем тип запроса
  3833. */
  3834. xhr.responseType = 'json';
  3835. /**
  3836. * We set the request headers
  3837. * Задаем заголовки запроса
  3838. */
  3839. for(let nameHeader in headers) {
  3840. let head = headers[nameHeader];
  3841. xhr.setRequestHeader(nameHeader, head);
  3842. }
  3843. /**
  3844. * Sending a request
  3845. * Отправляем запрос
  3846. */
  3847. xhr.send(json);
  3848. }
  3849.  
  3850. let hideTimeoutProgress = 0;
  3851. /**
  3852. * Hide progress
  3853. *
  3854. * Скрыть прогресс
  3855. */
  3856. function hideProgress(timeout) {
  3857. const { ScriptMenu } = HWHClasses;
  3858. const scriptMenu = ScriptMenu.getInst();
  3859. timeout = timeout || 0;
  3860. clearTimeout(hideTimeoutProgress);
  3861. hideTimeoutProgress = setTimeout(function () {
  3862. scriptMenu.setStatus('');
  3863. }, timeout);
  3864. }
  3865. /**
  3866. * Progress display
  3867. *
  3868. * Отображение прогресса
  3869. */
  3870. function setProgress(text, hide, onclick) {
  3871. const { ScriptMenu } = HWHClasses;
  3872. const scriptMenu = ScriptMenu.getInst();
  3873. scriptMenu.setStatus(text, onclick);
  3874. hide = hide || false;
  3875. if (hide) {
  3876. hideProgress(3000);
  3877. }
  3878. }
  3879.  
  3880. /**
  3881. * Progress added
  3882. *
  3883. * Дополнение прогресса
  3884. */
  3885. function addProgress(text) {
  3886. const { ScriptMenu } = HWHClasses;
  3887. const scriptMenu = ScriptMenu.getInst();
  3888. scriptMenu.addStatus(text);
  3889. }
  3890.  
  3891. /**
  3892. * Returns the timer value depending on the subscription
  3893. *
  3894. * Возвращает значение таймера в зависимости от подписки
  3895. */
  3896. function getTimer(time, div) {
  3897. let speedDiv = 5;
  3898. if (subEndTime < Date.now()) {
  3899. speedDiv = div || 1.5;
  3900. }
  3901. return Math.max(Math.ceil(time / speedDiv + 1.5), 4);
  3902. }
  3903.  
  3904. function startSlave() {
  3905. const { slaveFixBattle } = HWHClasses;
  3906. const sFix = new slaveFixBattle();
  3907. sFix.wsStart();
  3908. }
  3909.  
  3910. this.testFuntions = {
  3911. hideProgress,
  3912. setProgress,
  3913. addProgress,
  3914. masterFix: false,
  3915. startSlave,
  3916. };
  3917.  
  3918. this.HWHFuncs = {
  3919. send,
  3920. I18N,
  3921. isChecked,
  3922. getInput,
  3923. copyText,
  3924. confShow,
  3925. hideProgress,
  3926. setProgress,
  3927. addProgress,
  3928. getTimer,
  3929. addExtentionName,
  3930. getUserInfo,
  3931. setIsCancalBattle,
  3932. random,
  3933. };
  3934.  
  3935. this.HWHClasses = {
  3936. checkChangeSend,
  3937. checkChangeResponse,
  3938. };
  3939.  
  3940. this.HWHData = {
  3941. i18nLangData,
  3942. checkboxes,
  3943. inputs,
  3944. buttons,
  3945. invasionInfo,
  3946. invasionDataPacks,
  3947. countPredictionCard,
  3948. };
  3949.  
  3950. /**
  3951. * Calculates HASH MD5 from string
  3952. *
  3953. * Расчитывает HASH MD5 из строки
  3954. *
  3955. * [js-md5]{@link https://github.com/emn178/js-md5}
  3956. *
  3957. * @namespace md5
  3958. * @version 0.7.3
  3959. * @author Chen, Yi-Cyuan [emn178@gmail.com]
  3960. * @copyright Chen, Yi-Cyuan 2014-2017
  3961. * @license MIT
  3962. */
  3963. !function(){"use strict";function t(t){if(t)d[0]=d[16]=d[1]=d[2]=d[3]=d[4]=d[5]=d[6]=d[7]=d[8]=d[9]=d[10]=d[11]=d[12]=d[13]=d[14]=d[15]=0,this.blocks=d,this.buffer8=l;else if(a){var r=new ArrayBuffer(68);this.buffer8=new Uint8Array(r),this.blocks=new Uint32Array(r)}else this.blocks=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];this.h0=this.h1=this.h2=this.h3=this.start=this.bytes=this.hBytes=0,this.finalized=this.hashed=!1,this.first=!0}var r="input is invalid type",e="object"==typeof window,i=e?window:{};i.JS_MD5_NO_WINDOW&&(e=!1);var s=!e&&"object"==typeof self,h=!i.JS_MD5_NO_NODE_JS&&"object"==typeof process&&process.versions&&process.versions.node;h?i=global:s&&(i=self);var f=!i.JS_MD5_NO_COMMON_JS&&"object"==typeof module&&module.exports,o="function"==typeof define&&define.amd,a=!i.JS_MD5_NO_ARRAY_BUFFER&&"undefined"!=typeof ArrayBuffer,n="0123456789abcdef".split(""),u=[128,32768,8388608,-2147483648],y=[0,8,16,24],c=["hex","array","digest","buffer","arrayBuffer","base64"],p="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""),d=[],l;if(a){var A=new ArrayBuffer(68);l=new Uint8Array(A),d=new Uint32Array(A)}!i.JS_MD5_NO_NODE_JS&&Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),!a||!i.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW&&ArrayBuffer.isView||(ArrayBuffer.isView=function(t){return"object"==typeof t&&t.buffer&&t.buffer.constructor===ArrayBuffer});var b=function(r){return function(e){return new t(!0).update(e)[r]()}},v=function(){var r=b("hex");h&&(r=w(r)),r.create=function(){return new t},r.update=function(t){return r.create().update(t)};for(var e=0;e<c.length;++e){var i=c[e];r[i]=b(i)}return r},w=function(t){var e=eval("require('crypto')"),i=eval("require('buffer').Buffer"),s=function(s){if("string"==typeof s)return e.createHash("md5").update(s,"utf8").digest("hex");if(null===s||void 0===s)throw r;return s.constructor===ArrayBuffer&&(s=new Uint8Array(s)),Array.isArray(s)||ArrayBuffer.isView(s)||s.constructor===i?e.createHash("md5").update(new i(s)).digest("hex"):t(s)};return s};t.prototype.update=function(t){if(!this.finalized){var e,i=typeof t;if("string"!==i){if("object"!==i)throw r;if(null===t)throw r;if(a&&t.constructor===ArrayBuffer)t=new Uint8Array(t);else if(!(Array.isArray(t)||a&&ArrayBuffer.isView(t)))throw r;e=!0}for(var s,h,f=0,o=t.length,n=this.blocks,u=this.buffer8;f<o;){if(this.hashed&&(this.hashed=!1,n[0]=n[16],n[16]=n[1]=n[2]=n[3]=n[4]=n[5]=n[6]=n[7]=n[8]=n[9]=n[10]=n[11]=n[12]=n[13]=n[14]=n[15]=0),e)if(a)for(h=this.start;f<o&&h<64;++f)u[h++]=t[f];else for(h=this.start;f<o&&h<64;++f)n[h>>2]|=t[f]<<y[3&h++];else if(a)for(h=this.start;f<o&&h<64;++f)(s=t.charCodeAt(f))<128?u[h++]=s:s<2048?(u[h++]=192|s>>6,u[h++]=128|63&s):s<55296||s>=57344?(u[h++]=224|s>>12,u[h++]=128|s>>6&63,u[h++]=128|63&s):(s=65536+((1023&s)<<10|1023&t.charCodeAt(++f)),u[h++]=240|s>>18,u[h++]=128|s>>12&63,u[h++]=128|s>>6&63,u[h++]=128|63&s);else for(h=this.start;f<o&&h<64;++f)(s=t.charCodeAt(f))<128?n[h>>2]|=s<<y[3&h++]:s<2048?(n[h>>2]|=(192|s>>6)<<y[3&h++],n[h>>2]|=(128|63&s)<<y[3&h++]):s<55296||s>=57344?(n[h>>2]|=(224|s>>12)<<y[3&h++],n[h>>2]|=(128|s>>6&63)<<y[3&h++],n[h>>2]|=(128|63&s)<<y[3&h++]):(s=65536+((1023&s)<<10|1023&t.charCodeAt(++f)),n[h>>2]|=(240|s>>18)<<y[3&h++],n[h>>2]|=(128|s>>12&63)<<y[3&h++],n[h>>2]|=(128|s>>6&63)<<y[3&h++],n[h>>2]|=(128|63&s)<<y[3&h++]);this.lastByteIndex=h,this.bytes+=h-this.start,h>=64?(this.start=h-64,this.hash(),this.hashed=!0):this.start=h}return this.bytes>4294967295&&(this.hBytes+=this.bytes/4294967296<<0,this.bytes=this.bytes%4294967296),this}},t.prototype.finalize=function(){if(!this.finalized){this.finalized=!0;var t=this.blocks,r=this.lastByteIndex;t[r>>2]|=u[3&r],r>=56&&(this.hashed||this.hash(),t[0]=t[16],t[16]=t[1]=t[2]=t[3]=t[4]=t[5]=t[6]=t[7]=t[8]=t[9]=t[10]=t[11]=t[12]=t[13]=t[14]=t[15]=0),t[14]=this.bytes<<3,t[15]=this.hBytes<<3|this.bytes>>>29,this.hash()}},t.prototype.hash=function(){var t,r,e,i,s,h,f=this.blocks;this.first?r=((r=((t=((t=f[0]-680876937)<<7|t>>>25)-271733879<<0)^(e=((e=(-271733879^(i=((i=(-1732584194^2004318071&t)+f[1]-117830708)<<12|i>>>20)+t<<0)&(-271733879^t))+f[2]-1126478375)<<17|e>>>15)+i<<0)&(i^t))+f[3]-1316259209)<<22|r>>>10)+e<<0:(t=this.h0,r=this.h1,e=this.h2,r=((r+=((t=((t+=((i=this.h3)^r&(e^i))+f[0]-680876936)<<7|t>>>25)+r<<0)^(e=((e+=(r^(i=((i+=(e^t&(r^e))+f[1]-389564586)<<12|i>>>20)+t<<0)&(t^r))+f[2]+606105819)<<17|e>>>15)+i<<0)&(i^t))+f[3]-1044525330)<<22|r>>>10)+e<<0),r=((r+=((t=((t+=(i^r&(e^i))+f[4]-176418897)<<7|t>>>25)+r<<0)^(e=((e+=(r^(i=((i+=(e^t&(r^e))+f[5]+1200080426)<<12|i>>>20)+t<<0)&(t^r))+f[6]-1473231341)<<17|e>>>15)+i<<0)&(i^t))+f[7]-45705983)<<22|r>>>10)+e<<0,r=((r+=((t=((t+=(i^r&(e^i))+f[8]+1770035416)<<7|t>>>25)+r<<0)^(e=((e+=(r^(i=((i+=(e^t&(r^e))+f[9]-1958414417)<<12|i>>>20)+t<<0)&(t^r))+f[10]-42063)<<17|e>>>15)+i<<0)&(i^t))+f[11]-1990404162)<<22|r>>>10)+e<<0,r=((r+=((t=((t+=(i^r&(e^i))+f[12]+1804603682)<<7|t>>>25)+r<<0)^(e=((e+=(r^(i=((i+=(e^t&(r^e))+f[13]-40341101)<<12|i>>>20)+t<<0)&(t^r))+f[14]-1502002290)<<17|e>>>15)+i<<0)&(i^t))+f[15]+1236535329)<<22|r>>>10)+e<<0,r=((r+=((i=((i+=(r^e&((t=((t+=(e^i&(r^e))+f[1]-165796510)<<5|t>>>27)+r<<0)^r))+f[6]-1069501632)<<9|i>>>23)+t<<0)^t&((e=((e+=(t^r&(i^t))+f[11]+643717713)<<14|e>>>18)+i<<0)^i))+f[0]-373897302)<<20|r>>>12)+e<<0,r=((r+=((i=((i+=(r^e&((t=((t+=(e^i&(r^e))+f[5]-701558691)<<5|t>>>27)+r<<0)^r))+f[10]+38016083)<<9|i>>>23)+t<<0)^t&((e=((e+=(t^r&(i^t))+f[15]-660478335)<<14|e>>>18)+i<<0)^i))+f[4]-405537848)<<20|r>>>12)+e<<0,r=((r+=((i=((i+=(r^e&((t=((t+=(e^i&(r^e))+f[9]+568446438)<<5|t>>>27)+r<<0)^r))+f[14]-1019803690)<<9|i>>>23)+t<<0)^t&((e=((e+=(t^r&(i^t))+f[3]-187363961)<<14|e>>>18)+i<<0)^i))+f[8]+1163531501)<<20|r>>>12)+e<<0,r=((r+=((i=((i+=(r^e&((t=((t+=(e^i&(r^e))+f[13]-1444681467)<<5|t>>>27)+r<<0)^r))+f[2]-51403784)<<9|i>>>23)+t<<0)^t&((e=((e+=(t^r&(i^t))+f[7]+1735328473)<<14|e>>>18)+i<<0)^i))+f[12]-1926607734)<<20|r>>>12)+e<<0,r=((r+=((h=(i=((i+=((s=r^e)^(t=((t+=(s^i)+f[5]-378558)<<4|t>>>28)+r<<0))+f[8]-2022574463)<<11|i>>>21)+t<<0)^t)^(e=((e+=(h^r)+f[11]+1839030562)<<16|e>>>16)+i<<0))+f[14]-35309556)<<23|r>>>9)+e<<0,r=((r+=((h=(i=((i+=((s=r^e)^(t=((t+=(s^i)+f[1]-1530992060)<<4|t>>>28)+r<<0))+f[4]+1272893353)<<11|i>>>21)+t<<0)^t)^(e=((e+=(h^r)+f[7]-155497632)<<16|e>>>16)+i<<0))+f[10]-1094730640)<<23|r>>>9)+e<<0,r=((r+=((h=(i=((i+=((s=r^e)^(t=((t+=(s^i)+f[13]+681279174)<<4|t>>>28)+r<<0))+f[0]-358537222)<<11|i>>>21)+t<<0)^t)^(e=((e+=(h^r)+f[3]-722521979)<<16|e>>>16)+i<<0))+f[6]+76029189)<<23|r>>>9)+e<<0,r=((r+=((h=(i=((i+=((s=r^e)^(t=((t+=(s^i)+f[9]-640364487)<<4|t>>>28)+r<<0))+f[12]-421815835)<<11|i>>>21)+t<<0)^t)^(e=((e+=(h^r)+f[15]+530742520)<<16|e>>>16)+i<<0))+f[2]-995338651)<<23|r>>>9)+e<<0,r=((r+=((i=((i+=(r^((t=((t+=(e^(r|~i))+f[0]-198630844)<<6|t>>>26)+r<<0)|~e))+f[7]+1126891415)<<10|i>>>22)+t<<0)^((e=((e+=(t^(i|~r))+f[14]-1416354905)<<15|e>>>17)+i<<0)|~t))+f[5]-57434055)<<21|r>>>11)+e<<0,r=((r+=((i=((i+=(r^((t=((t+=(e^(r|~i))+f[12]+1700485571)<<6|t>>>26)+r<<0)|~e))+f[3]-1894986606)<<10|i>>>22)+t<<0)^((e=((e+=(t^(i|~r))+f[10]-1051523)<<15|e>>>17)+i<<0)|~t))+f[1]-2054922799)<<21|r>>>11)+e<<0,r=((r+=((i=((i+=(r^((t=((t+=(e^(r|~i))+f[8]+1873313359)<<6|t>>>26)+r<<0)|~e))+f[15]-30611744)<<10|i>>>22)+t<<0)^((e=((e+=(t^(i|~r))+f[6]-1560198380)<<15|e>>>17)+i<<0)|~t))+f[13]+1309151649)<<21|r>>>11)+e<<0,r=((r+=((i=((i+=(r^((t=((t+=(e^(r|~i))+f[4]-145523070)<<6|t>>>26)+r<<0)|~e))+f[11]-1120210379)<<10|i>>>22)+t<<0)^((e=((e+=(t^(i|~r))+f[2]+718787259)<<15|e>>>17)+i<<0)|~t))+f[9]-343485551)<<21|r>>>11)+e<<0,this.first?(this.h0=t+1732584193<<0,this.h1=r-271733879<<0,this.h2=e-1732584194<<0,this.h3=i+271733878<<0,this.first=!1):(this.h0=this.h0+t<<0,this.h1=this.h1+r<<0,this.h2=this.h2+e<<0,this.h3=this.h3+i<<0)},t.prototype.hex=function(){this.finalize();var t=this.h0,r=this.h1,e=this.h2,i=this.h3;return n[t>>4&15]+n[15&t]+n[t>>12&15]+n[t>>8&15]+n[t>>20&15]+n[t>>16&15]+n[t>>28&15]+n[t>>24&15]+n[r>>4&15]+n[15&r]+n[r>>12&15]+n[r>>8&15]+n[r>>20&15]+n[r>>16&15]+n[r>>28&15]+n[r>>24&15]+n[e>>4&15]+n[15&e]+n[e>>12&15]+n[e>>8&15]+n[e>>20&15]+n[e>>16&15]+n[e>>28&15]+n[e>>24&15]+n[i>>4&15]+n[15&i]+n[i>>12&15]+n[i>>8&15]+n[i>>20&15]+n[i>>16&15]+n[i>>28&15]+n[i>>24&15]},t.prototype.toString=t.prototype.hex,t.prototype.digest=function(){this.finalize();var t=this.h0,r=this.h1,e=this.h2,i=this.h3;return[255&t,t>>8&255,t>>16&255,t>>24&255,255&r,r>>8&255,r>>16&255,r>>24&255,255&e,e>>8&255,e>>16&255,e>>24&255,255&i,i>>8&255,i>>16&255,i>>24&255]},t.prototype.array=t.prototype.digest,t.prototype.arrayBuffer=function(){this.finalize();var t=new ArrayBuffer(16),r=new Uint32Array(t);return r[0]=this.h0,r[1]=this.h1,r[2]=this.h2,r[3]=this.h3,t},t.prototype.buffer=t.prototype.arrayBuffer,t.prototype.base64=function(){for(var t,r,e,i="",s=this.array(),h=0;h<15;)t=s[h++],r=s[h++],e=s[h++],i+=p[t>>>2]+p[63&(t<<4|r>>>4)]+p[63&(r<<2|e>>>6)]+p[63&e];return t=s[h],i+=p[t>>>2]+p[t<<4&63]+"=="};var _=v();f?module.exports=_:(i.md5=_,o&&define(function(){return _}))}();
  3964.  
  3965. class Caller {
  3966. static globalHooks = {
  3967. onError: null,
  3968. };
  3969.  
  3970. constructor(calls = null) {
  3971. this.calls = [];
  3972. this.results = {};
  3973. this.sideResults = {};
  3974. if (calls) {
  3975. this.add(calls);
  3976. }
  3977. }
  3978.  
  3979. static setGlobalHook(event, callback) {
  3980. if (this.globalHooks[event] !== undefined) {
  3981. this.globalHooks[event] = callback;
  3982. } else {
  3983. throw new Error(`Unknown event: ${event}`);
  3984. }
  3985. }
  3986.  
  3987. addCall(call) {
  3988. const { name = call, args = {} } = typeof call === 'object' ? call : { name: call };
  3989. this.calls.push({ name, args });
  3990. return this;
  3991. }
  3992.  
  3993. add(name) {
  3994. if (Array.isArray(name)) {
  3995. name.forEach((call) => this.addCall(call));
  3996. } else {
  3997. this.addCall(name);
  3998. }
  3999. return this;
  4000. }
  4001.  
  4002. handleError(error) {
  4003. const errorName = error.name;
  4004. const errorDescription = error.description;
  4005.  
  4006. if (Caller.globalHooks.onError) {
  4007. const shouldThrow = Caller.globalHooks.onError(error);
  4008. if (shouldThrow === false) {
  4009. return;
  4010. }
  4011. }
  4012.  
  4013. if (error.call) {
  4014. const callInfo = error.call;
  4015. throw new Error(`${errorName} in ${callInfo.name}: ${errorDescription}\n` + `Args: ${JSON.stringify(callInfo.args)}\n`);
  4016. } else if (errorName === 'common\\rpc\\exception\\InvalidRequest') {
  4017. throw new Error(`Invalid request: ${errorDescription}`);
  4018. } else {
  4019. throw new Error(`Unknown error: ${errorName} - ${errorDescription}`);
  4020. }
  4021. }
  4022.  
  4023. async send() {
  4024. if (!this.calls.length) {
  4025. throw new Error('No calls to send.');
  4026. }
  4027.  
  4028. const identToNameMap = {};
  4029. const callsWithIdent = this.calls.map((call, index) => {
  4030. const ident = this.calls.length === 1 ? 'body' : `group_${index}_body`;
  4031. identToNameMap[ident] = call.name;
  4032. return { ...call, ident };
  4033. });
  4034.  
  4035. try {
  4036. const response = await Send({ calls: callsWithIdent });
  4037.  
  4038. if (response.error) {
  4039. this.handleError(response.error);
  4040. }
  4041.  
  4042. if (!response.results) {
  4043. throw new Error('Invalid response format: missing "results" field');
  4044. }
  4045.  
  4046. response.results.forEach((result) => {
  4047. const name = identToNameMap[result.ident];
  4048. if (!this.results[name]) {
  4049. this.results[name] = [];
  4050. this.sideResults[name] = [];
  4051. }
  4052. this.results[name].push(result.result.response);
  4053. const sideResults = {};
  4054. for (const key of Object.keys(result.result)) {
  4055. if (key === 'response') continue;
  4056. sideResults[key] = result.result[key];
  4057. }
  4058. this.sideResults[name].push(sideResults);
  4059. });
  4060. } catch (error) {
  4061. throw error;
  4062. }
  4063. return this;
  4064. }
  4065.  
  4066. result(name, forceArray = false) {
  4067. const results = name ? this.results[name] || [] : Object.values(this.results).flat();
  4068. return forceArray || results.length !== 1 ? results : results[0];
  4069. }
  4070.  
  4071. sideResult(name, forceArray = false) {
  4072. const results = name ? this.sideResults[name] || [] : Object.values(this.sideResults).flat();
  4073. return forceArray || results.length !== 1 ? results : results[0];
  4074. }
  4075.  
  4076. async execute(name) {
  4077. try {
  4078. await this.send();
  4079. return this.result(name);
  4080. } catch (error) {
  4081. throw error;
  4082. }
  4083. }
  4084.  
  4085. clear() {
  4086. this.calls = [];
  4087. this.results = {};
  4088. return this;
  4089. }
  4090.  
  4091. isEmpty() {
  4092. return this.calls.length === 0 && Object.keys(this.results).length === 0;
  4093. }
  4094.  
  4095. static async send(calls) {
  4096. return new Caller(calls).execute();
  4097. }
  4098. }
  4099.  
  4100. this.Caller = Caller;
  4101.  
  4102. /*
  4103. // Примеры использования
  4104. (async () => {
  4105. // Короткий вызов
  4106. await new Caller('inventoryGet').execute();
  4107. // Простой вызов
  4108. let result = await new Caller().add('inventoryGet').execute();
  4109. console.log('Inventory Get Result:', result);
  4110.  
  4111. // Сложный вызов
  4112. let caller = new Caller();
  4113. await caller
  4114. .add([
  4115. {
  4116. name: 'inventoryGet',
  4117. args: {},
  4118. },
  4119. {
  4120. name: 'heroGetAll',
  4121. args: {},
  4122. },
  4123. ])
  4124. .send();
  4125. console.log('Inventory Get Result:', caller.result('inventoryGet'));
  4126. console.log('Hero Get All Result:', caller.result('heroGetAll'));
  4127.  
  4128. // Очистка всех данных
  4129. caller.clear();
  4130. })();
  4131. */
  4132.  
  4133. /**
  4134. * Script for beautiful dialog boxes
  4135. *
  4136. * Скрипт для красивых диалоговых окошек
  4137. */
  4138. const popup = new (function () {
  4139. this.popUp,
  4140. this.downer,
  4141. this.middle,
  4142. this.msgText,
  4143. this.buttons = [];
  4144. this.checkboxes = [];
  4145. this.dialogPromice = null;
  4146. this.isInit = false;
  4147.  
  4148. this.init = function () {
  4149. if (this.isInit) {
  4150. return;
  4151. }
  4152. addStyle();
  4153. addBlocks();
  4154. addEventListeners();
  4155. this.isInit = true;
  4156. }
  4157.  
  4158. const addEventListeners = () => {
  4159. document.addEventListener('keyup', (e) => {
  4160. if (e.key == 'Escape') {
  4161. if (this.dialogPromice) {
  4162. const { func, result } = this.dialogPromice;
  4163. this.dialogPromice = null;
  4164. popup.hide();
  4165. func(result);
  4166. }
  4167. }
  4168. });
  4169. }
  4170.  
  4171. const addStyle = () => {
  4172. let style = document.createElement('style');
  4173. style.innerText = `
  4174. .PopUp_ {
  4175. position: fixed;
  4176. left: 50%;
  4177. top: 50%;
  4178. transform: translate(-50%, -50%);
  4179. min-width: 300px;
  4180. max-width: 80%;
  4181. max-height: 80%;
  4182. background-color: #190e08e6;
  4183. z-index: 10001;
  4184. border: 3px #ce9767 solid;
  4185. border-radius: 10px;
  4186. display: flex;
  4187. flex-direction: column;
  4188. justify-content: space-around;
  4189. padding: 15px 9px;
  4190. box-sizing: border-box;
  4191. }
  4192.  
  4193. .PopUp_back {
  4194. position: absolute;
  4195. background-color: #00000066;
  4196. width: 100%;
  4197. height: 100%;
  4198. z-index: 10000;
  4199. top: 0;
  4200. left: 0;
  4201. }
  4202.  
  4203. .PopUp_close {
  4204. width: 40px;
  4205. height: 40px;
  4206. position: absolute;
  4207. right: -18px;
  4208. top: -18px;
  4209. border: 3px solid #c18550;
  4210. border-radius: 20px;
  4211. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  4212. background-position-y: 3px;
  4213. box-shadow: -1px 1px 3px black;
  4214. cursor: pointer;
  4215. box-sizing: border-box;
  4216. }
  4217.  
  4218. .PopUp_close:hover {
  4219. filter: brightness(1.2);
  4220. }
  4221.  
  4222. .PopUp_crossClose {
  4223. width: 100%;
  4224. height: 100%;
  4225. background-size: 65%;
  4226. background-position: center;
  4227. background-repeat: no-repeat;
  4228. background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='%23f4cd73' d='M 0.826 12.559 C 0.431 12.963 3.346 15.374 3.74 14.97 C 4.215 15.173 8.167 10.457 7.804 10.302 C 7.893 10.376 11.454 14.64 11.525 14.372 C 12.134 15.042 15.118 12.086 14.638 11.689 C 14.416 11.21 10.263 7.477 10.402 7.832 C 10.358 7.815 11.731 7.101 14.872 3.114 C 14.698 2.145 13.024 1.074 12.093 1.019 C 11.438 0.861 8.014 5.259 8.035 5.531 C 7.86 5.082 3.61 1.186 3.522 1.59 C 2.973 1.027 0.916 4.611 1.17 4.873 C 0.728 4.914 5.088 7.961 5.61 7.995 C 5.225 7.532 0.622 12.315 0.826 12.559 Z'/%3e%3c/svg%3e")
  4229. }
  4230.  
  4231. .PopUp_blocks {
  4232. width: 100%;
  4233. height: 50%;
  4234. display: flex;
  4235. justify-content: space-evenly;
  4236. align-items: center;
  4237. flex-wrap: wrap;
  4238. justify-content: center;
  4239. }
  4240.  
  4241. .PopUp_blocks:last-child {
  4242. margin-top: 25px;
  4243. }
  4244.  
  4245. .PopUp_buttons {
  4246. display: flex;
  4247. margin: 7px 10px;
  4248. flex-direction: column;
  4249. }
  4250.  
  4251. .PopUp_button {
  4252. background-color: #52A81C;
  4253. border-radius: 5px;
  4254. box-shadow: inset 0px -4px 10px, inset 0px 3px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  4255. cursor: pointer;
  4256. padding: 4px 12px 6px;
  4257. }
  4258.  
  4259. .PopUp_input {
  4260. text-align: center;
  4261. font-size: 16px;
  4262. height: 27px;
  4263. border: 1px solid #cf9250;
  4264. border-radius: 9px 9px 0px 0px;
  4265. background: transparent;
  4266. color: #fce1ac;
  4267. padding: 1px 10px;
  4268. box-sizing: border-box;
  4269. box-shadow: 0px 0px 4px, 0px 0px 0px 3px #ce9767;
  4270. }
  4271.  
  4272. .PopUp_checkboxes {
  4273. display: flex;
  4274. flex-direction: column;
  4275. margin: 15px 15px -5px 15px;
  4276. align-items: flex-start;
  4277. }
  4278.  
  4279. .PopUp_ContCheckbox {
  4280. margin: 2px 0px;
  4281. }
  4282.  
  4283. .PopUp_checkbox {
  4284. position: absolute;
  4285. z-index: -1;
  4286. opacity: 0;
  4287. }
  4288. .PopUp_checkbox+label {
  4289. display: inline-flex;
  4290. align-items: center;
  4291. user-select: none;
  4292.  
  4293. font-size: 15px;
  4294. font-family: sans-serif;
  4295. font-weight: 600;
  4296. font-stretch: condensed;
  4297. letter-spacing: 1px;
  4298. color: #fce1ac;
  4299. text-shadow: 0px 0px 1px;
  4300. }
  4301. .PopUp_checkbox+label::before {
  4302. content: '';
  4303. display: inline-block;
  4304. width: 20px;
  4305. height: 20px;
  4306. border: 1px solid #cf9250;
  4307. border-radius: 7px;
  4308. margin-right: 7px;
  4309. }
  4310. .PopUp_checkbox:checked+label::before {
  4311. background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2388cb13' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e");
  4312. }
  4313.  
  4314. .PopUp_input::placeholder {
  4315. color: #fce1ac75;
  4316. }
  4317.  
  4318. .PopUp_input:focus {
  4319. outline: 0;
  4320. }
  4321.  
  4322. .PopUp_input + .PopUp_button {
  4323. border-radius: 0px 0px 5px 5px;
  4324. padding: 2px 18px 5px;
  4325. }
  4326.  
  4327. .PopUp_button:hover {
  4328. filter: brightness(1.2);
  4329. }
  4330.  
  4331. .PopUp_button:active {
  4332. box-shadow: inset 0px 5px 10px, inset 0px 1px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  4333. }
  4334.  
  4335. .PopUp_text {
  4336. font-size: 22px;
  4337. font-family: sans-serif;
  4338. font-weight: 600;
  4339. font-stretch: condensed;
  4340. letter-spacing: 1px;
  4341. text-align: center;
  4342. }
  4343.  
  4344. .PopUp_buttonText {
  4345. color: #E4FF4C;
  4346. text-shadow: 0px 1px 2px black;
  4347. }
  4348.  
  4349. .PopUp_msgText {
  4350. color: #FDE5B6;
  4351. text-shadow: 0px 0px 2px;
  4352. }
  4353.  
  4354. .PopUp_hideBlock {
  4355. display: none;
  4356. }
  4357. `;
  4358. document.head.appendChild(style);
  4359. }
  4360.  
  4361. const addBlocks = () => {
  4362. this.back = document.createElement('div');
  4363. this.back.classList.add('PopUp_back');
  4364. this.back.classList.add('PopUp_hideBlock');
  4365. document.body.append(this.back);
  4366.  
  4367. this.popUp = document.createElement('div');
  4368. this.popUp.classList.add('PopUp_');
  4369. this.back.append(this.popUp);
  4370.  
  4371. let upper = document.createElement('div')
  4372. upper.classList.add('PopUp_blocks');
  4373. this.popUp.append(upper);
  4374.  
  4375. this.middle = document.createElement('div')
  4376. this.middle.classList.add('PopUp_blocks');
  4377. this.middle.classList.add('PopUp_checkboxes');
  4378. this.popUp.append(this.middle);
  4379.  
  4380. this.downer = document.createElement('div')
  4381. this.downer.classList.add('PopUp_blocks');
  4382. this.popUp.append(this.downer);
  4383.  
  4384. this.msgText = document.createElement('div');
  4385. this.msgText.classList.add('PopUp_text', 'PopUp_msgText');
  4386. upper.append(this.msgText);
  4387. }
  4388.  
  4389. this.showBack = function () {
  4390. this.back.classList.remove('PopUp_hideBlock');
  4391. }
  4392.  
  4393. this.hideBack = function () {
  4394. this.back.classList.add('PopUp_hideBlock');
  4395. }
  4396.  
  4397. this.show = function () {
  4398. if (this.checkboxes.length) {
  4399. this.middle.classList.remove('PopUp_hideBlock');
  4400. }
  4401. this.showBack();
  4402. this.popUp.classList.remove('PopUp_hideBlock');
  4403. }
  4404.  
  4405. this.hide = function () {
  4406. this.hideBack();
  4407. this.popUp.classList.add('PopUp_hideBlock');
  4408. }
  4409.  
  4410. this.addAnyButton = (option) => {
  4411. const contButton = document.createElement('div');
  4412. contButton.classList.add('PopUp_buttons');
  4413. this.downer.append(contButton);
  4414.  
  4415. let inputField = {
  4416. value: option.result || option.default
  4417. }
  4418. if (option.isInput) {
  4419. inputField = document.createElement('input');
  4420. inputField.type = 'text';
  4421. if (option.placeholder) {
  4422. inputField.placeholder = option.placeholder;
  4423. }
  4424. if (option.default) {
  4425. inputField.value = option.default;
  4426. }
  4427. inputField.classList.add('PopUp_input');
  4428. contButton.append(inputField);
  4429. }
  4430.  
  4431. const button = document.createElement('div');
  4432. button.classList.add('PopUp_button');
  4433. button.title = option.title || '';
  4434. contButton.append(button);
  4435.  
  4436. const buttonText = document.createElement('div');
  4437. buttonText.classList.add('PopUp_text', 'PopUp_buttonText');
  4438. buttonText.innerHTML = option.msg;
  4439. button.append(buttonText);
  4440.  
  4441. return { button, contButton, inputField };
  4442. }
  4443.  
  4444. this.addCloseButton = () => {
  4445. let button = document.createElement('div')
  4446. button.classList.add('PopUp_close');
  4447. this.popUp.append(button);
  4448.  
  4449. let crossClose = document.createElement('div')
  4450. crossClose.classList.add('PopUp_crossClose');
  4451. button.append(crossClose);
  4452.  
  4453. return { button, contButton: button };
  4454. }
  4455.  
  4456. this.addButton = (option, buttonClick) => {
  4457.  
  4458. const { button, contButton, inputField } = option.isClose ? this.addCloseButton() : this.addAnyButton(option);
  4459. if (option.isClose) {
  4460. this.dialogPromice = { func: buttonClick, result: option.result };
  4461. }
  4462. button.addEventListener('click', () => {
  4463. let result = '';
  4464. if (option.isInput) {
  4465. result = inputField.value;
  4466. }
  4467. if (option.isClose || option.isCancel) {
  4468. this.dialogPromice = null;
  4469. }
  4470. buttonClick(result);
  4471. });
  4472.  
  4473. this.buttons.push(contButton);
  4474. }
  4475.  
  4476. this.clearButtons = () => {
  4477. while (this.buttons.length) {
  4478. this.buttons.pop().remove();
  4479. }
  4480. }
  4481.  
  4482. this.addCheckBox = (checkBox) => {
  4483. const contCheckbox = document.createElement('div');
  4484. contCheckbox.classList.add('PopUp_ContCheckbox');
  4485. this.middle.append(contCheckbox);
  4486.  
  4487. const checkbox = document.createElement('input');
  4488. checkbox.type = 'checkbox';
  4489. checkbox.id = 'PopUpCheckbox' + this.checkboxes.length;
  4490. checkbox.dataset.name = checkBox.name;
  4491. checkbox.checked = checkBox.checked;
  4492. checkbox.label = checkBox.label;
  4493. checkbox.title = checkBox.title || '';
  4494. checkbox.classList.add('PopUp_checkbox');
  4495. contCheckbox.appendChild(checkbox)
  4496.  
  4497. const checkboxLabel = document.createElement('label');
  4498. checkboxLabel.innerText = checkBox.label;
  4499. checkboxLabel.title = checkBox.title || '';
  4500. checkboxLabel.setAttribute('for', checkbox.id);
  4501. contCheckbox.appendChild(checkboxLabel);
  4502.  
  4503. this.checkboxes.push(checkbox);
  4504. }
  4505.  
  4506. this.clearCheckBox = () => {
  4507. this.middle.classList.add('PopUp_hideBlock');
  4508. while (this.checkboxes.length) {
  4509. this.checkboxes.pop().parentNode.remove();
  4510. }
  4511. }
  4512.  
  4513. this.setMsgText = (text) => {
  4514. this.msgText.innerHTML = text;
  4515. }
  4516.  
  4517. this.getCheckBoxes = () => {
  4518. const checkBoxes = [];
  4519.  
  4520. for (const checkBox of this.checkboxes) {
  4521. checkBoxes.push({
  4522. name: checkBox.dataset.name,
  4523. label: checkBox.label,
  4524. checked: checkBox.checked
  4525. });
  4526. }
  4527.  
  4528. return checkBoxes;
  4529. }
  4530.  
  4531. this.confirm = async (msg, buttOpt, checkBoxes = []) => {
  4532. if (!this.isInit) {
  4533. this.init();
  4534. }
  4535. this.clearButtons();
  4536. this.clearCheckBox();
  4537. return new Promise((complete, failed) => {
  4538. this.setMsgText(msg);
  4539. if (!buttOpt) {
  4540. buttOpt = [{ msg: 'Ok', result: true, isInput: false }];
  4541. }
  4542. for (const checkBox of checkBoxes) {
  4543. this.addCheckBox(checkBox);
  4544. }
  4545. for (let butt of buttOpt) {
  4546. this.addButton(butt, (result) => {
  4547. result = result || butt.result;
  4548. complete(result);
  4549. popup.hide();
  4550. });
  4551. if (butt.isCancel) {
  4552. this.dialogPromice = { func: complete, result: butt.result };
  4553. }
  4554. }
  4555. this.show();
  4556. });
  4557. }
  4558. });
  4559.  
  4560. this.HWHFuncs.popup = popup;
  4561.  
  4562. /**
  4563. * Миксин EventEmitter
  4564. * @param {Class} BaseClass Базовый класс (по умолчанию Object)
  4565. * @returns {Class} Класс с методами EventEmitter
  4566. */
  4567. const EventEmitterMixin = (BaseClass = Object) =>
  4568. class EventEmitter extends BaseClass {
  4569. constructor(...args) {
  4570. super(...args);
  4571. this._events = new Map();
  4572. }
  4573.  
  4574. /**
  4575. * Подписаться на событие
  4576. * @param {string} event Имя события
  4577. * @param {function} listener Функция-обработчик
  4578. * @returns {this} Возвращает экземпляр для чейнинга
  4579. */
  4580. on(event, listener) {
  4581. if (typeof listener !== 'function') {
  4582. throw new TypeError('Listener must be a function');
  4583. }
  4584.  
  4585. if (!this._events.has(event)) {
  4586. this._events.set(event, new Set());
  4587. }
  4588. this._events.get(event).add(listener);
  4589. return this;
  4590. }
  4591.  
  4592. /**
  4593. * Отписаться от события
  4594. * @param {string} event Имя события
  4595. * @param {function} listener Функция-обработчик
  4596. * @returns {this} Возвращает экземпляр для чейнинга
  4597. */
  4598. off(event, listener) {
  4599. if (this._events.has(event)) {
  4600. const listeners = this._events.get(event);
  4601. listeners.delete(listener);
  4602. if (listeners.size === 0) {
  4603. this._events.delete(event);
  4604. }
  4605. }
  4606. return this;
  4607. }
  4608.  
  4609. /**
  4610. * Вызвать событие
  4611. * @param {string} event Имя события
  4612. * @param {...any} args Аргументы для обработчиков
  4613. * @returns {boolean} Было ли событие обработано
  4614. */
  4615. emit(event, ...args) {
  4616. if (!this._events.has(event)) return false;
  4617. const listeners = new Set(this._events.get(event));
  4618. listeners.forEach((listener) => {
  4619. try {
  4620. listener.apply(this, args);
  4621. } catch (e) {
  4622. console.error(`Error in event handler for "${event}":`, e);
  4623. }
  4624. });
  4625.  
  4626. return true;
  4627. }
  4628.  
  4629. /**
  4630. * Подписаться на событие один раз
  4631. * @param {string} event Имя события
  4632. * @param {function} listener Функция-обработчик
  4633. * @returns {this} Возвращает экземпляр для чейнинга
  4634. */
  4635. once(event, listener) {
  4636. const onceWrapper = (...args) => {
  4637. this.off(event, onceWrapper);
  4638. listener.apply(this, args);
  4639. };
  4640. return this.on(event, onceWrapper);
  4641. }
  4642.  
  4643. /**
  4644. * Удалить все обработчики для события
  4645. * @param {string} [event] Имя события (если не указано - очистить все)
  4646. * @returns {this} Возвращает экземпляр для чейнинга
  4647. */
  4648. removeAllListeners(event) {
  4649. if (event) {
  4650. this._events.delete(event);
  4651. } else {
  4652. this._events.clear();
  4653. }
  4654. return this;
  4655. }
  4656.  
  4657. /**
  4658. * Получить количество обработчиков для события
  4659. * @param {string} event Имя события
  4660. * @returns {number} Количество обработчиков
  4661. */
  4662. listenerCount(event) {
  4663. return this._events.has(event) ? this._events.get(event).size : 0;
  4664. }
  4665. };
  4666.  
  4667. this.HWHFuncs.EventEmitterMixin = EventEmitterMixin;
  4668.  
  4669. /**
  4670. * Script control panel
  4671. *
  4672. * Панель управления скриптом
  4673. */
  4674. class ScriptMenu extends EventEmitterMixin() {
  4675. constructor() {
  4676. if (ScriptMenu.instance) {
  4677. return ScriptMenu.instance;
  4678. }
  4679. super();
  4680. this.mainMenu = null;
  4681. this.buttons = [];
  4682. this.checkboxes = [];
  4683. this.option = {
  4684. showMenu: true,
  4685. showDetails: {},
  4686. };
  4687. ScriptMenu.instance = this;
  4688. return this;
  4689. }
  4690.  
  4691. static getInst() {
  4692. if (!ScriptMenu.instance) {
  4693. new ScriptMenu();
  4694. }
  4695. return ScriptMenu.instance;
  4696. }
  4697.  
  4698. init(option = {}) {
  4699. this.emit('beforeInit', option);
  4700. this.option = Object.assign(this.option, option);
  4701. const saveOption = this.loadSaveOption();
  4702. this.option = Object.assign(this.option, saveOption);
  4703. this.addStyle();
  4704. this.addBlocks();
  4705. this.emit('afterInit', option);
  4706. }
  4707.  
  4708. addStyle() {
  4709. const style = document.createElement('style');
  4710. style.innerText = `
  4711. .scriptMenu_status {
  4712. position: absolute;
  4713. z-index: 10001;
  4714. top: -1px;
  4715. left: 30%;
  4716. cursor: pointer;
  4717. border-radius: 0px 0px 10px 10px;
  4718. background: #190e08e6;
  4719. border: 1px #ce9767 solid;
  4720. font-size: 18px;
  4721. font-family: sans-serif;
  4722. font-weight: 600;
  4723. font-stretch: condensed;
  4724. letter-spacing: 1px;
  4725. color: #fce1ac;
  4726. text-shadow: 0px 0px 1px;
  4727. transition: 0.5s;
  4728. padding: 2px 10px 3px;
  4729. }
  4730. .scriptMenu_statusHide {
  4731. top: -35px;
  4732. height: 30px;
  4733. overflow: hidden;
  4734. }
  4735. .scriptMenu_label {
  4736. position: absolute;
  4737. top: 30%;
  4738. left: -4px;
  4739. z-index: 9999;
  4740. cursor: pointer;
  4741. width: 30px;
  4742. height: 30px;
  4743. background: radial-gradient(circle, #47a41b 0%, #1a2f04 100%);
  4744. border: 1px solid #1a2f04;
  4745. border-radius: 5px;
  4746. box-shadow:
  4747. inset 0px 2px 4px #83ce26,
  4748. inset 0px -4px 6px #1a2f04,
  4749. 0px 0px 2px black,
  4750. 0px 0px 0px 2px #ce9767;
  4751. }
  4752. .scriptMenu_label:hover {
  4753. filter: brightness(1.2);
  4754. }
  4755. .scriptMenu_arrowLabel {
  4756. width: 100%;
  4757. height: 100%;
  4758. background-size: 75%;
  4759. background-position: center;
  4760. background-repeat: no-repeat;
  4761. background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='%2388cb13' d='M7.596 7.304a.802.802 0 0 1 0 1.392l-6.363 3.692C.713 12.69 0 12.345 0 11.692V4.308c0-.653.713-.998 1.233-.696l6.363 3.692Z'/%3e%3cpath fill='%2388cb13' d='M15.596 7.304a.802.802 0 0 1 0 1.392l-6.363 3.692C8.713 12.69 8 12.345 8 11.692V4.308c0-.653.713-.998 1.233-.696l6.363 3.692Z'/%3e%3c/svg%3e");
  4762. box-shadow: 0px 1px 2px #000;
  4763. border-radius: 5px;
  4764. filter: drop-shadow(0px 1px 2px #000D);
  4765. }
  4766. .scriptMenu_main {
  4767. position: absolute;
  4768. max-width: 285px;
  4769. z-index: 9999;
  4770. top: 50%;
  4771. transform: translateY(-40%);
  4772. background: #190e08e6;
  4773. border: 1px #ce9767 solid;
  4774. border-radius: 0px 10px 10px 0px;
  4775. border-left: none;
  4776. box-sizing: border-box;
  4777. font-size: 15px;
  4778. font-family: sans-serif;
  4779. font-weight: 600;
  4780. font-stretch: condensed;
  4781. letter-spacing: 1px;
  4782. color: #fce1ac;
  4783. text-shadow: 0px 0px 1px;
  4784. transition: 1s;
  4785. }
  4786. .scriptMenu_conteiner {
  4787. max-height: 80vh;
  4788. overflow: scroll;
  4789. scrollbar-width: none; /* Для Firefox */
  4790. -ms-overflow-style: none; /* Для Internet Explorer и Edge */
  4791. display: flex;
  4792. flex-direction: column;
  4793. flex-wrap: nowrap;
  4794. padding: 5px 10px 5px 5px;
  4795. }
  4796. .scriptMenu_conteiner::-webkit-scrollbar {
  4797. display: none; /* Для Chrome, Safari и Opera */
  4798. }
  4799. .scriptMenu_showMenu {
  4800. display: none;
  4801. }
  4802. .scriptMenu_showMenu:checked~.scriptMenu_main {
  4803. left: 0px;
  4804. }
  4805. .scriptMenu_showMenu:not(:checked)~.scriptMenu_main {
  4806. left: -300px;
  4807. }
  4808. .scriptMenu_divInput {
  4809. margin: 2px;
  4810. }
  4811. .scriptMenu_divInputText {
  4812. margin: 2px;
  4813. align-self: center;
  4814. display: flex;
  4815. }
  4816. .scriptMenu_checkbox {
  4817. position: absolute;
  4818. z-index: -1;
  4819. opacity: 0;
  4820. }
  4821. .scriptMenu_checkbox+label {
  4822. display: inline-flex;
  4823. align-items: center;
  4824. user-select: none;
  4825. }
  4826. .scriptMenu_checkbox+label::before {
  4827. content: '';
  4828. display: inline-block;
  4829. width: 20px;
  4830. height: 20px;
  4831. border: 1px solid #cf9250;
  4832. border-radius: 7px;
  4833. margin-right: 7px;
  4834. }
  4835. .scriptMenu_checkbox:checked+label::before {
  4836. background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2388cb13' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e");
  4837. }
  4838. .scriptMenu_close {
  4839. width: 40px;
  4840. height: 40px;
  4841. position: absolute;
  4842. right: -18px;
  4843. top: -18px;
  4844. border: 3px solid #c18550;
  4845. border-radius: 20px;
  4846. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  4847. background-position-y: 3px;
  4848. box-shadow: -1px 1px 3px black;
  4849. cursor: pointer;
  4850. box-sizing: border-box;
  4851. }
  4852. .scriptMenu_close:hover {
  4853. filter: brightness(1.2);
  4854. }
  4855. .scriptMenu_crossClose {
  4856. width: 100%;
  4857. height: 100%;
  4858. background-size: 65%;
  4859. background-position: center;
  4860. background-repeat: no-repeat;
  4861. background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='%23f4cd73' d='M 0.826 12.559 C 0.431 12.963 3.346 15.374 3.74 14.97 C 4.215 15.173 8.167 10.457 7.804 10.302 C 7.893 10.376 11.454 14.64 11.525 14.372 C 12.134 15.042 15.118 12.086 14.638 11.689 C 14.416 11.21 10.263 7.477 10.402 7.832 C 10.358 7.815 11.731 7.101 14.872 3.114 C 14.698 2.145 13.024 1.074 12.093 1.019 C 11.438 0.861 8.014 5.259 8.035 5.531 C 7.86 5.082 3.61 1.186 3.522 1.59 C 2.973 1.027 0.916 4.611 1.17 4.873 C 0.728 4.914 5.088 7.961 5.61 7.995 C 5.225 7.532 0.622 12.315 0.826 12.559 Z'/%3e%3c/svg%3e")
  4862. }
  4863. .scriptMenu_button {
  4864. user-select: none;
  4865. cursor: pointer;
  4866. padding: 5px 14px 8px;
  4867. }
  4868. .scriptMenu_button:hover {
  4869. filter: brightness(1.2);
  4870. }
  4871. .scriptMenu_buttonText {
  4872. color: #fce5b7;
  4873. text-shadow: 0px 1px 2px black;
  4874. text-align: center;
  4875. }
  4876. .scriptMenu_header {
  4877. text-align: center;
  4878. align-self: center;
  4879. font-size: 15px;
  4880. margin: 0px 15px;
  4881. }
  4882. .scriptMenu_header a {
  4883. color: #fce5b7;
  4884. text-decoration: none;
  4885. }
  4886. .scriptMenu_InputText {
  4887. text-align: center;
  4888. width: 130px;
  4889. height: 24px;
  4890. border: 1px solid #cf9250;
  4891. border-radius: 9px;
  4892. background: transparent;
  4893. color: #fce1ac;
  4894. padding: 0px 10px;
  4895. box-sizing: border-box;
  4896. }
  4897. .scriptMenu_InputText:focus {
  4898. filter: brightness(1.2);
  4899. outline: 0;
  4900. }
  4901. .scriptMenu_InputText::placeholder {
  4902. color: #fce1ac75;
  4903. }
  4904. .scriptMenu_Summary {
  4905. cursor: pointer;
  4906. margin-left: 7px;
  4907. }
  4908. .scriptMenu_Details {
  4909. align-self: center;
  4910. }
  4911. .scriptMenu_buttonGroup {
  4912. display: flex;
  4913. justify-content: center;
  4914. user-select: none;
  4915. cursor: pointer;
  4916. padding: 0;
  4917. margin: 3px 0;
  4918. }
  4919. .scriptMenu_buttonGroup .scriptMenu_button {
  4920. width: 100%;
  4921. padding: 5px 8px 8px;
  4922. }
  4923. .scriptMenu_mainButton {
  4924. border-radius: 5px;
  4925. margin: 3px 0;
  4926. }
  4927. .scriptMenu_combineButtonLeft {
  4928. border-top-left-radius: 5px;
  4929. border-bottom-left-radius: 5px;
  4930. margin-right: 2px;
  4931. }
  4932. .scriptMenu_combineButtonCenter {
  4933. border-radius: 0px;
  4934. margin-right: 2px;
  4935. }
  4936. .scriptMenu_combineButtonRight {
  4937. border-top-right-radius: 5px;
  4938. border-bottom-right-radius: 5px;
  4939. }
  4940. .scriptMenu_beigeButton {
  4941. border: 1px solid #442901;
  4942. background: radial-gradient(circle, rgba(165,120,56,1) 80%, rgba(0,0,0,1) 110%);
  4943. box-shadow: inset 0px 2px 4px #e9b282, inset 0px -4px 6px #442901, inset 0px 1px 6px #442901, inset 0px 0px 6px, 0px 0px 2px black, 0px 0px 0px 1px #ce9767;
  4944. }
  4945. .scriptMenu_beigeButton:active {
  4946. box-shadow: inset 0px 4px 6px #442901, inset 0px 4px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 1px #ce9767;
  4947. }
  4948. .scriptMenu_greenButton {
  4949. border: 1px solid #1a2f04;
  4950. background: radial-gradient(circle, #47a41b 0%, #1a2f04 150%);
  4951. box-shadow: inset 0px 2px 4px #83ce26, inset 0px -4px 6px #1a2f04, 0px 0px 2px black, 0px 0px 0px 1px #ce9767;
  4952. }
  4953. .scriptMenu_greenButton:active {
  4954. box-shadow: inset 0px 4px 6px #1a2f04, inset 0px 4px 6px #1a2f04, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 1px #ce9767;
  4955. }
  4956. .scriptMenu_redButton {
  4957. border: 1px solid #440101;
  4958. background: radial-gradient(circle, rgb(198, 34, 34) 80%, rgb(0, 0, 0) 110%);
  4959. box-shadow: inset 0px 2px 4px #e98282, inset 0px -4px 6px #440101, inset 0px 1px 6px #440101, inset 0px 0px 6px, 0px 0px 2px black, 0px 0px 0px 1px #ce9767;
  4960. }
  4961. .scriptMenu_redButton:active {
  4962. box-shadow: inset 0px 4px 6px #440101, inset 0px 4px 6px #440101, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 1px #ce9767;
  4963. }
  4964. .scriptMenu_attention {
  4965. position: relative;
  4966. }
  4967. .scriptMenu_attention .scriptMenu_dot {
  4968. display: flex;
  4969. justify-content: center;
  4970. align-items: center;
  4971. }
  4972. .scriptMenu_dot {
  4973. position: absolute;
  4974. top: -7px;
  4975. right: -7px;
  4976. width: 20px;
  4977. height: 20px;
  4978. border-radius: 50%;
  4979. border: 1px solid #c18550;
  4980. background: radial-gradient(circle, #f000 25%, black 100%);
  4981. box-shadow: 0px 0px 2px black;
  4982. background-position: 0px -1px;
  4983. font-size: 10px;
  4984. text-align: center;
  4985. color: white;
  4986. text-shadow: 1px 1px 1px black;
  4987. box-sizing: border-box;
  4988. display: none;
  4989. }
  4990. `;
  4991. document.head.appendChild(style);
  4992. }
  4993.  
  4994. addBlocks() {
  4995. const main = document.createElement('div');
  4996. document.body.appendChild(main);
  4997.  
  4998. this.status = document.createElement('div');
  4999. this.status.classList.add('scriptMenu_status');
  5000. this.setStatus('');
  5001. main.appendChild(this.status);
  5002.  
  5003. const label = document.createElement('label');
  5004. label.classList.add('scriptMenu_label');
  5005. label.setAttribute('for', 'checkbox_showMenu');
  5006. main.appendChild(label);
  5007.  
  5008. const arrowLabel = document.createElement('div');
  5009. arrowLabel.classList.add('scriptMenu_arrowLabel');
  5010. label.appendChild(arrowLabel);
  5011.  
  5012. const checkbox = document.createElement('input');
  5013. checkbox.type = 'checkbox';
  5014. checkbox.id = 'checkbox_showMenu';
  5015. checkbox.checked = this.option.showMenu;
  5016. checkbox.classList.add('scriptMenu_showMenu');
  5017. checkbox.addEventListener('change', () => {
  5018. this.option.showMenu = checkbox.checked;
  5019. this.saveSaveOption();
  5020. });
  5021. main.appendChild(checkbox);
  5022.  
  5023. const mainMenu = document.createElement('div');
  5024. mainMenu.classList.add('scriptMenu_main');
  5025. main.appendChild(mainMenu);
  5026.  
  5027. this.mainMenu = document.createElement('div');
  5028. this.mainMenu.classList.add('scriptMenu_conteiner');
  5029. mainMenu.appendChild(this.mainMenu);
  5030.  
  5031. const closeButton = document.createElement('label');
  5032. closeButton.classList.add('scriptMenu_close');
  5033. closeButton.setAttribute('for', 'checkbox_showMenu');
  5034. this.mainMenu.appendChild(closeButton);
  5035.  
  5036. const crossClose = document.createElement('div');
  5037. crossClose.classList.add('scriptMenu_crossClose');
  5038. closeButton.appendChild(crossClose);
  5039. }
  5040.  
  5041. getButtonColor(color) {
  5042. const buttonColors = {
  5043. green: 'scriptMenu_greenButton',
  5044. red: 'scriptMenu_redButton',
  5045. beige: 'scriptMenu_beigeButton',
  5046. };
  5047. return buttonColors[color] || buttonColors['beige'];
  5048. }
  5049.  
  5050. setStatus(text, onclick) {
  5051. if (this._currentStatusClickHandler) {
  5052. this.status.removeEventListener('click', this._currentStatusClickHandler);
  5053. this._currentStatusClickHandler = null;
  5054. }
  5055.  
  5056. if (!text) {
  5057. this.status.classList.add('scriptMenu_statusHide');
  5058. this.status.innerHTML = '';
  5059. } else {
  5060. this.status.classList.remove('scriptMenu_statusHide');
  5061. this.status.innerHTML = text;
  5062. }
  5063.  
  5064. if (typeof onclick === 'function') {
  5065. this.status.addEventListener('click', onclick, { once: true });
  5066. this._currentStatusClickHandler = onclick;
  5067. }
  5068. }
  5069.  
  5070. addStatus(text) {
  5071. if (!this.status.innerHTML) {
  5072. this.status.classList.remove('scriptMenu_statusHide');
  5073. }
  5074. this.status.innerHTML += text;
  5075. }
  5076.  
  5077. addHeader(text, onClick, main = this.mainMenu) {
  5078. this.emit('beforeAddHeader', text, onClick, main);
  5079. const header = document.createElement('div');
  5080. header.classList.add('scriptMenu_header');
  5081. header.innerHTML = text;
  5082. if (typeof onClick === 'function') {
  5083. header.addEventListener('click', onClick);
  5084. }
  5085. main.appendChild(header);
  5086. this.emit('afterAddHeader', text, onClick, main);
  5087. return header;
  5088. }
  5089.  
  5090. addButton(btn, main = this.mainMenu) {
  5091. this.emit('beforeAddButton', btn, main);
  5092. const { name, onClick, title, color, dot, classes = [], isCombine } = btn;
  5093. const button = document.createElement('div');
  5094. if (!isCombine) {
  5095. classes.push('scriptMenu_mainButton');
  5096. }
  5097. button.classList.add('scriptMenu_button', this.getButtonColor(color), ...classes);
  5098. button.title = title;
  5099. button.addEventListener('click', onClick);
  5100. main.appendChild(button);
  5101.  
  5102. const buttonText = document.createElement('div');
  5103. buttonText.classList.add('scriptMenu_buttonText');
  5104. buttonText.innerText = name;
  5105. button.appendChild(buttonText);
  5106.  
  5107. if (dot) {
  5108. const dotAtention = document.createElement('div');
  5109. dotAtention.classList.add('scriptMenu_dot');
  5110. dotAtention.title = dot;
  5111. button.appendChild(dotAtention);
  5112. }
  5113.  
  5114. this.buttons.push(button);
  5115. this.emit('afterAddButton', button, btn);
  5116. return button;
  5117. }
  5118.  
  5119. addCombinedButton(buttonList, main = this.mainMenu) {
  5120. this.emit('beforeAddCombinedButton', buttonList, main);
  5121. const buttonGroup = document.createElement('div');
  5122. buttonGroup.classList.add('scriptMenu_buttonGroup');
  5123. let count = 0;
  5124.  
  5125. for (const btn of buttonList) {
  5126. btn.isCombine = true;
  5127. btn.classes ??= [];
  5128. if (count === 0) {
  5129. btn.classes.push('scriptMenu_combineButtonLeft');
  5130. } else if (count === buttonList.length - 1) {
  5131. btn.classes.push('scriptMenu_combineButtonRight');
  5132. } else {
  5133. btn.classes.push('scriptMenu_combineButtonCenter');
  5134. }
  5135. this.addButton(btn, buttonGroup);
  5136. count++;
  5137. }
  5138.  
  5139. const dotAtention = document.createElement('div');
  5140. dotAtention.classList.add('scriptMenu_dot');
  5141. buttonGroup.appendChild(dotAtention);
  5142.  
  5143. main.appendChild(buttonGroup);
  5144. this.emit('afterAddCombinedButton', buttonGroup, buttonList);
  5145. return buttonGroup;
  5146. }
  5147.  
  5148. addCheckbox(label, title, main = this.mainMenu) {
  5149. this.emit('beforeAddCheckbox', label, title, main);
  5150. const divCheckbox = document.createElement('div');
  5151. divCheckbox.classList.add('scriptMenu_divInput');
  5152. divCheckbox.title = title;
  5153. main.appendChild(divCheckbox);
  5154.  
  5155. const checkbox = document.createElement('input');
  5156. checkbox.type = 'checkbox';
  5157. checkbox.id = 'scriptMenuCheckbox' + this.checkboxes.length;
  5158. checkbox.classList.add('scriptMenu_checkbox');
  5159. divCheckbox.appendChild(checkbox);
  5160.  
  5161. const checkboxLabel = document.createElement('label');
  5162. checkboxLabel.innerText = label;
  5163. checkboxLabel.setAttribute('for', checkbox.id);
  5164. divCheckbox.appendChild(checkboxLabel);
  5165.  
  5166. this.checkboxes.push(checkbox);
  5167. this.emit('afterAddCheckbox', label, title, main);
  5168. return checkbox;
  5169. }
  5170.  
  5171. addInputText(title, placeholder, main = this.mainMenu) {
  5172. this.emit('beforeAddCheckbox', title, placeholder, main);
  5173. const divInputText = document.createElement('div');
  5174. divInputText.classList.add('scriptMenu_divInputText');
  5175. divInputText.title = title;
  5176. main.appendChild(divInputText);
  5177.  
  5178. const newInputText = document.createElement('input');
  5179. newInputText.type = 'text';
  5180. if (placeholder) {
  5181. newInputText.placeholder = placeholder;
  5182. }
  5183. newInputText.classList.add('scriptMenu_InputText');
  5184. divInputText.appendChild(newInputText);
  5185. this.emit('afterAddCheckbox', title, placeholder, main);
  5186. return newInputText;
  5187. }
  5188.  
  5189. addDetails(summaryText, name = null) {
  5190. this.emit('beforeAddDetails', summaryText, name);
  5191. const details = document.createElement('details');
  5192. details.classList.add('scriptMenu_Details');
  5193. this.mainMenu.appendChild(details);
  5194.  
  5195. const summary = document.createElement('summary');
  5196. summary.classList.add('scriptMenu_Summary');
  5197. summary.innerText = summaryText;
  5198. if (name) {
  5199. details.open = this.option.showDetails[name] ?? false;
  5200. details.dataset.name = name;
  5201. details.addEventListener('toggle', () => {
  5202. this.option.showDetails[details.dataset.name] = details.open;
  5203. this.saveSaveOption();
  5204. });
  5205. }
  5206.  
  5207. details.appendChild(summary);
  5208. this.emit('afterAddDetails', summaryText, name);
  5209. return details;
  5210. }
  5211.  
  5212. saveSaveOption() {
  5213. try {
  5214. localStorage.setItem('scriptMenu_saveOption', JSON.stringify(this.option));
  5215. } catch (e) {
  5216. console.log('¯\\_(ツ)_/¯');
  5217. }
  5218. }
  5219.  
  5220. loadSaveOption() {
  5221. let saveOption = null;
  5222. try {
  5223. saveOption = localStorage.getItem('scriptMenu_saveOption');
  5224. } catch (e) {
  5225. console.log('¯\\_(ツ)_/¯');
  5226. }
  5227.  
  5228. if (!saveOption) {
  5229. return {};
  5230. }
  5231.  
  5232. try {
  5233. saveOption = JSON.parse(saveOption);
  5234. } catch (e) {
  5235. return {};
  5236. }
  5237.  
  5238. return saveOption;
  5239. }
  5240. }
  5241.  
  5242. this.HWHClasses.ScriptMenu = ScriptMenu;
  5243.  
  5244. //const scriptMenu = ScriptMenu.getInst();
  5245.  
  5246. /**
  5247. * Пример использования
  5248. const scriptMenu = ScriptMenu.getInst();
  5249. scriptMenu.init();
  5250. scriptMenu.addHeader('v1.508');
  5251. scriptMenu.addCheckbox('testHack', 'Тестовый взлом игры!');
  5252. scriptMenu.addButton({
  5253. text: 'Запуск!',
  5254. onClick: () => console.log('click'),
  5255. title: 'подсказака',
  5256. });
  5257. scriptMenu.addInputText('input подсказака');
  5258. scriptMenu.on('beforeInit', (option) => {
  5259. console.log('beforeInit', option);
  5260. })
  5261. scriptMenu.on('beforeAddHeader', (text, onClick, main) => {
  5262. console.log('beforeAddHeader', text, onClick, main);
  5263. });
  5264. scriptMenu.on('beforeAddButton', (btn, main) => {
  5265. console.log('beforeAddButton', btn, main);
  5266. });
  5267. scriptMenu.on('beforeAddCombinedButton', (buttonList, main) => {
  5268. console.log('beforeAddCombinedButton', buttonList, main);
  5269. });
  5270. scriptMenu.on('beforeAddCheckbox', (label, title, main) => {
  5271. console.log('beforeAddCheckbox', label, title, main);
  5272. });
  5273. scriptMenu.on('beforeAddDetails', (summaryText, name) => {
  5274. console.log('beforeAddDetails', summaryText, name);
  5275. });
  5276. */
  5277.  
  5278. /**
  5279. * Game Library
  5280. *
  5281. * Игровая библиотека
  5282. */
  5283. class Library {
  5284. defaultLibUrl = 'https://heroesru-a.akamaihd.net/vk/v1101/lib/lib.json';
  5285.  
  5286. constructor() {
  5287. if (!Library.instance) {
  5288. Library.instance = this;
  5289. }
  5290.  
  5291. return Library.instance;
  5292. }
  5293.  
  5294. async load() {
  5295. try {
  5296. await this.getUrlLib();
  5297. console.log(this.defaultLibUrl);
  5298. this.data = await fetch(this.defaultLibUrl).then(e => e.json())
  5299. } catch (error) {
  5300. console.error('Не удалось загрузить библиотеку', error)
  5301. }
  5302. }
  5303.  
  5304. async getUrlLib() {
  5305. try {
  5306. const db = new Database('hw_cache', 'cache');
  5307. await db.open();
  5308. const cacheLibFullUrl = await db.get('lib/lib.json.gz', false);
  5309. this.defaultLibUrl = cacheLibFullUrl.fullUrl.split('.gz').shift();
  5310. } catch(e) {}
  5311. }
  5312.  
  5313. getData(id) {
  5314. return this.data[id];
  5315. }
  5316.  
  5317. setData(data) {
  5318. this.data = data;
  5319. }
  5320. }
  5321.  
  5322. this.lib = new Library();
  5323. /**
  5324. * Database
  5325. *
  5326. * База данных
  5327. */
  5328. class Database {
  5329. constructor(dbName, storeName) {
  5330. this.dbName = dbName;
  5331. this.storeName = storeName;
  5332. this.db = null;
  5333. }
  5334.  
  5335. async open() {
  5336. return new Promise((resolve, reject) => {
  5337. const request = indexedDB.open(this.dbName);
  5338.  
  5339. request.onerror = () => {
  5340. reject(new Error(`Failed to open database ${this.dbName}`));
  5341. };
  5342.  
  5343. request.onsuccess = () => {
  5344. this.db = request.result;
  5345. resolve();
  5346. };
  5347.  
  5348. request.onupgradeneeded = (event) => {
  5349. const db = event.target.result;
  5350. if (!db.objectStoreNames.contains(this.storeName)) {
  5351. db.createObjectStore(this.storeName);
  5352. }
  5353. };
  5354. });
  5355. }
  5356.  
  5357. async set(key, value) {
  5358. return new Promise((resolve, reject) => {
  5359. const transaction = this.db.transaction([this.storeName], 'readwrite');
  5360. const store = transaction.objectStore(this.storeName);
  5361. const request = store.put(value, key);
  5362.  
  5363. request.onerror = () => {
  5364. reject(new Error(`Failed to save value with key ${key}`));
  5365. };
  5366.  
  5367. request.onsuccess = () => {
  5368. resolve();
  5369. };
  5370. });
  5371. }
  5372.  
  5373. async get(key, def) {
  5374. return new Promise((resolve, reject) => {
  5375. const transaction = this.db.transaction([this.storeName], 'readonly');
  5376. const store = transaction.objectStore(this.storeName);
  5377. const request = store.get(key);
  5378.  
  5379. request.onerror = () => {
  5380. resolve(def);
  5381. };
  5382.  
  5383. request.onsuccess = () => {
  5384. resolve(request.result);
  5385. };
  5386. });
  5387. }
  5388.  
  5389. async delete(key) {
  5390. return new Promise((resolve, reject) => {
  5391. const transaction = this.db.transaction([this.storeName], 'readwrite');
  5392. const store = transaction.objectStore(this.storeName);
  5393. const request = store.delete(key);
  5394.  
  5395. request.onerror = () => {
  5396. reject(new Error(`Failed to delete value with key ${key}`));
  5397. };
  5398.  
  5399. request.onsuccess = () => {
  5400. resolve();
  5401. };
  5402. });
  5403. }
  5404. }
  5405.  
  5406. /**
  5407. * Returns the stored value
  5408. *
  5409. * Возвращает сохраненное значение
  5410. */
  5411. function getSaveVal(saveName, def) {
  5412. const result = storage.get(saveName, def);
  5413. return result;
  5414. }
  5415. this.HWHFuncs.getSaveVal = getSaveVal;
  5416.  
  5417. /**
  5418. * Stores value
  5419. *
  5420. * Сохраняет значение
  5421. */
  5422. function setSaveVal(saveName, value) {
  5423. storage.set(saveName, value);
  5424. }
  5425. this.HWHFuncs.setSaveVal = setSaveVal;
  5426.  
  5427. /**
  5428. * Database initialization
  5429. *
  5430. * Инициализация базы данных
  5431. */
  5432. const db = new Database(GM_info.script.name, 'settings');
  5433.  
  5434. /**
  5435. * Data store
  5436. *
  5437. * Хранилище данных
  5438. */
  5439. const storage = {
  5440. userId: 0,
  5441. /**
  5442. * Default values
  5443. *
  5444. * Значения по умолчанию
  5445. */
  5446. values: {},
  5447. name: GM_info.script.name,
  5448. init: function () {
  5449. const { checkboxes, inputs } = HWHData;
  5450. this.values = [
  5451. ...Object.entries(checkboxes).map((e) => ({ [e[0]]: e[1].default })),
  5452. ...Object.entries(inputs).map((e) => ({ [e[0]]: e[1].default })),
  5453. ].reduce((acc, obj) => ({ ...acc, ...obj }), {});
  5454. },
  5455. get: function (key, def) {
  5456. if (key in this.values) {
  5457. return this.values[key];
  5458. }
  5459. return def;
  5460. },
  5461. set: function (key, value) {
  5462. this.values[key] = value;
  5463. db.set(this.userId, this.values).catch((e) => null);
  5464. localStorage[this.name + ':' + key] = value;
  5465. },
  5466. delete: function (key) {
  5467. delete this.values[key];
  5468. db.set(this.userId, this.values);
  5469. delete localStorage[this.name + ':' + key];
  5470. },
  5471. };
  5472.  
  5473. /**
  5474. * Returns all keys from localStorage that start with prefix (for migration)
  5475. *
  5476. * Возвращает все ключи из localStorage которые начинаются с prefix (для миграции)
  5477. */
  5478. function getAllValuesStartingWith(prefix) {
  5479. const values = [];
  5480. for (let i = 0; i < localStorage.length; i++) {
  5481. const key = localStorage.key(i);
  5482. if (key.startsWith(prefix)) {
  5483. const val = localStorage.getItem(key);
  5484. const keyValue = key.split(':')[1];
  5485. values.push({ key: keyValue, val });
  5486. }
  5487. }
  5488. return values;
  5489. }
  5490.  
  5491. /**
  5492. * Opens or migrates to a database
  5493. *
  5494. * Открывает или мигрирует в базу данных
  5495. */
  5496. async function openOrMigrateDatabase(userId) {
  5497. storage.init();
  5498. storage.userId = userId;
  5499. try {
  5500. await db.open();
  5501. } catch(e) {
  5502. return;
  5503. }
  5504. let settings = await db.get(userId, false);
  5505.  
  5506. if (settings) {
  5507. storage.values = settings;
  5508. return;
  5509. }
  5510.  
  5511. const values = getAllValuesStartingWith(GM_info.script.name);
  5512. for (const value of values) {
  5513. let val = null;
  5514. try {
  5515. val = JSON.parse(value.val);
  5516. } catch {
  5517. break;
  5518. }
  5519. storage.values[value.key] = val;
  5520. }
  5521. await db.set(userId, storage.values);
  5522. }
  5523.  
  5524. class ZingerYWebsiteAPI {
  5525. /**
  5526. * Class for interaction with the API of the zingery.ru website
  5527. * Intended only for use with the HeroWarsHelper script:
  5528. * https://greasyfork.org/ru/scripts/450693-herowarshelper
  5529. * Copyright ZingerY
  5530. */
  5531. url = 'https://zingery.ru/heroes/';
  5532. // YWJzb2x1dGVseSB1c2VsZXNzIGxpbmU=
  5533. constructor(urn, env, data = {}) {
  5534. this.urn = urn;
  5535. this.fd = {
  5536. now: Date.now(),
  5537. fp: this.constructor.toString().replaceAll(/\s/g, ''),
  5538. env: env.callee.toString().replaceAll(/\s/g, ''),
  5539. info: (({ name, version, author }) => [name, version, author])(GM_info.script),
  5540. ...data,
  5541. };
  5542. }
  5543.  
  5544. sign() {
  5545. return md5([...this.fd.info, ~(this.fd.now % 1e3), this.fd.fp].join('_'));
  5546. }
  5547.  
  5548. encode(data) {
  5549. return btoa(encodeURIComponent(JSON.stringify(data)));
  5550. }
  5551.  
  5552. decode(data) {
  5553. return JSON.parse(decodeURIComponent(atob(data)));
  5554. }
  5555.  
  5556. headers() {
  5557. return {
  5558. 'X-Request-Signature': this.sign(),
  5559. 'X-Script-Name': GM_info.script.name,
  5560. 'X-Script-Version': GM_info.script.version,
  5561. 'X-Script-Author': GM_info.script.author,
  5562. 'X-Script-ZingerY': 42,
  5563. };
  5564. }
  5565.  
  5566. async request() {
  5567. try {
  5568. const response = await fetch(this.url + this.urn, {
  5569. method: 'POST',
  5570. headers: this.headers(),
  5571. body: this.encode(this.fd),
  5572. });
  5573. const text = await response.text();
  5574. return this.decode(text);
  5575. } catch (e) {
  5576. console.error(e);
  5577. return [];
  5578. }
  5579. }
  5580. /**
  5581. * Класс для взаимодействия с API сайта zingery.ru
  5582. * Предназначен только для использования со скриптом HeroWarsHelper:
  5583. * https://greasyfork.org/ru/scripts/450693-herowarshelper
  5584. * Copyright ZingerY
  5585. */
  5586. }
  5587.  
  5588. /**
  5589. * Sending expeditions
  5590. *
  5591. * Отправка экспедиций
  5592. */
  5593. function checkExpedition() {
  5594. const { Expedition } = HWHClasses;
  5595. return new Promise((resolve, reject) => {
  5596. const expedition = new Expedition(resolve, reject);
  5597. expedition.start();
  5598. });
  5599. }
  5600.  
  5601. class Expedition {
  5602. checkExpedInfo = {
  5603. calls: [
  5604. {
  5605. name: 'expeditionGet',
  5606. args: {},
  5607. ident: 'expeditionGet',
  5608. },
  5609. {
  5610. name: 'heroGetAll',
  5611. args: {},
  5612. ident: 'heroGetAll',
  5613. },
  5614. ],
  5615. };
  5616.  
  5617. constructor(resolve, reject) {
  5618. this.resolve = resolve;
  5619. this.reject = reject;
  5620. }
  5621.  
  5622. async start() {
  5623. const data = await Send(JSON.stringify(this.checkExpedInfo));
  5624.  
  5625. const expedInfo = data.results[0].result.response;
  5626. const dataHeroes = data.results[1].result.response;
  5627. const dataExped = { useHeroes: [], exped: [] };
  5628. const calls = [];
  5629.  
  5630. /**
  5631. * Adding expeditions to collect
  5632. * Добавляем экспедиции для сбора
  5633. */
  5634. let countGet = 0;
  5635. for (var n in expedInfo) {
  5636. const exped = expedInfo[n];
  5637. const dateNow = Date.now() / 1000;
  5638. if (exped.status == 2 && exped.endTime != 0 && dateNow > exped.endTime) {
  5639. countGet++;
  5640. calls.push({
  5641. name: 'expeditionFarm',
  5642. args: { expeditionId: exped.id },
  5643. ident: 'expeditionFarm_' + exped.id,
  5644. });
  5645. } else {
  5646. dataExped.useHeroes = dataExped.useHeroes.concat(exped.heroes);
  5647. }
  5648. if (exped.status == 1) {
  5649. dataExped.exped.push({ id: exped.id, power: exped.power });
  5650. }
  5651. }
  5652. dataExped.exped = dataExped.exped.sort((a, b) => b.power - a.power);
  5653.  
  5654. /**
  5655. * Putting together a list of heroes
  5656. * Собираем список героев
  5657. */
  5658. const heroesArr = [];
  5659. for (let n in dataHeroes) {
  5660. const hero = dataHeroes[n];
  5661. if (hero.power > 0 && !dataExped.useHeroes.includes(hero.id)) {
  5662. let heroPower = hero.power;
  5663. // Лара Крофт * 3
  5664. if (hero.id == 63 && hero.color >= 16) {
  5665. heroPower *= 3;
  5666. }
  5667. heroesArr.push({ id: hero.id, power: heroPower });
  5668. }
  5669. }
  5670.  
  5671. /**
  5672. * Adding expeditions to send
  5673. * Добавляем экспедиции для отправки
  5674. */
  5675. let countSend = 0;
  5676. heroesArr.sort((a, b) => a.power - b.power);
  5677. for (const exped of dataExped.exped) {
  5678. let heroesIds = this.selectionHeroes(heroesArr, exped.power);
  5679. if (heroesIds && heroesIds.length > 4) {
  5680. for (let q in heroesArr) {
  5681. if (heroesIds.includes(heroesArr[q].id)) {
  5682. delete heroesArr[q];
  5683. }
  5684. }
  5685. countSend++;
  5686. calls.push({
  5687. name: 'expeditionSendHeroes',
  5688. args: {
  5689. expeditionId: exped.id,
  5690. heroes: heroesIds,
  5691. },
  5692. ident: 'expeditionSendHeroes_' + exped.id,
  5693. });
  5694. }
  5695. }
  5696.  
  5697. if (calls.length) {
  5698. await Send({ calls });
  5699. this.end(I18N('EXPEDITIONS_SENT', {countGet, countSend}));
  5700. return;
  5701. }
  5702.  
  5703. this.end(I18N('EXPEDITIONS_NOTHING'));
  5704. }
  5705.  
  5706. /**
  5707. * Selection of heroes for expeditions
  5708. *
  5709. * Подбор героев для экспедиций
  5710. */
  5711. selectionHeroes(heroes, power) {
  5712. const resultHeroers = [];
  5713. const heroesIds = [];
  5714. for (let q = 0; q < 5; q++) {
  5715. for (let i in heroes) {
  5716. let hero = heroes[i];
  5717. if (heroesIds.includes(hero.id)) {
  5718. continue;
  5719. }
  5720.  
  5721. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  5722. const need = Math.round((power - summ) / (5 - resultHeroers.length));
  5723. if (hero.power > need) {
  5724. resultHeroers.push(hero);
  5725. heroesIds.push(hero.id);
  5726. break;
  5727. }
  5728. }
  5729. }
  5730.  
  5731. const summ = resultHeroers.reduce((acc, hero) => acc + hero.power, 0);
  5732. if (summ < power) {
  5733. return false;
  5734. }
  5735. return heroesIds;
  5736. }
  5737.  
  5738. /**
  5739. * Ends expedition script
  5740. *
  5741. * Завершает скрипт экспедиции
  5742. */
  5743. end(msg) {
  5744. setProgress(msg, true);
  5745. this.resolve();
  5746. }
  5747. }
  5748.  
  5749. this.HWHClasses.Expedition = Expedition;
  5750.  
  5751. /**
  5752. * Walkthrough of the dungeon
  5753. *
  5754. * Прохождение подземелья
  5755. */
  5756. function testDungeon() {
  5757. const { executeDungeon } = HWHClasses;
  5758. return new Promise((resolve, reject) => {
  5759. const dung = new executeDungeon(resolve, reject);
  5760. const titanit = getInput('countTitanit');
  5761. dung.start(titanit);
  5762. });
  5763. }
  5764.  
  5765. /**
  5766. * Walkthrough of the dungeon
  5767. *
  5768. * Прохождение подземелья
  5769. */
  5770. function executeDungeon(resolve, reject) {
  5771. dungeonActivity = 0;
  5772. let maxDungeonActivity = 150;
  5773.  
  5774. titanGetAll = [];
  5775.  
  5776. teams = {
  5777. heroes: [],
  5778. earth: [],
  5779. fire: [],
  5780. neutral: [],
  5781. water: [],
  5782. }
  5783.  
  5784. titanStats = [];
  5785.  
  5786. titansStates = {};
  5787.  
  5788. let talentMsg = '';
  5789. let talentMsgReward = '';
  5790.  
  5791. callsExecuteDungeon = {
  5792. calls: [{
  5793. name: "dungeonGetInfo",
  5794. args: {},
  5795. ident: "dungeonGetInfo"
  5796. }, {
  5797. name: "teamGetAll",
  5798. args: {},
  5799. ident: "teamGetAll"
  5800. }, {
  5801. name: "teamGetFavor",
  5802. args: {},
  5803. ident: "teamGetFavor"
  5804. }, {
  5805. name: "clanGetInfo",
  5806. args: {},
  5807. ident: "clanGetInfo"
  5808. }, {
  5809. name: "titanGetAll",
  5810. args: {},
  5811. ident: "titanGetAll"
  5812. }, {
  5813. name: "inventoryGet",
  5814. args: {},
  5815. ident: "inventoryGet"
  5816. }]
  5817. }
  5818.  
  5819. this.start = function(titanit) {
  5820. maxDungeonActivity = titanit || getInput('countTitanit');
  5821. send(JSON.stringify(callsExecuteDungeon), startDungeon);
  5822. }
  5823.  
  5824. /**
  5825. * Getting data on the dungeon
  5826. *
  5827. * Получаем данные по подземелью
  5828. */
  5829. function startDungeon(e) {
  5830. res = e.results;
  5831. dungeonGetInfo = res[0].result.response;
  5832. if (!dungeonGetInfo) {
  5833. endDungeon('noDungeon', res);
  5834. return;
  5835. }
  5836. teamGetAll = res[1].result.response;
  5837. teamGetFavor = res[2].result.response;
  5838. dungeonActivity = res[3].result.response.stat.todayDungeonActivity;
  5839. titanGetAll = Object.values(res[4].result.response);
  5840. HWHData.countPredictionCard = res[5].result.response.consumable[81];
  5841.  
  5842. teams.hero = {
  5843. favor: teamGetFavor.dungeon_hero,
  5844. heroes: teamGetAll.dungeon_hero.filter(id => id < 6000),
  5845. teamNum: 0,
  5846. }
  5847. heroPet = teamGetAll.dungeon_hero.filter(id => id >= 6000).pop();
  5848. if (heroPet) {
  5849. teams.hero.pet = heroPet;
  5850. }
  5851.  
  5852. teams.neutral = {
  5853. favor: {},
  5854. heroes: getTitanTeam(titanGetAll, 'neutral'),
  5855. teamNum: 0,
  5856. };
  5857. teams.water = {
  5858. favor: {},
  5859. heroes: getTitanTeam(titanGetAll, 'water'),
  5860. teamNum: 0,
  5861. };
  5862. teams.fire = {
  5863. favor: {},
  5864. heroes: getTitanTeam(titanGetAll, 'fire'),
  5865. teamNum: 0,
  5866. };
  5867. teams.earth = {
  5868. favor: {},
  5869. heroes: getTitanTeam(titanGetAll, 'earth'),
  5870. teamNum: 0,
  5871. };
  5872.  
  5873.  
  5874. checkFloor(dungeonGetInfo);
  5875. }
  5876.  
  5877. function getTitanTeam(titans, type) {
  5878. switch (type) {
  5879. case 'neutral':
  5880. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5881. case 'water':
  5882. return titans.filter(e => e.id.toString().slice(2, 3) == '0').map(e => e.id);
  5883. case 'fire':
  5884. return titans.filter(e => e.id.toString().slice(2, 3) == '1').map(e => e.id);
  5885. case 'earth':
  5886. return titans.filter(e => e.id.toString().slice(2, 3) == '2').map(e => e.id);
  5887. }
  5888. }
  5889.  
  5890. function getNeutralTeam() {
  5891. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  5892. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5893. }
  5894.  
  5895. function fixTitanTeam(titans) {
  5896. titans.heroes = titans.heroes.filter(e => !titansStates[e]?.isDead);
  5897. return titans;
  5898. }
  5899.  
  5900. /**
  5901. * Checking the floor
  5902. *
  5903. * Проверяем этаж
  5904. */
  5905. async function checkFloor(dungeonInfo) {
  5906. if (!('floor' in dungeonInfo) || dungeonInfo.floor?.state == 2) {
  5907. saveProgress();
  5908. return;
  5909. }
  5910. checkTalent(dungeonInfo);
  5911. // console.log(dungeonInfo, dungeonActivity);
  5912. maxDungeonActivity = +getInput('countTitanit');
  5913. setProgress(`${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity} ${talentMsg}`);
  5914. if (dungeonActivity >= maxDungeonActivity) {
  5915. endDungeon('endDungeon', 'maxActive ' + dungeonActivity + '/' + maxDungeonActivity);
  5916. return;
  5917. }
  5918. titansStates = dungeonInfo.states.titans;
  5919. titanStats = titanObjToArray(titansStates);
  5920. const floorChoices = dungeonInfo.floor.userData;
  5921. const floorType = dungeonInfo.floorType;
  5922. //const primeElement = dungeonInfo.elements.prime;
  5923. if (floorType == "battle") {
  5924. const calls = [];
  5925. for (let teamNum in floorChoices) {
  5926. attackerType = floorChoices[teamNum].attackerType;
  5927. const args = fixTitanTeam(teams[attackerType]);
  5928. if (attackerType == 'neutral') {
  5929. args.heroes = getNeutralTeam();
  5930. }
  5931. if (!args.heroes.length) {
  5932. continue;
  5933. }
  5934. args.teamNum = teamNum;
  5935. calls.push({
  5936. name: "dungeonStartBattle",
  5937. args,
  5938. ident: "body_" + teamNum
  5939. })
  5940. }
  5941. if (!calls.length) {
  5942. endDungeon('endDungeon', 'All Dead');
  5943. return;
  5944. }
  5945. const battleDatas = await Send(JSON.stringify({ calls }))
  5946. .then(e => e.results.map(n => n.result.response))
  5947. const battleResults = [];
  5948. for (n in battleDatas) {
  5949. battleData = battleDatas[n]
  5950. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  5951. battleResults.push(await Calc(battleData).then(result => {
  5952. result.teamNum = n;
  5953. result.attackerType = floorChoices[n].attackerType;
  5954. return result;
  5955. }));
  5956. }
  5957. processingPromises(battleResults)
  5958. }
  5959. }
  5960.  
  5961. async function checkTalent(dungeonInfo) {
  5962. const talent = dungeonInfo.talent;
  5963. if (!talent) {
  5964. return;
  5965. }
  5966. const dungeonFloor = +dungeonInfo.floorNumber;
  5967. const talentFloor = +talent.floorRandValue;
  5968. let doorsAmount = 3 - talent.conditions.doorsAmount;
  5969.  
  5970. if (dungeonFloor === talentFloor && (!doorsAmount || !talent.conditions?.farmedDoors[dungeonFloor])) {
  5971. const reward = await Send({
  5972. calls: [
  5973. { name: 'heroTalent_getReward', args: { talentType: 'tmntDungeonTalent', reroll: false }, ident: 'group_0_body' },
  5974. { name: 'heroTalent_farmReward', args: { talentType: 'tmntDungeonTalent' }, ident: 'group_1_body' },
  5975. ],
  5976. }).then((e) => e.results[0].result.response);
  5977. const type = Object.keys(reward).pop();
  5978. const itemId = Object.keys(reward[type]).pop();
  5979. const count = reward[type][itemId];
  5980. const itemName = cheats.translate(`LIB_${type.toUpperCase()}_NAME_${itemId}`);
  5981. talentMsgReward += `<br> ${count} ${itemName}`;
  5982. doorsAmount++;
  5983. }
  5984. talentMsg = `<br>TMNT Talent: ${doorsAmount}/3 ${talentMsgReward}<br>`;
  5985. }
  5986.  
  5987. function processingPromises(results) {
  5988. let selectBattle = results[0];
  5989. if (results.length < 2) {
  5990. // console.log(selectBattle);
  5991. if (!selectBattle.result.win) {
  5992. endDungeon('dungeonEndBattle\n', selectBattle);
  5993. return;
  5994. }
  5995. endBattle(selectBattle);
  5996. return;
  5997. }
  5998.  
  5999. selectBattle = false;
  6000. let bestState = -1000;
  6001. for (const result of results) {
  6002. const recovery = getState(result);
  6003. if (recovery > bestState) {
  6004. bestState = recovery;
  6005. selectBattle = result
  6006. }
  6007. }
  6008. // console.log(selectBattle.teamNum, results);
  6009. if (!selectBattle || bestState <= -1000) {
  6010. endDungeon('dungeonEndBattle\n', results);
  6011. return;
  6012. }
  6013.  
  6014. startBattle(selectBattle.teamNum, selectBattle.attackerType)
  6015. .then(endBattle);
  6016. }
  6017.  
  6018. /**
  6019. * Let's start the fight
  6020. *
  6021. * Начинаем бой
  6022. */
  6023. function startBattle(teamNum, attackerType) {
  6024. return new Promise(function (resolve, reject) {
  6025. args = fixTitanTeam(teams[attackerType]);
  6026. args.teamNum = teamNum;
  6027. if (attackerType == 'neutral') {
  6028. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  6029. args.heroes = titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  6030. }
  6031. startBattleCall = {
  6032. calls: [{
  6033. name: "dungeonStartBattle",
  6034. args,
  6035. ident: "body"
  6036. }]
  6037. }
  6038. send(JSON.stringify(startBattleCall), resultBattle, {
  6039. resolve,
  6040. teamNum,
  6041. attackerType
  6042. });
  6043. });
  6044. }
  6045. /**
  6046. * Returns the result of the battle in a promise
  6047. *
  6048. * Возращает резульат боя в промис
  6049. */
  6050. function resultBattle(resultBattles, args) {
  6051. battleData = resultBattles.results[0].result.response;
  6052. battleType = "get_tower";
  6053. if (battleData.type == "dungeon_titan") {
  6054. battleType = "get_titan";
  6055. }
  6056. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  6057. BattleCalc(battleData, battleType, function (result) {
  6058. result.teamNum = args.teamNum;
  6059. result.attackerType = args.attackerType;
  6060. args.resolve(result);
  6061. });
  6062. }
  6063. /**
  6064. * Finishing the fight
  6065. *
  6066. * Заканчиваем бой
  6067. */
  6068. async function endBattle(battleInfo) {
  6069. if (battleInfo.result.win) {
  6070. const args = {
  6071. result: battleInfo.result,
  6072. progress: battleInfo.progress,
  6073. }
  6074. if (HWHData.countPredictionCard > 0) {
  6075. args.isRaid = true;
  6076. } else {
  6077. const timer = getTimer(battleInfo.battleTime);
  6078. console.log(timer);
  6079. await countdownTimer(timer, `${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity} ${talentMsg}`);
  6080. }
  6081. const calls = [{
  6082. name: "dungeonEndBattle",
  6083. args,
  6084. ident: "body"
  6085. }];
  6086. lastDungeonBattleData = null;
  6087. send(JSON.stringify({ calls }), resultEndBattle);
  6088. } else {
  6089. endDungeon('dungeonEndBattle win: false\n', battleInfo);
  6090. }
  6091. }
  6092.  
  6093. /**
  6094. * Getting and processing battle results
  6095. *
  6096. * Получаем и обрабатываем результаты боя
  6097. */
  6098. function resultEndBattle(e) {
  6099. if ('error' in e) {
  6100. popup.confirm(I18N('ERROR_MSG', {
  6101. name: e.error.name,
  6102. description: e.error.description,
  6103. }));
  6104. endDungeon('errorRequest', e);
  6105. return;
  6106. }
  6107. battleResult = e.results[0].result.response;
  6108. if ('error' in battleResult) {
  6109. endDungeon('errorBattleResult', battleResult);
  6110. return;
  6111. }
  6112. dungeonGetInfo = battleResult.dungeon ?? battleResult;
  6113. dungeonActivity += battleResult.reward.dungeonActivity ?? 0;
  6114. checkFloor(dungeonGetInfo);
  6115. }
  6116.  
  6117. /**
  6118. * Returns the coefficient of condition of the
  6119. * difference in titanium before and after the battle
  6120. *
  6121. * Возвращает коэффициент состояния титанов после боя
  6122. */
  6123. function getState(result) {
  6124. if (!result.result.win) {
  6125. return -1000;
  6126. }
  6127.  
  6128. let beforeSumFactor = 0;
  6129. const beforeTitans = result.battleData.attackers;
  6130. for (let titanId in beforeTitans) {
  6131. const titan = beforeTitans[titanId];
  6132. const state = titan.state;
  6133. let factor = 1;
  6134. if (state) {
  6135. const hp = state.hp / titan.hp;
  6136. const energy = state.energy / 1e3;
  6137. factor = hp + energy / 20
  6138. }
  6139. beforeSumFactor += factor;
  6140. }
  6141.  
  6142. let afterSumFactor = 0;
  6143. const afterTitans = result.progress[0].attackers.heroes;
  6144. for (let titanId in afterTitans) {
  6145. const titan = afterTitans[titanId];
  6146. const hp = titan.hp / beforeTitans[titanId].hp;
  6147. const energy = titan.energy / 1e3;
  6148. const factor = hp + energy / 20;
  6149. afterSumFactor += factor;
  6150. }
  6151. return afterSumFactor - beforeSumFactor;
  6152. }
  6153.  
  6154. /**
  6155. * Converts an object with IDs to an array with IDs
  6156. *
  6157. * Преобразует объект с идетификаторами в массив с идетификаторами
  6158. */
  6159. function titanObjToArray(obj) {
  6160. let titans = [];
  6161. for (let id in obj) {
  6162. obj[id].id = id;
  6163. titans.push(obj[id]);
  6164. }
  6165. return titans;
  6166. }
  6167.  
  6168. function saveProgress() {
  6169. let saveProgressCall = {
  6170. calls: [{
  6171. name: "dungeonSaveProgress",
  6172. args: {},
  6173. ident: "body"
  6174. }]
  6175. }
  6176. send(JSON.stringify(saveProgressCall), resultEndBattle);
  6177. }
  6178.  
  6179. function endDungeon(reason, info) {
  6180. console.warn(reason, info);
  6181. setProgress(`${I18N('DUNGEON')} ${I18N('COMPLETED')}`, true);
  6182. resolve();
  6183. }
  6184. }
  6185.  
  6186. this.HWHClasses.executeDungeon = executeDungeon;
  6187.  
  6188. /**
  6189. * Passing the tower
  6190. *
  6191. * Прохождение башни
  6192. */
  6193. function testTower() {
  6194. const { executeTower } = HWHClasses;
  6195. return new Promise((resolve, reject) => {
  6196. tower = new executeTower(resolve, reject);
  6197. tower.start();
  6198. });
  6199. }
  6200.  
  6201. /**
  6202. * Passing the tower
  6203. *
  6204. * Прохождение башни
  6205. */
  6206. function executeTower(resolve, reject) {
  6207. lastTowerInfo = {};
  6208.  
  6209. scullCoin = 0;
  6210.  
  6211. heroGetAll = [];
  6212.  
  6213. heroesStates = {};
  6214.  
  6215. argsBattle = {
  6216. heroes: [],
  6217. favor: {},
  6218. };
  6219.  
  6220. callsExecuteTower = {
  6221. calls: [{
  6222. name: "towerGetInfo",
  6223. args: {},
  6224. ident: "towerGetInfo"
  6225. }, {
  6226. name: "teamGetAll",
  6227. args: {},
  6228. ident: "teamGetAll"
  6229. }, {
  6230. name: "teamGetFavor",
  6231. args: {},
  6232. ident: "teamGetFavor"
  6233. }, {
  6234. name: "inventoryGet",
  6235. args: {},
  6236. ident: "inventoryGet"
  6237. }, {
  6238. name: "heroGetAll",
  6239. args: {},
  6240. ident: "heroGetAll"
  6241. }]
  6242. }
  6243.  
  6244. buffIds = [
  6245. {id: 0, cost: 0, isBuy: false}, // plug // заглушка
  6246. {id: 1, cost: 1, isBuy: true}, // 3% attack // 3% атака
  6247. {id: 2, cost: 6, isBuy: true}, // 2% attack // 2% атака
  6248. {id: 3, cost: 16, isBuy: true}, // 4% attack // 4% атака
  6249. {id: 4, cost: 40, isBuy: true}, // 8% attack // 8% атака
  6250. {id: 5, cost: 1, isBuy: true}, // 10% armor // 10% броня
  6251. {id: 6, cost: 6, isBuy: true}, // 5% armor // 5% броня
  6252. {id: 7, cost: 16, isBuy: true}, // 10% armor // 10% броня
  6253. {id: 8, cost: 40, isBuy: true}, // 20% armor // 20% броня
  6254. { id: 9, cost: 1, isBuy: true }, // 10% protection from magic // 10% защита от магии
  6255. { id: 10, cost: 6, isBuy: true }, // 5% protection from magic // 5% защита от магии
  6256. { id: 11, cost: 16, isBuy: true }, // 10% protection from magic // 10% защита от магии
  6257. { id: 12, cost: 40, isBuy: true }, // 20% protection from magic // 20% защита от магии
  6258. { id: 13, cost: 1, isBuy: false }, // 40% health hero // 40% здоровья герою
  6259. { id: 14, cost: 6, isBuy: false }, // 40% health hero // 40% здоровья герою
  6260. { id: 15, cost: 16, isBuy: false }, // 80% health hero // 80% здоровья герою
  6261. { id: 16, cost: 40, isBuy: false }, // 40% health to all heroes // 40% здоровья всем героям
  6262. { id: 17, cost: 1, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  6263. { id: 18, cost: 3, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  6264. { id: 19, cost: 8, isBuy: false }, // 80% energy to the hero // 80% энергии герою
  6265. { id: 20, cost: 20, isBuy: false }, // 40% energy to all heroes // 40% энергии всем героям
  6266. { id: 21, cost: 40, isBuy: false }, // Hero Resurrection // Воскрешение героя
  6267. ]
  6268.  
  6269. this.start = function () {
  6270. send(JSON.stringify(callsExecuteTower), startTower);
  6271. }
  6272.  
  6273. /**
  6274. * Getting data on the Tower
  6275. *
  6276. * Получаем данные по башне
  6277. */
  6278. function startTower(e) {
  6279. res = e.results;
  6280. towerGetInfo = res[0].result.response;
  6281. if (!towerGetInfo) {
  6282. endTower('noTower', res);
  6283. return;
  6284. }
  6285. teamGetAll = res[1].result.response;
  6286. teamGetFavor = res[2].result.response;
  6287. inventoryGet = res[3].result.response;
  6288. heroGetAll = Object.values(res[4].result.response);
  6289.  
  6290. scullCoin = inventoryGet.coin[7] ?? 0;
  6291.  
  6292. argsBattle.favor = teamGetFavor.tower;
  6293. argsBattle.heroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  6294. pet = teamGetAll.tower.filter(id => id >= 6000).pop();
  6295. if (pet) {
  6296. argsBattle.pet = pet;
  6297. }
  6298.  
  6299. checkFloor(towerGetInfo);
  6300. }
  6301.  
  6302. function fixHeroesTeam(argsBattle) {
  6303. let fixHeroes = argsBattle.heroes.filter(e => !heroesStates[e]?.isDead);
  6304. if (fixHeroes.length < 5) {
  6305. heroGetAll = heroGetAll.filter(e => !heroesStates[e.id]?.isDead);
  6306. fixHeroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  6307. Object.keys(argsBattle.favor).forEach(e => {
  6308. if (!fixHeroes.includes(+e)) {
  6309. delete argsBattle.favor[e];
  6310. }
  6311. })
  6312. }
  6313. argsBattle.heroes = fixHeroes;
  6314. return argsBattle;
  6315. }
  6316.  
  6317. /**
  6318. * Check the floor
  6319. *
  6320. * Проверяем этаж
  6321. */
  6322. function checkFloor(towerInfo) {
  6323. lastTowerInfo = towerInfo;
  6324. maySkipFloor = +towerInfo.maySkipFloor;
  6325. floorNumber = +towerInfo.floorNumber;
  6326. heroesStates = towerInfo.states.heroes;
  6327. floorInfo = towerInfo.floor;
  6328.  
  6329. /**
  6330. * Is there at least one chest open on the floor
  6331. * Открыт ли на этаже хоть один сундук
  6332. */
  6333. isOpenChest = false;
  6334. if (towerInfo.floorType == "chest") {
  6335. isOpenChest = towerInfo.floor.chests.reduce((n, e) => n + e.opened, 0);
  6336. }
  6337.  
  6338. setProgress(`${I18N('TOWER')}: ${I18N('FLOOR')} ${floorNumber}`);
  6339. if (floorNumber > 49) {
  6340. if (isOpenChest) {
  6341. endTower('alreadyOpenChest 50 floor', floorNumber);
  6342. return;
  6343. }
  6344. }
  6345. /**
  6346. * If the chest is open and you can skip floors, then move on
  6347. * Если сундук открыт и можно скипать этажи, то переходим дальше
  6348. */
  6349. if (towerInfo.mayFullSkip && +towerInfo.teamLevel == 130) {
  6350. if (floorNumber == 1) {
  6351. fullSkipTower();
  6352. return;
  6353. }
  6354. if (isOpenChest) {
  6355. nextOpenChest(floorNumber);
  6356. } else {
  6357. nextChestOpen(floorNumber);
  6358. }
  6359. return;
  6360. }
  6361.  
  6362. // console.log(towerInfo, scullCoin);
  6363. switch (towerInfo.floorType) {
  6364. case "battle":
  6365. if (floorNumber <= maySkipFloor) {
  6366. skipFloor();
  6367. return;
  6368. }
  6369. if (floorInfo.state == 2) {
  6370. nextFloor();
  6371. return;
  6372. }
  6373. startBattle().then(endBattle);
  6374. return;
  6375. case "buff":
  6376. checkBuff(towerInfo);
  6377. return;
  6378. case "chest":
  6379. openChest(floorNumber);
  6380. return;
  6381. default:
  6382. console.log('!', towerInfo.floorType, towerInfo);
  6383. break;
  6384. }
  6385. }
  6386.  
  6387. /**
  6388. * Let's start the fight
  6389. *
  6390. * Начинаем бой
  6391. */
  6392. function startBattle() {
  6393. return new Promise(function (resolve, reject) {
  6394. towerStartBattle = {
  6395. calls: [{
  6396. name: "towerStartBattle",
  6397. args: fixHeroesTeam(argsBattle),
  6398. ident: "body"
  6399. }]
  6400. }
  6401. send(JSON.stringify(towerStartBattle), resultBattle, resolve);
  6402. });
  6403. }
  6404. /**
  6405. * Returns the result of the battle in a promise
  6406. *
  6407. * Возращает резульат боя в промис
  6408. */
  6409. function resultBattle(resultBattles, resolve) {
  6410. battleData = resultBattles.results[0].result.response;
  6411. battleType = "get_tower";
  6412. BattleCalc(battleData, battleType, function (result) {
  6413. resolve(result);
  6414. });
  6415. }
  6416. /**
  6417. * Finishing the fight
  6418. *
  6419. * Заканчиваем бой
  6420. */
  6421. function endBattle(battleInfo) {
  6422. if (battleInfo.result.stars >= 3) {
  6423. endBattleCall = {
  6424. calls: [{
  6425. name: "towerEndBattle",
  6426. args: {
  6427. result: battleInfo.result,
  6428. progress: battleInfo.progress,
  6429. },
  6430. ident: "body"
  6431. }]
  6432. }
  6433. send(JSON.stringify(endBattleCall), resultEndBattle);
  6434. } else {
  6435. endTower('towerEndBattle win: false\n', battleInfo);
  6436. }
  6437. }
  6438.  
  6439. /**
  6440. * Getting and processing battle results
  6441. *
  6442. * Получаем и обрабатываем результаты боя
  6443. */
  6444. function resultEndBattle(e) {
  6445. battleResult = e.results[0].result.response;
  6446. if ('error' in battleResult) {
  6447. endTower('errorBattleResult', battleResult);
  6448. return;
  6449. }
  6450. if ('reward' in battleResult) {
  6451. scullCoin += battleResult.reward?.coin[7] ?? 0;
  6452. }
  6453. nextFloor();
  6454. }
  6455.  
  6456. function nextFloor() {
  6457. nextFloorCall = {
  6458. calls: [{
  6459. name: "towerNextFloor",
  6460. args: {},
  6461. ident: "body"
  6462. }]
  6463. }
  6464. send(JSON.stringify(nextFloorCall), checkDataFloor);
  6465. }
  6466.  
  6467. function openChest(floorNumber) {
  6468. floorNumber = floorNumber || 0;
  6469. openChestCall = {
  6470. calls: [{
  6471. name: "towerOpenChest",
  6472. args: {
  6473. num: 2
  6474. },
  6475. ident: "body"
  6476. }]
  6477. }
  6478. send(JSON.stringify(openChestCall), floorNumber < 50 ? nextFloor : lastChest);
  6479. }
  6480.  
  6481. function lastChest() {
  6482. endTower('openChest 50 floor', floorNumber);
  6483. }
  6484.  
  6485. function skipFloor() {
  6486. skipFloorCall = {
  6487. calls: [{
  6488. name: "towerSkipFloor",
  6489. args: {},
  6490. ident: "body"
  6491. }]
  6492. }
  6493. send(JSON.stringify(skipFloorCall), checkDataFloor);
  6494. }
  6495.  
  6496. function checkBuff(towerInfo) {
  6497. buffArr = towerInfo.floor;
  6498. promises = [];
  6499. for (let buff of buffArr) {
  6500. buffInfo = buffIds[buff.id];
  6501. if (buffInfo.isBuy && buffInfo.cost <= scullCoin) {
  6502. scullCoin -= buffInfo.cost;
  6503. promises.push(buyBuff(buff.id));
  6504. }
  6505. }
  6506. Promise.all(promises).then(nextFloor);
  6507. }
  6508.  
  6509. function buyBuff(buffId) {
  6510. return new Promise(function (resolve, reject) {
  6511. buyBuffCall = {
  6512. calls: [{
  6513. name: "towerBuyBuff",
  6514. args: {
  6515. buffId
  6516. },
  6517. ident: "body"
  6518. }]
  6519. }
  6520. send(JSON.stringify(buyBuffCall), resolve);
  6521. });
  6522. }
  6523.  
  6524. function checkDataFloor(result) {
  6525. towerInfo = result.results[0].result.response;
  6526. if ('reward' in towerInfo && towerInfo.reward?.coin) {
  6527. scullCoin += towerInfo.reward?.coin[7] ?? 0;
  6528. }
  6529. if ('tower' in towerInfo) {
  6530. towerInfo = towerInfo.tower;
  6531. }
  6532. if ('skullReward' in towerInfo) {
  6533. scullCoin += towerInfo.skullReward?.coin[7] ?? 0;
  6534. }
  6535. checkFloor(towerInfo);
  6536. }
  6537. /**
  6538. * Getting tower rewards
  6539. *
  6540. * Получаем награды башни
  6541. */
  6542. function farmTowerRewards(reason) {
  6543. let { pointRewards, points } = lastTowerInfo;
  6544. let pointsAll = Object.getOwnPropertyNames(pointRewards);
  6545. let farmPoints = pointsAll.filter(e => +e <= +points && !pointRewards[e]);
  6546. if (!farmPoints.length) {
  6547. return;
  6548. }
  6549. let farmTowerRewardsCall = {
  6550. calls: [{
  6551. name: "tower_farmPointRewards",
  6552. args: {
  6553. points: farmPoints
  6554. },
  6555. ident: "tower_farmPointRewards"
  6556. }]
  6557. }
  6558.  
  6559. if (scullCoin > 0) {
  6560. farmTowerRewardsCall.calls.push({
  6561. name: "tower_farmSkullReward",
  6562. args: {},
  6563. ident: "tower_farmSkullReward"
  6564. });
  6565. }
  6566.  
  6567. send(JSON.stringify(farmTowerRewardsCall), () => { });
  6568. }
  6569.  
  6570. function fullSkipTower() {
  6571. /**
  6572. * Next chest
  6573. *
  6574. * Следующий сундук
  6575. */
  6576. function nextChest(n) {
  6577. return {
  6578. name: "towerNextChest",
  6579. args: {},
  6580. ident: "group_" + n + "_body"
  6581. }
  6582. }
  6583. /**
  6584. * Open chest
  6585. *
  6586. * Открыть сундук
  6587. */
  6588. function openChest(n) {
  6589. return {
  6590. name: "towerOpenChest",
  6591. args: {
  6592. "num": 2
  6593. },
  6594. ident: "group_" + n + "_body"
  6595. }
  6596. }
  6597.  
  6598. const fullSkipTowerCall = {
  6599. calls: []
  6600. }
  6601.  
  6602. let n = 0;
  6603. for (let i = 0; i < 15; i++) {
  6604. // 15 сундуков
  6605. fullSkipTowerCall.calls.push(nextChest(++n));
  6606. fullSkipTowerCall.calls.push(openChest(++n));
  6607. // +5 сундуков, 250 изюма // towerOpenChest
  6608. // if (i < 5) {
  6609. // fullSkipTowerCall.calls.push(openChest(++n, 2));
  6610. // }
  6611. }
  6612.  
  6613. fullSkipTowerCall.calls.push({
  6614. name: 'towerGetInfo',
  6615. args: {},
  6616. ident: 'group_' + ++n + '_body',
  6617. });
  6618.  
  6619. send(JSON.stringify(fullSkipTowerCall), data => {
  6620. for (const r of data.results) {
  6621. const towerInfo = r?.result?.response;
  6622. if (towerInfo && 'skullReward' in towerInfo) {
  6623. scullCoin += towerInfo.skullReward?.coin[7] ?? 0;
  6624. }
  6625. }
  6626. data.results[0] = data.results[data.results.length - 1];
  6627. checkDataFloor(data);
  6628. });
  6629. }
  6630.  
  6631. function nextChestOpen(floorNumber) {
  6632. const calls = [{
  6633. name: "towerOpenChest",
  6634. args: {
  6635. num: 2
  6636. },
  6637. ident: "towerOpenChest"
  6638. }];
  6639.  
  6640. Send(JSON.stringify({ calls })).then(e => {
  6641. nextOpenChest(floorNumber);
  6642. });
  6643. }
  6644.  
  6645. function nextOpenChest(floorNumber) {
  6646. if (floorNumber > 49) {
  6647. endTower('openChest 50 floor', floorNumber);
  6648. return;
  6649. }
  6650.  
  6651. let nextOpenChestCall = {
  6652. calls: [{
  6653. name: "towerNextChest",
  6654. args: {},
  6655. ident: "towerNextChest"
  6656. }, {
  6657. name: "towerOpenChest",
  6658. args: {
  6659. num: 2
  6660. },
  6661. ident: "towerOpenChest"
  6662. }]
  6663. }
  6664. send(JSON.stringify(nextOpenChestCall), checkDataFloor);
  6665. }
  6666.  
  6667. function endTower(reason, info) {
  6668. console.log(reason, info);
  6669. if (reason != 'noTower') {
  6670. farmTowerRewards(reason);
  6671. }
  6672. setProgress(`${I18N('TOWER')} ${I18N('COMPLETED')}!`, true);
  6673. resolve();
  6674. }
  6675. }
  6676.  
  6677. this.HWHClasses.executeTower = executeTower;
  6678.  
  6679. /**
  6680. * Passage of the arena of the titans
  6681. *
  6682. * Прохождение арены титанов
  6683. */
  6684. function testTitanArena() {
  6685. const { executeTitanArena } = HWHClasses;
  6686. return new Promise((resolve, reject) => {
  6687. titAren = new executeTitanArena(resolve, reject);
  6688. titAren.start();
  6689. });
  6690. }
  6691.  
  6692. /**
  6693. * Passage of the arena of the titans
  6694. *
  6695. * Прохождение арены титанов
  6696. */
  6697. function executeTitanArena(resolve, reject) {
  6698. let titan_arena = [];
  6699. let finishListBattle = [];
  6700. /**
  6701. * ID of the current batch
  6702. *
  6703. * Идетификатор текущей пачки
  6704. */
  6705. let currentRival = 0;
  6706. /**
  6707. * Number of attempts to finish off the pack
  6708. *
  6709. * Количество попыток добития пачки
  6710. */
  6711. let attempts = 0;
  6712. /**
  6713. * Was there an attempt to finish off the current shooting range
  6714. *
  6715. * Была ли попытка добития текущего тира
  6716. */
  6717. let isCheckCurrentTier = false;
  6718. /**
  6719. * Current shooting range
  6720. *
  6721. * Текущий тир
  6722. */
  6723. let currTier = 0;
  6724. /**
  6725. * Number of battles on the current dash
  6726. *
  6727. * Количество битв на текущем тире
  6728. */
  6729. let countRivalsTier = 0;
  6730.  
  6731. let callsStart = {
  6732. calls: [{
  6733. name: "titanArenaGetStatus",
  6734. args: {},
  6735. ident: "titanArenaGetStatus"
  6736. }, {
  6737. name: "teamGetAll",
  6738. args: {},
  6739. ident: "teamGetAll"
  6740. }]
  6741. }
  6742.  
  6743. this.start = function () {
  6744. send(JSON.stringify(callsStart), startTitanArena);
  6745. }
  6746.  
  6747. function startTitanArena(data) {
  6748. let titanArena = data.results[0].result.response;
  6749. if (titanArena.status == 'disabled') {
  6750. endTitanArena('disabled', titanArena);
  6751. return;
  6752. }
  6753.  
  6754. let teamGetAll = data.results[1].result.response;
  6755. titan_arena = teamGetAll.titan_arena;
  6756.  
  6757. checkTier(titanArena)
  6758. }
  6759.  
  6760. function checkTier(titanArena) {
  6761. if (titanArena.status == "peace_time") {
  6762. endTitanArena('Peace_time', titanArena);
  6763. return;
  6764. }
  6765. currTier = titanArena.tier;
  6766. if (currTier) {
  6767. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier}`);
  6768. }
  6769.  
  6770. if (titanArena.status == "completed_tier") {
  6771. titanArenaCompleteTier();
  6772. return;
  6773. }
  6774. /**
  6775. * Checking for the possibility of a raid
  6776. * Проверка на возможность рейда
  6777. */
  6778. if (titanArena.canRaid) {
  6779. titanArenaStartRaid();
  6780. return;
  6781. }
  6782. /**
  6783. * Check was an attempt to achieve the current shooting range
  6784. * Проверка была ли попытка добития текущего тира
  6785. */
  6786. if (!isCheckCurrentTier) {
  6787. checkRivals(titanArena.rivals);
  6788. return;
  6789. }
  6790.  
  6791. endTitanArena('Done or not canRaid', titanArena);
  6792. }
  6793. /**
  6794. * Submit dash information for verification
  6795. *
  6796. * Отправка информации о тире на проверку
  6797. */
  6798. function checkResultInfo(data) {
  6799. let titanArena = data.results[0].result.response;
  6800. checkTier(titanArena);
  6801. }
  6802. /**
  6803. * Finish the current tier
  6804. *
  6805. * Завершить текущий тир
  6806. */
  6807. function titanArenaCompleteTier() {
  6808. isCheckCurrentTier = false;
  6809. let calls = [{
  6810. name: "titanArenaCompleteTier",
  6811. args: {},
  6812. ident: "body"
  6813. }];
  6814. send(JSON.stringify({calls}), checkResultInfo);
  6815. }
  6816. /**
  6817. * Gathering points to be completed
  6818. *
  6819. * Собираем точки которые нужно добить
  6820. */
  6821. function checkRivals(rivals) {
  6822. finishListBattle = [];
  6823. for (let n in rivals) {
  6824. if (rivals[n].attackScore < 250) {
  6825. finishListBattle.push(n);
  6826. }
  6827. }
  6828. console.log('checkRivals', finishListBattle);
  6829. countRivalsTier = finishListBattle.length;
  6830. roundRivals();
  6831. }
  6832. /**
  6833. * Selecting the next point to finish off
  6834. *
  6835. * Выбор следующей точки для добития
  6836. */
  6837. function roundRivals() {
  6838. let countRivals = finishListBattle.length;
  6839. if (!countRivals) {
  6840. /**
  6841. * Whole range checked
  6842. *
  6843. * Весь тир проверен
  6844. */
  6845. isCheckCurrentTier = true;
  6846. titanArenaGetStatus();
  6847. return;
  6848. }
  6849. // setProgress('TitanArena: Уровень ' + currTier + ' Бои: ' + (countRivalsTier - countRivals + 1) + '/' + countRivalsTier);
  6850. currentRival = finishListBattle.pop();
  6851. attempts = +currentRival;
  6852. // console.log('roundRivals', currentRival);
  6853. titanArenaStartBattle(currentRival);
  6854. }
  6855. /**
  6856. * The start of a solo battle
  6857. *
  6858. * Начало одиночной битвы
  6859. */
  6860. function titanArenaStartBattle(rivalId) {
  6861. let calls = [{
  6862. name: "titanArenaStartBattle",
  6863. args: {
  6864. rivalId: rivalId,
  6865. titans: titan_arena
  6866. },
  6867. ident: "body"
  6868. }];
  6869. send(JSON.stringify({calls}), calcResult);
  6870. }
  6871. /**
  6872. * Calculation of the results of the battle
  6873. *
  6874. * Расчет результатов боя
  6875. */
  6876. function calcResult(data) {
  6877. let battlesInfo = data.results[0].result.response.battle;
  6878. /**
  6879. * If attempts are equal to the current battle number we make
  6880. * Если попытки равны номеру текущего боя делаем прерасчет
  6881. */
  6882. if (attempts == currentRival) {
  6883. preCalcBattle(battlesInfo);
  6884. return;
  6885. }
  6886. /**
  6887. * If there are still attempts, we calculate a new battle
  6888. * Если попытки еще есть делаем расчет нового боя
  6889. */
  6890. if (attempts > 0) {
  6891. attempts--;
  6892. calcBattleResult(battlesInfo)
  6893. .then(resultCalcBattle);
  6894. return;
  6895. }
  6896. /**
  6897. * Otherwise, go to the next opponent
  6898. * Иначе переходим к следующему сопернику
  6899. */
  6900. roundRivals();
  6901. }
  6902. /**
  6903. * Processing the results of the battle calculation
  6904. *
  6905. * Обработка результатов расчета битвы
  6906. */
  6907. async function resultCalcBattle(resultBattle) {
  6908. // console.log('resultCalcBattle', currentRival, attempts, resultBattle.result.win);
  6909. /**
  6910. * If the current calculation of victory is not a chance or the attempt ended with the finish the battle
  6911. * Если текущий расчет победа или шансов нет или попытки кончились завершаем бой
  6912. */
  6913. if (resultBattle.result.win || !attempts) {
  6914. let { progress, result } = resultBattle;
  6915. if (!resultBattle.result.win && isChecked('tryFixIt_v2')) {
  6916. const bFix = new BestOrWinFixBattle(resultBattle.battleData);
  6917. bFix.isGetTimer = false;
  6918. bFix.maxTimer = 100;
  6919. const resultFix = await bFix.start(Date.now() + 6e4, 500);
  6920. if (resultFix.value > 0) {
  6921. progress = resultFix.progress;
  6922. result = resultFix.result;
  6923. }
  6924. }
  6925. titanArenaEndBattle({
  6926. progress,
  6927. result,
  6928. rivalId: resultBattle.battleData.typeId,
  6929. });
  6930. return;
  6931. }
  6932. /**
  6933. * If not victory and there are attempts we start a new battle
  6934. * Если не победа и есть попытки начинаем новый бой
  6935. */
  6936. titanArenaStartBattle(resultBattle.battleData.typeId);
  6937. }
  6938. /**
  6939. * Returns the promise of calculating the results of the battle
  6940. *
  6941. * Возращает промис расчета результатов битвы
  6942. */
  6943. function getBattleInfo(battle, isRandSeed) {
  6944. return new Promise(function (resolve) {
  6945. battle = structuredClone(battle);
  6946. if (isRandSeed) {
  6947. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  6948. }
  6949. // console.log(battle.seed);
  6950. BattleCalc(battle, "get_titanClanPvp", e => resolve(e));
  6951. });
  6952. }
  6953. /**
  6954. * Recalculate battles
  6955. *
  6956. * Прерасчтет битвы
  6957. */
  6958. function preCalcBattle(battle) {
  6959. let actions = [getBattleInfo(battle, false)];
  6960. const countTestBattle = getInput('countTestBattle');
  6961. for (let i = 0; i < countTestBattle; i++) {
  6962. actions.push(getBattleInfo(battle, true));
  6963. }
  6964. Promise.all(actions)
  6965. .then(resultPreCalcBattle);
  6966. }
  6967. /**
  6968. * Processing the results of the battle recalculation
  6969. *
  6970. * Обработка результатов прерасчета битвы
  6971. */
  6972. function resultPreCalcBattle(e) {
  6973. let wins = e.map(n => n.result.win);
  6974. let firstBattle = e.shift();
  6975. let countWin = wins.reduce((w, s) => w + s);
  6976. const countTestBattle = getInput('countTestBattle');
  6977. console.log('resultPreCalcBattle', `${countWin}/${countTestBattle}`)
  6978. if (countWin > 0) {
  6979. attempts = getInput('countAutoBattle');
  6980. } else {
  6981. attempts = 0;
  6982. }
  6983. resultCalcBattle(firstBattle);
  6984. }
  6985.  
  6986. /**
  6987. * Complete an arena battle
  6988. *
  6989. * Завершить битву на арене
  6990. */
  6991. function titanArenaEndBattle(args) {
  6992. let calls = [{
  6993. name: "titanArenaEndBattle",
  6994. args,
  6995. ident: "body"
  6996. }];
  6997. send(JSON.stringify({calls}), resultTitanArenaEndBattle);
  6998. }
  6999.  
  7000. function resultTitanArenaEndBattle(e) {
  7001. let attackScore = e.results[0].result.response.attackScore;
  7002. let numReval = countRivalsTier - finishListBattle.length;
  7003. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier} </br>${I18N('BATTLES')}: ${numReval}/${countRivalsTier} - ${attackScore}`);
  7004. // console.log('resultTitanArenaEndBattle', e)
  7005. console.log('resultTitanArenaEndBattle', numReval + '/' + countRivalsTier, attempts)
  7006. roundRivals();
  7007. }
  7008. /**
  7009. * Arena State
  7010. *
  7011. * Состояние арены
  7012. */
  7013. function titanArenaGetStatus() {
  7014. let calls = [{
  7015. name: "titanArenaGetStatus",
  7016. args: {},
  7017. ident: "body"
  7018. }];
  7019. send(JSON.stringify({calls}), checkResultInfo);
  7020. }
  7021. /**
  7022. * Arena Raid Request
  7023. *
  7024. * Запрос рейда арены
  7025. */
  7026. function titanArenaStartRaid() {
  7027. let calls = [{
  7028. name: "titanArenaStartRaid",
  7029. args: {
  7030. titans: titan_arena
  7031. },
  7032. ident: "body"
  7033. }];
  7034. send(JSON.stringify({calls}), calcResults);
  7035. }
  7036.  
  7037. function calcResults(data) {
  7038. let battlesInfo = data.results[0].result.response;
  7039. let {attackers, rivals} = battlesInfo;
  7040.  
  7041. let promises = [];
  7042. for (let n in rivals) {
  7043. rival = rivals[n];
  7044. promises.push(calcBattleResult({
  7045. attackers: attackers,
  7046. defenders: [rival.team],
  7047. seed: rival.seed,
  7048. typeId: n,
  7049. }));
  7050. }
  7051.  
  7052. Promise.all(promises)
  7053. .then(results => {
  7054. const endResults = {};
  7055. for (let info of results) {
  7056. let id = info.battleData.typeId;
  7057. endResults[id] = {
  7058. progress: info.progress,
  7059. result: info.result,
  7060. }
  7061. }
  7062. titanArenaEndRaid(endResults);
  7063. });
  7064. }
  7065.  
  7066. function calcBattleResult(battleData) {
  7067. return new Promise(function (resolve, reject) {
  7068. BattleCalc(battleData, "get_titanClanPvp", resolve);
  7069. });
  7070. }
  7071.  
  7072. /**
  7073. * Sending Raid Results
  7074. *
  7075. * Отправка результатов рейда
  7076. */
  7077. function titanArenaEndRaid(results) {
  7078. titanArenaEndRaidCall = {
  7079. calls: [{
  7080. name: "titanArenaEndRaid",
  7081. args: {
  7082. results
  7083. },
  7084. ident: "body"
  7085. }]
  7086. }
  7087. send(JSON.stringify(titanArenaEndRaidCall), checkRaidResults);
  7088. }
  7089.  
  7090. function checkRaidResults(data) {
  7091. results = data.results[0].result.response.results;
  7092. isSucsesRaid = true;
  7093. for (let i in results) {
  7094. isSucsesRaid &&= (results[i].attackScore >= 250);
  7095. }
  7096.  
  7097. if (isSucsesRaid) {
  7098. titanArenaCompleteTier();
  7099. } else {
  7100. titanArenaGetStatus();
  7101. }
  7102. }
  7103.  
  7104. function titanArenaFarmDailyReward() {
  7105. titanArenaFarmDailyRewardCall = {
  7106. calls: [{
  7107. name: "titanArenaFarmDailyReward",
  7108. args: {},
  7109. ident: "body"
  7110. }]
  7111. }
  7112. send(JSON.stringify(titanArenaFarmDailyRewardCall), () => {console.log('Done farm daily reward')});
  7113. }
  7114.  
  7115. function endTitanArena(reason, info) {
  7116. if (!['Peace_time', 'disabled'].includes(reason)) {
  7117. titanArenaFarmDailyReward();
  7118. }
  7119. console.log(reason, info);
  7120. setProgress(`${I18N('TITAN_ARENA')} ${I18N('COMPLETED')}!`, true);
  7121. resolve();
  7122. }
  7123. }
  7124.  
  7125. this.HWHClasses.executeTitanArena = executeTitanArena;
  7126.  
  7127. function hackGame() {
  7128. const self = this;
  7129. selfGame = null;
  7130. bindId = 1e9;
  7131. this.libGame = null;
  7132. this.doneLibLoad = () => {};
  7133.  
  7134. /**
  7135. * List of correspondence of used classes to their names
  7136. *
  7137. * Список соответствия используемых классов их названиям
  7138. */
  7139. ObjectsList = [
  7140. { name: 'BattlePresets', prop: 'game.battle.controller.thread.BattlePresets' },
  7141. { name: 'DataStorage', prop: 'game.data.storage.DataStorage' },
  7142. { name: 'BattleConfigStorage', prop: 'game.data.storage.battle.BattleConfigStorage' },
  7143. { name: 'BattleInstantPlay', prop: 'game.battle.controller.instant.BattleInstantPlay' },
  7144. { name: 'MultiBattleInstantReplay', prop: 'game.battle.controller.instant.MultiBattleInstantReplay' },
  7145. { name: 'MultiBattleResult', prop: 'game.battle.controller.MultiBattleResult' },
  7146.  
  7147. { name: 'PlayerMissionData', prop: 'game.model.user.mission.PlayerMissionData' },
  7148. { name: 'PlayerMissionBattle', prop: 'game.model.user.mission.PlayerMissionBattle' },
  7149. { name: 'GameModel', prop: 'game.model.GameModel' },
  7150. { name: 'CommandManager', prop: 'game.command.CommandManager' },
  7151. { name: 'MissionCommandList', prop: 'game.command.rpc.mission.MissionCommandList' },
  7152. { name: 'RPCCommandBase', prop: 'game.command.rpc.RPCCommandBase' },
  7153. { name: 'PlayerTowerData', prop: 'game.model.user.tower.PlayerTowerData' },
  7154. { name: 'TowerCommandList', prop: 'game.command.tower.TowerCommandList' },
  7155. { name: 'PlayerHeroTeamResolver', prop: 'game.model.user.hero.PlayerHeroTeamResolver' },
  7156. { name: 'BattlePausePopup', prop: 'game.view.popup.battle.BattlePausePopup' },
  7157. { name: 'BattlePopup', prop: 'game.view.popup.battle.BattlePopup' },
  7158. { name: 'DisplayObjectContainer', prop: 'starling.display.DisplayObjectContainer' },
  7159. { name: 'GuiClipContainer', prop: 'engine.core.clipgui.GuiClipContainer' },
  7160. { name: 'BattlePausePopupClip', prop: 'game.view.popup.battle.BattlePausePopupClip' },
  7161. { name: 'ClipLabel', prop: 'game.view.gui.components.ClipLabel' },
  7162. { name: 'ClipLabelBase', prop: 'game.view.gui.components.ClipLabelBase' },
  7163. { name: 'Translate', prop: 'com.progrestar.common.lang.Translate' },
  7164. { name: 'ClipButtonLabeledCentered', prop: 'game.view.gui.components.ClipButtonLabeledCentered' },
  7165. { name: 'BattlePausePopupMediator', prop: 'game.mediator.gui.popup.battle.BattlePausePopupMediator' },
  7166. { name: 'SettingToggleButton', prop: 'game.mechanics.settings.popup.view.SettingToggleButton' },
  7167. { name: 'PlayerDungeonData', prop: 'game.mechanics.dungeon.model.PlayerDungeonData' },
  7168. { name: 'NextDayUpdatedManager', prop: 'game.model.user.NextDayUpdatedManager' },
  7169. { name: 'BattleController', prop: 'game.battle.controller.BattleController' },
  7170. { name: 'BattleSettingsModel', prop: 'game.battle.controller.BattleSettingsModel' },
  7171. { name: 'BooleanProperty', prop: 'engine.core.utils.property.BooleanProperty' },
  7172. { name: 'RuleStorage', prop: 'game.data.storage.rule.RuleStorage' },
  7173. { name: 'BattleConfig', prop: 'battle.BattleConfig' },
  7174. { name: 'BattleGuiMediator', prop: 'game.battle.gui.BattleGuiMediator' },
  7175. { name: 'BooleanPropertyWriteable', prop: 'engine.core.utils.property.BooleanPropertyWriteable' },
  7176. { name: 'BattleLogEncoder', prop: 'battle.log.BattleLogEncoder' },
  7177. { name: 'BattleLogReader', prop: 'battle.log.BattleLogReader' },
  7178. { name: 'PlayerSubscriptionInfoValueObject', prop: 'game.model.user.subscription.PlayerSubscriptionInfoValueObject' },
  7179. { name: 'AdventureMapCamera', prop: 'game.mechanics.adventure.popup.map.AdventureMapCamera' },
  7180. ];
  7181.  
  7182. /**
  7183. * Contains the game classes needed to write and override game methods
  7184. *
  7185. * Содержит классы игры необходимые для написания и подмены методов игры
  7186. */
  7187. Game = {
  7188. /**
  7189. * Function 'e'
  7190. * Функция 'e'
  7191. */
  7192. bindFunc: function (a, b) {
  7193. if (null == b) return null;
  7194. null == b.__id__ && (b.__id__ = bindId++);
  7195. var c;
  7196. null == a.hx__closures__ ? (a.hx__closures__ = {}) : (c = a.hx__closures__[b.__id__]);
  7197. null == c && ((c = b.bind(a)), (a.hx__closures__[b.__id__] = c));
  7198. return c;
  7199. },
  7200. };
  7201.  
  7202. /**
  7203. * Connects to game objects via the object creation event
  7204. *
  7205. * Подключается к объектам игры через событие создания объекта
  7206. */
  7207. function connectGame() {
  7208. for (let obj of ObjectsList) {
  7209. /**
  7210. * https: //stackoverflow.com/questions/42611719/how-to-intercept-and-modify-a-specific-property-for-any-object
  7211. */
  7212. Object.defineProperty(Object.prototype, obj.prop, {
  7213. set: function (value) {
  7214. if (!selfGame) {
  7215. selfGame = this;
  7216. }
  7217. if (!Game[obj.name]) {
  7218. Game[obj.name] = value;
  7219. }
  7220. // console.log('set ' + obj.prop, this, value);
  7221. this[obj.prop + '_'] = value;
  7222. },
  7223. get: function () {
  7224. // console.log('get ' + obj.prop, this);
  7225. return this[obj.prop + '_'];
  7226. },
  7227. });
  7228. }
  7229. }
  7230.  
  7231. /**
  7232. * Game.BattlePresets
  7233. * @param {bool} a isReplay
  7234. * @param {bool} b autoToggleable
  7235. * @param {bool} c auto On Start
  7236. * @param {object} d config
  7237. * @param {bool} f showBothTeams
  7238. */
  7239. /**
  7240. * Returns the results of the battle to the callback function
  7241. * Возвращает в функцию callback результаты боя
  7242. * @param {*} battleData battle data данные боя
  7243. * @param {*} battleConfig combat configuration type options:
  7244. *
  7245. * тип конфигурации боя варианты:
  7246. *
  7247. * "get_invasion", "get_titanPvpManual", "get_titanPvp",
  7248. * "get_titanClanPvp","get_clanPvp","get_titan","get_boss",
  7249. * "get_tower","get_pve","get_pvpManual","get_pvp","get_core"
  7250. *
  7251. * You can specify the xYc function in the game.assets.storage.BattleAssetStorage class
  7252. *
  7253. * Можно уточнить в классе game.assets.storage.BattleAssetStorage функция xYc
  7254. * @param {*} callback функция в которую вернуться результаты боя
  7255. */
  7256. this.BattleCalc = function (battleData, battleConfig, callback) {
  7257. // battleConfig = battleConfig || getBattleType(battleData.type)
  7258. if (!Game.BattlePresets) throw Error('Use connectGame');
  7259. battlePresets = new Game.BattlePresets(
  7260. battleData.progress,
  7261. !1,
  7262. !0,
  7263. Game.DataStorage[getFn(Game.DataStorage, 24)][getF(Game.BattleConfigStorage, battleConfig)](),
  7264. !1
  7265. );
  7266. let battleInstantPlay;
  7267. if (battleData.progress?.length > 1) {
  7268. battleInstantPlay = new Game.MultiBattleInstantReplay(battleData, battlePresets);
  7269. } else {
  7270. battleInstantPlay = new Game.BattleInstantPlay(battleData, battlePresets);
  7271. }
  7272. battleInstantPlay[getProtoFn(Game.BattleInstantPlay, 9)].add((battleInstant) => {
  7273. const MBR_2 = getProtoFn(Game.MultiBattleResult, 2);
  7274. const battleResults = battleInstant[getF(Game.BattleInstantPlay, 'get_result')]();
  7275. const battleData = battleInstant[getF(Game.BattleInstantPlay, 'get_rawBattleInfo')]();
  7276. const battleLogs = [];
  7277. const timeLimit = battlePresets[getF(Game.BattlePresets, 'get_timeLimit')]();
  7278. let battleTime = 0;
  7279. let battleTimer = 0;
  7280. for (const battleResult of battleResults[MBR_2]) {
  7281. const battleLog = Game.BattleLogEncoder.read(new Game.BattleLogReader(battleResult));
  7282. battleLogs.push(battleLog);
  7283. const maxTime = Math.max(...battleLog.map((e) => (e.time < timeLimit && e.time !== 168.8 ? e.time : 0)));
  7284. battleTimer += getTimer(maxTime);
  7285. battleTime += maxTime;
  7286. }
  7287. callback({
  7288. battleLogs,
  7289. battleTime,
  7290. battleTimer,
  7291. battleData,
  7292. progress: battleResults[getF(Game.MultiBattleResult, 'get_progress')](),
  7293. result: battleResults[getF(Game.MultiBattleResult, 'get_result')](),
  7294. });
  7295. });
  7296. battleInstantPlay.start();
  7297. };
  7298.  
  7299. /**
  7300. * Returns a function with the specified name from the class
  7301. *
  7302. * Возвращает из класса функцию с указанным именем
  7303. * @param {Object} classF Class // класс
  7304. * @param {String} nameF function name // имя функции
  7305. * @param {String} pos name and alias order // порядок имени и псевдонима
  7306. * @returns
  7307. */
  7308. function getF(classF, nameF, pos) {
  7309. pos = pos || false;
  7310. let prop = Object.entries(classF.prototype.__properties__);
  7311. if (!pos) {
  7312. return prop.filter((e) => e[1] == nameF).pop()[0];
  7313. } else {
  7314. return prop.filter((e) => e[0] == nameF).pop()[1];
  7315. }
  7316. }
  7317.  
  7318. /**
  7319. * Returns a function with the specified name from the class
  7320. *
  7321. * Возвращает из класса функцию с указанным именем
  7322. * @param {Object} classF Class // класс
  7323. * @param {String} nameF function name // имя функции
  7324. * @returns
  7325. */
  7326. function getFnP(classF, nameF) {
  7327. let prop = Object.entries(classF.__properties__);
  7328. return prop.filter((e) => e[1] == nameF).pop()[0];
  7329. }
  7330.  
  7331. /**
  7332. * Returns the function name with the specified ordinal from the class
  7333. *
  7334. * Возвращает имя функции с указаным порядковым номером из класса
  7335. * @param {Object} classF Class // класс
  7336. * @param {Number} nF Order number of function // порядковый номер функции
  7337. * @returns
  7338. */
  7339. function getFn(classF, nF) {
  7340. let prop = Object.keys(classF);
  7341. return prop[nF];
  7342. }
  7343.  
  7344. /**
  7345. * Returns the name of the function with the specified serial number from the prototype of the class
  7346. *
  7347. * Возвращает имя функции с указаным порядковым номером из прототипа класса
  7348. * @param {Object} classF Class // класс
  7349. * @param {Number} nF Order number of function // порядковый номер функции
  7350. * @returns
  7351. */
  7352. function getProtoFn(classF, nF) {
  7353. let prop = Object.keys(classF.prototype);
  7354. return prop[nF];
  7355. }
  7356.  
  7357. function findInstanceOf(obj, targetClass) {
  7358. const prototypeKeys = Object.keys(Object.getPrototypeOf(obj));
  7359. const matchingKey = prototypeKeys.find((key) => obj[key] instanceof targetClass);
  7360. return matchingKey ? obj[matchingKey] : null;
  7361. }
  7362. /**
  7363. * Description of replaced functions
  7364. *
  7365. * Описание подменяемых функций
  7366. */
  7367. replaceFunction = {
  7368. company: function () {
  7369. let PMD_12 = getProtoFn(Game.PlayerMissionData, 12);
  7370. let oldSkipMisson = Game.PlayerMissionData.prototype[PMD_12];
  7371. Game.PlayerMissionData.prototype[PMD_12] = function (a, b, c) {
  7372. if (!isChecked('passBattle')) {
  7373. oldSkipMisson.call(this, a, b, c);
  7374. return;
  7375. }
  7376.  
  7377. try {
  7378. this[getProtoFn(Game.PlayerMissionData, 9)] = new Game.PlayerMissionBattle(a, b, c);
  7379.  
  7380. var a = new Game.BattlePresets(
  7381. !1,
  7382. !1,
  7383. !0,
  7384. Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](),
  7385. !1
  7386. );
  7387. a = new Game.BattleInstantPlay(c, a);
  7388. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  7389. a.start();
  7390. } catch (error) {
  7391. console.error('company', error);
  7392. oldSkipMisson.call(this, a, b, c);
  7393. }
  7394. };
  7395.  
  7396. Game.PlayerMissionData.prototype.P$h = function (a) {
  7397. let GM_2 = getFn(Game.GameModel, 2);
  7398. let GM_P2 = getProtoFn(Game.GameModel, 2);
  7399. let CM_21 = getProtoFn(Game.CommandManager, 21);
  7400. let MCL_2 = getProtoFn(Game.MissionCommandList, 2);
  7401. let MBR_15 = getF(Game.MultiBattleResult, 'get_result');
  7402. let RPCCB_17 = getProtoFn(Game.RPCCommandBase, 17);
  7403. let PMD_34 = getProtoFn(Game.PlayerMissionData, 34);
  7404. Game.GameModel[GM_2]()[GM_P2][CM_21][MCL_2](a[MBR_15]())[RPCCB_17](Game.bindFunc(this, this[PMD_34]));
  7405. };
  7406. },
  7407. /*
  7408. tower: function () {
  7409. let PTD_67 = getProtoFn(Game.PlayerTowerData, 67);
  7410. let oldSkipTower = Game.PlayerTowerData.prototype[PTD_67];
  7411. Game.PlayerTowerData.prototype[PTD_67] = function (a) {
  7412. if (!isChecked('passBattle')) {
  7413. oldSkipTower.call(this, a);
  7414. return;
  7415. }
  7416. try {
  7417. var p = new Game.BattlePresets(
  7418. !1,
  7419. !1,
  7420. !0,
  7421. Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](),
  7422. !1
  7423. );
  7424. a = new Game.BattleInstantPlay(a, p);
  7425. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  7426. a.start();
  7427. } catch (error) {
  7428. console.error('tower', error);
  7429. oldSkipMisson.call(this, a, b, c);
  7430. }
  7431. };
  7432.  
  7433. Game.PlayerTowerData.prototype.P$h = function (a) {
  7434. const GM_2 = getFnP(Game.GameModel, 'get_instance');
  7435. const GM_P2 = getProtoFn(Game.GameModel, 2);
  7436. const CM_29 = getProtoFn(Game.CommandManager, 29);
  7437. const TCL_5 = getProtoFn(Game.TowerCommandList, 5);
  7438. const MBR_15 = getF(Game.MultiBattleResult, 'get_result');
  7439. const RPCCB_15 = getProtoFn(Game.RPCCommandBase, 17);
  7440. const PTD_78 = getProtoFn(Game.PlayerTowerData, 78);
  7441. Game.GameModel[GM_2]()[GM_P2][CM_29][TCL_5](a[MBR_15]())[RPCCB_15](Game.bindFunc(this, this[PTD_78]));
  7442. };
  7443. },
  7444. */
  7445. // skipSelectHero: function() {
  7446. // if (!HOST) throw Error('Use connectGame');
  7447. // Game.PlayerHeroTeamResolver.prototype[getProtoFn(Game.PlayerHeroTeamResolver, 3)] = () => false;
  7448. // },
  7449. passBattle: function () {
  7450. let BPP_4 = getProtoFn(Game.BattlePausePopup, 4);
  7451. let oldPassBattle = Game.BattlePausePopup.prototype[BPP_4];
  7452. Game.BattlePausePopup.prototype[BPP_4] = function (a) {
  7453. if (!isChecked('passBattle')) {
  7454. oldPassBattle.call(this, a);
  7455. return;
  7456. }
  7457. try {
  7458. Game.BattlePopup.prototype[getProtoFn(Game.BattlePausePopup, 4)].call(this, a);
  7459. this[getProtoFn(Game.BattlePausePopup, 3)]();
  7460. this[getProtoFn(Game.DisplayObjectContainer, 3)](this.clip[getProtoFn(Game.GuiClipContainer, 2)]());
  7461. this.clip[getProtoFn(Game.BattlePausePopupClip, 1)][getProtoFn(Game.ClipLabelBase, 9)](
  7462. Game.Translate.translate('UI_POPUP_BATTLE_PAUSE')
  7463. );
  7464.  
  7465. this.clip[getProtoFn(Game.BattlePausePopupClip, 2)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  7466. Game.Translate.translate('UI_POPUP_BATTLE_RETREAT'),
  7467. ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 17)]))
  7468. );
  7469. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  7470. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 14)](),
  7471. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 13)]()
  7472. ? ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  7473. : ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  7474. );
  7475.  
  7476. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 0)][
  7477. getProtoFn(Game.ClipLabelBase, 24)
  7478. ]();
  7479. this.clip[getProtoFn(Game.BattlePausePopupClip, 3)][getProtoFn(Game.SettingToggleButton, 3)](
  7480. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 9)]()
  7481. );
  7482. this.clip[getProtoFn(Game.BattlePausePopupClip, 4)][getProtoFn(Game.SettingToggleButton, 3)](
  7483. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 10)]()
  7484. );
  7485. this.clip[getProtoFn(Game.BattlePausePopupClip, 6)][getProtoFn(Game.SettingToggleButton, 3)](
  7486. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 11)]()
  7487. );
  7488. } catch (error) {
  7489. console.error('passBattle', error);
  7490. oldPassBattle.call(this, a);
  7491. }
  7492. };
  7493.  
  7494. let retreatButtonLabel = getF(Game.BattlePausePopupMediator, 'get_retreatButtonLabel');
  7495. let oldFunc = Game.BattlePausePopupMediator.prototype[retreatButtonLabel];
  7496. Game.BattlePausePopupMediator.prototype[retreatButtonLabel] = function () {
  7497. if (isChecked('passBattle')) {
  7498. return I18N('BTN_PASS');
  7499. } else {
  7500. return oldFunc.call(this);
  7501. }
  7502. };
  7503. },
  7504. endlessCards: function () {
  7505. let PDD_21 = getProtoFn(Game.PlayerDungeonData, 21);
  7506. let oldEndlessCards = Game.PlayerDungeonData.prototype[PDD_21];
  7507. Game.PlayerDungeonData.prototype[PDD_21] = function () {
  7508. if (HWHData.countPredictionCard <= 0) {
  7509. return true;
  7510. } else {
  7511. return oldEndlessCards.call(this);
  7512. }
  7513. };
  7514. },
  7515. speedBattle: function () {
  7516. const get_timeScale = getF(Game.BattleController, 'get_timeScale');
  7517. const oldSpeedBattle = Game.BattleController.prototype[get_timeScale];
  7518. Game.BattleController.prototype[get_timeScale] = function () {
  7519. const speedBattle = Number.parseFloat(getInput('speedBattle'));
  7520. if (!speedBattle) {
  7521. return oldSpeedBattle.call(this);
  7522. }
  7523. try {
  7524. const BC_12 = getProtoFn(Game.BattleController, 12);
  7525. const BSM_12 = getProtoFn(Game.BattleSettingsModel, 12);
  7526. const BP_get_value = getF(Game.BooleanProperty, 'get_value');
  7527. if (this[BC_12][BSM_12][BP_get_value]()) {
  7528. return 0;
  7529. }
  7530. const BSM_2 = getProtoFn(Game.BattleSettingsModel, 2);
  7531. const BC_49 = getProtoFn(Game.BattleController, 49);
  7532. const BSM_1 = getProtoFn(Game.BattleSettingsModel, 1);
  7533. const BC_14 = getProtoFn(Game.BattleController, 14);
  7534. const BC_3 = getFn(Game.BattleController, 3);
  7535. if (this[BC_12][BSM_2][BP_get_value]()) {
  7536. var a = speedBattle * this[BC_49]();
  7537. } else {
  7538. a = this[BC_12][BSM_1][BP_get_value]();
  7539. const maxSpeed = Math.max(...this[BC_14]);
  7540. const multiple = a == this[BC_14].indexOf(maxSpeed) ? (maxSpeed >= 4 ? speedBattle : this[BC_14][a]) : this[BC_14][a];
  7541. a = multiple * Game.BattleController[BC_3][BP_get_value]() * this[BC_49]();
  7542. }
  7543. const BSM_24 = getProtoFn(Game.BattleSettingsModel, 24);
  7544. a > this[BC_12][BSM_24][BP_get_value]() && (a = this[BC_12][BSM_24][BP_get_value]());
  7545. const DS_23 = getFn(Game.DataStorage, 23);
  7546. const get_battleSpeedMultiplier = getF(Game.RuleStorage, 'get_battleSpeedMultiplier', true);
  7547. var b = Game.DataStorage[DS_23][get_battleSpeedMultiplier]();
  7548. const R_1 = getFn(selfGame.Reflect, 1);
  7549. const BC_1 = getFn(Game.BattleController, 1);
  7550. const get_config = getF(Game.BattlePresets, 'get_config');
  7551. null != b &&
  7552. (a = selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident)
  7553. ? a * selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident)
  7554. : a * selfGame.Reflect[R_1](b, 'default'));
  7555. return a;
  7556. } catch (error) {
  7557. console.error('passBatspeedBattletle', error);
  7558. return oldSpeedBattle.call(this);
  7559. }
  7560. };
  7561. },
  7562.  
  7563. /**
  7564. * Acceleration button without Valkyries favor
  7565. *
  7566. * Кнопка ускорения без Покровительства Валькирий
  7567. */
  7568. battleFastKey: function () {
  7569. const BGM_44 = getProtoFn(Game.BattleGuiMediator, 44);
  7570. const oldBattleFastKey = Game.BattleGuiMediator.prototype[BGM_44];
  7571. Game.BattleGuiMediator.prototype[BGM_44] = function () {
  7572. let flag = true;
  7573. //console.log(flag)
  7574. if (!flag) {
  7575. return oldBattleFastKey.call(this);
  7576. }
  7577. try {
  7578. const BGM_9 = getProtoFn(Game.BattleGuiMediator, 9);
  7579. const BGM_10 = getProtoFn(Game.BattleGuiMediator, 10);
  7580. const BPW_0 = getProtoFn(Game.BooleanPropertyWriteable, 0);
  7581. this[BGM_9][BPW_0](true);
  7582. this[BGM_10][BPW_0](true);
  7583. } catch (error) {
  7584. console.error(error);
  7585. return oldBattleFastKey.call(this);
  7586. }
  7587. };
  7588. },
  7589. fastSeason: function () {
  7590. const GameNavigator = selfGame['game.screen.navigator.GameNavigator'];
  7591. const oldFuncName = getProtoFn(GameNavigator, 18);
  7592. const newFuncName = getProtoFn(GameNavigator, 16);
  7593. const oldFastSeason = GameNavigator.prototype[oldFuncName];
  7594. const newFastSeason = GameNavigator.prototype[newFuncName];
  7595. GameNavigator.prototype[oldFuncName] = function (a, b) {
  7596. if (isChecked('fastSeason')) {
  7597. return newFastSeason.apply(this, [a]);
  7598. } else {
  7599. return oldFastSeason.apply(this, [a, b]);
  7600. }
  7601. };
  7602. },
  7603. ShowChestReward: function () {
  7604. const TitanArtifactChest = selfGame['game.mechanics.titan_arena.mediator.chest.TitanArtifactChestRewardPopupMediator'];
  7605. const getOpenAmountTitan = getF(TitanArtifactChest, 'get_openAmount');
  7606. const oldGetOpenAmountTitan = TitanArtifactChest.prototype[getOpenAmountTitan];
  7607. TitanArtifactChest.prototype[getOpenAmountTitan] = function () {
  7608. if (correctShowOpenArtifact) {
  7609. correctShowOpenArtifact--;
  7610. return 100;
  7611. }
  7612. return oldGetOpenAmountTitan.call(this);
  7613. };
  7614.  
  7615. const ArtifactChest = selfGame['game.view.popup.artifactchest.rewardpopup.ArtifactChestRewardPopupMediator'];
  7616. const getOpenAmount = getF(ArtifactChest, 'get_openAmount');
  7617. const oldGetOpenAmount = ArtifactChest.prototype[getOpenAmount];
  7618. ArtifactChest.prototype[getOpenAmount] = function () {
  7619. if (correctShowOpenArtifact) {
  7620. correctShowOpenArtifact--;
  7621. return 100;
  7622. }
  7623. return oldGetOpenAmount.call(this);
  7624. };
  7625. },
  7626. fixCompany: function () {
  7627. const GameBattleView = selfGame['game.mediator.gui.popup.battle.GameBattleView'];
  7628. const BattleThread = selfGame['game.battle.controller.thread.BattleThread'];
  7629. const getOnViewDisposed = getF(BattleThread, 'get_onViewDisposed');
  7630. const getThread = getF(GameBattleView, 'get_thread');
  7631. const oldFunc = GameBattleView.prototype[getThread];
  7632. GameBattleView.prototype[getThread] = function () {
  7633. return (
  7634. oldFunc.call(this) || {
  7635. [getOnViewDisposed]: async () => {},
  7636. }
  7637. );
  7638. };
  7639. },
  7640. BuyTitanArtifact: function () {
  7641. const BIP_4 = getProtoFn(selfGame['game.view.popup.shop.buy.BuyItemPopup'], 4);
  7642. const BuyItemPopup = selfGame['game.view.popup.shop.buy.BuyItemPopup'];
  7643. const oldFunc = BuyItemPopup.prototype[BIP_4];
  7644. BuyItemPopup.prototype[BIP_4] = function () {
  7645. if (isChecked('countControl')) {
  7646. const BuyTitanArtifactItemPopup = selfGame['game.view.popup.shop.buy.BuyTitanArtifactItemPopup'];
  7647. const BTAP_0 = getProtoFn(BuyTitanArtifactItemPopup, 0);
  7648. if (this[BTAP_0]) {
  7649. const BuyTitanArtifactPopupMediator = selfGame['game.mediator.gui.popup.shop.buy.BuyTitanArtifactItemPopupMediator'];
  7650. const BTAM_1 = getProtoFn(BuyTitanArtifactPopupMediator, 1);
  7651. const BuyItemPopupMediator = selfGame['game.mediator.gui.popup.shop.buy.BuyItemPopupMediator'];
  7652. const BIPM_5 = getProtoFn(BuyItemPopupMediator, 5);
  7653. const BIPM_7 = getProtoFn(BuyItemPopupMediator, 7);
  7654. const BIPM_9 = getProtoFn(BuyItemPopupMediator, 9);
  7655.  
  7656. let need = Math.min(this[BTAP_0][BTAM_1](), this[BTAP_0][BIPM_7]);
  7657. need = need ? need : 60;
  7658. this[BTAP_0][BIPM_9] = need;
  7659. this[BTAP_0][BIPM_5] = 10;
  7660. }
  7661. }
  7662. oldFunc.call(this);
  7663. };
  7664. },
  7665. ClanQuestsFastFarm: function () {
  7666. const VipRuleValueObject = selfGame['game.data.storage.rule.VipRuleValueObject'];
  7667. const getClanQuestsFastFarm = getF(VipRuleValueObject, 'get_clanQuestsFastFarm', 1);
  7668. VipRuleValueObject.prototype[getClanQuestsFastFarm] = function () {
  7669. return 0;
  7670. };
  7671. },
  7672. adventureCamera: function () {
  7673. const AMC_40 = getProtoFn(Game.AdventureMapCamera, 40);
  7674. const AMC_5 = getProtoFn(Game.AdventureMapCamera, 5);
  7675. const oldFunc = Game.AdventureMapCamera.prototype[AMC_40];
  7676. Game.AdventureMapCamera.prototype[AMC_40] = function (a) {
  7677. this[AMC_5] = 0.4;
  7678. oldFunc.bind(this)(a);
  7679. };
  7680. },
  7681. unlockMission: function () {
  7682. const WorldMapStoryDrommerHelper = selfGame['game.mediator.gui.worldmap.WorldMapStoryDrommerHelper'];
  7683. const WMSDH_4 = getFn(WorldMapStoryDrommerHelper, 4);
  7684. const WMSDH_7 = getFn(WorldMapStoryDrommerHelper, 7);
  7685. WorldMapStoryDrommerHelper[WMSDH_4] = function () {
  7686. return true;
  7687. };
  7688. WorldMapStoryDrommerHelper[WMSDH_7] = function () {
  7689. return true;
  7690. };
  7691. },
  7692. doublePets: function () {
  7693. const TeamGatherPopupMediator = selfGame['game.mediator.gui.popup.team.TeamGatherPopupMediator'];
  7694. const InvasionBossTeamGatherPopupMediator = selfGame['game.mechanics.invasion.mediator.boss.InvasionBossTeamGatherPopupMediator'];
  7695. const TeamGatherPopupHeroValueObject = selfGame['game.mediator.gui.popup.team.TeamGatherPopupHeroValueObject'];
  7696. const ObjectPropertyWriteable = selfGame['engine.core.utils.property.ObjectPropertyWriteable'];
  7697. const TGPM_8 = getProtoFn(TeamGatherPopupMediator, 8);
  7698. const TGPM_45 = getProtoFn(TeamGatherPopupMediator, 45);
  7699. const TGPM_114 = getProtoFn(TeamGatherPopupMediator, 114);
  7700. const TGPM_117 = getProtoFn(TeamGatherPopupMediator, 117);
  7701. const TGPM_123 = getProtoFn(TeamGatherPopupMediator, 123);
  7702. const TGPM_135 = getProtoFn(TeamGatherPopupMediator, 135);
  7703. const TGPHVO_40 = getProtoFn(TeamGatherPopupHeroValueObject, 40);
  7704. const OPW_0 = getProtoFn(ObjectPropertyWriteable, 0);
  7705. const oldFunc = InvasionBossTeamGatherPopupMediator.prototype[TGPM_135];
  7706. InvasionBossTeamGatherPopupMediator.prototype[TGPM_135] = function (a, b) {
  7707. try {
  7708. if (b == 0) {
  7709. this[TGPM_8].remove(a);
  7710. } else {
  7711. this[TGPM_8].F[a] = b;
  7712. }
  7713. this[TGPM_114](this[TGPM_45], a)[TGPHVO_40][OPW_0](this[TGPM_117](b));
  7714. this[TGPM_123]();
  7715. return;
  7716. } catch (e) {}
  7717. oldFunc.call(this, a, b);
  7718. };
  7719. },
  7720. };
  7721.  
  7722. /**
  7723. * Starts replacing recorded functions
  7724. *
  7725. * Запускает замену записанных функций
  7726. */
  7727. this.activateHacks = function () {
  7728. if (!selfGame) throw Error('Use connectGame');
  7729. for (let func in replaceFunction) {
  7730. try {
  7731. replaceFunction[func]();
  7732. } catch (error) {
  7733. console.error(error);
  7734. }
  7735. }
  7736. };
  7737.  
  7738. /**
  7739. * Returns the game object
  7740. *
  7741. * Возвращает объект игры
  7742. */
  7743. this.getSelfGame = function () {
  7744. return selfGame;
  7745. };
  7746.  
  7747. /** Возвращает объект игры */
  7748. this.getGame = function () {
  7749. return Game;
  7750. };
  7751.  
  7752. /**
  7753. * Updates game data
  7754. *
  7755. * Обновляет данные игры
  7756. */
  7757. this.refreshGame = function () {
  7758. new Game.NextDayUpdatedManager()[getProtoFn(Game.NextDayUpdatedManager, 5)]();
  7759. try {
  7760. cheats.refreshInventory();
  7761. } catch (e) {}
  7762. };
  7763.  
  7764. /**
  7765. * Update inventory
  7766. *
  7767. * Обновляет инвентарь
  7768. */
  7769. this.refreshInventory = async function () {
  7770. const GM_INST = getFnP(Game.GameModel, 'get_instance');
  7771. const GM_0 = getProtoFn(Game.GameModel, 0);
  7772. const P_24 = getProtoFn(selfGame['game.model.user.Player'], 24);
  7773. const Player = Game.GameModel[GM_INST]()[GM_0];
  7774. Player[P_24] = new selfGame['game.model.user.inventory.PlayerInventory']();
  7775. Player[P_24].init(await Send({ calls: [{ name: 'inventoryGet', args: {}, ident: 'body' }] }).then((e) => e.results[0].result.response));
  7776. };
  7777. this.updateInventory = function (reward) {
  7778. const GM_INST = getFnP(Game.GameModel, 'get_instance');
  7779. const GM_0 = getProtoFn(Game.GameModel, 0);
  7780. const P_24 = getProtoFn(selfGame['game.model.user.Player'], 24);
  7781. const Player = Game.GameModel[GM_INST]()[GM_0];
  7782. Player[P_24].init(reward);
  7783. };
  7784.  
  7785. this.updateMap = function (data) {
  7786. const PCDD_21 = getProtoFn(selfGame['game.mechanics.clanDomination.model.PlayerClanDominationData'], 21);
  7787. const P_60 = getProtoFn(selfGame['game.model.user.Player'], 60);
  7788. const GM_0 = getProtoFn(Game.GameModel, 0);
  7789. const getInstance = getFnP(selfGame['Game'], 'get_instance');
  7790. const PlayerClanDominationData = Game.GameModel[getInstance]()[GM_0];
  7791. PlayerClanDominationData[P_60][PCDD_21].update(data);
  7792. };
  7793.  
  7794. /**
  7795. * Change the play screen on windowName
  7796. *
  7797. * Сменить экран игры на windowName
  7798. *
  7799. * Possible options:
  7800. *
  7801. * Возможные варианты:
  7802. *
  7803. * MISSION, ARENA, GRAND, CHEST, SKILLS, SOCIAL_GIFT, CLAN, ENCHANT, TOWER, RATING, CHALLENGE, BOSS, CHAT, CLAN_DUNGEON, CLAN_CHEST, TITAN_GIFT, CLAN_RAID, ASGARD, HERO_ASCENSION, ROLE_ASCENSION, ASCENSION_CHEST, TITAN_MISSION, TITAN_ARENA, TITAN_ARTIFACT, TITAN_ARTIFACT_CHEST, TITAN_VALLEY, TITAN_SPIRITS, TITAN_ARTIFACT_MERCHANT, TITAN_ARENA_HALL_OF_FAME, CLAN_PVP, CLAN_PVP_MERCHANT, CLAN_GLOBAL_PVP, CLAN_GLOBAL_PVP_TITAN, ARTIFACT, ZEPPELIN, ARTIFACT_CHEST, ARTIFACT_MERCHANT, EXPEDITIONS, SUBSCRIPTION, NY2018_GIFTS, NY2018_TREE, NY2018_WELCOME, ADVENTURE, ADVENTURESOLO, SANCTUARY, PET_MERCHANT, PET_LIST, PET_SUMMON, BOSS_RATING_EVENT, BRAWL
  7804. */
  7805. this.goNavigtor = function (windowName) {
  7806. let mechanicStorage = selfGame['game.data.storage.mechanic.MechanicStorage'];
  7807. let window = mechanicStorage[windowName];
  7808. let event = new selfGame['game.mediator.gui.popup.PopupStashEventParams']();
  7809. let Game = selfGame['Game'];
  7810. let navigator = getF(Game, 'get_navigator');
  7811. let navigate = getProtoFn(selfGame['game.screen.navigator.GameNavigator'], 20);
  7812. let instance = getFnP(Game, 'get_instance');
  7813. Game[instance]()[navigator]()[navigate](window, event);
  7814. };
  7815.  
  7816. /**
  7817. * Move to the sanctuary cheats.goSanctuary()
  7818. *
  7819. * Переместиться в святилище cheats.goSanctuary()
  7820. */
  7821. this.goSanctuary = () => {
  7822. this.goNavigtor('SANCTUARY');
  7823. };
  7824.  
  7825. /** Перейти в Долину титанов */
  7826. this.goTitanValley = () => {
  7827. this.goNavigtor('TITAN_VALLEY');
  7828. };
  7829.  
  7830. /**
  7831. * Go to Guild War
  7832. *
  7833. * Перейти к Войне Гильдий
  7834. */
  7835. this.goClanWar = function () {
  7836. let instance = getFnP(Game.GameModel, 'get_instance');
  7837. let player = Game.GameModel[instance]().A;
  7838. let clanWarSelect = selfGame['game.mechanics.cross_clan_war.popup.selectMode.CrossClanWarSelectModeMediator'];
  7839. new clanWarSelect(player).open();
  7840. };
  7841.  
  7842. /** Перейти к Острову гильдии */
  7843. this.goClanIsland = function () {
  7844. let instance = getFnP(Game.GameModel, 'get_instance');
  7845. let player = Game.GameModel[instance]().A;
  7846. let clanIslandSelect = selfGame['game.view.gui.ClanIslandPopupMediator'];
  7847. new clanIslandSelect(player).open();
  7848. };
  7849.  
  7850. /**
  7851. * Go to BrawlShop
  7852. *
  7853. * Переместиться в BrawlShop
  7854. */
  7855. this.goBrawlShop = () => {
  7856. const instance = getFnP(Game.GameModel, 'get_instance');
  7857. const P_36 = getProtoFn(selfGame['game.model.user.Player'], 36);
  7858. const PSD_0 = getProtoFn(selfGame['game.model.user.shop.PlayerShopData'], 0);
  7859. const IM_0 = getProtoFn(selfGame['haxe.ds.IntMap'], 0);
  7860. const PSDE_4 = getProtoFn(selfGame['game.model.user.shop.PlayerShopDataEntry'], 4);
  7861.  
  7862. const player = Game.GameModel[instance]().A;
  7863. const shop = player[P_36][PSD_0][IM_0][1038][PSDE_4];
  7864. const shopPopup = new selfGame['game.mechanics.brawl.mediator.BrawlShopPopupMediator'](player, shop);
  7865. shopPopup.open(new selfGame['game.mediator.gui.popup.PopupStashEventParams']());
  7866. };
  7867.  
  7868. /**
  7869. * Returns all stores from game data
  7870. *
  7871. * Возвращает все магазины из данных игры
  7872. */
  7873. this.getShops = () => {
  7874. const instance = getFnP(Game.GameModel, 'get_instance');
  7875. const P_36 = getProtoFn(selfGame['game.model.user.Player'], 36);
  7876. const PSD_0 = getProtoFn(selfGame['game.model.user.shop.PlayerShopData'], 0);
  7877. const IM_0 = getProtoFn(selfGame['haxe.ds.IntMap'], 0);
  7878.  
  7879. const player = Game.GameModel[instance]().A;
  7880. return player[P_36][PSD_0][IM_0];
  7881. };
  7882.  
  7883. /**
  7884. * Returns the store from the game data by ID
  7885. *
  7886. * Возвращает магазин из данных игры по идетификатору
  7887. */
  7888. this.getShop = (id) => {
  7889. const PSDE_4 = getProtoFn(selfGame['game.model.user.shop.PlayerShopDataEntry'], 4);
  7890. const shops = this.getShops();
  7891. const shop = shops[id]?.[PSDE_4];
  7892. return shop;
  7893. };
  7894.  
  7895. /**
  7896. * Change island map
  7897. *
  7898. * Сменить карту острова
  7899. */
  7900. this.changeIslandMap = (mapId = 2) => {
  7901. const GameInst = getFnP(selfGame['Game'], 'get_instance');
  7902. const GM_0 = getProtoFn(Game.GameModel, 0);
  7903. const PSAD_31 = getProtoFn(selfGame['game.mechanics.season_adventure.model.PlayerSeasonAdventureData'], 31);
  7904. const Player = Game.GameModel[GameInst]()[GM_0];
  7905. const PlayerSeasonAdventureData = findInstanceOf(Player, selfGame['game.mechanics.season_adventure.model.PlayerSeasonAdventureData']);
  7906. PlayerSeasonAdventureData[PSAD_31]({ id: mapId, seasonAdventure: { id: mapId, startDate: 1701914400, endDate: 1709690400, closed: false } });
  7907.  
  7908. const GN_15 = getProtoFn(selfGame['game.screen.navigator.GameNavigator'], 17);
  7909. const navigator = getF(selfGame['Game'], 'get_navigator');
  7910. selfGame['Game'][GameInst]()[navigator]()[GN_15](new selfGame['game.mediator.gui.popup.PopupStashEventParams']());
  7911. };
  7912.  
  7913. /**
  7914. * Game library availability tracker
  7915. *
  7916. * Отслеживание доступности игровой библиотеки
  7917. */
  7918. function checkLibLoad() {
  7919. timeout = setTimeout(() => {
  7920. if (Game.GameModel) {
  7921. changeLib();
  7922. } else {
  7923. checkLibLoad();
  7924. }
  7925. }, 100);
  7926. }
  7927.  
  7928. /**
  7929. * Game library data spoofing
  7930. *
  7931. * Подмена данных игровой библиотеки
  7932. */
  7933. function changeLib() {
  7934. console.log('lib connect');
  7935. const originalStartFunc = Game.GameModel.prototype.start;
  7936. Game.GameModel.prototype.start = function (a, b, c) {
  7937. self.libGame = b.raw;
  7938. self.doneLibLoad(self.libGame);
  7939. try {
  7940. const levels = b.raw.seasonAdventure.level;
  7941. for (const id in levels) {
  7942. const level = levels[id];
  7943. level.clientData.graphics.fogged = level.clientData.graphics.visible;
  7944. }
  7945. const adv = b.raw.seasonAdventure.list[1];
  7946. adv.clientData.asset = 'dialog_season_adventure_tiles';
  7947. } catch (e) {
  7948. console.warn(e);
  7949. }
  7950. originalStartFunc.call(this, a, b, c);
  7951. };
  7952. }
  7953.  
  7954. this.LibLoad = function () {
  7955. return new Promise((e) => {
  7956. this.doneLibLoad = e;
  7957. });
  7958. };
  7959.  
  7960. /**
  7961. * Returns the value of a language constant
  7962. *
  7963. * Возвращает значение языковой константы
  7964. * @param {*} langConst language constant // языковая константа
  7965. * @returns
  7966. */
  7967. this.translate = function (langConst) {
  7968. return Game.Translate.translate(langConst);
  7969. };
  7970.  
  7971. connectGame();
  7972. checkLibLoad();
  7973. }
  7974.  
  7975. /**
  7976. * Auto collection of gifts
  7977. *
  7978. * Автосбор подарков
  7979. */
  7980. function getAutoGifts() {
  7981. // c3ltYm9scyB0aGF0IG1lYW4gbm90aGluZw==
  7982. let valName = 'giftSendIds_' + userInfo.id;
  7983.  
  7984. if (!localStorage['clearGift' + userInfo.id]) {
  7985. localStorage[valName] = '';
  7986. localStorage['clearGift' + userInfo.id] = '+';
  7987. }
  7988.  
  7989. if (!localStorage[valName]) {
  7990. localStorage[valName] = '';
  7991. }
  7992.  
  7993. const giftsAPI = new ZingerYWebsiteAPI('getGifts.php', arguments);
  7994. /**
  7995. * Submit a request to receive gift codes
  7996. *
  7997. * Отправка запроса для получения кодов подарков
  7998. */
  7999. giftsAPI.request().then((data) => {
  8000. let freebieCheckCalls = {
  8001. calls: [],
  8002. };
  8003. data.forEach((giftId, n) => {
  8004. if (localStorage[valName].includes(giftId)) return;
  8005. freebieCheckCalls.calls.push({
  8006. name: 'registration',
  8007. args: {
  8008. user: { referrer: {} },
  8009. giftId,
  8010. },
  8011. context: {
  8012. actionTs: Math.floor(performance.now()),
  8013. cookie: window?.NXAppInfo?.session_id || null,
  8014. },
  8015. ident: giftId,
  8016. });
  8017. });
  8018.  
  8019. if (!freebieCheckCalls.calls.length) {
  8020. return;
  8021. }
  8022.  
  8023. send(JSON.stringify(freebieCheckCalls), (e) => {
  8024. let countGetGifts = 0;
  8025. const gifts = [];
  8026. for (check of e.results) {
  8027. gifts.push(check.ident);
  8028. if (check.result.response != null) {
  8029. countGetGifts++;
  8030. }
  8031. }
  8032. const saveGifts = localStorage[valName].split(';');
  8033. localStorage[valName] = [...saveGifts, ...gifts].slice(-50).join(';');
  8034. console.log(`${I18N('GIFTS')}: ${countGetGifts}`);
  8035. });
  8036. });
  8037. }
  8038.  
  8039. /**
  8040. * To fill the kills in the Forge of Souls
  8041. *
  8042. * Набить килов в горниле душ
  8043. */
  8044. async function bossRatingEvent() {
  8045. const topGet = await Send(JSON.stringify({ calls: [{ name: "topGet", args: { type: "bossRatingTop", extraId: 0 }, ident: "body" }] }));
  8046. if (!topGet || !topGet.results[0].result.response[0]) {
  8047. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  8048. return;
  8049. }
  8050. const replayId = topGet.results[0].result.response[0].userData.replayId;
  8051. const result = await Send(JSON.stringify({
  8052. calls: [
  8053. { name: "battleGetReplay", args: { id: replayId }, ident: "battleGetReplay" },
  8054. { name: "heroGetAll", args: {}, ident: "heroGetAll" },
  8055. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  8056. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  8057. ]
  8058. }));
  8059. const bossEventInfo = result.results[3].result.response.find(e => e.offerType == "bossEvent");
  8060. if (!bossEventInfo) {
  8061. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  8062. return;
  8063. }
  8064. const usedHeroes = bossEventInfo.progress.usedHeroes;
  8065. const party = Object.values(result.results[0].result.response.replay.attackers);
  8066. const availableHeroes = Object.values(result.results[1].result.response).map(e => e.id);
  8067. const availablePets = Object.values(result.results[2].result.response).map(e => e.id);
  8068. const calls = [];
  8069. /**
  8070. * First pack
  8071. *
  8072. * Первая пачка
  8073. */
  8074. const args = {
  8075. heroes: [],
  8076. favor: {}
  8077. }
  8078. for (let hero of party) {
  8079. if (hero.id >= 6000 && availablePets.includes(hero.id)) {
  8080. args.pet = hero.id;
  8081. continue;
  8082. }
  8083. if (!availableHeroes.includes(hero.id) || usedHeroes.includes(hero.id)) {
  8084. continue;
  8085. }
  8086. args.heroes.push(hero.id);
  8087. if (hero.favorPetId) {
  8088. args.favor[hero.id] = hero.favorPetId;
  8089. }
  8090. }
  8091. if (args.heroes.length) {
  8092. calls.push({
  8093. name: 'bossRating_startBattle',
  8094. args,
  8095. ident: 'body_0',
  8096. });
  8097. }
  8098. /**
  8099. * Other packs
  8100. *
  8101. * Другие пачки
  8102. */
  8103. let heroes = [];
  8104. let count = 1;
  8105. while (heroId = availableHeroes.pop()) {
  8106. if (args.heroes.includes(heroId) || usedHeroes.includes(heroId)) {
  8107. continue;
  8108. }
  8109. heroes.push(heroId);
  8110. if (heroes.length == 5) {
  8111. calls.push({
  8112. name: 'bossRating_startBattle',
  8113. args: {
  8114. heroes: [...heroes],
  8115. pet: availablePets[Math.floor(Math.random() * availablePets.length)],
  8116. },
  8117. ident: 'body_' + count,
  8118. });
  8119. heroes = [];
  8120. count++;
  8121. }
  8122. }
  8123.  
  8124. if (!calls.length) {
  8125. setProgress(`${I18N('NO_HEROES')}`, true);
  8126. return;
  8127. }
  8128.  
  8129. const resultBattles = await Send(JSON.stringify({ calls }));
  8130. console.log(resultBattles);
  8131. rewardBossRatingEvent();
  8132. }
  8133.  
  8134. /**
  8135. * Collecting Rewards from the Forge of Souls
  8136. *
  8137. * Сбор награды из Горнила Душ
  8138. */
  8139. function rewardBossRatingEvent() {
  8140. let rewardBossRatingCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  8141. send(rewardBossRatingCall, function (data) {
  8142. let bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  8143. if (!bossEventInfo) {
  8144. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  8145. return;
  8146. }
  8147.  
  8148. let farmedChests = bossEventInfo.progress.farmedChests;
  8149. let score = bossEventInfo.progress.score;
  8150. setProgress(`${I18N('DAMAGE_AMOUNT')}: ${score}`);
  8151. let revard = bossEventInfo.reward;
  8152.  
  8153. let getRewardCall = {
  8154. calls: []
  8155. }
  8156.  
  8157. let count = 0;
  8158. for (let i = 1; i < 10; i++) {
  8159. if (farmedChests.includes(i)) {
  8160. continue;
  8161. }
  8162. if (score < revard[i].score) {
  8163. break;
  8164. }
  8165. getRewardCall.calls.push({
  8166. name: 'bossRating_getReward',
  8167. args: {
  8168. rewardId: i,
  8169. },
  8170. ident: 'body_' + i,
  8171. });
  8172. count++;
  8173. }
  8174. if (!count) {
  8175. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  8176. return;
  8177. }
  8178.  
  8179. send(JSON.stringify(getRewardCall), e => {
  8180. console.log(e);
  8181. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  8182. });
  8183. });
  8184. }
  8185.  
  8186. /**
  8187. * Collect Easter eggs and event rewards
  8188. *
  8189. * Собрать пасхалки и награды событий
  8190. */
  8191. function offerFarmAllReward() {
  8192. const offerGetAllCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  8193. return Send(offerGetAllCall).then((data) => {
  8194. const offerGetAll = data.results[0].result.response.filter(e => e.type == "reward" && !e?.freeRewardObtained && e.reward);
  8195. if (!offerGetAll.length) {
  8196. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  8197. return;
  8198. }
  8199.  
  8200. const calls = [];
  8201. for (let reward of offerGetAll) {
  8202. calls.push({
  8203. name: "offerFarmReward",
  8204. args: {
  8205. offerId: reward.id
  8206. },
  8207. ident: "offerFarmReward_" + reward.id
  8208. });
  8209. }
  8210.  
  8211. return Send(JSON.stringify({ calls })).then(e => {
  8212. console.log(e);
  8213. setProgress(`${I18N('COLLECTED')} ${e?.results?.length} ${I18N('REWARD')}`, true);
  8214. });
  8215. });
  8216. }
  8217.  
  8218. /**
  8219. * Assemble Outland
  8220. *
  8221. * Собрать запределье
  8222. */
  8223. function getOutland() {
  8224. return new Promise(function (resolve, reject) {
  8225. send('{"calls":[{"name":"bossGetAll","args":{},"ident":"bossGetAll"}]}', e => {
  8226. let bosses = e.results[0].result.response;
  8227.  
  8228. let bossRaidOpenChestCall = {
  8229. calls: []
  8230. };
  8231.  
  8232. for (let boss of bosses) {
  8233. if (boss.mayRaid) {
  8234. bossRaidOpenChestCall.calls.push({
  8235. name: "bossRaid",
  8236. args: {
  8237. bossId: boss.id
  8238. },
  8239. ident: "bossRaid_" + boss.id
  8240. });
  8241. bossRaidOpenChestCall.calls.push({
  8242. name: "bossOpenChest",
  8243. args: {
  8244. bossId: boss.id,
  8245. amount: 1,
  8246. starmoney: 0
  8247. },
  8248. ident: "bossOpenChest_" + boss.id
  8249. });
  8250. } else if (boss.chestId == 1) {
  8251. bossRaidOpenChestCall.calls.push({
  8252. name: "bossOpenChest",
  8253. args: {
  8254. bossId: boss.id,
  8255. amount: 1,
  8256. starmoney: 0
  8257. },
  8258. ident: "bossOpenChest_" + boss.id
  8259. });
  8260. }
  8261. }
  8262.  
  8263. if (!bossRaidOpenChestCall.calls.length) {
  8264. setProgress(`${I18N('OUTLAND')} ${I18N('NOTHING_TO_COLLECT')}`, true);
  8265. resolve();
  8266. return;
  8267. }
  8268.  
  8269. send(JSON.stringify(bossRaidOpenChestCall), e => {
  8270. setProgress(`${I18N('OUTLAND')} ${I18N('COLLECTED')}`, true);
  8271. resolve();
  8272. });
  8273. });
  8274. });
  8275. }
  8276.  
  8277. /**
  8278. * Collect all rewards
  8279. *
  8280. * Собрать все награды
  8281. */
  8282. function questAllFarm() {
  8283. return new Promise(function (resolve, reject) {
  8284. let questGetAllCall = {
  8285. calls: [{
  8286. name: "questGetAll",
  8287. args: {},
  8288. ident: "body"
  8289. }]
  8290. }
  8291. send(JSON.stringify(questGetAllCall), function (data) {
  8292. let questGetAll = data.results[0].result.response;
  8293. const questAllFarmCall = {
  8294. calls: []
  8295. }
  8296. let number = 0;
  8297. for (let quest of questGetAll) {
  8298. if (quest.id < 1e6 && quest.state == 2) {
  8299. questAllFarmCall.calls.push({
  8300. name: "questFarm",
  8301. args: {
  8302. questId: quest.id
  8303. },
  8304. ident: `group_${number}_body`
  8305. });
  8306. number++;
  8307. }
  8308. }
  8309.  
  8310. if (!questAllFarmCall.calls.length) {
  8311. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  8312. resolve();
  8313. return;
  8314. }
  8315.  
  8316. send(JSON.stringify(questAllFarmCall), function (res) {
  8317. console.log(res);
  8318. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  8319. resolve();
  8320. });
  8321. });
  8322. })
  8323. }
  8324.  
  8325. /**
  8326. * Mission auto repeat
  8327. *
  8328. * Автоповтор миссии
  8329. * isStopSendMission = false;
  8330. * isSendsMission = true;
  8331. **/
  8332. this.sendsMission = async function (param) {
  8333. async function stopMission() {
  8334. isSendsMission = false;
  8335. console.log(I18N('STOPPED'));
  8336. setProgress('');
  8337. await popup.confirm(`${I18N('STOPPED')}<br>${I18N('REPETITIONS')}: ${param.count}`, [{
  8338. msg: 'Ok',
  8339. result: true
  8340. }, ])
  8341. }
  8342. if (isStopSendMission) {
  8343. stopMission();
  8344. return;
  8345. }
  8346. lastMissionBattleStart = Date.now();
  8347. let missionStartCall = {
  8348. "calls": [{
  8349. "name": "missionStart",
  8350. "args": lastMissionStart,
  8351. "ident": "body"
  8352. }]
  8353. }
  8354. /**
  8355. * Mission Request
  8356. *
  8357. * Запрос на выполнение мисии
  8358. */
  8359. SendRequest(JSON.stringify(missionStartCall), async e => {
  8360. if (e['error']) {
  8361. isSendsMission = false;
  8362. console.log(e['error']);
  8363. setProgress('');
  8364. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  8365. await popup.confirm(msg, [
  8366. {msg: 'Ok', result: true},
  8367. ])
  8368. return;
  8369. }
  8370. /**
  8371. * Mission data calculation
  8372. *
  8373. * Расчет данных мисии
  8374. */
  8375. BattleCalc(e.results[0].result.response, 'get_tower', async r => {
  8376. /** missionTimer */
  8377. let timer = getTimer(r.battleTime) + 5;
  8378. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  8379. if (period < timer) {
  8380. timer = timer - period;
  8381. const isSuccess = await countdownTimer(timer, `${I18N('MISSIONS_PASSED')}: ${param.count}`, () => {
  8382. isStopSendMission = true;
  8383. });
  8384. if (!isSuccess) {
  8385. stopMission();
  8386. return;
  8387. }
  8388. }
  8389.  
  8390. let missionEndCall = {
  8391. "calls": [{
  8392. "name": "missionEnd",
  8393. "args": {
  8394. "id": param.id,
  8395. "result": r.result,
  8396. "progress": r.progress
  8397. },
  8398. "ident": "body"
  8399. }]
  8400. }
  8401. /**
  8402. * Mission Completion Request
  8403. *
  8404. * Запрос на завершение миссии
  8405. */
  8406. SendRequest(JSON.stringify(missionEndCall), async (e) => {
  8407. if (e['error']) {
  8408. isSendsMission = false;
  8409. console.log(e['error']);
  8410. setProgress('');
  8411. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  8412. await popup.confirm(msg, [
  8413. {msg: 'Ok', result: true},
  8414. ])
  8415. return;
  8416. }
  8417. r = e.results[0].result.response;
  8418. if (r['error']) {
  8419. isSendsMission = false;
  8420. console.log(r['error']);
  8421. setProgress('');
  8422. await popup.confirm(`<br>${I18N('REPETITIONS')}: ${param.count}` + ' 3 ' + r['error'], [
  8423. {msg: 'Ok', result: true},
  8424. ])
  8425. return;
  8426. }
  8427.  
  8428. param.count++;
  8429. setProgress(`${I18N('MISSIONS_PASSED')}: ${param.count} (${I18N('STOP')})`, false, () => {
  8430. isStopSendMission = true;
  8431. });
  8432. setTimeout(sendsMission, 1, param);
  8433. });
  8434. })
  8435. });
  8436. }
  8437.  
  8438. /**
  8439. * Opening of russian dolls
  8440. *
  8441. * Открытие матрешек
  8442. */
  8443. async function openRussianDolls(libId, amount) {
  8444. let sum = 0;
  8445. const sumResult = {};
  8446. let count = 0;
  8447.  
  8448. while (amount) {
  8449. sum += amount;
  8450. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`);
  8451. const calls = [
  8452. {
  8453. name: 'consumableUseLootBox',
  8454. args: { libId, amount },
  8455. ident: 'body',
  8456. },
  8457. ];
  8458. const response = await Send(JSON.stringify({ calls })).then((e) => e.results[0].result.response);
  8459. let [countLootBox, result] = Object.entries(response).pop();
  8460. count += +countLootBox;
  8461. let newCount = 0;
  8462.  
  8463. if (result?.consumable && result.consumable[libId]) {
  8464. newCount = result.consumable[libId];
  8465. delete result.consumable[libId];
  8466. }
  8467.  
  8468. mergeItemsObj(sumResult, result);
  8469. amount = newCount;
  8470. }
  8471.  
  8472. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`, 5000);
  8473. return [count, sumResult];
  8474. }
  8475.  
  8476. function mergeItemsObj(obj1, obj2) {
  8477. for (const key in obj2) {
  8478. if (obj1[key]) {
  8479. if (typeof obj1[key] == 'object') {
  8480. for (const innerKey in obj2[key]) {
  8481. obj1[key][innerKey] = (obj1[key][innerKey] || 0) + obj2[key][innerKey];
  8482. }
  8483. } else {
  8484. obj1[key] += obj2[key] || 0;
  8485. }
  8486. } else {
  8487. obj1[key] = obj2[key];
  8488. }
  8489. }
  8490.  
  8491. return obj1;
  8492. }
  8493.  
  8494. /**
  8495. * Collect all mail, except letters with energy and charges of the portal
  8496. *
  8497. * Собрать всю почту, кроме писем с энергией и зарядами портала
  8498. */
  8499. function mailGetAll() {
  8500. const getMailInfo = '{"calls":[{"name":"mailGetAll","args":{},"ident":"body"}]}';
  8501.  
  8502. return Send(getMailInfo).then(dataMail => {
  8503. const letters = dataMail.results[0].result.response.letters;
  8504. const letterIds = lettersFilter(letters);
  8505. if (!letterIds.length) {
  8506. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  8507. return;
  8508. }
  8509.  
  8510. const calls = [
  8511. { name: "mailFarm", args: { letterIds }, ident: "body" }
  8512. ];
  8513.  
  8514. return Send(JSON.stringify({ calls })).then(res => {
  8515. const lettersIds = res.results[0].result.response;
  8516. if (lettersIds) {
  8517. const countLetters = Object.keys(lettersIds).length;
  8518. setProgress(`${I18N('RECEIVED')} ${countLetters} ${I18N('LETTERS')}`, true);
  8519. }
  8520. });
  8521. });
  8522. }
  8523.  
  8524. /**
  8525. * Filters received emails
  8526. *
  8527. * Фильтрует получаемые письма
  8528. */
  8529. function lettersFilter(letters) {
  8530. const lettersIds = [];
  8531. for (let l in letters) {
  8532. letter = letters[l];
  8533. const reward = letter?.reward;
  8534. if (!reward || !Object.keys(reward).length) {
  8535. continue;
  8536. }
  8537. /**
  8538. * Mail Collection Exceptions
  8539. *
  8540. * Исключения на сбор писем
  8541. */
  8542. const isFarmLetter = !(
  8543. /** Portals // сферы портала */
  8544. (reward?.refillable ? reward.refillable[45] : false) ||
  8545. /** Energy // энергия */
  8546. (reward?.stamina ? reward.stamina : false) ||
  8547. /** accelerating energy gain // ускорение набора энергии */
  8548. (reward?.buff ? true : false) ||
  8549. /** VIP Points // вип очки */
  8550. (reward?.vipPoints ? reward.vipPoints : false) ||
  8551. /** souls of heroes // душы героев */
  8552. (reward?.fragmentHero ? true : false) ||
  8553. /** heroes // герои */
  8554. (reward?.bundleHeroReward ? true : false)
  8555. );
  8556. if (isFarmLetter) {
  8557. lettersIds.push(~~letter.id);
  8558. continue;
  8559. }
  8560. /**
  8561. * Если до окончания годности письма менее 24 часов,
  8562. * то оно собирается не смотря на исключения
  8563. */
  8564. const availableUntil = +letter?.availableUntil;
  8565. if (availableUntil) {
  8566. const maxTimeLeft = 24 * 60 * 60 * 1000;
  8567. const timeLeft = (new Date(availableUntil * 1000) - new Date())
  8568. console.log('Time left:', timeLeft)
  8569. if (timeLeft < maxTimeLeft) {
  8570. lettersIds.push(~~letter.id);
  8571. continue;
  8572. }
  8573. }
  8574. }
  8575. return lettersIds;
  8576. }
  8577.  
  8578. function setPortals(value = 0, isChange = false) {
  8579. const { buttons } = HWHData;
  8580. const sanctuaryButton = buttons['testAdventure'].button;
  8581. const sanctuaryDot = sanctuaryButton.querySelector('.scriptMenu_dot');
  8582. if (isChange) {
  8583. value = Math.max(+sanctuaryDot.innerText + value, 0);
  8584. }
  8585. if (value) {
  8586. sanctuaryButton.classList.add('scriptMenu_attention');
  8587. sanctuaryDot.title = `${value} ${I18N('PORTALS')}`;
  8588. sanctuaryDot.innerText = value;
  8589. sanctuaryDot.style.backgroundColor = 'red';
  8590. } else {
  8591. sanctuaryButton.classList.remove('scriptMenu_attention');
  8592. sanctuaryDot.innerText = 0;
  8593. }
  8594. }
  8595.  
  8596. function setWarTries(value = 0, isChange = false, arePointsMax = false) {
  8597. const { buttons } = HWHData;
  8598. const clanWarButton = buttons['goToClanWar'].button;
  8599. const clanWarDot = clanWarButton.querySelector('.scriptMenu_dot');
  8600. if (isChange) {
  8601. value = Math.max(+clanWarDot.innerText + value, 0);
  8602. }
  8603. if (value && !arePointsMax) {
  8604. clanWarButton.classList.add('scriptMenu_attention');
  8605. clanWarDot.title = `${value} ${I18N('ATTEMPTS')}`;
  8606. clanWarDot.innerText = value;
  8607. clanWarDot.style.backgroundColor = 'red';
  8608. } else {
  8609. clanWarButton.classList.remove('scriptMenu_attention');
  8610. clanWarDot.innerText = 0;
  8611. }
  8612. }
  8613.  
  8614. /**
  8615. * Displaying information about the areas of the portal and attempts on the VG
  8616. *
  8617. * Отображение информации о сферах портала и попытках на ВГ
  8618. */
  8619. async function justInfo() {
  8620. return new Promise(async (resolve, reject) => {
  8621. const calls = [
  8622. {
  8623. name: 'userGetInfo',
  8624. args: {},
  8625. ident: 'userGetInfo',
  8626. },
  8627. {
  8628. name: 'clanWarGetInfo',
  8629. args: {},
  8630. ident: 'clanWarGetInfo',
  8631. },
  8632. {
  8633. name: 'titanArenaGetStatus',
  8634. args: {},
  8635. ident: 'titanArenaGetStatus',
  8636. },
  8637. {
  8638. name: 'quest_completeEasterEggQuest',
  8639. args: {},
  8640. ident: 'quest_completeEasterEggQuest',
  8641. },
  8642. ];
  8643. const result = await Send(JSON.stringify({ calls }));
  8644. const infos = result.results;
  8645. const portalSphere = infos[0].result.response.refillable.find(n => n.id == 45);
  8646. const clanWarMyTries = infos[1].result.response?.myTries ?? 0;
  8647. const arePointsMax = infos[1].result.response?.arePointsMax;
  8648. const titansLevel = +(infos[2].result.response?.tier ?? 0);
  8649. const titansStatus = infos[2].result.response?.status; //peace_time || battle
  8650.  
  8651. setPortals(portalSphere.amount);
  8652. setWarTries(clanWarMyTries, false, arePointsMax);
  8653.  
  8654. const { buttons } = HWHData;
  8655. const titansArenaButton = buttons['testTitanArena'].button;
  8656. const titansArenaDot = titansArenaButton.querySelector('.scriptMenu_dot');
  8657.  
  8658. if (titansLevel < 7 && titansStatus == 'battle') { ;
  8659. titansArenaButton.classList.add('scriptMenu_attention');
  8660. titansArenaDot.title = `${titansLevel} ${I18N('LEVEL')}`;
  8661. titansArenaDot.innerText = titansLevel;
  8662. titansArenaDot.style.backgroundColor = 'red';
  8663. } else {
  8664. titansArenaButton.classList.remove('scriptMenu_attention');
  8665. }
  8666.  
  8667. const imgPortal =
  8668. 'data:image/gif;base64,R0lGODlhLwAvAHAAACH5BAEAAP8ALAAAAAAvAC8AhwAAABkQWgjF3krO3ghSjAhSzinF3u+tGWvO3s5rGSmE5gha7+/OWghSrWvmnClShCmUlAiE5u+MGe/W3mvvWmspUmvvGSnOWinOnCnOGWsZjErvnAiUlErvWmsIUkrvGQjOWgjOnAjOGUoZjM6MGe/OIWvv5q1KGSnv5mulGe/vWs7v3ozv3kqEGYxKGWuEWmtSKUrv3mNaCEpKUs7OWiml5ggxWmMpEAgZpRlaCO/35q1rGRkxKWtarSkZrRljKSkZhAjv3msIGRk6CEparQhjWq3v3kql3ozOGe/vnM6tGYytWu9rGWuEGYzO3kqE3gil5s6MWq3vnGvFnM7vWoxrGc5KGYyMWs6tWq2MGYzOnO+tWmvFWkqlWoxrWgAZhEqEWq2tWoytnIyt3krFnGul3mulWmulnEIpUkqlGUqlnK3OnK2MWs7OnClSrSmUte+tnGvFGYytGYzvWs5rWowpGa3O3u/OnErFWoyMnGuE3muEnEqEnIyMGYzOWs7OGe9r3u9rWq3vWq1rWq1r3invWimlWu+t3q0pWq2t3u8pWu8p3q0p3invnCnvGe/vGa2tGa3vGa2tnK0pGe9rnK1rnCmlGe8pGe8pnK0pnGsZrSkp3msp3s7vGYzvnM7vnIzvGc6tnM5r3oxr3gilWs6t3owpWs4pWs4p3owp3s5rnIxrnAilGc4pGc4pnIwpnAgp3kop3s7O3u9KGe+MWoxKWoyM3kIIUgiUte+MnErFGc5KWowIGe9K3u9KWq3OWq1KWq1K3gjvWimEWu+M3q0IWq2M3u8IWu8I3q0I3gjvnAjvGa3OGa2MnK0IGe9KnK1KnCmEGe8IGe8InK0InEoZrSkI3msI3s6MnM5K3oxK3giEWs6M3owIWs4IWs4I3owI3s5KnIxKnAiEGc4IGc4InIwInAgI3koI3kJaCAgQKUIpEGtKUkJSKUIIECla7ylazmtahGta70pa70pahGtazkpazmtrWiExUkprUiljWikQKRkQCAAQCAAACAAAAAj/AP8JHEiwoMGDCBMqXMiwocODJlBIRBHDxMOLBmMEkSjAgICPE2Mw/OUH4z8TGz+agBIBCsuWUAQE0WLwzkAkKZZcnAilhk+fA1bUiEC0ZZABJOD8IyHhwJYDkpakafJQ4kooR5yw0LFihQ4WJhAMKCoARRYSTJgkUOInBZK2DiX2rGHEiI67eFcYATtAAVEoKEiQSFBFDs4UKbg0lGgAigIEeCNzrWvCxIChEcoy3dGiSoITTRQvnCLRrxOveI2McbKahevKJmooiKkFy4Gzg5tMMaMwitwIj/PqGPCugL0CT47ANhEjQg3Atg9IT5CiS4uEUcRIBH4EtREETuB9/xn/BUcBBbBXGGgpoPaBEid23EuXgvdBJhtQGFCwwA7eMgs0gEMDBJD3hR7KbRVbSwP8UcIWJNwjIRLXGZRAAhLVsIACR9y1whMNfNGAHgiUcUSBX8ADWwwKzCYADTSUcMA9ebwQmkFYMMFGhgu80x1XTxSAwxNdGWGCAiG6YQBzly3QkhYxlsDGP1cg4YBBaC0h1zsLPGHXCkfA00AZeu11hALl1VBZXwW0RAaMDGDxTxNdTGEQExJoiUINXCpwmhFOKJCcVmCdOR56MezXJhRvwFlCC2lcWVAUEjBxRobw9HhEXUYekWBlsoVoQEWyFbAAFPRIQQMDJcDQhRhYSv+QZ1kGcAnPYya4BhZYlb1TQ4iI+tVmBPpIQQWrMORxkKwSsEFrDaa+8xgCy1mmgLSHxtDXAhtGMIOxDKjgAkLM7iAAYD4VJ+0RAyAgVl++ikfAESxy62QB365awrjLyprAcxEY4FOmXEp7LbctjlfAAE1yGwEBYBirAgP8GtTUARIMM1QBPrVYQAHF9dgiml/Mexl/3DbAwxnHMqBExQVdLAEMjRXQgHOyydaibPCgqEDH3JrawDosUDExCTATZJuMJ0AAxRNXtLFFPD+P/DB58AC9wH4N4BMxDRPvkPRAbLx3AAlVMLBFCXeQgIaIKJKHQ9X8+forAetMsaoKB7j/MAhCL5j9VFNPJYBGiCGW18CtsvWIs5j7gLEGqyV81gxC6ZBQQgkSMEUCLQckMMLHNhcAD3B+8TdyA0PPACWrB8SH0BItyHAAAwdE4YILTSUww8cELwAyt7D4JSberkd5wA4neIFQE020sMPmJZBwAi0SJMBOA6WTXgAsDYDPOj7r3KNFy5WfkEBCKbTQBQzTM+By5wm4YAPr+LM+IIE27LPOFWswmgqqZ4UEXCEhLUjBGWbgAs3JD2OfWcc68GEDArCOAASwAfnWUYUwtIEKSVCBCiSgPuclpAlImMI9YNDAzeFuMEwQ2w3W4Q530PAGLthBFNqwghCKMAoF3MEB/xNihvr8Ix4sdCCrJja47CVAMFjAwid6eJcQWi8BO4jHQl6AGFjdwwUnOMF75CfCMpoxCTpAoxoZMBgs3qMh7ZODQFYYxgSMsQThCpcK0BiZJNxBCZ7zwhsbYqO3wCoe7AjjCaxAggNUcY94mcDa3qMECWSBHYN0CBfj0IQliEFCMFjkIulAAisUkBZYyB4USxAFCZnkH1xsgltSYCMYyACMpizghS7kOTZIKJMmeYEZzCCH6iCmBS1IRzpkcEsXVMGZMMgHJvfwyoLsYQ9nmMIUuDAFPIAhH8pUZjLbcY89rKKaC9nDFeLxy3vkYwbJTMcL0InOeOSjBVShJz2pqQvPfvrznwANKEMCAgA7';
  8669.  
  8670. setProgress('<img src="' + imgPortal + '" style="height: 25px;position: relative;top: 5px;"> ' + `${portalSphere.amount} </br> ${I18N('GUILD_WAR')}: ${clanWarMyTries}`, true);
  8671. resolve();
  8672. });
  8673. }
  8674.  
  8675. async function getDailyBonus() {
  8676. const dailyBonusInfo = await Send(JSON.stringify({
  8677. calls: [{
  8678. name: "dailyBonusGetInfo",
  8679. args: {},
  8680. ident: "body"
  8681. }]
  8682. })).then(e => e.results[0].result.response);
  8683. const { availableToday, availableVip, currentDay } = dailyBonusInfo;
  8684.  
  8685. if (!availableToday) {
  8686. console.log('Уже собрано');
  8687. return;
  8688. }
  8689.  
  8690. const currentVipPoints = +userInfo.vipPoints;
  8691. const dailyBonusStat = lib.getData('dailyBonusStatic');
  8692. const vipInfo = lib.getData('level').vip;
  8693. let currentVipLevel = 0;
  8694. for (let i in vipInfo) {
  8695. vipLvl = vipInfo[i];
  8696. if (currentVipPoints >= vipLvl.vipPoints) {
  8697. currentVipLevel = vipLvl.level;
  8698. }
  8699. }
  8700. const vipLevelDouble = dailyBonusStat[`${currentDay}_0_0`].vipLevelDouble;
  8701.  
  8702. const calls = [{
  8703. name: "dailyBonusFarm",
  8704. args: {
  8705. vip: availableVip && currentVipLevel >= vipLevelDouble ? 1 : 0
  8706. },
  8707. ident: "body"
  8708. }];
  8709.  
  8710. const result = await Send(JSON.stringify({ calls }));
  8711. if (result.error) {
  8712. console.error(result.error);
  8713. return;
  8714. }
  8715.  
  8716. const reward = result.results[0].result.response;
  8717. const type = Object.keys(reward).pop();
  8718. const itemId = Object.keys(reward[type]).pop();
  8719. const count = reward[type][itemId];
  8720. const itemName = cheats.translate(`LIB_${type.toUpperCase()}_NAME_${itemId}`);
  8721.  
  8722. console.log(`Ежедневная награда: Получено ${count} ${itemName}`, reward);
  8723. }
  8724.  
  8725. async function farmStamina(lootBoxId = 148) {
  8726. const lootBox = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"}]}')
  8727. .then(e => e.results[0].result.response.consumable[148]);
  8728.  
  8729. /** Добавить другие ящики */
  8730. /**
  8731. * 144 - медная шкатулка
  8732. * 145 - бронзовая шкатулка
  8733. * 148 - платиновая шкатулка
  8734. */
  8735. if (!lootBox) {
  8736. setProgress(I18N('NO_BOXES'), true);
  8737. return;
  8738. }
  8739.  
  8740. let maxFarmEnergy = getSaveVal('maxFarmEnergy', 100);
  8741. const result = await popup.confirm(I18N('OPEN_LOOTBOX', { lootBox }), [
  8742. { result: false, isClose: true },
  8743. { msg: I18N('BTN_YES'), result: true },
  8744. { msg: I18N('STAMINA'), isInput: true, default: maxFarmEnergy },
  8745. ]);
  8746. if (!+result) {
  8747. return;
  8748. }
  8749.  
  8750. if ((typeof result) !== 'boolean' && Number.parseInt(result)) {
  8751. maxFarmEnergy = +result;
  8752. setSaveVal('maxFarmEnergy', maxFarmEnergy);
  8753. } else {
  8754. maxFarmEnergy = 0;
  8755. }
  8756.  
  8757. let collectEnergy = 0;
  8758. for (let count = lootBox; count > 0; count--) {
  8759. const response = await Send('{"calls":[{"name":"consumableUseLootBox","args":{"libId":148,"amount":1},"ident":"body"}]}').then(
  8760. (e) => e.results[0].result.response
  8761. );
  8762. const result = Object.values(response).pop();
  8763. if ('stamina' in result) {
  8764. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox} ${I18N('STAMINA')} +${result.stamina}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  8765. console.log(`${ I18N('STAMINA') } + ${ result.stamina }`);
  8766. if (!maxFarmEnergy) {
  8767. return;
  8768. }
  8769. collectEnergy += +result.stamina;
  8770. if (collectEnergy >= maxFarmEnergy) {
  8771. console.log(`${I18N('STAMINA')} + ${ collectEnergy }`);
  8772. setProgress(`${I18N('STAMINA')} + ${ collectEnergy }`, false);
  8773. return;
  8774. }
  8775. } else {
  8776. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  8777. console.log(result);
  8778. }
  8779. }
  8780.  
  8781. setProgress(I18N('BOXES_OVER'), true);
  8782. }
  8783.  
  8784. async function fillActive() {
  8785. const data = await Send(JSON.stringify({
  8786. calls: [{
  8787. name: "questGetAll",
  8788. args: {},
  8789. ident: "questGetAll"
  8790. }, {
  8791. name: "inventoryGet",
  8792. args: {},
  8793. ident: "inventoryGet"
  8794. }, {
  8795. name: "clanGetInfo",
  8796. args: {},
  8797. ident: "clanGetInfo"
  8798. }
  8799. ]
  8800. })).then(e => e.results.map(n => n.result.response));
  8801.  
  8802. const quests = data[0];
  8803. const inv = data[1];
  8804. const stat = data[2].stat;
  8805. const maxActive = 2000 - stat.todayItemsActivity;
  8806. if (maxActive <= 0) {
  8807. setProgress(I18N('NO_MORE_ACTIVITY'), true);
  8808. return;
  8809. }
  8810. let countGetActive = 0;
  8811. const quest = quests.find(e => e.id > 10046 && e.id < 10051);
  8812. if (quest) {
  8813. countGetActive = 1750 - quest.progress;
  8814. }
  8815. if (countGetActive <= 0) {
  8816. countGetActive = maxActive;
  8817. }
  8818. console.log(countGetActive);
  8819.  
  8820. countGetActive = +(await popup.confirm(I18N('EXCHANGE_ITEMS', { maxActive }), [
  8821. { result: false, isClose: true },
  8822. { msg: I18N('GET_ACTIVITY'), isInput: true, default: countGetActive.toString() },
  8823. ]));
  8824.  
  8825. if (!countGetActive) {
  8826. return;
  8827. }
  8828.  
  8829. if (countGetActive > maxActive) {
  8830. countGetActive = maxActive;
  8831. }
  8832.  
  8833. const items = lib.getData('inventoryItem');
  8834.  
  8835. let itemsInfo = [];
  8836. for (let type of ['gear', 'scroll']) {
  8837. for (let i in inv[type]) {
  8838. const v = items[type][i]?.enchantValue || 0;
  8839. itemsInfo.push({
  8840. id: i,
  8841. count: inv[type][i],
  8842. v,
  8843. type
  8844. })
  8845. }
  8846. const invType = 'fragment' + type.toLowerCase().charAt(0).toUpperCase() + type.slice(1);
  8847. for (let i in inv[invType]) {
  8848. const v = items[type][i]?.fragmentEnchantValue || 0;
  8849. itemsInfo.push({
  8850. id: i,
  8851. count: inv[invType][i],
  8852. v,
  8853. type: invType
  8854. })
  8855. }
  8856. }
  8857. itemsInfo = itemsInfo.filter(e => e.v < 4 && e.count > 200);
  8858. itemsInfo = itemsInfo.sort((a, b) => b.count - a.count);
  8859. console.log(itemsInfo);
  8860. const activeItem = itemsInfo.shift();
  8861. console.log(activeItem);
  8862. const countItem = Math.ceil(countGetActive / activeItem.v);
  8863. if (countItem > activeItem.count) {
  8864. setProgress(I18N('NOT_ENOUGH_ITEMS'), true);
  8865. console.log(activeItem);
  8866. return;
  8867. }
  8868.  
  8869. await Send(JSON.stringify({
  8870. calls: [{
  8871. name: "clanItemsForActivity",
  8872. args: {
  8873. items: {
  8874. [activeItem.type]: {
  8875. [activeItem.id]: countItem
  8876. }
  8877. }
  8878. },
  8879. ident: "body"
  8880. }]
  8881. })).then(e => {
  8882. /** TODO: Вывести потраченые предметы */
  8883. console.log(e);
  8884. setProgress(`${I18N('ACTIVITY_RECEIVED')}: ` + e.results[0].result.response, true);
  8885. });
  8886. }
  8887.  
  8888. async function buyHeroFragments() {
  8889. const result = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"},{"name":"shopGetAll","args":{},"ident":"shopGetAll"}]}')
  8890. .then(e => e.results.map(n => n.result.response));
  8891. const inv = result[0];
  8892. const shops = Object.values(result[1]).filter(shop => [4, 5, 6, 8, 9, 10, 17].includes(shop.id));
  8893. const calls = [];
  8894.  
  8895. for (let shop of shops) {
  8896. const slots = Object.values(shop.slots);
  8897. for (const slot of slots) {
  8898. /* Уже куплено */
  8899. if (slot.bought) {
  8900. continue;
  8901. }
  8902. /* Не душа героя */
  8903. if (!('fragmentHero' in slot.reward)) {
  8904. continue;
  8905. }
  8906. const coin = Object.keys(slot.cost).pop();
  8907. const coinId = Object.keys(slot.cost[coin]).pop();
  8908. const stock = inv[coin][coinId] || 0;
  8909. /* Не хватает на покупку */
  8910. if (slot.cost[coin][coinId] > stock) {
  8911. continue;
  8912. }
  8913. inv[coin][coinId] -= slot.cost[coin][coinId];
  8914. calls.push({
  8915. name: "shopBuy",
  8916. args: {
  8917. shopId: shop.id,
  8918. slot: slot.id,
  8919. cost: slot.cost,
  8920. reward: slot.reward,
  8921. },
  8922. ident: `shopBuy_${shop.id}_${slot.id}`,
  8923. })
  8924. }
  8925. }
  8926.  
  8927. if (!calls.length) {
  8928. setProgress(I18N('NO_PURCHASABLE_HERO_SOULS'), true);
  8929. return;
  8930. }
  8931.  
  8932. const bought = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  8933. if (!bought) {
  8934. console.log('что-то пошло не так')
  8935. return;
  8936. }
  8937.  
  8938. let countHeroSouls = 0;
  8939. for (const buy of bought) {
  8940. countHeroSouls += +Object.values(Object.values(buy).pop()).pop();
  8941. }
  8942. console.log(countHeroSouls, bought, calls);
  8943. setProgress(I18N('PURCHASED_HERO_SOULS', { countHeroSouls }), true);
  8944. }
  8945.  
  8946. /** Открыть платные сундуки в Запределье за 90 */
  8947. async function bossOpenChestPay() {
  8948. const callsNames = ['userGetInfo', 'bossGetAll', 'specialOffer_getAll', 'getTime'];
  8949. const info = await Send({ calls: callsNames.map((name) => ({ name, args: {}, ident: name })) }).then((e) =>
  8950. e.results.map((n) => n.result.response)
  8951. );
  8952.  
  8953. const user = info[0];
  8954. const boses = info[1];
  8955. const offers = info[2];
  8956. const time = info[3];
  8957.  
  8958. const discountOffer = offers.find((e) => e.offerType == 'costReplaceOutlandChest');
  8959.  
  8960. let discount = 1;
  8961. if (discountOffer && discountOffer.endTime > time) {
  8962. discount = 1 - discountOffer.offerData.outlandChest.discountPercent / 100;
  8963. }
  8964.  
  8965. cost9chests = 540 * discount;
  8966. cost18chests = 1740 * discount;
  8967. costFirstChest = 90 * discount;
  8968. costSecondChest = 200 * discount;
  8969.  
  8970. const currentStarMoney = user.starMoney;
  8971. if (currentStarMoney < cost9chests) {
  8972. setProgress('Недостаточно изюма, нужно ' + cost9chests + ' у Вас ' + currentStarMoney, true);
  8973. return;
  8974. }
  8975.  
  8976. const imgEmerald =
  8977. "<img style='position: relative;top: 3px;' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAXCAYAAAD+4+QTAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAY8SURBVEhLpVV5bFVlFv/d7a19W3tfN1pKabGFAm3Rlg4toAWRiH+AioiaqAkaE42NycRR0ZnomJnJYHAJERGNyx/GJYoboo2igKVSMUUKreW1pRvUvr7XvvXe9+7qeW1nGJaJycwvObnny/fl/L7zO+c7l8EV0LAKzA+H83lAFAC/BeDJN2gnc5yd/WaQ8Q0NCCnAANkU+ZfjIpKqJWBOd4EDbHagueBPb1tWuesi9Rqn86zJZDbAMTp4xoSFzMaa4FVe6fra3bbzQbYN6A8Cmrz0qoBx8gzMmaj/QfKHWyxs+4e1DiC78M9v5TTn1RtbVH+kMWlJCCad100VOmQiUWFnNLg4HW42QeYEl3KnIiP5Bzu/dr27o0UistD48k2d8rF9Sib9GZKaejAnOmrs2/6e3VR3q7idF41GWVA41uQQ1RMY00ZJrChcrAYvx8HHaSjil8LLilCY98BORylBKlWQHhjzfvfFnuTfPn1O+xFolzM7s5nMI80rSl7qib8ykRNcWyaUosBWgnN6BL3pHuRwucjmnBTUCjfHwElkNiaNPHYr0mYCKnMeE/r3OC2NQiZZheHsfQ9Vu1uAM+eBIX2W5Nqsh/ewtxlrhl75NtUviDpwq+s+NOXWwWFhKKCd6iCQVByV2qSb0wEo5PvhY9YikGrH3uAdiBtBDIdVVAvlyfjBOffuesTcDxySqD3mUxaOPLZ6aktAOS/kqHaYigN7gnsxMGnDAuEuiPw6ymIt3MwaZFFQB7MeTmYjPLSWjTTCioQ5XCOMJIPeoInD/SNOviy6heLmALkckRTyf3xLbtQ8k6sdOodcxoocMoXU9JoFdF8VESMMiWRJmykyedqXTInaQJnOTtYDcJtZ+DXkRSrOou1cCoHx4LptL0nLgYU8kWhwlFgrNV2wFnEmVAr+w9gUzkwQic2DoNmLYe0QgkYXIuYg4uYYosYQJs1fMGkEpqWzUVucDh9E37gCIWFgvY9FcbniEipii6hbwZVilP0kXB/jysrrPLqU3yDG0JzXhA3OjWgsXo8UG6XbR6AxScqJjJHo/gmY0+9FIOn80I0UkukQFohJNFZmwV/uhosX2j59KPuF8JgS5CI3wHB90RUdKL12pMs7Z3VvfH6WyOajPt+Deb7FRDCBmNmNpNmPhHEWCW0IMXUQaTVEtVPhseYTZRCBeB86h8+hY0yDodsHfny+4NETB7JOLN74TXqmu1Yu4ixHuj3ii0/eaatx7RgY/NYKtR2tm+6B7lbwTGg3bDQ06MLTcsoJettR4DqaC8+u/gfe6HwZOzuGQU8JDR5f1B2+6uHWp8RPSjfsj5/dDyMzfIAj3bqSK8bGW579ECPWXRViHTijDK2BPojcPCxkbXCZflh1H5ISkCCSWJxI8jcjmErhnaHh6fdzdbZTd0aKd7Q+5T/gqj6VyBBkwmfG0QySkkHDJq19dDrgvP3GQq/Pt6h/8mesLqqFz+6DRq0qWkR4uGzEYhrGJBktNdvQGfoJH490YwmNuwKt+LWvWubtAk6GlPHhfw/LCyQz0BXEZOaoLcDf1lAt2z1z5nIhlIsL0Csfo90sWDkHXDYXaq2VWFZShffOfoQc0qOIzT9wbGvpXxOYGgG6SdwLuJSE6mPT1ZNdUdM9fyi8YlnTEiHLc423GBPaFBSVQcrQqcMYrJrbjElVRUf8FIq57K4z/8x7rL9f7ymsb0vHz83GmsXlJJSlsXKhxn3w+YSyrC48vKB0zVbLYqHCUYEe5SekaRYznBuLvU1olwbBmvr4r/v4RzteN4761x+Wxg9dGPH/wkzhL8WRHkMvKo7j/sc/Swfir7ZT/WTYSapc6LwFhc4qSKwLEYHXoz/bnzv8dOw7+4ojyYkvLyfI4MokhNToSKZwYf+6u3e39P3y8XH6AeY5yxHiBcx11OA8rZO9qTdaNx9/n9KPyUdnOulKuFyui6GHAAkHpEDBptqauaKtcMySRBW3HH2Do1+9WbP9GXocVGj5okJfit8jATY06Dh+MBIyiwZrrylb4XXneO1BV9df7n/tMb0/0J17O9LJU7Nn/x+UrKvOyOq58dXtNz0Q2Luz+cUnrqe1q+qmyv8q9/+EypuXZrK2kdEwgW3R5pW/r8I0gN8AVk6uP7Y929oAAAAASUVORK5CYII='>";
  8978.  
  8979. if (currentStarMoney < cost9chests) {
  8980. setProgress(I18N('NOT_ENOUGH_EMERALDS_540', { currentStarMoney, imgEmerald }), true);
  8981. return;
  8982. }
  8983.  
  8984. const buttons = [{ result: false, isClose: true }];
  8985.  
  8986. if (currentStarMoney >= cost9chests) {
  8987. buttons.push({
  8988. msg: I18N('BUY_OUTLAND_BTN', { count: 9, countEmerald: cost9chests, imgEmerald }),
  8989. result: [costFirstChest, costFirstChest, 0],
  8990. });
  8991. }
  8992.  
  8993. if (currentStarMoney >= cost18chests) {
  8994. buttons.push({
  8995. msg: I18N('BUY_OUTLAND_BTN', { count: 18, countEmerald: cost18chests, imgEmerald }),
  8996. result: [costFirstChest, costFirstChest, 0, costSecondChest, costSecondChest, 0],
  8997. });
  8998. }
  8999.  
  9000. const answer = await popup.confirm(`<div style="margin-bottom: 15px;">${I18N('BUY_OUTLAND')}</div>`, buttons);
  9001.  
  9002. if (!answer) {
  9003. return;
  9004. }
  9005.  
  9006. const callBoss = [];
  9007. let n = 0;
  9008. for (let boss of boses) {
  9009. const bossId = boss.id;
  9010. if (boss.chestNum != 2) {
  9011. continue;
  9012. }
  9013. const calls = [];
  9014. for (const starmoney of answer) {
  9015. calls.push({
  9016. name: 'bossOpenChest',
  9017. args: {
  9018. amount: 1,
  9019. bossId,
  9020. starmoney,
  9021. },
  9022. ident: 'bossOpenChest_' + ++n,
  9023. });
  9024. }
  9025. callBoss.push(calls);
  9026. }
  9027.  
  9028. if (!callBoss.length) {
  9029. setProgress(I18N('CHESTS_NOT_AVAILABLE'), true);
  9030. return;
  9031. }
  9032.  
  9033. let count = 0;
  9034. let errors = 0;
  9035. for (const calls of callBoss) {
  9036. const result = await Send({ calls });
  9037. console.log(result);
  9038. if (result?.results) {
  9039. count += result.results.length;
  9040. } else {
  9041. errors++;
  9042. }
  9043. }
  9044.  
  9045. setProgress(`${I18N('OUTLAND_CHESTS_RECEIVED')}: ${count}`, true);
  9046. }
  9047.  
  9048. async function autoRaidAdventure() {
  9049. const calls = [
  9050. {
  9051. name: "userGetInfo",
  9052. args: {},
  9053. ident: "userGetInfo"
  9054. },
  9055. {
  9056. name: "adventure_raidGetInfo",
  9057. args: {},
  9058. ident: "adventure_raidGetInfo"
  9059. }
  9060. ];
  9061. const result = await Send(JSON.stringify({ calls }))
  9062. .then(e => e.results.map(n => n.result.response));
  9063.  
  9064. const portalSphere = result[0].refillable.find(n => n.id == 45);
  9065. const adventureRaid = Object.entries(result[1].raid).filter(e => e[1]).pop()
  9066. const adventureId = adventureRaid ? adventureRaid[0] : 0;
  9067.  
  9068. if (!portalSphere.amount || !adventureId) {
  9069. setProgress(I18N('RAID_NOT_AVAILABLE'), true);
  9070. return;
  9071. }
  9072.  
  9073. const countRaid = +(await popup.confirm(I18N('RAID_ADVENTURE', { adventureId }), [
  9074. { result: false, isClose: true },
  9075. { msg: I18N('RAID'), isInput: true, default: portalSphere.amount },
  9076. ]));
  9077.  
  9078. if (!countRaid) {
  9079. return;
  9080. }
  9081.  
  9082. if (countRaid > portalSphere.amount) {
  9083. countRaid = portalSphere.amount;
  9084. }
  9085.  
  9086. const resultRaid = await Send(JSON.stringify({
  9087. calls: [...Array(countRaid)].map((e, i) => ({
  9088. name: "adventure_raid",
  9089. args: {
  9090. adventureId
  9091. },
  9092. ident: `body_${i}`
  9093. }))
  9094. })).then(e => e.results.map(n => n.result.response));
  9095.  
  9096. if (!resultRaid.length) {
  9097. console.log(resultRaid);
  9098. setProgress(I18N('SOMETHING_WENT_WRONG'), true);
  9099. return;
  9100. }
  9101.  
  9102. console.log(resultRaid, adventureId, portalSphere.amount);
  9103. setProgress(I18N('ADVENTURE_COMPLETED', { adventureId, times: resultRaid.length }), true);
  9104. }
  9105.  
  9106. /** Вывести всю клановую статистику в консоль браузера */
  9107. async function clanStatistic() {
  9108. const copy = function (text) {
  9109. const copyTextarea = document.createElement("textarea");
  9110. copyTextarea.style.opacity = "0";
  9111. copyTextarea.textContent = text;
  9112. document.body.appendChild(copyTextarea);
  9113. copyTextarea.select();
  9114. document.execCommand("copy");
  9115. document.body.removeChild(copyTextarea);
  9116. delete copyTextarea;
  9117. }
  9118. const calls = [
  9119. { name: "clanGetInfo", args: {}, ident: "clanGetInfo" },
  9120. { name: "clanGetWeeklyStat", args: {}, ident: "clanGetWeeklyStat" },
  9121. { name: "clanGetLog", args: {}, ident: "clanGetLog" },
  9122. ];
  9123.  
  9124. const result = await Send(JSON.stringify({ calls }));
  9125.  
  9126. const dataClanInfo = result.results[0].result.response;
  9127. const dataClanStat = result.results[1].result.response;
  9128. const dataClanLog = result.results[2].result.response;
  9129.  
  9130. const membersStat = {};
  9131. for (let i = 0; i < dataClanStat.stat.length; i++) {
  9132. membersStat[dataClanStat.stat[i].id] = dataClanStat.stat[i];
  9133. }
  9134.  
  9135. const joinStat = {};
  9136. historyLog = dataClanLog.history;
  9137. for (let j in historyLog) {
  9138. his = historyLog[j];
  9139. if (his.event == 'join') {
  9140. joinStat[his.userId] = his.ctime;
  9141. }
  9142. }
  9143.  
  9144. const infoArr = [];
  9145. const members = dataClanInfo.clan.members;
  9146. for (let n in members) {
  9147. var member = [
  9148. n,
  9149. members[n].name,
  9150. members[n].level,
  9151. dataClanInfo.clan.warriors.includes(+n) ? 1 : 0,
  9152. (new Date(members[n].lastLoginTime * 1000)).toLocaleString().replace(',', ''),
  9153. joinStat[n] ? (new Date(joinStat[n] * 1000)).toLocaleString().replace(',', '') : '',
  9154. membersStat[n].activity.reverse().join('\t'),
  9155. membersStat[n].adventureStat.reverse().join('\t'),
  9156. membersStat[n].clanGifts.reverse().join('\t'),
  9157. membersStat[n].clanWarStat.reverse().join('\t'),
  9158. membersStat[n].dungeonActivity.reverse().join('\t'),
  9159. ];
  9160. infoArr.push(member);
  9161. }
  9162. const info = infoArr.sort((a, b) => (b[2] - a[2])).map((e) => e.join('\t')).join('\n');
  9163. console.log(info);
  9164. copy(info);
  9165. setProgress(I18N('CLAN_STAT_COPY'), true);
  9166. }
  9167.  
  9168. async function buyInStoreForGold() {
  9169. const result = await Send('{"calls":[{"name":"shopGetAll","args":{},"ident":"body"},{"name":"userGetInfo","args":{},"ident":"userGetInfo"}]}').then(e => e.results.map(n => n.result.response));
  9170. const shops = result[0];
  9171. const user = result[1];
  9172. let gold = user.gold;
  9173. const calls = [];
  9174. if (shops[17]) {
  9175. const slots = shops[17].slots;
  9176. for (let i = 1; i <= 2; i++) {
  9177. if (!slots[i].bought) {
  9178. const costGold = slots[i].cost.gold;
  9179. if ((gold - costGold) < 0) {
  9180. continue;
  9181. }
  9182. gold -= costGold;
  9183. calls.push({
  9184. name: "shopBuy",
  9185. args: {
  9186. shopId: 17,
  9187. slot: i,
  9188. cost: slots[i].cost,
  9189. reward: slots[i].reward,
  9190. },
  9191. ident: 'body_' + i,
  9192. })
  9193. }
  9194. }
  9195. }
  9196. const slots = shops[1].slots;
  9197. for (let i = 4; i <= 6; i++) {
  9198. if (!slots[i].bought && slots[i]?.cost?.gold) {
  9199. const costGold = slots[i].cost.gold;
  9200. if ((gold - costGold) < 0) {
  9201. continue;
  9202. }
  9203. gold -= costGold;
  9204. calls.push({
  9205. name: "shopBuy",
  9206. args: {
  9207. shopId: 1,
  9208. slot: i,
  9209. cost: slots[i].cost,
  9210. reward: slots[i].reward,
  9211. },
  9212. ident: 'body_' + i,
  9213. })
  9214. }
  9215. }
  9216.  
  9217. if (!calls.length) {
  9218. setProgress(I18N('NOTHING_BUY'), true);
  9219. return;
  9220. }
  9221.  
  9222. const resultBuy = await Send(JSON.stringify({ calls })).then(e => e.results.map(n => n.result.response));
  9223. console.log(resultBuy);
  9224. const countBuy = resultBuy.length;
  9225. setProgress(I18N('LOTS_BOUGHT', { countBuy }), true);
  9226. }
  9227.  
  9228. async function rewardsAndMailFarm() {
  9229. try {
  9230. const [questGetAll, mailGetAll, specialOffer] = await Caller.send(['questGetAll', 'mailGetAll', 'specialOffer_getAll']);
  9231. const questsFarm = questGetAll.filter((e) => e.state == 2);
  9232. const mailFarm = mailGetAll?.letters || [];
  9233. const stagesOffers = specialOffer.filter(e => e.offerType === "stagesOffer" && e.farmedStage == -1);
  9234.  
  9235. const questBattlePass = lib.getData('quest').battlePass;
  9236. const { questChain: questChainBPass, list: listBattlePass } = lib.getData('battlePass');
  9237. const currentTime = Date.now();
  9238.  
  9239. const farmCaller = new Caller();
  9240.  
  9241. for (const offer of stagesOffers) {
  9242. const offerId = offer.id;
  9243. //const stage = 0 - offer.farmedStage;
  9244. for (const stage of offer.offerData.stages) {
  9245. if (stage.billingId) {
  9246. break;
  9247. }
  9248. farmCaller.add({
  9249. name: 'specialOffer_farmReward',
  9250. args: { offerId },
  9251. });
  9252. }
  9253. }
  9254.  
  9255. const farmQuestIds = [];
  9256. const questIds = [];
  9257. for (let quest of questsFarm) {
  9258. const questId = +quest.id;
  9259.  
  9260. /*
  9261. if ([20010001, 20010002, 20010004].includes(questId)) {
  9262. farmCaller.add({
  9263. name: 'questFarm',
  9264. args: { questId },
  9265. });
  9266. farmQuestIds.push(questId);
  9267. continue;
  9268. }
  9269. */
  9270.  
  9271. if (questId >= 2001e4) {
  9272. continue;
  9273. }
  9274.  
  9275. if (questId > 1e6 && questId < 2e7) {
  9276. const questInfo = questBattlePass[questId];
  9277. const chain = questChainBPass[questInfo.chain];
  9278. if (chain.requirement?.battlePassTicket) {
  9279. continue;
  9280. }
  9281. const battlePass = listBattlePass[chain.battlePass];
  9282. const startTime = battlePass.startCondition.time.value * 1e3;
  9283. const endTime = startTime + battlePass.duration * 1e3;
  9284. if (startTime > currentTime || endTime < currentTime) {
  9285. continue;
  9286. }
  9287. }
  9288.  
  9289. if (questId >= 2e7) {
  9290. questIds.push(questId);
  9291. farmQuestIds.push(questId);
  9292. continue;
  9293. }
  9294.  
  9295. farmCaller.add({
  9296. name: 'questFarm',
  9297. args: { questId },
  9298. });
  9299. farmQuestIds.push(questId);
  9300. }
  9301.  
  9302. if (questIds.length) {
  9303. farmCaller.add({
  9304. name: 'quest_questsFarm',
  9305. args: { questIds },
  9306. });
  9307. }
  9308.  
  9309. const letterIds = lettersFilter(mailFarm);
  9310. if (letterIds.length) {
  9311. farmCaller.add({
  9312. name: 'mailFarm',
  9313. args: { letterIds },
  9314. });
  9315. }
  9316.  
  9317. if (farmCaller.isEmpty()) {
  9318. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  9319. return;
  9320. }
  9321.  
  9322. const farmResults = await farmCaller.send();
  9323.  
  9324. let countQuests = 0;
  9325. let countMail = 0;
  9326. let questsIds = [];
  9327.  
  9328. const questFarm = farmResults.result('questFarm', true);
  9329. countQuests += questFarm.length;
  9330. countQuests += questIds.length;
  9331. countMail += Object.keys(farmResults.result('mailFarm')).length;
  9332.  
  9333. const sideResult = farmResults.sideResult('questFarm', true);
  9334. sideResult.push(...farmResults.sideResult('quest_questsFarm', true));
  9335.  
  9336. for (let side of sideResult) {
  9337. const quests = [...(side.newQuests ?? []), ...(side.quests ?? [])];
  9338. for (let quest of quests) {
  9339. if ((quest.id < 1e6 || (quest.id >= 2e7 && quest.id < 2001e4)) && quest.state == 2) {
  9340. questsIds.push(quest.id);
  9341. }
  9342. }
  9343. }
  9344. questsIds = [...new Set(questsIds)];
  9345.  
  9346. while (questsIds.length) {
  9347. const recursiveCaller = new Caller();
  9348. const newQuestIds = [];
  9349.  
  9350. for (let questId of questsIds) {
  9351. if (farmQuestIds.includes(questId)) {
  9352. continue;
  9353. }
  9354. if (questId < 1e6) {
  9355. recursiveCaller.add({
  9356. name: 'questFarm',
  9357. args: { questId },
  9358. });
  9359. farmQuestIds.push(questId);
  9360. countQuests++;
  9361. } else if (questId >= 2e7 && questId < 2001e4) {
  9362. farmQuestIds.push(questId);
  9363. newQuestIds.push(questId);
  9364. countQuests++;
  9365. }
  9366. }
  9367.  
  9368. if (newQuestIds.length) {
  9369. recursiveCaller.add({
  9370. name: 'quest_questsFarm',
  9371. args: { questIds: newQuestIds },
  9372. });
  9373. }
  9374.  
  9375. questsIds = [];
  9376. if (recursiveCaller.isEmpty()) {
  9377. break;
  9378. }
  9379.  
  9380. await recursiveCaller.send();
  9381. const sideResult = recursiveCaller.sideResult('questFarm', true);
  9382. sideResult.push(...recursiveCaller.sideResult('quest_questsFarm', true));
  9383.  
  9384. for (let side of sideResult) {
  9385. const quests = [...(side.newQuests ?? []), ...(side.quests ?? [])];
  9386. for (let quest of quests) {
  9387. if ((quest.id < 1e6 || (quest.id >= 2e7 && quest.id < 2001e4)) && quest.state == 2) {
  9388. questsIds.push(quest.id);
  9389. }
  9390. }
  9391. }
  9392. questsIds = [...new Set(questsIds)];
  9393. }
  9394.  
  9395. setProgress(I18N('COLLECT_REWARDS_AND_MAIL', { countQuests, countMail }), true);
  9396. } catch (error) {
  9397. console.error('Error in questAllFarm:', error);
  9398. }
  9399. }
  9400.  
  9401. class epicBrawl {
  9402. timeout = null;
  9403. time = null;
  9404.  
  9405. constructor() {
  9406. if (epicBrawl.inst) {
  9407. return epicBrawl.inst;
  9408. }
  9409. epicBrawl.inst = this;
  9410. return this;
  9411. }
  9412.  
  9413. runTimeout(func, timeDiff) {
  9414. const worker = new Worker(URL.createObjectURL(new Blob([`
  9415. self.onmessage = function(e) {
  9416. const timeDiff = e.data;
  9417.  
  9418. if (timeDiff > 0) {
  9419. setTimeout(() => {
  9420. self.postMessage(1);
  9421. self.close();
  9422. }, timeDiff);
  9423. }
  9424. };
  9425. `])));
  9426. worker.postMessage(timeDiff);
  9427. worker.onmessage = () => {
  9428. func();
  9429. };
  9430. return true;
  9431. }
  9432.  
  9433. timeDiff(date1, date2) {
  9434. const date1Obj = new Date(date1);
  9435. const date2Obj = new Date(date2);
  9436.  
  9437. const timeDiff = Math.abs(date2Obj - date1Obj);
  9438.  
  9439. const totalSeconds = timeDiff / 1000;
  9440. const minutes = Math.floor(totalSeconds / 60);
  9441. const seconds = Math.floor(totalSeconds % 60);
  9442.  
  9443. const formattedMinutes = String(minutes).padStart(2, '0');
  9444. const formattedSeconds = String(seconds).padStart(2, '0');
  9445.  
  9446. return `${formattedMinutes}:${formattedSeconds}`;
  9447. }
  9448.  
  9449. check() {
  9450. console.log(new Date(this.time))
  9451. if (Date.now() > this.time) {
  9452. this.timeout = null;
  9453. this.start()
  9454. return;
  9455. }
  9456. this.timeout = this.runTimeout(() => this.check(), 6e4);
  9457. return this.timeDiff(this.time, Date.now())
  9458. }
  9459.  
  9460. async start() {
  9461. if (this.timeout) {
  9462. const time = this.timeDiff(this.time, Date.now());
  9463. console.log(new Date(this.time))
  9464. setProgress(I18N('TIMER_ALREADY', { time }), false, hideProgress);
  9465. return;
  9466. }
  9467. setProgress(I18N('EPIC_BRAWL'), false, hideProgress);
  9468. const teamInfo = await Send('{"calls":[{"name":"teamGetAll","args":{},"ident":"teamGetAll"},{"name":"teamGetFavor","args":{},"ident":"teamGetFavor"},{"name":"userGetInfo","args":{},"ident":"userGetInfo"}]}').then(e => e.results.map(n => n.result.response));
  9469. const refill = teamInfo[2].refillable.find(n => n.id == 52)
  9470. this.time = (refill.lastRefill + 3600) * 1000
  9471. const attempts = refill.amount;
  9472. if (!attempts) {
  9473. console.log(new Date(this.time));
  9474. const time = this.check();
  9475. setProgress(I18N('NO_ATTEMPTS_TIMER_START', { time }), false, hideProgress);
  9476. return;
  9477. }
  9478.  
  9479. if (!teamInfo[0].epic_brawl) {
  9480. setProgress(I18N('NO_HEROES_PACK'), false, hideProgress);
  9481. return;
  9482. }
  9483.  
  9484. const args = {
  9485. heroes: teamInfo[0].epic_brawl.filter(e => e < 1000),
  9486. pet: teamInfo[0].epic_brawl.filter(e => e > 6000).pop(),
  9487. favor: teamInfo[1].epic_brawl,
  9488. }
  9489.  
  9490. let wins = 0;
  9491. let coins = 0;
  9492. let streak = { progress: 0, nextStage: 0 };
  9493. for (let i = attempts; i > 0; i--) {
  9494. const info = await Send(JSON.stringify({
  9495. calls: [
  9496. { name: "epicBrawl_getEnemy", args: {}, ident: "epicBrawl_getEnemy" }, { name: "epicBrawl_startBattle", args, ident: "epicBrawl_startBattle" }
  9497. ]
  9498. })).then(e => e.results.map(n => n.result.response));
  9499.  
  9500. const { progress, result } = await Calc(info[1].battle);
  9501. const endResult = await Send(JSON.stringify({ calls: [{ name: "epicBrawl_endBattle", args: { progress, result }, ident: "epicBrawl_endBattle" }, { name: "epicBrawl_getWinStreak", args: {}, ident: "epicBrawl_getWinStreak" }] })).then(e => e.results.map(n => n.result.response));
  9502.  
  9503. const resultInfo = endResult[0].result;
  9504. streak = endResult[1];
  9505.  
  9506. wins += resultInfo.win;
  9507. coins += resultInfo.reward ? resultInfo.reward.coin[39] : 0;
  9508.  
  9509. console.log(endResult[0].result)
  9510. if (endResult[1].progress == endResult[1].nextStage) {
  9511. const farm = await Send('{"calls":[{"name":"epicBrawl_farmWinStreak","args":{},"ident":"body"}]}').then(e => e.results[0].result.response);
  9512. coins += farm.coin[39];
  9513. }
  9514.  
  9515. setProgress(I18N('EPIC_BRAWL_RESULT', {
  9516. i, wins, attempts, coins,
  9517. progress: streak.progress,
  9518. nextStage: streak.nextStage,
  9519. end: '',
  9520. }), false, hideProgress);
  9521. }
  9522.  
  9523. console.log(new Date(this.time));
  9524. const time = this.check();
  9525. setProgress(I18N('EPIC_BRAWL_RESULT', {
  9526. wins, attempts, coins,
  9527. i: '',
  9528. progress: streak.progress,
  9529. nextStage: streak.nextStage,
  9530. end: I18N('ATTEMPT_ENDED', { time }),
  9531. }), false, hideProgress);
  9532. }
  9533. }
  9534.  
  9535. function countdownTimer(seconds, message, onClick = null) {
  9536. message = message || I18N('TIMER');
  9537. const stopTimer = Date.now() + seconds * 1e3;
  9538. const isOnClick = typeof onClick === 'function';
  9539. return new Promise((resolve) => {
  9540. const interval = setInterval(async () => {
  9541. const now = Date.now();
  9542. const remaining = (stopTimer - now) / 1000;
  9543. const clickHandler = isOnClick
  9544. ? () => {
  9545. onClick();
  9546. clearInterval(interval);
  9547. setProgress('', true);
  9548. resolve(false);
  9549. }
  9550. : undefined;
  9551.  
  9552. setProgress(`${message} ${remaining.toFixed(2)}`, false, clickHandler);
  9553. if (now > stopTimer) {
  9554. clearInterval(interval);
  9555. setProgress('', true);
  9556. resolve(true);
  9557. }
  9558. }, 100);
  9559. });
  9560. }
  9561.  
  9562. this.HWHFuncs.countdownTimer = countdownTimer;
  9563.  
  9564. /** Набить килов в горниле душк */
  9565. async function bossRatingEventSouls() {
  9566. const data = await Send({
  9567. calls: [
  9568. { name: "heroGetAll", args: {}, ident: "teamGetAll" },
  9569. { name: "offerGetAll", args: {}, ident: "offerGetAll" },
  9570. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  9571. ]
  9572. });
  9573. const bossEventInfo = data.results[1].result.response.find(e => e.offerType == "bossEvent");
  9574. if (!bossEventInfo) {
  9575. setProgress('Эвент завершен', true);
  9576. return;
  9577. }
  9578.  
  9579. if (bossEventInfo.progress.score > 250) {
  9580. setProgress('Уже убито больше 250 врагов');
  9581. rewardBossRatingEventSouls();
  9582. return;
  9583. }
  9584. const availablePets = Object.values(data.results[2].result.response).map(e => e.id);
  9585. const heroGetAllList = data.results[0].result.response;
  9586. const usedHeroes = bossEventInfo.progress.usedHeroes;
  9587. const heroList = [];
  9588.  
  9589. for (let heroId in heroGetAllList) {
  9590. let hero = heroGetAllList[heroId];
  9591. if (usedHeroes.includes(hero.id)) {
  9592. continue;
  9593. }
  9594. heroList.push(hero.id);
  9595. }
  9596.  
  9597. if (!heroList.length) {
  9598. setProgress('Нет героев', true);
  9599. return;
  9600. }
  9601.  
  9602. const pet = availablePets.includes(6005) ? 6005 : availablePets[Math.floor(Math.random() * availablePets.length)];
  9603. const petLib = lib.getData('pet');
  9604. let count = 1;
  9605.  
  9606. for (const heroId of heroList) {
  9607. const args = {
  9608. heroes: [heroId],
  9609. pet
  9610. }
  9611. /** Поиск питомца для героя */
  9612. for (const petId of availablePets) {
  9613. if (petLib[petId].favorHeroes.includes(heroId)) {
  9614. args.favor = {
  9615. [heroId]: petId
  9616. }
  9617. break;
  9618. }
  9619. }
  9620.  
  9621. const calls = [{
  9622. name: "bossRatingEvent_startBattle",
  9623. args,
  9624. ident: "body"
  9625. }, {
  9626. name: "offerGetAll",
  9627. args: {},
  9628. ident: "offerGetAll"
  9629. }];
  9630.  
  9631. const res = await Send({ calls });
  9632. count++;
  9633.  
  9634. if ('error' in res) {
  9635. console.error(res.error);
  9636. setProgress('Перезагрузите игру и попробуйте позже', true);
  9637. return;
  9638. }
  9639.  
  9640. const eventInfo = res.results[1].result.response.find(e => e.offerType == "bossEvent");
  9641. if (eventInfo.progress.score > 250) {
  9642. break;
  9643. }
  9644. setProgress('Количество убитых врагов: ' + eventInfo.progress.score + '<br>Использовано ' + count + ' героев');
  9645. }
  9646.  
  9647. rewardBossRatingEventSouls();
  9648. }
  9649. /** Сбор награды из Горнила Душ */
  9650. async function rewardBossRatingEventSouls() {
  9651. const data = await Send({
  9652. calls: [
  9653. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  9654. ]
  9655. });
  9656.  
  9657. const bossEventInfo = data.results[0].result.response.find(e => e.offerType == "bossEvent");
  9658. if (!bossEventInfo) {
  9659. setProgress('Эвент завершен', true);
  9660. return;
  9661. }
  9662.  
  9663. const farmedChests = bossEventInfo.progress.farmedChests;
  9664. const score = bossEventInfo.progress.score;
  9665. // setProgress('Количество убитых врагов: ' + score);
  9666. const revard = bossEventInfo.reward;
  9667. const calls = [];
  9668.  
  9669. let count = 0;
  9670. for (let i = 1; i < 10; i++) {
  9671. if (farmedChests.includes(i)) {
  9672. continue;
  9673. }
  9674. if (score < revard[i].score) {
  9675. break;
  9676. }
  9677. calls.push({
  9678. name: "bossRatingEvent_getReward",
  9679. args: {
  9680. rewardId: i
  9681. },
  9682. ident: "body_" + i
  9683. });
  9684. count++;
  9685. }
  9686. if (!count) {
  9687. setProgress('Нечего собирать', true);
  9688. return;
  9689. }
  9690.  
  9691. Send({ calls }).then(e => {
  9692. console.log(e);
  9693. setProgress('Собрано ' + e?.results?.length + ' наград', true);
  9694. })
  9695. }
  9696. /**
  9697. * Spin the Seer
  9698. *
  9699. * Покрутить провидца
  9700. */
  9701. async function rollAscension() {
  9702. const refillable = await Send({calls:[
  9703. {
  9704. name:"userGetInfo",
  9705. args:{},
  9706. ident:"userGetInfo"
  9707. }
  9708. ]}).then(e => e.results[0].result.response.refillable);
  9709. const i47 = refillable.find(i => i.id == 47);
  9710. if (i47?.amount) {
  9711. await Send({ calls: [{ name: "ascensionChest_open", args: { paid: false, amount: 1 }, ident: "body" }] });
  9712. setProgress(I18N('DONE'), true);
  9713. } else {
  9714. setProgress(I18N('NOT_ENOUGH_AP'), true);
  9715. }
  9716. }
  9717.  
  9718. /**
  9719. * Collect gifts for the New Year
  9720. *
  9721. * Собрать подарки на новый год
  9722. */
  9723. function getGiftNewYear() {
  9724. Send({ calls: [{ name: "newYearGiftGet", args: { type: 0 }, ident: "body" }] }).then(e => {
  9725. const gifts = e.results[0].result.response.gifts;
  9726. const calls = gifts.filter(e => e.opened == 0).map(e => ({
  9727. name: "newYearGiftOpen",
  9728. args: {
  9729. giftId: e.id
  9730. },
  9731. ident: `body_${e.id}`
  9732. }));
  9733. if (!calls.length) {
  9734. setProgress(I18N('NY_NO_GIFTS'), 5000);
  9735. return;
  9736. }
  9737. Send({ calls }).then(e => {
  9738. console.log(e.results)
  9739. const msg = I18N('NY_GIFTS_COLLECTED', { count: e.results.length });
  9740. console.log(msg);
  9741. setProgress(msg, 5000);
  9742. });
  9743. })
  9744. }
  9745.  
  9746. async function updateArtifacts() {
  9747. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  9748. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  9749. { result: false, isClose: true }
  9750. ]);
  9751. if (!count) {
  9752. return;
  9753. }
  9754. const quest = new questRun;
  9755. await quest.autoInit();
  9756. const heroes = Object.values(quest.questInfo['heroGetAll']);
  9757. const inventory = quest.questInfo['inventoryGet'];
  9758. const calls = [];
  9759. for (let i = count; i > 0; i--) {
  9760. const upArtifact = quest.getUpgradeArtifact();
  9761. if (!upArtifact.heroId) {
  9762. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  9763. { msg: I18N('YES'), result: true },
  9764. { result: false, isClose: true }
  9765. ])) {
  9766. break;
  9767. } else {
  9768. return;
  9769. }
  9770. }
  9771. const hero = heroes.find(e => e.id == upArtifact.heroId);
  9772. hero.artifacts[upArtifact.slotId].level++;
  9773. inventory[upArtifact.costCurrency][upArtifact.costId] -= upArtifact.costValue;
  9774. calls.push({
  9775. name: "heroArtifactLevelUp",
  9776. args: {
  9777. heroId: upArtifact.heroId,
  9778. slotId: upArtifact.slotId
  9779. },
  9780. ident: `heroArtifactLevelUp_${i}`
  9781. });
  9782. }
  9783.  
  9784. if (!calls.length) {
  9785. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  9786. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  9787. return;
  9788. }
  9789.  
  9790. await Send(JSON.stringify({ calls })).then(e => {
  9791. if ('error' in e) {
  9792. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  9793. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  9794. } else {
  9795. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  9796. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  9797. }
  9798. });
  9799. }
  9800.  
  9801. window.sign = a => {
  9802. const i = this['\x78\x79\x7a'];
  9803. return md5([i['\x6e\x61\x6d\x65'], i['\x76\x65\x72\x73\x69\x6f\x6e'], i['\x61\x75\x74\x68\x6f\x72'], ~(a % 1e3)]['\x6a\x6f\x69\x6e']('\x5f'))
  9804. }
  9805.  
  9806. async function updateSkins() {
  9807. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  9808. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  9809. { result: false, isClose: true }
  9810. ]);
  9811. if (!count) {
  9812. return;
  9813. }
  9814.  
  9815. const quest = new questRun;
  9816. await quest.autoInit();
  9817. const heroes = Object.values(quest.questInfo['heroGetAll']);
  9818. const inventory = quest.questInfo['inventoryGet'];
  9819. const calls = [];
  9820. for (let i = count; i > 0; i--) {
  9821. const upSkin = quest.getUpgradeSkin();
  9822. if (!upSkin.heroId) {
  9823. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  9824. { msg: I18N('YES'), result: true },
  9825. { result: false, isClose: true }
  9826. ])) {
  9827. break;
  9828. } else {
  9829. return;
  9830. }
  9831. }
  9832. const hero = heroes.find(e => e.id == upSkin.heroId);
  9833. hero.skins[upSkin.skinId]++;
  9834. inventory[upSkin.costCurrency][upSkin.costCurrencyId] -= upSkin.cost;
  9835. calls.push({
  9836. name: "heroSkinUpgrade",
  9837. args: {
  9838. heroId: upSkin.heroId,
  9839. skinId: upSkin.skinId
  9840. },
  9841. ident: `heroSkinUpgrade_${i}`
  9842. })
  9843. }
  9844.  
  9845. if (!calls.length) {
  9846. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  9847. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  9848. return;
  9849. }
  9850.  
  9851. await Send(JSON.stringify({ calls })).then(e => {
  9852. if ('error' in e) {
  9853. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  9854. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  9855. } else {
  9856. console.log(I18N('IMPROVED_LEVELS', { count: e.results.length }));
  9857. setProgress(I18N('IMPROVED_LEVELS', { count: e.results.length }), false);
  9858. }
  9859. });
  9860. }
  9861.  
  9862. function getQuestionInfo(img, nameOnly = false) {
  9863. const libHeroes = Object.values(lib.data.hero);
  9864. const parts = img.split(':');
  9865. const id = parts[1];
  9866. switch (parts[0]) {
  9867. case 'titanArtifact_id':
  9868. return cheats.translate("LIB_TITAN_ARTIFACT_NAME_" + id);
  9869. case 'titan':
  9870. return cheats.translate("LIB_HERO_NAME_" + id);
  9871. case 'skill':
  9872. return cheats.translate("LIB_SKILL_" + id);
  9873. case 'inventoryItem_gear':
  9874. return cheats.translate("LIB_GEAR_NAME_" + id);
  9875. case 'inventoryItem_coin':
  9876. return cheats.translate("LIB_COIN_NAME_" + id);
  9877. case 'artifact':
  9878. if (nameOnly) {
  9879. return cheats.translate("LIB_ARTIFACT_NAME_" + id);
  9880. }
  9881. heroes = libHeroes.filter(h => h.id < 100 && h.artifacts.includes(+id));
  9882. return {
  9883. /** Как называется этот артефакт? */
  9884. name: cheats.translate("LIB_ARTIFACT_NAME_" + id),
  9885. /** Какому герою принадлежит этот артефакт? */
  9886. heroes: heroes.map(h => cheats.translate("LIB_HERO_NAME_" + h.id))
  9887. };
  9888. case 'hero':
  9889. if (nameOnly) {
  9890. return cheats.translate("LIB_HERO_NAME_" + id);
  9891. }
  9892. artifacts = lib.data.hero[id].artifacts;
  9893. return {
  9894. /** Как зовут этого героя? */
  9895. name: cheats.translate("LIB_HERO_NAME_" + id),
  9896. /** Какой артефакт принадлежит этому герою? */
  9897. artifact: artifacts.map(a => cheats.translate("LIB_ARTIFACT_NAME_" + a))
  9898. };
  9899. }
  9900. }
  9901.  
  9902. function hintQuest(quest) {
  9903. const result = {};
  9904. if (quest?.questionIcon) {
  9905. const info = getQuestionInfo(quest.questionIcon);
  9906. if (info?.heroes) {
  9907. /** Какому герою принадлежит этот артефакт? */
  9908. result.answer = quest.answers.filter(e => info.heroes.includes(e.answerText.slice(1)));
  9909. }
  9910. if (info?.artifact) {
  9911. /** Какой артефакт принадлежит этому герою? */
  9912. result.answer = quest.answers.filter(e => info.artifact.includes(e.answerText.slice(1)));
  9913. }
  9914. if (typeof info == 'string') {
  9915. result.info = { name: info };
  9916. } else {
  9917. result.info = info;
  9918. }
  9919. }
  9920.  
  9921. if (quest.answers[0]?.answerIcon) {
  9922. result.answer = quest.answers.filter(e => quest.question.includes(getQuestionInfo(e.answerIcon, true)))
  9923. }
  9924.  
  9925. if ((!result?.answer || !result.answer.length) && !result.info?.name) {
  9926. return false;
  9927. }
  9928.  
  9929. let resultText = '';
  9930. if (result?.info) {
  9931. resultText += I18N('PICTURE') + result.info.name;
  9932. }
  9933. console.log(result);
  9934. if (result?.answer && result.answer.length) {
  9935. resultText += I18N('ANSWER') + result.answer[0].id + (!result.answer[0].answerIcon ? ' - ' + result.answer[0].answerText : '');
  9936. }
  9937.  
  9938. return resultText;
  9939. }
  9940.  
  9941. async function farmBattlePass() {
  9942. const isFarmReward = (reward) => {
  9943. return !(reward?.buff || reward?.fragmentHero || reward?.bundleHeroReward);
  9944. };
  9945.  
  9946. const battlePassProcess = (pass) => {
  9947. if (!pass.id) {return []}
  9948. const levels = Object.values(lib.data.battlePass.level).filter(x => x.battlePass == pass.id)
  9949. const last_level = levels[levels.length - 1];
  9950. let actual = Math.max(...levels.filter(p => pass.exp >= p.experience).map(p => p.level))
  9951.  
  9952. if (pass.exp > last_level.experience) {
  9953. actual = last_level.level + (pass.exp - last_level.experience) / last_level.experienceByLevel;
  9954. }
  9955. const calls = [];
  9956. for(let i = 1; i <= actual; i++) {
  9957. const level = i >= last_level.level ? last_level : levels.find(l => l.level === i);
  9958. const reward = {free: level?.freeReward, paid:level?.paidReward};
  9959.  
  9960. if (!pass.rewards[i]?.free && isFarmReward(reward.free)) {
  9961. const args = {level: i, free:true};
  9962. if (!pass.gold) { args.id = pass.id }
  9963. calls.push({ name: 'battlePass_farmReward', args, ident: `${pass.gold ? 'body' : 'spesial'}_free_${args.id}_${i}` });
  9964. }
  9965. if (pass.ticket && !pass.rewards[i]?.paid && isFarmReward(reward.paid)) {
  9966. const args = {level: i, free:false};
  9967. if (!pass.gold) { args.id = pass.id}
  9968. calls.push({ name: 'battlePass_farmReward', args, ident: `${pass.gold ? 'body' : 'spesial'}_paid_${args.id}_${i}` });
  9969. }
  9970. }
  9971. return calls;
  9972. }
  9973.  
  9974. const passes = await Send({
  9975. calls: [
  9976. { name: 'battlePass_getInfo', args: {}, ident: 'getInfo' },
  9977. { name: 'battlePass_getSpecial', args: {}, ident: 'getSpecial' },
  9978. ],
  9979. }).then((e) => [{...e.results[0].result.response?.battlePass, gold: true}, ...Object.values(e.results[1].result.response)]);
  9980.  
  9981. const calls = passes.map(p => battlePassProcess(p)).flat()
  9982.  
  9983. if (!calls.length) {
  9984. setProgress(I18N('NOTHING_TO_COLLECT'));
  9985. return;
  9986. }
  9987.  
  9988. let results = await Send({calls});
  9989. if (results.error) {
  9990. console.log(results.error);
  9991. setProgress(I18N('SOMETHING_WENT_WRONG'));
  9992. } else {
  9993. setProgress(I18N('SEASON_REWARD_COLLECTED', {count: results.results.length}), true);
  9994. }
  9995. }
  9996.  
  9997. async function sellHeroSoulsForGold() {
  9998. let { fragmentHero, heroes } = await Send({
  9999. calls: [
  10000. { name: 'inventoryGet', args: {}, ident: 'inventoryGet' },
  10001. { name: 'heroGetAll', args: {}, ident: 'heroGetAll' },
  10002. ],
  10003. })
  10004. .then((e) => e.results.map((r) => r.result.response))
  10005. .then((e) => ({ fragmentHero: e[0].fragmentHero, heroes: e[1] }));
  10006.  
  10007. const calls = [];
  10008. for (let i in fragmentHero) {
  10009. if (heroes[i] && heroes[i].star == 6) {
  10010. calls.push({
  10011. name: 'inventorySell',
  10012. args: {
  10013. type: 'hero',
  10014. libId: i,
  10015. amount: fragmentHero[i],
  10016. fragment: true,
  10017. },
  10018. ident: 'inventorySell_' + i,
  10019. });
  10020. }
  10021. }
  10022. if (!calls.length) {
  10023. console.log(0);
  10024. return 0;
  10025. }
  10026. const rewards = await Send({ calls }).then((e) => e.results.map((r) => r.result?.response?.gold || 0));
  10027. const gold = rewards.reduce((e, a) => e + a, 0);
  10028. setProgress(I18N('GOLD_RECEIVED', { gold }), true);
  10029. }
  10030.  
  10031. /**
  10032. * Attack of the minions of Asgard
  10033. *
  10034. * Атака прислужников Асгарда
  10035. */
  10036. function testRaidNodes() {
  10037. const { executeRaidNodes } = HWHClasses;
  10038. return new Promise((resolve, reject) => {
  10039. const tower = new executeRaidNodes(resolve, reject);
  10040. tower.start();
  10041. });
  10042. }
  10043.  
  10044. /**
  10045. * Attack of the minions of Asgard
  10046. *
  10047. * Атака прислужников Асгарда
  10048. */
  10049. function executeRaidNodes(resolve, reject) {
  10050. let raidData = {
  10051. teams: [],
  10052. favor: {},
  10053. nodes: [],
  10054. attempts: 0,
  10055. countExecuteBattles: 0,
  10056. cancelBattle: 0,
  10057. }
  10058.  
  10059. callsExecuteRaidNodes = {
  10060. calls: [{
  10061. name: "clanRaid_getInfo",
  10062. args: {},
  10063. ident: "clanRaid_getInfo"
  10064. }, {
  10065. name: "teamGetAll",
  10066. args: {},
  10067. ident: "teamGetAll"
  10068. }, {
  10069. name: "teamGetFavor",
  10070. args: {},
  10071. ident: "teamGetFavor"
  10072. }]
  10073. }
  10074.  
  10075. this.start = function () {
  10076. send(JSON.stringify(callsExecuteRaidNodes), startRaidNodes);
  10077. }
  10078.  
  10079. async function startRaidNodes(data) {
  10080. res = data.results;
  10081. clanRaidInfo = res[0].result.response;
  10082. teamGetAll = res[1].result.response;
  10083. teamGetFavor = res[2].result.response;
  10084.  
  10085. let index = 0;
  10086. let isNotFullPack = false;
  10087. for (let team of teamGetAll.clanRaid_nodes) {
  10088. if (team.length < 6) {
  10089. isNotFullPack = true;
  10090. }
  10091. raidData.teams.push({
  10092. data: {},
  10093. heroes: team.filter(id => id < 6000),
  10094. pet: team.filter(id => id >= 6000).pop(),
  10095. battleIndex: index++
  10096. });
  10097. }
  10098. raidData.favor = teamGetFavor.clanRaid_nodes;
  10099.  
  10100. if (isNotFullPack) {
  10101. if (await popup.confirm(I18N('MINIONS_WARNING'), [
  10102. { msg: I18N('BTN_NO'), result: true },
  10103. { msg: I18N('BTN_YES'), result: false },
  10104. ])) {
  10105. endRaidNodes('isNotFullPack');
  10106. return;
  10107. }
  10108. }
  10109.  
  10110. raidData.nodes = clanRaidInfo.nodes;
  10111. raidData.attempts = clanRaidInfo.attempts;
  10112. setIsCancalBattle(false);
  10113.  
  10114. checkNodes();
  10115. }
  10116.  
  10117. function getAttackNode() {
  10118. for (let nodeId in raidData.nodes) {
  10119. let node = raidData.nodes[nodeId];
  10120. let points = 0
  10121. for (team of node.teams) {
  10122. points += team.points;
  10123. }
  10124. let now = Date.now() / 1000;
  10125. if (!points && now > node.timestamps.start && now < node.timestamps.end) {
  10126. let countTeam = node.teams.length;
  10127. delete raidData.nodes[nodeId];
  10128. return {
  10129. nodeId,
  10130. countTeam
  10131. };
  10132. }
  10133. }
  10134. return null;
  10135. }
  10136.  
  10137. function checkNodes() {
  10138. setProgress(`${I18N('REMAINING_ATTEMPTS')}: ${raidData.attempts}`);
  10139. let nodeInfo = getAttackNode();
  10140. if (nodeInfo && raidData.attempts) {
  10141. startNodeBattles(nodeInfo);
  10142. return;
  10143. }
  10144.  
  10145. endRaidNodes('EndRaidNodes');
  10146. }
  10147.  
  10148. function startNodeBattles(nodeInfo) {
  10149. let {nodeId, countTeam} = nodeInfo;
  10150. let teams = raidData.teams.slice(0, countTeam);
  10151. let heroes = raidData.teams.map(e => e.heroes).flat();
  10152. let favor = {...raidData.favor};
  10153. for (let heroId in favor) {
  10154. if (!heroes.includes(+heroId)) {
  10155. delete favor[heroId];
  10156. }
  10157. }
  10158.  
  10159. let calls = [{
  10160. name: "clanRaid_startNodeBattles",
  10161. args: {
  10162. nodeId,
  10163. teams,
  10164. favor
  10165. },
  10166. ident: "body"
  10167. }];
  10168.  
  10169. send(JSON.stringify({calls}), resultNodeBattles);
  10170. }
  10171.  
  10172. function resultNodeBattles(e) {
  10173. if (e['error']) {
  10174. endRaidNodes('nodeBattlesError', e['error']);
  10175. return;
  10176. }
  10177.  
  10178. console.log(e);
  10179. let battles = e.results[0].result.response.battles;
  10180. let promises = [];
  10181. let battleIndex = 0;
  10182. for (let battle of battles) {
  10183. battle.battleIndex = battleIndex++;
  10184. promises.push(calcBattleResult(battle));
  10185. }
  10186.  
  10187. Promise.all(promises)
  10188. .then(results => {
  10189. const endResults = {};
  10190. let isAllWin = true;
  10191. for (let r of results) {
  10192. isAllWin &&= r.result.win;
  10193. }
  10194. if (!isAllWin) {
  10195. cancelEndNodeBattle(results[0]);
  10196. return;
  10197. }
  10198. raidData.countExecuteBattles = results.length;
  10199. let timeout = 500;
  10200. for (let r of results) {
  10201. setTimeout(endNodeBattle, timeout, r);
  10202. timeout += 500;
  10203. }
  10204. });
  10205. }
  10206. /**
  10207. * Returns the battle calculation promise
  10208. *
  10209. * Возвращает промис расчета боя
  10210. */
  10211. function calcBattleResult(battleData) {
  10212. return new Promise(function (resolve, reject) {
  10213. BattleCalc(battleData, "get_clanPvp", resolve);
  10214. });
  10215. }
  10216. /**
  10217. * Cancels the fight
  10218. *
  10219. * Отменяет бой
  10220. */
  10221. function cancelEndNodeBattle(r) {
  10222. const fixBattle = function (heroes) {
  10223. for (const ids in heroes) {
  10224. hero = heroes[ids];
  10225. hero.energy = random(1, 999);
  10226. if (hero.hp > 0) {
  10227. hero.hp = random(1, hero.hp);
  10228. }
  10229. }
  10230. }
  10231. fixBattle(r.progress[0].attackers.heroes);
  10232. fixBattle(r.progress[0].defenders.heroes);
  10233. endNodeBattle(r);
  10234. }
  10235. /**
  10236. * Ends the fight
  10237. *
  10238. * Завершает бой
  10239. */
  10240. function endNodeBattle(r) {
  10241. let nodeId = r.battleData.result.nodeId;
  10242. let battleIndex = r.battleData.battleIndex;
  10243. let calls = [{
  10244. name: "clanRaid_endNodeBattle",
  10245. args: {
  10246. nodeId,
  10247. battleIndex,
  10248. result: r.result,
  10249. progress: r.progress
  10250. },
  10251. ident: "body"
  10252. }]
  10253.  
  10254. SendRequest(JSON.stringify({calls}), battleResult);
  10255. }
  10256. /**
  10257. * Processing the results of the battle
  10258. *
  10259. * Обработка результатов боя
  10260. */
  10261. function battleResult(e) {
  10262. if (e['error']) {
  10263. endRaidNodes('missionEndError', e['error']);
  10264. return;
  10265. }
  10266. r = e.results[0].result.response;
  10267. if (r['error']) {
  10268. if (r.reason == "invalidBattle") {
  10269. raidData.cancelBattle++;
  10270. checkNodes();
  10271. } else {
  10272. endRaidNodes('missionEndError', e['error']);
  10273. }
  10274. return;
  10275. }
  10276.  
  10277. if (!(--raidData.countExecuteBattles)) {
  10278. raidData.attempts--;
  10279. checkNodes();
  10280. }
  10281. }
  10282. /**
  10283. * Completing a task
  10284. *
  10285. * Завершение задачи
  10286. */
  10287. function endRaidNodes(reason, info) {
  10288. setIsCancalBattle(true);
  10289. let textCancel = raidData.cancelBattle ? ` ${I18N('BATTLES_CANCELED')}: ${raidData.cancelBattle}` : '';
  10290. setProgress(`${I18N('MINION_RAID')} ${I18N('COMPLETED')}! ${textCancel}`, true);
  10291. console.log(reason, info);
  10292. resolve();
  10293. }
  10294. }
  10295.  
  10296. this.HWHClasses.executeRaidNodes = executeRaidNodes;
  10297.  
  10298. /**
  10299. * Asgard Boss Attack Replay
  10300. *
  10301. * Повтор атаки босса Асгарда
  10302. */
  10303. function testBossBattle() {
  10304. const { executeBossBattle } = HWHClasses;
  10305. return new Promise((resolve, reject) => {
  10306. const bossBattle = new executeBossBattle(resolve, reject);
  10307. bossBattle.start(lastBossBattle);
  10308. });
  10309. }
  10310.  
  10311. /**
  10312. * Asgard Boss Attack Replay
  10313. *
  10314. * Повтор атаки босса Асгарда
  10315. */
  10316. function executeBossBattle(resolve, reject) {
  10317.  
  10318. this.start = function (battleInfo) {
  10319. preCalcBattle(battleInfo);
  10320. }
  10321.  
  10322. function getBattleInfo(battle) {
  10323. return new Promise(function (resolve) {
  10324. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  10325. BattleCalc(battle, getBattleType(battle.type), e => {
  10326. let extra = e.progress[0].defenders.heroes[1].extra;
  10327. resolve(extra.damageTaken + extra.damageTakenNextLevel);
  10328. });
  10329. });
  10330. }
  10331.  
  10332. function preCalcBattle(battle) {
  10333. let actions = [];
  10334. const countTestBattle = getInput('countTestBattle');
  10335. for (let i = 0; i < countTestBattle; i++) {
  10336. actions.push(getBattleInfo(battle, true));
  10337. }
  10338. Promise.all(actions)
  10339. .then(resultPreCalcBattle);
  10340. }
  10341.  
  10342. async function resultPreCalcBattle(damages) {
  10343. let maxDamage = 0;
  10344. let minDamage = 1e10;
  10345. let avgDamage = 0;
  10346. for (let damage of damages) {
  10347. avgDamage += damage
  10348. if (damage > maxDamage) {
  10349. maxDamage = damage;
  10350. }
  10351. if (damage < minDamage) {
  10352. minDamage = damage;
  10353. }
  10354. }
  10355. avgDamage /= damages.length;
  10356. console.log(damages.map(e => e.toLocaleString()).join('\n'), avgDamage, maxDamage);
  10357.  
  10358. await popup.confirm(
  10359. `${I18N('ROUND_STAT')} ${damages.length} ${I18N('BATTLE')}:` +
  10360. `<br>${I18N('MINIMUM')}: ` + minDamage.toLocaleString() +
  10361. `<br>${I18N('MAXIMUM')}: ` + maxDamage.toLocaleString() +
  10362. `<br>${I18N('AVERAGE')}: ` + avgDamage.toLocaleString()
  10363. , [
  10364. { msg: I18N('BTN_OK'), result: 0},
  10365. ])
  10366. endBossBattle(I18N('BTN_CANCEL'));
  10367. }
  10368.  
  10369. /**
  10370. * Completing a task
  10371. *
  10372. * Завершение задачи
  10373. */
  10374. function endBossBattle(reason, info) {
  10375. console.log(reason, info);
  10376. resolve();
  10377. }
  10378. }
  10379.  
  10380. this.HWHClasses.executeBossBattle = executeBossBattle;
  10381.  
  10382. class FixBattle {
  10383. minTimer = 1.3;
  10384. maxTimer = 15.3;
  10385.  
  10386. constructor(battle, isTimeout = true) {
  10387. this.battle = structuredClone(battle);
  10388. this.isTimeout = isTimeout;
  10389. this.isGetTimer = true;
  10390. }
  10391.  
  10392. timeout(callback, timeout) {
  10393. if (this.isTimeout) {
  10394. this.worker.postMessage(timeout);
  10395. this.worker.onmessage = callback;
  10396. } else {
  10397. callback();
  10398. }
  10399. }
  10400.  
  10401. randTimer() {
  10402. return Math.random() * (this.maxTimer - this.minTimer + 1) + this.minTimer;
  10403. }
  10404.  
  10405. getTimer() {
  10406. if (this.count === 1) {
  10407. this.initTimers();
  10408. }
  10409.  
  10410. return this.battleLogTimers[this.count];
  10411. }
  10412.  
  10413. setAvgTime(startTime) {
  10414. this.fixTime += Date.now() - startTime;
  10415. this.avgTime = this.fixTime / this.count;
  10416. }
  10417.  
  10418. initTimers() {
  10419. const timers = [...new Set(this.lastResult.battleLogs[0].map((e) => e.time))];
  10420. this.battleLogTimers = timers.sort(() => Math.random() - 0.5);
  10421. this.maxCount = Math.min(this.maxCount, this.battleLogTimers.length);
  10422. console.log('maxCount', this.maxCount);
  10423. }
  10424.  
  10425. init() {
  10426. this.fixTime = 0;
  10427. this.lastTimer = 0;
  10428. this.index = 0;
  10429. this.lastBossDamage = 0;
  10430. this.bestResult = {
  10431. count: 0,
  10432. timer: 0,
  10433. value: -Infinity,
  10434. result: null,
  10435. progress: null,
  10436. };
  10437. this.lastBattleResult = {
  10438. win: false,
  10439. };
  10440. this.worker = new Worker(
  10441. URL.createObjectURL(
  10442. new Blob([
  10443. `self.onmessage = function(e) {
  10444. const timeout = e.data;
  10445. setTimeout(() => {
  10446. self.postMessage(1);
  10447. }, timeout);
  10448. };`,
  10449. ])
  10450. )
  10451. );
  10452. }
  10453.  
  10454. async start(endTime = Date.now() + 6e4, maxCount = 100) {
  10455. this.endTime = endTime;
  10456. this.maxCount = maxCount;
  10457. this.init();
  10458. return await new Promise((resolve) => {
  10459. this.resolve = resolve;
  10460. this.count = 0;
  10461. this.loop();
  10462. });
  10463. }
  10464.  
  10465. endFix() {
  10466. this.bestResult.maxCount = this.count;
  10467. this.worker.terminate();
  10468. console.log('endFix', this.bestResult);
  10469. this.resolve(this.bestResult);
  10470. }
  10471.  
  10472. async loop() {
  10473. const start = Date.now();
  10474. if (this.isEndLoop()) {
  10475. this.endFix();
  10476. return;
  10477. }
  10478. this.count++;
  10479. try {
  10480. this.lastResult = await Calc(this.battle);
  10481. } catch (e) {
  10482. this.updateProgressTimer(this.index++);
  10483. this.timeout(this.loop.bind(this), 0);
  10484. return;
  10485. }
  10486. const { progress, result } = this.lastResult;
  10487. this.lastBattleResult = result;
  10488. this.lastBattleProgress = progress;
  10489. this.setAvgTime(start);
  10490. this.checkResult();
  10491. this.showResult();
  10492. this.updateProgressTimer();
  10493. this.timeout(this.loop.bind(this), 0);
  10494. }
  10495.  
  10496. isEndLoop() {
  10497. return this.count >= this.maxCount || this.endTime < Date.now();
  10498. }
  10499.  
  10500. updateProgressTimer(index = 0) {
  10501. this.lastTimer = this.isGetTimer ? this.getTimer() : this.randTimer();
  10502. this.battle.progress = [{ attackers: { input: ['auto', 0, 0, 'auto', index, this.lastTimer] } }];
  10503. }
  10504.  
  10505. showResult() {
  10506. console.log(
  10507. this.count,
  10508. this.avgTime.toFixed(2),
  10509. (this.endTime - Date.now()) / 1000,
  10510. this.lastTimer.toFixed(2),
  10511. this.lastBossDamage.toLocaleString(),
  10512. this.bestResult.value.toLocaleString()
  10513. );
  10514. }
  10515.  
  10516. checkResult() {
  10517. const { damageTaken, damageTakenNextLevel } = this.lastBattleProgress[0].defenders.heroes[1].extra;
  10518. this.lastBossDamage = damageTaken + damageTakenNextLevel;
  10519. if (this.lastBossDamage > this.bestResult.value) {
  10520. this.bestResult = {
  10521. count: this.count,
  10522. timer: this.lastTimer,
  10523. value: this.lastBossDamage,
  10524. result: structuredClone(this.lastBattleResult),
  10525. progress: structuredClone(this.lastBattleProgress),
  10526. };
  10527. }
  10528. }
  10529.  
  10530. stopFix() {
  10531. this.endTime = 0;
  10532. }
  10533. }
  10534.  
  10535. this.HWHClasses.FixBattle = FixBattle;
  10536.  
  10537. class WinFixBattle extends FixBattle {
  10538. checkResult() {
  10539. if (this.lastBattleResult.win) {
  10540. this.bestResult = {
  10541. count: this.count,
  10542. timer: this.lastTimer,
  10543. value: this.lastBattleResult.stars,
  10544. result: structuredClone(this.lastBattleResult),
  10545. progress: structuredClone(this.lastBattleProgress),
  10546. battleTimer: this.lastResult.battleTimer,
  10547. };
  10548. }
  10549. }
  10550.  
  10551. setWinTimer(value) {
  10552. this.winTimer = value;
  10553. }
  10554.  
  10555. setMaxTimer(value) {
  10556. this.maxTimer = value;
  10557. }
  10558.  
  10559. randTimer() {
  10560. if (this.winTimer) {
  10561. return this.winTimer;
  10562. }
  10563. return super.randTimer();
  10564. }
  10565.  
  10566. isEndLoop() {
  10567. return super.isEndLoop() || this.bestResult.result?.win;
  10568. }
  10569.  
  10570. showResult() {
  10571. console.log(
  10572. this.count,
  10573. this.avgTime.toFixed(2),
  10574. (this.endTime - Date.now()) / 1000,
  10575. this.lastResult.battleTime,
  10576. this.lastTimer,
  10577. this.bestResult.value
  10578. );
  10579. const endTime = ((this.endTime - Date.now()) / 1000).toFixed(2);
  10580. const avgTime = this.avgTime.toFixed(2);
  10581. const msg = `${I18N('LETS_FIX')} ${this.count}/${this.maxCount}<br/>${endTime}s<br/>${avgTime}ms`;
  10582. setProgress(msg, false, this.stopFix.bind(this));
  10583. }
  10584. }
  10585.  
  10586. this.HWHClasses.WinFixBattle = WinFixBattle;
  10587.  
  10588. class BestOrWinFixBattle extends WinFixBattle {
  10589. isNoMakeWin = false;
  10590.  
  10591. getState(result) {
  10592. let beforeSumFactor = 0;
  10593. const beforeHeroes = result.battleData.defenders[0];
  10594. for (let heroId in beforeHeroes) {
  10595. const hero = beforeHeroes[heroId];
  10596. const state = hero.state;
  10597. let factor = 1;
  10598. if (state) {
  10599. const hp = state.hp / (hero?.hp || 1);
  10600. const energy = state.energy / 1e3;
  10601. factor = hp + energy / 20;
  10602. }
  10603. beforeSumFactor += factor;
  10604. }
  10605.  
  10606. let afterSumFactor = 0;
  10607. const afterHeroes = result.progress[0].defenders.heroes;
  10608. for (let heroId in afterHeroes) {
  10609. const hero = afterHeroes[heroId];
  10610. const hp = hero.hp / (beforeHeroes[heroId]?.hp || 1);
  10611. const energy = hero.energy / 1e3;
  10612. const factor = hp + energy / 20;
  10613. afterSumFactor += factor;
  10614. }
  10615. return 100 - Math.floor((afterSumFactor / beforeSumFactor) * 1e4) / 100;
  10616. }
  10617.  
  10618. setNoMakeWin(value) {
  10619. this.isNoMakeWin = value;
  10620. }
  10621.  
  10622. checkResult() {
  10623. const state = this.getState(this.lastResult);
  10624. console.log(state);
  10625.  
  10626. if (state > this.bestResult.value) {
  10627. if (!(this.isNoMakeWin && this.lastBattleResult.win)) {
  10628. this.bestResult = {
  10629. count: this.count,
  10630. timer: this.lastTimer,
  10631. value: state,
  10632. result: structuredClone(this.lastBattleResult),
  10633. progress: structuredClone(this.lastBattleProgress),
  10634. battleTimer: this.lastResult.battleTimer,
  10635. };
  10636. }
  10637. }
  10638. }
  10639. }
  10640.  
  10641. this.HWHClasses.BestOrWinFixBattle = BestOrWinFixBattle;
  10642.  
  10643. class BossFixBattle extends FixBattle {
  10644. showResult() {
  10645. super.showResult();
  10646. //setTimeout(() => {
  10647. const best = this.bestResult;
  10648. const maxDmg = best.value.toLocaleString();
  10649. const avgTime = this.avgTime.toLocaleString();
  10650. const msg = `${I18N('LETS_FIX')} ${this.count}/${this.maxCount}<br/>${maxDmg}<br/>${avgTime}ms`;
  10651. setProgress(msg, false, this.stopFix.bind(this));
  10652. //}, 0);
  10653. }
  10654. }
  10655.  
  10656. this.HWHClasses.BossFixBattle = BossFixBattle;
  10657.  
  10658. class DungeonFixBattle extends FixBattle {
  10659. init() {
  10660. super.init();
  10661. this.isTimeout = false;
  10662. this.bestResult = {
  10663. count: 0,
  10664. timer: 0,
  10665. value: {
  10666. hp: -Infinity,
  10667. energy: -Infinity,
  10668. },
  10669. result: null,
  10670. progress: null,
  10671. };
  10672. }
  10673.  
  10674. setState() {
  10675. const result = this.lastResult;
  10676. const isAllDead = Object.values(result.progress[0].attackers.heroes).every((item) => item.isDead);
  10677. if (isAllDead) {
  10678. this.lastState = {
  10679. hp: -Infinity,
  10680. energy: -Infinity,
  10681. };
  10682. return;
  10683. }
  10684. let beforeHP = 0;
  10685. let beforeEnergy = 0;
  10686. const beforeTitans = result.battleData.attackers;
  10687. for (let titanId in beforeTitans) {
  10688. const titan = beforeTitans[titanId];
  10689. const state = titan.state;
  10690. if (state) {
  10691. beforeHP += state.hp / titan.hp;
  10692. beforeEnergy += state.energy / 1e3;
  10693. }
  10694. }
  10695.  
  10696. let afterHP = 0;
  10697. let afterEnergy = 0;
  10698. const afterTitans = result.progress[0].attackers.heroes;
  10699. for (let titanId in afterTitans) {
  10700. const titan = afterTitans[titanId];
  10701. afterHP += titan.hp / beforeTitans[titanId].hp;
  10702. afterEnergy += titan.energy / 1e3;
  10703. }
  10704.  
  10705. this.lastState = {
  10706. hp: afterHP - beforeHP,
  10707. energy: afterEnergy - beforeEnergy,
  10708. };
  10709. }
  10710.  
  10711. checkResult() {
  10712. this.setState();
  10713. if (
  10714. this.lastState.hp > this.bestResult.value.hp ||
  10715. (this.lastState.hp === this.bestResult.value.hp && this.lastState.energy > this.bestResult.value.energy)
  10716. ) {
  10717. this.bestResult = {
  10718. count: this.count,
  10719. timer: this.lastTimer,
  10720. value: this.lastState,
  10721. result: this.lastResult.result,
  10722. progress: this.lastResult.progress,
  10723. };
  10724. }
  10725. }
  10726.  
  10727. showResult() {
  10728. if (this.isShowResult) {
  10729. console.log(this.count, this.lastTimer.toFixed(2), JSON.stringify(this.lastState), JSON.stringify(this.bestResult.value));
  10730. }
  10731. }
  10732. }
  10733.  
  10734. this.HWHClasses.DungeonFixBattle = DungeonFixBattle;
  10735.  
  10736. const masterWsMixin = {
  10737. wsStart() {
  10738. const socket = new WebSocket(this.url);
  10739.  
  10740. socket.onopen = () => {
  10741. console.log('Connected to server');
  10742.  
  10743. // Пример создания новой задачи
  10744. const newTask = {
  10745. type: 'newTask',
  10746. battle: this.battle,
  10747. endTime: this.endTime - 1e4,
  10748. maxCount: this.maxCount,
  10749. };
  10750. socket.send(JSON.stringify(newTask));
  10751. };
  10752.  
  10753. socket.onmessage = this.onmessage.bind(this);
  10754.  
  10755. socket.onclose = () => {
  10756. console.log('Disconnected from server');
  10757. };
  10758.  
  10759. this.ws = socket;
  10760. },
  10761.  
  10762. onmessage(event) {
  10763. const data = JSON.parse(event.data);
  10764. switch (data.type) {
  10765. case 'newTask': {
  10766. console.log('newTask:', data);
  10767. this.id = data.id;
  10768. this.countExecutor = data.count;
  10769. break;
  10770. }
  10771. case 'getSolTask': {
  10772. console.log('getSolTask:', data);
  10773. this.endFix(data.solutions);
  10774. break;
  10775. }
  10776. case 'resolveTask': {
  10777. console.log('resolveTask:', data);
  10778. if (data.id === this.id && data.solutions.length === this.countExecutor) {
  10779. this.worker.terminate();
  10780. this.endFix(data.solutions);
  10781. }
  10782. break;
  10783. }
  10784. default:
  10785. console.log('Unknown message type:', data.type);
  10786. }
  10787. },
  10788.  
  10789. getTask() {
  10790. this.ws.send(
  10791. JSON.stringify({
  10792. type: 'getSolTask',
  10793. id: this.id,
  10794. })
  10795. );
  10796. },
  10797. };
  10798.  
  10799. /*
  10800. mFix = new action.masterFixBattle(battle)
  10801. await mFix.start(Date.now() + 6e4, 1);
  10802. */
  10803. class masterFixBattle extends FixBattle {
  10804. constructor(battle, url = 'wss://localho.st:3000') {
  10805. super(battle, true);
  10806. this.url = url;
  10807. }
  10808.  
  10809. async start(endTime, maxCount) {
  10810. this.endTime = endTime;
  10811. this.maxCount = maxCount;
  10812. this.init();
  10813. this.wsStart();
  10814. return await new Promise((resolve) => {
  10815. this.resolve = resolve;
  10816. const timeout = this.endTime - Date.now();
  10817. this.timeout(this.getTask.bind(this), timeout);
  10818. });
  10819. }
  10820.  
  10821. async endFix(solutions) {
  10822. this.ws.close();
  10823. let maxCount = 0;
  10824. for (const solution of solutions) {
  10825. maxCount += solution.maxCount;
  10826. if (solution.value > this.bestResult.value) {
  10827. this.bestResult = solution;
  10828. }
  10829. }
  10830. this.count = maxCount;
  10831. super.endFix();
  10832. }
  10833. }
  10834.  
  10835. Object.assign(masterFixBattle.prototype, masterWsMixin);
  10836.  
  10837. this.HWHClasses.masterFixBattle = masterFixBattle;
  10838.  
  10839. class masterWinFixBattle extends WinFixBattle {
  10840. constructor(battle, url = 'wss://localho.st:3000') {
  10841. super(battle, true);
  10842. this.url = url;
  10843. }
  10844.  
  10845. async start(endTime, maxCount) {
  10846. this.endTime = endTime;
  10847. this.maxCount = maxCount;
  10848. this.init();
  10849. this.wsStart();
  10850. return await new Promise((resolve) => {
  10851. this.resolve = resolve;
  10852. const timeout = this.endTime - Date.now();
  10853. this.timeout(this.getTask.bind(this), timeout);
  10854. });
  10855. }
  10856.  
  10857. async endFix(solutions) {
  10858. this.ws.close();
  10859. let maxCount = 0;
  10860. for (const solution of solutions) {
  10861. maxCount += solution.maxCount;
  10862. if (solution.value > this.bestResult.value) {
  10863. this.bestResult = solution;
  10864. }
  10865. }
  10866. this.count = maxCount;
  10867. super.endFix();
  10868. }
  10869. }
  10870.  
  10871. Object.assign(masterWinFixBattle.prototype, masterWsMixin);
  10872.  
  10873. this.HWHClasses.masterWinFixBattle = masterWinFixBattle;
  10874.  
  10875. const slaveWsMixin = {
  10876. wsStop() {
  10877. this.ws.close();
  10878. },
  10879.  
  10880. wsStart() {
  10881. const socket = new WebSocket(this.url);
  10882.  
  10883. socket.onopen = () => {
  10884. console.log('Connected to server');
  10885. };
  10886. socket.onmessage = this.onmessage.bind(this);
  10887. socket.onclose = () => {
  10888. console.log('Disconnected from server');
  10889. };
  10890.  
  10891. this.ws = socket;
  10892. },
  10893.  
  10894. async onmessage(event) {
  10895. const data = JSON.parse(event.data);
  10896. switch (data.type) {
  10897. case 'newTask': {
  10898. console.log('newTask:', data.task);
  10899. const { battle, endTime, maxCount } = data.task;
  10900. this.battle = battle;
  10901. const id = data.task.id;
  10902. const solution = await this.start(endTime, maxCount);
  10903. this.ws.send(
  10904. JSON.stringify({
  10905. type: 'resolveTask',
  10906. id,
  10907. solution,
  10908. })
  10909. );
  10910. break;
  10911. }
  10912. default:
  10913. console.log('Unknown message type:', data.type);
  10914. }
  10915. },
  10916. };
  10917. /*
  10918. sFix = new action.slaveFixBattle();
  10919. sFix.wsStart()
  10920. */
  10921. class slaveFixBattle extends FixBattle {
  10922. constructor(url = 'wss://localho.st:3000') {
  10923. super(null, false);
  10924. this.isTimeout = false;
  10925. this.url = url;
  10926. }
  10927. }
  10928.  
  10929. Object.assign(slaveFixBattle.prototype, slaveWsMixin);
  10930.  
  10931. this.HWHClasses.slaveFixBattle = slaveFixBattle;
  10932.  
  10933. class slaveWinFixBattle extends WinFixBattle {
  10934. constructor(url = 'wss://localho.st:3000') {
  10935. super(null, false);
  10936. this.isTimeout = false;
  10937. this.url = url;
  10938. }
  10939. }
  10940.  
  10941. Object.assign(slaveWinFixBattle.prototype, slaveWsMixin);
  10942.  
  10943. this.HWHClasses.slaveWinFixBattle = slaveWinFixBattle;
  10944. /**
  10945. * Auto-repeat attack
  10946. *
  10947. * Автоповтор атаки
  10948. */
  10949. function testAutoBattle() {
  10950. const { executeAutoBattle } = HWHClasses;
  10951. return new Promise((resolve, reject) => {
  10952. const bossBattle = new executeAutoBattle(resolve, reject);
  10953. bossBattle.start(lastBattleArg, lastBattleInfo);
  10954. });
  10955. }
  10956.  
  10957. /**
  10958. * Auto-repeat attack
  10959. *
  10960. * Автоповтор атаки
  10961. */
  10962. function executeAutoBattle(resolve, reject) {
  10963. let battleArg = {};
  10964. let countBattle = 0;
  10965. let countError = 0;
  10966. let findCoeff = 0;
  10967. let dataNotEeceived = 0;
  10968. let stopAutoBattle = false;
  10969.  
  10970. let isSetWinTimer = false;
  10971. const svgJustice = '<svg width="20" height="20" viewBox="0 0 124 125" xmlns="http://www.w3.org/2000/svg" style="fill: #fff;"><g><path d="m54 0h-1c-7.25 6.05-17.17 6.97-25.78 10.22-8.6 3.25-23.68 1.07-23.22 12.78s-0.47 24.08 1 35 2.36 18.36 7 28c4.43-8.31-3.26-18.88-3-30 0.26-11.11-2.26-25.29-1-37 11.88-4.16 26.27-0.42 36.77-9.23s20.53 6.05 29.23-0.77c-6.65-2.98-14.08-4.96-20-9z"/></g><g><path d="m108 5c-11.05 2.96-27.82 2.2-35.08 11.92s-14.91 14.71-22.67 23.33c-7.77 8.62-14.61 15.22-22.25 23.75 7.05 11.93 14.33 2.58 20.75-4.25 6.42-6.82 12.98-13.03 19.5-19.5s12.34-13.58 19.75-18.25c2.92 7.29-8.32 12.65-13.25 18.75-4.93 6.11-12.19 11.48-17.5 17.5s-12.31 11.38-17.25 17.75c10.34 14.49 17.06-3.04 26.77-10.23s15.98-16.89 26.48-24.52c10.5-7.64 12.09-24.46 14.75-36.25z"/></g><g><path d="m60 25c-11.52-6.74-24.53 8.28-38 6 0.84 9.61-1.96 20.2 2 29 5.53-4.04-4.15-23.2 4.33-26.67 8.48-3.48 18.14-1.1 24.67-8.33 2.73 0.3 4.81 2.98 7 0z"/></g><g><path d="m100 75c3.84-11.28 5.62-25.85 3-38-4.2 5.12-3.5 13.58-4 20s-3.52 13.18 1 18z"/></g><g><path d="m55 94c15.66-5.61 33.71-20.85 29-39-3.07 8.05-4.3 16.83-10.75 23.25s-14.76 8.35-18.25 15.75z"/></g><g><path d="m0 94v7c6.05 3.66 9.48 13.3 18 11-3.54-11.78 8.07-17.05 14-25 6.66 1.52 13.43 16.26 19 5-11.12-9.62-20.84-21.33-32-31-9.35 6.63 4.76 11.99 6 19-7.88 5.84-13.24 17.59-25 14z"/></g><g><path d="m82 125h26v-19h16v-1c-11.21-8.32-18.38-21.74-30-29-8.59 10.26-19.05 19.27-27 30h15v19z"/></g><g><path d="m68 110c-7.68-1.45-15.22 4.83-21.92-1.08s-11.94-5.72-18.08-11.92c-3.03 8.84 10.66 9.88 16.92 16.08s17.09 3.47 23.08-3.08z"/></g></svg>';
  10972. const svgBoss = '<svg width="20" height="20" viewBox="0 0 40 41" xmlns="http://www.w3.org/2000/svg" style="fill: #fff;"><g><path d="m21 12c-2.19-3.23 5.54-10.95-0.97-10.97-6.52-0.02 1.07 7.75-1.03 10.97-2.81 0.28-5.49-0.2-8-1-0.68 3.53 0.55 6.06 4 4 0.65 7.03 1.11 10.95 1.67 18.33 0.57 7.38 6.13 7.2 6.55-0.11 0.42-7.3 1.35-11.22 1.78-18.22 3.53 1.9 4.73-0.42 4-4-2.61 0.73-5.14 1.35-8 1m-1 17c-1.59-3.6-1.71-10.47 0-14 1.59 3.6 1.71 10.47 0 14z"/></g><g><path d="m6 19c-1.24-4.15 2.69-8.87 1-12-3.67 4.93-6.52 10.57-6 17 5.64-0.15 8.82 4.98 13 8 1.3-6.54-0.67-12.84-8-13z"/></g><g><path d="m33 7c0.38 5.57 2.86 14.79-7 15v10c4.13-2.88 7.55-7.97 13-8 0.48-6.46-2.29-12.06-6-17z"/></g></svg>';
  10973. const svgAttempt = '<svg width="20" height="20" viewBox="0 0 645 645" xmlns="http://www.w3.org/2000/svg" style="fill: #fff;"><g><path d="m442 26c-8.8 5.43-6.6 21.6-12.01 30.99-2.5 11.49-5.75 22.74-8.99 34.01-40.61-17.87-92.26-15.55-133.32-0.32-72.48 27.31-121.88 100.19-142.68 171.32 10.95-4.49 19.28-14.97 29.3-21.7 50.76-37.03 121.21-79.04 183.47-44.07 16.68 5.8 2.57 21.22-0.84 31.7-4.14 12.19-11.44 23.41-13.93 36.07 56.01-17.98 110.53-41.23 166-61-20.49-59.54-46.13-117.58-67-177z"/></g><g><path d="m563 547c23.89-16.34 36.1-45.65 47.68-71.32 23.57-62.18 7.55-133.48-28.38-186.98-15.1-22.67-31.75-47.63-54.3-63.7 1.15 14.03 6.71 26.8 8.22 40.78 12.08 61.99 15.82 148.76-48.15 183.29-10.46-0.54-15.99-16.1-24.32-22.82-8.2-7.58-14.24-19.47-23.75-24.25-4.88 59.04-11.18 117.71-15 177 62.9 5.42 126.11 9.6 189 15-4.84-9.83-17.31-15.4-24.77-24.23-9.02-7.06-17.8-15.13-26.23-22.77z"/></g><g><path d="m276 412c-10.69-15.84-30.13-25.9-43.77-40.23-15.39-12.46-30.17-25.94-45.48-38.52-15.82-11.86-29.44-28.88-46.75-37.25-19.07 24.63-39.96 48.68-60.25 72.75-18.71 24.89-42.41 47.33-58.75 73.25 22.4-2.87 44.99-13.6 66.67-13.67 0.06 22.8 10.69 42.82 20.41 62.59 49.09 93.66 166.6 114.55 261.92 96.08-6.07-9.2-22.11-9.75-31.92-16.08-59.45-26.79-138.88-75.54-127.08-151.92 21.66-2.39 43.42-4.37 65-7z"/></g></svg>';
  10974.  
  10975. this.start = function (battleArgs, battleInfo) {
  10976. battleArg = battleArgs;
  10977. if (nameFuncStartBattle == 'invasion_bossStart') {
  10978. startBattle();
  10979. return;
  10980. }
  10981. preCalcBattle(battleInfo);
  10982. }
  10983. /**
  10984. * Returns a promise for combat recalculation
  10985. *
  10986. * Возвращает промис для прерасчета боя
  10987. */
  10988. function getBattleInfo(battle) {
  10989. return new Promise(function (resolve) {
  10990. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  10991. Calc(battle).then(e => {
  10992. e.coeff = calcCoeff(e, 'defenders');
  10993. resolve(e);
  10994. });
  10995. });
  10996. }
  10997. /**
  10998. * Battle recalculation
  10999. *
  11000. * Прерасчет боя
  11001. */
  11002. function preCalcBattle(battle) {
  11003. let actions = [];
  11004. const countTestBattle = getInput('countTestBattle');
  11005. for (let i = 0; i < countTestBattle; i++) {
  11006. actions.push(getBattleInfo(battle));
  11007. }
  11008. Promise.all(actions)
  11009. .then(resultPreCalcBattle);
  11010. }
  11011. /**
  11012. * Processing the results of the battle recalculation
  11013. *
  11014. * Обработка результатов прерасчета боя
  11015. */
  11016. async function resultPreCalcBattle(results) {
  11017. let countWin = results.reduce((s, w) => w.result.win + s, 0);
  11018. setProgress(`${I18N('CHANCE_TO_WIN')} ${Math.floor(countWin / results.length * 100)}% (${results.length})`, false, hideProgress);
  11019. if (countWin > 0) {
  11020. setIsCancalBattle(false);
  11021. startBattle();
  11022. return;
  11023. }
  11024.  
  11025. let minCoeff = 100;
  11026. let maxCoeff = -100;
  11027. let avgCoeff = 0;
  11028. results.forEach(e => {
  11029. if (e.coeff < minCoeff) minCoeff = e.coeff;
  11030. if (e.coeff > maxCoeff) maxCoeff = e.coeff;
  11031. avgCoeff += e.coeff;
  11032. });
  11033. avgCoeff /= results.length;
  11034.  
  11035. if (nameFuncStartBattle == 'invasion_bossStart' ||
  11036. nameFuncStartBattle == 'bossAttack') {
  11037. const result = await popup.confirm(
  11038. I18N('BOSS_VICTORY_IMPOSSIBLE', { battles: results.length }), [
  11039. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  11040. { msg: I18N('BTN_DO_IT'), result: true },
  11041. ])
  11042. if (result) {
  11043. setIsCancalBattle(false);
  11044. startBattle();
  11045. return;
  11046. }
  11047. setProgress(I18N('NOT_THIS_TIME'), true);
  11048. endAutoBattle('invasion_bossStart');
  11049. return;
  11050. }
  11051.  
  11052. const result = await popup.confirm(
  11053. I18N('VICTORY_IMPOSSIBLE') +
  11054. `<br>${I18N('ROUND_STAT')} ${results.length} ${I18N('BATTLE')}:` +
  11055. `<br>${I18N('MINIMUM')}: ` + minCoeff.toLocaleString() +
  11056. `<br>${I18N('MAXIMUM')}: ` + maxCoeff.toLocaleString() +
  11057. `<br>${I18N('AVERAGE')}: ` + avgCoeff.toLocaleString() +
  11058. `<br>${I18N('FIND_COEFF')} ` + avgCoeff.toLocaleString(), [
  11059. { msg: I18N('BTN_CANCEL'), result: 0, isCancel: true },
  11060. { msg: I18N('BTN_GO'), isInput: true, default: Math.round(avgCoeff * 1000) / 1000 },
  11061. ])
  11062. if (result) {
  11063. findCoeff = result;
  11064. setIsCancalBattle(false);
  11065. startBattle();
  11066. return;
  11067. }
  11068. setProgress(I18N('NOT_THIS_TIME'), true);
  11069. endAutoBattle(I18N('NOT_THIS_TIME'));
  11070. }
  11071.  
  11072. /**
  11073. * Calculation of the combat result coefficient
  11074. *
  11075. * Расчет коэфициента результата боя
  11076. */
  11077. function calcCoeff(result, packType) {
  11078. let beforeSumFactor = 0;
  11079. const beforePack = result.battleData[packType][0];
  11080. for (let heroId in beforePack) {
  11081. const hero = beforePack[heroId];
  11082. const state = hero.state;
  11083. let factor = 1;
  11084. if (state) {
  11085. const hp = state.hp / state.maxHp;
  11086. const energy = state.energy / 1e3;
  11087. factor = hp + energy / 20;
  11088. }
  11089. beforeSumFactor += factor;
  11090. }
  11091.  
  11092. let afterSumFactor = 0;
  11093. const afterPack = result.progress[0][packType].heroes;
  11094. for (let heroId in afterPack) {
  11095. const hero = afterPack[heroId];
  11096. const stateHp = beforePack[heroId]?.state?.hp || beforePack[heroId]?.stats?.hp;
  11097. const hp = hero.hp / stateHp;
  11098. const energy = hero.energy / 1e3;
  11099. const factor = hp + energy / 20;
  11100. afterSumFactor += factor;
  11101. }
  11102. const resultCoeff = -(afterSumFactor - beforeSumFactor);
  11103. return Math.round(resultCoeff * 1000) / 1000;
  11104. }
  11105. /**
  11106. * Start battle
  11107. *
  11108. * Начало боя
  11109. */
  11110. function startBattle() {
  11111. countBattle++;
  11112. const countMaxBattle = getInput('countAutoBattle');
  11113. // setProgress(countBattle + '/' + countMaxBattle);
  11114. if (countBattle > countMaxBattle) {
  11115. setProgress(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`, true);
  11116. endAutoBattle(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`)
  11117. return;
  11118. }
  11119. if (stopAutoBattle) {
  11120. setProgress(I18N('STOPPED'), true);
  11121. endAutoBattle('STOPPED');
  11122. return;
  11123. }
  11124. send({calls: [{
  11125. name: nameFuncStartBattle,
  11126. args: battleArg,
  11127. ident: "body"
  11128. }]}, calcResultBattle);
  11129. }
  11130. /**
  11131. * Battle calculation
  11132. *
  11133. * Расчет боя
  11134. */
  11135. async function calcResultBattle(e) {
  11136. if (!e) {
  11137. console.log('данные не были получены');
  11138. if (dataNotEeceived < 10) {
  11139. dataNotEeceived++;
  11140. startBattle();
  11141. return;
  11142. }
  11143. endAutoBattle('Error', 'данные не были получены ' + dataNotEeceived + ' раз');
  11144. return;
  11145. }
  11146. if ('error' in e) {
  11147. if (e.error.description === 'too many tries') {
  11148. invasionTimer += 100;
  11149. countBattle--;
  11150. countError++;
  11151. console.log(`Errors: ${countError}`, e.error);
  11152. startBattle();
  11153. return;
  11154. }
  11155. const result = await popup.confirm(I18N('ERROR_DURING_THE_BATTLE') + '<br>' + e.error.description, [
  11156. { msg: I18N('BTN_OK'), result: false },
  11157. { msg: I18N('RELOAD_GAME'), result: true },
  11158. ]);
  11159. endAutoBattle('Error', e.error);
  11160. if (result) {
  11161. location.reload();
  11162. }
  11163. return;
  11164. }
  11165. let battle = e.results[0].result.response.battle
  11166. if (nameFuncStartBattle == 'towerStartBattle' ||
  11167. nameFuncStartBattle == 'bossAttack' ||
  11168. nameFuncStartBattle == 'invasion_bossStart') {
  11169. battle = e.results[0].result.response;
  11170. }
  11171. lastBattleInfo = battle;
  11172. BattleCalc(battle, getBattleType(battle.type), resultBattle);
  11173. }
  11174. /**
  11175. * Processing the results of the battle
  11176. *
  11177. * Обработка результатов боя
  11178. */
  11179. async function resultBattle(e) {
  11180. const isWin = e.result.win;
  11181. if (isWin) {
  11182. endBattle(e, false);
  11183. return;
  11184. } else if (isChecked('tryFixIt_v2')) {
  11185. const { WinFixBattle } = HWHClasses;
  11186. const cloneBattle = structuredClone(e.battleData);
  11187. const bFix = new WinFixBattle(cloneBattle);
  11188. let attempts = Infinity;
  11189. if (nameFuncStartBattle == 'invasion_bossStart' && !isSetWinTimer) {
  11190. let winTimer = await popup.confirm(`Secret number:`, [
  11191. { result: false, isClose: true },
  11192. { msg: 'Go', isInput: true, default: '0' },
  11193. ]);
  11194. winTimer = Number.parseFloat(winTimer);
  11195. if (winTimer) {
  11196. attempts = 5;
  11197. bFix.setWinTimer(winTimer);
  11198. }
  11199. isSetWinTimer = true;
  11200. }
  11201. let endTime = Date.now() + 6e4;
  11202. if (nameFuncStartBattle == 'invasion_bossStart') {
  11203. endTime = Date.now() + 6e4 * 4;
  11204. bFix.setMaxTimer(120.3);
  11205. }
  11206. const result = await bFix.start(endTime, attempts);
  11207. console.log(result);
  11208. if (result.result?.win) {
  11209. endBattle(result, false);
  11210. return;
  11211. }
  11212. }
  11213. const countMaxBattle = getInput('countAutoBattle');
  11214. if (findCoeff) {
  11215. const coeff = calcCoeff(e, 'defenders');
  11216. setProgress(`${countBattle}/${countMaxBattle}, ${coeff}`);
  11217. if (coeff > findCoeff) {
  11218. endBattle(e, false);
  11219. return;
  11220. }
  11221. } else {
  11222. if (nameFuncStartBattle == 'invasion_bossStart') {
  11223. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  11224. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageModAndEnergyIncrease_any_99_100_300_99_1000_300 || 0;
  11225. setProgress(`${svgBoss} ${bossLvl} ${svgJustice} ${justice} <br>${svgAttempt} ${countBattle}/${countMaxBattle}`, false, () => {
  11226. stopAutoBattle = true;
  11227. });
  11228. await new Promise((resolve) => setTimeout(resolve, 5000));
  11229. } else {
  11230. setProgress(`${countBattle}/${countMaxBattle}`);
  11231. }
  11232. }
  11233. if (nameFuncStartBattle == 'towerStartBattle' ||
  11234. nameFuncStartBattle == 'bossAttack' ||
  11235. nameFuncStartBattle == 'invasion_bossStart') {
  11236. startBattle();
  11237. return;
  11238. }
  11239. cancelEndBattle(e);
  11240. }
  11241. /**
  11242. * Cancel fight
  11243. *
  11244. * Отмена боя
  11245. */
  11246. function cancelEndBattle(r) {
  11247. const fixBattle = function (heroes) {
  11248. for (const ids in heroes) {
  11249. hero = heroes[ids];
  11250. hero.energy = random(1, 999);
  11251. if (hero.hp > 0) {
  11252. hero.hp = random(1, hero.hp);
  11253. }
  11254. }
  11255. }
  11256. fixBattle(r.progress[0].attackers.heroes);
  11257. fixBattle(r.progress[0].defenders.heroes);
  11258. endBattle(r, true);
  11259. }
  11260. /**
  11261. * End of the fight
  11262. *
  11263. * Завершение боя */
  11264. function endBattle(battleResult, isCancal) {
  11265. let calls = [{
  11266. name: nameFuncEndBattle,
  11267. args: {
  11268. result: battleResult.result,
  11269. progress: battleResult.progress
  11270. },
  11271. ident: "body"
  11272. }];
  11273.  
  11274. if (nameFuncStartBattle == 'invasion_bossStart') {
  11275. calls[0].args.id = lastBattleArg.id;
  11276. }
  11277.  
  11278. send(JSON.stringify({
  11279. calls
  11280. }), async e => {
  11281. console.log(e);
  11282. if (isCancal) {
  11283. startBattle();
  11284. return;
  11285. }
  11286.  
  11287. setProgress(`${I18N('SUCCESS')}!`, 5000)
  11288. if (nameFuncStartBattle == 'invasion_bossStart' ||
  11289. nameFuncStartBattle == 'bossAttack') {
  11290. const countMaxBattle = getInput('countAutoBattle');
  11291. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  11292. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageModAndEnergyIncrease_any_99_100_300_99_1000_300 || 0;
  11293. let winTimer = '';
  11294. if (nameFuncStartBattle == 'invasion_bossStart') {
  11295. winTimer = '<br>Secret number: ' + battleResult.progress[0].attackers.input[5];
  11296. }
  11297. const result = await popup.confirm(
  11298. I18N('BOSS_HAS_BEEN_DEF_TEXT', {
  11299. bossLvl: `${svgBoss} ${bossLvl} ${svgJustice} ${justice}`,
  11300. countBattle: svgAttempt + ' ' + countBattle,
  11301. countMaxBattle,
  11302. winTimer,
  11303. }),
  11304. [
  11305. { msg: I18N('BTN_OK'), result: 0 },
  11306. { msg: I18N('MAKE_A_SYNC'), result: 1 },
  11307. { msg: I18N('RELOAD_GAME'), result: 2 },
  11308. ]
  11309. );
  11310. if (result) {
  11311. if (result == 1) {
  11312. cheats.refreshGame();
  11313. }
  11314. if (result == 2) {
  11315. location.reload();
  11316. }
  11317. }
  11318.  
  11319. }
  11320. endAutoBattle(`${I18N('SUCCESS')}!`)
  11321. });
  11322. }
  11323. /**
  11324. * Completing a task
  11325. *
  11326. * Завершение задачи
  11327. */
  11328. function endAutoBattle(reason, info) {
  11329. setIsCancalBattle(true);
  11330. console.log(reason, info);
  11331. resolve();
  11332. }
  11333. }
  11334.  
  11335. this.HWHClasses.executeAutoBattle = executeAutoBattle;
  11336.  
  11337. function testDailyQuests() {
  11338. const { dailyQuests } = HWHClasses;
  11339. return new Promise((resolve, reject) => {
  11340. const quests = new dailyQuests(resolve, reject);
  11341. quests.init(questsInfo);
  11342. quests.start();
  11343. });
  11344. }
  11345.  
  11346. /**
  11347. * Automatic completion of daily quests
  11348. *
  11349. * Автоматическое выполнение ежедневных квестов
  11350. */
  11351. class dailyQuests {
  11352. /**
  11353. * Send(' {"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}').then(e => console.log(e))
  11354. * Send(' {"calls":[{"name":"heroGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  11355. * Send(' {"calls":[{"name":"titanGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  11356. * Send(' {"calls":[{"name":"inventoryGet","args":{},"ident":"body"}]}').then(e => console.log(e))
  11357. * Send(' {"calls":[{"name":"questGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  11358. * Send(' {"calls":[{"name":"bossGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  11359. */
  11360. callsList = ['userGetInfo', 'heroGetAll', 'titanGetAll', 'inventoryGet', 'questGetAll', 'bossGetAll', 'missionGetAll'];
  11361.  
  11362. dataQuests = {
  11363. 10001: {
  11364. description: 'Улучши умения героев 3 раза', // ++++++++++++++++
  11365. doItCall: () => {
  11366. const upgradeSkills = this.getUpgradeSkills();
  11367. return upgradeSkills.map(({ heroId, skill }, index) => ({
  11368. name: 'heroUpgradeSkill',
  11369. args: { heroId, skill },
  11370. ident: `heroUpgradeSkill_${index}`,
  11371. }));
  11372. },
  11373. isWeCanDo: () => {
  11374. const upgradeSkills = this.getUpgradeSkills();
  11375. let sumGold = 0;
  11376. for (const skill of upgradeSkills) {
  11377. sumGold += this.skillCost(skill.value);
  11378. if (!skill.heroId) {
  11379. return false;
  11380. }
  11381. }
  11382. return this.questInfo['userGetInfo'].gold > sumGold;
  11383. },
  11384. },
  11385. 10002: {
  11386. description: 'Пройди 10 миссий', // --------------
  11387. isWeCanDo: () => false,
  11388. },
  11389. 10003: {
  11390. description: 'Пройди 3 героические миссии', // ++++++++++++++++
  11391. isWeCanDo: () => {
  11392. const vipPoints = +this.questInfo.userGetInfo.vipPoints;
  11393. const goldTicket = !!this.questInfo.inventoryGet.consumable[151];
  11394. return (vipPoints > 100 || goldTicket) && this.getHeroicMissionId();
  11395. },
  11396. doItCall: () => {
  11397. const selectedMissionId = this.getHeroicMissionId();
  11398. const goldTicket = !!this.questInfo.inventoryGet.consumable[151];
  11399. const vipLevel = Math.max(...lib.data.level.vip.filter(l => l.vipPoints <= +this.questInfo.userGetInfo.vipPoints).map(l => l.level));
  11400. // Возвращаем массив команд для рейда
  11401. if (vipLevel >= 5 || goldTicket) {
  11402. return [{ name: 'missionRaid', args: { id: selectedMissionId, times: 3 }, ident: 'missionRaid_1' }];
  11403. } else {
  11404. return [
  11405. { name: 'missionRaid', args: { id: selectedMissionId, times: 1 }, ident: 'missionRaid_1' },
  11406. { name: 'missionRaid', args: { id: selectedMissionId, times: 1 }, ident: 'missionRaid_2' },
  11407. { name: 'missionRaid', args: { id: selectedMissionId, times: 1 }, ident: 'missionRaid_3' },
  11408. ];
  11409. }
  11410. },
  11411. },
  11412. 10004: {
  11413. description: 'Сразись 3 раза на Арене или Гранд Арене', // --------------
  11414. isWeCanDo: () => false,
  11415. },
  11416. 10006: {
  11417. description: 'Используй обмен изумрудов 1 раз', // ++++++++++++++++
  11418. doItCall: () => [
  11419. {
  11420. name: 'refillableAlchemyUse',
  11421. args: { multi: false },
  11422. ident: 'refillableAlchemyUse',
  11423. },
  11424. ],
  11425. isWeCanDo: () => {
  11426. const starMoney = this.questInfo['userGetInfo'].starMoney;
  11427. return starMoney >= 20;
  11428. },
  11429. },
  11430. 10007: {
  11431. description: 'Соверши 1 призыв в Атриуме Душ', // ++++++++++++++++
  11432. doItCall: () => [{ name: 'gacha_open', args: { ident: 'heroGacha', free: true, pack: false }, ident: 'gacha_open' }],
  11433. isWeCanDo: () => {
  11434. const soulCrystal = this.questInfo['inventoryGet'].coin[38];
  11435. return soulCrystal > 0;
  11436. },
  11437. },
  11438. 10016: {
  11439. description: 'Отправь подарки согильдийцам', // ++++++++++++++++
  11440. doItCall: () => [{ name: 'clanSendDailyGifts', args: {}, ident: 'clanSendDailyGifts' }],
  11441. isWeCanDo: () => true,
  11442. },
  11443. 10018: {
  11444. description: 'Используй зелье опыта', // ++++++++++++++++
  11445. doItCall: () => {
  11446. const expHero = this.getExpHero();
  11447. return [
  11448. {
  11449. name: 'consumableUseHeroXp',
  11450. args: {
  11451. heroId: expHero.heroId,
  11452. libId: expHero.libId,
  11453. amount: 1,
  11454. },
  11455. ident: 'consumableUseHeroXp',
  11456. },
  11457. ];
  11458. },
  11459. isWeCanDo: () => {
  11460. const expHero = this.getExpHero();
  11461. return expHero.heroId && expHero.libId;
  11462. },
  11463. },
  11464. 10019: {
  11465. description: 'Открой 1 сундук в Башне',
  11466. doItFunc: testTower,
  11467. isWeCanDo: () => false,
  11468. },
  11469. 10020: {
  11470. description: 'Открой 3 сундука в Запределье', // Готово
  11471. doItCall: () => {
  11472. return this.getOutlandChest();
  11473. },
  11474. isWeCanDo: () => {
  11475. const outlandChest = this.getOutlandChest();
  11476. return outlandChest.length > 0;
  11477. },
  11478. },
  11479. 10021: {
  11480. description: 'Собери 75 Титанита в Подземелье Гильдии',
  11481. isWeCanDo: () => false,
  11482. },
  11483. 10022: {
  11484. description: 'Собери 150 Титанита в Подземелье Гильдии',
  11485. doItFunc: testDungeon,
  11486. isWeCanDo: () => false,
  11487. },
  11488. 10023: {
  11489. description: 'Прокачай Дар Стихий на 1 уровень', // Готово
  11490. doItCall: () => {
  11491. const heroId = this.getHeroIdTitanGift();
  11492. return [
  11493. { name: 'heroTitanGiftLevelUp', args: { heroId }, ident: 'heroTitanGiftLevelUp' },
  11494. { name: 'heroTitanGiftDrop', args: { heroId }, ident: 'heroTitanGiftDrop' },
  11495. ];
  11496. },
  11497. isWeCanDo: () => {
  11498. const heroId = this.getHeroIdTitanGift();
  11499. return heroId;
  11500. },
  11501. },
  11502. 10024: {
  11503. description: 'Повысь уровень любого артефакта один раз', // Готово
  11504. doItCall: () => {
  11505. const upArtifact = this.getUpgradeArtifact();
  11506. return [
  11507. {
  11508. name: 'heroArtifactLevelUp',
  11509. args: {
  11510. heroId: upArtifact.heroId,
  11511. slotId: upArtifact.slotId,
  11512. },
  11513. ident: `heroArtifactLevelUp`,
  11514. },
  11515. ];
  11516. },
  11517. isWeCanDo: () => {
  11518. const upgradeArtifact = this.getUpgradeArtifact();
  11519. return upgradeArtifact.heroId;
  11520. },
  11521. },
  11522. 10025: {
  11523. description: 'Начни 1 Экспедицию',
  11524. doItFunc: checkExpedition,
  11525. isWeCanDo: () => false,
  11526. },
  11527. 10026: {
  11528. description: 'Начни 4 Экспедиции', // --------------
  11529. doItFunc: checkExpedition,
  11530. isWeCanDo: () => false,
  11531. },
  11532. 10027: {
  11533. description: 'Победи в 1 бою Турнира Стихий',
  11534. doItFunc: testTitanArena,
  11535. isWeCanDo: () => false,
  11536. },
  11537. 10028: {
  11538. description: 'Повысь уровень любого артефакта титанов', // Готово
  11539. doItCall: () => {
  11540. const upTitanArtifact = this.getUpgradeTitanArtifact();
  11541. return [
  11542. {
  11543. name: 'titanArtifactLevelUp',
  11544. args: {
  11545. titanId: upTitanArtifact.titanId,
  11546. slotId: upTitanArtifact.slotId,
  11547. },
  11548. ident: `titanArtifactLevelUp`,
  11549. },
  11550. ];
  11551. },
  11552. isWeCanDo: () => {
  11553. const upgradeTitanArtifact = this.getUpgradeTitanArtifact();
  11554. return upgradeTitanArtifact.titanId;
  11555. },
  11556. },
  11557. 10029: {
  11558. description: 'Открой сферу артефактов титанов', // ++++++++++++++++
  11559. doItCall: () => [{ name: 'titanArtifactChestOpen', args: { amount: 1, free: true }, ident: 'titanArtifactChestOpen' }],
  11560. isWeCanDo: () => {
  11561. return this.questInfo['inventoryGet']?.consumable[55] > 0;
  11562. },
  11563. },
  11564. 10030: {
  11565. description: 'Улучши облик любого героя 1 раз', // Готово
  11566. doItCall: () => {
  11567. const upSkin = this.getUpgradeSkin();
  11568. return [
  11569. {
  11570. name: 'heroSkinUpgrade',
  11571. args: {
  11572. heroId: upSkin.heroId,
  11573. skinId: upSkin.skinId,
  11574. },
  11575. ident: `heroSkinUpgrade`,
  11576. },
  11577. ];
  11578. },
  11579. isWeCanDo: () => {
  11580. const upgradeSkin = this.getUpgradeSkin();
  11581. return upgradeSkin.heroId;
  11582. },
  11583. },
  11584. 10031: {
  11585. description: 'Победи в 6 боях Турнира Стихий', // --------------
  11586. doItFunc: testTitanArena,
  11587. isWeCanDo: () => false,
  11588. },
  11589. 10043: {
  11590. description: 'Начни или присоеденись к Приключению', // --------------
  11591. isWeCanDo: () => false,
  11592. },
  11593. 10044: {
  11594. description: 'Воспользуйся призывом питомцев 1 раз', // ++++++++++++++++
  11595. doItCall: () => [{ name: 'pet_chestOpen', args: { amount: 1, paid: false }, ident: 'pet_chestOpen' }],
  11596. isWeCanDo: () => {
  11597. return this.questInfo['inventoryGet']?.consumable[90] > 0;
  11598. },
  11599. },
  11600. 10046: {
  11601. /**
  11602. * TODO: Watch Adventure
  11603. * TODO: Смотреть приключение
  11604. */
  11605. description: 'Открой 3 сундука в Приключениях',
  11606. isWeCanDo: () => false,
  11607. },
  11608. 10047: {
  11609. description: 'Набери 150 очков активности в Гильдии', // Готово
  11610. doItCall: () => {
  11611. const enchantRune = this.getEnchantRune();
  11612. return [
  11613. {
  11614. name: 'heroEnchantRune',
  11615. args: {
  11616. heroId: enchantRune.heroId,
  11617. tier: enchantRune.tier,
  11618. items: {
  11619. consumable: { [enchantRune.itemId]: 1 },
  11620. },
  11621. },
  11622. ident: `heroEnchantRune`,
  11623. },
  11624. ];
  11625. },
  11626. isWeCanDo: () => {
  11627. const userInfo = this.questInfo['userGetInfo'];
  11628. const enchantRune = this.getEnchantRune();
  11629. return enchantRune.heroId && userInfo.gold > 1e3;
  11630. },
  11631. },
  11632. };
  11633.  
  11634. constructor(resolve, reject, questInfo) {
  11635. this.resolve = resolve;
  11636. this.reject = reject;
  11637. }
  11638.  
  11639. init(questInfo) {
  11640. this.questInfo = questInfo;
  11641. this.isAuto = false;
  11642. }
  11643.  
  11644. async autoInit(isAuto) {
  11645. this.isAuto = isAuto || false;
  11646. const quests = {};
  11647. const calls = this.callsList.map((name) => ({
  11648. name,
  11649. args: {},
  11650. ident: name,
  11651. }));
  11652. const result = await Send(JSON.stringify({ calls })).then((e) => e.results);
  11653. for (const call of result) {
  11654. quests[call.ident] = call.result.response;
  11655. }
  11656. this.questInfo = quests;
  11657. }
  11658.  
  11659. async start() {
  11660. const weCanDo = [];
  11661. const selectedActions = getSaveVal('selectedActions', {});
  11662. for (let quest of this.questInfo['questGetAll']) {
  11663. if (quest.id in this.dataQuests && quest.state == 1) {
  11664. if (!selectedActions[quest.id]) {
  11665. selectedActions[quest.id] = {
  11666. checked: false,
  11667. };
  11668. }
  11669.  
  11670. const isWeCanDo = this.dataQuests[quest.id].isWeCanDo;
  11671. if (!isWeCanDo.call(this)) {
  11672. continue;
  11673. }
  11674.  
  11675. weCanDo.push({
  11676. name: quest.id,
  11677. label: I18N(`QUEST_${quest.id}`),
  11678. checked: selectedActions[quest.id].checked,
  11679. });
  11680. }
  11681. }
  11682.  
  11683. if (!weCanDo.length) {
  11684. this.end(I18N('NOTHING_TO_DO'));
  11685. return;
  11686. }
  11687.  
  11688. console.log(weCanDo);
  11689. let taskList = [];
  11690. if (this.isAuto) {
  11691. taskList = weCanDo;
  11692. } else {
  11693. const answer = await popup.confirm(
  11694. `${I18N('YOU_CAN_COMPLETE')}:`,
  11695. [
  11696. { msg: I18N('BTN_DO_IT'), result: true },
  11697. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  11698. ],
  11699. weCanDo
  11700. );
  11701. if (!answer) {
  11702. this.end('');
  11703. return;
  11704. }
  11705. taskList = popup.getCheckBoxes();
  11706. taskList.forEach((e) => {
  11707. selectedActions[e.name].checked = e.checked;
  11708. });
  11709. setSaveVal('selectedActions', selectedActions);
  11710. }
  11711.  
  11712. const calls = [];
  11713. let countChecked = 0;
  11714. for (const task of taskList) {
  11715. if (task.checked) {
  11716. countChecked++;
  11717. const quest = this.dataQuests[task.name];
  11718. console.log(quest.description);
  11719.  
  11720. if (quest.doItCall) {
  11721. const doItCall = quest.doItCall.call(this);
  11722. calls.push(...doItCall);
  11723. }
  11724. }
  11725. }
  11726.  
  11727. if (!countChecked) {
  11728. this.end(I18N('NOT_QUEST_COMPLETED'));
  11729. return;
  11730. }
  11731.  
  11732. const result = await Send(JSON.stringify({ calls }));
  11733. if (result.error) {
  11734. console.error(result.error, result.error.call);
  11735. }
  11736. this.end(`${I18N('COMPLETED_QUESTS')}: ${countChecked}`);
  11737. }
  11738.  
  11739. errorHandling(error) {
  11740. //console.error(error);
  11741. let errorInfo = error.toString() + '\n';
  11742. try {
  11743. const errorStack = error.stack.split('\n');
  11744. const endStack = errorStack.map((e) => e.split('@')[0]).indexOf('testDoYourBest');
  11745. errorInfo += errorStack.slice(0, endStack).join('\n');
  11746. } catch (e) {
  11747. errorInfo += error.stack;
  11748. }
  11749. copyText(errorInfo);
  11750. }
  11751.  
  11752. skillCost(lvl) {
  11753. return 573 * lvl ** 0.9 + lvl ** 2.379;
  11754. }
  11755.  
  11756. getUpgradeSkills() {
  11757. const heroes = Object.values(this.questInfo['heroGetAll']);
  11758. const upgradeSkills = [
  11759. { heroId: 0, slotId: 0, value: 130 },
  11760. { heroId: 0, slotId: 0, value: 130 },
  11761. { heroId: 0, slotId: 0, value: 130 },
  11762. ];
  11763. const skillLib = lib.getData('skill');
  11764. /**
  11765. * color - 1 (белый) открывает 1 навык
  11766. * color - 2 (зеленый) открывает 2 навык
  11767. * color - 4 (синий) открывает 3 навык
  11768. * color - 7 (фиолетовый) открывает 4 навык
  11769. */
  11770. const colors = [1, 2, 4, 7];
  11771. for (const hero of heroes) {
  11772. const level = hero.level;
  11773. const color = hero.color;
  11774. for (let skillId in hero.skills) {
  11775. const tier = skillLib[skillId].tier;
  11776. const sVal = hero.skills[skillId];
  11777. if (color < colors[tier] || tier < 1 || tier > 4) {
  11778. continue;
  11779. }
  11780. for (let upSkill of upgradeSkills) {
  11781. if (sVal < upSkill.value && sVal < level) {
  11782. upSkill.value = sVal;
  11783. upSkill.heroId = hero.id;
  11784. upSkill.skill = tier;
  11785. break;
  11786. }
  11787. }
  11788. }
  11789. }
  11790. return upgradeSkills;
  11791. }
  11792.  
  11793. getUpgradeArtifact() {
  11794. const heroes = Object.values(this.questInfo['heroGetAll']);
  11795. const inventory = this.questInfo['inventoryGet'];
  11796. const upArt = { heroId: 0, slotId: 0, level: 100 };
  11797.  
  11798. const heroLib = lib.getData('hero');
  11799. const artifactLib = lib.getData('artifact');
  11800.  
  11801. for (const hero of heroes) {
  11802. const heroInfo = heroLib[hero.id];
  11803. const level = hero.level;
  11804. if (level < 20) {
  11805. continue;
  11806. }
  11807.  
  11808. for (let slotId in hero.artifacts) {
  11809. const art = hero.artifacts[slotId];
  11810. /* Текущая звезданость арта */
  11811. const star = art.star;
  11812. if (!star) {
  11813. continue;
  11814. }
  11815. /* Текущий уровень арта */
  11816. const level = art.level;
  11817. if (level >= 100) {
  11818. continue;
  11819. }
  11820. /* Идентификатор арта в библиотеке */
  11821. const artifactId = heroInfo.artifacts[slotId];
  11822. const artInfo = artifactLib.id[artifactId];
  11823. const costNextLevel = artifactLib.type[artInfo.type].levels[level + 1].cost;
  11824.  
  11825. const costCurrency = Object.keys(costNextLevel).pop();
  11826. const costValues = Object.entries(costNextLevel[costCurrency]).pop();
  11827. const costId = costValues[0];
  11828. const costValue = +costValues[1];
  11829.  
  11830. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  11831. if (level < upArt.level && inventory[costCurrency][costId] >= costValue) {
  11832. upArt.level = level;
  11833. upArt.heroId = hero.id;
  11834. upArt.slotId = slotId;
  11835. upArt.costCurrency = costCurrency;
  11836. upArt.costId = costId;
  11837. upArt.costValue = costValue;
  11838. }
  11839. }
  11840. }
  11841. return upArt;
  11842. }
  11843.  
  11844. getUpgradeSkin() {
  11845. const heroes = Object.values(this.questInfo['heroGetAll']);
  11846. const inventory = this.questInfo['inventoryGet'];
  11847. const upSkin = { heroId: 0, skinId: 0, level: 60, cost: 1500 };
  11848.  
  11849. const skinLib = lib.getData('skin');
  11850.  
  11851. for (const hero of heroes) {
  11852. const level = hero.level;
  11853. if (level < 20) {
  11854. continue;
  11855. }
  11856.  
  11857. for (let skinId in hero.skins) {
  11858. /* Текущий уровень скина */
  11859. const level = hero.skins[skinId];
  11860. if (level >= 60) {
  11861. continue;
  11862. }
  11863. /* Идентификатор скина в библиотеке */
  11864. const skinInfo = skinLib[skinId];
  11865. if (!skinInfo.statData.levels?.[level + 1]) {
  11866. continue;
  11867. }
  11868. const costNextLevel = skinInfo.statData.levels[level + 1].cost;
  11869.  
  11870. const costCurrency = Object.keys(costNextLevel).pop();
  11871. const costCurrencyId = Object.keys(costNextLevel[costCurrency]).pop();
  11872. const costValue = +costNextLevel[costCurrency][costCurrencyId];
  11873.  
  11874. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  11875. if (level < upSkin.level && costValue < upSkin.cost && inventory[costCurrency][costCurrencyId] >= costValue) {
  11876. upSkin.cost = costValue;
  11877. upSkin.level = level;
  11878. upSkin.heroId = hero.id;
  11879. upSkin.skinId = skinId;
  11880. upSkin.costCurrency = costCurrency;
  11881. upSkin.costCurrencyId = costCurrencyId;
  11882. }
  11883. }
  11884. }
  11885. return upSkin;
  11886. }
  11887.  
  11888. getUpgradeTitanArtifact() {
  11889. const titans = Object.values(this.questInfo['titanGetAll']);
  11890. const inventory = this.questInfo['inventoryGet'];
  11891. const userInfo = this.questInfo['userGetInfo'];
  11892. const upArt = { titanId: 0, slotId: 0, level: 120 };
  11893.  
  11894. const titanLib = lib.getData('titan');
  11895. const artTitanLib = lib.getData('titanArtifact');
  11896.  
  11897. for (const titan of titans) {
  11898. const titanInfo = titanLib[titan.id];
  11899. // const level = titan.level
  11900. // if (level < 20) {
  11901. // continue;
  11902. // }
  11903.  
  11904. for (let slotId in titan.artifacts) {
  11905. const art = titan.artifacts[slotId];
  11906. /* Текущая звезданость арта */
  11907. const star = art.star;
  11908. if (!star) {
  11909. continue;
  11910. }
  11911. /* Текущий уровень арта */
  11912. const level = art.level;
  11913. if (level >= 120) {
  11914. continue;
  11915. }
  11916. /* Идентификатор арта в библиотеке */
  11917. const artifactId = titanInfo.artifacts[slotId];
  11918. const artInfo = artTitanLib.id[artifactId];
  11919. const costNextLevel = artTitanLib.type[artInfo.type].levels[level + 1].cost;
  11920.  
  11921. const costCurrency = Object.keys(costNextLevel).pop();
  11922. let costValue = 0;
  11923. let currentValue = 0;
  11924. if (costCurrency == 'gold') {
  11925. costValue = costNextLevel[costCurrency];
  11926. currentValue = userInfo.gold;
  11927. } else {
  11928. const costValues = Object.entries(costNextLevel[costCurrency]).pop();
  11929. const costId = costValues[0];
  11930. costValue = +costValues[1];
  11931. currentValue = inventory[costCurrency][costId];
  11932. }
  11933.  
  11934. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  11935. if (level < upArt.level && currentValue >= costValue) {
  11936. upArt.level = level;
  11937. upArt.titanId = titan.id;
  11938. upArt.slotId = slotId;
  11939. break;
  11940. }
  11941. }
  11942. }
  11943. return upArt;
  11944. }
  11945.  
  11946. getEnchantRune() {
  11947. const heroes = Object.values(this.questInfo['heroGetAll']);
  11948. const inventory = this.questInfo['inventoryGet'];
  11949. const enchRune = { heroId: 0, tier: 0, exp: 43750, itemId: 0 };
  11950. for (let i = 1; i <= 4; i++) {
  11951. if (inventory.consumable[i] > 0) {
  11952. enchRune.itemId = i;
  11953. break;
  11954. }
  11955. return enchRune;
  11956. }
  11957.  
  11958. const runeLib = lib.getData('rune');
  11959. const runeLvls = Object.values(runeLib.level);
  11960. /**
  11961. * color - 4 (синий) открывает 1 и 2 символ
  11962. * color - 7 (фиолетовый) открывает 3 символ
  11963. * color - 8 (фиолетовый +1) открывает 4 символ
  11964. * color - 9 (фиолетовый +2) открывает 5 символ
  11965. */
  11966. // TODO: кажется надо учесть уровень команды
  11967. const colors = [4, 4, 7, 8, 9];
  11968. for (const hero of heroes) {
  11969. const color = hero.color;
  11970.  
  11971. for (let runeTier in hero.runes) {
  11972. /* Проверка на доступность руны */
  11973. if (color < colors[runeTier]) {
  11974. continue;
  11975. }
  11976. /* Текущий опыт руны */
  11977. const exp = hero.runes[runeTier];
  11978. if (exp >= 43750) {
  11979. continue;
  11980. }
  11981.  
  11982. let level = 0;
  11983. if (exp) {
  11984. for (let lvl of runeLvls) {
  11985. if (exp >= lvl.enchantValue) {
  11986. level = lvl.level;
  11987. } else {
  11988. break;
  11989. }
  11990. }
  11991. }
  11992. /** Уровень героя необходимый для уровня руны */
  11993. const heroLevel = runeLib.level[level].heroLevel;
  11994. if (hero.level < heroLevel) {
  11995. continue;
  11996. }
  11997.  
  11998. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  11999. if (exp < enchRune.exp) {
  12000. enchRune.exp = exp;
  12001. enchRune.heroId = hero.id;
  12002. enchRune.tier = runeTier;
  12003. break;
  12004. }
  12005. }
  12006. }
  12007. return enchRune;
  12008. }
  12009.  
  12010. getOutlandChest() {
  12011. const bosses = this.questInfo['bossGetAll'];
  12012.  
  12013. const calls = [];
  12014.  
  12015. for (let boss of bosses) {
  12016. if (boss.mayRaid) {
  12017. calls.push({
  12018. name: 'bossRaid',
  12019. args: {
  12020. bossId: boss.id,
  12021. },
  12022. ident: 'bossRaid_' + boss.id,
  12023. });
  12024. calls.push({
  12025. name: 'bossOpenChest',
  12026. args: {
  12027. bossId: boss.id,
  12028. amount: 1,
  12029. starmoney: 0,
  12030. },
  12031. ident: 'bossOpenChest_' + boss.id,
  12032. });
  12033. } else if (boss.chestId == 1) {
  12034. calls.push({
  12035. name: 'bossOpenChest',
  12036. args: {
  12037. bossId: boss.id,
  12038. amount: 1,
  12039. starmoney: 0,
  12040. },
  12041. ident: 'bossOpenChest_' + boss.id,
  12042. });
  12043. }
  12044. }
  12045.  
  12046. return calls;
  12047. }
  12048.  
  12049. getExpHero() {
  12050. const heroes = Object.values(this.questInfo['heroGetAll']);
  12051. const inventory = this.questInfo['inventoryGet'];
  12052. const expHero = { heroId: 0, exp: 3625195, libId: 0 };
  12053. /** зелья опыта (consumable 9, 10, 11, 12) */
  12054. for (let i = 9; i <= 12; i++) {
  12055. if (inventory.consumable[i]) {
  12056. expHero.libId = i;
  12057. break;
  12058. }
  12059. }
  12060.  
  12061. for (const hero of heroes) {
  12062. const exp = hero.xp;
  12063. if (exp < expHero.exp) {
  12064. expHero.heroId = hero.id;
  12065. }
  12066. }
  12067. return expHero;
  12068. }
  12069.  
  12070. getHeroIdTitanGift() {
  12071. const heroes = Object.values(this.questInfo['heroGetAll']);
  12072. const inventory = this.questInfo['inventoryGet'];
  12073. const user = this.questInfo['userGetInfo'];
  12074. const titanGiftLib = lib.getData('titanGift');
  12075. /** Искры */
  12076. const titanGift = inventory.consumable[24];
  12077. let heroId = 0;
  12078. let minLevel = 30;
  12079.  
  12080. if (titanGift < 250 || user.gold < 7000) {
  12081. return 0;
  12082. }
  12083.  
  12084. for (const hero of heroes) {
  12085. if (hero.titanGiftLevel >= 30) {
  12086. continue;
  12087. }
  12088.  
  12089. if (!hero.titanGiftLevel) {
  12090. return hero.id;
  12091. }
  12092.  
  12093. const cost = titanGiftLib[hero.titanGiftLevel].cost;
  12094. if (minLevel > hero.titanGiftLevel && titanGift >= cost.consumable[24] && user.gold >= cost.gold) {
  12095. minLevel = hero.titanGiftLevel;
  12096. heroId = hero.id;
  12097. }
  12098. }
  12099.  
  12100. return heroId;
  12101. }
  12102.  
  12103. getHeroicMissionId() {
  12104. // Получаем доступные миссии с 3 звездами
  12105. const availableMissionsToRaid = Object.values(this.questInfo.missionGetAll)
  12106. .filter((mission) => mission.stars === 3)
  12107. .map((mission) => mission.id);
  12108.  
  12109. // Получаем героев для улучшения, у которых меньше 6 звезд
  12110. const heroesToUpgrade = Object.values(this.questInfo.heroGetAll)
  12111. .filter((hero) => hero.star < 6)
  12112. .sort((a, b) => b.power - a.power)
  12113. .map((hero) => hero.id);
  12114.  
  12115. // Получаем героические миссии, которые доступны для рейдов
  12116. const heroicMissions = Object.values(lib.data.mission).filter((mission) => mission.isHeroic && availableMissionsToRaid.includes(mission.id));
  12117.  
  12118. // Собираем дропы из героических миссий
  12119. const drops = heroicMissions.map((mission) => {
  12120. const lastWave = mission.normalMode.waves[mission.normalMode.waves.length - 1];
  12121. const allRewards = lastWave.enemies[lastWave.enemies.length - 1]
  12122. .drop.map((drop) => drop.reward);
  12123.  
  12124. const heroId = +Object.keys(allRewards.find((reward) => reward.fragmentHero).fragmentHero).pop();
  12125.  
  12126. return { id: mission.id, heroId };
  12127. });
  12128.  
  12129. // Определяем, какие дропы подходят для героев, которых нужно улучшить
  12130. const heroDrops = heroesToUpgrade.map((heroId) => drops.find((drop) => drop.heroId == heroId)).filter((drop) => drop);
  12131. const firstMission = heroDrops[0];
  12132. // Выбираем миссию для рейда
  12133. const selectedMissionId = firstMission ? firstMission.id : 1;
  12134.  
  12135. const stamina = this.questInfo.userGetInfo.refillable.find((x) => x.id == 1).amount;
  12136. const costMissions = 3 * lib.data.mission[selectedMissionId].normalMode.teamExp;
  12137. if (stamina < costMissions) {
  12138. console.log('Энергии не достаточно');
  12139. return 0;
  12140. }
  12141. return selectedMissionId;
  12142. }
  12143.  
  12144. end(status) {
  12145. setProgress(status, true);
  12146. this.resolve();
  12147. }
  12148. }
  12149.  
  12150. this.questRun = dailyQuests;
  12151. this.HWHClasses.dailyQuests = dailyQuests;
  12152.  
  12153. function testDoYourBest() {
  12154. const { doYourBest } = HWHClasses;
  12155. return new Promise((resolve, reject) => {
  12156. const doIt = new doYourBest(resolve, reject);
  12157. doIt.start();
  12158. });
  12159. }
  12160.  
  12161. /**
  12162. * Do everything button
  12163. *
  12164. * Кнопка сделать все
  12165. */
  12166. class doYourBest {
  12167.  
  12168. funcList = [
  12169. {
  12170. name: 'getOutland',
  12171. label: I18N('ASSEMBLE_OUTLAND'),
  12172. checked: false
  12173. },
  12174. {
  12175. name: 'testTower',
  12176. label: I18N('PASS_THE_TOWER'),
  12177. checked: false
  12178. },
  12179. {
  12180. name: 'checkExpedition',
  12181. label: I18N('CHECK_EXPEDITIONS'),
  12182. checked: false
  12183. },
  12184. {
  12185. name: 'testTitanArena',
  12186. label: I18N('COMPLETE_TOE'),
  12187. checked: false
  12188. },
  12189. {
  12190. name: 'mailGetAll',
  12191. label: I18N('COLLECT_MAIL'),
  12192. checked: false
  12193. },
  12194. {
  12195. name: 'collectAllStuff',
  12196. label: I18N('COLLECT_MISC'),
  12197. title: I18N('COLLECT_MISC_TITLE'),
  12198. checked: false
  12199. },
  12200. {
  12201. name: 'getDailyBonus',
  12202. label: I18N('DAILY_BONUS'),
  12203. checked: false
  12204. },
  12205. {
  12206. name: 'dailyQuests',
  12207. label: I18N('DO_DAILY_QUESTS'),
  12208. checked: false
  12209. },
  12210. {
  12211. name: 'rollAscension',
  12212. label: I18N('SEER_TITLE'),
  12213. checked: false
  12214. },
  12215. {
  12216. name: 'questAllFarm',
  12217. label: I18N('COLLECT_QUEST_REWARDS'),
  12218. checked: false
  12219. },
  12220. {
  12221. name: 'testDungeon',
  12222. label: I18N('COMPLETE_DUNGEON'),
  12223. checked: false
  12224. },
  12225. {
  12226. name: 'synchronization',
  12227. label: I18N('MAKE_A_SYNC'),
  12228. checked: false
  12229. },
  12230. {
  12231. name: 'reloadGame',
  12232. label: I18N('RELOAD_GAME'),
  12233. checked: false
  12234. },
  12235. ];
  12236.  
  12237. functions = {
  12238. getOutland,
  12239. testTower,
  12240. checkExpedition,
  12241. testTitanArena,
  12242. mailGetAll,
  12243. collectAllStuff: async () => {
  12244. await offerFarmAllReward();
  12245. await Send('{"calls":[{"name":"subscriptionFarm","args":{},"ident":"body"},{"name":"zeppelinGiftFarm","args":{},"ident":"zeppelinGiftFarm"},{"name":"grandFarmCoins","args":{},"ident":"grandFarmCoins"},{"name":"gacha_refill","args":{"ident":"heroGacha"},"ident":"gacha_refill"}]}');
  12246. },
  12247. dailyQuests: async function () {
  12248. const quests = new dailyQuests(() => { }, () => { });
  12249. await quests.autoInit(true);
  12250. await quests.start();
  12251. },
  12252. rollAscension,
  12253. getDailyBonus,
  12254. questAllFarm,
  12255. testDungeon,
  12256. synchronization: async () => {
  12257. cheats.refreshGame();
  12258. },
  12259. reloadGame: async () => {
  12260. location.reload();
  12261. },
  12262. }
  12263.  
  12264. constructor(resolve, reject, questInfo) {
  12265. this.resolve = resolve;
  12266. this.reject = reject;
  12267. this.questInfo = questInfo
  12268. }
  12269.  
  12270. async start() {
  12271. const selectedDoIt = getSaveVal('selectedDoIt', {});
  12272.  
  12273. this.funcList.forEach(task => {
  12274. if (!selectedDoIt[task.name]) {
  12275. selectedDoIt[task.name] = {
  12276. checked: task.checked
  12277. }
  12278. } else {
  12279. task.checked = selectedDoIt[task.name].checked
  12280. }
  12281. });
  12282.  
  12283. const answer = await popup.confirm(I18N('RUN_FUNCTION'), [
  12284. { msg: I18N('BTN_CANCEL'), result: false, isCancel: true },
  12285. { msg: I18N('BTN_GO'), result: true },
  12286. ], this.funcList);
  12287.  
  12288. if (!answer) {
  12289. this.end('');
  12290. return;
  12291. }
  12292.  
  12293. const taskList = popup.getCheckBoxes();
  12294. taskList.forEach(task => {
  12295. selectedDoIt[task.name].checked = task.checked;
  12296. });
  12297. setSaveVal('selectedDoIt', selectedDoIt);
  12298. for (const task of popup.getCheckBoxes()) {
  12299. if (task.checked) {
  12300. try {
  12301. setProgress(`${task.label} <br>${I18N('PERFORMED')}!`);
  12302. await this.functions[task.name]();
  12303. setProgress(`${task.label} <br>${I18N('DONE')}!`);
  12304. } catch (error) {
  12305. if (await popup.confirm(`${I18N('ERRORS_OCCURRES')}:<br> ${task.label} <br>${I18N('COPY_ERROR')}?`, [
  12306. { msg: I18N('BTN_NO'), result: false },
  12307. { msg: I18N('BTN_YES'), result: true },
  12308. ])) {
  12309. this.errorHandling(error);
  12310. }
  12311. }
  12312. }
  12313. }
  12314. setTimeout((msg) => {
  12315. this.end(msg);
  12316. }, 2000, I18N('ALL_TASK_COMPLETED'));
  12317. return;
  12318. }
  12319.  
  12320. errorHandling(error) {
  12321. //console.error(error);
  12322. let errorInfo = error.toString() + '\n';
  12323. try {
  12324. const errorStack = error.stack.split('\n');
  12325. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testDoYourBest");
  12326. errorInfo += errorStack.slice(0, endStack).join('\n');
  12327. } catch (e) {
  12328. errorInfo += error.stack;
  12329. }
  12330. copyText(errorInfo);
  12331. }
  12332.  
  12333. end(status) {
  12334. setProgress(status, true);
  12335. this.resolve();
  12336. }
  12337. }
  12338.  
  12339. this.HWHClasses.doYourBest = doYourBest;
  12340.  
  12341. /**
  12342. * Passing the adventure along the specified route
  12343. *
  12344. * Прохождение приключения по указанному маршруту
  12345. */
  12346. function testAdventure(type) {
  12347. const { executeAdventure } = HWHClasses;
  12348. return new Promise((resolve, reject) => {
  12349. const bossBattle = new executeAdventure(resolve, reject);
  12350. bossBattle.start(type);
  12351. });
  12352. }
  12353.  
  12354. /**
  12355. * Passing the adventure along the specified route
  12356. *
  12357. * Прохождение приключения по указанному маршруту
  12358. */
  12359. class executeAdventure {
  12360.  
  12361. type = 'default';
  12362.  
  12363. actions = {
  12364. default: {
  12365. getInfo: "adventure_getInfo",
  12366. startBattle: 'adventure_turnStartBattle',
  12367. endBattle: 'adventure_endBattle',
  12368. collectBuff: 'adventure_turnCollectBuff'
  12369. },
  12370. solo: {
  12371. getInfo: "adventureSolo_getInfo",
  12372. startBattle: 'adventureSolo_turnStartBattle',
  12373. endBattle: 'adventureSolo_endBattle',
  12374. collectBuff: 'adventureSolo_turnCollectBuff'
  12375. }
  12376. }
  12377.  
  12378. terminatеReason = I18N('UNKNOWN');
  12379. callAdventureInfo = {
  12380. name: "adventure_getInfo",
  12381. args: {},
  12382. ident: "adventure_getInfo"
  12383. }
  12384. callTeamGetAll = {
  12385. name: "teamGetAll",
  12386. args: {},
  12387. ident: "teamGetAll"
  12388. }
  12389. callTeamGetFavor = {
  12390. name: "teamGetFavor",
  12391. args: {},
  12392. ident: "teamGetFavor"
  12393. }
  12394. callStartBattle = {
  12395. name: "adventure_turnStartBattle",
  12396. args: {},
  12397. ident: "body"
  12398. }
  12399. callEndBattle = {
  12400. name: "adventure_endBattle",
  12401. args: {
  12402. result: {},
  12403. progress: {},
  12404. },
  12405. ident: "body"
  12406. }
  12407. callCollectBuff = {
  12408. name: "adventure_turnCollectBuff",
  12409. args: {},
  12410. ident: "body"
  12411. }
  12412.  
  12413. constructor(resolve, reject) {
  12414. this.resolve = resolve;
  12415. this.reject = reject;
  12416. }
  12417.  
  12418. async start(type) {
  12419. this.type = type || this.type;
  12420. this.callAdventureInfo.name = this.actions[this.type].getInfo;
  12421. const data = await Send(JSON.stringify({
  12422. calls: [
  12423. this.callAdventureInfo,
  12424. this.callTeamGetAll,
  12425. this.callTeamGetFavor
  12426. ]
  12427. }));
  12428. return this.checkAdventureInfo(data.results);
  12429. }
  12430.  
  12431. async getPath() {
  12432. const oldVal = getSaveVal('adventurePath', '');
  12433. const keyPath = `adventurePath:${this.mapIdent}`;
  12434. const answer = await popup.confirm(I18N('ENTER_THE_PATH'), [
  12435. {
  12436. msg: I18N('START_ADVENTURE'),
  12437. placeholder: '1,2,3,4,5,6',
  12438. isInput: true,
  12439. default: getSaveVal(keyPath, oldVal)
  12440. },
  12441. {
  12442. msg: I18N('BTN_CANCEL'),
  12443. result: false,
  12444. isCancel: true
  12445. },
  12446. ]);
  12447. if (!answer) {
  12448. this.terminatеReason = I18N('BTN_CANCELED');
  12449. return false;
  12450. }
  12451.  
  12452. let path = answer.split(',');
  12453. if (path.length < 2) {
  12454. path = answer.split('-');
  12455. }
  12456. if (path.length < 2) {
  12457. this.terminatеReason = I18N('MUST_TWO_POINTS');
  12458. return false;
  12459. }
  12460.  
  12461. for (let p in path) {
  12462. path[p] = +path[p].trim()
  12463. if (Number.isNaN(path[p])) {
  12464. this.terminatеReason = I18N('MUST_ONLY_NUMBERS');
  12465. return false;
  12466. }
  12467. }
  12468.  
  12469. if (!this.checkPath(path)) {
  12470. return false;
  12471. }
  12472. setSaveVal(keyPath, answer);
  12473. return path;
  12474. }
  12475.  
  12476. checkPath(path) {
  12477. for (let i = 0; i < path.length - 1; i++) {
  12478. const currentPoint = path[i];
  12479. const nextPoint = path[i + 1];
  12480.  
  12481. const isValidPath = this.paths.some(p =>
  12482. (p.from_id === currentPoint && p.to_id === nextPoint) ||
  12483. (p.from_id === nextPoint && p.to_id === currentPoint)
  12484. );
  12485.  
  12486. if (!isValidPath) {
  12487. this.terminatеReason = I18N('INCORRECT_WAY', {
  12488. from: currentPoint,
  12489. to: nextPoint,
  12490. });
  12491. return false;
  12492. }
  12493. }
  12494.  
  12495. return true;
  12496. }
  12497.  
  12498. async checkAdventureInfo(data) {
  12499. this.advInfo = data[0].result.response;
  12500. if (!this.advInfo) {
  12501. this.terminatеReason = I18N('NOT_ON_AN_ADVENTURE') ;
  12502. return this.end();
  12503. }
  12504. const heroesTeam = data[1].result.response.adventure_hero;
  12505. const favor = data[2]?.result.response.adventure_hero;
  12506. const heroes = heroesTeam.slice(0, 5);
  12507. const pet = heroesTeam[5];
  12508. this.args = {
  12509. pet,
  12510. heroes,
  12511. favor,
  12512. path: [],
  12513. broadcast: false
  12514. }
  12515. const advUserInfo = this.advInfo.users[userInfo.id];
  12516. this.turnsLeft = advUserInfo.turnsLeft;
  12517. this.currentNode = advUserInfo.currentNode;
  12518. this.nodes = this.advInfo.nodes;
  12519. this.paths = this.advInfo.paths;
  12520. this.mapIdent = this.advInfo.mapIdent;
  12521.  
  12522. this.path = await this.getPath();
  12523. if (!this.path) {
  12524. return this.end();
  12525. }
  12526.  
  12527. if (this.currentNode == 1 && this.path[0] != 1) {
  12528. this.path.unshift(1);
  12529. }
  12530.  
  12531. return this.loop();
  12532. }
  12533.  
  12534. async loop() {
  12535. const position = this.path.indexOf(+this.currentNode);
  12536. if (!(~position)) {
  12537. this.terminatеReason = I18N('YOU_IN_NOT_ON_THE_WAY');
  12538. return this.end();
  12539. }
  12540. this.path = this.path.slice(position);
  12541. if ((this.path.length - 1) > this.turnsLeft &&
  12542. await popup.confirm(I18N('ATTEMPTS_NOT_ENOUGH'), [
  12543. { msg: I18N('YES_CONTINUE'), result: false },
  12544. { msg: I18N('BTN_NO'), result: true },
  12545. ])) {
  12546. this.terminatеReason = I18N('NOT_ENOUGH_AP');
  12547. return this.end();
  12548. }
  12549. const toPath = [];
  12550. for (const nodeId of this.path) {
  12551. if (!this.turnsLeft) {
  12552. this.terminatеReason = I18N('ATTEMPTS_ARE_OVER');
  12553. return this.end();
  12554. }
  12555. toPath.push(nodeId);
  12556. console.log(toPath);
  12557. if (toPath.length > 1) {
  12558. setProgress(toPath.join(' > ') + ` ${I18N('MOVES')}: ` + this.turnsLeft);
  12559. }
  12560. if (nodeId == this.currentNode) {
  12561. continue;
  12562. }
  12563.  
  12564. const nodeInfo = this.getNodeInfo(nodeId);
  12565. if (nodeInfo.type == 'TYPE_COMBAT') {
  12566. if (nodeInfo.state == 'empty') {
  12567. this.turnsLeft--;
  12568. continue;
  12569. }
  12570.  
  12571. /**
  12572. * Disable regular battle cancellation
  12573. *
  12574. * Отключаем штатную отменую боя
  12575. */
  12576. setIsCancalBattle(false);
  12577. if (await this.battle(toPath)) {
  12578. this.turnsLeft--;
  12579. toPath.splice(0, toPath.indexOf(nodeId));
  12580. nodeInfo.state = 'empty';
  12581. setIsCancalBattle(true);
  12582. continue;
  12583. }
  12584. setIsCancalBattle(true);
  12585. return this.end()
  12586. }
  12587.  
  12588. if (nodeInfo.type == 'TYPE_PLAYERBUFF') {
  12589. const buff = this.checkBuff(nodeInfo);
  12590. if (buff == null) {
  12591. continue;
  12592. }
  12593.  
  12594. if (await this.collectBuff(buff, toPath)) {
  12595. this.turnsLeft--;
  12596. toPath.splice(0, toPath.indexOf(nodeId));
  12597. continue;
  12598. }
  12599. this.terminatеReason = I18N('BUFF_GET_ERROR');
  12600. return this.end();
  12601. }
  12602. }
  12603. this.terminatеReason = I18N('SUCCESS');
  12604. return this.end();
  12605. }
  12606.  
  12607. /**
  12608. * Carrying out a fight
  12609. *
  12610. * Проведение боя
  12611. */
  12612. async battle(path, preCalc = true) {
  12613. const data = await this.startBattle(path);
  12614. try {
  12615. const battle = data.results[0].result.response.battle;
  12616. let result = await Calc(battle);
  12617.  
  12618. if (!result.result.win && isChecked('tryFixIt_v2')) {
  12619. const cloneBattle = structuredClone(battle);
  12620. const bFix = new WinFixBattle(cloneBattle);
  12621. const endTime = Date.now() + 3e4; // 30 sec
  12622. const fixResult = await bFix.start(endTime, 500);
  12623. console.log(fixResult);
  12624. if (fixResult.result?.win) {
  12625. result = fixResult;
  12626. }
  12627. }
  12628.  
  12629. if (result.result.win) {
  12630. const info = await this.endBattle(result);
  12631. if (info.results[0].result.response?.error) {
  12632. this.terminatеReason = I18N('BATTLE_END_ERROR');
  12633. return false;
  12634. }
  12635. } else {
  12636. await this.cancelBattle(result);
  12637.  
  12638. if (preCalc && await this.preCalcBattle(battle)) {
  12639. path = path.slice(-2);
  12640. for (let i = 1; i <= getInput('countAutoBattle'); i++) {
  12641. setProgress(`${I18N('AUTOBOT')}: ${i}/${getInput('countAutoBattle')}`);
  12642. const result = await this.battle(path, false);
  12643. if (result) {
  12644. setProgress(I18N('VICTORY'));
  12645. return true;
  12646. }
  12647. }
  12648. this.terminatеReason = I18N('FAILED_TO_WIN_AUTO');
  12649. return false;
  12650. }
  12651. return false;
  12652. }
  12653. } catch (error) {
  12654. console.error(error);
  12655. if (await popup.confirm(I18N('ERROR_OF_THE_BATTLE_COPY'), [
  12656. { msg: I18N('BTN_NO'), result: false },
  12657. { msg: I18N('BTN_YES'), result: true },
  12658. ])) {
  12659. this.errorHandling(error, data);
  12660. }
  12661. this.terminatеReason = I18N('ERROR_DURING_THE_BATTLE');
  12662. return false;
  12663. }
  12664. return true;
  12665. }
  12666.  
  12667. /**
  12668. * Recalculate battles
  12669. *
  12670. * Прерасчтет битвы
  12671. */
  12672. async preCalcBattle(battle) {
  12673. const countTestBattle = getInput('countTestBattle');
  12674. for (let i = 0; i < countTestBattle; i++) {
  12675. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  12676. const result = await Calc(battle);
  12677. if (result.result.win) {
  12678. console.log(i, countTestBattle);
  12679. return true;
  12680. }
  12681. }
  12682. this.terminatеReason = I18N('NO_CHANCE_WIN') + countTestBattle;
  12683. return false;
  12684. }
  12685.  
  12686. /**
  12687. * Starts a fight
  12688. *
  12689. * Начинает бой
  12690. */
  12691. startBattle(path) {
  12692. this.args.path = path;
  12693. this.callStartBattle.name = this.actions[this.type].startBattle;
  12694. this.callStartBattle.args = this.args
  12695. const calls = [this.callStartBattle];
  12696. return Send(JSON.stringify({ calls }));
  12697. }
  12698.  
  12699. cancelBattle(battle) {
  12700. const fixBattle = function (heroes) {
  12701. for (const ids in heroes) {
  12702. const hero = heroes[ids];
  12703. hero.energy = random(1, 999);
  12704. if (hero.hp > 0) {
  12705. hero.hp = random(1, hero.hp);
  12706. }
  12707. }
  12708. }
  12709. fixBattle(battle.progress[0].attackers.heroes);
  12710. fixBattle(battle.progress[0].defenders.heroes);
  12711. return this.endBattle(battle);
  12712. }
  12713.  
  12714. /**
  12715. * Ends the fight
  12716. *
  12717. * Заканчивает бой
  12718. */
  12719. endBattle(battle) {
  12720. this.callEndBattle.name = this.actions[this.type].endBattle;
  12721. this.callEndBattle.args.result = battle.result
  12722. this.callEndBattle.args.progress = battle.progress
  12723. const calls = [this.callEndBattle];
  12724. return Send(JSON.stringify({ calls }));
  12725. }
  12726.  
  12727. /**
  12728. * Checks if you can get a buff
  12729. *
  12730. * Проверяет можно ли получить баф
  12731. */
  12732. checkBuff(nodeInfo) {
  12733. let id = null;
  12734. let value = 0;
  12735. for (const buffId in nodeInfo.buffs) {
  12736. const buff = nodeInfo.buffs[buffId];
  12737. if (buff.owner == null && buff.value > value) {
  12738. id = buffId;
  12739. value = buff.value;
  12740. }
  12741. }
  12742. nodeInfo.buffs[id].owner = 'Я';
  12743. return id;
  12744. }
  12745.  
  12746. /**
  12747. * Collects a buff
  12748. *
  12749. * Собирает баф
  12750. */
  12751. async collectBuff(buff, path) {
  12752. this.callCollectBuff.name = this.actions[this.type].collectBuff;
  12753. this.callCollectBuff.args = { buff, path };
  12754. const calls = [this.callCollectBuff];
  12755. return Send(JSON.stringify({ calls }));
  12756. }
  12757.  
  12758. getNodeInfo(nodeId) {
  12759. return this.nodes.find(node => node.id == nodeId);
  12760. }
  12761.  
  12762. errorHandling(error, data) {
  12763. //console.error(error);
  12764. let errorInfo = error.toString() + '\n';
  12765. try {
  12766. const errorStack = error.stack.split('\n');
  12767. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testAdventure");
  12768. errorInfo += errorStack.slice(0, endStack).join('\n');
  12769. } catch (e) {
  12770. errorInfo += error.stack;
  12771. }
  12772. if (data) {
  12773. errorInfo += '\nData: ' + JSON.stringify(data);
  12774. }
  12775. copyText(errorInfo);
  12776. }
  12777.  
  12778. end() {
  12779. setIsCancalBattle(true);
  12780. setProgress(this.terminatеReason, true);
  12781. console.log(this.terminatеReason);
  12782. this.resolve();
  12783. }
  12784. }
  12785.  
  12786. this.HWHClasses.executeAdventure = executeAdventure;
  12787.  
  12788. /**
  12789. * Passage of brawls
  12790. *
  12791. * Прохождение потасовок
  12792. */
  12793. function testBrawls(isAuto) {
  12794. const { executeBrawls } = HWHClasses;
  12795. return new Promise((resolve, reject) => {
  12796. const brawls = new executeBrawls(resolve, reject);
  12797. brawls.start(brawlsPack, isAuto);
  12798. });
  12799. }
  12800. /**
  12801. * Passage of brawls
  12802. *
  12803. * Прохождение потасовок
  12804. */
  12805. class executeBrawls {
  12806. callBrawlQuestGetInfo = {
  12807. name: "brawl_questGetInfo",
  12808. args: {},
  12809. ident: "brawl_questGetInfo"
  12810. }
  12811. callBrawlFindEnemies = {
  12812. name: "brawl_findEnemies",
  12813. args: {},
  12814. ident: "brawl_findEnemies"
  12815. }
  12816. callBrawlQuestFarm = {
  12817. name: "brawl_questFarm",
  12818. args: {},
  12819. ident: "brawl_questFarm"
  12820. }
  12821. callUserGetInfo = {
  12822. name: "userGetInfo",
  12823. args: {},
  12824. ident: "userGetInfo"
  12825. }
  12826. callTeamGetMaxUpgrade = {
  12827. name: "teamGetMaxUpgrade",
  12828. args: {},
  12829. ident: "teamGetMaxUpgrade"
  12830. }
  12831. callBrawlGetInfo = {
  12832. name: "brawl_getInfo",
  12833. args: {},
  12834. ident: "brawl_getInfo"
  12835. }
  12836.  
  12837. stats = {
  12838. win: 0,
  12839. loss: 0,
  12840. count: 0,
  12841. }
  12842.  
  12843. stage = {
  12844. '3': 1,
  12845. '7': 2,
  12846. '12': 3,
  12847. }
  12848.  
  12849. attempts = 0;
  12850.  
  12851. constructor(resolve, reject) {
  12852. this.resolve = resolve;
  12853. this.reject = reject;
  12854.  
  12855. const allHeroIds = Object.keys(lib.getData('hero'));
  12856. this.callTeamGetMaxUpgrade.args.units = {
  12857. hero: allHeroIds.filter((id) => +id < 1000),
  12858. titan: allHeroIds.filter((id) => +id >= 4000 && +id < 4100),
  12859. pet: allHeroIds.filter((id) => +id >= 6000 && +id < 6100),
  12860. };
  12861. }
  12862.  
  12863. async start(args, isAuto) {
  12864. this.isAuto = isAuto;
  12865. this.args = args;
  12866. setIsCancalBattle(false);
  12867. this.brawlInfo = await this.getBrawlInfo();
  12868. this.attempts = this.brawlInfo.attempts;
  12869.  
  12870. if (!this.attempts && !this.info.boughtEndlessLivesToday) {
  12871. this.end(I18N('DONT_HAVE_LIVES'));
  12872. return;
  12873. }
  12874.  
  12875. while (1) {
  12876. if (!isBrawlsAutoStart) {
  12877. this.end(I18N('BTN_CANCELED'));
  12878. return;
  12879. }
  12880.  
  12881. const maxStage = this.brawlInfo.questInfo.stage;
  12882. const stage = this.stage[maxStage];
  12883. const progress = this.brawlInfo.questInfo.progress;
  12884.  
  12885. setProgress(
  12886. `${I18N('STAGE')} ${stage}: ${progress}/${maxStage}<br>${I18N('FIGHTS')}: ${this.stats.count}<br>${I18N('WINS')}: ${
  12887. this.stats.win
  12888. }<br>${I18N('LOSSES')}: ${this.stats.loss}<br>${I18N('LIVES')}: ${this.attempts}<br>${I18N('STOP')}`,
  12889. false,
  12890. function () {
  12891. isBrawlsAutoStart = false;
  12892. }
  12893. );
  12894.  
  12895. if (this.brawlInfo.questInfo.canFarm) {
  12896. const result = await this.questFarm();
  12897. console.log(result);
  12898. }
  12899.  
  12900. if (!this.continueAttack && this.brawlInfo.questInfo.stage == 12 && this.brawlInfo.questInfo.progress == 12) {
  12901. if (
  12902. await popup.confirm(I18N('BRAWL_DAILY_TASK_COMPLETED'), [
  12903. { msg: I18N('BTN_NO'), result: true },
  12904. { msg: I18N('BTN_YES'), result: false },
  12905. ])
  12906. ) {
  12907. this.end(I18N('SUCCESS'));
  12908. return;
  12909. } else {
  12910. this.continueAttack = true;
  12911. }
  12912. }
  12913.  
  12914. if (!this.attempts && !this.info.boughtEndlessLivesToday) {
  12915. this.end(I18N('DONT_HAVE_LIVES'));
  12916. return;
  12917. }
  12918.  
  12919. const enemie = Object.values(this.brawlInfo.findEnemies).shift();
  12920.  
  12921. // Автоматический подбор пачки
  12922. if (this.isAuto) {
  12923. if (this.mandatoryId <= 4000 && this.mandatoryId != 13) {
  12924. this.end(I18N('BRAWL_AUTO_PACK_NOT_CUR_HERO'));
  12925. return;
  12926. }
  12927. if (this.mandatoryId >= 4000 && this.mandatoryId < 4100) {
  12928. this.args = await this.updateTitanPack(enemie.heroes);
  12929. } else if (this.mandatoryId < 4000 && this.mandatoryId == 13) {
  12930. this.args = await this.updateHeroesPack(enemie.heroes);
  12931. }
  12932. }
  12933.  
  12934. const result = await this.battle(enemie.userId);
  12935. this.brawlInfo = {
  12936. questInfo: result[1].result.response,
  12937. findEnemies: result[2].result.response,
  12938. };
  12939. }
  12940. }
  12941.  
  12942. async updateTitanPack(enemieHeroes) {
  12943. const packs = [
  12944. [4033, 4040, 4041, 4042, 4043],
  12945. [4032, 4040, 4041, 4042, 4043],
  12946. [4031, 4040, 4041, 4042, 4043],
  12947. [4030, 4040, 4041, 4042, 4043],
  12948. [4032, 4033, 4040, 4042, 4043],
  12949. [4030, 4033, 4041, 4042, 4043],
  12950. [4031, 4033, 4040, 4042, 4043],
  12951. [4032, 4033, 4040, 4041, 4043],
  12952. [4023, 4040, 4041, 4042, 4043],
  12953. [4030, 4033, 4040, 4042, 4043],
  12954. [4031, 4033, 4040, 4041, 4043],
  12955. [4022, 4040, 4041, 4042, 4043],
  12956. [4030, 4033, 4040, 4041, 4043],
  12957. [4021, 4040, 4041, 4042, 4043],
  12958. [4020, 4040, 4041, 4042, 4043],
  12959. [4023, 4033, 4040, 4042, 4043],
  12960. [4030, 4032, 4033, 4042, 4043],
  12961. [4023, 4033, 4040, 4041, 4043],
  12962. [4031, 4032, 4033, 4040, 4043],
  12963. [4030, 4032, 4033, 4041, 4043],
  12964. [4030, 4031, 4033, 4042, 4043],
  12965. [4013, 4040, 4041, 4042, 4043],
  12966. [4030, 4032, 4033, 4040, 4043],
  12967. [4030, 4031, 4033, 4041, 4043],
  12968. [4012, 4040, 4041, 4042, 4043],
  12969. [4030, 4031, 4033, 4040, 4043],
  12970. [4011, 4040, 4041, 4042, 4043],
  12971. [4010, 4040, 4041, 4042, 4043],
  12972. [4023, 4032, 4033, 4042, 4043],
  12973. [4022, 4032, 4033, 4042, 4043],
  12974. [4023, 4032, 4033, 4041, 4043],
  12975. [4021, 4032, 4033, 4042, 4043],
  12976. [4022, 4032, 4033, 4041, 4043],
  12977. [4023, 4030, 4033, 4042, 4043],
  12978. [4023, 4032, 4033, 4040, 4043],
  12979. [4013, 4033, 4040, 4042, 4043],
  12980. [4020, 4032, 4033, 4042, 4043],
  12981. [4021, 4032, 4033, 4041, 4043],
  12982. [4022, 4030, 4033, 4042, 4043],
  12983. [4022, 4032, 4033, 4040, 4043],
  12984. [4023, 4030, 4033, 4041, 4043],
  12985. [4023, 4031, 4033, 4040, 4043],
  12986. [4013, 4033, 4040, 4041, 4043],
  12987. [4020, 4031, 4033, 4042, 4043],
  12988. [4020, 4032, 4033, 4041, 4043],
  12989. [4021, 4030, 4033, 4042, 4043],
  12990. [4021, 4032, 4033, 4040, 4043],
  12991. [4022, 4030, 4033, 4041, 4043],
  12992. [4022, 4031, 4033, 4040, 4043],
  12993. [4023, 4030, 4033, 4040, 4043],
  12994. [4030, 4031, 4032, 4033, 4043],
  12995. [4003, 4040, 4041, 4042, 4043],
  12996. [4020, 4030, 4033, 4042, 4043],
  12997. [4020, 4031, 4033, 4041, 4043],
  12998. [4020, 4032, 4033, 4040, 4043],
  12999. [4021, 4030, 4033, 4041, 4043],
  13000. [4021, 4031, 4033, 4040, 4043],
  13001. [4022, 4030, 4033, 4040, 4043],
  13002. [4030, 4031, 4032, 4033, 4042],
  13003. [4002, 4040, 4041, 4042, 4043],
  13004. [4020, 4030, 4033, 4041, 4043],
  13005. [4020, 4031, 4033, 4040, 4043],
  13006. [4021, 4030, 4033, 4040, 4043],
  13007. [4030, 4031, 4032, 4033, 4041],
  13008. [4001, 4040, 4041, 4042, 4043],
  13009. [4030, 4031, 4032, 4033, 4040],
  13010. [4000, 4040, 4041, 4042, 4043],
  13011. [4013, 4032, 4033, 4042, 4043],
  13012. [4012, 4032, 4033, 4042, 4043],
  13013. [4013, 4032, 4033, 4041, 4043],
  13014. [4023, 4031, 4032, 4033, 4043],
  13015. [4011, 4032, 4033, 4042, 4043],
  13016. [4012, 4032, 4033, 4041, 4043],
  13017. [4013, 4030, 4033, 4042, 4043],
  13018. [4013, 4032, 4033, 4040, 4043],
  13019. [4023, 4030, 4032, 4033, 4043],
  13020. [4003, 4033, 4040, 4042, 4043],
  13021. [4013, 4023, 4040, 4042, 4043],
  13022. [4010, 4032, 4033, 4042, 4043],
  13023. [4011, 4032, 4033, 4041, 4043],
  13024. [4012, 4030, 4033, 4042, 4043],
  13025. [4012, 4032, 4033, 4040, 4043],
  13026. [4013, 4030, 4033, 4041, 4043],
  13027. [4013, 4031, 4033, 4040, 4043],
  13028. [4023, 4030, 4031, 4033, 4043],
  13029. [4003, 4033, 4040, 4041, 4043],
  13030. [4013, 4023, 4040, 4041, 4043],
  13031. [4010, 4031, 4033, 4042, 4043],
  13032. [4010, 4032, 4033, 4041, 4043],
  13033. [4011, 4030, 4033, 4042, 4043],
  13034. [4011, 4032, 4033, 4040, 4043],
  13035. [4012, 4030, 4033, 4041, 4043],
  13036. [4012, 4031, 4033, 4040, 4043],
  13037. [4013, 4030, 4033, 4040, 4043],
  13038. [4010, 4030, 4033, 4042, 4043],
  13039. [4010, 4031, 4033, 4041, 4043],
  13040. [4010, 4032, 4033, 4040, 4043],
  13041. [4011, 4030, 4033, 4041, 4043],
  13042. [4011, 4031, 4033, 4040, 4043],
  13043. [4012, 4030, 4033, 4040, 4043],
  13044. [4010, 4030, 4033, 4041, 4043],
  13045. [4010, 4031, 4033, 4040, 4043],
  13046. [4011, 4030, 4033, 4040, 4043],
  13047. [4003, 4032, 4033, 4042, 4043],
  13048. [4002, 4032, 4033, 4042, 4043],
  13049. [4003, 4032, 4033, 4041, 4043],
  13050. [4013, 4031, 4032, 4033, 4043],
  13051. [4001, 4032, 4033, 4042, 4043],
  13052. [4002, 4032, 4033, 4041, 4043],
  13053. [4003, 4030, 4033, 4042, 4043],
  13054. [4003, 4032, 4033, 4040, 4043],
  13055. [4013, 4030, 4032, 4033, 4043],
  13056. [4003, 4023, 4040, 4042, 4043],
  13057. [4000, 4032, 4033, 4042, 4043],
  13058. [4001, 4032, 4033, 4041, 4043],
  13059. [4002, 4030, 4033, 4042, 4043],
  13060. [4002, 4032, 4033, 4040, 4043],
  13061. [4003, 4030, 4033, 4041, 4043],
  13062. [4003, 4031, 4033, 4040, 4043],
  13063. [4020, 4022, 4023, 4042, 4043],
  13064. [4013, 4030, 4031, 4033, 4043],
  13065. [4003, 4023, 4040, 4041, 4043],
  13066. [4000, 4031, 4033, 4042, 4043],
  13067. [4000, 4032, 4033, 4041, 4043],
  13068. [4001, 4030, 4033, 4042, 4043],
  13069. [4001, 4032, 4033, 4040, 4043],
  13070. [4002, 4030, 4033, 4041, 4043],
  13071. [4002, 4031, 4033, 4040, 4043],
  13072. [4003, 4030, 4033, 4040, 4043],
  13073. [4021, 4022, 4023, 4040, 4043],
  13074. [4020, 4022, 4023, 4041, 4043],
  13075. [4020, 4021, 4023, 4042, 4043],
  13076. [4023, 4030, 4031, 4032, 4033],
  13077. [4000, 4030, 4033, 4042, 4043],
  13078. [4000, 4031, 4033, 4041, 4043],
  13079. [4000, 4032, 4033, 4040, 4043],
  13080. [4001, 4030, 4033, 4041, 4043],
  13081. [4001, 4031, 4033, 4040, 4043],
  13082. [4002, 4030, 4033, 4040, 4043],
  13083. [4020, 4022, 4023, 4040, 4043],
  13084. [4020, 4021, 4023, 4041, 4043],
  13085. [4022, 4030, 4031, 4032, 4033],
  13086. [4000, 4030, 4033, 4041, 4043],
  13087. [4000, 4031, 4033, 4040, 4043],
  13088. [4001, 4030, 4033, 4040, 4043],
  13089. [4020, 4021, 4023, 4040, 4043],
  13090. [4021, 4030, 4031, 4032, 4033],
  13091. [4020, 4030, 4031, 4032, 4033],
  13092. [4003, 4031, 4032, 4033, 4043],
  13093. [4020, 4022, 4023, 4033, 4043],
  13094. [4003, 4030, 4032, 4033, 4043],
  13095. [4003, 4013, 4040, 4042, 4043],
  13096. [4020, 4021, 4023, 4033, 4043],
  13097. [4003, 4030, 4031, 4033, 4043],
  13098. [4003, 4013, 4040, 4041, 4043],
  13099. [4013, 4030, 4031, 4032, 4033],
  13100. [4012, 4030, 4031, 4032, 4033],
  13101. [4011, 4030, 4031, 4032, 4033],
  13102. [4010, 4030, 4031, 4032, 4033],
  13103. [4013, 4023, 4031, 4032, 4033],
  13104. [4013, 4023, 4030, 4032, 4033],
  13105. [4020, 4022, 4023, 4032, 4033],
  13106. [4013, 4023, 4030, 4031, 4033],
  13107. [4021, 4022, 4023, 4030, 4033],
  13108. [4020, 4022, 4023, 4031, 4033],
  13109. [4020, 4021, 4023, 4032, 4033],
  13110. [4020, 4021, 4022, 4023, 4043],
  13111. [4003, 4030, 4031, 4032, 4033],
  13112. [4020, 4022, 4023, 4030, 4033],
  13113. [4020, 4021, 4023, 4031, 4033],
  13114. [4020, 4021, 4022, 4023, 4042],
  13115. [4002, 4030, 4031, 4032, 4033],
  13116. [4020, 4021, 4023, 4030, 4033],
  13117. [4020, 4021, 4022, 4023, 4041],
  13118. [4001, 4030, 4031, 4032, 4033],
  13119. [4020, 4021, 4022, 4023, 4040],
  13120. [4000, 4030, 4031, 4032, 4033],
  13121. [4003, 4023, 4031, 4032, 4033],
  13122. [4013, 4020, 4022, 4023, 4043],
  13123. [4003, 4023, 4030, 4032, 4033],
  13124. [4010, 4012, 4013, 4042, 4043],
  13125. [4013, 4020, 4021, 4023, 4043],
  13126. [4003, 4023, 4030, 4031, 4033],
  13127. [4011, 4012, 4013, 4040, 4043],
  13128. [4010, 4012, 4013, 4041, 4043],
  13129. [4010, 4011, 4013, 4042, 4043],
  13130. [4020, 4021, 4022, 4023, 4033],
  13131. [4010, 4012, 4013, 4040, 4043],
  13132. [4010, 4011, 4013, 4041, 4043],
  13133. [4020, 4021, 4022, 4023, 4032],
  13134. [4010, 4011, 4013, 4040, 4043],
  13135. [4020, 4021, 4022, 4023, 4031],
  13136. [4020, 4021, 4022, 4023, 4030],
  13137. [4003, 4013, 4031, 4032, 4033],
  13138. [4010, 4012, 4013, 4033, 4043],
  13139. [4003, 4020, 4022, 4023, 4043],
  13140. [4013, 4020, 4022, 4023, 4033],
  13141. [4003, 4013, 4030, 4032, 4033],
  13142. [4010, 4011, 4013, 4033, 4043],
  13143. [4003, 4020, 4021, 4023, 4043],
  13144. [4013, 4020, 4021, 4023, 4033],
  13145. [4003, 4013, 4030, 4031, 4033],
  13146. [4010, 4012, 4013, 4023, 4043],
  13147. [4003, 4020, 4022, 4023, 4033],
  13148. [4010, 4012, 4013, 4032, 4033],
  13149. [4010, 4011, 4013, 4023, 4043],
  13150. [4003, 4020, 4021, 4023, 4033],
  13151. [4011, 4012, 4013, 4030, 4033],
  13152. [4010, 4012, 4013, 4031, 4033],
  13153. [4010, 4011, 4013, 4032, 4033],
  13154. [4013, 4020, 4021, 4022, 4023],
  13155. [4010, 4012, 4013, 4030, 4033],
  13156. [4010, 4011, 4013, 4031, 4033],
  13157. [4012, 4020, 4021, 4022, 4023],
  13158. [4010, 4011, 4013, 4030, 4033],
  13159. [4011, 4020, 4021, 4022, 4023],
  13160. [4010, 4020, 4021, 4022, 4023],
  13161. [4010, 4012, 4013, 4023, 4033],
  13162. [4000, 4002, 4003, 4042, 4043],
  13163. [4010, 4011, 4013, 4023, 4033],
  13164. [4001, 4002, 4003, 4040, 4043],
  13165. [4000, 4002, 4003, 4041, 4043],
  13166. [4000, 4001, 4003, 4042, 4043],
  13167. [4010, 4011, 4012, 4013, 4043],
  13168. [4003, 4020, 4021, 4022, 4023],
  13169. [4000, 4002, 4003, 4040, 4043],
  13170. [4000, 4001, 4003, 4041, 4043],
  13171. [4010, 4011, 4012, 4013, 4042],
  13172. [4002, 4020, 4021, 4022, 4023],
  13173. [4000, 4001, 4003, 4040, 4043],
  13174. [4010, 4011, 4012, 4013, 4041],
  13175. [4001, 4020, 4021, 4022, 4023],
  13176. [4010, 4011, 4012, 4013, 4040],
  13177. [4000, 4020, 4021, 4022, 4023],
  13178. [4001, 4002, 4003, 4033, 4043],
  13179. [4000, 4002, 4003, 4033, 4043],
  13180. [4003, 4010, 4012, 4013, 4043],
  13181. [4003, 4013, 4020, 4022, 4023],
  13182. [4000, 4001, 4003, 4033, 4043],
  13183. [4003, 4010, 4011, 4013, 4043],
  13184. [4003, 4013, 4020, 4021, 4023],
  13185. [4010, 4011, 4012, 4013, 4033],
  13186. [4010, 4011, 4012, 4013, 4032],
  13187. [4010, 4011, 4012, 4013, 4031],
  13188. [4010, 4011, 4012, 4013, 4030],
  13189. [4001, 4002, 4003, 4023, 4043],
  13190. [4000, 4002, 4003, 4023, 4043],
  13191. [4003, 4010, 4012, 4013, 4033],
  13192. [4000, 4002, 4003, 4032, 4033],
  13193. [4000, 4001, 4003, 4023, 4043],
  13194. [4003, 4010, 4011, 4013, 4033],
  13195. [4001, 4002, 4003, 4030, 4033],
  13196. [4000, 4002, 4003, 4031, 4033],
  13197. [4000, 4001, 4003, 4032, 4033],
  13198. [4010, 4011, 4012, 4013, 4023],
  13199. [4000, 4002, 4003, 4030, 4033],
  13200. [4000, 4001, 4003, 4031, 4033],
  13201. [4010, 4011, 4012, 4013, 4022],
  13202. [4000, 4001, 4003, 4030, 4033],
  13203. [4010, 4011, 4012, 4013, 4021],
  13204. [4010, 4011, 4012, 4013, 4020],
  13205. [4001, 4002, 4003, 4013, 4043],
  13206. [4001, 4002, 4003, 4023, 4033],
  13207. [4000, 4002, 4003, 4013, 4043],
  13208. [4000, 4002, 4003, 4023, 4033],
  13209. [4003, 4010, 4012, 4013, 4023],
  13210. [4000, 4001, 4003, 4013, 4043],
  13211. [4000, 4001, 4003, 4023, 4033],
  13212. [4003, 4010, 4011, 4013, 4023],
  13213. [4001, 4002, 4003, 4013, 4033],
  13214. [4000, 4002, 4003, 4013, 4033],
  13215. [4000, 4001, 4003, 4013, 4033],
  13216. [4000, 4001, 4002, 4003, 4043],
  13217. [4003, 4010, 4011, 4012, 4013],
  13218. [4000, 4001, 4002, 4003, 4042],
  13219. [4002, 4010, 4011, 4012, 4013],
  13220. [4000, 4001, 4002, 4003, 4041],
  13221. [4001, 4010, 4011, 4012, 4013],
  13222. [4000, 4001, 4002, 4003, 4040],
  13223. [4000, 4010, 4011, 4012, 4013],
  13224. [4001, 4002, 4003, 4013, 4023],
  13225. [4000, 4002, 4003, 4013, 4023],
  13226. [4000, 4001, 4003, 4013, 4023],
  13227. [4000, 4001, 4002, 4003, 4033],
  13228. [4000, 4001, 4002, 4003, 4032],
  13229. [4000, 4001, 4002, 4003, 4031],
  13230. [4000, 4001, 4002, 4003, 4030],
  13231. [4000, 4001, 4002, 4003, 4023],
  13232. [4000, 4001, 4002, 4003, 4022],
  13233. [4000, 4001, 4002, 4003, 4021],
  13234. [4000, 4001, 4002, 4003, 4020],
  13235. [4000, 4001, 4002, 4003, 4013],
  13236. [4000, 4001, 4002, 4003, 4012],
  13237. [4000, 4001, 4002, 4003, 4011],
  13238. [4000, 4001, 4002, 4003, 4010],
  13239. ].filter((p) => p.includes(this.mandatoryId));
  13240.  
  13241. const bestPack = {
  13242. pack: packs[0],
  13243. winRate: 0,
  13244. countBattle: 0,
  13245. id: 0,
  13246. };
  13247.  
  13248. for (const id in packs) {
  13249. const pack = packs[id];
  13250. const attackers = this.maxUpgrade.filter((e) => pack.includes(e.id)).reduce((obj, e) => ({ ...obj, [e.id]: e }), {});
  13251. const battle = {
  13252. attackers,
  13253. defenders: [enemieHeroes],
  13254. type: 'brawl_titan',
  13255. };
  13256. const isRandom = this.isRandomBattle(battle);
  13257. const stat = {
  13258. count: 0,
  13259. win: 0,
  13260. winRate: 0,
  13261. };
  13262. for (let i = 1; i <= 20; i++) {
  13263. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  13264. const result = await Calc(battle);
  13265. stat.win += result.result.win;
  13266. stat.count += 1;
  13267. stat.winRate = stat.win / stat.count;
  13268. if (!isRandom || (i >= 2 && stat.winRate < 0.65) || (i >= 10 && stat.winRate == 1)) {
  13269. break;
  13270. }
  13271. }
  13272.  
  13273. if (!isRandom && stat.win) {
  13274. return {
  13275. favor: {},
  13276. heroes: pack,
  13277. };
  13278. }
  13279. if (stat.winRate > 0.85) {
  13280. return {
  13281. favor: {},
  13282. heroes: pack,
  13283. };
  13284. }
  13285. if (stat.winRate > bestPack.winRate) {
  13286. bestPack.countBattle = stat.count;
  13287. bestPack.winRate = stat.winRate;
  13288. bestPack.pack = pack;
  13289. bestPack.id = id;
  13290. }
  13291. }
  13292.  
  13293. //console.log(bestPack.id, bestPack.pack, bestPack.winRate, bestPack.countBattle);
  13294. return {
  13295. favor: {},
  13296. heroes: bestPack.pack,
  13297. };
  13298. }
  13299.  
  13300. isRandomPack(pack) {
  13301. const ids = Object.keys(pack);
  13302. return ids.includes('4023') || ids.includes('4021');
  13303. }
  13304.  
  13305. isRandomBattle(battle) {
  13306. return this.isRandomPack(battle.attackers) || this.isRandomPack(battle.defenders[0]);
  13307. }
  13308.  
  13309. async updateHeroesPack(enemieHeroes) {
  13310. const packs = [{id:1,args:{userId:-830021,heroes:[63,13,9,48,1],pet:6006,favor:{1:6004,9:6005,13:6002,48:6e3,63:6009}},attackers:{1:{id:1,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{2:130,3:130,4:130,5:130,6022:130,8268:1,8269:1},power:198058,star:6,runes:[43750,43750,43750,43750,43750],skins:{1:60,54:60,95:60,154:60,250:60,325:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[4,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3093,hp:419649,intelligence:3644,physicalAttack:11481.6,strength:17049,armor:12720,dodge:17232.28,magicPenetration:22780,magicPower:55816,magicResist:1580,modifiedSkillTier:5,skin:0,favorPetId:6004,favorPower:11064},9:{id:9,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{335:130,336:130,337:130,338:130,6027:130,8270:1,8271:1},power:195886,star:6,runes:[43750,43750,43750,43750,43750],skins:{9:60,41:60,163:60,189:60,311:60,338:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6005,type:"hero",perks:[7,2,20],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3068,hp:227134,intelligence:19003,physicalAttack:7020.32,strength:3068,armor:19995,dodge:14644,magicPower:64780.6,magicResist:31597,modifiedSkillTier:5,skin:0,favorPetId:6005,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6012:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:19060,magicPenetration:58138.6,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6002,favorPower:11064},48:{id:48,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{240:130,241:130,242:130,243:130,6002:130},power:190584,star:6,runes:[43750,43750,43750,43750,43750],skins:{103:60,165:60,217:60,296:60,326:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6e3,type:"hero",perks:[5,2],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:17308,hp:397737,intelligence:2888,physicalAttack:40298.32,physicalCritChance:12280,strength:3169,armor:12185,armorPenetration:20137.6,magicResist:24816,skin:0,favorPetId:6e3,favorPower:11064},63:{id:63,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{442:130,443:130,444:130,445:130,6041:130,8272:1,8273:1},power:193520,star:6,runes:[43750,43750,43750,43750,43750],skins:{341:60,350:60,351:60,352:1},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6009,type:"hero",perks:[6,1,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:17931,hp:488832,intelligence:2737,physicalAttack:54213.6,strength:2877,armor:800,armorPenetration:32477.6,magicResist:8526,physicalCritChance:9545,modifiedSkillTier:3,skin:0,favorPetId:6009,favorPower:11064},6006:{id:6006,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6030:130,6031:130},power:181943,type:"pet",perks:[5,9],name:null,intelligence:11064,magicPenetration:47911,strength:12360}}},{id:2,args:{userId:-830049,heroes:[46,13,52,49,4],pet:6006,favor:{4:6001,13:6002,46:6006,49:6004,52:6003}},attackers:{4:{id:4,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{255:130,256:130,257:130,258:130,6007:130},power:189782,star:6,runes:[43750,43750,43750,43750,43750],skins:{4:60,35:60,92:60,161:60,236:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6001,type:"hero",perks:[4,5,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:3065,hp:482631,intelligence:3402,physicalAttack:2800,strength:17488,armor:56262.6,magicPower:51021,magicResist:36971,skin:0,favorPetId:6001,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6012:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:19060,magicPenetration:58138.6,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6002,favorPower:11064},46:{id:46,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{230:130,231:130,232:130,233:130,6032:130},power:189653,star:6,runes:[43750,43750,43750,43750,43750],skins:{101:60,159:60,178:60,262:60,315:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6006,type:"hero",perks:[9,5,1,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2122,hp:637517,intelligence:16208,physicalAttack:50,strength:5151,armor:38507.6,magicPower:74495.6,magicResist:22237,skin:0,favorPetId:6006,favorPower:11064},49:{id:49,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{245:130,246:130,247:130,248:130,6022:130},power:193163,star:6,runes:[43750,43750,43750,43750,43750],skins:{104:60,191:60,252:60,305:60,329:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[10,1,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:17935,hp:250405,intelligence:2790,physicalAttack:40413.6,strength:2987,armor:11655,dodge:14844.28,magicResist:3175,physicalCritChance:14135,skin:0,favorPetId:6004,favorPower:11064},52:{id:52,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{310:130,311:130,312:130,313:130,6017:130},power:185075,star:6,runes:[43750,43750,43750,43750,43750],skins:{188:60,213:60,248:60,297:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6003,type:"hero",perks:[5,8,2,13,15,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:18270,hp:226207,intelligence:2620,physicalAttack:44206,strength:3260,armor:13150,armorPenetration:40301,magicPower:9957.6,magicResist:33892.6,skin:0,favorPetId:6003,favorPower:11064},6006:{id:6006,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6030:130,6031:130},power:181943,type:"pet",perks:[5,9],name:null,intelligence:11064,magicPenetration:47911,strength:12360}}},{id:3,args:{userId:8263225,heroes:[29,63,13,48,1],pet:6006,favor:{1:6004,13:6002,29:6006,48:6e3,63:6003}},attackers:{1:{id:1,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{2:130,3:130,4:130,5:130,6022:130,8268:1,8269:1},power:198058,star:6,runes:[43750,43750,43750,43750,43750],skins:{1:60,54:60,95:60,154:60,250:60,325:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[4,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3093,hp:419649,intelligence:3644,physicalAttack:11481.6,strength:17049,armor:12720,dodge:17232.28,magicPenetration:22780,magicPower:55816,magicResist:1580,modifiedSkillTier:5,skin:0,favorPetId:6004,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6012:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:19060,magicPenetration:58138.6,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6002,favorPower:11064},29:{id:29,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{145:130,146:130,147:130,148:130,6032:130},power:189790,star:6,runes:[43750,43750,43750,43750,43750],skins:{29:60,72:60,88:60,147:60,242:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6006,type:"hero",perks:[9,5,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2885,hp:491431,intelligence:18331,physicalAttack:106,strength:3020,armor:37716.6,magicPower:76792.6,magicResist:31377,skin:0,favorPetId:6006,favorPower:11064},48:{id:48,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{240:130,241:130,242:130,243:130,6002:130},power:190584,star:6,runes:[43750,43750,43750,43750,43750],skins:{103:60,165:60,217:60,296:60,326:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6e3,type:"hero",perks:[5,2],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:17308,hp:397737,intelligence:2888,physicalAttack:40298.32,physicalCritChance:12280,strength:3169,armor:12185,armorPenetration:20137.6,magicResist:24816,skin:0,favorPetId:6e3,favorPower:11064},63:{id:63,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{442:130,443:130,444:130,445:130,6017:130,8272:1,8273:1},power:191031,star:6,runes:[43750,43750,43750,43750,43750],skins:{341:60,350:60,351:60,352:1},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6003,type:"hero",perks:[6,1,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:17931,hp:488832,intelligence:2737,physicalAttack:44256,strength:2877,armor:800,armorPenetration:22520,magicPower:9957.6,magicResist:18483.6,physicalCritChance:9545,modifiedSkillTier:3,skin:0,favorPetId:6003,favorPower:11064},6006:{id:6006,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6030:130,6031:130},power:181943,type:"pet",perks:[5,9],name:null,intelligence:11064,magicPenetration:47911,strength:12360}}},{id:4,args:{userId:8263247,heroes:[55,13,40,51,1],pet:6006,favor:{1:6007,13:6002,40:6004,51:6006,55:6001}},attackers:{1:{id:1,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{2:130,3:130,4:130,5:130,6035:130,8268:1,8269:1},power:195170,star:6,runes:[43750,43750,43750,43750,43750],skins:{1:60,54:60,95:60,154:60,250:60,325:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6007,type:"hero",perks:[4,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3093,hp:419649,intelligence:3644,physicalAttack:1524,strength:17049,armor:22677.6,dodge:14245,magicPenetration:22780,magicPower:65773.6,magicResist:1580,modifiedSkillTier:5,skin:0,favorPetId:6007,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6012:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:19060,magicPenetration:58138.6,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6002,favorPower:11064},40:{id:40,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{200:130,201:130,202:130,203:130,6022:130,8244:1,8245:1},power:192541,star:6,runes:[43750,43750,43750,43750,43750],skins:{53:60,89:60,129:60,168:60,314:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[5,9,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:17540,hp:343191,intelligence:2805,physicalAttack:48430.6,strength:2976,armor:24410,dodge:15732.28,magicResist:17633,modifiedSkillTier:3,skin:0,favorPetId:6004,favorPower:11064},51:{id:51,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{305:130,306:130,307:130,308:130,6032:130},power:190005,star:6,runes:[43750,43750,43750,43750,43750],skins:{181:60,219:60,260:60,290:60,334:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6006,type:"hero",perks:[5,9,1,12],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2526,hp:438205,intelligence:18851,physicalAttack:50,strength:2921,armor:39442.6,magicPower:88978.6,magicResist:22960,skin:0,favorPetId:6006,favorPower:11064},55:{id:55,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{325:130,326:130,327:130,328:130,6007:130},power:190529,star:6,runes:[43750,43750,43750,43750,43750],skins:{239:60,278:60,309:60,327:60,346:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6001,type:"hero",perks:[7,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2631,hp:499591,intelligence:19438,physicalAttack:50,strength:3286,armor:32892.6,armorPenetration:36870,magicPower:60704,magicResist:10010,skin:0,favorPetId:6001,favorPower:11064},6006:{id:6006,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6030:130,6031:130},power:181943,type:"pet",perks:[5,9],name:null,intelligence:11064,magicPenetration:47911,strength:12360}}},{id:5,args:{userId:8263303,heroes:[31,29,13,40,1],pet:6004,favor:{1:6001,13:6007,29:6002,31:6006,40:6004}},attackers:{1:{id:1,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{2:130,3:130,4:130,5:130,6007:130,8268:1,8269:1},power:195170,star:6,runes:[43750,43750,43750,43750,43750],skins:{1:60,54:60,95:60,154:60,250:60,325:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6001,type:"hero",perks:[4,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3093,hp:519225,intelligence:3644,physicalAttack:1524,strength:17049,armor:22677.6,dodge:14245,magicPenetration:22780,magicPower:55816,magicResist:1580,modifiedSkillTier:5,skin:0,favorPetId:6001,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6035:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6007,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:29017.6,magicPenetration:48181,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6007,favorPower:11064},29:{id:29,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{145:130,146:130,147:130,148:130,6012:130},power:189790,star:6,runes:[43750,43750,43750,43750,43750],skins:{29:60,72:60,88:60,147:60,242:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[9,5,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2885,hp:491431,intelligence:18331,physicalAttack:106,strength:3020,armor:27759,magicPenetration:9957.6,magicPower:76792.6,magicResist:31377,skin:0,favorPetId:6002,favorPower:11064},31:{id:31,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{155:130,156:130,157:130,158:130,6032:130},power:190305,star:6,runes:[43750,43750,43750,43750,43750],skins:{44:60,94:60,133:60,200:60,295:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6006,type:"hero",perks:[9,5,2,20],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2781,dodge:12620,hp:374484,intelligence:18945,physicalAttack:78,strength:2916,armor:28049.6,magicPower:67686.6,magicResist:15252,skin:0,favorPetId:6006,favorPower:11064},40:{id:40,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{200:130,201:130,202:130,203:130,6022:130,8244:1,8245:1},power:192541,star:6,runes:[43750,43750,43750,43750,43750],skins:{53:60,89:60,129:60,168:60,314:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[5,9,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:17540,hp:343191,intelligence:2805,physicalAttack:48430.6,strength:2976,armor:24410,dodge:15732.28,magicResist:17633,modifiedSkillTier:3,skin:0,favorPetId:6004,favorPower:11064},6004:{id:6004,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6020:130,6021:130},power:181943,type:"pet",perks:[5],name:null,armorPenetration:47911,intelligence:11064,strength:12360}}},{id:6,args:{userId:8263317,heroes:[62,13,9,56,61],pet:6003,favor:{9:6004,13:6002,56:6006,61:6001,62:6003}},attackers:{9:{id:9,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{335:130,336:130,337:130,338:130,6022:130,8270:1,8271:1},power:198525,star:6,runes:[43750,43750,43750,43750,43750],skins:{9:60,41:60,163:60,189:60,311:60,338:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[7,2,20],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3068,hp:227134,intelligence:19003,physicalAttack:10007.6,strength:3068,armor:19995,dodge:17631.28,magicPower:54823,magicResist:31597,modifiedSkillTier:5,skin:0,favorPetId:6004,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6012:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:19060,magicPenetration:58138.6,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6002,favorPower:11064},56:{id:56,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{376:130,377:130,378:130,379:130,6032:130},power:184420,star:6,runes:[43750,43750,43750,43750,43750],skins:{264:60,279:60,294:60,321:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6006,type:"hero",perks:[5,7,1,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2791,hp:235111,intelligence:18813,physicalAttack:50,strength:2656,armor:22982.6,magicPenetration:48159,magicPower:75598.6,magicResist:13990,skin:0,favorPetId:6006,favorPower:11064},61:{id:61,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{411:130,412:130,413:130,414:130,6007:130},power:184868,star:6,runes:[43750,43750,43750,43750,43750],skins:{302:60,306:60,323:60,340:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6001,type:"hero",perks:[4,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2545,hp:466176,intelligence:3320,physicalAttack:34305,strength:18309,armor:31077.6,magicResist:24101,physicalCritChance:9009,skin:0,favorPetId:6001,favorPower:11064},62:{id:62,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{437:130,438:130,439:130,440:130,6017:130},power:173991,star:6,runes:[43750,43750,43750,43750,43750],skins:{320:60,343:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6003,type:"hero",perks:[8,7,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2530,hp:276010,intelligence:19245,physicalAttack:50,strength:3543,armor:12890,magicPenetration:23658,magicPower:80966.6,magicResist:12447.6,skin:0,favorPetId:6003,favorPower:11064},6003:{id:6003,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6015:130,6016:130},power:181943,type:"pet",perks:[8],name:null,intelligence:11064,magicPenetration:47911,strength:12360}}},{id:7,args:{userId:8263335,heroes:[32,29,13,43,1],pet:6006,favor:{1:6004,13:6008,29:6006,32:6002,43:6007}},attackers:{1:{id:1,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{2:130,3:130,4:130,5:130,6022:130,8268:1,8269:1},power:198058,star:6,runes:[43750,43750,43750,43750,43750],skins:{1:60,54:60,95:60,154:60,250:60,325:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6004,type:"hero",perks:[4,1],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:3093,hp:419649,intelligence:3644,physicalAttack:11481.6,strength:17049,armor:12720,dodge:17232.28,magicPenetration:22780,magicPower:55816,magicResist:1580,modifiedSkillTier:5,skin:0,favorPetId:6004,favorPower:11064},13:{id:"13",xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{452:130,453:130,454:130,455:130,6038:130,8274:1,8275:1},power:194833,star:6,runes:[43750,43750,43750,43750,43750],skins:{13:60,38:60,148:60,199:60,240:60,335:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6008,type:"hero",perks:[7,2,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,9,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,9,10]},agility:2885,hp:344763,intelligence:17625,physicalAttack:50,strength:3020,armor:29017.6,magicPenetration:48181,magicPower:70100.6,magicResist:27227,modifiedSkillTier:4,skin:0,favorPetId:6008,favorPower:11064},29:{id:29,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{145:130,146:130,147:130,148:130,6032:130},power:189790,star:6,runes:[43750,43750,43750,43750,43750],skins:{29:60,72:60,88:60,147:60,242:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6006,type:"hero",perks:[9,5,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2885,hp:491431,intelligence:18331,physicalAttack:106,strength:3020,armor:37716.6,magicPower:76792.6,magicResist:31377,skin:0,favorPetId:6006,favorPower:11064},32:{id:32,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{160:130,161:130,162:130,163:130,6012:130},power:189956,star:6,runes:[43750,43750,43750,43750,43750],skins:{45:60,73:60,81:60,135:60,212:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6002,type:"hero",perks:[7,5,2,22],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2815,hp:551066,intelligence:18800,physicalAttack:50,strength:2810,armor:19040,magicPenetration:9957.6,magicPower:89495.6,magicResist:20805,skin:0,favorPetId:6002,favorPower:11064},43:{id:43,xp:3625195,level:130,color:18,slots:[0,0,0,0,0,0],skills:{215:130,216:130,217:130,218:130,6035:130},power:189593,star:6,runes:[43750,43750,43750,43750,43750],skins:{98:60,130:60,169:60,201:60,304:60},currentSkin:0,titanGiftLevel:30,titanCoinsSpent:null,artifacts:[{level:130,star:6},{level:130,star:6},{level:130,star:6}],scale:1,petId:6007,type:"hero",perks:[7,9,1,21],ascensions:{1:[0,1,2,3,4,5,6,7,8,9],2:[0,1,2,3,4,5,6,7,8,10],3:[0,1,2,3,4,5,6,7,8,9],4:[0,1,2,3,4,5,6,7,8,9],5:[0,1,2,3,4,5,6,7,8,10]},agility:2447,hp:265217,intelligence:18758,physicalAttack:50,strength:2842,armor:18637.6,magicPenetration:52439,magicPower:75465.6,magicResist:22695,skin:0,favorPetId:6007,favorPower:11064},6006:{id:6006,color:10,star:6,xp:450551,level:130,slots:[25,50,50,25,50,50],skills:{6030:130,6031:130},power:181943,type:"pet",perks:[5,9],name:null,intelligence:11064,magicPenetration:47911,strength:12360}}}];
  13311.  
  13312. const bestPack = {
  13313. pack: packs[0],
  13314. countWin: 0,
  13315. }
  13316.  
  13317. for (const pack of packs) {
  13318. const attackers = pack.attackers;
  13319. const battle = {
  13320. attackers,
  13321. defenders: [enemieHeroes],
  13322. type: 'brawl',
  13323. };
  13324.  
  13325. let countWinBattles = 0;
  13326. let countTestBattle = 10;
  13327. for (let i = 0; i < countTestBattle; i++) {
  13328. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  13329. const result = await Calc(battle);
  13330. if (result.result.win) {
  13331. countWinBattles++;
  13332. }
  13333. if (countWinBattles > 7) {
  13334. console.log(pack)
  13335. return pack.args;
  13336. }
  13337. }
  13338. if (countWinBattles > bestPack.countWin) {
  13339. bestPack.countWin = countWinBattles;
  13340. bestPack.pack = pack.args;
  13341. }
  13342. }
  13343.  
  13344. console.log(bestPack);
  13345. return bestPack.pack;
  13346. }
  13347.  
  13348. async questFarm() {
  13349. const calls = [this.callBrawlQuestFarm];
  13350. const result = await Send(JSON.stringify({ calls }));
  13351. return result.results[0].result.response;
  13352. }
  13353.  
  13354. async getBrawlInfo() {
  13355. const data = await Send(JSON.stringify({
  13356. calls: [
  13357. this.callUserGetInfo,
  13358. this.callBrawlQuestGetInfo,
  13359. this.callBrawlFindEnemies,
  13360. this.callTeamGetMaxUpgrade,
  13361. this.callBrawlGetInfo,
  13362. ]
  13363. }));
  13364.  
  13365. let attempts = data.results[0].result.response.refillable.find(n => n.id == 48);
  13366.  
  13367. const maxUpgrade = data.results[3].result.response;
  13368. const maxHero = Object.values(maxUpgrade.hero);
  13369. const maxTitan = Object.values(maxUpgrade.titan);
  13370. const maxPet = Object.values(maxUpgrade.pet);
  13371. this.maxUpgrade = [...maxHero, ...maxPet, ...maxTitan];
  13372.  
  13373. this.info = data.results[4].result.response;
  13374. this.mandatoryId = lib.data.brawl.promoHero[this.info.id].promoHero;
  13375. return {
  13376. attempts: attempts.amount,
  13377. questInfo: data.results[1].result.response,
  13378. findEnemies: data.results[2].result.response,
  13379. }
  13380. }
  13381.  
  13382. /**
  13383. * Carrying out a fight
  13384. *
  13385. * Проведение боя
  13386. */
  13387. async battle(userId) {
  13388. this.stats.count++;
  13389. const battle = await this.startBattle(userId, this.args);
  13390. const result = await Calc(battle);
  13391. console.log(result.result);
  13392. if (result.result.win) {
  13393. this.stats.win++;
  13394. } else {
  13395. this.stats.loss++;
  13396. if (!this.info.boughtEndlessLivesToday) {
  13397. this.attempts--;
  13398. }
  13399. }
  13400. return await this.endBattle(result);
  13401. // return await this.cancelBattle(result);
  13402. }
  13403.  
  13404. /**
  13405. * Starts a fight
  13406. *
  13407. * Начинает бой
  13408. */
  13409. async startBattle(userId, args) {
  13410. const call = {
  13411. name: "brawl_startBattle",
  13412. args,
  13413. ident: "brawl_startBattle"
  13414. }
  13415. call.args.userId = userId;
  13416. const calls = [call];
  13417. const result = await Send(JSON.stringify({ calls }));
  13418. return result.results[0].result.response;
  13419. }
  13420.  
  13421. cancelBattle(battle) {
  13422. const fixBattle = function (heroes) {
  13423. for (const ids in heroes) {
  13424. const hero = heroes[ids];
  13425. hero.energy = random(1, 999);
  13426. if (hero.hp > 0) {
  13427. hero.hp = random(1, hero.hp);
  13428. }
  13429. }
  13430. }
  13431. fixBattle(battle.progress[0].attackers.heroes);
  13432. fixBattle(battle.progress[0].defenders.heroes);
  13433. return this.endBattle(battle);
  13434. }
  13435.  
  13436. /**
  13437. * Ends the fight
  13438. *
  13439. * Заканчивает бой
  13440. */
  13441. async endBattle(battle) {
  13442. battle.progress[0].attackers.input = ['auto', 0, 0, 'auto', 0, 0];
  13443. const calls = [{
  13444. name: "brawl_endBattle",
  13445. args: {
  13446. result: battle.result,
  13447. progress: battle.progress
  13448. },
  13449. ident: "brawl_endBattle"
  13450. },
  13451. this.callBrawlQuestGetInfo,
  13452. this.callBrawlFindEnemies,
  13453. ];
  13454. const result = await Send(JSON.stringify({ calls }));
  13455. return result.results;
  13456. }
  13457.  
  13458. end(endReason) {
  13459. setIsCancalBattle(true);
  13460. isBrawlsAutoStart = false;
  13461. setProgress(endReason, true);
  13462. console.log(endReason);
  13463. this.resolve();
  13464. }
  13465. }
  13466.  
  13467. this.HWHClasses.executeBrawls = executeBrawls;
  13468.  
  13469. /**
  13470. * Runs missions from the company on a specified list
  13471. * Выполняет миссии из компании по списку
  13472. * @param {Array} missions [{id: 25, times: 3}, {id: 45, times: 30}]
  13473. * @param {Boolean} isRaids выполнять миссии рейдом
  13474. * @returns
  13475. */
  13476. function testCompany(missions, isRaids = false) {
  13477. const { ExecuteCompany } = HWHClasses;
  13478. return new Promise((resolve, reject) => {
  13479. const tower = new ExecuteCompany(resolve, reject);
  13480. tower.start(missions, isRaids);
  13481. });
  13482. }
  13483.  
  13484. /**
  13485. * Fulfilling company missions
  13486. * Выполнение миссий компании
  13487. */
  13488. class ExecuteCompany {
  13489. constructor(resolve, reject) {
  13490. this.resolve = resolve;
  13491. this.reject = reject;
  13492. this.missionsIds = [];
  13493. this.currentNum = 0;
  13494. this.isRaid = false;
  13495. this.currentTimes = 0;
  13496.  
  13497. this.argsMission = {
  13498. id: 0,
  13499. heroes: [],
  13500. favor: {},
  13501. };
  13502. }
  13503.  
  13504. async start(missionIds, isRaids) {
  13505. this.missionsIds = missionIds;
  13506. this.isRaid = isRaids;
  13507. const data = await Caller.send(['teamGetAll', 'teamGetFavor']);
  13508. this.startCompany(data);
  13509. }
  13510.  
  13511. startCompany(data) {
  13512. const [teamGetAll, teamGetFavor] = data;
  13513.  
  13514. this.argsMission.heroes = teamGetAll.mission.filter((id) => id < 6000);
  13515. this.argsMission.favor = teamGetFavor.mission;
  13516.  
  13517. const pet = teamGetAll.mission.filter((id) => id >= 6000).pop();
  13518. if (pet) {
  13519. this.argsMission.pet = pet;
  13520. }
  13521.  
  13522. this.checkStat();
  13523. }
  13524.  
  13525. checkStat() {
  13526. if (!this.missionsIds[this.currentNum].times) {
  13527. this.currentNum++;
  13528. }
  13529.  
  13530. if (this.currentNum === this.missionsIds.length) {
  13531. this.endCompany('EndCompany');
  13532. return;
  13533. }
  13534.  
  13535. this.argsMission.id = this.missionsIds[this.currentNum].id;
  13536. this.currentTimes = this.missionsIds[this.currentNum].times;
  13537. setProgress('Сompany: ' + this.argsMission.id + ' - ' + this.currentTimes, false);
  13538. if (this.isRaid) {
  13539. this.missionRaid();
  13540. } else {
  13541. this.missionStart();
  13542. }
  13543. }
  13544.  
  13545. async missionRaid() {
  13546. try {
  13547. await Caller.send({
  13548. name: 'missionRaid',
  13549. args: {
  13550. id: this.argsMission.id,
  13551. times: this.currentTimes,
  13552. },
  13553. });
  13554. } catch (error) {
  13555. console.warn(error);
  13556. }
  13557.  
  13558. this.missionsIds[this.currentNum].times = 0;
  13559. this.checkStat();
  13560. }
  13561.  
  13562. async missionStart() {
  13563. this.lastMissionBattleStart = Date.now();
  13564. let result = null;
  13565. try {
  13566. result = await Caller.send({
  13567. name: 'missionStart',
  13568. args: this.argsMission,
  13569. });
  13570. } catch (error) {
  13571. console.warn(error);
  13572. this.endCompany('missionStartError', error['error']);
  13573. return;
  13574. }
  13575. this.missionEnd(await Calc(result));
  13576. }
  13577.  
  13578. async missionEnd(r) {
  13579. const timer = r.battleTimer;
  13580. await countdownTimer(timer, 'Сompany: ' + this.argsMission.id + ' - ' + this.currentTimes);
  13581.  
  13582. try {
  13583. await Caller.send({
  13584. name: 'missionEnd',
  13585. args: {
  13586. id: this.argsMission.id,
  13587. result: r.result,
  13588. progress: r.progress,
  13589. },
  13590. });
  13591. } catch (error) {
  13592. this.endCompany('missionEndError', error);
  13593. return;
  13594. }
  13595.  
  13596. this.missionsIds[this.currentNum].times--;
  13597. this.checkStat();
  13598. }
  13599.  
  13600. endCompany(reason, info) {
  13601. setProgress('Сompany completed!', true);
  13602. console.log(reason, info);
  13603. this.resolve();
  13604. }
  13605. }
  13606.  
  13607. this.HWHClasses.ExecuteCompany = ExecuteCompany;
  13608. })();
  13609.  
  13610. /**
  13611. * TODO:
  13612. * Закрытие окошек по Esc +-
  13613. * Починить работу скрипта на уровне команды ниже 10 +-
  13614. * Написать номальную синхронизацию
  13615. */