🏠 Home 

HeroWarsHelper

Automation of actions for the game Hero Wars


Install this script?
  1. // ==UserScript==
  2. // @name HeroWarsHelper
  3. // @name:en HeroWarsHelper
  4. // @name:ru HeroWarsHelper
  5. // @namespace HeroWarsHelper
  6. // @version 2.330
  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. (function() {
  20. /**
  21. * Start script
  22. *
  23. * Стартуем скрипт
  24. */
  25. console.log('%cStart ' + GM_info.script.name + ', v' + GM_info.script.version + ' by ' + GM_info.script.author, 'color: red');
  26. /**
  27. * Script info
  28. *
  29. * Информация о скрипте
  30. */
  31. this.scriptInfo = (({name, version, author, homepage, lastModified}, updateUrl) =>
  32. ({name, version, author, homepage, lastModified, updateUrl}))
  33. (GM_info.script, GM_info.scriptUpdateURL);
  34. this.GM_info = GM_info;
  35. /**
  36. * Information for completing daily quests
  37. *
  38. * Информация для выполнения ежендевных квестов
  39. */
  40. const questsInfo = {};
  41. /**
  42. * Is the game data loaded
  43. *
  44. * Загружены ли данные игры
  45. */
  46. let isLoadGame = false;
  47. /**
  48. * Headers of the last request
  49. *
  50. * Заголовки последнего запроса
  51. */
  52. let lastHeaders = {};
  53. /**
  54. * Information about sent gifts
  55. *
  56. * Информация об отправленных подарках
  57. */
  58. let freebieCheckInfo = null;
  59. /**
  60. * missionTimer
  61. *
  62. * missionTimer
  63. */
  64. let missionBattle = null;
  65. /**
  66. * User data
  67. *
  68. * Данные пользователя
  69. */
  70. let userInfo;
  71. this.isTimeBetweenNewDays = function () {
  72. if (userInfo.timeZone <= 3) {
  73. return false;
  74. }
  75. const nextDayTs = new Date(userInfo.nextDayTs * 1e3);
  76. const nextServerDayTs = new Date(userInfo.nextServerDayTs * 1e3);
  77. if (nextDayTs > nextServerDayTs) {
  78. nextDayTs.setDate(nextDayTs.getDate() - 1);
  79. }
  80. const now = Date.now();
  81. if (now > nextDayTs && now < nextServerDayTs) {
  82. return true;
  83. }
  84. return false;
  85. };
  86. function getUserInfo() {
  87. return userInfo;
  88. }
  89. /**
  90. * Original methods for working with AJAX
  91. *
  92. * Оригинальные методы для работы с AJAX
  93. */
  94. const original = {
  95. open: XMLHttpRequest.prototype.open,
  96. send: XMLHttpRequest.prototype.send,
  97. setRequestHeader: XMLHttpRequest.prototype.setRequestHeader,
  98. SendWebSocket: WebSocket.prototype.send,
  99. fetch: fetch,
  100. };
  101. // Sentry blocking
  102. // Блокировка наблюдателя
  103. this.fetch = function (url, options) {
  104. /**
  105. * Checking URL for blocking
  106. * Проверяем URL на блокировку
  107. */
  108. if (url.includes('sentry.io')) {
  109. console.log('%cFetch blocked', 'color: red');
  110. console.log(url, options);
  111. const body = {
  112. id: md5(Date.now()),
  113. };
  114. let info = {};
  115. try {
  116. info = JSON.parse(options.body);
  117. } catch (e) {}
  118. if (info.event_id) {
  119. body.id = info.event_id;
  120. }
  121. /**
  122. * Mock response for blocked URL
  123. *
  124. * Мокаем ответ для заблокированного URL
  125. */
  126. const mockResponse = new Response('Custom blocked response', {
  127. status: 200,
  128. headers: { 'Content-Type': 'application/json' },
  129. body,
  130. });
  131. return Promise.resolve(mockResponse);
  132. } else {
  133. /**
  134. * Call the original fetch function for all other URLs
  135. * Вызываем оригинальную функцию fetch для всех других URL
  136. */
  137. return original.fetch.apply(this, arguments);
  138. }
  139. };
  140. /**
  141. * Decoder for converting byte data to JSON string
  142. *
  143. * Декодер для перобразования байтовых данных в JSON строку
  144. */
  145. const decoder = new TextDecoder("utf-8");
  146. /**
  147. * Stores a history of requests
  148. *
  149. * Хранит историю запросов
  150. */
  151. let requestHistory = {};
  152. /**
  153. * URL for API requests
  154. *
  155. * URL для запросов к API
  156. */
  157. let apiUrl = '';
  158. /**
  159. * Connecting to the game code
  160. *
  161. * Подключение к коду игры
  162. */
  163. this.cheats = new hackGame();
  164. /**
  165. * The function of calculating the r###lts of the battle
  166. *
  167. * Функция расчета результатов боя
  168. */
  169. this.BattleCalc = cheats.BattleCalc;
  170. /**
  171. * Sending a request available through the console
  172. *
  173. * Отправка запроса доступная через консоль
  174. */
  175. this.SendRequest = send;
  176. /**
  177. * Simple combat calculation available through the console
  178. *
  179. * Простой расчет боя доступный через консоль
  180. */
  181. this.Calc = function (data) {
  182. const type = getBattleType(data?.type);
  183. return new Promise((resolve, reject) => {
  184. try {
  185. BattleCalc(data, type, resolve);
  186. } catch (e) {
  187. reject(e);
  188. }
  189. })
  190. }
  191. /**
  192. * Short asynchronous request
  193. * Usage example (returns information about a character):
  194. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  195. *
  196. * Короткий асинхронный запрос
  197. * Пример использования (возвращает информацию о персонаже):
  198. * const userInfo = await Send('{"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}')
  199. */
  200. this.Send = function (json, pr) {
  201. return new Promise((resolve, reject) => {
  202. try {
  203. send(json, resolve, pr);
  204. } catch (e) {
  205. reject(e);
  206. }
  207. })
  208. }
  209. this.xyz = (({ name, version, author }) => ({ name, version, author }))(GM_info.script);
  210. const i18nLangData = {
  211. /* English translation by BaBa */
  212. en: {
  213. /* Checkboxes */
  214. SKIP_FIGHTS: 'Skip battle',
  215. SKIP_FIGHTS_TITLE: 'Skip battle in Outland and the arena of the titans, auto-pass in the tower and campaign',
  216. ENDLESS_CARDS: 'Infinite cards',
  217. ENDLESS_CARDS_TITLE: 'Disable Divination Cards wasting',
  218. AUTO_EXPEDITION: 'Auto Expedition',
  219. AUTO_EXPEDITION_TITLE: 'Auto-sending expeditions',
  220. CANCEL_FIGHT: 'Cancel battle',
  221. CANCEL_FIGHT_TITLE: 'Ability to cancel manual combat on GW, CoW and Asgard',
  222. GIFTS: 'Gifts',
  223. GIFTS_TITLE: 'Collect gifts automatically',
  224. BATTLE_RECALCULATION: 'Battle recalculation',
  225. BATTLE_RECALCULATION_TITLE: 'Preliminary calculation of the battle',
  226. QUANTITY_CONTROL: 'Quantity control',
  227. QUANTITY_CONTROL_TITLE: 'Ability to specify the number of opened "lootboxes"',
  228. REPEAT_CAMPAIGN: 'Repeat missions',
  229. REPEAT_CAMPAIGN_TITLE: 'Auto-repeat battles in the campaign',
  230. DISABLE_DONAT: 'Disable donation',
  231. DISABLE_DONAT_TITLE: 'Removes all donation offers',
  232. DAILY_QUESTS: 'Quests',
  233. DAILY_QUESTS_TITLE: 'Complete daily quests',
  234. AUTO_QUIZ: 'AutoQuiz',
  235. AUTO_QUIZ_TITLE: 'Automatically receive correct answers to quiz questions',
  236. SECRET_WEALTH_CHECKBOX: 'Automatic purchase in the store "Secret Wealth" when entering the game',
  237. HIDE_SERVERS: 'Collapse servers',
  238. HIDE_SERVERS_TITLE: 'Hide unused servers',
  239. /* Input fields */
  240. HOW_MUCH_TITANITE: 'How much titanite to farm',
  241. COMBAT_SPEED: 'Combat Speed Multiplier',
  242. NUMBER_OF_TEST: 'Number of test fights',
  243. NUMBER_OF_AUTO_BATTLE: 'Number of auto-battle attempts',
  244. /* Buttons */
  245. RUN_SCRIPT: 'Run the',
  246. TO_DO_EVERYTHING: 'Do All',
  247. TO_DO_EVERYTHING_TITLE: 'Perform multiple actions of your choice',
  248. OUTLAND: 'Outland',
  249. OUTLAND_TITLE: 'Collect Outland',
  250. TITAN_ARENA: 'ToE',
  251. TITAN_ARENA_TITLE: 'Complete the titan arena',
  252. DUNGEON: 'Dungeon',
  253. DUNGEON_TITLE: 'Go through the dungeon',
  254. SEER: 'Seer',
  255. SEER_TITLE: 'Roll the Seer',
  256. TOWER: 'Tower',
  257. TOWER_TITLE: 'Pass the tower',
  258. EXPEDITIONS: 'Expeditions',
  259. EXPEDITIONS_TITLE: 'Sending and collecting expeditions',
  260. SYNC: 'Sync',
  261. SYNC_TITLE: 'Partial synchronization of game data without reloading the page',
  262. ARCHDEMON: 'Archdemon',
  263. FURNACE_OF_SOULS: 'Furnace of souls',
  264. ARCHDEMON_TITLE: 'Hitting kills and collecting rewards',
  265. ESTER_EGGS: 'Easter eggs',
  266. ESTER_EGGS_TITLE: 'Collect all Easter eggs or rewards',
  267. REWARDS: 'Rewards',
  268. REWARDS_TITLE: 'Collect all quest rewards',
  269. MAIL: 'Mail',
  270. MAIL_TITLE: 'Collect all mail, except letters with energy and charges of the portal',
  271. MINIONS: 'Minions',
  272. MINIONS_TITLE: 'Attack minions with saved packs',
  273. ADVENTURE: 'Adv.',
  274. ADVENTURE_TITLE: 'Passes the adventure along the specified route',
  275. STORM: 'Storm',
  276. STORM_TITLE: 'Passes the Storm along the specified route',
  277. SANCTUARY: 'Sanctuary',
  278. SANCTUARY_TITLE: 'Fast travel to Sanctuary',
  279. GUILD_WAR: 'Guild War',
  280. GUILD_WAR_TITLE: 'Fast travel to Guild War',
  281. SECRET_WEALTH: 'Secret Wealth',
  282. SECRET_WEALTH_TITLE: 'Buy something in the store "Secret Wealth"',
  283. /* Misc */
  284. BOTTOM_URLS:
  285. '<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>',
  286. GIFTS_SENT: 'Gifts sent!',
  287. DO_YOU_WANT: 'Do you really want to do this?',
  288. BTN_RUN: 'Run',
  289. BTN_CANCEL: 'Cancel',
  290. BTN_ACCEPT: 'Accept',
  291. BTN_OK: 'OK',
  292. MSG_HAVE_BEEN_DEFEATED: 'You have been defeated!',
  293. BTN_AUTO: 'Auto',
  294. MSG_YOU_APPLIED: 'You applied',
  295. MSG_DAMAGE: 'damage',
  296. MSG_CANCEL_AND_STAT: 'Auto (F5) and show statistic',
  297. MSG_REPEAT_MISSION: 'Repeat the mission?',
  298. BTN_REPEAT: 'Repeat',
  299. BTN_NO: 'No',
  300. MSG_SPECIFY_QUANT: 'Specify Quantity:',
  301. BTN_OPEN: 'Open',
  302. QUESTION_COPY: 'Question copied to clipboard',
  303. ANSWER_KNOWN: 'The answer is known',
  304. ANSWER_NOT_KNOWN: 'ATTENTION THE ANSWER IS NOT KNOWN',
  305. BEING_RECALC: 'The battle is being recalculated',
  306. THIS_TIME: 'This time',
  307. VICTORY: '<span style="color:green;">VICTORY</span>',
  308. DEFEAT: '<span style="color:red;">DEFEAT</span>',
  309. CHANCE_TO_WIN: 'Chance to win <span style="color: red;">based on pre-calculation</span>',
  310. OPEN_DOLLS: 'nesting dolls recursively',
  311. SENT_QUESTION: 'Question sent',
  312. SETTINGS: 'Settings',
  313. MSG_BAN_ATTENTION: '<p style="color:red;">Using this feature may r###lt in a ban.</p> Continue?',
  314. BTN_YES_I_AGREE: 'Yes, I understand the risks!',
  315. BTN_NO_I_AM_AGAINST: 'No, I refuse it!',
  316. VALUES: 'Values',
  317. EXPEDITIONS_SENT: 'Expeditions:<br>Collected: {countGet}<br>Sent: {countSend}',
  318. EXPEDITIONS_NOTHING: 'Nothing to collect/send',
  319. EXPEDITIONS_NOTTIME: 'It is not time for expeditions',
  320. TITANIT: 'Titanit',
  321. COMPLETED: 'completed',
  322. FLOOR: 'Floor',
  323. LEVEL: 'Level',
  324. BATTLES: 'battles',
  325. EVENT: 'Event',
  326. NOT_AVAILABLE: 'not available',
  327. NO_HEROES: 'No heroes',
  328. DAMAGE_AMOUNT: 'Damage amount',
  329. NOTHING_TO_COLLECT: 'Nothing to collect',
  330. COLLECTED: 'Collected',
  331. REWARD: 'rewards',
  332. REMAINING_ATTEMPTS: 'Remaining attempts',
  333. BATTLES_CANCELED: 'Battles canceled',
  334. MINION_RAID: 'Minion Raid',
  335. STOPPED: 'Stopped',
  336. REPETITIONS: 'Repetitions',
  337. MISSIONS_PASSED: 'Missions passed',
  338. STOP: 'stop',
  339. TOTAL_OPEN: 'Total open',
  340. OPEN: 'Open',
  341. ROUND_STAT: 'Damage statistics for ',
  342. BATTLE: 'battles',
  343. MINIMUM: 'Minimum',
  344. MAXIMUM: 'Maximum',
  345. AVERAGE: 'Average',
  346. NOT_THIS_TIME: 'Not this time',
  347. RETRY_LIMIT_EXCEEDED: 'Retry limit exceeded',
  348. SUCCESS: 'Success',
  349. RECEIVED: 'Received',
  350. LETTERS: 'letters',
  351. PORTALS: 'portals',
  352. ATTEMPTS: 'attempts',
  353. /* Quests */
  354. QUEST_10001: 'Upgrade the skills of heroes 3 times',
  355. QUEST_10002: 'Complete 10 missions',
  356. QUEST_10003: 'Complete 3 heroic missions',
  357. QUEST_10004: 'Fight 3 times in the Arena or Grand Arena',
  358. QUEST_10006: 'Use the exchange of emeralds 1 time',
  359. QUEST_10007: 'Perform 1 summon in the Solu Atrium',
  360. QUEST_10016: 'Send gifts to guildmates',
  361. QUEST_10018: 'Use an experience potion',
  362. QUEST_10019: 'Open 1 chest in the Tower',
  363. QUEST_10020: 'Open 3 chests in Outland',
  364. QUEST_10021: 'Collect 75 Titanite in the Guild Dungeon',
  365. QUEST_10021: 'Collect 150 Titanite in the Guild Dungeon',
  366. QUEST_10023: 'Upgrade Gift of the Elements by 1 level',
  367. QUEST_10024: 'Level up any artifact once',
  368. QUEST_10025: 'Start Expedition 1',
  369. QUEST_10026: 'Start 4 Expeditions',
  370. QUEST_10027: 'Win 1 battle of the Tournament of Elements',
  371. QUEST_10028: 'Level up any titan artifact',
  372. QUEST_10029: 'Unlock the Orb of Titan Artifacts',
  373. QUEST_10030: 'Upgrade any Skin of any hero 1 time',
  374. QUEST_10031: 'Win 6 battles of the Tournament of Elements',
  375. QUEST_10043: 'Start or Join an Adventure',
  376. QUEST_10044: 'Use Summon Pets 1 time',
  377. QUEST_10046: 'Open 3 chests in Adventure',
  378. QUEST_10047: 'Get 150 Guild Activity Points',
  379. NOTHING_TO_DO: 'Nothing to do',
  380. YOU_CAN_COMPLETE: 'You can complete quests',
  381. BTN_DO_IT: 'Do it',
  382. NOT_QUEST_COMPLETED: 'Not a single quest completed',
  383. COMPLETED_QUESTS: 'Completed quests',
  384. /* everything button */
  385. ASSEMBLE_OUTLAND: 'Assemble Outland',
  386. PASS_THE_TOWER: 'Pass the tower',
  387. CHECK_EXPEDITIONS: 'Check Expeditions',
  388. COMPLETE_TOE: 'Complete ToE',
  389. COMPLETE_DUNGEON: 'Complete the dungeon',
  390. COLLECT_MAIL: 'Collect mail',
  391. COLLECT_MISC: 'Collect some bullshit',
  392. COLLECT_MISC_TITLE: 'Collect Easter Eggs, Skin Gems, Keys, Arena Coins and Soul Crystal',
  393. COLLECT_QUEST_REWARDS: 'Collect quest rewards',
  394. MAKE_A_SYNC: 'Make a sync',
  395. RUN_FUNCTION: 'Run the following functions?',
  396. BTN_GO: 'Go!',
  397. PERFORMED: 'Performed',
  398. DONE: 'Done',
  399. ERRORS_OCCURRES: 'Errors occurred while executing',
  400. COPY_ERROR: 'Copy error information to clipboard',
  401. BTN_YES: 'Yes',
  402. ALL_TASK_COMPLETED: 'All tasks completed',
  403. UNKNOWN: 'unknown',
  404. ENTER_THE_PATH: 'Enter the path of adventure using commas or dashes',
  405. START_ADVENTURE: 'Start your adventure along this path!',
  406. INCORRECT_WAY: 'Incorrect path in adventure: {from} -> {to}',
  407. BTN_CANCELED: 'Canceled',
  408. MUST_TWO_POINTS: 'The path must contain at least 2 points.',
  409. MUST_ONLY_NUMBERS: 'The path must contain only numbers and commas',
  410. NOT_ON_AN_ADVENTURE: 'You are not on an adventure',
  411. YOU_IN_NOT_ON_THE_WAY: 'Your location is not on the way',
  412. ATTEMPTS_NOT_ENOUGH: 'Your attempts are not enough to complete the path, continue?',
  413. YES_CONTINUE: 'Yes, continue!',
  414. NOT_ENOUGH_AP: 'Not enough action points',
  415. ATTEMPTS_ARE_OVER: 'The attempts are over',
  416. MOVES: 'Moves',
  417. BUFF_GET_ERROR: 'Buff getting error',
  418. BATTLE_END_ERROR: 'Battle end error',
  419. AUTOBOT: 'Autobot',
  420. FAILED_TO_WIN_AUTO: 'Failed to win the auto battle',
  421. ERROR_OF_THE_BATTLE_COPY: 'An error occurred during the passage of the battle<br>Copy the error to the clipboard?',
  422. ERROR_DURING_THE_BATTLE: 'Error during the battle',
  423. NO_CHANCE_WIN: 'No chance of winning this fight: 0/',
  424. LOST_HEROES: 'You have won, but you have lost one or several heroes',
  425. VICTORY_IMPOSSIBLE: 'Is victory impossible, should we focus on the r###lt?',
  426. FIND_COEFF: 'Find the coefficient greater than',
  427. BTN_PASS: 'PASS',
  428. BRAWLS: 'Brawls',
  429. BRAWLS_TITLE: 'Activates the ability to auto-brawl',
  430. START_AUTO_BRAWLS: 'Start Auto Brawls?',
  431. LOSSES: 'Losses',
  432. WINS: 'Wins',
  433. FIGHTS: 'Fights',
  434. STAGE: 'Stage',
  435. DONT_HAVE_LIVES: "You don't have lives",
  436. LIVES: 'Lives',
  437. SECRET_WEALTH_ALREADY: 'Item for Pet Potions already purchased',
  438. SECRET_WEALTH_NOT_ENOUGH: 'Not Enough Pet Potion, You Have {available}, Need {need}',
  439. SECRET_WEALTH_UPGRADE_NEW_PET: 'After purchasing the Pet Potion, it will not be enough to upgrade a new pet',
  440. SECRET_WEALTH_PURCHASED: 'Purchased {count} {name}',
  441. SECRET_WEALTH_CANCELED: 'Secret Wealth: Purchase Canceled',
  442. SECRET_WEALTH_BUY: 'You have {available} Pet Potion.<br>Do you want to buy {countBuy} {name} for {price} Pet Potion?',
  443. DAILY_BONUS: 'Daily bonus',
  444. DO_DAILY_QUESTS: 'Do daily quests',
  445. ACTIONS: 'Actions',
  446. ACTIONS_TITLE: 'Dialog box with various actions',
  447. OTHERS: 'Others',
  448. OTHERS_TITLE: 'Others',
  449. CHOOSE_ACTION: 'Choose an action',
  450. OPEN_LOOTBOX: 'You have {lootBox} boxes, should we open them?',
  451. STAMINA: 'Energy',
  452. BOXES_OVER: 'The boxes are over',
  453. NO_BOXES: 'No boxes',
  454. NO_MORE_ACTIVITY: 'No more activity for items today',
  455. EXCHANGE_ITEMS: 'Exchange items for activity points (max {maxActive})?',
  456. GET_ACTIVITY: 'Get Activity',
  457. NOT_ENOUGH_ITEMS: 'Not enough items',
  458. ACTIVITY_RECEIVED: 'Activity received',
  459. NO_PURCHASABLE_HERO_SOULS: 'No purchasable Hero Souls',
  460. PURCHASED_HERO_SOULS: 'Purchased {countHeroSouls} Hero Souls',
  461. NOT_ENOUGH_EMERALDS_540: 'Not enough emeralds, you need {imgEmerald}540 you have {imgEmerald}{currentStarMoney}',
  462. BUY_OUTLAND_BTN: 'Buy {count} chests {imgEmerald}{countEmerald}',
  463. CHESTS_NOT_AVAILABLE: 'Chests not available',
  464. OUTLAND_CHESTS_RECEIVED: 'Outland chests received',
  465. RAID_NOT_AVAILABLE: 'The raid is not available or there are no spheres',
  466. RAID_ADVENTURE: 'Raid {adventureId} adventure!',
  467. SOMETHING_WENT_WRONG: 'Something went wrong',
  468. ADVENTURE_COMPLETED: 'Adventure {adventureId} completed {times} times',
  469. CLAN_STAT_COPY: 'Clan statistics copied to clipboard',
  470. GET_ENERGY: 'Get Energy',
  471. GET_ENERGY_TITLE: 'Opens platinum boxes one at a time until you get 250 energy',
  472. ITEM_EXCHANGE: 'Item Exchange',
  473. ITEM_EXCHANGE_TITLE: 'Exchanges items for the specified amount of activity',
  474. BUY_SOULS: 'Buy souls',
  475. BUY_SOULS_TITLE: 'Buy hero souls from all available shops',
  476. BUY_OUTLAND: 'Buy Outland',
  477. BUY_OUTLAND_TITLE: 'Buy 9 chests in Outland for 540 emeralds',
  478. RAID: 'Raid',
  479. AUTO_RAID_ADVENTURE: 'Raid',
  480. AUTO_RAID_ADVENTURE_TITLE: 'Raid adventure set number of times',
  481. CLAN_STAT: 'Clan statistics',
  482. CLAN_STAT_TITLE: 'Copies clan statistics to the clipboard',
  483. BTN_AUTO_F5: 'Auto (F5)',
  484. BOSS_DAMAGE: 'Boss Damage: ',
  485. NOTHING_BUY: 'Nothing to buy',
  486. LOTS_BOUGHT: '{countBuy} lots bought for gold',
  487. BUY_FOR_GOLD: 'Buy for gold',
  488. BUY_FOR_GOLD_TITLE: 'Buy items for gold in the Town Shop and in the Pet Soul Stone Shop',
  489. REWARDS_AND_MAIL: 'Rewards and Mail',
  490. REWARDS_AND_MAIL_TITLE: 'Collects rewards and mail',
  491. COLLECT_REWARDS_AND_MAIL: 'Collected {countQuests} rewards and {countMail} letters',
  492. TIMER_ALREADY: 'Timer already started {time}',
  493. NO_ATTEMPTS_TIMER_START: 'No attempts, timer started {time}',
  494. EPIC_BRAWL_R###LT: 'Wins: {wins}/{attempts}, Coins: {coins}, Streak: {progress}/{nextStage} [Close]{end}',
  495. ATTEMPT_ENDED: '<br>Attempts ended, timer started {time}',
  496. EPIC_BRAWL: 'Cosmic Battle',
  497. EPIC_BRAWL_TITLE: 'Spends attempts in the Cosmic Battle',
  498. RELOAD_GAME: 'Reload game',
  499. TIMER: 'Timer:',
  500. SHOW_ERRORS: 'Show errors',
  501. SHOW_ERRORS_TITLE: 'Show server request errors',
  502. ERROR_MSG: 'Error: {name}<br>{description}',
  503. EVENT_AUTO_BOSS:
  504. '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?',
  505. BEST_SLOW: 'Best (slower)',
  506. FIRST_FAST: 'First (faster)',
  507. FREEZE_INTERFACE: 'Calculating... <br>The interface may freeze.',
  508. ERROR_F12: 'Error, details in the console (F12)',
  509. FAILED_FIND_WIN_PACK: 'Failed to find a winning pack',
  510. BEST_PACK: 'Best pack:',
  511. BOSS_HAS_BEEN_DEF: 'Boss {bossLvl} has been defeated.',
  512. NOT_ENOUGH_ATTEMPTS_BOSS: 'Not enough attempts to defeat boss {bossLvl}, retry?',
  513. BOSS_VICTORY_IMPOSSIBLE:
  514. '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?',
  515. BOSS_HAS_BEEN_DEF_TEXT:
  516. 'Boss {bossLvl} defeated in<br>{countBattle}/{countMaxBattle} attempts{winTimer}<br>(Please synchronize or restart the game to update the data)',
  517. MAP: 'Map: ',
  518. PLAYER_POS: 'Player positions:',
  519. NY_GIFTS: 'Gifts',
  520. NY_GIFTS_TITLE: "Open all New Year's gifts",
  521. NY_NO_GIFTS: 'No gifts not received',
  522. NY_GIFTS_COLLECTED: '{count} gifts collected',
  523. CHANGE_MAP: 'Island map',
  524. CHANGE_MAP_TITLE: 'Change island map',
  525. SELECT_ISLAND_MAP: 'Select an island map:',
  526. MAP_NUM: 'Map {num}',
  527. SECRET_WEALTH_SHOP: 'Secret Wealth {name}: ',
  528. SHOPS: 'Shops',
  529. SHOPS_DEFAULT: 'Default',
  530. SHOPS_DEFAULT_TITLE: 'Default stores',
  531. SHOPS_LIST: 'Shops {number}',
  532. SHOPS_LIST_TITLE: 'List of shops {number}',
  533. SHOPS_WARNING:
  534. '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>',
  535. MINIONS_WARNING: 'The hero packs for attacking minions are incomplete, should I continue?',
  536. FAST_SEASON: 'Fast season',
  537. FAST_SEASON_TITLE: 'Skip the map selection screen in a season',
  538. SET_NUMBER_LEVELS: 'Specify the number of levels:',
  539. POSSIBLE_IMPROVE_LEVELS: 'It is possible to improve only {count} levels.<br>Improving?',
  540. NOT_ENOUGH_RESOURECES: 'Not enough resources',
  541. IMPROVED_LEVELS: 'Improved levels: {count}',
  542. ARTIFACTS_UPGRADE: 'Artifacts Upgrade',
  543. ARTIFACTS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero artifacts',
  544. SKINS_UPGRADE: 'Skins Upgrade',
  545. SKINS_UPGRADE_TITLE: 'Upgrades the specified amount of the cheapest hero skins',
  546. HINT: '<br>Hint: ',
  547. PICTURE: '<br>Picture: ',
  548. ANSWER: '<br>Answer: ',
  549. NO_HEROES_PACK: 'Fight at least one battle to save the attacking team',
  550. BRAWL_AUTO_PACK: 'Automatic selection of packs',
  551. BRAWL_AUTO_PACK_NOT_CUR_HERO: 'Automatic pack selection is not suitable for the current hero',
  552. BRAWL_DAILY_TASK_COMPLETED: 'Daily task completed, continue attacking?',
  553. CALC_STAT: 'Calculate statistics',
  554. ELEMENT_TOURNAMENT_REWARD: 'Unclaimed bonus for Elemental Tournament',
  555. BTN_TRY_FIX_IT: 'Fix it',
  556. BTN_TRY_FIX_IT_TITLE: 'Enable auto attack combat correction',
  557. DAMAGE_FIXED: 'Damage fixed from {lastDamage} to {maxDamage}!',
  558. DAMAGE_NO_FIXED: 'Failed to fix damage: {lastDamage}',
  559. LETS_FIX: "Let's fix",
  560. COUNT_FIXED: 'For {count} attempts',
  561. DEFEAT_TURN_TIMER: 'Defeat! Turn on the timer to complete the mission?',
  562. SEASON_REWARD: 'Season Rewards',
  563. SEASON_REWARD_TITLE: 'Collects available free rewards from all current seasons',
  564. SEASON_REWARD_COLLECTED: 'Collected {count} season rewards',
  565. SELL_HERO_SOULS: 'Sell ​​souls',
  566. SELL_HERO_SOULS_TITLE: 'Exchanges all absolute star hero souls for gold',
  567. GOLD_RECEIVED: 'Gold received: {gold}',
  568. OPEN_ALL_EQUIP_BOXES: 'Open all Equipment Fragment Box?',
  569. SERVER_NOT_ACCEPT: 'The server did not accept the r###lt',
  570. INVASION_BOSS_BUFF: 'For {bossLvl} boss need buff {needBuff} you have {haveBuff}}',
  571. HERO_POWER: 'Hero Power',
  572. HERO_POWER_TITLE: 'Displays the current and maximum power of heroes',
  573. MAX_POWER_REACHED: 'Maximum power reached: {power}',
  574. CURRENT_POWER: 'Current power: {power}',
  575. POWER_TO_MAX: 'Power left to reach maximum: <span style="color:{color};">{power}</span><br>',
  576. BEST_R###LT: 'Best r###lt: {value}%',
  577. GUILD_ISLAND_TITLE: 'Fast travel to Guild Island',
  578. TITAN_VALLEY_TITLE: 'Fast travel to Titan Valley',
  579. },
  580. ru: {
  581. /* Чекбоксы */
  582. SKIP_FIGHTS: 'Пропуск боев',
  583. SKIP_FIGHTS_TITLE: 'Пропуск боев в запределье и арене титанов, автопропуск в башне и кампании',
  584. ENDLESS_CARDS: 'Бесконечные карты',
  585. ENDLESS_CARDS_TITLE: 'Отключить трату карт предсказаний',
  586. AUTO_EXPEDITION: 'АвтоЭкспедиции',
  587. AUTO_EXPEDITION_TITLE: 'Автоотправка экспедиций',
  588. CANCEL_FIGHT: 'Отмена боя',
  589. CANCEL_FIGHT_TITLE: 'Возможность отмены ручного боя на ВГ, СМ и в Асгарде',
  590. GIFTS: 'Подарки',
  591. GIFTS_TITLE: 'Собирать подарки автоматически',
  592. BATTLE_RECALCULATION: 'Прерасчет боя',
  593. BATTLE_RECALCULATION_TITLE: 'Предварительный расчет боя',
  594. QUANTITY_CONTROL: 'Контроль кол-ва',
  595. QUANTITY_CONTROL_TITLE: 'Возможность указывать количество открываемых "лутбоксов"',
  596. REPEAT_CAMPAIGN: 'Повтор в кампании',
  597. REPEAT_CAMPAIGN_TITLE: 'Автоповтор боев в кампании',
  598. DISABLE_DONAT: 'Отключить донат',
  599. DISABLE_DONAT_TITLE: 'Убирает все предложения доната',
  600. DAILY_QUESTS: 'Квесты',
  601. DAILY_QUESTS_TITLE: 'Выполнять ежедневные квесты',
  602. AUTO_QUIZ: 'АвтоВикторина',
  603. AUTO_QUIZ_TITLE: 'Автоматическое получение правильных ответов на вопросы викторины',
  604. SECRET_WEALTH_CHECKBOX: 'Автоматическая покупка в магазине "Тайное Богатство" при заходе в игру',
  605. HIDE_SERVERS: 'Свернуть сервера',
  606. HIDE_SERVERS_TITLE: 'Скрывать неиспользуемые сервера',
  607. /* Поля ввода */
  608. HOW_MUCH_TITANITE: 'Сколько фармим титанита',
  609. COMBAT_SPEED: 'Множитель ускорения боя',
  610. NUMBER_OF_TEST: 'Количество тестовых боев',
  611. NUMBER_OF_AUTO_BATTLE: 'Количество попыток автобоев',
  612. /* Кнопки */
  613. RUN_SCRIPT: 'Запустить скрипт',
  614. TO_DO_EVERYTHING: 'Сделать все',
  615. TO_DO_EVERYTHING_TITLE: 'Выполнить несколько действий',
  616. OUTLAND: 'Запределье',
  617. OUTLAND_TITLE: 'Собрать Запределье',
  618. TITAN_ARENA: 'Турн.Стихий',
  619. TITAN_ARENA_TITLE: 'Автопрохождение Турнира Стихий',
  620. DUNGEON: 'Подземелье',
  621. DUNGEON_TITLE: 'Автопрохождение подземелья',
  622. SEER: 'Провидец',
  623. SEER_TITLE: 'Покрутить Провидца',
  624. TOWER: 'Башня',
  625. TOWER_TITLE: 'Автопрохождение башни',
  626. EXPEDITIONS: 'Экспедиции',
  627. EXPEDITIONS_TITLE: 'Отправка и сбор экспедиций',
  628. SYNC: 'Синхронизация',
  629. SYNC_TITLE: 'Частичная синхронизация данных игры без перезагрузки сатраницы',
  630. ARCHDEMON: 'Архидемон',
  631. FURNACE_OF_SOULS: 'Горнило душ',
  632. ARCHDEMON_TITLE: 'Набивает килы и собирает награду',
  633. ESTER_EGGS: 'Пасхалки',
  634. ESTER_EGGS_TITLE: 'Собрать все пасхалки или награды',
  635. REWARDS: 'Награды',
  636. REWARDS_TITLE: 'Собрать все награды за задания',
  637. MAIL: 'Почта',
  638. MAIL_TITLE: 'Собрать всю почту, кроме писем с энергией и зарядами портала',
  639. MINIONS: 'Прислужники',
  640. MINIONS_TITLE: 'Атакует прислужников сохраннеными пачками',
  641. ADVENTURE: 'Прикл',
  642. ADVENTURE_TITLE: 'Проходит приключение по указанному маршруту',
  643. STORM: 'Буря',
  644. STORM_TITLE: 'Проходит бурю по указанному маршруту',
  645. SANCTUARY: 'Святилище',
  646. SANCTUARY_TITLE: 'Быстрый переход к Святилищу',
  647. GUILD_WAR: 'Война гильдий',
  648. GUILD_WAR_TITLE: 'Быстрый переход к Войне гильдий',
  649. SECRET_WEALTH: 'Тайное богатство',
  650. SECRET_WEALTH_TITLE: 'Купить что-то в магазине "Тайное богатство"',
  651. /* Разное */
  652. BOTTOM_URLS:
  653. '<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>',
  654. GIFTS_SENT: 'Подарки отправлены!',
  655. DO_YOU_WANT: 'Вы действительно хотите это сделать?',
  656. BTN_RUN: 'Запускай',
  657. BTN_CANCEL: 'Отмена',
  658. BTN_ACCEPT: 'Принять',
  659. BTN_OK: 'Ок',
  660. MSG_HAVE_BEEN_DEFEATED: 'Вы потерпели поражение!',
  661. BTN_AUTO: 'Авто',
  662. MSG_YOU_APPLIED: 'Вы нанесли',
  663. MSG_DAMAGE: 'урона',
  664. MSG_CANCEL_AND_STAT: 'Авто (F5) и показать Статистику',
  665. MSG_REPEAT_MISSION: 'Повторить миссию?',
  666. BTN_REPEAT: 'Повторить',
  667. BTN_NO: 'Нет',
  668. MSG_SPECIFY_QUANT: 'Указать количество:',
  669. BTN_OPEN: 'Открыть',
  670. QUESTION_COPY: 'Вопрос скопирован в буфер обмена',
  671. ANSWER_KNOWN: 'Ответ известен',
  672. ANSWER_NOT_KNOWN: 'ВНИМАНИЕ ОТВЕТ НЕ ИЗВЕСТЕН',
  673. BEING_RECALC: 'Идет прерасчет боя',
  674. THIS_TIME: 'На этот раз',
  675. VICTORY: '<span style="color:green;">ПОБЕДА</span>',
  676. DEFEAT: '<span style="color:red;">ПОРАЖЕНИЕ</span>',
  677. CHANCE_TO_WIN: 'Шансы на победу <span style="color:red;">на основе прерасчета</span>',
  678. OPEN_DOLLS: 'матрешек рекурсивно',
  679. SENT_QUESTION: 'Вопрос отправлен',
  680. SETTINGS: 'Настройки',
  681. MSG_BAN_ATTENTION: '<p style="color:red;">Использование этой функции может привести к бану.</p> Продолжить?',
  682. BTN_YES_I_AGREE: 'Да, я беру на себя все риски!',
  683. BTN_NO_I_AM_AGAINST: 'Нет, я отказываюсь от этого!',
  684. VALUES: 'Значения',
  685. EXPEDITIONS_SENT: 'Экспедиции:<br>Собрано: {countGet}<br>Отправлено: {countSend}',
  686. EXPEDITIONS_NOTHING: 'Нечего собирать/отправлять',
  687. EXPEDITIONS_NOTTIME: 'Не время для экспедиций',
  688. TITANIT: 'Титанит',
  689. COMPLETED: 'завершено',
  690. FLOOR: 'Этаж',
  691. LEVEL: 'Уровень',
  692. BATTLES: 'бои',
  693. EVENT: 'Эвент',
  694. NOT_AVAILABLE: 'недоступен',
  695. NO_HEROES: 'Нет героев',
  696. DAMAGE_AMOUNT: 'Количество урона',
  697. NOTHING_TO_COLLECT: 'Нечего собирать',
  698. COLLECTED: 'Собрано',
  699. REWARD: 'наград',
  700. REMAINING_ATTEMPTS: 'Осталось попыток',
  701. BATTLES_CANCELED: 'Битв отменено',
  702. MINION_RAID: 'Рейд прислужников',
  703. STOPPED: 'Остановлено',
  704. REPETITIONS: 'Повторений',
  705. MISSIONS_PASSED: 'Миссий пройдено',
  706. STOP: 'остановить',
  707. TOTAL_OPEN: 'Всего открыто',
  708. OPEN: 'Открыто',
  709. ROUND_STAT: 'Статистика урона за',
  710. BATTLE: 'боев',
  711. MINIMUM: 'Минимальный',
  712. MAXIMUM: 'Максимальный',
  713. AVERAGE: 'Средний',
  714. NOT_THIS_TIME: 'Не в этот раз',
  715. RETRY_LIMIT_EXCEEDED: 'Превышен лимит попыток',
  716. SUCCESS: 'Успех',
  717. RECEIVED: 'Получено',
  718. LETTERS: 'писем',
  719. PORTALS: 'порталов',
  720. ATTEMPTS: 'попыток',
  721. QUEST_10001: 'Улучши умения героев 3 раза',
  722. QUEST_10002: 'Пройди 10 миссий',
  723. QUEST_10003: 'Пройди 3 героические миссии',
  724. QUEST_10004: 'Сразись 3 раза на Арене или Гранд Арене',
  725. QUEST_10006: 'Используй обмен изумрудов 1 раз',
  726. QUEST_10007: 'Соверши 1 призыв в Атриуме Душ',
  727. QUEST_10016: 'Отправь подарки согильдийцам',
  728. QUEST_10018: 'Используй зелье опыта',
  729. QUEST_10019: 'Открой 1 сундук в Башне',
  730. QUEST_10020: 'Открой 3 сундука в Запределье',
  731. QUEST_10021: 'Собери 75 Титанита в Подземелье Гильдии',
  732. QUEST_10021: 'Собери 150 Титанита в Подземелье Гильдии',
  733. QUEST_10023: 'Прокачай Дар Стихий на 1 уровень',
  734. QUEST_10024: 'Повысь уровень любого артефакта один раз',
  735. QUEST_10025: 'Начни 1 Экспедицию',
  736. QUEST_10026: 'Начни 4 Экспедиции',
  737. QUEST_10027: 'Победи в 1 бою Турнира Стихий',
  738. QUEST_10028: 'Повысь уровень любого артефакта титанов',
  739. QUEST_10029: 'Открой сферу артефактов титанов',
  740. QUEST_10030: 'Улучши облик любого героя 1 раз',
  741. QUEST_10031: 'Победи в 6 боях Турнира Стихий',
  742. QUEST_10043: 'Начни или присоеденись к Приключению',
  743. QUEST_10044: 'Воспользуйся призывом питомцев 1 раз',
  744. QUEST_10046: 'Открой 3 сундука в Приключениях',
  745. QUEST_10047: 'Набери 150 очков активности в Гильдии',
  746. NOTHING_TO_DO: 'Нечего выполнять',
  747. YOU_CAN_COMPLETE: 'Можно выполнить квесты',
  748. BTN_DO_IT: 'Выполняй',
  749. NOT_QUEST_COMPLETED: 'Ни одного квеста не выполенно',
  750. COMPLETED_QUESTS: 'Выполнено квестов',
  751. /* everything button */
  752. ASSEMBLE_OUTLAND: 'Собрать Запределье',
  753. PASS_THE_TOWER: 'Пройти башню',
  754. CHECK_EXPEDITIONS: 'Проверить экспедиции',
  755. COMPLETE_TOE: 'Пройти Турнир Стихий',
  756. COMPLETE_DUNGEON: 'Пройти подземелье',
  757. COLLECT_MAIL: 'Собрать почту',
  758. COLLECT_MISC: 'Собрать всякую херню',
  759. COLLECT_MISC_TITLE: 'Собрать пасхалки, камни облика, ключи, монеты арены и Хрусталь души',
  760. COLLECT_QUEST_REWARDS: 'Собрать награды за квесты',
  761. MAKE_A_SYNC: 'Сделать синхронизацию',
  762. RUN_FUNCTION: 'Выполнить следующие функции?',
  763. BTN_GO: 'Погнали!',
  764. PERFORMED: 'Выполняется',
  765. DONE: 'Выполнено',
  766. ERRORS_OCCURRES: 'Призошли ошибки при выполнении',
  767. COPY_ERROR: 'Скопировать в буфер информацию об ошибке',
  768. BTN_YES: 'Да',
  769. ALL_TASK_COMPLETED: 'Все задачи выполнены',
  770. UNKNOWN: 'Неизвестно',
  771. ENTER_THE_PATH: 'Введите путь приключения через запятые или дефисы',
  772. START_ADVENTURE: 'Начать приключение по этому пути!',
  773. INCORRECT_WAY: 'Неверный путь в приключении: {from} -> {to}',
  774. BTN_CANCELED: 'Отменено',
  775. MUST_TWO_POINTS: 'Путь должен состоять минимум из 2х точек',
  776. MUST_ONLY_NUMBERS: 'Путь должен содержать только цифры и запятые',
  777. NOT_ON_AN_ADVENTURE: 'Вы не в приключении',
  778. YOU_IN_NOT_ON_THE_WAY: 'Указанный путь должен включать точку вашего положения',
  779. ATTEMPTS_NOT_ENOUGH: 'Ваших попыток не достаточно для завершения пути, продолжить?',
  780. YES_CONTINUE: 'Да, продолжай!',
  781. NOT_ENOUGH_AP: 'Попыток не достаточно',
  782. ATTEMPTS_ARE_OVER: 'Попытки закончились',
  783. MOVES: 'Ходы',
  784. BUFF_GET_ERROR: 'Ошибка при получении бафа',
  785. BATTLE_END_ERROR: 'Ошибка завершения боя',
  786. AUTOBOT: 'АвтоБой',
  787. FAILED_TO_WIN_AUTO: 'Не удалось победить в автобою',
  788. ERROR_OF_THE_BATTLE_COPY: 'Призошли ошибка в процессе прохождения боя<br>Скопировать ошибку в буфер обмена?',
  789. ERROR_DURING_THE_BATTLE: 'Ошибка в процессе прохождения боя',
  790. NO_CHANCE_WIN: 'Нет шансов победить в этом бою: 0/',
  791. LOST_HEROES: 'Вы победили, но потеряли одного или несколько героев!',
  792. VICTORY_IMPOSSIBLE: 'Победа не возможна, бъем на результат?',
  793. FIND_COEFF: 'Поиск коэффициента больше чем',
  794. BTN_PASS: 'ПРОПУСК',
  795. BRAWLS: 'Потасовки',
  796. BRAWLS_TITLE: 'Включает возможность автопотасовок',
  797. START_AUTO_BRAWLS: 'Запустить Автопотасовки?',
  798. LOSSES: 'Поражений',
  799. WINS: 'Побед',
  800. FIGHTS: 'Боев',
  801. STAGE: 'Стадия',
  802. DONT_HAVE_LIVES: 'У Вас нет жизней',
  803. LIVES: 'Жизни',
  804. SECRET_WEALTH_ALREADY: 'товар за Зелья питомцев уже куплен',
  805. SECRET_WEALTH_NOT_ENOUGH: 'Не достаточно Зелье Питомца, у Вас {available}, нужно {need}',
  806. SECRET_WEALTH_UPGRADE_NEW_PET: 'После покупки Зелье Питомца будет не достаточно для прокачки нового питомца',
  807. SECRET_WEALTH_PURCHASED: 'Куплено {count} {name}',
  808. SECRET_WEALTH_CANCELED: 'Тайное богатство: покупка отменена',
  809. SECRET_WEALTH_BUY: 'У вас {available} Зелье Питомца.<br>Вы хотите купить {countBuy} {name} за {price} Зелье Питомца?',
  810. DAILY_BONUS: 'Ежедневная награда',
  811. DO_DAILY_QUESTS: 'Сделать ежедневные квесты',
  812. ACTIONS: 'Действия',
  813. ACTIONS_TITLE: 'Диалоговое окно с различными действиями',
  814. OTHERS: 'Разное',
  815. OTHERS_TITLE: 'Диалоговое окно с дополнительными различными действиями',
  816. CHOOSE_ACTION: 'Выберите действие',
  817. OPEN_LOOTBOX: 'У Вас {lootBox} ящиков, откываем?',
  818. STAMINA: 'Энергия',
  819. BOXES_OVER: 'Ящики закончились',
  820. NO_BOXES: 'Нет ящиков',
  821. NO_MORE_ACTIVITY: 'Больше активности за предметы сегодня не получить',
  822. EXCHANGE_ITEMS: 'Обменять предметы на очки активности (не более {maxActive})?',
  823. GET_ACTIVITY: 'Получить активность',
  824. NOT_ENOUGH_ITEMS: 'Предметов недостаточно',
  825. ACTIVITY_RECEIVED: 'Получено активности',
  826. NO_PURCHASABLE_HERO_SOULS: 'Нет доступных для покупки душ героев',
  827. PURCHASED_HERO_SOULS: 'Куплено {countHeroSouls} душ героев',
  828. NOT_ENOUGH_EMERALDS_540: 'Недостаточно изюма, нужно {imgEmerald}540 у Вас {imgEmerald}{currentStarMoney}',
  829. BUY_OUTLAND_BTN: 'Купить {count} сундуков {imgEmerald}{countEmerald}',
  830. CHESTS_NOT_AVAILABLE: 'Сундуки не доступны',
  831. OUTLAND_CHESTS_RECEIVED: 'Получено сундуков Запределья',
  832. RAID_NOT_AVAILABLE: 'Рейд не доступен или сфер нет',
  833. RAID_ADVENTURE: 'Рейд {adventureId} приключения!',
  834. SOMETHING_WENT_WRONG: 'Что-то пошло не так',
  835. ADVENTURE_COMPLETED: 'Приключение {adventureId} пройдено {times} раз',
  836. CLAN_STAT_COPY: 'Клановая статистика скопирована в буфер обмена',
  837. GET_ENERGY: 'Получить энергию',
  838. GET_ENERGY_TITLE: 'Открывает платиновые шкатулки по одной до получения 250 энергии',
  839. ITEM_EXCHANGE: 'Обмен предметов',
  840. ITEM_EXCHANGE_TITLE: 'Обменивает предметы на указанное количество активности',
  841. BUY_SOULS: 'Купить души',
  842. BUY_SOULS_TITLE: 'Купить души героев из всех доступных магазинов',
  843. BUY_OUTLAND: 'Купить Запределье',
  844. BUY_OUTLAND_TITLE: 'Купить 9 сундуков в Запределье за 540 изумрудов',
  845. RAID: 'Рейд',
  846. AUTO_RAID_ADVENTURE: 'Рейд',
  847. AUTO_RAID_ADVENTURE_TITLE: 'Рейд приключения заданное количество раз',
  848. CLAN_STAT: 'Клановая статистика',
  849. CLAN_STAT_TITLE: 'Копирует клановую статистику в буфер обмена',
  850. BTN_AUTO_F5: 'Авто (F5)',
  851. BOSS_DAMAGE: 'Урон по боссу: ',
  852. NOTHING_BUY: 'Нечего покупать',
  853. LOTS_BOUGHT: 'За золото куплено {countBuy} лотов',
  854. BUY_FOR_GOLD: 'Скупить за золото',
  855. BUY_FOR_GOLD_TITLE: 'Скупить предметы за золото в Городской лавке и в магазине Камней Душ Питомцев',
  856. REWARDS_AND_MAIL: 'Награды и почта',
  857. REWARDS_AND_MAIL_TITLE: 'Собирает награды и почту',
  858. COLLECT_REWARDS_AND_MAIL: 'Собрано {countQuests} наград и {countMail} писем',
  859. TIMER_ALREADY: 'Таймер уже запущен {time}',
  860. NO_ATTEMPTS_TIMER_START: 'Попыток нет, запущен таймер {time}',
  861. EPIC_BRAWL_R###LT: '{i} Победы: {wins}/{attempts}, Монеты: {coins}, Серия: {progress}/{nextStage} [Закрыть]{end}',
  862. ATTEMPT_ENDED: '<br>Попытки закончились, запущен таймер {time}',
  863. EPIC_BRAWL: 'Вселенская битва',
  864. EPIC_BRAWL_TITLE: 'Тратит попытки во Вселенской битве',
  865. RELOAD_GAME: 'Перезагрузить игру',
  866. TIMER: 'Таймер:',
  867. SHOW_ERRORS: 'Отображать ошибки',
  868. SHOW_ERRORS_TITLE: 'Отображать ошибки запросов к серверу',
  869. ERROR_MSG: 'Ошибка: {name}<br>{description}',
  870. EVENT_AUTO_BOSS:
  871. 'Максимальное количество боев для расчета:</br>{length} * {countTestBattle} = {maxCalcBattle}</br>Если у Вас слабый компьютер на это может потребоваться много времени, нажмите крестик для отмены.</br>Искать лучший пак из всех или первый подходящий?',
  872. BEST_SLOW: 'Лучший (медленее)',
  873. FIRST_FAST: 'Первый (быстрее)',
  874. FREEZE_INTERFACE: 'Идет расчет... <br> Интерфейс может зависнуть.',
  875. ERROR_F12: 'Ошибка, подробности в консоли (F12)',
  876. FAILED_FIND_WIN_PACK: 'Победный пак найти не удалось',
  877. BEST_PACK: 'Наилучший пак: ',
  878. BOSS_HAS_BEEN_DEF: 'Босс {bossLvl} побежден',
  879. NOT_ENOUGH_ATTEMPTS_BOSS: 'Для победы босса ${bossLvl} не хватило попыток, повторить?',
  880. BOSS_VICTORY_IMPOSSIBLE:
  881. 'По результатам прерасчета {battles} боев победу получить не удалось. Вы хотите продолжить поиск победного боя на реальных боях?',
  882. BOSS_HAS_BEEN_DEF_TEXT:
  883. 'Босс {bossLvl} побежден за<br>{countBattle}/{countMaxBattle} попыток{winTimer}<br>(Сделайте синхронизацию или перезагрузите игру для обновления данных)',
  884. MAP: 'Карта: ',
  885. PLAYER_POS: 'Позиции игроков:',
  886. NY_GIFTS: 'Подарки',
  887. NY_GIFTS_TITLE: 'Открыть все новогодние подарки',
  888. NY_NO_GIFTS: 'Нет не полученных подарков',
  889. NY_GIFTS_COLLECTED: 'Собрано {count} подарков',
  890. CHANGE_MAP: 'Карта острова',
  891. CHANGE_MAP_TITLE: 'Сменить карту острова',
  892. SELECT_ISLAND_MAP: 'Выберите карту острова:',
  893. MAP_NUM: 'Карта {num}',
  894. SECRET_WEALTH_SHOP: 'Тайное богатство {name}: ',
  895. SHOPS: 'Магазины',
  896. SHOPS_DEFAULT: 'Стандартные',
  897. SHOPS_DEFAULT_TITLE: 'Стандартные магазины',
  898. SHOPS_LIST: 'Магазины {number}',
  899. SHOPS_LIST_TITLE: 'Список магазинов {number}',
  900. SHOPS_WARNING:
  901. 'Магазины<br><span style="color:red">Если Вы купите монеты магазинов потасовок за изумруды, то их надо использовать сразу, иначе после перезагрузки игры они пропадут!</span>',
  902. MINIONS_WARNING: 'Пачки героев для атаки приспешников неполные, продолжить?',
  903. FAST_SEASON: 'Быстрый сезон',
  904. FAST_SEASON_TITLE: 'Пропуск экрана с выбором карты в сезоне',
  905. SET_NUMBER_LEVELS: 'Указать колличество уровней:',
  906. POSSIBLE_IMPROVE_LEVELS: 'Возможно улучшить только {count} уровней.<br>Улучшаем?',
  907. NOT_ENOUGH_RESOURECES: 'Не хватает ресурсов',
  908. IMPROVED_LEVELS: 'Улучшено уровней: {count}',
  909. ARTIFACTS_UPGRADE: 'Улучшение артефактов',
  910. ARTIFACTS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых артефактов героев',
  911. SKINS_UPGRADE: 'Улучшение обликов',
  912. SKINS_UPGRADE_TITLE: 'Улучшает указанное количество самых дешевых обликов героев',
  913. HINT: '<br>Подсказка: ',
  914. PICTURE: '<br>На картинке: ',
  915. ANSWER: '<br>Ответ: ',
  916. NO_HEROES_PACK: 'Проведите хотя бы один бой для сохранения атакующей команды',
  917. BRAWL_AUTO_PACK: 'Автоподбор пачки',
  918. BRAWL_AUTO_PACK_NOT_CUR_HERO: 'Автоматический подбор пачки не подходит для текущего героя',
  919. BRAWL_DAILY_TASK_COMPLETED: 'Ежедневное задание выполнено, продолжить атаку?',
  920. CALC_STAT: 'Посчитать статистику',
  921. ELEMENT_TOURNAMENT_REWARD: 'Несобранная награда за Турнир Стихий',
  922. BTN_TRY_FIX_IT: 'Исправить',
  923. BTN_TRY_FIX_IT_TITLE: 'Включить исправление боев при автоатаке',
  924. DAMAGE_FIXED: 'Урон исправлен с {lastDamage} до {maxDamage}!',
  925. DAMAGE_NO_FIXED: 'Не удалось исправить урон: {lastDamage}',
  926. LETS_FIX: 'Исправляем',
  927. COUNT_FIXED: 'За {count} попыток',
  928. DEFEAT_TURN_TIMER: 'Поражение! Включить таймер для завершения миссии?',
  929. SEASON_REWARD: 'Награды сезонов',
  930. SEASON_REWARD_TITLE: 'Собирает доступные бесплатные награды со всех текущих сезонов',
  931. SEASON_REWARD_COLLECTED: 'Собрано {count} наград сезонов',
  932. SELL_HERO_SOULS: 'Продать души',
  933. SELL_HERO_SOULS_TITLE: 'Обменивает все души героев с абсолютной звездой на золото',
  934. GOLD_RECEIVED: 'Получено золота: {gold}',
  935. OPEN_ALL_EQUIP_BOXES: 'Открыть все ящики фрагментов экипировки?',
  936. SERVER_NOT_ACCEPT: 'Сервер не принял результат',
  937. INVASION_BOSS_BUFF: 'Для {bossLvl} босса нужен баф {needBuff} у вас {haveBuff}',
  938. HERO_POWER: 'Сила героев',
  939. HERO_POWER_TITLE: 'Отображает текущую и максимальную силу героев',
  940. MAX_POWER_REACHED: 'Максимальная достигнутая мощь: {power}',
  941. CURRENT_POWER: 'Текущая мощь: {power}',
  942. POWER_TO_MAX: 'До максимума мощи осталось: <span style="color:{color};">{power}</span><br>',
  943. BEST_R###LT: 'Лучший результат: {value}%',
  944. GUILD_ISLAND_TITLE: 'Перейти к Острову гильдии',
  945. TITAN_VALLEY_TITLE: 'Перейти к Долине титанов',
  946. },
  947. };
  948. function getLang() {
  949. let lang = '';
  950. if (typeof NXFlashVars !== 'undefined') {
  951. lang = NXFlashVars.interface_lang
  952. }
  953. if (!lang) {
  954. lang = (navigator.language || navigator.userLanguage).substr(0, 2);
  955. }
  956. if (lang == 'ru') {
  957. return lang;
  958. }
  959. return 'en';
  960. }
  961. this.I18N = function (constant, replace) {
  962. const selectLang = getLang();
  963. if (constant && constant in i18nLangData[selectLang]) {
  964. const r###lt = i18nLangData[selectLang][constant];
  965. if (replace) {
  966. return r###lt.sprintf(replace);
  967. }
  968. return r###lt;
  969. }
  970. return `% ${constant} %`;
  971. };
  972. String.prototype.sprintf = String.prototype.sprintf ||
  973. function () {
  974. "use strict";
  975. var str = this.toString();
  976. if (arguments.length) {
  977. var t = typeof arguments[0];
  978. var key;
  979. var args = ("string" === t || "number" === t) ?
  980. Array.prototype.slice.call(arguments)
  981. : arguments[0];
  982. for (key in args) {
  983. str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
  984. }
  985. }
  986. return str;
  987. };
  988. /**
  989. * Checkboxes
  990. *
  991. * Чекбоксы
  992. */
  993. const checkboxes = {
  994. passBattle: {
  995. label: I18N('SKIP_FIGHTS'),
  996. cbox: null,
  997. title: I18N('SKIP_FIGHTS_TITLE'),
  998. default: false,
  999. },
  1000. sendExpedition: {
  1001. label: I18N('AUTO_EXPEDITION'),
  1002. cbox: null,
  1003. title: I18N('AUTO_EXPEDITION_TITLE'),
  1004. default: false,
  1005. },
  1006. cancelBattle: {
  1007. label: I18N('CANCEL_FIGHT'),
  1008. cbox: null,
  1009. title: I18N('CANCEL_FIGHT_TITLE'),
  1010. default: false,
  1011. },
  1012. preCalcBattle: {
  1013. label: I18N('BATTLE_RECALCULATION'),
  1014. cbox: null,
  1015. title: I18N('BATTLE_RECALCULATION_TITLE'),
  1016. default: false,
  1017. },
  1018. countControl: {
  1019. label: I18N('QUANTITY_CONTROL'),
  1020. cbox: null,
  1021. title: I18N('QUANTITY_CONTROL_TITLE'),
  1022. default: true,
  1023. },
  1024. repeatMission: {
  1025. label: I18N('REPEAT_CAMPAIGN'),
  1026. cbox: null,
  1027. title: I18N('REPEAT_CAMPAIGN_TITLE'),
  1028. default: false,
  1029. },
  1030. noOfferDonat: {
  1031. label: I18N('DISABLE_DONAT'),
  1032. cbox: null,
  1033. title: I18N('DISABLE_DONAT_TITLE'),
  1034. /**
  1035. * A crutch to get the field before getting the character id
  1036. *
  1037. * Костыль чтоб получать поле до получения id персонажа
  1038. */
  1039. default: (() => {
  1040. $r###lt = false;
  1041. try {
  1042. $r###lt = JSON.parse(localStorage[GM_info.script.name + ':noOfferDonat']);
  1043. } catch (e) {
  1044. $r###lt = false;
  1045. }
  1046. return $r###lt || false;
  1047. })(),
  1048. },
  1049. dailyQuests: {
  1050. label: I18N('DAILY_QUESTS'),
  1051. cbox: null,
  1052. title: I18N('DAILY_QUESTS_TITLE'),
  1053. default: false,
  1054. },
  1055. // Потасовки
  1056. autoBrawls: {
  1057. label: I18N('BRAWLS'),
  1058. cbox: null,
  1059. title: I18N('BRAWLS_TITLE'),
  1060. default: (() => {
  1061. $r###lt = false;
  1062. try {
  1063. $r###lt = JSON.parse(localStorage[GM_info.script.name + ':autoBrawls']);
  1064. } catch (e) {
  1065. $r###lt = false;
  1066. }
  1067. return $r###lt || false;
  1068. })(),
  1069. hide: false,
  1070. },
  1071. getAnswer: {
  1072. label: I18N('AUTO_QUIZ'),
  1073. cbox: null,
  1074. title: I18N('AUTO_QUIZ_TITLE'),
  1075. default: false,
  1076. hide: false,
  1077. },
  1078. tryFixIt_v2: {
  1079. label: I18N('BTN_TRY_FIX_IT'),
  1080. cbox: null,
  1081. title: I18N('BTN_TRY_FIX_IT_TITLE'),
  1082. default: false,
  1083. hide: false,
  1084. },
  1085. showErrors: {
  1086. label: I18N('SHOW_ERRORS'),
  1087. cbox: null,
  1088. title: I18N('SHOW_ERRORS_TITLE'),
  1089. default: true,
  1090. },
  1091. buyForGold: {
  1092. label: I18N('BUY_FOR_GOLD'),
  1093. cbox: null,
  1094. title: I18N('BUY_FOR_GOLD_TITLE'),
  1095. default: false,
  1096. },
  1097. hideServers: {
  1098. label: I18N('HIDE_SERVERS'),
  1099. cbox: null,
  1100. title: I18N('HIDE_SERVERS_TITLE'),
  1101. default: false,
  1102. },
  1103. fastSeason: {
  1104. label: I18N('FAST_SEASON'),
  1105. cbox: null,
  1106. title: I18N('FAST_SEASON_TITLE'),
  1107. default: false,
  1108. },
  1109. };
  1110. /**
  1111. * Get checkbox state
  1112. *
  1113. * Получить состояние чекбокса
  1114. */
  1115. function isChecked(checkBox) {
  1116. if (!(checkBox in checkboxes)) {
  1117. return false;
  1118. }
  1119. return checkboxes[checkBox].cbox?.checked;
  1120. }
  1121. /**
  1122. * Input fields
  1123. *
  1124. * Поля ввода
  1125. */
  1126. const inputs = {
  1127. countTitanit: {
  1128. input: null,
  1129. title: I18N('HOW_MUCH_TITANITE'),
  1130. default: 150,
  1131. },
  1132. speedBattle: {
  1133. input: null,
  1134. title: I18N('COMBAT_SPEED'),
  1135. default: 5,
  1136. },
  1137. countTestBattle: {
  1138. input: null,
  1139. title: I18N('NUMBER_OF_TEST'),
  1140. default: 10,
  1141. },
  1142. countAutoBattle: {
  1143. input: null,
  1144. title: I18N('NUMBER_OF_AUTO_BATTLE'),
  1145. default: 10,
  1146. },
  1147. FPS: {
  1148. input: null,
  1149. title: 'FPS',
  1150. default: 60,
  1151. }
  1152. }
  1153. /**
  1154. * Checks the checkbox
  1155. *
  1156. * Поплучить данные поля ввода
  1157. */
  1158. function getInput(inputName) {
  1159. return inputs[inputName]?.input?.value;
  1160. }
  1161. /**
  1162. * Control FPS
  1163. *
  1164. * Контроль FPS
  1165. */
  1166. let nextAnimationFrame = Date.now();
  1167. const oldRequestAnimationFrame = this.requestAnimationFrame;
  1168. this.requestAnimationFrame = async function (e) {
  1169. const FPS = Number(getInput('FPS')) || -1;
  1170. const now = Date.now();
  1171. const delay = nextAnimationFrame - now;
  1172. nextAnimationFrame = Math.max(now, nextAnimationFrame) + Math.min(1e3 / FPS, 1e3);
  1173. if (delay > 0) {
  1174. await new Promise((e) => setTimeout(e, delay));
  1175. }
  1176. oldRequestAnimationFrame(e);
  1177. };
  1178. /**
  1179. * Button List
  1180. *
  1181. * Список кнопочек
  1182. */
  1183. const buttons = {
  1184. getOutland: {
  1185. name: I18N('TO_DO_EVERYTHING'),
  1186. title: I18N('TO_DO_EVERYTHING_TITLE'),
  1187. onClick: testDoYourBest,
  1188. },
  1189. doActions: {
  1190. name: I18N('ACTIONS'),
  1191. title: I18N('ACTIONS_TITLE'),
  1192. onClick: async function () {
  1193. const popupButtons = [
  1194. {
  1195. msg: I18N('OUTLAND'),
  1196. r###lt: function () {
  1197. confShow(`${I18N('RUN_SCRIPT')} ${I18N('OUTLAND')}?`, getOutland);
  1198. },
  1199. title: I18N('OUTLAND_TITLE'),
  1200. },
  1201. {
  1202. msg: I18N('TOWER'),
  1203. r###lt: function () {
  1204. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TOWER')}?`, testTower);
  1205. },
  1206. title: I18N('TOWER_TITLE'),
  1207. },
  1208. {
  1209. msg: I18N('EXPEDITIONS'),
  1210. r###lt: function () {
  1211. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EXPEDITIONS')}?`, checkExpedition);
  1212. },
  1213. title: I18N('EXPEDITIONS_TITLE'),
  1214. },
  1215. {
  1216. msg: I18N('MINIONS'),
  1217. r###lt: function () {
  1218. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MINIONS')}?`, testRaidNodes);
  1219. },
  1220. title: I18N('MINIONS_TITLE'),
  1221. },
  1222. {
  1223. msg: I18N('ESTER_EGGS'),
  1224. r###lt: function () {
  1225. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ESTER_EGGS')}?`, offerFarmAllReward);
  1226. },
  1227. title: I18N('ESTER_EGGS_TITLE'),
  1228. },
  1229. {
  1230. msg: I18N('STORM'),
  1231. r###lt: function () {
  1232. testAdventure('solo');
  1233. },
  1234. title: I18N('STORM_TITLE'),
  1235. },
  1236. {
  1237. msg: I18N('REWARDS'),
  1238. r###lt: function () {
  1239. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS')}?`, questAllFarm);
  1240. },
  1241. title: I18N('REWARDS_TITLE'),
  1242. },
  1243. {
  1244. msg: I18N('MAIL'),
  1245. r###lt: function () {
  1246. confShow(`${I18N('RUN_SCRIPT')} ${I18N('MAIL')}?`, mailGetAll);
  1247. },
  1248. title: I18N('MAIL_TITLE'),
  1249. },
  1250. {
  1251. msg: I18N('SEER'),
  1252. r###lt: function () {
  1253. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SEER')}?`, rollAscension);
  1254. },
  1255. title: I18N('SEER_TITLE'),
  1256. },
  1257. /*
  1258. {
  1259. msg: I18N('NY_GIFTS'),
  1260. r###lt: getGiftNewYear,
  1261. title: I18N('NY_GIFTS_TITLE'),
  1262. },
  1263. */
  1264. ];
  1265. popupButtons.push({ r###lt: false, isClose: true });
  1266. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1267. if (typeof answer === 'function') {
  1268. answer();
  1269. }
  1270. },
  1271. },
  1272. doOthers: {
  1273. name: I18N('OTHERS'),
  1274. title: I18N('OTHERS_TITLE'),
  1275. onClick: async function () {
  1276. const popupButtons = [
  1277. {
  1278. msg: I18N('GET_ENERGY'),
  1279. r###lt: farmStamina,
  1280. title: I18N('GET_ENERGY_TITLE'),
  1281. },
  1282. {
  1283. msg: I18N('ITEM_EXCHANGE'),
  1284. r###lt: fillActive,
  1285. title: I18N('ITEM_EXCHANGE_TITLE'),
  1286. },
  1287. {
  1288. msg: I18N('BUY_SOULS'),
  1289. r###lt: function () {
  1290. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_SOULS')}?`, buyHeroFragments);
  1291. },
  1292. title: I18N('BUY_SOULS_TITLE'),
  1293. },
  1294. {
  1295. msg: I18N('BUY_FOR_GOLD'),
  1296. r###lt: function () {
  1297. confShow(`${I18N('RUN_SCRIPT')} ${I18N('BUY_FOR_GOLD')}?`, buyInStoreForGold);
  1298. },
  1299. title: I18N('BUY_FOR_GOLD_TITLE'),
  1300. },
  1301. {
  1302. msg: I18N('BUY_OUTLAND'),
  1303. r###lt: bossOpenChestPay,
  1304. title: I18N('BUY_OUTLAND_TITLE'),
  1305. },
  1306. {
  1307. msg: I18N('CLAN_STAT'),
  1308. r###lt: clanStatistic,
  1309. title: I18N('CLAN_STAT_TITLE'),
  1310. },
  1311. {
  1312. msg: I18N('EPIC_BRAWL'),
  1313. r###lt: async function () {
  1314. confShow(`${I18N('RUN_SCRIPT')} ${I18N('EPIC_BRAWL')}?`, () => {
  1315. const brawl = new epicBrawl();
  1316. brawl.start();
  1317. });
  1318. },
  1319. title: I18N('EPIC_BRAWL_TITLE'),
  1320. },
  1321. {
  1322. msg: I18N('ARTIFACTS_UPGRADE'),
  1323. r###lt: updateArtifacts,
  1324. title: I18N('ARTIFACTS_UPGRADE_TITLE'),
  1325. },
  1326. {
  1327. msg: I18N('SKINS_UPGRADE'),
  1328. r###lt: updateSkins,
  1329. title: I18N('SKINS_UPGRADE_TITLE'),
  1330. },
  1331. {
  1332. msg: I18N('SEASON_REWARD'),
  1333. r###lt: farmBattlePass,
  1334. title: I18N('SEASON_REWARD_TITLE'),
  1335. },
  1336. {
  1337. msg: I18N('SELL_HERO_SOULS'),
  1338. r###lt: sellHeroSoulsForGold,
  1339. title: I18N('SELL_HERO_SOULS_TITLE'),
  1340. },
  1341. {
  1342. msg: I18N('CHANGE_MAP'),
  1343. r###lt: async function () {
  1344. const maps = Object.values(lib.data.seasonAdventure.list)
  1345. .filter((e) => e.map.cells.length > 2)
  1346. .map((i) => ({
  1347. msg: I18N('MAP_NUM', { num: i.id }),
  1348. r###lt: i.id,
  1349. }));
  1350. const r###lt = await popup.confirm(I18N('SELECT_ISLAND_MAP'), [...maps, { r###lt: false, isClose: true }]);
  1351. if (r###lt) {
  1352. cheats.changeIslandMap(r###lt);
  1353. }
  1354. },
  1355. title: I18N('CHANGE_MAP_TITLE'),
  1356. },
  1357. {
  1358. msg: I18N('HERO_POWER'),
  1359. r###lt: async () => {
  1360. const calls = ['userGetInfo', 'heroGetAll'].map((name) => ({
  1361. name,
  1362. args: {},
  1363. ident: name,
  1364. }));
  1365. const [maxHeroSumPower, heroSumPower] = await Send({ calls }).then((e) => [
  1366. e.r###lts[0].r###lt.response.maxSumPower.heroes,
  1367. Object.values(e.r###lts[1].r###lt.response).reduce((a, e) => a + e.power, 0),
  1368. ]);
  1369. const power = maxHeroSumPower - heroSumPower;
  1370. let msg =
  1371. I18N('MAX_POWER_REACHED', { power: maxHeroSumPower.toLocaleString() }) +
  1372. '<br>' +
  1373. I18N('CURRENT_POWER', { power: heroSumPower.toLocaleString() }) +
  1374. '<br>' +
  1375. I18N('POWER_TO_MAX', { power: power.toLocaleString(), color: power >= 4000 ? 'green' : 'red' });
  1376. await popup.confirm(msg, [{ msg: I18N('BTN_OK'), r###lt: 0 }]);
  1377. },
  1378. title: I18N('HERO_POWER_TITLE'),
  1379. },
  1380. ];
  1381. popupButtons.push({ r###lt: false, isClose: true });
  1382. const answer = await popup.confirm(`${I18N('CHOOSE_ACTION')}:`, popupButtons);
  1383. if (typeof answer === 'function') {
  1384. answer();
  1385. }
  1386. },
  1387. },
  1388. testTitanArena: {
  1389. isCombine: true,
  1390. combineList: [
  1391. {
  1392. name: I18N('TITAN_ARENA'),
  1393. title: I18N('TITAN_ARENA_TITLE'),
  1394. onClick: function () {
  1395. confShow(`${I18N('RUN_SCRIPT')} ${I18N('TITAN_ARENA')}?`, testTitanArena);
  1396. },
  1397. },
  1398. {
  1399. name: '>>',
  1400. onClick: cheats.goTitanValley,
  1401. title: I18N('TITAN_VALLEY_TITLE'),
  1402. color: 'green',
  1403. },
  1404. ],
  1405. },
  1406. testDungeon: {
  1407. isCombine: true,
  1408. combineList: [
  1409. {
  1410. name: I18N('DUNGEON'),
  1411. onClick: function () {
  1412. confShow(`${I18N('RUN_SCRIPT')} ${I18N('DUNGEON')}?`, testDungeon);
  1413. },
  1414. title: I18N('DUNGEON_TITLE'),
  1415. },
  1416. {
  1417. name: '>>',
  1418. onClick: cheats.goClanIsland,
  1419. title: I18N('GUILD_ISLAND_TITLE'),
  1420. color: 'green',
  1421. },
  1422. ],
  1423. },
  1424. testAdventure: {
  1425. isCombine: true,
  1426. combineList: [
  1427. {
  1428. name: I18N('ADVENTURE'),
  1429. onClick: () => {
  1430. testAdventure();
  1431. },
  1432. title: I18N('ADVENTURE_TITLE'),
  1433. },
  1434. {
  1435. name: I18N('AUTO_RAID_ADVENTURE'),
  1436. onClick: autoRaidAdventure,
  1437. title: I18N('AUTO_RAID_ADVENTURE_TITLE'),
  1438. },
  1439. {
  1440. name: '>>',
  1441. onClick: cheats.goSanctuary,
  1442. title: I18N('SANCTUARY_TITLE'),
  1443. color: 'green',
  1444. },
  1445. ],
  1446. },
  1447. rewardsAndMailFarm: {
  1448. name: I18N('REWARDS_AND_MAIL'),
  1449. title: I18N('REWARDS_AND_MAIL_TITLE'),
  1450. onClick: function () {
  1451. confShow(`${I18N('RUN_SCRIPT')} ${I18N('REWARDS_AND_MAIL')}?`, rewardsAndMailFarm);
  1452. },
  1453. },
  1454. goToClanWar: {
  1455. name: I18N('GUILD_WAR'),
  1456. title: I18N('GUILD_WAR_TITLE'),
  1457. onClick: cheats.goClanWar,
  1458. dot: true,
  1459. },
  1460. dailyQuests: {
  1461. name: I18N('DAILY_QUESTS'),
  1462. title: I18N('DAILY_QUESTS_TITLE'),
  1463. onClick: async function () {
  1464. const quests = new dailyQuests(
  1465. () => {},
  1466. () => {}
  1467. );
  1468. await quests.autoInit();
  1469. quests.start();
  1470. },
  1471. },
  1472. newDay: {
  1473. name: I18N('SYNC'),
  1474. title: I18N('SYNC_TITLE'),
  1475. onClick: function () {
  1476. confShow(`${I18N('RUN_SCRIPT')} ${I18N('SYNC')}?`, cheats.refreshGame);
  1477. },
  1478. },
  1479. // Архидемон
  1480. bossRatingEventDemon: {
  1481. name: I18N('ARCHDEMON'),
  1482. title: I18N('ARCHDEMON_TITLE'),
  1483. onClick: function () {
  1484. confShow(`${I18N('RUN_SCRIPT')} ${I18N('ARCHDEMON')}?`, bossRatingEvent);
  1485. },
  1486. hide: false,
  1487. color: 'red',
  1488. },
  1489. // Горнило душ
  1490. bossRatingEventSouls: {
  1491. name: I18N('FURNACE_OF_SOULS'),
  1492. title: I18N('ARCHDEMON_TITLE'),
  1493. onClick: function () {
  1494. confShow(`${I18N('RUN_SCRIPT')} ${I18N('FURNACE_OF_SOULS')}?`, bossRatingEventSouls);
  1495. },
  1496. hide: true,
  1497. color: 'red',
  1498. },
  1499. };
  1500. /**
  1501. * Display buttons
  1502. *
  1503. * Вывести кнопочки
  1504. */
  1505. function addControlButtons() {
  1506. for (let name in buttons) {
  1507. button = buttons[name];
  1508. if (button.hide) {
  1509. continue;
  1510. }
  1511. if (button.isCombine) {
  1512. button['button'] = scriptMenu.addCombinedButton(button.combineList);
  1513. continue;
  1514. }
  1515. button['button'] = scriptMenu.addButton(button);
  1516. }
  1517. }
  1518. /**
  1519. * Adds links
  1520. *
  1521. * Добавляет ссылки
  1522. */
  1523. function addBottomUrls() {
  1524. scriptMenu.addHeader(I18N('BOTTOM_URLS'));
  1525. }
  1526. /**
  1527. * Stop repetition of the mission
  1528. *
  1529. * Остановить повтор миссии
  1530. */
  1531. let isStopSendMission = false;
  1532. /**
  1533. * There is a repetition of the mission
  1534. *
  1535. * Идет повтор миссии
  1536. */
  1537. let isSendsMission = false;
  1538. /**
  1539. * Data on the past mission
  1540. *
  1541. * Данные о прошедшей мисии
  1542. */
  1543. let lastMissionStart = {}
  1544. /**
  1545. * Start time of the last battle in the company
  1546. *
  1547. * Время начала последнего боя в кампании
  1548. */
  1549. let lastMissionBattleStart = 0;
  1550. /**
  1551. * Data for calculating the last battle with the boss
  1552. *
  1553. * Данные для расчете последнего боя с боссом
  1554. */
  1555. let lastBossBattle = null;
  1556. /**
  1557. * Information about the last battle
  1558. *
  1559. * Данные о прошедшей битве
  1560. */
  1561. let lastBattleArg = {}
  1562. let lastBossBattleStart = null;
  1563. this.addBattleTimer = 4;
  1564. this.invasionTimer = 2500;
  1565. const invasionInfo = {
  1566. id: 225,
  1567. buff: 0,
  1568. bossLvl: 130,
  1569. };
  1570. const invasionDataPacks = {
  1571. 130: { buff: 0, pet: 6005, heroes: [9, 62, 10, 1, 66], favor: { 9: 6006 } },
  1572. 140: { buff: 0, pet: 6005, heroes: [9, 62, 10, 1, 66], favor: {} },
  1573. 150: { buff: 0, pet: 6005, heroes: [9, 62, 10, 1, 66], favor: {} },
  1574. 160: { buff: 0, pet: 6005, heroes: [64, 66, 13, 9, 4], favor: { 4: 6006, 9: 6004, 13: 6003, 64: 6005, 66: 6002 } },
  1575. 170: { buff: 0, pet: 6005, heroes: [9, 62, 10, 1, 66], favor: { 1: 6006, 9: 6005, 10: 6008, 62: 6003, 66: 6002 } },
  1576. 180: { buff: 0, pet: 6006, heroes: [62, 10, 2, 4, 66], favor: { 2: 6005, 4: 6001, 10: 6006, 62: 6003 } },
  1577. 190: { buff: 40, pet: 6005, heroes: [9, 2, 43, 45, 66], favor: { 9: 6005, 45: 6002, 66: 6006 } },
  1578. 200: { buff: 20, pet: 6005, heroes: [9, 62, 1, 48, 66], favor: { 9: 6007, 62: 6003 } },
  1579. 210: { buff: 10, pet: 6008, heroes: [9, 10, 4, 32, 66], favor: { 9: 6005, 10: 6003, 32: 6007, 66: 6006 } },
  1580. 220: { buff: 20, pet: 6004, heroes: [9, 1, 48, 43, 66], favor: { 9: 6005, 43: 6006, 48: 6000, 66: 6002 } },
  1581. 230: { buff: 45, pet: 6001, heroes: [9, 7, 40, 43, 66], favor: { 7: 6006, 9: 6005, 40: 6004, 43: 6006, 66: 6006 } },
  1582. 240: { buff: 50, pet: 6009, heroes: [9, 40, 43, 51, 66], favor: { 9: 6005, 40: 6004, 43: 6002, 66: 6007 } },
  1583. 250: { buff: 70, pet: 6005, heroes: [9, 10, 13, 43, 66], favor: { 9: 6005, 10: 6002, 13: 6002, 43: 6006, 66: 6006 } },
  1584. 260: { buff: 80, pet: 6008, heroes: [9, 40, 43, 4, 66], favor: { 4: 6001, 9: 6006, 43: 6006 } },
  1585. 270: { buff: 115, pet: 6001, heroes: [9, 13, 43, 51, 66], favor: { 9: 6006, 43: 6006, 51: 6001 } },
  1586. 280: { buff: 80, pet: 6008, heroes: [9, 13, 43, 56, 66], favor: { 9: 6004, 13: 6006, 43: 6006, 66: 6006 } },
  1587. 290: { buff: 60, pet: 6005, heroes: [9, 10, 43, 56, 66], favor: { 9: 6005, 10: 6002, 43: 6006 } },
  1588. 300: { buff: 75, pet: 6006, heroes: [9, 62, 1, 45, 66], favor: { 1: 6006, 9: 6005, 45: 6002, 66: 6007 } },
  1589. };
  1590. /**
  1591. * The name of the function of the beginning of the battle
  1592. *
  1593. * Имя функции начала боя
  1594. */
  1595. let nameFuncStartBattle = '';
  1596. /**
  1597. * The name of the function of the end of the battle
  1598. *
  1599. * Имя функции конца боя
  1600. */
  1601. let nameFuncEndBattle = '';
  1602. /**
  1603. * Data for calculating the last battle
  1604. *
  1605. * Данные для расчета последнего боя
  1606. */
  1607. let lastBattleInfo = null;
  1608. /**
  1609. * The ability to cancel the battle
  1610. *
  1611. * Возможность отменить бой
  1612. */
  1613. let isCancalBattle = true;
  1614. function setIsCancalBattle(value) {
  1615. isCancalBattle = value;
  1616. }
  1617. /**
  1618. * Certificator of the last open nesting doll
  1619. *
  1620. * Идетификатор последней открытой матрешки
  1621. */
  1622. let lastRussianDollId = null;
  1623. /**
  1624. * Cancel the training guide
  1625. *
  1626. * Отменить обучающее руководство
  1627. */
  1628. this.isCanceledTutorial = false;
  1629. /**
  1630. * Data from the last question of the quiz
  1631. *
  1632. * Данные последнего вопроса викторины
  1633. */
  1634. let lastQuestion = null;
  1635. /**
  1636. * Answer to the last question of the quiz
  1637. *
  1638. * Ответ на последний вопрос викторины
  1639. */
  1640. let lastAnswer = null;
  1641. /**
  1642. * Flag for opening keys or titan artifact spheres
  1643. *
  1644. * Флаг открытия ключей или сфер артефактов титанов
  1645. */
  1646. let artifactChestOpen = false;
  1647. /**
  1648. * The name of the function to open keys or orbs of titan artifacts
  1649. *
  1650. * Имя функции открытия ключей или сфер артефактов титанов
  1651. */
  1652. let artifactChestOpenCallName = '';
  1653. let correctShowOpenArtifact = 0;
  1654. /**
  1655. * Data for the last battle in the dungeon
  1656. * (Fix endless cards)
  1657. *
  1658. * Данные для последнего боя в подземке
  1659. * (Исправление бесконечных карт)
  1660. */
  1661. let lastDungeonBattleData = null;
  1662. /**
  1663. * Start time of the last battle in the dungeon
  1664. *
  1665. * Время начала последнего боя в подземелье
  1666. */
  1667. let lastDungeonBattleStart = 0;
  1668. /**
  1669. * Subscription end time
  1670. *
  1671. * Время окончания подписки
  1672. */
  1673. let subEndTime = 0;
  1674. /**
  1675. * Number of prediction cards
  1676. *
  1677. * Количество карт предсказаний
  1678. */
  1679. let countPredictionCard = 0;
  1680. /**
  1681. * Brawl pack
  1682. *
  1683. * Пачка для потасовок
  1684. */
  1685. let brawlsPack = null;
  1686. /**
  1687. * Autobrawl started
  1688. *
  1689. * Автопотасовка запущена
  1690. */
  1691. let isBrawlsAutoStart = false;
  1692. let clanDominationGetInfo = null;
  1693. /**
  1694. * Copies the text to the clipboard
  1695. *
  1696. * Копирует тест в буфер обмена
  1697. * @param {*} text copied text // копируемый текст
  1698. */
  1699. function copyText(text) {
  1700. let copyTextarea = document.createElement("textarea");
  1701. copyTextarea.style.opacity = "0";
  1702. copyTextarea.textContent = text;
  1703. document.body.appendChild(copyTextarea);
  1704. copyTextarea.select();
  1705. document.execCommand("copy");
  1706. document.body.removeChild(copyTextarea);
  1707. delete copyTextarea;
  1708. }
  1709. /**
  1710. * Returns the history of requests
  1711. *
  1712. * Возвращает историю запросов
  1713. */
  1714. this.getRequestHistory = function() {
  1715. return requestHistory;
  1716. }
  1717. /**
  1718. * Generates a random integer from min to max
  1719. *
  1720. * Гененирует случайное целое число от min до max
  1721. */
  1722. const random = function (min, max) {
  1723. return Math.floor(Math.random() * (max - min + 1) + min);
  1724. }
  1725. const randf = function (min, max) {
  1726. return Math.random() * (max - min + 1) + min;
  1727. };
  1728. /**
  1729. * Clearing the request history
  1730. *
  1731. * Очистка истоии запросов
  1732. */
  1733. setInterval(function () {
  1734. let now = Date.now();
  1735. for (let i in requestHistory) {
  1736. const time = +i.split('_')[0];
  1737. if (now - time > 300000) {
  1738. delete requestHistory[i];
  1739. }
  1740. }
  1741. }, 300000);
  1742. /**
  1743. * Displays the dialog box
  1744. *
  1745. * Отображает диалоговое окно
  1746. */
  1747. function confShow(message, yesCallback, noCallback) {
  1748. let buts = [];
  1749. message = message || I18N('DO_YOU_WANT');
  1750. noCallback = noCallback || (() => {});
  1751. if (yesCallback) {
  1752. buts = [
  1753. { msg: I18N('BTN_RUN'), r###lt: true},
  1754. { msg: I18N('BTN_CANCEL'), r###lt: false, isCancel: true},
  1755. ]
  1756. } else {
  1757. yesCallback = () => {};
  1758. buts = [
  1759. { msg: I18N('BTN_OK'), r###lt: true},
  1760. ];
  1761. }
  1762. popup.confirm(message, buts).then((e) => {
  1763. // dialogPromice = null;
  1764. if (e) {
  1765. yesCallback();
  1766. } else {
  1767. noCallback();
  1768. }
  1769. });
  1770. }
  1771. /**
  1772. * Override/proxy the method for creating a WS package send
  1773. *
  1774. * Переопределяем/проксируем метод создания отправки WS пакета
  1775. */
  1776. WebSocket.prototype.send = function (data) {
  1777. if (!this.isSetOnMessage) {
  1778. const oldOnmessage = this.onmessage;
  1779. this.onmessage = function (event) {
  1780. try {
  1781. const data = JSON.parse(event.data);
  1782. if (!this.isWebSocketLogin && data.r###lt.type == "iframeEvent.login") {
  1783. this.isWebSocketLogin = true;
  1784. } else if (data.r###lt.type == "iframeEvent.login") {
  1785. return;
  1786. }
  1787. } catch (e) { }
  1788. return oldOnmessage.apply(this, arguments);
  1789. }
  1790. this.isSetOnMessage = true;
  1791. }
  1792. original.SendWebSocket.call(this, data);
  1793. }
  1794. /**
  1795. * Overriding/Proxying the Ajax Request Creation Method
  1796. *
  1797. * Переопределяем/проксируем метод создания Ajax запроса
  1798. */
  1799. XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
  1800. this.uniqid = Date.now() + '_' + random(1000000, 10000000);
  1801. this.errorRequest = false;
  1802. if (method == 'POST' && url.includes('.nextersglobal.com/api/') && /api\/$/.test(url)) {
  1803. if (!apiUrl) {
  1804. apiUrl = url;
  1805. const socialInfo = /heroes-(.+?)\./.exec(apiUrl);
  1806. console.log(socialInfo);
  1807. }
  1808. requestHistory[this.uniqid] = {
  1809. method,
  1810. url,
  1811. error: [],
  1812. headers: {},
  1813. request: null,
  1814. response: null,
  1815. signature: [],
  1816. calls: {},
  1817. };
  1818. } else if (method == 'POST' && url.includes('error.nextersglobal.com/client/')) {
  1819. this.errorRequest = true;
  1820. }
  1821. return original.open.call(this, method, url, async, user, password);
  1822. };
  1823. /**
  1824. * Overriding/Proxying the header setting method for the AJAX request
  1825. *
  1826. * Переопределяем/проксируем метод установки заголовков для AJAX запроса
  1827. */
  1828. XMLHttpRequest.prototype.setRequestHeader = function (name, value, check) {
  1829. if (this.uniqid in requestHistory) {
  1830. requestHistory[this.uniqid].headers[name] = value;
  1831. } else {
  1832. check = true;
  1833. }
  1834. if (name == 'X-Auth-Signature') {
  1835. requestHistory[this.uniqid].signature.push(value);
  1836. if (!check) {
  1837. return;
  1838. }
  1839. }
  1840. return original.setRequestHeader.call(this, name, value);
  1841. };
  1842. /**
  1843. * Overriding/Proxying the AJAX Request Sending Method
  1844. *
  1845. * Переопределяем/проксируем метод отправки AJAX запроса
  1846. */
  1847. XMLHttpRequest.prototype.send = async function (sourceData) {
  1848. if (this.uniqid in requestHistory) {
  1849. let tempData = null;
  1850. if (getClass(sourceData) == "ArrayBuffer") {
  1851. tempData = decoder.decode(sourceData);
  1852. } else {
  1853. tempData = sourceData;
  1854. }
  1855. requestHistory[this.uniqid].request = tempData;
  1856. let headers = requestHistory[this.uniqid].headers;
  1857. lastHeaders = Object.assign({}, headers);
  1858. /**
  1859. * Game loading event
  1860. *
  1861. * Событие загрузки игры
  1862. */
  1863. if (headers["X-Request-Id"] > 2 && !isLoadGame) {
  1864. isLoadGame = true;
  1865. if (cheats.libGame) {
  1866. lib.setData(cheats.libGame);
  1867. } else {
  1868. lib.setData(await cheats.LibLoad());
  1869. }
  1870. addControls();
  1871. addControlButtons();
  1872. addBottomUrls();
  1873. if (isChecked('sendExpedition')) {
  1874. const isTimeBetweenDays = isTimeBetweenNewDays();
  1875. if (!isTimeBetweenDays) {
  1876. checkExpedition();
  1877. } else {
  1878. setProgress(I18N('EXPEDITIONS_NOTTIME'), true);
  1879. }
  1880. }
  1881. getAutoGifts();
  1882. cheats.activateHacks();
  1883. justInfo();
  1884. if (isChecked('dailyQuests')) {
  1885. testDailyQuests();
  1886. }
  1887. if (isChecked('buyForGold')) {
  1888. buyInStoreForGold();
  1889. }
  1890. }
  1891. /**
  1892. * Outgoing request data processing
  1893. *
  1894. * Обработка данных исходящего запроса
  1895. */
  1896. sourceData = await checkChangeSend.call(this, sourceData, tempData);
  1897. /**
  1898. * Handling incoming request data
  1899. *
  1900. * Обработка данных входящего запроса
  1901. */
  1902. const oldReady = this.onreadystatechange;
  1903. this.onreadystatechange = async function (e) {
  1904. if (this.errorRequest) {
  1905. return oldReady.apply(this, arguments);
  1906. }
  1907. if(this.readyState == 4 && this.status == 200) {
  1908. isTextResponse = this.responseType === "text" || this.responseType === "";
  1909. let response = isTextResponse ? this.responseText : this.response;
  1910. requestHistory[this.uniqid].response = response;
  1911. /**
  1912. * Replacing incoming request data
  1913. *
  1914. * Заменна данных входящего запроса
  1915. */
  1916. if (isTextResponse) {
  1917. await checkChangeResponse.call(this, response);
  1918. }
  1919. /**
  1920. * A function to run after the request is executed
  1921. *
  1922. * Функция запускаемая после выполения запроса
  1923. */
  1924. if (typeof this.onReadySuccess == 'function') {
  1925. setTimeout(this.onReadySuccess, 500);
  1926. }
  1927. /** Удаляем из истории запросов битвы с боссом */
  1928. if ('invasion_bossStart' in requestHistory[this.uniqid].calls) delete requestHistory[this.uniqid];
  1929. }
  1930. if (oldReady) {
  1931. try {
  1932. return oldReady.apply(this, arguments);
  1933. } catch(e) {
  1934. console.log(oldReady);
  1935. console.error('Error in oldReady:', e);
  1936. }
  1937. }
  1938. }
  1939. }
  1940. if (this.errorRequest) {
  1941. const oldReady = this.onreadystatechange;
  1942. this.onreadystatechange = function () {
  1943. Object.defineProperty(this, 'status', {
  1944. writable: true
  1945. });
  1946. this.status = 200;
  1947. Object.defineProperty(this, 'readyState', {
  1948. writable: true
  1949. });
  1950. this.readyState = 4;
  1951. Object.defineProperty(this, 'responseText', {
  1952. writable: true
  1953. });
  1954. this.responseText = JSON.stringify({
  1955. "r###lt": true
  1956. });
  1957. if (typeof this.onReadySuccess == 'function') {
  1958. setTimeout(this.onReadySuccess, 200);
  1959. }
  1960. return oldReady.apply(this, arguments);
  1961. }
  1962. this.onreadystatechange();
  1963. } else {
  1964. try {
  1965. return original.send.call(this, sourceData);
  1966. } catch(e) {
  1967. debugger;
  1968. }
  1969. }
  1970. };
  1971. /**
  1972. * Processing and substitution of outgoing data
  1973. *
  1974. * Обработка и подмена исходящих данных
  1975. */
  1976. async function checkChangeSend(sourceData, tempData) {
  1977. try {
  1978. /**
  1979. * A function that replaces battle data with incorrect ones to cancel combatя
  1980. *
  1981. * Функция заменяющая данные боя на неверные для отмены боя
  1982. */
  1983. const fixBattle = function (heroes) {
  1984. for (const ids in heroes) {
  1985. hero = heroes[ids];
  1986. hero.energy = random(1, 999);
  1987. if (hero.hp > 0) {
  1988. hero.hp = random(1, hero.hp);
  1989. }
  1990. }
  1991. }
  1992. /**
  1993. * Dialog window 2
  1994. *
  1995. * Диалоговое окно 2
  1996. */
  1997. const showMsg = async function (msg, ansF, ansS) {
  1998. if (typeof popup == 'object') {
  1999. return await popup.confirm(msg, [
  2000. {msg: ansF, r###lt: false},
  2001. {msg: ansS, r###lt: true},
  2002. ]);
  2003. } else {
  2004. return !confirm(`${msg}\n ${ansF} (${I18N('BTN_OK')})\n ${ansS} (${I18N('BTN_CANCEL')})`);
  2005. }
  2006. }
  2007. /**
  2008. * Dialog window 3
  2009. *
  2010. * Диалоговое окно 3
  2011. */
  2012. const showMsgs = async function (msg, ansF, ansS, ansT) {
  2013. return await popup.confirm(msg, [
  2014. {msg: ansF, r###lt: 0},
  2015. {msg: ansS, r###lt: 1},
  2016. {msg: ansT, r###lt: 2},
  2017. ]);
  2018. }
  2019. let changeRequest = false;
  2020. testData = JSON.parse(tempData);
  2021. for (const call of testData.calls) {
  2022. if (!artifactChestOpen) {
  2023. requestHistory[this.uniqid].calls[call.name] = call.ident;
  2024. }
  2025. /**
  2026. * Cancellation of the battle in adventures, on VG and with minions of Asgard
  2027. * Отмена боя в приключениях, на ВГ и с прислужниками Асгарда
  2028. */
  2029. if ((call.name == 'adventure_endBattle' ||
  2030. call.name == 'adventureSolo_endBattle' ||
  2031. call.name == 'clanWarEndBattle' &&
  2032. isChecked('cancelBattle') ||
  2033. call.name == 'crossClanWar_endBattle' &&
  2034. isChecked('cancelBattle') ||
  2035. call.name == 'brawl_endBattle' ||
  2036. call.name == 'towerEndBattle' ||
  2037. call.name == 'invasion_bossEnd' ||
  2038. call.name == 'titanArenaEndBattle' ||
  2039. call.name == 'bossEndBattle' ||
  2040. call.name == 'clanRaid_endNodeBattle') &&
  2041. isCancalBattle) {
  2042. nameFuncEndBattle = call.name;
  2043. if (isChecked('tryFixIt_v2') &&
  2044. !call.args.r###lt.win &&
  2045. (call.name == 'brawl_endBattle' ||
  2046. //call.name == 'crossClanWar_endBattle' ||
  2047. call.name == 'epicBrawl_endBattle' ||
  2048. //call.name == 'clanWarEndBattle' ||
  2049. call.name == 'adventure_endBattle' ||
  2050. call.name == 'titanArenaEndBattle' ||
  2051. call.name == 'bossEndBattle' ||
  2052. call.name == 'adventureSolo_endBattle') &&
  2053. lastBattleInfo) {
  2054. const noFixWin = call.name == 'clanWarEndBattle' || call.name == 'crossClanWar_endBattle';
  2055. const cloneBattle = structuredClone(lastBattleInfo);
  2056. lastBattleInfo = null;
  2057. try {
  2058. const { BestOrWinFixBattle } = HWHClasses;
  2059. const bFix = new BestOrWinFixBattle(cloneBattle);
  2060. bFix.setNoMakeWin(noFixWin);
  2061. let endTime = Date.now() + 3e4;
  2062. if (endTime < cloneBattle.endTime) {
  2063. endTime = cloneBattle.endTime;
  2064. }
  2065. const r###lt = await bFix.start(cloneBattle.endTime, 150);
  2066. if (r###lt.r###lt.win) {
  2067. call.args.r###lt = r###lt.r###lt;
  2068. call.args.progress = r###lt.progress;
  2069. changeRequest = true;
  2070. } else if (r###lt.value) {
  2071. if (
  2072. await popup.confirm(I18N('DEFEAT') + '<br>' + I18N('BEST_R###LT', { value: r###lt.value }), [
  2073. { msg: I18N('BTN_CANCEL'), r###lt: 0 },
  2074. { msg: I18N('BTN_ACCEPT'), r###lt: 1 },
  2075. ])
  2076. ) {
  2077. call.args.r###lt = r###lt.r###lt;
  2078. call.args.progress = r###lt.progress;
  2079. changeRequest = true;
  2080. }
  2081. }
  2082. } catch (error) {
  2083. console.error(error);
  2084. }
  2085. }
  2086. if (!call.args.r###lt.win) {
  2087. let r###ltPopup = false;
  2088. if (call.name == 'adventure_endBattle' ||
  2089. //call.name == 'invasion_bossEnd' ||
  2090. call.name == 'bossEndBattle' ||
  2091. call.name == 'adventureSolo_endBattle') {
  2092. r###ltPopup = await showMsgs(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  2093. } else if (call.name == 'clanWarEndBattle' ||
  2094. call.name == 'crossClanWar_endBattle') {
  2095. r###ltPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_AUTO_F5'));
  2096. } else if (call.name !== 'epicBrawl_endBattle' && call.name !== 'titanArenaEndBattle') {
  2097. r###ltPopup = await showMsg(I18N('MSG_HAVE_BEEN_DEFEATED'), I18N('BTN_OK'), I18N('BTN_CANCEL'));
  2098. }
  2099. if (r###ltPopup) {
  2100. if (call.name == 'invasion_bossEnd') {
  2101. this.errorRequest = true;
  2102. }
  2103. fixBattle(call.args.progress[0].attackers.heroes);
  2104. fixBattle(call.args.progress[0].defenders.heroes);
  2105. changeRequest = true;
  2106. if (r###ltPopup > 1) {
  2107. this.onReadySuccess = testAutoBattle;
  2108. // setTimeout(bossBattle, 1000);
  2109. }
  2110. }
  2111. } else if (call.args.r###lt.stars < 3 && call.name == 'towerEndBattle') {
  2112. r###ltPopup = await showMsg(I18N('LOST_HEROES'), I18N('BTN_OK'), I18N('BTN_CANCEL'), I18N('BTN_AUTO'));
  2113. if (r###ltPopup) {
  2114. fixBattle(call.args.progress[0].attackers.heroes);
  2115. fixBattle(call.args.progress[0].defenders.heroes);
  2116. changeRequest = true;
  2117. if (r###ltPopup > 1) {
  2118. this.onReadySuccess = testAutoBattle;
  2119. }
  2120. }
  2121. }
  2122. // Потасовки
  2123. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_endBattle') {}
  2124. }
  2125. /**
  2126. * Save pack for Brawls
  2127. *
  2128. * Сохраняем пачку для потасовок
  2129. */
  2130. if (isChecked('autoBrawls') && !isBrawlsAutoStart && call.name == 'brawl_startBattle') {
  2131. console.log(JSON.stringify(call.args));
  2132. brawlsPack = call.args;
  2133. if (
  2134. await popup.confirm(
  2135. I18N('START_AUTO_BRAWLS'),
  2136. [
  2137. { msg: I18N('BTN_NO'), r###lt: false },
  2138. { msg: I18N('BTN_YES'), r###lt: true },
  2139. ],
  2140. [
  2141. {
  2142. name: 'isAuto',
  2143. label: I18N('BRAWL_AUTO_PACK'),
  2144. checked: false,
  2145. },
  2146. ]
  2147. )
  2148. ) {
  2149. isBrawlsAutoStart = true;
  2150. const isAuto = popup.getCheckBoxes().find((e) => e.name === 'isAuto');
  2151. this.errorRequest = true;
  2152. testBrawls(isAuto.checked);
  2153. }
  2154. }
  2155. /**
  2156. * Canceled fight in Asgard
  2157. * Отмена боя в Асгарде
  2158. */
  2159. if (call.name == 'clanRaid_endBossBattle' && isChecked('cancelBattle')) {
  2160. const bossDamage = call.args.progress[0].defenders.heroes[1].extra;
  2161. let maxDamage = bossDamage.damageTaken + bossDamage.damageTakenNextLevel;
  2162. const lastDamage = maxDamage;
  2163. const testFunc = [];
  2164. if (testFuntions.masterFix) {
  2165. testFunc.push({ msg: 'masterFix', isInput: true, default: 100 });
  2166. }
  2167. const r###ltPopup = await popup.confirm(
  2168. `${I18N('MSG_YOU_APPLIED')} ${lastDamage.toLocaleString()} ${I18N('MSG_DAMAGE')}.`,
  2169. [
  2170. { msg: I18N('BTN_OK'), r###lt: false },
  2171. { msg: I18N('BTN_AUTO_F5'), r###lt: 1 },
  2172. { msg: I18N('BTN_TRY_FIX_IT'), r###lt: 2 },
  2173. ...testFunc,
  2174. ],
  2175. [
  2176. {
  2177. name: 'isStat',
  2178. label: I18N('CALC_STAT'),
  2179. checked: false,
  2180. },
  2181. ]
  2182. );
  2183. if (r###ltPopup) {
  2184. if (r###ltPopup == 2) {
  2185. setProgress(I18N('LETS_FIX'), false);
  2186. await new Promise((e) => setTimeout(e, 0));
  2187. const cloneBattle = structuredClone(lastBossBattle);
  2188. const endTime = cloneBattle.endTime - 1e4;
  2189. console.log('fixBossBattleStart');
  2190. const { BossFixBattle } = HWHClasses;
  2191. const bFix = new BossFixBattle(cloneBattle);
  2192. const r###lt = await bFix.start(endTime, 300);
  2193. console.log(r###lt);
  2194. let msgR###lt = I18N('DAMAGE_NO_FIXED', {
  2195. lastDamage: lastDamage.toLocaleString()
  2196. });
  2197. if (r###lt.value > lastDamage) {
  2198. call.args.r###lt = r###lt.r###lt;
  2199. call.args.progress = r###lt.progress;
  2200. msgR###lt = I18N('DAMAGE_FIXED', {
  2201. lastDamage: lastDamage.toLocaleString(),
  2202. maxDamage: r###lt.value.toLocaleString(),
  2203. });
  2204. }
  2205. console.log(lastDamage, '>', r###lt.value);
  2206. setProgress(
  2207. msgR###lt +
  2208. '<br/>' +
  2209. I18N('COUNT_FIXED', {
  2210. count: r###lt.maxCount,
  2211. }),
  2212. false,
  2213. hideProgress
  2214. );
  2215. } else if (r###ltPopup > 3) {
  2216. const cloneBattle = structuredClone(lastBossBattle);
  2217. const { masterFixBattle } = HWHClasses;
  2218. const mFix = new masterFixBattle(cloneBattle);
  2219. const r###lt = await mFix.start(cloneBattle.endTime, r###ltPopup);
  2220. console.log(r###lt);
  2221. let msgR###lt = I18N('DAMAGE_NO_FIXED', {
  2222. lastDamage: lastDamage.toLocaleString(),
  2223. });
  2224. if (r###lt.value > lastDamage) {
  2225. maxDamage = r###lt.value;
  2226. call.args.r###lt = r###lt.r###lt;
  2227. call.args.progress = r###lt.progress;
  2228. msgR###lt = I18N('DAMAGE_FIXED', {
  2229. lastDamage: lastDamage.toLocaleString(),
  2230. maxDamage: maxDamage.toLocaleString(),
  2231. });
  2232. }
  2233. console.log('Урон:', lastDamage, maxDamage);
  2234. setProgress(msgR###lt, false, hideProgress);
  2235. } else {
  2236. fixBattle(call.args.progress[0].attackers.heroes);
  2237. fixBattle(call.args.progress[0].defenders.heroes);
  2238. }
  2239. changeRequest = true;
  2240. }
  2241. const isStat = popup.getCheckBoxes().find((e) => e.name === 'isStat');
  2242. if (isStat.checked) {
  2243. this.onReadySuccess = testBossBattle;
  2244. }
  2245. }
  2246. /**
  2247. * Save the Asgard Boss Attack Pack
  2248. * Сохраняем пачку для атаки босса Асгарда
  2249. */
  2250. if (call.name == 'clanRaid_startBossBattle') {
  2251. console.log(JSON.stringify(call.args));
  2252. }
  2253. /**
  2254. * Saving the request to start the last battle
  2255. * Сохранение запроса начала последнего боя
  2256. */
  2257. if (
  2258. call.name == 'clanWarAttack' ||
  2259. call.name == 'crossClanWar_startBattle' ||
  2260. call.name == 'adventure_turnStartBattle' ||
  2261. call.name == 'adventureSolo_turnStartBattle' ||
  2262. call.name == 'bossAttack' ||
  2263. call.name == 'invasion_bossStart' ||
  2264. call.name == 'towerStartBattle'
  2265. ) {
  2266. nameFuncStartBattle = call.name;
  2267. lastBattleArg = call.args;
  2268. if (call.name == 'invasion_bossStart') {
  2269. const timePassed = Date.now() - lastBossBattleStart;
  2270. if (timePassed < invasionTimer) {
  2271. await new Promise((e) => setTimeout(e, invasionTimer - timePassed));
  2272. }
  2273. invasionTimer -= 1;
  2274. }
  2275. lastBossBattleStart = Date.now();
  2276. }
  2277. if (call.name == 'invasion_bossEnd') {
  2278. const lastBattle = lastBattleInfo;
  2279. if (lastBattle && call.args.r###lt.win) {
  2280. lastBattle.progress = call.args.progress;
  2281. const r###lt = await Calc(lastBattle);
  2282. let timer = getTimer(r###lt.battleTime, 1) + addBattleTimer;
  2283. const period = Math.ceil((Date.now() - lastBossBattleStart) / 1000);
  2284. console.log(timer, period);
  2285. if (period < timer) {
  2286. timer = timer - period;
  2287. await countdownTimer(timer);
  2288. }
  2289. }
  2290. }
  2291. /**
  2292. * Disable spending divination cards
  2293. * Отключить трату карт предсказаний
  2294. */
  2295. if (call.name == 'dungeonEndBattle') {
  2296. if (call.args.isRaid) {
  2297. if (countPredictionCard <= 0) {
  2298. delete call.args.isRaid;
  2299. changeRequest = true;
  2300. } else if (countPredictionCard > 0) {
  2301. countPredictionCard--;
  2302. }
  2303. }
  2304. console.log(`Cards: ${countPredictionCard}`);
  2305. /**
  2306. * Fix endless cards
  2307. * Исправление бесконечных карт
  2308. */
  2309. const lastBattle = lastDungeonBattleData;
  2310. if (lastBattle && !call.args.isRaid) {
  2311. if (changeRequest) {
  2312. lastBattle.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  2313. } else {
  2314. lastBattle.progress = call.args.progress;
  2315. }
  2316. const r###lt = await Calc(lastBattle);
  2317. if (changeRequest) {
  2318. call.args.progress = r###lt.progress;
  2319. call.args.r###lt = r###lt.r###lt;
  2320. }
  2321. let timer = r###lt.battleTimer + addBattleTimer;
  2322. const period = Math.ceil((Date.now() - lastDungeonBattleStart) / 1000);
  2323. console.log(timer, period);
  2324. if (period < timer) {
  2325. timer = timer - period;
  2326. await countdownTimer(timer);
  2327. }
  2328. }
  2329. }
  2330. /**
  2331. * Quiz Answer
  2332. * Ответ на викторину
  2333. */
  2334. if (call.name == 'quiz_answer') {
  2335. /**
  2336. * Automatically changes the answer to the correct one if there is one.
  2337. * Автоматически меняет ответ на правильный если он есть
  2338. */
  2339. if (lastAnswer && isChecked('getAnswer')) {
  2340. call.args.answerId = lastAnswer;
  2341. lastAnswer = null;
  2342. changeRequest = true;
  2343. }
  2344. }
  2345. /**
  2346. * Present
  2347. * Подарки
  2348. */
  2349. if (call.name == 'freebieCheck') {
  2350. freebieCheckInfo = call;
  2351. }
  2352. /** missionTimer */
  2353. if (call.name == 'missionEnd' && missionBattle) {
  2354. let startTimer = false;
  2355. if (!call.args.r###lt.win) {
  2356. startTimer = await popup.confirm(I18N('DEFEAT_TURN_TIMER'), [
  2357. { msg: I18N('BTN_NO'), r###lt: false },
  2358. { msg: I18N('BTN_YES'), r###lt: true },
  2359. ]);
  2360. }
  2361. if (call.args.r###lt.win || startTimer) {
  2362. missionBattle.progress = call.args.progress;
  2363. missionBattle.r###lt = call.args.r###lt;
  2364. const r###lt = await Calc(missionBattle);
  2365. let timer = r###lt.battleTimer + addBattleTimer;
  2366. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  2367. if (period < timer) {
  2368. timer = timer - period;
  2369. await countdownTimer(timer);
  2370. }
  2371. missionBattle = null;
  2372. } else {
  2373. this.errorRequest = true;
  2374. }
  2375. }
  2376. /**
  2377. * Getting mission data for auto-repeat
  2378. * Получение данных миссии для автоповтора
  2379. */
  2380. if (isChecked('repeatMission') &&
  2381. call.name == 'missionEnd') {
  2382. let missionInfo = {
  2383. id: call.args.id,
  2384. r###lt: call.args.r###lt,
  2385. heroes: call.args.progress[0].attackers.heroes,
  2386. count: 0,
  2387. }
  2388. setTimeout(async () => {
  2389. if (!isSendsMission && await popup.confirm(I18N('MSG_REPEAT_MISSION'), [
  2390. { msg: I18N('BTN_REPEAT'), r###lt: true},
  2391. { msg: I18N('BTN_NO'), r###lt: false},
  2392. ])) {
  2393. isStopSendMission = false;
  2394. isSendsMission = true;
  2395. sendsMission(missionInfo);
  2396. }
  2397. }, 0);
  2398. }
  2399. /**
  2400. * Getting mission data
  2401. * Получение данных миссии
  2402. * missionTimer
  2403. */
  2404. if (call.name == 'missionStart') {
  2405. lastMissionStart = call.args;
  2406. lastMissionBattleStart = Date.now();
  2407. }
  2408. /**
  2409. * Specify the quantity for Titan Orbs and Pet Eggs
  2410. * Указать количество для сфер титанов и яиц петов
  2411. */
  2412. if (isChecked('countControl') &&
  2413. (call.name == 'pet_chestOpen' ||
  2414. call.name == 'titanUs###mmonCircle') &&
  2415. call.args.amount > 1) {
  2416. const startAmount = call.args.amount;
  2417. const r###lt = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2418. { msg: I18N('BTN_OPEN'), isInput: true, default: 1},
  2419. ]);
  2420. if (r###lt) {
  2421. const item = call.name == 'pet_chestOpen' ? { id: 90, type: 'consumable' } : { id: 13, type: 'coin' };
  2422. cheats.updateInventory({
  2423. [item.type]: {
  2424. [item.id]: -(r###lt - startAmount),
  2425. },
  2426. });
  2427. call.args.amount = r###lt;
  2428. changeRequest = true;
  2429. }
  2430. }
  2431. /**
  2432. * Specify the amount for keys and spheres of titan artifacts
  2433. * Указать колличество для ключей и сфер артефактов титанов
  2434. */
  2435. if (isChecked('countControl') &&
  2436. (call.name == 'artifactChestOpen' ||
  2437. call.name == 'titanArtifactChestOpen') &&
  2438. call.args.amount > 1 &&
  2439. call.args.free &&
  2440. !changeRequest) {
  2441. artifactChestOpenCallName = call.name;
  2442. const startAmount = call.args.amount;
  2443. let r###lt = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2444. { msg: I18N('BTN_OPEN'), isInput: true, default: 1 },
  2445. ]);
  2446. if (r###lt) {
  2447. const openChests = r###lt;
  2448. let sphere = r###lt < 10 ? 1 : 10;
  2449. call.args.amount = sphere;
  2450. for (let count = openChests - sphere; count > 0; count -= sphere) {
  2451. if (count < 10) sphere = 1;
  2452. const ident = artifactChestOpenCallName + "_" + count;
  2453. testData.calls.push({
  2454. name: artifactChestOpenCallName,
  2455. args: {
  2456. amount: sphere,
  2457. free: true,
  2458. },
  2459. ident: ident
  2460. });
  2461. if (!Array.isArray(requestHistory[this.uniqid].calls[call.name])) {
  2462. requestHistory[this.uniqid].calls[call.name] = [requestHistory[this.uniqid].calls[call.name]];
  2463. }
  2464. requestHistory[this.uniqid].calls[call.name].push(ident);
  2465. }
  2466. const consumableId = call.name == 'artifactChestOpen' ? 45 : 55;
  2467. cheats.updateInventory({
  2468. consumable: {
  2469. [consumableId]: -(openChests - startAmount),
  2470. },
  2471. });
  2472. artifactChestOpen = true;
  2473. changeRequest = true;
  2474. }
  2475. }
  2476. if (call.name == 'consumableUseLootBox') {
  2477. lastRussianDollId = call.args.libId;
  2478. /**
  2479. * Specify quantity for gold caskets
  2480. * Указать количество для золотых шкатулок
  2481. */
  2482. if (isChecked('countControl') &&
  2483. call.args.libId == 148 &&
  2484. call.args.amount > 1) {
  2485. const r###lt = await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2486. { msg: I18N('BTN_OPEN'), isInput: true, default: call.args.amount},
  2487. ]);
  2488. call.args.amount = r###lt;
  2489. changeRequest = true;
  2490. }
  2491. if (isChecked('countControl') && call.args.libId >= 362 && call.args.libId <= 389) {
  2492. this.massOpen = call.args.libId;
  2493. }
  2494. }
  2495. if (call.name == 'invasion_bossStart' && isChecked('tryFixIt_v2') && call.args.id == invasionInfo.id) {
  2496. const pack = invasionDataPacks[invasionInfo.bossLvl];
  2497. if (pack) {
  2498. if (pack.buff != invasionInfo.buff) {
  2499. setProgress(
  2500. I18N('INVASION_BOSS_BUFF', {
  2501. bossLvl: invasionInfo.bossLvl,
  2502. needBuff: pack.buff,
  2503. haveBuff: invasionInfo.buff,
  2504. }),
  2505. false
  2506. );
  2507. } else {
  2508. call.args.pet = pack.pet;
  2509. call.args.heroes = pack.heroes;
  2510. call.args.favor = pack.favor;
  2511. changeRequest = true;
  2512. }
  2513. }
  2514. }
  2515. if (call.name == 'workshopBuff_create') {
  2516. const pack = invasionDataPacks[invasionInfo.bossLvl];
  2517. if (pack) {
  2518. const addBuff = call.args.amount * 5;
  2519. if (pack.buff < addBuff + invasionInfo.buff) {
  2520. this.errorRequest = true;
  2521. }
  2522. setProgress(
  2523. I18N('INVASION_BOSS_BUFF', {
  2524. bossLvl: invasionInfo.bossLvl,
  2525. needBuff: pack.buff,
  2526. haveBuff: invasionInfo.buff,
  2527. }),
  2528. false
  2529. );
  2530. }
  2531. }
  2532. /**
  2533. * Changing the maximum number of raids in the campaign
  2534. * Изменение максимального количества рейдов в кампании
  2535. */
  2536. // if (call.name == 'missionRaid') {
  2537. // if (isChecked('countControl') && call.args.times > 1) {
  2538. // const r###lt = +(await popup.confirm(I18N('MSG_SPECIFY_QUANT'), [
  2539. // { msg: I18N('BTN_RUN'), isInput: true, default: call.args.times },
  2540. // ]));
  2541. // call.args.times = r###lt > call.args.times ? call.args.times : r###lt;
  2542. // changeRequest = true;
  2543. // }
  2544. // }
  2545. }
  2546. let headers = requestHistory[this.uniqid].headers;
  2547. if (changeRequest) {
  2548. sourceData = JSON.stringify(testData);
  2549. headers['X-Auth-Signature'] = getSignature(headers, sourceData);
  2550. }
  2551. let signature = headers['X-Auth-Signature'];
  2552. if (signature) {
  2553. original.setRequestHeader.call(this, 'X-Auth-Signature', signature);
  2554. }
  2555. } catch (err) {
  2556. console.log("Request(send, " + this.uniqid + "):\n", sourceData, "Error:\n", err);
  2557. }
  2558. return sourceData;
  2559. }
  2560. /**
  2561. * Processing and substitution of incoming data
  2562. *
  2563. * Обработка и подмена входящих данных
  2564. */
  2565. async function checkChangeResponse(response) {
  2566. try {
  2567. isChange = false;
  2568. let nowTime = Math.round(Date.now() / 1000);
  2569. callsIdent = requestHistory[this.uniqid].calls;
  2570. respond = JSON.parse(response);
  2571. /**
  2572. * If the request returned an error removes the error (removes synchronization errors)
  2573. * Если запрос вернул ошибку удаляет ошибку (убирает ошибки синхронизации)
  2574. */
  2575. if (respond.error) {
  2576. isChange = true;
  2577. console.error(respond.error);
  2578. if (isChecked('showErrors')) {
  2579. popup.confirm(I18N('ERROR_MSG', {
  2580. name: respond.error.name,
  2581. description: respond.error.description,
  2582. }));
  2583. }
  2584. if (respond.error.name != 'AccountBan') {
  2585. delete respond.error;
  2586. respond.r###lts = [];
  2587. }
  2588. }
  2589. let mainReward = null;
  2590. const allReward = {};
  2591. let countTypeReward = 0;
  2592. let readQuestInfo = false;
  2593. for (const call of respond.r###lts) {
  2594. /**
  2595. * Obtaining initial data for completing quests
  2596. * Получение исходных данных для выполнения квестов
  2597. */
  2598. if (readQuestInfo) {
  2599. questsInfo[call.ident] = call.r###lt.response;
  2600. }
  2601. /**
  2602. * Getting a user ID
  2603. * Получение идетификатора пользователя
  2604. */
  2605. if (call.ident == callsIdent['registration']) {
  2606. userId = call.r###lt.response.userId;
  2607. if (localStorage['userId'] != userId) {
  2608. localStorage['newGiftSendIds'] = '';
  2609. localStorage['userId'] = userId;
  2610. }
  2611. await openOrMigrateDatabase(userId);
  2612. readQuestInfo = true;
  2613. }
  2614. /**
  2615. * Hiding donation offers 1
  2616. * Скрываем предложения доната 1
  2617. */
  2618. if (call.ident == callsIdent['billingGetAll'] && getSaveVal('noOfferDonat')) {
  2619. const billings = call.r###lt.response?.billings;
  2620. const bundle = call.r###lt.response?.bundle;
  2621. if (billings && bundle) {
  2622. call.r###lt.response.billings = call.r###lt.response.billings.filter((e) => ['repeatableOffer'].includes(e.type));
  2623. call.r###lt.response.bundle = [];
  2624. isChange = true;
  2625. }
  2626. }
  2627. /**
  2628. * Hiding donation offers 2
  2629. * Скрываем предложения доната 2
  2630. */
  2631. if (getSaveVal('noOfferDonat') &&
  2632. (call.ident == callsIdent['offerGetAll'] ||
  2633. call.ident == callsIdent['specialOffer_getAll'])) {
  2634. let offers = call.r###lt.response;
  2635. if (offers) {
  2636. call.r###lt.response = offers.filter(
  2637. (e) => !['addBilling', 'bundleCarousel'].includes(e.type) || ['idleResource', 'stagesOffer'].includes(e.offerType)
  2638. );
  2639. isChange = true;
  2640. }
  2641. }
  2642. /**
  2643. * Hiding donation offers 3
  2644. * Скрываем предложения доната 3
  2645. */
  2646. if (getSaveVal('noOfferDonat') && call.r###lt?.bundleUpdate) {
  2647. delete call.r###lt.bundleUpdate;
  2648. isChange = true;
  2649. }
  2650. /**
  2651. * Hiding donation offers 4
  2652. * Скрываем предложения доната 4
  2653. */
  2654. if (call.r###lt?.specialOffers) {
  2655. const offers = call.r###lt.specialOffers;
  2656. call.r###lt.specialOffers = offers.filter(
  2657. (e) => !['addBilling', 'bundleCarousel'].includes(e.type) || ['idleResource', 'stagesOffer'].includes(e.offerType)
  2658. );
  2659. isChange = true;
  2660. }
  2661. /**
  2662. * Copies a quiz question to the clipboard
  2663. * Копирует вопрос викторины в буфер обмена и получает на него ответ если есть
  2664. */
  2665. if (call.ident == callsIdent['quiz_getNewQuestion']) {
  2666. let quest = call.r###lt.response;
  2667. console.log(quest.question);
  2668. copyText(quest.question);
  2669. setProgress(I18N('QUESTION_COPY'), true);
  2670. quest.lang = null;
  2671. if (typeof NXFlashVars !== 'undefined') {
  2672. quest.lang = NXFlashVars.interface_lang;
  2673. }
  2674. lastQuestion = quest;
  2675. if (isChecked('getAnswer')) {
  2676. const answer = await getAnswer(lastQuestion);
  2677. let showText = '';
  2678. if (answer) {
  2679. lastAnswer = answer;
  2680. console.log(answer);
  2681. showText = `${I18N('ANSWER_KNOWN')}: ${answer}`;
  2682. } else {
  2683. showText = I18N('ANSWER_NOT_KNOWN');
  2684. }
  2685. try {
  2686. const hint = hintQuest(quest);
  2687. if (hint) {
  2688. showText += I18N('HINT') + hint;
  2689. }
  2690. } catch (e) {}
  2691. setProgress(showText, true);
  2692. }
  2693. }
  2694. /**
  2695. * Submits a question with an answer to the database
  2696. * Отправляет вопрос с ответом в базу данных
  2697. */
  2698. if (call.ident == callsIdent['quiz_answer']) {
  2699. const answer = call.r###lt.response;
  2700. if (lastQuestion) {
  2701. const answerInfo = {
  2702. answer,
  2703. question: lastQuestion,
  2704. lang: null,
  2705. };
  2706. if (typeof NXFlashVars !== 'undefined') {
  2707. answerInfo.lang = NXFlashVars.interface_lang;
  2708. }
  2709. lastQuestion = null;
  2710. setTimeout(sendAnswerInfo, 0, answerInfo);
  2711. }
  2712. }
  2713. /**
  2714. * Get user data
  2715. * Получить даныне пользователя
  2716. */
  2717. if (call.ident == callsIdent['userGetInfo']) {
  2718. let user = call.r###lt.response;
  2719. document.title = user.name;
  2720. userInfo = Object.assign({}, user);
  2721. delete userInfo.refillable;
  2722. if (!questsInfo['userGetInfo']) {
  2723. questsInfo['userGetInfo'] = user;
  2724. }
  2725. }
  2726. /**
  2727. * Start of the battle for recalculation
  2728. * Начало боя для прерасчета
  2729. */
  2730. if (call.ident == callsIdent['clanWarAttack'] ||
  2731. call.ident == callsIdent['crossClanWar_startBattle'] ||
  2732. call.ident == callsIdent['bossAttack'] ||
  2733. call.ident == callsIdent['battleGetReplay'] ||
  2734. call.ident == callsIdent['brawl_startBattle'] ||
  2735. call.ident == callsIdent['adventureSolo_turnStartBattle'] ||
  2736. call.ident == callsIdent['invasion_bossStart'] ||
  2737. call.ident == callsIdent['titanArenaStartBattle'] ||
  2738. call.ident == callsIdent['towerStartBattle'] ||
  2739. call.ident == callsIdent['epicBrawl_startBattle'] ||
  2740. call.ident == callsIdent['adventure_turnStartBattle']) {
  2741. let battle = call.r###lt.response.battle || call.r###lt.response.replay;
  2742. if (call.ident == callsIdent['brawl_startBattle'] ||
  2743. call.ident == callsIdent['bossAttack'] ||
  2744. call.ident == callsIdent['towerStartBattle'] ||
  2745. call.ident == callsIdent['invasion_bossStart']) {
  2746. battle = call.r###lt.response;
  2747. }
  2748. lastBattleInfo = battle;
  2749. if (call.ident == callsIdent['battleGetReplay'] && call.r###lt.response.replay.type === "clan_raid") {
  2750. if (call?.r###lt?.response?.replay?.r###lt?.damage) {
  2751. const damages = Object.values(call.r###lt.response.replay.r###lt.damage);
  2752. const bossDamage = damages.reduce((a, v) => a + v, 0);
  2753. setProgress(I18N('BOSS_DAMAGE') + bossDamage.toLocaleString(), false, hideProgress);
  2754. continue;
  2755. }
  2756. }
  2757. if (!isChecked('preCalcBattle')) {
  2758. continue;
  2759. }
  2760. const preCalcBattle = structuredClone(battle);
  2761. setProgress(I18N('BEING_RECALC'));
  2762. let battleDuration = 120;
  2763. try {
  2764. const typeBattle = getBattleType(preCalcBattle.type);
  2765. battleDuration = +lib.data.battleConfig[typeBattle.split('_')[1]].config.battleDuration;
  2766. } catch (e) { }
  2767. //console.log(battle.type);
  2768. function getBattleInfo(battle, isRandSeed) {
  2769. return new Promise(function (resolve) {
  2770. if (isRandSeed) {
  2771. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  2772. }
  2773. BattleCalc(battle, getBattleType(battle.type), e => resolve(e));
  2774. });
  2775. }
  2776. let actions = [getBattleInfo(preCalcBattle, false)];
  2777. let countTestBattle = getInput('countTestBattle');
  2778. if (call.ident == callsIdent['invasion_bossStart'] ) {
  2779. countTestBattle = 0;
  2780. }
  2781. if (call.ident == callsIdent['battleGetReplay']) {
  2782. preCalcBattle.progress = [{ attackers: { input: ['auto', 0, 0, 'auto', 0, 0] } }];
  2783. }
  2784. for (let i = 0; i < countTestBattle; i++) {
  2785. actions.push(getBattleInfo(preCalcBattle, true));
  2786. }
  2787. Promise.all(actions)
  2788. .then(e => {
  2789. e = e.map(n => ({win: n.r###lt.win, time: n.battleTime}));
  2790. let firstBattle = e.shift();
  2791. const timer = Math.floor(battleDuration - firstBattle.time);
  2792. const min = ('00' + Math.floor(timer / 60)).slice(-2);
  2793. const sec = ('00' + Math.floor(timer - min * 60)).slice(-2);
  2794. let msg = `${I18N('THIS_TIME')} ${firstBattle.win ? I18N('VICTORY') : I18N('DEFEAT')}`;
  2795. if (e.length) {
  2796. const countWin = e.reduce((w, s) => w + s.win, 0);
  2797. msg += ` ${I18N('CHANCE_TO_WIN')}: ${Math.floor((countWin / e.length) * 100)}% (${e.length})`;
  2798. }
  2799. msg += `, ${min}:${sec}`
  2800. setProgress(msg, false, hideProgress)
  2801. });
  2802. }
  2803. /**
  2804. * Start of the Asgard boss fight
  2805. * Начало боя с боссом Асгарда
  2806. */
  2807. if (call.ident == callsIdent['clanRaid_startBossBattle']) {
  2808. lastBossBattle = call.r###lt.response.battle;
  2809. lastBossBattle.endTime = Date.now() + 160 * 1000;
  2810. if (isChecked('preCalcBattle')) {
  2811. const r###lt = await Calc(lastBossBattle).then(e => e.progress[0].defenders.heroes[1].extra);
  2812. const bossDamage = r###lt.damageTaken + r###lt.damageTakenNextLevel;
  2813. setProgress(I18N('BOSS_DAMAGE') + bossDamage.toLocaleString(), false, hideProgress);
  2814. }
  2815. }
  2816. /**
  2817. * Cancel tutorial
  2818. * Отмена туториала
  2819. */
  2820. if (isCanceledTutorial && call.ident == callsIdent['tutorialGetInfo']) {
  2821. let chains = call.r###lt.response.chains;
  2822. for (let n in chains) {
  2823. chains[n] = 9999;
  2824. }
  2825. isChange = true;
  2826. }
  2827. /**
  2828. * Opening keys and spheres of titan artifacts
  2829. * Открытие ключей и сфер артефактов титанов
  2830. */
  2831. if (artifactChestOpen &&
  2832. (call.ident == callsIdent[artifactChestOpenCallName] ||
  2833. (callsIdent[artifactChestOpenCallName] && callsIdent[artifactChestOpenCallName].includes(call.ident)))) {
  2834. let reward = call.r###lt.response[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'];
  2835. reward.forEach(e => {
  2836. for (let f in e) {
  2837. if (!allReward[f]) {
  2838. allReward[f] = {};
  2839. }
  2840. for (let o in e[f]) {
  2841. if (!allReward[f][o]) {
  2842. allReward[f][o] = e[f][o];
  2843. countTypeReward++;
  2844. } else {
  2845. allReward[f][o] += e[f][o];
  2846. }
  2847. }
  2848. }
  2849. });
  2850. if (!call.ident.includes(artifactChestOpenCallName)) {
  2851. mainReward = call.r###lt.response;
  2852. }
  2853. }
  2854. if (countTypeReward > 20) {
  2855. correctShowOpenArtifact = 3;
  2856. } else {
  2857. correctShowOpenArtifact = 0;
  2858. }
  2859. /**
  2860. * Sum the r###lt of opening Pet Eggs
  2861. * Суммирование результата открытия яиц питомцев
  2862. */
  2863. if (isChecked('countControl') && call.ident == callsIdent['pet_chestOpen']) {
  2864. const rewards = call.r###lt.response.rewards;
  2865. if (rewards.length > 10) {
  2866. /**
  2867. * Removing pet cards
  2868. * Убираем карточки петов
  2869. */
  2870. for (const reward of rewards) {
  2871. if (reward.petCard) {
  2872. delete reward.petCard;
  2873. }
  2874. }
  2875. }
  2876. rewards.forEach(e => {
  2877. for (let f in e) {
  2878. if (!allReward[f]) {
  2879. allReward[f] = {};
  2880. }
  2881. for (let o in e[f]) {
  2882. if (!allReward[f][o]) {
  2883. allReward[f][o] = e[f][o];
  2884. } else {
  2885. allReward[f][o] += e[f][o];
  2886. }
  2887. }
  2888. }
  2889. });
  2890. call.r###lt.response.rewards = [allReward];
  2891. isChange = true;
  2892. }
  2893. /**
  2894. * Removing titan cards
  2895. * Убираем карточки титанов
  2896. */
  2897. if (call.ident == callsIdent['titanUs###mmonCircle']) {
  2898. if (call.r###lt.response.rewards.length > 10) {
  2899. for (const reward of call.r###lt.response.rewards) {
  2900. if (reward.titanCard) {
  2901. delete reward.titanCard;
  2902. }
  2903. }
  2904. isChange = true;
  2905. }
  2906. }
  2907. /**
  2908. * Auto-repeat opening matryoshkas
  2909. * АвтоПовтор открытия матрешек
  2910. */
  2911. if (isChecked('countControl') && call.ident == callsIdent['consumableUseLootBox']) {
  2912. let [countLootBox, lootBox] = Object.entries(call.r###lt.response).pop();
  2913. countLootBox = +countLootBox;
  2914. let newCount = 0;
  2915. if (lootBox?.consumable && lootBox.consumable[lastRussianDollId]) {
  2916. newCount += lootBox.consumable[lastRussianDollId];
  2917. delete lootBox.consumable[lastRussianDollId];
  2918. }
  2919. if (
  2920. newCount &&
  2921. (await popup.confirm(`${I18N('BTN_OPEN')} ${newCount} ${I18N('OPEN_DOLLS')}?`, [
  2922. { msg: I18N('BTN_OPEN'), r###lt: true },
  2923. { msg: I18N('BTN_NO'), r###lt: false, isClose: true },
  2924. ]))
  2925. ) {
  2926. const [count, recursionR###lt] = await openRussianDolls(lastRussianDollId, newCount);
  2927. countLootBox += +count;
  2928. mergeItemsObj(lootBox, recursionR###lt);
  2929. isChange = true;
  2930. }
  2931. if (this.massOpen) {
  2932. if (
  2933. await popup.confirm(I18N('OPEN_ALL_EQUIP_BOXES'), [
  2934. { msg: I18N('BTN_OPEN'), r###lt: true },
  2935. { msg: I18N('BTN_NO'), r###lt: false, isClose: true },
  2936. ])
  2937. ) {
  2938. const consumable = await Send({ calls: [{ name: 'inventoryGet', args: {}, ident: 'inventoryGet' }] }).then((e) =>
  2939. Object.entries(e.r###lts[0].r###lt.response.consumable)
  2940. );
  2941. const calls = [];
  2942. const deleteItems = {};
  2943. for (const [libId, amount] of consumable) {
  2944. if (libId != this.massOpen && libId >= 362 && libId <= 389) {
  2945. calls.push({
  2946. name: 'consumableUseLootBox',
  2947. args: { libId, amount },
  2948. ident: 'consumableUseLootBox_' + libId,
  2949. });
  2950. deleteItems[libId] = -amount;
  2951. }
  2952. }
  2953. const responses = await Send({ calls }).then((e) => e.r###lts.map((r) => r.r###lt.response).flat());
  2954. for (const loot of responses) {
  2955. const [count, r###lt] = Object.entries(loot).pop();
  2956. countLootBox += +count;
  2957. mergeItemsObj(lootBox, r###lt);
  2958. }
  2959. isChange = true;
  2960. this.onReadySuccess = () => {
  2961. cheats.updateInventory({ consumable: deleteItems });
  2962. cheats.refreshInventory();
  2963. };
  2964. }
  2965. }
  2966. if (isChange) {
  2967. call.r###lt.response = {
  2968. [countLootBox]: lootBox,
  2969. };
  2970. }
  2971. }
  2972. /**
  2973. * Dungeon recalculation (fix endless cards)
  2974. * Прерасчет подземки (исправление бесконечных карт)
  2975. */
  2976. if (call.ident == callsIdent['dungeonStartBattle']) {
  2977. lastDungeonBattleData = call.r###lt.response;
  2978. lastDungeonBattleStart = Date.now();
  2979. }
  2980. /**
  2981. * Getting the number of prediction cards
  2982. * Получение количества карт предсказаний
  2983. */
  2984. if (call.ident == callsIdent['inventoryGet']) {
  2985. countPredictionCard = call.r###lt.response.consumable[81] || 0;
  2986. }
  2987. /**
  2988. * Getting subscription status
  2989. * Получение состояния подписки
  2990. */
  2991. if (call.ident == callsIdent['subscriptionGetInfo']) {
  2992. const subscription = call.r###lt.response.subscription;
  2993. if (subscription) {
  2994. subEndTime = subscription.endTime * 1000;
  2995. }
  2996. }
  2997. /**
  2998. * Getting prediction cards
  2999. * Получение карт предсказаний
  3000. */
  3001. if (call.ident == callsIdent['questFarm']) {
  3002. const consumable = call.r###lt.response?.consumable;
  3003. if (consumable && consumable[81]) {
  3004. countPredictionCard += consumable[81];
  3005. console.log(`Cards: ${countPredictionCard}`);
  3006. }
  3007. }
  3008. /**
  3009. * Hiding extra servers
  3010. * Скрытие лишних серверов
  3011. */
  3012. if (call.ident == callsIdent['serverGetAll'] && isChecked('hideServers')) {
  3013. let servers = call.r###lt.response.users.map(s => s.serverId)
  3014. call.r###lt.response.servers = call.r###lt.response.servers.filter(s => servers.includes(s.id));
  3015. isChange = true;
  3016. }
  3017. /**
  3018. * Displays player positions in the adventure
  3019. * Отображает позиции игроков в приключении
  3020. */
  3021. if (call.ident == callsIdent['adventure_getLobbyInfo']) {
  3022. const users = Object.values(call.r###lt.response.users);
  3023. const mapIdent = call.r###lt.response.mapIdent;
  3024. const adventureId = call.r###lt.response.adventureId;
  3025. const maps = {
  3026. adv_strongford_3pl_hell: 9,
  3027. adv_valley_3pl_hell: 10,
  3028. adv_ghirwil_3pl_hell: 11,
  3029. adv_angels_3pl_hell: 12,
  3030. }
  3031. let msg = I18N('MAP') + (mapIdent in maps ? maps[mapIdent] : adventureId);
  3032. msg += '<br>' + I18N('PLAYER_POS');
  3033. for (const user of users) {
  3034. msg += `<br>${user.user.name} - ${user.currentNode}`;
  3035. }
  3036. setProgress(msg, false, hideProgress);
  3037. }
  3038. /**
  3039. * Automatic launch of a raid at the end of the adventure
  3040. * Автоматический запуск рейда при окончании приключения
  3041. */
  3042. if (call.ident == callsIdent['adventure_end']) {
  3043. autoRaidAdventure()
  3044. }
  3045. /** Удаление лавки редкостей */
  3046. if (call.ident == callsIdent['missionRaid']) {
  3047. if (call.r###lt?.heroesMerchant) {
  3048. delete call.r###lt.heroesMerchant;
  3049. isChange = true;
  3050. }
  3051. }
  3052. /** missionTimer */
  3053. if (call.ident == callsIdent['missionStart']) {
  3054. missionBattle = call.r###lt.response;
  3055. }
  3056. /** Награды турнира стихий */
  3057. if (call.ident == callsIdent['hallOfFameGetTrophies']) {
  3058. const trophys = call.r###lt.response;
  3059. const calls = [];
  3060. for (const week in trophys) {
  3061. const trophy = trophys[week];
  3062. if (!trophy.championRewardFarmed) {
  3063. calls.push({
  3064. name: 'hallOfFameFarmTrophyReward',
  3065. args: { trophyId: week, rewardType: 'champion' },
  3066. ident: 'body_champion_' + week,
  3067. });
  3068. }
  3069. if (Object.keys(trophy.clanReward).length && !trophy.clanRewardFarmed) {
  3070. calls.push({
  3071. name: 'hallOfFameFarmTrophyReward',
  3072. args: { trophyId: week, rewardType: 'clan' },
  3073. ident: 'body_clan_' + week,
  3074. });
  3075. }
  3076. }
  3077. if (calls.length) {
  3078. Send({ calls })
  3079. .then((e) => e.r###lts.map((e) => e.r###lt.response))
  3080. .then(async r###lts => {
  3081. let coin18 = 0,
  3082. coin19 = 0,
  3083. gold = 0,
  3084. starmoney = 0;
  3085. for (const r of r###lts) {
  3086. coin18 += r?.coin ? +r.coin[18] : 0;
  3087. coin19 += r?.coin ? +r.coin[19] : 0;
  3088. gold += r?.gold ? +r.gold : 0;
  3089. starmoney += r?.starmoney ? +r.starmoney : 0;
  3090. }
  3091. let msg = I18N('ELEMENT_TOURNAMENT_REWARD') + '<br>';
  3092. if (coin18) {
  3093. msg += cheats.translate('LIB_COIN_NAME_18') + `: ${coin18}<br>`;
  3094. }
  3095. if (coin19) {
  3096. msg += cheats.translate('LIB_COIN_NAME_19') + `: ${coin19}<br>`;
  3097. }
  3098. if (gold) {
  3099. msg += cheats.translate('LIB_PSEUDO_COIN') + `: ${gold}<br>`;
  3100. }
  3101. if (starmoney) {
  3102. msg += cheats.translate('LIB_PSEUDO_STARMONEY') + `: ${starmoney}<br>`;
  3103. }
  3104. await popup.confirm(msg, [{ msg: I18N('BTN_OK'), r###lt: 0 }]);
  3105. });
  3106. }
  3107. }
  3108. if (call.ident == callsIdent['clanDomination_getInfo']) {
  3109. clanDominationGetInfo = call.r###lt.response;
  3110. }
  3111. if (call.ident == callsIdent['clanRaid_endBossBattle']) {
  3112. console.log(call.r###lt.response);
  3113. const damage = Object.values(call.r###lt.response.damage).reduce((a, e) => a + e);
  3114. if (call.r###lt.response.r###lt.afterInvalid) {
  3115. addProgress('<br>' + I18N('SERVER_NOT_ACCEPT'));
  3116. }
  3117. addProgress('<br>Server > ' + I18N('BOSS_DAMAGE') + damage.toLocaleString());
  3118. }
  3119. if (call.ident == callsIdent['invasion_getInfo']) {
  3120. const r = call.r###lt.response;
  3121. if (r?.actions?.length) {
  3122. const boss = r.actions.find((e) => e.payload.id === invasionInfo.id);
  3123. if (boss) {
  3124. invasionInfo.buff = r.buffAmount;
  3125. invasionInfo.bossLvl = boss.payload.level;
  3126. if (isChecked('tryFixIt_v2')) {
  3127. const pack = invasionDataPacks[invasionInfo.bossLvl];
  3128. if (pack) {
  3129. setProgress(
  3130. I18N('INVASION_BOSS_BUFF', {
  3131. bossLvl: invasionInfo.bossLvl,
  3132. needBuff: pack.buff,
  3133. haveBuff: invasionInfo.buff,
  3134. }),
  3135. false
  3136. );
  3137. }
  3138. }
  3139. }
  3140. }
  3141. }
  3142. if (call.ident == callsIdent['workshopBuff_create']) {
  3143. const r = call.r###lt.response;
  3144. if (r.id == 1) {
  3145. invasionInfo.buff = r.amount;
  3146. if (isChecked('tryFixIt_v2')) {
  3147. const pack = invasionDataPacks[invasionInfo.bossLvl];
  3148. if (pack) {
  3149. setProgress(
  3150. I18N('INVASION_BOSS_BUFF', {
  3151. bossLvl: invasionInfo.bossLvl,
  3152. needBuff: pack.buff,
  3153. haveBuff: invasionInfo.buff,
  3154. }),
  3155. false
  3156. );
  3157. }
  3158. }
  3159. }
  3160. }
  3161. /*
  3162. if (call.ident == callsIdent['chatGetAll'] && call.args.chatType == 'clanDomination' && !callsIdent['clanDomination_mapState']) {
  3163. this.onReadySuccess = async function () {
  3164. const r###lt = await Send({
  3165. calls: [
  3166. {
  3167. name: 'clanDomination_mapState',
  3168. args: {},
  3169. ident: 'clanDomination_mapState',
  3170. },
  3171. ],
  3172. }).then((e) => e.r###lts[0].r###lt.response);
  3173. let townPositions = r###lt.townPositions;
  3174. let positions = {};
  3175. for (let pos in townPositions) {
  3176. let townPosition = townPositions[pos];
  3177. positions[townPosition.position] = townPosition;
  3178. }
  3179. Object.assign(clanDominationGetInfo, {
  3180. townPositions: positions,
  3181. });
  3182. let userPositions = r###lt.userPositions;
  3183. for (let pos in clanDominationGetInfo.townPositions) {
  3184. let townPosition = clanDominationGetInfo.townPositions[pos];
  3185. if (townPosition.status) {
  3186. userPositions[townPosition.userId] = +pos;
  3187. }
  3188. }
  3189. cheats.updateMap(r###lt);
  3190. };
  3191. }
  3192. if (call.ident == callsIdent['clanDomination_mapState']) {
  3193. const townPositions = call.r###lt.response.townPositions;
  3194. const userPositions = call.r###lt.response.userPositions;
  3195. for (let pos in townPositions) {
  3196. let townPos = townPositions[pos];
  3197. if (townPos.status) {
  3198. userPositions[townPos.userId] = townPos.position;
  3199. }
  3200. }
  3201. isChange = true;
  3202. }
  3203. */
  3204. }
  3205. if (mainReward && artifactChestOpen) {
  3206. console.log(allReward);
  3207. mainReward[artifactChestOpenCallName == 'artifactChestOpen' ? 'chestReward' : 'reward'] = [allReward];
  3208. artifactChestOpen = false;
  3209. artifactChestOpenCallName = '';
  3210. isChange = true;
  3211. }
  3212. } catch(err) {
  3213. console.log("Request(response, " + this.uniqid + "):\n", "Error:\n", response, err);
  3214. }
  3215. if (isChange) {
  3216. Object.defineProperty(this, 'responseText', {
  3217. writable: true
  3218. });
  3219. this.responseText = JSON.stringify(respond);
  3220. }
  3221. }
  3222. /**
  3223. * Request an answer to a question
  3224. *
  3225. * Запрос ответа на вопрос
  3226. */
  3227. async function getAnswer(question) {
  3228. // c29tZSBzdHJhbmdlIHN5bWJvbHM=
  3229. const quizAPI = new ZingerYWebsiteAPI('getAnswer.php', arguments, { question });
  3230. return new Promise((resolve, reject) => {
  3231. quizAPI.request().then((data) => {
  3232. if (data.r###lt) {
  3233. resolve(data.r###lt);
  3234. } else {
  3235. resolve(false);
  3236. }
  3237. }).catch((error) => {
  3238. console.error(error);
  3239. resolve(false);
  3240. });
  3241. })
  3242. }
  3243. /**
  3244. * Submitting a question and answer to a database
  3245. *
  3246. * Отправка вопроса и ответа в базу данных
  3247. */
  3248. function sendAnswerInfo(answerInfo) {
  3249. // c29tZSBub25zZW5zZQ==
  3250. const quizAPI = new ZingerYWebsiteAPI('setAnswer.php', arguments, { answerInfo });
  3251. quizAPI.request().then((data) => {
  3252. if (data.r###lt) {
  3253. console.log(I18N('SENT_QUESTION'));
  3254. }
  3255. });
  3256. }
  3257. /**
  3258. * Returns the battle type by preset type
  3259. *
  3260. * Возвращает тип боя по типу пресета
  3261. */
  3262. function getBattleType(strBattleType) {
  3263. if (!strBattleType) {
  3264. return null;
  3265. }
  3266. switch (strBattleType) {
  3267. case 'titan_pvp':
  3268. return 'get_titanPvp';
  3269. case 'titan_pvp_manual':
  3270. case 'titan_clan_pvp':
  3271. case 'clan_pvp_titan':
  3272. case 'clan_global_pvp_titan':
  3273. case 'brawl_titan':
  3274. case 'challenge_titan':
  3275. case 'titan_mission':
  3276. return 'get_titanPvpManual';
  3277. case 'clan_raid': // Asgard Boss // Босс асгарда
  3278. case 'adventure': // Adventures // Приключения
  3279. case 'clan_global_pvp':
  3280. case 'epic_brawl':
  3281. case 'clan_pvp':
  3282. return 'get_clanPvp';
  3283. case 'dungeon_titan':
  3284. case 'titan_tower':
  3285. return 'get_titan';
  3286. case 'tower':
  3287. case 'clan_dungeon':
  3288. return 'get_tower';
  3289. case 'pve':
  3290. case 'mission':
  3291. return 'get_pve';
  3292. case 'mission_boss':
  3293. return 'get_missionBoss';
  3294. case 'challenge':
  3295. case 'pvp_manual':
  3296. return 'get_pvpManual';
  3297. case 'grand':
  3298. case 'arena':
  3299. case 'pvp':
  3300. case 'clan_domination':
  3301. return 'get_pvp';
  3302. case 'core':
  3303. return 'get_core';
  3304. default: {
  3305. if (strBattleType.includes('invasion')) {
  3306. return 'get_invasion';
  3307. }
  3308. if (strBattleType.includes('boss')) {
  3309. return 'get_boss';
  3310. }
  3311. if (strBattleType.includes('titan_arena')) {
  3312. return 'get_titanPvpManual';
  3313. }
  3314. return 'get_clanPvp';
  3315. }
  3316. }
  3317. }
  3318. /**
  3319. * Returns the class name of the passed object
  3320. *
  3321. * Возвращает название класса переданного объекта
  3322. */
  3323. function getClass(obj) {
  3324. return {}.toString.call(obj).slice(8, -1);
  3325. }
  3326. /**
  3327. * Calculates the request signature
  3328. *
  3329. * Расчитывает сигнатуру запроса
  3330. */
  3331. this.getSignature = function(headers, data) {
  3332. const sign = {
  3333. signature: '',
  3334. length: 0,
  3335. add: function (text) {
  3336. this.signature += text;
  3337. if (this.length < this.signature.length) {
  3338. this.length = 3 * (this.signature.length + 1) >> 1;
  3339. }
  3340. },
  3341. }
  3342. sign.add(headers["X-Request-Id"]);
  3343. sign.add(':');
  3344. sign.add(headers["X-Auth-Token"]);
  3345. sign.add(':');
  3346. sign.add(headers["X-Auth-Session-Id"]);
  3347. sign.add(':');
  3348. sign.add(data);
  3349. sign.add(':');
  3350. sign.add('LIBRARY-VERSION=1');
  3351. sign.add('UNIQUE-SESSION-ID=' + headers["X-Env-Unique-Session-Id"]);
  3352. return md5(sign.signature);
  3353. }
  3354. class HotkeyManager {
  3355. constructor() {
  3356. if (HotkeyManager.instance) {
  3357. return HotkeyManager.instance;
  3358. }
  3359. this.hotkeys = [];
  3360. document.addEventListener('keydown', this.handleKeyDown.bind(this));
  3361. HotkeyManager.instance = this;
  3362. }
  3363. handleKeyDown(event) {
  3364. const key = event.key.toLowerCase();
  3365. const mods = {
  3366. ctrl: event.ctrlKey,
  3367. alt: event.altKey,
  3368. shift: event.shiftKey,
  3369. };
  3370. this.hotkeys.forEach((hotkey) => {
  3371. if (hotkey.key === key && hotkey.ctrl === mods.ctrl && hotkey.alt === mods.alt && hotkey.shift === mods.shift) {
  3372. hotkey.callback(hotkey);
  3373. }
  3374. });
  3375. }
  3376. add(key, opt = {}, callback) {
  3377. this.hotkeys.push({
  3378. key: key.toLowerCase(),
  3379. callback,
  3380. ctrl: opt.ctrl || false,
  3381. alt: opt.alt || false,
  3382. shift: opt.shift || false,
  3383. });
  3384. }
  3385. remove(key, opt = {}) {
  3386. this.hotkeys = this.hotkeys.filter((hotkey) => {
  3387. return !(
  3388. hotkey.key === key.toLowerCase() &&
  3389. hotkey.ctrl === (opt.ctrl || false) &&
  3390. hotkey.alt === (opt.alt || false) &&
  3391. hotkey.shift === (opt.shift || false)
  3392. );
  3393. });
  3394. }
  3395. static getInst() {
  3396. if (!HotkeyManager.instance) {
  3397. new HotkeyManager();
  3398. }
  3399. return HotkeyManager.instance;
  3400. }
  3401. }
  3402. class MouseClicker {
  3403. constructor(element) {
  3404. if (MouseClicker.instance) {
  3405. return MouseClicker.instance;
  3406. }
  3407. this.element = element;
  3408. this.mouse = {
  3409. bubbles: true,
  3410. cancelable: true,
  3411. clientX: 0,
  3412. clientY: 0,
  3413. };
  3414. this.element.addEventListener('mousemove', this.handleMouseMove.bind(this));
  3415. this.clickInfo = {};
  3416. this.nextTimeoutId = 1;
  3417. MouseClicker.instance = this;
  3418. }
  3419. handleMouseMove(event) {
  3420. this.mouse.clientX = event.clientX;
  3421. this.mouse.clientY = event.clientY;
  3422. }
  3423. click(options) {
  3424. options = options || this.mouse;
  3425. this.element.dispatchEvent(new MouseEvent('mousedown', options));
  3426. this.element.dispatchEvent(new MouseEvent('mouseup', options));
  3427. }
  3428. start(interval = 1000, clickCount = Infinity) {
  3429. const currentMouse = { ...this.mouse };
  3430. const timeoutId = this.nextTimeoutId++;
  3431. let count = 0;
  3432. const clickTimeout = () => {
  3433. this.click(currentMouse);
  3434. count++;
  3435. if (count < clickCount) {
  3436. this.clickInfo[timeoutId].timeout = setTimeout(clickTimeout, interval);
  3437. } else {
  3438. delete this.clickInfo[timeoutId];
  3439. }
  3440. };
  3441. this.clickInfo[timeoutId] = {
  3442. timeout: setTimeout(clickTimeout, interval),
  3443. count: clickCount,
  3444. };
  3445. return timeoutId;
  3446. }
  3447. stop(timeoutId) {
  3448. if (this.clickInfo[timeoutId]) {
  3449. clearTimeout(this.clickInfo[timeoutId].timeout);
  3450. delete this.clickInfo[timeoutId];
  3451. }
  3452. }
  3453. stopAll() {
  3454. for (const timeoutId in this.clickInfo) {
  3455. clearTimeout(this.clickInfo[timeoutId].timeout);
  3456. }
  3457. this.clickInfo = {};
  3458. }
  3459. static getInst(element) {
  3460. if (!MouseClicker.instance) {
  3461. new MouseClicker(element);
  3462. }
  3463. return MouseClicker.instance;
  3464. }
  3465. }
  3466. let extintionsList = [];
  3467. /**
  3468. * Creates an interface
  3469. *
  3470. * Создает интерфейс
  3471. */
  3472. function createInterface() {
  3473. popup.init();
  3474. scriptMenu.init();
  3475. scriptMenu.addHeader(GM_info.script.name, justInfo);
  3476. const versionHeader = scriptMenu.addHeader('v' + GM_info.script.version);
  3477. if (extintionsList.length) {
  3478. versionHeader.title = '';
  3479. versionHeader.style.color = 'red';
  3480. for (const extintion of extintionsList) {
  3481. const { name, ver, author } = extintion;
  3482. versionHeader.title += name + ', v' + ver + ' by ' + author + '\n';
  3483. }
  3484. }
  3485. // AutoClicker
  3486. const hkm = new HotkeyManager();
  3487. const fc = document.getElementById('flash-content') || document.getElementById('game');
  3488. const mc = new MouseClicker(fc);
  3489. function toggleClicker(self, timeout) {
  3490. if (self.onClick) {
  3491. console.log('Останавливаем клики');
  3492. mc.stop(self.onClick);
  3493. self.onClick = false;
  3494. } else {
  3495. console.log('Стартуем клики');
  3496. self.onClick = mc.start(timeout);
  3497. }
  3498. }
  3499. hkm.add('C', { ctrl: true, alt: true }, (self) => {
  3500. console.log('"Ctrl + Alt + C"');
  3501. toggleClicker(self, 20);
  3502. });
  3503. hkm.add('V', { ctrl: true, alt: true }, (self) => {
  3504. console.log('"Ctrl + Alt + V"');
  3505. toggleClicker(self, 100);
  3506. });
  3507. }
  3508. function addExtentionName(name, ver, author) {
  3509. extintionsList.push({
  3510. name,
  3511. ver,
  3512. author,
  3513. });
  3514. }
  3515. function addControls() {
  3516. createInterface();
  3517. const checkboxDetails = scriptMenu.addDetails(I18N('SETTINGS'), 'settings');
  3518. for (let name in checkboxes) {
  3519. if (checkboxes[name].hide) {
  3520. continue;
  3521. }
  3522. checkboxes[name].cbox = scriptMenu.addCheckbox(checkboxes[name].label, checkboxes[name].title, checkboxDetails);
  3523. /**
  3524. * Getting the state of checkboxes from storage
  3525. * Получаем состояние чекбоксов из storage
  3526. */
  3527. let val = storage.get(name, null);
  3528. if (val != null) {
  3529. checkboxes[name].cbox.checked = val;
  3530. } else {
  3531. storage.set(name, checkboxes[name].default);
  3532. checkboxes[name].cbox.checked = checkboxes[name].default;
  3533. }
  3534. /**
  3535. * Tracing the change event of the checkbox for writing to storage
  3536. * Отсеживание события изменения чекбокса для записи в storage
  3537. */
  3538. checkboxes[name].cbox.dataset['name'] = name;
  3539. checkboxes[name].cbox.addEventListener('change', async function (event) {
  3540. const nameCheckbox = this.dataset['name'];
  3541. /*
  3542. if (this.checked && nameCheckbox == 'cancelBattle') {
  3543. this.checked = false;
  3544. if (await popup.confirm(I18N('MSG_BAN_ATTENTION'), [
  3545. { msg: I18N('BTN_NO_I_AM_AGAINST'), r###lt: true },
  3546. { msg: I18N('BTN_YES_I_AGREE'), r###lt: false },
  3547. ])) {
  3548. return;
  3549. }
  3550. this.checked = true;
  3551. }
  3552. */
  3553. storage.set(nameCheckbox, this.checked);
  3554. })
  3555. }
  3556. const inputDetails = scriptMenu.addDetails(I18N('VALUES'), 'values');
  3557. for (let name in inputs) {
  3558. inputs[name].input = scriptMenu.addInputText(inputs[name].title, false, inputDetails);
  3559. /**
  3560. * Get inputText state from storage
  3561. * Получаем состояние inputText из storage
  3562. */
  3563. let val = storage.get(name, null);
  3564. if (val != null) {
  3565. inputs[name].input.value = val;
  3566. } else {
  3567. storage.set(name, inputs[name].default);
  3568. inputs[name].input.value = inputs[name].default;
  3569. }
  3570. /**
  3571. * Tracing a field change event for a record in storage
  3572. * Отсеживание события изменения поля для записи в storage
  3573. */
  3574. inputs[name].input.dataset['name'] = name;
  3575. inputs[name].input.addEventListener('input', function () {
  3576. const inputName = this.dataset['name'];
  3577. let value = +this.value;
  3578. if (!value || Number.isNaN(value)) {
  3579. value = storage.get(inputName, inputs[inputName].default);
  3580. inputs[name].input.value = value;
  3581. }
  3582. storage.set(inputName, value);
  3583. })
  3584. }
  3585. }
  3586. /**
  3587. * Sending a request
  3588. *
  3589. * Отправка запроса
  3590. */
  3591. function send(json, callback, pr) {
  3592. if (typeof json == 'string') {
  3593. json = JSON.parse(json);
  3594. }
  3595. for (const call of json.calls) {
  3596. if (!call?.context?.actionTs) {
  3597. call.context = {
  3598. actionTs: Math.floor(performance.now())
  3599. }
  3600. }
  3601. }
  3602. json = JSON.stringify(json);
  3603. /**
  3604. * We get the headlines of the previous intercepted request
  3605. * Получаем заголовки предыдущего перехваченого запроса
  3606. */
  3607. let headers = lastHeaders;
  3608. /**
  3609. * We increase the header of the query Certifier by 1
  3610. * Увеличиваем заголовок идетификатора запроса на 1
  3611. */
  3612. headers["X-Request-Id"]++;
  3613. /**
  3614. * We calculate the title with the signature
  3615. * Расчитываем заголовок с сигнатурой
  3616. */
  3617. headers["X-Auth-Signature"] = getSignature(headers, json);
  3618. /**
  3619. * Create a new ajax request
  3620. * Создаем новый AJAX запрос
  3621. */
  3622. let xhr = new XMLHttpRequest;
  3623. /**
  3624. * Indicate the previously saved URL for API queries
  3625. * Указываем ранее сохраненный URL для API запросов
  3626. */
  3627. xhr.open('POST', apiUrl, true);
  3628. /**
  3629. * Add the function to the event change event
  3630. * Добавляем функцию к событию смены статуса запроса
  3631. */
  3632. xhr.onreadystatechange = function() {
  3633. /**
  3634. * If the r###lt of the request is obtained, we call the flask function
  3635. * Если результат запроса получен вызываем колбек функцию
  3636. */
  3637. if(xhr.readyState == 4) {
  3638. callback(xhr.response, pr);
  3639. }
  3640. };
  3641. /**
  3642. * Indicate the type of request
  3643. * Указываем тип запроса
  3644. */
  3645. xhr.responseType = 'json';
  3646. /**
  3647. * We set the request headers
  3648. * Задаем заголовки запроса
  3649. */
  3650. for(let nameHeader in headers) {
  3651. let head = headers[nameHeader];
  3652. xhr.setRequestHeader(nameHeader, head);
  3653. }
  3654. /**
  3655. * Sending a request
  3656. * Отправляем запрос
  3657. */
  3658. xhr.send(json);
  3659. }
  3660. let hideTimeoutProgress = 0;
  3661. /**
  3662. * Hide progress
  3663. *
  3664. * Скрыть прогресс
  3665. */
  3666. function hideProgress(timeout) {
  3667. timeout = timeout || 0;
  3668. clearTimeout(hideTimeoutProgress);
  3669. hideTimeoutProgress = setTimeout(function () {
  3670. scriptMenu.setStatus('');
  3671. }, timeout);
  3672. }
  3673. /**
  3674. * Progress display
  3675. *
  3676. * Отображение прогресса
  3677. */
  3678. function setProgress(text, hide, onclick) {
  3679. scriptMenu.setStatus(text, onclick);
  3680. hide = hide || false;
  3681. if (hide) {
  3682. hideProgress(3000);
  3683. }
  3684. }
  3685. /**
  3686. * Progress added
  3687. *
  3688. * Дополнение прогресса
  3689. */
  3690. function addProgress(text) {
  3691. scriptMenu.addStatus(text);
  3692. }
  3693. /**
  3694. * Returns the timer value depending on the subscription
  3695. *
  3696. * Возвращает значение таймера в зависимости от подписки
  3697. */
  3698. function getTimer(time, div) {
  3699. let speedDiv = 5;
  3700. if (subEndTime < Date.now()) {
  3701. speedDiv = div || 1.5;
  3702. }
  3703. return Math.max(Math.ceil(time / speedDiv + 1.5), 4);
  3704. }
  3705. function startSlave() {
  3706. const { slaveFixBattle } = HWHClasses;
  3707. const sFix = new slaveFixBattle();
  3708. sFix.wsStart();
  3709. }
  3710. this.testFuntions = {
  3711. hideProgress,
  3712. setProgress,
  3713. addProgress,
  3714. masterFix: false,
  3715. startSlave,
  3716. };
  3717. this.HWHFuncs = {
  3718. send,
  3719. I18N,
  3720. isChecked,
  3721. getInput,
  3722. copyText,
  3723. confShow,
  3724. hideProgress,
  3725. setProgress,
  3726. addProgress,
  3727. getTimer,
  3728. addExtentionName,
  3729. getUserInfo,
  3730. setIsCancalBattle,
  3731. random,
  3732. };
  3733. this.HWHClasses = {
  3734. checkChangeSend,
  3735. checkChangeResponse,
  3736. };
  3737. /**
  3738. * Calculates HASH MD5 from string
  3739. *
  3740. * Расчитывает HASH MD5 из строки
  3741. *
  3742. * [js-md5]{@link https://github.com/emn178/js-md5}
  3743. *
  3744. * @namespace md5
  3745. * @version 0.7.3
  3746. * @author Chen, Yi-Cyuan [emn178@gmail.com]
  3747. * @copyright Chen, Yi-Cyuan 2014-2017
  3748. * @license MIT
  3749. */
  3750. !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 _}))}();
  3751. class Caller {
  3752. static globalHooks = {
  3753. onError: null,
  3754. };
  3755. constructor(calls = null) {
  3756. this.calls = [];
  3757. this.r###lts = {};
  3758. if (calls) {
  3759. this.add(calls);
  3760. }
  3761. }
  3762. static setGlobalHook(event, callback) {
  3763. if (this.globalHooks[event] !== undefined) {
  3764. this.globalHooks[event] = callback;
  3765. } else {
  3766. throw new Error(`Unknown event: ${event}`);
  3767. }
  3768. }
  3769. addCall(call) {
  3770. const { name = call, args = {} } = typeof call === 'object' ? call : { name: call };
  3771. this.calls.push({ name, args });
  3772. return this;
  3773. }
  3774. add(name) {
  3775. if (Array.isArray(name)) {
  3776. name.forEach((call) => this.addCall(call));
  3777. } else {
  3778. this.addCall(name);
  3779. }
  3780. return this;
  3781. }
  3782. handleError(error) {
  3783. const errorName = error.name;
  3784. const errorDescription = error.description;
  3785. if (Caller.globalHooks.onError) {
  3786. const shouldThrow = Caller.globalHooks.onError(error);
  3787. if (shouldThrow === false) {
  3788. return;
  3789. }
  3790. }
  3791. if (error.call) {
  3792. const callInfo = error.call;
  3793. throw new Error(`${errorName} in ${callInfo.name}: ${errorDescription}\n` + `Args: ${JSON.stringify(callInfo.args)}\n`);
  3794. } else if (errorName === 'common\\rpc\\exception\\InvalidRequest') {
  3795. throw new Error(`Invalid request: ${errorDescription}`);
  3796. } else {
  3797. throw new Error(`Unknown error: ${errorName} - ${errorDescription}`);
  3798. }
  3799. }
  3800. async send() {
  3801. if (!this.calls.length) {
  3802. throw new Error('No calls to send.');
  3803. }
  3804. const identToNameMap = {};
  3805. const callsWithIdent = this.calls.map((call, index) => {
  3806. const ident = this.calls.length === 1 ? 'body' : `group_${index}_body`;
  3807. identToNameMap[ident] = call.name;
  3808. return { ...call, ident };
  3809. });
  3810. try {
  3811. const response = await Send({ calls: callsWithIdent });
  3812. if (response.error) {
  3813. this.handleError(response.error);
  3814. }
  3815. if (!response.r###lts) {
  3816. throw new Error('Invalid response format: missing "r###lts" field');
  3817. }
  3818. response.r###lts.forEach((r###lt) => {
  3819. const name = identToNameMap[r###lt.ident];
  3820. if (!this.r###lts[name]) {
  3821. this.r###lts[name] = [];
  3822. }
  3823. this.r###lts[name].push(r###lt.r###lt.response);
  3824. });
  3825. } catch (error) {
  3826. throw error;
  3827. }
  3828. return this;
  3829. }
  3830. r###lt(name, forceArray = false) {
  3831. const r###lts = name ? this.r###lts[name] || [] : Object.values(this.r###lts).flat();
  3832. return forceArray || r###lts.length !== 1 ? r###lts : r###lts[0];
  3833. }
  3834. async execute(name) {
  3835. try {
  3836. await this.send();
  3837. return this.r###lt(name);
  3838. } catch (error) {
  3839. throw error;
  3840. }
  3841. }
  3842. clear() {
  3843. this.calls = [];
  3844. this.r###lts = {};
  3845. return this;
  3846. }
  3847. isEmpty() {
  3848. return this.calls.length === 0 && Object.keys(this.r###lts).length === 0;
  3849. }
  3850. }
  3851. this.Caller = Caller;
  3852. /*
  3853. // Примеры использования
  3854. (async () => {
  3855. // Короткий вызов
  3856. await new Caller('inventoryGet').execute();
  3857. // Простой вызов
  3858. let r###lt = await new Caller().add('inventoryGet').execute();
  3859. console.log('Inventory Get R###lt:', r###lt);
  3860. // Сложный вызов
  3861. let caller = new Caller();
  3862. await caller
  3863. .add([
  3864. {
  3865. name: 'inventoryGet',
  3866. args: {},
  3867. },
  3868. {
  3869. name: 'heroGetAll',
  3870. args: {},
  3871. },
  3872. ])
  3873. .send();
  3874. console.log('Inventory Get R###lt:', caller.r###lt('inventoryGet'));
  3875. console.log('Hero Get All R###lt:', caller.r###lt('heroGetAll'));
  3876. // Очистка всех данных
  3877. caller.clear();
  3878. })();
  3879. */
  3880. /**
  3881. * Script for beautiful dialog boxes
  3882. *
  3883. * Скрипт для красивых диалоговых окошек
  3884. */
  3885. const popup = new (function () {
  3886. this.popUp,
  3887. this.downer,
  3888. this.middle,
  3889. this.msgText,
  3890. this.buttons = [];
  3891. this.checkboxes = [];
  3892. this.dialogPromice = null;
  3893. this.isInit = false;
  3894. this.init = function () {
  3895. if (this.isInit) {
  3896. return;
  3897. }
  3898. addStyle();
  3899. addBlocks();
  3900. addEventListeners();
  3901. this.isInit = true;
  3902. }
  3903. const addEventListeners = () => {
  3904. document.addEventListener('keyup', (e) => {
  3905. if (e.key == 'Escape') {
  3906. if (this.dialogPromice) {
  3907. const { func, r###lt } = this.dialogPromice;
  3908. this.dialogPromice = null;
  3909. popup.hide();
  3910. func(r###lt);
  3911. }
  3912. }
  3913. });
  3914. }
  3915. const addStyle = () => {
  3916. let style = document.createElement('style');
  3917. style.innerText = `
  3918. .PopUp_ {
  3919. position: absolute;
  3920. min-width: 300px;
  3921. max-width: 500px;
  3922. max-height: 600px;
  3923. background-color: #190e08e6;
  3924. z-index: 10001;
  3925. top: 169px;
  3926. left: 345px;
  3927. border: 3px #ce9767 solid;
  3928. border-radius: 10px;
  3929. display: flex;
  3930. flex-direction: column;
  3931. justify-content: space-around;
  3932. padding: 15px 9px;
  3933. box-sizing: border-box;
  3934. }
  3935. .PopUp_back {
  3936. position: absolute;
  3937. background-color: #00000066;
  3938. width: 100%;
  3939. height: 100%;
  3940. z-index: 10000;
  3941. top: 0;
  3942. left: 0;
  3943. }
  3944. .PopUp_close {
  3945. width: 40px;
  3946. height: 40px;
  3947. position: absolute;
  3948. right: -18px;
  3949. top: -18px;
  3950. border: 3px solid #c18550;
  3951. border-radius: 20px;
  3952. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  3953. background-position-y: 3px;
  3954. box-shadow: -1px 1px 3px black;
  3955. cursor: pointer;
  3956. box-sizing: border-box;
  3957. }
  3958. .PopUp_close:hover {
  3959. filter: brightness(1.2);
  3960. }
  3961. .PopUp_crossClose {
  3962. width: 100%;
  3963. height: 100%;
  3964. background-size: 65%;
  3965. background-position: center;
  3966. background-repeat: no-repeat;
  3967. 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")
  3968. }
  3969. .PopUp_blocks {
  3970. width: 100%;
  3971. height: 50%;
  3972. display: flex;
  3973. justify-content: space-evenly;
  3974. align-items: center;
  3975. flex-wrap: wrap;
  3976. justify-content: center;
  3977. }
  3978. .PopUp_blocks:last-child {
  3979. margin-top: 25px;
  3980. }
  3981. .PopUp_buttons {
  3982. display: flex;
  3983. margin: 7px 10px;
  3984. flex-direction: column;
  3985. }
  3986. .PopUp_button {
  3987. background-color: #52A81C;
  3988. border-radius: 5px;
  3989. box-shadow: inset 0px -4px 10px, inset 0px 3px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  3990. cursor: pointer;
  3991. padding: 4px 12px 6px;
  3992. }
  3993. .PopUp_input {
  3994. text-align: center;
  3995. font-size: 16px;
  3996. height: 27px;
  3997. border: 1px solid #cf9250;
  3998. border-radius: 9px 9px 0px 0px;
  3999. background: transparent;
  4000. color: #fce1ac;
  4001. padding: 1px 10px;
  4002. box-sizing: border-box;
  4003. box-shadow: 0px 0px 4px, 0px 0px 0px 3px #ce9767;
  4004. }
  4005. .PopUp_checkboxes {
  4006. display: flex;
  4007. flex-direction: column;
  4008. margin: 15px 15px -5px 15px;
  4009. align-items: flex-start;
  4010. }
  4011. .PopUp_ContCheckbox {
  4012. margin: 2px 0px;
  4013. }
  4014. .PopUp_checkbox {
  4015. position: absolute;
  4016. z-index: -1;
  4017. opacity: 0;
  4018. }
  4019. .PopUp_checkbox+label {
  4020. display: inline-flex;
  4021. align-items: center;
  4022. user-select: none;
  4023. font-size: 15px;
  4024. font-family: sans-serif;
  4025. font-weight: 600;
  4026. font-stretch: condensed;
  4027. letter-spacing: 1px;
  4028. color: #fce1ac;
  4029. text-shadow: 0px 0px 1px;
  4030. }
  4031. .PopUp_checkbox+label::before {
  4032. content: '';
  4033. display: inline-block;
  4034. width: 20px;
  4035. height: 20px;
  4036. border: 1px solid #cf9250;
  4037. border-radius: 7px;
  4038. margin-right: 7px;
  4039. }
  4040. .PopUp_checkbox:checked+label::before {
  4041. 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");
  4042. }
  4043. .PopUp_input::placeholder {
  4044. color: #fce1ac75;
  4045. }
  4046. .PopUp_input:focus {
  4047. outline: 0;
  4048. }
  4049. .PopUp_input + .PopUp_button {
  4050. border-radius: 0px 0px 5px 5px;
  4051. padding: 2px 18px 5px;
  4052. }
  4053. .PopUp_button:hover {
  4054. filter: brightness(1.2);
  4055. }
  4056. .PopUp_button:active {
  4057. box-shadow: inset 0px 5px 10px, inset 0px 1px 2px #99fe20, 0px 0px 4px, 0px -3px 1px #d7b275, 0px 0px 0px 3px #ce9767;
  4058. }
  4059. .PopUp_text {
  4060. font-size: 22px;
  4061. font-family: sans-serif;
  4062. font-weight: 600;
  4063. font-stretch: condensed;
  4064. letter-spacing: 1px;
  4065. text-align: center;
  4066. }
  4067. .PopUp_buttonText {
  4068. color: #E4FF4C;
  4069. text-shadow: 0px 1px 2px black;
  4070. }
  4071. .PopUp_msgText {
  4072. color: #FDE5B6;
  4073. text-shadow: 0px 0px 2px;
  4074. }
  4075. .PopUp_hideBlock {
  4076. display: none;
  4077. }
  4078. `;
  4079. document.head.appendChild(style);
  4080. }
  4081. const addBlocks = () => {
  4082. this.back = document.createElement('div');
  4083. this.back.classList.add('PopUp_back');
  4084. this.back.classList.add('PopUp_hideBlock');
  4085. document.body.append(this.back);
  4086. this.popUp = document.createElement('div');
  4087. this.popUp.classList.add('PopUp_');
  4088. this.back.append(this.popUp);
  4089. let upper = document.createElement('div')
  4090. upper.classList.add('PopUp_blocks');
  4091. this.popUp.append(upper);
  4092. this.middle = document.createElement('div')
  4093. this.middle.classList.add('PopUp_blocks');
  4094. this.middle.classList.add('PopUp_checkboxes');
  4095. this.popUp.append(this.middle);
  4096. this.downer = document.createElement('div')
  4097. this.downer.classList.add('PopUp_blocks');
  4098. this.popUp.append(this.downer);
  4099. this.msgText = document.createElement('div');
  4100. this.msgText.classList.add('PopUp_text', 'PopUp_msgText');
  4101. upper.append(this.msgText);
  4102. }
  4103. this.showBack = function () {
  4104. this.back.classList.remove('PopUp_hideBlock');
  4105. }
  4106. this.hideBack = function () {
  4107. this.back.classList.add('PopUp_hideBlock');
  4108. }
  4109. this.show = function () {
  4110. if (this.checkboxes.length) {
  4111. this.middle.classList.remove('PopUp_hideBlock');
  4112. }
  4113. this.showBack();
  4114. this.popUp.classList.remove('PopUp_hideBlock');
  4115. this.popUp.style.left = (window.innerWidth - this.popUp.offsetWidth) / 2 + 'px';
  4116. this.popUp.style.top = (window.innerHeight - this.popUp.offsetHeight) / 3 + 'px';
  4117. }
  4118. this.hide = function () {
  4119. this.hideBack();
  4120. this.popUp.classList.add('PopUp_hideBlock');
  4121. }
  4122. this.addAnyButton = (option) => {
  4123. const contButton = document.createElement('div');
  4124. contButton.classList.add('PopUp_buttons');
  4125. this.downer.append(contButton);
  4126. let inputField = {
  4127. value: option.r###lt || option.default
  4128. }
  4129. if (option.isInput) {
  4130. inputField = document.createElement('input');
  4131. inputField.type = 'text';
  4132. if (option.placeholder) {
  4133. inputField.placeholder = option.placeholder;
  4134. }
  4135. if (option.default) {
  4136. inputField.value = option.default;
  4137. }
  4138. inputField.classList.add('PopUp_input');
  4139. contButton.append(inputField);
  4140. }
  4141. const button = document.createElement('div');
  4142. button.classList.add('PopUp_button');
  4143. button.title = option.title || '';
  4144. contButton.append(button);
  4145. const buttonText = document.createElement('div');
  4146. buttonText.classList.add('PopUp_text', 'PopUp_buttonText');
  4147. buttonText.innerHTML = option.msg;
  4148. button.append(buttonText);
  4149. return { button, contButton, inputField };
  4150. }
  4151. this.addCloseButton = () => {
  4152. let button = document.createElement('div')
  4153. button.classList.add('PopUp_close');
  4154. this.popUp.append(button);
  4155. let crossClose = document.createElement('div')
  4156. crossClose.classList.add('PopUp_crossClose');
  4157. button.append(crossClose);
  4158. return { button, contButton: button };
  4159. }
  4160. this.addButton = (option, buttonClick) => {
  4161. const { button, contButton, inputField } = option.isClose ? this.addCloseButton() : this.addAnyButton(option);
  4162. if (option.isClose) {
  4163. this.dialogPromice = { func: buttonClick, r###lt: option.r###lt };
  4164. }
  4165. button.addEventListener('click', () => {
  4166. let r###lt = '';
  4167. if (option.isInput) {
  4168. r###lt = inputField.value;
  4169. }
  4170. if (option.isClose || option.isCancel) {
  4171. this.dialogPromice = null;
  4172. }
  4173. buttonClick(r###lt);
  4174. });
  4175. this.buttons.push(contButton);
  4176. }
  4177. this.clearButtons = () => {
  4178. while (this.buttons.length) {
  4179. this.buttons.pop().remove();
  4180. }
  4181. }
  4182. this.addCheckBox = (checkBox) => {
  4183. const contCheckbox = document.createElement('div');
  4184. contCheckbox.classList.add('PopUp_ContCheckbox');
  4185. this.middle.append(contCheckbox);
  4186. const checkbox = document.createElement('input');
  4187. checkbox.type = 'checkbox';
  4188. checkbox.id = 'PopUpCheckbox' + this.checkboxes.length;
  4189. checkbox.dataset.name = checkBox.name;
  4190. checkbox.checked = checkBox.checked;
  4191. checkbox.label = checkBox.label;
  4192. checkbox.title = checkBox.title || '';
  4193. checkbox.classList.add('PopUp_checkbox');
  4194. contCheckbox.appendChild(checkbox)
  4195. const checkboxLabel = document.createElement('label');
  4196. checkboxLabel.innerText = checkBox.label;
  4197. checkboxLabel.title = checkBox.title || '';
  4198. checkboxLabel.setAttribute('for', checkbox.id);
  4199. contCheckbox.appendChild(checkboxLabel);
  4200. this.checkboxes.push(checkbox);
  4201. }
  4202. this.clearCheckBox = () => {
  4203. this.middle.classList.add('PopUp_hideBlock');
  4204. while (this.checkboxes.length) {
  4205. this.checkboxes.pop().parentNode.remove();
  4206. }
  4207. }
  4208. this.setMsgText = (text) => {
  4209. this.msgText.innerHTML = text;
  4210. }
  4211. this.getCheckBoxes = () => {
  4212. const checkBoxes = [];
  4213. for (const checkBox of this.checkboxes) {
  4214. checkBoxes.push({
  4215. name: checkBox.dataset.name,
  4216. label: checkBox.label,
  4217. checked: checkBox.checked
  4218. });
  4219. }
  4220. return checkBoxes;
  4221. }
  4222. this.confirm = async (msg, buttOpt, checkBoxes = []) => {
  4223. if (!this.isInit) {
  4224. this.init();
  4225. }
  4226. this.clearButtons();
  4227. this.clearCheckBox();
  4228. return new Promise((complete, failed) => {
  4229. this.setMsgText(msg);
  4230. if (!buttOpt) {
  4231. buttOpt = [{ msg: 'Ok', r###lt: true, isInput: false }];
  4232. }
  4233. for (const checkBox of checkBoxes) {
  4234. this.addCheckBox(checkBox);
  4235. }
  4236. for (let butt of buttOpt) {
  4237. this.addButton(butt, (r###lt) => {
  4238. r###lt = r###lt || butt.r###lt;
  4239. complete(r###lt);
  4240. popup.hide();
  4241. });
  4242. if (butt.isCancel) {
  4243. this.dialogPromice = { func: complete, r###lt: butt.r###lt };
  4244. }
  4245. }
  4246. this.show();
  4247. });
  4248. }
  4249. });
  4250. this.HWHFuncs.popup = popup;
  4251. /**
  4252. * Script control panel
  4253. *
  4254. * Панель управления скриптом
  4255. */
  4256. class ScriptMenu {
  4257. constructor() {
  4258. this.mainMenu = null;
  4259. this.buttons = [];
  4260. this.checkboxes = [];
  4261. this.option = {
  4262. showMenu: true,
  4263. showDetails: {},
  4264. };
  4265. }
  4266. init(option = {}) {
  4267. this.option = Object.assign(this.option, option);
  4268. const saveOption = this.loadSaveOption();
  4269. this.option = Object.assign(this.option, saveOption);
  4270. this.addStyle();
  4271. this.addBlocks();
  4272. }
  4273. addStyle() {
  4274. const style = document.createElement('style');
  4275. style.innerText = `
  4276. .scriptMenu_status {
  4277. position: absolute;
  4278. z-index: 10001;
  4279. top: -1px;
  4280. left: 30%;
  4281. cursor: pointer;
  4282. border-radius: 0px 0px 10px 10px;
  4283. background: #190e08e6;
  4284. border: 1px #ce9767 solid;
  4285. font-size: 18px;
  4286. font-family: sans-serif;
  4287. font-weight: 600;
  4288. font-stretch: condensed;
  4289. letter-spacing: 1px;
  4290. color: #fce1ac;
  4291. text-shadow: 0px 0px 1px;
  4292. transition: 0.5s;
  4293. padding: 2px 10px 3px;
  4294. }
  4295. .scriptMenu_statusHide {
  4296. top: -35px;
  4297. height: 30px;
  4298. overflow: hidden;
  4299. }
  4300. .scriptMenu_label {
  4301. position: absolute;
  4302. top: 30%;
  4303. left: -4px;
  4304. z-index: 9999;
  4305. cursor: pointer;
  4306. width: 30px;
  4307. height: 30px;
  4308. background: radial-gradient(circle, #47a41b 0%, #1a2f04 100%);
  4309. border: 1px solid #1a2f04;
  4310. border-radius: 5px;
  4311. box-shadow:
  4312. inset 0px 2px 4px #83ce26,
  4313. inset 0px -4px 6px #1a2f04,
  4314. 0px 0px 2px black,
  4315. 0px 0px 0px 2px #ce9767;
  4316. }
  4317. .scriptMenu_label:hover {
  4318. filter: brightness(1.2);
  4319. }
  4320. .scriptMenu_arrowLabel {
  4321. width: 100%;
  4322. height: 100%;
  4323. background-size: 75%;
  4324. background-position: center;
  4325. background-repeat: no-repeat;
  4326. 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");
  4327. box-shadow: 0px 1px 2px #000;
  4328. border-radius: 5px;
  4329. filter: drop-shadow(0px 1px 2px #000D);
  4330. }
  4331. .scriptMenu_main {
  4332. position: absolute;
  4333. max-width: 285px;
  4334. z-index: 9999;
  4335. top: 50%;
  4336. transform: translateY(-40%);
  4337. background: #190e08e6;
  4338. border: 1px #ce9767 solid;
  4339. border-radius: 0px 10px 10px 0px;
  4340. border-left: none;
  4341. box-sizing: border-box;
  4342. font-size: 15px;
  4343. font-family: sans-serif;
  4344. font-weight: 600;
  4345. font-stretch: condensed;
  4346. letter-spacing: 1px;
  4347. color: #fce1ac;
  4348. text-shadow: 0px 0px 1px;
  4349. transition: 1s;
  4350. }
  4351. .scriptMenu_conteiner {
  4352. max-height: 80vh;
  4353. overflow: scroll;
  4354. scrollbar-width: none; /* Для Firefox */
  4355. -ms-overflow-style: none; /* Для Internet Explorer и Edge */
  4356. display: flex;
  4357. flex-direction: column;
  4358. flex-wrap: nowrap;
  4359. padding: 5px 10px 5px 5px;
  4360. }
  4361. .scriptMenu_conteiner::-webkit-scrollbar {
  4362. display: none; /* Для Chrome, Safari и Opera */
  4363. }
  4364. .scriptMenu_showMenu {
  4365. display: none;
  4366. }
  4367. .scriptMenu_showMenu:checked~.scriptMenu_main {
  4368. left: 0px;
  4369. }
  4370. .scriptMenu_showMenu:not(:checked)~.scriptMenu_main {
  4371. left: -300px;
  4372. }
  4373. .scriptMenu_divInput {
  4374. margin: 2px;
  4375. }
  4376. .scriptMenu_divInputText {
  4377. margin: 2px;
  4378. align-self: center;
  4379. display: flex;
  4380. }
  4381. .scriptMenu_checkbox {
  4382. position: absolute;
  4383. z-index: -1;
  4384. opacity: 0;
  4385. }
  4386. .scriptMenu_checkbox+label {
  4387. display: inline-flex;
  4388. align-items: center;
  4389. user-select: none;
  4390. }
  4391. .scriptMenu_checkbox+label::before {
  4392. content: '';
  4393. display: inline-block;
  4394. width: 20px;
  4395. height: 20px;
  4396. border: 1px solid #cf9250;
  4397. border-radius: 7px;
  4398. margin-right: 7px;
  4399. }
  4400. .scriptMenu_checkbox:checked+label::before {
  4401. 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");
  4402. }
  4403. .scriptMenu_close {
  4404. width: 40px;
  4405. height: 40px;
  4406. position: absolute;
  4407. right: -18px;
  4408. top: -18px;
  4409. border: 3px solid #c18550;
  4410. border-radius: 20px;
  4411. background: radial-gradient(circle, rgba(190,30,35,1) 0%, rgba(0,0,0,1) 100%);
  4412. background-position-y: 3px;
  4413. box-shadow: -1px 1px 3px black;
  4414. cursor: pointer;
  4415. box-sizing: border-box;
  4416. }
  4417. .scriptMenu_close:hover {
  4418. filter: brightness(1.2);
  4419. }
  4420. .scriptMenu_crossClose {
  4421. width: 100%;
  4422. height: 100%;
  4423. background-size: 65%;
  4424. background-position: center;
  4425. background-repeat: no-repeat;
  4426. 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")
  4427. }
  4428. .scriptMenu_button {
  4429. user-select: none;
  4430. cursor: pointer;
  4431. padding: 5px 14px 8px;
  4432. }
  4433. .scriptMenu_button:hover {
  4434. filter: brightness(1.2);
  4435. }
  4436. .scriptMenu_buttonText {
  4437. color: #fce5b7;
  4438. text-shadow: 0px 1px 2px black;
  4439. text-align: center;
  4440. }
  4441. .scriptMenu_header {
  4442. text-align: center;
  4443. align-self: center;
  4444. font-size: 15px;
  4445. margin: 0px 15px;
  4446. }
  4447. .scriptMenu_header a {
  4448. color: #fce5b7;
  4449. text-decoration: none;
  4450. }
  4451. .scriptMenu_InputText {
  4452. text-align: center;
  4453. width: 130px;
  4454. height: 24px;
  4455. border: 1px solid #cf9250;
  4456. border-radius: 9px;
  4457. background: transparent;
  4458. color: #fce1ac;
  4459. padding: 0px 10px;
  4460. box-sizing: border-box;
  4461. }
  4462. .scriptMenu_InputText:focus {
  4463. filter: brightness(1.2);
  4464. outline: 0;
  4465. }
  4466. .scriptMenu_InputText::placeholder {
  4467. color: #fce1ac75;
  4468. }
  4469. .scriptMenu_Summary {
  4470. cursor: pointer;
  4471. margin-left: 7px;
  4472. }
  4473. .scriptMenu_Details {
  4474. align-self: center;
  4475. }
  4476. .scriptMenu_buttonGroup {
  4477. display: flex;
  4478. justify-content: center;
  4479. user-select: none;
  4480. cursor: pointer;
  4481. padding: 0;
  4482. margin: 3px 0;
  4483. }
  4484. .scriptMenu_buttonGroup .scriptMenu_button {
  4485. width: 100%;
  4486. padding: 5px 8px 8px;
  4487. }
  4488. .scriptMenu_mainButton {
  4489. border-radius: 5px;
  4490. margin: 3px 0;
  4491. }
  4492. .scriptMenu_combineButtonLeft {
  4493. border-top-left-radius: 5px;
  4494. border-bottom-left-radius: 5px;
  4495. margin-right: 2px;
  4496. }
  4497. .scriptMenu_combineButtonCenter {
  4498. border-radius: 0px;
  4499. margin-right: 2px;
  4500. }
  4501. .scriptMenu_combineButtonRight {
  4502. border-top-right-radius: 5px;
  4503. border-bottom-right-radius: 5px;
  4504. }
  4505. .scriptMenu_beigeButton {
  4506. border: 1px solid #442901;
  4507. background: radial-gradient(circle, rgba(165,120,56,1) 80%, rgba(0,0,0,1) 110%);
  4508. 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;
  4509. }
  4510. .scriptMenu_beigeButton:active {
  4511. box-shadow: inset 0px 4px 6px #442901, inset 0px 4px 6px #442901, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 1px #ce9767;
  4512. }
  4513. .scriptMenu_greenButton {
  4514. border: 1px solid #1a2f04;
  4515. background: radial-gradient(circle, #47a41b 0%, #1a2f04 150%);
  4516. box-shadow: inset 0px 2px 4px #83ce26, inset 0px -4px 6px #1a2f04, 0px 0px 2px black, 0px 0px 0px 1px #ce9767;
  4517. }
  4518. .scriptMenu_greenButton:active {
  4519. box-shadow: inset 0px 4px 6px #1a2f04, inset 0px 4px 6px #1a2f04, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 1px #ce9767;
  4520. }
  4521. .scriptMenu_redButton {
  4522. border: 1px solid #440101;
  4523. background: radial-gradient(circle, rgb(198, 34, 34) 80%, rgb(0, 0, 0) 110%);
  4524. 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;
  4525. }
  4526. .scriptMenu_redButton:active {
  4527. box-shadow: inset 0px 4px 6px #440101, inset 0px 4px 6px #440101, inset 0px 0px 6px, 0px 0px 4px, 0px 0px 0px 1px #ce9767;
  4528. }
  4529. .scriptMenu_attention {
  4530. position: relative;
  4531. }
  4532. .scriptMenu_attention .scriptMenu_dot {
  4533. display: flex;
  4534. justify-content: center;
  4535. align-items: center;
  4536. }
  4537. .scriptMenu_dot {
  4538. position: absolute;
  4539. top: -7px;
  4540. right: -7px;
  4541. width: 20px;
  4542. height: 20px;
  4543. border-radius: 50%;
  4544. border: 1px solid #c18550;
  4545. background: radial-gradient(circle, #f000 25%, black 100%);
  4546. box-shadow: 0px 0px 2px black;
  4547. background-position: 0px -1px;
  4548. font-size: 10px;
  4549. text-align: center;
  4550. color: white;
  4551. text-shadow: 1px 1px 1px black;
  4552. box-sizing: border-box;
  4553. display: none;
  4554. }
  4555. `;
  4556. document.head.appendChild(style);
  4557. }
  4558. addBlocks() {
  4559. const main = document.createElement('div');
  4560. document.body.appendChild(main);
  4561. this.status = document.createElement('div');
  4562. this.status.classList.add('scriptMenu_status');
  4563. this.setStatus('');
  4564. main.appendChild(this.status);
  4565. const label = document.createElement('label');
  4566. label.classList.add('scriptMenu_label');
  4567. label.setAttribute('for', 'checkbox_showMenu');
  4568. main.appendChild(label);
  4569. const arrowLabel = document.createElement('div');
  4570. arrowLabel.classList.add('scriptMenu_arrowLabel');
  4571. label.appendChild(arrowLabel);
  4572. const checkbox = document.createElement('input');
  4573. checkbox.type = 'checkbox';
  4574. checkbox.id = 'checkbox_showMenu';
  4575. checkbox.checked = this.option.showMenu;
  4576. checkbox.classList.add('scriptMenu_showMenu');
  4577. checkbox.addEventListener('change', () => {
  4578. this.option.showMenu = checkbox.checked;
  4579. this.saveSaveOption();
  4580. });
  4581. main.appendChild(checkbox);
  4582. const mainMenu = document.createElement('div');
  4583. mainMenu.classList.add('scriptMenu_main');
  4584. main.appendChild(mainMenu);
  4585. this.mainMenu = document.createElement('div');
  4586. this.mainMenu.classList.add('scriptMenu_conteiner');
  4587. mainMenu.appendChild(this.mainMenu);
  4588. const closeButton = document.createElement('label');
  4589. closeButton.classList.add('scriptMenu_close');
  4590. closeButton.setAttribute('for', 'checkbox_showMenu');
  4591. this.mainMenu.appendChild(closeButton);
  4592. const crossClose = document.createElement('div');
  4593. crossClose.classList.add('scriptMenu_crossClose');
  4594. closeButton.appendChild(crossClose);
  4595. }
  4596. getButtonColor(color) {
  4597. const buttonColors = {
  4598. green: 'scriptMenu_greenButton',
  4599. red: 'scriptMenu_redButton',
  4600. beige: 'scriptMenu_beigeButton',
  4601. };
  4602. return buttonColors[color] || buttonColors['beige'];
  4603. }
  4604. setStatus(text, onclick) {
  4605. if (!text) {
  4606. this.status.classList.add('scriptMenu_statusHide');
  4607. this.status.innerHTML = '';
  4608. } else {
  4609. this.status.classList.remove('scriptMenu_statusHide');
  4610. this.status.innerHTML = text;
  4611. }
  4612. if (typeof onclick === 'function') {
  4613. this.status.addEventListener('click', onclick, { once: true });
  4614. }
  4615. }
  4616. addStatus(text) {
  4617. if (!this.status.innerHTML) {
  4618. this.status.classList.remove('scriptMenu_statusHide');
  4619. }
  4620. this.status.innerHTML += text;
  4621. }
  4622. addHeader(text, onClick, main = this.mainMenu) {
  4623. const header = document.createElement('div');
  4624. header.classList.add('scriptMenu_header');
  4625. header.innerHTML = text;
  4626. if (typeof onClick === 'function') {
  4627. header.addEventListener('click', onClick);
  4628. }
  4629. main.appendChild(header);
  4630. return header;
  4631. }
  4632. addButton(btn, main = this.mainMenu) {
  4633. const { name, onClick, title, color, dot, classes = [], isCombine } = btn;
  4634. const button = document.createElement('div');
  4635. if (!isCombine) {
  4636. classes.push('scriptMenu_mainButton');
  4637. }
  4638. button.classList.add('scriptMenu_button', this.getButtonColor(color), ...classes);
  4639. button.title = title;
  4640. button.addEventListener('click', onClick);
  4641. main.appendChild(button);
  4642. const buttonText = document.createElement('div');
  4643. buttonText.classList.add('scriptMenu_buttonText');
  4644. buttonText.innerText = name;
  4645. button.appendChild(buttonText);
  4646. if (dot) {
  4647. const dotAtention = document.createElement('div');
  4648. dotAtention.classList.add('scriptMenu_dot');
  4649. dotAtention.title = dot;
  4650. button.appendChild(dotAtention);
  4651. }
  4652. this.buttons.push(button);
  4653. return button;
  4654. }
  4655. addCombinedButton(buttonList, main = this.mainMenu) {
  4656. const buttonGroup = document.createElement('div');
  4657. buttonGroup.classList.add('scriptMenu_buttonGroup');
  4658. let count = 0;
  4659. for (const btn of buttonList) {
  4660. btn.isCombine = true;
  4661. btn.classes ??= [];
  4662. if (count === 0) {
  4663. btn.classes.push('scriptMenu_combineButtonLeft');
  4664. } else if (count === buttonList.length - 1) {
  4665. btn.classes.push('scriptMenu_combineButtonRight');
  4666. } else {
  4667. btn.classes.push('scriptMenu_combineButtonCenter');
  4668. }
  4669. this.addButton(btn, buttonGroup);
  4670. count++;
  4671. }
  4672. const dotAtention = document.createElement('div');
  4673. dotAtention.classList.add('scriptMenu_dot');
  4674. buttonGroup.appendChild(dotAtention);
  4675. main.appendChild(buttonGroup);
  4676. return buttonGroup;
  4677. }
  4678. addCheckbox(label, title, main = this.mainMenu) {
  4679. const divCheckbox = document.createElement('div');
  4680. divCheckbox.classList.add('scriptMenu_divInput');
  4681. divCheckbox.title = title;
  4682. main.appendChild(divCheckbox);
  4683. const checkbox = document.createElement('input');
  4684. checkbox.type = 'checkbox';
  4685. checkbox.id = 'scriptMenuCheckbox' + this.checkboxes.length;
  4686. checkbox.classList.add('scriptMenu_checkbox');
  4687. divCheckbox.appendChild(checkbox);
  4688. const checkboxLabel = document.createElement('label');
  4689. checkboxLabel.innerText = label;
  4690. checkboxLabel.setAttribute('for', checkbox.id);
  4691. divCheckbox.appendChild(checkboxLabel);
  4692. this.checkboxes.push(checkbox);
  4693. return checkbox;
  4694. }
  4695. addInputText(title, placeholder, main = this.mainMenu) {
  4696. const divInputText = document.createElement('div');
  4697. divInputText.classList.add('scriptMenu_divInputText');
  4698. divInputText.title = title;
  4699. main.appendChild(divInputText);
  4700. const newInputText = document.createElement('input');
  4701. newInputText.type = 'text';
  4702. if (placeholder) {
  4703. newInputText.placeholder = placeholder;
  4704. }
  4705. newInputText.classList.add('scriptMenu_InputText');
  4706. divInputText.appendChild(newInputText);
  4707. return newInputText;
  4708. }
  4709. addDetails(summaryText, name = null) {
  4710. const details = document.createElement('details');
  4711. details.classList.add('scriptMenu_Details');
  4712. this.mainMenu.appendChild(details);
  4713. const summary = document.createElement('summary');
  4714. summary.classList.add('scriptMenu_Summary');
  4715. summary.innerText = summaryText;
  4716. if (name) {
  4717. details.open = this.option.showDetails[name] ?? false;
  4718. details.dataset.name = name;
  4719. details.addEventListener('toggle', () => {
  4720. this.option.showDetails[details.dataset.name] = details.open;
  4721. this.saveSaveOption();
  4722. });
  4723. }
  4724. details.appendChild(summary);
  4725. return details;
  4726. }
  4727. saveSaveOption() {
  4728. try {
  4729. localStorage.setItem('scriptMenu_saveOption', JSON.stringify(this.option));
  4730. } catch (e) {
  4731. console.log('¯\\_(ツ)_/¯');
  4732. }
  4733. }
  4734. loadSaveOption() {
  4735. let saveOption = null;
  4736. try {
  4737. saveOption = localStorage.getItem('scriptMenu_saveOption');
  4738. } catch (e) {
  4739. console.log('¯\\_(ツ)_/¯');
  4740. }
  4741. if (!saveOption) {
  4742. return {};
  4743. }
  4744. try {
  4745. saveOption = JSON.parse(saveOption);
  4746. } catch (e) {
  4747. return {};
  4748. }
  4749. return saveOption;
  4750. }
  4751. }
  4752. const scriptMenu = new ScriptMenu();
  4753. /**
  4754. * Пример использования
  4755. const scriptMenu = new ScriptMenu();
  4756. scriptMenu.init();
  4757. scriptMenu.addHeader('v1.508');
  4758. scriptMenu.addCheckbox('testHack', 'Тестовый взлом игры!');
  4759. scriptMenu.addButton({
  4760. text: 'Запуск!',
  4761. onClick: () => console.log('click'),
  4762. title: 'подсказака',
  4763. });
  4764. scriptMenu.addInputText('input подсказака');
  4765. */
  4766. /**
  4767. * Game Library
  4768. *
  4769. * Игровая библиотека
  4770. */
  4771. class Library {
  4772. defaultLibUrl = 'https://heroesru-a.akamaihd.net/vk/v1101/lib/lib.json';
  4773. constructor() {
  4774. if (!Library.instance) {
  4775. Library.instance = this;
  4776. }
  4777. return Library.instance;
  4778. }
  4779. async load() {
  4780. try {
  4781. await this.getUrlLib();
  4782. console.log(this.defaultLibUrl);
  4783. this.data = await fetch(this.defaultLibUrl).then(e => e.json())
  4784. } catch (error) {
  4785. console.error('Не удалось загрузить библиотеку', error)
  4786. }
  4787. }
  4788. async getUrlLib() {
  4789. try {
  4790. const db = new Database('hw_cache', 'cache');
  4791. await db.open();
  4792. const cacheLibFullUrl = await db.get('lib/lib.json.gz', false);
  4793. this.defaultLibUrl = cacheLibFullUrl.fullUrl.split('.gz').shift();
  4794. } catch(e) {}
  4795. }
  4796. getData(id) {
  4797. return this.data[id];
  4798. }
  4799. setData(data) {
  4800. this.data = data;
  4801. }
  4802. }
  4803. this.lib = new Library();
  4804. /**
  4805. * Database
  4806. *
  4807. * База данных
  4808. */
  4809. class Database {
  4810. constructor(dbName, storeName) {
  4811. this.dbName = dbName;
  4812. this.storeName = storeName;
  4813. this.db = null;
  4814. }
  4815. async open() {
  4816. return new Promise((resolve, reject) => {
  4817. const request = indexedDB.open(this.dbName);
  4818. request.onerror = () => {
  4819. reject(new Error(`Failed to open database ${this.dbName}`));
  4820. };
  4821. request.onsuccess = () => {
  4822. this.db = request.r###lt;
  4823. resolve();
  4824. };
  4825. request.onupgradeneeded = (event) => {
  4826. const db = event.target.r###lt;
  4827. if (!db.objectStoreNames.contains(this.storeName)) {
  4828. db.createObjectStore(this.storeName);
  4829. }
  4830. };
  4831. });
  4832. }
  4833. async set(key, value) {
  4834. return new Promise((resolve, reject) => {
  4835. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4836. const store = transaction.objectStore(this.storeName);
  4837. const request = store.put(value, key);
  4838. request.onerror = () => {
  4839. reject(new Error(`Failed to save value with key ${key}`));
  4840. };
  4841. request.onsuccess = () => {
  4842. resolve();
  4843. };
  4844. });
  4845. }
  4846. async get(key, def) {
  4847. return new Promise((resolve, reject) => {
  4848. const transaction = this.db.transaction([this.storeName], 'readonly');
  4849. const store = transaction.objectStore(this.storeName);
  4850. const request = store.get(key);
  4851. request.onerror = () => {
  4852. resolve(def);
  4853. };
  4854. request.onsuccess = () => {
  4855. resolve(request.r###lt);
  4856. };
  4857. });
  4858. }
  4859. async delete(key) {
  4860. return new Promise((resolve, reject) => {
  4861. const transaction = this.db.transaction([this.storeName], 'readwrite');
  4862. const store = transaction.objectStore(this.storeName);
  4863. const request = store.delete(key);
  4864. request.onerror = () => {
  4865. reject(new Error(`Failed to delete value with key ${key}`));
  4866. };
  4867. request.onsuccess = () => {
  4868. resolve();
  4869. };
  4870. });
  4871. }
  4872. }
  4873. /**
  4874. * Returns the stored value
  4875. *
  4876. * Возвращает сохраненное значение
  4877. */
  4878. function getSaveVal(saveName, def) {
  4879. const r###lt = storage.get(saveName, def);
  4880. return r###lt;
  4881. }
  4882. this.HWHFuncs.getSaveVal = getSaveVal;
  4883. /**
  4884. * Stores value
  4885. *
  4886. * Сохраняет значение
  4887. */
  4888. function setSaveVal(saveName, value) {
  4889. storage.set(saveName, value);
  4890. }
  4891. this.HWHFuncs.setSaveVal = setSaveVal;
  4892. /**
  4893. * Database initialization
  4894. *
  4895. * Инициализация базы данных
  4896. */
  4897. const db = new Database(GM_info.script.name, 'settings');
  4898. /**
  4899. * Data store
  4900. *
  4901. * Хранилище данных
  4902. */
  4903. const storage = {
  4904. userId: 0,
  4905. /**
  4906. * Default values
  4907. *
  4908. * Значения по умолчанию
  4909. */
  4910. values: [
  4911. ...Object.entries(checkboxes).map(e => ({ [e[0]]: e[1].default })),
  4912. ...Object.entries(inputs).map(e => ({ [e[0]]: e[1].default })),
  4913. ].reduce((acc, obj) => ({ ...acc, ...obj }), {}),
  4914. name: GM_info.script.name,
  4915. get: function (key, def) {
  4916. if (key in this.values) {
  4917. return this.values[key];
  4918. }
  4919. return def;
  4920. },
  4921. set: function (key, value) {
  4922. this.values[key] = value;
  4923. db.set(this.userId, this.values).catch(
  4924. e => null
  4925. );
  4926. localStorage[this.name + ':' + key] = value;
  4927. },
  4928. delete: function (key) {
  4929. delete this.values[key];
  4930. db.set(this.userId, this.values);
  4931. delete localStorage[this.name + ':' + key];
  4932. }
  4933. }
  4934. /**
  4935. * Returns all keys from localStorage that start with prefix (for migration)
  4936. *
  4937. * Возвращает все ключи из localStorage которые начинаются с prefix (для миграции)
  4938. */
  4939. function getAllValuesStartingWith(prefix) {
  4940. const values = [];
  4941. for (let i = 0; i < localStorage.length; i++) {
  4942. const key = localStorage.key(i);
  4943. if (key.startsWith(prefix)) {
  4944. const val = localStorage.getItem(key);
  4945. const keyValue = key.split(':')[1];
  4946. values.push({ key: keyValue, val });
  4947. }
  4948. }
  4949. return values;
  4950. }
  4951. /**
  4952. * Opens or migrates to a database
  4953. *
  4954. * Открывает или мигрирует в базу данных
  4955. */
  4956. async function openOrMigrateDatabase(userId) {
  4957. storage.userId = userId;
  4958. try {
  4959. await db.open();
  4960. } catch(e) {
  4961. return;
  4962. }
  4963. let settings = await db.get(userId, false);
  4964. if (settings) {
  4965. storage.values = settings;
  4966. return;
  4967. }
  4968. const values = getAllValuesStartingWith(GM_info.script.name);
  4969. for (const value of values) {
  4970. let val = null;
  4971. try {
  4972. val = JSON.parse(value.val);
  4973. } catch {
  4974. break;
  4975. }
  4976. storage.values[value.key] = val;
  4977. }
  4978. await db.set(userId, storage.values);
  4979. }
  4980. class ZingerYWebsiteAPI {
  4981. /**
  4982. * Class for interaction with the API of the zingery.ru website
  4983. * Intended only for use with the HeroWarsHelper script:
  4984. * https://greasyfork.org/ru/scripts/450693-herowarshelper
  4985. * Copyright ZingerY
  4986. */
  4987. url = 'https://zingery.ru/heroes/';
  4988. // YWJzb2x1dGVseSB1c2VsZXNzIGxpbmU=
  4989. constructor(urn, env, data = {}) {
  4990. this.urn = urn;
  4991. this.fd = {
  4992. now: Date.now(),
  4993. fp: this.constructor.toString().replaceAll(/\s/g, ''),
  4994. env: env.callee.toString().replaceAll(/\s/g, ''),
  4995. info: (({ name, version, author }) => [name, version, author])(GM_info.script),
  4996. ...data,
  4997. };
  4998. }
  4999. sign() {
  5000. return md5([...this.fd.info, ~(this.fd.now % 1e3), this.fd.fp].join('_'));
  5001. }
  5002. encode(data) {
  5003. return btoa(encodeURIComponent(JSON.stringify(data)));
  5004. }
  5005. decode(data) {
  5006. return JSON.parse(decodeURIComponent(atob(data)));
  5007. }
  5008. headers() {
  5009. return {
  5010. 'X-Request-Signature': this.sign(),
  5011. 'X-Script-Name': GM_info.script.name,
  5012. 'X-Script-Version': GM_info.script.version,
  5013. 'X-Script-Author': GM_info.script.author,
  5014. 'X-Script-ZingerY': 42,
  5015. };
  5016. }
  5017. async request() {
  5018. try {
  5019. const response = await fetch(this.url + this.urn, {
  5020. method: 'POST',
  5021. headers: this.headers(),
  5022. body: this.encode(this.fd),
  5023. });
  5024. const text = await response.text();
  5025. return this.decode(text);
  5026. } catch (e) {
  5027. console.error(e);
  5028. return [];
  5029. }
  5030. }
  5031. /**
  5032. * Класс для взаимодействия с API сайта zingery.ru
  5033. * Предназначен только для использования со скриптом HeroWarsHelper:
  5034. * https://greasyfork.org/ru/scripts/450693-herowarshelper
  5035. * Copyright ZingerY
  5036. */
  5037. }
  5038. /**
  5039. * Sending expeditions
  5040. *
  5041. * Отправка экспедиций
  5042. */
  5043. function checkExpedition() {
  5044. const { Expedition } = HWHClasses;
  5045. return new Promise((resolve, reject) => {
  5046. const expedition = new Expedition(resolve, reject);
  5047. expedition.start();
  5048. });
  5049. }
  5050. class Expedition {
  5051. checkExpedInfo = {
  5052. calls: [
  5053. {
  5054. name: 'expeditionGet',
  5055. args: {},
  5056. ident: 'expeditionGet',
  5057. },
  5058. {
  5059. name: 'heroGetAll',
  5060. args: {},
  5061. ident: 'heroGetAll',
  5062. },
  5063. ],
  5064. };
  5065. constructor(resolve, reject) {
  5066. this.resolve = resolve;
  5067. this.reject = reject;
  5068. }
  5069. async start() {
  5070. const data = await Send(JSON.stringify(this.checkExpedInfo));
  5071. const expedInfo = data.r###lts[0].r###lt.response;
  5072. const dataHeroes = data.r###lts[1].r###lt.response;
  5073. const dataExped = { useHeroes: [], exped: [] };
  5074. const calls = [];
  5075. /**
  5076. * Adding expeditions to collect
  5077. * Добавляем экспедиции для сбора
  5078. */
  5079. let countGet = 0;
  5080. for (var n in expedInfo) {
  5081. const exped = expedInfo[n];
  5082. const dateNow = Date.now() / 1000;
  5083. if (exped.status == 2 && exped.endTime != 0 && dateNow > exped.endTime) {
  5084. countGet++;
  5085. calls.push({
  5086. name: 'expeditionFarm',
  5087. args: { expeditionId: exped.id },
  5088. ident: 'expeditionFarm_' + exped.id,
  5089. });
  5090. } else {
  5091. dataExped.useHeroes = dataExped.useHeroes.concat(exped.heroes);
  5092. }
  5093. if (exped.status == 1) {
  5094. dataExped.exped.push({ id: exped.id, power: exped.power });
  5095. }
  5096. }
  5097. dataExped.exped = dataExped.exped.sort((a, b) => b.power - a.power);
  5098. /**
  5099. * Putting together a list of heroes
  5100. * Собираем список героев
  5101. */
  5102. const heroesArr = [];
  5103. for (let n in dataHeroes) {
  5104. const hero = dataHeroes[n];
  5105. if (hero.power > 0 && !dataExped.useHeroes.includes(hero.id)) {
  5106. let heroPower = hero.power;
  5107. // Лара Крофт * 3
  5108. if (hero.id == 63 && hero.color >= 16) {
  5109. heroPower *= 3;
  5110. }
  5111. heroesArr.push({ id: hero.id, power: heroPower });
  5112. }
  5113. }
  5114. /**
  5115. * Adding expeditions to send
  5116. * Добавляем экспедиции для отправки
  5117. */
  5118. let countSend = 0;
  5119. heroesArr.sort((a, b) => a.power - b.power);
  5120. for (const exped of dataExped.exped) {
  5121. let heroesIds = this.selectionHeroes(heroesArr, exped.power);
  5122. if (heroesIds && heroesIds.length > 4) {
  5123. for (let q in heroesArr) {
  5124. if (heroesIds.includes(heroesArr[q].id)) {
  5125. delete heroesArr[q];
  5126. }
  5127. }
  5128. countSend++;
  5129. calls.push({
  5130. name: 'expeditionSendHeroes',
  5131. args: {
  5132. expeditionId: exped.id,
  5133. heroes: heroesIds,
  5134. },
  5135. ident: 'expeditionSendHeroes_' + exped.id,
  5136. });
  5137. }
  5138. }
  5139. if (calls.length) {
  5140. await Send({ calls });
  5141. this.end(I18N('EXPEDITIONS_SENT', {countGet, countSend}));
  5142. return;
  5143. }
  5144. this.end(I18N('EXPEDITIONS_NOTHING'));
  5145. }
  5146. /**
  5147. * Selection of heroes for expeditions
  5148. *
  5149. * Подбор героев для экспедиций
  5150. */
  5151. selectionHeroes(heroes, power) {
  5152. const r###ltHeroers = [];
  5153. const heroesIds = [];
  5154. for (let q = 0; q < 5; q++) {
  5155. for (let i in heroes) {
  5156. let hero = heroes[i];
  5157. if (heroesIds.includes(hero.id)) {
  5158. continue;
  5159. }
  5160. const summ = r###ltHeroers.reduce((acc, hero) => acc + hero.power, 0);
  5161. const need = Math.round((power - summ) / (5 - r###ltHeroers.length));
  5162. if (hero.power > need) {
  5163. r###ltHeroers.push(hero);
  5164. heroesIds.push(hero.id);
  5165. break;
  5166. }
  5167. }
  5168. }
  5169. const summ = r###ltHeroers.reduce((acc, hero) => acc + hero.power, 0);
  5170. if (summ < power) {
  5171. return false;
  5172. }
  5173. return heroesIds;
  5174. }
  5175. /**
  5176. * Ends expedition script
  5177. *
  5178. * Завершает скрипт экспедиции
  5179. */
  5180. end(msg) {
  5181. setProgress(msg, true);
  5182. this.resolve();
  5183. }
  5184. }
  5185. this.HWHClasses.Expedition = Expedition;
  5186. /**
  5187. * Walkthrough of the dungeon
  5188. *
  5189. * Прохождение подземелья
  5190. */
  5191. function testDungeon() {
  5192. const { executeDungeon } = HWHClasses;
  5193. return new Promise((resolve, reject) => {
  5194. const dung = new executeDungeon(resolve, reject);
  5195. const titanit = getInput('countTitanit');
  5196. dung.start(titanit);
  5197. });
  5198. }
  5199. /**
  5200. * Walkthrough of the dungeon
  5201. *
  5202. * Прохождение подземелья
  5203. */
  5204. function executeDungeon(resolve, reject) {
  5205. dungeonActivity = 0;
  5206. maxDungeonActivity = 150;
  5207. titanGetAll = [];
  5208. teams = {
  5209. heroes: [],
  5210. earth: [],
  5211. fire: [],
  5212. neutral: [],
  5213. water: [],
  5214. }
  5215. titanStats = [];
  5216. titansStates = {};
  5217. let talentMsg = '';
  5218. let talentMsgReward = '';
  5219. callsExecuteDungeon = {
  5220. calls: [{
  5221. name: "dungeonGetInfo",
  5222. args: {},
  5223. ident: "dungeonGetInfo"
  5224. }, {
  5225. name: "teamGetAll",
  5226. args: {},
  5227. ident: "teamGetAll"
  5228. }, {
  5229. name: "teamGetFavor",
  5230. args: {},
  5231. ident: "teamGetFavor"
  5232. }, {
  5233. name: "clanGetInfo",
  5234. args: {},
  5235. ident: "clanGetInfo"
  5236. }, {
  5237. name: "titanGetAll",
  5238. args: {},
  5239. ident: "titanGetAll"
  5240. }, {
  5241. name: "inventoryGet",
  5242. args: {},
  5243. ident: "inventoryGet"
  5244. }]
  5245. }
  5246. this.start = function(titanit) {
  5247. maxDungeonActivity = titanit || getInput('countTitanit');
  5248. send(JSON.stringify(callsExecuteDungeon), startDungeon);
  5249. }
  5250. /**
  5251. * Getting data on the dungeon
  5252. *
  5253. * Получаем данные по подземелью
  5254. */
  5255. function startDungeon(e) {
  5256. res = e.r###lts;
  5257. dungeonGetInfo = res[0].r###lt.response;
  5258. if (!dungeonGetInfo) {
  5259. endDungeon('noDungeon', res);
  5260. return;
  5261. }
  5262. teamGetAll = res[1].r###lt.response;
  5263. teamGetFavor = res[2].r###lt.response;
  5264. dungeonActivity = res[3].r###lt.response.stat.todayDungeonActivity;
  5265. titanGetAll = Object.values(res[4].r###lt.response);
  5266. countPredictionCard = res[5].r###lt.response.consumable[81];
  5267. teams.hero = {
  5268. favor: teamGetFavor.dungeon_hero,
  5269. heroes: teamGetAll.dungeon_hero.filter(id => id < 6000),
  5270. teamNum: 0,
  5271. }
  5272. heroPet = teamGetAll.dungeon_hero.filter(id => id >= 6000).pop();
  5273. if (heroPet) {
  5274. teams.hero.pet = heroPet;
  5275. }
  5276. teams.neutral = {
  5277. favor: {},
  5278. heroes: getTitanTeam(titanGetAll, 'neutral'),
  5279. teamNum: 0,
  5280. };
  5281. teams.water = {
  5282. favor: {},
  5283. heroes: getTitanTeam(titanGetAll, 'water'),
  5284. teamNum: 0,
  5285. };
  5286. teams.fire = {
  5287. favor: {},
  5288. heroes: getTitanTeam(titanGetAll, 'fire'),
  5289. teamNum: 0,
  5290. };
  5291. teams.earth = {
  5292. favor: {},
  5293. heroes: getTitanTeam(titanGetAll, 'earth'),
  5294. teamNum: 0,
  5295. };
  5296. checkFloor(dungeonGetInfo);
  5297. }
  5298. function getTitanTeam(titans, type) {
  5299. switch (type) {
  5300. case 'neutral':
  5301. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5302. case 'water':
  5303. return titans.filter(e => e.id.toString().slice(2, 3) == '0').map(e => e.id);
  5304. case 'fire':
  5305. return titans.filter(e => e.id.toString().slice(2, 3) == '1').map(e => e.id);
  5306. case 'earth':
  5307. return titans.filter(e => e.id.toString().slice(2, 3) == '2').map(e => e.id);
  5308. }
  5309. }
  5310. function getNeutralTeam() {
  5311. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  5312. return titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5313. }
  5314. function fixTitanTeam(titans) {
  5315. titans.heroes = titans.heroes.filter(e => !titansStates[e]?.isDead);
  5316. return titans;
  5317. }
  5318. /**
  5319. * Checking the floor
  5320. *
  5321. * Проверяем этаж
  5322. */
  5323. async function checkFloor(dungeonInfo) {
  5324. if (!('floor' in dungeonInfo) || dungeonInfo.floor?.state == 2) {
  5325. saveProgress();
  5326. return;
  5327. }
  5328. checkTalent(dungeonInfo);
  5329. // console.log(dungeonInfo, dungeonActivity);
  5330. setProgress(`${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity} ${talentMsg}`);
  5331. if (dungeonActivity >= maxDungeonActivity) {
  5332. endDungeon('endDungeon', 'maxActive ' + dungeonActivity + '/' + maxDungeonActivity);
  5333. return;
  5334. }
  5335. titansStates = dungeonInfo.states.titans;
  5336. titanStats = titanObjToArray(titansStates);
  5337. const floorChoices = dungeonInfo.floor.userData;
  5338. const floorType = dungeonInfo.floorType;
  5339. //const primeElement = dungeonInfo.elements.prime;
  5340. if (floorType == "battle") {
  5341. const calls = [];
  5342. for (let teamNum in floorChoices) {
  5343. attackerType = floorChoices[teamNum].attackerType;
  5344. const args = fixTitanTeam(teams[attackerType]);
  5345. if (attackerType == 'neutral') {
  5346. args.heroes = getNeutralTeam();
  5347. }
  5348. if (!args.heroes.length) {
  5349. continue;
  5350. }
  5351. args.teamNum = teamNum;
  5352. calls.push({
  5353. name: "dungeonStartBattle",
  5354. args,
  5355. ident: "body_" + teamNum
  5356. })
  5357. }
  5358. if (!calls.length) {
  5359. endDungeon('endDungeon', 'All Dead');
  5360. return;
  5361. }
  5362. const battleDatas = await Send(JSON.stringify({ calls }))
  5363. .then(e => e.r###lts.map(n => n.r###lt.response))
  5364. const battleR###lts = [];
  5365. for (n in battleDatas) {
  5366. battleData = battleDatas[n]
  5367. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  5368. battleR###lts.push(await Calc(battleData).then(r###lt => {
  5369. r###lt.teamNum = n;
  5370. r###lt.attackerType = floorChoices[n].attackerType;
  5371. return r###lt;
  5372. }));
  5373. }
  5374. processingPromises(battleR###lts)
  5375. }
  5376. }
  5377. async function checkTalent(dungeonInfo) {
  5378. const talent = dungeonInfo.talent;
  5379. if (!talent) {
  5380. return;
  5381. }
  5382. const dungeonFloor = +dungeonInfo.floorNumber;
  5383. const talentFloor = +talent.floorRandValue;
  5384. let doorsAmount = 3 - talent.conditions.doorsAmount;
  5385. if (dungeonFloor === talentFloor && (!doorsAmount || !talent.conditions?.farmedDoors[dungeonFloor])) {
  5386. const reward = await Send({
  5387. calls: [
  5388. { name: 'heroTalent_getReward', args: { talentType: 'tmntDungeonTalent', reroll: false }, ident: 'group_0_body' },
  5389. { name: 'heroTalent_farmReward', args: { talentType: 'tmntDungeonTalent' }, ident: 'group_1_body' },
  5390. ],
  5391. }).then((e) => e.r###lts[0].r###lt.response);
  5392. const type = Object.keys(reward).pop();
  5393. const itemId = Object.keys(reward[type]).pop();
  5394. const count = reward[type][itemId];
  5395. const itemName = cheats.translate(`LIB_${type.toUpperCase()}_NAME_${itemId}`);
  5396. talentMsgReward += `<br> ${count} ${itemName}`;
  5397. doorsAmount++;
  5398. }
  5399. talentMsg = `<br>TMNT Talent: ${doorsAmount}/3 ${talentMsgReward}<br>`;
  5400. }
  5401. function processingPromises(r###lts) {
  5402. let selectBattle = r###lts[0];
  5403. if (r###lts.length < 2) {
  5404. // console.log(selectBattle);
  5405. if (!selectBattle.r###lt.win) {
  5406. endDungeon('dungeonEndBattle\n', selectBattle);
  5407. return;
  5408. }
  5409. endBattle(selectBattle);
  5410. return;
  5411. }
  5412. selectBattle = false;
  5413. let bestState = -1000;
  5414. for (const r###lt of r###lts) {
  5415. const recovery = getState(r###lt);
  5416. if (recovery > bestState) {
  5417. bestState = recovery;
  5418. selectBattle = r###lt
  5419. }
  5420. }
  5421. // console.log(selectBattle.teamNum, r###lts);
  5422. if (!selectBattle || bestState <= -1000) {
  5423. endDungeon('dungeonEndBattle\n', r###lts);
  5424. return;
  5425. }
  5426. startBattle(selectBattle.teamNum, selectBattle.attackerType)
  5427. .then(endBattle);
  5428. }
  5429. /**
  5430. * Let's start the fight
  5431. *
  5432. * Начинаем бой
  5433. */
  5434. function startBattle(teamNum, attackerType) {
  5435. return new Promise(function (resolve, reject) {
  5436. args = fixTitanTeam(teams[attackerType]);
  5437. args.teamNum = teamNum;
  5438. if (attackerType == 'neutral') {
  5439. const titans = titanGetAll.filter(e => !titansStates[e.id]?.isDead)
  5440. args.heroes = titans.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5441. }
  5442. startBattleCall = {
  5443. calls: [{
  5444. name: "dungeonStartBattle",
  5445. args,
  5446. ident: "body"
  5447. }]
  5448. }
  5449. send(JSON.stringify(startBattleCall), r###ltBattle, {
  5450. resolve,
  5451. teamNum,
  5452. attackerType
  5453. });
  5454. });
  5455. }
  5456. /**
  5457. * Returns the r###lt of the battle in a promise
  5458. *
  5459. * Возращает резульат боя в промис
  5460. */
  5461. function r###ltBattle(r###ltBattles, args) {
  5462. battleData = r###ltBattles.r###lts[0].r###lt.response;
  5463. battleType = "get_tower";
  5464. if (battleData.type == "dungeon_titan") {
  5465. battleType = "get_titan";
  5466. }
  5467. battleData.progress = [{ attackers: { input: ["auto", 0, 0, "auto", 0, 0] } }];
  5468. BattleCalc(battleData, battleType, function (r###lt) {
  5469. r###lt.teamNum = args.teamNum;
  5470. r###lt.attackerType = args.attackerType;
  5471. args.resolve(r###lt);
  5472. });
  5473. }
  5474. /**
  5475. * Finishing the fight
  5476. *
  5477. * Заканчиваем бой
  5478. */
  5479. async function endBattle(battleInfo) {
  5480. if (battleInfo.r###lt.win) {
  5481. const args = {
  5482. r###lt: battleInfo.r###lt,
  5483. progress: battleInfo.progress,
  5484. }
  5485. if (countPredictionCard > 0) {
  5486. args.isRaid = true;
  5487. } else {
  5488. const timer = getTimer(battleInfo.battleTime);
  5489. console.log(timer);
  5490. await countdownTimer(timer, `${I18N('DUNGEON')}: ${I18N('TITANIT')} ${dungeonActivity}/${maxDungeonActivity} ${talentMsg}`);
  5491. }
  5492. const calls = [{
  5493. name: "dungeonEndBattle",
  5494. args,
  5495. ident: "body"
  5496. }];
  5497. lastDungeonBattleData = null;
  5498. send(JSON.stringify({ calls }), r###ltEndBattle);
  5499. } else {
  5500. endDungeon('dungeonEndBattle win: false\n', battleInfo);
  5501. }
  5502. }
  5503. /**
  5504. * Getting and processing battle r###lts
  5505. *
  5506. * Получаем и обрабатываем результаты боя
  5507. */
  5508. function r###ltEndBattle(e) {
  5509. if ('error' in e) {
  5510. popup.confirm(I18N('ERROR_MSG', {
  5511. name: e.error.name,
  5512. description: e.error.description,
  5513. }));
  5514. endDungeon('errorRequest', e);
  5515. return;
  5516. }
  5517. battleR###lt = e.r###lts[0].r###lt.response;
  5518. if ('error' in battleR###lt) {
  5519. endDungeon('errorBattleR###lt', battleR###lt);
  5520. return;
  5521. }
  5522. dungeonGetInfo = battleR###lt.dungeon ?? battleR###lt;
  5523. dungeonActivity += battleR###lt.reward.dungeonActivity ?? 0;
  5524. checkFloor(dungeonGetInfo);
  5525. }
  5526. /**
  5527. * Returns the coefficient of condition of the
  5528. * difference in titanium before and after the battle
  5529. *
  5530. * Возвращает коэффициент состояния титанов после боя
  5531. */
  5532. function getState(r###lt) {
  5533. if (!r###lt.r###lt.win) {
  5534. return -1000;
  5535. }
  5536. let befor###mFactor = 0;
  5537. const beforeTitans = r###lt.battleData.attackers;
  5538. for (let titanId in beforeTitans) {
  5539. const titan = beforeTitans[titanId];
  5540. const state = titan.state;
  5541. let factor = 1;
  5542. if (state) {
  5543. const hp = state.hp / titan.hp;
  5544. const energy = state.energy / 1e3;
  5545. factor = hp + energy / 20
  5546. }
  5547. befor###mFactor += factor;
  5548. }
  5549. let afterSumFactor = 0;
  5550. const afterTitans = r###lt.progress[0].attackers.heroes;
  5551. for (let titanId in afterTitans) {
  5552. const titan = afterTitans[titanId];
  5553. const hp = titan.hp / beforeTitans[titanId].hp;
  5554. const energy = titan.energy / 1e3;
  5555. const factor = hp + energy / 20;
  5556. afterSumFactor += factor;
  5557. }
  5558. return afterSumFactor - befor###mFactor;
  5559. }
  5560. /**
  5561. * Converts an object with IDs to an array with IDs
  5562. *
  5563. * Преобразует объект с идетификаторами в массив с идетификаторами
  5564. */
  5565. function titanObjToArray(obj) {
  5566. let titans = [];
  5567. for (let id in obj) {
  5568. obj[id].id = id;
  5569. titans.push(obj[id]);
  5570. }
  5571. return titans;
  5572. }
  5573. function saveProgress() {
  5574. let saveProgressCall = {
  5575. calls: [{
  5576. name: "dungeonSaveProgress",
  5577. args: {},
  5578. ident: "body"
  5579. }]
  5580. }
  5581. send(JSON.stringify(saveProgressCall), r###ltEndBattle);
  5582. }
  5583. function endDungeon(reason, info) {
  5584. console.warn(reason, info);
  5585. setProgress(`${I18N('DUNGEON')} ${I18N('COMPLETED')}`, true);
  5586. resolve();
  5587. }
  5588. }
  5589. this.HWHClasses.executeDungeon = executeDungeon;
  5590. /**
  5591. * Passing the tower
  5592. *
  5593. * Прохождение башни
  5594. */
  5595. function testTower() {
  5596. const { executeTower } = HWHClasses;
  5597. return new Promise((resolve, reject) => {
  5598. tower = new executeTower(resolve, reject);
  5599. tower.start();
  5600. });
  5601. }
  5602. /**
  5603. * Passing the tower
  5604. *
  5605. * Прохождение башни
  5606. */
  5607. function executeTower(resolve, reject) {
  5608. lastTowerInfo = {};
  5609. scullCoin = 0;
  5610. heroGetAll = [];
  5611. heroesStates = {};
  5612. argsBattle = {
  5613. heroes: [],
  5614. favor: {},
  5615. };
  5616. callsExecuteTower = {
  5617. calls: [{
  5618. name: "towerGetInfo",
  5619. args: {},
  5620. ident: "towerGetInfo"
  5621. }, {
  5622. name: "teamGetAll",
  5623. args: {},
  5624. ident: "teamGetAll"
  5625. }, {
  5626. name: "teamGetFavor",
  5627. args: {},
  5628. ident: "teamGetFavor"
  5629. }, {
  5630. name: "inventoryGet",
  5631. args: {},
  5632. ident: "inventoryGet"
  5633. }, {
  5634. name: "heroGetAll",
  5635. args: {},
  5636. ident: "heroGetAll"
  5637. }]
  5638. }
  5639. buffIds = [
  5640. {id: 0, cost: 0, isBuy: false}, // plug // заглушка
  5641. {id: 1, cost: 1, isBuy: true}, // 3% attack // 3% атака
  5642. {id: 2, cost: 6, isBuy: true}, // 2% attack // 2% атака
  5643. {id: 3, cost: 16, isBuy: true}, // 4% attack // 4% атака
  5644. {id: 4, cost: 40, isBuy: true}, // 8% attack // 8% атака
  5645. {id: 5, cost: 1, isBuy: true}, // 10% armor // 10% броня
  5646. {id: 6, cost: 6, isBuy: true}, // 5% armor // 5% броня
  5647. {id: 7, cost: 16, isBuy: true}, // 10% armor // 10% броня
  5648. {id: 8, cost: 40, isBuy: true}, // 20% armor // 20% броня
  5649. { id: 9, cost: 1, isBuy: true }, // 10% protection from magic // 10% защита от магии
  5650. { id: 10, cost: 6, isBuy: true }, // 5% protection from magic // 5% защита от магии
  5651. { id: 11, cost: 16, isBuy: true }, // 10% protection from magic // 10% защита от магии
  5652. { id: 12, cost: 40, isBuy: true }, // 20% protection from magic // 20% защита от магии
  5653. { id: 13, cost: 1, isBuy: false }, // 40% health hero // 40% здоровья герою
  5654. { id: 14, cost: 6, isBuy: false }, // 40% health hero // 40% здоровья герою
  5655. { id: 15, cost: 16, isBuy: false }, // 80% health hero // 80% здоровья герою
  5656. { id: 16, cost: 40, isBuy: false }, // 40% health to all heroes // 40% здоровья всем героям
  5657. { id: 17, cost: 1, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  5658. { id: 18, cost: 3, isBuy: false }, // 40% energy to the hero // 40% энергии герою
  5659. { id: 19, cost: 8, isBuy: false }, // 80% energy to the hero // 80% энергии герою
  5660. { id: 20, cost: 20, isBuy: false }, // 40% energy to all heroes // 40% энергии всем героям
  5661. { id: 21, cost: 40, isBuy: false }, // Hero R###rrection // Воскрешение героя
  5662. ]
  5663. this.start = function () {
  5664. send(JSON.stringify(callsExecuteTower), startTower);
  5665. }
  5666. /**
  5667. * Getting data on the Tower
  5668. *
  5669. * Получаем данные по башне
  5670. */
  5671. function startTower(e) {
  5672. res = e.r###lts;
  5673. towerGetInfo = res[0].r###lt.response;
  5674. if (!towerGetInfo) {
  5675. endTower('noTower', res);
  5676. return;
  5677. }
  5678. teamGetAll = res[1].r###lt.response;
  5679. teamGetFavor = res[2].r###lt.response;
  5680. inventoryGet = res[3].r###lt.response;
  5681. heroGetAll = Object.values(res[4].r###lt.response);
  5682. scullCoin = inventoryGet.coin[7] ?? 0;
  5683. argsBattle.favor = teamGetFavor.tower;
  5684. argsBattle.heroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5685. pet = teamGetAll.tower.filter(id => id >= 6000).pop();
  5686. if (pet) {
  5687. argsBattle.pet = pet;
  5688. }
  5689. checkFloor(towerGetInfo);
  5690. }
  5691. function fixHeroesTeam(argsBattle) {
  5692. let fixHeroes = argsBattle.heroes.filter(e => !heroesStates[e]?.isDead);
  5693. if (fixHeroes.length < 5) {
  5694. heroGetAll = heroGetAll.filter(e => !heroesStates[e.id]?.isDead);
  5695. fixHeroes = heroGetAll.sort((a, b) => b.power - a.power).slice(0, 5).map(e => e.id);
  5696. Object.keys(argsBattle.favor).forEach(e => {
  5697. if (!fixHeroes.includes(+e)) {
  5698. delete argsBattle.favor[e];
  5699. }
  5700. })
  5701. }
  5702. argsBattle.heroes = fixHeroes;
  5703. return argsBattle;
  5704. }
  5705. /**
  5706. * Check the floor
  5707. *
  5708. * Проверяем этаж
  5709. */
  5710. function checkFloor(towerInfo) {
  5711. lastTowerInfo = towerInfo;
  5712. maySkipFloor = +towerInfo.maySkipFloor;
  5713. floorNumber = +towerInfo.floorNumber;
  5714. heroesStates = towerInfo.states.heroes;
  5715. floorInfo = towerInfo.floor;
  5716. /**
  5717. * Is there at least one chest open on the floor
  5718. * Открыт ли на этаже хоть один сундук
  5719. */
  5720. isOpenChest = false;
  5721. if (towerInfo.floorType == "chest") {
  5722. isOpenChest = towerInfo.floor.chests.reduce((n, e) => n + e.opened, 0);
  5723. }
  5724. setProgress(`${I18N('TOWER')}: ${I18N('FLOOR')} ${floorNumber}`);
  5725. if (floorNumber > 49) {
  5726. if (isOpenChest) {
  5727. endTower('alreadyOpenChest 50 floor', floorNumber);
  5728. return;
  5729. }
  5730. }
  5731. /**
  5732. * If the chest is open and you can skip floors, then move on
  5733. * Если сундук открыт и можно скипать этажи, то переходим дальше
  5734. */
  5735. if (towerInfo.mayFullSkip && +towerInfo.teamLevel == 130) {
  5736. if (floorNumber == 1) {
  5737. fullSkipTower();
  5738. return;
  5739. }
  5740. if (isOpenChest) {
  5741. nextOpenChest(floorNumber);
  5742. } else {
  5743. nextChestOpen(floorNumber);
  5744. }
  5745. return;
  5746. }
  5747. // console.log(towerInfo, scullCoin);
  5748. switch (towerInfo.floorType) {
  5749. case "battle":
  5750. if (floorNumber <= maySkipFloor) {
  5751. skipFloor();
  5752. return;
  5753. }
  5754. if (floorInfo.state == 2) {
  5755. nextFloor();
  5756. return;
  5757. }
  5758. startBattle().then(endBattle);
  5759. return;
  5760. case "buff":
  5761. checkBuff(towerInfo);
  5762. return;
  5763. case "chest":
  5764. openChest(floorNumber);
  5765. return;
  5766. default:
  5767. console.log('!', towerInfo.floorType, towerInfo);
  5768. break;
  5769. }
  5770. }
  5771. /**
  5772. * Let's start the fight
  5773. *
  5774. * Начинаем бой
  5775. */
  5776. function startBattle() {
  5777. return new Promise(function (resolve, reject) {
  5778. towerStartBattle = {
  5779. calls: [{
  5780. name: "towerStartBattle",
  5781. args: fixHeroesTeam(argsBattle),
  5782. ident: "body"
  5783. }]
  5784. }
  5785. send(JSON.stringify(towerStartBattle), r###ltBattle, resolve);
  5786. });
  5787. }
  5788. /**
  5789. * Returns the r###lt of the battle in a promise
  5790. *
  5791. * Возращает резульат боя в промис
  5792. */
  5793. function r###ltBattle(r###ltBattles, resolve) {
  5794. battleData = r###ltBattles.r###lts[0].r###lt.response;
  5795. battleType = "get_tower";
  5796. BattleCalc(battleData, battleType, function (r###lt) {
  5797. resolve(r###lt);
  5798. });
  5799. }
  5800. /**
  5801. * Finishing the fight
  5802. *
  5803. * Заканчиваем бой
  5804. */
  5805. function endBattle(battleInfo) {
  5806. if (battleInfo.r###lt.stars >= 3) {
  5807. endBattleCall = {
  5808. calls: [{
  5809. name: "towerEndBattle",
  5810. args: {
  5811. r###lt: battleInfo.r###lt,
  5812. progress: battleInfo.progress,
  5813. },
  5814. ident: "body"
  5815. }]
  5816. }
  5817. send(JSON.stringify(endBattleCall), r###ltEndBattle);
  5818. } else {
  5819. endTower('towerEndBattle win: false\n', battleInfo);
  5820. }
  5821. }
  5822. /**
  5823. * Getting and processing battle r###lts
  5824. *
  5825. * Получаем и обрабатываем результаты боя
  5826. */
  5827. function r###ltEndBattle(e) {
  5828. battleR###lt = e.r###lts[0].r###lt.response;
  5829. if ('error' in battleR###lt) {
  5830. endTower('errorBattleR###lt', battleR###lt);
  5831. return;
  5832. }
  5833. if ('reward' in battleR###lt) {
  5834. scullCoin += battleR###lt.reward?.coin[7] ?? 0;
  5835. }
  5836. nextFloor();
  5837. }
  5838. function nextFloor() {
  5839. nextFloorCall = {
  5840. calls: [{
  5841. name: "towerNextFloor",
  5842. args: {},
  5843. ident: "body"
  5844. }]
  5845. }
  5846. send(JSON.stringify(nextFloorCall), checkDataFloor);
  5847. }
  5848. function openChest(floorNumber) {
  5849. floorNumber = floorNumber || 0;
  5850. openChestCall = {
  5851. calls: [{
  5852. name: "towerOpenChest",
  5853. args: {
  5854. num: 2
  5855. },
  5856. ident: "body"
  5857. }]
  5858. }
  5859. send(JSON.stringify(openChestCall), floorNumber < 50 ? nextFloor : lastChest);
  5860. }
  5861. function lastChest() {
  5862. endTower('openChest 50 floor', floorNumber);
  5863. }
  5864. function skipFloor() {
  5865. skipFloorCall = {
  5866. calls: [{
  5867. name: "towerSkipFloor",
  5868. args: {},
  5869. ident: "body"
  5870. }]
  5871. }
  5872. send(JSON.stringify(skipFloorCall), checkDataFloor);
  5873. }
  5874. function checkBuff(towerInfo) {
  5875. buffArr = towerInfo.floor;
  5876. promises = [];
  5877. for (let buff of buffArr) {
  5878. buffInfo = buffIds[buff.id];
  5879. if (buffInfo.isBuy && buffInfo.cost <= scullCoin) {
  5880. scullCoin -= buffInfo.cost;
  5881. promises.push(buyBuff(buff.id));
  5882. }
  5883. }
  5884. Promise.all(promises).then(nextFloor);
  5885. }
  5886. function buyBuff(buffId) {
  5887. return new Promise(function (resolve, reject) {
  5888. buyBuffCall = {
  5889. calls: [{
  5890. name: "towerBuyBuff",
  5891. args: {
  5892. buffId
  5893. },
  5894. ident: "body"
  5895. }]
  5896. }
  5897. send(JSON.stringify(buyBuffCall), resolve);
  5898. });
  5899. }
  5900. function checkDataFloor(r###lt) {
  5901. towerInfo = r###lt.r###lts[0].r###lt.response;
  5902. if ('reward' in towerInfo && towerInfo.reward?.coin) {
  5903. scullCoin += towerInfo.reward?.coin[7] ?? 0;
  5904. }
  5905. if ('tower' in towerInfo) {
  5906. towerInfo = towerInfo.tower;
  5907. }
  5908. if ('skullReward' in towerInfo) {
  5909. scullCoin += towerInfo.skullReward?.coin[7] ?? 0;
  5910. }
  5911. checkFloor(towerInfo);
  5912. }
  5913. /**
  5914. * Getting tower rewards
  5915. *
  5916. * Получаем награды башни
  5917. */
  5918. function farmTowerRewards(reason) {
  5919. let { pointRewards, points } = lastTowerInfo;
  5920. let pointsAll = Object.getOwnPropertyNames(pointRewards);
  5921. let farmPoints = pointsAll.filter(e => +e <= +points && !pointRewards[e]);
  5922. if (!farmPoints.length) {
  5923. return;
  5924. }
  5925. let farmTowerRewardsCall = {
  5926. calls: [{
  5927. name: "tower_farmPointRewards",
  5928. args: {
  5929. points: farmPoints
  5930. },
  5931. ident: "tower_farmPointRewards"
  5932. }]
  5933. }
  5934. if (scullCoin > 0) {
  5935. farmTowerRewardsCall.calls.push({
  5936. name: "tower_farmSkullReward",
  5937. args: {},
  5938. ident: "tower_farmSkullReward"
  5939. });
  5940. }
  5941. send(JSON.stringify(farmTowerRewardsCall), () => { });
  5942. }
  5943. function fullSkipTower() {
  5944. /**
  5945. * Next chest
  5946. *
  5947. * Следующий сундук
  5948. */
  5949. function nextChest(n) {
  5950. return {
  5951. name: "towerNextChest",
  5952. args: {},
  5953. ident: "group_" + n + "_body"
  5954. }
  5955. }
  5956. /**
  5957. * Open chest
  5958. *
  5959. * Открыть сундук
  5960. */
  5961. function openChest(n) {
  5962. return {
  5963. name: "towerOpenChest",
  5964. args: {
  5965. "num": 2
  5966. },
  5967. ident: "group_" + n + "_body"
  5968. }
  5969. }
  5970. const fullSkipTowerCall = {
  5971. calls: []
  5972. }
  5973. let n = 0;
  5974. for (let i = 0; i < 15; i++) {
  5975. // 15 сундуков
  5976. fullSkipTowerCall.calls.push(nextChest(++n));
  5977. fullSkipTowerCall.calls.push(openChest(++n));
  5978. // +5 сундуков, 250 изюма // towerOpenChest
  5979. // if (i < 5) {
  5980. // fullSkipTowerCall.calls.push(openChest(++n, 2));
  5981. // }
  5982. }
  5983. fullSkipTowerCall.calls.push({
  5984. name: 'towerGetInfo',
  5985. args: {},
  5986. ident: 'group_' + ++n + '_body',
  5987. });
  5988. send(JSON.stringify(fullSkipTowerCall), data => {
  5989. for (const r of data.r###lts) {
  5990. const towerInfo = r?.r###lt?.response;
  5991. if (towerInfo && 'skullReward' in towerInfo) {
  5992. scullCoin += towerInfo.skullReward?.coin[7] ?? 0;
  5993. }
  5994. }
  5995. data.r###lts[0] = data.r###lts[data.r###lts.length - 1];
  5996. checkDataFloor(data);
  5997. });
  5998. }
  5999. function nextChestOpen(floorNumber) {
  6000. const calls = [{
  6001. name: "towerOpenChest",
  6002. args: {
  6003. num: 2
  6004. },
  6005. ident: "towerOpenChest"
  6006. }];
  6007. Send(JSON.stringify({ calls })).then(e => {
  6008. nextOpenChest(floorNumber);
  6009. });
  6010. }
  6011. function nextOpenChest(floorNumber) {
  6012. if (floorNumber > 49) {
  6013. endTower('openChest 50 floor', floorNumber);
  6014. return;
  6015. }
  6016. let nextOpenChestCall = {
  6017. calls: [{
  6018. name: "towerNextChest",
  6019. args: {},
  6020. ident: "towerNextChest"
  6021. }, {
  6022. name: "towerOpenChest",
  6023. args: {
  6024. num: 2
  6025. },
  6026. ident: "towerOpenChest"
  6027. }]
  6028. }
  6029. send(JSON.stringify(nextOpenChestCall), checkDataFloor);
  6030. }
  6031. function endTower(reason, info) {
  6032. console.log(reason, info);
  6033. if (reason != 'noTower') {
  6034. farmTowerRewards(reason);
  6035. }
  6036. setProgress(`${I18N('TOWER')} ${I18N('COMPLETED')}!`, true);
  6037. resolve();
  6038. }
  6039. }
  6040. this.HWHClasses.executeTower = executeTower;
  6041. /**
  6042. * Passage of the arena of the titans
  6043. *
  6044. * Прохождение арены титанов
  6045. */
  6046. function testTitanArena() {
  6047. const { executeTitanArena } = HWHClasses;
  6048. return new Promise((resolve, reject) => {
  6049. titAren = new executeTitanArena(resolve, reject);
  6050. titAren.start();
  6051. });
  6052. }
  6053. /**
  6054. * Passage of the arena of the titans
  6055. *
  6056. * Прохождение арены титанов
  6057. */
  6058. function executeTitanArena(resolve, reject) {
  6059. let titan_arena = [];
  6060. let finishListBattle = [];
  6061. /**
  6062. * ID of the current batch
  6063. *
  6064. * Идетификатор текущей пачки
  6065. */
  6066. let currentRival = 0;
  6067. /**
  6068. * Number of attempts to finish off the pack
  6069. *
  6070. * Количество попыток добития пачки
  6071. */
  6072. let attempts = 0;
  6073. /**
  6074. * Was there an attempt to finish off the current shooting range
  6075. *
  6076. * Была ли попытка добития текущего тира
  6077. */
  6078. let isCheckCurrentTier = false;
  6079. /**
  6080. * Current shooting range
  6081. *
  6082. * Текущий тир
  6083. */
  6084. let currTier = 0;
  6085. /**
  6086. * Number of battles on the current dash
  6087. *
  6088. * Количество битв на текущем тире
  6089. */
  6090. let countRivalsTier = 0;
  6091. let callsStart = {
  6092. calls: [{
  6093. name: "titanArenaGetStatus",
  6094. args: {},
  6095. ident: "titanArenaGetStatus"
  6096. }, {
  6097. name: "teamGetAll",
  6098. args: {},
  6099. ident: "teamGetAll"
  6100. }]
  6101. }
  6102. this.start = function () {
  6103. send(JSON.stringify(callsStart), startTitanArena);
  6104. }
  6105. function startTitanArena(data) {
  6106. let titanArena = data.r###lts[0].r###lt.response;
  6107. if (titanArena.status == 'disabled') {
  6108. endTitanArena('disabled', titanArena);
  6109. return;
  6110. }
  6111. let teamGetAll = data.r###lts[1].r###lt.response;
  6112. titan_arena = teamGetAll.titan_arena;
  6113. checkTier(titanArena)
  6114. }
  6115. function checkTier(titanArena) {
  6116. if (titanArena.status == "peace_time") {
  6117. endTitanArena('Peace_time', titanArena);
  6118. return;
  6119. }
  6120. currTier = titanArena.tier;
  6121. if (currTier) {
  6122. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier}`);
  6123. }
  6124. if (titanArena.status == "completed_tier") {
  6125. titanArenaCompleteTier();
  6126. return;
  6127. }
  6128. /**
  6129. * Checking for the possibility of a raid
  6130. * Проверка на возможность рейда
  6131. */
  6132. if (titanArena.canRaid) {
  6133. titanArenaStartRaid();
  6134. return;
  6135. }
  6136. /**
  6137. * Check was an attempt to achieve the current shooting range
  6138. * Проверка была ли попытка добития текущего тира
  6139. */
  6140. if (!isCheckCurrentTier) {
  6141. checkRivals(titanArena.rivals);
  6142. return;
  6143. }
  6144. endTitanArena('Done or not canRaid', titanArena);
  6145. }
  6146. /**
  6147. * Submit dash information for verification
  6148. *
  6149. * Отправка информации о тире на проверку
  6150. */
  6151. function checkR###ltInfo(data) {
  6152. let titanArena = data.r###lts[0].r###lt.response;
  6153. checkTier(titanArena);
  6154. }
  6155. /**
  6156. * Finish the current tier
  6157. *
  6158. * Завершить текущий тир
  6159. */
  6160. function titanArenaCompleteTier() {
  6161. isCheckCurrentTier = false;
  6162. let calls = [{
  6163. name: "titanArenaCompleteTier",
  6164. args: {},
  6165. ident: "body"
  6166. }];
  6167. send(JSON.stringify({calls}), checkR###ltInfo);
  6168. }
  6169. /**
  6170. * Gathering points to be completed
  6171. *
  6172. * Собираем точки которые нужно добить
  6173. */
  6174. function checkRivals(rivals) {
  6175. finishListBattle = [];
  6176. for (let n in rivals) {
  6177. if (rivals[n].attackScore < 250) {
  6178. finishListBattle.push(n);
  6179. }
  6180. }
  6181. console.log('checkRivals', finishListBattle);
  6182. countRivalsTier = finishListBattle.length;
  6183. roundRivals();
  6184. }
  6185. /**
  6186. * Selecting the next point to finish off
  6187. *
  6188. * Выбор следующей точки для добития
  6189. */
  6190. function roundRivals() {
  6191. let countRivals = finishListBattle.length;
  6192. if (!countRivals) {
  6193. /**
  6194. * Whole range checked
  6195. *
  6196. * Весь тир проверен
  6197. */
  6198. isCheckCurrentTier = true;
  6199. titanArenaGetStatus();
  6200. return;
  6201. }
  6202. // setProgress('TitanArena: Уровень ' + currTier + ' Бои: ' + (countRivalsTier - countRivals + 1) + '/' + countRivalsTier);
  6203. currentRival = finishListBattle.pop();
  6204. attempts = +currentRival;
  6205. // console.log('roundRivals', currentRival);
  6206. titanArenaStartBattle(currentRival);
  6207. }
  6208. /**
  6209. * The start of a solo battle
  6210. *
  6211. * Начало одиночной битвы
  6212. */
  6213. function titanArenaStartBattle(rivalId) {
  6214. let calls = [{
  6215. name: "titanArenaStartBattle",
  6216. args: {
  6217. rivalId: rivalId,
  6218. titans: titan_arena
  6219. },
  6220. ident: "body"
  6221. }];
  6222. send(JSON.stringify({calls}), calcR###lt);
  6223. }
  6224. /**
  6225. * Calculation of the r###lts of the battle
  6226. *
  6227. * Расчет результатов боя
  6228. */
  6229. function calcR###lt(data) {
  6230. let battlesInfo = data.r###lts[0].r###lt.response.battle;
  6231. /**
  6232. * If attempts are equal to the current battle number we make
  6233. * Если попытки равны номеру текущего боя делаем прерасчет
  6234. */
  6235. if (attempts == currentRival) {
  6236. preCalcBattle(battlesInfo);
  6237. return;
  6238. }
  6239. /**
  6240. * If there are still attempts, we calculate a new battle
  6241. * Если попытки еще есть делаем расчет нового боя
  6242. */
  6243. if (attempts > 0) {
  6244. attempts--;
  6245. calcBattleR###lt(battlesInfo)
  6246. .then(r###ltCalcBattle);
  6247. return;
  6248. }
  6249. /**
  6250. * Otherwise, go to the next opponent
  6251. * Иначе переходим к следующему сопернику
  6252. */
  6253. roundRivals();
  6254. }
  6255. /**
  6256. * Processing the r###lts of the battle calculation
  6257. *
  6258. * Обработка результатов расчета битвы
  6259. */
  6260. function r###ltCalcBattle(r###ltBattle) {
  6261. // console.log('r###ltCalcBattle', currentRival, attempts, r###ltBattle.r###lt.win);
  6262. /**
  6263. * If the current calculation of victory is not a chance or the attempt ended with the finish the battle
  6264. * Если текущий расчет победа или шансов нет или попытки кончились завершаем бой
  6265. */
  6266. if (r###ltBattle.r###lt.win || !attempts) {
  6267. titanArenaEndBattle({
  6268. progress: r###ltBattle.progress,
  6269. r###lt: r###ltBattle.r###lt,
  6270. rivalId: r###ltBattle.battleData.typeId
  6271. });
  6272. return;
  6273. }
  6274. /**
  6275. * If not victory and there are attempts we start a new battle
  6276. * Если не победа и есть попытки начинаем новый бой
  6277. */
  6278. titanArenaStartBattle(r###ltBattle.battleData.typeId);
  6279. }
  6280. /**
  6281. * Returns the promise of calculating the r###lts of the battle
  6282. *
  6283. * Возращает промис расчета результатов битвы
  6284. */
  6285. function getBattleInfo(battle, isRandSeed) {
  6286. return new Promise(function (resolve) {
  6287. if (isRandSeed) {
  6288. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  6289. }
  6290. // console.log(battle.seed);
  6291. BattleCalc(battle, "get_titanClanPvp", e => resolve(e));
  6292. });
  6293. }
  6294. /**
  6295. * Recalculate battles
  6296. *
  6297. * Прерасчтет битвы
  6298. */
  6299. function preCalcBattle(battle) {
  6300. let actions = [getBattleInfo(battle, false)];
  6301. const countTestBattle = getInput('countTestBattle');
  6302. for (let i = 0; i < countTestBattle; i++) {
  6303. actions.push(getBattleInfo(battle, true));
  6304. }
  6305. Promise.all(actions)
  6306. .then(r###ltPreCalcBattle);
  6307. }
  6308. /**
  6309. * Processing the r###lts of the battle recalculation
  6310. *
  6311. * Обработка результатов прерасчета битвы
  6312. */
  6313. function r###ltPreCalcBattle(e) {
  6314. let wins = e.map(n => n.r###lt.win);
  6315. let firstBattle = e.shift();
  6316. let countWin = wins.reduce((w, s) => w + s);
  6317. const countTestBattle = getInput('countTestBattle');
  6318. console.log('r###ltPreCalcBattle', `${countWin}/${countTestBattle}`)
  6319. if (countWin > 0) {
  6320. attempts = getInput('countAutoBattle');
  6321. } else {
  6322. attempts = 0;
  6323. }
  6324. r###ltCalcBattle(firstBattle);
  6325. }
  6326. /**
  6327. * Complete an arena battle
  6328. *
  6329. * Завершить битву на арене
  6330. */
  6331. function titanArenaEndBattle(args) {
  6332. let calls = [{
  6333. name: "titanArenaEndBattle",
  6334. args,
  6335. ident: "body"
  6336. }];
  6337. send(JSON.stringify({calls}), r###ltTitanArenaEndBattle);
  6338. }
  6339. function r###ltTitanArenaEndBattle(e) {
  6340. let attackScore = e.r###lts[0].r###lt.response.attackScore;
  6341. let numReval = countRivalsTier - finishListBattle.length;
  6342. setProgress(`${I18N('TITAN_ARENA')}: ${I18N('LEVEL')} ${currTier} </br>${I18N('BATTLES')}: ${numReval}/${countRivalsTier} - ${attackScore}`);
  6343. /**
  6344. * TODO: Might need to improve the r###lts.
  6345. * TODO: Возможно стоит сделать улучшение результатов
  6346. */
  6347. // console.log('r###ltTitanArenaEndBattle', e)
  6348. console.log('r###ltTitanArenaEndBattle', numReval + '/' + countRivalsTier, attempts)
  6349. roundRivals();
  6350. }
  6351. /**
  6352. * Arena State
  6353. *
  6354. * Состояние арены
  6355. */
  6356. function titanArenaGetStatus() {
  6357. let calls = [{
  6358. name: "titanArenaGetStatus",
  6359. args: {},
  6360. ident: "body"
  6361. }];
  6362. send(JSON.stringify({calls}), checkR###ltInfo);
  6363. }
  6364. /**
  6365. * Arena Raid Request
  6366. *
  6367. * Запрос рейда арены
  6368. */
  6369. function titanArenaStartRaid() {
  6370. let calls = [{
  6371. name: "titanArenaStartRaid",
  6372. args: {
  6373. titans: titan_arena
  6374. },
  6375. ident: "body"
  6376. }];
  6377. send(JSON.stringify({calls}), calcR###lts);
  6378. }
  6379. function calcR###lts(data) {
  6380. let battlesInfo = data.r###lts[0].r###lt.response;
  6381. let {attackers, rivals} = battlesInfo;
  6382. let promises = [];
  6383. for (let n in rivals) {
  6384. rival = rivals[n];
  6385. promises.push(calcBattleR###lt({
  6386. attackers: attackers,
  6387. defenders: [rival.team],
  6388. seed: rival.seed,
  6389. typeId: n,
  6390. }));
  6391. }
  6392. Promise.all(promises)
  6393. .then(r###lts => {
  6394. const endR###lts = {};
  6395. for (let info of r###lts) {
  6396. let id = info.battleData.typeId;
  6397. endR###lts[id] = {
  6398. progress: info.progress,
  6399. r###lt: info.r###lt,
  6400. }
  6401. }
  6402. titanArenaEndRaid(endR###lts);
  6403. });
  6404. }
  6405. function calcBattleR###lt(battleData) {
  6406. return new Promise(function (resolve, reject) {
  6407. BattleCalc(battleData, "get_titanClanPvp", resolve);
  6408. });
  6409. }
  6410. /**
  6411. * Sending Raid R###lts
  6412. *
  6413. * Отправка результатов рейда
  6414. */
  6415. function titanArenaEndRaid(r###lts) {
  6416. titanArenaEndRaidCall = {
  6417. calls: [{
  6418. name: "titanArenaEndRaid",
  6419. args: {
  6420. r###lts
  6421. },
  6422. ident: "body"
  6423. }]
  6424. }
  6425. send(JSON.stringify(titanArenaEndRaidCall), checkRaidR###lts);
  6426. }
  6427. function checkRaidR###lts(data) {
  6428. r###lts = data.r###lts[0].r###lt.response.r###lts;
  6429. isSucsesRaid = true;
  6430. for (let i in r###lts) {
  6431. isSucsesRaid &&= (r###lts[i].attackScore >= 250);
  6432. }
  6433. if (isSucsesRaid) {
  6434. titanArenaCompleteTier();
  6435. } else {
  6436. titanArenaGetStatus();
  6437. }
  6438. }
  6439. function titanArenaFarmDailyReward() {
  6440. titanArenaFarmDailyRewardCall = {
  6441. calls: [{
  6442. name: "titanArenaFarmDailyReward",
  6443. args: {},
  6444. ident: "body"
  6445. }]
  6446. }
  6447. send(JSON.stringify(titanArenaFarmDailyRewardCall), () => {console.log('Done farm daily reward')});
  6448. }
  6449. function endTitanArena(reason, info) {
  6450. if (!['Peace_time', 'disabled'].includes(reason)) {
  6451. titanArenaFarmDailyReward();
  6452. }
  6453. console.log(reason, info);
  6454. setProgress(`${I18N('TITAN_ARENA')} ${I18N('COMPLETED')}!`, true);
  6455. resolve();
  6456. }
  6457. }
  6458. this.HWHClasses.executeTitanArena = executeTitanArena;
  6459. function hackGame() {
  6460. const self = this;
  6461. selfGame = null;
  6462. bindId = 1e9;
  6463. this.libGame = null;
  6464. this.doneLibLoad = () => {};
  6465. /**
  6466. * List of correspondence of used classes to their names
  6467. *
  6468. * Список соответствия используемых классов их названиям
  6469. */
  6470. ObjectsList = [
  6471. { name: 'BattlePresets', prop: 'game.battle.controller.thread.BattlePresets' },
  6472. { name: 'DataStorage', prop: 'game.data.storage.DataStorage' },
  6473. { name: 'BattleConfigStorage', prop: 'game.data.storage.battle.BattleConfigStorage' },
  6474. { name: 'BattleInstantPlay', prop: 'game.battle.controller.instant.BattleInstantPlay' },
  6475. { name: 'MultiBattleInstantReplay', prop: 'game.battle.controller.instant.MultiBattleInstantReplay' },
  6476. { name: 'MultiBattleR###lt', prop: 'game.battle.controller.MultiBattleR###lt' },
  6477. { name: 'PlayerMissionData', prop: 'game.model.user.mission.PlayerMissionData' },
  6478. { name: 'PlayerMissionBattle', prop: 'game.model.user.mission.PlayerMissionBattle' },
  6479. { name: 'GameModel', prop: 'game.model.GameModel' },
  6480. { name: 'CommandManager', prop: 'game.command.CommandManager' },
  6481. { name: 'MissionCommandList', prop: 'game.command.rpc.mission.MissionCommandList' },
  6482. { name: 'RPCCommandBase', prop: 'game.command.rpc.RPCCommandBase' },
  6483. { name: 'PlayerTowerData', prop: 'game.model.user.tower.PlayerTowerData' },
  6484. { name: 'TowerCommandList', prop: 'game.command.tower.TowerCommandList' },
  6485. { name: 'PlayerHeroTeamResolver', prop: 'game.model.user.hero.PlayerHeroTeamResolver' },
  6486. { name: 'BattlePausePopup', prop: 'game.view.popup.battle.BattlePausePopup' },
  6487. { name: 'BattlePopup', prop: 'game.view.popup.battle.BattlePopup' },
  6488. { name: 'DisplayObjectContainer', prop: 'starling.display.DisplayObjectContainer' },
  6489. { name: 'GuiClipContainer', prop: 'engine.core.clipgui.GuiClipContainer' },
  6490. { name: 'BattlePausePopupClip', prop: 'game.view.popup.battle.BattlePausePopupClip' },
  6491. { name: 'ClipLabel', prop: 'game.view.gui.components.ClipLabel' },
  6492. { name: 'ClipLabelBase', prop: 'game.view.gui.components.ClipLabelBase' },
  6493. { name: 'Translate', prop: 'com.progrestar.common.lang.Translate' },
  6494. { name: 'ClipButtonLabeledCentered', prop: 'game.view.gui.components.ClipButtonLabeledCentered' },
  6495. { name: 'BattlePausePopupMediator', prop: 'game.mediator.gui.popup.battle.BattlePausePopupMediator' },
  6496. { name: 'SettingToggleButton', prop: 'game.mechanics.settings.popup.view.SettingToggleButton' },
  6497. { name: 'PlayerDungeonData', prop: 'game.mechanics.dungeon.model.PlayerDungeonData' },
  6498. { name: 'NextDayUpdatedManager', prop: 'game.model.user.NextDayUpdatedManager' },
  6499. { name: 'BattleController', prop: 'game.battle.controller.BattleController' },
  6500. { name: 'BattleSettingsModel', prop: 'game.battle.controller.BattleSettingsModel' },
  6501. { name: 'BooleanProperty', prop: 'engine.core.utils.property.BooleanProperty' },
  6502. { name: 'RuleStorage', prop: 'game.data.storage.rule.RuleStorage' },
  6503. { name: 'BattleConfig', prop: 'battle.BattleConfig' },
  6504. { name: 'BattleGuiMediator', prop: 'game.battle.gui.BattleGuiMediator' },
  6505. { name: 'BooleanPropertyWriteable', prop: 'engine.core.utils.property.BooleanPropertyWriteable' },
  6506. { name: 'BattleLogEncoder', prop: 'battle.log.BattleLogEncoder' },
  6507. { name: 'BattleLogReader', prop: 'battle.log.BattleLogReader' },
  6508. { name: 'PlayerSubscriptionInfoValueObject', prop: 'game.model.user.subscription.PlayerSubscriptionInfoValueObject' },
  6509. { name: 'AdventureMapCamera', prop: 'game.mechanics.adventure.popup.map.AdventureMapCamera' },
  6510. ];
  6511. /**
  6512. * Contains the game classes needed to write and override game methods
  6513. *
  6514. * Содержит классы игры необходимые для написания и подмены методов игры
  6515. */
  6516. Game = {
  6517. /**
  6518. * Function 'e'
  6519. * Функция 'e'
  6520. */
  6521. bindFunc: function (a, b) {
  6522. if (null == b) return null;
  6523. null == b.__id__ && (b.__id__ = bindId++);
  6524. var c;
  6525. null == a.hx__closures__ ? (a.hx__closures__ = {}) : (c = a.hx__closures__[b.__id__]);
  6526. null == c && ((c = b.bind(a)), (a.hx__closures__[b.__id__] = c));
  6527. return c;
  6528. },
  6529. };
  6530. /**
  6531. * Connects to game objects via the object creation event
  6532. *
  6533. * Подключается к объектам игры через событие создания объекта
  6534. */
  6535. function connectGame() {
  6536. for (let obj of ObjectsList) {
  6537. /**
  6538. * https: //stackoverflow.com/questions/42611719/how-to-intercept-and-modify-a-specific-property-for-any-object
  6539. */
  6540. Object.defineProperty(Object.prototype, obj.prop, {
  6541. set: function (value) {
  6542. if (!selfGame) {
  6543. selfGame = this;
  6544. }
  6545. if (!Game[obj.name]) {
  6546. Game[obj.name] = value;
  6547. }
  6548. // console.log('set ' + obj.prop, this, value);
  6549. this[obj.prop + '_'] = value;
  6550. },
  6551. get: function () {
  6552. // console.log('get ' + obj.prop, this);
  6553. return this[obj.prop + '_'];
  6554. },
  6555. });
  6556. }
  6557. }
  6558. /**
  6559. * Game.BattlePresets
  6560. * @param {bool} a isReplay
  6561. * @param {bool} b autoToggleable
  6562. * @param {bool} c auto On Start
  6563. * @param {object} d config
  6564. * @param {bool} f showBothTeams
  6565. */
  6566. /**
  6567. * Returns the r###lts of the battle to the callback function
  6568. * Возвращает в функцию callback результаты боя
  6569. * @param {*} battleData battle data данные боя
  6570. * @param {*} battleConfig combat configuration type options:
  6571. *
  6572. * тип конфигурации боя варианты:
  6573. *
  6574. * "get_invasion", "get_titanPvpManual", "get_titanPvp",
  6575. * "get_titanClanPvp","get_clanPvp","get_titan","get_boss",
  6576. * "get_tower","get_pve","get_pvpManual","get_pvp","get_core"
  6577. *
  6578. * You can specify the xYc function in the game.assets.storage.BattleAssetStorage class
  6579. *
  6580. * Можно уточнить в классе game.assets.storage.BattleAssetStorage функция xYc
  6581. * @param {*} callback функция в которую вернуться результаты боя
  6582. */
  6583. this.BattleCalc = function (battleData, battleConfig, callback) {
  6584. // battleConfig = battleConfig || getBattleType(battleData.type)
  6585. if (!Game.BattlePresets) throw Error('Use connectGame');
  6586. battlePresets = new Game.BattlePresets(
  6587. battleData.progress,
  6588. !1,
  6589. !0,
  6590. Game.DataStorage[getFn(Game.DataStorage, 24)][getF(Game.BattleConfigStorage, battleConfig)](),
  6591. !1
  6592. );
  6593. let battleInstantPlay;
  6594. if (battleData.progress?.length > 1) {
  6595. battleInstantPlay = new Game.MultiBattleInstantReplay(battleData, battlePresets);
  6596. } else {
  6597. battleInstantPlay = new Game.BattleInstantPlay(battleData, battlePresets);
  6598. }
  6599. battleInstantPlay[getProtoFn(Game.BattleInstantPlay, 9)].add((battleInstant) => {
  6600. const MBR_2 = getProtoFn(Game.MultiBattleR###lt, 2);
  6601. const battleR###lts = battleInstant[getF(Game.BattleInstantPlay, 'get_r###lt')]();
  6602. const battleData = battleInstant[getF(Game.BattleInstantPlay, 'get_rawBattleInfo')]();
  6603. const battleLogs = [];
  6604. const timeLimit = battlePresets[getF(Game.BattlePresets, 'get_timeLimit')]();
  6605. let battleTime = 0;
  6606. let battleTimer = 0;
  6607. for (const battleR###lt of battleR###lts[MBR_2]) {
  6608. const battleLog = Game.BattleLogEncoder.read(new Game.BattleLogReader(battleR###lt));
  6609. battleLogs.push(battleLog);
  6610. const maxTime = Math.max(...battleLog.map((e) => (e.time < timeLimit && e.time !== 168.8 ? e.time : 0)));
  6611. battleTimer += getTimer(maxTime);
  6612. battleTime += maxTime;
  6613. }
  6614. callback({
  6615. battleLogs,
  6616. battleTime,
  6617. battleTimer,
  6618. battleData,
  6619. progress: battleR###lts[getF(Game.MultiBattleR###lt, 'get_progress')](),
  6620. r###lt: battleR###lts[getF(Game.MultiBattleR###lt, 'get_r###lt')](),
  6621. });
  6622. });
  6623. battleInstantPlay.start();
  6624. };
  6625. /**
  6626. * Returns a function with the specified name from the class
  6627. *
  6628. * Возвращает из класса функцию с указанным именем
  6629. * @param {Object} classF Class // класс
  6630. * @param {String} nameF function name // имя функции
  6631. * @param {String} pos name and alias order // порядок имени и псевдонима
  6632. * @returns
  6633. */
  6634. function getF(classF, nameF, pos) {
  6635. pos = pos || false;
  6636. let prop = Object.entries(classF.prototype.__properties__);
  6637. if (!pos) {
  6638. return prop.filter((e) => e[1] == nameF).pop()[0];
  6639. } else {
  6640. return prop.filter((e) => e[0] == nameF).pop()[1];
  6641. }
  6642. }
  6643. /**
  6644. * Returns a function with the specified name from the class
  6645. *
  6646. * Возвращает из класса функцию с указанным именем
  6647. * @param {Object} classF Class // класс
  6648. * @param {String} nameF function name // имя функции
  6649. * @returns
  6650. */
  6651. function getFnP(classF, nameF) {
  6652. let prop = Object.entries(classF.__properties__);
  6653. return prop.filter((e) => e[1] == nameF).pop()[0];
  6654. }
  6655. /**
  6656. * Returns the function name with the specified ordinal from the class
  6657. *
  6658. * Возвращает имя функции с указаным порядковым номером из класса
  6659. * @param {Object} classF Class // класс
  6660. * @param {Number} nF Order number of function // порядковый номер функции
  6661. * @returns
  6662. */
  6663. function getFn(classF, nF) {
  6664. let prop = Object.keys(classF);
  6665. return prop[nF];
  6666. }
  6667. /**
  6668. * Returns the name of the function with the specified serial number from the prototype of the class
  6669. *
  6670. * Возвращает имя функции с указаным порядковым номером из прототипа класса
  6671. * @param {Object} classF Class // класс
  6672. * @param {Number} nF Order number of function // порядковый номер функции
  6673. * @returns
  6674. */
  6675. function getProtoFn(classF, nF) {
  6676. let prop = Object.keys(classF.prototype);
  6677. return prop[nF];
  6678. }
  6679. /**
  6680. * Description of replaced functions
  6681. *
  6682. * Описание подменяемых функций
  6683. */
  6684. replaceFunction = {
  6685. company: function () {
  6686. let PMD_12 = getProtoFn(Game.PlayerMissionData, 12);
  6687. let oldSkipMisson = Game.PlayerMissionData.prototype[PMD_12];
  6688. Game.PlayerMissionData.prototype[PMD_12] = function (a, b, c) {
  6689. if (!isChecked('passBattle')) {
  6690. oldSkipMisson.call(this, a, b, c);
  6691. return;
  6692. }
  6693. try {
  6694. this[getProtoFn(Game.PlayerMissionData, 9)] = new Game.PlayerMissionBattle(a, b, c);
  6695. var a = new Game.BattlePresets(
  6696. !1,
  6697. !1,
  6698. !0,
  6699. Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](),
  6700. !1
  6701. );
  6702. a = new Game.BattleInstantPlay(c, a);
  6703. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  6704. a.start();
  6705. } catch (error) {
  6706. console.error('company', error);
  6707. oldSkipMisson.call(this, a, b, c);
  6708. }
  6709. };
  6710. Game.PlayerMissionData.prototype.P$h = function (a) {
  6711. let GM_2 = getFn(Game.GameModel, 2);
  6712. let GM_P2 = getProtoFn(Game.GameModel, 2);
  6713. let CM_20 = getProtoFn(Game.CommandManager, 20);
  6714. let MCL_2 = getProtoFn(Game.MissionCommandList, 2);
  6715. let MBR_15 = getF(Game.MultiBattleR###lt, 'get_r###lt');
  6716. let RP###_15 = getProtoFn(Game.RPCCommandBase, 16);
  6717. let PMD_32 = getProtoFn(Game.PlayerMissionData, 32);
  6718. Game.GameModel[GM_2]()[GM_P2][CM_20][MCL_2](a[MBR_15]())[RP###_15](Game.bindFunc(this, this[PMD_32]));
  6719. };
  6720. },
  6721. /*
  6722. tower: function () {
  6723. let PTD_67 = getProtoFn(Game.PlayerTowerData, 67);
  6724. let oldSkipTower = Game.PlayerTowerData.prototype[PTD_67];
  6725. Game.PlayerTowerData.prototype[PTD_67] = function (a) {
  6726. if (!isChecked('passBattle')) {
  6727. oldSkipTower.call(this, a);
  6728. return;
  6729. }
  6730. try {
  6731. var p = new Game.BattlePresets(
  6732. !1,
  6733. !1,
  6734. !0,
  6735. Game.DataStorage[getFn(Game.DataStorage, 24)][getProtoFn(Game.BattleConfigStorage, 20)](),
  6736. !1
  6737. );
  6738. a = new Game.BattleInstantPlay(a, p);
  6739. a[getProtoFn(Game.BattleInstantPlay, 9)].add(Game.bindFunc(this, this.P$h));
  6740. a.start();
  6741. } catch (error) {
  6742. console.error('tower', error);
  6743. oldSkipMisson.call(this, a, b, c);
  6744. }
  6745. };
  6746. Game.PlayerTowerData.prototype.P$h = function (a) {
  6747. const GM_2 = getFnP(Game.GameModel, 'get_instance');
  6748. const GM_P2 = getProtoFn(Game.GameModel, 2);
  6749. const CM_29 = getProtoFn(Game.CommandManager, 29);
  6750. const TCL_5 = getProtoFn(Game.TowerCommandList, 5);
  6751. const MBR_15 = getF(Game.MultiBattleR###lt, 'get_r###lt');
  6752. const RP###_15 = getProtoFn(Game.RPCCommandBase, 17);
  6753. const PTD_78 = getProtoFn(Game.PlayerTowerData, 78);
  6754. Game.GameModel[GM_2]()[GM_P2][CM_29][TCL_5](a[MBR_15]())[RP###_15](Game.bindFunc(this, this[PTD_78]));
  6755. };
  6756. },
  6757. */
  6758. // skipSelectHero: function() {
  6759. // if (!HOST) throw Error('Use connectGame');
  6760. // Game.PlayerHeroTeamResolver.prototype[getProtoFn(Game.PlayerHeroTeamResolver, 3)] = () => false;
  6761. // },
  6762. passBattle: function () {
  6763. let BPP_4 = getProtoFn(Game.BattlePausePopup, 4);
  6764. let oldPassBattle = Game.BattlePausePopup.prototype[BPP_4];
  6765. Game.BattlePausePopup.prototype[BPP_4] = function (a) {
  6766. if (!isChecked('passBattle')) {
  6767. oldPassBattle.call(this, a);
  6768. return;
  6769. }
  6770. try {
  6771. Game.BattlePopup.prototype[getProtoFn(Game.BattlePausePopup, 4)].call(this, a);
  6772. this[getProtoFn(Game.BattlePausePopup, 3)]();
  6773. this[getProtoFn(Game.DisplayObjectContainer, 3)](this.clip[getProtoFn(Game.GuiClipContainer, 2)]());
  6774. this.clip[getProtoFn(Game.BattlePausePopupClip, 1)][getProtoFn(Game.ClipLabelBase, 9)](
  6775. Game.Translate.translate('UI_POPUP_BATTLE_PAUSE')
  6776. );
  6777. this.clip[getProtoFn(Game.BattlePausePopupClip, 2)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  6778. Game.Translate.translate('UI_POPUP_BATTLE_RETREAT'),
  6779. ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 17)]))
  6780. );
  6781. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 2)](
  6782. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 14)](),
  6783. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 13)]()
  6784. ? ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  6785. : ((q = this[getProtoFn(Game.BattlePausePopup, 1)]), Game.bindFunc(q, q[getProtoFn(Game.BattlePausePopupMediator, 18)]))
  6786. );
  6787. this.clip[getProtoFn(Game.BattlePausePopupClip, 5)][getProtoFn(Game.ClipButtonLabeledCentered, 0)][
  6788. getProtoFn(Game.ClipLabelBase, 24)
  6789. ]();
  6790. this.clip[getProtoFn(Game.BattlePausePopupClip, 3)][getProtoFn(Game.SettingToggleButton, 3)](
  6791. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 9)]()
  6792. );
  6793. this.clip[getProtoFn(Game.BattlePausePopupClip, 4)][getProtoFn(Game.SettingToggleButton, 3)](
  6794. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 10)]()
  6795. );
  6796. this.clip[getProtoFn(Game.BattlePausePopupClip, 6)][getProtoFn(Game.SettingToggleButton, 3)](
  6797. this[getProtoFn(Game.BattlePausePopup, 1)][getProtoFn(Game.BattlePausePopupMediator, 11)]()
  6798. );
  6799. } catch (error) {
  6800. console.error('passBattle', error);
  6801. oldPassBattle.call(this, a);
  6802. }
  6803. };
  6804. let retreatButtonLabel = getF(Game.BattlePausePopupMediator, 'get_retreatButtonLabel');
  6805. let oldFunc = Game.BattlePausePopupMediator.prototype[retreatButtonLabel];
  6806. Game.BattlePausePopupMediator.prototype[retreatButtonLabel] = function () {
  6807. if (isChecked('passBattle')) {
  6808. return I18N('BTN_PASS');
  6809. } else {
  6810. return oldFunc.call(this);
  6811. }
  6812. };
  6813. },
  6814. endlessCards: function () {
  6815. let PDD_21 = getProtoFn(Game.PlayerDungeonData, 21);
  6816. let oldEndlessCards = Game.PlayerDungeonData.prototype[PDD_21];
  6817. Game.PlayerDungeonData.prototype[PDD_21] = function () {
  6818. if (countPredictionCard <= 0) {
  6819. return true;
  6820. } else {
  6821. return oldEndlessCards.call(this);
  6822. }
  6823. };
  6824. },
  6825. speedBattle: function () {
  6826. const get_timeScale = getF(Game.BattleController, 'get_timeScale');
  6827. const oldSpeedBattle = Game.BattleController.prototype[get_timeScale];
  6828. Game.BattleController.prototype[get_timeScale] = function () {
  6829. const speedBattle = Number.parseFloat(getInput('speedBattle'));
  6830. if (!speedBattle) {
  6831. return oldSpeedBattle.call(this);
  6832. }
  6833. try {
  6834. const BC_12 = getProtoFn(Game.BattleController, 12);
  6835. const BSM_12 = getProtoFn(Game.BattleSettingsModel, 12);
  6836. const BP_get_value = getF(Game.BooleanProperty, 'get_value');
  6837. if (this[BC_12][BSM_12][BP_get_value]()) {
  6838. return 0;
  6839. }
  6840. const BSM_2 = getProtoFn(Game.BattleSettingsModel, 2);
  6841. const BC_49 = getProtoFn(Game.BattleController, 49);
  6842. const BSM_1 = getProtoFn(Game.BattleSettingsModel, 1);
  6843. const BC_14 = getProtoFn(Game.BattleController, 14);
  6844. const BC_3 = getFn(Game.BattleController, 3);
  6845. if (this[BC_12][BSM_2][BP_get_value]()) {
  6846. var a = speedBattle * this[BC_49]();
  6847. } else {
  6848. a = this[BC_12][BSM_1][BP_get_value]();
  6849. const maxSpeed = Math.max(...this[BC_14]);
  6850. const multiple = a == this[BC_14].indexOf(maxSpeed) ? (maxSpeed >= 4 ? speedBattle : this[BC_14][a]) : this[BC_14][a];
  6851. a = multiple * Game.BattleController[BC_3][BP_get_value]() * this[BC_49]();
  6852. }
  6853. const BSM_24 = getProtoFn(Game.BattleSettingsModel, 24);
  6854. a > this[BC_12][BSM_24][BP_get_value]() && (a = this[BC_12][BSM_24][BP_get_value]());
  6855. const DS_23 = getFn(Game.DataStorage, 23);
  6856. const get_battleSpeedMultiplier = getF(Game.RuleStorage, 'get_battleSpeedMultiplier', true);
  6857. var b = Game.DataStorage[DS_23][get_battleSpeedMultiplier]();
  6858. const R_1 = getFn(selfGame.Reflect, 1);
  6859. const BC_1 = getFn(Game.BattleController, 1);
  6860. const get_config = getF(Game.BattlePresets, 'get_config');
  6861. null != b &&
  6862. (a = selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident)
  6863. ? a * selfGame.Reflect[R_1](b, this[BC_1][get_config]().ident)
  6864. : a * selfGame.Reflect[R_1](b, 'default'));
  6865. return a;
  6866. } catch (error) {
  6867. console.error('passBatspeedBattletle', error);
  6868. return oldSpeedBattle.call(this);
  6869. }
  6870. };
  6871. },
  6872. /**
  6873. * Acceleration button without Valkyries favor
  6874. *
  6875. * Кнопка ускорения без Покровительства Валькирий
  6876. */
  6877. battleFastKey: function () {
  6878. const BGM_44 = getProtoFn(Game.BattleGuiMediator, 44);
  6879. const oldBattleFastKey = Game.BattleGuiMediator.prototype[BGM_44];
  6880. Game.BattleGuiMediator.prototype[BGM_44] = function () {
  6881. let flag = true;
  6882. //console.log(flag)
  6883. if (!flag) {
  6884. return oldBattleFastKey.call(this);
  6885. }
  6886. try {
  6887. const BGM_9 = getProtoFn(Game.BattleGuiMediator, 9);
  6888. const BGM_10 = getProtoFn(Game.BattleGuiMediator, 10);
  6889. const BPW_0 = getProtoFn(Game.BooleanPropertyWriteable, 0);
  6890. this[BGM_9][BPW_0](true);
  6891. this[BGM_10][BPW_0](true);
  6892. } catch (error) {
  6893. console.error(error);
  6894. return oldBattleFastKey.call(this);
  6895. }
  6896. };
  6897. },
  6898. fastSeason: function () {
  6899. const GameNavigator = selfGame['game.screen.navigator.GameNavigator'];
  6900. const oldFuncName = getProtoFn(GameNavigator, 18);
  6901. const newFuncName = getProtoFn(GameNavigator, 16);
  6902. const oldFastSeason = GameNavigator.prototype[oldFuncName];
  6903. const newFastSeason = GameNavigator.prototype[newFuncName];
  6904. GameNavigator.prototype[oldFuncName] = function (a, b) {
  6905. if (isChecked('fastSeason')) {
  6906. return newFastSeason.apply(this, [a]);
  6907. } else {
  6908. return oldFastSeason.apply(this, [a, b]);
  6909. }
  6910. };
  6911. },
  6912. ShowChestReward: function () {
  6913. const TitanArtifactChest = selfGame['game.mechanics.titan_arena.mediator.chest.TitanArtifactChestRewardPopupMediator'];
  6914. const getOpenAmountTitan = getF(TitanArtifactChest, 'get_openAmount');
  6915. const oldGetOpenAmountTitan = TitanArtifactChest.prototype[getOpenAmountTitan];
  6916. TitanArtifactChest.prototype[getOpenAmountTitan] = function () {
  6917. if (correctShowOpenArtifact) {
  6918. correctShowOpenArtifact--;
  6919. return 100;
  6920. }
  6921. return oldGetOpenAmountTitan.call(this);
  6922. };
  6923. const ArtifactChest = selfGame['game.view.popup.artifactchest.rewardpopup.ArtifactChestRewardPopupMediator'];
  6924. const getOpenAmount = getF(ArtifactChest, 'get_openAmount');
  6925. const oldGetOpenAmount = ArtifactChest.prototype[getOpenAmount];
  6926. ArtifactChest.prototype[getOpenAmount] = function () {
  6927. if (correctShowOpenArtifact) {
  6928. correctShowOpenArtifact--;
  6929. return 100;
  6930. }
  6931. return oldGetOpenAmount.call(this);
  6932. };
  6933. },
  6934. fixCompany: function () {
  6935. const GameBattleView = selfGame['game.mediator.gui.popup.battle.GameBattleView'];
  6936. const BattleThread = selfGame['game.battle.controller.thread.BattleThread'];
  6937. const getOnViewDisposed = getF(BattleThread, 'get_onViewDisposed');
  6938. const getThread = getF(GameBattleView, 'get_thread');
  6939. const oldFunc = GameBattleView.prototype[getThread];
  6940. GameBattleView.prototype[getThread] = function () {
  6941. return (
  6942. oldFunc.call(this) || {
  6943. [getOnViewDisposed]: async () => {},
  6944. }
  6945. );
  6946. };
  6947. },
  6948. BuyTitanArtifact: function () {
  6949. const BIP_4 = getProtoFn(selfGame['game.view.popup.shop.buy.BuyItemPopup'], 4);
  6950. const BuyItemPopup = selfGame['game.view.popup.shop.buy.BuyItemPopup'];
  6951. const oldFunc = BuyItemPopup.prototype[BIP_4];
  6952. BuyItemPopup.prototype[BIP_4] = function () {
  6953. if (isChecked('countControl')) {
  6954. const BuyTitanArtifactItemPopup = selfGame['game.view.popup.shop.buy.BuyTitanArtifactItemPopup'];
  6955. const BTAP_0 = getProtoFn(BuyTitanArtifactItemPopup, 0);
  6956. if (this[BTAP_0]) {
  6957. const BuyTitanArtifactPopupMediator = selfGame['game.mediator.gui.popup.shop.buy.BuyTitanArtifactItemPopupMediator'];
  6958. const BTAM_1 = getProtoFn(BuyTitanArtifactPopupMediator, 1);
  6959. const BuyItemPopupMediator = selfGame['game.mediator.gui.popup.shop.buy.BuyItemPopupMediator'];
  6960. const BIPM_5 = getProtoFn(BuyItemPopupMediator, 5);
  6961. const BIPM_7 = getProtoFn(BuyItemPopupMediator, 7);
  6962. const BIPM_9 = getProtoFn(BuyItemPopupMediator, 9);
  6963. let need = Math.min(this[BTAP_0][BTAM_1](), this[BTAP_0][BIPM_7]);
  6964. need = need ? need : 60;
  6965. this[BTAP_0][BIPM_9] = need;
  6966. this[BTAP_0][BIPM_5] = 10;
  6967. }
  6968. }
  6969. oldFunc.call(this);
  6970. };
  6971. },
  6972. ClanQuestsFastFarm: function () {
  6973. const VipRuleValueObject = selfGame['game.data.storage.rule.VipRuleValueObject'];
  6974. const getClanQuestsFastFarm = getF(VipRuleValueObject, 'get_clanQuestsFastFarm', 1);
  6975. VipRuleValueObject.prototype[getClanQuestsFastFarm] = function () {
  6976. return 0;
  6977. };
  6978. },
  6979. adventureCamera: function () {
  6980. const AMC_40 = getProtoFn(Game.AdventureMapCamera, 40);
  6981. const AMC_5 = getProtoFn(Game.AdventureMapCamera, 5);
  6982. const oldFunc = Game.AdventureMapCamera.prototype[AMC_40];
  6983. Game.AdventureMapCamera.prototype[AMC_40] = function (a) {
  6984. this[AMC_5] = 0.4;
  6985. oldFunc.bind(this)(a);
  6986. };
  6987. },
  6988. unlockMission: function () {
  6989. const WorldMapStoryDrommerHelper = selfGame['game.mediator.gui.worldmap.WorldMapStoryDrommerHelper'];
  6990. const WMSDH_4 = getFn(WorldMapStoryDrommerHelper, 4);
  6991. const WMSDH_7 = getFn(WorldMapStoryDrommerHelper, 7);
  6992. WorldMapStoryDrommerHelper[WMSDH_4] = function () {
  6993. return true;
  6994. };
  6995. WorldMapStoryDrommerHelper[WMSDH_7] = function () {
  6996. return true;
  6997. };
  6998. },
  6999. };
  7000. /**
  7001. * Starts replacing recorded functions
  7002. *
  7003. * Запускает замену записанных функций
  7004. */
  7005. this.activateHacks = function () {
  7006. if (!selfGame) throw Error('Use connectGame');
  7007. for (let func in replaceFunction) {
  7008. try {
  7009. replaceFunction[func]();
  7010. } catch (error) {
  7011. console.error(error);
  7012. }
  7013. }
  7014. };
  7015. /**
  7016. * Returns the game object
  7017. *
  7018. * Возвращает объект игры
  7019. */
  7020. this.getSelfGame = function () {
  7021. return selfGame;
  7022. };
  7023. /**
  7024. * Updates game data
  7025. *
  7026. * Обновляет данные игры
  7027. */
  7028. this.refreshGame = function () {
  7029. new Game.NextDayUpdatedManager()[getProtoFn(Game.NextDayUpdatedManager, 5)]();
  7030. try {
  7031. cheats.refreshInventory();
  7032. } catch (e) {}
  7033. };
  7034. /**
  7035. * Update inventory
  7036. *
  7037. * Обновляет инвентарь
  7038. */
  7039. this.refreshInventory = async function () {
  7040. const GM_INST = getFnP(Game.GameModel, 'get_instance');
  7041. const GM_0 = getProtoFn(Game.GameModel, 0);
  7042. const P_24 = getProtoFn(selfGame['game.model.user.Player'], 24);
  7043. const Player = Game.GameModel[GM_INST]()[GM_0];
  7044. Player[P_24] = new selfGame['game.model.user.inventory.PlayerInventory']();
  7045. Player[P_24].init(await Send({ calls: [{ name: 'inventoryGet', args: {}, ident: 'body' }] }).then((e) => e.r###lts[0].r###lt.response));
  7046. };
  7047. this.updateInventory = function (reward) {
  7048. const GM_INST = getFnP(Game.GameModel, 'get_instance');
  7049. const GM_0 = getProtoFn(Game.GameModel, 0);
  7050. const P_24 = getProtoFn(selfGame['game.model.user.Player'], 24);
  7051. const Player = Game.GameModel[GM_INST]()[GM_0];
  7052. Player[P_24].init(reward);
  7053. };
  7054. this.updateMap = function (data) {
  7055. const PCDD_21 = getProtoFn(selfGame['game.mechanics.clanDomination.model.PlayerClanDominationData'], 21);
  7056. const P_60 = getProtoFn(selfGame['game.model.user.Player'], 60);
  7057. const GM_0 = getProtoFn(Game.GameModel, 0);
  7058. const getInstance = getFnP(selfGame['Game'], 'get_instance');
  7059. const PlayerClanDominationData = Game.GameModel[getInstance]()[GM_0];
  7060. PlayerClanDominationData[P_60][PCDD_21].update(data);
  7061. };
  7062. /**
  7063. * Change the play screen on windowName
  7064. *
  7065. * Сменить экран игры на windowName
  7066. *
  7067. * Possible options:
  7068. *
  7069. * Возможные варианты:
  7070. *
  7071. * 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
  7072. */
  7073. this.goNavigtor = function (windowName) {
  7074. let mechanicStorage = selfGame['game.data.storage.mechanic.MechanicStorage'];
  7075. let window = mechanicStorage[windowName];
  7076. let event = new selfGame['game.mediator.gui.popup.PopupStashEventParams']();
  7077. let Game = selfGame['Game'];
  7078. let navigator = getF(Game, 'get_navigator');
  7079. let navigate = getProtoFn(selfGame['game.screen.navigator.GameNavigator'], 20);
  7080. let instance = getFnP(Game, 'get_instance');
  7081. Game[instance]()[navigator]()[navigate](window, event);
  7082. };
  7083. /**
  7084. * Move to the sanctuary cheats.goSanctuary()
  7085. *
  7086. * Переместиться в святилище cheats.goSanctuary()
  7087. */
  7088. this.goSanctuary = () => {
  7089. this.goNavigtor('SANCTUARY');
  7090. };
  7091. /** Перейти в Долину титанов */
  7092. this.goTitanValley = () => {
  7093. this.goNavigtor('TITAN_VALLEY');
  7094. };
  7095. /**
  7096. * Go to Guild War
  7097. *
  7098. * Перейти к Войне Гильдий
  7099. */
  7100. this.goClanWar = function () {
  7101. let instance = getFnP(Game.GameModel, 'get_instance');
  7102. let player = Game.GameModel[instance]().A;
  7103. let clanWarSelect = selfGame['game.mechanics.cross_clan_war.popup.selectMode.CrossClanWarSelectModeMediator'];
  7104. new clanWarSelect(player).open();
  7105. };
  7106. /** Перейти к Острову гильдии */
  7107. this.goClanIsland = function () {
  7108. let instance = getFnP(Game.GameModel, 'get_instance');
  7109. let player = Game.GameModel[instance]().A;
  7110. let clanIslandSelect = selfGame['game.view.gui.ClanIslandPopupMediator'];
  7111. new clanIslandSelect(player).open();
  7112. };
  7113. /**
  7114. * Go to BrawlShop
  7115. *
  7116. * Переместиться в BrawlShop
  7117. */
  7118. this.goBrawlShop = () => {
  7119. const instance = getFnP(Game.GameModel, 'get_instance');
  7120. const P_36 = getProtoFn(selfGame['game.model.user.Player'], 36);
  7121. const PSD_0 = getProtoFn(selfGame['game.model.user.shop.PlayerShopData'], 0);
  7122. const IM_0 = getProtoFn(selfGame['haxe.ds.IntMap'], 0);
  7123. const PSDE_4 = getProtoFn(selfGame['game.model.user.shop.PlayerShopDataEntry'], 4);
  7124. const player = Game.GameModel[instance]().A;
  7125. const shop = player[P_36][PSD_0][IM_0][1038][PSDE_4];
  7126. const shopPopup = new selfGame['game.mechanics.brawl.mediator.BrawlShopPopupMediator'](player, shop);
  7127. shopPopup.open(new selfGame['game.mediator.gui.popup.PopupStashEventParams']());
  7128. };
  7129. /**
  7130. * Returns all stores from game data
  7131. *
  7132. * Возвращает все магазины из данных игры
  7133. */
  7134. this.getShops = () => {
  7135. const instance = getFnP(Game.GameModel, 'get_instance');
  7136. const P_36 = getProtoFn(selfGame['game.model.user.Player'], 36);
  7137. const PSD_0 = getProtoFn(selfGame['game.model.user.shop.PlayerShopData'], 0);
  7138. const IM_0 = getProtoFn(selfGame['haxe.ds.IntMap'], 0);
  7139. const player = Game.GameModel[instance]().A;
  7140. return player[P_36][PSD_0][IM_0];
  7141. };
  7142. /**
  7143. * Returns the store from the game data by ID
  7144. *
  7145. * Возвращает магазин из данных игры по идетификатору
  7146. */
  7147. this.getShop = (id) => {
  7148. const PSDE_4 = getProtoFn(selfGame['game.model.user.shop.PlayerShopDataEntry'], 4);
  7149. const shops = this.getShops();
  7150. const shop = shops[id]?.[PSDE_4];
  7151. return shop;
  7152. };
  7153. /**
  7154. * Change island map
  7155. *
  7156. * Сменить карту острова
  7157. */
  7158. this.changeIslandMap = (mapId = 2) => {
  7159. const GameInst = getFnP(selfGame['Game'], 'get_instance');
  7160. const GM_0 = getProtoFn(Game.GameModel, 0);
  7161. const P_59 = getProtoFn(selfGame['game.model.user.Player'], 60);
  7162. const PSAD_31 = getProtoFn(selfGame['game.mechanics.season_adventure.model.PlayerSeasonAdventureData'], 31);
  7163. const Player = Game.GameModel[GameInst]()[GM_0];
  7164. Player[P_59][PSAD_31]({ id: mapId, seasonAdventure: { id: mapId, startDate: 1701914400, endDate: 1709690400, closed: false } });
  7165. const GN_15 = getProtoFn(selfGame['game.screen.navigator.GameNavigator'], 17);
  7166. const navigator = getF(selfGame['Game'], 'get_navigator');
  7167. selfGame['Game'][GameInst]()[navigator]()[GN_15](new selfGame['game.mediator.gui.popup.PopupStashEventParams']());
  7168. };
  7169. /**
  7170. * Game library availability tracker
  7171. *
  7172. * Отслеживание доступности игровой библиотеки
  7173. */
  7174. function checkLibLoad() {
  7175. timeout = setTimeout(() => {
  7176. if (Game.GameModel) {
  7177. changeLib();
  7178. } else {
  7179. checkLibLoad();
  7180. }
  7181. }, 100);
  7182. }
  7183. /**
  7184. * Game library data spoofing
  7185. *
  7186. * Подмена данных игровой библиотеки
  7187. */
  7188. function changeLib() {
  7189. console.log('lib connect');
  7190. const originalStartFunc = Game.GameModel.prototype.start;
  7191. Game.GameModel.prototype.start = function (a, b, c) {
  7192. self.libGame = b.raw;
  7193. self.doneLibLoad(self.libGame);
  7194. try {
  7195. const levels = b.raw.seasonAdventure.level;
  7196. for (const id in levels) {
  7197. const level = levels[id];
  7198. level.clientData.graphics.fogged = level.clientData.graphics.visible;
  7199. }
  7200. const adv = b.raw.seasonAdventure.list[1];
  7201. adv.clientData.asset = 'dialog_season_adventure_tiles';
  7202. } catch (e) {
  7203. console.warn(e);
  7204. }
  7205. originalStartFunc.call(this, a, b, c);
  7206. };
  7207. }
  7208. this.LibLoad = function () {
  7209. return new Promise((e) => {
  7210. this.doneLibLoad = e;
  7211. });
  7212. };
  7213. /**
  7214. * Returns the value of a language constant
  7215. *
  7216. * Возвращает значение языковой константы
  7217. * @param {*} langConst language constant // языковая константа
  7218. * @returns
  7219. */
  7220. this.translate = function (langConst) {
  7221. return Game.Translate.translate(langConst);
  7222. };
  7223. connectGame();
  7224. checkLibLoad();
  7225. }
  7226. /**
  7227. * Auto collection of gifts
  7228. *
  7229. * Автосбор подарков
  7230. */
  7231. function getAutoGifts() {
  7232. // c3ltYm9scyB0aGF0IG1lYW4gbm90aGluZw==
  7233. let valName = 'giftSendIds_' + userInfo.id;
  7234. if (!localStorage['clearGift' + userInfo.id]) {
  7235. localStorage[valName] = '';
  7236. localStorage['clearGift' + userInfo.id] = '+';
  7237. }
  7238. if (!localStorage[valName]) {
  7239. localStorage[valName] = '';
  7240. }
  7241. const giftsAPI = new ZingerYWebsiteAPI('getGifts.php', arguments);
  7242. /**
  7243. * Submit a request to receive gift codes
  7244. *
  7245. * Отправка запроса для получения кодов подарков
  7246. */
  7247. giftsAPI.request().then((data) => {
  7248. let freebieCheckCalls = {
  7249. calls: [],
  7250. };
  7251. data.forEach((giftId, n) => {
  7252. if (localStorage[valName].includes(giftId)) return;
  7253. freebieCheckCalls.calls.push({
  7254. name: 'registration',
  7255. args: {
  7256. user: { referrer: {} },
  7257. giftId,
  7258. },
  7259. context: {
  7260. actionTs: Math.floor(performance.now()),
  7261. cookie: window?.NXAppInfo?.session_id || null,
  7262. },
  7263. ident: giftId,
  7264. });
  7265. });
  7266. if (!freebieCheckCalls.calls.length) {
  7267. return;
  7268. }
  7269. send(JSON.stringify(freebieCheckCalls), (e) => {
  7270. let countGetGifts = 0;
  7271. const gifts = [];
  7272. for (check of e.r###lts) {
  7273. gifts.push(check.ident);
  7274. if (check.r###lt.response != null) {
  7275. countGetGifts++;
  7276. }
  7277. }
  7278. const saveGifts = localStorage[valName].split(';');
  7279. localStorage[valName] = [...saveGifts, ...gifts].slice(-50).join(';');
  7280. console.log(`${I18N('GIFTS')}: ${countGetGifts}`);
  7281. });
  7282. });
  7283. }
  7284. /**
  7285. * To fill the kills in the Forge of Souls
  7286. *
  7287. * Набить килов в горниле душ
  7288. */
  7289. async function bossRatingEvent() {
  7290. const topGet = await Send(JSON.stringify({ calls: [{ name: "topGet", args: { type: "bossRatingTop", extraId: 0 }, ident: "body" }] }));
  7291. if (!topGet || !topGet.r###lts[0].r###lt.response[0]) {
  7292. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7293. return;
  7294. }
  7295. const replayId = topGet.r###lts[0].r###lt.response[0].userData.replayId;
  7296. const r###lt = await Send(JSON.stringify({
  7297. calls: [
  7298. { name: "battleGetReplay", args: { id: replayId }, ident: "battleGetReplay" },
  7299. { name: "heroGetAll", args: {}, ident: "heroGetAll" },
  7300. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  7301. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  7302. ]
  7303. }));
  7304. const bossEventInfo = r###lt.r###lts[3].r###lt.response.find(e => e.offerType == "bossEvent");
  7305. if (!bossEventInfo) {
  7306. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7307. return;
  7308. }
  7309. const usedHeroes = bossEventInfo.progress.usedHeroes;
  7310. const party = Object.values(r###lt.r###lts[0].r###lt.response.replay.attackers);
  7311. const availableHeroes = Object.values(r###lt.r###lts[1].r###lt.response).map(e => e.id);
  7312. const availablePets = Object.values(r###lt.r###lts[2].r###lt.response).map(e => e.id);
  7313. const calls = [];
  7314. /**
  7315. * First pack
  7316. *
  7317. * Первая пачка
  7318. */
  7319. const args = {
  7320. heroes: [],
  7321. favor: {}
  7322. }
  7323. for (let hero of party) {
  7324. if (hero.id >= 6000 && availablePets.includes(hero.id)) {
  7325. args.pet = hero.id;
  7326. continue;
  7327. }
  7328. if (!availableHeroes.includes(hero.id) || usedHeroes.includes(hero.id)) {
  7329. continue;
  7330. }
  7331. args.heroes.push(hero.id);
  7332. if (hero.favorPetId) {
  7333. args.favor[hero.id] = hero.favorPetId;
  7334. }
  7335. }
  7336. if (args.heroes.length) {
  7337. calls.push({
  7338. name: 'bossRating_startBattle',
  7339. args,
  7340. ident: 'body_0',
  7341. });
  7342. }
  7343. /**
  7344. * Other packs
  7345. *
  7346. * Другие пачки
  7347. */
  7348. let heroes = [];
  7349. let count = 1;
  7350. while (heroId = availableHeroes.pop()) {
  7351. if (args.heroes.includes(heroId) || usedHeroes.includes(heroId)) {
  7352. continue;
  7353. }
  7354. heroes.push(heroId);
  7355. if (heroes.length == 5) {
  7356. calls.push({
  7357. name: 'bossRating_startBattle',
  7358. args: {
  7359. heroes: [...heroes],
  7360. pet: availablePets[Math.floor(Math.random() * availablePets.length)],
  7361. },
  7362. ident: 'body_' + count,
  7363. });
  7364. heroes = [];
  7365. count++;
  7366. }
  7367. }
  7368. if (!calls.length) {
  7369. setProgress(`${I18N('NO_HEROES')}`, true);
  7370. return;
  7371. }
  7372. const r###ltBattles = await Send(JSON.stringify({ calls }));
  7373. console.log(r###ltBattles);
  7374. rewardBossRatingEvent();
  7375. }
  7376. /**
  7377. * Collecting Rewards from the Forge of Souls
  7378. *
  7379. * Сбор награды из Горнила Душ
  7380. */
  7381. function rewardBossRatingEvent() {
  7382. let rewardBossRatingCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  7383. send(rewardBossRatingCall, function (data) {
  7384. let bossEventInfo = data.r###lts[0].r###lt.response.find(e => e.offerType == "bossEvent");
  7385. if (!bossEventInfo) {
  7386. setProgress(`${I18N('EVENT')} ${I18N('NOT_AVAILABLE')}`, true);
  7387. return;
  7388. }
  7389. let farmedChests = bossEventInfo.progress.farmedChests;
  7390. let score = bossEventInfo.progress.score;
  7391. setProgress(`${I18N('DAMAGE_AMOUNT')}: ${score}`);
  7392. let revard = bossEventInfo.reward;
  7393. let getRewardCall = {
  7394. calls: []
  7395. }
  7396. let count = 0;
  7397. for (let i = 1; i < 10; i++) {
  7398. if (farmedChests.includes(i)) {
  7399. continue;
  7400. }
  7401. if (score < revard[i].score) {
  7402. break;
  7403. }
  7404. getRewardCall.calls.push({
  7405. name: 'bossRating_getReward',
  7406. args: {
  7407. rewardId: i,
  7408. },
  7409. ident: 'body_' + i,
  7410. });
  7411. count++;
  7412. }
  7413. if (!count) {
  7414. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  7415. return;
  7416. }
  7417. send(JSON.stringify(getRewardCall), e => {
  7418. console.log(e);
  7419. setProgress(`${I18N('COLLECTED')} ${e?.r###lts?.length} ${I18N('REWARD')}`, true);
  7420. });
  7421. });
  7422. }
  7423. /**
  7424. * Collect Easter eggs and event rewards
  7425. *
  7426. * Собрать пасхалки и награды событий
  7427. */
  7428. function offerFarmAllReward() {
  7429. const offerGetAllCall = '{"calls":[{"name":"offerGetAll","args":{},"ident":"offerGetAll"}]}';
  7430. return Send(offerGetAllCall).then((data) => {
  7431. const offerGetAll = data.r###lts[0].r###lt.response.filter(e => e.type == "reward" && !e?.freeRewardObtained && e.reward);
  7432. if (!offerGetAll.length) {
  7433. setProgress(`${I18N('NOTHING_TO_COLLECT')}`, true);
  7434. return;
  7435. }
  7436. const calls = [];
  7437. for (let reward of offerGetAll) {
  7438. calls.push({
  7439. name: "offerFarmReward",
  7440. args: {
  7441. offerId: reward.id
  7442. },
  7443. ident: "offerFarmReward_" + reward.id
  7444. });
  7445. }
  7446. return Send(JSON.stringify({ calls })).then(e => {
  7447. console.log(e);
  7448. setProgress(`${I18N('COLLECTED')} ${e?.r###lts?.length} ${I18N('REWARD')}`, true);
  7449. });
  7450. });
  7451. }
  7452. /**
  7453. * Assemble Outland
  7454. *
  7455. * Собрать запределье
  7456. */
  7457. function getOutland() {
  7458. return new Promise(function (resolve, reject) {
  7459. send('{"calls":[{"name":"bossGetAll","args":{},"ident":"bossGetAll"}]}', e => {
  7460. let bosses = e.r###lts[0].r###lt.response;
  7461. let bossRaidOpenChestCall = {
  7462. calls: []
  7463. };
  7464. for (let boss of bosses) {
  7465. if (boss.mayRaid) {
  7466. bossRaidOpenChestCall.calls.push({
  7467. name: "bossRaid",
  7468. args: {
  7469. bossId: boss.id
  7470. },
  7471. ident: "bossRaid_" + boss.id
  7472. });
  7473. bossRaidOpenChestCall.calls.push({
  7474. name: "bossOpenChest",
  7475. args: {
  7476. bossId: boss.id,
  7477. amount: 1,
  7478. starmoney: 0
  7479. },
  7480. ident: "bossOpenChest_" + boss.id
  7481. });
  7482. } else if (boss.chestId == 1) {
  7483. bossRaidOpenChestCall.calls.push({
  7484. name: "bossOpenChest",
  7485. args: {
  7486. bossId: boss.id,
  7487. amount: 1,
  7488. starmoney: 0
  7489. },
  7490. ident: "bossOpenChest_" + boss.id
  7491. });
  7492. }
  7493. }
  7494. if (!bossRaidOpenChestCall.calls.length) {
  7495. setProgress(`${I18N('OUTLAND')} ${I18N('NOTHING_TO_COLLECT')}`, true);
  7496. resolve();
  7497. return;
  7498. }
  7499. send(JSON.stringify(bossRaidOpenChestCall), e => {
  7500. setProgress(`${I18N('OUTLAND')} ${I18N('COLLECTED')}`, true);
  7501. resolve();
  7502. });
  7503. });
  7504. });
  7505. }
  7506. /**
  7507. * Collect all rewards
  7508. *
  7509. * Собрать все награды
  7510. */
  7511. function questAllFarm() {
  7512. return new Promise(function (resolve, reject) {
  7513. let questGetAllCall = {
  7514. calls: [{
  7515. name: "questGetAll",
  7516. args: {},
  7517. ident: "body"
  7518. }]
  7519. }
  7520. send(JSON.stringify(questGetAllCall), function (data) {
  7521. let questGetAll = data.r###lts[0].r###lt.response;
  7522. const questAllFarmCall = {
  7523. calls: []
  7524. }
  7525. let number = 0;
  7526. for (let quest of questGetAll) {
  7527. if (quest.id < 1e6 && quest.state == 2) {
  7528. questAllFarmCall.calls.push({
  7529. name: "questFarm",
  7530. args: {
  7531. questId: quest.id
  7532. },
  7533. ident: `group_${number}_body`
  7534. });
  7535. number++;
  7536. }
  7537. }
  7538. if (!questAllFarmCall.calls.length) {
  7539. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  7540. resolve();
  7541. return;
  7542. }
  7543. send(JSON.stringify(questAllFarmCall), function (res) {
  7544. console.log(res);
  7545. setProgress(`${I18N('COLLECTED')} ${number} ${I18N('REWARD')}`, true);
  7546. resolve();
  7547. });
  7548. });
  7549. })
  7550. }
  7551. /**
  7552. * Mission auto repeat
  7553. *
  7554. * Автоповтор миссии
  7555. * isStopSendMission = false;
  7556. * isSendsMission = true;
  7557. **/
  7558. this.sendsMission = async function (param) {
  7559. if (isStopSendMission) {
  7560. isSendsMission = false;
  7561. console.log(I18N('STOPPED'));
  7562. setProgress('');
  7563. await popup.confirm(`${I18N('STOPPED')}<br>${I18N('REPETITIONS')}: ${param.count}`, [{
  7564. msg: 'Ok',
  7565. r###lt: true
  7566. }, ])
  7567. return;
  7568. }
  7569. lastMissionBattleStart = Date.now();
  7570. let missionStartCall = {
  7571. "calls": [{
  7572. "name": "missionStart",
  7573. "args": lastMissionStart,
  7574. "ident": "body"
  7575. }]
  7576. }
  7577. /**
  7578. * Mission Request
  7579. *
  7580. * Запрос на выполнение мисии
  7581. */
  7582. SendRequest(JSON.stringify(missionStartCall), async e => {
  7583. if (e['error']) {
  7584. isSendsMission = false;
  7585. console.log(e['error']);
  7586. setProgress('');
  7587. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  7588. await popup.confirm(msg, [
  7589. {msg: 'Ok', r###lt: true},
  7590. ])
  7591. return;
  7592. }
  7593. /**
  7594. * Mission data calculation
  7595. *
  7596. * Расчет данных мисии
  7597. */
  7598. BattleCalc(e.r###lts[0].r###lt.response, 'get_tower', async r => {
  7599. /** missionTimer */
  7600. let timer = getTimer(r.battleTime) + 5;
  7601. const period = Math.ceil((Date.now() - lastMissionBattleStart) / 1000);
  7602. if (period < timer) {
  7603. timer = timer - period;
  7604. await countdownTimer(timer, `${I18N('MISSIONS_PASSED')}: ${param.count}`);
  7605. }
  7606. let missionEndCall = {
  7607. "calls": [{
  7608. "name": "missionEnd",
  7609. "args": {
  7610. "id": param.id,
  7611. "r###lt": r.r###lt,
  7612. "progress": r.progress
  7613. },
  7614. "ident": "body"
  7615. }]
  7616. }
  7617. /**
  7618. * Mission Completion Request
  7619. *
  7620. * Запрос на завершение миссии
  7621. */
  7622. SendRequest(JSON.stringify(missionEndCall), async (e) => {
  7623. if (e['error']) {
  7624. isSendsMission = false;
  7625. console.log(e['error']);
  7626. setProgress('');
  7627. let msg = e['error'].name + ' ' + e['error'].description + `<br>${I18N('REPETITIONS')}: ${param.count}`;
  7628. await popup.confirm(msg, [
  7629. {msg: 'Ok', r###lt: true},
  7630. ])
  7631. return;
  7632. }
  7633. r = e.r###lts[0].r###lt.response;
  7634. if (r['error']) {
  7635. isSendsMission = false;
  7636. console.log(r['error']);
  7637. setProgress('');
  7638. await popup.confirm(`<br>${I18N('REPETITIONS')}: ${param.count}` + ' 3 ' + r['error'], [
  7639. {msg: 'Ok', r###lt: true},
  7640. ])
  7641. return;
  7642. }
  7643. param.count++;
  7644. setProgress(`${I18N('MISSIONS_PASSED')}: ${param.count} (${I18N('STOP')})`, false, () => {
  7645. isStopSendMission = true;
  7646. });
  7647. setTimeout(sendsMission, 1, param);
  7648. });
  7649. })
  7650. });
  7651. }
  7652. /**
  7653. * Opening of russian dolls
  7654. *
  7655. * Открытие матрешек
  7656. */
  7657. async function openRussianDolls(libId, amount) {
  7658. let sum = 0;
  7659. const sumR###lt = {};
  7660. let count = 0;
  7661. while (amount) {
  7662. sum += amount;
  7663. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`);
  7664. const calls = [
  7665. {
  7666. name: 'consumableUseLootBox',
  7667. args: { libId, amount },
  7668. ident: 'body',
  7669. },
  7670. ];
  7671. const response = await Send(JSON.stringify({ calls })).then((e) => e.r###lts[0].r###lt.response);
  7672. let [countLootBox, r###lt] = Object.entries(response).pop();
  7673. count += +countLootBox;
  7674. let newCount = 0;
  7675. if (r###lt?.consumable && r###lt.consumable[libId]) {
  7676. newCount = r###lt.consumable[libId];
  7677. delete r###lt.consumable[libId];
  7678. }
  7679. mergeItemsObj(sumR###lt, r###lt);
  7680. amount = newCount;
  7681. }
  7682. setProgress(`${I18N('TOTAL_OPEN')} ${sum}`, 5000);
  7683. return [count, sumR###lt];
  7684. }
  7685. function mergeItemsObj(obj1, obj2) {
  7686. for (const key in obj2) {
  7687. if (obj1[key]) {
  7688. if (typeof obj1[key] == 'object') {
  7689. for (const innerKey in obj2[key]) {
  7690. obj1[key][innerKey] = (obj1[key][innerKey] || 0) + obj2[key][innerKey];
  7691. }
  7692. } else {
  7693. obj1[key] += obj2[key] || 0;
  7694. }
  7695. } else {
  7696. obj1[key] = obj2[key];
  7697. }
  7698. }
  7699. return obj1;
  7700. }
  7701. /**
  7702. * Collect all mail, except letters with energy and charges of the portal
  7703. *
  7704. * Собрать всю почту, кроме писем с энергией и зарядами портала
  7705. */
  7706. function mailGetAll() {
  7707. const getMailInfo = '{"calls":[{"name":"mailGetAll","args":{},"ident":"body"}]}';
  7708. return Send(getMailInfo).then(dataMail => {
  7709. const letters = dataMail.r###lts[0].r###lt.response.letters;
  7710. const letterIds = lettersFilter(letters);
  7711. if (!letterIds.length) {
  7712. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  7713. return;
  7714. }
  7715. const calls = [
  7716. { name: "mailFarm", args: { letterIds }, ident: "body" }
  7717. ];
  7718. return Send(JSON.stringify({ calls })).then(res => {
  7719. const lettersIds = res.r###lts[0].r###lt.response;
  7720. if (lettersIds) {
  7721. const countLetters = Object.keys(lettersIds).length;
  7722. setProgress(`${I18N('RECEIVED')} ${countLetters} ${I18N('LETTERS')}`, true);
  7723. }
  7724. });
  7725. });
  7726. }
  7727. /**
  7728. * Filters received emails
  7729. *
  7730. * Фильтрует получаемые письма
  7731. */
  7732. function lettersFilter(letters) {
  7733. const lettersIds = [];
  7734. for (let l in letters) {
  7735. letter = letters[l];
  7736. const reward = letter?.reward;
  7737. if (!reward || !Object.keys(reward).length) {
  7738. continue;
  7739. }
  7740. /**
  7741. * Mail Collection Exceptions
  7742. *
  7743. * Исключения на сбор писем
  7744. */
  7745. const isFarmLetter = !(
  7746. /** Portals // сферы портала */
  7747. (reward?.refillable ? reward.refillable[45] : false) ||
  7748. /** Energy // энергия */
  7749. (reward?.stamina ? reward.stamina : false) ||
  7750. /** accelerating energy gain // ускорение набора энергии */
  7751. (reward?.buff ? true : false) ||
  7752. /** VIP Points // вип очки */
  7753. (reward?.vipPoints ? reward.vipPoints : false) ||
  7754. /** souls of heroes // душы героев */
  7755. (reward?.fragmentHero ? true : false) ||
  7756. /** heroes // герои */
  7757. (reward?.bundleHeroReward ? true : false)
  7758. );
  7759. if (isFarmLetter) {
  7760. lettersIds.push(~~letter.id);
  7761. continue;
  7762. }
  7763. /**
  7764. * Если до окончания годности письма менее 24 часов,
  7765. * то оно собирается не смотря на исключения
  7766. */
  7767. const availableUntil = +letter?.availableUntil;
  7768. if (availableUntil) {
  7769. const maxTimeLeft = 24 * 60 * 60 * 1000;
  7770. const timeLeft = (new Date(availableUntil * 1000) - new Date())
  7771. console.log('Time left:', timeLeft)
  7772. if (timeLeft < maxTimeLeft) {
  7773. lettersIds.push(~~letter.id);
  7774. continue;
  7775. }
  7776. }
  7777. }
  7778. return lettersIds;
  7779. }
  7780. /**
  7781. * Displaying information about the areas of the portal and attempts on the VG
  7782. *
  7783. * Отображение информации о сферах портала и попытках на ВГ
  7784. */
  7785. async function justInfo() {
  7786. return new Promise(async (resolve, reject) => {
  7787. const calls = [
  7788. {
  7789. name: 'userGetInfo',
  7790. args: {},
  7791. ident: 'userGetInfo',
  7792. },
  7793. {
  7794. name: 'clanWarGetInfo',
  7795. args: {},
  7796. ident: 'clanWarGetInfo',
  7797. },
  7798. {
  7799. name: 'titanArenaGetStatus',
  7800. args: {},
  7801. ident: 'titanArenaGetStatus',
  7802. },
  7803. {
  7804. name: 'quest_completeEasterEggQuest',
  7805. args: {},
  7806. ident: 'quest_completeEasterEggQuest',
  7807. },
  7808. ];
  7809. const r###lt = await Send(JSON.stringify({ calls }));
  7810. const infos = r###lt.r###lts;
  7811. const portalSphere = infos[0].r###lt.response.refillable.find(n => n.id == 45);
  7812. const clanWarMyTries = infos[1].r###lt.response?.myTries ?? 0;
  7813. const arePointsMax = infos[1].r###lt.response?.arePointsMax;
  7814. const titansLevel = +(infos[2].r###lt.response?.tier ?? 0);
  7815. const titansStatus = infos[2].r###lt.response?.status; //peace_time || battle
  7816. const sanctuaryButton = buttons['testAdventure'].button;
  7817. const sanctuaryDot = sanctuaryButton.querySelector('.scriptMenu_dot');
  7818. const clanWarButton = buttons['goToClanWar'].button;
  7819. const clanWarDot = clanWarButton.querySelector('.scriptMenu_dot');
  7820. const titansArenaButton = buttons['testTitanArena'].button;
  7821. const titansArenaDot = titansArenaButton.querySelector('.scriptMenu_dot');
  7822. if (portalSphere.amount) {
  7823. sanctuaryButton.classList.add('scriptMenu_attention');
  7824. sanctuaryDot.title = `${portalSphere.amount} ${I18N('PORTALS')}`;
  7825. sanctuaryDot.innerText = portalSphere.amount;
  7826. sanctuaryDot.style.backgroundColor = 'red';
  7827. } else {
  7828. sanctuaryButton.classList.remove('scriptMenu_attention');
  7829. }
  7830. if (clanWarMyTries && !arePointsMax) {
  7831. clanWarButton.classList.add('scriptMenu_attention');
  7832. clanWarDot.title = `${clanWarMyTries} ${I18N('ATTEMPTS')}`;
  7833. clanWarDot.innerText = clanWarMyTries;
  7834. clanWarDot.style.backgroundColor = 'red';
  7835. } else {
  7836. clanWarButton.classList.remove('scriptMenu_attention');
  7837. }
  7838. if (titansLevel < 7 && titansStatus == 'battle') { ;
  7839. titansArenaButton.classList.add('scriptMenu_attention');
  7840. titansArenaDot.title = `${titansLevel} ${I18N('LEVEL')}`;
  7841. titansArenaDot.innerText = titansLevel;
  7842. titansArenaDot.style.backgroundColor = 'red';
  7843. } else {
  7844. titansArenaButton.classList.remove('scriptMenu_attention');
  7845. }
  7846. const imgPortal =
  7847. '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/xNihvr8Ix4sdCCrJja47CVAMFjAwid6eJcQWi8BO4jHQl6AGFjdwwUnOMF75CfCMpoxCTpAoxoZMBgs3qMh7ZODQFYYxgSMsQTh###K0BiZJNxBCZ7zwhsbYqO3wCoe7AjjCaxAggNUcY94mcDa3qMECWSBHYN0CBfj0IQliEFCMFjkIulAAisUkBZYyB4USxAFCZnkH1xsgltSYCMYyACMpizghS7kOTZIKJMmeYEZzCCH6iCmBS1IRzpkcEsXVMGZMMgHJvfwyoLsYQ9nmMIUuDAFPIAhH8pUZjLbcY89rKKaC9nDFeLxy3vkYwbJTMcL0InOeOSjBVShJz2pqQvPfvrznwANKEMCAgA7';
  7848. setProgress('<img src="' + imgPortal + '" style="height: 25px;position: relative;top: 5px;"> ' + `${portalSphere.amount} </br> ${I18N('GUILD_WAR')}: ${clanWarMyTries}`, true);
  7849. resolve();
  7850. });
  7851. }
  7852. async function getDailyBonus() {
  7853. const dailyBonusInfo = await Send(JSON.stringify({
  7854. calls: [{
  7855. name: "dailyBonusGetInfo",
  7856. args: {},
  7857. ident: "body"
  7858. }]
  7859. })).then(e => e.r###lts[0].r###lt.response);
  7860. const { availableToday, availableVip, currentDay } = dailyBonusInfo;
  7861. if (!availableToday) {
  7862. console.log('Уже собрано');
  7863. return;
  7864. }
  7865. const currentVipPoints = +userInfo.vipPoints;
  7866. const dailyBonusStat = lib.getData('dailyBonusStatic');
  7867. const vipInfo = lib.getData('level').vip;
  7868. let currentVipLevel = 0;
  7869. for (let i in vipInfo) {
  7870. vipLvl = vipInfo[i];
  7871. if (currentVipPoints >= vipLvl.vipPoints) {
  7872. currentVipLevel = vipLvl.level;
  7873. }
  7874. }
  7875. const vipLevelDouble = dailyBonusStat[`${currentDay}_0_0`].vipLevelDouble;
  7876. const calls = [{
  7877. name: "dailyBonusFarm",
  7878. args: {
  7879. vip: availableVip && currentVipLevel >= vipLevelDouble ? 1 : 0
  7880. },
  7881. ident: "body"
  7882. }];
  7883. const r###lt = await Send(JSON.stringify({ calls }));
  7884. if (r###lt.error) {
  7885. console.error(r###lt.error);
  7886. return;
  7887. }
  7888. const reward = r###lt.r###lts[0].r###lt.response;
  7889. const type = Object.keys(reward).pop();
  7890. const itemId = Object.keys(reward[type]).pop();
  7891. const count = reward[type][itemId];
  7892. const itemName = cheats.translate(`LIB_${type.toUpperCase()}_NAME_${itemId}`);
  7893. console.log(`Ежедневная награда: Получено ${count} ${itemName}`, reward);
  7894. }
  7895. async function farmStamina(lootBoxId = 148) {
  7896. const lootBox = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"}]}')
  7897. .then(e => e.r###lts[0].r###lt.response.consumable[148]);
  7898. /** Добавить другие ящики */
  7899. /**
  7900. * 144 - медная шкатулка
  7901. * 145 - бронзовая шкатулка
  7902. * 148 - платиновая шкатулка
  7903. */
  7904. if (!lootBox) {
  7905. setProgress(I18N('NO_BOXES'), true);
  7906. return;
  7907. }
  7908. let maxFarmEnergy = getSaveVal('maxFarmEnergy', 100);
  7909. const r###lt = await popup.confirm(I18N('OPEN_LOOTBOX', { lootBox }), [
  7910. { r###lt: false, isClose: true },
  7911. { msg: I18N('BTN_YES'), r###lt: true },
  7912. { msg: I18N('STAMINA'), isInput: true, default: maxFarmEnergy },
  7913. ]);
  7914. if (!+r###lt) {
  7915. return;
  7916. }
  7917. if ((typeof r###lt) !== 'boolean' && Number.parseInt(r###lt)) {
  7918. maxFarmEnergy = +r###lt;
  7919. setSaveVal('maxFarmEnergy', maxFarmEnergy);
  7920. } else {
  7921. maxFarmEnergy = 0;
  7922. }
  7923. let collectEnergy = 0;
  7924. for (let count = lootBox; count > 0; count--) {
  7925. const response = await Send('{"calls":[{"name":"consumableUseLootBox","args":{"libId":148,"amount":1},"ident":"body"}]}').then(
  7926. (e) => e.r###lts[0].r###lt.response
  7927. );
  7928. const r###lt = Object.values(response).pop();
  7929. if ('stamina' in r###lt) {
  7930. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox} ${I18N('STAMINA')} +${r###lt.stamina}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  7931. console.log(`${ I18N('STAMINA') } + ${ r###lt.stamina }`);
  7932. if (!maxFarmEnergy) {
  7933. return;
  7934. }
  7935. collectEnergy += +r###lt.stamina;
  7936. if (collectEnergy >= maxFarmEnergy) {
  7937. console.log(`${I18N('STAMINA')} + ${ collectEnergy }`);
  7938. setProgress(`${I18N('STAMINA')} + ${ collectEnergy }`, false);
  7939. return;
  7940. }
  7941. } else {
  7942. setProgress(`${I18N('OPEN')}: ${lootBox - count}/${lootBox}<br>${I18N('STAMINA')}: ${collectEnergy}`, false);
  7943. console.log(r###lt);
  7944. }
  7945. }
  7946. setProgress(I18N('BOXES_OVER'), true);
  7947. }
  7948. async function fillActive() {
  7949. const data = await Send(JSON.stringify({
  7950. calls: [{
  7951. name: "questGetAll",
  7952. args: {},
  7953. ident: "questGetAll"
  7954. }, {
  7955. name: "inventoryGet",
  7956. args: {},
  7957. ident: "inventoryGet"
  7958. }, {
  7959. name: "clanGetInfo",
  7960. args: {},
  7961. ident: "clanGetInfo"
  7962. }
  7963. ]
  7964. })).then(e => e.r###lts.map(n => n.r###lt.response));
  7965. const quests = data[0];
  7966. const inv = data[1];
  7967. const stat = data[2].stat;
  7968. const maxActive = 2000 - stat.todayItemsActivity;
  7969. if (maxActive <= 0) {
  7970. setProgress(I18N('NO_MORE_ACTIVITY'), true);
  7971. return;
  7972. }
  7973. let countGetActive = 0;
  7974. const quest = quests.find(e => e.id > 10046 && e.id < 10051);
  7975. if (quest) {
  7976. countGetActive = 1750 - quest.progress;
  7977. }
  7978. if (countGetActive <= 0) {
  7979. countGetActive = maxActive;
  7980. }
  7981. console.log(countGetActive);
  7982. countGetActive = +(await popup.confirm(I18N('EXCHANGE_ITEMS', { maxActive }), [
  7983. { r###lt: false, isClose: true },
  7984. { msg: I18N('GET_ACTIVITY'), isInput: true, default: countGetActive.toString() },
  7985. ]));
  7986. if (!countGetActive) {
  7987. return;
  7988. }
  7989. if (countGetActive > maxActive) {
  7990. countGetActive = maxActive;
  7991. }
  7992. const items = lib.getData('inventoryItem');
  7993. let itemsInfo = [];
  7994. for (let type of ['gear', 'scroll']) {
  7995. for (let i in inv[type]) {
  7996. const v = items[type][i]?.enchantValue || 0;
  7997. itemsInfo.push({
  7998. id: i,
  7999. count: inv[type][i],
  8000. v,
  8001. type
  8002. })
  8003. }
  8004. const invType = 'fragment' + type.toLowerCase().charAt(0).toUpperCase() + type.slice(1);
  8005. for (let i in inv[invType]) {
  8006. const v = items[type][i]?.fragmentEnchantValue || 0;
  8007. itemsInfo.push({
  8008. id: i,
  8009. count: inv[invType][i],
  8010. v,
  8011. type: invType
  8012. })
  8013. }
  8014. }
  8015. itemsInfo = itemsInfo.filter(e => e.v < 4 && e.count > 200);
  8016. itemsInfo = itemsInfo.sort((a, b) => b.count - a.count);
  8017. console.log(itemsInfo);
  8018. const activeItem = itemsInfo.shift();
  8019. console.log(activeItem);
  8020. const countItem = Math.ceil(countGetActive / activeItem.v);
  8021. if (countItem > activeItem.count) {
  8022. setProgress(I18N('NOT_ENOUGH_ITEMS'), true);
  8023. console.log(activeItem);
  8024. return;
  8025. }
  8026. await Send(JSON.stringify({
  8027. calls: [{
  8028. name: "clanItemsForActivity",
  8029. args: {
  8030. items: {
  8031. [activeItem.type]: {
  8032. [activeItem.id]: countItem
  8033. }
  8034. }
  8035. },
  8036. ident: "body"
  8037. }]
  8038. })).then(e => {
  8039. /** TODO: Вывести потраченые предметы */
  8040. console.log(e);
  8041. setProgress(`${I18N('ACTIVITY_RECEIVED')}: ` + e.r###lts[0].r###lt.response, true);
  8042. });
  8043. }
  8044. async function buyHeroFragments() {
  8045. const r###lt = await Send('{"calls":[{"name":"inventoryGet","args":{},"ident":"inventoryGet"},{"name":"shopGetAll","args":{},"ident":"shopGetAll"}]}')
  8046. .then(e => e.r###lts.map(n => n.r###lt.response));
  8047. const inv = r###lt[0];
  8048. const shops = Object.values(r###lt[1]).filter(shop => [4, 5, 6, 8, 9, 10, 17].includes(shop.id));
  8049. const calls = [];
  8050. for (let shop of shops) {
  8051. const slots = Object.values(shop.slots);
  8052. for (const slot of slots) {
  8053. /* Уже куплено */
  8054. if (slot.bought) {
  8055. continue;
  8056. }
  8057. /* Не душа героя */
  8058. if (!('fragmentHero' in slot.reward)) {
  8059. continue;
  8060. }
  8061. const coin = Object.keys(slot.cost).pop();
  8062. const coinId = Object.keys(slot.cost[coin]).pop();
  8063. const stock = inv[coin][coinId] || 0;
  8064. /* Не хватает на покупку */
  8065. if (slot.cost[coin][coinId] > stock) {
  8066. continue;
  8067. }
  8068. inv[coin][coinId] -= slot.cost[coin][coinId];
  8069. calls.push({
  8070. name: "shopBuy",
  8071. args: {
  8072. shopId: shop.id,
  8073. slot: slot.id,
  8074. cost: slot.cost,
  8075. reward: slot.reward,
  8076. },
  8077. ident: `shopBuy_${shop.id}_${slot.id}`,
  8078. })
  8079. }
  8080. }
  8081. if (!calls.length) {
  8082. setProgress(I18N('NO_PURCHASABLE_HERO_SOULS'), true);
  8083. return;
  8084. }
  8085. const bought = await Send(JSON.stringify({ calls })).then(e => e.r###lts.map(n => n.r###lt.response));
  8086. if (!bought) {
  8087. console.log('что-то пошло не так')
  8088. return;
  8089. }
  8090. let countHeroSouls = 0;
  8091. for (const buy of bought) {
  8092. countHeroSouls += +Object.values(Object.values(buy).pop()).pop();
  8093. }
  8094. console.log(countHeroSouls, bought, calls);
  8095. setProgress(I18N('PURCHASED_HERO_SOULS', { countHeroSouls }), true);
  8096. }
  8097. /** Открыть платные сундуки в Запределье за 90 */
  8098. async function bossOpenChestPay() {
  8099. const callsNames = ['userGetInfo', 'bossGetAll', 'specialOffer_getAll', 'getTime'];
  8100. const info = await Send({ calls: callsNames.map((name) => ({ name, args: {}, ident: name })) }).then((e) =>
  8101. e.r###lts.map((n) => n.r###lt.response)
  8102. );
  8103. const user = info[0];
  8104. const boses = info[1];
  8105. const offers = info[2];
  8106. const time = info[3];
  8107. const discountOffer = offers.find((e) => e.offerType == 'costReplaceOutlandChest');
  8108. let discount = 1;
  8109. if (discountOffer && discountOffer.endTime > time) {
  8110. discount = 1 - discountOffer.offerData.outlandChest.discountPercent / 100;
  8111. }
  8112. cost9chests = 540 * discount;
  8113. cost18chests = 1740 * discount;
  8114. costFirstChest = 90 * discount;
  8115. costSecondChest = 200 * discount;
  8116. const currentStarMoney = user.starMoney;
  8117. if (currentStarMoney < cost9chests) {
  8118. setProgress('Недостаточно изюма, нужно ' + cost9chests + ' у Вас ' + currentStarMoney, true);
  8119. return;
  8120. }
  8121. const imgEmerald =
  8122. "<img style='position: relative;top: 3px;' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAXCAYAAAD+4+QTAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAY8SURBVEhLpVV5bFVlFv/d7a19W3tfN1pKabGFAm3Rlg4toAWRiH+AioiaqAkaE42NycRR0ZnomJnJYHAJERGNyx/GJYoboo2igKVSMUUKreW1pRvUvr7XvvXe9+7qeW1nGJaJycwvObnny/fl/L7zO+c7l8EV0LAKzA+H83lAFAC/BeDJN2gnc5yd/WaQ8Q0NCCnAANkU+ZfjIpKqJWBOd4EDbHagueBPb1tWuesi9Rqn86zJZDbAMTp4xo###Maa4FVe6fra3bbzQbYN6A8Cmrz0qoBx8gzMmaj/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/dDyMzfIAj3bqSK8bGW579ECPWXRViHTijDK2BPoj###xkbXCZflh1H5ISkCCSWJxI8jcjmErhnaHh6fdzdbZTd0aKd7Q+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='>";
  8123. if (currentStarMoney < cost9chests) {
  8124. setProgress(I18N('NOT_ENOUGH_EMERALDS_540', { currentStarMoney, imgEmerald }), true);
  8125. return;
  8126. }
  8127. const buttons = [{ r###lt: false, isClose: true }];
  8128. if (currentStarMoney >= cost9chests) {
  8129. buttons.push({
  8130. msg: I18N('BUY_OUTLAND_BTN', { count: 9, countEmerald: cost9chests, imgEmerald }),
  8131. r###lt: [costFirstChest, costFirstChest, 0],
  8132. });
  8133. }
  8134. if (currentStarMoney >= cost18chests) {
  8135. buttons.push({
  8136. msg: I18N('BUY_OUTLAND_BTN', { count: 18, countEmerald: cost18chests, imgEmerald }),
  8137. r###lt: [costFirstChest, costFirstChest, 0, costSecondChest, costSecondChest, 0],
  8138. });
  8139. }
  8140. const answer = await popup.confirm(`<div style="margin-bottom: 15px;">${I18N('BUY_OUTLAND')}</div>`, buttons);
  8141. if (!answer) {
  8142. return;
  8143. }
  8144. const callBoss = [];
  8145. let n = 0;
  8146. for (let boss of boses) {
  8147. const bossId = boss.id;
  8148. if (boss.chestNum != 2) {
  8149. continue;
  8150. }
  8151. const calls = [];
  8152. for (const starmoney of answer) {
  8153. calls.push({
  8154. name: 'bossOpenChest',
  8155. args: {
  8156. amount: 1,
  8157. bossId,
  8158. starmoney,
  8159. },
  8160. ident: 'bossOpenChest_' + ++n,
  8161. });
  8162. }
  8163. callBoss.push(calls);
  8164. }
  8165. if (!callBoss.length) {
  8166. setProgress(I18N('CHESTS_NOT_AVAILABLE'), true);
  8167. return;
  8168. }
  8169. let count = 0;
  8170. let errors = 0;
  8171. for (const calls of callBoss) {
  8172. const r###lt = await Send({ calls });
  8173. console.log(r###lt);
  8174. if (r###lt?.r###lts) {
  8175. count += r###lt.r###lts.length;
  8176. } else {
  8177. errors++;
  8178. }
  8179. }
  8180. setProgress(`${I18N('OUTLAND_CHESTS_RECEIVED')}: ${count}`, true);
  8181. }
  8182. async function autoRaidAdventure() {
  8183. const calls = [
  8184. {
  8185. name: "userGetInfo",
  8186. args: {},
  8187. ident: "userGetInfo"
  8188. },
  8189. {
  8190. name: "adventure_raidGetInfo",
  8191. args: {},
  8192. ident: "adventure_raidGetInfo"
  8193. }
  8194. ];
  8195. const r###lt = await Send(JSON.stringify({ calls }))
  8196. .then(e => e.r###lts.map(n => n.r###lt.response));
  8197. const portalSphere = r###lt[0].refillable.find(n => n.id == 45);
  8198. const adventureRaid = Object.entries(r###lt[1].raid).filter(e => e[1]).pop()
  8199. const adventureId = adventureRaid ? adventureRaid[0] : 0;
  8200. if (!portalSphere.amount || !adventureId) {
  8201. setProgress(I18N('RAID_NOT_AVAILABLE'), true);
  8202. return;
  8203. }
  8204. const countRaid = +(await popup.confirm(I18N('RAID_ADVENTURE', { adventureId }), [
  8205. { r###lt: false, isClose: true },
  8206. { msg: I18N('RAID'), isInput: true, default: portalSphere.amount },
  8207. ]));
  8208. if (!countRaid) {
  8209. return;
  8210. }
  8211. if (countRaid > portalSphere.amount) {
  8212. countRaid = portalSphere.amount;
  8213. }
  8214. const r###ltRaid = await Send(JSON.stringify({
  8215. calls: [...Array(countRaid)].map((e, i) => ({
  8216. name: "adventure_raid",
  8217. args: {
  8218. adventureId
  8219. },
  8220. ident: `body_${i}`
  8221. }))
  8222. })).then(e => e.r###lts.map(n => n.r###lt.response));
  8223. if (!r###ltRaid.length) {
  8224. console.log(r###ltRaid);
  8225. setProgress(I18N('SOMETHING_WENT_WRONG'), true);
  8226. return;
  8227. }
  8228. console.log(r###ltRaid, adventureId, portalSphere.amount);
  8229. setProgress(I18N('ADVENTURE_COMPLETED', { adventureId, times: r###ltRaid.length }), true);
  8230. }
  8231. /** Вывести всю клановую статистику в консоль браузера */
  8232. async function clanStatistic() {
  8233. const copy = function (text) {
  8234. const copyTextarea = document.createElement("textarea");
  8235. copyTextarea.style.opacity = "0";
  8236. copyTextarea.textContent = text;
  8237. document.body.appendChild(copyTextarea);
  8238. copyTextarea.select();
  8239. document.execCommand("copy");
  8240. document.body.removeChild(copyTextarea);
  8241. delete copyTextarea;
  8242. }
  8243. const calls = [
  8244. { name: "clanGetInfo", args: {}, ident: "clanGetInfo" },
  8245. { name: "clanGetWeeklyStat", args: {}, ident: "clanGetWeeklyStat" },
  8246. { name: "clanGetLog", args: {}, ident: "clanGetLog" },
  8247. ];
  8248. const r###lt = await Send(JSON.stringify({ calls }));
  8249. const dataClanInfo = r###lt.r###lts[0].r###lt.response;
  8250. const dataClanStat = r###lt.r###lts[1].r###lt.response;
  8251. const dataClanLog = r###lt.r###lts[2].r###lt.response;
  8252. const membersStat = {};
  8253. for (let i = 0; i < dataClanStat.stat.length; i++) {
  8254. membersStat[dataClanStat.stat[i].id] = dataClanStat.stat[i];
  8255. }
  8256. const joinStat = {};
  8257. historyLog = dataClanLog.history;
  8258. for (let j in historyLog) {
  8259. his = historyLog[j];
  8260. if (his.event == 'join') {
  8261. joinStat[his.userId] = his.ctime;
  8262. }
  8263. }
  8264. const infoArr = [];
  8265. const members = dataClanInfo.clan.members;
  8266. for (let n in members) {
  8267. var member = [
  8268. n,
  8269. members[n].name,
  8270. members[n].level,
  8271. dataClanInfo.clan.warriors.includes(+n) ? 1 : 0,
  8272. (new Date(members[n].lastLoginTime * 1000)).toLocaleString().replace(',', ''),
  8273. joinStat[n] ? (new Date(joinStat[n] * 1000)).toLocaleString().replace(',', '') : '',
  8274. membersStat[n].activity.reverse().join('\t'),
  8275. membersStat[n].adventureStat.reverse().join('\t'),
  8276. membersStat[n].clanGifts.reverse().join('\t'),
  8277. membersStat[n].clanWarStat.reverse().join('\t'),
  8278. membersStat[n].dungeonActivity.reverse().join('\t'),
  8279. ];
  8280. infoArr.push(member);
  8281. }
  8282. const info = infoArr.sort((a, b) => (b[2] - a[2])).map((e) => e.join('\t')).join('\n');
  8283. console.log(info);
  8284. copy(info);
  8285. setProgress(I18N('CLAN_STAT_COPY'), true);
  8286. }
  8287. async function buyInStoreForGold() {
  8288. const r###lt = await Send('{"calls":[{"name":"shopGetAll","args":{},"ident":"body"},{"name":"userGetInfo","args":{},"ident":"userGetInfo"}]}').then(e => e.r###lts.map(n => n.r###lt.response));
  8289. const shops = r###lt[0];
  8290. const user = r###lt[1];
  8291. let gold = user.gold;
  8292. const calls = [];
  8293. if (shops[17]) {
  8294. const slots = shops[17].slots;
  8295. for (let i = 1; i <= 2; i++) {
  8296. if (!slots[i].bought) {
  8297. const costGold = slots[i].cost.gold;
  8298. if ((gold - costGold) < 0) {
  8299. continue;
  8300. }
  8301. gold -= costGold;
  8302. calls.push({
  8303. name: "shopBuy",
  8304. args: {
  8305. shopId: 17,
  8306. slot: i,
  8307. cost: slots[i].cost,
  8308. reward: slots[i].reward,
  8309. },
  8310. ident: 'body_' + i,
  8311. })
  8312. }
  8313. }
  8314. }
  8315. const slots = shops[1].slots;
  8316. for (let i = 4; i <= 6; i++) {
  8317. if (!slots[i].bought && slots[i]?.cost?.gold) {
  8318. const costGold = slots[i].cost.gold;
  8319. if ((gold - costGold) < 0) {
  8320. continue;
  8321. }
  8322. gold -= costGold;
  8323. calls.push({
  8324. name: "shopBuy",
  8325. args: {
  8326. shopId: 1,
  8327. slot: i,
  8328. cost: slots[i].cost,
  8329. reward: slots[i].reward,
  8330. },
  8331. ident: 'body_' + i,
  8332. })
  8333. }
  8334. }
  8335. if (!calls.length) {
  8336. setProgress(I18N('NOTHING_BUY'), true);
  8337. return;
  8338. }
  8339. const r###ltBuy = await Send(JSON.stringify({ calls })).then(e => e.r###lts.map(n => n.r###lt.response));
  8340. console.log(r###ltBuy);
  8341. const countBuy = r###ltBuy.length;
  8342. setProgress(I18N('LOTS_BOUGHT', { countBuy }), true);
  8343. }
  8344. function rewardsAndMailFarm() {
  8345. return new Promise(function (resolve, reject) {
  8346. let questGetAllCall = {
  8347. calls: [{
  8348. name: "questGetAll",
  8349. args: {},
  8350. ident: "questGetAll"
  8351. }, {
  8352. name: "mailGetAll",
  8353. args: {},
  8354. ident: "mailGetAll"
  8355. }]
  8356. }
  8357. send(JSON.stringify(questGetAllCall), function (data) {
  8358. if (!data) return;
  8359. const questGetAll = data.r###lts[0].r###lt.response.filter((e) => e.state == 2);
  8360. const questBattlePass = lib.getData('quest').battlePass;
  8361. const questChainBPass = lib.getData('battlePass').questChain;
  8362. const listBattlePass = lib.getData('battlePass').list;
  8363. const questAllFarmCall = {
  8364. calls: [],
  8365. };
  8366. const questIds = [];
  8367. for (let quest of questGetAll) {
  8368. if (quest.id >= 2001e4) {
  8369. continue;
  8370. }
  8371. if (quest.id > 1e6 && quest.id < 2e7) {
  8372. const questInfo = questBattlePass[quest.id];
  8373. const chain = questChainBPass[questInfo.chain];
  8374. if (chain.requirement?.battlePassTicket) {
  8375. continue;
  8376. }
  8377. const battlePass = listBattlePass[chain.battlePass];
  8378. const startTime = battlePass.startCondition.time.value * 1e3
  8379. const endTime = new Date(startTime + battlePass.duration * 1e3);
  8380. if (startTime > Date.now() || endTime < Date.now()) {
  8381. continue;
  8382. }
  8383. }
  8384. if (quest.id >= 2e7) {
  8385. questIds.push(quest.id);
  8386. continue;
  8387. }
  8388. questAllFarmCall.calls.push({
  8389. name: 'questFarm',
  8390. args: {
  8391. questId: quest.id,
  8392. },
  8393. ident: `questFarm_${quest.id}`,
  8394. });
  8395. }
  8396. if (questIds.length) {
  8397. questAllFarmCall.calls.push({
  8398. name: 'quest_questsFarm',
  8399. args: { questIds },
  8400. ident: 'quest_questsFarm',
  8401. });
  8402. }
  8403. let letters = data?.r###lts[1]?.r###lt?.response?.letters;
  8404. letterIds = lettersFilter(letters);
  8405. if (letterIds.length) {
  8406. questAllFarmCall.calls.push({
  8407. name: 'mailFarm',
  8408. args: { letterIds },
  8409. ident: 'mailFarm',
  8410. });
  8411. }
  8412. if (!questAllFarmCall.calls.length) {
  8413. setProgress(I18N('NOTHING_TO_COLLECT'), true);
  8414. resolve();
  8415. return;
  8416. }
  8417. send(JSON.stringify(questAllFarmCall), async function (res) {
  8418. let countQuests = 0;
  8419. let countMail = 0;
  8420. let questsIds = [];
  8421. for (let call of res.r###lts) {
  8422. if (call.ident.includes('questFarm')) {
  8423. countQuests++;
  8424. } else if (call.ident.includes('questsFarm')) {
  8425. countQuests += Object.keys(call.r###lt.response).length;
  8426. } else if (call.ident.includes('mailFarm')) {
  8427. countMail = Object.keys(call.r###lt.response).length;
  8428. }
  8429. const newQuests = call.r###lt.newQuests;
  8430. if (newQuests) {
  8431. for (let quest of newQuests) {
  8432. if ((quest.id < 1e6 || (quest.id >= 2e7 && quest.id < 2001e4)) && quest.state == 2) {
  8433. questsIds.push(quest.id);
  8434. }
  8435. }
  8436. }
  8437. }
  8438. while (questsIds.length) {
  8439. const questIds = [];
  8440. const calls = [];
  8441. for (let questId of questsIds) {
  8442. if (questId < 1e6) {
  8443. calls.push({
  8444. name: 'questFarm',
  8445. args: {
  8446. questId,
  8447. },
  8448. ident: `questFarm_${questId}`,
  8449. });
  8450. countQuests++;
  8451. } else if (questId >= 2e7 && questId < 2001e4) {
  8452. questIds.push(questId);
  8453. countQuests++;
  8454. }
  8455. }
  8456. calls.push({
  8457. name: 'quest_questsFarm',
  8458. args: { questIds },
  8459. ident: 'body',
  8460. });
  8461. const r###lts = await Send({ calls }).then((e) => e.r###lts.map((e) => e.r###lt));
  8462. questsIds = [];
  8463. for (const r###lt of r###lts) {
  8464. const newQuests = r###lt.newQuests;
  8465. if (newQuests) {
  8466. for (let quest of newQuests) {
  8467. if (quest.state == 2) {
  8468. questsIds.push(quest.id);
  8469. }
  8470. }
  8471. }
  8472. }
  8473. }
  8474. setProgress(I18N('COLLECT_REWARDS_AND_MAIL', { countQuests, countMail }), true);
  8475. resolve();
  8476. });
  8477. });
  8478. })
  8479. }
  8480. class epicBrawl {
  8481. timeout = null;
  8482. time = null;
  8483. constructor() {
  8484. if (epicBrawl.inst) {
  8485. return epicBrawl.inst;
  8486. }
  8487. epicBrawl.inst = this;
  8488. return this;
  8489. }
  8490. runTimeout(func, timeDiff) {
  8491. const worker = new Worker(URL.createObjectURL(new Blob([`
  8492. self.onmessage = function(e) {
  8493. const timeDiff = e.data;
  8494. if (timeDiff > 0) {
  8495. setTimeout(() => {
  8496. self.postMessage(1);
  8497. self.close();
  8498. }, timeDiff);
  8499. }
  8500. };
  8501. `])));
  8502. worker.postMessage(timeDiff);
  8503. worker.onmessage = () => {
  8504. func();
  8505. };
  8506. return true;
  8507. }
  8508. timeDiff(date1, date2) {
  8509. const date1Obj = new Date(date1);
  8510. const date2Obj = new Date(date2);
  8511. const timeDiff = Math.abs(date2Obj - date1Obj);
  8512. const totalSeconds = timeDiff / 1000;
  8513. const minutes = Math.floor(totalSeconds / 60);
  8514. const seconds = Math.floor(totalSeconds % 60);
  8515. const formattedMinutes = String(minutes).padStart(2, '0');
  8516. const formattedSeconds = String(seconds).padStart(2, '0');
  8517. return `${formattedMinutes}:${formattedSeconds}`;
  8518. }
  8519. check() {
  8520. console.log(new Date(this.time))
  8521. if (Date.now() > this.time) {
  8522. this.timeout = null;
  8523. this.start()
  8524. return;
  8525. }
  8526. this.timeout = this.runTimeout(() => this.check(), 6e4);
  8527. return this.timeDiff(this.time, Date.now())
  8528. }
  8529. async start() {
  8530. if (this.timeout) {
  8531. const time = this.timeDiff(this.time, Date.now());
  8532. console.log(new Date(this.time))
  8533. setProgress(I18N('TIMER_ALREADY', { time }), false, hideProgress);
  8534. return;
  8535. }
  8536. setProgress(I18N('EPIC_BRAWL'), false, hideProgress);
  8537. const teamInfo = await Send('{"calls":[{"name":"teamGetAll","args":{},"ident":"teamGetAll"},{"name":"teamGetFavor","args":{},"ident":"teamGetFavor"},{"name":"userGetInfo","args":{},"ident":"userGetInfo"}]}').then(e => e.r###lts.map(n => n.r###lt.response));
  8538. const refill = teamInfo[2].refillable.find(n => n.id == 52)
  8539. this.time = (refill.lastRefill + 3600) * 1000
  8540. const attempts = refill.amount;
  8541. if (!attempts) {
  8542. console.log(new Date(this.time));
  8543. const time = this.check();
  8544. setProgress(I18N('NO_ATTEMPTS_TIMER_START', { time }), false, hideProgress);
  8545. return;
  8546. }
  8547. if (!teamInfo[0].epic_brawl) {
  8548. setProgress(I18N('NO_HEROES_PACK'), false, hideProgress);
  8549. return;
  8550. }
  8551. const args = {
  8552. heroes: teamInfo[0].epic_brawl.filter(e => e < 1000),
  8553. pet: teamInfo[0].epic_brawl.filter(e => e > 6000).pop(),
  8554. favor: teamInfo[1].epic_brawl,
  8555. }
  8556. let wins = 0;
  8557. let coins = 0;
  8558. let streak = { progress: 0, nextStage: 0 };
  8559. for (let i = attempts; i > 0; i--) {
  8560. const info = await Send(JSON.stringify({
  8561. calls: [
  8562. { name: "epicBrawl_getEnemy", args: {}, ident: "epicBrawl_getEnemy" }, { name: "epicBrawl_startBattle", args, ident: "epicBrawl_startBattle" }
  8563. ]
  8564. })).then(e => e.r###lts.map(n => n.r###lt.response));
  8565. const { progress, r###lt } = await Calc(info[1].battle);
  8566. const endR###lt = await Send(JSON.stringify({ calls: [{ name: "epicBrawl_endBattle", args: { progress, r###lt }, ident: "epicBrawl_endBattle" }, { name: "epicBrawl_getWinStreak", args: {}, ident: "epicBrawl_getWinStreak" }] })).then(e => e.r###lts.map(n => n.r###lt.response));
  8567. const r###ltInfo = endR###lt[0].r###lt;
  8568. streak = endR###lt[1];
  8569. wins += r###ltInfo.win;
  8570. coins += r###ltInfo.reward ? r###ltInfo.reward.coin[39] : 0;
  8571. console.log(endR###lt[0].r###lt)
  8572. if (endR###lt[1].progress == endR###lt[1].nextStage) {
  8573. const farm = await Send('{"calls":[{"name":"epicBrawl_farmWinStreak","args":{},"ident":"body"}]}').then(e => e.r###lts[0].r###lt.response);
  8574. coins += farm.coin[39];
  8575. }
  8576. setProgress(I18N('EPIC_BRAWL_R###LT', {
  8577. i, wins, attempts, coins,
  8578. progress: streak.progress,
  8579. nextStage: streak.nextStage,
  8580. end: '',
  8581. }), false, hideProgress);
  8582. }
  8583. console.log(new Date(this.time));
  8584. const time = this.check();
  8585. setProgress(I18N('EPIC_BRAWL_R###LT', {
  8586. wins, attempts, coins,
  8587. i: '',
  8588. progress: streak.progress,
  8589. nextStage: streak.nextStage,
  8590. end: I18N('ATTEMPT_ENDED', { time }),
  8591. }), false, hideProgress);
  8592. }
  8593. }
  8594. function countdownTimer(seconds, message) {
  8595. message = message || I18N('TIMER');
  8596. const stopTimer = Date.now() + seconds * 1e3
  8597. return new Promise(resolve => {
  8598. const interval = setInterval(async () => {
  8599. const now = Date.now();
  8600. setProgress(`${message} ${((stopTimer - now) / 1000).toFixed(2)}`, false);
  8601. if (now > stopTimer) {
  8602. clearInterval(interval);
  8603. setProgress('', 1);
  8604. resolve();
  8605. }
  8606. }, 100);
  8607. });
  8608. }
  8609. this.HWHFuncs.countdownTimer = countdownTimer;
  8610. /** Набить килов в горниле душк */
  8611. async function bossRatingEventSouls() {
  8612. const data = await Send({
  8613. calls: [
  8614. { name: "heroGetAll", args: {}, ident: "teamGetAll" },
  8615. { name: "offerGetAll", args: {}, ident: "offerGetAll" },
  8616. { name: "pet_getAll", args: {}, ident: "pet_getAll" },
  8617. ]
  8618. });
  8619. const bossEventInfo = data.r###lts[1].r###lt.response.find(e => e.offerType == "bossEvent");
  8620. if (!bossEventInfo) {
  8621. setProgress('Эвент завершен', true);
  8622. return;
  8623. }
  8624. if (bossEventInfo.progress.score > 250) {
  8625. setProgress('Уже убито больше 250 врагов');
  8626. rewardBossRatingEventSouls();
  8627. return;
  8628. }
  8629. const availablePets = Object.values(data.r###lts[2].r###lt.response).map(e => e.id);
  8630. const heroGetAllList = data.r###lts[0].r###lt.response;
  8631. const usedHeroes = bossEventInfo.progress.usedHeroes;
  8632. const heroList = [];
  8633. for (let heroId in heroGetAllList) {
  8634. let hero = heroGetAllList[heroId];
  8635. if (usedHeroes.includes(hero.id)) {
  8636. continue;
  8637. }
  8638. heroList.push(hero.id);
  8639. }
  8640. if (!heroList.length) {
  8641. setProgress('Нет героев', true);
  8642. return;
  8643. }
  8644. const pet = availablePets.includes(6005) ? 6005 : availablePets[Math.floor(Math.random() * availablePets.length)];
  8645. const petLib = lib.getData('pet');
  8646. let count = 1;
  8647. for (const heroId of heroList) {
  8648. const args = {
  8649. heroes: [heroId],
  8650. pet
  8651. }
  8652. /** Поиск питомца для героя */
  8653. for (const petId of availablePets) {
  8654. if (petLib[petId].favorHeroes.includes(heroId)) {
  8655. args.favor = {
  8656. [heroId]: petId
  8657. }
  8658. break;
  8659. }
  8660. }
  8661. const calls = [{
  8662. name: "bossRatingEvent_startBattle",
  8663. args,
  8664. ident: "body"
  8665. }, {
  8666. name: "offerGetAll",
  8667. args: {},
  8668. ident: "offerGetAll"
  8669. }];
  8670. const res = await Send({ calls });
  8671. count++;
  8672. if ('error' in res) {
  8673. console.error(res.error);
  8674. setProgress('Перезагрузите игру и попробуйте позже', true);
  8675. return;
  8676. }
  8677. const eventInfo = res.r###lts[1].r###lt.response.find(e => e.offerType == "bossEvent");
  8678. if (eventInfo.progress.score > 250) {
  8679. break;
  8680. }
  8681. setProgress('Количество убитых врагов: ' + eventInfo.progress.score + '<br>Использовано ' + count + ' героев');
  8682. }
  8683. rewardBossRatingEventSouls();
  8684. }
  8685. /** Сбор награды из Горнила Душ */
  8686. async function rewardBossRatingEventSouls() {
  8687. const data = await Send({
  8688. calls: [
  8689. { name: "offerGetAll", args: {}, ident: "offerGetAll" }
  8690. ]
  8691. });
  8692. const bossEventInfo = data.r###lts[0].r###lt.response.find(e => e.offerType == "bossEvent");
  8693. if (!bossEventInfo) {
  8694. setProgress('Эвент завершен', true);
  8695. return;
  8696. }
  8697. const farmedChests = bossEventInfo.progress.farmedChests;
  8698. const score = bossEventInfo.progress.score;
  8699. // setProgress('Количество убитых врагов: ' + score);
  8700. const revard = bossEventInfo.reward;
  8701. const calls = [];
  8702. let count = 0;
  8703. for (let i = 1; i < 10; i++) {
  8704. if (farmedChests.includes(i)) {
  8705. continue;
  8706. }
  8707. if (score < revard[i].score) {
  8708. break;
  8709. }
  8710. calls.push({
  8711. name: "bossRatingEvent_getReward",
  8712. args: {
  8713. rewardId: i
  8714. },
  8715. ident: "body_" + i
  8716. });
  8717. count++;
  8718. }
  8719. if (!count) {
  8720. setProgress('Нечего собирать', true);
  8721. return;
  8722. }
  8723. Send({ calls }).then(e => {
  8724. console.log(e);
  8725. setProgress('Собрано ' + e?.r###lts?.length + ' наград', true);
  8726. })
  8727. }
  8728. /**
  8729. * Spin the Seer
  8730. *
  8731. * Покрутить провидца
  8732. */
  8733. async function rollAscension() {
  8734. const refillable = await Send({calls:[
  8735. {
  8736. name:"userGetInfo",
  8737. args:{},
  8738. ident:"userGetInfo"
  8739. }
  8740. ]}).then(e => e.r###lts[0].r###lt.response.refillable);
  8741. const i47 = refillable.find(i => i.id == 47);
  8742. if (i47?.amount) {
  8743. await Send({ calls: [{ name: "ascensionChest_open", args: { paid: false, amount: 1 }, ident: "body" }] });
  8744. setProgress(I18N('DONE'), true);
  8745. } else {
  8746. setProgress(I18N('NOT_ENOUGH_AP'), true);
  8747. }
  8748. }
  8749. /**
  8750. * Collect gifts for the New Year
  8751. *
  8752. * Собрать подарки на новый год
  8753. */
  8754. function getGiftNewYear() {
  8755. Send({ calls: [{ name: "newYearGiftGet", args: { type: 0 }, ident: "body" }] }).then(e => {
  8756. const gifts = e.r###lts[0].r###lt.response.gifts;
  8757. const calls = gifts.filter(e => e.opened == 0).map(e => ({
  8758. name: "newYearGiftOpen",
  8759. args: {
  8760. giftId: e.id
  8761. },
  8762. ident: `body_${e.id}`
  8763. }));
  8764. if (!calls.length) {
  8765. setProgress(I18N('NY_NO_GIFTS'), 5000);
  8766. return;
  8767. }
  8768. Send({ calls }).then(e => {
  8769. console.log(e.r###lts)
  8770. const msg = I18N('NY_GIFTS_COLLECTED', { count: e.r###lts.length });
  8771. console.log(msg);
  8772. setProgress(msg, 5000);
  8773. });
  8774. })
  8775. }
  8776. async function updateArtifacts() {
  8777. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  8778. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  8779. { r###lt: false, isClose: true }
  8780. ]);
  8781. if (!count) {
  8782. return;
  8783. }
  8784. const quest = new questRun;
  8785. await quest.autoInit();
  8786. const heroes = Object.values(quest.questInfo['heroGetAll']);
  8787. const inventory = quest.questInfo['inventoryGet'];
  8788. const calls = [];
  8789. for (let i = count; i > 0; i--) {
  8790. const upArtifact = quest.getUpgradeArtifact();
  8791. if (!upArtifact.heroId) {
  8792. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  8793. { msg: I18N('YES'), r###lt: true },
  8794. { r###lt: false, isClose: true }
  8795. ])) {
  8796. break;
  8797. } else {
  8798. return;
  8799. }
  8800. }
  8801. const hero = heroes.find(e => e.id == upArtifact.heroId);
  8802. hero.artifacts[upArtifact.slotId].level++;
  8803. inventory[upArtifact.costCurrency][upArtifact.costId] -= upArtifact.costValue;
  8804. calls.push({
  8805. name: "heroArtifactLevelUp",
  8806. args: {
  8807. heroId: upArtifact.heroId,
  8808. slotId: upArtifact.slotId
  8809. },
  8810. ident: `heroArtifactLevelUp_${i}`
  8811. });
  8812. }
  8813. if (!calls.length) {
  8814. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8815. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8816. return;
  8817. }
  8818. await Send(JSON.stringify({ calls })).then(e => {
  8819. if ('error' in e) {
  8820. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8821. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8822. } else {
  8823. console.log(I18N('IMPROVED_LEVELS', { count: e.r###lts.length }));
  8824. setProgress(I18N('IMPROVED_LEVELS', { count: e.r###lts.length }), false);
  8825. }
  8826. });
  8827. }
  8828. window.sign = a => {
  8829. const i = this['\x78\x79\x7a'];
  8830. 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'))
  8831. }
  8832. async function updateSkins() {
  8833. const count = +await popup.confirm(I18N('SET_NUMBER_LEVELS'), [
  8834. { msg: I18N('BTN_GO'), isInput: true, default: 10 },
  8835. { r###lt: false, isClose: true }
  8836. ]);
  8837. if (!count) {
  8838. return;
  8839. }
  8840. const quest = new questRun;
  8841. await quest.autoInit();
  8842. const heroes = Object.values(quest.questInfo['heroGetAll']);
  8843. const inventory = quest.questInfo['inventoryGet'];
  8844. const calls = [];
  8845. for (let i = count; i > 0; i--) {
  8846. const upSkin = quest.getUpgradeSkin();
  8847. if (!upSkin.heroId) {
  8848. if (await popup.confirm(I18N('POSSIBLE_IMPROVE_LEVELS', { count: calls.length }), [
  8849. { msg: I18N('YES'), r###lt: true },
  8850. { r###lt: false, isClose: true }
  8851. ])) {
  8852. break;
  8853. } else {
  8854. return;
  8855. }
  8856. }
  8857. const hero = heroes.find(e => e.id == upSkin.heroId);
  8858. hero.skins[upSkin.skinId]++;
  8859. inventory[upSkin.costCurrency][upSkin.costCurrencyId] -= upSkin.cost;
  8860. calls.push({
  8861. name: "heroSkinUpgrade",
  8862. args: {
  8863. heroId: upSkin.heroId,
  8864. skinId: upSkin.skinId
  8865. },
  8866. ident: `heroSkinUpgrade_${i}`
  8867. })
  8868. }
  8869. if (!calls.length) {
  8870. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8871. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8872. return;
  8873. }
  8874. await Send(JSON.stringify({ calls })).then(e => {
  8875. if ('error' in e) {
  8876. console.log(I18N('NOT_ENOUGH_RESOURECES'));
  8877. setProgress(I18N('NOT_ENOUGH_RESOURECES'), false);
  8878. } else {
  8879. console.log(I18N('IMPROVED_LEVELS', { count: e.r###lts.length }));
  8880. setProgress(I18N('IMPROVED_LEVELS', { count: e.r###lts.length }), false);
  8881. }
  8882. });
  8883. }
  8884. function getQuestionInfo(img, nameOnly = false) {
  8885. const libHeroes = Object.values(lib.data.hero);
  8886. const parts = img.split(':');
  8887. const id = parts[1];
  8888. switch (parts[0]) {
  8889. case 'titanArtifact_id':
  8890. return cheats.translate("LIB_TITAN_ARTIFACT_NAME_" + id);
  8891. case 'titan':
  8892. return cheats.translate("LIB_HERO_NAME_" + id);
  8893. case 'skill':
  8894. return cheats.translate("LIB_SKILL_" + id);
  8895. case 'inventoryItem_gear':
  8896. return cheats.translate("LIB_GEAR_NAME_" + id);
  8897. case 'inventoryItem_coin':
  8898. return cheats.translate("LIB_COIN_NAME_" + id);
  8899. case 'artifact':
  8900. if (nameOnly) {
  8901. return cheats.translate("LIB_ARTIFACT_NAME_" + id);
  8902. }
  8903. heroes = libHeroes.filter(h => h.id < 100 && h.artifacts.includes(+id));
  8904. return {
  8905. /** Как называется этот артефакт? */
  8906. name: cheats.translate("LIB_ARTIFACT_NAME_" + id),
  8907. /** Какому герою принадлежит этот артефакт? */
  8908. heroes: heroes.map(h => cheats.translate("LIB_HERO_NAME_" + h.id))
  8909. };
  8910. case 'hero':
  8911. if (nameOnly) {
  8912. return cheats.translate("LIB_HERO_NAME_" + id);
  8913. }
  8914. artifacts = lib.data.hero[id].artifacts;
  8915. return {
  8916. /** Как зовут этого героя? */
  8917. name: cheats.translate("LIB_HERO_NAME_" + id),
  8918. /** Какой артефакт принадлежит этому герою? */
  8919. artifact: artifacts.map(a => cheats.translate("LIB_ARTIFACT_NAME_" + a))
  8920. };
  8921. }
  8922. }
  8923. function hintQuest(quest) {
  8924. const r###lt = {};
  8925. if (quest?.questionIcon) {
  8926. const info = getQuestionInfo(quest.questionIcon);
  8927. if (info?.heroes) {
  8928. /** Какому герою принадлежит этот артефакт? */
  8929. r###lt.answer = quest.answers.filter(e => info.heroes.includes(e.answerText.slice(1)));
  8930. }
  8931. if (info?.artifact) {
  8932. /** Какой артефакт принадлежит этому герою? */
  8933. r###lt.answer = quest.answers.filter(e => info.artifact.includes(e.answerText.slice(1)));
  8934. }
  8935. if (typeof info == 'string') {
  8936. r###lt.info = { name: info };
  8937. } else {
  8938. r###lt.info = info;
  8939. }
  8940. }
  8941. if (quest.answers[0]?.answerIcon) {
  8942. r###lt.answer = quest.answers.filter(e => quest.question.includes(getQuestionInfo(e.answerIcon, true)))
  8943. }
  8944. if ((!r###lt?.answer || !r###lt.answer.length) && !r###lt.info?.name) {
  8945. return false;
  8946. }
  8947. let r###ltText = '';
  8948. if (r###lt?.info) {
  8949. r###ltText += I18N('PICTURE') + r###lt.info.name;
  8950. }
  8951. console.log(r###lt);
  8952. if (r###lt?.answer && r###lt.answer.length) {
  8953. r###ltText += I18N('ANSWER') + r###lt.answer[0].id + (!r###lt.answer[0].answerIcon ? ' - ' + r###lt.answer[0].answerText : '');
  8954. }
  8955. return r###ltText;
  8956. }
  8957. async function farmBattlePass() {
  8958. const isFarmReward = (reward) => {
  8959. return !(reward?.buff || reward?.fragmentHero || reward?.bundleHeroReward);
  8960. };
  8961. const battlePassProcess = (pass) => {
  8962. if (!pass.id) {return []}
  8963. const levels = Object.values(lib.data.battlePass.level).filter(x => x.battlePass == pass.id)
  8964. const last_level = levels[levels.length - 1];
  8965. let actual = Math.max(...levels.filter(p => pass.exp >= p.experience).map(p => p.level))
  8966. if (pass.exp > last_level.experience) {
  8967. actual = last_level.level + (pass.exp - last_level.experience) / last_level.experienceByLevel;
  8968. }
  8969. const calls = [];
  8970. for(let i = 1; i <= actual; i++) {
  8971. const level = i >= last_level.level ? last_level : levels.find(l => l.level === i);
  8972. const reward = {free: level?.freeReward, paid:level?.paidReward};
  8973. if (!pass.rewards[i]?.free && isFarmReward(reward.free)) {
  8974. const args = {level: i, free:true};
  8975. if (!pass.gold) { args.id = pass.id }
  8976. calls.push({ name: 'battlePass_farmReward', args, ident: `${pass.gold ? 'body' : 'spesial'}_free_${args.id}_${i}` });
  8977. }
  8978. if (pass.ticket && !pass.rewards[i]?.paid && isFarmReward(reward.paid)) {
  8979. const args = {level: i, free:false};
  8980. if (!pass.gold) { args.id = pass.id}
  8981. calls.push({ name: 'battlePass_farmReward', args, ident: `${pass.gold ? 'body' : 'spesial'}_paid_${args.id}_${i}` });
  8982. }
  8983. }
  8984. return calls;
  8985. }
  8986. const passes = await Send({
  8987. calls: [
  8988. { name: 'battlePass_getInfo', args: {}, ident: 'getInfo' },
  8989. { name: 'battlePass_getSpecial', args: {}, ident: 'getSpecial' },
  8990. ],
  8991. }).then((e) => [{...e.r###lts[0].r###lt.response?.battlePass, gold: true}, ...Object.values(e.r###lts[1].r###lt.response)]);
  8992. const calls = passes.map(p => battlePassProcess(p)).flat()
  8993. if (!calls.length) {
  8994. setProgress(I18N('NOTHING_TO_COLLECT'));
  8995. return;
  8996. }
  8997. let r###lts = await Send({calls});
  8998. if (r###lts.error) {
  8999. console.log(r###lts.error);
  9000. setProgress(I18N('SOMETHING_WENT_WRONG'));
  9001. } else {
  9002. setProgress(I18N('SEASON_REWARD_COLLECTED', {count: r###lts.r###lts.length}), true);
  9003. }
  9004. }
  9005. async function sellHeroSoulsForGold() {
  9006. let { fragmentHero, heroes } = await Send({
  9007. calls: [
  9008. { name: 'inventoryGet', args: {}, ident: 'inventoryGet' },
  9009. { name: 'heroGetAll', args: {}, ident: 'heroGetAll' },
  9010. ],
  9011. })
  9012. .then((e) => e.r###lts.map((r) => r.r###lt.response))
  9013. .then((e) => ({ fragmentHero: e[0].fragmentHero, heroes: e[1] }));
  9014. const calls = [];
  9015. for (let i in fragmentHero) {
  9016. if (heroes[i] && heroes[i].star == 6) {
  9017. calls.push({
  9018. name: 'inventorySell',
  9019. args: {
  9020. type: 'hero',
  9021. libId: i,
  9022. amount: fragmentHero[i],
  9023. fragment: true,
  9024. },
  9025. ident: 'inventorySell_' + i,
  9026. });
  9027. }
  9028. }
  9029. if (!calls.length) {
  9030. console.log(0);
  9031. return 0;
  9032. }
  9033. const rewards = await Send({ calls }).then((e) => e.r###lts.map((r) => r.r###lt?.response?.gold || 0));
  9034. const gold = rewards.reduce((e, a) => e + a, 0);
  9035. setProgress(I18N('GOLD_RECEIVED', { gold }), true);
  9036. }
  9037. /**
  9038. * Attack of the minions of Asgard
  9039. *
  9040. * Атака прислужников Асгарда
  9041. */
  9042. function testRaidNodes() {
  9043. const { executeRaidNodes } = HWHClasses;
  9044. return new Promise((resolve, reject) => {
  9045. const tower = new executeRaidNodes(resolve, reject);
  9046. tower.start();
  9047. });
  9048. }
  9049. /**
  9050. * Attack of the minions of Asgard
  9051. *
  9052. * Атака прислужников Асгарда
  9053. */
  9054. function executeRaidNodes(resolve, reject) {
  9055. let raidData = {
  9056. teams: [],
  9057. favor: {},
  9058. nodes: [],
  9059. attempts: 0,
  9060. countExecuteBattles: 0,
  9061. cancelBattle: 0,
  9062. }
  9063. callsExecuteRaidNodes = {
  9064. calls: [{
  9065. name: "clanRaid_getInfo",
  9066. args: {},
  9067. ident: "clanRaid_getInfo"
  9068. }, {
  9069. name: "teamGetAll",
  9070. args: {},
  9071. ident: "teamGetAll"
  9072. }, {
  9073. name: "teamGetFavor",
  9074. args: {},
  9075. ident: "teamGetFavor"
  9076. }]
  9077. }
  9078. this.start = function () {
  9079. send(JSON.stringify(callsExecuteRaidNodes), startRaidNodes);
  9080. }
  9081. async function startRaidNodes(data) {
  9082. res = data.r###lts;
  9083. clanRaidInfo = res[0].r###lt.response;
  9084. teamGetAll = res[1].r###lt.response;
  9085. teamGetFavor = res[2].r###lt.response;
  9086. let index = 0;
  9087. let isNotFullPack = false;
  9088. for (let team of teamGetAll.clanRaid_nodes) {
  9089. if (team.length < 6) {
  9090. isNotFullPack = true;
  9091. }
  9092. raidData.teams.push({
  9093. data: {},
  9094. heroes: team.filter(id => id < 6000),
  9095. pet: team.filter(id => id >= 6000).pop(),
  9096. battleIndex: index++
  9097. });
  9098. }
  9099. raidData.favor = teamGetFavor.clanRaid_nodes;
  9100. if (isNotFullPack) {
  9101. if (await popup.confirm(I18N('MINIONS_WARNING'), [
  9102. { msg: I18N('BTN_NO'), r###lt: true },
  9103. { msg: I18N('BTN_YES'), r###lt: false },
  9104. ])) {
  9105. endRaidNodes('isNotFullPack');
  9106. return;
  9107. }
  9108. }
  9109. raidData.nodes = clanRaidInfo.nodes;
  9110. raidData.attempts = clanRaidInfo.attempts;
  9111. setIsCancalBattle(false);
  9112. checkNodes();
  9113. }
  9114. function getAttackNode() {
  9115. for (let nodeId in raidData.nodes) {
  9116. let node = raidData.nodes[nodeId];
  9117. let points = 0
  9118. for (team of node.teams) {
  9119. points += team.points;
  9120. }
  9121. let now = Date.now() / 1000;
  9122. if (!points && now > node.timestamps.start && now < node.timestamps.end) {
  9123. let countTeam = node.teams.length;
  9124. delete raidData.nodes[nodeId];
  9125. return {
  9126. nodeId,
  9127. countTeam
  9128. };
  9129. }
  9130. }
  9131. return null;
  9132. }
  9133. function checkNodes() {
  9134. setProgress(`${I18N('REMAINING_ATTEMPTS')}: ${raidData.attempts}`);
  9135. let nodeInfo = getAttackNode();
  9136. if (nodeInfo && raidData.attempts) {
  9137. startNodeBattles(nodeInfo);
  9138. return;
  9139. }
  9140. endRaidNodes('EndRaidNodes');
  9141. }
  9142. function startNodeBattles(nodeInfo) {
  9143. let {nodeId, countTeam} = nodeInfo;
  9144. let teams = raidData.teams.slice(0, countTeam);
  9145. let heroes = raidData.teams.map(e => e.heroes).flat();
  9146. let favor = {...raidData.favor};
  9147. for (let heroId in favor) {
  9148. if (!heroes.includes(+heroId)) {
  9149. delete favor[heroId];
  9150. }
  9151. }
  9152. let calls = [{
  9153. name: "clanRaid_startNodeBattles",
  9154. args: {
  9155. nodeId,
  9156. teams,
  9157. favor
  9158. },
  9159. ident: "body"
  9160. }];
  9161. send(JSON.stringify({calls}), r###ltNodeBattles);
  9162. }
  9163. function r###ltNodeBattles(e) {
  9164. if (e['error']) {
  9165. endRaidNodes('nodeBattlesError', e['error']);
  9166. return;
  9167. }
  9168. console.log(e);
  9169. let battles = e.r###lts[0].r###lt.response.battles;
  9170. let promises = [];
  9171. let battleIndex = 0;
  9172. for (let battle of battles) {
  9173. battle.battleIndex = battleIndex++;
  9174. promises.push(calcBattleR###lt(battle));
  9175. }
  9176. Promise.all(promises)
  9177. .then(r###lts => {
  9178. const endR###lts = {};
  9179. let isAllWin = true;
  9180. for (let r of r###lts) {
  9181. isAllWin &&= r.r###lt.win;
  9182. }
  9183. if (!isAllWin) {
  9184. cancelEndNodeBattle(r###lts[0]);
  9185. return;
  9186. }
  9187. raidData.countExecuteBattles = r###lts.length;
  9188. let timeout = 500;
  9189. for (let r of r###lts) {
  9190. setTimeout(endNodeBattle, timeout, r);
  9191. timeout += 500;
  9192. }
  9193. });
  9194. }
  9195. /**
  9196. * Returns the battle calculation promise
  9197. *
  9198. * Возвращает промис расчета боя
  9199. */
  9200. function calcBattleR###lt(battleData) {
  9201. return new Promise(function (resolve, reject) {
  9202. BattleCalc(battleData, "get_clanPvp", resolve);
  9203. });
  9204. }
  9205. /**
  9206. * Cancels the fight
  9207. *
  9208. * Отменяет бой
  9209. */
  9210. function cancelEndNodeBattle(r) {
  9211. const fixBattle = function (heroes) {
  9212. for (const ids in heroes) {
  9213. hero = heroes[ids];
  9214. hero.energy = random(1, 999);
  9215. if (hero.hp > 0) {
  9216. hero.hp = random(1, hero.hp);
  9217. }
  9218. }
  9219. }
  9220. fixBattle(r.progress[0].attackers.heroes);
  9221. fixBattle(r.progress[0].defenders.heroes);
  9222. endNodeBattle(r);
  9223. }
  9224. /**
  9225. * Ends the fight
  9226. *
  9227. * Завершает бой
  9228. */
  9229. function endNodeBattle(r) {
  9230. let nodeId = r.battleData.r###lt.nodeId;
  9231. let battleIndex = r.battleData.battleIndex;
  9232. let calls = [{
  9233. name: "clanRaid_endNodeBattle",
  9234. args: {
  9235. nodeId,
  9236. battleIndex,
  9237. r###lt: r.r###lt,
  9238. progress: r.progress
  9239. },
  9240. ident: "body"
  9241. }]
  9242. SendRequest(JSON.stringify({calls}), battleR###lt);
  9243. }
  9244. /**
  9245. * Processing the r###lts of the battle
  9246. *
  9247. * Обработка результатов боя
  9248. */
  9249. function battleR###lt(e) {
  9250. if (e['error']) {
  9251. endRaidNodes('missionEndError', e['error']);
  9252. return;
  9253. }
  9254. r = e.r###lts[0].r###lt.response;
  9255. if (r['error']) {
  9256. if (r.reason == "invalidBattle") {
  9257. raidData.cancelBattle++;
  9258. checkNodes();
  9259. } else {
  9260. endRaidNodes('missionEndError', e['error']);
  9261. }
  9262. return;
  9263. }
  9264. if (!(--raidData.countExecuteBattles)) {
  9265. raidData.attempts--;
  9266. checkNodes();
  9267. }
  9268. }
  9269. /**
  9270. * Completing a task
  9271. *
  9272. * Завершение задачи
  9273. */
  9274. function endRaidNodes(reason, info) {
  9275. setIsCancalBattle(true);
  9276. let textCancel = raidData.cancelBattle ? ` ${I18N('BATTLES_CANCELED')}: ${raidData.cancelBattle}` : '';
  9277. setProgress(`${I18N('MINION_RAID')} ${I18N('COMPLETED')}! ${textCancel}`, true);
  9278. console.log(reason, info);
  9279. resolve();
  9280. }
  9281. }
  9282. this.HWHClasses.executeRaidNodes = executeRaidNodes;
  9283. /**
  9284. * Asgard Boss Attack Replay
  9285. *
  9286. * Повтор атаки босса Асгарда
  9287. */
  9288. function testBossBattle() {
  9289. const { executeBossBattle } = HWHClasses;
  9290. return new Promise((resolve, reject) => {
  9291. const bossBattle = new executeBossBattle(resolve, reject);
  9292. bossBattle.start(lastBossBattle);
  9293. });
  9294. }
  9295. /**
  9296. * Asgard Boss Attack Replay
  9297. *
  9298. * Повтор атаки босса Асгарда
  9299. */
  9300. function executeBossBattle(resolve, reject) {
  9301. this.start = function (battleInfo) {
  9302. preCalcBattle(battleInfo);
  9303. }
  9304. function getBattleInfo(battle) {
  9305. return new Promise(function (resolve) {
  9306. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  9307. BattleCalc(battle, getBattleType(battle.type), e => {
  9308. let extra = e.progress[0].defenders.heroes[1].extra;
  9309. resolve(extra.damageTaken + extra.damageTakenNextLevel);
  9310. });
  9311. });
  9312. }
  9313. function preCalcBattle(battle) {
  9314. let actions = [];
  9315. const countTestBattle = getInput('countTestBattle');
  9316. for (let i = 0; i < countTestBattle; i++) {
  9317. actions.push(getBattleInfo(battle, true));
  9318. }
  9319. Promise.all(actions)
  9320. .then(r###ltPreCalcBattle);
  9321. }
  9322. async function r###ltPreCalcBattle(damages) {
  9323. let maxDamage = 0;
  9324. let minDamage = 1e10;
  9325. let avgDamage = 0;
  9326. for (let damage of damages) {
  9327. avgDamage += damage
  9328. if (damage > maxDamage) {
  9329. maxDamage = damage;
  9330. }
  9331. if (damage < minDamage) {
  9332. minDamage = damage;
  9333. }
  9334. }
  9335. avgDamage /= damages.length;
  9336. console.log(damages.map(e => e.toLocaleString()).join('\n'), avgDamage, maxDamage);
  9337. await popup.confirm(
  9338. `${I18N('ROUND_STAT')} ${damages.length} ${I18N('BATTLE')}:` +
  9339. `<br>${I18N('MINIMUM')}: ` + minDamage.toLocaleString() +
  9340. `<br>${I18N('MAXIMUM')}: ` + maxDamage.toLocaleString() +
  9341. `<br>${I18N('AVERAGE')}: ` + avgDamage.toLocaleString()
  9342. , [
  9343. { msg: I18N('BTN_OK'), r###lt: 0},
  9344. ])
  9345. endBossBattle(I18N('BTN_CANCEL'));
  9346. }
  9347. /**
  9348. * Completing a task
  9349. *
  9350. * Завершение задачи
  9351. */
  9352. function endBossBattle(reason, info) {
  9353. console.log(reason, info);
  9354. resolve();
  9355. }
  9356. }
  9357. this.HWHClasses.executeBossBattle = executeBossBattle;
  9358. class FixBattle {
  9359. minTimer = 1.3;
  9360. maxTimer = 15.3;
  9361. constructor(battle, isTimeout = true) {
  9362. this.battle = structuredClone(battle);
  9363. this.isTimeout = isTimeout;
  9364. }
  9365. timeout(callback, timeout) {
  9366. if (this.isTimeout) {
  9367. this.worker.postMessage(timeout);
  9368. this.worker.onmessage = callback;
  9369. } else {
  9370. callback();
  9371. }
  9372. }
  9373. randTimer() {
  9374. return Math.random() * (this.maxTimer - this.minTimer + 1) + this.minTimer;
  9375. }
  9376. setAvgTime(startTime) {
  9377. this.fixTime += Date.now() - startTime;
  9378. this.avgTime = this.fixTime / this.count;
  9379. }
  9380. init() {
  9381. this.fixTime = 0;
  9382. this.lastTimer = 0;
  9383. this.index = 0;
  9384. this.lastBossDamage = 0;
  9385. this.bestR###lt = {
  9386. count: 0,
  9387. timer: 0,
  9388. value: 0,
  9389. r###lt: null,
  9390. progress: null,
  9391. };
  9392. this.lastBattleR###lt = {
  9393. win: false,
  9394. };
  9395. this.worker = new Worker(
  9396. URL.createObjectURL(
  9397. new Blob([
  9398. `self.onmessage = function(e) {
  9399. const timeout = e.data;
  9400. setTimeout(() => {
  9401. self.postMessage(1);
  9402. }, timeout);
  9403. };`,
  9404. ])
  9405. )
  9406. );
  9407. }
  9408. async start(endTime = Date.now() + 6e4, maxCount = 100) {
  9409. this.endTime = endTime;
  9410. this.maxCount = maxCount;
  9411. this.init();
  9412. return await new Promise((resolve) => {
  9413. this.resolve = resolve;
  9414. this.count = 0;
  9415. this.loop();
  9416. });
  9417. }
  9418. endFix() {
  9419. this.bestR###lt.maxCount = this.count;
  9420. this.worker.terminate();
  9421. this.resolve(this.bestR###lt);
  9422. }
  9423. async loop() {
  9424. const start = Date.now();
  9425. if (this.isEndLoop()) {
  9426. this.endFix();
  9427. return;
  9428. }
  9429. this.count++;
  9430. try {
  9431. this.lastR###lt = await Calc(this.battle);
  9432. } catch (e) {
  9433. this.updateProgressTimer(this.index++);
  9434. this.timeout(this.loop.bind(this), 0);
  9435. return;
  9436. }
  9437. const { progress, r###lt } = this.lastR###lt;
  9438. this.lastBattleR###lt = r###lt;
  9439. this.lastBattleProgress = progress;
  9440. this.setAvgTime(start);
  9441. this.checkR###lt();
  9442. this.showR###lt();
  9443. this.updateProgressTimer();
  9444. this.timeout(this.loop.bind(this), 0);
  9445. }
  9446. isEndLoop() {
  9447. return this.count >= this.maxCount || this.endTime < Date.now();
  9448. }
  9449. updateProgressTimer(index = 0) {
  9450. this.lastTimer = this.randTimer();
  9451. this.battle.progress = [{ attackers: { input: ['auto', 0, 0, 'auto', index, this.lastTimer] } }];
  9452. }
  9453. showR###lt() {
  9454. console.log(
  9455. this.count,
  9456. this.avgTime.toFixed(2),
  9457. (this.endTime - Date.now()) / 1000,
  9458. this.lastTimer.toFixed(2),
  9459. this.lastBossDamage.toLocaleString(),
  9460. this.bestR###lt.value.toLocaleString()
  9461. );
  9462. }
  9463. checkR###lt() {
  9464. const { damageTaken, damageTakenNextLevel } = this.lastBattleProgress[0].defenders.heroes[1].extra;
  9465. this.lastBossDamage = damageTaken + damageTakenNextLevel;
  9466. if (this.lastBossDamage > this.bestR###lt.value) {
  9467. this.bestR###lt = {
  9468. count: this.count,
  9469. timer: this.lastTimer,
  9470. value: this.lastBossDamage,
  9471. r###lt: structuredClone(this.lastBattleR###lt),
  9472. progress: structuredClone(this.lastBattleProgress),
  9473. };
  9474. }
  9475. }
  9476. stopFix() {
  9477. this.endTime = 0;
  9478. }
  9479. }
  9480. this.HWHClasses.FixBattle = FixBattle;
  9481. class WinFixBattle extends FixBattle {
  9482. checkR###lt() {
  9483. if (this.lastBattleR###lt.win) {
  9484. this.bestR###lt = {
  9485. count: this.count,
  9486. timer: this.lastTimer,
  9487. value: this.lastBattleR###lt.stars,
  9488. r###lt: structuredClone(this.lastBattleR###lt),
  9489. progress: structuredClone(this.lastBattleProgress),
  9490. battleTimer: this.lastR###lt.battleTimer,
  9491. };
  9492. }
  9493. }
  9494. setWinTimer(value) {
  9495. this.winTimer = value;
  9496. }
  9497. setMaxTimer(value) {
  9498. this.maxTimer = value;
  9499. }
  9500. randTimer() {
  9501. if (this.winTimer) {
  9502. return this.winTimer;
  9503. }
  9504. return super.randTimer();
  9505. }
  9506. isEndLoop() {
  9507. return super.isEndLoop() || this.bestR###lt.r###lt?.win;
  9508. }
  9509. showR###lt() {
  9510. console.log(
  9511. this.count,
  9512. this.avgTime.toFixed(2),
  9513. (this.endTime - Date.now()) / 1000,
  9514. this.lastR###lt.battleTime,
  9515. this.lastTimer,
  9516. this.bestR###lt.value
  9517. );
  9518. const endTime = ((this.endTime - Date.now()) / 1000).toFixed(2);
  9519. const avgTime = this.avgTime.toFixed(2);
  9520. const msg = `${I18N('LETS_FIX')} ${this.count}/${this.maxCount}<br/>${endTime}s<br/>${avgTime}ms`;
  9521. setProgress(msg, false, this.stopFix.bind(this));
  9522. }
  9523. }
  9524. this.HWHClasses.WinFixBattle = WinFixBattle;
  9525. class BestOrWinFixBattle extends WinFixBattle {
  9526. isNoMakeWin = false;
  9527. getState(r###lt) {
  9528. let befor###mFactor = 0;
  9529. const beforeHeroes = r###lt.battleData.defenders[0];
  9530. for (let heroId in beforeHeroes) {
  9531. const hero = beforeHeroes[heroId];
  9532. const state = hero.state;
  9533. let factor = 1;
  9534. if (state) {
  9535. const hp = state.hp / (hero?.hp || 1);
  9536. const energy = state.energy / 1e3;
  9537. factor = hp + energy / 20;
  9538. }
  9539. befor###mFactor += factor;
  9540. }
  9541. let afterSumFactor = 0;
  9542. const afterHeroes = r###lt.progress[0].defenders.heroes;
  9543. for (let heroId in afterHeroes) {
  9544. const hero = afterHeroes[heroId];
  9545. const hp = hero.hp / (beforeHeroes[heroId]?.hp || 1);
  9546. const energy = hero.energy / 1e3;
  9547. const factor = hp + energy / 20;
  9548. afterSumFactor += factor;
  9549. }
  9550. return 100 - Math.floor((afterSumFactor / befor###mFactor) * 1e4) / 100;
  9551. }
  9552. setNoMakeWin(value) {
  9553. this.isNoMakeWin = value;
  9554. }
  9555. checkR###lt() {
  9556. const state = this.getState(this.lastR###lt);
  9557. console.log(state);
  9558. if (state > this.bestR###lt.value) {
  9559. if (!(this.isNoMakeWin && this.lastBattleR###lt.win)) {
  9560. this.bestR###lt = {
  9561. count: this.count,
  9562. timer: this.lastTimer,
  9563. value: state,
  9564. r###lt: structuredClone(this.lastBattleR###lt),
  9565. progress: structuredClone(this.lastBattleProgress),
  9566. battleTimer: this.lastR###lt.battleTimer,
  9567. };
  9568. }
  9569. }
  9570. }
  9571. }
  9572. this.HWHClasses.BestOrWinFixBattle = BestOrWinFixBattle;
  9573. class BossFixBattle extends FixBattle {
  9574. showR###lt() {
  9575. super.showR###lt();
  9576. //setTimeout(() => {
  9577. const best = this.bestR###lt;
  9578. const maxDmg = best.value.toLocaleString();
  9579. const avgTime = this.avgTime.toLocaleString();
  9580. const msg = `${I18N('LETS_FIX')} ${this.count}/${this.maxCount}<br/>${maxDmg}<br/>${avgTime}ms`;
  9581. setProgress(msg, false, this.stopFix.bind(this));
  9582. //}, 0);
  9583. }
  9584. }
  9585. this.HWHClasses.BossFixBattle = BossFixBattle;
  9586. class DungeonFixBattle extends FixBattle {
  9587. init() {
  9588. super.init();
  9589. this.isTimeout = false;
  9590. }
  9591. setState() {
  9592. const r###lt = this.lastR###lt;
  9593. let befor###mFactor = 0;
  9594. const beforeHeroes = r###lt.battleData.attackers;
  9595. for (let heroId in beforeHeroes) {
  9596. const hero = beforeHeroes[heroId];
  9597. const state = hero.state;
  9598. let factor = 1;
  9599. if (state) {
  9600. const hp = state.hp / (hero?.hp || 1);
  9601. const energy = state.energy / 1e3;
  9602. factor = hp + energy / 20;
  9603. }
  9604. befor###mFactor += factor;
  9605. }
  9606. let afterSumFactor = 0;
  9607. const afterHeroes = r###lt.progress[0].attackers.heroes;
  9608. for (let heroId in afterHeroes) {
  9609. const hero = afterHeroes[heroId];
  9610. const hp = hero.hp / (beforeHeroes[heroId]?.hp || 1);
  9611. const energy = hero.energy / 1e3;
  9612. const factor = hp + energy / 20;
  9613. afterSumFactor += factor;
  9614. }
  9615. this.lastState = Math.floor((afterSumFactor / befor###mFactor) * 1e4) / 100;
  9616. }
  9617. checkR###lt() {
  9618. this.setState();
  9619. if (this.lastR###lt.r###lt.win && this.lastState > this.bestR###lt.value) {
  9620. this.bestR###lt = {
  9621. count: this.count,
  9622. timer: this.lastTimer,
  9623. value: this.lastState,
  9624. r###lt: this.lastR###lt.r###lt,
  9625. progress: this.lastR###lt.progress,
  9626. };
  9627. }
  9628. }
  9629. showR###lt() {
  9630. console.log(
  9631. this.count,
  9632. this.avgTime.toFixed(2),
  9633. (this.endTime - Date.now()) / 1000,
  9634. this.lastTimer.toFixed(2),
  9635. this.lastState.toLocaleString(),
  9636. this.bestR###lt.value.toLocaleString()
  9637. );
  9638. }
  9639. }
  9640. this.HWHClasses.DungeonFixBattle = DungeonFixBattle;
  9641. const masterWsMixin = {
  9642. wsStart() {
  9643. const socket = new WebSocket(this.url);
  9644. socket.onopen = () => {
  9645. console.log('Connected to server');
  9646. // Пример создания новой задачи
  9647. const newTask = {
  9648. type: 'newTask',
  9649. battle: this.battle,
  9650. endTime: this.endTime - 1e4,
  9651. maxCount: this.maxCount,
  9652. };
  9653. socket.send(JSON.stringify(newTask));
  9654. };
  9655. socket.onmessage = this.onmessage.bind(this);
  9656. socket.onclose = () => {
  9657. console.log('Disconnected from server');
  9658. };
  9659. this.ws = socket;
  9660. },
  9661. onmessage(event) {
  9662. const data = JSON.parse(event.data);
  9663. switch (data.type) {
  9664. case 'newTask': {
  9665. console.log('newTask:', data);
  9666. this.id = data.id;
  9667. this.countExecutor = data.count;
  9668. break;
  9669. }
  9670. case 'getSolTask': {
  9671. console.log('getSolTask:', data);
  9672. this.endFix(data.solutions);
  9673. break;
  9674. }
  9675. case 'resolveTask': {
  9676. console.log('resolveTask:', data);
  9677. if (data.id === this.id && data.solutions.length === this.countExecutor) {
  9678. this.worker.terminate();
  9679. this.endFix(data.solutions);
  9680. }
  9681. break;
  9682. }
  9683. default:
  9684. console.log('Unknown message type:', data.type);
  9685. }
  9686. },
  9687. getTask() {
  9688. this.ws.send(
  9689. JSON.stringify({
  9690. type: 'getSolTask',
  9691. id: this.id,
  9692. })
  9693. );
  9694. },
  9695. };
  9696. /*
  9697. mFix = new action.masterFixBattle(battle)
  9698. await mFix.start(Date.now() + 6e4, 1);
  9699. */
  9700. class masterFixBattle extends FixBattle {
  9701. constructor(battle, url = 'wss://localho.st:3000') {
  9702. super(battle, true);
  9703. this.url = url;
  9704. }
  9705. async start(endTime, maxCount) {
  9706. this.endTime = endTime;
  9707. this.maxCount = maxCount;
  9708. this.init();
  9709. this.wsStart();
  9710. return await new Promise((resolve) => {
  9711. this.resolve = resolve;
  9712. const timeout = this.endTime - Date.now();
  9713. this.timeout(this.getTask.bind(this), timeout);
  9714. });
  9715. }
  9716. async endFix(solutions) {
  9717. this.ws.close();
  9718. let maxCount = 0;
  9719. for (const solution of solutions) {
  9720. maxCount += solution.maxCount;
  9721. if (solution.value > this.bestR###lt.value) {
  9722. this.bestR###lt = solution;
  9723. }
  9724. }
  9725. this.count = maxCount;
  9726. super.endFix();
  9727. }
  9728. }
  9729. Object.assign(masterFixBattle.prototype, masterWsMixin);
  9730. this.HWHClasses.masterFixBattle = masterFixBattle;
  9731. class masterWinFixBattle extends WinFixBattle {
  9732. constructor(battle, url = 'wss://localho.st:3000') {
  9733. super(battle, true);
  9734. this.url = url;
  9735. }
  9736. async start(endTime, maxCount) {
  9737. this.endTime = endTime;
  9738. this.maxCount = maxCount;
  9739. this.init();
  9740. this.wsStart();
  9741. return await new Promise((resolve) => {
  9742. this.resolve = resolve;
  9743. const timeout = this.endTime - Date.now();
  9744. this.timeout(this.getTask.bind(this), timeout);
  9745. });
  9746. }
  9747. async endFix(solutions) {
  9748. this.ws.close();
  9749. let maxCount = 0;
  9750. for (const solution of solutions) {
  9751. maxCount += solution.maxCount;
  9752. if (solution.value > this.bestR###lt.value) {
  9753. this.bestR###lt = solution;
  9754. }
  9755. }
  9756. this.count = maxCount;
  9757. super.endFix();
  9758. }
  9759. }
  9760. Object.assign(masterWinFixBattle.prototype, masterWsMixin);
  9761. this.HWHClasses.masterWinFixBattle = masterWinFixBattle;
  9762. const slaveWsMixin = {
  9763. wsStop() {
  9764. this.ws.close();
  9765. },
  9766. wsStart() {
  9767. const socket = new WebSocket(this.url);
  9768. socket.onopen = () => {
  9769. console.log('Connected to server');
  9770. };
  9771. socket.onmessage = this.onmessage.bind(this);
  9772. socket.onclose = () => {
  9773. console.log('Disconnected from server');
  9774. };
  9775. this.ws = socket;
  9776. },
  9777. async onmessage(event) {
  9778. const data = JSON.parse(event.data);
  9779. switch (data.type) {
  9780. case 'newTask': {
  9781. console.log('newTask:', data.task);
  9782. const { battle, endTime, maxCount } = data.task;
  9783. this.battle = battle;
  9784. const id = data.task.id;
  9785. const solution = await this.start(endTime, maxCount);
  9786. this.ws.send(
  9787. JSON.stringify({
  9788. type: 'resolveTask',
  9789. id,
  9790. solution,
  9791. })
  9792. );
  9793. break;
  9794. }
  9795. default:
  9796. console.log('Unknown message type:', data.type);
  9797. }
  9798. },
  9799. };
  9800. /*
  9801. sFix = new action.slaveFixBattle();
  9802. sFix.wsStart()
  9803. */
  9804. class slaveFixBattle extends FixBattle {
  9805. constructor(url = 'wss://localho.st:3000') {
  9806. super(null, false);
  9807. this.isTimeout = false;
  9808. this.url = url;
  9809. }
  9810. }
  9811. Object.assign(slaveFixBattle.prototype, slaveWsMixin);
  9812. this.HWHClasses.slaveFixBattle = slaveFixBattle;
  9813. class slaveWinFixBattle extends WinFixBattle {
  9814. constructor(url = 'wss://localho.st:3000') {
  9815. super(null, false);
  9816. this.isTimeout = false;
  9817. this.url = url;
  9818. }
  9819. }
  9820. Object.assign(slaveWinFixBattle.prototype, slaveWsMixin);
  9821. this.HWHClasses.slaveWinFixBattle = slaveWinFixBattle;
  9822. /**
  9823. * Auto-repeat attack
  9824. *
  9825. * Автоповтор атаки
  9826. */
  9827. function testAutoBattle() {
  9828. const { executeAutoBattle } = HWHClasses;
  9829. return new Promise((resolve, reject) => {
  9830. const bossBattle = new executeAutoBattle(resolve, reject);
  9831. bossBattle.start(lastBattleArg, lastBattleInfo);
  9832. });
  9833. }
  9834. /**
  9835. * Auto-repeat attack
  9836. *
  9837. * Автоповтор атаки
  9838. */
  9839. function executeAutoBattle(resolve, reject) {
  9840. let battleArg = {};
  9841. let countBattle = 0;
  9842. let countError = 0;
  9843. let findCoeff = 0;
  9844. let dataNotEeceived = 0;
  9845. let stopAutoBattle = false;
  9846. let isSetWinTimer = false;
  9847. 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>';
  9848. 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>';
  9849. 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>';
  9850. this.start = function (battleArgs, battleInfo) {
  9851. battleArg = battleArgs;
  9852. if (nameFuncStartBattle == 'invasion_bossStart') {
  9853. startBattle();
  9854. return;
  9855. }
  9856. preCalcBattle(battleInfo);
  9857. }
  9858. /**
  9859. * Returns a promise for combat recalculation
  9860. *
  9861. * Возвращает промис для прерасчета боя
  9862. */
  9863. function getBattleInfo(battle) {
  9864. return new Promise(function (resolve) {
  9865. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  9866. Calc(battle).then(e => {
  9867. e.coeff = calcCoeff(e, 'defenders');
  9868. resolve(e);
  9869. });
  9870. });
  9871. }
  9872. /**
  9873. * Battle recalculation
  9874. *
  9875. * Прерасчет боя
  9876. */
  9877. function preCalcBattle(battle) {
  9878. let actions = [];
  9879. const countTestBattle = getInput('countTestBattle');
  9880. for (let i = 0; i < countTestBattle; i++) {
  9881. actions.push(getBattleInfo(battle));
  9882. }
  9883. Promise.all(actions)
  9884. .then(r###ltPreCalcBattle);
  9885. }
  9886. /**
  9887. * Processing the r###lts of the battle recalculation
  9888. *
  9889. * Обработка результатов прерасчета боя
  9890. */
  9891. async function r###ltPreCalcBattle(r###lts) {
  9892. let countWin = r###lts.reduce((s, w) => w.r###lt.win + s, 0);
  9893. setProgress(`${I18N('CHANCE_TO_WIN')} ${Math.floor(countWin / r###lts.length * 100)}% (${r###lts.length})`, false, hideProgress);
  9894. if (countWin > 0) {
  9895. setIsCancalBattle(false);
  9896. startBattle();
  9897. return;
  9898. }
  9899. let minCoeff = 100;
  9900. let maxCoeff = -100;
  9901. let avgCoeff = 0;
  9902. r###lts.forEach(e => {
  9903. if (e.coeff < minCoeff) minCoeff = e.coeff;
  9904. if (e.coeff > maxCoeff) maxCoeff = e.coeff;
  9905. avgCoeff += e.coeff;
  9906. });
  9907. avgCoeff /= r###lts.length;
  9908. if (nameFuncStartBattle == 'invasion_bossStart' ||
  9909. nameFuncStartBattle == 'bossAttack') {
  9910. const r###lt = await popup.confirm(
  9911. I18N('BOSS_VICTORY_IMPOSSIBLE', { battles: r###lts.length }), [
  9912. { msg: I18N('BTN_CANCEL'), r###lt: false, isCancel: true },
  9913. { msg: I18N('BTN_DO_IT'), r###lt: true },
  9914. ])
  9915. if (r###lt) {
  9916. setIsCancalBattle(false);
  9917. startBattle();
  9918. return;
  9919. }
  9920. setProgress(I18N('NOT_THIS_TIME'), true);
  9921. endAutoBattle('invasion_bossStart');
  9922. return;
  9923. }
  9924. const r###lt = await popup.confirm(
  9925. I18N('VICTORY_IMPOSSIBLE') +
  9926. `<br>${I18N('ROUND_STAT')} ${r###lts.length} ${I18N('BATTLE')}:` +
  9927. `<br>${I18N('MINIMUM')}: ` + minCoeff.toLocaleString() +
  9928. `<br>${I18N('MAXIMUM')}: ` + maxCoeff.toLocaleString() +
  9929. `<br>${I18N('AVERAGE')}: ` + avgCoeff.toLocaleString() +
  9930. `<br>${I18N('FIND_COEFF')} ` + avgCoeff.toLocaleString(), [
  9931. { msg: I18N('BTN_CANCEL'), r###lt: 0, isCancel: true },
  9932. { msg: I18N('BTN_GO'), isInput: true, default: Math.round(avgCoeff * 1000) / 1000 },
  9933. ])
  9934. if (r###lt) {
  9935. findCoeff = r###lt;
  9936. setIsCancalBattle(false);
  9937. startBattle();
  9938. return;
  9939. }
  9940. setProgress(I18N('NOT_THIS_TIME'), true);
  9941. endAutoBattle(I18N('NOT_THIS_TIME'));
  9942. }
  9943. /**
  9944. * Calculation of the combat r###lt coefficient
  9945. *
  9946. * Расчет коэфициента результата боя
  9947. */
  9948. function calcCoeff(r###lt, packType) {
  9949. let befor###mFactor = 0;
  9950. const beforePack = r###lt.battleData[packType][0];
  9951. for (let heroId in beforePack) {
  9952. const hero = beforePack[heroId];
  9953. const state = hero.state;
  9954. let factor = 1;
  9955. if (state) {
  9956. const hp = state.hp / state.maxHp;
  9957. const energy = state.energy / 1e3;
  9958. factor = hp + energy / 20;
  9959. }
  9960. befor###mFactor += factor;
  9961. }
  9962. let afterSumFactor = 0;
  9963. const afterPack = r###lt.progress[0][packType].heroes;
  9964. for (let heroId in afterPack) {
  9965. const hero = afterPack[heroId];
  9966. const stateHp = beforePack[heroId]?.state?.hp || beforePack[heroId]?.stats?.hp;
  9967. const hp = hero.hp / stateHp;
  9968. const energy = hero.energy / 1e3;
  9969. const factor = hp + energy / 20;
  9970. afterSumFactor += factor;
  9971. }
  9972. const r###ltCoeff = -(afterSumFactor - befor###mFactor);
  9973. return Math.round(r###ltCoeff * 1000) / 1000;
  9974. }
  9975. /**
  9976. * Start battle
  9977. *
  9978. * Начало боя
  9979. */
  9980. function startBattle() {
  9981. countBattle++;
  9982. const countMaxBattle = getInput('countAutoBattle');
  9983. // setProgress(countBattle + '/' + countMaxBattle);
  9984. if (countBattle > countMaxBattle) {
  9985. setProgress(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`, true);
  9986. endAutoBattle(`${I18N('RETRY_LIMIT_EXCEEDED')}: ${countMaxBattle}`)
  9987. return;
  9988. }
  9989. if (stopAutoBattle) {
  9990. setProgress(I18N('STOPPED'), true);
  9991. endAutoBattle('STOPPED');
  9992. return;
  9993. }
  9994. send({calls: [{
  9995. name: nameFuncStartBattle,
  9996. args: battleArg,
  9997. ident: "body"
  9998. }]}, calcR###ltBattle);
  9999. }
  10000. /**
  10001. * Battle calculation
  10002. *
  10003. * Расчет боя
  10004. */
  10005. async function calcR###ltBattle(e) {
  10006. if (!e) {
  10007. console.log('данные не были получены');
  10008. if (dataNotEeceived < 10) {
  10009. dataNotEeceived++;
  10010. startBattle();
  10011. return;
  10012. }
  10013. endAutoBattle('Error', 'данные не были получены ' + dataNotEeceived + ' раз');
  10014. return;
  10015. }
  10016. if ('error' in e) {
  10017. if (e.error.description === 'too many tries') {
  10018. invasionTimer += 100;
  10019. countBattle--;
  10020. countError++;
  10021. console.log(`Errors: ${countError}`, e.error);
  10022. startBattle();
  10023. return;
  10024. }
  10025. const r###lt = await popup.confirm(I18N('ERROR_DURING_THE_BATTLE') + '<br>' + e.error.description, [
  10026. { msg: I18N('BTN_OK'), r###lt: false },
  10027. { msg: I18N('RELOAD_GAME'), r###lt: true },
  10028. ]);
  10029. endAutoBattle('Error', e.error);
  10030. if (r###lt) {
  10031. location.reload();
  10032. }
  10033. return;
  10034. }
  10035. let battle = e.r###lts[0].r###lt.response.battle
  10036. if (nameFuncStartBattle == 'towerStartBattle' ||
  10037. nameFuncStartBattle == 'bossAttack' ||
  10038. nameFuncStartBattle == 'invasion_bossStart') {
  10039. battle = e.r###lts[0].r###lt.response;
  10040. }
  10041. lastBattleInfo = battle;
  10042. BattleCalc(battle, getBattleType(battle.type), r###ltBattle);
  10043. }
  10044. /**
  10045. * Processing the r###lts of the battle
  10046. *
  10047. * Обработка результатов боя
  10048. */
  10049. async function r###ltBattle(e) {
  10050. const isWin = e.r###lt.win;
  10051. if (isWin) {
  10052. endBattle(e, false);
  10053. return;
  10054. } else if (isChecked('tryFixIt_v2')) {
  10055. const { WinFixBattle } = HWHClasses;
  10056. const cloneBattle = structuredClone(e.battleData);
  10057. const bFix = new WinFixBattle(cloneBattle);
  10058. let attempts = Infinity;
  10059. if (nameFuncStartBattle == 'invasion_bossStart' && !isSetWinTimer) {
  10060. let winTimer = await popup.confirm(`Secret number:`, [
  10061. { r###lt: false, isClose: true },
  10062. { msg: 'Go', isInput: true, default: '0' },
  10063. ]);
  10064. winTimer = Number.parseFloat(winTimer);
  10065. if (winTimer) {
  10066. attempts = 5;
  10067. bFix.setWinTimer(winTimer);
  10068. }
  10069. isSetWinTimer = true;
  10070. }
  10071. let endTime = Date.now() + 6e4;
  10072. if (nameFuncStartBattle == 'invasion_bossStart') {
  10073. endTime = Date.now() + 6e4 * 4;
  10074. bFix.setMaxTimer(120.3);
  10075. }
  10076. const r###lt = await bFix.start(endTime, attempts);
  10077. console.log(r###lt);
  10078. if (r###lt.value) {
  10079. endBattle(r###lt, false);
  10080. return;
  10081. }
  10082. }
  10083. const countMaxBattle = getInput('countAutoBattle');
  10084. if (findCoeff) {
  10085. const coeff = calcCoeff(e, 'defenders');
  10086. setProgress(`${countBattle}/${countMaxBattle}, ${coeff}`);
  10087. if (coeff > findCoeff) {
  10088. endBattle(e, false);
  10089. return;
  10090. }
  10091. } else {
  10092. if (nameFuncStartBattle == 'invasion_bossStart') {
  10093. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  10094. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageModAndEnergyIncrease_any_99_100_300_99_1000_300 || 0;
  10095. setProgress(`${svgBoss} ${bossLvl} ${svgJustice} ${justice} <br>${svgAttempt} ${countBattle}/${countMaxBattle}`, false, () => {
  10096. stopAutoBattle = true;
  10097. });
  10098. await new Promise((resolve) => setTimeout(resolve, 5000));
  10099. } else {
  10100. setProgress(`${countBattle}/${countMaxBattle}`);
  10101. }
  10102. }
  10103. if (nameFuncStartBattle == 'towerStartBattle' ||
  10104. nameFuncStartBattle == 'bossAttack' ||
  10105. nameFuncStartBattle == 'invasion_bossStart') {
  10106. startBattle();
  10107. return;
  10108. }
  10109. cancelEndBattle(e);
  10110. }
  10111. /**
  10112. * Cancel fight
  10113. *
  10114. * Отмена боя
  10115. */
  10116. function cancelEndBattle(r) {
  10117. const fixBattle = function (heroes) {
  10118. for (const ids in heroes) {
  10119. hero = heroes[ids];
  10120. hero.energy = random(1, 999);
  10121. if (hero.hp > 0) {
  10122. hero.hp = random(1, hero.hp);
  10123. }
  10124. }
  10125. }
  10126. fixBattle(r.progress[0].attackers.heroes);
  10127. fixBattle(r.progress[0].defenders.heroes);
  10128. endBattle(r, true);
  10129. }
  10130. /**
  10131. * End of the fight
  10132. *
  10133. * Завершение боя */
  10134. function endBattle(battleR###lt, isCancal) {
  10135. let calls = [{
  10136. name: nameFuncEndBattle,
  10137. args: {
  10138. r###lt: battleR###lt.r###lt,
  10139. progress: battleR###lt.progress
  10140. },
  10141. ident: "body"
  10142. }];
  10143. if (nameFuncStartBattle == 'invasion_bossStart') {
  10144. calls[0].args.id = lastBattleArg.id;
  10145. }
  10146. send(JSON.stringify({
  10147. calls
  10148. }), async e => {
  10149. console.log(e);
  10150. if (isCancal) {
  10151. startBattle();
  10152. return;
  10153. }
  10154. setProgress(`${I18N('SUCCESS')}!`, 5000)
  10155. if (nameFuncStartBattle == 'invasion_bossStart' ||
  10156. nameFuncStartBattle == 'bossAttack') {
  10157. const countMaxBattle = getInput('countAutoBattle');
  10158. const bossLvl = lastBattleInfo.typeId >= 130 ? lastBattleInfo.typeId : '';
  10159. const justice = lastBattleInfo?.effects?.attackers?.percentInOutDamageModAndEnergyIncrease_any_99_100_300_99_1000_300 || 0;
  10160. let winTimer = '';
  10161. if (nameFuncStartBattle == 'invasion_bossStart') {
  10162. winTimer = '<br>Secret number: ' + battleR###lt.progress[0].attackers.input[5];
  10163. }
  10164. const r###lt = await popup.confirm(
  10165. I18N('BOSS_HAS_BEEN_DEF_TEXT', {
  10166. bossLvl: `${svgBoss} ${bossLvl} ${svgJustice} ${justice}`,
  10167. countBattle: svgAttempt + ' ' + countBattle,
  10168. countMaxBattle,
  10169. winTimer,
  10170. }),
  10171. [
  10172. { msg: I18N('BTN_OK'), r###lt: 0 },
  10173. { msg: I18N('MAKE_A_SYNC'), r###lt: 1 },
  10174. { msg: I18N('RELOAD_GAME'), r###lt: 2 },
  10175. ]
  10176. );
  10177. if (r###lt) {
  10178. if (r###lt == 1) {
  10179. cheats.refreshGame();
  10180. }
  10181. if (r###lt == 2) {
  10182. location.reload();
  10183. }
  10184. }
  10185. }
  10186. endAutoBattle(`${I18N('SUCCESS')}!`)
  10187. });
  10188. }
  10189. /**
  10190. * Completing a task
  10191. *
  10192. * Завершение задачи
  10193. */
  10194. function endAutoBattle(reason, info) {
  10195. setIsCancalBattle(true);
  10196. console.log(reason, info);
  10197. resolve();
  10198. }
  10199. }
  10200. this.HWHClasses.executeAutoBattle = executeAutoBattle;
  10201. function testDailyQuests() {
  10202. const { dailyQuests } = HWHClasses;
  10203. return new Promise((resolve, reject) => {
  10204. const quests = new dailyQuests(resolve, reject);
  10205. quests.init(questsInfo);
  10206. quests.start();
  10207. });
  10208. }
  10209. /**
  10210. * Automatic completion of daily quests
  10211. *
  10212. * Автоматическое выполнение ежедневных квестов
  10213. */
  10214. class dailyQuests {
  10215. /**
  10216. * Send(' {"calls":[{"name":"userGetInfo","args":{},"ident":"body"}]}').then(e => console.log(e))
  10217. * Send(' {"calls":[{"name":"heroGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10218. * Send(' {"calls":[{"name":"titanGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10219. * Send(' {"calls":[{"name":"inventoryGet","args":{},"ident":"body"}]}').then(e => console.log(e))
  10220. * Send(' {"calls":[{"name":"questGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10221. * Send(' {"calls":[{"name":"bossGetAll","args":{},"ident":"body"}]}').then(e => console.log(e))
  10222. */
  10223. callsList = ['userGetInfo', 'heroGetAll', 'titanGetAll', 'inventoryGet', 'questGetAll', 'bossGetAll', 'missionGetAll'];
  10224. dataQuests = {
  10225. 10001: {
  10226. description: 'Улучши умения героев 3 раза', // ++++++++++++++++
  10227. doItCall: () => {
  10228. const upgradeSkills = this.getUpgradeSkills();
  10229. return upgradeSkills.map(({ heroId, skill }, index) => ({
  10230. name: 'heroUpgradeSkill',
  10231. args: { heroId, skill },
  10232. ident: `heroUpgradeSkill_${index}`,
  10233. }));
  10234. },
  10235. isWeCanDo: () => {
  10236. const upgradeSkills = this.getUpgradeSkills();
  10237. let sumGold = 0;
  10238. for (const skill of upgradeSkills) {
  10239. sumGold += this.skillCost(skill.value);
  10240. if (!skill.heroId) {
  10241. return false;
  10242. }
  10243. }
  10244. return this.questInfo['userGetInfo'].gold > sumGold;
  10245. },
  10246. },
  10247. 10002: {
  10248. description: 'Пройди 10 миссий', // --------------
  10249. isWeCanDo: () => false,
  10250. },
  10251. 10003: {
  10252. description: 'Пройди 3 героические миссии', // ++++++++++++++++
  10253. isWeCanDo: () => {
  10254. const vipPoints = +this.questInfo.userGetInfo.vipPoints;
  10255. const goldTicket = !!this.questInfo.inventoryGet.consumable[151];
  10256. return (vipPoints > 100 || goldTicket) && this.getHeroicMissionId();
  10257. },
  10258. doItCall: () => {
  10259. const selectedMissionId = this.getHeroicMissionId();
  10260. const goldTicket = !!this.questInfo.inventoryGet.consumable[151];
  10261. const vipLevel = Math.max(...lib.data.level.vip.filter(l => l.vipPoints <= +this.questInfo.userGetInfo.vipPoints).map(l => l.level));
  10262. // Возвращаем массив команд для рейда
  10263. if (vipLevel >= 5 || goldTicket) {
  10264. return [{ name: 'missionRaid', args: { id: selectedMissionId, times: 3 }, ident: 'missionRaid_1' }];
  10265. } else {
  10266. return [
  10267. { name: 'missionRaid', args: { id: selectedMissionId, times: 1 }, ident: 'missionRaid_1' },
  10268. { name: 'missionRaid', args: { id: selectedMissionId, times: 1 }, ident: 'missionRaid_2' },
  10269. { name: 'missionRaid', args: { id: selectedMissionId, times: 1 }, ident: 'missionRaid_3' },
  10270. ];
  10271. }
  10272. },
  10273. },
  10274. 10004: {
  10275. description: 'Сразись 3 раза на Арене или Гранд Арене', // --------------
  10276. isWeCanDo: () => false,
  10277. },
  10278. 10006: {
  10279. description: 'Используй обмен изумрудов 1 раз', // ++++++++++++++++
  10280. doItCall: () => [
  10281. {
  10282. name: 'refillableAlchemyUse',
  10283. args: { multi: false },
  10284. ident: 'refillableAlchemyUse',
  10285. },
  10286. ],
  10287. isWeCanDo: () => {
  10288. const starMoney = this.questInfo['userGetInfo'].starMoney;
  10289. return starMoney >= 20;
  10290. },
  10291. },
  10292. 10007: {
  10293. description: 'Соверши 1 призыв в Атриуме Душ', // ++++++++++++++++
  10294. doItCall: () => [{ name: 'gacha_open', args: { ident: 'heroGacha', free: true, pack: false }, ident: 'gacha_open' }],
  10295. isWeCanDo: () => {
  10296. const soulCrystal = this.questInfo['inventoryGet'].coin[38];
  10297. return soulCrystal > 0;
  10298. },
  10299. },
  10300. 10016: {
  10301. description: 'Отправь подарки согильдийцам', // ++++++++++++++++
  10302. doItCall: () => [{ name: 'clanSendDailyGifts', args: {}, ident: 'clanSendDailyGifts' }],
  10303. isWeCanDo: () => true,
  10304. },
  10305. 10018: {
  10306. description: 'Используй зелье опыта', // ++++++++++++++++
  10307. doItCall: () => {
  10308. const expHero = this.getExpHero();
  10309. return [
  10310. {
  10311. name: 'consumableUseHeroXp',
  10312. args: {
  10313. heroId: expHero.heroId,
  10314. libId: expHero.libId,
  10315. amount: 1,
  10316. },
  10317. ident: 'consumableUseHeroXp',
  10318. },
  10319. ];
  10320. },
  10321. isWeCanDo: () => {
  10322. const expHero = this.getExpHero();
  10323. return expHero.heroId && expHero.libId;
  10324. },
  10325. },
  10326. 10019: {
  10327. description: 'Открой 1 сундук в Башне',
  10328. doItFunc: testTower,
  10329. isWeCanDo: () => false,
  10330. },
  10331. 10020: {
  10332. description: 'Открой 3 сундука в Запределье', // Готово
  10333. doItCall: () => {
  10334. return this.getOutlandChest();
  10335. },
  10336. isWeCanDo: () => {
  10337. const outlandChest = this.getOutlandChest();
  10338. return outlandChest.length > 0;
  10339. },
  10340. },
  10341. 10021: {
  10342. description: 'Собери 75 Титанита в Подземелье Гильдии',
  10343. isWeCanDo: () => false,
  10344. },
  10345. 10022: {
  10346. description: 'Собери 150 Титанита в Подземелье Гильдии',
  10347. doItFunc: testDungeon,
  10348. isWeCanDo: () => false,
  10349. },
  10350. 10023: {
  10351. description: 'Прокачай Дар Стихий на 1 уровень', // Готово
  10352. doItCall: () => {
  10353. const heroId = this.getHeroIdTitanGift();
  10354. return [
  10355. { name: 'heroTitanGiftLevelUp', args: { heroId }, ident: 'heroTitanGiftLevelUp' },
  10356. { name: 'heroTitanGiftDrop', args: { heroId }, ident: 'heroTitanGiftDrop' },
  10357. ];
  10358. },
  10359. isWeCanDo: () => {
  10360. const heroId = this.getHeroIdTitanGift();
  10361. return heroId;
  10362. },
  10363. },
  10364. 10024: {
  10365. description: 'Повысь уровень любого артефакта один раз', // Готово
  10366. doItCall: () => {
  10367. const upArtifact = this.getUpgradeArtifact();
  10368. return [
  10369. {
  10370. name: 'heroArtifactLevelUp',
  10371. args: {
  10372. heroId: upArtifact.heroId,
  10373. slotId: upArtifact.slotId,
  10374. },
  10375. ident: `heroArtifactLevelUp`,
  10376. },
  10377. ];
  10378. },
  10379. isWeCanDo: () => {
  10380. const upgradeArtifact = this.getUpgradeArtifact();
  10381. return upgradeArtifact.heroId;
  10382. },
  10383. },
  10384. 10025: {
  10385. description: 'Начни 1 Экспедицию',
  10386. doItFunc: checkExpedition,
  10387. isWeCanDo: () => false,
  10388. },
  10389. 10026: {
  10390. description: 'Начни 4 Экспедиции', // --------------
  10391. doItFunc: checkExpedition,
  10392. isWeCanDo: () => false,
  10393. },
  10394. 10027: {
  10395. description: 'Победи в 1 бою Турнира Стихий',
  10396. doItFunc: testTitanArena,
  10397. isWeCanDo: () => false,
  10398. },
  10399. 10028: {
  10400. description: 'Повысь уровень любого артефакта титанов', // Готово
  10401. doItCall: () => {
  10402. const upTitanArtifact = this.getUpgradeTitanArtifact();
  10403. return [
  10404. {
  10405. name: 'titanArtifactLevelUp',
  10406. args: {
  10407. titanId: upTitanArtifact.titanId,
  10408. slotId: upTitanArtifact.slotId,
  10409. },
  10410. ident: `titanArtifactLevelUp`,
  10411. },
  10412. ];
  10413. },
  10414. isWeCanDo: () => {
  10415. const upgradeTitanArtifact = this.getUpgradeTitanArtifact();
  10416. return upgradeTitanArtifact.titanId;
  10417. },
  10418. },
  10419. 10029: {
  10420. description: 'Открой сферу артефактов титанов', // ++++++++++++++++
  10421. doItCall: () => [{ name: 'titanArtifactChestOpen', args: { amount: 1, free: true }, ident: 'titanArtifactChestOpen' }],
  10422. isWeCanDo: () => {
  10423. return this.questInfo['inventoryGet']?.consumable[55] > 0;
  10424. },
  10425. },
  10426. 10030: {
  10427. description: 'Улучши облик любого героя 1 раз', // Готово
  10428. doItCall: () => {
  10429. const upSkin = this.getUpgradeSkin();
  10430. return [
  10431. {
  10432. name: 'heroSkinUpgrade',
  10433. args: {
  10434. heroId: upSkin.heroId,
  10435. skinId: upSkin.skinId,
  10436. },
  10437. ident: `heroSkinUpgrade`,
  10438. },
  10439. ];
  10440. },
  10441. isWeCanDo: () => {
  10442. const upgradeSkin = this.getUpgradeSkin();
  10443. return upgradeSkin.heroId;
  10444. },
  10445. },
  10446. 10031: {
  10447. description: 'Победи в 6 боях Турнира Стихий', // --------------
  10448. doItFunc: testTitanArena,
  10449. isWeCanDo: () => false,
  10450. },
  10451. 10043: {
  10452. description: 'Начни или присоеденись к Приключению', // --------------
  10453. isWeCanDo: () => false,
  10454. },
  10455. 10044: {
  10456. description: 'Воспользуйся призывом питомцев 1 раз', // ++++++++++++++++
  10457. doItCall: () => [{ name: 'pet_chestOpen', args: { amount: 1, paid: false }, ident: 'pet_chestOpen' }],
  10458. isWeCanDo: () => {
  10459. return this.questInfo['inventoryGet']?.consumable[90] > 0;
  10460. },
  10461. },
  10462. 10046: {
  10463. /**
  10464. * TODO: Watch Adventure
  10465. * TODO: Смотреть приключение
  10466. */
  10467. description: 'Открой 3 сундука в Приключениях',
  10468. isWeCanDo: () => false,
  10469. },
  10470. 10047: {
  10471. description: 'Набери 150 очков активности в Гильдии', // Готово
  10472. doItCall: () => {
  10473. const enchantRune = this.getEnchantRune();
  10474. return [
  10475. {
  10476. name: 'heroEnchantRune',
  10477. args: {
  10478. heroId: enchantRune.heroId,
  10479. tier: enchantRune.tier,
  10480. items: {
  10481. consumable: { [enchantRune.itemId]: 1 },
  10482. },
  10483. },
  10484. ident: `heroEnchantRune`,
  10485. },
  10486. ];
  10487. },
  10488. isWeCanDo: () => {
  10489. const userInfo = this.questInfo['userGetInfo'];
  10490. const enchantRune = this.getEnchantRune();
  10491. return enchantRune.heroId && userInfo.gold > 1e3;
  10492. },
  10493. },
  10494. };
  10495. constructor(resolve, reject, questInfo) {
  10496. this.resolve = resolve;
  10497. this.reject = reject;
  10498. }
  10499. init(questInfo) {
  10500. this.questInfo = questInfo;
  10501. this.isAuto = false;
  10502. }
  10503. async autoInit(isAuto) {
  10504. this.isAuto = isAuto || false;
  10505. const quests = {};
  10506. const calls = this.callsList.map((name) => ({
  10507. name,
  10508. args: {},
  10509. ident: name,
  10510. }));
  10511. const r###lt = await Send(JSON.stringify({ calls })).then((e) => e.r###lts);
  10512. for (const call of r###lt) {
  10513. quests[call.ident] = call.r###lt.response;
  10514. }
  10515. this.questInfo = quests;
  10516. }
  10517. async start() {
  10518. const weCanDo = [];
  10519. const selectedActions = getSaveVal('selectedActions', {});
  10520. for (let quest of this.questInfo['questGetAll']) {
  10521. if (quest.id in this.dataQuests && quest.state == 1) {
  10522. if (!selectedActions[quest.id]) {
  10523. selectedActions[quest.id] = {
  10524. checked: false,
  10525. };
  10526. }
  10527. const isWeCanDo = this.dataQuests[quest.id].isWeCanDo;
  10528. if (!isWeCanDo.call(this)) {
  10529. continue;
  10530. }
  10531. weCanDo.push({
  10532. name: quest.id,
  10533. label: I18N(`QUEST_${quest.id}`),
  10534. checked: selectedActions[quest.id].checked,
  10535. });
  10536. }
  10537. }
  10538. if (!weCanDo.length) {
  10539. this.end(I18N('NOTHING_TO_DO'));
  10540. return;
  10541. }
  10542. console.log(weCanDo);
  10543. let taskList = [];
  10544. if (this.isAuto) {
  10545. taskList = weCanDo;
  10546. } else {
  10547. const answer = await popup.confirm(
  10548. `${I18N('YOU_CAN_COMPLETE')}:`,
  10549. [
  10550. { msg: I18N('BTN_DO_IT'), r###lt: true },
  10551. { msg: I18N('BTN_CANCEL'), r###lt: false, isCancel: true },
  10552. ],
  10553. weCanDo
  10554. );
  10555. if (!answer) {
  10556. this.end('');
  10557. return;
  10558. }
  10559. taskList = popup.getCheckBoxes();
  10560. taskList.forEach((e) => {
  10561. selectedActions[e.name].checked = e.checked;
  10562. });
  10563. setSaveVal('selectedActions', selectedActions);
  10564. }
  10565. const calls = [];
  10566. let countChecked = 0;
  10567. for (const task of taskList) {
  10568. if (task.checked) {
  10569. countChecked++;
  10570. const quest = this.dataQuests[task.name];
  10571. console.log(quest.description);
  10572. if (quest.doItCall) {
  10573. const doItCall = quest.doItCall.call(this);
  10574. calls.push(...doItCall);
  10575. }
  10576. }
  10577. }
  10578. if (!countChecked) {
  10579. this.end(I18N('NOT_QUEST_COMPLETED'));
  10580. return;
  10581. }
  10582. const r###lt = await Send(JSON.stringify({ calls }));
  10583. if (r###lt.error) {
  10584. console.error(r###lt.error, r###lt.error.call);
  10585. }
  10586. this.end(`${I18N('COMPLETED_QUESTS')}: ${countChecked}`);
  10587. }
  10588. errorHandling(error) {
  10589. //console.error(error);
  10590. let errorInfo = error.toString() + '\n';
  10591. try {
  10592. const errorStack = error.stack.split('\n');
  10593. const endStack = errorStack.map((e) => e.split('@')[0]).indexOf('testDoYourBest');
  10594. errorInfo += errorStack.slice(0, endStack).join('\n');
  10595. } catch (e) {
  10596. errorInfo += error.stack;
  10597. }
  10598. copyText(errorInfo);
  10599. }
  10600. skillCost(lvl) {
  10601. return 573 * lvl ** 0.9 + lvl ** 2.379;
  10602. }
  10603. getUpgradeSkills() {
  10604. const heroes = Object.values(this.questInfo['heroGetAll']);
  10605. const upgradeSkills = [
  10606. { heroId: 0, slotId: 0, value: 130 },
  10607. { heroId: 0, slotId: 0, value: 130 },
  10608. { heroId: 0, slotId: 0, value: 130 },
  10609. ];
  10610. const skillLib = lib.getData('skill');
  10611. /**
  10612. * color - 1 (белый) открывает 1 навык
  10613. * color - 2 (зеленый) открывает 2 навык
  10614. * color - 4 (синий) открывает 3 навык
  10615. * color - 7 (фиолетовый) открывает 4 навык
  10616. */
  10617. const colors = [1, 2, 4, 7];
  10618. for (const hero of heroes) {
  10619. const level = hero.level;
  10620. const color = hero.color;
  10621. for (let skillId in hero.skills) {
  10622. const tier = skillLib[skillId].tier;
  10623. const sVal = hero.skills[skillId];
  10624. if (color < colors[tier] || tier < 1 || tier > 4) {
  10625. continue;
  10626. }
  10627. for (let upSkill of upgradeSkills) {
  10628. if (sVal < upSkill.value && sVal < level) {
  10629. upSkill.value = sVal;
  10630. upSkill.heroId = hero.id;
  10631. upSkill.skill = tier;
  10632. break;
  10633. }
  10634. }
  10635. }
  10636. }
  10637. return upgradeSkills;
  10638. }
  10639. getUpgradeArtifact() {
  10640. const heroes = Object.values(this.questInfo['heroGetAll']);
  10641. const inventory = this.questInfo['inventoryGet'];
  10642. const upArt = { heroId: 0, slotId: 0, level: 100 };
  10643. const heroLib = lib.getData('hero');
  10644. const artifactLib = lib.getData('artifact');
  10645. for (const hero of heroes) {
  10646. const heroInfo = heroLib[hero.id];
  10647. const level = hero.level;
  10648. if (level < 20) {
  10649. continue;
  10650. }
  10651. for (let slotId in hero.artifacts) {
  10652. const art = hero.artifacts[slotId];
  10653. /* Текущая звезданость арта */
  10654. const star = art.star;
  10655. if (!star) {
  10656. continue;
  10657. }
  10658. /* Текущий уровень арта */
  10659. const level = art.level;
  10660. if (level >= 100) {
  10661. continue;
  10662. }
  10663. /* Идентификатор арта в библиотеке */
  10664. const artifactId = heroInfo.artifacts[slotId];
  10665. const artInfo = artifactLib.id[artifactId];
  10666. const costNextLevel = artifactLib.type[artInfo.type].levels[level + 1].cost;
  10667. const costCurrency = Object.keys(costNextLevel).pop();
  10668. const costValues = Object.entries(costNextLevel[costCurrency]).pop();
  10669. const costId = costValues[0];
  10670. const costValue = +costValues[1];
  10671. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10672. if (level < upArt.level && inventory[costCurrency][costId] >= costValue) {
  10673. upArt.level = level;
  10674. upArt.heroId = hero.id;
  10675. upArt.slotId = slotId;
  10676. upArt.costCurrency = costCurrency;
  10677. upArt.costId = costId;
  10678. upArt.costValue = costValue;
  10679. }
  10680. }
  10681. }
  10682. return upArt;
  10683. }
  10684. getUpgradeSkin() {
  10685. const heroes = Object.values(this.questInfo['heroGetAll']);
  10686. const inventory = this.questInfo['inventoryGet'];
  10687. const upSkin = { heroId: 0, skinId: 0, level: 60, cost: 1500 };
  10688. const skinLib = lib.getData('skin');
  10689. for (const hero of heroes) {
  10690. const level = hero.level;
  10691. if (level < 20) {
  10692. continue;
  10693. }
  10694. for (let skinId in hero.skins) {
  10695. /* Текущий уровень скина */
  10696. const level = hero.skins[skinId];
  10697. if (level >= 60) {
  10698. continue;
  10699. }
  10700. /* Идентификатор скина в библиотеке */
  10701. const skinInfo = skinLib[skinId];
  10702. if (!skinInfo.statData.levels?.[level + 1]) {
  10703. continue;
  10704. }
  10705. const costNextLevel = skinInfo.statData.levels[level + 1].cost;
  10706. const costCurrency = Object.keys(costNextLevel).pop();
  10707. const costCurrencyId = Object.keys(costNextLevel[costCurrency]).pop();
  10708. const costValue = +costNextLevel[costCurrency][costCurrencyId];
  10709. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10710. if (level < upSkin.level && costValue < upSkin.cost && inventory[costCurrency][costCurrencyId] >= costValue) {
  10711. upSkin.cost = costValue;
  10712. upSkin.level = level;
  10713. upSkin.heroId = hero.id;
  10714. upSkin.skinId = skinId;
  10715. upSkin.costCurrency = costCurrency;
  10716. upSkin.costCurrencyId = costCurrencyId;
  10717. }
  10718. }
  10719. }
  10720. return upSkin;
  10721. }
  10722. getUpgradeTitanArtifact() {
  10723. const titans = Object.values(this.questInfo['titanGetAll']);
  10724. const inventory = this.questInfo['inventoryGet'];
  10725. const userInfo = this.questInfo['userGetInfo'];
  10726. const upArt = { titanId: 0, slotId: 0, level: 120 };
  10727. const titanLib = lib.getData('titan');
  10728. const artTitanLib = lib.getData('titanArtifact');
  10729. for (const titan of titans) {
  10730. const titanInfo = titanLib[titan.id];
  10731. // const level = titan.level
  10732. // if (level < 20) {
  10733. // continue;
  10734. // }
  10735. for (let slotId in titan.artifacts) {
  10736. const art = titan.artifacts[slotId];
  10737. /* Текущая звезданость арта */
  10738. const star = art.star;
  10739. if (!star) {
  10740. continue;
  10741. }
  10742. /* Текущий уровень арта */
  10743. const level = art.level;
  10744. if (level >= 120) {
  10745. continue;
  10746. }
  10747. /* Идентификатор арта в библиотеке */
  10748. const artifactId = titanInfo.artifacts[slotId];
  10749. const artInfo = artTitanLib.id[artifactId];
  10750. const costNextLevel = artTitanLib.type[artInfo.type].levels[level + 1].cost;
  10751. const costCurrency = Object.keys(costNextLevel).pop();
  10752. let costValue = 0;
  10753. let currentValue = 0;
  10754. if (costCurrency == 'gold') {
  10755. costValue = costNextLevel[costCurrency];
  10756. currentValue = userInfo.gold;
  10757. } else {
  10758. const costValues = Object.entries(costNextLevel[costCurrency]).pop();
  10759. const costId = costValues[0];
  10760. costValue = +costValues[1];
  10761. currentValue = inventory[costCurrency][costId];
  10762. }
  10763. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10764. if (level < upArt.level && currentValue >= costValue) {
  10765. upArt.level = level;
  10766. upArt.titanId = titan.id;
  10767. upArt.slotId = slotId;
  10768. break;
  10769. }
  10770. }
  10771. }
  10772. return upArt;
  10773. }
  10774. getEnchantRune() {
  10775. const heroes = Object.values(this.questInfo['heroGetAll']);
  10776. const inventory = this.questInfo['inventoryGet'];
  10777. const enchRune = { heroId: 0, tier: 0, exp: 43750, itemId: 0 };
  10778. for (let i = 1; i <= 4; i++) {
  10779. if (inventory.consumable[i] > 0) {
  10780. enchRune.itemId = i;
  10781. break;
  10782. }
  10783. return enchRune;
  10784. }
  10785. const runeLib = lib.getData('rune');
  10786. const runeLvls = Object.values(runeLib.level);
  10787. /**
  10788. * color - 4 (синий) открывает 1 и 2 символ
  10789. * color - 7 (фиолетовый) открывает 3 символ
  10790. * color - 8 (фиолетовый +1) открывает 4 символ
  10791. * color - 9 (фиолетовый +2) открывает 5 символ
  10792. */
  10793. // TODO: кажется надо учесть уровень команды
  10794. const colors = [4, 4, 7, 8, 9];
  10795. for (const hero of heroes) {
  10796. const color = hero.color;
  10797. for (let runeTier in hero.runes) {
  10798. /* Проверка на доступность руны */
  10799. if (color < colors[runeTier]) {
  10800. continue;
  10801. }
  10802. /* Текущий опыт руны */
  10803. const exp = hero.runes[runeTier];
  10804. if (exp >= 43750) {
  10805. continue;
  10806. }
  10807. let level = 0;
  10808. if (exp) {
  10809. for (let lvl of runeLvls) {
  10810. if (exp >= lvl.enchantValue) {
  10811. level = lvl.level;
  10812. } else {
  10813. break;
  10814. }
  10815. }
  10816. }
  10817. /** Уровень героя необходимый для уровня руны */
  10818. const heroLevel = runeLib.level[level].heroLevel;
  10819. if (hero.level < heroLevel) {
  10820. continue;
  10821. }
  10822. /** TODO: Возможно стоит искать самый высокий уровень который можно качнуть? */
  10823. if (exp < enchRune.exp) {
  10824. enchRune.exp = exp;
  10825. enchRune.heroId = hero.id;
  10826. enchRune.tier = runeTier;
  10827. break;
  10828. }
  10829. }
  10830. }
  10831. return enchRune;
  10832. }
  10833. getOutlandChest() {
  10834. const bosses = this.questInfo['bossGetAll'];
  10835. const calls = [];
  10836. for (let boss of bosses) {
  10837. if (boss.mayRaid) {
  10838. calls.push({
  10839. name: 'bossRaid',
  10840. args: {
  10841. bossId: boss.id,
  10842. },
  10843. ident: 'bossRaid_' + boss.id,
  10844. });
  10845. calls.push({
  10846. name: 'bossOpenChest',
  10847. args: {
  10848. bossId: boss.id,
  10849. amount: 1,
  10850. starmoney: 0,
  10851. },
  10852. ident: 'bossOpenChest_' + boss.id,
  10853. });
  10854. } else if (boss.chestId == 1) {
  10855. calls.push({
  10856. name: 'bossOpenChest',
  10857. args: {
  10858. bossId: boss.id,
  10859. amount: 1,
  10860. starmoney: 0,
  10861. },
  10862. ident: 'bossOpenChest_' + boss.id,
  10863. });
  10864. }
  10865. }
  10866. return calls;
  10867. }
  10868. getExpHero() {
  10869. const heroes = Object.values(this.questInfo['heroGetAll']);
  10870. const inventory = this.questInfo['inventoryGet'];
  10871. const expHero = { heroId: 0, exp: 3625195, libId: 0 };
  10872. /** зелья опыта (consumable 9, 10, 11, 12) */
  10873. for (let i = 9; i <= 12; i++) {
  10874. if (inventory.consumable[i]) {
  10875. expHero.libId = i;
  10876. break;
  10877. }
  10878. }
  10879. for (const hero of heroes) {
  10880. const exp = hero.xp;
  10881. if (exp < expHero.exp) {
  10882. expHero.heroId = hero.id;
  10883. }
  10884. }
  10885. return expHero;
  10886. }
  10887. getHeroIdTitanGift() {
  10888. const heroes = Object.values(this.questInfo['heroGetAll']);
  10889. const inventory = this.questInfo['inventoryGet'];
  10890. const user = this.questInfo['userGetInfo'];
  10891. const titanGiftLib = lib.getData('titanGift');
  10892. /** Искры */
  10893. const titanGift = inventory.consumable[24];
  10894. let heroId = 0;
  10895. let minLevel = 30;
  10896. if (titanGift < 250 || user.gold < 7000) {
  10897. return 0;
  10898. }
  10899. for (const hero of heroes) {
  10900. if (hero.titanGiftLevel >= 30) {
  10901. continue;
  10902. }
  10903. if (!hero.titanGiftLevel) {
  10904. return hero.id;
  10905. }
  10906. const cost = titanGiftLib[hero.titanGiftLevel].cost;
  10907. if (minLevel > hero.titanGiftLevel && titanGift >= cost.consumable[24] && user.gold >= cost.gold) {
  10908. minLevel = hero.titanGiftLevel;
  10909. heroId = hero.id;
  10910. }
  10911. }
  10912. return heroId;
  10913. }
  10914. getHeroicMissionId() {
  10915. // Получаем доступные миссии с 3 звездами
  10916. const availableMissionsToRaid = Object.values(this.questInfo.missionGetAll)
  10917. .filter((mission) => mission.stars === 3)
  10918. .map((mission) => mission.id);
  10919. // Получаем героев для улучшения, у которых меньше 6 звезд
  10920. const heroesToUpgrade = Object.values(this.questInfo.heroGetAll)
  10921. .filter((hero) => hero.star < 6)
  10922. .sort((a, b) => b.power - a.power)
  10923. .map((hero) => hero.id);
  10924. // Получаем героические миссии, которые доступны для рейдов
  10925. const heroicMissions = Object.values(lib.data.mission).filter((mission) => mission.isHeroic && availableMissionsToRaid.includes(mission.id));
  10926. // Собираем дропы из героических миссий
  10927. const drops = heroicMissions.map((mission) => {
  10928. const lastWave = mission.normalMode.waves[mission.normalMode.waves.length - 1];
  10929. const allRewards = lastWave.enemies[lastWave.enemies.length - 1]
  10930. .drop.map((drop) => drop.reward);
  10931. const heroId = +Object.keys(allRewards.find((reward) => reward.fragmentHero).fragmentHero).pop();
  10932. return { id: mission.id, heroId };
  10933. });
  10934. // Определяем, какие дропы подходят для героев, которых нужно улучшить
  10935. const heroDrops = heroesToUpgrade.map((heroId) => drops.find((drop) => drop.heroId == heroId)).filter((drop) => drop);
  10936. const firstMission = heroDrops[0];
  10937. // Выбираем миссию для рейда
  10938. const selectedMissionId = firstMission ? firstMission.id : 1;
  10939. const stamina = this.questInfo.userGetInfo.refillable.find((x) => x.id == 1).amount;
  10940. const costMissions = 3 * lib.data.mission[selectedMissionId].normalMode.teamExp;
  10941. if (stamina < costMissions) {
  10942. console.log('Энергии не достаточно');
  10943. return 0;
  10944. }
  10945. return selectedMissionId;
  10946. }
  10947. end(status) {
  10948. setProgress(status, true);
  10949. this.resolve();
  10950. }
  10951. }
  10952. this.questRun = dailyQuests;
  10953. this.HWHClasses.dailyQuests = dailyQuests;
  10954. function testDoYourBest() {
  10955. const { doYourBest } = HWHClasses;
  10956. return new Promise((resolve, reject) => {
  10957. const doIt = new doYourBest(resolve, reject);
  10958. doIt.start();
  10959. });
  10960. }
  10961. /**
  10962. * Do everything button
  10963. *
  10964. * Кнопка сделать все
  10965. */
  10966. class doYourBest {
  10967. funcList = [
  10968. {
  10969. name: 'getOutland',
  10970. label: I18N('ASSEMBLE_OUTLAND'),
  10971. checked: false
  10972. },
  10973. {
  10974. name: 'testTower',
  10975. label: I18N('PASS_THE_TOWER'),
  10976. checked: false
  10977. },
  10978. {
  10979. name: 'checkExpedition',
  10980. label: I18N('CHECK_EXPEDITIONS'),
  10981. checked: false
  10982. },
  10983. {
  10984. name: 'testTitanArena',
  10985. label: I18N('COMPLETE_TOE'),
  10986. checked: false
  10987. },
  10988. {
  10989. name: 'mailGetAll',
  10990. label: I18N('COLLECT_MAIL'),
  10991. checked: false
  10992. },
  10993. {
  10994. name: 'collectAllStuff',
  10995. label: I18N('COLLECT_MISC'),
  10996. title: I18N('COLLECT_MISC_TITLE'),
  10997. checked: false
  10998. },
  10999. {
  11000. name: 'getDailyBonus',
  11001. label: I18N('DAILY_BONUS'),
  11002. checked: false
  11003. },
  11004. {
  11005. name: 'dailyQuests',
  11006. label: I18N('DO_DAILY_QUESTS'),
  11007. checked: false
  11008. },
  11009. {
  11010. name: 'rollAscension',
  11011. label: I18N('SEER_TITLE'),
  11012. checked: false
  11013. },
  11014. {
  11015. name: 'questAllFarm',
  11016. label: I18N('COLLECT_QUEST_REWARDS'),
  11017. checked: false
  11018. },
  11019. {
  11020. name: 'testDungeon',
  11021. label: I18N('COMPLETE_DUNGEON'),
  11022. checked: false
  11023. },
  11024. {
  11025. name: 'synchronization',
  11026. label: I18N('MAKE_A_SYNC'),
  11027. checked: false
  11028. },
  11029. {
  11030. name: 'reloadGame',
  11031. label: I18N('RELOAD_GAME'),
  11032. checked: false
  11033. },
  11034. ];
  11035. functions = {
  11036. getOutland,
  11037. testTower,
  11038. checkExpedition,
  11039. testTitanArena,
  11040. mailGetAll,
  11041. collectAllStuff: async () => {
  11042. await offerFarmAllReward();
  11043. 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"}]}');
  11044. },
  11045. dailyQuests: async function () {
  11046. const quests = new dailyQuests(() => { }, () => { });
  11047. await quests.autoInit(true);
  11048. await quests.start();
  11049. },
  11050. rollAscension,
  11051. getDailyBonus,
  11052. questAllFarm,
  11053. testDungeon,
  11054. synchronization: async () => {
  11055. cheats.refreshGame();
  11056. },
  11057. reloadGame: async () => {
  11058. location.reload();
  11059. },
  11060. }
  11061. constructor(resolve, reject, questInfo) {
  11062. this.resolve = resolve;
  11063. this.reject = reject;
  11064. this.questInfo = questInfo
  11065. }
  11066. async start() {
  11067. const selectedDoIt = getSaveVal('selectedDoIt', {});
  11068. this.funcList.forEach(task => {
  11069. if (!selectedDoIt[task.name]) {
  11070. selectedDoIt[task.name] = {
  11071. checked: task.checked
  11072. }
  11073. } else {
  11074. task.checked = selectedDoIt[task.name].checked
  11075. }
  11076. });
  11077. const answer = await popup.confirm(I18N('RUN_FUNCTION'), [
  11078. { msg: I18N('BTN_CANCEL'), r###lt: false, isCancel: true },
  11079. { msg: I18N('BTN_GO'), r###lt: true },
  11080. ], this.funcList);
  11081. if (!answer) {
  11082. this.end('');
  11083. return;
  11084. }
  11085. const taskList = popup.getCheckBoxes();
  11086. taskList.forEach(task => {
  11087. selectedDoIt[task.name].checked = task.checked;
  11088. });
  11089. setSaveVal('selectedDoIt', selectedDoIt);
  11090. for (const task of popup.getCheckBoxes()) {
  11091. if (task.checked) {
  11092. try {
  11093. setProgress(`${task.label} <br>${I18N('PERFORMED')}!`);
  11094. await this.functions[task.name]();
  11095. setProgress(`${task.label} <br>${I18N('DONE')}!`);
  11096. } catch (error) {
  11097. if (await popup.confirm(`${I18N('ERRORS_OCCURRES')}:<br> ${task.label} <br>${I18N('COPY_ERROR')}?`, [
  11098. { msg: I18N('BTN_NO'), r###lt: false },
  11099. { msg: I18N('BTN_YES'), r###lt: true },
  11100. ])) {
  11101. this.errorHandling(error);
  11102. }
  11103. }
  11104. }
  11105. }
  11106. setTimeout((msg) => {
  11107. this.end(msg);
  11108. }, 2000, I18N('ALL_TASK_COMPLETED'));
  11109. return;
  11110. }
  11111. errorHandling(error) {
  11112. //console.error(error);
  11113. let errorInfo = error.toString() + '\n';
  11114. try {
  11115. const errorStack = error.stack.split('\n');
  11116. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testDoYourBest");
  11117. errorInfo += errorStack.slice(0, endStack).join('\n');
  11118. } catch (e) {
  11119. errorInfo += error.stack;
  11120. }
  11121. copyText(errorInfo);
  11122. }
  11123. end(status) {
  11124. setProgress(status, true);
  11125. this.resolve();
  11126. }
  11127. }
  11128. this.HWHClasses.doYourBest = doYourBest;
  11129. /**
  11130. * Passing the adventure along the specified route
  11131. *
  11132. * Прохождение приключения по указанному маршруту
  11133. */
  11134. function testAdventure(type) {
  11135. const { executeAdventure } = HWHClasses;
  11136. return new Promise((resolve, reject) => {
  11137. const bossBattle = new executeAdventure(resolve, reject);
  11138. bossBattle.start(type);
  11139. });
  11140. }
  11141. /**
  11142. * Passing the adventure along the specified route
  11143. *
  11144. * Прохождение приключения по указанному маршруту
  11145. */
  11146. class executeAdventure {
  11147. type = 'default';
  11148. actions = {
  11149. default: {
  11150. getInfo: "adventure_getInfo",
  11151. startBattle: 'adventure_turnStartBattle',
  11152. endBattle: 'adventure_endBattle',
  11153. collectBuff: 'adventure_turnCollectBuff'
  11154. },
  11155. solo: {
  11156. getInfo: "adventureSolo_getInfo",
  11157. startBattle: 'adventureSolo_turnStartBattle',
  11158. endBattle: 'adventureSolo_endBattle',
  11159. collectBuff: 'adventureSolo_turnCollectBuff'
  11160. }
  11161. }
  11162. terminatеReason = I18N('UNKNOWN');
  11163. callAdventureInfo = {
  11164. name: "adventure_getInfo",
  11165. args: {},
  11166. ident: "adventure_getInfo"
  11167. }
  11168. callTeamGetAll = {
  11169. name: "teamGetAll",
  11170. args: {},
  11171. ident: "teamGetAll"
  11172. }
  11173. callTeamGetFavor = {
  11174. name: "teamGetFavor",
  11175. args: {},
  11176. ident: "teamGetFavor"
  11177. }
  11178. callStartBattle = {
  11179. name: "adventure_turnStartBattle",
  11180. args: {},
  11181. ident: "body"
  11182. }
  11183. callEndBattle = {
  11184. name: "adventure_endBattle",
  11185. args: {
  11186. r###lt: {},
  11187. progress: {},
  11188. },
  11189. ident: "body"
  11190. }
  11191. callCollectBuff = {
  11192. name: "adventure_turnCollectBuff",
  11193. args: {},
  11194. ident: "body"
  11195. }
  11196. constructor(resolve, reject) {
  11197. this.resolve = resolve;
  11198. this.reject = reject;
  11199. }
  11200. async start(type) {
  11201. this.type = type || this.type;
  11202. this.callAdventureInfo.name = this.actions[this.type].getInfo;
  11203. const data = await Send(JSON.stringify({
  11204. calls: [
  11205. this.callAdventureInfo,
  11206. this.callTeamGetAll,
  11207. this.callTeamGetFavor
  11208. ]
  11209. }));
  11210. return this.checkAdventureInfo(data.r###lts);
  11211. }
  11212. async getPath() {
  11213. const oldVal = getSaveVal('adventurePath', '');
  11214. const keyPath = `adventurePath:${this.mapIdent}`;
  11215. const answer = await popup.confirm(I18N('ENTER_THE_PATH'), [
  11216. {
  11217. msg: I18N('START_ADVENTURE'),
  11218. placeholder: '1,2,3,4,5,6',
  11219. isInput: true,
  11220. default: getSaveVal(keyPath, oldVal)
  11221. },
  11222. {
  11223. msg: I18N('BTN_CANCEL'),
  11224. r###lt: false,
  11225. isCancel: true
  11226. },
  11227. ]);
  11228. if (!answer) {
  11229. this.terminatеReason = I18N('BTN_CANCELED');
  11230. return false;
  11231. }
  11232. let path = answer.split(',');
  11233. if (path.length < 2) {
  11234. path = answer.split('-');
  11235. }
  11236. if (path.length < 2) {
  11237. this.terminatеReason = I18N('MUST_TWO_POINTS');
  11238. return false;
  11239. }
  11240. for (let p in path) {
  11241. path[p] = +path[p].trim()
  11242. if (Number.isNaN(path[p])) {
  11243. this.terminatеReason = I18N('MUST_ONLY_NUMBERS');
  11244. return false;
  11245. }
  11246. }
  11247. if (!this.checkPath(path)) {
  11248. return false;
  11249. }
  11250. setSaveVal(keyPath, answer);
  11251. return path;
  11252. }
  11253. checkPath(path) {
  11254. for (let i = 0; i < path.length - 1; i++) {
  11255. const currentPoint = path[i];
  11256. const nextPoint = path[i + 1];
  11257. const isValidPath = this.paths.some(p =>
  11258. (p.from_id === currentPoint && p.to_id === nextPoint) ||
  11259. (p.from_id === nextPoint && p.to_id === currentPoint)
  11260. );
  11261. if (!isValidPath) {
  11262. this.terminatеReason = I18N('INCORRECT_WAY', {
  11263. from: currentPoint,
  11264. to: nextPoint,
  11265. });
  11266. return false;
  11267. }
  11268. }
  11269. return true;
  11270. }
  11271. async checkAdventureInfo(data) {
  11272. this.advInfo = data[0].r###lt.response;
  11273. if (!this.advInfo) {
  11274. this.terminatеReason = I18N('NOT_ON_AN_ADVENTURE') ;
  11275. return this.end();
  11276. }
  11277. const heroesTeam = data[1].r###lt.response.adventure_hero;
  11278. const favor = data[2]?.r###lt.response.adventure_hero;
  11279. const heroes = heroesTeam.slice(0, 5);
  11280. const pet = heroesTeam[5];
  11281. this.args = {
  11282. pet,
  11283. heroes,
  11284. favor,
  11285. path: [],
  11286. broadcast: false
  11287. }
  11288. const advUserInfo = this.advInfo.users[userInfo.id];
  11289. this.turnsLeft = advUserInfo.turnsLeft;
  11290. this.currentNode = advUserInfo.currentNode;
  11291. this.nodes = this.advInfo.nodes;
  11292. this.paths = this.advInfo.paths;
  11293. this.mapIdent = this.advInfo.mapIdent;
  11294. this.path = await this.getPath();
  11295. if (!this.path) {
  11296. return this.end();
  11297. }
  11298. if (this.currentNode == 1 && this.path[0] != 1) {
  11299. this.path.unshift(1);
  11300. }
  11301. return this.loop();
  11302. }
  11303. async loop() {
  11304. const position = this.path.indexOf(+this.currentNode);
  11305. if (!(~position)) {
  11306. this.terminatеReason = I18N('YOU_IN_NOT_ON_THE_WAY');
  11307. return this.end();
  11308. }
  11309. this.path = this.path.slice(position);
  11310. if ((this.path.length - 1) > this.turnsLeft &&
  11311. await popup.confirm(I18N('ATTEMPTS_NOT_ENOUGH'), [
  11312. { msg: I18N('YES_CONTINUE'), r###lt: false },
  11313. { msg: I18N('BTN_NO'), r###lt: true },
  11314. ])) {
  11315. this.terminatеReason = I18N('NOT_ENOUGH_AP');
  11316. return this.end();
  11317. }
  11318. const toPath = [];
  11319. for (const nodeId of this.path) {
  11320. if (!this.turnsLeft) {
  11321. this.terminatеReason = I18N('ATTEMPTS_ARE_OVER');
  11322. return this.end();
  11323. }
  11324. toPath.push(nodeId);
  11325. console.log(toPath);
  11326. if (toPath.length > 1) {
  11327. setProgress(toPath.join(' > ') + ` ${I18N('MOVES')}: ` + this.turnsLeft);
  11328. }
  11329. if (nodeId == this.currentNode) {
  11330. continue;
  11331. }
  11332. const nodeInfo = this.getNodeInfo(nodeId);
  11333. if (nodeInfo.type == 'TYPE_COMBAT') {
  11334. if (nodeInfo.state == 'empty') {
  11335. this.turnsLeft--;
  11336. continue;
  11337. }
  11338. /**
  11339. * Disable regular battle cancellation
  11340. *
  11341. * Отключаем штатную отменую боя
  11342. */
  11343. setIsCancalBattle(false);
  11344. if (await this.battle(toPath)) {
  11345. this.turnsLeft--;
  11346. toPath.splice(0, toPath.indexOf(nodeId));
  11347. nodeInfo.state = 'empty';
  11348. setIsCancalBattle(true);
  11349. continue;
  11350. }
  11351. setIsCancalBattle(true);
  11352. return this.end()
  11353. }
  11354. if (nodeInfo.type == 'TYPE_PLAYERBUFF') {
  11355. const buff = this.checkBuff(nodeInfo);
  11356. if (buff == null) {
  11357. continue;
  11358. }
  11359. if (await this.collectBuff(buff, toPath)) {
  11360. this.turnsLeft--;
  11361. toPath.splice(0, toPath.indexOf(nodeId));
  11362. continue;
  11363. }
  11364. this.terminatеReason = I18N('BUFF_GET_ERROR');
  11365. return this.end();
  11366. }
  11367. }
  11368. this.terminatеReason = I18N('SUCCESS');
  11369. return this.end();
  11370. }
  11371. /**
  11372. * Carrying out a fight
  11373. *
  11374. * Проведение боя
  11375. */
  11376. async battle(path, preCalc = true) {
  11377. const data = await this.startBattle(path);
  11378. try {
  11379. const battle = data.r###lts[0].r###lt.response.battle;
  11380. const r###lt = await Calc(battle);
  11381. if (r###lt.r###lt.win) {
  11382. const info = await this.endBattle(r###lt);
  11383. if (info.r###lts[0].r###lt.response?.error) {
  11384. this.terminatеReason = I18N('BATTLE_END_ERROR');
  11385. return false;
  11386. }
  11387. } else {
  11388. await this.cancelBattle(r###lt);
  11389. if (preCalc && await this.preCalcBattle(battle)) {
  11390. path = path.slice(-2);
  11391. for (let i = 1; i <= getInput('countAutoBattle'); i++) {
  11392. setProgress(`${I18N('AUTOBOT')}: ${i}/${getInput('countAutoBattle')}`);
  11393. const r###lt = await this.battle(path, false);
  11394. if (r###lt) {
  11395. setProgress(I18N('VICTORY'));
  11396. return true;
  11397. }
  11398. }
  11399. this.terminatеReason = I18N('FAILED_TO_WIN_AUTO');
  11400. return false;
  11401. }
  11402. return false;
  11403. }
  11404. } catch (error) {
  11405. console.error(error);
  11406. if (await popup.confirm(I18N('ERROR_OF_THE_BATTLE_COPY'), [
  11407. { msg: I18N('BTN_NO'), r###lt: false },
  11408. { msg: I18N('BTN_YES'), r###lt: true },
  11409. ])) {
  11410. this.errorHandling(error, data);
  11411. }
  11412. this.terminatеReason = I18N('ERROR_DURING_THE_BATTLE');
  11413. return false;
  11414. }
  11415. return true;
  11416. }
  11417. /**
  11418. * Recalculate battles
  11419. *
  11420. * Прерасчтет битвы
  11421. */
  11422. async preCalcBattle(battle) {
  11423. const countTestBattle = getInput('countTestBattle');
  11424. for (let i = 0; i < countTestBattle; i++) {
  11425. battle.seed = Math.floor(Date.now() / 1000) + random(0, 1e3);
  11426. const r###lt = await Calc(battle);
  11427. if (r###lt.r###lt.win) {
  11428. console.log(i, countTestBattle);
  11429. return true;
  11430. }
  11431. }
  11432. this.terminatеReason = I18N('NO_CHANCE_WIN') + countTestBattle;
  11433. return false;
  11434. }
  11435. /**
  11436. * Starts a fight
  11437. *
  11438. * Начинает бой
  11439. */
  11440. startBattle(path) {
  11441. this.args.path = path;
  11442. this.callStartBattle.name = this.actions[this.type].startBattle;
  11443. this.callStartBattle.args = this.args
  11444. const calls = [this.callStartBattle];
  11445. return Send(JSON.stringify({ calls }));
  11446. }
  11447. cancelBattle(battle) {
  11448. const fixBattle = function (heroes) {
  11449. for (const ids in heroes) {
  11450. const hero = heroes[ids];
  11451. hero.energy = random(1, 999);
  11452. if (hero.hp > 0) {
  11453. hero.hp = random(1, hero.hp);
  11454. }
  11455. }
  11456. }
  11457. fixBattle(battle.progress[0].attackers.heroes);
  11458. fixBattle(battle.progress[0].defenders.heroes);
  11459. return this.endBattle(battle);
  11460. }
  11461. /**
  11462. * Ends the fight
  11463. *
  11464. * Заканчивает бой
  11465. */
  11466. endBattle(battle) {
  11467. this.callEndBattle.name = this.actions[this.type].endBattle;
  11468. this.callEndBattle.args.r###lt = battle.r###lt
  11469. this.callEndBattle.args.progress = battle.progress
  11470. const calls = [this.callEndBattle];
  11471. return Send(JSON.stringify({ calls }));
  11472. }
  11473. /**
  11474. * Checks if you can get a buff
  11475. *
  11476. * Проверяет можно ли получить баф
  11477. */
  11478. checkBuff(nodeInfo) {
  11479. let id = null;
  11480. let value = 0;
  11481. for (const buffId in nodeInfo.buffs) {
  11482. const buff = nodeInfo.buffs[buffId];
  11483. if (buff.owner == null && buff.value > value) {
  11484. id = buffId;
  11485. value = buff.value;
  11486. }
  11487. }
  11488. nodeInfo.buffs[id].owner = 'Я';
  11489. return id;
  11490. }
  11491. /**
  11492. * Collects a buff
  11493. *
  11494. * Собирает баф
  11495. */
  11496. async collectBuff(buff, path) {
  11497. this.callCollectBuff.name = this.actions[this.type].collectBuff;
  11498. this.callCollectBuff.args = { buff, path };
  11499. const calls = [this.callCollectBuff];
  11500. return Send(JSON.stringify({ calls }));
  11501. }
  11502. getNodeInfo(nodeId) {
  11503. return this.nodes.find(node => node.id == nodeId);
  11504. }
  11505. errorHandling(error, data) {
  11506. //console.error(error);
  11507. let errorInfo = error.toString() + '\n';
  11508. try {
  11509. const errorStack = error.stack.split('\n');
  11510. const endStack = errorStack.map(e => e.split('@')[0]).indexOf("testAdventure");
  11511. errorInfo += errorStack.slice(0, endStack).join('\n');
  11512. } catch (e) {
  11513. errorInfo += error.stack;
  11514. }
  11515. if (data) {
  11516. errorInfo += '\nData: ' + JSON.stringify(data);
  11517. }
  11518. copyText(errorInfo);
  11519. }
  11520. end() {
  11521. setIsCancalBattle(true);
  11522. setProgress(this.terminatеReason, true);
  11523. console.log(this.terminatеReason);
  11524. this.resolve();
  11525. }
  11526. }
  11527. this.HWHClasses.executeAdventure = executeAdventure;
  11528. /**
  11529. * Passage of brawls
  11530. *
  11531. * Прохождение потасовок
  11532. */
  11533. function testBrawls(isAuto) {
  11534. const { executeBrawls } = HWHClasses;
  11535. return new Promise((resolve, reject) => {
  11536. const brawls = new executeBrawls(resolve, reject);
  11537. brawls.start(brawlsPack, isAuto);
  11538. });
  11539. }
  11540. /**
  11541. * Passage of brawls
  11542. *
  11543. * Прохождение потасовок
  11544. */
  11545. class executeBrawls {
  11546. callBrawlQuestGetInfo = {
  11547. name: "brawl_questGetInfo",
  11548. args: {},
  11549. ident: "brawl_questGetInfo"
  11550. }
  11551. callBrawlFindEnemies = {
  11552. name: "brawl_findEnemies",
  11553. args: {},
  11554. ident: "brawl_findEnemies"
  11555. }
  11556. callBrawlQuestFarm = {
  11557. name: "brawl_questFarm",
  11558. args: {},
  11559. ident: "brawl_questFarm"
  11560. }
  11561. callUserGetInfo = {
  11562. name: "userGetInfo",
  11563. args: {},
  11564. ident: "userGetInfo"
  11565. }
  11566. callTeamGetMaxUpgrade = {
  11567. name: "teamGetMaxUpgrade",
  11568. args: {},
  11569. ident: "teamGetMaxUpgrade"
  11570. }
  11571. callBrawlGetInfo = {
  11572. name: "brawl_getInfo",
  11573. args: {},
  11574. ident: "brawl_getInfo"
  11575. }
  11576. stats = {
  11577. win: 0,
  11578. loss: 0,
  11579. count: 0,
  11580. }
  11581. stage = {
  11582. '3': 1,
  11583. '7': 2,
  11584. '12': 3,
  11585. }
  11586. attempts = 0;
  11587. constructor(resolve, reject) {
  11588. this.resolve = resolve;
  11589. this.reject = reject;
  11590. const allHeroIds = Object.keys(lib.getData('hero'));
  11591. this.callTeamGetMaxUpgrade.args.units = {
  11592. hero: allHeroIds.filter((id) => +id < 1000),
  11593. titan: allHeroIds.filter((id) => +id >= 4000 && +id < 4100),
  11594. pet: allHeroIds.filter((id) => +id >= 6000 && +id < 6100),
  11595. };
  11596. }
  11597. async start(args, isAuto) {
  11598. this.isAuto = isAuto;
  11599. this.args = args;
  11600. setIsCancalBattle(false);
  11601. this.brawlInfo = await this.getBrawlInfo();
  11602. this.attempts = this.brawlInfo.attempts;
  11603. if (!this.attempts && !this.info.boughtEndlessLivesToday) {
  11604. this.end(I18N('DONT_HAVE_LIVES'));
  11605. return;
  11606. }
  11607. while (1) {
  11608. if (!isBrawlsAutoStart) {
  11609. this.end(I18N('BTN_CANCELED'));
  11610. return;
  11611. }
  11612. const maxStage = this.brawlInfo.questInfo.stage;
  11613. const stage = this.stage[maxStage];
  11614. const progress = this.brawlInfo.questInfo.progress;
  11615. setProgress(
  11616. `${I18N('STAGE')} ${stage}: ${progress}/${maxStage}<br>${I18N('FIGHTS')}: ${this.stats.count}<br>${I18N('WINS')}: ${
  11617. this.stats.win
  11618. }<br>${I18N('LOSSES')}: ${this.stats.loss}<br>${I18N('LIVES')}: ${this.attempts}<br>${I18N('STOP')}`,
  11619. false,
  11620. function () {
  11621. isBrawlsAutoStart = false;
  11622. }
  11623. );
  11624. if (this.brawlInfo.questInfo.canFarm) {
  11625. const r###lt = await this.questFarm();
  11626. console.log(r###lt);
  11627. }
  11628. if (!this.continueAttack && this.brawlInfo.questInfo.stage == 12 && this.brawlInfo.questInfo.progress == 12) {
  11629. if (
  11630. await popup.confirm(I18N('BRAWL_DAILY_TASK_COMPLETED'), [
  11631. { msg: I18N('BTN_NO'), r###lt: true },
  11632. { msg: I18N('BTN_YES'), r###lt: false },
  11633. ])
  11634. ) {
  11635. this.end(I18N('SUCCESS'));
  11636. return;
  11637. } else {
  11638. this.continueAttack = true;
  11639. }
  11640. }
  11641. if (!this.attempts && !this.info.boughtEndlessLivesToday) {
  11642. this.end(I18N('DONT_HAVE_LIVES'));
  11643. return;
  11644. }
  11645. const enemie = Object.values(this.brawlInfo.findEnemies).shift();
  11646. // Автоматический подбор пачки
  11647. if (this.isAuto) {
  11648. if (this.mandatoryId <= 4000 && this.mandatoryId != 13) {
  11649. this.end(I18N('BRAWL_AUTO_PACK_NOT_CUR_HERO'));
  11650. return;
  11651. }
  11652. if (this.mandatoryId >= 4000 && this.mandatoryId < 4100) {
  11653. this.args = await this.updateTitanPack(enemie.heroes);
  11654. } else if (this.mandatoryId < 4000 && this.mandatoryId == 13) {
  11655. this.args = await this.updateHeroesPack(enemie.heroes);
  11656. }
  11657. }
  11658. const r###lt = await this.battle(enemie.userId);
  11659. this.brawlInfo = {
  11660. questInfo: r###lt[1].r###lt.response,
  11661. findEnemies: r###lt[2].r###lt.response,
  11662. };
  11663. }
  11664. }
  11665. async updateTitanPack(enemieHeroes) {
  11666. const packs = [
  11667. [4033, 4040, 4041, 4042, 4043],
  11668. [4032, 4040, 4041, 4042, 4043],
  11669. [4031, 4040, 4041, 4042, 4043],
  11670. [4030, 4040, 4041, 4042, 4043],
  11671. [4032, 4033, 4040, 4042, 4043],
  11672. [4030, 4033, 4041, 4042, 4043],
  11673. [4031, 4033, 4040, 4042, 4043],
  11674. [4032, 4033, 4040, 4041, 4043],
  11675. [4023, 4040, 4041, 4042, 4043],
  11676. [4030, 4033, 4040, 4042, 4043],
  11677. [4031, 4033, 4040, 4041, 4043],
  11678. [4022, 4040, 4041, 4042, 4043],
  11679. [4030, 4033, 4040, 4041, 4043],
  11680. [4021, 4040, 4041, 4042, 4043],
  11681. [4020, 4040, 4041, 4042, 4043],
  11682. [4023, 4033, 4040, 4042, 4043],
  11683. [4030, 4032, 4033, 4042, 4043],
  11684. [4023, 4033, 4040, 4041, 4043],
  11685. [4031, 4032, 4033, 4040, 4043],
  11686. [4030, 4032, 4033, 4041, 4043],
  11687. [4030, 4031, 4033, 4042, 4043],
  11688. [4013, 4040, 4041, 4042, 4043],
  11689. [4030, 4032, 4033, 4040, 4043],
  11690. [4030, 4031, 4033, 4041, 4043],
  11691. [4012, 4040, 4041, 4042, 4043],
  11692. [4030, 4031, 4033, 4040, 4043],
  11693. [4011, 4040, 4041, 4042, 4043],
  11694. [4010, 4040, 4041, 4042, 4043],
  11695. [4023, 4032, 4033, 4042, 4043],
  11696. [4022, 4032, 4033, 4042, 4043],
  11697. [4023, 4032, 4033, 4041, 4043],
  11698. [4021, 4032, 4033, 4042, 4043],
  11699. [4022, 4032, 4033, 4041, 4043],
  11700. [4023, 4030, 4033, 4042, 4043],
  11701. [4023, 4032, 4033, 4040, 4043],
  11702. [4013, 4033, 4040, 4042, 4043],
  11703. [4020, 4032, 4033, 4042, 4043],
  11704. [4021, 4032, 4033, 4041, 4043],
  11705. [4022, 4030, 4033, 4042, 4043],
  11706. [4022, 4032, 4033, 4040, 4043],
  11707. [4023, 4030, 4033, 4041, 4043],
  11708. [4023, 4031, 4033, 4040, 4043],
  11709. [4013, 4033, 4040, 4041, 4043],
  11710. [4020, 4031, 4033, 4042, 4043],
  11711. [4020, 4032, 4033, 4041, 4043],
  11712. [4021, 4030, 4033, 4042, 4043],
  11713. [4021, 4032, 4033, 4040, 4043],
  11714. [4022, 4030, 4033, 4041, 4043],
  11715. [4022, 4031, 4033, 4040, 4043],
  11716. [4023, 4030, 4033, 4040, 4043],
  11717. [4030, 4031, 4032, 4033, 4043],
  11718. [4003, 4040, 4041, 4042, 4043],
  11719. [4020, 4030, 4033, 4042, 4043],
  11720. [4020, 4031, 4033, 4041, 4043],
  11721. [4020, 4032, 4033, 4040, 4043],
  11722. [4021, 4030, 4033, 4041, 4043],
  11723. [4021, 4031, 4033, 4040, 4043],
  11724. [4022, 4030, 4033, 4040, 4043],
  11725. [4030, 4031, 4032, 4033, 4042],
  11726. [4002, 4040, 4041, 4042, 4043],
  11727. [4020, 4030, 4033, 4041, 4043],
  11728. [4020, 4031, 4033, 4040, 4043],
  11729. [4021, 4030, 4033, 4040, 4043],
  11730. [4030, 4031, 4032, 4033, 4041],
  11731. [4001, 4040, 4041, 4042, 4043],
  11732. [4030, 4031, 4032, 4033, 4040],
  11733. [4000, 4040, 4041, 4042, 4043],
  11734. [4013, 4032, 4033, 4042, 4043],
  11735. [4012, 4032, 4033, 4042, 4043],
  11736. [4013, 4032, 4033, 4041, 4043],
  11737. [4023, 4031, 4032, 4033, 4043],
  11738. [4011, 4032, 4033, 4042, 4043],
  11739. [4012, 4032, 4033, 4041, 4043],
  11740. [4013, 4030, 4033, 4042, 4043],
  11741. [4013, 4032, 4033, 4040, 4043],
  11742. [4023, 4030, 4032, 4033, 4043],
  11743. [4003, 4033, 4040, 4042, 4043],
  11744. [4013, 4023, 4040, 4042, 4043],
  11745. [4010, 4032, 4033, 4042, 4043],
  11746. [4011, 4032, 4033, 4041, 4043],
  11747. [4012, 4030, 4033, 4042, 4043],
  11748. [4012, 4032, 4033, 4040, 4043],
  11749. [4013, 4030, 4033, 4041, 4043],
  11750. [4013, 4031, 4033, 4040, 4043],
  11751. [4023, 4030, 4031, 4033, 4043],
  11752. [4003, 4033, 4040, 4041, 4043],
  11753. [4013, 4023, 4040, 4041, 4043],
  11754. [4010, 4031, 4033, 4042, 4043],
  11755. [4010, 4032, 4033, 4041, 4043],
  11756. [4011, 4030, 4033, 4042, 4043],
  11757. [4011, 4032, 4033, 4040, 4043],
  11758. [4012, 4030, 4033, 4041, 4043],
  11759. [4012, 4031, 4033, 4040, 4043],
  11760. [4013, 4030, 4033, 4040, 4043],
  11761. [4010, 4030, 4033, 4042, 4043],
  11762. [4010, 4031, 4033, 4041, 4043],
  11763. [4010, 4032, 4033, 4040, 4043],
  11764. [4011, 4030, 4033, 4041, 4043],
  11765. [4011, 4031, 4033, 4040, 4043],
  11766. [4012, 4030, 4033, 4040, 4043],
  11767. [4010, 4030, 4033, 4041, 4043],
  11768. [4010, 4031, 4033, 4040, 4043],
  11769. [4011, 4030, 4033, 4040, 4043],
  11770. [4003, 4032, 4033, 4042, 4043],
  11771. [4002, 4032, 4033, 4042, 4043],
  11772. [4003, 4032, 4033, 4041, 4043],
  11773. [4013, 4031, 4032, 4033, 4043],
  11774. [4001, 4032, 4033, 4042, 4043],
  11775. [4002, 4032, 4033, 4041, 4043],
  11776. [4003, 4030, 4033, 4042, 4043],
  11777. [4003, 4032, 4033, 4040, 4043],
  11778. [4013, 4030, 4032, 4033, 4043],
  11779. [4003, 4023, 4040, 4042, 4043],
  11780. [4000, 4032, 4033, 4042, 4043],
  11781. [4001, 4032, 4033, 4041, 4043],
  11782. [4002, 4030, 4033, 4042, 4043],
  11783. [4002, 4032, 4033, 4040, 4043],
  11784. [4003, 4030, 4033, 4041, 4043],
  11785. [4003, 4031, 4033, 4040, 4043],
  11786. [4020, 4022, 4023, 4042, 4043],
  11787. [4013, 4030, 4031, 4033, 4043],
  11788. [4003, 4023, 4040, 4041, 4043],
  11789. [4000, 4031, 4033, 4042, 4043],
  11790. [4000, 4032, 4033, 4041, 4043],
  11791. [4001, 4030, 4033, 4042, 4043],
  11792. [4001, 4032, 4033, 4040, 4043],
  11793. [4002, 4030, 4033, 4041, 4043],
  11794. [4002, 4031, 4033, 4040, 4043],
  11795. [4003, 4030, 4033, 4040, 4043],
  11796. [4021, 4022, 4023, 4040, 4043],
  11797. [4020, 4022, 4023, 4041, 4043],
  11798. [4020, 4021, 4023, 4042, 4043],
  11799. [4023, 4030, 4031, 4032, 4033],
  11800. [4000, 4030, 4033, 4042, 4043],
  11801. [4000, 4031, 4033, 4041, 4043],
  11802. [4000, 4032, 4033, 4040, 4043],
  11803. [4001, 4030, 4033, 4041, 4043],
  11804. [4001, 4031, 4033, 4040, 4043],
  11805. [4002, 4030, 4033, 4040, 4043],
  11806. [4020, 4022, 4023, 4040, 4043],
  11807. [4020, 4021, 4023, 4041, 4043],
  11808. [4022, 4030, 4031, 4032, 4033],
  11809. [4000, 4030, 4033, 4041, 4043],
  11810. [4000, 4031, 4033, 4040, 4043],
  11811. [4001, 4030, 4033, 4040, 4043],
  11812. [4020, 4021, 4023, 4040, 4043],
  11813. [4021, 4030, 4031, 4032, 4033],
  11814. [4020, 4030, 4031, 4032, 4033],
  11815. [4003, 4031, 4032, 4033, 4043],
  11816. [4020, 4022, 4023, 4033, 4043],
  11817. [4003, 4030, 4032, 4033, 4043],
  11818. [4003, 4013, 4040, 4042, 4043],
  11819. [4020, 4021, 4023, 4033, 4043],
  11820. [4003, 4030, 4031, 4033, 4043],
  11821. [4003, 4013, 4040, 4041, 4043],
  11822. [4013, 4030, 4031, 4032, 4033],
  11823. [4012, 4030, 4031, 4032, 4033],
  11824. [4011, 4030, 4031, 4032, 4033],
  11825. [4010, 4030, 4031, 4032, 4033],
  11826. [4013, 4023, 4031, 4032, 4033],
  11827. [4013, 4023, 4030, 4032, 4033],
  11828. [4020, 4022, 4023, 4032, 4033],
  11829. [4013, 4023, 4030, 4031, 4033],
  11830. [4021, 4022, 4023, 4030, 4033],
  11831. [4020, 4022, 4023, 4031, 4033],
  11832. [4020, 4021, 4023, 4032, 4033],
  11833. [4020, 4021, 4022, 4023, 4043],
  11834. [4003, 4030, 4031, 4032, 4033],
  11835. [4020, 4022, 4023, 4030, 4033],
  11836. [4020, 4021, 4023, 4031, 4033],
  11837. [4020, 4021, 4022, 4023, 4042],
  11838. [4002, 4030, 4031, 4032, 4033],
  11839. [4020, 4021, 4023, 4030, 4033],
  11840. [4020, 4021, 4022, 4023, 4041],
  11841. [4001, 4030, 4031, 4032, 4033],
  11842. [4020, 4021, 4022, 4023, 4040],
  11843. [4000, 4030, 4031, 4032, 4033],
  11844. [4003, 4023, 4031, 4032, 4033],
  11845. [4013, 4020, 4022, 4023, 4043],
  11846. [4003, 4023, 4030, 4032, 4033],
  11847. [4010, 4012, 4013, 4042, 4043],
  11848. [4013, 4020, 4021, 4023, 4043],
  11849. [4003, 4023, 4030, 4031, 4033],
  11850. [4011, 4012, 4013, 4040, 4043],
  11851. [4010, 4012, 4013, 4041, 4043],
  11852. [4010, 4011, 4013, 4042, 4043],
  11853. [4020, 4021, 4022, 4023, 4033],
  11854. [4010, 4012, 4013, 4040, 4043],
  11855. [4010, 4011, 4013, 4041, 4043],
  11856. [4020, 4021, 4022, 4023, 4032],
  11857. [4010, 4011, 4013, 4040, 4043],
  11858. [4020, 4021, 4022, 4023, 4031],
  11859. [4020, 4021, 4022, 4023, 4030],
  11860. [4003, 4013, 4031, 4032, 4033],
  11861. [4010, 4012, 4013, 4033, 4043],
  11862. [4003, 4020, 4022, 4023, 4043],
  11863. [4013, 4020, 4022, 4023, 4033],
  11864. [4003, 4013, 4030, 4032, 4033],
  11865. [4010, 4011, 4013, 4033, 4043],
  11866. [4003, 4020, 4021, 4023, 4043],
  11867. [4013, 4020, 4021, 4023, 4033],
  11868. [4003, 4013, 4030, 4031, 4033],
  11869. [4010, 4012, 4013, 4023, 4043],
  11870. [4003, 4020, 4022, 4023, 4033],
  11871. [4010, 4012, 4013, 4032, 4033],
  11872. [4010, 4011, 4013, 4023, 4043],
  11873. [4003, 4020, 4021, 4023, 4033],
  11874. [4011, 4012, 4013, 4030, 4033],
  11875. [4010, 4012, 4013, 4031, 4033],
  11876. [4010, 4011, 4013, 4032, 4033],
  11877. [4013, 4020, 4021, 4022, 4023],
  11878. [4010, 4012, 4013, 4030, 4033],
  11879. [4010, 4011, 4013, 4031, 4033],
  11880. [4012, 4020, 4021, 4022, 4023],
  11881. [4010, 4011, 4013, 4030, 4033],
  11882. [4011, 4020, 4021, 4022, 4023],
  11883. [4010, 4020, 4021, 4022, 4023],
  11884. [4010, 4012, 4013, 4023, 4033],
  11885. [4000, 4002, 4003, 4042, 4043],
  11886. [4010, 4011, 4013, 4023, 4033],
  11887. [4001, 4002, 4003, 4040, 4043],
  11888. [4000, 4002, 4003, 4041, 4043],
  11889. [4000, 4001, 4003, 4042, 4043],
  11890. [4010, 4011, 4012, 4013, 4043],
  11891. [4003, 4020, 4021, 4022, 4023],
  11892. [4000, 4002, 4003, 4040, 4043],
  11893. [4000, 4001, 4003, 4041, 4043],
  11894. [4010, 4011, 4012, 4013, 4042],
  11895. [4002, 4020, 4021, 4022, 4023],
  11896. [4000, 4001, 4003, 4040, 4043],
  11897. [4010, 4011, 4012, 4013, 4041],
  11898. [4001, 4020, 4021, 4022, 4023],
  11899. [4010, 4011, 4012, 4013, 4040],
  11900. [4000, 4020, 4021, 4022, 4023],
  11901. [4001, 4002, 4003, 4033, 4043],
  11902. [4000, 4002, 4003, 4033, 4043],
  11903. [4003, 4010, 4012, 4013, 4043],
  11904. [4003, 4013, 4020, 4022, 4023],
  11905. [4000, 4001, 4003, 4033, 4043],
  11906. [4003, 4010, 4011, 4013, 4043],
  11907. [4003, 4013, 4020, 4021, 4023],
  11908. [4010, 4011, 4012, 4013, 4033],
  11909. [4010, 4011, 4012, 4013, 4032],
  11910. [4010, 4011, 4012, 4013, 4031],
  11911. [4010, 4011, 4012, 4013, 4030],
  11912. [4001, 4002, 4003, 4023, 4043],
  11913. [4000, 4002, 4003, 4023, 4043],
  11914. [4003, 4010, 4012, 4013, 4033],
  11915. [4000, 4002, 4003, 4032, 4033],
  11916. [4000, 4001, 4003, 4023, 4043],
  11917. [4003, 4010, 4011, 4013, 4033],
  11918. [4001, 4002, 4003, 4030, 4033],
  11919. [4000, 4002, 4003, 4031, 4033],
  11920. [4000, 4001, 4003, 4032, 4033],
  11921. [4010, 4011, 4012, 4013, 4023],
  11922. [4000, 4002, 4003, 4030, 4033],
  11923. [4000, 4001, 4003, 4031, 4033],
  11924. [4010, 4011, 4012, 4013, 4022],
  11925. [4000, 4001, 4003, 4030, 4033],
  11926. [4010, 4011, 4012, 4013, 4021],
  11927. [4010, 4011, 4012, 4013, 4020],
  11928. [4001, 4002, 4003, 4013, 4043],
  11929. [4001, 4002, 4003, 4023, 4033],
  11930. [4000, 4002, 4003, 4013, 4043],
  11931. [4000, 4002, 4003, 4023, 4033],
  11932. [4003, 4010, 4012, 4013, 4023],
  11933. [4000, 4001, 4003, 4013, 4043],
  11934. [4000, 4001, 4003, 4023, 4033],
  11935. [4003, 4010, 4011, 4013, 4023],
  11936. [4001, 4002, 4003, 4013, 4033],
  11937. [4000, 4002, 4003, 4013, 4033],
  11938. [4000, 4001, 4003, 4013, 4033],
  11939. [4000, 4001, 4002, 4003, 4043],
  11940. [4003, 4010, 4011, 4012, 4013],
  11941. [4000, 4001, 4002, 4003, 4042],
  11942. [4002, 4010, 4011, 4012, 4013],
  11943. [4000, 4001, 4002, 4003, 4041],
  11944. [4001, 4010, 4011, 4012, 4013],
  11945. [4000, 4001, 4002, 4003, 4040],
  11946. [4000, 4010, 4011, 4012, 4013],
  11947. [4001, 4002, 4003, 4013, 4023],
  11948. [4000, 4002, 4003, 4013, 4023],
  11949. [4000, 4001, 4003, 4013, 4023],
  11950. [4000, 4001, 4002, 4003, 4033],
  11951. [4000, 4001, 4002, 4003, 4032],
  11952. [4000, 4001, 4002, 4003, 4031],
  11953. [4000, 4001, 4002, 4003, 4030],
  11954. [4000, 4001, 4002, 4003, 4023],
  11955. [4000, 4001, 4002, 4003, 4022],
  11956. [4000, 4001, 4002, 4003, 4021],
  11957. [4000, 4001, 4002, 4003, 4020],
  11958. [4000, 4001, 4002, 4003, 4013],
  11959. [4000, 4001, 4002, 4003, 4012],
  11960. [4000, 4001, 4002, 4003, 4011],
  11961. [4000, 4001, 4002, 4003, 4010],
  11962. ].filter((p) => p.includes(this.mandatoryId));
  11963. const bestPack = {
  11964. pack: packs[0],
  11965. winRate: 0,
  11966. countBattle: 0,
  11967. id: 0,
  11968. };
  11969. for (const id in packs) {
  11970. const pack = packs[id];
  11971. const attackers = this.maxUpgrade.filter((e) => pack.includes(e.id)).reduce((obj, e) => ({ ...obj, [e.id]: e }), {});
  11972. const battle = {
  11973. attackers,
  11974. defenders: [enemieHeroes],
  11975. type: 'brawl_titan',
  11976. };
  11977. const isRandom = this.isRandomBattle(battle);
  11978. const stat = {
  11979. count: 0,
  11980. win: 0,
  11981. winRate: 0,
  11982. };
  11983. for (let i = 1; i <= 20; i++) {
  11984. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  11985. const r###lt = await Calc(battle);
  11986. stat.win += r###lt.r###lt.win;
  11987. stat.count += 1;
  11988. stat.winRate = stat.win / stat.count;
  11989. if (!isRandom || (i >= 2 && stat.winRate < 0.65) || (i >= 10 && stat.winRate == 1)) {
  11990. break;
  11991. }
  11992. }
  11993. if (!isRandom && stat.win) {
  11994. return {
  11995. favor: {},
  11996. heroes: pack,
  11997. };
  11998. }
  11999. if (stat.winRate > 0.85) {
  12000. return {
  12001. favor: {},
  12002. heroes: pack,
  12003. };
  12004. }
  12005. if (stat.winRate > bestPack.winRate) {
  12006. bestPack.countBattle = stat.count;
  12007. bestPack.winRate = stat.winRate;
  12008. bestPack.pack = pack;
  12009. bestPack.id = id;
  12010. }
  12011. }
  12012. //console.log(bestPack.id, bestPack.pack, bestPack.winRate, bestPack.countBattle);
  12013. return {
  12014. favor: {},
  12015. heroes: bestPack.pack,
  12016. };
  12017. }
  12018. isRandomPack(pack) {
  12019. const ids = Object.keys(pack);
  12020. return ids.includes('4023') || ids.includes('4021');
  12021. }
  12022. isRandomBattle(battle) {
  12023. return this.isRandomPack(battle.attackers) || this.isRandomPack(battle.defenders[0]);
  12024. }
  12025. async updateHeroesPack(enemieHeroes) {
  12026. 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}}}];
  12027. const bestPack = {
  12028. pack: packs[0],
  12029. countWin: 0,
  12030. }
  12031. for (const pack of packs) {
  12032. const attackers = pack.attackers;
  12033. const battle = {
  12034. attackers,
  12035. defenders: [enemieHeroes],
  12036. type: 'brawl',
  12037. };
  12038. let countWinBattles = 0;
  12039. let countTestBattle = 10;
  12040. for (let i = 0; i < countTestBattle; i++) {
  12041. battle.seed = Math.floor(Date.now() / 1000) + Math.random() * 1000;
  12042. const r###lt = await Calc(battle);
  12043. if (r###lt.r###lt.win) {
  12044. countWinBattles++;
  12045. }
  12046. if (countWinBattles > 7) {
  12047. console.log(pack)
  12048. return pack.args;
  12049. }
  12050. }
  12051. if (countWinBattles > bestPack.countWin) {
  12052. bestPack.countWin = countWinBattles;
  12053. bestPack.pack = pack.args;
  12054. }
  12055. }
  12056. console.log(bestPack);
  12057. return bestPack.pack;
  12058. }
  12059. async questFarm() {
  12060. const calls = [this.callBrawlQuestFarm];
  12061. const r###lt = await Send(JSON.stringify({ calls }));
  12062. return r###lt.r###lts[0].r###lt.response;
  12063. }
  12064. async getBrawlInfo() {
  12065. const data = await Send(JSON.stringify({
  12066. calls: [
  12067. this.callUserGetInfo,
  12068. this.callBrawlQuestGetInfo,
  12069. this.callBrawlFindEnemies,
  12070. this.callTeamGetMaxUpgrade,
  12071. this.callBrawlGetInfo,
  12072. ]
  12073. }));
  12074. let attempts = data.r###lts[0].r###lt.response.refillable.find(n => n.id == 48);
  12075. const maxUpgrade = data.r###lts[3].r###lt.response;
  12076. const maxHero = Object.values(maxUpgrade.hero);
  12077. const maxTitan = Object.values(maxUpgrade.titan);
  12078. const maxPet = Object.values(maxUpgrade.pet);
  12079. this.maxUpgrade = [...maxHero, ...maxPet, ...maxTitan];
  12080. this.info = data.r###lts[4].r###lt.response;
  12081. this.mandatoryId = lib.data.brawl.promoHero[this.info.id].promoHero;
  12082. return {
  12083. attempts: attempts.amount,
  12084. questInfo: data.r###lts[1].r###lt.response,
  12085. findEnemies: data.r###lts[2].r###lt.response,
  12086. }
  12087. }
  12088. /**
  12089. * Carrying out a fight
  12090. *
  12091. * Проведение боя
  12092. */
  12093. async battle(userId) {
  12094. this.stats.count++;
  12095. const battle = await this.startBattle(userId, this.args);
  12096. const r###lt = await Calc(battle);
  12097. console.log(r###lt.r###lt);
  12098. if (r###lt.r###lt.win) {
  12099. this.stats.win++;
  12100. } else {
  12101. this.stats.loss++;
  12102. if (!this.info.boughtEndlessLivesToday) {
  12103. this.attempts--;
  12104. }
  12105. }
  12106. return await this.endBattle(r###lt);
  12107. // return await this.cancelBattle(r###lt);
  12108. }
  12109. /**
  12110. * Starts a fight
  12111. *
  12112. * Начинает бой
  12113. */
  12114. async startBattle(userId, args) {
  12115. const call = {
  12116. name: "brawl_startBattle",
  12117. args,
  12118. ident: "brawl_startBattle"
  12119. }
  12120. call.args.userId = userId;
  12121. const calls = [call];
  12122. const r###lt = await Send(JSON.stringify({ calls }));
  12123. return r###lt.r###lts[0].r###lt.response;
  12124. }
  12125. cancelBattle(battle) {
  12126. const fixBattle = function (heroes) {
  12127. for (const ids in heroes) {
  12128. const hero = heroes[ids];
  12129. hero.energy = random(1, 999);
  12130. if (hero.hp > 0) {
  12131. hero.hp = random(1, hero.hp);
  12132. }
  12133. }
  12134. }
  12135. fixBattle(battle.progress[0].attackers.heroes);
  12136. fixBattle(battle.progress[0].defenders.heroes);
  12137. return this.endBattle(battle);
  12138. }
  12139. /**
  12140. * Ends the fight
  12141. *
  12142. * Заканчивает бой
  12143. */
  12144. async endBattle(battle) {
  12145. battle.progress[0].attackers.input = ['auto', 0, 0, 'auto', 0, 0];
  12146. const calls = [{
  12147. name: "brawl_endBattle",
  12148. args: {
  12149. r###lt: battle.r###lt,
  12150. progress: battle.progress
  12151. },
  12152. ident: "brawl_endBattle"
  12153. },
  12154. this.callBrawlQuestGetInfo,
  12155. this.callBrawlFindEnemies,
  12156. ];
  12157. const r###lt = await Send(JSON.stringify({ calls }));
  12158. return r###lt.r###lts;
  12159. }
  12160. end(endReason) {
  12161. setIsCancalBattle(true);
  12162. isBrawlsAutoStart = false;
  12163. setProgress(endReason, true);
  12164. console.log(endReason);
  12165. this.resolve();
  12166. }
  12167. }
  12168. this.HWHClasses.executeBrawls = executeBrawls;
  12169. })();
  12170. /**
  12171. * TODO:
  12172. * Получение всех уровней при сборе всех наград (квест на титанит и на энку) +-
  12173. * Добивание на арене титанов
  12174. * Закрытие окошек по Esc +-
  12175. * Починить работу скрипта на уровне команды ниже 10 +-
  12176. * Написать номальную синхронизацию
  12177. * Запрет сбора квестов и отправки экспеиций в промежуток между локальным обновлением и глобальным обновлением дня
  12178. * Улучшение боев
  12179. */